Add ui to create new custom project roles and column restrictions
This commit is contained in:
parent
75470c7242
commit
44f680cf2f
|
|
@ -25,7 +25,7 @@ class ColumnController extends BaseController
|
|||
$this->response->html($this->helper->layout->project('column/index', array(
|
||||
'columns' => $columns,
|
||||
'project' => $project,
|
||||
'title' => t('Edit board')
|
||||
'title' => t('Edit columns')
|
||||
)));
|
||||
}
|
||||
|
||||
|
|
@ -49,7 +49,6 @@ class ColumnController extends BaseController
|
|||
'values' => $values,
|
||||
'errors' => $errors,
|
||||
'project' => $project,
|
||||
'title' => t('Add a new column')
|
||||
)));
|
||||
}
|
||||
|
||||
|
|
@ -102,7 +101,6 @@ class ColumnController extends BaseController
|
|||
'values' => $values ?: $column,
|
||||
'project' => $project,
|
||||
'column' => $column,
|
||||
'title' => t('Edit column "%s"', $column['title'])
|
||||
)));
|
||||
}
|
||||
|
||||
|
|
@ -168,7 +166,6 @@ class ColumnController extends BaseController
|
|||
$this->response->html($this->helper->layout->project('column/remove', array(
|
||||
'column' => $this->columnModel->getById($this->request->getIntegerParam('column_id')),
|
||||
'project' => $project,
|
||||
'title' => t('Remove a column from a board')
|
||||
)));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,102 @@
|
|||
<?php
|
||||
|
||||
namespace Kanboard\Controller;
|
||||
|
||||
use Kanboard\Core\Controller\AccessForbiddenException;
|
||||
|
||||
/**
|
||||
* Class ColumnMoveRestrictionController
|
||||
*
|
||||
* @package Kanboard\Controller
|
||||
* @author Frederic Guillot
|
||||
*/
|
||||
class ColumnMoveRestrictionController extends BaseController
|
||||
{
|
||||
/**
|
||||
* Show form to create a new column restriction
|
||||
*
|
||||
* @param array $values
|
||||
* @param array $errors
|
||||
* @throws AccessForbiddenException
|
||||
*/
|
||||
public function create(array $values = array(), array $errors = array())
|
||||
{
|
||||
$project = $this->getProject();
|
||||
$role_id = $this->request->getIntegerParam('role_id');
|
||||
$role = $this->projectRoleModel->getById($project['id'], $role_id);
|
||||
|
||||
$this->response->html($this->template->render('column_move_restriction/create', array(
|
||||
'project' => $project,
|
||||
'role' => $role,
|
||||
'columns' => $this->columnModel->getList($project['id']),
|
||||
'values' => $values + array('project_id' => $project['id'], 'role_id' => $role['role_id']),
|
||||
'errors' => $errors,
|
||||
)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Save new column restriction
|
||||
*/
|
||||
public function save()
|
||||
{
|
||||
$project = $this->getProject();
|
||||
$values = $this->request->getValues();
|
||||
|
||||
list($valid, $errors) = $this->columnMoveRestrictionValidator->validateCreation($values);
|
||||
|
||||
if ($valid) {
|
||||
$role_id = $this->columnMoveRestrictionModel->create(
|
||||
$project['id'],
|
||||
$values['role_id'],
|
||||
$values['src_column_id'],
|
||||
$values['dst_column_id']
|
||||
);
|
||||
|
||||
if ($role_id !== false) {
|
||||
$this->flash->success(t('The column restriction has been created successfully.'));
|
||||
} else {
|
||||
$this->flash->failure(t('Unable to create this column restriction.'));
|
||||
}
|
||||
|
||||
$this->response->redirect($this->helper->url->to('ProjectRoleController', 'show', array('project_id' => $project['id'])));
|
||||
} else {
|
||||
$this->create($values, $errors);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Confirm suppression
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
public function confirm()
|
||||
{
|
||||
$project = $this->getProject();
|
||||
$restriction_id = $this->request->getIntegerParam('restriction_id');
|
||||
|
||||
$this->response->html($this->helper->layout->project('column_move_restriction/remove', array(
|
||||
'project' => $project,
|
||||
'restriction' => $this->columnMoveRestrictionModel->getById($project['id'], $restriction_id),
|
||||
)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a restriction
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
public function remove()
|
||||
{
|
||||
$project = $this->getProject();
|
||||
$this->checkCSRFParam();
|
||||
$restriction_id = $this->request->getIntegerParam('restriction_id');
|
||||
|
||||
if ($this->columnMoveRestrictionModel->remove($restriction_id)) {
|
||||
$this->flash->success(t('Column restriction removed successfully.'));
|
||||
} else {
|
||||
$this->flash->failure(t('Unable to remove this restriction.'));
|
||||
}
|
||||
|
||||
$this->response->redirect($this->helper->url->to('ProjectRoleController', 'show', array('project_id' => $project['id'])));
|
||||
}
|
||||
}
|
||||
|
|
@ -23,7 +23,7 @@ class ProjectOverviewController extends BaseController
|
|||
'title' => $project['name'],
|
||||
'description' => $this->helper->projectHeader->getDescription($project),
|
||||
'users' => $this->projectUserRoleModel->getAllUsersGroupedByRole($project['id']),
|
||||
'roles' => $this->role->getProjectRoles(),
|
||||
'roles' => $this->projectRoleModel->getList($project['id']),
|
||||
'events' => $this->helper->projectActivity->getProjectEvents($project['id'], 10),
|
||||
'images' => $this->projectFileModel->getAllImages($project['id']),
|
||||
'files' => $this->projectFileModel->getAllDocuments($project['id']),
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ class ProjectPermissionController extends BaseController
|
|||
'project' => $project,
|
||||
'users' => $this->projectUserRoleModel->getUsers($project['id']),
|
||||
'groups' => $this->projectGroupRoleModel->getGroups($project['id']),
|
||||
'roles' => $this->role->getProjectRoles(),
|
||||
'roles' => $this->projectRoleModel->getList($project['id']),
|
||||
'values' => $values,
|
||||
'errors' => $errors,
|
||||
'title' => t('Project Permissions'),
|
||||
|
|
|
|||
|
|
@ -0,0 +1,107 @@
|
|||
<?php
|
||||
|
||||
namespace Kanboard\Controller;
|
||||
|
||||
use Kanboard\Core\Controller\AccessForbiddenException;
|
||||
|
||||
/**
|
||||
* Class ProjectRoleController
|
||||
*
|
||||
* @package Kanboard\Controller
|
||||
* @author Frederic Guillot
|
||||
*/
|
||||
class ProjectRoleController extends BaseController
|
||||
{
|
||||
/**
|
||||
* Show roles and permissions
|
||||
*/
|
||||
public function show()
|
||||
{
|
||||
$project = $this->getProject();
|
||||
|
||||
$this->response->html($this->helper->layout->project('project_role/show', array(
|
||||
'project' => $project,
|
||||
'roles' => $this->projectRoleModel->getAllWithRestrictions($project['id']),
|
||||
'title' => t('Custom Project Roles'),
|
||||
)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Show form to create new role
|
||||
*
|
||||
* @param array $values
|
||||
* @param array $errors
|
||||
* @throws AccessForbiddenException
|
||||
*/
|
||||
public function create(array $values = array(), array $errors = array())
|
||||
{
|
||||
$project = $this->getProject();
|
||||
|
||||
$this->response->html($this->template->render('project_role/create', array(
|
||||
'project' => $project,
|
||||
'values' => $values + array('project_id' => $project['id']),
|
||||
'errors' => $errors,
|
||||
)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Save new role
|
||||
*/
|
||||
public function save()
|
||||
{
|
||||
$project = $this->getProject();
|
||||
$values = $this->request->getValues();
|
||||
|
||||
list($valid, $errors) = $this->projectRoleValidator->validateCreation($values);
|
||||
|
||||
if ($valid) {
|
||||
$role_id = $this->projectRoleModel->create($project['id'], $values['role']);
|
||||
|
||||
if ($role_id !== false) {
|
||||
$this->flash->success(t('Your custom project role has been created successfully.'));
|
||||
} else {
|
||||
$this->flash->failure(t('Unable to create custom project role.'));
|
||||
}
|
||||
|
||||
$this->response->redirect($this->helper->url->to('ProjectRoleController', 'show', array('project_id' => $project['id'])));
|
||||
} else {
|
||||
$this->create($values, $errors);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Confirm suppression
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
public function confirm()
|
||||
{
|
||||
$project = $this->getProject();
|
||||
$role_id = $this->request->getIntegerParam('role_id');
|
||||
|
||||
$this->response->html($this->helper->layout->project('project_role/remove', array(
|
||||
'project' => $project,
|
||||
'role' => $this->projectRoleModel->getById($project['id'], $role_id),
|
||||
)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a custom role
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
public function remove()
|
||||
{
|
||||
$project = $this->getProject();
|
||||
$this->checkCSRFParam();
|
||||
$role_id = $this->request->getIntegerParam('role_id');
|
||||
|
||||
if ($this->projectRoleModel->remove($project['id'], $role_id)) {
|
||||
$this->flash->success(t('Custom project role removed successfully.'));
|
||||
} else {
|
||||
$this->flash->failure(t('Unable to remove this project role.'));
|
||||
}
|
||||
|
||||
$this->response->redirect($this->helper->url->to('ProjectRoleController', 'show', array('project_id' => $project['id'])));
|
||||
}
|
||||
}
|
||||
|
|
@ -122,9 +122,9 @@ class ProjectUserOverviewController extends BaseController
|
|||
{
|
||||
$project = $this->getProject();
|
||||
|
||||
return $this->response->html($this->template->render('project_user_overview/tooltip_users', array(
|
||||
$this->response->html($this->template->render('project_user_overview/tooltip_users', array(
|
||||
'users' => $this->projectUserRoleModel->getAllUsersGroupedByRole($project['id']),
|
||||
'roles' => $this->role->getProjectRoles(),
|
||||
'roles' => $this->projectRoleModel->getList($project['id']),
|
||||
)));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -135,6 +135,7 @@ use Pimple\Container;
|
|||
* @property \Kanboard\Validator\AuthValidator $authValidator
|
||||
* @property \Kanboard\Validator\ColumnValidator $columnValidator
|
||||
* @property \Kanboard\Validator\CategoryValidator $categoryValidator
|
||||
* @property \Kanboard\Validator\ColumnMoveRestrictionValidator $columnMoveRestrictionValidator
|
||||
* @property \Kanboard\Validator\CommentValidator $commentValidator
|
||||
* @property \Kanboard\Validator\CurrencyValidator $currencyValidator
|
||||
* @property \Kanboard\Validator\CustomFilterValidator $customFilterValidator
|
||||
|
|
@ -143,6 +144,7 @@ use Pimple\Container;
|
|||
* @property \Kanboard\Validator\LinkValidator $linkValidator
|
||||
* @property \Kanboard\Validator\PasswordResetValidator $passwordResetValidator
|
||||
* @property \Kanboard\Validator\ProjectValidator $projectValidator
|
||||
* @property \Kanboard\Validator\ProjectRoleValidator $projectRoleValidator
|
||||
* @property \Kanboard\Validator\SubtaskValidator $subtaskValidator
|
||||
* @property \Kanboard\Validator\SwimlaneValidator $swimlaneValidator
|
||||
* @property \Kanboard\Validator\TagValidator $tagValidator
|
||||
|
|
|
|||
|
|
@ -42,13 +42,13 @@ class ColumnMoveRestrictionCacheDecorator
|
|||
* @param int $project_id
|
||||
* @return array|mixed
|
||||
*/
|
||||
public function getAllSrcColumns($project_id)
|
||||
public function getAllSrcColumns($project_id, $role)
|
||||
{
|
||||
$key = $this->cachePrefix.$project_id;
|
||||
$key = $this->cachePrefix.$project_id.$role;
|
||||
$columnIds = $this->cache->get($key);
|
||||
|
||||
if ($columnIds === null) {
|
||||
$columnIds = $this->columnMoveRestrictionModel->getAllSrcColumns($project_id);
|
||||
$columnIds = $this->columnMoveRestrictionModel->getAllSrcColumns($project_id, $role);
|
||||
$this->cache->set($key, $columnIds);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -34,10 +34,16 @@ class BoardHelper extends Base
|
|||
public function isDraggable(array $task)
|
||||
{
|
||||
if ($task['is_active'] == 1 && $this->helper->user->hasProjectAccess('BoardViewController', 'save', $task['project_id'])) {
|
||||
$srcColumnIds = $this->columnMoveRestrictionCacheDecorator->getAllSrcColumns($task['project_id']);
|
||||
$role = $this->helper->user->getProjectUserRole($task['project_id']);
|
||||
|
||||
if ($this->role->isCustomProjectRole($role)) {
|
||||
$srcColumnIds = $this->columnMoveRestrictionCacheDecorator->getAllSrcColumns($task['project_id'], $role);
|
||||
return ! isset($srcColumnIds[$task['column_id']]);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,6 +34,35 @@ class ColumnMoveRestrictionModel extends Base
|
|||
->exists();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch one restriction
|
||||
*
|
||||
* @param int $project_id
|
||||
* @param int $restriction_id
|
||||
* @return array|null
|
||||
*/
|
||||
public function getById($project_id, $restriction_id)
|
||||
{
|
||||
return $this->db
|
||||
->table(self::TABLE)
|
||||
->columns(
|
||||
self::TABLE.'.restriction_id',
|
||||
self::TABLE.'.project_id',
|
||||
self::TABLE.'.role_id',
|
||||
self::TABLE.'.src_column_id',
|
||||
self::TABLE.'.dst_column_id',
|
||||
'pr.role',
|
||||
'sc.title as src_column_title',
|
||||
'dc.title as dst_column_title'
|
||||
)
|
||||
->left(ColumnModel::TABLE, 'sc', 'id', self::TABLE, 'src_column_id')
|
||||
->left(ColumnModel::TABLE, 'dc', 'id', self::TABLE, 'dst_column_id')
|
||||
->left(ProjectRoleModel::TABLE, 'pr', 'role_id', self::TABLE, 'role_id')
|
||||
->eq(self::TABLE.'.project_id', $project_id)
|
||||
->eq(self::TABLE.'.restriction_id', $restriction_id)
|
||||
->findOne();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all project column restrictions
|
||||
*
|
||||
|
|
@ -45,9 +74,11 @@ class ColumnMoveRestrictionModel extends Base
|
|||
return $this->db
|
||||
->table(self::TABLE)
|
||||
->columns(
|
||||
'restriction_id',
|
||||
'src_column_id',
|
||||
'dst_column_id',
|
||||
self::TABLE.'.restriction_id',
|
||||
self::TABLE.'.project_id',
|
||||
self::TABLE.'.role_id',
|
||||
self::TABLE.'.src_column_id',
|
||||
self::TABLE.'.dst_column_id',
|
||||
'pr.role',
|
||||
'sc.title as src_column_title',
|
||||
'dc.title as dst_column_title'
|
||||
|
|
@ -63,13 +94,16 @@ class ColumnMoveRestrictionModel extends Base
|
|||
* Get all source column Ids
|
||||
*
|
||||
* @param int $project_id
|
||||
* @param string $role
|
||||
* @return array
|
||||
*/
|
||||
public function getAllSrcColumns($project_id)
|
||||
public function getAllSrcColumns($project_id, $role)
|
||||
{
|
||||
return $this->db
|
||||
->hashtable(self::TABLE)
|
||||
->left(ProjectRoleModel::TABLE, 'pr', 'role_id', self::TABLE, 'role_id')
|
||||
->eq(self::TABLE.'.project_id', $project_id)
|
||||
->eq('pr.role', $role)
|
||||
->getAll('src_column_id', 'src_column_id');
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
namespace Kanboard\Model;
|
||||
|
||||
use Kanboard\Core\Base;
|
||||
use Kanboard\Core\Security\Role;
|
||||
|
||||
/**
|
||||
* Class ProjectRoleModel
|
||||
|
|
@ -14,6 +15,38 @@ class ProjectRoleModel extends Base
|
|||
{
|
||||
const TABLE = 'project_has_roles';
|
||||
|
||||
/**
|
||||
* Get list of project roles
|
||||
*
|
||||
* @param int $project_id
|
||||
* @return array
|
||||
*/
|
||||
public function getList($project_id)
|
||||
{
|
||||
$defaultRoles = $this->role->getProjectRoles();
|
||||
$customRoles = $this->db
|
||||
->hashtable(self::TABLE)
|
||||
->eq('project_id', $project_id)
|
||||
->getAll('role', 'role');
|
||||
|
||||
return $defaultRoles + $customRoles;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a role
|
||||
*
|
||||
* @param int $project_id
|
||||
* @param int $role_id
|
||||
* @return array|null
|
||||
*/
|
||||
public function getById($project_id, $role_id)
|
||||
{
|
||||
return $this->db->table(self::TABLE)
|
||||
->eq('project_id', $project_id)
|
||||
->eq('role_id', $role_id)
|
||||
->findOne();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all project roles
|
||||
*
|
||||
|
|
@ -28,6 +61,22 @@ class ProjectRoleModel extends Base
|
|||
->findAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all project roles with restrictions
|
||||
*
|
||||
* @param int $project_id
|
||||
* @return array
|
||||
*/
|
||||
public function getAllWithRestrictions($project_id)
|
||||
{
|
||||
$roles = $this->getAll($project_id);
|
||||
$restrictions = $this->columnMoveRestrictionModel->getAll($project_id);
|
||||
$restrictions = array_column_index($restrictions, 'role_id');
|
||||
array_merge_relation($roles, $restrictions, 'restrictions', 'role_id');
|
||||
|
||||
return $roles;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new project role
|
||||
*
|
||||
|
|
@ -73,10 +122,38 @@ class ProjectRoleModel extends Base
|
|||
*/
|
||||
public function remove($project_id, $role_id)
|
||||
{
|
||||
return $this->db
|
||||
$this->db->startTransaction();
|
||||
|
||||
$role = $this->getById($project_id, $role_id);
|
||||
|
||||
$r1 = $this->db
|
||||
->table(ProjectUserRoleModel::TABLE)
|
||||
->eq('project_id', $project_id)
|
||||
->eq('role', $role['role'])
|
||||
->update(array(
|
||||
'role' => Role::PROJECT_MEMBER
|
||||
));
|
||||
|
||||
$r2 = $this->db
|
||||
->table(ProjectGroupRoleModel::TABLE)
|
||||
->eq('project_id', $project_id)
|
||||
->eq('role', $role['role'])
|
||||
->update(array(
|
||||
'role' => Role::PROJECT_MEMBER
|
||||
));
|
||||
|
||||
$r3 = $this->db
|
||||
->table(self::TABLE)
|
||||
->eq('project_id', $project_id)
|
||||
->eq('role_id', $role_id)
|
||||
->remove();
|
||||
|
||||
if ($r1 && $r2 && $r3) {
|
||||
$this->db->closeTransaction();
|
||||
return true;
|
||||
}
|
||||
|
||||
$this->db->cancelTransaction();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -99,6 +99,7 @@ class ClassProvider implements ServiceProviderInterface
|
|||
'ActionValidator',
|
||||
'AuthValidator',
|
||||
'CategoryValidator',
|
||||
'ColumnMoveRestrictionValidator',
|
||||
'ColumnValidator',
|
||||
'CommentValidator',
|
||||
'CurrencyValidator',
|
||||
|
|
@ -108,6 +109,7 @@ class ClassProvider implements ServiceProviderInterface
|
|||
'LinkValidator',
|
||||
'PasswordResetValidator',
|
||||
'ProjectValidator',
|
||||
'ProjectRoleValidator',
|
||||
'SubtaskValidator',
|
||||
'SwimlaneValidator',
|
||||
'TagValidator',
|
||||
|
|
|
|||
|
|
@ -41,9 +41,11 @@
|
|||
<a href="#" class="dropdown-menu dropdown-menu-link-icon"><i class="fa fa-cog fa-fw"></i><i class="fa fa-caret-down"></i></a>
|
||||
<ul>
|
||||
<li>
|
||||
<i class="fa fa-pencil-square-o fa-fw" aria-hidden="true"></i>
|
||||
<?= $this->url->link(t('Edit'), 'ColumnController', 'edit', array('project_id' => $project['id'], 'column_id' => $column['id']), false, 'popover') ?>
|
||||
</li>
|
||||
<li>
|
||||
<i class="fa fa-trash-o fa-fw" aria-hidden="true"></i>
|
||||
<?= $this->url->link(t('Remove'), 'ColumnController', 'confirm', array('project_id' => $project['id'], 'column_id' => $column['id']), false, 'popover') ?>
|
||||
</li>
|
||||
</ul>
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
</p>
|
||||
|
||||
<div class="form-actions">
|
||||
<?= $this->url->link(t('Yes'), 'ColumnController', 'remove', array('project_id' => $project['id'], 'column_id' => $column['id'], 'remove' => 'yes'), true, 'btn btn-red') ?>
|
||||
<?= $this->url->link(t('Yes'), 'ColumnController', 'remove', array('project_id' => $project['id'], 'column_id' => $column['id']), true, 'btn btn-red') ?>
|
||||
<?= t('or') ?> <?= $this->url->link(t('cancel'), 'ColumnController', 'index', array('project_id' => $project['id']), false, 'close-popover') ?>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,24 @@
|
|||
<section id="main">
|
||||
<div class="page-header">
|
||||
<h2><?= t('New column restriction for the role "%s"', $role['role']) ?></h2>
|
||||
</div>
|
||||
<form class="popover-form" method="post" action="<?= $this->url->href('ColumnMoveRestrictionController', 'save', array('project_id' => $project['id'])) ?>" autocomplete="off">
|
||||
<?= $this->form->csrf() ?>
|
||||
<?= $this->form->hidden('project_id', $values) ?>
|
||||
<?= $this->form->hidden('role_id', $values) ?>
|
||||
|
||||
<?= $this->form->label(t('Source column'), 'src_column_id') ?>
|
||||
<?= $this->form->select('src_column_id', $columns, $values, $errors) ?>
|
||||
|
||||
<?= $this->form->label(t('Destination column'), 'dst_column_id') ?>
|
||||
<?= $this->form->select('dst_column_id', $columns, $values, $errors) ?>
|
||||
|
||||
<div class="form-actions">
|
||||
<button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
|
||||
<?= t('or') ?>
|
||||
<?= $this->url->link(t('cancel'), 'ProjectRoleController', 'show', array(), false, 'close-popover') ?>
|
||||
</div>
|
||||
|
||||
<p class="alert alert-info"><?= t('People belonging to this role won\'t be able to move tasks between the source and the destination column.') ?></p>
|
||||
</form>
|
||||
</section>
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
<div class="page-header">
|
||||
<h2><?= t('Remove a column restriction') ?></h2>
|
||||
</div>
|
||||
|
||||
<div class="confirm">
|
||||
<p class="alert alert-info">
|
||||
<?= t('Do you really want to remove this column restriction: "%s" to "%s"?', $restriction['src_column_title'], $restriction['dst_column_title']) ?>
|
||||
</p>
|
||||
|
||||
<div class="form-actions">
|
||||
<?= $this->url->link(t('Yes'), 'ColumnMoveRestrictionController', 'remove', array('project_id' => $project['id'], 'restriction_id' => $restriction['restriction_id']), true, 'btn btn-red') ?>
|
||||
<?= t('or') ?> <?= $this->url->link(t('cancel'), 'ProjectRoleController', 'show', array('project_id' => $project['id']), false, 'close-popover') ?>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -38,6 +38,9 @@
|
|||
<li <?= $this->app->checkMenuSelection('ProjectPermissionController') ?>>
|
||||
<?= $this->url->link(t('Permissions'), 'ProjectPermissionController', 'index', array('project_id' => $project['id'])) ?>
|
||||
</li>
|
||||
<li <?= $this->app->checkMenuSelection('ProjectRoleController') ?>>
|
||||
<?= $this->url->link(t('Custom roles'), 'ProjectRoleController', 'show', array('project_id' => $project['id'])) ?>
|
||||
</li>
|
||||
<?php endif ?>
|
||||
<li <?= $this->app->checkMenuSelection('ActionController') ?>>
|
||||
<?= $this->url->link(t('Automatic actions'), 'ActionController', 'index', array('project_id' => $project['id'])) ?>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
<section id="main">
|
||||
<div class="page-header">
|
||||
<h2><?= t('New custom project role') ?></h2>
|
||||
</div>
|
||||
<form class="popover-form" method="post" action="<?= $this->url->href('ProjectRoleController', 'save', array('project_id' => $project['id'])) ?>" autocomplete="off">
|
||||
<?= $this->form->csrf() ?>
|
||||
<?= $this->form->hidden('project_id', $values) ?>
|
||||
|
||||
<?= $this->form->label(t('Role'), 'role') ?>
|
||||
<?= $this->form->text('role', $values, $errors, array('autofocus', 'required', 'maxlength="50"')) ?>
|
||||
|
||||
<div class="form-actions">
|
||||
<button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
|
||||
<?= t('or') ?>
|
||||
<?= $this->url->link(t('cancel'), 'ProjectRoleController', 'show', array(), false, 'close-popover') ?>
|
||||
</div>
|
||||
</form>
|
||||
</section>
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
<div class="page-header">
|
||||
<h2><?= t('Remove a custom role') ?></h2>
|
||||
</div>
|
||||
|
||||
<div class="confirm">
|
||||
<p class="alert alert-info">
|
||||
<?= t('Do you really want to remove this custom role: "%s"? All people assigned to this role will become project member.', $role['role']) ?>
|
||||
</p>
|
||||
|
||||
<div class="form-actions">
|
||||
<?= $this->url->link(t('Yes'), 'ProjectRoleController', 'remove', array('project_id' => $project['id'], 'role_id' => $role['role_id']), true, 'btn btn-red') ?>
|
||||
<?= t('or') ?> <?= $this->url->link(t('cancel'), 'ProjectRoleController', 'show', array('project_id' => $project['id']), false, 'close-popover') ?>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
<div class="page-header">
|
||||
<h2><?= t('Custom Project Roles') ?></h2>
|
||||
<ul>
|
||||
<li>
|
||||
<i class="fa fa-plus fa-fw" aria-hidden="true"></i>
|
||||
<?= $this->url->link(t('Add a new custom role'), 'ProjectRoleController', 'create', array('project_id' => $project['id']), false, 'popover') ?>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<?php if (empty($roles)): ?>
|
||||
<div class="alert"><?= t('There is no custom role for this project.') ?></div>
|
||||
<?php else: ?>
|
||||
<?php foreach ($roles as $role): ?>
|
||||
<table class="table-striped">
|
||||
<tr>
|
||||
<th>
|
||||
<div class="dropdown">
|
||||
<a href="#" class="dropdown-menu"><?= t('Column restrictions for the role "%s"', $role['role']) ?> <i class="fa fa-caret-down"></i></a>
|
||||
<ul>
|
||||
<li>
|
||||
<i class="fa fa-plus fa-fw" aria-hidden="true"></i>
|
||||
<?= $this->url->link(t('Add a new column restriction'), 'ColumnMoveRestrictionController', 'create', array('project_id' => $project['id'], 'role_id' => $role['role_id']), false, 'popover') ?>
|
||||
</li>
|
||||
<li>
|
||||
<i class="fa fa-trash-o fa-fw" aria-hidden="true"></i>
|
||||
<?= $this->url->link(t('Remove this role'), 'ProjectRoleController', 'confirm', array('project_id' => $project['id'], 'role_id' => $role['role_id']), false, 'popover') ?>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</th>
|
||||
<th class="column-15">
|
||||
<?= t('Actions') ?>
|
||||
</th>
|
||||
</tr>
|
||||
<?php if (empty($role['restrictions'])): ?>
|
||||
<tr>
|
||||
<td colspan="2"><?= t('There is no restriction for this role.') ?></td>
|
||||
</tr>
|
||||
<?php else: ?>
|
||||
<?php foreach ($role['restrictions'] as $restriction): ?>
|
||||
<tr>
|
||||
<td>
|
||||
<i class="fa fa-ban fa-fw" aria-hidden="true"></i>
|
||||
<?= $this->text->e($restriction['src_column_title']) ?>
|
||||
<i class="fa fa-arrow-right fa-fw" aria-hidden="true"></i>
|
||||
<?= $this->text->e($restriction['dst_column_title']) ?>
|
||||
</td>
|
||||
<td>
|
||||
<i class="fa fa-trash-o fa-fw" aria-hidden="true"></i>
|
||||
<?= $this->url->link(t('Remove'), 'ColumnMoveRestrictionController', 'confirm', array('project_id' => $project['id'], 'restriction_id' => $restriction['restriction_id']), false, 'popover') ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach ?>
|
||||
<?php endif ?>
|
||||
</table>
|
||||
<?php endforeach ?>
|
||||
<?php endif ?>
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
<?php
|
||||
|
||||
namespace Kanboard\Validator;
|
||||
|
||||
use SimpleValidator\Validator;
|
||||
use SimpleValidator\Validators;
|
||||
|
||||
/**
|
||||
* Class ColumnMoveRestrictionValidator
|
||||
*
|
||||
* @package Kanboard\Validator
|
||||
* @author Frederic Guillot
|
||||
*/
|
||||
class ColumnMoveRestrictionValidator extends BaseValidator
|
||||
{
|
||||
/**
|
||||
* Validate 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, array(
|
||||
new Validators\Required('project_id', t('This field is required')),
|
||||
new Validators\Integer('project_id', t('This value must be an integer')),
|
||||
new Validators\Required('role_id', t('This field is required')),
|
||||
new Validators\Integer('role_id', t('This value must be an integer')),
|
||||
new Validators\Required('src_column_id', t('This field is required')),
|
||||
new Validators\Integer('src_column_id', t('This value must be an integer')),
|
||||
new Validators\Required('dst_column_id', t('This field is required')),
|
||||
new Validators\Integer('dst_column_id', t('This value must be an integer')),
|
||||
));
|
||||
|
||||
return array(
|
||||
$v->execute(),
|
||||
$v->getErrors()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
<?php
|
||||
|
||||
namespace Kanboard\Validator;
|
||||
|
||||
use SimpleValidator\Validator;
|
||||
use SimpleValidator\Validators;
|
||||
|
||||
/**
|
||||
* Class ProjectRoleValidator
|
||||
*
|
||||
* @package Kanboard\Validator
|
||||
* @author Frederic Guillot
|
||||
*/
|
||||
class ProjectRoleValidator extends BaseValidator
|
||||
{
|
||||
/**
|
||||
* Validate 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 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('The id is required')),
|
||||
);
|
||||
|
||||
$v = new Validator($values, array_merge($rules, $this->commonValidationRules()));
|
||||
|
||||
return array(
|
||||
$v->execute(),
|
||||
$v->getErrors()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Common validation rules
|
||||
*
|
||||
* @access private
|
||||
* @return array
|
||||
*/
|
||||
private function commonValidationRules()
|
||||
{
|
||||
return array(
|
||||
new Validators\Required('role', t('This field is required')),
|
||||
new Validators\MaxLength('role', t('The maximum length is %d characters', 100), 100),
|
||||
new Validators\Required('project_id', t('This field is required')),
|
||||
new Validators\Integer('project_id', t('This value must be an integer')),
|
||||
new Validators\Integer('id', t('This value must be an integer')),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -25,13 +25,13 @@ function array_merge_relation(array &$input, array &$relations, $relation, $colu
|
|||
* Create indexed array from a list of dict
|
||||
*
|
||||
* $input = [
|
||||
* ['k1' => 1, 'k2' => 2], ['k1' => 3, 'k2' => 4], ['k1' => 2, 'k2' => 5]
|
||||
* ['k1' => 1, 'k2' => 2], ['k1' => 3, 'k2' => 4], ['k1' => 1, 'k2' => 5]
|
||||
* ]
|
||||
*
|
||||
* array_column_index($input, 'k1') will returns:
|
||||
*
|
||||
* [
|
||||
* 1 => [['k1' => 1, 'k2' => 2], ['k1' => 2, 'k2' => 5]],
|
||||
* 1 => [['k1' => 1, 'k2' => 2], ['k1' => 1, 'k2' => 5]],
|
||||
* 3 => [['k1' => 3, 'k2' => 4]],
|
||||
* ]
|
||||
*
|
||||
|
|
|
|||
|
|
@ -32,6 +32,54 @@ class ColumnMoveRestrictionModelTest extends Base
|
|||
$this->assertTrue($columnMoveRestrictionModel->remove(1));
|
||||
}
|
||||
|
||||
public function testGetById()
|
||||
{
|
||||
$projectModel = new ProjectModel($this->container);
|
||||
$projectRoleModel = new ProjectRoleModel($this->container);
|
||||
$columnMoveRestrictionModel = new ColumnMoveRestrictionModel($this->container);
|
||||
|
||||
$this->assertEquals(1, $projectModel->create(array('name' => 'Test')));
|
||||
$this->assertEquals(2, $projectModel->create(array('name' => 'Test')));
|
||||
$this->assertEquals(1, $projectRoleModel->create(1, 'Role A'));
|
||||
$this->assertEquals(1, $columnMoveRestrictionModel->create(1, 1, 2, 3));
|
||||
|
||||
$restriction = $columnMoveRestrictionModel->getById(1, 1);
|
||||
$this->assertEquals(1, $restriction['restriction_id']);
|
||||
$this->assertEquals('Role A', $restriction['role']);
|
||||
$this->assertEquals(1, $restriction['role_id']);
|
||||
$this->assertEquals(1, $restriction['project_id']);
|
||||
$this->assertEquals('Ready', $restriction['src_column_title']);
|
||||
$this->assertEquals('Work in progress', $restriction['dst_column_title']);
|
||||
$this->assertEquals(2, $restriction['src_column_id']);
|
||||
$this->assertEquals(3, $restriction['dst_column_id']);
|
||||
}
|
||||
|
||||
public function testGetSrcColumns()
|
||||
{
|
||||
$projectModel = new ProjectModel($this->container);
|
||||
$projectRoleModel = new ProjectRoleModel($this->container);
|
||||
$columnMoveRestrictionModel = new ColumnMoveRestrictionModel($this->container);
|
||||
|
||||
$this->assertEquals(1, $projectModel->create(array('name' => 'Test')));
|
||||
$this->assertEquals(2, $projectModel->create(array('name' => 'Test')));
|
||||
|
||||
$this->assertEquals(1, $projectRoleModel->create(1, 'Role A'));
|
||||
$this->assertEquals(2, $projectRoleModel->create(1, 'Role B'));
|
||||
$this->assertEquals(3, $projectRoleModel->create(2, 'Role C'));
|
||||
|
||||
$this->assertEquals(1, $columnMoveRestrictionModel->create(1, 1, 2, 3));
|
||||
$this->assertEquals(2, $columnMoveRestrictionModel->create(1, 2, 3, 4));
|
||||
|
||||
$columnIds = $columnMoveRestrictionModel->getAllSrcColumns(1, 'Role A');
|
||||
$this->assertEquals(2, $columnIds[2]);
|
||||
|
||||
$this->assertEmpty($columnMoveRestrictionModel->getAllSrcColumns(2, 'Role A'));
|
||||
$this->assertEmpty($columnMoveRestrictionModel->getAllSrcColumns(2, 'Role C'));
|
||||
|
||||
$columnIds = $columnMoveRestrictionModel->getAllSrcColumns(1, 'Role B');
|
||||
$this->assertEquals(3, $columnIds[3]);
|
||||
}
|
||||
|
||||
public function testGetAll()
|
||||
{
|
||||
$projectModel = new ProjectModel($this->container);
|
||||
|
|
@ -53,6 +101,8 @@ class ColumnMoveRestrictionModelTest extends Base
|
|||
|
||||
$this->assertEquals(1, $restrictions[0]['restriction_id']);
|
||||
$this->assertEquals('Role A', $restrictions[0]['role']);
|
||||
$this->assertEquals(1, $restrictions[0]['role_id']);
|
||||
$this->assertEquals(1, $restrictions[0]['project_id']);
|
||||
$this->assertEquals('Ready', $restrictions[0]['src_column_title']);
|
||||
$this->assertEquals('Work in progress', $restrictions[0]['dst_column_title']);
|
||||
$this->assertEquals(2, $restrictions[0]['src_column_id']);
|
||||
|
|
|
|||
|
|
@ -1,7 +1,12 @@
|
|||
<?php
|
||||
|
||||
use Kanboard\Core\Security\Role;
|
||||
use Kanboard\Model\GroupMemberModel;
|
||||
use Kanboard\Model\GroupModel;
|
||||
use Kanboard\Model\ProjectGroupRoleModel;
|
||||
use Kanboard\Model\ProjectModel;
|
||||
use Kanboard\Model\ProjectRoleModel;
|
||||
use Kanboard\Model\ProjectUserRoleModel;
|
||||
|
||||
require_once __DIR__.'/../Base.php';
|
||||
|
||||
|
|
@ -46,14 +51,79 @@ class ProjectRoleModelTest extends Base
|
|||
$this->assertTrue($projectRoleModel->update(1, 1, 'Role B'));
|
||||
}
|
||||
|
||||
public function testRemove()
|
||||
public function testRemoveWithUserRole()
|
||||
{
|
||||
$projectModel = new ProjectModel($this->container);
|
||||
$projectRoleModel = new ProjectRoleModel($this->container);
|
||||
$projectUserRoleModel = new ProjectUserRoleModel($this->container);
|
||||
|
||||
$this->assertEquals(1, $projectModel->create(array('name' => 'Test')));
|
||||
$this->assertEquals(1, $projectRoleModel->create(1, 'Role A'));
|
||||
$this->assertTrue($projectUserRoleModel->addUser(1, 1, 'Role A'));
|
||||
$this->assertEquals('Role A', $projectUserRoleModel->getUserRole(1, 1));
|
||||
|
||||
$this->assertTrue($projectRoleModel->remove(1, 1));
|
||||
$this->assertEmpty($projectRoleModel->getAll(1));
|
||||
$this->assertEquals(Role::PROJECT_MEMBER, $projectUserRoleModel->getUserRole(1, 1));
|
||||
}
|
||||
|
||||
public function testRemoveWithGroupRole()
|
||||
{
|
||||
$projectModel = new ProjectModel($this->container);
|
||||
$projectRoleModel = new ProjectRoleModel($this->container);
|
||||
$projectGroupRoleModel = new ProjectGroupRoleModel($this->container);
|
||||
$groupModel = new GroupModel($this->container);
|
||||
$groupMemberModel = new GroupMemberModel($this->container);
|
||||
|
||||
$this->assertEquals(1, $groupModel->create('Group A'));
|
||||
$this->assertTrue($groupMemberModel->addUser(1, 1));
|
||||
|
||||
$this->assertEquals(1, $projectModel->create(array('name' => 'Test')));
|
||||
$this->assertEquals(1, $projectRoleModel->create(1, 'Role A'));
|
||||
$this->assertTrue($projectGroupRoleModel->addGroup(1, 1, 'Role A'));
|
||||
$this->assertEquals('Role A', $projectGroupRoleModel->getUserRole(1, 1));
|
||||
|
||||
$this->assertTrue($projectRoleModel->remove(1, 1));
|
||||
$this->assertEmpty($projectRoleModel->getAll(1));
|
||||
$this->assertEquals(Role::PROJECT_MEMBER, $projectGroupRoleModel->getUserRole(1, 1));
|
||||
}
|
||||
|
||||
public function testGetRoleListWithoutCustomRoles()
|
||||
{
|
||||
$projectModel = new ProjectModel($this->container);
|
||||
$projectRoleModel = new ProjectRoleModel($this->container);
|
||||
|
||||
$this->assertEquals(1, $projectModel->create(array('name' => 'Test')));
|
||||
|
||||
$roles = $projectRoleModel->getList(1);
|
||||
$this->assertCount(3, $roles);
|
||||
$this->assertEquals('Project Manager', $roles[Role::PROJECT_MANAGER]);
|
||||
}
|
||||
|
||||
public function testGetRoleListWithCustomRoles()
|
||||
{
|
||||
$projectModel = new ProjectModel($this->container);
|
||||
$projectRoleModel = new ProjectRoleModel($this->container);
|
||||
|
||||
$this->assertEquals(1, $projectModel->create(array('name' => 'Test')));
|
||||
$this->assertEquals(1, $projectRoleModel->create(1, 'Role A'));
|
||||
$this->assertTrue($projectRoleModel->remove(1, 1));
|
||||
$this->assertEmpty($projectRoleModel->getAll(1));
|
||||
|
||||
$roles = $projectRoleModel->getList(1);
|
||||
$this->assertCount(4, $roles);
|
||||
$this->assertEquals('Role A', $roles['Role A']);
|
||||
}
|
||||
|
||||
public function testGetById()
|
||||
{
|
||||
$projectModel = new ProjectModel($this->container);
|
||||
$projectRoleModel = new ProjectRoleModel($this->container);
|
||||
|
||||
$this->assertEquals(1, $projectModel->create(array('name' => 'Test')));
|
||||
$this->assertEquals(1, $projectRoleModel->create(1, 'Role A'));
|
||||
|
||||
$role = $projectRoleModel->getById(1, 1);
|
||||
$this->assertEquals(1, $role['role_id']);
|
||||
$this->assertEquals(1, $role['project_id']);
|
||||
$this->assertEquals('Role A', $role['role']);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue