diff options
Diffstat (limited to 'app')
22 files changed, 511 insertions, 100 deletions
diff --git a/app/Controller/BoardAjaxController.php b/app/Controller/BoardAjaxController.php index cc3b846e..484ef67d 100644 --- a/app/Controller/BoardAjaxController.php +++ b/app/Controller/BoardAjaxController.php @@ -28,14 +28,8 @@ class BoardAjaxController extends BaseController          }          $values = $this->request->getJson(); -        $canMoveTask = $this->columnMoveRestrictionModel->isAllowed( -            $project_id, -            $this->helper->user->getProjectUserRole($project_id), -            $values['src_column_id'], -            $values['dst_column_id'] -        ); -        if (! $canMoveTask) { +        if (! $this->helper->projectRole->canMoveTask($project_id, $values['src_column_id'], $values['dst_column_id'])) {              throw new AccessForbiddenException(e("You don't have the permission to move this task"));          } diff --git a/app/Controller/ColumnMoveRestrictionController.php b/app/Controller/ColumnMoveRestrictionController.php index 3f1b878f..b12f6b77 100644 --- a/app/Controller/ColumnMoveRestrictionController.php +++ b/app/Controller/ColumnMoveRestrictionController.php @@ -45,14 +45,14 @@ class ColumnMoveRestrictionController extends BaseController          list($valid, $errors) = $this->columnMoveRestrictionValidator->validateCreation($values);          if ($valid) { -            $role_id = $this->columnMoveRestrictionModel->create( +            $restriction_id = $this->columnMoveRestrictionModel->create(                  $project['id'],                  $values['role_id'],                  $values['src_column_id'],                  $values['dst_column_id']              ); -            if ($role_id !== false) { +            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.')); diff --git a/app/Controller/ProjectRoleRestrictionController.php b/app/Controller/ProjectRoleRestrictionController.php new file mode 100644 index 00000000..4fa9b13b --- /dev/null +++ b/app/Controller/ProjectRoleRestrictionController.php @@ -0,0 +1,96 @@ +<?php + +namespace Kanboard\Controller; + +use Kanboard\Core\Controller\AccessForbiddenException; + +/** + * Class ProjectRoleRestrictionController + * + * @package Kanboard\Controller + * @author  Frederic Guillot + */ +class ProjectRoleRestrictionController extends BaseController +{ +    /** +     * Show form to create a new project 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('project_role_restriction/create', array( +            'project' => $project, +            'role' => $role, +            'values' => $values + array('project_id' => $project['id'], 'role_id' => $role['role_id']), +            'errors' => $errors, +            'restrictions' => $this->projectRoleRestrictionModel->getRules(), +        ))); +    } + +    /** +     * Save new restriction +     */ +    public function save() +    { +        $project = $this->getProject(); +        $values = $this->request->getValues(); + +        $restriction_id = $this->projectRoleRestrictionModel->create( +            $project['id'], +            $values['role_id'], +            $values['rule'] +        ); + +        if ($restriction_id !== false) { +            $this->flash->success(t('The project restriction has been created successfully.')); +        } else { +            $this->flash->failure(t('Unable to create this project restriction.')); +        } + +        $this->response->redirect($this->helper->url->to('ProjectRoleController', 'show', array('project_id' => $project['id']))); +    } + +    /** +     * Confirm suppression +     * +     * @access public +     */ +    public function confirm() +    { +        $project = $this->getProject(); +        $restriction_id = $this->request->getIntegerParam('restriction_id'); + +        $this->response->html($this->helper->layout->project('project_role_restriction/remove', array( +            'project' => $project, +            'restriction' => $this->projectRoleRestrictionModel->getById($project['id'], $restriction_id), +            'restrictions' => $this->projectRoleRestrictionModel->getRules(), +        ))); +    } + +    /** +     * Remove a restriction +     * +     * @access public +     */ +    public function remove() +    { +        $project = $this->getProject(); +        $this->checkCSRFParam(); +        $restriction_id = $this->request->getIntegerParam('restriction_id'); + +        if ($this->projectRoleRestrictionModel->remove($restriction_id)) { +            $this->flash->success(t('Project 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']))); +    } +} diff --git a/app/Controller/TaskSuppressionController.php b/app/Controller/TaskSuppressionController.php index 600107c9..019bd97c 100644 --- a/app/Controller/TaskSuppressionController.php +++ b/app/Controller/TaskSuppressionController.php @@ -19,7 +19,7 @@ class TaskSuppressionController extends BaseController      {          $task = $this->getTask(); -        if (! $this->helper->user->canRemoveTask($task)) { +        if (! $this->helper->projectRole->canRemoveTask($task)) {              throw new AccessForbiddenException();          } @@ -37,7 +37,7 @@ class TaskSuppressionController extends BaseController          $task = $this->getTask();          $this->checkCSRFParam(); -        if (! $this->helper->user->canRemoveTask($task)) { +        if (! $this->helper->projectRole->canRemoveTask($task)) {              throw new AccessForbiddenException();          } diff --git a/app/Core/Base.php b/app/Core/Base.php index cadaef72..d6da13f2 100644 --- a/app/Core/Base.php +++ b/app/Core/Base.php @@ -91,6 +91,7 @@ use Pimple\Container;   * @property \Kanboard\Model\ProjectNotificationModel                $projectNotificationModel   * @property \Kanboard\Model\ProjectNotificationTypeModel            $projectNotificationTypeModel   * @property \Kanboard\Model\ProjectRoleModel                        $projectRoleModel + * @property \Kanboard\Model\ProjectRoleRestrictionModel             $projectRoleRestrictionModel   * @property \Kanboard\Model\ProjectTaskDuplicationModel             $projectTaskDuplicationModel   * @property \Kanboard\Model\ProjectTaskPriorityModel                $projectTaskPriorityModel   * @property \Kanboard\Model\RememberMeSessionModel                  $rememberMeSessionModel diff --git a/app/Core/Helper.php b/app/Core/Helper.php index c98b3c5e..b5c560af 100644 --- a/app/Core/Helper.php +++ b/app/Core/Helper.php @@ -26,6 +26,7 @@ use Pimple\Container;   * @property \Kanboard\Helper\UrlHelper               $url   * @property \Kanboard\Helper\UserHelper              $user   * @property \Kanboard\Helper\LayoutHelper            $layout + * @property \Kanboard\Helper\ProjectRoleHelper       $projectRole   * @property \Kanboard\Helper\ProjectHeaderHelper     $projectHeader   * @property \Kanboard\Helper\ProjectActivityHelper   $projectActivity   * @property \Kanboard\Helper\MailHelper              $mail diff --git a/app/Formatter/BoardTaskFormatter.php b/app/Formatter/BoardTaskFormatter.php index 5956ae35..cd10f77a 100644 --- a/app/Formatter/BoardTaskFormatter.php +++ b/app/Formatter/BoardTaskFormatter.php @@ -81,7 +81,7 @@ class BoardTaskFormatter extends BaseFormatter implements FormatterInterface          array_merge_relation($tasks, $this->tags, 'tags', 'id');          foreach ($tasks as &$task) { -            $task['is_draggable'] = $this->helper->board->isDraggable($task); +            $task['is_draggable'] = $this->helper->projectRole->isDraggable($task);          }          return $tasks; diff --git a/app/Helper/BoardHelper.php b/app/Helper/BoardHelper.php index 9e8e78ac..f5df3db2 100644 --- a/app/Helper/BoardHelper.php +++ b/app/Helper/BoardHelper.php @@ -24,26 +24,4 @@ class BoardHelper extends Base      {          return $this->userMetadataCacheDecorator->get(UserMetadataModel::KEY_BOARD_COLLAPSED.$project_id, 0) == 1;      } - -    /** -     * Return true if the task can be moved by the connected user -     * -     * @param array $task -     * @return bool -     */ -    public function isDraggable(array $task) -    { -        if ($task['is_active'] == 1 && $this->helper->user->hasProjectAccess('BoardViewController', 'save', $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; -    }  } diff --git a/app/Helper/ProjectRoleHelper.php b/app/Helper/ProjectRoleHelper.php new file mode 100644 index 00000000..34905b52 --- /dev/null +++ b/app/Helper/ProjectRoleHelper.php @@ -0,0 +1,130 @@ +<?php + +namespace Kanboard\Helper; + +use Kanboard\Core\Base; +use Kanboard\Core\Security\Role; + +/** + * Class ProjectRoleHelper + * + * @package Kanboard\Helper + * @author  Frederic Guillot + */ +class ProjectRoleHelper extends Base +{ +    /** +     * Get project role for the current user +     * +     * @access public +     * @param  integer $project_id +     * @return string +     */ +    public function getProjectUserRole($project_id) +    { +        return $this->memoryCache->proxy($this->projectUserRoleModel, 'getUserRole', $project_id, $this->userSession->getId()); +    } + +    /** +     * Return true if the task can be moved by the connected user +     * +     * @param array $task +     * @return bool +     */ +    public function isDraggable(array $task) +    { +        if ($task['is_active'] == 1 && $this->helper->user->hasProjectAccess('BoardViewController', 'save', $task['project_id'])) { +            $role = $this->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; +    } + +    /** +     * Check if the user can move a task +     * +     * @param  int $project_id +     * @param  int $src_column_id +     * @param  int $dst_column_id +     * @return bool|int +     */ +    public function canMoveTask($project_id, $src_column_id, $dst_column_id) +    { +        $role = $this->getProjectUserRole($project_id); + +        if ($this->role->isCustomProjectRole($role)) { +            return $this->columnMoveRestrictionModel->isAllowed( +                $project_id, +                $role, +                $src_column_id, +                $dst_column_id +            ); +        } + +        return true; +    } + +    /** +     * Return true if the user can remove a task +     * +     * Regular users can't remove tasks from other people +     * +     * @public +     * @param  array $task +     * @return bool +     */ +    public function canRemoveTask(array $task) +    { +        if (isset($task['creator_id']) && $task['creator_id'] == $this->userSession->getId()) { +            return true; +        } + +        if ($this->userSession->isAdmin() || $this->getProjectUserRole($task['project_id']) === Role::PROJECT_MANAGER) { +            return true; +        } + +        return false; +    } + +    /** +     * Check project access +     * +     * @param  string  $controller +     * @param  string  $action +     * @param  integer $project_id +     * @return bool +     */ +    public function checkProjectAccess($controller, $action, $project_id) +    { +        if (! $this->userSession->isLogged()) { +            return false; +        } + +        if ($this->userSession->isAdmin()) { +            return true; +        } + +        if (! $this->helper->user->hasAccess($controller, $action)) { +            return false; +        } + +        $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); +        } else { +            $result = $this->projectAuthorization->isAllowed($controller, $action, $role); +        } + +        return $result; +    } +} diff --git a/app/Helper/UserHelper.php b/app/Helper/UserHelper.php index 17c66616..8c2567b9 100644 --- a/app/Helper/UserHelper.php +++ b/app/Helper/UserHelper.php @@ -3,7 +3,6 @@  namespace Kanboard\Helper;  use Kanboard\Core\Base; -use Kanboard\Core\Security\Role;  /**   * User helpers @@ -133,66 +132,14 @@ class UserHelper extends Base       */      public function hasProjectAccess($controller, $action, $project_id)      { -        if (! $this->userSession->isLogged()) { -            return false; -        } - -        if ($this->userSession->isAdmin()) { -            return true; -        } - -        if (! $this->hasAccess($controller, $action)) { -            return false; -        } -          $key = 'project_access:'.$controller.$action.$project_id;          $result = $this->memoryCache->get($key);          if ($result === null) { -            $role = $this->getProjectUserRole($project_id); - -            if ($this->role->isCustomProjectRole($role)) { -                $role = Role::PROJECT_MEMBER; -            } - -            $result = $this->projectAuthorization->isAllowed($controller, $action, $role); +            $result = $this->helper->projectRole->checkProjectAccess($controller, $action, $project_id);              $this->memoryCache->set($key, $result);          }          return $result;      } - -    /** -     * Get project role for the current user -     * -     * @access public -     * @param  integer $project_id -     * @return string -     */ -    public function getProjectUserRole($project_id) -    { -        return $this->memoryCache->proxy($this->projectUserRoleModel, 'getUserRole', $project_id, $this->userSession->getId()); -    } - -    /** -     * Return true if the user can remove a task -     * -     * Regular users can't remove tasks from other people -     * -     * @public -     * @param  array $task -     * @return bool -     */ -    public function canRemoveTask(array $task) -    { -        if (isset($task['creator_id']) && $task['creator_id'] == $this->userSession->getId()) { -            return true; -        } - -        if ($this->userSession->isAdmin() || $this->getProjectUserRole($task['project_id']) === Role::PROJECT_MANAGER) { -            return true; -        } - -        return false; -    }  } diff --git a/app/Model/ProjectRoleModel.php b/app/Model/ProjectRoleModel.php index 82f22806..ed86d6ed 100644 --- a/app/Model/ProjectRoleModel.php +++ b/app/Model/ProjectRoleModel.php @@ -17,7 +17,7 @@ class ProjectRoleModel extends Base      /**       * Get list of project roles -     *  +     *       * @param  int $project_id       * @return array       */ @@ -70,9 +70,14 @@ class ProjectRoleModel extends Base      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'); + +        $column_restrictions = $this->columnMoveRestrictionModel->getAll($project_id); +        $column_restrictions = array_column_index($column_restrictions, 'role_id'); +        array_merge_relation($roles, $column_restrictions, 'column_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');          return $roles;      } diff --git a/app/Model/ProjectRoleRestrictionModel.php b/app/Model/ProjectRoleRestrictionModel.php new file mode 100644 index 00000000..0411838d --- /dev/null +++ b/app/Model/ProjectRoleRestrictionModel.php @@ -0,0 +1,164 @@ +<?php + +namespace Kanboard\Model; + +use Kanboard\Core\Base; + +/** + * Class ProjectRoleRestrictionModel + * + * @package Kanboard\Model + * @author  Frederic Guillot + */ +class ProjectRoleRestrictionModel extends Base +{ +    const TABLE = 'project_role_has_restrictions'; +    const RULE_TASK_CREATION = 'task_creation'; + +    protected $ruleMapping = array( +        self::RULE_TASK_CREATION => array( +            array('controller' => 'TaskCreationController', 'method' => '*'), +        ) +    ); + +    /** +     * Get rules +     * +     * @return array +     */ +    public function getRules() +    { +        return array( +            self::RULE_TASK_CREATION => t('Task creation is not permitted'), +        ); +    } + +    /** +     * Get a single restriction +     * +     * @param  integer $project_id +     * @param  integer $restriction_id +     * @return array|null +     */ +    public function getById($project_id, $restriction_id) +    { +        return $this->db +            ->table(self::TABLE) +            ->eq('project_id', $project_id) +            ->eq('restriction_id', $restriction_id) +            ->findOne(); +    } + +    /** +     * Get 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.'.rule' +            ) +            ->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) +    { +        $rules = $this->db +            ->table(self::TABLE) +            ->columns( +                self::TABLE.'.restriction_id', +                self::TABLE.'.project_id', +                self::TABLE.'.role_id', +                self::TABLE.'.rule', +                'pr.role' +            ) +            ->eq(self::TABLE.'.project_id', $project_id) +            ->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; +    } + +    /** +     * Create a new restriction +     * +     * @param  int $project_id +     * @param  int $role_id +     * @param  string $rule +     * @return bool|int +     */ +    public function create($project_id, $role_id, $rule) +    { +        return $this->db->table(self::TABLE) +            ->persist(array( +                'project_id' => $project_id, +                'role_id' => $role_id, +                'rule' => $rule, +            )); +    } + +    /** +     * Remove a restriction +     * +     * @param  integer $restriction_id +     * @return bool +     */ +    public function remove($restriction_id) +    { +        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; +    } +} diff --git a/app/Schema/Mysql.php b/app/Schema/Mysql.php index 11c7f232..0da54597 100644 --- a/app/Schema/Mysql.php +++ b/app/Schema/Mysql.php @@ -6,7 +6,22 @@ use PDO;  use Kanboard\Core\Security\Token;  use Kanboard\Core\Security\Role; -const VERSION = 113; +const VERSION = 114; + +function version_114(PDO $pdo) +{ +    $pdo->exec(" +        CREATE TABLE project_role_has_restrictions ( +            restriction_id INT NOT NULL AUTO_INCREMENT, +            project_id INT NOT NULL, +            role_id INT NOT NULL, +            rule VARCHAR(255) NOT NULL, +            UNIQUE(role_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 +        ) ENGINE=InnoDB CHARSET=utf8 +    "); +}  function version_113(PDO $pdo)  { diff --git a/app/Schema/Postgres.php b/app/Schema/Postgres.php index 2d1695d0..56cd9de9 100644 --- a/app/Schema/Postgres.php +++ b/app/Schema/Postgres.php @@ -6,7 +6,22 @@ use PDO;  use Kanboard\Core\Security\Token;  use Kanboard\Core\Security\Role; -const VERSION = 92; +const VERSION = 93; + +function version_93(PDO $pdo) +{ +    $pdo->exec(" +        CREATE TABLE project_role_has_restrictions ( +            restriction_id SERIAL PRIMARY KEY, +            project_id INTEGER NOT NULL, +            role_id INTEGER NOT NULL, +            rule VARCHAR(255) NOT NULL, +            UNIQUE(role_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 +        ) +    "); +}  function version_92(PDO $pdo)  { diff --git a/app/Schema/Sqlite.php b/app/Schema/Sqlite.php index ecfa93de..c952d58f 100644 --- a/app/Schema/Sqlite.php +++ b/app/Schema/Sqlite.php @@ -6,7 +6,22 @@ use Kanboard\Core\Security\Token;  use Kanboard\Core\Security\Role;  use PDO; -const VERSION = 104; +const VERSION = 105; + +function version_105(PDO $pdo) +{ +    $pdo->exec(" +        CREATE TABLE project_role_has_restrictions ( +            restriction_id INTEGER PRIMARY KEY, +            project_id INTEGER NOT NULL, +            role_id INTEGER NOT NULL, +            rule VARCHAR(255) NOT NULL, +            UNIQUE(role_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 +        ) +    "); +}  function version_104(PDO $pdo)  { diff --git a/app/ServiceProvider/ClassProvider.php b/app/ServiceProvider/ClassProvider.php index 98669e6d..4841d1f0 100644 --- a/app/ServiceProvider/ClassProvider.php +++ b/app/ServiceProvider/ClassProvider.php @@ -57,6 +57,7 @@ class ClassProvider implements ServiceProviderInterface              'ProjectMetadataModel',              'ProjectGroupRoleModel',              'ProjectRoleModel', +            'ProjectRoleRestrictionModel',              'ProjectTaskDuplicationModel',              'ProjectTaskPriorityModel',              'ProjectUserRoleModel', diff --git a/app/ServiceProvider/HelperProvider.php b/app/ServiceProvider/HelperProvider.php index a909e3cf..f4c0db22 100644 --- a/app/ServiceProvider/HelperProvider.php +++ b/app/ServiceProvider/HelperProvider.php @@ -35,6 +35,7 @@ class HelperProvider implements ServiceProviderInterface          $container['helper']->register('url', '\Kanboard\Helper\UrlHelper');          $container['helper']->register('user', '\Kanboard\Helper\UserHelper');          $container['helper']->register('avatar', '\Kanboard\Helper\AvatarHelper'); +        $container['helper']->register('projectRole', '\Kanboard\Helper\ProjectRoleHelper');          $container['helper']->register('projectHeader', '\Kanboard\Helper\ProjectHeaderHelper');          $container['helper']->register('projectActivity', '\Kanboard\Helper\ProjectActivityHelper');          $container['helper']->register('mail', '\Kanboard\Helper\MailHelper'); diff --git a/app/Template/project_role/show.php b/app/Template/project_role/show.php index 5fbd413b..595416ac 100644 --- a/app/Template/project_role/show.php +++ b/app/Template/project_role/show.php @@ -20,6 +20,10 @@                      <ul>                          <li>                              <i class="fa fa-plus fa-fw" aria-hidden="true"></i> +                            <?= $this->url->link(t('Add a new project restriction'), 'ProjectRoleRestrictionController', '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'), 'ColumnMoveRestrictionController', 'create', array('project_id' => $project['id'], 'role_id' => $role['role_id']), false, 'popover') ?>                          </li>                          <li> @@ -33,15 +37,26 @@                  <?= t('Actions') ?>              </th>          </tr> -        <?php if (empty($role['restrictions'])): ?> +        <?php if (empty($role['project_restrictions']) && empty($role['column_restrictions'])): ?>              <tr>                  <td colspan="2"><?= t('There is no restriction for this role.') ?></td>              </tr>          <?php else: ?> -            <?php foreach ($role['restrictions'] as $restriction): ?> +            <?php foreach ($role['project_restrictions'] as $restriction): ?> +                <tr> +                    <td> +                        <?= $this->text->e($restriction['title']) ?> +                    </td> +                    <td> +                        <i class="fa fa-trash-o fa-fw" aria-hidden="true"></i> +                        <?= $this->url->link(t('Remove'), 'ProjectRoleRestrictionController', 'confirm', array('project_id' => $project['id'], 'restriction_id' => $restriction['restriction_id']), false, 'popover') ?> +                    </td> +                </tr> +            <?php endforeach ?> +            <?php foreach ($role['column_restrictions'] as $restriction): ?>                  <tr>                      <td> -                        <?= t('Moving task from the column "%s" to "%s" is permitted', $restriction['src_column_title'], $restriction['dst_column_title']) ?> +                        <?= t('Only moving task from the column "%s" to "%s" is permitted', $restriction['src_column_title'], $restriction['dst_column_title']) ?>                      </td>                      <td>                          <i class="fa fa-trash-o fa-fw" aria-hidden="true"></i> diff --git a/app/Template/project_role_restriction/create.php b/app/Template/project_role_restriction/create.php new file mode 100644 index 00000000..f49eafb3 --- /dev/null +++ b/app/Template/project_role_restriction/create.php @@ -0,0 +1,19 @@ +<section id="main"> +    <div class="page-header"> +        <h2><?= t('New project restriction for the role "%s"', $role['role']) ?></h2> +    </div> +    <form class="popover-form" method="post" action="<?= $this->url->href('ProjectRoleRestrictionController', '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('Restriction'), 'rule') ?> +        <?= $this->form->select('rule', $restrictions, $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> diff --git a/app/Template/project_role_restriction/remove.php b/app/Template/project_role_restriction/remove.php new file mode 100644 index 00000000..db1148e1 --- /dev/null +++ b/app/Template/project_role_restriction/remove.php @@ -0,0 +1,14 @@ +<div class="page-header"> +    <h2><?= t('Remove a project restriction') ?></h2> +</div> + +<div class="confirm"> +    <p class="alert alert-info"> +        <?= t('Do you really want to remove this project restriction: "%s"?', $this->text->in($restriction['rule'], $restrictions)) ?> +    </p> + +    <div class="form-actions"> +        <?= $this->url->link(t('Yes'), 'ProjectRoleRestrictionController', '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> diff --git a/app/Template/task/dropdown.php b/app/Template/task/dropdown.php index 95c7a88c..19c8316e 100644 --- a/app/Template/task/dropdown.php +++ b/app/Template/task/dropdown.php @@ -43,7 +43,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->canRemoveTask($task)): ?> +        <?php if ($this->projectRole->canRemoveTask($task)): ?>              <li>                  <i class="fa fa-trash-o fa-fw"></i>                  <?= $this->url->link(t('Remove'), 'TaskSuppressionController', 'confirm', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?> diff --git a/app/Template/task/sidebar.php b/app/Template/task/sidebar.php index de0750ff..827c2f39 100644 --- a/app/Template/task/sidebar.php +++ b/app/Template/task/sidebar.php @@ -93,7 +93,7 @@                  <?= $this->url->link(t('Open this task'), 'TaskStatusController', 'open', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?>              </li>          <?php endif ?> -        <?php if ($this->user->canRemoveTask($task)): ?> +        <?php if ($this->projectRole->canRemoveTask($task)): ?>              <li>                  <i class="fa fa-trash-o fa-fw"></i>                  <?= $this->url->link(t('Remove'), 'TaskSuppressionController', 'confirm', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'redirect' => 'board'), false, 'popover') ?>  | 
