diff options
Diffstat (limited to 'app')
-rw-r--r-- | app/Controller/Board.php | 1 | ||||
-rw-r--r-- | app/Controller/Customfilter.php | 142 | ||||
-rw-r--r-- | app/Core/Base.php | 1 | ||||
-rw-r--r-- | app/Model/Acl.php | 1 | ||||
-rw-r--r-- | app/Model/CustomFilter.php | 163 | ||||
-rw-r--r-- | app/Schema/Mysql.php | 19 | ||||
-rw-r--r-- | app/Schema/Postgres.php | 16 | ||||
-rw-r--r-- | app/Schema/Sqlite.php | 16 | ||||
-rw-r--r-- | app/ServiceProvider/ClassProvider.php | 1 | ||||
-rw-r--r-- | app/Template/board/view_private.php | 1 | ||||
-rw-r--r-- | app/Template/custom_filter/add.php | 22 | ||||
-rw-r--r-- | app/Template/custom_filter/edit.php | 30 | ||||
-rw-r--r-- | app/Template/custom_filter/index.php | 40 | ||||
-rw-r--r-- | app/Template/project/dropdown.php | 4 | ||||
-rw-r--r-- | app/Template/project/filters.php | 11 | ||||
-rw-r--r-- | app/Template/project/sidebar.php | 3 |
16 files changed, 468 insertions, 3 deletions
diff --git a/app/Controller/Board.php b/app/Controller/Board.php index 5851bd26..840db05b 100644 --- a/app/Controller/Board.php +++ b/app/Controller/Board.php @@ -52,6 +52,7 @@ class Board extends Base $this->response->html($this->template->layout('board/view_private', array( 'categories_list' => $this->category->getList($params['project']['id'], false), 'users_list' => $this->projectPermission->getMemberList($params['project']['id'], false), + 'custom_filters_list' => $this->customFilter->getAll($params['project']['id'], $this->userSession->getId()), 'swimlanes' => $this->taskFilter->search($params['filters']['search'])->getBoard($params['project']['id']), 'description' => $params['project']['description'], 'board_private_refresh_interval' => $this->config->get('board_private_refresh_interval'), diff --git a/app/Controller/Customfilter.php b/app/Controller/Customfilter.php new file mode 100644 index 00000000..c403cb4b --- /dev/null +++ b/app/Controller/Customfilter.php @@ -0,0 +1,142 @@ +<?php + +namespace Controller; + +/** + * Custom Filter management + * + * @package controller + * @author Timo Litzbarski + */ +class Customfilter extends Base +{ + /** + * Display list of filters + * + * @access public + */ + public function index(array $values = array(), array $errors = array()) + { + $project = $this->getProject(); + + $this->response->html($this->projectLayout('custom_filter/index', array( + 'values' => $values + array('project_id' => $project['id']), + 'errors' => $errors, + 'project' => $project, + 'custom_filters' => $this->customFilter->getAll($project['id'], $this->userSession->getId()), + 'title' => t('Custom filters'), + ))); + } + + /** + * Save a new custom filter + * + * @access public + */ + public function save() + { + $project = $this->getProject(); + + $values = $this->request->getValues(); + $values['user_id'] = $this->userSession->getId(); + + list($valid, $errors) = $this->customFilter->validateCreation($values); + + if ($valid) { + if ($this->customFilter->create($values)) { + $this->session->flash(t('Your custom filter have been created successfully.')); + $this->response->redirect($this->helper->url->to('customfilter', 'index', array('project_id' => $project['id']))); + } + else { + $this->session->flashError(t('Unable to create your custom filter.')); + } + } + + $this->index($values, $errors); + } + + /** + * Remove a custom filter + * + * @access public + */ + public function remove() + { + $this->checkCSRFParam(); + $project = $this->getProject(); + $filter = $this->customFilter->getById($this->request->getIntegerParam('filter_id')); + + $this->checkPermission($project, $filter); + + if ($this->customFilter->remove($filter['id'])) { + $this->session->flash(t('Custom filter removed successfully.')); + } else { + $this->session->flashError(t('Unable to remove this custom filter.')); + } + + $this->response->redirect($this->helper->url->to('customfilter', 'index', array('project_id' => $project['id']))); + } + + /** + * Edit a custom filter (display the form) + * + * @access public + */ + public function edit(array $values = array(), array $errors = array()) + { + $project = $this->getProject(); + $filter = $this->customFilter->getById($this->request->getIntegerParam('filter_id')); + + $this->checkPermission($project, $filter); + + $this->response->html($this->projectLayout('custom_filter/edit', array( + 'values' => empty($values) ? $filter : $values, + 'errors' => $errors, + 'project' => $project, + 'filter' => $filter, + 'title' => t('Edit custom filter') + ))); + } + + /** + * Edit a custom filter (validate the form and update the database) + * + * @access public + */ + public function update() + { + $project = $this->getProject(); + $filter = $this->customFilter->getById($this->request->getIntegerParam('filter_id')); + + $this->checkPermission($project, $filter); + + $values = $this->request->getValues(); + + if (! isset($values['is_shared'])) { + $values += array('is_shared' => 0); + } + + list($valid, $errors) = $this->customFilter->validateModification($values); + + if ($valid) { + if ($this->customFilter->update($values)) { + $this->session->flash(t('Your custom filter have been updated successfully.')); + $this->response->redirect($this->helper->url->to('customfilter', 'index', array('project_id' => $project['id']))); + } + else { + $this->session->flashError(t('Unable to update custom filter.')); + } + } + + $this->edit($values, $errors); + } + + private function checkPermission(array $project, array $filter) + { + $user_id = $this->userSession->getId(); + + if ($filter['user_id'] != $user_id && (! $this->projectPermission->isManager($project['id'], $user_id) || ! $this->userSession->isAdmin())) { + $this->forbidden(); + } + } +} diff --git a/app/Core/Base.php b/app/Core/Base.php index b919d551..71d54413 100644 --- a/app/Core/Base.php +++ b/app/Core/Base.php @@ -47,6 +47,7 @@ use Pimple\Container; * @property \Model\Comment $comment * @property \Model\Config $config * @property \Model\Currency $currency + * @property \Model\CustomFilter $customFilter * @property \Model\DateParser $dateParser * @property \Model\File $file * @property \Model\LastLogin $lastLogin diff --git a/app/Model/Acl.php b/app/Model/Acl.php index 9a227cf5..675ca36e 100644 --- a/app/Model/Acl.php +++ b/app/Model/Acl.php @@ -47,6 +47,7 @@ class Acl extends Base 'taskstatus' => '*', 'tasklink' => '*', 'timer' => '*', + 'customfilter' => '*', 'calendar' => array('show', 'project'), ); diff --git a/app/Model/CustomFilter.php b/app/Model/CustomFilter.php new file mode 100644 index 00000000..2c485247 --- /dev/null +++ b/app/Model/CustomFilter.php @@ -0,0 +1,163 @@ +<?php + +namespace Model; + +use SimpleValidator\Validator; +use SimpleValidator\Validators; + +/** + * Custom Filter model + * + * @package model + * @author Timo Litzbarski + */ +class CustomFilter extends Base +{ + /** + * SQL table name + * + * @var string + */ + const TABLE = 'custom_filters'; + + /** + * Return the list of all allowed custom filters for a user and project + * + * @access public + * @param integer $project_id Project id + * @param integer $user_id User id + * @return array + */ + public function getAll($project_id, $user_id) + { + return $this->db + ->table(self::TABLE) + ->columns( + User::TABLE.'.name as owner_name', + User::TABLE.'.username as owner_username', + self::TABLE.'.id', + self::TABLE.'.user_id', + self::TABLE.'.project_id', + self::TABLE.'.filter', + self::TABLE.'.name', + self::TABLE.'.is_shared' + ) + ->asc(self::TABLE.'.name') + ->join(User::TABLE, 'id', 'user_id') + ->beginOr() + ->eq('is_shared', 1) + ->eq('user_id', $user_id) + ->closeOr() + ->eq('project_id', $project_id) + ->findAll(); + } + + /** + * Get custom filter by id + * + * @access private + * @param integer $filter_id + * @return array + */ + public function getById($filter_id) + { + return $this->db->table(self::TABLE)->eq('id', $filter_id)->findOne(); + } + + /** + * Create a custom filter + * + * @access public + * @param array $values Form values + * @return bool|integer + */ + public function create(array $values) + { + return $this->persist(self::TABLE, $values); + } + + /** + * Update a custom filter + * + * @access public + * @param array $values Form values + * @return bool + */ + public function update(array $values) + { + return $this->db->table(self::TABLE) + ->eq('id', $values['id']) + ->update($values); + } + + /** + * Remove a custom filter + * + * @access public + * @param integer $filter_id + * @return bool + */ + public function remove($filter_id) + { + return $this->db->table(self::TABLE)->eq('id', $filter_id)->remove(); + } + + /** + * Common validation rules + * + * @access private + * @return array + */ + private function commonValidationRules() + { + return array( + new Validators\Required('project_id', t('Field required')), + new Validators\Required('user_id', t('Field required')), + new Validators\Required('name', t('Field required')), + new Validators\Required('filter', t('Field required')), + new Validators\Integer('user_id', t('This value must be an integer')), + new Validators\Integer('project_id', t('This value must be an integer')), + new Validators\MaxLength('name', t('The maximum length is %d characters', 100), 100), + new Validators\MaxLength('filter', t('The maximum length is %d characters', 100), 100) + ); + } + + /** + * Validate filter creation + * + * @access public + * @param array $values Form values + * @return array $valid, $errors [0] = Success or not, [1] = List of errors + */ + public function validateCreation(array $values) + { + $v = new Validator($values, $this->commonValidationRules()); + + return array( + $v->execute(), + $v->getErrors() + ); + } + + /** + * Validate filter modification + * + * @access public + * @param array $values Form values + * @return array $valid, $errors [0] = Success or not, [1] = List of errors + */ + public function validateModification(array $values) + { + $rules = array( + new Validators\Required('id', t('Field required')), + new Validators\Integer('id', t('This value must be an integer')), + ); + + $v = new Validator($values, array_merge($rules, $this->commonValidationRules())); + + return array( + $v->execute(), + $v->getErrors() + ); + } +} diff --git a/app/Schema/Mysql.php b/app/Schema/Mysql.php index c146eb0c..a1cef344 100644 --- a/app/Schema/Mysql.php +++ b/app/Schema/Mysql.php @@ -6,7 +6,24 @@ use PDO; use Core\Security; use Model\Link; -const VERSION = 87; +const VERSION = 88; + +function version_88($pdo) +{ + $pdo->exec(" + CREATE TABLE custom_filters ( + id INT NOT NULL AUTO_INCREMENT, + filter VARCHAR(100) NOT NULL, + project_id INT NOT NULL, + user_id INT NOT NULL, + name VARCHAR(100) NOT NULL, + is_shared TINYINT(1) DEFAULT 0, + PRIMARY KEY(id), + FOREIGN KEY(project_id) REFERENCES projects(id) ON DELETE CASCADE, + FOREIGN KEY(user_id) REFERENCES users(id) ON DELETE CASCADE + ) ENGINE=InnoDB CHARSET=utf8 + "); +} function version_87($pdo) { diff --git a/app/Schema/Postgres.php b/app/Schema/Postgres.php index 695d8f1f..f7263e75 100644 --- a/app/Schema/Postgres.php +++ b/app/Schema/Postgres.php @@ -6,7 +6,21 @@ use PDO; use Core\Security; use Model\Link; -const VERSION = 67; +const VERSION = 68; + +function version_68($pdo) +{ + $pdo->exec(" + CREATE TABLE custom_filters ( + id SERIAL PRIMARY KEY, + filter VARCHAR(100) NOT NULL, + project_id INTEGER NOT NULL, + user_id INTEGER NOT NULL, + name VARCHAR(100) NOT NULL, + is_shared BOOLEAN DEFAULT '0' + ) + "); +} function version_67($pdo) { diff --git a/app/Schema/Sqlite.php b/app/Schema/Sqlite.php index 26ad96c7..064d0f3c 100644 --- a/app/Schema/Sqlite.php +++ b/app/Schema/Sqlite.php @@ -6,7 +6,21 @@ use Core\Security; use PDO; use Model\Link; -const VERSION = 83; +const VERSION = 84; + +function version_84($pdo) +{ + $pdo->exec(" + CREATE TABLE custom_filters ( + id INTEGER PRIMARY KEY, + filter TEXT NOT NULL, + project_id INTEGER NOT NULL, + user_id INTEGER NOT NULL, + name TEXT NOT NULL, + is_shared INTEGER DEFAULT 0 + ) + "); +} function version_83($pdo) { diff --git a/app/ServiceProvider/ClassProvider.php b/app/ServiceProvider/ClassProvider.php index a89b78bb..b671dace 100644 --- a/app/ServiceProvider/ClassProvider.php +++ b/app/ServiceProvider/ClassProvider.php @@ -27,6 +27,7 @@ class ClassProvider implements ServiceProviderInterface 'Comment', 'Config', 'Currency', + 'CustomFilter', 'DateParser', 'File', 'LastLogin', diff --git a/app/Template/board/view_private.php b/app/Template/board/view_private.php index d4c2c651..63d261f6 100644 --- a/app/Template/board/view_private.php +++ b/app/Template/board/view_private.php @@ -5,6 +5,7 @@ 'filters' => $filters, 'categories_list' => $categories_list, 'users_list' => $users_list, + 'custom_filters_list' => $custom_filters_list, 'is_board' => true, )) ?> diff --git a/app/Template/custom_filter/add.php b/app/Template/custom_filter/add.php new file mode 100644 index 00000000..d4e102b3 --- /dev/null +++ b/app/Template/custom_filter/add.php @@ -0,0 +1,22 @@ +<div class="page-header"> + <h2><?= t('Add a new filter') ?></h2> +</div> +<form method="post" action="<?= $this->url->href('customfilter', 'save', array('project_id' => $project['id'])) ?>" autocomplete="off"> + + <?= $this->form->csrf() ?> + <?= $this->form->hidden('project_id', $values) ?> + + <?= $this->form->label(t('Name'), 'name') ?> + <?= $this->form->text('name', $values, $errors, array('required', 'maxlength="100"')) ?> + + <?= $this->form->label(t('Filter'), 'filter') ?> + <?= $this->form->text('filter', $values, $errors, array('required', 'maxlength="100"')) ?> + + <?php if ($this->user->isProjectManagementAllowed($project['id'])): ?> + <?= $this->form->checkbox('is_shared', t('Share with all project members'), 1) ?> + <?php endif ?> + + <div class="form-actions"> + <input type="submit" value="<?= t('Save') ?>" class="btn btn-blue"> + </div> +</form>
\ No newline at end of file diff --git a/app/Template/custom_filter/edit.php b/app/Template/custom_filter/edit.php new file mode 100644 index 00000000..7525574c --- /dev/null +++ b/app/Template/custom_filter/edit.php @@ -0,0 +1,30 @@ +<div class="page-header"> + <h2><?= t('Edit custom filter') ?></h2> +</div> + +<form method="post" action="<?= $this->url->href('customfilter', 'update', array('project_id' => $filter['project_id'], 'filter_id' => $filter['id'])) ?>" autocomplete="off"> + + <?= $this->form->csrf() ?> + + <?= $this->form->hidden('id', $values) ?> + <?= $this->form->hidden('user_id', $values) ?> + <?= $this->form->hidden('project_id', $values) ?> + + <?= $this->form->label(t('Name'), 'name') ?> + <?= $this->form->text('name', $values, $errors, array('autofocus', 'required', 'maxlength="100"')) ?> + + <?= $this->form->label(t('Filter'), 'filter') ?> + <?= $this->form->text('filter', $values, $errors, array('required', 'maxlength="100"')) ?> + + <?php if ($this->user->isProjectManagementAllowed($project['id'])): ?> + <?= $this->form->checkbox('is_shared', t('Share with all project members'), 1, $values['is_shared'] == 1) ?> + <?php else: ?> + <?= $this->form->hidden('is_shared', $values) ?> + <?php endif ?> + + <div class="form-actions"> + <input type="submit" value="<?= t('Save') ?>" class="btn btn-blue"> + <?= t('or') ?> + <?= $this->url->link(t('cancel'), 'customfilter', 'index', array('project_id' => $project['id'])) ?> + </div> +</form>
\ No newline at end of file diff --git a/app/Template/custom_filter/index.php b/app/Template/custom_filter/index.php new file mode 100644 index 00000000..a53d0d0a --- /dev/null +++ b/app/Template/custom_filter/index.php @@ -0,0 +1,40 @@ +<?php if (! empty($custom_filters)): ?> +<div class="page-header"> + <h2><?= t('Custom filters') ?></h2> +</div> +<div> + <table> + <tr> + <th><?= t('Name') ?></th> + <th><?= t('Filter') ?></th> + <th><?= t('Shared') ?></th> + <th><?= t('Owner') ?></th> + <th><?= t('Actions') ?></th> + </tr> + <?php foreach ($custom_filters as $filter): ?> + <tr> + <td><?= $this->e($filter['name']) ?></td> + <td><?= $this->e($filter['filter']) ?></td> + <td> + <?php if ($filter['is_shared'] == 1): ?> + <?= t('Yes') ?> + <?php else: ?> + <?= t('No') ?> + <?php endif ?> + </td> + <td><?= $this->e($filter['owner_name'] ?: $filter['owner_username']) ?></td> + <td> + <?php if ($filter['user_id'] == $this->user->getId() || $this->user->isProjectManagementAllowed($project['id'])): ?> + <ul> + <li><?= $this->url->link(t('Remove'), 'customfilter', 'remove', array('project_id' => $filter['project_id'], 'filter_id' => $filter['id']), true) ?></li> + <li><?= $this->url->link(t('Edit'), 'customfilter', 'edit', array('project_id' => $filter['project_id'], 'filter_id' => $filter['id'])) ?></li> + </ul> + <?php endif ?> + </td> + </tr> + <?php endforeach ?> + </table> +</div> +<?php endif ?> + +<?= $this->render('custom_filter/add', array('project' => $project, 'values' => $values, 'errors' => $errors)) ?>
\ No newline at end of file diff --git a/app/Template/project/dropdown.php b/app/Template/project/dropdown.php index 96b6a43a..1eb87b0e 100644 --- a/app/Template/project/dropdown.php +++ b/app/Template/project/dropdown.php @@ -2,6 +2,10 @@ <i class="fa fa-dashboard fa-fw"></i> <?= $this->url->link(t('Activity'), 'activity', 'project', array('project_id' => $project['id'])) ?> </li> +<li> + <i class="fa fa-filter fa-fw"></i> + <?= $this->url->link(t('Custom filters'), 'customfilter', 'index', array('project_id' => $project['id'])) ?> +</li> <?php if ($project['is_public']): ?> <li> diff --git a/app/Template/project/filters.php b/app/Template/project/filters.php index 5b9ac472..c8f09fee 100644 --- a/app/Template/project/filters.php +++ b/app/Template/project/filters.php @@ -86,5 +86,16 @@ </ul> </div> <?php endif ?> + + <?php if (isset($custom_filters_list) && ! empty($custom_filters_list)): ?> + <div class="dropdown filters"> + <i class="fa fa-caret-down"></i> <a href="#" class="dropdown-menu"><?= t('My filters') ?></a> + <ul> + <?php foreach ($custom_filters_list as $filter): ?> + <li><a href="#" class="filter-helper" data-filter='<?= $this->e($filter['filter']) ?>'><?= $this->e($filter['name']) ?></a></li> + <?php endforeach ?> + </ul> + </div> + <?php endif ?> </div> </div>
\ No newline at end of file diff --git a/app/Template/project/sidebar.php b/app/Template/project/sidebar.php index 482a95d2..d8b35e3b 100644 --- a/app/Template/project/sidebar.php +++ b/app/Template/project/sidebar.php @@ -4,6 +4,9 @@ <li <?= $this->app->getRouterAction() === 'show' ? 'class="active"' : '' ?>> <?= $this->url->link(t('Summary'), 'project', 'show', array('project_id' => $project['id'])) ?> </li> + <li <?= $this->app->getRouterController() === 'customfilter' && $this->app->getRouterAction() === 'index' ? 'class="active"' : '' ?>> + <?= $this->url->link(t('Custom filters'), 'customfilter', 'index', array('project_id' => $project['id'])) ?> + </li> <?php if ($this->user->isProjectManagementAllowed($project['id'])): ?> <li <?= $this->app->getRouterController() === 'project' && $this->app->getRouterAction() === 'share' ? 'class="active"' : '' ?>> |