diff options
Diffstat (limited to 'app/Controller')
| -rw-r--r-- | app/Controller/ActionController.php (renamed from app/Controller/Action.php) | 28 | ||||
| -rw-r--r-- | app/Controller/ActionCreationController.php (renamed from app/Controller/ActionCreation.php) | 23 | ||||
| -rw-r--r-- | app/Controller/ActivityController.php (renamed from app/Controller/Activity.php) | 8 | ||||
| -rw-r--r-- | app/Controller/AnalyticController.php (renamed from app/Controller/Analytic.php) | 20 | ||||
| -rw-r--r-- | app/Controller/AppController.php | 46 | ||||
| -rw-r--r-- | app/Controller/AuthController.php (renamed from app/Controller/Auth.php) | 36 | ||||
| -rw-r--r-- | app/Controller/AvatarFileController.php (renamed from app/Controller/AvatarFile.php) | 20 | ||||
| -rw-r--r-- | app/Controller/Base.php | 290 | ||||
| -rw-r--r-- | app/Controller/BaseController.php | 158 | ||||
| -rw-r--r-- | app/Controller/Board.php | 192 | ||||
| -rw-r--r-- | app/Controller/BoardAjaxController.php | 140 | ||||
| -rw-r--r-- | app/Controller/BoardPopover.php | 135 | ||||
| -rw-r--r-- | app/Controller/BoardPopoverController.php | 47 | ||||
| -rw-r--r-- | app/Controller/BoardTooltipController.php (renamed from app/Controller/BoardTooltip.php) | 22 | ||||
| -rw-r--r-- | app/Controller/BoardViewController.php | 65 | ||||
| -rw-r--r-- | app/Controller/CalendarController.php (renamed from app/Controller/Calendar.php) | 14 | ||||
| -rw-r--r-- | app/Controller/CaptchaController.php (renamed from app/Controller/Captcha.php) | 6 | ||||
| -rw-r--r-- | app/Controller/CategoryController.php (renamed from app/Controller/Category.php) | 47 | ||||
| -rw-r--r-- | app/Controller/ColumnController.php (renamed from app/Controller/Column.php) | 41 | ||||
| -rw-r--r-- | app/Controller/CommentController.php (renamed from app/Controller/Comment.php) | 43 | ||||
| -rw-r--r-- | app/Controller/ConfigController.php (renamed from app/Controller/Config.php) | 122 | ||||
| -rw-r--r-- | app/Controller/CurrencyController.php (renamed from app/Controller/Currency.php) | 25 | ||||
| -rw-r--r-- | app/Controller/CustomFilterController.php (renamed from app/Controller/Customfilter.php) | 45 | ||||
| -rw-r--r-- | app/Controller/DashboardController.php (renamed from app/Controller/App.php) | 58 | ||||
| -rw-r--r-- | app/Controller/DocumentationController.php (renamed from app/Controller/Doc.php) | 10 | ||||
| -rw-r--r-- | app/Controller/ExportController.php (renamed from app/Controller/Export.php) | 18 | ||||
| -rw-r--r-- | app/Controller/FeedController.php (renamed from app/Controller/Feed.php) | 17 | ||||
| -rw-r--r-- | app/Controller/FileViewerController.php (renamed from app/Controller/FileViewer.php) | 56 | ||||
| -rw-r--r-- | app/Controller/Gantt.php | 162 | ||||
| -rw-r--r-- | app/Controller/Group.php | 250 | ||||
| -rw-r--r-- | app/Controller/GroupAjaxController.php (renamed from app/Controller/GroupHelper.php) | 8 | ||||
| -rw-r--r-- | app/Controller/GroupCreationController.php | 49 | ||||
| -rw-r--r-- | app/Controller/GroupListController.php | 173 | ||||
| -rw-r--r-- | app/Controller/GroupModificationController.php | 53 | ||||
| -rw-r--r-- | app/Controller/ICalendarController.php (renamed from app/Controller/Ical.php) | 23 | ||||
| -rw-r--r-- | app/Controller/LinkController.php (renamed from app/Controller/Link.php) | 38 | ||||
| -rw-r--r-- | app/Controller/OAuthController.php (renamed from app/Controller/Oauth.php) | 14 | ||||
| -rw-r--r-- | app/Controller/PasswordResetController.php (renamed from app/Controller/PasswordReset.php) | 36 | ||||
| -rw-r--r-- | app/Controller/PluginController.php | 126 | ||||
| -rw-r--r-- | app/Controller/Project.php | 243 | ||||
| -rw-r--r-- | app/Controller/ProjectActionDuplicationController.php (renamed from app/Controller/ActionProject.php) | 14 | ||||
| -rw-r--r-- | app/Controller/ProjectCreationController.php (renamed from app/Controller/ProjectCreation.php) | 20 | ||||
| -rw-r--r-- | app/Controller/ProjectEditController.php (renamed from app/Controller/ProjectEdit.php) | 26 | ||||
| -rw-r--r-- | app/Controller/ProjectFileController.php (renamed from app/Controller/ProjectFile.php) | 16 | ||||
| -rw-r--r-- | app/Controller/ProjectGanttController.php | 57 | ||||
| -rw-r--r-- | app/Controller/ProjectListController.php | 41 | ||||
| -rw-r--r-- | app/Controller/ProjectOverviewController.php (renamed from app/Controller/ProjectOverview.php) | 12 | ||||
| -rw-r--r-- | app/Controller/ProjectPermissionController.php (renamed from app/Controller/ProjectPermission.php) | 43 | ||||
| -rw-r--r-- | app/Controller/ProjectStatusController.php | 102 | ||||
| -rw-r--r-- | app/Controller/ProjectUserOverviewController.php (renamed from app/Controller/Projectuser.php) | 32 | ||||
| -rw-r--r-- | app/Controller/ProjectViewController.php | 162 | ||||
| -rw-r--r-- | app/Controller/SearchController.php (renamed from app/Controller/Search.php) | 14 | ||||
| -rw-r--r-- | app/Controller/SubtaskController.php (renamed from app/Controller/Subtask.php) | 49 | ||||
| -rw-r--r-- | app/Controller/SubtaskConverterController.php | 39 | ||||
| -rw-r--r-- | app/Controller/SubtaskRestrictionController.php (renamed from app/Controller/SubtaskRestriction.php) | 20 | ||||
| -rw-r--r-- | app/Controller/SubtaskStatusController.php (renamed from app/Controller/SubtaskStatus.php) | 15 | ||||
| -rw-r--r-- | app/Controller/SwimlaneController.php (renamed from app/Controller/Swimlane.php) | 86 | ||||
| -rw-r--r-- | app/Controller/Task.php | 174 | ||||
| -rw-r--r-- | app/Controller/TaskAjaxController.php (renamed from app/Controller/TaskHelper.php) | 8 | ||||
| -rw-r--r-- | app/Controller/TaskBulkController.php | 89 | ||||
| -rw-r--r-- | app/Controller/TaskCreationController.php (renamed from app/Controller/Taskcreation.php) | 33 | ||||
| -rw-r--r-- | app/Controller/TaskDuplicationController.php (renamed from app/Controller/Taskduplication.php) | 36 | ||||
| -rw-r--r-- | app/Controller/TaskExternalLinkController.php (renamed from app/Controller/TaskExternalLink.php) | 45 | ||||
| -rw-r--r-- | app/Controller/TaskFileController.php (renamed from app/Controller/TaskFile.php) | 22 | ||||
| -rw-r--r-- | app/Controller/TaskGanttController.php | 62 | ||||
| -rw-r--r-- | app/Controller/TaskGanttCreationController.php | 71 | ||||
| -rw-r--r-- | app/Controller/TaskImport.php | 72 | ||||
| -rw-r--r-- | app/Controller/TaskImportController.php | 74 | ||||
| -rw-r--r-- | app/Controller/TaskInternalLinkController.php (renamed from app/Controller/TaskInternalLink.php) | 41 | ||||
| -rw-r--r-- | app/Controller/TaskListController.php (renamed from app/Controller/Listing.php) | 12 | ||||
| -rw-r--r-- | app/Controller/TaskModificationController.php (renamed from app/Controller/Taskmodification.php) | 38 | ||||
| -rw-r--r-- | app/Controller/TaskPopoverController.php | 100 | ||||
| -rw-r--r-- | app/Controller/TaskRecurrenceController.php (renamed from app/Controller/TaskRecurrence.php) | 22 | ||||
| -rw-r--r-- | app/Controller/TaskStatusController.php (renamed from app/Controller/Taskstatus.php) | 10 | ||||
| -rw-r--r-- | app/Controller/TaskSuppressionController.php | 53 | ||||
| -rw-r--r-- | app/Controller/TaskViewController.php | 146 | ||||
| -rw-r--r-- | app/Controller/TwoFactorController.php (renamed from app/Controller/Twofactor.php) | 30 | ||||
| -rw-r--r-- | app/Controller/User.php | 408 | ||||
| -rw-r--r-- | app/Controller/UserAjaxController.php (renamed from app/Controller/UserHelper.php) | 20 | ||||
| -rw-r--r-- | app/Controller/UserCreationController.php | 83 | ||||
| -rw-r--r-- | app/Controller/UserCredentialController.php | 109 | ||||
| -rw-r--r-- | app/Controller/UserImportController.php (renamed from app/Controller/UserImport.php) | 51 | ||||
| -rw-r--r-- | app/Controller/UserListController.php | 32 | ||||
| -rw-r--r-- | app/Controller/UserModificationController.php | 69 | ||||
| -rw-r--r-- | app/Controller/UserStatusController.php (renamed from app/Controller/UserStatus.php) | 16 | ||||
| -rw-r--r-- | app/Controller/UserViewController.php | 217 | ||||
| -rw-r--r-- | app/Controller/WebNotification.php | 50 | ||||
| -rw-r--r-- | app/Controller/WebNotificationController.php | 79 | ||||
| -rw-r--r-- | app/Controller/Webhook.php | 42 |
89 files changed, 3257 insertions, 2712 deletions
diff --git a/app/Controller/Action.php b/app/Controller/ActionController.php index 8881e8ec..097640f6 100644 --- a/app/Controller/Action.php +++ b/app/Controller/ActionController.php @@ -3,12 +3,12 @@ namespace Kanboard\Controller; /** - * Automatic Actions + * Automatic Actions Controller * - * @package controller + * @package Kanboard\Controller * @author Frederic Guillot */ -class Action extends Base +class ActionController extends BaseController { /** * List of automatic actions for a given project @@ -18,7 +18,7 @@ class Action extends Base public function index() { $project = $this->getProject(); - $actions = $this->action->getAllByProject($project['id']); + $actions = $this->actionModel->getAllByProject($project['id']); $this->response->html($this->helper->layout->project('action/index', array( 'values' => array('project_id' => $project['id']), @@ -27,12 +27,12 @@ class Action extends Base 'available_actions' => $this->actionManager->getAvailableActions(), 'available_events' => $this->eventManager->getAll(), 'available_params' => $this->actionManager->getAvailableParameters($actions), - 'columns_list' => $this->column->getList($project['id']), - 'users_list' => $this->projectUserRole->getAssignableUsersList($project['id']), - 'projects_list' => $this->projectUserRole->getProjectsByUser($this->userSession->getId()), - 'colors_list' => $this->color->getList(), - 'categories_list' => $this->category->getList($project['id']), - 'links_list' => $this->link->getList(0, false), + 'columns_list' => $this->columnModel->getList($project['id']), + 'users_list' => $this->projectUserRoleModel->getAssignableUsersList($project['id']), + 'projects_list' => $this->projectUserRoleModel->getProjectsByUser($this->userSession->getId()), + 'colors_list' => $this->colorModel->getList(), + 'categories_list' => $this->categoryModel->getList($project['id']), + 'links_list' => $this->linkModel->getList(0, false), 'title' => t('Automatic actions') ))); } @@ -47,7 +47,7 @@ class Action extends Base $project = $this->getProject(); $this->response->html($this->helper->layout->project('action/remove', array( - 'action' => $this->action->getById($this->request->getIntegerParam('action_id')), + 'action' => $this->actionModel->getById($this->request->getIntegerParam('action_id')), 'available_events' => $this->eventManager->getAll(), 'available_actions' => $this->actionManager->getAvailableActions(), 'project' => $project, @@ -64,14 +64,14 @@ class Action extends Base { $this->checkCSRFParam(); $project = $this->getProject(); - $action = $this->action->getById($this->request->getIntegerParam('action_id')); + $action = $this->actionModel->getById($this->request->getIntegerParam('action_id')); - if (! empty($action) && $this->action->remove($action['id'])) { + if (! empty($action) && $this->actionModel->remove($action['id'])) { $this->flash->success(t('Action removed successfully.')); } else { $this->flash->failure(t('Unable to remove this action.')); } - $this->response->redirect($this->helper->url->to('action', 'index', array('project_id' => $project['id']))); + $this->response->redirect($this->helper->url->to('ActionController', 'index', array('project_id' => $project['id']))); } } diff --git a/app/Controller/ActionCreation.php b/app/Controller/ActionCreationController.php index 24a12d92..e984f8d4 100644 --- a/app/Controller/ActionCreation.php +++ b/app/Controller/ActionCreationController.php @@ -3,12 +3,12 @@ namespace Kanboard\Controller; /** - * Action Creation + * Action Creation Controller * - * @package controller + * @package Kanboard\Controller * @author Frederic Guillot */ -class ActionCreation extends Base +class ActionCreationController extends BaseController { /** * Show the form (step 1) @@ -69,18 +69,19 @@ class ActionCreation extends Base $this->doCreation($project, $values + array('params' => array())); } - $projects_list = $this->projectUserRole->getActiveProjectsByUser($this->userSession->getId()); + $projects_list = $this->projectUserRoleModel->getActiveProjectsByUser($this->userSession->getId()); unset($projects_list[$project['id']]); $this->response->html($this->template->render('action_creation/params', array( 'values' => $values, 'action_params' => $action_params, - 'columns_list' => $this->column->getList($project['id']), - 'users_list' => $this->projectUserRole->getAssignableUsersList($project['id']), + 'columns_list' => $this->columnModel->getList($project['id']), + 'users_list' => $this->projectUserRoleModel->getAssignableUsersList($project['id']), 'projects_list' => $projects_list, - 'colors_list' => $this->color->getList(), - 'categories_list' => $this->category->getList($project['id']), - 'links_list' => $this->link->getList(0, false), + 'colors_list' => $this->colorModel->getList(), + 'categories_list' => $this->categoryModel->getList($project['id']), + 'links_list' => $this->linkModel->getList(0, false), + 'priorities_list' => $this->projectModel->getPriorities($project), 'project' => $project, 'available_actions' => $this->actionManager->getAvailableActions(), 'events' => $this->actionManager->getCompatibleEvents($values['action_name']), @@ -109,13 +110,13 @@ class ActionCreation extends Base list($valid, ) = $this->actionValidator->validateCreation($values); if ($valid) { - if ($this->action->create($values) !== false) { + if ($this->actionModel->create($values) !== false) { $this->flash->success(t('Your automatic action have been created successfully.')); } else { $this->flash->failure(t('Unable to create your automatic action.')); } } - $this->response->redirect($this->helper->url->to('action', 'index', array('project_id' => $project['id']))); + $this->response->redirect($this->helper->url->to('ActionController', 'index', array('project_id' => $project['id']))); } } diff --git a/app/Controller/Activity.php b/app/Controller/ActivityController.php index 47a66e0a..9f9841af 100644 --- a/app/Controller/Activity.php +++ b/app/Controller/ActivityController.php @@ -3,12 +3,12 @@ namespace Kanboard\Controller; /** - * Activity stream + * Activity Controller * - * @package controller + * @package Kanboard\Controller * @author Frederic Guillot */ -class Activity extends Base +class ActivityController extends BaseController { /** * Activity page for a project @@ -38,7 +38,7 @@ class Activity extends Base $this->response->html($this->helper->layout->task('activity/task', array( 'title' => $task['title'], 'task' => $task, - 'project' => $this->project->getById($task['project_id']), + 'project' => $this->projectModel->getById($task['project_id']), 'events' => $this->helper->projectActivity->getTaskEvents($task['id']), ))); } diff --git a/app/Controller/Analytic.php b/app/Controller/AnalyticController.php index 35bc3048..cf3ba034 100644 --- a/app/Controller/Analytic.php +++ b/app/Controller/AnalyticController.php @@ -3,15 +3,15 @@ namespace Kanboard\Controller; use Kanboard\Filter\TaskProjectFilter; -use Kanboard\Model\Task as TaskModel; +use Kanboard\Model\TaskModel; /** - * Project Analytic controller + * Project Analytic Controller * - * @package controller + * @package Kanboard\Controller * @author Frederic Guillot */ -class Analytic extends Base +class AnalyticController extends BaseController { /** * Show average Lead and Cycle time @@ -30,8 +30,8 @@ class Analytic extends Base ), 'project' => $project, 'average' => $this->averageLeadCycleTimeAnalytic->build($project['id']), - 'metrics' => $this->projectDailyStats->getRawMetrics($project['id'], $from, $to), - 'date_format' => $this->config->get('application_date_format'), + 'metrics' => $this->projectDailyStatsModel->getRawMetrics($project['id'], $from, $to), + 'date_format' => $this->configModel->get('application_date_format'), 'date_formats' => $this->dateParser->getAvailableFormats($this->dateParser->getDateFormats()), 'title' => t('Lead and Cycle time for "%s"', $project['name']), ))); @@ -47,7 +47,7 @@ class Analytic extends Base $project = $this->getProject(); $paginator = $this->paginator - ->setUrl('analytic', 'compareHours', array('project_id' => $project['id'])) + ->setUrl('AnalyticController', 'compareHours', array('project_id' => $project['id'])) ->setMax(30) ->setOrder(TaskModel::TABLE.'.id') ->setQuery($this->taskQuery @@ -145,7 +145,7 @@ class Analytic extends Base $project = $this->getProject(); list($from, $to) = $this->getDates(); - $display_graph = $this->projectDailyColumnStats->countDays($project['id'], $from, $to) >= 2; + $display_graph = $this->projectDailyColumnStatsModel->countDays($project['id'], $from, $to) >= 2; $this->response->html($this->helper->layout->analytic($template, array( 'values' => array( @@ -153,9 +153,9 @@ class Analytic extends Base 'to' => $to, ), 'display_graph' => $display_graph, - 'metrics' => $display_graph ? $this->projectDailyColumnStats->getAggregatedMetrics($project['id'], $from, $to, $column) : array(), + 'metrics' => $display_graph ? $this->projectDailyColumnStatsModel->getAggregatedMetrics($project['id'], $from, $to, $column) : array(), 'project' => $project, - 'date_format' => $this->config->get('application_date_format'), + 'date_format' => $this->configModel->get('application_date_format'), 'date_formats' => $this->dateParser->getAvailableFormats($this->dateParser->getDateFormats()), 'title' => t($title, $project['name']), ))); diff --git a/app/Controller/AppController.php b/app/Controller/AppController.php new file mode 100644 index 00000000..45cf39a5 --- /dev/null +++ b/app/Controller/AppController.php @@ -0,0 +1,46 @@ +<?php + +namespace Kanboard\Controller; + +use Kanboard\Core\Base; + +/** + * Class AppController + * + * @package Kanboard\Controller + * @author Frederic Guillot + */ +class AppController extends Base +{ + /** + * Forbidden page + * + * @access public + * @param bool $withoutLayout + */ + public function accessForbidden($withoutLayout = false) + { + if ($this->request->isAjax()) { + $this->response->json(array('message' => 'Access Forbidden'), 403); + } + + $this->response->html($this->helper->layout->app('app/forbidden', array( + 'title' => t('Access Forbidden'), + 'no_layout' => $withoutLayout, + ))); + } + + /** + * Page not found + * + * @access public + * @param boolean $withoutLayout + */ + public function notFound($withoutLayout = false) + { + $this->response->html($this->helper->layout->app('app/notfound', array( + 'title' => t('Page not found'), + 'no_layout' => $withoutLayout, + ))); + } +} diff --git a/app/Controller/Auth.php b/app/Controller/AuthController.php index b882a720..dc46070c 100644 --- a/app/Controller/Auth.php +++ b/app/Controller/AuthController.php @@ -3,12 +3,12 @@ namespace Kanboard\Controller; /** - * Authentication controller + * Authentication Controller * - * @package controller + * @package Kanboard\Controller * @author Frederic Guillot */ -class Auth extends Base +class AuthController extends BaseController { /** * Display the form login @@ -20,16 +20,16 @@ class Auth extends Base public function login(array $values = array(), array $errors = array()) { if ($this->userSession->isLogged()) { - $this->response->redirect($this->helper->url->to('app', 'index')); + $this->response->redirect($this->helper->url->to('DashboardController', 'show')); + } else { + $this->response->html($this->helper->layout->app('auth/index', array( + 'captcha' => ! empty($values['username']) && $this->userLockingModel->hasCaptcha($values['username']), + 'errors' => $errors, + 'values' => $values, + 'no_layout' => true, + 'title' => t('Login') + ))); } - - $this->response->html($this->helper->layout->app('auth/index', array( - 'captcha' => ! empty($values['username']) && $this->userLocking->hasCaptcha($values['username']), - 'errors' => $errors, - 'values' => $values, - 'no_layout' => true, - 'title' => t('Login') - ))); } /** @@ -45,9 +45,9 @@ class Auth extends Base if ($valid) { $this->redirectAfterLogin(); + } else { + $this->login($values, $errors); } - - $this->login($values, $errors); } /** @@ -59,9 +59,9 @@ class Auth extends Base { if (! DISABLE_LOGOUT) { $this->sessionManager->close(); - $this->response->redirect($this->helper->url->to('auth', 'login')); + $this->response->redirect($this->helper->url->to('AuthController', 'login')); } else { - $this->response->redirect($this->helper->url->to('auth', 'index')); + $this->response->redirect($this->helper->url->to('AuthController', 'index')); } } @@ -76,8 +76,8 @@ class Auth extends Base $redirect = $this->sessionStorage->redirectAfterLogin; unset($this->sessionStorage->redirectAfterLogin); $this->response->redirect($redirect); + } else { + $this->response->redirect($this->helper->url->to('DashboardController', 'show')); } - - $this->response->redirect($this->helper->url->to('app', 'index')); } } diff --git a/app/Controller/AvatarFile.php b/app/Controller/AvatarFileController.php index a47cca66..6879c577 100644 --- a/app/Controller/AvatarFile.php +++ b/app/Controller/AvatarFileController.php @@ -8,10 +8,10 @@ use Kanboard\Core\Thumbnail; /** * Avatar File Controller * - * @package controller + * @package Kanboard\Controller * @author Frederic Guillot */ -class AvatarFile extends Base +class AvatarFileController extends BaseController { /** * Display avatar page @@ -32,11 +32,11 @@ class AvatarFile extends Base { $user = $this->getUser(); - if (! $this->avatarFile->uploadFile($user['id'], $this->request->getFileInfo('avatar'))) { + if (! $this->avatarFileModel->uploadImageFile($user['id'], $this->request->getFileInfo('avatar'))) { $this->flash->failure(t('Unable to upload the file.')); } - $this->response->redirect($this->helper->url->to('AvatarFile', 'show', array('user_id' => $user['id']))); + $this->response->redirect($this->helper->url->to('AvatarFileController', 'show', array('user_id' => $user['id']))); } /** @@ -46,8 +46,9 @@ class AvatarFile extends Base { $this->checkCSRFParam(); $user = $this->getUser(); - $this->avatarFile->remove($user['id']); - $this->response->redirect($this->helper->url->to('AvatarFile', 'show', array('user_id' => $user['id']))); + $this->avatarFileModel->remove($user['id']); + $this->userSession->refresh($user['id']); + $this->response->redirect($this->helper->url->to('AvatarFileController', 'show', array('user_id' => $user['id']))); } /** @@ -57,13 +58,14 @@ class AvatarFile extends Base { $user_id = $this->request->getIntegerParam('user_id'); $size = $this->request->getStringParam('size', 48); - $filename = $this->avatarFile->getFilename($user_id); + $filename = $this->avatarFileModel->getFilename($user_id); $etag = md5($filename.$size); - $this->response->cache(365 * 86400, $etag); - $this->response->contentType('image/jpeg'); + $this->response->withCache(365 * 86400, $etag); + $this->response->withContentType('image/jpeg'); if ($this->request->getHeader('If-None-Match') !== '"'.$etag.'"') { + $this->response->send(); $this->render($filename, $size); } else { $this->response->status(304); diff --git a/app/Controller/Base.php b/app/Controller/Base.php deleted file mode 100644 index beb56909..00000000 --- a/app/Controller/Base.php +++ /dev/null @@ -1,290 +0,0 @@ -<?php - -namespace Kanboard\Controller; - -use Kanboard\Core\Security\Role; - -/** - * Base controller - * - * @package controller - * @author Frederic Guillot - */ -abstract class Base extends \Kanboard\Core\Base -{ - /** - * Method executed before each action - * - * @access public - */ - public function beforeAction() - { - $this->sessionManager->open(); - $this->dispatcher->dispatch('app.bootstrap'); - $this->sendHeaders(); - $this->authenticationManager->checkCurrentSession(); - - if (! $this->applicationAuthorization->isAllowed($this->router->getController(), $this->router->getAction(), Role::APP_PUBLIC)) { - $this->handleAuthentication(); - $this->handlePostAuthentication(); - $this->checkApplicationAuthorization(); - $this->checkProjectAuthorization(); - } - } - - /** - * Send HTTP headers - * - * @access private - */ - private function sendHeaders() - { - // HTTP secure headers - $this->response->csp($this->container['cspRules']); - $this->response->nosniff(); - $this->response->xss(); - - // Allow the public board iframe inclusion - if (ENABLE_XFRAME && $this->router->getAction() !== 'readonly') { - $this->response->xframe(); - } - - if (ENABLE_HSTS) { - $this->response->hsts(); - } - } - - /** - * Check authentication - * - * @access private - */ - private function handleAuthentication() - { - if (! $this->userSession->isLogged() && ! $this->authenticationManager->preAuthentication()) { - if ($this->request->isAjax()) { - $this->response->text('Not Authorized', 401); - } - - $this->sessionStorage->redirectAfterLogin = $this->request->getUri(); - $this->response->redirect($this->helper->url->to('auth', 'login')); - } - } - - /** - * Handle Post-Authentication (2FA) - * - * @access private - */ - private function handlePostAuthentication() - { - $controller = strtolower($this->router->getController()); - $action = strtolower($this->router->getAction()); - $ignore = ($controller === 'twofactor' && in_array($action, array('code', 'check'))) || ($controller === 'auth' && $action === 'logout'); - - if ($ignore === false && $this->userSession->hasPostAuthentication() && ! $this->userSession->isPostAuthenticationValidated()) { - if ($this->request->isAjax()) { - $this->response->text('Not Authorized', 401); - } - - $this->response->redirect($this->helper->url->to('twofactor', 'code')); - } - } - - /** - * Check application authorization - * - * @access private - */ - private function checkApplicationAuthorization() - { - if (! $this->helper->user->hasAccess($this->router->getController(), $this->router->getAction())) { - $this->forbidden(); - } - } - - /** - * Check project authorization - * - * @access private - */ - private function checkProjectAuthorization() - { - $project_id = $this->request->getIntegerParam('project_id'); - $task_id = $this->request->getIntegerParam('task_id'); - - // Allow urls without "project_id" - if ($task_id > 0 && $project_id === 0) { - $project_id = $this->taskFinder->getProjectId($task_id); - } - - if ($project_id > 0 && ! $this->helper->user->hasProjectAccess($this->router->getController(), $this->router->getAction(), $project_id)) { - $this->forbidden(); - } - } - - /** - * Application not found page (404 error) - * - * @access protected - * @param boolean $no_layout Display the layout or not - */ - protected function notfound($no_layout = false) - { - $this->response->html($this->helper->layout->app('app/notfound', array( - 'title' => t('Page not found'), - 'no_layout' => $no_layout, - ))); - } - - /** - * Application forbidden page - * - * @access protected - * @param boolean $no_layout Display the layout or not - */ - protected function forbidden($no_layout = false) - { - if ($this->request->isAjax()) { - $this->response->text('Access Forbidden', 403); - } - - $this->response->html($this->helper->layout->app('app/forbidden', array( - 'title' => t('Access Forbidden'), - 'no_layout' => $no_layout, - ))); - } - - /** - * Check if the CSRF token from the URL is correct - * - * @access protected - */ - protected function checkCSRFParam() - { - if (! $this->token->validateCSRFToken($this->request->getStringParam('csrf_token'))) { - $this->forbidden(); - } - } - - /** - * Check webhook token - * - * @access protected - */ - protected function checkWebhookToken() - { - if ($this->config->get('webhook_token') !== $this->request->getStringParam('token')) { - $this->response->text('Not Authorized', 401); - } - } - - /** - * Common method to get a task for task views - * - * @access protected - * @return array - */ - protected function getTask() - { - $project_id = $this->request->getIntegerParam('project_id'); - $task = $this->taskFinder->getDetails($this->request->getIntegerParam('task_id')); - - if (empty($task)) { - $this->notfound(); - } - - if ($project_id !== 0 && $project_id != $task['project_id']) { - $this->forbidden(); - } - - return $task; - } - - /** - * Get Task or Project file - * - * @access protected - */ - protected function getFile() - { - $task_id = $this->request->getIntegerParam('task_id'); - $file_id = $this->request->getIntegerParam('file_id'); - $model = 'projectFile'; - - if ($task_id > 0) { - $model = 'taskFile'; - $project_id = $this->taskFinder->getProjectId($task_id); - - if ($project_id !== $this->request->getIntegerParam('project_id')) { - $this->forbidden(); - } - } - - $file = $this->$model->getById($file_id); - - if (empty($file)) { - $this->notfound(); - } - - $file['model'] = $model; - return $file; - } - - /** - * Common method to get a project - * - * @access protected - * @param integer $project_id Default project id - * @return array - */ - protected function getProject($project_id = 0) - { - $project_id = $this->request->getIntegerParam('project_id', $project_id); - $project = $this->project->getByIdWithOwner($project_id); - - if (empty($project)) { - $this->notfound(); - } - - return $project; - } - - /** - * Common method to get the user - * - * @access protected - * @return array - */ - protected function getUser() - { - $user = $this->user->getById($this->request->getIntegerParam('user_id', $this->userSession->getId())); - - if (empty($user)) { - $this->notfound(); - } - - if (! $this->userSession->isAdmin() && $this->userSession->getId() != $user['id']) { - $this->forbidden(); - } - - return $user; - } - - /** - * Get the current subtask - * - * @access protected - * @return array - */ - protected function getSubtask() - { - $subtask = $this->subtask->getById($this->request->getIntegerParam('subtask_id')); - - if (empty($subtask)) { - $this->notfound(); - } - - return $subtask; - } -} diff --git a/app/Controller/BaseController.php b/app/Controller/BaseController.php new file mode 100644 index 00000000..ae2dc006 --- /dev/null +++ b/app/Controller/BaseController.php @@ -0,0 +1,158 @@ +<?php + +namespace Kanboard\Controller; + +use Kanboard\Core\Base; +use Kanboard\Core\Controller\AccessForbiddenException; +use Kanboard\Core\Controller\PageNotFoundException; + +/** + * Base Controller + * + * @package Kanboard\Controller + * @author Frederic Guillot + */ +abstract class BaseController extends Base +{ + /** + * Check if the CSRF token from the URL is correct + * + * @access protected + */ + protected function checkCSRFParam() + { + if (! $this->token->validateCSRFToken($this->request->getStringParam('csrf_token'))) { + throw new AccessForbiddenException(); + } + } + + /** + * Check webhook token + * + * @access protected + */ + protected function checkWebhookToken() + { + if ($this->configModel->get('webhook_token') !== $this->request->getStringParam('token')) { + throw AccessForbiddenException::getInstance()->withoutLayout(); + } + } + + /** + * Common method to get a task for task views + * + * @access protected + * @return array + * @throws PageNotFoundException + * @throws AccessForbiddenException + */ + protected function getTask() + { + $project_id = $this->request->getIntegerParam('project_id'); + $task = $this->taskFinderModel->getDetails($this->request->getIntegerParam('task_id')); + + if (empty($task)) { + throw new PageNotFoundException(); + } + + if ($project_id !== 0 && $project_id != $task['project_id']) { + throw new AccessForbiddenException(); + } + + return $task; + } + + /** + * Get Task or Project file + * + * @access protected + * @return array + * @throws PageNotFoundException + * @throws AccessForbiddenException + */ + protected function getFile() + { + $task_id = $this->request->getIntegerParam('task_id'); + $file_id = $this->request->getIntegerParam('file_id'); + $model = 'projectFile'; + + if ($task_id > 0) { + $model = 'taskFileModel'; + $project_id = $this->taskFinderModel->getProjectId($task_id); + + if ($project_id !== $this->request->getIntegerParam('project_id')) { + throw new AccessForbiddenException(); + } + } + + $file = $this->$model->getById($file_id); + + if (empty($file)) { + throw new PageNotFoundException(); + } + + $file['model'] = $model; + return $file; + } + + /** + * Common method to get a project + * + * @access protected + * @param integer $project_id Default project id + * @return array + * @throws PageNotFoundException + */ + protected function getProject($project_id = 0) + { + $project_id = $this->request->getIntegerParam('project_id', $project_id); + $project = $this->projectModel->getByIdWithOwner($project_id); + + if (empty($project)) { + throw new PageNotFoundException(); + } + + return $project; + } + + /** + * Common method to get the user + * + * @access protected + * @return array + * @throws PageNotFoundException + * @throws AccessForbiddenException + */ + protected function getUser() + { + $user = $this->userModel->getById($this->request->getIntegerParam('user_id', $this->userSession->getId())); + + if (empty($user)) { + throw new PageNotFoundException(); + } + + if (! $this->userSession->isAdmin() && $this->userSession->getId() != $user['id']) { + throw new AccessForbiddenException(); + } + + return $user; + } + + /** + * Get the current subtask + * + * @access protected + * @return array + * @throws PageNotFoundException + */ + protected function getSubtask() + { + $subtask = $this->subtaskModel->getById($this->request->getIntegerParam('subtask_id')); + + if (empty($subtask)) { + throw new PageNotFoundException(); + } + + return $subtask; + } +} diff --git a/app/Controller/Board.php b/app/Controller/Board.php deleted file mode 100644 index 67e99b81..00000000 --- a/app/Controller/Board.php +++ /dev/null @@ -1,192 +0,0 @@ -<?php - -namespace Kanboard\Controller; - -use Kanboard\Formatter\BoardFormatter; - -/** - * Board controller - * - * @package controller - * @author Frederic Guillot - */ -class Board extends Base -{ - /** - * 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 (empty($project)) { - $this->forbidden(true); - } - - // Display the board with a specific layout - $this->response->html($this->helper->layout->app('board/view_public', array( - 'project' => $project, - 'swimlanes' => $this->board->getBoard($project['id']), - 'title' => $project['name'], - 'description' => $project['description'], - 'no_layout' => true, - 'not_editable' => true, - 'board_public_refresh_interval' => $this->config->get('board_public_refresh_interval'), - 'board_private_refresh_interval' => $this->config->get('board_private_refresh_interval'), - 'board_highlight_period' => $this->config->get('board_highlight_period'), - ))); - } - - /** - * Show a board for a given project - * - * @access public - */ - public function show() - { - $project = $this->getProject(); - $search = $this->helper->projectHeader->getSearchQuery($project); - - $this->response->html($this->helper->layout->app('board/view_private', array( - 'project' => $project, - 'title' => $project['name'], - 'description' => $this->helper->projectHeader->getDescription($project), - 'board_private_refresh_interval' => $this->config->get('board_private_refresh_interval'), - 'board_highlight_period' => $this->config->get('board_highlight_period'), - 'swimlanes' => $this->taskLexer - ->build($search) - ->format(BoardFormatter::getInstance($this->container)->setProjectId($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'); - - if (! $project_id || ! $this->request->isAjax()) { - return $this->response->status(403); - } - - $values = $this->request->getJson(); - - $result =$this->taskPosition->movePosition( - $project_id, - $values['task_id'], - $values['column_id'], - $values['position'], - $values['swimlane_id'] - ); - - if (! $result) { - return $this->response->status(400); - } - - $this->response->html($this->renderBoard($project_id), 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 || ! $this->request->isAjax()) { - return $this->response->status(403); - } - - if (! $this->project->isModifiedSince($project_id, $timestamp)) { - return $this->response->status(304); - } - - return $this->response->html($this->renderBoard($project_id)); - } - - /** - * Reload the board with new filters - * - * @access public - */ - public function reload() - { - $project_id = $this->request->getIntegerParam('project_id'); - - if (! $project_id || ! $this->request->isAjax()) { - return $this->response->status(403); - } - - $values = $this->request->getJson(); - $this->userSession->setFilters($project_id, empty($values['search']) ? '' : $values['search']); - - $this->response->html($this->renderBoard($project_id)); - } - - /** - * Enable collapsed mode - * - * @access public - */ - public function collapse() - { - $this->changeDisplayMode(true); - } - - /** - * Enable expanded mode - * - * @access public - */ - public function expand() - { - $this->changeDisplayMode(false); - } - - /** - * Change display mode - * - * @access private - * @param boolean $mode - */ - private function changeDisplayMode($mode) - { - $project_id = $this->request->getIntegerParam('project_id'); - $this->userSession->setBoardDisplayMode($project_id, $mode); - - if ($this->request->isAjax()) { - $this->response->html($this->renderBoard($project_id)); - } else { - $this->response->redirect($this->helper->url->to('board', 'show', array('project_id' => $project_id))); - } - } - - /** - * Render board - * - * @access private - * @param integer $project_id - */ - private function renderBoard($project_id) - { - return $this->template->render('board/table_container', array( - 'project' => $this->project->getById($project_id), - 'board_private_refresh_interval' => $this->config->get('board_private_refresh_interval'), - 'board_highlight_period' => $this->config->get('board_highlight_period'), - 'swimlanes' => $this->taskLexer - ->build($this->userSession->getFilters($project_id)) - ->format(BoardFormatter::getInstance($this->container)->setProjectId($project_id)) - )); - } -} diff --git a/app/Controller/BoardAjaxController.php b/app/Controller/BoardAjaxController.php new file mode 100644 index 00000000..24914671 --- /dev/null +++ b/app/Controller/BoardAjaxController.php @@ -0,0 +1,140 @@ +<?php + +namespace Kanboard\Controller; + +use Kanboard\Core\Controller\AccessForbiddenException; +use Kanboard\Formatter\BoardFormatter; + +/** + * Class BoardAjaxController + * + * @package Kanboard\Controller + * @author Fredric Guillot + */ +class BoardAjaxController extends BaseController +{ + /** + * Save new task positions (Ajax request made by the drag and drop) + * + * @access public + */ + public function save() + { + $project_id = $this->request->getIntegerParam('project_id'); + + if (! $project_id || ! $this->request->isAjax()) { + throw new AccessForbiddenException(); + } + + $values = $this->request->getJson(); + + $result =$this->taskPositionModel->movePosition( + $project_id, + $values['task_id'], + $values['column_id'], + $values['position'], + $values['swimlane_id'] + ); + + if (! $result) { + $this->response->status(400); + } else { + $this->response->html($this->renderBoard($project_id), 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 || ! $this->request->isAjax()) { + throw new AccessForbiddenException(); + } elseif (! $this->projectModel->isModifiedSince($project_id, $timestamp)) { + $this->response->status(304); + } else { + $this->response->html($this->renderBoard($project_id)); + } + } + + /** + * Reload the board with new filters + * + * @access public + */ + public function reload() + { + $project_id = $this->request->getIntegerParam('project_id'); + + if (! $project_id || ! $this->request->isAjax()) { + throw new AccessForbiddenException(); + } + + $values = $this->request->getJson(); + $this->userSession->setFilters($project_id, empty($values['search']) ? '' : $values['search']); + + $this->response->html($this->renderBoard($project_id)); + } + + /** + * Enable collapsed mode + * + * @access public + */ + public function collapse() + { + $this->changeDisplayMode(true); + } + + /** + * Enable expanded mode + * + * @access public + */ + public function expand() + { + $this->changeDisplayMode(false); + } + + /** + * Change display mode + * + * @access private + * @param boolean $mode + */ + private function changeDisplayMode($mode) + { + $project_id = $this->request->getIntegerParam('project_id'); + $this->userSession->setBoardDisplayMode($project_id, $mode); + + if ($this->request->isAjax()) { + $this->response->html($this->renderBoard($project_id)); + } else { + $this->response->redirect($this->helper->url->to('BoardViewController', 'show', array('project_id' => $project_id))); + } + } + + /** + * Render board + * + * @access protected + * @param integer $project_id + * @return string + */ + protected function renderBoard($project_id) + { + return $this->template->render('board/table_container', array( + 'project' => $this->projectModel->getById($project_id), + 'board_private_refresh_interval' => $this->configModel->get('board_private_refresh_interval'), + 'board_highlight_period' => $this->configModel->get('board_highlight_period'), + 'swimlanes' => $this->taskLexer + ->build($this->userSession->getFilters($project_id)) + ->format(BoardFormatter::getInstance($this->container)->setProjectId($project_id)) + )); + } +} diff --git a/app/Controller/BoardPopover.php b/app/Controller/BoardPopover.php deleted file mode 100644 index 63dab302..00000000 --- a/app/Controller/BoardPopover.php +++ /dev/null @@ -1,135 +0,0 @@ -<?php - -namespace Kanboard\Controller; - -/** - * Board Popover - * - * @package controller - * @author Frederic Guillot - */ -class BoardPopover extends Base -{ - /** - * Change a task assignee directly from the board - * - * @access public - */ - public function changeAssignee() - { - $task = $this->getTask(); - $project = $this->project->getById($task['project_id']); - - $this->response->html($this->template->render('board/popover_assignee', array( - 'values' => $task, - 'users_list' => $this->projectUserRole->getAssignableUsersList($project['id']), - 'project' => $project, - ))); - } - - /** - * Validate an assignee modification - * - * @access public - */ - public function updateAssignee() - { - $values = $this->request->getValues(); - - list($valid, ) = $this->taskValidator->validateAssigneeModification($values); - - if ($valid && $this->taskModification->update($values)) { - $this->flash->success(t('Task updated successfully.')); - } else { - $this->flash->failure(t('Unable to update your task.')); - } - - $this->response->redirect($this->helper->url->to('board', 'show', array('project_id' => $values['project_id']))); - } - - /** - * Change a task category directly from the board - * - * @access public - */ - public function changeCategory() - { - $task = $this->getTask(); - $project = $this->project->getById($task['project_id']); - - $this->response->html($this->template->render('board/popover_category', array( - 'values' => $task, - 'categories_list' => $this->category->getList($project['id']), - 'project' => $project, - ))); - } - - /** - * Validate a category modification - * - * @access public - */ - public function updateCategory() - { - $values = $this->request->getValues(); - - list($valid, ) = $this->taskValidator->validateCategoryModification($values); - - if ($valid && $this->taskModification->update($values)) { - $this->flash->success(t('Task updated successfully.')); - } else { - $this->flash->failure(t('Unable to update your task.')); - } - - $this->response->redirect($this->helper->url->to('board', 'show', array('project_id' => $values['project_id']))); - } - - /** - * Screenshot popover - * - * @access public - */ - public function screenshot() - { - $task = $this->getTask(); - - $this->response->html($this->template->render('task_file/screenshot', array( - 'task' => $task, - ))); - } - - /** - * Confirmation before to close all column tasks - * - * @access public - */ - public function confirmCloseColumnTasks() - { - $project = $this->getProject(); - $column_id = $this->request->getIntegerParam('column_id'); - $swimlane_id = $this->request->getIntegerParam('swimlane_id'); - - $this->response->html($this->template->render('board/popover_close_all_tasks_column', array( - 'project' => $project, - 'nb_tasks' => $this->taskFinder->countByColumnAndSwimlaneId($project['id'], $column_id, $swimlane_id), - 'column' => $this->column->getColumnTitleById($column_id), - 'swimlane' => $this->swimlane->getNameById($swimlane_id) ?: t($project['default_swimlane']), - 'values' => array('column_id' => $column_id, 'swimlane_id' => $swimlane_id), - ))); - } - - /** - * Close all column tasks - * - * @access public - */ - public function closeColumnTasks() - { - $project = $this->getProject(); - $values = $this->request->getValues(); - - $this->taskStatus->closeTasksBySwimlaneAndColumn($values['swimlane_id'], $values['column_id']); - $this->flash->success(t('All tasks of the column "%s" and the swimlane "%s" have been closed successfully.', $this->column->getColumnTitleById($values['column_id']), $this->swimlane->getNameById($values['swimlane_id']) ?: t($project['default_swimlane']))); - $this->response->redirect($this->helper->url->to('board', 'show', array('project_id' => $project['id']))); - } -} diff --git a/app/Controller/BoardPopoverController.php b/app/Controller/BoardPopoverController.php new file mode 100644 index 00000000..a0f5ae12 --- /dev/null +++ b/app/Controller/BoardPopoverController.php @@ -0,0 +1,47 @@ +<?php + +namespace Kanboard\Controller; + +/** + * Board Popover Controller + * + * @package Kanboard\Controller + * @author Frederic Guillot + */ +class BoardPopoverController extends BaseController +{ + /** + * Confirmation before to close all column tasks + * + * @access public + */ + public function confirmCloseColumnTasks() + { + $project = $this->getProject(); + $column_id = $this->request->getIntegerParam('column_id'); + $swimlane_id = $this->request->getIntegerParam('swimlane_id'); + + $this->response->html($this->template->render('board_popover/close_all_tasks_column', array( + 'project' => $project, + 'nb_tasks' => $this->taskFinderModel->countByColumnAndSwimlaneId($project['id'], $column_id, $swimlane_id), + 'column' => $this->columnModel->getColumnTitleById($column_id), + 'swimlane' => $this->swimlaneModel->getNameById($swimlane_id) ?: t($project['default_swimlane']), + 'values' => array('column_id' => $column_id, 'swimlane_id' => $swimlane_id), + ))); + } + + /** + * Close all column tasks + * + * @access public + */ + public function closeColumnTasks() + { + $project = $this->getProject(); + $values = $this->request->getValues(); + + $this->taskStatusModel->closeTasksBySwimlaneAndColumn($values['swimlane_id'], $values['column_id']); + $this->flash->success(t('All tasks of the column "%s" and the swimlane "%s" have been closed successfully.', $this->columnModel->getColumnTitleById($values['column_id']), $this->swimlaneModel->getNameById($values['swimlane_id']) ?: t($project['default_swimlane']))); + $this->response->redirect($this->helper->url->to('BoardViewController', 'show', array('project_id' => $project['id']))); + } +} diff --git a/app/Controller/BoardTooltip.php b/app/Controller/BoardTooltipController.php index c7819bc1..2a947027 100644 --- a/app/Controller/BoardTooltip.php +++ b/app/Controller/BoardTooltipController.php @@ -5,10 +5,10 @@ namespace Kanboard\Controller; /** * Board Tooltip * - * @package controller + * @package Kanboard\Controller * @author Frederic Guillot */ -class BoardTooltip extends Base +class BoardTooltipController extends BaseController { /** * Get links on mouseover @@ -19,7 +19,7 @@ class BoardTooltip extends Base { $task = $this->getTask(); $this->response->html($this->template->render('board/tooltip_tasklinks', array( - 'links' => $this->taskLink->getAllGroupedByLabel($task['id']), + 'links' => $this->taskLinkModel->getAllGroupedByLabel($task['id']), 'task' => $task, ))); } @@ -33,7 +33,7 @@ class BoardTooltip extends Base { $task = $this->getTask(); $this->response->html($this->template->render('board/tooltip_external_links', array( - 'links' => $this->taskExternalLink->getAll($task['id']), + 'links' => $this->taskExternalLinkModel->getAll($task['id']), 'task' => $task, ))); } @@ -47,7 +47,7 @@ class BoardTooltip extends Base { $task = $this->getTask(); $this->response->html($this->template->render('board/tooltip_subtasks', array( - 'subtasks' => $this->subtask->getAll($task['id']), + 'subtasks' => $this->subtaskModel->getAll($task['id']), 'task' => $task, ))); } @@ -62,7 +62,7 @@ class BoardTooltip extends Base $task = $this->getTask(); $this->response->html($this->template->render('board/tooltip_files', array( - 'files' => $this->taskFile->getAll($task['id']), + 'files' => $this->taskFileModel->getAll($task['id']), 'task' => $task, ))); } @@ -78,7 +78,7 @@ class BoardTooltip extends Base $this->response->html($this->template->render('board/tooltip_comments', array( 'task' => $task, - 'comments' => $this->comment->getAll($task['id'], $this->userSession->getCommentSorting()) + 'comments' => $this->commentModel->getAll($task['id'], $this->userSession->getCommentSorting()) ))); } @@ -107,9 +107,9 @@ class BoardTooltip extends Base $this->response->html($this->template->render('task_recurrence/info', array( 'task' => $task, - 'recurrence_trigger_list' => $this->task->getRecurrenceTriggerList(), - 'recurrence_timeframe_list' => $this->task->getRecurrenceTimeframeList(), - 'recurrence_basedate_list' => $this->task->getRecurrenceBasedateList(), + 'recurrence_trigger_list' => $this->taskModel->getRecurrenceTriggerList(), + 'recurrence_timeframe_list' => $this->taskModel->getRecurrenceTimeframeList(), + 'recurrence_basedate_list' => $this->taskModel->getRecurrenceBasedateList(), ))); } @@ -121,7 +121,7 @@ class BoardTooltip extends Base public function swimlane() { $this->getProject(); - $swimlane = $this->swimlane->getById($this->request->getIntegerParam('swimlane_id')); + $swimlane = $this->swimlaneModel->getById($this->request->getIntegerParam('swimlane_id')); $this->response->html($this->template->render('board/tooltip_description', array('task' => $swimlane))); } } diff --git a/app/Controller/BoardViewController.php b/app/Controller/BoardViewController.php new file mode 100644 index 00000000..496fa995 --- /dev/null +++ b/app/Controller/BoardViewController.php @@ -0,0 +1,65 @@ +<?php + +namespace Kanboard\Controller; + +use Kanboard\Core\Controller\AccessForbiddenException; +use Kanboard\Formatter\BoardFormatter; + +/** + * Board controller + * + * @package Kanboard\Controller + * @author Frederic Guillot + */ +class BoardViewController extends BaseController +{ + /** + * 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->projectModel->getByToken($token); + + if (empty($project)) { + throw AccessForbiddenException::getInstance()->withoutLayout(); + } + + $this->response->html($this->helper->layout->app('board/view_public', array( + 'project' => $project, + 'swimlanes' => $this->boardModel->getBoard($project['id']), + 'title' => $project['name'], + 'description' => $project['description'], + 'no_layout' => true, + 'not_editable' => true, + 'board_public_refresh_interval' => $this->configModel->get('board_public_refresh_interval'), + 'board_private_refresh_interval' => $this->configModel->get('board_private_refresh_interval'), + 'board_highlight_period' => $this->configModel->get('board_highlight_period'), + ))); + } + + /** + * Show a board for a given project + * + * @access public + */ + public function show() + { + $project = $this->getProject(); + $search = $this->helper->projectHeader->getSearchQuery($project); + + $this->response->html($this->helper->layout->app('board/view_private', array( + 'project' => $project, + 'title' => $project['name'], + 'description' => $this->helper->projectHeader->getDescription($project), + 'board_private_refresh_interval' => $this->configModel->get('board_private_refresh_interval'), + 'board_highlight_period' => $this->configModel->get('board_highlight_period'), + 'swimlanes' => $this->taskLexer + ->build($search) + ->format(BoardFormatter::getInstance($this->container)->setProjectId($project['id'])) + ))); + } +} diff --git a/app/Controller/Calendar.php b/app/Controller/CalendarController.php index 2517286d..e5114f02 100644 --- a/app/Controller/Calendar.php +++ b/app/Controller/CalendarController.php @@ -5,16 +5,16 @@ namespace Kanboard\Controller; use Kanboard\Filter\TaskAssigneeFilter; use Kanboard\Filter\TaskProjectFilter; use Kanboard\Filter\TaskStatusFilter; -use Kanboard\Model\Task as TaskModel; +use Kanboard\Model\TaskModel; /** - * Project Calendar controller + * Calendar Controller * - * @package controller + * @package Kanboard\Controller * @author Frederic Guillot * @author Timo Litzbarski */ -class Calendar extends Base +class CalendarController extends BaseController { /** * Show calendar view for projects @@ -29,7 +29,7 @@ class Calendar extends Base 'project' => $project, 'title' => $project['name'], 'description' => $this->helper->projectHeader->getDescription($project), - 'check_interval' => $this->config->get('board_private_refresh_interval'), + 'check_interval' => $this->configModel->get('board_private_refresh_interval'), ))); } @@ -75,7 +75,7 @@ class Calendar extends Base $events = $this->helper->calendar->getTaskDateDueEvents(clone($queryBuilder), $start, $end); $events = array_merge($events, $this->helper->calendar->getTaskEvents(clone($queryBuilder), $start, $end)); - if ($this->config->get('calendar_user_subtasks_time_tracking') == 1) { + if ($this->configModel->get('calendar_user_subtasks_time_tracking') == 1) { $events = array_merge($events, $this->helper->calendar->getSubtaskTimeTrackingEvents($user_id, $start, $end)); } @@ -98,7 +98,7 @@ class Calendar extends Base if ($this->request->isAjax() && $this->request->isPost()) { $values = $this->request->getJson(); - $this->taskModification->update(array( + $this->taskModificationModel->update(array( 'id' => $values['task_id'], 'date_due' => substr($values['date_due'], 0, 10), )); diff --git a/app/Controller/Captcha.php b/app/Controller/CaptchaController.php index fcf081ea..43b2f823 100644 --- a/app/Controller/Captcha.php +++ b/app/Controller/CaptchaController.php @@ -7,10 +7,10 @@ use Gregwar\Captcha\CaptchaBuilder; /** * Captcha Controller * - * @package controller + * @package Kanboard\Controller * @author Frederic Guillot */ -class Captcha extends Base +class CaptchaController extends BaseController { /** * Display captcha image @@ -19,7 +19,7 @@ class Captcha extends Base */ public function image() { - $this->response->contentType('image/jpeg'); + $this->response->withContentType('image/jpeg')->send(); $builder = new CaptchaBuilder; $builder->build(); diff --git a/app/Controller/Category.php b/app/Controller/CategoryController.php index 258a3b78..dd6e1c35 100644 --- a/app/Controller/Category.php +++ b/app/Controller/CategoryController.php @@ -2,28 +2,29 @@ namespace Kanboard\Controller; +use Kanboard\Core\Controller\PageNotFoundException; + /** - * Category management + * Category Controller * - * @package controller + * @package Kanboard\Controller * @author Frederic Guillot */ -class Category extends Base +class CategoryController extends BaseController { /** * Get the category (common method between actions) * * @access private - * @param integer $project_id * @return array + * @throws PageNotFoundException */ - private function getCategory($project_id) + private function getCategory() { - $category = $this->category->getById($this->request->getIntegerParam('category_id')); + $category = $this->categoryModel->getById($this->request->getIntegerParam('category_id')); if (empty($category)) { - $this->flash->failure(t('Category not found.')); - $this->response->redirect($this->helper->url->to('category', 'index', array('project_id' => $project_id))); + throw new PageNotFoundException(); } return $category; @@ -33,13 +34,16 @@ class Category extends Base * List of categories for a given project * * @access public + * @param array $values + * @param array $errors + * @throws PageNotFoundException */ public function index(array $values = array(), array $errors = array()) { $project = $this->getProject(); $this->response->html($this->helper->layout->project('category/index', array( - 'categories' => $this->category->getList($project['id'], false), + 'categories' => $this->categoryModel->getList($project['id'], false), 'values' => $values + array('project_id' => $project['id']), 'errors' => $errors, 'project' => $project, @@ -60,26 +64,29 @@ class Category extends Base list($valid, $errors) = $this->categoryValidator->validateCreation($values); if ($valid) { - if ($this->category->create($values)) { + if ($this->categoryModel->create($values) !== false) { $this->flash->success(t('Your category have been created successfully.')); - $this->response->redirect($this->helper->url->to('category', 'index', array('project_id' => $project['id']))); + return $this->response->redirect($this->helper->url->to('CategoryController', 'index', array('project_id' => $project['id']))); } else { $this->flash->failure(t('Unable to create your category.')); } } - $this->index($values, $errors); + return $this->index($values, $errors); } /** * Edit a category (display the form) * * @access public + * @param array $values + * @param array $errors + * @throws PageNotFoundException */ public function edit(array $values = array(), array $errors = array()) { $project = $this->getProject(); - $category = $this->getCategory($project['id']); + $category = $this->getCategory(); $this->response->html($this->helper->layout->project('category/edit', array( 'values' => empty($values) ? $category : $values, @@ -102,15 +109,15 @@ class Category extends Base list($valid, $errors) = $this->categoryValidator->validateModification($values); if ($valid) { - if ($this->category->update($values)) { + if ($this->categoryModel->update($values)) { $this->flash->success(t('Your category have been updated successfully.')); - $this->response->redirect($this->helper->url->to('category', 'index', array('project_id' => $project['id']))); + return $this->response->redirect($this->helper->url->to('CategoryController', 'index', array('project_id' => $project['id']))); } else { $this->flash->failure(t('Unable to update your category.')); } } - $this->edit($values, $errors); + return $this->edit($values, $errors); } /** @@ -121,7 +128,7 @@ class Category extends Base public function confirm() { $project = $this->getProject(); - $category = $this->getCategory($project['id']); + $category = $this->getCategory(); $this->response->html($this->helper->layout->project('category/remove', array( 'project' => $project, @@ -139,14 +146,14 @@ class Category extends Base { $this->checkCSRFParam(); $project = $this->getProject(); - $category = $this->getCategory($project['id']); + $category = $this->getCategory(); - if ($this->category->remove($category['id'])) { + if ($this->categoryModel->remove($category['id'])) { $this->flash->success(t('Category removed successfully.')); } else { $this->flash->failure(t('Unable to remove this category.')); } - $this->response->redirect($this->helper->url->to('category', 'index', array('project_id' => $project['id']))); + $this->response->redirect($this->helper->url->to('CategoryController', 'index', array('project_id' => $project['id']))); } } diff --git a/app/Controller/Column.php b/app/Controller/ColumnController.php index bbe12fe1..95fbcaaa 100644 --- a/app/Controller/Column.php +++ b/app/Controller/ColumnController.php @@ -2,13 +2,15 @@ namespace Kanboard\Controller; +use Kanboard\Core\Controller\AccessForbiddenException; + /** - * Column controller + * Column Controller * - * @package controller + * @package Kanboard\Controller * @author Frederic Guillot */ -class Column extends Base +class ColumnController extends BaseController { /** * Display columns list @@ -18,7 +20,7 @@ class Column extends Base public function index() { $project = $this->getProject(); - $columns = $this->column->getAll($project['id']); + $columns = $this->columnModel->getAll($project['id']); $this->response->html($this->helper->layout->project('column/index', array( 'columns' => $columns, @@ -31,6 +33,9 @@ class Column extends Base * Show form to create a new column * * @access public + * @param array $values + * @param array $errors + * @throws \Kanboard\Core\Controller\PageNotFoundException */ public function create(array $values = array(), array $errors = array()) { @@ -61,15 +66,15 @@ class Column extends Base list($valid, $errors) = $this->columnValidator->validateCreation($values); if ($valid) { - if ($this->column->create($project['id'], $values['title'], $values['task_limit'], $values['description'])) { + if ($this->columnModel->create($project['id'], $values['title'], $values['task_limit'], $values['description']) !== false) { $this->flash->success(t('Column created successfully.')); - return $this->response->redirect($this->helper->url->to('column', 'index', array('project_id' => $project['id'])), true); + return $this->response->redirect($this->helper->url->to('ColumnController', 'index', array('project_id' => $project['id'])), true); } else { $errors['title'] = array(t('Another column with the same name exists in the project')); } } - $this->create($values, $errors); + return $this->create($values, $errors); } /** @@ -82,7 +87,7 @@ class Column extends Base public function edit(array $values = array(), array $errors = array()) { $project = $this->getProject(); - $column = $this->column->getById($this->request->getIntegerParam('column_id')); + $column = $this->columnModel->getById($this->request->getIntegerParam('column_id')); $this->response->html($this->helper->layout->project('column/edit', array( 'errors' => $errors, @@ -106,15 +111,15 @@ class Column extends Base list($valid, $errors) = $this->columnValidator->validateModification($values); if ($valid) { - if ($this->column->update($values['id'], $values['title'], $values['task_limit'], $values['description'])) { + if ($this->columnModel->update($values['id'], $values['title'], $values['task_limit'], $values['description'])) { $this->flash->success(t('Board updated successfully.')); - $this->response->redirect($this->helper->url->to('column', 'index', array('project_id' => $project['id']))); + return $this->response->redirect($this->helper->url->to('ColumnController', 'index', array('project_id' => $project['id']))); } else { $this->flash->failure(t('Unable to update this board.')); } } - $this->edit($values, $errors); + return $this->edit($values, $errors); } /** @@ -128,11 +133,11 @@ class Column extends Base $values = $this->request->getJson(); if (! empty($values) && isset($values['column_id']) && isset($values['position'])) { - $result = $this->column->changePosition($project['id'], $values['column_id'], $values['position']); - return $this->response->json(array('result' => $result)); + $result = $this->columnModel->changePosition($project['id'], $values['column_id'], $values['position']); + $this->response->json(array('result' => $result)); + } else { + throw new AccessForbiddenException(); } - - $this->forbidden(); } /** @@ -145,7 +150,7 @@ class Column extends Base $project = $this->getProject(); $this->response->html($this->helper->layout->project('column/remove', array( - 'column' => $this->column->getById($this->request->getIntegerParam('column_id')), + 'column' => $this->columnModel->getById($this->request->getIntegerParam('column_id')), 'project' => $project, 'title' => t('Remove a column from a board') ))); @@ -162,12 +167,12 @@ class Column extends Base $this->checkCSRFParam(); $column_id = $this->request->getIntegerParam('column_id'); - if ($this->column->remove($column_id)) { + if ($this->columnModel->remove($column_id)) { $this->flash->success(t('Column removed successfully.')); } else { $this->flash->failure(t('Unable to remove this column.')); } - $this->response->redirect($this->helper->url->to('column', 'index', array('project_id' => $project['id']))); + $this->response->redirect($this->helper->url->to('ColumnController', 'index', array('project_id' => $project['id']))); } } diff --git a/app/Controller/Comment.php b/app/Controller/CommentController.php index 0b39f390..2a8c258a 100644 --- a/app/Controller/Comment.php +++ b/app/Controller/CommentController.php @@ -2,30 +2,35 @@ namespace Kanboard\Controller; +use Kanboard\Core\Controller\AccessForbiddenException; +use Kanboard\Core\Controller\PageNotFoundException; + /** - * Comment controller + * Comment Controller * - * @package controller + * @package Kanboard\Controller * @author Frederic Guillot */ -class Comment extends Base +class CommentController extends BaseController { /** * Get the current comment * * @access private * @return array + * @throws PageNotFoundException + * @throws AccessForbiddenException */ private function getComment() { - $comment = $this->comment->getById($this->request->getIntegerParam('comment_id')); + $comment = $this->commentModel->getById($this->request->getIntegerParam('comment_id')); if (empty($comment)) { - return $this->notfound(); + throw new PageNotFoundException(); } if (! $this->userSession->isAdmin() && $comment['user_id'] != $this->userSession->getId()) { - return $this->forbidden(); + throw new AccessForbiddenException(); } return $comment; @@ -35,6 +40,10 @@ class Comment extends Base * Add comment form * * @access public + * @param array $values + * @param array $errors + * @throws AccessForbiddenException + * @throws PageNotFoundException */ public function create(array $values = array(), array $errors = array()) { @@ -67,22 +76,26 @@ class Comment extends Base list($valid, $errors) = $this->commentValidator->validateCreation($values); if ($valid) { - if ($this->comment->create($values)) { + if ($this->commentModel->create($values) !== false) { $this->flash->success(t('Comment added successfully.')); } else { $this->flash->failure(t('Unable to create your comment.')); } - return $this->response->redirect($this->helper->url->to('task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), 'comments'), true); + return $this->response->redirect($this->helper->url->to('TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), 'comments'), true); } - $this->create($values, $errors); + return $this->create($values, $errors); } /** * Edit a comment * * @access public + * @param array $values + * @param array $errors + * @throws AccessForbiddenException + * @throws PageNotFoundException */ public function edit(array $values = array(), array $errors = array()) { @@ -112,16 +125,16 @@ class Comment extends Base list($valid, $errors) = $this->commentValidator->validateModification($values); if ($valid) { - if ($this->comment->update($values)) { + if ($this->commentModel->update($values)) { $this->flash->success(t('Comment updated successfully.')); } else { $this->flash->failure(t('Unable to update your comment.')); } - return $this->response->redirect($this->helper->url->to('task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])), false); + return $this->response->redirect($this->helper->url->to('TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])), false); } - $this->edit($values, $errors); + return $this->edit($values, $errors); } /** @@ -152,13 +165,13 @@ class Comment extends Base $task = $this->getTask(); $comment = $this->getComment(); - if ($this->comment->remove($comment['id'])) { + if ($this->commentModel->remove($comment['id'])) { $this->flash->success(t('Comment removed successfully.')); } else { $this->flash->failure(t('Unable to remove this comment.')); } - $this->response->redirect($this->helper->url->to('task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), 'comments')); + $this->response->redirect($this->helper->url->to('TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), 'comments')); } /** @@ -173,6 +186,6 @@ class Comment extends Base $order = $this->userSession->getCommentSorting() === 'ASC' ? 'DESC' : 'ASC'; $this->userSession->setCommentSorting($order); - $this->response->redirect($this->helper->url->to('task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), 'comments')); + $this->response->redirect($this->helper->url->to('TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), 'comments')); } } diff --git a/app/Controller/Config.php b/app/Controller/ConfigController.php index a1b8c2af..8bcf4c35 100644 --- a/app/Controller/Config.php +++ b/app/Controller/ConfigController.php @@ -3,56 +3,14 @@ namespace Kanboard\Controller; /** - * Config controller + * Config Controller * - * @package controller + * @package Kanboard/Controller * @author Frederic Guillot */ -class Config extends Base +class ConfigController extends BaseController { /** - * Common method between pages - * - * @access private - * @param string $redirect Action to redirect after saving the form - */ - private function common($redirect) - { - if ($this->request->isPost()) { - $values = $this->request->getValues(); - - switch ($redirect) { - case 'application': - $values += array('password_reset' => 0); - break; - case 'project': - $values += array( - 'subtask_restriction' => 0, - 'subtask_time_tracking' => 0, - 'cfd_include_closed_tasks' => 0, - 'disable_private_project' => 0, - ); - break; - case 'integrations': - $values += array('integration_gravatar' => 0); - break; - case 'calendar': - $values += array('calendar_user_subtasks_time_tracking' => 0); - break; - } - - if ($this->config->save($values)) { - $this->config->reload(); - $this->flash->success(t('Settings saved successfully.')); - } else { - $this->flash->failure(t('Unable to save your settings.')); - } - - $this->response->redirect($this->helper->url->to('config', $redirect)); - } - } - - /** * Display the about page * * @access public @@ -60,7 +18,7 @@ class Config extends Base public function index() { $this->response->html($this->helper->layout->config('config/about', array( - 'db_size' => $this->config->getDatabaseSize(), + 'db_size' => $this->configModel->getDatabaseSize(), 'db_version' => $this->db->getDriver()->getDatabaseVersion(), 'user_agent' => $this->request->getServerVariable('HTTP_USER_AGENT'), 'title' => t('Settings').' > '.t('About'), @@ -68,16 +26,42 @@ class Config extends Base } /** - * Display the plugin page + * Save settings * - * @access public */ - public function plugins() + public function save() { - $this->response->html($this->helper->layout->config('config/plugins', array( - 'plugins' => $this->pluginLoader->plugins, - 'title' => t('Settings').' > '.t('Plugins'), - ))); + $values = $this->request->getValues(); + $redirect = $this->request->getStringParam('redirect', 'application'); + + switch ($redirect) { + case 'application': + $values += array('password_reset' => 0); + break; + case 'project': + $values += array( + 'subtask_restriction' => 0, + 'subtask_time_tracking' => 0, + 'cfd_include_closed_tasks' => 0, + 'disable_private_project' => 0, + ); + break; + case 'integrations': + $values += array('integration_gravatar' => 0); + break; + case 'calendar': + $values += array('calendar_user_subtasks_time_tracking' => 0); + break; + } + + if ($this->configModel->save($values)) { + $this->languageModel->loadCurrentLanguage(); + $this->flash->success(t('Settings saved successfully.')); + } else { + $this->flash->failure(t('Unable to save your settings.')); + } + + $this->response->redirect($this->helper->url->to('ConfigController', $redirect)); } /** @@ -87,11 +71,9 @@ class Config extends Base */ public function application() { - $this->common('application'); - $this->response->html($this->helper->layout->config('config/application', array( - 'languages' => $this->config->getLanguages(), - 'timezones' => $this->config->getTimezones(), + 'languages' => $this->languageModel->getLanguages(), + 'timezones' => $this->timezoneModel->getTimezones(), 'date_formats' => $this->dateParser->getAvailableFormats($this->dateParser->getDateFormats()), 'datetime_formats' => $this->dateParser->getAvailableFormats($this->dateParser->getDateTimeFormats()), 'time_formats' => $this->dateParser->getAvailableFormats($this->dateParser->getTimeFormats()), @@ -106,11 +88,9 @@ class Config extends Base */ public function project() { - $this->common('project'); - $this->response->html($this->helper->layout->config('config/project', array( - 'colors' => $this->color->getList(), - 'default_columns' => implode(', ', $this->board->getDefaultColumns()), + 'colors' => $this->colorModel->getList(), + 'default_columns' => implode(', ', $this->boardModel->getDefaultColumns()), 'title' => t('Settings').' > '.t('Project settings'), ))); } @@ -122,8 +102,6 @@ class Config extends Base */ public function board() { - $this->common('board'); - $this->response->html($this->helper->layout->config('config/board', array( 'title' => t('Settings').' > '.t('Board settings'), ))); @@ -136,8 +114,6 @@ class Config extends Base */ public function calendar() { - $this->common('calendar'); - $this->response->html($this->helper->layout->config('config/calendar', array( 'title' => t('Settings').' > '.t('Calendar settings'), ))); @@ -150,8 +126,6 @@ class Config extends Base */ public function integrations() { - $this->common('integrations'); - $this->response->html($this->helper->layout->config('config/integrations', array( 'title' => t('Settings').' > '.t('Integrations'), ))); @@ -164,8 +138,6 @@ class Config extends Base */ public function webhook() { - $this->common('webhook'); - $this->response->html($this->helper->layout->config('config/webhook', array( 'title' => t('Settings').' > '.t('Webhook settings'), ))); @@ -191,8 +163,8 @@ class Config extends Base public function downloadDb() { $this->checkCSRFParam(); - $this->response->forceDownload('db.sqlite.gz'); - $this->response->binary($this->config->downloadDatabase()); + $this->response->withFileDownload('db.sqlite.gz'); + $this->response->binary($this->configModel->downloadDatabase()); } /** @@ -203,9 +175,9 @@ class Config extends Base public function optimizeDb() { $this->checkCSRFParam(); - $this->config->optimizeDatabase(); + $this->configModel->optimizeDatabase(); $this->flash->success(t('Database optimization done.')); - $this->response->redirect($this->helper->url->to('config', 'index')); + $this->response->redirect($this->helper->url->to('ConfigController', 'index')); } /** @@ -218,9 +190,9 @@ class Config extends Base $type = $this->request->getStringParam('type'); $this->checkCSRFParam(); - $this->config->regenerateToken($type.'_token'); + $this->configModel->regenerateToken($type.'_token'); $this->flash->success(t('Token regenerated.')); - $this->response->redirect($this->helper->url->to('config', $type)); + $this->response->redirect($this->helper->url->to('ConfigController', $type)); } } diff --git a/app/Controller/Currency.php b/app/Controller/CurrencyController.php index ecaa9834..ad590035 100644 --- a/app/Controller/Currency.php +++ b/app/Controller/CurrencyController.php @@ -3,26 +3,28 @@ namespace Kanboard\Controller; /** - * Currency controller + * Currency Controller * - * @package controller + * @package Kanboard\Controller * @author Frederic Guillot */ -class Currency extends Base +class CurrencyController extends BaseController { /** * Display all currency rates and form * * @access public + * @param array $values + * @param array $errors */ public function index(array $values = array(), array $errors = array()) { $this->response->html($this->helper->layout->config('currency/index', array( - 'config_values' => array('application_currency' => $this->config->get('application_currency')), + 'config_values' => array('application_currency' => $this->configModel->get('application_currency')), 'values' => $values, 'errors' => $errors, - 'rates' => $this->currency->getAll(), - 'currencies' => $this->currency->getCurrencies(), + 'rates' => $this->currencyModel->getAll(), + 'currencies' => $this->currencyModel->getCurrencies(), 'title' => t('Settings').' > '.t('Currency rates'), ))); } @@ -38,15 +40,15 @@ class Currency extends Base list($valid, $errors) = $this->currencyValidator->validateCreation($values); if ($valid) { - if ($this->currency->create($values['currency'], $values['rate'])) { + if ($this->currencyModel->create($values['currency'], $values['rate'])) { $this->flash->success(t('The currency rate have been added successfully.')); - $this->response->redirect($this->helper->url->to('currency', 'index')); + return $this->response->redirect($this->helper->url->to('CurrencyController', 'index')); } else { $this->flash->failure(t('Unable to add this currency rate.')); } } - $this->index($values, $errors); + return $this->index($values, $errors); } /** @@ -58,13 +60,12 @@ class Currency extends Base { $values = $this->request->getValues(); - if ($this->config->save($values)) { - $this->config->reload(); + if ($this->configModel->save($values)) { $this->flash->success(t('Settings saved successfully.')); } else { $this->flash->failure(t('Unable to save your settings.')); } - $this->response->redirect($this->helper->url->to('currency', 'index')); + $this->response->redirect($this->helper->url->to('CurrencyController', 'index')); } } diff --git a/app/Controller/Customfilter.php b/app/Controller/CustomFilterController.php index 41da0b11..e5f674cd 100644 --- a/app/Controller/Customfilter.php +++ b/app/Controller/CustomFilterController.php @@ -2,20 +2,25 @@ namespace Kanboard\Controller; +use Kanboard\Core\Controller\AccessForbiddenException; use Kanboard\Core\Security\Role; /** - * Custom Filter management + * Custom Filter Controller * - * @package controller + * @package Kanboard\Controller * @author Timo Litzbarski + * @author Frederic Guillot */ -class Customfilter extends Base +class CustomFilterController extends BaseController { /** * Display list of filters * * @access public + * @param array $values + * @param array $errors + * @throws \Kanboard\Core\Controller\PageNotFoundException */ public function index(array $values = array(), array $errors = array()) { @@ -25,7 +30,7 @@ class Customfilter extends Base 'values' => $values + array('project_id' => $project['id']), 'errors' => $errors, 'project' => $project, - 'custom_filters' => $this->customFilter->getAll($project['id'], $this->userSession->getId()), + 'custom_filters' => $this->customFilterModel->getAll($project['id'], $this->userSession->getId()), 'title' => t('Custom filters'), ))); } @@ -45,15 +50,15 @@ class Customfilter extends Base list($valid, $errors) = $this->customFilterValidator->validateCreation($values); if ($valid) { - if ($this->customFilter->create($values)) { + if ($this->customFilterModel->create($values) !== false) { $this->flash->success(t('Your custom filter have been created successfully.')); - $this->response->redirect($this->helper->url->to('customfilter', 'index', array('project_id' => $project['id']))); + return $this->response->redirect($this->helper->url->to('CustomFilterController', 'index', array('project_id' => $project['id']))); } else { $this->flash->failure(t('Unable to create your custom filter.')); } } - $this->index($values, $errors); + return $this->index($values, $errors); } /** @@ -64,7 +69,7 @@ class Customfilter extends Base public function confirm() { $project = $this->getProject(); - $filter = $this->customFilter->getById($this->request->getIntegerParam('filter_id')); + $filter = $this->customFilterModel->getById($this->request->getIntegerParam('filter_id')); $this->response->html($this->helper->layout->project('custom_filter/remove', array( 'project' => $project, @@ -82,28 +87,32 @@ class Customfilter extends Base { $this->checkCSRFParam(); $project = $this->getProject(); - $filter = $this->customFilter->getById($this->request->getIntegerParam('filter_id')); + $filter = $this->customFilterModel->getById($this->request->getIntegerParam('filter_id')); $this->checkPermission($project, $filter); - if ($this->customFilter->remove($filter['id'])) { + if ($this->customFilterModel->remove($filter['id'])) { $this->flash->success(t('Custom filter removed successfully.')); } else { $this->flash->failure(t('Unable to remove this custom filter.')); } - $this->response->redirect($this->helper->url->to('customfilter', 'index', array('project_id' => $project['id']))); + $this->response->redirect($this->helper->url->to('CustomFilterController', 'index', array('project_id' => $project['id']))); } /** * Edit a custom filter (display the form) * * @access public + * @param array $values + * @param array $errors + * @throws AccessForbiddenException + * @throws \Kanboard\Core\Controller\PageNotFoundException */ public function edit(array $values = array(), array $errors = array()) { $project = $this->getProject(); - $filter = $this->customFilter->getById($this->request->getIntegerParam('filter_id')); + $filter = $this->customFilterModel->getById($this->request->getIntegerParam('filter_id')); $this->checkPermission($project, $filter); @@ -124,7 +133,7 @@ class Customfilter extends Base public function update() { $project = $this->getProject(); - $filter = $this->customFilter->getById($this->request->getIntegerParam('filter_id')); + $filter = $this->customFilterModel->getById($this->request->getIntegerParam('filter_id')); $this->checkPermission($project, $filter); @@ -141,23 +150,23 @@ class Customfilter extends Base list($valid, $errors) = $this->customFilterValidator->validateModification($values); if ($valid) { - if ($this->customFilter->update($values)) { + if ($this->customFilterModel->update($values)) { $this->flash->success(t('Your custom filter have been updated successfully.')); - $this->response->redirect($this->helper->url->to('customfilter', 'index', array('project_id' => $project['id']))); + return $this->response->redirect($this->helper->url->to('CustomFilterController', 'index', array('project_id' => $project['id']))); } else { $this->flash->failure(t('Unable to update custom filter.')); } } - $this->edit($values, $errors); + return $this->edit($values, $errors); } private function checkPermission(array $project, array $filter) { $user_id = $this->userSession->getId(); - if ($filter['user_id'] != $user_id && ($this->projectUserRole->getUserRole($project['id'], $user_id) === Role::PROJECT_MANAGER || ! $this->userSession->isAdmin())) { - $this->forbidden(); + if ($filter['user_id'] != $user_id && ($this->projectUserRoleModel->getUserRole($project['id'], $user_id) === Role::PROJECT_MANAGER || ! $this->userSession->isAdmin())) { + throw new AccessForbiddenException(); } } } diff --git a/app/Controller/App.php b/app/Controller/DashboardController.php index 01f733ff..44874546 100644 --- a/app/Controller/App.php +++ b/app/Controller/DashboardController.php @@ -2,16 +2,16 @@ namespace Kanboard\Controller; -use Kanboard\Model\Project as ProjectModel; -use Kanboard\Model\Subtask as SubtaskModel; +use Kanboard\Model\ProjectModel; +use Kanboard\Model\SubtaskModel; /** - * Application controller + * Dashboard Controller * - * @package controller + * @package Kanboard\Controller * @author Frederic Guillot */ -class App extends Base +class DashboardController extends BaseController { /** * Get project pagination @@ -25,10 +25,10 @@ class App extends Base private function getProjectPaginator($user_id, $action, $max) { return $this->paginator - ->setUrl('app', $action, array('pagination' => 'projects', 'user_id' => $user_id)) + ->setUrl('DashboardController', $action, array('pagination' => 'projects', 'user_id' => $user_id)) ->setMax($max) ->setOrder(ProjectModel::TABLE.'.name') - ->setQuery($this->project->getQueryColumnStats($this->projectPermission->getActiveProjectIds($user_id))) + ->setQuery($this->projectModel->getQueryColumnStats($this->projectPermissionModel->getActiveProjectIds($user_id))) ->calculateOnlyIf($this->request->getStringParam('pagination') === 'projects'); } @@ -44,10 +44,10 @@ class App extends Base private function getTaskPaginator($user_id, $action, $max) { return $this->paginator - ->setUrl('app', $action, array('pagination' => 'tasks', 'user_id' => $user_id)) + ->setUrl('DashboardController', $action, array('pagination' => 'tasks', 'user_id' => $user_id)) ->setMax($max) ->setOrder('tasks.id') - ->setQuery($this->taskFinder->getUserQuery($user_id)) + ->setQuery($this->taskFinderModel->getUserQuery($user_id)) ->calculateOnlyIf($this->request->getStringParam('pagination') === 'tasks'); } @@ -63,37 +63,27 @@ class App extends Base private function getSubtaskPaginator($user_id, $action, $max) { return $this->paginator - ->setUrl('app', $action, array('pagination' => 'subtasks', 'user_id' => $user_id)) + ->setUrl('DashboardController', $action, array('pagination' => 'subtasks', 'user_id' => $user_id)) ->setMax($max) ->setOrder('tasks.id') - ->setQuery($this->subtask->getUserQuery($user_id, array(SubTaskModel::STATUS_TODO, SubtaskModel::STATUS_INPROGRESS))) + ->setQuery($this->subtaskModel->getUserQuery($user_id, array(SubTaskModel::STATUS_TODO, SubtaskModel::STATUS_INPROGRESS))) ->calculateOnlyIf($this->request->getStringParam('pagination') === 'subtasks'); } /** - * Check if the user is connected - * - * @access public - */ - public function status() - { - $this->response->text('OK'); - } - - /** * Dashboard overview * * @access public */ - public function index() + public function show() { $user = $this->getUser(); - $this->response->html($this->helper->layout->dashboard('app/overview', array( + $this->response->html($this->helper->layout->dashboard('dashboard/show', array( 'title' => t('Dashboard'), - 'project_paginator' => $this->getProjectPaginator($user['id'], 'index', 10), - 'task_paginator' => $this->getTaskPaginator($user['id'], 'index', 10), - 'subtask_paginator' => $this->getSubtaskPaginator($user['id'], 'index', 10), + 'project_paginator' => $this->getProjectPaginator($user['id'], 'show', 10), + 'task_paginator' => $this->getTaskPaginator($user['id'], 'show', 10), + 'subtask_paginator' => $this->getSubtaskPaginator($user['id'], 'show', 10), 'user' => $user, ))); } @@ -107,7 +97,7 @@ class App extends Base { $user = $this->getUser(); - $this->response->html($this->helper->layout->dashboard('app/tasks', array( + $this->response->html($this->helper->layout->dashboard('dashboard/tasks', array( 'title' => t('My tasks'), 'paginator' => $this->getTaskPaginator($user['id'], 'tasks', 50), 'user' => $user, @@ -123,7 +113,7 @@ class App extends Base { $user = $this->getUser(); - $this->response->html($this->helper->layout->dashboard('app/subtasks', array( + $this->response->html($this->helper->layout->dashboard('dashboard/subtasks', array( 'title' => t('My subtasks'), 'paginator' => $this->getSubtaskPaginator($user['id'], 'subtasks', 50), 'user' => $user, @@ -139,7 +129,7 @@ class App extends Base { $user = $this->getUser(); - $this->response->html($this->helper->layout->dashboard('app/projects', array( + $this->response->html($this->helper->layout->dashboard('dashboard/projects', array( 'title' => t('My projects'), 'paginator' => $this->getProjectPaginator($user['id'], 'projects', 25), 'user' => $user, @@ -155,9 +145,9 @@ class App extends Base { $user = $this->getUser(); - $this->response->html($this->helper->layout->dashboard('app/activity', array( + $this->response->html($this->helper->layout->dashboard('dashboard/activity', array( 'title' => t('My activity stream'), - 'events' => $this->helper->projectActivity->getProjectsEvents($this->projectPermission->getActiveProjectIds($user['id']), 100), + 'events' => $this->helper->projectActivity->getProjectsEvents($this->projectPermissionModel->getActiveProjectIds($user['id']), 100), 'user' => $user, ))); } @@ -169,7 +159,7 @@ class App extends Base */ public function calendar() { - $this->response->html($this->helper->layout->dashboard('app/calendar', array( + $this->response->html($this->helper->layout->dashboard('dashboard/calendar', array( 'title' => t('My calendar'), 'user' => $this->getUser(), ))); @@ -184,9 +174,9 @@ class App extends Base { $user = $this->getUser(); - $this->response->html($this->helper->layout->dashboard('app/notifications', array( + $this->response->html($this->helper->layout->dashboard('dashboard/notifications', array( 'title' => t('My notifications'), - 'notifications' => $this->userUnreadNotification->getAll($user['id']), + 'notifications' => $this->userUnreadNotificationModel->getAll($user['id']), 'user' => $user, ))); } diff --git a/app/Controller/Doc.php b/app/Controller/DocumentationController.php index 00b9e585..d86fb3c8 100644 --- a/app/Controller/Doc.php +++ b/app/Controller/DocumentationController.php @@ -7,10 +7,10 @@ use Parsedown; /** * Documentation Viewer * - * @package controller + * @package Kanboard\Controller * @author Frederic Guillot */ -class Doc extends Base +class DocumentationController extends BaseController { public function show() { @@ -20,7 +20,7 @@ class Doc extends Base $page = 'index'; } - if ($this->config->getCurrentLanguage() === 'fr_FR') { + if ($this->languageModel->getCurrentLanguage() === 'fr_FR') { $filename = __DIR__.'/../../doc/fr/' . $page . '.markdown'; } else { $filename = __DIR__ . '/../../doc/' . $page . '.markdown'; @@ -71,7 +71,7 @@ class Doc extends Base */ public function replaceMarkdownUrl(array $matches) { - return '('.$this->helper->url->to('doc', 'show', array('file' => str_replace('.markdown', '', $matches[1]))).')'; + return '('.$this->helper->url->to('DocumentationController', 'show', array('file' => str_replace('.markdown', '', $matches[1]))).')'; } /** @@ -83,7 +83,7 @@ class Doc extends Base */ public function replaceImageUrl(array $matches) { - if ($this->config->getCurrentLanguage() === 'fr_FR') { + if ($this->languageModel->getCurrentLanguage() === 'fr_FR') { return '('.$this->helper->url->base().'doc/fr/'.$matches[1].')'; } diff --git a/app/Controller/Export.php b/app/Controller/ExportController.php index c2ff652e..b2fe0ebd 100644 --- a/app/Controller/Export.php +++ b/app/Controller/ExportController.php @@ -3,17 +3,23 @@ namespace Kanboard\Controller; /** - * Export controller + * Export Controller * - * @package controller + * @package Kanboard\Controller * @author Frederic Guillot */ -class Export extends Base +class ExportController extends BaseController { /** * Common export method * * @access private + * @param string $model + * @param string $method + * @param string $filename + * @param string $action + * @param string $page_title + * @throws \Kanboard\Core\Controller\PageNotFoundException */ private function common($model, $method, $filename, $action, $page_title) { @@ -23,20 +29,20 @@ class Export extends Base if ($from && $to) { $data = $this->$model->$method($project['id'], $from, $to); - $this->response->forceDownload($filename.'.csv'); + $this->response->withFileDownload($filename.'.csv'); $this->response->csv($data); } $this->response->html($this->helper->layout->project('export/'.$action, array( 'values' => array( - 'controller' => 'export', + 'controller' => 'ExportController', 'action' => $action, 'project_id' => $project['id'], 'from' => $from, 'to' => $to, ), 'errors' => array(), - 'date_format' => $this->config->get('application_date_format'), + 'date_format' => $this->configModel->get('application_date_format'), 'date_formats' => $this->dateParser->getAvailableFormats($this->dateParser->getDateFormats()), 'project' => $project, 'title' => $page_title, diff --git a/app/Controller/Feed.php b/app/Controller/FeedController.php index f8b3d320..cf2b1088 100644 --- a/app/Controller/Feed.php +++ b/app/Controller/FeedController.php @@ -2,13 +2,15 @@ namespace Kanboard\Controller; +use Kanboard\Core\Controller\AccessForbiddenException; + /** * Atom/RSS Feed controller * - * @package controller + * @package Kanboard\Controller * @author Frederic Guillot */ -class Feed extends Base +class FeedController extends BaseController { /** * RSS feed for a user @@ -18,15 +20,15 @@ class Feed extends Base public function user() { $token = $this->request->getStringParam('token'); - $user = $this->user->getByToken($token); + $user = $this->userModel->getByToken($token); // Token verification if (empty($user)) { - $this->forbidden(true); + throw AccessForbiddenException::getInstance()->withoutLayout(); } $this->response->xml($this->template->render('feed/user', array( - 'events' => $this->helper->projectActivity->getProjectsEvents($this->projectPermission->getActiveProjectIds($user['id'])), + 'events' => $this->helper->projectActivity->getProjectsEvents($this->projectPermissionModel->getActiveProjectIds($user['id'])), 'user' => $user, ))); } @@ -39,11 +41,10 @@ class Feed extends Base public function project() { $token = $this->request->getStringParam('token'); - $project = $this->project->getByToken($token); + $project = $this->projectModel->getByToken($token); - // Token verification if (empty($project)) { - $this->forbidden(true); + throw AccessForbiddenException::getInstance()->withoutLayout(); } $this->response->xml($this->template->render('feed/project', array( diff --git a/app/Controller/FileViewer.php b/app/Controller/FileViewerController.php index 3be4ea14..518f5b0b 100644 --- a/app/Controller/FileViewer.php +++ b/app/Controller/FileViewerController.php @@ -7,10 +7,10 @@ use Kanboard\Core\ObjectStorage\ObjectStorageException; /** * File Viewer Controller * - * @package controller + * @package Kanbaord\Controller * @author Frederic Guillot */ -class FileViewer extends Base +class FileViewerController extends BaseController { /** * Get file content from object storage @@ -24,11 +24,9 @@ class FileViewer extends Base $content = ''; try { - if ($file['is_image'] == 0) { $content = $this->objectStorage->get($file['path']); } - } catch (ObjectStorageException $e) { $this->logger->error($e->getMessage()); } @@ -47,7 +45,7 @@ class FileViewer extends Base $type = $this->helper->file->getPreviewType($file['name']); $params = array('file_id' => $file['id'], 'project_id' => $this->request->getIntegerParam('project_id')); - if ($file['model'] === 'taskFile') { + if ($file['model'] === 'taskFileModel') { $params['task_id'] = $file['task_id']; } @@ -68,17 +66,19 @@ class FileViewer extends Base { $file = $this->getFile(); $etag = md5($file['path']); - $this->response->contentType($this->helper->file->getImageMimeType($file['name'])); - $this->response->cache(5 * 86400, $etag); + $this->response->withContentType($this->helper->file->getImageMimeType($file['name'])); + $this->response->withCache(5 * 86400, $etag); if ($this->request->getHeader('If-None-Match') === '"'.$etag.'"') { - return $this->response->status(304); - } + $this->response->status(304); + } else { - try { - $this->objectStorage->output($file['path']); - } catch (ObjectStorageException $e) { - $this->logger->error($e->getMessage()); + try { + $this->response->send(); + $this->objectStorage->output($file['path']); + } catch (ObjectStorageException $e) { + $this->logger->error($e->getMessage()); + } } } @@ -94,23 +94,26 @@ class FileViewer extends Base $filename = $this->$model->getThumbnailPath($file['path']); $etag = md5($filename); - $this->response->cache(5 * 86400, $etag); - $this->response->contentType('image/jpeg'); + $this->response->withCache(5 * 86400, $etag); + $this->response->withContentType('image/jpeg'); if ($this->request->getHeader('If-None-Match') === '"'.$etag.'"') { - return $this->response->status(304); - } + $this->response->status(304); + } else { - try { + $this->response->send(); - $this->objectStorage->output($filename); - } catch (ObjectStorageException $e) { - $this->logger->error($e->getMessage()); + try { + + $this->objectStorage->output($filename); + } catch (ObjectStorageException $e) { + $this->logger->error($e->getMessage()); - // Try to generate thumbnail on the fly for images uploaded before Kanboard < 1.0.19 - $data = $this->objectStorage->get($file['path']); - $this->$model->generateThumbnailFromData($file['path'], $data); - $this->objectStorage->output($this->$model->getThumbnailPath($file['path'])); + // Try to generate thumbnail on the fly for images uploaded before Kanboard < 1.0.19 + $data = $this->objectStorage->get($file['path']); + $this->$model->generateThumbnailFromData($file['path'], $data); + $this->objectStorage->output($this->$model->getThumbnailPath($file['path'])); + } } } @@ -123,7 +126,8 @@ class FileViewer extends Base { try { $file = $this->getFile(); - $this->response->forceDownload($file['name']); + $this->response->withFileDownload($file['name']); + $this->response->send(); $this->objectStorage->output($file['path']); } catch (ObjectStorageException $e) { $this->logger->error($e->getMessage()); diff --git a/app/Controller/Gantt.php b/app/Controller/Gantt.php deleted file mode 100644 index 5e9ad55e..00000000 --- a/app/Controller/Gantt.php +++ /dev/null @@ -1,162 +0,0 @@ -<?php - -namespace Kanboard\Controller; - -use Kanboard\Filter\ProjectIdsFilter; -use Kanboard\Filter\ProjectStatusFilter; -use Kanboard\Filter\ProjectTypeFilter; -use Kanboard\Filter\TaskProjectFilter; -use Kanboard\Formatter\ProjectGanttFormatter; -use Kanboard\Formatter\TaskGanttFormatter; -use Kanboard\Model\Task as TaskModel; -use Kanboard\Model\Project as ProjectModel; - -/** - * Gantt controller - * - * @package controller - * @author Frederic Guillot - */ -class Gantt extends Base -{ - /** - * Show Gantt chart for all projects - */ - public function projects() - { - $project_ids = $this->projectPermission->getActiveProjectIds($this->userSession->getId()); - $filter = $this->projectQuery - ->withFilter(new ProjectTypeFilter(ProjectModel::TYPE_TEAM)) - ->withFilter(new ProjectStatusFilter(ProjectModel::ACTIVE)) - ->withFilter(new ProjectIdsFilter($project_ids)); - - $filter->getQuery()->asc(ProjectModel::TABLE.'.start_date'); - - $this->response->html($this->helper->layout->app('gantt/projects', array( - 'projects' => $filter->format(new ProjectGanttFormatter($this->container)), - 'title' => t('Gantt chart for all projects'), - ))); - } - - /** - * Save new project start date and end date - */ - public function saveProjectDate() - { - $values = $this->request->getJson(); - - $result = $this->project->update(array( - 'id' => $values['id'], - 'start_date' => $this->dateParser->getIsoDate(strtotime($values['start'])), - 'end_date' => $this->dateParser->getIsoDate(strtotime($values['end'])), - )); - - if (! $result) { - $this->response->json(array('message' => 'Unable to save project'), 400); - } - - $this->response->json(array('message' => 'OK'), 201); - } - - /** - * Show Gantt chart for one project - */ - public function project() - { - $project = $this->getProject(); - $search = $this->helper->projectHeader->getSearchQuery($project); - $sorting = $this->request->getStringParam('sorting', 'board'); - $filter = $this->taskLexer->build($search)->withFilter(new TaskProjectFilter($project['id'])); - - if ($sorting === 'date') { - $filter->getQuery()->asc(TaskModel::TABLE.'.date_started')->asc(TaskModel::TABLE.'.date_creation'); - } else { - $filter->getQuery()->asc('column_position')->asc(TaskModel::TABLE.'.position'); - } - - $this->response->html($this->helper->layout->app('gantt/project', array( - 'project' => $project, - 'title' => $project['name'], - 'description' => $this->helper->projectHeader->getDescription($project), - 'sorting' => $sorting, - 'tasks' => $filter->format(new TaskGanttFormatter($this->container)), - ))); - } - - /** - * Save new task start date and due date - */ - public function saveTaskDate() - { - $this->getProject(); - $values = $this->request->getJson(); - - $result = $this->taskModification->update(array( - 'id' => $values['id'], - 'date_started' => strtotime($values['start']), - 'date_due' => strtotime($values['end']), - )); - - if (! $result) { - $this->response->json(array('message' => 'Unable to save task'), 400); - } - - $this->response->json(array('message' => 'OK'), 201); - } - - /** - * Simplified form to create a new task - * - * @access public - */ - public function task(array $values = array(), array $errors = array()) - { - $project = $this->getProject(); - - $values = $values + array( - 'project_id' => $project['id'], - 'column_id' => $this->column->getFirstColumnId($project['id']), - 'position' => 1 - ); - - $values = $this->hook->merge('controller:task:form:default', $values, array('default_values' => $values)); - $values = $this->hook->merge('controller:gantt:task:form:default', $values, array('default_values' => $values)); - - $this->response->html($this->template->render('gantt/task_creation', array( - 'project' => $project, - 'errors' => $errors, - 'values' => $values, - 'users_list' => $this->projectUserRole->getAssignableUsersList($project['id'], true, false, true), - 'colors_list' => $this->color->getList(), - 'categories_list' => $this->category->getList($project['id']), - 'swimlanes_list' => $this->swimlane->getList($project['id'], false, true), - 'title' => $project['name'].' > '.t('New task') - ))); - } - - /** - * Validate and save a new task - * - * @access public - */ - public function saveTask() - { - $project = $this->getProject(); - $values = $this->request->getValues(); - - list($valid, $errors) = $this->taskValidator->validateCreation($values); - - if ($valid) { - $task_id = $this->taskCreation->create($values); - - if ($task_id !== false) { - $this->flash->success(t('Task created successfully.')); - $this->response->redirect($this->helper->url->to('gantt', 'project', array('project_id' => $project['id']))); - } else { - $this->flash->failure(t('Unable to create your task.')); - } - } - - $this->task($values, $errors); - } -} diff --git a/app/Controller/Group.php b/app/Controller/Group.php deleted file mode 100644 index fa47f428..00000000 --- a/app/Controller/Group.php +++ /dev/null @@ -1,250 +0,0 @@ -<?php - -namespace Kanboard\Controller; - -/** - * Group Controller - * - * @package controller - * @author Frederic Guillot - */ -class Group extends Base -{ - /** - * List all groups - * - * @access public - */ - public function index() - { - $paginator = $this->paginator - ->setUrl('group', 'index') - ->setMax(30) - ->setOrder('name') - ->setQuery($this->group->getQuery()) - ->calculate(); - - $this->response->html($this->helper->layout->app('group/index', array( - 'title' => t('Groups').' ('.$paginator->getTotal().')', - 'paginator' => $paginator, - ))); - } - - /** - * List all users - * - * @access public - */ - public function users() - { - $group_id = $this->request->getIntegerParam('group_id'); - $group = $this->group->getById($group_id); - - $paginator = $this->paginator - ->setUrl('group', 'users', array('group_id' => $group_id)) - ->setMax(30) - ->setOrder('username') - ->setQuery($this->groupMember->getQuery($group_id)) - ->calculate(); - - $this->response->html($this->helper->layout->app('group/users', array( - 'title' => t('Members of %s', $group['name']).' ('.$paginator->getTotal().')', - 'paginator' => $paginator, - 'group' => $group, - ))); - } - - /** - * Display a form to create a new group - * - * @access public - */ - public function create(array $values = array(), array $errors = array()) - { - $this->response->html($this->helper->layout->app('group/create', array( - 'errors' => $errors, - 'values' => $values, - 'title' => t('New group') - ))); - } - - /** - * Validate and save a new group - * - * @access public - */ - public function save() - { - $values = $this->request->getValues(); - list($valid, $errors) = $this->groupValidator->validateCreation($values); - - if ($valid) { - if ($this->group->create($values['name']) !== false) { - $this->flash->success(t('Group created successfully.')); - $this->response->redirect($this->helper->url->to('group', 'index')); - } else { - $this->flash->failure(t('Unable to create your group.')); - } - } - - $this->create($values, $errors); - } - - /** - * Display a form to update a group - * - * @access public - */ - public function edit(array $values = array(), array $errors = array()) - { - if (empty($values)) { - $values = $this->group->getById($this->request->getIntegerParam('group_id')); - } - - $this->response->html($this->helper->layout->app('group/edit', array( - 'errors' => $errors, - 'values' => $values, - 'title' => t('Edit group') - ))); - } - - /** - * Validate and save a group - * - * @access public - */ - public function update() - { - $values = $this->request->getValues(); - list($valid, $errors) = $this->groupValidator->validateModification($values); - - if ($valid) { - if ($this->group->update($values) !== false) { - $this->flash->success(t('Group updated successfully.')); - $this->response->redirect($this->helper->url->to('group', 'index')); - } else { - $this->flash->failure(t('Unable to update your group.')); - } - } - - $this->edit($values, $errors); - } - - /** - * Form to associate a user to a group - * - * @access public - */ - public function associate(array $values = array(), array $errors = array()) - { - $group_id = $this->request->getIntegerParam('group_id'); - $group = $this->group->getbyId($group_id); - - if (empty($values)) { - $values['group_id'] = $group_id; - } - - $this->response->html($this->helper->layout->app('group/associate', array( - 'users' => $this->user->prepareList($this->groupMember->getNotMembers($group_id)), - 'group' => $group, - 'errors' => $errors, - 'values' => $values, - 'title' => t('Add group member to "%s"', $group['name']), - ))); - } - - /** - * Add user to a group - * - * @access public - */ - public function addUser() - { - $values = $this->request->getValues(); - - if (isset($values['group_id']) && isset($values['user_id'])) { - if ($this->groupMember->addUser($values['group_id'], $values['user_id'])) { - $this->flash->success(t('Group member added successfully.')); - $this->response->redirect($this->helper->url->to('group', 'users', array('group_id' => $values['group_id']))); - } else { - $this->flash->failure(t('Unable to add group member.')); - } - } - - $this->associate($values); - } - - /** - * Confirmation dialog to remove a user from a group - * - * @access public - */ - public function dissociate() - { - $group_id = $this->request->getIntegerParam('group_id'); - $user_id = $this->request->getIntegerParam('user_id'); - $group = $this->group->getById($group_id); - $user = $this->user->getById($user_id); - - $this->response->html($this->helper->layout->app('group/dissociate', array( - 'group' => $group, - 'user' => $user, - 'title' => t('Remove user from group "%s"', $group['name']), - ))); - } - - /** - * Remove a user from a group - * - * @access public - */ - public function removeUser() - { - $this->checkCSRFParam(); - $group_id = $this->request->getIntegerParam('group_id'); - $user_id = $this->request->getIntegerParam('user_id'); - - if ($this->groupMember->removeUser($group_id, $user_id)) { - $this->flash->success(t('User removed successfully from this group.')); - } else { - $this->flash->failure(t('Unable to remove this user from the group.')); - } - - $this->response->redirect($this->helper->url->to('group', 'users', array('group_id' => $group_id))); - } - - /** - * Confirmation dialog to remove a group - * - * @access public - */ - public function confirm() - { - $group_id = $this->request->getIntegerParam('group_id'); - $group = $this->group->getById($group_id); - - $this->response->html($this->helper->layout->app('group/remove', array( - 'group' => $group, - 'title' => t('Remove group'), - ))); - } - - /** - * Remove a group - * - * @access public - */ - public function remove() - { - $this->checkCSRFParam(); - $group_id = $this->request->getIntegerParam('group_id'); - - if ($this->group->remove($group_id)) { - $this->flash->success(t('Group removed successfully.')); - } else { - $this->flash->failure(t('Unable to remove this group.')); - } - - $this->response->redirect($this->helper->url->to('group', 'index')); - } -} diff --git a/app/Controller/GroupHelper.php b/app/Controller/GroupAjaxController.php index 429614c2..496e9ef2 100644 --- a/app/Controller/GroupHelper.php +++ b/app/Controller/GroupAjaxController.php @@ -5,12 +5,12 @@ namespace Kanboard\Controller; use Kanboard\Formatter\GroupAutoCompleteFormatter; /** - * Group Helper + * Group Ajax Controller * - * @package controller - * @author Frederic Guillot + * @package Kanboard\Controller + * @author Frederic Guillot */ -class GroupHelper extends Base +class GroupAjaxController extends BaseController { /** * Group auto-completion (Ajax) diff --git a/app/Controller/GroupCreationController.php b/app/Controller/GroupCreationController.php new file mode 100644 index 00000000..b297b19f --- /dev/null +++ b/app/Controller/GroupCreationController.php @@ -0,0 +1,49 @@ +<?php + +namespace Kanboard\Controller; + +/** + * Class GroupCreationController + * + * @package Kanboard\Controller + * @author Frederic Guillot + */ +class GroupCreationController extends BaseController +{ + /** + * Display a form to create a new group + * + * @access public + * @param array $values + * @param array $errors + */ + public function show(array $values = array(), array $errors = array()) + { + $this->response->html($this->template->render('group_creation/show', array( + 'errors' => $errors, + 'values' => $values, + ))); + } + + /** + * Validate and save a new group + * + * @access public + */ + public function save() + { + $values = $this->request->getValues(); + list($valid, $errors) = $this->groupValidator->validateCreation($values); + + if ($valid) { + if ($this->groupModel->create($values['name']) !== false) { + $this->flash->success(t('Group created successfully.')); + return $this->response->redirect($this->helper->url->to('GroupListController', 'index'), true); + } else { + $this->flash->failure(t('Unable to create your group.')); + } + } + + return $this->show($values, $errors); + } +} diff --git a/app/Controller/GroupListController.php b/app/Controller/GroupListController.php new file mode 100644 index 00000000..4486bbff --- /dev/null +++ b/app/Controller/GroupListController.php @@ -0,0 +1,173 @@ +<?php + +namespace Kanboard\Controller; + +/** + * Group Controller + * + * @package Kanboard\Controller + * @author Frederic Guillot + */ +class GroupListController extends BaseController +{ + /** + * List all groups + * + * @access public + */ + public function index() + { + $paginator = $this->paginator + ->setUrl('GroupListController', 'index') + ->setMax(30) + ->setOrder('name') + ->setQuery($this->groupModel->getQuery()) + ->calculate(); + + $this->response->html($this->helper->layout->app('group/index', array( + 'title' => t('Groups').' ('.$paginator->getTotal().')', + 'paginator' => $paginator, + ))); + } + + /** + * List all users + * + * @access public + */ + public function users() + { + $group_id = $this->request->getIntegerParam('group_id'); + $group = $this->groupModel->getById($group_id); + + $paginator = $this->paginator + ->setUrl('GroupListController', 'users', array('group_id' => $group_id)) + ->setMax(30) + ->setOrder('username') + ->setQuery($this->groupMemberModel->getQuery($group_id)) + ->calculate(); + + $this->response->html($this->helper->layout->app('group/users', array( + 'title' => t('Members of %s', $group['name']).' ('.$paginator->getTotal().')', + 'paginator' => $paginator, + 'group' => $group, + ))); + } + + /** + * Form to associate a user to a group + * + * @access public + * @param array $values + * @param array $errors + */ + public function associate(array $values = array(), array $errors = array()) + { + $group_id = $this->request->getIntegerParam('group_id'); + $group = $this->groupModel->getById($group_id); + + if (empty($values)) { + $values['group_id'] = $group_id; + } + + $this->response->html($this->template->render('group/associate', array( + 'users' => $this->userModel->prepareList($this->groupMemberModel->getNotMembers($group_id)), + 'group' => $group, + 'errors' => $errors, + 'values' => $values, + ))); + } + + /** + * Add user to a group + * + * @access public + */ + public function addUser() + { + $values = $this->request->getValues(); + + if (isset($values['group_id']) && isset($values['user_id'])) { + if ($this->groupMemberModel->addUser($values['group_id'], $values['user_id'])) { + $this->flash->success(t('Group member added successfully.')); + return $this->response->redirect($this->helper->url->to('GroupListController', 'users', array('group_id' => $values['group_id'])), true); + } else { + $this->flash->failure(t('Unable to add group member.')); + } + } + + return $this->associate($values); + } + + /** + * Confirmation dialog to remove a user from a group + * + * @access public + */ + public function dissociate() + { + $group_id = $this->request->getIntegerParam('group_id'); + $user_id = $this->request->getIntegerParam('user_id'); + $group = $this->groupModel->getById($group_id); + $user = $this->userModel->getById($user_id); + + $this->response->html($this->template->render('group/dissociate', array( + 'group' => $group, + 'user' => $user, + ))); + } + + /** + * Remove a user from a group + * + * @access public + */ + public function removeUser() + { + $this->checkCSRFParam(); + $group_id = $this->request->getIntegerParam('group_id'); + $user_id = $this->request->getIntegerParam('user_id'); + + if ($this->groupMemberModel->removeUser($group_id, $user_id)) { + $this->flash->success(t('User removed successfully from this group.')); + } else { + $this->flash->failure(t('Unable to remove this user from the group.')); + } + + $this->response->redirect($this->helper->url->to('GroupListController', 'users', array('group_id' => $group_id)), true); + } + + /** + * Confirmation dialog to remove a group + * + * @access public + */ + public function confirm() + { + $group_id = $this->request->getIntegerParam('group_id'); + $group = $this->groupModel->getById($group_id); + + $this->response->html($this->template->render('group/remove', array( + 'group' => $group, + ))); + } + + /** + * Remove a group + * + * @access public + */ + public function remove() + { + $this->checkCSRFParam(); + $group_id = $this->request->getIntegerParam('group_id'); + + if ($this->groupModel->remove($group_id)) { + $this->flash->success(t('Group removed successfully.')); + } else { + $this->flash->failure(t('Unable to remove this group.')); + } + + $this->response->redirect($this->helper->url->to('GroupListController', 'index'), true); + } +} diff --git a/app/Controller/GroupModificationController.php b/app/Controller/GroupModificationController.php new file mode 100644 index 00000000..bd181b74 --- /dev/null +++ b/app/Controller/GroupModificationController.php @@ -0,0 +1,53 @@ +<?php + +namespace Kanboard\Controller; + +/** + * Class GroupModificationController + * + * @package Kanboard\Controller + * @author Frederic Guillot + */ +class GroupModificationController extends BaseController +{ + /** + * Display a form to update a group + * + * @access public + * @param array $values + * @param array $errors + */ + public function show(array $values = array(), array $errors = array()) + { + if (empty($values)) { + $values = $this->groupModel->getById($this->request->getIntegerParam('group_id')); + } + + $this->response->html($this->template->render('group_modification/show', array( + 'errors' => $errors, + 'values' => $values, + ))); + } + + /** + * Validate and save a group + * + * @access public + */ + public function save() + { + $values = $this->request->getValues(); + list($valid, $errors) = $this->groupValidator->validateModification($values); + + if ($valid) { + if ($this->groupModel->update($values) !== false) { + $this->flash->success(t('Group updated successfully.')); + return $this->response->redirect($this->helper->url->to('GroupListController', 'index'), true); + } else { + $this->flash->failure(t('Unable to update your group.')); + } + } + + return $this->show($values, $errors); + } +} diff --git a/app/Controller/Ical.php b/app/Controller/ICalendarController.php index 8fe97b46..e354c6f1 100644 --- a/app/Controller/Ical.php +++ b/app/Controller/ICalendarController.php @@ -2,21 +2,22 @@ namespace Kanboard\Controller; +use Kanboard\Core\Controller\AccessForbiddenException; use Kanboard\Core\Filter\QueryBuilder; use Kanboard\Filter\TaskAssigneeFilter; use Kanboard\Filter\TaskProjectFilter; use Kanboard\Filter\TaskStatusFilter; use Kanboard\Formatter\TaskICalFormatter; -use Kanboard\Model\Task as TaskModel; +use Kanboard\Model\TaskModel; use Eluceo\iCal\Component\Calendar as iCalendar; /** - * iCalendar controller + * iCalendar Controller * - * @package controller + * @package Kanboard\Controller * @author Frederic Guillot */ -class Ical extends Base +class ICalendarController extends BaseController { /** * Get user iCalendar @@ -26,17 +27,17 @@ class Ical extends Base public function user() { $token = $this->request->getStringParam('token'); - $user = $this->user->getByToken($token); + $user = $this->userModel->getByToken($token); // Token verification if (empty($user)) { - $this->forbidden(true); + throw AccessForbiddenException::getInstance()->withoutLayout(); } // Common filter $queryBuilder = new QueryBuilder(); $queryBuilder - ->withQuery($this->taskFinder->getICalQuery()) + ->withQuery($this->taskFinderModel->getICalQuery()) ->withFilter(new TaskStatusFilter(TaskModel::STATUS_OPEN)) ->withFilter(new TaskAssigneeFilter($user['id'])); @@ -57,17 +58,17 @@ class Ical extends Base public function project() { $token = $this->request->getStringParam('token'); - $project = $this->project->getByToken($token); + $project = $this->projectModel->getByToken($token); // Token verification if (empty($project)) { - $this->forbidden(true); + throw AccessForbiddenException::getInstance()->withoutLayout(); } // Common filter $queryBuilder = new QueryBuilder(); $queryBuilder - ->withQuery($this->taskFinder->getICalQuery()) + ->withQuery($this->taskFinderModel->getICalQuery()) ->withFilter(new TaskStatusFilter(TaskModel::STATUS_OPEN)) ->withFilter(new TaskProjectFilter($project['id'])); @@ -84,6 +85,8 @@ class Ical extends Base * Common method to render iCal events * * @access private + * @param QueryBuilder $queryBuilder + * @param iCalendar $calendar */ private function renderCalendar(QueryBuilder $queryBuilder, iCalendar $calendar) { diff --git a/app/Controller/Link.php b/app/Controller/LinkController.php index ec7ab1af..477b25a4 100644 --- a/app/Controller/Link.php +++ b/app/Controller/LinkController.php @@ -2,27 +2,30 @@ namespace Kanboard\Controller; +use Kanboard\Core\Controller\PageNotFoundException; + /** - * Link controller + * Link Controller * - * @package controller + * @package Kanboard\Controller * @author Olivier Maridat * @author Frederic Guillot */ -class Link extends Base +class LinkController extends BaseController { /** * Get the current link * * @access private * @return array + * @throws PageNotFoundException */ private function getLink() { - $link = $this->link->getById($this->request->getIntegerParam('link_id')); + $link = $this->linkModel->getById($this->request->getIntegerParam('link_id')); if (empty($link)) { - $this->notfound(); + throw new PageNotFoundException(); } return $link; @@ -32,11 +35,13 @@ class Link extends Base * List of links * * @access public + * @param array $values + * @param array $errors */ public function index(array $values = array(), array $errors = array()) { $this->response->html($this->helper->layout->config('link/index', array( - 'links' => $this->link->getMergedList(), + 'links' => $this->linkModel->getMergedList(), 'values' => $values, 'errors' => $errors, 'title' => t('Settings').' > '.t('Task\'s links'), @@ -54,21 +59,24 @@ class Link extends Base list($valid, $errors) = $this->linkValidator->validateCreation($values); if ($valid) { - if ($this->link->create($values['label'], $values['opposite_label']) !== false) { + if ($this->linkModel->create($values['label'], $values['opposite_label']) !== false) { $this->flash->success(t('Link added successfully.')); - $this->response->redirect($this->helper->url->to('link', 'index')); + return $this->response->redirect($this->helper->url->to('LinkController', 'index')); } else { $this->flash->failure(t('Unable to create your link.')); } } - $this->index($values, $errors); + return $this->index($values, $errors); } /** * Edit form * * @access public + * @param array $values + * @param array $errors + * @throws PageNotFoundException */ public function edit(array $values = array(), array $errors = array()) { @@ -78,7 +86,7 @@ class Link extends Base $this->response->html($this->helper->layout->config('link/edit', array( 'values' => $values ?: $link, 'errors' => $errors, - 'labels' => $this->link->getList($link['id']), + 'labels' => $this->linkModel->getList($link['id']), 'link' => $link, 'title' => t('Link modification') ))); @@ -95,15 +103,15 @@ class Link extends Base list($valid, $errors) = $this->linkValidator->validateModification($values); if ($valid) { - if ($this->link->update($values)) { + if ($this->linkModel->update($values)) { $this->flash->success(t('Link updated successfully.')); - $this->response->redirect($this->helper->url->to('link', 'index')); + return $this->response->redirect($this->helper->url->to('LinkController', 'index')); } else { $this->flash->failure(t('Unable to update your link.')); } } - $this->edit($values, $errors); + return $this->edit($values, $errors); } /** @@ -131,12 +139,12 @@ class Link extends Base $this->checkCSRFParam(); $link = $this->getLink(); - if ($this->link->remove($link['id'])) { + if ($this->linkModel->remove($link['id'])) { $this->flash->success(t('Link removed successfully.')); } else { $this->flash->failure(t('Unable to remove this link.')); } - $this->response->redirect($this->helper->url->to('link', 'index')); + $this->response->redirect($this->helper->url->to('LinkController', 'index')); } } diff --git a/app/Controller/Oauth.php b/app/Controller/OAuthController.php index 12b91144..7663ddcc 100644 --- a/app/Controller/Oauth.php +++ b/app/Controller/OAuthController.php @@ -5,12 +5,12 @@ namespace Kanboard\Controller; use Kanboard\Core\Security\OAuthAuthenticationProviderInterface; /** - * OAuth controller + * OAuth Controller * - * @package controller + * @package Kanboard\Controller * @author Frederic Guillot */ -class Oauth extends Base +class OAuthController extends BaseController { /** * Redirect to the provider if no code received @@ -49,7 +49,7 @@ class Oauth extends Base $this->link($provider); } else { $this->flash->failure(t('The OAuth2 state parameter is invalid')); - $this->response->redirect($this->helper->url->to('user', 'external', array('user_id' => $this->userSession->getId()))); + $this->response->redirect($this->helper->url->to('UserViewController', 'external', array('user_id' => $this->userSession->getId()))); } } else { if ($hasValidState) { @@ -75,7 +75,7 @@ class Oauth extends Base $this->flash->success(t('Your external account is linked to your profile successfully.')); } - $this->response->redirect($this->helper->url->to('user', 'external', array('user_id' => $this->userSession->getId()))); + $this->response->redirect($this->helper->url->to('UserViewController', 'external', array('user_id' => $this->userSession->getId()))); } /** @@ -94,7 +94,7 @@ class Oauth extends Base $this->flash->failure(t('Unable to unlink your external account.')); } - $this->response->redirect($this->helper->url->to('user', 'external', array('user_id' => $this->userSession->getId()))); + $this->response->redirect($this->helper->url->to('UserViewController', 'external', array('user_id' => $this->userSession->getId()))); } /** @@ -106,7 +106,7 @@ class Oauth extends Base protected function authenticate($providerName) { if ($this->authenticationManager->oauthAuthentication($providerName)) { - $this->response->redirect($this->helper->url->to('app', 'index')); + $this->response->redirect($this->helper->url->to('DashboardController', 'show')); } else { $this->authenticationFailure(t('External authentication failed')); } diff --git a/app/Controller/PasswordReset.php b/app/Controller/PasswordResetController.php index f6a0eb8e..18b4be80 100644 --- a/app/Controller/PasswordReset.php +++ b/app/Controller/PasswordResetController.php @@ -2,13 +2,15 @@ namespace Kanboard\Controller; +use Kanboard\Core\Controller\AccessForbiddenException; + /** * Password Reset Controller * - * @package controller + * @package Kanboard\Controller * @author Frederic Guillot */ -class PasswordReset extends Base +class PasswordResetController extends BaseController { /** * Show the form to reset the password @@ -36,10 +38,10 @@ class PasswordReset extends Base if ($valid) { $this->sendEmail($values['username']); - $this->response->redirect($this->helper->url->to('auth', 'login')); + $this->response->redirect($this->helper->url->to('AuthController', 'login')); + } else { + $this->create($values, $errors); } - - $this->create($values, $errors); } /** @@ -50,7 +52,7 @@ class PasswordReset extends Base $this->checkActivation(); $token = $this->request->getStringParam('token'); - $user_id = $this->passwordReset->getUserIdByToken($token); + $user_id = $this->passwordResetModel->getUserIdByToken($token); if ($user_id !== false) { $this->response->html($this->helper->layout->app('password_reset/change', array( @@ -59,9 +61,9 @@ class PasswordReset extends Base 'values' => $values, 'no_layout' => true, ))); + } else { + $this->response->redirect($this->helper->url->to('AuthController', 'login')); } - - $this->response->redirect($this->helper->url->to('auth', 'login')); } /** @@ -76,17 +78,17 @@ class PasswordReset extends Base list($valid, $errors) = $this->passwordResetValidator->validateModification($values); if ($valid) { - $user_id = $this->passwordReset->getUserIdByToken($token); + $user_id = $this->passwordResetModel->getUserIdByToken($token); if ($user_id !== false) { - $this->user->update(array('id' => $user_id, 'password' => $values['password'])); - $this->passwordReset->disable($user_id); + $this->userModel->update(array('id' => $user_id, 'password' => $values['password'])); + $this->passwordResetModel->disable($user_id); } - $this->response->redirect($this->helper->url->to('auth', 'login')); + return $this->response->redirect($this->helper->url->to('AuthController', 'login')); } - $this->change($values, $errors); + return $this->change($values, $errors); } /** @@ -94,10 +96,10 @@ class PasswordReset extends Base */ private function sendEmail($username) { - $token = $this->passwordReset->create($username); + $token = $this->passwordResetModel->create($username); if ($token !== false) { - $user = $this->user->getByUsername($username); + $user = $this->userModel->getByUsername($username); $this->emailClient->send( $user['email'], @@ -113,8 +115,8 @@ class PasswordReset extends Base */ private function checkActivation() { - if ($this->config->get('password_reset', 0) == 0) { - $this->response->redirect($this->helper->url->to('auth', 'login')); + if ($this->configModel->get('password_reset', 0) == 0) { + throw AccessForbiddenException::getInstance()->withoutLayout(); } } } diff --git a/app/Controller/PluginController.php b/app/Controller/PluginController.php new file mode 100644 index 00000000..7b9d64d9 --- /dev/null +++ b/app/Controller/PluginController.php @@ -0,0 +1,126 @@ +<?php + +namespace Kanboard\Controller; + +use Kanboard\Core\Plugin\Directory; +use Kanboard\Core\Plugin\Installer; +use Kanboard\Core\Plugin\PluginInstallerException; + +/** + * Class PluginController + * + * @package Kanboard\Controller + * @author Frederic Guillot + */ +class PluginController extends BaseController +{ + /** + * Display the plugin page + * + * @access public + */ + public function show() + { + $this->response->html($this->helper->layout->plugin('plugin/show', array( + 'plugins' => $this->pluginLoader->getPlugins(), + 'title' => t('Installed Plugins'), + 'is_configured' => Installer::isConfigured(), + ))); + } + + /** + * Display list of available plugins + */ + public function directory() + { + $installedPlugins = array(); + + foreach ($this->pluginLoader->getPlugins() as $plugin) { + $installedPlugins[$plugin->getPluginName()] = $plugin->getPluginVersion(); + } + + $this->response->html($this->helper->layout->plugin('plugin/directory', array( + 'installed_plugins' => $installedPlugins, + 'available_plugins' => Directory::getInstance($this->container)->getAvailablePlugins(), + 'title' => t('Plugin Directory'), + 'is_configured' => Installer::isConfigured(), + ))); + } + + /** + * Install plugin from URL + * + * @throws \Kanboard\Core\Controller\AccessForbiddenException + */ + public function install() + { + $this->checkCSRFParam(); + $pluginArchiveUrl = urldecode($this->request->getStringParam('archive_url')); + + try { + $installer = new Installer($this->container); + $installer->install($pluginArchiveUrl); + $this->flash->success(t('Plugin installed successfully.')); + } catch (PluginInstallerException $e) { + $this->flash->failure($e->getMessage()); + } + + $this->response->redirect($this->helper->url->to('PluginController', 'show')); + } + + /** + * Update plugin from URL + * + * @throws \Kanboard\Core\Controller\AccessForbiddenException + */ + public function update() + { + $this->checkCSRFParam(); + $pluginArchiveUrl = urldecode($this->request->getStringParam('archive_url')); + + try { + $installer = new Installer($this->container); + $installer->update($pluginArchiveUrl); + $this->flash->success(t('Plugin updated successfully.')); + } catch (PluginInstallerException $e) { + $this->flash->failure($e->getMessage()); + } + + $this->response->redirect($this->helper->url->to('PluginController', 'show')); + } + + /** + * Confirmation before to remove the plugin + */ + public function confirm() + { + $pluginId = $this->request->getStringParam('pluginId'); + $plugins = $this->pluginLoader->getPlugins(); + + $this->response->html($this->template->render('plugin/remove', array( + 'plugin_id' => $pluginId, + 'plugin' => $plugins[$pluginId], + ))); + } + + /** + * Remove a plugin + * + * @throws \Kanboard\Core\Controller\AccessForbiddenException + */ + public function uninstall() + { + $this->checkCSRFParam(); + $pluginId = $this->request->getStringParam('pluginId'); + + try { + $installer = new Installer($this->container); + $installer->uninstall($pluginId); + $this->flash->success(t('Plugin removed successfully.')); + } catch (PluginInstallerException $e) { + $this->flash->failure($e->getMessage()); + } + + $this->response->redirect($this->helper->url->to('PluginController', 'show')); + } +} diff --git a/app/Controller/Project.php b/app/Controller/Project.php deleted file mode 100644 index cdfbd94a..00000000 --- a/app/Controller/Project.php +++ /dev/null @@ -1,243 +0,0 @@ -<?php - -namespace Kanboard\Controller; - -/** - * Project controller (Settings + creation/edition) - * - * @package controller - * @author Frederic Guillot - */ -class Project extends Base -{ - /** - * List of projects - * - * @access public - */ - public function index() - { - if ($this->userSession->isAdmin()) { - $project_ids = $this->project->getAllIds(); - } else { - $project_ids = $this->projectPermission->getActiveProjectIds($this->userSession->getId()); - } - - $nb_projects = count($project_ids); - - $paginator = $this->paginator - ->setUrl('project', 'index') - ->setMax(20) - ->setOrder('name') - ->setQuery($this->project->getQueryColumnStats($project_ids)) - ->calculate(); - - $this->response->html($this->helper->layout->app('project/index', array( - 'paginator' => $paginator, - 'nb_projects' => $nb_projects, - 'title' => t('Projects').' ('.$nb_projects.')' - ))); - } - - /** - * Show the project information page - * - * @access public - */ - public function show() - { - $project = $this->getProject(); - - $this->response->html($this->helper->layout->project('project/show', array( - 'project' => $project, - 'stats' => $this->project->getTaskStats($project['id']), - 'title' => $project['name'], - ))); - } - - /** - * Public access management - * - * @access public - */ - public function share() - { - $project = $this->getProject(); - $switch = $this->request->getStringParam('switch'); - - if ($switch === 'enable' || $switch === 'disable') { - $this->checkCSRFParam(); - - if ($this->project->{$switch.'PublicAccess'}($project['id'])) { - $this->flash->success(t('Project updated successfully.')); - } else { - $this->flash->failure(t('Unable to update this project.')); - } - - $this->response->redirect($this->helper->url->to('project', 'share', array('project_id' => $project['id']))); - } - - $this->response->html($this->helper->layout->project('project/share', array( - 'project' => $project, - 'title' => t('Public access'), - ))); - } - - /** - * Integrations page - * - * @access public - */ - public function integrations() - { - $project = $this->getProject(); - - if ($this->request->isPost()) { - $this->projectMetadata->save($project['id'], $this->request->getValues()); - $this->flash->success(t('Project updated successfully.')); - $this->response->redirect($this->helper->url->to('project', 'integrations', array('project_id' => $project['id']))); - } - - $this->response->html($this->helper->layout->project('project/integrations', array( - 'project' => $project, - 'title' => t('Integrations'), - 'webhook_token' => $this->config->get('webhook_token'), - 'values' => $this->projectMetadata->getAll($project['id']), - 'errors' => array(), - ))); - } - - /** - * Display project notifications - * - * @access public - */ - public function notifications() - { - $project = $this->getProject(); - - if ($this->request->isPost()) { - $values = $this->request->getValues(); - $this->projectNotification->saveSettings($project['id'], $values); - $this->flash->success(t('Project updated successfully.')); - $this->response->redirect($this->helper->url->to('project', 'notifications', array('project_id' => $project['id']))); - } - - $this->response->html($this->helper->layout->project('project/notifications', array( - 'notifications' => $this->projectNotification->readSettings($project['id']), - 'types' => $this->projectNotificationType->getTypes(), - 'project' => $project, - 'title' => t('Notifications'), - ))); - } - - /** - * Remove a project - * - * @access public - */ - public function remove() - { - $project = $this->getProject(); - - if ($this->request->getStringParam('remove') === 'yes') { - $this->checkCSRFParam(); - - if ($this->project->remove($project['id'])) { - $this->flash->success(t('Project removed successfully.')); - } else { - $this->flash->failure(t('Unable to remove this project.')); - } - - $this->response->redirect($this->helper->url->to('project', 'index')); - } - - $this->response->html($this->helper->layout->project('project/remove', array( - 'project' => $project, - 'title' => t('Remove project') - ))); - } - - /** - * Duplicate a project - * - * @author Antonio Rabelo - * @author Michael Lüpkes - * @access public - */ - public function duplicate() - { - $project = $this->getProject(); - - if ($this->request->getStringParam('duplicate') === 'yes') { - $project_id = $this->projectDuplication->duplicate($project['id'], array_keys($this->request->getValues()), $this->userSession->getId()); - - if ($project_id !== false) { - $this->flash->success(t('Project cloned successfully.')); - } else { - $this->flash->failure(t('Unable to clone this project.')); - } - - $this->response->redirect($this->helper->url->to('project', 'show', array('project_id' => $project_id))); - } - - $this->response->html($this->helper->layout->project('project/duplicate', array( - 'project' => $project, - 'title' => t('Clone this project') - ))); - } - - /** - * Disable a project - * - * @access public - */ - public function disable() - { - $project = $this->getProject(); - - if ($this->request->getStringParam('disable') === 'yes') { - $this->checkCSRFParam(); - - if ($this->project->disable($project['id'])) { - $this->flash->success(t('Project disabled successfully.')); - } else { - $this->flash->failure(t('Unable to disable this project.')); - } - - $this->response->redirect($this->helper->url->to('project', 'show', array('project_id' => $project['id']))); - } - - $this->response->html($this->helper->layout->project('project/disable', array( - 'project' => $project, - 'title' => t('Project activation') - ))); - } - - /** - * Enable a project - * - * @access public - */ - public function enable() - { - $project = $this->getProject(); - - if ($this->request->getStringParam('enable') === 'yes') { - $this->checkCSRFParam(); - - if ($this->project->enable($project['id'])) { - $this->flash->success(t('Project activated successfully.')); - } else { - $this->flash->failure(t('Unable to activate this project.')); - } - - $this->response->redirect($this->helper->url->to('project', 'show', array('project_id' => $project['id']))); - } - - $this->response->html($this->helper->layout->project('project/enable', array( - 'project' => $project, - 'title' => t('Project activation') - ))); - } -} diff --git a/app/Controller/ActionProject.php b/app/Controller/ProjectActionDuplicationController.php index e5063f73..a4993cca 100644 --- a/app/Controller/ActionProject.php +++ b/app/Controller/ProjectActionDuplicationController.php @@ -5,18 +5,18 @@ namespace Kanboard\Controller; /** * Duplicate automatic action from another project * - * @package controller + * @package Kanboard\Controller * @author Frederic Guillot */ -class ActionProject extends Base +class ProjectActionDuplicationController extends BaseController { - public function project() + public function show() { $project = $this->getProject(); - $projects = $this->projectUserRole->getProjectsByUser($this->userSession->getId()); + $projects = $this->projectUserRoleModel->getProjectsByUser($this->userSession->getId()); unset($projects[$project['id']]); - $this->response->html($this->template->render('action_project/project', array( + $this->response->html($this->template->render('project_action_duplication/show', array( 'project' => $project, 'projects_list' => $projects, ))); @@ -27,12 +27,12 @@ class ActionProject extends Base $project = $this->getProject(); $src_project_id = $this->request->getValue('src_project_id'); - if ($this->action->duplicate($src_project_id, $project['id'])) { + if ($this->actionModel->duplicate($src_project_id, $project['id'])) { $this->flash->success(t('Actions duplicated successfully.')); } else { $this->flash->failure(t('Unable to duplicate actions.')); } - $this->response->redirect($this->helper->url->to('action', 'index', array('project_id' => $project['id']))); + $this->response->redirect($this->helper->url->to('ActionController', 'index', array('project_id' => $project['id']))); } } diff --git a/app/Controller/ProjectCreation.php b/app/Controller/ProjectCreationController.php index 88f41fcd..c471cfdd 100644 --- a/app/Controller/ProjectCreation.php +++ b/app/Controller/ProjectCreationController.php @@ -5,20 +5,22 @@ namespace Kanboard\Controller; /** * Project Creation Controller * - * @package controller + * @package Kanboard\Controller * @author Frederic Guillot */ -class ProjectCreation extends Base +class ProjectCreationController extends BaseController { /** * Display a form to create a new project * * @access public + * @param array $values + * @param array $errors */ public function create(array $values = array(), array $errors = array()) { $is_private = isset($values['is_private']) && $values['is_private'] == 1; - $projects_list = array(0 => t('Do not duplicate anything')) + $this->projectUserRole->getActiveProjectsByUser($this->userSession->getId()); + $projects_list = array(0 => t('Do not duplicate anything')) + $this->projectUserRoleModel->getActiveProjectsByUser($this->userSession->getId()); $this->response->html($this->helper->layout->app('project_creation/create', array( 'values' => $values, @@ -33,6 +35,8 @@ class ProjectCreation extends Base * Display a form to create a private project * * @access public + * @param array $values + * @param array $errors */ public function createPrivate(array $values = array(), array $errors = array()) { @@ -55,13 +59,13 @@ class ProjectCreation extends Base if ($project_id > 0) { $this->flash->success(t('Your project have been created successfully.')); - return $this->response->redirect($this->helper->url->to('project', 'show', array('project_id' => $project_id))); + return $this->response->redirect($this->helper->url->to('ProjectViewController', 'show', array('project_id' => $project_id))); } $this->flash->failure(t('Unable to create your project.')); } - $this->create($values, $errors); + return $this->create($values, $errors); } /** @@ -94,7 +98,7 @@ class ProjectCreation extends Base 'is_private' => $values['is_private'], ); - return $this->project->create($project, $this->userSession->getId(), true); + return $this->projectModel->create($project, $this->userSession->getId(), true); } /** @@ -108,13 +112,13 @@ class ProjectCreation extends Base { $selection = array(); - foreach ($this->projectDuplication->getOptionalSelection() as $item) { + foreach ($this->projectDuplicationModel->getOptionalSelection() as $item) { if (isset($values[$item]) && $values[$item] == 1) { $selection[] = $item; } } - return $this->projectDuplication->duplicate( + return $this->projectDuplicationModel->duplicate( $values['src_project_id'], $selection, $this->userSession->getId(), diff --git a/app/Controller/ProjectEdit.php b/app/Controller/ProjectEditController.php index 94be0206..228d681c 100644 --- a/app/Controller/ProjectEdit.php +++ b/app/Controller/ProjectEditController.php @@ -5,15 +5,17 @@ namespace Kanboard\Controller; /** * Project Edit Controller * - * @package controller + * @package Kanboard\Controller * @author Frederic Guillot */ -class ProjectEdit extends Base +class ProjectEditController extends BaseController { /** * General edition (most common operations) * * @access public + * @param array $values + * @param array $errors */ public function edit(array $values = array(), array $errors = array()) { @@ -24,6 +26,8 @@ class ProjectEdit extends Base * Change start and end dates * * @access public + * @param array $values + * @param array $errors */ public function dates(array $values = array(), array $errors = array()) { @@ -34,6 +38,8 @@ class ProjectEdit extends Base * Change project description * * @access public + * @param array $values + * @param array $errors */ public function description(array $values = array(), array $errors = array()) { @@ -44,6 +50,8 @@ class ProjectEdit extends Base * Change task priority * * @access public + * @param array $values + * @param array $errors */ public function priority(array $values = array(), array $errors = array()) { @@ -65,15 +73,15 @@ class ProjectEdit extends Base list($valid, $errors) = $this->projectValidator->validateModification($values); if ($valid) { - if ($this->project->update($values)) { + if ($this->projectModel->update($values)) { $this->flash->success(t('Project updated successfully.')); - $this->response->redirect($this->helper->url->to('ProjectEdit', $redirect, array('project_id' => $project['id'])), true); + return $this->response->redirect($this->helper->url->to('ProjectEditController', $redirect, array('project_id' => $project['id'])), true); } else { $this->flash->failure(t('Unable to update this project.')); } } - $this->$redirect($values, $errors); + return $this->$redirect($values, $errors); } /** @@ -89,11 +97,11 @@ class ProjectEdit extends Base { if ($redirect === 'edit') { if (isset($values['is_private'])) { - if (! $this->helper->user->hasProjectAccess('ProjectCreation', 'create', $project['id'])) { + if (! $this->helper->user->hasProjectAccess('ProjectCreationController', 'create', $project['id'])) { unset($values['is_private']); } } elseif ($project['is_private'] == 1 && ! isset($values['is_private'])) { - if ($this->helper->user->hasProjectAccess('ProjectCreation', 'create', $project['id'])) { + if ($this->helper->user->hasProjectAccess('ProjectCreationController', 'create', $project['id'])) { $values += array('is_private' => 0); } } @@ -103,7 +111,7 @@ class ProjectEdit extends Base } /** - * Common metthod to render different views + * Common method to render different views * * @access private * @param string $template @@ -115,7 +123,7 @@ class ProjectEdit extends Base $project = $this->getProject(); $this->response->html($this->helper->layout->project($template, array( - 'owners' => $this->projectUserRole->getAssignableUsersList($project['id'], true), + 'owners' => $this->projectUserRoleModel->getAssignableUsersList($project['id'], true), 'values' => empty($values) ? $project : $values, 'errors' => $errors, 'project' => $project, diff --git a/app/Controller/ProjectFile.php b/app/Controller/ProjectFileController.php index 96764a92..cbe48679 100644 --- a/app/Controller/ProjectFile.php +++ b/app/Controller/ProjectFileController.php @@ -5,10 +5,10 @@ namespace Kanboard\Controller; /** * Project File Controller * - * @package controller + * @package Kanboard\Controller * @author Frederic Guillot */ -class ProjectFile extends Base +class ProjectFileController extends BaseController { /** * File upload form @@ -34,11 +34,11 @@ class ProjectFile extends Base { $project = $this->getProject(); - if (! $this->projectFile->uploadFiles($project['id'], $this->request->getFileInfo('files'))) { + if (! $this->projectFileModel->uploadFiles($project['id'], $this->request->getFileInfo('files'))) { $this->flash->failure(t('Unable to upload the file.')); } - $this->response->redirect($this->helper->url->to('ProjectOverview', 'show', array('project_id' => $project['id'])), true); + $this->response->redirect($this->helper->url->to('ProjectOverviewController', 'show', array('project_id' => $project['id'])), true); } /** @@ -50,15 +50,15 @@ class ProjectFile extends Base { $this->checkCSRFParam(); $project = $this->getProject(); - $file = $this->projectFile->getById($this->request->getIntegerParam('file_id')); + $file = $this->projectFileModel->getById($this->request->getIntegerParam('file_id')); - if ($this->projectFile->remove($file['id'])) { + if ($this->projectFileModel->remove($file['id'])) { $this->flash->success(t('File removed successfully.')); } else { $this->flash->failure(t('Unable to remove this file.')); } - $this->response->redirect($this->helper->url->to('ProjectOverview', 'show', array('project_id' => $project['id']))); + $this->response->redirect($this->helper->url->to('ProjectOverviewController', 'show', array('project_id' => $project['id']))); } /** @@ -69,7 +69,7 @@ class ProjectFile extends Base public function confirm() { $project = $this->getProject(); - $file = $this->projectFile->getById($this->request->getIntegerParam('file_id')); + $file = $this->projectFileModel->getById($this->request->getIntegerParam('file_id')); $this->response->html($this->template->render('project_file/remove', array( 'project' => $project, diff --git a/app/Controller/ProjectGanttController.php b/app/Controller/ProjectGanttController.php new file mode 100644 index 00000000..a70d9eee --- /dev/null +++ b/app/Controller/ProjectGanttController.php @@ -0,0 +1,57 @@ +<?php + +namespace Kanboard\Controller; + +use Kanboard\Filter\ProjectIdsFilter; +use Kanboard\Filter\ProjectStatusFilter; +use Kanboard\Filter\ProjectTypeFilter; +use Kanboard\Formatter\ProjectGanttFormatter; +use Kanboard\Model\ProjectModel; + +/** + * Projects Gantt Controller + * + * @package Kanboard\Controller + * @author Frederic Guillot + */ +class ProjectGanttController extends BaseController +{ + /** + * Show Gantt chart for all projects + */ + public function show() + { + $project_ids = $this->projectPermissionModel->getActiveProjectIds($this->userSession->getId()); + $filter = $this->projectQuery + ->withFilter(new ProjectTypeFilter(ProjectModel::TYPE_TEAM)) + ->withFilter(new ProjectStatusFilter(ProjectModel::ACTIVE)) + ->withFilter(new ProjectIdsFilter($project_ids)); + + $filter->getQuery()->asc(ProjectModel::TABLE.'.start_date'); + + $this->response->html($this->helper->layout->app('project_gantt/show', array( + 'projects' => $filter->format(new ProjectGanttFormatter($this->container)), + 'title' => t('Gantt chart for all projects'), + ))); + } + + /** + * Save new project start date and end date + */ + public function save() + { + $values = $this->request->getJson(); + + $result = $this->projectModel->update(array( + 'id' => $values['id'], + 'start_date' => $this->dateParser->getIsoDate(strtotime($values['start'])), + 'end_date' => $this->dateParser->getIsoDate(strtotime($values['end'])), + )); + + if (! $result) { + $this->response->json(array('message' => 'Unable to save project'), 400); + } else { + $this->response->json(array('message' => 'OK'), 201); + } + } +} diff --git a/app/Controller/ProjectListController.php b/app/Controller/ProjectListController.php new file mode 100644 index 00000000..e1172400 --- /dev/null +++ b/app/Controller/ProjectListController.php @@ -0,0 +1,41 @@ +<?php + +namespace Kanboard\Controller; + +/** + * Class ProjectListController + * + * @package Kanboard\Controller + * @author Frederic Guillot + */ +class ProjectListController extends BaseController +{ + /** + * List of projects + * + * @access public + */ + public function show() + { + if ($this->userSession->isAdmin()) { + $project_ids = $this->projectModel->getAllIds(); + } else { + $project_ids = $this->projectPermissionModel->getActiveProjectIds($this->userSession->getId()); + } + + $nb_projects = count($project_ids); + + $paginator = $this->paginator + ->setUrl('ProjectListController', 'show') + ->setMax(20) + ->setOrder('name') + ->setQuery($this->projectModel->getQueryColumnStats($project_ids)) + ->calculate(); + + $this->response->html($this->helper->layout->app('project_list/show', array( + 'paginator' => $paginator, + 'nb_projects' => $nb_projects, + 'title' => t('Projects').' ('.$nb_projects.')' + ))); + } +} diff --git a/app/Controller/ProjectOverview.php b/app/Controller/ProjectOverviewController.php index b2bb33d6..abdff657 100644 --- a/app/Controller/ProjectOverview.php +++ b/app/Controller/ProjectOverviewController.php @@ -5,10 +5,10 @@ namespace Kanboard\Controller; /** * Project Overview Controller * - * @package controller + * @package Kanboard\Controller * @author Frederic Guillot */ -class ProjectOverview extends Base +class ProjectOverviewController extends BaseController { /** * Show project overview @@ -16,17 +16,17 @@ class ProjectOverview extends Base public function show() { $project = $this->getProject(); - $this->project->getColumnStats($project); + $this->projectModel->getColumnStats($project); $this->response->html($this->helper->layout->app('project_overview/show', array( 'project' => $project, 'title' => $project['name'], 'description' => $this->helper->projectHeader->getDescription($project), - 'users' => $this->projectUserRole->getAllUsersGroupedByRole($project['id']), + 'users' => $this->projectUserRoleModel->getAllUsersGroupedByRole($project['id']), 'roles' => $this->role->getProjectRoles(), 'events' => $this->helper->projectActivity->getProjectEvents($project['id'], 10), - 'images' => $this->projectFile->getAllImages($project['id']), - 'files' => $this->projectFile->getAllDocuments($project['id']), + 'images' => $this->projectFileModel->getAllImages($project['id']), + 'files' => $this->projectFileModel->getAllDocuments($project['id']), ))); } } diff --git a/app/Controller/ProjectPermission.php b/app/Controller/ProjectPermissionController.php index e203c0db..f3ca6ed9 100644 --- a/app/Controller/ProjectPermission.php +++ b/app/Controller/ProjectPermissionController.php @@ -2,15 +2,16 @@ namespace Kanboard\Controller; +use Kanboard\Core\Controller\AccessForbiddenException; use Kanboard\Core\Security\Role; /** - * Project Permission + * Project Permission Controller * - * @package controller + * @package Kanboard\Controller * @author Frederic Guillot */ -class ProjectPermission extends Base +class ProjectPermissionController extends BaseController { /** * Permissions are only available for team projects @@ -18,13 +19,14 @@ class ProjectPermission extends Base * @access protected * @param integer $project_id Default project id * @return array + * @throws AccessForbiddenException */ protected function getProject($project_id = 0) { $project = parent::getProject($project_id); if ($project['is_private'] == 1) { - $this->forbidden(); + throw new AccessForbiddenException(); } return $project; @@ -34,6 +36,9 @@ class ProjectPermission extends Base * Show all permissions * * @access public + * @param array $values + * @param array $errors + * @throws AccessForbiddenException */ public function index(array $values = array(), array $errors = array()) { @@ -45,8 +50,8 @@ class ProjectPermission extends Base $this->response->html($this->helper->layout->project('project_permission/index', array( 'project' => $project, - 'users' => $this->projectUserRole->getUsers($project['id']), - 'groups' => $this->projectGroupRole->getGroups($project['id']), + 'users' => $this->projectUserRoleModel->getUsers($project['id']), + 'groups' => $this->projectGroupRoleModel->getGroups($project['id']), 'roles' => $this->role->getProjectRoles(), 'values' => $values, 'errors' => $errors, @@ -64,13 +69,13 @@ class ProjectPermission extends Base $project = $this->getProject(); $values = $this->request->getValues() + array('is_everybody_allowed' => 0); - if ($this->project->update($values)) { + if ($this->projectModel->update($values)) { $this->flash->success(t('Project updated successfully.')); } else { $this->flash->failure(t('Unable to update this project.')); } - $this->response->redirect($this->helper->url->to('ProjectPermission', 'index', array('project_id' => $project['id']))); + $this->response->redirect($this->helper->url->to('ProjectPermissionController', 'index', array('project_id' => $project['id']))); } /** @@ -85,13 +90,13 @@ class ProjectPermission extends Base if (empty($values['user_id'])) { $this->flash->failure(t('User not found.')); - } elseif ($this->projectUserRole->addUser($values['project_id'], $values['user_id'], $values['role'])) { + } elseif ($this->projectUserRoleModel->addUser($values['project_id'], $values['user_id'], $values['role'])) { $this->flash->success(t('Project updated successfully.')); } else { $this->flash->failure(t('Unable to update this project.')); } - $this->response->redirect($this->helper->url->to('ProjectPermission', 'index', array('project_id' => $project['id']))); + $this->response->redirect($this->helper->url->to('ProjectPermissionController', 'index', array('project_id' => $project['id']))); } /** @@ -105,13 +110,13 @@ class ProjectPermission extends Base $project = $this->getProject(); $user_id = $this->request->getIntegerParam('user_id'); - if ($this->projectUserRole->removeUser($project['id'], $user_id)) { + if ($this->projectUserRoleModel->removeUser($project['id'], $user_id)) { $this->flash->success(t('Project updated successfully.')); } else { $this->flash->failure(t('Unable to update this project.')); } - $this->response->redirect($this->helper->url->to('ProjectPermission', 'index', array('project_id' => $project['id']))); + $this->response->redirect($this->helper->url->to('ProjectPermissionController', 'index', array('project_id' => $project['id']))); } /** @@ -124,7 +129,7 @@ class ProjectPermission extends Base $project = $this->getProject(); $values = $this->request->getJson(); - if (! empty($project) && ! empty($values) && $this->projectUserRole->changeUserRole($project['id'], $values['id'], $values['role'])) { + if (! empty($project) && ! empty($values) && $this->projectUserRoleModel->changeUserRole($project['id'], $values['id'], $values['role'])) { $this->response->json(array('status' => 'ok')); } else { $this->response->json(array('status' => 'error')); @@ -142,16 +147,16 @@ class ProjectPermission extends Base $values = $this->request->getValues(); if (empty($values['group_id']) && ! empty($values['external_id'])) { - $values['group_id'] = $this->group->create($values['name'], $values['external_id']); + $values['group_id'] = $this->groupModel->create($values['name'], $values['external_id']); } - if ($this->projectGroupRole->addGroup($project['id'], $values['group_id'], $values['role'])) { + if ($this->projectGroupRoleModel->addGroup($project['id'], $values['group_id'], $values['role'])) { $this->flash->success(t('Project updated successfully.')); } else { $this->flash->failure(t('Unable to update this project.')); } - $this->response->redirect($this->helper->url->to('ProjectPermission', 'index', array('project_id' => $project['id']))); + $this->response->redirect($this->helper->url->to('ProjectPermissionController', 'index', array('project_id' => $project['id']))); } /** @@ -165,13 +170,13 @@ class ProjectPermission extends Base $project = $this->getProject(); $group_id = $this->request->getIntegerParam('group_id'); - if ($this->projectGroupRole->removeGroup($project['id'], $group_id)) { + if ($this->projectGroupRoleModel->removeGroup($project['id'], $group_id)) { $this->flash->success(t('Project updated successfully.')); } else { $this->flash->failure(t('Unable to update this project.')); } - $this->response->redirect($this->helper->url->to('ProjectPermission', 'index', array('project_id' => $project['id']))); + $this->response->redirect($this->helper->url->to('ProjectPermissionController', 'index', array('project_id' => $project['id']))); } /** @@ -184,7 +189,7 @@ class ProjectPermission extends Base $project = $this->getProject(); $values = $this->request->getJson(); - if (! empty($project) && ! empty($values) && $this->projectGroupRole->changeGroupRole($project['id'], $values['id'], $values['role'])) { + if (! empty($project) && ! empty($values) && $this->projectGroupRoleModel->changeGroupRole($project['id'], $values['id'], $values['role'])) { $this->response->json(array('status' => 'ok')); } else { $this->response->json(array('status' => 'error')); diff --git a/app/Controller/ProjectStatusController.php b/app/Controller/ProjectStatusController.php new file mode 100644 index 00000000..78e77870 --- /dev/null +++ b/app/Controller/ProjectStatusController.php @@ -0,0 +1,102 @@ +<?php + +namespace Kanboard\Controller; + +/** + * Class ProjectStatusController + * + * @package Kanboard\Controller + * @author Frederic Guillot + */ +class ProjectStatusController extends BaseController +{ + /** + * Enable a project (confirmation dialog box) + */ + public function confirmEnable() + { + $project = $this->getProject(); + + $this->response->html($this->template->render('project_status/enable', array( + 'project' => $project, + 'title' => t('Project activation') + ))); + } + + /** + * Enable the project + */ + public function enable() + { + $project = $this->getProject(); + $this->checkCSRFParam(); + + if ($this->projectModel->enable($project['id'])) { + $this->flash->success(t('Project activated successfully.')); + } else { + $this->flash->failure(t('Unable to activate this project.')); + } + + $this->response->redirect($this->helper->url->to('ProjectViewController', 'show', array('project_id' => $project['id'])), true); + } + + /** + * Disable a project (confirmation dialog box) + */ + public function confirmDisable() + { + $project = $this->getProject(); + + $this->response->html($this->template->render('project_status/disable', array( + 'project' => $project, + 'title' => t('Project activation') + ))); + } + + /** + * Disable a project + */ + public function disable() + { + $project = $this->getProject(); + $this->checkCSRFParam(); + + if ($this->projectModel->disable($project['id'])) { + $this->flash->success(t('Project disabled successfully.')); + } else { + $this->flash->failure(t('Unable to disable this project.')); + } + + $this->response->redirect($this->helper->url->to('ProjectViewController', 'show', array('project_id' => $project['id'])), true); + } + + /** + * Remove a project (confirmation dialog box) + */ + public function confirmRemove() + { + $project = $this->getProject(); + + $this->response->html($this->template->render('project_status/remove', array( + 'project' => $project, + 'title' => t('Remove project') + ))); + } + + /** + * Remove a project + */ + public function remove() + { + $project = $this->getProject(); + $this->checkCSRFParam(); + + if ($this->projectModel->remove($project['id'])) { + $this->flash->success(t('Project removed successfully.')); + } else { + $this->flash->failure(t('Unable to remove this project.')); + } + + $this->response->redirect($this->helper->url->to('ProjectListController', 'show'), true); + } +} diff --git a/app/Controller/Projectuser.php b/app/Controller/ProjectUserOverviewController.php index a6d4fe4e..686de830 100644 --- a/app/Controller/Projectuser.php +++ b/app/Controller/ProjectUserOverviewController.php @@ -2,36 +2,36 @@ namespace Kanboard\Controller; -use Kanboard\Model\User as UserModel; -use Kanboard\Model\Task as TaskModel; +use Kanboard\Model\UserModel; +use Kanboard\Model\TaskModel; use Kanboard\Core\Security\Role; /** * Project User overview * - * @package controller + * @package Kanboard\Controller * @author Frederic Guillot */ -class Projectuser extends Base +class ProjectUserOverviewController extends BaseController { private function common() { $user_id = $this->request->getIntegerParam('user_id', UserModel::EVERYBODY_ID); if ($this->userSession->isAdmin()) { - $project_ids = $this->project->getAllIds(); + $project_ids = $this->projectModel->getAllIds(); } else { - $project_ids = $this->projectPermission->getActiveProjectIds($this->userSession->getId()); + $project_ids = $this->projectPermissionModel->getActiveProjectIds($this->userSession->getId()); } - return array($user_id, $project_ids, $this->user->getActiveUsersList(true)); + return array($user_id, $project_ids, $this->userModel->getActiveUsersList(true)); } private function role($role, $action, $title, $title_user) { list($user_id, $project_ids, $users) = $this->common(); - $query = $this->projectPermission->getQueryByRole($project_ids, $role)->callback(array($this->project, 'applyColumnStats')); + $query = $this->projectPermissionModel->getQueryByRole($project_ids, $role)->callback(array($this->projectModel, 'applyColumnStats')); if ($user_id !== UserModel::EVERYBODY_ID && isset($users[$user_id])) { $query->eq(UserModel::TABLE.'.id', $user_id); @@ -39,13 +39,13 @@ class Projectuser extends Base } $paginator = $this->paginator - ->setUrl('projectuser', $action, array('user_id' => $user_id)) + ->setUrl('ProjectUserOverviewController', $action, array('user_id' => $user_id)) ->setMax(30) ->setOrder('projects.name') ->setQuery($query) ->calculate(); - $this->response->html($this->helper->layout->projectUser('project_user/roles', array( + $this->response->html($this->helper->layout->projectUser('project_user_overview/roles', array( 'paginator' => $paginator, 'title' => $title, 'user_id' => $user_id, @@ -57,7 +57,7 @@ class Projectuser extends Base { list($user_id, $project_ids, $users) = $this->common(); - $query = $this->taskFinder->getProjectUserOverviewQuery($project_ids, $is_active); + $query = $this->taskFinderModel->getProjectUserOverviewQuery($project_ids, $is_active); if ($user_id !== UserModel::EVERYBODY_ID && isset($users[$user_id])) { $query->eq(TaskModel::TABLE.'.owner_id', $user_id); @@ -65,13 +65,13 @@ class Projectuser extends Base } $paginator = $this->paginator - ->setUrl('projectuser', $action, array('user_id' => $user_id)) + ->setUrl('ProjectUserOverviewController', $action, array('user_id' => $user_id)) ->setMax(50) ->setOrder(TaskModel::TABLE.'.id') ->setQuery($query) ->calculate(); - $this->response->html($this->helper->layout->projectUser('project_user/tasks', array( + $this->response->html($this->helper->layout->projectUser('project_user_overview/tasks', array( 'paginator' => $paginator, 'title' => $title, 'user_id' => $user_id, @@ -94,7 +94,7 @@ class Projectuser extends Base */ public function members() { - $this->role(ROLE::PROJECT_MEMBER, 'members', t('People who are project members'), 'Projects where "%s" is member'); + $this->role(Role::PROJECT_MEMBER, 'members', t('People who are project members'), 'Projects where "%s" is member'); } /** @@ -122,8 +122,8 @@ class Projectuser extends Base { $project = $this->getProject(); - return $this->response->html($this->template->render('project_user/tooltip_users', array( - 'users' => $this->projectUserRole->getAllUsersGroupedByRole($project['id']), + return $this->response->html($this->template->render('project_user_overview/tooltip_users', array( + 'users' => $this->projectUserRoleModel->getAllUsersGroupedByRole($project['id']), 'roles' => $this->role->getProjectRoles(), ))); } diff --git a/app/Controller/ProjectViewController.php b/app/Controller/ProjectViewController.php new file mode 100644 index 00000000..92b93804 --- /dev/null +++ b/app/Controller/ProjectViewController.php @@ -0,0 +1,162 @@ +<?php + +namespace Kanboard\Controller; + +/** + * Class ProjectViewController + * + * @package Kanboard\Controller + * @author Frederic Guillot + */ +class ProjectViewController extends BaseController +{ + /** + * Show the project information page + * + * @access public + */ + public function show() + { + $project = $this->getProject(); + + $this->response->html($this->helper->layout->project('project_view/show', array( + 'project' => $project, + 'stats' => $this->projectModel->getTaskStats($project['id']), + 'title' => $project['name'], + ))); + } + + /** + * Public access management + * + * @access public + */ + public function share() + { + $project = $this->getProject(); + + $this->response->html($this->helper->layout->project('project_view/share', array( + 'project' => $project, + 'title' => t('Public access'), + ))); + } + + /** + * Change project sharing + * + * @throws \Kanboard\Core\Controller\AccessForbiddenException + * @throws \Kanboard\Core\Controller\PageNotFoundException + */ + public function updateSharing() + { + $project = $this->getProject(); + $this->checkCSRFParam(); + $switch = $this->request->getStringParam('switch'); + + if ($this->projectModel->{$switch.'PublicAccess'}($project['id'])) { + $this->flash->success(t('Project updated successfully.')); + } else { + $this->flash->failure(t('Unable to update this project.')); + } + + $this->response->redirect($this->helper->url->to('ProjectViewController', 'share', array('project_id' => $project['id']))); + } + + /** + * Integrations page + * + * @access public + */ + public function integrations() + { + $project = $this->getProject(); + + $this->response->html($this->helper->layout->project('project_view/integrations', array( + 'project' => $project, + 'title' => t('Integrations'), + 'webhook_token' => $this->configModel->get('webhook_token'), + 'values' => $this->projectMetadataModel->getAll($project['id']), + 'errors' => array(), + ))); + } + + /** + * Update integrations + * + * @throws \Kanboard\Core\Controller\PageNotFoundException + */ + public function updateIntegrations() + { + $project = $this->getProject(); + + $this->projectMetadataModel->save($project['id'], $this->request->getValues()); + $this->flash->success(t('Project updated successfully.')); + $this->response->redirect($this->helper->url->to('ProjectViewController', 'integrations', array('project_id' => $project['id']))); + } + + /** + * Display project notifications + * + * @access public + */ + public function notifications() + { + $project = $this->getProject(); + + $this->response->html($this->helper->layout->project('project_view/notifications', array( + 'notifications' => $this->projectNotificationModel->readSettings($project['id']), + 'types' => $this->projectNotificationTypeModel->getTypes(), + 'project' => $project, + 'title' => t('Notifications'), + ))); + } + + /** + * Update notifications + * + * @throws \Kanboard\Core\Controller\PageNotFoundException + */ + public function updateNotifications() + { + $project = $this->getProject(); + $values = $this->request->getValues(); + + $this->projectNotificationModel->saveSettings($project['id'], $values); + $this->flash->success(t('Project updated successfully.')); + $this->response->redirect($this->helper->url->to('ProjectViewController', 'notifications', array('project_id' => $project['id']))); + } + + /** + * Duplicate a project + * + * @author Antonio Rabelo + * @author Michael Lüpkes + * @access public + */ + public function duplicate() + { + $project = $this->getProject(); + + $this->response->html($this->helper->layout->project('project_view/duplicate', array( + 'project' => $project, + 'title' => t('Clone this project') + ))); + } + + /** + * Do project duplication + */ + public function doDuplication() + { + $project = $this->getProject(); + $project_id = $this->projectDuplicationModel->duplicate($project['id'], array_keys($this->request->getValues()), $this->userSession->getId()); + + if ($project_id !== false) { + $this->flash->success(t('Project cloned successfully.')); + } else { + $this->flash->failure(t('Unable to clone this project.')); + } + + $this->response->redirect($this->helper->url->to('ProjectViewController', 'show', array('project_id' => $project_id))); + } +} diff --git a/app/Controller/Search.php b/app/Controller/SearchController.php index a42e9d3d..8557b182 100644 --- a/app/Controller/Search.php +++ b/app/Controller/SearchController.php @@ -5,21 +5,21 @@ namespace Kanboard\Controller; use Kanboard\Filter\TaskProjectsFilter; /** - * Search controller + * Search Controller * - * @package controller + * @package Kanboard\Controller * @author Frederic Guillot */ -class Search extends Base +class SearchController extends BaseController { public function index() { - $projects = $this->projectUserRole->getProjectsByUser($this->userSession->getId()); + $projects = $this->projectUserRoleModel->getProjectsByUser($this->userSession->getId()); $search = urldecode($this->request->getStringParam('search')); $nb_tasks = 0; $paginator = $this->paginator - ->setUrl('search', 'index', array('search' => $search)) + ->setUrl('SearchController', 'index', array('search' => $search)) ->setMax(30) ->setOrder('tasks.id') ->setDirection('DESC'); @@ -39,7 +39,7 @@ class Search extends Base $this->response->html($this->helper->layout->app('search/index', array( 'values' => array( 'search' => $search, - 'controller' => 'search', + 'controller' => 'SearchController', 'action' => 'index', ), 'paginator' => $paginator, @@ -56,7 +56,7 @@ class Search extends Base $this->response->html($this->helper->layout->app('search/activity', array( 'values' => array( 'search' => $search, - 'controller' => 'search', + 'controller' => 'SearchController', 'action' => 'activity', ), 'title' => t('Search in activity stream').($nb_events > 0 ? ' ('.$nb_events.')' : ''), diff --git a/app/Controller/Subtask.php b/app/Controller/SubtaskController.php index dea2b08e..93dab5cd 100644 --- a/app/Controller/Subtask.php +++ b/app/Controller/SubtaskController.php @@ -2,18 +2,25 @@ namespace Kanboard\Controller; +use Kanboard\Core\Controller\AccessForbiddenException; +use Kanboard\Core\Controller\PageNotFoundException; + /** * Subtask controller * - * @package controller + * @package Kanboard\Controller * @author Frederic Guillot */ -class Subtask extends Base +class SubtaskController extends BaseController { /** * Creation form * * @access public + * @param array $values + * @param array $errors + * @throws AccessForbiddenException + * @throws PageNotFoundException */ public function create(array $values = array(), array $errors = array()) { @@ -29,7 +36,7 @@ class Subtask extends Base $this->response->html($this->template->render('subtask/create', array( 'values' => $values, 'errors' => $errors, - 'users_list' => $this->projectUserRole->getAssignableUsersList($task['project_id']), + 'users_list' => $this->projectUserRoleModel->getAssignableUsersList($task['project_id']), 'task' => $task, ))); } @@ -47,7 +54,7 @@ class Subtask extends Base list($valid, $errors) = $this->subtaskValidator->validateCreation($values); if ($valid) { - if ($this->subtask->create($values)) { + if ($this->subtaskModel->create($values) !== false) { $this->flash->success(t('Sub-task added successfully.')); } else { $this->flash->failure(t('Unable to create your sub-task.')); @@ -57,27 +64,31 @@ class Subtask extends Base return $this->create(array('project_id' => $task['project_id'], 'task_id' => $task['id'], 'another_subtask' => 1)); } - return $this->response->redirect($this->helper->url->to('task', 'show', array('project_id' => $task['project_id'], 'task_id' => $task['id']), 'subtasks'), true); + return $this->response->redirect($this->helper->url->to('TaskViewController', 'show', array('project_id' => $task['project_id'], 'task_id' => $task['id']), 'subtasks'), true); } - $this->create($values, $errors); + return $this->create($values, $errors); } /** * Edit form * * @access public + * @param array $values + * @param array $errors + * @throws AccessForbiddenException + * @throws PageNotFoundException */ public function edit(array $values = array(), array $errors = array()) { $task = $this->getTask(); - $subtask = $this->getSubTask(); + $subtask = $this->getSubtask(); $this->response->html($this->template->render('subtask/edit', array( 'values' => empty($values) ? $subtask : $values, 'errors' => $errors, - 'users_list' => $this->projectUserRole->getAssignableUsersList($task['project_id']), - 'status_list' => $this->subtask->getStatusList(), + 'users_list' => $this->projectUserRoleModel->getAssignableUsersList($task['project_id']), + 'status_list' => $this->subtaskModel->getStatusList(), 'subtask' => $subtask, 'task' => $task, ))); @@ -97,16 +108,16 @@ class Subtask extends Base list($valid, $errors) = $this->subtaskValidator->validateModification($values); if ($valid) { - if ($this->subtask->update($values)) { + if ($this->subtaskModel->update($values)) { $this->flash->success(t('Sub-task updated successfully.')); } else { $this->flash->failure(t('Unable to update your sub-task.')); } - return $this->response->redirect($this->helper->url->to('task', 'show', array('project_id' => $task['project_id'], 'task_id' => $task['id'])), true); + return $this->response->redirect($this->helper->url->to('TaskViewController', 'show', array('project_id' => $task['project_id'], 'task_id' => $task['id'])), true); } - $this->edit($values, $errors); + return $this->edit($values, $errors); } /** @@ -136,13 +147,13 @@ class Subtask extends Base $task = $this->getTask(); $subtask = $this->getSubtask(); - if ($this->subtask->remove($subtask['id'])) { + if ($this->subtaskModel->remove($subtask['id'])) { $this->flash->success(t('Sub-task removed successfully.')); } else { $this->flash->failure(t('Unable to remove this sub-task.')); } - $this->response->redirect($this->helper->url->to('task', 'show', array('project_id' => $task['project_id'], 'task_id' => $task['id'])), true); + $this->response->redirect($this->helper->url->to('TaskViewController', 'show', array('project_id' => $task['project_id'], 'task_id' => $task['id'])), true); } /** @@ -156,11 +167,11 @@ class Subtask extends Base $task_id = $this->request->getIntegerParam('task_id'); $values = $this->request->getJson(); - if (! empty($values) && $this->helper->user->hasProjectAccess('Subtask', 'movePosition', $project_id)) { - $result = $this->subtask->changePosition($task_id, $values['subtask_id'], $values['position']); - return $this->response->json(array('result' => $result)); + if (! empty($values) && $this->helper->user->hasProjectAccess('SubtaskController', 'movePosition', $project_id)) { + $result = $this->subtaskModel->changePosition($task_id, $values['subtask_id'], $values['position']); + $this->response->json(array('result' => $result)); + } else { + throw new AccessForbiddenException(); } - - $this->forbidden(); } } diff --git a/app/Controller/SubtaskConverterController.php b/app/Controller/SubtaskConverterController.php new file mode 100644 index 00000000..65bcd2da --- /dev/null +++ b/app/Controller/SubtaskConverterController.php @@ -0,0 +1,39 @@ +<?php + +namespace Kanboard\Controller; + +/** + * Class SubtaskConverterController + * + * @package Kanboard\Controller + * @author Frederic Guillot + */ +class SubtaskConverterController extends BaseController +{ + public function show() + { + $task = $this->getTask(); + $subtask = $this->getSubtask(); + + $this->response->html($this->template->render('subtask_converter/show', array( + 'subtask' => $subtask, + 'task' => $task, + ))); + } + + public function save() + { + $project = $this->getProject(); + $subtask = $this->getSubtask(); + + $task_id = $this->subtaskModel->convertToTask($project['id'], $subtask['id']); + + if ($task_id !== false) { + $this->flash->success(t('Subtask converted to task successfully.')); + } else { + $this->flash->failure(t('Unable to convert the subtask.')); + } + + $this->response->redirect($this->helper->url->to('TaskViewController', 'show', array('project_id' => $project['id'], 'task_id' => $task_id)), true); + } +} diff --git a/app/Controller/SubtaskRestriction.php b/app/Controller/SubtaskRestrictionController.php index 56024867..084fc0d9 100644 --- a/app/Controller/SubtaskRestriction.php +++ b/app/Controller/SubtaskRestrictionController.php @@ -2,32 +2,32 @@ namespace Kanboard\Controller; -use Kanboard\Model\Subtask as SubtaskModel; +use Kanboard\Model\SubtaskModel; /** * Subtask Restriction * - * @package controller + * @package Kanboard\Controller * @author Frederic Guillot */ -class SubtaskRestriction extends Base +class SubtaskRestrictionController extends BaseController { /** * Show popup * * @access public */ - public function popover() + public function show() { $task = $this->getTask(); $subtask = $this->getSubtask(); - $this->response->html($this->template->render('subtask_restriction/popover', array( + $this->response->html($this->template->render('subtask_restriction/show', array( 'status_list' => array( SubtaskModel::STATUS_TODO => t('Todo'), SubtaskModel::STATUS_DONE => t('Done'), ), - 'subtask_inprogress' => $this->subtask->getSubtaskInProgress($this->userSession->getId()), + 'subtask_inprogress' => $this->subtaskModel->getSubtaskInProgress($this->userSession->getId()), 'subtask' => $subtask, 'task' => $task, ))); @@ -38,24 +38,24 @@ class SubtaskRestriction extends Base * * @access public */ - public function update() + public function save() { $task = $this->getTask(); $subtask = $this->getSubtask(); $values = $this->request->getValues(); // Change status of the previous "in progress" subtask - $this->subtask->update(array( + $this->subtaskModel->update(array( 'id' => $values['id'], 'status' => $values['status'], )); // Set the current subtask to "in progress" - $this->subtask->update(array( + $this->subtaskModel->update(array( 'id' => $subtask['id'], 'status' => SubtaskModel::STATUS_INPROGRESS, )); - $this->response->redirect($this->helper->url->to('task', 'show', array('project_id' => $task['project_id'], 'task_id' => $task['id'])), true); + $this->response->redirect($this->helper->url->to('TaskViewController', 'show', array('project_id' => $task['project_id'], 'task_id' => $task['id'])), true); } } diff --git a/app/Controller/SubtaskStatus.php b/app/Controller/SubtaskStatusController.php index 4fb82fc0..699951fe 100644 --- a/app/Controller/SubtaskStatus.php +++ b/app/Controller/SubtaskStatusController.php @@ -5,10 +5,10 @@ namespace Kanboard\Controller; /** * Subtask Status * - * @package controller + * @package Kanboard\Controller * @author Frederic Guillot */ -class SubtaskStatus extends Base +class SubtaskStatusController extends BaseController { /** * Change status to the next status: Toto -> In Progress -> Done @@ -20,7 +20,7 @@ class SubtaskStatus extends Base $task = $this->getTask(); $subtask = $this->getSubtask(); - $status = $this->subtask->toggleStatus($subtask['id']); + $status = $this->subtaskModel->toggleStatus($subtask['id']); if ($this->request->getIntegerParam('refresh-table') === 0) { $subtask['status'] = $status; @@ -44,10 +44,10 @@ class SubtaskStatus extends Base $timer = $this->request->getStringParam('timer'); if ($timer === 'start') { - $this->subtaskTimeTracking->logStartTime($subtask_id, $this->userSession->getId()); + $this->subtaskTimeTrackingModel->logStartTime($subtask_id, $this->userSession->getId()); } elseif ($timer === 'stop') { - $this->subtaskTimeTracking->logEndTime($subtask_id, $this->userSession->getId()); - $this->subtaskTimeTracking->updateTaskTimeTracking($task['id']); + $this->subtaskTimeTrackingModel->logEndTime($subtask_id, $this->userSession->getId()); + $this->subtaskTimeTrackingModel->updateTaskTimeTracking($task['id']); } $this->response->html($this->renderTable($task)); @@ -64,9 +64,8 @@ class SubtaskStatus extends Base { return $this->template->render('subtask/table', array( 'task' => $task, - 'subtasks' => $this->subtask->getAll($task['id']), + 'subtasks' => $this->subtaskModel->getAll($task['id']), 'editable' => true, - 'redirect' => 'task', )); } } diff --git a/app/Controller/Swimlane.php b/app/Controller/SwimlaneController.php index 8270a16f..c7c20ce8 100644 --- a/app/Controller/Swimlane.php +++ b/app/Controller/SwimlaneController.php @@ -2,30 +2,31 @@ namespace Kanboard\Controller; -use Kanboard\Model\Swimlane as SwimlaneModel; +use Kanboard\Core\Controller\AccessForbiddenException; +use Kanboard\Core\Controller\PageNotFoundException; +use Kanboard\Model\SwimlaneModel; /** - * Swimlanes + * Swimlanes Controller * - * @package controller + * @package Kanboard\Controller * @author Frederic Guillot */ -class Swimlane extends Base +class SwimlaneController extends BaseController { /** * Get the swimlane (common method between actions) * * @access private - * @param integer $project_id * @return array + * @throws PageNotFoundException */ - private function getSwimlane($project_id) + private function getSwimlane() { - $swimlane = $this->swimlane->getById($this->request->getIntegerParam('swimlane_id')); + $swimlane = $this->swimlaneModel->getById($this->request->getIntegerParam('swimlane_id')); if (empty($swimlane)) { - $this->flash->failure(t('Swimlane not found.')); - $this->response->redirect($this->helper->url->to('swimlane', 'index', array('project_id' => $project_id))); + throw new PageNotFoundException(); } return $swimlane; @@ -41,9 +42,9 @@ class Swimlane extends Base $project = $this->getProject(); $this->response->html($this->helper->layout->project('swimlane/index', array( - 'default_swimlane' => $this->swimlane->getDefault($project['id']), - 'active_swimlanes' => $this->swimlane->getAllByStatus($project['id'], SwimlaneModel::ACTIVE), - 'inactive_swimlanes' => $this->swimlane->getAllByStatus($project['id'], SwimlaneModel::INACTIVE), + 'default_swimlane' => $this->swimlaneModel->getDefault($project['id']), + 'active_swimlanes' => $this->swimlaneModel->getAllByStatus($project['id'], SwimlaneModel::ACTIVE), + 'inactive_swimlanes' => $this->swimlaneModel->getAllByStatus($project['id'], SwimlaneModel::INACTIVE), 'project' => $project, 'title' => t('Swimlanes') ))); @@ -53,6 +54,9 @@ class Swimlane extends Base * Create a new swimlane * * @access public + * @param array $values + * @param array $errors + * @throws \Kanboard\Core\Controller\PageNotFoundException */ public function create(array $values = array(), array $errors = array()) { @@ -77,26 +81,29 @@ class Swimlane extends Base list($valid, $errors) = $this->swimlaneValidator->validateCreation($values); if ($valid) { - if ($this->swimlane->create($values)) { + if ($this->swimlaneModel->create($values) !== false) { $this->flash->success(t('Your swimlane have been created successfully.')); - $this->response->redirect($this->helper->url->to('swimlane', 'index', array('project_id' => $project['id']))); + return $this->response->redirect($this->helper->url->to('SwimlaneController', 'index', array('project_id' => $project['id']))); } else { $errors = array('name' => array(t('Another swimlane with the same name exists in the project'))); } } - $this->create($values, $errors); + return $this->create($values, $errors); } /** * Edit default swimlane (display the form) * * @access public + * @param array $values + * @param array $errors + * @throws \Kanboard\Core\Controller\PageNotFoundException */ public function editDefault(array $values = array(), array $errors = array()) { $project = $this->getProject(); - $swimlane = $this->swimlane->getDefault($project['id']); + $swimlane = $this->swimlaneModel->getDefault($project['id']); $this->response->html($this->helper->layout->project('swimlane/edit_default', array( 'values' => empty($values) ? $swimlane : $values, @@ -118,26 +125,29 @@ class Swimlane extends Base list($valid, $errors) = $this->swimlaneValidator->validateDefaultModification($values); if ($valid) { - if ($this->swimlane->updateDefault($values)) { + if ($this->swimlaneModel->updateDefault($values)) { $this->flash->success(t('The default swimlane have been updated successfully.')); - $this->response->redirect($this->helper->url->to('swimlane', 'index', array('project_id' => $project['id'])), true); + return $this->response->redirect($this->helper->url->to('SwimlaneController', 'index', array('project_id' => $project['id'])), true); } else { $this->flash->failure(t('Unable to update this swimlane.')); } } - $this->editDefault($values, $errors); + return $this->editDefault($values, $errors); } /** * Edit a swimlane (display the form) * * @access public + * @param array $values + * @param array $errors + * @throws \Kanboard\Core\Controller\PageNotFoundException */ public function edit(array $values = array(), array $errors = array()) { $project = $this->getProject(); - $swimlane = $this->getSwimlane($project['id']); + $swimlane = $this->getSwimlane(); $this->response->html($this->helper->layout->project('swimlane/edit', array( 'values' => empty($values) ? $swimlane : $values, @@ -159,15 +169,15 @@ class Swimlane extends Base list($valid, $errors) = $this->swimlaneValidator->validateModification($values); if ($valid) { - if ($this->swimlane->update($values)) { + if ($this->swimlaneModel->update($values)) { $this->flash->success(t('Swimlane updated successfully.')); - $this->response->redirect($this->helper->url->to('swimlane', 'index', array('project_id' => $project['id']))); + return $this->response->redirect($this->helper->url->to('SwimlaneController', 'index', array('project_id' => $project['id']))); } else { $errors = array('name' => array(t('Another swimlane with the same name exists in the project'))); } } - $this->edit($values, $errors); + return $this->edit($values, $errors); } /** @@ -178,7 +188,7 @@ class Swimlane extends Base public function confirm() { $project = $this->getProject(); - $swimlane = $this->getSwimlane($project['id']); + $swimlane = $this->getSwimlane(); $this->response->html($this->helper->layout->project('swimlane/remove', array( 'project' => $project, @@ -197,13 +207,13 @@ class Swimlane extends Base $project = $this->getProject(); $swimlane_id = $this->request->getIntegerParam('swimlane_id'); - if ($this->swimlane->remove($project['id'], $swimlane_id)) { + if ($this->swimlaneModel->remove($project['id'], $swimlane_id)) { $this->flash->success(t('Swimlane removed successfully.')); } else { $this->flash->failure(t('Unable to remove this swimlane.')); } - $this->response->redirect($this->helper->url->to('swimlane', 'index', array('project_id' => $project['id']))); + $this->response->redirect($this->helper->url->to('SwimlaneController', 'index', array('project_id' => $project['id']))); } /** @@ -217,13 +227,13 @@ class Swimlane extends Base $project = $this->getProject(); $swimlane_id = $this->request->getIntegerParam('swimlane_id'); - if ($this->swimlane->disable($project['id'], $swimlane_id)) { + if ($this->swimlaneModel->disable($project['id'], $swimlane_id)) { $this->flash->success(t('Swimlane updated successfully.')); } else { $this->flash->failure(t('Unable to update this swimlane.')); } - $this->response->redirect($this->helper->url->to('swimlane', 'index', array('project_id' => $project['id']))); + $this->response->redirect($this->helper->url->to('SwimlaneController', 'index', array('project_id' => $project['id']))); } /** @@ -236,13 +246,13 @@ class Swimlane extends Base $this->checkCSRFParam(); $project = $this->getProject(); - if ($this->swimlane->disableDefault($project['id'])) { + if ($this->swimlaneModel->disableDefault($project['id'])) { $this->flash->success(t('Swimlane updated successfully.')); } else { $this->flash->failure(t('Unable to update this swimlane.')); } - $this->response->redirect($this->helper->url->to('swimlane', 'index', array('project_id' => $project['id']))); + $this->response->redirect($this->helper->url->to('SwimlaneController', 'index', array('project_id' => $project['id']))); } /** @@ -256,13 +266,13 @@ class Swimlane extends Base $project = $this->getProject(); $swimlane_id = $this->request->getIntegerParam('swimlane_id'); - if ($this->swimlane->enable($project['id'], $swimlane_id)) { + if ($this->swimlaneModel->enable($project['id'], $swimlane_id)) { $this->flash->success(t('Swimlane updated successfully.')); } else { $this->flash->failure(t('Unable to update this swimlane.')); } - $this->response->redirect($this->helper->url->to('swimlane', 'index', array('project_id' => $project['id']))); + $this->response->redirect($this->helper->url->to('SwimlaneController', 'index', array('project_id' => $project['id']))); } /** @@ -275,13 +285,13 @@ class Swimlane extends Base $this->checkCSRFParam(); $project = $this->getProject(); - if ($this->swimlane->enableDefault($project['id'])) { + if ($this->swimlaneModel->enableDefault($project['id'])) { $this->flash->success(t('Swimlane updated successfully.')); } else { $this->flash->failure(t('Unable to update this swimlane.')); } - $this->response->redirect($this->helper->url->to('swimlane', 'index', array('project_id' => $project['id']))); + $this->response->redirect($this->helper->url->to('SwimlaneController', 'index', array('project_id' => $project['id']))); } /** @@ -295,10 +305,10 @@ class Swimlane extends Base $values = $this->request->getJson(); if (! empty($values) && isset($values['swimlane_id']) && isset($values['position'])) { - $result = $this->swimlane->changePosition($project['id'], $values['swimlane_id'], $values['position']); - return $this->response->json(array('result' => $result)); + $result = $this->swimlaneModel->changePosition($project['id'], $values['swimlane_id'], $values['position']); + $this->response->json(array('result' => $result)); + } else { + throw new AccessForbiddenException(); } - - $this->forbidden(); } } diff --git a/app/Controller/Task.php b/app/Controller/Task.php deleted file mode 100644 index 902a32d6..00000000 --- a/app/Controller/Task.php +++ /dev/null @@ -1,174 +0,0 @@ -<?php - -namespace Kanboard\Controller; - -use Kanboard\Core\DateParser; - -/** - * Task controller - * - * @package controller - * @author Frederic Guillot - */ -class Task extends Base -{ - /** - * Public access (display a task) - * - * @access public - */ - public function readonly() - { - $project = $this->project->getByToken($this->request->getStringParam('token')); - - // Token verification - if (empty($project)) { - return $this->forbidden(true); - } - - $task = $this->taskFinder->getDetails($this->request->getIntegerParam('task_id')); - - if (empty($task)) { - return $this->notfound(true); - } - - if ($task['project_id'] != $project['id']) { - return $this->forbidden(true); - } - - $this->response->html($this->helper->layout->app('task/public', array( - 'project' => $project, - 'comments' => $this->comment->getAll($task['id']), - 'subtasks' => $this->subtask->getAll($task['id']), - 'links' => $this->taskLink->getAllGroupedByLabel($task['id']), - 'task' => $task, - 'columns_list' => $this->column->getList($task['project_id']), - 'colors_list' => $this->color->getList(), - 'title' => $task['title'], - 'no_layout' => true, - 'auto_refresh' => true, - 'not_editable' => true, - ))); - } - - /** - * Show a task - * - * @access public - */ - public function show() - { - $task = $this->getTask(); - $subtasks = $this->subtask->getAll($task['id']); - - $values = array( - 'id' => $task['id'], - 'date_started' => $task['date_started'], - 'time_estimated' => $task['time_estimated'] ?: '', - 'time_spent' => $task['time_spent'] ?: '', - ); - - $values = $this->dateParser->format($values, array('date_started'), $this->config->get('application_datetime_format', DateParser::DATE_TIME_FORMAT)); - - $this->response->html($this->helper->layout->task('task/show', array( - 'task' => $task, - 'project' => $this->project->getById($task['project_id']), - 'values' => $values, - 'files' => $this->taskFile->getAllDocuments($task['id']), - 'images' => $this->taskFile->getAllImages($task['id']), - 'comments' => $this->comment->getAll($task['id'], $this->userSession->getCommentSorting()), - 'subtasks' => $subtasks, - 'internal_links' => $this->taskLink->getAllGroupedByLabel($task['id']), - 'external_links' => $this->taskExternalLink->getAll($task['id']), - 'link_label_list' => $this->link->getList(0, false), - ))); - } - - /** - * Display task analytics - * - * @access public - */ - public function analytics() - { - $task = $this->getTask(); - - $this->response->html($this->helper->layout->task('task/analytics', array( - 'task' => $task, - 'project' => $this->project->getById($task['project_id']), - 'lead_time' => $this->taskAnalytic->getLeadTime($task), - 'cycle_time' => $this->taskAnalytic->getCycleTime($task), - 'time_spent_columns' => $this->taskAnalytic->getTimeSpentByColumn($task), - ))); - } - - /** - * Display the time tracking details - * - * @access public - */ - public function timetracking() - { - $task = $this->getTask(); - - $subtask_paginator = $this->paginator - ->setUrl('task', 'timetracking', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'pagination' => 'subtasks')) - ->setMax(15) - ->setOrder('start') - ->setDirection('DESC') - ->setQuery($this->subtaskTimeTracking->getTaskQuery($task['id'])) - ->calculateOnlyIf($this->request->getStringParam('pagination') === 'subtasks'); - - $this->response->html($this->helper->layout->task('task/time_tracking_details', array( - 'task' => $task, - 'project' => $this->project->getById($task['project_id']), - 'subtask_paginator' => $subtask_paginator, - ))); - } - - /** - * Display the task transitions - * - * @access public - */ - public function transitions() - { - $task = $this->getTask(); - - $this->response->html($this->helper->layout->task('task/transitions', array( - 'task' => $task, - 'project' => $this->project->getById($task['project_id']), - 'transitions' => $this->transition->getAllByTask($task['id']), - ))); - } - - /** - * Remove a task - * - * @access public - */ - public function remove() - { - $task = $this->getTask(); - - if (! $this->taskPermission->canRemoveTask($task)) { - $this->forbidden(); - } - - if ($this->request->getStringParam('confirmation') === 'yes') { - $this->checkCSRFParam(); - - if ($this->task->remove($task['id'])) { - $this->flash->success(t('Task removed successfully.')); - } else { - $this->flash->failure(t('Unable to remove this task.')); - } - - $this->response->redirect($this->helper->url->to('board', 'show', array('project_id' => $task['project_id']))); - } - - $this->response->html($this->template->render('task/remove', array( - 'task' => $task, - ))); - } -} diff --git a/app/Controller/TaskHelper.php b/app/Controller/TaskAjaxController.php index 6835ab2b..f9feff15 100644 --- a/app/Controller/TaskHelper.php +++ b/app/Controller/TaskAjaxController.php @@ -9,12 +9,12 @@ use Kanboard\Filter\TaskTitleFilter; use Kanboard\Formatter\TaskAutoCompleteFormatter; /** - * Task Ajax Helper + * Task Ajax Controller * - * @package controller + * @package Kanboard\Controller * @author Frederic Guillot */ -class TaskHelper extends Base +class TaskAjaxController extends BaseController { /** * Task auto-completion (Ajax) @@ -24,7 +24,7 @@ class TaskHelper extends Base public function autocomplete() { $search = $this->request->getStringParam('term'); - $project_ids = $this->projectPermission->getActiveProjectIds($this->userSession->getId()); + $project_ids = $this->projectPermissionModel->getActiveProjectIds($this->userSession->getId()); $exclude_task_id = $this->request->getIntegerParam('exclude_task_id'); if (empty($project_ids)) { diff --git a/app/Controller/TaskBulkController.php b/app/Controller/TaskBulkController.php new file mode 100644 index 00000000..df7f589b --- /dev/null +++ b/app/Controller/TaskBulkController.php @@ -0,0 +1,89 @@ +<?php + +namespace Kanboard\Controller; + +/** + * Class TaskBulkController + * + * @package Kanboard\Controller + * @author Frederic Guillot + */ +class TaskBulkController extends BaseController +{ + /** + * Show the form + * + * @param array $values + * @param array $errors + */ + public function show(array $values = array(), array $errors = array()) + { + $project = $this->getProject(); + + if (empty($values)) { + $values = array( + 'swimlane_id' => $this->request->getIntegerParam('swimlane_id'), + 'column_id' => $this->request->getIntegerParam('column_id'), + 'project_id' => $project['id'], + ); + } + + $this->response->html($this->template->render('task_bulk/show', array( + 'project' => $project, + 'values' => $values, + 'errors' => $errors, + 'users_list' => $this->projectUserRoleModel->getAssignableUsersList($project['id'], true, false, true), + 'colors_list' => $this->colorModel->getList(), + 'categories_list' => $this->categoryModel->getList($project['id']), + ))); + } + + /** + * Save all tasks in the database + */ + public function save() + { + $project = $this->getProject(); + $values = $this->request->getValues(); + list($valid, $errors) = $this->taskValidator->validateBulkCreation($values); + + if ($valid) { + $this->createTasks($project, $values); + $this->response->redirect($this->helper->url->to( + 'BoardViewController', + 'show', + array('project_id' => $project['id']), + 'swimlane-'. $values['swimlane_id'] + ), true); + } else { + $this->show($values, $errors); + } + } + + /** + * Create all tasks + * + * @param array $project + * @param array $values + */ + protected function createTasks(array $project, array $values) + { + $tasks = preg_split('/\r\n|[\r\n]/', $values['tasks']); + + foreach ($tasks as $title) { + $title = trim($title); + + if (! empty($title)) { + $this->taskCreationModel->create(array( + 'title' => $title, + 'column_id' => $values['column_id'], + 'swimlane_id' => $values['swimlane_id'], + 'category_id' => empty($values['category_id']) ? 0 : $values['category_id'], + 'owner_id' => empty($values['owner_id']) ? 0 : $values['owner_id'], + 'color_id' => $values['color_id'], + 'project_id' => $project['id'], + )); + } + } + } +} diff --git a/app/Controller/Taskcreation.php b/app/Controller/TaskCreationController.php index 1d8a0e29..819de96e 100644 --- a/app/Controller/Taskcreation.php +++ b/app/Controller/TaskCreationController.php @@ -3,28 +3,31 @@ namespace Kanboard\Controller; /** - * Task Creation controller + * Task Creation Controller * - * @package controller + * @package Kanboard\Controller * @author Frederic Guillot */ -class Taskcreation extends Base +class TaskCreationController extends BaseController { /** * Display a form to create a new task * * @access public + * @param array $values + * @param array $errors + * @throws \Kanboard\Core\Controller\PageNotFoundException */ - public function create(array $values = array(), array $errors = array()) + public function show(array $values = array(), array $errors = array()) { $project = $this->getProject(); - $swimlanes_list = $this->swimlane->getList($project['id'], false, true); + $swimlanes_list = $this->swimlaneModel->getList($project['id'], false, true); if (empty($values)) { $values = array( 'swimlane_id' => $this->request->getIntegerParam('swimlane_id', key($swimlanes_list)), 'column_id' => $this->request->getIntegerParam('column_id'), - 'color_id' => $this->color->getDefaultColor(), + 'color_id' => $this->colorModel->getDefaultColor(), 'owner_id' => $this->userSession->getId(), ); @@ -32,14 +35,14 @@ class Taskcreation extends Base $values = $this->hook->merge('controller:task-creation:form:default', $values, array('default_values' => $values)); } - $this->response->html($this->template->render('task_creation/form', array( + $this->response->html($this->template->render('task_creation/show', array( 'project' => $project, 'errors' => $errors, 'values' => $values + array('project_id' => $project['id']), - 'columns_list' => $this->column->getList($project['id']), - 'users_list' => $this->projectUserRole->getAssignableUsersList($project['id'], true, false, true), - 'colors_list' => $this->color->getList(), - 'categories_list' => $this->category->getList($project['id']), + 'columns_list' => $this->columnModel->getList($project['id']), + 'users_list' => $this->projectUserRoleModel->getAssignableUsersList($project['id'], true, false, true), + 'colors_list' => $this->colorModel->getList(), + 'categories_list' => $this->categoryModel->getList($project['id']), 'swimlanes_list' => $swimlanes_list, 'title' => $project['name'].' > '.t('New task') ))); @@ -57,19 +60,19 @@ class Taskcreation extends Base list($valid, $errors) = $this->taskValidator->validateCreation($values); - if ($valid && $this->taskCreation->create($values)) { + if ($valid && $this->taskCreationModel->create($values)) { $this->flash->success(t('Task created successfully.')); return $this->afterSave($project, $values); } $this->flash->failure(t('Unable to create your task.')); - $this->create($values, $errors); + return $this->show($values, $errors); } private function afterSave(array $project, array &$values) { if (isset($values['another_task']) && $values['another_task'] == 1) { - return $this->create(array( + return $this->show(array( 'owner_id' => $values['owner_id'], 'color_id' => $values['color_id'], 'category_id' => isset($values['category_id']) ? $values['category_id'] : 0, @@ -79,6 +82,6 @@ class Taskcreation extends Base )); } - $this->response->redirect($this->helper->url->to('board', 'show', array('project_id' => $project['id']))); + return $this->response->redirect($this->helper->url->to('BoardViewController', 'show', array('project_id' => $project['id'])), true); } } diff --git a/app/Controller/Taskduplication.php b/app/Controller/TaskDuplicationController.php index 8fca930d..6a475374 100644 --- a/app/Controller/Taskduplication.php +++ b/app/Controller/TaskDuplicationController.php @@ -5,10 +5,10 @@ namespace Kanboard\Controller; /** * Task Duplication controller * - * @package controller + * @package Kanboard\Controller * @author Frederic Guillot */ -class Taskduplication extends Base +class TaskDuplicationController extends BaseController { /** * Duplicate a task @@ -21,18 +21,18 @@ class Taskduplication extends Base if ($this->request->getStringParam('confirmation') === 'yes') { $this->checkCSRFParam(); - $task_id = $this->taskDuplication->duplicate($task['id']); + $task_id = $this->taskDuplicationModel->duplicate($task['id']); if ($task_id > 0) { $this->flash->success(t('Task created successfully.')); - $this->response->redirect($this->helper->url->to('task', 'show', array('project_id' => $task['project_id'], 'task_id' => $task_id))); + return $this->response->redirect($this->helper->url->to('TaskViewController', 'show', array('project_id' => $task['project_id'], 'task_id' => $task_id))); } else { $this->flash->failure(t('Unable to create this task.')); - $this->response->redirect($this->helper->url->to('taskduplication', 'duplicate', array('project_id' => $task['project_id'], 'task_id' => $task['id'])), true); + return $this->response->redirect($this->helper->url->to('TaskDuplicationController', 'duplicate', array('project_id' => $task['project_id'], 'task_id' => $task['id'])), true); } } - $this->response->html($this->template->render('task_duplication/duplicate', array( + return $this->response->html($this->template->render('task_duplication/duplicate', array( 'task' => $task, ))); } @@ -50,20 +50,20 @@ class Taskduplication extends Base $values = $this->request->getValues(); list($valid, ) = $this->taskValidator->validateProjectModification($values); - if ($valid && $this->taskDuplication->moveToProject($task['id'], + if ($valid && $this->taskDuplicationModel->moveToProject($task['id'], $values['project_id'], $values['swimlane_id'], $values['column_id'], $values['category_id'], $values['owner_id'])) { $this->flash->success(t('Task updated successfully.')); - $this->response->redirect($this->helper->url->to('task', 'show', array('project_id' => $values['project_id'], 'task_id' => $task['id']))); + return $this->response->redirect($this->helper->url->to('TaskViewController', 'show', array('project_id' => $values['project_id'], 'task_id' => $task['id']))); } $this->flash->failure(t('Unable to update your task.')); } - $this->chooseDestination($task, 'task_duplication/move'); + return $this->chooseDestination($task, 'task_duplication/move'); } /** @@ -80,21 +80,21 @@ class Taskduplication extends Base list($valid, ) = $this->taskValidator->validateProjectModification($values); if ($valid) { - $task_id = $this->taskDuplication->duplicateToProject( + $task_id = $this->taskDuplicationModel->duplicateToProject( $task['id'], $values['project_id'], $values['swimlane_id'], $values['column_id'], $values['category_id'], $values['owner_id'] ); if ($task_id > 0) { $this->flash->success(t('Task created successfully.')); - $this->response->redirect($this->helper->url->to('task', 'show', array('project_id' => $values['project_id'], 'task_id' => $task_id))); + return $this->response->redirect($this->helper->url->to('TaskViewController', 'show', array('project_id' => $values['project_id'], 'task_id' => $task_id))); } } $this->flash->failure(t('Unable to create your task.')); } - $this->chooseDestination($task, 'task_duplication/copy'); + return $this->chooseDestination($task, 'task_duplication/copy'); } /** @@ -107,19 +107,19 @@ class Taskduplication extends Base private function chooseDestination(array $task, $template) { $values = array(); - $projects_list = $this->projectUserRole->getActiveProjectsByUser($this->userSession->getId()); + $projects_list = $this->projectUserRoleModel->getActiveProjectsByUser($this->userSession->getId()); unset($projects_list[$task['project_id']]); if (! empty($projects_list)) { $dst_project_id = $this->request->getIntegerParam('dst_project_id', key($projects_list)); - $swimlanes_list = $this->swimlane->getList($dst_project_id, false, true); - $columns_list = $this->column->getList($dst_project_id); - $categories_list = $this->category->getList($dst_project_id); - $users_list = $this->projectUserRole->getAssignableUsersList($dst_project_id); + $swimlanes_list = $this->swimlaneModel->getList($dst_project_id, false, true); + $columns_list = $this->columnModel->getList($dst_project_id); + $categories_list = $this->categoryModel->getList($dst_project_id); + $users_list = $this->projectUserRoleModel->getAssignableUsersList($dst_project_id); - $values = $this->taskDuplication->checkDestinationProjectValues($task); + $values = $this->taskDuplicationModel->checkDestinationProjectValues($task); $values['project_id'] = $dst_project_id; } else { $swimlanes_list = array(); diff --git a/app/Controller/TaskExternalLink.php b/app/Controller/TaskExternalLinkController.php index 0db8ec37..9c04eb00 100644 --- a/app/Controller/TaskExternalLink.php +++ b/app/Controller/TaskExternalLinkController.php @@ -2,20 +2,25 @@ namespace Kanboard\Controller; +use Kanboard\Core\Controller\PageNotFoundException; use Kanboard\Core\ExternalLink\ExternalLinkProviderNotFound; /** * Task External Link Controller * - * @package controller + * @package Kanboard\Controller * @author Frederic Guillot */ -class TaskExternalLink extends Base +class TaskExternalLinkController extends BaseController { /** * First creation form * * @access public + * @param array $values + * @param array $errors + * @throws PageNotFoundException + * @throws \Kanboard\Core\Controller\AccessForbiddenException */ public function find(array $values = array(), array $errors = array()) { @@ -36,11 +41,10 @@ class TaskExternalLink extends Base */ public function create() { - try { - - $task = $this->getTask(); - $values = $this->request->getValues(); + $task = $this->getTask(); + $values = $this->request->getValues(); + try { $provider = $this->externalLinkManager->setUserInput($values)->find(); $link = $provider->getLink(); @@ -72,18 +76,23 @@ class TaskExternalLink extends Base $values = $this->request->getValues(); list($valid, $errors) = $this->externalLinkValidator->validateCreation($values); - if ($valid && $this->taskExternalLink->create($values)) { + if ($valid && $this->taskExternalLinkModel->create($values) !== false) { $this->flash->success(t('Link added successfully.')); - return $this->response->redirect($this->helper->url->to('task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])), true); + return $this->response->redirect($this->helper->url->to('TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])), true); } - $this->edit($values, $errors); + return $this->edit($values, $errors); } /** * Edit form * * @access public + * @param array $values + * @param array $errors + * @throws ExternalLinkProviderNotFound + * @throws PageNotFoundException + * @throws \Kanboard\Core\Controller\AccessForbiddenException */ public function edit(array $values = array(), array $errors = array()) { @@ -91,11 +100,11 @@ class TaskExternalLink extends Base $link_id = $this->request->getIntegerParam('link_id'); if ($link_id > 0) { - $values = $this->taskExternalLink->getById($link_id); + $values = $this->taskExternalLinkModel->getById($link_id); } if (empty($values)) { - return $this->notfound(); + throw new PageNotFoundException(); } $provider = $this->externalLinkManager->getProvider($values['link_type']); @@ -119,12 +128,12 @@ class TaskExternalLink extends Base $values = $this->request->getValues(); list($valid, $errors) = $this->externalLinkValidator->validateModification($values); - if ($valid && $this->taskExternalLink->update($values)) { + if ($valid && $this->taskExternalLinkModel->update($values)) { $this->flash->success(t('Link updated successfully.')); - return $this->response->redirect($this->helper->url->to('task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])), true); + return $this->response->redirect($this->helper->url->to('TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])), true); } - $this->edit($values, $errors); + return $this->edit($values, $errors); } /** @@ -136,10 +145,10 @@ class TaskExternalLink extends Base { $task = $this->getTask(); $link_id = $this->request->getIntegerParam('link_id'); - $link = $this->taskExternalLink->getById($link_id); + $link = $this->taskExternalLinkModel->getById($link_id); if (empty($link)) { - return $this->notfound(); + throw new PageNotFoundException(); } $this->response->html($this->template->render('task_external_link/remove', array( @@ -158,12 +167,12 @@ class TaskExternalLink extends Base $this->checkCSRFParam(); $task = $this->getTask(); - if ($this->taskExternalLink->remove($this->request->getIntegerParam('link_id'))) { + if ($this->taskExternalLinkModel->remove($this->request->getIntegerParam('link_id'))) { $this->flash->success(t('Link removed successfully.')); } else { $this->flash->failure(t('Unable to remove this link.')); } - $this->response->redirect($this->helper->url->to('task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']))); + $this->response->redirect($this->helper->url->to('TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']))); } } diff --git a/app/Controller/TaskFile.php b/app/Controller/TaskFileController.php index 2b0152a7..77c0c026 100644 --- a/app/Controller/TaskFile.php +++ b/app/Controller/TaskFileController.php @@ -5,10 +5,10 @@ namespace Kanboard\Controller; /** * Task File Controller * - * @package controller + * @package Kanboard\Controller * @author Frederic Guillot */ -class TaskFile extends Base +class TaskFileController extends BaseController { /** * Screenshot @@ -19,12 +19,12 @@ class TaskFile extends Base { $task = $this->getTask(); - if ($this->request->isPost() && $this->taskFile->uploadScreenshot($task['id'], $this->request->getValue('screenshot')) !== false) { + if ($this->request->isPost() && $this->taskFileModel->uploadScreenshot($task['id'], $this->request->getValue('screenshot')) !== false) { $this->flash->success(t('Screenshot uploaded successfully.')); - return $this->response->redirect($this->helper->url->to('task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])), true); + return $this->response->redirect($this->helper->url->to('TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])), true); } - $this->response->html($this->template->render('task_file/screenshot', array( + return $this->response->html($this->template->render('task_file/screenshot', array( 'task' => $task, ))); } @@ -53,11 +53,11 @@ class TaskFile extends Base { $task = $this->getTask(); - if (! $this->taskFile->uploadFiles($task['id'], $this->request->getFileInfo('files'))) { + if (! $this->taskFileModel->uploadFiles($task['id'], $this->request->getFileInfo('files'))) { $this->flash->failure(t('Unable to upload the file.')); } - $this->response->redirect($this->helper->url->to('task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])), true); + $this->response->redirect($this->helper->url->to('TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])), true); } /** @@ -69,15 +69,15 @@ class TaskFile extends Base { $this->checkCSRFParam(); $task = $this->getTask(); - $file = $this->taskFile->getById($this->request->getIntegerParam('file_id')); + $file = $this->taskFileModel->getById($this->request->getIntegerParam('file_id')); - if ($file['task_id'] == $task['id'] && $this->taskFile->remove($file['id'])) { + if ($file['task_id'] == $task['id'] && $this->taskFileModel->remove($file['id'])) { $this->flash->success(t('File removed successfully.')); } else { $this->flash->failure(t('Unable to remove this file.')); } - $this->response->redirect($this->helper->url->to('task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']))); + $this->response->redirect($this->helper->url->to('TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']))); } /** @@ -88,7 +88,7 @@ class TaskFile extends Base public function confirm() { $task = $this->getTask(); - $file = $this->taskFile->getById($this->request->getIntegerParam('file_id')); + $file = $this->taskFileModel->getById($this->request->getIntegerParam('file_id')); $this->response->html($this->template->render('task_file/remove', array( 'task' => $task, diff --git a/app/Controller/TaskGanttController.php b/app/Controller/TaskGanttController.php new file mode 100644 index 00000000..868368e1 --- /dev/null +++ b/app/Controller/TaskGanttController.php @@ -0,0 +1,62 @@ +<?php + +namespace Kanboard\Controller; + +use Kanboard\Filter\TaskProjectFilter; +use Kanboard\Formatter\TaskGanttFormatter; +use Kanboard\Model\TaskModel; + +/** + * Tasks Gantt Controller + * + * @package Kanboard\Controller + * @author Frederic Guillot + */ +class TaskGanttController extends BaseController +{ + /** + * Show Gantt chart for one project + */ + public function show() + { + $project = $this->getProject(); + $search = $this->helper->projectHeader->getSearchQuery($project); + $sorting = $this->request->getStringParam('sorting', 'board'); + $filter = $this->taskLexer->build($search)->withFilter(new TaskProjectFilter($project['id'])); + + if ($sorting === 'date') { + $filter->getQuery()->asc(TaskModel::TABLE.'.date_started')->asc(TaskModel::TABLE.'.date_creation'); + } else { + $filter->getQuery()->asc('column_position')->asc(TaskModel::TABLE.'.position'); + } + + $this->response->html($this->helper->layout->app('task_gantt/show', array( + 'project' => $project, + 'title' => $project['name'], + 'description' => $this->helper->projectHeader->getDescription($project), + 'sorting' => $sorting, + 'tasks' => $filter->format(new TaskGanttFormatter($this->container)), + ))); + } + + /** + * Save new task start date and due date + */ + public function save() + { + $this->getProject(); + $values = $this->request->getJson(); + + $result = $this->taskModificationModel->update(array( + 'id' => $values['id'], + 'date_started' => strtotime($values['start']), + 'date_due' => strtotime($values['end']), + )); + + if (! $result) { + $this->response->json(array('message' => 'Unable to save task'), 400); + } else { + $this->response->json(array('message' => 'OK'), 201); + } + } +} diff --git a/app/Controller/TaskGanttCreationController.php b/app/Controller/TaskGanttCreationController.php new file mode 100644 index 00000000..c2998a3e --- /dev/null +++ b/app/Controller/TaskGanttCreationController.php @@ -0,0 +1,71 @@ +<?php + +namespace Kanboard\Controller; + +/** + * Class TaskGanttCreationController + * + * @package Kanboard\Controller + * @author Frederic Guillot + */ +class TaskGanttCreationController extends BaseController +{ + /** + * Simplified form to create a new task + * + * @access public + * @param array $values + * @param array $errors + * @throws \Kanboard\Core\Controller\PageNotFoundException + */ + public function show(array $values = array(), array $errors = array()) + { + $project = $this->getProject(); + + $values = $values + array( + 'project_id' => $project['id'], + 'column_id' => $this->columnModel->getFirstColumnId($project['id']), + 'position' => 1 + ); + + $values = $this->hook->merge('controller:task:form:default', $values, array('default_values' => $values)); + $values = $this->hook->merge('controller:gantt:task:form:default', $values, array('default_values' => $values)); + + $this->response->html($this->template->render('task_gantt_creation/show', array( + 'project' => $project, + 'errors' => $errors, + 'values' => $values, + 'users_list' => $this->projectUserRoleModel->getAssignableUsersList($project['id'], true, false, true), + 'colors_list' => $this->colorModel->getList(), + 'categories_list' => $this->categoryModel->getList($project['id']), + 'swimlanes_list' => $this->swimlaneModel->getList($project['id'], false, true), + 'title' => $project['name'].' > '.t('New task') + ))); + } + + /** + * Validate and save a new task + * + * @access public + */ + public function save() + { + $project = $this->getProject(); + $values = $this->request->getValues(); + + list($valid, $errors) = $this->taskValidator->validateCreation($values); + + if ($valid) { + $task_id = $this->taskCreationModel->create($values); + + if ($task_id !== false) { + $this->flash->success(t('Task created successfully.')); + return $this->response->redirect($this->helper->url->to('TaskGanttController', 'show', array('project_id' => $project['id']))); + } else { + $this->flash->failure(t('Unable to create your task.')); + } + } + + return $this->show($values, $errors); + } +} diff --git a/app/Controller/TaskImport.php b/app/Controller/TaskImport.php deleted file mode 100644 index 460c608c..00000000 --- a/app/Controller/TaskImport.php +++ /dev/null @@ -1,72 +0,0 @@ -<?php - -namespace Kanboard\Controller; - -use Kanboard\Core\Csv; - -/** - * Task Import controller - * - * @package controller - * @author Frederic Guillot - */ -class TaskImport extends Base -{ - /** - * Upload the file and ask settings - * - */ - public function step1(array $values = array(), array $errors = array()) - { - $project = $this->getProject(); - - $this->response->html($this->helper->layout->project('task_import/step1', array( - 'project' => $project, - 'values' => $values, - 'errors' => $errors, - 'max_size' => ini_get('upload_max_filesize'), - 'delimiters' => Csv::getDelimiters(), - 'enclosures' => Csv::getEnclosures(), - 'title' => t('Import tasks from CSV file'), - ))); - } - - /** - * Process CSV file - * - */ - public function step2() - { - $project = $this->getProject(); - $values = $this->request->getValues(); - $filename = $this->request->getFilePath('file'); - - if (! file_exists($filename)) { - $this->step1($values, array('file' => array(t('Unable to read your file')))); - } - - $this->taskImport->projectId = $project['id']; - - $csv = new Csv($values['delimiter'], $values['enclosure']); - $csv->setColumnMapping($this->taskImport->getColumnMapping()); - $csv->read($filename, array($this->taskImport, 'import')); - - if ($this->taskImport->counter > 0) { - $this->flash->success(t('%d task(s) have been imported successfully.', $this->taskImport->counter)); - } else { - $this->flash->failure(t('Nothing have been imported!')); - } - - $this->response->redirect($this->helper->url->to('taskImport', 'step1', array('project_id' => $project['id']))); - } - - /** - * Generate template - * - */ - public function template() - { - $this->response->forceDownload('tasks.csv'); - $this->response->csv(array($this->taskImport->getColumnMapping())); - } -} diff --git a/app/Controller/TaskImportController.php b/app/Controller/TaskImportController.php new file mode 100644 index 00000000..aff2d390 --- /dev/null +++ b/app/Controller/TaskImportController.php @@ -0,0 +1,74 @@ +<?php + +namespace Kanboard\Controller; + +use Kanboard\Core\Csv; + +/** + * Task Import controller + * + * @package Kanboard\Controller + * @author Frederic Guillot + */ +class TaskImportController extends BaseController +{ + /** + * Upload the file and ask settings + * + * @param array $values + * @param array $errors + * @throws \Kanboard\Core\Controller\PageNotFoundException + */ + public function show(array $values = array(), array $errors = array()) + { + $project = $this->getProject(); + + $this->response->html($this->helper->layout->project('task_import/show', array( + 'project' => $project, + 'values' => $values, + 'errors' => $errors, + 'max_size' => ini_get('upload_max_filesize'), + 'delimiters' => Csv::getDelimiters(), + 'enclosures' => Csv::getEnclosures(), + 'title' => t('Import tasks from CSV file'), + ), 'task_import/sidebar')); + } + + /** + * Process CSV file + */ + public function save() + { + $project = $this->getProject(); + $values = $this->request->getValues(); + $filename = $this->request->getFilePath('file'); + + if (! file_exists($filename)) { + $this->show($values, array('file' => array(t('Unable to read your file')))); + } else { + $this->taskImport->projectId = $project['id']; + + $csv = new Csv($values['delimiter'], $values['enclosure']); + $csv->setColumnMapping($this->taskImport->getColumnMapping()); + $csv->read($filename, array($this->taskImport, 'import')); + + if ($this->taskImport->counter > 0) { + $this->flash->success(t('%d task(s) have been imported successfully.', $this->taskImport->counter)); + } else { + $this->flash->failure(t('Nothing have been imported!')); + } + + $this->response->redirect($this->helper->url->to('TaskImportController', 'show', array('project_id' => $project['id']))); + } + } + + /** + * Generate template + * + */ + public function template() + { + $this->response->withFileDownload('tasks.csv'); + $this->response->csv(array($this->taskImport->getColumnMapping())); + } +} diff --git a/app/Controller/TaskInternalLink.php b/app/Controller/TaskInternalLinkController.php index ac5e04b7..a140f1ff 100644 --- a/app/Controller/TaskInternalLink.php +++ b/app/Controller/TaskInternalLinkController.php @@ -2,27 +2,30 @@ namespace Kanboard\Controller; +use Kanboard\Core\Controller\PageNotFoundException; + /** * TaskInternalLink Controller * - * @package controller + * @package Kanboard\Controller * @author Olivier Maridat * @author Frederic Guillot */ -class TaskInternalLink extends Base +class TaskInternalLinkController extends BaseController { /** * Get the current link * * @access private * @return array + * @throws PageNotFoundException */ private function getTaskLink() { - $link = $this->taskLink->getById($this->request->getIntegerParam('link_id')); + $link = $this->taskLinkModel->getById($this->request->getIntegerParam('link_id')); if (empty($link)) { - return $this->notfound(); + throw new PageNotFoundException(); } return $link; @@ -32,6 +35,10 @@ class TaskInternalLink extends Base * Creation form * * @access public + * @param array $values + * @param array $errors + * @throws PageNotFoundException + * @throws \Kanboard\Core\Controller\AccessForbiddenException */ public function create(array $values = array(), array $errors = array()) { @@ -41,7 +48,7 @@ class TaskInternalLink extends Base 'values' => $values, 'errors' => $errors, 'task' => $task, - 'labels' => $this->link->getList(0, false), + 'labels' => $this->linkModel->getList(0, false), ))); } @@ -58,22 +65,26 @@ class TaskInternalLink extends Base list($valid, $errors) = $this->taskLinkValidator->validateCreation($values); if ($valid) { - if ($this->taskLink->create($values['task_id'], $values['opposite_task_id'], $values['link_id'])) { + if ($this->taskLinkModel->create($values['task_id'], $values['opposite_task_id'], $values['link_id'])) { $this->flash->success(t('Link added successfully.')); - return $this->response->redirect($this->helper->url->to('task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])), true); + return $this->response->redirect($this->helper->url->to('TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])), true); } $errors = array('title' => array(t('The exact same link already exists'))); $this->flash->failure(t('Unable to create your link.')); } - $this->create($values, $errors); + return $this->create($values, $errors); } /** * Edit form * * @access public + * @param array $values + * @param array $errors + * @throws PageNotFoundException + * @throws \Kanboard\Core\Controller\AccessForbiddenException */ public function edit(array $values = array(), array $errors = array()) { @@ -81,7 +92,7 @@ class TaskInternalLink extends Base $task_link = $this->getTaskLink(); if (empty($values)) { - $opposite_task = $this->taskFinder->getById($task_link['opposite_task_id']); + $opposite_task = $this->taskFinderModel->getById($task_link['opposite_task_id']); $values = $task_link; $values['title'] = '#'.$opposite_task['id'].' - '.$opposite_task['title']; } @@ -91,7 +102,7 @@ class TaskInternalLink extends Base 'errors' => $errors, 'task_link' => $task_link, 'task' => $task, - 'labels' => $this->link->getList(0, false) + 'labels' => $this->linkModel->getList(0, false) ))); } @@ -108,15 +119,15 @@ class TaskInternalLink extends Base list($valid, $errors) = $this->taskLinkValidator->validateModification($values); if ($valid) { - if ($this->taskLink->update($values['id'], $values['task_id'], $values['opposite_task_id'], $values['link_id'])) { + if ($this->taskLinkModel->update($values['id'], $values['task_id'], $values['opposite_task_id'], $values['link_id'])) { $this->flash->success(t('Link updated successfully.')); - return $this->response->redirect($this->helper->url->to('task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])).'#links'); + return $this->response->redirect($this->helper->url->to('TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])).'#links'); } $this->flash->failure(t('Unable to update your link.')); } - $this->edit($values, $errors); + return $this->edit($values, $errors); } /** @@ -145,12 +156,12 @@ class TaskInternalLink extends Base $this->checkCSRFParam(); $task = $this->getTask(); - if ($this->taskLink->remove($this->request->getIntegerParam('link_id'))) { + if ($this->taskLinkModel->remove($this->request->getIntegerParam('link_id'))) { $this->flash->success(t('Link removed successfully.')); } else { $this->flash->failure(t('Unable to remove this link.')); } - $this->response->redirect($this->helper->url->to('task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']))); + $this->response->redirect($this->helper->url->to('TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']))); } } diff --git a/app/Controller/Listing.php b/app/Controller/TaskListController.php index 2024ff03..c6d1fa92 100644 --- a/app/Controller/Listing.php +++ b/app/Controller/TaskListController.php @@ -3,15 +3,15 @@ namespace Kanboard\Controller; use Kanboard\Filter\TaskProjectFilter; -use Kanboard\Model\Task as TaskModel; +use Kanboard\Model\TaskModel; /** - * List view controller + * Task List Controller * - * @package controller + * @package Kanboard\Controller * @author Frederic Guillot */ -class Listing extends Base +class TaskListController extends BaseController { /** * Show list view for projects @@ -24,7 +24,7 @@ class Listing extends Base $search = $this->helper->projectHeader->getSearchQuery($project); $paginator = $this->paginator - ->setUrl('listing', 'show', array('project_id' => $project['id'])) + ->setUrl('TaskListController', 'show', array('project_id' => $project['id'])) ->setMax(30) ->setOrder(TaskModel::TABLE.'.id') ->setDirection('DESC') @@ -35,7 +35,7 @@ class Listing extends Base ) ->calculate(); - $this->response->html($this->helper->layout->app('listing/show', array( + $this->response->html($this->helper->layout->app('task_list/show', array( 'project' => $project, 'title' => $project['name'], 'description' => $this->helper->projectHeader->getDescription($project), diff --git a/app/Controller/Taskmodification.php b/app/Controller/TaskModificationController.php index 6b945f37..fc9113dd 100644 --- a/app/Controller/Taskmodification.php +++ b/app/Controller/TaskModificationController.php @@ -7,10 +7,10 @@ use Kanboard\Core\DateParser; /** * Task Modification controller * - * @package controller + * @package Kanboard\Controller * @author Frederic Guillot */ -class Taskmodification extends Base +class TaskModificationController extends BaseController { /** * Set automatically the start date @@ -20,14 +20,18 @@ class Taskmodification extends Base public function start() { $task = $this->getTask(); - $this->taskModification->update(array('id' => $task['id'], 'date_started' => time())); - $this->response->redirect($this->helper->url->to('task', 'show', array('project_id' => $task['project_id'], 'task_id' => $task['id']))); + $this->taskModificationModel->update(array('id' => $task['id'], 'date_started' => time())); + $this->response->redirect($this->helper->url->to('TaskViewController', 'show', array('project_id' => $task['project_id'], 'task_id' => $task['id']))); } /** * Edit description form * * @access public + * @param array $values + * @param array $errors + * @throws \Kanboard\Core\Controller\AccessForbiddenException + * @throws \Kanboard\Core\Controller\PageNotFoundException */ public function description(array $values = array(), array $errors = array()) { @@ -57,27 +61,31 @@ class Taskmodification extends Base list($valid, $errors) = $this->taskValidator->validateDescriptionCreation($values); if ($valid) { - if ($this->taskModification->update($values)) { + if ($this->taskModificationModel->update($values)) { $this->flash->success(t('Task updated successfully.')); } else { $this->flash->failure(t('Unable to update your task.')); } - return $this->response->redirect($this->helper->url->to('task', 'show', array('project_id' => $task['project_id'], 'task_id' => $task['id'])), true); + return $this->response->redirect($this->helper->url->to('TaskViewController', 'show', array('project_id' => $task['project_id'], 'task_id' => $task['id'])), true); } - $this->description($values, $errors); + return $this->description($values, $errors); } /** * Display a form to edit a task * * @access public + * @param array $values + * @param array $errors + * @throws \Kanboard\Core\Controller\AccessForbiddenException + * @throws \Kanboard\Core\Controller\PageNotFoundException */ public function edit(array $values = array(), array $errors = array()) { $task = $this->getTask(); - $project = $this->project->getById($task['project_id']); + $project = $this->projectModel->getById($task['project_id']); if (empty($values)) { $values = $task; @@ -85,17 +93,17 @@ class Taskmodification extends Base $values = $this->hook->merge('controller:task-modification:form:default', $values, array('default_values' => $values)); } - $values = $this->dateParser->format($values, array('date_due'), $this->config->get('application_date_format', DateParser::DATE_FORMAT)); - $values = $this->dateParser->format($values, array('date_started'), $this->config->get('application_datetime_format', DateParser::DATE_TIME_FORMAT)); + $values = $this->dateParser->format($values, array('date_due'), $this->configModel->get('application_date_format', DateParser::DATE_FORMAT)); + $values = $this->dateParser->format($values, array('date_started'), $this->configModel->get('application_datetime_format', DateParser::DATE_TIME_FORMAT)); $this->response->html($this->template->render('task_modification/edit_task', array( 'project' => $project, 'values' => $values, 'errors' => $errors, 'task' => $task, - 'users_list' => $this->projectUserRole->getAssignableUsersList($task['project_id']), - 'colors_list' => $this->color->getList(), - 'categories_list' => $this->category->getList($task['project_id']), + 'users_list' => $this->projectUserRoleModel->getAssignableUsersList($task['project_id']), + 'colors_list' => $this->colorModel->getList(), + 'categories_list' => $this->categoryModel->getList($task['project_id']), ))); } @@ -111,9 +119,9 @@ class Taskmodification extends Base list($valid, $errors) = $this->taskValidator->validateModification($values); - if ($valid && $this->taskModification->update($values)) { + if ($valid && $this->taskModificationModel->update($values)) { $this->flash->success(t('Task updated successfully.')); - return $this->response->redirect($this->helper->url->to('task', 'show', array('project_id' => $task['project_id'], 'task_id' => $task['id'])), true); + $this->response->redirect($this->helper->url->to('TaskViewController', 'show', array('project_id' => $task['project_id'], 'task_id' => $task['id'])), true); } else { $this->flash->failure(t('Unable to update your task.')); $this->edit($values, $errors); diff --git a/app/Controller/TaskPopoverController.php b/app/Controller/TaskPopoverController.php new file mode 100644 index 00000000..bf4e23d5 --- /dev/null +++ b/app/Controller/TaskPopoverController.php @@ -0,0 +1,100 @@ +<?php + +namespace Kanboard\Controller; + +/** + * Task Popover + * + * @package Kanboard\Controller + * @author Frederic Guillot + */ +class TaskPopoverController extends BaseController +{ + /** + * Change a task assignee directly from the board + * + * @access public + */ + public function changeAssignee() + { + $task = $this->getTask(); + $project = $this->projectModel->getById($task['project_id']); + + $this->response->html($this->template->render('task_popover/change_assignee', array( + 'values' => $task, + 'users_list' => $this->projectUserRoleModel->getAssignableUsersList($project['id']), + 'project' => $project, + ))); + } + + /** + * Validate an assignee modification + * + * @access public + */ + public function updateAssignee() + { + $values = $this->request->getValues(); + + list($valid,) = $this->taskValidator->validateAssigneeModification($values); + + if ($valid && $this->taskModificationModel->update($values)) { + $this->flash->success(t('Task updated successfully.')); + } else { + $this->flash->failure(t('Unable to update your task.')); + } + + $this->response->redirect($this->helper->url->to('BoardViewController', 'show', array('project_id' => $values['project_id'])), true); + } + + /** + * Change a task category directly from the board + * + * @access public + */ + public function changeCategory() + { + $task = $this->getTask(); + $project = $this->projectModel->getById($task['project_id']); + + $this->response->html($this->template->render('task_popover/change_category', array( + 'values' => $task, + 'categories_list' => $this->categoryModel->getList($project['id']), + 'project' => $project, + ))); + } + + /** + * Validate a category modification + * + * @access public + */ + public function updateCategory() + { + $values = $this->request->getValues(); + + list($valid,) = $this->taskValidator->validateCategoryModification($values); + + if ($valid && $this->taskModificationModel->update($values)) { + $this->flash->success(t('Task updated successfully.')); + } else { + $this->flash->failure(t('Unable to update your task.')); + } + + $this->response->redirect($this->helper->url->to('BoardViewController', 'show', array('project_id' => $values['project_id'])), true); + } + + /** + * Screenshot popover + * + * @access public + */ + public function screenshot() + { + $task = $this->getTask(); + + $this->response->html($this->template->render('task_file/screenshot', array( + 'task' => $task, + ))); + } +} diff --git a/app/Controller/TaskRecurrence.php b/app/Controller/TaskRecurrenceController.php index 569ef8d9..dc7a0e1b 100644 --- a/app/Controller/TaskRecurrence.php +++ b/app/Controller/TaskRecurrenceController.php @@ -5,15 +5,19 @@ namespace Kanboard\Controller; /** * Task Recurrence controller * - * @package controller + * @package Kanboard\Controller * @author Frederic Guillot */ -class TaskRecurrence extends Base +class TaskRecurrenceController extends BaseController { /** * Edit recurrence form * * @access public + * @param array $values + * @param array $errors + * @throws \Kanboard\Core\Controller\AccessForbiddenException + * @throws \Kanboard\Core\Controller\PageNotFoundException */ public function edit(array $values = array(), array $errors = array()) { @@ -27,10 +31,10 @@ class TaskRecurrence extends Base 'values' => $values, 'errors' => $errors, 'task' => $task, - 'recurrence_status_list' => $this->task->getRecurrenceStatusList(), - 'recurrence_trigger_list' => $this->task->getRecurrenceTriggerList(), - 'recurrence_timeframe_list' => $this->task->getRecurrenceTimeframeList(), - 'recurrence_basedate_list' => $this->task->getRecurrenceBasedateList(), + 'recurrence_status_list' => $this->taskModel->getRecurrenceStatusList(), + 'recurrence_trigger_list' => $this->taskModel->getRecurrenceTriggerList(), + 'recurrence_timeframe_list' => $this->taskModel->getRecurrenceTimeframeList(), + 'recurrence_basedate_list' => $this->taskModel->getRecurrenceBasedateList(), ))); } @@ -47,15 +51,15 @@ class TaskRecurrence extends Base list($valid, $errors) = $this->taskValidator->validateEditRecurrence($values); if ($valid) { - if ($this->taskModification->update($values)) { + if ($this->taskModificationModel->update($values)) { $this->flash->success(t('Task updated successfully.')); } else { $this->flash->failure(t('Unable to update your task.')); } - $this->response->redirect($this->helper->url->to('task', 'show', array('project_id' => $task['project_id'], 'task_id' => $task['id'])), true); + return $this->response->redirect($this->helper->url->to('TaskViewController', 'show', array('project_id' => $task['project_id'], 'task_id' => $task['id'])), true); } - $this->edit($values, $errors); + return $this->edit($values, $errors); } } diff --git a/app/Controller/Taskstatus.php b/app/Controller/TaskStatusController.php index a67459c9..82b4f9c4 100644 --- a/app/Controller/Taskstatus.php +++ b/app/Controller/TaskStatusController.php @@ -5,10 +5,10 @@ namespace Kanboard\Controller; /** * Task Status controller * - * @package controller + * @package Kanboard\Controller * @author Frederic Guillot */ -class Taskstatus extends Base +class TaskStatusController extends BaseController { /** * Close a task @@ -46,16 +46,16 @@ class Taskstatus extends Base if ($this->request->getStringParam('confirmation') === 'yes') { $this->checkCSRFParam(); - if ($this->taskStatus->$method($task['id'])) { + if ($this->taskStatusModel->$method($task['id'])) { $this->flash->success($success_message); } else { $this->flash->failure($failure_message); } - return $this->response->redirect($this->helper->url->to('task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])), true); + return $this->response->redirect($this->helper->url->to('TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])), true); } - $this->response->html($this->template->render($template, array( + return $this->response->html($this->template->render($template, array( 'task' => $task, ))); } diff --git a/app/Controller/TaskSuppressionController.php b/app/Controller/TaskSuppressionController.php new file mode 100644 index 00000000..600107c9 --- /dev/null +++ b/app/Controller/TaskSuppressionController.php @@ -0,0 +1,53 @@ +<?php + +namespace Kanboard\Controller; + +use Kanboard\Core\Controller\AccessForbiddenException; + +/** + * Class TaskSuppressionController + * + * @package Kanboard\Controller + * @author Frederic Guillot + */ +class TaskSuppressionController extends BaseController +{ + /** + * Confirmation dialog box before to remove the task + */ + public function confirm() + { + $task = $this->getTask(); + + if (! $this->helper->user->canRemoveTask($task)) { + throw new AccessForbiddenException(); + } + + $this->response->html($this->template->render('task_suppression/remove', array( + 'task' => $task, + 'redirect' => $this->request->getStringParam('redirect'), + ))); + } + + /** + * Remove a task + */ + public function remove() + { + $task = $this->getTask(); + $this->checkCSRFParam(); + + if (! $this->helper->user->canRemoveTask($task)) { + throw new AccessForbiddenException(); + } + + if ($this->taskModel->remove($task['id'])) { + $this->flash->success(t('Task removed successfully.')); + } else { + $this->flash->failure(t('Unable to remove this task.')); + } + + $redirect = $this->request->getStringParam('redirect') === ''; + $this->response->redirect($this->helper->url->to('BoardViewController', 'show', array('project_id' => $task['project_id'])), $redirect); + } +} diff --git a/app/Controller/TaskViewController.php b/app/Controller/TaskViewController.php new file mode 100644 index 00000000..2a79ee45 --- /dev/null +++ b/app/Controller/TaskViewController.php @@ -0,0 +1,146 @@ +<?php + +namespace Kanboard\Controller; + +use Kanboard\Core\Controller\AccessForbiddenException; +use Kanboard\Core\Controller\PageNotFoundException; +use Kanboard\Core\DateParser; + +/** + * Task Controller + * + * @package Kanboard\Controller + * @author Frederic Guillot + */ +class TaskViewController extends BaseController +{ + /** + * Public access (display a task) + * + * @access public + */ + public function readonly() + { + $project = $this->projectModel->getByToken($this->request->getStringParam('token')); + + // Token verification + if (empty($project)) { + throw AccessForbiddenException::getInstance()->withoutLayout(); + } + + $task = $this->taskFinderModel->getDetails($this->request->getIntegerParam('task_id')); + + if (empty($task)) { + throw PageNotFoundException::getInstance()->withoutLayout(); + } + + if ($task['project_id'] != $project['id']) { + throw AccessForbiddenException::getInstance()->withoutLayout(); + } + + $this->response->html($this->helper->layout->app('task/public', array( + 'project' => $project, + 'comments' => $this->commentModel->getAll($task['id']), + 'subtasks' => $this->subtaskModel->getAll($task['id']), + 'links' => $this->taskLinkModel->getAllGroupedByLabel($task['id']), + 'task' => $task, + 'columns_list' => $this->columnModel->getList($task['project_id']), + 'colors_list' => $this->colorModel->getList(), + 'title' => $task['title'], + 'no_layout' => true, + 'auto_refresh' => true, + 'not_editable' => true, + ))); + } + + /** + * Show a task + * + * @access public + */ + public function show() + { + $task = $this->getTask(); + $subtasks = $this->subtaskModel->getAll($task['id']); + + $values = array( + 'id' => $task['id'], + 'date_started' => $task['date_started'], + 'time_estimated' => $task['time_estimated'] ?: '', + 'time_spent' => $task['time_spent'] ?: '', + ); + + $values = $this->dateParser->format($values, array('date_started'), $this->configModel->get('application_datetime_format', DateParser::DATE_TIME_FORMAT)); + + $this->response->html($this->helper->layout->task('task/show', array( + 'task' => $task, + 'project' => $this->projectModel->getById($task['project_id']), + 'values' => $values, + 'files' => $this->taskFileModel->getAllDocuments($task['id']), + 'images' => $this->taskFileModel->getAllImages($task['id']), + 'comments' => $this->commentModel->getAll($task['id'], $this->userSession->getCommentSorting()), + 'subtasks' => $subtasks, + 'internal_links' => $this->taskLinkModel->getAllGroupedByLabel($task['id']), + 'external_links' => $this->taskExternalLinkModel->getAll($task['id']), + 'link_label_list' => $this->linkModel->getList(0, false), + ))); + } + + /** + * Display task analytics + * + * @access public + */ + public function analytics() + { + $task = $this->getTask(); + + $this->response->html($this->helper->layout->task('task/analytics', array( + 'task' => $task, + 'project' => $this->projectModel->getById($task['project_id']), + 'lead_time' => $this->taskAnalyticModel->getLeadTime($task), + 'cycle_time' => $this->taskAnalyticModel->getCycleTime($task), + 'time_spent_columns' => $this->taskAnalyticModel->getTimeSpentByColumn($task), + ))); + } + + /** + * Display the time tracking details + * + * @access public + */ + public function timetracking() + { + $task = $this->getTask(); + + $subtask_paginator = $this->paginator + ->setUrl('TaskViewController', 'timetracking', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'pagination' => 'subtasks')) + ->setMax(15) + ->setOrder('start') + ->setDirection('DESC') + ->setQuery($this->subtaskTimeTrackingModel->getTaskQuery($task['id'])) + ->calculateOnlyIf($this->request->getStringParam('pagination') === 'subtasks'); + + $this->response->html($this->helper->layout->task('task/time_tracking_details', array( + 'task' => $task, + 'project' => $this->projectModel->getById($task['project_id']), + 'subtask_paginator' => $subtask_paginator, + ))); + } + + /** + * Display the task transitions + * + * @access public + */ + public function transitions() + { + $task = $this->getTask(); + + $this->response->html($this->helper->layout->task('task/transitions', array( + 'task' => $task, + 'project' => $this->projectModel->getById($task['project_id']), + 'transitions' => $this->transitionModel->getAllByTask($task['id']), + ))); + } +} diff --git a/app/Controller/Twofactor.php b/app/Controller/TwoFactorController.php index 10292261..d02c8950 100644 --- a/app/Controller/Twofactor.php +++ b/app/Controller/TwoFactorController.php @@ -2,23 +2,27 @@ namespace Kanboard\Controller; +use Kanboard\Core\Controller\AccessForbiddenException; + /** * Two Factor Auth controller * - * @package controller + * @package Kanboard/Controller * @author Frederic Guillot */ -class Twofactor extends User +class TwoFactorController extends UserViewController { /** * Only the current user can access to 2FA settings * * @access private + * @param array $user + * @throws AccessForbiddenException */ private function checkCurrentUser(array $user) { if ($user['id'] != $this->userSession->getId()) { - $this->forbidden(); + throw new AccessForbiddenException(); } } @@ -87,7 +91,7 @@ class Twofactor extends User if ($provider->authenticate()) { $this->flash->success(t('The two factor authentication code is valid.')); - $this->user->update(array( + $this->userModel->update(array( 'id' => $user['id'], 'twofactor_activated' => 1, 'twofactor_secret' => $this->authenticationManager->getPostAuthenticationProvider()->getSecret(), @@ -96,10 +100,10 @@ class Twofactor extends User unset($this->sessionStorage->twoFactorSecret); $this->userSession->disablePostAuthentication(); - $this->response->redirect($this->helper->url->to('twofactor', 'index', array('user_id' => $user['id']))); + $this->response->redirect($this->helper->url->to('TwoFactorController', 'index', array('user_id' => $user['id']))); } else { $this->flash->failure(t('The two factor authentication code is not valid.')); - $this->response->redirect($this->helper->url->to('twofactor', 'show', array('user_id' => $user['id']))); + $this->response->redirect($this->helper->url->to('TwoFactorController', 'show', array('user_id' => $user['id']))); } } @@ -113,7 +117,7 @@ class Twofactor extends User $user = $this->getUser(); $this->checkCurrentUser($user); - $this->user->update(array( + $this->userModel->update(array( 'id' => $user['id'], 'twofactor_activated' => 0, 'twofactor_secret' => '', @@ -123,7 +127,7 @@ class Twofactor extends User $this->userSession->disablePostAuthentication(); $this->flash->success(t('User updated successfully.')); - $this->response->redirect($this->helper->url->to('twofactor', 'index', array('user_id' => $user['id']))); + $this->response->redirect($this->helper->url->to('TwoFactorController', 'index', array('user_id' => $user['id']))); } /** @@ -145,10 +149,10 @@ class Twofactor extends User if ($provider->authenticate()) { $this->userSession->validatePostAuthentication(); $this->flash->success(t('The two factor authentication code is valid.')); - $this->response->redirect($this->helper->url->to('app', 'index')); + $this->response->redirect($this->helper->url->to('DashboardController', 'show')); } else { $this->flash->failure(t('The two factor authentication code is not valid.')); - $this->response->redirect($this->helper->url->to('twofactor', 'code')); + $this->response->redirect($this->helper->url->to('TwoFactorController', 'code')); } } @@ -182,16 +186,16 @@ class Twofactor extends User if ($this->request->getStringParam('disable') === 'yes') { $this->checkCSRFParam(); - $this->user->update(array( + $this->userModel->update(array( 'id' => $user['id'], 'twofactor_activated' => 0, 'twofactor_secret' => '', )); - $this->response->redirect($this->helper->url->to('user', 'show', array('user_id' => $user['id']))); + return $this->response->redirect($this->helper->url->to('UserViewController', 'show', array('user_id' => $user['id']))); } - $this->response->html($this->helper->layout->user('twofactor/disable', array( + return $this->response->html($this->helper->layout->user('twofactor/disable', array( 'user' => $user, ))); } diff --git a/app/Controller/User.php b/app/Controller/User.php deleted file mode 100644 index f7d7d2e0..00000000 --- a/app/Controller/User.php +++ /dev/null @@ -1,408 +0,0 @@ -<?php - -namespace Kanboard\Controller; - -use Kanboard\Notification\Mail as MailNotification; -use Kanboard\Model\Project as ProjectModel; -use Kanboard\Core\Security\Role; - -/** - * User controller - * - * @package controller - * @author Frederic Guillot - */ -class User extends Base -{ - /** - * List all users - * - * @access public - */ - public function index() - { - $paginator = $this->paginator - ->setUrl('user', 'index') - ->setMax(30) - ->setOrder('username') - ->setQuery($this->user->getQuery()) - ->calculate(); - - $this->response->html( - $this->helper->layout->app('user/index', array( - 'title' => t('Users').' ('.$paginator->getTotal().')', - 'paginator' => $paginator, - ) - )); - } - - /** - * Public user profile - * - * @access public - */ - public function profile() - { - $user = $this->user->getById($this->request->getIntegerParam('user_id')); - - if (empty($user)) { - $this->notfound(); - } - - $this->response->html( - $this->helper->layout->app('user/profile', array( - 'title' => $user['name'] ?: $user['username'], - 'user' => $user, - ) - )); - } - - /** - * Display a form to create a new user - * - * @access public - */ - public function create(array $values = array(), array $errors = array()) - { - $is_remote = $this->request->getIntegerParam('remote') == 1 || (isset($values['is_ldap_user']) && $values['is_ldap_user'] == 1); - - $this->response->html($this->helper->layout->app($is_remote ? 'user/create_remote' : 'user/create_local', array( - 'timezones' => $this->config->getTimezones(true), - 'languages' => $this->config->getLanguages(true), - 'roles' => $this->role->getApplicationRoles(), - 'projects' => $this->project->getList(), - 'errors' => $errors, - 'values' => $values + array('role' => Role::APP_USER), - 'title' => t('New user') - ))); - } - - /** - * Validate and save a new user - * - * @access public - */ - public function save() - { - $values = $this->request->getValues(); - list($valid, $errors) = $this->userValidator->validateCreation($values); - - if ($valid) { - $project_id = empty($values['project_id']) ? 0 : $values['project_id']; - unset($values['project_id']); - - $user_id = $this->user->create($values); - - if ($user_id !== false) { - $this->projectUserRole->addUser($project_id, $user_id, Role::PROJECT_MEMBER); - - if (! empty($values['notifications_enabled'])) { - $this->userNotificationType->saveSelectedTypes($user_id, array(MailNotification::TYPE)); - } - - $this->flash->success(t('User created successfully.')); - $this->response->redirect($this->helper->url->to('user', 'show', array('user_id' => $user_id))); - } else { - $this->flash->failure(t('Unable to create your user.')); - $values['project_id'] = $project_id; - } - } - - $this->create($values, $errors); - } - - /** - * Display user information - * - * @access public - */ - public function show() - { - $user = $this->getUser(); - $this->response->html($this->helper->layout->user('user/show', array( - 'user' => $user, - 'timezones' => $this->config->getTimezones(true), - 'languages' => $this->config->getLanguages(true), - ))); - } - - /** - * Display timesheet - * - * @access public - */ - public function timesheet() - { - $user = $this->getUser(); - - $subtask_paginator = $this->paginator - ->setUrl('user', 'timesheet', array('user_id' => $user['id'], 'pagination' => 'subtasks')) - ->setMax(20) - ->setOrder('start') - ->setDirection('DESC') - ->setQuery($this->subtaskTimeTracking->getUserQuery($user['id'])) - ->calculateOnlyIf($this->request->getStringParam('pagination') === 'subtasks'); - - $this->response->html($this->helper->layout->user('user/timesheet', array( - 'subtask_paginator' => $subtask_paginator, - 'user' => $user, - ))); - } - - /** - * Display last password reset - * - * @access public - */ - public function passwordReset() - { - $user = $this->getUser(); - $this->response->html($this->helper->layout->user('user/password_reset', array( - 'tokens' => $this->passwordReset->getAll($user['id']), - 'user' => $user, - ))); - } - - /** - * Display last connections - * - * @access public - */ - public function last() - { - $user = $this->getUser(); - $this->response->html($this->helper->layout->user('user/last', array( - 'last_logins' => $this->lastLogin->getAll($user['id']), - 'user' => $user, - ))); - } - - /** - * Display user sessions - * - * @access public - */ - public function sessions() - { - $user = $this->getUser(); - $this->response->html($this->helper->layout->user('user/sessions', array( - 'sessions' => $this->rememberMeSession->getAll($user['id']), - 'user' => $user, - ))); - } - - /** - * Remove a "RememberMe" token - * - * @access public - */ - public function removeSession() - { - $this->checkCSRFParam(); - $user = $this->getUser(); - $this->rememberMeSession->remove($this->request->getIntegerParam('id')); - $this->response->redirect($this->helper->url->to('user', 'sessions', array('user_id' => $user['id']))); - } - - /** - * Display user notifications - * - * @access public - */ - public function notifications() - { - $user = $this->getUser(); - - if ($this->request->isPost()) { - $values = $this->request->getValues(); - $this->userNotification->saveSettings($user['id'], $values); - $this->flash->success(t('User updated successfully.')); - $this->response->redirect($this->helper->url->to('user', 'notifications', array('user_id' => $user['id']))); - } - - $this->response->html($this->helper->layout->user('user/notifications', array( - 'projects' => $this->projectUserRole->getProjectsByUser($user['id'], array(ProjectModel::ACTIVE)), - 'notifications' => $this->userNotification->readSettings($user['id']), - 'types' => $this->userNotificationType->getTypes(), - 'filters' => $this->userNotificationFilter->getFilters(), - 'user' => $user, - ))); - } - - /** - * Display user integrations - * - * @access public - */ - public function integrations() - { - $user = $this->getUser(); - - if ($this->request->isPost()) { - $values = $this->request->getValues(); - $this->userMetadata->save($user['id'], $values); - $this->flash->success(t('User updated successfully.')); - $this->response->redirect($this->helper->url->to('user', 'integrations', array('user_id' => $user['id']))); - } - - $this->response->html($this->helper->layout->user('user/integrations', array( - 'user' => $user, - 'values' => $this->userMetadata->getall($user['id']), - ))); - } - - /** - * Display external accounts - * - * @access public - */ - public function external() - { - $user = $this->getUser(); - $this->response->html($this->helper->layout->user('user/external', array( - 'last_logins' => $this->lastLogin->getAll($user['id']), - 'user' => $user, - ))); - } - - /** - * Public access management - * - * @access public - */ - public function share() - { - $user = $this->getUser(); - $switch = $this->request->getStringParam('switch'); - - if ($switch === 'enable' || $switch === 'disable') { - $this->checkCSRFParam(); - - if ($this->user->{$switch.'PublicAccess'}($user['id'])) { - $this->flash->success(t('User updated successfully.')); - } else { - $this->flash->failure(t('Unable to update this user.')); - } - - $this->response->redirect($this->helper->url->to('user', 'share', array('user_id' => $user['id']))); - } - - $this->response->html($this->helper->layout->user('user/share', array( - 'user' => $user, - 'title' => t('Public access'), - ))); - } - - /** - * Password modification - * - * @access public - */ - public function password() - { - $user = $this->getUser(); - $values = array('id' => $user['id']); - $errors = array(); - - if ($this->request->isPost()) { - $values = $this->request->getValues(); - list($valid, $errors) = $this->userValidator->validatePasswordModification($values); - - if ($valid) { - if ($this->user->update($values)) { - $this->flash->success(t('Password modified successfully.')); - } else { - $this->flash->failure(t('Unable to change the password.')); - } - - $this->response->redirect($this->helper->url->to('user', 'show', array('user_id' => $user['id']))); - } - } - - $this->response->html($this->helper->layout->user('user/password', array( - 'values' => $values, - 'errors' => $errors, - 'user' => $user, - ))); - } - - /** - * Display a form to edit a user - * - * @access public - */ - public function edit() - { - $user = $this->getUser(); - $values = $user; - $errors = array(); - - unset($values['password']); - - if ($this->request->isPost()) { - $values = $this->request->getValues(); - - if (! $this->userSession->isAdmin()) { - if (isset($values['role'])) { - unset($values['role']); - } - } - - list($valid, $errors) = $this->userValidator->validateModification($values); - - if ($valid) { - if ($this->user->update($values)) { - $this->flash->success(t('User updated successfully.')); - } else { - $this->flash->failure(t('Unable to update your user.')); - } - - $this->response->redirect($this->helper->url->to('user', 'show', array('user_id' => $user['id']))); - } - } - - $this->response->html($this->helper->layout->user('user/edit', array( - 'values' => $values, - 'errors' => $errors, - 'user' => $user, - 'timezones' => $this->config->getTimezones(true), - 'languages' => $this->config->getLanguages(true), - 'roles' => $this->role->getApplicationRoles(), - ))); - } - - /** - * Display a form to edit authentication - * - * @access public - */ - public function authentication() - { - $user = $this->getUser(); - $values = $user; - $errors = array(); - - unset($values['password']); - - if ($this->request->isPost()) { - $values = $this->request->getValues() + array('disable_login_form' => 0, 'is_ldap_user' => 0); - list($valid, $errors) = $this->userValidator->validateModification($values); - - if ($valid) { - if ($this->user->update($values)) { - $this->flash->success(t('User updated successfully.')); - } else { - $this->flash->failure(t('Unable to update your user.')); - } - - $this->response->redirect($this->helper->url->to('user', 'authentication', array('user_id' => $user['id']))); - } - } - - $this->response->html($this->helper->layout->user('user/authentication', array( - 'values' => $values, - 'errors' => $errors, - 'user' => $user, - ))); - } -} diff --git a/app/Controller/UserHelper.php b/app/Controller/UserAjaxController.php index 47bbe554..ed180471 100644 --- a/app/Controller/UserHelper.php +++ b/app/Controller/UserAjaxController.php @@ -4,15 +4,15 @@ namespace Kanboard\Controller; use Kanboard\Filter\UserNameFilter; use Kanboard\Formatter\UserAutoCompleteFormatter; -use Kanboard\Model\User as UserModel; +use Kanboard\Model\UserModel; /** - * User Helper + * User Ajax Controller * - * @package controller + * @package Kanboard\Controller * @author Frederic Guillot */ -class UserHelper extends Base +class UserAjaxController extends BaseController { /** * User auto-completion (Ajax) @@ -36,7 +36,17 @@ class UserHelper extends Base { $project_id = $this->request->getStringParam('project_id'); $query = $this->request->getStringParam('q'); - $users = $this->projectPermission->findUsernames($project_id, $query); + $users = $this->projectPermissionModel->findUsernames($project_id, $query); $this->response->json($users); } + + /** + * Check if the user is connected + * + * @access public + */ + public function status() + { + $this->response->text('OK'); + } } diff --git a/app/Controller/UserCreationController.php b/app/Controller/UserCreationController.php new file mode 100644 index 00000000..9c873f85 --- /dev/null +++ b/app/Controller/UserCreationController.php @@ -0,0 +1,83 @@ +<?php + +namespace Kanboard\Controller; + +use Kanboard\Core\Security\Role; +use Kanboard\Notification\MailNotification; + +/** + * Class UserCreationController + * + * @package Kanboard\Controller + * @author Frederic Guillot + */ +class UserCreationController extends BaseController +{ + /** + * Display a form to create a new user + * + * @access public + * @param array $values + * @param array $errors + */ + public function show(array $values = array(), array $errors = array()) + { + $isRemote = $this->request->getIntegerParam('remote') == 1 || (isset($values['is_ldap_user']) && $values['is_ldap_user'] == 1); + $template = $isRemote ? 'user_creation/remote' : 'user_creation/local'; + + $this->response->html($this->template->render($template, array( + 'timezones' => $this->timezoneModel->getTimezones(true), + 'languages' => $this->languageModel->getLanguages(true), + 'roles' => $this->role->getApplicationRoles(), + 'projects' => $this->projectModel->getList(), + 'errors' => $errors, + 'values' => $values + array('role' => Role::APP_USER), + ))); + } + + /** + * Validate and save a new user + * + * @access public + */ + public function save() + { + $values = $this->request->getValues(); + list($valid, $errors) = $this->userValidator->validateCreation($values); + + if ($valid) { + $this->createUser($values); + } else { + $this->show($values, $errors); + } + } + + /** + * Create user + * + * @param array $values + */ + private function createUser(array $values) + { + $project_id = empty($values['project_id']) ? 0 : $values['project_id']; + unset($values['project_id']); + + $user_id = $this->userModel->create($values); + + if ($user_id !== false) { + if ($project_id !== 0) { + $this->projectUserRoleModel->addUser($project_id, $user_id, Role::PROJECT_MEMBER); + } + + if (! empty($values['notifications_enabled'])) { + $this->userNotificationTypeModel->saveSelectedTypes($user_id, array(MailNotification::TYPE)); + } + + $this->flash->success(t('User created successfully.')); + $this->response->redirect($this->helper->url->to('UserViewController', 'show', array('user_id' => $user_id))); + } else { + $this->flash->failure(t('Unable to create your user.')); + $this->response->redirect($this->helper->url->to('UserListController', 'show')); + } + } +} diff --git a/app/Controller/UserCredentialController.php b/app/Controller/UserCredentialController.php new file mode 100644 index 00000000..4021dc37 --- /dev/null +++ b/app/Controller/UserCredentialController.php @@ -0,0 +1,109 @@ +<?php + +namespace Kanboard\Controller; + +/** + * Class UserCredentialController + * + * @package Kanboard\Controller + * @author Frederic Guillot + */ +class UserCredentialController extends BaseController +{ + /** + * Password modification form + * + * @access public + * @param array $values + * @param array $errors + * @throws \Kanboard\Core\Controller\AccessForbiddenException + * @throws \Kanboard\Core\Controller\PageNotFoundException + */ + public function changePassword(array $values = array(), array $errors = array()) + { + $user = $this->getUser(); + + return $this->response->html($this->helper->layout->user('user_credential/password', array( + 'values' => $values + array('id' => $user['id']), + 'errors' => $errors, + 'user' => $user, + ))); + } + + /** + * Save new password + * + * @throws \Kanboard\Core\Controller\AccessForbiddenException + * @throws \Kanboard\Core\Controller\PageNotFoundException + */ + public function savePassword() + { + $user = $this->getUser(); + $values = $this->request->getValues(); + + list($valid, $errors) = $this->userValidator->validatePasswordModification($values); + + if ($valid) { + if ($this->userModel->update($values)) { + $this->flash->success(t('Password modified successfully.')); + $this->userLockingModel->resetFailedLogin($user['username']); + } else { + $this->flash->failure(t('Unable to change the password.')); + } + + return $this->response->redirect($this->helper->url->to('UserViewController', 'show', array('user_id' => $user['id']))); + } + + return $this->changePassword($values, $errors); + } + + /** + * Display a form to edit authentication + * + * @access public + * @param array $values + * @param array $errors + * @throws \Kanboard\Core\Controller\AccessForbiddenException + * @throws \Kanboard\Core\Controller\PageNotFoundException + */ + public function changeAuthentication(array $values = array(), array $errors = array()) + { + $user = $this->getUser(); + + if (empty($values)) { + $values = $user; + unset($values['password']); + } + + return $this->response->html($this->helper->layout->user('user_credential/authentication', array( + 'values' => $values, + 'errors' => $errors, + 'user' => $user, + ))); + } + + /** + * Save authentication + * + * @throws \Kanboard\Core\Controller\AccessForbiddenException + * @throws \Kanboard\Core\Controller\PageNotFoundException + */ + public function saveAuthentication() + { + $user = $this->getUser(); + $values = $this->request->getValues() + array('disable_login_form' => 0, 'is_ldap_user' => 0); + list($valid, $errors) = $this->userValidator->validateModification($values); + + if ($valid) { + if ($this->userModel->update($values)) { + $this->flash->success(t('User updated successfully.')); + } else { + $this->flash->failure(t('Unable to update your user.')); + } + + return $this->response->redirect($this->helper->url->to('UserCredentialController', 'changeAuthentication', array('user_id' => $user['id']))); + } + + return $this->changeAuthentication($values, $errors); + } +} diff --git a/app/Controller/UserImport.php b/app/Controller/UserImportController.php index debd69e5..fec9a31d 100644 --- a/app/Controller/UserImport.php +++ b/app/Controller/UserImportController.php @@ -7,51 +7,43 @@ use Kanboard\Core\Csv; /** * User Import controller * - * @package controller + * @package Kanboard\Controller * @author Frederic Guillot */ -class UserImport extends Base +class UserImportController extends BaseController { /** * Upload the file and ask settings * + * @param array $values + * @param array $errors */ - public function step1(array $values = array(), array $errors = array()) + public function show(array $values = array(), array $errors = array()) { - $this->response->html($this->helper->layout->app('user_import/step1', array( + $this->response->html($this->template->render('user_import/show', array( 'values' => $values, 'errors' => $errors, 'max_size' => ini_get('upload_max_filesize'), 'delimiters' => Csv::getDelimiters(), 'enclosures' => Csv::getEnclosures(), - 'title' => t('Import users from CSV file'), ))); } /** - * Process CSV file - * + * Submit form */ - public function step2() + public function save() { $values = $this->request->getValues(); $filename = $this->request->getFilePath('file'); if (! file_exists($filename)) { - $this->step1($values, array('file' => array(t('Unable to read your file')))); - } - - $csv = new Csv($values['delimiter'], $values['enclosure']); - $csv->setColumnMapping($this->userImport->getColumnMapping()); - $csv->read($filename, array($this->userImport, 'import')); - - if ($this->userImport->counter > 0) { - $this->flash->success(t('%d user(s) have been imported successfully.', $this->userImport->counter)); + $this->flash->failure(t('Unable to read your file')); } else { - $this->flash->failure(t('Nothing have been imported!')); + $this->importFile($values, $filename); } - $this->response->redirect($this->helper->url->to('userImport', 'step1')); + $this->response->redirect($this->helper->url->to('UserListController', 'show')); } /** @@ -60,7 +52,26 @@ class UserImport extends Base */ public function template() { - $this->response->forceDownload('users.csv'); + $this->response->withFileDownload('users.csv'); $this->response->csv(array($this->userImport->getColumnMapping())); } + + /** + * Process file + * + * @param array $values + * @param $filename + */ + private function importFile(array $values, $filename) + { + $csv = new Csv($values['delimiter'], $values['enclosure']); + $csv->setColumnMapping($this->userImport->getColumnMapping()); + $csv->read($filename, array($this->userImport, 'import')); + + if ($this->userImport->counter > 0) { + $this->flash->success(t('%d user(s) have been imported successfully.', $this->userImport->counter)); + } else { + $this->flash->failure(t('Nothing have been imported!')); + } + } } diff --git a/app/Controller/UserListController.php b/app/Controller/UserListController.php new file mode 100644 index 00000000..31fcdd44 --- /dev/null +++ b/app/Controller/UserListController.php @@ -0,0 +1,32 @@ +<?php + +namespace Kanboard\Controller; + +/** + * Class User List Controller + * + * @package Kanboard\Controller + * @author Frederic Guillot + */ +class UserListController extends BaseController +{ + /** + * List all users + * + * @access public + */ + public function show() + { + $paginator = $this->paginator + ->setUrl('UserListController', 'show') + ->setMax(30) + ->setOrder('username') + ->setQuery($this->userModel->getQuery()) + ->calculate(); + + $this->response->html($this->helper->layout->app('user_list/show', array( + 'title' => t('Users').' ('.$paginator->getTotal().')', + 'paginator' => $paginator, + ))); + } +} diff --git a/app/Controller/UserModificationController.php b/app/Controller/UserModificationController.php new file mode 100644 index 00000000..d339fd9a --- /dev/null +++ b/app/Controller/UserModificationController.php @@ -0,0 +1,69 @@ +<?php + +namespace Kanboard\Controller; + +/** + * Class UserModificationController + * + * @package Kanboard\Controller + * @author Frederic Guillot + */ +class UserModificationController extends BaseController +{ + /** + * Display a form to edit user information + * + * @access public + * @param array $values + * @param array $errors + * @throws \Kanboard\Core\Controller\AccessForbiddenException + * @throws \Kanboard\Core\Controller\PageNotFoundException + */ + public function show(array $values = array(), array $errors = array()) + { + $user = $this->getUser(); + + if (empty($values)) { + $values = $user; + unset($values['password']); + } + + return $this->response->html($this->helper->layout->user('user_modification/show', array( + 'values' => $values, + 'errors' => $errors, + 'user' => $user, + 'timezones' => $this->timezoneModel->getTimezones(true), + 'languages' => $this->languageModel->getLanguages(true), + 'roles' => $this->role->getApplicationRoles(), + ))); + } + + /** + * Save user information + */ + public function save() + { + $user = $this->getUser(); + $values = $this->request->getValues(); + + if (! $this->userSession->isAdmin()) { + if (isset($values['role'])) { + unset($values['role']); + } + } + + list($valid, $errors) = $this->userValidator->validateModification($values); + + if ($valid) { + if ($this->userModel->update($values)) { + $this->flash->success(t('User updated successfully.')); + } else { + $this->flash->failure(t('Unable to update your user.')); + } + + return $this->response->redirect($this->helper->url->to('UserViewController', 'show', array('user_id' => $user['id']))); + } + + return $this->show($values, $errors); + } +} diff --git a/app/Controller/UserStatus.php b/app/Controller/UserStatusController.php index b8ee5c91..070fb6fc 100644 --- a/app/Controller/UserStatus.php +++ b/app/Controller/UserStatusController.php @@ -5,10 +5,10 @@ namespace Kanboard\Controller; /** * User Status Controller * - * @package controller + * @package Kanboard\Controller * @author Frederic Guillot */ -class UserStatus extends Base +class UserStatusController extends BaseController { /** * Confirm remove a user @@ -34,13 +34,13 @@ class UserStatus extends Base $user = $this->getUser(); $this->checkCSRFParam(); - if ($this->user->remove($user['id'])) { + if ($this->userModel->remove($user['id'])) { $this->flash->success(t('User removed successfully.')); } else { $this->flash->failure(t('Unable to remove this user.')); } - $this->response->redirect($this->helper->url->to('user', 'index')); + $this->response->redirect($this->helper->url->to('UserListController', 'show')); } /** @@ -67,13 +67,13 @@ class UserStatus extends Base $user = $this->getUser(); $this->checkCSRFParam(); - if ($this->user->enable($user['id'])) { + if ($this->userModel->enable($user['id'])) { $this->flash->success(t('User activated successfully.')); } else { $this->flash->failure(t('Unable to enable this user.')); } - $this->response->redirect($this->helper->url->to('user', 'index')); + $this->response->redirect($this->helper->url->to('UserListController', 'show')); } /** @@ -100,12 +100,12 @@ class UserStatus extends Base $user = $this->getUser(); $this->checkCSRFParam(); - if ($this->user->disable($user['id'])) { + if ($this->userModel->disable($user['id'])) { $this->flash->success(t('User disabled successfully.')); } else { $this->flash->failure(t('Unable to disable this user.')); } - $this->response->redirect($this->helper->url->to('user', 'index')); + $this->response->redirect($this->helper->url->to('UserListController', 'show')); } } diff --git a/app/Controller/UserViewController.php b/app/Controller/UserViewController.php new file mode 100644 index 00000000..a73c5c51 --- /dev/null +++ b/app/Controller/UserViewController.php @@ -0,0 +1,217 @@ +<?php + +namespace Kanboard\Controller; + +use Kanboard\Core\Controller\PageNotFoundException; +use Kanboard\Model\ProjectModel; + +/** + * Class UserViewController + * + * @package Kanboard\Controller + * @author Frederic Guillot + */ +class UserViewController extends BaseController +{ + /** + * Public user profile + * + * @access public + * @throws PageNotFoundException + */ + public function profile() + { + $user = $this->userModel->getById($this->request->getIntegerParam('user_id')); + + if (empty($user)) { + throw new PageNotFoundException(); + } + + $this->response->html($this->helper->layout->app('user_view/profile', array( + 'title' => $user['name'] ?: $user['username'], + 'user' => $user, + ))); + } + + /** + * Display user information + * + * @access public + */ + public function show() + { + $user = $this->getUser(); + $this->response->html($this->helper->layout->user('user_view/show', array( + 'user' => $user, + 'timezones' => $this->timezoneModel->getTimezones(true), + 'languages' => $this->languageModel->getLanguages(true), + ))); + } + + /** + * Display timesheet + * + * @access public + */ + public function timesheet() + { + $user = $this->getUser(); + + $subtask_paginator = $this->paginator + ->setUrl('UserViewController', 'timesheet', array('user_id' => $user['id'], 'pagination' => 'subtasks')) + ->setMax(20) + ->setOrder('start') + ->setDirection('DESC') + ->setQuery($this->subtaskTimeTrackingModel->getUserQuery($user['id'])) + ->calculateOnlyIf($this->request->getStringParam('pagination') === 'subtasks'); + + $this->response->html($this->helper->layout->user('user_view/timesheet', array( + 'subtask_paginator' => $subtask_paginator, + 'user' => $user, + ))); + } + + /** + * Display last password reset + * + * @access public + */ + public function passwordReset() + { + $user = $this->getUser(); + $this->response->html($this->helper->layout->user('user_view/password_reset', array( + 'tokens' => $this->passwordResetModel->getAll($user['id']), + 'user' => $user, + ))); + } + + /** + * Display last connections + * + * @access public + */ + public function lastLogin() + { + $user = $this->getUser(); + $this->response->html($this->helper->layout->user('user_view/last', array( + 'last_logins' => $this->lastLoginModel->getAll($user['id']), + 'user' => $user, + ))); + } + + /** + * Display user sessions + * + * @access public + */ + public function sessions() + { + $user = $this->getUser(); + $this->response->html($this->helper->layout->user('user_view/sessions', array( + 'sessions' => $this->rememberMeSessionModel->getAll($user['id']), + 'user' => $user, + ))); + } + + /** + * Remove a "RememberMe" token + * + * @access public + */ + public function removeSession() + { + $this->checkCSRFParam(); + $user = $this->getUser(); + $this->rememberMeSessionModel->remove($this->request->getIntegerParam('id')); + $this->response->redirect($this->helper->url->to('UserViewController', 'sessions', array('user_id' => $user['id']))); + } + + /** + * Display user notifications + * + * @access public + */ + public function notifications() + { + $user = $this->getUser(); + + if ($this->request->isPost()) { + $values = $this->request->getValues(); + $this->userNotificationModel->saveSettings($user['id'], $values); + $this->flash->success(t('User updated successfully.')); + return $this->response->redirect($this->helper->url->to('UserViewController', 'notifications', array('user_id' => $user['id']))); + } + + return $this->response->html($this->helper->layout->user('user_view/notifications', array( + 'projects' => $this->projectUserRoleModel->getProjectsByUser($user['id'], array(ProjectModel::ACTIVE)), + 'notifications' => $this->userNotificationModel->readSettings($user['id']), + 'types' => $this->userNotificationTypeModel->getTypes(), + 'filters' => $this->userNotificationFilterModel->getFilters(), + 'user' => $user, + ))); + } + + /** + * Display user integrations + * + * @access public + */ + public function integrations() + { + $user = $this->getUser(); + + if ($this->request->isPost()) { + $values = $this->request->getValues(); + $this->userMetadataModel->save($user['id'], $values); + $this->flash->success(t('User updated successfully.')); + $this->response->redirect($this->helper->url->to('UserViewController', 'integrations', array('user_id' => $user['id']))); + } + + $this->response->html($this->helper->layout->user('user_view/integrations', array( + 'user' => $user, + 'values' => $this->userMetadataModel->getAll($user['id']), + ))); + } + + /** + * Display external accounts + * + * @access public + */ + public function external() + { + $user = $this->getUser(); + $this->response->html($this->helper->layout->user('user_view/external', array( + 'last_logins' => $this->lastLoginModel->getAll($user['id']), + 'user' => $user, + ))); + } + + /** + * Public access management + * + * @access public + */ + public function share() + { + $user = $this->getUser(); + $switch = $this->request->getStringParam('switch'); + + if ($switch === 'enable' || $switch === 'disable') { + $this->checkCSRFParam(); + + if ($this->userModel->{$switch . 'PublicAccess'}($user['id'])) { + $this->flash->success(t('User updated successfully.')); + } else { + $this->flash->failure(t('Unable to update this user.')); + } + + return $this->response->redirect($this->helper->url->to('UserViewController', 'share', array('user_id' => $user['id']))); + } + + return $this->response->html($this->helper->layout->user('user_view/share', array( + 'user' => $user, + 'title' => t('Public access'), + ))); + } +} diff --git a/app/Controller/WebNotification.php b/app/Controller/WebNotification.php deleted file mode 100644 index dca5cb46..00000000 --- a/app/Controller/WebNotification.php +++ /dev/null @@ -1,50 +0,0 @@ -<?php - -namespace Kanboard\Controller; - -/** - * Web notification controller - * - * @package controller - * @author Frederic Guillot - */ -class WebNotification extends Base -{ - /** - * Mark all notifications as read - * - * @access public - */ - public function flush() - { - $user_id = $this->getUserId(); - - $this->userUnreadNotification->markAllAsRead($user_id); - $this->response->redirect($this->helper->url->to('app', 'notifications', array('user_id' => $user_id))); - } - - /** - * Mark a notification as read - * - * @access public - */ - public function remove() - { - $user_id = $this->getUserId(); - $notification_id = $this->request->getIntegerParam('notification_id'); - - $this->userUnreadNotification->markAsRead($user_id, $notification_id); - $this->response->redirect($this->helper->url->to('app', 'notifications', array('user_id' => $user_id))); - } - - private function getUserId() - { - $user_id = $this->request->getIntegerParam('user_id'); - - if (! $this->userSession->isAdmin() && $user_id != $this->userSession->getId()) { - $user_id = $this->userSession->getId(); - } - - return $user_id; - } -} diff --git a/app/Controller/WebNotificationController.php b/app/Controller/WebNotificationController.php new file mode 100644 index 00000000..46a42063 --- /dev/null +++ b/app/Controller/WebNotificationController.php @@ -0,0 +1,79 @@ +<?php + +namespace Kanboard\Controller; + +/** + * Web notification controller + * + * @package Kanboard\Controller + * @author Frederic Guillot + */ +class WebNotificationController extends BaseController +{ + /** + * Mark all notifications as read + * + * @access public + */ + public function flush() + { + $user_id = $this->getUserId(); + + $this->userUnreadNotificationModel->markAllAsRead($user_id); + $this->response->redirect($this->helper->url->to('DashboardController', 'notifications', array('user_id' => $user_id))); + } + + /** + * Mark a notification as read + * + * @access public + */ + public function remove() + { + $user_id = $this->getUserId(); + $notification_id = $this->request->getIntegerParam('notification_id'); + + $this->userUnreadNotificationModel->markAsRead($user_id, $notification_id); + $this->response->redirect($this->helper->url->to('DashboardController', 'notifications', array('user_id' => $user_id))); + } + + /** + * Redirect to the task and mark notification as read + */ + public function redirect() + { + $user_id = $this->getUserId(); + $notification_id = $this->request->getIntegerParam('notification_id'); + + $notification = $this->userUnreadNotificationModel->getById($notification_id); + $this->userUnreadNotificationModel->markAsRead($user_id, $notification_id); + + if (empty($notification)) { + $this->response->redirect($this->helper->url->to('DashboardController', 'notifications', array('user_id' => $user_id))); + } elseif ($this->helper->text->contains($notification['event_name'], 'comment')) { + $this->response->redirect($this->helper->url->to( + 'TaskViewController', + 'show', + array('task_id' => $notification['event_data']['task']['id'], 'project_id' => $notification['event_data']['task']['project_id']), + 'comment-'.$notification['event_data']['comment']['id'] + )); + } else { + $this->response->redirect($this->helper->url->to( + 'TaskViewController', + 'show', + array('task_id' => $notification['event_data']['task']['id'], 'project_id' => $notification['event_data']['task']['project_id']) + )); + } + } + + private function getUserId() + { + $user_id = $this->request->getIntegerParam('user_id'); + + if (! $this->userSession->isAdmin() && $user_id != $this->userSession->getId()) { + $user_id = $this->userSession->getId(); + } + + return $user_id; + } +} diff --git a/app/Controller/Webhook.php b/app/Controller/Webhook.php deleted file mode 100644 index 0eafe3e5..00000000 --- a/app/Controller/Webhook.php +++ /dev/null @@ -1,42 +0,0 @@ -<?php - -namespace Kanboard\Controller; - -/** - * Webhook controller - * - * @package controller - * @author Frederic Guillot - */ -class Webhook extends Base -{ - /** - * Webhook to create a task - * - * @access public - */ - public function task() - { - $this->checkWebhookToken(); - - $defaultProject = $this->project->getFirst(); - - $values = array( - 'title' => $this->request->getStringParam('title'), - 'description' => $this->request->getStringParam('description'), - 'color_id' => $this->request->getStringParam('color_id'), - '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'), - ); - - list($valid, ) = $this->taskValidator->validateCreation($values); - - if ($valid && $this->taskCreation->create($values)) { - $this->response->text('OK'); - } - - $this->response->text('FAILED'); - } -} |
