diff options
Diffstat (limited to 'app/Controller')
-rw-r--r-- | app/Controller/Action.php | 142 | ||||
-rw-r--r-- | app/Controller/App.php | 29 | ||||
-rw-r--r-- | app/Controller/Base.php | 238 | ||||
-rw-r--r-- | app/Controller/Board.php | 411 | ||||
-rw-r--r-- | app/Controller/Category.php | 189 | ||||
-rw-r--r-- | app/Controller/Comment.php | 189 | ||||
-rw-r--r-- | app/Controller/Config.php | 117 | ||||
-rw-r--r-- | app/Controller/Project.php | 375 | ||||
-rw-r--r-- | app/Controller/Task.php | 397 | ||||
-rw-r--r-- | app/Controller/User.php | 310 |
10 files changed, 2397 insertions, 0 deletions
diff --git a/app/Controller/Action.php b/app/Controller/Action.php new file mode 100644 index 00000000..b32a8906 --- /dev/null +++ b/app/Controller/Action.php @@ -0,0 +1,142 @@ +<?php + +namespace Controller; + +/** + * Automatic actions management + * + * @package controller + * @author Frederic Guillot + */ +class Action extends Base +{ + /** + * List of automatic actions for a given project + * + * @access public + */ + public function index() + { + $project_id = $this->request->getIntegerParam('project_id'); + $project = $this->project->getById($project_id); + + if (! $project) { + $this->session->flashError(t('Project not found.')); + $this->response->redirect('?controller=project'); + } + + $this->response->html($this->template->layout('action_index', array( + 'values' => array('project_id' => $project['id']), + 'project' => $project, + 'actions' => $this->action->getAllByProject($project['id']), + 'available_actions' => $this->action->getAvailableActions(), + 'available_events' => $this->action->getAvailableEvents(), + 'available_params' => $this->action->getAllActionParameters(), + 'columns_list' => $this->board->getColumnsList($project['id']), + 'users_list' => $this->project->getUsersList($project['id'], false), + 'projects_list' => $this->project->getList(false), + 'colors_list' => $this->task->getColors(), + 'categories_list' => $this->category->getList($project['id'], false), + 'menu' => 'projects', + 'title' => t('Automatic actions') + ))); + } + + /** + * Define action parameters (step 2) + * + * @access public + */ + public function params() + { + $project_id = $this->request->getIntegerParam('project_id'); + $project = $this->project->getById($project_id); + + if (! $project) { + $this->session->flashError(t('Project not found.')); + $this->response->redirect('?controller=project'); + } + + $values = $this->request->getValues(); + $action = $this->action->load($values['action_name'], $values['project_id']); + + $this->response->html($this->template->layout('action_params', array( + 'values' => $values, + 'action_params' => $action->getActionRequiredParameters(), + 'columns_list' => $this->board->getColumnsList($project['id']), + 'users_list' => $this->project->getUsersList($project['id'], false), + 'projects_list' => $this->project->getList(false), + 'colors_list' => $this->task->getColors(), + 'categories_list' => $this->category->getList($project['id'], false), + 'project' => $project, + 'menu' => 'projects', + 'title' => t('Automatic actions') + ))); + } + + /** + * Create a new action (last step) + * + * @access public + */ + public function create() + { + $project_id = $this->request->getIntegerParam('project_id'); + $project = $this->project->getById($project_id); + + if (! $project) { + $this->session->flashError(t('Project not found.')); + $this->response->redirect('?controller=project'); + } + + $values = $this->request->getValues(); + + list($valid, $errors) = $this->action->validateCreation($values); + + if ($valid) { + + if ($this->action->create($values)) { + $this->session->flash(t('Your automatic action have been created successfully.')); + } + else { + $this->session->flashError(t('Unable to create your automatic action.')); + } + } + + $this->response->redirect('?controller=action&action=index&project_id='.$project['id']); + } + + /** + * Confirmation dialog before removing an action + * + * @access public + */ + public function confirm() + { + $this->response->html($this->template->layout('action_remove', array( + 'action' => $this->action->getById($this->request->getIntegerParam('action_id')), + 'available_events' => $this->action->getAvailableEvents(), + 'available_actions' => $this->action->getAvailableActions(), + 'menu' => 'projects', + 'title' => t('Remove an action') + ))); + } + + /** + * Remove an action + * + * @access public + */ + public function remove() + { + $action = $this->action->getById($this->request->getIntegerParam('action_id')); + + if ($action && $this->action->remove($action['id'])) { + $this->session->flash(t('Action removed successfully.')); + } else { + $this->session->flashError(t('Unable to remove this action.')); + } + + $this->response->redirect('?controller=action&action=index&project_id='.$action['project_id']); + } +} diff --git a/app/Controller/App.php b/app/Controller/App.php new file mode 100644 index 00000000..64f9461f --- /dev/null +++ b/app/Controller/App.php @@ -0,0 +1,29 @@ +<?php + +namespace Controller; + +use Model\Project; + +/** + * Application controller + * + * @package controller + * @author Frederic Guillot + */ +class App extends Base +{ + /** + * Redirect to the project creation page or the board controller + * + * @access public + */ + public function index() + { + if ($this->project->countByStatus(Project::ACTIVE)) { + $this->response->redirect('?controller=board'); + } + else { + $this->redirectNoProject(); + } + } +} diff --git a/app/Controller/Base.php b/app/Controller/Base.php new file mode 100644 index 00000000..bb9add4f --- /dev/null +++ b/app/Controller/Base.php @@ -0,0 +1,238 @@ +<?php + +namespace Controller; + +use Core\Registry; +use Core\Translator; +use Model\LastLogin; + +/** + * Base controller + * + * @package controller + * @author Frederic Guillot + */ +abstract class Base +{ + /** + * Request instance + * + * @accesss public + * @var \Core\Request + */ + public $request; + + /** + * Response instance + * + * @accesss public + * @var \Core\Response + */ + public $response; + + /** + * Template instance + * + * @accesss public + * @var \Core\Template + */ + public $template; + + /** + * Session instance + * + * @accesss public + * @var \Core\Session + */ + public $session; + + /** + * Registry instance + * + * @access private + * @var Core\Registry + */ + private $registry; + + /** + * Constructor + * + * @access public + * @param \Core\Registry $registry Registry instance + */ + public function __construct(Registry $registry) + { + $this->registry = $registry; + } + + /** + * Load automatically models + * + * @access public + * @param string $name Model name + */ + public function __get($name) + { + $class = '\Model\\'.ucfirst($name); + $this->registry->$name = new $class($this->registry->shared('db'), $this->registry->shared('event')); + return $this->registry->shared($name); + } + + /** + * Method executed before each action + * + * @access public + */ + public function beforeAction($controller, $action) + { + // Start the session + $this->session->open(BASE_URL_DIRECTORY, SESSION_SAVE_PATH); + + // HTTP secure headers + $this->response->csp(); + $this->response->nosniff(); + $this->response->xss(); + $this->response->hsts(); + $this->response->xframe(); + + // Load translations + $language = $this->config->get('language', 'en_US'); + if ($language !== 'en_US') Translator::load($language); + + // Set timezone + date_default_timezone_set($this->config->get('timezone', 'UTC')); + + // Authentication + if (! $this->acl->isLogged() && ! $this->acl->isPublicAction($controller, $action)) { + + // Try the remember me authentication first + if (! $this->rememberMe->authenticate()) { + + // Redirect to the login form if not authenticated + $this->response->redirect('?controller=user&action=login'); + } + else { + + $this->lastLogin->create( + LastLogin::AUTH_REMEMBER_ME, + $this->acl->getUserId(), + $this->user->getIpAddress(), + $this->user->getUserAgent() + ); + } + } + else if ($this->rememberMe->hasCookie()) { + $this->rememberMe->refresh(); + } + + // Check if the user is allowed to see this page + if (! $this->acl->isPageAccessAllowed($controller, $action)) { + $this->response->redirect('?controller=user&action=forbidden'); + } + + // Attach events + $this->action->attachEvents(); + $this->project->attachEvents(); + } + + /** + * Application not found page (404 error) + * + * @access public + */ + public function notfound() + { + $this->response->html($this->template->layout('app_notfound', array('title' => t('Page not found')))); + } + + /** + * 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()) { + + if ($project_id > 0 && ! $this->project->isUserAllowed($project_id, $this->acl->getUserId())) { + $this->response->redirect('?controller=project&action=forbidden'); + } + } + } + + /** + * Redirection when there is no project in the database + * + * @access protected + */ + protected function redirectNoProject() + { + $this->session->flash(t('There is no active project, the first step is to create a new project.')); + $this->response->redirect('?controller=project&action=create'); + } + + /** + * Display the template show task (common between different actions) + * + * @access protected + * @param array $task Task data + * @param array $comment_form Comment form data + * @param array $description_form Description form data + * @param array $comment_edit_form Comment edit form data + */ + protected function showTask(array $task, array $comment_form = array(), array $description_form = array(), array $comment_edit_form = array()) + { + if (empty($comment_form)) { + $comment_form = array( + 'values' => array('task_id' => $task['id'], 'user_id' => $this->acl->getUserId()), + 'errors' => array() + ); + } + + if (empty($description_form)) { + $description_form = array( + 'values' => array('id' => $task['id']), + 'errors' => array() + ); + } + + if (empty($comment_edit_form)) { + $comment_edit_form = array( + 'values' => array('id' => 0), + 'errors' => array() + ); + } + else { + $hide_comment_form = true; + } + + $this->response->html($this->taskLayout('task_show', array( + 'hide_comment_form' => isset($hide_comment_form), + 'comment_edit_form' => $comment_edit_form, + 'comment_form' => $comment_form, + 'description_form' => $description_form, + 'comments' => $this->comment->getAll($task['id']), + 'task' => $task, + 'columns_list' => $this->board->getColumnsList($task['project_id']), + 'colors_list' => $this->task->getColors(), + 'menu' => 'tasks', + 'title' => $task['title'], + ))); + } + + /** + * Common layout for task views + * + * @access protected + * @param string $template Template name + * @param array $params Template parameters + */ + protected function taskLayout($template, array $params) + { + $content = $this->template->load($template, $params); + $params['task_content_for_layout'] = $content; + + return $this->template->layout('task_layout', $params); + } +} diff --git a/app/Controller/Board.php b/app/Controller/Board.php new file mode 100644 index 00000000..c727a422 --- /dev/null +++ b/app/Controller/Board.php @@ -0,0 +1,411 @@ +<?php + +namespace Controller; + +use Model\Project; +use Model\User; + +/** + * Board controller + * + * @package controller + * @author Frederic Guillot + */ +class Board extends Base +{ + /** + * Move a column up + * + * @access public + */ + public function moveUp() + { + $project_id = $this->request->getIntegerParam('project_id'); + $column_id = $this->request->getIntegerParam('column_id'); + + $this->board->moveUp($project_id, $column_id); + + $this->response->redirect('?controller=board&action=edit&project_id='.$project_id); + } + + /** + * Move a column down + * + * @access public + */ + public function moveDown() + { + $project_id = $this->request->getIntegerParam('project_id'); + $column_id = $this->request->getIntegerParam('column_id'); + + $this->board->moveDown($project_id, $column_id); + + $this->response->redirect('?controller=board&action=edit&project_id='.$project_id); + } + + /** + * Change a task assignee directly from the board + * + * @access public + */ + public function assign() + { + $task = $this->task->getById($this->request->getIntegerParam('task_id')); + $project = $this->project->getById($task['project_id']); + $projects = $this->project->getListByStatus(Project::ACTIVE); + + if ($this->acl->isRegularUser()) { + $projects = $this->project->filterListByAccess($projects, $this->acl->getUserId()); + } + + if (! $project) $this->notfound(); + $this->checkProjectPermissions($project['id']); + + if ($this->request->isAjax()) { + + $this->response->html($this->template->load('board_assign', array( + 'errors' => array(), + 'values' => $task, + 'users_list' => $this->project->getUsersList($project['id']), + 'projects' => $projects, + 'current_project_id' => $project['id'], + 'current_project_name' => $project['name'], + ))); + } + else { + + $this->response->html($this->template->layout('board_assign', array( + 'errors' => array(), + 'values' => $task, + 'users_list' => $this->project->getUsersList($project['id']), + 'projects' => $projects, + 'current_project_id' => $project['id'], + 'current_project_name' => $project['name'], + 'menu' => 'boards', + 'title' => t('Change assignee').' - '.$task['title'], + ))); + } + } + + /** + * Validate an assignee modification + * + * @access public + */ + public function assignTask() + { + $values = $this->request->getValues(); + $this->checkProjectPermissions($values['project_id']); + + list($valid,) = $this->task->validateAssigneeModification($values); + + if ($valid && $this->task->update($values)) { + $this->session->flash(t('Task updated successfully.')); + } + else { + $this->session->flashError(t('Unable to update your task.')); + } + + $this->response->redirect('?controller=board&action=show&project_id='.$values['project_id']); + } + + /** + * Display the public version of a board + * Access checked by a simple token, no user login, read only, auto-refresh + * + * @access public + */ + public function readonly() + { + $token = $this->request->getStringParam('token'); + $project = $this->project->getByToken($token); + + // Token verification + if (! $project) { + $this->response->text('Not Authorized', 401); + } + + // Display the board with a specific layout + $this->response->html($this->template->layout('board_public', array( + 'project' => $project, + 'columns' => $this->board->get($project['id']), + 'categories' => $this->category->getList($project['id'], false), + 'title' => $project['name'], + 'no_layout' => true, + 'auto_refresh' => true, + ))); + } + + /** + * Redirect the user to the default project + * + * @access public + */ + public function index() + { + $projects = $this->project->getListByStatus(Project::ACTIVE); + + if ($this->acl->isRegularUser()) { + $projects = $this->project->filterListByAccess($projects, $this->acl->getUserId()); + } + + if (empty($projects)) { + + if ($this->acl->isAdminUser()) { + $this->redirectNoProject(); + } + else { + $this->response->redirect('?controller=project&action=forbidden'); + } + } + else if (! empty($_SESSION['user']['default_project_id']) && isset($projects[$_SESSION['user']['default_project_id']])) { + $project_id = $_SESSION['user']['default_project_id']; + $project_name = $projects[$_SESSION['user']['default_project_id']]; + } + else { + list($project_id, $project_name) = each($projects); + } + + $this->response->redirect('?controller=board&action=show&project_id='.$project_id); + } + + /** + * Show a board for a given project + * + * @access public + */ + public function show() + { + $project_id = $this->request->getIntegerParam('project_id'); + $user_id = $this->request->getIntegerParam('user_id', User::EVERYBODY_ID); + + $this->checkProjectPermissions($project_id); + $projects = $this->project->getListByStatus(Project::ACTIVE); + + if ($this->acl->isRegularUser()) { + $projects = $this->project->filterListByAccess($projects, $this->acl->getUserId()); + } + + if (! isset($projects[$project_id])) { + $this->notfound(); + } + + $this->response->html($this->template->layout('board_index', array( + 'users' => $this->project->getUsersList($project_id, true, true), + 'filters' => array('user_id' => $user_id), + 'projects' => $projects, + 'current_project_id' => $project_id, + 'current_project_name' => $projects[$project_id], + 'board' => $this->board->get($project_id), + 'categories' => $this->category->getList($project_id, true, true), + 'menu' => 'boards', + 'title' => $projects[$project_id] + ))); + } + + /** + * Display a form to edit a board + * + * @access public + */ + public function edit() + { + $project_id = $this->request->getIntegerParam('project_id'); + $project = $this->project->getById($project_id); + + if (! $project) $this->notfound(); + + $columns = $this->board->getColumns($project_id); + $values = array(); + + foreach ($columns as $column) { + $values['title['.$column['id'].']'] = $column['title']; + $values['task_limit['.$column['id'].']'] = $column['task_limit'] ?: null; + } + + $this->response->html($this->template->layout('board_edit', array( + 'errors' => array(), + 'values' => $values + array('project_id' => $project_id), + 'columns' => $columns, + 'project' => $project, + 'menu' => 'projects', + 'title' => t('Edit board') + ))); + } + + /** + * Validate and update a board + * + * @access public + */ + public function update() + { + $project_id = $this->request->getIntegerParam('project_id'); + $project = $this->project->getById($project_id); + + if (! $project) $this->notfound(); + + $columns = $this->board->getColumns($project_id); + $data = $this->request->getValues(); + $values = $columns_list = array(); + + foreach ($columns as $column) { + $columns_list[$column['id']] = $column['title']; + $values['title['.$column['id'].']'] = isset($data['title'][$column['id']]) ? $data['title'][$column['id']] : ''; + $values['task_limit['.$column['id'].']'] = isset($data['task_limit'][$column['id']]) ? $data['task_limit'][$column['id']] : 0; + } + + list($valid, $errors) = $this->board->validateModification($columns_list, $values); + + if ($valid) { + + if ($this->board->update($data)) { + $this->session->flash(t('Board updated successfully.')); + $this->response->redirect('?controller=board&action=edit&project_id='.$project['id']); + } + else { + $this->session->flashError(t('Unable to update this board.')); + } + } + + $this->response->html($this->template->layout('board_edit', array( + 'errors' => $errors, + 'values' => $values + array('project_id' => $project_id), + 'columns' => $columns, + 'project' => $project, + 'menu' => 'projects', + 'title' => t('Edit board') + ))); + } + + /** + * Validate and add a new column + * + * @access public + */ + public function add() + { + $project_id = $this->request->getIntegerParam('project_id'); + $project = $this->project->getById($project_id); + + if (! $project) $this->notfound(); + + $columns = $this->board->getColumnsList($project_id); + $data = $this->request->getValues(); + $values = array(); + + foreach ($columns as $column_id => $column_title) { + $values['title['.$column_id.']'] = $column_title; + } + + list($valid, $errors) = $this->board->validateCreation($data); + + if ($valid) { + + if ($this->board->add($data)) { + $this->session->flash(t('Board updated successfully.')); + $this->response->redirect('?controller=board&action=edit&project_id='.$project['id']); + } + else { + $this->session->flashError(t('Unable to update this board.')); + } + } + + $this->response->html($this->template->layout('board_edit', array( + 'errors' => $errors, + 'values' => $values + $data, + 'columns' => $columns, + 'project' => $project, + 'menu' => 'projects', + 'title' => t('Edit board') + ))); + } + + /** + * Confirmation dialog before removing a column + * + * @access public + */ + public function confirm() + { + $this->response->html($this->template->layout('board_remove', array( + 'column' => $this->board->getColumn($this->request->getIntegerParam('column_id')), + 'menu' => 'projects', + 'title' => t('Remove a column from a board') + ))); + } + + /** + * Remove a column + * + * @access public + */ + public function remove() + { + $column = $this->board->getColumn($this->request->getIntegerParam('column_id')); + + if ($column && $this->board->removeColumn($column['id'])) { + $this->session->flash(t('Column removed successfully.')); + } else { + $this->session->flashError(t('Unable to remove this column.')); + } + + $this->response->redirect('?controller=board&action=edit&project_id='.$column['project_id']); + } + + /** + * Save the board (Ajax request made by the drag and drop) + * + * @access public + */ + public function save() + { + $project_id = $this->request->getIntegerParam('project_id'); + $values = $this->request->getValues(); + + if ($project_id > 0 && ! $this->project->isUserAllowed($project_id, $this->acl->getUserId())) { + $this->response->text('Not Authorized', 401); + } + + if (isset($values['positions'])) { + $this->board->saveTasksPosition($values['positions']); + } + + $this->response->html( + $this->template->load('board_show', array( + 'current_project_id' => $project_id, + 'board' => $this->board->get($project_id), + 'categories' => $this->category->getList($project_id, false), + )), + 201 + ); + } + + /** + * Check if the board have been changed + * + * @access public + */ + public function check() + { + $project_id = $this->request->getIntegerParam('project_id'); + $timestamp = $this->request->getIntegerParam('timestamp'); + + if ($project_id > 0 && ! $this->project->isUserAllowed($project_id, $this->acl->getUserId())) { + $this->response->text('Not Authorized', 401); + } + + if ($this->project->isModifiedSince($project_id, $timestamp)) { + $this->response->html( + $this->template->load('board_show', array( + 'current_project_id' => $project_id, + 'board' => $this->board->get($project_id), + 'categories' => $this->category->getList($project_id, false), + )) + ); + } + else { + $this->response->status(304); + } + } +} diff --git a/app/Controller/Category.php b/app/Controller/Category.php new file mode 100644 index 00000000..f96c1d4a --- /dev/null +++ b/app/Controller/Category.php @@ -0,0 +1,189 @@ +<?php + +namespace Controller; + +/** + * Categories management + * + * @package controller + * @author Frederic Guillot + */ +class Category extends Base +{ + /** + * Get the current project (common method between actions) + * + * @access private + * @return array + */ + private function getProject() + { + $project_id = $this->request->getIntegerParam('project_id'); + $project = $this->project->getById($project_id); + + if (! $project) { + $this->session->flashError(t('Project not found.')); + $this->response->redirect('?controller=project'); + } + + return $project; + } + + /** + * Get the category (common method between actions) + * + * @access private + * @return array + */ + private function getCategory($project_id) + { + $category = $this->category->getById($this->request->getIntegerParam('category_id')); + + if (! $category) { + $this->session->flashError(t('Category not found.')); + $this->response->redirect('?controller=category&action=index&project_id='.$project_id); + } + + return $category; + } + + /** + * List of categories for a given project + * + * @access public + */ + public function index() + { + $project = $this->getProject(); + + $this->response->html($this->template->layout('category_index', array( + 'categories' => $this->category->getList($project['id'], false), + 'values' => array('project_id' => $project['id']), + 'errors' => array(), + 'project' => $project, + 'menu' => 'projects', + 'title' => t('Categories') + ))); + } + + /** + * Validate and save a new project + * + * @access public + */ + public function save() + { + $project = $this->getProject(); + + $values = $this->request->getValues(); + list($valid, $errors) = $this->category->validateCreation($values); + + if ($valid) { + + if ($this->category->create($values)) { + $this->session->flash(t('Your category have been created successfully.')); + $this->response->redirect('?controller=category&action=index&project_id='.$project['id']); + } + else { + $this->session->flashError(t('Unable to create your category.')); + } + } + + $this->response->html($this->template->layout('category_index', array( + 'categories' => $this->category->getList($project['id'], false), + 'values' => $values, + 'errors' => $errors, + 'project' => $project, + 'menu' => 'projects', + 'title' => t('Categories') + ))); + } + + /** + * Edit a category (display the form) + * + * @access public + */ + public function edit() + { + $project = $this->getProject(); + $category = $this->getCategory($project['id']); + + $this->response->html($this->template->layout('category_edit', array( + 'values' => $category, + 'errors' => array(), + 'project' => $project, + 'menu' => 'projects', + 'title' => t('Categories') + ))); + } + + /** + * Edit a category (validate the form and update the database) + * + * @access public + */ + public function update() + { + $project = $this->getProject(); + + $values = $this->request->getValues(); + list($valid, $errors) = $this->category->validateModification($values); + + if ($valid) { + + if ($this->category->update($values)) { + $this->session->flash(t('Your category have been updated successfully.')); + $this->response->redirect('?controller=category&action=index&project_id='.$project['id']); + } + else { + $this->session->flashError(t('Unable to update your category.')); + } + } + + $this->response->html($this->template->layout('category_edit', array( + 'values' => $values, + 'errors' => $errors, + 'project' => $project, + 'menu' => 'projects', + 'title' => t('Categories') + ))); + } + + /** + * Confirmation dialog before removing a category + * + * @access public + */ + public function confirm() + { + $project = $this->getProject(); + $category = $this->getCategory($project['id']); + + $this->response->html($this->template->layout('category_remove', array( + 'project' => $project, + 'category' => $category, + 'menu' => 'projects', + 'title' => t('Remove a category') + ))); + } + + /** + * Remove a category + * + * @access public + */ + public function remove() + { + $project = $this->getProject(); + $category = $this->getCategory($project['id']); + + if ($this->category->remove($category['id'])) { + $this->session->flash(t('Category removed successfully.')); + } else { + $this->session->flashError(t('Unable to remove this category.')); + } + + $this->response->redirect('?controller=category&action=index&project_id='.$project['id']); + } +} diff --git a/app/Controller/Comment.php b/app/Controller/Comment.php new file mode 100644 index 00000000..c9f226f7 --- /dev/null +++ b/app/Controller/Comment.php @@ -0,0 +1,189 @@ +<?php + +namespace Controller; + +/** + * Comment controller + * + * @package controller + * @author Frederic Guillot + */ +class Comment extends Base +{ + /** + * Forbidden page for comments + * + * @access public + */ + public function forbidden() + { + $this->response->html($this->template->layout('comment_forbidden', array( + 'menu' => 'tasks', + 'title' => t('Access Forbidden') + ))); + } + + /** + * Add a comment + * + * @access public + */ + public function save() + { + $task = $this->task->getById($this->request->getIntegerParam('task_id'), true); + $values = $this->request->getValues(); + + if (! $task) $this->notfound(); + $this->checkProjectPermissions($task['project_id']); + + list($valid, $errors) = $this->comment->validateCreation($values); + + if ($valid) { + + if ($this->comment->create($values)) { + $this->session->flash(t('Comment added successfully.')); + } + else { + $this->session->flashError(t('Unable to create your comment.')); + } + + $this->response->redirect('?controller=task&action=show&task_id='.$task['id']); + } + + $this->showTask( + $task, + array('values' => $values, 'errors' => $errors) + ); + } + + /** + * Edit a comment + * + * @access public + */ + public function edit() + { + $task_id = $this->request->getIntegerParam('task_id'); + $comment_id = $this->request->getIntegerParam('comment_id'); + + $task = $this->task->getById($task_id, true); + $comment = $this->comment->getById($comment_id); + + if (! $task || ! $comment) $this->notfound(); + $this->checkProjectPermissions($task['project_id']); + + if ($this->acl->isAdminUser() || $comment['user_id'] == $this->acl->getUserId()) { + + $this->showTask( + $task, + array(), + array(), + array('values' => array('id' => $comment['id']), 'errors' => array()) + ); + } + + $this->forbidden(); + } + + /** + * Update and validate a comment + * + * @access public + */ + public function update() + { + $task_id = $this->request->getIntegerParam('task_id'); + $comment_id = $this->request->getIntegerParam('comment_id'); + + $task = $this->task->getById($task_id, true); + $comment = $this->comment->getById($comment_id); + + $values = $this->request->getValues(); + + if (! $task || ! $comment) $this->notfound(); + $this->checkProjectPermissions($task['project_id']); + + if ($this->acl->isAdminUser() || $comment['user_id'] == $this->acl->getUserId()) { + + list($valid, $errors) = $this->comment->validateModification($values); + + if ($valid) { + + if ($this->comment->update($values)) { + $this->session->flash(t('Comment updated successfully.')); + } + else { + $this->session->flashError(t('Unable to update your comment.')); + } + + $this->response->redirect('?controller=task&action=show&task_id='.$task['id'].'#comment-'.$comment_id); + } + + $this->showTask( + $task, + array(), + array(), + array('values' => $values, 'errors' => $errors) + ); + } + + $this->forbidden(); + } + + /** + * Confirmation dialog before removing a comment + * + * @access public + */ + public function confirm() + { + $project_id = $this->request->getIntegerParam('project_id'); + $comment_id = $this->request->getIntegerParam('comment_id'); + + $this->checkProjectPermissions($project_id); + + $comment = $this->comment->getById($comment_id); + if (! $comment) $this->notfound(); + + if ($this->acl->isAdminUser() || $comment['user_id'] == $this->acl->getUserId()) { + + $this->response->html($this->template->layout('comment_remove', array( + 'comment' => $comment, + 'project_id' => $project_id, + 'menu' => 'tasks', + 'title' => t('Remove a comment') + ))); + } + + $this->forbidden(); + } + + /** + * Remove a comment + * + * @access public + */ + public function remove() + { + $project_id = $this->request->getIntegerParam('project_id'); + $comment_id = $this->request->getIntegerParam('comment_id'); + + $this->checkProjectPermissions($project_id); + + $comment = $this->comment->getById($comment_id); + if (! $comment) $this->notfound(); + + if ($this->acl->isAdminUser() || $comment['user_id'] == $this->acl->getUserId()) { + + if ($this->comment->remove($comment['id'])) { + $this->session->flash(t('Comment removed successfully.')); + } else { + $this->session->flashError(t('Unable to remove this comment.')); + } + + $this->response->redirect('?controller=task&action=show&task_id='.$comment['task_id']); + } + + $this->forbidden(); + } +} diff --git a/app/Controller/Config.php b/app/Controller/Config.php new file mode 100644 index 00000000..b4a5b8d3 --- /dev/null +++ b/app/Controller/Config.php @@ -0,0 +1,117 @@ +<?php + +namespace Controller; + +/** + * Config controller + * + * @package controller + * @author Frederic Guillot + */ +class Config extends Base +{ + /** + * Display the settings page + * + * @access public + */ + public function index() + { + $this->response->html($this->template->layout('config_index', array( + 'db_size' => $this->config->getDatabaseSize(), + 'user' => $_SESSION['user'], + 'projects' => $this->project->getList(), + 'languages' => $this->config->getLanguages(), + 'values' => $this->config->getAll(), + 'errors' => array(), + 'menu' => 'config', + 'title' => t('Settings'), + 'timezones' => $this->config->getTimezones(), + 'remember_me_sessions' => $this->rememberMe->getAll($this->acl->getUserId()), + 'last_logins' => $this->lastLogin->getAll($this->acl->getUserId()), + ))); + } + + /** + * Validate and save settings + * + * @access public + */ + public function save() + { + $values = $this->request->getValues(); + list($valid, $errors) = $this->config->validateModification($values); + + if ($valid) { + + if ($this->config->save($values)) { + $this->config->reload(); + $this->session->flash(t('Settings saved successfully.')); + } else { + $this->session->flashError(t('Unable to save your settings.')); + } + + $this->response->redirect('?controller=config'); + } + + $this->response->html($this->template->layout('config_index', array( + 'db_size' => $this->config->getDatabaseSize(), + 'user' => $_SESSION['user'], + 'projects' => $this->project->getList(), + 'languages' => $this->config->getLanguages(), + 'values' => $values, + 'errors' => $errors, + 'menu' => 'config', + 'title' => t('Settings'), + 'timezones' => $this->config->getTimezones(), + 'remember_me_sessions' => $this->rememberMe->getAll($this->acl->getUserId()), + 'last_logins' => $this->lastLogin->getAll($this->acl->getUserId()), + ))); + } + + /** + * Download the Sqlite database + * + * @access public + */ + public function downloadDb() + { + $this->response->forceDownload('db.sqlite.gz'); + $this->response->binary($this->config->downloadDatabase()); + } + + /** + * Optimize the Sqlite database + * + * @access public + */ + public function optimizeDb() + { + $this->config->optimizeDatabase(); + $this->session->flash(t('Database optimization done.')); + $this->response->redirect('?controller=config'); + } + + /** + * Regenerate all application tokens + * + * @access public + */ + public function tokens() + { + $this->config->regenerateTokens(); + $this->session->flash(t('All tokens have been regenerated.')); + $this->response->redirect('?controller=config'); + } + + /** + * Remove a "RememberMe" token + * + * @access public + */ + public function removeRememberMeToken() + { + $this->rememberMe->remove($this->request->getIntegerParam('id')); + $this->response->redirect('?controller=config&action=index#remember-me'); + } +} diff --git a/app/Controller/Project.php b/app/Controller/Project.php new file mode 100644 index 00000000..5cb244a2 --- /dev/null +++ b/app/Controller/Project.php @@ -0,0 +1,375 @@ +<?php + +namespace Controller; + +use Model\Task; + +/** + * Project controller + * + * @package controller + * @author Frederic Guillot + */ +class Project extends Base +{ + /** + * Display access forbidden page + * + * @access public + */ + public function forbidden() + { + $this->response->html($this->template->layout('project_forbidden', array( + 'menu' => 'projects', + 'title' => t('Access Forbidden') + ))); + } + + /** + * Task search for a given project + * + * @access public + */ + public function search() + { + $project_id = $this->request->getIntegerParam('project_id'); + $search = $this->request->getStringParam('search'); + + $project = $this->project->getById($project_id); + $tasks = array(); + $nb_tasks = 0; + + if (! $project) { + $this->session->flashError(t('Project not found.')); + $this->response->redirect('?controller=project'); + } + + $this->checkProjectPermissions($project['id']); + + if ($search !== '') { + + $filters = array( + array('column' => 'project_id', 'operator' => 'eq', 'value' => $project_id), + 'or' => array( + array('column' => 'title', 'operator' => 'like', 'value' => '%'.$search.'%'), + //array('column' => 'description', 'operator' => 'like', 'value' => '%'.$search.'%'), + ) + ); + + $tasks = $this->task->find($filters); + $nb_tasks = count($tasks); + } + + $this->response->html($this->template->layout('project_search', array( + 'tasks' => $tasks, + 'nb_tasks' => $nb_tasks, + 'values' => array( + 'search' => $search, + 'controller' => 'project', + 'action' => 'search', + 'project_id' => $project['id'], + ), + 'menu' => 'projects', + 'project' => $project, + 'columns' => $this->board->getColumnsList($project_id), + 'categories' => $this->category->getList($project['id'], false), + 'title' => $project['name'].($nb_tasks > 0 ? ' ('.$nb_tasks.')' : '') + ))); + } + + /** + * List of completed tasks for a given project + * + * @access public + */ + public function tasks() + { + $project_id = $this->request->getIntegerParam('project_id'); + $project = $this->project->getById($project_id); + + if (! $project) { + $this->session->flashError(t('Project not found.')); + $this->response->redirect('?controller=project'); + } + + $this->checkProjectPermissions($project['id']); + + $filters = array( + array('column' => 'project_id', 'operator' => 'eq', 'value' => $project_id), + array('column' => 'is_active', 'operator' => 'eq', 'value' => Task::STATUS_CLOSED), + ); + + $tasks = $this->task->find($filters); + $nb_tasks = count($tasks); + + $this->response->html($this->template->layout('project_tasks', array( + 'menu' => 'projects', + 'project' => $project, + 'columns' => $this->board->getColumnsList($project_id), + 'categories' => $this->category->getList($project['id'], false), + 'tasks' => $tasks, + 'nb_tasks' => $nb_tasks, + 'title' => $project['name'].' ('.$nb_tasks.')' + ))); + } + + /** + * List of projects + * + * @access public + */ + public function index() + { + $projects = $this->project->getAll(true, $this->acl->isRegularUser()); + $nb_projects = count($projects); + + $this->response->html($this->template->layout('project_index', array( + 'projects' => $projects, + 'nb_projects' => $nb_projects, + 'menu' => 'projects', + 'title' => t('Projects').' ('.$nb_projects.')' + ))); + } + + /** + * Display a form to create a new project + * + * @access public + */ + public function create() + { + $this->response->html($this->template->layout('project_new', array( + 'errors' => array(), + 'values' => array(), + 'menu' => 'projects', + 'title' => t('New project') + ))); + } + + /** + * Validate and save a new project + * + * @access public + */ + public function save() + { + $values = $this->request->getValues(); + list($valid, $errors) = $this->project->validateCreation($values); + + if ($valid) { + + if ($this->project->create($values)) { + $this->session->flash(t('Your project have been created successfully.')); + $this->response->redirect('?controller=project'); + } + else { + $this->session->flashError(t('Unable to create your project.')); + } + } + + $this->response->html($this->template->layout('project_new', array( + 'errors' => $errors, + 'values' => $values, + 'menu' => 'projects', + 'title' => t('New Project') + ))); + } + + /** + * Display a form to edit a project + * + * @access public + */ + public function edit() + { + $project = $this->project->getById($this->request->getIntegerParam('project_id')); + + if (! $project) { + $this->session->flashError(t('Project not found.')); + $this->response->redirect('?controller=project'); + } + + $this->response->html($this->template->layout('project_edit', array( + 'errors' => array(), + 'values' => $project, + 'menu' => 'projects', + 'title' => t('Edit project') + ))); + } + + /** + * Validate and update a project + * + * @access public + */ + public function update() + { + $values = $this->request->getValues() + array('is_active' => 0); + list($valid, $errors) = $this->project->validateModification($values); + + if ($valid) { + + if ($this->project->update($values)) { + $this->session->flash(t('Project updated successfully.')); + $this->response->redirect('?controller=project'); + } + else { + $this->session->flashError(t('Unable to update this project.')); + } + } + + $this->response->html($this->template->layout('project_edit', array( + 'errors' => $errors, + 'values' => $values, + 'menu' => 'projects', + 'title' => t('Edit Project') + ))); + } + + /** + * Confirmation dialog before to remove a project + * + * @access public + */ + public function confirm() + { + $project = $this->project->getById($this->request->getIntegerParam('project_id')); + + if (! $project) { + $this->session->flashError(t('Project not found.')); + $this->response->redirect('?controller=project'); + } + + $this->response->html($this->template->layout('project_remove', array( + 'project' => $project, + 'menu' => 'projects', + 'title' => t('Remove project') + ))); + } + + /** + * Remove a project + * + * @access public + */ + public function remove() + { + $project_id = $this->request->getIntegerParam('project_id'); + + if ($project_id && $this->project->remove($project_id)) { + $this->session->flash(t('Project removed successfully.')); + } else { + $this->session->flashError(t('Unable to remove this project.')); + } + + $this->response->redirect('?controller=project'); + } + + /** + * Enable a project + * + * @access public + */ + public function enable() + { + $project_id = $this->request->getIntegerParam('project_id'); + + if ($project_id && $this->project->enable($project_id)) { + $this->session->flash(t('Project activated successfully.')); + } else { + $this->session->flashError(t('Unable to activate this project.')); + } + + $this->response->redirect('?controller=project'); + } + + /** + * Disable a project + * + * @access public + */ + public function disable() + { + $project_id = $this->request->getIntegerParam('project_id'); + + if ($project_id && $this->project->disable($project_id)) { + $this->session->flash(t('Project disabled successfully.')); + } else { + $this->session->flashError(t('Unable to disable this project.')); + } + + $this->response->redirect('?controller=project'); + } + + /** + * Users list for the selected project + * + * @access public + */ + public function users() + { + $project = $this->project->getById($this->request->getIntegerParam('project_id')); + + if (! $project) { + $this->session->flashError(t('Project not found.')); + $this->response->redirect('?controller=project'); + } + + $this->response->html($this->template->layout('project_users', array( + 'project' => $project, + 'users' => $this->project->getAllUsers($project['id']), + 'menu' => 'projects', + 'title' => t('Edit project access list') + ))); + } + + /** + * Allow a specific user for the selected project + * + * @access public + */ + public function allow() + { + $values = $this->request->getValues(); + list($valid,) = $this->project->validateUserAccess($values); + + if ($valid) { + + if ($this->project->allowUser($values['project_id'], $values['user_id'])) { + $this->session->flash(t('Project updated successfully.')); + } + else { + $this->session->flashError(t('Unable to update this project.')); + } + } + + $this->response->redirect('?controller=project&action=users&project_id='.$values['project_id']); + } + + /** + * Revoke user access + * + * @access public + */ + public function revoke() + { + $values = array( + 'project_id' => $this->request->getIntegerParam('project_id'), + 'user_id' => $this->request->getIntegerParam('user_id'), + ); + + list($valid,) = $this->project->validateUserAccess($values); + + if ($valid) { + + if ($this->project->revokeUser($values['project_id'], $values['user_id'])) { + $this->session->flash(t('Project updated successfully.')); + } + else { + $this->session->flashError(t('Unable to update this project.')); + } + } + + $this->response->redirect('?controller=project&action=users&project_id='.$values['project_id']); + } +} diff --git a/app/Controller/Task.php b/app/Controller/Task.php new file mode 100644 index 00000000..2291ad43 --- /dev/null +++ b/app/Controller/Task.php @@ -0,0 +1,397 @@ +<?php + +namespace Controller; + +use Model\Project; + +/** + * Task controller + * + * @package controller + * @author Frederic Guillot + */ +class Task extends Base +{ + /** + * Webhook to create a task (useful for external software) + * + * @access public + */ + public function add() + { + $token = $this->request->getStringParam('token'); + + if ($this->config->get('webhooks_token') !== $token) { + $this->response->text('Not Authorized', 401); + } + + $defaultProject = $this->project->getFirst(); + + $values = array( + 'title' => $this->request->getStringParam('title'), + 'description' => $this->request->getStringParam('description'), + 'color_id' => $this->request->getStringParam('color_id', 'blue'), + 'project_id' => $this->request->getIntegerParam('project_id', $defaultProject['id']), + 'owner_id' => $this->request->getIntegerParam('owner_id'), + 'column_id' => $this->request->getIntegerParam('column_id'), + 'category_id' => $this->request->getIntegerParam('category_id'), + ); + + if ($values['column_id'] == 0) { + $values['column_id'] = $this->board->getFirstColumn($values['project_id']); + } + + list($valid,) = $this->task->validateCreation($values); + + if ($valid && $this->task->create($values)) { + $this->response->text('OK'); + } + + $this->response->text('FAILED'); + } + + /** + * Show a task + * + * @access public + */ + public function show() + { + $task = $this->task->getById($this->request->getIntegerParam('task_id'), true); + + if (! $task) $this->notfound(); + $this->checkProjectPermissions($task['project_id']); + + $this->showTask($task); + } + + /** + * Add a description from the show task page + * + * @access public + */ + public function description() + { + $task = $this->task->getById($this->request->getIntegerParam('task_id'), true); + $values = $this->request->getValues(); + + if (! $task) $this->notfound(); + $this->checkProjectPermissions($task['project_id']); + + list($valid, $errors) = $this->task->validateDescriptionCreation($values); + + if ($valid) { + + if ($this->task->update($values)) { + $this->session->flash(t('Task updated successfully.')); + } + else { + $this->session->flashError(t('Unable to update your task.')); + } + + $this->response->redirect('?controller=task&action=show&task_id='.$task['id']); + } + + $this->showTask( + $task, + array(), + array('values' => $values, 'errors' => $errors) + ); + } + + /** + * Display a form to create a new task + * + * @access public + */ + public function create() + { + $project_id = $this->request->getIntegerParam('project_id'); + $this->checkProjectPermissions($project_id); + + $this->response->html($this->template->layout('task_new', array( + 'errors' => array(), + 'values' => array( + 'project_id' => $project_id, + 'column_id' => $this->request->getIntegerParam('column_id'), + 'color_id' => $this->request->getStringParam('color_id'), + 'owner_id' => $this->request->getIntegerParam('owner_id'), + 'another_task' => $this->request->getIntegerParam('another_task'), + ), + 'projects_list' => $this->project->getListByStatus(\Model\Project::ACTIVE), + 'columns_list' => $this->board->getColumnsList($project_id), + 'users_list' => $this->project->getUsersList($project_id), + 'colors_list' => $this->task->getColors(), + 'categories_list' => $this->category->getList($project_id), + 'menu' => 'tasks', + 'title' => t('New task') + ))); + } + + /** + * Validate and save a new task + * + * @access public + */ + public function save() + { + $values = $this->request->getValues(); + $this->checkProjectPermissions($values['project_id']); + + list($valid, $errors) = $this->task->validateCreation($values); + + if ($valid) { + + if ($this->task->create($values)) { + $this->session->flash(t('Task created successfully.')); + + if (isset($values['another_task']) && $values['another_task'] == 1) { + unset($values['title']); + unset($values['description']); + $this->response->redirect('?controller=task&action=create&'.http_build_query($values)); + } + else { + $this->response->redirect('?controller=board&action=show&project_id='.$values['project_id']); + } + } + else { + $this->session->flashError(t('Unable to create your task.')); + } + } + + $this->response->html($this->template->layout('task_new', array( + 'errors' => $errors, + 'values' => $values, + 'projects_list' => $this->project->getListByStatus(Project::ACTIVE), + 'columns_list' => $this->board->getColumnsList($values['project_id']), + 'users_list' => $this->project->getUsersList($values['project_id']), + 'colors_list' => $this->task->getColors(), + 'categories_list' => $this->category->getList($values['project_id']), + 'menu' => 'tasks', + 'title' => t('New task') + ))); + } + + /** + * Display a form to edit a task + * + * @access public + */ + public function edit() + { + $task = $this->task->getById($this->request->getIntegerParam('task_id')); + + if (! $task) $this->notfound(); + $this->checkProjectPermissions($task['project_id']); + + if (! empty($task['date_due'])) { + $task['date_due'] = date(t('m/d/Y'), $task['date_due']); + } + else { + $task['date_due'] = ''; + } + + $task['score'] = $task['score'] ?: ''; + + $this->response->html($this->template->layout('task_edit', array( + 'errors' => array(), + 'values' => $task, + 'columns_list' => $this->board->getColumnsList($task['project_id']), + 'users_list' => $this->project->getUsersList($task['project_id']), + 'colors_list' => $this->task->getColors(), + 'categories_list' => $this->category->getList($task['project_id']), + 'menu' => 'tasks', + 'title' => t('Edit a task') + ))); + } + + /** + * Validate and update a task + * + * @access public + */ + public function update() + { + $values = $this->request->getValues(); + $this->checkProjectPermissions($values['project_id']); + + list($valid, $errors) = $this->task->validateModification($values); + + if ($valid) { + + if ($this->task->update($values)) { + $this->session->flash(t('Task updated successfully.')); + $this->response->redirect('?controller=task&action=show&task_id='.$values['id']); + } + else { + $this->session->flashError(t('Unable to update your task.')); + } + } + + $this->response->html($this->template->layout('task_edit', array( + 'errors' => $errors, + 'values' => $values, + 'columns_list' => $this->board->getColumnsList($values['project_id']), + 'users_list' => $this->project->getUsersList($values['project_id']), + 'colors_list' => $this->task->getColors(), + 'categories_list' => $this->category->getList($values['project_id']), + 'menu' => 'tasks', + 'title' => t('Edit a task') + ))); + } + + /** + * Hide a task + * + * @access public + */ + public function close() + { + $task = $this->task->getById($this->request->getIntegerParam('task_id')); + + if (! $task) $this->notfound(); + $this->checkProjectPermissions($task['project_id']); + + if ($this->task->close($task['id'])) { + $this->session->flash(t('Task closed successfully.')); + } else { + $this->session->flashError(t('Unable to close this task.')); + } + + $this->response->redirect('?controller=task&action=show&task_id='.$task['id']); + } + + /** + * Confirmation dialog before to close a task + * + * @access public + */ + public function confirmClose() + { + $task = $this->task->getById($this->request->getIntegerParam('task_id'), true); + + if (! $task) $this->notfound(); + $this->checkProjectPermissions($task['project_id']); + + $this->response->html($this->taskLayout('task_close', array( + 'task' => $task, + 'menu' => 'tasks', + 'title' => t('Close a task') + ))); + } + + /** + * Open a task + * + * @access public + */ + public function open() + { + $task = $this->task->getById($this->request->getIntegerParam('task_id')); + + if (! $task) $this->notfound(); + $this->checkProjectPermissions($task['project_id']); + + if ($this->task->open($task['id'])) { + $this->session->flash(t('Task opened successfully.')); + } else { + $this->session->flashError(t('Unable to open this task.')); + } + + $this->response->redirect('?controller=task&action=show&task_id='.$task['id']); + } + + /** + * Confirmation dialog before to open a task + * + * @access public + */ + public function confirmOpen() + { + $task = $this->task->getById($this->request->getIntegerParam('task_id'), true); + + if (! $task) $this->notfound(); + $this->checkProjectPermissions($task['project_id']); + + $this->response->html($this->taskLayout('task_open', array( + 'task' => $task, + 'menu' => 'tasks', + 'title' => t('Open a task') + ))); + } + + /** + * Remove a task + * + * @access public + */ + public function remove() + { + $task = $this->task->getById($this->request->getIntegerParam('task_id')); + + if (! $task) $this->notfound(); + $this->checkProjectPermissions($task['project_id']); + + if ($this->task->remove($task['id'])) { + $this->session->flash(t('Task removed successfully.')); + } else { + $this->session->flashError(t('Unable to remove this task.')); + } + + $this->response->redirect('?controller=board&action=show&project_id='.$task['project_id']); + } + + /** + * Confirmation dialog before removing a task + * + * @access public + */ + public function confirmRemove() + { + $task = $this->task->getById($this->request->getIntegerParam('task_id'), true); + + if (! $task) $this->notfound(); + $this->checkProjectPermissions($task['project_id']); + + $this->response->html($this->taskLayout('task_remove', array( + 'task' => $task, + 'menu' => 'tasks', + 'title' => t('Remove a task') + ))); + } + + /** + * Duplicate a task (fill the form for a new task) + * + * @access public + */ + public function duplicate() + { + $task = $this->task->getById($this->request->getIntegerParam('task_id')); + + if (! $task) $this->notfound(); + $this->checkProjectPermissions($task['project_id']); + + if (! empty($task['date_due'])) { + $task['date_due'] = date(t('m/d/Y'), $task['date_due']); + } + else { + $task['date_due'] = ''; + } + + $task['score'] = $task['score'] ?: ''; + + $this->response->html($this->template->layout('task_new', array( + 'errors' => array(), + 'values' => $task, + 'projects_list' => $this->project->getListByStatus(Project::ACTIVE), + 'columns_list' => $this->board->getColumnsList($task['project_id']), + 'users_list' => $this->project->getUsersList($task['project_id']), + 'colors_list' => $this->task->getColors(), + 'categories_list' => $this->category->getList($task['project_id']), + 'duplicate' => true, + 'menu' => 'tasks', + 'title' => t('New task') + ))); + } +} diff --git a/app/Controller/User.php b/app/Controller/User.php new file mode 100644 index 00000000..e3fd8253 --- /dev/null +++ b/app/Controller/User.php @@ -0,0 +1,310 @@ +<?php + +namespace Controller; + +/** + * User controller + * + * @package controller + * @author Frederic Guillot + */ +class User extends Base +{ + /** + * Display access forbidden page + * + * @access public + */ + public function forbidden() + { + $this->response->html($this->template->layout('user_forbidden', array( + 'menu' => 'users', + 'title' => t('Access Forbidden') + ))); + } + + /** + * Logout and destroy session + * + * @access public + */ + public function logout() + { + $this->rememberMe->destroy($this->acl->getUserId()); + $this->session->close(); + $this->response->redirect('?controller=user&action=login'); + } + + /** + * Display the form login + * + * @access public + */ + public function login() + { + if (isset($_SESSION['user'])) $this->response->redirect('?controller=app'); + + $this->response->html($this->template->layout('user_login', array( + 'errors' => array(), + 'values' => array(), + 'no_layout' => true, + 'title' => t('Login') + ))); + } + + /** + * Check credentials + * + * @access public + */ + public function check() + { + $values = $this->request->getValues(); + list($valid, $errors) = $this->user->validateLogin($values); + + if ($valid) { + $this->response->redirect('?controller=app'); + } + + $this->response->html($this->template->layout('user_login', array( + 'errors' => $errors, + 'values' => $values, + 'no_layout' => true, + 'title' => t('Login') + ))); + } + + /** + * List all users + * + * @access public + */ + public function index() + { + $users = $this->user->getAll(); + $nb_users = count($users); + + $this->response->html( + $this->template->layout('user_index', array( + 'projects' => $this->project->getList(), + 'users' => $users, + 'nb_users' => $nb_users, + 'menu' => 'users', + 'title' => t('Users').' ('.$nb_users.')' + ))); + } + + /** + * Display a form to create a new user + * + * @access public + */ + public function create() + { + $this->response->html($this->template->layout('user_new', array( + 'projects' => $this->project->getList(), + 'errors' => array(), + 'values' => array(), + 'menu' => 'users', + 'title' => t('New user') + ))); + } + + /** + * Validate and save a new user + * + * @access public + */ + public function save() + { + $values = $this->request->getValues(); + list($valid, $errors) = $this->user->validateCreation($values); + + if ($valid) { + + if ($this->user->create($values)) { + $this->session->flash(t('User created successfully.')); + $this->response->redirect('?controller=user'); + } + else { + $this->session->flashError(t('Unable to create your user.')); + } + } + + $this->response->html($this->template->layout('user_new', array( + 'projects' => $this->project->getList(), + 'errors' => $errors, + 'values' => $values, + 'menu' => 'users', + 'title' => t('New user') + ))); + } + + /** + * Display a form to edit a user + * + * @access public + */ + public function edit() + { + $user = $this->user->getById($this->request->getIntegerParam('user_id')); + + if (! $user) $this->notfound(); + + if ($this->acl->isRegularUser() && $this->acl->getUserId() != $user['id']) { + $this->forbidden(); + } + + unset($user['password']); + + $this->response->html($this->template->layout('user_edit', array( + 'projects' => $this->project->filterListByAccess($this->project->getList(), $user['id']), + 'errors' => array(), + 'values' => $user, + 'menu' => 'users', + 'title' => t('Edit user') + ))); + } + + /** + * Validate and update a user + * + * @access public + */ + public function update() + { + $values = $this->request->getValues(); + + if ($this->acl->isAdminUser()) { + $values += array('is_admin' => 0); + } + else { + + if ($this->acl->getUserId() != $values['id']) { + $this->forbidden(); + } + + if (isset($values['is_admin'])) { + unset($values['is_admin']); // Regular users can't be admin + } + } + + list($valid, $errors) = $this->user->validateModification($values); + + if ($valid) { + + if ($this->user->update($values)) { + $this->session->flash(t('User updated successfully.')); + $this->response->redirect('?controller=user'); + } + else { + $this->session->flashError(t('Unable to update your user.')); + } + } + + $this->response->html($this->template->layout('user_edit', array( + 'projects' => $this->project->filterListByAccess($this->project->getList(), $values['id']), + 'errors' => $errors, + 'values' => $values, + 'menu' => 'users', + 'title' => t('Edit user') + ))); + } + + /** + * Confirmation dialog before to remove a user + * + * @access public + */ + public function confirm() + { + $user = $this->user->getById($this->request->getIntegerParam('user_id')); + + if (! $user) $this->notfound(); + + $this->response->html($this->template->layout('user_remove', array( + 'user' => $user, + 'menu' => 'users', + 'title' => t('Remove user') + ))); + } + + /** + * Remove a user + * + * @access public + */ + public function remove() + { + $user_id = $this->request->getIntegerParam('user_id'); + + if ($user_id && $this->user->remove($user_id)) { + $this->session->flash(t('User removed successfully.')); + } else { + $this->session->flashError(t('Unable to remove this user.')); + } + + $this->response->redirect('?controller=user'); + } + + /** + * Google authentication + * + * @access public + */ + public function google() + { + $code = $this->request->getStringParam('code'); + + if ($code) { + + $profile = $this->google->getGoogleProfile($code); + + if (is_array($profile)) { + + // If the user is already logged, link the account otherwise authenticate + if ($this->acl->isLogged()) { + + if ($this->google->updateUser($this->acl->getUserId(), $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'); + } + else if ($this->google->authenticate($profile['id'])) { + $this->response->redirect('?controller=app'); + } + else { + $this->response->html($this->template->layout('user_login', array( + 'errors' => array('login' => t('Google authentication failed')), + 'values' => array(), + 'no_layout' => true, + 'title' => t('Login') + ))); + } + } + } + + $this->response->redirect($this->google->getAuthorizationUrl()); + } + + /** + * Unlink a Google account + * + * @access public + */ + public function unlinkGoogle() + { + if ($this->google->unlink($this->acl->getUserId())) { + $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'); + } +} |