summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
Diffstat (limited to 'app')
-rw-r--r--app/Controller/PredefinedTaskDescriptionController.php116
-rw-r--r--app/Controller/ProjectPredefinedContentController.php15
-rw-r--r--app/Core/Base.php2
-rw-r--r--app/Helper/TaskHelper.php24
-rw-r--r--app/Locale/bs_BA/translations.php11
-rw-r--r--app/Locale/ca_ES/translations.php11
-rw-r--r--app/Locale/cs_CZ/translations.php11
-rw-r--r--app/Locale/da_DK/translations.php11
-rw-r--r--app/Locale/de_DE/translations.php11
-rw-r--r--app/Locale/el_GR/translations.php11
-rw-r--r--app/Locale/es_ES/translations.php11
-rw-r--r--app/Locale/fi_FI/translations.php11
-rw-r--r--app/Locale/fr_FR/translations.php11
-rw-r--r--app/Locale/hr_HR/translations.php11
-rw-r--r--app/Locale/hu_HU/translations.php11
-rw-r--r--app/Locale/id_ID/translations.php11
-rw-r--r--app/Locale/it_IT/translations.php11
-rw-r--r--app/Locale/ja_JP/translations.php11
-rw-r--r--app/Locale/ko_KR/translations.php11
-rw-r--r--app/Locale/my_MY/translations.php11
-rw-r--r--app/Locale/nb_NO/translations.php11
-rw-r--r--app/Locale/nl_NL/translations.php11
-rw-r--r--app/Locale/pl_PL/translations.php11
-rw-r--r--app/Locale/pt_BR/translations.php11
-rw-r--r--app/Locale/pt_PT/translations.php11
-rw-r--r--app/Locale/ru_RU/translations.php11
-rw-r--r--app/Locale/sr_Latn_RS/translations.php11
-rw-r--r--app/Locale/sv_SE/translations.php11
-rw-r--r--app/Locale/th_TH/translations.php11
-rw-r--r--app/Locale/tr_TR/translations.php11
-rw-r--r--app/Locale/vi_VN/translations.php11
-rw-r--r--app/Locale/zh_CN/translations.php11
-rw-r--r--app/Model/PredefinedTaskDescriptionModel.php42
-rw-r--r--app/Schema/Mysql.php14
-rw-r--r--app/Schema/Postgres.php13
-rw-r--r--app/Schema/Sqlite.php13
-rw-r--r--app/ServiceProvider/AuthenticationProvider.php1
-rw-r--r--app/ServiceProvider/ClassProvider.php2
-rw-r--r--app/Template/predefined_task_description/create.php14
-rw-r--r--app/Template/predefined_task_description/edit.php14
-rw-r--r--app/Template/predefined_task_description/remove.php15
-rw-r--r--app/Template/project_predefined_content/show.php33
-rw-r--r--app/Template/task_creation/show.php1
-rw-r--r--app/Validator/PredefinedTaskDescriptionValidator.php22
44 files changed, 633 insertions, 16 deletions
diff --git a/app/Controller/PredefinedTaskDescriptionController.php b/app/Controller/PredefinedTaskDescriptionController.php
new file mode 100644
index 00000000..1b7eca12
--- /dev/null
+++ b/app/Controller/PredefinedTaskDescriptionController.php
@@ -0,0 +1,116 @@
+<?php
+
+namespace Kanboard\Controller;
+
+use Kanboard\Core\Controller\PageNotFoundException;
+
+/**
+ * Predefined Task Description Controller
+ *
+ * @package Kanboard\Controller
+ * @author Frederic Guillot
+ */
+class PredefinedTaskDescriptionController extends BaseController
+{
+ public function create(array $values = array(), array $errors = array())
+ {
+ $project = $this->getProject();
+
+ $this->response->html($this->template->render('predefined_task_description/create', array(
+ 'values' => $values,
+ 'errors' => $errors,
+ 'project' => $project,
+ )));
+ }
+
+ public function save()
+ {
+ $project = $this->getProject();
+ $values = $this->request->getValues();
+
+ list($valid, $errors) = $this->predefinedTaskDescriptionValidator->validate($values);
+
+ if ($valid) {
+ if ($this->predefinedTaskDescriptionModel->create($project['id'], $values['title'], $values['description']) !== false) {
+ $this->flash->success(t('Template created successfully.'));
+ } else {
+ $this->flash->failure(t('Unable to create this template.'));
+ }
+
+ $this->response->redirect($this->helper->url->to('ProjectPredefinedContentController', 'show', array('project_id' => $project['id'])), true);
+ } else {
+ $this->create($values, $errors);
+ }
+ }
+
+ public function edit(array $values = array(), array $errors = array())
+ {
+ $project = $this->getProject();
+ $template = $this->predefinedTaskDescriptionModel->getById($project['id'], $this->request->getIntegerParam('id'));
+
+ $this->response->html($this->template->render('predefined_task_description/edit', array(
+ 'values' => empty($values) ? $template : $values,
+ 'template' => $template,
+ 'errors' => $errors,
+ 'project' => $project,
+ )));
+ }
+
+ public function update()
+ {
+ $project = $this->getProject();
+ $template = $this->getTemplate($project);
+ $values = $this->request->getValues();
+
+ list($valid, $errors) = $this->predefinedTaskDescriptionValidator->validate($values);
+
+ if ($valid) {
+ if ($this->predefinedTaskDescriptionModel->update($project['id'], $template['id'], $values['title'], $values['description']) !== false) {
+ $this->flash->success(t('Template updated successfully.'));
+ } else {
+ $this->flash->failure(t('Unable to update this template.'));
+ }
+
+ $this->response->redirect($this->helper->url->to('ProjectPredefinedContentController', 'show', array('project_id' => $project['id'])), true);
+ } else {
+ $this->edit($values, $errors);
+ }
+ }
+
+ public function confirm()
+ {
+ $project = $this->getProject();
+ $template = $this->getTemplate($project);
+
+ $this->response->html($this->template->render('predefined_task_description/remove', array(
+ 'template' => $template,
+ 'project' => $project,
+ )));
+ }
+
+ public function remove()
+ {
+ $this->checkCSRFParam();
+ $project = $this->getProject();
+ $template = $this->getTemplate($project);
+
+ if ($this->predefinedTaskDescriptionModel->remove($project['id'], $template['id'])) {
+ $this->flash->success(t('Template removed successfully.'));
+ } else {
+ $this->flash->failure(t('Unable to remove this template.'));
+ }
+
+ $this->response->redirect($this->helper->url->to('ProjectPredefinedContentController', 'show', array('project_id' => $project['id'])), true);
+ }
+
+ protected function getTemplate(array $project)
+ {
+ $template = $this->predefinedTaskDescriptionModel->getById($project['id'], $this->request->getIntegerParam('id'));
+
+ if (empty($template)) {
+ throw new PageNotFoundException();
+ }
+
+ return $template;
+ }
+} \ No newline at end of file
diff --git a/app/Controller/ProjectPredefinedContentController.php b/app/Controller/ProjectPredefinedContentController.php
index 1195dfa3..709d6b79 100644
--- a/app/Controller/ProjectPredefinedContentController.php
+++ b/app/Controller/ProjectPredefinedContentController.php
@@ -10,13 +10,6 @@ namespace Kanboard\Controller;
*/
class ProjectPredefinedContentController extends BaseController
{
- /**
- * Edit project
- *
- * @access public
- * @param array $values
- * @param array $errors
- */
public function show(array $values = array(), array $errors = array())
{
$project = $this->getProject();
@@ -25,15 +18,11 @@ class ProjectPredefinedContentController extends BaseController
'values' => empty($values) ? $project : $values,
'errors' => $errors,
'project' => $project,
- 'title' => t('Predefined Contents')
+ 'predefined_task_descriptions' => $this->predefinedTaskDescriptionModel->getAll($project['id']),
+ 'title' => t('Predefined Contents'),
)));
}
- /**
- * Validate and update a project
- *
- * @access public
- */
public function update()
{
$project = $this->getProject();
diff --git a/app/Core/Base.php b/app/Core/Base.php
index bf89c00f..4e553746 100644
--- a/app/Core/Base.php
+++ b/app/Core/Base.php
@@ -105,6 +105,7 @@ use Pimple\Container;
* @property \Kanboard\Model\LinkModel $linkModel
* @property \Kanboard\Model\NotificationModel $notificationModel
* @property \Kanboard\Model\PasswordResetModel $passwordResetModel
+ * @property \Kanboard\Model\PredefinedTaskDescriptionModel $predefinedTaskDescriptionModel
* @property \Kanboard\Model\ProjectModel $projectModel
* @property \Kanboard\Model\ProjectActivityModel $projectActivityModel
* @property \Kanboard\Model\ProjectDuplicationModel $projectDuplicationModel
@@ -179,6 +180,7 @@ use Pimple\Container;
* @property \Kanboard\Validator\TaskLinkValidator $taskLinkValidator
* @property \Kanboard\Validator\TaskValidator $taskValidator
* @property \Kanboard\Validator\UserValidator $userValidator
+ * @property \Kanboard\Validator\PredefinedTaskDescriptionValidator $predefinedTaskDescriptionValidator
* @property \Kanboard\Import\TaskImport $taskImport
* @property \Kanboard\Import\UserImport $userImport
* @property \Kanboard\Export\SubtaskExport $subtaskExport
diff --git a/app/Helper/TaskHelper.php b/app/Helper/TaskHelper.php
index b105eaec..43347a6d 100644
--- a/app/Helper/TaskHelper.php
+++ b/app/Helper/TaskHelper.php
@@ -61,6 +61,30 @@ class TaskHelper extends Base
return $this->helper->form->textEditor('description', $values, $errors, array('tabindex' => 2));
}
+ public function renderDescriptionTemplateDropdown($projectId)
+ {
+ $templates = $this->predefinedTaskDescriptionModel->getAll($projectId);
+
+ if (! empty($templates)) {
+ $html = '<div class="dropdown">';
+ $html .= '<a href="#" class="dropdown-menu dropdown-menu-link-icon"><i class="fa fa-floppy-o fa-fw" aria-hidden="true"></i>'.t('Description Templates').' <i class="fa fa-caret-down" aria-hidden="true"></i></a>';
+ $html .= '<ul>';
+
+ foreach ($templates as $template) {
+ $html .= '<li>';
+ $html .= '<a href="#" data-template-target="textarea[name=description]" data-template="'.$this->helper->text->e($template['description']).'" class="js-template">';
+ $html .= $this->helper->text->e($template['title']);
+ $html .= '</a>';
+ $html .= '</li>';
+ }
+
+ $html .= '</ul></div>';
+ return $html;
+ }
+
+ return '';
+ }
+
public function renderTagField(array $project, array $tags = array())
{
$options = $this->tagModel->getAssignableList($project['id']);
diff --git a/app/Locale/bs_BA/translations.php b/app/Locale/bs_BA/translations.php
index ce0374f2..d53f9291 100644
--- a/app/Locale/bs_BA/translations.php
+++ b/app/Locale/bs_BA/translations.php
@@ -1345,4 +1345,15 @@ return array(
// 'Enter one subtask by line.' => '',
// 'Predefined Contents' => '',
// 'Predefined contents' => '',
+ // 'Predefined Task Description' => '',
+ // 'Do you really want to remove this template? "%s"' => '',
+ // 'Add predefined task description' => '',
+ // 'Predefined Task Descriptions' => '',
+ // 'Template created successfully.' => '',
+ // 'Unable to create this template.' => '',
+ // 'Template updated successfully.' => '',
+ // 'Unable to update this template.' => '',
+ // 'Template removed successfully.' => '',
+ // 'Unable to remove this template.' => '',
+ // 'Description Templates' => '',
);
diff --git a/app/Locale/ca_ES/translations.php b/app/Locale/ca_ES/translations.php
index 8e14e2fb..f114484f 100644
--- a/app/Locale/ca_ES/translations.php
+++ b/app/Locale/ca_ES/translations.php
@@ -1345,4 +1345,15 @@ return array(
// 'Enter one subtask by line.' => '',
// 'Predefined Contents' => '',
// 'Predefined contents' => '',
+ // 'Predefined Task Description' => '',
+ // 'Do you really want to remove this template? "%s"' => '',
+ // 'Add predefined task description' => '',
+ // 'Predefined Task Descriptions' => '',
+ // 'Template created successfully.' => '',
+ // 'Unable to create this template.' => '',
+ // 'Template updated successfully.' => '',
+ // 'Unable to update this template.' => '',
+ // 'Template removed successfully.' => '',
+ // 'Unable to remove this template.' => '',
+ // 'Description Templates' => '',
);
diff --git a/app/Locale/cs_CZ/translations.php b/app/Locale/cs_CZ/translations.php
index 92645582..8b713c8c 100644
--- a/app/Locale/cs_CZ/translations.php
+++ b/app/Locale/cs_CZ/translations.php
@@ -1345,4 +1345,15 @@ return array(
// 'Enter one subtask by line.' => '',
// 'Predefined Contents' => '',
// 'Predefined contents' => '',
+ // 'Predefined Task Description' => '',
+ // 'Do you really want to remove this template? "%s"' => '',
+ // 'Add predefined task description' => '',
+ // 'Predefined Task Descriptions' => '',
+ // 'Template created successfully.' => '',
+ // 'Unable to create this template.' => '',
+ // 'Template updated successfully.' => '',
+ // 'Unable to update this template.' => '',
+ // 'Template removed successfully.' => '',
+ // 'Unable to remove this template.' => '',
+ // 'Description Templates' => '',
);
diff --git a/app/Locale/da_DK/translations.php b/app/Locale/da_DK/translations.php
index cfd27c2c..fef985b4 100644
--- a/app/Locale/da_DK/translations.php
+++ b/app/Locale/da_DK/translations.php
@@ -1345,4 +1345,15 @@ return array(
// 'Enter one subtask by line.' => '',
// 'Predefined Contents' => '',
// 'Predefined contents' => '',
+ // 'Predefined Task Description' => '',
+ // 'Do you really want to remove this template? "%s"' => '',
+ // 'Add predefined task description' => '',
+ // 'Predefined Task Descriptions' => '',
+ // 'Template created successfully.' => '',
+ // 'Unable to create this template.' => '',
+ // 'Template updated successfully.' => '',
+ // 'Unable to update this template.' => '',
+ // 'Template removed successfully.' => '',
+ // 'Unable to remove this template.' => '',
+ // 'Description Templates' => '',
);
diff --git a/app/Locale/de_DE/translations.php b/app/Locale/de_DE/translations.php
index 81139377..e2d9ba5a 100644
--- a/app/Locale/de_DE/translations.php
+++ b/app/Locale/de_DE/translations.php
@@ -1345,4 +1345,15 @@ return array(
// 'Enter one subtask by line.' => '',
// 'Predefined Contents' => '',
// 'Predefined contents' => '',
+ // 'Predefined Task Description' => '',
+ // 'Do you really want to remove this template? "%s"' => '',
+ // 'Add predefined task description' => '',
+ // 'Predefined Task Descriptions' => '',
+ // 'Template created successfully.' => '',
+ // 'Unable to create this template.' => '',
+ // 'Template updated successfully.' => '',
+ // 'Unable to update this template.' => '',
+ // 'Template removed successfully.' => '',
+ // 'Unable to remove this template.' => '',
+ // 'Description Templates' => '',
);
diff --git a/app/Locale/el_GR/translations.php b/app/Locale/el_GR/translations.php
index 9bd08132..908c015e 100644
--- a/app/Locale/el_GR/translations.php
+++ b/app/Locale/el_GR/translations.php
@@ -1345,4 +1345,15 @@ return array(
// 'Enter one subtask by line.' => '',
// 'Predefined Contents' => '',
// 'Predefined contents' => '',
+ // 'Predefined Task Description' => '',
+ // 'Do you really want to remove this template? "%s"' => '',
+ // 'Add predefined task description' => '',
+ // 'Predefined Task Descriptions' => '',
+ // 'Template created successfully.' => '',
+ // 'Unable to create this template.' => '',
+ // 'Template updated successfully.' => '',
+ // 'Unable to update this template.' => '',
+ // 'Template removed successfully.' => '',
+ // 'Unable to remove this template.' => '',
+ // 'Description Templates' => '',
);
diff --git a/app/Locale/es_ES/translations.php b/app/Locale/es_ES/translations.php
index d0777c00..b97e24eb 100644
--- a/app/Locale/es_ES/translations.php
+++ b/app/Locale/es_ES/translations.php
@@ -1345,4 +1345,15 @@ return array(
// 'Enter one subtask by line.' => '',
// 'Predefined Contents' => '',
// 'Predefined contents' => '',
+ // 'Predefined Task Description' => '',
+ // 'Do you really want to remove this template? "%s"' => '',
+ // 'Add predefined task description' => '',
+ // 'Predefined Task Descriptions' => '',
+ // 'Template created successfully.' => '',
+ // 'Unable to create this template.' => '',
+ // 'Template updated successfully.' => '',
+ // 'Unable to update this template.' => '',
+ // 'Template removed successfully.' => '',
+ // 'Unable to remove this template.' => '',
+ // 'Description Templates' => '',
);
diff --git a/app/Locale/fi_FI/translations.php b/app/Locale/fi_FI/translations.php
index ad2fa6b1..a508162d 100644
--- a/app/Locale/fi_FI/translations.php
+++ b/app/Locale/fi_FI/translations.php
@@ -1345,4 +1345,15 @@ return array(
// 'Enter one subtask by line.' => '',
// 'Predefined Contents' => '',
// 'Predefined contents' => '',
+ // 'Predefined Task Description' => '',
+ // 'Do you really want to remove this template? "%s"' => '',
+ // 'Add predefined task description' => '',
+ // 'Predefined Task Descriptions' => '',
+ // 'Template created successfully.' => '',
+ // 'Unable to create this template.' => '',
+ // 'Template updated successfully.' => '',
+ // 'Unable to update this template.' => '',
+ // 'Template removed successfully.' => '',
+ // 'Unable to remove this template.' => '',
+ // 'Description Templates' => '',
);
diff --git a/app/Locale/fr_FR/translations.php b/app/Locale/fr_FR/translations.php
index 24367389..d281def6 100644
--- a/app/Locale/fr_FR/translations.php
+++ b/app/Locale/fr_FR/translations.php
@@ -1345,4 +1345,15 @@ return array(
'Enter one subtask by line.' => 'Entrez une sous-tâche par ligne.',
'Predefined Contents' => 'Contenus prédéfini',
'Predefined contents' => 'Contenus prédéfini',
+ 'Predefined Task Description' => 'Modèles de description de tâches',
+ 'Do you really want to remove this template? "%s"' => 'Voulez-vous vraiment supprimer ce modèle ? « %s »',
+ 'Add predefined task description' => 'Ajouter un modèle de description de tâche',
+ 'Predefined Task Descriptions' => 'Modèles de description de tâches',
+ 'Template created successfully.' => 'Modèle créé avec succès.',
+ 'Unable to create this template.' => 'Impossible de créer ce modèle.',
+ 'Template updated successfully.' => 'Modèle mis à jour avec succès.',
+ 'Unable to update this template.' => 'Impossible de mettre à jour ce modèle.',
+ 'Template removed successfully.' => 'Modèle supprimé avec succès.',
+ 'Unable to remove this template.' => 'Impossible de supprimer ce modèle.',
+ 'Description Templates' => 'Modèles de description',
);
diff --git a/app/Locale/hr_HR/translations.php b/app/Locale/hr_HR/translations.php
index fa4c87d7..5f2f0a70 100644
--- a/app/Locale/hr_HR/translations.php
+++ b/app/Locale/hr_HR/translations.php
@@ -1345,4 +1345,15 @@ return array(
// 'Enter one subtask by line.' => '',
// 'Predefined Contents' => '',
// 'Predefined contents' => '',
+ // 'Predefined Task Description' => '',
+ // 'Do you really want to remove this template? "%s"' => '',
+ // 'Add predefined task description' => '',
+ // 'Predefined Task Descriptions' => '',
+ // 'Template created successfully.' => '',
+ // 'Unable to create this template.' => '',
+ // 'Template updated successfully.' => '',
+ // 'Unable to update this template.' => '',
+ // 'Template removed successfully.' => '',
+ // 'Unable to remove this template.' => '',
+ // 'Description Templates' => '',
);
diff --git a/app/Locale/hu_HU/translations.php b/app/Locale/hu_HU/translations.php
index c8f9d8ea..740a8e4f 100644
--- a/app/Locale/hu_HU/translations.php
+++ b/app/Locale/hu_HU/translations.php
@@ -1345,4 +1345,15 @@ return array(
// 'Enter one subtask by line.' => '',
// 'Predefined Contents' => '',
// 'Predefined contents' => '',
+ // 'Predefined Task Description' => '',
+ // 'Do you really want to remove this template? "%s"' => '',
+ // 'Add predefined task description' => '',
+ // 'Predefined Task Descriptions' => '',
+ // 'Template created successfully.' => '',
+ // 'Unable to create this template.' => '',
+ // 'Template updated successfully.' => '',
+ // 'Unable to update this template.' => '',
+ // 'Template removed successfully.' => '',
+ // 'Unable to remove this template.' => '',
+ // 'Description Templates' => '',
);
diff --git a/app/Locale/id_ID/translations.php b/app/Locale/id_ID/translations.php
index aad497ad..2fcbbf76 100644
--- a/app/Locale/id_ID/translations.php
+++ b/app/Locale/id_ID/translations.php
@@ -1345,4 +1345,15 @@ return array(
// 'Enter one subtask by line.' => '',
// 'Predefined Contents' => '',
// 'Predefined contents' => '',
+ // 'Predefined Task Description' => '',
+ // 'Do you really want to remove this template? "%s"' => '',
+ // 'Add predefined task description' => '',
+ // 'Predefined Task Descriptions' => '',
+ // 'Template created successfully.' => '',
+ // 'Unable to create this template.' => '',
+ // 'Template updated successfully.' => '',
+ // 'Unable to update this template.' => '',
+ // 'Template removed successfully.' => '',
+ // 'Unable to remove this template.' => '',
+ // 'Description Templates' => '',
);
diff --git a/app/Locale/it_IT/translations.php b/app/Locale/it_IT/translations.php
index 98647574..13cfd247 100644
--- a/app/Locale/it_IT/translations.php
+++ b/app/Locale/it_IT/translations.php
@@ -1345,4 +1345,15 @@ return array(
// 'Enter one subtask by line.' => '',
// 'Predefined Contents' => '',
// 'Predefined contents' => '',
+ // 'Predefined Task Description' => '',
+ // 'Do you really want to remove this template? "%s"' => '',
+ // 'Add predefined task description' => '',
+ // 'Predefined Task Descriptions' => '',
+ // 'Template created successfully.' => '',
+ // 'Unable to create this template.' => '',
+ // 'Template updated successfully.' => '',
+ // 'Unable to update this template.' => '',
+ // 'Template removed successfully.' => '',
+ // 'Unable to remove this template.' => '',
+ // 'Description Templates' => '',
);
diff --git a/app/Locale/ja_JP/translations.php b/app/Locale/ja_JP/translations.php
index 86c4800b..1c7c8879 100644
--- a/app/Locale/ja_JP/translations.php
+++ b/app/Locale/ja_JP/translations.php
@@ -1345,4 +1345,15 @@ return array(
'Enter one subtask by line.' => '1行に1件のサブタスクを入力',
// 'Predefined Contents' => '',
// 'Predefined contents' => '',
+ // 'Predefined Task Description' => '',
+ // 'Do you really want to remove this template? "%s"' => '',
+ // 'Add predefined task description' => '',
+ // 'Predefined Task Descriptions' => '',
+ // 'Template created successfully.' => '',
+ // 'Unable to create this template.' => '',
+ // 'Template updated successfully.' => '',
+ // 'Unable to update this template.' => '',
+ // 'Template removed successfully.' => '',
+ // 'Unable to remove this template.' => '',
+ // 'Description Templates' => '',
);
diff --git a/app/Locale/ko_KR/translations.php b/app/Locale/ko_KR/translations.php
index 083ddc67..8eafaedb 100644
--- a/app/Locale/ko_KR/translations.php
+++ b/app/Locale/ko_KR/translations.php
@@ -1345,4 +1345,15 @@ return array(
// 'Enter one subtask by line.' => '',
// 'Predefined Contents' => '',
// 'Predefined contents' => '',
+ // 'Predefined Task Description' => '',
+ // 'Do you really want to remove this template? "%s"' => '',
+ // 'Add predefined task description' => '',
+ // 'Predefined Task Descriptions' => '',
+ // 'Template created successfully.' => '',
+ // 'Unable to create this template.' => '',
+ // 'Template updated successfully.' => '',
+ // 'Unable to update this template.' => '',
+ // 'Template removed successfully.' => '',
+ // 'Unable to remove this template.' => '',
+ // 'Description Templates' => '',
);
diff --git a/app/Locale/my_MY/translations.php b/app/Locale/my_MY/translations.php
index 50544f2e..b0bcf90f 100644
--- a/app/Locale/my_MY/translations.php
+++ b/app/Locale/my_MY/translations.php
@@ -1345,4 +1345,15 @@ return array(
// 'Enter one subtask by line.' => '',
// 'Predefined Contents' => '',
// 'Predefined contents' => '',
+ // 'Predefined Task Description' => '',
+ // 'Do you really want to remove this template? "%s"' => '',
+ // 'Add predefined task description' => '',
+ // 'Predefined Task Descriptions' => '',
+ // 'Template created successfully.' => '',
+ // 'Unable to create this template.' => '',
+ // 'Template updated successfully.' => '',
+ // 'Unable to update this template.' => '',
+ // 'Template removed successfully.' => '',
+ // 'Unable to remove this template.' => '',
+ // 'Description Templates' => '',
);
diff --git a/app/Locale/nb_NO/translations.php b/app/Locale/nb_NO/translations.php
index 3fe60424..9f563fd5 100644
--- a/app/Locale/nb_NO/translations.php
+++ b/app/Locale/nb_NO/translations.php
@@ -1345,4 +1345,15 @@ return array(
// 'Enter one subtask by line.' => '',
// 'Predefined Contents' => '',
// 'Predefined contents' => '',
+ // 'Predefined Task Description' => '',
+ // 'Do you really want to remove this template? "%s"' => '',
+ // 'Add predefined task description' => '',
+ // 'Predefined Task Descriptions' => '',
+ // 'Template created successfully.' => '',
+ // 'Unable to create this template.' => '',
+ // 'Template updated successfully.' => '',
+ // 'Unable to update this template.' => '',
+ // 'Template removed successfully.' => '',
+ // 'Unable to remove this template.' => '',
+ // 'Description Templates' => '',
);
diff --git a/app/Locale/nl_NL/translations.php b/app/Locale/nl_NL/translations.php
index 169654c4..eeb99d5f 100644
--- a/app/Locale/nl_NL/translations.php
+++ b/app/Locale/nl_NL/translations.php
@@ -1345,4 +1345,15 @@ return array(
// 'Enter one subtask by line.' => '',
// 'Predefined Contents' => '',
// 'Predefined contents' => '',
+ // 'Predefined Task Description' => '',
+ // 'Do you really want to remove this template? "%s"' => '',
+ // 'Add predefined task description' => '',
+ // 'Predefined Task Descriptions' => '',
+ // 'Template created successfully.' => '',
+ // 'Unable to create this template.' => '',
+ // 'Template updated successfully.' => '',
+ // 'Unable to update this template.' => '',
+ // 'Template removed successfully.' => '',
+ // 'Unable to remove this template.' => '',
+ // 'Description Templates' => '',
);
diff --git a/app/Locale/pl_PL/translations.php b/app/Locale/pl_PL/translations.php
index d0858db9..ec684e98 100644
--- a/app/Locale/pl_PL/translations.php
+++ b/app/Locale/pl_PL/translations.php
@@ -1345,4 +1345,15 @@ return array(
// 'Enter one subtask by line.' => '',
// 'Predefined Contents' => '',
// 'Predefined contents' => '',
+ // 'Predefined Task Description' => '',
+ // 'Do you really want to remove this template? "%s"' => '',
+ // 'Add predefined task description' => '',
+ // 'Predefined Task Descriptions' => '',
+ // 'Template created successfully.' => '',
+ // 'Unable to create this template.' => '',
+ // 'Template updated successfully.' => '',
+ // 'Unable to update this template.' => '',
+ // 'Template removed successfully.' => '',
+ // 'Unable to remove this template.' => '',
+ // 'Description Templates' => '',
);
diff --git a/app/Locale/pt_BR/translations.php b/app/Locale/pt_BR/translations.php
index b9384a65..47e7b629 100644
--- a/app/Locale/pt_BR/translations.php
+++ b/app/Locale/pt_BR/translations.php
@@ -1345,4 +1345,15 @@ return array(
'Enter one subtask by line.' => 'Escreva uma subtarefa por linha.',
'Predefined Contents' => 'Conteúdos predefinidos',
'Predefined contents' => 'Conteúdos predefinidos',
+ // 'Predefined Task Description' => '',
+ // 'Do you really want to remove this template? "%s"' => '',
+ // 'Add predefined task description' => '',
+ // 'Predefined Task Descriptions' => '',
+ // 'Template created successfully.' => '',
+ // 'Unable to create this template.' => '',
+ // 'Template updated successfully.' => '',
+ // 'Unable to update this template.' => '',
+ // 'Template removed successfully.' => '',
+ // 'Unable to remove this template.' => '',
+ // 'Description Templates' => '',
);
diff --git a/app/Locale/pt_PT/translations.php b/app/Locale/pt_PT/translations.php
index 6fddbfb2..a8abeda3 100644
--- a/app/Locale/pt_PT/translations.php
+++ b/app/Locale/pt_PT/translations.php
@@ -1345,4 +1345,15 @@ return array(
// 'Enter one subtask by line.' => '',
// 'Predefined Contents' => '',
// 'Predefined contents' => '',
+ // 'Predefined Task Description' => '',
+ // 'Do you really want to remove this template? "%s"' => '',
+ // 'Add predefined task description' => '',
+ // 'Predefined Task Descriptions' => '',
+ // 'Template created successfully.' => '',
+ // 'Unable to create this template.' => '',
+ // 'Template updated successfully.' => '',
+ // 'Unable to update this template.' => '',
+ // 'Template removed successfully.' => '',
+ // 'Unable to remove this template.' => '',
+ // 'Description Templates' => '',
);
diff --git a/app/Locale/ru_RU/translations.php b/app/Locale/ru_RU/translations.php
index 6223f94c..940e58f5 100644
--- a/app/Locale/ru_RU/translations.php
+++ b/app/Locale/ru_RU/translations.php
@@ -1345,4 +1345,15 @@ return array(
'Enter one subtask by line.' => 'Записывайте по одной подзадаче на строку.',
// 'Predefined Contents' => '',
// 'Predefined contents' => '',
+ // 'Predefined Task Description' => '',
+ // 'Do you really want to remove this template? "%s"' => '',
+ // 'Add predefined task description' => '',
+ // 'Predefined Task Descriptions' => '',
+ // 'Template created successfully.' => '',
+ // 'Unable to create this template.' => '',
+ // 'Template updated successfully.' => '',
+ // 'Unable to update this template.' => '',
+ // 'Template removed successfully.' => '',
+ // 'Unable to remove this template.' => '',
+ // 'Description Templates' => '',
);
diff --git a/app/Locale/sr_Latn_RS/translations.php b/app/Locale/sr_Latn_RS/translations.php
index 7d88e0af..0628ebd5 100644
--- a/app/Locale/sr_Latn_RS/translations.php
+++ b/app/Locale/sr_Latn_RS/translations.php
@@ -1345,4 +1345,15 @@ return array(
// 'Enter one subtask by line.' => '',
// 'Predefined Contents' => '',
// 'Predefined contents' => '',
+ // 'Predefined Task Description' => '',
+ // 'Do you really want to remove this template? "%s"' => '',
+ // 'Add predefined task description' => '',
+ // 'Predefined Task Descriptions' => '',
+ // 'Template created successfully.' => '',
+ // 'Unable to create this template.' => '',
+ // 'Template updated successfully.' => '',
+ // 'Unable to update this template.' => '',
+ // 'Template removed successfully.' => '',
+ // 'Unable to remove this template.' => '',
+ // 'Description Templates' => '',
);
diff --git a/app/Locale/sv_SE/translations.php b/app/Locale/sv_SE/translations.php
index 427f00a1..f20f0501 100644
--- a/app/Locale/sv_SE/translations.php
+++ b/app/Locale/sv_SE/translations.php
@@ -1345,4 +1345,15 @@ return array(
// 'Enter one subtask by line.' => '',
// 'Predefined Contents' => '',
// 'Predefined contents' => '',
+ // 'Predefined Task Description' => '',
+ // 'Do you really want to remove this template? "%s"' => '',
+ // 'Add predefined task description' => '',
+ // 'Predefined Task Descriptions' => '',
+ // 'Template created successfully.' => '',
+ // 'Unable to create this template.' => '',
+ // 'Template updated successfully.' => '',
+ // 'Unable to update this template.' => '',
+ // 'Template removed successfully.' => '',
+ // 'Unable to remove this template.' => '',
+ // 'Description Templates' => '',
);
diff --git a/app/Locale/th_TH/translations.php b/app/Locale/th_TH/translations.php
index ba4a587e..0d26b352 100644
--- a/app/Locale/th_TH/translations.php
+++ b/app/Locale/th_TH/translations.php
@@ -1345,4 +1345,15 @@ return array(
// 'Enter one subtask by line.' => '',
// 'Predefined Contents' => '',
// 'Predefined contents' => '',
+ // 'Predefined Task Description' => '',
+ // 'Do you really want to remove this template? "%s"' => '',
+ // 'Add predefined task description' => '',
+ // 'Predefined Task Descriptions' => '',
+ // 'Template created successfully.' => '',
+ // 'Unable to create this template.' => '',
+ // 'Template updated successfully.' => '',
+ // 'Unable to update this template.' => '',
+ // 'Template removed successfully.' => '',
+ // 'Unable to remove this template.' => '',
+ // 'Description Templates' => '',
);
diff --git a/app/Locale/tr_TR/translations.php b/app/Locale/tr_TR/translations.php
index e420eff4..a7ffda9a 100644
--- a/app/Locale/tr_TR/translations.php
+++ b/app/Locale/tr_TR/translations.php
@@ -1345,4 +1345,15 @@ return array(
// 'Enter one subtask by line.' => '',
// 'Predefined Contents' => '',
// 'Predefined contents' => '',
+ // 'Predefined Task Description' => '',
+ // 'Do you really want to remove this template? "%s"' => '',
+ // 'Add predefined task description' => '',
+ // 'Predefined Task Descriptions' => '',
+ // 'Template created successfully.' => '',
+ // 'Unable to create this template.' => '',
+ // 'Template updated successfully.' => '',
+ // 'Unable to update this template.' => '',
+ // 'Template removed successfully.' => '',
+ // 'Unable to remove this template.' => '',
+ // 'Description Templates' => '',
);
diff --git a/app/Locale/vi_VN/translations.php b/app/Locale/vi_VN/translations.php
index dde397bb..bf9e6ffd 100644
--- a/app/Locale/vi_VN/translations.php
+++ b/app/Locale/vi_VN/translations.php
@@ -1351,4 +1351,15 @@ return array(
// 'Enter one subtask by line.' => '',
// 'Predefined Contents' => '',
// 'Predefined contents' => '',
+ // 'Predefined Task Description' => '',
+ // 'Do you really want to remove this template? "%s"' => '',
+ // 'Add predefined task description' => '',
+ // 'Predefined Task Descriptions' => '',
+ // 'Template created successfully.' => '',
+ // 'Unable to create this template.' => '',
+ // 'Template updated successfully.' => '',
+ // 'Unable to update this template.' => '',
+ // 'Template removed successfully.' => '',
+ // 'Unable to remove this template.' => '',
+ // 'Description Templates' => '',
);
diff --git a/app/Locale/zh_CN/translations.php b/app/Locale/zh_CN/translations.php
index 9094a7b4..68bbef66 100644
--- a/app/Locale/zh_CN/translations.php
+++ b/app/Locale/zh_CN/translations.php
@@ -1345,4 +1345,15 @@ return array(
// 'Enter one subtask by line.' => '',
// 'Predefined Contents' => '',
// 'Predefined contents' => '',
+ // 'Predefined Task Description' => '',
+ // 'Do you really want to remove this template? "%s"' => '',
+ // 'Add predefined task description' => '',
+ // 'Predefined Task Descriptions' => '',
+ // 'Template created successfully.' => '',
+ // 'Unable to create this template.' => '',
+ // 'Template updated successfully.' => '',
+ // 'Unable to update this template.' => '',
+ // 'Template removed successfully.' => '',
+ // 'Unable to remove this template.' => '',
+ // 'Description Templates' => '',
);
diff --git a/app/Model/PredefinedTaskDescriptionModel.php b/app/Model/PredefinedTaskDescriptionModel.php
new file mode 100644
index 00000000..7b8e6de2
--- /dev/null
+++ b/app/Model/PredefinedTaskDescriptionModel.php
@@ -0,0 +1,42 @@
+<?php
+
+namespace Kanboard\Model;
+
+use Kanboard\Core\Base;
+
+class PredefinedTaskDescriptionModel extends Base
+{
+ const TABLE = 'predefined_task_descriptions';
+
+ public function getAll($projectId)
+ {
+ return $this->db->table(self::TABLE)->eq('project_id', $projectId)->findAll();
+ }
+
+ public function getById($projectId, $id)
+ {
+ return $this->db->table(self::TABLE)->eq('project_id', $projectId)->eq('id', $id)->findOne();
+ }
+
+ public function create($projectId, $title, $description)
+ {
+ return $this->db->table(self::TABLE)->persist(array(
+ 'project_id' => $projectId,
+ 'title' => $title,
+ 'description' => $description,
+ ));
+ }
+
+ public function update($projectId, $id, $title, $description)
+ {
+ return $this->db->table(self::TABLE)->eq('project_id', $projectId)->eq('id', $id)->update(array(
+ 'title' => $title,
+ 'description' => $description,
+ ));
+ }
+
+ public function remove($projectId, $id)
+ {
+ return $this->db->table(self::TABLE)->eq('project_id', $projectId)->eq('id', $id)->remove();
+ }
+}
diff --git a/app/Schema/Mysql.php b/app/Schema/Mysql.php
index ca284f47..5709b86d 100644
--- a/app/Schema/Mysql.php
+++ b/app/Schema/Mysql.php
@@ -8,7 +8,19 @@ use PDO;
use Kanboard\Core\Security\Token;
use Kanboard\Core\Security\Role;
-const VERSION = 125;
+const VERSION = 126;
+
+function version_126(PDO $pdo)
+{
+ $pdo->exec('CREATE TABLE predefined_task_descriptions (
+ id INT NOT NULL AUTO_INCREMENT,
+ project_id INT NOT NULL,
+ title TEXT NOT NULL,
+ description TEXT NOT NULL,
+ FOREIGN KEY(project_id) REFERENCES projects(id) ON DELETE CASCADE,
+ PRIMARY KEY(id)
+ ) ENGINE=InnoDB CHARSET=utf8');
+}
function version_125(PDO $pdo)
{
diff --git a/app/Schema/Postgres.php b/app/Schema/Postgres.php
index 312b1dba..bf9acaa7 100644
--- a/app/Schema/Postgres.php
+++ b/app/Schema/Postgres.php
@@ -8,7 +8,18 @@ use PDO;
use Kanboard\Core\Security\Token;
use Kanboard\Core\Security\Role;
-const VERSION = 104;
+const VERSION = 105;
+
+function version_105(PDO $pdo)
+{
+ $pdo->exec('CREATE TABLE predefined_task_descriptions (
+ id SERIAL PRIMARY KEY,
+ project_id INTEGER NOT NULL,
+ title TEXT NOT NULL,
+ description TEXT NOT NULL,
+ FOREIGN KEY(project_id) REFERENCES projects(id) ON DELETE CASCADE
+ )');
+}
function version_104(PDO $pdo)
{
diff --git a/app/Schema/Sqlite.php b/app/Schema/Sqlite.php
index 3966d373..70d13b98 100644
--- a/app/Schema/Sqlite.php
+++ b/app/Schema/Sqlite.php
@@ -8,7 +8,18 @@ use Kanboard\Core\Security\Token;
use Kanboard\Core\Security\Role;
use PDO;
-const VERSION = 115;
+const VERSION = 116;
+
+function version_116(PDO $pdo)
+{
+ $pdo->exec('CREATE TABLE predefined_task_descriptions (
+ id INTEGER PRIMARY KEY,
+ project_id INTEGER NOT NULL,
+ title TEXT NOT NULL,
+ description TEXT NOT NULL,
+ FOREIGN KEY(project_id) REFERENCES projects(id) ON DELETE CASCADE
+ )');
+}
function version_115(PDO $pdo)
{
diff --git a/app/ServiceProvider/AuthenticationProvider.php b/app/ServiceProvider/AuthenticationProvider.php
index 98212d45..797e70d0 100644
--- a/app/ServiceProvider/AuthenticationProvider.php
+++ b/app/ServiceProvider/AuthenticationProvider.php
@@ -93,6 +93,7 @@ class AuthenticationProvider implements ServiceProviderInterface
$acl->add('ProjectPermissionController', '*', Role::PROJECT_MANAGER);
$acl->add('ProjectEditController', '*', Role::PROJECT_MANAGER);
$acl->add('ProjectPredefinedContentController', '*', Role::PROJECT_MANAGER);
+ $acl->add('PredefinedTaskDescriptionController', '*', Role::PROJECT_MANAGER);
$acl->add('ProjectFileController', '*', Role::PROJECT_MEMBER);
$acl->add('ProjectUserOverviewController', '*', Role::PROJECT_MANAGER);
$acl->add('ProjectStatusController', '*', Role::PROJECT_MANAGER);
diff --git a/app/ServiceProvider/ClassProvider.php b/app/ServiceProvider/ClassProvider.php
index f8bb3ae4..aaafafdf 100644
--- a/app/ServiceProvider/ClassProvider.php
+++ b/app/ServiceProvider/ClassProvider.php
@@ -47,6 +47,7 @@ class ClassProvider implements ServiceProviderInterface
'LinkModel',
'NotificationModel',
'PasswordResetModel',
+ 'PredefinedTaskDescriptionModel',
'ProjectModel',
'ProjectFileModel',
'ProjectActivityModel',
@@ -118,6 +119,7 @@ class ClassProvider implements ServiceProviderInterface
'TaskLinkValidator',
'TaskValidator',
'UserValidator',
+ 'PredefinedTaskDescriptionValidator',
),
'Import' => array(
'TaskImport',
diff --git a/app/Template/predefined_task_description/create.php b/app/Template/predefined_task_description/create.php
new file mode 100644
index 00000000..5a7a8d9f
--- /dev/null
+++ b/app/Template/predefined_task_description/create.php
@@ -0,0 +1,14 @@
+<div class="page-header">
+ <h2><?= t('Predefined Task Description') ?></h2>
+</div>
+<form method="post" action="<?= $this->url->href('PredefinedTaskDescriptionController', 'save', array('project_id' => $project['id'])) ?>" autocomplete="off">
+ <?= $this->form->csrf() ?>
+
+ <?= $this->form->label(t('Title'), 'title') ?>
+ <?= $this->form->text('title', $values, $errors, array('autofocus', 'required', 'tabindex="1"')) ?>
+
+ <?= $this->form->label(t('Description'), 'description') ?>
+ <?= $this->form->textEditor('description', $values, $errors, array('tabindex' => 2)) ?>
+
+ <?= $this->modal->submitButtons() ?>
+</form>
diff --git a/app/Template/predefined_task_description/edit.php b/app/Template/predefined_task_description/edit.php
new file mode 100644
index 00000000..039d650b
--- /dev/null
+++ b/app/Template/predefined_task_description/edit.php
@@ -0,0 +1,14 @@
+<div class="page-header">
+ <h2><?= t('Predefined Task Description') ?></h2>
+</div>
+<form method="post" action="<?= $this->url->href('PredefinedTaskDescriptionController', 'update', array('project_id' => $project['id'], 'id' => $template['id'])) ?>" autocomplete="off">
+ <?= $this->form->csrf() ?>
+
+ <?= $this->form->label(t('Title'), 'title') ?>
+ <?= $this->form->text('title', $values, $errors, array('autofocus', 'required', 'tabindex="1"')) ?>
+
+ <?= $this->form->label(t('Description'), 'description') ?>
+ <?= $this->form->textEditor('description', $values, $errors, array('tabindex' => 2)) ?>
+
+ <?= $this->modal->submitButtons() ?>
+</form>
diff --git a/app/Template/predefined_task_description/remove.php b/app/Template/predefined_task_description/remove.php
new file mode 100644
index 00000000..f60a8e75
--- /dev/null
+++ b/app/Template/predefined_task_description/remove.php
@@ -0,0 +1,15 @@
+<div class="page-header">
+ <h2><?= t('Predefined Task Description') ?></h2>
+</div>
+
+<div class="confirm">
+ <p class="alert alert-info">
+ <?= t('Do you really want to remove this template? "%s"', $template['title']) ?>
+ </p>
+
+ <?= $this->modal->confirmButtons(
+ 'PredefinedTaskDescriptionController',
+ 'remove',
+ array('project_id' => $project['id'], 'id' => $template['id'])
+ ) ?>
+</div>
diff --git a/app/Template/project_predefined_content/show.php b/app/Template/project_predefined_content/show.php
index 8e5ca3dc..b2785ada 100644
--- a/app/Template/project_predefined_content/show.php
+++ b/app/Template/project_predefined_content/show.php
@@ -1,6 +1,39 @@
<div class="page-header">
<h2><?= t('Predefined Contents') ?></h2>
+ <ul>
+ <li>
+ <?= $this->modal->medium('plus', t('Add predefined task description'), 'PredefinedTaskDescriptionController', 'create', array('project_id' => $project['id'])) ?>
+ </li>
+ </ul>
</div>
+
+<?php if (! empty($predefined_task_descriptions)): ?>
+ <h3><?= t('Predefined Task Descriptions') ?></h3>
+ <table>
+ <?php foreach ($predefined_task_descriptions as $template): ?>
+ <tr>
+ <td>
+ <div class="dropdown">
+ <a href="#" class="dropdown-menu dropdown-menu-link-icon"><i class="fa fa-cog"></i><i class="fa fa-caret-down"></i></a>
+ <ul>
+ <li>
+ <?= $this->modal->medium('edit', t('Edit'), 'PredefinedTaskDescriptionController', 'edit', array('project_id' => $project['id'], 'id' => $template['id'])) ?>
+ </li>
+ <li>
+ <?= $this->modal->confirm('trash-o', t('Remove'), 'PredefinedTaskDescriptionController', 'confirm', array('project_id' => $project['id'], 'id' => $template['id'])) ?>
+ </li>
+ </ul>
+ </div>
+ <?= $this->text->e($template['title']) ?>
+ <span class="tooltip" title="<?= $this->text->markdownAttribute($template['description']) ?>">
+ <i class="fa fa-info-circle"></i>
+ </span>
+ </td>
+ </tr>
+ <?php endforeach ?>
+ </table>
+<?php endif ?>
+
<form method="post" action="<?= $this->url->href('ProjectPredefinedContentController', 'update', array('project_id' => $project['id'], 'redirect' => 'edit')) ?>" autocomplete="off">
<?= $this->form->csrf() ?>
diff --git a/app/Template/task_creation/show.php b/app/Template/task_creation/show.php
index e21ea8be..935e0823 100644
--- a/app/Template/task_creation/show.php
+++ b/app/Template/task_creation/show.php
@@ -8,6 +8,7 @@
<div class="task-form-main-column">
<?= $this->task->renderTitleField($values, $errors) ?>
<?= $this->task->renderDescriptionField($values, $errors) ?>
+ <?= $this->task->renderDescriptionTemplateDropdown($project['id']) ?>
<?= $this->task->renderTagField($project) ?>
<?= $this->hook->render('template:task:form:first-column', array('values' => $values, 'errors' => $errors)) ?>
diff --git a/app/Validator/PredefinedTaskDescriptionValidator.php b/app/Validator/PredefinedTaskDescriptionValidator.php
new file mode 100644
index 00000000..3ff4e3cb
--- /dev/null
+++ b/app/Validator/PredefinedTaskDescriptionValidator.php
@@ -0,0 +1,22 @@
+<?php
+
+namespace Kanboard\Validator;
+
+use SimpleValidator\Validator;
+use SimpleValidator\Validators;
+
+class PredefinedTaskDescriptionValidator extends BaseValidator
+{
+ public function validate(array $values)
+ {
+ $v = new Validator($values, array(
+ new Validators\Required('title', t('This value is required')),
+ new Validators\Required('description', t('This value is required')),
+ ));
+
+ return array(
+ $v->execute(),
+ $v->getErrors()
+ );
+ }
+} \ No newline at end of file