summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.travis.yml22
-rw-r--r--README.markdown1
-rw-r--r--app/Controller/Config.php2
-rw-r--r--app/Core/Helper.php19
-rw-r--r--app/Core/HttpClient.php3
-rw-r--r--app/Integration/Hipchat.php53
-rw-r--r--app/Locale/da_DK/translations.php5
-rw-r--r--app/Locale/de_DE/translations.php191
-rw-r--r--app/Locale/es_ES/translations.php5
-rw-r--r--app/Locale/fi_FI/translations.php5
-rw-r--r--app/Locale/fr_FR/translations.php8
-rw-r--r--app/Locale/hu_HU/translations.php5
-rw-r--r--app/Locale/it_IT/translations.php5
-rw-r--r--app/Locale/ja_JP/translations.php5
-rw-r--r--app/Locale/nl_NL/translations.php5
-rw-r--r--app/Locale/pl_PL/translations.php5
-rw-r--r--app/Locale/pt_BR/translations.php5
-rw-r--r--app/Locale/ru_RU/translations.php5
-rw-r--r--app/Locale/sr_Latn_RS/translations.php5
-rw-r--r--app/Locale/sv_SE/translations.php5
-rw-r--r--app/Locale/th_TH/translations.php5
-rw-r--r--app/Locale/tr_TR/translations.php5
-rw-r--r--app/Locale/zh_CN/translations.php5
-rw-r--r--app/Model/Comment.php3
-rw-r--r--app/Model/ProjectActivity.php7
-rw-r--r--app/Model/Subtask.php1
-rw-r--r--app/Schema/Mysql.php17
-rw-r--r--app/Schema/Postgres.php17
-rw-r--r--app/Schema/Sqlite.php17
-rw-r--r--app/ServiceProvider/ClassProvider.php1
-rw-r--r--app/Subscriber/ProjectActivitySubscriber.php34
-rw-r--r--app/Template/app/subtasks.php4
-rw-r--r--app/Template/comment/show.php4
-rw-r--r--app/Template/config/integrations.php21
-rw-r--r--app/Template/event/comment_create.php2
-rw-r--r--app/Template/event/comment_update.php2
-rw-r--r--app/Template/event/subtask_create.php2
-rw-r--r--app/Template/event/subtask_update.php2
-rw-r--r--app/Template/event/task_assignee_change.php2
-rw-r--r--app/Template/event/task_close.php2
-rw-r--r--app/Template/event/task_create.php2
-rw-r--r--app/Template/event/task_move_column.php2
-rw-r--r--app/Template/event/task_move_position.php2
-rw-r--r--app/Template/event/task_open.php2
-rw-r--r--app/Template/event/task_update.php2
-rw-r--r--app/Template/project/integrations.php2
-rw-r--r--app/constants.php2
-rw-r--r--assets/css/app.css6
-rw-r--r--assets/css/src/base.css5
-rw-r--r--assets/img/gitlab-icon.pngbin0 -> 661 bytes
-rw-r--r--assets/img/hipchat-icon.pngbin0 -> 1373 bytes
-rw-r--r--composer.json3
-rw-r--r--config.default.php5
-rw-r--r--docs/hipchat.markdown31
-rw-r--r--docs/slack.markdown4
55 files changed, 455 insertions, 125 deletions
diff --git a/.travis.yml b/.travis.yml
index 1596ec9a..398dda1b 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,12 +1,20 @@
language: php
php:
- - "5.6"
- - "5.5"
- - "5.4"
- - "5.3"
+ - 7.0
+ - 5.6
+ - 5.5
+ - 5.4
+ - 5.3
-before_script: wget https://phar.phpunit.de/phpunit.phar
-script:
+matrix:
+ fast_finish: true
+ allow_failures:
+ - php: 7.0
+
+before_script:
- composer install
- - php phpunit.phar -c tests/units.sqlite.xml \ No newline at end of file
+
+script:
+ - phpunit -c tests/units.sqlite.xml
+
diff --git a/README.markdown b/README.markdown
index fd34c6fb..32a67c48 100644
--- a/README.markdown
+++ b/README.markdown
@@ -97,6 +97,7 @@ Documentation
- [Bitbucket webhooks](docs/bitbucket-webhooks.markdown)
- [Github webhooks](docs/github-webhooks.markdown)
- [Gitlab webhooks](docs/gitlab-webhooks.markdown)
+- [Hipchat](docs/hipchat.markdown)
- [Slack](docs/slack.markdown)
#### More
diff --git a/app/Controller/Config.php b/app/Controller/Config.php
index 57f586ae..3c884191 100644
--- a/app/Controller/Config.php
+++ b/app/Controller/Config.php
@@ -44,7 +44,7 @@ class Config extends Base
$values += array('subtask_restriction' => 0, 'subtask_time_tracking' => 0, 'subtask_forecast' => 0);
}
else if ($redirect === 'integrations') {
- $values += array('integration_slack_webhook' => 0);
+ $values += array('integration_slack_webhook' => 0, 'integration_hipchat' => 0, 'integration_gravatar' => 0);
}
if ($this->config->save($values)) {
diff --git a/app/Core/Helper.php b/app/Core/Helper.php
index 34a5e6ab..29003416 100644
--- a/app/Core/Helper.php
+++ b/app/Core/Helper.php
@@ -502,7 +502,7 @@ class Helper
public function markdown($text, array $link = array())
{
$parser = new Markdown($link, $this);
- $parser->setMarkupEscaped(true);
+ $parser->setMarkupEscaped(MARKDOWN_ESCAPE_HTML);
return $parser->text($text);
}
@@ -770,4 +770,21 @@ class Helper
return 'fa-file-o';
}
+
+ /**
+ * Display gravatar image
+ *
+ * @access public
+ * @param string $email
+ * @param string $alt
+ * @return string
+ */
+ public function avatar($email, $alt = '')
+ {
+ if (! empty($email) && $this->config->get('integration_gravatar') == 1) {
+ return '<img class="avatar" src="https://www.gravatar.com/avatar/'.md5(strtolower($email)).'?s=25" alt="'.$this->e($alt).'" title="'.$this->e($alt).'">';
+ }
+
+ return '';
+ }
}
diff --git a/app/Core/HttpClient.php b/app/Core/HttpClient.php
index 96860152..e1d90858 100644
--- a/app/Core/HttpClient.php
+++ b/app/Core/HttpClient.php
@@ -47,8 +47,9 @@ class HttpClient
}
$headers = array(
- 'Connection: close',
'User-Agent: '.self::HTTP_USER_AGENT,
+ 'Content-Type: application/json',
+ 'Connection: close',
);
$context = stream_context_create(array(
diff --git a/app/Integration/Hipchat.php b/app/Integration/Hipchat.php
new file mode 100644
index 00000000..036925f7
--- /dev/null
+++ b/app/Integration/Hipchat.php
@@ -0,0 +1,53 @@
+<?php
+
+namespace Integration;
+
+/**
+ * Hipchat Webhook
+ *
+ * @package integration
+ * @author Frederic Guillot
+ */
+class Hipchat extends Base
+{
+ /**
+ * Send message to the Hipchat room
+ *
+ * @access public
+ * @param integer $project_id Project id
+ * @param integer $task_id Task id
+ * @param string $event_name Event name
+ * @param array $data Event data
+ */
+ public function notify($project_id, $task_id, $event_name, array $event)
+ {
+ $project = $this->project->getbyId($project_id);
+
+ $event['event_name'] = $event_name;
+ $event['author'] = $this->user->getFullname($this->session['user']);
+
+ $html = '<img src="http://kanboard.net/assets/img/favicon-32x32.png"/>';
+ $html .= '<strong>'.$project['name'].'</strong><br/>';
+ $html .= $this->projectActivity->getTitle($event);
+
+ if ($this->config->get('application_url')) {
+ $html .= '<br/><a href="'.$this->config->get('application_url');
+ $html .= $this->helper->u('task', 'show', array('task_id' => $task_id, 'project_id' => $project_id)).'">';
+ $html .= t('view the task on Kanboard').'</a>';
+ }
+
+ $payload = array(
+ 'message' => $html,
+ 'color' => 'yellow',
+ );
+
+ $url = sprintf(
+ '%s/v2/room/%s/notification?auth_token=%s',
+ $this->config->get('integration_hipchat_api_url'),
+ $this->config->get('integration_hipchat_room_id'),
+ $this->config->get('integration_hipchat_room_token')
+ );
+
+ $this->httpClient->post($url, $payload);
+ }
+}
diff --git a/app/Locale/da_DK/translations.php b/app/Locale/da_DK/translations.php
index 9af5dcb8..a13aa3af 100644
--- a/app/Locale/da_DK/translations.php
+++ b/app/Locale/da_DK/translations.php
@@ -827,4 +827,9 @@ return array(
// 'Webhook URL' => '',
// 'Help on Slack integration' => '',
// '%s remove the assignee of the task %s' => '',
+ // 'Send notifications to Hipchat' => '',
+ // 'API URL' => '',
+ // 'Room API ID or name' => '',
+ // 'Room notification token' => '',
+ // 'Help on Hipchat integration' => '',
);
diff --git a/app/Locale/de_DE/translations.php b/app/Locale/de_DE/translations.php
index dda991c7..2043215b 100644
--- a/app/Locale/de_DE/translations.php
+++ b/app/Locale/de_DE/translations.php
@@ -1,8 +1,8 @@
<?php
return array(
- // 'number.decimals_separator' => '',
- // 'number.thousands_separator' => '',
+ 'number.decimals_separator' => ',',
+ 'number.thousands_separator' => '.',
'None' => 'Keines',
'edit' => 'Bearbeiten',
'Edit' => 'Bearbeiten',
@@ -410,13 +410,13 @@ return array(
'Comment updated' => 'Kommentar wurde aktualisiert',
'New comment posted by %s' => 'Neuer Kommentar verfasst durch %s',
'List of due tasks for the project "%s"' => 'Liste der fälligen Aufgaben für das Projekt "%s"',
- // 'New attachment' => '',
- // 'New comment' => '',
- // 'New subtask' => '',
- // 'Subtask updated' => '',
- // 'Task updated' => '',
- // 'Task closed' => '',
- // 'Task opened' => '',
+ 'New attachment' => 'Neuer Anhang',
+ 'New comment' => 'Neuer Kommentar',
+ 'New subtask' => 'Neue Teilaufgabe',
+ 'Subtask updated' => 'Teilaufgabe aktualisiert',
+ 'Task updated' => 'Aufgabe aktualisiert',
+ 'Task closed' => 'Aufgabe geschlossen',
+ 'Task opened' => 'Aufgabe geöffnet',
'[%s][Due tasks]' => '[%s][Fällige Aufgaben]',
'[Kanboard] Notification' => '[Kanboard] Benachrichtigung',
'I want to receive notifications only for those projects:' => 'Ich möchte nur für diese Projekte Benachrichtigungen erhalten:',
@@ -500,9 +500,9 @@ return array(
'Task assignee change' => 'Zuständigkeit geändert',
'%s change the assignee of the task #%d to %s' => '%s hat die Zusständigkeit der Aufgabe #%d geändert um %s',
'%s changed the assignee of the task %s to %s' => '%s hat die Zuständigkeit der Aufgabe %s geändert um %s',
- // 'Column Change' => '',
- // 'Position Change' => '',
- // 'Assignee Change' => '',
+ 'Column Change' => 'Spalte ändern',
+ 'Position Change' => 'Position ändern',
+ 'Assignee Change' => 'Zuordnung ändern',
'New password for the user "%s"' => 'Neues Passwort des Benutzers "%s"',
'Choose an event' => 'Aktion wählen',
'Github commit received' => 'Github commit empfangen',
@@ -736,95 +736,100 @@ return array(
'Filter recently updated' => 'Zuletzt geänderte anzeigen',
'since %B %e, %Y at %k:%M %p' => 'seit %B %e, %Y um %k:%M %p',
'More filters' => 'Mehr Filter',
- // 'Compact view' => '',
- // 'Horizontal scrolling' => '',
- // 'Compact/wide view' => '',
- // 'No results match:' => '',
- // 'Remove hourly rate' => '',
- // 'Do you really want to remove this hourly rate?' => '',
- // 'Hourly rates' => '',
- // 'Hourly rate' => '',
- // 'Currency' => '',
- // 'Effective date' => '',
- // 'Add new rate' => '',
- // 'Rate removed successfully.' => '',
- // 'Unable to remove this rate.' => '',
- // 'Unable to save the hourly rate.' => '',
- // 'Hourly rate created successfully.' => '',
- // 'Start time' => '',
- // 'End time' => '',
- // 'Comment' => '',
- // 'All day' => '',
- // 'Day' => '',
- // 'Manage timetable' => '',
- // 'Overtime timetable' => '',
- // 'Time off timetable' => '',
- // 'Timetable' => '',
- // 'Work timetable' => '',
- // 'Week timetable' => '',
- // 'Day timetable' => '',
- // 'From' => '',
- // 'To' => '',
- // 'Time slot created successfully.' => '',
- // 'Unable to save this time slot.' => '',
- // 'Time slot removed successfully.' => '',
- // 'Unable to remove this time slot.' => '',
- // 'Do you really want to remove this time slot?' => '',
- // 'Remove time slot' => '',
- // 'Add new time slot' => '',
- // 'This timetable is used when the checkbox "all day" is checked for scheduled time off and overtime.' => '',
- // 'Files' => '',
- // 'Images' => '',
- // 'Private project' => '',
- // 'Amount' => '',
+ 'Compact view' => 'Kompaktansicht',
+ 'Horizontal scrolling' => 'Horizontales Scrollen',
+ 'Compact/wide view' => 'Kompakt/Breite-Ansicht',
+ 'No results match:' => 'Keine Ergebnisse:',
+ 'Remove hourly rate' => 'Stundensatz entfernen',
+ 'Do you really want to remove this hourly rate?' => 'Diesen Stundensatz wirklich entfernen?',
+ 'Hourly rates' => 'Stundensätze',
+ 'Hourly rate' => 'Stundensatz',
+ 'Currency' => 'Währung',
+ 'Effective date' => 'Inkraftsetzung',
+ 'Add new rate' => 'Neue Rate hinzufügen',
+ 'Rate removed successfully.' => 'Rate erfolgreich entfernt',
+ 'Unable to remove this rate.' => 'Nicht in der Lage, diese Rate zu entfernen.',
+ 'Unable to save the hourly rate.' => 'Nicht in der Lage, diese Rate zu speichern',
+ 'Hourly rate created successfully.' => 'Stundensatz erfolgreich angelegt.',
+ 'Start time' => 'Startzeit',
+ 'End time' => 'Endzeit',
+ 'Comment' => 'Kommentar',
+ 'All day' => 'ganztägig',
+ 'Day' => 'Tag',
+ 'Manage timetable' => 'Zeitplan verwalten',
+ 'Overtime timetable' => 'Überstunden Zeitplan',
+ 'Time off timetable' => 'Freizeit Zeitplan',
+ 'Timetable' => 'Zeitplan',
+ 'Work timetable' => 'Arbeitszeitplan',
+ 'Week timetable' => 'Wochenzeitplan',
+ 'Day timetable' => 'Tageszeitplan',
+ 'From' => 'von',
+ 'To' => 'bis',
+ 'Time slot created successfully.' => 'Zeitfenster erfolgreich erstellt.',
+ 'Unable to save this time slot.' => 'Nicht in der Lage, dieses Zeitfenster zu speichern.',
+ 'Time slot removed successfully.' => 'Zeitfenster erfolgreich entfernt.',
+ 'Unable to remove this time slot.' => 'Nicht in der Lage, dieses Zeitfenster zu entfernen',
+ 'Do you really want to remove this time slot?' => 'Soll diese Zeitfenster wirklich gelöscht werden?',
+ 'Remove time slot' => 'Zeitfenster entfernen',
+ 'Add new time slot' => 'Neues Zeitfenster hinzufügen',
+ 'This timetable is used when the checkbox "all day" is checked for scheduled time off and overtime.' => 'Dieses Zeitfenster wird verwendet, wenn die Checkbox "gantägig" für Freizeit und Überstunden angeklickt ist.',
+ 'Files' => 'Dateien',
+ 'Images' => 'Bilder',
+ 'Private project' => 'privates Projekt',
+ 'Amount' => 'Betrag',
// 'AUD - Australian Dollar' => '',
- // 'Budget' => '',
- // 'Budget line' => '',
- // 'Budget line removed successfully.' => '',
- // 'Budget lines' => '',
+ 'Budget' => 'Budget',
+ 'Budget line' => 'Budgetlinie',
+ 'Budget line removed successfully.' => 'Budgetlinie erfolgreich entfernt',
+ 'Budget lines' => 'Budgetlinien',
// 'CAD - Canadian Dollar' => '',
// 'CHF - Swiss Francs' => '',
- // 'Cost' => '',
- // 'Cost breakdown' => '',
- // 'Custom Stylesheet' => '',
- // 'download' => '',
- // 'Do you really want to remove this budget line?' => '',
+ 'Cost' => 'Kosten',
+ 'Cost breakdown' => 'Kostenaufschlüsselung',
+ 'Custom Stylesheet' => 'benutzerdefiniertes Stylesheet',
+ 'download' => 'Download',
+ 'Do you really want to remove this budget line?' => 'Soll diese Budgetlinie wirklich entfernt werden?',
// 'EUR - Euro' => '',
- // 'Expenses' => '',
+ 'Expenses' => 'Kosten',
// 'GBP - British Pound' => '',
// 'INR - Indian Rupee' => '',
// 'JPY - Japanese Yen' => '',
- // 'New budget line' => '',
+ 'New budget line' => 'Neue Budgetlinie',
// 'NZD - New Zealand Dollar' => '',
- // 'Remove a budget line' => '',
- // 'Remove budget line' => '',
+ 'Remove a budget line' => 'Budgetlinie entfernen',
+ 'Remove budget line' => 'Budgetlinie entfernen',
// 'RSD - Serbian dinar' => '',
- // 'The budget line have been created successfully.' => '',
- // 'Unable to create the budget line.' => '',
- // 'Unable to remove this budget line.' => '',
+ 'The budget line have been created successfully.' => 'Die Budgetlinie wurde erfolgreich angelegt.',
+ 'Unable to create the budget line.' => 'Budgetlinie konnte nicht erstellt werden.',
+ 'Unable to remove this budget line.' => 'Budgetlinie konnte nicht gelöscht werden.',
// 'USD - US Dollar' => '',
- // 'Remaining' => '',
- // 'Destination column' => '',
- // 'Move the task to another column when assigned to a user' => '',
- // 'Move the task to another column when assignee is cleared' => '',
- // 'Source column' => '',
- // 'Show subtask estimates in the user calendar' => '',
- // 'Transitions' => '',
- // 'Executer' => '',
- // 'Time spent in the column' => '',
- // 'Task transitions' => '',
- // 'Task transitions export' => '',
- // 'This report contains all column moves for each task with the date, the user and the time spent for each transition.' => '',
- // 'Currency rates' => '',
- // 'Rate' => '',
- // 'Change reference currency' => '',
- // 'Add a new currency rate' => '',
- // 'Currency rates are used to calculate project budget.' => '',
- // 'Reference currency' => '',
- // 'The currency rate have been added successfully.' => '',
- // 'Unable to add this currency rate.' => '',
- // 'Send notifications to a Slack channel' => '',
- // 'Webhook URL' => '',
- // 'Help on Slack integration' => '',
- // '%s remove the assignee of the task %s' => '',
+ 'Remaining' => 'Verbleibend',
+ 'Destination column' => 'Zielspalte',
+ 'Move the task to another column when assigned to a user' => 'Aufgabe in eine andere Spalte verschieben, wenn ein User zugeordnet wurde.',
+ 'Move the task to another column when assignee is cleared' => 'Aufgabe in eine andere Spalte verschieben, wenn die Zuordnung gelöscht wurde.',
+ 'Source column' => 'Quellspalte',
+ 'Show subtask estimates in the user calendar' => 'Teilaufgabenschätzung in Benutzerkalender anzeigen.',
+ 'Transitions' => 'Übergänge',
+ 'Executer' => 'Ausführender',
+ 'Time spent in the column' => 'Zeit in Spalte verbracht',
+ 'Task transitions' => 'Aufgaben Übergänge',
+ 'Task transitions export' => 'Aufgaben Übergänge exportieren',
+ 'This report contains all column moves for each task with the date, the user and the time spent for each transition.' => 'Diese Auswertung enthält alle Spaltenbewegungen für jede Aufgabe mit Datum, Benutzer und Zeit vor jedem Wechsel.',
+ 'Currency rates' => 'Währungskurse',
+ 'Rate' => 'Kurse',
+ 'Change reference currency' => 'Referenzwährung ändern',
+ 'Add a new currency rate' => 'Neuen Währungskurs hinzufügen',
+ 'Currency rates are used to calculate project budget.' => 'Währungskurse werden verwendet um das Projektbudget zu berechnen.',
+ 'Reference currency' => 'Referenzwährung',
+ 'The currency rate have been added successfully.' => 'Der Währungskurs wurde erfolgreich hinzugefügt.',
+ 'Unable to add this currency rate.' => 'Währungskurs konnte nicht hinzugefügt werden',
+ 'Send notifications to a Slack channel' => 'Benachrichtigung an einen Slack-Kanal senden',
+ 'Webhook URL' => 'Webhook URL',
+ 'Help on Slack integration' => 'Hilfe für Slack integration.',
+ '%s remove the assignee of the task %s' => '%s Zuordnung für die Aufgabe %s entfernen',
+ // 'Send notifications to Hipchat' => '',
+ // 'API URL' => '',
+ // 'Room API ID or name' => '',
+ // 'Room notification token' => '',
+ // 'Help on Hipchat integration' => '',
);
diff --git a/app/Locale/es_ES/translations.php b/app/Locale/es_ES/translations.php
index a857493f..33c062c6 100644
--- a/app/Locale/es_ES/translations.php
+++ b/app/Locale/es_ES/translations.php
@@ -827,4 +827,9 @@ return array(
// 'Webhook URL' => '',
// 'Help on Slack integration' => '',
// '%s remove the assignee of the task %s' => '',
+ // 'Send notifications to Hipchat' => '',
+ // 'API URL' => '',
+ // 'Room API ID or name' => '',
+ // 'Room notification token' => '',
+ // 'Help on Hipchat integration' => '',
);
diff --git a/app/Locale/fi_FI/translations.php b/app/Locale/fi_FI/translations.php
index ae238224..856914ad 100644
--- a/app/Locale/fi_FI/translations.php
+++ b/app/Locale/fi_FI/translations.php
@@ -827,4 +827,9 @@ return array(
// 'Webhook URL' => '',
// 'Help on Slack integration' => '',
// '%s remove the assignee of the task %s' => '',
+ // 'Send notifications to Hipchat' => '',
+ // 'API URL' => '',
+ // 'Room API ID or name' => '',
+ // 'Room notification token' => '',
+ // 'Help on Hipchat integration' => '',
);
diff --git a/app/Locale/fr_FR/translations.php b/app/Locale/fr_FR/translations.php
index e2425892..ac21f387 100644
--- a/app/Locale/fr_FR/translations.php
+++ b/app/Locale/fr_FR/translations.php
@@ -825,8 +825,14 @@ return array(
'Reference currency' => 'Devise de référence',
'The currency rate have been added successfully.' => 'Le taux de change a été ajouté avec succès.',
'Unable to add this currency rate.' => 'Impossible d\'ajouter ce taux de change',
- 'Send notifications to a Slack channel' => 'Envoyer des notifications sur un channel Slack',
+ 'Send notifications to a Slack channel' => 'Envoyer les notifications sur un salon de discussion Slack',
'Webhook URL' => 'URL du webhook',
'Help on Slack integration' => 'Aide sur l\'intégration avec Slack',
'%s remove the assignee of the task %s' => '%s a enlevé la personne assignée à la tâche %s',
+ 'Send notifications to Hipchat' => 'Envoyer les notifications vers Hipchat',
+ 'API URL' => 'URL de l\'api',
+ 'Room API ID or name' => 'Nom ou identifiant du salon de discussion',
+ 'Room notification token' => 'Jeton de sécurité du salon de discussion',
+ 'Help on Hipchat integration' => 'Aide sur l\'intégration avec Hipchat',
+ 'Enable Gravatar images' => 'Activer les images Gravatar',
);
diff --git a/app/Locale/hu_HU/translations.php b/app/Locale/hu_HU/translations.php
index 70ab8898..29792417 100644
--- a/app/Locale/hu_HU/translations.php
+++ b/app/Locale/hu_HU/translations.php
@@ -827,4 +827,9 @@ return array(
// 'Webhook URL' => '',
// 'Help on Slack integration' => '',
// '%s remove the assignee of the task %s' => '',
+ // 'Send notifications to Hipchat' => '',
+ // 'API URL' => '',
+ // 'Room API ID or name' => '',
+ // 'Room notification token' => '',
+ // 'Help on Hipchat integration' => '',
);
diff --git a/app/Locale/it_IT/translations.php b/app/Locale/it_IT/translations.php
index 5924ed0c..e8d4c4d1 100644
--- a/app/Locale/it_IT/translations.php
+++ b/app/Locale/it_IT/translations.php
@@ -827,4 +827,9 @@ return array(
// 'Webhook URL' => '',
// 'Help on Slack integration' => '',
// '%s remove the assignee of the task %s' => '',
+ // 'Send notifications to Hipchat' => '',
+ // 'API URL' => '',
+ // 'Room API ID or name' => '',
+ // 'Room notification token' => '',
+ // 'Help on Hipchat integration' => '',
);
diff --git a/app/Locale/ja_JP/translations.php b/app/Locale/ja_JP/translations.php
index f7d225af..52d5413d 100644
--- a/app/Locale/ja_JP/translations.php
+++ b/app/Locale/ja_JP/translations.php
@@ -827,4 +827,9 @@ return array(
// 'Webhook URL' => '',
// 'Help on Slack integration' => '',
// '%s remove the assignee of the task %s' => '',
+ // 'Send notifications to Hipchat' => '',
+ // 'API URL' => '',
+ // 'Room API ID or name' => '',
+ // 'Room notification token' => '',
+ // 'Help on Hipchat integration' => '',
);
diff --git a/app/Locale/nl_NL/translations.php b/app/Locale/nl_NL/translations.php
index 0efbc7f3..b53f9c83 100644
--- a/app/Locale/nl_NL/translations.php
+++ b/app/Locale/nl_NL/translations.php
@@ -827,4 +827,9 @@ return array(
// 'Webhook URL' => '',
// 'Help on Slack integration' => '',
// '%s remove the assignee of the task %s' => '',
+ // 'Send notifications to Hipchat' => '',
+ // 'API URL' => '',
+ // 'Room API ID or name' => '',
+ // 'Room notification token' => '',
+ // 'Help on Hipchat integration' => '',
);
diff --git a/app/Locale/pl_PL/translations.php b/app/Locale/pl_PL/translations.php
index 97c185c3..42a3dff7 100644
--- a/app/Locale/pl_PL/translations.php
+++ b/app/Locale/pl_PL/translations.php
@@ -827,4 +827,9 @@ return array(
// 'Webhook URL' => '',
// 'Help on Slack integration' => '',
// '%s remove the assignee of the task %s' => '',
+ // 'Send notifications to Hipchat' => '',
+ // 'API URL' => '',
+ // 'Room API ID or name' => '',
+ // 'Room notification token' => '',
+ // 'Help on Hipchat integration' => '',
);
diff --git a/app/Locale/pt_BR/translations.php b/app/Locale/pt_BR/translations.php
index bca27142..b18f2143 100644
--- a/app/Locale/pt_BR/translations.php
+++ b/app/Locale/pt_BR/translations.php
@@ -827,4 +827,9 @@ return array(
// 'Webhook URL' => '',
// 'Help on Slack integration' => '',
// '%s remove the assignee of the task %s' => '',
+ // 'Send notifications to Hipchat' => '',
+ // 'API URL' => '',
+ // 'Room API ID or name' => '',
+ // 'Room notification token' => '',
+ // 'Help on Hipchat integration' => '',
);
diff --git a/app/Locale/ru_RU/translations.php b/app/Locale/ru_RU/translations.php
index 8b84fc1f..b77960d3 100644
--- a/app/Locale/ru_RU/translations.php
+++ b/app/Locale/ru_RU/translations.php
@@ -827,4 +827,9 @@ return array(
// 'Webhook URL' => '',
// 'Help on Slack integration' => '',
// '%s remove the assignee of the task %s' => '',
+ // 'Send notifications to Hipchat' => '',
+ // 'API URL' => '',
+ // 'Room API ID or name' => '',
+ // 'Room notification token' => '',
+ // 'Help on Hipchat integration' => '',
);
diff --git a/app/Locale/sr_Latn_RS/translations.php b/app/Locale/sr_Latn_RS/translations.php
index a04a31af..0514faa4 100644
--- a/app/Locale/sr_Latn_RS/translations.php
+++ b/app/Locale/sr_Latn_RS/translations.php
@@ -827,4 +827,9 @@ return array(
// 'Webhook URL' => '',
// 'Help on Slack integration' => '',
// '%s remove the assignee of the task %s' => '',
+ // 'Send notifications to Hipchat' => '',
+ // 'API URL' => '',
+ // 'Room API ID or name' => '',
+ // 'Room notification token' => '',
+ // 'Help on Hipchat integration' => '',
);
diff --git a/app/Locale/sv_SE/translations.php b/app/Locale/sv_SE/translations.php
index b5e6a629..dede7364 100644
--- a/app/Locale/sv_SE/translations.php
+++ b/app/Locale/sv_SE/translations.php
@@ -827,4 +827,9 @@ return array(
// 'Webhook URL' => '',
// 'Help on Slack integration' => '',
// '%s remove the assignee of the task %s' => '',
+ // 'Send notifications to Hipchat' => '',
+ // 'API URL' => '',
+ // 'Room API ID or name' => '',
+ // 'Room notification token' => '',
+ // 'Help on Hipchat integration' => '',
);
diff --git a/app/Locale/th_TH/translations.php b/app/Locale/th_TH/translations.php
index f45b24cb..86a4f79c 100644
--- a/app/Locale/th_TH/translations.php
+++ b/app/Locale/th_TH/translations.php
@@ -827,4 +827,9 @@ return array(
// 'Webhook URL' => '',
// 'Help on Slack integration' => '',
// '%s remove the assignee of the task %s' => '',
+ // 'Send notifications to Hipchat' => '',
+ // 'API URL' => '',
+ // 'Room API ID or name' => '',
+ // 'Room notification token' => '',
+ // 'Help on Hipchat integration' => '',
);
diff --git a/app/Locale/tr_TR/translations.php b/app/Locale/tr_TR/translations.php
index d46e71a4..eb971798 100644
--- a/app/Locale/tr_TR/translations.php
+++ b/app/Locale/tr_TR/translations.php
@@ -827,4 +827,9 @@ return array(
// 'Webhook URL' => '',
// 'Help on Slack integration' => '',
// '%s remove the assignee of the task %s' => '',
+ // 'Send notifications to Hipchat' => '',
+ // 'API URL' => '',
+ // 'Room API ID or name' => '',
+ // 'Room notification token' => '',
+ // 'Help on Hipchat integration' => '',
);
diff --git a/app/Locale/zh_CN/translations.php b/app/Locale/zh_CN/translations.php
index b6be113d..70175e5f 100644
--- a/app/Locale/zh_CN/translations.php
+++ b/app/Locale/zh_CN/translations.php
@@ -827,4 +827,9 @@ return array(
// 'Webhook URL' => '',
// 'Help on Slack integration' => '',
// '%s remove the assignee of the task %s' => '',
+ // 'Send notifications to Hipchat' => '',
+ // 'API URL' => '',
+ // 'Room API ID or name' => '',
+ // 'Room notification token' => '',
+ // 'Help on Hipchat integration' => '',
);
diff --git a/app/Model/Comment.php b/app/Model/Comment.php
index a36f2b45..844f0c89 100644
--- a/app/Model/Comment.php
+++ b/app/Model/Comment.php
@@ -47,7 +47,8 @@ class Comment extends Base
self::TABLE.'.user_id',
self::TABLE.'.comment',
User::TABLE.'.username',
- User::TABLE.'.name'
+ User::TABLE.'.name',
+ User::TABLE.'.email'
)
->join(User::TABLE, 'id', 'user_id')
->orderBy(self::TABLE.'.date', 'ASC')
diff --git a/app/Model/ProjectActivity.php b/app/Model/ProjectActivity.php
index 46d71fc7..05081a47 100644
--- a/app/Model/ProjectActivity.php
+++ b/app/Model/ProjectActivity.php
@@ -131,18 +131,19 @@ class ProjectActivity extends Base
->columns(
self::TABLE.'.*',
User::TABLE.'.username AS author_username',
- User::TABLE.'.name AS author_name'
+ User::TABLE.'.name AS author_name',
+ User::TABLE.'.email'
)
->in('project_id', $project_ids)
->join(User::TABLE, 'id', 'creator_id')
->desc(self::TABLE.'.id')
->limit($limit);
- if(!is_null($start)){
+ if (!is_null($start)){
$query->gte('date_creation', $start);
}
- if(!is_null($end)){
+ if (!is_null($end)){
$query->lte('date_creation', $end);
}
diff --git a/app/Model/Subtask.php b/app/Model/Subtask.php
index e33373e0..492f3a77 100644
--- a/app/Model/Subtask.php
+++ b/app/Model/Subtask.php
@@ -98,6 +98,7 @@ class Subtask extends Base
Subtask::TABLE.'.*',
Task::TABLE.'.project_id',
Task::TABLE.'.color_id',
+ Task::TABLE.'.title AS task_name',
Project::TABLE.'.name AS project_name'
)
->eq('user_id', $user_id)
diff --git a/app/Schema/Mysql.php b/app/Schema/Mysql.php
index dc0b8b42..4ea7b041 100644
--- a/app/Schema/Mysql.php
+++ b/app/Schema/Mysql.php
@@ -6,7 +6,22 @@ use PDO;
use Core\Security;
use Model\Link;
-const VERSION = 58;
+const VERSION = 60;
+
+function version_60($pdo)
+{
+ $rq = $pdo->prepare('INSERT INTO settings VALUES (?, ?)');
+ $rq->execute(array('integration_gravatar', '0'));
+}
+
+function version_59($pdo)
+{
+ $rq = $pdo->prepare('INSERT INTO settings VALUES (?, ?)');
+ $rq->execute(array('integration_hipchat', '0'));
+ $rq->execute(array('integration_hipchat_api_url', 'https://api.hipchat.com'));
+ $rq->execute(array('integration_hipchat_room_id', ''));
+ $rq->execute(array('integration_hipchat_room_token', ''));
+}
function version_58($pdo)
{
diff --git a/app/Schema/Postgres.php b/app/Schema/Postgres.php
index ea7b84d1..93d8e869 100644
--- a/app/Schema/Postgres.php
+++ b/app/Schema/Postgres.php
@@ -6,7 +6,22 @@ use PDO;
use Core\Security;
use Model\Link;
-const VERSION = 39;
+const VERSION = 40;
+
+function version_41($pdo)
+{
+ $rq = $pdo->prepare('INSERT INTO settings VALUES (?, ?)');
+ $rq->execute(array('integration_gravatar', '0'));
+}
+
+function version_40($pdo)
+{
+ $rq = $pdo->prepare('INSERT INTO settings VALUES (?, ?)');
+ $rq->execute(array('integration_hipchat', '0'));
+ $rq->execute(array('integration_hipchat_api_url', 'https://api.hipchat.com'));
+ $rq->execute(array('integration_hipchat_room_id', ''));
+ $rq->execute(array('integration_hipchat_room_token', ''));
+}
function version_39($pdo)
{
diff --git a/app/Schema/Sqlite.php b/app/Schema/Sqlite.php
index 1ffd9405..3683acb6 100644
--- a/app/Schema/Sqlite.php
+++ b/app/Schema/Sqlite.php
@@ -6,7 +6,22 @@ use Core\Security;
use PDO;
use Model\Link;
-const VERSION = 57;
+const VERSION = 59;
+
+function version_59($pdo)
+{
+ $rq = $pdo->prepare('INSERT INTO settings VALUES (?, ?)');
+ $rq->execute(array('integration_gravatar', '0'));
+}
+
+function version_58($pdo)
+{
+ $rq = $pdo->prepare('INSERT INTO settings VALUES (?, ?)');
+ $rq->execute(array('integration_hipchat', '0'));
+ $rq->execute(array('integration_hipchat_api_url', 'https://api.hipchat.com'));
+ $rq->execute(array('integration_hipchat_room_id', ''));
+ $rq->execute(array('integration_hipchat_room_token', ''));
+}
function version_57($pdo)
{
diff --git a/app/ServiceProvider/ClassProvider.php b/app/ServiceProvider/ClassProvider.php
index 5f6298aa..6a12ea5a 100644
--- a/app/ServiceProvider/ClassProvider.php
+++ b/app/ServiceProvider/ClassProvider.php
@@ -75,6 +75,7 @@ class ClassProvider implements ServiceProviderInterface
'GitlabWebhook',
'GithubWebhook',
'BitbucketWebhook',
+ 'Hipchat',
'SlackWebhook',
)
);
diff --git a/app/Subscriber/ProjectActivitySubscriber.php b/app/Subscriber/ProjectActivitySubscriber.php
index d2e85166..42314637 100644
--- a/app/Subscriber/ProjectActivitySubscriber.php
+++ b/app/Subscriber/ProjectActivitySubscriber.php
@@ -42,14 +42,32 @@ class ProjectActivitySubscriber extends Base implements EventSubscriberInterface
$values
);
- if ($this->config->get('integration_slack_webhook') == 1) {
- $this->slackWebhook->notify(
- $values['task']['project_id'],
- $values['task']['id'],
- $event_name,
- $values
- );
- }
+ $this->sendSlackNotification($event_name, $values);
+ $this->sendHipchatNotification($event_name, $values);
+ }
+ }
+
+ private function sendSlackNotification($event_name, array $values)
+ {
+ if ($this->config->get('integration_slack_webhook') == 1) {
+ $this->slackWebhook->notify(
+ $values['task']['project_id'],
+ $values['task']['id'],
+ $event_name,
+ $values
+ );
+ }
+ }
+
+ private function sendHipchatNotification($event_name, array $values)
+ {
+ if ($this->config->get('integration_hipchat') == 1) {
+ $this->hipchat->notify(
+ $values['task']['project_id'],
+ $values['task']['id'],
+ $event_name,
+ $values
+ );
}
}
diff --git a/app/Template/app/subtasks.php b/app/Template/app/subtasks.php
index fdfbdf2f..487b66fc 100644
--- a/app/Template/app/subtasks.php
+++ b/app/Template/app/subtasks.php
@@ -6,6 +6,7 @@
<tr>
<th class="column-10"><?= $paginator->order('Id', 'tasks.id') ?></th>
<th class="column-20"><?= $paginator->order(t('Project'), 'project_name') ?></th>
+ <th><?= $paginator->order(t('Task'), 'task_name') ?></th>
<th><?= $paginator->order(t('Subtask'), 'title') ?></th>
<th class="column-20"><?= t('Time tracking') ?></th>
</tr>
@@ -18,6 +19,9 @@
<?= $this->a($this->e($subtask['project_name']), 'board', 'show', array('project_id' => $subtask['project_id'])) ?>
</td>
<td>
+ <?= $this->a($this->e($subtask['task_name']), 'task', 'show', array('task_id' => $subtask['task_id'], 'project_id' => $subtask['project_id'])) ?>
+ </td>
+ <td>
<?= $this->toggleSubtaskStatus($subtask, 'dashboard') ?>
</td>
<td>
diff --git a/app/Template/comment/show.php b/app/Template/comment/show.php
index 23389c06..98c29441 100644
--- a/app/Template/comment/show.php
+++ b/app/Template/comment/show.php
@@ -1,9 +1,11 @@
<div class="comment <?= isset($preview) ? 'comment-preview' : '' ?>" id="comment-<?= $comment['id'] ?>">
<p class="comment-title">
+ <?php if (! empty($comment['email'])): ?>
+ <?= $this->avatar($comment['email'], $comment['name'] ?: $comment['username']) ?>
+ <?php endif ?>
<span class="comment-username"><?= $this->e($comment['name'] ?: $comment['username']) ?></span> @ <span class="comment-date"><?= dt('%B %e, %Y at %k:%M %p', $comment['date']) ?></span>
</p>
-
<div class="comment-inner">
<?php if (! isset($preview)): ?>
diff --git a/app/Template/config/integrations.php b/app/Template/config/integrations.php
index 104ebc16..e11b62f8 100644
--- a/app/Template/config/integrations.php
+++ b/app/Template/config/integrations.php
@@ -6,6 +6,27 @@
<?= $this->formCsrf() ?>
+ <h3><?= t('Gravatar') ?></h3>
+ <div class="listing">
+ <?= $this->formCheckbox('integration_gravatar', t('Enable Gravatar images'), 1, $values['integration_gravatar'] == 1) ?>
+ </div>
+
+ <h3><img src="assets/img/hipchat-icon.png"/> <?= t('Hipchat') ?></h3>
+ <div class="listing">
+ <?= $this->formCheckbox('integration_hipchat', t('Send notifications to Hipchat'), 1, $values['integration_hipchat'] == 1) ?>
+
+ <?= $this->formLabel(t('API URL'), 'integration_hipchat_api_url') ?>
+ <?= $this->formText('integration_hipchat_api_url', $values, $errors) ?>
+
+ <?= $this->formLabel(t('Room API ID or name'), 'integration_hipchat_room_id') ?>
+ <?= $this->formText('integration_hipchat_room_id', $values, $errors) ?>
+
+ <?= $this->formLabel(t('Room notification token'), 'integration_hipchat_room_token') ?>
+ <?= $this->formText('integration_hipchat_room_token', $values, $errors) ?>
+
+ <p class="form-help"><a href="http://kanboard.net/documentation/hipchat" target="_blank"><?= t('Help on Hipchat integration') ?></a></p>
+ </div>
+
<h3><i class="fa fa-slack fa-fw"></i>&nbsp;<?= t('Slack') ?></h3>
<div class="listing">
<?= $this->formCheckbox('integration_slack_webhook', t('Send notifications to a Slack channel'), 1, $values['integration_slack_webhook'] == 1) ?>
diff --git a/app/Template/event/comment_create.php b/app/Template/event/comment_create.php
index fd046fd1..79238aba 100644
--- a/app/Template/event/comment_create.php
+++ b/app/Template/event/comment_create.php
@@ -1,3 +1,5 @@
+<?= $this->avatar($email, $author) ?>
+
<p class="activity-title">
<?= e('%s commented the task %s',
$this->e($author),
diff --git a/app/Template/event/comment_update.php b/app/Template/event/comment_update.php
index 7149bacf..5d22a2ce 100644
--- a/app/Template/event/comment_update.php
+++ b/app/Template/event/comment_update.php
@@ -1,3 +1,5 @@
+<?= $this->avatar($email, $author) ?>
+
<p class="activity-title">
<?= e('%s updated a comment on the task %s',
$this->e($author),
diff --git a/app/Template/event/subtask_create.php b/app/Template/event/subtask_create.php
index 1cc7585c..4f33069a 100644
--- a/app/Template/event/subtask_create.php
+++ b/app/Template/event/subtask_create.php
@@ -1,3 +1,5 @@
+<?= $this->avatar($email, $author) ?>
+
<p class="activity-title">
<?= e('%s created a subtask for the task %s',
$this->e($author),
diff --git a/app/Template/event/subtask_update.php b/app/Template/event/subtask_update.php
index be06f7f5..19fe2e56 100644
--- a/app/Template/event/subtask_update.php
+++ b/app/Template/event/subtask_update.php
@@ -1,3 +1,5 @@
+<?= $this->avatar($email, $author) ?>
+
<p class="activity-title">
<?= e('%s updated a subtask for the task %s',
$this->e($author),
diff --git a/app/Template/event/task_assignee_change.php b/app/Template/event/task_assignee_change.php
index 22ed936b..38e2bca7 100644
--- a/app/Template/event/task_assignee_change.php
+++ b/app/Template/event/task_assignee_change.php
@@ -1,3 +1,5 @@
+<?= $this->avatar($email, $author) ?>
+
<p class="activity-title">
<?php $assignee = $task['assignee_name'] ?: $task['assignee_username'] ?>
diff --git a/app/Template/event/task_close.php b/app/Template/event/task_close.php
index b5ad4d1d..afedbef3 100644
--- a/app/Template/event/task_close.php
+++ b/app/Template/event/task_close.php
@@ -1,3 +1,5 @@
+<?= $this->avatar($email, $author) ?>
+
<p class="activity-title">
<?= e('%s closed the task %s',
$this->e($author),
diff --git a/app/Template/event/task_create.php b/app/Template/event/task_create.php
index de9a7e0d..4b920234 100644
--- a/app/Template/event/task_create.php
+++ b/app/Template/event/task_create.php
@@ -1,3 +1,5 @@
+<?= $this->avatar($email, $author) ?>
+
<p class="activity-title">
<?= e('%s created the task %s',
$this->e($author),
diff --git a/app/Template/event/task_move_column.php b/app/Template/event/task_move_column.php
index e56e92d7..e97a3ab7 100644
--- a/app/Template/event/task_move_column.php
+++ b/app/Template/event/task_move_column.php
@@ -1,3 +1,5 @@
+<?= $this->avatar($email, $author) ?>
+
<p class="activity-title">
<?= e('%s moved the task %s to the column "%s"',
$this->e($author),
diff --git a/app/Template/event/task_move_position.php b/app/Template/event/task_move_position.php
index 412a9401..2ed4ffe8 100644
--- a/app/Template/event/task_move_position.php
+++ b/app/Template/event/task_move_position.php
@@ -1,3 +1,5 @@
+<?= $this->avatar($email, $author) ?>
+
<p class="activity-title">
<?= e('%s moved the task %s to the position #%d in the column "%s"',
$this->e($author),
diff --git a/app/Template/event/task_open.php b/app/Template/event/task_open.php
index 353f8dac..9a408449 100644
--- a/app/Template/event/task_open.php
+++ b/app/Template/event/task_open.php
@@ -1,3 +1,5 @@
+<?= $this->avatar($email, $author) ?>
+
<p class="activity-title">
<?= e('%s opened the task %s',
$this->e($author),
diff --git a/app/Template/event/task_update.php b/app/Template/event/task_update.php
index 24b17446..0f81870b 100644
--- a/app/Template/event/task_update.php
+++ b/app/Template/event/task_update.php
@@ -1,3 +1,5 @@
+<?= $this->avatar($email, $author) ?>
+
<p class="activity-title">
<?= e('%s updated the task %s',
$this->e($author),
diff --git a/app/Template/project/integrations.php b/app/Template/project/integrations.php
index 194bd672..4f6553ad 100644
--- a/app/Template/project/integrations.php
+++ b/app/Template/project/integrations.php
@@ -8,7 +8,7 @@
<p class="form-help"><a href="http://kanboard.net/documentation/github-webhooks" target="_blank"><?= t('Help on Github webhooks') ?></a></p>
</div>
-<h3><i class="fa fa-git fa-fw"></i>&nbsp;<?= t('Gitlab webhooks') ?></h3>
+<h3><img src="assets/img/gitlab-icon.png"/>&nbsp;<?= t('Gitlab webhooks') ?></h3>
<div class="listing">
<input type="text" class="auto-select" readonly="readonly" value="<?= $this->getCurrentBaseUrl().$this->u('webhook', 'gitlab', array('token' => $webhook_token, 'project_id' => $project['id'])) ?>"/><br/>
<p class="form-help"><a href="http://kanboard.net/documentation/gitlab-webhooks" target="_blank"><?= t('Help on Gitlab webhooks') ?></a></p>
diff --git a/app/constants.php b/app/constants.php
index 82d26f2c..08759cbd 100644
--- a/app/constants.php
+++ b/app/constants.php
@@ -74,3 +74,5 @@ defined('ENABLE_XFRAME') or define('ENABLE_XFRAME', true);
// Default files directory
defined('FILES_DIR') or define('FILES_DIR', 'data/files/');
+// Escape html inside markdown text
+defined('MARKDOWN_ESCAPE_HTML') or define('MARKDOWN_ESCAPE_HTML', true);
diff --git a/assets/css/app.css b/assets/css/app.css
index 79d61c6b..e3797b1d 100644
--- a/assets/css/app.css
+++ b/assets/css/app.css
@@ -62,7 +62,11 @@ hr {
.chosen-select {
min-height: 27px; /* Reserve some space to avoid re-layout due to chosen */
}
-/* links */
+
+.avatar {
+ float: left;
+ margin-right: 10px;
+}/* links */
a {
color: #3366CC;
border: none;
diff --git a/assets/css/src/base.css b/assets/css/src/base.css
index d92df612..10a3ee8e 100644
--- a/assets/css/src/base.css
+++ b/assets/css/src/base.css
@@ -46,3 +46,8 @@ hr {
.chosen-select {
min-height: 27px; /* Reserve some space to avoid re-layout due to chosen */
}
+
+.avatar {
+ float: left;
+ margin-right: 10px;
+} \ No newline at end of file
diff --git a/assets/img/gitlab-icon.png b/assets/img/gitlab-icon.png
new file mode 100644
index 00000000..7e1eaa5c
--- /dev/null
+++ b/assets/img/gitlab-icon.png
Binary files differ
diff --git a/assets/img/hipchat-icon.png b/assets/img/hipchat-icon.png
new file mode 100644
index 00000000..1b0a825f
--- /dev/null
+++ b/assets/img/hipchat-icon.png
Binary files differ
diff --git a/composer.json b/composer.json
index 0ab8f511..8e78ab39 100644
--- a/composer.json
+++ b/composer.json
@@ -1,5 +1,6 @@
{
"require" : {
+ "php": ">=5.3",
"ext-mbstring" : "*",
"fguillot/simple-validator" : "dev-master",
"swiftmailer/swiftmailer" : "@stable",
@@ -24,4 +25,4 @@
"require-dev" : {
"symfony/stopwatch" : "~2.6"
}
-} \ No newline at end of file
+}
diff --git a/config.default.php b/config.default.php
index eb9ad1b8..92b61bde 100644
--- a/config.default.php
+++ b/config.default.php
@@ -1,5 +1,7 @@
<?php
+// Rename this file to config.php if you want to change the values
+
// Enable/Disable debug
define('DEBUG', false);
@@ -127,3 +129,6 @@ define('ENABLE_HSTS', true);
// Enable or disable "X-Frame-Options: DENY" HTTP header
define('ENABLE_XFRAME', true);
+
+// Escape html inside markdown text
+define('MARKDOWN_ESCAPE_HTML', true);
diff --git a/docs/hipchat.markdown b/docs/hipchat.markdown
new file mode 100644
index 00000000..45d93eb2
--- /dev/null
+++ b/docs/hipchat.markdown
@@ -0,0 +1,31 @@
+Hipchat integration
+===================
+
+Send notifications to a room
+-----------------------------
+
+Example of notifications:
+
+![Hipchat notification](http://kanboard.net/screenshots/documentation/hipchat-notification.png)
+
+This feature use the room notification token system of Hipchat.
+
+### Hipchat configuration
+
+![Hipchat room token](http://kanboard.net/screenshots/documentation/hipchat-room-token.png)
+
+1. Go to to **My account**
+2. Click on the tab **Rooms** and select the room you want to send the notifications
+3. On the left, choose **Tokens**
+4. Enter a label, by example "Kanboard" and save
+
+### Kanboard configuration
+
+![Hipchat settings](http://kanboard.net/screenshots/documentation/hipchat-settings.png)
+
+1. Go to **Settings > Integrations > Hipchat**
+2. Replace the API url if you use the self-hosted version of Hipchat
+3. Set the room name or the room API ID
+4. Copy and paste the token generated previously
+
+Now, all Kanboard events will be sent to the Hipchat room.
diff --git a/docs/slack.markdown b/docs/slack.markdown
index 7d7777eb..89e3006b 100644
--- a/docs/slack.markdown
+++ b/docs/slack.markdown
@@ -10,7 +10,7 @@ Example of notifications:
This feature use the [Incoming webhook](https://api.slack.com/incoming-webhooks) system of Slack.
-### Configure Slack
+### Slack configuration
![Slack webhook creation](http://kanboard.net/screenshots/documentation/slack-add-incoming-webhook.png)
@@ -18,4 +18,4 @@ This feature use the [Incoming webhook](https://api.slack.com/incoming-webhooks)
2. On the list of services, scroll-down and choose **DIY Integrations & Customizations > Incoming WebHooks**
3. Copy the webhook url to the Kanboard settings page: **Settings > Integrations > Slack**
-
+Now, all Kanboard events will be sent to the Slack channel.