Add formatters

This commit is contained in:
Frederic Guillot 2015-09-20 22:18:56 -04:00
parent f579663adc
commit 689687dd4e
20 changed files with 651 additions and 377 deletions

View File

@ -213,7 +213,7 @@ class App extends Base
{
$search = $this->request->getStringParam('term');
$filter = $this->taskFilter
$filter = $this->taskFilterAutoCompleteFormatter
->create()
->filterByProjects($this->projectPermission->getActiveMemberProjectIds($this->userSession->getId()))
->excludeTasks(array($this->request->getIntegerParam('exclude_task_id')));
@ -226,6 +226,6 @@ class App extends Base
$filter->filterByTitle($search);
}
$this->response->json($filter->toAutoCompletion());
$this->response->json($filter->format());
}
}

View File

@ -37,20 +37,20 @@ class Calendar extends Base
$end = $this->request->getStringParam('end');
// Common filter
$filter = $this->taskFilter
$filter = $this->taskFilterCalendarFormatter
->search($this->userSession->getFilters($project_id))
->filterByProject($project_id);
// Tasks
if ($this->config->get('calendar_project_tasks', 'date_started') === 'date_creation') {
$events = $filter->copy()->filterByCreationDateRange($start, $end)->toDateTimeCalendarEvents('date_creation', 'date_completed');
$events = $filter->copy()->filterByCreationDateRange($start, $end)->setColumns('date_creation', 'date_completed')->format();
}
else {
$events = $filter->copy()->filterByStartDateRange($start, $end)->toDateTimeCalendarEvents('date_started', 'date_completed');
$events = $filter->copy()->filterByStartDateRange($start, $end)->setColumns('date_started', 'date_completed')->format();
}
// Tasks with due date
$events = array_merge($events, $filter->copy()->filterByDueDateRange($start, $end)->toAllDayCalendarEvents());
$events = array_merge($events, $filter->copy()->filterByDueDateRange($start, $end)->setColumns('date_due')->setFullDay()->format());
$events = $this->hook->merge('controller:calendar:project:events', $events, array(
'project_id' => $project_id,
@ -71,17 +71,17 @@ class Calendar extends Base
$user_id = $this->request->getIntegerParam('user_id');
$start = $this->request->getStringParam('start');
$end = $this->request->getStringParam('end');
$filter = $this->taskFilter->create()->filterByOwner($user_id)->filterByStatus(TaskModel::STATUS_OPEN);
$filter = $this->taskFilterCalendarFormatter->create()->filterByOwner($user_id)->filterByStatus(TaskModel::STATUS_OPEN);
// Task with due date
$events = $filter->copy()->filterByDueDateRange($start, $end)->toAllDayCalendarEvents();
$events = $filter->copy()->filterByDueDateRange($start, $end)->setColumns('date_due')->setFullDay()->format();
// Tasks
if ($this->config->get('calendar_user_tasks', 'date_started') === 'date_creation') {
$events = array_merge($events, $filter->copy()->filterByCreationDateRange($start, $end)->toDateTimeCalendarEvents('date_creation', 'date_completed'));
$events = array_merge($events, $filter->copy()->filterByCreationDateRange($start, $end)->setColumns('date_creation', 'date_completed')->format());
}
else {
$events = array_merge($events, $filter->copy()->filterByStartDateRange($start, $end)->toDateTimeCalendarEvents('date_started', 'date_completed'));
$events = array_merge($events, $filter->copy()->filterByStartDateRange($start, $end)->setColumns('date_started', 'date_completed')->format());
}
// Subtasks time tracking

View File

@ -25,7 +25,7 @@ class Gantt extends Base
}
$this->response->html($this->template->layout('gantt/projects', array(
'projects' => $this->project->getGanttBars($project_ids),
'projects' => $this->projectGanttFormatter->filter($project_ids)->format(),
'title' => t('Gantt chart for all projects'),
'board_selector' => $this->projectPermission->getAllowedProjects($this->userSession->getId()),
)));
@ -57,7 +57,7 @@ class Gantt extends Base
public function project()
{
$params = $this->getProjectFilters('gantt', 'project');
$filter = $this->taskFilter->search($params['filters']['search'])->filterByProject($params['project']['id']);
$filter = $this->taskFilterGanttFormatter->search($params['filters']['search'])->filterByProject($params['project']['id']);
$sorting = $this->request->getStringParam('sorting', 'board');
if ($sorting === 'date') {
@ -70,7 +70,7 @@ class Gantt extends Base
$this->response->html($this->template->layout('gantt/project', $params + array(
'users_list' => $this->projectPermission->getMemberList($params['project']['id'], false),
'sorting' => $sorting,
'tasks' => $filter->toGanttBars(),
'tasks' => $filter->format(),
)));
}

View File

@ -29,7 +29,7 @@ class Ical extends Base
}
// Common filter
$filter = $this->taskFilter
$filter = $this->taskFilterICalendarFormatter
->create()
->filterByOwner($user['id']);
@ -58,7 +58,7 @@ class Ical extends Base
}
// Common filter
$filter = $this->taskFilter
$filter = $this->taskFilterICalendarFormatter
->create()
->filterByProject($project['id']);
@ -83,16 +83,31 @@ class Ical extends Base
// Tasks
if ($this->config->get('calendar_project_tasks', 'date_started') === 'date_creation') {
$filter->copy()->filterByCreationDateRange($start, $end)->addDateTimeIcalEvents('date_creation', 'date_completed', $calendar);
$filter
->copy()
->filterByCreationDateRange($start, $end)
->setColumns('date_creation', 'date_completed')
->setCalendar($calendar)
->addDateTimeEvents();
}
else {
$filter->copy()->filterByStartDateRange($start, $end)->addDateTimeIcalEvents('date_started', 'date_completed', $calendar);
$filter
->copy()
->filterByStartDateRange($start, $end)
->setColumns('date_started', 'date_completed')
->setCalendar($calendar)
->addDateTimeEvents($calendar);
}
// Tasks with due date
$filter->copy()->filterByDueDateRange($start, $end)->addAllDayIcalEvents('date_due', $calendar);
$filter
->copy()
->filterByDueDateRange($start, $end)
->setColumns('date_due')
->setCalendar($calendar)
->addFullDayEvents($calendar);
$this->response->contentType('text/calendar; charset=utf-8');
echo $calendar->render();
echo $filter->setCalendar($calendar)->format();
}
}

View File

@ -0,0 +1,14 @@
<?php
namespace Formatter;
/**
* Formatter Interface
*
* @package formatter
* @author Frederic Guillot
*/
interface FormatterInterface
{
public function format();
}

View File

@ -0,0 +1,90 @@
<?php
namespace Formatter;
use Model\Project;
/**
* Gantt chart formatter for projects
*
* @package formatter
* @author Frederic Guillot
*/
class ProjectGanttFormatter extends Project implements FormatterInterface
{
/**
* List of projects
*
* @access private
* @var array
*/
private $projects = array();
/**
* Filter projects to generate the Gantt chart
*
* @access public
* @param int[] $project_ids
* @return ProjectGanttFormatter
*/
public function filter(array $project_ids)
{
if (empty($project_ids)) {
$this->projects = array();
}
else {
$this->projects = $this->db
->table(self::TABLE)
->asc('start_date')
->in('id', $project_ids)
->eq('is_active', self::ACTIVE)
->eq('is_private', 0)
->findAll();
}
return $this;
}
/**
* Format projects to be displayed in the Gantt chart
*
* @access public
* @return array
*/
public function format()
{
$colors = $this->color->getDefaultColors();
$bars = array();
foreach ($this->projects as $project) {
$start = empty($project['start_date']) ? time() : strtotime($project['start_date']);
$end = empty($project['end_date']) ? $start : strtotime($project['end_date']);
$color = next($colors) ?: reset($colors);
$bars[] = array(
'type' => 'project',
'id' => $project['id'],
'title' => $project['name'],
'start' => array(
(int) date('Y', $start),
(int) date('n', $start),
(int) date('j', $start),
),
'end' => array(
(int) date('Y', $end),
(int) date('n', $end),
(int) date('j', $end),
),
'link' => $this->helper->url->href('project', 'show', array('project_id' => $project['id'])),
'board_link' => $this->helper->url->href('board', 'show', array('project_id' => $project['id'])),
'gantt_link' => $this->helper->url->href('gantt', 'project', array('project_id' => $project['id'])),
'color' => $color,
'not_defined' => empty($project['start_date']) || empty($project['end_date']),
'users' => $this->projectPermission->getProjectUsers($project['id']),
);
}
return $bars;
}
}

View File

@ -0,0 +1,33 @@
<?php
namespace Formatter;
use Model\Task;
use Model\TaskFilter;
/**
* Autocomplete formatter for task filter
*
* @package formatter
* @author Frederic Guillot
*/
class TaskFilterAutoCompleteFormatter extends TaskFilter implements FormatterInterface
{
/**
* Format the tasks for the ajax autocompletion
*
* @access public
* @return array
*/
public function format()
{
$tasks = $this->query->columns(Task::TABLE.'.id', Task::TABLE.'.title')->findAll();
foreach ($tasks as &$task) {
$task['value'] = $task['title'];
$task['label'] = '#'.$task['id'].' - '.$task['title'];
}
return $tasks;
}
}

View File

@ -0,0 +1,76 @@
<?php
namespace Formatter;
use Model\TaskFilter;
/**
* Common class to handle calendar events
*
* @package formatter
* @author Frederic Guillot
*/
abstract class TaskFilterCalendarEvent extends TaskFilter
{
/**
* Column used for event start date
*
* @access protected
* @var string
*/
protected $startColumn = 'date_started';
/**
* Column used for event end date
*
* @access protected
* @var string
*/
protected $endColumn = 'date_completed';
/**
* Full day event flag
*
* @access private
* @var boolean
*/
private $fullDay = false;
/**
* Transform results to calendar events
*
* @access public
* @param string $start_column Column name for the start date
* @param string $end_column Column name for the end date
* @return TaskFilterCalendarEvent
*/
public function setColumns($start_column, $end_column = '')
{
$this->startColumn = $start_column;
$this->endColumn = $end_column ?: $start_column;
return $this;
}
/**
* When called calendar events will be full day
*
* @access public
* @return TaskFilterCalendarEvent
*/
public function setFullDay()
{
$this->fullDay = true;
return $this;
}
/**
* Return true if the events are full day
*
* @access public
* @return boolean
*/
public function isFullDay()
{
return $this->fullDay;
}
}

View File

@ -0,0 +1,52 @@
<?php
namespace Formatter;
/**
* Calendar event formatter for task filter
*
* @package formatter
* @author Frederic Guillot
*/
class TaskFilterCalendarFormatter extends TaskFilterCalendarEvent implements FormatterInterface
{
/**
* Transform tasks to calendar events
*
* @access public
* @return array
*/
public function format()
{
$events = array();
foreach ($this->query->findAll() as $task) {
$events[] = array(
'timezoneParam' => $this->config->getCurrentTimezone(),
'id' => $task['id'],
'title' => t('#%d', $task['id']).' '.$task['title'],
'backgroundColor' => $this->color->getBackgroundColor($task['color_id']),
'borderColor' => $this->color->getBorderColor($task['color_id']),
'textColor' => 'black',
'url' => $this->helper->url->to('task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])),
'start' => date($this->getDateTimeFormat(), $task[$this->startColumn]),
'end' => date($this->getDateTimeFormat(), $task[$this->endColumn] ?: time()),
'editable' => $this->isFullDay(),
'allday' => $this->isFullDay(),
);
}
return $events;
}
/**
* Get DateTime format for event
*
* @access private
* @return string
*/
private function getDateTimeFormat()
{
return $this->isFullDay() ? 'Y-m-d' : 'Y-m-d\TH:i:s';
}
}

View File

@ -0,0 +1,78 @@
<?php
namespace Formatter;
use Model\TaskFilter;
/**
* Gantt chart formatter for task filter
*
* @package formatter
* @author Frederic Guillot
*/
class TaskFilterGanttFormatter extends TaskFilter implements FormatterInterface
{
/**
* Local cache for project columns
*
* @access private
* @var array
*/
private $columns = array();
/**
* Format tasks to be displayed in the Gantt chart
*
* @access public
* @return array
*/
public function format()
{
$bars = array();
foreach ($this->query->findAll() as $task) {
$bars[] = $this->formatTask($task);
}
return $bars;
}
/**
* Format a single task
*
* @access private
* @param array $task
* @return array
*/
private function formatTask(array $task)
{
if (! isset($this->columns[$task['project_id']])) {
$this->columns[$task['project_id']] = $this->board->getColumnsList($task['project_id']);
}
$start = $task['date_started'] ?: time();
$end = $task['date_due'] ?: $start;
return array(
'type' => 'task',
'id' => $task['id'],
'title' => $task['title'],
'start' => array(
(int) date('Y', $start),
(int) date('n', $start),
(int) date('j', $start),
),
'end' => array(
(int) date('Y', $end),
(int) date('n', $end),
(int) date('j', $end),
),
'column_title' => $task['column_name'],
'assignee' => $task['assignee_name'] ?: $task['assignee_username'],
'progress' => $this->task->getProgress($task, $this->columns[$task['project_id']]).'%',
'link' => $this->helper->url->href('task', 'show', array('project_id' => $task['project_id'], 'task_id' => $task['id'])),
'color' => $this->color->getColorProperties($task['color_id']),
'not_defined' => empty($task['date_due']) || empty($task['date_started']),
);
}
}

View File

@ -0,0 +1,135 @@
<?php
namespace Formatter;
use DateTime;
use Eluceo\iCal\Component\Calendar;
use Eluceo\iCal\Component\Event;
use Eluceo\iCal\Property\Event\Attendees;
/**
* iCal event formatter for task filter
*
* @package formatter
* @author Frederic Guillot
*/
class TaskFilterICalendarFormatter extends TaskFilterCalendarEvent implements FormatterInterface
{
/**
* Calendar object
*
* @access private
* @var \Eluceo\iCal\Component\Calendar
*/
private $vCalendar;
/**
* Get Ical events
*
* @access public
* @return string
*/
public function format()
{
return $this->vCalendar->render();
}
/**
* Set calendar object
*
* @access public
* @param \Eluceo\iCal\Component\Calendar $vCalendar
* @return TaskFilterICalendarFormatter
*/
public function setCalendar(Calendar $vCalendar)
{
$this->vCalendar = $vCalendar;
return $this;
}
/**
* Transform results to ical events
*
* @access public
* @return TaskFilterICalendarFormatter
*/
public function addDateTimeEvents()
{
foreach ($this->query->findAll() as $task) {
$start = new DateTime;
$start->setTimestamp($task[$this->startColumn]);
$end = new DateTime;
$end->setTimestamp($task[$this->endColumn] ?: time());
$vEvent = $this->getTaskIcalEvent($task, 'task-#'.$task['id'].'-'.$this->startColumn.'-'.$this->endColumn);
$vEvent->setDtStart($start);
$vEvent->setDtEnd($end);
$this->vCalendar->addComponent($vEvent);
}
return $this;
}
/**
* Transform results to all day ical events
*
* @access public
* @return TaskFilterICalendarFormatter
*/
public function addFullDayEvents()
{
foreach ($this->query->findAll() as $task) {
$date = new DateTime;
$date->setTimestamp($task[$this->startColumn]);
$vEvent = $this->getTaskIcalEvent($task, 'task-#'.$task['id'].'-'.$this->startColumn);
$vEvent->setDtStart($date);
$vEvent->setDtEnd($date);
$vEvent->setNoTime(true);
$this->vCalendar->addComponent($vEvent);
}
return $this;
}
/**
* Get common events for task ical events
*
* @access protected
* @param array $task
* @param string $uid
* @return Event
*/
protected function getTaskIcalEvent(array &$task, $uid)
{
$dateCreation = new DateTime;
$dateCreation->setTimestamp($task['date_creation']);
$dateModif = new DateTime;
$dateModif->setTimestamp($task['date_modification']);
$vEvent = new Event($uid);
$vEvent->setCreated($dateCreation);
$vEvent->setModified($dateModif);
$vEvent->setUseTimezone(true);
$vEvent->setSummary(t('#%d', $task['id']).' '.$task['title']);
$vEvent->setUrl($this->helper->url->base().$this->helper->url->to('task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])));
if (! empty($task['owner_id'])) {
$vEvent->setOrganizer($task['assignee_name'] ?: $task['assignee_username'], $task['assignee_email']);
}
if (! empty($task['creator_id'])) {
$attendees = new Attendees;
$attendees->add('MAILTO:'.($task['creator_email'] ?: $task['creator_username'].'@kanboard.local'));
$vEvent->setAttendees($attendees);
}
return $vEvent;
}
}

View File

@ -120,26 +120,6 @@ abstract class Base extends \Core\Base
return $start_column.' IS NOT NULL AND '.$start_column.' > 0 AND ('.implode(' OR ', $conditions).')';
}
/**
* Get common properties for task calendar events
*
* @access protected
* @param array $task
* @return array
*/
protected function getTaskCalendarProperties(array &$task)
{
return array(
'timezoneParam' => $this->config->getCurrentTimezone(),
'id' => $task['id'],
'title' => t('#%d', $task['id']).' '.$task['title'],
'backgroundColor' => $this->color->getBackgroundColor($task['color_id']),
'borderColor' => $this->color->getBorderColor($task['color_id']),
'textColor' => 'black',
'url' => $this->helper->url->to('task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])),
);
}
/**
* Group a collection of records by a column
*

View File

@ -114,54 +114,6 @@ class Project extends Base
return $this->db->table(self::TABLE)->eq('id', $project_id)->eq('is_private', 1)->exists();
}
/**
* Get all projects to generate the Gantt chart
*
* @access public
* @param array $project_ids
* @return array
*/
public function getGanttBars(array $project_ids)
{
if (empty($project_ids)) {
return array();
}
$colors = $this->color->getDefaultColors();
$projects = $this->db->table(self::TABLE)->asc('start_date')->in('id', $project_ids)->eq('is_active', self::ACTIVE)->eq('is_private', 0)->findAll();
$bars = array();
foreach ($projects as $project) {
$start = empty($project['start_date']) ? time() : strtotime($project['start_date']);
$end = empty($project['end_date']) ? $start : strtotime($project['end_date']);
$color = next($colors) ?: reset($colors);
$bars[] = array(
'type' => 'project',
'id' => $project['id'],
'title' => $project['name'],
'start' => array(
(int) date('Y', $start),
(int) date('n', $start),
(int) date('j', $start),
),
'end' => array(
(int) date('Y', $end),
(int) date('n', $end),
(int) date('j', $end),
),
'link' => $this->helper->url->href('project', 'show', array('project_id' => $project['id'])),
'board_link' => $this->helper->url->href('board', 'show', array('project_id' => $project['id'])),
'gantt_link' => $this->helper->url->href('gantt', 'project', array('project_id' => $project['id'])),
'color' => $color,
'not_defined' => empty($project['start_date']) || empty($project['end_date']),
'users' => $this->projectPermission->getProjectUsers($project['id']),
);
}
return $bars;
}
/**
* Get all projects
*

View File

@ -2,11 +2,6 @@
namespace Model;
use DateTime;
use Eluceo\iCal\Component\Calendar;
use Eluceo\iCal\Component\Event;
use Eluceo\iCal\Property\Event\Attendees;
/**
* Task Filter
*
@ -137,7 +132,7 @@ class TaskFilter extends Base
*/
public function copy()
{
$filter = clone($this);
$filter = new static($this->container);
$filter->query = clone($this->query);
$filter->query->condition = clone($this->query->condition);
return $filter;
@ -674,223 +669,6 @@ class TaskFilter extends Base
});
}
/**
* Format tasks to be displayed in the Gantt chart
*
* @access public
* @return array
*/
public function toGanttBars()
{
$bars = array();
$columns = array();
foreach ($this->query->findAll() as $task) {
if (! isset($column_count[$task['project_id']])) {
$columns[$task['project_id']] = $this->board->getColumnsList($task['project_id']);
}
$start = $task['date_started'] ?: time();
$end = $task['date_due'] ?: $start;
$bars[] = array(
'type' => 'task',
'id' => $task['id'],
'title' => $task['title'],
'start' => array(
(int) date('Y', $start),
(int) date('n', $start),
(int) date('j', $start),
),
'end' => array(
(int) date('Y', $end),
(int) date('n', $end),
(int) date('j', $end),
),
'column_title' => $task['column_name'],
'assignee' => $task['assignee_name'] ?: $task['assignee_username'],
'progress' => $this->task->getProgress($task, $columns[$task['project_id']]).'%',
'link' => $this->helper->url->href('task', 'show', array('project_id' => $task['project_id'], 'task_id' => $task['id'])),
'color' => $this->color->getColorProperties($task['color_id']),
'not_defined' => empty($task['date_due']) || empty($task['date_started']),
);
}
return $bars;
}
/**
* Format the results to the ajax autocompletion
*
* @access public
* @return array
*/
public function toAutoCompletion()
{
return $this->query->columns(Task::TABLE.'.id', Task::TABLE.'.title')->callback(function(array $results) {
foreach ($results as &$result) {
$result['value'] = $result['title'];
$result['label'] = '#'.$result['id'].' - '.$result['title'];
}
return $results;
})->findAll();
}
/**
* Transform results to calendar events
*
* @access public
* @param string $start_column Column name for the start date
* @param string $end_column Column name for the end date
* @return array
*/
public function toDateTimeCalendarEvents($start_column, $end_column)
{
$events = array();
foreach ($this->query->findAll() as $task) {
$events[] = array_merge(
$this->getTaskCalendarProperties($task),
array(
'start' => date('Y-m-d\TH:i:s', $task[$start_column]),
'end' => date('Y-m-d\TH:i:s', $task[$end_column] ?: time()),
'editable' => false,
)
);
}
return $events;
}
/**
* Transform results to all day calendar events
*
* @access public
* @param string $column Column name for the date
* @return array
*/
public function toAllDayCalendarEvents($column = 'date_due')
{
$events = array();
foreach ($this->query->findAll() as $task) {
$events[] = array_merge(
$this->getTaskCalendarProperties($task),
array(
'start' => date('Y-m-d', $task[$column]),
'end' => date('Y-m-d', $task[$column]),
'allday' => true,
)
);
}
return $events;
}
/**
* Transform results to ical events
*
* @access public
* @param string $start_column Column name for the start date
* @param string $end_column Column name for the end date
* @param Calendar $vCalendar Calendar object
* @return Calendar
*/
public function addDateTimeIcalEvents($start_column, $end_column, Calendar $vCalendar = null)
{
if ($vCalendar === null) {
$vCalendar = new Calendar('Kanboard');
}
foreach ($this->query->findAll() as $task) {
$start = new DateTime;
$start->setTimestamp($task[$start_column]);
$end = new DateTime;
$end->setTimestamp($task[$end_column] ?: time());
$vEvent = $this->getTaskIcalEvent($task, 'task-#'.$task['id'].'-'.$start_column.'-'.$end_column);
$vEvent->setDtStart($start);
$vEvent->setDtEnd($end);
$vCalendar->addComponent($vEvent);
}
return $vCalendar;
}
/**
* Transform results to all day ical events
*
* @access public
* @param string $column Column name for the date
* @param Calendar $vCalendar Calendar object
* @return Calendar
*/
public function addAllDayIcalEvents($column = 'date_due', Calendar $vCalendar = null)
{
if ($vCalendar === null) {
$vCalendar = new Calendar('Kanboard');
}
foreach ($this->query->findAll() as $task) {
$date = new DateTime;
$date->setTimestamp($task[$column]);
$vEvent = $this->getTaskIcalEvent($task, 'task-#'.$task['id'].'-'.$column);
$vEvent->setDtStart($date);
$vEvent->setDtEnd($date);
$vEvent->setNoTime(true);
$vCalendar->addComponent($vEvent);
}
return $vCalendar;
}
/**
* Get common events for task ical events
*
* @access protected
* @param array $task
* @param string $uid
* @return Event
*/
protected function getTaskIcalEvent(array &$task, $uid)
{
$dateCreation = new DateTime;
$dateCreation->setTimestamp($task['date_creation']);
$dateModif = new DateTime;
$dateModif->setTimestamp($task['date_modification']);
$vEvent = new Event($uid);
$vEvent->setCreated($dateCreation);
$vEvent->setModified($dateModif);
$vEvent->setUseTimezone(true);
$vEvent->setSummary(t('#%d', $task['id']).' '.$task['title']);
$vEvent->setUrl($this->helper->url->base().$this->helper->url->to('task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])));
if (! empty($task['owner_id'])) {
$vEvent->setOrganizer($task['assignee_name'] ?: $task['assignee_username'], $task['assignee_email']);
}
if (! empty($task['creator_id'])) {
$attendees = new Attendees;
$attendees->add('MAILTO:'.($task['creator_email'] ?: $task['creator_username'].'@kanboard.local'));
$vEvent->setAttendees($attendees);
}
return $vEvent;
}
/**
* Filter with an operator
*

View File

@ -61,6 +61,13 @@ class ClassProvider implements ServiceProviderInterface
'UserSession',
'Webhook',
),
'Formatter' => array(
'TaskFilterGanttFormatter',
'TaskFilterAutoCompleteFormatter',
'TaskFilterCalendarFormatter',
'TaskFilterICalendarFormatter',
'ProjectGanttFormatter',
),
'Core' => array(
'EmailClient',
'Helper',

View File

@ -2,6 +2,4 @@
require __DIR__.'/app/common.php';
if (! $container['router']->dispatch($_SERVER['REQUEST_URI'], isset($_SERVER['QUERY_STRING']) ? $_SERVER['QUERY_STRING'] : '')) {
die('Page not found!');
}
$container['router']->dispatch($_SERVER['REQUEST_URI'], isset($_SERVER['QUERY_STRING']) ? $_SERVER['QUERY_STRING'] : '');

View File

@ -0,0 +1,29 @@
<?php
require_once __DIR__.'/../Base.php';
use Formatter\TaskFilterCalendarFormatter;
use Model\Project;
use Model\User;
use Model\TaskCreation;
use Model\DateParser;
use Model\Category;
use Model\Subtask;
use Model\Config;
use Model\Swimlane;
class TaskFilterCalendarFormatterTest extends Base
{
public function testCopy()
{
$tf = new TaskFilterCalendarFormatter($this->container);
$filter1 = $tf->create()->setFullDay();
$filter2 = $tf->copy();
$this->assertTrue($filter1 !== $filter2);
$this->assertTrue($filter1->query !== $filter2->query);
$this->assertTrue($filter1->query->condition !== $filter2->query->condition);
$this->assertTrue($filter1->isFullDay());
$this->assertFalse($filter2->isFullDay());
}
}

View File

@ -0,0 +1,24 @@
<?php
require_once __DIR__.'/../Base.php';
use Formatter\TaskFilterGanttFormatter;
use Model\Project;
use Model\TaskCreation;
use Model\DateParser;
class TaskFilterGanttFormatterTest extends Base
{
public function testFormat()
{
$dp = new DateParser($this->container);
$p = new Project($this->container);
$tc = new TaskCreation($this->container);
$tf = new TaskFilterGanttFormatter($this->container);
$this->assertEquals(1, $p->create(array('name' => 'test')));
$this->assertNotFalse($tc->create(array('project_id' => 1, 'title' => 'task1')));
$this->assertNotEmpty($tf->search('status:open')->format());
}
}

View File

@ -0,0 +1,77 @@
<?php
require_once __DIR__.'/../Base.php';
use Eluceo\iCal\Component\Calendar;
use Formatter\TaskFilterICalendarFormatter;
use Model\Project;
use Model\User;
use Model\TaskCreation;
use Model\DateParser;
use Model\Category;
use Model\Subtask;
use Model\Config;
use Model\Swimlane;
class TaskFilterICalendarFormatterTest extends Base
{
public function testIcalEventsWithCreatorAndDueDate()
{
$dp = new DateParser($this->container);
$p = new Project($this->container);
$tc = new TaskCreation($this->container);
$tf = new TaskFilterICalendarFormatter($this->container);
$this->assertEquals(1, $p->create(array('name' => 'test')));
$this->assertNotFalse($tc->create(array('project_id' => 1, 'title' => 'task1', 'creator_id' => 1, 'date_due' => $dp->getTimestampFromIsoFormat('-2 days'))));
$ics = $tf->create()
->filterByDueDateRange(strtotime('-1 month'), strtotime('+1 month'))
->setFullDay()
->setCalendar(new Calendar('Kanboard'))
->setColumns('date_due')
->addFullDayEvents()
->format();
$this->assertContains('UID:task-#1-date_due', $ics);
$this->assertContains('DTSTART;TZID=UTC;VALUE=DATE:'.date('Ymd', strtotime('-2 days')), $ics);
$this->assertContains('DTEND;TZID=UTC;VALUE=DATE:'.date('Ymd', strtotime('-2 days')), $ics);
$this->assertContains('URL:http://localhost/?controller=task&action=show&task_id=1&project_id=1', $ics);
$this->assertContains('SUMMARY:#1 task1', $ics);
$this->assertContains('ATTENDEE:MAILTO:admin@kanboard.local', $ics);
$this->assertContains('X-MICROSOFT-CDO-ALLDAYEVENT:TRUE', $ics);
}
public function testIcalEventsWithAssigneeAndDueDate()
{
$dp = new DateParser($this->container);
$p = new Project($this->container);
$tc = new TaskCreation($this->container);
$tf = new TaskFilterICalendarFormatter($this->container);
$u = new User($this->container);
$c = new Config($this->container);
$this->assertNotFalse($c->save(array('application_url' => 'http://kb/')));
$this->assertEquals('http://kb/', $c->get('application_url'));
$this->assertNotFalse($u->update(array('id' => 1, 'email' => 'bob@localhost')));
$this->assertEquals(1, $p->create(array('name' => 'test')));
$this->assertNotFalse($tc->create(array('project_id' => 1, 'title' => 'task1', 'owner_id' => 1, 'date_due' => $dp->getTimestampFromIsoFormat('+5 days'))));
$ics = $tf->create()
->filterByDueDateRange(strtotime('-1 month'), strtotime('+1 month'))
->setFullDay()
->setCalendar(new Calendar('Kanboard'))
->setColumns('date_due')
->addFullDayEvents()
->format();
$this->assertContains('UID:task-#1-date_due', $ics);
$this->assertContains('DTSTART;TZID=UTC;VALUE=DATE:'.date('Ymd', strtotime('+5 days')), $ics);
$this->assertContains('DTEND;TZID=UTC;VALUE=DATE:'.date('Ymd', strtotime('+5 days')), $ics);
$this->assertContains('URL:http://kb/?controller=task&action=show&task_id=1&project_id=1', $ics);
$this->assertContains('SUMMARY:#1 task1', $ics);
$this->assertContains('ORGANIZER;CN=admin:MAILTO:bob@localhost', $ics);
$this->assertContains('X-MICROSOFT-CDO-ALLDAYEVENT:TRUE', $ics);
}
}

View File

@ -14,70 +14,6 @@ use Model\Swimlane;
class TaskFilterTest extends Base
{
public function testGetGanttbar()
{
$dp = new DateParser($this->container);
$p = new Project($this->container);
$tc = new TaskCreation($this->container);
$tf = new TaskFilter($this->container);
$this->assertEquals(1, $p->create(array('name' => 'test')));
$this->assertNotFalse($tc->create(array('project_id' => 1, 'title' => 'task1')));
$this->assertNotEmpty($tf->search('status:open')->toGanttBars());
$this->assertNotEmpty($p->getGanttBars(array(1)));
}
public function testIcalEventsWithCreatorAndDueDate()
{
$dp = new DateParser($this->container);
$p = new Project($this->container);
$tc = new TaskCreation($this->container);
$tf = new TaskFilter($this->container);
$this->assertEquals(1, $p->create(array('name' => 'test')));
$this->assertNotFalse($tc->create(array('project_id' => 1, 'title' => 'task1', 'creator_id' => 1, 'date_due' => $dp->getTimestampFromIsoFormat('-2 days'))));
$events = $tf->create()->filterByDueDateRange(strtotime('-1 month'), strtotime('+1 month'))->addAllDayIcalEvents();
$ics = $events->render();
$this->assertContains('UID:task-#1-date_due', $ics);
$this->assertContains('DTSTART;TZID=UTC;VALUE=DATE:'.date('Ymd', strtotime('-2 days')), $ics);
$this->assertContains('DTEND;TZID=UTC;VALUE=DATE:'.date('Ymd', strtotime('-2 days')), $ics);
$this->assertContains('URL:http://localhost/?controller=task&action=show&task_id=1&project_id=1', $ics);
$this->assertContains('SUMMARY:#1 task1', $ics);
$this->assertContains('ATTENDEE:MAILTO:admin@kanboard.local', $ics);
$this->assertContains('X-MICROSOFT-CDO-ALLDAYEVENT:TRUE', $ics);
}
public function testIcalEventsWithAssigneeAndDueDate()
{
$dp = new DateParser($this->container);
$p = new Project($this->container);
$tc = new TaskCreation($this->container);
$tf = new TaskFilter($this->container);
$u = new User($this->container);
$c = new Config($this->container);
$this->assertNotFalse($c->save(array('application_url' => 'http://kb/')));
$this->assertEquals('http://kb/', $c->get('application_url'));
$this->assertNotFalse($u->update(array('id' => 1, 'email' => 'bob@localhost')));
$this->assertEquals(1, $p->create(array('name' => 'test')));
$this->assertNotFalse($tc->create(array('project_id' => 1, 'title' => 'task1', 'owner_id' => 1, 'date_due' => $dp->getTimestampFromIsoFormat('+5 days'))));
$events = $tf->create()->filterByDueDateRange(strtotime('-1 month'), strtotime('+1 month'))->addAllDayIcalEvents();
$ics = $events->render();
$this->assertContains('UID:task-#1-date_due', $ics);
$this->assertContains('DTSTART;TZID=UTC;VALUE=DATE:'.date('Ymd', strtotime('+5 days')), $ics);
$this->assertContains('DTEND;TZID=UTC;VALUE=DATE:'.date('Ymd', strtotime('+5 days')), $ics);
$this->assertContains('URL:http://kb/?controller=task&action=show&task_id=1&project_id=1', $ics);
$this->assertContains('SUMMARY:#1 task1', $ics);
$this->assertContains('ORGANIZER;CN=admin:MAILTO:bob@localhost', $ics);
$this->assertContains('X-MICROSOFT-CDO-ALLDAYEVENT:TRUE', $ics);
}
public function testSearchWithEmptyResult()
{
$dp = new DateParser($this->container);