diff options
93 files changed, 917 insertions, 600 deletions
diff --git a/app/Action/Base.php b/app/Action/Base.php index 5133c7db..0d8bd565 100644 --- a/app/Action/Base.php +++ b/app/Action/Base.php @@ -11,7 +11,7 @@ use Pimple\Container; * @package action * @author Frederic Guillot * - * @property \Model\Acl $acl + * @property \Model\UserSession $userSession * @property \Model\Comment $comment * @property \Model\Task $task * @property \Model\TaskCreation $taskCreation diff --git a/app/Action/TaskAssignCurrentUser.php b/app/Action/TaskAssignCurrentUser.php index b2015100..ff3aaee1 100644 --- a/app/Action/TaskAssignCurrentUser.php +++ b/app/Action/TaskAssignCurrentUser.php @@ -62,13 +62,13 @@ class TaskAssignCurrentUser extends Base */ public function doAction(array $data) { - if (! $this->acl->isLogged()) { + if (! $this->userSession->isLogged()) { return false; } $values = array( 'id' => $data['task_id'], - 'owner_id' => $this->acl->getUserId(), + 'owner_id' => $this->userSession->getId(), ); return $this->taskModification->update($values); diff --git a/app/Auth/RememberMe.php b/app/Auth/RememberMe.php index 9f2bb13a..fc2ea78d 100644 --- a/app/Auth/RememberMe.php +++ b/app/Auth/RememberMe.php @@ -102,11 +102,10 @@ class RememberMe extends Base // Create the session $this->user->updateSession($this->user->getById($record['user_id'])); - $this->acl->isRememberMe(true); $this->container['dispatcher']->dispatch( 'auth.success', - new AuthEvent(self::AUTH_NAME, $this->acl->getUserId()) + new AuthEvent(self::AUTH_NAME, $this->userSession->getId()) ); return true; diff --git a/app/Controller/Action.php b/app/Controller/Action.php index 22358cb5..2b58dca1 100644 --- a/app/Controller/Action.php +++ b/app/Controller/Action.php @@ -17,7 +17,7 @@ class Action extends Base */ public function index() { - $project = $this->getProjectManagement(); + $project = $this->getProject(); $this->response->html($this->projectLayout('action/index', array( 'values' => array('project_id' => $project['id']), @@ -42,7 +42,7 @@ class Action extends Base */ public function event() { - $project = $this->getProjectManagement(); + $project = $this->getProject(); $values = $this->request->getValues(); if (empty($values['action_name']) || empty($values['project_id'])) { @@ -64,7 +64,7 @@ class Action extends Base */ public function params() { - $project = $this->getProjectManagement(); + $project = $this->getProject(); $values = $this->request->getValues(); if (empty($values['action_name']) || empty($values['project_id']) || empty($values['event_name'])) { @@ -101,7 +101,7 @@ class Action extends Base */ public function create() { - $this->doCreation($this->getProjectManagement(), $this->request->getValues()); + $this->doCreation($this->getProject(), $this->request->getValues()); } /** @@ -135,7 +135,7 @@ class Action extends Base */ public function confirm() { - $project = $this->getProjectManagement(); + $project = $this->getProject(); $this->response->html($this->projectLayout('action/remove', array( 'action' => $this->action->getById($this->request->getIntegerParam('action_id')), @@ -154,7 +154,7 @@ class Action extends Base public function remove() { $this->checkCSRFParam(); - $project = $this->getProjectManagement(); + $project = $this->getProject(); $action = $this->action->getById($this->request->getIntegerParam('action_id')); if ($action && $this->action->remove($action['id'])) { diff --git a/app/Controller/Analytic.php b/app/Controller/Analytic.php index 115f75f0..8b0684d4 100644 --- a/app/Controller/Analytic.php +++ b/app/Controller/Analytic.php @@ -20,7 +20,7 @@ class Analytic extends Base */ private function layout($template, array $params) { - $params['board_selector'] = $this->projectPermission->getAllowedProjects($this->acl->getUserId()); + $params['board_selector'] = $this->projectPermission->getAllowedProjects($this->userSession->getId()); $params['analytic_content_for_layout'] = $this->template->render($template, $params); return $this->template->layout('analytic/layout', $params); diff --git a/app/Controller/App.php b/app/Controller/App.php index 87b4ccbe..aa2673a1 100644 --- a/app/Controller/App.php +++ b/app/Controller/App.php @@ -34,7 +34,7 @@ class App extends Base $direction = $this->request->getStringParam('direction'); $order = $this->request->getStringParam('order'); - $user_id = $this->acl->getUserId(); + $user_id = $this->userSession->getId(); $projects = $this->projectPermission->getMemberProjects($user_id); $project_ids = array_keys($projects); @@ -191,8 +191,9 @@ class App extends Base $this->response->html('<p>'.t('Nothing to preview...').'</p>'); } else { - $this->response->html($this->template->markdown($payload['text'])); + $this->response->html( + $this->template->markdown($payload['text']) + ); } } - } diff --git a/app/Controller/Base.php b/app/Controller/Base.php index 18f21ee8..4afcba37 100644 --- a/app/Controller/Base.php +++ b/app/Controller/Base.php @@ -51,6 +51,7 @@ use Symfony\Component\EventDispatcher\Event; * @property \Model\SubtaskHistory $subtaskHistory * @property \Model\TimeTracking $timeTracking * @property \Model\User $user + * @property \Model\UserSession $userSession * @property \Model\Webhook $webhook */ abstract class Base @@ -117,16 +118,12 @@ abstract class Base } /** - * Method executed before each action + * Send HTTP headers * - * @access public + * @access private */ - public function beforeAction($controller, $action) + private function sendHeaders($action) { - // Start the session - $this->session->open(BASE_URL_DIRECTORY); - $this->container['dispatcher']->dispatch('session.bootstrap', new Event); - // HTTP secure headers $this->response->csp(array('style-src' => "'self' 'unsafe-inline'")); $this->response->nosniff(); @@ -140,8 +137,32 @@ abstract class Base if (ENABLE_HSTS) { $this->response->hsts(); } + } - // Authentication + /** + * Method executed before each action + * + * @access public + */ + public function beforeAction($controller, $action) + { + // Start the session + $this->session->open(BASE_URL_DIRECTORY); + $this->sendHeaders($action); + $this->container['dispatcher']->dispatch('session.bootstrap', new Event); + + if (! $this->acl->isPublicAction($controller, $action)) { + $this->handleAuthenticatedUser($controller, $action); + } + } + + /** + * Check page access and authentication + * + * @access public + */ + public function handleAuthenticatedUser($controller, $action) + { if (! $this->authentication->isAuthenticated($controller, $action)) { if ($this->request->isAjax()) { @@ -151,9 +172,8 @@ abstract class Base $this->response->redirect('?controller=user&action=login&redirect_query='.urlencode($this->request->getQueryString())); } - // Check if the user is allowed to see this page - if (! $this->acl->isPageAccessAllowed($controller, $action)) { - $this->response->redirect('?controller=user&action=forbidden'); + if (! $this->acl->isAllowed($controller, $action, $this->request->getIntegerParam('project_id', 0))) { + $this->forbidden(); } } @@ -198,33 +218,6 @@ abstract class Base } /** - * Check if the current user have access to the given project - * - * @access protected - * @param integer $project_id Project id - */ - protected function checkProjectPermissions($project_id) - { - if ($this->acl->isRegularUser() && ! $this->projectPermission->isUserAllowed($project_id, $this->acl->getUserId())) { - $this->forbidden(); - } - } - - /** - * Check if the current user is owner of the given project - * - * @access protected - * @param integer $project_id Project id - */ - protected function checkProjectOwnerPermissions($project_id) - { - if (! $this->acl->isAdminUser() && - ! ($this->acl->isRegularUser() && $this->projectPermission->isOwner($project_id, $this->acl->getUserId()))) { - $this->forbidden(); - } - } - - /** * Redirection when there is no project in the database * * @access protected @@ -252,7 +245,7 @@ abstract class Base $content = $this->template->render($template, $params); $params['task_content_for_layout'] = $content; $params['title'] = $params['task']['project_name'].' > '.$params['task']['title']; - $params['board_selector'] = $this->projectPermission->getAllowedProjects($this->acl->getUserId()); + $params['board_selector'] = $this->projectPermission->getAllowedProjects($this->userSession->getId()); return $this->template->layout('task/layout', $params); } @@ -270,8 +263,7 @@ abstract class Base $content = $this->template->render($template, $params); $params['project_content_for_layout'] = $content; $params['title'] = $params['project']['name'] === $params['title'] ? $params['title'] : $params['project']['name'].' > '.$params['title']; - $params['board_selector'] = $this->projectPermission->getAllowedProjects($this->acl->getUserId()); - $params['is_owner'] = $this->projectPermission->isOwner($params['project']['id'], $this->acl->getUserId()); + $params['board_selector'] = $this->projectPermission->getAllowedProjects($this->userSession->getId()); return $this->template->layout('project/layout', $params); } @@ -286,12 +278,10 @@ abstract class Base { $task = $this->taskFinder->getDetails($this->request->getIntegerParam('task_id')); - if (! $task) { + if (! $task || $task['project_id'] != $this->request->getIntegerParam('project_id')) { $this->notfound(); } - $this->checkProjectPermissions($task['project_id']); - return $task; } @@ -312,29 +302,6 @@ abstract class Base $this->response->redirect('?controller=project'); } - $this->checkProjectPermissions($project['id']); - - return $project; - } - - /** - * Common method to get a project with administration rights - * - * @access protected - * @return array - */ - protected function getProjectManagement() - { - $project = $this->project->getById($this->request->getIntegerParam('project_id')); - - if (! $project) { - $this->notfound(); - } - - if ($this->acl->isRegularUser() && ! $this->projectPermission->adminAllowed($project['id'], $this->acl->getUserId())) { - $this->forbidden(); - } - return $project; } } diff --git a/app/Controller/Board.php b/app/Controller/Board.php index 2c10e105..128d9215 100644 --- a/app/Controller/Board.php +++ b/app/Controller/Board.php @@ -18,7 +18,7 @@ class Board extends Base public function moveColumn() { $this->checkCSRFParam(); - $project = $this->getProjectManagement(); + $project = $this->getProject(); $column_id = $this->request->getIntegerParam('column_id'); $direction = $this->request->getStringParam('direction'); @@ -54,7 +54,6 @@ class Board extends Base public function updateAssignee() { $values = $this->request->getValues(); - $this->checkProjectPermissions($values['project_id']); list($valid,) = $this->taskValidator->validateAssigneeModification($values); @@ -93,7 +92,6 @@ class Board extends Base public function updateCategory() { $values = $this->request->getValues(); - $this->checkProjectPermissions($values['project_id']); list($valid,) = $this->taskValidator->validateCategoryModification($values); @@ -144,16 +142,16 @@ class Board extends Base */ public function index() { - $last_seen_project_id = $this->user->getLastSeenProjectId(); - $favorite_project_id = $this->user->getFavoriteProjectId(); + $last_seen_project_id = $this->userSession->getLastSeenProjectId(); + $favorite_project_id = $this->userSession->getFavoriteProjectId(); $project_id = $last_seen_project_id ?: $favorite_project_id; if (! $project_id) { - $projects = $this->projectPermission->getAllowedProjects($this->acl->getUserId()); + $projects = $this->projectPermission->getAllowedProjects($this->userSession->getId()); if (empty($projects)) { - if ($this->acl->isAdminUser()) { + if ($this->userSession->isAdmin()) { $this->redirectNoProject(); } @@ -175,12 +173,12 @@ class Board extends Base public function show($project_id = 0) { $project = $this->getProject($project_id); - $projects = $this->projectPermission->getAllowedProjects($this->acl->getUserId()); + $projects = $this->projectPermission->getAllowedProjects($this->userSession->getId()); $board_selector = $projects; unset($board_selector[$project['id']]); - $this->user->storeLastSeenProjectId($project['id']); + $this->userSession->storeLastSeenProjectId($project['id']); $this->response->html($this->template->layout('board/index', array( 'users' => $this->projectPermission->getMemberList($project['id'], true, true), @@ -202,7 +200,7 @@ class Board extends Base */ public function edit() { - $project = $this->getProjectManagement(); + $project = $this->getProject(); $columns = $this->board->getColumns($project['id']); $values = array(); @@ -227,7 +225,7 @@ class Board extends Base */ public function update() { - $project = $this->getProjectManagement(); + $project = $this->getProject(); $columns = $this->board->getColumns($project['id']); $data = $this->request->getValues(); $values = $columns_list = array(); @@ -267,7 +265,7 @@ class Board extends Base */ public function add() { - $project = $this->getProjectManagement(); + $project = $this->getProject(); $columns = $this->board->getColumnsList($project['id']); $data = $this->request->getValues(); $values = array(); @@ -305,7 +303,7 @@ class Board extends Base */ public function remove() { - $project = $this->getProjectManagement(); + $project = $this->getProject(); if ($this->request->getStringParam('remove') === 'yes') { @@ -341,7 +339,7 @@ class Board extends Base return $this->response->status(403); } - if (! $this->projectPermission->isUserAllowed($project_id, $this->acl->getUserId())) { + if (! $this->projectPermission->isUserAllowed($project_id, $this->userSession->getId())) { $this->response->text('Forbidden', 403); } @@ -385,7 +383,7 @@ class Board extends Base $project_id = $this->request->getIntegerParam('project_id'); $timestamp = $this->request->getIntegerParam('timestamp'); - if (! $this->projectPermission->isUserAllowed($project_id, $this->acl->getUserId())) { + if (! $this->projectPermission->isUserAllowed($project_id, $this->userSession->getId())) { $this->response->text('Forbidden', 403); } @@ -413,7 +411,8 @@ class Board extends Base { $task = $this->getTask(); $this->response->html($this->template->render('board/subtasks', array( - 'subtasks' => $this->subTask->getAll($task['id']) + 'subtasks' => $this->subTask->getAll($task['id']), + 'task' => $task, ))); } @@ -428,7 +427,8 @@ class Board extends Base $this->subTask->toggleStatus($this->request->getIntegerParam('subtask_id')); $this->response->html($this->template->render('board/subtasks', array( - 'subtasks' => $this->subTask->getAll($task['id']) + 'subtasks' => $this->subTask->getAll($task['id']), + 'task' => $task, ))); } @@ -442,7 +442,8 @@ class Board extends Base $task = $this->getTask(); $this->response->html($this->template->render('board/files', array( - 'files' => $this->file->getAll($task['id']) + 'files' => $this->file->getAll($task['id']), + 'task' => $task, ))); } diff --git a/app/Controller/Category.php b/app/Controller/Category.php index b30608b7..68961a0e 100644 --- a/app/Controller/Category.php +++ b/app/Controller/Category.php @@ -36,7 +36,7 @@ class Category extends Base */ public function index(array $values = array(), array $errors = array()) { - $project = $this->getProjectManagement(); + $project = $this->getProject(); $this->response->html($this->projectLayout('category/index', array( 'categories' => $this->category->getList($project['id'], false), @@ -54,7 +54,7 @@ class Category extends Base */ public function save() { - $project = $this->getProjectManagement(); + $project = $this->getProject(); $values = $this->request->getValues(); list($valid, $errors) = $this->category->validateCreation($values); @@ -80,7 +80,7 @@ class Category extends Base */ public function edit(array $values = array(), array $errors = array()) { - $project = $this->getProjectManagement(); + $project = $this->getProject(); $category = $this->getCategory($project['id']); $this->response->html($this->projectLayout('category/edit', array( @@ -98,7 +98,7 @@ class Category extends Base */ public function update() { - $project = $this->getProjectManagement(); + $project = $this->getProject(); $values = $this->request->getValues(); list($valid, $errors) = $this->category->validateModification($values); @@ -124,7 +124,7 @@ class Category extends Base */ public function confirm() { - $project = $this->getProjectManagement(); + $project = $this->getProject(); $category = $this->getCategory($project['id']); $this->response->html($this->projectLayout('category/remove', array( @@ -142,7 +142,7 @@ class Category extends Base public function remove() { $this->checkCSRFParam(); - $project = $this->getProjectManagement(); + $project = $this->getProject(); $category = $this->getCategory($project['id']); if ($this->category->remove($category['id'])) { diff --git a/app/Controller/Comment.php b/app/Controller/Comment.php index fb21353e..9796ea38 100644 --- a/app/Controller/Comment.php +++ b/app/Controller/Comment.php @@ -24,7 +24,7 @@ class Comment extends Base $this->notfound(); } - if (! $this->acl->isAdminUser() && $comment['user_id'] != $this->acl->getUserId()) { + if (! $this->userSession->isAdmin() && $comment['user_id'] != $this->userSession->getId()) { $this->response->html($this->template->layout('comment/forbidden', array( 'title' => t('Access Forbidden') ))); @@ -44,7 +44,7 @@ class Comment extends Base if (empty($values)) { $values = array( - 'user_id' => $this->acl->getUserId(), + 'user_id' => $this->userSession->getId(), 'task_id' => $task['id'], ); } @@ -78,7 +78,7 @@ class Comment extends Base $this->session->flashError(t('Unable to create your comment.')); } - $this->response->redirect('?controller=task&action=show&task_id='.$task['id'].'#comments'); + $this->response->redirect('?controller=task&action=show&task_id='.$task['id'].'&project_id='.$task['project_id'].'#comments'); } $this->create($values, $errors); @@ -125,7 +125,7 @@ class Comment extends Base $this->session->flashError(t('Unable to update your comment.')); } - $this->response->redirect('?controller=task&action=show&task_id='.$task['id'].'#comment-'.$comment['id']); + $this->response->redirect('?controller=task&action=show&task_id='.$task['id'].'&project_id='.$task['project_id'].'#comment-'.$comment['id']); } $this->edit($values, $errors); @@ -166,6 +166,6 @@ class Comment extends Base $this->session->flashError(t('Unable to remove this comment.')); } - $this->response->redirect('?controller=task&action=show&task_id='.$task['id'].'#comments'); + $this->response->redirect('?controller=task&action=show&task_id='.$task['id'].'&project_id='.$task['project_id'].'#comments'); } } diff --git a/app/Controller/Config.php b/app/Controller/Config.php index 4093b7a1..9005c300 100644 --- a/app/Controller/Config.php +++ b/app/Controller/Config.php @@ -20,7 +20,7 @@ class Config extends Base */ private function layout($template, array $params) { - $params['board_selector'] = $this->projectPermission->getAllowedProjects($this->acl->getUserId()); + $params['board_selector'] = $this->projectPermission->getAllowedProjects($this->userSession->getId()); $params['values'] = $this->config->getAll(); $params['errors'] = array(); $params['config_content_for_layout'] = $this->template->render($template, $params); diff --git a/app/Controller/File.php b/app/Controller/File.php index 1585a701..63052610 100644 --- a/app/Controller/File.php +++ b/app/Controller/File.php @@ -37,11 +37,11 @@ class File extends Base $task = $this->getTask(); if ($this->file->upload($task['project_id'], $task['id'], 'files') === true) { - $this->response->redirect('?controller=task&action=show&task_id='.$task['id'].'#attachments'); + $this->response->redirect('?controller=task&action=show&task_id='.$task['id'].'&project_id='.$task['project_id'].'#attachments'); } else { $this->session->flashError(t('Unable to upload the file.')); - $this->response->redirect('?controller=file&action=create&task_id='.$task['id']); + $this->response->redirect('?controller=file&action=create&task_id='.$task['id'].'&project_id='.$task['project_id']); } } @@ -61,7 +61,7 @@ class File extends Base $this->response->binary(file_get_contents($filename)); } - $this->response->redirect('?controller=task&action=show&task_id='.$task['id']); + $this->response->redirect('?controller=task&action=show&task_id='.$task['id'].'&project_id='.$task['project_id']); } /** @@ -76,7 +76,8 @@ class File extends Base if ($file['task_id'] == $task['id']) { $this->response->html($this->template->render('file/open', array( - 'file' => $file + 'file' => $file, + 'task' => $task, ))); } } @@ -119,7 +120,7 @@ class File extends Base $this->session->flashError(t('Unable to remove this file.')); } - $this->response->redirect('?controller=task&action=show&task_id='.$task['id']); + $this->response->redirect('?controller=task&action=show&task_id='.$task['id'].'&project_id='.$task['project_id']); } /** diff --git a/app/Controller/Project.php b/app/Controller/Project.php index a7e8a39b..6079971a 100644 --- a/app/Controller/Project.php +++ b/app/Controller/Project.php @@ -17,7 +17,7 @@ class Project extends Base */ public function index() { - $projects = $this->project->getAll($this->acl->isRegularUser()); + $projects = $this->project->getAll(! $this->userSession->isAdmin()); $nb_projects = count($projects); $active_projects = array(); $inactive_projects = array(); @@ -32,7 +32,7 @@ class Project extends Base } $this->response->html($this->template->layout('project/index', array( - 'board_selector' => $this->projectPermission->getAllowedProjects($this->acl->getUserId()), + 'board_selector' => $this->projectPermission->getAllowedProjects($this->userSession->getId()), 'active_projects' => $active_projects, 'inactive_projects' => $inactive_projects, 'nb_projects' => $nb_projects, @@ -63,7 +63,7 @@ class Project extends Base */ public function exportTasks() { - $project = $this->getProjectManagement(); + $project = $this->getProject(); $from = $this->request->getStringParam('from'); $to = $this->request->getStringParam('to'); @@ -96,7 +96,7 @@ class Project extends Base */ public function exportDailyProjectSummary() { - $project = $this->getProjectManagement(); + $project = $this->getProject(); $from = $this->request->getStringParam('from'); $to = $this->request->getStringParam('to'); @@ -129,7 +129,7 @@ class Project extends Base */ public function share() { - $project = $this->getProjectManagement(); + $project = $this->getProject(); $switch = $this->request->getStringParam('switch'); if ($switch === 'enable' || $switch === 'disable') { @@ -158,7 +158,7 @@ class Project extends Base */ public function integration() { - $project = $this->getProjectManagement(); + $project = $this->getProject(); $this->response->html($this->projectLayout('project/integrations', array( 'project' => $project, @@ -174,7 +174,7 @@ class Project extends Base */ public function edit(array $values = array(), array $errors = array()) { - $project = $this->getProjectManagement(); + $project = $this->getProject(); $this->response->html($this->projectLayout('project/edit', array( 'values' => empty($values) ? $project : $values, @@ -191,7 +191,7 @@ class Project extends Base */ public function update() { - $project = $this->getProjectManagement(); + $project = $this->getProject(); $values = $this->request->getValues(); list($valid, $errors) = $this->project->validateModification($values); @@ -216,7 +216,7 @@ class Project extends Base */ public function users() { - $project = $this->getProjectManagement(); + $project = $this->getProject(); $this->response->html($this->projectLayout('project/users', array( 'project' => $project, @@ -232,7 +232,7 @@ class Project extends Base */ public function allowEverybody() { - $project = $this->getProjectManagement(); + $project = $this->getProject(); $values = $this->request->getValues() + array('is_everybody_allowed' => 0); list($valid,) = $this->projectPermission->validateProjectModification($values); @@ -257,12 +257,11 @@ class Project extends Base public function allow() { $values = $this->request->getValues(); - $this->checkProjectOwnerPermissions($values['project_id']); list($valid,) = $this->projectPermission->validateUserModification($values); if ($valid) { - if ($this->projectPermission->allowUser($values['project_id'], $values['user_id'])) { + if ($this->projectPermission->addMember($values['project_id'], $values['user_id'])) { $this->session->flash(t('Project updated successfully.')); } else { @@ -274,11 +273,11 @@ class Project extends Base } /** - * Set ownership for a specific user (admin only) + * Change the role of a project member * * @access public */ - public function setOwner() + public function role() { $this->checkCSRFParam(); @@ -288,12 +287,11 @@ class Project extends Base 'is_owner' => $this->request->getIntegerParam('is_owner'), ); - $this->checkProjectOwnerPermissions($values['project_id']); list($valid,) = $this->projectPermission->validateUserModification($values); if ($valid) { - if ($this->projectPermission->setOwner($values['project_id'], $values['user_id'], $values['is_owner'])) { + if ($this->projectPermission->changeRole($values['project_id'], $values['user_id'], $values['is_owner'])) { $this->session->flash(t('Project updated successfully.')); } else { @@ -318,12 +316,11 @@ class Project extends Base 'user_id' => $this->request->getIntegerParam('user_id'), ); - $this->checkProjectOwnerPermissions($values['project_id']); list($valid,) = $this->projectPermission->validateUserModification($values); if ($valid) { - if ($this->projectPermission->revokeUser($values['project_id'], $values['user_id'])) { + if ($this->projectPermission->revokeMember($values['project_id'], $values['user_id'])) { $this->session->flash(t('Project updated successfully.')); } else { @@ -341,7 +338,7 @@ class Project extends Base */ public function remove() { - $project = $this->getProjectManagement(); + $project = $this->getProject(); if ($this->request->getStringParam('remove') === 'yes') { @@ -370,7 +367,7 @@ class Project extends Base */ public function duplicate() { - $project = $this->getProjectManagement(); + $project = $this->getProject(); if ($this->request->getStringParam('duplicate') === 'yes') { @@ -398,7 +395,7 @@ class Project extends Base */ public function disable() { - $project = $this->getProjectManagement(); + $project = $this->getProject(); if ($this->request->getStringParam('disable') === 'yes') { @@ -426,7 +423,7 @@ class Project extends Base */ public function enable() { - $project = $this->getProjectManagement(); + $project = $this->getProject(); if ($this->request->getStringParam('enable') === 'yes') { @@ -478,7 +475,7 @@ class Project extends Base $project = $this->getProject(); $this->response->html($this->template->layout('project/activity', array( - 'board_selector' => $this->projectPermission->getAllowedProjects($this->acl->getUserId()), + 'board_selector' => $this->projectPermission->getAllowedProjects($this->userSession->getId()), 'events' => $this->projectActivity->getProject($project['id']), 'project' => $project, 'title' => t('%s\'s activity', $project['name']) @@ -507,7 +504,7 @@ class Project extends Base } $this->response->html($this->template->layout('project/search', array( - 'board_selector' => $this->projectPermission->getAllowedProjects($this->acl->getUserId()), + 'board_selector' => $this->projectPermission->getAllowedProjects($this->userSession->getId()), 'tasks' => $tasks, 'nb_tasks' => $nb_tasks, 'pagination' => array( @@ -550,7 +547,7 @@ class Project extends Base $nb_tasks = $this->taskPaginator->countClosedTasks($project['id']); $this->response->html($this->template->layout('project/tasks', array( - 'board_selector' => $this->projectPermission->getAllowedProjects($this->acl->getUserId()), + 'board_selector' => $this->projectPermission->getAllowedProjects($this->userSession->getId()), 'pagination' => array( 'controller' => 'project', 'action' => 'tasks', @@ -577,10 +574,10 @@ class Project extends Base */ public function create(array $values = array(), array $errors = array()) { - $is_private = $this->request->getIntegerParam('private', $this->acl->isRegularUser()); + $is_private = $this->request->getIntegerParam('private', ! $this->userSession->isAdmin()); $this->response->html($this->template->layout('project/new', array( - 'board_selector' => $this->projectPermission->getAllowedProjects($this->acl->getUserId()), + 'board_selector' => $this->projectPermission->getAllowedProjects($this->userSession->getId()), 'values' => empty($values) ? array('is_private' => $is_private) : $values, 'errors' => $errors, 'title' => $is_private ? t('New private project') : t('New project'), @@ -599,7 +596,7 @@ class Project extends Base if ($valid) { - $project_id = $this->project->create($values, $this->acl->getUserId(), true); + $project_id = $this->project->create($values, $this->userSession->getId(), true); if ($project_id) { $this->session->flash(t('Your project have been created successfully.')); diff --git a/app/Controller/Subtask.php b/app/Controller/Subtask.php index 948f3c76..59e9fe5c 100644 --- a/app/Controller/Subtask.php +++ b/app/Controller/Subtask.php @@ -73,10 +73,10 @@ class Subtask extends Base } if (isset($values['another_subtask']) && $values['another_subtask'] == 1) { - $this->response->redirect('?controller=subtask&action=create&task_id='.$task['id'].'&another_subtask=1'); + $this->response->redirect('?controller=subtask&action=create&task_id='.$task['id'].'&another_subtask=1&project_id='.$task['project_id']); } - $this->response->redirect('?controller=task&action=show&task_id='.$task['id'].'#subtasks'); + $this->response->redirect('?controller=task&action=show&task_id='.$task['id'].'&project_id='.$task['project_id'].'#subtasks'); } $this->create($values, $errors); @@ -124,7 +124,7 @@ class Subtask extends Base $this->session->flashError(t('Unable to update your sub-task.')); } - $this->response->redirect('?controller=task&action=show&task_id='.$task['id'].'#subtasks'); + $this->response->redirect('?controller=task&action=show&task_id='.$task['id'].'&project_id='.$task['project_id'].'#subtasks'); } $this->edit($values, $errors); @@ -164,7 +164,7 @@ class Subtask extends Base $this->session->flashError(t('Unable to remove this sub-task.')); } - $this->response->redirect('?controller=task&action=show&task_id='.$task['id'].'#subtasks'); + $this->response->redirect('?controller=task&action=show&task_id='.$task['id'].'&project_id='.$task['project_id'].'#subtasks'); } /** @@ -181,6 +181,6 @@ class Subtask extends Base $this->session->flashError(t('Unable to update your sub-task.')); } - $this->response->redirect('?controller=task&action=show&task_id='.$task['id'].'#subtasks'); + $this->response->redirect('?controller=task&action=show&task_id='.$task['id'].'&project_id='.$task['project_id'].'#subtasks'); } } diff --git a/app/Controller/Swimlane.php b/app/Controller/Swimlane.php index f0920f60..10b29569 100644 --- a/app/Controller/Swimlane.php +++ b/app/Controller/Swimlane.php @@ -38,7 +38,7 @@ class Swimlane extends Base */ public function index(array $values = array(), array $errors = array()) { - $project = $this->getProjectManagement(); + $project = $this->getProject(); $this->response->html($this->projectLayout('swimlane/index', array( 'default_swimlane' => $this->swimlane->getDefault($project['id']), @@ -58,7 +58,7 @@ class Swimlane extends Base */ public function save() { - $project = $this->getProjectManagement(); + $project = $this->getProject(); $values = $this->request->getValues(); list($valid, $errors) = $this->swimlane->validateCreation($values); @@ -84,7 +84,7 @@ class Swimlane extends Base */ public function change() { - $project = $this->getProjectManagement(); + $project = $this->getProject(); $values = $this->request->getValues(); list($valid, $errors) = $this->swimlane->validateDefaultModification($values); @@ -110,7 +110,7 @@ class Swimlane extends Base */ public function edit(array $values = array(), array $errors = array()) { - $project = $this->getProjectManagement(); + $project = $this->getProject(); $swimlane = $this->getSwimlane($project['id']); $this->response->html($this->projectLayout('swimlane/edit', array( @@ -128,7 +128,7 @@ class Swimlane extends Base */ public function update() { - $project = $this->getProjectManagement(); + $project = $this->getProject(); $values = $this->request->getValues(); list($valid, $errors) = $this->swimlane->validateModification($values); @@ -154,7 +154,7 @@ class Swimlane extends Base */ public function confirm() { - $project = $this->getProjectManagement(); + $project = $this->getProject(); $swimlane = $this->getSwimlane($project['id']); $this->response->html($this->projectLayout('swimlane/remove', array( @@ -172,7 +172,7 @@ class Swimlane extends Base public function remove() { $this->checkCSRFParam(); - $project = $this->getProjectManagement(); + $project = $this->getProject(); $swimlane_id = $this->request->getIntegerParam('swimlane_id'); if ($this->swimlane->remove($project['id'], $swimlane_id)) { @@ -192,7 +192,7 @@ class Swimlane extends Base public function disable() { $this->checkCSRFParam(); - $project = $this->getProjectManagement(); + $project = $this->getProject(); $swimlane_id = $this->request->getIntegerParam('swimlane_id'); if ($this->swimlane->disable($project['id'], $swimlane_id)) { @@ -212,7 +212,7 @@ class Swimlane extends Base public function enable() { $this->checkCSRFParam(); - $project = $this->getProjectManagement(); + $project = $this->getProject(); $swimlane_id = $this->request->getIntegerParam('swimlane_id'); if ($this->swimlane->enable($project['id'], $swimlane_id)) { @@ -232,7 +232,7 @@ class Swimlane extends Base public function moveup() { $this->checkCSRFParam(); - $project = $this->getProjectManagement(); + $project = $this->getProject(); $swimlane_id = $this->request->getIntegerParam('swimlane_id'); $this->swimlane->moveUp($project['id'], $swimlane_id); @@ -247,7 +247,7 @@ class Swimlane extends Base public function movedown() { $this->checkCSRFParam(); - $project = $this->getProjectManagement(); + $project = $this->getProject(); $swimlane_id = $this->request->getIntegerParam('swimlane_id'); $this->swimlane->moveDown($project['id'], $swimlane_id); diff --git a/app/Controller/Task.php b/app/Controller/Task.php index 284cbec0..77ea60d9 100644 --- a/app/Controller/Task.php +++ b/app/Controller/Task.php @@ -126,9 +126,7 @@ class Task extends Base { $project = $this->getProject(); $values = $this->request->getValues(); - $values['creator_id'] = $this->acl->getUserId(); - - $this->checkProjectPermissions($project['id']); + $values['creator_id'] = $this->userSession->getId(); list($valid, $errors) = $this->taskValidator->validateCreation($values); @@ -207,7 +205,7 @@ class Task extends Base $this->response->redirect('?controller=board&action=show&project_id='.$task['project_id']); } else { - $this->response->redirect('?controller=task&action=show&task_id='.$task['id']); + $this->response->redirect('?controller=task&action=show&task_id='.$task['id'].'&project_id='.$task['project_id']); } } else { @@ -248,7 +246,7 @@ class Task extends Base $this->session->flashError(t('Unable to update your task.')); } - $this->response->redirect('?controller=task&action=show&task_id='.$task['id']); + $this->response->redirect('?controller=task&action=show&task_id='.$task['id'].'&project_id='.$task['project_id']); } /** @@ -270,7 +268,7 @@ class Task extends Base $this->session->flashError(t('Unable to close this task.')); } - $this->response->redirect('?controller=task&action=show&task_id='.$task['id']); + $this->response->redirect('?controller=task&action=show&task_id='.$task['id'].'&project_id='.$task['project_id']); } $this->response->html($this->taskLayout('task/close', array( @@ -297,7 +295,7 @@ class Task extends Base $this->session->flashError(t('Unable to open this task.')); } - $this->response->redirect('?controller=task&action=show&task_id='.$task['id']); + $this->response->redirect('?controller=task&action=show&task_id='.$task['id'].'&project_id='.$task['project_id']); } $this->response->html($this->taskLayout('task/open', array( @@ -352,10 +350,10 @@ class Task extends Base if ($task_id) { $this->session->flash(t('Task created successfully.')); - $this->response->redirect('?controller=task&action=show&task_id='.$task_id); + $this->response->redirect('?controller=task&action=show&task_id='.$task_id.'&project_id='.$task['project_id']); } else { $this->session->flashError(t('Unable to create this task.')); - $this->response->redirect('?controller=task&action=duplicate&task_id='.$task['id']); + $this->response->redirect('?controller=task&action=duplicate&task_id='.$task['id'].'&project_id='.$task['project_id']); } } @@ -393,7 +391,7 @@ class Task extends Base $this->response->redirect('?controller=board&action=show&project_id='.$task['project_id']); } else { - $this->response->redirect('?controller=task&action=show&task_id='.$task['id']); + $this->response->redirect('?controller=task&action=show&task_id='.$task['id'].'&project_id='.$task['project_id']); } } } @@ -427,7 +425,7 @@ class Task extends Base $task = $this->getTask(); $values = $task; $errors = array(); - $projects_list = $this->projectPermission->getMemberProjects($this->acl->getUserId()); + $projects_list = $this->projectPermission->getMemberProjects($this->userSession->getId()); unset($projects_list[$task['project_id']]); @@ -440,7 +438,7 @@ class Task extends Base if ($this->taskDuplication->moveToProject($task['id'], $values['project_id'])) { $this->session->flash(t('Task updated successfully.')); - $this->response->redirect('?controller=task&action=show&task_id='.$task['id']); + $this->response->redirect('?controller=task&action=show&task_id='.$task['id'].'&project_id='.$task['project_id']); } else { $this->session->flashError(t('Unable to update your task.')); @@ -466,7 +464,7 @@ class Task extends Base $task = $this->getTask(); $values = $task; $errors = array(); - $projects_list = $this->projectPermission->getMemberProjects($this->acl->getUserId()); + $projects_list = $this->projectPermission->getMemberProjects($this->userSession->getId()); unset($projects_list[$task['project_id']]); @@ -479,7 +477,7 @@ class Task extends Base $task_id = $this->taskDuplication->duplicateToProject($task['id'], $values['project_id']); if ($task_id) { $this->session->flash(t('Task created successfully.')); - $this->response->redirect('?controller=task&action=show&task_id='.$task_id); + $this->response->redirect('?controller=task&action=show&task_id='.$task_id.'&project_id='.$task['project_id']); } else { $this->session->flashError(t('Unable to create your task.')); diff --git a/app/Controller/User.php b/app/Controller/User.php index 619bbc90..00c2f104 100644 --- a/app/Controller/User.php +++ b/app/Controller/User.php @@ -18,7 +18,7 @@ class User extends Base public function logout() { $this->checkCSRFParam(); - $this->authentication->backend('rememberMe')->destroy($this->acl->getUserId()); + $this->authentication->backend('rememberMe')->destroy($this->userSession->getId()); $this->session->close(); $this->response->redirect('?controller=user&action=login'); } @@ -30,7 +30,7 @@ class User extends Base */ public function login(array $values = array(), array $errors = array()) { - if ($this->acl->isLogged()) { + if ($this->userSession->isLogged()) { $this->response->redirect('?controller=app'); } @@ -78,7 +78,7 @@ class User extends Base { $content = $this->template->render($template, $params); $params['user_content_for_layout'] = $content; - $params['board_selector'] = $this->projectPermission->getAllowedProjects($this->acl->getUserId()); + $params['board_selector'] = $this->projectPermission->getAllowedProjects($this->userSession->getId()); if (isset($params['user'])) { $params['title'] = ($params['user']['name'] ?: $params['user']['username']).' (#'.$params['user']['id'].')'; @@ -101,7 +101,7 @@ class User extends Base $this->notfound(); } - if ($this->acl->isRegularUser() && $this->acl->getUserId() != $user['id']) { + if (! $this->userSession->isAdmin() && $this->userSession->getId() != $user['id']) { $this->forbidden(); } @@ -125,7 +125,7 @@ class User extends Base $this->response->html( $this->template->layout('user/index', array( - 'board_selector' => $this->projectPermission->getAllowedProjects($this->acl->getUserId()), + 'board_selector' => $this->projectPermission->getAllowedProjects($this->userSession->getId()), 'projects' => $this->project->getList(), 'nb_users' => $nb_users, 'users' => $users, @@ -151,7 +151,7 @@ class User extends Base public function create(array $values = array(), array $errors = array()) { $this->response->html($this->template->layout('user/new', array( - 'board_selector' => $this->projectPermission->getAllowedProjects($this->acl->getUserId()), + 'board_selector' => $this->projectPermission->getAllowedProjects($this->userSession->getId()), 'projects' => $this->project->getList(), 'errors' => $errors, 'values' => $values, @@ -328,7 +328,7 @@ class User extends Base $values = $this->request->getValues(); - if ($this->acl->isAdminUser()) { + if ($this->userSession->isAdmin()) { $values += array('is_admin' => 0); } else { @@ -404,16 +404,16 @@ class User extends Base if (is_array($profile)) { // If the user is already logged, link the account otherwise authenticate - if ($this->acl->isLogged()) { + if ($this->userSession->isLogged()) { - if ($this->authentication->backend('google')->updateUser($this->acl->getUserId(), $profile)) { + if ($this->authentication->backend('google')->updateUser($this->userSession->getId(), $profile)) { $this->session->flash(t('Your Google Account is linked to your profile successfully.')); } else { $this->session->flashError(t('Unable to link your Google Account.')); } - $this->response->redirect('?controller=user&action=external&user_id='.$this->acl->getUserId()); + $this->response->redirect('?controller=user&action=external&user_id='.$this->userSession->getId()); } else if ($this->authentication->backend('google')->authenticate($profile['id'])) { $this->response->redirect('?controller=app'); @@ -441,14 +441,14 @@ class User extends Base public function unlinkGoogle() { $this->checkCSRFParam(); - if ($this->authentication->backend('google')->unlink($this->acl->getUserId())) { + if ($this->authentication->backend('google')->unlink($this->userSession->getId())) { $this->session->flash(t('Your Google Account is not linked anymore to your profile.')); } else { $this->session->flashError(t('Unable to unlink your Google Account.')); } - $this->response->redirect('?controller=user&action=external&user_id='.$this->acl->getUserId()); + $this->response->redirect('?controller=user&action=external&user_id='.$this->userSession->getId()); } /** @@ -466,16 +466,16 @@ class User extends Base if (is_array($profile)) { // If the user is already logged, link the account otherwise authenticate - if ($this->acl->isLogged()) { + if ($this->userSession->isLogged()) { - if ($this->authentication->backend('gitHub')->updateUser($this->acl->getUserId(), $profile)) { + if ($this->authentication->backend('gitHub')->updateUser($this->userSession->getId(), $profile)) { $this->session->flash(t('Your GitHub account was successfully linked to your profile.')); } else { $this->session->flashError(t('Unable to link your GitHub Account.')); } - $this->response->redirect('?controller=user&action=external&user_id='.$this->acl->getUserId()); + $this->response->redirect('?controller=user&action=external&user_id='.$this->userSession->getId()); } else if ($this->authentication->backend('gitHub')->authenticate($profile['id'])) { $this->response->redirect('?controller=app'); @@ -506,13 +506,13 @@ class User extends Base $this->authentication->backend('gitHub')->revokeGitHubAccess(); - if ($this->authentication->backend('gitHub')->unlink($this->acl->getUserId())) { + if ($this->authentication->backend('gitHub')->unlink($this->userSession->getId())) { $this->session->flash(t('Your GitHub account is no longer linked to your profile.')); } else { $this->session->flashError(t('Unable to unlink your GitHub Account.')); } - $this->response->redirect('?controller=user&action=external&user_id='.$this->acl->getUserId()); + $this->response->redirect('?controller=user&action=external&user_id='.$this->userSession->getId()); } } diff --git a/app/Core/Helper.php b/app/Core/Helper.php index 82dd6698..5eaa8dc9 100644 --- a/app/Core/Helper.php +++ b/app/Core/Helper.php @@ -498,14 +498,14 @@ class Helper * @param array $link Link parameters for replacement * @return string */ - public function markdown($text, array $link = array('controller' => 'task', 'action' => 'show', 'params' => array())) + public function markdown($text, array $link = array()) { $html = Parsedown::instance() ->setMarkupEscaped(true) # escapes markup (HTML) ->text($text); // Replace task #123 by a link to the task - if (preg_match_all('!#(\d+)!i', $html, $matches, PREG_SET_ORDER)) { + if (! empty($link) && preg_match_all('!#(\d+)!i', $html, $matches, PREG_SET_ORDER)) { foreach ($matches as $match) { diff --git a/app/Model/Acl.php b/app/Model/Acl.php index d294197a..0d26edc4 100644 --- a/app/Model/Acl.php +++ b/app/Model/Acl.php @@ -3,7 +3,7 @@ namespace Model; /** - * Acl model + * Access List * * @package model * @author Frederic Guillot @@ -16,162 +16,188 @@ class Acl extends Base * @access private * @var array */ - private $public_actions = array( + private $public_acl = array( 'user' => array('login', 'check', 'google', 'github'), 'task' => array('readonly'), 'board' => array('readonly'), 'project' => array('feed'), - 'webhook' => array('task', 'github', 'gitlab'), + 'webhook' => '*', ); /** - * Controllers and actions allowed for regular users + * Controllers and actions for project members * * @access private * @var array */ - private $user_actions = array( - 'app' => array('index', 'preview', 'status'), - 'project' => array('index', 'show', 'exporttasks', 'exportdaily', 'share', 'edit', 'update', 'users', 'remove', 'duplicate', 'disable', 'enable', 'activity', 'search', 'tasks', 'create', 'save', 'revoke', 'setowner', 'allow'), - 'board' => array('index', 'show', 'save', 'check', 'changeassignee', 'updateassignee', 'changecategory', 'updatecategory', 'movecolumn', 'edit', 'update', 'add', 'confirm', 'remove', 'subtasks', 'togglesubtask', 'attachments', 'comments', 'description'), - 'user' => array('edit', 'forbidden', 'logout', 'show', 'external', 'unlinkgoogle', 'unlinkgithub', 'sessions', 'removesession', 'last', 'notifications', 'password'), - 'comment' => array('create', 'save', 'confirm', 'remove', 'update', 'edit', 'forbidden'), - 'file' => array('create', 'save', 'download', 'confirm', 'remove', 'open', 'image'), - 'subtask' => array('create', 'save', 'edit', 'update', 'confirm', 'remove', 'togglestatus'), - 'task' => array('show', 'create', 'save', 'edit', 'update', 'close', 'open', 'duplicate', 'remove', 'description', 'move', 'copy', 'time'), - 'category' => array('index', 'save', 'edit', 'update', 'confirm', 'remove'), - 'action' => array('index', 'event', 'params', 'create', 'confirm', 'remove'), - 'analytic' => array('tasks', 'users', 'cfd'), - 'swimlane' => array('index', 'save', 'change', 'edit', 'update', 'confirm', 'remove', 'disable', 'enable', 'moveup', 'movedown'), + private $member_acl = array( + 'board' => '*', + 'comment' => '*', + 'file' => '*', + 'project' => array('show', 'tasks', 'search', 'activity'), + 'subtask' => '*', + 'task' => '*', ); /** - * Return true if the specified controller/action is allowed according to the given acl + * Controllers and actions for project managers * - * @access public - * @param array $acl Acl list - * @param string $controller Controller name - * @param string $action Action name - * @return bool + * @access private + * @var array */ - public function isAllowedAction(array $acl, $controller, $action) - { - if (isset($acl[$controller])) { - return in_array($action, $acl[$controller]); - } + private $manager_acl = array( + 'action' => '*', + 'analytic' => '*', + 'board' => array('movecolumn', 'edit', 'update', 'add', 'remove'), + 'category' => '*', + 'project' => array('edit', 'update', 'exporttasks', 'exportdailyprojectsummary', 'share', 'integration', 'users', 'alloweverybody', 'allow', 'setowner', 'revoke', 'duplicate', 'disable', 'enable'), + 'swimlane' => '*', + 'task' => array('remove'), + ); - return false; - } + /** + * Controllers and actions for admins + * + * @access private + * @var array + */ + private $admin_acl = array( + 'user' => array('index', 'create', 'save', 'remove'), + 'config' => '*', + 'project' => array('remove'), + ); /** - * Return true if the given action is public + * Return true if the specified controller/action match the given acl * * @access public + * @param array $acl Acl list * @param string $controller Controller name * @param string $action Action name * @return bool */ - public function isPublicAction($controller, $action) + public function matchAcl(array $acl, $controller, $action) { - return $this->isAllowedAction($this->public_actions, $controller, $action); + $action = strtolower($action); + return isset($acl[$controller]) && $this->hasAction($action, $acl[$controller]); } /** - * Return true if the given action is allowed for a regular user + * Return true if the specified action is inside the list of actions * * @access public - * @param string $controller Controller name * @param string $action Action name + * @param mixed $action Actions list * @return bool */ - public function isUserAction($controller, $action) + public function hasAction($action, $actions) { - return $this->isAllowedAction($this->user_actions, $controller, $action); + if (is_array($actions)) { + return in_array($action, $actions); + } + + return $actions === '*'; } /** - * Return true if the logged user is admin + * Return true if the given action is public * * @access public + * @param string $controller Controller name + * @param string $action Action name * @return bool */ - public function isAdminUser() + public function isPublicAction($controller, $action) { - return isset($this->session['user']['is_admin']) && $this->session['user']['is_admin'] === true; + return $this->matchAcl($this->public_acl, $controller, $action); } /** - * Return true if the logged user is not admin + * Return true if the given action is for admins * * @access public + * @param string $controller Controller name + * @param string $action Action name * @return bool */ - public function isRegularUser() + public function isAdminAction($controller, $action) { - return isset($this->session['user']['is_admin']) && $this->session['user']['is_admin'] === false; + return $this->matchAcl($this->admin_acl, $controller, $action); } /** - * Get the connected user id + * Return true if the given action is for project managers * * @access public - * @return integer + * @param string $controller Controller name + * @param string $action Action name + * @return bool */ - public function getUserId() + public function isManagerAction($controller, $action) { - return isset($this->session['user']['id']) ? (int) $this->session['user']['id'] : 0; + return $this->matchAcl($this->manager_acl, $controller, $action); } /** - * Check if the given user_id is the connected user + * Return true if the given action is for project members * - * @param integer $user_id User id - * @return boolean + * @access public + * @param string $controller Controller name + * @param string $action Action name + * @return bool */ - public function isCurrentUser($user_id) + public function isMemberAction($controller, $action) { - return $this->acl->getUserId() == $user_id; + return $this->matchAcl($this->member_acl, $controller, $action); } /** - * Check is the user is connected + * Return true if the visitor is allowed to access to the given page + * We suppose the user already authenticated * * @access public + * @param string $controller Controller name + * @param string $action Action name + * @param integer $project_id Project id * @return bool */ - public function isLogged() + public function isAllowed($controller, $action, $project_id = 0) { - return ! empty($this->session['user']); + // If you are admin you have access to everything + if ($this->userSession->isAdmin()) { + return true; + } + + // If you access to an admin action, your are not allowed + if ($this->isAdminAction($controller, $action)) { + return false; + } + + // Check project manager permissions + if ($this->isManagerAction($controller, $action)) { + return $this->isManagerActionAllowed($project_id); + } + + // Check project member permissions + if ($this->isMemberAction($controller, $action)) { + return $this->isMemberActionAllowed($project_id); + } + + // Other applications actions are allowed + return true; } - /** - * Check is the user was authenticated with the RememberMe or set the value - * - * @access public - * @param bool $value Set true if the user use the RememberMe - * @return bool - */ - public function isRememberMe($value = null) + public function isManagerActionAllowed($project_id) { - if ($value !== null) { - $this->session['is_remember_me'] = $value; + if ($this->userSession->isAdmin()) { + return true; } - return empty($this->session['is_remember_me']) ? false : $this->session['is_remember_me']; + return $project_id > 0 && $this->projectPermission->isManager($project_id, $this->userSession->getId()); } - /** - * Check if an action is allowed for the logged user - * - * @access public - * @param string $controller Controller name - * @param string $action Action name - * @return bool - */ - public function isPageAccessAllowed($controller, $action) + public function isMemberActionAllowed($project_id) { - return $this->isPublicAction($controller, $action) || - $this->isAdminUser() || - ($this->isRegularUser() && $this->isUserAction($controller, $action)); + return $project_id > 0 && $this->projectPermission->isMember($project_id, $this->userSession->getId()); } } diff --git a/app/Model/Authentication.php b/app/Model/Authentication.php index 87493c88..f917bff4 100644 --- a/app/Model/Authentication.php +++ b/app/Model/Authentication.php @@ -41,13 +41,8 @@ class Authentication extends Base */ public function isAuthenticated($controller, $action) { - // If the action is public we don't need to do any checks - if ($this->acl->isPublicAction($controller, $action)) { - return true; - } - // If the user is already logged it's ok - if ($this->acl->isLogged()) { + if ($this->userSession->isLogged()) { // We update each time the RememberMe cookie tokens if ($this->backend('rememberMe')->hasCookie()) { @@ -117,7 +112,7 @@ class Authentication extends Base if (! empty($values['remember_me'])) { $credentials = $this->backend('rememberMe') - ->create($this->acl->getUserId(), Request::getIpAddress(), Request::getUserAgent()); + ->create($this->userSession->getId(), Request::getIpAddress(), Request::getUserAgent()); $this->backend('rememberMe')->writeCookie($credentials['token'], $credentials['sequence'], $credentials['expiration']); } diff --git a/app/Model/Base.php b/app/Model/Base.php index db670969..3f847c2e 100644 --- a/app/Model/Base.php +++ b/app/Model/Base.php @@ -39,6 +39,7 @@ use Pimple\Container; * @property \Model\TaskValidator $taskValidator * @property \Model\TimeTracking $timeTracking * @property \Model\User $user + * @property \Model\UserSession $userSession * @property \Model\Webhook $webhook */ abstract class Base diff --git a/app/Model/Notification.php b/app/Model/Notification.php index 99db78ad..8c13aada 100644 --- a/app/Model/Notification.php +++ b/app/Model/Notification.php @@ -66,7 +66,7 @@ class Notification extends Base { // Exclude the connected user if (Session::isOpen()) { - $exclude_users[] = $this->acl->getUserId(); + $exclude_users[] = $this->userSession->getId(); } $users = $this->getUsersWithNotification($project_id, $exclude_users); diff --git a/app/Model/Project.php b/app/Model/Project.php index 278fe6ab..de9408ec 100644 --- a/app/Model/Project.php +++ b/app/Model/Project.php @@ -109,7 +109,7 @@ class Project extends Base foreach ($projects as $key => $project) { - if (! $this->projectPermission->isUserAllowed($project['id'], $this->acl->getUserId())) { + if (! $this->projectPermission->isUserAllowed($project['id'], $this->userSession->getId())) { unset($projects[$key]); } } @@ -295,7 +295,7 @@ class Project extends Base } if ($add_user && $user_id) { - $this->projectPermission->allowUser($project_id, $user_id); + $this->projectPermission->addManager($project_id, $user_id); } $this->category->createDefaultCategories($project_id); diff --git a/app/Model/ProjectPermission.php b/app/Model/ProjectPermission.php index bcb11eca..a53f9195 100644 --- a/app/Model/ProjectPermission.php +++ b/app/Model/ProjectPermission.php @@ -92,7 +92,7 @@ class ProjectPermission extends Base * @param integer $project_id Project id * @return array */ - public function getOwners($project_id) + public function getManagers($project_id) { $users = $this->db ->table(self::TABLE) @@ -118,13 +118,13 @@ class ProjectPermission extends Base $users = array( 'allowed' => array(), 'not_allowed' => array(), - 'owners' => array(), + 'managers' => array(), ); $all_users = $this->user->getList(); $users['allowed'] = $this->getMembers($project_id); - $users['owners'] = $this->getOwners($project_id); + $users['managers'] = $this->getManagers($project_id); foreach ($all_users as $user_id => $username) { @@ -137,14 +137,14 @@ class ProjectPermission extends Base } /** - * Allow a specific user for a given project + * Add a new project member * * @access public * @param integer $project_id Project id * @param integer $user_id User id * @return bool */ - public function allowUser($project_id, $user_id) + public function addMember($project_id, $user_id) { return $this->db ->table(self::TABLE) @@ -152,38 +152,53 @@ class ProjectPermission extends Base } /** - * Make the specific user owner of the given project + * Remove a member * * @access public * @param integer $project_id Project id * @param integer $user_id User id - * @param integer $is_owner Is user owner of the project * @return bool */ - public function setOwner($project_id, $user_id, $is_owner = 1) + public function revokeMember($project_id, $user_id) { return $this->db ->table(self::TABLE) ->eq('project_id', $project_id) ->eq('user_id', $user_id) - ->update(array('is_owner' => $is_owner)); + ->remove(); + } + + /** + * Add a project manager + * + * @access public + * @param integer $project_id Project id + * @param integer $user_id User id + * @return bool + */ + public function addManager($project_id, $user_id) + { + return $this->db + ->table(self::TABLE) + ->save(array('project_id' => $project_id, 'user_id' => $user_id, 'is_owner' => 1)); } /** - * Revoke a specific user for a given project + * Change the role of a member * * @access public * @param integer $project_id Project id * @param integer $user_id User id + * @param integer $is_owner Is user owner of the project * @return bool */ - public function revokeUser($project_id, $user_id) + public function changeRole($project_id, $user_id, $is_owner) { return $this->db ->table(self::TABLE) ->eq('project_id', $project_id) ->eq('user_id', $user_id) - ->remove(); + ->update(array('is_owner' => $is_owner)); } /** @@ -200,29 +215,29 @@ class ProjectPermission extends Base return true; } - return (bool) $this->db + return $this->db ->table(self::TABLE) ->eq('project_id', $project_id) ->eq('user_id', $user_id) - ->count(); + ->count() === 1; } /** - * Check if a specific user is owner of a given project + * Check if a specific user is manager of a given project * * @access public * @param integer $project_id Project id * @param integer $user_id User id * @return bool */ - public function isOwner($project_id, $user_id) + public function isManager($project_id, $user_id) { - return (bool) $this->db + return $this->db ->table(self::TABLE) ->eq('project_id', $project_id) ->eq('user_id', $user_id) ->eq('is_owner', 1) - ->count(); + ->count() === 1; } /** @@ -247,36 +262,11 @@ class ProjectPermission extends Base */ public function isEverybodyAllowed($project_id) { - return (bool) $this->db + return $this->db ->table(Project::TABLE) ->eq('id', $project_id) ->eq('is_everybody_allowed', 1) - ->count(); - } - - /** - * Check if a specific user is allowed to manage a project - * - * @access public - * @param integer $project_id Project id - * @param integer $user_id User id - * @return bool - */ - public function adminAllowed($project_id, $user_id) - { - if ($this->user->isAdmin($user_id)) { - return true; - } - - if ($this->isUserAllowed($project_id, $user_id) && $this->project->isPrivate($project_id)) { - return true; - } - - if ($this->isOwner($project_id, $user_id)) { - return true; - } - - return false; + ->count() === 1; } /** @@ -336,7 +326,7 @@ class ProjectPermission extends Base $users = $this->getMembers($project_from); foreach ($users as $user_id => $name) { - if (! $this->allowUser($project_to, $user_id)) { + if (! $this->addMember($project_to, $user_id)) { // TODO: Duplicate managers return false; } } diff --git a/app/Model/SubTask.php b/app/Model/SubTask.php index 12558429..adc5aa73 100644 --- a/app/Model/SubTask.php +++ b/app/Model/SubTask.php @@ -227,6 +227,7 @@ class SubTask extends Base $subtasks = $db->table(SubTask::TABLE) ->columns('title', 'time_estimated') ->eq('task_id', $src_task_id) + ->asc('id') // Explicit sorting for postgresql ->findAll(); foreach ($subtasks as &$subtask) { diff --git a/app/Model/TaskExport.php b/app/Model/TaskExport.php index 13a1eddd..1592deb1 100644 --- a/app/Model/TaskExport.php +++ b/app/Model/TaskExport.php @@ -73,6 +73,7 @@ class TaskExport extends Base LEFT JOIN columns ON columns.id = tasks.column_id LEFT JOIN projects ON projects.id = tasks.project_id WHERE tasks.date_creation >= ? AND tasks.date_creation <= ? AND tasks.project_id = ? + ORDER BY tasks.id ASC '; if (! is_numeric($from)) { diff --git a/app/Model/TaskPermission.php b/app/Model/TaskPermission.php index 2ab154f4..53740a9a 100644 --- a/app/Model/TaskPermission.php +++ b/app/Model/TaskPermission.php @@ -20,10 +20,10 @@ class TaskPermission extends Base */ public function canRemoveTask(array $task) { - if ($this->acl->isAdminUser()) { + if ($this->userSession->isAdmin()) { return true; } - else if (isset($task['creator_id']) && $task['creator_id'] == $this->acl->getUserId()) { + else if (isset($task['creator_id']) && $task['creator_id'] == $this->userSession->getId()) { return true; } diff --git a/app/Model/TaskPosition.php b/app/Model/TaskPosition.php index a1e4152c..2c271de7 100644 --- a/app/Model/TaskPosition.php +++ b/app/Model/TaskPosition.php @@ -72,6 +72,7 @@ class TaskPosition extends Base ->eq('column_id', $board_column_id) ->neq('id', $task_id) ->asc('position') + ->asc('id') // Fix Postgresql unit test ->findAllByColumn('id'); } diff --git a/app/Model/User.php b/app/Model/User.php index 3754b918..78d44b47 100644 --- a/app/Model/User.php +++ b/app/Model/User.php @@ -48,46 +48,11 @@ class User extends Base */ public function isAdmin($user_id) { - $result = $this->db + return $this->db ->table(User::TABLE) ->eq('id', $user_id) ->eq('is_admin', 1) - ->count(); - - return $result > 0; - } - - /** - * Get the default project from the session - * - * @access public - * @return integer - */ - public function getFavoriteProjectId() - { - return isset($this->session['user']['default_project_id']) ? $this->session['user']['default_project_id'] : 0; - } - - /** - * Get the last seen project from the session - * - * @access public - * @return integer - */ - public function getLastSeenProjectId() - { - return empty($this->session['last_show_project_id']) ? 0 : $this->session['last_show_project_id']; - } - - /** - * Set the last seen project from the session - * - * @access public - * @@param integer $project_id Project id - */ - public function storeLastSeenProjectId($project_id) - { - $this->session['last_show_project_id'] = (int) $project_id; + ->count() === 1; } /** @@ -287,7 +252,7 @@ class User extends Base $result = $this->db->table(self::TABLE)->eq('id', $values['id'])->update($values); // If the user is connected refresh his session - if (Session::isOpen() && $this->acl->getUserId() == $values['id']) { + if (Session::isOpen() && $this->userSession->getId() == $values['id']) { $this->updateSession(); } @@ -337,7 +302,7 @@ class User extends Base public function updateSession(array $user = array()) { if (empty($user)) { - $user = $this->getById($this->acl->getUserId()); + $user = $this->getById($this->userSession->getId()); } if (isset($user['password'])) { diff --git a/app/Model/UserSession.php b/app/Model/UserSession.php new file mode 100644 index 00000000..c27b3743 --- /dev/null +++ b/app/Model/UserSession.php @@ -0,0 +1,89 @@ +<?php + +namespace Model; + +/** + * User Session + * + * @package model + * @author Frederic Guillot + */ +class UserSession extends Base +{ + /** + * Return true if the logged user is admin + * + * @access public + * @return bool + */ + public function isAdmin() + { + return isset($this->session['user']['is_admin']) && $this->session['user']['is_admin'] === true; + } + + /** + * Get the connected user id + * + * @access public + * @return integer + */ + public function getId() + { + return isset($this->session['user']['id']) ? (int) $this->session['user']['id'] : 0; + } + + /** + * Check if the given user_id is the connected user + * + * @param integer $user_id User id + * @return boolean + */ + public function isCurrentUser($user_id) + { + return $this->getId() == $user_id; + } + + /** + * Check is the user is connected + * + * @access public + * @return bool + */ + public function isLogged() + { + return ! empty($this->session['user']); + } + + /** + * Get the last seen project from the session + * + * @access public + * @return integer + */ + public function getLastSeenProjectId() + { + return empty($this->session['last_show_project_id']) ? 0 : $this->session['last_show_project_id']; + } + + /** + * Get the default project from the session + * + * @access public + * @return integer + */ + public function getFavoriteProjectId() + { + return isset($this->session['user']['default_project_id']) ? $this->session['user']['default_project_id'] : 0; + } + + /** + * Set the last seen project from the session + * + * @access public + * @param integer $project_id Project id + */ + public function storeLastSeenProjectId($project_id) + { + $this->session['last_show_project_id'] = (int) $project_id; + } +} diff --git a/app/Schema/Mysql.php b/app/Schema/Mysql.php index 4d155f26..25ef86d5 100644 --- a/app/Schema/Mysql.php +++ b/app/Schema/Mysql.php @@ -5,7 +5,31 @@ namespace Schema; use PDO; use Core\Security; -const VERSION = 39; +const VERSION = 40; + +function version_40($pdo) +{ + // Avoid some full table scans + $pdo->exec('CREATE INDEX users_admin_idx ON users(is_admin)'); + $pdo->exec('CREATE INDEX columns_project_idx ON columns(project_id)'); + $pdo->exec('CREATE INDEX tasks_project_idx ON tasks(project_id)'); + $pdo->exec('CREATE INDEX swimlanes_project_idx ON swimlanes(project_id)'); + $pdo->exec('CREATE INDEX categories_project_idx ON project_has_categories(project_id)'); + $pdo->exec('CREATE INDEX subtasks_task_idx ON task_has_subtasks(task_id)'); + $pdo->exec('CREATE INDEX files_task_idx ON task_has_files(task_id)'); + $pdo->exec('CREATE INDEX comments_task_idx ON comments(task_id)'); + + // Set the ownership for all private projects + $rq = $pdo->prepare('SELECT id FROM projects WHERE is_private=1'); + $rq->execute(); + $project_ids = $rq->fetchAll(PDO::FETCH_COLUMN, 0); + + $rq = $pdo->prepare('UPDATE project_has_users SET is_owner=1 WHERE project_id=?'); + + foreach ($project_ids as $project_id) { + $rq->execute(array($project_id)); + } +} function version_39($pdo) { diff --git a/app/Schema/Postgres.php b/app/Schema/Postgres.php index 2d84a578..75d184de 100644 --- a/app/Schema/Postgres.php +++ b/app/Schema/Postgres.php @@ -5,7 +5,31 @@ namespace Schema; use PDO; use Core\Security; -const VERSION = 20; +const VERSION = 21; + +function version_21($pdo) +{ + // Avoid some full table scans + $pdo->exec('CREATE INDEX users_admin_idx ON users(is_admin)'); + $pdo->exec('CREATE INDEX columns_project_idx ON columns(project_id)'); + $pdo->exec('CREATE INDEX tasks_project_idx ON tasks(project_id)'); + $pdo->exec('CREATE INDEX swimlanes_project_idx ON swimlanes(project_id)'); + $pdo->exec('CREATE INDEX categories_project_idx ON project_has_categories(project_id)'); + $pdo->exec('CREATE INDEX subtasks_task_idx ON task_has_subtasks(task_id)'); + $pdo->exec('CREATE INDEX files_task_idx ON task_has_files(task_id)'); + $pdo->exec('CREATE INDEX comments_task_idx ON comments(task_id)'); + + // Set the ownership for all private projects + $rq = $pdo->prepare("SELECT id FROM projects WHERE is_private='1'"); + $rq->execute(); + $project_ids = $rq->fetchAll(PDO::FETCH_COLUMN, 0); + + $rq = $pdo->prepare('UPDATE project_has_users SET is_owner=1 WHERE project_id=?'); + + foreach ($project_ids as $project_id) { + $rq->execute(array($project_id)); + } +} function version_20($pdo) { diff --git a/app/Schema/Sqlite.php b/app/Schema/Sqlite.php index 39377a91..39a40ace 100644 --- a/app/Schema/Sqlite.php +++ b/app/Schema/Sqlite.php @@ -5,7 +5,31 @@ namespace Schema; use Core\Security; use PDO; -const VERSION = 38; +const VERSION = 39; + +function version_39($pdo) +{ + // Avoid some full table scans + $pdo->exec('CREATE INDEX users_admin_idx ON users(is_admin)'); + $pdo->exec('CREATE INDEX columns_project_idx ON columns(project_id)'); + $pdo->exec('CREATE INDEX tasks_project_idx ON tasks(project_id)'); + $pdo->exec('CREATE INDEX swimlanes_project_idx ON swimlanes(project_id)'); + $pdo->exec('CREATE INDEX categories_project_idx ON project_has_categories(project_id)'); + $pdo->exec('CREATE INDEX subtasks_task_idx ON task_has_subtasks(task_id)'); + $pdo->exec('CREATE INDEX files_task_idx ON task_has_files(task_id)'); + $pdo->exec('CREATE INDEX comments_task_idx ON comments(task_id)'); + + // Set the ownership for all private projects + $rq = $pdo->prepare('SELECT id FROM projects WHERE is_private=1'); + $rq->execute(); + $project_ids = $rq->fetchAll(PDO::FETCH_COLUMN, 0); + + $rq = $pdo->prepare('UPDATE project_has_users SET is_owner=1 WHERE project_id=?'); + + foreach ($project_ids as $project_id) { + $rq->execute(array($project_id)); + } +} function version_38($pdo) { diff --git a/app/ServiceProvider/ClassProvider.php b/app/ServiceProvider/ClassProvider.php index 645a85ef..39a32cf6 100644 --- a/app/ServiceProvider/ClassProvider.php +++ b/app/ServiceProvider/ClassProvider.php @@ -46,6 +46,7 @@ class ClassProvider implements ServiceProviderInterface 'TaskValidator', 'TimeTracking', 'User', + 'UserSession', 'Webhook', ), 'Core' => array( diff --git a/app/Subscriber/Base.php b/app/Subscriber/Base.php index 5f884b39..abc051b3 100644 --- a/app/Subscriber/Base.php +++ b/app/Subscriber/Base.php @@ -19,6 +19,7 @@ use Pimple\Container; * @property \Model\Task $task * @property \Model\TaskExport $taskExport * @property \Model\TaskFinder $taskFinder + * @property \Model\UserSession $userSession */ abstract class Base { diff --git a/app/Subscriber/BootstrapSubscriber.php b/app/Subscriber/BootstrapSubscriber.php index 30b8f168..e256159a 100644 --- a/app/Subscriber/BootstrapSubscriber.php +++ b/app/Subscriber/BootstrapSubscriber.php @@ -16,7 +16,7 @@ class BootstrapSubscriber extends Base implements EventSubscriberInterface public function setup() { - $this->container['config']->setupTranslations(); - $this->container['config']->setupTimezone(); + $this->config->setupTranslations(); + $this->config->setupTimezone(); } } diff --git a/app/Subscriber/ProjectActivitySubscriber.php b/app/Subscriber/ProjectActivitySubscriber.php index 1aca8539..3daf2f4d 100644 --- a/app/Subscriber/ProjectActivitySubscriber.php +++ b/app/Subscriber/ProjectActivitySubscriber.php @@ -30,14 +30,14 @@ class ProjectActivitySubscriber extends Base implements EventSubscriberInterface public function execute(GenericEvent $event) { // Executed only when someone is logged - if ($this->container['acl']->isLogged() && isset($event['task_id'])) { + if ($this->userSession->isLogged() && isset($event['task_id'])) { $values = $this->getValues($event); $this->projectActivity->createEvent( $values['task']['project_id'], $values['task']['id'], - $this->acl->getUserId(), + $this->userSession->getId(), $event->getName(), $values ); diff --git a/app/Template/app/dashboard.php b/app/Template/app/dashboard.php index 5064967b..81305ed8 100644 --- a/app/Template/app/dashboard.php +++ b/app/Template/app/dashboard.php @@ -1,12 +1,12 @@ <section id="main"> <div class="page-header"> <ul> - <?php if ($this->acl->isAdminUser()): ?> + <?php if ($this->userSession->isAdmin()): ?> <li><i class="fa fa-plus fa-fw"></i><?= $this->a(t('New project'), 'project', 'create') ?></li> <?php endif ?> <li><i class="fa fa-lock fa-fw"></i><?= $this->a(t('New private project'), 'project', 'create', array('private' => 1)) ?></li> <li><i class="fa fa-folder fa-fw"></i><?= $this->a(t('Project management'), 'project', 'index') ?></li> - <?php if ($this->acl->isAdminUser()): ?> + <?php if ($this->userSession->isAdmin()): ?> <li><i class="fa fa-user fa-fw"></i><?= $this->a(t('User management'), 'user', 'index') ?></li> <li><i class="fa fa-cog fa-fw"></i><?= $this->a(t('Settings'), 'config', 'index') ?></li> <?php endif ?> diff --git a/app/Template/app/projects.php b/app/Template/app/projects.php index cb698c28..1a405210 100644 --- a/app/Template/app/projects.php +++ b/app/Template/app/projects.php @@ -14,7 +14,7 @@ <?= $this->a('#'.$project['id'], 'board', 'show', array('project_id' => $project['id']), false, 'dashboard-table-link') ?> </td> <td> - <?php if ($this->projectPermission->adminAllowed($project['id'], $this->acl->getUserId())): ?> + <?php if ($this->projectPermission->isManager($project['id'], $this->userSession->getId())): ?> <?= $this->a('<i class="fa fa-cog"></i>', 'project', 'show', array('project_id' => $project['id']), false, 'dashboard-table-link', t('Settings')) ?> <?php endif ?> <?= $this->a($this->e($project['name']), 'board', 'show', array('project_id' => $project['id'])) ?> diff --git a/app/Template/board/assignee.php b/app/Template/board/assignee.php index 1faf07f8..cd03a67e 100644 --- a/app/Template/board/assignee.php +++ b/app/Template/board/assignee.php @@ -1,7 +1,7 @@ <section id="main"> <section> <h3><?= t('Change assignee for the task "%s"', $values['title']) ?></h3> - <form method="post" action="<?= $this->u('board', 'updateAssignee', array('task_id' => $values['id'])) ?>"> + <form method="post" action="<?= $this->u('board', 'updateAssignee', array('task_id' => $values['id'], 'project_id' => $values['project_id'])) ?>"> <?= $this->formCsrf() ?> diff --git a/app/Template/board/category.php b/app/Template/board/category.php index 3fc77632..24842146 100644 --- a/app/Template/board/category.php +++ b/app/Template/board/category.php @@ -1,7 +1,7 @@ <section id="main"> <section> <h3><?= t('Change category for the task "%s"', $values['title']) ?></h3> - <form method="post" action="<?= $this->u('board', 'updateCategory', array('task_id' => $values['id'])) ?>"> + <form method="post" action="<?= $this->u('board', 'updateCategory', array('task_id' => $values['id'], 'project_id' => $values['project_id'])) ?>"> <?= $this->formCsrf() ?> diff --git a/app/Template/board/filters.php b/app/Template/board/filters.php index 1bce0029..e99fe234 100644 --- a/app/Template/board/filters.php +++ b/app/Template/board/filters.php @@ -27,7 +27,7 @@ <i class="fa fa-line-chart fa-fw"></i> <?= $this->a(t('Analytics'), 'analytic', 'tasks', array('project_id' => $project['id'])) ?> </li> - <?php if ($this->projectPermission->adminAllowed($project['id'], $this->acl->getUserId())): ?> + <?php if ($this->acl->isManagerActionAllowed($project['id'])): ?> <li><i class="fa fa-cog fa-fw"></i> <?= $this->a(t('Configure'), 'project', 'show', array('project_id' => $project['id'])) ?> <?php endif ?> diff --git a/app/Template/board/subtasks.php b/app/Template/board/subtasks.php index 72e2b15c..1cb05498 100644 --- a/app/Template/board/subtasks.php +++ b/app/Template/board/subtasks.php @@ -4,7 +4,7 @@ trim($this->render('subtask/icons', array('subtask' => $subtask))) . $this->e($subtask['title']), 'board', 'toggleSubtask', - array('task_id' => $subtask['task_id'], 'subtask_id' => $subtask['id']) + array('task_id' => $subtask['task_id'], 'project_id' => $task['project_id'], 'subtask_id' => $subtask['id']) ) ?> <?= $this->e(empty($subtask['username']) ? '' : ' ['.$this->getFullname($subtask).']') ?> diff --git a/app/Template/board/task.php b/app/Template/board/task.php index dca9a13a..78fabf70 100644 --- a/app/Template/board/task.php +++ b/app/Template/board/task.php @@ -1,5 +1,3 @@ - - <?php if ($not_editable): ?> <div class="task-board task-<?= $task['color_id'] ?> <?= $task['date_modification'] > time() - $board_highlight_period ? 'task-board-recent' : '' ?>"> @@ -37,10 +35,10 @@ data-owner-id="<?= $task['owner_id'] ?>" data-category-id="<?= $task['category_id'] ?>" data-due-date="<?= $task['date_due'] ?>" - data-task-url="<?= $this->u('task', 'show', array('task_id' => $task['id'])) ?>" + data-task-url="<?= $this->u('task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>" title="<?= t('View this task') ?>"> - <?= $this->a('#'.$task['id'], 'task', 'edit', array('task_id' => $task['id']), false, 'task-edit-popover', t('Edit this task')) ?> + <?= $this->a('#'.$task['id'], 'task', 'edit', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'task-edit-popover', t('Edit this task')) ?> <?php if ($task['reference']): ?> <span class="task-board-reference" title="<?= t('Reference') ?>"> @@ -48,12 +46,12 @@ </span> <?php endif ?> - <span class="task-board-user <?= $this->acl->isCurrentUser($task['owner_id']) ? 'task-board-current-user' : '' ?>"> + <span class="task-board-user <?= $this->userSession->isCurrentUser($task['owner_id']) ? 'task-board-current-user' : '' ?>"> <?= $this->a( (! empty($task['owner_id']) ? t('Assigned to %s', $task['assignee_name'] ?: $task['assignee_username']) : t('Nobody assigned')), 'board', 'changeAssignee', - array('task_id' => $task['id']), + array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'assignee-popover', t('Change assignee') @@ -78,7 +76,7 @@ $this->inList($task['category_id'], $categories), 'board', 'changeCategory', - array('task_id' => $task['id']), + array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'category-popover', t('Change category') @@ -100,19 +98,19 @@ <div class="task-board-icons"> <?php if (! empty($task['nb_subtasks'])): ?> - <span title="<?= t('Sub-Tasks') ?>" class="task-board-tooltip" data-href="<?= $this->u('board', 'subtasks', array('task_id' => $task['id'])) ?>"><?= $task['nb_completed_subtasks'].'/'.$task['nb_subtasks'] ?> <i class="fa fa-bars"></i></span> + <span title="<?= t('Sub-Tasks') ?>" class="task-board-tooltip" data-href="<?= $this->u('board', 'subtasks', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>"><?= $task['nb_completed_subtasks'].'/'.$task['nb_subtasks'] ?> <i class="fa fa-bars"></i></span> <?php endif ?> <?php if (! empty($task['nb_files'])): ?> - <span title="<?= t('Attachments') ?>" class="task-board-tooltip" data-href="<?= $this->u('board', 'attachments', array('task_id' => $task['id'])) ?>"><?= $task['nb_files'] ?> <i class="fa fa-paperclip"></i></span> + <span title="<?= t('Attachments') ?>" class="task-board-tooltip" data-href="<?= $this->u('board', 'attachments', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>"><?= $task['nb_files'] ?> <i class="fa fa-paperclip"></i></span> <?php endif ?> <?php if (! empty($task['nb_comments'])): ?> - <span title="<?= p($task['nb_comments'], t('%d comment', $task['nb_comments']), t('%d comments', $task['nb_comments'])) ?>" class="task-board-tooltip" data-href="<?= $this->u('board', 'comments', array('task_id' => $task['id'])) ?>"><?= $task['nb_comments'] ?> <i class="fa fa-comment-o"></i></span> + <span title="<?= p($task['nb_comments'], t('%d comment', $task['nb_comments']), t('%d comments', $task['nb_comments'])) ?>" class="task-board-tooltip" data-href="<?= $this->u('board', 'comments', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>"><?= $task['nb_comments'] ?> <i class="fa fa-comment-o"></i></span> <?php endif ?> <?php if (! empty($task['description'])): ?> - <span title="<?= t('Description') ?>" class="task-board-tooltip" data-href="<?= $this->u('board', 'description', array('task_id' => $task['id'])) ?>"> + <span title="<?= t('Description') ?>" class="task-board-tooltip" data-href="<?= $this->u('board', 'description', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>"> <?php if (! isset($not_editable)): ?> <a class="task-description-popover" href="?controller=task&action=description&task_id=<?= $task['id'] ?>"><i class="fa fa-file-text-o" data-href="?controller=task&action=description&task_id=<?= $task['id'] ?>"></i></a> <?php else: ?> diff --git a/app/Template/comment/create.php b/app/Template/comment/create.php index 4110711e..1bdbac49 100644 --- a/app/Template/comment/create.php +++ b/app/Template/comment/create.php @@ -2,7 +2,7 @@ <h2><?= t('Add a comment') ?></h2> </div> -<form method="post" action="<?= $this->u('comment', 'save', array('task_id' => $task['id'])) ?>" autocomplete="off"> +<form method="post" action="<?= $this->u('comment', 'save', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>" autocomplete="off"> <?= $this->formCsrf() ?> <?= $this->formHidden('task_id', $values) ?> <?= $this->formHidden('user_id', $values) ?> @@ -30,7 +30,7 @@ <input type="submit" value="<?= t('Save') ?>" class="btn btn-blue"/> <?php if (! isset($skip_cancel)): ?> <?= t('or') ?> - <?= $this->a(t('cancel'), 'task', 'show', array('task_id' => $task['id'])) ?> + <?= $this->a(t('cancel'), 'task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?> <?php endif ?> </div> </form> diff --git a/app/Template/comment/edit.php b/app/Template/comment/edit.php index 51c3ced8..b4126a3e 100644 --- a/app/Template/comment/edit.php +++ b/app/Template/comment/edit.php @@ -2,7 +2,7 @@ <h2><?= t('Edit a comment') ?></h2> </div> -<form method="post" action="<?= $this->u('comment', 'update', array('task_id' => $task['id'], 'comment_id' => $comment['id'])) ?>" autocomplete="off"> +<form method="post" action="<?= $this->u('comment', 'update', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'comment_id' => $comment['id'])) ?>" autocomplete="off"> <?= $this->formCsrf() ?> <?= $this->formHidden('id', $values) ?> @@ -30,6 +30,6 @@ <div class="form-actions"> <input type="submit" value="<?= t('Update') ?>" class="btn btn-blue"/> <?= t('or') ?> - <?= $this->a(t('cancel'), 'task', 'show', array('task_id' => $task['id'])) ?> + <?= $this->a(t('cancel'), 'task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?> </div> </form> diff --git a/app/Template/comment/remove.php b/app/Template/comment/remove.php index 374d2c37..2338a03d 100644 --- a/app/Template/comment/remove.php +++ b/app/Template/comment/remove.php @@ -10,8 +10,8 @@ <?= $this->render('comment/show', array('comment' => $comment, 'task' => $task, 'preview' => true)) ?> <div class="form-actions"> - <?= $this->a(t('Yes'), 'comment', 'remove', array('task_id' => $task['id'], 'comment_id' => $comment['id']), true, 'btn btn-red') ?> + <?= $this->a(t('Yes'), 'comment', 'remove', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'comment_id' => $comment['id']), true, 'btn btn-red') ?> <?= t('or') ?> - <?= $this->a(t('cancel'), 'task', 'show', array('task_id' => $task['id'])) ?> + <?= $this->a(t('cancel'), 'task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?> </div> </div>
\ No newline at end of file diff --git a/app/Template/comment/show.php b/app/Template/comment/show.php index 2631975a..2cf9708b 100644 --- a/app/Template/comment/show.php +++ b/app/Template/comment/show.php @@ -9,12 +9,12 @@ <?php if (! isset($preview)): ?> <ul class="comment-actions"> <li><a href="#comment-<?= $comment['id'] ?>"><?= t('link') ?></a></li> - <?php if ((! isset($not_editable) || ! $not_editable) && ($this->acl->isAdminUser() || $this->acl->isCurrentUser($comment['user_id']))): ?> + <?php if ((! isset($not_editable) || ! $not_editable) && ($this->userSession->isAdmin() || $this->userSession->isCurrentUser($comment['user_id']))): ?> <li> - <?= $this->a(t('remove'), 'comment', 'confirm', array('task_id' => $task['id'], 'comment_id' => $comment['id'])) ?> + <?= $this->a(t('remove'), 'comment', 'confirm', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'comment_id' => $comment['id'])) ?> </li> <li> - <?= $this->a(t('edit'), 'comment', 'edit', array('task_id' => $task['id'], 'comment_id' => $comment['id'])) ?> + <?= $this->a(t('edit'), 'comment', 'edit', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'comment_id' => $comment['id'])) ?> </li> <?php endif ?> </ul> @@ -33,7 +33,16 @@ ) ) ?> <?php else: ?> - <?= $this->markdown($comment['comment']) ?> + <?= $this->markdown( + $comment['comment'], + array( + 'controller' => 'task', + 'action' => 'show', + 'params' => array( + 'project_id' => $project['id'] + ) + ) + ) ?> <?php endif ?> </div> diff --git a/app/Template/file/new.php b/app/Template/file/new.php index 861344b4..4f0c233b 100644 --- a/app/Template/file/new.php +++ b/app/Template/file/new.php @@ -2,13 +2,13 @@ <h2><?= t('Attach a document') ?></h2> </div> -<form action="<?= $this->u('file', 'save', array('task_id' => $task['id'])) ?>" method="post" enctype="multipart/form-data"> +<form action="<?= $this->u('file', 'save', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>" method="post" enctype="multipart/form-data"> <?= $this->formCsrf() ?> <input type="file" name="files[]" multiple /> <div class="form-help"><?= t('Maximum size: ') ?><?= is_integer($max_size) ? $this->formatBytes($max_size) : $max_size ?></div> <div class="form-actions"> <input type="submit" value="<?= t('Save') ?>" class="btn btn-blue"/> <?= t('or') ?> - <?= $this->a(t('cancel'), 'task', 'show', array('task_id' => $task['id'])) ?> + <?= $this->a(t('cancel'), 'task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?> </div> </form>
\ No newline at end of file diff --git a/app/Template/file/open.php b/app/Template/file/open.php index 9efd7780..70e0f8aa 100644 --- a/app/Template/file/open.php +++ b/app/Template/file/open.php @@ -1,6 +1,6 @@ <div class="page-header"> <h2><?= $this->e($file['name']) ?></h2> <div class="task-file-viewer"> - <img src="<?= $this->u('file', 'image', array('file_id' => $file['id'], 'task_id' => $file['task_id'])) ?>" alt="<?= $this->e($file['name']) ?>"/> + <img src="<?= $this->u('file', 'image', array('file_id' => $file['id'], 'project_id' => $task['project_id'], 'task_id' => $file['task_id'])) ?>" alt="<?= $this->e($file['name']) ?>"/> </div> </div>
\ No newline at end of file diff --git a/app/Template/file/remove.php b/app/Template/file/remove.php index 3e542c05..04ec30d5 100644 --- a/app/Template/file/remove.php +++ b/app/Template/file/remove.php @@ -8,8 +8,8 @@ </p> <div class="form-actions"> - <?= $this->a(t('Yes'), 'file', 'remove', array('task_id' => $task['id'], 'file_id' => $file['id']), true, 'btn btn-red') ?> + <?= $this->a(t('Yes'), 'file', 'remove', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'file_id' => $file['id']), true, 'btn btn-red') ?> <?= t('or') ?> - <?= $this->a(t('cancel'), 'task', 'show', array('task_id' => $task['id'])) ?> + <?= $this->a(t('cancel'), 'task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?> </div> </div>
\ No newline at end of file diff --git a/app/Template/file/show.php b/app/Template/file/show.php index 4742db87..179f5744 100644 --- a/app/Template/file/show.php +++ b/app/Template/file/show.php @@ -8,12 +8,12 @@ <ul class="task-show-files"> <?php foreach ($files as $file): ?> <li> - <?= $this->a($this->e($file['name']), 'file', 'download', array('task_id' => $task['id'], 'file_id' => $file['id'])) ?> + <?= $this->a($this->e($file['name']), 'file', 'download', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'file_id' => $file['id'])) ?> <span class="task-show-file-actions"> <?php if ($file['is_image']): ?> - <?= $this->a(t('open'), 'file', 'open', array('task_id' => $task['id'], 'file_id' => $file['id']), false, 'file-popover') ?>, + <?= $this->a(t('open'), 'file', 'open', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'file_id' => $file['id']), false, 'file-popover') ?>, <?php endif ?> - <?= $this->a(t('remove'), 'file', 'confirm', array('task_id' => $task['id'], 'file_id' => $file['id'])) ?> + <?= $this->a(t('remove'), 'file', 'confirm', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'file_id' => $file['id'])) ?> </span> </li> <?php endforeach ?> diff --git a/app/Template/layout.php b/app/Template/layout.php index 3b642b48..9aa34905 100644 --- a/app/Template/layout.php +++ b/app/Template/layout.php @@ -44,7 +44,7 @@ <?php endif ?> <li> <?= $this->a(t('Logout'), 'user', 'logout', array(), true) ?> - <span class="username hide-tablet">(<?= $this->a($this->e($this->getFullname()), 'user', 'show', array('user_id' => $this->acl->getUserId())) ?>)</span> + <span class="username hide-tablet">(<?= $this->a($this->e($this->getFullname()), 'user', 'show', array('user_id' => $this->userSession->getId())) ?>)</span> </li> </ul> </nav> diff --git a/app/Template/project/index.php b/app/Template/project/index.php index 4f07a83a..58c520d1 100644 --- a/app/Template/project/index.php +++ b/app/Template/project/index.php @@ -1,7 +1,7 @@ <section id="main"> <div class="page-header"> <ul> - <?php if ($this->acl->isAdminUser()): ?> + <?php if ($this->userSession->isAdmin()): ?> <li><i class="fa fa-plus fa-fw"></i><?= $this->a(t('New project'), 'project', 'create') ?></li> <?php endif ?> <li><i class="fa fa-lock fa-fw"></i><?= $this->a(t('New private project'), 'project', 'create', array('private' => 1)) ?></li> diff --git a/app/Template/project/layout.php b/app/Template/project/layout.php index 0db9f3e8..ce154c19 100644 --- a/app/Template/project/layout.php +++ b/app/Template/project/layout.php @@ -7,7 +7,7 @@ </div> <section class="sidebar-container" id="project-section"> - <?= $this->render('project/sidebar', array('project' => $project, 'is_owner' => $is_owner)) ?> + <?= $this->render('project/sidebar', array('project' => $project)) ?> <div class="sidebar-content"> <?= $project_content_for_layout ?> diff --git a/app/Template/project/sidebar.php b/app/Template/project/sidebar.php index 52a971d6..f5d0e352 100644 --- a/app/Template/project/sidebar.php +++ b/app/Template/project/sidebar.php @@ -5,7 +5,7 @@ <?= $this->a(t('Summary'), 'project', 'show', array('project_id' => $project['id'])) ?> </li> - <?php if ($this->acl->isAdminUser() || $project['is_private']): ?> + <?php if ($this->acl->isManagerActionAllowed($project['id'])): ?> <li> <?= $this->a(t('Public access'), 'project', 'share', array('project_id' => $project['id'])) ?> </li> @@ -15,27 +15,23 @@ <li> <?= $this->a(t('Edit project'), 'project', 'edit', array('project_id' => $project['id'])) ?> </li> + <li> + <?= $this->a(t('Edit board'), 'board', 'edit', array('project_id' => $project['id'])) ?> + </li> + <li> + <?= $this->a(t('Category management'), 'category', 'index', array('project_id' => $project['id'])) ?> + </li> + <li> + <?= $this->a(t('Swimlanes'), 'swimlane', 'index', array('project_id' => $project['id'])) ?> + </li> + <?php if ($project['is_private'] == 0): ?> + <li> + <?= $this->a(t('User management'), 'project', 'users', array('project_id' => $project['id'])) ?> + </li> <?php endif ?> - <?php if ($this->acl->isAdminUser() || $is_owner || $project['is_private']): ?> - <li> - <?= $this->a(t('Edit board'), 'board', 'edit', array('project_id' => $project['id'])) ?> - </li> - <li> - <?= $this->a(t('Category management'), 'category', 'index', array('project_id' => $project['id'])) ?> - </li> - <li> - <?= $this->a(t('Swimlanes'), 'swimlane', 'index', array('project_id' => $project['id'])) ?> - </li> - <?php if ($project['is_private'] == 0): ?> - <li> - <?= $this->a(t('User management'), 'project', 'users', array('project_id' => $project['id'])) ?> - </li> - <?php endif ?> - <li> - <?= $this->a(t('Automatic actions'), 'action', 'index', array('project_id' => $project['id'])) ?> - </li> - <?php endif ?> - <?php if ($this->acl->isAdminUser() || $project['is_private']): ?> + <li> + <?= $this->a(t('Automatic actions'), 'action', 'index', array('project_id' => $project['id'])) ?> + </li> <li> <?= $this->a(t('Duplicate'), 'project', 'duplicate', array('project_id' => $project['id']), true) ?> </li> @@ -46,13 +42,15 @@ <?= $this->a(t('Enable'), 'project', 'enable', array('project_id' => $project['id']), true) ?> <?php endif ?> </li> - <li> - <?= $this->a(t('Remove'), 'project', 'remove', array('project_id' => $project['id'])) ?> - </li> + <?php if ($this->userSession->isAdmin()): ?> + <li> + <?= $this->a(t('Remove'), 'project', 'remove', array('project_id' => $project['id'])) ?> + </li> + <?php endif ?> <?php endif ?> </ul> - <?php if ($this->acl->isAdminUser() || $project['is_private']): ?> + <?php if ($this->acl->isManagerActionAllowed($project['id'])): ?> <h2><?= t('Exports') ?></h2> <ul> <li> diff --git a/app/Template/project/users.php b/app/Template/project/users.php index da5da392..5dc4a7e5 100644 --- a/app/Template/project/users.php +++ b/app/Template/project/users.php @@ -18,15 +18,15 @@ <?php foreach ($users['allowed'] as $user_id => $username): ?> <tr> <td><?= $this->e($username) ?></td> - <td><?= isset($users['owners'][$user_id]) ? t('Project manager') : t('Project member') ?></td> + <td><?= isset($users['managers'][$user_id]) ? t('Project manager') : t('Project member') ?></td> <td> <ul> <li><?= $this->a(t('Revoke'), 'project', 'revoke', array('project_id' => $project['id'], 'user_id' => $user_id), true) ?></li> <li> - <?php if (isset($users['owners'][$user_id])): ?> - <?= $this->a(t('Set project member'), 'project', 'setOwner', array('project_id' => $project['id'], 'user_id' => $user_id, 'is_owner' => 0), true) ?> + <?php if (isset($users['managers'][$user_id])): ?> + <?= $this->a(t('Set project member'), 'project', 'role', array('project_id' => $project['id'], 'user_id' => $user_id, 'is_owner' => 0), true) ?> <?php else: ?> - <?= $this->a(t('Set project manager'), 'project', 'setOwner', array('project_id' => $project['id'], 'user_id' => $user_id, 'is_owner' => 1), true) ?> + <?= $this->a(t('Set project manager'), 'project', 'role', array('project_id' => $project['id'], 'user_id' => $user_id, 'is_owner' => 1), true) ?> <?php endif ?> </li> </ul> diff --git a/app/Template/subtask/create.php b/app/Template/subtask/create.php index ba550aea..73a08af1 100644 --- a/app/Template/subtask/create.php +++ b/app/Template/subtask/create.php @@ -2,7 +2,7 @@ <h2><?= t('Add a sub-task') ?></h2> </div> -<form method="post" action="<?= $this->u('subtask', 'save', array('task_id' => $task['id'])) ?>" autocomplete="off"> +<form method="post" action="<?= $this->u('subtask', 'save', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>" autocomplete="off"> <?= $this->formCsrf() ?> @@ -22,6 +22,6 @@ <div class="form-actions"> <input type="submit" value="<?= t('Save') ?>" class="btn btn-blue"/> <?= t('or') ?> - <?= $this->a(t('cancel'), 'task', 'show', array('task_id' => $task['id'])) ?> + <?= $this->a(t('cancel'), 'task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?> </div> </form> diff --git a/app/Template/subtask/edit.php b/app/Template/subtask/edit.php index 76a04e45..4920eb32 100644 --- a/app/Template/subtask/edit.php +++ b/app/Template/subtask/edit.php @@ -2,7 +2,7 @@ <h2><?= t('Edit a sub-task') ?></h2> </div> -<form method="post" action="<?= $this->u('subtask', 'update', array('task_id' => $task['id'], 'subtask_id' => $subtask['id'])) ?>" autocomplete="off"> +<form method="post" action="<?= $this->u('subtask', 'update', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'subtask_id' => $subtask['id'])) ?>" autocomplete="off"> <?= $this->formCsrf() ?> @@ -27,6 +27,6 @@ <div class="form-actions"> <input type="submit" value="<?= t('Save') ?>" class="btn btn-blue"/> <?= t('or') ?> - <?= $this->a(t('cancel'), 'task', 'show', array('task_id' => $task['id'])) ?> + <?= $this->a(t('cancel'), 'task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?> </div> </form> diff --git a/app/Template/subtask/remove.php b/app/Template/subtask/remove.php index 3d57ec9d..af193c59 100644 --- a/app/Template/subtask/remove.php +++ b/app/Template/subtask/remove.php @@ -12,6 +12,6 @@ <div class="form-actions"> <?= $this->a(t('Yes'), 'subtask', 'remove', array('task_id' => $task['id'], 'subtask_id' => $subtask['id']), true, 'btn btn-red') ?> <?= t('or') ?> - <?= $this->a(t('cancel'), 'task', 'show', array('task_id' => $task['id'])) ?> + <?= $this->a(t('cancel'), 'task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?> </div> </div>
\ No newline at end of file diff --git a/app/Template/subtask/show.php b/app/Template/subtask/show.php index b453762c..c0f61f0e 100644 --- a/app/Template/subtask/show.php +++ b/app/Template/subtask/show.php @@ -21,7 +21,7 @@ <td> <?php if (! isset($not_editable)): ?> <?= $this->a(trim($this->render('subtask/icons', array('subtask' => $subtask))) . $this->e($subtask['status_name']), - 'subtask', 'toggleStatus', array('task_id' => $task['id'], 'subtask_id' => $subtask['id'])) ?> + 'subtask', 'toggleStatus', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'subtask_id' => $subtask['id'])) ?> <?php else: ?> <?= $this->render('subtask/icons', array('subtask' => $subtask)) . $this->e($subtask['status_name']) ?> <?php endif ?> @@ -57,7 +57,7 @@ </table> <?php if (! isset($not_editable)): ?> - <form method="post" action="<?= $this->u('subtask', 'save', array('task_id' => $task['id'])) ?>" autocomplete="off"> + <form method="post" action="<?= $this->u('subtask', 'save', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>" autocomplete="off"> <?= $this->formCsrf() ?> <?= $this->formHidden('task_id', array('task_id' => $task['id'])) ?> <?= $this->formText('title', array(), array(), array('required', 'placeholder="'.t('Type here to create a new sub-task').'"')) ?> diff --git a/app/Template/task/close.php b/app/Template/task/close.php index 76852862..316d58eb 100644 --- a/app/Template/task/close.php +++ b/app/Template/task/close.php @@ -8,8 +8,8 @@ </p> <div class="form-actions"> - <?= $this->a(t('Yes'), 'task', 'close', array('task_id' => $task['id'], 'confirmation' => 'yes'), true, 'btn btn-red') ?> + <?= $this->a(t('Yes'), 'task', 'close', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'confirmation' => 'yes'), true, 'btn btn-red') ?> <?= t('or') ?> - <?= $this->a(t('cancel'), 'task', 'show', array('task_id' => $task['id'])) ?> + <?= $this->a(t('cancel'), 'task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?> </div> </div>
\ No newline at end of file diff --git a/app/Template/task/comments.php b/app/Template/task/comments.php index 6f380567..f81e0dc9 100644 --- a/app/Template/task/comments.php +++ b/app/Template/task/comments.php @@ -18,7 +18,7 @@ <?= $this->render('comment/create', array( 'skip_cancel' => true, 'values' => array( - 'user_id' => $this->acl->getUserId(), + 'user_id' => $this->userSession->getId(), 'task_id' => $task['id'], ), 'errors' => array(), diff --git a/app/Template/task/duplicate.php b/app/Template/task/duplicate.php index c1aed6be..cc7e0870 100644 --- a/app/Template/task/duplicate.php +++ b/app/Template/task/duplicate.php @@ -8,8 +8,8 @@ </p> <div class="form-actions"> - <?= $this->a(t('Yes'), 'task', 'duplicate', array('task_id' => $task['id'], 'confirmation' => 'yes'), true, 'btn btn-red') ?> + <?= $this->a(t('Yes'), 'task', 'duplicate', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'confirmation' => 'yes'), true, 'btn btn-red') ?> <?= t('or') ?> - <?= $this->a(t('cancel'), 'task', 'show', array('task_id' => $task['id'])) ?> + <?= $this->a(t('cancel'), 'task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?> </div> </div>
\ No newline at end of file diff --git a/app/Template/task/duplicate_project.php b/app/Template/task/duplicate_project.php index d69da9d5..e227e046 100644 --- a/app/Template/task/duplicate_project.php +++ b/app/Template/task/duplicate_project.php @@ -17,7 +17,7 @@ <div class="form-actions"> <input type="submit" value="<?= t('Save') ?>" class="btn btn-blue"/> <?= t('or') ?> - <?= $this->a(t('cancel'), 'task', 'show', array('task_id' => $task['id'])) ?> + <?= $this->a(t('cancel'), 'task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?> </div> </form> diff --git a/app/Template/task/edit.php b/app/Template/task/edit.php index ef1a9dfa..51cb2884 100644 --- a/app/Template/task/edit.php +++ b/app/Template/task/edit.php @@ -2,7 +2,7 @@ <h2><?= t('Edit a task') ?></h2> </div> <section id="task-section"> -<form method="post" action="<?= $this->u('task', 'update', array('task_id' => $task['id'], 'ajax' => $ajax)) ?>" autocomplete="off"> +<form method="post" action="<?= $this->u('task', 'update', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'ajax' => $ajax)) ?>" autocomplete="off"> <?= $this->formCsrf() ?> @@ -61,7 +61,7 @@ <?php if ($ajax): ?> <?= $this->a(t('cancel'), 'board', 'show', array('project_id' => $task['project_id'])) ?> <?php else: ?> - <?= $this->a(t('cancel'), 'task', 'show', array('task_id' => $task['id'])) ?> + <?= $this->a(t('cancel'), 'task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?> <?php endif ?> </div> </form> diff --git a/app/Template/task/edit_description.php b/app/Template/task/edit_description.php index d53aff93..2af26ef4 100644 --- a/app/Template/task/edit_description.php +++ b/app/Template/task/edit_description.php @@ -2,7 +2,7 @@ <h2><?= t('Edit the description') ?></h2> </div> -<form method="post" action="<?= $this->u('task', 'description', array('task_id' => $task['id'], 'ajax' => $ajax)) ?>" autocomplete="off"> +<form method="post" action="<?= $this->u('task', 'description', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'ajax' => $ajax)) ?>" autocomplete="off"> <?= $this->formCsrf() ?> <?= $this->formHidden('id', $values) ?> @@ -32,7 +32,7 @@ <?php if ($ajax): ?> <?= $this->a(t('cancel'), 'board', 'show', array('project_id' => $task['project_id'])) ?> <?php else: ?> - <?= $this->a(t('cancel'), 'task', 'show', array('task_id' => $task['id'])) ?> + <?= $this->a(t('cancel'), 'task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?> <?php endif ?> </div> </form> diff --git a/app/Template/task/move_project.php b/app/Template/task/move_project.php index 15b295d7..ccc67851 100644 --- a/app/Template/task/move_project.php +++ b/app/Template/task/move_project.php @@ -17,7 +17,7 @@ <div class="form-actions"> <input type="submit" value="<?= t('Save') ?>" class="btn btn-blue"/> <?= t('or') ?> - <?= $this->a(t('cancel'), 'task', 'show', array('task_id' => $task['id'])) ?> + <?= $this->a(t('cancel'), 'task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?> </div> </form> diff --git a/app/Template/task/open.php b/app/Template/task/open.php index 438acb34..1fcdcd80 100644 --- a/app/Template/task/open.php +++ b/app/Template/task/open.php @@ -8,8 +8,8 @@ </p> <div class="form-actions"> - <?= $this->a(t('Yes'), 'task', 'open', array('task_id' => $task['id'], 'confirmation' => 'yes'), true, 'btn btn-red') ?> + <?= $this->a(t('Yes'), 'task', 'open', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'confirmation' => 'yes'), true, 'btn btn-red') ?> <?= t('or') ?> - <?= $this->a(t('cancel'), 'task', 'show', array('task_id' => $task['id'])) ?> + <?= $this->a(t('cancel'), 'task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?> </div> </div>
\ No newline at end of file diff --git a/app/Template/task/remove.php b/app/Template/task/remove.php index 59845c6a..c1eea5a0 100644 --- a/app/Template/task/remove.php +++ b/app/Template/task/remove.php @@ -8,8 +8,8 @@ </p> <div class="form-actions"> - <?= $this->a(t('Yes'), 'task', 'remove', array('task_id' => $task['id'], 'confirmation' => 'yes'), true, 'btn btn-red') ?> + <?= $this->a(t('Yes'), 'task', 'remove', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'confirmation' => 'yes'), true, 'btn btn-red') ?> <?= t('or') ?> - <?= $this->a(t('cancel'), 'task', 'show', array('task_id' => $task['id'])) ?> + <?= $this->a(t('cancel'), 'task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?> </div> </div>
\ No newline at end of file diff --git a/app/Template/task/show.php b/app/Template/task/show.php index b98af52d..3bc6796f 100644 --- a/app/Template/task/show.php +++ b/app/Template/task/show.php @@ -1,5 +1,5 @@ <?= $this->render('task/details', array('task' => $task, 'project' => $project)) ?> -<?= $this->render('task/time', array('values' => $values, 'date_format' => $date_format, 'date_formats' => $date_formats)) ?> +<?= $this->render('task/time', array('task' => $task, 'values' => $values, 'date_format' => $date_format, 'date_formats' => $date_formats)) ?> <?= $this->render('task/show_description', array('task' => $task)) ?> <?= $this->render('subtask/show', array('task' => $task, 'subtasks' => $subtasks)) ?> <?= $this->render('task/timesheet', array('timesheet' => $timesheet)) ?> diff --git a/app/Template/task/show_description.php b/app/Template/task/show_description.php index 9cd278e3..3807ddd2 100644 --- a/app/Template/task/show_description.php +++ b/app/Template/task/show_description.php @@ -6,7 +6,16 @@ <article class="markdown task-show-description"> <?php if (! isset($is_public)): ?> - <?= $this->markdown($task['description']) ?> + <?= $this->markdown( + $task['description'], + array( + 'controller' => 'task', + 'action' => 'show', + 'params' => array( + 'project_id' => $task['project_id'] + ) + ) + ) ?> <?php else: ?> <?= $this->markdown( $task['description'], diff --git a/app/Template/task/sidebar.php b/app/Template/task/sidebar.php index 1779255a..4ee7ca8a 100644 --- a/app/Template/task/sidebar.php +++ b/app/Template/task/sidebar.php @@ -2,22 +2,22 @@ <h2><?= t('Actions') ?></h2> <ul> <li> - <?= $this->a(t('Summary'), 'task', 'show', array('task_id' => $task['id'])) ?> + <?= $this->a(t('Summary'), 'task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?> </li> <li> - <?= $this->a(t('Edit the task'), 'task', 'edit', array('task_id' => $task['id'])) ?> + <?= $this->a(t('Edit the task'), 'task', 'edit', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?> </li> <li> - <?= $this->a(t('Edit the description'), 'task', 'description', array('task_id' => $task['id'])) ?> + <?= $this->a(t('Edit the description'), 'task', 'description', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?> </li> <li> - <?= $this->a(t('Add a sub-task'), 'subtask', 'create', array('task_id' => $task['id'])) ?> + <?= $this->a(t('Add a sub-task'), 'subtask', 'create', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?> </li> <li> - <?= $this->a(t('Add a comment'), 'comment', 'create', array('task_id' => $task['id'])) ?> + <?= $this->a(t('Add a comment'), 'comment', 'create', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?> </li> <li> - <?= $this->a(t('Attach a document'), 'file', 'create', array('task_id' => $task['id'])) ?> + <?= $this->a(t('Attach a document'), 'file', 'create', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?> </li> <li> <?= $this->a(t('Duplicate'), 'task', 'duplicate', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?> @@ -30,14 +30,14 @@ </li> <li> <?php if ($task['is_active'] == 1): ?> - <?= $this->a(t('Close this task'), 'task', 'close', array('task_id' => $task['id'])) ?> + <?= $this->a(t('Close this task'), 'task', 'close', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?> <?php else: ?> - <?= $this->a(t('Open this task'), 'task', 'open', array('task_id' => $task['id'])) ?> + <?= $this->a(t('Open this task'), 'task', 'open', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?> <?php endif ?> </li> <?php if (! $hide_remove_menu): ?> <li> - <?= $this->a(t('Remove'), 'task', 'remove', array('task_id' => $task['id'])) ?> + <?= $this->a(t('Remove'), 'task', 'remove', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?> </li> <?php endif ?> </ul> diff --git a/app/Template/task/table.php b/app/Template/task/table.php index dfde4561..689cdcc4 100644 --- a/app/Template/task/table.php +++ b/app/Template/task/table.php @@ -13,7 +13,7 @@ <?php foreach ($tasks as $task): ?> <tr> <td class="task-table task-<?= $task['color_id'] ?>"> - <?= $this->a('#'.$this->e($task['id']), 'task', 'show', array('task_id' => $task['id']), false, '', t('View this task')) ?> + <?= $this->a('#'.$this->e($task['id']), 'task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, '', t('View this task')) ?> </td> <td> <?= $this->inList($task['column_id'], $columns) ?> @@ -22,7 +22,7 @@ <?= $this->inList($task['category_id'], $categories, '') ?> </td> <td> - <?= $this->a($this->e($task['title']), 'task', 'show', array('task_id' => $task['id']), false, '', t('View this task')) ?> + <?= $this->a($this->e($task['title']), 'task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, '', t('View this task')) ?> </td> <td> <?php if ($task['assignee_username']): ?> diff --git a/app/Template/task/time.php b/app/Template/task/time.php index b00cbc14..4aeddc70 100644 --- a/app/Template/task/time.php +++ b/app/Template/task/time.php @@ -1,4 +1,4 @@ -<form method="post" action="<?= $this->u('task', 'time', array('task_id' => $values['id'])) ?>" class="form-inline task-time-form" autocomplete="off"> +<form method="post" action="<?= $this->u('task', 'time', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>" class="form-inline task-time-form" autocomplete="off"> <?= $this->formCsrf() ?> <?= $this->formHidden('id', $values) ?> diff --git a/app/Template/user/edit.php b/app/Template/user/edit.php index 6766f952..68b264ec 100644 --- a/app/Template/user/edit.php +++ b/app/Template/user/edit.php @@ -20,7 +20,7 @@ <?= $this->formLabel(t('Default project'), 'default_project_id') ?> <?= $this->formSelect('default_project_id', $projects, $values, $errors) ?><br/> - <?php if ($this->acl->isAdminUser()): ?> + <?php if ($this->userSession->isAdmin()): ?> <?= $this->formCheckbox('is_admin', t('Administrator'), 1, isset($values['is_admin']) && $values['is_admin'] == 1 ? true : false) ?><br/> <?php endif ?> diff --git a/app/Template/user/external.php b/app/Template/user/external.php index 6ee1e459..b4cea156 100644 --- a/app/Template/user/external.php +++ b/app/Template/user/external.php @@ -6,7 +6,7 @@ <h3><i class="fa fa-google"></i> <?= t('Google Account') ?></h3> <p class="listing"> - <?php if ($this->acl->isCurrentUser($user['id'])): ?> + <?php if ($this->userSession->isCurrentUser($user['id'])): ?> <?php if (empty($user['google_id'])): ?> <?= $this->a(t('Link my Google Account'), 'user', 'google', array(), true) ?> <?php else: ?> @@ -22,7 +22,7 @@ <h3><i class="fa fa-github"></i> <?= t('Github Account') ?></h3> <p class="listing"> - <?php if ($this->acl->isCurrentUser($user['id'])): ?> + <?php if ($this->userSession->isCurrentUser($user['id'])): ?> <?php if (empty($user['github_id'])): ?> <?= $this->a(t('Link my GitHub Account'), 'user', 'github', array(), true) ?> <?php else: ?> diff --git a/app/Template/user/index.php b/app/Template/user/index.php index a6da9f65..e4729501 100644 --- a/app/Template/user/index.php +++ b/app/Template/user/index.php @@ -1,6 +1,6 @@ <section id="main"> <div class="page-header"> - <?php if ($this->acl->isAdminUser()): ?> + <?php if ($this->userSession->isAdmin()): ?> <ul> <li><i class="fa fa-plus fa-fw"></i><?= $this->a(t('New user'), 'user', 'create') ?></li> </ul> diff --git a/app/Template/user/layout.php b/app/Template/user/layout.php index 94610000..a5a78a3f 100644 --- a/app/Template/user/layout.php +++ b/app/Template/user/layout.php @@ -1,6 +1,6 @@ <section id="main"> <div class="page-header"> - <?php if ($this->acl->isAdminUser()): ?> + <?php if ($this->userSession->isAdmin()): ?> <ul> <li><i class="fa fa-user fa-fw"></i><?= $this->a(t('All users'), 'user', 'index') ?></li> <li><i class="fa fa-plus fa-fw"></i><?= $this->a(t('New user'), 'user', 'create') ?></li> diff --git a/app/Template/user/sidebar.php b/app/Template/user/sidebar.php index 5b7abc34..f74c8b01 100644 --- a/app/Template/user/sidebar.php +++ b/app/Template/user/sidebar.php @@ -5,7 +5,7 @@ <?= $this->a(t('Summary'), 'user', 'show', array('user_id' => $user['id'])) ?> </li> - <?php if ($this->acl->isAdminUser() || $this->acl->isCurrentUser($user['id'])): ?> + <?php if ($this->userSession->isAdmin() || $this->userSession->isCurrentUser($user['id'])): ?> <li> <?= $this->a(t('Edit profile'), 'user', 'edit', array('user_id' => $user['id'])) ?> </li> @@ -30,7 +30,7 @@ </li> <?php endif ?> - <?php if ($this->acl->isAdminUser() && ! $this->acl->isCurrentUser($user['id'])): ?> + <?php if ($this->userSession->isAdmin() && ! $this->userSession->isCurrentUser($user['id'])): ?> <li> <?= $this->a(t('Remove'), 'user', 'remove', array('user_id' => $user['id'])) ?> </li> diff --git a/assets/css/alert.css b/assets/css/alert.css index 14e26c91..99dc417c 100644 --- a/assets/css/alert.css +++ b/assets/css/alert.css @@ -74,6 +74,7 @@ } } +#main .alert, .page .alert { margin-top: 10px; -}
\ No newline at end of file +} diff --git a/assets/css/app.css b/assets/css/app.css index 970030e4..3e579918 100644 --- a/assets/css/app.css +++ b/assets/css/app.css @@ -523,9 +523,11 @@ a.btn-blue:focus, } } +#main .alert, .page .alert { margin-top: 10px; -}/* tooltip */ +} +/* tooltip */ .tooltip-arrow:after { background: #fff; border: 1px solid #aaaaaa; diff --git a/jsonrpc.php b/jsonrpc.php index 411e73dc..d0951e73 100644 --- a/jsonrpc.php +++ b/jsonrpc.php @@ -63,8 +63,8 @@ $server->bind('removeColumn', $container['board'], 'removeColumn'); * Project permissions procedures */ $server->bind('getMembers', $container['projectPermission'], 'getMembers'); -$server->bind('revokeUser', $container['projectPermission'], 'revokeUser'); -$server->bind('allowUser', $container['projectPermission'], 'allowUser'); +$server->bind('revokeUser', $container['projectPermission'], 'revokeMember'); +$server->bind('allowUser', $container['projectPermission'], 'addMember'); /** * Task procedures diff --git a/scripts/create-random-projects.php b/scripts/create-random-projects.php index 5cab1a25..2b68174e 100755 --- a/scripts/create-random-projects.php +++ b/scripts/create-random-projects.php @@ -14,5 +14,5 @@ for ($i = 0; $i < 100; $i++) { 'name' => 'Project #'.$i )); - $permissionModel->allowUser($id, 1); + $permissionModel->addMember($id, 1); } diff --git a/scripts/create-random-tasks.php b/scripts/create-random-tasks.php index 98548445..aa6044b8 100755 --- a/scripts/create-random-tasks.php +++ b/scripts/create-random-tasks.php @@ -21,7 +21,7 @@ $project_id = $projectModel->create(array( 'name' => 'Project #1' )); -$permissionModel->allowUser($project_id, 1); +$permissionModel->addMember($project_id, 1); for ($i = 0; $i <= 5; $i++) { $userModel->create(array( diff --git a/tests/units/AclTest.php b/tests/units/AclTest.php index 99d1a849..3c18beae 100644 --- a/tests/units/AclTest.php +++ b/tests/units/AclTest.php @@ -2,111 +2,222 @@ require_once __DIR__.'/Base.php'; +use Core\Session; use Model\Acl; +use Model\Project; +use Model\ProjectPermission; +use Model\User; class AclTest extends Base { - public function testAllowedAction() + public function testMatchAcl() { $acl_rules = array( 'controller1' => array('action1', 'action3'), + 'controller3' => '*', + 'controller5' => '-', + 'controller6' => array(), ); $acl = new Acl($this->container); - $this->assertTrue($acl->isAllowedAction($acl_rules, 'controller1', 'action1')); - $this->assertTrue($acl->isAllowedAction($acl_rules, 'controller1', 'action3')); - $this->assertFalse($acl->isAllowedAction($acl_rules, 'controller1', 'action2')); - $this->assertFalse($acl->isAllowedAction($acl_rules, 'controller2', 'action2')); - $this->assertFalse($acl->isAllowedAction($acl_rules, 'controller2', 'action3')); + $this->assertTrue($acl->matchAcl($acl_rules, 'controller1', 'aCtiOn1')); + $this->assertTrue($acl->matchAcl($acl_rules, 'controller1', 'action1')); + $this->assertTrue($acl->matchAcl($acl_rules, 'controller1', 'action3')); + $this->assertFalse($acl->matchAcl($acl_rules, 'controller1', 'action2')); + $this->assertFalse($acl->matchAcl($acl_rules, 'controller2', 'action2')); + $this->assertFalse($acl->matchAcl($acl_rules, 'controller2', 'action3')); + $this->assertTrue($acl->matchAcl($acl_rules, 'controller3', 'anything')); + $this->assertFalse($acl->matchAcl($acl_rules, 'controller4', 'anything')); + $this->assertFalse($acl->matchAcl($acl_rules, 'controller5', 'anything')); + $this->assertFalse($acl->matchAcl($acl_rules, 'controller6', 'anything')); } - public function testIsAdmin() + public function testPublicActions() { $acl = new Acl($this->container); + $this->assertTrue($acl->isPublicAction('board', 'readonly')); + $this->assertFalse($acl->isPublicAction('board', 'show')); + } + + public function testAdminActions() + { + $acl = new Acl($this->container); + $this->assertFalse($acl->isAdminAction('board', 'show')); + $this->assertFalse($acl->isAdminAction('task', 'show')); + $this->assertTrue($acl->isAdminAction('config', 'api')); + $this->assertTrue($acl->isAdminAction('config', 'anything')); + $this->assertTrue($acl->isAdminAction('config', 'anything')); + $this->assertTrue($acl->isAdminAction('user', 'save')); + } - $_SESSION = array(); - $this->assertFalse($acl->isAdminUser()); + public function testManagerActions() + { + $acl = new Acl($this->container); + $this->assertFalse($acl->isManagerAction('board', 'readonly')); + $this->assertFalse($acl->isManagerAction('project', 'remove')); + $this->assertFalse($acl->isManagerAction('project', 'show')); + $this->assertTrue($acl->isManagerAction('project', 'disable')); + $this->assertTrue($acl->isManagerAction('category', 'index')); + $this->assertTrue($acl->isManagerAction('project', 'users')); + $this->assertTrue($acl->isManagerAction('task', 'remove')); + $this->assertFalse($acl->isManagerAction('app', 'index')); + } + + public function testPageAccessNoSession() + { + $acl = new Acl($this->container); + $this->assertFalse($acl->isAllowed('board', 'readonly')); + $this->assertFalse($acl->isAllowed('task', 'show')); + $this->assertFalse($acl->isAllowed('config', 'application')); + $this->assertFalse($acl->isAllowed('project', 'users')); + $this->assertFalse($acl->isAllowed('task', 'remove')); + $this->assertTrue($acl->isAllowed('app', 'index')); + } + + public function testPageAccessEmptySession() + { + $acl = new Acl($this->container); + $session = new Session; - $_SESSION = array('user' => array()); - $this->assertFalse($acl->isAdminUser()); + $session['user'] = array(); - $_SESSION = array('user' => array('is_admin' => '1')); - $this->assertFalse($acl->isAdminUser()); + $this->assertFalse($acl->isAllowed('board', 'readonly')); + $this->assertFalse($acl->isAllowed('task', 'show')); + $this->assertFalse($acl->isAllowed('config', 'application')); + $this->assertFalse($acl->isAllowed('project', 'users')); + $this->assertFalse($acl->isAllowed('task', 'remove')); + $this->assertTrue($acl->isAllowed('app', 'index')); + } - $_SESSION = array('user' => array('is_admin' => false)); - $this->assertFalse($acl->isAdminUser()); + public function testPageAccessAdminUser() + { + $acl = new Acl($this->container); + $session = new Session; - $_SESSION = array('user' => array('is_admin' => '2')); - $this->assertFalse($acl->isAdminUser()); + $session['user'] = array( + 'is_admin' => true, + ); - $_SESSION = array('user' => array('is_admin' => true)); - $this->assertTrue($acl->isAdminUser()); + $this->assertTrue($acl->isAllowed('board', 'readonly')); + $this->assertTrue($acl->isAllowed('task', 'readonly')); + $this->assertTrue($acl->isAllowed('webhook', 'github')); + $this->assertTrue($acl->isAllowed('task', 'show')); + $this->assertTrue($acl->isAllowed('task', 'update')); + $this->assertTrue($acl->isAllowed('project', 'show')); + $this->assertTrue($acl->isAllowed('config', 'application')); + $this->assertTrue($acl->isAllowed('project', 'users')); + $this->assertTrue($acl->isAllowed('category', 'edit')); + $this->assertTrue($acl->isAllowed('task', 'remove')); + $this->assertTrue($acl->isAllowed('app', 'index')); } - public function testIsUser() + public function testPageAccessManager() { $acl = new Acl($this->container); + $p = new Project($this->container); + $pp = new ProjectPermission($this->container); + $u = new User($this->container); + $session = new Session; + + // We create our user + $this->assertEquals(2, $u->create(array('username' => 'unittest', 'password' => 'unittest'))); + + // We create a project and set our user as project manager + $this->assertEquals(1, $p->create(array('name' => 'UnitTest'), 2, true)); + $this->assertTrue($pp->isMember(1, 2)); + $this->assertTrue($pp->isManager(1, 2)); + + // We fake a session for him + $session['user'] = array( + 'id' => 2, + 'is_admin' => false, + ); - $_SESSION = array(); - $this->assertFalse($acl->isRegularUser()); + $this->assertTrue($acl->isAllowed('board', 'readonly', 1)); + $this->assertTrue($acl->isAllowed('task', 'readonly', 1)); + $this->assertTrue($acl->isAllowed('webhook', 'github', 1)); + $this->assertTrue($acl->isAllowed('task', 'show', 1)); + $this->assertFalse($acl->isAllowed('task', 'show', 2)); + $this->assertTrue($acl->isAllowed('task', 'update', 1)); + $this->assertTrue($acl->isAllowed('project', 'show', 1)); + $this->assertFalse($acl->isAllowed('config', 'application', 1)); + $this->assertTrue($acl->isAllowed('project', 'users', 1)); + $this->assertFalse($acl->isAllowed('project', 'users', 2)); + $this->assertTrue($acl->isAllowed('category', 'edit', 1)); + $this->assertTrue($acl->isAllowed('task', 'remove', 1)); + $this->assertTrue($acl->isAllowed('app', 'index', 1)); + } - $_SESSION = array('user' => array()); - $this->assertFalse($acl->isRegularUser()); + public function testPageAccessMember() + { + $acl = new Acl($this->container); + $p = new Project($this->container); + $pp = new ProjectPermission($this->container); + $u = new User($this->container); - $_SESSION = array('user' => array('is_admin' => true)); - $this->assertFalse($acl->isRegularUser()); + // We create our user + $this->assertEquals(2, $u->create(array('username' => 'unittest', 'password' => 'unittest'))); - $_SESSION = array('user' => array('is_admin' => true)); - $this->assertFalse($acl->isRegularUser()); + // We create a project and set our user as member + $this->assertEquals(1, $p->create(array('name' => 'UnitTest1'))); + $this->assertEquals(2, $p->create(array('name' => 'UnitTest2'))); + $this->assertTrue($pp->addMember(1, 2)); + $this->assertTrue($pp->isMember(1, 2)); + $this->assertFalse($pp->isManager(1, 2)); - $_SESSION = array('user' => array('is_admin' => '2')); - $this->assertFalse($acl->isRegularUser()); + $session = new Session; - $_SESSION = array('user' => array('is_admin' => false)); - $this->assertTrue($acl->isRegularUser()); + $session['user'] = array( + 'id' => 2, + 'is_admin' => false, + ); + + $this->assertTrue($acl->isAllowed('board', 'readonly', 1)); + $this->assertTrue($acl->isAllowed('task', 'readonly', 1)); + $this->assertTrue($acl->isAllowed('webhook', 'github', 1)); + $this->assertFalse($acl->isAllowed('board', 'show', 2)); + $this->assertTrue($acl->isAllowed('board', 'show', 1)); + $this->assertFalse($acl->isAllowed('task', 'show', 2)); + $this->assertTrue($acl->isAllowed('task', 'show', 1)); + $this->assertTrue($acl->isAllowed('task', 'update', 1)); + $this->assertTrue($acl->isAllowed('project', 'show', 1)); + $this->assertFalse($acl->isAllowed('config', 'application', 1)); + $this->assertFalse($acl->isAllowed('project', 'users', 1)); + $this->assertFalse($acl->isAllowed('task', 'remove', 1)); + $this->assertTrue($acl->isAllowed('app', 'index', 1)); } - public function testIsPageAllowed() + public function testPageAccessNotMember() { $acl = new Acl($this->container); + $p = new Project($this->container); + $pp = new ProjectPermission($this->container); + $u = new User($this->container); + + // We create our user + $this->assertEquals(2, $u->create(array('username' => 'unittest', 'password' => 'unittest'))); + + // We create a project and set our user as member + $this->assertEquals(1, $p->create(array('name' => 'UnitTest1'))); + $this->assertEquals(2, $p->create(array('name' => 'UnitTest2'))); + $this->assertFalse($pp->isMember(1, 2)); + $this->assertFalse($pp->isManager(1, 2)); + + $session = new Session; + + $session['user'] = array( + 'id' => 2, + 'is_admin' => false, + ); - // Public access - $_SESSION = array(); - $this->assertFalse($acl->isPageAccessAllowed('user', 'create')); - $this->assertFalse($acl->isPageAccessAllowed('user', 'save')); - $this->assertFalse($acl->isPageAccessAllowed('user', 'remove')); - $this->assertFalse($acl->isPageAccessAllowed('user', 'confirm')); - $this->assertFalse($acl->isPageAccessAllowed('app', 'index')); - $this->assertFalse($acl->isPageAccessAllowed('user', 'index')); - $this->assertTrue($acl->isPageAccessAllowed('user', 'login')); - $this->assertTrue($acl->isPageAccessAllowed('user', 'check')); - $this->assertTrue($acl->isPageAccessAllowed('webhook', 'task')); - $this->assertTrue($acl->isPageAccessAllowed('board', 'readonly')); - - // Regular user - $_SESSION = array('user' => array('is_admin' => false)); - $this->assertFalse($acl->isPageAccessAllowed('user', 'create')); - $this->assertFalse($acl->isPageAccessAllowed('user', 'save')); - $this->assertFalse($acl->isPageAccessAllowed('user', 'remove')); - $this->assertFalse($acl->isPageAccessAllowed('user', 'confirm')); - $this->assertTrue($acl->isPageAccessAllowed('app', 'index')); - $this->assertFalse($acl->isPageAccessAllowed('user', 'index')); - $this->assertTrue($acl->isPageAccessAllowed('user', 'login')); - $this->assertTrue($acl->isPageAccessAllowed('user', 'check')); - $this->assertTrue($acl->isPageAccessAllowed('webhook', 'task')); - $this->assertTrue($acl->isPageAccessAllowed('board', 'readonly')); - - // Admin user - $_SESSION = array('user' => array('is_admin' => true)); - $this->assertTrue($acl->isPageAccessAllowed('user', 'create')); - $this->assertTrue($acl->isPageAccessAllowed('user', 'save')); - $this->assertTrue($acl->isPageAccessAllowed('user', 'remove')); - $this->assertTrue($acl->isPageAccessAllowed('user', 'confirm')); - $this->assertTrue($acl->isPageAccessAllowed('app', 'index')); - $this->assertTrue($acl->isPageAccessAllowed('user', 'index')); - $this->assertTrue($acl->isPageAccessAllowed('user', 'login')); - $this->assertTrue($acl->isPageAccessAllowed('user', 'check')); - $this->assertTrue($acl->isPageAccessAllowed('task', 'add')); - $this->assertTrue($acl->isPageAccessAllowed('board', 'readonly')); + $this->assertFalse($acl->isAllowed('board', 'show', 2)); + $this->assertFalse($acl->isAllowed('board', 'show', 1)); + $this->assertFalse($acl->isAllowed('task', 'show', 1)); + $this->assertFalse($acl->isAllowed('task', 'update', 1)); + $this->assertFalse($acl->isAllowed('project', 'show', 1)); + $this->assertFalse($acl->isAllowed('config', 'application', 1)); + $this->assertFalse($acl->isAllowed('project', 'users', 1)); + $this->assertFalse($acl->isAllowed('task', 'remove', 1)); + $this->assertTrue($acl->isAllowed('app', 'index', 1)); } } diff --git a/tests/units/ActionTaskAssignCurrentUserTest.php b/tests/units/ActionTaskAssignCurrentUserTest.php index 374277ce..f32fc77c 100644 --- a/tests/units/ActionTaskAssignCurrentUserTest.php +++ b/tests/units/ActionTaskAssignCurrentUserTest.php @@ -7,7 +7,7 @@ use Model\Task; use Model\TaskCreation; use Model\TaskFinder; use Model\Project; -use Model\Acl; +use Model\UserSession; class ActionTaskAssignCurrentUser extends Base { @@ -52,9 +52,9 @@ class ActionTaskAssignCurrentUser extends Base $tc = new TaskCreation($this->container); $tf = new TaskFinder($this->container); $p = new Project($this->container); - $a = new Acl($this->container); + $us = new UserSession($this->container); - $this->assertEquals(5, $a->getUserId()); + $this->assertEquals(5, $us->getId()); $this->assertEquals(1, $p->create(array('name' => 'test'))); $this->assertEquals(1, $tc->create(array('title' => 'test', 'project_id' => 1, 'column_id' => 1))); diff --git a/tests/units/HelperTest.php b/tests/units/HelperTest.php index 72f84a24..2ae75684 100644 --- a/tests/units/HelperTest.php +++ b/tests/units/HelperTest.php @@ -13,7 +13,7 @@ class HelperTest extends Base $this->assertEquals('<p>Test</p>', $h->markdown('Test')); $this->assertEquals( - '<p>Task <a href="?controller=task&action=show&task_id=123" class="" title="" >#123</a></p>', + '<p>Task #123</p>', $h->markdown('Task #123') ); diff --git a/tests/units/NotificationTest.php b/tests/units/NotificationTest.php index d8e623e1..37285212 100644 --- a/tests/units/NotificationTest.php +++ b/tests/units/NotificationTest.php @@ -35,10 +35,10 @@ class NotificationTest extends Base $this->assertEmpty($n->getUsersWithNotification(1)); // We allow all users to be member of our projects - $this->assertTrue($pp->allowUser(1, 1)); - $this->assertTrue($pp->allowUser(1, 2)); - $this->assertTrue($pp->allowUser(1, 3)); - $this->assertTrue($pp->allowUser(1, 4)); + $this->assertTrue($pp->addMember(1, 1)); + $this->assertTrue($pp->addMember(1, 2)); + $this->assertTrue($pp->addMember(1, 3)); + $this->assertTrue($pp->addMember(1, 4)); $this->assertNotEmpty($pp->getMembers(1)); $users = $n->getUsersWithNotification(1); @@ -73,15 +73,15 @@ class NotificationTest extends Base $this->assertNotFalse($u->create(array('username' => 'user4'))); // We allow all users to be member of our projects - $this->assertTrue($pp->allowUser(1, 1)); - $this->assertTrue($pp->allowUser(1, 2)); - $this->assertTrue($pp->allowUser(1, 3)); - $this->assertTrue($pp->allowUser(1, 4)); - - $this->assertTrue($pp->allowUser(2, 1)); - $this->assertTrue($pp->allowUser(2, 2)); - $this->assertTrue($pp->allowUser(2, 3)); - $this->assertTrue($pp->allowUser(2, 4)); + $this->assertTrue($pp->addMember(1, 1)); + $this->assertTrue($pp->addMember(1, 2)); + $this->assertTrue($pp->addMember(1, 3)); + $this->assertTrue($pp->addMember(1, 4)); + + $this->assertTrue($pp->addMember(2, 1)); + $this->assertTrue($pp->addMember(2, 2)); + $this->assertTrue($pp->addMember(2, 3)); + $this->assertTrue($pp->addMember(2, 4)); $users = $n->getUsersList(1); $this->assertNotEmpty($users); diff --git a/tests/units/ProjectPermissionTest.php b/tests/units/ProjectPermissionTest.php index b169b63e..3cbd6bec 100644 --- a/tests/units/ProjectPermissionTest.php +++ b/tests/units/ProjectPermissionTest.php @@ -62,14 +62,14 @@ class ProjectPermissionTest extends Base $this->assertEquals(1, $p->create(array('name' => 'UnitTest'))); // We allow the admin user - $this->assertTrue($pp->allowUser(1, 1)); - $this->assertTrue($pp->allowUser(1, 2)); + $this->assertTrue($pp->addMember(1, 1)); + $this->assertTrue($pp->addMember(1, 2)); // Non-existant project - $this->assertFalse($pp->allowUser(50, 1)); + $this->assertFalse($pp->addMember(50, 1)); // Non-existant user - $this->assertFalse($pp->allowUser(1, 50)); + $this->assertFalse($pp->addMember(1, 50)); // Both users should be allowed $this->assertEquals(array('1' => 'admin', '2' => 'unittest'), $pp->getMembers(1)); @@ -89,7 +89,7 @@ class ProjectPermissionTest extends Base $this->assertEquals(1, $p->create(array('name' => 'UnitTest'))); // We revoke our admin user (not existing row) - $this->assertFalse($pp->revokeUser(1, 1)); + $this->assertFalse($pp->revokeMember(1, 1)); // We should have nobody in the users list $this->assertEmpty($pp->getMembers(1)); @@ -99,7 +99,7 @@ class ProjectPermissionTest extends Base $this->assertFalse($pp->isUserAllowed(1, 2)); // We allow only the regular user - $this->assertTrue($pp->allowUser(1, 2)); + $this->assertTrue($pp->addMember(1, 2)); // All users should be allowed (admin and regular) $this->assertTrue($pp->isUserAllowed(1, 1)); @@ -109,13 +109,13 @@ class ProjectPermissionTest extends Base $this->assertEquals(array('2' => 'unittest'), $pp->getMembers(1)); // We allow our admin, we should have both in the list - $this->assertTrue($pp->allowUser(1, 1)); + $this->assertTrue($pp->addMember(1, 1)); $this->assertEquals(array('1' => 'admin', '2' => 'unittest'), $pp->getMembers(1)); $this->assertTrue($pp->isUserAllowed(1, 1)); $this->assertTrue($pp->isUserAllowed(1, 2)); // We revoke the regular user - $this->assertTrue($pp->revokeUser(1, 2)); + $this->assertTrue($pp->revokeMember(1, 2)); // Only admin should be allowed $this->assertTrue($pp->isUserAllowed(1, 1)); @@ -125,7 +125,7 @@ class ProjectPermissionTest extends Base $this->assertEquals(array('1' => 'admin'), $pp->getMembers(1)); // We revoke the admin user - $this->assertTrue($pp->revokeUser(1, 1)); + $this->assertTrue($pp->revokeMember(1, 1)); $this->assertEmpty($pp->getMembers(1)); // Only admin should be allowed again @@ -133,6 +133,42 @@ class ProjectPermissionTest extends Base $this->assertFalse($pp->isUserAllowed(1, 2)); } + public function testManager() + { + $p = new Project($this->container); + $pp = new ProjectPermission($this->container); + $u = new User($this->container); + + $this->assertEquals(2, $u->create(array('username' => 'unittest', 'password' => 'unittest'))); + + $this->assertEquals(1, $p->create(array('name' => 'UnitTest1'))); + $this->assertFalse($pp->isMember(1, 2)); + $this->assertFalse($pp->isManager(1, 2)); + + $this->assertEquals(2, $p->create(array('name' => 'UnitTest2'), 1, true)); + $this->assertFalse($pp->isMember(2, 2)); + $this->assertFalse($pp->isManager(2, 2)); + + $this->assertEquals(3, $p->create(array('name' => 'UnitTest3'), 2, true)); + $this->assertTrue($pp->isMember(3, 2)); + $this->assertTrue($pp->isManager(3, 2)); + + $this->assertEquals(4, $p->create(array('name' => 'UnitTest4'))); + + $this->assertTrue($pp->addManager(4, 2)); + $this->assertTrue($pp->isMember(4, 2)); + $this->assertTrue($pp->isManager(4, 2)); + + $this->assertEquals(5, $p->create(array('name' => 'UnitTest5'))); + $this->assertTrue($pp->addMember(5, 2)); + $this->assertTrue($pp->changeRole(5, 2, 1)); + $this->assertTrue($pp->isMember(5, 2)); + $this->assertTrue($pp->isManager(5, 2)); + $this->assertTrue($pp->changeRole(5, 2, 0)); + $this->assertTrue($pp->isMember(5, 2)); + $this->assertFalse($pp->isManager(5, 2)); + } + public function testUsersList() { $p = new Project($this->container); @@ -151,7 +187,7 @@ class ProjectPermissionTest extends Base ); // We allow only the regular user - $this->assertTrue($pp->allowUser(1, 2)); + $this->assertTrue($pp->addMember(1, 2)); $this->assertEquals( array(0 => 'Unassigned', 2 => 'unittest'), @@ -159,7 +195,7 @@ class ProjectPermissionTest extends Base ); // We allow the admin user - $this->assertTrue($pp->allowUser(1, 1)); + $this->assertTrue($pp->addMember(1, 1)); $this->assertEquals( array(0 => 'Unassigned', 1 => 'admin', 2 => 'unittest'), @@ -167,7 +203,7 @@ class ProjectPermissionTest extends Base ); // We revoke only the regular user - $this->assertTrue($pp->revokeUser(1, 2)); + $this->assertTrue($pp->revokeMember(1, 2)); $this->assertEquals( array(0 => 'Unassigned', 1 => 'admin'), @@ -175,7 +211,7 @@ class ProjectPermissionTest extends Base ); // We revoke only the admin user, we should have everybody - $this->assertTrue($pp->revokeUser(1, 1)); + $this->assertTrue($pp->revokeMember(1, 1)); $this->assertEquals( array(0 => 'Unassigned'), diff --git a/tests/units/TaskDuplicationTest.php b/tests/units/TaskDuplicationTest.php index 6f1ee0e2..bc455873 100644 --- a/tests/units/TaskDuplicationTest.php +++ b/tests/units/TaskDuplicationTest.php @@ -240,8 +240,8 @@ class TaskDuplicationTest extends Base // We create a new user for our project $user = new User($this->container); $this->assertNotFalse($user->create(array('username' => 'unittest#1', 'password' => 'unittest'))); - $this->assertTrue($pp->allowUser(1, 2)); - $this->assertTrue($pp->allowUser(2, 2)); + $this->assertTrue($pp->addMember(1, 2)); + $this->assertTrue($pp->addMember(2, 2)); $this->assertTrue($pp->isUserAllowed(1, 2)); $this->assertTrue($pp->isUserAllowed(2, 2)); @@ -363,8 +363,8 @@ class TaskDuplicationTest extends Base // We create a new user for our project $this->assertNotFalse($user->create(array('username' => 'unittest#1', 'password' => 'unittest'))); - $this->assertTrue($pp->allowUser(1, 2)); - $this->assertTrue($pp->allowUser(2, 2)); + $this->assertTrue($pp->addMember(1, 2)); + $this->assertTrue($pp->addMember(2, 2)); $this->assertTrue($pp->isUserAllowed(1, 2)); $this->assertTrue($pp->isUserAllowed(2, 2)); @@ -398,8 +398,8 @@ class TaskDuplicationTest extends Base // We create a new user for our project $this->assertNotFalse($user->create(array('username' => 'unittest#1', 'password' => 'unittest'))); - $this->assertTrue($pp->allowUser(1, 2)); - $this->assertTrue($pp->allowUser(2, 2)); + $this->assertTrue($pp->addMember(1, 2)); + $this->assertTrue($pp->addMember(2, 2)); $this->assertTrue($pp->isUserAllowed(1, 2)); $this->assertTrue($pp->isUserAllowed(2, 2)); diff --git a/tests/units/TaskExportTest.php b/tests/units/TaskExportTest.php index 963c031d..3892f2bd 100644 --- a/tests/units/TaskExportTest.php +++ b/tests/units/TaskExportTest.php @@ -48,6 +48,7 @@ class TaskExportTest extends Base } $rows = $e->export(1, strtotime('-1 day'), strtotime('+1 day')); + $this->assertEquals($i, count($rows)); $this->assertEquals('Task Id', $rows[0][0]); $this->assertEquals(1, $rows[1][0]); diff --git a/tests/units/UserSessionTest.php b/tests/units/UserSessionTest.php new file mode 100644 index 00000000..45f1bfde --- /dev/null +++ b/tests/units/UserSessionTest.php @@ -0,0 +1,45 @@ +<?php + +require_once __DIR__.'/Base.php'; + +use Core\Session; +use Model\UserSession; + +class UserSessionTest extends Base +{ + public function testIsAdmin() + { + $s = new Session; + $us = new UserSession($this->container); + + $this->assertFalse($us->isAdmin()); + + $s['user'] = array(); + $this->assertFalse($us->isAdmin()); + + $s['user'] = array('is_admin' => '1'); + $this->assertFalse($us->isAdmin()); + + $s['user'] = array('is_admin' => false); + $this->assertFalse($us->isAdmin()); + + $s['user'] = array('is_admin' => '2'); + $this->assertFalse($us->isAdmin()); + + $s['user'] = array('is_admin' => true); + $this->assertTrue($us->isAdmin()); + } + + public function testLastSeenProject() + { + $us = new UserSession($this->container); + + $this->assertEquals(0, $us->getLastSeenProjectId()); + + $us->storeLastSeenProjectId(33); + $this->assertEquals(33, $us->getLastSeenProjectId()); + + $us->storeLastSeenProjectId(66); + $this->assertEquals(66, $us->getLastSeenProjectId()); + } +} |