diff options
-rw-r--r-- | ChangeLog | 1 | ||||
-rw-r--r-- | app/Export/TaskExport.php | 129 | ||||
-rw-r--r-- | tests/units/Export/TaskExportTest.php | 104 |
3 files changed, 135 insertions, 99 deletions
@@ -13,6 +13,7 @@ New features: Improvements: * Introduce Vue.js to manage user interface components +* Add column "Reference" and "Creator Name" in CSV task export * Show both time spent and estimated on the board * Store board collapsed mode user preference in the database * Store comment sorting direction in the database diff --git a/app/Export/TaskExport.php b/app/Export/TaskExport.php index 975c7dcd..e708f0e3 100644 --- a/app/Export/TaskExport.php +++ b/app/Export/TaskExport.php @@ -3,9 +3,12 @@ namespace Kanboard\Export; use Kanboard\Core\Base; -use Kanboard\Core\DateParser; +use Kanboard\Model\CategoryModel; +use Kanboard\Model\ColumnModel; +use Kanboard\Model\ProjectModel; +use Kanboard\Model\SwimlaneModel; use Kanboard\Model\TaskModel; -use PDO; +use Kanboard\Model\UserModel; /** * Task Export @@ -19,19 +22,21 @@ class TaskExport extends Base * Fetch tasks and return the prepared CSV * * @access public - * @param integer $project_id Project id - * @param mixed $from Start date (timestamp or user formatted date) - * @param mixed $to End date (timestamp or user formatted date) + * @param integer $project_id Project id + * @param mixed $from Start date (timestamp or user formatted date) + * @param mixed $to End date (timestamp or user formatted date) * @return array */ public function export($project_id, $from, $to) { $tasks = $this->getTasks($project_id, $from, $to); - $swimlanes = $this->swimlaneModel->getList($project_id); + $colors = $this->colorModel->getList(); + $defaultSwimlane = $this->swimlaneModel->getDefault($project_id); $results = array($this->getColumns()); foreach ($tasks as &$task) { - $results[] = array_values($this->format($task, $swimlanes)); + $task = $this->format($task, $defaultSwimlane['default_swimlane'], $colors); + $results[] = array_values($task); } return $results; @@ -40,77 +45,80 @@ class TaskExport extends Base /** * Get the list of tasks for a given project and date range * - * @access public - * @param integer $project_id Project id - * @param mixed $from Start date (timestamp or user formatted date) - * @param mixed $to End date (timestamp or user formatted date) + * @access protected + * @param integer $project_id Project id + * @param mixed $from Start date (timestamp or user formatted date) + * @param mixed $to End date (timestamp or user formatted date) * @return array */ - public function getTasks($project_id, $from, $to) + protected function getTasks($project_id, $from, $to) { - $sql = ' - SELECT - tasks.id, - projects.name AS project_name, - tasks.is_active, - project_has_categories.name AS category_name, - tasks.swimlane_id, - columns.title AS column_title, - tasks.position, - tasks.color_id, - tasks.date_due, - creators.username AS creator_username, - users.username AS assignee_username, - users.name AS assignee_name, - tasks.score, - tasks.title, - tasks.date_creation, - tasks.date_modification, - tasks.date_completed, - tasks.date_started, - tasks.time_estimated, - tasks.time_spent, - tasks.reference - FROM tasks - LEFT JOIN users ON users.id = tasks.owner_id - LEFT JOIN users AS creators ON creators.id = tasks.creator_id - LEFT JOIN project_has_categories ON project_has_categories.id = tasks.category_id - LEFT JOIN columns ON columns.id = tasks.column_id - LEFT JOIN projects ON projects.id = tasks.project_id - WHERE tasks.date_creation >= ? AND tasks.date_creation <= ? AND tasks.project_id = ? - ORDER BY tasks.id ASC - '; - - if (! is_numeric($from)) { + if (!is_numeric($from)) { $from = $this->dateParser->removeTimeFromTimestamp($this->dateParser->getTimestamp($from)); } - if (! is_numeric($to)) { + if (!is_numeric($to)) { $to = $this->dateParser->removeTimeFromTimestamp(strtotime('+1 day', $this->dateParser->getTimestamp($to))); } - $rq = $this->db->execute($sql, array($from, $to, $project_id)); - return $rq->fetchAll(PDO::FETCH_ASSOC); + return $this->db->table(TaskModel::TABLE) + ->columns( + TaskModel::TABLE . '.id', + TaskModel::TABLE . '.reference', + ProjectModel::TABLE . '.name AS project_name', + TaskModel::TABLE . '.is_active', + CategoryModel::TABLE . '.name AS category_name', + SwimlaneModel::TABLE . '.name AS swimlane_name', + ColumnModel::TABLE . '.title AS column_title', + TaskModel::TABLE . '.position', + TaskModel::TABLE . '.color_id', + TaskModel::TABLE . '.date_due', + 'uc.username AS creator_username', + 'uc.name AS creator_name', + UserModel::TABLE . '.username AS assignee_username', + UserModel::TABLE . '.name AS assignee_name', + TaskModel::TABLE . '.score', + TaskModel::TABLE . '.title', + TaskModel::TABLE . '.date_creation', + TaskModel::TABLE . '.date_modification', + TaskModel::TABLE . '.date_completed', + TaskModel::TABLE . '.date_started', + TaskModel::TABLE . '.time_estimated', + TaskModel::TABLE . '.time_spent' + ) + ->join(UserModel::TABLE, 'id', 'owner_id', TaskModel::TABLE) + ->left(UserModel::TABLE, 'uc', 'id', TaskModel::TABLE, 'creator_id') + ->join(CategoryModel::TABLE, 'id', 'category_id', TaskModel::TABLE) + ->join(ColumnModel::TABLE, 'id', 'column_id', TaskModel::TABLE) + ->join(SwimlaneModel::TABLE, 'id', 'swimlane_id', TaskModel::TABLE) + ->join(ProjectModel::TABLE, 'id', 'project_id', TaskModel::TABLE) + ->gte(TaskModel::TABLE . '.date_creation', $from) + ->lte(TaskModel::TABLE . '.date_creation', $to) + ->eq(TaskModel::TABLE . '.project_id', $project_id) + ->findAll(); } /** * Format the output of a task array * - * @access public - * @param array $task Task properties - * @param array $swimlanes List of swimlanes + * @access protected + * @param array $task + * @param string $defaultSwimlaneName + * @param array $colors * @return array */ - public function format(array &$task, array &$swimlanes) + protected function format(array &$task, $defaultSwimlaneName, array $colors) { - $colors = $this->colorModel->getList(); - $task['is_active'] = $task['is_active'] == TaskModel::STATUS_OPEN ? e('Open') : e('Closed'); $task['color_id'] = $colors[$task['color_id']]; $task['score'] = $task['score'] ?: 0; - $task['swimlane_id'] = isset($swimlanes[$task['swimlane_id']]) ? $swimlanes[$task['swimlane_id']] : '?'; + $task['swimlane_name'] = $task['swimlane_name'] ?: $defaultSwimlaneName; - $task = $this->dateParser->format($task, array('date_due', 'date_modification', 'date_creation', 'date_started', 'date_completed'), DateParser::DATE_FORMAT); + $task = $this->dateParser->format( + $task, + array('date_due', 'date_modification', 'date_creation', 'date_started', 'date_completed'), + $this->dateParser->getUserDateTimeFormat() + ); return $task; } @@ -118,13 +126,14 @@ class TaskExport extends Base /** * Get column titles * - * @access public + * @access protected * @return string[] */ - public function getColumns() + protected function getColumns() { return array( e('Task Id'), + e('Reference'), e('Project'), e('Status'), e('Category'), @@ -134,6 +143,7 @@ class TaskExport extends Base e('Color'), e('Due date'), e('Creator'), + e('Creator Name'), e('Assignee Username'), e('Assignee Name'), e('Complexity'), @@ -144,7 +154,6 @@ class TaskExport extends Base e('Start date'), e('Time estimated'), e('Time spent'), - e('Reference'), ); } } diff --git a/tests/units/Export/TaskExportTest.php b/tests/units/Export/TaskExportTest.php index c142cde9..ae6ca308 100644 --- a/tests/units/Export/TaskExportTest.php +++ b/tests/units/Export/TaskExportTest.php @@ -12,44 +12,70 @@ class TaskExportTest extends Base { public function testExport() { - $tc = new TaskCreationModel($this->container); - $p = new ProjectModel($this->container); - $c = new CategoryModel($this->container); - $e = new TaskExport($this->container); - $s = new SwimlaneModel($this->container); - - $this->assertEquals(1, $p->create(array('name' => 'Export Project'))); - - $this->assertEquals(1, $s->create(array('project_id' => 1, 'name' => 'S1'))); - $this->assertEquals(2, $s->create(array('project_id' => 1, 'name' => 'S2'))); - - $this->assertNotFalse($c->create(array('name' => 'Category #1', 'project_id' => 1))); - $this->assertNotFalse($c->create(array('name' => 'Category #2', 'project_id' => 1))); - $this->assertNotFalse($c->create(array('name' => 'Category #3', 'project_id' => 1))); - - for ($i = 1; $i <= 100; $i++) { - $task = array( - 'title' => 'Task #'.$i, - 'project_id' => 1, - 'column_id' => rand(1, 3), - 'creator_id' => rand(0, 1), - 'owner_id' => rand(0, 1), - 'color_id' => rand(0, 1) === 0 ? 'green' : 'purple', - 'category_id' => rand(0, 3), - 'date_due' => array_rand(array(0, date('Y-m-d'), date('Y-m-d', strtotime('+'.$i.'day')))), - 'score' => rand(0, 21), - 'swimlane_id' => rand(0, 2), - ); - - $this->assertEquals($i, $tc->create($task)); - } - - $rows = $e->export(1, strtotime('-1 day'), strtotime('+1 day')); - - $this->assertEquals($i, count($rows)); - $this->assertEquals('Task Id', $rows[0][0]); - $this->assertEquals(1, $rows[1][0]); - $this->assertEquals('Task #'.($i - 1), $rows[$i - 1][13]); - $this->assertTrue(in_array($rows[$i - 1][4], array('Default swimlane', 'S1', 'S2'))); + $taskCreationModel = new TaskCreationModel($this->container); + $projectModel = new ProjectModel($this->container); + $categoryModel = new CategoryModel($this->container); + $taskExport = new TaskExport($this->container); + $swimlaneModel = new SwimlaneModel($this->container); + + $this->assertEquals(1, $projectModel->create(array('name' => 'Export Project'))); + $this->assertEquals(1, $swimlaneModel->create(array('project_id' => 1, 'name' => 'S1'))); + $this->assertEquals(1, $categoryModel->create(array('name' => 'Category #1', 'project_id' => 1))); + + $this->assertEquals(1, $taskCreationModel->create(array( + 'project_id' => 1, + 'column_id' => 2, + 'category_id' => 1, + 'reference' => 'REF1', + 'title' => 'Task 1', + 'time_estimated' => 2.5, + 'time_spent' => 3, + ))); + + $this->assertEquals(2, $taskCreationModel->create(array( + 'project_id' => 1, + 'swimlane_id' => 1, + 'title' => 'Task 2', + 'date_due' => time(), + ))); + + $report = $taskExport->export(1, date('Y-m-d'), date('Y-m-d')); + + $this->assertCount(3, $report); + $this->assertCount(22, $report[0]); + $this->assertEquals('Task Id', $report[0][0]); + + $this->assertEquals(1, $report[1][0]); + $this->assertEquals(2, $report[2][0]); + + $this->assertEquals('REF1', $report[1][1]); + $this->assertEquals('', $report[2][1]); + + $this->assertEquals('Export Project', $report[1][2]); + $this->assertEquals('Export Project', $report[2][2]); + + $this->assertEquals('Open', $report[1][3]); + $this->assertEquals('Open', $report[2][3]); + + $this->assertEquals('Category #1', $report[1][4]); + $this->assertEquals('', $report[2][4]); + + $this->assertEquals('Default swimlane', $report[1][5]); + $this->assertEquals('S1', $report[2][5]); + + $this->assertEquals('Ready', $report[1][6]); + $this->assertEquals('Backlog', $report[2][6]); + + $this->assertEquals('Yellow', $report[1][8]); + $this->assertEquals('Yellow', $report[2][8]); + + $this->assertEquals('', $report[1][9]); + $this->assertEquals(date('m/d/Y').' 00:00', $report[2][9]); + + $this->assertEquals(3, $report[1][21]); + $this->assertEquals(0, $report[2][21]); + + $this->assertEquals(2.5, $report[1][20]); + $this->assertEquals(0, $report[2][20]); } } |