summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app/Controller/Webhook.php61
-rw-r--r--app/Core/Request.php2
-rw-r--r--app/Model/Acl.php3
-rw-r--r--app/Model/Action.php1
-rw-r--r--app/Model/GithubWebhook.php81
-rw-r--r--app/Model/Task.php18
-rw-r--r--app/functions.php4
7 files changed, 168 insertions, 2 deletions
diff --git a/app/Controller/Webhook.php b/app/Controller/Webhook.php
new file mode 100644
index 00000000..8a81a0c4
--- /dev/null
+++ b/app/Controller/Webhook.php
@@ -0,0 +1,61 @@
+<?php
+
+namespace Controller;
+
+/**
+ * Webhook controller
+ *
+ * @package controller
+ * @author Frederic Guillot
+ */
+class Webhook extends Base
+{
+ /**
+ * Webhook to create a task
+ *
+ * @access public
+ */
+ public function task()
+ {
+ if ($this->config->get('webhooks_token') !== $this->request->getStringParam('token')) {
+ $this->response->text('Not Authorized', 401);
+ }
+
+ $defaultProject = $this->project->getFirst();
+
+ $values = array(
+ 'title' => $this->request->getStringParam('title'),
+ 'description' => $this->request->getStringParam('description'),
+ 'color_id' => $this->request->getStringParam('color_id'),
+ 'project_id' => $this->request->getIntegerParam('project_id', $defaultProject['id']),
+ 'owner_id' => $this->request->getIntegerParam('owner_id'),
+ 'column_id' => $this->request->getIntegerParam('column_id'),
+ 'category_id' => $this->request->getIntegerParam('category_id'),
+ );
+
+ list($valid,) = $this->taskValidator->validateCreation($values);
+
+ if ($valid && $this->task->create($values)) {
+ $this->response->text('OK');
+ }
+
+ $this->response->text('FAILED');
+ }
+
+ /**
+ * Handle Github webhooks
+ *
+ * @access public
+ */
+ public function github()
+ {
+ if ($this->config->get('webhooks_token') !== $this->request->getStringParam('token')) {
+ $this->response->text('Not Authorized', 401);
+ }
+
+ $this->githubWebhook->parsePayload(
+ $this->request->getHeader('X-Github-Event'),
+ $this->request->getBody()
+ );
+ }
+}
diff --git a/app/Core/Request.php b/app/Core/Request.php
index e86cf609..09792013 100644
--- a/app/Core/Request.php
+++ b/app/Core/Request.php
@@ -145,7 +145,7 @@ class Request
*/
public function getQueryString()
{
- return $_SERVER['QUERY_STRING'];
+ return isset($_SERVER['QUERY_STRING']) ? $_SERVER['QUERY_STRING'] : '';
}
}
diff --git a/app/Model/Acl.php b/app/Model/Acl.php
index aea13e8c..f92b3021 100644
--- a/app/Model/Acl.php
+++ b/app/Model/Acl.php
@@ -18,9 +18,10 @@ class Acl extends Base
*/
private $public_actions = array(
'user' => array('login', 'check', 'google', 'github'),
- 'task' => array('add', 'readonly'),
+ 'task' => array('readonly'),
'board' => array('readonly'),
'project' => array('feed'),
+ 'webhook' => array('task', 'github'),
);
/**
diff --git a/app/Model/Action.php b/app/Model/Action.php
index a318c5b0..a0c992aa 100644
--- a/app/Model/Action.php
+++ b/app/Model/Action.php
@@ -65,6 +65,7 @@ class Action extends Base
Task::EVENT_CLOSE => t('Closing a task'),
Task::EVENT_CREATE_UPDATE => t('Task creation or modification'),
Task::EVENT_ASSIGNEE_CHANGE => t('Task assignee change'),
+ GithubWebhook::EVENT_COMMIT => t('Github commit received'),
);
}
diff --git a/app/Model/GithubWebhook.php b/app/Model/GithubWebhook.php
new file mode 100644
index 00000000..688ab601
--- /dev/null
+++ b/app/Model/GithubWebhook.php
@@ -0,0 +1,81 @@
+<?php
+
+namespace Model;
+
+/**
+ * Github Webhook model
+ *
+ * @package model
+ * @author Frederic Guillot
+ */
+class GithubWebhook extends Base
+{
+ /**
+ * Events
+ *
+ * @var string
+ */
+ const EVENT_ISSUE_OPENED = 'github.webhook.issue.opened';
+ const EVENT_ISSUE_CLOSED = 'github.webhook.issue.closed';
+ const EVENT_ISSUE_LABELED = 'github.webhook.issue.labeled';
+ const EVENT_ISSUE_COMMENT = 'github.webhook.issue.commented';
+ const EVENT_COMMIT = 'github.webhook.commit';
+
+ /**
+ * Parse Github events
+ *
+ * @access public
+ * @param string $type Github event type
+ * @param string $payload Raw Github event (JSON)
+ */
+ public function parsePayload($type, $payload)
+ {
+ $payload = json_decode($payload, true);
+
+ switch ($type) {
+ case 'push':
+ return $this->parsePushEvent($payload);
+ case 'issues':
+ return $this->parseIssueEvent($payload);
+ }
+ }
+
+ /**
+ * Parse Push events (list of commits)
+ *
+ * @access public
+ * @param array $payload Event data
+ */
+ public function parsePushEvent(array $payload)
+ {
+ foreach ($payload['commits'] as $commit) {
+
+ $task_id = $this->task->getTaskIdFromText($commit['message']);
+
+ if (! $task_id) {
+ continue;
+ }
+
+ $task = $this->task->getById($task_id);
+
+ if (! $task) {
+ continue;
+ }
+
+ if ($task['is_active'] == Task::STATUS_OPEN) {
+ $this->event->trigger(self::EVENT_COMMIT, array('task_id' => $task_id) + $task);
+ }
+ }
+ }
+
+ /**
+ * Parse issue events
+ *
+ * @access public
+ * @param array $payload Event data
+ */
+ public function parseIssueEvent(array $payload)
+ {
+
+ }
+}
diff --git a/app/Model/Task.php b/app/Model/Task.php
index 262e8d76..8708f128 100644
--- a/app/Model/Task.php
+++ b/app/Model/Task.php
@@ -696,4 +696,22 @@ class Task extends Base
return false;
}
+
+ /**
+ * Get a the task id from a text
+ *
+ * Example: "Fix bug #1234" will return 1234
+ *
+ * @access public
+ * @param string $message Text
+ * @return integer
+ */
+ public function getTaskIdFromText($message)
+ {
+ if (preg_match('!#(\d+)!i', $message, $matches) && isset($matches[1])) {
+ return $matches[1];
+ }
+
+ return 0;
+ }
}
diff --git a/app/functions.php b/app/functions.php
index 4cbbbbfe..dc6431b9 100644
--- a/app/functions.php
+++ b/app/functions.php
@@ -6,6 +6,10 @@ use PicoDb\Database;
function debug($message)
{
+ if (! is_string($message)) {
+ $message = var_export($message, true);
+ }
+
error_log($message.PHP_EOL, 3, 'data/debug.log');
}