summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
Diffstat (limited to 'app')
-rw-r--r--app/Controller/Board.php17
-rw-r--r--app/Controller/Task.php60
-rw-r--r--app/Locale/da_DK/translations.php24
-rw-r--r--app/Locale/de_DE/translations.php24
-rw-r--r--app/Locale/es_ES/translations.php24
-rw-r--r--app/Locale/fi_FI/translations.php24
-rw-r--r--app/Locale/fr_FR/translations.php24
-rw-r--r--app/Locale/hu_HU/translations.php24
-rw-r--r--app/Locale/it_IT/translations.php24
-rw-r--r--app/Locale/ja_JP/translations.php24
-rw-r--r--app/Locale/nl_NL/translations.php24
-rw-r--r--app/Locale/pl_PL/translations.php24
-rw-r--r--app/Locale/pt_BR/translations.php47
-rw-r--r--app/Locale/ru_RU/translations.php24
-rw-r--r--app/Locale/sr_Latn_RS/translations.php24
-rw-r--r--app/Locale/sv_SE/translations.php24
-rw-r--r--app/Locale/th_TH/translations.php24
-rw-r--r--app/Locale/tr_TR/translations.php24
-rw-r--r--app/Locale/zh_CN/translations.php24
-rw-r--r--app/Model/Board.php12
-rw-r--r--app/Model/Task.php93
-rwxr-xr-x[-rw-r--r--]app/Model/TaskDuplication.php87
-rw-r--r--app/Model/TaskFinder.php14
-rw-r--r--app/Model/TaskModification.php2
-rw-r--r--app/Model/TaskPosition.php13
-rw-r--r--app/Model/TaskStatus.php11
-rw-r--r--app/Model/TaskValidator.php29
-rw-r--r--app/Schema/Mysql.php13
-rw-r--r--app/Schema/Postgres.php13
-rw-r--r--app/Schema/Sqlite.php13
-rw-r--r--app/Template/board/recurrence.php18
-rw-r--r--app/Template/board/task_footer.php8
-rw-r--r--app/Template/board/task_menu.php3
-rw-r--r--app/Template/task/details.php39
-rw-r--r--app/Template/task/edit_recurrence.php85
-rw-r--r--app/Template/task/show.php2
-rw-r--r--app/Template/task/sidebar.php5
37 files changed, 960 insertions, 8 deletions
diff --git a/app/Controller/Board.php b/app/Controller/Board.php
index f539a77c..e92cfe37 100644
--- a/app/Controller/Board.php
+++ b/app/Controller/Board.php
@@ -350,4 +350,21 @@ class Board extends Base
'redirect' => 'board',
)));
}
+
+ /**
+ * Get recurrence information on mouseover
+ *
+ * @access public
+ */
+ public function recurrence()
+ {
+ $task = $this->getTask();
+
+ $this->response->html($this->template->render('board/recurrence', array(
+ 'task' => $task,
+ 'recurrence_trigger_list' => $this->task->getRecurrenceTriggerList(),
+ 'recurrence_timeframe_list' => $this->task->getRecurrenceTimeframeList(),
+ 'recurrence_basedate_list' => $this->task->getRecurrenceBasedateList(),
+ )));
+ }
}
diff --git a/app/Controller/Task.php b/app/Controller/Task.php
index 866ef774..060a478c 100644
--- a/app/Controller/Task.php
+++ b/app/Controller/Task.php
@@ -81,6 +81,9 @@ class Task extends Base
'date_format' => $this->config->get('application_date_format'),
'date_formats' => $this->dateParser->getAvailableFormats(),
'title' => $task['project_name'].' > '.$task['title'],
+ 'recurrence_trigger_list' => $this->task->getRecurrenceTriggerList(),
+ 'recurrence_timeframe_list' => $this->task->getRecurrenceTimeframeList(),
+ 'recurrence_basedate_list' => $this->task->getRecurrenceBasedateList(),
)));
}
@@ -444,6 +447,63 @@ class Task extends Base
}
/**
+ * Edit recurrence form
+ *
+ * @access public
+ */
+ public function recurrence()
+ {
+ $task = $this->getTask();
+ $ajax = $this->request->isAjax() || $this->request->getIntegerParam('ajax');
+
+ if ($this->request->isPost()) {
+
+ $values = $this->request->getValues();
+
+ list($valid, $errors) = $this->taskValidator->validateEditRecurrence($values);
+
+ if ($valid) {
+
+ if ($this->taskModification->update($values)) {
+ $this->session->flash(t('Task updated successfully.'));
+ }
+ else {
+ $this->session->flashError(t('Unable to update your task.'));
+ }
+
+ if ($ajax) {
+ $this->response->redirect('?controller=board&action=show&project_id='.$task['project_id']);
+ }
+ else {
+ $this->response->redirect('?controller=task&action=show&task_id='.$task['id'].'&project_id='.$task['project_id']);
+ }
+ }
+ }
+ else {
+ $values = $task;
+ $errors = array();
+ }
+
+ $params = array(
+ 'values' => $values,
+ 'errors' => $errors,
+ 'task' => $task,
+ 'ajax' => $ajax,
+ 'recurrence_status_list' => $this->task->getRecurrenceStatusList(),
+ 'recurrence_trigger_list' => $this->task->getRecurrenceTriggerList(),
+ 'recurrence_timeframe_list' => $this->task->getRecurrenceTimeframeList(),
+ 'recurrence_basedate_list' => $this->task->getRecurrenceBasedateList(),
+ );
+
+ if ($ajax) {
+ $this->response->html($this->template->render('task/edit_recurrence', $params));
+ }
+ else {
+ $this->response->html($this->taskLayout('task/edit_recurrence', $params));
+ }
+ }
+
+ /**
* Move a task to another project
*
* @access public
diff --git a/app/Locale/da_DK/translations.php b/app/Locale/da_DK/translations.php
index 663c2603..3d166f5d 100644
--- a/app/Locale/da_DK/translations.php
+++ b/app/Locale/da_DK/translations.php
@@ -872,4 +872,28 @@ return array(
// 'Start to type task title...' => '',
// 'A task cannot be linked to itself' => '',
// 'The exact same link already exists' => '',
+ // 'Action date' => '',
+ // 'Base date to calculate new due date' => '',
+ // 'Base date to calculate new due date: %s' => '',
+ // 'Created recurrent task: %s' => '',
+ // 'Day(s)' => '',
+ // 'Edit recurrence' => '',
+ // 'Existing due date' => '',
+ // 'Factor to calculate new due date' => '',
+ // 'Factor to calculate new due date: %s' => '',
+ // 'Generate recurrent task' => '',
+ // 'Month(s)' => '',
+ // 'No recurrent task is scheduled to generate' => '',
+ // 'Recurrence' => '',
+ // 'Recurrent task created by: %s' => '',
+ // 'Recurrent task has been generated' => '',
+ // 'Recurrent task is scheduled to generate' => '',
+ // 'Timeframe to calculate new due date' => '',
+ // 'Timeframe to calculate new due date: %s' => '',
+ // 'Trigger to generate recurrent task' => '',
+ // 'Trigger to generate recurrent task: %s' => '',
+ // 'When task is closed' => '',
+ // 'When task is moved from first column' => '',
+ // 'When task is moved to last column' => '',
+ // 'Year(s)' => '',
);
diff --git a/app/Locale/de_DE/translations.php b/app/Locale/de_DE/translations.php
index 6efe6167..0aab9fde 100644
--- a/app/Locale/de_DE/translations.php
+++ b/app/Locale/de_DE/translations.php
@@ -872,4 +872,28 @@ return array(
// 'Start to type task title...' => '',
// 'A task cannot be linked to itself' => '',
// 'The exact same link already exists' => '',
+ // 'Action date' => '',
+ // 'Base date to calculate new due date' => '',
+ // 'Base date to calculate new due date: %s' => '',
+ // 'Created recurrent task: %s' => '',
+ // 'Day(s)' => '',
+ // 'Edit recurrence' => '',
+ // 'Existing due date' => '',
+ // 'Factor to calculate new due date' => '',
+ // 'Factor to calculate new due date: %s' => '',
+ // 'Generate recurrent task' => '',
+ // 'Month(s)' => '',
+ // 'No recurrent task is scheduled to generate' => '',
+ // 'Recurrence' => '',
+ // 'Recurrent task created by: %s' => '',
+ // 'Recurrent task has been generated' => '',
+ // 'Recurrent task is scheduled to generate' => '',
+ // 'Timeframe to calculate new due date' => '',
+ // 'Timeframe to calculate new due date: %s' => '',
+ // 'Trigger to generate recurrent task' => '',
+ // 'Trigger to generate recurrent task: %s' => '',
+ // 'When task is closed' => '',
+ // 'When task is moved from first column' => '',
+ // 'When task is moved to last column' => '',
+ // 'Year(s)' => '',
);
diff --git a/app/Locale/es_ES/translations.php b/app/Locale/es_ES/translations.php
index 449fcd94..d89f7b1d 100644
--- a/app/Locale/es_ES/translations.php
+++ b/app/Locale/es_ES/translations.php
@@ -872,4 +872,28 @@ return array(
// 'Start to type task title...' => '',
// 'A task cannot be linked to itself' => '',
// 'The exact same link already exists' => '',
+ // 'Action date' => '',
+ // 'Base date to calculate new due date' => '',
+ // 'Base date to calculate new due date: %s' => '',
+ // 'Created recurrent task: %s' => '',
+ // 'Day(s)' => '',
+ // 'Edit recurrence' => '',
+ // 'Existing due date' => '',
+ // 'Factor to calculate new due date' => '',
+ // 'Factor to calculate new due date: %s' => '',
+ // 'Generate recurrent task' => '',
+ // 'Month(s)' => '',
+ // 'No recurrent task is scheduled to generate' => '',
+ // 'Recurrence' => '',
+ // 'Recurrent task created by: %s' => '',
+ // 'Recurrent task has been generated' => '',
+ // 'Recurrent task is scheduled to generate' => '',
+ // 'Timeframe to calculate new due date' => '',
+ // 'Timeframe to calculate new due date: %s' => '',
+ // 'Trigger to generate recurrent task' => '',
+ // 'Trigger to generate recurrent task: %s' => '',
+ // 'When task is closed' => '',
+ // 'When task is moved from first column' => '',
+ // 'When task is moved to last column' => '',
+ // 'Year(s)' => '',
);
diff --git a/app/Locale/fi_FI/translations.php b/app/Locale/fi_FI/translations.php
index 15c919ed..ba01e7be 100644
--- a/app/Locale/fi_FI/translations.php
+++ b/app/Locale/fi_FI/translations.php
@@ -872,4 +872,28 @@ return array(
// 'Start to type task title...' => '',
// 'A task cannot be linked to itself' => '',
// 'The exact same link already exists' => '',
+ // 'Action date' => '',
+ // 'Base date to calculate new due date' => '',
+ // 'Base date to calculate new due date: %s' => '',
+ // 'Created recurrent task: %s' => '',
+ // 'Day(s)' => '',
+ // 'Edit recurrence' => '',
+ // 'Existing due date' => '',
+ // 'Factor to calculate new due date' => '',
+ // 'Factor to calculate new due date: %s' => '',
+ // 'Generate recurrent task' => '',
+ // 'Month(s)' => '',
+ // 'No recurrent task is scheduled to generate' => '',
+ // 'Recurrence' => '',
+ // 'Recurrent task created by: %s' => '',
+ // 'Recurrent task has been generated' => '',
+ // 'Recurrent task is scheduled to generate' => '',
+ // 'Timeframe to calculate new due date' => '',
+ // 'Timeframe to calculate new due date: %s' => '',
+ // 'Trigger to generate recurrent task' => '',
+ // 'Trigger to generate recurrent task: %s' => '',
+ // 'When task is closed' => '',
+ // 'When task is moved from first column' => '',
+ // 'When task is moved to last column' => '',
+ // 'Year(s)' => '',
);
diff --git a/app/Locale/fr_FR/translations.php b/app/Locale/fr_FR/translations.php
index 84a28207..934762d0 100644
--- a/app/Locale/fr_FR/translations.php
+++ b/app/Locale/fr_FR/translations.php
@@ -874,4 +874,28 @@ return array(
'Start to type task title...' => 'Tappez le titre de la tâche...',
'A task cannot be linked to itself' => 'Une tâche ne peut être liée à elle-même',
'The exact same link already exists' => 'Un lien identique existe déjà',
+ // 'Action date' => '',
+ // 'Base date to calculate new due date' => '',
+ // 'Base date to calculate new due date: %s' => '',
+ // 'Created recurrent task: %s' => '',
+ // 'Day(s)' => '',
+ // 'Edit recurrence' => '',
+ // 'Existing due date' => '',
+ // 'Factor to calculate new due date' => '',
+ // 'Factor to calculate new due date: %s' => '',
+ // 'Generate recurrent task' => '',
+ // 'Month(s)' => '',
+ // 'No recurrent task is scheduled to generate' => '',
+ // 'Recurrence' => '',
+ // 'Recurrent task created by: %s' => '',
+ // 'Recurrent task has been generated' => '',
+ // 'Recurrent task is scheduled to generate' => '',
+ // 'Timeframe to calculate new due date' => '',
+ // 'Timeframe to calculate new due date: %s' => '',
+ // 'Trigger to generate recurrent task' => '',
+ // 'Trigger to generate recurrent task: %s' => '',
+ // 'When task is closed' => '',
+ // 'When task is moved from first column' => '',
+ // 'When task is moved to last column' => '',
+ // 'Year(s)' => '',
);
diff --git a/app/Locale/hu_HU/translations.php b/app/Locale/hu_HU/translations.php
index 26b1e132..3614f4cd 100644
--- a/app/Locale/hu_HU/translations.php
+++ b/app/Locale/hu_HU/translations.php
@@ -872,4 +872,28 @@ return array(
// 'Start to type task title...' => '',
// 'A task cannot be linked to itself' => '',
// 'The exact same link already exists' => '',
+ // 'Action date' => '',
+ // 'Base date to calculate new due date' => '',
+ // 'Base date to calculate new due date: %s' => '',
+ // 'Created recurrent task: %s' => '',
+ // 'Day(s)' => '',
+ // 'Edit recurrence' => '',
+ // 'Existing due date' => '',
+ // 'Factor to calculate new due date' => '',
+ // 'Factor to calculate new due date: %s' => '',
+ // 'Generate recurrent task' => '',
+ // 'Month(s)' => '',
+ // 'No recurrent task is scheduled to generate' => '',
+ // 'Recurrence' => '',
+ // 'Recurrent task created by: %s' => '',
+ // 'Recurrent task has been generated' => '',
+ // 'Recurrent task is scheduled to generate' => '',
+ // 'Timeframe to calculate new due date' => '',
+ // 'Timeframe to calculate new due date: %s' => '',
+ // 'Trigger to generate recurrent task' => '',
+ // 'Trigger to generate recurrent task: %s' => '',
+ // 'When task is closed' => '',
+ // 'When task is moved from first column' => '',
+ // 'When task is moved to last column' => '',
+ // 'Year(s)' => '',
);
diff --git a/app/Locale/it_IT/translations.php b/app/Locale/it_IT/translations.php
index 8736572e..11f4f47d 100644
--- a/app/Locale/it_IT/translations.php
+++ b/app/Locale/it_IT/translations.php
@@ -872,4 +872,28 @@ return array(
// 'Start to type task title...' => '',
// 'A task cannot be linked to itself' => '',
// 'The exact same link already exists' => '',
+ // 'Action date' => '',
+ // 'Base date to calculate new due date' => '',
+ // 'Base date to calculate new due date: %s' => '',
+ // 'Created recurrent task: %s' => '',
+ // 'Day(s)' => '',
+ // 'Edit recurrence' => '',
+ // 'Existing due date' => '',
+ // 'Factor to calculate new due date' => '',
+ // 'Factor to calculate new due date: %s' => '',
+ // 'Generate recurrent task' => '',
+ // 'Month(s)' => '',
+ // 'No recurrent task is scheduled to generate' => '',
+ // 'Recurrence' => '',
+ // 'Recurrent task created by: %s' => '',
+ // 'Recurrent task has been generated' => '',
+ // 'Recurrent task is scheduled to generate' => '',
+ // 'Timeframe to calculate new due date' => '',
+ // 'Timeframe to calculate new due date: %s' => '',
+ // 'Trigger to generate recurrent task' => '',
+ // 'Trigger to generate recurrent task: %s' => '',
+ // 'When task is closed' => '',
+ // 'When task is moved from first column' => '',
+ // 'When task is moved to last column' => '',
+ // 'Year(s)' => '',
);
diff --git a/app/Locale/ja_JP/translations.php b/app/Locale/ja_JP/translations.php
index fa047f69..3d54b0c2 100644
--- a/app/Locale/ja_JP/translations.php
+++ b/app/Locale/ja_JP/translations.php
@@ -872,4 +872,28 @@ return array(
// 'Start to type task title...' => '',
// 'A task cannot be linked to itself' => '',
// 'The exact same link already exists' => '',
+ // 'Action date' => '',
+ // 'Base date to calculate new due date' => '',
+ // 'Base date to calculate new due date: %s' => '',
+ // 'Created recurrent task: %s' => '',
+ // 'Day(s)' => '',
+ // 'Edit recurrence' => '',
+ // 'Existing due date' => '',
+ // 'Factor to calculate new due date' => '',
+ // 'Factor to calculate new due date: %s' => '',
+ // 'Generate recurrent task' => '',
+ // 'Month(s)' => '',
+ // 'No recurrent task is scheduled to generate' => '',
+ // 'Recurrence' => '',
+ // 'Recurrent task created by: %s' => '',
+ // 'Recurrent task has been generated' => '',
+ // 'Recurrent task is scheduled to generate' => '',
+ // 'Timeframe to calculate new due date' => '',
+ // 'Timeframe to calculate new due date: %s' => '',
+ // 'Trigger to generate recurrent task' => '',
+ // 'Trigger to generate recurrent task: %s' => '',
+ // 'When task is closed' => '',
+ // 'When task is moved from first column' => '',
+ // 'When task is moved to last column' => '',
+ // 'Year(s)' => '',
);
diff --git a/app/Locale/nl_NL/translations.php b/app/Locale/nl_NL/translations.php
index eecdaa9f..2fb1637b 100644
--- a/app/Locale/nl_NL/translations.php
+++ b/app/Locale/nl_NL/translations.php
@@ -872,4 +872,28 @@ return array(
// 'Start to type task title...' => '',
// 'A task cannot be linked to itself' => '',
// 'The exact same link already exists' => '',
+ // 'Action date' => '',
+ // 'Base date to calculate new due date' => '',
+ // 'Base date to calculate new due date: %s' => '',
+ // 'Created recurrent task: %s' => '',
+ // 'Day(s)' => '',
+ // 'Edit recurrence' => '',
+ // 'Existing due date' => '',
+ // 'Factor to calculate new due date' => '',
+ // 'Factor to calculate new due date: %s' => '',
+ // 'Generate recurrent task' => '',
+ // 'Month(s)' => '',
+ // 'No recurrent task is scheduled to generate' => '',
+ // 'Recurrence' => '',
+ // 'Recurrent task created by: %s' => '',
+ // 'Recurrent task has been generated' => '',
+ // 'Recurrent task is scheduled to generate' => '',
+ // 'Timeframe to calculate new due date' => '',
+ // 'Timeframe to calculate new due date: %s' => '',
+ // 'Trigger to generate recurrent task' => '',
+ // 'Trigger to generate recurrent task: %s' => '',
+ // 'When task is closed' => '',
+ // 'When task is moved from first column' => '',
+ // 'When task is moved to last column' => '',
+ // 'Year(s)' => '',
);
diff --git a/app/Locale/pl_PL/translations.php b/app/Locale/pl_PL/translations.php
index a3871723..5065ddbf 100644
--- a/app/Locale/pl_PL/translations.php
+++ b/app/Locale/pl_PL/translations.php
@@ -872,4 +872,28 @@ return array(
// 'Start to type task title...' => '',
// 'A task cannot be linked to itself' => '',
// 'The exact same link already exists' => '',
+ // 'Action date' => '',
+ // 'Base date to calculate new due date' => '',
+ // 'Base date to calculate new due date: %s' => '',
+ // 'Created recurrent task: %s' => '',
+ // 'Day(s)' => '',
+ // 'Edit recurrence' => '',
+ // 'Existing due date' => '',
+ // 'Factor to calculate new due date' => '',
+ // 'Factor to calculate new due date: %s' => '',
+ // 'Generate recurrent task' => '',
+ // 'Month(s)' => '',
+ // 'No recurrent task is scheduled to generate' => '',
+ // 'Recurrence' => '',
+ // 'Recurrent task created by: %s' => '',
+ // 'Recurrent task has been generated' => '',
+ // 'Recurrent task is scheduled to generate' => '',
+ // 'Timeframe to calculate new due date' => '',
+ // 'Timeframe to calculate new due date: %s' => '',
+ // 'Trigger to generate recurrent task' => '',
+ // 'Trigger to generate recurrent task: %s' => '',
+ // 'When task is closed' => '',
+ // 'When task is moved from first column' => '',
+ // 'When task is moved to last column' => '',
+ // 'Year(s)' => '',
);
diff --git a/app/Locale/pt_BR/translations.php b/app/Locale/pt_BR/translations.php
index 3e1ddd13..576e1a8f 100644
--- a/app/Locale/pt_BR/translations.php
+++ b/app/Locale/pt_BR/translations.php
@@ -846,6 +846,7 @@ return array(
'Secret key: ' => 'Chave secreta:',
'Test your device' => 'Teste o seu dispositivo',
'Assign a color when the task is moved to a specific column' => 'Atribuir uma cor quando a tarefa é movida em uma coluna específica',
+<<<<<<< HEAD
'%s via Kanboard' => '%s via Kanboard',
'uploaded by: %s' => 'carregado por: %s',
'uploaded on: %s' => 'carregado em: %s',
@@ -872,4 +873,50 @@ return array(
// 'Start to type task title...' => '',
// 'A task cannot be linked to itself' => '',
// 'The exact same link already exists' => '',
+ // '%s via Kanboard' => '',
+ // 'uploaded by: %s' => '',
+ // 'uploaded on: %s' => '',
+ // 'size: %s' => '',
+ // 'Burndown chart for "%s"' => '',
+ // 'Burndown chart' => '',
+ // 'This chart show the task complexity over the time (Work Remaining).' => '',
+ // 'Screenshot taken %s' => '',
+ // 'Add a screenshot' => '',
+ // 'Take a screenshot and press CTRL+V or ⌘+V to paste here.' => '',
+ // 'Screenshot uploaded successfully.' => '',
+ // 'SEK - Swedish Krona' => '',
+ // 'The project identifier is an optional alphanumeric code used to identify your project.' => '',
+ // 'Identifier' => '',
+ // 'Postmark (incoming emails)' => '',
+ // 'Help on Postmark integration' => '',
+ // 'Mailgun (incoming emails)' => '',
+ // 'Help on Mailgun integration' => '',
+ // 'Sendgrid (incoming emails)' => '',
+ // 'Help on Sendgrid integration' => '',
+ // 'Disable two factor authentication' => '',
+ // 'Do you really want to disable the two factor authentication for this user: "%s"?' => '',
+ // 'Action date' => '',
+ // 'Base date to calculate new due date' => '',
+ // 'Base date to calculate new due date: %s' => '',
+ // 'Created recurrent task: %s' => '',
+ // 'Day(s)' => '',
+ // 'Edit recurrence' => '',
+ // 'Existing due date' => '',
+ // 'Factor to calculate new due date' => '',
+ // 'Factor to calculate new due date: %s' => '',
+ // 'Generate recurrent task' => '',
+ // 'Month(s)' => '',
+ // 'No recurrent task is scheduled to generate' => '',
+ // 'Recurrence' => '',
+ // 'Recurrent task created by: %s' => '',
+ // 'Recurrent task has been generated' => '',
+ // 'Recurrent task is scheduled to generate' => '',
+ // 'Timeframe to calculate new due date' => '',
+ // 'Timeframe to calculate new due date: %s' => '',
+ // 'Trigger to generate recurrent task' => '',
+ // 'Trigger to generate recurrent task: %s' => '',
+ // 'When task is closed' => '',
+ // 'When task is moved from first column' => '',
+ // 'When task is moved to last column' => '',
+ // 'Year(s)' => '',
);
diff --git a/app/Locale/ru_RU/translations.php b/app/Locale/ru_RU/translations.php
index 4787d2c3..14019773 100644
--- a/app/Locale/ru_RU/translations.php
+++ b/app/Locale/ru_RU/translations.php
@@ -872,4 +872,28 @@ return array(
// 'Start to type task title...' => '',
// 'A task cannot be linked to itself' => '',
// 'The exact same link already exists' => '',
+ // 'Action date' => '',
+ // 'Base date to calculate new due date' => '',
+ // 'Base date to calculate new due date: %s' => '',
+ // 'Created recurrent task: %s' => '',
+ // 'Day(s)' => '',
+ // 'Edit recurrence' => '',
+ // 'Existing due date' => '',
+ // 'Factor to calculate new due date' => '',
+ // 'Factor to calculate new due date: %s' => '',
+ // 'Generate recurrent task' => '',
+ // 'Month(s)' => '',
+ // 'No recurrent task is scheduled to generate' => '',
+ // 'Recurrence' => '',
+ // 'Recurrent task created by: %s' => '',
+ // 'Recurrent task has been generated' => '',
+ // 'Recurrent task is scheduled to generate' => '',
+ // 'Timeframe to calculate new due date' => '',
+ // 'Timeframe to calculate new due date: %s' => '',
+ // 'Trigger to generate recurrent task' => '',
+ // 'Trigger to generate recurrent task: %s' => '',
+ // 'When task is closed' => '',
+ // 'When task is moved from first column' => '',
+ // 'When task is moved to last column' => '',
+ // 'Year(s)' => '',
);
diff --git a/app/Locale/sr_Latn_RS/translations.php b/app/Locale/sr_Latn_RS/translations.php
index b74be22f..521721b8 100644
--- a/app/Locale/sr_Latn_RS/translations.php
+++ b/app/Locale/sr_Latn_RS/translations.php
@@ -872,4 +872,28 @@ return array(
// 'Start to type task title...' => '',
// 'A task cannot be linked to itself' => '',
// 'The exact same link already exists' => '',
+ // 'Action date' => '',
+ // 'Base date to calculate new due date' => '',
+ // 'Base date to calculate new due date: %s' => '',
+ // 'Created recurrent task: %s' => '',
+ // 'Day(s)' => '',
+ // 'Edit recurrence' => '',
+ // 'Existing due date' => '',
+ // 'Factor to calculate new due date' => '',
+ // 'Factor to calculate new due date: %s' => '',
+ // 'Generate recurrent task' => '',
+ // 'Month(s)' => '',
+ // 'No recurrent task is scheduled to generate' => '',
+ // 'Recurrence' => '',
+ // 'Recurrent task created by: %s' => '',
+ // 'Recurrent task has been generated' => '',
+ // 'Recurrent task is scheduled to generate' => '',
+ // 'Timeframe to calculate new due date' => '',
+ // 'Timeframe to calculate new due date: %s' => '',
+ // 'Trigger to generate recurrent task' => '',
+ // 'Trigger to generate recurrent task: %s' => '',
+ // 'When task is closed' => '',
+ // 'When task is moved from first column' => '',
+ // 'When task is moved to last column' => '',
+ // 'Year(s)' => '',
);
diff --git a/app/Locale/sv_SE/translations.php b/app/Locale/sv_SE/translations.php
index f5636925..3303cede 100644
--- a/app/Locale/sv_SE/translations.php
+++ b/app/Locale/sv_SE/translations.php
@@ -872,4 +872,28 @@ return array(
// 'Start to type task title...' => '',
// 'A task cannot be linked to itself' => '',
// 'The exact same link already exists' => '',
+ // 'Action date' => '',
+ // 'Base date to calculate new due date' => '',
+ // 'Base date to calculate new due date: %s' => '',
+ // 'Created recurrent task: %s' => '',
+ // 'Day(s)' => '',
+ // 'Edit recurrence' => '',
+ // 'Existing due date' => '',
+ // 'Factor to calculate new due date' => '',
+ // 'Factor to calculate new due date: %s' => '',
+ // 'Generate recurrent task' => '',
+ // 'Month(s)' => '',
+ // 'No recurrent task is scheduled to generate' => '',
+ // 'Recurrence' => '',
+ // 'Recurrent task created by: %s' => '',
+ // 'Recurrent task has been generated' => '',
+ // 'Recurrent task is scheduled to generate' => '',
+ // 'Timeframe to calculate new due date' => '',
+ // 'Timeframe to calculate new due date: %s' => '',
+ // 'Trigger to generate recurrent task' => '',
+ // 'Trigger to generate recurrent task: %s' => '',
+ // 'When task is closed' => '',
+ // 'When task is moved from first column' => '',
+ // 'When task is moved to last column' => '',
+ // 'Year(s)' => '',
);
diff --git a/app/Locale/th_TH/translations.php b/app/Locale/th_TH/translations.php
index 1e1d81d9..045b1f66 100644
--- a/app/Locale/th_TH/translations.php
+++ b/app/Locale/th_TH/translations.php
@@ -872,4 +872,28 @@ return array(
// 'Start to type task title...' => '',
// 'A task cannot be linked to itself' => '',
// 'The exact same link already exists' => '',
+ // 'Action date' => '',
+ // 'Base date to calculate new due date' => '',
+ // 'Base date to calculate new due date: %s' => '',
+ // 'Created recurrent task: %s' => '',
+ // 'Day(s)' => '',
+ // 'Edit recurrence' => '',
+ // 'Existing due date' => '',
+ // 'Factor to calculate new due date' => '',
+ // 'Factor to calculate new due date: %s' => '',
+ // 'Generate recurrent task' => '',
+ // 'Month(s)' => '',
+ // 'No recurrent task is scheduled to generate' => '',
+ // 'Recurrence' => '',
+ // 'Recurrent task created by: %s' => '',
+ // 'Recurrent task has been generated' => '',
+ // 'Recurrent task is scheduled to generate' => '',
+ // 'Timeframe to calculate new due date' => '',
+ // 'Timeframe to calculate new due date: %s' => '',
+ // 'Trigger to generate recurrent task' => '',
+ // 'Trigger to generate recurrent task: %s' => '',
+ // 'When task is closed' => '',
+ // 'When task is moved from first column' => '',
+ // 'When task is moved to last column' => '',
+ // 'Year(s)' => '',
);
diff --git a/app/Locale/tr_TR/translations.php b/app/Locale/tr_TR/translations.php
index 5bd66e4a..96e3e034 100644
--- a/app/Locale/tr_TR/translations.php
+++ b/app/Locale/tr_TR/translations.php
@@ -872,4 +872,28 @@ return array(
// 'Start to type task title...' => '',
// 'A task cannot be linked to itself' => '',
// 'The exact same link already exists' => '',
+ // 'Action date' => '',
+ // 'Base date to calculate new due date' => '',
+ // 'Base date to calculate new due date: %s' => '',
+ // 'Created recurrent task: %s' => '',
+ // 'Day(s)' => '',
+ // 'Edit recurrence' => '',
+ // 'Existing due date' => '',
+ // 'Factor to calculate new due date' => '',
+ // 'Factor to calculate new due date: %s' => '',
+ // 'Generate recurrent task' => '',
+ // 'Month(s)' => '',
+ // 'No recurrent task is scheduled to generate' => '',
+ // 'Recurrence' => '',
+ // 'Recurrent task created by: %s' => '',
+ // 'Recurrent task has been generated' => '',
+ // 'Recurrent task is scheduled to generate' => '',
+ // 'Timeframe to calculate new due date' => '',
+ // 'Timeframe to calculate new due date: %s' => '',
+ // 'Trigger to generate recurrent task' => '',
+ // 'Trigger to generate recurrent task: %s' => '',
+ // 'When task is closed' => '',
+ // 'When task is moved from first column' => '',
+ // 'When task is moved to last column' => '',
+ // 'Year(s)' => '',
);
diff --git a/app/Locale/zh_CN/translations.php b/app/Locale/zh_CN/translations.php
index 8a7c5e42..5daa713a 100644
--- a/app/Locale/zh_CN/translations.php
+++ b/app/Locale/zh_CN/translations.php
@@ -872,4 +872,28 @@ return array(
// 'Start to type task title...' => '',
// 'A task cannot be linked to itself' => '',
// 'The exact same link already exists' => '',
+ // 'Action date' => '',
+ // 'Base date to calculate new due date' => '',
+ // 'Base date to calculate new due date: %s' => '',
+ // 'Created recurrent task: %s' => '',
+ // 'Day(s)' => '',
+ // 'Edit recurrence' => '',
+ // 'Existing due date' => '',
+ // 'Factor to calculate new due date' => '',
+ // 'Factor to calculate new due date: %s' => '',
+ // 'Generate recurrent task' => '',
+ // 'Month(s)' => '',
+ // 'No recurrent task is scheduled to generate' => '',
+ // 'Recurrence' => '',
+ // 'Recurrent task created by: %s' => '',
+ // 'Recurrent task has been generated' => '',
+ // 'Recurrent task is scheduled to generate' => '',
+ // 'Timeframe to calculate new due date' => '',
+ // 'Timeframe to calculate new due date: %s' => '',
+ // 'Trigger to generate recurrent task' => '',
+ // 'Trigger to generate recurrent task: %s' => '',
+ // 'When task is closed' => '',
+ // 'When task is moved from first column' => '',
+ // 'When task is moved to last column' => '',
+ // 'Year(s)' => '',
);
diff --git a/app/Model/Board.php b/app/Model/Board.php
index 3650418f..eecbc91c 100644
--- a/app/Model/Board.php
+++ b/app/Model/Board.php
@@ -315,6 +315,18 @@ class Board extends Base
}
/**
+ * Get the last column id for a given project
+ *
+ * @access public
+ * @param integer $project_id Project id
+ * @return integer
+ */
+ public function getLastColumn($project_id)
+ {
+ return $this->db->table(self::TABLE)->eq('project_id', $project_id)->desc('position')->findOneColumn('id');
+ }
+
+ /**
* Get the list of columns sorted by position [ column_id => title ]
*
* @access public
diff --git a/app/Model/Task.php b/app/Model/Task.php
index bc2913ec..02469047 100644
--- a/app/Model/Task.php
+++ b/app/Model/Task.php
@@ -42,6 +42,41 @@ class Task extends Base
const EVENT_ASSIGNEE_CHANGE = 'task.assignee_change';
/**
+ * Recurrence: status
+ *
+ * @var integer
+ */
+ const RECURE_STATUS_NONE = 0;
+ const RECURE_STATUS_PENDING = 1;
+ const RECURE_STATUS_PROCESSED = 2;
+
+ /**
+ * Recurrence: trigger
+ *
+ * @var integer
+ */
+ const RECURE_TRIGGER_FIRST = 0;
+ const RECURE_TRIGGER_LAST = 1;
+ const RECURE_TRIGGER_CLOSE = 2;
+
+ /**
+ * Recurrence: timeframe
+ *
+ * @var integer
+ */
+ const RECURE_DAYS = 0;
+ const RECURE_MONTHS = 1;
+ const RECURE_YEARS = 2;
+
+ /**
+ * Recurrence: base date used to calculate new due date
+ *
+ * @var integer
+ */
+ const RECURE_BASEDATE_DUEDATE = 0;
+ const RECURE_BASEDATE_TRIGGERDATE = 1;
+
+ /**
* Remove a task
*
* @access public
@@ -76,4 +111,62 @@ class Task extends Base
return 0;
}
+
+ /**
+ * Return the list user selectable recurrence status
+ *
+ * @access public
+ * @return array
+ */
+ public function getRecurrenceStatusList()
+ {
+ return array (
+ Task::RECURE_STATUS_NONE => t('No'),
+ Task::RECURE_STATUS_PENDING => t('Yes'),
+ );
+ }
+
+ /**
+ * Return the list recurrence triggers
+ *
+ * @access public
+ * @return array
+ */
+ public function getRecurrenceTriggerList()
+ {
+ return array (
+ Task::RECURE_TRIGGER_FIRST => t('When task is moved from first column'),
+ Task::RECURE_TRIGGER_LAST => t('When task is moved to last column'),
+ Task::RECURE_TRIGGER_CLOSE => t('When task is closed'),
+ );
+ }
+
+ /**
+ * Return the list options to calculate recurrence due date
+ *
+ * @access public
+ * @return array
+ */
+ public function getRecurrenceBasedateList()
+ {
+ return array (
+ Task::RECURE_BASEDATE_DUEDATE => t('Existing due date'),
+ Task::RECURE_BASEDATE_TRIGGERDATE => t('Action date'),
+ );
+ }
+
+ /**
+ * Return the list recurrence timeframes
+ *
+ * @access public
+ * @return array
+ */
+ public function getRecurrenceTimeframeList()
+ {
+ return array (
+ Task::RECURE_DAYS => t('Day(s)'),
+ Task::RECURE_MONTHS => t('Month(s)'),
+ Task::RECURE_YEARS => t('Year(s)'),
+ );
+ }
}
diff --git a/app/Model/TaskDuplication.php b/app/Model/TaskDuplication.php
index bd593dc1..f3ce4f7b 100644..100755
--- a/app/Model/TaskDuplication.php
+++ b/app/Model/TaskDuplication.php
@@ -30,6 +30,11 @@ class TaskDuplication extends Base
'category_id',
'time_estimated',
'swimlane_id',
+ 'recurrence_status',
+ 'recurrence_trigger',
+ 'recurrence_factor',
+ 'recurrence_timeframe',
+ 'recurrence_basedate',
);
/**
@@ -45,6 +50,43 @@ class TaskDuplication extends Base
}
/**
+ * Create task recurrence to the same project
+ *
+ * @access public
+ * @param integer $task_id Task id
+ * @return boolean|integer Recurrence task id
+ */
+ public function createRecurrence($task_id)
+ {
+ $values = $this->copyFields($task_id);
+
+ if ($values['recurrence_status'] == Task::RECURE_STATUS_PENDING)
+ {
+ $values['recurrence_parent'] = $task_id;
+ $values['column_id'] = $this->board->getFirstColumn($values['project_id']);
+ $this->recurrenceDateDue($values);
+ $recuretask = $this->save($task_id, $values);
+
+ if ($recuretask)
+ {
+ $recurrenceStatusUpdate = $this->db
+ ->table(Task::TABLE)
+ ->eq('id',$task_id)
+ ->update(array(
+ 'recurrence_status' => Task::RECURE_STATUS_PROCESSED,
+ 'recurrence_child' => $recuretask,
+ ));
+
+ if($recurrenceStatusUpdate)
+ {
+ return $recuretask;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
* Duplicate a task to another project
*
* @access public
@@ -127,6 +169,51 @@ class TaskDuplication extends Base
}
/**
+ * Calculate new due date for new recurrence task
+ *
+ * @access private
+ * @param array $values
+ */
+ private function recurrenceDateDue(&$values)
+ {
+ if ($values['date_due'] && $values['recurrence_factor'])
+ {
+ if ($values['recurrence_basedate'])
+ {
+ $values['date_due'] = time();
+ }
+
+ $factor = abs($values['recurrence_factor']);
+
+ if ($values['recurrence_factor'] < 0)
+ {
+ $subtract=TRUE;
+ }
+
+ switch ($values['recurrence_timeframe'])
+ {
+ case Task::RECURE_MONTHS:
+ $interval = 'P' . $factor . 'M';
+ break;
+ case Task::RECURE_YEARS:
+ $interval = 'P' . $factor . 'Y';
+ break;
+ default:
+ $interval = 'P' . $factor . 'D';
+ break;
+ }
+
+ $date_due = new \DateTime();
+
+ $date_due->setTimestamp($values['date_due']);
+
+ $subtract ? $date_due->sub(new \DateInterval($interval)) : $date_due->add(new \DateInterval($interval));
+
+ $values['date_due'] = $date_due->getTimestamp();
+ }
+ }
+
+ /**
* Duplicate fields for the new task
*
* @access private
diff --git a/app/Model/TaskFinder.php b/app/Model/TaskFinder.php
index 54dd578a..6f53249a 100644
--- a/app/Model/TaskFinder.php
+++ b/app/Model/TaskFinder.php
@@ -104,6 +104,13 @@ class TaskFinder extends Base
'tasks.score',
'tasks.category_id',
'tasks.date_moved',
+ 'tasks.recurrence_status',
+ 'tasks.recurrence_trigger',
+ 'tasks.recurrence_factor',
+ 'tasks.recurrence_timeframe',
+ 'tasks.recurrence_basedate',
+ 'tasks.recurrence_parent',
+ 'tasks.recurrence_child',
'users.username AS assignee_username',
'users.name AS assignee_name'
)
@@ -246,6 +253,13 @@ class TaskFinder extends Base
tasks.category_id,
tasks.swimlane_id,
tasks.date_moved,
+ tasks.recurrence_status,
+ tasks.recurrence_trigger,
+ tasks.recurrence_factor,
+ tasks.recurrence_timeframe,
+ tasks.recurrence_basedate,
+ tasks.recurrence_parent,
+ tasks.recurrence_child,
project_has_categories.name AS category_name,
projects.name AS project_name,
columns.title AS column_title,
diff --git a/app/Model/TaskModification.php b/app/Model/TaskModification.php
index dac52334..677fcd60 100644
--- a/app/Model/TaskModification.php
+++ b/app/Model/TaskModification.php
@@ -67,7 +67,7 @@ class TaskModification extends Base
$this->dateParser->convert($values, array('date_due', 'date_started'));
$this->removeFields($values, array('another_task', 'id'));
$this->resetFields($values, array('date_due', 'date_started', 'score', 'category_id', 'time_estimated', 'time_spent'));
- $this->convertIntegerFields($values, array('is_active'));
+ $this->convertIntegerFields($values, array('is_active', 'recurrence_status', 'recurrence_trigger', 'recurrence_factor', 'recurrence_timeframe', 'recurrence_basedate'));
$values['date_modification'] = time();
}
diff --git a/app/Model/TaskPosition.php b/app/Model/TaskPosition.php
index ab5fe43b..37c1ace0 100644
--- a/app/Model/TaskPosition.php
+++ b/app/Model/TaskPosition.php
@@ -39,6 +39,19 @@ class TaskPosition extends Base
if ($fire_events) {
$this->fireEvents($original_task, $column_id, $position, $swimlane_id);
}
+
+ if ($original_task['recurrence_status'] == Task::RECURE_STATUS_PENDING
+ && $original_task['column_id'] != $column_id
+ && (
+ ($original_task['column_id'] == $this->board->getFirstColumn($project_id)
+ && $original_task['recurrence_trigger'] == Task::RECURE_TRIGGER_FIRST)
+ || ($column_id == $this->board->getLastColumn($project_id)
+ && $original_task['recurrence_trigger'] == Task::RECURE_TRIGGER_LAST)
+ )
+ )
+ {
+ $this->taskDuplication->createRecurrence($task_id);
+ }
}
return $result;
diff --git a/app/Model/TaskStatus.php b/app/Model/TaskStatus.php
index 30a65e1e..1ae8bfeb 100644
--- a/app/Model/TaskStatus.php
+++ b/app/Model/TaskStatus.php
@@ -89,7 +89,9 @@ class TaskStatus extends Base
*/
private function changeStatus($task_id, $status, $date_completed, $event)
{
- if (! $this->taskFinder->exists($task_id)) {
+ $task = $this->taskFinder->getById($task_id);
+
+ if (!$task['id']) {
return false;
}
@@ -107,6 +109,13 @@ class TaskStatus extends Base
$event,
new TaskEvent(array('task_id' => $task_id) + $this->taskFinder->getById($task_id))
);
+
+ if ($status == Task::STATUS_CLOSED
+ && $task['recurrence_status'] == Task::RECURE_STATUS_PENDING
+ && $task['recurrence_trigger'] == Task::RECURE_TRIGGER_CLOSE)
+ {
+ $this->taskDuplication->createRecurrence($task_id);
+ }
}
return $result;
diff --git a/app/Model/TaskValidator.php b/app/Model/TaskValidator.php
index ae21ca28..ec1383ad 100644
--- a/app/Model/TaskValidator.php
+++ b/app/Model/TaskValidator.php
@@ -30,6 +30,13 @@ class TaskValidator extends Base
new Validators\Integer('score', t('This value must be an integer')),
new Validators\Integer('category_id', t('This value must be an integer')),
new Validators\Integer('swimlane_id', t('This value must be an integer')),
+ new Validators\Integer('recurrence_child', t('This value must be an integer')),
+ new Validators\Integer('recurrence_parent', t('This value must be an integer')),
+ new Validators\Integer('recurrence_factor', t('This value must be an integer')),
+ new Validators\Integer('recurrence_timeframe', t('This value must be an integer')),
+ new Validators\Integer('recurrence_basedate', t('This value must be an integer')),
+ new Validators\Integer('recurrence_trigger', t('This value must be an integer')),
+ new Validators\Integer('recurrence_status', t('This value must be an integer')),
new Validators\MaxLength('title', t('The maximum length is %d characters', 200), 200),
new Validators\Date('date_due', t('Invalid date'), $this->dateParser->getDateFormats()),
new Validators\Date('date_started', t('Invalid date'), $this->dateParser->getDateFormats()),
@@ -82,6 +89,28 @@ class TaskValidator extends Base
}
/**
+ * Validate edit recurrence
+ *
+ * @access public
+ * @param array $values Form values
+ * @return array $valid, $errors [0] = Success or not, [1] = List of errors
+ */
+ public function validateEditRecurrence(array $values)
+ {
+ $rules = array(
+ new Validators\Required('id', t('The id is required')),
+ );
+
+ $v = new Validator($values, array_merge($rules, $this->commonValidationRules()));
+
+ return array(
+ $v->execute(),
+ $v->getErrors()
+ );
+ }
+
+
+ /**
* Validate task modification (form)
*
* @access public
diff --git a/app/Schema/Mysql.php b/app/Schema/Mysql.php
index 22f8c1b0..9ed23ee0 100644
--- a/app/Schema/Mysql.php
+++ b/app/Schema/Mysql.php
@@ -6,7 +6,18 @@ use PDO;
use Core\Security;
use Model\Link;
-const VERSION = 66;
+const VERSION = 67;
+
+function version_67($pdo)
+{
+ $pdo->exec('ALTER TABLE tasks ADD COLUMN recurrence_status INTEGER NOT NULL DEFAULT 0');
+ $pdo->exec('ALTER TABLE tasks ADD COLUMN recurrence_trigger INTEGER NOT NULL DEFAULT 0');
+ $pdo->exec('ALTER TABLE tasks ADD COLUMN recurrence_factor INTEGER NOT NULL DEFAULT 0');
+ $pdo->exec('ALTER TABLE tasks ADD COLUMN recurrence_timeframe INTEGER NOT NULL DEFAULT 0');
+ $pdo->exec('ALTER TABLE tasks ADD COLUMN recurrence_basedate INTEGER NOT NULL DEFAULT 0');
+ $pdo->exec('ALTER TABLE tasks ADD COLUMN recurrence_parent INTEGER');
+ $pdo->exec('ALTER TABLE tasks ADD COLUMN recurrence_child INTEGER');
+}
function version_66($pdo)
{
diff --git a/app/Schema/Postgres.php b/app/Schema/Postgres.php
index db30af67..f1262816 100644
--- a/app/Schema/Postgres.php
+++ b/app/Schema/Postgres.php
@@ -6,7 +6,18 @@ use PDO;
use Core\Security;
use Model\Link;
-const VERSION = 47;
+const VERSION = 48;
+
+function version_48($pdo)
+{
+ $pdo->exec('ALTER TABLE tasks ADD COLUMN recurrence_status INTEGER NOT NULL DEFAULT 0');
+ $pdo->exec('ALTER TABLE tasks ADD COLUMN recurrence_trigger INTEGER NOT NULL DEFAULT 0');
+ $pdo->exec('ALTER TABLE tasks ADD COLUMN recurrence_factor INTEGER NOT NULL DEFAULT 0');
+ $pdo->exec('ALTER TABLE tasks ADD COLUMN recurrence_timeframe INTEGER NOT NULL DEFAULT 0');
+ $pdo->exec('ALTER TABLE tasks ADD COLUMN recurrence_basedate INTEGER NOT NULL DEFAULT 0');
+ $pdo->exec('ALTER TABLE tasks ADD COLUMN recurrence_parent INTEGER');
+ $pdo->exec('ALTER TABLE tasks ADD COLUMN recurrence_child INTEGER');
+}
function version_47($pdo)
{
diff --git a/app/Schema/Sqlite.php b/app/Schema/Sqlite.php
index 79c50458..714d0e2f 100644
--- a/app/Schema/Sqlite.php
+++ b/app/Schema/Sqlite.php
@@ -6,7 +6,18 @@ use Core\Security;
use PDO;
use Model\Link;
-const VERSION = 65;
+const VERSION = 66;
+
+function version_66($pdo)
+{
+ $pdo->exec('ALTER TABLE tasks ADD COLUMN recurrence_status INTEGER NOT NULL DEFAULT 0');
+ $pdo->exec('ALTER TABLE tasks ADD COLUMN recurrence_trigger INTEGER NOT NULL DEFAULT 0');
+ $pdo->exec('ALTER TABLE tasks ADD COLUMN recurrence_factor INTEGER NOT NULL DEFAULT 0');
+ $pdo->exec('ALTER TABLE tasks ADD COLUMN recurrence_timeframe INTEGER NOT NULL DEFAULT 0');
+ $pdo->exec('ALTER TABLE tasks ADD COLUMN recurrence_basedate INTEGER NOT NULL DEFAULT 0');
+ $pdo->exec('ALTER TABLE tasks ADD COLUMN recurrence_parent INTEGER');
+ $pdo->exec('ALTER TABLE tasks ADD COLUMN recurrence_child INTEGER');
+}
function version_65($pdo)
{
diff --git a/app/Template/board/recurrence.php b/app/Template/board/recurrence.php
new file mode 100644
index 00000000..1b71bc34
--- /dev/null
+++ b/app/Template/board/recurrence.php
@@ -0,0 +1,18 @@
+<section class="tooltip-large">
+<?php if ($task['recurrence_status'] == \Model\Task::RECURE_STATUS_PENDING): ?>
+ <?= t('Recurrent task is scheduled to generate') ?><br/>
+<?php endif ?>
+<?php if ($task['recurrence_status'] == \Model\Task::RECURE_STATUS_PROCESSED): ?>
+ <?= t('Recurrent task has been generated') ?><br/>
+<?php endif ?>
+ <?= t('Trigger to generate recurrent task: %s', $recurrence_trigger_list[$task['recurrence_trigger']]) ?><br/>
+ <?= t('Factor to calculate new due date: %s', $task['recurrence_factor']) ?><br/>
+ <?= t('Timeframe to calculate new due date: %s', $recurrence_timeframe_list[$task['recurrence_timeframe']]) ?><br/>
+ <?= t('Base date to calculate new due date: %s', $recurrence_basedate_list[$task['recurrence_basedate']]) ?><br/>
+<?php if ($task['recurrence_parent']): ?>
+ <?= t('Recurrent task created by: %s', $task['recurrence_parent']) ?><br/>
+<?php endif ?>
+<?php if ($task['recurrence_child']): ?>
+ <?= t('Created recurrent task: %s', $task['recurrence_child']) ?><br/>
+<?php endif ?>
+</section>
diff --git a/app/Template/board/task_footer.php b/app/Template/board/task_footer.php
index 36ed2684..b8868f52 100644
--- a/app/Template/board/task_footer.php
+++ b/app/Template/board/task_footer.php
@@ -25,6 +25,14 @@
</span>
<?php endif ?>
+ <?php if ($task['recurrence_status'] == \Model\Task::RECURE_STATUS_PENDING): ?>
+ <span title="<?= t('Recurrence') ?>" class="task-board-tooltip" data-href="<?= $this->u('board', 'recurrence', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>"><i class="fa fa-refresh fa-rotate-90"></i></span>
+ <?php endif ?>
+
+ <?php if ($task['recurrence_status'] == \Model\Task::RECURE_STATUS_PROCESSED): ?>
+ <span title="<?= t('Recurrence') ?>" class="task-board-tooltip" data-href="<?= $this->u('board', 'recurrence', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>"><i class="fa fa-refresh fa-rotate-90 fa-inverse"></i></span>
+ <?php endif ?>
+
<?php if (! empty($task['nb_links'])): ?>
<span title="<?= t('Links') ?>" class="task-board-tooltip" data-href="<?= $this->u('board', 'tasklinks', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>"><i class="fa fa-code-fork"></i>&nbsp;<?= $task['nb_links'] ?></span>
<?php endif ?>
diff --git a/app/Template/board/task_menu.php b/app/Template/board/task_menu.php
index f3ec3019..fba2d71d 100644
--- a/app/Template/board/task_menu.php
+++ b/app/Template/board/task_menu.php
@@ -5,6 +5,7 @@
<li><i class="fa fa-user"></i> <?= $this->a(t('Change assignee'), 'board', 'changeAssignee', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'task-board-popover') ?></li>
<li><i class="fa fa-tag"></i> <?= $this->a(t('Change category'), 'board', 'changeCategory', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'task-board-popover') ?></li>
<li><i class="fa fa-align-left"></i> <?= $this->a(t('Change description'), 'task', 'description', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'task-board-popover') ?></li>
+ <li><i class="fa fa-refresh fa-rotate-90"></i> <?= $this->a(t('Edit recurrence'), 'task', 'recurrence', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'task-board-popover') ?></li>
<li><i class="fa fa-comment-o"></i> <?= $this->a(t('Add a comment'), 'comment', 'create', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'task-board-popover') ?></li>
<li><i class="fa fa-code-fork"></i> <?= $this->a(t('Add a link'), 'tasklink', 'create', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'task-board-popover') ?></li>
<li><i class="fa fa-pencil-square-o"></i> <?= $this->a(t('Edit this task'), 'task', 'edit', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'task-board-popover') ?></li>
@@ -12,4 +13,4 @@
<li><i class="fa fa-close"></i> <?= $this->a(t('Close this task'), 'task', 'close', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'redirect' => 'board'), false, 'task-board-popover') ?></li>
</ul>
</span>
-</span> \ No newline at end of file
+</span>
diff --git a/app/Template/task/details.php b/app/Template/task/details.php
index 76241acf..331862b9 100644
--- a/app/Template/task/details.php
+++ b/app/Template/task/details.php
@@ -80,5 +80,44 @@
<?= $this->a(t('Public link'), 'task', 'readonly', array('task_id' => $task['id'], 'token' => $project['token']), false, '', '', true) ?>
</li>
<?php endif ?>
+ <?php if ($task['recurrence_status'] == \Model\Task::RECURE_STATUS_NONE): ?>
+ <li>
+ <?= t('No recurrent task is scheduled to generate') ?>
+ </li>
+ <?php endif ?>
+ <?php if ($task['recurrence_status'] != \Model\Task::RECURE_STATUS_NONE): ?>
+ <li>
+ <?php if ($task['recurrence_status'] == \Model\Task::RECURE_STATUS_PENDING): ?>
+ <?= t('Recurrent task is scheduled to generate') ?>
+ <?php endif ?>
+ <?php if ($task['recurrence_status'] == \Model\Task::RECURE_STATUS_PROCESSED): ?>
+ <?= t('Recurrent task has been generated') ?>
+ <?php endif ?>
+ <ul>
+ <li>
+ <?= t('Trigger to generate recurrent task: %s', $recurrence_trigger_list[$task['recurrence_trigger']]) ?></stong>
+ </li>
+ <li>
+ <?= t('Factor to calculate new due date: %s', $task['recurrence_factor']) ?></stong>
+ </li>
+ <li>
+ <?= t('Timeframe to calculate new due date: %s', $recurrence_timeframe_list[$task['recurrence_timeframe']]) ?></stong>
+ </li>
+ <li>
+ <?= t('Base date to calculate new due date: %s', $recurrence_basedate_list[$task['recurrence_basedate']]) ?></stong>
+ </li>
+ </ul>
+ </li>
+ <?php endif ?>
+ <?php if ($task['recurrence_parent']): ?>
+ <li>
+ <?= t('Recurrent task created by: %s', $task['recurrence_parent']) ?>
+ </li>
+ <?php endif ?>
+ <?php if ($task['recurrence_child']): ?>
+ <li>
+ <?= t('Created recurrent task: %s', $task['recurrence_child']) ?>
+ </li>
+ <?php endif ?>
</ul>
</div>
diff --git a/app/Template/task/edit_recurrence.php b/app/Template/task/edit_recurrence.php
new file mode 100644
index 00000000..bb86e429
--- /dev/null
+++ b/app/Template/task/edit_recurrence.php
@@ -0,0 +1,85 @@
+<div class="page-header">
+ <h2><?= t('Edit recurrence') ?></h2>
+</div>
+<section id="task-section">
+
+
+
+<form method="post" action="<?= $this->u('task', 'recurrence', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'ajax' => $ajax)) ?>" autocomplete="off">
+
+ <?= $this->formCsrf() ?>
+
+
+ <div class="form-column">
+ <?php if ($task['recurrence_status'] == \Model\Task::RECURE_STATUS_PROCESSED): ?>
+ <ul>
+ <li><?= t('Recurrent task has been generated') ?>
+ <ul>
+ <li>
+ <?= t('Trigger to generate recurrent task: %s', $recurrence_trigger_list[$task['recurrence_trigger']]) ?></stong>
+ </li>
+ <li>
+ <?= t('Factor to calculate new due date: %s', $task['recurrence_factor']) ?></stong>
+ </li>
+ <li>
+ <?= t('Timeframe to calculate new due date: %s', $recurrence_timeframe_list[$task['recurrence_timeframe']]) ?></stong>
+ </li>
+ <li>
+ <?= t('Base date to calculate new due date: %s', $recurrence_basedate_list[$task['recurrence_basedate']]) ?></stong>
+ </li>
+ </ul>
+ </li>
+ </ul>
+ <?php endif ?>
+ <?php if ($task['recurrence_parent'] || $task['recurrence_child']): ?>
+ <ul>
+ <?php if ($task['recurrence_parent']): ?>
+ <li>
+ <?= t('Recurrent task created by: %s', $task['recurrence_parent']) ?>
+ </li>
+ <?php endif ?>
+ <?php if ($task['recurrence_child']): ?>
+ <li>
+ <?= t('Created recurrent task: %s', $task['recurrence_child']) ?>
+ </li>
+ <?php endif ?>
+ </ul>
+ <?php endif ?>
+
+ <?php if ($task['recurrence_status'] != \Model\Task::RECURE_STATUS_PROCESSED): ?>
+
+ <?= $this->formHidden('id', $values) ?>
+ <?= $this->formHidden('project_id', $values) ?>
+
+ <?= $this->formLabel(t('Generate recurrent task'), 'recurrence_status') ?>
+ <?= $this->formSelect('recurrence_status', $recurrence_status_list, $values, $errors) ?> </br>
+
+ <?= $this->formLabel(t('Trigger to generate recurrent task'), 'recurrence_trigger') ?>
+ <?= $this->formSelect('recurrence_trigger', $recurrence_trigger_list, $values, $errors) ?> </br>
+
+ <?= $this->formLabel(t('Factor to calculate new due date'), 'recurrence_factor') ?>
+ <?= $this->formNumber('recurrence_factor', $values, $errors) ?> </br>
+
+ <?= $this->formLabel(t('Timeframe to calculate new due date'), 'recurrence_timeframe') ?>
+ <?= $this->formSelect('recurrence_timeframe', $recurrence_timeframe_list, $values, $errors) ?> </br>
+
+ <?= $this->formLabel(t('Base date to calculate new due date'), 'recurrence_basedate') ?>
+ <?= $this->formSelect('recurrence_basedate', $recurrence_basedate_list, $values, $errors) ?> </br>
+
+ <?php endif ?>
+
+ </div>
+
+ <div class="form-actions">
+ <?php if ($task['recurrence_status'] != \Model\Task::RECURE_STATUS_PROCESSED): ?>
+ <input type="submit" value="<?= t('Save') ?>" class="btn btn-blue"/>
+ <?= t('or') ?>
+ <?php endif ?>
+ <?php if ($ajax): ?>
+ <?= $this->a(t('cancel'), 'board', 'show', array('project_id' => $task['project_id'])) ?>
+ <?php else: ?>
+ <?= $this->a(t('cancel'), 'task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>
+ <?php endif ?>
+ </div>
+</form>
+</section>
diff --git a/app/Template/task/show.php b/app/Template/task/show.php
index 50316c9f..9d16ab74 100644
--- a/app/Template/task/show.php
+++ b/app/Template/task/show.php
@@ -1,4 +1,4 @@
-<?= $this->render('task/details', array('task' => $task, 'project' => $project)) ?>
+<?= $this->render('task/details', array('task' => $task, 'project' => $project, 'recurrence_trigger_list' => $this->task->getRecurrenceTriggerList(), 'recurrence_timeframe_list' => $this->task->getRecurrenceTimeframeList(), 'recurrence_basedate_list' => $this->task->getRecurrenceBasedateList())) ?>
<?= $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, 'link_label_list' => $link_label_list)) ?>
diff --git a/app/Template/task/sidebar.php b/app/Template/task/sidebar.php
index a740e939..7c82700a 100644
--- a/app/Template/task/sidebar.php
+++ b/app/Template/task/sidebar.php
@@ -25,6 +25,9 @@
<?= $this->a(t('Edit the description'), 'task', 'description', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>
</li>
<li>
+ <?= $this->a(t('Edit recurrence'), 'task', 'recurrence', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>
+ </li>
+ <li>
<?= $this->a(t('Add a sub-task'), 'subtask', 'create', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>
</li>
<li>
@@ -61,4 +64,4 @@
</li>
<?php endif ?>
</ul>
-</div> \ No newline at end of file
+</div>