Add a 'due date' field and display the number of comments on the board
This commit is contained in:
parent
1e994f3448
commit
544f992424
|
|
@ -210,6 +210,10 @@ textarea.form-error {
|
|||
margin-right: 15px;
|
||||
}
|
||||
|
||||
input.form-date {
|
||||
width: 150px;
|
||||
}
|
||||
|
||||
/* alerts */
|
||||
.alert {
|
||||
padding: 8px 35px 8px 14px;
|
||||
|
|
@ -462,6 +466,21 @@ nav .active a {
|
|||
font-style: italic;
|
||||
}
|
||||
|
||||
.task-date {
|
||||
font-weight: bold;
|
||||
color: #D90000;
|
||||
}
|
||||
|
||||
.task-comment-counter {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
right: 5px;
|
||||
}
|
||||
|
||||
.task-footer {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.task {
|
||||
border: 1px solid #000;
|
||||
padding: 5px;
|
||||
|
|
|
|||
|
|
@ -216,6 +216,10 @@ class Task extends Base
|
|||
if (! $task) $this->notfound();
|
||||
$this->checkProjectPermissions($task['project_id']);
|
||||
|
||||
if (! empty($task['date_due'])) {
|
||||
$task['date_due'] = date(t('m/d/Y'), $task['date_due']);
|
||||
}
|
||||
|
||||
$this->response->html($this->template->layout('task_edit', array(
|
||||
'errors' => array(),
|
||||
'values' => $task,
|
||||
|
|
|
|||
|
|
@ -151,7 +151,7 @@ return array(
|
|||
'Task opened successfully.' => 'Tâche ouverte avec succès.',
|
||||
'Unable to close this task.' => 'Impossible de fermer cette tâche.',
|
||||
'Task closed successfully.' => 'Tâche fermé avec succès.',
|
||||
'Unable to update your task.' => 'Impossible de fermer cette tâche.',
|
||||
'Unable to update your task.' => 'Impossible de modifier cette tâche.',
|
||||
'Task updated successfully.' => 'Tâche mise à jour avec succès.',
|
||||
'Unable to create your task.' => 'Impossible de créer cette tâche.',
|
||||
'Task created successfully.' => 'Tâche créée avec succès.',
|
||||
|
|
@ -212,4 +212,10 @@ return array(
|
|||
'Unable to create your comment.' => 'Impossible de sauvegarder votre commentaire.',
|
||||
'The description is required' => 'La description est obligatoire',
|
||||
'Edit this task' => 'Modifier cette tâche',
|
||||
'Due Date' => 'Date d\'échéance',
|
||||
'm/d/Y' => 'd/m/Y', // Date format parsed with php
|
||||
'month/day/year' => 'jour/mois/année', // Help shown to the user
|
||||
'Invalid date' => 'Date invalide',
|
||||
'Must be done before %B %e, %G' => 'Doit être fait avant le %e %B %G',
|
||||
'%B %e, %G' => '%e %B %G',
|
||||
);
|
||||
|
|
|
|||
|
|
@ -214,5 +214,11 @@ return array(
|
|||
'Comment added successfully.' => 'Komentarz dodany',
|
||||
'Unable to create your comment.' => 'Nie udało się dodać komentarza',
|
||||
'The description is required' => 'Opis jest wymagany',
|
||||
'Edit this task' => 'Edytuj zadanie'
|
||||
'Edit this task' => 'Edytuj zadanie',
|
||||
// 'Due Date' => '',
|
||||
// 'm/d/Y' => 'd/m/Y', // Date format parsed with php
|
||||
// 'month/day/year' => 'jour/mois/année', // Help shown to the user
|
||||
// 'Invalid date' => '',
|
||||
// 'Must be done before %B %e, %G' => '',
|
||||
// '%B %e, %G' => '%e %B %G',
|
||||
);
|
||||
|
|
|
|||
|
|
@ -12,13 +12,14 @@ require __DIR__.'/../vendor/SimpleValidator/Validators/Integer.php';
|
|||
require __DIR__.'/../vendor/SimpleValidator/Validators/Equals.php';
|
||||
require __DIR__.'/../vendor/SimpleValidator/Validators/AlphaNumeric.php';
|
||||
require __DIR__.'/../vendor/SimpleValidator/Validators/GreaterThan.php';
|
||||
require __DIR__.'/../vendor/SimpleValidator/Validators/Date.php';
|
||||
require __DIR__.'/../vendor/PicoDb/Database.php';
|
||||
require __DIR__.'/schema.php';
|
||||
|
||||
abstract class Base
|
||||
{
|
||||
const APP_VERSION = 'master';
|
||||
const DB_VERSION = 8;
|
||||
const DB_VERSION = 9;
|
||||
|
||||
private static $dbInstance = null;
|
||||
protected $db;
|
||||
|
|
@ -59,4 +60,19 @@ abstract class Base
|
|||
|
||||
return hash('crc32b', $token);
|
||||
}
|
||||
|
||||
public function getTimestampFromDate($value, $format)
|
||||
{
|
||||
$date = \DateTime::createFromFormat($format, $value);
|
||||
|
||||
if ($date !== false) {
|
||||
$errors = \DateTime::getLastErrors();
|
||||
if ($errors['error_count'] === 0 && $errors['warning_count'] === 0) {
|
||||
$timestamp = $date->getTimestamp();
|
||||
return $timestamp > 0 ? $timestamp : 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,6 +25,14 @@ class Comment extends Base
|
|||
->findAll();
|
||||
}
|
||||
|
||||
public function count($task_id)
|
||||
{
|
||||
return $this->db
|
||||
->table(self::TABLE)
|
||||
->eq(self::TABLE.'.task_id', $task_id)
|
||||
->count();
|
||||
}
|
||||
|
||||
public function create(array $values)
|
||||
{
|
||||
$values['date'] = time();
|
||||
|
|
|
|||
|
|
@ -2,6 +2,11 @@
|
|||
|
||||
namespace Schema;
|
||||
|
||||
function version_9($pdo)
|
||||
{
|
||||
$pdo->exec("ALTER TABLE tasks ADD COLUMN date_due INTEGER");
|
||||
}
|
||||
|
||||
function version_8($pdo)
|
||||
{
|
||||
$pdo->exec(
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ class Task extends Base
|
|||
self::TABLE.'.description',
|
||||
self::TABLE.'.date_creation',
|
||||
self::TABLE.'.date_completed',
|
||||
self::TABLE.'.date_due',
|
||||
self::TABLE.'.color_id',
|
||||
self::TABLE.'.project_id',
|
||||
self::TABLE.'.column_id',
|
||||
|
|
@ -66,6 +67,7 @@ class Task extends Base
|
|||
self::TABLE.'.description',
|
||||
self::TABLE.'.date_creation',
|
||||
self::TABLE.'.date_completed',
|
||||
self::TABLE.'.date_due',
|
||||
self::TABLE.'.color_id',
|
||||
self::TABLE.'.project_id',
|
||||
self::TABLE.'.column_id',
|
||||
|
|
@ -95,15 +97,23 @@ class Task extends Base
|
|||
|
||||
public function getAllByColumnId($project_id, $column_id, $status = array(1))
|
||||
{
|
||||
return $this->db
|
||||
$tasks = $this->db
|
||||
->table(self::TABLE)
|
||||
->columns('tasks.id', 'title', 'color_id', 'project_id', 'owner_id', 'column_id', 'position', 'score', 'users.username')
|
||||
->columns('tasks.id', 'title', 'color_id', 'project_id', 'owner_id', 'column_id', 'position', 'score', 'date_due', 'users.username')
|
||||
->join('users', 'id', 'owner_id')
|
||||
->eq('project_id', $project_id)
|
||||
->eq('column_id', $column_id)
|
||||
->in('is_active', $status)
|
||||
->asc('position')
|
||||
->findAll();
|
||||
|
||||
$commentModel = new Comment;
|
||||
|
||||
foreach ($tasks as &$task) {
|
||||
$task['nb_comments'] = $commentModel->count($task['id']);
|
||||
}
|
||||
|
||||
return $tasks;
|
||||
}
|
||||
|
||||
public function countByColumnId($project_id, $column_id, $status = array(1))
|
||||
|
|
@ -122,10 +132,17 @@ class Task extends Base
|
|||
|
||||
unset($values['another_task']);
|
||||
|
||||
if (! empty($values['date_due'])) {
|
||||
$values['date_due'] = $this->getTimestampFromDate($values['date_due'], t('m/d/Y')) ?: null;
|
||||
}
|
||||
|
||||
$values['date_creation'] = time();
|
||||
$values['position'] = $this->countByColumnId($values['project_id'], $values['column_id']);
|
||||
|
||||
$this->db->table(self::TABLE)->save($values);
|
||||
if (! $this->db->table(self::TABLE)->save($values)) {
|
||||
$this->db->cancelTransaction();
|
||||
return false;
|
||||
}
|
||||
|
||||
$task_id = $this->db->getConnection()->getLastId();
|
||||
|
||||
|
|
@ -136,9 +153,14 @@ class Task extends Base
|
|||
|
||||
public function update(array $values)
|
||||
{
|
||||
if (! empty($values['date_due'])) {
|
||||
$values['date_due'] = $this->getTimestampFromDate($values['date_due'], t('m/d/Y')) ?: null;
|
||||
}
|
||||
|
||||
return $this->db->table(self::TABLE)->eq('id', $values['id'])->update($values);
|
||||
}
|
||||
|
||||
// Mark a task closed
|
||||
public function close($task_id)
|
||||
{
|
||||
return $this->db->table(self::TABLE)
|
||||
|
|
@ -149,6 +171,7 @@ class Task extends Base
|
|||
));
|
||||
}
|
||||
|
||||
// Mark a task open
|
||||
public function open($task_id)
|
||||
{
|
||||
return $this->db->table(self::TABLE)
|
||||
|
|
@ -159,11 +182,13 @@ class Task extends Base
|
|||
));
|
||||
}
|
||||
|
||||
// Remove a task
|
||||
public function remove($task_id)
|
||||
{
|
||||
return $this->db->table(self::TABLE)->eq('id', $task_id)->remove();
|
||||
}
|
||||
|
||||
// Move a task to another column or to another position
|
||||
public function move($task_id, $column_id, $position)
|
||||
{
|
||||
return (bool) $this->db
|
||||
|
|
@ -184,6 +209,7 @@ class Task extends Base
|
|||
new Validators\Integer('score', t('This value must be an integer')),
|
||||
new Validators\Required('title', t('The title is required')),
|
||||
new Validators\MaxLength('title', t('The maximum length is %d characters', 200), 200),
|
||||
new Validators\Date('date_due', t('Invalid date'), t('m/d/Y')),
|
||||
));
|
||||
|
||||
return array(
|
||||
|
|
@ -220,6 +246,7 @@ class Task extends Base
|
|||
new Validators\Integer('score', t('This value must be an integer')),
|
||||
new Validators\Required('title', t('The title is required')),
|
||||
new Validators\MaxLength('title', t('The maximum length is %d characters', 200), 200),
|
||||
new Validators\Date('date_due', t('Invalid date'), t('m/d/Y')),
|
||||
));
|
||||
|
||||
return array(
|
||||
|
|
|
|||
|
|
@ -74,6 +74,19 @@
|
|||
<?= Helper\escape($task['title']) ?>
|
||||
</div>
|
||||
|
||||
<div class="task-footer">
|
||||
<?php if (! empty($task['date_due'])): ?>
|
||||
<div class="task-date">
|
||||
<?= dt('%B %e, %G', $task['date_due']) ?>
|
||||
</div>
|
||||
<?php endif ?>
|
||||
|
||||
<?php if (! empty($task['nb_comments'])): ?>
|
||||
<div class="task-comment-counter">
|
||||
<?= $task['nb_comments'] ?>
|
||||
</div>
|
||||
<?php endif ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach ?>
|
||||
|
|
|
|||
|
|
@ -40,6 +40,20 @@
|
|||
<?= Helper\escape($task['title']) ?>
|
||||
</div>
|
||||
|
||||
<div class="task-footer">
|
||||
<?php if (! empty($task['date_due'])): ?>
|
||||
<div class="task-date">
|
||||
<?= dt('%B %e, %G', $task['date_due']) ?>
|
||||
</div>
|
||||
<?php endif ?>
|
||||
|
||||
<?php if (! empty($task['nb_comments'])): ?>
|
||||
<div class="task-comment-counter">
|
||||
<?= $task['nb_comments'] ?>
|
||||
</div>
|
||||
<?php endif ?>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach ?>
|
||||
|
|
|
|||
|
|
@ -23,6 +23,9 @@
|
|||
<?= Helper\form_label(t('Story Points'), 'score') ?>
|
||||
<?= Helper\form_number('score', $values, $errors) ?><br/>
|
||||
|
||||
<?= Helper\form_label(t('Due Date'), 'date_due') ?>
|
||||
<?= Helper\form_text('date_due', $values, $errors, array('placeholder="'.t('month/day/year').'"'), 'form-date') ?><br/>
|
||||
|
||||
<?= Helper\form_label(t('Description'), 'description') ?>
|
||||
<?= Helper\form_textarea('description', $values, $errors) ?><br/>
|
||||
<div class="form-help"><a href="http://en.wikipedia.org/wiki/Markdown#Example" target="_blank"><?= t('Write your text in Markdown') ?></a></div>
|
||||
|
|
|
|||
|
|
@ -23,6 +23,9 @@
|
|||
<?= Helper\form_label(t('Story Points'), 'score') ?>
|
||||
<?= Helper\form_number('score', $values, $errors) ?><br/>
|
||||
|
||||
<?= Helper\form_label(t('Due Date'), 'date_due') ?>
|
||||
<?= Helper\form_text('date_due', $values, $errors, array('placeholder="'.t('month/day/year').'"'), 'form-date') ?><br/>
|
||||
|
||||
<?= Helper\form_label(t('Description'), 'description') ?>
|
||||
<?= Helper\form_textarea('description', $values, $errors) ?><br/>
|
||||
|
||||
|
|
|
|||
|
|
@ -20,6 +20,11 @@
|
|||
<?= dt('Completed on %B %e, %G at %k:%M %p', $task['date_completed']) ?>
|
||||
</li>
|
||||
<?php endif ?>
|
||||
<?php if ($task['date_due']): ?>
|
||||
<li>
|
||||
<strong><?= dt('Must be done before %B %e, %G', $task['date_due']) ?></strong>
|
||||
</li>
|
||||
<?php endif ?>
|
||||
<li>
|
||||
<strong>
|
||||
<?php if ($task['username']): ?>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
|
||||
require_once __DIR__.'/../models/base.php';
|
||||
require_once __DIR__.'/../models/task.php';
|
||||
|
||||
use Model\Task;
|
||||
|
||||
class TaskTest extends PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function setUp()
|
||||
{
|
||||
defined('DB_FILENAME') or define('DB_FILENAME', ':memory:');
|
||||
}
|
||||
|
||||
public function testDateFormat()
|
||||
{
|
||||
$t = new Task;
|
||||
|
||||
$this->assertEquals('2014-03-05', date('Y-m-d', $t->getTimestampFromDate('05/03/2014', 'd/m/Y')));
|
||||
$this->assertEquals('2014-03-05', date('Y-m-d', $t->getTimestampFromDate('03/05/2014', 'm/d/Y')));
|
||||
$this->assertEquals('2014-03-05', date('Y-m-d', $t->getTimestampFromDate('3/5/2014', 'm/d/Y')));
|
||||
$this->assertEquals('2014-03-05', date('Y-m-d', $t->getTimestampFromDate('5/3/2014', 'd/m/Y')));
|
||||
$this->assertEquals('2014-03-05', date('Y-m-d', $t->getTimestampFromDate('5/3/14', 'd/m/y')));
|
||||
$this->assertEquals(0, $t->getTimestampFromDate('5/3/14', 'd/m/Y'));
|
||||
$this->assertEquals(0, $t->getTimestampFromDate('5-3-2014', 'd/m/Y'));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
|
||||
namespace SimpleValidator\Validators;
|
||||
|
||||
use SimpleValidator\Base;
|
||||
|
||||
class Date extends Base
|
||||
{
|
||||
private $format;
|
||||
|
||||
public function __construct($field, $error_message, $format)
|
||||
{
|
||||
parent::__construct($field, $error_message);
|
||||
$this->format = $format;
|
||||
}
|
||||
|
||||
public function execute(array $data)
|
||||
{
|
||||
if (isset($data[$this->field]) && $data[$this->field] !== '') {
|
||||
|
||||
$date = \DateTime::createFromFormat($this->format, $data[$this->field]);
|
||||
|
||||
if ($date !== false) {
|
||||
$errors = \DateTime::getLastErrors();
|
||||
return $errors['error_count'] === 0 && $errors['warning_count'] === 0;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue