From 7cbae61dbddefb98f1c5b412d8d72bf5ad883ac9 Mon Sep 17 00:00:00 2001 From: Frederic Guillot Date: Sun, 29 Mar 2015 13:51:51 -0400 Subject: [PATCH] Add Hipchat integration --- README.markdown | 1 + app/Controller/Config.php | 2 +- app/Core/HttpClient.php | 3 +- app/Integration/Hipchat.php | 53 +++++++++++++++++++ app/Locale/da_DK/translations.php | 5 ++ app/Locale/de_DE/translations.php | 5 ++ app/Locale/es_ES/translations.php | 5 ++ app/Locale/fi_FI/translations.php | 5 ++ app/Locale/fr_FR/translations.php | 7 ++- app/Locale/hu_HU/translations.php | 5 ++ app/Locale/it_IT/translations.php | 5 ++ app/Locale/ja_JP/translations.php | 5 ++ app/Locale/nl_NL/translations.php | 5 ++ app/Locale/pl_PL/translations.php | 5 ++ app/Locale/pt_BR/translations.php | 5 ++ app/Locale/ru_RU/translations.php | 5 ++ app/Locale/sr_Latn_RS/translations.php | 5 ++ app/Locale/sv_SE/translations.php | 5 ++ app/Locale/th_TH/translations.php | 5 ++ app/Locale/tr_TR/translations.php | 5 ++ app/Locale/zh_CN/translations.php | 5 ++ app/Schema/Mysql.php | 11 +++- app/Schema/Postgres.php | 11 +++- app/Schema/Sqlite.php | 11 +++- app/ServiceProvider/ClassProvider.php | 1 + app/Subscriber/ProjectActivitySubscriber.php | 34 +++++++++--- app/Template/config/integrations.php | 16 ++++++ app/Template/project/integrations.php | 2 +- assets/img/gitlab-icon.png | Bin 0 -> 661 bytes assets/img/hipchat-icon.png | Bin 0 -> 1373 bytes docs/hipchat.markdown | 31 +++++++++++ docs/slack.markdown | 4 +- 32 files changed, 250 insertions(+), 17 deletions(-) create mode 100644 app/Integration/Hipchat.php create mode 100644 assets/img/gitlab-icon.png create mode 100644 assets/img/hipchat-icon.png create mode 100644 docs/hipchat.markdown diff --git a/README.markdown b/README.markdown index fd34c6fba..32a67c48f 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 57f586ae3..bb6e860a9 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); } if ($this->config->save($values)) { diff --git a/app/Core/HttpClient.php b/app/Core/HttpClient.php index 968601529..e1d90858b 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 000000000..036925f7f --- /dev/null +++ b/app/Integration/Hipchat.php @@ -0,0 +1,53 @@ +project->getbyId($project_id); + + $event['event_name'] = $event_name; + $event['author'] = $this->user->getFullname($this->session['user']); + + $html = ''; + $html .= ''.$project['name'].'
'; + $html .= $this->projectActivity->getTitle($event); + + if ($this->config->get('application_url')) { + $html .= '
'; + $html .= t('view the task on Kanboard').''; + } + + $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 9af5dcb88..a13aa3afe 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 dda991c7d..1ec93d44c 100644 --- a/app/Locale/de_DE/translations.php +++ b/app/Locale/de_DE/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/es_ES/translations.php b/app/Locale/es_ES/translations.php index a857493fb..33c062c6f 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 ae2382246..856914ade 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 e24258922..d389b0e17 100644 --- a/app/Locale/fr_FR/translations.php +++ b/app/Locale/fr_FR/translations.php @@ -825,8 +825,13 @@ 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', ); diff --git a/app/Locale/hu_HU/translations.php b/app/Locale/hu_HU/translations.php index 70ab88986..297924173 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 5924ed0c1..e8d4c4d1f 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 f7d225af9..52d5413d5 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 0efbc7f3f..b53f9c83c 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 97c185c3b..42a3dff73 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 bca271427..b18f2143f 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 8b84fc1f6..b77960d36 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 a04a31afe..0514faa4e 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 b5e6a6297..dede73642 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 f45b24cb7..86a4f79cb 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 d46e71a42..eb9717983 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 b6be113d7..70175e5fb 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/Schema/Mysql.php b/app/Schema/Mysql.php index dc0b8b428..f0e0d6b2b 100644 --- a/app/Schema/Mysql.php +++ b/app/Schema/Mysql.php @@ -6,7 +6,16 @@ use PDO; use Core\Security; use Model\Link; -const VERSION = 58; +const VERSION = 59; + +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 ea7b84d13..f7a0453da 100644 --- a/app/Schema/Postgres.php +++ b/app/Schema/Postgres.php @@ -6,7 +6,16 @@ use PDO; use Core\Security; use Model\Link; -const VERSION = 39; +const VERSION = 40; + +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 1ffd94057..3ad045e6f 100644 --- a/app/Schema/Sqlite.php +++ b/app/Schema/Sqlite.php @@ -6,7 +6,16 @@ use Core\Security; use PDO; use Model\Link; -const VERSION = 57; +const VERSION = 58; + +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 5f6298aa7..6a12ea5a9 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 d2e851665..42314637f 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/config/integrations.php b/app/Template/config/integrations.php index 104ebc167..6f90e0ab4 100644 --- a/app/Template/config/integrations.php +++ b/app/Template/config/integrations.php @@ -6,6 +6,22 @@ formCsrf() ?> +

+
+ formCheckbox('integration_hipchat', t('Send notifications to Hipchat'), 1, $values['integration_hipchat'] == 1) ?> + + formLabel(t('API URL'), 'integration_hipchat_api_url') ?> + formText('integration_hipchat_api_url', $values, $errors) ?> + + formLabel(t('Room API ID or name'), 'integration_hipchat_room_id') ?> + formText('integration_hipchat_room_id', $values, $errors) ?> + + formLabel(t('Room notification token'), 'integration_hipchat_room_token') ?> + formText('integration_hipchat_room_token', $values, $errors) ?> + +

+
+

 

formCheckbox('integration_slack_webhook', t('Send notifications to a Slack channel'), 1, $values['integration_slack_webhook'] == 1) ?> diff --git a/app/Template/project/integrations.php b/app/Template/project/integrations.php index 194bd672e..4f6553adc 100644 --- a/app/Template/project/integrations.php +++ b/app/Template/project/integrations.php @@ -8,7 +8,7 @@

-

 

+

 


diff --git a/assets/img/gitlab-icon.png b/assets/img/gitlab-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..7e1eaa5c02dbbacfde44eaf6c654de951ec3a02b GIT binary patch literal 661 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!60wlNoGJgf6SkfJR9T^xl_H+M9WCijSl0AZa z85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP=YDR+ueoXe|!I#{R|9@ z-JULvAsXjfC;EC!W@KoapZ|NC-CTQ*9h{pKZgLnpO%K|w;?%BqhEMiT*^1oVtc&8y$@?dayj zUz%^{?YvQ@Df@m4)7`lJPhaicXEa;q>#=8>M07ZkA{GmC>Yfan$*h|l<@|U@vqcb( znD}G$ZpKd>3=^N4+}nG#Q~kH*3fAYZA2!KptuohIxk51ZBKOTI^Pa$d$<*b_0-IMX znkZS5W7yxX<@4uy)v+w`vto5m-p-G{7hR+3IZG#YOL1RrNJbGm!?KDClW+V`JsB3{ zDeDn+{rFq=+D9x70zJ>S+dnZ^)qSyf$rhob)4vyNoA$JIWtsin-~Z0{8J*Hte)7$Q zznjCBT>8N(b;kPdV{OT&BJtgKbIMx(^#}EHY~5dFZF%)(sY=*Wj?cG~CC={jKd!p& ziF~x$#tMUI1z@BxsFt`!l%yn14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>oN@Ck7RDv;L;Ktl@p z0dl%PZ}>VXUe5DG-o1ri4u2-O8uk8CWMjY}Nv zHi8P^Dg)$n{4mUi%1UW^;F2Ow92iPKM4nzM=mG~jE^{D}f=d=IPNWxz@g|y@|NsA= zcs_G4Fp-@q3GxFaSi*os#V;enPnm_uZ0^0+&z`-$H^-ETE%*6_DhEwX$LfpEvRN6k z-*$;h^uEntuz1kH#@>D3bk2E6=}R+iO`LN5Rb}n->r6ko z85uOYF28#9>dlG5%QZ}lBF64+mSsm@eMn;vbIoz|{JOdX=oQ8!Z+DkdpSPGj19I3) zJbhi+@9~I>a!Q!Y6^{W5{quBj43W5;oB#wNp~2TLT)A{DF^PdOE!MV{*;zSRIM}$D zTa1k@%v(EKI@-FL-CaFhJlx!jt(@OqKfjERjm=L_KHmO6L)(D`4+Qcy#Ieo0u;Bwo z+ldt!acmk7x;uN5JNzGrH*j)rsj3;OEa&Jxz~XW==(5Bm<0HnKH>pZUs1z4{Uh;`s zf~&jB+w1fxZLQU-va?>ll9rH~Ju5ou_AP6x-Mgx*e*aQ8@bI5wQhDl1=H>J=b4;tx z-KjL<+4NalCuU2<$xErH!`H-Yt?HFwZvJzt^tE};oh_B8ujSq@e-pxRbJ>pU@ALNl z{w8lx@#2G^Dw{=sUDcZ(os+c~?*I1p;}4iz4h#v^64!{5l*E!$tK_0oAjM#0U}&Oi zXryao9Aac>WngJ#WTI^VWEijXC4d?vK{f>Er 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 7d7777eb3..89e3006bb 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.