summaryrefslogtreecommitdiff
path: root/app/Controller
diff options
context:
space:
mode:
Diffstat (limited to 'app/Controller')
-rw-r--r--app/Controller/App.php29
-rw-r--r--app/Controller/Base.php8
-rw-r--r--app/Controller/Board.php14
-rw-r--r--app/Controller/Calendar.php62
-rw-r--r--app/Controller/Link.php162
-rw-r--r--app/Controller/Task.php13
-rw-r--r--app/Controller/Tasklink.php116
7 files changed, 365 insertions, 39 deletions
diff --git a/app/Controller/App.php b/app/Controller/App.php
index ef0a08a9..46731e7c 100644
--- a/app/Controller/App.php
+++ b/app/Controller/App.php
@@ -2,7 +2,8 @@
namespace Controller;
-use Model\Subtask as SubTaskModel;
+use Model\Subtask as SubtaskModel;
+use Model\Task as TaskModel;
/**
* Application controller
@@ -39,7 +40,7 @@ class App extends Base
*/
public function index($user_id = 0, $action = 'index')
{
- $status = array(SubTaskModel::STATUS_TODO, SubTaskModel::STATUS_INPROGRESS);
+ $status = array(SubTaskModel::STATUS_TODO, SubtaskModel::STATUS_INPROGRESS);
$user_id = $user_id ?: $this->userSession->getId();
$projects = $this->projectPermission->getActiveMemberProjects($user_id);
$project_ids = array_keys($projects);
@@ -88,11 +89,8 @@ class App extends Base
if (empty($payload['text'])) {
$this->response->html('<p>'.t('Nothing to preview...').'</p>');
}
- else {
- $this->response->html(
- $this->template->markdown($payload['text'])
- );
- }
+
+ $this->response->html($this->template->markdown($payload['text']));
}
/**
@@ -104,4 +102,21 @@ class App extends Base
{
$this->response->css($this->color->getCss());
}
+
+ /**
+ * Task autocompletion (Ajax)
+ *
+ * @access public
+ */
+ public function autocomplete()
+ {
+ $this->response->json(
+ $this->taskFilter
+ ->create()
+ ->filterByProjects($this->projectPermission->getActiveMemberProjectIds($this->userSession->getId()))
+ ->excludeTasks(array($this->request->getIntegerParam('exclude_task_id')))
+ ->filterByTitle($this->request->getStringParam('term'))
+ ->toAutoCompletion()
+ );
+ }
}
diff --git a/app/Controller/Base.php b/app/Controller/Base.php
index 7f65e882..548fdb40 100644
--- a/app/Controller/Base.php
+++ b/app/Controller/Base.php
@@ -17,11 +17,13 @@ use Symfony\Component\EventDispatcher\Event;
* @package controller
* @author Frederic Guillot
*
+ * @property \Core\Helper $helper
* @property \Core\Session $session
* @property \Core\Template $template
* @property \Core\Paginator $paginator
* @property \Integration\GithubWebhook $githubWebhook
* @property \Integration\GitlabWebhook $gitlabWebhook
+ * @property \Integration\BitbucketWebhook $bitbucketWebhook
* @property \Model\Acl $acl
* @property \Model\Authentication $authentication
* @property \Model\Action $action
@@ -43,6 +45,7 @@ use Symfony\Component\EventDispatcher\Event;
* @property \Model\Subtask $subtask
* @property \Model\Swimlane $swimlane
* @property \Model\Task $task
+ * @property \Model\Link $link
* @property \Model\TaskCreation $taskCreation
* @property \Model\TaskModification $taskModification
* @property \Model\TaskDuplication $taskDuplication
@@ -54,6 +57,7 @@ use Symfony\Component\EventDispatcher\Event;
* @property \Model\TaskPermission $taskPermission
* @property \Model\TaskStatus $taskStatus
* @property \Model\TaskValidator $taskValidator
+ * @property \Model\TaskLink $taskLink
* @property \Model\CommentHistory $commentHistory
* @property \Model\SubtaskHistory $subtaskHistory
* @property \Model\SubtaskTimeTracking $subtaskTimeTracking
@@ -139,7 +143,7 @@ abstract class Base
private function sendHeaders($action)
{
// HTTP secure headers
- $this->response->csp(array('style-src' => "'self' 'unsafe-inline'"));
+ $this->response->csp(array('style-src' => "'self' 'unsafe-inline'", 'img-src' => '*'));
$this->response->nosniff();
$this->response->xss();
@@ -199,7 +203,7 @@ abstract class Base
{
$project_id = $this->request->getIntegerParam('project_id');
$task_id = $this->request->getIntegerParam('task_id');
-
+
// Allow urls without "project_id"
if ($task_id > 0 && $project_id === 0) {
$project_id = $this->taskFinder->getProjectId($task_id);
diff --git a/app/Controller/Board.php b/app/Controller/Board.php
index e859348e..90b7f357 100644
--- a/app/Controller/Board.php
+++ b/app/Controller/Board.php
@@ -402,6 +402,20 @@ class Board extends Base
}
/**
+ * Get links on mouseover
+ *
+ * @access public
+ */
+ public function tasklinks()
+ {
+ $task = $this->getTask();
+ $this->response->html($this->template->render('board/tasklinks', array(
+ 'links' => $this->taskLink->getLinks($task['id']),
+ 'task' => $task,
+ )));
+ }
+
+ /**
* Get subtasks on mouseover
*
* @access public
diff --git a/app/Controller/Calendar.php b/app/Controller/Calendar.php
index abbcab7f..1c7ac7c0 100644
--- a/app/Controller/Calendar.php
+++ b/app/Controller/Calendar.php
@@ -2,7 +2,7 @@
namespace Controller;
-use Model\Task;
+use Model\Task as TaskModel;
/**
* Project Calendar controller
@@ -41,24 +41,27 @@ class Calendar extends Base
*
* @access public
*/
- public function events()
+ public function project()
{
- $this->response->json(
- $this->taskFilter
- ->create()
- ->filterByProject($this->request->getIntegerParam('project_id'))
- ->filterByCategory($this->request->getIntegerParam('category_id', -1))
- ->filterByOwner($this->request->getIntegerParam('owner_id', -1))
- ->filterByColumn($this->request->getIntegerParam('column_id', -1))
- ->filterBySwimlane($this->request->getIntegerParam('swimlane_id', -1))
- ->filterByColor($this->request->getStringParam('color_id'))
- ->filterByStatus($this->request->getIntegerParam('is_active', -1))
- ->filterByDueDateRange(
- $this->request->getStringParam('start'),
- $this->request->getStringParam('end')
- )
- ->toCalendarEvents()
- );
+ $project_id = $this->request->getIntegerParam('project_id');
+ $start = $this->request->getStringParam('start');
+ $end = $this->request->getStringParam('end');
+
+ $due_tasks = $this->taskFilter
+ ->create()
+ ->filterByProject($project_id)
+ ->filterByCategory($this->request->getIntegerParam('category_id', -1))
+ ->filterByOwner($this->request->getIntegerParam('owner_id', -1))
+ ->filterByColumn($this->request->getIntegerParam('column_id', -1))
+ ->filterBySwimlane($this->request->getIntegerParam('swimlane_id', -1))
+ ->filterByColor($this->request->getStringParam('color_id'))
+ ->filterByStatus($this->request->getIntegerParam('is_active', -1))
+ ->filterByDueDateRange($start, $end)
+ ->toCalendarEvents();
+
+ $subtask_timeslots = $this->subtaskTimeTracking->getProjectCalendarEvents($project_id, $start, $end);
+
+ $this->response->json(array_merge($due_tasks, $subtask_timeslots));
}
/**
@@ -69,18 +72,19 @@ class Calendar extends Base
public function user()
{
$user_id = $this->request->getIntegerParam('user_id');
+ $start = $this->request->getStringParam('start');
+ $end = $this->request->getStringParam('end');
+
+ $due_tasks = $this->taskFilter
+ ->create()
+ ->filterByOwner($user_id)
+ ->filterByStatus(TaskModel::STATUS_OPEN)
+ ->filterByDueDateRange($start, $end)
+ ->toCalendarEvents();
+
+ $subtask_timeslots = $this->subtaskTimeTracking->getUserCalendarEvents($user_id, $start, $end);
- $this->response->json(
- $this->taskFilter
- ->create()
- ->filterByOwner($user_id)
- ->filterByStatus(Task::STATUS_OPEN)
- ->filterByDueDateRange(
- $this->request->getStringParam('start'),
- $this->request->getStringParam('end')
- )
- ->toCalendarEvents()
- );
+ $this->response->json(array_merge($due_tasks, $subtask_timeslots));
}
/**
diff --git a/app/Controller/Link.php b/app/Controller/Link.php
new file mode 100644
index 00000000..ec9c6195
--- /dev/null
+++ b/app/Controller/Link.php
@@ -0,0 +1,162 @@
+<?php
+
+namespace Controller;
+
+/**
+ * Link controller
+ *
+ * @package controller
+ * @author Olivier Maridat
+ * @author Frederic Guillot
+ */
+class Link extends Base
+{
+ /**
+ * Common layout for config views
+ *
+ * @access private
+ * @param string $template Template name
+ * @param array $params Template parameters
+ * @return string
+ */
+ private function layout($template, array $params)
+ {
+ $params['board_selector'] = $this->projectPermission->getAllowedProjects($this->userSession->getId());
+ $params['config_content_for_layout'] = $this->template->render($template, $params);
+
+ return $this->template->layout('config/layout', $params);
+ }
+
+ /**
+ * Get the current link
+ *
+ * @access private
+ * @return array
+ */
+ private function getLink()
+ {
+ $link = $this->link->getById($this->request->getIntegerParam('link_id'));
+
+ if (! $link) {
+ $this->notfound();
+ }
+
+ return $link;
+ }
+
+ /**
+ * List of links
+ *
+ * @access public
+ */
+ public function index(array $values = array(), array $errors = array())
+ {
+ $this->response->html($this->layout('link/index', array(
+ 'links' => $this->link->getMergedList(),
+ 'values' => $values,
+ 'errors' => $errors,
+ 'title' => t('Settings').' &gt; '.t('Task\'s links'),
+ )));
+ }
+
+ /**
+ * Validate and save a new link
+ *
+ * @access public
+ */
+ public function save()
+ {
+ $values = $this->request->getValues();
+ list($valid, $errors) = $this->link->validateCreation($values);
+
+ if ($valid) {
+
+ if ($this->link->create($values['label'], $values['opposite_label'])) {
+ $this->session->flash(t('Link added successfully.'));
+ $this->response->redirect($this->helper->url('link', 'index'));
+ }
+ else {
+ $this->session->flashError(t('Unable to create your link.'));
+ }
+ }
+
+ $this->index($values, $errors);
+ }
+
+ /**
+ * Edit form
+ *
+ * @access public
+ */
+ public function edit(array $values = array(), array $errors = array())
+ {
+ $link = $this->getLink();
+ $link['label'] = t($link['label']);
+
+ $this->response->html($this->layout('link/edit', array(
+ 'values' => $values ?: $link,
+ 'errors' => $errors,
+ 'labels' => $this->link->getList($link['id']),
+ 'link' => $link,
+ 'title' => t('Link modification')
+ )));
+ }
+
+ /**
+ * Edit a link (validate the form and update the database)
+ *
+ * @access public
+ */
+ public function update()
+ {
+ $values = $this->request->getValues();
+ list($valid, $errors) = $this->link->validateModification($values);
+
+ if ($valid) {
+ if ($this->link->update($values)) {
+ $this->session->flash(t('Link updated successfully.'));
+ $this->response->redirect($this->helper->url('link', 'index'));
+ }
+ else {
+ $this->session->flashError(t('Unable to update your link.'));
+ }
+ }
+
+ $this->edit($values, $errors);
+ }
+
+ /**
+ * Confirmation dialog before removing a link
+ *
+ * @access public
+ */
+ public function confirm()
+ {
+ $link = $this->getLink();
+
+ $this->response->html($this->layout('link/remove', array(
+ 'link' => $link,
+ 'title' => t('Remove a link')
+ )));
+ }
+
+ /**
+ * Remove a link
+ *
+ * @access public
+ */
+ public function remove()
+ {
+ $this->checkCSRFParam();
+ $link = $this->getLink();
+
+ if ($this->link->remove($link['id'])) {
+ $this->session->flash(t('Link removed successfully.'));
+ }
+ else {
+ $this->session->flashError(t('Unable to remove this link.'));
+ }
+
+ $this->response->redirect($this->helper->url('link', 'index'));
+ }
+}
diff --git a/app/Controller/Task.php b/app/Controller/Task.php
index fdd20b5e..741db61e 100644
--- a/app/Controller/Task.php
+++ b/app/Controller/Task.php
@@ -36,6 +36,7 @@ class Task extends Base
'project' => $project,
'comments' => $this->comment->getAll($task['id']),
'subtasks' => $this->subtask->getAll($task['id']),
+ 'links' => $this->taskLink->getLinks($task['id']),
'task' => $task,
'columns_list' => $this->board->getColumnsList($task['project_id']),
'colors_list' => $this->color->getList(),
@@ -70,6 +71,7 @@ class Task extends Base
'files' => $this->file->getAll($task['id']),
'comments' => $this->comment->getAll($task['id']),
'subtasks' => $subtasks,
+ 'links' => $this->taskLink->getLinks($task['id']),
'task' => $task,
'values' => $values,
'columns_list' => $this->board->getColumnsList($task['project_id']),
@@ -249,6 +251,7 @@ class Task extends Base
public function close()
{
$task = $this->getTask();
+ $redirect = $this->request->getStringParam('redirect');
if ($this->request->getStringParam('confirmation') === 'yes') {
@@ -260,15 +263,23 @@ class Task extends Base
$this->session->flashError(t('Unable to close this task.'));
}
- if ($this->request->getStringParam('redirect') === 'board') {
+ if ($redirect === 'board') {
$this->response->redirect($this->helper->url('board', 'show', array('project_id' => $task['project_id'])));
}
$this->response->redirect($this->helper->url('task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])));
}
+ if ($this->request->isAjax()) {
+ $this->response->html($this->template->render('task/close', array(
+ 'task' => $task,
+ 'redirect' => $redirect,
+ )));
+ }
+
$this->response->html($this->taskLayout('task/close', array(
'task' => $task,
+ 'redirect' => $redirect,
)));
}
diff --git a/app/Controller/Tasklink.php b/app/Controller/Tasklink.php
new file mode 100644
index 00000000..61b7fab8
--- /dev/null
+++ b/app/Controller/Tasklink.php
@@ -0,0 +1,116 @@
+<?php
+
+namespace Controller;
+
+/**
+ * TaskLink controller
+ *
+ * @package controller
+ * @author Olivier Maridat
+ * @author Frederic Guillot
+ */
+class Tasklink extends Base
+{
+ /**
+ * Get the current link
+ *
+ * @access private
+ * @return array
+ */
+ private function getTaskLink()
+ {
+ $link = $this->taskLink->getById($this->request->getIntegerParam('link_id'));
+
+ if (! $link) {
+ $this->notfound();
+ }
+
+ return $link;
+ }
+
+ /**
+ * Creation form
+ *
+ * @access public
+ */
+ public function create(array $values = array(), array $errors = array())
+ {
+ $task = $this->getTask();
+
+ if (empty($values)) {
+ $values = array(
+ 'task_id' => $task['id'],
+ );
+ }
+
+ $this->response->html($this->taskLayout('tasklink/create', array(
+ 'values' => $values,
+ 'errors' => $errors,
+ 'task' => $task,
+ 'labels' => $this->link->getList(0, false),
+ 'title' => t('Add a new link')
+ )));
+ }
+
+ /**
+ * Validation and creation
+ *
+ * @access public
+ */
+ public function save()
+ {
+ $task = $this->getTask();
+ $values = $this->request->getValues();
+
+ list($valid, $errors) = $this->taskLink->validateCreation($values);
+
+ if ($valid) {
+
+ if ($this->taskLink->create($values['task_id'], $values['opposite_task_id'], $values['link_id'])) {
+ $this->session->flash(t('Link added successfully.'));
+ $this->response->redirect($this->helper->url('task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])).'#links');
+ }
+ else {
+ $this->session->flashError(t('Unable to create your link.'));
+ }
+ }
+
+ $this->create($values, $errors);
+ }
+
+ /**
+ * Confirmation dialog before removing a link
+ *
+ * @access public
+ */
+ public function confirm()
+ {
+ $task = $this->getTask();
+ $link = $this->getTaskLink();
+
+ $this->response->html($this->taskLayout('tasklink/remove', array(
+ 'link' => $link,
+ 'task' => $task,
+ )));
+ }
+
+ /**
+ * Remove a link
+ *
+ * @access public
+ */
+ public function remove()
+ {
+ $this->checkCSRFParam();
+ $task = $this->getTask();
+
+ if ($this->taskLink->remove($this->request->getIntegerParam('link_id'))) {
+ $this->session->flash(t('Link removed successfully.'));
+ }
+ else {
+ $this->session->flashError(t('Unable to remove this link.'));
+ }
+
+ $this->response->redirect($this->helper->url('task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])));
+ }
+}