From 35d99ec5d3e5d18e83537c68831be02d40f36d8e Mon Sep 17 00:00:00 2001 From: Frederic Guillot Date: Sun, 1 Mar 2015 18:03:58 -0500 Subject: Add subtask position --- app/Controller/Subtask.php | 20 ++++++++++- app/Model/Subtask.php | 82 +++++++++++++++++++++++++++++++++++++++++-- app/Schema/Mysql.php | 24 ++++++++++++- app/Schema/Postgres.php | 24 ++++++++++++- app/Schema/Sqlite.php | 26 +++++++++++++- app/Template/subtask/show.php | 12 ++++++- app/Template/task/show.php | 2 +- 7 files changed, 181 insertions(+), 9 deletions(-) (limited to 'app') diff --git a/app/Controller/Subtask.php b/app/Controller/Subtask.php index c7ec00d1..385785a1 100644 --- a/app/Controller/Subtask.php +++ b/app/Controller/Subtask.php @@ -185,7 +185,7 @@ class Subtask extends Base if ($redirect === 'board') { $this->session['has_subtask_inprogress'] = $this->subtask->hasSubtaskInProgress($this->userSession->getId()); - + $this->response->html($this->template->render('board/subtasks', array( 'subtasks' => $this->subtask->getAll($task['id']), 'task' => $task, @@ -259,4 +259,22 @@ class Subtask extends Base $this->response->redirect($this->helper->url('task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']))); } } + + /** + * Move subtask position + * + * @access public + */ + public function movePosition() + { + $this->checkCSRFParam(); + $project_id = $this->request->getIntegerParam('project_id'); + $task_id = $this->request->getIntegerParam('task_id'); + $subtask_id = $this->request->getIntegerParam('subtask_id'); + $direction = $this->request->getStringParam('direction'); + $method = $direction === 'up' ? 'moveUp' : 'moveDown'; + + $this->subtask->$method($task_id, $subtask_id); + $this->response->redirect($this->helper->url('task', 'show', array('project_id' => $project_id, 'task_id' => $task_id)).'#subtasks'); + } } diff --git a/app/Model/Subtask.php b/app/Model/Subtask.php index aa4a6f81..2d108eab 100644 --- a/app/Model/Subtask.php +++ b/app/Model/Subtask.php @@ -122,7 +122,7 @@ class Subtask extends Base ->eq('task_id', $task_id) ->columns(self::TABLE.'.*', User::TABLE.'.username', User::TABLE.'.name') ->join(User::TABLE, 'id', 'user_id') - ->asc(self::TABLE.'.id') + ->asc(self::TABLE.'.position') ->filter(array($this, 'addStatusName')) ->findAll(); } @@ -163,6 +163,22 @@ class Subtask extends Base $this->resetFields($values, array('time_estimated', 'time_spent')); } + /** + * Get the position of the last column for a given project + * + * @access public + * @param integer $task_id Task id + * @return integer + */ + public function getLastPosition($task_id) + { + return (int) $this->db + ->table(self::TABLE) + ->eq('task_id', $task_id) + ->desc('position') + ->findOneColumn('position'); + } + /** * Create a new subtask * @@ -173,6 +189,8 @@ class Subtask extends Base public function create(array $values) { $this->prepare($values); + $values['position'] = $this->getLastPosition($values['task_id']) + 1; + $subtask_id = $this->persist(self::TABLE, $values); if ($subtask_id) { @@ -208,6 +226,64 @@ class Subtask extends Base return $result; } + /** + * Move a subtask down, increment the position value + * + * @access public + * @param integer $task_id + * @param integer $subtask_id + * @return boolean + */ + public function moveDown($task_id, $subtask_id) + { + $subtasks = $this->db->hashtable(self::TABLE)->eq('task_id', $task_id)->asc('position')->getAll('id', 'position'); + $positions = array_flip($subtasks); + + if (isset($subtasks[$subtask_id]) && $subtasks[$subtask_id] < count($subtasks)) { + + $position = ++$subtasks[$subtask_id]; + $subtasks[$positions[$position]]--; + + $this->db->startTransaction(); + $this->db->table(self::TABLE)->eq('id', $subtask_id)->update(array('position' => $position)); + $this->db->table(self::TABLE)->eq('id', $positions[$position])->update(array('position' => $subtasks[$positions[$position]])); + $this->db->closeTransaction(); + + return true; + } + + return false; + } + + /** + * Move a subtask up, decrement the position value + * + * @access public + * @param integer $task_id + * @param integer $subtask_id + * @return boolean + */ + public function moveUp($task_id, $subtask_id) + { + $subtasks = $this->db->hashtable(self::TABLE)->eq('task_id', $task_id)->asc('position')->getAll('id', 'position'); + $positions = array_flip($subtasks); + + if (isset($subtasks[$subtask_id]) && $subtasks[$subtask_id] > 1) { + + $position = --$subtasks[$subtask_id]; + $subtasks[$positions[$position]]++; + + $this->db->startTransaction(); + $this->db->table(self::TABLE)->eq('id', $subtask_id)->update(array('position' => $position)); + $this->db->table(self::TABLE)->eq('id', $positions[$position])->update(array('position' => $subtasks[$positions[$position]])); + $this->db->closeTransaction(); + + return true; + } + + return false; + } + /** * Change the status of subtask * @@ -286,9 +362,9 @@ class Subtask extends Base return $this->db->transaction(function ($db) use ($src_task_id, $dst_task_id) { $subtasks = $db->table(Subtask::TABLE) - ->columns('title', 'time_estimated') + ->columns('title', 'time_estimated', 'position') ->eq('task_id', $src_task_id) - ->asc('id') // Explicit sorting for postgresql + ->asc('position') ->findAll(); foreach ($subtasks as &$subtask) { diff --git a/app/Schema/Mysql.php b/app/Schema/Mysql.php index 1c5cdc3a..21c304c1 100644 --- a/app/Schema/Mysql.php +++ b/app/Schema/Mysql.php @@ -6,7 +6,29 @@ use PDO; use Core\Security; use Model\Link; -const VERSION = 48; +const VERSION = 49; + +function version_49($pdo) +{ + $pdo->exec('ALTER TABLE subtasks ADD COLUMN position INTEGER DEFAULT 1'); + + $task_id = 0; + $urq = $pdo->prepare('UPDATE subtasks SET position=? WHERE id=?'); + + $rq = $pdo->prepare('SELECT * FROM subtasks ORDER BY task_id, id ASC'); + $rq->execute(); + + foreach ($rq->fetchAll(PDO::FETCH_ASSOC) as $subtask) { + + if ($task_id != $subtask['task_id']) { + $position = 1; + $task_id = $subtask['task_id']; + } + + $urq->execute(array($position, $subtask['id'])); + $position++; + } +} function version_48($pdo) { diff --git a/app/Schema/Postgres.php b/app/Schema/Postgres.php index aa3f60f7..df003267 100644 --- a/app/Schema/Postgres.php +++ b/app/Schema/Postgres.php @@ -6,7 +6,29 @@ use PDO; use Core\Security; use Model\Link; -const VERSION = 29; +const VERSION = 30; + +function version_30($pdo) +{ + $pdo->exec('ALTER TABLE subtasks ADD COLUMN position INTEGER DEFAULT 1'); + + $task_id = 0; + $urq = $pdo->prepare('UPDATE subtasks SET position=? WHERE id=?'); + + $rq = $pdo->prepare('SELECT * FROM subtasks ORDER BY task_id, id ASC'); + $rq->execute(); + + foreach ($rq->fetchAll(PDO::FETCH_ASSOC) as $subtask) { + + if ($task_id != $subtask['task_id']) { + $position = 1; + $task_id = $subtask['task_id']; + } + + $urq->execute(array($position, $subtask['id'])); + $position++; + } +} function version_29($pdo) { diff --git a/app/Schema/Sqlite.php b/app/Schema/Sqlite.php index 6fc2d07e..9134760f 100644 --- a/app/Schema/Sqlite.php +++ b/app/Schema/Sqlite.php @@ -6,7 +6,31 @@ use Core\Security; use PDO; use Model\Link; -const VERSION = 47; +const VERSION = 48; + +function version_48($pdo) +{ + $pdo->exec('ALTER TABLE subtasks ADD COLUMN position INTEGER DEFAULT 1'); + + // Migrate all subtasks position + + $task_id = 0; + $urq = $pdo->prepare('UPDATE subtasks SET position=? WHERE id=?'); + + $rq = $pdo->prepare('SELECT * FROM subtasks ORDER BY task_id, id ASC'); + $rq->execute(); + + foreach ($rq->fetchAll(PDO::FETCH_ASSOC) as $subtask) { + + if ($task_id != $subtask['task_id']) { + $position = 1; + $task_id = $subtask['task_id']; + } + + $urq->execute(array($position, $subtask['id'])); + $position++; + } +} function version_47($pdo) { diff --git a/app/Template/subtask/show.php b/app/Template/subtask/show.php index 1d55d1ee..c7ac652a 100644 --- a/app/Template/subtask/show.php +++ b/app/Template/subtask/show.php @@ -20,7 +20,7 @@ toggleSubtaskStatus($subtask, 'task') ?> - render('subtask/icons', array('subtask' => $subtask)) . $this->e($subtask['status_name']) ?> + render('subtask/icons', array('subtask' => $subtask)) . $this->e($subtask['title']) ?> @@ -40,6 +40,16 @@