summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
authorFrederic Guillot <fred@kanboard.net>2016-11-05 22:26:58 -0400
committerFrederic Guillot <fred@kanboard.net>2016-11-05 22:26:58 -0400
commit3f7840c4db7384eb142f92c33330827b8d7255f9 (patch)
tree8f0cb3b6e0039eb4914534dd64718ecff6dc4715 /app
parentae5d31e4c285e0ce672de780fdacff953fe71bba (diff)
Add the possibility to create external tasks
Diffstat (limited to 'app')
-rw-r--r--app/Controller/ExternalTaskCreationController.php97
-rw-r--r--app/Core/ExternalTask/AccessForbiddenException.php5
-rw-r--r--app/Core/ExternalTask/ExternalTaskException.php15
-rw-r--r--app/Core/ExternalTask/ExternalTaskInterface.php26
-rw-r--r--app/Core/ExternalTask/ExternalTaskProviderInterface.php35
-rw-r--r--app/Core/ExternalTask/NotFoundException.php4
-rw-r--r--app/Core/ExternalTask/ProviderNotFoundException.php4
-rw-r--r--app/Helper/TaskHelper.php28
-rw-r--r--app/Schema/Mysql.php8
-rw-r--r--app/Schema/Postgres.php8
-rw-r--r--app/Schema/Sqlite.php8
-rw-r--r--app/Template/external_task_creation/step1.php19
-rw-r--r--app/Template/external_task_creation/step2.php25
-rw-r--r--app/Template/task_creation/show.php5
14 files changed, 256 insertions, 31 deletions
diff --git a/app/Controller/ExternalTaskCreationController.php b/app/Controller/ExternalTaskCreationController.php
new file mode 100644
index 00000000..f2afd9aa
--- /dev/null
+++ b/app/Controller/ExternalTaskCreationController.php
@@ -0,0 +1,97 @@
+<?php
+
+namespace Kanboard\Controller;
+
+use Kanboard\Core\ExternalTask\ExternalTaskException;
+
+/**
+ * External Task Creation Controller
+ *
+ * @package Kanboard\Controller
+ * @author Frederic Guillot
+ */
+class ExternalTaskCreationController extends BaseController
+{
+ public function step1(array $values = array(), $errorMessage = '')
+ {
+ $project = $this->getProject();
+ $providerName = $this->request->getStringParam('provider_name');
+ $taskProvider = $this->externalTaskManager->getProvider($providerName);
+
+ if (empty($values)) {
+ $values = array(
+ 'swimlane_id' => $this->request->getIntegerParam('swimlane_id'),
+ 'column_id' => $this->request->getIntegerParam('column_id'),
+ );
+ }
+
+ $this->response->html($this->template->render('external_task_creation/step1', array(
+ 'project' => $project,
+ 'values' => $values,
+ 'error_message' => $errorMessage,
+ 'provider_name' => $providerName,
+ 'template' => $taskProvider->getImportFormTemplate(),
+ )));
+ }
+
+ public function step2(array $values = array(), array $errors = array())
+ {
+ $project = $this->getProject();
+ $providerName = $this->request->getStringParam('provider_name');
+
+ try {
+ $taskProvider = $this->externalTaskManager->getProvider($providerName);
+
+ if (empty($values)) {
+ $values = $this->request->getValues();
+ $externalTask = $taskProvider->retrieve($taskProvider->buildTaskUri($values));
+
+ $values = $externalTask->getFormValues() + array(
+ 'external_uri' => $externalTask->getUri(),
+ 'external_provider' => $providerName,
+ 'project_id' => $project['id'],
+ 'swimlane_id' => $values['swimlane_id'],
+ 'column_id' => $values['column_id'],
+ 'color_id' => $this->colorModel->getDefaultColor(),
+ 'owner_id' => $this->userSession->getId(),
+ );
+ } else {
+ $externalTask = $taskProvider->retrieve($values['external_uri']);
+ }
+
+ $this->response->html($this->template->render('external_task_creation/step2', array(
+ 'project' => $project,
+ 'external_task' => $externalTask,
+ 'provider_name' => $providerName,
+ 'values' => $values,
+ 'errors' => $errors,
+ 'template' => $taskProvider->getCreationFormTemplate(),
+ 'columns_list' => $this->columnModel->getList($project['id']),
+ 'users_list' => $this->projectUserRoleModel->getAssignableUsersList($project['id'], true, false, true),
+ 'categories_list' => $this->categoryModel->getList($project['id']),
+ 'swimlanes_list' => $this->swimlaneModel->getList($project['id'], false, true),
+ )));
+ } catch (ExternalTaskException $e) {
+ $this->step1($values, $e->getMessage());
+ }
+ }
+
+ public function step3()
+ {
+ $project = $this->getProject();
+ $values = $this->request->getValues();
+
+ list($valid, $errors) = $this->taskValidator->validateCreation($values);
+
+ if (! $valid) {
+ $this->step2($values, $errors);
+ } else if (! $this->helper->projectRole->canCreateTaskInColumn($project['id'], $values['column_id'])) {
+ $this->flash->failure(t('You cannot create tasks in this column.'));
+ $this->response->redirect($this->helper->url->to('BoardViewController', 'show', array('project_id' => $project['id'])), true);
+ } else {
+ $taskId = $this->taskCreationModel->create($values);
+ $this->flash->success(t('Task created successfully.'));
+ $this->response->redirect($this->helper->url->to('TaskViewController', 'show', array('project_id' => $project['id'], 'task_id' => $taskId)), true);
+ }
+ }
+}
diff --git a/app/Core/ExternalTask/AccessForbiddenException.php b/app/Core/ExternalTask/AccessForbiddenException.php
index a379d812..2b5ebd33 100644
--- a/app/Core/ExternalTask/AccessForbiddenException.php
+++ b/app/Core/ExternalTask/AccessForbiddenException.php
@@ -2,13 +2,12 @@
namespace Kanboard\Core\ExternalTask;
-use Exception;
-
/**
* Class AccessForbiddenException
*
* @package Kanboard\Core\ExternalTask
+ * @author Frederic Guillot
*/
-class AccessForbiddenException extends Exception
+class AccessForbiddenException extends ExternalTaskException
{
}
diff --git a/app/Core/ExternalTask/ExternalTaskException.php b/app/Core/ExternalTask/ExternalTaskException.php
new file mode 100644
index 00000000..07e5665d
--- /dev/null
+++ b/app/Core/ExternalTask/ExternalTaskException.php
@@ -0,0 +1,15 @@
+<?php
+
+namespace Kanboard\Core\ExternalTask;
+
+use Exception;
+
+/**
+ * Class NotFoundException
+ *
+ * @package Kanboard\Core\ExternalTask
+ * @author Frederic Guillot
+ */
+class ExternalTaskException extends Exception
+{
+}
diff --git a/app/Core/ExternalTask/ExternalTaskInterface.php b/app/Core/ExternalTask/ExternalTaskInterface.php
new file mode 100644
index 00000000..084af509
--- /dev/null
+++ b/app/Core/ExternalTask/ExternalTaskInterface.php
@@ -0,0 +1,26 @@
+<?php
+
+namespace Kanboard\Core\ExternalTask;
+
+/**
+ * Interface ExternalTaskInterface
+ *
+ * @package Kanboard\Core\ExternalTask
+ * @author Frederic Guillot
+ */
+interface ExternalTaskInterface
+{
+ /**
+ * Return Uniform Resource Identifier for the task
+ *
+ * @return string
+ */
+ public function getUri();
+
+ /**
+ * Return a dict to populate the task form
+ *
+ * @return array
+ */
+ public function getFormValues();
+}
diff --git a/app/Core/ExternalTask/ExternalTaskProviderInterface.php b/app/Core/ExternalTask/ExternalTaskProviderInterface.php
index 9e672780..af1dffec 100644
--- a/app/Core/ExternalTask/ExternalTaskProviderInterface.php
+++ b/app/Core/ExternalTask/ExternalTaskProviderInterface.php
@@ -11,15 +11,6 @@ namespace Kanboard\Core\ExternalTask;
interface ExternalTaskProviderInterface
{
/**
- * Get templates
- *
- * @return string
- */
- public function getCreationFormTemplate();
- public function getModificationFormTemplate();
- public function getTaskViewTemplate();
-
- /**
* Get provider name (visible in the user interface)
*
* @access public
@@ -34,17 +25,29 @@ interface ExternalTaskProviderInterface
* @throws \Kanboard\Core\ExternalTask\AccessForbiddenException
* @throws \Kanboard\Core\ExternalTask\NotFoundException
* @param string $uri
- * @return array Dict that will populate the form
+ * @return ExternalTaskInterface
*/
public function retrieve($uri);
/**
- * Save the task to the external system and/or update the cache
+ * Get task import template name
*
- * @access public
- * @param string $uri
- * @param array $data
- * @return bool
+ * @return string
+ */
+ public function getImportFormTemplate();
+
+ /**
+ * Get creation form template
+ *
+ * @return string
+ */
+ public function getCreationFormTemplate();
+
+ /**
+ * Build external task URI based on import form values
+ *
+ * @param array $values
+ * @return string
*/
- public function persist($uri, array $data);
+ public function buildTaskUri(array $values);
}
diff --git a/app/Core/ExternalTask/NotFoundException.php b/app/Core/ExternalTask/NotFoundException.php
index c7ed13ef..34eff8ea 100644
--- a/app/Core/ExternalTask/NotFoundException.php
+++ b/app/Core/ExternalTask/NotFoundException.php
@@ -2,14 +2,12 @@
namespace Kanboard\Core\ExternalTask;
-use Exception;
-
/**
* Class NotFoundException
*
* @package Kanboard\Core\ExternalTask
* @author Frederic Guillot
*/
-class NotFoundException extends Exception
+class NotFoundException extends ExternalTaskException
{
}
diff --git a/app/Core/ExternalTask/ProviderNotFoundException.php b/app/Core/ExternalTask/ProviderNotFoundException.php
index 2deddda8..6ad1fae1 100644
--- a/app/Core/ExternalTask/ProviderNotFoundException.php
+++ b/app/Core/ExternalTask/ProviderNotFoundException.php
@@ -2,14 +2,12 @@
namespace Kanboard\Core\ExternalTask;
-use Exception;
-
/**
* Class ProviderNotFoundException
*
* @package Kanboard\Core\ExternalTask
* @author Frederic Guillot
*/
-class ProviderNotFoundException extends Exception
+class ProviderNotFoundException extends ExternalTaskException
{
}
diff --git a/app/Helper/TaskHelper.php b/app/Helper/TaskHelper.php
index 678b4bed..1dce7c54 100644
--- a/app/Helper/TaskHelper.php
+++ b/app/Helper/TaskHelper.php
@@ -238,4 +238,32 @@ class TaskHelper extends Base
return $this->taskModel->getProgress($task, $this->columns[$task['project_id']]);
}
+
+ public function getNewTaskDropdown($projectId, $swimlaneId, $columnId)
+ {
+ $providers = $this->externalTaskManager->getProvidersList();
+
+ if (empty($providers)) {
+ return '';
+ }
+
+ $html = '<small class="pull-right"><div class="dropdown">';
+ $html .= '<a href="#" class="dropdown-menu"><i class="fa fa-cloud-download" aria-hidden="true"></i> <i class="fa fa-caret-down"></i></a><ul>';
+
+ foreach ($providers as $providerName) {
+ $link = $this->helper->url->link(
+ t('New External Task: %s', $providerName),
+ 'ExternalTaskCreationController',
+ 'step1',
+ array('project_id' => $projectId, 'swimlane_id' => $swimlaneId, 'column_id' => $columnId, 'provider_name' => $providerName),
+ false,
+ 'popover-link'
+ );
+
+ $html .= '<li><i class="fa fa-fw fa-plus-square" aria-hidden="true"></i> '.$link.'</li>';
+ }
+
+ $html .= '</ul></div></small>';
+ return $html;
+ }
}
diff --git a/app/Schema/Mysql.php b/app/Schema/Mysql.php
index 274ce8c8..b50164ca 100644
--- a/app/Schema/Mysql.php
+++ b/app/Schema/Mysql.php
@@ -6,7 +6,13 @@ use PDO;
use Kanboard\Core\Security\Token;
use Kanboard\Core\Security\Role;
-const VERSION = 115;
+const VERSION = 116;
+
+function version_116(PDO $pdo)
+{
+ $pdo->exec("ALTER TABLE tasks ADD COLUMN external_provider VARCHAR(255)");
+ $pdo->exec("ALTER TABLE tasks ADD COLUMN external_uri VARCHAR(255)");
+}
function version_115(PDO $pdo)
{
diff --git a/app/Schema/Postgres.php b/app/Schema/Postgres.php
index 213d9869..83926f19 100644
--- a/app/Schema/Postgres.php
+++ b/app/Schema/Postgres.php
@@ -6,7 +6,13 @@ use PDO;
use Kanboard\Core\Security\Token;
use Kanboard\Core\Security\Role;
-const VERSION = 94;
+const VERSION = 95;
+
+function version_95(PDO $pdo)
+{
+ $pdo->exec("ALTER TABLE tasks ADD COLUMN external_provider VARCHAR(255)");
+ $pdo->exec("ALTER TABLE tasks ADD COLUMN external_uri VARCHAR(255)");
+}
function version_94(PDO $pdo)
{
diff --git a/app/Schema/Sqlite.php b/app/Schema/Sqlite.php
index f86a6af0..edf6ce63 100644
--- a/app/Schema/Sqlite.php
+++ b/app/Schema/Sqlite.php
@@ -6,7 +6,13 @@ use Kanboard\Core\Security\Token;
use Kanboard\Core\Security\Role;
use PDO;
-const VERSION = 106;
+const VERSION = 107;
+
+function version_107(PDO $pdo)
+{
+ $pdo->exec("ALTER TABLE tasks ADD COLUMN external_provider TEXT");
+ $pdo->exec("ALTER TABLE tasks ADD COLUMN external_uri TEXT");
+}
function version_106(PDO $pdo)
{
diff --git a/app/Template/external_task_creation/step1.php b/app/Template/external_task_creation/step1.php
new file mode 100644
index 00000000..2af9b427
--- /dev/null
+++ b/app/Template/external_task_creation/step1.php
@@ -0,0 +1,19 @@
+<form class="popover-form" method="post" action="<?= $this->url->href('ExternalTaskCreationController', 'step2', array('project_id' => $project['id'], 'provider_name' => $provider_name)) ?>">
+ <?= $this->form->csrf() ?>
+ <?= $this->form->hidden('swimlane_id', $values) ?>
+ <?= $this->form->hidden('column_id', $values) ?>
+
+ <?= $this->render($template, array(
+ 'project' => $project,
+ 'values' => $values,
+ )) ?>
+
+ <?php if (! empty($error_message)): ?>
+ <div class="alert alert-error"><?= $this->text->e($error_message) ?></div>
+ <?php endif ?>
+
+ <div class="form-actions">
+ <button type="submit" class="btn btn-blue"><?= t('Next') ?></button>
+ <?= t('or') ?> <?= $this->url->link(t('cancel'), 'BoardViewController', 'show', array('project_id' => $project['id']), false, 'close-popover') ?>
+ </div>
+</form>
diff --git a/app/Template/external_task_creation/step2.php b/app/Template/external_task_creation/step2.php
new file mode 100644
index 00000000..4bc0e509
--- /dev/null
+++ b/app/Template/external_task_creation/step2.php
@@ -0,0 +1,25 @@
+<form class="popover-form" method="post" action="<?= $this->url->href('ExternalTaskCreationController', 'step3', array('project_id' => $project['id'], 'provider_name' => $provider_name)) ?>">
+ <?= $this->form->csrf() ?>
+ <?= $this->form->hidden('external_provider', $values) ?>
+ <?= $this->form->hidden('external_uri', $values) ?>
+
+ <?= $this->render($template, array(
+ 'project' => $project,
+ 'external_task' => $external_task,
+ 'values' => $values,
+ 'errors' => $errors,
+ 'users_list' => $users_list,
+ 'categories_list' => $categories_list,
+ 'swimlanes_list' => $swimlanes_list,
+ 'columns_list' => $columns_list,
+ )) ?>
+
+ <?php if (! empty($error_message)): ?>
+ <div class="alert alert-error"><?= $this->text->e($error_message) ?></div>
+ <?php endif ?>
+
+ <div class="form-actions">
+ <button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
+ <?= t('or') ?> <?= $this->url->link(t('cancel'), 'BoardViewController', 'show', array('project_id' => $project['id']), false, 'close-popover') ?>
+ </div>
+</form>
diff --git a/app/Template/task_creation/show.php b/app/Template/task_creation/show.php
index 0c267aff..840d1804 100644
--- a/app/Template/task_creation/show.php
+++ b/app/Template/task_creation/show.php
@@ -1,8 +1,8 @@
<div class="page-header">
- <h2><?= $this->text->e($project['name']) ?> &gt; <?= t('New task') ?></h2>
+ <h2><?= $this->text->e($project['name']) ?> &gt; <?= t('New task') ?><?= $this->task->getNewTaskDropdown($project['id'], $values['swimlane_id'], $values['column_id']) ?></h2>
</div>
-<form class="popover-form" method="post" action="<?= $this->url->href('TaskCreationController', 'save', array('project_id' => $values['project_id'])) ?>" autocomplete="off">
+<form class="popover-form" method="post" action="<?= $this->url->href('TaskCreationController', 'save', array('project_id' => $project['id'])) ?>" autocomplete="off">
<?= $this->form->csrf() ?>
<div class="form-columns">
@@ -17,7 +17,6 @@
<?= $this->form->checkbox('another_task', t('Create another task'), 1, isset($values['another_task']) && $values['another_task'] == 1) ?>
<?= $this->form->checkbox('duplicate_multiple_projects', t('Duplicate to multiple projects'), 1) ?>
<?php endif ?>
-
</div>
<div class="form-column">