From 5266b821446b14b79a3c5a5c77c57791b985f0a9 Mon Sep 17 00:00:00 2001 From: Frédéric Guillot Date: Sun, 28 Dec 2014 22:22:15 -0500 Subject: Add Gitlab webhook --- app/Action/CommentCreation.php | 2 +- app/Action/TaskAssignCategoryLabel.php | 2 +- app/Action/TaskAssignUser.php | 2 +- app/Action/TaskClose.php | 11 +- app/Action/TaskCreation.php | 4 +- app/Action/TaskOpen.php | 2 +- app/Controller/Project.php | 17 +- app/Controller/Webhook.php | 22 +- app/Integration/Base.php | 49 +++ app/Integration/GithubWebhook.php | 375 +++++++++++++++++++++ app/Integration/GitlabWebhook.php | 213 ++++++++++++ app/Locale/da_DK/translations.php | 11 +- app/Locale/de_DE/translations.php | 11 +- app/Locale/es_ES/translations.php | 11 +- app/Locale/fi_FI/translations.php | 11 +- app/Locale/fr_FR/translations.php | 11 +- app/Locale/hu_HU/translations.php | 11 +- app/Locale/it_IT/translations.php | 11 +- app/Locale/ja_JP/translations.php | 11 +- app/Locale/pl_PL/translations.php | 11 +- app/Locale/pt_BR/translations.php | 11 +- app/Locale/ru_RU/translations.php | 11 +- app/Locale/sv_SE/translations.php | 11 +- app/Locale/th_TH/translations.php | 11 +- app/Locale/zh_CN/translations.php | 11 +- app/Model/Acl.php | 2 +- app/Model/Action.php | 5 + app/Model/Base.php | 1 + app/Model/GithubWebhook.php | 374 -------------------- app/ServiceProvider/ClassProvider.php | 5 +- .../ProjectModificationDateSubscriber.php | 2 +- app/Template/project/integrations.php | 15 + app/Template/project/show.php | 11 - app/Template/project/sidebar.php | 3 + 34 files changed, 847 insertions(+), 424 deletions(-) create mode 100644 app/Integration/Base.php create mode 100644 app/Integration/GithubWebhook.php create mode 100644 app/Integration/GitlabWebhook.php delete mode 100644 app/Model/GithubWebhook.php create mode 100644 app/Template/project/integrations.php (limited to 'app') diff --git a/app/Action/CommentCreation.php b/app/Action/CommentCreation.php index 5dbe32f1..27ed011b 100644 --- a/app/Action/CommentCreation.php +++ b/app/Action/CommentCreation.php @@ -2,7 +2,7 @@ namespace Action; -use Model\GithubWebhook; +use Integration\GithubWebhook; /** * Create automatically a comment from a webhook diff --git a/app/Action/TaskAssignCategoryLabel.php b/app/Action/TaskAssignCategoryLabel.php index 19064526..1383d491 100644 --- a/app/Action/TaskAssignCategoryLabel.php +++ b/app/Action/TaskAssignCategoryLabel.php @@ -2,7 +2,7 @@ namespace Action; -use Model\GithubWebhook; +use Integration\GithubWebhook; /** * Set a category automatically according to a label diff --git a/app/Action/TaskAssignUser.php b/app/Action/TaskAssignUser.php index f24ff415..cf2a9a4b 100644 --- a/app/Action/TaskAssignUser.php +++ b/app/Action/TaskAssignUser.php @@ -2,7 +2,7 @@ namespace Action; -use Model\GithubWebhook; +use Integration\GithubWebhook; /** * Assign a task to someone diff --git a/app/Action/TaskClose.php b/app/Action/TaskClose.php index 6cf9be05..760dfd84 100644 --- a/app/Action/TaskClose.php +++ b/app/Action/TaskClose.php @@ -2,7 +2,8 @@ namespace Action; -use Model\GithubWebhook; +use Integration\GitlabWebhook; +use Integration\GithubWebhook; use Model\Task; /** @@ -25,6 +26,8 @@ class TaskClose extends Base Task::EVENT_MOVE_COLUMN, GithubWebhook::EVENT_COMMIT, GithubWebhook::EVENT_ISSUE_CLOSED, + GitlabWebhook::EVENT_COMMIT, + GitlabWebhook::EVENT_ISSUE_CLOSED, ); } @@ -39,6 +42,8 @@ class TaskClose extends Base switch ($this->event_name) { case GithubWebhook::EVENT_COMMIT: case GithubWebhook::EVENT_ISSUE_CLOSED: + case GitlabWebhook::EVENT_COMMIT: + case GitlabWebhook::EVENT_ISSUE_CLOSED: return array(); default: return array('column_id' => t('Column')); @@ -56,6 +61,8 @@ class TaskClose extends Base switch ($this->event_name) { case GithubWebhook::EVENT_COMMIT: case GithubWebhook::EVENT_ISSUE_CLOSED: + case GitlabWebhook::EVENT_COMMIT: + case GitlabWebhook::EVENT_ISSUE_CLOSED: return array('task_id'); default: return array('task_id', 'column_id'); @@ -86,6 +93,8 @@ class TaskClose extends Base switch ($this->event_name) { case GithubWebhook::EVENT_COMMIT: case GithubWebhook::EVENT_ISSUE_CLOSED: + case GitlabWebhook::EVENT_COMMIT: + case GitlabWebhook::EVENT_ISSUE_CLOSED: return true; default: return $data['column_id'] == $this->getParam('column_id'); diff --git a/app/Action/TaskCreation.php b/app/Action/TaskCreation.php index 9b7a0b13..1c093eee 100644 --- a/app/Action/TaskCreation.php +++ b/app/Action/TaskCreation.php @@ -2,7 +2,8 @@ namespace Action; -use Model\GithubWebhook; +use Integration\GithubWebhook; +use Integration\GitlabWebhook; /** * Create automatically a task from a webhook @@ -22,6 +23,7 @@ class TaskCreation extends Base { return array( GithubWebhook::EVENT_ISSUE_OPENED, + GitlabWebhook::EVENT_ISSUE_OPENED, ); } diff --git a/app/Action/TaskOpen.php b/app/Action/TaskOpen.php index fc29e9eb..73f1fad3 100644 --- a/app/Action/TaskOpen.php +++ b/app/Action/TaskOpen.php @@ -2,7 +2,7 @@ namespace Action; -use Model\GithubWebhook; +use Integration\GithubWebhook; /** * Open automatically a task diff --git a/app/Controller/Project.php b/app/Controller/Project.php index 9037a91a..a7e8a39b 100644 --- a/app/Controller/Project.php +++ b/app/Controller/Project.php @@ -52,7 +52,6 @@ class Project extends Base $this->response->html($this->projectLayout('project/show', array( 'project' => $project, 'stats' => $this->project->getStats($project['id']), - 'webhook_token' => $this->config->get('webhook_token'), 'title' => $project['name'], ))); } @@ -152,6 +151,22 @@ class Project extends Base ))); } + /** + * Integrations page + * + * @access public + */ + public function integration() + { + $project = $this->getProjectManagement(); + + $this->response->html($this->projectLayout('project/integrations', array( + 'project' => $project, + 'title' => t('Integrations'), + 'webhook_token' => $this->config->get('webhook_token'), + ))); + } + /** * Display a form to edit a project * diff --git a/app/Controller/Webhook.php b/app/Controller/Webhook.php index dcd66a1a..1ae3b0a4 100644 --- a/app/Controller/Webhook.php +++ b/app/Controller/Webhook.php @@ -57,7 +57,27 @@ class Webhook extends Base $result = $this->githubWebhook->parsePayload( $this->request->getHeader('X-Github-Event'), - $this->request->getJson() + $this->request->getJson() ?: array() + ); + + echo $result ? 'PARSED' : 'IGNORED'; + } + + /** + * Handle Gitlab webhooks + * + * @access public + */ + public function gitlab() + { + if ($this->config->get('webhook_token') !== $this->request->getStringParam('token')) { + $this->response->text('Not Authorized', 401); + } + + $this->gitlabWebhook->setProjectId($this->request->getIntegerParam('project_id')); + + $result = $this->gitlabWebhook->parsePayload( + $this->request->getJson() ?: array() ); echo $result ? 'PARSED' : 'IGNORED'; diff --git a/app/Integration/Base.php b/app/Integration/Base.php new file mode 100644 index 00000000..babf8c8f --- /dev/null +++ b/app/Integration/Base.php @@ -0,0 +1,49 @@ +container = $container; + } + + /** + * Load automatically class from the container + * + * @access public + * @param string $name + * @return mixed + */ + public function __get($name) + { + return $this->container[$name]; + } +} diff --git a/app/Integration/GithubWebhook.php b/app/Integration/GithubWebhook.php new file mode 100644 index 00000000..fd0b49f6 --- /dev/null +++ b/app/Integration/GithubWebhook.php @@ -0,0 +1,375 @@ +project_id = $project_id; + } + + /** + * Parse Github events + * + * @access public + * @param string $type Github event type + * @param array $payload Github event + * @return boolean + */ + public function parsePayload($type, array $payload) + { + switch ($type) { + case 'push': + return $this->parsePushEvent($payload); + case 'issues': + return $this->parseIssueEvent($payload); + case 'issue_comment': + return $this->parseCommentIssueEvent($payload); + } + + return false; + } + + /** + * Parse Push events (list of commits) + * + * @access public + * @param array $payload Event data + * @return boolean + */ + public function parsePushEvent(array $payload) + { + foreach ($payload['commits'] as $commit) { + + $task_id = $this->task->getTaskIdFromText($commit['message']); + + if (! $task_id) { + continue; + } + + $task = $this->taskFinder->getById($task_id); + + if (! $task) { + continue; + } + + if ($task['is_active'] == Task::STATUS_OPEN && $task['project_id'] == $this->project_id) { + $this->container['dispatcher']->dispatch( + self::EVENT_COMMIT, + new GenericEvent(array('task_id' => $task_id) + $task) + ); + } + } + + return true; + } + + /** + * Parse issue events + * + * @access public + * @param array $payload Event data + * @return boolean + */ + public function parseIssueEvent(array $payload) + { + switch ($payload['action']) { + case 'opened': + return $this->handleIssueOpened($payload['issue']); + case 'closed': + return $this->handleIssueClosed($payload['issue']); + case 'reopened': + return $this->handleIssueReopened($payload['issue']); + case 'assigned': + return $this->handleIssueAssigned($payload['issue']); + case 'unassigned': + return $this->handleIssueUnassigned($payload['issue']); + case 'labeled': + return $this->handleIssueLabeled($payload['issue'], $payload['label']); + case 'unlabeled': + return $this->handleIssueUnlabeled($payload['issue'], $payload['label']); + } + + return false; + } + + /** + * Parse comment issue events + * + * @access public + * @param array $payload Event data + * @return boolean + */ + public function parseCommentIssueEvent(array $payload) + { + $task = $this->taskFinder->getByReference($payload['issue']['number']); + $user = $this->user->getByUsername($payload['comment']['user']['login']); + + if ($task && $user) { + + $event = array( + 'project_id' => $this->project_id, + 'reference' => $payload['comment']['id'], + 'comment' => $payload['comment']['body'], + 'user_id' => $user['id'], + 'task_id' => $task['id'], + ); + + $this->container['dispatcher']->dispatch( + self::EVENT_ISSUE_COMMENT, + new GenericEvent($event) + ); + + return true; + } + + return false; + } + + /** + * Handle new issues + * + * @access public + * @param array $issue Issue data + * @return boolean + */ + public function handleIssueOpened(array $issue) + { + $event = array( + 'project_id' => $this->project_id, + 'reference' => $issue['number'], + 'title' => $issue['title'], + 'description' => $issue['body']."\n\n[".t('Github Issue').']('.$issue['html_url'].')', + ); + + $this->container['dispatcher']->dispatch( + self::EVENT_ISSUE_OPENED, + new GenericEvent($event) + ); + + return true; + } + + /** + * Handle issue closing + * + * @access public + * @param array $issue Issue data + * @return boolean + */ + public function handleIssueClosed(array $issue) + { + $task = $this->taskFinder->getByReference($issue['number']); + + if ($task) { + $event = array( + 'project_id' => $this->project_id, + 'task_id' => $task['id'], + 'reference' => $issue['number'], + ); + + $this->container['dispatcher']->dispatch( + self::EVENT_ISSUE_CLOSED, + new GenericEvent($event) + ); + + return true; + } + + return false; + } + + /** + * Handle issue reopened + * + * @access public + * @param array $issue Issue data + * @return boolean + */ + public function handleIssueReopened(array $issue) + { + $task = $this->taskFinder->getByReference($issue['number']); + + if ($task) { + $event = array( + 'project_id' => $this->project_id, + 'task_id' => $task['id'], + 'reference' => $issue['number'], + ); + + $this->container['dispatcher']->dispatch( + self::EVENT_ISSUE_REOPENED, + new GenericEvent($event) + ); + + return true; + } + + return false; + } + + /** + * Handle issue assignee change + * + * @access public + * @param array $issue Issue data + * @return boolean + */ + public function handleIssueAssigned(array $issue) + { + $user = $this->user->getByUsername($issue['assignee']['login']); + $task = $this->taskFinder->getByReference($issue['number']); + + if ($user && $task) { + + $event = array( + 'project_id' => $this->project_id, + 'task_id' => $task['id'], + 'owner_id' => $user['id'], + 'reference' => $issue['number'], + ); + + $this->container['dispatcher']->dispatch( + self::EVENT_ISSUE_ASSIGNEE_CHANGE, + new GenericEvent($event) + ); + + return true; + } + + return false; + } + + /** + * Handle unassigned issue + * + * @access public + * @param array $issue Issue data + * @return boolean + */ + public function handleIssueUnassigned(array $issue) + { + $task = $this->taskFinder->getByReference($issue['number']); + + if ($task) { + + $event = array( + 'project_id' => $this->project_id, + 'task_id' => $task['id'], + 'owner_id' => 0, + 'reference' => $issue['number'], + ); + + $this->container['dispatcher']->dispatch( + self::EVENT_ISSUE_ASSIGNEE_CHANGE, + new GenericEvent($event) + ); + + return true; + } + + return false; + } + + /** + * Handle labeled issue + * + * @access public + * @param array $issue Issue data + * @param array $label Label data + * @return boolean + */ + public function handleIssueLabeled(array $issue, array $label) + { + $task = $this->taskFinder->getByReference($issue['number']); + + if ($task) { + + $event = array( + 'project_id' => $this->project_id, + 'task_id' => $task['id'], + 'reference' => $issue['number'], + 'label' => $label['name'], + ); + + $this->container['dispatcher']->dispatch( + self::EVENT_ISSUE_LABEL_CHANGE, + new GenericEvent($event) + ); + + return true; + } + + return false; + } + + /** + * Handle unlabeled issue + * + * @access public + * @param array $issue Issue data + * @param array $label Label data + * @return boolean + */ + public function handleIssueUnlabeled(array $issue, array $label) + { + $task = $this->taskFinder->getByReference($issue['number']); + + if ($task) { + + $event = array( + 'project_id' => $this->project_id, + 'task_id' => $task['id'], + 'reference' => $issue['number'], + 'label' => $label['name'], + 'category_id' => 0, + ); + + $this->container['dispatcher']->dispatch( + self::EVENT_ISSUE_LABEL_CHANGE, + new GenericEvent($event) + ); + + return true; + } + + return false; + } +} diff --git a/app/Integration/GitlabWebhook.php b/app/Integration/GitlabWebhook.php new file mode 100644 index 00000000..f5df32a6 --- /dev/null +++ b/app/Integration/GitlabWebhook.php @@ -0,0 +1,213 @@ +project_id = $project_id; + } + + /** + * Parse events + * + * @access public + * @param array $payload Gitlab event + * @return boolean + */ + public function parsePayload(array $payload) + { + switch ($this->getType($payload)) { + case self::TYPE_PUSH: + return $this->handlePushEvent($payload); + case self::TYPE_ISSUE; + return $this->handleIssueEvent($payload); + } + + return false; + } + + /** + * Get event type + * + * @access public + * @param array $payload Gitlab event + * @return string + */ + public function getType(array $payload) + { + if (isset($payload['object_kind']) && $payload['object_kind'] === 'issue') { + return self::TYPE_ISSUE; + } + + if (isset($payload['commits'])) { + return self::TYPE_PUSH; + } + + return ''; + } + + /** + * Parse push event + * + * @access public + * @param array $payload Gitlab event + * @return boolean + */ + public function handlePushEvent(array $payload) + { + foreach ($payload['commits'] as $commit) { + $this->handleCommit($commit); + } + + return true; + } + + /** + * Parse commit + * + * @access public + * @param array $commit Gitlab commit + * @return boolean + */ + public function handleCommit(array $commit) + { + $task_id = $this->task->getTaskIdFromText($commit['message']); + + if (! $task_id) { + return false; + } + + $task = $this->taskFinder->getById($task_id); + + if (! $task) { + return false; + } + + if ($task['is_active'] == Task::STATUS_OPEN && $task['project_id'] == $this->project_id) { + + $this->container['dispatcher']->dispatch( + self::EVENT_COMMIT, + new TaskEvent(array('task_id' => $task_id) + $task) + ); + + return true; + } + + return false; + } + + /** + * Parse issue event + * + * @access public + * @param array $payload Gitlab event + * @return boolean + */ + public function handleIssueEvent(array $payload) + { + switch ($payload['object_attributes']['state']) { + case 'opened': + return $this->handleIssueOpened($payload['object_attributes']); + case 'closed': + return $this->handleIssueClosed($payload['object_attributes']); + } + + return false; + } + + /** + * Handle new issues + * + * @access public + * @param array $issue Issue data + * @return boolean + */ + public function handleIssueOpened(array $issue) + { + $event = array( + 'project_id' => $this->project_id, + 'reference' => $issue['id'], + 'title' => $issue['title'], + 'description' => $issue['description']."\n\n[".t('Gitlab Issue').']('.$issue['url'].')', + ); + + $this->container['dispatcher']->dispatch( + self::EVENT_ISSUE_OPENED, + new GenericEvent($event) + ); + + return true; + } + + /** + * Handle issue closing + * + * @access public + * @param array $issue Issue data + * @return boolean + */ + public function handleIssueClosed(array $issue) + { + $task = $this->taskFinder->getByReference($issue['id']); + + if ($task) { + $event = array( + 'project_id' => $this->project_id, + 'task_id' => $task['id'], + 'reference' => $issue['id'], + ); + + $this->container['dispatcher']->dispatch( + self::EVENT_ISSUE_CLOSED, + new GenericEvent($event) + ); + + return true; + } + + return false; + } +} diff --git a/app/Locale/da_DK/translations.php b/app/Locale/da_DK/translations.php index b6227771..a0c04610 100644 --- a/app/Locale/da_DK/translations.php +++ b/app/Locale/da_DK/translations.php @@ -556,8 +556,8 @@ return array( // 'Webhooks' => '', // 'API' => '', // 'Integration' => '', - // 'Github webhook' => '', - // 'Help on Github webhook' => '', + // 'Github webhooks' => '', + // 'Help on Github webhooks' => '', // 'Create a comment from an external provider' => '', // 'Github issue comment created' => '', // 'Configure' => '', @@ -626,4 +626,11 @@ return array( // 'Your swimlane have been created successfully.' => '', // 'Example: "Bug, Feature Request, Improvement"' => '', // 'Default categories for new projects (Comma-separated)' => '', + // 'Gitlab commit received' => '', + // 'Gitlab issue opened' => '', + // 'Gitlab issue closed' => '', + // 'Gitlab webhooks' => '', + // 'Help on Gitlab webhooks' => '', + // 'Integrations' => '', + // 'Integration with third-party services' => '', ); diff --git a/app/Locale/de_DE/translations.php b/app/Locale/de_DE/translations.php index f9d8e714..b03ef801 100644 --- a/app/Locale/de_DE/translations.php +++ b/app/Locale/de_DE/translations.php @@ -556,8 +556,8 @@ return array( 'Webhooks' => 'Webhooks', 'API' => 'API', 'Integration' => 'Integration', - 'Github webhook' => 'Github Webhook', - 'Help on Github webhook' => 'Hilfe bei einem Github Webhook', + 'Github webhooks' => 'Github Webhook', + 'Help on Github webhooks' => 'Hilfe bei einem Github Webhook', 'Create a comment from an external provider' => 'Kommentar eines externen Providers hinzufügen', 'Github issue comment created' => 'Github Fehler Kommentar hinzugefügt', 'Configure' => 'konfigurieren', @@ -626,4 +626,11 @@ return array( // 'Your swimlane have been created successfully.' => '', // 'Example: "Bug, Feature Request, Improvement"' => '', // 'Default categories for new projects (Comma-separated)' => '', + // 'Gitlab commit received' => '', + // 'Gitlab issue opened' => '', + // 'Gitlab issue closed' => '', + // 'Gitlab webhooks' => '', + // 'Help on Gitlab webhooks' => '', + // 'Integrations' => '', + // 'Integration with third-party services' => '', ); diff --git a/app/Locale/es_ES/translations.php b/app/Locale/es_ES/translations.php index 1f4a3d87..527e3b95 100644 --- a/app/Locale/es_ES/translations.php +++ b/app/Locale/es_ES/translations.php @@ -556,8 +556,8 @@ return array( // 'Webhooks' => '', // 'API' => '', // 'Integration' => '', - // 'Github webhook' => '', - // 'Help on Github webhook' => '', + // 'Github webhooks' => '', + // 'Help on Github webhooks' => '', // 'Create a comment from an external provider' => '', // 'Github issue comment created' => '', // 'Configure' => '', @@ -626,4 +626,11 @@ return array( // 'Your swimlane have been created successfully.' => '', // 'Example: "Bug, Feature Request, Improvement"' => '', // 'Default categories for new projects (Comma-separated)' => '', + // 'Gitlab commit received' => '', + // 'Gitlab issue opened' => '', + // 'Gitlab issue closed' => '', + // 'Gitlab webhooks' => '', + // 'Help on Gitlab webhooks' => '', + // 'Integrations' => '', + // 'Integration with third-party services' => '', ); diff --git a/app/Locale/fi_FI/translations.php b/app/Locale/fi_FI/translations.php index 25cf67c3..98fcfdc8 100644 --- a/app/Locale/fi_FI/translations.php +++ b/app/Locale/fi_FI/translations.php @@ -556,8 +556,8 @@ return array( // 'Webhooks' => '', // 'API' => '', // 'Integration' => '', - // 'Github webhook' => '', - // 'Help on Github webhook' => '', + // 'Github webhooks' => '', + // 'Help on Github webhooks' => '', // 'Create a comment from an external provider' => '', // 'Github issue comment created' => '', // 'Configure' => '', @@ -626,4 +626,11 @@ return array( // 'Your swimlane have been created successfully.' => '', // 'Example: "Bug, Feature Request, Improvement"' => '', // 'Default categories for new projects (Comma-separated)' => '', + // 'Gitlab commit received' => '', + // 'Gitlab issue opened' => '', + // 'Gitlab issue closed' => '', + // 'Gitlab webhooks' => '', + // 'Help on Gitlab webhooks' => '', + // 'Integrations' => '', + // 'Integration with third-party services' => '', ); diff --git a/app/Locale/fr_FR/translations.php b/app/Locale/fr_FR/translations.php index fb281f13..ef52d333 100644 --- a/app/Locale/fr_FR/translations.php +++ b/app/Locale/fr_FR/translations.php @@ -556,8 +556,8 @@ return array( 'Webhooks' => 'Webhooks', 'API' => 'API', 'Integration' => 'Intégration', - 'Github webhook' => 'Webhook Github', - 'Help on Github webhook' => 'Aide sur les webhooks Github', + 'Github webhooks' => 'Webhook Github', + 'Help on Github webhooks' => 'Aide sur les webhooks Github', 'Create a comment from an external provider' => 'Créer un commentaire depuis un fournisseur externe', 'Github issue comment created' => 'Commentaire créé sur un ticket Github', 'Configure' => 'Configurer', @@ -626,4 +626,11 @@ return array( 'Your swimlane have been created successfully.' => 'Votre swimlane a été créée avec succès.', 'Example: "Bug, Feature Request, Improvement"' => 'Exemple: « Incident, Demande de fonctionnalité, Amélioration »', 'Default categories for new projects (Comma-separated)' => 'Catégories par défaut pour les nouveaux projets (séparé par des virgules)', + 'Gitlab commit received' => '« Commit » reçu via Gitlab', + 'Gitlab issue opened' => 'Ouverture d\'un ticket sur Gitlab', + 'Gitlab issue closed' => 'Fermeture d\'un ticket sur Gitlab', + 'Gitlab webhooks' => 'Webhook Gitlab', + 'Help on Gitlab webhooks' => 'Aide sur les webhooks Gitlab', + 'Integrations' => 'Intégrations', + 'Integration with third-party services' => 'Intégration avec des services externes', ); diff --git a/app/Locale/hu_HU/translations.php b/app/Locale/hu_HU/translations.php index 7188d197..5dbbe988 100644 --- a/app/Locale/hu_HU/translations.php +++ b/app/Locale/hu_HU/translations.php @@ -556,8 +556,8 @@ return array( 'Webhooks' => 'Webhook', 'API' => 'API', 'Integration' => 'Integráció', - 'Github webhook' => 'Github webhook', - 'Help on Github webhook' => 'Github Webhook súgó', + 'Github webhooks' => 'Github webhooks', + 'Help on Github webhooks' => 'Github Webhook súgó', 'Create a comment from an external provider' => 'Megjegyzés létrehozása külső felhasználótól', 'Github issue comment created' => 'Github issue megjegyzés létrehozva', 'Configure' => 'Konfigurál', @@ -626,4 +626,11 @@ return array( // 'Your swimlane have been created successfully.' => '', // 'Example: "Bug, Feature Request, Improvement"' => '', // 'Default categories for new projects (Comma-separated)' => '', + // 'Gitlab commit received' => '', + // 'Gitlab issue opened' => '', + // 'Gitlab issue closed' => '', + // 'Gitlab webhooks' => '', + // 'Help on Gitlab webhooks' => '', + // 'Integrations' => '', + // 'Integration with third-party services' => '', ); diff --git a/app/Locale/it_IT/translations.php b/app/Locale/it_IT/translations.php index 3117a068..7bd48a2b 100644 --- a/app/Locale/it_IT/translations.php +++ b/app/Locale/it_IT/translations.php @@ -556,8 +556,8 @@ return array( // 'Webhooks' => '', // 'API' => '', // 'Integration' => '', - // 'Github webhook' => '', - // 'Help on Github webhook' => '', + // 'Github webhooks' => '', + // 'Help on Github webhooks' => '', // 'Create a comment from an external provider' => '', // 'Github issue comment created' => '', // 'Configure' => '', @@ -626,4 +626,11 @@ return array( // 'Your swimlane have been created successfully.' => '', // 'Example: "Bug, Feature Request, Improvement"' => '', // 'Default categories for new projects (Comma-separated)' => '', + // 'Gitlab commit received' => '', + // 'Gitlab issue opened' => '', + // 'Gitlab issue closed' => '', + // 'Gitlab webhooks' => '', + // 'Help on Gitlab webhooks' => '', + // 'Integrations' => '', + // 'Integration with third-party services' => '', ); diff --git a/app/Locale/ja_JP/translations.php b/app/Locale/ja_JP/translations.php index 60ded536..b519d68c 100644 --- a/app/Locale/ja_JP/translations.php +++ b/app/Locale/ja_JP/translations.php @@ -556,8 +556,8 @@ return array( // 'Webhooks' => '', // 'API' => '', // 'Integration' => '', - // 'Github webhook' => '', - // 'Help on Github webhook' => '', + // 'Github webhooks' => '', + // 'Help on Github webhooks' => '', // 'Create a comment from an external provider' => '', // 'Github issue comment created' => '', // 'Configure' => '', @@ -626,4 +626,11 @@ return array( // 'Your swimlane have been created successfully.' => '', // 'Example: "Bug, Feature Request, Improvement"' => '', // 'Default categories for new projects (Comma-separated)' => '', + // 'Gitlab commit received' => '', + // 'Gitlab issue opened' => '', + // 'Gitlab issue closed' => '', + // 'Gitlab webhooks' => '', + // 'Help on Gitlab webhooks' => '', + // 'Integrations' => '', + // 'Integration with third-party services' => '', ); diff --git a/app/Locale/pl_PL/translations.php b/app/Locale/pl_PL/translations.php index 1c0492ed..bcab4874 100644 --- a/app/Locale/pl_PL/translations.php +++ b/app/Locale/pl_PL/translations.php @@ -556,8 +556,8 @@ return array( // 'Webhooks' => '', // 'API' => '', // 'Integration' => '', - // 'Github webhook' => '', - // 'Help on Github webhook' => '', + // 'Github webhooks' => '', + // 'Help on Github webhooks' => '', // 'Create a comment from an external provider' => '', // 'Github issue comment created' => '', // 'Configure' => '', @@ -626,4 +626,11 @@ return array( // 'Your swimlane have been created successfully.' => '', // 'Example: "Bug, Feature Request, Improvement"' => '', // 'Default categories for new projects (Comma-separated)' => '', + // 'Gitlab commit received' => '', + // 'Gitlab issue opened' => '', + // 'Gitlab issue closed' => '', + // 'Gitlab webhooks' => '', + // 'Help on Gitlab webhooks' => '', + // 'Integrations' => '', + // 'Integration with third-party services' => '', ); diff --git a/app/Locale/pt_BR/translations.php b/app/Locale/pt_BR/translations.php index 28858ec5..48c15f61 100644 --- a/app/Locale/pt_BR/translations.php +++ b/app/Locale/pt_BR/translations.php @@ -556,8 +556,8 @@ return array( // 'Webhooks' => '', // 'API' => '', 'Integration' => 'Integração', - // 'Github webhook' => '', - 'Help on Github webhook' => 'Ajuda para o Github webhook', + // 'Github webhooks' => '', + 'Help on Github webhooks' => 'Ajuda para o Github webhooks', 'Create a comment from an external provider' => 'Criar um comentário de um provedor externo', // 'Github issue comment created' => '', 'Configure' => 'Configurar', @@ -626,4 +626,11 @@ return array( // 'Your swimlane have been created successfully.' => '', // 'Example: "Bug, Feature Request, Improvement"' => '', // 'Default categories for new projects (Comma-separated)' => '', + // 'Gitlab commit received' => '', + // 'Gitlab issue opened' => '', + // 'Gitlab issue closed' => '', + // 'Gitlab webhooks' => '', + // 'Help on Gitlab webhooks' => '', + // 'Integrations' => '', + // 'Integration with third-party services' => '', ); diff --git a/app/Locale/ru_RU/translations.php b/app/Locale/ru_RU/translations.php index 5d58ca25..08fc35de 100644 --- a/app/Locale/ru_RU/translations.php +++ b/app/Locale/ru_RU/translations.php @@ -556,8 +556,8 @@ return array( // 'Webhooks' => '', // 'API' => '', // 'Integration' => '', - // 'Github webhook' => '', - // 'Help on Github webhook' => '', + // 'Github webhooks' => '', + // 'Help on Github webhooks' => '', // 'Create a comment from an external provider' => '', // 'Github issue comment created' => '', // 'Configure' => '', @@ -626,4 +626,11 @@ return array( // 'Your swimlane have been created successfully.' => '', // 'Example: "Bug, Feature Request, Improvement"' => '', // 'Default categories for new projects (Comma-separated)' => '', + // 'Gitlab commit received' => '', + // 'Gitlab issue opened' => '', + // 'Gitlab issue closed' => '', + // 'Gitlab webhooks' => '', + // 'Help on Gitlab webhooks' => '', + // 'Integrations' => '', + // 'Integration with third-party services' => '', ); diff --git a/app/Locale/sv_SE/translations.php b/app/Locale/sv_SE/translations.php index cd0bb2bf..b33983ca 100644 --- a/app/Locale/sv_SE/translations.php +++ b/app/Locale/sv_SE/translations.php @@ -556,8 +556,8 @@ return array( // 'Webhooks' => '', // 'API' => '', // 'Integration' => '', - // 'Github webhook' => '', - // 'Help on Github webhook' => '', + // 'Github webhooks' => '', + // 'Help on Github webhooks' => '', // 'Create a comment from an external provider' => '', // 'Github issue comment created' => '', // 'Configure' => '', @@ -626,4 +626,11 @@ return array( // 'Your swimlane have been created successfully.' => '', // 'Example: "Bug, Feature Request, Improvement"' => '', // 'Default categories for new projects (Comma-separated)' => '', + // 'Gitlab commit received' => '', + // 'Gitlab issue opened' => '', + // 'Gitlab issue closed' => '', + // 'Gitlab webhooks' => '', + // 'Help on Gitlab webhooks' => '', + // 'Integrations' => '', + // 'Integration with third-party services' => '', ); diff --git a/app/Locale/th_TH/translations.php b/app/Locale/th_TH/translations.php index 7331d877..0dbe486c 100644 --- a/app/Locale/th_TH/translations.php +++ b/app/Locale/th_TH/translations.php @@ -556,8 +556,8 @@ return array( // 'Webhooks' => '', // 'API' => '', // 'Integration' => '', - // 'Github webhook' => '', - // 'Help on Github webhook' => '', + // 'Github webhooks' => '', + // 'Help on Github webhooks' => '', // 'Create a comment from an external provider' => '', // 'Github issue comment created' => '', // 'Configure' => '', @@ -626,4 +626,11 @@ return array( // 'Your swimlane have been created successfully.' => '', // 'Example: "Bug, Feature Request, Improvement"' => '', // 'Default categories for new projects (Comma-separated)' => '', + // 'Gitlab commit received' => '', + // 'Gitlab issue opened' => '', + // 'Gitlab issue closed' => '', + // 'Gitlab webhooks' => '', + // 'Help on Gitlab webhooks' => '', + // 'Integrations' => '', + // 'Integration with third-party services' => '', ); diff --git a/app/Locale/zh_CN/translations.php b/app/Locale/zh_CN/translations.php index 455e37ed..b77a21d0 100644 --- a/app/Locale/zh_CN/translations.php +++ b/app/Locale/zh_CN/translations.php @@ -556,8 +556,8 @@ return array( 'Webhooks' => '网络钩子', 'API' => '应用程序接口', 'Integration' => '整合', - 'Github webhook' => 'Github 网络钩子', - 'Help on Github webhook' => 'Github 网络钩子帮助', + 'Github webhooks' => 'Github 网络钩子', + 'Help on Github webhooks' => 'Github 网络钩子帮助', 'Create a comment from an external provider' => '从外部创建一个评论', 'Github issue comment created' => '已经创建了Github问题评论', 'Configure' => '配置', @@ -626,4 +626,11 @@ return array( 'Your swimlane have been created successfully.' => '已经成功创建泳道。', // 'Example: "Bug, Feature Request, Improvement"' => '', // 'Default categories for new projects (Comma-separated)' => '', + // 'Gitlab commit received' => '', + // 'Gitlab issue opened' => '', + // 'Gitlab issue closed' => '', + // 'Gitlab webhooks' => '', + // 'Help on Gitlab webhooks' => '', + // 'Integrations' => '', + // 'Integration with third-party services' => '', ); diff --git a/app/Model/Acl.php b/app/Model/Acl.php index 3f454885..d294197a 100644 --- a/app/Model/Acl.php +++ b/app/Model/Acl.php @@ -21,7 +21,7 @@ class Acl extends Base 'task' => array('readonly'), 'board' => array('readonly'), 'project' => array('feed'), - 'webhook' => array('task', 'github'), + 'webhook' => array('task', 'github', 'gitlab'), ); /** diff --git a/app/Model/Action.php b/app/Model/Action.php index 36e0aa62..905b8914 100644 --- a/app/Model/Action.php +++ b/app/Model/Action.php @@ -2,6 +2,8 @@ namespace Model; +use Integration\GitlabWebhook; +use Integration\GithubWebhook; use SimpleValidator\Validator; use SimpleValidator\Validators; @@ -79,6 +81,9 @@ class Action extends Base GithubWebhook::EVENT_ISSUE_ASSIGNEE_CHANGE => t('Github issue assignee change'), GithubWebhook::EVENT_ISSUE_LABEL_CHANGE => t('Github issue label change'), GithubWebhook::EVENT_ISSUE_COMMENT => t('Github issue comment created'), + GitlabWebhook::EVENT_COMMIT => t('Gitlab commit received'), + GitlabWebhook::EVENT_ISSUE_OPENED => t('Gitlab issue opened'), + GitlabWebhook::EVENT_ISSUE_CLOSED => t('Gitlab issue closed'), ); asort($values); diff --git a/app/Model/Base.php b/app/Model/Base.php index dfac12ae..db670969 100644 --- a/app/Model/Base.php +++ b/app/Model/Base.php @@ -29,6 +29,7 @@ use Pimple\Container; * @property \Model\ProjectPermission $projectPermission * @property \Model\SubTask $subTask * @property \Model\SubtaskHistory $subtaskHistory + * @property \Model\Swimlane $swimlane * @property \Model\Task $task * @property \Model\TaskCreation $taskCreation * @property \Model\TaskExport $taskExport diff --git a/app/Model/GithubWebhook.php b/app/Model/GithubWebhook.php deleted file mode 100644 index f66358eb..00000000 --- a/app/Model/GithubWebhook.php +++ /dev/null @@ -1,374 +0,0 @@ -project_id = $project_id; - } - - /** - * Parse Github events - * - * @access public - * @param string $type Github event type - * @param array $payload Github event - * @return boolean - */ - public function parsePayload($type, array $payload) - { - switch ($type) { - case 'push': - return $this->parsePushEvent($payload); - case 'issues': - return $this->parseIssueEvent($payload); - case 'issue_comment': - return $this->parseCommentIssueEvent($payload); - } - - return false; - } - - /** - * Parse Push events (list of commits) - * - * @access public - * @param array $payload Event data - * @return boolean - */ - public function parsePushEvent(array $payload) - { - foreach ($payload['commits'] as $commit) { - - $task_id = $this->task->getTaskIdFromText($commit['message']); - - if (! $task_id) { - continue; - } - - $task = $this->taskFinder->getById($task_id); - - if (! $task) { - continue; - } - - if ($task['is_active'] == Task::STATUS_OPEN) { - $this->container['dispatcher']->dispatch( - self::EVENT_COMMIT, - new GenericEvent(array('task_id' => $task_id) + $task) - ); - } - } - - return true; - } - - /** - * Parse issue events - * - * @access public - * @param array $payload Event data - * @return boolean - */ - public function parseIssueEvent(array $payload) - { - switch ($payload['action']) { - case 'opened': - return $this->handleIssueOpened($payload['issue']); - case 'closed': - return $this->handleIssueClosed($payload['issue']); - case 'reopened': - return $this->handleIssueReopened($payload['issue']); - case 'assigned': - return $this->handleIssueAssigned($payload['issue']); - case 'unassigned': - return $this->handleIssueUnassigned($payload['issue']); - case 'labeled': - return $this->handleIssueLabeled($payload['issue'], $payload['label']); - case 'unlabeled': - return $this->handleIssueUnlabeled($payload['issue'], $payload['label']); - } - - return false; - } - - /** - * Parse comment issue events - * - * @access public - * @param array $payload Event data - * @return boolean - */ - public function parseCommentIssueEvent(array $payload) - { - $task = $this->taskFinder->getByReference($payload['issue']['number']); - $user = $this->user->getByUsername($payload['comment']['user']['login']); - - if ($task && $user) { - - $event = array( - 'project_id' => $this->project_id, - 'reference' => $payload['comment']['id'], - 'comment' => $payload['comment']['body'], - 'user_id' => $user['id'], - 'task_id' => $task['id'], - ); - - $this->container['dispatcher']->dispatch( - self::EVENT_ISSUE_COMMENT, - new GenericEvent($event) - ); - - return true; - } - - return false; - } - - /** - * Handle new issues - * - * @access public - * @param array $issue Issue data - * @return boolean - */ - public function handleIssueOpened(array $issue) - { - $event = array( - 'project_id' => $this->project_id, - 'reference' => $issue['number'], - 'title' => $issue['title'], - 'description' => $issue['body']."\n\n[".t('Github Issue').']('.$issue['html_url'].')', - ); - - $this->container['dispatcher']->dispatch( - self::EVENT_ISSUE_OPENED, - new GenericEvent($event) - ); - - return true; - } - - /** - * Handle issue closing - * - * @access public - * @param array $issue Issue data - * @return boolean - */ - public function handleIssueClosed(array $issue) - { - $task = $this->taskFinder->getByReference($issue['number']); - - if ($task) { - $event = array( - 'project_id' => $this->project_id, - 'task_id' => $task['id'], - 'reference' => $issue['number'], - ); - - $this->container['dispatcher']->dispatch( - self::EVENT_ISSUE_CLOSED, - new GenericEvent($event) - ); - - return true; - } - - return false; - } - - /** - * Handle issue reopened - * - * @access public - * @param array $issue Issue data - * @return boolean - */ - public function handleIssueReopened(array $issue) - { - $task = $this->taskFinder->getByReference($issue['number']); - - if ($task) { - $event = array( - 'project_id' => $this->project_id, - 'task_id' => $task['id'], - 'reference' => $issue['number'], - ); - - $this->container['dispatcher']->dispatch( - self::EVENT_ISSUE_REOPENED, - new GenericEvent($event) - ); - - return true; - } - - return false; - } - - /** - * Handle issue assignee change - * - * @access public - * @param array $issue Issue data - * @return boolean - */ - public function handleIssueAssigned(array $issue) - { - $user = $this->user->getByUsername($issue['assignee']['login']); - $task = $this->taskFinder->getByReference($issue['number']); - - if ($user && $task) { - - $event = array( - 'project_id' => $this->project_id, - 'task_id' => $task['id'], - 'owner_id' => $user['id'], - 'reference' => $issue['number'], - ); - - $this->container['dispatcher']->dispatch( - self::EVENT_ISSUE_ASSIGNEE_CHANGE, - new GenericEvent($event) - ); - - return true; - } - - return false; - } - - /** - * Handle unassigned issue - * - * @access public - * @param array $issue Issue data - * @return boolean - */ - public function handleIssueUnassigned(array $issue) - { - $task = $this->taskFinder->getByReference($issue['number']); - - if ($task) { - - $event = array( - 'project_id' => $this->project_id, - 'task_id' => $task['id'], - 'owner_id' => 0, - 'reference' => $issue['number'], - ); - - $this->container['dispatcher']->dispatch( - self::EVENT_ISSUE_ASSIGNEE_CHANGE, - new GenericEvent($event) - ); - - return true; - } - - return false; - } - - /** - * Handle labeled issue - * - * @access public - * @param array $issue Issue data - * @param array $label Label data - * @return boolean - */ - public function handleIssueLabeled(array $issue, array $label) - { - $task = $this->taskFinder->getByReference($issue['number']); - - if ($task) { - - $event = array( - 'project_id' => $this->project_id, - 'task_id' => $task['id'], - 'reference' => $issue['number'], - 'label' => $label['name'], - ); - - $this->container['dispatcher']->dispatch( - self::EVENT_ISSUE_LABEL_CHANGE, - new GenericEvent($event) - ); - - return true; - } - - return false; - } - - /** - * Handle unlabeled issue - * - * @access public - * @param array $issue Issue data - * @param array $label Label data - * @return boolean - */ - public function handleIssueUnlabeled(array $issue, array $label) - { - $task = $this->taskFinder->getByReference($issue['number']); - - if ($task) { - - $event = array( - 'project_id' => $this->project_id, - 'task_id' => $task['id'], - 'reference' => $issue['number'], - 'label' => $label['name'], - 'category_id' => 0, - ); - - $this->container['dispatcher']->dispatch( - self::EVENT_ISSUE_LABEL_CHANGE, - new GenericEvent($event) - ); - - return true; - } - - return false; - } -} diff --git a/app/ServiceProvider/ClassProvider.php b/app/ServiceProvider/ClassProvider.php index acba26d4..645a85ef 100644 --- a/app/ServiceProvider/ClassProvider.php +++ b/app/ServiceProvider/ClassProvider.php @@ -22,7 +22,6 @@ class ClassProvider implements ServiceProviderInterface 'Config', 'DateParser', 'File', - 'GithubWebhook', 'LastLogin', 'Notification', 'Project', @@ -53,6 +52,10 @@ class ClassProvider implements ServiceProviderInterface 'Template', 'Session', ), + 'Integration' => array( + 'GitlabWebhook', + 'GithubWebhook', + ) ); public function register(Container $container) diff --git a/app/Subscriber/ProjectModificationDateSubscriber.php b/app/Subscriber/ProjectModificationDateSubscriber.php index 3d5484f7..cd83f370 100644 --- a/app/Subscriber/ProjectModificationDateSubscriber.php +++ b/app/Subscriber/ProjectModificationDateSubscriber.php @@ -4,7 +4,7 @@ namespace Subscriber; use Event\GenericEvent; use Model\Task; -use Model\GithubWebhook; +use Integration\GithubWebhook; use Symfony\Component\EventDispatcher\EventSubscriberInterface; class ProjectModificationDateSubscriber extends Base implements EventSubscriberInterface diff --git a/app/Template/project/integrations.php b/app/Template/project/integrations.php new file mode 100644 index 00000000..8ec43f90 --- /dev/null +++ b/app/Template/project/integrations.php @@ -0,0 +1,15 @@ + + +

 

+
+
+

+
+ +

 

+
+
+

+
\ No newline at end of file diff --git a/app/Template/project/show.php b/app/Template/project/show.php index 22d710e6..bc622d0d 100644 --- a/app/Template/project/show.php +++ b/app/Template/project/show.php @@ -53,14 +53,3 @@ - -acl->isAdminUser()): ?> - - -

-
-

- - diff --git a/app/Template/project/sidebar.php b/app/Template/project/sidebar.php index 35019fdb..52a971d6 100644 --- a/app/Template/project/sidebar.php +++ b/app/Template/project/sidebar.php @@ -9,6 +9,9 @@
  • a(t('Public access'), 'project', 'share', array('project_id' => $project['id'])) ?>
  • +
  • + a(t('Integrations'), 'project', 'integration', array('project_id' => $project['id'])) ?> +
  • a(t('Edit project'), 'project', 'edit', array('project_id' => $project['id'])) ?>
  • -- cgit v1.2.3