Add column restrictions to custom project roles

This commit is contained in:
Frederic Guillot 2016-09-18 21:19:48 -04:00
parent 4bc83646b0
commit 3043163747
No known key found for this signature in database
GPG Key ID: 92D77191BA7FBC99
33 changed files with 1132 additions and 68 deletions

View File

@ -0,0 +1,103 @@
<?php
namespace Kanboard\Controller;
use Kanboard\Core\Controller\AccessForbiddenException;
/**
* Class ColumnMoveRestrictionController
*
* @package Kanboard\Controller
* @author Frederic Guillot
*/
class ColumnRestrictionController 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_restriction/create', array(
'project' => $project,
'role' => $role,
'rules' => $this->columnRestrictionModel->getRules(),
'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->columnRestrictionValidator->validateCreation($values);
if ($valid) {
$restriction_id = $this->columnRestrictionModel->create(
$project['id'],
$values['role_id'],
$values['column_id'],
$values['rule']
);
if ($restriction_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_restriction/remove', array(
'project' => $project,
'restriction' => $this->columnRestrictionModel->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->columnRestrictionModel->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'])));
}
}

View File

@ -52,12 +52,16 @@ class TaskCreationController extends BaseController
list($valid, $errors) = $this->taskValidator->validateCreation($values);
if ($valid && ($task_id = $this->taskCreationModel->create($values))) {
$this->flash->success(t('Task created successfully.'));
$this->afterSave($project, $values, $task_id);
} else {
if (! $valid) {
$this->flash->failure(t('Unable to create your task.'));
$this->show($values, $errors);
} else if (! $this->helper->projectRole->canCreateTaskInColumn($project['id'], $values['column_id'])) {
$this->flash->failure(t('You cannot create tasks in this column.'));
$this->response->redirect($this->helper->url->to('BoardViewController', 'show', array('project_id' => $project['id'])), true);
} else {
$task_id = $this->taskCreationModel->create($values);
$this->flash->success(t('Task created successfully.'));
$this->afterSave($project, $values, $task_id);
}
}

View File

@ -2,6 +2,7 @@
namespace Kanboard\Controller;
use Kanboard\Core\Controller\AccessForbiddenException;
use Kanboard\Formatter\BoardFormatter;
/**

View File

@ -57,7 +57,9 @@ use Pimple\Container;
* @property \Kanboard\Core\Paginator $paginator
* @property \Kanboard\Core\Template $template
* @property \Kanboard\Decorator\MetadataCacheDecorator $userMetadataCacheDecorator
* @property \Kanboard\Decorator\columnRestrictionCacheDecorator $columnRestrictionCacheDecorator
* @property \Kanboard\Decorator\ColumnMoveRestrictionCacheDecorator $columnMoveRestrictionCacheDecorator
* @property \Kanboard\Decorator\ProjectRoleRestrictionCacheDecorator $projectRoleRestrictionCacheDecorator
* @property \Kanboard\Model\ActionModel $actionModel
* @property \Kanboard\Model\ActionParameterModel $actionParameterModel
* @property \Kanboard\Model\AvatarFileModel $avatarFileModel
@ -65,6 +67,7 @@ use Pimple\Container;
* @property \Kanboard\Model\CategoryModel $categoryModel
* @property \Kanboard\Model\ColorModel $colorModel
* @property \Kanboard\Model\ColumnModel $columnModel
* @property \Kanboard\Model\ColumnRestrictionModel $columnRestrictionModel
* @property \Kanboard\Model\ColumnMoveRestrictionModel $columnMoveRestrictionModel
* @property \Kanboard\Model\CommentModel $commentModel
* @property \Kanboard\Model\ConfigModel $configModel
@ -136,6 +139,7 @@ use Pimple\Container;
* @property \Kanboard\Validator\AuthValidator $authValidator
* @property \Kanboard\Validator\ColumnValidator $columnValidator
* @property \Kanboard\Validator\CategoryValidator $categoryValidator
* @property \Kanboard\Validator\ColumnRestrictionValidator $columnRestrictionValidator
* @property \Kanboard\Validator\ColumnMoveRestrictionValidator $columnMoveRestrictionValidator
* @property \Kanboard\Validator\CommentValidator $commentValidator
* @property \Kanboard\Validator\CurrencyValidator $currencyValidator

View File

@ -40,7 +40,8 @@ class ColumnMoveRestrictionCacheDecorator
/**
* Proxy method to get sortable columns
*
* @param int $project_id
* @param int $project_id
* @param string $role
* @return array|mixed
*/
public function getSortableColumns($project_id, $role)

View File

@ -0,0 +1,59 @@
<?php
namespace Kanboard\Decorator;
use Kanboard\Core\Cache\CacheInterface;
use Kanboard\Model\ColumnRestrictionModel;
/**
* Class ColumnRestrictionCacheDecorator
*
* @package Kanboard\Decorator
* @author Frederic Guillot
*/
class ColumnRestrictionCacheDecorator
{
protected $cachePrefix = 'column_restriction:';
/**
* @var CacheInterface
*/
protected $cache;
/**
* @var ColumnRestrictionModel
*/
protected $columnRestrictionModel;
/**
* ColumnMoveRestrictionDecorator constructor.
*
* @param CacheInterface $cache
* @param ColumnRestrictionModel $columnMoveRestrictionModel
*/
public function __construct(CacheInterface $cache, ColumnRestrictionModel $columnMoveRestrictionModel)
{
$this->cache = $cache;
$this->columnRestrictionModel = $columnMoveRestrictionModel;
}
/**
* Proxy method to get sortable columns
*
* @param int $project_id
* @param string $role
* @return array|mixed
*/
public function getAllByRole($project_id, $role)
{
$key = $this->cachePrefix.$project_id.$role;
$columnRestrictions = $this->cache->get($key);
if ($columnRestrictions === null) {
$columnRestrictions = $this->columnRestrictionModel->getAllByRole($project_id, $role);
$this->cache->set($key, $columnRestrictions);
}
return $columnRestrictions;
}
}

View File

@ -0,0 +1,59 @@
<?php
namespace Kanboard\Decorator;
use Kanboard\Core\Cache\CacheInterface;
use Kanboard\Model\ProjectRoleRestrictionModel;
/**
* Class ProjectRoleRestrictionCacheDecorator
*
* @package Kanboard\Decorator
* @author Frederic Guillot
*/
class ProjectRoleRestrictionCacheDecorator
{
protected $cachePrefix = 'project_restriction:';
/**
* @var CacheInterface
*/
protected $cache;
/**
* @var ProjectRoleRestrictionModel
*/
protected $projectRoleRestrictionModel;
/**
* ColumnMoveRestrictionDecorator constructor.
*
* @param CacheInterface $cache
* @param ProjectRoleRestrictionModel $projectRoleRestrictionModel
*/
public function __construct(CacheInterface $cache, ProjectRoleRestrictionModel $projectRoleRestrictionModel)
{
$this->cache = $cache;
$this->projectRoleRestrictionModel = $projectRoleRestrictionModel;
}
/**
* Proxy method to get sortable columns
*
* @param int $project_id
* @param string $role
* @return array|mixed
*/
public function getAllByRole($project_id, $role)
{
$key = $this->cachePrefix.$project_id.$role;
$projectRestrictions = $this->cache->get($key);
if ($projectRestrictions === null) {
$projectRestrictions = $this->projectRoleRestrictionModel->getAllByRole($project_id, $role);
$this->cache->set($key, $projectRestrictions);
}
return $projectRestrictions;
}
}

View File

@ -4,6 +4,8 @@ namespace Kanboard\Helper;
use Kanboard\Core\Base;
use Kanboard\Core\Security\Role;
use Kanboard\Model\ColumnRestrictionModel;
use Kanboard\Model\ProjectRoleRestrictionModel;
/**
* Class ProjectRoleHelper
@ -98,6 +100,46 @@ class ProjectRoleHelper extends Base
return true;
}
/**
* Return true if the user can create a task for the given column
*
* @param int $project_id
* @param int $column_id
* @return bool
*/
public function canCreateTaskInColumn($project_id, $column_id)
{
$role = $this->getProjectUserRole($project_id);
if ($this->role->isCustomProjectRole($role)) {
if (! $this->isAllowedToCreateTask($project_id, $column_id, $role)) {
return false;
}
}
return $this->helper->user->hasProjectAccess('TaskCreationController', 'show', $project_id);
}
/**
* Return true if the user can create a task for the given column
*
* @param int $project_id
* @param int $column_id
* @return bool
*/
public function canChangeTaskStatusInColumn($project_id, $column_id)
{
$role = $this->getProjectUserRole($project_id);
if ($this->role->isCustomProjectRole($role)) {
if (! $this->isAllowedToChangeTaskStatus($project_id, $column_id, $role)) {
return false;
}
}
return $this->helper->user->hasProjectAccess('TaskStatusController', 'close', $project_id);
}
/**
* Return true if the user can remove a task
*
@ -145,13 +187,77 @@ class ProjectRoleHelper extends Base
$role = $this->getProjectUserRole($project_id);
if ($this->role->isCustomProjectRole($role)) {
$restrictions = $this->projectRoleRestrictionModel->getAllByRole($project_id, $role);
$result = $this->projectRoleRestrictionModel->isAllowed($restrictions, $controller, $action);
$result = $result && $this->projectAuthorization->isAllowed($controller, $action, Role::PROJECT_MEMBER);
$result = $this->projectAuthorization->isAllowed($controller, $action, Role::PROJECT_MEMBER);
} else {
$result = $this->projectAuthorization->isAllowed($controller, $action, $role);
}
return $result;
}
/**
* Check authorization for a custom project role to change the task status
*
* @param int $project_id
* @param int $column_id
* @param string $role
* @return bool
*/
protected function isAllowedToChangeTaskStatus($project_id, $column_id, $role)
{
$columnRestrictions = $this->columnRestrictionCacheDecorator->getAllByRole($project_id, $role);
foreach ($columnRestrictions as $restriction) {
if ($restriction['column_id'] == $column_id) {
if ($restriction['rule'] == ColumnRestrictionModel::RULE_ALLOW_TASK_OPEN_CLOSE) {
return true;
} else if ($restriction['rule'] == ColumnRestrictionModel::RULE_BLOCK_TASK_OPEN_CLOSE) {
return false;
}
}
}
$projectRestrictions = $this->projectRoleRestrictionCacheDecorator->getAllByRole($project_id, $role);
foreach ($projectRestrictions as $restriction) {
if ($restriction['rule'] == ProjectRoleRestrictionModel::RULE_TASK_OPEN_CLOSE) {
return false;
}
}
return true;
}
/**
* Check authorization for a custom project role to create a task
*
* @param int $project_id
* @param int $column_id
* @param string $role
* @return bool
*/
protected function isAllowedToCreateTask($project_id, $column_id, $role)
{
$columnRestrictions = $this->columnRestrictionCacheDecorator->getAllByRole($project_id, $role);
foreach ($columnRestrictions as $restriction) {
if ($restriction['column_id'] == $column_id) {
if ($restriction['rule'] == ColumnRestrictionModel::RULE_ALLOW_TASK_CREATION) {
return true;
} else if ($restriction['rule'] == ColumnRestrictionModel::RULE_BLOCK_TASK_CREATION) {
return false;
}
}
}
$projectRestrictions = $this->projectRoleRestrictionCacheDecorator->getAllByRole($project_id, $role);
foreach ($projectRestrictions as $restriction) {
if ($restriction['rule'] == ProjectRoleRestrictionModel::RULE_TASK_CREATION) {
return false;
}
}
return true;
}
}

View File

@ -0,0 +1,152 @@
<?php
namespace Kanboard\Model;
use Kanboard\Core\Base;
/**
* Class ColumnRestrictionModel
*
* @package Kanboard\Model
* @author Frederic Guillot
*/
class ColumnRestrictionModel extends Base
{
const TABLE = 'column_has_restrictions';
const RULE_ALLOW_TASK_CREATION = 'allow.task_creation';
const RULE_ALLOW_TASK_OPEN_CLOSE = 'allow.task_open_close';
const RULE_BLOCK_TASK_CREATION = 'block.task_creation';
const RULE_BLOCK_TASK_OPEN_CLOSE = 'block.task_open_close';
/**
* Get rules
*
* @return array
*/
public function getRules()
{
return array(
self::RULE_ALLOW_TASK_CREATION => t('Task creation is permitted for this column'),
self::RULE_ALLOW_TASK_OPEN_CLOSE => t('Closing or opening a task is permitted for this column'),
self::RULE_BLOCK_TASK_CREATION => t('Task creation is blocked for this column'),
self::RULE_BLOCK_TASK_OPEN_CLOSE => t('Closing or opening a task is blocked for this column'),
);
}
/**
* 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.'.column_id',
self::TABLE.'.rule',
'pr.role',
'c.title as column_title'
)
->left(ColumnModel::TABLE, 'c', 'id', self::TABLE, '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
*
* @param int $project_id
* @return array
*/
public function getAll($project_id)
{
$rules = $this->getRules();
$restrictions = $this->db
->table(self::TABLE)
->columns(
self::TABLE.'.restriction_id',
self::TABLE.'.project_id',
self::TABLE.'.role_id',
self::TABLE.'.column_id',
self::TABLE.'.rule',
'pr.role',
'c.title as column_title'
)
->left(ColumnModel::TABLE, 'c', 'id', self::TABLE, 'column_id')
->left(ProjectRoleModel::TABLE, 'pr', 'role_id', self::TABLE, 'role_id')
->eq(self::TABLE.'.project_id', $project_id)
->findAll();
foreach ($restrictions as &$restriction) {
$restriction['title'] = $rules[$restriction['rule']];
}
return $restrictions;
}
/**
* Get restrictions
*
* @param int $project_id
* @param string $role
* @return array
*/
public function getAllByRole($project_id, $role)
{
return $this->db
->table(self::TABLE)
->columns(
self::TABLE.'.restriction_id',
self::TABLE.'.project_id',
self::TABLE.'.role_id',
self::TABLE.'.column_id',
self::TABLE.'.rule',
'pr.role'
)
->eq(self::TABLE.'.project_id', $project_id)
->eq('pr.role', $role)
->left(ProjectRoleModel::TABLE, 'pr', 'role_id', self::TABLE, 'role_id')
->findAll();
}
/**
* Create a new column restriction
*
* @param int $project_id
* @param int $role_id
* @param int $column_id
* @param int $rule
* @return bool|int
*/
public function create($project_id, $role_id, $column_id, $rule)
{
return $this->db
->table(self::TABLE)
->persist(array(
'project_id' => $project_id,
'role_id' => $role_id,
'column_id' => $column_id,
'rule' => $rule,
));
}
/**
* Remove a permission
*
* @param int $restriction_id
* @return bool
*/
public function remove($restriction_id)
{
return $this->db->table(self::TABLE)->eq('restriction_id', $restriction_id)->remove();
}
}

View File

@ -122,8 +122,13 @@ class ProjectPermissionModel extends Base
*/
public function isAssignable($project_id, $user_id)
{
return $this->userModel->isActive($user_id) &&
in_array($this->projectUserRoleModel->getUserRole($project_id, $user_id), array(Role::PROJECT_MEMBER, Role::PROJECT_MANAGER));
if ($this->userModel->isActive($user_id)) {
$role = $this->projectUserRoleModel->getUserRole($project_id, $user_id);
return ! empty($role) && $role !== Role::PROJECT_VIEWER;
}
return false;
}
/**

View File

@ -71,10 +71,14 @@ class ProjectRoleModel extends Base
{
$roles = $this->getAll($project_id);
$column_restrictions = $this->columnMoveRestrictionModel->getAll($project_id);
$column_restrictions = $this->columnRestrictionModel->getAll($project_id);
$column_restrictions = array_column_index($column_restrictions, 'role_id');
array_merge_relation($roles, $column_restrictions, 'column_restrictions', 'role_id');
$column_move_restrictions = $this->columnMoveRestrictionModel->getAll($project_id);
$column_move_restrictions = array_column_index($column_move_restrictions, 'role_id');
array_merge_relation($roles, $column_move_restrictions, 'column_move_restrictions', 'role_id');
$project_restrictions = $this->projectRoleRestrictionModel->getAll($project_id);
$project_restrictions = array_column_index($project_restrictions, 'role_id');
array_merge_relation($roles, $project_restrictions, 'project_restrictions', 'role_id');
@ -109,13 +113,41 @@ class ProjectRoleModel extends Base
*/
public function update($role_id, $project_id, $role)
{
return $this->db
$this->db->startTransaction();
$previousRole = $this->getById($project_id, $role_id);
$r1 = $this->db
->table(ProjectUserRoleModel::TABLE)
->eq('project_id', $project_id)
->eq('role', $previousRole['role'])
->update(array(
'role' => $role
));
$r2 = $this->db
->table(ProjectGroupRoleModel::TABLE)
->eq('project_id', $project_id)
->eq('role', $previousRole['role'])
->update(array(
'role' => $role
));
$r3 = $this->db
->table(self::TABLE)
->eq('role_id', $role_id)
->eq('project_id', $project_id)
->update(array(
'role' => $role,
));
if ($r1 && $r2 && $r3) {
$this->db->closeTransaction();
return true;
}
$this->db->cancelTransaction();
return false;
}
/**

View File

@ -17,15 +17,6 @@ class ProjectRoleRestrictionModel extends Base
const RULE_TASK_CREATION = 'task_creation';
const RULE_TASK_OPEN_CLOSE = 'task_open_close';
protected $ruleMapping = array(
self::RULE_TASK_CREATION => array(
array('controller' => 'TaskCreationController', 'method' => '*'),
),
self::RULE_TASK_OPEN_CLOSE => array(
array('controller' => 'TaskStatusController', 'method' => '*'),
)
);
/**
* Get rules
*
@ -91,7 +82,7 @@ class ProjectRoleRestrictionModel extends Base
*/
public function getAllByRole($project_id, $role)
{
$rules = $this->db
return $this->db
->table(self::TABLE)
->columns(
self::TABLE.'.restriction_id',
@ -104,12 +95,6 @@ class ProjectRoleRestrictionModel extends Base
->eq('role', $role)
->left(ProjectRoleModel::TABLE, 'pr', 'role_id', self::TABLE, 'role_id')
->findAll();
foreach ($rules as &$rule) {
$rule['acl'] = $this->ruleMapping[$rule['rule']];
}
return $rules;
}
/**
@ -140,31 +125,4 @@ class ProjectRoleRestrictionModel extends Base
{
return $this->db->table(self::TABLE)->eq('restriction_id', $restriction_id)->remove();
}
/**
* Check if the controller/method is allowed
*
* @param array $restrictions
* @param string $controller
* @param string $method
* @return bool
*/
public function isAllowed(array $restrictions, $controller, $method)
{
$controller = strtolower($controller);
$method = strtolower($method);
foreach ($restrictions as $restriction) {
foreach ($restriction['acl'] as $acl) {
$acl['controller'] = strtolower($acl['controller']);
$acl['method'] = strtolower($acl['method']);
if ($acl['controller'] === $controller && ($acl['method'] === '*' || $acl['method'] === $method)) {
return false;
}
}
}
return true;
}
}

View File

@ -166,7 +166,7 @@ class ProjectUserRoleModel extends Base
->join(UserModel::TABLE, 'id', 'user_id')
->eq(UserModel::TABLE.'.is_active', 1)
->eq(self::TABLE.'.project_id', $project_id)
->in(self::TABLE.'.role', array(Role::PROJECT_MANAGER, Role::PROJECT_MEMBER))
->neq(self::TABLE.'.role', Role::PROJECT_VIEWER)
->findAll();
$groupMembers = $this->projectGroupRoleModel->getAssignableUsers($project_id);

View File

@ -67,6 +67,7 @@ class TaskFinderModel extends Base
TaskModel::TABLE.'.date_due',
TaskModel::TABLE.'.date_creation',
TaskModel::TABLE.'.project_id',
TaskModel::TABLE.'.column_id',
TaskModel::TABLE.'.color_id',
TaskModel::TABLE.'.priority',
TaskModel::TABLE.'.time_spent',

View File

@ -6,7 +6,25 @@ use PDO;
use Kanboard\Core\Security\Token;
use Kanboard\Core\Security\Role;
const VERSION = 114;
const VERSION = 115;
function version_115(PDO $pdo)
{
$pdo->exec("
CREATE TABLE column_has_restrictions (
restriction_id INT NOT NULL AUTO_INCREMENT,
project_id INT NOT NULL,
role_id INT NOT NULL,
column_id INT NOT NULL,
rule VARCHAR(255) NOT NULL,
UNIQUE(role_id, column_id, rule),
FOREIGN KEY(project_id) REFERENCES projects(id) ON DELETE CASCADE,
FOREIGN KEY(role_id) REFERENCES project_has_roles(role_id) ON DELETE CASCADE,
FOREIGN KEY(column_id) REFERENCES columns(id) ON DELETE CASCADE,
PRIMARY KEY(restriction_id)
) ENGINE=InnoDB CHARSET=utf8
");
}
function version_114(PDO $pdo)
{

View File

@ -6,7 +6,24 @@ use PDO;
use Kanboard\Core\Security\Token;
use Kanboard\Core\Security\Role;
const VERSION = 93;
const VERSION = 94;
function version_94(PDO $pdo)
{
$pdo->exec("
CREATE TABLE column_has_restrictions (
restriction_id SERIAL PRIMARY KEY,
project_id INTEGER NOT NULL,
role_id INTEGER NOT NULL,
column_id INTEGER NOT NULL,
rule VARCHAR(255) NOT NULL,
UNIQUE(role_id, column_id, rule),
FOREIGN KEY(project_id) REFERENCES projects(id) ON DELETE CASCADE,
FOREIGN KEY(role_id) REFERENCES project_has_roles(role_id) ON DELETE CASCADE,
FOREIGN KEY(column_id) REFERENCES columns(id) ON DELETE CASCADE
)
");
}
function version_93(PDO $pdo)
{

View File

@ -6,7 +6,24 @@ use Kanboard\Core\Security\Token;
use Kanboard\Core\Security\Role;
use PDO;
const VERSION = 105;
const VERSION = 106;
function version_106(PDO $pdo)
{
$pdo->exec("
CREATE TABLE column_has_restrictions (
restriction_id INTEGER PRIMARY KEY,
project_id INTEGER NOT NULL,
role_id INTEGER NOT NULL,
column_id INTEGER NOT NULL,
rule VARCHAR(255) NOT NULL,
UNIQUE(role_id, column_id, rule),
FOREIGN KEY(project_id) REFERENCES projects(id) ON DELETE CASCADE,
FOREIGN KEY(role_id) REFERENCES project_has_roles(role_id) ON DELETE CASCADE,
FOREIGN KEY(column_id) REFERENCES columns(id) ON DELETE CASCADE
)
");
}
function version_105(PDO $pdo)
{

View File

@ -5,7 +5,9 @@ namespace Kanboard\ServiceProvider;
use Kanboard\Core\Cache\FileCache;
use Kanboard\Core\Cache\MemoryCache;
use Kanboard\Decorator\ColumnMoveRestrictionCacheDecorator;
use Kanboard\Decorator\ColumnRestrictionCacheDecorator;
use Kanboard\Decorator\MetadataCacheDecorator;
use Kanboard\Decorator\ProjectRoleRestrictionCacheDecorator;
use Pimple\Container;
use Pimple\ServiceProviderInterface;
@ -54,6 +56,20 @@ class CacheProvider implements ServiceProviderInterface
);
};
$container['columnRestrictionCacheDecorator'] = function($c) {
return new ColumnRestrictionCacheDecorator(
$c['memoryCache'],
$c['columnRestrictionModel']
);
};
$container['projectRoleRestrictionCacheDecorator'] = function($c) {
return new ProjectRoleRestrictionCacheDecorator(
$c['memoryCache'],
$c['projectRoleRestrictionModel']
);
};
return $container;
}
}

View File

@ -34,6 +34,7 @@ class ClassProvider implements ServiceProviderInterface
'CategoryModel',
'ColorModel',
'ColumnModel',
'ColumnRestrictionModel',
'ColumnMoveRestrictionModel',
'CommentModel',
'ConfigModel',
@ -101,6 +102,7 @@ class ClassProvider implements ServiceProviderInterface
'AuthValidator',
'CategoryValidator',
'ColumnMoveRestrictionValidator',
'ColumnRestrictionValidator',
'ColumnValidator',
'CommentValidator',
'CurrencyValidator',

View File

@ -12,7 +12,7 @@
<!-- column in expanded mode -->
<div class="board-column-expanded">
<?php if (! $not_editable && $this->user->hasProjectAccess('TaskCreationController', 'show', $column['project_id'])): ?>
<?php if (! $not_editable && $this->projectRole->canCreateTaskInColumn($column['project_id'], $column['id'])): ?>
<div class="board-add-icon">
<?= $this->url->link('+', 'TaskCreationController', 'show', array('project_id' => $column['project_id'], 'column_id' => $column['id'], 'swimlane_id' => $swimlane['id']), false, 'popover', t('Add a new task')) ?>
</div>

View File

@ -1,6 +1,6 @@
<section id="main">
<div class="page-header">
<h2><?= t('New column restriction for the role "%s"', $role['role']) ?></h2>
<h2><?= t('New drag and drop 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() ?>

View File

@ -0,0 +1,22 @@
<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('ColumnRestrictionController', '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('Rule'), 'rule') ?>
<?= $this->form->select('rule', $rules, $values, $errors) ?>
<?= $this->form->label(t('Column'), 'column_id') ?>
<?= $this->form->select('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>
</form>
</section>

View File

@ -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?') ?>
</p>
<div class="form-actions">
<?= $this->url->link(t('Yes'), 'ColumnRestrictionController', '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>

View File

@ -24,7 +24,11 @@
</li>
<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') ?>
<?= $this->url->link(t('Add a new drag and drop restriction'), 'ColumnMoveRestrictionController', 'create', array('project_id' => $project['id'], 'role_id' => $role['role_id']), false, 'popover') ?>
</li>
<li>
<i class="fa fa-plus fa-fw" aria-hidden="true"></i>
<?= $this->url->link(t('Add a new column restriction'), 'ColumnRestrictionController', 'create', array('project_id' => $project['id'], 'role_id' => $role['role_id']), false, 'popover') ?>
</li>
<li>
<i class="fa fa-pencil fa-fw" aria-hidden="true"></i>
@ -41,7 +45,7 @@
<?= t('Actions') ?>
</th>
</tr>
<?php if (empty($role['project_restrictions']) && empty($role['column_restrictions'])): ?>
<?php if (empty($role['project_restrictions']) && empty($role['column_restrictions']) && empty($role['column_move_restrictions'])): ?>
<tr>
<td colspan="2"><?= t('There is no restriction for this role.') ?></td>
</tr>
@ -49,6 +53,9 @@
<?php foreach ($role['project_restrictions'] as $restriction): ?>
<tr>
<td>
<i class="fa fa-ban fa-fw" aria-hidden="true"></i>
<strong><?= t('Project') ?></strong>
<i class="fa fa-arrow-right fa-fw" aria-hidden="true"></i>
<?= $this->text->e($restriction['title']) ?>
</td>
<td>
@ -60,7 +67,28 @@
<?php foreach ($role['column_restrictions'] as $restriction): ?>
<tr>
<td>
<?= t('Only moving task from the column "%s" to "%s" is permitted', $restriction['src_column_title'], $restriction['dst_column_title']) ?>
<?php if (strpos($restriction['rule'], 'block') === 0): ?>
<i class="fa fa-ban fa-fw" aria-hidden="true"></i>
<?php else: ?>
<i class="fa fa-check-circle-o fa-fw" aria-hidden="true"></i>
<?php endif ?>
<strong><?= $this->text->e($restriction['column_title']) ?></strong>
<i class="fa fa-arrow-right fa-fw" aria-hidden="true"></i>
<?= $this->text->e($restriction['title']) ?>
</td>
<td>
<i class="fa fa-trash-o fa-fw" aria-hidden="true"></i>
<?= $this->url->link(t('Remove'), 'ColumnRestrictionController', 'confirm', array('project_id' => $project['id'], 'restriction_id' => $restriction['restriction_id']), false, 'popover') ?>
</td>
</tr>
<?php endforeach ?>
<?php foreach ($role['column_move_restrictions'] as $restriction): ?>
<tr>
<td>
<i class="fa fa-check-circle-o fa-fw" aria-hidden="true"></i>
<strong><?= $this->text->e($restriction['src_column_title']) ?> / <?= $this->text->e($restriction['dst_column_title']) ?></strong>
<i class="fa fa-arrow-right fa-fw" aria-hidden="true"></i>
<?= t('Only moving task between those columns is permitted') ?>
</td>
<td>
<i class="fa fa-trash-o fa-fw" aria-hidden="true"></i>

View File

@ -49,7 +49,7 @@
<?= $this->url->link(t('Remove'), 'TaskSuppressionController', 'confirm', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?>
</li>
<?php endif ?>
<?php if (isset($task['is_active']) && $this->user->hasProjectAccess('TaskStatusController', 'close', $task['project_id'])): ?>
<?php if (isset($task['is_active']) && $this->projectRole->canChangeTaskStatusInColumn($task['project_id'], $task['column_id'])): ?>
<li>
<?php if ($task['is_active'] == 1): ?>
<i class="fa fa-times fa-fw"></i>

View File

@ -78,7 +78,7 @@
<i class="fa fa-clone fa-fw"></i>
<?= $this->url->link(t('Move to another project'), 'TaskDuplicationController', 'move', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?>
</li>
<?php if ($this->user->hasProjectAccess('TaskStatusController', 'close', $task['project_id'])): ?>
<?php if ($this->projectRole->canChangeTaskStatusInColumn($task['project_id'], $task['column_id'])): ?>
<?php if ($task['is_active'] == 1): ?>
<li>
<i class="fa fa-arrows fa-fw"></i>

View File

@ -0,0 +1,40 @@
<?php
namespace Kanboard\Validator;
use SimpleValidator\Validator;
use SimpleValidator\Validators;
/**
* Class ColumnRestrictionValidator
*
* @package Kanboard\Validator
* @author Frederic Guillot
*/
class ColumnRestrictionValidator 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('rule', t('This field is required')),
new Validators\Required('column_id', t('This field is required')),
new Validators\Integer('column_id', t('This value must be an integer')),
));
return array(
$v->execute(),
$v->getErrors()
);
}
}

View File

@ -4,8 +4,10 @@ use Kanboard\Core\Security\Role;
use Kanboard\Core\User\UserSession;
use Kanboard\Helper\ProjectRoleHelper;
use Kanboard\Model\ColumnMoveRestrictionModel;
use Kanboard\Model\ColumnRestrictionModel;
use Kanboard\Model\ProjectModel;
use Kanboard\Model\ProjectRoleModel;
use Kanboard\Model\ProjectRoleRestrictionModel;
use Kanboard\Model\ProjectUserRoleModel;
use Kanboard\Model\TaskCreationModel;
use Kanboard\Model\TaskFinderModel;
@ -16,6 +18,182 @@ require_once __DIR__.'/../Base.php';
class ProjectRoleHelperTest extends Base
{
public function testCanCreateTaskInColumnWithProjectViewer()
{
$projectRoleHelper = new ProjectRoleHelper($this->container);
$projectModel = new ProjectModel($this->container);
$projectUserRole = new ProjectUserRoleModel($this->container);
$userModel = new UserModel($this->container);
$this->container['sessionStorage']->user = array(
'id' => 2,
'role' => Role::APP_USER,
);
$this->assertEquals(2, $userModel->create(array('username' => 'user')));
$this->assertEquals(1, $projectModel->create(array('name' => 'Test')));
$this->assertTrue($projectUserRole->addUser(1, 2, Role::PROJECT_VIEWER));
$this->assertFalse($projectRoleHelper->canCreateTaskInColumn(1, 1));
}
public function testCanCreateTaskInColumnWithProjectMember()
{
$projectRoleHelper = new ProjectRoleHelper($this->container);
$projectModel = new ProjectModel($this->container);
$projectUserRole = new ProjectUserRoleModel($this->container);
$userModel = new UserModel($this->container);
$this->container['sessionStorage']->user = array(
'id' => 2,
'role' => Role::APP_USER,
);
$this->assertEquals(2, $userModel->create(array('username' => 'user')));
$this->assertEquals(1, $projectModel->create(array('name' => 'Test')));
$this->assertTrue($projectUserRole->addUser(1, 2, Role::PROJECT_MEMBER));
$this->assertTrue($projectRoleHelper->canCreateTaskInColumn(1, 1));
}
public function testCanCreateTaskInColumnWithCustomProjectRole()
{
$projectRoleHelper = new ProjectRoleHelper($this->container);
$projectModel = new ProjectModel($this->container);
$projectUserRole = new ProjectUserRoleModel($this->container);
$userModel = new UserModel($this->container);
$projectRoleModel = new ProjectRoleModel($this->container);
$this->container['sessionStorage']->user = array(
'id' => 2,
'role' => Role::APP_USER,
);
$this->assertEquals(2, $userModel->create(array('username' => 'user')));
$this->assertEquals(1, $projectModel->create(array('name' => 'Test')));
$this->assertEquals(1, $projectRoleModel->create(1, 'Custom Role'));
$this->assertTrue($projectUserRole->addUser(1, 2, 'Custom Role'));
$this->assertTrue($projectRoleHelper->canCreateTaskInColumn(1, 1));
}
public function testCanCreateTaskInColumnWithCustomProjectRoleAndRestrictions()
{
$projectRoleHelper = new ProjectRoleHelper($this->container);
$projectModel = new ProjectModel($this->container);
$projectUserRole = new ProjectUserRoleModel($this->container);
$userModel = new UserModel($this->container);
$projectRoleModel = new ProjectRoleModel($this->container);
$projectRoleRestrictionModel = new ProjectRoleRestrictionModel($this->container);
$columnRestrictionModel = new ColumnRestrictionModel($this->container);
$this->container['sessionStorage']->user = array(
'id' => 2,
'role' => Role::APP_USER,
);
$this->assertEquals(2, $userModel->create(array('username' => 'user')));
$this->assertEquals(1, $projectModel->create(array('name' => 'Test')));
$this->assertEquals(1, $projectRoleModel->create(1, 'Custom Role'));
$this->assertTrue($projectUserRole->addUser(1, 2, 'Custom Role'));
$this->assertEquals(1, $projectRoleRestrictionModel->create(1, 1, ProjectRoleRestrictionModel::RULE_TASK_CREATION));
$this->assertEquals(1, $columnRestrictionModel->create(1, 1, 1, ColumnRestrictionModel::RULE_ALLOW_TASK_CREATION));
$this->assertTrue($projectRoleHelper->canCreateTaskInColumn(1, 1));
$this->assertFalse($projectRoleHelper->canCreateTaskInColumn(1, 2));
}
public function testCanChangeTaskStatusInColumnWithProjectViewer()
{
$projectRoleHelper = new ProjectRoleHelper($this->container);
$projectModel = new ProjectModel($this->container);
$projectUserRole = new ProjectUserRoleModel($this->container);
$userModel = new UserModel($this->container);
$this->container['sessionStorage']->user = array(
'id' => 2,
'role' => Role::APP_USER,
);
$this->assertEquals(2, $userModel->create(array('username' => 'user')));
$this->assertEquals(1, $projectModel->create(array('name' => 'Test')));
$this->assertTrue($projectUserRole->addUser(1, 2, Role::PROJECT_VIEWER));
$this->assertFalse($projectRoleHelper->canChangeTaskStatusInColumn(1, 1));
}
public function testCanChangeTaskStatusInColumnWithProjectMember()
{
$projectRoleHelper = new ProjectRoleHelper($this->container);
$projectModel = new ProjectModel($this->container);
$projectUserRole = new ProjectUserRoleModel($this->container);
$userModel = new UserModel($this->container);
$this->container['sessionStorage']->user = array(
'id' => 2,
'role' => Role::APP_USER,
);
$this->assertEquals(2, $userModel->create(array('username' => 'user')));
$this->assertEquals(1, $projectModel->create(array('name' => 'Test')));
$this->assertTrue($projectUserRole->addUser(1, 2, Role::PROJECT_MEMBER));
$this->assertTrue($projectRoleHelper->canChangeTaskStatusInColumn(1, 1));
}
public function testCanChangeTaskStatusInColumnWithCustomProjectRole()
{
$projectRoleHelper = new ProjectRoleHelper($this->container);
$projectModel = new ProjectModel($this->container);
$projectUserRole = new ProjectUserRoleModel($this->container);
$userModel = new UserModel($this->container);
$projectRoleModel = new ProjectRoleModel($this->container);
$this->container['sessionStorage']->user = array(
'id' => 2,
'role' => Role::APP_USER,
);
$this->assertEquals(2, $userModel->create(array('username' => 'user')));
$this->assertEquals(1, $projectModel->create(array('name' => 'Test')));
$this->assertEquals(1, $projectRoleModel->create(1, 'Custom Role'));
$this->assertTrue($projectUserRole->addUser(1, 2, 'Custom Role'));
$this->assertTrue($projectRoleHelper->canChangeTaskStatusInColumn(1, 1));
}
public function testCanChangeTaskStatusInColumnWithCustomProjectRoleAndRestrictions()
{
$projectRoleHelper = new ProjectRoleHelper($this->container);
$projectModel = new ProjectModel($this->container);
$projectUserRole = new ProjectUserRoleModel($this->container);
$userModel = new UserModel($this->container);
$projectRoleModel = new ProjectRoleModel($this->container);
$projectRoleRestrictionModel = new ProjectRoleRestrictionModel($this->container);
$columnRestrictionModel = new ColumnRestrictionModel($this->container);
$this->container['sessionStorage']->user = array(
'id' => 2,
'role' => Role::APP_USER,
);
$this->assertEquals(2, $userModel->create(array('username' => 'user')));
$this->assertEquals(1, $projectModel->create(array('name' => 'Test')));
$this->assertEquals(1, $projectRoleModel->create(1, 'Custom Role'));
$this->assertTrue($projectUserRole->addUser(1, 2, 'Custom Role'));
$this->assertEquals(1, $projectRoleRestrictionModel->create(1, 1, ProjectRoleRestrictionModel::RULE_TASK_OPEN_CLOSE));
$this->assertEquals(1, $columnRestrictionModel->create(1, 1, 1, ColumnRestrictionModel::RULE_ALLOW_TASK_OPEN_CLOSE));
$this->assertTrue($projectRoleHelper->canChangeTaskStatusInColumn(1, 1));
$this->assertFalse($projectRoleHelper->canChangeTaskStatusInColumn(1, 2));
}
public function testIsDraggableWithProjectMember()
{
$projectRoleHelper = new ProjectRoleHelper($this->container);

View File

@ -0,0 +1,100 @@
<?php
use Kanboard\Model\ColumnRestrictionModel;
use Kanboard\Model\ProjectModel;
use Kanboard\Model\ProjectRoleModel;
require_once __DIR__.'/../Base.php';
class ColumnRestrictionModelTest extends Base
{
public function testCreation()
{
$projectModel = new ProjectModel($this->container);
$projectRoleModel = new ProjectRoleModel($this->container);
$columnRestrictionModel = new ColumnRestrictionModel($this->container);
$this->assertEquals(1, $projectModel->create(array('name' => 'Test')));
$this->assertEquals(1, $projectRoleModel->create(1, 'my-custom-role'));
$this->assertEquals(1, $columnRestrictionModel->create(1, 1, 2, ColumnRestrictionModel::RULE_BLOCK_TASK_CREATION));
}
public function testRemove()
{
$projectModel = new ProjectModel($this->container);
$projectRoleModel = new ProjectRoleModel($this->container);
$projectRoleRestrictionModel = new ColumnRestrictionModel($this->container);
$this->assertEquals(1, $projectModel->create(array('name' => 'Test')));
$this->assertEquals(1, $projectRoleModel->create(1, 'my-custom-role'));
$this->assertEquals(1, $projectRoleRestrictionModel->create(1, 1, 2, ColumnRestrictionModel::RULE_ALLOW_TASK_OPEN_CLOSE));
$this->assertTrue($projectRoleRestrictionModel->remove(1));
$this->assertFalse($projectRoleRestrictionModel->remove(1));
}
public function testGetById()
{
$projectModel = new ProjectModel($this->container);
$projectRoleModel = new ProjectRoleModel($this->container);
$projectRoleRestrictionModel = new ColumnRestrictionModel($this->container);
$this->assertEquals(1, $projectModel->create(array('name' => 'Test')));
$this->assertEquals(1, $projectRoleModel->create(1, 'my-custom-role'));
$this->assertEquals(1, $projectRoleRestrictionModel->create(1, 1, 2, ColumnRestrictionModel::RULE_ALLOW_TASK_CREATION));
$restriction = $projectRoleRestrictionModel->getById(1, 1);
$this->assertEquals(ColumnRestrictionModel::RULE_ALLOW_TASK_CREATION, $restriction['rule']);
$this->assertEquals(1, $restriction['project_id']);
$this->assertEquals(1, $restriction['restriction_id']);
$this->assertEquals('Ready', $restriction['column_title']);
}
public function testGetAll()
{
$projectModel = new ProjectModel($this->container);
$projectRoleModel = new ProjectRoleModel($this->container);
$projectRoleRestrictionModel = new ColumnRestrictionModel($this->container);
$this->assertEquals(1, $projectModel->create(array('name' => 'Test')));
$this->assertEquals(1, $projectRoleModel->create(1, 'my-custom-role'));
$this->assertEquals(1, $projectRoleRestrictionModel->create(1, 1, 2, ColumnRestrictionModel::RULE_ALLOW_TASK_CREATION));
$restrictions = $projectRoleRestrictionModel->getAll(1);
$this->assertCount(1, $restrictions);
$this->assertEquals(ColumnRestrictionModel::RULE_ALLOW_TASK_CREATION, $restrictions[0]['rule']);
$this->assertEquals(1, $restrictions[0]['project_id']);
$this->assertEquals(1, $restrictions[0]['restriction_id']);
$this->assertEquals(1, $restrictions[0]['role_id']);
$this->assertEquals(2, $restrictions[0]['column_id']);
$this->assertEquals('Ready', $restrictions[0]['column_title']);
}
public function testGetByRole()
{
$projectModel = new ProjectModel($this->container);
$projectRoleModel = new ProjectRoleModel($this->container);
$columnRestrictionModel = new ColumnRestrictionModel($this->container);
$this->assertEquals(1, $projectModel->create(array('name' => 'Test')));
$this->assertEquals(1, $projectRoleModel->create(1, 'my-custom-role'));
$this->assertEquals(1, $columnRestrictionModel->create(1, 1, 2, ColumnRestrictionModel::RULE_BLOCK_TASK_CREATION));
$restrictions = $columnRestrictionModel->getAllByRole(1, 'my-custom-role');
$this->assertCount(1, $restrictions);
$this->assertEquals(ColumnRestrictionModel::RULE_BLOCK_TASK_CREATION, $restrictions[0]['rule']);
$this->assertEquals(1, $restrictions[0]['project_id']);
$this->assertEquals(1, $restrictions[0]['restriction_id']);
$this->assertEquals(1, $restrictions[0]['role_id']);
$this->assertEquals(2, $restrictions[0]['column_id']);
$this->assertEquals('my-custom-role', $restrictions[0]['role']);
}
public function testGetRules()
{
$columnRestrictionModel = new ColumnRestrictionModel($this->container);
$rules = $columnRestrictionModel->getRules();
$this->assertCount(4, $rules);
$this->assertArrayHasKey(ColumnRestrictionModel::RULE_ALLOW_TASK_CREATION, $rules);
}
}

View File

@ -11,7 +11,7 @@ use Kanboard\Model\ProjectGroupRoleModel;
use Kanboard\Model\ProjectUserRoleModel;
use Kanboard\Core\Security\Role;
class ProjectPermissionTest extends Base
class ProjectPermissionModelTest extends Base
{
public function testFindByUsernames()
{

View File

@ -41,14 +41,44 @@ class ProjectRoleModelTest extends Base
$this->assertEquals('Role B', $roles[1]['role']);
}
public function testModification()
public function testModificationWithUserRole()
{
$projectModel = new ProjectModel($this->container);
$projectRoleModel = new ProjectRoleModel($this->container);
$projectUserRoleModel = new ProjectUserRoleModel($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($projectUserRoleModel->addUser(1, 1, 'Role A'));
$this->assertEquals('Role A', $projectUserRoleModel->getUserRole(1, 1));
$this->assertTrue($projectRoleModel->update(1, 1, 'Role B'));
$this->assertEquals('Role B', $projectUserRoleModel->getUserRole(1, 1));
}
public function testModificationWithGroupRole()
{
$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->update(1, 1, 'Role B'));
$this->assertEquals('Role B', $projectGroupRoleModel->getUserRole(1, 1));
}
public function testRemoveWithUserRole()

View File

@ -0,0 +1,96 @@
<?php
use Kanboard\Model\ProjectModel;
use Kanboard\Model\ProjectRoleModel;
use Kanboard\Model\ProjectRoleRestrictionModel;
require_once __DIR__.'/../Base.php';
class ProjectRoleRestrictionModelTest extends Base
{
public function testCreation()
{
$projectModel = new ProjectModel($this->container);
$projectRoleModel = new ProjectRoleModel($this->container);
$projectRoleRestrictionModel = new ProjectRoleRestrictionModel($this->container);
$this->assertEquals(1, $projectModel->create(array('name' => 'Test')));
$this->assertEquals(1, $projectRoleModel->create(1, 'my-custom-role'));
$this->assertEquals(1, $projectRoleRestrictionModel->create(1, 1, ProjectRoleRestrictionModel::RULE_TASK_CREATION));
}
public function testRemove()
{
$projectModel = new ProjectModel($this->container);
$projectRoleModel = new ProjectRoleModel($this->container);
$projectRoleRestrictionModel = new ProjectRoleRestrictionModel($this->container);
$this->assertEquals(1, $projectModel->create(array('name' => 'Test')));
$this->assertEquals(1, $projectRoleModel->create(1, 'my-custom-role'));
$this->assertEquals(1, $projectRoleRestrictionModel->create(1, 1, ProjectRoleRestrictionModel::RULE_TASK_CREATION));
$this->assertTrue($projectRoleRestrictionModel->remove(1));
$this->assertFalse($projectRoleRestrictionModel->remove(1));
}
public function testGetById()
{
$projectModel = new ProjectModel($this->container);
$projectRoleModel = new ProjectRoleModel($this->container);
$projectRoleRestrictionModel = new ProjectRoleRestrictionModel($this->container);
$this->assertEquals(1, $projectModel->create(array('name' => 'Test')));
$this->assertEquals(1, $projectRoleModel->create(1, 'my-custom-role'));
$this->assertEquals(1, $projectRoleRestrictionModel->create(1, 1, ProjectRoleRestrictionModel::RULE_TASK_CREATION));
$restriction = $projectRoleRestrictionModel->getById(1, 1);
$this->assertEquals(ProjectRoleRestrictionModel::RULE_TASK_CREATION, $restriction['rule']);
$this->assertEquals(1, $restriction['project_id']);
$this->assertEquals(1, $restriction['restriction_id']);
}
public function testGetAll()
{
$projectModel = new ProjectModel($this->container);
$projectRoleModel = new ProjectRoleModel($this->container);
$projectRoleRestrictionModel = new ProjectRoleRestrictionModel($this->container);
$this->assertEquals(1, $projectModel->create(array('name' => 'Test')));
$this->assertEquals(1, $projectRoleModel->create(1, 'my-custom-role'));
$this->assertEquals(1, $projectRoleRestrictionModel->create(1, 1, ProjectRoleRestrictionModel::RULE_TASK_CREATION));
$restrictions = $projectRoleRestrictionModel->getAll(1);
$this->assertCount(1, $restrictions);
$this->assertEquals(ProjectRoleRestrictionModel::RULE_TASK_CREATION, $restrictions[0]['rule']);
$this->assertEquals(1, $restrictions[0]['project_id']);
$this->assertEquals(1, $restrictions[0]['restriction_id']);
$this->assertEquals(1, $restrictions[0]['role_id']);
}
public function testGetByRole()
{
$projectModel = new ProjectModel($this->container);
$projectRoleModel = new ProjectRoleModel($this->container);
$projectRoleRestrictionModel = new ProjectRoleRestrictionModel($this->container);
$this->assertEquals(1, $projectModel->create(array('name' => 'Test')));
$this->assertEquals(1, $projectRoleModel->create(1, 'my-custom-role'));
$this->assertEquals(1, $projectRoleRestrictionModel->create(1, 1, ProjectRoleRestrictionModel::RULE_TASK_CREATION));
$restrictions = $projectRoleRestrictionModel->getAllByRole(1, 'my-custom-role');
$this->assertCount(1, $restrictions);
$this->assertEquals(ProjectRoleRestrictionModel::RULE_TASK_CREATION, $restrictions[0]['rule']);
$this->assertEquals(1, $restrictions[0]['project_id']);
$this->assertEquals(1, $restrictions[0]['restriction_id']);
$this->assertEquals(1, $restrictions[0]['role_id']);
$this->assertEquals('my-custom-role', $restrictions[0]['role']);
}
public function testGetRules()
{
$projectRoleRestrictionModel = new ProjectRoleRestrictionModel($this->container);
$rules = $projectRoleRestrictionModel->getRules();
$this->assertCount(2, $rules);
$this->assertArrayHasKey(ProjectRoleRestrictionModel::RULE_TASK_OPEN_CLOSE, $rules);
}
}

View File

@ -89,6 +89,7 @@ class TaskFinderModelTest extends Base
$tasks = $taskFinderModel->getUserQuery(1)->findAll();
$this->assertCount(1, $tasks);
$this->assertEquals('Task #1', $tasks[0]['title']);
$this->assertEquals(1, $tasks[0]['column_id']);
$this->assertTrue($columnModel->update(2, 'Test', 0, '', 0));