diff options
Diffstat (limited to 'app')
45 files changed, 998 insertions, 1161 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 2c8b5cde..76a81612 100644 --- a/app/Controller/Base.php +++ b/app/Controller/Base.php @@ -141,7 +141,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' => "'self' data:")); $this->response->nosniff(); $this->response->xss(); @@ -201,7 +201,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 ae249982..90b7f357 100644 --- a/app/Controller/Board.php +++ b/app/Controller/Board.php @@ -410,7 +410,7 @@ class Board extends Base { $task = $this->getTask(); $this->response->html($this->template->render('board/tasklinks', array( - 'links' => $this->taskLink->getAll($task['id']), + 'links' => $this->taskLink->getLinks($task['id']), 'task' => $task, ))); } diff --git a/app/Controller/Calendar.php b/app/Controller/Calendar.php index abbcab7f..0e749558 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 @@ -74,7 +74,7 @@ class Calendar extends Base $this->taskFilter ->create() ->filterByOwner($user_id) - ->filterByStatus(Task::STATUS_OPEN) + ->filterByStatus(TaskModel::STATUS_OPEN) ->filterByDueDateRange( $this->request->getStringParam('start'), $this->request->getStringParam('end') diff --git a/app/Controller/Config.php b/app/Controller/Config.php index 6ec10279..01c7ad53 100644 --- a/app/Controller/Config.php +++ b/app/Controller/Config.php @@ -87,17 +87,12 @@ class Config extends Base * * @access public */ - public function board(array $values = array(), array $errors = array()) + public function board() { $this->common('board'); $this->response->html($this->layout('config/board', array( 'default_columns' => implode(', ', $this->board->getDefaultColumns()), - 'links' => $this->link->getMergedList(), - 'values' => $values + array( - 'project_id' => -1 - ), - 'errors' => $errors, 'title' => t('Settings').' > '.t('Board settings'), ))); } diff --git a/app/Controller/Link.php b/app/Controller/Link.php index fca9017a..ec9c6195 100644 --- a/app/Controller/Link.php +++ b/app/Controller/Link.php @@ -1,11 +1,13 @@ <?php + namespace Controller; /** * Link controller * * @package controller - * @author Olivier Maridat + * @author Olivier Maridat + * @author Frederic Guillot */ class Link extends Base { @@ -21,13 +23,10 @@ class Link extends Base { $params['board_selector'] = $this->projectPermission->getAllowedProjects($this->userSession->getId()); $params['config_content_for_layout'] = $this->template->render($template, $params); - - if (isset($params['values']['project_id']) && -1 != $params['values']['project_id']) { - return $this->projectLayout($template, $params); - } + return $this->template->layout('config/layout', $params); } - + /** * Get the current link * @@ -36,49 +35,27 @@ class Link extends Base */ private function getLink() { - $link = $this->link->getById($this->request->getIntegerParam('link_id'), $this->request->getIntegerParam('project_id', -1)); + $link = $this->link->getById($this->request->getIntegerParam('link_id')); + if (! $link) { $this->notfound(); } - $link['link_id'] = $link[0]['link_id'];
- $link['project_id'] = $link[0]['project_id']; - return $link; - } - /** - * Method to get a project - * - * @access protected - * @param integer $project_id Default project id - * @return array - */ - protected function getProject($project_id = -1) - { - $project = array('id' => $project_id); - $project_id = $this->request->getIntegerParam('project_id', $project_id); - if (-1 != $project_id) { - $project = parent::getProject($project_id); - } - return $project; + return $link; } /** - * List of links for a given project + * List of links * * @access public */ public function index(array $values = array(), array $errors = array()) { - $project = $this->getProject(); - $values['project_id'] = $project['id']; - $values[] = array(); - $this->response->html($this->layout('link/index', array( - 'links' => $this->link->getMergedList($project['id']), + 'links' => $this->link->getMergedList(), 'values' => $values, 'errors' => $errors, - 'project' => $project, - 'title' => t('Settings').' > '.t('Board\'s links settings'), + 'title' => t('Settings').' > '.t('Task\'s links'), ))); } @@ -91,19 +68,18 @@ class Link extends Base { $values = $this->request->getValues(); list($valid, $errors) = $this->link->validateCreation($values); - + if ($valid) { - if ($this->link->create($values)) { + + if ($this->link->create($values['label'], $values['opposite_label'])) { $this->session->flash(t('Link added successfully.')); - $this->response->redirect('?controller=link&action=index&project_id='.$values['project_id']); + $this->response->redirect($this->helper->url('link', 'index')); } else { $this->session->flashError(t('Unable to create your link.')); } } - if (!empty($values)) { - $this->link->prepare($values); - } + $this->index($values, $errors); } @@ -114,14 +90,15 @@ class Link extends Base */ public function edit(array $values = array(), array $errors = array()) { - $project = $this->getProject(); - + $link = $this->getLink(); + $link['label'] = t($link['label']); + $this->response->html($this->layout('link/edit', array( - 'values' => empty($values) ? $this->getLink() : $values, + 'values' => $values ?: $link, 'errors' => $errors, - 'project' => $project, - 'edit' => true, - 'title' => t('Links') + 'labels' => $this->link->getList($link['id']), + 'link' => $link, + 'title' => t('Link modification') ))); } @@ -134,19 +111,17 @@ class Link extends Base { $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('?controller=link&action=index&project_id='.$values['project_id']); + $this->response->redirect($this->helper->url('link', 'index')); } - else {
+ else { $this->session->flashError(t('Unable to update your link.')); } } - if (!empty($values)) { - $this->link->prepare($values); - } + $this->edit($values, $errors); } @@ -157,11 +132,9 @@ class Link extends Base */ public function confirm() { - $project = $this->getProject(); $link = $this->getLink(); - + $this->response->html($this->layout('link/remove', array( - 'project' => $project, 'link' => $link, 'title' => t('Remove a link') ))); @@ -176,14 +149,14 @@ class Link extends Base { $this->checkCSRFParam(); $link = $this->getLink(); - - if ($this->link->remove($link['link_id'])) { + + if ($this->link->remove($link['id'])) { $this->session->flash(t('Link removed successfully.')); - $this->response->redirect('?controller=link&action=index&project_id='.$link['project_id']); } else { $this->session->flashError(t('Unable to remove this link.')); } - $this->confirm(); + + $this->response->redirect($this->helper->url('link', 'index')); } } diff --git a/app/Controller/Task.php b/app/Controller/Task.php index e4c2d773..0789e8eb 100644 --- a/app/Controller/Task.php +++ b/app/Controller/Task.php @@ -37,7 +37,7 @@ class Task extends Base 'project' => $project, 'comments' => $this->comment->getAll($task['id']), 'subtasks' => $this->subtask->getAll($task['id']), - 'links' => $this->taskLink->getAll($task['id']), + 'links' => $this->taskLink->getLinks($task['id']), 'task' => $task, 'columns_list' => $this->board->getColumnsList($task['project_id']), 'colors_list' => $this->color->getList(), @@ -72,13 +72,11 @@ class Task extends Base 'files' => $this->file->getAll($task['id']), 'comments' => $this->comment->getAll($task['id']), 'subtasks' => $subtasks, - 'links' => $this->taskLink->getAll($task['id']), + 'links' => $this->taskLink->getLinks($task['id']), 'task' => $task, 'values' => $values, 'columns_list' => $this->board->getColumnsList($task['project_id']), 'colors_list' => $this->color->getList(), - 'link_list' => $this->link->getLinkLabelList($task['project_id'], false), - 'task_list' => $this->taskFinder->getList($task['project_id'], TaskModel::STATUS_OPEN, $task['id']), 'date_format' => $this->config->get('application_date_format'), 'date_formats' => $this->dateParser->getAvailableFormats(), 'title' => $task['project_name'].' > '.$task['title'], diff --git a/app/Controller/Tasklink.php b/app/Controller/Tasklink.php index d76de8fe..61b7fab8 100644 --- a/app/Controller/Tasklink.php +++ b/app/Controller/Tasklink.php @@ -2,12 +2,12 @@ namespace Controller; -use Model\Task AS TaskModel; /** * TaskLink controller * * @package controller * @author Olivier Maridat + * @author Frederic Guillot */ class Tasklink extends Base { @@ -20,9 +20,11 @@ class Tasklink extends Base private function getTaskLink() { $link = $this->taskLink->getById($this->request->getIntegerParam('link_id')); + if (! $link) { $this->notfound(); } + return $link; } @@ -38,16 +40,15 @@ class Tasklink extends Base if (empty($values)) { $values = array( 'task_id' => $task['id'], - 'another_link' => $this->request->getIntegerParam('another_link', 0) ); } - $this->response->html($this->taskLayout('tasklink/edit', array( + $this->response->html($this->taskLayout('tasklink/create', array( 'values' => $values, 'errors' => $errors, - 'link_list' => $this->link->getLinkLabelList($task['project_id']), - 'task_list' => $this->taskFinder->getList($task['project_id'], TaskModel::STATUS_OPEN, $task['id']), 'task' => $task, + 'labels' => $this->link->getList(0, false), + 'title' => t('Add a new link') ))); } @@ -60,19 +61,17 @@ class Tasklink extends Base { $task = $this->getTask(); $values = $this->request->getValues(); + list($valid, $errors) = $this->taskLink->validateCreation($values); if ($valid) { - if ($this->taskLink->create($values)) { + + if ($this->taskLink->create($values['task_id'], $values['opposite_task_id'], $values['link_id'])) { $this->session->flash(t('Link added successfully.')); - if (isset($values['another_link']) && $values['another_link'] == 1) { - $this->response->redirect('?controller=tasklink&action=create&task_id='.$task['id'].'&project_id='.$task['project_id'].'&another_link=1'); - } - - $this->response->redirect('?controller=task&action=show&task_id='.$task['id'].'&project_id='.$task['project_id'].'#links'); + $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 add the link.')); + $this->session->flashError(t('Unable to create your link.')); } } @@ -80,50 +79,6 @@ class Tasklink extends Base } /** - * Edit form - * - * @access public - */ - public function edit(array $values = array(), array $errors = array()) - { - $task = $this->getTask(); - $taskLink = $this->getTaskLink(); - - $this->response->html($this->taskLayout('tasklink/edit', array( - 'values' => empty($values) ? $taskLink : $values, - 'errors' => $errors, - 'link_list' => $this->link->getLinkLabelList($task['project_id'], false), - 'task_list' => $this->taskFinder->getList($task['project_id'], TaskModel::STATUS_OPEN, $task['id']), - 'link' => $taskLink, - 'task' => $task, - 'edit' => true, - ))); - } - - /** - * Update and validate a link - * - * @access public - */ - public function update() - { - $task = $this->getTask(); - $values = $this->request->getValues(); - list($valid, $errors) = $this->taskLink->validateModification($values); - - if ($valid) { - if ($this->taskLink->update($values)) { - $this->session->flash(t('Link updated successfully.')); - $this->response->redirect('?controller=task&action=show&task_id='.$task['id'].'&project_id='.$task['project_id'].'#links'); - } - else { - $this->session->flashError(t('Unable to update the link.')); - } - } - $this->edit($values, $errors); - } - - /** * Confirmation dialog before removing a link * * @access public @@ -132,6 +87,7 @@ class Tasklink extends Base { $task = $this->getTask(); $link = $this->getTaskLink(); + $this->response->html($this->taskLayout('tasklink/remove', array( 'link' => $link, 'task' => $task, @@ -147,14 +103,14 @@ class Tasklink extends Base { $this->checkCSRFParam(); $task = $this->getTask(); - + if ($this->taskLink->remove($this->request->getIntegerParam('link_id'))) { $this->session->flash(t('Link removed successfully.')); - $this->response->redirect('?controller=task&action=show&task_id='.$task['id'].'&project_id='.$task['project_id'].'#links'); } else { $this->session->flashError(t('Unable to remove this link.')); } - $this->confirm(); + + $this->response->redirect($this->helper->url('task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']))); } } diff --git a/app/Core/Helper.php b/app/Core/Helper.php index a9d455f9..d60e29d4 100644 --- a/app/Core/Helper.php +++ b/app/Core/Helper.php @@ -155,9 +155,6 @@ class Helper */ public function formValue($values, $name) { - if (false !== ($pos = strpos($name, '['))) { - $name = substr($name, 0, $pos); - } if (isset($values->$name)) { return 'value="'.$this->e($values->$name).'"'; } @@ -584,7 +581,6 @@ class Helper { return strpos($haystack, $needle) !== false; } - /** * Return a value from a dictionary diff --git a/app/Locale/da_DK/translations.php b/app/Locale/da_DK/translations.php index d0bebe0c..db91895f 100644 --- a/app/Locale/da_DK/translations.php +++ b/app/Locale/da_DK/translations.php @@ -686,4 +686,37 @@ return array( // 'Task age in days' => '', // 'Days in this column' => '', // '%dd' => '', + // 'Add a link' => '', + // 'Add a new link' => '', + // 'Do you really want to remove this link: "%s"?' => '', + // 'Do you really want to remove this link with task #%d?' => '', + // 'Field required' => '', + // 'Link added successfully.' => '', + // 'Link updated successfully.' => '', + // 'Link removed successfully.' => '', + // 'Link labels' => '', + // 'Link modification' => '', + // 'Links' => '', + // 'Link settings' => '', + // 'Opposite label' => '', + // 'Remove a link' => '', + // 'Task\'s links' => '', + // 'The labels must be different' => '', + // 'There is no link.' => '', + // 'This label must be unique' => '', + // 'Unable to create your link.' => '', + // 'Unable to update your link.' => '', + // 'Unable to remove this link.' => '', + // 'relates to' => '', + // 'blocks' => '', + // 'is blocked by' => '', + // 'duplicates' => '', + // 'is duplicated by' => '', + // 'is a child of' => '', + // 'is a parent of' => '', + // 'targets milestone' => '', + // 'is a milestone of' => '', + // 'fixes' => '', + // 'is fixed by' => '', + // 'This task' => '', ); diff --git a/app/Locale/de_DE/translations.php b/app/Locale/de_DE/translations.php index 42db9bcd..967d5f62 100644 --- a/app/Locale/de_DE/translations.php +++ b/app/Locale/de_DE/translations.php @@ -686,4 +686,37 @@ return array( // 'Task age in days' => '', // 'Days in this column' => '', // '%dd' => '', + // 'Add a link' => '', + // 'Add a new link' => '', + // 'Do you really want to remove this link: "%s"?' => '', + // 'Do you really want to remove this link with task #%d?' => '', + // 'Field required' => '', + // 'Link added successfully.' => '', + // 'Link updated successfully.' => '', + // 'Link removed successfully.' => '', + // 'Link labels' => '', + // 'Link modification' => '', + // 'Links' => '', + // 'Link settings' => '', + // 'Opposite label' => '', + // 'Remove a link' => '', + // 'Task\'s links' => '', + // 'The labels must be different' => '', + // 'There is no link.' => '', + // 'This label must be unique' => '', + // 'Unable to create your link.' => '', + // 'Unable to update your link.' => '', + // 'Unable to remove this link.' => '', + // 'relates to' => '', + // 'blocks' => '', + // 'is blocked by' => '', + // 'duplicates' => '', + // 'is duplicated by' => '', + // 'is a child of' => '', + // 'is a parent of' => '', + // 'targets milestone' => '', + // 'is a milestone of' => '', + // 'fixes' => '', + // 'is fixed by' => '', + // 'This task' => '', ); diff --git a/app/Locale/es_ES/translations.php b/app/Locale/es_ES/translations.php index e921c10f..c69d9084 100644 --- a/app/Locale/es_ES/translations.php +++ b/app/Locale/es_ES/translations.php @@ -686,4 +686,37 @@ return array( // 'Task age in days' => '', // 'Days in this column' => '', // '%dd' => '', + // 'Add a link' => '', + // 'Add a new link' => '', + // 'Do you really want to remove this link: "%s"?' => '', + // 'Do you really want to remove this link with task #%d?' => '', + // 'Field required' => '', + // 'Link added successfully.' => '', + // 'Link updated successfully.' => '', + // 'Link removed successfully.' => '', + // 'Link labels' => '', + // 'Link modification' => '', + // 'Links' => '', + // 'Link settings' => '', + // 'Opposite label' => '', + // 'Remove a link' => '', + // 'Task\'s links' => '', + // 'The labels must be different' => '', + // 'There is no link.' => '', + // 'This label must be unique' => '', + // 'Unable to create your link.' => '', + // 'Unable to update your link.' => '', + // 'Unable to remove this link.' => '', + // 'relates to' => '', + // 'blocks' => '', + // 'is blocked by' => '', + // 'duplicates' => '', + // 'is duplicated by' => '', + // 'is a child of' => '', + // 'is a parent of' => '', + // 'targets milestone' => '', + // 'is a milestone of' => '', + // 'fixes' => '', + // 'is fixed by' => '', + // 'This task' => '', ); diff --git a/app/Locale/fi_FI/translations.php b/app/Locale/fi_FI/translations.php index 0ed1031b..0dd29c37 100644 --- a/app/Locale/fi_FI/translations.php +++ b/app/Locale/fi_FI/translations.php @@ -686,4 +686,37 @@ return array( // 'Task age in days' => '', // 'Days in this column' => '', // '%dd' => '', + // 'Add a link' => '', + // 'Add a new link' => '', + // 'Do you really want to remove this link: "%s"?' => '', + // 'Do you really want to remove this link with task #%d?' => '', + // 'Field required' => '', + // 'Link added successfully.' => '', + // 'Link updated successfully.' => '', + // 'Link removed successfully.' => '', + // 'Link labels' => '', + // 'Link modification' => '', + // 'Links' => '', + // 'Link settings' => '', + // 'Opposite label' => '', + // 'Remove a link' => '', + // 'Task\'s links' => '', + // 'The labels must be different' => '', + // 'There is no link.' => '', + // 'This label must be unique' => '', + // 'Unable to create your link.' => '', + // 'Unable to update your link.' => '', + // 'Unable to remove this link.' => '', + // 'relates to' => '', + // 'blocks' => '', + // 'is blocked by' => '', + // 'duplicates' => '', + // 'is duplicated by' => '', + // 'is a child of' => '', + // 'is a parent of' => '', + // 'targets milestone' => '', + // 'is a milestone of' => '', + // 'fixes' => '', + // 'is fixed by' => '', + // 'This task' => '', ); diff --git a/app/Locale/fr_FR/translations.php b/app/Locale/fr_FR/translations.php index ec09348d..7872dec4 100644 --- a/app/Locale/fr_FR/translations.php +++ b/app/Locale/fr_FR/translations.php @@ -688,52 +688,37 @@ return array( 'Task age in days' => 'Age de la tâche en jours', 'Days in this column' => 'Jours dans cette colonne', '%dd' => '%dj', - 'relates to' => 'liée à ', + 'Add a link' => 'Ajouter un lien', + 'Add a new link' => 'Ajouter un nouveau lien', + 'Do you really want to remove this link: "%s"?' => 'Voulez-vous vraiment supprimer ce lien : « %s » ?', + 'Do you really want to remove this link with task #%d?' => 'Voulez-vous vraiment supprimer ce lien avec la tâche n°%s ?', + 'Field required' => 'Champ obligatoire', + 'Link added successfully.' => 'Lien créé avec succès.', + 'Link updated successfully.' => 'Lien mis à jour avec succès.', + 'Link removed successfully.' => 'Lien supprimé avec succès.', + 'Link labels' => 'Libellé des liens', + 'Link modification' => 'Modification d\'un lien', + 'Links' => 'Liens', + 'Link settings' => 'Paramètres des liens', + 'Opposite label' => 'Nom du libellé opposé', + 'Remove a link' => 'Supprimer un lien', + 'Task\'s links' => 'Liens des tâches', + 'The labels must be different' => 'Les libellés doivent être différents', + 'There is no link.' => 'Il n\'y a aucun lien.', + 'This label must be unique' => 'Ce libellé doit être unique', + 'Unable to create your link.' => 'Impossible d\'ajouter ce lien.', + 'Unable to update your link.' => 'Impossible de mettre à jour ce lien.', + 'Unable to remove this link.' => 'Impossible de supprimer ce lien.', + 'relates to' => 'est liée à ', 'blocks' => 'bloque', 'is blocked by' => 'est bloquée par', 'duplicates' => 'duplique', 'is duplicated by' => 'est dupliquée par', 'is a child of' => 'est un enfant de', 'is a parent of' => 'est un parent de', - 'targets milestone' => 'vise la milestone', - 'is a milestone o' => 'est une milestone de', + 'targets milestone' => 'vise l\'étape importante', + 'is a milestone of' => 'est une étape importante de', 'fixes' => 'corrige', 'is fixed by' => 'est corrigée par', - 'Links' => 'Liens', - 'Add a link' => 'Ajouter un lien', - 'Edit a link' => 'Mettre à jour un lien', - 'Remove a link' => 'Supprimer un lien', - 'Create another link' => 'Ajouter un autre lien', - 'Linked task id' => 'Id de la tâche à lier', - 'The exact same link already exists' => 'Un tel lien existe déjà ', - 'This linked task id doesn\'t exist' => 'Cette tâche n\'existe pas', - 'A task can not be linked to itself' => 'Une tâche ne peut être liée à elle-même', - 'Link added successfully.' => 'Lien créé avec succès.', - 'Link updated successfully.' => 'Lien mis à jour avec succès.', - 'Link removed successfully.' => 'Lien supprimé avec succès.', - 'Unable to add the link.' => 'Impossible d\'ajouter ce lien.', - 'Unable to update the link.' => 'Impossible de mettre à jour ce lien.', - 'Unable to remove this link.' => 'Impossible de supprimer ce lien.', - 'Do you really want to remove this link with task #%s?' => 'Voulez-vous vraiment supprimer ce lien avec la tâche #%s ?', - 'The link type is required' => 'Le type du lien est obligatoire', - 'The linked task id is required' => 'L\'id de la tâche à lier est obligatoire', - 'The link id must be an integer' => 'L\'id du lien doit être un entier', - 'The related task id must be an integer' => 'L\'id de la tâche à lier doit être un entier', - 'Link management' => 'Gestion des liens', - 'Add a new link' => 'Ajouter un nouveau lien', - 'Add a new link label' => 'Ajouter un nouveau libellé de lien', - 'Link modification for the project "%s"' => 'Mettre à jour un lien du projet « %s »', - 'Links settings' => 'Paramètres des liens', - 'Board\'s links settings' => 'Paramètres des liens du tableau', - 'Link labels' => 'Libellés des liens', - 'Link Label' => 'Libellé du lien', - 'Link Inverse Label' => 'Libellé du lien inverse', - 'Example:' => 'Exemple :', - 'precedes' => 'précède', - 'follows' => 'suit', - '#9 precedes #10' => '#9 précède #10', - '#10 follows #9' => '#10 suit #9', - 'and therefore' => 'et donc', - 'Do you really want to remove this link: "%s"?' => 'Voulez-vous vraiment supprimer ce lien: « %s » ?', - 'You need to add link labels to this project before to link this task to another one.' => 'Il faut ajouter des libellés de liens à ce project avant de pouvoir lier une tâche à une autre.', + 'This task' => 'Cette tâche', ); diff --git a/app/Locale/hu_HU/translations.php b/app/Locale/hu_HU/translations.php index 3ca6cf28..1f8de0ea 100644 --- a/app/Locale/hu_HU/translations.php +++ b/app/Locale/hu_HU/translations.php @@ -686,4 +686,37 @@ return array( // 'Task age in days' => '', // 'Days in this column' => '', // '%dd' => '', + // 'Add a link' => '', + // 'Add a new link' => '', + // 'Do you really want to remove this link: "%s"?' => '', + // 'Do you really want to remove this link with task #%d?' => '', + // 'Field required' => '', + // 'Link added successfully.' => '', + // 'Link updated successfully.' => '', + // 'Link removed successfully.' => '', + // 'Link labels' => '', + // 'Link modification' => '', + // 'Links' => '', + // 'Link settings' => '', + // 'Opposite label' => '', + // 'Remove a link' => '', + // 'Task\'s links' => '', + // 'The labels must be different' => '', + // 'There is no link.' => '', + // 'This label must be unique' => '', + // 'Unable to create your link.' => '', + // 'Unable to update your link.' => '', + // 'Unable to remove this link.' => '', + // 'relates to' => '', + // 'blocks' => '', + // 'is blocked by' => '', + // 'duplicates' => '', + // 'is duplicated by' => '', + // 'is a child of' => '', + // 'is a parent of' => '', + // 'targets milestone' => '', + // 'is a milestone of' => '', + // 'fixes' => '', + // 'is fixed by' => '', + // 'This task' => '', ); diff --git a/app/Locale/it_IT/translations.php b/app/Locale/it_IT/translations.php index 5c3ef47b..afd41d5c 100644 --- a/app/Locale/it_IT/translations.php +++ b/app/Locale/it_IT/translations.php @@ -686,4 +686,37 @@ return array( // 'Task age in days' => '', // 'Days in this column' => '', // '%dd' => '', + // 'Add a link' => '', + // 'Add a new link' => '', + // 'Do you really want to remove this link: "%s"?' => '', + // 'Do you really want to remove this link with task #%d?' => '', + // 'Field required' => '', + // 'Link added successfully.' => '', + // 'Link updated successfully.' => '', + // 'Link removed successfully.' => '', + // 'Link labels' => '', + // 'Link modification' => '', + // 'Links' => '', + // 'Link settings' => '', + // 'Opposite label' => '', + // 'Remove a link' => '', + // 'Task\'s links' => '', + // 'The labels must be different' => '', + // 'There is no link.' => '', + // 'This label must be unique' => '', + // 'Unable to create your link.' => '', + // 'Unable to update your link.' => '', + // 'Unable to remove this link.' => '', + // 'relates to' => '', + // 'blocks' => '', + // 'is blocked by' => '', + // 'duplicates' => '', + // 'is duplicated by' => '', + // 'is a child of' => '', + // 'is a parent of' => '', + // 'targets milestone' => '', + // 'is a milestone of' => '', + // 'fixes' => '', + // 'is fixed by' => '', + // 'This task' => '', ); diff --git a/app/Locale/ja_JP/translations.php b/app/Locale/ja_JP/translations.php index 91030bee..9d06b83f 100644 --- a/app/Locale/ja_JP/translations.php +++ b/app/Locale/ja_JP/translations.php @@ -686,4 +686,37 @@ return array( // 'Task age in days' => '', // 'Days in this column' => '', // '%dd' => '', + // 'Add a link' => '', + // 'Add a new link' => '', + // 'Do you really want to remove this link: "%s"?' => '', + // 'Do you really want to remove this link with task #%d?' => '', + // 'Field required' => '', + // 'Link added successfully.' => '', + // 'Link updated successfully.' => '', + // 'Link removed successfully.' => '', + // 'Link labels' => '', + // 'Link modification' => '', + // 'Links' => '', + // 'Link settings' => '', + // 'Opposite label' => '', + // 'Remove a link' => '', + // 'Task\'s links' => '', + // 'The labels must be different' => '', + // 'There is no link.' => '', + // 'This label must be unique' => '', + // 'Unable to create your link.' => '', + // 'Unable to update your link.' => '', + // 'Unable to remove this link.' => '', + // 'relates to' => '', + // 'blocks' => '', + // 'is blocked by' => '', + // 'duplicates' => '', + // 'is duplicated by' => '', + // 'is a child of' => '', + // 'is a parent of' => '', + // 'targets milestone' => '', + // 'is a milestone of' => '', + // 'fixes' => '', + // 'is fixed by' => '', + // 'This task' => '', ); diff --git a/app/Locale/pl_PL/translations.php b/app/Locale/pl_PL/translations.php index 7acb1497..2ebfc219 100644 --- a/app/Locale/pl_PL/translations.php +++ b/app/Locale/pl_PL/translations.php @@ -686,4 +686,37 @@ return array( // 'Task age in days' => '', // 'Days in this column' => '', // '%dd' => '', + // 'Add a link' => '', + // 'Add a new link' => '', + // 'Do you really want to remove this link: "%s"?' => '', + // 'Do you really want to remove this link with task #%d?' => '', + // 'Field required' => '', + // 'Link added successfully.' => '', + // 'Link updated successfully.' => '', + // 'Link removed successfully.' => '', + // 'Link labels' => '', + // 'Link modification' => '', + // 'Links' => '', + // 'Link settings' => '', + // 'Opposite label' => '', + // 'Remove a link' => '', + // 'Task\'s links' => '', + // 'The labels must be different' => '', + // 'There is no link.' => '', + // 'This label must be unique' => '', + // 'Unable to create your link.' => '', + // 'Unable to update your link.' => '', + // 'Unable to remove this link.' => '', + // 'relates to' => '', + // 'blocks' => '', + // 'is blocked by' => '', + // 'duplicates' => '', + // 'is duplicated by' => '', + // 'is a child of' => '', + // 'is a parent of' => '', + // 'targets milestone' => '', + // 'is a milestone of' => '', + // 'fixes' => '', + // 'is fixed by' => '', + // 'This task' => '', ); diff --git a/app/Locale/pt_BR/translations.php b/app/Locale/pt_BR/translations.php index ac865046..ded6e0db 100644 --- a/app/Locale/pt_BR/translations.php +++ b/app/Locale/pt_BR/translations.php @@ -686,4 +686,37 @@ return array( // 'Task age in days' => '', // 'Days in this column' => '', // '%dd' => '', + // 'Add a link' => '', + // 'Add a new link' => '', + // 'Do you really want to remove this link: "%s"?' => '', + // 'Do you really want to remove this link with task #%d?' => '', + // 'Field required' => '', + // 'Link added successfully.' => '', + // 'Link updated successfully.' => '', + // 'Link removed successfully.' => '', + // 'Link labels' => '', + // 'Link modification' => '', + // 'Links' => '', + // 'Link settings' => '', + // 'Opposite label' => '', + // 'Remove a link' => '', + // 'Task\'s links' => '', + // 'The labels must be different' => '', + // 'There is no link.' => '', + // 'This label must be unique' => '', + // 'Unable to create your link.' => '', + // 'Unable to update your link.' => '', + // 'Unable to remove this link.' => '', + // 'relates to' => '', + // 'blocks' => '', + // 'is blocked by' => '', + // 'duplicates' => '', + // 'is duplicated by' => '', + // 'is a child of' => '', + // 'is a parent of' => '', + // 'targets milestone' => '', + // 'is a milestone of' => '', + // 'fixes' => '', + // 'is fixed by' => '', + // 'This task' => '', ); diff --git a/app/Locale/ru_RU/translations.php b/app/Locale/ru_RU/translations.php index 624a17f1..de792516 100644 --- a/app/Locale/ru_RU/translations.php +++ b/app/Locale/ru_RU/translations.php @@ -686,4 +686,37 @@ return array( // 'Task age in days' => '', // 'Days in this column' => '', // '%dd' => '', + // 'Add a link' => '', + // 'Add a new link' => '', + // 'Do you really want to remove this link: "%s"?' => '', + // 'Do you really want to remove this link with task #%d?' => '', + // 'Field required' => '', + // 'Link added successfully.' => '', + // 'Link updated successfully.' => '', + // 'Link removed successfully.' => '', + // 'Link labels' => '', + // 'Link modification' => '', + // 'Links' => '', + // 'Link settings' => '', + // 'Opposite label' => '', + // 'Remove a link' => '', + // 'Task\'s links' => '', + // 'The labels must be different' => '', + // 'There is no link.' => '', + // 'This label must be unique' => '', + // 'Unable to create your link.' => '', + // 'Unable to update your link.' => '', + // 'Unable to remove this link.' => '', + // 'relates to' => '', + // 'blocks' => '', + // 'is blocked by' => '', + // 'duplicates' => '', + // 'is duplicated by' => '', + // 'is a child of' => '', + // 'is a parent of' => '', + // 'targets milestone' => '', + // 'is a milestone of' => '', + // 'fixes' => '', + // 'is fixed by' => '', + // 'This task' => '', ); diff --git a/app/Locale/sv_SE/translations.php b/app/Locale/sv_SE/translations.php index b77a8a5a..838b426a 100644 --- a/app/Locale/sv_SE/translations.php +++ b/app/Locale/sv_SE/translations.php @@ -686,4 +686,37 @@ return array( // 'Task age in days' => '', // 'Days in this column' => '', // '%dd' => '', + // 'Add a link' => '', + // 'Add a new link' => '', + // 'Do you really want to remove this link: "%s"?' => '', + // 'Do you really want to remove this link with task #%d?' => '', + // 'Field required' => '', + // 'Link added successfully.' => '', + // 'Link updated successfully.' => '', + // 'Link removed successfully.' => '', + // 'Link labels' => '', + // 'Link modification' => '', + // 'Links' => '', + // 'Link settings' => '', + // 'Opposite label' => '', + // 'Remove a link' => '', + // 'Task\'s links' => '', + // 'The labels must be different' => '', + // 'There is no link.' => '', + // 'This label must be unique' => '', + // 'Unable to create your link.' => '', + // 'Unable to update your link.' => '', + // 'Unable to remove this link.' => '', + // 'relates to' => '', + // 'blocks' => '', + // 'is blocked by' => '', + // 'duplicates' => '', + // 'is duplicated by' => '', + // 'is a child of' => '', + // 'is a parent of' => '', + // 'targets milestone' => '', + // 'is a milestone of' => '', + // 'fixes' => '', + // 'is fixed by' => '', + // 'This task' => '', ); diff --git a/app/Locale/th_TH/translations.php b/app/Locale/th_TH/translations.php index 64e0170e..66c7712b 100644 --- a/app/Locale/th_TH/translations.php +++ b/app/Locale/th_TH/translations.php @@ -686,4 +686,37 @@ return array( // 'Task age in days' => '', // 'Days in this column' => '', // '%dd' => '', + // 'Add a link' => '', + // 'Add a new link' => '', + // 'Do you really want to remove this link: "%s"?' => '', + // 'Do you really want to remove this link with task #%d?' => '', + // 'Field required' => '', + // 'Link added successfully.' => '', + // 'Link updated successfully.' => '', + // 'Link removed successfully.' => '', + // 'Link labels' => '', + // 'Link modification' => '', + // 'Links' => '', + // 'Link settings' => '', + // 'Opposite label' => '', + // 'Remove a link' => '', + // 'Task\'s links' => '', + // 'The labels must be different' => '', + // 'There is no link.' => '', + // 'This label must be unique' => '', + // 'Unable to create your link.' => '', + // 'Unable to update your link.' => '', + // 'Unable to remove this link.' => '', + // 'relates to' => '', + // 'blocks' => '', + // 'is blocked by' => '', + // 'duplicates' => '', + // 'is duplicated by' => '', + // 'is a child of' => '', + // 'is a parent of' => '', + // 'targets milestone' => '', + // 'is a milestone of' => '', + // 'fixes' => '', + // 'is fixed by' => '', + // 'This task' => '', ); diff --git a/app/Locale/zh_CN/translations.php b/app/Locale/zh_CN/translations.php index addf7fa6..32278e21 100644 --- a/app/Locale/zh_CN/translations.php +++ b/app/Locale/zh_CN/translations.php @@ -686,4 +686,37 @@ return array( // 'Task age in days' => '', // 'Days in this column' => '', // '%dd' => '', + // 'Add a link' => '', + // 'Add a new link' => '', + // 'Do you really want to remove this link: "%s"?' => '', + // 'Do you really want to remove this link with task #%d?' => '', + // 'Field required' => '', + // 'Link added successfully.' => '', + // 'Link updated successfully.' => '', + // 'Link removed successfully.' => '', + // 'Link labels' => '', + // 'Link modification' => '', + // 'Links' => '', + // 'Link settings' => '', + // 'Opposite label' => '', + // 'Remove a link' => '', + // 'Task\'s links' => '', + // 'The labels must be different' => '', + // 'There is no link.' => '', + // 'This label must be unique' => '', + // 'Unable to create your link.' => '', + // 'Unable to update your link.' => '', + // 'Unable to remove this link.' => '', + // 'relates to' => '', + // 'blocks' => '', + // 'is blocked by' => '', + // 'duplicates' => '', + // 'is duplicated by' => '', + // 'is a child of' => '', + // 'is a parent of' => '', + // 'targets milestone' => '', + // 'is a milestone of' => '', + // 'fixes' => '', + // 'is fixed by' => '', + // 'This task' => '', ); diff --git a/app/Model/Acl.php b/app/Model/Acl.php index b6c0e6b8..e713f2e1 100644 --- a/app/Model/Acl.php +++ b/app/Model/Acl.php @@ -38,6 +38,7 @@ class Acl extends Base 'project' => array('show', 'tasks', 'search', 'activity'), 'subtask' => '*', 'task' => '*', + 'tasklink' => '*', 'calendar' => array('show', 'events', 'save'), ); @@ -67,6 +68,7 @@ class Acl extends Base 'app' => array('dashboard'), 'user' => array('index', 'create', 'save', 'remove'), 'config' => '*', + 'link' => '*', 'project' => array('remove'), ); diff --git a/app/Model/Link.php b/app/Model/Link.php index eddf1c6c..87ba49c4 100644 --- a/app/Model/Link.php +++ b/app/Model/Link.php @@ -1,389 +1,209 @@ <?php + namespace Model; +use PDO; use SimpleValidator\Validator; use SimpleValidator\Validators; -use PDO; /** * Link model - * A link is made of one bidirectional (<->), or two sided (<- and ->) link labels. * * @package model - * @author Olivier Maridat + * @author Olivier Maridat + * @author Frederic Guillot */ class Link extends Base { - /** * SQL table name * * @var string */ - const TABLE = 'link'; - - const TABLE_LABEL = 'link_label'; - - /** - * Direction: left to right -> - * - * @var integer - */ - const BEHAVIOUR_LEFT2RIGTH = 0; - - /** - * Direction: right to left <- - * - * @var integer - */ - const BEHAVIOUR_RIGHT2LEFT = 1; - - /** - * Bidirectional <-> - * - * @var integer - */ - const BEHAVIOUR_BOTH = 2; + const TABLE = 'links'; /** - * Get a link by the id + * Get a link by id * * @access public - * @param integer $link_id - * Link id - * @param integer $project_id - * Specify a project id. Default: -1 to target all projects + * @param integer $link_id Link id * @return array */ - public function getById($link_id, $project_id = -1) + public function getById($link_id) { - return $this->db->table(self::TABLE) - ->eq(self::TABLE . '.link_id', $link_id) - ->in('project_id', array( - - 1, - $project_id - )) - ->join(self::TABLE_LABEL, 'link_id', 'link_id') - ->findAll(); + return $this->db->table(self::TABLE)->eq('id', $link_id)->findOne(); } /** - * Get the id of the inverse link label by a link label id + * Get a link by name * * @access public - * @param integer $link_id - * Link id - * @param integer $link_label_id - * Link label id - * @return integer + * @param string $label + * @return array */ - public function getInverseLinkLabelId($link_label_id) + public function getByLabel($label) { - $sql = 'SELECT - la2.id - FROM ' . self::TABLE_LABEL . ' la1 - JOIN '.self::TABLE_LABEL.' la2 ON la2.link_id = la1.link_id AND (la2.behaviour=2 OR la2.id != la1.id) - WHERE la1.id = ? - '; - $rq = $this->db->execute($sql, array( - $link_label_id - )); - return $rq->fetchColumn(0); + return $this->db->table(self::TABLE)->eq('label', $label)->findOne(); } /** - * Return all link labels for a given project + * Get the opposite link id * * @access public - * @param integer $project_id - * Specify a project id. Default: -1 to target all projects - * @return array + * @param integer $link_id Link id + * @return integer */ - public function getLinkLabels($project_id = -1) + public function getOppositeLinkId($link_id) { - return $this->db->table(self::TABLE_LABEL) - ->in(self::TABLE . '.project_id', array( - - 1, - $project_id - )) - ->join(self::TABLE, 'link_id', 'link_id') - ->asc(self::TABLE_LABEL.'.link_id', 'behaviour') - ->columns('id', self::TABLE . '.project_id', self::TABLE_LABEL.'.link_id', 'label', 'behaviour') - ->findAll(); + $link = $this->getById($link_id); + return $link['opposite_id'] ?: $link_id; } /** - * Return the list of all link labels - * Used to select a link label + * Get all links * * @access public - * @param integer $project_id - * Specify a project id. Default: -1 to target all projects * @return array */ - public function getLinkLabelList($project_id = -1) + public function getAll() { - $listing = $this->getLinkLabels($project_id); - $mergedListing = array(); - foreach ($listing as $link) { - $suffix = ''; - $prefix = ''; - if (self::BEHAVIOUR_BOTH == $link['behaviour'] || self::BEHAVIOUR_LEFT2RIGTH == $link['behaviour']) { - $suffix = ' »'; - } - if (self::BEHAVIOUR_BOTH == $link['behaviour'] || self::BEHAVIOUR_RIGHT2LEFT == $link['behaviour']) { - $prefix = '« '; - } - $mergedListing[$link['id']] = $prefix . t($link['label']) . $suffix; - } - $listing = $mergedListing; - return $listing; + return $this->db->table(self::TABLE)->findAll(); } /** - * Return the list of all links (label + inverse label) + * Get merged links * * @access public - * @param integer $project_id - * Specify a project id. Default: -1 to target all projects * @return array */ - public function getMergedList($project_id = -1) + public function getMergedList() { - $listing = $this->getLinkLabels($project_id); - $mergedListing = array(); - $current = null; - foreach ($listing as $link) { - if (self::BEHAVIOUR_BOTH == $link['behaviour'] || self::BEHAVIOUR_LEFT2RIGTH == $link['behaviour']) { - $current = $link; - } - else { - $current['label_inverse'] = $link['label']; - } - if (self::BEHAVIOUR_BOTH == $link['behaviour'] || self::BEHAVIOUR_RIGHT2LEFT == $link['behaviour']) { - $mergedListing[] = $current; - $current = null; - } - } - $listing = $mergedListing; - return $listing; + return $this->db + ->execute(' + SELECT + links.id, links.label, opposite.label as opposite_label + FROM links + LEFT JOIN links AS opposite ON opposite.id=links.opposite_id + ') + ->fetchAll(PDO::FETCH_ASSOC); } /** - * Prepare data before insert/update + * Get label list * * @access public - * @param array $values - * Form values + * @param integer $exclude_id Exclude this link + * @param booelan $prepend Prepend default value + * @return array */ - public function prepare(array &$values) + public function getList($exclude_id = 0, $prepend = true) { - // Prepare label 1 - $link = array( - 'project_id' => $values['project_id'] - ); - $label1 = array( - 'label' => @$values['label'][0], - 'behaviour' => (isset($values['behaviour'][0]) || !isset($values['label'][1]) || null == $values['label'][1]) ? self::BEHAVIOUR_BOTH : self::BEHAVIOUR_LEFT2RIGTH - ); - $label2 = array( - 'label' => @$values['label'][1], - 'behaviour' => self::BEHAVIOUR_RIGHT2LEFT - ); - if (isset($values['link_id'])) { - $link['link_id'] = $values['link_id']; - $label1['id'] = $values['id'][0]; - $label2['id'] = @$values['id'][1]; - $label1['link_id'] = $values['link_id']; - $label2['link_id'] = $values['link_id']; + $labels = $this->db->hashtable(self::TABLE)->neq('id', $exclude_id)->asc('id')->getAll('id', 'label'); + + foreach ($labels as &$value) { + $value = t($value); } - - $values = $link; - $values[] = $label1;
- $values[] = $label2; - return array( - $link, - $label1, - $label2 - ); + + return $prepend ? array('') + $labels : $labels; } /** - * Create a link + * Create a new link label * * @access public - * @param array $values - * Form values - * @return bool integer + * @param string $label + * @param string $opposite_label + * @return boolean */ - public function create(array $values) + public function create($label, $opposite_label = '') { - list ($link, $label1, $label2) = $this->prepare($values); - // Create link $this->db->startTransaction(); - $res = $this->db->table(self::TABLE)->save($link); - if (! $res) { - $this->db->cancelTransaction(); - return false; - } - - // Create label 1 - $label1['link_id'] = $this->db->getConnection()->lastInsertId(self::TABLE); - $res = $this->db->table(self::TABLE_LABEL)->save($label1); - if (! $res) { + + if (! $this->db->table(self::TABLE)->insert(array('label' => $label))) { $this->db->cancelTransaction(); return false; } - - // Create label 2 if any - if (null != $label2 && self::BEHAVIOUR_BOTH != $label1['behaviour']) { - $label2['link_id'] = $label1['link_id']; - $res = $this->db->table(self::TABLE_LABEL)->save($label2); - if (! $res) { - $this->db->cancelTransaction(); - return false; - } + + if ($opposite_label !== '') { + $this->createOpposite($opposite_label); } + $this->db->closeTransaction(); - return $res; + + return true; } /** - * Update a link + * Create the opposite label (executed inside create() method) * - * @access public - * @param array $values - * Form values - * @return bool + * @access private + * @param string $label */ - public function update(array $values) + private function createOpposite($label) { - list($link, $label1, $label2) = $this->prepare($values); - // Update link - $this->db->startTransaction(); - $res = $this->db->table(self::TABLE) - ->eq('link_id', $link['link_id']) - ->save($link); - if (! $res) { - $this->db->cancelTransaction(); - return false; - } - - // Update label 1 - $this->db->startTransaction(); - $res = $this->db->table(self::TABLE_LABEL) - ->eq('id', $label1['id']) - ->save($label1); - if (! $res) { - $this->db->cancelTransaction(); - return false; - } - - // Update label 2 (if label 1 not bidirectional) - if (null != $label2 && self::BEHAVIOUR_BOTH != $label1['behaviour']) { - // Create - if (! isset($label2['id']) || null == $label2['id']) { - unset($label2['id']); - $res = $this->db->table(self::TABLE_LABEL)->save($label2); - if (! $res) { - $this->db->cancelTransaction(); - return false; - } - $label2['id'] = $this->db->getConnection()->lastInsertId(self::TABLE_LABEL); - $this->taskLink->changeLinkLabel($link['link_id'], $label2['id'], true); - } - // Update - else { - $res = $this->db->table(self::TABLE_LABEL) - ->eq('id', $label2['id']) - ->save($label2); - if (! $res) { - $this->db->cancelTransaction(); - return false; - } - } - } - // Remove label 2 (if label 1 bidirectional) - else { - $this->taskLink->changeLinkLabel($link['link_id'], $label1['id']); - $this->db->table(self::TABLE_LABEL) - ->eq('link_id', $link['link_id']) - ->neq('id', $label1['id']) - ->remove(); - } - $this->db->closeTransaction(); - return $res; + $label_id = $this->db->getConnection()->getLastId(); + + $this->db + ->table(self::TABLE) + ->insert(array( + 'label' => $label, + 'opposite_id' => $label_id, + )); + + $this->db + ->table(self::TABLE) + ->eq('id', $label_id) + ->update(array( + 'opposite_id' => $this->db->getConnection()->getLastId() + )); } /** - * Remove a link + * Update a link * * @access public - * @param integer $link_id - * Link id - * @return bool + * @param array $values + * @return boolean */ - public function remove($link_id) + public function update(array $values) { - $this->db->startTransaction(); - if (! $this->db->table(self::TABLE) - ->eq('link_id', $link_id) - ->remove()) { - $this->db->cancelTransaction(); - return false; - } - $this->db->closeTransaction(); - return true; + return $this->db + ->table(self::TABLE) + ->eq('id', $values['id']) + ->update(array( + 'label' => $values['label'], + 'opposite_id' => $values['opposite_id'], + )); } /** - * Duplicate links from a project to another one, must be executed inside a transaction + * Remove a link a the relation to its opposite * - * @param integer $src_project_id - * Source project id - * @return integer $dst_project_id Destination project id + * @access public + * @param integer $link_id * @return boolean */ - public function duplicate($src_project_id, $dst_project_id) + public function remove($link_id) { - $labels = $this->db->table(self::TABLE_LABEL) - ->columns(self::TABLE_LABEL.'.link_id', 'label', 'behaviour') - ->eq('project_id', $src_project_id) - ->join(self::TABLE, 'link_id', 'link_id') - ->asc(self::TABLE_LABEL.'.link_id', 'behaviour') - ->findAll(); - - $this->db->startTransaction(); - $link = array('project_id' => $dst_project_id);
- if (! $this->db->table(self::TABLE)->save($link)) { - $this->db->cancelTransaction();
- return false;
- } - $link['id'] = $this->db->getConnection()->lastInsertId(self::TABLE); - - foreach ($labels as $label) { - $label['link_id'] = $link['id']; - if (! $this->db->table(self::TABLE_LABEL)->save($label)) { - $this->db->cancelTransaction(); - return false; - } - } - $this->db->closeTransaction(); - return true; + $this->db->table(self::TABLE)->eq('opposite_id', $link_id)->update(array('opposite_id' => 0)); + return $this->db->table(self::TABLE)->eq('id', $link_id)->remove(); } /** - * Validate link creation + * Validate creation * * @access public - * @param array $values - * Form values - * @return array $valid, $errors [0] = Success or not, [1] = List of errors + * @param array $values Form values + * @return array $valid, $errors [0] = Success or not, [1] = List of errors */ public function validateCreation(array $values) { - $v = new Validator($values, $this->commonValidationRules()); - + $v = new Validator($values, array( + new Validators\Required('label', t('Field required')), + new Validators\Unique('label', t('This label must be unique'), $this->db->getConnection(), self::TABLE), + new Validators\NotEquals('label', 'opposite_label', t('The labels must be different')), + )); + return array( $v->execute(), $v->getErrors() @@ -391,47 +211,24 @@ class Link extends Base } /** - * Validate link modification + * Validate modification * * @access public - * @param array $values - * Form values - * @return array $valid, $errors [0] = Success or not, [1] = List of errors + * @param array $values Form values + * @return array $valid, $errors [0] = Success or not, [1] = List of errors */ public function validateModification(array $values) { - $rules = array( - new Validators\Required('link_id', t('The id is required')), -// new Validators\Required('id[0]', t('The label id is required')) - ); - $v = new Validator($values, array_merge($rules, $this->commonValidationRules())); - + $v = new Validator($values, array( + new Validators\Required('id', t('Field required')), + new Validators\Required('opposite_id', t('Field required')), + new Validators\Required('label', t('Field required')), + new Validators\Unique('label', t('This label must be unique'), $this->db->getConnection(), self::TABLE), + )); + return array( $v->execute(), $v->getErrors() ); } - - /** - * Common validation rules - * - * @access private - * @return array - */ - private function commonValidationRules() - { - // TODO Update simple-validator to support array in forms - return array( - new Validators\Required('project_id', t('The project id required')), - // new Validators\Required('label[0]', t('The link label is required')), - new Validators\Integer('project_id', t('The project id must be an integer')), - new Validators\Integer('link_id', t('The link id must be an integer')), -// new Validators\Integer('id[0]', t('The link label id must be an integer')), -// new Validators\Integer('id[1]', t('The link label id must be an integer')), -// new Validators\Integer('behaviour[0]', t('The link label id must be an integer')), -// new Validators\Integer('behaviour[1]', t('The link label id must be an integer')), -// new Validators\MaxLength('label[0]', t('The maximum length is %d characters', 200), 200), -// new Validators\MaxLength('label[1]', t('The maximum length is %d characters', 200), 200) - ); - } } diff --git a/app/Model/ProjectPermission.php b/app/Model/ProjectPermission.php index fb6316b6..cd892da4 100644 --- a/app/Model/ProjectPermission.php +++ b/app/Model/ProjectPermission.php @@ -338,6 +338,23 @@ class ProjectPermission extends Base } /** + * Return a list of active project ids where the user is member + * + * @access public + * @param integer $user_id User id + * @return []integer + */ + public function getActiveMemberProjectIds($user_id) + { + return $this->db + ->table(Project::TABLE) + ->eq('user_id', $user_id) + ->eq(Project::TABLE.'.is_active', Project::ACTIVE) + ->join(self::TABLE, 'project_id', 'id') + ->findAllByColumn('projects.id'); + } + + /** * Return a list of active projects where the user is member * * @access public diff --git a/app/Model/TaskDuplication.php b/app/Model/TaskDuplication.php index faa5467f..bd593dc1 100644 --- a/app/Model/TaskDuplication.php +++ b/app/Model/TaskDuplication.php @@ -159,7 +159,6 @@ class TaskDuplication extends Base if ($new_task_id) { $this->subtask->duplicate($task_id, $new_task_id); - $this->taskLink->duplicate($task_id, $new_task_id); } return $new_task_id; diff --git a/app/Model/TaskFilter.php b/app/Model/TaskFilter.php index b5a90154..31de2795 100644 --- a/app/Model/TaskFilter.php +++ b/app/Model/TaskFilter.php @@ -18,6 +18,24 @@ class TaskFilter extends Base return $this; } + public function excludeTasks(array $task_ids) + { + $this->query->notin('id', $task_ids); + return $this; + } + + public function filterByTitle($title) + { + $this->query->ilike('title', '%'.$title.'%'); + return $this; + } + + public function filterByProjects(array $project_ids) + { + $this->query->in('project_id', $project_ids); + return $this; + } + public function filterByProject($project_id) { if ($project_id > 0) { @@ -94,6 +112,20 @@ class TaskFilter extends Base return $this->query->findAll(); } + public function toAutoCompletion() + { + return $this->query->columns('id', 'title')->filter(function(array $results) { + + foreach ($results as &$result) { + $result['value'] = $result['title']; + $result['label'] = '#'.$result['id'].' - '.$result['title']; + } + + return $results; + + })->findAll(); + } + public function toCalendarEvents() { $events = array(); diff --git a/app/Model/TaskFinder.php b/app/Model/TaskFinder.php index cf756cd8..98ece4e1 100644 --- a/app/Model/TaskFinder.php +++ b/app/Model/TaskFinder.php @@ -3,7 +3,6 @@ namespace Model; use PDO; -use Model\TaskLink; /** * Task Finder model @@ -130,29 +129,6 @@ class TaskFinder extends Base ->asc('tasks.position') ->findAll(); } - - /** - * Get ids and names of all (limited by $limit) tasks for a given project and status - * - * @access public - * @param integer $project_id Project id - * @param integer $status_id Status id - * @param integer $exclude_id Exclude this task id in the result - * @param integer $limit Number of tasks to list - * @return array - */ - public function getList($project_id, $status_id = Task::STATUS_OPEN, $exclude_id=null, $limit=50) - { - $sql = $this->db - ->hashtable(Task::TABLE) - ->eq('project_id', $project_id) - ->eq('is_active', $status_id) - ->limit($limit); - if (null != $exclude_id) { - $sql->neq('id', $exclude_id); - } - return $sql->getAll('id', 'title'); - } /** * Get all tasks for a given project and status diff --git a/app/Model/TaskLink.php b/app/Model/TaskLink.php index 09f37d2e..c712e5a8 100644 --- a/app/Model/TaskLink.php +++ b/app/Model/TaskLink.php @@ -1,20 +1,19 @@ <?php + namespace Model; -use Core\Helper; use SimpleValidator\Validator; use SimpleValidator\Validators; -use PDO; /** * TaskLink model * * @package model - * @author Olivier Maridat + * @author Olivier Maridat + * @author Frederic Guillot */ class TaskLink extends Base { - /** * SQL table name * @@ -23,339 +22,121 @@ class TaskLink extends Base const TABLE = 'task_has_links'; /** - * Get a link by the task link id + * Get a task link * * @access public - * @param integer $task_link_id - * Task link id + * @param integer $task_link_id Task link id * @return array */ public function getById($task_link_id) { - $sql = 'SELECT - tl1.id AS id, - tl1.link_label_id AS link_label_id, - tl1.task_id AS task_id, - tl1.task_inverse_id AS task_inverse_id, - tl2.id AS task_link_inverse_id - FROM ' . self::TABLE . ' tl1 - LEFT JOIN ' . Link::TABLE_LABEL . ' l1 ON l1.id = tl1.link_label_id - LEFT JOIN ' . Link::TABLE_LABEL . ' l2 ON l2.link_id = l1.link_id - LEFT JOIN ' . self::TABLE . ' tl2 ON tl2.task_id = tl1.task_inverse_id - AND ( (l1.behaviour = 2 AND tl2.link_label_id = l1.id) OR (tl2.link_label_id = l2.id) ) - WHERE tl1.id = ? - '; - $rq = $this->db->execute($sql, array( - $task_link_id - )); - return $rq->fetch(); + return $this->db->table(self::TABLE)->eq('id', $task_link_id)->findOne(); } /** - * Get the id of the inverse task link by a task link id + * Get all links attached to a task * * @access public - * @param integer $link_id - * Task link id - * @return integer + * @param integer $task_id Task id + * @return array */ - public function getInverseTaskLinkId($task_link_id) + public function getLinks($task_id) { - $sql = 'SELECT - tl2.id - FROM ' . self::TABLE . ' tl1 - LEFT JOIN ' . Link::TABLE_LABEL . ' l1 ON l1.id = tl1.link_label_id - LEFT JOIN ' . Link::TABLE_LABEL . ' l2 ON l2.link_id = l1.link_id - LEFT JOIN ' . self::TABLE . ' tl2 ON tl2.task_id = tl1.task_inverse_id - AND ( (l1.behaviour = 2 AND tl2.link_label_id = l1.id) OR (tl2.link_label_id = l2.id) ) - WHERE tl1.id = ? - '; - $rq = $this->db->execute($sql, array( - $task_link_id - )); - return $rq->fetchColumn(0); + return $this->db + ->table(self::TABLE) + ->columns( + self::TABLE.'.id', + self::TABLE.'.opposite_task_id AS task_id', + Link::TABLE.'.label', + Task::TABLE.'.title', + Task::TABLE.'.is_active', + Task::TABLE.'.project_id' + ) + ->eq(self::TABLE.'.task_id', $task_id) + ->join(Link::TABLE, 'id', 'link_id') + ->join(Task::TABLE, 'id', 'opposite_task_id') + ->findAll(); } /** - * Return all links for a given task + * Create a new link * * @access public - * @param integer $task_id - * Task id - * @return array + * @param integer $task_id Task id + * @param integer $opposite_task_id Opposite task id + * @param integer $link_id Link id + * @return boolean */ - public function getAll($task_id) + public function create($task_id, $opposite_task_id, $link_id) { - $sql = 'SELECT - tl1.id, - l.label AS label, - t2.id AS task_inverse_id, - t2.project_id AS task_inverse_project_id, - t2.title AS task_inverse_title, - t2.is_active AS task_inverse_is_active, - t2cat.name AS task_inverse_category - FROM ' . self::TABLE . ' tl1 - LEFT JOIN ' . Link::TABLE_LABEL . ' l ON l.id = tl1.link_label_id - LEFT JOIN ' . Task::TABLE . ' t2 ON t2.id = tl1.task_inverse_id - LEFT JOIN ' . Category::TABLE . ' t2cat ON t2cat.id = t2.category_id - WHERE tl1.task_id = ? - ORDER BY l.label, t2cat.name, t2.id - '; - $rq = $this->db->execute($sql, array( - $task_id + $this->db->startTransaction(); + + // Create the original link + $this->db->table(self::TABLE)->insert(array( + 'task_id' => $task_id, + 'opposite_task_id' => $opposite_task_id, + 'link_id' => $link_id, )); - $res = $rq->fetchAll(PDO::FETCH_ASSOC); - return $res; - } - /** - * Prepare data before insert/update - * - * @access public - * @param array $values - * Form values - */ - public function prepare(array &$values) - { - $this->removeFields($values, array( - 'another_link' + $link_id = $this->link->getOppositeLinkId($link_id); + + // Create the opposite link + $this->db->table(self::TABLE)->insert(array( + 'task_id' => $opposite_task_id, + 'opposite_task_id' => $task_id, + 'link_id' => $link_id, )); - $taskLink1 = array( - 'link_label_id' => $values['link_label_id'], - 'task_id' => $values['task_id'], - 'task_inverse_id' => $values['task_inverse_id'] - ); - $taskLink2 = array( - 'link_label_id' => $this->link->getInverseLinkLabelId($taskLink1['link_label_id']), - 'task_id' => $values['task_inverse_id'], - 'task_inverse_id' => $values['task_id'] - ); - if (isset($values['id']) && isset($values['task_link_inverse_id'])) { - $taskLink1['id'] = $values['id']; - $taskLink2['id'] = $values['task_link_inverse_id']; - } - return array( - $taskLink1, - $taskLink2 - ); - } - /** - * Create a link - * - * @access public - * @param array $values - * Form values - * @return bool integer - */ - public function create(array $values) - { - list($taskLink1, $taskLink2) = $this->prepare($values); - $this->db->startTransaction(); - if (! $this->db->table(self::TABLE)->save($taskLink1)) { - $this->db->cancelTransaction(); - return false; - } - if (! $this->db->table(self::TABLE)->save($taskLink2)) { - $this->db->cancelTransaction(); - return false; - } $this->db->closeTransaction(); - return true; - } - /** - * Update a link - * - * @access public - * @param array $values - * Form values - * @return bool - */ - public function update(array $values) - { - list($taskLink1, $taskLink2) = $this->prepare($values); - $this->db->startTransaction(); - if (! $this->db->table(self::TABLE) - ->eq('id', $taskLink1['id']) - ->save($taskLink1)) { - $this->db->cancelTransaction(); - return false; - } - if (! $this->db->table(self::TABLE) - ->eq('id', $taskLink2['id']) - ->save($taskLink2)) { - $this->db->cancelTransaction(); - return false; - } - $this->db->closeTransaction(); return true; } /** - * Remove a link + * Remove a link between two tasks * * @access public - * @param integer $task_link_id - * Task Link id - * @return bool + * @param integer $task_link_id + * @return boolean */ public function remove($task_link_id) { - $task_link_inverse_id = $this->getInverseTaskLinkId($task_link_id); $this->db->startTransaction(); - if (! $this->db->table(self::TABLE) - ->eq('id', $task_link_id) - ->remove()) { - $this->db->cancelTransaction(); - return false; - } - if (! $this->db->table(self::TABLE) - ->eq('id', $task_link_inverse_id) - ->remove()) { - $this->db->cancelTransaction(); - return false; - } - $this->db->closeTransaction(); - return true; - } - /** - * Duplicate all links to another task - * - * @access public - * @param integer $src_task_id - * Source task id - * @param integer $dst_task_id - * Destination task id - * @return bool - */ - public function duplicate($src_task_id, $dst_task_id) - { - return $this->db->transaction(function ($db) use($src_task_id, $dst_task_id) - { - $links = $db->table(TaskLink::TABLE) - ->columns('link_label_id', 'task_id', 'task_inverse_id') - ->eq('task_id', $src_task_id) - ->asc('id') - ->findAll(); - foreach ($links as &$link) { - $link['task_id'] = $dst_task_id; - if (! $db->table(TaskLink::TABLE) - ->save($link)) { - return false; - } - } - - $links = $db->table(TaskLink::TABLE) - ->columns('link_label_id', 'task_id', 'task_inverse_id') - ->eq('task_inverse_id', $src_task_id) - ->asc('id') - ->findAll(); - foreach ($links as &$link) { - $link['task_inverse_id'] = $dst_task_id; - if (! $db->table(TaskLink::TABLE) - ->save($link)) { - return false; - } - } - }); - } + $link = $this->getById($task_link_id); + $link_id = $this->link->getOppositeLinkId($link['link_id']); + + $this->db->table(self::TABLE)->eq('id', $task_link_id)->remove(); + + $this->db + ->table(self::TABLE) + ->eq('opposite_task_id', $link['task_id']) + ->eq('task_id', $link['opposite_task_id']) + ->eq('link_id', $link_id)->remove(); + + $this->db->closeTransaction(); - /** - * Move a task link from a link label to an other - * - * @access public - * @param integer $link_id - * Link id - * @param integer $dst_link_label_id - * Destination link label id - * @return bool - */ - public function changeLinkLabel($link_id, $dst_link_label_id, $alternate=false) - { - $taskLinks = $this->db->table(Link::TABLE_LABEL) - ->eq('link_id', $link_id) - ->neq(Link::TABLE_LABEL.'.id', $dst_link_label_id) - ->join(self::TABLE, 'link_label_id', 'id') - ->asc(self::TABLE.'.id') - ->findAllByColumn(self::TABLE.'.id'); - foreach ($taskLinks as $i => $taskLinkId) { - if (null == $taskLinkId || ($alternate && 0 != $i % 2)) { - continue; - } - if (! $this->db->table(self::TABLE) - ->eq('id', $taskLinkId) - ->save(array('link_label_id' => $dst_link_label_id))) { - return false; - } - } return true; } /** - * Validate link creation + * Validate creation * * @access public - * @param array $values - * Form values - * @return array $valid, $errors [0] = Success or not, [1] = List of errors + * @param array $values Form values + * @return array $valid, $errors [0] = Success or not, [1] = List of errors */ public function validateCreation(array $values) { - $v = new Validator($values, $this->commonValidationRules()); - $res = array( - $v->execute(), - $v->getErrors() - ); - return $res; - } + $v = new Validator($values, array( + new Validators\Required('task_id', t('Field required')), + new Validators\Required('link_id', t('Field required')), + new Validators\Required('title', t('Field required')), + )); - /** - * Validate link modification - * - * @access public - * @param array $values - * Form values - * @return array $valid, $errors [0] = Success or not, [1] = List of errors - */ - public function validateModification(array $values) - { - $rules = array( - new Validators\Required('id', t('The id is required')) - ); - $v = new Validator($values, array_merge($rules, $this->commonValidationRules())); - $res = array( + return array( $v->execute(), $v->getErrors() ); - return $res; - } - - /** - * Common validation rules - * - * @access private - * @return array - */ - private function commonValidationRules() - { - return array( - new Validators\Required('link_label_id', t('The link type is required')), - new Validators\Required('task_id', t('The task id is required')), - new Validators\Required('task_inverse_id', t('The linked task id is required')), - new Validators\Integer('id', t('The id must be an integer')), - new Validators\Integer('link_label_id', t('The link id must be an integer')), - new Validators\Integer('task_id', t('The task id must be an integer')), - new Validators\Integer('task_inverse_id', t('The related task id must be an integer')), - new Validators\Integer('task_link_inverse_id', t('The related task link id must be an integer')), - new Validators\NotEquals('task_inverse_id', 'task_id', t('A task can not be linked to itself')), - new Validators\Exists('task_inverse_id', t('This linked task id doesn\'t exist'), $this->db->getConnection(), Task::TABLE, 'id'), - new Validators\Unique(array( - 'task_inverse_id', - 'link_label_id', - 'task_id' - ), t('The exact same link already exists'), $this->db->getConnection(), self::TABLE) - ); } } diff --git a/app/Schema/Mysql.php b/app/Schema/Mysql.php index 82dd8428..947a62b3 100644 --- a/app/Schema/Mysql.php +++ b/app/Schema/Mysql.php @@ -10,59 +10,46 @@ const VERSION = 46; function version_46($pdo) { - $pdo->exec("CREATE TABLE link - ( - link_id INT NOT NULL AUTO_INCREMENT, - project_id INT NOT NULL DEFAULT -1, - PRIMARY KEY(link_id) - ) ENGINE=InnoDB CHARSET=utf8"); - $pdo->exec("CREATE TABLE link_label - ( - id INT NOT NULL AUTO_INCREMENT, - link_id INT NOT NULL, - label TEXT NOT NULL, - behaviour INT DEFAULT 2, - PRIMARY KEY(id), - FOREIGN KEY(link_id) REFERENCES link(link_id) ON DELETE CASCADE - ) ENGINE=InnoDB CHARSET=utf8"); - $pdo->exec("CREATE TABLE task_has_links - ( - id INT NOT NULL AUTO_INCREMENT, - link_label_id INT NOT NULL, - task_id INT NOT NULL, - task_inverse_id INT NOT NULL, - PRIMARY KEY(id), - FOREIGN KEY(link_label_id) REFERENCES link_label(id) ON DELETE CASCADE, - FOREIGN KEY(task_id) REFERENCES tasks(id) ON DELETE CASCADE, - FOREIGN KEY(task_inverse_id) REFERENCES tasks(id) ON DELETE CASCADE - ) ENGINE=InnoDB CHARSET=utf8"); + $pdo->exec("CREATE TABLE links ( + id INT NOT NULL AUTO_INCREMENT, + label VARCHAR(255) NOT NULL, + opposite_id INT DEFAULT 0, + PRIMARY KEY(id), + UNIQUE(label) + ) ENGINE=InnoDB CHARSET=utf8"); + + $pdo->exec("CREATE TABLE task_has_links ( + id INT NOT NULL AUTO_INCREMENT, + link_id INT NOT NULL, + task_id INT NOT NULL, + opposite_task_id INT NOT NULL, + FOREIGN KEY(link_id) REFERENCES links(id) ON DELETE CASCADE, + FOREIGN KEY(task_id) REFERENCES tasks(id) ON DELETE CASCADE, + FOREIGN KEY(opposite_task_id) REFERENCES tasks(id) ON DELETE CASCADE, + PRIMARY KEY(id) + ) ENGINE=InnoDB CHARSET=utf8"); + $pdo->exec("CREATE INDEX task_has_links_task_index ON task_has_links(task_id)"); - $pdo->exec("CREATE UNIQUE INDEX task_has_links_unique ON task_has_links(link_label_id, task_id, task_inverse_id)"); - $rq = $pdo->prepare('INSERT INTO link (project_id) VALUES (?)'); - $rq->execute(array(-1)); - $rq->execute(array(-1)); - $rq->execute(array(-1)); - $rq->execute(array(-1)); - $rq->execute(array(-1)); - $rq->execute(array(-1)); - $rq = $pdo->prepare('INSERT INTO link_label (link_id, label, behaviour) VALUES (?, ?, ?)'); - $rq->execute(array(1, t('relates to'), Link::BEHAVIOUR_BOTH)); - $rq->execute(array(2, t('blocks'), Link::BEHAVIOUR_LEFT2RIGTH)); - $rq->execute(array(2, t('is blocked by'), Link::BEHAVIOUR_RIGHT2LEFT)); - $rq->execute(array(3, t('duplicates'), Link::BEHAVIOUR_LEFT2RIGTH)); - $rq->execute(array(3, t('is duplicated by'), Link::BEHAVIOUR_RIGHT2LEFT)); - $rq->execute(array(4, t('is a child of'), Link::BEHAVIOUR_LEFT2RIGTH)); - $rq->execute(array(4, t('is a parent of'), Link::BEHAVIOUR_RIGHT2LEFT)); - $rq->execute(array(5, t('targets milestone'), Link::BEHAVIOUR_LEFT2RIGTH)); - $rq->execute(array(5, t('is a milestone of'), Link::BEHAVIOUR_RIGHT2LEFT)); - $rq->execute(array(6, t('fixes'), Link::BEHAVIOUR_LEFT2RIGTH)); - $rq->execute(array(6, t('is fixed by'), Link::BEHAVIOUR_RIGHT2LEFT)); + $pdo->exec("CREATE UNIQUE INDEX task_has_links_unique ON task_has_links(link_id, task_id, opposite_task_id)"); + + $rq = $pdo->prepare('INSERT INTO links (label, opposite_id) VALUES (?, ?)'); + $rq->execute(array('relates to', 0)); + $rq->execute(array('blocks', 3)); + $rq->execute(array('is blocked by', 2)); + $rq->execute(array('duplicates', 5)); + $rq->execute(array('is duplicated by', 4)); + $rq->execute(array('is a child of', 7)); + $rq->execute(array('is a parent of', 6)); + $rq->execute(array('targets milestone', 9)); + $rq->execute(array('is a milestone of', 8)); + $rq->execute(array('fixes', 11)); + $rq->execute(array('is fixed by', 10)); } function version_45($pdo) { $pdo->exec('ALTER TABLE tasks ADD COLUMN date_moved INT DEFAULT 0'); - + /* Update tasks.date_moved from project_activities table if tasks.date_moved = null or 0. * We take max project_activities.date_creation where event_name in task.create','task.move.column * since creation date is always less than task moves @@ -174,7 +161,7 @@ function version_38($pdo) "); $pdo->exec('ALTER TABLE tasks ADD COLUMN swimlane_id INT DEFAULT 0'); - $pdo->exec("ALTER TABLE projects ADD COLUMN default_swimlane VARCHAR(200) DEFAULT '".t('Default swimlane')."'"); + $pdo->exec("ALTER TABLE projects ADD COLUMN default_swimlane VARCHAR(200) DEFAULT 'Default swimlane'"); $pdo->exec("ALTER TABLE projects ADD COLUMN show_default_swimlane INT DEFAULT 1"); } diff --git a/app/Schema/Postgres.php b/app/Schema/Postgres.php index af1f3170..027401ff 100644 --- a/app/Schema/Postgres.php +++ b/app/Schema/Postgres.php @@ -10,50 +10,38 @@ const VERSION = 27; function version_27($pdo) { - $pdo->exec("CREATE TABLE link - ( - link_id SERIAL PRIMARY KEY, - project_id INTEGER NOT NULL DEFAULT -1 - ) ENGINE=InnoDB CHARSET=utf8"); - $pdo->exec("CREATE TABLE link_label - ( - id SERIAL PRIMARY KEY, - link_id INTEGER NOT NULL, - label TEXT NOT NULL, - behaviour INTEGER NOT NULL DEFAULT 2, - FOREIGN KEY(link_id) REFERENCES link(link_id) ON DELETE CASCADE - ) ENGINE=InnoDB CHARSET=utf8"); - $pdo->exec("CREATE TABLE task_has_links - ( - id SERIAL PRIMARY KEY, - link_label_id INTEGER NOT NULL, - task_id INTEGER NOT NULL, - task_inverse_id INTEGER NOT NULL, - FOREIGN KEY(link_label_id) REFERENCES link_label(id) ON DELETE CASCADE, - FOREIGN KEY(task_id) REFERENCES tasks(id) ON DELETE CASCADE, - FOREIGN KEY(task_inverse_id) REFERENCES tasks(id) ON DELETE CASCADE - ) ENGINE=InnoDB CHARSET=utf8"); + $pdo->exec('CREATE TABLE links ( + "id" SERIAL PRIMARY KEY, + "label" VARCHAR(255) NOT NULL, + "opposite_id" INTEGER DEFAULT 0, + UNIQUE("label") + )'); + + $pdo->exec("CREATE TABLE task_has_links ( + id SERIAL PRIMARY KEY, + link_id INTEGER NOT NULL, + task_id INTEGER NOT NULL, + opposite_task_id INTEGER NOT NULL, + FOREIGN KEY(link_id) REFERENCES links(id) ON DELETE CASCADE, + FOREIGN KEY(task_id) REFERENCES tasks(id) ON DELETE CASCADE, + FOREIGN KEY(opposite_task_id) REFERENCES tasks(id) ON DELETE CASCADE + )"); + $pdo->exec("CREATE INDEX task_has_links_task_index ON task_has_links(task_id)"); - $pdo->exec("CREATE UNIQUE INDEX task_has_links_unique ON task_has_links(link_label_id, task_id, task_inverse_id)"); - $rq = $pdo->prepare('INSERT INTO link (project_id) VALUES (?)'); - $rq->execute(array(-1)); - $rq->execute(array(-1)); - $rq->execute(array(-1)); - $rq->execute(array(-1)); - $rq->execute(array(-1)); - $rq->execute(array(-1)); - $rq = $pdo->prepare('INSERT INTO link_label (link_id, label, behaviour) VALUES (?, ?, ?)'); - $rq->execute(array(1, t('relates to'), Link::BEHAVIOUR_BOTH)); - $rq->execute(array(2, t('blocks'), Link::BEHAVIOUR_LEFT2RIGTH)); - $rq->execute(array(2, t('is blocked by'), Link::BEHAVIOUR_RIGHT2LEFT)); - $rq->execute(array(3, t('duplicates'), Link::BEHAVIOUR_LEFT2RIGTH)); - $rq->execute(array(3, t('is duplicated by'), Link::BEHAVIOUR_RIGHT2LEFT)); - $rq->execute(array(4, t('is a child of'), Link::BEHAVIOUR_LEFT2RIGTH)); - $rq->execute(array(4, t('is a parent of'), Link::BEHAVIOUR_RIGHT2LEFT)); - $rq->execute(array(5, t('targets milestone'), Link::BEHAVIOUR_LEFT2RIGTH)); - $rq->execute(array(5, t('is a milestone of'), Link::BEHAVIOUR_RIGHT2LEFT)); - $rq->execute(array(6, t('fixes'), Link::BEHAVIOUR_LEFT2RIGTH)); - $rq->execute(array(6, t('is fixed by'), Link::BEHAVIOUR_RIGHT2LEFT)); + $pdo->exec("CREATE UNIQUE INDEX task_has_links_unique ON task_has_links(link_id, task_id, opposite_task_id)"); + + $rq = $pdo->prepare('INSERT INTO links (label, opposite_id) VALUES (?, ?)'); + $rq->execute(array('relates to', 0)); + $rq->execute(array('blocks', 3)); + $rq->execute(array('is blocked by', 2)); + $rq->execute(array('duplicates', 5)); + $rq->execute(array('is duplicated by', 4)); + $rq->execute(array('is a child of', 7)); + $rq->execute(array('is a parent of', 6)); + $rq->execute(array('targets milestone', 9)); + $rq->execute(array('is a milestone of', 8)); + $rq->execute(array('fixes', 11)); + $rq->execute(array('is fixed by', 10)); } function version_26($pdo) @@ -169,7 +157,7 @@ function version_19($pdo) "); $pdo->exec('ALTER TABLE tasks ADD COLUMN swimlane_id INTEGER DEFAULT 0'); - $pdo->exec("ALTER TABLE projects ADD COLUMN default_swimlane VARCHAR(200) DEFAULT '".t('Default swimlane')."'"); + $pdo->exec("ALTER TABLE projects ADD COLUMN default_swimlane VARCHAR(200) DEFAULT 'Default swimlane'"); $pdo->exec("ALTER TABLE projects ADD COLUMN show_default_swimlane BOOLEAN DEFAULT '1'"); } diff --git a/app/Schema/Sqlite.php b/app/Schema/Sqlite.php index 727a32cd..c6dec33f 100644 --- a/app/Schema/Sqlite.php +++ b/app/Schema/Sqlite.php @@ -10,56 +10,44 @@ const VERSION = 45; function version_45($pdo) { - $pdo->exec("CREATE TABLE link - ( - link_id INTEGER PRIMARY KEY, - project_id INTEGER NOT NULL DEFAULT -1 - )"); - $pdo->exec("CREATE TABLE link_label - ( - id INTEGER PRIMARY KEY, - link_id INTEGER NOT NULL, - label TEXT NOT NULL, - behaviour INTEGER DEFAULT '2', - FOREIGN KEY(link_id) REFERENCES link(link_id) ON DELETE CASCADE - )"); - $pdo->exec("CREATE TABLE task_has_links - ( - id INTEGER PRIMARY KEY, - link_label_id INTEGER NOT NULL, - task_id INTEGER NOT NULL, - task_inverse_id INTEGER NOT NULL, - FOREIGN KEY(link_label_id) REFERENCES link_label(id) ON DELETE CASCADE, - FOREIGN KEY(task_id) REFERENCES tasks(id) ON DELETE CASCADE, - FOREIGN KEY(task_inverse_id) REFERENCES tasks(id) ON DELETE CASCADE - )"); + $pdo->exec("CREATE TABLE links ( + id INTEGER PRIMARY KEY, + label TEXT NOT NULL, + opposite_id INTEGER DEFAULT 0, + UNIQUE(label) + )"); + + $pdo->exec("CREATE TABLE task_has_links ( + id INTEGER PRIMARY KEY, + link_id INTEGER NOT NULL, + task_id INTEGER NOT NULL, + opposite_task_id INTEGER NOT NULL, + FOREIGN KEY(link_id) REFERENCES links(id) ON DELETE CASCADE, + FOREIGN KEY(task_id) REFERENCES tasks(id) ON DELETE CASCADE, + FOREIGN KEY(opposite_task_id) REFERENCES tasks(id) ON DELETE CASCADE + )"); + $pdo->exec("CREATE INDEX task_has_links_task_index ON task_has_links(task_id)"); - $pdo->exec("CREATE UNIQUE INDEX task_has_links_unique ON task_has_links(link_label_id, task_id, task_inverse_id)"); - $rq = $pdo->prepare('INSERT INTO link (project_id) VALUES (?)'); - $rq->execute(array(-1)); - $rq->execute(array(-1)); - $rq->execute(array(-1)); - $rq->execute(array(-1)); - $rq->execute(array(-1)); - $rq->execute(array(-1)); - $rq = $pdo->prepare('INSERT INTO link_label (link_id, label, behaviour) VALUES (?, ?, ?)'); - $rq->execute(array(1, t('relates to'), Link::BEHAVIOUR_BOTH)); - $rq->execute(array(2, t('blocks'), Link::BEHAVIOUR_LEFT2RIGTH)); - $rq->execute(array(2, t('is blocked by'), Link::BEHAVIOUR_RIGHT2LEFT)); - $rq->execute(array(3, t('duplicates'), Link::BEHAVIOUR_LEFT2RIGTH)); - $rq->execute(array(3, t('is duplicated by'), Link::BEHAVIOUR_RIGHT2LEFT)); - $rq->execute(array(4, t('is a child of'), Link::BEHAVIOUR_LEFT2RIGTH)); - $rq->execute(array(4, t('is a parent of'), Link::BEHAVIOUR_RIGHT2LEFT)); - $rq->execute(array(5, t('targets milestone'), Link::BEHAVIOUR_LEFT2RIGTH)); - $rq->execute(array(5, t('is a milestone of'), Link::BEHAVIOUR_RIGHT2LEFT)); - $rq->execute(array(6, t('fixes'), Link::BEHAVIOUR_LEFT2RIGTH)); - $rq->execute(array(6, t('is fixed by'), Link::BEHAVIOUR_RIGHT2LEFT)); + $pdo->exec("CREATE UNIQUE INDEX task_has_links_unique ON task_has_links(link_id, task_id, opposite_task_id)"); + + $rq = $pdo->prepare('INSERT INTO links (label, opposite_id) VALUES (?, ?)'); + $rq->execute(array('relates to', 0)); + $rq->execute(array('blocks', 3)); + $rq->execute(array('is blocked by', 2)); + $rq->execute(array('duplicates', 5)); + $rq->execute(array('is duplicated by', 4)); + $rq->execute(array('is a child of', 7)); + $rq->execute(array('is a parent of', 6)); + $rq->execute(array('targets milestone', 9)); + $rq->execute(array('is a milestone of', 8)); + $rq->execute(array('fixes', 11)); + $rq->execute(array('is fixed by', 10)); } function version_44($pdo) { $pdo->exec('ALTER TABLE tasks ADD COLUMN date_moved INTEGER DEFAULT 0'); - + /* Update tasks.date_moved from project_activities table if tasks.date_moved = null or 0. * We take max project_activities.date_creation where event_name in task.create','task.move.column * since creation date is always less than task moves @@ -169,7 +157,7 @@ function version_37($pdo) "); $pdo->exec('ALTER TABLE tasks ADD COLUMN swimlane_id INTEGER DEFAULT 0'); - $pdo->exec("ALTER TABLE projects ADD COLUMN default_swimlane TEXT DEFAULT '".t('Default swimlane')."'"); + $pdo->exec("ALTER TABLE projects ADD COLUMN default_swimlane TEXT DEFAULT 'Default swimlane'"); $pdo->exec("ALTER TABLE projects ADD COLUMN show_default_swimlane INTEGER DEFAULT 1"); } diff --git a/app/Template/board/tasklinks.php b/app/Template/board/tasklinks.php index d7b64e1d..9c4f52ca 100644 --- a/app/Template/board/tasklinks.php +++ b/app/Template/board/tasklinks.php @@ -1,28 +1,15 @@ -<section class="tooltip-tasklinks"> -<div> -<ul> -<?php -$previous_link = null; -foreach ($links as $link): ?> - <?php if (null == $previous_link || $previous_link != $link['label']): ?> - <?php if (null != $previous_link): ?> - </ul> +<div class="tooltip-tasklinks"> + <ul> + <?php foreach($links as $link): ?> + <li> + <strong><?= t($link['label']) ?></strong> + <?= $this->a( + $this->e('#'.$link['task_id'].' - '.$link['title']), + 'task', 'show', array('task_id' => $link['task_id'], 'project_id' => $link['project_id']), + false, + $link['is_active'] ? '' : 'task-link-closed' + ) ?> </li> - <?php endif ?> - <?php $previous_link = $link['label']; ?> - <li><?= t($this->e($link['label'])) ?> - <ul> - <?php endif ?> - <li<?php if (0 == $link['task_inverse_is_active']): ?> class="task-closed"<?php endif ?>> - <?= $this->e($link['task_inverse_category']) ?> - <?= $this->a('#'.$this->e($link['task_inverse_id']).' - '.trim($this->e($link['task_inverse_title'])), - 'task', - 'show', - array('task_id' => $link['task_inverse_id'], 'project_id' => $link['task_inverse_project_id'])) ?> - </li> -<?php endforeach ?> - </ul> - </li> -</ul> -</div> -</section> + <?php endforeach ?> + </ul> +</div>
\ No newline at end of file diff --git a/app/Template/config/sidebar.php b/app/Template/config/sidebar.php index a0ec8b36..89f2c203 100644 --- a/app/Template/config/sidebar.php +++ b/app/Template/config/sidebar.php @@ -11,7 +11,7 @@ <?= $this->a(t('Board settings'), 'config', 'board') ?> </li> <li> - <?= $this->a(t('Links settings'), 'link', 'index') ?> + <?= $this->a(t('Link settings'), 'link', 'index') ?> </li> <li> <?= $this->a(t('Webhooks'), 'config', 'webhook') ?> diff --git a/app/Template/link/create.php b/app/Template/link/create.php new file mode 100644 index 00000000..12589574 --- /dev/null +++ b/app/Template/link/create.php @@ -0,0 +1,18 @@ +<div class="page-header"> + <h2><?= t('Add a new link') ?></h2> +</div> + +<form action="<?= $this->u('link', 'save') ?>" method="post" autocomplete="off"> + + <?= $this->formCsrf() ?> + + <?= $this->formLabel(t('Label'), 'label') ?> + <?= $this->formText('label', $values, $errors, array('required')) ?> + + <?= $this->formLabel(t('Opposite label'), 'opposite_label') ?> + <?= $this->formText('opposite_label', $values, $errors) ?> + + <div class="form-actions"> + <input type="submit" value="<?= t('Save') ?>" class="btn btn-blue"/> + </div> +</form>
\ No newline at end of file diff --git a/app/Template/link/edit.php b/app/Template/link/edit.php index 71d4f3ca..d9ce280c 100644 --- a/app/Template/link/edit.php +++ b/app/Template/link/edit.php @@ -1,49 +1,21 @@ -<section id="link-edit-section"> -<?php use Model\Link; -if (! isset($edit)): ?> - <h3><?= t('Add a new link label') ?></h3> -<?php else: ?> <div class="page-header"> - <h2><?= t('Edit the link label') ?></h2> + <h2><?= t('Link modification') ?></h2> </div> -<?php endif ?> -<form method="post" action="<?= $this->u('link', isset($edit) ? 'update' : 'save', array('project_id' => $project['id'], 'link_id' => @$values['id'])) ?>" autocomplete="off"> +<form action="<?= $this->u('link', 'update', array('link_id' => $link['id'])) ?>" method="post" autocomplete="off"> + <?= $this->formCsrf() ?> + <?= $this->formHidden('id', $values) ?> - <?php if (isset($edit)): ?> - <?= $this->formHidden('link_id', $values) ?> - <?= $this->formHidden('id[0]', $values[0]) ?> - <?php if (isset($values[1])): ?> - <?= $this->formHidden('id[1]', $values[1]) ?> - <?php endif ?> - <?php endif ?> - <?= $this->formHidden('project_id', $values) ?> + <?= $this->formLabel(t('Label'), 'label') ?> + <?= $this->formText('label', $values, $errors, array('required')) ?> - <?= $this->formLabel(t('Link Label'), 'label[0]') ?> - <?= $this->formText('label[0]', $values[0], $errors, array('required', 'autofocus', 'placeholder="'.t('precedes').'"')) ?> » - - <?= $this->formCheckbox('behaviour[0]', t('Bidrectional link label'), Link::BEHAVIOUR_BOTH, (isset($values[0]['behaviour']) && Link::BEHAVIOUR_BOTH == $values[0]['behaviour']), 'behaviour') ?> + <?= $this->formLabel(t('Opposite label'), 'opposite_id') ?> + <?= $this->formSelect('opposite_id', $labels, $values, $errors) ?> - <div class="link-inverse-label"> - <?= $this->formLabel(t('Link Inverse Label'), 'label[1]') ?> - « <?= $this->formText('label[1]', isset($values[1]) ? $values[1] : $values, $errors, array('placeholder="'.t('follows').'"')) ?> - </div> - <div class="form-actions"> <input type="submit" value="<?= t('Save') ?>" class="btn btn-blue"/> - <?php if (isset($edit)): ?> <?= t('or') ?> - <?= $this->a(t('cancel'), 'link', 'index', array('project_id' => $project['id'])) ?> - <?php endif ?> - </div> - <?php if (! isset($edit)): ?> - <div class="alert alert-info"> - <strong><?= t('Example:') ?></strong> - <i><?= t('#9 precedes #10') ?></i> - <?= t('and therefore') ?> - <i><?= t('#10 follows #9') ?></i> + <?= $this->a(t('cancel'), 'link', 'index') ?> </div> - <?php endif ?> -</form> -</section>
\ No newline at end of file +</form>
\ No newline at end of file diff --git a/app/Template/link/index.php b/app/Template/link/index.php index 0c19b614..90d1c357 100644 --- a/app/Template/link/index.php +++ b/app/Template/link/index.php @@ -1,30 +1,33 @@ <div class="page-header"> <h2><?= t('Link labels') ?></h2> </div> - -<section> <?php if (! empty($links)): ?> <table> <tr> - <th width="70%"><?= t('Link labels') ?></th> + <th class="column-70"><?= t('Link labels') ?></th> <th><?= t('Actions') ?></th> </tr> <?php foreach ($links as $link): ?> <tr> - <td><?= t($this->e($link['label'])) ?><?php if (isset($link['label_inverse']) && !empty($link['label_inverse'])): ?> | <?= t($this->e($link['label_inverse'])) ?><?php endif ?></td> + <td> + <strong><?= t($link['label']) ?></strong> + + <?php if (! empty($link['opposite_label'])): ?> + | <?= t($link['opposite_label']) ?> + <?php endif ?> + </td> <td> <ul> - <?= $this->a(t('Edit'), 'link', 'edit', array('link_id' => $link['link_id'], 'project_id' => $link['project_id'])) ?> + <?= $this->a(t('Edit'), 'link', 'edit', array('link_id' => $link['id'])) ?> <?= t('or') ?> - <?= $this->a(t('Remove'), 'link', 'confirm', array('link_id' => $link['link_id'], 'project_id' => $link['project_id'])) ?> + <?= $this->a(t('Remove'), 'link', 'confirm', array('link_id' => $link['id'])) ?> </ul> </td> </tr> <?php endforeach ?> </table> <?php else: ?> - <?= t('There is no link yet.') ?> + <?= t('There is no link.') ?> <?php endif ?> -</section> -<?= $this->render('link/edit', array('values' => $values, 'errors' => $errors, 'project' => $project)) ?> +<?= $this->render('link/create', array('values' => $values, 'errors' => $errors)) ?>
\ No newline at end of file diff --git a/app/Template/link/remove.php b/app/Template/link/remove.php index d0b14b08..a802feb0 100644 --- a/app/Template/link/remove.php +++ b/app/Template/link/remove.php @@ -1,17 +1,15 @@ -<section id="main"> - <div class="page-header"> - <h2><?= t('Remove a link') ?></h2> - </div> +<div class="page-header"> + <h2><?= t('Remove a link') ?></h2> +</div> - <div class="confirm"> - <p class="alert alert-info"> - <?= t('Do you really want to remove this link: "%s"?', t($link[0]['label']).(isset($link[1]['label']) ? ' | '.t($link[1]['label']) : '')) ?> - </p> +<div class="confirm"> + <p class="alert alert-info"> + <?= t('Do you really want to remove this link: "%s"?', $link['label']) ?> + </p> - <div class="form-actions"> - <?= $this->a(t('Yes'), 'link', 'remove', array('project_id' => $project['id'], 'link_id' => $link[0]['link_id']), true, 'btn btn-red') ?> - <?= t('or') ?> - <?= $this->a(t('cancel'), 'link', 'index', array('project_id' => $project['id'])) ?> - </div> + <div class="form-actions"> + <?= $this->a(t('Yes'), 'link', 'remove', array('link_id' => $link['id']), true, 'btn btn-red') ?> + <?= t('or') ?> + <?= $this->a(t('cancel'), 'link', 'index') ?> </div> -</section>
\ No newline at end of file +</div>
\ No newline at end of file diff --git a/app/Template/task/public.php b/app/Template/task/public.php index c66b2433..d7acef9f 100644 --- a/app/Template/task/public.php +++ b/app/Template/task/public.php @@ -10,19 +10,19 @@ 'is_public' => true )) ?> - <?= $this->render('subtask/show', array( + <?= $this->render('tasklink/show', array( 'task' => $task, - 'subtasks' => $subtasks, + 'links' => $links, + 'project' => $project, 'not_editable' => true )) ?> - <?= $this->render('tasklink/show', array( + <?= $this->render('subtask/show', array( 'task' => $task, - 'links' => $links, - 'project' => $project, + 'subtasks' => $subtasks, 'not_editable' => true )) ?> - + <?= $this->render('task/comments', array( 'task' => $task, 'comments' => $comments, diff --git a/app/Template/task/show.php b/app/Template/task/show.php index f968a409..1ff2ef43 100644 --- a/app/Template/task/show.php +++ b/app/Template/task/show.php @@ -1,8 +1,8 @@ <?= $this->render('task/details', array('task' => $task, 'project' => $project)) ?> <?= $this->render('task/time', array('task' => $task, 'values' => $values, 'date_format' => $date_format, 'date_formats' => $date_formats)) ?> <?= $this->render('task/show_description', array('task' => $task)) ?> +<?= $this->render('tasklink/show', array('task' => $task, 'links' => $links)) ?> <?= $this->render('subtask/show', array('task' => $task, 'subtasks' => $subtasks)) ?> <?= $this->render('task/timesheet', array('task' => $task)) ?> -<?= $this->render('tasklink/show', array('task' => $task, 'links' => $links, 'link_list' => $link_list, 'task_list' => $task_list)) ?> <?= $this->render('file/show', array('task' => $task, 'files' => $files)) ?> <?= $this->render('task/comments', array('task' => $task, 'comments' => $comments, 'project' => $project)) ?> diff --git a/app/Template/tasklink/create.php b/app/Template/tasklink/create.php new file mode 100644 index 00000000..fb438cd8 --- /dev/null +++ b/app/Template/tasklink/create.php @@ -0,0 +1,27 @@ +<div class="page-header"> + <h2><?= t('Add a new link') ?></h2> +</div> + +<form action="<?= $this->u('tasklink', 'save', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>" method="post" autocomplete="off"> + + <?= $this->formCsrf() ?> + <?= $this->formHidden('task_id', $values) ?> + <?= $this->formHidden('opposite_task_id', $values) ?> + + <?= $this->formLabel(t('Label'), 'link_id') ?> + <?= $this->formSelect('link_id', $labels, $values, $errors) ?> + + <?= $this->formLabel(t('Task'), 'title') ?> + <?= $this->formText( + 'title', + $values, + $errors, + array('required', 'data-dst-field="opposite_task_id"', 'data-search-url="'.$this->u('app', 'autocomplete', array('exclude_task_id' => $task['id'])).'"'), + 'task-autocomplete') ?> + + <div class="form-actions"> + <input type="submit" value="<?= t('Save') ?>" class="btn btn-blue"/> + <?= t('or') ?> + <?= $this->a(t('cancel'), 'task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?> + </div> +</form>
\ No newline at end of file diff --git a/app/Template/tasklink/edit.php b/app/Template/tasklink/edit.php deleted file mode 100644 index e1fcded2..00000000 --- a/app/Template/tasklink/edit.php +++ /dev/null @@ -1,53 +0,0 @@ -<div class="page-header"> - <?php if (! isset($edit)): ?> - <h2><?= t('Add a link') ?></h2> - <?php else: ?> - <h2><?= t('Edit a link') ?></h2> - <?php endif ?> -</div> - -<?php if (!empty($link_list)): ?> -<form method="post" action="<?= $this->u('tasklink', isset($edit) ? 'update' : 'save', array('task_id' => $task['id'], 'link_id' => @$values['id'], 'project_id' => $task['project_id'])) ?>" autocomplete="off"> - - <?= $this->formCsrf() ?> - - <?php if (isset($edit)): ?> - <?= $this->formHidden('id', $values) ?> - <?= $this->formHidden('task_link_inverse_id', $values) ?> - <?php endif ?> - <?= $this->formHidden('task_id', $values) ?> - - #<?= $task['id'] ?> -   - <?= $this->formSelect('link_label_id', $link_list, $values, $errors, 'required autofocus') ?> -   - #<?= $this->formNumeric('task_inverse_id', $values, $errors, array('required', 'placeholder="'.t('Task id').'"', 'title="'.t('Linked task id').'"', 'list="task_inverse_ids"')) ?> - <?php if (!empty($task_list)): ?> - <datalist id="task_inverse_ids"> - <select> - <?php foreach ($task_list as $task_inverse_id => $task_inverse_title): ?> - <option value="<?= $task_inverse_id ?>">#<?= $task_inverse_id.' '.$task_inverse_title ?></option> - <?php endforeach ?> - </select> - </datalist> - <?php endif ?> - <br/> - - <?php if (! isset($edit)): ?> - <?= $this->formCheckbox('another_link', t('Create another link'), 1, isset($values['another_link']) && $values['another_link'] == 1) ?> - <?php endif ?> - - <div class="form-actions"> - <input type="submit" value="<?= t('Save') ?>" class="btn btn-blue"/> - <?= t('or') ?> - <?= $this->a(t('cancel'), 'task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?> - </div> -</form> -<?php else: ?> -<div class="alert alert-info"> - <?= t('You need to add link labels to this project before to link this task to another one.') ?> - <ul> - <li><?= $this->a(t('Add link labels'), 'link', 'index', array('project_id' => $task['project_id'])) ?></li> - </ul> -</div> -<?php endif ?> diff --git a/app/Template/tasklink/remove.php b/app/Template/tasklink/remove.php index 2ed87be7..9322ec24 100644 --- a/app/Template/tasklink/remove.php +++ b/app/Template/tasklink/remove.php @@ -4,13 +4,11 @@ <div class="confirm"> <p class="alert alert-info"> - <?= t('Do you really want to remove this link with task #%s?', $link['task_inverse_id']) ?> - <br /> - + <?= t('Do you really want to remove this link with task #%d?', $link['opposite_task_id']) ?> </p> <div class="form-actions"> - <?= $this->a(t('Yes'), 'tasklink', 'remove', array('task_id' => $task['id'], 'link_id' => $link['id'], 'project_id' => $task['project_id']), true, 'btn btn-red') ?> + <?= $this->a(t('Yes'), 'tasklink', 'remove', array('link_id' => $link['id'], 'task_id' => $task['id'], 'project_id' => $task['project_id']), true, 'btn btn-red') ?> <?= t('or') ?> <?= $this->a(t('cancel'), 'task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?> </div> diff --git a/app/Template/tasklink/show.php b/app/Template/tasklink/show.php index ac49d070..ca4e4383 100644 --- a/app/Template/tasklink/show.php +++ b/app/Template/tasklink/show.php @@ -1,68 +1,41 @@ <?php if (! empty($links)): ?> -<aside id="links" class="task-show-section"> - <div class="page-header"> - <h2><?= t('Links') ?></h2> - </div> - - <table class="link-table"> - <tr> - <th><?= t('Label') ?></th> - <th width="70%"><?= t('Task') ?></th> - <?php if (! isset($not_editable)): ?> - <th><?= t('Actions') ?></th> - <?php endif ?> - </tr> - <?php $previous_link = null; - foreach ($links as $link): ?> - <tr> +<div class="page-header"> + <h2><?= t('Links') ?></h2> +</div> +<table class="table-fixed" id="links"> + <tr> + <th class="column-30"><?= t('Label') ?></th> + <th class="column-60"><?= t('Task') ?></th> + <?php if (! isset($not_editable)): ?> + <th><?= t('Action') ?></th> + <?php endif ?> + </tr> + <?php foreach ($links as $link): ?> + <tr> + <td><?= t('This task') ?> <strong><?= t($link['label']) ?></strong></td> + <?php if (! isset($not_editable)): ?> <td> - <?php if (null == $previous_link || $previous_link != $link['label']): - $previous_link = $link['label']; ?> - <?= t($this->e($link['label'])) ?> - <?php endif ?> + <?= $this->a( + $this->e('#'.$link['task_id'].' - '.$link['title']), + 'task', 'show', array('task_id' => $link['task_id'], 'project_id' => $link['project_id']), + false, + $link['is_active'] ? '' : 'task-link-closed' + ) ?> </td> <td> - <?php if (0 == $link['task_inverse_is_active']): ?><span class="task-closed"><?php endif ?> - <?= $this->e($link['task_inverse_category']) ?> - <?php if (! isset($not_editable)): ?> - <?= $this->a('#'.$this->e($link['task_inverse_id']).' - '.trim($this->e($link['task_inverse_title'])), 'task', 'show', array('task_id' => $link['task_inverse_id'], 'project_id' => $link['task_inverse_project_id'])) ?> - <?php else: ?> - <?= $this->a('#'.$this->e($link['task_inverse_id']).' - '.trim($this->e($link['task_inverse_title'])), 'task', 'readonly', array('task_id' => $link['task_inverse_id'], 'project_id' => $link['task_inverse_project_id'], 'token' => $project['token'])) ?> - <?php endif ?> - <?php if (0 == $link['task_inverse_is_active']): ?></span><?php endif ?> + <?= $this->a(t('Remove'), 'tasklink', 'confirm', array('link_id' => $link['id'], 'task_id' => $task['id'], 'project_id' => $task['project_id'])) ?> </td> - <?php if (! isset($not_editable)): ?> + <?php else: ?> <td> - <ul> - <li><?= $this->a(t('Edit'), 'tasklink', 'edit', array('task_id' => $task['id'], 'link_id' => $link['id'], 'project_id' => $task['project_id'])) ?></li> - <li><?= $this->a(t('Remove'), 'tasklink', 'confirm', array('task_id' => $task['id'], 'link_id' => $link['id'], 'project_id' => $task['project_id'])) ?></li> - </ul> + <?= $this->a( + $this->e('#'.$link['task_id'].' - '.$link['title']), + 'task', 'readonly', array('task_id' => $link['task_id'], 'token' => $project['token']), + false, + $link['is_active'] ? '' : 'task-link-closed' + ) ?> </td> - <?php endif ?> - </tr> - <?php endforeach ?> - </table> - - <?php if (! isset($not_editable) && !empty($link_list)): ?> - <form method="post" action="<?= $this->u('tasklink', 'save', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>" autocomplete="off"> - <?= $this->formCsrf() ?> - <?= $this->formHidden('task_id', array('task_id' => $task['id'])) ?> - #<?= $this->e($task['id']) ?> -   - <?= $this->formSelect('link_label_id', $link_list, array(), array(), 'required autofocus') ?> -   - #<?= $this->formNumeric('task_inverse_id', array(), array(), array('required', 'placeholder="'.t('Task id').'"', 'title="'.t('Linked task id').'"', 'list="task_inverse_ids"')) ?> - <?php if (!empty($task_list)): ?> - <datalist id="task_inverse_ids"> - <select> - <?php foreach ($task_list as $task_inverse_id => $task_inverse_title): ?> - <option value="<?= $task_inverse_id ?>">#<?= $task_inverse_id.' '.$task_inverse_title ?></option> - <?php endforeach ?> - </select> - </datalist> <?php endif ?> - <input type="submit" value="<?= t('Add') ?>" class="btn btn-blue"/> - </form> - <?php endif ?> -</aside> -<?php endif ?> + </tr> + <?php endforeach ?> +</table> +<?php endif ?>
\ No newline at end of file |