diff options
Diffstat (limited to 'app/Controller')
-rw-r--r-- | app/Controller/App.php | 29 | ||||
-rw-r--r-- | app/Controller/Base.php | 8 | ||||
-rw-r--r-- | app/Controller/Board.php | 14 | ||||
-rw-r--r-- | app/Controller/Calendar.php | 62 | ||||
-rw-r--r-- | app/Controller/Link.php | 162 | ||||
-rw-r--r-- | app/Controller/Task.php | 13 | ||||
-rw-r--r-- | app/Controller/Tasklink.php | 116 |
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').' > '.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']))); + } +} |