summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
Diffstat (limited to 'app')
-rw-r--r--app/Action/CommentCreation.php4
-rw-r--r--app/Action/CommentCreationMoveTaskColumn.php8
-rw-r--r--app/Action/TaskAssignCategoryColor.php6
-rw-r--r--app/Action/TaskAssignCategoryLabel.php2
-rw-r--r--app/Action/TaskAssignCategoryLink.php8
-rw-r--r--app/Action/TaskAssignColorCategory.php6
-rw-r--r--app/Action/TaskAssignColorColumn.php8
-rw-r--r--app/Action/TaskAssignColorLink.php6
-rw-r--r--app/Action/TaskAssignColorPriority.php95
-rw-r--r--app/Action/TaskAssignColorUser.php8
-rw-r--r--app/Action/TaskAssignCurrentUser.php6
-rw-r--r--app/Action/TaskAssignCurrentUserColumn.php6
-rw-r--r--app/Action/TaskAssignSpecificUser.php8
-rw-r--r--app/Action/TaskAssignUser.php4
-rw-r--r--app/Action/TaskClose.php2
-rw-r--r--app/Action/TaskCloseColumn.php6
-rw-r--r--app/Action/TaskCloseNoActivity.php6
-rw-r--r--app/Action/TaskCreation.php2
-rw-r--r--app/Action/TaskDuplicateAnotherProject.php10
-rw-r--r--app/Action/TaskEmail.php12
-rw-r--r--app/Action/TaskEmailNoActivity.php10
-rw-r--r--app/Action/TaskMoveAnotherProject.php8
-rw-r--r--app/Action/TaskMoveColumnAssigned.php10
-rw-r--r--app/Action/TaskMoveColumnCategoryChange.php8
-rw-r--r--app/Action/TaskMoveColumnUnAssigned.php10
-rw-r--r--app/Action/TaskOpen.php2
-rw-r--r--app/Action/TaskUpdateStartDate.php6
-rw-r--r--app/Analytic/AverageLeadCycleTimeAnalytic.php4
-rw-r--r--app/Analytic/AverageTimeSpentColumnAnalytic.php8
-rw-r--r--app/Analytic/EstimatedTimeComparisonAnalytic.php6
-rw-r--r--app/Analytic/TaskDistributionAnalytic.php4
-rw-r--r--app/Analytic/UserDistributionAnalytic.php4
-rw-r--r--app/Api/ActionApi.php (renamed from app/Api/Action.php)12
-rw-r--r--app/Api/AppApi.php (renamed from app/Api/App.php)14
-rw-r--r--app/Api/Auth.php81
-rw-r--r--app/Api/Base.php118
-rw-r--r--app/Api/BaseApi.php74
-rw-r--r--app/Api/BoardApi.php (renamed from app/Api/Board.php)6
-rw-r--r--app/Api/CategoryApi.php (renamed from app/Api/Category.php)16
-rw-r--r--app/Api/ColumnApi.php (renamed from app/Api/Column.php)16
-rw-r--r--app/Api/CommentApi.php (renamed from app/Api/Comment.php)16
-rw-r--r--app/Api/FileApi.php (renamed from app/Api/File.php)19
-rw-r--r--app/Api/GroupApi.php (renamed from app/Api/Group.php)16
-rw-r--r--app/Api/GroupMemberApi.php (renamed from app/Api/GroupMember.php)16
-rw-r--r--app/Api/LinkApi.php (renamed from app/Api/Link.php)20
-rw-r--r--app/Api/MeApi.php (renamed from app/Api/Me.php)26
-rw-r--r--app/Api/Middleware/AuthenticationApiMiddleware.php130
-rw-r--r--app/Api/ProjectApi.php (renamed from app/Api/Project.php)24
-rw-r--r--app/Api/ProjectPermissionApi.php (renamed from app/Api/ProjectPermission.php)21
-rw-r--r--app/Api/SubtaskApi.php (renamed from app/Api/Subtask.php)16
-rw-r--r--app/Api/SwimlaneApi.php (renamed from app/Api/Swimlane.php)30
-rw-r--r--app/Api/TaskApi.php (renamed from app/Api/Task.php)38
-rw-r--r--app/Api/TaskLinkApi.php (renamed from app/Api/TaskLink.php)16
-rw-r--r--app/Api/UserApi.php (renamed from app/Api/User.php)25
-rw-r--r--app/Auth/DatabaseAuth.php6
-rw-r--r--app/Auth/LdapAuth.php2
-rw-r--r--app/Auth/RememberMeAuth.php6
-rw-r--r--app/Console/BaseCommand.php35
-rw-r--r--app/Console/PluginInstallCommand.php36
-rw-r--r--app/Console/PluginUninstallCommand.php36
-rw-r--r--app/Console/PluginUpgradeCommand.php55
-rw-r--r--app/Console/ProjectDailyColumnStatsExportCommand.php2
-rw-r--r--app/Console/ProjectDailyStatsCalculationCommand.php8
-rw-r--r--app/Console/ResetPasswordCommand.php4
-rw-r--r--app/Console/ResetTwoFactorCommand.php4
-rw-r--r--app/Console/TaskOverdueNotificationCommand.php26
-rw-r--r--app/Console/TaskTriggerCommand.php8
-rw-r--r--app/Console/WorkerCommand.php28
-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.php46
-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.php290
-rw-r--r--app/Controller/BaseController.php158
-rw-r--r--app/Controller/Board.php192
-rw-r--r--app/Controller/BoardAjaxController.php140
-rw-r--r--app/Controller/BoardPopover.php135
-rw-r--r--app/Controller/BoardPopoverController.php47
-rw-r--r--app/Controller/BoardTooltipController.php (renamed from app/Controller/BoardTooltip.php)22
-rw-r--r--app/Controller/BoardViewController.php65
-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)58
-rw-r--r--app/Controller/Gantt.php162
-rw-r--r--app/Controller/Group.php250
-rw-r--r--app/Controller/GroupAjaxController.php (renamed from app/Controller/GroupHelper.php)8
-rw-r--r--app/Controller/GroupCreationController.php49
-rw-r--r--app/Controller/GroupListController.php173
-rw-r--r--app/Controller/GroupModificationController.php53
-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.php126
-rw-r--r--app/Controller/Project.php243
-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.php57
-rw-r--r--app/Controller/ProjectListController.php41
-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.php102
-rw-r--r--app/Controller/ProjectUserOverviewController.php (renamed from app/Controller/Projectuser.php)32
-rw-r--r--app/Controller/ProjectViewController.php162
-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.php39
-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.php174
-rw-r--r--app/Controller/TaskAjaxController.php (renamed from app/Controller/TaskHelper.php)8
-rw-r--r--app/Controller/TaskBulkController.php89
-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.php62
-rw-r--r--app/Controller/TaskGanttCreationController.php71
-rw-r--r--app/Controller/TaskImport.php72
-rw-r--r--app/Controller/TaskImportController.php74
-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.php100
-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.php53
-rw-r--r--app/Controller/TaskViewController.php146
-rw-r--r--app/Controller/TwoFactorController.php (renamed from app/Controller/Twofactor.php)30
-rw-r--r--app/Controller/User.php408
-rw-r--r--app/Controller/UserAjaxController.php (renamed from app/Controller/UserHelper.php)20
-rw-r--r--app/Controller/UserCreationController.php83
-rw-r--r--app/Controller/UserCredentialController.php109
-rw-r--r--app/Controller/UserImportController.php (renamed from app/Controller/UserImport.php)51
-rw-r--r--app/Controller/UserListController.php32
-rw-r--r--app/Controller/UserModificationController.php69
-rw-r--r--app/Controller/UserStatusController.php (renamed from app/Controller/UserStatus.php)16
-rw-r--r--app/Controller/UserViewController.php217
-rw-r--r--app/Controller/WebNotification.php50
-rw-r--r--app/Controller/WebNotificationController.php79
-rw-r--r--app/Controller/Webhook.php42
-rw-r--r--app/Core/Action/ActionManager.php4
-rw-r--r--app/Core/Base.php260
-rw-r--r--app/Core/Controller/AccessForbiddenException.php14
-rw-r--r--app/Core/Controller/BaseException.php52
-rw-r--r--app/Core/Controller/BaseMiddleware.php58
-rw-r--r--app/Core/Controller/PageNotFoundException.php14
-rw-r--r--app/Core/Controller/Runner.php105
-rw-r--r--app/Core/Event/EventManager.php22
-rw-r--r--app/Core/Filter/Lexer.php24
-rw-r--r--app/Core/Helper.php3
-rw-r--r--app/Core/Http/Response.php365
-rw-r--r--app/Core/Http/Route.php4
-rw-r--r--app/Core/Http/Router.php62
-rw-r--r--app/Core/Ldap/Group.php7
-rw-r--r--app/Core/Ldap/Query.php4
-rw-r--r--app/Core/Ldap/User.php160
-rw-r--r--app/Core/Mail/Client.php31
-rw-r--r--app/Core/Mail/Transport/Mail.php2
-rw-r--r--app/Core/Markdown.php87
-rw-r--r--app/Core/Notification/NotificationInterface.php (renamed from app/Notification/NotificationInterface.php)4
-rw-r--r--app/Core/Plugin/Base.php16
-rw-r--r--app/Core/Plugin/Directory.php56
-rw-r--r--app/Core/Plugin/Hook.php4
-rw-r--r--app/Core/Plugin/Installer.php162
-rw-r--r--app/Core/Plugin/Loader.php133
-rw-r--r--app/Core/Plugin/PluginInstallerException.php15
-rw-r--r--app/Core/Plugin/SchemaHandler.php122
-rw-r--r--app/Core/Queue/JobHandler.php50
-rw-r--r--app/Core/Queue/QueueManager.php71
-rw-r--r--app/Core/Session/SessionStorage.php1
-rw-r--r--app/Core/Tool.php20
-rw-r--r--app/Core/User/GroupSync.php50
-rw-r--r--app/Core/User/UserProfile.php10
-rw-r--r--app/Core/User/UserProperty.php6
-rw-r--r--app/Core/User/UserSession.php2
-rw-r--r--app/Core/User/UserSync.php10
-rw-r--r--app/Event/UserProfileSyncEvent.php64
-rw-r--r--app/Export/SubtaskExport.php24
-rw-r--r--app/Export/TaskExport.php8
-rw-r--r--app/Export/TransitionExport.php4
-rw-r--r--app/Filter/ProjectActivityCreationDateFilter.php4
-rw-r--r--app/Filter/ProjectActivityCreatorFilter.php4
-rw-r--r--app/Filter/ProjectActivityProjectIdFilter.php4
-rw-r--r--app/Filter/ProjectActivityProjectIdsFilter.php6
-rw-r--r--app/Filter/ProjectActivityProjectNameFilter.php4
-rw-r--r--app/Filter/ProjectActivityTaskIdFilter.php4
-rw-r--r--app/Filter/ProjectActivityTaskStatusFilter.php6
-rw-r--r--app/Filter/ProjectGroupRoleProjectFilter.php4
-rw-r--r--app/Filter/ProjectGroupRoleUsernameFilter.php12
-rw-r--r--app/Filter/ProjectIdsFilter.php6
-rw-r--r--app/Filter/ProjectStatusFilter.php8
-rw-r--r--app/Filter/ProjectTypeFilter.php8
-rw-r--r--app/Filter/ProjectUserRoleProjectFilter.php4
-rw-r--r--app/Filter/ProjectUserRoleUsernameFilter.php6
-rw-r--r--app/Filter/TaskAssigneeFilter.php14
-rw-r--r--app/Filter/TaskCategoryFilter.php10
-rw-r--r--app/Filter/TaskColorFilter.php12
-rw-r--r--app/Filter/TaskColumnFilter.php8
-rw-r--r--app/Filter/TaskCommentFilter.php8
-rw-r--r--app/Filter/TaskCompletionDateFilter.php4
-rw-r--r--app/Filter/TaskCreationDateFilter.php4
-rw-r--r--app/Filter/TaskCreatorFilter.php8
-rw-r--r--app/Filter/TaskDescriptionFilter.php4
-rw-r--r--app/Filter/TaskDueDateFilter.php8
-rw-r--r--app/Filter/TaskDueDateRangeFilter.php6
-rw-r--r--app/Filter/TaskIdExclusionFilter.php4
-rw-r--r--app/Filter/TaskIdFilter.php4
-rw-r--r--app/Filter/TaskLinkFilter.php20
-rw-r--r--app/Filter/TaskModificationDateFilter.php4
-rw-r--r--app/Filter/TaskProjectFilter.php8
-rw-r--r--app/Filter/TaskProjectsFilter.php6
-rw-r--r--app/Filter/TaskReferenceFilter.php4
-rw-r--r--app/Filter/TaskStartDateFilter.php4
-rw-r--r--app/Filter/TaskStatusFilter.php6
-rw-r--r--app/Filter/TaskSubtaskAssigneeFilter.php34
-rw-r--r--app/Filter/TaskSwimlaneFilter.php14
-rw-r--r--app/Filter/TaskTitleFilter.php8
-rw-r--r--app/Formatter/BoardFormatter.php8
-rw-r--r--app/Formatter/ProjectActivityEventFormatter.php2
-rw-r--r--app/Formatter/ProjectGanttFormatter.php10
-rw-r--r--app/Formatter/SubtaskTimeTrackingCalendarFormatter.php6
-rw-r--r--app/Formatter/TaskAutoCompleteFormatter.php4
-rw-r--r--app/Formatter/TaskCalendarFormatter.php8
-rw-r--r--app/Formatter/TaskGanttFormatter.php8
-rw-r--r--app/Formatter/TaskICalFormatter.php2
-rw-r--r--app/Formatter/UserAutoCompleteFormatter.php4
-rw-r--r--app/Group/DatabaseBackendGroupProvider.php2
-rw-r--r--app/Helper/AppHelper.php6
-rw-r--r--app/Helper/AssetHelper.php6
-rw-r--r--app/Helper/CalendarHelper.php4
-rw-r--r--app/Helper/DateHelper.php6
-rw-r--r--app/Helper/LayoutHelper.php24
-rw-r--r--app/Helper/MailHelper.php65
-rw-r--r--app/Helper/ProjectActivityHelper.php12
-rw-r--r--app/Helper/ProjectHeaderHelper.php6
-rw-r--r--app/Helper/SubtaskHelper.php6
-rw-r--r--app/Helper/TaskHelper.php21
-rw-r--r--app/Helper/TextHelper.php20
-rw-r--r--app/Helper/UrlHelper.php4
-rw-r--r--app/Helper/UserHelper.php41
-rw-r--r--app/Import/TaskImport.php14
-rw-r--r--app/Import/UserImport.php6
-rw-r--r--app/Job/BaseJob.php33
-rw-r--r--app/Job/EmailJob.php54
-rw-r--r--app/Job/NotificationJob.php85
-rw-r--r--app/Job/ProjectMetricJob.php40
-rw-r--r--app/Locale/bs_BA/translations.php41
-rw-r--r--app/Locale/cs_CZ/translations.php41
-rw-r--r--app/Locale/da_DK/translations.php41
-rw-r--r--app/Locale/de_DE/translations.php75
-rw-r--r--app/Locale/el_GR/translations.php41
-rw-r--r--app/Locale/es_ES/translations.php41
-rw-r--r--app/Locale/fi_FI/translations.php41
-rw-r--r--app/Locale/fr_FR/translations.php42
-rw-r--r--app/Locale/hu_HU/translations.php1239
-rw-r--r--app/Locale/id_ID/translations.php41
-rw-r--r--app/Locale/it_IT/translations.php41
-rw-r--r--app/Locale/ja_JP/translations.php41
-rw-r--r--app/Locale/ko_KR/translations.php927
-rw-r--r--app/Locale/my_MY/translations.php41
-rw-r--r--app/Locale/nb_NO/translations.php41
-rw-r--r--app/Locale/nl_NL/translations.php41
-rw-r--r--app/Locale/pl_PL/translations.php577
-rw-r--r--app/Locale/pt_BR/translations.php41
-rw-r--r--app/Locale/pt_PT/translations.php41
-rw-r--r--app/Locale/ru_RU/translations.php41
-rw-r--r--app/Locale/sr_Latn_RS/translations.php41
-rw-r--r--app/Locale/sv_SE/translations.php41
-rw-r--r--app/Locale/th_TH/translations.php41
-rw-r--r--app/Locale/tr_TR/translations.php41
-rw-r--r--app/Locale/zh_CN/translations.php41
-rw-r--r--app/Middleware/ApplicationAuthorizationMiddleware.php27
-rw-r--r--app/Middleware/AuthenticationMiddleware.php56
-rw-r--r--app/Middleware/BootstrapMiddleware.php44
-rw-r--r--app/Middleware/PostAuthenticationMiddleware.php36
-rw-r--r--app/Middleware/ProjectAuthorizationMiddleware.php34
-rw-r--r--app/Model/ActionModel.php (renamed from app/Model/Action.php)22
-rw-r--r--app/Model/ActionParameterModel.php (renamed from app/Model/ActionParameter.php)14
-rw-r--r--app/Model/AvatarFileModel.php (renamed from app/Model/AvatarFile.php)53
-rw-r--r--app/Model/Base.php34
-rw-r--r--app/Model/BoardModel.php (renamed from app/Model/Board.php)22
-rw-r--r--app/Model/CategoryModel.php (renamed from app/Model/Category.php)12
-rw-r--r--app/Model/ColorModel.php (renamed from app/Model/Color.php)8
-rw-r--r--app/Model/ColumnModel.php (renamed from app/Model/Column.php)8
-rw-r--r--app/Model/CommentModel.php (renamed from app/Model/Comment.php)31
-rw-r--r--app/Model/Config.php255
-rw-r--r--app/Model/ConfigModel.php89
-rw-r--r--app/Model/CurrencyModel.php (renamed from app/Model/Currency.php)8
-rw-r--r--app/Model/CustomFilterModel.php (renamed from app/Model/CustomFilter.php)14
-rw-r--r--app/Model/FileModel.php (renamed from app/Model/File.php)88
-rw-r--r--app/Model/GroupMemberModel.php (renamed from app/Model/GroupMember.php)16
-rw-r--r--app/Model/GroupModel.php (renamed from app/Model/Group.php)10
-rw-r--r--app/Model/LanguageModel.php179
-rw-r--r--app/Model/LastLoginModel.php (renamed from app/Model/LastLogin.php)6
-rw-r--r--app/Model/LinkModel.php (renamed from app/Model/Link.php)5
-rw-r--r--app/Model/MetadataModel.php (renamed from app/Model/Metadata.php)30
-rw-r--r--app/Model/NotificationModel.php (renamed from app/Model/Notification.php)68
-rw-r--r--app/Model/NotificationTypeModel.php (renamed from app/Model/NotificationType.php)7
-rw-r--r--app/Model/PasswordResetModel.php (renamed from app/Model/PasswordReset.php)8
-rw-r--r--app/Model/ProjectActivityModel.php (renamed from app/Model/ProjectActivity.php)15
-rw-r--r--app/Model/ProjectDailyColumnStatsModel.php (renamed from app/Model/ProjectDailyColumnStats.php)20
-rw-r--r--app/Model/ProjectDailyStatsModel.php (renamed from app/Model/ProjectDailyStats.php)6
-rw-r--r--app/Model/ProjectDuplicationModel.php (renamed from app/Model/ProjectDuplication.php)21
-rw-r--r--app/Model/ProjectFile.php40
-rw-r--r--app/Model/ProjectFileModel.php74
-rw-r--r--app/Model/ProjectGroupRoleModel.php (renamed from app/Model/ProjectGroupRole.php)45
-rw-r--r--app/Model/ProjectMetadata.php30
-rw-r--r--app/Model/ProjectMetadataModel.php54
-rw-r--r--app/Model/ProjectModel.php (renamed from app/Model/Project.php)48
-rw-r--r--app/Model/ProjectNotificationModel.php (renamed from app/Model/ProjectNotification.php)18
-rw-r--r--app/Model/ProjectNotificationTypeModel.php (renamed from app/Model/ProjectNotificationType.php)4
-rw-r--r--app/Model/ProjectPermissionModel.php (renamed from app/Model/ProjectPermission.php)43
-rw-r--r--app/Model/ProjectUserRoleModel.php (renamed from app/Model/ProjectUserRole.php)60
-rw-r--r--app/Model/RememberMeSessionModel.php (renamed from app/Model/RememberMeSession.php)5
-rw-r--r--app/Model/SettingModel.php (renamed from app/Model/Setting.php)6
-rw-r--r--app/Model/SubtaskModel.php (renamed from app/Model/Subtask.php)78
-rw-r--r--app/Model/SubtaskTimeTrackingModel.php (renamed from app/Model/SubtaskTimeTracking.php)69
-rw-r--r--app/Model/SwimlaneModel.php (renamed from app/Model/Swimlane.php)41
-rw-r--r--app/Model/TaskAnalyticModel.php (renamed from app/Model/TaskAnalytic.php)10
-rw-r--r--app/Model/TaskCreationModel.php (renamed from app/Model/TaskCreation.php)27
-rw-r--r--app/Model/TaskDuplicationModel.php (renamed from app/Model/TaskDuplication.php)49
-rw-r--r--app/Model/TaskExternalLinkModel.php (renamed from app/Model/TaskExternalLink.php)12
-rw-r--r--app/Model/TaskFile.php54
-rw-r--r--app/Model/TaskFileModel.php88
-rw-r--r--app/Model/TaskFinderModel.php (renamed from app/Model/TaskFinder.php)211
-rw-r--r--app/Model/TaskLinkModel.php (renamed from app/Model/TaskLink.php)61
-rw-r--r--app/Model/TaskMetadataModel.php (renamed from app/Model/TaskMetadata.php)15
-rw-r--r--app/Model/TaskModel.php (renamed from app/Model/Task.php)34
-rw-r--r--app/Model/TaskModificationModel.php (renamed from app/Model/TaskModification.php)15
-rw-r--r--app/Model/TaskPermission.php34
-rw-r--r--app/Model/TaskPositionModel.php (renamed from app/Model/TaskPosition.php)27
-rw-r--r--app/Model/TaskStatusModel.php (renamed from app/Model/TaskStatus.php)31
-rw-r--r--app/Model/TimezoneModel.php58
-rw-r--r--app/Model/TransitionModel.php (renamed from app/Model/Transition.php)32
-rw-r--r--app/Model/UserLockingModel.php (renamed from app/Model/UserLocking.php)16
-rw-r--r--app/Model/UserMentionModel.php (renamed from app/Model/UserMention.php)11
-rw-r--r--app/Model/UserMetadataModel.php (renamed from app/Model/UserMetadata.php)15
-rw-r--r--app/Model/UserModel.php (renamed from app/Model/User.php)33
-rw-r--r--app/Model/UserNotificationFilterModel.php (renamed from app/Model/UserNotificationFilter.php)10
-rw-r--r--app/Model/UserNotificationModel.php (renamed from app/Model/UserNotification.php)70
-rw-r--r--app/Model/UserNotificationTypeModel.php (renamed from app/Model/UserNotificationType.php)4
-rw-r--r--app/Model/UserUnreadNotificationModel.php (renamed from app/Model/UserUnreadNotification.php)32
-rw-r--r--app/Notification/ActivityStreamNotification.php (renamed from app/Notification/ActivityStream.php)7
-rw-r--r--app/Notification/MailNotification.php (renamed from app/Notification/Mail.php)47
-rw-r--r--app/Notification/WebNotification.php (renamed from app/Notification/Web.php)7
-rw-r--r--app/Notification/WebhookNotification.php (renamed from app/Notification/Webhook.php)9
-rw-r--r--app/Schema/Sql/mysql.sql4
-rw-r--r--app/Schema/Sql/postgres.sql1365
-rw-r--r--app/ServiceProvider/ActionProvider.php4
-rw-r--r--app/ServiceProvider/ApiProvider.php74
-rw-r--r--app/ServiceProvider/AuthenticationProvider.php116
-rw-r--r--app/ServiceProvider/AvatarProvider.php2
-rw-r--r--app/ServiceProvider/ClassProvider.php122
-rw-r--r--app/ServiceProvider/CommandProvider.php62
-rw-r--r--app/ServiceProvider/DatabaseProvider.php25
-rw-r--r--app/ServiceProvider/EventDispatcherProvider.php11
-rw-r--r--app/ServiceProvider/ExternalLinkProvider.php2
-rw-r--r--app/ServiceProvider/FilterProvider.php28
-rw-r--r--app/ServiceProvider/GroupProvider.php2
-rw-r--r--app/ServiceProvider/HelperProvider.php7
-rw-r--r--app/ServiceProvider/LoggingProvider.php35
-rw-r--r--app/ServiceProvider/MailProvider.php34
-rw-r--r--app/ServiceProvider/NotificationProvider.php26
-rw-r--r--app/ServiceProvider/PluginProvider.php2
-rw-r--r--app/ServiceProvider/QueueProvider.php27
-rw-r--r--app/ServiceProvider/RouteProvider.php221
-rw-r--r--app/ServiceProvider/SessionProvider.php2
-rw-r--r--app/Subscriber/AuthSubscriber.php16
-rw-r--r--app/Subscriber/BaseSubscriber.php1
-rw-r--r--app/Subscriber/BootstrapSubscriber.php16
-rw-r--r--app/Subscriber/LdapUserPhotoSubscriber.php49
-rw-r--r--app/Subscriber/NotificationSubscriber.php86
-rw-r--r--app/Subscriber/ProjectDailySummarySubscriber.php16
-rw-r--r--app/Subscriber/ProjectModificationDateSubscriber.php20
-rw-r--r--app/Subscriber/RecurringTaskSubscriber.php20
-rw-r--r--app/Subscriber/SubtaskTimeTrackingSubscriber.php20
-rw-r--r--app/Subscriber/TransitionSubscriber.php6
-rw-r--r--app/Template/action/index.php8
-rw-r--r--app/Template/action/remove.php6
-rw-r--r--app/Template/action_creation/create.php6
-rw-r--r--app/Template/action_creation/event.php6
-rw-r--r--app/Template/action_creation/params.php9
-rw-r--r--app/Template/activity/project.php8
-rw-r--r--app/Template/analytic/burndown.php2
-rw-r--r--app/Template/analytic/cfd.php2
-rw-r--r--app/Template/analytic/compare_hours.php6
-rw-r--r--app/Template/analytic/layout.php5
-rw-r--r--app/Template/analytic/lead_cycle_time.php2
-rw-r--r--app/Template/analytic/sidebar.php32
-rw-r--r--app/Template/app/calendar.php5
-rw-r--r--app/Template/app/overview.php12
-rw-r--r--app/Template/app/sidebar.php27
-rw-r--r--app/Template/auth/index.php8
-rw-r--r--app/Template/avatar_file/show.php19
-rw-r--r--app/Template/board/table_column.php18
-rw-r--r--app/Template/board/table_container.php10
-rw-r--r--app/Template/board/table_swimlane.php2
-rw-r--r--app/Template/board/task_avatar.php4
-rw-r--r--app/Template/board/task_footer.php26
-rw-r--r--app/Template/board/task_menu.php18
-rw-r--r--app/Template/board/task_private.php16
-rw-r--r--app/Template/board/task_public.php6
-rw-r--r--app/Template/board/tooltip_files.php4
-rw-r--r--app/Template/board/tooltip_tasklinks.php4
-rw-r--r--app/Template/board/view_private.php2
-rw-r--r--app/Template/board_popover/close_all_tasks_column.php (renamed from app/Template/board/popover_close_all_tasks_column.php)6
-rw-r--r--app/Template/calendar/show.php8
-rw-r--r--app/Template/category/edit.php6
-rw-r--r--app/Template/category/index.php8
-rw-r--r--app/Template/category/remove.php6
-rw-r--r--app/Template/column/create.php4
-rw-r--r--app/Template/column/edit.php6
-rw-r--r--app/Template/column/index.php10
-rw-r--r--app/Template/column/remove.php6
-rw-r--r--app/Template/comment/create.php6
-rw-r--r--app/Template/comment/edit.php4
-rw-r--r--app/Template/comment/remove.php6
-rw-r--r--app/Template/comment/show.php28
-rw-r--r--app/Template/comments/create.php4
-rw-r--r--app/Template/comments/show.php4
-rw-r--r--app/Template/config/about.php10
-rw-r--r--app/Template/config/api.php4
-rw-r--r--app/Template/config/application.php5
-rw-r--r--app/Template/config/board.php2
-rw-r--r--app/Template/config/calendar.php4
-rw-r--r--app/Template/config/integrations.php4
-rw-r--r--app/Template/config/layout.php3
-rw-r--r--app/Template/config/plugins.php30
-rw-r--r--app/Template/config/project.php2
-rw-r--r--app/Template/config/sidebar.php45
-rw-r--r--app/Template/config/webhook.php12
-rw-r--r--app/Template/currency/index.php4
-rw-r--r--app/Template/custom_filter/add.php6
-rw-r--r--app/Template/custom_filter/edit.php8
-rw-r--r--app/Template/custom_filter/index.php6
-rw-r--r--app/Template/custom_filter/remove.php4
-rw-r--r--app/Template/dashboard/activity.php (renamed from app/Template/app/activity.php)0
-rw-r--r--app/Template/dashboard/calendar.php5
-rw-r--r--app/Template/dashboard/layout.php (renamed from app/Template/app/layout.php)12
-rw-r--r--app/Template/dashboard/notifications.php (renamed from app/Template/app/notifications.php)14
-rw-r--r--app/Template/dashboard/projects.php (renamed from app/Template/app/projects.php)18
-rw-r--r--app/Template/dashboard/show.php12
-rw-r--r--app/Template/dashboard/sidebar.php27
-rw-r--r--app/Template/dashboard/subtasks.php (renamed from app/Template/app/subtasks.php)8
-rw-r--r--app/Template/dashboard/tasks.php (renamed from app/Template/app/tasks.php)12
-rw-r--r--app/Template/doc/show.php4
-rw-r--r--app/Template/event/comment_create.php2
-rw-r--r--app/Template/event/comment_update.php2
-rw-r--r--app/Template/event/subtask_create.php4
-rw-r--r--app/Template/event/subtask_update.php2
-rw-r--r--app/Template/event/task_assignee_change.php6
-rw-r--r--app/Template/event/task_close.php2
-rw-r--r--app/Template/event/task_create.php2
-rw-r--r--app/Template/event/task_file_create.php2
-rw-r--r--app/Template/event/task_move_column.php2
-rw-r--r--app/Template/event/task_move_position.php2
-rw-r--r--app/Template/event/task_move_swimlane.php4
-rw-r--r--app/Template/event/task_open.php2
-rw-r--r--app/Template/event/task_update.php2
-rw-r--r--app/Template/export/sidebar.php18
-rw-r--r--app/Template/feed/project.php8
-rw-r--r--app/Template/feed/user.php8
-rw-r--r--app/Template/file_viewer/show.php4
-rw-r--r--app/Template/group/associate.php41
-rw-r--r--app/Template/group/create.php19
-rw-r--r--app/Template/group/dissociate.php25
-rw-r--r--app/Template/group/edit.php22
-rw-r--r--app/Template/group/index.php14
-rw-r--r--app/Template/group/remove.php25
-rw-r--r--app/Template/group/users.php11
-rw-r--r--app/Template/group_creation/show.php15
-rw-r--r--app/Template/group_modification/show.php18
-rw-r--r--app/Template/header.php44
-rw-r--r--app/Template/layout.php33
-rw-r--r--app/Template/link/create.php4
-rw-r--r--app/Template/link/edit.php4
-rw-r--r--app/Template/link/index.php6
-rw-r--r--app/Template/link/remove.php6
-rw-r--r--app/Template/notification/footer.php4
-rw-r--r--app/Template/notification/task_overdue.php6
-rw-r--r--app/Template/password_reset/change.php4
-rw-r--r--app/Template/password_reset/create.php6
-rw-r--r--app/Template/password_reset/email.php4
-rw-r--r--app/Template/plugin/directory.php55
-rw-r--r--app/Template/plugin/layout.php9
-rw-r--r--app/Template/plugin/remove.php13
-rw-r--r--app/Template/plugin/show.php41
-rw-r--r--app/Template/plugin/sidebar.php11
-rw-r--r--app/Template/project/disable.php14
-rw-r--r--app/Template/project/dropdown.php76
-rw-r--r--app/Template/project/duplicate.php27
-rw-r--r--app/Template/project/enable.php14
-rw-r--r--app/Template/project/layout.php4
-rw-r--r--app/Template/project/remove.php14
-rw-r--r--app/Template/project/share.php19
-rw-r--r--app/Template/project/sidebar.php69
-rw-r--r--app/Template/project_action_duplication/show.php (renamed from app/Template/action_project/project.php)5
-rw-r--r--app/Template/project_creation/create.php14
-rw-r--r--app/Template/project_edit/dates.php10
-rw-r--r--app/Template/project_edit/description.php10
-rw-r--r--app/Template/project_edit/general.php12
-rw-r--r--app/Template/project_edit/task_priority.php10
-rw-r--r--app/Template/project_file/create.php8
-rw-r--r--app/Template/project_file/remove.php6
-rw-r--r--app/Template/project_gantt/show.php (renamed from app/Template/gantt/projects.php)12
-rw-r--r--app/Template/project_header/dropdown.php68
-rw-r--r--app/Template/project_header/views.php24
-rw-r--r--app/Template/project_list/show.php (renamed from app/Template/project/index.php)23
-rw-r--r--app/Template/project_overview/attachments.php4
-rw-r--r--app/Template/project_overview/description.php4
-rw-r--r--app/Template/project_overview/files.php8
-rw-r--r--app/Template/project_overview/images.php8
-rw-r--r--app/Template/project_overview/information.php6
-rw-r--r--app/Template/project_overview/show.php2
-rw-r--r--app/Template/project_permission/index.php18
-rw-r--r--app/Template/project_status/disable.php14
-rw-r--r--app/Template/project_status/enable.php14
-rw-r--r--app/Template/project_status/remove.php14
-rw-r--r--app/Template/project_user/sidebar.php30
-rw-r--r--app/Template/project_user_overview/layout.php (renamed from app/Template/project_user/layout.php)8
-rw-r--r--app/Template/project_user_overview/roles.php (renamed from app/Template/project_user/roles.php)8
-rw-r--r--app/Template/project_user_overview/sidebar.php30
-rw-r--r--app/Template/project_user_overview/tasks.php (renamed from app/Template/project_user/tasks.php)6
-rw-r--r--app/Template/project_user_overview/tooltip_users.php (renamed from app/Template/project_user/tooltip_users.php)12
-rw-r--r--app/Template/project_view/duplicate.php28
-rw-r--r--app/Template/project_view/integrations.php (renamed from app/Template/project/integrations.php)4
-rw-r--r--app/Template/project_view/notifications.php (renamed from app/Template/project/notifications.php)6
-rw-r--r--app/Template/project_view/share.php18
-rw-r--r--app/Template/project_view/show.php (renamed from app/Template/project/show.php)12
-rw-r--r--app/Template/search/activity.php4
-rw-r--r--app/Template/search/index.php4
-rw-r--r--app/Template/search/results.php8
-rw-r--r--app/Template/subtask/create.php4
-rw-r--r--app/Template/subtask/edit.php4
-rw-r--r--app/Template/subtask/menu.php10
-rw-r--r--app/Template/subtask/remove.php17
-rw-r--r--app/Template/subtask/table.php6
-rw-r--r--app/Template/subtask_converter/show.php20
-rw-r--r--app/Template/subtask_restriction/show.php (renamed from app/Template/subtask_restriction/popover.php)6
-rw-r--r--app/Template/swimlane/create.php4
-rw-r--r--app/Template/swimlane/edit.php6
-rw-r--r--app/Template/swimlane/edit_default.php4
-rw-r--r--app/Template/swimlane/index.php2
-rw-r--r--app/Template/swimlane/remove.php6
-rw-r--r--app/Template/swimlane/table.php18
-rw-r--r--app/Template/task/analytics.php3
-rw-r--r--app/Template/task/description.php26
-rw-r--r--app/Template/task/details.php6
-rw-r--r--app/Template/task/dropdown.php44
-rw-r--r--app/Template/task/layout.php12
-rw-r--r--app/Template/task/remove.php15
-rw-r--r--app/Template/task/show.php4
-rw-r--r--app/Template/task/sidebar.php54
-rw-r--r--app/Template/task/time_tracking_details.php6
-rw-r--r--app/Template/task/transitions.php4
-rw-r--r--app/Template/task_bulk/show.php25
-rw-r--r--app/Template/task_creation/show.php (renamed from app/Template/task_creation/form.php)6
-rw-r--r--app/Template/task_duplication/copy.php8
-rw-r--r--app/Template/task_duplication/duplicate.php6
-rw-r--r--app/Template/task_duplication/move.php8
-rw-r--r--app/Template/task_external_link/create.php6
-rw-r--r--app/Template/task_external_link/edit.php6
-rw-r--r--app/Template/task_external_link/find.php6
-rw-r--r--app/Template/task_external_link/remove.php6
-rw-r--r--app/Template/task_external_link/table.php8
-rw-r--r--app/Template/task_file/create.php8
-rw-r--r--app/Template/task_file/files.php10
-rw-r--r--app/Template/task_file/images.php10
-rw-r--r--app/Template/task_file/remove.php6
-rw-r--r--app/Template/task_file/screenshot.php6
-rw-r--r--app/Template/task_gantt/show.php (renamed from app/Template/gantt/project.php)12
-rw-r--r--app/Template/task_gantt_creation/show.php (renamed from app/Template/gantt/task_creation.php)4
-rw-r--r--app/Template/task_import/show.php (renamed from app/Template/task_import/step1.php)4
-rw-r--r--app/Template/task_import/sidebar.php9
-rw-r--r--app/Template/task_internal_link/create.php8
-rw-r--r--app/Template/task_internal_link/edit.php8
-rw-r--r--app/Template/task_internal_link/remove.php6
-rw-r--r--app/Template/task_internal_link/table.php12
-rw-r--r--app/Template/task_list/show.php (renamed from app/Template/listing/show.php)10
-rw-r--r--app/Template/task_modification/edit_description.php6
-rw-r--r--app/Template/task_modification/edit_task.php5
-rw-r--r--app/Template/task_popover/change_assignee.php (renamed from app/Template/board/popover_assignee.php)6
-rw-r--r--app/Template/task_popover/change_category.php (renamed from app/Template/board/popover_category.php)6
-rw-r--r--app/Template/task_recurrence/edit.php10
-rw-r--r--app/Template/task_recurrence/info.php10
-rw-r--r--app/Template/task_status/close.php6
-rw-r--r--app/Template/task_status/open.php6
-rw-r--r--app/Template/task_suppression/remove.php15
-rw-r--r--app/Template/twofactor/check.php4
-rw-r--r--app/Template/twofactor/disable.php6
-rw-r--r--app/Template/twofactor/index.php2
-rw-r--r--app/Template/twofactor/show.php4
-rw-r--r--app/Template/user/create_local.php53
-rw-r--r--app/Template/user/create_remote.php55
-rw-r--r--app/Template/user/dropdown.php27
-rw-r--r--app/Template/user/layout.php19
-rw-r--r--app/Template/user/share.php18
-rw-r--r--app/Template/user/sidebar.php83
-rw-r--r--app/Template/user_creation/local.php45
-rw-r--r--app/Template/user_creation/remote.php50
-rw-r--r--app/Template/user_credential/authentication.php (renamed from app/Template/user/authentication.php)7
-rw-r--r--app/Template/user_credential/password.php (renamed from app/Template/user/password.php)11
-rw-r--r--app/Template/user_import/show.php41
-rw-r--r--app/Template/user_import/step1.php46
-rw-r--r--app/Template/user_list/dropdown.php27
-rw-r--r--app/Template/user_list/show.php (renamed from app/Template/user/index.php)14
-rw-r--r--app/Template/user_modification/show.php (renamed from app/Template/user/edit.php)6
-rw-r--r--app/Template/user_status/disable.php4
-rw-r--r--app/Template/user_status/enable.php4
-rw-r--r--app/Template/user_status/remove.php4
-rw-r--r--app/Template/user_view/external.php (renamed from app/Template/user/external.php)0
-rw-r--r--app/Template/user_view/integrations.php (renamed from app/Template/user/integrations.php)2
-rw-r--r--app/Template/user_view/last.php (renamed from app/Template/user/last.php)0
-rw-r--r--app/Template/user_view/layout.php19
-rw-r--r--app/Template/user_view/notifications.php (renamed from app/Template/user/notifications.php)6
-rw-r--r--app/Template/user_view/password_reset.php (renamed from app/Template/user/password_reset.php)0
-rw-r--r--app/Template/user_view/profile.php (renamed from app/Template/user/profile.php)0
-rw-r--r--app/Template/user_view/sessions.php (renamed from app/Template/user/sessions.php)2
-rw-r--r--app/Template/user_view/share.php15
-rw-r--r--app/Template/user_view/show.php (renamed from app/Template/user/show.php)8
-rw-r--r--app/Template/user_view/sidebar.php83
-rw-r--r--app/Template/user_view/timesheet.php (renamed from app/Template/user/timesheet.php)6
-rw-r--r--app/User/Avatar/AvatarFileProvider.php2
-rw-r--r--app/User/Avatar/GravatarProvider.php2
-rw-r--r--app/User/Avatar/LetterAvatarProvider.php4
-rw-r--r--app/User/LdapUserProvider.php48
-rw-r--r--app/Validator/ActionValidator.php4
-rw-r--r--app/Validator/AuthValidator.php8
-rw-r--r--app/Validator/BaseValidator.php (renamed from app/Validator/Base.php)5
-rw-r--r--app/Validator/CategoryValidator.php4
-rw-r--r--app/Validator/ColumnValidator.php4
-rw-r--r--app/Validator/CommentValidator.php4
-rw-r--r--app/Validator/CurrencyValidator.php4
-rw-r--r--app/Validator/CustomFilterValidator.php4
-rw-r--r--app/Validator/ExternalLinkValidator.php4
-rw-r--r--app/Validator/GroupValidator.php8
-rw-r--r--app/Validator/LinkValidator.php10
-rw-r--r--app/Validator/PasswordResetValidator.php6
-rw-r--r--app/Validator/ProjectValidator.php8
-rw-r--r--app/Validator/SubtaskValidator.php4
-rw-r--r--app/Validator/SwimlaneValidator.php4
-rw-r--r--app/Validator/TaskLinkValidator.php8
-rw-r--r--app/Validator/TaskValidator.php30
-rw-r--r--app/Validator/UserValidator.php8
-rw-r--r--app/common.php55
-rw-r--r--app/constants.php32
663 files changed, 13271 insertions, 9236 deletions
diff --git a/app/Action/CommentCreation.php b/app/Action/CommentCreation.php
index b91e39e2..60ca24f7 100644
--- a/app/Action/CommentCreation.php
+++ b/app/Action/CommentCreation.php
@@ -65,11 +65,11 @@ class CommentCreation extends Base
*/
public function doAction(array $data)
{
- return (bool) $this->comment->create(array(
+ return (bool) $this->commentModel->create(array(
'reference' => isset($data['reference']) ? $data['reference'] : '',
'comment' => $data['comment'],
'task_id' => $data['task_id'],
- 'user_id' => isset($data['user_id']) && $this->projectPermission->isAssignable($this->getProjectId(), $data['user_id']) ? $data['user_id'] : 0,
+ 'user_id' => isset($data['user_id']) && $this->projectPermissionModel->isAssignable($this->getProjectId(), $data['user_id']) ? $data['user_id'] : 0,
));
}
diff --git a/app/Action/CommentCreationMoveTaskColumn.php b/app/Action/CommentCreationMoveTaskColumn.php
index 11224d67..1b16f481 100644
--- a/app/Action/CommentCreationMoveTaskColumn.php
+++ b/app/Action/CommentCreationMoveTaskColumn.php
@@ -2,7 +2,7 @@
namespace Kanboard\Action;
-use Kanboard\Model\Task;
+use Kanboard\Model\TaskModel;
/**
* Add a comment of the triggering event to the task description.
@@ -32,7 +32,7 @@ class CommentCreationMoveTaskColumn extends Base
public function getCompatibleEvents()
{
return array(
- Task::EVENT_MOVE_COLUMN,
+ TaskModel::EVENT_MOVE_COLUMN,
);
}
@@ -71,9 +71,9 @@ class CommentCreationMoveTaskColumn extends Base
return false;
}
- $column = $this->column->getById($data['column_id']);
+ $column = $this->columnModel->getById($data['column_id']);
- return (bool) $this->comment->create(array(
+ return (bool) $this->commentModel->create(array(
'comment' => t('Moved to column %s', $column['title']),
'task_id' => $data['task_id'],
'user_id' => $this->userSession->getId(),
diff --git a/app/Action/TaskAssignCategoryColor.php b/app/Action/TaskAssignCategoryColor.php
index f5085cb0..fc486870 100644
--- a/app/Action/TaskAssignCategoryColor.php
+++ b/app/Action/TaskAssignCategoryColor.php
@@ -2,7 +2,7 @@
namespace Kanboard\Action;
-use Kanboard\Model\Task;
+use Kanboard\Model\TaskModel;
/**
* Set a category automatically according to the color
@@ -32,7 +32,7 @@ class TaskAssignCategoryColor extends Base
public function getCompatibleEvents()
{
return array(
- Task::EVENT_CREATE_UPDATE,
+ TaskModel::EVENT_CREATE_UPDATE,
);
}
@@ -78,7 +78,7 @@ class TaskAssignCategoryColor extends Base
'category_id' => $this->getParam('category_id'),
);
- return $this->taskModification->update($values);
+ return $this->taskModificationModel->update($values);
}
/**
diff --git a/app/Action/TaskAssignCategoryLabel.php b/app/Action/TaskAssignCategoryLabel.php
index 95fa116e..48299010 100644
--- a/app/Action/TaskAssignCategoryLabel.php
+++ b/app/Action/TaskAssignCategoryLabel.php
@@ -74,7 +74,7 @@ class TaskAssignCategoryLabel extends Base
'category_id' => $this->getParam('category_id'),
);
- return $this->taskModification->update($values);
+ return $this->taskModificationModel->update($values);
}
/**
diff --git a/app/Action/TaskAssignCategoryLink.php b/app/Action/TaskAssignCategoryLink.php
index b39e41b4..6937edd1 100644
--- a/app/Action/TaskAssignCategoryLink.php
+++ b/app/Action/TaskAssignCategoryLink.php
@@ -2,7 +2,7 @@
namespace Kanboard\Action;
-use Kanboard\Model\TaskLink;
+use Kanboard\Model\TaskLinkModel;
/**
* Set a category automatically according to a task link
@@ -33,7 +33,7 @@ class TaskAssignCategoryLink extends Base
public function getCompatibleEvents()
{
return array(
- TaskLink::EVENT_CREATE_UPDATE,
+ TaskLinkModel::EVENT_CREATE_UPDATE,
);
}
@@ -79,7 +79,7 @@ class TaskAssignCategoryLink extends Base
'category_id' => $this->getParam('category_id'),
);
- return $this->taskModification->update($values);
+ return $this->taskModificationModel->update($values);
}
/**
@@ -92,7 +92,7 @@ class TaskAssignCategoryLink extends Base
public function hasRequiredCondition(array $data)
{
if ($data['link_id'] == $this->getParam('link_id')) {
- $task = $this->taskFinder->getById($data['task_id']);
+ $task = $this->taskFinderModel->getById($data['task_id']);
return empty($task['category_id']);
}
diff --git a/app/Action/TaskAssignColorCategory.php b/app/Action/TaskAssignColorCategory.php
index 139c24cb..284b8f40 100644
--- a/app/Action/TaskAssignColorCategory.php
+++ b/app/Action/TaskAssignColorCategory.php
@@ -2,7 +2,7 @@
namespace Kanboard\Action;
-use Kanboard\Model\Task;
+use Kanboard\Model\TaskModel;
/**
* Assign a color to a specific category
@@ -32,7 +32,7 @@ class TaskAssignColorCategory extends Base
public function getCompatibleEvents()
{
return array(
- Task::EVENT_CREATE_UPDATE,
+ TaskModel::EVENT_CREATE_UPDATE,
);
}
@@ -78,7 +78,7 @@ class TaskAssignColorCategory extends Base
'color_id' => $this->getParam('color_id'),
);
- return $this->taskModification->update($values, false);
+ return $this->taskModificationModel->update($values, false);
}
/**
diff --git a/app/Action/TaskAssignColorColumn.php b/app/Action/TaskAssignColorColumn.php
index 92412739..57fd6f44 100644
--- a/app/Action/TaskAssignColorColumn.php
+++ b/app/Action/TaskAssignColorColumn.php
@@ -2,7 +2,7 @@
namespace Kanboard\Action;
-use Kanboard\Model\Task;
+use Kanboard\Model\TaskModel;
/**
* Assign a color to a task
@@ -32,8 +32,8 @@ class TaskAssignColorColumn extends Base
public function getCompatibleEvents()
{
return array(
- Task::EVENT_CREATE,
- Task::EVENT_MOVE_COLUMN,
+ TaskModel::EVENT_CREATE,
+ TaskModel::EVENT_MOVE_COLUMN,
);
}
@@ -79,7 +79,7 @@ class TaskAssignColorColumn extends Base
'color_id' => $this->getParam('color_id'),
);
- return $this->taskModification->update($values, false);
+ return $this->taskModificationModel->update($values, false);
}
/**
diff --git a/app/Action/TaskAssignColorLink.php b/app/Action/TaskAssignColorLink.php
index 12ceabb3..9ab5458b 100644
--- a/app/Action/TaskAssignColorLink.php
+++ b/app/Action/TaskAssignColorLink.php
@@ -2,7 +2,7 @@
namespace Kanboard\Action;
-use Kanboard\Model\TaskLink;
+use Kanboard\Model\TaskLinkModel;
/**
* Assign a color to a specific task link
@@ -32,7 +32,7 @@ class TaskAssignColorLink extends Base
public function getCompatibleEvents()
{
return array(
- TaskLink::EVENT_CREATE_UPDATE,
+ TaskLinkModel::EVENT_CREATE_UPDATE,
);
}
@@ -78,7 +78,7 @@ class TaskAssignColorLink extends Base
'color_id' => $this->getParam('color_id'),
);
- return $this->taskModification->update($values, false);
+ return $this->taskModificationModel->update($values, false);
}
/**
diff --git a/app/Action/TaskAssignColorPriority.php b/app/Action/TaskAssignColorPriority.php
new file mode 100644
index 00000000..eae1b771
--- /dev/null
+++ b/app/Action/TaskAssignColorPriority.php
@@ -0,0 +1,95 @@
+<?php
+
+namespace Kanboard\Action;
+
+use Kanboard\Model\TaskModel;
+
+/**
+ * Assign a color to a priority
+ *
+ * @package action
+ * @author Frederic Guillot
+ */
+class TaskAssignColorPriority extends Base
+{
+ /**
+ * Get automatic action description
+ *
+ * @access public
+ * @return string
+ */
+ public function getDescription()
+ {
+ return t('Assign automatically a color based on a priority');
+ }
+
+ /**
+ * Get the list of compatible events
+ *
+ * @access public
+ * @return array
+ */
+ public function getCompatibleEvents()
+ {
+ return array(
+ TaskModel::EVENT_CREATE_UPDATE,
+ );
+ }
+
+ /**
+ * Get the required parameter for the action (defined by the user)
+ *
+ * @access public
+ * @return array
+ */
+ public function getActionRequiredParameters()
+ {
+ return array(
+ 'color_id' => t('Color'),
+ 'priority' => t('Priority'),
+ );
+ }
+
+ /**
+ * Get the required parameter for the event
+ *
+ * @access public
+ * @return string[]
+ */
+ public function getEventRequiredParameters()
+ {
+ return array(
+ 'task_id',
+ 'priority',
+ );
+ }
+
+ /**
+ * Execute the action (change the task color)
+ *
+ * @access public
+ * @param array $data Event data dictionary
+ * @return bool True if the action was executed or false when not executed
+ */
+ public function doAction(array $data)
+ {
+ $values = array(
+ 'id' => $data['task_id'],
+ 'color_id' => $this->getParam('color_id'),
+ );
+
+ return $this->taskModificationModel->update($values, false);
+ }
+
+ /**
+ * Check if the event data meet the action condition
+ *
+ * @access public
+ * @param array $data Event data dictionary
+ * @return bool
+ */
+ public function hasRequiredCondition(array $data)
+ {
+ return $data['priority'] == $this->getParam('priority');
+ }
+}
diff --git a/app/Action/TaskAssignColorUser.php b/app/Action/TaskAssignColorUser.php
index 6ec8ce95..4bcf7a5c 100644
--- a/app/Action/TaskAssignColorUser.php
+++ b/app/Action/TaskAssignColorUser.php
@@ -2,7 +2,7 @@
namespace Kanboard\Action;
-use Kanboard\Model\Task;
+use Kanboard\Model\TaskModel;
/**
* Assign a color to a specific user
@@ -32,8 +32,8 @@ class TaskAssignColorUser extends Base
public function getCompatibleEvents()
{
return array(
- Task::EVENT_CREATE,
- Task::EVENT_ASSIGNEE_CHANGE,
+ TaskModel::EVENT_CREATE,
+ TaskModel::EVENT_ASSIGNEE_CHANGE,
);
}
@@ -79,7 +79,7 @@ class TaskAssignColorUser extends Base
'color_id' => $this->getParam('color_id'),
);
- return $this->taskModification->update($values, false);
+ return $this->taskModificationModel->update($values, false);
}
/**
diff --git a/app/Action/TaskAssignCurrentUser.php b/app/Action/TaskAssignCurrentUser.php
index 192a120c..997aa98f 100644
--- a/app/Action/TaskAssignCurrentUser.php
+++ b/app/Action/TaskAssignCurrentUser.php
@@ -2,7 +2,7 @@
namespace Kanboard\Action;
-use Kanboard\Model\Task;
+use Kanboard\Model\TaskModel;
/**
* Assign a task to the logged user
@@ -32,7 +32,7 @@ class TaskAssignCurrentUser extends Base
public function getCompatibleEvents()
{
return array(
- Task::EVENT_CREATE,
+ TaskModel::EVENT_CREATE,
);
}
@@ -78,7 +78,7 @@ class TaskAssignCurrentUser extends Base
'owner_id' => $this->userSession->getId(),
);
- return $this->taskModification->update($values);
+ return $this->taskModificationModel->update($values);
}
/**
diff --git a/app/Action/TaskAssignCurrentUserColumn.php b/app/Action/TaskAssignCurrentUserColumn.php
index 05d08dd3..bc28a90b 100644
--- a/app/Action/TaskAssignCurrentUserColumn.php
+++ b/app/Action/TaskAssignCurrentUserColumn.php
@@ -2,7 +2,7 @@
namespace Kanboard\Action;
-use Kanboard\Model\Task;
+use Kanboard\Model\TaskModel;
/**
* Assign a task to the logged user on column change
@@ -32,7 +32,7 @@ class TaskAssignCurrentUserColumn extends Base
public function getCompatibleEvents()
{
return array(
- Task::EVENT_MOVE_COLUMN,
+ TaskModel::EVENT_MOVE_COLUMN,
);
}
@@ -81,7 +81,7 @@ class TaskAssignCurrentUserColumn extends Base
'owner_id' => $this->userSession->getId(),
);
- return $this->taskModification->update($values);
+ return $this->taskModificationModel->update($values);
}
/**
diff --git a/app/Action/TaskAssignSpecificUser.php b/app/Action/TaskAssignSpecificUser.php
index 2dc3e966..50a2b2ae 100644
--- a/app/Action/TaskAssignSpecificUser.php
+++ b/app/Action/TaskAssignSpecificUser.php
@@ -2,7 +2,7 @@
namespace Kanboard\Action;
-use Kanboard\Model\Task;
+use Kanboard\Model\TaskModel;
/**
* Assign a task to a specific user
@@ -32,8 +32,8 @@ class TaskAssignSpecificUser extends Base
public function getCompatibleEvents()
{
return array(
- Task::EVENT_CREATE_UPDATE,
- Task::EVENT_MOVE_COLUMN,
+ TaskModel::EVENT_CREATE_UPDATE,
+ TaskModel::EVENT_MOVE_COLUMN,
);
}
@@ -79,7 +79,7 @@ class TaskAssignSpecificUser extends Base
'owner_id' => $this->getParam('user_id'),
);
- return $this->taskModification->update($values);
+ return $this->taskModificationModel->update($values);
}
/**
diff --git a/app/Action/TaskAssignUser.php b/app/Action/TaskAssignUser.php
index da54d186..9ea22986 100644
--- a/app/Action/TaskAssignUser.php
+++ b/app/Action/TaskAssignUser.php
@@ -71,7 +71,7 @@ class TaskAssignUser extends Base
'owner_id' => $data['owner_id'],
);
- return $this->taskModification->update($values);
+ return $this->taskModificationModel->update($values);
}
/**
@@ -83,6 +83,6 @@ class TaskAssignUser extends Base
*/
public function hasRequiredCondition(array $data)
{
- return $this->projectPermission->isAssignable($this->getProjectId(), $data['owner_id']);
+ return $this->projectPermissionModel->isAssignable($this->getProjectId(), $data['owner_id']);
}
}
diff --git a/app/Action/TaskClose.php b/app/Action/TaskClose.php
index cf91e83e..91e8cf43 100644
--- a/app/Action/TaskClose.php
+++ b/app/Action/TaskClose.php
@@ -63,7 +63,7 @@ class TaskClose extends Base
*/
public function doAction(array $data)
{
- return $this->taskStatus->close($data['task_id']);
+ return $this->taskStatusModel->close($data['task_id']);
}
/**
diff --git a/app/Action/TaskCloseColumn.php b/app/Action/TaskCloseColumn.php
index 09af3b96..1edce8fa 100644
--- a/app/Action/TaskCloseColumn.php
+++ b/app/Action/TaskCloseColumn.php
@@ -2,7 +2,7 @@
namespace Kanboard\Action;
-use Kanboard\Model\Task;
+use Kanboard\Model\TaskModel;
/**
* Close automatically a task in a specific column
@@ -32,7 +32,7 @@ class TaskCloseColumn extends Base
public function getCompatibleEvents()
{
return array(
- Task::EVENT_MOVE_COLUMN,
+ TaskModel::EVENT_MOVE_COLUMN,
);
}
@@ -67,7 +67,7 @@ class TaskCloseColumn extends Base
*/
public function doAction(array $data)
{
- return $this->taskStatus->close($data['task_id']);
+ return $this->taskStatusModel->close($data['task_id']);
}
/**
diff --git a/app/Action/TaskCloseNoActivity.php b/app/Action/TaskCloseNoActivity.php
index 59f7f56a..5a10510f 100644
--- a/app/Action/TaskCloseNoActivity.php
+++ b/app/Action/TaskCloseNoActivity.php
@@ -2,7 +2,7 @@
namespace Kanboard\Action;
-use Kanboard\Model\Task;
+use Kanboard\Model\TaskModel;
/**
* Close automatically a task after when inactive
@@ -31,7 +31,7 @@ class TaskCloseNoActivity extends Base
*/
public function getCompatibleEvents()
{
- return array(Task::EVENT_DAILY_CRONJOB);
+ return array(TaskModel::EVENT_DAILY_CRONJOB);
}
/**
@@ -74,7 +74,7 @@ class TaskCloseNoActivity extends Base
$duration = time() - $task['date_modification'];
if ($duration > $max) {
- $results[] = $this->taskStatus->close($task['id']);
+ $results[] = $this->taskStatusModel->close($task['id']);
}
}
diff --git a/app/Action/TaskCreation.php b/app/Action/TaskCreation.php
index 290c31e1..e9e5c5f3 100644
--- a/app/Action/TaskCreation.php
+++ b/app/Action/TaskCreation.php
@@ -66,7 +66,7 @@ class TaskCreation extends Base
*/
public function doAction(array $data)
{
- return (bool) $this->taskCreation->create(array(
+ return (bool) $this->taskCreationModel->create(array(
'project_id' => $data['project_id'],
'title' => $data['title'],
'reference' => $data['reference'],
diff --git a/app/Action/TaskDuplicateAnotherProject.php b/app/Action/TaskDuplicateAnotherProject.php
index 5f05136e..93fae5cc 100644
--- a/app/Action/TaskDuplicateAnotherProject.php
+++ b/app/Action/TaskDuplicateAnotherProject.php
@@ -2,7 +2,7 @@
namespace Kanboard\Action;
-use Kanboard\Model\Task;
+use Kanboard\Model\TaskModel;
/**
* Duplicate a task to another project
@@ -32,8 +32,8 @@ class TaskDuplicateAnotherProject extends Base
public function getCompatibleEvents()
{
return array(
- Task::EVENT_MOVE_COLUMN,
- Task::EVENT_CLOSE,
+ TaskModel::EVENT_MOVE_COLUMN,
+ TaskModel::EVENT_CLOSE,
);
}
@@ -74,8 +74,8 @@ class TaskDuplicateAnotherProject extends Base
*/
public function doAction(array $data)
{
- $destination_column_id = $this->column->getFirstColumnId($this->getParam('project_id'));
- return (bool) $this->taskDuplication->duplicateToProject($data['task_id'], $this->getParam('project_id'), null, $destination_column_id);
+ $destination_column_id = $this->columnModel->getFirstColumnId($this->getParam('project_id'));
+ return (bool) $this->taskDuplicationModel->duplicateToProject($data['task_id'], $this->getParam('project_id'), null, $destination_column_id);
}
/**
diff --git a/app/Action/TaskEmail.php b/app/Action/TaskEmail.php
index 4e0e06a6..7f9ba416 100644
--- a/app/Action/TaskEmail.php
+++ b/app/Action/TaskEmail.php
@@ -2,7 +2,7 @@
namespace Kanboard\Action;
-use Kanboard\Model\Task;
+use Kanboard\Model\TaskModel;
/**
* Email a task to someone
@@ -32,8 +32,8 @@ class TaskEmail extends Base
public function getCompatibleEvents()
{
return array(
- Task::EVENT_MOVE_COLUMN,
- Task::EVENT_CLOSE,
+ TaskModel::EVENT_MOVE_COLUMN,
+ TaskModel::EVENT_CLOSE,
);
}
@@ -75,16 +75,16 @@ class TaskEmail extends Base
*/
public function doAction(array $data)
{
- $user = $this->user->getById($this->getParam('user_id'));
+ $user = $this->userModel->getById($this->getParam('user_id'));
if (! empty($user['email'])) {
- $task = $this->taskFinder->getDetails($data['task_id']);
+ $task = $this->taskFinderModel->getDetails($data['task_id']);
$this->emailClient->send(
$user['email'],
$user['name'] ?: $user['username'],
$this->getParam('subject'),
- $this->template->render('notification/task_create', array('task' => $task, 'application_url' => $this->config->get('application_url')))
+ $this->template->render('notification/task_create', array('task' => $task, 'application_url' => $this->configModel->get('application_url')))
);
return true;
diff --git a/app/Action/TaskEmailNoActivity.php b/app/Action/TaskEmailNoActivity.php
index c5d7a797..c60702fb 100644
--- a/app/Action/TaskEmailNoActivity.php
+++ b/app/Action/TaskEmailNoActivity.php
@@ -2,7 +2,7 @@
namespace Kanboard\Action;
-use Kanboard\Model\Task;
+use Kanboard\Model\TaskModel;
/**
* Email a task with no activity
@@ -32,7 +32,7 @@ class TaskEmailNoActivity extends Base
public function getCompatibleEvents()
{
return array(
- Task::EVENT_DAILY_CRONJOB,
+ TaskModel::EVENT_DAILY_CRONJOB,
);
}
@@ -85,7 +85,7 @@ class TaskEmailNoActivity extends Base
{
$results = array();
$max = $this->getParam('duration') * 86400;
- $user = $this->user->getById($this->getParam('user_id'));
+ $user = $this->userModel->getById($this->getParam('user_id'));
if (! empty($user['email'])) {
foreach ($data['tasks'] as $task) {
@@ -110,13 +110,13 @@ class TaskEmailNoActivity extends Base
*/
private function sendEmail($task_id, array $user)
{
- $task = $this->taskFinder->getDetails($task_id);
+ $task = $this->taskFinderModel->getDetails($task_id);
$this->emailClient->send(
$user['email'],
$user['name'] ?: $user['username'],
$this->getParam('subject'),
- $this->template->render('notification/task_create', array('task' => $task, 'application_url' => $this->config->get('application_url')))
+ $this->template->render('notification/task_create', array('task' => $task, 'application_url' => $this->configModel->get('application_url')))
);
return true;
diff --git a/app/Action/TaskMoveAnotherProject.php b/app/Action/TaskMoveAnotherProject.php
index fdff0d8c..73ad4b69 100644
--- a/app/Action/TaskMoveAnotherProject.php
+++ b/app/Action/TaskMoveAnotherProject.php
@@ -2,7 +2,7 @@
namespace Kanboard\Action;
-use Kanboard\Model\Task;
+use Kanboard\Model\TaskModel;
/**
* Move a task to another project
@@ -32,8 +32,8 @@ class TaskMoveAnotherProject extends Base
public function getCompatibleEvents()
{
return array(
- Task::EVENT_MOVE_COLUMN,
- Task::EVENT_CLOSE,
+ TaskModel::EVENT_MOVE_COLUMN,
+ TaskModel::EVENT_CLOSE,
);
}
@@ -75,7 +75,7 @@ class TaskMoveAnotherProject extends Base
*/
public function doAction(array $data)
{
- return $this->taskDuplication->moveToProject($data['task_id'], $this->getParam('project_id'));
+ return $this->taskDuplicationModel->moveToProject($data['task_id'], $this->getParam('project_id'));
}
/**
diff --git a/app/Action/TaskMoveColumnAssigned.php b/app/Action/TaskMoveColumnAssigned.php
index 1b23a591..7e3db9c5 100644
--- a/app/Action/TaskMoveColumnAssigned.php
+++ b/app/Action/TaskMoveColumnAssigned.php
@@ -2,7 +2,7 @@
namespace Kanboard\Action;
-use Kanboard\Model\Task;
+use Kanboard\Model\TaskModel;
/**
* Move a task to another column when an assignee is set
@@ -32,8 +32,8 @@ class TaskMoveColumnAssigned extends Base
public function getCompatibleEvents()
{
return array(
- Task::EVENT_ASSIGNEE_CHANGE,
- Task::EVENT_UPDATE,
+ TaskModel::EVENT_ASSIGNEE_CHANGE,
+ TaskModel::EVENT_UPDATE,
);
}
@@ -75,9 +75,9 @@ class TaskMoveColumnAssigned extends Base
*/
public function doAction(array $data)
{
- $original_task = $this->taskFinder->getById($data['task_id']);
+ $original_task = $this->taskFinderModel->getById($data['task_id']);
- return $this->taskPosition->movePosition(
+ return $this->taskPositionModel->movePosition(
$data['project_id'],
$data['task_id'],
$this->getParam('dest_column_id'),
diff --git a/app/Action/TaskMoveColumnCategoryChange.php b/app/Action/TaskMoveColumnCategoryChange.php
index 0f591eda..e4f88760 100644
--- a/app/Action/TaskMoveColumnCategoryChange.php
+++ b/app/Action/TaskMoveColumnCategoryChange.php
@@ -2,7 +2,7 @@
namespace Kanboard\Action;
-use Kanboard\Model\Task;
+use Kanboard\Model\TaskModel;
/**
* Move a task to another column when the category is changed
@@ -32,7 +32,7 @@ class TaskMoveColumnCategoryChange extends Base
public function getCompatibleEvents()
{
return array(
- Task::EVENT_UPDATE,
+ TaskModel::EVENT_UPDATE,
);
}
@@ -74,9 +74,9 @@ class TaskMoveColumnCategoryChange extends Base
*/
public function doAction(array $data)
{
- $original_task = $this->taskFinder->getById($data['task_id']);
+ $original_task = $this->taskFinderModel->getById($data['task_id']);
- return $this->taskPosition->movePosition(
+ return $this->taskPositionModel->movePosition(
$data['project_id'],
$data['task_id'],
$this->getParam('dest_column_id'),
diff --git a/app/Action/TaskMoveColumnUnAssigned.php b/app/Action/TaskMoveColumnUnAssigned.php
index 99ef9351..c3ae9e1d 100644
--- a/app/Action/TaskMoveColumnUnAssigned.php
+++ b/app/Action/TaskMoveColumnUnAssigned.php
@@ -2,7 +2,7 @@
namespace Kanboard\Action;
-use Kanboard\Model\Task;
+use Kanboard\Model\TaskModel;
/**
* Move a task to another column when an assignee is cleared
@@ -32,8 +32,8 @@ class TaskMoveColumnUnAssigned extends Base
public function getCompatibleEvents()
{
return array(
- Task::EVENT_ASSIGNEE_CHANGE,
- Task::EVENT_UPDATE,
+ TaskModel::EVENT_ASSIGNEE_CHANGE,
+ TaskModel::EVENT_UPDATE,
);
}
@@ -75,9 +75,9 @@ class TaskMoveColumnUnAssigned extends Base
*/
public function doAction(array $data)
{
- $original_task = $this->taskFinder->getById($data['task_id']);
+ $original_task = $this->taskFinderModel->getById($data['task_id']);
- return $this->taskPosition->movePosition(
+ return $this->taskPositionModel->movePosition(
$data['project_id'],
$data['task_id'],
$this->getParam('dest_column_id'),
diff --git a/app/Action/TaskOpen.php b/app/Action/TaskOpen.php
index ec0f96f7..8e847b8e 100644
--- a/app/Action/TaskOpen.php
+++ b/app/Action/TaskOpen.php
@@ -63,7 +63,7 @@ class TaskOpen extends Base
*/
public function doAction(array $data)
{
- return $this->taskStatus->open($data['task_id']);
+ return $this->taskStatusModel->open($data['task_id']);
}
/**
diff --git a/app/Action/TaskUpdateStartDate.php b/app/Action/TaskUpdateStartDate.php
index e5cea01b..e5410a87 100644
--- a/app/Action/TaskUpdateStartDate.php
+++ b/app/Action/TaskUpdateStartDate.php
@@ -2,7 +2,7 @@
namespace Kanboard\Action;
-use Kanboard\Model\Task;
+use Kanboard\Model\TaskModel;
/**
* Set the start date of task
@@ -32,7 +32,7 @@ class TaskUpdateStartDate extends Base
public function getCompatibleEvents()
{
return array(
- Task::EVENT_MOVE_COLUMN,
+ TaskModel::EVENT_MOVE_COLUMN,
);
}
@@ -77,7 +77,7 @@ class TaskUpdateStartDate extends Base
'date_started' => time(),
);
- return $this->taskModification->update($values, false);
+ return $this->taskModificationModel->update($values, false);
}
/**
diff --git a/app/Analytic/AverageLeadCycleTimeAnalytic.php b/app/Analytic/AverageLeadCycleTimeAnalytic.php
index 62c83559..d6cd1f86 100644
--- a/app/Analytic/AverageLeadCycleTimeAnalytic.php
+++ b/app/Analytic/AverageLeadCycleTimeAnalytic.php
@@ -3,7 +3,7 @@
namespace Kanboard\Analytic;
use Kanboard\Core\Base;
-use Kanboard\Model\Task;
+use Kanboard\Model\TaskModel;
/**
* Average Lead and Cycle Time
@@ -106,7 +106,7 @@ class AverageLeadCycleTimeAnalytic extends Base
private function getTasks($project_id)
{
return $this->db
- ->table(Task::TABLE)
+ ->table(TaskModel::TABLE)
->columns('date_completed', 'date_creation', 'date_started')
->eq('project_id', $project_id)
->desc('id')
diff --git a/app/Analytic/AverageTimeSpentColumnAnalytic.php b/app/Analytic/AverageTimeSpentColumnAnalytic.php
index 11078323..3556fb9d 100644
--- a/app/Analytic/AverageTimeSpentColumnAnalytic.php
+++ b/app/Analytic/AverageTimeSpentColumnAnalytic.php
@@ -3,7 +3,7 @@
namespace Kanboard\Analytic;
use Kanboard\Core\Base;
-use Kanboard\Model\Task;
+use Kanboard\Model\TaskModel;
/**
* Average Time Spent by Column
@@ -40,7 +40,7 @@ class AverageTimeSpentColumnAnalytic extends Base
private function initialize($project_id)
{
$stats = array();
- $columns = $this->column->getList($project_id);
+ $columns = $this->columnModel->getList($project_id);
foreach ($columns as $column_id => $column_title) {
$stats[$column_id] = array(
@@ -110,7 +110,7 @@ class AverageTimeSpentColumnAnalytic extends Base
*/
private function getTaskTimeByColumns(array &$task)
{
- $columns = $this->transition->getTimeSpentByTask($task['id']);
+ $columns = $this->transitionModel->getTimeSpentByTask($task['id']);
if (! isset($columns[$task['column_id']])) {
$columns[$task['column_id']] = 0;
@@ -144,7 +144,7 @@ class AverageTimeSpentColumnAnalytic extends Base
private function getTasks($project_id)
{
return $this->db
- ->table(Task::TABLE)
+ ->table(TaskModel::TABLE)
->columns('id', 'date_completed', 'date_moved', 'column_id')
->eq('project_id', $project_id)
->desc('id')
diff --git a/app/Analytic/EstimatedTimeComparisonAnalytic.php b/app/Analytic/EstimatedTimeComparisonAnalytic.php
index 490bcd50..d9aea32d 100644
--- a/app/Analytic/EstimatedTimeComparisonAnalytic.php
+++ b/app/Analytic/EstimatedTimeComparisonAnalytic.php
@@ -3,7 +3,7 @@
namespace Kanboard\Analytic;
use Kanboard\Core\Base;
-use Kanboard\Model\Task;
+use Kanboard\Model\TaskModel;
/**
* Estimated/Spent Time Comparison
@@ -22,7 +22,7 @@ class EstimatedTimeComparisonAnalytic extends Base
*/
public function build($project_id)
{
- $rows = $this->db->table(Task::TABLE)
+ $rows = $this->db->table(TaskModel::TABLE)
->columns('SUM(time_estimated) AS time_estimated', 'SUM(time_spent) AS time_spent', 'is_active')
->eq('project_id', $project_id)
->groupBy('is_active')
@@ -40,7 +40,7 @@ class EstimatedTimeComparisonAnalytic extends Base
);
foreach ($rows as $row) {
- $key = $row['is_active'] == Task::STATUS_OPEN ? 'open' : 'closed';
+ $key = $row['is_active'] == TaskModel::STATUS_OPEN ? 'open' : 'closed';
$metrics[$key]['time_spent'] = $row['time_spent'];
$metrics[$key]['time_estimated'] = $row['time_estimated'];
}
diff --git a/app/Analytic/TaskDistributionAnalytic.php b/app/Analytic/TaskDistributionAnalytic.php
index 838652e3..447d88a1 100644
--- a/app/Analytic/TaskDistributionAnalytic.php
+++ b/app/Analytic/TaskDistributionAnalytic.php
@@ -23,10 +23,10 @@ class TaskDistributionAnalytic extends Base
{
$metrics = array();
$total = 0;
- $columns = $this->column->getAll($project_id);
+ $columns = $this->columnModel->getAll($project_id);
foreach ($columns as $column) {
- $nb_tasks = $this->taskFinder->countByColumnId($project_id, $column['id']);
+ $nb_tasks = $this->taskFinderModel->countByColumnId($project_id, $column['id']);
$total += $nb_tasks;
$metrics[] = array(
diff --git a/app/Analytic/UserDistributionAnalytic.php b/app/Analytic/UserDistributionAnalytic.php
index e1815f9c..421d4242 100644
--- a/app/Analytic/UserDistributionAnalytic.php
+++ b/app/Analytic/UserDistributionAnalytic.php
@@ -23,8 +23,8 @@ class UserDistributionAnalytic extends Base
{
$metrics = array();
$total = 0;
- $tasks = $this->taskFinder->getAll($project_id);
- $users = $this->projectUserRole->getAssignableUsersList($project_id);
+ $tasks = $this->taskFinderModel->getAll($project_id);
+ $users = $this->projectUserRoleModel->getAssignableUsersList($project_id);
foreach ($tasks as $task) {
$user = isset($users[$task['owner_id']]) ? $users[$task['owner_id']] : $users[0];
diff --git a/app/Api/Action.php b/app/Api/ActionApi.php
index 9e3b86f6..116742d8 100644
--- a/app/Api/Action.php
+++ b/app/Api/ActionApi.php
@@ -2,13 +2,15 @@
namespace Kanboard\Api;
+use Kanboard\Core\Base;
+
/**
* Action API controller
*
- * @package api
+ * @package Kanboard\Api
* @author Frederic Guillot
*/
-class Action extends \Kanboard\Core\Base
+class ActionApi extends Base
{
public function getAvailableActions()
{
@@ -27,12 +29,12 @@ class Action extends \Kanboard\Core\Base
public function removeAction($action_id)
{
- return $this->action->remove($action_id);
+ return $this->actionModel->remove($action_id);
}
public function getActions($project_id)
{
- return $this->action->getAllByProject($project_id);
+ return $this->actionModel->getAllByProject($project_id);
}
public function createAction($project_id, $event_name, $action_name, array $params)
@@ -80,6 +82,6 @@ class Action extends \Kanboard\Core\Base
}
}
- return $this->action->create($values);
+ return $this->actionModel->create($values);
}
}
diff --git a/app/Api/App.php b/app/Api/AppApi.php
index 635f1ce2..637de5c5 100644
--- a/app/Api/App.php
+++ b/app/Api/AppApi.php
@@ -2,17 +2,19 @@
namespace Kanboard\Api;
+use Kanboard\Core\Base;
+
/**
* App API controller
*
- * @package api
+ * @package Kanboard\Api
* @author Frederic Guillot
*/
-class App extends \Kanboard\Core\Base
+class AppApi extends Base
{
public function getTimezone()
{
- return $this->config->get('application_timezone');
+ return $this->timezoneModel->getCurrentTimezone();
}
public function getVersion()
@@ -22,17 +24,17 @@ class App extends \Kanboard\Core\Base
public function getDefaultTaskColor()
{
- return $this->color->getDefaultColor();
+ return $this->colorModel->getDefaultColor();
}
public function getDefaultTaskColors()
{
- return $this->color->getDefaultColors();
+ return $this->colorModel->getDefaultColors();
}
public function getColorList()
{
- return $this->color->getList();
+ return $this->colorModel->getList();
}
public function getApplicationRoles()
diff --git a/app/Api/Auth.php b/app/Api/Auth.php
deleted file mode 100644
index 1cc6627f..00000000
--- a/app/Api/Auth.php
+++ /dev/null
@@ -1,81 +0,0 @@
-<?php
-
-namespace Kanboard\Api;
-
-use JsonRPC\Exception\AuthenticationFailureException;
-
-/**
- * Base class
- *
- * @package api
- * @author Frederic Guillot
- */
-class Auth extends Base
-{
- /**
- * Check api credentials
- *
- * @access public
- * @param string $username
- * @param string $password
- * @param string $class
- * @param string $method
- */
- public function checkCredentials($username, $password, $class, $method)
- {
- $this->dispatcher->dispatch('app.bootstrap');
-
- if ($this->isUserAuthenticated($username, $password)) {
- $this->checkProcedurePermission(true, $method);
- $this->userSession->initialize($this->user->getByUsername($username));
- } elseif ($this->isAppAuthenticated($username, $password)) {
- $this->checkProcedurePermission(false, $method);
- } else {
- $this->logger->error('API authentication failure for '.$username);
- throw new AuthenticationFailureException('Wrong credentials');
- }
- }
-
- /**
- * Check user credentials
- *
- * @access public
- * @param string $username
- * @param string $password
- * @return boolean
- */
- private function isUserAuthenticated($username, $password)
- {
- return $username !== 'jsonrpc' &&
- ! $this->userLocking->isLocked($username) &&
- $this->authenticationManager->passwordAuthentication($username, $password);
- }
-
- /**
- * Check administrative credentials
- *
- * @access public
- * @param string $username
- * @param string $password
- * @return boolean
- */
- private function isAppAuthenticated($username, $password)
- {
- return $username === 'jsonrpc' && $password === $this->getApiToken();
- }
-
- /**
- * Get API Token
- *
- * @access private
- * @return string
- */
- private function getApiToken()
- {
- if (defined('API_AUTHENTICATION_TOKEN')) {
- return API_AUTHENTICATION_TOKEN;
- }
-
- return $this->config->get('api_token');
- }
-}
diff --git a/app/Api/Base.php b/app/Api/Base.php
deleted file mode 100644
index ea817f7d..00000000
--- a/app/Api/Base.php
+++ /dev/null
@@ -1,118 +0,0 @@
-<?php
-
-namespace Kanboard\Api;
-
-use JsonRPC\Exception\AccessDeniedException;
-
-/**
- * Base class
- *
- * @package api
- * @author Frederic Guillot
- */
-abstract class Base extends \Kanboard\Core\Base
-{
- private $user_allowed_procedures = array(
- 'getMe',
- 'getMyDashboard',
- 'getMyActivityStream',
- 'createMyPrivateProject',
- 'getMyProjectsList',
- 'getMyProjects',
- 'getMyOverdueTasks',
- );
-
- private $both_allowed_procedures = array(
- 'getTimezone',
- 'getVersion',
- 'getDefaultTaskColor',
- 'getDefaultTaskColors',
- 'getColorList',
- 'getProjectById',
- 'getTask',
- 'getTaskByReference',
- 'getAllTasks',
- 'openTask',
- 'closeTask',
- 'moveTaskPosition',
- 'createTask',
- 'updateTask',
- 'getBoard',
- 'getProjectActivity',
- 'getOverdueTasksByProject',
- 'searchTasks',
- );
-
- public function checkProcedurePermission($is_user, $procedure)
- {
- $is_both_procedure = in_array($procedure, $this->both_allowed_procedures);
- $is_user_procedure = in_array($procedure, $this->user_allowed_procedures);
-
- if ($is_user && ! $is_both_procedure && ! $is_user_procedure) {
- throw new AccessDeniedException('Permission denied');
- } elseif (! $is_user && ! $is_both_procedure && $is_user_procedure) {
- throw new AccessDeniedException('Permission denied');
- }
-
- $this->logger->debug('API call: '.$procedure);
- }
-
- public function checkProjectPermission($project_id)
- {
- if ($this->userSession->isLogged() && ! $this->projectPermission->isUserAllowed($project_id, $this->userSession->getId())) {
- throw new AccessDeniedException('Permission denied');
- }
- }
-
- public function checkTaskPermission($task_id)
- {
- if ($this->userSession->isLogged()) {
- $this->checkProjectPermission($this->taskFinder->getProjectId($task_id));
- }
- }
-
- protected function formatTask($task)
- {
- if (! empty($task)) {
- $task['url'] = $this->helper->url->to('task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), '', true);
- $task['color'] = $this->color->getColorProperties($task['color_id']);
- }
-
- return $task;
- }
-
- protected function formatTasks($tasks)
- {
- if (! empty($tasks)) {
- foreach ($tasks as &$task) {
- $task = $this->formatTask($task);
- }
- }
-
- return $tasks;
- }
-
- protected function formatProject($project)
- {
- if (! empty($project)) {
- $project['url'] = array(
- 'board' => $this->helper->url->to('board', 'show', array('project_id' => $project['id']), '', true),
- 'calendar' => $this->helper->url->to('calendar', 'show', array('project_id' => $project['id']), '', true),
- 'list' => $this->helper->url->to('listing', 'show', array('project_id' => $project['id']), '', true),
- );
- }
-
- return $project;
- }
-
- protected function formatProjects($projects)
- {
- if (! empty($projects)) {
- foreach ($projects as &$project) {
- $project = $this->formatProject($project);
- }
- }
-
- return $projects;
- }
-}
diff --git a/app/Api/BaseApi.php b/app/Api/BaseApi.php
new file mode 100644
index 00000000..9f69aa65
--- /dev/null
+++ b/app/Api/BaseApi.php
@@ -0,0 +1,74 @@
+<?php
+
+namespace Kanboard\Api;
+
+use JsonRPC\Exception\AccessDeniedException;
+use Kanboard\Core\Base;
+
+/**
+ * Base class
+ *
+ * @package Kanboard\Api
+ * @author Frederic Guillot
+ */
+abstract class BaseApi extends Base
+{
+ public function checkProjectPermission($project_id)
+ {
+ if ($this->userSession->isLogged() && ! $this->projectPermissionModel->isUserAllowed($project_id, $this->userSession->getId())) {
+ throw new AccessDeniedException('Permission denied');
+ }
+ }
+
+ public function checkTaskPermission($task_id)
+ {
+ if ($this->userSession->isLogged()) {
+ $this->checkProjectPermission($this->taskFinderModel->getProjectId($task_id));
+ }
+ }
+
+ protected function formatTask($task)
+ {
+ if (! empty($task)) {
+ $task['url'] = $this->helper->url->to('TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), '', true);
+ $task['color'] = $this->colorModel->getColorProperties($task['color_id']);
+ }
+
+ return $task;
+ }
+
+ protected function formatTasks($tasks)
+ {
+ if (! empty($tasks)) {
+ foreach ($tasks as &$task) {
+ $task = $this->formatTask($task);
+ }
+ }
+
+ return $tasks;
+ }
+
+ protected function formatProject($project)
+ {
+ if (! empty($project)) {
+ $project['url'] = array(
+ 'board' => $this->helper->url->to('BoardViewController', 'show', array('project_id' => $project['id']), '', true),
+ 'calendar' => $this->helper->url->to('CalendarController', 'show', array('project_id' => $project['id']), '', true),
+ 'list' => $this->helper->url->to('TaskListController', 'show', array('project_id' => $project['id']), '', true),
+ );
+ }
+
+ return $project;
+ }
+
+ protected function formatProjects($projects)
+ {
+ if (! empty($projects)) {
+ foreach ($projects as &$project) {
+ $project = $this->formatProject($project);
+ }
+ }
+
+ return $projects;
+ }
+}
diff --git a/app/Api/Board.php b/app/Api/BoardApi.php
index 185ac51a..aa5942af 100644
--- a/app/Api/Board.php
+++ b/app/Api/BoardApi.php
@@ -5,14 +5,14 @@ namespace Kanboard\Api;
/**
* Board API controller
*
- * @package api
+ * @package Kanboard\Api
* @author Frederic Guillot
*/
-class Board extends Base
+class BoardApi extends BaseApi
{
public function getBoard($project_id)
{
$this->checkProjectPermission($project_id);
- return $this->board->getBoard($project_id);
+ return $this->boardModel->getBoard($project_id);
}
}
diff --git a/app/Api/Category.php b/app/Api/CategoryApi.php
index fbd61c56..c56cfb35 100644
--- a/app/Api/Category.php
+++ b/app/Api/CategoryApi.php
@@ -2,27 +2,29 @@
namespace Kanboard\Api;
+use Kanboard\Core\Base;
+
/**
* Category API controller
*
- * @package api
+ * @package Kanboard\Api
* @author Frederic Guillot
*/
-class Category extends \Kanboard\Core\Base
+class CategoryApi extends Base
{
public function getCategory($category_id)
{
- return $this->category->getById($category_id);
+ return $this->categoryModel->getById($category_id);
}
public function getAllCategories($project_id)
{
- return $this->category->getAll($project_id);
+ return $this->categoryModel->getAll($project_id);
}
public function removeCategory($category_id)
{
- return $this->category->remove($category_id);
+ return $this->categoryModel->remove($category_id);
}
public function createCategory($project_id, $name)
@@ -33,7 +35,7 @@ class Category extends \Kanboard\Core\Base
);
list($valid, ) = $this->categoryValidator->validateCreation($values);
- return $valid ? $this->category->create($values) : false;
+ return $valid ? $this->categoryModel->create($values) : false;
}
public function updateCategory($id, $name)
@@ -44,6 +46,6 @@ class Category extends \Kanboard\Core\Base
);
list($valid, ) = $this->categoryValidator->validateModification($values);
- return $valid && $this->category->update($values);
+ return $valid && $this->categoryModel->update($values);
}
}
diff --git a/app/Api/Column.php b/app/Api/ColumnApi.php
index ddc3a5d0..aa4026f6 100644
--- a/app/Api/Column.php
+++ b/app/Api/ColumnApi.php
@@ -5,38 +5,38 @@ namespace Kanboard\Api;
/**
* Column API controller
*
- * @package api
+ * @package Kanboard\Api
* @author Frederic Guillot
*/
-class Column extends Base
+class ColumnApi extends BaseApi
{
public function getColumns($project_id)
{
- return $this->column->getAll($project_id);
+ return $this->columnModel->getAll($project_id);
}
public function getColumn($column_id)
{
- return $this->column->getById($column_id);
+ return $this->columnModel->getById($column_id);
}
public function updateColumn($column_id, $title, $task_limit = 0, $description = '')
{
- return $this->column->update($column_id, $title, $task_limit, $description);
+ return $this->columnModel->update($column_id, $title, $task_limit, $description);
}
public function addColumn($project_id, $title, $task_limit = 0, $description = '')
{
- return $this->column->create($project_id, $title, $task_limit, $description);
+ return $this->columnModel->create($project_id, $title, $task_limit, $description);
}
public function removeColumn($column_id)
{
- return $this->column->remove($column_id);
+ return $this->columnModel->remove($column_id);
}
public function changeColumnPosition($project_id, $column_id, $position)
{
- return $this->column->changePosition($project_id, $column_id, $position);
+ return $this->columnModel->changePosition($project_id, $column_id, $position);
}
}
diff --git a/app/Api/Comment.php b/app/Api/CommentApi.php
index 1fc1c708..8358efee 100644
--- a/app/Api/Comment.php
+++ b/app/Api/CommentApi.php
@@ -2,27 +2,29 @@
namespace Kanboard\Api;
+use Kanboard\Core\Base;
+
/**
* Comment API controller
*
- * @package api
+ * @package Kanboard\Api
* @author Frederic Guillot
*/
-class Comment extends \Kanboard\Core\Base
+class CommentApi extends Base
{
public function getComment($comment_id)
{
- return $this->comment->getById($comment_id);
+ return $this->commentModel->getById($comment_id);
}
public function getAllComments($task_id)
{
- return $this->comment->getAll($task_id);
+ return $this->commentModel->getAll($task_id);
}
public function removeComment($comment_id)
{
- return $this->comment->remove($comment_id);
+ return $this->commentModel->remove($comment_id);
}
public function createComment($task_id, $user_id, $content, $reference = '')
@@ -36,7 +38,7 @@ class Comment extends \Kanboard\Core\Base
list($valid, ) = $this->commentValidator->validateCreation($values);
- return $valid ? $this->comment->create($values) : false;
+ return $valid ? $this->commentModel->create($values) : false;
}
public function updateComment($id, $content)
@@ -47,6 +49,6 @@ class Comment extends \Kanboard\Core\Base
);
list($valid, ) = $this->commentValidator->validateModification($values);
- return $valid && $this->comment->update($values);
+ return $valid && $this->commentModel->update($values);
}
}
diff --git a/app/Api/File.php b/app/Api/FileApi.php
index 71c31c76..1ed3aeb9 100644
--- a/app/Api/File.php
+++ b/app/Api/FileApi.php
@@ -7,39 +7,40 @@ use Kanboard\Core\ObjectStorage\ObjectStorageException;
/**
* File API controller
*
- * @package api
+ * @package Kanboard\Api
* @author Frederic Guillot
*/
-class File extends Base
+class FileApi extends BaseApi
{
public function getTaskFile($file_id)
{
- return $this->taskFile->getById($file_id);
+ return $this->taskFileModel->getById($file_id);
}
public function getAllTaskFiles($task_id)
{
- return $this->taskFile->getAll($task_id);
+ return $this->taskFileModel->getAll($task_id);
}
public function downloadTaskFile($file_id)
{
try {
- $file = $this->taskFile->getById($file_id);
+ $file = $this->taskFileModel->getById($file_id);
if (! empty($file)) {
return base64_encode($this->objectStorage->get($file['path']));
}
} catch (ObjectStorageException $e) {
$this->logger->error($e->getMessage());
- return '';
}
+
+ return '';
}
public function createTaskFile($project_id, $task_id, $filename, $blob)
{
try {
- return $this->taskFile->uploadContent($task_id, $filename, $blob);
+ return $this->taskFileModel->uploadContent($task_id, $filename, $blob);
} catch (ObjectStorageException $e) {
$this->logger->error($e->getMessage());
return false;
@@ -48,12 +49,12 @@ class File extends Base
public function removeTaskFile($file_id)
{
- return $this->taskFile->remove($file_id);
+ return $this->taskFileModel->remove($file_id);
}
public function removeAllTaskFiles($task_id)
{
- return $this->taskFile->removeAll($task_id);
+ return $this->taskFileModel->removeAll($task_id);
}
// Deprecated procedures
diff --git a/app/Api/Group.php b/app/Api/GroupApi.php
index a1e0a73d..1701edc3 100644
--- a/app/Api/Group.php
+++ b/app/Api/GroupApi.php
@@ -2,17 +2,19 @@
namespace Kanboard\Api;
+use Kanboard\Core\Base;
+
/**
* Group API controller
*
- * @package api
+ * @package Kanboard\Api
* @author Frederic Guillot
*/
-class Group extends \Kanboard\Core\Base
+class GroupApi extends Base
{
public function createGroup($name, $external_id = '')
{
- return $this->group->create($name, $external_id);
+ return $this->groupModel->create($name, $external_id);
}
public function updateGroup($group_id, $name = null, $external_id = null)
@@ -29,21 +31,21 @@ class Group extends \Kanboard\Core\Base
}
}
- return $this->group->update($values);
+ return $this->groupModel->update($values);
}
public function removeGroup($group_id)
{
- return $this->group->remove($group_id);
+ return $this->groupModel->remove($group_id);
}
public function getGroup($group_id)
{
- return $this->group->getById($group_id);
+ return $this->groupModel->getById($group_id);
}
public function getAllGroups()
{
- return $this->group->getAll();
+ return $this->groupModel->getAll();
}
}
diff --git a/app/Api/GroupMember.php b/app/Api/GroupMemberApi.php
index 9d2a4796..e09f6975 100644
--- a/app/Api/GroupMember.php
+++ b/app/Api/GroupMemberApi.php
@@ -2,36 +2,38 @@
namespace Kanboard\Api;
+use Kanboard\Core\Base;
+
/**
* Group Member API controller
*
- * @package api
+ * @package Kanboard\Api
* @author Frederic Guillot
*/
-class GroupMember extends \Kanboard\Core\Base
+class GroupMemberApi extends Base
{
public function getMemberGroups($user_id)
{
- return $this->groupMember->getGroups($user_id);
+ return $this->groupMemberModel->getGroups($user_id);
}
public function getGroupMembers($group_id)
{
- return $this->groupMember->getMembers($group_id);
+ return $this->groupMemberModel->getMembers($group_id);
}
public function addGroupMember($group_id, $user_id)
{
- return $this->groupMember->addUser($group_id, $user_id);
+ return $this->groupMemberModel->addUser($group_id, $user_id);
}
public function removeGroupMember($group_id, $user_id)
{
- return $this->groupMember->removeUser($group_id, $user_id);
+ return $this->groupMemberModel->removeUser($group_id, $user_id);
}
public function isGroupMember($group_id, $user_id)
{
- return $this->groupMember->isMember($group_id, $user_id);
+ return $this->groupMemberModel->isMember($group_id, $user_id);
}
}
diff --git a/app/Api/Link.php b/app/Api/LinkApi.php
index 23a9916d..d8e525e4 100644
--- a/app/Api/Link.php
+++ b/app/Api/LinkApi.php
@@ -2,13 +2,15 @@
namespace Kanboard\Api;
+use Kanboard\Core\Base;
+
/**
* Link API controller
*
- * @package api
+ * @package Kanboard\Api
* @author Frederic Guillot
*/
-class Link extends \Kanboard\Core\Base
+class LinkApi extends Base
{
/**
* Get a link by id
@@ -19,7 +21,7 @@ class Link extends \Kanboard\Core\Base
*/
public function getLinkById($link_id)
{
- return $this->link->getById($link_id);
+ return $this->linkModel->getById($link_id);
}
/**
@@ -31,7 +33,7 @@ class Link extends \Kanboard\Core\Base
*/
public function getLinkByLabel($label)
{
- return $this->link->getByLabel($label);
+ return $this->linkModel->getByLabel($label);
}
/**
@@ -43,7 +45,7 @@ class Link extends \Kanboard\Core\Base
*/
public function getOppositeLinkId($link_id)
{
- return $this->link->getOppositeLinkId($link_id);
+ return $this->linkModel->getOppositeLinkId($link_id);
}
/**
@@ -54,7 +56,7 @@ class Link extends \Kanboard\Core\Base
*/
public function getAllLinks()
{
- return $this->link->getAll();
+ return $this->linkModel->getAll();
}
/**
@@ -73,7 +75,7 @@ class Link extends \Kanboard\Core\Base
);
list($valid, ) = $this->linkValidator->validateCreation($values);
- return $valid ? $this->link->create($label, $opposite_label) : false;
+ return $valid ? $this->linkModel->create($label, $opposite_label) : false;
}
/**
@@ -94,7 +96,7 @@ class Link extends \Kanboard\Core\Base
);
list($valid, ) = $this->linkValidator->validateModification($values);
- return $valid && $this->link->update($values);
+ return $valid && $this->linkModel->update($values);
}
/**
@@ -106,6 +108,6 @@ class Link extends \Kanboard\Core\Base
*/
public function removeLink($link_id)
{
- return $this->link->remove($link_id);
+ return $this->linkModel->remove($link_id);
}
}
diff --git a/app/Api/Me.php b/app/Api/MeApi.php
index 3d08626a..497749b6 100644
--- a/app/Api/Me.php
+++ b/app/Api/MeApi.php
@@ -2,15 +2,15 @@
namespace Kanboard\Api;
-use Kanboard\Model\Subtask as SubtaskModel;
+use Kanboard\Model\SubtaskModel;
/**
* Me API controller
*
- * @package api
+ * @package Kanboard\Api
* @author Frederic Guillot
*/
-class Me extends Base
+class MeApi extends BaseApi
{
public function getMe()
{
@@ -20,25 +20,25 @@ class Me extends Base
public function getMyDashboard()
{
$user_id = $this->userSession->getId();
- $projects = $this->project->getQueryColumnStats($this->projectPermission->getActiveProjectIds($user_id))->findAll();
- $tasks = $this->taskFinder->getUserQuery($user_id)->findAll();
+ $projects = $this->projectModel->getQueryColumnStats($this->projectPermissionModel->getActiveProjectIds($user_id))->findAll();
+ $tasks = $this->taskFinderModel->getUserQuery($user_id)->findAll();
return array(
'projects' => $this->formatProjects($projects),
'tasks' => $this->formatTasks($tasks),
- 'subtasks' => $this->subtask->getUserQuery($user_id, array(SubTaskModel::STATUS_TODO, SubtaskModel::STATUS_INPROGRESS))->findAll(),
+ 'subtasks' => $this->subtaskModel->getUserQuery($user_id, array(SubtaskModel::STATUS_TODO, SubtaskModel::STATUS_INPROGRESS))->findAll(),
);
}
public function getMyActivityStream()
{
- $project_ids = $this->projectPermission->getActiveProjectIds($this->userSession->getId());
+ $project_ids = $this->projectPermissionModel->getActiveProjectIds($this->userSession->getId());
return $this->helper->projectActivity->getProjectsEvents($project_ids, 100);
}
public function createMyPrivateProject($name, $description = null)
{
- if ($this->config->get('disable_private_project', 0) == 1) {
+ if ($this->configModel->get('disable_private_project', 0) == 1) {
return false;
}
@@ -49,23 +49,23 @@ class Me extends Base
);
list($valid, ) = $this->projectValidator->validateCreation($values);
- return $valid ? $this->project->create($values, $this->userSession->getId(), true) : false;
+ return $valid ? $this->projectModel->create($values, $this->userSession->getId(), true) : false;
}
public function getMyProjectsList()
{
- return $this->projectUserRole->getProjectsByUser($this->userSession->getId());
+ return $this->projectUserRoleModel->getProjectsByUser($this->userSession->getId());
}
public function getMyOverdueTasks()
{
- return $this->taskFinder->getOverdueTasksByUser($this->userSession->getId());
+ return $this->taskFinderModel->getOverdueTasksByUser($this->userSession->getId());
}
public function getMyProjects()
{
- $project_ids = $this->projectPermission->getActiveProjectIds($this->userSession->getId());
- $projects = $this->project->getAllByIds($project_ids);
+ $project_ids = $this->projectPermissionModel->getActiveProjectIds($this->userSession->getId());
+ $projects = $this->projectModel->getAllByIds($project_ids);
return $this->formatProjects($projects);
}
diff --git a/app/Api/Middleware/AuthenticationApiMiddleware.php b/app/Api/Middleware/AuthenticationApiMiddleware.php
new file mode 100644
index 00000000..5f63e1a1
--- /dev/null
+++ b/app/Api/Middleware/AuthenticationApiMiddleware.php
@@ -0,0 +1,130 @@
+<?php
+
+namespace Kanboard\Api\Middleware;
+
+use JsonRPC\Exception\AccessDeniedException;
+use JsonRPC\Exception\AuthenticationFailureException;
+use JsonRPC\MiddlewareInterface;
+use Kanboard\Core\Base;
+
+/**
+ * Class AuthenticationApiMiddleware
+ *
+ * @package Kanboard\Api\Middleware
+ * @author Frederic Guillot
+ */
+class AuthenticationApiMiddleware extends Base implements MiddlewareInterface
+{
+ private $user_allowed_procedures = array(
+ 'getMe',
+ 'getMyDashboard',
+ 'getMyActivityStream',
+ 'createMyPrivateProject',
+ 'getMyProjectsList',
+ 'getMyProjects',
+ 'getMyOverdueTasks',
+ );
+
+ private $both_allowed_procedures = array(
+ 'getTimezone',
+ 'getVersion',
+ 'getDefaultTaskColor',
+ 'getDefaultTaskColors',
+ 'getColorList',
+ 'getProjectById',
+ 'getTask',
+ 'getTaskByReference',
+ 'getAllTasks',
+ 'openTask',
+ 'closeTask',
+ 'moveTaskPosition',
+ 'createTask',
+ 'updateTask',
+ 'getBoard',
+ 'getProjectActivity',
+ 'getOverdueTasksByProject',
+ 'searchTasks',
+ );
+
+ /**
+ * Execute Middleware
+ *
+ * @access public
+ * @param string $username
+ * @param string $password
+ * @param string $procedureName
+ * @throws AccessDeniedException
+ * @throws AuthenticationFailureException
+ */
+ public function execute($username, $password, $procedureName)
+ {
+ $this->dispatcher->dispatch('app.bootstrap');
+
+ if ($this->isUserAuthenticated($username, $password)) {
+ $this->checkProcedurePermission(true, $procedureName);
+ $this->userSession->initialize($this->userModel->getByUsername($username));
+ } elseif ($this->isAppAuthenticated($username, $password)) {
+ $this->checkProcedurePermission(false, $procedureName);
+ } else {
+ $this->logger->error('API authentication failure for '.$username);
+ throw new AuthenticationFailureException('Wrong credentials');
+ }
+ }
+
+ /**
+ * Check user credentials
+ *
+ * @access public
+ * @param string $username
+ * @param string $password
+ * @return boolean
+ */
+ private function isUserAuthenticated($username, $password)
+ {
+ return $username !== 'jsonrpc' &&
+ ! $this->userLockingModel->isLocked($username) &&
+ $this->authenticationManager->passwordAuthentication($username, $password);
+ }
+
+ /**
+ * Check administrative credentials
+ *
+ * @access public
+ * @param string $username
+ * @param string $password
+ * @return boolean
+ */
+ private function isAppAuthenticated($username, $password)
+ {
+ return $username === 'jsonrpc' && $password === $this->getApiToken();
+ }
+
+ /**
+ * Get API Token
+ *
+ * @access private
+ * @return string
+ */
+ private function getApiToken()
+ {
+ if (defined('API_AUTHENTICATION_TOKEN')) {
+ return API_AUTHENTICATION_TOKEN;
+ }
+
+ return $this->configModel->get('api_token');
+ }
+
+ public function checkProcedurePermission($is_user, $procedure)
+ {
+ $is_both_procedure = in_array($procedure, $this->both_allowed_procedures);
+ $is_user_procedure = in_array($procedure, $this->user_allowed_procedures);
+
+ if ($is_user && ! $is_both_procedure && ! $is_user_procedure) {
+ throw new AccessDeniedException('Permission denied');
+ } elseif (! $is_user && ! $is_both_procedure && $is_user_procedure) {
+ throw new AccessDeniedException('Permission denied');
+ }
+
+ $this->logger->debug('API call: '.$procedure);
+ }
+}
diff --git a/app/Api/Project.php b/app/Api/ProjectApi.php
index 846d7046..29a9cd79 100644
--- a/app/Api/Project.php
+++ b/app/Api/ProjectApi.php
@@ -5,50 +5,50 @@ namespace Kanboard\Api;
/**
* Project API controller
*
- * @package api
+ * @package Kanboard\Api
* @author Frederic Guillot
*/
-class Project extends Base
+class ProjectApi extends BaseApi
{
public function getProjectById($project_id)
{
$this->checkProjectPermission($project_id);
- return $this->formatProject($this->project->getById($project_id));
+ return $this->formatProject($this->projectModel->getById($project_id));
}
public function getProjectByName($name)
{
- return $this->formatProject($this->project->getByName($name));
+ return $this->formatProject($this->projectModel->getByName($name));
}
public function getAllProjects()
{
- return $this->formatProjects($this->project->getAll());
+ return $this->formatProjects($this->projectModel->getAll());
}
public function removeProject($project_id)
{
- return $this->project->remove($project_id);
+ return $this->projectModel->remove($project_id);
}
public function enableProject($project_id)
{
- return $this->project->enable($project_id);
+ return $this->projectModel->enable($project_id);
}
public function disableProject($project_id)
{
- return $this->project->disable($project_id);
+ return $this->projectModel->disable($project_id);
}
public function enableProjectPublicAccess($project_id)
{
- return $this->project->enablePublicAccess($project_id);
+ return $this->projectModel->enablePublicAccess($project_id);
}
public function disableProjectPublicAccess($project_id)
{
- return $this->project->disablePublicAccess($project_id);
+ return $this->projectModel->disablePublicAccess($project_id);
}
public function getProjectActivities(array $project_ids)
@@ -70,7 +70,7 @@ class Project extends Base
);
list($valid, ) = $this->projectValidator->validateCreation($values);
- return $valid ? $this->project->create($values) : false;
+ return $valid ? $this->projectModel->create($values) : false;
}
public function updateProject($id, $name, $description = null)
@@ -82,6 +82,6 @@ class Project extends Base
);
list($valid, ) = $this->projectValidator->validateModification($values);
- return $valid && $this->project->update($values);
+ return $valid && $this->projectModel->update($values);
}
}
diff --git a/app/Api/ProjectPermission.php b/app/Api/ProjectPermissionApi.php
index 11e92af0..703cd0f3 100644
--- a/app/Api/ProjectPermission.php
+++ b/app/Api/ProjectPermissionApi.php
@@ -2,54 +2,55 @@
namespace Kanboard\Api;
+use Kanboard\Core\Base;
use Kanboard\Core\Security\Role;
/**
* Project Permission API controller
*
- * @package api
+ * @package Kanboard\Api
* @author Frederic Guillot
*/
-class ProjectPermission extends \Kanboard\Core\Base
+class ProjectPermissionApi extends Base
{
public function getProjectUsers($project_id)
{
- return $this->projectUserRole->getAllUsers($project_id);
+ return $this->projectUserRoleModel->getAllUsers($project_id);
}
public function getAssignableUsers($project_id, $prepend_unassigned = false)
{
- return $this->projectUserRole->getAssignableUsersList($project_id, $prepend_unassigned);
+ return $this->projectUserRoleModel->getAssignableUsersList($project_id, $prepend_unassigned);
}
public function addProjectUser($project_id, $user_id, $role = Role::PROJECT_MEMBER)
{
- return $this->projectUserRole->addUser($project_id, $user_id, $role);
+ return $this->projectUserRoleModel->addUser($project_id, $user_id, $role);
}
public function addProjectGroup($project_id, $group_id, $role = Role::PROJECT_MEMBER)
{
- return $this->projectGroupRole->addGroup($project_id, $group_id, $role);
+ return $this->projectGroupRoleModel->addGroup($project_id, $group_id, $role);
}
public function removeProjectUser($project_id, $user_id)
{
- return $this->projectUserRole->removeUser($project_id, $user_id);
+ return $this->projectUserRoleModel->removeUser($project_id, $user_id);
}
public function removeProjectGroup($project_id, $group_id)
{
- return $this->projectGroupRole->removeGroup($project_id, $group_id);
+ return $this->projectGroupRoleModel->removeGroup($project_id, $group_id);
}
public function changeProjectUserRole($project_id, $user_id, $role)
{
- return $this->projectUserRole->changeUserRole($project_id, $user_id, $role);
+ return $this->projectUserRoleModel->changeUserRole($project_id, $user_id, $role);
}
public function changeProjectGroupRole($project_id, $group_id, $role)
{
- return $this->projectGroupRole->changeGroupRole($project_id, $group_id, $role);
+ return $this->projectGroupRoleModel->changeGroupRole($project_id, $group_id, $role);
}
// Deprecated
diff --git a/app/Api/Subtask.php b/app/Api/SubtaskApi.php
index 782fdb02..5764ff7d 100644
--- a/app/Api/Subtask.php
+++ b/app/Api/SubtaskApi.php
@@ -2,27 +2,29 @@
namespace Kanboard\Api;
+use Kanboard\Core\Base;
+
/**
* Subtask API controller
*
- * @package api
+ * @package Kanboard\Api
* @author Frederic Guillot
*/
-class Subtask extends \Kanboard\Core\Base
+class SubtaskApi extends Base
{
public function getSubtask($subtask_id)
{
- return $this->subtask->getById($subtask_id);
+ return $this->subtaskModel->getById($subtask_id);
}
public function getAllSubtasks($task_id)
{
- return $this->subtask->getAll($task_id);
+ return $this->subtaskModel->getAll($task_id);
}
public function removeSubtask($subtask_id)
{
- return $this->subtask->remove($subtask_id);
+ return $this->subtaskModel->remove($subtask_id);
}
public function createSubtask($task_id, $title, $user_id = 0, $time_estimated = 0, $time_spent = 0, $status = 0)
@@ -37,7 +39,7 @@ class Subtask extends \Kanboard\Core\Base
);
list($valid, ) = $this->subtaskValidator->validateCreation($values);
- return $valid ? $this->subtask->create($values) : false;
+ return $valid ? $this->subtaskModel->create($values) : false;
}
public function updateSubtask($id, $task_id, $title = null, $user_id = null, $time_estimated = null, $time_spent = null, $status = null)
@@ -59,6 +61,6 @@ class Subtask extends \Kanboard\Core\Base
}
list($valid, ) = $this->subtaskValidator->validateApiModification($values);
- return $valid && $this->subtask->update($values);
+ return $valid && $this->subtaskModel->update($values);
}
}
diff --git a/app/Api/Swimlane.php b/app/Api/SwimlaneApi.php
index 03a2819f..c3c56a71 100644
--- a/app/Api/Swimlane.php
+++ b/app/Api/SwimlaneApi.php
@@ -2,47 +2,49 @@
namespace Kanboard\Api;
+use Kanboard\Core\Base;
+
/**
* Swimlane API controller
*
- * @package api
+ * @package Kanboard\Api
* @author Frederic Guillot
*/
-class Swimlane extends \Kanboard\Core\Base
+class SwimlaneApi extends Base
{
public function getActiveSwimlanes($project_id)
{
- return $this->swimlane->getSwimlanes($project_id);
+ return $this->swimlaneModel->getSwimlanes($project_id);
}
public function getAllSwimlanes($project_id)
{
- return $this->swimlane->getAll($project_id);
+ return $this->swimlaneModel->getAll($project_id);
}
public function getSwimlaneById($swimlane_id)
{
- return $this->swimlane->getById($swimlane_id);
+ return $this->swimlaneModel->getById($swimlane_id);
}
public function getSwimlaneByName($project_id, $name)
{
- return $this->swimlane->getByName($project_id, $name);
+ return $this->swimlaneModel->getByName($project_id, $name);
}
public function getSwimlane($swimlane_id)
{
- return $this->swimlane->getById($swimlane_id);
+ return $this->swimlaneModel->getById($swimlane_id);
}
public function getDefaultSwimlane($project_id)
{
- return $this->swimlane->getDefault($project_id);
+ return $this->swimlaneModel->getDefault($project_id);
}
public function addSwimlane($project_id, $name, $description = '')
{
- return $this->swimlane->create(array('project_id' => $project_id, 'name' => $name, 'description' => $description));
+ return $this->swimlaneModel->create(array('project_id' => $project_id, 'name' => $name, 'description' => $description));
}
public function updateSwimlane($swimlane_id, $name, $description = null)
@@ -53,26 +55,26 @@ class Swimlane extends \Kanboard\Core\Base
$values['description'] = $description;
}
- return $this->swimlane->update($values);
+ return $this->swimlaneModel->update($values);
}
public function removeSwimlane($project_id, $swimlane_id)
{
- return $this->swimlane->remove($project_id, $swimlane_id);
+ return $this->swimlaneModel->remove($project_id, $swimlane_id);
}
public function disableSwimlane($project_id, $swimlane_id)
{
- return $this->swimlane->disable($project_id, $swimlane_id);
+ return $this->swimlaneModel->disable($project_id, $swimlane_id);
}
public function enableSwimlane($project_id, $swimlane_id)
{
- return $this->swimlane->enable($project_id, $swimlane_id);
+ return $this->swimlaneModel->enable($project_id, $swimlane_id);
}
public function changeSwimlanePosition($project_id, $swimlane_id, $position)
{
- return $this->swimlane->changePosition($project_id, $swimlane_id, $position);
+ return $this->swimlaneModel->changePosition($project_id, $swimlane_id, $position);
}
}
diff --git a/app/Api/Task.php b/app/Api/TaskApi.php
index 1d1211f2..ddb3ac54 100644
--- a/app/Api/Task.php
+++ b/app/Api/TaskApi.php
@@ -3,15 +3,15 @@
namespace Kanboard\Api;
use Kanboard\Filter\TaskProjectFilter;
-use Kanboard\Model\Task as TaskModel;
+use Kanboard\Model\TaskModel;
/**
* Task API controller
*
- * @package api
+ * @package Kanboard\Api
* @author Frederic Guillot
*/
-class Task extends Base
+class TaskApi extends BaseApi
{
public function searchTasks($project_id, $query)
{
@@ -22,63 +22,63 @@ class Task extends Base
public function getTask($task_id)
{
$this->checkTaskPermission($task_id);
- return $this->formatTask($this->taskFinder->getById($task_id));
+ return $this->formatTask($this->taskFinderModel->getById($task_id));
}
public function getTaskByReference($project_id, $reference)
{
$this->checkProjectPermission($project_id);
- return $this->formatTask($this->taskFinder->getByReference($project_id, $reference));
+ return $this->formatTask($this->taskFinderModel->getByReference($project_id, $reference));
}
public function getAllTasks($project_id, $status_id = TaskModel::STATUS_OPEN)
{
$this->checkProjectPermission($project_id);
- return $this->formatTasks($this->taskFinder->getAll($project_id, $status_id));
+ return $this->formatTasks($this->taskFinderModel->getAll($project_id, $status_id));
}
public function getOverdueTasks()
{
- return $this->taskFinder->getOverdueTasks();
+ return $this->taskFinderModel->getOverdueTasks();
}
public function getOverdueTasksByProject($project_id)
{
$this->checkProjectPermission($project_id);
- return $this->taskFinder->getOverdueTasksByProject($project_id);
+ return $this->taskFinderModel->getOverdueTasksByProject($project_id);
}
public function openTask($task_id)
{
$this->checkTaskPermission($task_id);
- return $this->taskStatus->open($task_id);
+ return $this->taskStatusModel->open($task_id);
}
public function closeTask($task_id)
{
$this->checkTaskPermission($task_id);
- return $this->taskStatus->close($task_id);
+ return $this->taskStatusModel->close($task_id);
}
public function removeTask($task_id)
{
- return $this->task->remove($task_id);
+ return $this->taskModel->remove($task_id);
}
public function moveTaskPosition($project_id, $task_id, $column_id, $position, $swimlane_id = 0)
{
$this->checkProjectPermission($project_id);
- return $this->taskPosition->movePosition($project_id, $task_id, $column_id, $position, $swimlane_id);
+ return $this->taskPositionModel->movePosition($project_id, $task_id, $column_id, $position, $swimlane_id);
}
public function moveTaskToProject($task_id, $project_id, $swimlane_id = null, $column_id = null, $category_id = null, $owner_id = null)
{
- return $this->taskDuplication->moveToProject($task_id, $project_id, $swimlane_id, $column_id, $category_id, $owner_id);
+ return $this->taskDuplicationModel->moveToProject($task_id, $project_id, $swimlane_id, $column_id, $category_id, $owner_id);
}
public function duplicateTaskToProject($task_id, $project_id, $swimlane_id = null, $column_id = null, $category_id = null, $owner_id = null)
{
- return $this->taskDuplication->duplicateToProject($task_id, $project_id, $swimlane_id, $column_id, $category_id, $owner_id);
+ return $this->taskDuplicationModel->duplicateToProject($task_id, $project_id, $swimlane_id, $column_id, $category_id, $owner_id);
}
public function createTask($title, $project_id, $color_id = '', $column_id = 0, $owner_id = 0, $creator_id = 0,
@@ -88,7 +88,7 @@ class Task extends Base
{
$this->checkProjectPermission($project_id);
- if ($owner_id !== 0 && ! $this->projectPermission->isAssignable($project_id, $owner_id)) {
+ if ($owner_id !== 0 && ! $this->projectPermissionModel->isAssignable($project_id, $owner_id)) {
return false;
}
@@ -119,7 +119,7 @@ class Task extends Base
list($valid, ) = $this->taskValidator->validateCreation($values);
- return $valid ? $this->taskCreation->create($values) : false;
+ return $valid ? $this->taskCreationModel->create($values) : false;
}
public function updateTask($id, $title = null, $color_id = null, $owner_id = null,
@@ -129,13 +129,13 @@ class Task extends Base
{
$this->checkTaskPermission($id);
- $project_id = $this->taskFinder->getProjectId($id);
+ $project_id = $this->taskFinderModel->getProjectId($id);
if ($project_id === 0) {
return false;
}
- if ($owner_id !== null && $owner_id != 0 && ! $this->projectPermission->isAssignable($project_id, $owner_id)) {
+ if ($owner_id !== null && $owner_id != 0 && ! $this->projectPermissionModel->isAssignable($project_id, $owner_id)) {
return false;
}
@@ -164,6 +164,6 @@ class Task extends Base
}
list($valid) = $this->taskValidator->validateApiModification($values);
- return $valid && $this->taskModification->update($values);
+ return $valid && $this->taskModificationModel->update($values);
}
}
diff --git a/app/Api/TaskLink.php b/app/Api/TaskLinkApi.php
index 47d70d1e..bb809133 100644
--- a/app/Api/TaskLink.php
+++ b/app/Api/TaskLinkApi.php
@@ -2,13 +2,15 @@
namespace Kanboard\Api;
+use Kanboard\Core\Base;
+
/**
* TaskLink API controller
*
- * @package api
+ * @package Kanboard\Api
* @author Frederic Guillot
*/
-class TaskLink extends \Kanboard\Core\Base
+class TaskLinkApi extends Base
{
/**
* Get a task link
@@ -19,7 +21,7 @@ class TaskLink extends \Kanboard\Core\Base
*/
public function getTaskLinkById($task_link_id)
{
- return $this->taskLink->getById($task_link_id);
+ return $this->taskLinkModel->getById($task_link_id);
}
/**
@@ -31,7 +33,7 @@ class TaskLink extends \Kanboard\Core\Base
*/
public function getAllTaskLinks($task_id)
{
- return $this->taskLink->getAll($task_id);
+ return $this->taskLinkModel->getAll($task_id);
}
/**
@@ -45,7 +47,7 @@ class TaskLink extends \Kanboard\Core\Base
*/
public function createTaskLink($task_id, $opposite_task_id, $link_id)
{
- return $this->taskLink->create($task_id, $opposite_task_id, $link_id);
+ return $this->taskLinkModel->create($task_id, $opposite_task_id, $link_id);
}
/**
@@ -60,7 +62,7 @@ class TaskLink extends \Kanboard\Core\Base
*/
public function updateTaskLink($task_link_id, $task_id, $opposite_task_id, $link_id)
{
- return $this->taskLink->update($task_link_id, $task_id, $opposite_task_id, $link_id);
+ return $this->taskLinkModel->update($task_link_id, $task_id, $opposite_task_id, $link_id);
}
/**
@@ -72,6 +74,6 @@ class TaskLink extends \Kanboard\Core\Base
*/
public function removeTaskLink($task_link_id)
{
- return $this->taskLink->remove($task_link_id);
+ return $this->taskLinkModel->remove($task_link_id);
}
}
diff --git a/app/Api/User.php b/app/Api/UserApi.php
index 6ee935a3..88d75527 100644
--- a/app/Api/User.php
+++ b/app/Api/UserApi.php
@@ -2,6 +2,7 @@
namespace Kanboard\Api;
+use Kanboard\Core\Base;
use LogicException;
use Kanboard\Core\Security\Role;
use Kanboard\Core\Ldap\Client as LdapClient;
@@ -11,44 +12,44 @@ use Kanboard\Core\Ldap\User as LdapUser;
/**
* User API controller
*
- * @package api
+ * @package Kanboard\Api
* @author Frederic Guillot
*/
-class User extends \Kanboard\Core\Base
+class UserApi extends Base
{
public function getUser($user_id)
{
- return $this->user->getById($user_id);
+ return $this->userModel->getById($user_id);
}
public function getUserByName($username)
{
- return $this->user->getByUsername($username);
+ return $this->userModel->getByUsername($username);
}
public function getAllUsers()
{
- return $this->user->getAll();
+ return $this->userModel->getAll();
}
public function removeUser($user_id)
{
- return $this->user->remove($user_id);
+ return $this->userModel->remove($user_id);
}
public function disableUser($user_id)
{
- return $this->user->disable($user_id);
+ return $this->userModel->disable($user_id);
}
public function enableUser($user_id)
{
- return $this->user->enable($user_id);
+ return $this->userModel->enable($user_id);
}
public function isActiveUser($user_id)
{
- return $this->user->isActive($user_id);
+ return $this->userModel->isActive($user_id);
}
public function createUser($username, $password, $name = '', $email = '', $role = Role::APP_USER)
@@ -63,7 +64,7 @@ class User extends \Kanboard\Core\Base
);
list($valid, ) = $this->userValidator->validateCreation($values);
- return $valid ? $this->user->create($values) : false;
+ return $valid ? $this->userModel->create($values) : false;
}
/**
@@ -107,7 +108,7 @@ class User extends \Kanboard\Core\Base
'is_ldap_user' => 1,
);
- return $this->user->create($values);
+ return $this->userModel->create($values);
} catch (LdapException $e) {
$this->logger->error($e->getMessage());
@@ -132,6 +133,6 @@ class User extends \Kanboard\Core\Base
}
list($valid, ) = $this->userValidator->validateApiModification($values);
- return $valid && $this->user->update($values);
+ return $valid && $this->userModel->update($values);
}
}
diff --git a/app/Auth/DatabaseAuth.php b/app/Auth/DatabaseAuth.php
index c13af687..ecb42c17 100644
--- a/app/Auth/DatabaseAuth.php
+++ b/app/Auth/DatabaseAuth.php
@@ -5,7 +5,7 @@ namespace Kanboard\Auth;
use Kanboard\Core\Base;
use Kanboard\Core\Security\PasswordAuthenticationProviderInterface;
use Kanboard\Core\Security\SessionCheckProviderInterface;
-use Kanboard\Model\User;
+use Kanboard\Model\UserModel;
use Kanboard\User\DatabaseUserProvider;
/**
@@ -60,7 +60,7 @@ class DatabaseAuth extends Base implements PasswordAuthenticationProviderInterfa
public function authenticate()
{
$user = $this->db
- ->table(User::TABLE)
+ ->table(UserModel::TABLE)
->columns('id', 'password')
->eq('username', $this->username)
->eq('disable_login_form', 0)
@@ -84,7 +84,7 @@ class DatabaseAuth extends Base implements PasswordAuthenticationProviderInterfa
*/
public function isValidSession()
{
- return $this->user->isActive($this->userSession->getId());
+ return $this->userModel->isActive($this->userSession->getId());
}
/**
diff --git a/app/Auth/LdapAuth.php b/app/Auth/LdapAuth.php
index c9423580..a8dcfcb6 100644
--- a/app/Auth/LdapAuth.php
+++ b/app/Auth/LdapAuth.php
@@ -76,7 +76,7 @@ class LdapAuth extends Base implements PasswordAuthenticationProviderInterface
throw new LogicException('Username not found in LDAP profile, check the parameter LDAP_USER_ATTRIBUTE_USERNAME');
}
- $this->logger->info('Authenticate user: '.$user->getDn());
+ $this->logger->info('Authenticate this user: '.$user->getDn());
if ($client->authenticate($user->getDn(), $this->password)) {
$this->userInfo = $user;
diff --git a/app/Auth/RememberMeAuth.php b/app/Auth/RememberMeAuth.php
index 509a511d..5d0a8b2e 100644
--- a/app/Auth/RememberMeAuth.php
+++ b/app/Auth/RememberMeAuth.php
@@ -44,16 +44,16 @@ class RememberMeAuth extends Base implements PreAuthenticationProviderInterface
$credentials = $this->rememberMeCookie->read();
if ($credentials !== false) {
- $session = $this->rememberMeSession->find($credentials['token'], $credentials['sequence']);
+ $session = $this->rememberMeSessionModel->find($credentials['token'], $credentials['sequence']);
if (! empty($session)) {
$this->rememberMeCookie->write(
$session['token'],
- $this->rememberMeSession->updateSequence($session['token']),
+ $this->rememberMeSessionModel->updateSequence($session['token']),
$session['expiration']
);
- $this->userInfo = $this->user->getById($session['user_id']);
+ $this->userInfo = $this->userModel->getById($session['user_id']);
return true;
}
diff --git a/app/Console/BaseCommand.php b/app/Console/BaseCommand.php
index 4444ceba..50417071 100644
--- a/app/Console/BaseCommand.php
+++ b/app/Console/BaseCommand.php
@@ -11,22 +11,25 @@ use Symfony\Component\Console\Command\Command;
* @package console
* @author Frederic Guillot
*
- * @property \Kanboard\Validator\PasswordResetValidator $passwordResetValidator
- * @property \Kanboard\Export\SubtaskExport $subtaskExport
- * @property \Kanboard\Export\TaskExport $taskExport
- * @property \Kanboard\Export\TransitionExport $transitionExport
- * @property \Kanboard\Model\Notification $notification
- * @property \Kanboard\Model\Project $project
- * @property \Kanboard\Model\ProjectPermission $projectPermission
- * @property \Kanboard\Model\ProjectDailyColumnStats $projectDailyColumnStats
- * @property \Kanboard\Model\ProjectDailyStats $projectDailyStats
- * @property \Kanboard\Model\Task $task
- * @property \Kanboard\Model\TaskFinder $taskFinder
- * @property \Kanboard\Model\User $user
- * @property \Kanboard\Model\UserNotification $userNotification
- * @property \Kanboard\Model\UserNotificationFilter $userNotificationFilter
- * @property \Kanboard\Model\ProjectUserRole $projectUserRole
- * @property \Symfony\Component\EventDispatcher\EventDispatcher $dispatcher
+ * @property \Kanboard\Validator\PasswordResetValidator $passwordResetValidator
+ * @property \Kanboard\Export\SubtaskExport $subtaskExport
+ * @property \Kanboard\Export\TaskExport $taskExport
+ * @property \Kanboard\Export\TransitionExport $transitionExport
+ * @property \Kanboard\Model\NotificationModel $notificationModel
+ * @property \Kanboard\Model\ProjectModel $projectModel
+ * @property \Kanboard\Model\ProjectPermissionModel $projectPermissionModel
+ * @property \Kanboard\Model\ProjectDailyColumnStatsModel $projectDailyColumnStatsModel
+ * @property \Kanboard\Model\ProjectDailyStatsModel $projectDailyStatsModel
+ * @property \Kanboard\Model\TaskModel $taskModel
+ * @property \Kanboard\Model\TaskFinderModel $taskFinderModel
+ * @property \Kanboard\Model\UserModel $userModel
+ * @property \Kanboard\Model\UserNotificationModel $userNotificationModel
+ * @property \Kanboard\Model\UserNotificationFilterModel $userNotificationFilterModel
+ * @property \Kanboard\Model\ProjectUserRoleModel $projectUserRoleModel
+ * @property \Kanboard\Core\Plugin\Loader $pluginLoader
+ * @property \Kanboard\Core\Http\Client $httpClient
+ * @property \Kanboard\Core\Queue\QueueManager $queueManager
+ * @property \Symfony\Component\EventDispatcher\EventDispatcher $dispatcher
*/
abstract class BaseCommand extends Command
{
diff --git a/app/Console/PluginInstallCommand.php b/app/Console/PluginInstallCommand.php
new file mode 100644
index 00000000..a82f0069
--- /dev/null
+++ b/app/Console/PluginInstallCommand.php
@@ -0,0 +1,36 @@
+<?php
+
+namespace Kanboard\Console;
+
+use Kanboard\Core\Plugin\Installer;
+use Kanboard\Core\Plugin\PluginInstallerException;
+use LogicException;
+use Symfony\Component\Console\Input\InputArgument;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
+
+class PluginInstallCommand extends BaseCommand
+{
+ protected function configure()
+ {
+ $this
+ ->setName('plugin:install')
+ ->setDescription('Install a plugin from a remote Zip archive')
+ ->addArgument('url', InputArgument::REQUIRED, 'Archive URL');
+ }
+
+ protected function execute(InputInterface $input, OutputInterface $output)
+ {
+ if (!Installer::isConfigured()) {
+ throw new LogicException('Kanboard is not configured to install plugins itself');
+ }
+
+ try {
+ $installer = new Installer($this->container);
+ $installer->install($input->getArgument('url'));
+ $output->writeln('<info>Plugin installed successfully</info>');
+ } catch (PluginInstallerException $e) {
+ $output->writeln('<error>'.$e->getMessage().'</error>');
+ }
+ }
+}
diff --git a/app/Console/PluginUninstallCommand.php b/app/Console/PluginUninstallCommand.php
new file mode 100644
index 00000000..48722130
--- /dev/null
+++ b/app/Console/PluginUninstallCommand.php
@@ -0,0 +1,36 @@
+<?php
+
+namespace Kanboard\Console;
+
+use Kanboard\Core\Plugin\Installer;
+use Kanboard\Core\Plugin\PluginInstallerException;
+use LogicException;
+use Symfony\Component\Console\Input\InputArgument;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
+
+class PluginUninstallCommand extends BaseCommand
+{
+ protected function configure()
+ {
+ $this
+ ->setName('plugin:uninstall')
+ ->setDescription('Remove a plugin')
+ ->addArgument('pluginId', InputArgument::REQUIRED, 'Plugin directory name');
+ }
+
+ protected function execute(InputInterface $input, OutputInterface $output)
+ {
+ if (!Installer::isConfigured()) {
+ throw new LogicException('Kanboard is not configured to install plugins itself');
+ }
+
+ try {
+ $installer = new Installer($this->container);
+ $installer->uninstall($input->getArgument('pluginId'));
+ $output->writeln('<info>Plugin removed successfully</info>');
+ } catch (PluginInstallerException $e) {
+ $output->writeln('<error>'.$e->getMessage().'</error>');
+ }
+ }
+}
diff --git a/app/Console/PluginUpgradeCommand.php b/app/Console/PluginUpgradeCommand.php
new file mode 100644
index 00000000..6c66e917
--- /dev/null
+++ b/app/Console/PluginUpgradeCommand.php
@@ -0,0 +1,55 @@
+<?php
+
+namespace Kanboard\Console;
+
+use Kanboard\Core\Plugin\Base as BasePlugin;
+use Kanboard\Core\Plugin\Directory;
+use Kanboard\Core\Plugin\Installer;
+use LogicException;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
+
+class PluginUpgradeCommand extends BaseCommand
+{
+ protected function configure()
+ {
+ $this
+ ->setName('plugin:upgrade')
+ ->setDescription('Update all installed plugins')
+ ;
+ }
+
+ protected function execute(InputInterface $input, OutputInterface $output)
+ {
+ if (!Installer::isConfigured()) {
+ throw new LogicException('Kanboard is not configured to install plugins itself');
+ }
+
+ $installer = new Installer($this->container);
+ $availablePlugins = Directory::getInstance($this->container)->getAvailablePlugins();
+
+ foreach ($this->pluginLoader->getPlugins() as $installedPlugin) {
+ $pluginDetails = $this->getPluginDetails($availablePlugins, $installedPlugin);
+
+ if ($pluginDetails === null) {
+ $output->writeln('<error>* Plugin not available in the directory: '.$installedPlugin->getPluginName().'</error>');
+ } elseif ($pluginDetails['version'] > $installedPlugin->getPluginVersion()) {
+ $output->writeln('<comment>* Updating plugin: '.$installedPlugin->getPluginName().'</comment>');
+ $installer->update($pluginDetails['download']);
+ } else {
+ $output->writeln('<info>* Plugin up to date: '.$installedPlugin->getPluginName().'</info>');
+ }
+ }
+ }
+
+ protected function getPluginDetails(array $availablePlugins, BasePlugin $installedPlugin)
+ {
+ foreach ($availablePlugins as $availablePlugin) {
+ if ($availablePlugin['title'] === $installedPlugin->getPluginName()) {
+ return $availablePlugin;
+ }
+ }
+
+ return null;
+ }
+}
diff --git a/app/Console/ProjectDailyColumnStatsExportCommand.php b/app/Console/ProjectDailyColumnStatsExportCommand.php
index ced1a374..1e8af727 100644
--- a/app/Console/ProjectDailyColumnStatsExportCommand.php
+++ b/app/Console/ProjectDailyColumnStatsExportCommand.php
@@ -21,7 +21,7 @@ class ProjectDailyColumnStatsExportCommand extends BaseCommand
protected function execute(InputInterface $input, OutputInterface $output)
{
- $data = $this->projectDailyColumnStats->getAggregatedMetrics(
+ $data = $this->projectDailyColumnStatsModel->getAggregatedMetrics(
$input->getArgument('project_id'),
$input->getArgument('start_date'),
$input->getArgument('end_date')
diff --git a/app/Console/ProjectDailyStatsCalculationCommand.php b/app/Console/ProjectDailyStatsCalculationCommand.php
index 5b898f02..8dde8a79 100644
--- a/app/Console/ProjectDailyStatsCalculationCommand.php
+++ b/app/Console/ProjectDailyStatsCalculationCommand.php
@@ -2,7 +2,7 @@
namespace Kanboard\Console;
-use Kanboard\Model\Project;
+use Kanboard\Model\ProjectModel;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
@@ -17,12 +17,12 @@ class ProjectDailyStatsCalculationCommand extends BaseCommand
protected function execute(InputInterface $input, OutputInterface $output)
{
- $projects = $this->project->getAllByStatus(Project::ACTIVE);
+ $projects = $this->projectModel->getAllByStatus(ProjectModel::ACTIVE);
foreach ($projects as $project) {
$output->writeln('Run calculation for '.$project['name']);
- $this->projectDailyColumnStats->updateTotals($project['id'], date('Y-m-d'));
- $this->projectDailyStats->updateTotals($project['id'], date('Y-m-d'));
+ $this->projectDailyColumnStatsModel->updateTotals($project['id'], date('Y-m-d'));
+ $this->projectDailyStatsModel->updateTotals($project['id'], date('Y-m-d'));
}
}
}
diff --git a/app/Console/ResetPasswordCommand.php b/app/Console/ResetPasswordCommand.php
index 93dc3761..b483f902 100644
--- a/app/Console/ResetPasswordCommand.php
+++ b/app/Console/ResetPasswordCommand.php
@@ -60,14 +60,14 @@ class ResetPasswordCommand extends BaseCommand
private function resetPassword(OutputInterface $output, $username, $password)
{
- $userId = $this->user->getIdByUsername($username);
+ $userId = $this->userModel->getIdByUsername($username);
if (empty($userId)) {
$output->writeln('<error>User not found</error>');
return false;
}
- if (!$this->user->update(array('id' => $userId, 'password' => $password))) {
+ if (!$this->userModel->update(array('id' => $userId, 'password' => $password))) {
$output->writeln('<error>Unable to update password</error>');
return false;
}
diff --git a/app/Console/ResetTwoFactorCommand.php b/app/Console/ResetTwoFactorCommand.php
index 3bf01e81..a64206b6 100644
--- a/app/Console/ResetTwoFactorCommand.php
+++ b/app/Console/ResetTwoFactorCommand.php
@@ -19,14 +19,14 @@ class ResetTwoFactorCommand extends BaseCommand
protected function execute(InputInterface $input, OutputInterface $output)
{
$username = $input->getArgument('username');
- $userId = $this->user->getIdByUsername($username);
+ $userId = $this->userModel->getIdByUsername($username);
if (empty($userId)) {
$output->writeln('<error>User not found</error>');
return false;
}
- if (!$this->user->update(array('id' => $userId, 'twofactor_activated' => 0, 'twofactor_secret' => ''))) {
+ if (!$this->userModel->update(array('id' => $userId, 'twofactor_activated' => 0, 'twofactor_secret' => ''))) {
$output->writeln('<error>Unable to update user profile</error>');
return false;
}
diff --git a/app/Console/TaskOverdueNotificationCommand.php b/app/Console/TaskOverdueNotificationCommand.php
index 7e8484c8..225a6a1a 100644
--- a/app/Console/TaskOverdueNotificationCommand.php
+++ b/app/Console/TaskOverdueNotificationCommand.php
@@ -2,7 +2,7 @@
namespace Kanboard\Console;
-use Kanboard\Model\Task;
+use Kanboard\Model\TaskModel;
use Kanboard\Core\Security\Role;
use Symfony\Component\Console\Helper\Table;
use Symfony\Component\Console\Input\InputInterface;
@@ -65,10 +65,10 @@ class TaskOverdueNotificationCommand extends BaseCommand
*/
public function sendGroupOverdueTaskNotifications()
{
- $tasks = $this->taskFinder->getOverdueTasks();
+ $tasks = $this->taskFinderModel->getOverdueTasks();
foreach ($this->groupByColumn($tasks, 'owner_id') as $user_tasks) {
- $users = $this->userNotification->getUsersWithNotificationEnabled($user_tasks[0]['project_id']);
+ $users = $this->userNotificationModel->getUsersWithNotificationEnabled($user_tasks[0]['project_id']);
foreach ($users as $user) {
$this->sendUserOverdueTaskNotifications($user, $user_tasks);
@@ -85,14 +85,14 @@ class TaskOverdueNotificationCommand extends BaseCommand
*/
public function sendOverdueTaskNotificationsToManagers()
{
- $tasks = $this->taskFinder->getOverdueTasks();
+ $tasks = $this->taskFinderModel->getOverdueTasks();
foreach ($this->groupByColumn($tasks, 'project_id') as $project_id => $project_tasks) {
- $users = $this->userNotification->getUsersWithNotificationEnabled($project_id);
+ $users = $this->userNotificationModel->getUsersWithNotificationEnabled($project_id);
$managers = array();
foreach ($users as $user) {
- $role = $this->projectUserRole->getUserRole($project_id, $user['id']);
+ $role = $this->projectUserRoleModel->getUserRole($project_id, $user['id']);
if($role == Role::PROJECT_MANAGER) {
$managers[] = $user;
}
@@ -113,10 +113,10 @@ class TaskOverdueNotificationCommand extends BaseCommand
*/
public function sendOverdueTaskNotifications()
{
- $tasks = $this->taskFinder->getOverdueTasks();
+ $tasks = $this->taskFinderModel->getOverdueTasks();
foreach ($this->groupByColumn($tasks, 'project_id') as $project_id => $project_tasks) {
- $users = $this->userNotification->getUsersWithNotificationEnabled($project_id);
+ $users = $this->userNotificationModel->getUsersWithNotificationEnabled($project_id);
foreach ($users as $user) {
$this->sendUserOverdueTaskNotifications($user, $project_tasks);
@@ -139,16 +139,16 @@ class TaskOverdueNotificationCommand extends BaseCommand
$project_names = array();
foreach ($tasks as $task) {
- if ($this->userNotificationFilter->shouldReceiveNotification($user, array('task' => $task))) {
+ if ($this->userNotificationFilterModel->shouldReceiveNotification($user, array('task' => $task))) {
$user_tasks[] = $task;
$project_names[$task['project_id']] = $task['project_name'];
}
}
if (! empty($user_tasks)) {
- $this->userNotification->sendUserNotification(
+ $this->userNotificationModel->sendUserNotification(
$user,
- Task::EVENT_OVERDUE,
+ TaskModel::EVENT_OVERDUE,
array('tasks' => $user_tasks, 'project_name' => implode(", ", $project_names))
);
}
@@ -163,9 +163,9 @@ class TaskOverdueNotificationCommand extends BaseCommand
*/
public function sendUserOverdueTaskNotificationsToManagers(array $manager, array $tasks)
{
- $this->userNotification->sendUserNotification(
+ $this->userNotificationModel->sendUserNotification(
$manager,
- Task::EVENT_OVERDUE,
+ TaskModel::EVENT_OVERDUE,
array('tasks' => $tasks, 'project_name' => $tasks[0]['project_name'])
);
}
diff --git a/app/Console/TaskTriggerCommand.php b/app/Console/TaskTriggerCommand.php
index 9e9554f9..a1f4dccf 100644
--- a/app/Console/TaskTriggerCommand.php
+++ b/app/Console/TaskTriggerCommand.php
@@ -4,7 +4,7 @@ namespace Kanboard\Console;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
-use Kanboard\Model\Task;
+use Kanboard\Model\TaskModel;
use Kanboard\Event\TaskListEvent;
class TaskTriggerCommand extends BaseCommand
@@ -19,7 +19,7 @@ class TaskTriggerCommand extends BaseCommand
protected function execute(InputInterface $input, OutputInterface $output)
{
foreach ($this->getProjectIds() as $project_id) {
- $tasks = $this->taskFinder->getAll($project_id);
+ $tasks = $this->taskFinderModel->getAll($project_id);
$nb_tasks = count($tasks);
if ($nb_tasks > 0) {
@@ -31,7 +31,7 @@ class TaskTriggerCommand extends BaseCommand
private function getProjectIds()
{
- $listeners = $this->dispatcher->getListeners(Task::EVENT_DAILY_CRONJOB);
+ $listeners = $this->dispatcher->getListeners(TaskModel::EVENT_DAILY_CRONJOB);
$project_ids = array();
foreach ($listeners as $listener) {
@@ -46,6 +46,6 @@ class TaskTriggerCommand extends BaseCommand
$event = new TaskListEvent(array('project_id' => $project_id));
$event->setTasks($tasks);
- $this->dispatcher->dispatch(Task::EVENT_DAILY_CRONJOB, $event);
+ $this->dispatcher->dispatch(TaskModel::EVENT_DAILY_CRONJOB, $event);
}
}
diff --git a/app/Console/WorkerCommand.php b/app/Console/WorkerCommand.php
new file mode 100644
index 00000000..e332624b
--- /dev/null
+++ b/app/Console/WorkerCommand.php
@@ -0,0 +1,28 @@
+<?php
+
+namespace Kanboard\Console;
+
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
+
+/**
+ * Class WorkerCommand
+ *
+ * @package Kanboard\Console
+ * @author Frederic Guillot
+ */
+class WorkerCommand extends BaseCommand
+{
+ protected function configure()
+ {
+ $this
+ ->setName('worker')
+ ->setDescription('Execute queue worker')
+ ;
+ }
+
+ protected function execute(InputInterface $input, OutputInterface $output)
+ {
+ $this->queueManager->listen();
+ }
+}
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').' &gt; '.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').' &gt; '.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').' &gt; '.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').' &gt; '.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').' &gt; '.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').' &gt; '.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').' &gt; '.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').' &gt; '.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);
- }
-
- try {
- $this->objectStorage->output($file['path']);
- } catch (ObjectStorageException $e) {
- $this->logger->error($e->getMessage());
+ $this->response->status(304);
+ } else {
+
+ 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'].' &gt; '.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').' &gt; '.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'].' &gt; '.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'].' &gt; '.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');
- }
-}
diff --git a/app/Core/Action/ActionManager.php b/app/Core/Action/ActionManager.php
index dfa5a140..1dfd820c 100644
--- a/app/Core/Action/ActionManager.php
+++ b/app/Core/Action/ActionManager.php
@@ -121,9 +121,9 @@ class ActionManager extends Base
public function attachEvents()
{
if ($this->userSession->isLogged()) {
- $actions = $this->action->getAllByUser($this->userSession->getId());
+ $actions = $this->actionModel->getAllByUser($this->userSession->getId());
} else {
- $actions = $this->action->getAll();
+ $actions = $this->actionModel->getAll();
}
foreach ($actions as $action) {
diff --git a/app/Core/Base.php b/app/Core/Base.php
index 2b619af5..7b4462e2 100644
--- a/app/Core/Base.php
+++ b/app/Core/Base.php
@@ -10,134 +10,138 @@ use Pimple\Container;
* @package core
* @author Frederic Guillot
*
- * @property \Kanboard\Analytic\TaskDistributionAnalytic $taskDistributionAnalytic
- * @property \Kanboard\Analytic\UserDistributionAnalytic $userDistributionAnalytic
- * @property \Kanboard\Analytic\EstimatedTimeComparisonAnalytic $estimatedTimeComparisonAnalytic
- * @property \Kanboard\Analytic\AverageLeadCycleTimeAnalytic $averageLeadCycleTimeAnalytic
- * @property \Kanboard\Analytic\AverageTimeSpentColumnAnalytic $averageTimeSpentColumnAnalytic
- * @property \Kanboard\Core\Action\ActionManager $actionManager
- * @property \Kanboard\Core\ExternalLink\ExternalLinkManager $externalLinkManager
- * @property \Kanboard\Core\Cache\MemoryCache $memoryCache
- * @property \Kanboard\Core\Event\EventManager $eventManager
- * @property \Kanboard\Core\Group\GroupManager $groupManager
- * @property \Kanboard\Core\Http\Client $httpClient
- * @property \Kanboard\Core\Http\OAuth2 $oauth
- * @property \Kanboard\Core\Http\RememberMeCookie $rememberMeCookie
- * @property \Kanboard\Core\Http\Request $request
- * @property \Kanboard\Core\Http\Response $response
- * @property \Kanboard\Core\Http\Router $router
- * @property \Kanboard\Core\Http\Route $route
- * @property \Kanboard\Core\Mail\Client $emailClient
- * @property \Kanboard\Core\ObjectStorage\ObjectStorageInterface $objectStorage
- * @property \Kanboard\Core\Plugin\Hook $hook
- * @property \Kanboard\Core\Plugin\Loader $pluginLoader
- * @property \Kanboard\Core\Security\AuthenticationManager $authenticationManager
- * @property \Kanboard\Core\Security\AccessMap $applicationAccessMap
- * @property \Kanboard\Core\Security\AccessMap $projectAccessMap
- * @property \Kanboard\Core\Security\Authorization $applicationAuthorization
- * @property \Kanboard\Core\Security\Authorization $projectAuthorization
- * @property \Kanboard\Core\Security\Role $role
- * @property \Kanboard\Core\Security\Token $token
- * @property \Kanboard\Core\Session\FlashMessage $flash
- * @property \Kanboard\Core\Session\SessionManager $sessionManager
- * @property \Kanboard\Core\Session\SessionStorage $sessionStorage
- * @property \Kanboard\Core\User\Avatar\AvatarManager $avatarManager
- * @property \Kanboard\Core\User\GroupSync $groupSync
- * @property \Kanboard\Core\User\UserProfile $userProfile
- * @property \Kanboard\Core\User\UserSync $userSync
- * @property \Kanboard\Core\User\UserSession $userSession
- * @property \Kanboard\Core\DateParser $dateParser
- * @property \Kanboard\Core\Helper $helper
- * @property \Kanboard\Core\Paginator $paginator
- * @property \Kanboard\Core\Template $template
- * @property \Kanboard\Model\Action $action
- * @property \Kanboard\Model\ActionParameter $actionParameter
- * @property \Kanboard\Model\AvatarFile $avatarFile
- * @property \Kanboard\Model\Board $board
- * @property \Kanboard\Model\Category $category
- * @property \Kanboard\Model\Color $color
- * @property \Kanboard\Model\Column $column
- * @property \Kanboard\Model\Comment $comment
- * @property \Kanboard\Model\Config $config
- * @property \Kanboard\Model\Currency $currency
- * @property \Kanboard\Model\CustomFilter $customFilter
- * @property \Kanboard\Model\TaskFile $taskFile
- * @property \Kanboard\Model\ProjectFile $projectFile
- * @property \Kanboard\Model\Group $group
- * @property \Kanboard\Model\GroupMember $groupMember
- * @property \Kanboard\Model\LastLogin $lastLogin
- * @property \Kanboard\Model\Link $link
- * @property \Kanboard\Model\Notification $notification
- * @property \Kanboard\Model\PasswordReset $passwordReset
- * @property \Kanboard\Model\Project $project
- * @property \Kanboard\Model\ProjectActivity $projectActivity
- * @property \Kanboard\Model\ProjectDuplication $projectDuplication
- * @property \Kanboard\Model\ProjectDailyColumnStats $projectDailyColumnStats
- * @property \Kanboard\Model\ProjectDailyStats $projectDailyStats
- * @property \Kanboard\Model\ProjectMetadata $projectMetadata
- * @property \Kanboard\Model\ProjectPermission $projectPermission
- * @property \Kanboard\Model\ProjectUserRole $projectUserRole
- * @property \Kanboard\Model\ProjectGroupRole $projectGroupRole
- * @property \Kanboard\Model\ProjectNotification $projectNotification
- * @property \Kanboard\Model\ProjectNotificationType $projectNotificationType
- * @property \Kanboard\Model\RememberMeSession $rememberMeSession
- * @property \Kanboard\Model\Subtask $subtask
- * @property \Kanboard\Model\SubtaskTimeTracking $subtaskTimeTracking
- * @property \Kanboard\Model\Swimlane $swimlane
- * @property \Kanboard\Model\Task $task
- * @property \Kanboard\Model\TaskAnalytic $taskAnalytic
- * @property \Kanboard\Model\TaskCreation $taskCreation
- * @property \Kanboard\Model\TaskDuplication $taskDuplication
- * @property \Kanboard\Model\TaskExternalLink $taskExternalLink
- * @property \Kanboard\Model\TaskFinder $taskFinder
- * @property \Kanboard\Model\TaskLink $taskLink
- * @property \Kanboard\Model\TaskModification $taskModification
- * @property \Kanboard\Model\TaskPermission $taskPermission
- * @property \Kanboard\Model\TaskPosition $taskPosition
- * @property \Kanboard\Model\TaskStatus $taskStatus
- * @property \Kanboard\Model\TaskMetadata $taskMetadata
- * @property \Kanboard\Model\Transition $transition
- * @property \Kanboard\Model\User $user
- * @property \Kanboard\Model\UserLocking $userLocking
- * @property \Kanboard\Model\UserMention $userMention
- * @property \Kanboard\Model\UserNotification $userNotification
- * @property \Kanboard\Model\UserNotificationType $userNotificationType
- * @property \Kanboard\Model\UserNotificationFilter $userNotificationFilter
- * @property \Kanboard\Model\UserUnreadNotification $userUnreadNotification
- * @property \Kanboard\Model\UserMetadata $userMetadata
- * @property \Kanboard\Validator\ActionValidator $actionValidator
- * @property \Kanboard\Validator\AuthValidator $authValidator
- * @property \Kanboard\Validator\ColumnValidator $columnValidator
- * @property \Kanboard\Validator\CategoryValidator $categoryValidator
- * @property \Kanboard\Validator\CommentValidator $commentValidator
- * @property \Kanboard\Validator\CurrencyValidator $currencyValidator
- * @property \Kanboard\Validator\CustomFilterValidator $customFilterValidator
- * @property \Kanboard\Validator\GroupValidator $groupValidator
- * @property \Kanboard\Validator\LinkValidator $linkValidator
- * @property \Kanboard\Validator\PasswordResetValidator $passwordResetValidator
- * @property \Kanboard\Validator\ProjectValidator $projectValidator
- * @property \Kanboard\Validator\SubtaskValidator $subtaskValidator
- * @property \Kanboard\Validator\SwimlaneValidator $swimlaneValidator
- * @property \Kanboard\Validator\TaskLinkValidator $taskLinkValidator
- * @property \Kanboard\Validator\ExternalLinkValidator $externalLinkValidator
- * @property \Kanboard\Validator\TaskValidator $taskValidator
- * @property \Kanboard\Validator\UserValidator $userValidator
- * @property \Kanboard\Import\TaskImport $taskImport
- * @property \Kanboard\Import\UserImport $userImport
- * @property \Kanboard\Export\SubtaskExport $subtaskExport
- * @property \Kanboard\Export\TaskExport $taskExport
- * @property \Kanboard\Export\TransitionExport $transitionExport
- * @property \Kanboard\Core\Filter\QueryBuilder $projectGroupRoleQuery
- * @property \Kanboard\Core\Filter\QueryBuilder $projectUserRoleQuery
- * @property \Kanboard\Core\Filter\QueryBuilder $projectActivityQuery
- * @property \Kanboard\Core\Filter\QueryBuilder $userQuery
- * @property \Kanboard\Core\Filter\QueryBuilder $projectQuery
- * @property \Kanboard\Core\Filter\QueryBuilder $taskQuery
- * @property \Kanboard\Core\Filter\LexerBuilder $taskLexer
- * @property \Kanboard\Core\Filter\LexerBuilder $projectActivityLexer
- * @property \Psr\Log\LoggerInterface $logger
- * @property \PicoDb\Database $db
- * @property \Symfony\Component\EventDispatcher\EventDispatcher $dispatcher
+ * @property \Kanboard\Analytic\TaskDistributionAnalytic $taskDistributionAnalytic
+ * @property \Kanboard\Analytic\UserDistributionAnalytic $userDistributionAnalytic
+ * @property \Kanboard\Analytic\EstimatedTimeComparisonAnalytic $estimatedTimeComparisonAnalytic
+ * @property \Kanboard\Analytic\AverageLeadCycleTimeAnalytic $averageLeadCycleTimeAnalytic
+ * @property \Kanboard\Analytic\AverageTimeSpentColumnAnalytic $averageTimeSpentColumnAnalytic
+ * @property \Kanboard\Core\Action\ActionManager $actionManager
+ * @property \Kanboard\Core\ExternalLink\ExternalLinkManager $externalLinkManager
+ * @property \Kanboard\Core\Cache\MemoryCache $memoryCache
+ * @property \Kanboard\Core\Event\EventManager $eventManager
+ * @property \Kanboard\Core\Group\GroupManager $groupManager
+ * @property \Kanboard\Core\Http\Client $httpClient
+ * @property \Kanboard\Core\Http\OAuth2 $oauth
+ * @property \Kanboard\Core\Http\RememberMeCookie $rememberMeCookie
+ * @property \Kanboard\Core\Http\Request $request
+ * @property \Kanboard\Core\Http\Response $response
+ * @property \Kanboard\Core\Http\Router $router
+ * @property \Kanboard\Core\Http\Route $route
+ * @property \Kanboard\Core\Queue\QueueManager $queueManager
+ * @property \Kanboard\Core\Mail\Client $emailClient
+ * @property \Kanboard\Core\ObjectStorage\ObjectStorageInterface $objectStorage
+ * @property \Kanboard\Core\Plugin\Hook $hook
+ * @property \Kanboard\Core\Plugin\Loader $pluginLoader
+ * @property \Kanboard\Core\Security\AuthenticationManager $authenticationManager
+ * @property \Kanboard\Core\Security\AccessMap $applicationAccessMap
+ * @property \Kanboard\Core\Security\AccessMap $projectAccessMap
+ * @property \Kanboard\Core\Security\Authorization $applicationAuthorization
+ * @property \Kanboard\Core\Security\Authorization $projectAuthorization
+ * @property \Kanboard\Core\Security\Role $role
+ * @property \Kanboard\Core\Security\Token $token
+ * @property \Kanboard\Core\Session\FlashMessage $flash
+ * @property \Kanboard\Core\Session\SessionManager $sessionManager
+ * @property \Kanboard\Core\Session\SessionStorage $sessionStorage
+ * @property \Kanboard\Core\User\Avatar\AvatarManager $avatarManager
+ * @property \Kanboard\Core\User\GroupSync $groupSync
+ * @property \Kanboard\Core\User\UserProfile $userProfile
+ * @property \Kanboard\Core\User\UserSync $userSync
+ * @property \Kanboard\Core\User\UserSession $userSession
+ * @property \Kanboard\Core\DateParser $dateParser
+ * @property \Kanboard\Core\Helper $helper
+ * @property \Kanboard\Core\Paginator $paginator
+ * @property \Kanboard\Core\Template $template
+ * @property \Kanboard\Model\ActionModel $actionModel
+ * @property \Kanboard\Model\ActionParameterModel $actionParameterModel
+ * @property \Kanboard\Model\AvatarFileModel $avatarFileModel
+ * @property \Kanboard\Model\BoardModel $boardModel
+ * @property \Kanboard\Model\CategoryModel $categoryModel
+ * @property \Kanboard\Model\ColorModel $colorModel
+ * @property \Kanboard\Model\ColumnModel $columnModel
+ * @property \Kanboard\Model\CommentModel $commentModel
+ * @property \Kanboard\Model\ConfigModel $configModel
+ * @property \Kanboard\Model\CurrencyModel $currencyModel
+ * @property \Kanboard\Model\CustomFilterModel $customFilterModel
+ * @property \Kanboard\Model\TaskFileModel $taskFileModel
+ * @property \Kanboard\Model\ProjectFileModel $projectFileModel
+ * @property \Kanboard\Model\GroupModel $groupModel
+ * @property \Kanboard\Model\GroupMemberModel $groupMemberModel
+ * @property \Kanboard\Model\LanguageModel $languageModel
+ * @property \Kanboard\Model\LastLoginModel $lastLoginModel
+ * @property \Kanboard\Model\LinkModel $linkModel
+ * @property \Kanboard\Model\NotificationModel $notificationModel
+ * @property \Kanboard\Model\PasswordResetModel $passwordResetModel
+ * @property \Kanboard\Model\ProjectModel $projectModel
+ * @property \Kanboard\Model\ProjectActivityModel $projectActivityModel
+ * @property \Kanboard\Model\ProjectDuplicationModel $projectDuplicationModel
+ * @property \Kanboard\Model\ProjectDailyColumnStatsModel $projectDailyColumnStatsModel
+ * @property \Kanboard\Model\ProjectDailyStatsModel $projectDailyStatsModel
+ * @property \Kanboard\Model\ProjectMetadataModel $projectMetadataModel
+ * @property \Kanboard\Model\ProjectPermissionModel $projectPermissionModel
+ * @property \Kanboard\Model\ProjectUserRoleModel $projectUserRoleModel
+ * @property \Kanboard\Model\ProjectGroupRoleModel $projectGroupRoleModel
+ * @property \Kanboard\Model\ProjectNotificationModel $projectNotificationModel
+ * @property \Kanboard\Model\ProjectNotificationTypeModel $projectNotificationTypeModel
+ * @property \Kanboard\Model\RememberMeSessionModel $rememberMeSessionModel
+ * @property \Kanboard\Model\SubtaskModel $subtaskModel
+ * @property \Kanboard\Model\SubtaskTimeTrackingModel $subtaskTimeTrackingModel
+ * @property \Kanboard\Model\SwimlaneModel $swimlaneModel
+ * @property \Kanboard\Model\TaskModel $taskModel
+ * @property \Kanboard\Model\TaskAnalyticModel $taskAnalyticModel
+ * @property \Kanboard\Model\TaskCreationModel $taskCreationModel
+ * @property \Kanboard\Model\TaskDuplicationModel $taskDuplicationModel
+ * @property \Kanboard\Model\TaskExternalLinkModel $taskExternalLinkModel
+ * @property \Kanboard\Model\TaskFinderModel $taskFinderModel
+ * @property \Kanboard\Model\TaskLinkModel $taskLinkModel
+ * @property \Kanboard\Model\TaskModificationModel $taskModificationModel
+ * @property \Kanboard\Model\TaskPositionModel $taskPositionModel
+ * @property \Kanboard\Model\TaskStatusModel $taskStatusModel
+ * @property \Kanboard\Model\TaskMetadataModel $taskMetadataModel
+ * @property \Kanboard\Model\TimezoneModel $timezoneModel
+ * @property \Kanboard\Model\TransitionModel $transitionModel
+ * @property \Kanboard\Model\UserModel $userModel
+ * @property \Kanboard\Model\UserLockingModel $userLockingModel
+ * @property \Kanboard\Model\UserMentionModel $userMentionModel
+ * @property \Kanboard\Model\UserNotificationModel $userNotificationModel
+ * @property \Kanboard\Model\UserNotificationTypeModel $userNotificationTypeModel
+ * @property \Kanboard\Model\UserNotificationFilterModel $userNotificationFilterModel
+ * @property \Kanboard\Model\UserUnreadNotificationModel $userUnreadNotificationModel
+ * @property \Kanboard\Model\UserMetadataModel $userMetadataModel
+ * @property \Kanboard\Validator\ActionValidator $actionValidator
+ * @property \Kanboard\Validator\AuthValidator $authValidator
+ * @property \Kanboard\Validator\ColumnValidator $columnValidator
+ * @property \Kanboard\Validator\CategoryValidator $categoryValidator
+ * @property \Kanboard\Validator\CommentValidator $commentValidator
+ * @property \Kanboard\Validator\CurrencyValidator $currencyValidator
+ * @property \Kanboard\Validator\CustomFilterValidator $customFilterValidator
+ * @property \Kanboard\Validator\GroupValidator $groupValidator
+ * @property \Kanboard\Validator\LinkValidator $linkValidator
+ * @property \Kanboard\Validator\PasswordResetValidator $passwordResetValidator
+ * @property \Kanboard\Validator\ProjectValidator $projectValidator
+ * @property \Kanboard\Validator\SubtaskValidator $subtaskValidator
+ * @property \Kanboard\Validator\SwimlaneValidator $swimlaneValidator
+ * @property \Kanboard\Validator\TaskLinkValidator $taskLinkValidator
+ * @property \Kanboard\Validator\ExternalLinkValidator $externalLinkValidator
+ * @property \Kanboard\Validator\TaskValidator $taskValidator
+ * @property \Kanboard\Validator\UserValidator $userValidator
+ * @property \Kanboard\Import\TaskImport $taskImport
+ * @property \Kanboard\Import\UserImport $userImport
+ * @property \Kanboard\Export\SubtaskExport $subtaskExport
+ * @property \Kanboard\Export\TaskExport $taskExport
+ * @property \Kanboard\Export\TransitionExport $transitionExport
+ * @property \Kanboard\Core\Filter\QueryBuilder $projectGroupRoleQuery
+ * @property \Kanboard\Core\Filter\QueryBuilder $projectUserRoleQuery
+ * @property \Kanboard\Core\Filter\QueryBuilder $projectActivityQuery
+ * @property \Kanboard\Core\Filter\QueryBuilder $userQuery
+ * @property \Kanboard\Core\Filter\QueryBuilder $projectQuery
+ * @property \Kanboard\Core\Filter\QueryBuilder $taskQuery
+ * @property \Kanboard\Core\Filter\LexerBuilder $taskLexer
+ * @property \Kanboard\Core\Filter\LexerBuilder $projectActivityLexer
+ * @property \Psr\Log\LoggerInterface $logger
+ * @property \PicoDb\Database $db
+ * @property \Symfony\Component\EventDispatcher\EventDispatcher $dispatcher
+ * @property \Symfony\Component\Console\Application $cli
+ * @property \JsonRPC\Server $api
*/
abstract class Base
{
diff --git a/app/Core/Controller/AccessForbiddenException.php b/app/Core/Controller/AccessForbiddenException.php
new file mode 100644
index 00000000..b5dccb78
--- /dev/null
+++ b/app/Core/Controller/AccessForbiddenException.php
@@ -0,0 +1,14 @@
+<?php
+
+namespace Kanboard\Core\Controller;
+
+/**
+ * Class AccessForbiddenException
+ *
+ * @package Kanboard\Core\Controller
+ * @author Frederic Guillot
+ */
+class AccessForbiddenException extends BaseException
+{
+
+}
diff --git a/app/Core/Controller/BaseException.php b/app/Core/Controller/BaseException.php
new file mode 100644
index 00000000..13836d2c
--- /dev/null
+++ b/app/Core/Controller/BaseException.php
@@ -0,0 +1,52 @@
+<?php
+
+namespace Kanboard\Core\Controller;
+
+use Exception;
+
+/**
+ * Class AccessForbiddenException
+ *
+ * @package Kanboard\Core\Controller
+ * @author Frederic Guillot
+ */
+class BaseException extends Exception
+{
+ protected $withoutLayout = false;
+
+ /**
+ * Get object instance
+ *
+ * @static
+ * @access public
+ * @param string $message
+ * @return static
+ */
+ public static function getInstance($message = '')
+ {
+ return new static($message);
+ }
+
+ /**
+ * There is no layout
+ *
+ * @access public
+ * @return BaseException
+ */
+ public function withoutLayout()
+ {
+ $this->withoutLayout = true;
+ return $this;
+ }
+
+ /**
+ * Return true if no layout
+ *
+ * @access public
+ * @return boolean
+ */
+ public function hasLayout()
+ {
+ return $this->withoutLayout;
+ }
+}
diff --git a/app/Core/Controller/BaseMiddleware.php b/app/Core/Controller/BaseMiddleware.php
new file mode 100644
index 00000000..e94ad95c
--- /dev/null
+++ b/app/Core/Controller/BaseMiddleware.php
@@ -0,0 +1,58 @@
+<?php
+
+namespace Kanboard\Core\Controller;
+
+use Kanboard\Core\Base;
+
+/**
+ * Class BaseMiddleware
+ *
+ * @package Kanboard\Core\Controller
+ * @author Frederic Guillot
+ */
+abstract class BaseMiddleware extends Base
+{
+ /**
+ * @var BaseMiddleware
+ */
+ protected $nextMiddleware = null;
+
+ /**
+ * Execute middleware
+ */
+ abstract public function execute();
+
+ /**
+ * Set next middleware
+ *
+ * @param BaseMiddleware $nextMiddleware
+ * @return BaseMiddleware
+ */
+ public function setNextMiddleware(BaseMiddleware $nextMiddleware)
+ {
+ $this->nextMiddleware = $nextMiddleware;
+ return $this;
+ }
+
+ /**
+ * @return BaseMiddleware
+ */
+ public function getNextMiddleware()
+ {
+ return $this->nextMiddleware;
+ }
+
+ /**
+ * Move to next middleware
+ */
+ public function next()
+ {
+ if ($this->nextMiddleware !== null) {
+ if (DEBUG) {
+ $this->logger->debug(__METHOD__.' => ' . get_class($this->nextMiddleware));
+ }
+
+ $this->nextMiddleware->execute();
+ }
+ }
+}
diff --git a/app/Core/Controller/PageNotFoundException.php b/app/Core/Controller/PageNotFoundException.php
new file mode 100644
index 00000000..e96a2057
--- /dev/null
+++ b/app/Core/Controller/PageNotFoundException.php
@@ -0,0 +1,14 @@
+<?php
+
+namespace Kanboard\Core\Controller;
+
+/**
+ * Class PageNotFoundException
+ *
+ * @package Kanboard\Core\Controller
+ * @author Frederic Guillot
+ */
+class PageNotFoundException extends BaseException
+{
+
+}
diff --git a/app/Core/Controller/Runner.php b/app/Core/Controller/Runner.php
new file mode 100644
index 00000000..8353cf69
--- /dev/null
+++ b/app/Core/Controller/Runner.php
@@ -0,0 +1,105 @@
+<?php
+
+namespace Kanboard\Core\Controller;
+
+use Kanboard\Controller\AppController;
+use Kanboard\Core\Base;
+use Kanboard\Middleware\ApplicationAuthorizationMiddleware;
+use Kanboard\Middleware\AuthenticationMiddleware;
+use Kanboard\Middleware\BootstrapMiddleware;
+use Kanboard\Middleware\PostAuthenticationMiddleware;
+use Kanboard\Middleware\ProjectAuthorizationMiddleware;
+use RuntimeException;
+
+/**
+ * Class Runner
+ *
+ * @package Kanboard\Core\Controller
+ * @author Frederic Guillot
+ */
+class Runner extends Base
+{
+ /**
+ * Execute middleware and controller
+ */
+ public function execute()
+ {
+ try {
+ $this->executeMiddleware();
+
+ if (!$this->response->isResponseAlreadySent()) {
+ $this->executeController();
+ }
+ } catch (PageNotFoundException $e) {
+ $controllerObject = new AppController($this->container);
+ $controllerObject->notFound($e->hasLayout());
+ } catch (AccessForbiddenException $e) {
+ $controllerObject = new AppController($this->container);
+ $controllerObject->accessForbidden($e->hasLayout());
+ }
+ }
+
+ /**
+ * Execute all middleware
+ */
+ protected function executeMiddleware()
+ {
+ if (DEBUG) {
+ $this->logger->debug(__METHOD__);
+ }
+
+ $bootstrapMiddleware = new BootstrapMiddleware($this->container);
+ $authenticationMiddleware = new AuthenticationMiddleware($this->container);
+ $postAuthenticationMiddleware = new PostAuthenticationMiddleware($this->container);
+ $appAuthorizationMiddleware = new ApplicationAuthorizationMiddleware($this->container);
+ $projectAuthorizationMiddleware = new ProjectAuthorizationMiddleware($this->container);
+
+ $bootstrapMiddleware->setNextMiddleware($authenticationMiddleware);
+ $authenticationMiddleware->setNextMiddleware($postAuthenticationMiddleware);
+ $postAuthenticationMiddleware->setNextMiddleware($appAuthorizationMiddleware);
+ $appAuthorizationMiddleware->setNextMiddleware($projectAuthorizationMiddleware);
+
+ $bootstrapMiddleware->execute();
+ }
+
+ /**
+ * Execute the controller
+ */
+ protected function executeController()
+ {
+ $className = $this->getControllerClassName();
+
+ if (DEBUG) {
+ $this->logger->debug(__METHOD__.' => '.$className.'::'.$this->router->getAction());
+ }
+
+ $controllerObject = new $className($this->container);
+ $controllerObject->{$this->router->getAction()}();
+ }
+
+ /**
+ * Get controller class name
+ *
+ * @access protected
+ * @return string
+ * @throws RuntimeException
+ */
+ protected function getControllerClassName()
+ {
+ if ($this->router->getPlugin() !== '') {
+ $className = '\Kanboard\Plugin\\'.$this->router->getPlugin().'\Controller\\'.$this->router->getController();
+ } else {
+ $className = '\Kanboard\Controller\\'.$this->router->getController();
+ }
+
+ if (! class_exists($className)) {
+ throw new RuntimeException('Controller not found');
+ }
+
+ if (! method_exists($className, $this->router->getAction())) {
+ throw new RuntimeException('Action not implemented');
+ }
+
+ return $className;
+ }
+}
diff --git a/app/Core/Event/EventManager.php b/app/Core/Event/EventManager.php
index 162d23e8..9ae43170 100644
--- a/app/Core/Event/EventManager.php
+++ b/app/Core/Event/EventManager.php
@@ -2,8 +2,8 @@
namespace Kanboard\Core\Event;
-use Kanboard\Model\Task;
-use Kanboard\Model\TaskLink;
+use Kanboard\Model\TaskModel;
+use Kanboard\Model\TaskLinkModel;
/**
* Event Manager
@@ -44,15 +44,15 @@ class EventManager
public function getAll()
{
$events = array(
- TaskLink::EVENT_CREATE_UPDATE => t('Task link creation or modification'),
- Task::EVENT_MOVE_COLUMN => t('Move a task to another column'),
- Task::EVENT_UPDATE => t('Task modification'),
- Task::EVENT_CREATE => t('Task creation'),
- Task::EVENT_OPEN => t('Reopen a task'),
- Task::EVENT_CLOSE => t('Closing a task'),
- Task::EVENT_CREATE_UPDATE => t('Task creation or modification'),
- Task::EVENT_ASSIGNEE_CHANGE => t('Task assignee change'),
- Task::EVENT_DAILY_CRONJOB => t('Daily background job for tasks'),
+ TaskLinkModel::EVENT_CREATE_UPDATE => t('Task link creation or modification'),
+ TaskModel::EVENT_MOVE_COLUMN => t('Move a task to another column'),
+ TaskModel::EVENT_UPDATE => t('Task modification'),
+ TaskModel::EVENT_CREATE => t('Task creation'),
+ TaskModel::EVENT_OPEN => t('Reopen a task'),
+ TaskModel::EVENT_CLOSE => t('Closing a task'),
+ TaskModel::EVENT_CREATE_UPDATE => t('Task creation or modification'),
+ TaskModel::EVENT_ASSIGNEE_CHANGE => t('Task assignee change'),
+ TaskModel::EVENT_DAILY_CRONJOB => t('Daily background job for tasks'),
);
$events = array_merge($events, $this->events);
diff --git a/app/Core/Filter/Lexer.php b/app/Core/Filter/Lexer.php
index 041b58d3..fa5b8d2d 100644
--- a/app/Core/Filter/Lexer.php
+++ b/app/Core/Filter/Lexer.php
@@ -25,12 +25,13 @@ class Lexer
* @var array
*/
private $tokenMap = array(
- "/^(\s+)/" => 'T_WHITESPACE',
- '/^([<=>]{0,2}[0-9]{4}-[0-9]{2}-[0-9]{2})/' => 'T_DATE',
- '/^(yesterday|tomorrow|today)/' => 'T_DATE',
- '/^("(.*?)")/' => 'T_STRING',
- "/^(\w+)/" => 'T_STRING',
- "/^(#\d+)/" => 'T_STRING',
+ '/^(\s+)/' => 'T_WHITESPACE',
+ '/^([<=>]{0,2}[0-9]{4}-[0-9]{2}-[0-9]{2})/' => 'T_STRING',
+ '/^([<=>]{1,2}\w+)/u' => 'T_STRING',
+ '/^([<=>]{1,2}".+")/' => 'T_STRING',
+ '/^("(.+)")/' => 'T_STRING',
+ '/^(\w+)/u' => 'T_STRING',
+ '/^(#\d+)/' => 'T_STRING',
);
/**
@@ -79,9 +80,10 @@ class Lexer
{
$tokens = array();
$this->offset = 0;
+ $input_length = mb_strlen($input, 'UTF-8');
- while (isset($input[$this->offset])) {
- $result = $this->match(substr($input, $this->offset));
+ while ($this->offset < $input_length) {
+ $result = $this->match(mb_substr($input, $this->offset, $input_length, 'UTF-8'));
if ($result === false) {
return array();
@@ -104,10 +106,10 @@ class Lexer
{
foreach ($this->tokenMap as $pattern => $name) {
if (preg_match($pattern, $string, $matches)) {
- $this->offset += strlen($matches[1]);
+ $this->offset += mb_strlen($matches[1], 'UTF-8');
return array(
- 'match' => trim($matches[1], '"'),
+ 'match' => str_replace('"', '', $matches[1]),
'token' => $name,
);
}
@@ -134,7 +136,7 @@ class Lexer
} else {
$next = next($tokens);
- if ($next !== false && in_array($next['token'], array('T_STRING', 'T_DATE'))) {
+ if ($next !== false && $next['token'] === 'T_STRING') {
$map[$token['token']][] = $next['match'];
}
}
diff --git a/app/Core/Helper.php b/app/Core/Helper.php
index 66f8d429..43151be8 100644
--- a/app/Core/Helper.php
+++ b/app/Core/Helper.php
@@ -27,6 +27,7 @@ use Pimple\Container;
* @property \Kanboard\Helper\LayoutHelper $layout
* @property \Kanboard\Helper\ProjectHeaderHelper $projectHeader
* @property \Kanboard\Helper\ProjectActivityHelper $projectActivity
+ * @property \Kanboard\Helper\MailHelper $mail
*/
class Helper
{
@@ -94,7 +95,7 @@ class Helper
{
$container = $this->container;
- $this->helpers[$property] = function() use($className, $container) {
+ $this->helpers[$property] = function() use ($className, $container) {
return new $className($container);
};
diff --git a/app/Core/Http/Response.php b/app/Core/Http/Response.php
index 996fc58d..0f16fb65 100644
--- a/app/Core/Http/Response.php
+++ b/app/Core/Http/Response.php
@@ -13,296 +13,373 @@ use Kanboard\Core\Csv;
*/
class Response extends Base
{
+ private $httpStatusCode = 200;
+ private $httpHeaders = array();
+ private $httpBody = '';
+ private $responseSent = false;
+
/**
- * Send headers to cache a resource
+ * Return true if the response have been sent to the user agent
*
* @access public
- * @param integer $duration
- * @param string $etag
+ * @return bool
*/
- public function cache($duration, $etag = '')
+ public function isResponseAlreadySent()
{
- header('Pragma: cache');
- header('Expires: ' . gmdate('D, d M Y H:i:s', time() + $duration) . ' GMT');
- header('Cache-Control: public, max-age=' . $duration);
-
- if ($etag) {
- header('ETag: "' . $etag . '"');
- }
+ return $this->responseSent;
}
/**
- * Send no cache headers
+ * Set HTTP status code
*
* @access public
+ * @param integer $statusCode
+ * @return $this
*/
- public function nocache()
+ public function withStatusCode($statusCode)
{
- header('Pragma: no-cache');
- header('Expires: Sat, 26 Jul 1997 05:00:00 GMT');
-
- // Use no-store due to a Chrome bug: https://code.google.com/p/chromium/issues/detail?id=28035
- header('Cache-Control: no-store, must-revalidate');
+ $this->httpStatusCode = $statusCode;
+ return $this;
}
/**
- * Send a custom Content-Type header
+ * Set HTTP header
*
* @access public
- * @param string $mimetype Mime-type
+ * @param string $header
+ * @param string $value
+ * @return $this
*/
- public function contentType($mimetype)
+ public function withHeader($header, $value)
{
- header('Content-Type: '.$mimetype);
+ $this->httpHeaders[$header] = $value;
+ return $this;
}
/**
- * Force the browser to download an attachment
+ * Set content type header
*
* @access public
- * @param string $filename File name
+ * @param string $value
+ * @return $this
*/
- public function forceDownload($filename)
+ public function withContentType($value)
{
- header('Content-Disposition: attachment; filename="'.$filename.'"');
- header('Content-Transfer-Encoding: binary');
- header('Content-Type: application/octet-stream');
+ $this->httpHeaders['Content-Type'] = $value;
+ return $this;
}
/**
- * Send a custom HTTP status code
+ * Set default security headers
*
* @access public
- * @param integer $status_code HTTP status code
+ * @return $this
*/
- public function status($status_code)
+ public function withSecurityHeaders()
{
- header('Status: '.$status_code);
- header($this->request->getServerVariable('SERVER_PROTOCOL').' '.$status_code);
+ $this->httpHeaders['X-Content-Type-Options'] = 'nosniff';
+ $this->httpHeaders['X-XSS-Protection'] = '1; mode=block';
+ return $this;
}
/**
- * Redirect to another URL
+ * Set header Content-Security-Policy
*
* @access public
- * @param string $url Redirection URL
- * @param boolean $self If Ajax request and true: refresh the current page
+ * @param array $policies
+ * @return $this
*/
- public function redirect($url, $self = false)
+ public function withContentSecurityPolicy(array $policies = array())
{
- if ($this->request->isAjax()) {
- header('X-Ajax-Redirect: '.($self ? 'self' : $url));
- } else {
- header('Location: '.$url);
+ $values = '';
+
+ foreach ($policies as $policy => $acl) {
+ $values .= $policy.' '.trim($acl).'; ';
}
- exit;
+ $this->withHeader('Content-Security-Policy', $values);
+ return $this;
}
/**
- * Send a CSV response
+ * Set header X-Frame-Options
*
* @access public
- * @param array $data Data to serialize in csv
- * @param integer $status_code HTTP status code
+ * @return $this
*/
- public function csv(array $data, $status_code = 200)
+ public function withXframe()
{
- $this->status($status_code);
- $this->nocache();
+ $this->withHeader('X-Frame-Options', 'DENY');
+ return $this;
+ }
- header('Content-Type: text/csv');
- Csv::output($data);
- exit;
+ /**
+ * Set header Strict-Transport-Security (only if we use HTTPS)
+ *
+ * @access public
+ * @return $this
+ */
+ public function withStrictTransportSecurity()
+ {
+ if ($this->request->isHTTPS()) {
+ $this->withHeader('Strict-Transport-Security', 'max-age=31536000');
+ }
+
+ return $this;
}
/**
- * Send a Json response
+ * Set HTTP response body
*
* @access public
- * @param array $data Data to serialize in json
- * @param integer $status_code HTTP status code
+ * @param string $body
+ * @return $this
*/
- public function json(array $data, $status_code = 200)
+ public function withBody($body)
{
- $this->status($status_code);
- $this->nocache();
- header('Content-Type: application/json');
- echo json_encode($data);
- exit;
+ $this->httpBody = $body;
+ return $this;
}
/**
- * Send a text response
+ * Send headers to cache a resource
*
* @access public
- * @param string $data Raw data
- * @param integer $status_code HTTP status code
+ * @param integer $duration
+ * @param string $etag
+ * @return $this
*/
- public function text($data, $status_code = 200)
+ public function withCache($duration, $etag = '')
{
- $this->status($status_code);
- $this->nocache();
- header('Content-Type: text/plain; charset=utf-8');
- echo $data;
- exit;
+ $this
+ ->withHeader('Pragma', 'cache')
+ ->withHeader('Expires', gmdate('D, d M Y H:i:s', time() + $duration) . ' GMT')
+ ->withHeader('Cache-Control', 'public, max-age=' . $duration)
+ ;
+
+ if ($etag) {
+ $this->withHeader('ETag', '"' . $etag . '"');
+ }
+
+ return $this;
}
/**
- * Send a HTML response
+ * Send no cache headers
*
* @access public
- * @param string $data Raw data
- * @param integer $status_code HTTP status code
+ * @return $this
*/
- public function html($data, $status_code = 200)
+ public function withoutCache()
{
- $this->status($status_code);
- $this->nocache();
- header('Content-Type: text/html; charset=utf-8');
- echo $data;
- exit;
+ $this->withHeader('Pragma', 'no-cache');
+ $this->withHeader('Expires', 'Sat, 26 Jul 1997 05:00:00 GMT');
+ return $this;
}
/**
- * Send a XML response
+ * Force the browser to download an attachment
*
* @access public
- * @param string $data Raw data
- * @param integer $status_code HTTP status code
+ * @param string $filename
+ * @return $this
*/
- public function xml($data, $status_code = 200)
+ public function withFileDownload($filename)
{
- $this->status($status_code);
- $this->nocache();
- header('Content-Type: text/xml; charset=utf-8');
- echo $data;
- exit;
+ $this->withHeader('Content-Disposition', 'attachment; filename="'.$filename.'"');
+ $this->withHeader('Content-Transfer-Encoding', 'binary');
+ $this->withHeader('Content-Type', 'application/octet-stream');
+ return $this;
}
/**
- * Send a javascript response
+ * Send headers and body
*
* @access public
- * @param string $data Raw data
- * @param integer $status_code HTTP status code
*/
- public function js($data, $status_code = 200)
+ public function send()
{
- $this->status($status_code);
+ $this->responseSent = true;
- header('Content-Type: text/javascript; charset=utf-8');
- echo $data;
+ if ($this->httpStatusCode !== 200) {
+ header('Status: '.$this->httpStatusCode);
+ header($this->request->getServerVariable('SERVER_PROTOCOL').' '.$this->httpStatusCode);
+ }
- exit;
+ foreach ($this->httpHeaders as $header => $value) {
+ header($header.': '.$value);
+ }
+
+ if (! empty($this->httpBody)) {
+ echo $this->httpBody;
+ }
}
/**
- * Send a css response
+ * Send a custom HTTP status code
*
* @access public
- * @param string $data Raw data
- * @param integer $status_code HTTP status code
+ * @param integer $statusCode
*/
- public function css($data, $status_code = 200)
+ public function status($statusCode)
{
- $this->status($status_code);
+ $this->withStatusCode($statusCode);
+ $this->send();
+ }
- header('Content-Type: text/css; charset=utf-8');
- echo $data;
+ /**
+ * Redirect to another URL
+ *
+ * @access public
+ * @param string $url Redirection URL
+ * @param boolean $self If Ajax request and true: refresh the current page
+ */
+ public function redirect($url, $self = false)
+ {
+ if ($this->request->isAjax()) {
+ $this->withHeader('X-Ajax-Redirect', $self ? 'self' : $url);
+ } else {
+ $this->withHeader('Location', $url);
+ }
- exit;
+ $this->send();
}
/**
- * Send a binary response
+ * Send a HTML response
*
* @access public
- * @param string $data Raw data
- * @param integer $status_code HTTP status code
+ * @param string $data
+ * @param integer $statusCode
*/
- public function binary($data, $status_code = 200)
+ public function html($data, $statusCode = 200)
{
- $this->status($status_code);
- $this->nocache();
- header('Content-Transfer-Encoding: binary');
- header('Content-Type: application/octet-stream');
- echo $data;
- exit;
+ $this->withStatusCode($statusCode);
+ $this->withContentType('text/html; charset=utf-8');
+ $this->withBody($data);
+ $this->send();
}
/**
- * Send a iCal response
+ * Send a text response
*
* @access public
- * @param string $data Raw data
- * @param integer $status_code HTTP status code
+ * @param string $data
+ * @param integer $statusCode
*/
- public function ical($data, $status_code = 200)
+ public function text($data, $statusCode = 200)
{
- $this->status($status_code);
- $this->contentType('text/calendar; charset=utf-8');
- echo $data;
+ $this->withStatusCode($statusCode);
+ $this->withContentType('text/plain; charset=utf-8');
+ $this->withBody($data);
+ $this->send();
}
/**
- * Send the security header: Content-Security-Policy
+ * Send a CSV response
*
* @access public
- * @param array $policies CSP rules
+ * @param array $data Data to serialize in csv
*/
- public function csp(array $policies = array())
+ public function csv(array $data)
{
- $values = '';
+ $this->withoutCache();
+ $this->withContentType('text/csv; charset=utf-8');
+ $this->send();
+ Csv::output($data);
+ }
- foreach ($policies as $policy => $acl) {
- $values .= $policy.' '.trim($acl).'; ';
- }
+ /**
+ * Send a Json response
+ *
+ * @access public
+ * @param array $data Data to serialize in json
+ * @param integer $statusCode HTTP status code
+ */
+ public function json(array $data, $statusCode = 200)
+ {
+ $this->withStatusCode($statusCode);
+ $this->withContentType('application/json');
+ $this->withoutCache();
+ $this->withBody(json_encode($data));
+ $this->send();
+ }
- header('Content-Security-Policy: '.$values);
+ /**
+ * Send a XML response
+ *
+ * @access public
+ * @param string $data
+ * @param integer $statusCode
+ */
+ public function xml($data, $statusCode = 200)
+ {
+ $this->withStatusCode($statusCode);
+ $this->withContentType('text/xml; charset=utf-8');
+ $this->withoutCache();
+ $this->withBody($data);
+ $this->send();
}
/**
- * Send the security header: X-Content-Type-Options
+ * Send a javascript response
*
* @access public
+ * @param string $data
+ * @param integer $statusCode
*/
- public function nosniff()
+ public function js($data, $statusCode = 200)
{
- header('X-Content-Type-Options: nosniff');
+ $this->withStatusCode($statusCode);
+ $this->withContentType('text/javascript; charset=utf-8');
+ $this->withBody($data);
+ $this->send();
}
/**
- * Send the security header: X-XSS-Protection
+ * Send a css response
*
* @access public
+ * @param string $data
+ * @param integer $statusCode
*/
- public function xss()
+ public function css($data, $statusCode = 200)
{
- header('X-XSS-Protection: 1; mode=block');
+ $this->withStatusCode($statusCode);
+ $this->withContentType('text/css; charset=utf-8');
+ $this->withBody($data);
+ $this->send();
}
/**
- * Send the security header: Strict-Transport-Security (only if we use HTTPS)
+ * Send a binary response
*
* @access public
+ * @param string $data
+ * @param integer $statusCode
*/
- public function hsts()
+ public function binary($data, $statusCode = 200)
{
- if ($this->request->isHTTPS()) {
- header('Strict-Transport-Security: max-age=31536000');
- }
+ $this->withStatusCode($statusCode);
+ $this->withoutCache();
+ $this->withHeader('Content-Transfer-Encoding', 'binary');
+ $this->withContentType('application/octet-stream');
+ $this->withBody($data);
+ $this->send();
}
/**
- * Send the security header: X-Frame-Options (deny by default)
+ * Send a iCal response
*
* @access public
- * @param string $mode Frame option mode
- * @param array $urls Allowed urls for the given mode
+ * @param string $data
+ * @param integer $statusCode
*/
- public function xframe($mode = 'DENY', array $urls = array())
+ public function ical($data, $statusCode = 200)
{
- header('X-Frame-Options: '.$mode.' '.implode(' ', $urls));
+ $this->withStatusCode($statusCode);
+ $this->withContentType('text/calendar; charset=utf-8');
+ $this->withBody($data);
+ $this->send();
}
}
diff --git a/app/Core/Http/Route.php b/app/Core/Http/Route.php
index 7836146d..9b45b725 100644
--- a/app/Core/Http/Route.php
+++ b/app/Core/Http/Route.php
@@ -119,8 +119,8 @@ class Route extends Base
}
return array(
- 'controller' => 'app',
- 'action' => 'index',
+ 'controller' => 'DashboardController',
+ 'action' => 'show',
'plugin' => '',
);
}
diff --git a/app/Core/Http/Router.php b/app/Core/Http/Router.php
index 0fe80ecc..4de276a0 100644
--- a/app/Core/Http/Router.php
+++ b/app/Core/Http/Router.php
@@ -2,7 +2,6 @@
namespace Kanboard\Core\Http;
-use RuntimeException;
use Kanboard\Core\Base;
/**
@@ -13,13 +12,16 @@ use Kanboard\Core\Base;
*/
class Router extends Base
{
+ const DEFAULT_CONTROLLER = 'DashboardController';
+ const DEFAULT_METHOD = 'show';
+
/**
* Plugin name
*
* @access private
* @var string
*/
- private $plugin = '';
+ private $currentPluginName = '';
/**
* Controller
@@ -27,7 +29,7 @@ class Router extends Base
* @access private
* @var string
*/
- private $controller = '';
+ private $currentControllerName = '';
/**
* Action
@@ -35,7 +37,7 @@ class Router extends Base
* @access private
* @var string
*/
- private $action = '';
+ private $currentActionName = '';
/**
* Get plugin name
@@ -45,7 +47,7 @@ class Router extends Base
*/
public function getPlugin()
{
- return $this->plugin;
+ return $this->currentPluginName;
}
/**
@@ -56,7 +58,7 @@ class Router extends Base
*/
public function getController()
{
- return $this->controller;
+ return $this->currentControllerName;
}
/**
@@ -67,7 +69,7 @@ class Router extends Base
*/
public function getAction()
{
- return $this->action;
+ return $this->currentActionName;
}
/**
@@ -109,11 +111,9 @@ class Router extends Base
$plugin = $route['plugin'];
}
- $this->controller = ucfirst($this->sanitize($controller, 'app'));
- $this->action = $this->sanitize($action, 'index');
- $this->plugin = ucfirst($this->sanitize($plugin));
-
- return $this->executeAction();
+ $this->currentControllerName = ucfirst($this->sanitize($controller, self::DEFAULT_CONTROLLER));
+ $this->currentActionName = $this->sanitize($action, self::DEFAULT_METHOD);
+ $this->currentPluginName = ucfirst($this->sanitize($plugin));
}
/**
@@ -128,42 +128,4 @@ class Router extends Base
{
return preg_match('/^[a-zA-Z_0-9]+$/', $value) ? $value : $default;
}
-
- /**
- * Execute controller action
- *
- * @access private
- */
- private function executeAction()
- {
- $class = $this->getControllerClassName();
-
- if (! class_exists($class)) {
- throw new RuntimeException('Controller not found');
- }
-
- if (! method_exists($class, $this->action)) {
- throw new RuntimeException('Action not implemented');
- }
-
- $instance = new $class($this->container);
- $instance->beforeAction();
- $instance->{$this->action}();
- return $instance;
- }
-
- /**
- * Get controller class name
- *
- * @access private
- * @return string
- */
- private function getControllerClassName()
- {
- if ($this->plugin !== '') {
- return '\Kanboard\Plugin\\'.$this->plugin.'\Controller\\'.$this->controller;
- }
-
- return '\Kanboard\Controller\\'.$this->controller;
- }
}
diff --git a/app/Core/Ldap/Group.php b/app/Core/Ldap/Group.php
index 634d47ee..e1f60ab5 100644
--- a/app/Core/Ldap/Group.php
+++ b/app/Core/Ldap/Group.php
@@ -39,12 +39,11 @@ class Group
* @access public
* @param Client $client
* @param string $query
- * @return array
+ * @return LdapGroupProvider[]
*/
public static function getGroups(Client $client, $query)
{
- $className = get_called_class();
- $self = new $className(new Query($client));
+ $self = new static(new Query($client));
return $self->find($query);
}
@@ -111,7 +110,7 @@ class Group
throw new LogicException('LDAP full name attribute empty, check the parameter LDAP_GROUP_ATTRIBUTE_NAME');
}
- return LDAP_GROUP_ATTRIBUTE_NAME;
+ return strtolower(LDAP_GROUP_ATTRIBUTE_NAME);
}
/**
diff --git a/app/Core/Ldap/Query.php b/app/Core/Ldap/Query.php
index 7c1524ca..0f9abb5c 100644
--- a/app/Core/Ldap/Query.php
+++ b/app/Core/Ldap/Query.php
@@ -66,6 +66,10 @@ class Query
$this->entries = $entries;
+ if (DEBUG && $this->client->hasLogger()) {
+ $this->client->getLogger()->debug('NbEntries='.$entries['count']);
+ }
+
return $this;
}
diff --git a/app/Core/Ldap/User.php b/app/Core/Ldap/User.php
index d23ec07e..91b48530 100644
--- a/app/Core/Ldap/User.php
+++ b/app/Core/Ldap/User.php
@@ -23,14 +23,24 @@ class User
protected $query;
/**
+ * LDAP Group object
+ *
+ * @access protected
+ * @var Group
+ */
+ protected $group;
+
+ /**
* Constructor
*
* @access public
- * @param Query $query
+ * @param Query $query
+ * @param Group $group
*/
- public function __construct(Query $query)
+ public function __construct(Query $query, Group $group = null)
{
$this->query = $query;
+ $this->group = $group;
}
/**
@@ -44,7 +54,7 @@ class User
*/
public static function getUser(Client $client, $username)
{
- $self = new static(new Query($client));
+ $self = new static(new Query($client), new Group(new Query($client)));
return $self->find($self->getLdapUserPattern($username));
}
@@ -53,7 +63,7 @@ class User
*
* @access public
* @param string $query
- * @return null|LdapUserProvider
+ * @return LdapUserProvider
*/
public function find($query)
{
@@ -68,6 +78,62 @@ class User
}
/**
+ * Get user groupIds (DN)
+ *
+ * 1) If configured, use memberUid and posixGroup
+ * 2) Otherwise, use memberOf
+ *
+ * @access protected
+ * @param Entry $entry
+ * @param string $username
+ * @return string[]
+ */
+ protected function getGroups(Entry $entry, $username)
+ {
+ $groupIds = array();
+
+ if (! empty($username) && $this->group !== null && $this->hasGroupUserFilter()) {
+ $groups = $this->group->find(sprintf($this->getGroupUserFilter(), $username));
+
+ foreach ($groups as $group) {
+ $groupIds[] = $group->getExternalId();
+ }
+ } else {
+ $groupIds = $entry->getAll($this->getAttributeGroup());
+ }
+
+ return $groupIds;
+ }
+
+ /**
+ * Get role from LDAP groups
+ *
+ * Note: Do not touch the current role if groups are not configured
+ *
+ * @access protected
+ * @param string[] $groupIds
+ * @return string
+ */
+ protected function getRole(array $groupIds)
+ {
+ if ($this->hasGroupsNotConfigured()) {
+ return null;
+ }
+
+ foreach ($groupIds as $groupId) {
+ $groupId = strtolower($groupId);
+
+ if ($groupId === strtolower($this->getGroupAdminDn())) {
+ return Role::APP_ADMIN;
+ } elseif ($groupId === strtolower($this->getGroupManagerDn())) {
+ return Role::APP_MANAGER;
+ }
+ }
+
+ return Role::APP_USER;
+ }
+
+ /**
* Build user profile
*
* @access protected
@@ -76,21 +142,18 @@ class User
protected function build()
{
$entry = $this->query->getEntries()->getFirstEntry();
- $role = Role::APP_USER;
-
- if ($entry->hasValue($this->getAttributeGroup(), $this->getGroupAdminDn())) {
- $role = Role::APP_ADMIN;
- } elseif ($entry->hasValue($this->getAttributeGroup(), $this->getGroupManagerDn())) {
- $role = Role::APP_MANAGER;
- }
+ $username = $entry->getFirstValue($this->getAttributeUsername());
+ $groupIds = $this->getGroups($entry, $username);
return new LdapUserProvider(
$entry->getDn(),
- $entry->getFirstValue($this->getAttributeUsername()),
+ $username,
$entry->getFirstValue($this->getAttributeName()),
$entry->getFirstValue($this->getAttributeEmail()),
- $role,
- $entry->getAll($this->getAttributeGroup())
+ $this->getRole($groupIds),
+ $groupIds,
+ $entry->getFirstValue($this->getAttributePhoto()),
+ $entry->getFirstValue($this->getAttributeLanguage())
);
}
@@ -109,6 +172,8 @@ class User
$this->getAttributeName(),
$this->getAttributeEmail(),
$this->getAttributeGroup(),
+ $this->getAttributePhoto(),
+ $this->getAttributeLanguage(),
)));
}
@@ -124,7 +189,7 @@ class User
throw new LogicException('LDAP username attribute empty, check the parameter LDAP_USER_ATTRIBUTE_USERNAME');
}
- return LDAP_USER_ATTRIBUTE_USERNAME;
+ return strtolower(LDAP_USER_ATTRIBUTE_USERNAME);
}
/**
@@ -139,7 +204,7 @@ class User
throw new LogicException('LDAP full name attribute empty, check the parameter LDAP_USER_ATTRIBUTE_FULLNAME');
}
- return LDAP_USER_ATTRIBUTE_FULLNAME;
+ return strtolower(LDAP_USER_ATTRIBUTE_FULLNAME);
}
/**
@@ -154,18 +219,73 @@ class User
throw new LogicException('LDAP email attribute empty, check the parameter LDAP_USER_ATTRIBUTE_EMAIL');
}
- return LDAP_USER_ATTRIBUTE_EMAIL;
+ return strtolower(LDAP_USER_ATTRIBUTE_EMAIL);
}
/**
- * Get LDAP account memberof attribute
+ * Get LDAP account memberOf attribute
*
* @access public
* @return string
*/
public function getAttributeGroup()
{
- return LDAP_USER_ATTRIBUTE_GROUPS;
+ return strtolower(LDAP_USER_ATTRIBUTE_GROUPS);
+ }
+
+ /**
+ * Get LDAP profile photo attribute
+ *
+ * @access public
+ * @return string
+ */
+ public function getAttributePhoto()
+ {
+ return strtolower(LDAP_USER_ATTRIBUTE_PHOTO);
+ }
+
+ /**
+ * Get LDAP language attribute
+ *
+ * @access public
+ * @return string
+ */
+ public function getAttributeLanguage()
+ {
+ return strtolower(LDAP_USER_ATTRIBUTE_LANGUAGE);
+ }
+
+ /**
+ * Get LDAP Group User filter
+ *
+ * @access public
+ * @return string
+ */
+ public function getGroupUserFilter()
+ {
+ return LDAP_GROUP_USER_FILTER;
+ }
+
+ /**
+ * Return true if LDAP Group User filter is defined
+ *
+ * @access public
+ * @return string
+ */
+ public function hasGroupUserFilter()
+ {
+ return $this->getGroupUserFilter() !== '' && $this->getGroupUserFilter() !== null;
+ }
+
+ /**
+ * Return true if LDAP Group mapping is not configured
+ *
+ * @access public
+ * @return boolean
+ */
+ public function hasGroupsNotConfigured()
+ {
+ return !$this->getGroupAdminDn() && !$this->getGroupManagerDn();
}
/**
@@ -176,7 +296,7 @@ class User
*/
public function getGroupAdminDn()
{
- return LDAP_GROUP_ADMIN_DN;
+ return strtolower(LDAP_GROUP_ADMIN_DN);
}
/**
diff --git a/app/Core/Mail/Client.php b/app/Core/Mail/Client.php
index 641b6abe..44f4753a 100644
--- a/app/Core/Mail/Client.php
+++ b/app/Core/Mail/Client.php
@@ -2,6 +2,7 @@
namespace Kanboard\Core\Mail;
+use Kanboard\Job\EmailJob;
use Pimple\Container;
use Kanboard\Core\Base;
@@ -46,23 +47,29 @@ class Client extends Base
public function send($email, $name, $subject, $html)
{
if (! empty($email)) {
- $this->logger->debug('Sending email to '.$email.' ('.MAIL_TRANSPORT.')');
-
- $start_time = microtime(true);
- $author = 'Kanboard';
+ $this->queueManager->push(EmailJob::getInstance($this->container)
+ ->withParams($email, $name, $subject, $html, $this->getAuthor())
+ );
+ }
- if ($this->userSession->isLogged()) {
- $author = e('%s via Kanboard', $this->helper->user->getFullname());
- }
+ return $this;
+ }
- $this->getTransport(MAIL_TRANSPORT)->sendEmail($email, $name, $subject, $html, $author);
+ /**
+ * Get email author
+ *
+ * @access public
+ * @return string
+ */
+ public function getAuthor()
+ {
+ $author = 'Kanboard';
- if (DEBUG) {
- $this->logger->debug('Email sent in '.round(microtime(true) - $start_time, 6).' seconds');
- }
+ if ($this->userSession->isLogged()) {
+ $author = e('%s via Kanboard', $this->helper->user->getFullname());
}
- return $this;
+ return $author;
}
/**
diff --git a/app/Core/Mail/Transport/Mail.php b/app/Core/Mail/Transport/Mail.php
index aff3ee20..d27925f0 100644
--- a/app/Core/Mail/Transport/Mail.php
+++ b/app/Core/Mail/Transport/Mail.php
@@ -32,7 +32,7 @@ class Mail extends Base implements ClientInterface
try {
$message = Swift_Message::newInstance()
->setSubject($subject)
- ->setFrom(array(MAIL_FROM => $author))
+ ->setFrom(array($this->helper->mail->getMailSenderAddress() => $author))
->setBody($html, 'text/html')
->setTo(array($email => $name));
diff --git a/app/Core/Markdown.php b/app/Core/Markdown.php
index 827fd0df..b5abe5ed 100644
--- a/app/Core/Markdown.php
+++ b/app/Core/Markdown.php
@@ -15,12 +15,12 @@ use Pimple\Container;
class Markdown extends Parsedown
{
/**
- * Link params for tasks
+ * Task links generated will use the project token instead
*
* @access private
- * @var array
+ * @var boolean
*/
- private $link = array();
+ private $isPublicLink = false;
/**
* Container
@@ -35,11 +35,11 @@ class Markdown extends Parsedown
*
* @access public
* @param Container $container
- * @param array $link
+ * @param boolean $isPublicLink
*/
- public function __construct(Container $container, array $link)
+ public function __construct(Container $container, $isPublicLink)
{
- $this->link = $link;
+ $this->isPublicLink = $isPublicLink;
$this->container = $container;
$this->InlineTypes['#'][] = 'TaskLink';
$this->InlineTypes['@'][] = 'UserLink';
@@ -53,26 +53,26 @@ class Markdown extends Parsedown
*
* @access public
* @param array $Excerpt
- * @return array
+ * @return array|null
*/
protected function inlineTaskLink(array $Excerpt)
{
- if (! empty($this->link) && preg_match('!#(\d+)!i', $Excerpt['text'], $matches)) {
- $url = $this->container['helper']->url->href(
- $this->link['controller'],
- $this->link['action'],
- $this->link['params'] + array('task_id' => $matches[1])
- );
-
- return array(
- 'extent' => strlen($matches[0]),
- 'element' => array(
- 'name' => 'a',
- 'text' => $matches[0],
- 'attributes' => array('href' => $url)
- ),
- );
+ if (preg_match('!#(\d+)!i', $Excerpt['text'], $matches)) {
+ $link = $this->buildTaskLink($matches[1]);
+
+ if (! empty($link)) {
+ return array(
+ 'extent' => strlen($matches[0]),
+ 'element' => array(
+ 'name' => 'a',
+ 'text' => $matches[0],
+ 'attributes' => array('href' => $link),
+ ),
+ );
+ }
}
+
+ return null;
}
/**
@@ -82,15 +82,15 @@ class Markdown extends Parsedown
*
* @access public
* @param array $Excerpt
- * @return array
+ * @return array|null
*/
protected function inlineUserLink(array $Excerpt)
{
- if (preg_match('/^@([^\s]+)/', $Excerpt['text'], $matches)) {
- $user_id = $this->container['user']->getIdByUsername($matches[1]);
+ if (! $this->isPublicLink && preg_match('/^@([^\s]+)/', $Excerpt['text'], $matches)) {
+ $user_id = $this->container['userModel']->getIdByUsername($matches[1]);
if (! empty($user_id)) {
- $url = $this->container['helper']->url->href('user', 'profile', array('user_id' => $user_id));
+ $url = $this->container['helper']->url->href('UserViewController', 'profile', array('user_id' => $user_id));
return array(
'extent' => strlen($matches[0]),
@@ -102,5 +102,40 @@ class Markdown extends Parsedown
);
}
}
+
+ return null;
+ }
+
+ /**
+ * Build task link
+ *
+ * @access private
+ * @param integer $task_id
+ * @return string
+ */
+ private function buildTaskLink($task_id)
+ {
+ if ($this->isPublicLink) {
+ $token = $this->container['memoryCache']->proxy($this->container['taskFinderModel'], 'getProjectToken', $task_id);
+
+ if (! empty($token)) {
+ return $this->container['helper']->url->href(
+ 'TaskViewController',
+ 'readonly',
+ array(
+ 'token' => $token,
+ 'task_id' => $task_id,
+ )
+ );
+ }
+
+ return '';
+ }
+
+ return $this->container['helper']->url->href(
+ 'TaskViewController',
+ 'show',
+ array('task_id' => $task_id)
+ );
}
}
diff --git a/app/Notification/NotificationInterface.php b/app/Core/Notification/NotificationInterface.php
index 8431a77c..d336983a 100644
--- a/app/Notification/NotificationInterface.php
+++ b/app/Core/Notification/NotificationInterface.php
@@ -1,11 +1,11 @@
<?php
-namespace Kanboard\Notification;
+namespace Kanboard\Core\Notification;
/**
* Notification Interface
*
- * @package core
+ * @package Kanboard\Core\Notification
* @author Frederic Guillot
*/
interface NotificationInterface
diff --git a/app/Core/Plugin/Base.php b/app/Core/Plugin/Base.php
index 381b8bb3..9d8167a9 100644
--- a/app/Core/Plugin/Base.php
+++ b/app/Core/Plugin/Base.php
@@ -5,8 +5,8 @@ namespace Kanboard\Core\Plugin;
/**
* Plugin Base class
*
- * @package plugin
- * @author Frederic Guillot
+ * @package Kanboard\Core\Plugin
+ * @author Frederic Guillot
*/
abstract class Base extends \Kanboard\Core\Base
{
@@ -62,7 +62,7 @@ abstract class Base extends \Kanboard\Core\Base
{
$container = $this->container;
- $this->container['dispatcher']->addListener($event, function () use ($container, $callback) {
+ $this->dispatcher->addListener($event, function () use ($container, $callback) {
call_user_func($callback, $container);
});
}
@@ -70,7 +70,7 @@ abstract class Base extends \Kanboard\Core\Base
/**
* Get plugin name
*
- * This method should be overrided by your Plugin class
+ * This method should be overridden by your Plugin class
*
* @access public
* @return string
@@ -83,7 +83,7 @@ abstract class Base extends \Kanboard\Core\Base
/**
* Get plugin description
*
- * This method should be overrided by your Plugin class
+ * This method should be overridden by your Plugin class
*
* @access public
* @return string
@@ -96,7 +96,7 @@ abstract class Base extends \Kanboard\Core\Base
/**
* Get plugin author
*
- * This method should be overrided by your Plugin class
+ * This method should be overridden by your Plugin class
*
* @access public
* @return string
@@ -109,7 +109,7 @@ abstract class Base extends \Kanboard\Core\Base
/**
* Get plugin version
*
- * This method should be overrided by your Plugin class
+ * This method should be overridden by your Plugin class
*
* @access public
* @return string
@@ -122,7 +122,7 @@ abstract class Base extends \Kanboard\Core\Base
/**
* Get plugin homepage
*
- * This method should be overrided by your Plugin class
+ * This method should be overridden by your Plugin class
*
* @access public
* @return string
diff --git a/app/Core/Plugin/Directory.php b/app/Core/Plugin/Directory.php
new file mode 100644
index 00000000..21f11ca9
--- /dev/null
+++ b/app/Core/Plugin/Directory.php
@@ -0,0 +1,56 @@
+<?php
+
+namespace Kanboard\Core\Plugin;
+
+use Kanboard\Core\Base as BaseCore;
+
+/**
+ * Class Directory
+ *
+ * @package Kanboard\Core\Plugin
+ * @author Frederic Guillot
+ */
+class Directory extends BaseCore
+{
+ /**
+ * Get all plugins available
+ *
+ * @access public
+ * @param string $url
+ * @return array
+ */
+ public function getAvailablePlugins($url = PLUGIN_API_URL)
+ {
+ $plugins = $this->httpClient->getJson($url);
+ $plugins = array_filter($plugins, array($this, 'isCompatible'));
+ $plugins = array_filter($plugins, array($this, 'isInstallable'));
+ return $plugins;
+ }
+
+ /**
+ * Filter plugins
+ *
+ * @param array $plugin
+ * @param string $appVersion
+ * @return bool
+ */
+ public function isCompatible(array $plugin, $appVersion = APP_VERSION)
+ {
+ if (strpos($appVersion, 'master') !== false) {
+ return true;
+ }
+
+ return $plugin['compatible_version'] === $appVersion;
+ }
+
+ /**
+ * Filter plugins
+ *
+ * @param array $plugin
+ * @return bool
+ */
+ public function isInstallable(array $plugin)
+ {
+ return $plugin['remote_install'];
+ }
+}
diff --git a/app/Core/Plugin/Hook.php b/app/Core/Plugin/Hook.php
index a3bcd918..ade69150 100644
--- a/app/Core/Plugin/Hook.php
+++ b/app/Core/Plugin/Hook.php
@@ -5,8 +5,8 @@ namespace Kanboard\Core\Plugin;
/**
* Plugin Hooks Handler
*
- * @package plugin
- * @author Frederic Guillot
+ * @package Kanboard\Core\Plugin
+ * @author Frederic Guillot
*/
class Hook
{
diff --git a/app/Core/Plugin/Installer.php b/app/Core/Plugin/Installer.php
new file mode 100644
index 00000000..48c4d978
--- /dev/null
+++ b/app/Core/Plugin/Installer.php
@@ -0,0 +1,162 @@
+<?php
+
+namespace Kanboard\Core\Plugin;
+
+use RecursiveDirectoryIterator;
+use RecursiveIteratorIterator;
+use ZipArchive;
+
+/**
+ * Class Installer
+ *
+ * @package Kanboard\Core\Plugin
+ * @author Frederic Guillot
+ */
+class Installer extends \Kanboard\Core\Base
+{
+ /**
+ * Return true if Kanboard is configured to install plugins
+ *
+ * @static
+ * @access public
+ * @return bool
+ */
+ public static function isConfigured()
+ {
+ return PLUGIN_INSTALLER && is_writable(PLUGINS_DIR) && extension_loaded('zip');
+ }
+
+ /**
+ * Install a plugin
+ *
+ * @access public
+ * @param string $archiveUrl
+ * @throws PluginInstallerException
+ */
+ public function install($archiveUrl)
+ {
+ $zip = $this->downloadPluginArchive($archiveUrl);
+
+ if (! $zip->extractTo(PLUGINS_DIR)) {
+ $this->cleanupArchive($zip);
+ throw new PluginInstallerException(t('Unable to extract plugin archive.'));
+ }
+
+ $this->cleanupArchive($zip);
+ }
+
+ /**
+ * Uninstall a plugin
+ *
+ * @access public
+ * @param string $pluginId
+ * @throws PluginInstallerException
+ */
+ public function uninstall($pluginId)
+ {
+ $pluginFolder = PLUGINS_DIR.DIRECTORY_SEPARATOR.basename($pluginId);
+
+ if (! file_exists($pluginFolder)) {
+ throw new PluginInstallerException(t('Plugin not found.'));
+ }
+
+ if (! is_writable($pluginFolder)) {
+ throw new PluginInstallerException(e('You don\'t have the permission to remove this plugin.'));
+ }
+
+ $this->removeAllDirectories($pluginFolder);
+ }
+
+ /**
+ * Update a plugin
+ *
+ * @access public
+ * @param string $archiveUrl
+ * @throws PluginInstallerException
+ */
+ public function update($archiveUrl)
+ {
+ $zip = $this->downloadPluginArchive($archiveUrl);
+
+ $firstEntry = $zip->statIndex(0);
+ $this->uninstall($firstEntry['name']);
+
+ if (! $zip->extractTo(PLUGINS_DIR)) {
+ $this->cleanupArchive($zip);
+ throw new PluginInstallerException(t('Unable to extract plugin archive.'));
+ }
+
+ $this->cleanupArchive($zip);
+ }
+
+ /**
+ * Download archive from URL
+ *
+ * @access protected
+ * @param string $archiveUrl
+ * @return ZipArchive
+ * @throws PluginInstallerException
+ */
+ protected function downloadPluginArchive($archiveUrl)
+ {
+ $zip = new ZipArchive();
+ $archiveData = $this->httpClient->get($archiveUrl);
+ $archiveFile = tempnam(sys_get_temp_dir(), 'kb_plugin');
+
+ if (empty($archiveData)) {
+ unlink($archiveFile);
+ throw new PluginInstallerException(t('Unable to download plugin archive.'));
+ }
+
+ if (file_put_contents($archiveFile, $archiveData) === false) {
+ unlink($archiveFile);
+ throw new PluginInstallerException(t('Unable to write temporary file for plugin.'));
+ }
+
+ if ($zip->open($archiveFile) !== true) {
+ unlink($archiveFile);
+ throw new PluginInstallerException(t('Unable to open plugin archive.'));
+ }
+
+ if ($zip->numFiles === 0) {
+ unlink($archiveFile);
+ throw new PluginInstallerException(t('There is no file in the plugin archive.'));
+ }
+
+ return $zip;
+ }
+
+ /**
+ * Remove archive file
+ *
+ * @access protected
+ * @param ZipArchive $zip
+ */
+ protected function cleanupArchive(ZipArchive $zip)
+ {
+ unlink($zip->filename);
+ $zip->close();
+ }
+
+ /**
+ * Remove recursively a directory
+ *
+ * @access protected
+ * @param string $directory
+ */
+ protected function removeAllDirectories($directory)
+ {
+ $it = new RecursiveDirectoryIterator($directory, RecursiveDirectoryIterator::SKIP_DOTS);
+ $files = new RecursiveIteratorIterator($it, RecursiveIteratorIterator::CHILD_FIRST);
+
+ foreach ($files as $file) {
+ if ($file->isDir()) {
+ rmdir($file->getRealPath());
+ } else {
+ unlink($file->getRealPath());
+ }
+ }
+
+ rmdir($directory);
+ }
+}
diff --git a/app/Core/Plugin/Loader.php b/app/Core/Plugin/Loader.php
index 799024ad..f2f6add7 100644
--- a/app/Core/Plugin/Loader.php
+++ b/app/Core/Plugin/Loader.php
@@ -4,33 +4,35 @@ namespace Kanboard\Core\Plugin;
use Composer\Autoload\ClassLoader;
use DirectoryIterator;
-use PDOException;
use LogicException;
-use RuntimeException;
use Kanboard\Core\Tool;
/**
* Plugin Loader
*
- * @package plugin
- * @author Frederic Guillot
+ * @package Kanboard\Core\Plugin
+ * @author Frederic Guillot
*/
class Loader extends \Kanboard\Core\Base
{
/**
- * Schema version table for plugins
+ * Plugin instances
*
- * @var string
+ * @access protected
+ * @var array
*/
- const TABLE_SCHEMA = 'plugin_schema_versions';
+ protected $plugins = array();
/**
- * Plugin instances
+ * Get list of loaded plugins
*
* @access public
- * @var array
+ * @return Base[]
*/
- public $plugins = array();
+ public function getPlugins()
+ {
+ return $this->plugins;
+ }
/**
* Scan plugin folder and load plugins
@@ -46,115 +48,66 @@ class Loader extends \Kanboard\Core\Base
$dir = new DirectoryIterator(PLUGINS_DIR);
- foreach ($dir as $fileinfo) {
- if (! $fileinfo->isDot() && $fileinfo->isDir()) {
- $plugin = $fileinfo->getFilename();
- $this->loadSchema($plugin);
- $this->load($plugin);
+ foreach ($dir as $fileInfo) {
+ if ($fileInfo->isDir() && substr($fileInfo->getFilename(), 0, 1) !== '.') {
+ $pluginName = $fileInfo->getFilename();
+ $this->loadSchema($pluginName);
+ $this->initializePlugin($pluginName, $this->loadPlugin($pluginName));
}
}
}
}
/**
- * Load plugin
- *
- * @access public
- * @throws LogicException
- * @param string $plugin
- */
- public function load($plugin)
- {
- $class = '\Kanboard\Plugin\\'.$plugin.'\\Plugin';
-
- if (! class_exists($class)) {
- throw new LogicException('Unable to load this plugin class '.$class);
- }
-
- $instance = new $class($this->container);
-
- Tool::buildDIC($this->container, $instance->getClasses());
- Tool::buildDICHelpers($this->container, $instance->getHelpers());
-
- $instance->initialize();
- $this->plugins[] = $instance;
- }
-
- /**
* Load plugin schema
*
* @access public
- * @param string $plugin
+ * @param string $pluginName
*/
- public function loadSchema($plugin)
+ public function loadSchema($pluginName)
{
- $filename = PLUGINS_DIR.'/'.$plugin.'/Schema/'.ucfirst(DB_DRIVER).'.php';
-
- if (file_exists($filename)) {
- require_once($filename);
- $this->migrateSchema($plugin);
+ if (SchemaHandler::hasSchema($pluginName)) {
+ $schemaHandler = new SchemaHandler($this->container);
+ $schemaHandler->loadSchema($pluginName);
}
}
/**
- * Execute plugin schema migrations
+ * Load plugin
*
* @access public
- * @param string $plugin
+ * @throws LogicException
+ * @param string $pluginName
+ * @return Base
*/
- public function migrateSchema($plugin)
+ public function loadPlugin($pluginName)
{
- $last_version = constant('\Kanboard\Plugin\\'.$plugin.'\Schema\VERSION');
- $current_version = $this->getSchemaVersion($plugin);
-
- try {
- $this->db->startTransaction();
- $this->db->getDriver()->disableForeignKeys();
-
- for ($i = $current_version + 1; $i <= $last_version; $i++) {
- $function_name = '\Kanboard\Plugin\\'.$plugin.'\Schema\version_'.$i;
-
- if (function_exists($function_name)) {
- call_user_func($function_name, $this->db->getConnection());
- }
- }
+ $className = '\Kanboard\Plugin\\'.$pluginName.'\\Plugin';
- $this->db->getDriver()->enableForeignKeys();
- $this->db->closeTransaction();
- $this->setSchemaVersion($plugin, $i - 1);
- } catch (PDOException $e) {
- $this->db->cancelTransaction();
- $this->db->getDriver()->enableForeignKeys();
- throw new RuntimeException('Unable to migrate schema for the plugin: '.$plugin.' => '.$e->getMessage());
+ if (! class_exists($className)) {
+ throw new LogicException('Unable to load this plugin class '.$className);
}
- }
- /**
- * Get current plugin schema version
- *
- * @access public
- * @param string $plugin
- * @return integer
- */
- public function getSchemaVersion($plugin)
- {
- return (int) $this->db->table(self::TABLE_SCHEMA)->eq('plugin', strtolower($plugin))->findOneColumn('version');
+ return new $className($this->container);
}
/**
- * Save last plugin schema version
+ * Initialize plugin
*
* @access public
- * @param string $plugin
- * @param integer $version
- * @return boolean
+ * @param string $pluginName
+ * @param Base $plugin
*/
- public function setSchemaVersion($plugin, $version)
+ public function initializePlugin($pluginName, Base $plugin)
{
- $dictionary = array(
- strtolower($plugin) => $version
- );
+ if (method_exists($plugin, 'onStartup')) {
+ $this->dispatcher->addListener('app.bootstrap', array($plugin, 'onStartup'));
+ }
+
+ Tool::buildDIC($this->container, $plugin->getClasses());
+ Tool::buildDICHelpers($this->container, $plugin->getHelpers());
- return $this->db->getDriver()->upsert(self::TABLE_SCHEMA, 'plugin', 'version', $dictionary);
+ $plugin->initialize();
+ $this->plugins[$pluginName] = $plugin;
}
}
diff --git a/app/Core/Plugin/PluginInstallerException.php b/app/Core/Plugin/PluginInstallerException.php
new file mode 100644
index 00000000..7d356c9b
--- /dev/null
+++ b/app/Core/Plugin/PluginInstallerException.php
@@ -0,0 +1,15 @@
+<?php
+
+namespace Kanboard\Core\Plugin;
+
+use Exception;
+
+/**
+ * Class PluginInstallerException
+ *
+ * @package Kanboard\Core\Plugin
+ * @author Frederic Guillot
+ */
+class PluginInstallerException extends Exception
+{
+}
diff --git a/app/Core/Plugin/SchemaHandler.php b/app/Core/Plugin/SchemaHandler.php
new file mode 100644
index 00000000..551141b8
--- /dev/null
+++ b/app/Core/Plugin/SchemaHandler.php
@@ -0,0 +1,122 @@
+<?php
+
+namespace Kanboard\Core\Plugin;
+
+use PDOException;
+use RuntimeException;
+
+/**
+ * Class SchemaHandler
+ *
+ * @package Kanboard\Core\Plugin
+ * @author Frederic Guillot
+ */
+class SchemaHandler extends \Kanboard\Core\Base
+{
+ /**
+ * Schema version table for plugins
+ *
+ * @var string
+ */
+ const TABLE_SCHEMA = 'plugin_schema_versions';
+
+ /**
+ * Get schema filename
+ *
+ * @static
+ * @access public
+ * @param string $pluginName
+ * @return string
+ */
+ public static function getSchemaFilename($pluginName)
+ {
+ return PLUGINS_DIR.'/'.$pluginName.'/Schema/'.ucfirst(DB_DRIVER).'.php';
+ }
+
+ /**
+ * Return true if the plugin has schema
+ *
+ * @static
+ * @access public
+ * @param string $pluginName
+ * @return boolean
+ */
+ public static function hasSchema($pluginName)
+ {
+ return file_exists(self::getSchemaFilename($pluginName));
+ }
+
+ /**
+ * Load plugin schema
+ *
+ * @access public
+ * @param string $pluginName
+ */
+ public function loadSchema($pluginName)
+ {
+ require_once self::getSchemaFilename($pluginName);
+ $this->migrateSchema($pluginName);
+ }
+
+ /**
+ * Execute plugin schema migrations
+ *
+ * @access public
+ * @param string $pluginName
+ */
+ public function migrateSchema($pluginName)
+ {
+ $lastVersion = constant('\Kanboard\Plugin\\'.$pluginName.'\Schema\VERSION');
+ $currentVersion = $this->getSchemaVersion($pluginName);
+
+ try {
+ $this->db->startTransaction();
+ $this->db->getDriver()->disableForeignKeys();
+
+ for ($i = $currentVersion + 1; $i <= $lastVersion; $i++) {
+ $functionName = '\Kanboard\Plugin\\'.$pluginName.'\Schema\version_'.$i;
+
+ if (function_exists($functionName)) {
+ call_user_func($functionName, $this->db->getConnection());
+ }
+ }
+
+ $this->db->getDriver()->enableForeignKeys();
+ $this->db->closeTransaction();
+ $this->setSchemaVersion($pluginName, $i - 1);
+ } catch (PDOException $e) {
+ $this->db->cancelTransaction();
+ $this->db->getDriver()->enableForeignKeys();
+ throw new RuntimeException('Unable to migrate schema for the plugin: '.$pluginName.' => '.$e->getMessage());
+ }
+ }
+
+ /**
+ * Get current plugin schema version
+ *
+ * @access public
+ * @param string $plugin
+ * @return integer
+ */
+ public function getSchemaVersion($plugin)
+ {
+ return (int) $this->db->table(self::TABLE_SCHEMA)->eq('plugin', strtolower($plugin))->findOneColumn('version');
+ }
+
+ /**
+ * Save last plugin schema version
+ *
+ * @access public
+ * @param string $plugin
+ * @param integer $version
+ * @return boolean
+ */
+ public function setSchemaVersion($plugin, $version)
+ {
+ $dictionary = array(
+ strtolower($plugin) => $version
+ );
+
+ return $this->db->getDriver()->upsert(self::TABLE_SCHEMA, 'plugin', 'version', $dictionary);
+ }
+}
diff --git a/app/Core/Queue/JobHandler.php b/app/Core/Queue/JobHandler.php
new file mode 100644
index 00000000..a2c4a2c7
--- /dev/null
+++ b/app/Core/Queue/JobHandler.php
@@ -0,0 +1,50 @@
+<?php
+
+namespace Kanboard\Core\Queue;
+
+use Kanboard\Core\Base;
+use Kanboard\Job\BaseJob;
+use SimpleQueue\Job;
+
+/**
+ * Class JobHandler
+ *
+ * @package Kanboard\Core\Queue
+ * @author Frederic Guillot
+ */
+class JobHandler extends Base
+{
+ /**
+ * Serialize a job
+ *
+ * @access public
+ * @param BaseJob $job
+ * @return Job
+ */
+ public function serializeJob(BaseJob $job)
+ {
+ return new Job(array(
+ 'class' => get_class($job),
+ 'params' => $job->getJobParams(),
+ ));
+ }
+
+ /**
+ * Execute a job
+ *
+ * @access public
+ * @param Job $job
+ */
+ public function executeJob(Job $job)
+ {
+ $payload = $job->getBody();
+ $className = $payload['class'];
+
+ if (DEBUG) {
+ $this->logger->debug(__METHOD__.' Received job => '.$className);
+ }
+
+ $worker = new $className($this->container);
+ call_user_func_array(array($worker, 'execute'), $payload['params']);
+ }
+}
diff --git a/app/Core/Queue/QueueManager.php b/app/Core/Queue/QueueManager.php
new file mode 100644
index 00000000..f34cb220
--- /dev/null
+++ b/app/Core/Queue/QueueManager.php
@@ -0,0 +1,71 @@
+<?php
+
+namespace Kanboard\Core\Queue;
+
+use Kanboard\Core\Base;
+use Kanboard\Job\BaseJob;
+use LogicException;
+use SimpleQueue\Queue;
+
+/**
+ * Class QueueManager
+ *
+ * @package Kanboard\Core\Queue
+ * @author Frederic Guillot
+ */
+class QueueManager extends Base
+{
+ /**
+ * @var Queue
+ */
+ protected $queue = null;
+
+ /**
+ * Set queue driver
+ *
+ * @access public
+ * @param Queue $queue
+ * @return $this
+ */
+ public function setQueue(Queue $queue)
+ {
+ $this->queue = $queue;
+ return $this;
+ }
+
+ /**
+ * Send a new job to the queue
+ *
+ * @access public
+ * @param BaseJob $job
+ * @return $this
+ */
+ public function push(BaseJob $job)
+ {
+ if ($this->queue !== null) {
+ $this->queue->push(JobHandler::getInstance($this->container)->serializeJob($job));
+ } else {
+ call_user_func_array(array($job, 'execute'), $job->getJobParams());
+ }
+
+ return $this;
+ }
+
+ /**
+ * Wait for new jobs
+ *
+ * @access public
+ * @throws LogicException
+ */
+ public function listen()
+ {
+ if ($this->queue === null) {
+ throw new LogicException('No Queue Driver defined!');
+ }
+
+ while ($job = $this->queue->pull()) {
+ JobHandler::getInstance($this->container)->executeJob($job);
+ $this->queue->completed($job);
+ }
+ }
+}
diff --git a/app/Core/Session/SessionStorage.php b/app/Core/Session/SessionStorage.php
index 6e2f9660..9e93602c 100644
--- a/app/Core/Session/SessionStorage.php
+++ b/app/Core/Session/SessionStorage.php
@@ -22,6 +22,7 @@ namespace Kanboard\Core\Session;
* @property bool $twoFactorBeforeCodeCalled
* @property string $twoFactorSecret
* @property string $oauthState
+ * @property int $smsTwoFactorSecret
*/
class SessionStorage
{
diff --git a/app/Core/Tool.php b/app/Core/Tool.php
index 3423998d..bfa6c955 100644
--- a/app/Core/Tool.php
+++ b/app/Core/Tool.php
@@ -13,26 +13,6 @@ use Pimple\Container;
class Tool
{
/**
- * Get the mailbox hash from an email address
- *
- * @static
- * @access public
- * @param string $email
- * @return string
- */
- public static function getMailboxHash($email)
- {
- if (! strpos($email, '@') || ! strpos($email, '+')) {
- return '';
- }
-
- list($local_part, ) = explode('@', $email);
- list(, $identifier) = explode('+', $local_part);
-
- return $identifier;
- }
-
- /**
* Build dependency injection container from an array
*
* @static
diff --git a/app/Core/User/GroupSync.php b/app/Core/User/GroupSync.php
index 573acd47..d0bb647b 100644
--- a/app/Core/User/GroupSync.php
+++ b/app/Core/User/GroupSync.php
@@ -16,16 +16,52 @@ class GroupSync extends Base
* Synchronize group membership
*
* @access public
- * @param integer $userId
- * @param array $groupIds
+ * @param integer $userId
+ * @param array $externalGroupIds
*/
- public function synchronize($userId, array $groupIds)
+ public function synchronize($userId, array $externalGroupIds)
{
- foreach ($groupIds as $groupId) {
- $group = $this->group->getByExternalId($groupId);
+ $userGroups = $this->groupMemberModel->getGroups($userId);
+ $this->addGroups($userId, $userGroups, $externalGroupIds);
+ $this->removeGroups($userId, $userGroups, $externalGroupIds);
+ }
+
+ /**
+ * Add missing groups to the user
+ *
+ * @access protected
+ * @param integer $userId
+ * @param array $userGroups
+ * @param array $externalGroupIds
+ */
+ protected function addGroups($userId, array $userGroups, array $externalGroupIds)
+ {
+ $userGroupIds = array_column($userGroups, 'external_id', 'external_id');
- if (! empty($group) && ! $this->groupMember->isMember($group['id'], $userId)) {
- $this->groupMember->addUser($group['id'], $userId);
+ foreach ($externalGroupIds as $externalGroupId) {
+ if (! isset($userGroupIds[$externalGroupId])) {
+ $group = $this->groupModel->getByExternalId($externalGroupId);
+
+ if (! empty($group)) {
+ $this->groupMemberModel->addUser($group['id'], $userId);
+ }
+ }
+ }
+ }
+
+ /**
+ * Remove groups from the user
+ *
+ * @access protected
+ * @param integer $userId
+ * @param array $userGroups
+ * @param array $externalGroupIds
+ */
+ protected function removeGroups($userId, array $userGroups, array $externalGroupIds)
+ {
+ foreach ($userGroups as $userGroup) {
+ if (! empty($userGroup['external_id']) && ! in_array($userGroup['external_id'], $externalGroupIds)) {
+ $this->groupMemberModel->removeUser($userGroup['id'], $userId);
}
}
}
diff --git a/app/Core/User/UserProfile.php b/app/Core/User/UserProfile.php
index ef325801..8b9ebb71 100644
--- a/app/Core/User/UserProfile.php
+++ b/app/Core/User/UserProfile.php
@@ -3,6 +3,7 @@
namespace Kanboard\Core\User;
use Kanboard\Core\Base;
+use Kanboard\Event\UserProfileSyncEvent;
/**
* User Profile
@@ -12,6 +13,8 @@ use Kanboard\Core\Base;
*/
class UserProfile extends Base
{
+ const EVENT_USER_PROFILE_AFTER_SYNC = 'user_profile.after.sync';
+
/**
* Assign provider data to the local user
*
@@ -22,12 +25,12 @@ class UserProfile extends Base
*/
public function assign($userId, UserProviderInterface $user)
{
- $profile = $this->user->getById($userId);
+ $profile = $this->userModel->getById($userId);
$values = UserProperty::filterProperties($profile, UserProperty::getProperties($user));
$values['id'] = $userId;
- if ($this->user->update($values)) {
+ if ($this->userModel->update($values)) {
$profile = array_merge($profile, $values);
$this->userSession->initialize($profile);
return true;
@@ -46,7 +49,7 @@ class UserProfile extends Base
public function initialize(UserProviderInterface $user)
{
if ($user->getInternalId()) {
- $profile = $this->user->getById($user->getInternalId());
+ $profile = $this->userModel->getById($user->getInternalId());
} elseif ($user->getExternalIdColumn() && $user->getExternalId()) {
$profile = $this->userSync->synchronize($user);
$this->groupSync->synchronize($profile['id'], $user->getExternalGroupIds());
@@ -54,6 +57,7 @@ class UserProfile extends Base
if (! empty($profile) && $profile['is_active'] == 1) {
$this->userSession->initialize($profile);
+ $this->dispatcher->dispatch(self::EVENT_USER_PROFILE_AFTER_SYNC, new UserProfileSyncEvent($profile, $user));
return true;
}
diff --git a/app/Core/User/UserProperty.php b/app/Core/User/UserProperty.php
index f8b08a3d..348bd7f3 100644
--- a/app/Core/User/UserProperty.php
+++ b/app/Core/User/UserProperty.php
@@ -44,10 +44,14 @@ class UserProperty
*/
public static function filterProperties(array $profile, array $properties)
{
+ $excludedProperties = array('username');
$values = array();
foreach ($properties as $property => $value) {
- if (array_key_exists($property, $profile) && ! self::isNotEmptyValue($profile[$property])) {
+ if (self::isNotEmptyValue($value) &&
+ ! in_array($property, $excludedProperties) &&
+ array_key_exists($property, $profile) &&
+ $value !== $profile[$property]) {
$values[$property] = $value;
}
}
diff --git a/app/Core/User/UserSession.php b/app/Core/User/UserSession.php
index 0034c47a..9c63f07a 100644
--- a/app/Core/User/UserSession.php
+++ b/app/Core/User/UserSession.php
@@ -22,7 +22,7 @@ class UserSession extends Base
public function refresh($user_id)
{
if ($this->getId() == $user_id) {
- $this->initialize($this->user->getById($user_id));
+ $this->initialize($this->userModel->getById($user_id));
}
}
diff --git a/app/Core/User/UserSync.php b/app/Core/User/UserSync.php
index d450a0bd..c2f85498 100644
--- a/app/Core/User/UserSync.php
+++ b/app/Core/User/UserSync.php
@@ -21,7 +21,7 @@ class UserSync extends Base
*/
public function synchronize(UserProviderInterface $user)
{
- $profile = $this->user->getByExternalId($user->getExternalIdColumn(), $user->getExternalId());
+ $profile = $this->userModel->getByExternalId($user->getExternalIdColumn(), $user->getExternalId());
$properties = UserProperty::getProperties($user);
if (! empty($profile)) {
@@ -47,7 +47,7 @@ class UserSync extends Base
if (! empty($values)) {
$values['id'] = $profile['id'];
- $result = $this->user->update($values);
+ $result = $this->userModel->update($values);
return $result ? array_merge($profile, $properties) : $profile;
}
@@ -64,13 +64,13 @@ class UserSync extends Base
*/
private function createUser(UserProviderInterface $user, array $properties)
{
- $id = $this->user->create($properties);
+ $userId = $this->userModel->create($properties);
- if ($id === false) {
+ if ($userId === false) {
$this->logger->error('Unable to create user profile: '.$user->getExternalId());
return array();
}
- return $this->user->getById($id);
+ return $this->userModel->getById($userId);
}
}
diff --git a/app/Event/UserProfileSyncEvent.php b/app/Event/UserProfileSyncEvent.php
new file mode 100644
index 00000000..c02e1d89
--- /dev/null
+++ b/app/Event/UserProfileSyncEvent.php
@@ -0,0 +1,64 @@
+<?php
+
+namespace Kanboard\Event;
+
+use Kanboard\Core\User\UserProviderInterface;
+use Kanboard\User\LdapUserProvider;
+use Symfony\Component\EventDispatcher\Event;
+
+/**
+ * Class UserProfileSyncEvent
+ *
+ * @package Kanboard\Event
+ * @author Fredic Guillot
+ */
+class UserProfileSyncEvent extends Event
+{
+ /**
+ * User profile
+ *
+ * @var array
+ */
+ private $profile;
+
+ /**
+ * User provider
+ *
+ * @var UserProviderInterface
+ */
+ private $user;
+
+ /**
+ * UserProfileSyncEvent constructor.
+ *
+ * @param array $profile
+ * @param UserProviderInterface $user
+ */
+ public function __construct(array $profile, UserProviderInterface $user)
+ {
+ $this->profile = $profile;
+ $this->user = $user;
+ }
+
+ /**
+ * Get user profile
+ *
+ * @access public
+ * @return array
+ */
+ public function getProfile()
+ {
+ return $this->profile;
+ }
+
+ /**
+ * Get user provider object
+ *
+ * @access public
+ * @return UserProviderInterface|LdapUserProvider
+ */
+ public function getUser()
+ {
+ return $this->user;
+ }
+}
diff --git a/app/Export/SubtaskExport.php b/app/Export/SubtaskExport.php
index 386c566b..0939838f 100644
--- a/app/Export/SubtaskExport.php
+++ b/app/Export/SubtaskExport.php
@@ -3,9 +3,9 @@
namespace Kanboard\Export;
use Kanboard\Core\Base;
-use Kanboard\Model\Task;
-use Kanboard\Model\Subtask;
-use Kanboard\Model\User;
+use Kanboard\Model\TaskModel;
+use Kanboard\Model\SubtaskModel;
+use Kanboard\Model\UserModel;
/**
* Subtask Export
@@ -34,7 +34,7 @@ class SubtaskExport extends Base
*/
public function export($project_id, $from, $to)
{
- $this->subtask_status = $this->subtask->getStatusList();
+ $this->subtask_status = $this->subtaskModel->getStatusList();
$subtasks = $this->getSubtasks($project_id, $from, $to);
$results = array($this->getColumns());
@@ -106,19 +106,19 @@ class SubtaskExport extends Base
$to = $this->dateParser->removeTimeFromTimestamp(strtotime('+1 day', $this->dateParser->getTimestamp($to)));
}
- return $this->db->table(Subtask::TABLE)
+ return $this->db->table(SubtaskModel::TABLE)
->eq('project_id', $project_id)
->columns(
- Subtask::TABLE.'.*',
- User::TABLE.'.username AS assignee_username',
- User::TABLE.'.name AS assignee_name',
- Task::TABLE.'.title AS task_title'
+ SubtaskModel::TABLE.'.*',
+ UserModel::TABLE.'.username AS assignee_username',
+ UserModel::TABLE.'.name AS assignee_name',
+ TaskModel::TABLE.'.title AS task_title'
)
->gte('date_creation', $from)
->lte('date_creation', $to)
- ->join(Task::TABLE, 'id', 'task_id')
- ->join(User::TABLE, 'id', 'user_id')
- ->asc(Subtask::TABLE.'.id')
+ ->join(TaskModel::TABLE, 'id', 'task_id')
+ ->join(UserModel::TABLE, 'id', 'user_id')
+ ->asc(SubtaskModel::TABLE.'.id')
->findAll();
}
}
diff --git a/app/Export/TaskExport.php b/app/Export/TaskExport.php
index b98582aa..0e576d33 100644
--- a/app/Export/TaskExport.php
+++ b/app/Export/TaskExport.php
@@ -4,7 +4,7 @@ namespace Kanboard\Export;
use Kanboard\Core\Base;
use Kanboard\Core\DateParser;
-use Kanboard\Model\Task;
+use Kanboard\Model\TaskModel;
use PDO;
/**
@@ -27,7 +27,7 @@ class TaskExport extends Base
public function export($project_id, $from, $to)
{
$tasks = $this->getTasks($project_id, $from, $to);
- $swimlanes = $this->swimlane->getList($project_id);
+ $swimlanes = $this->swimlaneModel->getList($project_id);
$results = array($this->getColumns());
foreach ($tasks as &$task) {
@@ -102,9 +102,9 @@ class TaskExport extends Base
*/
public function format(array &$task, array &$swimlanes)
{
- $colors = $this->color->getList();
+ $colors = $this->colorModel->getList();
- $task['is_active'] = $task['is_active'] == Task::STATUS_OPEN ? e('Open') : e('Closed');
+ $task['is_active'] = $task['is_active'] == TaskModel::STATUS_OPEN ? e('Open') : e('Closed');
$task['color_id'] = $colors[$task['color_id']];
$task['score'] = $task['score'] ?: 0;
$task['swimlane_id'] = isset($swimlanes[$task['swimlane_id']]) ? $swimlanes[$task['swimlane_id']] : '?';
diff --git a/app/Export/TransitionExport.php b/app/Export/TransitionExport.php
index 97dc28a7..0df1f70e 100644
--- a/app/Export/TransitionExport.php
+++ b/app/Export/TransitionExport.php
@@ -25,7 +25,7 @@ class TransitionExport extends Base
public function export($project_id, $from, $to)
{
$results = array($this->getColumns());
- $transitions = $this->transition->getAllByProjectAndDate($project_id, $from, $to);
+ $transitions = $this->transitionModel->getAllByProjectAndDate($project_id, $from, $to);
foreach ($transitions as $transition) {
$results[] = $this->format($transition);
@@ -68,7 +68,7 @@ class TransitionExport extends Base
$transition['src_column'],
$transition['dst_column'],
$transition['name'] ?: $transition['username'],
- date($this->config->get('application_datetime_format', DateParser::DATE_TIME_FORMAT), $transition['date']),
+ date($this->configModel->get('application_datetime_format', DateParser::DATE_TIME_FORMAT), $transition['date']),
round($transition['time_spent'] / 3600, 2)
);
diff --git a/app/Filter/ProjectActivityCreationDateFilter.php b/app/Filter/ProjectActivityCreationDateFilter.php
index d0b7f754..451f6548 100644
--- a/app/Filter/ProjectActivityCreationDateFilter.php
+++ b/app/Filter/ProjectActivityCreationDateFilter.php
@@ -3,7 +3,7 @@
namespace Kanboard\Filter;
use Kanboard\Core\Filter\FilterInterface;
-use Kanboard\Model\ProjectActivity;
+use Kanboard\Model\ProjectActivityModel;
/**
* Filter activity events by creation date
@@ -32,7 +32,7 @@ class ProjectActivityCreationDateFilter extends BaseDateFilter implements Filter
*/
public function apply()
{
- $this->applyDateFilter(ProjectActivity::TABLE.'.date_creation');
+ $this->applyDateFilter(ProjectActivityModel::TABLE.'.date_creation');
return $this;
}
}
diff --git a/app/Filter/ProjectActivityCreatorFilter.php b/app/Filter/ProjectActivityCreatorFilter.php
index c95569d6..573238d8 100644
--- a/app/Filter/ProjectActivityCreatorFilter.php
+++ b/app/Filter/ProjectActivityCreatorFilter.php
@@ -3,7 +3,7 @@
namespace Kanboard\Filter;
use Kanboard\Core\Filter\FilterInterface;
-use Kanboard\Model\ProjectActivity;
+use Kanboard\Model\ProjectActivityModel;
/**
* Filter activity events by creator
@@ -54,7 +54,7 @@ class ProjectActivityCreatorFilter extends BaseFilter implements FilterInterface
public function apply()
{
if ($this->value === 'me') {
- $this->query->eq(ProjectActivity::TABLE . '.creator_id', $this->currentUserId);
+ $this->query->eq(ProjectActivityModel::TABLE . '.creator_id', $this->currentUserId);
} else {
$this->query->beginOr();
$this->query->ilike('uc.username', '%'.$this->value.'%');
diff --git a/app/Filter/ProjectActivityProjectIdFilter.php b/app/Filter/ProjectActivityProjectIdFilter.php
index bb4d8bd1..7146a057 100644
--- a/app/Filter/ProjectActivityProjectIdFilter.php
+++ b/app/Filter/ProjectActivityProjectIdFilter.php
@@ -3,7 +3,7 @@
namespace Kanboard\Filter;
use Kanboard\Core\Filter\FilterInterface;
-use Kanboard\Model\ProjectActivity;
+use Kanboard\Model\ProjectActivityModel;
/**
* Filter activity events by projectId
@@ -32,7 +32,7 @@ class ProjectActivityProjectIdFilter extends BaseFilter implements FilterInterfa
*/
public function apply()
{
- $this->query->eq(ProjectActivity::TABLE.'.project_id', $this->value);
+ $this->query->eq(ProjectActivityModel::TABLE.'.project_id', $this->value);
return $this;
}
}
diff --git a/app/Filter/ProjectActivityProjectIdsFilter.php b/app/Filter/ProjectActivityProjectIdsFilter.php
index 47cf0c25..70968f79 100644
--- a/app/Filter/ProjectActivityProjectIdsFilter.php
+++ b/app/Filter/ProjectActivityProjectIdsFilter.php
@@ -3,7 +3,7 @@
namespace Kanboard\Filter;
use Kanboard\Core\Filter\FilterInterface;
-use Kanboard\Model\ProjectActivity;
+use Kanboard\Model\ProjectActivityModel;
/**
* Filter activity events by projectIds
@@ -33,9 +33,9 @@ class ProjectActivityProjectIdsFilter extends BaseFilter implements FilterInterf
public function apply()
{
if (empty($this->value)) {
- $this->query->eq(ProjectActivity::TABLE.'.project_id', 0);
+ $this->query->eq(ProjectActivityModel::TABLE.'.project_id', 0);
} else {
- $this->query->in(ProjectActivity::TABLE.'.project_id', $this->value);
+ $this->query->in(ProjectActivityModel::TABLE.'.project_id', $this->value);
}
return $this;
diff --git a/app/Filter/ProjectActivityProjectNameFilter.php b/app/Filter/ProjectActivityProjectNameFilter.php
index 0cf73657..b4872182 100644
--- a/app/Filter/ProjectActivityProjectNameFilter.php
+++ b/app/Filter/ProjectActivityProjectNameFilter.php
@@ -3,7 +3,7 @@
namespace Kanboard\Filter;
use Kanboard\Core\Filter\FilterInterface;
-use Kanboard\Model\Project;
+use Kanboard\Model\ProjectModel;
/**
* Filter activity events by project name
@@ -32,7 +32,7 @@ class ProjectActivityProjectNameFilter extends BaseFilter implements FilterInter
*/
public function apply()
{
- $this->query->ilike(Project::TABLE.'.name', '%'.$this->value.'%');
+ $this->query->ilike(ProjectModel::TABLE.'.name', '%'.$this->value.'%');
return $this;
}
}
diff --git a/app/Filter/ProjectActivityTaskIdFilter.php b/app/Filter/ProjectActivityTaskIdFilter.php
index e99efe09..b8e074db 100644
--- a/app/Filter/ProjectActivityTaskIdFilter.php
+++ b/app/Filter/ProjectActivityTaskIdFilter.php
@@ -3,7 +3,7 @@
namespace Kanboard\Filter;
use Kanboard\Core\Filter\FilterInterface;
-use Kanboard\Model\ProjectActivity;
+use Kanboard\Model\ProjectActivityModel;
/**
* Filter activity events by taskId
@@ -32,7 +32,7 @@ class ProjectActivityTaskIdFilter extends BaseFilter implements FilterInterface
*/
public function apply()
{
- $this->query->eq(ProjectActivity::TABLE.'.task_id', $this->value);
+ $this->query->eq(ProjectActivityModel::TABLE.'.task_id', $this->value);
return $this;
}
}
diff --git a/app/Filter/ProjectActivityTaskStatusFilter.php b/app/Filter/ProjectActivityTaskStatusFilter.php
index 69e2c52d..2c98cabf 100644
--- a/app/Filter/ProjectActivityTaskStatusFilter.php
+++ b/app/Filter/ProjectActivityTaskStatusFilter.php
@@ -3,7 +3,7 @@
namespace Kanboard\Filter;
use Kanboard\Core\Filter\FilterInterface;
-use Kanboard\Model\Task;
+use Kanboard\Model\TaskModel;
/**
* Filter activity events by task status
@@ -33,9 +33,9 @@ class ProjectActivityTaskStatusFilter extends BaseFilter implements FilterInterf
public function apply()
{
if ($this->value === 'open') {
- $this->query->eq(Task::TABLE.'.is_active', Task::STATUS_OPEN);
+ $this->query->eq(TaskModel::TABLE.'.is_active', TaskModel::STATUS_OPEN);
} elseif ($this->value === 'closed') {
- $this->query->eq(Task::TABLE.'.is_active', Task::STATUS_CLOSED);
+ $this->query->eq(TaskModel::TABLE.'.is_active', TaskModel::STATUS_CLOSED);
}
return $this;
diff --git a/app/Filter/ProjectGroupRoleProjectFilter.php b/app/Filter/ProjectGroupRoleProjectFilter.php
index b0950868..035931b3 100644
--- a/app/Filter/ProjectGroupRoleProjectFilter.php
+++ b/app/Filter/ProjectGroupRoleProjectFilter.php
@@ -3,7 +3,7 @@
namespace Kanboard\Filter;
use Kanboard\Core\Filter\FilterInterface;
-use Kanboard\Model\ProjectGroupRole;
+use Kanboard\Model\ProjectGroupRoleModel;
/**
* Filter ProjectGroupRole users by project
@@ -32,7 +32,7 @@ class ProjectGroupRoleProjectFilter extends BaseFilter implements FilterInterfac
*/
public function apply()
{
- $this->query->eq(ProjectGroupRole::TABLE.'.project_id', $this->value);
+ $this->query->eq(ProjectGroupRoleModel::TABLE.'.project_id', $this->value);
return $this;
}
}
diff --git a/app/Filter/ProjectGroupRoleUsernameFilter.php b/app/Filter/ProjectGroupRoleUsernameFilter.php
index c10855bc..9feac33f 100644
--- a/app/Filter/ProjectGroupRoleUsernameFilter.php
+++ b/app/Filter/ProjectGroupRoleUsernameFilter.php
@@ -3,9 +3,9 @@
namespace Kanboard\Filter;
use Kanboard\Core\Filter\FilterInterface;
-use Kanboard\Model\GroupMember;
-use Kanboard\Model\ProjectGroupRole;
-use Kanboard\Model\User;
+use Kanboard\Model\GroupMemberModel;
+use Kanboard\Model\ProjectGroupRoleModel;
+use Kanboard\Model\UserModel;
/**
* Filter ProjectGroupRole users by username
@@ -35,9 +35,9 @@ class ProjectGroupRoleUsernameFilter extends BaseFilter implements FilterInterfa
public function apply()
{
$this->query
- ->join(GroupMember::TABLE, 'group_id', 'group_id', ProjectGroupRole::TABLE)
- ->join(User::TABLE, 'id', 'user_id', GroupMember::TABLE)
- ->ilike(User::TABLE.'.username', $this->value.'%');
+ ->join(GroupMemberModel::TABLE, 'group_id', 'group_id', ProjectGroupRoleModel::TABLE)
+ ->join(UserModel::TABLE, 'id', 'user_id', GroupMemberModel::TABLE)
+ ->ilike(UserModel::TABLE.'.username', $this->value.'%');
return $this;
}
diff --git a/app/Filter/ProjectIdsFilter.php b/app/Filter/ProjectIdsFilter.php
index 641f7f18..9af9db5a 100644
--- a/app/Filter/ProjectIdsFilter.php
+++ b/app/Filter/ProjectIdsFilter.php
@@ -3,7 +3,7 @@
namespace Kanboard\Filter;
use Kanboard\Core\Filter\FilterInterface;
-use Kanboard\Model\Project;
+use Kanboard\Model\ProjectModel;
/**
* Filter project by ids
@@ -33,9 +33,9 @@ class ProjectIdsFilter extends BaseFilter implements FilterInterface
public function apply()
{
if (empty($this->value)) {
- $this->query->eq(Project::TABLE.'.id', 0);
+ $this->query->eq(ProjectModel::TABLE.'.id', 0);
} else {
- $this->query->in(Project::TABLE.'.id', $this->value);
+ $this->query->in(ProjectModel::TABLE.'.id', $this->value);
}
return $this;
diff --git a/app/Filter/ProjectStatusFilter.php b/app/Filter/ProjectStatusFilter.php
index a994600c..c1a06eff 100644
--- a/app/Filter/ProjectStatusFilter.php
+++ b/app/Filter/ProjectStatusFilter.php
@@ -3,7 +3,7 @@
namespace Kanboard\Filter;
use Kanboard\Core\Filter\FilterInterface;
-use Kanboard\Model\Project;
+use Kanboard\Model\ProjectModel;
/**
* Filter project by status
@@ -33,11 +33,11 @@ class ProjectStatusFilter extends BaseFilter implements FilterInterface
public function apply()
{
if (is_int($this->value) || ctype_digit($this->value)) {
- $this->query->eq(Project::TABLE.'.is_active', $this->value);
+ $this->query->eq(ProjectModel::TABLE.'.is_active', $this->value);
} elseif ($this->value === 'inactive' || $this->value === 'closed' || $this->value === 'disabled') {
- $this->query->eq(Project::TABLE.'.is_active', 0);
+ $this->query->eq(ProjectModel::TABLE.'.is_active', 0);
} else {
- $this->query->eq(Project::TABLE.'.is_active', 1);
+ $this->query->eq(ProjectModel::TABLE.'.is_active', 1);
}
return $this;
diff --git a/app/Filter/ProjectTypeFilter.php b/app/Filter/ProjectTypeFilter.php
index e085e2f6..6afcd293 100644
--- a/app/Filter/ProjectTypeFilter.php
+++ b/app/Filter/ProjectTypeFilter.php
@@ -3,7 +3,7 @@
namespace Kanboard\Filter;
use Kanboard\Core\Filter\FilterInterface;
-use Kanboard\Model\Project;
+use Kanboard\Model\ProjectModel;
/**
* Filter project by type
@@ -33,11 +33,11 @@ class ProjectTypeFilter extends BaseFilter implements FilterInterface
public function apply()
{
if (is_int($this->value) || ctype_digit($this->value)) {
- $this->query->eq(Project::TABLE.'.is_private', $this->value);
+ $this->query->eq(ProjectModel::TABLE.'.is_private', $this->value);
} elseif ($this->value === 'private') {
- $this->query->eq(Project::TABLE.'.is_private', Project::TYPE_PRIVATE);
+ $this->query->eq(ProjectModel::TABLE.'.is_private', ProjectModel::TYPE_PRIVATE);
} else {
- $this->query->eq(Project::TABLE.'.is_private', Project::TYPE_TEAM);
+ $this->query->eq(ProjectModel::TABLE.'.is_private', ProjectModel::TYPE_TEAM);
}
return $this;
diff --git a/app/Filter/ProjectUserRoleProjectFilter.php b/app/Filter/ProjectUserRoleProjectFilter.php
index 3b880df5..6952364e 100644
--- a/app/Filter/ProjectUserRoleProjectFilter.php
+++ b/app/Filter/ProjectUserRoleProjectFilter.php
@@ -3,7 +3,7 @@
namespace Kanboard\Filter;
use Kanboard\Core\Filter\FilterInterface;
-use Kanboard\Model\ProjectUserRole;
+use Kanboard\Model\ProjectUserRoleModel;
/**
* Filter ProjectUserRole users by project
@@ -32,7 +32,7 @@ class ProjectUserRoleProjectFilter extends BaseFilter implements FilterInterface
*/
public function apply()
{
- $this->query->eq(ProjectUserRole::TABLE.'.project_id', $this->value);
+ $this->query->eq(ProjectUserRoleModel::TABLE.'.project_id', $this->value);
return $this;
}
}
diff --git a/app/Filter/ProjectUserRoleUsernameFilter.php b/app/Filter/ProjectUserRoleUsernameFilter.php
index c00493a3..327d3d57 100644
--- a/app/Filter/ProjectUserRoleUsernameFilter.php
+++ b/app/Filter/ProjectUserRoleUsernameFilter.php
@@ -3,7 +3,7 @@
namespace Kanboard\Filter;
use Kanboard\Core\Filter\FilterInterface;
-use Kanboard\Model\User;
+use Kanboard\Model\UserModel;
/**
* Filter ProjectUserRole users by username
@@ -33,8 +33,8 @@ class ProjectUserRoleUsernameFilter extends BaseFilter implements FilterInterfac
public function apply()
{
$this->query
- ->join(User::TABLE, 'id', 'user_id')
- ->ilike(User::TABLE.'.username', $this->value.'%');
+ ->join(UserModel::TABLE, 'id', 'user_id')
+ ->ilike(UserModel::TABLE.'.username', $this->value.'%');
return $this;
}
diff --git a/app/Filter/TaskAssigneeFilter.php b/app/Filter/TaskAssigneeFilter.php
index 783d6a12..d6962a93 100644
--- a/app/Filter/TaskAssigneeFilter.php
+++ b/app/Filter/TaskAssigneeFilter.php
@@ -3,8 +3,8 @@
namespace Kanboard\Filter;
use Kanboard\Core\Filter\FilterInterface;
-use Kanboard\Model\Task;
-use Kanboard\Model\User;
+use Kanboard\Model\TaskModel;
+use Kanboard\Model\UserModel;
/**
* Filter tasks by assignee
@@ -55,19 +55,19 @@ class TaskAssigneeFilter extends BaseFilter implements FilterInterface
public function apply()
{
if (is_int($this->value) || ctype_digit($this->value)) {
- $this->query->eq(Task::TABLE.'.owner_id', $this->value);
+ $this->query->eq(TaskModel::TABLE.'.owner_id', $this->value);
} else {
switch ($this->value) {
case 'me':
- $this->query->eq(Task::TABLE.'.owner_id', $this->currentUserId);
+ $this->query->eq(TaskModel::TABLE.'.owner_id', $this->currentUserId);
break;
case 'nobody':
- $this->query->eq(Task::TABLE.'.owner_id', 0);
+ $this->query->eq(TaskModel::TABLE.'.owner_id', 0);
break;
default:
$this->query->beginOr();
- $this->query->ilike(User::TABLE.'.username', '%'.$this->value.'%');
- $this->query->ilike(User::TABLE.'.name', '%'.$this->value.'%');
+ $this->query->ilike(UserModel::TABLE.'.username', '%'.$this->value.'%');
+ $this->query->ilike(UserModel::TABLE.'.name', '%'.$this->value.'%');
$this->query->closeOr();
}
}
diff --git a/app/Filter/TaskCategoryFilter.php b/app/Filter/TaskCategoryFilter.php
index 517f24d9..35c52f69 100644
--- a/app/Filter/TaskCategoryFilter.php
+++ b/app/Filter/TaskCategoryFilter.php
@@ -3,8 +3,8 @@
namespace Kanboard\Filter;
use Kanboard\Core\Filter\FilterInterface;
-use Kanboard\Model\Category;
-use Kanboard\Model\Task;
+use Kanboard\Model\CategoryModel;
+use Kanboard\Model\TaskModel;
/**
* Filter tasks by category
@@ -34,11 +34,11 @@ class TaskCategoryFilter extends BaseFilter implements FilterInterface
public function apply()
{
if (is_int($this->value) || ctype_digit($this->value)) {
- $this->query->eq(Task::TABLE.'.category_id', $this->value);
+ $this->query->eq(TaskModel::TABLE.'.category_id', $this->value);
} elseif ($this->value === 'none') {
- $this->query->eq(Task::TABLE.'.category_id', 0);
+ $this->query->eq(TaskModel::TABLE.'.category_id', 0);
} else {
- $this->query->eq(Category::TABLE.'.name', $this->value);
+ $this->query->eq(CategoryModel::TABLE.'.name', $this->value);
}
return $this;
diff --git a/app/Filter/TaskColorFilter.php b/app/Filter/TaskColorFilter.php
index 784162d4..2ddb47ce 100644
--- a/app/Filter/TaskColorFilter.php
+++ b/app/Filter/TaskColorFilter.php
@@ -3,8 +3,8 @@
namespace Kanboard\Filter;
use Kanboard\Core\Filter\FilterInterface;
-use Kanboard\Model\Color;
-use Kanboard\Model\Task;
+use Kanboard\Model\ColorModel;
+use Kanboard\Model\TaskModel;
/**
* Filter tasks by color
@@ -18,7 +18,7 @@ class TaskColorFilter extends BaseFilter implements FilterInterface
* Color object
*
* @access private
- * @var Color
+ * @var ColorModel
*/
private $colorModel;
@@ -26,10 +26,10 @@ class TaskColorFilter extends BaseFilter implements FilterInterface
* Set color model object
*
* @access public
- * @param Color $colorModel
+ * @param ColorModel $colorModel
* @return TaskColorFilter
*/
- public function setColorModel(Color $colorModel)
+ public function setColorModel(ColorModel $colorModel)
{
$this->colorModel = $colorModel;
return $this;
@@ -54,7 +54,7 @@ class TaskColorFilter extends BaseFilter implements FilterInterface
*/
public function apply()
{
- $this->query->eq(Task::TABLE.'.color_id', $this->colorModel->find($this->value));
+ $this->query->eq(TaskModel::TABLE.'.color_id', $this->colorModel->find($this->value));
return $this;
}
}
diff --git a/app/Filter/TaskColumnFilter.php b/app/Filter/TaskColumnFilter.php
index 9a4d4253..fa925b79 100644
--- a/app/Filter/TaskColumnFilter.php
+++ b/app/Filter/TaskColumnFilter.php
@@ -3,8 +3,8 @@
namespace Kanboard\Filter;
use Kanboard\Core\Filter\FilterInterface;
-use Kanboard\Model\Column;
-use Kanboard\Model\Task;
+use Kanboard\Model\ColumnModel;
+use Kanboard\Model\TaskModel;
/**
* Filter tasks by column
@@ -34,9 +34,9 @@ class TaskColumnFilter extends BaseFilter implements FilterInterface
public function apply()
{
if (is_int($this->value) || ctype_digit($this->value)) {
- $this->query->eq(Task::TABLE.'.column_id', $this->value);
+ $this->query->eq(TaskModel::TABLE.'.column_id', $this->value);
} else {
- $this->query->eq(Column::TABLE.'.title', $this->value);
+ $this->query->eq(ColumnModel::TABLE.'.title', $this->value);
}
return $this;
diff --git a/app/Filter/TaskCommentFilter.php b/app/Filter/TaskCommentFilter.php
index 455098c2..52db5581 100644
--- a/app/Filter/TaskCommentFilter.php
+++ b/app/Filter/TaskCommentFilter.php
@@ -3,8 +3,8 @@
namespace Kanboard\Filter;
use Kanboard\Core\Filter\FilterInterface;
-use Kanboard\Model\Comment;
-use Kanboard\Model\Task;
+use Kanboard\Model\CommentModel;
+use Kanboard\Model\TaskModel;
/**
* Filter tasks by comment
@@ -33,8 +33,8 @@ class TaskCommentFilter extends BaseFilter implements FilterInterface
*/
public function apply()
{
- $this->query->ilike(Comment::TABLE.'.comment', '%'.$this->value.'%');
- $this->query->join(Comment::TABLE, 'task_id', 'id', Task::TABLE);
+ $this->query->ilike(CommentModel::TABLE.'.comment', '%'.$this->value.'%');
+ $this->query->join(CommentModel::TABLE, 'task_id', 'id', TaskModel::TABLE);
return $this;
}
diff --git a/app/Filter/TaskCompletionDateFilter.php b/app/Filter/TaskCompletionDateFilter.php
index f206a3e2..79b5e7d8 100644
--- a/app/Filter/TaskCompletionDateFilter.php
+++ b/app/Filter/TaskCompletionDateFilter.php
@@ -3,7 +3,7 @@
namespace Kanboard\Filter;
use Kanboard\Core\Filter\FilterInterface;
-use Kanboard\Model\Task;
+use Kanboard\Model\TaskModel;
/**
* Filter tasks by completion date
@@ -32,7 +32,7 @@ class TaskCompletionDateFilter extends BaseDateFilter implements FilterInterface
*/
public function apply()
{
- $this->applyDateFilter(Task::TABLE.'.date_completed');
+ $this->applyDateFilter(TaskModel::TABLE.'.date_completed');
return $this;
}
}
diff --git a/app/Filter/TaskCreationDateFilter.php b/app/Filter/TaskCreationDateFilter.php
index bb6efad6..db28ac88 100644
--- a/app/Filter/TaskCreationDateFilter.php
+++ b/app/Filter/TaskCreationDateFilter.php
@@ -3,7 +3,7 @@
namespace Kanboard\Filter;
use Kanboard\Core\Filter\FilterInterface;
-use Kanboard\Model\Task;
+use Kanboard\Model\TaskModel;
/**
* Filter tasks by creation date
@@ -32,7 +32,7 @@ class TaskCreationDateFilter extends BaseDateFilter implements FilterInterface
*/
public function apply()
{
- $this->applyDateFilter(Task::TABLE.'.date_creation');
+ $this->applyDateFilter(TaskModel::TABLE.'.date_creation');
return $this;
}
}
diff --git a/app/Filter/TaskCreatorFilter.php b/app/Filter/TaskCreatorFilter.php
index af35e6bc..611db189 100644
--- a/app/Filter/TaskCreatorFilter.php
+++ b/app/Filter/TaskCreatorFilter.php
@@ -3,7 +3,7 @@
namespace Kanboard\Filter;
use Kanboard\Core\Filter\FilterInterface;
-use Kanboard\Model\Task;
+use Kanboard\Model\TaskModel;
/**
* Filter tasks by creator
@@ -54,14 +54,14 @@ class TaskCreatorFilter extends BaseFilter implements FilterInterface
public function apply()
{
if (is_int($this->value) || ctype_digit($this->value)) {
- $this->query->eq(Task::TABLE.'.creator_id', $this->value);
+ $this->query->eq(TaskModel::TABLE.'.creator_id', $this->value);
} else {
switch ($this->value) {
case 'me':
- $this->query->eq(Task::TABLE.'.creator_id', $this->currentUserId);
+ $this->query->eq(TaskModel::TABLE.'.creator_id', $this->currentUserId);
break;
case 'nobody':
- $this->query->eq(Task::TABLE.'.creator_id', 0);
+ $this->query->eq(TaskModel::TABLE.'.creator_id', 0);
break;
default:
$this->query->beginOr();
diff --git a/app/Filter/TaskDescriptionFilter.php b/app/Filter/TaskDescriptionFilter.php
index 6dda58ae..c73c2f56 100644
--- a/app/Filter/TaskDescriptionFilter.php
+++ b/app/Filter/TaskDescriptionFilter.php
@@ -3,7 +3,7 @@
namespace Kanboard\Filter;
use Kanboard\Core\Filter\FilterInterface;
-use Kanboard\Model\Task;
+use Kanboard\Model\TaskModel;
/**
* Filter tasks by description
@@ -32,7 +32,7 @@ class TaskDescriptionFilter extends BaseFilter implements FilterInterface
*/
public function apply()
{
- $this->query->ilike(Task::TABLE.'.description', '%'.$this->value.'%');
+ $this->query->ilike(TaskModel::TABLE.'.description', '%'.$this->value.'%');
return $this;
}
}
diff --git a/app/Filter/TaskDueDateFilter.php b/app/Filter/TaskDueDateFilter.php
index e36efdd0..0de055bf 100644
--- a/app/Filter/TaskDueDateFilter.php
+++ b/app/Filter/TaskDueDateFilter.php
@@ -3,7 +3,7 @@
namespace Kanboard\Filter;
use Kanboard\Core\Filter\FilterInterface;
-use Kanboard\Model\Task;
+use Kanboard\Model\TaskModel;
/**
* Filter tasks by due date
@@ -32,9 +32,9 @@ class TaskDueDateFilter extends BaseDateFilter implements FilterInterface
*/
public function apply()
{
- $this->query->neq(Task::TABLE.'.date_due', 0);
- $this->query->notNull(Task::TABLE.'.date_due');
- $this->applyDateFilter(Task::TABLE.'.date_due');
+ $this->query->neq(TaskModel::TABLE.'.date_due', 0);
+ $this->query->notNull(TaskModel::TABLE.'.date_due');
+ $this->applyDateFilter(TaskModel::TABLE.'.date_due');
return $this;
}
diff --git a/app/Filter/TaskDueDateRangeFilter.php b/app/Filter/TaskDueDateRangeFilter.php
index 10deb0d3..a6aefbe2 100644
--- a/app/Filter/TaskDueDateRangeFilter.php
+++ b/app/Filter/TaskDueDateRangeFilter.php
@@ -3,7 +3,7 @@
namespace Kanboard\Filter;
use Kanboard\Core\Filter\FilterInterface;
-use Kanboard\Model\Task;
+use Kanboard\Model\TaskModel;
/**
* Filter tasks by due date range
@@ -32,8 +32,8 @@ class TaskDueDateRangeFilter extends BaseFilter implements FilterInterface
*/
public function apply()
{
- $this->query->gte(Task::TABLE.'.date_due', is_numeric($this->value[0]) ? $this->value[0] : strtotime($this->value[0]));
- $this->query->lte(Task::TABLE.'.date_due', is_numeric($this->value[1]) ? $this->value[1] : strtotime($this->value[1]));
+ $this->query->gte(TaskModel::TABLE.'.date_due', is_numeric($this->value[0]) ? $this->value[0] : strtotime($this->value[0]));
+ $this->query->lte(TaskModel::TABLE.'.date_due', is_numeric($this->value[1]) ? $this->value[1] : strtotime($this->value[1]));
return $this;
}
}
diff --git a/app/Filter/TaskIdExclusionFilter.php b/app/Filter/TaskIdExclusionFilter.php
index 8bfefb2b..20177b29 100644
--- a/app/Filter/TaskIdExclusionFilter.php
+++ b/app/Filter/TaskIdExclusionFilter.php
@@ -3,7 +3,7 @@
namespace Kanboard\Filter;
use Kanboard\Core\Filter\FilterInterface;
-use Kanboard\Model\Task;
+use Kanboard\Model\TaskModel;
/**
* Exclude task ids
@@ -32,7 +32,7 @@ class TaskIdExclusionFilter extends BaseFilter implements FilterInterface
*/
public function apply()
{
- $this->query->notin(Task::TABLE.'.id', $this->value);
+ $this->query->notin(TaskModel::TABLE.'.id', $this->value);
return $this;
}
}
diff --git a/app/Filter/TaskIdFilter.php b/app/Filter/TaskIdFilter.php
index 87bac794..fdf668b6 100644
--- a/app/Filter/TaskIdFilter.php
+++ b/app/Filter/TaskIdFilter.php
@@ -3,7 +3,7 @@
namespace Kanboard\Filter;
use Kanboard\Core\Filter\FilterInterface;
-use Kanboard\Model\Task;
+use Kanboard\Model\TaskModel;
/**
* Filter tasks by id
@@ -32,7 +32,7 @@ class TaskIdFilter extends BaseFilter implements FilterInterface
*/
public function apply()
{
- $this->query->eq(Task::TABLE.'.id', $this->value);
+ $this->query->eq(TaskModel::TABLE.'.id', $this->value);
return $this;
}
}
diff --git a/app/Filter/TaskLinkFilter.php b/app/Filter/TaskLinkFilter.php
index 18a13a09..98cd597f 100644
--- a/app/Filter/TaskLinkFilter.php
+++ b/app/Filter/TaskLinkFilter.php
@@ -3,9 +3,9 @@
namespace Kanboard\Filter;
use Kanboard\Core\Filter\FilterInterface;
-use Kanboard\Model\Link;
-use Kanboard\Model\Task;
-use Kanboard\Model\TaskLink;
+use Kanboard\Model\LinkModel;
+use Kanboard\Model\TaskModel;
+use Kanboard\Model\TaskLinkModel;
use PicoDb\Database;
use PicoDb\Table;
@@ -60,9 +60,9 @@ class TaskLinkFilter extends BaseFilter implements FilterInterface
$task_ids = $this->getSubQuery()->findAllByColumn('task_id');
if (! empty($task_ids)) {
- $this->query->in(Task::TABLE.'.id', $task_ids);
+ $this->query->in(TaskModel::TABLE.'.id', $task_ids);
} else {
- $this->query->eq(Task::TABLE.'.id', 0); // No match
+ $this->query->eq(TaskModel::TABLE.'.id', 0); // No match
}
}
@@ -74,12 +74,12 @@ class TaskLinkFilter extends BaseFilter implements FilterInterface
*/
protected function getSubQuery()
{
- return $this->db->table(TaskLink::TABLE)
+ return $this->db->table(TaskLinkModel::TABLE)
->columns(
- TaskLink::TABLE.'.task_id',
- Link::TABLE.'.label'
+ TaskLinkModel::TABLE.'.task_id',
+ LinkModel::TABLE.'.label'
)
- ->join(Link::TABLE, 'id', 'link_id', TaskLink::TABLE)
- ->ilike(Link::TABLE.'.label', $this->value);
+ ->join(LinkModel::TABLE, 'id', 'link_id', TaskLinkModel::TABLE)
+ ->ilike(LinkModel::TABLE.'.label', $this->value);
}
}
diff --git a/app/Filter/TaskModificationDateFilter.php b/app/Filter/TaskModificationDateFilter.php
index 5036e9c1..316f1835 100644
--- a/app/Filter/TaskModificationDateFilter.php
+++ b/app/Filter/TaskModificationDateFilter.php
@@ -3,7 +3,7 @@
namespace Kanboard\Filter;
use Kanboard\Core\Filter\FilterInterface;
-use Kanboard\Model\Task;
+use Kanboard\Model\TaskModel;
/**
* Filter tasks by modification date
@@ -32,7 +32,7 @@ class TaskModificationDateFilter extends BaseDateFilter implements FilterInterfa
*/
public function apply()
{
- $this->applyDateFilter(Task::TABLE.'.date_modification');
+ $this->applyDateFilter(TaskModel::TABLE.'.date_modification');
return $this;
}
}
diff --git a/app/Filter/TaskProjectFilter.php b/app/Filter/TaskProjectFilter.php
index e432efee..0b5a336b 100644
--- a/app/Filter/TaskProjectFilter.php
+++ b/app/Filter/TaskProjectFilter.php
@@ -3,8 +3,8 @@
namespace Kanboard\Filter;
use Kanboard\Core\Filter\FilterInterface;
-use Kanboard\Model\Project;
-use Kanboard\Model\Task;
+use Kanboard\Model\ProjectModel;
+use Kanboard\Model\TaskModel;
/**
* Filter tasks by project
@@ -34,9 +34,9 @@ class TaskProjectFilter extends BaseFilter implements FilterInterface
public function apply()
{
if (is_int($this->value) || ctype_digit($this->value)) {
- $this->query->eq(Task::TABLE.'.project_id', $this->value);
+ $this->query->eq(TaskModel::TABLE.'.project_id', $this->value);
} else {
- $this->query->ilike(Project::TABLE.'.name', $this->value);
+ $this->query->ilike(ProjectModel::TABLE.'.name', $this->value);
}
return $this;
diff --git a/app/Filter/TaskProjectsFilter.php b/app/Filter/TaskProjectsFilter.php
index 47636b1d..2b6b16cb 100644
--- a/app/Filter/TaskProjectsFilter.php
+++ b/app/Filter/TaskProjectsFilter.php
@@ -3,7 +3,7 @@
namespace Kanboard\Filter;
use Kanboard\Core\Filter\FilterInterface;
-use Kanboard\Model\Task;
+use Kanboard\Model\TaskModel;
/**
* Filter tasks by project ids
@@ -33,9 +33,9 @@ class TaskProjectsFilter extends BaseFilter implements FilterInterface
public function apply()
{
if (empty($this->value)) {
- $this->query->eq(Task::TABLE.'.project_id', 0);
+ $this->query->eq(TaskModel::TABLE.'.project_id', 0);
} else {
- $this->query->in(Task::TABLE.'.project_id', $this->value);
+ $this->query->in(TaskModel::TABLE.'.project_id', $this->value);
}
return $this;
diff --git a/app/Filter/TaskReferenceFilter.php b/app/Filter/TaskReferenceFilter.php
index 4ad47dd5..27c838f8 100644
--- a/app/Filter/TaskReferenceFilter.php
+++ b/app/Filter/TaskReferenceFilter.php
@@ -3,7 +3,7 @@
namespace Kanboard\Filter;
use Kanboard\Core\Filter\FilterInterface;
-use Kanboard\Model\Task;
+use Kanboard\Model\TaskModel;
/**
* Filter tasks by reference
@@ -32,7 +32,7 @@ class TaskReferenceFilter extends BaseFilter implements FilterInterface
*/
public function apply()
{
- $this->query->eq(Task::TABLE.'.reference', $this->value);
+ $this->query->eq(TaskModel::TABLE.'.reference', $this->value);
return $this;
}
}
diff --git a/app/Filter/TaskStartDateFilter.php b/app/Filter/TaskStartDateFilter.php
index dd30762b..d5abedb5 100644
--- a/app/Filter/TaskStartDateFilter.php
+++ b/app/Filter/TaskStartDateFilter.php
@@ -3,7 +3,7 @@
namespace Kanboard\Filter;
use Kanboard\Core\Filter\FilterInterface;
-use Kanboard\Model\Task;
+use Kanboard\Model\TaskModel;
/**
* Filter tasks by start date
@@ -32,7 +32,7 @@ class TaskStartDateFilter extends BaseDateFilter implements FilterInterface
*/
public function apply()
{
- $this->applyDateFilter(Task::TABLE.'.date_started');
+ $this->applyDateFilter(TaskModel::TABLE.'.date_started');
return $this;
}
}
diff --git a/app/Filter/TaskStatusFilter.php b/app/Filter/TaskStatusFilter.php
index 0ba4361e..a55532cb 100644
--- a/app/Filter/TaskStatusFilter.php
+++ b/app/Filter/TaskStatusFilter.php
@@ -3,7 +3,7 @@
namespace Kanboard\Filter;
use Kanboard\Core\Filter\FilterInterface;
-use Kanboard\Model\Task;
+use Kanboard\Model\TaskModel;
/**
* Filter tasks by status
@@ -33,9 +33,9 @@ class TaskStatusFilter extends BaseFilter implements FilterInterface
public function apply()
{
if ($this->value === 'open' || $this->value === 'closed') {
- $this->query->eq(Task::TABLE.'.is_active', $this->value === 'open' ? Task::STATUS_OPEN : Task::STATUS_CLOSED);
+ $this->query->eq(TaskModel::TABLE.'.is_active', $this->value === 'open' ? TaskModel::STATUS_OPEN : TaskModel::STATUS_CLOSED);
} else {
- $this->query->eq(Task::TABLE.'.is_active', $this->value);
+ $this->query->eq(TaskModel::TABLE.'.is_active', $this->value);
}
return $this;
diff --git a/app/Filter/TaskSubtaskAssigneeFilter.php b/app/Filter/TaskSubtaskAssigneeFilter.php
index 4c757315..46553a3d 100644
--- a/app/Filter/TaskSubtaskAssigneeFilter.php
+++ b/app/Filter/TaskSubtaskAssigneeFilter.php
@@ -3,9 +3,9 @@
namespace Kanboard\Filter;
use Kanboard\Core\Filter\FilterInterface;
-use Kanboard\Model\Subtask;
-use Kanboard\Model\Task;
-use Kanboard\Model\User;
+use Kanboard\Model\SubtaskModel;
+use Kanboard\Model\TaskModel;
+use Kanboard\Model\UserModel;
use PicoDb\Database;
use PicoDb\Table;
@@ -81,9 +81,9 @@ class TaskSubtaskAssigneeFilter extends BaseFilter implements FilterInterface
$task_ids = $this->getSubQuery()->findAllByColumn('task_id');
if (! empty($task_ids)) {
- $this->query->in(Task::TABLE.'.id', $task_ids);
+ $this->query->in(TaskModel::TABLE.'.id', $task_ids);
} else {
- $this->query->eq(Task::TABLE.'.id', 0); // No match
+ $this->query->eq(TaskModel::TABLE.'.id', 0); // No match
}
}
@@ -95,15 +95,15 @@ class TaskSubtaskAssigneeFilter extends BaseFilter implements FilterInterface
*/
protected function getSubQuery()
{
- $subquery = $this->db->table(Subtask::TABLE)
+ $subquery = $this->db->table(SubtaskModel::TABLE)
->columns(
- Subtask::TABLE.'.user_id',
- Subtask::TABLE.'.task_id',
- User::TABLE.'.name',
- User::TABLE.'.username'
+ SubtaskModel::TABLE.'.user_id',
+ SubtaskModel::TABLE.'.task_id',
+ UserModel::TABLE.'.name',
+ UserModel::TABLE.'.username'
)
- ->join(User::TABLE, 'id', 'user_id', Subtask::TABLE)
- ->neq(Subtask::TABLE.'.status', Subtask::STATUS_DONE);
+ ->join(UserModel::TABLE, 'id', 'user_id', SubtaskModel::TABLE)
+ ->neq(SubtaskModel::TABLE.'.status', SubtaskModel::STATUS_DONE);
return $this->applySubQueryFilter($subquery);
}
@@ -118,19 +118,19 @@ class TaskSubtaskAssigneeFilter extends BaseFilter implements FilterInterface
protected function applySubQueryFilter(Table $subquery)
{
if (is_int($this->value) || ctype_digit($this->value)) {
- $subquery->eq(Subtask::TABLE.'.user_id', $this->value);
+ $subquery->eq(SubtaskModel::TABLE.'.user_id', $this->value);
} else {
switch ($this->value) {
case 'me':
- $subquery->eq(Subtask::TABLE.'.user_id', $this->currentUserId);
+ $subquery->eq(SubtaskModel::TABLE.'.user_id', $this->currentUserId);
break;
case 'nobody':
- $subquery->eq(Subtask::TABLE.'.user_id', 0);
+ $subquery->eq(SubtaskModel::TABLE.'.user_id', 0);
break;
default:
$subquery->beginOr();
- $subquery->ilike(User::TABLE.'.username', $this->value.'%');
- $subquery->ilike(User::TABLE.'.name', '%'.$this->value.'%');
+ $subquery->ilike(UserModel::TABLE.'.username', $this->value.'%');
+ $subquery->ilike(UserModel::TABLE.'.name', '%'.$this->value.'%');
$subquery->closeOr();
}
}
diff --git a/app/Filter/TaskSwimlaneFilter.php b/app/Filter/TaskSwimlaneFilter.php
index 4e030244..07243969 100644
--- a/app/Filter/TaskSwimlaneFilter.php
+++ b/app/Filter/TaskSwimlaneFilter.php
@@ -3,9 +3,9 @@
namespace Kanboard\Filter;
use Kanboard\Core\Filter\FilterInterface;
-use Kanboard\Model\Project;
-use Kanboard\Model\Swimlane;
-use Kanboard\Model\Task;
+use Kanboard\Model\ProjectModel;
+use Kanboard\Model\SwimlaneModel;
+use Kanboard\Model\TaskModel;
/**
* Filter tasks by swimlane
@@ -35,13 +35,13 @@ class TaskSwimlaneFilter extends BaseFilter implements FilterInterface
public function apply()
{
if (is_int($this->value) || ctype_digit($this->value)) {
- $this->query->eq(Task::TABLE.'.swimlane_id', $this->value);
+ $this->query->eq(TaskModel::TABLE.'.swimlane_id', $this->value);
} elseif ($this->value === 'default') {
- $this->query->eq(Task::TABLE.'.swimlane_id', 0);
+ $this->query->eq(TaskModel::TABLE.'.swimlane_id', 0);
} else {
$this->query->beginOr();
- $this->query->ilike(Swimlane::TABLE.'.name', $this->value);
- $this->query->ilike(Project::TABLE.'.default_swimlane', $this->value);
+ $this->query->ilike(SwimlaneModel::TABLE.'.name', $this->value);
+ $this->query->ilike(ProjectModel::TABLE.'.default_swimlane', $this->value);
$this->query->closeOr();
}
diff --git a/app/Filter/TaskTitleFilter.php b/app/Filter/TaskTitleFilter.php
index 9853369c..4e3a2df1 100644
--- a/app/Filter/TaskTitleFilter.php
+++ b/app/Filter/TaskTitleFilter.php
@@ -3,7 +3,7 @@
namespace Kanboard\Filter;
use Kanboard\Core\Filter\FilterInterface;
-use Kanboard\Model\Task;
+use Kanboard\Model\TaskModel;
/**
* Filter tasks by title
@@ -34,11 +34,11 @@ class TaskTitleFilter extends BaseFilter implements FilterInterface
{
if (ctype_digit($this->value) || (strlen($this->value) > 1 && $this->value{0} === '#' && ctype_digit(substr($this->value, 1)))) {
$this->query->beginOr();
- $this->query->eq(Task::TABLE.'.id', str_replace('#', '', $this->value));
- $this->query->ilike(Task::TABLE.'.title', '%'.$this->value.'%');
+ $this->query->eq(TaskModel::TABLE.'.id', str_replace('#', '', $this->value));
+ $this->query->ilike(TaskModel::TABLE.'.title', '%'.$this->value.'%');
$this->query->closeOr();
} else {
- $this->query->ilike(Task::TABLE.'.title', '%'.$this->value.'%');
+ $this->query->ilike(TaskModel::TABLE.'.title', '%'.$this->value.'%');
}
return $this;
diff --git a/app/Formatter/BoardFormatter.php b/app/Formatter/BoardFormatter.php
index 6a96b3e6..dbc7cf21 100644
--- a/app/Formatter/BoardFormatter.php
+++ b/app/Formatter/BoardFormatter.php
@@ -3,7 +3,7 @@
namespace Kanboard\Formatter;
use Kanboard\Core\Filter\FormatterInterface;
-use Kanboard\Model\Task;
+use Kanboard\Model\TaskModel;
/**
* Board Formatter
@@ -43,11 +43,11 @@ class BoardFormatter extends BaseFormatter implements FormatterInterface
public function format()
{
$tasks = $this->query
- ->eq(Task::TABLE.'.project_id', $this->projectId)
- ->asc(Task::TABLE.'.position')
+ ->eq(TaskModel::TABLE.'.project_id', $this->projectId)
+ ->asc(TaskModel::TABLE.'.position')
->findAll();
- return $this->board->getBoard($this->projectId, function ($project_id, $column_id, $swimlane_id) use ($tasks) {
+ return $this->boardModel->getBoard($this->projectId, function ($project_id, $column_id, $swimlane_id) use ($tasks) {
return array_filter($tasks, function (array $task) use ($column_id, $swimlane_id) {
return $task['column_id'] == $column_id && $task['swimlane_id'] == $swimlane_id;
});
diff --git a/app/Formatter/ProjectActivityEventFormatter.php b/app/Formatter/ProjectActivityEventFormatter.php
index ae80e5e7..aa0ea7cd 100644
--- a/app/Formatter/ProjectActivityEventFormatter.php
+++ b/app/Formatter/ProjectActivityEventFormatter.php
@@ -21,7 +21,7 @@ class ProjectActivityEventFormatter extends BaseFormatter implements FormatterIn
unset($event['data']);
$event['author'] = $event['author_name'] ?: $event['author_username'];
- $event['event_title'] = $this->notification->getTitleWithAuthor($event['author'], $event['event_name'], $event);
+ $event['event_title'] = $this->notificationModel->getTitleWithAuthor($event['author'], $event['event_name'], $event);
$event['event_content'] = $this->renderEvent($event);
}
diff --git a/app/Formatter/ProjectGanttFormatter.php b/app/Formatter/ProjectGanttFormatter.php
index aee1f27f..af04f498 100644
--- a/app/Formatter/ProjectGanttFormatter.php
+++ b/app/Formatter/ProjectGanttFormatter.php
@@ -21,7 +21,7 @@ class ProjectGanttFormatter extends BaseFormatter implements FormatterInterface
public function format()
{
$projects = $this->query->findAll();
- $colors = $this->color->getDefaultColors();
+ $colors = $this->colorModel->getDefaultColors();
$bars = array();
foreach ($projects as $project) {
@@ -43,12 +43,12 @@ class ProjectGanttFormatter extends BaseFormatter implements FormatterInterface
(int) date('n', $end),
(int) date('j', $end),
),
- 'link' => $this->helper->url->href('project', 'show', array('project_id' => $project['id'])),
- 'board_link' => $this->helper->url->href('board', 'show', array('project_id' => $project['id'])),
- 'gantt_link' => $this->helper->url->href('gantt', 'project', array('project_id' => $project['id'])),
+ 'link' => $this->helper->url->href('ProjectViewController', 'show', array('project_id' => $project['id'])),
+ 'board_link' => $this->helper->url->href('BoardViewController', 'show', array('project_id' => $project['id'])),
+ 'gantt_link' => $this->helper->url->href('TaskGanttController', 'show', array('project_id' => $project['id'])),
'color' => $color,
'not_defined' => empty($project['start_date']) || empty($project['end_date']),
- 'users' => $this->projectUserRole->getAllUsersGroupedByRole($project['id']),
+ 'users' => $this->projectUserRoleModel->getAllUsersGroupedByRole($project['id']),
);
}
diff --git a/app/Formatter/SubtaskTimeTrackingCalendarFormatter.php b/app/Formatter/SubtaskTimeTrackingCalendarFormatter.php
index c5d4e2be..b7b81d87 100644
--- a/app/Formatter/SubtaskTimeTrackingCalendarFormatter.php
+++ b/app/Formatter/SubtaskTimeTrackingCalendarFormatter.php
@@ -25,10 +25,10 @@ class SubtaskTimeTrackingCalendarFormatter extends BaseFormatter implements Form
'title' => t('#%d', $row['task_id']).' '.$row['subtask_title'].$user,
'start' => date('Y-m-d\TH:i:s', $row['start']),
'end' => date('Y-m-d\TH:i:s', $row['end'] ?: time()),
- 'backgroundColor' => $this->color->getBackgroundColor($row['color_id']),
- 'borderColor' => $this->color->getBorderColor($row['color_id']),
+ 'backgroundColor' => $this->colorModel->getBackgroundColor($row['color_id']),
+ 'borderColor' => $this->colorModel->getBorderColor($row['color_id']),
'textColor' => 'black',
- 'url' => $this->helper->url->to('task', 'show', array('task_id' => $row['task_id'], 'project_id' => $row['project_id'])),
+ 'url' => $this->helper->url->to('TaskViewController', 'show', array('task_id' => $row['task_id'], 'project_id' => $row['project_id'])),
'editable' => false,
);
}
diff --git a/app/Formatter/TaskAutoCompleteFormatter.php b/app/Formatter/TaskAutoCompleteFormatter.php
index 480ee797..4f1c4c69 100644
--- a/app/Formatter/TaskAutoCompleteFormatter.php
+++ b/app/Formatter/TaskAutoCompleteFormatter.php
@@ -3,7 +3,7 @@
namespace Kanboard\Formatter;
use Kanboard\Core\Filter\FormatterInterface;
-use Kanboard\Model\Task;
+use Kanboard\Model\TaskModel;
/**
* Task AutoComplete Formatter
@@ -21,7 +21,7 @@ class TaskAutoCompleteFormatter extends BaseFormatter implements FormatterInterf
*/
public function format()
{
- $tasks = $this->query->columns(Task::TABLE.'.id', Task::TABLE.'.title')->findAll();
+ $tasks = $this->query->columns(TaskModel::TABLE.'.id', TaskModel::TABLE.'.title')->findAll();
foreach ($tasks as &$task) {
$task['value'] = $task['title'];
diff --git a/app/Formatter/TaskCalendarFormatter.php b/app/Formatter/TaskCalendarFormatter.php
index 60b9a062..75d2a83e 100644
--- a/app/Formatter/TaskCalendarFormatter.php
+++ b/app/Formatter/TaskCalendarFormatter.php
@@ -44,13 +44,13 @@ class TaskCalendarFormatter extends BaseTaskCalendarFormatter implements Formatt
foreach ($this->query->findAll() as $task) {
$events[] = array(
- 'timezoneParam' => $this->config->getCurrentTimezone(),
+ 'timezoneParam' => $this->timezoneModel->getCurrentTimezone(),
'id' => $task['id'],
'title' => t('#%d', $task['id']).' '.$task['title'],
- 'backgroundColor' => $this->color->getBackgroundColor($task['color_id']),
- 'borderColor' => $this->color->getBorderColor($task['color_id']),
+ 'backgroundColor' => $this->colorModel->getBackgroundColor($task['color_id']),
+ 'borderColor' => $this->colorModel->getBorderColor($task['color_id']),
'textColor' => 'black',
- 'url' => $this->helper->url->to('task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])),
+ 'url' => $this->helper->url->to('TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])),
'start' => date($this->getDateTimeFormat(), $task[$this->startColumn]),
'end' => date($this->getDateTimeFormat(), $task[$this->endColumn] ?: time()),
'editable' => $this->fullDay,
diff --git a/app/Formatter/TaskGanttFormatter.php b/app/Formatter/TaskGanttFormatter.php
index 3209aa37..ddb3f93a 100644
--- a/app/Formatter/TaskGanttFormatter.php
+++ b/app/Formatter/TaskGanttFormatter.php
@@ -47,7 +47,7 @@ class TaskGanttFormatter extends BaseFormatter implements FormatterInterface
private function formatTask(array $task)
{
if (! isset($this->columns[$task['project_id']])) {
- $this->columns[$task['project_id']] = $this->column->getList($task['project_id']);
+ $this->columns[$task['project_id']] = $this->columnModel->getList($task['project_id']);
}
$start = $task['date_started'] ?: time();
@@ -69,9 +69,9 @@ class TaskGanttFormatter extends BaseFormatter implements FormatterInterface
),
'column_title' => $task['column_name'],
'assignee' => $task['assignee_name'] ?: $task['assignee_username'],
- 'progress' => $this->task->getProgress($task, $this->columns[$task['project_id']]).'%',
- 'link' => $this->helper->url->href('task', 'show', array('project_id' => $task['project_id'], 'task_id' => $task['id'])),
- 'color' => $this->color->getColorProperties($task['color_id']),
+ 'progress' => $this->taskModel->getProgress($task, $this->columns[$task['project_id']]).'%',
+ 'link' => $this->helper->url->href('TaskViewController', 'show', array('project_id' => $task['project_id'], 'task_id' => $task['id'])),
+ 'color' => $this->colorModel->getColorProperties($task['color_id']),
'not_defined' => empty($task['date_due']) || empty($task['date_started']),
);
}
diff --git a/app/Formatter/TaskICalFormatter.php b/app/Formatter/TaskICalFormatter.php
index a149f725..890674c7 100644
--- a/app/Formatter/TaskICalFormatter.php
+++ b/app/Formatter/TaskICalFormatter.php
@@ -117,7 +117,7 @@ class TaskICalFormatter extends BaseTaskCalendarFormatter implements FormatterIn
$vEvent->setModified($dateModif);
$vEvent->setUseTimezone(true);
$vEvent->setSummary(t('#%d', $task['id']).' '.$task['title']);
- $vEvent->setUrl($this->helper->url->base().$this->helper->url->to('task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])));
+ $vEvent->setUrl($this->helper->url->base().$this->helper->url->to('TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])));
if (! empty($task['owner_id'])) {
$vEvent->setOrganizer($task['assignee_name'] ?: $task['assignee_username'], $task['assignee_email']);
diff --git a/app/Formatter/UserAutoCompleteFormatter.php b/app/Formatter/UserAutoCompleteFormatter.php
index c46a24d0..cd23a2a4 100644
--- a/app/Formatter/UserAutoCompleteFormatter.php
+++ b/app/Formatter/UserAutoCompleteFormatter.php
@@ -2,7 +2,7 @@
namespace Kanboard\Formatter;
-use Kanboard\Model\User;
+use Kanboard\Model\UserModel;
use Kanboard\Core\Filter\FormatterInterface;
/**
@@ -21,7 +21,7 @@ class UserAutoCompleteFormatter extends BaseFormatter implements FormatterInterf
*/
public function format()
{
- $users = $this->query->columns(User::TABLE.'.id', User::TABLE.'.username', User::TABLE.'.name')->findAll();
+ $users = $this->query->columns(UserModel::TABLE.'.id', UserModel::TABLE.'.username', UserModel::TABLE.'.name')->findAll();
foreach ($users as &$user) {
$user['value'] = $user['username'].' (#'.$user['id'].')';
diff --git a/app/Group/DatabaseBackendGroupProvider.php b/app/Group/DatabaseBackendGroupProvider.php
index 6dbaa43c..29d04d57 100644
--- a/app/Group/DatabaseBackendGroupProvider.php
+++ b/app/Group/DatabaseBackendGroupProvider.php
@@ -23,7 +23,7 @@ class DatabaseBackendGroupProvider extends Base implements GroupBackendProviderI
public function find($input)
{
$result = array();
- $groups = $this->group->search($input);
+ $groups = $this->groupModel->search($input);
foreach ($groups as $group) {
$result[] = new DatabaseGroupProvider($group);
diff --git a/app/Helper/AppHelper.php b/app/Helper/AppHelper.php
index e6f6412d..b738f85c 100644
--- a/app/Helper/AppHelper.php
+++ b/app/Helper/AppHelper.php
@@ -22,7 +22,7 @@ class AppHelper extends Base
*/
public function config($param, $default_value = '')
{
- return $this->config->get($param, $default_value);
+ return $this->configModel->get($param, $default_value);
}
/**
@@ -90,7 +90,7 @@ class AppHelper extends Base
*/
public function jsLang()
{
- return $this->config->getJsLanguageCode();
+ return $this->languageModel->getJsLanguageCode();
}
/**
@@ -101,7 +101,7 @@ class AppHelper extends Base
*/
public function getTimezone()
{
- return $this->config->getCurrentTimezone();
+ return $this->timezoneModel->getCurrentTimezone();
}
/**
diff --git a/app/Helper/AssetHelper.php b/app/Helper/AssetHelper.php
index b3dc711f..dad1448a 100644
--- a/app/Helper/AssetHelper.php
+++ b/app/Helper/AssetHelper.php
@@ -45,8 +45,8 @@ class AssetHelper extends Base
*/
public function customCss()
{
- if ($this->config->get('application_stylesheet')) {
- return '<style>'.$this->config->get('application_stylesheet').'</style>';
+ if ($this->configModel->get('application_stylesheet')) {
+ return '<style>'.$this->configModel->get('application_stylesheet').'</style>';
}
return '';
@@ -60,6 +60,6 @@ class AssetHelper extends Base
*/
public function colorCss()
{
- return '<style>'.$this->color->getCss().'</style>';
+ return '<style>'.$this->colorModel->getCss().'</style>';
}
}
diff --git a/app/Helper/CalendarHelper.php b/app/Helper/CalendarHelper.php
index d5f4af21..b35c40f7 100644
--- a/app/Helper/CalendarHelper.php
+++ b/app/Helper/CalendarHelper.php
@@ -47,7 +47,7 @@ class CalendarHelper extends Base
*/
public function getTaskEvents(QueryBuilder $queryBuilder, $start, $end)
{
- $startColumn = $this->config->get('calendar_project_tasks', 'date_started');
+ $startColumn = $this->configModel->get('calendar_project_tasks', 'date_started');
$queryBuilder->getQuery()->addCondition($this->getCalendarCondition(
$this->dateParser->getTimestampFromIsoFormat($start),
@@ -75,7 +75,7 @@ class CalendarHelper extends Base
{
$formatter = new SubtaskTimeTrackingCalendarFormatter($this->container);
return $formatter
- ->withQuery($this->subtaskTimeTracking->getUserQuery($user_id)
+ ->withQuery($this->subtaskTimeTrackingModel->getUserQuery($user_id)
->addCondition($this->getCalendarCondition(
$this->dateParser->getTimestampFromIsoFormat($start),
$this->dateParser->getTimestampFromIsoFormat($end),
diff --git a/app/Helper/DateHelper.php b/app/Helper/DateHelper.php
index 3844ce64..7e2ec79c 100644
--- a/app/Helper/DateHelper.php
+++ b/app/Helper/DateHelper.php
@@ -22,7 +22,7 @@ class DateHelper extends Base
*/
public function time($value)
{
- return date($this->config->get('application_time_format', 'H:i'), $value);
+ return date($this->configModel->get('application_time_format', 'H:i'), $value);
}
/**
@@ -42,7 +42,7 @@ class DateHelper extends Base
$value = strtotime($value);
}
- return date($this->config->get('application_date_format', 'm/d/Y'), $value);
+ return date($this->configModel->get('application_date_format', 'm/d/Y'), $value);
}
/**
@@ -54,7 +54,7 @@ class DateHelper extends Base
*/
public function datetime($value)
{
- return date($this->config->get('application_datetime_format', 'm/d/Y H:i'), $value);
+ return date($this->configModel->get('application_datetime_format', 'm/d/Y H:i'), $value);
}
/**
diff --git a/app/Helper/LayoutHelper.php b/app/Helper/LayoutHelper.php
index 9384da1b..8ebb05d4 100644
--- a/app/Helper/LayoutHelper.php
+++ b/app/Helper/LayoutHelper.php
@@ -27,7 +27,7 @@ class LayoutHelper extends Base
}
if (! isset($params['no_layout']) && ! isset($params['board_selector'])) {
- $params['board_selector'] = $this->projectUserRole->getActiveProjectsByUser($this->userSession->getId());
+ $params['board_selector'] = $this->projectUserRoleModel->getActiveProjectsByUser($this->userSession->getId());
}
return $this->pageLayout($template, $params);
@@ -47,7 +47,7 @@ class LayoutHelper extends Base
$params['title'] = '#'.$params['user']['id'].' '.($params['user']['name'] ?: $params['user']['username']);
}
- return $this->subLayout('user/layout', 'user/sidebar', $template, $params);
+ return $this->subLayout('user_view/layout', 'user_view/sidebar', $template, $params);
}
/**
@@ -60,6 +60,7 @@ class LayoutHelper extends Base
*/
public function task($template, array $params)
{
+ $params['page_title'] = $params['task']['project_name'].', #'.$params['task']['id'].' - '.$params['task']['title'];
$params['title'] = $params['task']['project_name'];
return $this->subLayout('task/layout', 'task/sidebar', $template, $params);
}
@@ -95,7 +96,7 @@ class LayoutHelper extends Base
public function projectUser($template, array $params)
{
$params['filter'] = array('user_id' => $params['user_id']);
- return $this->subLayout('project_user/layout', 'project_user/sidebar', $template, $params);
+ return $this->subLayout('project_user_overview/layout', 'project_user_overview/sidebar', $template, $params);
}
/**
@@ -109,7 +110,7 @@ class LayoutHelper extends Base
public function config($template, array $params)
{
if (! isset($params['values'])) {
- $params['values'] = $this->config->getAll();
+ $params['values'] = $this->configModel->getAll();
}
if (! isset($params['errors'])) {
@@ -120,6 +121,19 @@ class LayoutHelper extends Base
}
/**
+ * Common layout for plugin views
+ *
+ * @access public
+ * @param string $template
+ * @param array $params
+ * @return string
+ */
+ public function plugin($template, array $params)
+ {
+ return $this->subLayout('plugin/layout', 'plugin/sidebar', $template, $params);
+ }
+
+ /**
* Common layout for dashboard views
*
* @access public
@@ -129,7 +143,7 @@ class LayoutHelper extends Base
*/
public function dashboard($template, array $params)
{
- return $this->subLayout('app/layout', 'app/sidebar', $template, $params);
+ return $this->subLayout('dashboard/layout', 'dashboard/sidebar', $template, $params);
}
/**
diff --git a/app/Helper/MailHelper.php b/app/Helper/MailHelper.php
new file mode 100644
index 00000000..12e7f05f
--- /dev/null
+++ b/app/Helper/MailHelper.php
@@ -0,0 +1,65 @@
+<?php
+
+namespace Kanboard\Helper;
+
+use Kanboard\Core\Base;
+
+/**
+ * Class MailHelper
+ *
+ * @package Kanboard\Helper
+ * @author Frederic Guillot
+ */
+class MailHelper extends Base
+{
+ /**
+ * Get the mailbox hash from an email address
+ *
+ * @access public
+ * @param string $email
+ * @return string
+ */
+ public function getMailboxHash($email)
+ {
+ if (! strpos($email, '@') || ! strpos($email, '+')) {
+ return '';
+ }
+
+ list($localPart, ) = explode('@', $email);
+ list(, $identifier) = explode('+', $localPart);
+
+ return $identifier;
+ }
+
+ /**
+ * Filter mail subject
+ *
+ * @access public
+ * @param string $subject
+ * @return string
+ */
+ public function filterSubject($subject)
+ {
+ $subject = str_replace('RE: ', '', $subject);
+ $subject = str_replace('FW: ', '', $subject);
+
+ return $subject;
+ }
+
+ /**
+ * Get mail sender address
+ *
+ * @access public
+ * @return string
+ */
+ public function getMailSenderAddress()
+ {
+ $email = $this->configModel->get('mail_sender_address');
+
+ if (!empty($email)) {
+ return $email;
+ }
+
+ return MAIL_FROM;
+ }
+}
diff --git a/app/Helper/ProjectActivityHelper.php b/app/Helper/ProjectActivityHelper.php
index 0638a978..40f386db 100644
--- a/app/Helper/ProjectActivityHelper.php
+++ b/app/Helper/ProjectActivityHelper.php
@@ -7,7 +7,7 @@ use Kanboard\Filter\ProjectActivityProjectIdFilter;
use Kanboard\Filter\ProjectActivityProjectIdsFilter;
use Kanboard\Filter\ProjectActivityTaskIdFilter;
use Kanboard\Formatter\ProjectActivityEventFormatter;
-use Kanboard\Model\ProjectActivity;
+use Kanboard\Model\ProjectActivityModel;
/**
* Project Activity Helper
@@ -26,7 +26,7 @@ class ProjectActivityHelper extends Base
*/
public function searchEvents($search)
{
- $projects = $this->projectUserRole->getProjectsByUser($this->userSession->getId());
+ $projects = $this->projectUserRoleModel->getProjectsByUser($this->userSession->getId());
$events = array();
if ($search !== '') {
@@ -34,7 +34,7 @@ class ProjectActivityHelper extends Base
$queryBuilder
->withFilter(new ProjectActivityProjectIdsFilter(array_keys($projects)))
->getQuery()
- ->desc(ProjectActivity::TABLE.'.id')
+ ->desc(ProjectActivityModel::TABLE.'.id')
->limit(500)
;
@@ -58,7 +58,7 @@ class ProjectActivityHelper extends Base
->withFilter(new ProjectActivityProjectIdFilter($project_id));
$queryBuilder->getQuery()
- ->desc(ProjectActivity::TABLE.'.id')
+ ->desc(ProjectActivityModel::TABLE.'.id')
->limit($limit)
;
@@ -79,7 +79,7 @@ class ProjectActivityHelper extends Base
->withFilter(new ProjectActivityProjectIdsFilter($project_ids));
$queryBuilder->getQuery()
- ->desc(ProjectActivity::TABLE.'.id')
+ ->desc(ProjectActivityModel::TABLE.'.id')
->limit($limit)
;
@@ -98,7 +98,7 @@ class ProjectActivityHelper extends Base
$queryBuilder = $this->projectActivityQuery
->withFilter(new ProjectActivityTaskIdFilter($task_id));
- $queryBuilder->getQuery()->desc(ProjectActivity::TABLE.'.id');
+ $queryBuilder->getQuery()->desc(ProjectActivityModel::TABLE.'.id');
return $queryBuilder->format(new ProjectActivityEventFormatter($this->container));
}
diff --git a/app/Helper/ProjectHeaderHelper.php b/app/Helper/ProjectHeaderHelper.php
index 19570059..9514f4f2 100644
--- a/app/Helper/ProjectHeaderHelper.php
+++ b/app/Helper/ProjectHeaderHelper.php
@@ -48,9 +48,9 @@ class ProjectHeaderHelper extends Base
return $this->template->render('project_header/header', array(
'project' => $project,
'filters' => $filters,
- 'categories_list' => $this->category->getList($project['id'], false),
- 'users_list' => $this->projectUserRole->getAssignableUsersList($project['id'], false),
- 'custom_filters_list' => $this->customFilter->getAll($project['id'], $this->userSession->getId()),
+ 'categories_list' => $this->categoryModel->getList($project['id'], false),
+ 'users_list' => $this->projectUserRoleModel->getAssignableUsersList($project['id'], false),
+ 'custom_filters_list' => $this->customFilterModel->getAll($project['id'], $this->userSession->getId()),
'board_view' => $boardView,
));
}
diff --git a/app/Helper/SubtaskHelper.php b/app/Helper/SubtaskHelper.php
index afa3c14e..dac71203 100644
--- a/app/Helper/SubtaskHelper.php
+++ b/app/Helper/SubtaskHelper.php
@@ -36,18 +36,18 @@ class SubtaskHelper extends Base
*/
public function toggleStatus(array $subtask, $project_id, $refresh_table = false)
{
- if (! $this->helper->user->hasProjectAccess('subtask', 'edit', $project_id)) {
+ if (! $this->helper->user->hasProjectAccess('SubtaskController', 'edit', $project_id)) {
return $this->getTitle($subtask);
}
$params = array('task_id' => $subtask['task_id'], 'subtask_id' => $subtask['id'], 'refresh-table' => (int) $refresh_table);
if ($subtask['status'] == 0 && isset($this->sessionStorage->hasSubtaskInProgress) && $this->sessionStorage->hasSubtaskInProgress) {
- return $this->helper->url->link($this->getTitle($subtask), 'SubtaskRestriction', 'popover', $params, false, 'popover');
+ return $this->helper->url->link($this->getTitle($subtask), 'SubtaskRestrictionController', 'show', $params, false, 'popover');
}
$class = 'subtask-toggle-status '.($refresh_table ? 'subtask-refresh-table' : '');
- return $this->helper->url->link($this->getTitle($subtask), 'SubtaskStatus', 'change', $params, false, $class);
+ return $this->helper->url->link($this->getTitle($subtask), 'SubtaskStatusController', 'change', $params, false, $class);
}
public function selectTitle(array $values, array $errors = array(), array $attributes = array())
diff --git a/app/Helper/TaskHelper.php b/app/Helper/TaskHelper.php
index 4857d0ee..e33438d6 100644
--- a/app/Helper/TaskHelper.php
+++ b/app/Helper/TaskHelper.php
@@ -22,27 +22,22 @@ class TaskHelper extends Base
public function getColors()
{
- return $this->color->getList();
+ return $this->colorModel->getList();
}
public function recurrenceTriggers()
{
- return $this->task->getRecurrenceTriggerList();
+ return $this->taskModel->getRecurrenceTriggerList();
}
public function recurrenceTimeframes()
{
- return $this->task->getRecurrenceTimeframeList();
+ return $this->taskModel->getRecurrenceTimeframeList();
}
public function recurrenceBasedates()
{
- return $this->task->getRecurrenceBasedateList();
- }
-
- public function canRemove(array $task)
- {
- return $this->taskPermission->canRemoveTask($task);
+ return $this->taskModel->getRecurrenceBasedateList();
}
public function selectAssignee(array $users, array $values, array $errors = array(), array $attributes = array())
@@ -142,7 +137,7 @@ class TaskHelper extends Base
public function selectStartDate(array $values, array $errors = array(), array $attributes = array())
{
- $placeholder = date($this->config->get('application_date_format', 'm/d/Y H:i'));
+ $placeholder = date($this->configModel->get('application_date_format', 'm/d/Y H:i'));
$attributes = array_merge(array('tabindex="11"', 'placeholder="'.$placeholder.'"'), $attributes);
$html = $this->helper->form->label(t('Start Date'), 'date_started');
@@ -153,7 +148,7 @@ class TaskHelper extends Base
public function selectDueDate(array $values, array $errors = array(), array $attributes = array())
{
- $placeholder = date($this->config->get('application_date_format', 'm/d/Y'));
+ $placeholder = date($this->configModel->get('application_date_format', 'm/d/Y'));
$attributes = array_merge(array('tabindex="12"', 'placeholder="'.$placeholder.'"'), $attributes);
$html = $this->helper->form->label(t('Due Date'), 'date_due');
@@ -178,9 +173,9 @@ class TaskHelper extends Base
public function getProgress($task)
{
if (! isset($this->columns[$task['project_id']])) {
- $this->columns[$task['project_id']] = $this->column->getList($task['project_id']);
+ $this->columns[$task['project_id']] = $this->columnModel->getList($task['project_id']);
}
- return $this->task->getProgress($task, $this->columns[$task['project_id']]);
+ return $this->taskModel->getProgress($task, $this->columns[$task['project_id']]);
}
}
diff --git a/app/Helper/TextHelper.php b/app/Helper/TextHelper.php
index e5aefdcf..654eb171 100644
--- a/app/Helper/TextHelper.php
+++ b/app/Helper/TextHelper.php
@@ -27,18 +27,30 @@ class TextHelper extends Base
/**
* Markdown transformation
*
- * @param string $text Markdown content
- * @param array $link Link parameters for replacement
+ * @param string $text
+ * @param boolean $isPublicLink
* @return string
*/
- public function markdown($text, array $link = array())
+ public function markdown($text, $isPublicLink = false)
{
- $parser = new Markdown($this->container, $link);
+ $parser = new Markdown($this->container, $isPublicLink);
$parser->setMarkupEscaped(MARKDOWN_ESCAPE_HTML);
return $parser->text($text);
}
/**
+ * Escape Markdown text that need to be stored in HTML attribute
+ *
+ * @access public
+ * @param string $text
+ * @return mixed
+ */
+ public function markdownAttribute($text)
+ {
+ return htmlentities($this->markdown($text), ENT_QUOTES, 'UTF-8');
+ }
+
+ /**
* Format a file size
*
* @param integer $size Size in bytes
diff --git a/app/Helper/UrlHelper.php b/app/Helper/UrlHelper.php
index 095c4af4..2127c69e 100644
--- a/app/Helper/UrlHelper.php
+++ b/app/Helper/UrlHelper.php
@@ -25,7 +25,7 @@ class UrlHelper extends Base
*/
public function doc($label, $file)
{
- return $this->link($label, 'doc', 'show', array('file' => $file), false, '', '', true);
+ return $this->link($label, 'DocumentationController', 'show', array('file' => $file), false, '', '', true);
}
/**
@@ -109,7 +109,7 @@ class UrlHelper extends Base
public function base()
{
if (empty($this->base)) {
- $this->base = $this->config->get('application_url') ?: $this->server();
+ $this->base = $this->configModel->get('application_url') ?: $this->server();
}
return $this->base;
diff --git a/app/Helper/UserHelper.php b/app/Helper/UserHelper.php
index c3369dfd..ae3efe1d 100644
--- a/app/Helper/UserHelper.php
+++ b/app/Helper/UserHelper.php
@@ -3,6 +3,7 @@
namespace Kanboard\Helper;
use Kanboard\Core\Base;
+use Kanboard\Core\Security\Role;
/**
* User helpers
@@ -20,7 +21,7 @@ class UserHelper extends Base
*/
public function hasNotifications()
{
- return $this->userUnreadNotification->hasNotifications($this->userSession->getId());
+ return $this->userUnreadNotificationModel->hasNotifications($this->userSession->getId());
}
/**
@@ -35,10 +36,21 @@ class UserHelper extends Base
$initials = '';
foreach (explode(' ', $name, 2) as $string) {
- $initials .= mb_substr($string, 0, 1);
+ $initials .= mb_substr($string, 0, 1, 'UTF-8');
}
- return mb_strtoupper($initials);
+ return mb_strtoupper($initials, 'UTF-8');
+ }
+
+ /**
+ * Return the user full name
+ *
+ * @param array $user User properties
+ * @return string
+ */
+ public function getFullname(array $user = array())
+ {
+ return $this->userModel->getFullname(empty($user) ? $this->userSession->getAll() : $user);
}
/**
@@ -145,17 +157,28 @@ class UserHelper extends Base
*/
public function getProjectUserRole($project_id)
{
- return $this->memoryCache->proxy($this->projectUserRole, 'getUserRole', $project_id, $this->userSession->getId());
+ return $this->memoryCache->proxy($this->projectUserRoleModel, 'getUserRole', $project_id, $this->userSession->getId());
}
/**
- * Return the user full name
+ * Return true if the user can remove a task
*
- * @param array $user User properties
- * @return string
+ * Regular users can't remove tasks from other people
+ *
+ * @public
+ * @param array $task
+ * @return bool
*/
- public function getFullname(array $user = array())
+ public function canRemoveTask(array $task)
{
- return $this->user->getFullname(empty($user) ? $this->userSession->getAll() : $user);
+ if (isset($task['creator_id']) && $task['creator_id'] == $this->userSession->getId()) {
+ return true;
+ }
+
+ if ($this->userSession->isAdmin() || $this->getProjectUserRole($task['project_id']) === Role::PROJECT_MANAGER) {
+ return true;
+ }
+
+ return false;
}
}
diff --git a/app/Import/TaskImport.php b/app/Import/TaskImport.php
index 2abafe14..f5ca9b0e 100644
--- a/app/Import/TaskImport.php
+++ b/app/Import/TaskImport.php
@@ -69,7 +69,7 @@ class TaskImport extends Base
$row = $this->prepare($row);
if ($this->validateCreation($row)) {
- if ($this->taskCreation->create($row) > 0) {
+ if ($this->taskCreationModel->create($row) > 0) {
$this->logger->debug('TaskImport: imported successfully line '.$line_number);
$this->counter++;
} else {
@@ -100,27 +100,27 @@ class TaskImport extends Base
$values['time_spent'] = (float) $row['time_spent'];
if (! empty($row['assignee'])) {
- $values['owner_id'] = $this->user->getIdByUsername($row['assignee']);
+ $values['owner_id'] = $this->userModel->getIdByUsername($row['assignee']);
}
if (! empty($row['creator'])) {
- $values['creator_id'] = $this->user->getIdByUsername($row['creator']);
+ $values['creator_id'] = $this->userModel->getIdByUsername($row['creator']);
}
if (! empty($row['color'])) {
- $values['color_id'] = $this->color->find($row['color']);
+ $values['color_id'] = $this->colorModel->find($row['color']);
}
if (! empty($row['column'])) {
- $values['column_id'] = $this->column->getColumnIdByTitle($this->projectId, $row['column']);
+ $values['column_id'] = $this->columnModel->getColumnIdByTitle($this->projectId, $row['column']);
}
if (! empty($row['category'])) {
- $values['category_id'] = $this->category->getIdByName($this->projectId, $row['category']);
+ $values['category_id'] = $this->categoryModel->getIdByName($this->projectId, $row['category']);
}
if (! empty($row['swimlane'])) {
- $values['swimlane_id'] = $this->swimlane->getIdByName($this->projectId, $row['swimlane']);
+ $values['swimlane_id'] = $this->swimlaneModel->getIdByName($this->projectId, $row['swimlane']);
}
if (! empty($row['date_due'])) {
diff --git a/app/Import/UserImport.php b/app/Import/UserImport.php
index 64300d77..304a3254 100644
--- a/app/Import/UserImport.php
+++ b/app/Import/UserImport.php
@@ -2,7 +2,7 @@
namespace Kanboard\Import;
-use Kanboard\Model\User;
+use Kanboard\Model\UserModel;
use SimpleValidator\Validator;
use SimpleValidator\Validators;
use Kanboard\Core\Security\Role;
@@ -56,7 +56,7 @@ class UserImport extends Base
$row = $this->prepare($row);
if ($this->validateCreation($row)) {
- if ($this->user->create($row)) {
+ if ($this->userModel->create($row) !== false) {
$this->logger->debug('UserImport: imported successfully line '.$line_number);
$this->counter++;
} else {
@@ -109,7 +109,7 @@ class UserImport extends Base
{
$v = new Validator($values, array(
new Validators\MaxLength('username', t('The maximum length is %d characters', 50), 50),
- new Validators\Unique('username', t('The username must be unique'), $this->db->getConnection(), User::TABLE, 'id'),
+ new Validators\Unique('username', t('The username must be unique'), $this->db->getConnection(), UserModel::TABLE, 'id'),
new Validators\MinLength('password', t('The minimum length is %d characters', 6), 6),
new Validators\Email('email', t('Email address invalid')),
new Validators\Integer('is_ldap_user', t('This value must be an integer')),
diff --git a/app/Job/BaseJob.php b/app/Job/BaseJob.php
new file mode 100644
index 00000000..60522ac6
--- /dev/null
+++ b/app/Job/BaseJob.php
@@ -0,0 +1,33 @@
+<?php
+
+namespace Kanboard\Job;
+
+use Kanboard\Core\Base;
+
+/**
+ * Class BaseJob
+ *
+ * @package Kanboard\Job
+ * @author Frederic Guillot
+ */
+abstract class BaseJob extends Base
+{
+ /**
+ * Job parameters
+ *
+ * @access protected
+ * @var array
+ */
+ protected $jobParams = array();
+
+ /**
+ * Get job parameters
+ *
+ * @access public
+ * @return array
+ */
+ public function getJobParams()
+ {
+ return $this->jobParams;
+ }
+}
diff --git a/app/Job/EmailJob.php b/app/Job/EmailJob.php
new file mode 100644
index 00000000..9293a1d4
--- /dev/null
+++ b/app/Job/EmailJob.php
@@ -0,0 +1,54 @@
+<?php
+
+namespace Kanboard\Job;
+
+/**
+ * Class EmailJob
+ *
+ * @package Kanboard\Job
+ * @author Frederic Guillot
+ */
+class EmailJob extends BaseJob
+{
+ /**
+ * Set job parameters
+ *
+ * @access public
+ * @param string $email
+ * @param string $name
+ * @param string $subject
+ * @param string $html
+ * @param string $author
+ * @return $this
+ */
+ public function withParams($email, $name, $subject, $html, $author)
+ {
+ $this->jobParams = array($email, $name, $subject, $html, $author);
+ return $this;
+ }
+
+ /**
+ * Execute job
+ *
+ * @access public
+ * @param string $email
+ * @param string $name
+ * @param string $subject
+ * @param string $html
+ * @param string $author
+ */
+ public function execute($email, $name, $subject, $html, $author)
+ {
+ $this->logger->debug(__METHOD__.' Sending email to '.$email.' via '.MAIL_TRANSPORT);
+ $startTime = microtime(true);
+
+ $this->emailClient
+ ->getTransport(MAIL_TRANSPORT)
+ ->sendEmail($email, $name, $subject, $html, $author)
+ ;
+
+ if (DEBUG) {
+ $this->logger->debug('Email sent in '.round(microtime(true) - $startTime, 6).' seconds');
+ }
+ }
+}
diff --git a/app/Job/NotificationJob.php b/app/Job/NotificationJob.php
new file mode 100644
index 00000000..904a9273
--- /dev/null
+++ b/app/Job/NotificationJob.php
@@ -0,0 +1,85 @@
+<?php
+
+namespace Kanboard\Job;
+
+use Kanboard\Event\GenericEvent;
+
+/**
+ * Class NotificationJob
+ *
+ * @package Kanboard\Job
+ * @author Frederic Guillot
+ */
+class NotificationJob extends BaseJob
+{
+ /**
+ * Set job parameters
+ *
+ * @param GenericEvent $event
+ * @param string $eventName
+ * @param string $eventObjectName
+ * @return $this
+ */
+ public function withParams(GenericEvent $event, $eventName, $eventObjectName)
+ {
+ $this->jobParams = array($event->getAll(), $eventName, $eventObjectName);
+ return $this;
+ }
+
+ /**
+ * Execute job
+ *
+ * @param array $event
+ * @param string $eventName
+ * @param string $eventObjectName
+ */
+ public function execute(array $event, $eventName, $eventObjectName)
+ {
+ $eventData = $this->getEventData($event, $eventObjectName);
+
+ if (! empty($eventData)) {
+ if (! empty($event['mention'])) {
+ $this->userNotificationModel->sendUserNotification($event['mention'], $eventName, $eventData);
+ } else {
+ $this->userNotificationModel->sendNotifications($eventName, $eventData);
+ $this->projectNotificationModel->sendNotifications($eventData['task']['project_id'], $eventName, $eventData);
+ }
+ }
+ }
+
+ /**
+ * Get event data
+ *
+ * @param array $event
+ * @param string $eventObjectName
+ * @return array
+ */
+ public function getEventData(array $event, $eventObjectName)
+ {
+ $values = array();
+
+ if (! empty($event['changes'])) {
+ $values['changes'] = $event['changes'];
+ }
+
+ switch ($eventObjectName) {
+ case 'Kanboard\Event\TaskEvent':
+ $values['task'] = $this->taskFinderModel->getDetails($event['task_id']);
+ break;
+ case 'Kanboard\Event\SubtaskEvent':
+ $values['subtask'] = $this->subtaskModel->getById($event['id'], true);
+ $values['task'] = $this->taskFinderModel->getDetails($values['subtask']['task_id']);
+ break;
+ case 'Kanboard\Event\FileEvent':
+ $values['file'] = $event;
+ $values['task'] = $this->taskFinderModel->getDetails($values['file']['task_id']);
+ break;
+ case 'Kanboard\Event\CommentEvent':
+ $values['comment'] = $this->commentModel->getById($event['id']);
+ $values['task'] = $this->taskFinderModel->getDetails($values['comment']['task_id']);
+ break;
+ }
+
+ return $values;
+ }
+}
diff --git a/app/Job/ProjectMetricJob.php b/app/Job/ProjectMetricJob.php
new file mode 100644
index 00000000..6330bd4c
--- /dev/null
+++ b/app/Job/ProjectMetricJob.php
@@ -0,0 +1,40 @@
+<?php
+
+namespace Kanboard\Job;
+
+/**
+ * Class ProjectMetricJob
+ *
+ * @package Kanboard\Job
+ * @author Frederic Guillot
+ */
+class ProjectMetricJob extends BaseJob
+{
+ /**
+ * Set job parameters
+ *
+ * @access public
+ * @param integer $projectId
+ * @return $this
+ */
+ public function withParams($projectId)
+ {
+ $this->jobParams = array($projectId);
+ return $this;
+ }
+
+ /**
+ * Execute job
+ *
+ * @access public
+ * @param integer $projectId
+ */
+ public function execute($projectId)
+ {
+ $this->logger->debug(__METHOD__.' Run project metrics calculation');
+ $now = date('Y-m-d');
+
+ $this->projectDailyColumnStatsModel->updateTotals($projectId, $now);
+ $this->projectDailyStatsModel->updateTotals($projectId, $now);
+ }
+}
diff --git a/app/Locale/bs_BA/translations.php b/app/Locale/bs_BA/translations.php
index e689f07a..2532c3c9 100644
--- a/app/Locale/bs_BA/translations.php
+++ b/app/Locale/bs_BA/translations.php
@@ -170,7 +170,6 @@ return array(
'Leave a description' => 'Dodaj opis',
'Comment added successfully.' => 'Komentar uspješno dodan',
'Unable to create your comment.' => 'Nemoguće kreiranje komentara',
- 'Edit this task' => 'Uredi ovaj zadatak',
'Due Date' => 'Treba biti gotovo do dana',
'Invalid date' => 'Pogrešan datum',
'Automatic actions' => 'Automatske akcije',
@@ -517,7 +516,6 @@ return array(
'All swimlanes' => 'Sve swimline trake',
'All colors' => 'Sve boje',
'Moved to column %s' => 'Premješten u kolonu %s',
- 'Change description' => 'Promijeni opis',
'User dashboard' => 'Korisnički panel',
'Allow only one subtask in progress at the same time for a user' => 'Dozvoli samo jedan pod-zadatak "u radu" po korisniku',
'Edit column "%s"' => 'Uredi kolonu "%s"',
@@ -709,7 +707,6 @@ return array(
'view the board on Kanboard' => 'pregled ploče na Kanboard-u',
'The task have been moved to the first swimlane' => 'Zadatak je premješten u prvu swimline traku',
'The task have been moved to another swimlane:' => 'Zadatak je premješten u drugu swimline traku',
- 'Overdue tasks for the project(s) "%s"' => 'Zadaci u kašnjenju za projekat(te) "%s"',
'New title: %s' => 'Novi naslov: %s',
'The task is not assigned anymore' => 'Zadatak nema više izvršioca',
'New assignee: %s' => 'Novi izvršilac: %s',
@@ -738,7 +735,6 @@ return array(
'Stop timer' => 'Zaustavi tajmer',
'Start timer' => 'Pokreni tajmer',
'Add project member' => 'Dodaj člana projekta',
- 'Enable notifications' => 'Omogući obavještenja',
'My activity stream' => 'Tok mojih aktivnosti',
'My calendar' => 'Moj kalendar',
'Search tasks' => 'Pretraga zadataka',
@@ -1167,4 +1163,41 @@ return array(
'Projects where "%s" is member' => 'Projekti gdje je "%s" član',
'Open tasks assigned to "%s"' => 'Otvoreni zadaci dodijeljeni "%s"',
'Closed tasks assigned to "%s"' => 'Zatvoreni zadaci dodijeljeni "%s"',
+ // 'Assign automatically a color based on a priority' => '',
+ 'Overdue tasks for the project(s) "%s"' => 'Zadaci u kašnjenju za projekat(te) "%s"',
+ // 'Upload files' => '',
+ // 'Installed Plugins' => '',
+ // 'Plugin Directory' => '',
+ // 'Plugin installed successfully.' => '',
+ // 'Plugin updated successfully.' => '',
+ // 'Plugin removed successfully.' => '',
+ // 'Subtask converted to task successfully.' => '',
+ // 'Unable to convert the subtask.' => '',
+ // 'Unable to extract plugin archive.' => '',
+ // 'Plugin not found.' => '',
+ // 'You don\'t have the permission to remove this plugin.' => '',
+ // 'Unable to download plugin archive.' => '',
+ // 'Unable to write temporary file for plugin.' => '',
+ // 'Unable to open plugin archive.' => '',
+ // 'There is no file in the plugin archive.' => '',
+ // 'Create tasks in bulk' => '',
+ // 'Your Kanboard instance is not configured to install plugins from the user interface.' => '',
+ // 'There is no plugin available.' => '',
+ // 'Install' => '',
+ // 'Update' => '',
+ // 'Up to date' => '',
+ // 'Not available' => '',
+ // 'Remove plugin' => '',
+ // 'Do you really want to remove this plugin: "%s"?' => '',
+ // 'Uninstall' => '',
+ // 'Listing' => '',
+ // 'Metadata' => '',
+ // 'Manage projects' => '',
+ // 'Convert to task' => '',
+ // 'Convert sub-task to task' => '',
+ // 'Do you really want to convert this sub-task to a task?' => '',
+ // 'My task title' => '',
+ // 'Enter one task by line.' => '',
+ // 'Number of failed login:' => '',
+ // 'Account locked until:' => '',
);
diff --git a/app/Locale/cs_CZ/translations.php b/app/Locale/cs_CZ/translations.php
index a8fbdead..5bfe2def 100644
--- a/app/Locale/cs_CZ/translations.php
+++ b/app/Locale/cs_CZ/translations.php
@@ -170,7 +170,6 @@ return array(
'Leave a description' => 'Vložte popis',
'Comment added successfully.' => 'Komentář byl úspěšně přidán.',
'Unable to create your comment.' => 'Komentář nelze vytvořit.',
- 'Edit this task' => 'Editace úkolu',
'Due Date' => 'Datum splnění',
'Invalid date' => 'Neplatné datum',
'Automatic actions' => 'Automaticky vykonávané akce',
@@ -517,7 +516,6 @@ return array(
'All swimlanes' => 'Alle Swimlanes',
'All colors' => 'Všechny barvy',
'Moved to column %s' => 'Přesunuto do sloupce %s ',
- 'Change description' => 'Změna podrobného popisu',
'User dashboard' => 'Nástěnka uživatele',
'Allow only one subtask in progress at the same time for a user' => 'Umožnit uživateli práci pouze na jednom dílčím úkolu ve stejném čase',
'Edit column "%s"' => 'Upravit sloupec "%s" ',
@@ -709,7 +707,6 @@ return array(
'view the board on Kanboard' => 'Pinnwand in Kanboard anzeigen',
'The task have been moved to the first swimlane' => 'Die Aufgabe wurde in die erste Swimlane verschoben',
'The task have been moved to another swimlane:' => 'Die Aufgaben wurde in ene andere Swimlane verschoben',
- // 'Overdue tasks for the project(s) "%s"' => 'Überfällige Aufgaben für das Projekt "%s"',
'New title: %s' => 'Neuer Titel: %s',
'The task is not assigned anymore' => 'Die Aufgabe ist nicht mehr zugewiesen',
'New assignee: %s' => 'Neue Zuordnung: %s',
@@ -738,7 +735,6 @@ return array(
'Stop timer' => 'Zastavit časovač',
'Start timer' => 'Spustit časovač',
'Add project member' => 'Přidat člena projektu',
- 'Enable notifications' => 'Povolit notifikace',
'My activity stream' => 'Přehled mých aktivit',
'My calendar' => 'Můj kalendář',
'Search tasks' => 'Hledání úkolů',
@@ -1167,4 +1163,41 @@ return array(
// 'Projects where "%s" is member' => '',
// 'Open tasks assigned to "%s"' => '',
// 'Closed tasks assigned to "%s"' => '',
+ // 'Assign automatically a color based on a priority' => '',
+ // 'Overdue tasks for the project(s) "%s"' => '',
+ // 'Upload files' => '',
+ // 'Installed Plugins' => '',
+ // 'Plugin Directory' => '',
+ // 'Plugin installed successfully.' => '',
+ // 'Plugin updated successfully.' => '',
+ // 'Plugin removed successfully.' => '',
+ // 'Subtask converted to task successfully.' => '',
+ // 'Unable to convert the subtask.' => '',
+ // 'Unable to extract plugin archive.' => '',
+ // 'Plugin not found.' => '',
+ // 'You don\'t have the permission to remove this plugin.' => '',
+ // 'Unable to download plugin archive.' => '',
+ // 'Unable to write temporary file for plugin.' => '',
+ // 'Unable to open plugin archive.' => '',
+ // 'There is no file in the plugin archive.' => '',
+ // 'Create tasks in bulk' => '',
+ // 'Your Kanboard instance is not configured to install plugins from the user interface.' => '',
+ // 'There is no plugin available.' => '',
+ // 'Install' => '',
+ // 'Update' => '',
+ // 'Up to date' => '',
+ // 'Not available' => '',
+ // 'Remove plugin' => '',
+ // 'Do you really want to remove this plugin: "%s"?' => '',
+ // 'Uninstall' => '',
+ // 'Listing' => '',
+ // 'Metadata' => '',
+ // 'Manage projects' => '',
+ // 'Convert to task' => '',
+ // 'Convert sub-task to task' => '',
+ // 'Do you really want to convert this sub-task to a task?' => '',
+ // 'My task title' => '',
+ // 'Enter one task by line.' => '',
+ // 'Number of failed login:' => '',
+ // 'Account locked until:' => '',
);
diff --git a/app/Locale/da_DK/translations.php b/app/Locale/da_DK/translations.php
index aa53e382..e519a042 100644
--- a/app/Locale/da_DK/translations.php
+++ b/app/Locale/da_DK/translations.php
@@ -170,7 +170,6 @@ return array(
'Leave a description' => 'Efterlad en beskrivelse...',
'Comment added successfully.' => 'Kommentaren er tilføjet.',
'Unable to create your comment.' => 'Din kommentar kunne ikke oprettes.',
- 'Edit this task' => 'Rediger denne opgave',
'Due Date' => 'Forfaldsdato',
'Invalid date' => 'Ugyldig dato',
'Automatic actions' => 'Automatiske handlinger',
@@ -517,7 +516,6 @@ return array(
// 'All swimlanes' => '',
// 'All colors' => '',
// 'Moved to column %s' => '',
- // 'Change description' => '',
// 'User dashboard' => '',
// 'Allow only one subtask in progress at the same time for a user' => '',
// 'Edit column "%s"' => '',
@@ -709,7 +707,6 @@ return array(
// 'view the board on Kanboard' => '',
// 'The task have been moved to the first swimlane' => '',
// 'The task have been moved to another swimlane:' => '',
- // 'Overdue tasks for the project(s) "%s"' => '',
// 'New title: %s' => '',
// 'The task is not assigned anymore' => '',
// 'New assignee: %s' => '',
@@ -738,7 +735,6 @@ return array(
// 'Stop timer' => '',
// 'Start timer' => '',
// 'Add project member' => '',
- // 'Enable notifications' => '',
// 'My activity stream' => '',
// 'My calendar' => '',
// 'Search tasks' => '',
@@ -1167,4 +1163,41 @@ return array(
// 'Projects where "%s" is member' => '',
// 'Open tasks assigned to "%s"' => '',
// 'Closed tasks assigned to "%s"' => '',
+ // 'Assign automatically a color based on a priority' => '',
+ // 'Overdue tasks for the project(s) "%s"' => '',
+ // 'Upload files' => '',
+ // 'Installed Plugins' => '',
+ // 'Plugin Directory' => '',
+ // 'Plugin installed successfully.' => '',
+ // 'Plugin updated successfully.' => '',
+ // 'Plugin removed successfully.' => '',
+ // 'Subtask converted to task successfully.' => '',
+ // 'Unable to convert the subtask.' => '',
+ // 'Unable to extract plugin archive.' => '',
+ // 'Plugin not found.' => '',
+ // 'You don\'t have the permission to remove this plugin.' => '',
+ // 'Unable to download plugin archive.' => '',
+ // 'Unable to write temporary file for plugin.' => '',
+ // 'Unable to open plugin archive.' => '',
+ // 'There is no file in the plugin archive.' => '',
+ // 'Create tasks in bulk' => '',
+ // 'Your Kanboard instance is not configured to install plugins from the user interface.' => '',
+ // 'There is no plugin available.' => '',
+ // 'Install' => '',
+ // 'Update' => '',
+ // 'Up to date' => '',
+ // 'Not available' => '',
+ // 'Remove plugin' => '',
+ // 'Do you really want to remove this plugin: "%s"?' => '',
+ // 'Uninstall' => '',
+ // 'Listing' => '',
+ // 'Metadata' => '',
+ // 'Manage projects' => '',
+ // 'Convert to task' => '',
+ // 'Convert sub-task to task' => '',
+ // 'Do you really want to convert this sub-task to a task?' => '',
+ // 'My task title' => '',
+ // 'Enter one task by line.' => '',
+ // 'Number of failed login:' => '',
+ // 'Account locked until:' => '',
);
diff --git a/app/Locale/de_DE/translations.php b/app/Locale/de_DE/translations.php
index 160cd51f..d6bc0b34 100644
--- a/app/Locale/de_DE/translations.php
+++ b/app/Locale/de_DE/translations.php
@@ -170,7 +170,6 @@ return array(
'Leave a description' => 'Beschreibung eingeben',
'Comment added successfully.' => 'Kommentar erfolgreich hinzugefügt.',
'Unable to create your comment.' => 'Hinzufügen eines Kommentars nicht möglich.',
- 'Edit this task' => 'Aufgabe bearbeiten',
'Due Date' => 'Fällig am',
'Invalid date' => 'Ungültiges Datum',
'Automatic actions' => 'Automatische Aktionen',
@@ -317,14 +316,14 @@ return array(
'Project cloned successfully.' => 'Projekt wurde dupliziert.',
'Unable to clone this project.' => 'Duplizieren dieses Projekts schlug fehl.',
'Enable email notifications' => 'E-Mail-Benachrichtigungen einschalten',
- 'Task position:' => 'Position der Aufgabe',
+ 'Task position:' => 'Position der Aufgabe:',
'The task #%d have been opened.' => 'Die Aufgabe #%d wurde geöffnet.',
'The task #%d have been closed.' => 'Die Aufgabe #%d wurde geschlossen.',
'Sub-task updated' => 'Teilaufgabe aktualisiert',
- 'Title:' => 'Titel',
- 'Status:' => 'Status',
+ 'Title:' => 'Titel:',
+ 'Status:' => 'Status:',
'Assignee:' => 'Zuständigkeit:',
- 'Time tracking:' => 'Zeittracking',
+ 'Time tracking:' => 'Zeittracking:',
'New sub-task' => 'Neue Teilaufgabe',
'New attachment added "%s"' => 'Neuer Anhang "%s" wurde hinzugefügt.',
'New comment posted by %s' => 'Neuer Kommentar verfasst durch %s',
@@ -356,9 +355,9 @@ return array(
'Remote' => 'Remote',
'Enabled' => 'angeschaltet',
'Disabled' => 'abgeschaltet',
- 'Username:' => 'Benutzername',
- 'Name:' => 'Name',
- 'Email:' => 'E-Mail',
+ 'Username:' => 'Benutzername:',
+ 'Name:' => 'Name:',
+ 'Email:' => 'E-Mail:',
'Notifications:' => 'Benachrichtigungen:',
'Notifications' => 'Benachrichtigungen',
'Account type:' => 'Accounttyp:',
@@ -411,13 +410,13 @@ return array(
'Label' => 'Kennzeichnung',
'Database' => 'Datenbank',
'About' => 'Über',
- 'Database driver:' => 'Datenbanktreiber',
+ 'Database driver:' => 'Datenbanktreiber:',
'Board settings' => 'Pinnwandeinstellungen',
'URL and token' => 'URL und Token',
'Webhook settings' => 'Webhook-Einstellungen',
- 'URL for task creation:' => 'URL zur Aufgabenerstellung',
+ 'URL for task creation:' => 'URL zur Aufgabenerstellung:',
'Reset token' => 'Token zurücksetzen',
- 'API endpoint:' => 'API-Endpunkt',
+ 'API endpoint:' => 'API-Endpunkt:',
'Refresh interval for private board' => 'Aktualisierungsintervall für private Pinnwände',
'Refresh interval for public board' => 'Aktualisierungsintervall für öffentliche Pinnwände',
'Task highlight period' => 'Aufgaben-Hervorhebungsdauer',
@@ -517,7 +516,6 @@ return array(
'All swimlanes' => 'Alle Swimlanes',
'All colors' => 'Alle Farben',
'Moved to column %s' => 'In Spalte %s verschoben',
- 'Change description' => 'Beschreibung ändern',
'User dashboard' => 'Benutzer-Dashboard',
'Allow only one subtask in progress at the same time for a user' => 'Erlaube nur eine Teilaufgabe pro Benutzer zu bearbeiten',
'Edit column "%s"' => 'Spalte "%s" bearbeiten',
@@ -661,7 +659,7 @@ return array(
'Month(s)' => 'Monat(e)',
'Recurrence' => 'Wiederholung',
'This task has been created by: ' => 'DIese Aufgabe wurde erstellt von: ',
- 'Recurrent task has been generated:' => 'Wiederkehrende Aufgabe wurde erstellt ',
+ 'Recurrent task has been generated:' => 'Wiederkehrende Aufgabe wurde erstellt:',
'Timeframe to calculate new due date: ' => 'Zeitfenster zur Berechnung für neues Ablaufdatum: ',
'Trigger to generate recurrent task: ' => 'Auslöser für wiederkehrende Aufgabe: ',
'When task is closed' => 'Wenn Aufgabe geshlossen wird',
@@ -708,8 +706,7 @@ return array(
'Project activities for %s' => 'Projektaktivitäten für %s',
'view the board on Kanboard' => 'Pinnwand in Kanboard anzeigen',
'The task have been moved to the first swimlane' => 'Die Aufgabe wurde in die erste Swimlane verschoben',
- 'The task have been moved to another swimlane:' => 'Die Aufgaben wurde in ene andere Swimlane verschoben',
- // 'Overdue tasks for the project(s) "%s"' => 'Überfällige Aufgaben für das Projekt "%s"',
+ 'The task have been moved to another swimlane:' => 'Die Aufgaben wurde in eine andere Swimlane verschoben:',
'New title: %s' => 'Neuer Titel: %s',
'The task is not assigned anymore' => 'Die Aufgabe ist nicht mehr zugewiesen',
'New assignee: %s' => 'Neue Zuordnung: %s',
@@ -738,7 +735,6 @@ return array(
'Stop timer' => 'Stoppe Timer',
'Start timer' => 'Starte Timer',
'Add project member' => 'Projektmitglied hinzufügen',
- 'Enable notifications' => 'Benachrichtigung aktivieren',
'My activity stream' => 'Aktivitätsstream',
'My calendar' => 'Mein Kalender',
'Search tasks' => 'Suche nach Aufgaben',
@@ -808,7 +804,7 @@ return array(
'no category' => 'keine Kategorie',
'Current assignee: %s' => 'Aktuelle Zuordnung: %s',
'not assigned' => 'nicht zugeordnet',
- 'Author:' => 'Autor',
+ 'Author:' => 'Autor:',
'contributors' => 'Mitwirkende',
'License:' => 'Lizenz:',
'License' => 'Lizenz',
@@ -1158,13 +1154,50 @@ return array(
'My activities' => 'Meine Aktivitäten',
'Activity until yesterday' => 'Aktivitäten bis gestern',
'Activity until today' => 'Aktivitäten bis heute',
- 'Search by creator: ' => 'nach Ersteller suchen',
- 'Search by creation date: ' => 'nach Datum suchen',
- 'Search by task status: ' => 'nach Aufgabenstatus suchen',
- 'Search by task title: ' => 'nach Titel suchen',
+ 'Search by creator: ' => 'nach Ersteller suchen:',
+ 'Search by creation date: ' => 'nach Datum suchen:',
+ 'Search by task status: ' => 'nach Aufgabenstatus suchen:',
+ 'Search by task title: ' => 'nach Titel suchen:',
'Activity stream search' => 'Im Aktivitätenstrom suchen',
'Projects where "%s" is manager' => 'Projekte in denen "%s" Manager ist',
'Projects where "%s" is member' => 'Projekte in denen "%s" Mitglied ist',
'Open tasks assigned to "%s"' => 'Offene Aufgaben, die "%s" zugeteilt sind',
'Closed tasks assigned to "%s"' => 'Geschlossene Aufgaben, die "%s" zugeteilt sind',
+ 'Assign automatically a color based on a priority' => 'Eine Farbe basierend auf einer Priorität automatisch zuordnen',
+ 'Overdue tasks for the project(s) "%s"' => 'Überfällige Aufgaben des/der Projekt/e "%s"',
+ 'Upload files' => 'Dateien hochladen',
+ 'Installed Plugins' => 'Installierte Plugins',
+ 'Plugin Directory' => 'Plugin Verzeichnis',
+ 'Plugin installed successfully.' => 'Plugin erfolgreich installiert.',
+ 'Plugin updated successfully.' => 'Plugin erfolgreich aktualisiert.',
+ 'Plugin removed successfully.' => 'Plugin erfolgreich entfernt.',
+ 'Subtask converted to task successfully.' => 'Teilaufgabe erfolgreich in Aufgabe umgewandelt.',
+ 'Unable to convert the subtask.' => 'Teilaufgabe kann nicht umgewandelt werden.',
+ 'Unable to extract plugin archive.' => 'Plugin Archiv kann nicht entpackt werden.',
+ 'Plugin not found.' => 'Plugin nicht gefunden.',
+ 'You don\'t have the permission to remove this plugin.' => 'Sie dürfen dieses Plugin nicht entfernen.',
+ 'Unable to download plugin archive.' => 'Plugin Archiv kann nicht herunter geladen werden.',
+ 'Unable to write temporary file for plugin.' => 'Temporäre Dateien für das Plugin können nicht geschrieben werden.',
+ 'Unable to open plugin archive.' => 'Kann das Plugin Archiv nicht öffenen.',
+ 'There is no file in the plugin archive.' => 'Es gibt keine Datei im Plugin Archiv.',
+ 'Create tasks in bulk' => 'Viele Aufgaben auf einmal erstellen',
+ 'Your Kanboard instance is not configured to install plugins from the user interface.' => 'Ihre Kanboard Installation ist nicht dafür konfiguriert, Plugins mit dem Benutzerinterface zu installieren.',
+ 'There is no plugin available.' => 'Es gibt kein Plugin.',
+ 'Install' => 'Installieren',
+ 'Update' => 'Aktualisieren',
+ 'Up to date' => 'Aktuell',
+ 'Not available' => 'Nicht verfügbar',
+ 'Remove plugin' => 'Plugin entfernen',
+ 'Do you really want to remove this plugin: "%s"?' => 'Wollen Sie das Plugin "%s" wirklich entfernen?',
+ 'Uninstall' => 'Deinstallieren',
+ 'Listing' => 'Auflistung',
+ 'Metadata' => 'Metadaten',
+ 'Manage projects' => 'Projekte verwalten',
+ 'Convert to task' => 'In Aufgabe umwandeln',
+ 'Convert sub-task to task' => 'Teilaufgabe in Aufgabe umwandeln',
+ 'Do you really want to convert this sub-task to a task?' => 'Wollen Sie diese Teilaufgabe wirklich in eine Aufgabe umwandeln?',
+ 'My task title' => 'Mein Aufgabentitel',
+ 'Enter one task by line.' => 'Geben Sie eine Aufgabe pro Zeile ein.',
+ 'Number of failed login:' => 'Anzahl fehlgeschlagener Anmeldungen:',
+ 'Account locked until:' => 'Konto gesperrt bis:',
);
diff --git a/app/Locale/el_GR/translations.php b/app/Locale/el_GR/translations.php
index f70742a3..11ece5c6 100644
--- a/app/Locale/el_GR/translations.php
+++ b/app/Locale/el_GR/translations.php
@@ -170,7 +170,6 @@ return array(
'Leave a description' => 'Αφήστε μια περιγραφή',
'Comment added successfully.' => 'Το σχόλιο σας προστέθηκε με επιτυχία.',
'Unable to create your comment.' => 'Δεν είναι δυνατή η προσθήκη του σχολίου σας.',
- 'Edit this task' => 'Διόρθωση εργασίας',
'Due Date' => 'Μέχρι την ημερομηνία',
'Invalid date' => 'Μη ορθή ημερομηνία',
'Automatic actions' => 'Αυτόματες ενέργειες',
@@ -517,7 +516,6 @@ return array(
'All swimlanes' => 'Όλες οι λωρίδες',
'All colors' => 'Όλα τα χρώματα',
'Moved to column %s' => 'Μεταφορά στη στήλη %s',
- 'Change description' => 'Επεξεργασία περιγραφής',
'User dashboard' => 'Κεντρικό ταμπλό χρήστη',
'Allow only one subtask in progress at the same time for a user' => 'Αφήστε μόνο μία υπο-εργασία σε εξέλιξη ταυτόχρονα για έναν χρήστη',
'Edit column "%s"' => 'Επεξεργασία στήλης « %s »',
@@ -709,7 +707,6 @@ return array(
'view the board on Kanboard' => 'δείτε τον πίνακα στο Kanboard',
'The task have been moved to the first swimlane' => 'Η εργασία αυτή έχει μετακινηθεί στην πρώτη λωρίδα',
'The task have been moved to another swimlane:' => 'Η εργασία αυτή έχει μετακινηθεί σε άλλη λωρίδα:',
- // 'Overdue tasks for the project(s) "%s"' => 'Εκπρόθεσμες εργασίες για το έργο « %s »',
'New title: %s' => 'Νέος τίτλος: %s',
'The task is not assigned anymore' => 'Η εργασία δεν έχει ανατεθεί πλέον',
'New assignee: %s' => 'Καινούργια ανάθεση: %s',
@@ -738,7 +735,6 @@ return array(
'Stop timer' => 'Διακοπή ρολογιού',
'Start timer' => 'Έναρξη ρολογιού',
'Add project member' => 'Προσθήκη νέου μέλους έργου',
- 'Enable notifications' => 'Ενεργοποίηση ειδοποιήσεων',
'My activity stream' => 'Η ροή δραστηριοτήτων μου',
'My calendar' => 'Το ημερολόγιο μου',
'Search tasks' => 'Αναζήτηση εργασιών',
@@ -1167,4 +1163,41 @@ return array(
// 'Projects where "%s" is member' => '',
// 'Open tasks assigned to "%s"' => '',
// 'Closed tasks assigned to "%s"' => '',
+ // 'Assign automatically a color based on a priority' => '',
+ // 'Overdue tasks for the project(s) "%s"' => '',
+ // 'Upload files' => '',
+ // 'Installed Plugins' => '',
+ // 'Plugin Directory' => '',
+ // 'Plugin installed successfully.' => '',
+ // 'Plugin updated successfully.' => '',
+ // 'Plugin removed successfully.' => '',
+ // 'Subtask converted to task successfully.' => '',
+ // 'Unable to convert the subtask.' => '',
+ // 'Unable to extract plugin archive.' => '',
+ // 'Plugin not found.' => '',
+ // 'You don\'t have the permission to remove this plugin.' => '',
+ // 'Unable to download plugin archive.' => '',
+ // 'Unable to write temporary file for plugin.' => '',
+ // 'Unable to open plugin archive.' => '',
+ // 'There is no file in the plugin archive.' => '',
+ // 'Create tasks in bulk' => '',
+ // 'Your Kanboard instance is not configured to install plugins from the user interface.' => '',
+ // 'There is no plugin available.' => '',
+ // 'Install' => '',
+ // 'Update' => '',
+ // 'Up to date' => '',
+ // 'Not available' => '',
+ // 'Remove plugin' => '',
+ // 'Do you really want to remove this plugin: "%s"?' => '',
+ // 'Uninstall' => '',
+ // 'Listing' => '',
+ // 'Metadata' => '',
+ // 'Manage projects' => '',
+ // 'Convert to task' => '',
+ // 'Convert sub-task to task' => '',
+ // 'Do you really want to convert this sub-task to a task?' => '',
+ // 'My task title' => '',
+ // 'Enter one task by line.' => '',
+ // 'Number of failed login:' => '',
+ // 'Account locked until:' => '',
);
diff --git a/app/Locale/es_ES/translations.php b/app/Locale/es_ES/translations.php
index 240a04fe..243c2063 100644
--- a/app/Locale/es_ES/translations.php
+++ b/app/Locale/es_ES/translations.php
@@ -170,7 +170,6 @@ return array(
'Leave a description' => 'Dejar una descripción',
'Comment added successfully.' => 'El comentario ha sido añadido correctamente.',
'Unable to create your comment.' => 'No se puede crear este comentario.',
- 'Edit this task' => 'Editar esta tarea',
'Due Date' => 'Fecha límite',
'Invalid date' => 'Fecha no válida',
'Automatic actions' => 'Acciones automatizadas',
@@ -517,7 +516,6 @@ return array(
'All swimlanes' => 'Todas las calles',
'All colors' => 'Todos los colores',
'Moved to column %s' => 'Movido a columna %s',
- 'Change description' => 'Cambiar descripción',
'User dashboard' => 'Tablero de usuario',
'Allow only one subtask in progress at the same time for a user' => 'Permitir sólo una subtarea en progreso a la vez para cada usuario',
'Edit column "%s"' => 'Editar columna %s',
@@ -709,7 +707,6 @@ return array(
'view the board on Kanboard' => 'ver el tablero en Kanboard',
'The task have been moved to the first swimlane' => 'Se ha movido la tarea a la primera calle',
'The task have been moved to another swimlane:' => 'Se ha movido la tarea a otra calle',
- // 'Overdue tasks for the project(s) "%s"' => 'Tareas atrasadas para el proyecto "%s"',
'New title: %s' => 'Nuevo título: %s',
'The task is not assigned anymore' => 'La tarea ya no está asignada',
'New assignee: %s' => 'Nuevo concesionario: %s',
@@ -738,7 +735,6 @@ return array(
'Stop timer' => 'Parar temporizador',
'Start timer' => 'Arrancar temporizador',
'Add project member' => 'Añadir miembro al proyecto',
- 'Enable notifications' => 'Activar notificaciones',
'My activity stream' => 'Mi flujo de actividad',
'My calendar' => 'Mi calendario',
'Search tasks' => 'Buscar tareas',
@@ -1167,4 +1163,41 @@ return array(
// 'Projects where "%s" is member' => '',
// 'Open tasks assigned to "%s"' => '',
// 'Closed tasks assigned to "%s"' => '',
+ // 'Assign automatically a color based on a priority' => '',
+ // 'Overdue tasks for the project(s) "%s"' => '',
+ // 'Upload files' => '',
+ // 'Installed Plugins' => '',
+ // 'Plugin Directory' => '',
+ // 'Plugin installed successfully.' => '',
+ // 'Plugin updated successfully.' => '',
+ // 'Plugin removed successfully.' => '',
+ // 'Subtask converted to task successfully.' => '',
+ // 'Unable to convert the subtask.' => '',
+ // 'Unable to extract plugin archive.' => '',
+ // 'Plugin not found.' => '',
+ // 'You don\'t have the permission to remove this plugin.' => '',
+ // 'Unable to download plugin archive.' => '',
+ // 'Unable to write temporary file for plugin.' => '',
+ // 'Unable to open plugin archive.' => '',
+ // 'There is no file in the plugin archive.' => '',
+ // 'Create tasks in bulk' => '',
+ // 'Your Kanboard instance is not configured to install plugins from the user interface.' => '',
+ // 'There is no plugin available.' => '',
+ // 'Install' => '',
+ // 'Update' => '',
+ // 'Up to date' => '',
+ // 'Not available' => '',
+ // 'Remove plugin' => '',
+ // 'Do you really want to remove this plugin: "%s"?' => '',
+ // 'Uninstall' => '',
+ // 'Listing' => '',
+ // 'Metadata' => '',
+ // 'Manage projects' => '',
+ // 'Convert to task' => '',
+ // 'Convert sub-task to task' => '',
+ // 'Do you really want to convert this sub-task to a task?' => '',
+ // 'My task title' => '',
+ // 'Enter one task by line.' => '',
+ // 'Number of failed login:' => '',
+ // 'Account locked until:' => '',
);
diff --git a/app/Locale/fi_FI/translations.php b/app/Locale/fi_FI/translations.php
index 147713a5..bd5fa31b 100644
--- a/app/Locale/fi_FI/translations.php
+++ b/app/Locale/fi_FI/translations.php
@@ -170,7 +170,6 @@ return array(
'Leave a description' => 'Lisää kuvaus',
'Comment added successfully.' => 'Kommentti lisättiin onnistuneesti.',
'Unable to create your comment.' => 'Kommentin lisäys epäonnistui.',
- 'Edit this task' => 'Muokkaa tehtävää',
'Due Date' => 'Deadline',
'Invalid date' => 'Virheellinen päiväys',
'Automatic actions' => 'Automaattiset toiminnot',
@@ -517,7 +516,6 @@ return array(
// 'All swimlanes' => '',
// 'All colors' => '',
// 'Moved to column %s' => '',
- // 'Change description' => '',
// 'User dashboard' => '',
// 'Allow only one subtask in progress at the same time for a user' => '',
// 'Edit column "%s"' => '',
@@ -709,7 +707,6 @@ return array(
// 'view the board on Kanboard' => '',
// 'The task have been moved to the first swimlane' => '',
// 'The task have been moved to another swimlane:' => '',
- // 'Overdue tasks for the project(s) "%s"' => '',
// 'New title: %s' => '',
// 'The task is not assigned anymore' => '',
// 'New assignee: %s' => '',
@@ -738,7 +735,6 @@ return array(
// 'Stop timer' => '',
// 'Start timer' => '',
// 'Add project member' => '',
- // 'Enable notifications' => '',
// 'My activity stream' => '',
// 'My calendar' => '',
// 'Search tasks' => '',
@@ -1167,4 +1163,41 @@ return array(
// 'Projects where "%s" is member' => '',
// 'Open tasks assigned to "%s"' => '',
// 'Closed tasks assigned to "%s"' => '',
+ // 'Assign automatically a color based on a priority' => '',
+ // 'Overdue tasks for the project(s) "%s"' => '',
+ // 'Upload files' => '',
+ // 'Installed Plugins' => '',
+ // 'Plugin Directory' => '',
+ // 'Plugin installed successfully.' => '',
+ // 'Plugin updated successfully.' => '',
+ // 'Plugin removed successfully.' => '',
+ // 'Subtask converted to task successfully.' => '',
+ // 'Unable to convert the subtask.' => '',
+ // 'Unable to extract plugin archive.' => '',
+ // 'Plugin not found.' => '',
+ // 'You don\'t have the permission to remove this plugin.' => '',
+ // 'Unable to download plugin archive.' => '',
+ // 'Unable to write temporary file for plugin.' => '',
+ // 'Unable to open plugin archive.' => '',
+ // 'There is no file in the plugin archive.' => '',
+ // 'Create tasks in bulk' => '',
+ // 'Your Kanboard instance is not configured to install plugins from the user interface.' => '',
+ // 'There is no plugin available.' => '',
+ // 'Install' => '',
+ // 'Update' => '',
+ // 'Up to date' => '',
+ // 'Not available' => '',
+ // 'Remove plugin' => '',
+ // 'Do you really want to remove this plugin: "%s"?' => '',
+ // 'Uninstall' => '',
+ // 'Listing' => '',
+ // 'Metadata' => '',
+ // 'Manage projects' => '',
+ // 'Convert to task' => '',
+ // 'Convert sub-task to task' => '',
+ // 'Do you really want to convert this sub-task to a task?' => '',
+ // 'My task title' => '',
+ // 'Enter one task by line.' => '',
+ // 'Number of failed login:' => '',
+ // 'Account locked until:' => '',
);
diff --git a/app/Locale/fr_FR/translations.php b/app/Locale/fr_FR/translations.php
index 8f4bb5da..1771d1e6 100644
--- a/app/Locale/fr_FR/translations.php
+++ b/app/Locale/fr_FR/translations.php
@@ -170,7 +170,6 @@ return array(
'Leave a description' => 'Laissez une description',
'Comment added successfully.' => 'Commentaire ajouté avec succès.',
'Unable to create your comment.' => 'Impossible de sauvegarder votre commentaire.',
- 'Edit this task' => 'Modifier cette tâche',
'Due Date' => 'Date d\'échéance',
'Invalid date' => 'Date invalide',
'Automatic actions' => 'Actions automatisées',
@@ -367,7 +366,7 @@ return array(
'Password modification' => 'Changement de mot de passe',
'External authentications' => 'Authentifications externes',
'Never connected.' => 'Jamais connecté.',
- 'No external authentication enabled.' => 'Aucune authentication externe activée.',
+ 'No external authentication enabled.' => 'Aucune authentification externe activée.',
'Password modified successfully.' => 'Mot de passe changé avec succès.',
'Unable to change the password.' => 'Impossible de changer le mot de passe.',
'Change category for the task "%s"' => 'Changer la catégorie pour la tâche « %s »',
@@ -517,7 +516,6 @@ return array(
'All swimlanes' => 'Toutes les swimlanes',
'All colors' => 'Toutes les couleurs',
'Moved to column %s' => 'Tâche déplacée à la colonne %s',
- 'Change description' => 'Changer la description',
'User dashboard' => 'Tableau de bord de l\'utilisateur',
'Allow only one subtask in progress at the same time for a user' => 'Autoriser une seule sous-tâche en progrès en même temps pour un utilisateur',
'Edit column "%s"' => 'Modifier la colonne « %s »',
@@ -738,7 +736,6 @@ return array(
'Stop timer' => 'Stopper le chrono',
'Start timer' => 'Démarrer le chrono',
'Add project member' => 'Ajouter un membre au projet',
- 'Enable notifications' => 'Activer les notifications',
'My activity stream' => 'Mon flux d\'activité',
'My calendar' => 'Mon agenda',
'Search tasks' => 'Rechercher des tâches',
@@ -1167,4 +1164,41 @@ return array(
'Projects where "%s" is member' => 'Projets où « %s » est membre du projet',
'Open tasks assigned to "%s"' => 'Tâches ouvertes assignées à « %s »',
'Closed tasks assigned to "%s"' => 'Tâches fermées assignées à « %s »',
+ 'Assign automatically a color based on a priority' => 'Assigner automatiquement une couleur par rapport à une priorité',
+ 'Overdue tasks for the project(s) "%s"' => 'Tâches en retard pour le projet(s) « %s »',
+ 'Upload files' => 'Uploader les fichiers',
+ 'Installed Plugins' => 'Extensions installées',
+ 'Plugin Directory' => 'Liste des extensions',
+ 'Plugin installed successfully.' => 'Extension installée avec succès.',
+ 'Plugin updated successfully.' => 'Extension mise à jour avec succès.',
+ 'Plugin removed successfully.' => 'Extension supprimée avec succès.',
+ 'Subtask converted to task successfully.' => 'Sous-tâche convertie en tâche avec succès.',
+ 'Unable to convert the subtask.' => 'Impossible de convertir cette sous-tâche.',
+ 'Unable to extract plugin archive.' => 'Impossible d\'extraire l\'archive de l\'extension.',
+ 'Plugin not found.' => 'Extension introuvable.',
+ 'You don\'t have the permission to remove this plugin.' => 'Vous n\'avez pas la permission de supprimer ce plugin.',
+ 'Unable to download plugin archive.' => 'Impossible de télécharger l\'achive du plugin.',
+ 'Unable to write temporary file for plugin.' => 'Impossible d\'écrire le fichier temporaire pour l\'extension.',
+ 'Unable to open plugin archive.' => 'Impossible d\'ouvrir l\'archive du plugin.',
+ 'There is no file in the plugin archive.' => 'Il n\'y a aucun fichier dans l\'archive du plugin.',
+ 'Create tasks in bulk' => 'Créer plusieurs tâches en même temps',
+ 'Your Kanboard instance is not configured to install plugins from the user interface.' => 'Votre instance de Kanboard n\'est pas configurée pour installer des extension depuis l\'interface utilisateur.',
+ 'There is no plugin available.' => 'Il n\'a aucune extension disponible.',
+ 'Install' => 'Installer',
+ 'Update' => 'Mettre à jour',
+ 'Up to date' => 'À jour',
+ 'Not available' => 'Non disponible',
+ 'Remove plugin' => 'Supprimer l\'extension',
+ 'Do you really want to remove this plugin: "%s"?' => 'Voulez-vous vraiment supprimer cette extension : « %s » ?',
+ 'Uninstall' => 'Désinstaller',
+ 'Listing' => 'Listing',
+ 'Metadata' => 'Metadonnées',
+ 'Manage projects' => 'Gérer les projets',
+ 'Convert to task' => 'Convertir en tâche',
+ 'Convert sub-task to task' => 'Convertir une sous-tâche en tâche',
+ 'Do you really want to convert this sub-task to a task?' => 'Voulez-vous vraiment convertir cette sous-tâche en tâche ?',
+ 'My task title' => 'Mon titre pour la tâche',
+ 'Enter one task by line.' => 'Entrez une tâche par ligne.',
+ 'Number of failed login:' => 'Nombre de connexion échouées :',
+ 'Account locked until:' => 'Compte bloqué jusqu\'au :',
);
diff --git a/app/Locale/hu_HU/translations.php b/app/Locale/hu_HU/translations.php
index 920fda74..abe7ee94 100644
--- a/app/Locale/hu_HU/translations.php
+++ b/app/Locale/hu_HU/translations.php
@@ -19,22 +19,22 @@ return array(
'Red' => 'Piros',
'Orange' => 'Narancs',
'Grey' => 'Szürke',
- // 'Brown' => '',
- // 'Deep Orange' => '',
- // 'Dark Grey' => '',
- // 'Pink' => '',
- // 'Teal' => '',
- // 'Cyan' => '',
- // 'Lime' => '',
- // 'Light Green' => '',
- // 'Amber' => '',
+ 'Brown' => 'Barna',
+ 'Deep Orange' => 'Sötét narancs',
+ 'Dark Grey' => 'Sötét szürke',
+ 'Pink' => 'Rózsaszín',
+ 'Teal' => 'Pávakék',
+ 'Cyan' => 'Ciánkék',
+ 'Lime' => 'Lime',
+ 'Light Green' => 'Világos zöld',
+ 'Amber' => 'Borostyán',
'Save' => 'Mentés',
'Login' => 'Bejelentkezés',
'Official website:' => 'Hivatalos honlap:',
'Unassigned' => 'Nincs felelős',
'View this task' => 'Feladat megtekintése',
'Remove user' => 'Felhasználó törlése',
- 'Do you really want to remove this user: "%s"?' => 'Tényleg törli ezt a felhasználót: "%s"?',
+ 'Do you really want to remove this user: "%s"?' => 'Valóban törölni akarja ezt a felhasználót: "%s"?',
'New user' => 'Új felhasználó',
'All users' => 'Minden felhasználó',
'Username' => 'Felhasználónév',
@@ -96,7 +96,7 @@ return array(
'Create another task' => 'Új feladat létrehozása',
'New task' => 'Új feladat',
'Open a task' => 'Feladat felnyitás',
- 'Do you really want to open this task: "%s"?' => 'Tényleg meg akarja nyitni ezt a feladatot: "%s"?',
+ 'Do you really want to open this task: "%s"?' => 'Valóban meg akarja nyitni ezt a feladatot: "%s"?',
'Back to the board' => 'Vissza a táblához',
'There is nobody assigned' => 'Nincs felelős',
'Column on the board:' => 'Tábla oszlopa: ',
@@ -154,7 +154,7 @@ return array(
'Id' => 'ID',
'%d closed tasks' => '%d lezárt feladat',
'No task for this project' => 'Nincs feladat ebben a projektben',
- 'Public link' => 'Nyilvános link',
+ 'Public link' => 'Nyilvános hivatkozás',
'Change assignee' => 'Felelős módosítása',
'Change assignee for the task "%s"' => 'Feladat felelősének módosítása: "%s"',
'Timezone' => 'Időzóna',
@@ -170,7 +170,6 @@ return array(
'Leave a description' => 'Írjon leírást ...',
'Comment added successfully.' => 'Hozzászólás sikeresen elküldve.',
'Unable to create your comment.' => 'Hozzászólás létrehozása nem lehetséges.',
- 'Edit this task' => 'Feladat módosítása',
'Due Date' => 'Határidő',
'Invalid date' => 'Érvénytelen dátum',
'Automatic actions' => 'Automatikus intézkedések',
@@ -203,7 +202,7 @@ return array(
'Position' => 'Pozíció',
'Duplicate to another project' => 'Másolás másik projektbe',
'Duplicate' => 'Másolás',
- 'link' => 'link',
+ 'link' => 'hivatkozás',
'Comment updated successfully.' => 'Megjegyzés sikeresen frissítve.',
'Unable to update your comment.' => 'Megjegyzés frissítése sikertelen.',
'Remove a comment' => 'Megjegyzés törlése',
@@ -235,10 +234,10 @@ return array(
'%d comments' => '%d megjegyzés',
'%d comment' => '%d megjegyzés',
'Email address invalid' => 'Érvénytelen e-mail cím',
- // 'Your external account is not linked anymore to your profile.' => '',
- // 'Unable to unlink your external account.' => '',
- // 'External authentication failed' => '',
- // 'Your external account is linked to your profile successfully.' => '',
+ 'Your external account is not linked anymore to your profile.' => 'Az ön külső számlája és az ön profilja közötti kapcsolat megszűnt.',
+ 'Unable to unlink your external account.' => 'Nem sikerült megszüntetni a kapcsolatot az ön külső számlájával.',
+ 'External authentication failed' => 'A külső jelszó ellenőrzés nem sikerült',
+ 'Your external account is linked to your profile successfully.' => 'Az ön külső számlája sikeresen össze lett kapcsolva az ön profiljával.',
'Email' => 'E-mail',
'Task removed successfully.' => 'Feladat sikeresen törölve.',
'Unable to remove this task.' => 'A feladatot nem lehet törölni.',
@@ -269,7 +268,7 @@ return array(
'Unable to remove this file.' => 'Fájl törlése nem lehetséges.',
'File removed successfully.' => 'Fájl sikeresen törölve.',
'Attach a document' => 'Fájl csatolása',
- 'Do you really want to remove this file: "%s"?' => 'Valóban törölni akarja a fájlt: "%s"?',
+ 'Do you really want to remove this file: "%s"?' => 'Valóban törölni akarja ezt a fájlt: "%s"?',
'Attachments' => 'Mellékletek',
'Edit the task' => 'Feladat módosítása',
'Edit the description' => 'Leírás szerkesztése',
@@ -343,8 +342,8 @@ return array(
'Disable public access' => 'Nyilvános hozzáférés letiltása',
'Enable public access' => 'Nyilvános hozzáférés engedélyezése',
'Public access disabled' => 'Nyilvános hozzáférés letiltva',
- 'Do you really want to disable this project: "%s"?' => 'Tényleg szeretné letiltani ezt a projektet: "%s"',
- 'Do you really want to enable this project: "%s"?' => 'Tényleg szeretné engedélyezni ezt a projektet: "%s"',
+ 'Do you really want to disable this project: "%s"?' => 'Tényleg szeretné letiltani ezt a projektet: "%s"?',
+ 'Do you really want to enable this project: "%s"?' => 'Tényleg szeretné engedélyezni ezt a projektet: "%s"?',
'Project activation' => 'Projekt aktiválás',
'Move the task to another project' => 'Feladat áthelyezése másik projektbe',
'Move to another project' => 'Áthelyezés másik projektbe',
@@ -473,30 +472,30 @@ return array(
'This value is required' => 'Ez a mező kötelező',
'This value must be numeric' => 'Ez a mező csak szám lehet',
'Unable to create this task.' => 'A feladat nem hozható létre,',
- 'Cumulative flow diagram' => 'Kumulatív Flow Diagram',
- 'Cumulative flow diagram for "%s"' => 'Kumulatív Flow Diagram: %s',
+ 'Cumulative flow diagram' => 'Kumulatív folyamatábra',
+ 'Cumulative flow diagram for "%s"' => 'Kumulatív folyamatábra: %s',
'Daily project summary' => 'Napi projektösszefoglaló',
'Daily project summary export' => 'Napi projektösszefoglaló exportálása',
'Daily project summary export for "%s"' => 'Napi projektösszefoglaló exportálása: %s',
'Exports' => 'Exportálások',
'This export contains the number of tasks per column grouped per day.' => 'Ez az export tartalmazza a feladatok számát oszloponként összesítve, napokra lebontva.',
- 'Active swimlanes' => 'Aktív folyamatok',
- 'Add a new swimlane' => 'Új folyamat',
- 'Change default swimlane' => 'Alapértelmezett folyamat változtatás',
+ 'Active swimlanes' => 'Aktív sávok',
+ 'Add a new swimlane' => 'Új sáv',
+ 'Change default swimlane' => 'Alapértelmezett sáv megváltoztatása',
'Default swimlane' => 'Alapértelmezett folyamat',
- 'Do you really want to remove this swimlane: "%s"?' => 'Valóban törli a folyamatot:%s ?',
- 'Inactive swimlanes' => 'Inaktív folyamatok',
- 'Remove a swimlane' => 'Folyamat törlés',
- 'Show default swimlane' => 'Alapértelmezett folyamat megjelenítése',
- 'Swimlane modification for the project "%s"' => '%s projekt folyamatainak módosítása',
- 'Swimlane not found.' => 'Folyamat nem található',
- 'Swimlane removed successfully.' => 'Folyamat sikeresen törölve.',
- 'Swimlanes' => 'Folyamatok',
- 'Swimlane updated successfully.' => 'Folyamat sikeresn frissítve',
- 'The default swimlane have been updated successfully.' => 'Az alapértelmezett folyamat sikeresen frissítve.',
- 'Unable to remove this swimlane.' => 'A folyamat törlése sikertelen.',
- 'Unable to update this swimlane.' => 'A folyamat frissítése sikertelen.',
- 'Your swimlane have been created successfully.' => 'A folyamat sikeresen létrehozva.',
+ 'Do you really want to remove this swimlane: "%s"?' => 'Valóban törölni akarja ezt a sávot: %s ?',
+ 'Inactive swimlanes' => 'Inaktív sávok',
+ 'Remove a swimlane' => 'Sáv törlés',
+ 'Show default swimlane' => 'Alapértelmezett sáv megjelenítése',
+ 'Swimlane modification for the project "%s"' => '%s projekt sávjainak módosítása',
+ 'Swimlane not found.' => 'Sáv nem található',
+ 'Swimlane removed successfully.' => 'Sáv sikeresen törölve.',
+ 'Swimlanes' => 'Sávok',
+ 'Swimlane updated successfully.' => 'Sáv sikeresen frissítve',
+ 'The default swimlane have been updated successfully.' => 'Az alapértelmezett sáv sikeresen frissítve.',
+ 'Unable to remove this swimlane.' => 'A sáv törlése sikertelen.',
+ 'Unable to update this swimlane.' => 'A sáv frissítése sikertelen.',
+ 'Your swimlane have been created successfully.' => 'A sáv sikeresen létrehozva.',
'Example: "Bug, Feature Request, Improvement"' => 'Például: Hiba, Új funkció, Fejlesztés',
'Default categories for new projects (Comma-separated)' => 'Alapértelmezett kategóriák az új projektekben (Vesszővel elválasztva)',
'Integrations' => 'Integráció',
@@ -514,10 +513,9 @@ return array(
'Calendar' => 'Naptár',
'Next' => 'Következő',
'#%d' => '#%d',
- 'All swimlanes' => 'Minden folyamat',
+ 'All swimlanes' => 'Minden sáv',
'All colors' => 'Minden szín',
'Moved to column %s' => '%s oszlopba áthelyezve',
- 'Change description' => 'Leírás szerkesztés',
'User dashboard' => 'Felhasználói vezérlőpult',
'Allow only one subtask in progress at the same time for a user' => 'Egyszerre csak egy folyamatban levő részfeladat engedélyezése a felhasználóknak',
'Edit column "%s"' => 'Oszlop szerkesztés: %s',
@@ -527,7 +525,7 @@ return array(
'Time Tracking' => 'Idő követés',
'You already have one subtask in progress' => 'Már van egy folyamatban levő részfeladata',
'Which parts of the project do you want to duplicate?' => 'A projekt mely részeit szeretné másolni?',
- // 'Disallow login form' => '',
+ 'Disallow login form' => 'A login ablak letiltása',
'Start' => 'Kezdet',
'End' => 'Vég',
'Task age in days' => 'Feladat életkora napokban',
@@ -544,7 +542,7 @@ return array(
'Link modification' => 'Hivatkozás módosítás',
'Links' => 'Hivatkozások',
'Link settings' => 'Hivatkozás beállítasok',
- 'Opposite label' => 'Ellenekező címke',
+ 'Opposite label' => 'Ellenkező címke',
'Remove a link' => 'Hivatkozás törlése',
'Task\'s links' => 'Feladat hivatkozások',
'The labels must be different' => 'A címkék nem lehetnek azonosak',
@@ -585,7 +583,7 @@ return array(
'AUD - Australian Dollar' => 'AUD - Ausztrál dollár',
'CAD - Canadian Dollar' => 'CAD - Kanadai dollár',
'CHF - Swiss Francs' => 'CHF - Svájci frank',
- 'Custom Stylesheet' => 'Egyéni sítluslap',
+ 'Custom Stylesheet' => 'Egyéni stíluslap',
'download' => 'letöltés',
'EUR - Euro' => 'EUR - Euro',
'GBP - British Pound' => 'GBP - Angol font',
@@ -593,578 +591,613 @@ return array(
'JPY - Japanese Yen' => 'JPY - Japán Yen',
'NZD - New Zealand Dollar' => 'NZD - Új-Zélandi dollár',
'RSD - Serbian dinar' => 'RSD - Szerb dínár',
- 'USD - US Dollar' => 'USD - Amerikai ollár',
+ 'USD - US Dollar' => 'USD - Amerikai dollár',
'Destination column' => 'Cél oszlop',
'Move the task to another column when assigned to a user' => 'Feladat másik oszlopba helyezése felhasználóhoz rendélés után',
'Move the task to another column when assignee is cleared' => 'Feladat másik oszlopba helyezése felhasználóhoz rendélés törlésekor',
'Source column' => 'Forrás oszlop',
- // 'Transitions' => '',
- // 'Executer' => '',
- // 'Time spent in the column' => '',
- // 'Task transitions' => '',
- // 'Task transitions export' => '',
- // 'This report contains all column moves for each task with the date, the user and the time spent for each transition.' => '',
- // 'Currency rates' => '',
- // 'Rate' => '',
- // 'Change reference currency' => '',
- // 'Add a new currency rate' => '',
- // 'Reference currency' => '',
- // 'The currency rate have been added successfully.' => '',
- // 'Unable to add this currency rate.' => '',
- // 'Webhook URL' => '',
- // '%s remove the assignee of the task %s' => '',
- // 'Enable Gravatar images' => '',
- // 'Information' => '',
- // 'Check two factor authentication code' => '',
- // 'The two factor authentication code is not valid.' => '',
- // 'The two factor authentication code is valid.' => '',
- // 'Code' => '',
- // 'Two factor authentication' => '',
- // 'This QR code contains the key URI: ' => '',
- // 'Check my code' => '',
- // 'Secret key: ' => '',
- // 'Test your device' => '',
- // 'Assign a color when the task is moved to a specific column' => '',
- // '%s via Kanboard' => '',
+ 'Transitions' => 'Állapot-átmenetek',
+ 'Executer' => 'Végrehajtó',
+ 'Time spent in the column' => 'Az oszlopban töltött idő',
+ 'Task transitions' => 'Feladat állapot-átmenetek',
+ 'Task transitions export' => 'Feladat állapot-átmenetek exportálása',
+ 'This report contains all column moves for each task with the date, the user and the time spent for each transition.' => 'Ez a riport az összes feladatra vonatkozóan tartalmazza az oszlop mozgatásokat. Szerepel benne a dátum, a felhasználó neve, és az egyes állapot-átemenetekkel eltöltött idő.',
+ 'Currency rates' => 'Árfolyamok',
+ 'Rate' => 'Árfolyam',
+ 'Change reference currency' => 'A bázis pénznem megváltoztatása',
+ 'Add a new currency rate' => 'Új átváltási árfolyam megadása',
+ 'Reference currency' => 'Bázis pénznem',
+ 'The currency rate have been added successfully.' => 'Az átváltási árfolyammal történő bővítés sikerült',
+ 'Unable to add this currency rate.' => 'Nem sikerült az átváltási árfolyam felvétele',
+ 'Webhook URL' => 'Webhook URL',
+ '%s remove the assignee of the task %s' => '%s eltávolította a %s feladathoz rendelt személyt',
+ 'Enable Gravatar images' => 'Gravatár képek engedélyezése',
+ 'Information' => 'Információ',
+ 'Check two factor authentication code' => 'Két fázisú beléptető kód ellenőrzése',
+ 'The two factor authentication code is not valid.' => 'A két fázisú beléptető kód érvénytelen',
+ 'The two factor authentication code is valid.' => 'A két fázisú beléptető kód érvényes',
+ 'Code' => 'Kód',
+ 'Two factor authentication' => 'Két fázisú beléptetés',
+ 'This QR code contains the key URI: ' => 'Ez a QR kód a következő kulcs URI-t tartalmazza: ',
+ 'Check my code' => 'A kódom ellenőrzése',
+ 'Secret key: ' => 'Titkos kulcs',
+ 'Test your device' => 'Az eszköz ellenőrzése',
+ 'Assign a color when the task is moved to a specific column' => 'Szín hozzárendelése, ha a feladatot egy adott oszlopba mozgatták',
+ '%s via Kanboard' => '%s a Kanboard-on keresztül',
// 'Burndown chart for "%s"' => '',
// 'Burndown chart' => '',
- // 'This chart show the task complexity over the time (Work Remaining).' => '',
- // 'Screenshot taken %s' => '',
- // 'Add a screenshot' => '',
- // 'Take a screenshot and press CTRL+V or ⌘+V to paste here.' => '',
- // 'Screenshot uploaded successfully.' => '',
- // 'SEK - Swedish Krona' => '',
- // 'Identifier' => '',
- // 'Disable two factor authentication' => '',
- // 'Do you really want to disable the two factor authentication for this user: "%s"?' => '',
- // 'Edit link' => '',
- // 'Start to type task title...' => '',
- // 'A task cannot be linked to itself' => '',
- // 'The exact same link already exists' => '',
- // 'Recurrent task is scheduled to be generated' => '',
- // 'Score' => '',
- // 'The identifier must be unique' => '',
- // 'This linked task id doesn\'t exists' => '',
- // 'This value must be alphanumeric' => '',
- // 'Edit recurrence' => '',
- // 'Generate recurrent task' => '',
- // 'Trigger to generate recurrent task' => '',
- // 'Factor to calculate new due date' => '',
- // 'Timeframe to calculate new due date' => '',
- // 'Base date to calculate new due date' => '',
- // 'Action date' => '',
- // 'Base date to calculate new due date: ' => '',
- // 'This task has created this child task: ' => '',
- // 'Day(s)' => '',
- // 'Existing due date' => '',
- // 'Factor to calculate new due date: ' => '',
- // 'Month(s)' => '',
- // 'Recurrence' => '',
- // 'This task has been created by: ' => '',
- // 'Recurrent task has been generated:' => '',
- // 'Timeframe to calculate new due date: ' => '',
- // 'Trigger to generate recurrent task: ' => '',
- // 'When task is closed' => '',
- // 'When task is moved from first column' => '',
- // 'When task is moved to last column' => '',
- // 'Year(s)' => '',
- // 'Calendar settings' => '',
- // 'Project calendar view' => '',
- // 'Project settings' => '',
- // 'Show subtasks based on the time tracking' => '',
- // 'Show tasks based on the creation date' => '',
- // 'Show tasks based on the start date' => '',
- // 'Subtasks time tracking' => '',
- // 'User calendar view' => '',
- // 'Automatically update the start date' => '',
+ 'This chart show the task complexity over the time (Work Remaining).' => 'Ez a diagram a feladat időbeli bonyolultságát ábrázolja (mennyi munka van hátra)',
+ 'Screenshot taken %s' => 'A képernyőmentés megtörtént, %s',
+ 'Add a screenshot' => 'Képernyőmentés hozzáadása',
+ 'Take a screenshot and press CTRL+V or ⌘+V to paste here.' => 'Végezzen képernyőmentést, majd a CTRL+V vagy ⌘+V megnyomásával másolja be ide.',
+ 'Screenshot uploaded successfully.' => 'A képernyőmentés feltöltése sikeresen megtörtént.',
+ 'SEK - Swedish Krona' => 'SEK - Svéd korona',
+ 'Identifier' => 'Azonosító',
+ 'Disable two factor authentication' => 'A kétfázisú beléptetés letiltása',
+ 'Do you really want to disable the two factor authentication for this user: "%s"?' => 'Valóban le akarja tiltani a kétfázisú beléptetést ennél a felhasználónál: "%s"?',
+ 'Edit link' => 'Hivatkozás szerkesztése',
+ 'Start to type task title...' => 'Kezdje el begépelni a feladat címét... ',
+ 'A task cannot be linked to itself' => 'Egy feladatot nem lehet önmagához kapcsolni',
+ 'The exact same link already exists' => 'Már létezik pontosan ugyanez a hivatkozás',
+ 'Recurrent task is scheduled to be generated' => 'Az ismétlődő feladat előállítása ütemezve lett',
+ 'Score' => 'Pontszám',
+ 'The identifier must be unique' => 'Egyedi azonosító szükséges',
+ 'This linked task id doesn\'t exists' => 'Ez a hivatkozott feladat nem létezik',
+ 'This value must be alphanumeric' => 'Alfanumerikus érték szükséges',
+ 'Edit recurrence' => 'Ismétlődés szerkesztése',
+ 'Generate recurrent task' => 'Ismétlődő feladat előállítása',
+ 'Trigger to generate recurrent task' => 'Az ismétlődő feladatot előállító trigger',
+ 'Factor to calculate new due date' => 'Az új határidő kiszámításához használt tényező',
+ 'Timeframe to calculate new due date' => 'Az új határidő kiszámításához használt időablak',
+ 'Base date to calculate new due date' => 'A határidő kiszámításához használt kezdő dátum',
+ 'Action date' => 'Intézkedés dátuma',
+ 'Base date to calculate new due date: ' => 'Az új határidő kiszámításához használt kezdő dátum: ',
+ 'This task has created this child task: ' => 'Ez a feladat a következő leszármazott feladatot hozta létre: ',
+ 'Day(s)' => 'Nap(ok)',
+ 'Existing due date' => 'A jelenlegi határidő',
+ 'Factor to calculate new due date: ' => 'Az új határidő kiszámításához használt tényező: ',
+ 'Month(s)' => 'Hónap(ok)',
+ 'Recurrence' => 'Ismétlődés',
+ 'This task has been created by: ' => 'Ezt a feladatot a következő személy hozta létre: ',
+ 'Recurrent task has been generated:' => 'Ismétlődő feladat lett létrehozva: ',
+ 'Timeframe to calculate new due date: ' => 'Az új határidő kiszámításához használt időablak: ',
+ 'Trigger to generate recurrent task: ' => 'Az ismétlődő feladatot előállító trigger: ',
+ 'When task is closed' => 'Mikor a feladat be lett zárva',
+ 'When task is moved from first column' => 'Mikor a feladat az első oszlopból el lett mozgatva',
+ 'When task is moved to last column' => 'Mikor a feladat az utolsó oszlopba lett elmozgatva',
+ 'Year(s)' => 'Év(ek)',
+ 'Calendar settings' => 'Naptár beállítások',
+ 'Project calendar view' => 'A projekt megjelenítése naptári formában',
+ 'Project settings' => 'Projekt beállítások',
+ 'Show subtasks based on the time tracking' => 'A részfeladatok megjelenítése az idő nyomkövetés alapján',
+ 'Show tasks based on the creation date' => 'A feladatok megjelenítése a létrehozás dátuma alapján',
+ 'Show tasks based on the start date' => 'A feladatok megjelenítése a kezdő dátum alapján',
+ 'Subtasks time tracking' => 'A részfeladatok idejének megjelenítése',
+ 'User calendar view' => 'A felhasználó naptárának megjelenítése',
+ 'Automatically update the start date' => 'A kezdő dátum automatikus módosítása',
// 'iCal feed' => '',
- // 'Preferences' => '',
- // 'Security' => '',
- // 'Two factor authentication disabled' => '',
- // 'Two factor authentication enabled' => '',
- // 'Unable to update this user.' => '',
- // 'There is no user management for private projects.' => '',
- // 'User that will receive the email' => '',
- // 'Email subject' => '',
- // 'Date' => '',
- // 'Add a comment log when moving the task between columns' => '',
- // 'Move the task to another column when the category is changed' => '',
- // 'Send a task by email to someone' => '',
- // 'Reopen a task' => '',
- // 'Column change' => '',
- // 'Position change' => '',
- // 'Swimlane change' => '',
- // 'Assignee change' => '',
- // '[%s] Overdue tasks' => '',
- // 'Notification' => '',
- // '%s moved the task #%d to the first swimlane' => '',
- // '%s moved the task #%d to the swimlane "%s"' => '',
- // 'Swimlane' => '',
- // 'Gravatar' => '',
- // '%s moved the task %s to the first swimlane' => '',
- // '%s moved the task %s to the swimlane "%s"' => '',
- // 'This report contains all subtasks information for the given date range.' => '',
- // 'This report contains all tasks information for the given date range.' => '',
- // 'Project activities for %s' => '',
- // 'view the board on Kanboard' => '',
- // 'The task have been moved to the first swimlane' => '',
- // 'The task have been moved to another swimlane:' => '',
- // 'Overdue tasks for the project(s) "%s"' => '',
- // 'New title: %s' => '',
- // 'The task is not assigned anymore' => '',
- // 'New assignee: %s' => '',
- // 'There is no category now' => '',
- // 'New category: %s' => '',
- // 'New color: %s' => '',
- // 'New complexity: %d' => '',
- // 'The due date have been removed' => '',
- // 'There is no description anymore' => '',
- // 'Recurrence settings have been modified' => '',
- // 'Time spent changed: %sh' => '',
- // 'Time estimated changed: %sh' => '',
- // 'The field "%s" have been updated' => '',
- // 'The description has been modified:' => '',
- // 'Do you really want to close the task "%s" as well as all subtasks?' => '',
- // 'I want to receive notifications for:' => '',
- // 'All tasks' => '',
- // 'Only for tasks assigned to me' => '',
- // 'Only for tasks created by me' => '',
- // 'Only for tasks created by me and assigned to me' => '',
- // '%%Y-%%m-%%d' => '',
- // 'Total for all columns' => '',
- // 'You need at least 2 days of data to show the chart.' => '',
- // '<15m' => '',
- // '<30m' => '',
- // 'Stop timer' => '',
- // 'Start timer' => '',
- // 'Add project member' => '',
- // 'Enable notifications' => '',
- // 'My activity stream' => '',
- // 'My calendar' => '',
- // 'Search tasks' => '',
- // 'Reset filters' => '',
- // 'My tasks due tomorrow' => '',
- // 'Tasks due today' => '',
- // 'Tasks due tomorrow' => '',
- // 'Tasks due yesterday' => '',
- // 'Closed tasks' => '',
- // 'Open tasks' => '',
- // 'Not assigned' => '',
- // 'View advanced search syntax' => '',
- // 'Overview' => '',
- // 'Board/Calendar/List view' => '',
- // 'Switch to the board view' => '',
- // 'Switch to the calendar view' => '',
- // 'Switch to the list view' => '',
- // 'Go to the search/filter box' => '',
- // 'There is no activity yet.' => '',
- // 'No tasks found.' => '',
- // 'Keyboard shortcut: "%s"' => '',
- // 'List' => '',
- // 'Filter' => '',
- // 'Advanced search' => '',
- // 'Example of query: ' => '',
- // 'Search by project: ' => '',
- // 'Search by column: ' => '',
- // 'Search by assignee: ' => '',
- // 'Search by color: ' => '',
- // 'Search by category: ' => '',
- // 'Search by description: ' => '',
- // 'Search by due date: ' => '',
- // 'Lead and Cycle time for "%s"' => '',
- // 'Average time spent into each column for "%s"' => '',
- // 'Average time spent into each column' => '',
- // 'Average time spent' => '',
- // 'This chart show the average time spent into each column for the last %d tasks.' => '',
- // 'Average Lead and Cycle time' => '',
- // 'Average lead time: ' => '',
- // 'Average cycle time: ' => '',
- // 'Cycle Time' => '',
- // 'Lead Time' => '',
- // 'This chart show the average lead and cycle time for the last %d tasks over the time.' => '',
- // 'Average time into each column' => '',
- // 'Lead and cycle time' => '',
- // 'Lead time: ' => '',
- // 'Cycle time: ' => '',
- // 'Time spent into each column' => '',
- // 'The lead time is the duration between the task creation and the completion.' => '',
- // 'The cycle time is the duration between the start date and the completion.' => '',
- // 'If the task is not closed the current time is used instead of the completion date.' => '',
- // 'Set automatically the start date' => '',
- // 'Edit Authentication' => '',
- // 'Remote user' => '',
- // 'Remote users do not store their password in Kanboard database, examples: LDAP, Google and Github accounts.' => '',
- // 'If you check the box "Disallow login form", credentials entered in the login form will be ignored.' => '',
- // 'New remote user' => '',
- // 'New local user' => '',
- // 'Default task color' => '',
- // 'This feature does not work with all browsers.' => '',
- // 'There is no destination project available.' => '',
- // 'Trigger automatically subtask time tracking' => '',
- // 'Include closed tasks in the cumulative flow diagram' => '',
- // 'Current swimlane: %s' => '',
- // 'Current column: %s' => '',
- // 'Current category: %s' => '',
- // 'no category' => '',
- // 'Current assignee: %s' => '',
- // 'not assigned' => '',
- // 'Author:' => '',
- // 'contributors' => '',
- // 'License:' => '',
- // 'License' => '',
- // 'Enter the text below' => '',
- // 'Gantt chart for %s' => '',
- // 'Sort by position' => '',
- // 'Sort by date' => '',
- // 'Add task' => '',
- // 'Start date:' => '',
- // 'Due date:' => '',
- // 'There is no start date or due date for this task.' => '',
- // 'Moving or resizing a task will change the start and due date of the task.' => '',
- // 'There is no task in your project.' => '',
- // 'Gantt chart' => '',
- // 'People who are project managers' => '',
- // 'People who are project members' => '',
- // 'NOK - Norwegian Krone' => '',
- // 'Show this column' => '',
- // 'Hide this column' => '',
- // 'open file' => '',
- // 'End date' => '',
- // 'Users overview' => '',
- // 'Members' => '',
- // 'Shared project' => '',
- // 'Project managers' => '',
- // 'Gantt chart for all projects' => '',
- // 'Projects list' => '',
- // 'Gantt chart for this project' => '',
- // 'Project board' => '',
- // 'End date:' => '',
- // 'There is no start date or end date for this project.' => '',
- // 'Projects Gantt chart' => '',
- // 'Change task color when using a specific task link' => '',
- // 'Task link creation or modification' => '',
- // 'Milestone' => '',
- // 'Documentation: %s' => '',
- // 'Switch to the Gantt chart view' => '',
- // 'Reset the search/filter box' => '',
- // 'Documentation' => '',
- // 'Table of contents' => '',
- // 'Gantt' => '',
- // 'Author' => '',
- // 'Version' => '',
- // 'Plugins' => '',
- // 'There is no plugin loaded.' => '',
- // 'Set maximum column height' => '',
- // 'Remove maximum column height' => '',
- // 'My notifications' => '',
- // 'Custom filters' => '',
- // 'Your custom filter have been created successfully.' => '',
- // 'Unable to create your custom filter.' => '',
- // 'Custom filter removed successfully.' => '',
- // 'Unable to remove this custom filter.' => '',
- // 'Edit custom filter' => '',
- // 'Your custom filter have been updated successfully.' => '',
- // 'Unable to update custom filter.' => '',
- // 'Web' => '',
- // 'New attachment on task #%d: %s' => '',
- // 'New comment on task #%d' => '',
- // 'Comment updated on task #%d' => '',
- // 'New subtask on task #%d' => '',
- // 'Subtask updated on task #%d' => '',
- // 'New task #%d: %s' => '',
- // 'Task updated #%d' => '',
- // 'Task #%d closed' => '',
- // 'Task #%d opened' => '',
- // 'Column changed for task #%d' => '',
- // 'New position for task #%d' => '',
- // 'Swimlane changed for task #%d' => '',
- // 'Assignee changed on task #%d' => '',
- // '%d overdue tasks' => '',
- // 'Task #%d is overdue' => '',
- // 'No new notifications.' => '',
- // 'Mark all as read' => '',
- // 'Mark as read' => '',
- // 'Total number of tasks in this column across all swimlanes' => '',
- // 'Collapse swimlane' => '',
- // 'Expand swimlane' => '',
- // 'Add a new filter' => '',
- // 'Share with all project members' => '',
- // 'Shared' => '',
- // 'Owner' => '',
- // 'Unread notifications' => '',
- // 'Notification methods:' => '',
- // 'Import tasks from CSV file' => '',
- // 'Unable to read your file' => '',
- // '%d task(s) have been imported successfully.' => '',
- // 'Nothing have been imported!' => '',
- // 'Import users from CSV file' => '',
- // '%d user(s) have been imported successfully.' => '',
+ 'Preferences' => 'Preferenciák',
+ 'Security' => 'Biztonság',
+ 'Two factor authentication disabled' => 'A két fázisú beléptetés tiltva van',
+ 'Two factor authentication enabled' => 'A két fázisú beléptetés engedélyezve van',
+ 'Unable to update this user.' => 'A felhasználó {adatainak} módosítása nem sikerült.',
+ 'There is no user management for private projects.' => 'A privát projektek esetén nincs felhasználó kezelés',
+ 'User that will receive the email' => 'Az email-t a következő felhaszáló fogja megkapni',
+ 'Email subject' => 'Email tárgy',
+ 'Date' => 'Dátum',
+ 'Add a comment log when moving the task between columns' => 'Egy napló megjegyzés létrehozása a feladat oszlopok közötti mozgatásakor',
+ 'Move the task to another column when the category is changed' => 'A feladat átmozgatása egy másik oszlopba, ha megváltozik a kategória',
+ 'Send a task by email to someone' => 'Email-en egy feladat küldése valakinek',
+ 'Reopen a task' => 'Egy feladat újbóli megnyitása',
+ 'Column change' => 'Oszlop módosítás',
+ 'Position change' => 'Helyzet módosítás',
+ 'Swimlane change' => 'Sáv módosítás',
+ 'Assignee change' => 'Felelős módosítása',
+ '[%s] Overdue tasks' => '[%s] késésben lévő feladat',
+ 'Notification' => 'Értesítés',
+ '%s moved the task #%d to the first swimlane' => '%s a #%d feladatot az első sávba mozgatta',
+ '%s moved the task #%d to the swimlane "%s"' => '%s a #%d feladatot a "%s" sávba mozgatta',
+ 'Swimlane' => 'Sáv',
+ 'Gravatar' => 'Gravatár',
+ '%s moved the task %s to the first swimlane' => '%s a %s feladatot az első sávba mozgatta',
+ '%s moved the task %s to the swimlane "%s"' => '%s a %s feladatot a "%s" sávba mozgatta',
+ 'This report contains all subtasks information for the given date range.' => 'Ez a riport az adott dátumtartományra vonatkozón az összes részfeladatot tartalmazza',
+ 'This report contains all tasks information for the given date range.' => 'Ez a riport az adott dátumtartományra vonatkozóan az összes feladatot tartalmazza',
+ 'Project activities for %s' => '%s projekt tevékenységei',
+ 'view the board on Kanboard' => 'a tábla megjelenítése a Kanboard-on',
+ 'The task have been moved to the first swimlane' => 'A feladat ez első sávba lett elmozgatva',
+ 'The task have been moved to another swimlane:' => 'A feladat egy másik sávba lett elmozgatva',
+ 'New title: %s' => 'Új cím: %s',
+ 'The task is not assigned anymore' => 'A feladatnak már nincs felelőse',
+ 'New assignee: %s' => 'Az új felelős: %s',
+ 'There is no category now' => 'Jelenleg nincs kategória',
+ 'New category: %s' => 'Az új kategória: %s',
+ 'New color: %s' => 'Az új szín: %s',
+ 'New complexity: %d' => 'Az új bonyolultság: %d',
+ 'The due date have been removed' => 'A határidő törölve lett',
+ 'There is no description anymore' => 'Többé már nincs leírás',
+ 'Recurrence settings have been modified' => 'Az ismétlődés beállításai módosultak',
+ 'Time spent changed: %sh' => 'Módosult a ráfordított idő: %s óra',
+ 'Time estimated changed: %sh' => 'Módosult az időbecslés: %s óra',
+ 'The field "%s" have been updated' => 'A "%s" mező módosítva lett',
+ 'The description has been modified:' => 'A leírás módosítva lett:',
+ 'Do you really want to close the task "%s" as well as all subtasks?' => 'Valóban be akarja zárni a "%s" feladatot, valamint a hozzá tartozó részfeladatokat?',
+ 'I want to receive notifications for:' => 'Értesítéseket szeretnék kapni a következőkről:',
+ 'All tasks' => 'Az összes feladat',
+ 'Only for tasks assigned to me' => 'Csak a hozzám rendelt feladatok',
+ 'Only for tasks created by me' => 'Csak az általam létrehozott feladatok',
+ 'Only for tasks created by me and assigned to me' => 'Csak az általam lérehozott és a hozzám rendelt feladatok',
+ '%%Y-%%m-%%d' => '%%Y-%%m-%%d',
+ 'Total for all columns' => 'Az összes oszlop összege',
+ 'You need at least 2 days of data to show the chart.' => 'Legalább 2 nap adatára van szükség az ábra megjelenítéséshez',
+ '<15m' => '15p',
+ '<30m' => '30p',
+ 'Stop timer' => 'Időmérő leállítása',
+ 'Start timer' => 'Időmérő elindítása',
+ 'Add project member' => 'Projekt tag hozzáadása',
+ 'My activity stream' => 'Tevékenységem',
+ 'My calendar' => 'Naptáram',
+ 'Search tasks' => 'Feladatok közötti keresés',
+ 'Reset filters' => 'Szűrő alaphelyzetbe állítás',
+ 'My tasks due tomorrow' => 'Holnapi határidejű feladataim',
+ 'Tasks due today' => 'Mai határidejű feladatok',
+ 'Tasks due tomorrow' => 'Holnapi határidejű feladatok',
+ 'Tasks due yesterday' => 'Tegnapi határidejű feladatok',
+ 'Closed tasks' => 'Lezárt feladatok',
+ 'Open tasks' => 'Nyitott feladatok',
+ 'Not assigned' => 'Nincs felelős',
+ 'View advanced search syntax' => 'Részletes keresés megjelenítése',
+ 'Overview' => 'Áttekintés',
+ 'Board/Calendar/List view' => 'Tábla/Naptár/Lista nézet',
+ 'Switch to the board view' => 'Átkapcsolás tábla nézetbe',
+ 'Switch to the calendar view' => 'Átkapcsolás naptár nézetbe',
+ 'Switch to the list view' => 'Átkapcsolás lista nézetbe',
+ 'Go to the search/filter box' => 'Ugrás a keresés/szűrés dobozhoz',
+ 'There is no activity yet.' => 'Még nincs tevékenység',
+ 'No tasks found.' => 'Nincs feladat.',
+ 'Keyboard shortcut: "%s"' => 'Billentyű parancsok: "%s"',
+ 'List' => 'Lista',
+ 'Filter' => 'Szűrő',
+ 'Advanced search' => 'Keresés haladóknak',
+ 'Example of query: ' => 'Lekérdezési példa: ',
+ 'Search by project: ' => 'Keresés projekt alapján: ',
+ 'Search by column: ' => 'Keresés oszlop alapján: ',
+ 'Search by assignee: ' => 'Keresés felelős alapján: ',
+ 'Search by color: ' => 'Keresés szín alapján: ',
+ 'Search by category: ' => 'Keresés kategória alapján: ',
+ 'Search by description: ' => 'Keresés leírás alapján: ',
+ 'Search by due date: ' => 'Keresés határidő alapján: ',
+ 'Lead and Cycle time for "%s"' => 'A "%s" átfutási ideje és ciklusideje',
+ 'Average time spent into each column for "%s"' => 'A "%s" során az egyes oszlopokban töltött átlagos idő',
+ 'Average time spent into each column' => 'Az egyes oszlopokban töltött átlagos idő',
+ 'Average time spent' => 'Az eltöltött átlagos idő',
+ 'This chart show the average time spent into each column for the last %d tasks.' => 'Ez az ábra az utolsó %d feladatra vonatkozóan mutatja az egyes oszlopkban eltöltött átlagos időt.',
+ 'Average Lead and Cycle time' => 'Átlagos átfutási idő és ciklusidő',
+ 'Average lead time: ' => 'Átlagos átfutási idő: ',
+ 'Average cycle time: ' => 'Átlagos ciklusidő: ',
+ 'Cycle Time' => 'Ciklusidő',
+ 'Lead Time' => 'Átfutási idő',
+ 'This chart show the average lead and cycle time for the last %d tasks over the time.' => 'Ez az ábra az utolsó %d feladatra vonatkozóan mutatja az átlagos átfutási időt és ciklusidőt az idő függvényében.',
+ 'Average time into each column' => 'Az egyes oszlopokban töltött átlagos idő',
+ 'Lead and cycle time' => 'Átfutási és ciklusidő',
+ 'Lead time: ' => 'Átfutási idő: ',
+ 'Cycle time: ' => 'Ciklusidő: ',
+ 'Time spent into each column' => 'Az egyes oszlopokban töltött idő',
+ 'The lead time is the duration between the task creation and the completion.' => 'Az átfutási idő a feladat létrehozása és befejezése között eltelt idő.',
+ 'The cycle time is the duration between the start date and the completion.' => 'A ciklusidő a feladat elkezdése és befejezése közötti eltelt idő.',
+ 'If the task is not closed the current time is used instead of the completion date.' => 'Ha a feladat még nincs lezárva, akkor befejezés ideje helyett az aktuális idő lesz használva.',
+ 'Set automatically the start date' => 'A kezdési idő automatikus beállítása',
+ 'Edit Authentication' => 'A beléptetés szerkesztése',
+ 'Remote user' => 'Távoli felhasználó',
+ 'Remote users do not store their password in Kanboard database, examples: LDAP, Google and Github accounts.' => 'A távoli felhasználók jelszava nem a Kanboard adatbázisban van tárolva. Példák: LDAP, Google és GitHub számlák.',
+ 'If you check the box "Disallow login form", credentials entered in the login form will be ignored.' => 'Ha bekattintja a "Bejelentkezési ablak tiltása" jelölőnégyzetet, akkor a login ablakban megadott jelszó nem lesz figyelembe véve.',
+ 'New remote user' => 'Új távoli felhasználó',
+ 'New local user' => 'Új helyi felhasználó',
+ 'Default task color' => 'A feladathoz rendelt alapszín',
+ 'This feature does not work with all browsers.' => 'Ez a jellemző nem minden böngészőben működik.',
+ 'There is no destination project available.' => 'Nincs ilyen cél projekt.',
+ 'Trigger automatically subtask time tracking' => 'A részfeladatok időfelhasználas-követésének automatikus indítása',
+ 'Include closed tasks in the cumulative flow diagram' => 'A lezárt feladatok szerepeltetáse az összesített folyamatábrán',
+ 'Current swimlane: %s' => 'Aktuális sáv: %s',
+ 'Current column: %s' => 'Aktuális oszlop: %s',
+ 'Current category: %s' => 'Aktuális kategória: %s',
+ 'no category' => 'nincs kategória',
+ 'Current assignee: %s' => 'Aktuális felelős: %s',
+ 'not assigned' => 'nincs kijelölt felelős',
+ 'Author:' => 'Szerző:',
+ 'contributors' => 'bedolgozók',
+ 'License:' => 'Engedély:',
+ 'License' => 'Engedély',
+ 'Enter the text below' => 'Adja be a lenti szöveget',
+ 'Gantt chart for %s' => 'Gantt diagram a %s számára',
+ 'Sort by position' => 'Rendezés hely szerint',
+ 'Sort by date' => 'Rendezés idő szerint',
+ 'Add task' => 'Feladat hozzáadása',
+ 'Start date:' => 'Kezdés ideje: ',
+ 'Due date:' => 'Határidő: ',
+ 'There is no start date or due date for this task.' => 'Ehhez a feladathoz nem adtak meg kezdési időt vagy határidőt.',
+ 'Moving or resizing a task will change the start and due date of the task.' => 'A feladat elmozgatása vagy méretének megváltoztatása meg fogja változtatni a feladat kezdési idejét és határidejét.',
+ 'There is no task in your project.' => 'Az ön projektjében nincsenek feladatok.',
+ 'Gantt chart' => 'Gantt diagram',
+ 'People who are project managers' => 'Projekt vezetők',
+ 'People who are project members' => 'Projekt tagok',
+ 'NOK - Norwegian Krone' => 'NOK - Norvég korona',
+ 'Show this column' => 'Oszlop mutatása',
+ 'Hide this column' => 'Oszlop elrejtése',
+ 'open file' => 'fájl megnyitás',
+ 'End date' => 'Végdátum',
+ 'Users overview' => 'Felhasználók áttekintése',
+ 'Members' => 'Tagok',
+ 'Shared project' => 'Közös projekt',
+ 'Project managers' => 'Projektvezetők',
+ 'Gantt chart for all projects' => 'Gantt diagram az összes projektre vonatkozóan',
+ 'Projects list' => 'Projekt lista',
+ 'Gantt chart for this project' => 'Gantt diagram erre a projektre vonatkozóan',
+ 'Project board' => 'Projekt tábla',
+ 'End date:' => 'Befejezés dátuma: ',
+ 'There is no start date or end date for this project.' => 'Ennél a projektnél nem adták meg a kezdés és a befejezés dátumát.',
+ 'Projects Gantt chart' => 'A projektek Gantt diagramja',
+ 'Change task color when using a specific task link' => 'Az egyes specifikus feladat hivatkozások használatakor a feladat színének megváltoztatása',
+ 'Task link creation or modification' => 'Feladat hivatkozás létrehozása vagy módosítása',
+ 'Milestone' => 'Mérföldkő',
+ 'Documentation: %s' => 'Dokumentáció: %s',
+ 'Switch to the Gantt chart view' => 'Átkapcsolás a Gantt diagram nézetre',
+ 'Reset the search/filter box' => 'A keresés/szűrés doboz alaphelyzetbe állítása',
+ 'Documentation' => 'Dokumentáció',
+ 'Table of contents' => 'Tartalomjegyzék',
+ 'Gantt' => 'Gantt',
+ 'Author' => 'Szerző',
+ 'Version' => 'Verzió',
+ 'Plugins' => 'Plugin-ek',
+ 'There is no plugin loaded.' => 'Nincs betöltött plugin.',
+ 'Set maximum column height' => 'Max. oszlopmagasság beállítása',
+ 'Remove maximum column height' => 'Max. oszlopmagasság törlése',
+ 'My notifications' => 'Emlékeztetőim',
+ 'Custom filters' => 'Egyedi szűrők',
+ 'Your custom filter have been created successfully.' => 'Az ön egyedi szűrője sikeresen létrejött.',
+ 'Unable to create your custom filter.' => 'Nem sikerült létrehozni az ön egyedi szűrőjét.',
+ 'Custom filter removed successfully.' => 'Az egyedi szűrő sikeresen törölve lett.',
+ 'Unable to remove this custom filter.' => 'Nem sikerült egy egyedi szűrő törlése.',
+ 'Edit custom filter' => 'Egyedi szűrő szerkesztése',
+ 'Your custom filter have been updated successfully.' => 'Az ön egyedi szűrője sikeresen módosult.',
+ 'Unable to update custom filter.' => 'Nem sikerült az egyedi szűrő módosítása',
+ 'Web' => 'Web (háló)',
+ 'New attachment on task #%d: %s' => 'A #%d számú feladatnak új melléklete van: %s',
+ 'New comment on task #%d' => 'A #%d számú feladatnak új megjegyzése van',
+ 'Comment updated on task #%d' => 'A #%d szűmú feladathoz tartozó megjegyzés módosult',
+ 'New subtask on task #%d' => 'A #%d számú feladatnak új részfeladata van',
+ 'Subtask updated on task #%d' => 'A #%d számú feladat részfeladata módosult',
+ 'New task #%d: %s' => 'Új #%d számú feladat: %s',
+ 'Task updated #%d' => 'A #%d számú feladat módosult',
+ 'Task #%d closed' => 'A #%d számú feladat le lett zárva',
+ 'Task #%d opened' => 'A #%d számú feladat meg lett nyitva',
+ 'Column changed for task #%d' => 'A #%d számú feladat oszlopa módosult',
+ 'New position for task #%d' => 'A #%d számú feladat új helyre került',
+ 'Swimlane changed for task #%d' => 'A #%d számú feladat új sávba került',
+ 'Assignee changed on task #%d' => 'A #%d számú feladat felelőse megváltozott',
+ '%d overdue tasks' => '%d db feladatnál van határidő túllépés',
+ 'Task #%d is overdue' => 'A #%d számú feladat határideje lejárt',
+ 'No new notifications.' => 'Nincs új emlékeztető.',
+ 'Mark all as read' => 'Az összes megjelölése olvasottként',
+ 'Mark as read' => 'Megjelölés olvasottként',
+ 'Total number of tasks in this column across all swimlanes' => 'Az ebben az oszlopban, az összes sávban lévő feladatok száma',
+ 'Collapse swimlane' => 'Sáv összecsukása',
+ 'Expand swimlane' => 'Sáv lenyitása',
+ 'Add a new filter' => 'Új szűrő hozzáadása',
+ 'Share with all project members' => 'Megosztás minden projekt taggal',
+ 'Shared' => 'Megosztva',
+ 'Owner' => 'Tulajdonos',
+ 'Unread notifications' => 'Olvasatlan értesítések',
+ 'Notification methods:' => 'Értesítési módszerek:',
+ 'Import tasks from CSV file' => 'Feladatok beolvasása CSV fájlból',
+ 'Unable to read your file' => 'A fájl nem olvasható',
+ '%d task(s) have been imported successfully.' => '%d feladat sikeresen feldolgozva.',
+ 'Nothing have been imported!' => 'Nem történt beolvasás!',
+ 'Import users from CSV file' => 'Felhasználók importálása CSV fájlból',
+ '%d user(s) have been imported successfully.' => '%d felhasználó sikeresen importálva.',
// 'Comma' => '',
// 'Semi-colon' => '',
// 'Tab' => '',
// 'Vertical bar' => '',
// 'Double Quote' => '',
// 'Single Quote' => '',
- // '%s attached a file to the task #%d' => '',
- // 'There is no column or swimlane activated in your project!' => '',
- // 'Append filter (instead of replacement)' => '',
- // 'Append/Replace' => '',
- // 'Append' => '',
- // 'Replace' => '',
- // 'Import' => '',
- // 'change sorting' => '',
- // 'Tasks Importation' => '',
+ '%s attached a file to the task #%d' => '%s hozzákapcsolt a #%d feladathoz egy fájlt',
+ 'There is no column or swimlane activated in your project!' => 'Az ön projektjében nincs aktív oszlop vagy sáv!',
+ 'Append filter (instead of replacement)' => 'Szűrő hozzáfűzése (a helyettesítés helyett)',
+ 'Append/Replace' => 'Hozzáfűzés/Helyettesítés',
+ 'Append' => 'Hozzáfűz',
+ 'Replace' => 'Helyettesít',
+ 'Import' => 'Importál',
+ 'change sorting' => 'rendezési sorrend megváltoztatása',
+ 'Tasks Importation' => 'Feladat importálás',
// 'Delimiter' => '',
// 'Enclosure' => '',
- // 'CSV File' => '',
- // 'Instructions' => '',
- // 'Your file must use the predefined CSV format' => '',
- // 'Your file must be encoded in UTF-8' => '',
- // 'The first row must be the header' => '',
- // 'Duplicates are not verified for you' => '',
- // 'The due date must use the ISO format: YYYY-MM-DD' => '',
- // 'Download CSV template' => '',
- // 'No external integration registered.' => '',
- // 'Duplicates are not imported' => '',
- // 'Usernames must be lowercase and unique' => '',
- // 'Passwords will be encrypted if present' => '',
- // '%s attached a new file to the task %s' => '',
- // 'Link type' => '',
- // 'Assign automatically a category based on a link' => '',
- // 'BAM - Konvertible Mark' => '',
- // 'Assignee Username' => '',
- // 'Assignee Name' => '',
- // 'Groups' => '',
- // 'Members of %s' => '',
- // 'New group' => '',
- // 'Group created successfully.' => '',
- // 'Unable to create your group.' => '',
- // 'Edit group' => '',
- // 'Group updated successfully.' => '',
- // 'Unable to update your group.' => '',
- // 'Add group member to "%s"' => '',
- // 'Group member added successfully.' => '',
- // 'Unable to add group member.' => '',
- // 'Remove user from group "%s"' => '',
- // 'User removed successfully from this group.' => '',
- // 'Unable to remove this user from the group.' => '',
- // 'Remove group' => '',
- // 'Group removed successfully.' => '',
- // 'Unable to remove this group.' => '',
- // 'Project Permissions' => '',
- // 'Manager' => '',
- // 'Project Manager' => '',
- // 'Project Member' => '',
- // 'Project Viewer' => '',
- // 'Your account is locked for %d minutes' => '',
- // 'Invalid captcha' => '',
- // 'The name must be unique' => '',
- // 'View all groups' => '',
- // 'View group members' => '',
- // 'There is no user available.' => '',
- // 'Do you really want to remove the user "%s" from the group "%s"?' => '',
- // 'There is no group.' => '',
- // 'External Id' => '',
- // 'Add group member' => '',
- // 'Do you really want to remove this group: "%s"?' => '',
- // 'There is no user in this group.' => '',
- // 'Remove this user' => '',
- // 'Permissions' => '',
- // 'Allowed Users' => '',
- // 'No user have been allowed specifically.' => '',
- // 'Role' => '',
- // 'Enter user name...' => '',
- // 'Allowed Groups' => '',
- // 'No group have been allowed specifically.' => '',
- // 'Group' => '',
- // 'Group Name' => '',
- // 'Enter group name...' => '',
- // 'Role:' => '',
- // 'Project members' => '',
- // 'Compare hours for "%s"' => '',
- // '%s mentioned you in the task #%d' => '',
- // '%s mentioned you in a comment on the task #%d' => '',
- // 'You were mentioned in the task #%d' => '',
- // 'You were mentioned in a comment on the task #%d' => '',
- // 'Mentioned' => '',
- // 'Compare Estimated Time vs Actual Time' => '',
- // 'Estimated hours: ' => '',
- // 'Actual hours: ' => '',
- // 'Hours Spent' => '',
- // 'Hours Estimated' => '',
- // 'Estimated Time' => '',
- // 'Actual Time' => '',
- // 'Estimated vs actual time' => '',
- // 'RUB - Russian Ruble' => '',
- // 'Assign the task to the person who does the action when the column is changed' => '',
- // 'Close a task in a specific column' => '',
- // 'Time-based One-time Password Algorithm' => '',
- // 'Two-Factor Provider: ' => '',
- // 'Disable two-factor authentication' => '',
- // 'Enable two-factor authentication' => '',
- // 'There is no integration registered at the moment.' => '',
- // 'Password Reset for Kanboard' => '',
- // 'Forgot password?' => '',
- // 'Enable "Forget Password"' => '',
- // 'Password Reset' => '',
- // 'New password' => '',
- // 'Change Password' => '',
- // 'To reset your password click on this link:' => '',
- // 'Last Password Reset' => '',
- // 'The password has never been reinitialized.' => '',
- // 'Creation' => '',
- // 'Expiration' => '',
- // 'Password reset history' => '',
- // 'All tasks of the column "%s" and the swimlane "%s" have been closed successfully.' => '',
- // 'Do you really want to close all tasks of this column?' => '',
- // '%d task(s) in the column "%s" and the swimlane "%s" will be closed.' => '',
- // 'Close all tasks of this column' => '',
- // 'No plugin has registered a project notification method. You can still configure individual notifications in your user profile.' => '',
- // 'My dashboard' => '',
- // 'My profile' => '',
- // 'Project owner: ' => '',
- // 'The project identifier is optional and must be alphanumeric, example: MYPROJECT.' => '',
- // 'Project owner' => '',
- // 'Those dates are useful for the project Gantt chart.' => '',
- // 'Private projects do not have users and groups management.' => '',
- // 'There is no project member.' => '',
- // 'Priority' => '',
- // 'Task priority' => '',
- // 'General' => '',
- // 'Dates' => '',
- // 'Default priority' => '',
- // 'Lowest priority' => '',
- // 'Highest priority' => '',
- // 'If you put zero to the low and high priority, this feature will be disabled.' => '',
- // 'Close a task when there is no activity' => '',
- // 'Duration in days' => '',
- // 'Send email when there is no activity on a task' => '',
- // 'Unable to fetch link information.' => '',
- // 'Daily background job for tasks' => '',
- // 'Auto' => '',
- // 'Related' => '',
- // 'Attachment' => '',
- // 'Title not found' => '',
- // 'Web Link' => '',
- // 'External links' => '',
- // 'Add external link' => '',
- // 'Type' => '',
- // 'Dependency' => '',
- // 'Add internal link' => '',
- // 'Add a new external link' => '',
- // 'Edit external link' => '',
- // 'External link' => '',
- // 'Copy and paste your link here...' => '',
- // 'URL' => '',
- // 'Internal links' => '',
- // 'Assign to me' => '',
- // 'Me' => '',
- // 'Do not duplicate anything' => '',
- // 'Projects management' => '',
- // 'Users management' => '',
- // 'Groups management' => '',
- // 'Create from another project' => '',
- // 'open' => '',
- // 'closed' => '',
- // 'Priority:' => '',
- // 'Reference:' => '',
- // 'Complexity:' => '',
- // 'Swimlane:' => '',
- // 'Column:' => '',
- // 'Position:' => '',
- // 'Creator:' => '',
- // 'Time estimated:' => '',
- // '%s hours' => '',
- // 'Time spent:' => '',
- // 'Created:' => '',
- // 'Modified:' => '',
- // 'Completed:' => '',
- // 'Started:' => '',
- // 'Moved:' => '',
- // 'Task #%d' => '',
- // 'Date and time format' => '',
- // 'Time format' => '',
- // 'Start date: ' => '',
- // 'End date: ' => '',
- // 'New due date: ' => '',
- // 'Start date changed: ' => '',
- // 'Disable private projects' => '',
- // 'Do you really want to remove this custom filter: "%s"?' => '',
- // 'Remove a custom filter' => '',
- // 'User activated successfully.' => '',
- // 'Unable to enable this user.' => '',
- // 'User disabled successfully.' => '',
- // 'Unable to disable this user.' => '',
- // 'All files have been uploaded successfully.' => '',
- // 'View uploaded files' => '',
- // 'The maximum allowed file size is %sB.' => '',
- // 'Choose files again' => '',
- // 'Drag and drop your files here' => '',
- // 'choose files' => '',
- // 'View profile' => '',
- // 'Two Factor' => '',
- // 'Disable user' => '',
- // 'Do you really want to disable this user: "%s"?' => '',
- // 'Enable user' => '',
- // 'Do you really want to enable this user: "%s"?' => '',
- // 'Download' => '',
- // 'Uploaded: %s' => '',
- // 'Size: %s' => '',
- // 'Uploaded by %s' => '',
- // 'Filename' => '',
- // 'Size' => '',
- // 'Column created successfully.' => '',
- // 'Another column with the same name exists in the project' => '',
- // 'Default filters' => '',
- // 'Your board doesn\'t have any column!' => '',
- // 'Change column position' => '',
- // 'Switch to the project overview' => '',
- // 'User filters' => '',
- // 'Category filters' => '',
- // 'Upload a file' => '',
- // 'View file' => '',
- // 'Last activity' => '',
- // 'Change subtask position' => '',
- // 'This value must be greater than %d' => '',
- // 'Another swimlane with the same name exists in the project' => '',
- // 'Example: http://example.kanboard.net/ (used to generate absolute URLs)' => '',
- // 'Actions duplicated successfully.' => '',
- // 'Unable to duplicate actions.' => '',
- // 'Add a new action' => '',
- // 'Import from another project' => '',
- // 'There is no action at the moment.' => '',
- // 'Import actions from another project' => '',
- // 'There is no available project.' => '',
- // 'Local File' => '',
- // 'Configuration' => '',
- // 'PHP version:' => '',
- // 'PHP SAPI:' => '',
- // 'OS version:' => '',
- // 'Database version:' => '',
- // 'Browser:' => '',
- // 'Task view' => '',
- // 'Edit task' => '',
- // 'Edit description' => '',
- // 'New internal link' => '',
- // 'Display list of keyboard shortcuts' => '',
- // 'Menu' => '',
- // 'Set start date' => '',
- // 'Avatar' => '',
- // 'Upload my avatar image' => '',
- // 'Remove my image' => '',
- // 'The OAuth2 state parameter is invalid' => '',
- // 'User not found.' => '',
- // 'Search in activity stream' => '',
- // 'My activities' => '',
- // 'Activity until yesterday' => '',
- // 'Activity until today' => '',
- // 'Search by creator: ' => '',
- // 'Search by creation date: ' => '',
- // 'Search by task status: ' => '',
- // 'Search by task title: ' => '',
- // 'Activity stream search' => '',
- // 'Projects where "%s" is manager' => '',
- // 'Projects where "%s" is member' => '',
- // 'Open tasks assigned to "%s"' => '',
- // 'Closed tasks assigned to "%s"' => '',
+ 'CSV File' => 'CSV fájl',
+ 'Instructions' => 'Utasítások',
+ 'Your file must use the predefined CSV format' => 'A fájlnak az előre definiált CSV formátumot kell használnia',
+ 'Your file must be encoded in UTF-8' => 'A fájlnak UTF-8 karakterkódolást kell használnia',
+ 'The first row must be the header' => 'Az első sor kötelezően a fejléc',
+ 'Duplicates are not verified for you' => 'Az ismétlődések nincsenek ellenőrizve.',
+ 'The due date must use the ISO format: YYYY-MM-DD' => 'A határidőt ISO formátumban kell megadni: YYYY-MM-DD',
+ 'Download CSV template' => 'A CSV minta (template) letöltése',
+ 'No external integration registered.' => 'Nincs külső integráció regisztrálva.',
+ 'Duplicates are not imported' => 'Az ismétlődő értékek nem lesznek beimportálva',
+ 'Usernames must be lowercase and unique' => 'A felhasználói nevekre kötelező, hogy kisbetűsek és egyediek legyenek',
+ 'Passwords will be encrypted if present' => 'A jelszavak titkosítva lesznek',
+ '%s attached a new file to the task %s' => '%s a %s feladathoz egy új fájlt kapcsolt hozzá',
+ 'Link type' => 'Hivatkozás típus',
+ 'Assign automatically a category based on a link' => 'A hivatkozás alapján kategória automatikus hozzárendelése',
+ 'BAM - Konvertible Mark' => 'BAM - Konvertibilis márka',
+ 'Assignee Username' => 'A felelős felhasználói neve',
+ 'Assignee Name' => 'A felelős neve',
+ 'Groups' => 'Csoportok',
+ 'Members of %s' => 'A %s tagjai',
+ 'New group' => 'Új csoport',
+ 'Group created successfully.' => 'A csoport sikeresen létrejött.',
+ 'Unable to create your group.' => 'Nem sikerült a csoport létrehozása.',
+ 'Edit group' => 'Csoport szerkesztése',
+ 'Group updated successfully.' => 'A csoport módosítása sikeresen megtörtént',
+ 'Unable to update your group.' => 'Nem sikerült a csoport módosítása',
+ 'Add group member to "%s"' => 'Csoport tag hozzáadáasa "%s"-hez',
+ 'Group member added successfully.' => 'Tag hozzáadás sikeresen megtörtént',
+ 'Unable to add group member.' => 'Nem sikerült a tagot hozzáadni a csoporthoz.',
+ 'Remove user from group "%s"' => 'Felhasználó eltávolítása a "%s" csoportból',
+ 'User removed successfully from this group.' => 'A felhasználó sikeresen el lett távolítva a csoportból.',
+ 'Unable to remove this user from the group.' => 'Nem sikerült a felhasználó eltávolítása a csoportból',
+ 'Remove group' => 'Csoport törlése',
+ 'Group removed successfully.' => 'A csoport törlése sikeresen megtörtént.',
+ 'Unable to remove this group.' => 'Nem sikerült a csoport törlése.',
+ 'Project Permissions' => 'Projekt engedélyek',
+ 'Manager' => 'Vezető',
+ 'Project Manager' => 'Projekt vezető',
+ 'Project Member' => 'Projekt tag',
+ 'Project Viewer' => 'Projekt megtekintés',
+ 'Your account is locked for %d minutes' => 'Az ön számlája %d percre zárolva lett.',
+ 'Invalid captcha' => 'Érvénytelen captcha',
+ 'The name must be unique' => 'A névnek egyedinek kell lennie',
+ 'View all groups' => 'Az összes csoport megtekintése',
+ 'View group members' => 'A csoporttagok megtekintése',
+ 'There is no user available.' => 'Nincs ilyen felhasználó.',
+ 'Do you really want to remove the user "%s" from the group "%s"?' => 'Valóban el kívánja távolítani a "%s" felhasználót a "%s" csoportból?',
+ 'There is no group.' => 'Nincs ilyen csoport.',
+ 'External Id' => 'Külső azonosító',
+ 'Add group member' => 'Csoporttag hozzáadása',
+ 'Do you really want to remove this group: "%s"?' => 'Valóban törölni kívánja ezt a csoportot: "%s"?',
+ 'There is no user in this group.' => 'Nincs egy felhasználó sem ebben a csoportban.',
+ 'Remove this user' => 'A felhasználó eltávolítása',
+ 'Permissions' => 'Engedélyek',
+ 'Allowed Users' => 'Megengedett felhasználók',
+ 'No user have been allowed specifically.' => 'Egyedileg semelyik felhasználó sem lett engedélyezve.',
+ 'Role' => 'Szerepkör',
+ 'Enter user name...' => 'Adja be a felhasználó nevét...',
+ 'Allowed Groups' => 'Megengedett csoportok',
+ 'No group have been allowed specifically.' => 'Egyedileg semelyik csoport sem lett engedélyezve.',
+ 'Group' => 'Csoport',
+ 'Group Name' => 'Csoport név',
+ 'Enter group name...' => 'Adja meg a csoport nevét...',
+ 'Role:' => 'Szerepkör:',
+ 'Project members' => 'Projekt tagok',
+ 'Compare hours for "%s"' => 'Az órák összehasonlítása "%s" számára',
+ '%s mentioned you in the task #%d' => '%s megemlítette önt a #%d feladatban',
+ '%s mentioned you in a comment on the task #%d' => '%s megemlítette önt a #%d feladathoz fűzött megjegyzésben',
+ 'You were mentioned in the task #%d' => 'Ön meg lett említve a #%d feladatban',
+ 'You were mentioned in a comment on the task #%d' => 'Ön meg lett említve a #%d feladathoz fűzött megjegyzésben',
+ 'Mentioned' => 'Meg lett említve',
+ 'Compare Estimated Time vs Actual Time' => 'A becsült és a tényleges idő összehasonlítása',
+ 'Estimated hours: ' => 'Becsült órák: ',
+ 'Actual hours: ' => 'Tényleges órák: ',
+ 'Hours Spent' => 'Ráfordítás órákban',
+ 'Hours Estimated' => 'Becsült idő órákban',
+ 'Estimated Time' => 'Becsült idő',
+ 'Actual Time' => 'Tényleges idő',
+ 'Estimated vs actual time' => 'Becsült idő ill. tényleges idő',
+ 'RUB - Russian Ruble' => 'RUB - Orosz rubel',
+ 'Assign the task to the person who does the action when the column is changed' => 'A feladat hozzárendelése ahhoz a személyhez, aki az oszlop megváltoztatásakor intézkedik',
+ 'Close a task in a specific column' => 'A megadott oszlopban lévő feladat lezárása',
+ 'Time-based One-time Password Algorithm' => 'Idő alapú, egyszer használható jelszó algoritmus',
+ 'Two-Factor Provider: ' => 'Két tényezős bejelentkezés szolgáltatója',
+ 'Disable two-factor authentication' => 'Két tényezős bejelentkezés tiltása',
+ 'Enable two-factor authentication' => 'Két tényezős bejelentkezés engedélyezése',
+ 'There is no integration registered at the moment.' => 'Jelenleg nincs regisztrált integráció.',
+ 'Password Reset for Kanboard' => 'Jelszó alaphelyzetbe állítása',
+ 'Forgot password?' => 'Elfelejtett jelszó?',
+ 'Enable "Forget Password"' => '"Elfelejtett jelszó" engedélyezése',
+ 'Password Reset' => 'Jelszó alaphelyzetbe állíása',
+ 'New password' => 'Új jelszó',
+ 'Change Password' => 'Jelszó megváltoztatása',
+ 'To reset your password click on this link:' => 'A jelszó megváltoztatásáshoz kattintson erre a hivatkozásra',
+ 'Last Password Reset' => 'Jelszó alaphelyzetbe állítás utoljára ekkor',
+ 'The password has never been reinitialized.' => 'A jelszó soha sem lett alaphelyzetbe állítva.',
+ 'Creation' => 'Létrehozás',
+ 'Expiration' => 'Lejárat',
+ 'Password reset history' => 'A jelszó alaphelyzetbe állítás története',
+ 'All tasks of the column "%s" and the swimlane "%s" have been closed successfully.' => 'A "%s" oszlophoz és a "%s" sávhoz tartozó összes feladat sikeresen le lett zárva.',
+ 'Do you really want to close all tasks of this column?' => 'Valóban le kívánja zárni az oszlophoz tartozó összes feladatot?',
+ '%d task(s) in the column "%s" and the swimlane "%s" will be closed.' => '%d feladat lesz lezárva, ezek a "%s" oszlopban és a "%s" sávban vannak.',
+ 'Close all tasks of this column' => 'Az oszlophoz tartozó összes feladat lezárása',
+ 'No plugin has registered a project notification method. You can still configure individual notifications in your user profile.' => 'Egy plugin sem regisztrált projekt értesítési módszert. Egyedi értesítések még mindig beállíthatók a felhasználói profilban.',
+ 'My dashboard' => 'Az én dashboard-om',
+ 'My profile' => 'Az én profilom',
+ 'Project owner: ' => 'A projekt tulajdonosa: ',
+ 'The project identifier is optional and must be alphanumeric, example: MYPROJECT.' => 'A projekt azonosító opcionális, és kötelezően alfanumerikus karakterekből áll, pl: MYPROJECT.',
+ 'Project owner' => 'Projekt tulajdonos',
+ 'Those dates are useful for the project Gantt chart.' => 'Ezek a dátumok a projekt Gantt diagramjához hasznosak.',
+ 'Private projects do not have users and groups management.' => 'A privát projektekhez nem tartozik felhasználó kezelés és csoport kezelés.',
+ 'There is no project member.' => 'A projektnek nincs tagja.',
+ 'Priority' => 'Prioritás',
+ 'Task priority' => 'Feladat prioritás',
+ 'General' => 'Általános',
+ 'Dates' => 'Dátumok',
+ 'Default priority' => 'Alap prioritás',
+ 'Lowest priority' => 'Legalacsonyabb prioritás',
+ 'Highest priority' => 'Legmagasabb prioritás',
+ 'If you put zero to the low and high priority, this feature will be disabled.' => 'Ha nullát ad meg a legalacsonyabb és legmagasabb prioritásként, akkor ez a jellemző letiltásra kerül.',
+ 'Close a task when there is no activity' => 'A feladat lezárása, ha nincs tevékenység',
+ 'Duration in days' => 'Hossz napokban',
+ 'Send email when there is no activity on a task' => 'email küldése, ha egy feladathoz nincs tevékenység',
+ 'Unable to fetch link information.' => 'A hivatkozás adatainak sikertelen beolvasása',
+ 'Daily background job for tasks' => 'A feladatokhoz tartozó napi háttér munkák',
+ 'Auto' => 'Automatikus',
+ 'Related' => 'Kapcsolódó',
+ 'Attachment' => 'Csatolmány',
+ 'Title not found' => 'Nincs ilyen cím',
+ 'Web Link' => 'Web hivatkozás',
+ 'External links' => 'Külső hivatkozások',
+ 'Add external link' => 'Külső hivatkozás hozzáadása',
+ 'Type' => 'Típus',
+ 'Dependency' => 'Függőség',
+ 'Add internal link' => 'Belső hivatkozás hozzáadása',
+ 'Add a new external link' => 'Új külső hivatkozás hozzáadása',
+ 'Edit external link' => 'Külső hivatkozás szerkesztése',
+ 'External link' => 'Külső hivatkozás',
+ 'Copy and paste your link here...' => 'Másold be a hivatkozást ide...',
+ 'URL' => 'URL',
+ 'Internal links' => 'Belső hivatkozások',
+ 'Assign to me' => 'Rendeld hozzám',
+ 'Me' => 'Hozzám',
+ 'Do not duplicate anything' => 'Semmit se duplázz meg',
+ 'Projects management' => 'Projekt kezelés',
+ 'Users management' => 'Felhasználók kezelése',
+ 'Groups management' => 'Csoportok kezelése',
+ 'Create from another project' => 'Létrehozás egy másik projektből',
+ 'open' => 'nyitva',
+ 'closed' => 'zárva',
+ 'Priority:' => 'Prioritás:',
+ 'Reference:' => 'Hivatkozás:',
+ 'Complexity:' => 'Komplexitás:',
+ 'Swimlane:' => 'Sáv:',
+ 'Column:' => 'Oszlop:',
+ 'Position:' => 'Pozíció:',
+ 'Creator:' => 'Létrehozó:',
+ 'Time estimated:' => 'Becsült idő:',
+ '%s hours' => '%s óra',
+ 'Time spent:' => 'Eltelt idő:',
+ 'Created:' => 'Létrehozva:',
+ 'Modified:' => 'Módosítva:',
+ 'Completed:' => 'Elkészült:',
+ 'Started:' => 'Elindult:',
+ 'Moved:' => 'Elmozgatva:',
+ 'Task #%d' => '#%d. feladat',
+ 'Date and time format' => 'Dátum és idő formátum',
+ 'Time format' => 'Idő formátum',
+ 'Start date: ' => 'Kezdő datum: ',
+ 'End date: ' => 'Vég dátum: ',
+ 'New due date: ' => 'Új határidő: ',
+ 'Start date changed: ' => 'Kezdő dátum megváltozott: ',
+ 'Disable private projects' => 'Privát projektek tiltása',
+ 'Do you really want to remove this custom filter: "%s"?' => 'Valóban el kívánja távolítani ezt az egyedi szűrőt: "%s"?',
+ 'Remove a custom filter' => 'Egyedi szűrő eltávolítása',
+ 'User activated successfully.' => 'A felhasználó sikeresen aktiválva lett.',
+ 'Unable to enable this user.' => 'Nem sikerült a felhasználó engedélyezése.',
+ 'User disabled successfully.' => 'A felhaszáló sikeresen le lett tiltva.',
+ 'Unable to disable this user.' => 'Nem sikerült a felhasználó letiltása.',
+ 'All files have been uploaded successfully.' => 'Az összes fájl sikeresen feltöltődött.',
+ 'View uploaded files' => 'A feltöltött fájlok megtekintése',
+ 'The maximum allowed file size is %sB.' => 'A fájl max. megengedett mérete %s bájt',
+ 'Choose files again' => 'Válasszon újból fájlt',
+ 'Drag and drop your files here' => 'Fogdd-és-vidd módszerrel dobja ide a fájlt',
+ 'choose files' => 'válasszon fájlt',
+ 'View profile' => 'Profil megtekintés',
+ 'Two Factor' => 'Két tényezős',
+ 'Disable user' => 'Felhasználó tiltása',
+ 'Do you really want to disable this user: "%s"?' => 'Valóban le akarja tiltani ezt a felhasználót: "%s"?',
+ 'Enable user' => 'Felhasználó engedélyezése',
+ 'Do you really want to enable this user: "%s"?' => 'Valóban engedélyezni akarja ezt a felhasználót: "%s"?',
+ 'Download' => 'Letöltés',
+ 'Uploaded: %s' => 'Feltöltve: %s',
+ 'Size: %s' => 'méret %s',
+ 'Uploaded by %s' => 'Feltöltve %s által',
+ 'Filename' => 'Fájlnév',
+ 'Size' => 'Méret',
+ 'Column created successfully.' => 'Az oszlop sikeresen létrejött',
+ 'Another column with the same name exists in the project' => 'A projektben már létezik egy ugyanilyen nevű oszlop',
+ 'Default filters' => 'Alap szűrők',
+ 'Your board doesn\'t have any column!' => 'A táblának nincsenek oszlopai!',
+ 'Change column position' => 'Oszlop helyzetének megváltoztatása',
+ 'Switch to the project overview' => 'Projektek áttekintése',
+ 'User filters' => 'Felhasználók szűrése',
+ 'Category filters' => 'Kategóriák szűrése',
+ 'Upload a file' => 'Fájl feltöltése',
+ 'View file' => 'Fájl megtekintése',
+ 'Last activity' => 'Utolsó aktivitás',
+ 'Change subtask position' => 'Részfeladat helyzetének megváltoztatása',
+ 'This value must be greater than %d' => 'Ennek az értéknek nagyobbnak kell lennie, mint %d',
+ 'Another swimlane with the same name exists in the project' => 'A projektben létezik egy ugyanilyen nevű másik sáv',
+ 'Example: http://example.kanboard.net/ (used to generate absolute URLs)' => 'Példa: http://example.kanboard.net/ (ez abszolút URL-ek előállítására használható)',
+ 'Actions duplicated successfully.' => 'A tevékenység sikeresen meg lett duplázva.',
+ 'Unable to duplicate actions.' => 'A tevékenység megduplázása nem sikerült.',
+ 'Add a new action' => 'Új tevékenység létrehozása',
+ 'Import from another project' => 'Importálás egy másik projektből',
+ 'There is no action at the moment.' => 'Jelenleg nincs egy tevkenység sem.',
+ 'Import actions from another project' => 'Tevékenységek importálása egy másik projektből',
+ 'There is no available project.' => 'Nincs rendelkezésre álló projekt.',
+ 'Local File' => 'Helyi fájl',
+ 'Configuration' => 'Konfiguráció',
+ 'PHP version:' => 'PHP verzió:',
+ 'PHP SAPI:' => 'PHP SAPI:',
+ 'OS version:' => 'Operációs rendszer verzió:',
+ 'Database version:' => 'Adatbázis verzió:',
+ 'Browser:' => 'Böngésző:',
+ 'Task view' => 'Feladat nézet',
+ 'Edit task' => 'Feladat szerkesztése',
+ 'Edit description' => 'Leírás szerkesztése',
+ 'New internal link' => 'Új belső hivatkozás',
+ 'Display list of keyboard shortcuts' => 'Billentyű parancsok megjelenítése',
+ 'Menu' => 'Menü',
+ 'Set start date' => 'Kezdő időpont beállítása',
+ 'Avatar' => 'Avatár',
+ 'Upload my avatar image' => 'Kép feltöltése',
+ 'Remove my image' => 'Kép törése',
+ 'The OAuth2 state parameter is invalid' => 'Az OAuth2 állapot paraméter érvénytelen',
+ 'User not found.' => 'Nincs ilyen felhasználó.',
+ 'Search in activity stream' => 'Keresés a tevékenységek között',
+ 'My activities' => 'Tevékenységeim',
+ 'Activity until yesterday' => 'Tevékenységek tegnapig',
+ 'Activity until today' => 'Tevékenységek a mai napig',
+ 'Search by creator: ' => 'Keresés a létrehozó szerint: ',
+ 'Search by creation date: ' => 'Keresés a létrehozás ideje szerint: ',
+ 'Search by task status: ' => 'Keresés a feladat állapota szerint: ',
+ 'Search by task title: ' => 'Keresés a feladat címe szerint: ',
+ 'Activity stream search' => 'Tevékenységi láncban történő keresés',
+ 'Projects where "%s" is manager' => 'Azok a projektek, amelyekben "%s" vezető',
+ 'Projects where "%s" is member' => 'Azok a projektek, amelyekben "%s" tag',
+ 'Open tasks assigned to "%s"' => '"%s" -hez rendelt nyitott feladatok',
+ 'Closed tasks assigned to "%s"' => '"%s" -hez rendelt lezárt feladatok',
+ 'Assign automatically a color based on a priority' => 'A prioritás alapján szín automatikus hozzárendelése',
+ 'Overdue tasks for the project(s) "%s"' => 'A "%s" projekt(ek)hez tartozó, határidőt túllépő feladatok',
+ 'Upload files' => 'Fájlok feltöltése',
+ 'Installed Plugins' => 'Installált plugin-ek',
+ 'Plugin Directory' => 'Plugin könyvtár',
+ 'Plugin installed successfully.' => 'A plugin installálása sikerült.',
+ 'Plugin updated successfully.' => 'A plugin módosítása sikerült.',
+ 'Plugin removed successfully.' => 'A plugin törlése sikerült.',
+ 'Subtask converted to task successfully.' => 'Az alfeladat feladattá történő átalakítása sikerült.',
+ 'Unable to convert the subtask.' => 'Az alfeladat átalakítása nem sikerült.',
+ 'Unable to extract plugin archive.' => 'A plugin archívum kibontása nem sikerült.',
+ 'Plugin not found.' => 'A plugin nem található.',
+ 'You don\'t have the permission to remove this plugin.' => 'Nincs joga ennek a plugin-nek az eltávolításához.',
+ 'Unable to download plugin archive.' => 'A plugin archívum letöltése nem sikerült.',
+ 'Unable to write temporary file for plugin.' => 'A plugin-hez nem sikerült egy átmeneti fájl létrehozása.',
+ 'Unable to open plugin archive.' => 'Nem sikerült a plugin archívum megnyitása.',
+ 'There is no file in the plugin archive.' => 'A plugin archívumban nincs egyetelen egy fájl sem.',
+ 'Create tasks in bulk' => 'Feladatok tömeges létrehozása',
+ 'Your Kanboard instance is not configured to install plugins from the user interface.' => 'Az Ön Kanboard példánya úgy lett konfigurálva, hogy ne lehessen plugin-eket installálni a felhasználói felületről.',
+ 'There is no plugin available.' => 'Nem áll plugin rendelkezésre.',
+ 'Install' => 'Installálás',
+ 'Update' => 'Módosítás',
+ 'Up to date' => 'Naprakész',
+ 'Not available' => 'Nem áll rendelkezésre',
+ 'Remove plugin' => 'Plugin eltávolítása',
+ 'Do you really want to remove this plugin: "%s"?' => 'Valóban el kívánja távolítani ezt a plugin-t: "%s"?',
+ //'Uninstall' => '',
+ 'Listing' => 'Listázás',
+ 'Metadata' => 'Metaadat',
+ 'Manage projects' => 'Projektek kezelése',
+ 'Convert to task' => 'Feladattá történő átalakítás',
+ 'Convert sub-task to task' => 'Alfeladat feladattá történő átalakítása',
+ 'Do you really want to convert this sub-task to a task?' => 'Valóban feladattá akarja átalakítani ezt az alfeladatot?',
+ 'My task title' => 'A feladat címe',
+ 'Enter one task by line.' => 'Minden sorban egy feladatot adjon meg.',
+ 'Number of failed login:' => 'A sikertelen bejelentkezések száma:',
+ 'Account locked until:' => 'A számla zárolva a következő időpontig:',
);
diff --git a/app/Locale/id_ID/translations.php b/app/Locale/id_ID/translations.php
index 59fd75d4..050a0997 100644
--- a/app/Locale/id_ID/translations.php
+++ b/app/Locale/id_ID/translations.php
@@ -170,7 +170,6 @@ return array(
'Leave a description' => 'Tinggalkan deskripsi',
'Comment added successfully.' => 'Komentar berhasil ditambahkan.',
'Unable to create your comment.' => 'Tidak dapat menambahkan komentar anda.',
- 'Edit this task' => 'Modifikasi tugas ini',
'Due Date' => 'Batas Tanggal Terakhir',
'Invalid date' => 'Tanggal tidak valid',
'Automatic actions' => 'Tindakan otomatis',
@@ -517,7 +516,6 @@ return array(
'All swimlanes' => 'Semua swimlane',
'All colors' => 'Semua warna',
'Moved to column %s' => 'Pindah ke kolom %s',
- 'Change description' => 'Rubah deskripsi',
'User dashboard' => 'Dasbor pengguna',
'Allow only one subtask in progress at the same time for a user' => 'Izinkan hanya satu subtugas dalam proses secara bersamaan untuk satu pengguna',
'Edit column "%s"' => 'Modifikasi kolom « %s »',
@@ -709,7 +707,6 @@ return array(
'view the board on Kanboard' => 'lihat papan di Kanboard',
'The task have been moved to the first swimlane' => 'Tugas telah dipindahkan ke swimlane pertama',
'The task have been moved to another swimlane:' => 'Tugas telah dipindahkan ke swimlane lain:',
- // 'Overdue tasks for the project(s) "%s"' => 'Tugas terlambat untuk proyek « %s »',
'New title: %s' => 'Judul baru : %s',
'The task is not assigned anymore' => 'Tugas tidak ditugaskan lagi',
'New assignee: %s' => 'Penerima baru : %s',
@@ -738,7 +735,6 @@ return array(
'Stop timer' => 'Hentikan timer',
'Start timer' => 'Mulai timer',
'Add project member' => 'Tambahkan anggota proyek',
- 'Enable notifications' => 'Aktifkan pemberitahuan',
'My activity stream' => 'Aliran kegiatan saya',
'My calendar' => 'Kalender saya',
'Search tasks' => 'Cari tugas',
@@ -1167,4 +1163,41 @@ return array(
// 'Projects where "%s" is member' => '',
// 'Open tasks assigned to "%s"' => '',
// 'Closed tasks assigned to "%s"' => '',
+ // 'Assign automatically a color based on a priority' => '',
+ // 'Overdue tasks for the project(s) "%s"' => '',
+ // 'Upload files' => '',
+ // 'Installed Plugins' => '',
+ // 'Plugin Directory' => '',
+ // 'Plugin installed successfully.' => '',
+ // 'Plugin updated successfully.' => '',
+ // 'Plugin removed successfully.' => '',
+ // 'Subtask converted to task successfully.' => '',
+ // 'Unable to convert the subtask.' => '',
+ // 'Unable to extract plugin archive.' => '',
+ // 'Plugin not found.' => '',
+ // 'You don\'t have the permission to remove this plugin.' => '',
+ // 'Unable to download plugin archive.' => '',
+ // 'Unable to write temporary file for plugin.' => '',
+ // 'Unable to open plugin archive.' => '',
+ // 'There is no file in the plugin archive.' => '',
+ // 'Create tasks in bulk' => '',
+ // 'Your Kanboard instance is not configured to install plugins from the user interface.' => '',
+ // 'There is no plugin available.' => '',
+ // 'Install' => '',
+ // 'Update' => '',
+ // 'Up to date' => '',
+ // 'Not available' => '',
+ // 'Remove plugin' => '',
+ // 'Do you really want to remove this plugin: "%s"?' => '',
+ // 'Uninstall' => '',
+ // 'Listing' => '',
+ // 'Metadata' => '',
+ // 'Manage projects' => '',
+ // 'Convert to task' => '',
+ // 'Convert sub-task to task' => '',
+ // 'Do you really want to convert this sub-task to a task?' => '',
+ // 'My task title' => '',
+ // 'Enter one task by line.' => '',
+ // 'Number of failed login:' => '',
+ // 'Account locked until:' => '',
);
diff --git a/app/Locale/it_IT/translations.php b/app/Locale/it_IT/translations.php
index bd85b6c2..fa1c6e6f 100644
--- a/app/Locale/it_IT/translations.php
+++ b/app/Locale/it_IT/translations.php
@@ -170,7 +170,6 @@ return array(
'Leave a description' => 'Lascia una descrizione',
'Comment added successfully.' => 'Commenti aggiunti con successo.',
'Unable to create your comment.' => 'Impossibile creare questo commento.',
- 'Edit this task' => 'Modifica questo task',
'Due Date' => 'Data di scadenza',
'Invalid date' => 'Data non valida',
'Automatic actions' => 'Azioni automatiche',
@@ -517,7 +516,6 @@ return array(
'All swimlanes' => 'Tutte le corsie',
'All colors' => 'Tutti i colori',
'Moved to column %s' => 'Spostato sulla colonna "%s"',
- 'Change description' => 'Cambia descrizione',
'User dashboard' => 'Bacheca utente',
'Allow only one subtask in progress at the same time for a user' => 'Permetti un solo sotto-task in corso per utente alla volta',
'Edit column "%s"' => 'Modifica la colonna "%s"',
@@ -709,7 +707,6 @@ return array(
'view the board on Kanboard' => 'guarda la bacheca su Kanboard',
'The task have been moved to the first swimlane' => 'Il task è stato spostato nella prima corsia',
'The task have been moved to another swimlane:' => 'Il task è stato spostato in un\'altra corsia:',
- // 'Overdue tasks for the project(s) "%s"' => 'Task scaduti per il progetto "%s"',
'New title: %s' => 'Nuovo titolo: %s',
'The task is not assigned anymore' => 'Il task non è più assegnato a nessuno',
'New assignee: %s' => 'Nuovo assegnatario: %s',
@@ -738,7 +735,6 @@ return array(
'Stop timer' => 'Ferma il timer',
'Start timer' => 'Avvia il timer',
'Add project member' => 'Aggiungi un membro di progetto',
- 'Enable notifications' => 'Abilita notifiche',
'My activity stream' => 'Il mio flusso attività',
'My calendar' => 'Il mio calendario',
'Search tasks' => 'Ricerca task',
@@ -1167,4 +1163,41 @@ return array(
'Projects where "%s" is member' => 'Progetti all\'interno dei quali "%s" è membro',
'Open tasks assigned to "%s"' => 'Task aperti assegnati a "%s"',
'Closed tasks assigned to "%s"' => 'Task chiusi assegnati a "%s"',
+ // 'Assign automatically a color based on a priority' => '',
+ // 'Overdue tasks for the project(s) "%s"' => '',
+ // 'Upload files' => '',
+ // 'Installed Plugins' => '',
+ // 'Plugin Directory' => '',
+ // 'Plugin installed successfully.' => '',
+ // 'Plugin updated successfully.' => '',
+ // 'Plugin removed successfully.' => '',
+ // 'Subtask converted to task successfully.' => '',
+ // 'Unable to convert the subtask.' => '',
+ // 'Unable to extract plugin archive.' => '',
+ // 'Plugin not found.' => '',
+ // 'You don\'t have the permission to remove this plugin.' => '',
+ // 'Unable to download plugin archive.' => '',
+ // 'Unable to write temporary file for plugin.' => '',
+ // 'Unable to open plugin archive.' => '',
+ // 'There is no file in the plugin archive.' => '',
+ // 'Create tasks in bulk' => '',
+ // 'Your Kanboard instance is not configured to install plugins from the user interface.' => '',
+ // 'There is no plugin available.' => '',
+ // 'Install' => '',
+ // 'Update' => '',
+ // 'Up to date' => '',
+ // 'Not available' => '',
+ // 'Remove plugin' => '',
+ // 'Do you really want to remove this plugin: "%s"?' => '',
+ // 'Uninstall' => '',
+ // 'Listing' => '',
+ // 'Metadata' => '',
+ // 'Manage projects' => '',
+ // 'Convert to task' => '',
+ // 'Convert sub-task to task' => '',
+ // 'Do you really want to convert this sub-task to a task?' => '',
+ // 'My task title' => '',
+ // 'Enter one task by line.' => '',
+ // 'Number of failed login:' => '',
+ // 'Account locked until:' => '',
);
diff --git a/app/Locale/ja_JP/translations.php b/app/Locale/ja_JP/translations.php
index e3cf662c..3c8fa4c1 100644
--- a/app/Locale/ja_JP/translations.php
+++ b/app/Locale/ja_JP/translations.php
@@ -170,7 +170,6 @@ return array(
'Leave a description' => '説明を書く',
'Comment added successfully.' => 'コメントを追加しました。',
'Unable to create your comment.' => 'コメントの追加に失敗しました。',
- 'Edit this task' => 'タスクを変更する',
'Due Date' => '期限',
'Invalid date' => '日付が無効です',
'Automatic actions' => '自動アクションを管理する',
@@ -517,7 +516,6 @@ return array(
'All swimlanes' => '全てのスイムレーン',
'All colors' => '全ての色',
'Moved to column %s' => 'カラム %s へ移動しました',
- 'Change description' => '説明を変更',
'User dashboard' => 'ユーザダッシュボード',
'Allow only one subtask in progress at the same time for a user' => '一人のユーザにつき一つのタスクのみ進行中にできます',
'Edit column "%s"' => 'カラム「%s」の編集',
@@ -709,7 +707,6 @@ return array(
// 'view the board on Kanboard' => '',
// 'The task have been moved to the first swimlane' => '',
// 'The task have been moved to another swimlane:' => '',
- // 'Overdue tasks for the project(s) "%s"' => '',
// 'New title: %s' => '',
// 'The task is not assigned anymore' => '',
// 'New assignee: %s' => '',
@@ -738,7 +735,6 @@ return array(
// 'Stop timer' => '',
// 'Start timer' => '',
// 'Add project member' => '',
- // 'Enable notifications' => '',
// 'My activity stream' => '',
// 'My calendar' => '',
// 'Search tasks' => '',
@@ -1167,4 +1163,41 @@ return array(
// 'Projects where "%s" is member' => '',
// 'Open tasks assigned to "%s"' => '',
// 'Closed tasks assigned to "%s"' => '',
+ // 'Assign automatically a color based on a priority' => '',
+ // 'Overdue tasks for the project(s) "%s"' => '',
+ // 'Upload files' => '',
+ // 'Installed Plugins' => '',
+ // 'Plugin Directory' => '',
+ // 'Plugin installed successfully.' => '',
+ // 'Plugin updated successfully.' => '',
+ // 'Plugin removed successfully.' => '',
+ // 'Subtask converted to task successfully.' => '',
+ // 'Unable to convert the subtask.' => '',
+ // 'Unable to extract plugin archive.' => '',
+ // 'Plugin not found.' => '',
+ // 'You don\'t have the permission to remove this plugin.' => '',
+ // 'Unable to download plugin archive.' => '',
+ // 'Unable to write temporary file for plugin.' => '',
+ // 'Unable to open plugin archive.' => '',
+ // 'There is no file in the plugin archive.' => '',
+ // 'Create tasks in bulk' => '',
+ // 'Your Kanboard instance is not configured to install plugins from the user interface.' => '',
+ // 'There is no plugin available.' => '',
+ // 'Install' => '',
+ // 'Update' => '',
+ // 'Up to date' => '',
+ // 'Not available' => '',
+ // 'Remove plugin' => '',
+ // 'Do you really want to remove this plugin: "%s"?' => '',
+ // 'Uninstall' => '',
+ // 'Listing' => '',
+ // 'Metadata' => '',
+ // 'Manage projects' => '',
+ // 'Convert to task' => '',
+ // 'Convert sub-task to task' => '',
+ // 'Do you really want to convert this sub-task to a task?' => '',
+ // 'My task title' => '',
+ // 'Enter one task by line.' => '',
+ // 'Number of failed login:' => '',
+ // 'Account locked until:' => '',
);
diff --git a/app/Locale/ko_KR/translations.php b/app/Locale/ko_KR/translations.php
index 0cd0d93c..5c11ff34 100644
--- a/app/Locale/ko_KR/translations.php
+++ b/app/Locale/ko_KR/translations.php
@@ -20,14 +20,14 @@ return array(
'Orange' => '주황',
'Grey' => '회색',
'Brown' => '브라운',
- // 'Deep Orange' => '',
- // 'Dark Grey' => '',
- // 'Pink' => '',
- // 'Teal' => '',
- // 'Cyan' => '',
- // 'Lime' => '',
- // 'Light Green' => '',
- // 'Amber' => '',
+ 'Deep Orange' => '진홍',
+ 'Dark Grey' => '암회',
+ 'Pink' => '핑크',
+ 'Teal' => '암녹',
+ 'Cyan' => '청녹',
+ 'Lime' => '라임',
+ 'Light Green' => '연회',
+ 'Amber' => '호박',
'Save' => '저장',
'Login' => '로그인',
'Official website:' => '공식 웹사이트:',
@@ -66,9 +66,9 @@ return array(
'Disable' => '비활성화',
'Enable' => '유효하게 한다',
'New project' => '새 프로젝트',
- // 'Do you really want to remove this project: "%s"?' => '',
+ 'Do you really want to remove this project: "%s"?' => '프로젝트를 삭제하시겠습니까: "%s"?',
'Remove project' => '프로젝트의 삭제',
- // 'Edit the board for "%s"' => '',
+ 'Edit the board for "%s"' => '"%s"를 위한 보드 수정',
'All projects' => '모든 프로젝트',
'Add a new column' => '칼럼의 추가',
'Title' => '제목',
@@ -76,7 +76,7 @@ return array(
'Remove a column' => '칼럼 삭제',
'Remove a column from a board' => '보드에서 칼럼 삭제',
'Unable to remove this column.' => '(※)컬럼을 삭제할 수 없었습니다.',
- // 'Do you really want to remove this column: "%s"?' => '',
+ 'Do you really want to remove this column: "%s"?' => '칼럼을 삭제하시겠습니까: "%s"?',
'This action will REMOVE ALL TASKS associated to this column!' => '이 조작은 이 컬럼에 할당된 『 모든 할일을 삭제 』합니다!',
'Settings' => '설정',
'Application settings' => '애플리케이션의 설정',
@@ -96,7 +96,7 @@ return array(
'Create another task' => '다른 할일 추가',
'New task' => '새로운 할일',
'Open a task' => '할일 열기',
- // 'Do you really want to open this task: "%s"?' => '',
+ 'Do you really want to open this task: "%s"?' => '할일은 시작 하시겠습니까: "%s"?',
'Back to the board' => '보드로 돌아가기',
'There is nobody assigned' => '담당자가 없습니다',
'Column on the board:' => '칼럼:',
@@ -105,8 +105,8 @@ return array(
'There is no description.' => '설명이 없다',
'Add a new task' => '할일을 추가하는 ',
'The username is required' => '사용자 이름이 필요합니다',
- // 'The maximum length is %d characters' => '',
- // 'The minimum length is %d characters' => '',
+ 'The maximum length is %d characters' => '최대 길이는 "%d" 글자 입니다',
+ 'The minimum length is %d characters' => '최소 길이는 "%d" 글자 입니다',
'The password is required' => '패스워드가 필요합니다',
'This value must be an integer' => '정수로 입력하세요',
'The username must be unique' => '사용자 이름이 이미 사용되고 있습니다',
@@ -170,7 +170,6 @@ return array(
'Leave a description' => '설명을 입력하세요',
'Comment added successfully.' => '의견을 추가했습니다.',
'Unable to create your comment.' => '댓글의 추가에 실패했습니다.',
- 'Edit this task' => '할일 수정',
'Due Date' => '마감일',
'Invalid date' => '날짜가 무효입니다',
'Automatic actions' => '자동액션 관리',
@@ -179,7 +178,7 @@ return array(
'Remove an action' => '자동 액션의 삭제',
'Unable to remove this action.' => '자동 액션의 삭제에 실패했습니다.',
'Action removed successfully.' => '자동 액션의 삭제에 성공했어요.',
- // 'Automatic actions for the project "%s"' => '',
+ 'Automatic actions for the project "%s"' => '"%s" 프로젝트를 위한 자동 액션',
'Add an action' => '자동 액션 추가',
'Event name' => '이벤트 이름',
'Action name' => '액션 이름',
@@ -189,7 +188,7 @@ return array(
'When the selected event occurs execute the corresponding action.' => '선택된 이벤트가 발생했을 때 대응하는 액션을 실행한다.',
'Next step' => '다음 단계',
'Define action parameters' => '액션의 바로미터',
- // 'Do you really want to remove this action: "%s"?' => '',
+ 'Do you really want to remove this action: "%s"?' => '액션을 삭제하시겠습니까: "%s"?',
'Remove an automatic action' => '자동 액션의 삭제',
'Assign the task to a specific user' => '할일 담당자를 할당',
'Assign the task to the person who does the action' => '액션을 일으킨 사용자를 담당자이자',
@@ -235,15 +234,15 @@ return array(
'%d comments' => '%d개의 댓글',
'%d comment' => '%d개의 댓글',
'Email address invalid' => '메일 주소가 올바르지 않습니다.',
- // 'Your external account is not linked anymore to your profile.' => '',
- // 'Unable to unlink your external account.' => '',
- // 'External authentication failed' => '',
- // 'Your external account is linked to your profile successfully.' => '',
+ 'Your external account is not linked anymore to your profile.' => '외부 계정과 프로필이 더이상 연결되지 않습니다',
+ 'Unable to unlink your external account.' => '외부 계정과 연결 해제에 실패하였습니다',
+ 'External authentication failed' => '외부 인증 실패',
+ 'Your external account is linked to your profile successfully.' => '외부 계정과 프로필이 성공적으로 연결되었습니다',
'Email' => '이메일',
'Task removed successfully.' => '할일을 삭제했습니다.',
- 'Unable to remove this task.' => '할일 삭제에 실패했습니다.',
+ 'Unable to remove this task.' => '할일 삭제에 실패하였습니다',
'Remove a task' => '할일 삭제',
- // 'Do you really want to remove this task: "%s"?' => '',
+ 'Do you really want to remove this task: "%s"?' => '할일을 삭제하시겠습니까: "%s"?',
'Assign automatically a color based on a category' => '카테고리에 바탕을 두고 색을 바꾸고',
'Assign automatically a category based on a color' => '색에 바탕을 두고 카테고리를 바꾸었다',
'Task creation or modification' => '할일의 작성 또는 변경',
@@ -258,10 +257,10 @@ return array(
'Remove a category' => '카테고리의 삭제',
'Category removed successfully.' => '카테고리를 삭제했습니다.',
'Unable to remove this category.' => '카테고리를 삭제할 수 없었습니다.',
- // 'Category modification for the project "%s"' => '',
+ 'Category modification for the project "%s"' => '"%s" 프로젝트 카테고리 수정',
'Category Name' => '카테고리 이름',
'Add a new category' => '카테고리의 추가',
- // 'Do you really want to remove this category: "%s"?' => '',
+ 'Do you really want to remove this category: "%s"?' => '카테고리를 삭제하시겠습니까: "%s"?',
'All categories' => '모든 카테고리',
'No category' => '카테고리 없음',
'The name is required' => '이름을 입력하십시오',
@@ -305,7 +304,7 @@ return array(
'Display another project' => '프로젝트 보기',
'Created by %s' => '작성자 %s',
'Tasks Export' => '할일 내보내기',
- // 'Tasks exportation for "%s"' => '',
+ 'Tasks exportation for "%s"' => '"%s" 할일 내보내기',
'Start Date' => '시작일',
'End Date' => '종료일',
'Execute' => '실행',
@@ -318,15 +317,15 @@ return array(
'Unable to clone this project.' => '프로젝트의 복제에 실패했습니다.',
'Enable email notifications' => '이메일 알림 설정',
'Task position:' => '할일 위치:',
- // 'The task #%d have been opened.' => '',
- // 'The task #%d have been closed.' => '',
+ 'The task #%d have been opened.' => '할일 #%d가 시작되었습니다',
+ 'The task #%d have been closed.' => '할일 #%d가 종료되었습니다',
'Sub-task updated' => '서브 할일 갱신',
'Title:' => '제목:',
'Status:' => '상태:',
'Assignee:' => '담당:',
'Time tracking:' => '시간 계측:',
'New sub-task' => '새로운 서브 할일',
- // 'New attachment added "%s"' => '',
+ 'New attachment added "%s"' => '"%s"의 새로운 첨부 파일',
'New comment posted by %s' => '"%s"님이 댓글을 추가하였습니다',
'New attachment' => ' 새로운 첨부 파일',
'New comment' => ' 새로운 댓글',
@@ -343,8 +342,8 @@ return array(
'Disable public access' => '공개 접속 비활성화',
'Enable public access' => '공개 접속 활성화',
'Public access disabled' => '공개 접속 불가',
- // 'Do you really want to disable this project: "%s"?' => '',
- // 'Do you really want to enable this project: "%s"?' => '',
+ 'Do you really want to disable this project: "%s"?' => '프로젝트를 비활성화하시겠습니까: "%s"?',
+ 'Do you really want to enable this project: "%s"?' => '프로젝트를 활성화하시겠습니까: "%s"?',
'Project activation' => '프로젝트의 액티베ー션',
'Move the task to another project' => '할일별 프로젝트에 옮기',
'Move to another project' => '다른 프로젝트로 이동',
@@ -373,34 +372,34 @@ return array(
'Change category for the task "%s"' => '할일 "%s"의 카테고리의 변경',
'Change category' => '카테고리 수정',
'%s updated the task %s' => '%s이 할일 %s을 업데이트했습니다',
- // '%s opened the task %s' => '',
+ '%s opened the task %s' => '%s이 할일 %s을 시작시켰습니다',
'%s moved the task %s to the position #%d in the column "%s"' => '%s이 할일%s을 위치#%d컬럼%s로 옮겼습니다',
'%s moved the task %s to the column "%s"' => '%s이 할일 %s을 칼럼 "%s" 로 옮겼습니다',
'%s created the task %s' => '%s이 할일%s을 추가했습니다',
'%s closed the task %s' => '%s이 할일%s을 마쳤습니다',
'%s created a subtask for the task %s' => '%s이 할일%s의 서브 할일을 추가했습니다',
'%s updated a subtask for the task %s' => '%s이 할일%s의 서브 할일을 갱신했습니다',
- 'Assigned to %s with an estimate of %s/%sh' => '담당자 %s에게 예상 %s/%sh로 할당되었습니다',
- // 'Not assigned, estimate of %sh' => '',
+ 'Assigned to %s with an estimate of %s/%sh' => '담당자 %s에게 예상 %s/%sh을 할당했습니다',
+ 'Not assigned, estimate of %sh' => '예상 %sh가 할당되지 않았습니다',
'%s updated a comment on the task %s' => '%s이 할일%s의 댓글을 수정했습니다',
'%s commented the task %s' => '%s이 할일%s에 댓글을 남겼습니다',
'%s\'s activity' => '%s의 활동',
'RSS feed' => 'RSS피드',
- // '%s updated a comment on the task #%d' => '',
- // '%s commented on the task #%d' => '',
- // '%s updated a subtask for the task #%d' => '',
- // '%s created a subtask for the task #%d' => '',
+ '%s updated a comment on the task #%d' => '%s이 할일#%d의 댓글을 수정했습니다',
+ '%s commented on the task #%d' => '%s이 할일#%d을 언급하였습니다',
+ '%s updated a subtask for the task #%d' => '%s이 할일#%d의 서브 할일을 수정했습니다',
+ '%s created a subtask for the task #%d' => '%s이 할일#%d의 서브 할일을 수정했습니다',
'%s updated the task #%d' => '%s이 할일#%d을 갱신했습니다',
'%s created the task #%d' => '%s이 할일#%d을 추가했습니다',
'%s closed the task #%d' => '%s이 할일#%d을 닫혔습니다',
'%s open the task #%d' => '%s이 할일#%d를 오픈했습니다',
'%s moved the task #%d to the column "%s"' => '%s이 할일#%d을 칼럼"%s"로 옮겼습니다',
- // '%s moved the task #%d to the position %d in the column "%s"' => '',
+ '%s moved the task #%d to the position %d in the column "%s"' => '%s이 할일#%d을 칼럼 "%s"의 %d 위치로 이동시켰습니다',
'Activity' => '활동',
- // 'Default values are "%s"' => '',
- // 'Default columns for new projects (Comma-separated)' => '',
+ 'Default values are "%s"' => '기본 값은 "%s" 입니다',
+ 'Default columns for new projects (Comma-separated)' => '새로운 프로젝트의 기본 칼럼 (콤마(,)로 분리됨)',
'Task assignee change' => '담당자의 변경',
- // '%s change the assignee of the task #%d to %s' => '',
+ '%s change the assignee of the task #%d to %s' => '%s이 할일 #%d의 담당을 %s로 변경합니다',
'%s changed the assignee of the task %s to %s' => '%s이 할일 %s의 담당을 %s로 변경했습니다',
'New password for the user "%s"' => '사용자 "%s"의 새로운 패스워드',
'Choose an event' => '행사의 선택',
@@ -426,8 +425,8 @@ return array(
// 'Frequency in second (0 to disable this feature, 10 seconds by default)' => '',
'Application URL' => '애플리케이션의 URL',
'Token regenerated.' => '토큰이 다시 생성되었습니다.',
- 'Date format' => '데이터 포맷',
- // 'ISO format is always accepted, example: "%s" and "%s"' => '',
+ 'Date format' => '데이터 포멧',
+ 'ISO format is always accepted, example: "%s" and "%s"' => 'ISO 포멧은 항상 가능합니다. 예를 들어: "%s" 와 "%s"',
'New private project' => '새 비공개 프로젝트',
'This project is private' => '이 프로젝트는 비공개입니다',
'Add' => '추가',
@@ -452,12 +451,12 @@ return array(
'Number of tasks' => '할일 수',
'Task distribution' => '할일 분포',
'Reportings' => '리포트',
- // 'Task repartition for "%s"' => '',
+ 'Task repartition for "%s"' => '"%s"의 할일 분포',
'Analytics' => '분석',
'Subtask' => '서브 할일',
'My subtasks' => '내 서브 할일',
'User repartition' => '담당자 분포',
- // 'User repartition for "%s"' => '',
+ 'User repartition for "%s"' => '"%s"의 담당자 분포',
'Clone this project' => '이 프로젝트를 복제하는 ',
'Column removed successfully.' => '(※)컬럼을 삭제했습니다',
'Not enough data to show the graph.' => '그래프를 선묘화하려면 나왔지만 부족합니다',
@@ -473,22 +472,22 @@ return array(
'This value is required' => '이 값이 필요합니다',
'This value must be numeric' => '이 값은 숫자가 아니면 안 됩니다',
'Unable to create this task.' => '이 할일을 작성할 수 없었습니다',
- 'Cumulative flow diagram' => '축적 플로',
- // 'Cumulative flow diagram for "%s"' => '',
- 'Daily project summary' => '일시 프로젝트 개요',
- 'Daily project summary export' => '일시 프로젝트 개요의 출력',
- // 'Daily project summary export for "%s"' => '',
+ 'Cumulative flow diagram' => '축적 흐름',
+ 'Cumulative flow diagram for "%s"' => '"%s"의 축적 흐름',
+ 'Daily project summary' => '하루 프로젝트 개요',
+ 'Daily project summary export' => '하루 프로젝트 개요의 출력',
+ 'Daily project summary export for "%s"' => '"%s" 하루 프로젝트 개요의 출력',
'Exports' => '출력',
'This export contains the number of tasks per column grouped per day.' => '이 출력은 날짜의 칼람별 할일 수를 집계한 것입니다',
'Active swimlanes' => '액티브한 스윔레인',
'Add a new swimlane' => ' 새로운 스윔레인',
'Change default swimlane' => '기본 스윔레인의 변경',
'Default swimlane' => '기본 스윔레인',
- // 'Do you really want to remove this swimlane: "%s"?' => '',
+ 'Do you really want to remove this swimlane: "%s"?' => '스웜레인을 삭제하시겠습니까: "%s"?',
'Inactive swimlanes' => '인터랙티브한 스윔레인',
'Remove a swimlane' => '스윔레인의 삭제',
'Show default swimlane' => '기본 스윔레인의 표시',
- // 'Swimlane modification for the project "%s"' => '',
+ 'Swimlane modification for the project "%s"' => '"%s" 프로젝트의 스웜레인 수정',
'Swimlane not found.' => '스윔레인이 발견되지 않습니다.',
'Swimlane removed successfully.' => '스윔레인을 삭제했습니다.',
'Swimlanes' => '스윔레인',
@@ -497,14 +496,14 @@ return array(
'Unable to remove this swimlane.' => '스윔레인을 삭제할 수 없었습니다.',
'Unable to update this swimlane.' => '스윔레인을 갱신할 수 없었습니다.',
'Your swimlane have been created successfully.' => '스윔레인이 작성되었습니다.',
- // 'Example: "Bug, Feature Request, Improvement"' => '',
- // 'Default categories for new projects (Comma-separated)' => '',
+ 'Example: "Bug, Feature Request, Improvement"' => '예: "버그, 특성 요청, 향상"',
+ 'Default categories for new projects (Comma-separated)' => '새로운 프로젝트의 기본 카테고리 (콤마(,)로 구분)',
'Integrations' => '연계',
'Integration with third-party services' => '외부 서비스 연계',
'Subtask Id' => '서브 할일 Id',
'Subtasks' => '서브 할일',
'Subtasks Export' => '서브 할일 출력',
- // 'Subtasks exportation for "%s"' => '',
+ 'Subtasks exportation for "%s"' => '"%s"의 서브 할일 출력',
'Task Title' => '할일 제목',
'Untitled' => '제목 없음',
'Application default' => '애플리케이션 기본',
@@ -516,26 +515,25 @@ return array(
'#%d' => '#%d',
'All swimlanes' => '모든 스윔레인',
'All colors' => '모든 색',
- // 'Moved to column %s' => '',
- 'Change description' => '설명 수정',
+ 'Moved to column %s' => '"%s" 칼럼으로 이동',
'User dashboard' => '대시보드',
'Allow only one subtask in progress at the same time for a user' => '한 사용자에 대한 하나의 할일만 진행 중에 가능합니다',
- // 'Edit column "%s"' => '',
- // 'Select the new status of the subtask: "%s"' => '',
+ 'Edit column "%s"' => '"%s" 칼럼 수정',
+ 'Select the new status of the subtask: "%s"' => '서브 할일의 새로운 상태 선택: "%s"',
'Subtask timesheet' => '서브 할일 타임시트',
'There is nothing to show.' => '기록이 없습니다',
- 'Time Tracking' => '타임 트레킹',
+ 'Time Tracking' => '시간 트레킹',
'You already have one subtask in progress' => '이미 진행 중인 서브 할일가 있습니다.',
'Which parts of the project do you want to duplicate?' => '프로젝트의 무엇을 복제합니까?',
- // 'Disallow login form' => '',
+ 'Disallow login form' => '허가되지 않은 로그인 양식',
'Start' => '시작',
'End' => '종료',
'Task age in days' => '할일이 생긴 시간',
'Days in this column' => '이 칼럼에 있는 시간',
'%dd' => '%d일',
'Add a new link' => ' 새로운 링크 추가',
- // 'Do you really want to remove this link: "%s"?' => '',
- // 'Do you really want to remove this link with task #%d?' => '',
+ 'Do you really want to remove this link: "%s"?' => '링크를 삭제하시겠습니까: "%s"?',
+ 'Do you really want to remove this link with task #%d?' => '#%d 할일의 링크를 삭제하시겠습니까?',
'Field required' => '필드가 필요합니다',
'Link added successfully.' => '링크를 추가했습니다.',
'Link updated successfully.' => '링크를 갱신했습니다.',
@@ -609,7 +607,7 @@ return array(
'Change reference currency' => '현재의 기축 통화',
'Add a new currency rate' => ' 새로운 통화 환율을 추가',
'Reference currency' => '기축 통화',
- // 'The currency rate have been added successfully.' => '',
+ 'The currency rate have been added successfully.' => '통화가 성공적으로 추가되었습니다',
'Unable to add this currency rate.' => '이 통화 환율을 추가할 수 없습니다.',
'Webhook URL' => 'Webhook URL',
'%s remove the assignee of the task %s' => '%s이 할일 %s의 담당을 삭제했습니다',
@@ -620,35 +618,35 @@ return array(
'The two factor authentication code is valid.' => '2단 인증 코드는 유효합니다.',
'Code' => '코드',
'Two factor authentication' => '2단 인증',
- // 'This QR code contains the key URI: ' => '',
+ 'This QR code contains the key URI: ' => 'QR 코드는 키 URI를 포함합니다: ',
'Check my code' => '코드 체크',
- // 'Secret key: ' => '',
+ 'Secret key: ' => '비밀키: ',
'Test your device' => '디바이스 테스트',
- // 'Assign a color when the task is moved to a specific column' => '',
+ 'Assign a color when the task is moved to a specific column' => '상세 칼럼으로 이동할 할일의 색깔을 지정하세요',
'%s via Kanboard' => '%s via E-board',
- // 'Burndown chart for "%s"' => '',
- // 'Burndown chart' => '',
+ 'Burndown chart for "%s"' => '"%s" 번다운 차트',
+ 'Burndown chart' => '번다운 차트',
// 'This chart show the task complexity over the time (Work Remaining).' => '',
'Screenshot taken %s' => '스크린샷_%s',
'Add a screenshot' => '스크린샷 추가',
'Take a screenshot and press CTRL+V or ⌘+V to paste here.' => '스크린샷을 CTRL+V 혹은 ⌘+V를 눌러 붙여넣기',
'Screenshot uploaded successfully.' => '스크린샷을 업로드하였습니다',
// 'SEK - Swedish Krona' => '',
- // 'Identifier' => '',
- // 'Disable two factor authentication' => '',
- // 'Do you really want to disable the two factor authentication for this user: "%s"?' => '',
- // 'Edit link' => '',
- 'Start to type task title...' => '할일 제목을 처음부터 입력해주세요',
- // 'A task cannot be linked to itself' => '',
- // 'The exact same link already exists' => '',
+ 'Identifier' => '식별자',
+ 'Disable two factor authentication' => '이중 인증 비활성화',
+ 'Do you really want to disable the two factor authentication for this user: "%s"?' => '"%s" 담당자의 이중 인증을 비활성화 하시겠습니까?',
+ 'Edit link' => '링크 수정',
+ 'Start to type task title...' => '할일 제목을 입력하세요',
+ 'A task cannot be linked to itself' => '할일을 자기자신에게 연결할 수 없습니다',
+ 'The exact same link already exists' => '동일한 링크가 이미 존재합니다',
// 'Recurrent task is scheduled to be generated' => '',
- // 'Score' => '',
- // 'The identifier must be unique' => '',
- // 'This linked task id doesn\'t exists' => '',
- // 'This value must be alphanumeric' => '',
+ 'Score' => '점수',
+ 'The identifier must be unique' => '식별자는 유일해야 합니다',
+ 'This linked task id doesn\'t exists' => '연결된 할일 ID가 존재하지 않습니다',
+ 'This value must be alphanumeric' => '글자와 숫자만 가능합니다',
'Edit recurrence' => '반복 수정',
- 'Generate recurrent task' => '반복 할일 만들기',
- 'Trigger to generate recurrent task' => '반복 할일 트리거 만들기',
+ 'Generate recurrent task' => '반복 할일 생성',
+ 'Trigger to generate recurrent task' => '반복 할일 생성 트리거',
'Factor to calculate new due date' => '새로운 종료날짜 계산',
'Timeframe to calculate new due date' => '종료날짜 계산 단위',
'Base date to calculate new due date' => '새로운 기본 종료날짜 계산',
@@ -659,36 +657,36 @@ return array(
'Existing due date' => '기존 종료날짜',
'Factor to calculate new due date: ' => '새로운 종료날짜 계산: ',
'Month(s)' => '월',
- // 'Recurrence' => '',
- // 'This task has been created by: ' => '',
- // 'Recurrent task has been generated:' => '',
+ 'Recurrence' => '반복',
+ 'This task has been created by: ' => '할일을 만들었습니다: ',
+ 'Recurrent task has been generated:' => '반복 할일이 생성되었습니다',
'Timeframe to calculate new due date: ' => '종료날짜 계산 단위',
// 'Trigger to generate recurrent task: ' => '',
'When task is closed' => '할일을 마쳤을때',
'When task is moved from first column' => '할일이 첫번째 칼럼으로 옮겨졌을때',
'When task is moved to last column' => '할일이 마지막 칼럼으로 옮겨졌을때',
'Year(s)' => '년',
- // 'Calendar settings' => '',
- // 'Project calendar view' => '',
+ 'Calendar settings' => '달력 설정',
+ 'Project calendar view' => '프로젝트 달력 보기',
'Project settings' => '프로젝트 설정',
- // 'Show subtasks based on the time tracking' => '',
- // 'Show tasks based on the creation date' => '',
- // 'Show tasks based on the start date' => '',
- // 'Subtasks time tracking' => '',
- // 'User calendar view' => '',
- // 'Automatically update the start date' => '',
+ 'Show subtasks based on the time tracking' => '시간 트래킹의 서브 할일 보기',
+ 'Show tasks based on the creation date' => '생성 날짜로 할일 보기',
+ 'Show tasks based on the start date' => '시작 날짜로 할일 보기',
+ 'Subtasks time tracking' => '서브 할일 시간 트래킹',
+ 'User calendar view' => '담당자 달력 보기',
+ 'Automatically update the start date' => '시작일에 자동 업데이트',
// 'iCal feed' => '',
- // 'Preferences' => '',
- // 'Security' => '',
- 'Two factor authentication disabled' => '2단 인증 비활성화',
- // 'Two factor authentication enabled' => '',
- // 'Unable to update this user.' => '',
- // 'There is no user management for private projects.' => '',
- // 'User that will receive the email' => '',
+ 'Preferences' => '우선권',
+ 'Security' => '보안',
+ 'Two factor authentication disabled' => '이중 인증이 비활성화 되었습니다',
+ 'Two factor authentication enabled' => '이중 인증이 활성화 되었습니다',
+ 'Unable to update this user.' => '담당자의 업데이트가 가능합니다',
+ 'There is no user management for private projects.' => '비밀 프로젝트의 관리 담당자가 없습니다',
+ 'User that will receive the email' => '그 담당자가 이메일을 수신할 것입니다',
'Email subject' => '이메일 제목',
'Date' => '날짜',
- // 'Add a comment log when moving the task between columns' => '',
- // 'Move the task to another column when the category is changed' => '',
+ 'Add a comment log when moving the task between columns' => '칼럼 중간의 할일이 이동할 때 의견 달기',
+ 'Move the task to another column when the category is changed' => '카테고리 변경시 할일을 다른 칼럼으로 이동',
'Send a task by email to someone' => '할일을 이메일로 보내기',
'Reopen a task' => '할일 다시 시작',
'Column change' => '칼럼 이동',
@@ -697,19 +695,18 @@ return array(
'Assignee change' => '담당자 변경',
'[%s] Overdue tasks' => '[%s] 마감시간 지남',
'Notification' => '알림',
- // '%s moved the task #%d to the first swimlane' => '',
- // '%s moved the task #%d to the swimlane "%s"' => '',
+ '%s moved the task #%d to the first swimlane' => '%s가 할일 #%d를 첫번째 스웜레인으로 이동시켰습니다',
+ '%s moved the task #%d to the swimlane "%s"' => '%s가 할일 #%d를 "%s" 스웜레인으로 이동시켰습니다',
'Swimlane' => '스윔레인',
// 'Gravatar' => '',
- // '%s moved the task %s to the first swimlane' => '',
- // '%s moved the task %s to the swimlane "%s"' => '',
- // 'This report contains all subtasks information for the given date range.' => '',
- // 'This report contains all tasks information for the given date range.' => '',
- // 'Project activities for %s' => '',
- // 'view the board on Kanboard' => '',
- // 'The task have been moved to the first swimlane' => '',
- // 'The task have been moved to another swimlane:' => '',
- // 'Overdue tasks for the project(s) "%s"' => '',
+ '%s moved the task %s to the first swimlane' => '%s가 할일 %s를 첫번째 스웜레인으로 이동시켰습니다',
+ '%s moved the task %s to the swimlane "%s"' => '%s가 할일 %s를 %s 스웜레인으로 이동시켰습니다',
+ 'This report contains all subtasks information for the given date range.' => '해당 기간의 모든 서브 할일 정보가 보고서에 포함됩니다',
+ 'This report contains all tasks information for the given date range.' => '해당 기간의 모든 할일 정보가 보고서에 포함됩니다',
+ 'Project activities for %s' => '%s의 프로젝트 활성화',
+ 'view the board on Kanboard' => 'kanboard로 보드 보기',
+ 'The task have been moved to the first swimlane' => '할일이 첫번째 스웜라인으로 이동되어 있습니다',
+ 'The task have been moved to another swimlane:' => '할일이 다른 스웜라인으로 이동되어 있습니다',
'New title: %s' => '제목 변경: %s',
'The task is not assigned anymore' => '담당자 없음',
'New assignee: %s' => '담당자 변경: %s',
@@ -722,8 +719,8 @@ return array(
'Recurrence settings have been modified' => '반복할일 설정 수정',
'Time spent changed: %sh' => '경과시간 변경: %s시간',
'Time estimated changed: %sh' => '%s시간으로 예상시간 변경',
- // 'The field "%s" have been updated' => '',
- // 'The description has been modified:' => '',
+ 'The field "%s" have been updated' => '%s 필드가 업데이트 되어있습니다',
+ 'The description has been modified:' => '설명이 수정되어 있습니다: ',
'Do you really want to close the task "%s" as well as all subtasks?' => '할일 "%s"과 서브 할일을 모두 마치시겠습니까?',
'I want to receive notifications for:' => '다음의 알림을 받기를 원합니다:',
'All tasks' => '모든 할일',
@@ -731,17 +728,16 @@ return array(
'Only for tasks created by me' => '내가 만든 일',
'Only for tasks created by me and assigned to me' => '내가 만들었거나 내가 담당자인 일',
// '%%Y-%%m-%%d' => '',
- // 'Total for all columns' => '',
- // 'You need at least 2 days of data to show the chart.' => '',
+ 'Total for all columns' => '모든 칼럼',
+ 'You need at least 2 days of data to show the chart.' => '차트를 보기 위하여 최소 2일의 데이터가 필요합니다',
'<15m' => '<15분',
'<30m' => '<30분',
- // 'Stop timer' => '',
+ 'Stop timer' => '타이머 정지',
'Start timer' => '타이머 시작',
- // 'Add project member' => '',
- 'Enable notifications' => '알림 켜기',
+ 'Add project member' => '프로젝트 맴버 추가',
'My activity stream' => '내 활동기록',
'My calendar' => '내 캘린더',
- // 'Search tasks' => '',
+ 'Search tasks' => '할일 찾기',
'Reset filters' => '필터 리셋',
'My tasks due tomorrow' => '내일까지 내 할일',
'Tasks due today' => '오늘까지 할일',
@@ -752,16 +748,16 @@ return array(
'Not assigned' => '담당자가 없는 일',
'View advanced search syntax' => '추가 검색 문법보기',
'Overview' => '개요',
- // 'Board/Calendar/List view' => '',
- // 'Switch to the board view' => '',
- // 'Switch to the calendar view' => '',
- // 'Switch to the list view' => '',
- // 'Go to the search/filter box' => '',
+ 'Board/Calendar/List view' => '보드/달력/리스트 보기',
+ 'Switch to the board view' => '보드 보기로 전환',
+ 'Switch to the calendar view' => '달력 보기로 전환',
+ 'Switch to the list view' => '리스트 보기로 전환',
+ 'Go to the search/filter box' => '검색/필터 박스로 이동',
'There is no activity yet.' => '활동이 없습니다',
- // 'No tasks found.' => '',
- // 'Keyboard shortcut: "%s"' => '',
+ 'No tasks found.' => '할일을 찾을 수 없습니다',
+ 'Keyboard shortcut: "%s"' => '쉬운 키보드: "%s"',
'List' => '목록',
- // 'Filter' => '',
+ 'Filter' => '필터',
'Advanced search' => '검색 문법',
'Example of query: ' => '문법 예제 ',
'Search by project: ' => '프로젝트로 찾기 ',
@@ -771,58 +767,58 @@ return array(
'Search by category: ' => '카테고리로 찾기 ',
'Search by description: ' => '설명으로 찾기 ',
'Search by due date: ' => '마감날짜로 찾기 ',
- // 'Lead and Cycle time for "%s"' => '',
- // 'Average time spent into each column for "%s"' => '',
- // 'Average time spent into each column' => '',
- // 'Average time spent' => '',
- // 'This chart show the average time spent into each column for the last %d tasks.' => '',
- // 'Average Lead and Cycle time' => '',
- // 'Average lead time: ' => '',
- // 'Average cycle time: ' => '',
- 'Cycle Time' => '사이클 타임',
- 'Lead Time' => '리드 타임',
- // 'This chart show the average lead and cycle time for the last %d tasks over the time.' => '',
- // 'Average time into each column' => '',
- // 'Lead and cycle time' => '',
- 'Lead time: ' => '리드 타임: ',
- 'Cycle time: ' => '사이클 타임: ',
+ 'Lead and Cycle time for "%s"' => '"%s"의 리드와 사이클 시간',
+ 'Average time spent into each column for "%s"' => '"%s"의 각 칼럼 평균 소요시간',
+ 'Average time spent into each column' => '각 칼럼의 평균 소요시간',
+ 'Average time spent' => '평균 소요시간',
+ 'This chart show the average time spent into each column for the last %d tasks.' => '마지막 %d 할일의 칼럼 평균 소요시간을 차트에 표시합니다',
+ 'Average Lead and Cycle time' => '평균 Lead and Cycle 시간',
+ 'Average lead time: ' => '평균 lead 시간',
+ 'Average cycle time: ' => '평균 cycle 시간',
+ 'Cycle Time' => '사이클 시간',
+ 'Lead Time' => '리드 시간',
+ 'This chart show the average lead and cycle time for the last %d tasks over the time.' => '마지막 %d 할일의 평균 리드와 사이클 시간을 차트에 표시합니다',
+ 'Average time into each column' => '각 칼럼의 평균 시간',
+ 'Lead and cycle time' => '리드와 사이클 시간',
+ 'Lead time: ' => '리드 시간: ',
+ 'Cycle time: ' => '사이클 시간: ',
'Time spent into each column' => '각 칼럼에서 걸린 시간',
- // 'The lead time is the duration between the task creation and the completion.' => '',
- // 'The cycle time is the duration between the start date and the completion.' => '',
- // 'If the task is not closed the current time is used instead of the completion date.' => '',
- // 'Set automatically the start date' => '',
+ 'The lead time is the duration between the task creation and the completion.' => '리드 시간은 할일의 생성부터 완료까지의 기간입니다',
+ 'The cycle time is the duration between the start date and the completion.' => '사이클 시간은 할일의 시작일부터 완료까지의 기간입니다',
+ 'If the task is not closed the current time is used instead of the completion date.' => '할일이 종료되지 않았다면, 완료 시간 대신 현재 시간이 사용됩니다',
+ 'Set automatically the start date' => '자동으로 시작 날짜를 설정합니다',
'Edit Authentication' => '계정 수정',
- // 'Remote user' => '',
- // 'Remote users do not store their password in Kanboard database, examples: LDAP, Google and Github accounts.' => '',
- // 'If you check the box "Disallow login form", credentials entered in the login form will be ignored.' => '',
+ 'Remote user' => '원격 담당자',
+ 'Remote users do not store their password in Kanboard database, examples: LDAP, Google and Github accounts.' => '예를 들어 LDAP, Google, Github 계정같은 원격 담당자의 비밀번호는 칸반보드 데이터베이스에 저장하지 않습니다',
+ 'If you check the box "Disallow login form", credentials entered in the login form will be ignored.' => '만약 "로그인 폼 거절"에 체크한다면, 로그인 폼에 접근할 자격이 무시됩니다',
'New remote user' => '새로운 원격유저',
'New local user' => '새로운 유저',
- // 'Default task color' => '',
+ 'Default task color' => '기본 할일 색',
'This feature does not work with all browsers.' => '이 기능은 일부 브라우저에서 작동하지 않습니다',
- // 'There is no destination project available.' => '',
- // 'Trigger automatically subtask time tracking' => '',
- // 'Include closed tasks in the cumulative flow diagram' => '',
- // 'Current swimlane: %s' => '',
- // 'Current column: %s' => '',
- // 'Current category: %s' => '',
- // 'no category' => '',
- // 'Current assignee: %s' => '',
- // 'not assigned' => '',
- // 'Author:' => '',
- // 'contributors' => '',
- // 'License:' => '',
- // 'License' => '',
- // 'Enter the text below' => '',
- // 'Gantt chart for %s' => '',
- // 'Sort by position' => '',
- // 'Sort by date' => '',
- // 'Add task' => '',
- // 'Start date:' => '',
- // 'Due date:' => '',
- // 'There is no start date or due date for this task.' => '',
+ 'There is no destination project available.' => '가능한 목적 프로젝트가 없습니다',
+ 'Trigger automatically subtask time tracking' => '자동 서브 할일 시간 트래킹 트리거',
+ 'Include closed tasks in the cumulative flow diagram' => '누적 플로우 다이어그램에 종료된 할일을 포함합니다',
+ 'Current swimlane: %s' => '현재 스웜라인: %s',
+ 'Current column: %s' => '현재 칼럼: %s',
+ 'Current category: %s' => '현재 카테고리: %s',
+ 'no category' => '카테고리 아님',
+ 'Current assignee: %s' => '현재 할당자: %s',
+ 'not assigned' => '할당되지 않음',
+ 'Author:' => '글쓴이:',
+ 'contributors' => '기여자',
+ 'License:' => '라이센스:',
+ 'License' => '라이센스',
+ 'Enter the text below' => '아랫글로 들어가기',
+ 'Gantt chart for %s' => '%s의 간트 차트',
+ 'Sort by position' => '위치별 정렬',
+ 'Sort by date' => '날짜별 정렬',
+ 'Add task' => '할일 추가',
+ 'Start date:' => '시작일:',
+ 'Due date:' => '만기일:',
+ 'There is no start date or due date for this task.' => '할일의 시작일 또는 만기일이 없습니다',
// 'Moving or resizing a task will change the start and due date of the task.' => '',
// 'There is no task in your project.' => '',
- 'Gantt chart' => '간트차트',
+ 'Gantt chart' => '간트 차트',
'People who are project managers' => '프로젝트 매니저',
'People who are project members' => '프로젝트 멤버',
// 'NOK - Norwegian Krone' => '',
@@ -832,39 +828,39 @@ return array(
'End date' => '종료 날짜',
'Users overview' => '유저 전체보기',
'Members' => '멤버',
- // 'Shared project' => '',
+ 'Shared project' => '프로젝트 공유',
'Project managers' => '프로젝트 매니저',
- // 'Gantt chart for all projects' => '',
+ 'Gantt chart for all projects' => '모든 프로젝트의 간트 차트',
'Projects list' => '프로젝트 리스트',
'Gantt chart for this project' => '이 프로젝트 간트차트',
'Project board' => '프로젝트 보드',
- // 'End date:' => '',
+ 'End date:' => '날짜 수정',
'There is no start date or end date for this project.' => '이 프로젝트에는 시작날짜와 종료날짜가 없습니다',
'Projects Gantt chart' => '프로젝트 간트차트',
// 'Change task color when using a specific task link' => '',
// 'Task link creation or modification' => '',
- // 'Milestone' => '',
- // 'Documentation: %s' => '',
- // 'Switch to the Gantt chart view' => '',
+ 'Milestone' => '마일스톤',
+ 'Documentation: %s' => '문서: %s',
+ 'Switch to the Gantt chart view' => '간트 차트 보기로 변경',
// 'Reset the search/filter box' => '',
- // 'Documentation' => '',
+ 'Documentation' => '문서',
// 'Table of contents' => '',
'Gantt' => '간트',
- // 'Author' => '',
- // 'Version' => '',
- // 'Plugins' => '',
- // 'There is no plugin loaded.' => '',
+ 'Author' => '글쓴이',
+ 'Version' => '버전',
+ 'Plugins' => '플러그인',
+ 'There is no plugin loaded.' => '플러그인이 로드되지 않았습니다',
'Set maximum column height' => '최대 칼럼 높이 제한하기',
'Remove maximum column height' => '최대 칼럼 높이 없애기',
'My notifications' => '내 알림',
'Custom filters' => '사용자 정의 필터',
- // 'Your custom filter have been created successfully.' => '',
- // 'Unable to create your custom filter.' => '',
- // 'Custom filter removed successfully.' => '',
- // 'Unable to remove this custom filter.' => '',
- // 'Edit custom filter' => '',
- // 'Your custom filter have been updated successfully.' => '',
- // 'Unable to update custom filter.' => '',
+ 'Your custom filter have been created successfully.' => '사용자 정의 필터가 성공적으로 생성되었습니다',
+ 'Unable to create your custom filter.' => '사용자 정의 필터 생성 비활성화',
+ 'Custom filter removed successfully.' => '사용자 정의 필터가 성공적으로 삭제되었습니다',
+ 'Unable to remove this custom filter.' => '정의 필터 삭제 비활성화',
+ 'Edit custom filter' => '정의 필터 수정',
+ 'Your custom filter have been updated successfully.' => '사용자 정의 필터가 성공적으로 수정되었습니다',
+ 'Unable to update custom filter.' => '정의 필터 수정 비활성화',
'Web' => '웹',
// 'New attachment on task #%d: %s' => '',
'New comment on task #%d' => '할일 #%d에 새로운 댓글이 달렸습니다',
@@ -874,297 +870,334 @@ return array(
'New task #%d: %s' => '할일 #%d: %s이 추가되었습니다',
'Task updated #%d' => '할일 #%d이 업데이트되었습니다',
'Task #%d closed' => '할일 #%d를 마쳤습니다',
- // 'Task #%d opened' => '',
+ 'Task #%d opened' => '할일 #%d가 시작되었습니다',
'Column changed for task #%d' => '할일 #%d의 칼럼이 변경되었습니다',
'New position for task #%d' => '할일 #%d이 새로운 위치에 등록되었습니다',
- // 'Swimlane changed for task #%d' => '',
- // 'Assignee changed on task #%d' => '',
- // '%d overdue tasks' => '',
- // 'Task #%d is overdue' => '',
+ 'Swimlane changed for task #%d' => '#%d 할일의 스웜라인이 변경됩니다',
+ 'Assignee changed on task #%d' => '#%d 할일의 담당자가 변경됩니다',
+ '%d overdue tasks' => '할일의 기한이 %d일 지났습니다',
+ 'Task #%d is overdue' => '#%d 할일의 기한이 지났습니다',
'No new notifications.' => '알림이 없습니다',
'Mark all as read' => '모두 읽음',
'Mark as read' => '읽음',
// 'Total number of tasks in this column across all swimlanes' => '',
- // 'Collapse swimlane' => '',
- // 'Expand swimlane' => '',
- // 'Add a new filter' => '',
- // 'Share with all project members' => '',
- // 'Shared' => '',
- // 'Owner' => '',
+ 'Collapse swimlane' => '스웜라인 붕괴',
+ 'Expand swimlane' => '스웜라인 확장',
+ 'Add a new filter' => '새로운 필터 추가',
+ 'Share with all project members' => '모든 프로젝트 맴버 공유',
+ 'Shared' => '공유',
+ 'Owner' => '소유자',
'Unread notifications' => '읽지않은 알림',
'Notification methods:' => '알림 방법',
- // 'Import tasks from CSV file' => '',
- // 'Unable to read your file' => '',
- // '%d task(s) have been imported successfully.' => '',
- // 'Nothing have been imported!' => '',
- // 'Import users from CSV file' => '',
- // '%d user(s) have been imported successfully.' => '',
- // 'Comma' => '',
- // 'Semi-colon' => '',
- // 'Tab' => '',
- // 'Vertical bar' => '',
- // 'Double Quote' => '',
- // 'Single Quote' => '',
- // '%s attached a file to the task #%d' => '',
- // 'There is no column or swimlane activated in your project!' => '',
+ 'Import tasks from CSV file' => 'CSV 파일에서 할일 가져오기',
+ 'Unable to read your file' => '파일을 읽을 수 없습니다',
+ '%d task(s) have been imported successfully.' => '%d 할일이 성공적으로 추가되었습니다',
+ 'Nothing have been imported!' => '추가가 되지 않았습니다!',
+ 'Import users from CSV file' => 'CSV 파일에서 사용자 가져오기',
+ '%d user(s) have been imported successfully.' => '%d 사용자가 성공적으로 추가되었습니다',
+ 'Comma' => '콤마',
+ 'Semi-colon' => '세미콜론',
+ 'Tab' => '탭',
+ 'Vertical bar' => '세로줄',
+ 'Double Quote' => '이중 따옴표',
+ 'Single Quote' => '따옴표',
+ '%s attached a file to the task #%d' => '%s가 할일 #%d에 파일을 추가하였습니다',
+ 'There is no column or swimlane activated in your project!' => '프로젝트에 활성화된 칼럼이나 스웜라인이 없습니다',
// 'Append filter (instead of replacement)' => '',
- // 'Append/Replace' => '',
- // 'Append' => '',
- // 'Replace' => '',
+ 'Append/Replace' => '추가/변경',
+ 'Append' => '추가',
+ 'Replace' => '변경',
'Import' => '가져오기',
- // 'change sorting' => '',
- // 'Tasks Importation' => '',
- // 'Delimiter' => '',
- // 'Enclosure' => '',
- // 'CSV File' => '',
- // 'Instructions' => '',
- // 'Your file must use the predefined CSV format' => '',
- // 'Your file must be encoded in UTF-8' => '',
- // 'The first row must be the header' => '',
- // 'Duplicates are not verified for you' => '',
- // 'The due date must use the ISO format: YYYY-MM-DD' => '',
- // 'Download CSV template' => '',
+ 'change sorting' => '정렬 변경',
+ 'Tasks Importation' => '할일 가져오기',
+ 'Delimiter' => '구분자',
+ 'Enclosure' => '동봉',
+ 'CSV File' => 'CSV 파일',
+ 'Instructions' => '명령',
+ 'Your file must use the predefined CSV format' => '파일은 미리 정의된 CVS 형식이어야 합니다',
+ 'Your file must be encoded in UTF-8' => '파일은 UTF-8로 인코딩되어야 합니다',
+ 'The first row must be the header' => '첫 줄은 헤더이어야 합니다',
+ 'Duplicates are not verified for you' => '사본이 허락되지 않습니다',
+ 'The due date must use the ISO format: YYYY-MM-DD' => '만기일은 ISO 형식이어야 합니다: YYYY-MM-DD',
+ 'Download CSV template' => 'CVS 탬플릿 내려받기',
'No external integration registered.' => '설정이 되어있지 않습니다',
- // 'Duplicates are not imported' => '',
- // 'Usernames must be lowercase and unique' => '',
- // 'Passwords will be encrypted if present' => '',
+ 'Duplicates are not imported' => '사본을 가져올 수 없습니다',
+ 'Usernames must be lowercase and unique' => '사용자 이름은 소문자이며 유일해야 합니다',
+ 'Passwords will be encrypted if present' => '비밀번호는 암호화됩니다',
'%s attached a new file to the task %s' => '%s이 새로운 파일을 할일 %s에 추가했습니다',
- // 'Link type' => '',
- // 'Assign automatically a category based on a link' => '',
+ 'Link type' => '링크 형식',
+ 'Assign automatically a category based on a link' => '링크 기반 자동 카테고리 할당',
// 'BAM - Konvertible Mark' => '',
- // 'Assignee Username' => '',
- // 'Assignee Name' => '',
- // 'Groups' => '',
- // 'Members of %s' => '',
- // 'New group' => '',
- // 'Group created successfully.' => '',
- // 'Unable to create your group.' => '',
- // 'Edit group' => '',
- // 'Group updated successfully.' => '',
- // 'Unable to update your group.' => '',
- // 'Add group member to "%s"' => '',
- // 'Group member added successfully.' => '',
- // 'Unable to add group member.' => '',
- // 'Remove user from group "%s"' => '',
- // 'User removed successfully from this group.' => '',
- // 'Unable to remove this user from the group.' => '',
- // 'Remove group' => '',
- // 'Group removed successfully.' => '',
- // 'Unable to remove this group.' => '',
- // 'Project Permissions' => '',
+ 'Assignee Username' => '담당자의 사용자이름',
+ 'Assignee Name' => '당장자 이름',
+ 'Groups' => '그룹',
+ 'Members of %s' => '%s의 맴버',
+ 'New group' => '새로운 그룹',
+ 'Group created successfully.' => '그룹이 성공적으로 생성되었습니다',
+ 'Unable to create your group.' => '그룹 생성 비활성화',
+ 'Edit group' => '그룹 편집',
+ 'Group updated successfully.' => '그룹이 성공적으로 수정되었습니다',
+ 'Unable to update your group.' => '그룹 수정 비활성화',
+ 'Add group member to "%s"' => '%s 그룹 맴버 추가',
+ 'Group member added successfully.' => '그룹 맴버가 성공적으로 추가되었습니다',
+ 'Unable to add group member.' => '그룹 맴버 추가 비활성화',
+ 'Remove user from group "%s"' => '%s 그룹 사용자 삭제',
+ 'User removed successfully from this group.' => '그룹 사용자가 성공적으로 삭제되었습니다',
+ 'Unable to remove this user from the group.' => '그룹 사용자 삭제 비활성화',
+ 'Remove group' => '그룹 삭제',
+ 'Group removed successfully.' => '그룹이 성공적으로 삭제되었습니다',
+ 'Unable to remove this group.' => '그룹 삭제 비활성화',
+ 'Project Permissions' => '프로젝트 권한',
'Manager' => '매니저',
'Project Manager' => '프로젝트 매니저',
'Project Member' => '프로젝트 멤버',
- // 'Project Viewer' => '',
- // 'Your account is locked for %d minutes' => '',
+ 'Project Viewer' => '프로젝트 뷰어',
+ 'Your account is locked for %d minutes' => '%d분 동안 계정이 잠깁니다',
// 'Invalid captcha' => '',
- // 'The name must be unique' => '',
+ 'The name must be unique' => '이름은 유일해야 합니다',
'View all groups' => '모든그룹보기',
- // 'View group members' => '',
- // 'There is no user available.' => '',
- // 'Do you really want to remove the user "%s" from the group "%s"?' => '',
- // 'There is no group.' => '',
- // 'External Id' => '',
+ 'View group members' => '그룹맴버 보기',
+ 'There is no user available.' => '가능한 사용자가 없습니다',
+ 'Do you really want to remove the user "%s" from the group "%s"?' => '"%s" 사용자를 "%s" 에서 삭제하시겠습니까?',
+ 'There is no group.' => '그룹이 없습니다',
+ 'External Id' => '외부 아이디',
'Add group member' => '멤버추가',
- // 'Do you really want to remove this group: "%s"?' => '',
- // 'There is no user in this group.' => '',
- // 'Remove this user' => '',
+ 'Do you really want to remove this group: "%s"?' => '그룹을 삭제하시겠습니까: "%s"?',
+ 'There is no user in this group.' => '이 그룹에는 사용자가 없습니다',
+ 'Remove this user' => '사용자 삭제',
'Permissions' => '권한',
- // 'Allowed Users' => '',
- // 'No user have been allowed specifically.' => '',
+ 'Allowed Users' => '사용자 승인',
+ 'No user have been allowed specifically.' => '구체적으로 승인된 사용자가 없습니다',
'Role' => '역할',
- // 'Enter user name...' => '',
- // 'Allowed Groups' => '',
- // 'No group have been allowed specifically.' => '',
- // 'Group' => '',
- // 'Group Name' => '',
- // 'Enter group name...' => '',
+ 'Enter user name...' => '사용자 이름을 입력합니다...',
+ 'Allowed Groups' => '승인된 그룹',
+ 'No group have been allowed specifically.' => '구체적으로 승인된 그룹이 없습니다',
+ 'Group' => '그룹',
+ 'Group Name' => '그룹명',
+ 'Enter group name...' => '그룹명을 입력합니다...',
'Role:' => '역할: ',
'Project members' => '프로젝트 멤버',
- // 'Compare hours for "%s"' => '',
- // '%s mentioned you in the task #%d' => '',
- // '%s mentioned you in a comment on the task #%d' => '',
- // 'You were mentioned in the task #%d' => '',
+ 'Compare hours for "%s"' => '"%s" 시간동안 비교',
+ '%s mentioned you in the task #%d' => '#%d 할일에서 %s가 당신을 언급하였습니다',
+ '%s mentioned you in a comment on the task #%d' => '#%d 할일에서 %s가 당신의 댓글을 언급하였습니다',
+ 'You were mentioned in the task #%d' => '#%d 할일에서 당신이 언급되었습니다',
'You were mentioned in a comment on the task #%d' => '할일 #%d의 댓글에서 언급되었습니다',
- // 'Mentioned' => '',
- // 'Compare Estimated Time vs Actual Time' => '',
- // 'Estimated hours: ' => '',
- // 'Actual hours: ' => '',
- // 'Hours Spent' => '',
- // 'Hours Estimated' => '',
- // 'Estimated Time' => '',
- // 'Actual Time' => '',
- // 'Estimated vs actual time' => '',
+ 'Mentioned' => '언급된',
+ 'Compare Estimated Time vs Actual Time' => '예상 시간과 실제 시간 비교',
+ 'Estimated hours: ' => '예상 시간: ',
+ 'Actual hours: ' => '실제 시간: ',
+ 'Hours Spent' => '소요 시간',
+ 'Hours Estimated' => '예상 시간',
+ 'Estimated Time' => '예상 시간',
+ 'Actual Time' => '실제 시간',
+ 'Estimated vs actual time' => '예상 vs 실제 시간',
// 'RUB - Russian Ruble' => '',
- // 'Assign the task to the person who does the action when the column is changed' => '',
- // 'Close a task in a specific column' => '',
+ 'Assign the task to the person who does the action when the column is changed' => '칼럼이 변경되면 액션하지 않는 사람에게 할일을 할당합니다',
+ 'Close a task in a specific column' => '상세 칼럼의 할일을 종료합니다',
'Time-based One-time Password Algorithm' => '시간에 기반한 1회용 패스워드 알고리즘',
- 'Two-Factor Provider: ' => '2단 인증: ',
- // 'Disable two-factor authentication' => '',
- 'Enable two-factor authentication' => '2단 인증 활성화',
+ 'Two-Factor Provider: ' => '이중 인증: ',
+ 'Disable two-factor authentication' => '이중 인증 비활성화',
+ 'Enable two-factor authentication' => '이중 인증 활성화',
// 'There is no integration registered at the moment.' => '',
- // 'Password Reset for Kanboard' => '',
+ 'Password Reset for Kanboard' => 'Kanboard의 비밀번호 초기화',
'Forgot password?' => '비밀번호 찾기',
- // 'Enable "Forget Password"' => '',
- // 'Password Reset' => '',
- // 'New password' => '',
- // 'Change Password' => '',
- // 'To reset your password click on this link:' => '',
- 'Last Password Reset' => '비밀번호 초기화',
+ 'Enable "Forget Password"' => '"비밀번호 분실" 활성화',
+ 'Password Reset' => '비밀번호 초기화',
+ 'New password' => '새로운 비밀번호',
+ 'Change Password' => '비밀번호 변경',
+ 'To reset your password click on this link:' => '비밀번호를 초기화 하시려면 링크를 눌러주세요:',
+ 'Last Password Reset' => '마지막 비밀번호 초기화',
'The password has never been reinitialized.' => '비밀번호가 초기화되지 않았습니다',
- // 'Creation' => '',
- // 'Expiration' => '',
+ 'Creation' => '생성',
+ 'Expiration' => '만료',
'Password reset history' => '비밀번호 초기화 기록',
- // 'All tasks of the column "%s" and the swimlane "%s" have been closed successfully.' => '',
- // 'Do you really want to close all tasks of this column?' => '',
- // '%d task(s) in the column "%s" and the swimlane "%s" will be closed.' => '',
+ 'All tasks of the column "%s" and the swimlane "%s" have been closed successfully.' => '칼럼 "%s"와 스웜라인 "%s"의 모든 할일이 성공적으로 종료되었습니다',
+ 'Do you really want to close all tasks of this column?' => '이 칼럼의 모든 할일을 종료 하시겠습니까?',
+ '%d task(s) in the column "%s" and the swimlane "%s" will be closed.' => '칼럼 "%s"와 스웜라인 "%s"의 할일 %d가 종료될 것입니다',
'Close all tasks of this column' => '칼럼의 모든 할일 마치기',
- // 'No plugin has registered a project notification method. You can still configure individual notifications in your user profile.' => '',
+ 'No plugin has registered a project notification method. You can still configure individual notifications in your user profile.' => '프로젝트 알림 방법으로 플러그인이 등록되지 않았습니다. 각각의 알림을 프로파일에서 설정하실 수 있습니다',
'My dashboard' => '대시보드',
'My profile' => '프로필',
- // 'Project owner: ' => '',
- // 'The project identifier is optional and must be alphanumeric, example: MYPROJECT.' => '',
+ 'Project owner: ' => '프로젝트 소유자',
+ 'The project identifier is optional and must be alphanumeric, example: MYPROJECT.' => '프로젝트 구분자는 선택사항이며, 숫자와 문자만 가능합니다. 예: MYPROJECT.',
// 'Project owner' => '',
- // 'Those dates are useful for the project Gantt chart.' => '',
- // 'Private projects do not have users and groups management.' => '',
- // 'There is no project member.' => '',
- // 'Priority' => '',
- // 'Task priority' => '',
- // 'General' => '',
- // 'Dates' => '',
- // 'Default priority' => '',
- // 'Lowest priority' => '',
- // 'Highest priority' => '',
- // 'If you put zero to the low and high priority, this feature will be disabled.' => '',
- // 'Close a task when there is no activity' => '',
- // 'Duration in days' => '',
- // 'Send email when there is no activity on a task' => '',
- // 'Unable to fetch link information.' => '',
+ 'Those dates are useful for the project Gantt chart.' => '이 날짜는 프로젝트 간트 차트에 사용됩니다',
+ 'Private projects do not have users and groups management.' => '비밀 프로젝트는 사용자나 관리 그룹이 소유하지 않습니다',
+ 'There is no project member.' => '프로젝트 맴버가 없습니다',
+ 'Priority' => '우선순위',
+ 'Task priority' => '할일의 우선순위',
+ 'General' => '일반적인',
+ 'Dates' => '날짜',
+ 'Default priority' => '기본 우선순위',
+ 'Lowest priority' => '낮은 우선순위',
+ 'Highest priority' => '높은 우선순위',
+ 'If you put zero to the low and high priority, this feature will be disabled.' => '만약 낮은/높은 우선순위에 0을 입력하면 이 특성은 비활성화됩니다',
+ 'Close a task when there is no activity' => '활동이 없는 할일을 종료합니다',
+ 'Duration in days' => '기간',
+ 'Send email when there is no activity on a task' => '활동이 없는 할일을 이메일로 보냅니다',
+ 'Unable to fetch link information.' => '링크 정보 가져오기 비활성화',
// 'Daily background job for tasks' => '',
- // 'Auto' => '',
- // 'Related' => '',
- // 'Attachment' => '',
- // 'Title not found' => '',
- // 'Web Link' => '',
- // 'External links' => '',
- // 'Add external link' => '',
- // 'Type' => '',
- // 'Dependency' => '',
- // 'Add internal link' => '',
- // 'Add a new external link' => '',
- // 'Edit external link' => '',
- // 'External link' => '',
- // 'Copy and paste your link here...' => '',
+ 'Auto' => '자동',
+ 'Related' => '연관된',
+ 'Attachment' => '첨부',
+ 'Title not found' => '제목이 없습니다',
+ 'Web Link' => '웹 링크',
+ 'External links' => '외부 링크',
+ 'Add external link' => '외부 링크 추가',
+ 'Type' => '타입',
+ 'Dependency' => '의존',
+ 'Add internal link' => '내부 링크 추가',
+ 'Add a new external link' => '새로운 외부 링크 추가',
+ 'Edit external link' => '외부 링크 수정',
+ 'External link' => '외부 링크',
+ 'Copy and paste your link here...' => '여기에 링크를 복사/붙여넣기',
// 'URL' => '',
- // 'Internal links' => '',
- // 'Assign to me' => '',
- // 'Me' => '',
- // 'Do not duplicate anything' => '',
- // 'Projects management' => '',
- // 'Users management' => '',
- // 'Groups management' => '',
- // 'Create from another project' => '',
- // 'open' => '',
- // 'closed' => '',
- // 'Priority:' => '',
- // 'Reference:' => '',
- // 'Complexity:' => '',
- // 'Swimlane:' => '',
- // 'Column:' => '',
- // 'Position:' => '',
- // 'Creator:' => '',
- // 'Time estimated:' => '',
- // '%s hours' => '',
- // 'Time spent:' => '',
- // 'Created:' => '',
- // 'Modified:' => '',
- // 'Completed:' => '',
- // 'Started:' => '',
- // 'Moved:' => '',
- // 'Task #%d' => '',
- // 'Date and time format' => '',
- // 'Time format' => '',
- // 'Start date: ' => '',
- // 'End date: ' => '',
- // 'New due date: ' => '',
- // 'Start date changed: ' => '',
- // 'Disable private projects' => '',
- // 'Do you really want to remove this custom filter: "%s"?' => '',
- // 'Remove a custom filter' => '',
- // 'User activated successfully.' => '',
+ 'Internal links' => '내부 링크',
+ 'Assign to me' => '나에게 할당',
+ 'Me' => '나',
+ 'Do not duplicate anything' => '복사할까요?',
+ 'Projects management' => '프로젝트 관리',
+ 'Users management' => '사용자 관리',
+ 'Groups management' => '그룹 관리',
+ 'Create from another project' => '다른 프로젝트 생성',
+ 'open' => '시작',
+ 'closed' => '종료',
+ 'Priority:' => '우선순위:',
+ 'Reference:' => '참고:',
+ 'Complexity:' => '복합:',
+ 'Swimlane:' => '스웜라인:',
+ 'Column:' => '칼럼:',
+ 'Position:' => '위치:',
+ 'Creator:' => '생성자:',
+ 'Time estimated:' => '예상 시간:',
+ '%s hours' => '%s 시간',
+ 'Time spent:' => '소요 시간:',
+ 'Created:' => '생성:',
+ 'Modified:' => '수정;',
+ 'Completed:' => '완료:',
+ 'Started:' => '시작:',
+ 'Moved:' => '이동:',
+ 'Task #%d' => '할일 #%d',
+ 'Date and time format' => '날짜와 시간 형식',
+ 'Time format' => '시간 형식',
+ 'Start date: ' => '시작일: ',
+ 'End date: ' => '종료일: ',
+ 'New due date: ' => '새로운 만기일: ',
+ 'Start date changed: ' => '변경된 시작일: ',
+ 'Disable private projects' => '비밀 프로젝트 비활성화',
+ 'Do you really want to remove this custom filter: "%s"?' => '정의 필터를 삭제하시겠습니까: "%s"?',
+ 'Remove a custom filter' => '정의 필터 삭제',
+ 'User activated successfully.' => '사용자가 성공적으로 활성화되었습니다',
// 'Unable to enable this user.' => '',
- // 'User disabled successfully.' => '',
+ 'User disabled successfully.' => '사용자가 성공적으로 비활성화되었습니다',
// 'Unable to disable this user.' => '',
- // 'All files have been uploaded successfully.' => '',
- // 'View uploaded files' => '',
- // 'The maximum allowed file size is %sB.' => '',
- // 'Choose files again' => '',
- // 'Drag and drop your files here' => '',
- // 'choose files' => '',
- // 'View profile' => '',
- // 'Two Factor' => '',
- // 'Disable user' => '',
- // 'Do you really want to disable this user: "%s"?' => '',
- // 'Enable user' => '',
- // 'Do you really want to enable this user: "%s"?' => '',
- // 'Download' => '',
- // 'Uploaded: %s' => '',
- // 'Size: %s' => '',
- // 'Uploaded by %s' => '',
- // 'Filename' => '',
- // 'Size' => '',
- // 'Column created successfully.' => '',
- // 'Another column with the same name exists in the project' => '',
- // 'Default filters' => '',
- // 'Your board doesn\'t have any column!' => '',
- // 'Change column position' => '',
- // 'Switch to the project overview' => '',
- // 'User filters' => '',
- // 'Category filters' => '',
- // 'Upload a file' => '',
- // 'View file' => '',
- // 'Last activity' => '',
- // 'Change subtask position' => '',
- // 'This value must be greater than %d' => '',
- // 'Another swimlane with the same name exists in the project' => '',
- // 'Example: http://example.kanboard.net/ (used to generate absolute URLs)' => '',
- // 'Actions duplicated successfully.' => '',
- // 'Unable to duplicate actions.' => '',
- // 'Add a new action' => '',
- // 'Import from another project' => '',
- // 'There is no action at the moment.' => '',
- // 'Import actions from another project' => '',
- // 'There is no available project.' => '',
- // 'Local File' => '',
- // 'Configuration' => '',
- // 'PHP version:' => '',
+ 'All files have been uploaded successfully.' => '모든 파일이 성공적으로 업로드되었습니다',
+ 'View uploaded files' => '업로드 파일 보기',
+ 'The maximum allowed file size is %sB.' => '업로드 파일의 최대 크기는 %sB 입니다',
+ 'Choose files again' => '파일 다시 선택',
+ 'Drag and drop your files here' => '파일을 이곳으로 끌고오기',
+ 'choose files' => '파일 선택',
+ 'View profile' => '프로파일 보기',
+ 'Two Factor' => '이중',
+ 'Disable user' => '사용자 비활성화',
+ 'Do you really want to disable this user: "%s"?' => '사용자를 비활성화 시키겠습니까: "%s"?',
+ 'Enable user' => '사용자 활성화',
+ 'Do you really want to enable this user: "%s"?' => '사용자를 활성화 시키겠습니까: "%s"?',
+ 'Download' => '내려받기',
+ 'Uploaded: %s' => '올리기: %s',
+ 'Size: %s' => '크기: %s',
+ 'Uploaded by %s' => '%s로 올리기',
+ 'Filename' => '파일 이름',
+ 'Size' => '크기',
+ 'Column created successfully.' => '칼럼이 성공적으로 생성되었습니다',
+ 'Another column with the same name exists in the project' => '프로젝트에 동일한 이름의 칼럼이 있습니다',
+ 'Default filters' => '기본 필터',
+ 'Your board doesn\'t have any column!' => '보드에 칼럼이 존재하지 않습니다',
+ 'Change column position' => '칼럼 위치 변경',
+ 'Switch to the project overview' => '프로젝트 개요로 변경',
+ 'User filters' => '사용자 필터',
+ 'Category filters' => '카테고리 필터',
+ 'Upload a file' => '파일 업로드',
+ 'View file' => '파일 보기',
+ 'Last activity' => '마지막 행동',
+ 'Change subtask position' => '서브 할일 위치 변경',
+ 'This value must be greater than %d' => '이 값은 %d보다 커야 합니다',
+ 'Another swimlane with the same name exists in the project' => '프로젝트에 같은 이름의 스웜라인이 존재합니다',
+ 'Example: http://example.kanboard.net/ (used to generate absolute URLs)' => '예: http://example.kanboard.net/ (절대적 URLs을 생성하는데 사용됨)',
+ 'Actions duplicated successfully.' => '행동이 성공적으로 복제되었습니다',
+ 'Unable to duplicate actions.' => '행동 복제 비활성화',
+ 'Add a new action' => '새로운 행동 추가',
+ 'Import from another project' => '다른 프로젝트에서 가져오기',
+ 'There is no action at the moment.' => '현재 행동이 없습니다',
+ 'Import actions from another project' => '다른 프로젝트에서 행동 가져오기',
+ 'There is no available project.' => '사용 가능한 프로젝트가 없습니다',
+ 'Local File' => '로컬 파일',
+ 'Configuration' => '구성',
+ 'PHP version:' => 'PHP 버전:',
// 'PHP SAPI:' => '',
- // 'OS version:' => '',
- // 'Database version:' => '',
- // 'Browser:' => '',
- // 'Task view' => '',
- // 'Edit task' => '',
- // 'Edit description' => '',
- // 'New internal link' => '',
- // 'Display list of keyboard shortcuts' => '',
- // 'Menu' => '',
- // 'Set start date' => '',
- // 'Avatar' => '',
- // 'Upload my avatar image' => '',
- // 'Remove my image' => '',
- // 'The OAuth2 state parameter is invalid' => '',
- // 'User not found.' => '',
- // 'Search in activity stream' => '',
- // 'My activities' => '',
- // 'Activity until yesterday' => '',
- // 'Activity until today' => '',
- // 'Search by creator: ' => '',
- // 'Search by creation date: ' => '',
- // 'Search by task status: ' => '',
- // 'Search by task title: ' => '',
- // 'Activity stream search' => '',
- // 'Projects where "%s" is manager' => '',
- // 'Projects where "%s" is member' => '',
- // 'Open tasks assigned to "%s"' => '',
- // 'Closed tasks assigned to "%s"' => '',
+ 'OS version:' => '운영체제 버전:',
+ 'Database version:' => '데이터베이스 버전:',
+ 'Browser:' => '브라우저:',
+ 'Task view' => '할일 보기',
+ 'Edit task' => '할일 수정',
+ 'Edit description' => '설명 수정',
+ 'New internal link' => '새로운 내부 링크',
+ 'Display list of keyboard shortcuts' => '키보드 숏컷 리스트 보여주기',
+ 'Menu' => '메뉴',
+ 'Set start date' => '시작일 설정',
+ 'Avatar' => '아바타',
+ 'Upload my avatar image' => '아바타 이미지 올리기',
+ 'Remove my image' => '이미지 삭제',
+ 'The OAuth2 state parameter is invalid' => 'OAuth2 상태값이 올바르지 않습니다',
+ 'User not found.' => '사용자를 찾을 수 없습니다',
+ 'Search in activity stream' => '활성 스트림 찾기',
+ 'My activities' => '나의 활동',
+ 'Activity until yesterday' => '어제까지의 활동',
+ 'Activity until today' => '오늘까지의 활동',
+ 'Search by creator: ' => '생성자로 검색: ',
+ 'Search by creation date: ' => '생성 날짜로 검색: ',
+ 'Search by task status: ' => '할일 상태로 검색: ',
+ 'Search by task title: ' => '할일 제목으로 검색: ',
+ 'Activity stream search' => '활동 스트림 검색',
+ 'Projects where "%s" is manager' => '"%s" 관리자의 프로젝트',
+ 'Projects where "%s" is member' => '"%s" 맴버의 프로젝트',
+ 'Open tasks assigned to "%s"' => '"%s"에게 할당된 할일 시작하기',
+ 'Closed tasks assigned to "%s"' => '"%s"에게 할당된 할일 종료하기',
+ 'Assign automatically a color based on a priority' => '우선순위로 색깔 자동 지정',
+ 'Overdue tasks for the project(s) "%s"' => '"%s" 프로젝트의 기한이 지난 할일',
+ 'Upload files' => '파일 올리기',
+ // 'Installed Plugins' => '',
+ // 'Plugin Directory' => '',
+ // 'Plugin installed successfully.' => '',
+ // 'Plugin updated successfully.' => '',
+ // 'Plugin removed successfully.' => '',
+ // 'Subtask converted to task successfully.' => '',
+ // 'Unable to convert the subtask.' => '',
+ // 'Unable to extract plugin archive.' => '',
+ // 'Plugin not found.' => '',
+ // 'You don\'t have the permission to remove this plugin.' => '',
+ // 'Unable to download plugin archive.' => '',
+ // 'Unable to write temporary file for plugin.' => '',
+ // 'Unable to open plugin archive.' => '',
+ // 'There is no file in the plugin archive.' => '',
+ // 'Create tasks in bulk' => '',
+ // 'Your Kanboard instance is not configured to install plugins from the user interface.' => '',
+ // 'There is no plugin available.' => '',
+ // 'Install' => '',
+ // 'Update' => '',
+ // 'Up to date' => '',
+ // 'Not available' => '',
+ // 'Remove plugin' => '',
+ // 'Do you really want to remove this plugin: "%s"?' => '',
+ // 'Uninstall' => '',
+ // 'Listing' => '',
+ // 'Metadata' => '',
+ // 'Manage projects' => '',
+ // 'Convert to task' => '',
+ // 'Convert sub-task to task' => '',
+ // 'Do you really want to convert this sub-task to a task?' => '',
+ // 'My task title' => '',
+ // 'Enter one task by line.' => '',
+ // 'Number of failed login:' => '',
+ // 'Account locked until:' => '',
);
diff --git a/app/Locale/my_MY/translations.php b/app/Locale/my_MY/translations.php
index d6109be9..2322fa03 100644
--- a/app/Locale/my_MY/translations.php
+++ b/app/Locale/my_MY/translations.php
@@ -170,7 +170,6 @@ return array(
'Leave a description' => 'Tinggalkan deskripsi',
'Comment added successfully.' => 'Komentar berhasil ditambahkan.',
'Unable to create your comment.' => 'Tidak dapat menambahkan komentar anda.',
- 'Edit this task' => 'Modifikasi tugas ini',
'Due Date' => 'Batas Tanggal Terakhir',
'Invalid date' => 'Tanggal tidak valid',
'Automatic actions' => 'Tindakan otomatis',
@@ -517,7 +516,6 @@ return array(
'All swimlanes' => 'Semua swimlane',
'All colors' => 'Semua warna',
'Moved to column %s' => 'Pindah ke kolom %s',
- 'Change description' => 'Ubah keterangan',
'User dashboard' => 'Papan Kenyataan pengguna',
'Allow only one subtask in progress at the same time for a user' => 'Izinkan hanya satu subtugas dalam proses secara bersamaan untuk satu pengguna',
'Edit column "%s"' => 'Modifikasi kolom « %s »',
@@ -709,7 +707,6 @@ return array(
'view the board on Kanboard' => 'lihat papan di Kanboard',
'The task have been moved to the first swimlane' => 'Tugas telah dipindahkan ke swimlane pertama',
'The task have been moved to another swimlane:' => 'Tugas telah dipindahkan ke swimlane lain:',
- 'Overdue tasks for the project(s) "%s"' => 'Tugas terlambat untuk projek « %s »',
'New title: %s' => 'Judul baru : %s',
'The task is not assigned anymore' => 'Tugas tidak ditugaskan lagi',
'New assignee: %s' => 'Penerima baru : %s',
@@ -738,7 +735,6 @@ return array(
'Stop timer' => 'Hentikan timer',
'Start timer' => 'Mulai timer',
'Add project member' => 'Tambahkan anggota projek',
- 'Enable notifications' => 'Aktifkan pemberitahuan',
'My activity stream' => 'Aliran kegiatan saya',
'My calendar' => 'Kalender saya',
'Search tasks' => 'Cari tugas',
@@ -1167,4 +1163,41 @@ return array(
// 'Projects where "%s" is member' => '',
// 'Open tasks assigned to "%s"' => '',
// 'Closed tasks assigned to "%s"' => '',
+ // 'Assign automatically a color based on a priority' => '',
+ 'Overdue tasks for the project(s) "%s"' => 'Tugas terlambat untuk projek « %s »',
+ // 'Upload files' => '',
+ // 'Installed Plugins' => '',
+ // 'Plugin Directory' => '',
+ // 'Plugin installed successfully.' => '',
+ // 'Plugin updated successfully.' => '',
+ // 'Plugin removed successfully.' => '',
+ // 'Subtask converted to task successfully.' => '',
+ // 'Unable to convert the subtask.' => '',
+ // 'Unable to extract plugin archive.' => '',
+ // 'Plugin not found.' => '',
+ // 'You don\'t have the permission to remove this plugin.' => '',
+ // 'Unable to download plugin archive.' => '',
+ // 'Unable to write temporary file for plugin.' => '',
+ // 'Unable to open plugin archive.' => '',
+ // 'There is no file in the plugin archive.' => '',
+ // 'Create tasks in bulk' => '',
+ // 'Your Kanboard instance is not configured to install plugins from the user interface.' => '',
+ // 'There is no plugin available.' => '',
+ // 'Install' => '',
+ // 'Update' => '',
+ // 'Up to date' => '',
+ // 'Not available' => '',
+ // 'Remove plugin' => '',
+ // 'Do you really want to remove this plugin: "%s"?' => '',
+ // 'Uninstall' => '',
+ // 'Listing' => '',
+ // 'Metadata' => '',
+ // 'Manage projects' => '',
+ // 'Convert to task' => '',
+ // 'Convert sub-task to task' => '',
+ // 'Do you really want to convert this sub-task to a task?' => '',
+ // 'My task title' => '',
+ // 'Enter one task by line.' => '',
+ // 'Number of failed login:' => '',
+ // 'Account locked until:' => '',
);
diff --git a/app/Locale/nb_NO/translations.php b/app/Locale/nb_NO/translations.php
index 4bdbc250..57fd0f70 100644
--- a/app/Locale/nb_NO/translations.php
+++ b/app/Locale/nb_NO/translations.php
@@ -170,7 +170,6 @@ return array(
'Leave a description' => 'Legg inn en beskrivelse...',
'Comment added successfully.' => 'Kommentaren er lagt til.',
'Unable to create your comment.' => 'Din kommentar kunne ikke opprettes.',
- 'Edit this task' => 'Rediger oppgaven',
'Due Date' => 'Forfallsdato',
'Invalid date' => 'Ugyldig dato',
'Automatic actions' => 'Automatiske handlinger',
@@ -517,7 +516,6 @@ return array(
'All swimlanes' => 'Alle svømmebaner',
'All colors' => 'Alle farger',
// 'Moved to column %s' => '',
- 'Change description' => 'Endre beskrivelse',
'User dashboard' => 'Brukerens hovedside',
// 'Allow only one subtask in progress at the same time for a user' => '',
// 'Edit column "%s"' => '',
@@ -709,7 +707,6 @@ return array(
// 'view the board on Kanboard' => '',
// 'The task have been moved to the first swimlane' => '',
// 'The task have been moved to another swimlane:' => '',
- // 'Overdue tasks for the project(s) "%s"' => '',
// 'New title: %s' => '',
// 'The task is not assigned anymore' => '',
// 'New assignee: %s' => '',
@@ -738,7 +735,6 @@ return array(
'Stop timer' => 'Stopp timer',
'Start timer' => 'Start timer',
'Add project member' => 'Legg til prosjektmedlem',
- 'Enable notifications' => 'Aktiver varslinger',
'My activity stream' => 'Aktivitetslogg',
'My calendar' => 'Min kalender',
'Search tasks' => 'Søk oppgave',
@@ -1167,4 +1163,41 @@ return array(
// 'Projects where "%s" is member' => '',
// 'Open tasks assigned to "%s"' => '',
// 'Closed tasks assigned to "%s"' => '',
+ // 'Assign automatically a color based on a priority' => '',
+ // 'Overdue tasks for the project(s) "%s"' => '',
+ // 'Upload files' => '',
+ // 'Installed Plugins' => '',
+ // 'Plugin Directory' => '',
+ // 'Plugin installed successfully.' => '',
+ // 'Plugin updated successfully.' => '',
+ // 'Plugin removed successfully.' => '',
+ // 'Subtask converted to task successfully.' => '',
+ // 'Unable to convert the subtask.' => '',
+ // 'Unable to extract plugin archive.' => '',
+ // 'Plugin not found.' => '',
+ // 'You don\'t have the permission to remove this plugin.' => '',
+ // 'Unable to download plugin archive.' => '',
+ // 'Unable to write temporary file for plugin.' => '',
+ // 'Unable to open plugin archive.' => '',
+ // 'There is no file in the plugin archive.' => '',
+ // 'Create tasks in bulk' => '',
+ // 'Your Kanboard instance is not configured to install plugins from the user interface.' => '',
+ // 'There is no plugin available.' => '',
+ // 'Install' => '',
+ // 'Update' => '',
+ // 'Up to date' => '',
+ // 'Not available' => '',
+ // 'Remove plugin' => '',
+ // 'Do you really want to remove this plugin: "%s"?' => '',
+ // 'Uninstall' => '',
+ // 'Listing' => '',
+ // 'Metadata' => '',
+ // 'Manage projects' => '',
+ // 'Convert to task' => '',
+ // 'Convert sub-task to task' => '',
+ // 'Do you really want to convert this sub-task to a task?' => '',
+ // 'My task title' => '',
+ // 'Enter one task by line.' => '',
+ // 'Number of failed login:' => '',
+ // 'Account locked until:' => '',
);
diff --git a/app/Locale/nl_NL/translations.php b/app/Locale/nl_NL/translations.php
index 0cf8ae6d..37192081 100644
--- a/app/Locale/nl_NL/translations.php
+++ b/app/Locale/nl_NL/translations.php
@@ -170,7 +170,6 @@ return array(
'Leave a description' => 'Schrijf een omschrijving',
'Comment added successfully.' => 'Commentaar succesvol toegevoegd.',
'Unable to create your comment.' => 'Commentaar toevoegen niet gelukt.',
- 'Edit this task' => 'Deze taak aanpassen',
'Due Date' => 'Vervaldag',
'Invalid date' => 'Ongeldige datum',
'Automatic actions' => 'Geautomatiseerd acties',
@@ -517,7 +516,6 @@ return array(
'All swimlanes' => 'Alle swimlanes',
'All colors' => 'Alle kleuren',
'Moved to column %s' => 'Verplaatst naar kolom %s',
- 'Change description' => 'Verandering omschrijving',
'User dashboard' => 'Gebruiker dashboard',
'Allow only one subtask in progress at the same time for a user' => 'Sta maximaal één subtaak in behandeling toe per gebruiker',
'Edit column "%s"' => 'Kolom « %s » aanpassen',
@@ -709,7 +707,6 @@ return array(
// 'view the board on Kanboard' => '',
// 'The task have been moved to the first swimlane' => '',
// 'The task have been moved to another swimlane:' => '',
- // 'Overdue tasks for the project(s) "%s"' => '',
'New title: %s' => 'Nieuw titel: %s',
// 'The task is not assigned anymore' => '',
// 'New assignee: %s' => '',
@@ -738,7 +735,6 @@ return array(
'Stop timer' => 'Stop timer',
'Start timer' => 'Start timer',
'Add project member' => 'Voeg projectlid toe',
- 'Enable notifications' => 'Schakel notificaties in',
'My activity stream' => 'Mijn activiteiten',
'My calendar' => 'Mijn kalender',
'Search tasks' => 'Zoek taken',
@@ -1167,4 +1163,41 @@ return array(
// 'Projects where "%s" is member' => '',
// 'Open tasks assigned to "%s"' => '',
// 'Closed tasks assigned to "%s"' => '',
+ // 'Assign automatically a color based on a priority' => '',
+ // 'Overdue tasks for the project(s) "%s"' => '',
+ // 'Upload files' => '',
+ // 'Installed Plugins' => '',
+ // 'Plugin Directory' => '',
+ // 'Plugin installed successfully.' => '',
+ // 'Plugin updated successfully.' => '',
+ // 'Plugin removed successfully.' => '',
+ // 'Subtask converted to task successfully.' => '',
+ // 'Unable to convert the subtask.' => '',
+ // 'Unable to extract plugin archive.' => '',
+ // 'Plugin not found.' => '',
+ // 'You don\'t have the permission to remove this plugin.' => '',
+ // 'Unable to download plugin archive.' => '',
+ // 'Unable to write temporary file for plugin.' => '',
+ // 'Unable to open plugin archive.' => '',
+ // 'There is no file in the plugin archive.' => '',
+ // 'Create tasks in bulk' => '',
+ // 'Your Kanboard instance is not configured to install plugins from the user interface.' => '',
+ // 'There is no plugin available.' => '',
+ // 'Install' => '',
+ // 'Update' => '',
+ // 'Up to date' => '',
+ // 'Not available' => '',
+ // 'Remove plugin' => '',
+ // 'Do you really want to remove this plugin: "%s"?' => '',
+ // 'Uninstall' => '',
+ // 'Listing' => '',
+ // 'Metadata' => '',
+ // 'Manage projects' => '',
+ // 'Convert to task' => '',
+ // 'Convert sub-task to task' => '',
+ // 'Do you really want to convert this sub-task to a task?' => '',
+ // 'My task title' => '',
+ // 'Enter one task by line.' => '',
+ // 'Number of failed login:' => '',
+ // 'Account locked until:' => '',
);
diff --git a/app/Locale/pl_PL/translations.php b/app/Locale/pl_PL/translations.php
index 4aab974d..00b57db8 100644
--- a/app/Locale/pl_PL/translations.php
+++ b/app/Locale/pl_PL/translations.php
@@ -170,7 +170,6 @@ return array(
'Leave a description' => 'Dodaj opis',
'Comment added successfully.' => 'Komentarz dodany',
'Unable to create your comment.' => 'Nie udało się dodać komentarza',
- 'Edit this task' => 'Edytuj zadanie',
'Due Date' => 'Termin',
'Invalid date' => 'Błędna data',
'Automatic actions' => 'Akcje automatyczne',
@@ -192,7 +191,7 @@ return array(
'Do you really want to remove this action: "%s"?' => 'Na pewno chcesz usunąć akcję "%s"?',
'Remove an automatic action' => 'Usuń akcję automatyczną',
'Assign the task to a specific user' => 'Przypisz zadanie do wybranego użytkownika',
- 'Assign the task to the person who does the action' => 'Przypisz zadanie to osoby wykonującej akcję',
+ 'Assign the task to the person who does the action' => 'Przypisz zadanie do osoby wykonującej akcję',
'Duplicate the task to another project' => 'Kopiuj zadanie do innego projektu',
'Move a task to another column' => 'Przeniesienie zadania do innej kolumny',
'Task modification' => 'Modyfikacja zadania',
@@ -216,7 +215,7 @@ return array(
'Unknown' => 'Nieznany',
'Last logins' => 'Ostatnie logowania',
'Login date' => 'Data logowania',
- 'Authentication method' => 'Sposób autentykacji',
+ 'Authentication method' => 'Sposób uwierzytelnienia',
'IP address' => 'Adres IP',
'User agent' => 'Przeglądarka',
'Persistent connections' => 'Stałe połączenia',
@@ -235,10 +234,10 @@ return array(
'%d comments' => '%d Komentarzy',
'%d comment' => '%d Komentarz',
'Email address invalid' => 'Błędny adres email',
- // 'Your external account is not linked anymore to your profile.' => '',
- // 'Unable to unlink your external account.' => '',
- // 'External authentication failed' => '',
- // 'Your external account is linked to your profile successfully.' => '',
+ 'Your external account is not linked anymore to your profile.' => 'Twoje zewnętrzne konto nie jest już połączone z profilem',
+ 'Unable to unlink your external account.' => 'Nie można odłączyć zewnętrznego konta',
+ 'External authentication failed' => 'Uwierzytelnianie zewnętrzne zakończyło się niepowodzeniem',
+ 'Your external account is linked to your profile successfully.' => 'Twoje zewnętrzne konto zostało pomyślnie połączone z profilem',
'Email' => 'Email',
'Task removed successfully.' => 'Zadanie usunięto pomyślnie.',
'Unable to remove this task.' => 'Nie można usunąć tego zadania.',
@@ -284,21 +283,21 @@ return array(
'hours' => 'godzin(y)',
'spent' => 'przeznaczono',
'estimated' => 'szacowany',
- 'Sub-Tasks' => 'Podzadania',
- 'Add a sub-task' => 'Dodaj podzadanie',
+ 'Sub-Tasks' => 'Pod-zadania',
+ 'Add a sub-task' => 'Dodaj pod-zadanie',
'Original estimate' => 'Szacowanie początkowe',
'Create another sub-task' => 'Dodaj kolejne pod-zadanie',
- 'Time spent' => 'Przeznaczony czas',
+ 'Time spent' => 'Spędzony czas',
'Edit a sub-task' => 'Edytuj pod-zadanie',
'Remove a sub-task' => 'Usuń pod-zadanie',
'The time must be a numeric value' => 'Czas musi być wartością liczbową',
'Todo' => 'Do zrobienia',
'In progress' => 'W trakcie',
'Sub-task removed successfully.' => 'Pod-zadanie usunięte pomyślnie.',
- 'Unable to remove this sub-task.' => 'Nie można usunąć tego podzadania.',
+ 'Unable to remove this sub-task.' => 'Nie można usunąć tego pod-zadania.',
'Sub-task updated successfully.' => 'Pod-zadanie zaktualizowane pomyślnie.',
- 'Unable to update your sub-task.' => 'Nie można zaktualizować tego podzadania.',
- 'Unable to create your sub-task.' => 'Nie można utworzyć tego podzadania.',
+ 'Unable to update your sub-task.' => 'Nie można zaktualizować tego pod-zadania.',
+ 'Unable to create your sub-task.' => 'Nie można utworzyć tego pod-zadania.',
'Sub-task added successfully.' => 'Pod-zadanie utworzone pomyślnie',
'Maximum size: ' => 'Maksymalny rozmiar: ',
'Unable to upload the file.' => 'Nie można wczytać pliku.',
@@ -343,9 +342,9 @@ return array(
'Disable public access' => 'Zablokuj dostęp publiczny',
'Enable public access' => 'Odblokuj dostęp publiczny',
'Public access disabled' => 'Dostęp publiczny zablokowany',
- 'Do you really want to disable this project: "%s"?' => 'Czy na pewno chcesz zablokować projekt: "%s"?',
- 'Do you really want to enable this project: "%s"?' => 'Czy na pewno chcesz odblokować projekt: "%s"?',
- 'Project activation' => 'Aktywacja projekt',
+ 'Do you really want to disable this project: "%s"?' => 'Czy na pewno chcesz wyłączyć projekt: "%s"?',
+ 'Do you really want to enable this project: "%s"?' => 'Czy na pewno chcesz włączyć projekt: "%s"?',
+ 'Project activation' => 'Aktywacja projektu',
'Move the task to another project' => 'Przenieś zadanie do innego projektu',
'Move to another project' => 'Przenieś do innego projektu',
'Do you really want to duplicate this task?' => 'Czy na pewno chcesz zduplikować to zadanie?',
@@ -365,9 +364,9 @@ return array(
'Edit profile' => 'Edytuj profil',
'Change password' => 'Zmień hasło',
'Password modification' => 'Zmiana hasła',
- 'External authentications' => 'Autentykacja zewnętrzna',
+ 'External authentications' => 'Uwierzytelnienia zewnętrzne',
'Never connected.' => 'Nigdy nie połączone.',
- 'No external authentication enabled.' => 'Brak autentykacji zewnętrznych.',
+ 'No external authentication enabled.' => 'Brak włączonych uwierzytelnień zewnętrznych.',
'Password modified successfully.' => 'Hasło zmienione pomyślne.',
'Unable to change the password.' => 'Nie można zmienić hasła.',
'Change category for the task "%s"' => 'Zmień kategorię dla zadania "%s"',
@@ -378,8 +377,8 @@ return array(
'%s moved the task %s to the column "%s"' => '%s przeniósł zadanie %s do kolumny "%s"',
'%s created the task %s' => '%s utworzył zadanie %s',
'%s closed the task %s' => '%s zamknął zadanie %s',
- '%s created a subtask for the task %s' => '%s utworzył podzadanie dla zadania %s',
- '%s updated a subtask for the task %s' => '%s zaktualizował podzadanie dla zadania %s',
+ '%s created a subtask for the task %s' => '%s utworzył pod-zadanie dla zadania %s',
+ '%s updated a subtask for the task %s' => '%s zaktualizował pod-zadanie dla zadania %s',
'Assigned to %s with an estimate of %s/%sh' => 'Przypisano do %s z szacowanym czasem wykonania %s/%sh',
'Not assigned, estimate of %sh' => 'Nie przypisane, szacowany czas wykonania %sh',
'%s updated a comment on the task %s' => '%s zaktualizował komentarz do zadania %s',
@@ -388,8 +387,8 @@ return array(
'RSS feed' => 'Kanał RSS',
'%s updated a comment on the task #%d' => '%s zaktualizował komentarz do zadania #%d',
'%s commented on the task #%d' => '%s skomentował zadanie #%d',
- '%s updated a subtask for the task #%d' => '%s zaktualizował podzadanie dla zadania #%d',
- '%s created a subtask for the task #%d' => '%s utworzył podzadanie dla zadania #%d',
+ '%s updated a subtask for the task #%d' => '%s zaktualizował pod-zadanie dla zadania #%d',
+ '%s created a subtask for the task #%d' => '%s utworzył pod-zadanie dla zadania #%d',
'%s updated the task #%d' => '%s zaktualizował zadanie #%d',
'%s created the task #%d' => '%s utworzył zadanie #%d',
'%s closed the task #%d' => '%s zamknął zadanie #%d',
@@ -414,10 +413,10 @@ return array(
'Database driver:' => 'Silnik bazy danych:',
'Board settings' => 'Ustawienia tablicy',
'URL and token' => 'URL i token',
- // 'Webhook settings' => '',
+ 'Webhook settings' => 'Ustawienia webhook',
'URL for task creation:' => 'URL do tworzenia zadań',
'Reset token' => 'Resetuj token',
- // 'API endpoint:' => '',
+ 'API endpoint:' => 'Endpoint API',
'Refresh interval for private board' => 'Częstotliwość odświeżania dla tablicy prywatnej',
'Refresh interval for public board' => 'Częstotliwość odświeżania dla tablicy publicznej',
'Task highlight period' => 'Okres wyróżniania zadań',
@@ -440,7 +439,7 @@ return array(
'Confirmation' => 'Potwierdzenie',
'Allow everybody to access to this project' => 'Udostępnij ten projekt wszystkim',
'Everybody have access to this project.' => 'Wszyscy mają dostęp do tego projektu.',
- // 'Webhooks' => '',
+ 'Webhooks' => 'Webhooki',
// 'API' => '',
'Create a comment from an external provider' => 'Utwórz komentarz od zewnętrznego dostawcy',
'Project management' => 'Menadżer projektu',
@@ -454,8 +453,8 @@ return array(
'Reportings' => 'Raporty',
'Task repartition for "%s"' => 'Przydział zadań dla "%s"',
'Analytics' => 'Analizy',
- 'Subtask' => 'Podzadanie',
- 'My subtasks' => 'Moje podzadania',
+ 'Subtask' => 'Pod-zadanie',
+ 'My subtasks' => 'Moje pod-zadania',
'User repartition' => 'Przydział użytkownika',
'User repartition for "%s"' => 'Przydział użytkownika dla "%s"',
'Clone this project' => 'Sklonuj ten projekt',
@@ -466,7 +465,7 @@ return array(
'The project id must be an integer' => 'ID projektu musi być liczbą całkowitą',
'The status must be an integer' => 'Status musi być liczbą całkowitą',
'The subtask id is required' => 'ID pod-zadanie jest wymagane',
- 'The subtask id must be an integer' => 'ID podzadania musi być liczbą całkowitą',
+ 'The subtask id must be an integer' => 'ID pod-zadania musi być liczbą całkowitą',
'The task id is required' => 'ID zadania jest wymagane',
'The task id must be an integer' => 'ID zadania musi być liczbą całkowitą',
'The user id must be an integer' => 'ID użytkownika musi być liczbą całkowitą',
@@ -480,31 +479,31 @@ return array(
'Daily project summary export for "%s"' => 'Wygeneruj dzienny raport dla projektu: "%s"',
'Exports' => 'Eksporty',
'This export contains the number of tasks per column grouped per day.' => 'Ten eksport zawiera ilość zadań zgrupowanych w kolumnach na dzień',
- 'Active swimlanes' => 'Aktywne procesy',
- 'Add a new swimlane' => 'Dodaj proces',
- 'Change default swimlane' => 'Zmień domyślny proces',
- 'Default swimlane' => 'Domyślny proces',
- 'Do you really want to remove this swimlane: "%s"?' => 'Czy na pewno chcesz usunąć proces: "%s"?',
- 'Inactive swimlanes' => 'Nieaktywne procesy',
- 'Remove a swimlane' => 'Usuń proces',
- 'Show default swimlane' => 'Pokaż domyślny proces',
- 'Swimlane modification for the project "%s"' => 'Edycja procesów dla projektu "%s"',
- 'Swimlane not found.' => 'Nie znaleziono procesu.',
- 'Swimlane removed successfully.' => 'Proces usunięty pomyślnie.',
- 'Swimlanes' => 'Procesy',
- 'Swimlane updated successfully.' => 'Proces zaktualizowany pomyślnie.',
- 'The default swimlane have been updated successfully.' => 'Domyślny proces zaktualizowany pomyślnie.',
- 'Unable to remove this swimlane.' => 'Nie można usunąć procesu.',
- 'Unable to update this swimlane.' => 'Nie można zaktualizować procesu.',
- 'Your swimlane have been created successfully.' => 'Proces tworzony pomyślnie.',
+ 'Active swimlanes' => 'Aktywne tory',
+ 'Add a new swimlane' => 'Dodaj tor',
+ 'Change default swimlane' => 'Zmień domyślny tor',
+ 'Default swimlane' => 'Domyślny tor',
+ 'Do you really want to remove this swimlane: "%s"?' => 'Czy na pewno chcesz usunąć tor: "%s"?',
+ 'Inactive swimlanes' => 'Nieaktywne tory',
+ 'Remove a swimlane' => 'Usuń tor',
+ 'Show default swimlane' => 'Pokaż domyślny tor',
+ 'Swimlane modification for the project "%s"' => 'Edycja torów dla projektu "%s"',
+ 'Swimlane not found.' => 'Nie znaleziono toru.',
+ 'Swimlane removed successfully.' => 'Tor usunięty pomyślnie.',
+ 'Swimlanes' => 'Tory',
+ 'Swimlane updated successfully.' => 'Zaktualizowano tor.',
+ 'The default swimlane have been updated successfully.' => 'Domyślny tor zaktualizowany pomyślnie.',
+ 'Unable to remove this swimlane.' => 'Nie można usunąć toru.',
+ 'Unable to update this swimlane.' => 'Nie można zaktualizować toru.',
+ 'Your swimlane have been created successfully.' => 'Tor utworzony pomyślnie.',
'Example: "Bug, Feature Request, Improvement"' => 'Przykład: "Błąd, Żądanie Funkcjonalności, Udoskonalenia"',
'Default categories for new projects (Comma-separated)' => 'Domyślne kategorie dla nowych projektów (oddzielone przecinkiem)',
'Integrations' => 'Integracje',
'Integration with third-party services' => 'Integracja z usługami firm trzecich',
'Subtask Id' => 'ID pod-zadania',
- 'Subtasks' => 'Podzadania',
- 'Subtasks Export' => 'Eksport podzadań',
- 'Subtasks exportation for "%s"' => 'Wygeneruj raport podzadań dla projektu "%s"',
+ 'Subtasks' => 'Pod-zadania',
+ 'Subtasks Export' => 'Eksport pod-zadań',
+ 'Subtasks exportation for "%s"' => 'Wygeneruj raport pod-zadań dla projektu "%s"',
'Task Title' => 'Nazwa zadania',
'Untitled' => 'Bez nazwy',
'Application default' => 'Domyślne dla aplikacji',
@@ -514,10 +513,9 @@ return array(
'Calendar' => 'Kalendarz',
'Next' => 'Następny',
'#%d' => 'nr %d',
- 'All swimlanes' => 'Wszystkie procesy',
+ 'All swimlanes' => 'Wszystkie tory',
'All colors' => 'Wszystkie kolory',
'Moved to column %s' => 'Przeniosiono do kolumny %s',
- 'Change description' => 'Zmień opis',
'User dashboard' => 'Panel użytkownika',
'Allow only one subtask in progress at the same time for a user' => 'Zezwalaj na tylko jedno pod-zadanie o statusie "w trakcie" jednocześnie',
'Edit column "%s"' => 'Zmień kolumnę "%s"',
@@ -611,15 +609,15 @@ return array(
'Reference currency' => 'Waluta referencyjna',
'The currency rate have been added successfully.' => 'Dodano kurs waluty',
'Unable to add this currency rate.' => 'Nie można dodać kursu waluty',
- // 'Webhook URL' => '',
+ 'Webhook URL' => 'Adres webhooka',
'%s remove the assignee of the task %s' => '%s usunął osobę przypisaną do zadania %s',
- // 'Enable Gravatar images' => '',
+ 'Enable Gravatar images' => 'Włącz Gravatar',
'Information' => 'Informacje',
'Check two factor authentication code' => 'Sprawdź kod weryfikujący',
'The two factor authentication code is not valid.' => 'Kod weryfikujący niepoprawny',
'The two factor authentication code is valid.' => 'Kod weryfikujący poprawny',
'Code' => 'Kod',
- 'Two factor authentication' => 'Uwierzytelnianie dwustopniowe',
+ 'Two factor authentication' => 'Dwustopniowe uwierzytelnianie',
'This QR code contains the key URI: ' => 'Ten kod QR zawiera URI klucza: ',
'Check my code' => 'Sprawdź kod',
'Secret key: ' => 'Tajny kod: ',
@@ -628,15 +626,15 @@ return array(
'%s via Kanboard' => '%s poprzez Kanboard',
'Burndown chart for "%s"' => 'Wykres Burndown dla "%s"',
'Burndown chart' => 'Wykres Burndown',
- // 'This chart show the task complexity over the time (Work Remaining).' => '',
+ 'This chart show the task complexity over the time (Work Remaining).' => 'Ten wykres pokazuje złożoność zadania na przestrzeni czasu (pozostała praca).',
'Screenshot taken %s' => 'Zrzut ekranu zapisany %s',
'Add a screenshot' => 'Dołącz zrzut ekranu',
'Take a screenshot and press CTRL+V or ⌘+V to paste here.' => 'Zrób zrzut ekranu i wciśnij CTRL+V by dodać go tutaj.',
'Screenshot uploaded successfully.' => 'Zrzut ekranu dodany.',
'SEK - Swedish Krona' => 'SEK - Korona szwedzka',
'Identifier' => 'Identyfikator',
- 'Disable two factor authentication' => 'Wyłącz uwierzytelnianie dwuetapowe',
- 'Do you really want to disable the two factor authentication for this user: "%s"?' => 'Czy na pewno chcesz wyłączyć uwierzytelnianie dwuetapowe dla tego użytkownika: "%s"?',
+ 'Disable two factor authentication' => 'Wyłącz dwustopniowe uwierzytelnianie',
+ 'Do you really want to disable the two factor authentication for this user: "%s"?' => 'Czy na pewno chcesz wyłączyć dwustopniowe uwierzytelnianie dla tego użytkownika: "%s"?',
'Edit link' => 'Edytuj link',
'Start to type task title...' => 'Rozpocznij wpisywanie tytułu zadania...',
'A task cannot be linked to itself' => 'Link do zadania nie może wskazywać na samego siebie',
@@ -646,7 +644,7 @@ return array(
'The identifier must be unique' => 'Identyfikator musi być unikatowy',
'This linked task id doesn\'t exists' => 'Id zadania nie istnieje',
'This value must be alphanumeric' => 'Ta wartość musi być alfanumeryczna',
- 'Edit recurrence' => 'Rekurencja',
+ 'Edit recurrence' => 'Edytuj rekurencje',
'Generate recurrent task' => 'Włącz rekurencje',
'Trigger to generate recurrent task' => 'Wyzwalacz tworzący zadanie cykliczne',
'Factor to calculate new due date' => 'Czynnik wyliczający nowy termin',
@@ -671,7 +669,7 @@ return array(
'Calendar settings' => 'Ustawienia kalendarza',
'Project calendar view' => 'Widok kalendarza projektu',
'Project settings' => 'Ustawienia Projektu',
- 'Show subtasks based on the time tracking' => 'Pokaż podzadania w śledzeniu czasu',
+ 'Show subtasks based on the time tracking' => 'Pokaż pod-zadania w śledzeniu czasu',
'Show tasks based on the creation date' => 'Pokaż zadania względem daty utworzenia',
'Show tasks based on the start date' => 'Pokaż zadania względem daty rozpoczęcia',
'Subtasks time tracking' => 'Śledzenie czasu pod-zadań',
@@ -680,65 +678,63 @@ return array(
// 'iCal feed' => '',
'Preferences' => 'Ustawienia',
'Security' => 'Zabezpieczenia',
- 'Two factor authentication disabled' => 'Uwierzytelnianie dwuetapowe wyłączone',
- 'Two factor authentication enabled' => 'Uwierzytelnianie dwuetapowe włączone',
+ 'Two factor authentication disabled' => 'Dwustopniowe uwierzytelnianie wyłączone',
+ 'Two factor authentication enabled' => 'Dwustopniowe uwierzytelnianie włączone',
'Unable to update this user.' => 'Nie można zaktualizować tego użytkownika',
'There is no user management for private projects.' => 'Projekty prywatne nie wspierają zarządzania użytkownikami. Projekt prywatny ma tylko jednego użytkownika.',
- // 'User that will receive the email' => '',
- // 'Email subject' => '',
+ 'User that will receive the email' => 'Adresat',
+ 'Email subject' => 'Temat',
'Date' => 'Data',
- // 'Add a comment log when moving the task between columns' => '',
- // 'Move the task to another column when the category is changed' => '',
- 'Send a task by email to someone' => 'Wyślij zadanie mailem do kogokolwiek',
+ 'Add a comment log when moving the task between columns' => 'Wygeneruj komentarz pod zadaniem podczas przenoszenia między kolumnami',
+ 'Move the task to another column when the category is changed' => 'Przenieś zadanie do innej kolumny gdy kategoria ulegnie zmianie',
+ 'Send a task by email to someone' => 'Wyślij zadanie emailem do kogoś',
'Reopen a task' => 'Otwórz ponownie zadanie',
'Column change' => 'Zmiana kolumny',
'Position change' => 'Zmiana pozycji',
- 'Swimlane change' => 'Zmiana Swimlane',
+ 'Swimlane change' => 'Zmiana toru',
'Assignee change' => 'Zmiana przypisanego użytkownika',
- // '[%s] Overdue tasks' => '',
+ '[%s] Overdue tasks' => '[%s] zaległych zadań',
'Notification' => 'Powiadomienie',
- // '%s moved the task #%d to the first swimlane' => '',
- // '%s moved the task #%d to the swimlane "%s"' => '',
- 'Swimlane' => 'Proces',
+ '%s moved the task #%d to the first swimlane' => '%s przeniosł zadanie #%d na pierwszy tor',
+ '%s moved the task #%d to the swimlane "%s"' => '%s przeniosł zadanie #%d na tor "%s"',
+ 'Swimlane' => 'Tor',
// 'Gravatar' => '',
- // '%s moved the task %s to the first swimlane' => '',
- // '%s moved the task %s to the swimlane "%s"' => '',
- // 'This report contains all subtasks information for the given date range.' => '',
- // 'This report contains all tasks information for the given date range.' => '',
- // 'Project activities for %s' => '',
- // 'view the board on Kanboard' => '',
- // 'The task have been moved to the first swimlane' => '',
- // 'The task have been moved to another swimlane:' => '',
- // 'Overdue tasks for the project(s) "%s"' => '',
+ '%s moved the task %s to the first swimlane' => '%s przeniosł zadanie %s na pierwszy tor',
+ '%s moved the task %s to the swimlane "%s"' => '%s przeniosł zadanie %s na tor "%s"',
+ 'This report contains all subtasks information for the given date range.' => 'Niniejszy raport zawiera wszystkie informacje o pod-zadaniach dla podanego zakresu dat.',
+ 'This report contains all tasks information for the given date range.' => 'Niniejszy raport zawiera wszystkie informacje o zadaniach dla podanego zakresu dat.',
+ 'Project activities for %s' => 'Aktywności w ramach projektu dla %s',
+ 'view the board on Kanboard' => 'Zobacz tablice',
+ 'The task have been moved to the first swimlane' => 'Zadanie zostało przeniesione do piewszego toru',
+ 'The task have been moved to another swimlane:' => 'Zadanie zostało przeniesione do innego toru:',
'New title: %s' => 'Nowy tytuł: %s',
'The task is not assigned anymore' => 'Brak osoby odpowiedzialnej za zadanie',
'New assignee: %s' => 'Nowy odpowiedzialny: %s',
'There is no category now' => 'Aktualnie zadanie nie posiada kategorii',
'New category: %s' => 'Nowa kategoria: %s',
'New color: %s' => 'Nowy kolor: %s',
- // 'New complexity: %d' => '',
- // 'The due date have been removed' => '',
- // 'There is no description anymore' => '',
- // 'Recurrence settings have been modified' => '',
- // 'Time spent changed: %sh' => '',
- // 'Time estimated changed: %sh' => '',
- // 'The field "%s" have been updated' => '',
- // 'The description has been modified:' => '',
- // 'Do you really want to close the task "%s" as well as all subtasks?' => '',
+ 'New complexity: %d' => 'Nowa złożoność: %d',
+ 'The due date have been removed' => 'Termin został usunięty',
+ 'There is no description anymore' => 'Nie ma już opisu',
+ 'Recurrence settings have been modified' => 'Ustawienia cyklu zostały zmienione',
+ 'Time spent changed: %sh' => 'Spędzony czas uległ zmianie: %sh',
+ 'Time estimated changed: %sh' => 'Szacowany czas uległ zmianie: %sh',
+ 'The field "%s" have been updated' => 'Pole "%s" zostało zaktualizowane',
+ 'The description has been modified:' => 'Opis został zmodyfikowany:',
+ 'Do you really want to close the task "%s" as well as all subtasks?' => 'Naprawdę chcesz zamknąć zadanie "%s" wraz z wszystkimi pod-zadaniami?',
'I want to receive notifications for:' => 'Wysyłaj powiadomienia dla:',
'All tasks' => 'Wszystkich zadań',
'Only for tasks assigned to me' => 'Tylko zadań przypisanych do mnie',
'Only for tasks created by me' => 'Tylko zadań utworzonych przeze mnie',
'Only for tasks created by me and assigned to me' => 'Tylko zadań przypisanych lub utworzonych przeze mnie',
// '%%Y-%%m-%%d' => '',
- // 'Total for all columns' => '',
- // 'You need at least 2 days of data to show the chart.' => '',
+ 'Total for all columns' => 'Ogółem dla wszystkich kolumn',
+ 'You need at least 2 days of data to show the chart.' => 'Potrzebujesz przynajmniej 2 dni by wyświetlić wykres',
// '<15m' => '',
// '<30m' => '',
'Stop timer' => 'Zatrzymaj pomiar czasu',
'Start timer' => 'Uruchom pomiar czasu',
- 'Add project member' => 'Dodaj członka projektu',
- 'Enable notifications' => 'Włącz powiadomienia',
+ 'Add project member' => 'Dodaj uczestnika projektu',
'My activity stream' => 'Moja aktywność',
'My calendar' => 'Mój kalendarz',
'Search tasks' => 'Szukaj zadań',
@@ -771,42 +767,42 @@ return array(
'Search by category: ' => 'Szukaj wg kategorii:',
'Search by description: ' => 'Szukaj wg opisu:',
'Search by due date: ' => 'Szukaj wg terminu:',
- // 'Lead and Cycle time for "%s"' => '',
- // 'Average time spent into each column for "%s"' => '',
- // 'Average time spent into each column' => '',
- // 'Average time spent' => '',
- // 'This chart show the average time spent into each column for the last %d tasks.' => '',
- // 'Average Lead and Cycle time' => '',
- // 'Average lead time: ' => '',
- // 'Average cycle time: ' => '',
- // 'Cycle Time' => '',
- // 'Lead Time' => '',
- // 'This chart show the average lead and cycle time for the last %d tasks over the time.' => '',
- // 'Average time into each column' => '',
- // 'Lead and cycle time' => '',
- // 'Lead time: ' => '',
- // 'Cycle time: ' => '',
+ 'Lead and Cycle time for "%s"' => 'Czas cyklu i realizacji dla "%s"',
+ 'Average time spent into each column for "%s"' => 'Średni czas spędzony w każdej z kolumn dla "%s"',
+ 'Average time spent into each column' => 'Średni czas spędzony w każdej z kolumn',
+ 'Average time spent' => 'Średni spędzony czas',
+ 'This chart show the average time spent into each column for the last %d tasks.' => 'Niniejszy wykres pokazuje średni czas spędzony w każdej z kolumn dla ostatnich %d zadań.',
+ 'Average Lead and Cycle time' => 'Średni czas cyklu i realizacji',
+ 'Average lead time: ' => 'Średni czas realizacji:',
+ 'Average cycle time: ' => 'Średni czas cyklu:',
+ 'Cycle Time' => 'Czas cyklu',
+ 'Lead Time' => 'Czas realizacji',
+ 'This chart show the average lead and cycle time for the last %d tasks over the time.' => 'Niniejszy wykres pokazuje średni czas cyklu i realizacji dla ostatnich %d zadań na przestrzeni czasu.',
+ 'Average time into each column' => 'Średni czas dla każdej kolumny',
+ 'Lead and cycle time' => 'Czas cyklu i realizacji',
+ 'Lead time: ' => 'Czas realizacji:',
+ 'Cycle time: ' => 'Czas cyklu:',
'Time spent into each column' => 'Czas spędzony przez zadanie w każdej z kolumn',
- // 'The lead time is the duration between the task creation and the completion.' => '',
- // 'The cycle time is the duration between the start date and the completion.' => '',
- // 'If the task is not closed the current time is used instead of the completion date.' => '',
- // 'Set automatically the start date' => '',
- 'Edit Authentication' => 'Edycja autoryzacji',
- // 'Remote user' => '',
- // 'Remote users do not store their password in Kanboard database, examples: LDAP, Google and Github accounts.' => '',
- // 'If you check the box "Disallow login form", credentials entered in the login form will be ignored.' => '',
+ 'The lead time is the duration between the task creation and the completion.' => 'Czas realizacji pomiędzy utworzeniem a ukończeniem zadania.',
+ 'The cycle time is the duration between the start date and the completion.' => 'Czas cyklu pomiędzy datą rozpoczęcia a ukończeniem zadania.',
+ 'If the task is not closed the current time is used instead of the completion date.' => 'Jeśli zadanie nie jest zamknięte, bieżący czas zostaje użyty zamiast daty ukończenia.',
+ 'Set automatically the start date' => 'Ustaw automatycznie datę rozpoczęcia',
+ 'Edit Authentication' => 'Edycja uwierzytelnienia',
+ 'Remote user' => 'Zdalny użytkownik',
+ 'Remote users do not store their password in Kanboard database, examples: LDAP, Google and Github accounts.' => 'Zdalni użykownicy nie przechowują swojego hasła w bazie danych Kanboard, przykłady: konta LDAP, Google and Github.',
+ 'If you check the box "Disallow login form", credentials entered in the login form will be ignored.' => 'Jeśli zaznaczysz "Zablokuj możliwość logowania", dane podane przy logowaniu zostaną zignorowane.',
'New remote user' => 'Nowy użytkownik zdalny',
'New local user' => 'Nowy użytkownik lokalny',
'Default task color' => 'Domyślny kolor zadań',
- 'This feature does not work with all browsers.' => 'Ta funkcja może nie działać z każdą przeglądarką',
- // 'There is no destination project available.' => '',
- // 'Trigger automatically subtask time tracking' => '',
- // 'Include closed tasks in the cumulative flow diagram' => '',
- 'Current swimlane: %s' => 'Bieżący swimlane: %s',
+ 'This feature does not work with all browsers.' => 'Ta funkcja może nie działać z każdą przeglądarką.',
+ 'There is no destination project available.' => 'Żaden docelowy projekt nie jest aktualnie dostępny.',
+ 'Trigger automatically subtask time tracking' => 'Ustaw automatyczne śledzenie czasu dla pod-zadań',
+ 'Include closed tasks in the cumulative flow diagram' => 'Obejmuj zamknięte zadania w zbiorczym diagramie przepływu',
+ 'Current swimlane: %s' => 'Bieżący tor: %s',
'Current column: %s' => 'Bieżąca kolumna: %s',
'Current category: %s' => 'Bieżąca kategoria: %s',
'no category' => 'brak kategorii',
- // 'Current assignee: %s' => '',
+ 'Current assignee: %s' => 'Aktualnie odpowiedzialna osoba: %s',
'not assigned' => 'Brak osoby odpowiedzialnej',
'Author:' => 'Autor',
'contributors' => 'współautorzy',
@@ -820,18 +816,18 @@ return array(
'Start date:' => 'Data rozpoczęcia:',
'Due date:' => 'Termin',
'There is no start date or due date for this task.' => 'Brak daty rozpoczęcia lub terminu zadania',
- // 'Moving or resizing a task will change the start and due date of the task.' => '',
- // 'There is no task in your project.' => '',
+ 'Moving or resizing a task will change the start and due date of the task.' => 'Przeniesienie bądź edycja zmieni datę rozpoczęcia oraz termin ukończenia zadania.',
+ 'There is no task in your project.' => 'Brak zadań w projekcie.',
'Gantt chart' => 'Wykres Gantta',
'People who are project managers' => 'Użytkownicy będący menedżerami projektu',
'People who are project members' => 'Użytkownicy będący uczestnikami projektu',
- // 'NOK - Norwegian Krone' => '',
+ 'NOK - Norwegian Krone' => 'NOK - Korona norweska',
'Show this column' => 'Pokaż tą kolumnę',
'Hide this column' => 'Ukryj tą kolumnę',
'open file' => 'otwórz plik',
'End date' => 'Data zakończenia',
'Users overview' => 'Przegląd użytkowników',
- 'Members' => 'Uczestnicy',
+ 'Members' => 'Członkowie',
'Shared project' => 'Projekt udostępniony',
'Project managers' => 'Menedżerowie projektu',
'Gantt chart for all projects' => 'Wykres Gantta dla wszystkich projektów',
@@ -844,11 +840,11 @@ return array(
'Change task color when using a specific task link' => 'Zmień kolor zadania używając specjalnego adresu URL',
'Task link creation or modification' => 'Adres URL do utworzenia zadania lub modyfikacji',
'Milestone' => 'Kamień milowy',
- // 'Documentation: %s' => '',
- // 'Switch to the Gantt chart view' => '',
- // 'Reset the search/filter box' => '',
+ 'Documentation: %s' => 'Dokumentacja: %s',
+ 'Switch to the Gantt chart view' => 'Przełącz na wykres Gantta',
+ 'Reset the search/filter box' => 'Zresetuj pole wyszukiwania/filtrowania',
'Documentation' => 'Dokumentacja',
- // 'Table of contents' => '',
+ 'Table of contents' => 'Tablica zawartości',
// 'Gantt' => '',
'Author' => 'Autor',
'Version' => 'Wersja',
@@ -858,60 +854,60 @@ return array(
'Remove maximum column height' => 'Zwiń kolumny',
'My notifications' => 'Powiadomienia',
'Custom filters' => 'Dostosuj filtry',
- // 'Your custom filter have been created successfully.' => '',
- // 'Unable to create your custom filter.' => '',
- // 'Custom filter removed successfully.' => '',
- // 'Unable to remove this custom filter.' => '',
- // 'Edit custom filter' => '',
- // 'Your custom filter have been updated successfully.' => '',
- // 'Unable to update custom filter.' => '',
+ 'Your custom filter have been created successfully.' => 'Niestandardowy filtr został utworzony.',
+ 'Unable to create your custom filter.' => 'Nie można utworzyć niestandardowego filtra.',
+ 'Custom filter removed successfully.' => 'Niestandardowy filtr został usunięty.',
+ 'Unable to remove this custom filter.' => 'Nie można usunąć niestandardowego filtra.',
+ 'Edit custom filter' => 'Edytuj niestandardowy filtr',
+ 'Your custom filter have been updated successfully.' => 'Niestandardowy filtr został zaktualizowany',
+ 'Unable to update custom filter.' => 'Nie można zaktualizować niestandardowego filtra.',
// 'Web' => '',
'New attachment on task #%d: %s' => 'Nowy załącznik do zadania #%d: %s',
'New comment on task #%d' => 'Nowy komentarz do zadania #%d',
'Comment updated on task #%d' => 'Aktualizacja komentarza do zadania #%d',
- 'New subtask on task #%d' => 'Nowe podzadanie dla zadania #%d',
- 'Subtask updated on task #%d' => 'Aktualizacja podzadania w zadaniu #%d',
+ 'New subtask on task #%d' => 'Nowe pod-zadanie dla zadania #%d',
+ 'Subtask updated on task #%d' => 'Aktualizacja pod-zadania w zadaniu #%d',
'New task #%d: %s' => 'Nowe zadanie #%d: %s',
'Task updated #%d' => 'Aktualizacja zadania #%d',
'Task #%d closed' => 'Zamknięto zadanie #%d',
'Task #%d opened' => 'Otwarto zadanie #%d',
'Column changed for task #%d' => 'Zmieniono kolumnę zadania #%d',
'New position for task #%d' => 'Ustalono nową pozycję zadania #%d',
- 'Swimlane changed for task #%d' => 'Zmieniono swimlane dla zadania #%d',
+ 'Swimlane changed for task #%d' => 'Zmieniono tor dla zadania #%d',
'Assignee changed on task #%d' => 'Zmieniono osobę odpowiedzialną dla zadania #%d',
- // '%d overdue tasks' => '',
- // 'Task #%d is overdue' => '',
+ '%d overdue tasks' => '%d zaległych zadań',
+ 'Task #%d is overdue' => 'Zadanie #%d jest zaległe',
'No new notifications.' => 'Brak nowych powiadomień.',
'Mark all as read' => 'Oznacz wszystkie jako przeczytane',
'Mark as read' => 'Oznacz jako przeczytane',
- // 'Total number of tasks in this column across all swimlanes' => '',
- 'Collapse swimlane' => 'Zwiń swimlane',
- 'Expand swimlane' => 'Rozwiń swimlane',
+ 'Total number of tasks in this column across all swimlanes' => 'Całkowita liczba zadań z tej kolumny z wszystkich torów',
+ 'Collapse swimlane' => 'Zwiń tor',
+ 'Expand swimlane' => 'Rozwiń tor',
'Add a new filter' => 'Dodaj nowy filtr',
'Share with all project members' => 'Udostępnij wszystkim uczestnikom projektu',
- // 'Shared' => '',
+ 'Shared' => 'Udostępnione',
'Owner' => 'Właściciel',
'Unread notifications' => 'Nieprzeczytane powiadomienia',
'Notification methods:' => 'Metody powiadomień:',
- // 'Import tasks from CSV file' => '',
- // 'Unable to read your file' => '',
- // '%d task(s) have been imported successfully.' => '',
- // 'Nothing have been imported!' => '',
- // 'Import users from CSV file' => '',
- // '%d user(s) have been imported successfully.' => '',
+ 'Import tasks from CSV file' => 'Importuj zadania z pliku CSV',
+ 'Unable to read your file' => 'Nie można odczytać pliku',
+ '%d task(s) have been imported successfully.' => '%d zadań zostało zaimportowanych.',
+ 'Nothing have been imported!' => 'Nic nie zostało zaimportowane!',
+ 'Import users from CSV file' => 'Importuj użytkowników z pliku CSV',
+ '%d user(s) have been imported successfully.' => '%d użytkowników zostało zaimportowanych.',
'Comma' => 'Przecinek',
'Semi-colon' => 'Średnik',
'Tab' => 'Tabulacja',
'Vertical bar' => 'Kreska pionowa',
'Double Quote' => 'Cudzysłów',
'Single Quote' => 'Apostrof',
- // '%s attached a file to the task #%d' => '',
- // 'There is no column or swimlane activated in your project!' => '',
+ '%s attached a file to the task #%d' => '%s dołączył(a) plik do zadania #%d',
+ 'There is no column or swimlane activated in your project!' => 'Żaden tor badź kolumna nie została aktywowana!',
'Append filter (instead of replacement)' => 'Dołączaj filtr do zastosowanego filtru(zamiast przełączać)',
- // 'Append/Replace' => '',
- // 'Append' => '',
- // 'Replace' => '',
- // 'Import' => '',
+ 'Append/Replace' => 'Dołącz/Zastąp',
+ 'Append' => 'Dołącz',
+ 'Replace' => 'Zastąp',
+ 'Import' => 'Importuj',
'change sorting' => 'odwróć sortowanie',
'Tasks Importation' => 'Import zadań',
'Delimiter' => 'Separator pola',
@@ -924,16 +920,16 @@ return array(
'Duplicates are not verified for you' => 'Duplikaty nie będą weryfikowane',
'The due date must use the ISO format: YYYY-MM-DD' => 'Data musi być w formacie ISO: YYYY-MM-DD',
'Download CSV template' => 'Pobierz szablon pliku CSV',
- // 'No external integration registered.' => '',
+ 'No external integration registered.' => 'Żadna zewnętrzna integracja nie została zarejestrowana.',
'Duplicates are not imported' => 'Duplikaty nie zostaną zaimportowane',
- // 'Usernames must be lowercase and unique' => '',
- // 'Passwords will be encrypted if present' => '',
- // '%s attached a new file to the task %s' => '',
+ 'Usernames must be lowercase and unique' => 'Nazwy użytkowników muszą być unikalne i składać się z małych liter',
+ 'Passwords will be encrypted if present' => 'Hasła zostaną zaszyfrowane jeśli występują',
+ '%s attached a new file to the task %s' => '%s załączył nowy plik do zadania %s',
'Link type' => 'Rodzaj link\'u',
- // 'Assign automatically a category based on a link' => '',
- // 'BAM - Konvertible Mark' => '',
- // 'Assignee Username' => '',
- // 'Assignee Name' => '',
+ 'Assign automatically a category based on a link' => 'Przypisz kategorię automatycznie na podstawie linku',
+ 'BAM - Konvertible Mark' => 'BAM - Bośnia i Hercegowina Cabrio Marka',
+ 'Assignee Username' => 'Przypisz nazwę użytkownika',
+ 'Assignee Name' => 'Przypisz imię',
'Groups' => 'Grupy',
'Members of %s' => 'Członkowie %s',
'New group' => 'Nowa grupa',
@@ -962,11 +958,11 @@ return array(
'View all groups' => 'Wyświetl wszystkie grupy',
'View group members' => 'Wyświetl wszystkich członków grupy',
'There is no user available.' => 'Żaden użytkownik nie jest dostępny.',
- 'Do you really want to remove the user "%s" from the group "%s"?' => 'Czy napewno chcesz usunąć użytkownika "%s" z grupy "%s"?',
+ 'Do you really want to remove the user "%s" from the group "%s"?' => 'Czy na pewno chcesz usunąć użytkownika "%s" z grupy "%s"?',
'There is no group.' => 'Nie utworzono jeszcze żadnej grupy.',
'External Id' => 'Zewnętrzny Id',
'Add group member' => 'Dodaj członka grupy',
- 'Do you really want to remove this group: "%s"?' => 'Czy napewno chcesz usunąć grupę "%s"?',
+ 'Do you really want to remove this group: "%s"?' => 'Czy na pewno chcesz usunąć grupę "%s"?',
'There is no user in this group.' => 'Wybrana grupa nie posiada członków.',
'Remove this user' => 'Usuń użytkownika',
'Permissions' => 'Prawa dostępu',
@@ -981,53 +977,53 @@ return array(
'Enter group name...' => 'Wprowadź nazwę grupy...',
'Role:' => 'Rola:',
'Project members' => 'Uczestnicy projektu',
- // 'Compare hours for "%s"' => '',
+ 'Compare hours for "%s"' => 'Porównaj godziny dla "%s"',
'%s mentioned you in the task #%d' => '%s wspomiał o Tobie w zadaniu #%d',
'%s mentioned you in a comment on the task #%d' => '%s wspomiał o Tobie w komentarzu do zadania #%d',
'You were mentioned in the task #%d' => 'Wspomiano o Tobie w zadaniu #%d',
'You were mentioned in a comment on the task #%d' => 'Wspomiano o Tobie w komentarzu do zadania #%d',
'Mentioned' => 'Wspomiano',
- // 'Compare Estimated Time vs Actual Time' => '',
- // 'Estimated hours: ' => '',
- // 'Actual hours: ' => '',
- // 'Hours Spent' => '',
- // 'Hours Estimated' => '',
- // 'Estimated Time' => '',
- // 'Actual Time' => '',
- // 'Estimated vs actual time' => '',
- // 'RUB - Russian Ruble' => '',
- // 'Assign the task to the person who does the action when the column is changed' => '',
- // 'Close a task in a specific column' => '',
+ 'Compare Estimated Time vs Actual Time' => 'Porównaj szacowany czas z rzeczywistym',
+ 'Estimated hours: ' => 'Szacowane godziny: ',
+ 'Actual hours: ' => 'Rzeczywiste godziny: ',
+ 'Hours Spent' => 'Spędzone godziny',
+ 'Hours Estimated' => 'Szacowane godziny',
+ 'Estimated Time' => 'Szacowany czas',
+ 'Actual Time' => 'Rzeczywisty czas',
+ 'Estimated vs actual time' => 'Szacowany vs rzeczywisty czas',
+ 'RUB - Russian Ruble' => 'RUB - Rosyjskie Ruble',
+ 'Assign the task to the person who does the action when the column is changed' => 'Przypisz zadanie do osoby wykonującej akcję gdy kolumna zostanie zmodyfikowana',
+ 'Close a task in a specific column' => 'Zamknij zadanie w określonej kolumnie',
// 'Time-based One-time Password Algorithm' => '',
- // 'Two-Factor Provider: ' => '',
- // 'Disable two-factor authentication' => '',
- // 'Enable two-factor authentication' => '',
- 'There is no integration registered at the moment.' => 'W chwili obecnej funkcjonalność ta została wyłączona.',
+ 'Two-Factor Provider: ' => 'Dostawca: ',
+ 'Disable two-factor authentication' => 'Wyłącz dwustopniowe uwierzytelnianie',
+ 'Enable two-factor authentication' => 'Włącz dwustopniowe uwierzytelnianie',
+ 'There is no integration registered at the moment.' => 'W chwili obecnej nie ma zarejestrowanej żadnej integracji.',
'Password Reset for Kanboard' => 'Resetuj hasło do Kanboarda',
'Forgot password?' => 'Nie pamiętasz hasła?',
- 'Enable "Forget Password"' => 'Włącz możliwość odzyskiwania zapomianego hasła przez użytkowników',
+ 'Enable "Forget Password"' => 'Włącz "Nie pamiętasz hasła?"',
'Password Reset' => 'Resetuj hasło',
'New password' => 'Nowe hasło',
'Change Password' => 'Zmień hasło',
'To reset your password click on this link:' => 'Kliknij w poniższy link, aby zresetować hasło:',
'Last Password Reset' => 'Ostatnie odzyskiwanie hasła',
'The password has never been reinitialized.' => 'Hasło nigdy nie było odzyskiwane.',
- // 'Creation' => '',
- // 'Expiration' => '',
- 'Password reset history' => 'Historia hasła',
- // 'All tasks of the column "%s" and the swimlane "%s" have been closed successfully.' => '',
- // 'Do you really want to close all tasks of this column?' => '',
- // '%d task(s) in the column "%s" and the swimlane "%s" will be closed.' => '',
+ 'Creation' => 'Utworzenie',
+ 'Expiration' => 'Wygaśnięcie',
+ 'Password reset history' => 'Historia resetowania hasła',
+ 'All tasks of the column "%s" and the swimlane "%s" have been closed successfully.' => 'Wszystkie zadania z kolumny "%s" i toru "%s" zostały zamknięte.',
+ 'Do you really want to close all tasks of this column?' => 'Na pewno chcesz zamknąć wszystkie zadania z tej kolumny?',
+ '%d task(s) in the column "%s" and the swimlane "%s" will be closed.' => '%d zadania z kolumny "%s" i toru "%s" zostaną zamknięte.',
'Close all tasks of this column' => 'Zamknij wszystkie zadania w tej kolumnie',
'No plugin has registered a project notification method. You can still configure individual notifications in your user profile.' => 'Wtyczki obsługujące dodatkowe powiadomienia nie zostały zainstalowane. Dalej jednak możesz korzystać z standardowych powiadomień (sprawdź w ustawieniach Twojego profilu).',
'My dashboard' => 'Mój dashboard',
'My profile' => 'Mój profil',
- // 'Project owner: ' => '',
+ 'Project owner: ' => 'Właściciel projektu: ',
'The project identifier is optional and must be alphanumeric, example: MYPROJECT.' => 'Identyfikator projektu jest opcjonalny i musi być alfanumeryczny, przykład: MYPROJECT.',
'Project owner' => 'Właściciel projektu',
'Those dates are useful for the project Gantt chart.' => 'Daty te są przydatne dla wykresu Gantta.',
'Private projects do not have users and groups management.' => 'Projekty prywatne nie wspierają obsługi użytkowników i grup.',
- // 'There is no project member.' => '',
+ 'There is no project member.' => 'Projekt nie ma uczestników.',
'Priority' => 'Priorytet',
'Task priority' => 'Priorytety zadań',
'General' => 'Ogólne',
@@ -1036,15 +1032,15 @@ return array(
'Lowest priority' => 'Najniższy priorytet',
'Highest priority' => 'Najwyższy priorytet',
'If you put zero to the low and high priority, this feature will be disabled.' => 'Jeżeli dla najniższego i najwyższego priorytetu ustawisz 0, to priorytety dla tablicy zostaną wyłączone.',
- // 'Close a task when there is no activity' => '',
- // 'Duration in days' => '',
- // 'Send email when there is no activity on a task' => '',
- // 'Unable to fetch link information.' => '',
+ 'Close a task when there is no activity' => 'Zamknij zadanie gdy nie jest aktywne',
+ 'Duration in days' => 'Czas trwania w dniach',
+ 'Send email when there is no activity on a task' => 'Wyślij email gdy zadanie nie jest aktywne',
+ 'Unable to fetch link information.' => 'Nie można pobrać informacji o połączeniach.',
// 'Daily background job for tasks' => '',
'Auto' => 'Automatyczny',
'Related' => 'Powiązanie',
'Attachment' => 'Załącznik',
- // 'Title not found' => '',
+ 'Title not found' => 'Nie odnaleziono tytułu',
'Web Link' => 'Link URL',
'External links' => 'Linki zewnętrzne',
'Add external link' => 'Dodaj link zewnętrzny',
@@ -1057,7 +1053,7 @@ return array(
'Copy and paste your link here...' => 'Skopiuj i wklej link tutaj ...',
// 'URL' => '',
'Internal links' => 'Linki do innych zadań',
- // 'Assign to me' => '',
+ 'Assign to me' => 'Przypisz do mnie',
'Me' => 'JA',
'Do not duplicate anything' => 'Nie kopiuj żadnego projektu',
'Projects management' => 'Zarządzanie projektami',
@@ -1067,7 +1063,7 @@ return array(
'open' => 'otwarty',
'closed' => 'zamknięty',
'Priority:' => 'Priorytet:',
- // 'Reference:' => '',
+ 'Reference:' => 'Odnośnik:',
'Complexity:' => 'Złożoność:',
'Swimlane:' => 'Proces:',
'Column:' => 'Kolumna:',
@@ -1075,96 +1071,133 @@ return array(
'Creator:' => 'Utworzył:',
'Time estimated:' => 'Szacowany czas:',
'%s hours' => '%s godzin',
- 'Time spent:' => 'Wykorzystany czas:',
+ 'Time spent:' => 'Spędzony czas:',
'Created:' => 'Utworzone:',
'Modified:' => 'Zmodyfikowane:',
'Completed:' => 'Ukończone:',
'Started:' => 'Rozpoczęte:',
- 'Moved:' => 'Przesunięcie:',
+ 'Moved:' => 'Przeniesione:',
'Task #%d' => 'Zadanie #%d',
- // 'Date and time format' => '',
- // 'Time format' => '',
- // 'Start date: ' => '',
- // 'End date: ' => '',
- // 'New due date: ' => '',
- // 'Start date changed: ' => '',
- // 'Disable private projects' => '',
- // 'Do you really want to remove this custom filter: "%s"?' => '',
- // 'Remove a custom filter' => '',
- // 'User activated successfully.' => '',
- // 'Unable to enable this user.' => '',
- // 'User disabled successfully.' => '',
- // 'Unable to disable this user.' => '',
- // 'All files have been uploaded successfully.' => '',
- // 'View uploaded files' => '',
- // 'The maximum allowed file size is %sB.' => '',
- // 'Choose files again' => '',
+ 'Date and time format' => 'Format daty oraz czasu',
+ 'Time format' => 'Format czasu',
+ 'Start date: ' => 'Data rozpoczęcia: ',
+ 'End date: ' => 'Data zakończenia: ',
+ 'New due date: ' => 'Nowy termin: ',
+ 'Start date changed: ' => 'Data rozpoczęcia została zmieniona: ',
+ 'Disable private projects' => 'Wyłącz prywatne projekty',
+ 'Do you really want to remove this custom filter: "%s"?' => 'Na pewno usunąć niestandardowy filtr: "%s"?',
+ 'Remove a custom filter' => 'Usuń niestandardowy filtr',
+ 'User activated successfully.' => 'Użytkownik został aktywowany.',
+ 'Unable to enable this user.' => 'Nie można włączyć użytkownika.',
+ 'User disabled successfully.' => 'Użytkownik został wyłączony.',
+ 'Unable to disable this user.' => 'Nie można wyłączyć użytkownika.',
+ 'All files have been uploaded successfully.' => 'Wszystkie pliki zostały pomyślnie przesłane.',
+ 'View uploaded files' => 'Zobacz przesłane pliki',
+ 'The maximum allowed file size is %sB.' => 'Maksymalny rozmiar pliku to %sB.',
+ 'Choose files again' => 'Wybierz jeszcze raz pliki',
'Drag and drop your files here' => 'Przeciągnij i upuść pliki tutaj',
'choose files' => 'wybierz pliki',
- // 'View profile' => '',
- // 'Two Factor' => '',
- // 'Disable user' => '',
- // 'Do you really want to disable this user: "%s"?' => '',
- // 'Enable user' => '',
- // 'Do you really want to enable this user: "%s"?' => '',
+ 'View profile' => 'Zobacz profil',
+ 'Two Factor' => 'Dwustopniowe',
+ 'Disable user' => 'Wyłącz użytkownika',
+ 'Do you really want to disable this user: "%s"?' => 'Na pewno wyłączyć użytkownika: "%s"?',
+ 'Enable user' => 'Włącz użytkownika',
+ 'Do you really want to enable this user: "%s"?' => 'Na pewno włączyć użytkownika: "%s"?',
'Download' => 'Pobierz',
'Uploaded: %s' => 'Data załączenia: %s',
'Size: %s' => 'Rozmiar: %s',
'Uploaded by %s' => 'Załadowany przez %s',
'Filename' => 'Nazwa pliku',
'Size' => 'Rozmiar',
- // 'Column created successfully.' => '',
- // 'Another column with the same name exists in the project' => '',
- // 'Default filters' => '',
- // 'Your board doesn\'t have any column!' => '',
- // 'Change column position' => '',
- // 'Switch to the project overview' => '',
- // 'User filters' => '',
- // 'Category filters' => '',
+ 'Column created successfully.' => 'Utworzono kolumnę.',
+ 'Another column with the same name exists in the project' => 'Inna kolumna o tej samej nazwie już istnieje w projekcie',
+ 'Default filters' => 'Domyślne filtry',
+ 'Your board doesn\'t have any column!' => 'Twoja tablica nie ma żadnej kolumny!',
+ 'Change column position' => 'Zmień pozycję kolumny',
+ 'Switch to the project overview' => 'Przełącz do podsumowania projektu',
+ 'User filters' => 'Filtry użytkownika',
+ 'Category filters' => 'Filtry kategorii',
'Upload a file' => 'Prześlij plik',
'View file' => 'Wyświetl plik',
'Last activity' => 'Ostatnia aktywność',
- // 'Change subtask position' => '',
- // 'This value must be greater than %d' => '',
- // 'Another swimlane with the same name exists in the project' => '',
- // 'Example: http://example.kanboard.net/ (used to generate absolute URLs)' => '',
- // 'Actions duplicated successfully.' => '',
- // 'Unable to duplicate actions.' => '',
- // 'Add a new action' => '',
- // 'Import from another project' => '',
- // 'There is no action at the moment.' => '',
- // 'Import actions from another project' => '',
- // 'There is no available project.' => '',
- // 'Local File' => '',
- // 'Configuration' => '',
- // 'PHP version:' => '',
+ 'Change subtask position' => 'Zmień pozycję pod-zadania',
+ 'This value must be greater than %d' => 'Wartość musi być większa niż %d',
+ 'Another swimlane with the same name exists in the project' => 'Inny tor o tej samej nazwie już istnieje w projekcie',
+ 'Example: http://example.kanboard.net/ (used to generate absolute URLs)' => 'Przykład: http://example.kanboard.net/ (użyty do wygenerowania bezwzględnych adresów URL)',
+ 'Actions duplicated successfully.' => 'Pomyślnie zduplikowano akcje.',
+ 'Unable to duplicate actions.' => 'Nie można zduplikować akcji.',
+ 'Add a new action' => 'Dodaj nową akcję',
+ 'Import from another project' => 'Importuj z innego projektu',
+ 'There is no action at the moment.' => 'W chwili obecnej nie dodano żadnych akcji.',
+ 'Import actions from another project' => 'Importuj akcje z innego projektu',
+ 'There is no available project.' => 'Brak dostępnego projektu.',
+ 'Local File' => 'Plik lokalny',
+ 'Configuration' => 'Konfiguracja',
+ 'PHP version:' => 'Wersja PHP:',
// 'PHP SAPI:' => '',
- // 'OS version:' => '',
- // 'Database version:' => '',
- // 'Browser:' => '',
- // 'Task view' => '',
- // 'Edit task' => '',
- // 'Edit description' => '',
- // 'New internal link' => '',
- // 'Display list of keyboard shortcuts' => '',
+ 'OS version:' => 'Wersja OS:',
+ 'Database version:' => 'Wersja bazy danych:',
+ 'Browser:' => 'Przeglądarka',
+ 'Task view' => 'Widok zadań',
+ 'Edit task' => 'Edytuj zadanie',
+ 'Edit description' => 'Edytuj opis',
+ 'New internal link' => 'Nowy wewnętrzny link',
+ 'Display list of keyboard shortcuts' => 'Wyświetl skróty klawiszowe',
// 'Menu' => '',
- // 'Set start date' => '',
+ 'Set start date' => 'Ustaw datę rozpoczęcia',
// 'Avatar' => '',
- // 'Upload my avatar image' => '',
- // 'Remove my image' => '',
- // 'The OAuth2 state parameter is invalid' => '',
- // 'User not found.' => '',
- // 'Search in activity stream' => '',
- // 'My activities' => '',
- // 'Activity until yesterday' => '',
- // 'Activity until today' => '',
- // 'Search by creator: ' => '',
- // 'Search by creation date: ' => '',
- // 'Search by task status: ' => '',
- // 'Search by task title: ' => '',
- // 'Activity stream search' => '',
- // 'Projects where "%s" is manager' => '',
- // 'Projects where "%s" is member' => '',
- // 'Open tasks assigned to "%s"' => '',
- // 'Closed tasks assigned to "%s"' => '',
+ 'Upload my avatar image' => 'Prześlij avatar',
+ 'Remove my image' => 'Usuń',
+ 'The OAuth2 state parameter is invalid' => 'Parametr stanu OAuth2 jest niepoprawny',
+ 'User not found.' => 'Nie znaleziono użytkownika',
+ 'Search in activity stream' => 'Szukaj w strumieniu aktywności',
+ 'My activities' => 'Moje aktywności',
+ 'Activity until yesterday' => 'Aktywności do wczoraj',
+ 'Activity until today' => 'Aktywności do dzisiaj',
+ 'Search by creator: ' => 'Wyszukaj według twórcy: ',
+ 'Search by creation date: ' => 'Wyszukaj według daty utworzenia: ',
+ 'Search by task status: ' => 'Wyszukaj według statusu zadania: ',
+ 'Search by task title: ' => 'Wyszukaj po tytule zadania: ',
+ 'Activity stream search' => 'Wyszukaj w strumieniu aktywności',
+ 'Projects where "%s" is manager' => 'Projekty gdzie "%s" jest menedżerem',
+ 'Projects where "%s" is member' => 'Projekty gdzie "%s" jest uczestnikiem',
+ 'Open tasks assigned to "%s"' => 'Otwarte zadania przypisane do "%s"',
+ 'Closed tasks assigned to "%s"' => 'Zamknięte zadania przypisane do "%s"',
+ // 'Assign automatically a color based on a priority' => '',
+ 'Overdue tasks for the project(s) "%s"' => 'Zaległe zadania dla projektu/projektów "%s"',
+ // 'Upload files' => '',
+ // 'Installed Plugins' => '',
+ // 'Plugin Directory' => '',
+ // 'Plugin installed successfully.' => '',
+ // 'Plugin updated successfully.' => '',
+ // 'Plugin removed successfully.' => '',
+ // 'Subtask converted to task successfully.' => '',
+ // 'Unable to convert the subtask.' => '',
+ // 'Unable to extract plugin archive.' => '',
+ // 'Plugin not found.' => '',
+ // 'You don\'t have the permission to remove this plugin.' => '',
+ // 'Unable to download plugin archive.' => '',
+ // 'Unable to write temporary file for plugin.' => '',
+ // 'Unable to open plugin archive.' => '',
+ // 'There is no file in the plugin archive.' => '',
+ // 'Create tasks in bulk' => '',
+ // 'Your Kanboard instance is not configured to install plugins from the user interface.' => '',
+ // 'There is no plugin available.' => '',
+ // 'Install' => '',
+ // 'Update' => '',
+ // 'Up to date' => '',
+ // 'Not available' => '',
+ // 'Remove plugin' => '',
+ // 'Do you really want to remove this plugin: "%s"?' => '',
+ // 'Uninstall' => '',
+ // 'Listing' => '',
+ // 'Metadata' => '',
+ // 'Manage projects' => '',
+ // 'Convert to task' => '',
+ // 'Convert sub-task to task' => '',
+ // 'Do you really want to convert this sub-task to a task?' => '',
+ // 'My task title' => '',
+ // 'Enter one task by line.' => '',
+ // 'Number of failed login:' => '',
+ // 'Account locked until:' => '',
);
diff --git a/app/Locale/pt_BR/translations.php b/app/Locale/pt_BR/translations.php
index b0aba4db..ca8a72b4 100644
--- a/app/Locale/pt_BR/translations.php
+++ b/app/Locale/pt_BR/translations.php
@@ -170,7 +170,6 @@ return array(
'Leave a description' => 'Deixe uma descrição',
'Comment added successfully.' => 'Comentário adicionado com sucesso.',
'Unable to create your comment.' => 'Não é possível criar o seu comentário.',
- 'Edit this task' => 'Editar esta tarefa',
'Due Date' => 'Data de vencimento',
'Invalid date' => 'Data inválida',
'Automatic actions' => 'Ações automáticas',
@@ -517,7 +516,6 @@ return array(
'All swimlanes' => 'Todas as swimlanes',
'All colors' => 'Todas as cores',
'Moved to column %s' => 'Mover para a coluna %s',
- 'Change description' => 'Modificar a descrição',
'User dashboard' => 'Painel de Controle do usuário',
'Allow only one subtask in progress at the same time for a user' => 'Permitir apenas uma subtarefa em andamento ao mesmo tempo para um usuário',
'Edit column "%s"' => 'Editar a coluna "%s"',
@@ -709,7 +707,6 @@ return array(
'view the board on Kanboard' => 'ver o painel no Kanboard',
'The task have been moved to the first swimlane' => 'A tarefa foi movida para a primeira swimlane',
'The task have been moved to another swimlane:' => 'A tarefa foi movida para outra swimlane:',
- // 'Overdue tasks for the project(s) "%s"' => 'Tarefas atrasadas para o projeto "%s"',
'New title: %s' => 'Novo título: %s',
'The task is not assigned anymore' => 'Agora a tarefa não está mais atribuída',
'New assignee: %s' => 'Novo designado: %s',
@@ -738,7 +735,6 @@ return array(
'Stop timer' => 'Stop timer',
'Start timer' => 'Start timer',
'Add project member' => 'Adicionar membro ao projeto',
- 'Enable notifications' => 'Ativar as notificações',
'My activity stream' => 'Meu feed de atividades',
'My calendar' => 'Minha agenda',
'Search tasks' => 'Pesquisar tarefas',
@@ -1167,4 +1163,41 @@ return array(
// 'Projects where "%s" is member' => '',
// 'Open tasks assigned to "%s"' => '',
// 'Closed tasks assigned to "%s"' => '',
+ // 'Assign automatically a color based on a priority' => '',
+ // 'Overdue tasks for the project(s) "%s"' => '',
+ // 'Upload files' => '',
+ // 'Installed Plugins' => '',
+ // 'Plugin Directory' => '',
+ // 'Plugin installed successfully.' => '',
+ // 'Plugin updated successfully.' => '',
+ // 'Plugin removed successfully.' => '',
+ // 'Subtask converted to task successfully.' => '',
+ // 'Unable to convert the subtask.' => '',
+ // 'Unable to extract plugin archive.' => '',
+ // 'Plugin not found.' => '',
+ // 'You don\'t have the permission to remove this plugin.' => '',
+ // 'Unable to download plugin archive.' => '',
+ // 'Unable to write temporary file for plugin.' => '',
+ // 'Unable to open plugin archive.' => '',
+ // 'There is no file in the plugin archive.' => '',
+ // 'Create tasks in bulk' => '',
+ // 'Your Kanboard instance is not configured to install plugins from the user interface.' => '',
+ // 'There is no plugin available.' => '',
+ // 'Install' => '',
+ // 'Update' => '',
+ // 'Up to date' => '',
+ // 'Not available' => '',
+ // 'Remove plugin' => '',
+ // 'Do you really want to remove this plugin: "%s"?' => '',
+ // 'Uninstall' => '',
+ // 'Listing' => '',
+ // 'Metadata' => '',
+ // 'Manage projects' => '',
+ // 'Convert to task' => '',
+ // 'Convert sub-task to task' => '',
+ // 'Do you really want to convert this sub-task to a task?' => '',
+ // 'My task title' => '',
+ // 'Enter one task by line.' => '',
+ // 'Number of failed login:' => '',
+ // 'Account locked until:' => '',
);
diff --git a/app/Locale/pt_PT/translations.php b/app/Locale/pt_PT/translations.php
index f8ace69d..d21026e5 100644
--- a/app/Locale/pt_PT/translations.php
+++ b/app/Locale/pt_PT/translations.php
@@ -170,7 +170,6 @@ return array(
'Leave a description' => 'Deixe uma descrição',
'Comment added successfully.' => 'Comentário adicionado com sucesso.',
'Unable to create your comment.' => 'Não é possível criar o seu comentário.',
- 'Edit this task' => 'Editar esta tarefa',
'Due Date' => 'Data de vencimento',
'Invalid date' => 'Data inválida',
'Automatic actions' => 'Acções automáticas',
@@ -517,7 +516,6 @@ return array(
'All swimlanes' => 'Todos os swimlane',
'All colors' => 'Todas as cores',
'Moved to column %s' => 'Mover para a coluna %s',
- 'Change description' => 'Modificar a descrição',
'User dashboard' => 'Painel de Controlo do utilizador',
'Allow only one subtask in progress at the same time for a user' => 'Permitir apenas uma subtarefa em andamento ao mesmo tempo para um utilizador',
'Edit column "%s"' => 'Editar a coluna "%s"',
@@ -709,7 +707,6 @@ return array(
'view the board on Kanboard' => 'ver o painel no Kanboard',
'The task have been moved to the first swimlane' => 'A tarefa foi movida para o primeiro Swimlane',
'The task have been moved to another swimlane:' => 'A tarefa foi movida para outro Swimlane:',
- // 'Overdue tasks for the project(s) "%s"' => 'Tarefas atrasadas para o projecto "%s"',
'New title: %s' => 'Novo título: %s',
'The task is not assigned anymore' => 'Tarefa já não está atribuída',
'New assignee: %s' => 'Novo assignado: %s',
@@ -738,7 +735,6 @@ return array(
'Stop timer' => 'Parar temporizador',
'Start timer' => 'Iniciar temporizador',
'Add project member' => 'Adicionar um membro ao projecto',
- 'Enable notifications' => 'Activar as notificações',
'My activity stream' => 'O meu feed de actividade',
'My calendar' => 'A minha agenda',
'Search tasks' => 'Pesquisar tarefas',
@@ -1167,4 +1163,41 @@ return array(
'Projects where "%s" is member' => 'Projectos onde "%s" é membro',
'Open tasks assigned to "%s"' => 'Tarefas abertas assignadas a "%s"',
'Closed tasks assigned to "%s"' => 'Tarefas fechadas assignadas a "%s"',
+ 'Assign automatically a color based on a priority' => 'Assignar uma cor automáticamente de acordo com a prioridade',
+ 'Overdue tasks for the project(s) "%s"' => 'Tarefas em atraso para o(s) projecto(s) "%s"',
+ 'Upload files' => 'Enviar ficheiros',
+ // 'Installed Plugins' => '',
+ // 'Plugin Directory' => '',
+ // 'Plugin installed successfully.' => '',
+ // 'Plugin updated successfully.' => '',
+ // 'Plugin removed successfully.' => '',
+ // 'Subtask converted to task successfully.' => '',
+ // 'Unable to convert the subtask.' => '',
+ // 'Unable to extract plugin archive.' => '',
+ // 'Plugin not found.' => '',
+ // 'You don\'t have the permission to remove this plugin.' => '',
+ // 'Unable to download plugin archive.' => '',
+ // 'Unable to write temporary file for plugin.' => '',
+ // 'Unable to open plugin archive.' => '',
+ // 'There is no file in the plugin archive.' => '',
+ // 'Create tasks in bulk' => '',
+ // 'Your Kanboard instance is not configured to install plugins from the user interface.' => '',
+ // 'There is no plugin available.' => '',
+ // 'Install' => '',
+ // 'Update' => '',
+ // 'Up to date' => '',
+ // 'Not available' => '',
+ // 'Remove plugin' => '',
+ // 'Do you really want to remove this plugin: "%s"?' => '',
+ // 'Uninstall' => '',
+ // 'Listing' => '',
+ // 'Metadata' => '',
+ // 'Manage projects' => '',
+ // 'Convert to task' => '',
+ // 'Convert sub-task to task' => '',
+ // 'Do you really want to convert this sub-task to a task?' => '',
+ // 'My task title' => '',
+ // 'Enter one task by line.' => '',
+ // 'Number of failed login:' => '',
+ // 'Account locked until:' => '',
);
diff --git a/app/Locale/ru_RU/translations.php b/app/Locale/ru_RU/translations.php
index 322126e3..de744b9f 100644
--- a/app/Locale/ru_RU/translations.php
+++ b/app/Locale/ru_RU/translations.php
@@ -170,7 +170,6 @@ return array(
'Leave a description' => 'Напишите описание',
'Comment added successfully.' => 'Комментарий успешно добавлен.',
'Unable to create your comment.' => 'Невозможно создать комментарий.',
- 'Edit this task' => 'Изменить задачу',
'Due Date' => 'Сделать до',
'Invalid date' => 'Неверная дата',
'Automatic actions' => 'Автоматические действия',
@@ -517,7 +516,6 @@ return array(
'All swimlanes' => 'Все дорожки',
'All colors' => 'Все цвета',
'Moved to column %s' => 'Перемещена в колонку %s',
- 'Change description' => 'Изменить описание',
'User dashboard' => 'Пользователь панели мониторинга',
'Allow only one subtask in progress at the same time for a user' => 'Разрешена только одна подзадача в разработке одновременно для одного пользователя',
'Edit column "%s"' => 'Редактировать колонку "%s"',
@@ -709,7 +707,6 @@ return array(
'view the board on Kanboard' => 'посмотреть доску на Kanboard',
'The task have been moved to the first swimlane' => 'Эта задача была перемещена в первую дорожку',
'The task have been moved to another swimlane:' => 'Эта задача была перемещена в другую дорожку:',
- // 'Overdue tasks for the project(s) "%s"' => 'Просроченные задачи для проекта "%s"',
'New title: %s' => 'Новый заголовок: %s',
'The task is not assigned anymore' => 'Задача больше не назначена',
'New assignee: %s' => 'Новый назначенный: %s',
@@ -738,7 +735,6 @@ return array(
'Stop timer' => 'Остановить таймер',
'Start timer' => 'Запустить таймер',
'Add project member' => 'Добавить номер проекта',
- 'Enable notifications' => 'Включить уведомления',
'My activity stream' => 'Лента моей активности',
'My calendar' => 'Мой календарь',
'Search tasks' => 'Поиск задачи',
@@ -1167,4 +1163,41 @@ return array(
'Projects where "%s" is member' => 'Проекты, где членом является "%s"',
'Open tasks assigned to "%s"' => 'Открытые задачи, назначенные на "%s"',
'Closed tasks assigned to "%s"' => 'Закрытые задачи, назначенные на "%s"',
+ // 'Assign automatically a color based on a priority' => '',
+ // 'Overdue tasks for the project(s) "%s"' => '',
+ // 'Upload files' => '',
+ // 'Installed Plugins' => '',
+ // 'Plugin Directory' => '',
+ // 'Plugin installed successfully.' => '',
+ // 'Plugin updated successfully.' => '',
+ // 'Plugin removed successfully.' => '',
+ // 'Subtask converted to task successfully.' => '',
+ // 'Unable to convert the subtask.' => '',
+ // 'Unable to extract plugin archive.' => '',
+ // 'Plugin not found.' => '',
+ // 'You don\'t have the permission to remove this plugin.' => '',
+ // 'Unable to download plugin archive.' => '',
+ // 'Unable to write temporary file for plugin.' => '',
+ // 'Unable to open plugin archive.' => '',
+ // 'There is no file in the plugin archive.' => '',
+ // 'Create tasks in bulk' => '',
+ // 'Your Kanboard instance is not configured to install plugins from the user interface.' => '',
+ // 'There is no plugin available.' => '',
+ // 'Install' => '',
+ // 'Update' => '',
+ // 'Up to date' => '',
+ // 'Not available' => '',
+ // 'Remove plugin' => '',
+ // 'Do you really want to remove this plugin: "%s"?' => '',
+ // 'Uninstall' => '',
+ // 'Listing' => '',
+ // 'Metadata' => '',
+ // 'Manage projects' => '',
+ // 'Convert to task' => '',
+ // 'Convert sub-task to task' => '',
+ // 'Do you really want to convert this sub-task to a task?' => '',
+ // 'My task title' => '',
+ // 'Enter one task by line.' => '',
+ // 'Number of failed login:' => '',
+ // 'Account locked until:' => '',
);
diff --git a/app/Locale/sr_Latn_RS/translations.php b/app/Locale/sr_Latn_RS/translations.php
index 304b91dc..e6d39880 100644
--- a/app/Locale/sr_Latn_RS/translations.php
+++ b/app/Locale/sr_Latn_RS/translations.php
@@ -170,7 +170,6 @@ return array(
'Leave a description' => 'Dodaj opis',
'Comment added successfully.' => 'Komentar uspešno ostavljen',
'Unable to create your comment.' => 'Nemoguće kreiranje komentara',
- 'Edit this task' => 'Izmeni ovaj zadatak',
'Due Date' => 'Termin',
'Invalid date' => 'Loš datum',
'Automatic actions' => 'Automatske akcije',
@@ -517,7 +516,6 @@ return array(
'All swimlanes' => 'Svi razdelniki',
'All colors' => 'Sve boje',
'Moved to column %s' => 'Premešten u kolonu %s',
- // 'Change description' => '',
'User dashboard' => 'Korisnički panel',
// 'Allow only one subtask in progress at the same time for a user' => '',
// 'Edit column "%s"' => '',
@@ -709,7 +707,6 @@ return array(
// 'view the board on Kanboard' => '',
// 'The task have been moved to the first swimlane' => '',
// 'The task have been moved to another swimlane:' => '',
- // 'Overdue tasks for the project(s) "%s"' => '',
// 'New title: %s' => '',
// 'The task is not assigned anymore' => '',
// 'New assignee: %s' => '',
@@ -738,7 +735,6 @@ return array(
// 'Stop timer' => '',
// 'Start timer' => '',
// 'Add project member' => '',
- // 'Enable notifications' => '',
// 'My activity stream' => '',
// 'My calendar' => '',
// 'Search tasks' => '',
@@ -1167,4 +1163,41 @@ return array(
// 'Projects where "%s" is member' => '',
// 'Open tasks assigned to "%s"' => '',
// 'Closed tasks assigned to "%s"' => '',
+ // 'Assign automatically a color based on a priority' => '',
+ // 'Overdue tasks for the project(s) "%s"' => '',
+ // 'Upload files' => '',
+ // 'Installed Plugins' => '',
+ // 'Plugin Directory' => '',
+ // 'Plugin installed successfully.' => '',
+ // 'Plugin updated successfully.' => '',
+ // 'Plugin removed successfully.' => '',
+ // 'Subtask converted to task successfully.' => '',
+ // 'Unable to convert the subtask.' => '',
+ // 'Unable to extract plugin archive.' => '',
+ // 'Plugin not found.' => '',
+ // 'You don\'t have the permission to remove this plugin.' => '',
+ // 'Unable to download plugin archive.' => '',
+ // 'Unable to write temporary file for plugin.' => '',
+ // 'Unable to open plugin archive.' => '',
+ // 'There is no file in the plugin archive.' => '',
+ // 'Create tasks in bulk' => '',
+ // 'Your Kanboard instance is not configured to install plugins from the user interface.' => '',
+ // 'There is no plugin available.' => '',
+ // 'Install' => '',
+ // 'Update' => '',
+ // 'Up to date' => '',
+ // 'Not available' => '',
+ // 'Remove plugin' => '',
+ // 'Do you really want to remove this plugin: "%s"?' => '',
+ // 'Uninstall' => '',
+ // 'Listing' => '',
+ // 'Metadata' => '',
+ // 'Manage projects' => '',
+ // 'Convert to task' => '',
+ // 'Convert sub-task to task' => '',
+ // 'Do you really want to convert this sub-task to a task?' => '',
+ // 'My task title' => '',
+ // 'Enter one task by line.' => '',
+ // 'Number of failed login:' => '',
+ // 'Account locked until:' => '',
);
diff --git a/app/Locale/sv_SE/translations.php b/app/Locale/sv_SE/translations.php
index 6fca58a1..c849acc2 100644
--- a/app/Locale/sv_SE/translations.php
+++ b/app/Locale/sv_SE/translations.php
@@ -170,7 +170,6 @@ return array(
'Leave a description' => 'Lämna en beskrivning',
'Comment added successfully.' => 'Kommentaren har lagts till.',
'Unable to create your comment.' => 'Kommentaren kunde inte laddas upp.',
- 'Edit this task' => 'Ändra denna uppgift',
'Due Date' => 'Måldatum',
'Invalid date' => 'Ej tillåtet datum',
'Automatic actions' => 'Automatiska åtgärder',
@@ -517,7 +516,6 @@ return array(
'All swimlanes' => 'Alla swimlanes',
'All colors' => 'Alla färger',
'Moved to column %s' => 'Flyttad till kolumn %s',
- 'Change description' => 'Ändra beskrivning',
'User dashboard' => 'Användardashboard',
'Allow only one subtask in progress at the same time for a user' => 'Tillåt endast en deluppgift igång samtidigt för en användare',
'Edit column "%s"' => 'Ändra kolumn "%s"',
@@ -709,7 +707,6 @@ return array(
'view the board on Kanboard' => 'visa tavlan på Kanboard',
'The task have been moved to the first swimlane' => 'Uppgiften har flyttats till första swimlane',
'The task have been moved to another swimlane:' => 'Uppgiften har flyttats till en annan swimlane:',
- // 'Overdue tasks for the project(s) "%s"' => 'Försenade uppgifter för projektet "%s"',
'New title: %s' => 'Ny titel: %s',
'The task is not assigned anymore' => 'Uppgiften är inte länge tilldelad',
'New assignee: %s' => 'Ny tilldelning: %s',
@@ -738,7 +735,6 @@ return array(
'Stop timer' => 'Stoppa timer',
'Start timer' => 'Starta timer',
'Add project member' => 'Lägg till projektmedlem',
- 'Enable notifications' => 'Aktivera notiser',
'My activity stream' => 'Min aktivitetsström',
'My calendar' => 'Min kalender',
'Search tasks' => 'Sök uppgifter',
@@ -1167,4 +1163,41 @@ return array(
// 'Projects where "%s" is member' => '',
// 'Open tasks assigned to "%s"' => '',
// 'Closed tasks assigned to "%s"' => '',
+ // 'Assign automatically a color based on a priority' => '',
+ // 'Overdue tasks for the project(s) "%s"' => '',
+ // 'Upload files' => '',
+ // 'Installed Plugins' => '',
+ // 'Plugin Directory' => '',
+ // 'Plugin installed successfully.' => '',
+ // 'Plugin updated successfully.' => '',
+ // 'Plugin removed successfully.' => '',
+ // 'Subtask converted to task successfully.' => '',
+ // 'Unable to convert the subtask.' => '',
+ // 'Unable to extract plugin archive.' => '',
+ // 'Plugin not found.' => '',
+ // 'You don\'t have the permission to remove this plugin.' => '',
+ // 'Unable to download plugin archive.' => '',
+ // 'Unable to write temporary file for plugin.' => '',
+ // 'Unable to open plugin archive.' => '',
+ // 'There is no file in the plugin archive.' => '',
+ // 'Create tasks in bulk' => '',
+ // 'Your Kanboard instance is not configured to install plugins from the user interface.' => '',
+ // 'There is no plugin available.' => '',
+ // 'Install' => '',
+ // 'Update' => '',
+ // 'Up to date' => '',
+ // 'Not available' => '',
+ // 'Remove plugin' => '',
+ // 'Do you really want to remove this plugin: "%s"?' => '',
+ // 'Uninstall' => '',
+ // 'Listing' => '',
+ // 'Metadata' => '',
+ // 'Manage projects' => '',
+ // 'Convert to task' => '',
+ // 'Convert sub-task to task' => '',
+ // 'Do you really want to convert this sub-task to a task?' => '',
+ // 'My task title' => '',
+ // 'Enter one task by line.' => '',
+ // 'Number of failed login:' => '',
+ // 'Account locked until:' => '',
);
diff --git a/app/Locale/th_TH/translations.php b/app/Locale/th_TH/translations.php
index 2cdc870c..33713490 100644
--- a/app/Locale/th_TH/translations.php
+++ b/app/Locale/th_TH/translations.php
@@ -170,7 +170,6 @@ return array(
'Leave a description' => 'แสดงคำอธิบาย',
'Comment added successfully.' => 'เพิ่มความคิดเห็นเรียบร้อยแล้ว',
'Unable to create your comment.' => 'ไม่สามารถสร้างความคิดเห็น',
- 'Edit this task' => 'แก้ไขงาน',
'Due Date' => 'วันที่ครบกำหนด',
'Invalid date' => 'วันที่ผิด',
'Automatic actions' => 'การกระทำอัตโนมัติ',
@@ -517,7 +516,6 @@ return array(
'All swimlanes' => 'สวิมเลนทั้งหมด',
'All colors' => 'สีทั้งหมด',
'Moved to column %s' => 'เคลื่อนไปคอลัมน์ %s',
- 'Change description' => 'เปลี่ยนคำอธิบาย',
'User dashboard' => 'ผู้ใช้แดชบอร์ด',
'Allow only one subtask in progress at the same time for a user' => 'อนุญาตให้ทำงานย่อยได้เพียงงานเดียวต่อหนึ่งคนในเวลาเดียวกัน',
'Edit column "%s"' => 'แก้ไขคอลัมน์ "%s"',
@@ -709,7 +707,6 @@ return array(
'view the board on Kanboard' => 'แสดงบอร์ดบนคังบอร์ด',
'The task have been moved to the first swimlane' => 'งานถูกย้านไปสวิมเลนแรก',
'The task have been moved to another swimlane:' => 'งานถูกย้านไปสวิมเลนอื่น:',
- // 'Overdue tasks for the project(s) "%s"' => 'งานที่เกินกำหนดสำหรับโปรเจค "%s"',
'New title: %s' => 'ชื่อเรื่องใหม่: %s',
'The task is not assigned anymore' => 'ไม่กำหนดผู้รับผิดชอบ',
'New assignee: %s' => 'ผู้รับผิดชอบใหม่: %s',
@@ -738,7 +735,6 @@ return array(
'Stop timer' => 'หยุดจับเวลา',
'Start timer' => 'เริ่มจับเวลา',
'Add project member' => 'เพิ่มสมาชิกโปรเจค',
- 'Enable notifications' => 'เปิดการแจ้งเตือน',
'My activity stream' => 'กิจกรรมที่เกิดขึ้นของฉัน',
'My calendar' => 'ปฎิทินของฉัน',
'Search tasks' => 'ค้นหางาน',
@@ -1167,4 +1163,41 @@ return array(
// 'Projects where "%s" is member' => '',
// 'Open tasks assigned to "%s"' => '',
// 'Closed tasks assigned to "%s"' => '',
+ // 'Assign automatically a color based on a priority' => '',
+ // 'Overdue tasks for the project(s) "%s"' => '',
+ // 'Upload files' => '',
+ // 'Installed Plugins' => '',
+ // 'Plugin Directory' => '',
+ // 'Plugin installed successfully.' => '',
+ // 'Plugin updated successfully.' => '',
+ // 'Plugin removed successfully.' => '',
+ // 'Subtask converted to task successfully.' => '',
+ // 'Unable to convert the subtask.' => '',
+ // 'Unable to extract plugin archive.' => '',
+ // 'Plugin not found.' => '',
+ // 'You don\'t have the permission to remove this plugin.' => '',
+ // 'Unable to download plugin archive.' => '',
+ // 'Unable to write temporary file for plugin.' => '',
+ // 'Unable to open plugin archive.' => '',
+ // 'There is no file in the plugin archive.' => '',
+ // 'Create tasks in bulk' => '',
+ // 'Your Kanboard instance is not configured to install plugins from the user interface.' => '',
+ // 'There is no plugin available.' => '',
+ // 'Install' => '',
+ // 'Update' => '',
+ // 'Up to date' => '',
+ // 'Not available' => '',
+ // 'Remove plugin' => '',
+ // 'Do you really want to remove this plugin: "%s"?' => '',
+ // 'Uninstall' => '',
+ // 'Listing' => '',
+ // 'Metadata' => '',
+ // 'Manage projects' => '',
+ // 'Convert to task' => '',
+ // 'Convert sub-task to task' => '',
+ // 'Do you really want to convert this sub-task to a task?' => '',
+ // 'My task title' => '',
+ // 'Enter one task by line.' => '',
+ // 'Number of failed login:' => '',
+ // 'Account locked until:' => '',
);
diff --git a/app/Locale/tr_TR/translations.php b/app/Locale/tr_TR/translations.php
index ee9242a9..919e6513 100644
--- a/app/Locale/tr_TR/translations.php
+++ b/app/Locale/tr_TR/translations.php
@@ -170,7 +170,6 @@ return array(
'Leave a description' => 'Açıklama ekleyin',
'Comment added successfully.' => 'Yorum eklendi',
'Unable to create your comment.' => 'Yorumunuz oluşturulamadı',
- 'Edit this task' => 'Bu görevi değiştir',
'Due Date' => 'Bitiş Tarihi',
'Invalid date' => 'Geçersiz tarihi',
'Automatic actions' => 'Otomatik işlemler',
@@ -517,7 +516,6 @@ return array(
'All swimlanes' => 'Tüm Kulvarlar',
'All colors' => 'Tüm Renkler',
'Moved to column %s' => '%s Sütununa taşındı',
- 'Change description' => 'Açıklamayı değiştir',
'User dashboard' => 'Kullanıcı Anasayfası',
'Allow only one subtask in progress at the same time for a user' => 'Bir kullanıcı için aynı anda yalnızca bir alt göreve izin ver',
'Edit column "%s"' => '"%s" sütununu değiştir',
@@ -709,7 +707,6 @@ return array(
'view the board on Kanboard' => 'Tabloyu Kanboard\'da görüntüle',
'The task have been moved to the first swimlane' => 'Görev birinci kulvara taşındı',
'The task have been moved to another swimlane:' => 'Görev başka bir kulvara taşındı:',
- // 'Overdue tasks for the project(s) "%s"' => '"%s" projesi için gecikmiş görevler',
'New title: %s' => 'Yeni başlık: %s',
'The task is not assigned anymore' => 'Görev artık atanmamış',
'New assignee: %s' => 'Yeni atanan: %s',
@@ -738,7 +735,6 @@ return array(
'Stop timer' => 'Zamanlayıcıyı durdur',
'Start timer' => 'Zamanlayıcıyı başlat',
'Add project member' => 'Proje üyesi ekle',
- 'Enable notifications' => 'Bildirimleri etkinleştir',
'My activity stream' => 'Olay akışım',
'My calendar' => 'Takvimim',
'Search tasks' => 'Görevleri ara',
@@ -1167,4 +1163,41 @@ return array(
// 'Projects where "%s" is member' => '',
// 'Open tasks assigned to "%s"' => '',
// 'Closed tasks assigned to "%s"' => '',
+ // 'Assign automatically a color based on a priority' => '',
+ // 'Overdue tasks for the project(s) "%s"' => '',
+ // 'Upload files' => '',
+ // 'Installed Plugins' => '',
+ // 'Plugin Directory' => '',
+ // 'Plugin installed successfully.' => '',
+ // 'Plugin updated successfully.' => '',
+ // 'Plugin removed successfully.' => '',
+ // 'Subtask converted to task successfully.' => '',
+ // 'Unable to convert the subtask.' => '',
+ // 'Unable to extract plugin archive.' => '',
+ // 'Plugin not found.' => '',
+ // 'You don\'t have the permission to remove this plugin.' => '',
+ // 'Unable to download plugin archive.' => '',
+ // 'Unable to write temporary file for plugin.' => '',
+ // 'Unable to open plugin archive.' => '',
+ // 'There is no file in the plugin archive.' => '',
+ // 'Create tasks in bulk' => '',
+ // 'Your Kanboard instance is not configured to install plugins from the user interface.' => '',
+ // 'There is no plugin available.' => '',
+ // 'Install' => '',
+ // 'Update' => '',
+ // 'Up to date' => '',
+ // 'Not available' => '',
+ // 'Remove plugin' => '',
+ // 'Do you really want to remove this plugin: "%s"?' => '',
+ // 'Uninstall' => '',
+ // 'Listing' => '',
+ // 'Metadata' => '',
+ // 'Manage projects' => '',
+ // 'Convert to task' => '',
+ // 'Convert sub-task to task' => '',
+ // 'Do you really want to convert this sub-task to a task?' => '',
+ // 'My task title' => '',
+ // 'Enter one task by line.' => '',
+ // 'Number of failed login:' => '',
+ // 'Account locked until:' => '',
);
diff --git a/app/Locale/zh_CN/translations.php b/app/Locale/zh_CN/translations.php
index fc3fcbfc..2a4d1b1b 100644
--- a/app/Locale/zh_CN/translations.php
+++ b/app/Locale/zh_CN/translations.php
@@ -170,7 +170,6 @@ return array(
'Leave a description' => '给一个描述',
'Comment added successfully.' => '评论成功添加。',
'Unable to create your comment.' => '无法创建评论。',
- 'Edit this task' => '编辑该任务',
'Due Date' => '到期时间',
'Invalid date' => '无效日期',
'Automatic actions' => '自动动作',
@@ -517,7 +516,6 @@ return array(
'All swimlanes' => '全部里程碑',
'All colors' => '全部颜色',
'Moved to column %s' => '移动到栏目 %s',
- 'Change description' => '修改描述',
'User dashboard' => '用户仪表板',
'Allow only one subtask in progress at the same time for a user' => '每用户同时仅有一个活动子任务',
'Edit column "%s"' => '编辑栏目"%s"',
@@ -709,7 +707,6 @@ return array(
'view the board on Kanboard' => '在看板上查看面板',
'The task have been moved to the first swimlane' => '该任务已被移动到首个里程碑',
'The task have been moved to another swimlane:' => '该任务已被移动到别的里程碑:',
- // 'Overdue tasks for the project(s) "%s"' => '"%s"项目下的超期任务',
'New title: %s' => '新标题:%s',
'The task is not assigned anymore' => '该任务没有指派人',
'New assignee: %s' => '新指派到:%s',
@@ -738,7 +735,6 @@ return array(
'Stop timer' => '停止计时器',
'Start timer' => '开启计时器',
'Add project member' => '添加项目成员',
- 'Enable notifications' => '打开通知',
'My activity stream' => '我的活动流',
'My calendar' => '我的日程表',
'Search tasks' => '搜索任务',
@@ -1167,4 +1163,41 @@ return array(
// 'Projects where "%s" is member' => '',
// 'Open tasks assigned to "%s"' => '',
// 'Closed tasks assigned to "%s"' => '',
+ // 'Assign automatically a color based on a priority' => '',
+ // 'Overdue tasks for the project(s) "%s"' => '',
+ // 'Upload files' => '',
+ // 'Installed Plugins' => '',
+ // 'Plugin Directory' => '',
+ // 'Plugin installed successfully.' => '',
+ // 'Plugin updated successfully.' => '',
+ // 'Plugin removed successfully.' => '',
+ // 'Subtask converted to task successfully.' => '',
+ // 'Unable to convert the subtask.' => '',
+ // 'Unable to extract plugin archive.' => '',
+ // 'Plugin not found.' => '',
+ // 'You don\'t have the permission to remove this plugin.' => '',
+ // 'Unable to download plugin archive.' => '',
+ // 'Unable to write temporary file for plugin.' => '',
+ // 'Unable to open plugin archive.' => '',
+ // 'There is no file in the plugin archive.' => '',
+ // 'Create tasks in bulk' => '',
+ // 'Your Kanboard instance is not configured to install plugins from the user interface.' => '',
+ // 'There is no plugin available.' => '',
+ // 'Install' => '',
+ // 'Update' => '',
+ // 'Up to date' => '',
+ // 'Not available' => '',
+ // 'Remove plugin' => '',
+ // 'Do you really want to remove this plugin: "%s"?' => '',
+ // 'Uninstall' => '',
+ // 'Listing' => '',
+ // 'Metadata' => '',
+ // 'Manage projects' => '',
+ // 'Convert to task' => '',
+ // 'Convert sub-task to task' => '',
+ // 'Do you really want to convert this sub-task to a task?' => '',
+ // 'My task title' => '',
+ // 'Enter one task by line.' => '',
+ // 'Number of failed login:' => '',
+ // 'Account locked until:' => '',
);
diff --git a/app/Middleware/ApplicationAuthorizationMiddleware.php b/app/Middleware/ApplicationAuthorizationMiddleware.php
new file mode 100644
index 00000000..faca2d6a
--- /dev/null
+++ b/app/Middleware/ApplicationAuthorizationMiddleware.php
@@ -0,0 +1,27 @@
+<?php
+
+namespace Kanboard\Middleware;
+
+use Kanboard\Core\Controller\AccessForbiddenException;
+use Kanboard\Core\Controller\BaseMiddleware;
+
+/**
+ * Class ApplicationAuthorizationMiddleware
+ *
+ * @package Kanboard\Middleware
+ * @author Frederic Guillot
+ */
+class ApplicationAuthorizationMiddleware extends BaseMiddleware
+{
+ /**
+ * Execute middleware
+ */
+ public function execute()
+ {
+ if (! $this->helper->user->hasAccess($this->router->getController(), $this->router->getAction())) {
+ throw new AccessForbiddenException();
+ }
+
+ $this->next();
+ }
+}
diff --git a/app/Middleware/AuthenticationMiddleware.php b/app/Middleware/AuthenticationMiddleware.php
new file mode 100644
index 00000000..499843fd
--- /dev/null
+++ b/app/Middleware/AuthenticationMiddleware.php
@@ -0,0 +1,56 @@
+<?php
+
+namespace Kanboard\Middleware;
+
+use Kanboard\Core\Controller\AccessForbiddenException;
+use Kanboard\Core\Controller\BaseMiddleware;
+use Kanboard\Core\Security\Role;
+
+/**
+ * Class AuthenticationMiddleware
+ *
+ * @package Kanboard\Middleware
+ * @author Frederic Guillot
+ */
+class AuthenticationMiddleware extends BaseMiddleware
+{
+ /**
+ * Execute middleware
+ */
+ public function execute()
+ {
+ if (! $this->authenticationManager->checkCurrentSession()) {
+ throw AccessForbiddenException::getInstance()->withoutLayout();
+ }
+
+ if (! $this->isPublicAccess()) {
+ $this->handleAuthentication();
+ }
+
+ $this->next();
+ }
+
+ protected function handleAuthentication()
+ {
+ if (! $this->userSession->isLogged() && ! $this->authenticationManager->preAuthentication()) {
+ $this->nextMiddleware = null;
+
+ if ($this->request->isAjax()) {
+ $this->response->text('Not Authorized', 401);
+ } else {
+ $this->sessionStorage->redirectAfterLogin = $this->request->getUri();
+ $this->response->redirect($this->helper->url->to('AuthController', 'login'));
+ }
+ }
+ }
+
+ protected function isPublicAccess()
+ {
+ if ($this->applicationAuthorization->isAllowed($this->router->getController(), $this->router->getAction(), Role::APP_PUBLIC)) {
+ $this->nextMiddleware = null;
+ return true;
+ }
+
+ return false;
+ }
+}
diff --git a/app/Middleware/BootstrapMiddleware.php b/app/Middleware/BootstrapMiddleware.php
new file mode 100644
index 00000000..727f600c
--- /dev/null
+++ b/app/Middleware/BootstrapMiddleware.php
@@ -0,0 +1,44 @@
+<?php
+
+namespace Kanboard\Middleware;
+
+use Kanboard\Core\Controller\BaseMiddleware;
+
+/**
+ * Class BootstrapMiddleware
+ *
+ * @package Kanboard\Middleware
+ * @author Frederic Guillot
+ */
+class BootstrapMiddleware extends BaseMiddleware
+{
+ /**
+ * Execute middleware
+ */
+ public function execute()
+ {
+ $this->sessionManager->open();
+ $this->dispatcher->dispatch('app.bootstrap');
+ $this->sendHeaders();
+ $this->next();
+ }
+
+ /**
+ * Send HTTP headers
+ *
+ * @access private
+ */
+ private function sendHeaders()
+ {
+ $this->response->withContentSecurityPolicy($this->container['cspRules']);
+ $this->response->withSecurityHeaders();
+
+ if (ENABLE_XFRAME) {
+ $this->response->withXframe();
+ }
+
+ if (ENABLE_HSTS) {
+ $this->response->withStrictTransportSecurity();
+ }
+ }
+}
diff --git a/app/Middleware/PostAuthenticationMiddleware.php b/app/Middleware/PostAuthenticationMiddleware.php
new file mode 100644
index 00000000..f7eccbce
--- /dev/null
+++ b/app/Middleware/PostAuthenticationMiddleware.php
@@ -0,0 +1,36 @@
+<?php
+
+namespace Kanboard\Middleware;
+
+use Kanboard\Core\Controller\BaseMiddleware;
+
+/**
+ * Class PostAuthenticationMiddleware
+ *
+ * @package Kanboard\Middleware
+ * @author Frederic Guillot
+ */
+class PostAuthenticationMiddleware extends BaseMiddleware
+{
+ /**
+ * Execute middleware
+ */
+ public function execute()
+ {
+ $controller = strtolower($this->router->getController());
+ $action = strtolower($this->router->getAction());
+ $ignore = ($controller === 'twofactorcontroller' && in_array($action, array('code', 'check'))) || ($controller === 'authcontroller' && $action === 'logout');
+
+ if ($ignore === false && $this->userSession->hasPostAuthentication() && ! $this->userSession->isPostAuthenticationValidated()) {
+ $this->nextMiddleware = null;
+
+ if ($this->request->isAjax()) {
+ $this->response->text('Not Authorized', 401);
+ }
+
+ $this->response->redirect($this->helper->url->to('TwoFactorController', 'code'));
+ }
+
+ $this->next();
+ }
+}
diff --git a/app/Middleware/ProjectAuthorizationMiddleware.php b/app/Middleware/ProjectAuthorizationMiddleware.php
new file mode 100644
index 00000000..704491b7
--- /dev/null
+++ b/app/Middleware/ProjectAuthorizationMiddleware.php
@@ -0,0 +1,34 @@
+<?php
+
+namespace Kanboard\Middleware;
+
+use Kanboard\Core\Controller\AccessForbiddenException;
+use Kanboard\Core\Controller\BaseMiddleware;
+
+/**
+ * Class ProjectAuthorizationMiddleware
+ *
+ * @package Kanboard\Middleware
+ * @author Frederic Guillot
+ */
+class ProjectAuthorizationMiddleware extends BaseMiddleware
+{
+ /**
+ * Execute middleware
+ */
+ public function execute()
+ {
+ $project_id = $this->request->getIntegerParam('project_id');
+ $task_id = $this->request->getIntegerParam('task_id');
+
+ if ($task_id > 0 && $project_id === 0) {
+ $project_id = $this->taskFinderModel->getProjectId($task_id);
+ }
+
+ if ($project_id > 0 && ! $this->helper->user->hasProjectAccess($this->router->getController(), $this->router->getAction(), $project_id)) {
+ throw new AccessForbiddenException();
+ }
+
+ $this->next();
+ }
+}
diff --git a/app/Model/Action.php b/app/Model/ActionModel.php
index f055d9d0..53393ed5 100644
--- a/app/Model/Action.php
+++ b/app/Model/ActionModel.php
@@ -2,13 +2,15 @@
namespace Kanboard\Model;
+use Kanboard\Core\Base;
+
/**
* Action Model
*
- * @package model
+ * @package Kanboard\Model
* @author Frederic Guillot
*/
-class Action extends Base
+class ActionModel extends Base
{
/**
* SQL table name for actions
@@ -26,12 +28,12 @@ class Action extends Base
*/
public function getAllByUser($user_id)
{
- $project_ids = $this->projectPermission->getActiveProjectIds($user_id);
+ $project_ids = $this->projectPermissionModel->getActiveProjectIds($user_id);
$actions = array();
if (! empty($project_ids)) {
$actions = $this->db->table(self::TABLE)->in('project_id', $project_ids)->findAll();
- $params = $this->actionParameter->getAllByActions(array_column($actions, 'id'));
+ $params = $this->actionParameterModel->getAllByActions(array_column($actions, 'id'));
$this->attachParamsToActions($actions, $params);
}
@@ -48,7 +50,7 @@ class Action extends Base
public function getAllByProject($project_id)
{
$actions = $this->db->table(self::TABLE)->eq('project_id', $project_id)->findAll();
- $params = $this->actionParameter->getAllByActions(array_column($actions, 'id'));
+ $params = $this->actionParameterModel->getAllByActions(array_column($actions, 'id'));
return $this->attachParamsToActions($actions, $params);
}
@@ -61,7 +63,7 @@ class Action extends Base
public function getAll()
{
$actions = $this->db->table(self::TABLE)->findAll();
- $params = $this->actionParameter->getAll();
+ $params = $this->actionParameterModel->getAll();
return $this->attachParamsToActions($actions, $params);
}
@@ -77,7 +79,7 @@ class Action extends Base
$action = $this->db->table(self::TABLE)->eq('id', $action_id)->findOne();
if (! empty($action)) {
- $action['params'] = $this->actionParameter->getAllByAction($action_id);
+ $action['params'] = $this->actionParameterModel->getAllByAction($action_id);
}
return $action;
@@ -136,7 +138,7 @@ class Action extends Base
$action_id = $this->db->getLastId();
- if (! $this->actionParameter->create($action_id, $values)) {
+ if (! $this->actionParameterModel->create($action_id, $values)) {
$this->db->cancelTransaction();
return false;
}
@@ -156,7 +158,7 @@ class Action extends Base
*/
public function duplicate($src_project_id, $dst_project_id)
{
- $actions = $this->action->getAllByProject($src_project_id);
+ $actions = $this->actionModel->getAllByProject($src_project_id);
foreach ($actions as $action) {
$this->db->startTransaction();
@@ -174,7 +176,7 @@ class Action extends Base
$action_id = $this->db->getLastId();
- if (! $this->actionParameter->duplicateParameters($dst_project_id, $action_id, $action['params'])) {
+ if (! $this->actionParameterModel->duplicateParameters($dst_project_id, $action_id, $action['params'])) {
$this->logger->error('Action::duplicate => skip action '.$action['action_name'].' '.$action['id']);
$this->db->cancelTransaction();
continue;
diff --git a/app/Model/ActionParameter.php b/app/Model/ActionParameterModel.php
index 53edcbc8..9895da0f 100644
--- a/app/Model/ActionParameter.php
+++ b/app/Model/ActionParameterModel.php
@@ -2,13 +2,15 @@
namespace Kanboard\Model;
+use Kanboard\Core\Base;
+
/**
* Action Parameter Model
*
- * @package model
+ * @package Kanboard\Model
* @author Frederic Guillot
*/
-class ActionParameter extends Base
+class ActionParameterModel extends Base
{
/**
* SQL table name
@@ -145,16 +147,16 @@ class ActionParameter extends Base
case 'project_id':
return $value != $project_id ? $value : false;
case 'category_id':
- return $this->category->getIdByName($project_id, $this->category->getNameById($value)) ?: false;
+ return $this->categoryModel->getIdByName($project_id, $this->categoryModel->getNameById($value)) ?: false;
case 'src_column_id':
case 'dest_column_id':
case 'dst_column_id':
case 'column_id':
- $column = $this->column->getById($value);
- return empty($column) ? false : $this->column->getColumnIdByTitle($project_id, $column['title']) ?: false;
+ $column = $this->columnModel->getById($value);
+ return empty($column) ? false : $this->columnModel->getColumnIdByTitle($project_id, $column['title']) ?: false;
case 'user_id':
case 'owner_id':
- return $this->projectPermission->isAssignable($project_id, $value) ? $value : false;
+ return $this->projectPermissionModel->isAssignable($project_id, $value) ? $value : false;
default:
return $value;
}
diff --git a/app/Model/AvatarFile.php b/app/Model/AvatarFileModel.php
index c49f9fd5..6e36d83f 100644
--- a/app/Model/AvatarFile.php
+++ b/app/Model/AvatarFileModel.php
@@ -3,14 +3,15 @@
namespace Kanboard\Model;
use Exception;
+use Kanboard\Core\Base;
/**
* Avatar File
*
- * @package model
+ * @package Kanboard\Model
* @author Frederic Guillot
*/
-class AvatarFile extends Base
+class AvatarFileModel extends Base
{
/**
* Path prefix
@@ -28,7 +29,7 @@ class AvatarFile extends Base
*/
public function getFilename($user_id)
{
- return $this->db->table(User::TABLE)->eq('id', $user_id)->findOneColumn('avatar_path');
+ return $this->db->table(UserModel::TABLE)->eq('id', $user_id)->findOneColumn('avatar_path');
}
/**
@@ -41,7 +42,7 @@ class AvatarFile extends Base
*/
public function create($user_id, $path)
{
- $result = $this->db->table(User::TABLE)->eq('id', $user_id)->update(array(
+ $result = $this->db->table(UserModel::TABLE)->eq('id', $user_id)->update(array(
'avatar_path' => $path,
));
@@ -60,31 +61,35 @@ class AvatarFile extends Base
public function remove($user_id)
{
try {
- $this->objectStorage->remove($this->getFilename($user_id));
- $result = $this->db->table(User::TABLE)->eq('id', $user_id)->update(array('avatar_path' => ''));
- $this->userSession->refresh($user_id);
- return $result;
+ $filename = $this->getFilename($user_id);
+
+ if (! empty($filename)) {
+ $this->objectStorage->remove($filename);
+ return $this->db->table(UserModel::TABLE)->eq('id', $user_id)->update(array('avatar_path' => ''));
+ }
} catch (Exception $e) {
$this->logger->error($e->getMessage());
return false;
}
+
+ return true;
}
/**
- * Upload avatar image
+ * Upload avatar image file
*
* @access public
* @param integer $user_id
* @param array $file
* @return boolean
*/
- public function uploadFile($user_id, array $file)
+ public function uploadImageFile($user_id, array $file)
{
try {
if ($file['error'] == UPLOAD_ERR_OK && $file['size'] > 0) {
- $destination_filename = $this->generatePath($user_id, $file['name']);
- $this->objectStorage->moveUploadedFile($file['tmp_name'], $destination_filename);
- $this->create($user_id, $destination_filename);
+ $destinationFilename = $this->generatePath($user_id, $file['name']);
+ $this->objectStorage->moveUploadedFile($file['tmp_name'], $destinationFilename);
+ $this->create($user_id, $destinationFilename);
} else {
throw new Exception('File not uploaded: '.var_export($file['error'], true));
}
@@ -98,6 +103,28 @@ class AvatarFile extends Base
}
/**
+ * Upload avatar image content
+ *
+ * @access public
+ * @param integer $user_id
+ * @param string $blob
+ * @return boolean
+ */
+ public function uploadImageContent($user_id, &$blob)
+ {
+ try {
+ $destinationFilename = $this->generatePath($user_id, 'imageContent');
+ $this->objectStorage->put($destinationFilename, $blob);
+ $this->create($user_id, $destinationFilename);
+ } catch (Exception $e) {
+ $this->logger->error($e->getMessage());
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
* Generate the path for a new filename
*
* @access public
diff --git a/app/Model/Base.php b/app/Model/Base.php
deleted file mode 100644
index a27560c8..00000000
--- a/app/Model/Base.php
+++ /dev/null
@@ -1,34 +0,0 @@
-<?php
-
-namespace Kanboard\Model;
-
-use PicoDb\Database;
-
-/**
- * Base model class
- *
- * @package model
- * @author Frederic Guillot
- */
-abstract class Base extends \Kanboard\Core\Base
-{
- /**
- * Save a record in the database
- *
- * @access public
- * @param string $table Table name
- * @param array $values Form values
- * @return boolean|integer
- */
- public function persist($table, array $values)
- {
- return $this->db->transaction(function (Database $db) use ($table, $values) {
-
- if (! $db->table($table)->save($values)) {
- return false;
- }
-
- return (int) $db->getLastId();
- });
- }
-}
diff --git a/app/Model/Board.php b/app/Model/BoardModel.php
index d41ecafe..d2718b47 100644
--- a/app/Model/Board.php
+++ b/app/Model/BoardModel.php
@@ -2,13 +2,15 @@
namespace Kanboard\Model;
+use Kanboard\Core\Base;
+
/**
* Board model
*
- * @package model
+ * @package Kanboard\Model
* @author Frederic Guillot
*/
-class Board extends Base
+class BoardModel extends Base
{
/**
* Get Kanboard default columns
@@ -29,7 +31,7 @@ class Board extends Base
*/
public function getUserColumns()
{
- $column_names = explode(',', $this->config->get('board_columns', implode(',', $this->getDefaultColumns())));
+ $column_names = explode(',', $this->configModel->get('board_columns', implode(',', $this->getDefaultColumns())));
$columns = array();
foreach ($column_names as $column_name) {
@@ -64,7 +66,7 @@ class Board extends Base
'description' => $column['description'],
);
- if (! $this->db->table(Column::TABLE)->save($values)) {
+ if (! $this->db->table(ColumnModel::TABLE)->save($values)) {
return false;
}
}
@@ -82,13 +84,13 @@ class Board extends Base
*/
public function duplicate($project_from, $project_to)
{
- $columns = $this->db->table(Column::TABLE)
+ $columns = $this->db->table(ColumnModel::TABLE)
->columns('title', 'task_limit', 'description')
->eq('project_id', $project_from)
->asc('position')
->findAll();
- return $this->board->create($project_to, $columns);
+ return $this->boardModel->create($project_to, $columns);
}
/**
@@ -101,8 +103,8 @@ class Board extends Base
*/
public function getBoard($project_id, $callback = null)
{
- $swimlanes = $this->swimlane->getSwimlanes($project_id);
- $columns = $this->column->getAll($project_id);
+ $swimlanes = $this->swimlaneModel->getSwimlanes($project_id);
+ $columns = $this->columnModel->getAll($project_id);
$nb_columns = count($columns);
for ($i = 0, $ilen = count($swimlanes); $i < $ilen; $i++) {
@@ -120,7 +122,7 @@ class Board extends Base
$swimlanes[0]['columns'][$j]['total_score'] = 0;
}
- $swimlanes[$i]['columns'][$j]['tasks'] = $callback === null ? $this->taskFinder->getTasksByColumnAndSwimlane($project_id, $column_id, $swimlane_id) : $callback($project_id, $column_id, $swimlane_id);
+ $swimlanes[$i]['columns'][$j]['tasks'] = $callback === null ? $this->taskFinderModel->getTasksByColumnAndSwimlane($project_id, $column_id, $swimlane_id) : $callback($project_id, $column_id, $swimlane_id);
$swimlanes[$i]['columns'][$j]['nb_tasks'] = count($swimlanes[$i]['columns'][$j]['tasks']);
$swimlanes[$i]['columns'][$j]['score'] = $this->getColumnSum($swimlanes[$i]['columns'][$j]['tasks'], 'score');
$swimlanes[$i]['nb_tasks'] += $swimlanes[$i]['columns'][$j]['nb_tasks'];
@@ -162,7 +164,7 @@ class Board extends Base
public function getColumnStats($project_id, $prepend = false)
{
$listing = $this->db
- ->hashtable(Task::TABLE)
+ ->hashtable(TaskModel::TABLE)
->eq('project_id', $project_id)
->eq('is_active', 1)
->groupBy('column_id')
diff --git a/app/Model/Category.php b/app/Model/CategoryModel.php
index 1d5f6546..62fb5611 100644
--- a/app/Model/Category.php
+++ b/app/Model/CategoryModel.php
@@ -2,13 +2,15 @@
namespace Kanboard\Model;
+use Kanboard\Core\Base;
+
/**
* Category model
*
- * @package model
+ * @package Kanboard\Model
* @author Frederic Guillot
*/
-class Category extends Base
+class CategoryModel extends Base
{
/**
* SQL table name
@@ -123,7 +125,7 @@ class Category extends Base
public function createDefaultCategories($project_id)
{
$results = array();
- $categories = explode(',', $this->config->get('project_categories'));
+ $categories = explode(',', $this->configModel->get('project_categories'));
foreach ($categories as $category) {
$category = trim($category);
@@ -148,7 +150,7 @@ class Category extends Base
*/
public function create(array $values)
{
- return $this->persist(self::TABLE, $values);
+ return $this->db->table(self::TABLE)->persist($values);
}
/**
@@ -174,7 +176,7 @@ class Category extends Base
{
$this->db->startTransaction();
- $this->db->table(Task::TABLE)->eq('category_id', $category_id)->update(array('category_id' => 0));
+ $this->db->table(TaskModel::TABLE)->eq('category_id', $category_id)->update(array('category_id' => 0));
if (! $this->db->table(self::TABLE)->eq('id', $category_id)->remove()) {
$this->db->cancelTransaction();
diff --git a/app/Model/Color.php b/app/Model/ColorModel.php
index dee28643..9e69dda2 100644
--- a/app/Model/Color.php
+++ b/app/Model/ColorModel.php
@@ -2,13 +2,15 @@
namespace Kanboard\Model;
+use Kanboard\Core\Base;
+
/**
* Color model
*
- * @package model
+ * @package Kanboard\Model
* @author Frederic Guillot
*/
-class Color extends Base
+class ColorModel extends Base
{
/**
* Default colors
@@ -163,7 +165,7 @@ class Color extends Base
*/
public function getDefaultColor()
{
- return $this->config->get('default_color', 'yellow');
+ return $this->configModel->get('default_color', 'yellow');
}
/**
diff --git a/app/Model/Column.php b/app/Model/ColumnModel.php
index ccdcb049..1adac0f2 100644
--- a/app/Model/Column.php
+++ b/app/Model/ColumnModel.php
@@ -2,13 +2,15 @@
namespace Kanboard\Model;
+use Kanboard\Core\Base;
+
/**
* Column Model
*
- * @package model
+ * @package Kanboard\Model
* @author Frederic Guillot
*/
-class Column extends Base
+class ColumnModel extends Base
{
/**
* SQL table name
@@ -140,7 +142,7 @@ class Column extends Base
'description' => $description,
);
- return $this->persist(self::TABLE, $values);
+ return $this->db->table(self::TABLE)->persist($values);
}
/**
diff --git a/app/Model/Comment.php b/app/Model/CommentModel.php
index c5091d89..36e1fc48 100644
--- a/app/Model/Comment.php
+++ b/app/Model/CommentModel.php
@@ -3,14 +3,15 @@
namespace Kanboard\Model;
use Kanboard\Event\CommentEvent;
+use Kanboard\Core\Base;
/**
* Comment model
*
- * @package model
+ * @package Kanboard\Model
* @author Frederic Guillot
*/
-class Comment extends Base
+class CommentModel extends Base
{
/**
* SQL table name
@@ -46,12 +47,12 @@ class Comment extends Base
self::TABLE.'.task_id',
self::TABLE.'.user_id',
self::TABLE.'.comment',
- User::TABLE.'.username',
- User::TABLE.'.name',
- User::TABLE.'.email',
- User::TABLE.'.avatar_path'
+ UserModel::TABLE.'.username',
+ UserModel::TABLE.'.name',
+ UserModel::TABLE.'.email',
+ UserModel::TABLE.'.avatar_path'
)
- ->join(User::TABLE, 'id', 'user_id')
+ ->join(UserModel::TABLE, 'id', 'user_id')
->orderBy(self::TABLE.'.date_creation', $sorting)
->eq(self::TABLE.'.task_id', $task_id)
->findAll();
@@ -75,12 +76,12 @@ class Comment extends Base
self::TABLE.'.date_creation',
self::TABLE.'.comment',
self::TABLE.'.reference',
- User::TABLE.'.username',
- User::TABLE.'.name',
- User::TABLE.'.email',
- User::TABLE.'.avatar_path'
+ UserModel::TABLE.'.username',
+ UserModel::TABLE.'.name',
+ UserModel::TABLE.'.email',
+ UserModel::TABLE.'.avatar_path'
)
- ->join(User::TABLE, 'id', 'user_id')
+ ->join(UserModel::TABLE, 'id', 'user_id')
->eq(self::TABLE.'.id', $comment_id)
->findOne();
}
@@ -110,12 +111,12 @@ class Comment extends Base
public function create(array $values)
{
$values['date_creation'] = time();
- $comment_id = $this->persist(self::TABLE, $values);
+ $comment_id = $this->db->table(self::TABLE)->persist($values);
- if ($comment_id) {
+ if ($comment_id !== false) {
$event = new CommentEvent(array('id' => $comment_id) + $values);
$this->dispatcher->dispatch(self::EVENT_CREATE, $event);
- $this->userMention->fireEvents($values['comment'], self::EVENT_USER_MENTION, $event);
+ $this->userMentionModel->fireEvents($values['comment'], self::EVENT_USER_MENTION, $event);
}
return $comment_id;
diff --git a/app/Model/Config.php b/app/Model/Config.php
deleted file mode 100644
index 0c363fb0..00000000
--- a/app/Model/Config.php
+++ /dev/null
@@ -1,255 +0,0 @@
-<?php
-
-namespace Kanboard\Model;
-
-use Kanboard\Core\Translator;
-use Kanboard\Core\Security\Token;
-
-/**
- * Config model
- *
- * @package model
- * @author Frederic Guillot
- */
-class Config extends Setting
-{
- /**
- * Get available timezones
- *
- * @access public
- * @param boolean $prepend Prepend a default value
- * @return array
- */
- public function getTimezones($prepend = false)
- {
- $timezones = timezone_identifiers_list();
- $listing = array_combine(array_values($timezones), $timezones);
-
- if ($prepend) {
- return array('' => t('Application default')) + $listing;
- }
-
- return $listing;
- }
-
- /**
- * Get current timezone
- *
- * @access public
- * @return string
- */
- public function getCurrentTimezone()
- {
- if ($this->userSession->isLogged() && ! empty($this->sessionStorage->user['timezone'])) {
- return $this->sessionStorage->user['timezone'];
- }
-
- return $this->get('application_timezone', 'UTC');
- }
-
- /**
- * Set timezone
- *
- * @access public
- */
- public function setupTimezone()
- {
- date_default_timezone_set($this->getCurrentTimezone());
- }
-
- /**
- * Get available languages
- *
- * @access public
- * @param boolean $prepend Prepend a default value
- * @return array
- */
- public function getLanguages($prepend = false)
- {
- // Sorted by value
- $languages = array(
- 'id_ID' => 'Bahasa Indonesia',
- 'bs_BA' => 'Bosanski',
- 'cs_CZ' => 'Čeština',
- 'da_DK' => 'Dansk',
- 'de_DE' => 'Deutsch',
- 'en_US' => 'English',
- 'es_ES' => 'Español',
- 'fr_FR' => 'Français',
- 'el_GR' => 'Grec',
- 'it_IT' => 'Italiano',
- 'hu_HU' => 'Magyar',
- 'my_MY' => 'Melayu',
- 'nl_NL' => 'Nederlands',
- 'nb_NO' => 'Norsk',
- 'pl_PL' => 'Polski',
- 'pt_PT' => 'Português',
- 'pt_BR' => 'Português (Brasil)',
- 'ru_RU' => 'Русский',
- 'sr_Latn_RS' => 'Srpski',
- 'fi_FI' => 'Suomi',
- 'sv_SE' => 'Svenska',
- 'tr_TR' => 'Türkçe',
- 'ko_KR' => '한국어',
- 'zh_CN' => '中文(简体)',
- 'ja_JP' => '日本語',
- 'th_TH' => 'ไทย',
- );
-
- if ($prepend) {
- return array('' => t('Application default')) + $languages;
- }
-
- return $languages;
- }
-
- /**
- * Get javascript language code
- *
- * @access public
- * @return string
- */
- public function getJsLanguageCode()
- {
- $languages = array(
- 'cs_CZ' => 'cs',
- 'da_DK' => 'da',
- 'de_DE' => 'de',
- 'en_US' => 'en',
- 'es_ES' => 'es',
- 'fr_FR' => 'fr',
- 'it_IT' => 'it',
- 'hu_HU' => 'hu',
- 'nl_NL' => 'nl',
- 'nb_NO' => 'nb',
- 'pl_PL' => 'pl',
- 'pt_PT' => 'pt',
- 'pt_BR' => 'pt-br',
- 'ru_RU' => 'ru',
- 'sr_Latn_RS' => 'sr',
- 'fi_FI' => 'fi',
- 'sv_SE' => 'sv',
- 'tr_TR' => 'tr',
- 'ko_KR' => 'ko',
- 'zh_CN' => 'zh-cn',
- 'ja_JP' => 'ja',
- 'th_TH' => 'th',
- 'id_ID' => 'id',
- 'el_GR' => 'el',
- );
-
- $lang = $this->getCurrentLanguage();
-
- return isset($languages[$lang]) ? $languages[$lang] : 'en';
- }
-
- /**
- * Get current language
- *
- * @access public
- * @return string
- */
- public function getCurrentLanguage()
- {
- if ($this->userSession->isLogged() && ! empty($this->sessionStorage->user['language'])) {
- return $this->sessionStorage->user['language'];
- }
-
- return $this->get('application_language', 'en_US');
- }
-
- /**
- * Load translations
- *
- * @access public
- */
- public function setupTranslations()
- {
- Translator::load($this->getCurrentLanguage());
- }
-
- /**
- * Get a config variable from the session or the database
- *
- * @access public
- * @param string $name Parameter name
- * @param string $default_value Default value of the parameter
- * @return string
- */
- public function get($name, $default_value = '')
- {
- $options = $this->memoryCache->proxy($this, 'getAll');
- return isset($options[$name]) && $options[$name] !== '' ? $options[$name] : $default_value;
- }
-
- /**
- * Reload settings in the session and the translations
- *
- * @access public
- */
- public function reload()
- {
- $this->setupTranslations();
- }
-
- /**
- * Optimize the Sqlite database
- *
- * @access public
- * @return boolean
- */
- public function optimizeDatabase()
- {
- return $this->db->getconnection()->exec('VACUUM');
- }
-
- /**
- * Compress the Sqlite database
- *
- * @access public
- * @return string
- */
- public function downloadDatabase()
- {
- return gzencode(file_get_contents(DB_FILENAME));
- }
-
- /**
- * Get the Sqlite database size in bytes
- *
- * @access public
- * @return integer
- */
- public function getDatabaseSize()
- {
- return DB_DRIVER === 'sqlite' ? filesize(DB_FILENAME) : 0;
- }
-
- /**
- * Regenerate a token
- *
- * @access public
- * @param string $option Parameter name
- * @return boolean
- */
- public function regenerateToken($option)
- {
- return $this->save(array($option => Token::getToken()));
- }
-
- /**
- * Prepare data before save
- *
- * @access public
- * @param array $values
- * @return array
- */
- public function prepare(array $values)
- {
- if (! empty($values['application_url']) && substr($values['application_url'], -1) !== '/') {
- $values['application_url'] = $values['application_url'].'/';
- }
-
- return $values;
- }
-}
diff --git a/app/Model/ConfigModel.php b/app/Model/ConfigModel.php
new file mode 100644
index 00000000..945c5e6f
--- /dev/null
+++ b/app/Model/ConfigModel.php
@@ -0,0 +1,89 @@
+<?php
+
+namespace Kanboard\Model;
+
+use Kanboard\Core\Security\Token;
+
+/**
+ * Config model
+ *
+ * @package Kanboard\Model
+ * @author Frederic Guillot
+ */
+class ConfigModel extends SettingModel
+{
+ /**
+ * Get a config variable with in-memory caching
+ *
+ * @access public
+ * @param string $name Parameter name
+ * @param string $default_value Default value of the parameter
+ * @return string
+ */
+ public function get($name, $default_value = '')
+ {
+ $options = $this->memoryCache->proxy($this, 'getAll');
+ return isset($options[$name]) && $options[$name] !== '' ? $options[$name] : $default_value;
+ }
+
+ /**
+ * Optimize the Sqlite database
+ *
+ * @access public
+ * @return boolean
+ */
+ public function optimizeDatabase()
+ {
+ return $this->db->getConnection()->exec('VACUUM');
+ }
+
+ /**
+ * Compress the Sqlite database
+ *
+ * @access public
+ * @return string
+ */
+ public function downloadDatabase()
+ {
+ return gzencode(file_get_contents(DB_FILENAME));
+ }
+
+ /**
+ * Get the Sqlite database size in bytes
+ *
+ * @access public
+ * @return integer
+ */
+ public function getDatabaseSize()
+ {
+ return DB_DRIVER === 'sqlite' ? filesize(DB_FILENAME) : 0;
+ }
+
+ /**
+ * Regenerate a token
+ *
+ * @access public
+ * @param string $option Parameter name
+ * @return boolean
+ */
+ public function regenerateToken($option)
+ {
+ return $this->save(array($option => Token::getToken()));
+ }
+
+ /**
+ * Prepare data before save
+ *
+ * @access public
+ * @param array $values
+ * @return array
+ */
+ public function prepare(array $values)
+ {
+ if (! empty($values['application_url']) && substr($values['application_url'], -1) !== '/') {
+ $values['application_url'] = $values['application_url'].'/';
+ }
+
+ return $values;
+ }
+}
diff --git a/app/Model/Currency.php b/app/Model/CurrencyModel.php
index abcce2f0..bfd9697c 100644
--- a/app/Model/Currency.php
+++ b/app/Model/CurrencyModel.php
@@ -2,13 +2,15 @@
namespace Kanboard\Model;
+use Kanboard\Core\Base;
+
/**
* Currency
*
- * @package model
+ * @package Kanboard\Model
* @author Frederic Guillot
*/
-class Currency extends Base
+class CurrencyModel extends Base
{
/**
* SQL table name
@@ -65,7 +67,7 @@ class Currency extends Base
public function getPrice($currency, $price)
{
static $rates = null;
- $reference = $this->config->get('application_currency', 'USD');
+ $reference = $this->configModel->get('application_currency', 'USD');
if ($reference !== $currency) {
$rates = $rates === null ? $this->db->hashtable(self::TABLE)->getAll('currency', 'rate') : $rates;
diff --git a/app/Model/CustomFilter.php b/app/Model/CustomFilterModel.php
index 3a6a1a3a..a4c23b5c 100644
--- a/app/Model/CustomFilter.php
+++ b/app/Model/CustomFilterModel.php
@@ -2,13 +2,15 @@
namespace Kanboard\Model;
+use Kanboard\Core\Base;
+
/**
* Custom Filter model
*
- * @package model
+ * @package Kanboard\Model
* @author Timo Litzbarski
*/
-class CustomFilter extends Base
+class CustomFilterModel extends Base
{
/**
* SQL table name
@@ -30,8 +32,8 @@ class CustomFilter extends Base
return $this->db
->table(self::TABLE)
->columns(
- User::TABLE.'.name as owner_name',
- User::TABLE.'.username as owner_username',
+ UserModel::TABLE.'.name as owner_name',
+ UserModel::TABLE.'.username as owner_username',
self::TABLE.'.id',
self::TABLE.'.user_id',
self::TABLE.'.project_id',
@@ -41,7 +43,7 @@ class CustomFilter extends Base
self::TABLE.'.append'
)
->asc(self::TABLE.'.name')
- ->join(User::TABLE, 'id', 'user_id')
+ ->join(UserModel::TABLE, 'id', 'user_id')
->beginOr()
->eq('is_shared', 1)
->eq('user_id', $user_id)
@@ -71,7 +73,7 @@ class CustomFilter extends Base
*/
public function create(array $values)
{
- return $this->persist(self::TABLE, $values);
+ return $this->db->table(self::TABLE)->persist($values);
}
/**
diff --git a/app/Model/File.php b/app/Model/FileModel.php
index e383235c..8cdea9a0 100644
--- a/app/Model/File.php
+++ b/app/Model/FileModel.php
@@ -3,6 +3,7 @@
namespace Kanboard\Model;
use Exception;
+use Kanboard\Core\Base;
use Kanboard\Core\Thumbnail;
use Kanboard\Event\FileEvent;
use Kanboard\Core\ObjectStorage\ObjectStorageException;
@@ -10,12 +11,48 @@ use Kanboard\Core\ObjectStorage\ObjectStorageException;
/**
* Base File Model
*
- * @package model
+ * @package Kanboard\Model
* @author Frederic Guillot
*/
-abstract class File extends Base
+abstract class FileModel extends Base
{
/**
+ * Get the table
+ *
+ * @abstract
+ * @access protected
+ * @return string
+ */
+ abstract protected function getTable();
+
+ /**
+ * Define the foreign key
+ *
+ * @abstract
+ * @access protected
+ * @return string
+ */
+ abstract protected function getForeignKey();
+
+ /**
+ * Get the path prefix
+ *
+ * @abstract
+ * @access protected
+ * @return string
+ */
+ abstract protected function getPathPrefix();
+
+ /**
+ * Get event name
+ *
+ * @abstract
+ * @access protected
+ * @return string
+ */
+ abstract protected function getEventName();
+
+ /**
* Get PicoDb query to get all files
*
* @access protected
@@ -24,21 +61,21 @@ abstract class File extends Base
protected function getQuery()
{
return $this->db
- ->table(static::TABLE)
+ ->table($this->getTable())
->columns(
- static::TABLE.'.id',
- static::TABLE.'.name',
- static::TABLE.'.path',
- static::TABLE.'.is_image',
- static::TABLE.'.'.static::FOREIGN_KEY,
- static::TABLE.'.date',
- static::TABLE.'.user_id',
- static::TABLE.'.size',
- User::TABLE.'.username',
- User::TABLE.'.name as user_name'
+ $this->getTable().'.id',
+ $this->getTable().'.name',
+ $this->getTable().'.path',
+ $this->getTable().'.is_image',
+ $this->getTable().'.'.$this->getForeignKey(),
+ $this->getTable().'.date',
+ $this->getTable().'.user_id',
+ $this->getTable().'.size',
+ UserModel::TABLE.'.username',
+ UserModel::TABLE.'.name as user_name'
)
- ->join(User::TABLE, 'id', 'user_id')
- ->asc(static::TABLE.'.name');
+ ->join(UserModel::TABLE, 'id', 'user_id')
+ ->asc($this->getTable().'.name');
}
/**
@@ -50,7 +87,7 @@ abstract class File extends Base
*/
public function getById($file_id)
{
- return $this->db->table(static::TABLE)->eq('id', $file_id)->findOne();
+ return $this->db->table($this->getTable())->eq('id', $file_id)->findOne();
}
/**
@@ -62,7 +99,7 @@ abstract class File extends Base
*/
public function getAll($id)
{
- return $this->getQuery()->eq(static::FOREIGN_KEY, $id)->findAll();
+ return $this->getQuery()->eq($this->getForeignKey(), $id)->findAll();
}
/**
@@ -74,7 +111,7 @@ abstract class File extends Base
*/
public function getAllImages($id)
{
- return $this->getQuery()->eq(static::FOREIGN_KEY, $id)->eq('is_image', 1)->findAll();
+ return $this->getQuery()->eq($this->getForeignKey(), $id)->eq('is_image', 1)->findAll();
}
/**
@@ -86,7 +123,7 @@ abstract class File extends Base
*/
public function getAllDocuments($id)
{
- return $this->getQuery()->eq(static::FOREIGN_KEY, $id)->eq('is_image', 0)->findAll();
+ return $this->getQuery()->eq($this->getForeignKey(), $id)->eq('is_image', 0)->findAll();
}
/**
@@ -102,7 +139,7 @@ abstract class File extends Base
public function create($id, $name, $path, $size)
{
$values = array(
- static::FOREIGN_KEY => $id,
+ $this->getForeignKey() => $id,
'name' => substr($name, 0, 255),
'path' => $path,
'is_image' => $this->isImage($name) ? 1 : 0,
@@ -111,12 +148,12 @@ abstract class File extends Base
'date' => time(),
);
- $result = $this->db->table(static::TABLE)->insert($values);
+ $result = $this->db->table($this->getTable())->insert($values);
if ($result) {
$file_id = (int) $this->db->getLastId();
$event = new FileEvent($values + array('file_id' => $file_id));
- $this->dispatcher->dispatch(static::EVENT_CREATE, $event);
+ $this->dispatcher->dispatch($this->getEventName(), $event);
return $file_id;
}
@@ -132,7 +169,7 @@ abstract class File extends Base
*/
public function removeAll($id)
{
- $file_ids = $this->db->table(static::TABLE)->eq(static::FOREIGN_KEY, $id)->asc('id')->findAllByColumn('id');
+ $file_ids = $this->db->table($this->getTable())->eq($this->getForeignKey(), $id)->asc('id')->findAllByColumn('id');
$results = array();
foreach ($file_ids as $file_id) {
@@ -159,7 +196,7 @@ abstract class File extends Base
$this->objectStorage->remove($this->getThumbnailPath($file['path']));
}
- return $this->db->table(static::TABLE)->eq('id', $file['id'])->remove();
+ return $this->db->table($this->getTable())->eq('id', $file['id'])->remove();
} catch (ObjectStorageException $e) {
$this->logger->error($e->getMessage());
return false;
@@ -210,7 +247,7 @@ abstract class File extends Base
*/
public function generatePath($id, $filename)
{
- return static::PATH_PREFIX.DIRECTORY_SEPARATOR.$id.DIRECTORY_SEPARATOR.hash('sha1', $filename.time());
+ return $this->getPathPrefix().DIRECTORY_SEPARATOR.$id.DIRECTORY_SEPARATOR.hash('sha1', $filename.time());
}
/**
@@ -252,6 +289,7 @@ abstract class File extends Base
* @access public
* @param integer $id
* @param array $file
+ * @throws Exception
*/
public function uploadFile($id, array $file)
{
diff --git a/app/Model/GroupMember.php b/app/Model/GroupMemberModel.php
index 14041704..a2077789 100644
--- a/app/Model/GroupMember.php
+++ b/app/Model/GroupMemberModel.php
@@ -2,13 +2,15 @@
namespace Kanboard\Model;
+use Kanboard\Core\Base;
+
/**
* Group Member Model
*
- * @package model
+ * @package Kanboard\Model
* @author Frederic Guillot
*/
-class GroupMember extends Base
+class GroupMemberModel extends Base
{
/**
* SQL table name
@@ -27,7 +29,7 @@ class GroupMember extends Base
public function getQuery($group_id)
{
return $this->db->table(self::TABLE)
- ->join(User::TABLE, 'id', 'user_id')
+ ->join(UserModel::TABLE, 'id', 'user_id')
->eq('group_id', $group_id);
}
@@ -56,7 +58,7 @@ class GroupMember extends Base
->columns('user_id')
->eq('group_id', $group_id);
- return $this->db->table(User::TABLE)
+ return $this->db->table(UserModel::TABLE)
->notInSubquery('id', $subquery)
->findAll();
}
@@ -119,10 +121,10 @@ class GroupMember extends Base
public function getGroups($user_id)
{
return $this->db->table(self::TABLE)
- ->columns(Group::TABLE.'.id', Group::TABLE.'.name')
- ->join(Group::TABLE, 'id', 'group_id')
+ ->columns(GroupModel::TABLE.'.id', GroupModel::TABLE.'.external_id', GroupModel::TABLE.'.name')
+ ->join(GroupModel::TABLE, 'id', 'group_id')
->eq(self::TABLE.'.user_id', $user_id)
- ->asc(Group::TABLE.'.name')
+ ->asc(GroupModel::TABLE.'.name')
->findAll();
}
}
diff --git a/app/Model/Group.php b/app/Model/GroupModel.php
index 67899503..0a975570 100644
--- a/app/Model/Group.php
+++ b/app/Model/GroupModel.php
@@ -2,13 +2,15 @@
namespace Kanboard\Model;
+use Kanboard\Core\Base;
+
/**
* Group Model
*
- * @package model
+ * @package Kanboard\Model
* @author Frederic Guillot
*/
-class Group extends Base
+class GroupModel extends Base
{
/**
* SQL table name
@@ -80,7 +82,7 @@ class Group extends Base
*
* @access public
* @param integer $group_id
- * @return array
+ * @return boolean
*/
public function remove($group_id)
{
@@ -97,7 +99,7 @@ class Group extends Base
*/
public function create($name, $external_id = '')
{
- return $this->persist(self::TABLE, array(
+ return $this->db->table(self::TABLE)->persist(array(
'name' => $name,
'external_id' => $external_id,
));
diff --git a/app/Model/LanguageModel.php b/app/Model/LanguageModel.php
new file mode 100644
index 00000000..eb6de004
--- /dev/null
+++ b/app/Model/LanguageModel.php
@@ -0,0 +1,179 @@
+<?php
+
+namespace Kanboard\Model;
+
+use Kanboard\Core\Base;
+use Kanboard\Core\Translator;
+
+/**
+ * Class Language
+ *
+ * @package Kanboard\Model
+ * @author Frederic Guillot
+ */
+class LanguageModel extends Base
+{
+ /**
+ * Get all language codes
+ *
+ * @static
+ * @access public
+ * @return string[]
+ */
+ public static function getCodes()
+ {
+ return array(
+ 'id_ID',
+ 'bs_BA',
+ 'cs_CZ',
+ 'da_DK',
+ 'de_DE',
+ 'en_US',
+ 'es_ES',
+ 'fr_FR',
+ 'el_GR',
+ 'it_IT',
+ 'hu_HU',
+ 'my_MY',
+ 'nl_NL',
+ 'nb_NO',
+ 'pl_PL',
+ 'pt_PT',
+ 'pt_BR',
+ 'ru_RU',
+ 'sr_Latn_RS',
+ 'fi_FI',
+ 'sv_SE',
+ 'tr_TR',
+ 'ko_KR',
+ 'zh_CN',
+ 'ja_JP',
+ 'th_TH',
+ );
+ }
+
+ /**
+ * Find language code
+ *
+ * @static
+ * @access public
+ * @param string $code
+ * @return string
+ */
+ public static function findCode($code)
+ {
+ $code = str_replace('-', '_', $code);
+ return in_array($code, self::getCodes()) ? $code : '';
+ }
+
+ /**
+ * Get available languages
+ *
+ * @access public
+ * @param boolean $prepend Prepend a default value
+ * @return array
+ */
+ public function getLanguages($prepend = false)
+ {
+ // Sorted by value
+ $languages = array(
+ 'id_ID' => 'Bahasa Indonesia',
+ 'bs_BA' => 'Bosanski',
+ 'cs_CZ' => 'Čeština',
+ 'da_DK' => 'Dansk',
+ 'de_DE' => 'Deutsch',
+ 'en_US' => 'English',
+ 'es_ES' => 'Español',
+ 'fr_FR' => 'Français',
+ 'el_GR' => 'Grec',
+ 'it_IT' => 'Italiano',
+ 'hu_HU' => 'Magyar',
+ 'my_MY' => 'Melayu',
+ 'nl_NL' => 'Nederlands',
+ 'nb_NO' => 'Norsk',
+ 'pl_PL' => 'Polski',
+ 'pt_PT' => 'Português',
+ 'pt_BR' => 'Português (Brasil)',
+ 'ru_RU' => 'Русский',
+ 'sr_Latn_RS' => 'Srpski',
+ 'fi_FI' => 'Suomi',
+ 'sv_SE' => 'Svenska',
+ 'tr_TR' => 'Türkçe',
+ 'ko_KR' => '한국어',
+ 'zh_CN' => '中文(简体)',
+ 'ja_JP' => '日本語',
+ 'th_TH' => 'ไทย',
+ );
+
+ if ($prepend) {
+ return array('' => t('Application default')) + $languages;
+ }
+
+ return $languages;
+ }
+
+ /**
+ * Get javascript language code
+ *
+ * @access public
+ * @return string
+ */
+ public function getJsLanguageCode()
+ {
+ $languages = array(
+ 'cs_CZ' => 'cs',
+ 'da_DK' => 'da',
+ 'de_DE' => 'de',
+ 'en_US' => 'en',
+ 'es_ES' => 'es',
+ 'fr_FR' => 'fr',
+ 'it_IT' => 'it',
+ 'hu_HU' => 'hu',
+ 'nl_NL' => 'nl',
+ 'nb_NO' => 'nb',
+ 'pl_PL' => 'pl',
+ 'pt_PT' => 'pt',
+ 'pt_BR' => 'pt-br',
+ 'ru_RU' => 'ru',
+ 'sr_Latn_RS' => 'sr',
+ 'fi_FI' => 'fi',
+ 'sv_SE' => 'sv',
+ 'tr_TR' => 'tr',
+ 'ko_KR' => 'ko',
+ 'zh_CN' => 'zh-cn',
+ 'ja_JP' => 'ja',
+ 'th_TH' => 'th',
+ 'id_ID' => 'id',
+ 'el_GR' => 'el',
+ );
+
+ $lang = $this->getCurrentLanguage();
+
+ return isset($languages[$lang]) ? $languages[$lang] : 'en';
+ }
+
+ /**
+ * Get current language
+ *
+ * @access public
+ * @return string
+ */
+ public function getCurrentLanguage()
+ {
+ if ($this->userSession->isLogged() && ! empty($this->sessionStorage->user['language'])) {
+ return $this->sessionStorage->user['language'];
+ }
+
+ return $this->configModel->get('application_language', 'en_US');
+ }
+
+ /**
+ * Load translations for the current language
+ *
+ * @access public
+ */
+ public function loadCurrentLanguage()
+ {
+ Translator::load($this->getCurrentLanguage());
+ }
+}
diff --git a/app/Model/LastLogin.php b/app/Model/LastLoginModel.php
index feb5f5a3..16821392 100644
--- a/app/Model/LastLogin.php
+++ b/app/Model/LastLoginModel.php
@@ -2,13 +2,15 @@
namespace Kanboard\Model;
+use Kanboard\Core\Base;
+
/**
* LastLogin model
*
- * @package model
+ * @package Kanboard\Model
* @author Frederic Guillot
*/
-class LastLogin extends Base
+class LastLoginModel extends Base
{
/**
* SQL table name
diff --git a/app/Model/Link.php b/app/Model/LinkModel.php
index 903a98d6..b72c7532 100644
--- a/app/Model/Link.php
+++ b/app/Model/LinkModel.php
@@ -3,15 +3,16 @@
namespace Kanboard\Model;
use PDO;
+use Kanboard\Core\Base;
/**
* Link model
*
- * @package model
+ * @package Kanboard\Model
* @author Olivier Maridat
* @author Frederic Guillot
*/
-class Link extends Base
+class LinkModel extends Base
{
/**
* SQL table name
diff --git a/app/Model/Metadata.php b/app/Model/MetadataModel.php
index 01799a40..6177e5f3 100644
--- a/app/Model/Metadata.php
+++ b/app/Model/MetadataModel.php
@@ -2,15 +2,26 @@
namespace Kanboard\Model;
+use Kanboard\Core\Base;
+
/**
* Metadata
*
- * @package model
+ * @package Kanboard\Model
* @author Frederic Guillot
*/
-abstract class Metadata extends Base
+abstract class MetadataModel extends Base
{
/**
+ * Get the table
+ *
+ * @abstract
+ * @access protected
+ * @return string
+ */
+ abstract protected function getTable();
+
+ /**
* Define the entity key
*
* @abstract
@@ -29,7 +40,7 @@ abstract class Metadata extends Base
public function getAll($entity_id)
{
return $this->db
- ->hashtable(static::TABLE)
+ ->hashtable($this->getTable())
->eq($this->getEntityKey(), $entity_id)
->asc('name')
->getAll('name', 'value');
@@ -47,7 +58,7 @@ abstract class Metadata extends Base
public function get($entity_id, $name, $default = '')
{
return $this->db
- ->table(static::TABLE)
+ ->table($this->getTable())
->eq($this->getEntityKey(), $entity_id)
->eq('name', $name)
->findOneColumn('value') ?: $default;
@@ -64,7 +75,7 @@ abstract class Metadata extends Base
public function exists($entity_id, $name)
{
return $this->db
- ->table(static::TABLE)
+ ->table($this->getTable())
->eq($this->getEntityKey(), $entity_id)
->eq('name', $name)
->exists();
@@ -88,7 +99,7 @@ abstract class Metadata extends Base
foreach ($values as $key => $value) {
if ($this->exists($entity_id, $key)) {
- $results[] = $this->db->table(static::TABLE)
+ $results[] = $this->db->table($this->getTable())
->eq($this->getEntityKey(), $entity_id)
->eq('name', $key)->update(array(
'value' => $value,
@@ -96,7 +107,7 @@ abstract class Metadata extends Base
'changed_by' => $user_id,
));
} else {
- $results[] = $this->db->table(static::TABLE)->insert(array(
+ $results[] = $this->db->table($this->getTable())->insert(array(
'name' => $key,
'value' => $value,
$this->getEntityKey() => $entity_id,
@@ -120,6 +131,9 @@ abstract class Metadata extends Base
*/
public function remove($entity_id, $name)
{
- return $this->db->table(static::TABLE)->eq($this->getEntityKey(), $entity_id)->eq('name', $name)->remove();
+ return $this->db->table($this->getTable())
+ ->eq($this->getEntityKey(), $entity_id)
+ ->eq('name', $name)
+ ->remove();
}
}
diff --git a/app/Model/Notification.php b/app/Model/NotificationModel.php
index c252aa31..8937b77e 100644
--- a/app/Model/Notification.php
+++ b/app/Model/NotificationModel.php
@@ -2,13 +2,15 @@
namespace Kanboard\Model;
+use Kanboard\Core\Base;
+
/**
* Notification
*
- * @package model
+ * @package Kanboard\Model
* @author Frederic Guillot
*/
-class Notification extends Base
+class NotificationModel extends Base
{
/**
* Get the event title with author
@@ -22,7 +24,7 @@ class Notification extends Base
public function getTitleWithAuthor($event_author, $event_name, array $event_data)
{
switch ($event_name) {
- case Task::EVENT_ASSIGNEE_CHANGE:
+ case TaskModel::EVENT_ASSIGNEE_CHANGE:
$assignee = $event_data['task']['assignee_name'] ?: $event_data['task']['assignee_username'];
if (! empty($assignee)) {
@@ -30,22 +32,22 @@ class Notification extends Base
}
return e('%s remove the assignee of the task %s', $event_author, e('#%d', $event_data['task']['id']));
- case Task::EVENT_UPDATE:
+ case TaskModel::EVENT_UPDATE:
return e('%s updated the task #%d', $event_author, $event_data['task']['id']);
- case Task::EVENT_CREATE:
+ case TaskModel::EVENT_CREATE:
return e('%s created the task #%d', $event_author, $event_data['task']['id']);
- case Task::EVENT_CLOSE:
+ case TaskModel::EVENT_CLOSE:
return e('%s closed the task #%d', $event_author, $event_data['task']['id']);
- case Task::EVENT_OPEN:
+ case TaskModel::EVENT_OPEN:
return e('%s open the task #%d', $event_author, $event_data['task']['id']);
- case Task::EVENT_MOVE_COLUMN:
+ case TaskModel::EVENT_MOVE_COLUMN:
return e(
'%s moved the task #%d to the column "%s"',
$event_author,
$event_data['task']['id'],
$event_data['task']['column_title']
);
- case Task::EVENT_MOVE_POSITION:
+ case TaskModel::EVENT_MOVE_POSITION:
return e(
'%s moved the task #%d to the position %d in the column "%s"',
$event_author,
@@ -53,7 +55,7 @@ class Notification extends Base
$event_data['task']['position'],
$event_data['task']['column_title']
);
- case Task::EVENT_MOVE_SWIMLANE:
+ case TaskModel::EVENT_MOVE_SWIMLANE:
if ($event_data['task']['swimlane_id'] == 0) {
return e('%s moved the task #%d to the first swimlane', $event_author, $event_data['task']['id']);
}
@@ -64,19 +66,19 @@ class Notification extends Base
$event_data['task']['id'],
$event_data['task']['swimlane_name']
);
- case Subtask::EVENT_UPDATE:
+ case SubtaskModel::EVENT_UPDATE:
return e('%s updated a subtask for the task #%d', $event_author, $event_data['task']['id']);
- case Subtask::EVENT_CREATE:
+ case SubtaskModel::EVENT_CREATE:
return e('%s created a subtask for the task #%d', $event_author, $event_data['task']['id']);
- case Comment::EVENT_UPDATE:
+ case CommentModel::EVENT_UPDATE:
return e('%s updated a comment on the task #%d', $event_author, $event_data['task']['id']);
- case Comment::EVENT_CREATE:
+ case CommentModel::EVENT_CREATE:
return e('%s commented on the task #%d', $event_author, $event_data['task']['id']);
- case TaskFile::EVENT_CREATE:
+ case TaskFileModel::EVENT_CREATE:
return e('%s attached a file to the task #%d', $event_author, $event_data['task']['id']);
- case Task::EVENT_USER_MENTION:
+ case TaskModel::EVENT_USER_MENTION:
return e('%s mentioned you in the task #%d', $event_author, $event_data['task']['id']);
- case Comment::EVENT_USER_MENTION:
+ case CommentModel::EVENT_USER_MENTION:
return e('%s mentioned you in a comment on the task #%d', $event_author, $event_data['task']['id']);
default:
return e('Notification');
@@ -94,38 +96,38 @@ class Notification extends Base
public function getTitleWithoutAuthor($event_name, array $event_data)
{
switch ($event_name) {
- case TaskFile::EVENT_CREATE:
+ case TaskFileModel::EVENT_CREATE:
return e('New attachment on task #%d: %s', $event_data['file']['task_id'], $event_data['file']['name']);
- case Comment::EVENT_CREATE:
+ case CommentModel::EVENT_CREATE:
return e('New comment on task #%d', $event_data['comment']['task_id']);
- case Comment::EVENT_UPDATE:
+ case CommentModel::EVENT_UPDATE:
return e('Comment updated on task #%d', $event_data['comment']['task_id']);
- case Subtask::EVENT_CREATE:
+ case SubtaskModel::EVENT_CREATE:
return e('New subtask on task #%d', $event_data['subtask']['task_id']);
- case Subtask::EVENT_UPDATE:
+ case SubtaskModel::EVENT_UPDATE:
return e('Subtask updated on task #%d', $event_data['subtask']['task_id']);
- case Task::EVENT_CREATE:
+ case TaskModel::EVENT_CREATE:
return e('New task #%d: %s', $event_data['task']['id'], $event_data['task']['title']);
- case Task::EVENT_UPDATE:
+ case TaskModel::EVENT_UPDATE:
return e('Task updated #%d', $event_data['task']['id']);
- case Task::EVENT_CLOSE:
+ case TaskModel::EVENT_CLOSE:
return e('Task #%d closed', $event_data['task']['id']);
- case Task::EVENT_OPEN:
+ case TaskModel::EVENT_OPEN:
return e('Task #%d opened', $event_data['task']['id']);
- case Task::EVENT_MOVE_COLUMN:
+ case TaskModel::EVENT_MOVE_COLUMN:
return e('Column changed for task #%d', $event_data['task']['id']);
- case Task::EVENT_MOVE_POSITION:
+ case TaskModel::EVENT_MOVE_POSITION:
return e('New position for task #%d', $event_data['task']['id']);
- case Task::EVENT_MOVE_SWIMLANE:
+ case TaskModel::EVENT_MOVE_SWIMLANE:
return e('Swimlane changed for task #%d', $event_data['task']['id']);
- case Task::EVENT_ASSIGNEE_CHANGE:
+ case TaskModel::EVENT_ASSIGNEE_CHANGE:
return e('Assignee changed on task #%d', $event_data['task']['id']);
- case Task::EVENT_OVERDUE:
+ case TaskModel::EVENT_OVERDUE:
$nb = count($event_data['tasks']);
return $nb > 1 ? e('%d overdue tasks', $nb) : e('Task #%d is overdue', $event_data['tasks'][0]['id']);
- case Task::EVENT_USER_MENTION:
+ case TaskModel::EVENT_USER_MENTION:
return e('You were mentioned in the task #%d', $event_data['task']['id']);
- case Comment::EVENT_USER_MENTION:
+ case CommentModel::EVENT_USER_MENTION:
return e('You were mentioned in a comment on the task #%d', $event_data['task']['id']);
default:
return e('Notification');
diff --git a/app/Model/NotificationType.php b/app/Model/NotificationTypeModel.php
index 289aae9c..432832ee 100644
--- a/app/Model/NotificationType.php
+++ b/app/Model/NotificationTypeModel.php
@@ -3,6 +3,7 @@
namespace Kanboard\Model;
use Pimple\Container;
+use Kanboard\Core\Base;
/**
* Notification Type
@@ -10,7 +11,7 @@ use Pimple\Container;
* @package model
* @author Frederic Guillot
*/
-abstract class NotificationType extends Base
+abstract class NotificationTypeModel extends Base
{
/**
* Container
@@ -56,7 +57,7 @@ abstract class NotificationType extends Base
* @param string $label
* @param string $class
* @param boolean $hidden
- * @return NotificationType
+ * @return NotificationTypeModel
*/
public function setType($type, $label, $class, $hidden = false)
{
@@ -80,7 +81,7 @@ abstract class NotificationType extends Base
*
* @access public
* @param string $type
- * @return \Kanboard\Notification\NotificationInterface
+ * @return \Kanboard\Core\Notification\NotificationInterface
*/
public function getType($type)
{
diff --git a/app/Model/PasswordReset.php b/app/Model/PasswordResetModel.php
index 5cfd3c97..d7c74969 100644
--- a/app/Model/PasswordReset.php
+++ b/app/Model/PasswordResetModel.php
@@ -2,13 +2,15 @@
namespace Kanboard\Model;
+use Kanboard\Core\Base;
+
/**
* Password Reset Model
*
- * @package model
+ * @package Kanboard\Model
* @author Frederic Guillot
*/
-class PasswordReset extends Base
+class PasswordResetModel extends Base
{
/**
* SQL table name
@@ -46,7 +48,7 @@ class PasswordReset extends Base
*/
public function create($username, $expiration = 0)
{
- $user_id = $this->db->table(User::TABLE)->eq('username', $username)->neq('email', '')->notNull('email')->findOneColumn('id');
+ $user_id = $this->db->table(UserModel::TABLE)->eq('username', $username)->neq('email', '')->notNull('email')->findOneColumn('id');
if (! $user_id) {
return false;
diff --git a/app/Model/ProjectActivity.php b/app/Model/ProjectActivityModel.php
index d993015b..380ea125 100644
--- a/app/Model/ProjectActivity.php
+++ b/app/Model/ProjectActivityModel.php
@@ -2,15 +2,16 @@
namespace Kanboard\Model;
+use Kanboard\Core\Base;
use PicoDb\Table;
/**
* Project activity model
*
- * @package model
+ * @package Kanboard\Model
* @author Frederic Guillot
*/
-class ProjectActivity extends Base
+class ProjectActivityModel extends Base
{
/**
* SQL table name
@@ -62,17 +63,17 @@ class ProjectActivity extends Base
{
return $this
->db
- ->table(ProjectActivity::TABLE)
+ ->table(ProjectActivityModel::TABLE)
->columns(
- ProjectActivity::TABLE.'.*',
+ ProjectActivityModel::TABLE.'.*',
'uc.username AS author_username',
'uc.name AS author_name',
'uc.email',
'uc.avatar_path'
)
- ->join(Task::TABLE, 'id', 'task_id')
- ->join(Project::TABLE, 'id', 'project_id')
- ->left(User::TABLE, 'uc', 'id', ProjectActivity::TABLE, 'creator_id');
+ ->join(TaskModel::TABLE, 'id', 'task_id')
+ ->join(ProjectModel::TABLE, 'id', 'project_id')
+ ->left(UserModel::TABLE, 'uc', 'id', ProjectActivityModel::TABLE, 'creator_id');
}
/**
diff --git a/app/Model/ProjectDailyColumnStats.php b/app/Model/ProjectDailyColumnStatsModel.php
index 0706a110..a0f14cf4 100644
--- a/app/Model/ProjectDailyColumnStats.php
+++ b/app/Model/ProjectDailyColumnStatsModel.php
@@ -2,13 +2,15 @@
namespace Kanboard\Model;
+use Kanboard\Core\Base;
+
/**
* Project Daily Column Stats
*
- * @package model
+ * @package Kanboard\Model
* @author Frederic Guillot
*/
-class ProjectDailyColumnStats extends Base
+class ProjectDailyColumnStatsModel extends Base
{
/**
* SQL table name
@@ -84,7 +86,7 @@ class ProjectDailyColumnStats extends Base
*/
public function getAggregatedMetrics($project_id, $from, $to, $field = 'total')
{
- $columns = $this->column->getList($project_id);
+ $columns = $this->columnModel->getList($project_id);
$metrics = $this->getMetrics($project_id, $from, $to);
return $this->buildAggregate($metrics, $columns, $field);
}
@@ -205,10 +207,10 @@ class ProjectDailyColumnStats extends Base
*/
private function getScoreByColumns($project_id)
{
- $stats = $this->db->table(Task::TABLE)
+ $stats = $this->db->table(TaskModel::TABLE)
->columns('column_id', 'SUM(score) AS score')
->eq('project_id', $project_id)
- ->eq('is_active', Task::STATUS_OPEN)
+ ->eq('is_active', TaskModel::STATUS_OPEN)
->notNull('score')
->groupBy('column_id')
->findAll();
@@ -225,7 +227,7 @@ class ProjectDailyColumnStats extends Base
*/
private function getTotalByColumns($project_id)
{
- $stats = $this->db->table(Task::TABLE)
+ $stats = $this->db->table(TaskModel::TABLE)
->columns('column_id', 'COUNT(*) AS total')
->eq('project_id', $project_id)
->in('is_active', $this->getTaskStatusConfig())
@@ -243,10 +245,10 @@ class ProjectDailyColumnStats extends Base
*/
private function getTaskStatusConfig()
{
- if ($this->config->get('cfd_include_closed_tasks') == 1) {
- return array(Task::STATUS_OPEN, Task::STATUS_CLOSED);
+ if ($this->configModel->get('cfd_include_closed_tasks') == 1) {
+ return array(TaskModel::STATUS_OPEN, TaskModel::STATUS_CLOSED);
}
- return array(Task::STATUS_OPEN);
+ return array(TaskModel::STATUS_OPEN);
}
}
diff --git a/app/Model/ProjectDailyStats.php b/app/Model/ProjectDailyStatsModel.php
index 974f5813..0754d263 100644
--- a/app/Model/ProjectDailyStats.php
+++ b/app/Model/ProjectDailyStatsModel.php
@@ -2,13 +2,15 @@
namespace Kanboard\Model;
+use Kanboard\Core\Base;
+
/**
* Project Daily Stats
*
- * @package model
+ * @package Kanboard\Model
* @author Frederic Guillot
*/
-class ProjectDailyStats extends Base
+class ProjectDailyStatsModel extends Base
{
/**
* SQL table name
diff --git a/app/Model/ProjectDuplication.php b/app/Model/ProjectDuplicationModel.php
index 9c5f80ad..b67f8302 100644
--- a/app/Model/ProjectDuplication.php
+++ b/app/Model/ProjectDuplicationModel.php
@@ -2,16 +2,17 @@
namespace Kanboard\Model;
+use Kanboard\Core\Base;
use Kanboard\Core\Security\Role;
/**
* Project Duplication
*
- * @package model
+ * @package Kanboard\Model
* @author Frederic Guillot
* @author Antonio Rabelo
*/
-class ProjectDuplication extends Base
+class ProjectDuplicationModel extends Base
{
/**
* Get list of optional models to duplicate
@@ -21,7 +22,7 @@ class ProjectDuplication extends Base
*/
public function getOptionalSelection()
{
- return array('category', 'projectPermission', 'action', 'swimlane', 'task');
+ return array('categoryModel', 'projectPermissionModel', 'actionModel', 'swimlaneModel', 'taskModel', 'projectMetadataModel');
}
/**
@@ -32,7 +33,7 @@ class ProjectDuplication extends Base
*/
public function getPossibleSelection()
{
- return array('board', 'category', 'projectPermission', 'action', 'swimlane', 'task');
+ return array('boardModel', 'categoryModel', 'projectPermissionModel', 'actionModel', 'swimlaneModel', 'taskModel', 'projectMetadataModel');
}
/**
@@ -64,7 +65,7 @@ class ProjectDuplication extends Base
* @param boolean $private Force the project to be private
* @return integer Cloned Project Id
*/
- public function duplicate($src_project_id, $selection = array('projectPermission', 'category', 'action'), $owner_id = 0, $name = null, $private = null)
+ public function duplicate($src_project_id, $selection = array('projectPermissionModel', 'categoryModel', 'actionModel'), $owner_id = 0, $name = null, $private = null)
{
$this->db->startTransaction();
@@ -85,7 +86,7 @@ class ProjectDuplication extends Base
}
// Skip permissions for private projects
- if ($private && $model === 'projectPermission') {
+ if ($private && $model === 'projectPermissionModel') {
continue;
}
@@ -117,7 +118,7 @@ class ProjectDuplication extends Base
*/
private function copy($src_project_id, $owner_id = 0, $name = null, $private = null)
{
- $project = $this->project->getById($src_project_id);
+ $project = $this->projectModel->getById($src_project_id);
$is_private = empty($project['is_private']) ? 0 : 1;
$values = array(
@@ -130,7 +131,7 @@ class ProjectDuplication extends Base
'owner_id' => $owner_id,
);
- if (! $this->db->table(Project::TABLE)->save($values)) {
+ if (! $this->db->table(ProjectModel::TABLE)->save($values)) {
return false;
}
@@ -148,9 +149,9 @@ class ProjectDuplication extends Base
private function makeOwnerManager($dst_project_id, $owner_id)
{
if ($owner_id > 0) {
- $this->projectUserRole->removeUser($dst_project_id, $owner_id);
+ $this->projectUserRoleModel->removeUser($dst_project_id, $owner_id);
- if (! $this->projectUserRole->addUser($dst_project_id, $owner_id, Role::PROJECT_MANAGER)) {
+ if (! $this->projectUserRoleModel->addUser($dst_project_id, $owner_id, Role::PROJECT_MANAGER)) {
return false;
}
}
diff --git a/app/Model/ProjectFile.php b/app/Model/ProjectFile.php
deleted file mode 100644
index aa9bf15b..00000000
--- a/app/Model/ProjectFile.php
+++ /dev/null
@@ -1,40 +0,0 @@
-<?php
-
-namespace Kanboard\Model;
-
-/**
- * Project File Model
- *
- * @package model
- * @author Frederic Guillot
- */
-class ProjectFile extends File
-{
- /**
- * SQL table name
- *
- * @var string
- */
- const TABLE = 'project_has_files';
-
- /**
- * SQL foreign key
- *
- * @var string
- */
- const FOREIGN_KEY = 'project_id';
-
- /**
- * Path prefix
- *
- * @var string
- */
- const PATH_PREFIX = 'projects';
-
- /**
- * Events
- *
- * @var string
- */
- const EVENT_CREATE = 'project.file.create';
-}
diff --git a/app/Model/ProjectFileModel.php b/app/Model/ProjectFileModel.php
new file mode 100644
index 00000000..b464bb2a
--- /dev/null
+++ b/app/Model/ProjectFileModel.php
@@ -0,0 +1,74 @@
+<?php
+
+namespace Kanboard\Model;
+
+/**
+ * Project File Model
+ *
+ * @package Kanboard\Model
+ * @author Frederic Guillot
+ */
+class ProjectFileModel extends FileModel
+{
+ /**
+ * Table name
+ *
+ * @var string
+ */
+ const TABLE = 'project_has_files';
+
+ /**
+ * Events
+ *
+ * @var string
+ */
+ const EVENT_CREATE = 'project.file.create';
+
+ /**
+ * Get the table
+ *
+ * @abstract
+ * @access protected
+ * @return string
+ */
+ protected function getTable()
+ {
+ return self::TABLE;
+ }
+
+ /**
+ * Define the foreign key
+ *
+ * @abstract
+ * @access protected
+ * @return string
+ */
+ protected function getForeignKey()
+ {
+ return 'project_id';
+ }
+
+ /**
+ * Define the path prefix
+ *
+ * @abstract
+ * @access protected
+ * @return string
+ */
+ protected function getPathPrefix()
+ {
+ return 'projects';
+ }
+
+ /**
+ * Get event name
+ *
+ * @abstract
+ * @access protected
+ * @return string
+ */
+ protected function getEventName()
+ {
+ return self::EVENT_CREATE;
+ }
+}
diff --git a/app/Model/ProjectGroupRole.php b/app/Model/ProjectGroupRoleModel.php
index afad4a44..2729d5a6 100644
--- a/app/Model/ProjectGroupRole.php
+++ b/app/Model/ProjectGroupRoleModel.php
@@ -2,15 +2,16 @@
namespace Kanboard\Model;
+use Kanboard\Core\Base;
use Kanboard\Core\Security\Role;
/**
* Project Group Role
*
- * @package model
+ * @package Kanboard\Model
* @author Frederic Guillot
*/
-class ProjectGroupRole extends Base
+class ProjectGroupRoleModel extends Base
{
/**
* SQL table name
@@ -27,15 +28,15 @@ class ProjectGroupRole extends Base
* @param array $status
* @return array
*/
- public function getProjectsByUser($user_id, $status = array(Project::ACTIVE, Project::INACTIVE))
+ public function getProjectsByUser($user_id, $status = array(ProjectModel::ACTIVE, ProjectModel::INACTIVE))
{
return $this->db
- ->hashtable(Project::TABLE)
+ ->hashtable(ProjectModel::TABLE)
->join(self::TABLE, 'project_id', 'id')
- ->join(GroupMember::TABLE, 'group_id', 'group_id', self::TABLE)
- ->eq(GroupMember::TABLE.'.user_id', $user_id)
- ->in(Project::TABLE.'.is_active', $status)
- ->getAll(Project::TABLE.'.id', Project::TABLE.'.name');
+ ->join(GroupMemberModel::TABLE, 'group_id', 'group_id', self::TABLE)
+ ->eq(GroupMemberModel::TABLE.'.user_id', $user_id)
+ ->in(ProjectModel::TABLE.'.is_active', $status)
+ ->getAll(ProjectModel::TABLE.'.id', ProjectModel::TABLE.'.name');
}
/**
@@ -49,8 +50,8 @@ class ProjectGroupRole extends Base
public function getUserRole($project_id, $user_id)
{
$roles = $this->db->table(self::TABLE)
- ->join(GroupMember::TABLE, 'group_id', 'group_id', self::TABLE)
- ->eq(GroupMember::TABLE.'.user_id', $user_id)
+ ->join(GroupMemberModel::TABLE, 'group_id', 'group_id', self::TABLE)
+ ->eq(GroupMemberModel::TABLE.'.user_id', $user_id)
->eq(self::TABLE.'.project_id', $project_id)
->findAllByColumn('role');
@@ -67,8 +68,8 @@ class ProjectGroupRole extends Base
public function getGroups($project_id)
{
return $this->db->table(self::TABLE)
- ->columns(Group::TABLE.'.id', Group::TABLE.'.name', self::TABLE.'.role')
- ->join(Group::TABLE, 'id', 'group_id')
+ ->columns(GroupModel::TABLE.'.id', GroupModel::TABLE.'.name', self::TABLE.'.role')
+ ->join(GroupModel::TABLE, 'id', 'group_id')
->eq('project_id', $project_id)
->asc('name')
->findAll();
@@ -84,11 +85,11 @@ class ProjectGroupRole extends Base
public function getUsers($project_id)
{
return $this->db->table(self::TABLE)
- ->columns(User::TABLE.'.id', User::TABLE.'.username', User::TABLE.'.name', self::TABLE.'.role')
- ->join(GroupMember::TABLE, 'group_id', 'group_id', self::TABLE)
- ->join(User::TABLE, 'id', 'user_id', GroupMember::TABLE)
+ ->columns(UserModel::TABLE.'.id', UserModel::TABLE.'.username', UserModel::TABLE.'.name', self::TABLE.'.role')
+ ->join(GroupMemberModel::TABLE, 'group_id', 'group_id', self::TABLE)
+ ->join(UserModel::TABLE, 'id', 'user_id', GroupMemberModel::TABLE)
->eq(self::TABLE.'.project_id', $project_id)
- ->asc(User::TABLE.'.username')
+ ->asc(UserModel::TABLE.'.username')
->findAll();
}
@@ -101,14 +102,14 @@ class ProjectGroupRole extends Base
*/
public function getAssignableUsers($project_id)
{
- return $this->db->table(User::TABLE)
- ->columns(User::TABLE.'.id', User::TABLE.'.username', User::TABLE.'.name')
- ->join(GroupMember::TABLE, 'user_id', 'id', User::TABLE)
- ->join(self::TABLE, 'group_id', 'group_id', GroupMember::TABLE)
+ return $this->db->table(UserModel::TABLE)
+ ->columns(UserModel::TABLE.'.id', UserModel::TABLE.'.username', UserModel::TABLE.'.name')
+ ->join(GroupMemberModel::TABLE, 'user_id', 'id', UserModel::TABLE)
+ ->join(self::TABLE, 'group_id', 'group_id', GroupMemberModel::TABLE)
->eq(self::TABLE.'.project_id', $project_id)
- ->eq(User::TABLE.'.is_active', 1)
+ ->eq(UserModel::TABLE.'.is_active', 1)
->in(self::TABLE.'.role', array(Role::PROJECT_MANAGER, Role::PROJECT_MEMBER))
- ->asc(User::TABLE.'.username')
+ ->asc(UserModel::TABLE.'.username')
->findAll();
}
diff --git a/app/Model/ProjectMetadata.php b/app/Model/ProjectMetadata.php
deleted file mode 100644
index 85498053..00000000
--- a/app/Model/ProjectMetadata.php
+++ /dev/null
@@ -1,30 +0,0 @@
-<?php
-
-namespace Kanboard\Model;
-
-/**
- * Project Metadata
- *
- * @package model
- * @author Frederic Guillot
- */
-class ProjectMetadata extends Metadata
-{
- /**
- * SQL table name
- *
- * @var string
- */
- const TABLE = 'project_has_metadata';
-
- /**
- * Define the entity key
- *
- * @access protected
- * @return string
- */
- protected function getEntityKey()
- {
- return 'project_id';
- }
-}
diff --git a/app/Model/ProjectMetadataModel.php b/app/Model/ProjectMetadataModel.php
new file mode 100644
index 00000000..760acd7d
--- /dev/null
+++ b/app/Model/ProjectMetadataModel.php
@@ -0,0 +1,54 @@
+<?php
+
+namespace Kanboard\Model;
+
+/**
+ * Project Metadata
+ *
+ * @package Kanboard\Model
+ * @author Frederic Guillot
+ */
+class ProjectMetadataModel extends MetadataModel
+{
+ /**
+ * Get the table
+ *
+ * @abstract
+ * @access protected
+ * @return string
+ */
+ protected function getTable()
+ {
+ return 'project_has_metadata';
+ }
+
+ /**
+ * Define the entity key
+ *
+ * @access protected
+ * @return string
+ */
+ protected function getEntityKey()
+ {
+ return 'project_id';
+ }
+
+ /**
+ * Helper method to duplicate all metadata to another project
+ *
+ * @access public
+ * @param integer $src_project_id
+ * @param integer $dst_project_id
+ * @return boolean
+ */
+ public function duplicate($src_project_id, $dst_project_id)
+ {
+ $metadata = $this->getAll($src_project_id);
+
+ if (! $this->save($dst_project_id, $metadata)) {
+ return false;
+ }
+
+ return true;
+ }
+}
diff --git a/app/Model/Project.php b/app/Model/ProjectModel.php
index 6e3c2326..34e11c13 100644
--- a/app/Model/Project.php
+++ b/app/Model/ProjectModel.php
@@ -2,16 +2,17 @@
namespace Kanboard\Model;
+use Kanboard\Core\Base;
use Kanboard\Core\Security\Token;
use Kanboard\Core\Security\Role;
/**
* Project model
*
- * @package model
+ * @package Kanboard\Model
* @author Frederic Guillot
*/
-class Project extends Base
+class ProjectModel extends Base
{
/**
* SQL table name for projects
@@ -70,9 +71,9 @@ class Project extends Base
public function getByIdWithOwner($project_id)
{
return $this->db->table(self::TABLE)
- ->columns(self::TABLE.'.*', User::TABLE.'.username AS owner_username', User::TABLE.'.name AS owner_name')
+ ->columns(self::TABLE.'.*', UserModel::TABLE.'.username AS owner_username', UserModel::TABLE.'.name AS owner_name')
->eq(self::TABLE.'.id', $project_id)
- ->join(User::TABLE, 'id', 'owner_id')
+ ->join(UserModel::TABLE, 'id', 'owner_id')
->findOne();
}
@@ -201,7 +202,7 @@ class Project extends Base
* Get all projects with all its data for a given status
*
* @access public
- * @param integer $status Proejct status: self::ACTIVE or self:INACTIVE
+ * @param integer $status Project status: self::ACTIVE or self:INACTIVE
* @return array
*/
public function getAllByStatus($status)
@@ -245,6 +246,19 @@ class Project extends Base
}
/**
+ * Get Priority range from a project
+ *
+ * @access public
+ * @param array $project
+ * @return array
+ */
+ public function getPriorities(array $project)
+ {
+ $range = range($project['priority_start'], $project['priority_end']);
+ return array_combine($range, $range);
+ }
+
+ /**
* Gather some task metrics for a given project
*
* @access public
@@ -255,8 +269,8 @@ class Project extends Base
{
$stats = array();
$stats['nb_active_tasks'] = 0;
- $columns = $this->column->getAll($project_id);
- $column_stats = $this->board->getColumnStats($project_id);
+ $columns = $this->columnModel->getAll($project_id);
+ $column_stats = $this->boardModel->getColumnStats($project_id);
foreach ($columns as &$column) {
$column['nb_active_tasks'] = isset($column_stats[$column['id']]) ? $column_stats[$column['id']] : 0;
@@ -264,7 +278,7 @@ class Project extends Base
}
$stats['columns'] = $columns;
- $stats['nb_tasks'] = $this->taskFinder->countByProjectId($project_id);
+ $stats['nb_tasks'] = $this->taskFinderModel->countByProjectId($project_id);
$stats['nb_inactive_tasks'] = $stats['nb_tasks'] - $stats['nb_active_tasks'];
return $stats;
@@ -279,8 +293,8 @@ class Project extends Base
*/
public function getColumnStats(array &$project)
{
- $project['columns'] = $this->column->getAll($project['id']);
- $stats = $this->board->getColumnStats($project['id']);
+ $project['columns'] = $this->columnModel->getAll($project['id']);
+ $stats = $this->boardModel->getColumnStats($project['id']);
foreach ($project['columns'] as &$column) {
$column['nb_tasks'] = isset($stats[$column['id']]) ? $stats[$column['id']] : 0;
@@ -315,13 +329,13 @@ class Project extends Base
public function getQueryColumnStats(array $project_ids)
{
if (empty($project_ids)) {
- return $this->db->table(Project::TABLE)->limit(0);
+ return $this->db->table(ProjectModel::TABLE)->limit(0);
}
return $this->db
- ->table(Project::TABLE)
- ->columns(self::TABLE.'.*', User::TABLE.'.username AS owner_username', User::TABLE.'.name AS owner_name')
- ->join(User::TABLE, 'id', 'owner_id')
+ ->table(ProjectModel::TABLE)
+ ->columns(self::TABLE.'.*', UserModel::TABLE.'.username AS owner_username', UserModel::TABLE.'.name AS owner_name')
+ ->join(UserModel::TABLE, 'id', 'owner_id')
->in(self::TABLE.'.id', $project_ids)
->callback(array($this, 'applyColumnStats'));
}
@@ -357,16 +371,16 @@ class Project extends Base
$project_id = $this->db->getLastId();
- if (! $this->board->create($project_id, $this->board->getUserColumns())) {
+ if (! $this->boardModel->create($project_id, $this->boardModel->getUserColumns())) {
$this->db->cancelTransaction();
return false;
}
if ($add_user && $user_id) {
- $this->projectUserRole->addUser($project_id, $user_id, Role::PROJECT_MANAGER);
+ $this->projectUserRoleModel->addUser($project_id, $user_id, Role::PROJECT_MANAGER);
}
- $this->category->createDefaultCategories($project_id);
+ $this->categoryModel->createDefaultCategories($project_id);
$this->db->closeTransaction();
diff --git a/app/Model/ProjectNotification.php b/app/Model/ProjectNotificationModel.php
index a355902f..aeeee4cd 100644
--- a/app/Model/ProjectNotification.php
+++ b/app/Model/ProjectNotificationModel.php
@@ -2,13 +2,15 @@
namespace Kanboard\Model;
+use Kanboard\Core\Base;
+
/**
* Project Notification
*
- * @package model
+ * @package Kanboard\Model
* @author Frederic Guillot
*/
-class ProjectNotification extends Base
+class ProjectNotificationModel extends Base
{
/**
* Send notifications
@@ -20,15 +22,15 @@ class ProjectNotification extends Base
*/
public function sendNotifications($project_id, $event_name, array $event_data)
{
- $project = $this->project->getById($project_id);
+ $project = $this->projectModel->getById($project_id);
$types = array_merge(
- $this->projectNotificationType->getHiddenTypes(),
- $this->projectNotificationType->getSelectedTypes($project_id)
+ $this->projectNotificationTypeModel->getHiddenTypes(),
+ $this->projectNotificationTypeModel->getSelectedTypes($project_id)
);
foreach ($types as $type) {
- $this->projectNotificationType->getType($type)->notifyProject($project, $event_name, $event_data);
+ $this->projectNotificationTypeModel->getType($type)->notifyProject($project, $event_name, $event_data);
}
}
@@ -44,7 +46,7 @@ class ProjectNotification extends Base
$this->db->startTransaction();
$types = empty($values['notification_types']) ? array() : array_keys($values['notification_types']);
- $this->projectNotificationType->saveSelectedTypes($project_id, $types);
+ $this->projectNotificationTypeModel->saveSelectedTypes($project_id, $types);
$this->db->closeTransaction();
}
@@ -59,7 +61,7 @@ class ProjectNotification extends Base
public function readSettings($project_id)
{
return array(
- 'notification_types' => $this->projectNotificationType->getSelectedTypes($project_id),
+ 'notification_types' => $this->projectNotificationTypeModel->getSelectedTypes($project_id),
);
}
}
diff --git a/app/Model/ProjectNotificationType.php b/app/Model/ProjectNotificationTypeModel.php
index a4719598..aeec77f2 100644
--- a/app/Model/ProjectNotificationType.php
+++ b/app/Model/ProjectNotificationTypeModel.php
@@ -5,10 +5,10 @@ namespace Kanboard\Model;
/**
* Project Notification Type
*
- * @package model
+ * @package Kanboard\Model
* @author Frederic Guillot
*/
-class ProjectNotificationType extends NotificationType
+class ProjectNotificationTypeModel extends NotificationTypeModel
{
/**
* SQL table name
diff --git a/app/Model/ProjectPermission.php b/app/Model/ProjectPermissionModel.php
index 59af2b58..a7c1857c 100644
--- a/app/Model/ProjectPermission.php
+++ b/app/Model/ProjectPermissionModel.php
@@ -2,6 +2,7 @@
namespace Kanboard\Model;
+use Kanboard\Core\Base;
use Kanboard\Core\Security\Role;
use Kanboard\Filter\ProjectGroupRoleProjectFilter;
use Kanboard\Filter\ProjectGroupRoleUsernameFilter;
@@ -11,10 +12,10 @@ use Kanboard\Filter\ProjectUserRoleUsernameFilter;
/**
* Project Permission
*
- * @package model
+ * @package Kanboard\Model
* @author Frederic Guillot
*/
-class ProjectPermission extends Base
+class ProjectPermissionModel extends Base
{
/**
* Get query for project users overview
@@ -32,18 +33,18 @@ class ProjectPermission extends Base
return $this
->db
- ->table(ProjectUserRole::TABLE)
- ->join(User::TABLE, 'id', 'user_id')
- ->join(Project::TABLE, 'id', 'project_id')
- ->eq(ProjectUserRole::TABLE.'.role', $role)
- ->eq(Project::TABLE.'.is_private', 0)
- ->in(Project::TABLE.'.id', $project_ids)
+ ->table(ProjectUserRoleModel::TABLE)
+ ->join(UserModel::TABLE, 'id', 'user_id')
+ ->join(ProjectModel::TABLE, 'id', 'project_id')
+ ->eq(ProjectUserRoleModel::TABLE.'.role', $role)
+ ->eq(ProjectModel::TABLE.'.is_private', 0)
+ ->in(ProjectModel::TABLE.'.id', $project_ids)
->columns(
- User::TABLE.'.id',
- User::TABLE.'.username',
- User::TABLE.'.name',
- Project::TABLE.'.name AS project_name',
- Project::TABLE.'.id'
+ UserModel::TABLE.'.id',
+ UserModel::TABLE.'.username',
+ UserModel::TABLE.'.name',
+ ProjectModel::TABLE.'.name AS project_name',
+ ProjectModel::TABLE.'.id'
);
}
@@ -86,7 +87,7 @@ class ProjectPermission extends Base
public function isEverybodyAllowed($project_id)
{
return $this->db
- ->table(Project::TABLE)
+ ->table(ProjectModel::TABLE)
->eq('id', $project_id)
->eq('is_everybody_allowed', 1)
->exists();
@@ -106,7 +107,7 @@ class ProjectPermission extends Base
}
return in_array(
- $this->projectUserRole->getUserRole($project_id, $user_id),
+ $this->projectUserRoleModel->getUserRole($project_id, $user_id),
array(Role::PROJECT_MANAGER, Role::PROJECT_MEMBER, Role::PROJECT_VIEWER)
);
}
@@ -121,8 +122,8 @@ class ProjectPermission extends Base
*/
public function isAssignable($project_id, $user_id)
{
- return $this->user->isActive($user_id) &&
- in_array($this->projectUserRole->getUserRole($project_id, $user_id), array(Role::PROJECT_MEMBER, Role::PROJECT_MANAGER));
+ return $this->userModel->isActive($user_id) &&
+ in_array($this->projectUserRoleModel->getUserRole($project_id, $user_id), array(Role::PROJECT_MEMBER, Role::PROJECT_MANAGER));
}
/**
@@ -135,7 +136,7 @@ class ProjectPermission extends Base
*/
public function isMember($project_id, $user_id)
{
- return in_array($this->projectUserRole->getUserRole($project_id, $user_id), array(Role::PROJECT_MEMBER, Role::PROJECT_MANAGER, Role::PROJECT_VIEWER));
+ return in_array($this->projectUserRoleModel->getUserRole($project_id, $user_id), array(Role::PROJECT_MEMBER, Role::PROJECT_MANAGER, Role::PROJECT_VIEWER));
}
/**
@@ -147,7 +148,7 @@ class ProjectPermission extends Base
*/
public function getActiveProjectIds($user_id)
{
- return array_keys($this->projectUserRole->getActiveProjectsByUser($user_id));
+ return array_keys($this->projectUserRoleModel->getActiveProjectsByUser($user_id));
}
/**
@@ -159,7 +160,7 @@ class ProjectPermission extends Base
*/
public function duplicate($project_src_id, $project_dst_id)
{
- return $this->projectUserRole->duplicate($project_src_id, $project_dst_id) &&
- $this->projectGroupRole->duplicate($project_src_id, $project_dst_id);
+ return $this->projectUserRoleModel->duplicate($project_src_id, $project_dst_id) &&
+ $this->projectGroupRoleModel->duplicate($project_src_id, $project_dst_id);
}
}
diff --git a/app/Model/ProjectUserRole.php b/app/Model/ProjectUserRoleModel.php
index 2956c524..a0df0cfa 100644
--- a/app/Model/ProjectUserRole.php
+++ b/app/Model/ProjectUserRoleModel.php
@@ -2,15 +2,16 @@
namespace Kanboard\Model;
+use Kanboard\Core\Base;
use Kanboard\Core\Security\Role;
/**
* Project User Role
*
- * @package model
+ * @package Kanboard\Model
* @author Frederic Guillot
*/
-class ProjectUserRole extends Base
+class ProjectUserRoleModel extends Base
{
/**
* SQL table name
@@ -28,7 +29,7 @@ class ProjectUserRole extends Base
*/
public function getActiveProjectsByUser($user_id)
{
- return $this->getProjectsByUser($user_id, array(Project::ACTIVE));
+ return $this->getProjectsByUser($user_id, array(ProjectModel::ACTIVE));
}
/**
@@ -39,19 +40,19 @@ class ProjectUserRole extends Base
* @param array $status
* @return array
*/
- public function getProjectsByUser($user_id, $status = array(Project::ACTIVE, Project::INACTIVE))
+ public function getProjectsByUser($user_id, $status = array(ProjectModel::ACTIVE, ProjectModel::INACTIVE))
{
$userProjects = $this->db
- ->hashtable(Project::TABLE)
+ ->hashtable(ProjectModel::TABLE)
->beginOr()
->eq(self::TABLE.'.user_id', $user_id)
- ->eq(Project::TABLE.'.is_everybody_allowed', 1)
+ ->eq(ProjectModel::TABLE.'.is_everybody_allowed', 1)
->closeOr()
- ->in(Project::TABLE.'.is_active', $status)
+ ->in(ProjectModel::TABLE.'.is_active', $status)
->join(self::TABLE, 'project_id', 'id')
- ->getAll(Project::TABLE.'.id', Project::TABLE.'.name');
+ ->getAll(ProjectModel::TABLE.'.id', ProjectModel::TABLE.'.name');
- $groupProjects = $this->projectGroupRole->getProjectsByUser($user_id, $status);
+ $groupProjects = $this->projectGroupRoleModel->getProjectsByUser($user_id, $status);
$projects = $userProjects + $groupProjects;
asort($projects);
@@ -69,14 +70,19 @@ class ProjectUserRole extends Base
*/
public function getUserRole($project_id, $user_id)
{
- if ($this->projectPermission->isEverybodyAllowed($project_id)) {
- return Role::PROJECT_MEMBER;
+ $projectInfo = $this->db->table(ProjectModel::TABLE)
+ ->eq('id', $project_id)
+ ->columns('owner_id', 'is_everybody_allowed')
+ ->findOne();
+
+ if ($projectInfo['is_everybody_allowed'] == 1) {
+ return $projectInfo['owner_id'] == $user_id ? Role::PROJECT_MANAGER : Role::PROJECT_MEMBER;
}
$role = $this->db->table(self::TABLE)->eq('user_id', $user_id)->eq('project_id', $project_id)->findOneColumn('role');
if (empty($role)) {
- $role = $this->projectGroupRole->getUserRole($project_id, $user_id);
+ $role = $this->projectGroupRoleModel->getUserRole($project_id, $user_id);
}
return $role;
@@ -92,11 +98,11 @@ class ProjectUserRole extends Base
public function getUsers($project_id)
{
return $this->db->table(self::TABLE)
- ->columns(User::TABLE.'.id', User::TABLE.'.username', User::TABLE.'.name', self::TABLE.'.role')
- ->join(User::TABLE, 'id', 'user_id')
+ ->columns(UserModel::TABLE.'.id', UserModel::TABLE.'.username', UserModel::TABLE.'.name', self::TABLE.'.role')
+ ->join(UserModel::TABLE, 'id', 'user_id')
->eq('project_id', $project_id)
- ->asc(User::TABLE.'.username')
- ->asc(User::TABLE.'.name')
+ ->asc(UserModel::TABLE.'.username')
+ ->asc(UserModel::TABLE.'.name')
->findAll();
}
@@ -110,10 +116,10 @@ class ProjectUserRole extends Base
public function getAllUsers($project_id)
{
$userMembers = $this->getUsers($project_id);
- $groupMembers = $this->projectGroupRole->getUsers($project_id);
+ $groupMembers = $this->projectGroupRoleModel->getUsers($project_id);
$members = array_merge($userMembers, $groupMembers);
- return $this->user->prepareList($members);
+ return $this->userModel->prepareList($members);
}
/**
@@ -128,7 +134,7 @@ class ProjectUserRole extends Base
$users = array();
$userMembers = $this->getUsers($project_id);
- $groupMembers = $this->projectGroupRole->getUsers($project_id);
+ $groupMembers = $this->projectGroupRoleModel->getUsers($project_id);
$members = array_merge($userMembers, $groupMembers);
foreach ($members as $user) {
@@ -151,22 +157,22 @@ class ProjectUserRole extends Base
*/
public function getAssignableUsers($project_id)
{
- if ($this->projectPermission->isEverybodyAllowed($project_id)) {
- return $this->user->getActiveUsersList();
+ if ($this->projectPermissionModel->isEverybodyAllowed($project_id)) {
+ return $this->userModel->getActiveUsersList();
}
$userMembers = $this->db->table(self::TABLE)
- ->columns(User::TABLE.'.id', User::TABLE.'.username', User::TABLE.'.name')
- ->join(User::TABLE, 'id', 'user_id')
- ->eq(User::TABLE.'.is_active', 1)
+ ->columns(UserModel::TABLE.'.id', UserModel::TABLE.'.username', UserModel::TABLE.'.name')
+ ->join(UserModel::TABLE, 'id', 'user_id')
+ ->eq(UserModel::TABLE.'.is_active', 1)
->eq(self::TABLE.'.project_id', $project_id)
->in(self::TABLE.'.role', array(Role::PROJECT_MANAGER, Role::PROJECT_MEMBER))
->findAll();
- $groupMembers = $this->projectGroupRole->getAssignableUsers($project_id);
+ $groupMembers = $this->projectGroupRoleModel->getAssignableUsers($project_id);
$members = array_merge($userMembers, $groupMembers);
- return $this->user->prepareList($members);
+ return $this->userModel->prepareList($members);
}
/**
@@ -192,7 +198,7 @@ class ProjectUserRole extends Base
}
if ($everybody) {
- $users = array(User::EVERYBODY_ID => t('Everybody')) + $users;
+ $users = array(UserModel::EVERYBODY_ID => t('Everybody')) + $users;
}
return $users;
diff --git a/app/Model/RememberMeSession.php b/app/Model/RememberMeSessionModel.php
index 8989a6d7..f6c8d648 100644
--- a/app/Model/RememberMeSession.php
+++ b/app/Model/RememberMeSessionModel.php
@@ -2,15 +2,16 @@
namespace Kanboard\Model;
+use Kanboard\Core\Base;
use Kanboard\Core\Security\Token;
/**
* Remember Me Model
*
- * @package model
+ * @package Kanboard\Model
* @author Frederic Guillot
*/
-class RememberMeSession extends Base
+class RememberMeSessionModel extends Base
{
/**
* SQL table name
diff --git a/app/Model/Setting.php b/app/Model/SettingModel.php
index c5a4765c..5b2ee54f 100644
--- a/app/Model/Setting.php
+++ b/app/Model/SettingModel.php
@@ -2,13 +2,15 @@
namespace Kanboard\Model;
+use Kanboard\Core\Base;
+
/**
* Application Settings
*
- * @package model
+ * @package Kanboard\Model
* @author Frederic Guillot
*/
-abstract class Setting extends Base
+abstract class SettingModel extends Base
{
/**
* SQL table name
diff --git a/app/Model/Subtask.php b/app/Model/SubtaskModel.php
index 3f5cfe83..019064ad 100644
--- a/app/Model/Subtask.php
+++ b/app/Model/SubtaskModel.php
@@ -3,15 +3,16 @@
namespace Kanboard\Model;
use PicoDb\Database;
+use Kanboard\Core\Base;
use Kanboard\Event\SubtaskEvent;
/**
* Subtask Model
*
- * @package model
+ * @package Kanboard\Model
* @author Frederic Guillot
*/
-class Subtask extends Base
+class SubtaskModel extends Base
{
/**
* SQL table name
@@ -95,20 +96,20 @@ class Subtask extends Base
*/
public function getUserQuery($user_id, array $status)
{
- return $this->db->table(Subtask::TABLE)
+ return $this->db->table(SubtaskModel::TABLE)
->columns(
- Subtask::TABLE.'.*',
- Task::TABLE.'.project_id',
- Task::TABLE.'.color_id',
- Task::TABLE.'.title AS task_name',
- Project::TABLE.'.name AS project_name'
+ SubtaskModel::TABLE.'.*',
+ TaskModel::TABLE.'.project_id',
+ TaskModel::TABLE.'.color_id',
+ TaskModel::TABLE.'.title AS task_name',
+ ProjectModel::TABLE.'.name AS project_name'
)
- ->subquery($this->subtaskTimeTracking->getTimerQuery($user_id), 'timer_start_date')
+ ->subquery($this->subtaskTimeTrackingModel->getTimerQuery($user_id), 'timer_start_date')
->eq('user_id', $user_id)
- ->eq(Project::TABLE.'.is_active', Project::ACTIVE)
- ->in(Subtask::TABLE.'.status', $status)
- ->join(Task::TABLE, 'id', 'task_id')
- ->join(Project::TABLE, 'id', 'project_id', Task::TABLE)
+ ->eq(ProjectModel::TABLE.'.is_active', ProjectModel::ACTIVE)
+ ->in(SubtaskModel::TABLE.'.status', $status)
+ ->join(TaskModel::TABLE, 'id', 'task_id')
+ ->join(ProjectModel::TABLE, 'id', 'project_id', TaskModel::TABLE)
->callback(array($this, 'addStatusName'));
}
@@ -126,11 +127,11 @@ class Subtask extends Base
->eq('task_id', $task_id)
->columns(
self::TABLE.'.*',
- User::TABLE.'.username',
- User::TABLE.'.name'
+ UserModel::TABLE.'.username',
+ UserModel::TABLE.'.name'
)
- ->subquery($this->subtaskTimeTracking->getTimerQuery($this->userSession->getId()), 'timer_start_date')
- ->join(User::TABLE, 'id', 'user_id')
+ ->subquery($this->subtaskTimeTrackingModel->getTimerQuery($this->userSession->getId()), 'timer_start_date')
+ ->join(UserModel::TABLE, 'id', 'user_id')
->asc(self::TABLE.'.position')
->callback(array($this, 'addStatusName'))
->findAll();
@@ -150,9 +151,9 @@ class Subtask extends Base
return $this->db
->table(self::TABLE)
->eq(self::TABLE.'.id', $subtask_id)
- ->columns(self::TABLE.'.*', User::TABLE.'.username', User::TABLE.'.name')
- ->subquery($this->subtaskTimeTracking->getTimerQuery($this->userSession->getId()), 'timer_start_date')
- ->join(User::TABLE, 'id', 'user_id')
+ ->columns(self::TABLE.'.*', UserModel::TABLE.'.username', UserModel::TABLE.'.name')
+ ->subquery($this->subtaskTimeTrackingModel->getTimerQuery($this->userSession->getId()), 'timer_start_date')
+ ->join(UserModel::TABLE, 'id', 'user_id')
->callback(array($this, 'addStatusName'))
->findOne();
}
@@ -215,9 +216,9 @@ class Subtask extends Base
public function create(array $values)
{
$this->prepareCreation($values);
- $subtask_id = $this->persist(self::TABLE, $values);
+ $subtask_id = $this->db->table(self::TABLE)->persist($values);
- if ($subtask_id) {
+ if ($subtask_id !== false) {
$this->container['dispatcher']->dispatch(
self::EVENT_CREATE,
new SubtaskEvent(array('id' => $subtask_id) + $values)
@@ -344,7 +345,7 @@ class Subtask extends Base
*/
public function hasSubtaskInProgress($user_id)
{
- return $this->config->get('subtask_restriction') == 1 &&
+ return $this->configModel->get('subtask_restriction') == 1 &&
$this->db->table(self::TABLE)
->eq('status', self::STATUS_INPROGRESS)
->eq('user_id', $user_id)
@@ -382,7 +383,7 @@ class Subtask extends Base
{
return $this->db->transaction(function (Database $db) use ($src_task_id, $dst_task_id) {
- $subtasks = $db->table(Subtask::TABLE)
+ $subtasks = $db->table(SubtaskModel::TABLE)
->columns('title', 'time_estimated', 'position')
->eq('task_id', $src_task_id)
->asc('position')
@@ -391,10 +392,37 @@ class Subtask extends Base
foreach ($subtasks as &$subtask) {
$subtask['task_id'] = $dst_task_id;
- if (! $db->table(Subtask::TABLE)->save($subtask)) {
+ if (! $db->table(SubtaskModel::TABLE)->save($subtask)) {
return false;
}
}
});
}
+
+ /**
+ * Convert a subtask to a task
+ *
+ * @access public
+ * @param integer $project_id
+ * @param integer $subtask_id
+ * @return integer
+ */
+ public function convertToTask($project_id, $subtask_id)
+ {
+ $subtask = $this->getById($subtask_id);
+
+ $task_id = $this->taskCreationModel->create(array(
+ 'project_id' => $project_id,
+ 'title' => $subtask['title'],
+ 'time_estimated' => $subtask['time_estimated'],
+ 'time_spent' => $subtask['time_spent'],
+ 'owner_id' => $subtask['user_id'],
+ ));
+
+ if ($task_id !== false) {
+ $this->remove($subtask_id);
+ }
+
+ return $task_id;
+ }
}
diff --git a/app/Model/SubtaskTimeTracking.php b/app/Model/SubtaskTimeTrackingModel.php
index be04ee1b..062e594a 100644
--- a/app/Model/SubtaskTimeTracking.php
+++ b/app/Model/SubtaskTimeTrackingModel.php
@@ -3,14 +3,15 @@
namespace Kanboard\Model;
use DateTime;
+use Kanboard\Core\Base;
/**
- * Subtask timesheet
+ * Subtask time tracking
*
- * @package model
+ * @package Kanboard\Model
* @author Frederic Guillot
*/
-class SubtaskTimeTracking extends Base
+class SubtaskTimeTrackingModel extends Base
{
/**
* SQL table name
@@ -36,7 +37,7 @@ class SubtaskTimeTracking extends Base
$user_id,
$this->db->escapeIdentifier('end'),
$this->db->escapeIdentifier('subtask_id'),
- Subtask::TABLE.'.id'
+ SubtaskModel::TABLE.'.id'
);
}
@@ -57,14 +58,14 @@ class SubtaskTimeTracking extends Base
self::TABLE.'.end',
self::TABLE.'.start',
self::TABLE.'.time_spent',
- Subtask::TABLE.'.task_id',
- Subtask::TABLE.'.title AS subtask_title',
- Task::TABLE.'.title AS task_title',
- Task::TABLE.'.project_id',
- Task::TABLE.'.color_id'
+ SubtaskModel::TABLE.'.task_id',
+ SubtaskModel::TABLE.'.title AS subtask_title',
+ TaskModel::TABLE.'.title AS task_title',
+ TaskModel::TABLE.'.project_id',
+ TaskModel::TABLE.'.color_id'
)
- ->join(Subtask::TABLE, 'id', 'subtask_id')
- ->join(Task::TABLE, 'id', 'task_id', Subtask::TABLE)
+ ->join(SubtaskModel::TABLE, 'id', 'subtask_id')
+ ->join(TaskModel::TABLE, 'id', 'task_id', SubtaskModel::TABLE)
->eq(self::TABLE.'.user_id', $user_id);
}
@@ -86,16 +87,16 @@ class SubtaskTimeTracking extends Base
self::TABLE.'.start',
self::TABLE.'.time_spent',
self::TABLE.'.user_id',
- Subtask::TABLE.'.task_id',
- Subtask::TABLE.'.title AS subtask_title',
- Task::TABLE.'.project_id',
- User::TABLE.'.username',
- User::TABLE.'.name AS user_fullname'
+ SubtaskModel::TABLE.'.task_id',
+ SubtaskModel::TABLE.'.title AS subtask_title',
+ TaskModel::TABLE.'.project_id',
+ UserModel::TABLE.'.username',
+ UserModel::TABLE.'.name AS user_fullname'
)
- ->join(Subtask::TABLE, 'id', 'subtask_id')
- ->join(Task::TABLE, 'id', 'task_id', Subtask::TABLE)
- ->join(User::TABLE, 'id', 'user_id', self::TABLE)
- ->eq(Task::TABLE.'.id', $task_id);
+ ->join(SubtaskModel::TABLE, 'id', 'subtask_id')
+ ->join(TaskModel::TABLE, 'id', 'task_id', SubtaskModel::TABLE)
+ ->join(UserModel::TABLE, 'id', 'user_id', self::TABLE)
+ ->eq(TaskModel::TABLE.'.id', $task_id);
}
/**
@@ -116,17 +117,17 @@ class SubtaskTimeTracking extends Base
self::TABLE.'.start',
self::TABLE.'.time_spent',
self::TABLE.'.user_id',
- Subtask::TABLE.'.task_id',
- Subtask::TABLE.'.title AS subtask_title',
- Task::TABLE.'.project_id',
- Task::TABLE.'.color_id',
- User::TABLE.'.username',
- User::TABLE.'.name AS user_fullname'
+ SubtaskModel::TABLE.'.task_id',
+ SubtaskModel::TABLE.'.title AS subtask_title',
+ TaskModel::TABLE.'.project_id',
+ TaskModel::TABLE.'.color_id',
+ UserModel::TABLE.'.username',
+ UserModel::TABLE.'.name AS user_fullname'
)
- ->join(Subtask::TABLE, 'id', 'subtask_id')
- ->join(Task::TABLE, 'id', 'task_id', Subtask::TABLE)
- ->join(User::TABLE, 'id', 'user_id', self::TABLE)
- ->eq(Task::TABLE.'.project_id', $project_id)
+ ->join(SubtaskModel::TABLE, 'id', 'subtask_id')
+ ->join(TaskModel::TABLE, 'id', 'task_id', SubtaskModel::TABLE)
+ ->join(UserModel::TABLE, 'id', 'user_id', self::TABLE)
+ ->eq(TaskModel::TABLE.'.project_id', $project_id)
->asc(self::TABLE.'.id');
}
@@ -249,10 +250,10 @@ class SubtaskTimeTracking extends Base
*/
public function updateSubtaskTimeSpent($subtask_id, $time_spent)
{
- $subtask = $this->subtask->getById($subtask_id);
+ $subtask = $this->subtaskModel->getById($subtask_id);
// Fire the event subtask.update
- return $this->subtask->update(array(
+ return $this->subtaskModel->update(array(
'id' => $subtask['id'],
'time_spent' => $subtask['time_spent'] + $time_spent,
'task_id' => $subtask['task_id'],
@@ -271,7 +272,7 @@ class SubtaskTimeTracking extends Base
$values = $this->calculateSubtaskTime($task_id);
return $this->db
- ->table(Task::TABLE)
+ ->table(TaskModel::TABLE)
->eq('id', $task_id)
->update($values);
}
@@ -286,7 +287,7 @@ class SubtaskTimeTracking extends Base
public function calculateSubtaskTime($task_id)
{
return $this->db
- ->table(Subtask::TABLE)
+ ->table(SubtaskModel::TABLE)
->eq('task_id', $task_id)
->columns(
'SUM(time_spent) AS time_spent',
diff --git a/app/Model/Swimlane.php b/app/Model/SwimlaneModel.php
index 721f20d3..35e39879 100644
--- a/app/Model/Swimlane.php
+++ b/app/Model/SwimlaneModel.php
@@ -2,13 +2,15 @@
namespace Kanboard\Model;
+use Kanboard\Core\Base;
+
/**
* Swimlanes
*
- * @package model
+ * @package Kanboard\Model
* @author Frederic Guillot
*/
-class Swimlane extends Base
+class SwimlaneModel extends Base
{
/**
* SQL table name
@@ -88,6 +90,22 @@ class Swimlane extends Base
}
/**
+ * Get first active swimlane for a project
+ *
+ * @access public
+ * @param integer $project_id
+ * @return array
+ */
+ public function getFirstActiveSwimlane($project_id)
+ {
+ return $this->db->table(self::TABLE)
+ ->eq('is_active', self::ACTIVE)
+ ->eq('project_id', $project_id)
+ ->orderBy('position', 'asc')
+ ->findOne();
+ }
+
+ /**
* Get default swimlane properties
*
* @access public
@@ -97,7 +115,7 @@ class Swimlane extends Base
public function getDefault($project_id)
{
$result = $this->db
- ->table(Project::TABLE)
+ ->table(ProjectModel::TABLE)
->eq('id', $project_id)
->columns('id', 'default_swimlane', 'show_default_swimlane')
->findOne();
@@ -167,7 +185,7 @@ class Swimlane extends Base
->findAll();
$default_swimlane = $this->db
- ->table(Project::TABLE)
+ ->table(ProjectModel::TABLE)
->eq('id', $project_id)
->eq('show_default_swimlane', 1)
->findOneColumn('default_swimlane');
@@ -195,7 +213,7 @@ class Swimlane extends Base
public function getList($project_id, $prepend = false, $only_active = false)
{
$swimlanes = array();
- $default = $this->db->table(Project::TABLE)->eq('id', $project_id)->eq('show_default_swimlane', 1)->findOneColumn('default_swimlane');
+ $default = $this->db->table(ProjectModel::TABLE)->eq('id', $project_id)->eq('show_default_swimlane', 1)->findOneColumn('default_swimlane');
if ($prepend) {
$swimlanes[-1] = t('All swimlanes');
@@ -222,11 +240,12 @@ class Swimlane extends Base
*/
public function create($values)
{
- if (! $this->project->exists($values['project_id'])) {
+ if (! $this->projectModel->exists($values['project_id'])) {
return 0;
}
+
$values['position'] = $this->getLastPosition($values['project_id']);
- return $this->persist(self::TABLE, $values);
+ return $this->db->table(self::TABLE)->persist($values);
}
/**
@@ -254,7 +273,7 @@ class Swimlane extends Base
public function updateDefault(array $values)
{
return $this->db
- ->table(Project::TABLE)
+ ->table(ProjectModel::TABLE)
->eq('id', $values['id'])
->update(array(
'default_swimlane' => $values['default_swimlane'],
@@ -272,7 +291,7 @@ class Swimlane extends Base
public function enableDefault($project_id)
{
return $this->db
- ->table(Project::TABLE)
+ ->table(ProjectModel::TABLE)
->eq('id', $project_id)
->update(array(
'show_default_swimlane' => 1,
@@ -289,7 +308,7 @@ class Swimlane extends Base
public function disableDefault($project_id)
{
return $this->db
- ->table(Project::TABLE)
+ ->table(ProjectModel::TABLE)
->eq('id', $project_id)
->update(array(
'show_default_swimlane' => 0,
@@ -370,7 +389,7 @@ class Swimlane extends Base
$this->db->startTransaction();
// Tasks should not be assigned anymore to this swimlane
- $this->db->table(Task::TABLE)->eq('swimlane_id', $swimlane_id)->update(array('swimlane_id' => 0));
+ $this->db->table(TaskModel::TABLE)->eq('swimlane_id', $swimlane_id)->update(array('swimlane_id' => 0));
if (! $this->db->table(self::TABLE)->eq('id', $swimlane_id)->remove()) {
$this->db->cancelTransaction();
diff --git a/app/Model/TaskAnalytic.php b/app/Model/TaskAnalyticModel.php
index cff56744..3d6fe8a8 100644
--- a/app/Model/TaskAnalytic.php
+++ b/app/Model/TaskAnalyticModel.php
@@ -2,13 +2,15 @@
namespace Kanboard\Model;
+use Kanboard\Core\Base;
+
/**
* Task Analytic
*
- * @package model
+ * @package Kanboard\Model
* @author Frederic Guillot
*/
-class TaskAnalytic extends Base
+class TaskAnalyticModel extends Base
{
/**
* Get the time between date_creation and date_completed or now if empty
@@ -48,8 +50,8 @@ class TaskAnalytic extends Base
public function getTimeSpentByColumn(array $task)
{
$result = array();
- $columns = $this->column->getList($task['project_id']);
- $sums = $this->transition->getTimeSpentByTask($task['id']);
+ $columns = $this->columnModel->getList($task['project_id']);
+ $sums = $this->transitionModel->getTimeSpentByTask($task['id']);
foreach ($columns as $column_id => $column_title) {
$time_spent = isset($sums[$column_id]) ? $sums[$column_id] : 0;
diff --git a/app/Model/TaskCreation.php b/app/Model/TaskCreationModel.php
index 2d2e5504..3800f831 100644
--- a/app/Model/TaskCreation.php
+++ b/app/Model/TaskCreationModel.php
@@ -2,15 +2,16 @@
namespace Kanboard\Model;
+use Kanboard\Core\Base;
use Kanboard\Event\TaskEvent;
/**
* Task Creation
*
- * @package model
+ * @package Kanboard\Model
* @author Frederic Guillot
*/
-class TaskCreation extends Base
+class TaskCreationModel extends Base
{
/**
* Create a task
@@ -21,18 +22,18 @@ class TaskCreation extends Base
*/
public function create(array $values)
{
- if (! $this->project->exists($values['project_id'])) {
+ if (! $this->projectModel->exists($values['project_id'])) {
return 0;
}
$position = empty($values['position']) ? 0 : $values['position'];
$this->prepare($values);
- $task_id = $this->persist(Task::TABLE, $values);
+ $task_id = $this->db->table(TaskModel::TABLE)->persist($values);
if ($task_id !== false) {
if ($position > 0 && $values['position'] > 1) {
- $this->taskPosition->movePosition($values['project_id'], $task_id, $values['column_id'], $position, $values['swimlane_id'], false);
+ $this->taskPositionModel->movePosition($values['project_id'], $task_id, $values['column_id'], $position, $values['swimlane_id'], false);
}
$this->fireEvents($task_id, $values);
@@ -56,11 +57,11 @@ class TaskCreation extends Base
$this->helper->model->resetFields($values, array('date_started', 'creator_id', 'owner_id', 'swimlane_id', 'date_due', 'score', 'category_id', 'time_estimated'));
if (empty($values['column_id'])) {
- $values['column_id'] = $this->column->getFirstColumnId($values['project_id']);
+ $values['column_id'] = $this->columnModel->getFirstColumnId($values['project_id']);
}
if (empty($values['color_id'])) {
- $values['color_id'] = $this->color->getDefaultColor();
+ $values['color_id'] = $this->colorModel->getDefaultColor();
}
if (empty($values['title'])) {
@@ -75,7 +76,7 @@ class TaskCreation extends Base
$values['date_creation'] = time();
$values['date_modification'] = $values['date_creation'];
$values['date_moved'] = $values['date_creation'];
- $values['position'] = $this->taskFinder->countByColumnAndSwimlaneId($values['project_id'], $values['column_id'], $values['swimlane_id']) + 1;
+ $values['position'] = $this->taskFinderModel->countByColumnAndSwimlaneId($values['project_id'], $values['column_id'], $values['swimlane_id']) + 1;
}
/**
@@ -89,14 +90,14 @@ class TaskCreation extends Base
{
$event = new TaskEvent(array('task_id' => $task_id) + $values);
- $this->logger->debug('Event fired: '.Task::EVENT_CREATE_UPDATE);
- $this->logger->debug('Event fired: '.Task::EVENT_CREATE);
+ $this->logger->debug('Event fired: '.TaskModel::EVENT_CREATE_UPDATE);
+ $this->logger->debug('Event fired: '.TaskModel::EVENT_CREATE);
- $this->dispatcher->dispatch(Task::EVENT_CREATE_UPDATE, $event);
- $this->dispatcher->dispatch(Task::EVENT_CREATE, $event);
+ $this->dispatcher->dispatch(TaskModel::EVENT_CREATE_UPDATE, $event);
+ $this->dispatcher->dispatch(TaskModel::EVENT_CREATE, $event);
if (! empty($values['description'])) {
- $this->userMention->fireEvents($values['description'], Task::EVENT_USER_MENTION, $event);
+ $this->userMentionModel->fireEvents($values['description'], TaskModel::EVENT_USER_MENTION, $event);
}
}
}
diff --git a/app/Model/TaskDuplication.php b/app/Model/TaskDuplicationModel.php
index ebdd4d29..9a4613e2 100644
--- a/app/Model/TaskDuplication.php
+++ b/app/Model/TaskDuplicationModel.php
@@ -4,15 +4,16 @@ namespace Kanboard\Model;
use DateTime;
use DateInterval;
+use Kanboard\Core\Base;
use Kanboard\Event\TaskEvent;
/**
* Task Duplication
*
- * @package model
+ * @package Kanboard\Model
* @author Frederic Guillot
*/
-class TaskDuplication extends Base
+class TaskDuplicationModel extends Base
{
/**
* Fields to copy when duplicating a task
@@ -62,19 +63,19 @@ class TaskDuplication extends Base
{
$values = $this->copyFields($task_id);
- if ($values['recurrence_status'] == Task::RECURRING_STATUS_PENDING) {
+ if ($values['recurrence_status'] == TaskModel::RECURRING_STATUS_PENDING) {
$values['recurrence_parent'] = $task_id;
- $values['column_id'] = $this->column->getFirstColumnId($values['project_id']);
+ $values['column_id'] = $this->columnModel->getFirstColumnId($values['project_id']);
$this->calculateRecurringTaskDueDate($values);
$recurring_task_id = $this->save($task_id, $values);
if ($recurring_task_id > 0) {
$parent_update = $this->db
- ->table(Task::TABLE)
+ ->table(TaskModel::TABLE)
->eq('id', $task_id)
->update(array(
- 'recurrence_status' => Task::RECURRING_STATUS_PROCESSED,
+ 'recurrence_status' => TaskModel::RECURRING_STATUS_PROCESSED,
'recurrence_child' => $recurring_task_id,
));
@@ -127,22 +128,22 @@ class TaskDuplication extends Base
*/
public function moveToProject($task_id, $project_id, $swimlane_id = null, $column_id = null, $category_id = null, $owner_id = null)
{
- $task = $this->taskFinder->getById($task_id);
+ $task = $this->taskFinderModel->getById($task_id);
$values = array();
$values['is_active'] = 1;
$values['project_id'] = $project_id;
$values['column_id'] = $column_id !== null ? $column_id : $task['column_id'];
- $values['position'] = $this->taskFinder->countByColumnId($project_id, $values['column_id']) + 1;
+ $values['position'] = $this->taskFinderModel->countByColumnId($project_id, $values['column_id']) + 1;
$values['swimlane_id'] = $swimlane_id !== null ? $swimlane_id : $task['swimlane_id'];
$values['category_id'] = $category_id !== null ? $category_id : $task['category_id'];
$values['owner_id'] = $owner_id !== null ? $owner_id : $task['owner_id'];
$this->checkDestinationProjectValues($values);
- if ($this->db->table(Task::TABLE)->eq('id', $task['id'])->update($values)) {
+ if ($this->db->table(TaskModel::TABLE)->eq('id', $task['id'])->update($values)) {
$this->container['dispatcher']->dispatch(
- Task::EVENT_MOVE_PROJECT,
+ TaskModel::EVENT_MOVE_PROJECT,
new TaskEvent(array_merge($task, $values, array('task_id' => $task['id'])))
);
}
@@ -160,34 +161,34 @@ class TaskDuplication extends Base
public function checkDestinationProjectValues(array &$values)
{
// Check if the assigned user is allowed for the destination project
- if ($values['owner_id'] > 0 && ! $this->projectPermission->isUserAllowed($values['project_id'], $values['owner_id'])) {
+ if ($values['owner_id'] > 0 && ! $this->projectPermissionModel->isUserAllowed($values['project_id'], $values['owner_id'])) {
$values['owner_id'] = 0;
}
// Check if the category exists for the destination project
if ($values['category_id'] > 0) {
- $values['category_id'] = $this->category->getIdByName(
+ $values['category_id'] = $this->categoryModel->getIdByName(
$values['project_id'],
- $this->category->getNameById($values['category_id'])
+ $this->categoryModel->getNameById($values['category_id'])
);
}
// Check if the swimlane exists for the destination project
if ($values['swimlane_id'] > 0) {
- $values['swimlane_id'] = $this->swimlane->getIdByName(
+ $values['swimlane_id'] = $this->swimlaneModel->getIdByName(
$values['project_id'],
- $this->swimlane->getNameById($values['swimlane_id'])
+ $this->swimlaneModel->getNameById($values['swimlane_id'])
);
}
// Check if the column exists for the destination project
if ($values['column_id'] > 0) {
- $values['column_id'] = $this->column->getColumnIdByTitle(
+ $values['column_id'] = $this->columnModel->getColumnIdByTitle(
$values['project_id'],
- $this->column->getColumnTitleById($values['column_id'])
+ $this->columnModel->getColumnTitleById($values['column_id'])
);
- $values['column_id'] = $values['column_id'] ?: $this->column->getFirstColumnId($values['project_id']);
+ $values['column_id'] = $values['column_id'] ?: $this->columnModel->getFirstColumnId($values['project_id']);
}
return $values;
@@ -202,7 +203,7 @@ class TaskDuplication extends Base
public function calculateRecurringTaskDueDate(array &$values)
{
if (! empty($values['date_due']) && $values['recurrence_factor'] != 0) {
- if ($values['recurrence_basedate'] == Task::RECURRING_BASEDATE_TRIGGERDATE) {
+ if ($values['recurrence_basedate'] == TaskModel::RECURRING_BASEDATE_TRIGGERDATE) {
$values['date_due'] = time();
}
@@ -210,10 +211,10 @@ class TaskDuplication extends Base
$subtract = $values['recurrence_factor'] < 0;
switch ($values['recurrence_timeframe']) {
- case Task::RECURRING_TIMEFRAME_MONTHS:
+ case TaskModel::RECURRING_TIMEFRAME_MONTHS:
$interval = 'P' . $factor . 'M';
break;
- case Task::RECURRING_TIMEFRAME_YEARS:
+ case TaskModel::RECURRING_TIMEFRAME_YEARS:
$interval = 'P' . $factor . 'Y';
break;
default:
@@ -238,7 +239,7 @@ class TaskDuplication extends Base
*/
private function copyFields($task_id)
{
- $task = $this->taskFinder->getById($task_id);
+ $task = $this->taskFinderModel->getById($task_id);
$values = array();
foreach ($this->fields_to_duplicate as $field) {
@@ -258,10 +259,10 @@ class TaskDuplication extends Base
*/
private function save($task_id, array $values)
{
- $new_task_id = $this->taskCreation->create($values);
+ $new_task_id = $this->taskCreationModel->create($values);
if ($new_task_id) {
- $this->subtask->duplicate($task_id, $new_task_id);
+ $this->subtaskModel->duplicate($task_id, $new_task_id);
}
return $new_task_id;
diff --git a/app/Model/TaskExternalLink.php b/app/Model/TaskExternalLinkModel.php
index f2c756b4..220b9c6f 100644
--- a/app/Model/TaskExternalLink.php
+++ b/app/Model/TaskExternalLinkModel.php
@@ -2,13 +2,15 @@
namespace Kanboard\Model;
+use Kanboard\Core\Base;
+
/**
* Task External Link Model
*
- * @package model
+ * @package Kanboard\Model
* @author Frederic Guillot
*/
-class TaskExternalLink extends Base
+class TaskExternalLinkModel extends Base
{
/**
* SQL table name
@@ -29,10 +31,10 @@ class TaskExternalLink extends Base
$types = $this->externalLinkManager->getTypes();
$links = $this->db->table(self::TABLE)
- ->columns(self::TABLE.'.*', User::TABLE.'.name AS creator_name', User::TABLE.'.username AS creator_username')
+ ->columns(self::TABLE.'.*', UserModel::TABLE.'.name AS creator_name', UserModel::TABLE.'.username AS creator_username')
->eq('task_id', $task_id)
->asc('title')
- ->join(User::TABLE, 'id', 'creator_id')
+ ->join(UserModel::TABLE, 'id', 'creator_id')
->findAll();
foreach ($links as &$link) {
@@ -69,7 +71,7 @@ class TaskExternalLink extends Base
$values['date_creation'] = time();
$values['date_modification'] = $values['date_creation'];
- return $this->persist(self::TABLE, $values);
+ return $this->db->table(self::TABLE)->persist($values);
}
/**
diff --git a/app/Model/TaskFile.php b/app/Model/TaskFile.php
deleted file mode 100644
index 45a3b97f..00000000
--- a/app/Model/TaskFile.php
+++ /dev/null
@@ -1,54 +0,0 @@
-<?php
-
-namespace Kanboard\Model;
-
-/**
- * Task File Model
- *
- * @package model
- * @author Frederic Guillot
- */
-class TaskFile extends File
-{
- /**
- * SQL table name
- *
- * @var string
- */
- const TABLE = 'task_has_files';
-
- /**
- * SQL foreign key
- *
- * @var string
- */
- const FOREIGN_KEY = 'task_id';
-
- /**
- * Path prefix
- *
- * @var string
- */
- const PATH_PREFIX = 'tasks';
-
- /**
- * Events
- *
- * @var string
- */
- const EVENT_CREATE = 'task.file.create';
-
- /**
- * Handle screenshot upload
- *
- * @access public
- * @param integer $task_id Task id
- * @param string $blob Base64 encoded image
- * @return bool|integer
- */
- public function uploadScreenshot($task_id, $blob)
- {
- $original_filename = e('Screenshot taken %s', $this->helper->dt->datetime(time())).'.png';
- return $this->uploadContent($task_id, $original_filename, $blob);
- }
-}
diff --git a/app/Model/TaskFileModel.php b/app/Model/TaskFileModel.php
new file mode 100644
index 00000000..24c1ad4b
--- /dev/null
+++ b/app/Model/TaskFileModel.php
@@ -0,0 +1,88 @@
+<?php
+
+namespace Kanboard\Model;
+
+/**
+ * Task File Model
+ *
+ * @package Kanboard\Model
+ * @author Frederic Guillot
+ */
+class TaskFileModel extends FileModel
+{
+ /**
+ * Table name
+ *
+ * @var string
+ */
+ const TABLE = 'task_has_files';
+
+ /**
+ * Events
+ *
+ * @var string
+ */
+ const EVENT_CREATE = 'task.file.create';
+
+ /**
+ * Get the table
+ *
+ * @abstract
+ * @access protected
+ * @return string
+ */
+ protected function getTable()
+ {
+ return self::TABLE;
+ }
+
+ /**
+ * Define the foreign key
+ *
+ * @abstract
+ * @access protected
+ * @return string
+ */
+ protected function getForeignKey()
+ {
+ return 'task_id';
+ }
+
+ /**
+ * Define the path prefix
+ *
+ * @abstract
+ * @access protected
+ * @return string
+ */
+ protected function getPathPrefix()
+ {
+ return 'tasks';
+ }
+
+ /**
+ * Get event name
+ *
+ * @abstract
+ * @access protected
+ * @return string
+ */
+ protected function getEventName()
+ {
+ return self::EVENT_CREATE;
+ }
+
+ /**
+ * Handle screenshot upload
+ *
+ * @access public
+ * @param integer $task_id Task id
+ * @param string $blob Base64 encoded image
+ * @return bool|integer
+ */
+ public function uploadScreenshot($task_id, $blob)
+ {
+ $original_filename = e('Screenshot taken %s', $this->helper->dt->datetime(time())).'.png';
+ return $this->uploadContent($task_id, $original_filename, $blob);
+ }
+}
diff --git a/app/Model/TaskFinder.php b/app/Model/TaskFinderModel.php
index 0b2cbb84..8b636e28 100644
--- a/app/Model/TaskFinder.php
+++ b/app/Model/TaskFinderModel.php
@@ -3,14 +3,15 @@
namespace Kanboard\Model;
use PDO;
+use Kanboard\Core\Base;
/**
* Task Finder model
*
- * @package model
+ * @package Kanboard\Model
* @author Frederic Guillot
*/
-class TaskFinder extends Base
+class TaskFinderModel extends Base
{
/**
* Get query for project user overview
@@ -27,27 +28,27 @@ class TaskFinder extends Base
}
return $this->db
- ->table(Task::TABLE)
+ ->table(TaskModel::TABLE)
->columns(
- Task::TABLE.'.id',
- Task::TABLE.'.title',
- Task::TABLE.'.date_due',
- Task::TABLE.'.date_started',
- Task::TABLE.'.project_id',
- Task::TABLE.'.color_id',
- Task::TABLE.'.priority',
- Task::TABLE.'.time_spent',
- Task::TABLE.'.time_estimated',
- Project::TABLE.'.name AS project_name',
- Column::TABLE.'.title AS column_name',
- User::TABLE.'.username AS assignee_username',
- User::TABLE.'.name AS assignee_name'
+ TaskModel::TABLE.'.id',
+ TaskModel::TABLE.'.title',
+ TaskModel::TABLE.'.date_due',
+ TaskModel::TABLE.'.date_started',
+ TaskModel::TABLE.'.project_id',
+ TaskModel::TABLE.'.color_id',
+ TaskModel::TABLE.'.priority',
+ TaskModel::TABLE.'.time_spent',
+ TaskModel::TABLE.'.time_estimated',
+ ProjectModel::TABLE.'.name AS project_name',
+ ColumnModel::TABLE.'.title AS column_name',
+ UserModel::TABLE.'.username AS assignee_username',
+ UserModel::TABLE.'.name AS assignee_name'
)
- ->eq(Task::TABLE.'.is_active', $is_active)
- ->in(Project::TABLE.'.id', $project_ids)
- ->join(Project::TABLE, 'id', 'project_id')
- ->join(Column::TABLE, 'id', 'column_id', Task::TABLE)
- ->join(User::TABLE, 'id', 'owner_id', Task::TABLE);
+ ->eq(TaskModel::TABLE.'.is_active', $is_active)
+ ->in(ProjectModel::TABLE.'.id', $project_ids)
+ ->join(ProjectModel::TABLE, 'id', 'project_id')
+ ->join(ColumnModel::TABLE, 'id', 'column_id', TaskModel::TABLE)
+ ->join(UserModel::TABLE, 'id', 'owner_id', TaskModel::TABLE);
}
/**
@@ -60,7 +61,7 @@ class TaskFinder extends Base
public function getUserQuery($user_id)
{
return $this->db
- ->table(Task::TABLE)
+ ->table(TaskModel::TABLE)
->columns(
'tasks.id',
'tasks.title',
@@ -71,12 +72,16 @@ class TaskFinder extends Base
'tasks.priority',
'tasks.time_spent',
'tasks.time_estimated',
- 'projects.name AS project_name'
+ 'tasks.is_active',
+ 'tasks.creator_id',
+ 'projects.name AS project_name',
+ 'columns.title AS column_title'
)
- ->join(Project::TABLE, 'id', 'project_id')
- ->eq(Task::TABLE.'.owner_id', $user_id)
- ->eq(Task::TABLE.'.is_active', Task::STATUS_OPEN)
- ->eq(Project::TABLE.'.is_active', Project::ACTIVE);
+ ->join(ProjectModel::TABLE, 'id', 'project_id')
+ ->join(ColumnModel::TABLE, 'id', 'column_id')
+ ->eq(TaskModel::TABLE.'.owner_id', $user_id)
+ ->eq(TaskModel::TABLE.'.is_active', TaskModel::STATUS_OPEN)
+ ->eq(ProjectModel::TABLE.'.is_active', ProjectModel::ACTIVE);
}
/**
@@ -88,15 +93,15 @@ class TaskFinder extends Base
public function getExtendedQuery()
{
return $this->db
- ->table(Task::TABLE)
+ ->table(TaskModel::TABLE)
->columns(
- '(SELECT COUNT(*) FROM '.Comment::TABLE.' WHERE task_id=tasks.id) AS nb_comments',
- '(SELECT COUNT(*) FROM '.TaskFile::TABLE.' WHERE task_id=tasks.id) AS nb_files',
- '(SELECT COUNT(*) FROM '.Subtask::TABLE.' WHERE '.Subtask::TABLE.'.task_id=tasks.id) AS nb_subtasks',
- '(SELECT COUNT(*) FROM '.Subtask::TABLE.' WHERE '.Subtask::TABLE.'.task_id=tasks.id AND status=2) AS nb_completed_subtasks',
- '(SELECT COUNT(*) FROM '.TaskLink::TABLE.' WHERE '.TaskLink::TABLE.'.task_id = tasks.id) AS nb_links',
- '(SELECT COUNT(*) FROM '.TaskExternalLink::TABLE.' WHERE '.TaskExternalLink::TABLE.'.task_id = tasks.id) AS nb_external_links',
- '(SELECT DISTINCT 1 FROM '.TaskLink::TABLE.' WHERE '.TaskLink::TABLE.'.task_id = tasks.id AND '.TaskLink::TABLE.'.link_id = 9) AS is_milestone',
+ '(SELECT COUNT(*) FROM '.CommentModel::TABLE.' WHERE task_id=tasks.id) AS nb_comments',
+ '(SELECT COUNT(*) FROM '.TaskFileModel::TABLE.' WHERE task_id=tasks.id) AS nb_files',
+ '(SELECT COUNT(*) FROM '.SubtaskModel::TABLE.' WHERE '.SubtaskModel::TABLE.'.task_id=tasks.id) AS nb_subtasks',
+ '(SELECT COUNT(*) FROM '.SubtaskModel::TABLE.' WHERE '.SubtaskModel::TABLE.'.task_id=tasks.id AND status=2) AS nb_completed_subtasks',
+ '(SELECT COUNT(*) FROM '.TaskLinkModel::TABLE.' WHERE '.TaskLinkModel::TABLE.'.task_id = tasks.id) AS nb_links',
+ '(SELECT COUNT(*) FROM '.TaskExternalLinkModel::TABLE.' WHERE '.TaskExternalLinkModel::TABLE.'.task_id = tasks.id) AS nb_external_links',
+ '(SELECT DISTINCT 1 FROM '.TaskLinkModel::TABLE.' WHERE '.TaskLinkModel::TABLE.'.task_id = tasks.id AND '.TaskLinkModel::TABLE.'.link_id = 9) AS is_milestone',
'tasks.id',
'tasks.reference',
'tasks.title',
@@ -127,24 +132,24 @@ class TaskFinder extends Base
'tasks.recurrence_child',
'tasks.time_estimated',
'tasks.time_spent',
- User::TABLE.'.username AS assignee_username',
- User::TABLE.'.name AS assignee_name',
- User::TABLE.'.email AS assignee_email',
- User::TABLE.'.avatar_path AS assignee_avatar_path',
- Category::TABLE.'.name AS category_name',
- Category::TABLE.'.description AS category_description',
- Column::TABLE.'.title AS column_name',
- Column::TABLE.'.position AS column_position',
- Swimlane::TABLE.'.name AS swimlane_name',
- Project::TABLE.'.default_swimlane',
- Project::TABLE.'.name AS project_name'
+ UserModel::TABLE.'.username AS assignee_username',
+ UserModel::TABLE.'.name AS assignee_name',
+ UserModel::TABLE.'.email AS assignee_email',
+ UserModel::TABLE.'.avatar_path AS assignee_avatar_path',
+ CategoryModel::TABLE.'.name AS category_name',
+ CategoryModel::TABLE.'.description AS category_description',
+ ColumnModel::TABLE.'.title AS column_name',
+ ColumnModel::TABLE.'.position AS column_position',
+ SwimlaneModel::TABLE.'.name AS swimlane_name',
+ ProjectModel::TABLE.'.default_swimlane',
+ ProjectModel::TABLE.'.name AS project_name'
)
- ->join(User::TABLE, 'id', 'owner_id', Task::TABLE)
- ->left(User::TABLE, 'uc', 'id', Task::TABLE, 'creator_id')
- ->join(Category::TABLE, 'id', 'category_id', Task::TABLE)
- ->join(Column::TABLE, 'id', 'column_id', Task::TABLE)
- ->join(Swimlane::TABLE, 'id', 'swimlane_id', Task::TABLE)
- ->join(Project::TABLE, 'id', 'project_id', Task::TABLE);
+ ->join(UserModel::TABLE, 'id', 'owner_id', TaskModel::TABLE)
+ ->left(UserModel::TABLE, 'uc', 'id', TaskModel::TABLE, 'creator_id')
+ ->join(CategoryModel::TABLE, 'id', 'category_id', TaskModel::TABLE)
+ ->join(ColumnModel::TABLE, 'id', 'column_id', TaskModel::TABLE)
+ ->join(SwimlaneModel::TABLE, 'id', 'swimlane_id', TaskModel::TABLE)
+ ->join(ProjectModel::TABLE, 'id', 'project_id', TaskModel::TABLE);
}
/**
@@ -159,11 +164,11 @@ class TaskFinder extends Base
public function getTasksByColumnAndSwimlane($project_id, $column_id, $swimlane_id = 0)
{
return $this->getExtendedQuery()
- ->eq(Task::TABLE.'.project_id', $project_id)
- ->eq(Task::TABLE.'.column_id', $column_id)
- ->eq(Task::TABLE.'.swimlane_id', $swimlane_id)
- ->eq(Task::TABLE.'.is_active', Task::STATUS_OPEN)
- ->asc(Task::TABLE.'.position')
+ ->eq(TaskModel::TABLE.'.project_id', $project_id)
+ ->eq(TaskModel::TABLE.'.column_id', $column_id)
+ ->eq(TaskModel::TABLE.'.swimlane_id', $swimlane_id)
+ ->eq(TaskModel::TABLE.'.is_active', TaskModel::STATUS_OPEN)
+ ->asc(TaskModel::TABLE.'.position')
->findAll();
}
@@ -175,12 +180,12 @@ class TaskFinder extends Base
* @param integer $status_id Status id
* @return array
*/
- public function getAll($project_id, $status_id = Task::STATUS_OPEN)
+ public function getAll($project_id, $status_id = TaskModel::STATUS_OPEN)
{
return $this->db
- ->table(Task::TABLE)
- ->eq(Task::TABLE.'.project_id', $project_id)
- ->eq(Task::TABLE.'.is_active', $status_id)
+ ->table(TaskModel::TABLE)
+ ->eq(TaskModel::TABLE.'.project_id', $project_id)
+ ->eq(TaskModel::TABLE.'.is_active', $status_id)
->findAll();
}
@@ -192,12 +197,12 @@ class TaskFinder extends Base
* @param array $status
* @return array
*/
- public function getAllIds($project_id, array $status = array(Task::STATUS_OPEN))
+ public function getAllIds($project_id, array $status = array(TaskModel::STATUS_OPEN))
{
return $this->db
- ->table(Task::TABLE)
- ->eq(Task::TABLE.'.project_id', $project_id)
- ->in(Task::TABLE.'.is_active', $status)
+ ->table(TaskModel::TABLE)
+ ->eq(TaskModel::TABLE.'.project_id', $project_id)
+ ->in(TaskModel::TABLE.'.is_active', $status)
->findAllByColumn('id');
}
@@ -209,24 +214,24 @@ class TaskFinder extends Base
*/
public function getOverdueTasksQuery()
{
- return $this->db->table(Task::TABLE)
+ return $this->db->table(TaskModel::TABLE)
->columns(
- Task::TABLE.'.id',
- Task::TABLE.'.title',
- Task::TABLE.'.date_due',
- Task::TABLE.'.project_id',
- Task::TABLE.'.creator_id',
- Task::TABLE.'.owner_id',
- Project::TABLE.'.name AS project_name',
- User::TABLE.'.username AS assignee_username',
- User::TABLE.'.name AS assignee_name'
+ TaskModel::TABLE.'.id',
+ TaskModel::TABLE.'.title',
+ TaskModel::TABLE.'.date_due',
+ TaskModel::TABLE.'.project_id',
+ TaskModel::TABLE.'.creator_id',
+ TaskModel::TABLE.'.owner_id',
+ ProjectModel::TABLE.'.name AS project_name',
+ UserModel::TABLE.'.username AS assignee_username',
+ UserModel::TABLE.'.name AS assignee_name'
)
- ->join(Project::TABLE, 'id', 'project_id')
- ->join(User::TABLE, 'id', 'owner_id')
- ->eq(Project::TABLE.'.is_active', 1)
- ->eq(Task::TABLE.'.is_active', 1)
- ->neq(Task::TABLE.'.date_due', 0)
- ->lte(Task::TABLE.'.date_due', mktime(23, 59, 59));
+ ->join(ProjectModel::TABLE, 'id', 'project_id')
+ ->join(UserModel::TABLE, 'id', 'owner_id')
+ ->eq(ProjectModel::TABLE.'.is_active', 1)
+ ->eq(TaskModel::TABLE.'.is_active', 1)
+ ->neq(TaskModel::TABLE.'.date_due', 0)
+ ->lte(TaskModel::TABLE.'.date_due', mktime(23, 59, 59));
}
/**
@@ -249,7 +254,7 @@ class TaskFinder extends Base
*/
public function getOverdueTasksByProject($project_id)
{
- return $this->getOverdueTasksQuery()->eq(Task::TABLE.'.project_id', $project_id)->findAll();
+ return $this->getOverdueTasksQuery()->eq(TaskModel::TABLE.'.project_id', $project_id)->findAll();
}
/**
@@ -261,7 +266,7 @@ class TaskFinder extends Base
*/
public function getOverdueTasksByUser($user_id)
{
- return $this->getOverdueTasksQuery()->eq(Task::TABLE.'.owner_id', $user_id)->findAll();
+ return $this->getOverdueTasksQuery()->eq(TaskModel::TABLE.'.owner_id', $user_id)->findAll();
}
/**
@@ -273,7 +278,7 @@ class TaskFinder extends Base
*/
public function getProjectId($task_id)
{
- return (int) $this->db->table(Task::TABLE)->eq('id', $task_id)->findOneColumn('project_id') ?: 0;
+ return (int) $this->db->table(TaskModel::TABLE)->eq('id', $task_id)->findOneColumn('project_id') ?: 0;
}
/**
@@ -285,7 +290,7 @@ class TaskFinder extends Base
*/
public function getById($task_id)
{
- return $this->db->table(Task::TABLE)->eq('id', $task_id)->findOne();
+ return $this->db->table(TaskModel::TABLE)->eq('id', $task_id)->findOne();
}
/**
@@ -298,7 +303,7 @@ class TaskFinder extends Base
*/
public function getByReference($project_id, $reference)
{
- return $this->db->table(Task::TABLE)->eq('project_id', $project_id)->eq('reference', $reference)->findOne();
+ return $this->db->table(TaskModel::TABLE)->eq('project_id', $project_id)->eq('reference', $reference)->findOne();
}
/**
@@ -373,11 +378,11 @@ class TaskFinder extends Base
*/
public function getICalQuery()
{
- return $this->db->table(Task::TABLE)
- ->left(User::TABLE, 'ua', 'id', Task::TABLE, 'owner_id')
- ->left(User::TABLE, 'uc', 'id', Task::TABLE, 'creator_id')
+ return $this->db->table(TaskModel::TABLE)
+ ->left(UserModel::TABLE, 'ua', 'id', TaskModel::TABLE, 'owner_id')
+ ->left(UserModel::TABLE, 'uc', 'id', TaskModel::TABLE, 'creator_id')
->columns(
- Task::TABLE.'.*',
+ TaskModel::TABLE.'.*',
'ua.email AS assignee_email',
'ua.name AS assignee_name',
'ua.username AS assignee_username',
@@ -394,10 +399,10 @@ class TaskFinder extends Base
* @param array $status List of status id
* @return integer
*/
- public function countByProjectId($project_id, array $status = array(Task::STATUS_OPEN, Task::STATUS_CLOSED))
+ public function countByProjectId($project_id, array $status = array(TaskModel::STATUS_OPEN, TaskModel::STATUS_CLOSED))
{
return $this->db
- ->table(Task::TABLE)
+ ->table(TaskModel::TABLE)
->eq('project_id', $project_id)
->in('is_active', $status)
->count();
@@ -414,7 +419,7 @@ class TaskFinder extends Base
public function countByColumnId($project_id, $column_id)
{
return $this->db
- ->table(Task::TABLE)
+ ->table(TaskModel::TABLE)
->eq('project_id', $project_id)
->eq('column_id', $column_id)
->eq('is_active', 1)
@@ -433,7 +438,7 @@ class TaskFinder extends Base
public function countByColumnAndSwimlaneId($project_id, $column_id, $swimlane_id)
{
return $this->db
- ->table(Task::TABLE)
+ ->table(TaskModel::TABLE)
->eq('project_id', $project_id)
->eq('column_id', $column_id)
->eq('swimlane_id', $swimlane_id)
@@ -450,6 +455,22 @@ class TaskFinder extends Base
*/
public function exists($task_id)
{
- return $this->db->table(Task::TABLE)->eq('id', $task_id)->exists();
+ return $this->db->table(TaskModel::TABLE)->eq('id', $task_id)->exists();
+ }
+
+ /**
+ * Get project token
+ *
+ * @access public
+ * @param integer $task_id
+ * @return string
+ */
+ public function getProjectToken($task_id)
+ {
+ return $this->db
+ ->table(TaskModel::TABLE)
+ ->eq(TaskModel::TABLE.'.id', $task_id)
+ ->join(ProjectModel::TABLE, 'id', 'project_id')
+ ->findOneColumn(ProjectModel::TABLE.'.token');
}
}
diff --git a/app/Model/TaskLink.php b/app/Model/TaskLinkModel.php
index e46ea476..45225e35 100644
--- a/app/Model/TaskLink.php
+++ b/app/Model/TaskLinkModel.php
@@ -2,16 +2,17 @@
namespace Kanboard\Model;
+use Kanboard\Core\Base;
use Kanboard\Event\TaskLinkEvent;
/**
* TaskLink model
*
- * @package model
+ * @package Kanboard\Model
* @author Olivier Maridat
* @author Frederic Guillot
*/
-class TaskLink extends Base
+class TaskLinkModel extends Base
{
/**
* SQL table name
@@ -48,7 +49,7 @@ class TaskLink extends Base
*/
public function getOppositeTaskLink(array $task_link)
{
- $opposite_link_id = $this->link->getOppositeLinkId($task_link['link_id']);
+ $opposite_link_id = $this->linkModel->getOppositeLinkId($task_link['link_id']);
return $this->db->table(self::TABLE)
->eq('opposite_task_id', $task_link['task_id'])
@@ -71,31 +72,31 @@ class TaskLink extends Base
->columns(
self::TABLE.'.id',
self::TABLE.'.opposite_task_id AS task_id',
- Link::TABLE.'.label',
- Task::TABLE.'.title',
- Task::TABLE.'.is_active',
- Task::TABLE.'.project_id',
- Task::TABLE.'.column_id',
- Task::TABLE.'.color_id',
- Task::TABLE.'.time_spent AS task_time_spent',
- Task::TABLE.'.time_estimated AS task_time_estimated',
- Task::TABLE.'.owner_id AS task_assignee_id',
- User::TABLE.'.username AS task_assignee_username',
- User::TABLE.'.name AS task_assignee_name',
- Column::TABLE.'.title AS column_title',
- Project::TABLE.'.name AS project_name'
+ LinkModel::TABLE.'.label',
+ TaskModel::TABLE.'.title',
+ TaskModel::TABLE.'.is_active',
+ TaskModel::TABLE.'.project_id',
+ TaskModel::TABLE.'.column_id',
+ TaskModel::TABLE.'.color_id',
+ TaskModel::TABLE.'.time_spent AS task_time_spent',
+ TaskModel::TABLE.'.time_estimated AS task_time_estimated',
+ TaskModel::TABLE.'.owner_id AS task_assignee_id',
+ UserModel::TABLE.'.username AS task_assignee_username',
+ UserModel::TABLE.'.name AS task_assignee_name',
+ ColumnModel::TABLE.'.title AS column_title',
+ ProjectModel::TABLE.'.name AS project_name'
)
->eq(self::TABLE.'.task_id', $task_id)
- ->join(Link::TABLE, 'id', 'link_id')
- ->join(Task::TABLE, 'id', 'opposite_task_id')
- ->join(Column::TABLE, 'id', 'column_id', Task::TABLE)
- ->join(User::TABLE, 'id', 'owner_id', Task::TABLE)
- ->join(Project::TABLE, 'id', 'project_id', Task::TABLE)
- ->asc(Link::TABLE.'.id')
- ->desc(Column::TABLE.'.position')
- ->desc(Task::TABLE.'.is_active')
- ->asc(Task::TABLE.'.position')
- ->asc(Task::TABLE.'.id')
+ ->join(LinkModel::TABLE, 'id', 'link_id')
+ ->join(TaskModel::TABLE, 'id', 'opposite_task_id')
+ ->join(ColumnModel::TABLE, 'id', 'column_id', TaskModel::TABLE)
+ ->join(UserModel::TABLE, 'id', 'owner_id', TaskModel::TABLE)
+ ->join(ProjectModel::TABLE, 'id', 'project_id', TaskModel::TABLE)
+ ->asc(LinkModel::TABLE.'.id')
+ ->desc(ColumnModel::TABLE.'.position')
+ ->desc(TaskModel::TABLE.'.is_active')
+ ->asc(TaskModel::TABLE.'.position')
+ ->asc(TaskModel::TABLE.'.id')
->findAll();
}
@@ -131,7 +132,7 @@ class TaskLink extends Base
private function fireEvents(array $events)
{
foreach ($events as $event) {
- $event['project_id'] = $this->taskFinder->getProjectId($event['task_id']);
+ $event['project_id'] = $this->taskFinderModel->getProjectId($event['task_id']);
$this->container['dispatcher']->dispatch(self::EVENT_CREATE_UPDATE, new TaskLinkEvent($event));
}
}
@@ -151,7 +152,7 @@ class TaskLink extends Base
$this->db->startTransaction();
// Get opposite link
- $opposite_link_id = $this->link->getOppositeLinkId($link_id);
+ $opposite_link_id = $this->linkModel->getOppositeLinkId($link_id);
$values = array(
'task_id' => $task_id,
@@ -203,7 +204,7 @@ class TaskLink extends Base
$opposite_task_link = $this->getOppositeTaskLink($task_link);
// Get opposite link
- $opposite_link_id = $this->link->getOppositeLinkId($link_id);
+ $opposite_link_id = $this->linkModel->getOppositeLinkId($link_id);
// Update the original task link
$values = array(
@@ -247,7 +248,7 @@ class TaskLink extends Base
$this->db->startTransaction();
$link = $this->getById($task_link_id);
- $link_id = $this->link->getOppositeLinkId($link['link_id']);
+ $link_id = $this->linkModel->getOppositeLinkId($link['link_id']);
$this->db->table(self::TABLE)->eq('id', $task_link_id)->remove();
diff --git a/app/Model/TaskMetadata.php b/app/Model/TaskMetadataModel.php
index 1fd18415..dc3f56ec 100644
--- a/app/Model/TaskMetadata.php
+++ b/app/Model/TaskMetadataModel.php
@@ -5,17 +5,22 @@ namespace Kanboard\Model;
/**
* Task Metadata
*
- * @package model
+ * @package Kanboard\Model
* @author Frederic Guillot
*/
-class TaskMetadata extends Metadata
+class TaskMetadataModel extends MetadataModel
{
/**
- * SQL table name
+ * Get the table
*
- * @var string
+ * @abstract
+ * @access protected
+ * @return string
*/
- const TABLE = 'task_has_metadata';
+ protected function getTable()
+ {
+ return 'task_has_metadata';
+ }
/**
* Define the entity key
diff --git a/app/Model/Task.php b/app/Model/TaskModel.php
index f8b41b9f..b0e7772a 100644
--- a/app/Model/Task.php
+++ b/app/Model/TaskModel.php
@@ -2,13 +2,15 @@
namespace Kanboard\Model;
+use Kanboard\Core\Base;
+
/**
* Task model
*
- * @package model
+ * @package Kanboard\Model
* @author Frederic Guillot
*/
-class Task extends Base
+class TaskModel extends Base
{
/**
* SQL table name
@@ -88,11 +90,11 @@ class Task extends Base
*/
public function remove($task_id)
{
- if (! $this->taskFinder->exists($task_id)) {
+ if (! $this->taskFinderModel->exists($task_id)) {
return false;
}
- $this->taskFile->removeAll($task_id);
+ $this->taskFileModel->removeAll($task_id);
return $this->db->table(self::TABLE)->eq('id', $task_id)->remove();
}
@@ -124,8 +126,8 @@ class Task extends Base
public function getRecurrenceStatusList()
{
return array(
- Task::RECURRING_STATUS_NONE => t('No'),
- Task::RECURRING_STATUS_PENDING => t('Yes'),
+ TaskModel::RECURRING_STATUS_NONE => t('No'),
+ TaskModel::RECURRING_STATUS_PENDING => t('Yes'),
);
}
@@ -138,9 +140,9 @@ class Task extends Base
public function getRecurrenceTriggerList()
{
return array(
- Task::RECURRING_TRIGGER_FIRST_COLUMN => t('When task is moved from first column'),
- Task::RECURRING_TRIGGER_LAST_COLUMN => t('When task is moved to last column'),
- Task::RECURRING_TRIGGER_CLOSE => t('When task is closed'),
+ TaskModel::RECURRING_TRIGGER_FIRST_COLUMN => t('When task is moved from first column'),
+ TaskModel::RECURRING_TRIGGER_LAST_COLUMN => t('When task is moved to last column'),
+ TaskModel::RECURRING_TRIGGER_CLOSE => t('When task is closed'),
);
}
@@ -153,8 +155,8 @@ class Task extends Base
public function getRecurrenceBasedateList()
{
return array(
- Task::RECURRING_BASEDATE_DUEDATE => t('Existing due date'),
- Task::RECURRING_BASEDATE_TRIGGERDATE => t('Action date'),
+ TaskModel::RECURRING_BASEDATE_DUEDATE => t('Existing due date'),
+ TaskModel::RECURRING_BASEDATE_TRIGGERDATE => t('Action date'),
);
}
@@ -167,9 +169,9 @@ class Task extends Base
public function getRecurrenceTimeframeList()
{
return array(
- Task::RECURRING_TIMEFRAME_DAYS => t('Day(s)'),
- Task::RECURRING_TIMEFRAME_MONTHS => t('Month(s)'),
- Task::RECURRING_TIMEFRAME_YEARS => t('Year(s)'),
+ TaskModel::RECURRING_TIMEFRAME_DAYS => t('Day(s)'),
+ TaskModel::RECURRING_TIMEFRAME_MONTHS => t('Month(s)'),
+ TaskModel::RECURRING_TIMEFRAME_YEARS => t('Year(s)'),
);
}
@@ -210,10 +212,10 @@ class Task extends Base
*/
public function duplicate($src_project_id, $dst_project_id)
{
- $task_ids = $this->taskFinder->getAllIds($src_project_id, array(Task::STATUS_OPEN, Task::STATUS_CLOSED));
+ $task_ids = $this->taskFinderModel->getAllIds($src_project_id, array(TaskModel::STATUS_OPEN, TaskModel::STATUS_CLOSED));
foreach ($task_ids as $task_id) {
- if (! $this->taskDuplication->duplicateToProject($task_id, $dst_project_id)) {
+ if (! $this->taskDuplicationModel->duplicateToProject($task_id, $dst_project_id)) {
return false;
}
}
diff --git a/app/Model/TaskModification.php b/app/Model/TaskModificationModel.php
index a77b78a4..762af2c5 100644
--- a/app/Model/TaskModification.php
+++ b/app/Model/TaskModificationModel.php
@@ -2,15 +2,16 @@
namespace Kanboard\Model;
+use Kanboard\Core\Base;
use Kanboard\Event\TaskEvent;
/**
* Task Modification
*
- * @package model
+ * @package Kanboard\Model
* @author Frederic Guillot
*/
-class TaskModification extends Base
+class TaskModificationModel extends Base
{
/**
* Update a task
@@ -22,10 +23,10 @@ class TaskModification extends Base
*/
public function update(array $values, $fire_events = true)
{
- $original_task = $this->taskFinder->getById($values['id']);
+ $original_task = $this->taskFinderModel->getById($values['id']);
$this->prepare($values);
- $result = $this->db->table(Task::TABLE)->eq('id', $original_task['id'])->update($values);
+ $result = $this->db->table(TaskModel::TABLE)->eq('id', $original_task['id'])->update($values);
if ($fire_events && $result) {
$this->fireEvents($original_task, $values);
@@ -51,10 +52,10 @@ class TaskModification extends Base
unset($event_data['changes']['date_modification']);
if ($this->isFieldModified('owner_id', $event_data['changes'])) {
- $events[] = Task::EVENT_ASSIGNEE_CHANGE;
+ $events[] = TaskModel::EVENT_ASSIGNEE_CHANGE;
} elseif (! empty($event_data['changes'])) {
- $events[] = Task::EVENT_CREATE_UPDATE;
- $events[] = Task::EVENT_UPDATE;
+ $events[] = TaskModel::EVENT_CREATE_UPDATE;
+ $events[] = TaskModel::EVENT_UPDATE;
}
foreach ($events as $event) {
diff --git a/app/Model/TaskPermission.php b/app/Model/TaskPermission.php
deleted file mode 100644
index b1e02589..00000000
--- a/app/Model/TaskPermission.php
+++ /dev/null
@@ -1,34 +0,0 @@
-<?php
-
-namespace Kanboard\Model;
-
-use Kanboard\Core\Security\Role;
-
-/**
- * Task permission model
- *
- * @package model
- * @author Frederic Guillot
- */
-class TaskPermission extends Base
-{
- /**
- * Return true if the user can remove a task
- *
- * Regular users can't remove tasks from other people
- *
- * @public
- * @param array $task
- * @return bool
- */
- public function canRemoveTask(array $task)
- {
- if ($this->userSession->isAdmin() || $this->projectUserRole->getUserRole($task['project_id'], $this->userSession->getId()) === Role::PROJECT_MANAGER) {
- return true;
- } elseif (isset($task['creator_id']) && $task['creator_id'] == $this->userSession->getId()) {
- return true;
- }
-
- return false;
- }
-}
diff --git a/app/Model/TaskPosition.php b/app/Model/TaskPositionModel.php
index 4c9928d7..9fdb8f7d 100644
--- a/app/Model/TaskPosition.php
+++ b/app/Model/TaskPositionModel.php
@@ -2,15 +2,16 @@
namespace Kanboard\Model;
+use Kanboard\Core\Base;
use Kanboard\Event\TaskEvent;
/**
* Task Position
*
- * @package model
+ * @package Kanboard\Model
* @author Frederic Guillot
*/
-class TaskPosition extends Base
+class TaskPositionModel extends Base
{
/**
* Move a task to another column or to another position
@@ -30,9 +31,9 @@ class TaskPosition extends Base
return false;
}
- $task = $this->taskFinder->getById($task_id);
+ $task = $this->taskFinderModel->getById($task_id);
- if ($task['is_active'] == Task::STATUS_CLOSED) {
+ if ($task['is_active'] == TaskModel::STATUS_CLOSED) {
return true;
}
@@ -131,7 +132,7 @@ class TaskPosition extends Base
*/
private function saveTaskPositions($project_id, $task_id, $position, $column_id, $swimlane_id)
{
- $tasks_ids = $this->db->table(Task::TABLE)
+ $tasks_ids = $this->db->table(TaskModel::TABLE)
->eq('is_active', 1)
->eq('swimlane_id', $swimlane_id)
->eq('project_id', $project_id)
@@ -168,7 +169,7 @@ class TaskPosition extends Base
$now = time();
- return $this->db->table(Task::TABLE)->eq('id', $task_id)->update(array(
+ return $this->db->table(TaskModel::TABLE)->eq('id', $task_id)->update(array(
'date_moved' => $now,
'date_modification' => $now,
));
@@ -186,7 +187,7 @@ class TaskPosition extends Base
*/
private function saveTaskPosition($task_id, $position, $column_id, $swimlane_id)
{
- $result = $this->db->table(Task::TABLE)->eq('id', $task_id)->update(array(
+ $result = $this->db->table(TaskModel::TABLE)->eq('id', $task_id)->update(array(
'position' => $position,
'column_id' => $column_id,
'swimlane_id' => $swimlane_id,
@@ -225,14 +226,14 @@ class TaskPosition extends Base
);
if ($task['swimlane_id'] != $new_swimlane_id) {
- $this->logger->debug('Event fired: '.Task::EVENT_MOVE_SWIMLANE);
- $this->dispatcher->dispatch(Task::EVENT_MOVE_SWIMLANE, new TaskEvent($event_data));
+ $this->logger->debug('Event fired: '.TaskModel::EVENT_MOVE_SWIMLANE);
+ $this->dispatcher->dispatch(TaskModel::EVENT_MOVE_SWIMLANE, new TaskEvent($event_data));
} elseif ($task['column_id'] != $new_column_id) {
- $this->logger->debug('Event fired: '.Task::EVENT_MOVE_COLUMN);
- $this->dispatcher->dispatch(Task::EVENT_MOVE_COLUMN, new TaskEvent($event_data));
+ $this->logger->debug('Event fired: '.TaskModel::EVENT_MOVE_COLUMN);
+ $this->dispatcher->dispatch(TaskModel::EVENT_MOVE_COLUMN, new TaskEvent($event_data));
} elseif ($task['position'] != $new_position) {
- $this->logger->debug('Event fired: '.Task::EVENT_MOVE_POSITION);
- $this->dispatcher->dispatch(Task::EVENT_MOVE_POSITION, new TaskEvent($event_data));
+ $this->logger->debug('Event fired: '.TaskModel::EVENT_MOVE_POSITION);
+ $this->dispatcher->dispatch(TaskModel::EVENT_MOVE_POSITION, new TaskEvent($event_data));
}
}
}
diff --git a/app/Model/TaskStatus.php b/app/Model/TaskStatusModel.php
index 2b902815..4d573f0e 100644
--- a/app/Model/TaskStatus.php
+++ b/app/Model/TaskStatusModel.php
@@ -2,15 +2,16 @@
namespace Kanboard\Model;
+use Kanboard\Core\Base;
use Kanboard\Event\TaskEvent;
/**
* Task Status
*
- * @package model
+ * @package Kanboard\Model
* @author Frederic Guillot
*/
-class TaskStatus extends Base
+class TaskStatusModel extends Base
{
/**
* Return true if the task is closed
@@ -21,7 +22,7 @@ class TaskStatus extends Base
*/
public function isClosed($task_id)
{
- return $this->checkStatus($task_id, Task::STATUS_CLOSED);
+ return $this->checkStatus($task_id, TaskModel::STATUS_CLOSED);
}
/**
@@ -33,7 +34,7 @@ class TaskStatus extends Base
*/
public function isOpen($task_id)
{
- return $this->checkStatus($task_id, Task::STATUS_OPEN);
+ return $this->checkStatus($task_id, TaskModel::STATUS_OPEN);
}
/**
@@ -45,8 +46,8 @@ class TaskStatus extends Base
*/
public function close($task_id)
{
- $this->subtask->closeAll($task_id);
- return $this->changeStatus($task_id, Task::STATUS_CLOSED, time(), Task::EVENT_CLOSE);
+ $this->subtaskModel->closeAll($task_id);
+ return $this->changeStatus($task_id, TaskModel::STATUS_CLOSED, time(), TaskModel::EVENT_CLOSE);
}
/**
@@ -58,7 +59,7 @@ class TaskStatus extends Base
*/
public function open($task_id)
{
- return $this->changeStatus($task_id, Task::STATUS_OPEN, 0, Task::EVENT_OPEN);
+ return $this->changeStatus($task_id, TaskModel::STATUS_OPEN, 0, TaskModel::EVENT_OPEN);
}
/**
@@ -83,7 +84,13 @@ class TaskStatus extends Base
*/
public function closeTasksBySwimlaneAndColumn($swimlane_id, $column_id)
{
- $task_ids = $this->db->table(Task::TABLE)->eq('swimlane_id', $swimlane_id)->eq('column_id', $column_id)->findAllByColumn('id');
+ $task_ids = $this->db
+ ->table(TaskModel::TABLE)
+ ->eq('swimlane_id', $swimlane_id)
+ ->eq('column_id', $column_id)
+ ->eq(TaskModel::TABLE.'.is_active', TaskModel::STATUS_OPEN)
+ ->findAllByColumn('id');
+
$this->closeMultipleTasks($task_ids);
}
@@ -99,12 +106,12 @@ class TaskStatus extends Base
*/
private function changeStatus($task_id, $status, $date_completed, $event)
{
- if (! $this->taskFinder->exists($task_id)) {
+ if (! $this->taskFinderModel->exists($task_id)) {
return false;
}
$result = $this->db
- ->table(Task::TABLE)
+ ->table(TaskModel::TABLE)
->eq('id', $task_id)
->update(array(
'is_active' => $status,
@@ -114,7 +121,7 @@ class TaskStatus extends Base
if ($result) {
$this->logger->debug('Event fired: '.$event);
- $this->dispatcher->dispatch($event, new TaskEvent(array('task_id' => $task_id) + $this->taskFinder->getById($task_id)));
+ $this->dispatcher->dispatch($event, new TaskEvent(array('task_id' => $task_id) + $this->taskFinderModel->getById($task_id)));
}
return $result;
@@ -131,7 +138,7 @@ class TaskStatus extends Base
private function checkStatus($task_id, $status)
{
return $this->db
- ->table(Task::TABLE)
+ ->table(TaskModel::TABLE)
->eq('id', $task_id)
->eq('is_active', $status)
->count() === 1;
diff --git a/app/Model/TimezoneModel.php b/app/Model/TimezoneModel.php
new file mode 100644
index 00000000..8b3e895a
--- /dev/null
+++ b/app/Model/TimezoneModel.php
@@ -0,0 +1,58 @@
+<?php
+
+namespace Kanboard\Model;
+
+use Kanboard\Core\Base;
+
+/**
+ * Class Timezone
+ *
+ * @package Kanboard\Model
+ * @author Frederic Guillot
+ */
+class TimezoneModel extends Base
+{
+ /**
+ * Get available timezones
+ *
+ * @access public
+ * @param boolean $prepend Prepend a default value
+ * @return array
+ */
+ public function getTimezones($prepend = false)
+ {
+ $timezones = timezone_identifiers_list();
+ $listing = array_combine(array_values($timezones), $timezones);
+
+ if ($prepend) {
+ return array('' => t('Application default')) + $listing;
+ }
+
+ return $listing;
+ }
+
+ /**
+ * Get current timezone
+ *
+ * @access public
+ * @return string
+ */
+ public function getCurrentTimezone()
+ {
+ if ($this->userSession->isLogged() && ! empty($this->sessionStorage->user['timezone'])) {
+ return $this->sessionStorage->user['timezone'];
+ }
+
+ return $this->configModel->get('application_timezone', 'UTC');
+ }
+
+ /**
+ * Set timezone
+ *
+ * @access public
+ */
+ public function setCurrentTimezone()
+ {
+ date_default_timezone_set($this->getCurrentTimezone());
+ }
+}
diff --git a/app/Model/Transition.php b/app/Model/TransitionModel.php
index 870d95fd..a4a58472 100644
--- a/app/Model/Transition.php
+++ b/app/Model/TransitionModel.php
@@ -2,13 +2,15 @@
namespace Kanboard\Model;
+use Kanboard\Core\Base;
+
/**
* Transition
*
- * @package model
+ * @package Kanboard\Model
* @author Frederic Guillot
*/
-class Transition extends Base
+class TransitionModel extends Base
{
/**
* SQL table name
@@ -69,17 +71,17 @@ class Transition extends Base
->columns(
'src.title as src_column',
'dst.title as dst_column',
- User::TABLE.'.name',
- User::TABLE.'.username',
+ UserModel::TABLE.'.name',
+ UserModel::TABLE.'.username',
self::TABLE.'.user_id',
self::TABLE.'.date',
self::TABLE.'.time_spent'
)
->eq('task_id', $task_id)
->desc('date')
- ->join(User::TABLE, 'id', 'user_id')
- ->join(Column::TABLE.' as src', 'id', 'src_column_id', self::TABLE, 'src')
- ->join(Column::TABLE.' as dst', 'id', 'dst_column_id', self::TABLE, 'dst')
+ ->join(UserModel::TABLE, 'id', 'user_id')
+ ->join(ColumnModel::TABLE.' as src', 'id', 'src_column_id', self::TABLE, 'src')
+ ->join(ColumnModel::TABLE.' as dst', 'id', 'dst_column_id', self::TABLE, 'dst')
->findAll();
}
@@ -104,12 +106,12 @@ class Transition extends Base
return $this->db->table(self::TABLE)
->columns(
- Task::TABLE.'.id',
- Task::TABLE.'.title',
+ TaskModel::TABLE.'.id',
+ TaskModel::TABLE.'.title',
'src.title as src_column',
'dst.title as dst_column',
- User::TABLE.'.name',
- User::TABLE.'.username',
+ UserModel::TABLE.'.name',
+ UserModel::TABLE.'.username',
self::TABLE.'.user_id',
self::TABLE.'.date',
self::TABLE.'.time_spent'
@@ -119,10 +121,10 @@ class Transition extends Base
->eq(self::TABLE.'.project_id', $project_id)
->desc('date')
->desc(self::TABLE.'.id')
- ->join(Task::TABLE, 'id', 'task_id')
- ->join(User::TABLE, 'id', 'user_id')
- ->join(Column::TABLE.' as src', 'id', 'src_column_id', self::TABLE, 'src')
- ->join(Column::TABLE.' as dst', 'id', 'dst_column_id', self::TABLE, 'dst')
+ ->join(TaskModel::TABLE, 'id', 'task_id')
+ ->join(UserModel::TABLE, 'id', 'user_id')
+ ->join(ColumnModel::TABLE.' as src', 'id', 'src_column_id', self::TABLE, 'src')
+ ->join(ColumnModel::TABLE.' as dst', 'id', 'dst_column_id', self::TABLE, 'dst')
->findAll();
}
}
diff --git a/app/Model/UserLocking.php b/app/Model/UserLockingModel.php
index 67e4c244..1d4d994c 100644
--- a/app/Model/UserLocking.php
+++ b/app/Model/UserLockingModel.php
@@ -2,13 +2,15 @@
namespace Kanboard\Model;
+use Kanboard\Core\Base;
+
/**
* User Locking Model
*
- * @package model
+ * @package Kanboard\Model
* @author Frederic Guillot
*/
-class UserLocking extends Base
+class UserLockingModel extends Base
{
/**
* Get the number of failed login for the user
@@ -19,7 +21,7 @@ class UserLocking extends Base
*/
public function getFailedLogin($username)
{
- return (int) $this->db->table(User::TABLE)
+ return (int) $this->db->table(UserModel::TABLE)
->eq('username', $username)
->findOneColumn('nb_failed_login');
}
@@ -33,7 +35,7 @@ class UserLocking extends Base
*/
public function resetFailedLogin($username)
{
- return $this->db->table(User::TABLE)
+ return $this->db->table(UserModel::TABLE)
->eq('username', $username)
->update(array(
'nb_failed_login' => 0,
@@ -50,7 +52,7 @@ class UserLocking extends Base
*/
public function incrementFailedLogin($username)
{
- return $this->db->table(User::TABLE)
+ return $this->db->table(UserModel::TABLE)
->eq('username', $username)
->increment('nb_failed_login', 1);
}
@@ -64,7 +66,7 @@ class UserLocking extends Base
*/
public function isLocked($username)
{
- return $this->db->table(User::TABLE)
+ return $this->db->table(UserModel::TABLE)
->eq('username', $username)
->neq('lock_expiration_date', 0)
->gte('lock_expiration_date', time())
@@ -81,7 +83,7 @@ class UserLocking extends Base
*/
public function lock($username, $duration = 15)
{
- return $this->db->table(User::TABLE)
+ return $this->db->table(UserModel::TABLE)
->eq('username', $username)
->update(array(
'lock_expiration_date' => time() + $duration * 60
diff --git a/app/Model/UserMention.php b/app/Model/UserMentionModel.php
index 97a4e419..cdb9949e 100644
--- a/app/Model/UserMention.php
+++ b/app/Model/UserMentionModel.php
@@ -2,15 +2,16 @@
namespace Kanboard\Model;
+use Kanboard\Core\Base;
use Kanboard\Event\GenericEvent;
/**
* User Mention
*
- * @package model
+ * @package Kanboard\Model
* @author Frederic Guillot
*/
-class UserMention extends Base
+class UserMentionModel extends Base
{
/**
* Get list of mentioned users
@@ -24,7 +25,7 @@ class UserMention extends Base
$users = array();
if (preg_match_all('/@([^\s]+)/', $content, $matches)) {
- $users = $this->db->table(User::TABLE)
+ $users = $this->db->table(UserModel::TABLE)
->columns('id', 'username', 'name', 'email', 'language')
->eq('notifications_enabled', 1)
->neq('id', $this->userSession->getId())
@@ -46,13 +47,13 @@ class UserMention extends Base
public function fireEvents($content, $eventName, GenericEvent $event)
{
if (empty($event['project_id'])) {
- $event['project_id'] = $this->taskFinder->getProjectId($event['task_id']);
+ $event['project_id'] = $this->taskFinderModel->getProjectId($event['task_id']);
}
$users = $this->getMentionedUsers($content);
foreach ($users as $user) {
- if ($this->projectPermission->isMember($event['project_id'], $user['id'])) {
+ if ($this->projectPermissionModel->isMember($event['project_id'], $user['id'])) {
$event['mention'] = $user;
$this->dispatcher->dispatch($eventName, $event);
}
diff --git a/app/Model/UserMetadata.php b/app/Model/UserMetadataModel.php
index 411837bd..e931d3ba 100644
--- a/app/Model/UserMetadata.php
+++ b/app/Model/UserMetadataModel.php
@@ -5,17 +5,22 @@ namespace Kanboard\Model;
/**
* User Metadata
*
- * @package model
+ * @package Kanboard\Model
* @author Frederic Guillot
*/
-class UserMetadata extends Metadata
+class UserMetadataModel extends MetadataModel
{
/**
- * SQL table name
+ * Get the table
*
- * @var string
+ * @abstract
+ * @access protected
+ * @return string
*/
- const TABLE = 'user_has_metadata';
+ protected function getTable()
+ {
+ return 'user_has_metadata';
+ }
/**
* Define the entity key
diff --git a/app/Model/User.php b/app/Model/UserModel.php
index 57993002..f7a051c5 100644
--- a/app/Model/User.php
+++ b/app/Model/UserModel.php
@@ -3,16 +3,17 @@
namespace Kanboard\Model;
use PicoDb\Database;
+use Kanboard\Core\Base;
use Kanboard\Core\Security\Token;
use Kanboard\Core\Security\Role;
/**
* User model
*
- * @package model
+ * @package Kanboard\Model
* @author Frederic Guillot
*/
-class User extends Base
+class UserModel extends Base
{
/**
* SQL table name
@@ -22,7 +23,7 @@ class User extends Base
const TABLE = 'users';
/**
- * Id used for everbody (filtering)
+ * Id used for everybody (filtering)
*
* @var integer
*/
@@ -85,7 +86,7 @@ class User extends Base
{
return $this->userSession->isAdmin() || // Avoid SQL query if connected
$this->db
- ->table(User::TABLE)
+ ->table(UserModel::TABLE)
->eq('id', $user_id)
->eq('role', Role::APP_ADMIN)
->exists();
@@ -211,7 +212,7 @@ class User extends Base
$listing = $this->prepareList($users);
if ($prepend) {
- return array(User::EVERYBODY_ID => t('Everybody')) + $listing;
+ return array(UserModel::EVERYBODY_ID => t('Everybody')) + $listing;
}
return $listing;
@@ -269,7 +270,7 @@ class User extends Base
public function create(array $values)
{
$this->prepare($values);
- return $this->persist(self::TABLE, $values);
+ return $this->db->table(self::TABLE)->persist($values);
}
/**
@@ -320,38 +321,38 @@ class User extends Base
*/
public function remove($user_id)
{
- $this->avatarFile->remove($user_id);
+ $this->avatarFileModel->remove($user_id);
return $this->db->transaction(function (Database $db) use ($user_id) {
// All assigned tasks are now unassigned (no foreign key)
- if (! $db->table(Task::TABLE)->eq('owner_id', $user_id)->update(array('owner_id' => 0))) {
+ if (! $db->table(TaskModel::TABLE)->eq('owner_id', $user_id)->update(array('owner_id' => 0))) {
return false;
}
// All assigned subtasks are now unassigned (no foreign key)
- if (! $db->table(Subtask::TABLE)->eq('user_id', $user_id)->update(array('user_id' => 0))) {
+ if (! $db->table(SubtaskModel::TABLE)->eq('user_id', $user_id)->update(array('user_id' => 0))) {
return false;
}
// All comments are not assigned anymore (no foreign key)
- if (! $db->table(Comment::TABLE)->eq('user_id', $user_id)->update(array('user_id' => 0))) {
+ if (! $db->table(CommentModel::TABLE)->eq('user_id', $user_id)->update(array('user_id' => 0))) {
return false;
}
// All private projects are removed
- $project_ids = $db->table(Project::TABLE)
+ $project_ids = $db->table(ProjectModel::TABLE)
->eq('is_private', 1)
- ->eq(ProjectUserRole::TABLE.'.user_id', $user_id)
- ->join(ProjectUserRole::TABLE, 'project_id', 'id')
- ->findAllByColumn(Project::TABLE.'.id');
+ ->eq(ProjectUserRoleModel::TABLE.'.user_id', $user_id)
+ ->join(ProjectUserRoleModel::TABLE, 'project_id', 'id')
+ ->findAllByColumn(ProjectModel::TABLE.'.id');
if (! empty($project_ids)) {
- $db->table(Project::TABLE)->in('id', $project_ids)->remove();
+ $db->table(ProjectModel::TABLE)->in('id', $project_ids)->remove();
}
// Finally remove the user
- if (! $db->table(User::TABLE)->eq('id', $user_id)->remove()) {
+ if (! $db->table(UserModel::TABLE)->eq('id', $user_id)->remove()) {
return false;
}
});
diff --git a/app/Model/UserNotificationFilter.php b/app/Model/UserNotificationFilterModel.php
index 780ddfc7..112ba290 100644
--- a/app/Model/UserNotificationFilter.php
+++ b/app/Model/UserNotificationFilterModel.php
@@ -2,13 +2,15 @@
namespace Kanboard\Model;
+use Kanboard\Core\Base;
+
/**
* User Notification Filter
*
- * @package model
+ * @package Kanboard\Model
* @author Frederic Guillot
*/
-class UserNotificationFilter extends Base
+class UserNotificationFilterModel extends Base
{
/**
* SQL table name
@@ -52,7 +54,7 @@ class UserNotificationFilter extends Base
*/
public function getSelectedFilter($user_id)
{
- return $this->db->table(User::TABLE)->eq('id', $user_id)->findOneColumn('notifications_filter');
+ return $this->db->table(UserModel::TABLE)->eq('id', $user_id)->findOneColumn('notifications_filter');
}
/**
@@ -65,7 +67,7 @@ class UserNotificationFilter extends Base
*/
public function saveFilter($user_id, $filter)
{
- return $this->db->table(User::TABLE)->eq('id', $user_id)->update(array(
+ return $this->db->table(UserModel::TABLE)->eq('id', $user_id)->update(array(
'notifications_filter' => $filter,
));
}
diff --git a/app/Model/UserNotification.php b/app/Model/UserNotificationModel.php
index 7795da2e..d77526f6 100644
--- a/app/Model/UserNotification.php
+++ b/app/Model/UserNotificationModel.php
@@ -2,15 +2,16 @@
namespace Kanboard\Model;
+use Kanboard\Core\Base;
use Kanboard\Core\Translator;
/**
* User Notification
*
- * @package model
+ * @package Kanboard\Model
* @author Frederic Guillot
*/
-class UserNotification extends Base
+class UserNotificationModel extends Base
{
/**
* Send notifications to people
@@ -24,7 +25,7 @@ class UserNotification extends Base
$users = $this->getUsersWithNotificationEnabled($event_data['task']['project_id'], $this->userSession->getId());
foreach ($users as $user) {
- if ($this->userNotificationFilter->shouldReceiveNotification($user, $event_data)) {
+ if ($this->userNotificationFilterModel->shouldReceiveNotification($user, $event_data)) {
$this->sendUserNotification($user, $event_name, $event_data);
}
}
@@ -46,15 +47,15 @@ class UserNotification extends Base
if (! empty($user['language'])) {
Translator::load($user['language']);
} else {
- Translator::load($this->config->get('application_language', 'en_US'));
+ Translator::load($this->configModel->get('application_language', 'en_US'));
}
- foreach ($this->userNotificationType->getSelectedTypes($user['id']) as $type) {
- $this->userNotificationType->getType($type)->notifyUser($user, $event_name, $event_data);
+ foreach ($this->userNotificationTypeModel->getSelectedTypes($user['id']) as $type) {
+ $this->userNotificationTypeModel->getType($type)->notifyUser($user, $event_name, $event_data);
}
// Restore locales
- $this->config->setupTranslations();
+ $this->languageModel->loadCurrentLanguage();
}
/**
@@ -67,7 +68,7 @@ class UserNotification extends Base
*/
public function getUsersWithNotificationEnabled($project_id, $exclude_user_id = 0)
{
- if ($this->projectPermission->isEverybodyAllowed($project_id)) {
+ if ($this->projectPermissionModel->isEverybodyAllowed($project_id)) {
return $this->getEverybodyWithNotificationEnabled($exclude_user_id);
}
@@ -93,7 +94,7 @@ class UserNotification extends Base
*/
public function enableNotification($user_id)
{
- return $this->db->table(User::TABLE)->eq('id', $user_id)->update(array('notifications_enabled' => 1));
+ return $this->db->table(UserModel::TABLE)->eq('id', $user_id)->update(array('notifications_enabled' => 1));
}
/**
@@ -105,7 +106,7 @@ class UserNotification extends Base
*/
public function disableNotification($user_id)
{
- return $this->db->table(User::TABLE)->eq('id', $user_id)->update(array('notifications_enabled' => 0));
+ return $this->db->table(UserModel::TABLE)->eq('id', $user_id)->update(array('notifications_enabled' => 0));
}
/**
@@ -125,12 +126,12 @@ class UserNotification extends Base
$this->disableNotification($user_id);
}
- $filter = empty($values['notifications_filter']) ? UserNotificationFilter::FILTER_BOTH : $values['notifications_filter'];
+ $filter = empty($values['notifications_filter']) ? UserNotificationFilterModel::FILTER_BOTH : $values['notifications_filter'];
$project_ids = empty($values['notification_projects']) ? array() : array_keys($values['notification_projects']);
- $this->userNotificationFilter->saveFilter($user_id, $filter);
- $this->userNotificationFilter->saveSelectedProjects($user_id, $project_ids);
- $this->userNotificationType->saveSelectedTypes($user_id, $types);
+ $this->userNotificationFilterModel->saveFilter($user_id, $filter);
+ $this->userNotificationFilterModel->saveSelectedProjects($user_id, $project_ids);
+ $this->userNotificationTypeModel->saveSelectedTypes($user_id, $types);
}
/**
@@ -142,9 +143,9 @@ class UserNotification extends Base
*/
public function readSettings($user_id)
{
- $values = $this->db->table(User::TABLE)->eq('id', $user_id)->columns('notifications_enabled', 'notifications_filter')->findOne();
- $values['notification_types'] = $this->userNotificationType->getSelectedTypes($user_id);
- $values['notification_projects'] = $this->userNotificationFilter->getSelectedProjects($user_id);
+ $values = $this->db->table(UserModel::TABLE)->eq('id', $user_id)->columns('notifications_enabled', 'notifications_filter')->findOne();
+ $values['notification_types'] = $this->userNotificationTypeModel->getSelectedTypes($user_id);
+ $values['notification_projects'] = $this->userNotificationFilterModel->getSelectedProjects($user_id);
return $values;
}
@@ -159,25 +160,27 @@ class UserNotification extends Base
private function getProjectUserMembersWithNotificationEnabled($project_id, $exclude_user_id)
{
return $this->db
- ->table(ProjectUserRole::TABLE)
- ->columns(User::TABLE.'.id', User::TABLE.'.username', User::TABLE.'.name', User::TABLE.'.email', User::TABLE.'.language', User::TABLE.'.notifications_filter')
- ->join(User::TABLE, 'id', 'user_id')
- ->eq('project_id', $project_id)
- ->eq('notifications_enabled', '1')
- ->neq(User::TABLE.'.id', $exclude_user_id)
+ ->table(ProjectUserRoleModel::TABLE)
+ ->columns(UserModel::TABLE.'.id', UserModel::TABLE.'.username', UserModel::TABLE.'.name', UserModel::TABLE.'.email', UserModel::TABLE.'.language', UserModel::TABLE.'.notifications_filter')
+ ->join(UserModel::TABLE, 'id', 'user_id')
+ ->eq(ProjectUserRoleModel::TABLE.'.project_id', $project_id)
+ ->eq(UserModel::TABLE.'.notifications_enabled', '1')
+ ->eq(UserModel::TABLE.'.is_active', 1)
+ ->neq(UserModel::TABLE.'.id', $exclude_user_id)
->findAll();
}
private function getProjectGroupMembersWithNotificationEnabled($project_id, $exclude_user_id)
{
return $this->db
- ->table(ProjectGroupRole::TABLE)
- ->columns(User::TABLE.'.id', User::TABLE.'.username', User::TABLE.'.name', User::TABLE.'.email', User::TABLE.'.language', User::TABLE.'.notifications_filter')
- ->join(GroupMember::TABLE, 'group_id', 'group_id', ProjectGroupRole::TABLE)
- ->join(User::TABLE, 'id', 'user_id', GroupMember::TABLE)
- ->eq(ProjectGroupRole::TABLE.'.project_id', $project_id)
- ->eq(User::TABLE.'.notifications_enabled', '1')
- ->neq(User::TABLE.'.id', $exclude_user_id)
+ ->table(ProjectGroupRoleModel::TABLE)
+ ->columns(UserModel::TABLE.'.id', UserModel::TABLE.'.username', UserModel::TABLE.'.name', UserModel::TABLE.'.email', UserModel::TABLE.'.language', UserModel::TABLE.'.notifications_filter')
+ ->join(GroupMemberModel::TABLE, 'group_id', 'group_id', ProjectGroupRoleModel::TABLE)
+ ->join(UserModel::TABLE, 'id', 'user_id', GroupMemberModel::TABLE)
+ ->eq(ProjectGroupRoleModel::TABLE.'.project_id', $project_id)
+ ->eq(UserModel::TABLE.'.notifications_enabled', '1')
+ ->neq(UserModel::TABLE.'.id', $exclude_user_id)
+ ->eq(UserModel::TABLE.'.is_active', 1)
->findAll();
}
@@ -191,10 +194,11 @@ class UserNotification extends Base
private function getEverybodyWithNotificationEnabled($exclude_user_id)
{
return $this->db
- ->table(User::TABLE)
- ->columns(User::TABLE.'.id', User::TABLE.'.username', User::TABLE.'.name', User::TABLE.'.email', User::TABLE.'.language', User::TABLE.'.notifications_filter')
+ ->table(UserModel::TABLE)
+ ->columns(UserModel::TABLE.'.id', UserModel::TABLE.'.username', UserModel::TABLE.'.name', UserModel::TABLE.'.email', UserModel::TABLE.'.language', UserModel::TABLE.'.notifications_filter')
->eq('notifications_enabled', '1')
- ->neq(User::TABLE.'.id', $exclude_user_id)
+ ->neq(UserModel::TABLE.'.id', $exclude_user_id)
+ ->eq(UserModel::TABLE.'.is_active', 1)
->findAll();
}
}
diff --git a/app/Model/UserNotificationType.php b/app/Model/UserNotificationTypeModel.php
index 89beb480..0f377220 100644
--- a/app/Model/UserNotificationType.php
+++ b/app/Model/UserNotificationTypeModel.php
@@ -5,10 +5,10 @@ namespace Kanboard\Model;
/**
* User Notification Type
*
- * @package model
+ * @package Kanboard\Model
* @author Frederic Guillot
*/
-class UserNotificationType extends NotificationType
+class UserNotificationTypeModel extends NotificationTypeModel
{
/**
* SQL table name
diff --git a/app/Model/UserUnreadNotification.php b/app/Model/UserUnreadNotificationModel.php
index cc0f326a..6c930eef 100644
--- a/app/Model/UserUnreadNotification.php
+++ b/app/Model/UserUnreadNotificationModel.php
@@ -2,13 +2,15 @@
namespace Kanboard\Model;
+use Kanboard\Core\Base;
+
/**
* User Unread Notification
*
- * @package model
+ * @package Kanboard\Model
* @author Frederic Guillot
*/
-class UserUnreadNotification extends Base
+class UserUnreadNotificationModel extends Base
{
/**
* SQL table name
@@ -36,6 +38,23 @@ class UserUnreadNotification extends Base
}
/**
+ * Get one notification
+ *
+ * @param integer $notification_id
+ * @return array|null
+ */
+ public function getById($notification_id)
+ {
+ $notification = $this->db->table(self::TABLE)->eq('id', $notification_id)->findOne();
+
+ if (! empty($notification)) {
+ $this->unserialize($notification);
+ }
+
+ return $notification;
+ }
+
+ /**
* Get all notifications for a user
*
* @access public
@@ -47,8 +66,7 @@ class UserUnreadNotification extends Base
$events = $this->db->table(self::TABLE)->eq('user_id', $user_id)->asc('date_creation')->findAll();
foreach ($events as &$event) {
- $event['event_data'] = json_decode($event['event_data'], true);
- $event['title'] = $this->notification->getTitleWithoutAuthor($event['event_name'], $event['event_data']);
+ $this->unserialize($event);
}
return $events;
@@ -90,4 +108,10 @@ class UserUnreadNotification extends Base
{
return $this->db->table(self::TABLE)->eq('user_id', $user_id)->exists();
}
+
+ private function unserialize(&$event)
+ {
+ $event['event_data'] = json_decode($event['event_data'], true);
+ $event['title'] = $this->notificationModel->getTitleWithoutAuthor($event['event_name'], $event['event_data']);
+ }
}
diff --git a/app/Notification/ActivityStream.php b/app/Notification/ActivityStreamNotification.php
index 325732ec..9f23c88a 100644
--- a/app/Notification/ActivityStream.php
+++ b/app/Notification/ActivityStreamNotification.php
@@ -3,14 +3,15 @@
namespace Kanboard\Notification;
use Kanboard\Core\Base;
+use Kanboard\Core\Notification\NotificationInterface;
/**
* Activity Stream Notification
*
- * @package notification
+ * @package Kanboard\Notification
* @author Frederic Guillot
*/
-class ActivityStream extends Base implements NotificationInterface
+class ActivityStreamNotification extends Base implements NotificationInterface
{
/**
* Send notification to a user
@@ -35,7 +36,7 @@ class ActivityStream extends Base implements NotificationInterface
public function notifyProject(array $project, $event_name, array $event_data)
{
if ($this->userSession->isLogged()) {
- $this->projectActivity->createEvent(
+ $this->projectActivityModel->createEvent(
$project['id'],
$event_data['task']['id'],
$this->userSession->getId(),
diff --git a/app/Notification/Mail.php b/app/Notification/MailNotification.php
index c924fb50..2d27179c 100644
--- a/app/Notification/Mail.php
+++ b/app/Notification/MailNotification.php
@@ -3,18 +3,19 @@
namespace Kanboard\Notification;
use Kanboard\Core\Base;
-use Kanboard\Model\Task;
-use Kanboard\Model\TaskFile;
-use Kanboard\Model\Comment;
-use Kanboard\Model\Subtask;
+use Kanboard\Core\Notification\NotificationInterface;
+use Kanboard\Model\TaskModel;
+use Kanboard\Model\TaskFileModel;
+use Kanboard\Model\CommentModel;
+use Kanboard\Model\SubtaskModel;
/**
* Email Notification
*
- * @package notification
+ * @package Kanboard\Notification
* @author Frederic Guillot
*/
-class Mail extends Base implements NotificationInterface
+class MailNotification extends Base implements NotificationInterface
{
/**
* Notification type
@@ -67,7 +68,7 @@ class Mail extends Base implements NotificationInterface
{
return $this->template->render(
'notification/'.str_replace('.', '_', $event_name),
- $event_data + array('application_url' => $this->config->get('application_url'))
+ $event_data + array('application_url' => $this->configModel->get('application_url'))
);
}
@@ -82,50 +83,50 @@ class Mail extends Base implements NotificationInterface
public function getMailSubject($event_name, array $event_data)
{
switch ($event_name) {
- case TaskFile::EVENT_CREATE:
+ case TaskFileModel::EVENT_CREATE:
$subject = $this->getStandardMailSubject(e('New attachment'), $event_data);
break;
- case Comment::EVENT_CREATE:
+ case CommentModel::EVENT_CREATE:
$subject = $this->getStandardMailSubject(e('New comment'), $event_data);
break;
- case Comment::EVENT_UPDATE:
+ case CommentModel::EVENT_UPDATE:
$subject = $this->getStandardMailSubject(e('Comment updated'), $event_data);
break;
- case Subtask::EVENT_CREATE:
+ case SubtaskModel::EVENT_CREATE:
$subject = $this->getStandardMailSubject(e('New subtask'), $event_data);
break;
- case Subtask::EVENT_UPDATE:
+ case SubtaskModel::EVENT_UPDATE:
$subject = $this->getStandardMailSubject(e('Subtask updated'), $event_data);
break;
- case Task::EVENT_CREATE:
+ case TaskModel::EVENT_CREATE:
$subject = $this->getStandardMailSubject(e('New task'), $event_data);
break;
- case Task::EVENT_UPDATE:
+ case TaskModel::EVENT_UPDATE:
$subject = $this->getStandardMailSubject(e('Task updated'), $event_data);
break;
- case Task::EVENT_CLOSE:
+ case TaskModel::EVENT_CLOSE:
$subject = $this->getStandardMailSubject(e('Task closed'), $event_data);
break;
- case Task::EVENT_OPEN:
+ case TaskModel::EVENT_OPEN:
$subject = $this->getStandardMailSubject(e('Task opened'), $event_data);
break;
- case Task::EVENT_MOVE_COLUMN:
+ case TaskModel::EVENT_MOVE_COLUMN:
$subject = $this->getStandardMailSubject(e('Column change'), $event_data);
break;
- case Task::EVENT_MOVE_POSITION:
+ case TaskModel::EVENT_MOVE_POSITION:
$subject = $this->getStandardMailSubject(e('Position change'), $event_data);
break;
- case Task::EVENT_MOVE_SWIMLANE:
+ case TaskModel::EVENT_MOVE_SWIMLANE:
$subject = $this->getStandardMailSubject(e('Swimlane change'), $event_data);
break;
- case Task::EVENT_ASSIGNEE_CHANGE:
+ case TaskModel::EVENT_ASSIGNEE_CHANGE:
$subject = $this->getStandardMailSubject(e('Assignee change'), $event_data);
break;
- case Task::EVENT_USER_MENTION:
- case Comment::EVENT_USER_MENTION:
+ case TaskModel::EVENT_USER_MENTION:
+ case CommentModel::EVENT_USER_MENTION:
$subject = $this->getStandardMailSubject(e('Mentioned'), $event_data);
break;
- case Task::EVENT_OVERDUE:
+ case TaskModel::EVENT_OVERDUE:
$subject = e('[%s] Overdue tasks', $event_data['project_name']);
break;
default:
diff --git a/app/Notification/Web.php b/app/Notification/WebNotification.php
index 9271c193..d8818828 100644
--- a/app/Notification/Web.php
+++ b/app/Notification/WebNotification.php
@@ -3,14 +3,15 @@
namespace Kanboard\Notification;
use Kanboard\Core\Base;
+use Kanboard\Core\Notification\NotificationInterface;
/**
* Web Notification
*
- * @package notification
+ * @package Kanboard\Notification
* @author Frederic Guillot
*/
-class Web extends Base implements NotificationInterface
+class WebNotification extends Base implements NotificationInterface
{
/**
* Notification type
@@ -29,7 +30,7 @@ class Web extends Base implements NotificationInterface
*/
public function notifyUser(array $user, $event_name, array $event_data)
{
- $this->userUnreadNotification->create($user['id'], $event_name, $event_data);
+ $this->userUnreadNotificationModel->create($user['id'], $event_name, $event_data);
}
/**
diff --git a/app/Notification/Webhook.php b/app/Notification/WebhookNotification.php
index e187909f..16045535 100644
--- a/app/Notification/Webhook.php
+++ b/app/Notification/WebhookNotification.php
@@ -3,14 +3,15 @@
namespace Kanboard\Notification;
use Kanboard\Core\Base;
+use Kanboard\Core\Notification\NotificationInterface;
/**
* Webhook Notification
*
- * @package notification
+ * @package Kanboard\Notification
* @author Frederic Guillot
*/
-class Webhook extends Base implements NotificationInterface
+class WebhookNotification extends Base implements NotificationInterface
{
/**
* Send notification to a user
@@ -34,8 +35,8 @@ class Webhook extends Base implements NotificationInterface
*/
public function notifyProject(array $project, $event_name, array $event_data)
{
- $url = $this->config->get('webhook_url');
- $token = $this->config->get('webhook_token');
+ $url = $this->configModel->get('webhook_url');
+ $token = $this->configModel->get('webhook_token');
if (! empty($url)) {
if (strpos($url, '?') !== false) {
diff --git a/app/Schema/Sql/mysql.sql b/app/Schema/Sql/mysql.sql
index ce2374f0..92ca3686 100644
--- a/app/Schema/Sql/mysql.sql
+++ b/app/Schema/Sql/mysql.sql
@@ -647,7 +647,7 @@ CREATE TABLE `users` (
LOCK TABLES `settings` WRITE;
/*!40000 ALTER TABLE `settings` DISABLE KEYS */;
-INSERT INTO `settings` VALUES ('api_token','9c55053ae1d523893efc820e2e8338c4cf47f5c6c2c26861fec637eba62b',0,0),('application_currency','USD',0,0),('application_date_format','m/d/Y',0,0),('application_language','en_US',0,0),('application_stylesheet','',0,0),('application_timezone','UTC',0,0),('application_url','',0,0),('board_columns','',0,0),('board_highlight_period','172800',0,0),('board_private_refresh_interval','10',0,0),('board_public_refresh_interval','60',0,0),('calendar_project_tasks','date_started',0,0),('calendar_user_subtasks_time_tracking','0',0,0),('calendar_user_tasks','date_started',0,0),('cfd_include_closed_tasks','1',0,0),('default_color','yellow',0,0),('integration_gravatar','0',0,0),('password_reset','1',0,0),('project_categories','',0,0),('subtask_restriction','0',0,0),('subtask_time_tracking','1',0,0),('webhook_token','aaed762f4f6b0860902af0e2a87e5ad3427d24ff9e3ce8a2e0b005b58dfc',0,0),('webhook_url','',0,0);
+INSERT INTO `settings` VALUES ('api_token','e8a7a983f25efa80e203d44a832c9570a5083d3fefa91366989c00e931d0',0,0),('application_currency','USD',0,0),('application_date_format','m/d/Y',0,0),('application_language','en_US',0,0),('application_stylesheet','',0,0),('application_timezone','UTC',0,0),('application_url','',0,0),('board_columns','',0,0),('board_highlight_period','172800',0,0),('board_private_refresh_interval','10',0,0),('board_public_refresh_interval','60',0,0),('calendar_project_tasks','date_started',0,0),('calendar_user_subtasks_time_tracking','0',0,0),('calendar_user_tasks','date_started',0,0),('cfd_include_closed_tasks','1',0,0),('default_color','yellow',0,0),('integration_gravatar','0',0,0),('password_reset','1',0,0),('project_categories','',0,0),('subtask_restriction','0',0,0),('subtask_time_tracking','1',0,0),('webhook_token','296892f9c821909a92df539b028fdb384e47c9f7a34a8f9cad598e0edbba',0,0),('webhook_url','',0,0);
/*!40000 ALTER TABLE `settings` ENABLE KEYS */;
UNLOCK TABLES;
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
@@ -676,4 +676,4 @@ UNLOCK TABLES;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
-INSERT INTO users (username, password, role) VALUES ('admin', '$2y$10$e.SftITKuBvXeNbxtmTKS.KAbIy4Mx09t254BAiEAuWOxkuS4xfLG', 'app-admin');INSERT INTO schema_version VALUES ('110');
+INSERT INTO users (username, password, role) VALUES ('admin', '$2y$10$kliMGeKgDYtx9Igek9jGDu0eZM.KXivgzvqtnMuWMkjvZiIc.8p8S', 'app-admin');INSERT INTO schema_version VALUES ('110');
diff --git a/app/Schema/Sql/postgres.sql b/app/Schema/Sql/postgres.sql
index 48a269d3..6c17c1b1 100644
--- a/app/Schema/Sql/postgres.sql
+++ b/app/Schema/Sql/postgres.sql
@@ -2,42 +2,39 @@
-- PostgreSQL database dump
--
+-- Dumped from database version 9.5.2
+-- Dumped by pg_dump version 9.5.2
+
SET statement_timeout = 0;
SET lock_timeout = 0;
SET client_encoding = 'UTF8';
SET standard_conforming_strings = on;
SET check_function_bodies = false;
SET client_min_messages = warning;
+SET row_security = off;
--
--- Name: plpgsql; Type: EXTENSION; Schema: -; Owner: -
+-- Name: SCHEMA "public"; Type: COMMENT; Schema: -; Owner: -
--
-CREATE EXTENSION IF NOT EXISTS plpgsql WITH SCHEMA pg_catalog;
-
-
---
--- Name: EXTENSION plpgsql; Type: COMMENT; Schema: -; Owner: -
---
+COMMENT ON SCHEMA "public" IS 'standard public schema';
-COMMENT ON EXTENSION plpgsql IS 'PL/pgSQL procedural language';
-
-SET search_path = public, pg_catalog;
+SET search_path = "public", pg_catalog;
SET default_tablespace = '';
SET default_with_oids = false;
--
--- Name: action_has_params; Type: TABLE; Schema: public; Owner: -; Tablespace:
+-- Name: action_has_params; Type: TABLE; Schema: public; Owner: -
--
-CREATE TABLE action_has_params (
- id integer NOT NULL,
- action_id integer NOT NULL,
- name character varying(50) NOT NULL,
- value character varying(50) NOT NULL
+CREATE TABLE "action_has_params" (
+ "id" integer NOT NULL,
+ "action_id" integer NOT NULL,
+ "name" character varying(50) NOT NULL,
+ "value" character varying(50) NOT NULL
);
@@ -45,7 +42,7 @@ CREATE TABLE action_has_params (
-- Name: action_has_params_id_seq; Type: SEQUENCE; Schema: public; Owner: -
--
-CREATE SEQUENCE action_has_params_id_seq
+CREATE SEQUENCE "action_has_params_id_seq"
START WITH 1
INCREMENT BY 1
NO MINVALUE
@@ -57,18 +54,18 @@ CREATE SEQUENCE action_has_params_id_seq
-- Name: action_has_params_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
--
-ALTER SEQUENCE action_has_params_id_seq OWNED BY action_has_params.id;
+ALTER SEQUENCE "action_has_params_id_seq" OWNED BY "action_has_params"."id";
--
--- Name: actions; Type: TABLE; Schema: public; Owner: -; Tablespace:
+-- Name: actions; Type: TABLE; Schema: public; Owner: -
--
-CREATE TABLE actions (
- id integer NOT NULL,
- project_id integer NOT NULL,
- event_name character varying(50) NOT NULL,
- action_name character varying(255) NOT NULL
+CREATE TABLE "actions" (
+ "id" integer NOT NULL,
+ "project_id" integer NOT NULL,
+ "event_name" character varying(50) NOT NULL,
+ "action_name" character varying(255) NOT NULL
);
@@ -76,7 +73,7 @@ CREATE TABLE actions (
-- Name: actions_id_seq; Type: SEQUENCE; Schema: public; Owner: -
--
-CREATE SEQUENCE actions_id_seq
+CREATE SEQUENCE "actions_id_seq"
START WITH 1
INCREMENT BY 1
NO MINVALUE
@@ -88,20 +85,20 @@ CREATE SEQUENCE actions_id_seq
-- Name: actions_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
--
-ALTER SEQUENCE actions_id_seq OWNED BY actions.id;
+ALTER SEQUENCE "actions_id_seq" OWNED BY "actions"."id";
--
--- Name: columns; Type: TABLE; Schema: public; Owner: -; Tablespace:
+-- Name: columns; Type: TABLE; Schema: public; Owner: -
--
-CREATE TABLE columns (
- id integer NOT NULL,
- title character varying(255) NOT NULL,
+CREATE TABLE "columns" (
+ "id" integer NOT NULL,
+ "title" character varying(255) NOT NULL,
"position" integer,
- project_id integer NOT NULL,
- task_limit integer DEFAULT 0,
- description text
+ "project_id" integer NOT NULL,
+ "task_limit" integer DEFAULT 0,
+ "description" "text"
);
@@ -109,7 +106,7 @@ CREATE TABLE columns (
-- Name: columns_id_seq; Type: SEQUENCE; Schema: public; Owner: -
--
-CREATE SEQUENCE columns_id_seq
+CREATE SEQUENCE "columns_id_seq"
START WITH 1
INCREMENT BY 1
NO MINVALUE
@@ -121,20 +118,20 @@ CREATE SEQUENCE columns_id_seq
-- Name: columns_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
--
-ALTER SEQUENCE columns_id_seq OWNED BY columns.id;
+ALTER SEQUENCE "columns_id_seq" OWNED BY "columns"."id";
--
--- Name: comments; Type: TABLE; Schema: public; Owner: -; Tablespace:
+-- Name: comments; Type: TABLE; Schema: public; Owner: -
--
-CREATE TABLE comments (
- id integer NOT NULL,
- task_id integer NOT NULL,
- user_id integer DEFAULT 0,
- date_creation bigint NOT NULL,
- comment text,
- reference character varying(50) DEFAULT ''::character varying
+CREATE TABLE "comments" (
+ "id" integer NOT NULL,
+ "task_id" integer NOT NULL,
+ "user_id" integer DEFAULT 0,
+ "date_creation" bigint NOT NULL,
+ "comment" "text",
+ "reference" character varying(50) DEFAULT ''::character varying
);
@@ -142,7 +139,7 @@ CREATE TABLE comments (
-- Name: comments_id_seq; Type: SEQUENCE; Schema: public; Owner: -
--
-CREATE SEQUENCE comments_id_seq
+CREATE SEQUENCE "comments_id_seq"
START WITH 1
INCREMENT BY 1
NO MINVALUE
@@ -154,31 +151,31 @@ CREATE SEQUENCE comments_id_seq
-- Name: comments_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
--
-ALTER SEQUENCE comments_id_seq OWNED BY comments.id;
+ALTER SEQUENCE "comments_id_seq" OWNED BY "comments"."id";
--
--- Name: currencies; Type: TABLE; Schema: public; Owner: -; Tablespace:
+-- Name: currencies; Type: TABLE; Schema: public; Owner: -
--
-CREATE TABLE currencies (
- currency character(3) NOT NULL,
- rate real DEFAULT 0
+CREATE TABLE "currencies" (
+ "currency" character(3) NOT NULL,
+ "rate" real DEFAULT 0
);
--
--- Name: custom_filters; Type: TABLE; Schema: public; Owner: -; Tablespace:
+-- Name: custom_filters; Type: TABLE; Schema: public; Owner: -
--
-CREATE TABLE custom_filters (
- id integer NOT NULL,
- filter character varying(100) NOT NULL,
- project_id integer NOT NULL,
- user_id integer NOT NULL,
- name character varying(100) NOT NULL,
- is_shared boolean DEFAULT false,
- append boolean DEFAULT false
+CREATE TABLE "custom_filters" (
+ "id" integer NOT NULL,
+ "filter" character varying(100) NOT NULL,
+ "project_id" integer NOT NULL,
+ "user_id" integer NOT NULL,
+ "name" character varying(100) NOT NULL,
+ "is_shared" boolean DEFAULT false,
+ "append" boolean DEFAULT false
);
@@ -186,7 +183,7 @@ CREATE TABLE custom_filters (
-- Name: custom_filters_id_seq; Type: SEQUENCE; Schema: public; Owner: -
--
-CREATE SEQUENCE custom_filters_id_seq
+CREATE SEQUENCE "custom_filters_id_seq"
START WITH 1
INCREMENT BY 1
NO MINVALUE
@@ -198,27 +195,27 @@ CREATE SEQUENCE custom_filters_id_seq
-- Name: custom_filters_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
--
-ALTER SEQUENCE custom_filters_id_seq OWNED BY custom_filters.id;
+ALTER SEQUENCE "custom_filters_id_seq" OWNED BY "custom_filters"."id";
--
--- Name: group_has_users; Type: TABLE; Schema: public; Owner: -; Tablespace:
+-- Name: group_has_users; Type: TABLE; Schema: public; Owner: -
--
-CREATE TABLE group_has_users (
- group_id integer NOT NULL,
- user_id integer NOT NULL
+CREATE TABLE "group_has_users" (
+ "group_id" integer NOT NULL,
+ "user_id" integer NOT NULL
);
--
--- Name: groups; Type: TABLE; Schema: public; Owner: -; Tablespace:
+-- Name: groups; Type: TABLE; Schema: public; Owner: -
--
-CREATE TABLE groups (
- id integer NOT NULL,
- external_id character varying(255) DEFAULT ''::character varying,
- name character varying(100) NOT NULL
+CREATE TABLE "groups" (
+ "id" integer NOT NULL,
+ "external_id" character varying(255) DEFAULT ''::character varying,
+ "name" character varying(100) NOT NULL
);
@@ -226,7 +223,7 @@ CREATE TABLE groups (
-- Name: groups_id_seq; Type: SEQUENCE; Schema: public; Owner: -
--
-CREATE SEQUENCE groups_id_seq
+CREATE SEQUENCE "groups_id_seq"
START WITH 1
INCREMENT BY 1
NO MINVALUE
@@ -238,20 +235,20 @@ CREATE SEQUENCE groups_id_seq
-- Name: groups_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
--
-ALTER SEQUENCE groups_id_seq OWNED BY groups.id;
+ALTER SEQUENCE "groups_id_seq" OWNED BY "groups"."id";
--
--- Name: last_logins; Type: TABLE; Schema: public; Owner: -; Tablespace:
+-- Name: last_logins; Type: TABLE; Schema: public; Owner: -
--
-CREATE TABLE last_logins (
- id integer NOT NULL,
- auth_type character varying(25),
- user_id integer,
- ip character varying(45),
- user_agent character varying(255),
- date_creation bigint
+CREATE TABLE "last_logins" (
+ "id" integer NOT NULL,
+ "auth_type" character varying(25),
+ "user_id" integer,
+ "ip" character varying(45),
+ "user_agent" character varying(255),
+ "date_creation" bigint
);
@@ -259,7 +256,7 @@ CREATE TABLE last_logins (
-- Name: last_logins_id_seq; Type: SEQUENCE; Schema: public; Owner: -
--
-CREATE SEQUENCE last_logins_id_seq
+CREATE SEQUENCE "last_logins_id_seq"
START WITH 1
INCREMENT BY 1
NO MINVALUE
@@ -271,17 +268,17 @@ CREATE SEQUENCE last_logins_id_seq
-- Name: last_logins_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
--
-ALTER SEQUENCE last_logins_id_seq OWNED BY last_logins.id;
+ALTER SEQUENCE "last_logins_id_seq" OWNED BY "last_logins"."id";
--
--- Name: links; Type: TABLE; Schema: public; Owner: -; Tablespace:
+-- Name: links; Type: TABLE; Schema: public; Owner: -
--
-CREATE TABLE links (
- id integer NOT NULL,
- label character varying(255) NOT NULL,
- opposite_id integer DEFAULT 0
+CREATE TABLE "links" (
+ "id" integer NOT NULL,
+ "label" character varying(255) NOT NULL,
+ "opposite_id" integer DEFAULT 0
);
@@ -289,7 +286,7 @@ CREATE TABLE links (
-- Name: links_id_seq; Type: SEQUENCE; Schema: public; Owner: -
--
-CREATE SEQUENCE links_id_seq
+CREATE SEQUENCE "links_id_seq"
START WITH 1
INCREMENT BY 1
NO MINVALUE
@@ -301,46 +298,46 @@ CREATE SEQUENCE links_id_seq
-- Name: links_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
--
-ALTER SEQUENCE links_id_seq OWNED BY links.id;
+ALTER SEQUENCE "links_id_seq" OWNED BY "links"."id";
--
--- Name: password_reset; Type: TABLE; Schema: public; Owner: -; Tablespace:
+-- Name: password_reset; Type: TABLE; Schema: public; Owner: -
--
-CREATE TABLE password_reset (
- token character varying(80) NOT NULL,
- user_id integer NOT NULL,
- date_expiration integer NOT NULL,
- date_creation integer NOT NULL,
- ip character varying(45) NOT NULL,
- user_agent character varying(255) NOT NULL,
- is_active boolean NOT NULL
+CREATE TABLE "password_reset" (
+ "token" character varying(80) NOT NULL,
+ "user_id" integer NOT NULL,
+ "date_expiration" integer NOT NULL,
+ "date_creation" integer NOT NULL,
+ "ip" character varying(45) NOT NULL,
+ "user_agent" character varying(255) NOT NULL,
+ "is_active" boolean NOT NULL
);
--
--- Name: plugin_schema_versions; Type: TABLE; Schema: public; Owner: -; Tablespace:
+-- Name: plugin_schema_versions; Type: TABLE; Schema: public; Owner: -
--
-CREATE TABLE plugin_schema_versions (
- plugin character varying(80) NOT NULL,
- version integer DEFAULT 0 NOT NULL
+CREATE TABLE "plugin_schema_versions" (
+ "plugin" character varying(80) NOT NULL,
+ "version" integer DEFAULT 0 NOT NULL
);
--
--- Name: project_activities; Type: TABLE; Schema: public; Owner: -; Tablespace:
+-- Name: project_activities; Type: TABLE; Schema: public; Owner: -
--
-CREATE TABLE project_activities (
- id integer NOT NULL,
- date_creation bigint NOT NULL,
- event_name character varying(50) NOT NULL,
- creator_id integer,
- project_id integer,
- task_id integer,
- data text
+CREATE TABLE "project_activities" (
+ "id" integer NOT NULL,
+ "date_creation" bigint NOT NULL,
+ "event_name" character varying(50) NOT NULL,
+ "creator_id" integer,
+ "project_id" integer,
+ "task_id" integer,
+ "data" "text"
);
@@ -348,7 +345,7 @@ CREATE TABLE project_activities (
-- Name: project_activities_id_seq; Type: SEQUENCE; Schema: public; Owner: -
--
-CREATE SEQUENCE project_activities_id_seq
+CREATE SEQUENCE "project_activities_id_seq"
START WITH 1
INCREMENT BY 1
NO MINVALUE
@@ -360,33 +357,33 @@ CREATE SEQUENCE project_activities_id_seq
-- Name: project_activities_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
--
-ALTER SEQUENCE project_activities_id_seq OWNED BY project_activities.id;
+ALTER SEQUENCE "project_activities_id_seq" OWNED BY "project_activities"."id";
--
--- Name: project_daily_column_stats; Type: TABLE; Schema: public; Owner: -; Tablespace:
+-- Name: project_daily_column_stats; Type: TABLE; Schema: public; Owner: -
--
-CREATE TABLE project_daily_column_stats (
- id integer NOT NULL,
- day character(10) NOT NULL,
- project_id integer NOT NULL,
- column_id integer NOT NULL,
- total integer DEFAULT 0 NOT NULL,
- score integer DEFAULT 0 NOT NULL
+CREATE TABLE "project_daily_column_stats" (
+ "id" integer NOT NULL,
+ "day" character(10) NOT NULL,
+ "project_id" integer NOT NULL,
+ "column_id" integer NOT NULL,
+ "total" integer DEFAULT 0 NOT NULL,
+ "score" integer DEFAULT 0 NOT NULL
);
--
--- Name: project_daily_stats; Type: TABLE; Schema: public; Owner: -; Tablespace:
+-- Name: project_daily_stats; Type: TABLE; Schema: public; Owner: -
--
-CREATE TABLE project_daily_stats (
- id integer NOT NULL,
- day character(10) NOT NULL,
- project_id integer NOT NULL,
- avg_lead_time integer DEFAULT 0 NOT NULL,
- avg_cycle_time integer DEFAULT 0 NOT NULL
+CREATE TABLE "project_daily_stats" (
+ "id" integer NOT NULL,
+ "day" character(10) NOT NULL,
+ "project_id" integer NOT NULL,
+ "avg_lead_time" integer DEFAULT 0 NOT NULL,
+ "avg_cycle_time" integer DEFAULT 0 NOT NULL
);
@@ -394,7 +391,7 @@ CREATE TABLE project_daily_stats (
-- Name: project_daily_stats_id_seq; Type: SEQUENCE; Schema: public; Owner: -
--
-CREATE SEQUENCE project_daily_stats_id_seq
+CREATE SEQUENCE "project_daily_stats_id_seq"
START WITH 1
INCREMENT BY 1
NO MINVALUE
@@ -406,14 +403,14 @@ CREATE SEQUENCE project_daily_stats_id_seq
-- Name: project_daily_stats_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
--
-ALTER SEQUENCE project_daily_stats_id_seq OWNED BY project_daily_stats.id;
+ALTER SEQUENCE "project_daily_stats_id_seq" OWNED BY "project_daily_stats"."id";
--
-- Name: project_daily_summaries_id_seq; Type: SEQUENCE; Schema: public; Owner: -
--
-CREATE SEQUENCE project_daily_summaries_id_seq
+CREATE SEQUENCE "project_daily_summaries_id_seq"
START WITH 1
INCREMENT BY 1
NO MINVALUE
@@ -425,18 +422,18 @@ CREATE SEQUENCE project_daily_summaries_id_seq
-- Name: project_daily_summaries_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
--
-ALTER SEQUENCE project_daily_summaries_id_seq OWNED BY project_daily_column_stats.id;
+ALTER SEQUENCE "project_daily_summaries_id_seq" OWNED BY "project_daily_column_stats"."id";
--
--- Name: project_has_categories; Type: TABLE; Schema: public; Owner: -; Tablespace:
+-- Name: project_has_categories; Type: TABLE; Schema: public; Owner: -
--
-CREATE TABLE project_has_categories (
- id integer NOT NULL,
- name character varying(255) NOT NULL,
- project_id integer NOT NULL,
- description text
+CREATE TABLE "project_has_categories" (
+ "id" integer NOT NULL,
+ "name" character varying(255) NOT NULL,
+ "project_id" integer NOT NULL,
+ "description" "text"
);
@@ -444,7 +441,7 @@ CREATE TABLE project_has_categories (
-- Name: project_has_categories_id_seq; Type: SEQUENCE; Schema: public; Owner: -
--
-CREATE SEQUENCE project_has_categories_id_seq
+CREATE SEQUENCE "project_has_categories_id_seq"
START WITH 1
INCREMENT BY 1
NO MINVALUE
@@ -456,22 +453,22 @@ CREATE SEQUENCE project_has_categories_id_seq
-- Name: project_has_categories_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
--
-ALTER SEQUENCE project_has_categories_id_seq OWNED BY project_has_categories.id;
+ALTER SEQUENCE "project_has_categories_id_seq" OWNED BY "project_has_categories"."id";
--
--- Name: project_has_files; Type: TABLE; Schema: public; Owner: -; Tablespace:
+-- Name: project_has_files; Type: TABLE; Schema: public; Owner: -
--
-CREATE TABLE project_has_files (
- id integer NOT NULL,
- project_id integer NOT NULL,
- name character varying(255) NOT NULL,
- path character varying(255) NOT NULL,
- is_image boolean DEFAULT false,
- size integer DEFAULT 0 NOT NULL,
- user_id integer DEFAULT 0 NOT NULL,
- date integer DEFAULT 0 NOT NULL
+CREATE TABLE "project_has_files" (
+ "id" integer NOT NULL,
+ "project_id" integer NOT NULL,
+ "name" character varying(255) NOT NULL,
+ "path" character varying(255) NOT NULL,
+ "is_image" boolean DEFAULT false,
+ "size" integer DEFAULT 0 NOT NULL,
+ "user_id" integer DEFAULT 0 NOT NULL,
+ "date" integer DEFAULT 0 NOT NULL
);
@@ -479,7 +476,7 @@ CREATE TABLE project_has_files (
-- Name: project_has_files_id_seq; Type: SEQUENCE; Schema: public; Owner: -
--
-CREATE SEQUENCE project_has_files_id_seq
+CREATE SEQUENCE "project_has_files_id_seq"
START WITH 1
INCREMENT BY 1
NO MINVALUE
@@ -491,41 +488,41 @@ CREATE SEQUENCE project_has_files_id_seq
-- Name: project_has_files_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
--
-ALTER SEQUENCE project_has_files_id_seq OWNED BY project_has_files.id;
+ALTER SEQUENCE "project_has_files_id_seq" OWNED BY "project_has_files"."id";
--
--- Name: project_has_groups; Type: TABLE; Schema: public; Owner: -; Tablespace:
+-- Name: project_has_groups; Type: TABLE; Schema: public; Owner: -
--
-CREATE TABLE project_has_groups (
- group_id integer NOT NULL,
- project_id integer NOT NULL,
- role character varying(25) NOT NULL
+CREATE TABLE "project_has_groups" (
+ "group_id" integer NOT NULL,
+ "project_id" integer NOT NULL,
+ "role" character varying(25) NOT NULL
);
--
--- Name: project_has_metadata; Type: TABLE; Schema: public; Owner: -; Tablespace:
+-- Name: project_has_metadata; Type: TABLE; Schema: public; Owner: -
--
-CREATE TABLE project_has_metadata (
- project_id integer NOT NULL,
- name character varying(50) NOT NULL,
- value character varying(255) DEFAULT ''::character varying,
- changed_by integer DEFAULT 0 NOT NULL,
- changed_on integer DEFAULT 0 NOT NULL
+CREATE TABLE "project_has_metadata" (
+ "project_id" integer NOT NULL,
+ "name" character varying(50) NOT NULL,
+ "value" character varying(255) DEFAULT ''::character varying,
+ "changed_by" integer DEFAULT 0 NOT NULL,
+ "changed_on" integer DEFAULT 0 NOT NULL
);
--
--- Name: project_has_notification_types; Type: TABLE; Schema: public; Owner: -; Tablespace:
+-- Name: project_has_notification_types; Type: TABLE; Schema: public; Owner: -
--
-CREATE TABLE project_has_notification_types (
- id integer NOT NULL,
- project_id integer NOT NULL,
- notification_type character varying(50) NOT NULL
+CREATE TABLE "project_has_notification_types" (
+ "id" integer NOT NULL,
+ "project_id" integer NOT NULL,
+ "notification_type" character varying(50) NOT NULL
);
@@ -533,7 +530,7 @@ CREATE TABLE project_has_notification_types (
-- Name: project_has_notification_types_id_seq; Type: SEQUENCE; Schema: public; Owner: -
--
-CREATE SEQUENCE project_has_notification_types_id_seq
+CREATE SEQUENCE "project_has_notification_types_id_seq"
START WITH 1
INCREMENT BY 1
NO MINVALUE
@@ -545,43 +542,43 @@ CREATE SEQUENCE project_has_notification_types_id_seq
-- Name: project_has_notification_types_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
--
-ALTER SEQUENCE project_has_notification_types_id_seq OWNED BY project_has_notification_types.id;
+ALTER SEQUENCE "project_has_notification_types_id_seq" OWNED BY "project_has_notification_types"."id";
--
--- Name: project_has_users; Type: TABLE; Schema: public; Owner: -; Tablespace:
+-- Name: project_has_users; Type: TABLE; Schema: public; Owner: -
--
-CREATE TABLE project_has_users (
- project_id integer NOT NULL,
- user_id integer NOT NULL,
- role character varying(25) DEFAULT 'project-viewer'::character varying NOT NULL
+CREATE TABLE "project_has_users" (
+ "project_id" integer NOT NULL,
+ "user_id" integer NOT NULL,
+ "role" character varying(25) DEFAULT 'project-viewer'::character varying NOT NULL
);
--
--- Name: projects; Type: TABLE; Schema: public; Owner: -; Tablespace:
---
-
-CREATE TABLE projects (
- id integer NOT NULL,
- name character varying(255) NOT NULL,
- is_active boolean DEFAULT true,
- token character varying(255),
- last_modified bigint DEFAULT 0,
- is_public boolean DEFAULT false,
- is_private boolean DEFAULT false,
- is_everybody_allowed boolean DEFAULT false,
- default_swimlane character varying(200) DEFAULT 'Default swimlane'::character varying,
- show_default_swimlane boolean DEFAULT true,
- description text,
- identifier character varying(50) DEFAULT ''::character varying,
- start_date character varying(10) DEFAULT ''::character varying,
- end_date character varying(10) DEFAULT ''::character varying,
- owner_id integer DEFAULT 0,
- priority_default integer DEFAULT 0,
- priority_start integer DEFAULT 0,
- priority_end integer DEFAULT 3
+-- Name: projects; Type: TABLE; Schema: public; Owner: -
+--
+
+CREATE TABLE "projects" (
+ "id" integer NOT NULL,
+ "name" character varying(255) NOT NULL,
+ "is_active" boolean DEFAULT true,
+ "token" character varying(255),
+ "last_modified" bigint DEFAULT 0,
+ "is_public" boolean DEFAULT false,
+ "is_private" boolean DEFAULT false,
+ "is_everybody_allowed" boolean DEFAULT false,
+ "default_swimlane" character varying(200) DEFAULT 'Default swimlane'::character varying,
+ "show_default_swimlane" boolean DEFAULT true,
+ "description" "text",
+ "identifier" character varying(50) DEFAULT ''::character varying,
+ "start_date" character varying(10) DEFAULT ''::character varying,
+ "end_date" character varying(10) DEFAULT ''::character varying,
+ "owner_id" integer DEFAULT 0,
+ "priority_default" integer DEFAULT 0,
+ "priority_start" integer DEFAULT 0,
+ "priority_end" integer DEFAULT 3
);
@@ -589,7 +586,7 @@ CREATE TABLE projects (
-- Name: projects_id_seq; Type: SEQUENCE; Schema: public; Owner: -
--
-CREATE SEQUENCE projects_id_seq
+CREATE SEQUENCE "projects_id_seq"
START WITH 1
INCREMENT BY 1
NO MINVALUE
@@ -601,22 +598,22 @@ CREATE SEQUENCE projects_id_seq
-- Name: projects_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
--
-ALTER SEQUENCE projects_id_seq OWNED BY projects.id;
+ALTER SEQUENCE "projects_id_seq" OWNED BY "projects"."id";
--
--- Name: remember_me; Type: TABLE; Schema: public; Owner: -; Tablespace:
+-- Name: remember_me; Type: TABLE; Schema: public; Owner: -
--
-CREATE TABLE remember_me (
- id integer NOT NULL,
- user_id integer,
- ip character varying(45),
- user_agent character varying(255),
- token character varying(255),
- sequence character varying(255),
- expiration integer,
- date_creation bigint
+CREATE TABLE "remember_me" (
+ "id" integer NOT NULL,
+ "user_id" integer,
+ "ip" character varying(45),
+ "user_agent" character varying(255),
+ "token" character varying(255),
+ "sequence" character varying(255),
+ "expiration" integer,
+ "date_creation" bigint
);
@@ -624,7 +621,7 @@ CREATE TABLE remember_me (
-- Name: remember_me_id_seq; Type: SEQUENCE; Schema: public; Owner: -
--
-CREATE SEQUENCE remember_me_id_seq
+CREATE SEQUENCE "remember_me_id_seq"
START WITH 1
INCREMENT BY 1
NO MINVALUE
@@ -636,41 +633,41 @@ CREATE SEQUENCE remember_me_id_seq
-- Name: remember_me_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
--
-ALTER SEQUENCE remember_me_id_seq OWNED BY remember_me.id;
+ALTER SEQUENCE "remember_me_id_seq" OWNED BY "remember_me"."id";
--
--- Name: schema_version; Type: TABLE; Schema: public; Owner: -; Tablespace:
+-- Name: schema_version; Type: TABLE; Schema: public; Owner: -
--
-CREATE TABLE schema_version (
- version integer DEFAULT 0
+CREATE TABLE "schema_version" (
+ "version" integer DEFAULT 0
);
--
--- Name: settings; Type: TABLE; Schema: public; Owner: -; Tablespace:
+-- Name: settings; Type: TABLE; Schema: public; Owner: -
--
-CREATE TABLE settings (
- option character varying(100) NOT NULL,
- value character varying(255) DEFAULT ''::character varying,
- changed_by integer DEFAULT 0 NOT NULL,
- changed_on integer DEFAULT 0 NOT NULL
+CREATE TABLE "settings" (
+ "option" character varying(100) NOT NULL,
+ "value" character varying(255) DEFAULT ''::character varying,
+ "changed_by" integer DEFAULT 0 NOT NULL,
+ "changed_on" integer DEFAULT 0 NOT NULL
);
--
--- Name: subtask_time_tracking; Type: TABLE; Schema: public; Owner: -; Tablespace:
+-- Name: subtask_time_tracking; Type: TABLE; Schema: public; Owner: -
--
-CREATE TABLE subtask_time_tracking (
- id integer NOT NULL,
- user_id integer NOT NULL,
- subtask_id integer NOT NULL,
- start bigint DEFAULT 0,
+CREATE TABLE "subtask_time_tracking" (
+ "id" integer NOT NULL,
+ "user_id" integer NOT NULL,
+ "subtask_id" integer NOT NULL,
+ "start" bigint DEFAULT 0,
"end" bigint DEFAULT 0,
- time_spent real DEFAULT 0
+ "time_spent" real DEFAULT 0
);
@@ -678,7 +675,7 @@ CREATE TABLE subtask_time_tracking (
-- Name: subtask_time_tracking_id_seq; Type: SEQUENCE; Schema: public; Owner: -
--
-CREATE SEQUENCE subtask_time_tracking_id_seq
+CREATE SEQUENCE "subtask_time_tracking_id_seq"
START WITH 1
INCREMENT BY 1
NO MINVALUE
@@ -690,36 +687,36 @@ CREATE SEQUENCE subtask_time_tracking_id_seq
-- Name: subtask_time_tracking_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
--
-ALTER SEQUENCE subtask_time_tracking_id_seq OWNED BY subtask_time_tracking.id;
+ALTER SEQUENCE "subtask_time_tracking_id_seq" OWNED BY "subtask_time_tracking"."id";
--
--- Name: subtasks; Type: TABLE; Schema: public; Owner: -; Tablespace:
+-- Name: subtasks; Type: TABLE; Schema: public; Owner: -
--
-CREATE TABLE subtasks (
- id integer NOT NULL,
- title character varying(255) NOT NULL,
- status smallint DEFAULT 0,
- time_estimated double precision DEFAULT 0,
- time_spent double precision DEFAULT 0,
- task_id integer NOT NULL,
- user_id integer,
+CREATE TABLE "subtasks" (
+ "id" integer NOT NULL,
+ "title" character varying(255) NOT NULL,
+ "status" smallint DEFAULT 0,
+ "time_estimated" double precision DEFAULT 0,
+ "time_spent" double precision DEFAULT 0,
+ "task_id" integer NOT NULL,
+ "user_id" integer,
"position" integer DEFAULT 1
);
--
--- Name: swimlanes; Type: TABLE; Schema: public; Owner: -; Tablespace:
+-- Name: swimlanes; Type: TABLE; Schema: public; Owner: -
--
-CREATE TABLE swimlanes (
- id integer NOT NULL,
- name character varying(200) NOT NULL,
+CREATE TABLE "swimlanes" (
+ "id" integer NOT NULL,
+ "name" character varying(200) NOT NULL,
"position" integer DEFAULT 1,
- is_active boolean DEFAULT true,
- project_id integer,
- description text
+ "is_active" boolean DEFAULT true,
+ "project_id" integer,
+ "description" "text"
);
@@ -727,7 +724,7 @@ CREATE TABLE swimlanes (
-- Name: swimlanes_id_seq; Type: SEQUENCE; Schema: public; Owner: -
--
-CREATE SEQUENCE swimlanes_id_seq
+CREATE SEQUENCE "swimlanes_id_seq"
START WITH 1
INCREMENT BY 1
NO MINVALUE
@@ -739,23 +736,23 @@ CREATE SEQUENCE swimlanes_id_seq
-- Name: swimlanes_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
--
-ALTER SEQUENCE swimlanes_id_seq OWNED BY swimlanes.id;
+ALTER SEQUENCE "swimlanes_id_seq" OWNED BY "swimlanes"."id";
--
--- Name: task_has_external_links; Type: TABLE; Schema: public; Owner: -; Tablespace:
+-- Name: task_has_external_links; Type: TABLE; Schema: public; Owner: -
--
-CREATE TABLE task_has_external_links (
- id integer NOT NULL,
- link_type character varying(100) NOT NULL,
- dependency character varying(100) NOT NULL,
- title character varying(255) NOT NULL,
- url character varying(255) NOT NULL,
- date_creation integer NOT NULL,
- date_modification integer NOT NULL,
- task_id integer NOT NULL,
- creator_id integer DEFAULT 0
+CREATE TABLE "task_has_external_links" (
+ "id" integer NOT NULL,
+ "link_type" character varying(100) NOT NULL,
+ "dependency" character varying(100) NOT NULL,
+ "title" character varying(255) NOT NULL,
+ "url" character varying(255) NOT NULL,
+ "date_creation" integer NOT NULL,
+ "date_modification" integer NOT NULL,
+ "task_id" integer NOT NULL,
+ "creator_id" integer DEFAULT 0
);
@@ -763,7 +760,7 @@ CREATE TABLE task_has_external_links (
-- Name: task_has_external_links_id_seq; Type: SEQUENCE; Schema: public; Owner: -
--
-CREATE SEQUENCE task_has_external_links_id_seq
+CREATE SEQUENCE "task_has_external_links_id_seq"
START WITH 1
INCREMENT BY 1
NO MINVALUE
@@ -775,22 +772,22 @@ CREATE SEQUENCE task_has_external_links_id_seq
-- Name: task_has_external_links_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
--
-ALTER SEQUENCE task_has_external_links_id_seq OWNED BY task_has_external_links.id;
+ALTER SEQUENCE "task_has_external_links_id_seq" OWNED BY "task_has_external_links"."id";
--
--- Name: task_has_files; Type: TABLE; Schema: public; Owner: -; Tablespace:
+-- Name: task_has_files; Type: TABLE; Schema: public; Owner: -
--
-CREATE TABLE task_has_files (
- id integer NOT NULL,
- name character varying(255) NOT NULL,
- path character varying(255),
- is_image boolean DEFAULT false,
- task_id integer NOT NULL,
- date bigint DEFAULT 0 NOT NULL,
- user_id integer DEFAULT 0 NOT NULL,
- size integer DEFAULT 0 NOT NULL
+CREATE TABLE "task_has_files" (
+ "id" integer NOT NULL,
+ "name" character varying(255) NOT NULL,
+ "path" character varying(255),
+ "is_image" boolean DEFAULT false,
+ "task_id" integer NOT NULL,
+ "date" bigint DEFAULT 0 NOT NULL,
+ "user_id" integer DEFAULT 0 NOT NULL,
+ "size" integer DEFAULT 0 NOT NULL
);
@@ -798,7 +795,7 @@ CREATE TABLE task_has_files (
-- Name: task_has_files_id_seq; Type: SEQUENCE; Schema: public; Owner: -
--
-CREATE SEQUENCE task_has_files_id_seq
+CREATE SEQUENCE "task_has_files_id_seq"
START WITH 1
INCREMENT BY 1
NO MINVALUE
@@ -810,18 +807,18 @@ CREATE SEQUENCE task_has_files_id_seq
-- Name: task_has_files_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
--
-ALTER SEQUENCE task_has_files_id_seq OWNED BY task_has_files.id;
+ALTER SEQUENCE "task_has_files_id_seq" OWNED BY "task_has_files"."id";
--
--- Name: task_has_links; Type: TABLE; Schema: public; Owner: -; Tablespace:
+-- Name: task_has_links; Type: TABLE; Schema: public; Owner: -
--
-CREATE TABLE task_has_links (
- id integer NOT NULL,
- link_id integer NOT NULL,
- task_id integer NOT NULL,
- opposite_task_id integer NOT NULL
+CREATE TABLE "task_has_links" (
+ "id" integer NOT NULL,
+ "link_id" integer NOT NULL,
+ "task_id" integer NOT NULL,
+ "opposite_task_id" integer NOT NULL
);
@@ -829,7 +826,7 @@ CREATE TABLE task_has_links (
-- Name: task_has_links_id_seq; Type: SEQUENCE; Schema: public; Owner: -
--
-CREATE SEQUENCE task_has_links_id_seq
+CREATE SEQUENCE "task_has_links_id_seq"
START WITH 1
INCREMENT BY 1
NO MINVALUE
@@ -841,19 +838,19 @@ CREATE SEQUENCE task_has_links_id_seq
-- Name: task_has_links_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
--
-ALTER SEQUENCE task_has_links_id_seq OWNED BY task_has_links.id;
+ALTER SEQUENCE "task_has_links_id_seq" OWNED BY "task_has_links"."id";
--
--- Name: task_has_metadata; Type: TABLE; Schema: public; Owner: -; Tablespace:
+-- Name: task_has_metadata; Type: TABLE; Schema: public; Owner: -
--
-CREATE TABLE task_has_metadata (
- task_id integer NOT NULL,
- name character varying(50) NOT NULL,
- value character varying(255) DEFAULT ''::character varying,
- changed_by integer DEFAULT 0 NOT NULL,
- changed_on integer DEFAULT 0 NOT NULL
+CREATE TABLE "task_has_metadata" (
+ "task_id" integer NOT NULL,
+ "name" character varying(50) NOT NULL,
+ "value" character varying(255) DEFAULT ''::character varying,
+ "changed_by" integer DEFAULT 0 NOT NULL,
+ "changed_on" integer DEFAULT 0 NOT NULL
);
@@ -861,7 +858,7 @@ CREATE TABLE task_has_metadata (
-- Name: task_has_subtasks_id_seq; Type: SEQUENCE; Schema: public; Owner: -
--
-CREATE SEQUENCE task_has_subtasks_id_seq
+CREATE SEQUENCE "task_has_subtasks_id_seq"
START WITH 1
INCREMENT BY 1
NO MINVALUE
@@ -873,44 +870,44 @@ CREATE SEQUENCE task_has_subtasks_id_seq
-- Name: task_has_subtasks_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
--
-ALTER SEQUENCE task_has_subtasks_id_seq OWNED BY subtasks.id;
+ALTER SEQUENCE "task_has_subtasks_id_seq" OWNED BY "subtasks"."id";
--
--- Name: tasks; Type: TABLE; Schema: public; Owner: -; Tablespace:
+-- Name: tasks; Type: TABLE; Schema: public; Owner: -
--
-CREATE TABLE tasks (
- id integer NOT NULL,
- title character varying(255) NOT NULL,
- description text,
- date_creation bigint,
- color_id character varying(255),
- project_id integer NOT NULL,
- column_id integer NOT NULL,
- owner_id integer DEFAULT 0,
+CREATE TABLE "tasks" (
+ "id" integer NOT NULL,
+ "title" character varying(255) NOT NULL,
+ "description" "text",
+ "date_creation" bigint,
+ "color_id" character varying(255),
+ "project_id" integer NOT NULL,
+ "column_id" integer NOT NULL,
+ "owner_id" integer DEFAULT 0,
"position" integer,
- is_active boolean DEFAULT true,
- date_completed bigint,
- score integer,
- date_due bigint,
- category_id integer DEFAULT 0,
- creator_id integer DEFAULT 0,
- date_modification integer DEFAULT 0,
- reference character varying(50) DEFAULT ''::character varying,
- date_started bigint,
- time_spent double precision DEFAULT 0,
- time_estimated double precision DEFAULT 0,
- swimlane_id integer DEFAULT 0,
- date_moved bigint DEFAULT 0,
- recurrence_status integer DEFAULT 0 NOT NULL,
- recurrence_trigger integer DEFAULT 0 NOT NULL,
- recurrence_factor integer DEFAULT 0 NOT NULL,
- recurrence_timeframe integer DEFAULT 0 NOT NULL,
- recurrence_basedate integer DEFAULT 0 NOT NULL,
- recurrence_parent integer,
- recurrence_child integer,
- priority integer DEFAULT 0
+ "is_active" boolean DEFAULT true,
+ "date_completed" bigint,
+ "score" integer,
+ "date_due" bigint,
+ "category_id" integer DEFAULT 0,
+ "creator_id" integer DEFAULT 0,
+ "date_modification" integer DEFAULT 0,
+ "reference" character varying(50) DEFAULT ''::character varying,
+ "date_started" bigint,
+ "time_spent" double precision DEFAULT 0,
+ "time_estimated" double precision DEFAULT 0,
+ "swimlane_id" integer DEFAULT 0,
+ "date_moved" bigint DEFAULT 0,
+ "recurrence_status" integer DEFAULT 0 NOT NULL,
+ "recurrence_trigger" integer DEFAULT 0 NOT NULL,
+ "recurrence_factor" integer DEFAULT 0 NOT NULL,
+ "recurrence_timeframe" integer DEFAULT 0 NOT NULL,
+ "recurrence_basedate" integer DEFAULT 0 NOT NULL,
+ "recurrence_parent" integer,
+ "recurrence_child" integer,
+ "priority" integer DEFAULT 0
);
@@ -918,7 +915,7 @@ CREATE TABLE tasks (
-- Name: tasks_id_seq; Type: SEQUENCE; Schema: public; Owner: -
--
-CREATE SEQUENCE tasks_id_seq
+CREATE SEQUENCE "tasks_id_seq"
START WITH 1
INCREMENT BY 1
NO MINVALUE
@@ -930,22 +927,22 @@ CREATE SEQUENCE tasks_id_seq
-- Name: tasks_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
--
-ALTER SEQUENCE tasks_id_seq OWNED BY tasks.id;
+ALTER SEQUENCE "tasks_id_seq" OWNED BY "tasks"."id";
--
--- Name: transitions; Type: TABLE; Schema: public; Owner: -; Tablespace:
+-- Name: transitions; Type: TABLE; Schema: public; Owner: -
--
-CREATE TABLE transitions (
- id integer NOT NULL,
- user_id integer NOT NULL,
- project_id integer NOT NULL,
- task_id integer NOT NULL,
- src_column_id integer NOT NULL,
- dst_column_id integer NOT NULL,
- date bigint NOT NULL,
- time_spent integer DEFAULT 0
+CREATE TABLE "transitions" (
+ "id" integer NOT NULL,
+ "user_id" integer NOT NULL,
+ "project_id" integer NOT NULL,
+ "task_id" integer NOT NULL,
+ "src_column_id" integer NOT NULL,
+ "dst_column_id" integer NOT NULL,
+ "date" bigint NOT NULL,
+ "time_spent" integer DEFAULT 0
);
@@ -953,7 +950,7 @@ CREATE TABLE transitions (
-- Name: transitions_id_seq; Type: SEQUENCE; Schema: public; Owner: -
--
-CREATE SEQUENCE transitions_id_seq
+CREATE SEQUENCE "transitions_id_seq"
START WITH 1
INCREMENT BY 1
NO MINVALUE
@@ -965,30 +962,30 @@ CREATE SEQUENCE transitions_id_seq
-- Name: transitions_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
--
-ALTER SEQUENCE transitions_id_seq OWNED BY transitions.id;
+ALTER SEQUENCE "transitions_id_seq" OWNED BY "transitions"."id";
--
--- Name: user_has_metadata; Type: TABLE; Schema: public; Owner: -; Tablespace:
+-- Name: user_has_metadata; Type: TABLE; Schema: public; Owner: -
--
-CREATE TABLE user_has_metadata (
- user_id integer NOT NULL,
- name character varying(50) NOT NULL,
- value character varying(255) DEFAULT ''::character varying,
- changed_by integer DEFAULT 0 NOT NULL,
- changed_on integer DEFAULT 0 NOT NULL
+CREATE TABLE "user_has_metadata" (
+ "user_id" integer NOT NULL,
+ "name" character varying(50) NOT NULL,
+ "value" character varying(255) DEFAULT ''::character varying,
+ "changed_by" integer DEFAULT 0 NOT NULL,
+ "changed_on" integer DEFAULT 0 NOT NULL
);
--
--- Name: user_has_notification_types; Type: TABLE; Schema: public; Owner: -; Tablespace:
+-- Name: user_has_notification_types; Type: TABLE; Schema: public; Owner: -
--
-CREATE TABLE user_has_notification_types (
- id integer NOT NULL,
- user_id integer NOT NULL,
- notification_type character varying(50)
+CREATE TABLE "user_has_notification_types" (
+ "id" integer NOT NULL,
+ "user_id" integer NOT NULL,
+ "notification_type" character varying(50)
);
@@ -996,7 +993,7 @@ CREATE TABLE user_has_notification_types (
-- Name: user_has_notification_types_id_seq; Type: SEQUENCE; Schema: public; Owner: -
--
-CREATE SEQUENCE user_has_notification_types_id_seq
+CREATE SEQUENCE "user_has_notification_types_id_seq"
START WITH 1
INCREMENT BY 1
NO MINVALUE
@@ -1008,29 +1005,29 @@ CREATE SEQUENCE user_has_notification_types_id_seq
-- Name: user_has_notification_types_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
--
-ALTER SEQUENCE user_has_notification_types_id_seq OWNED BY user_has_notification_types.id;
+ALTER SEQUENCE "user_has_notification_types_id_seq" OWNED BY "user_has_notification_types"."id";
--
--- Name: user_has_notifications; Type: TABLE; Schema: public; Owner: -; Tablespace:
+-- Name: user_has_notifications; Type: TABLE; Schema: public; Owner: -
--
-CREATE TABLE user_has_notifications (
- user_id integer NOT NULL,
- project_id integer
+CREATE TABLE "user_has_notifications" (
+ "user_id" integer NOT NULL,
+ "project_id" integer
);
--
--- Name: user_has_unread_notifications; Type: TABLE; Schema: public; Owner: -; Tablespace:
+-- Name: user_has_unread_notifications; Type: TABLE; Schema: public; Owner: -
--
-CREATE TABLE user_has_unread_notifications (
- id integer NOT NULL,
- user_id integer NOT NULL,
- date_creation bigint NOT NULL,
- event_name character varying(50) NOT NULL,
- event_data text NOT NULL
+CREATE TABLE "user_has_unread_notifications" (
+ "id" integer NOT NULL,
+ "user_id" integer NOT NULL,
+ "date_creation" bigint NOT NULL,
+ "event_name" character varying(50) NOT NULL,
+ "event_data" "text" NOT NULL
);
@@ -1038,7 +1035,7 @@ CREATE TABLE user_has_unread_notifications (
-- Name: user_has_unread_notifications_id_seq; Type: SEQUENCE; Schema: public; Owner: -
--
-CREATE SEQUENCE user_has_unread_notifications_id_seq
+CREATE SEQUENCE "user_has_unread_notifications_id_seq"
START WITH 1
INCREMENT BY 1
NO MINVALUE
@@ -1050,36 +1047,36 @@ CREATE SEQUENCE user_has_unread_notifications_id_seq
-- Name: user_has_unread_notifications_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
--
-ALTER SEQUENCE user_has_unread_notifications_id_seq OWNED BY user_has_unread_notifications.id;
-
-
---
--- Name: users; Type: TABLE; Schema: public; Owner: -; Tablespace:
---
-
-CREATE TABLE users (
- id integer NOT NULL,
- username character varying(50) NOT NULL,
- password character varying(255),
- is_ldap_user boolean DEFAULT false,
- name character varying(255),
- email character varying(255),
- google_id character varying(255),
- github_id character varying(30),
- notifications_enabled boolean DEFAULT false,
- timezone character varying(50),
- language character varying(5),
- disable_login_form boolean DEFAULT false,
- twofactor_activated boolean DEFAULT false,
- twofactor_secret character(16),
- token character varying(255) DEFAULT ''::character varying,
- notifications_filter integer DEFAULT 4,
- nb_failed_login integer DEFAULT 0,
- lock_expiration_date bigint DEFAULT 0,
- gitlab_id integer,
- role character varying(25) DEFAULT 'app-user'::character varying NOT NULL,
- is_active boolean DEFAULT true,
- avatar_path character varying(255)
+ALTER SEQUENCE "user_has_unread_notifications_id_seq" OWNED BY "user_has_unread_notifications"."id";
+
+
+--
+-- Name: users; Type: TABLE; Schema: public; Owner: -
+--
+
+CREATE TABLE "users" (
+ "id" integer NOT NULL,
+ "username" character varying(50) NOT NULL,
+ "password" character varying(255),
+ "is_ldap_user" boolean DEFAULT false,
+ "name" character varying(255),
+ "email" character varying(255),
+ "google_id" character varying(255),
+ "github_id" character varying(30),
+ "notifications_enabled" boolean DEFAULT false,
+ "timezone" character varying(50),
+ "language" character varying(5),
+ "disable_login_form" boolean DEFAULT false,
+ "twofactor_activated" boolean DEFAULT false,
+ "twofactor_secret" character(16),
+ "token" character varying(255) DEFAULT ''::character varying,
+ "notifications_filter" integer DEFAULT 4,
+ "nb_failed_login" integer DEFAULT 0,
+ "lock_expiration_date" bigint DEFAULT 0,
+ "gitlab_id" integer,
+ "role" character varying(25) DEFAULT 'app-user'::character varying NOT NULL,
+ "is_active" boolean DEFAULT true,
+ "avatar_path" character varying(255)
);
@@ -1087,7 +1084,7 @@ CREATE TABLE users (
-- Name: users_id_seq; Type: SEQUENCE; Schema: public; Owner: -
--
-CREATE SEQUENCE users_id_seq
+CREATE SEQUENCE "users_id_seq"
START WITH 1
INCREMENT BY 1
NO MINVALUE
@@ -1099,1034 +1096,1034 @@ CREATE SEQUENCE users_id_seq
-- Name: users_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
--
-ALTER SEQUENCE users_id_seq OWNED BY users.id;
+ALTER SEQUENCE "users_id_seq" OWNED BY "users"."id";
--
-- Name: id; Type: DEFAULT; Schema: public; Owner: -
--
-ALTER TABLE ONLY action_has_params ALTER COLUMN id SET DEFAULT nextval('action_has_params_id_seq'::regclass);
+ALTER TABLE ONLY "action_has_params" ALTER COLUMN "id" SET DEFAULT "nextval"('"action_has_params_id_seq"'::"regclass");
--
-- Name: id; Type: DEFAULT; Schema: public; Owner: -
--
-ALTER TABLE ONLY actions ALTER COLUMN id SET DEFAULT nextval('actions_id_seq'::regclass);
+ALTER TABLE ONLY "actions" ALTER COLUMN "id" SET DEFAULT "nextval"('"actions_id_seq"'::"regclass");
--
-- Name: id; Type: DEFAULT; Schema: public; Owner: -
--
-ALTER TABLE ONLY columns ALTER COLUMN id SET DEFAULT nextval('columns_id_seq'::regclass);
+ALTER TABLE ONLY "columns" ALTER COLUMN "id" SET DEFAULT "nextval"('"columns_id_seq"'::"regclass");
--
-- Name: id; Type: DEFAULT; Schema: public; Owner: -
--
-ALTER TABLE ONLY comments ALTER COLUMN id SET DEFAULT nextval('comments_id_seq'::regclass);
+ALTER TABLE ONLY "comments" ALTER COLUMN "id" SET DEFAULT "nextval"('"comments_id_seq"'::"regclass");
--
-- Name: id; Type: DEFAULT; Schema: public; Owner: -
--
-ALTER TABLE ONLY custom_filters ALTER COLUMN id SET DEFAULT nextval('custom_filters_id_seq'::regclass);
+ALTER TABLE ONLY "custom_filters" ALTER COLUMN "id" SET DEFAULT "nextval"('"custom_filters_id_seq"'::"regclass");
--
-- Name: id; Type: DEFAULT; Schema: public; Owner: -
--
-ALTER TABLE ONLY groups ALTER COLUMN id SET DEFAULT nextval('groups_id_seq'::regclass);
+ALTER TABLE ONLY "groups" ALTER COLUMN "id" SET DEFAULT "nextval"('"groups_id_seq"'::"regclass");
--
-- Name: id; Type: DEFAULT; Schema: public; Owner: -
--
-ALTER TABLE ONLY last_logins ALTER COLUMN id SET DEFAULT nextval('last_logins_id_seq'::regclass);
+ALTER TABLE ONLY "last_logins" ALTER COLUMN "id" SET DEFAULT "nextval"('"last_logins_id_seq"'::"regclass");
--
-- Name: id; Type: DEFAULT; Schema: public; Owner: -
--
-ALTER TABLE ONLY links ALTER COLUMN id SET DEFAULT nextval('links_id_seq'::regclass);
+ALTER TABLE ONLY "links" ALTER COLUMN "id" SET DEFAULT "nextval"('"links_id_seq"'::"regclass");
--
-- Name: id; Type: DEFAULT; Schema: public; Owner: -
--
-ALTER TABLE ONLY project_activities ALTER COLUMN id SET DEFAULT nextval('project_activities_id_seq'::regclass);
+ALTER TABLE ONLY "project_activities" ALTER COLUMN "id" SET DEFAULT "nextval"('"project_activities_id_seq"'::"regclass");
--
-- Name: id; Type: DEFAULT; Schema: public; Owner: -
--
-ALTER TABLE ONLY project_daily_column_stats ALTER COLUMN id SET DEFAULT nextval('project_daily_summaries_id_seq'::regclass);
+ALTER TABLE ONLY "project_daily_column_stats" ALTER COLUMN "id" SET DEFAULT "nextval"('"project_daily_summaries_id_seq"'::"regclass");
--
-- Name: id; Type: DEFAULT; Schema: public; Owner: -
--
-ALTER TABLE ONLY project_daily_stats ALTER COLUMN id SET DEFAULT nextval('project_daily_stats_id_seq'::regclass);
+ALTER TABLE ONLY "project_daily_stats" ALTER COLUMN "id" SET DEFAULT "nextval"('"project_daily_stats_id_seq"'::"regclass");
--
-- Name: id; Type: DEFAULT; Schema: public; Owner: -
--
-ALTER TABLE ONLY project_has_categories ALTER COLUMN id SET DEFAULT nextval('project_has_categories_id_seq'::regclass);
+ALTER TABLE ONLY "project_has_categories" ALTER COLUMN "id" SET DEFAULT "nextval"('"project_has_categories_id_seq"'::"regclass");
--
-- Name: id; Type: DEFAULT; Schema: public; Owner: -
--
-ALTER TABLE ONLY project_has_files ALTER COLUMN id SET DEFAULT nextval('project_has_files_id_seq'::regclass);
+ALTER TABLE ONLY "project_has_files" ALTER COLUMN "id" SET DEFAULT "nextval"('"project_has_files_id_seq"'::"regclass");
--
-- Name: id; Type: DEFAULT; Schema: public; Owner: -
--
-ALTER TABLE ONLY project_has_notification_types ALTER COLUMN id SET DEFAULT nextval('project_has_notification_types_id_seq'::regclass);
+ALTER TABLE ONLY "project_has_notification_types" ALTER COLUMN "id" SET DEFAULT "nextval"('"project_has_notification_types_id_seq"'::"regclass");
--
-- Name: id; Type: DEFAULT; Schema: public; Owner: -
--
-ALTER TABLE ONLY projects ALTER COLUMN id SET DEFAULT nextval('projects_id_seq'::regclass);
+ALTER TABLE ONLY "projects" ALTER COLUMN "id" SET DEFAULT "nextval"('"projects_id_seq"'::"regclass");
--
-- Name: id; Type: DEFAULT; Schema: public; Owner: -
--
-ALTER TABLE ONLY remember_me ALTER COLUMN id SET DEFAULT nextval('remember_me_id_seq'::regclass);
+ALTER TABLE ONLY "remember_me" ALTER COLUMN "id" SET DEFAULT "nextval"('"remember_me_id_seq"'::"regclass");
--
-- Name: id; Type: DEFAULT; Schema: public; Owner: -
--
-ALTER TABLE ONLY subtask_time_tracking ALTER COLUMN id SET DEFAULT nextval('subtask_time_tracking_id_seq'::regclass);
+ALTER TABLE ONLY "subtask_time_tracking" ALTER COLUMN "id" SET DEFAULT "nextval"('"subtask_time_tracking_id_seq"'::"regclass");
--
-- Name: id; Type: DEFAULT; Schema: public; Owner: -
--
-ALTER TABLE ONLY subtasks ALTER COLUMN id SET DEFAULT nextval('task_has_subtasks_id_seq'::regclass);
+ALTER TABLE ONLY "subtasks" ALTER COLUMN "id" SET DEFAULT "nextval"('"task_has_subtasks_id_seq"'::"regclass");
--
-- Name: id; Type: DEFAULT; Schema: public; Owner: -
--
-ALTER TABLE ONLY swimlanes ALTER COLUMN id SET DEFAULT nextval('swimlanes_id_seq'::regclass);
+ALTER TABLE ONLY "swimlanes" ALTER COLUMN "id" SET DEFAULT "nextval"('"swimlanes_id_seq"'::"regclass");
--
-- Name: id; Type: DEFAULT; Schema: public; Owner: -
--
-ALTER TABLE ONLY task_has_external_links ALTER COLUMN id SET DEFAULT nextval('task_has_external_links_id_seq'::regclass);
+ALTER TABLE ONLY "task_has_external_links" ALTER COLUMN "id" SET DEFAULT "nextval"('"task_has_external_links_id_seq"'::"regclass");
--
-- Name: id; Type: DEFAULT; Schema: public; Owner: -
--
-ALTER TABLE ONLY task_has_files ALTER COLUMN id SET DEFAULT nextval('task_has_files_id_seq'::regclass);
+ALTER TABLE ONLY "task_has_files" ALTER COLUMN "id" SET DEFAULT "nextval"('"task_has_files_id_seq"'::"regclass");
--
-- Name: id; Type: DEFAULT; Schema: public; Owner: -
--
-ALTER TABLE ONLY task_has_links ALTER COLUMN id SET DEFAULT nextval('task_has_links_id_seq'::regclass);
+ALTER TABLE ONLY "task_has_links" ALTER COLUMN "id" SET DEFAULT "nextval"('"task_has_links_id_seq"'::"regclass");
--
-- Name: id; Type: DEFAULT; Schema: public; Owner: -
--
-ALTER TABLE ONLY tasks ALTER COLUMN id SET DEFAULT nextval('tasks_id_seq'::regclass);
+ALTER TABLE ONLY "tasks" ALTER COLUMN "id" SET DEFAULT "nextval"('"tasks_id_seq"'::"regclass");
--
-- Name: id; Type: DEFAULT; Schema: public; Owner: -
--
-ALTER TABLE ONLY transitions ALTER COLUMN id SET DEFAULT nextval('transitions_id_seq'::regclass);
+ALTER TABLE ONLY "transitions" ALTER COLUMN "id" SET DEFAULT "nextval"('"transitions_id_seq"'::"regclass");
--
-- Name: id; Type: DEFAULT; Schema: public; Owner: -
--
-ALTER TABLE ONLY user_has_notification_types ALTER COLUMN id SET DEFAULT nextval('user_has_notification_types_id_seq'::regclass);
+ALTER TABLE ONLY "user_has_notification_types" ALTER COLUMN "id" SET DEFAULT "nextval"('"user_has_notification_types_id_seq"'::"regclass");
--
-- Name: id; Type: DEFAULT; Schema: public; Owner: -
--
-ALTER TABLE ONLY user_has_unread_notifications ALTER COLUMN id SET DEFAULT nextval('user_has_unread_notifications_id_seq'::regclass);
+ALTER TABLE ONLY "user_has_unread_notifications" ALTER COLUMN "id" SET DEFAULT "nextval"('"user_has_unread_notifications_id_seq"'::"regclass");
--
-- Name: id; Type: DEFAULT; Schema: public; Owner: -
--
-ALTER TABLE ONLY users ALTER COLUMN id SET DEFAULT nextval('users_id_seq'::regclass);
+ALTER TABLE ONLY "users" ALTER COLUMN "id" SET DEFAULT "nextval"('"users_id_seq"'::"regclass");
--
--- Name: action_has_params_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace:
+-- Name: action_has_params_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
-ALTER TABLE ONLY action_has_params
- ADD CONSTRAINT action_has_params_pkey PRIMARY KEY (id);
+ALTER TABLE ONLY "action_has_params"
+ ADD CONSTRAINT "action_has_params_pkey" PRIMARY KEY ("id");
--
--- Name: actions_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace:
+-- Name: actions_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
-ALTER TABLE ONLY actions
- ADD CONSTRAINT actions_pkey PRIMARY KEY (id);
+ALTER TABLE ONLY "actions"
+ ADD CONSTRAINT "actions_pkey" PRIMARY KEY ("id");
--
--- Name: columns_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace:
+-- Name: columns_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
-ALTER TABLE ONLY columns
- ADD CONSTRAINT columns_pkey PRIMARY KEY (id);
+ALTER TABLE ONLY "columns"
+ ADD CONSTRAINT "columns_pkey" PRIMARY KEY ("id");
--
--- Name: columns_title_project_id_key; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace:
+-- Name: columns_title_project_id_key; Type: CONSTRAINT; Schema: public; Owner: -
--
-ALTER TABLE ONLY columns
- ADD CONSTRAINT columns_title_project_id_key UNIQUE (title, project_id);
+ALTER TABLE ONLY "columns"
+ ADD CONSTRAINT "columns_title_project_id_key" UNIQUE ("title", "project_id");
--
--- Name: comments_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace:
+-- Name: comments_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
-ALTER TABLE ONLY comments
- ADD CONSTRAINT comments_pkey PRIMARY KEY (id);
+ALTER TABLE ONLY "comments"
+ ADD CONSTRAINT "comments_pkey" PRIMARY KEY ("id");
--
--- Name: currencies_currency_key; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace:
+-- Name: currencies_currency_key; Type: CONSTRAINT; Schema: public; Owner: -
--
-ALTER TABLE ONLY currencies
- ADD CONSTRAINT currencies_currency_key UNIQUE (currency);
+ALTER TABLE ONLY "currencies"
+ ADD CONSTRAINT "currencies_currency_key" UNIQUE ("currency");
--
--- Name: custom_filters_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace:
+-- Name: custom_filters_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
-ALTER TABLE ONLY custom_filters
- ADD CONSTRAINT custom_filters_pkey PRIMARY KEY (id);
+ALTER TABLE ONLY "custom_filters"
+ ADD CONSTRAINT "custom_filters_pkey" PRIMARY KEY ("id");
--
--- Name: group_has_users_group_id_user_id_key; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace:
+-- Name: group_has_users_group_id_user_id_key; Type: CONSTRAINT; Schema: public; Owner: -
--
-ALTER TABLE ONLY group_has_users
- ADD CONSTRAINT group_has_users_group_id_user_id_key UNIQUE (group_id, user_id);
+ALTER TABLE ONLY "group_has_users"
+ ADD CONSTRAINT "group_has_users_group_id_user_id_key" UNIQUE ("group_id", "user_id");
--
--- Name: groups_name_key; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace:
+-- Name: groups_name_key; Type: CONSTRAINT; Schema: public; Owner: -
--
-ALTER TABLE ONLY groups
- ADD CONSTRAINT groups_name_key UNIQUE (name);
+ALTER TABLE ONLY "groups"
+ ADD CONSTRAINT "groups_name_key" UNIQUE ("name");
--
--- Name: groups_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace:
+-- Name: groups_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
-ALTER TABLE ONLY groups
- ADD CONSTRAINT groups_pkey PRIMARY KEY (id);
+ALTER TABLE ONLY "groups"
+ ADD CONSTRAINT "groups_pkey" PRIMARY KEY ("id");
--
--- Name: last_logins_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace:
+-- Name: last_logins_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
-ALTER TABLE ONLY last_logins
- ADD CONSTRAINT last_logins_pkey PRIMARY KEY (id);
+ALTER TABLE ONLY "last_logins"
+ ADD CONSTRAINT "last_logins_pkey" PRIMARY KEY ("id");
--
--- Name: links_label_key; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace:
+-- Name: links_label_key; Type: CONSTRAINT; Schema: public; Owner: -
--
-ALTER TABLE ONLY links
- ADD CONSTRAINT links_label_key UNIQUE (label);
+ALTER TABLE ONLY "links"
+ ADD CONSTRAINT "links_label_key" UNIQUE ("label");
--
--- Name: links_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace:
+-- Name: links_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
-ALTER TABLE ONLY links
- ADD CONSTRAINT links_pkey PRIMARY KEY (id);
+ALTER TABLE ONLY "links"
+ ADD CONSTRAINT "links_pkey" PRIMARY KEY ("id");
--
--- Name: password_reset_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace:
+-- Name: password_reset_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
-ALTER TABLE ONLY password_reset
- ADD CONSTRAINT password_reset_pkey PRIMARY KEY (token);
+ALTER TABLE ONLY "password_reset"
+ ADD CONSTRAINT "password_reset_pkey" PRIMARY KEY ("token");
--
--- Name: plugin_schema_versions_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace:
+-- Name: plugin_schema_versions_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
-ALTER TABLE ONLY plugin_schema_versions
- ADD CONSTRAINT plugin_schema_versions_pkey PRIMARY KEY (plugin);
+ALTER TABLE ONLY "plugin_schema_versions"
+ ADD CONSTRAINT "plugin_schema_versions_pkey" PRIMARY KEY ("plugin");
--
--- Name: project_activities_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace:
+-- Name: project_activities_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
-ALTER TABLE ONLY project_activities
- ADD CONSTRAINT project_activities_pkey PRIMARY KEY (id);
+ALTER TABLE ONLY "project_activities"
+ ADD CONSTRAINT "project_activities_pkey" PRIMARY KEY ("id");
--
--- Name: project_daily_stats_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace:
+-- Name: project_daily_stats_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
-ALTER TABLE ONLY project_daily_stats
- ADD CONSTRAINT project_daily_stats_pkey PRIMARY KEY (id);
+ALTER TABLE ONLY "project_daily_stats"
+ ADD CONSTRAINT "project_daily_stats_pkey" PRIMARY KEY ("id");
--
--- Name: project_daily_summaries_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace:
+-- Name: project_daily_summaries_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
-ALTER TABLE ONLY project_daily_column_stats
- ADD CONSTRAINT project_daily_summaries_pkey PRIMARY KEY (id);
+ALTER TABLE ONLY "project_daily_column_stats"
+ ADD CONSTRAINT "project_daily_summaries_pkey" PRIMARY KEY ("id");
--
--- Name: project_has_categories_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace:
+-- Name: project_has_categories_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
-ALTER TABLE ONLY project_has_categories
- ADD CONSTRAINT project_has_categories_pkey PRIMARY KEY (id);
+ALTER TABLE ONLY "project_has_categories"
+ ADD CONSTRAINT "project_has_categories_pkey" PRIMARY KEY ("id");
--
--- Name: project_has_categories_project_id_name_key; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace:
+-- Name: project_has_categories_project_id_name_key; Type: CONSTRAINT; Schema: public; Owner: -
--
-ALTER TABLE ONLY project_has_categories
- ADD CONSTRAINT project_has_categories_project_id_name_key UNIQUE (project_id, name);
+ALTER TABLE ONLY "project_has_categories"
+ ADD CONSTRAINT "project_has_categories_project_id_name_key" UNIQUE ("project_id", "name");
--
--- Name: project_has_files_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace:
+-- Name: project_has_files_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
-ALTER TABLE ONLY project_has_files
- ADD CONSTRAINT project_has_files_pkey PRIMARY KEY (id);
+ALTER TABLE ONLY "project_has_files"
+ ADD CONSTRAINT "project_has_files_pkey" PRIMARY KEY ("id");
--
--- Name: project_has_groups_group_id_project_id_key; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace:
+-- Name: project_has_groups_group_id_project_id_key; Type: CONSTRAINT; Schema: public; Owner: -
--
-ALTER TABLE ONLY project_has_groups
- ADD CONSTRAINT project_has_groups_group_id_project_id_key UNIQUE (group_id, project_id);
+ALTER TABLE ONLY "project_has_groups"
+ ADD CONSTRAINT "project_has_groups_group_id_project_id_key" UNIQUE ("group_id", "project_id");
--
--- Name: project_has_metadata_project_id_name_key; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace:
+-- Name: project_has_metadata_project_id_name_key; Type: CONSTRAINT; Schema: public; Owner: -
--
-ALTER TABLE ONLY project_has_metadata
- ADD CONSTRAINT project_has_metadata_project_id_name_key UNIQUE (project_id, name);
+ALTER TABLE ONLY "project_has_metadata"
+ ADD CONSTRAINT "project_has_metadata_project_id_name_key" UNIQUE ("project_id", "name");
--
--- Name: project_has_notification_types_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace:
+-- Name: project_has_notification_types_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
-ALTER TABLE ONLY project_has_notification_types
- ADD CONSTRAINT project_has_notification_types_pkey PRIMARY KEY (id);
+ALTER TABLE ONLY "project_has_notification_types"
+ ADD CONSTRAINT "project_has_notification_types_pkey" PRIMARY KEY ("id");
--
--- Name: project_has_notification_types_project_id_notification_type_key; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace:
+-- Name: project_has_notification_types_project_id_notification_type_key; Type: CONSTRAINT; Schema: public; Owner: -
--
-ALTER TABLE ONLY project_has_notification_types
- ADD CONSTRAINT project_has_notification_types_project_id_notification_type_key UNIQUE (project_id, notification_type);
+ALTER TABLE ONLY "project_has_notification_types"
+ ADD CONSTRAINT "project_has_notification_types_project_id_notification_type_key" UNIQUE ("project_id", "notification_type");
--
--- Name: project_has_users_project_id_user_id_key; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace:
+-- Name: project_has_users_project_id_user_id_key; Type: CONSTRAINT; Schema: public; Owner: -
--
-ALTER TABLE ONLY project_has_users
- ADD CONSTRAINT project_has_users_project_id_user_id_key UNIQUE (project_id, user_id);
+ALTER TABLE ONLY "project_has_users"
+ ADD CONSTRAINT "project_has_users_project_id_user_id_key" UNIQUE ("project_id", "user_id");
--
--- Name: projects_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace:
+-- Name: projects_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
-ALTER TABLE ONLY projects
- ADD CONSTRAINT projects_pkey PRIMARY KEY (id);
+ALTER TABLE ONLY "projects"
+ ADD CONSTRAINT "projects_pkey" PRIMARY KEY ("id");
--
--- Name: remember_me_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace:
+-- Name: remember_me_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
-ALTER TABLE ONLY remember_me
- ADD CONSTRAINT remember_me_pkey PRIMARY KEY (id);
+ALTER TABLE ONLY "remember_me"
+ ADD CONSTRAINT "remember_me_pkey" PRIMARY KEY ("id");
--
--- Name: settings_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace:
+-- Name: settings_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
-ALTER TABLE ONLY settings
- ADD CONSTRAINT settings_pkey PRIMARY KEY (option);
+ALTER TABLE ONLY "settings"
+ ADD CONSTRAINT "settings_pkey" PRIMARY KEY ("option");
--
--- Name: subtask_time_tracking_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace:
+-- Name: subtask_time_tracking_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
-ALTER TABLE ONLY subtask_time_tracking
- ADD CONSTRAINT subtask_time_tracking_pkey PRIMARY KEY (id);
+ALTER TABLE ONLY "subtask_time_tracking"
+ ADD CONSTRAINT "subtask_time_tracking_pkey" PRIMARY KEY ("id");
--
--- Name: swimlanes_name_project_id_key; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace:
+-- Name: swimlanes_name_project_id_key; Type: CONSTRAINT; Schema: public; Owner: -
--
-ALTER TABLE ONLY swimlanes
- ADD CONSTRAINT swimlanes_name_project_id_key UNIQUE (name, project_id);
+ALTER TABLE ONLY "swimlanes"
+ ADD CONSTRAINT "swimlanes_name_project_id_key" UNIQUE ("name", "project_id");
--
--- Name: swimlanes_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace:
+-- Name: swimlanes_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
-ALTER TABLE ONLY swimlanes
- ADD CONSTRAINT swimlanes_pkey PRIMARY KEY (id);
+ALTER TABLE ONLY "swimlanes"
+ ADD CONSTRAINT "swimlanes_pkey" PRIMARY KEY ("id");
--
--- Name: task_has_external_links_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace:
+-- Name: task_has_external_links_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
-ALTER TABLE ONLY task_has_external_links
- ADD CONSTRAINT task_has_external_links_pkey PRIMARY KEY (id);
+ALTER TABLE ONLY "task_has_external_links"
+ ADD CONSTRAINT "task_has_external_links_pkey" PRIMARY KEY ("id");
--
--- Name: task_has_files_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace:
+-- Name: task_has_files_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
-ALTER TABLE ONLY task_has_files
- ADD CONSTRAINT task_has_files_pkey PRIMARY KEY (id);
+ALTER TABLE ONLY "task_has_files"
+ ADD CONSTRAINT "task_has_files_pkey" PRIMARY KEY ("id");
--
--- Name: task_has_links_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace:
+-- Name: task_has_links_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
-ALTER TABLE ONLY task_has_links
- ADD CONSTRAINT task_has_links_pkey PRIMARY KEY (id);
+ALTER TABLE ONLY "task_has_links"
+ ADD CONSTRAINT "task_has_links_pkey" PRIMARY KEY ("id");
--
--- Name: task_has_metadata_task_id_name_key; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace:
+-- Name: task_has_metadata_task_id_name_key; Type: CONSTRAINT; Schema: public; Owner: -
--
-ALTER TABLE ONLY task_has_metadata
- ADD CONSTRAINT task_has_metadata_task_id_name_key UNIQUE (task_id, name);
+ALTER TABLE ONLY "task_has_metadata"
+ ADD CONSTRAINT "task_has_metadata_task_id_name_key" UNIQUE ("task_id", "name");
--
--- Name: task_has_subtasks_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace:
+-- Name: task_has_subtasks_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
-ALTER TABLE ONLY subtasks
- ADD CONSTRAINT task_has_subtasks_pkey PRIMARY KEY (id);
+ALTER TABLE ONLY "subtasks"
+ ADD CONSTRAINT "task_has_subtasks_pkey" PRIMARY KEY ("id");
--
--- Name: tasks_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace:
+-- Name: tasks_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
-ALTER TABLE ONLY tasks
- ADD CONSTRAINT tasks_pkey PRIMARY KEY (id);
+ALTER TABLE ONLY "tasks"
+ ADD CONSTRAINT "tasks_pkey" PRIMARY KEY ("id");
--
--- Name: transitions_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace:
+-- Name: transitions_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
-ALTER TABLE ONLY transitions
- ADD CONSTRAINT transitions_pkey PRIMARY KEY (id);
+ALTER TABLE ONLY "transitions"
+ ADD CONSTRAINT "transitions_pkey" PRIMARY KEY ("id");
--
--- Name: user_has_metadata_user_id_name_key; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace:
+-- Name: user_has_metadata_user_id_name_key; Type: CONSTRAINT; Schema: public; Owner: -
--
-ALTER TABLE ONLY user_has_metadata
- ADD CONSTRAINT user_has_metadata_user_id_name_key UNIQUE (user_id, name);
+ALTER TABLE ONLY "user_has_metadata"
+ ADD CONSTRAINT "user_has_metadata_user_id_name_key" UNIQUE ("user_id", "name");
--
--- Name: user_has_notification_types_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace:
+-- Name: user_has_notification_types_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
-ALTER TABLE ONLY user_has_notification_types
- ADD CONSTRAINT user_has_notification_types_pkey PRIMARY KEY (id);
+ALTER TABLE ONLY "user_has_notification_types"
+ ADD CONSTRAINT "user_has_notification_types_pkey" PRIMARY KEY ("id");
--
--- Name: user_has_notifications_project_id_user_id_key; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace:
+-- Name: user_has_notifications_project_id_user_id_key; Type: CONSTRAINT; Schema: public; Owner: -
--
-ALTER TABLE ONLY user_has_notifications
- ADD CONSTRAINT user_has_notifications_project_id_user_id_key UNIQUE (project_id, user_id);
+ALTER TABLE ONLY "user_has_notifications"
+ ADD CONSTRAINT "user_has_notifications_project_id_user_id_key" UNIQUE ("project_id", "user_id");
--
--- Name: user_has_unread_notifications_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace:
+-- Name: user_has_unread_notifications_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
-ALTER TABLE ONLY user_has_unread_notifications
- ADD CONSTRAINT user_has_unread_notifications_pkey PRIMARY KEY (id);
+ALTER TABLE ONLY "user_has_unread_notifications"
+ ADD CONSTRAINT "user_has_unread_notifications_pkey" PRIMARY KEY ("id");
--
--- Name: users_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace:
+-- Name: users_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
-ALTER TABLE ONLY users
- ADD CONSTRAINT users_pkey PRIMARY KEY (id);
+ALTER TABLE ONLY "users"
+ ADD CONSTRAINT "users_pkey" PRIMARY KEY ("id");
--
--- Name: categories_project_idx; Type: INDEX; Schema: public; Owner: -; Tablespace:
+-- Name: categories_project_idx; Type: INDEX; Schema: public; Owner: -
--
-CREATE INDEX categories_project_idx ON project_has_categories USING btree (project_id);
+CREATE INDEX "categories_project_idx" ON "project_has_categories" USING "btree" ("project_id");
--
--- Name: columns_project_idx; Type: INDEX; Schema: public; Owner: -; Tablespace:
+-- Name: columns_project_idx; Type: INDEX; Schema: public; Owner: -
--
-CREATE INDEX columns_project_idx ON columns USING btree (project_id);
+CREATE INDEX "columns_project_idx" ON "columns" USING "btree" ("project_id");
--
--- Name: comments_reference_idx; Type: INDEX; Schema: public; Owner: -; Tablespace:
+-- Name: comments_reference_idx; Type: INDEX; Schema: public; Owner: -
--
-CREATE INDEX comments_reference_idx ON comments USING btree (reference);
+CREATE INDEX "comments_reference_idx" ON "comments" USING "btree" ("reference");
--
--- Name: comments_task_idx; Type: INDEX; Schema: public; Owner: -; Tablespace:
+-- Name: comments_task_idx; Type: INDEX; Schema: public; Owner: -
--
-CREATE INDEX comments_task_idx ON comments USING btree (task_id);
+CREATE INDEX "comments_task_idx" ON "comments" USING "btree" ("task_id");
--
--- Name: files_task_idx; Type: INDEX; Schema: public; Owner: -; Tablespace:
+-- Name: files_task_idx; Type: INDEX; Schema: public; Owner: -
--
-CREATE INDEX files_task_idx ON task_has_files USING btree (task_id);
+CREATE INDEX "files_task_idx" ON "task_has_files" USING "btree" ("task_id");
--
--- Name: project_daily_column_stats_idx; Type: INDEX; Schema: public; Owner: -; Tablespace:
+-- Name: project_daily_column_stats_idx; Type: INDEX; Schema: public; Owner: -
--
-CREATE UNIQUE INDEX project_daily_column_stats_idx ON project_daily_column_stats USING btree (day, project_id, column_id);
+CREATE UNIQUE INDEX "project_daily_column_stats_idx" ON "project_daily_column_stats" USING "btree" ("day", "project_id", "column_id");
--
--- Name: project_daily_stats_idx; Type: INDEX; Schema: public; Owner: -; Tablespace:
+-- Name: project_daily_stats_idx; Type: INDEX; Schema: public; Owner: -
--
-CREATE UNIQUE INDEX project_daily_stats_idx ON project_daily_stats USING btree (day, project_id);
+CREATE UNIQUE INDEX "project_daily_stats_idx" ON "project_daily_stats" USING "btree" ("day", "project_id");
--
--- Name: subtasks_task_idx; Type: INDEX; Schema: public; Owner: -; Tablespace:
+-- Name: subtasks_task_idx; Type: INDEX; Schema: public; Owner: -
--
-CREATE INDEX subtasks_task_idx ON subtasks USING btree (task_id);
+CREATE INDEX "subtasks_task_idx" ON "subtasks" USING "btree" ("task_id");
--
--- Name: swimlanes_project_idx; Type: INDEX; Schema: public; Owner: -; Tablespace:
+-- Name: swimlanes_project_idx; Type: INDEX; Schema: public; Owner: -
--
-CREATE INDEX swimlanes_project_idx ON swimlanes USING btree (project_id);
+CREATE INDEX "swimlanes_project_idx" ON "swimlanes" USING "btree" ("project_id");
--
--- Name: task_has_links_task_index; Type: INDEX; Schema: public; Owner: -; Tablespace:
+-- Name: task_has_links_task_index; Type: INDEX; Schema: public; Owner: -
--
-CREATE INDEX task_has_links_task_index ON task_has_links USING btree (task_id);
+CREATE INDEX "task_has_links_task_index" ON "task_has_links" USING "btree" ("task_id");
--
--- Name: task_has_links_unique; Type: INDEX; Schema: public; Owner: -; Tablespace:
+-- Name: task_has_links_unique; Type: INDEX; Schema: public; Owner: -
--
-CREATE UNIQUE INDEX task_has_links_unique ON task_has_links USING btree (link_id, task_id, opposite_task_id);
+CREATE UNIQUE INDEX "task_has_links_unique" ON "task_has_links" USING "btree" ("link_id", "task_id", "opposite_task_id");
--
--- Name: tasks_project_idx; Type: INDEX; Schema: public; Owner: -; Tablespace:
+-- Name: tasks_project_idx; Type: INDEX; Schema: public; Owner: -
--
-CREATE INDEX tasks_project_idx ON tasks USING btree (project_id);
+CREATE INDEX "tasks_project_idx" ON "tasks" USING "btree" ("project_id");
--
--- Name: tasks_reference_idx; Type: INDEX; Schema: public; Owner: -; Tablespace:
+-- Name: tasks_reference_idx; Type: INDEX; Schema: public; Owner: -
--
-CREATE INDEX tasks_reference_idx ON tasks USING btree (reference);
+CREATE INDEX "tasks_reference_idx" ON "tasks" USING "btree" ("reference");
--
--- Name: transitions_project_index; Type: INDEX; Schema: public; Owner: -; Tablespace:
+-- Name: transitions_project_index; Type: INDEX; Schema: public; Owner: -
--
-CREATE INDEX transitions_project_index ON transitions USING btree (project_id);
+CREATE INDEX "transitions_project_index" ON "transitions" USING "btree" ("project_id");
--
--- Name: transitions_task_index; Type: INDEX; Schema: public; Owner: -; Tablespace:
+-- Name: transitions_task_index; Type: INDEX; Schema: public; Owner: -
--
-CREATE INDEX transitions_task_index ON transitions USING btree (task_id);
+CREATE INDEX "transitions_task_index" ON "transitions" USING "btree" ("task_id");
--
--- Name: transitions_user_index; Type: INDEX; Schema: public; Owner: -; Tablespace:
+-- Name: transitions_user_index; Type: INDEX; Schema: public; Owner: -
--
-CREATE INDEX transitions_user_index ON transitions USING btree (user_id);
+CREATE INDEX "transitions_user_index" ON "transitions" USING "btree" ("user_id");
--
--- Name: user_has_notification_types_user_idx; Type: INDEX; Schema: public; Owner: -; Tablespace:
+-- Name: user_has_notification_types_user_idx; Type: INDEX; Schema: public; Owner: -
--
-CREATE UNIQUE INDEX user_has_notification_types_user_idx ON user_has_notification_types USING btree (user_id, notification_type);
+CREATE UNIQUE INDEX "user_has_notification_types_user_idx" ON "user_has_notification_types" USING "btree" ("user_id", "notification_type");
--
--- Name: users_username_idx; Type: INDEX; Schema: public; Owner: -; Tablespace:
+-- Name: users_username_idx; Type: INDEX; Schema: public; Owner: -
--
-CREATE UNIQUE INDEX users_username_idx ON users USING btree (username);
+CREATE UNIQUE INDEX "users_username_idx" ON "users" USING "btree" ("username");
--
-- Name: action_has_params_action_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
-ALTER TABLE ONLY action_has_params
- ADD CONSTRAINT action_has_params_action_id_fkey FOREIGN KEY (action_id) REFERENCES actions(id) ON DELETE CASCADE;
+ALTER TABLE ONLY "action_has_params"
+ ADD CONSTRAINT "action_has_params_action_id_fkey" FOREIGN KEY ("action_id") REFERENCES "actions"("id") ON DELETE CASCADE;
--
-- Name: actions_project_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
-ALTER TABLE ONLY actions
- ADD CONSTRAINT actions_project_id_fkey FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE;
+ALTER TABLE ONLY "actions"
+ ADD CONSTRAINT "actions_project_id_fkey" FOREIGN KEY ("project_id") REFERENCES "projects"("id") ON DELETE CASCADE;
--
-- Name: columns_project_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
-ALTER TABLE ONLY columns
- ADD CONSTRAINT columns_project_id_fkey FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE;
+ALTER TABLE ONLY "columns"
+ ADD CONSTRAINT "columns_project_id_fkey" FOREIGN KEY ("project_id") REFERENCES "projects"("id") ON DELETE CASCADE;
--
-- Name: comments_task_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
-ALTER TABLE ONLY comments
- ADD CONSTRAINT comments_task_id_fkey FOREIGN KEY (task_id) REFERENCES tasks(id) ON DELETE CASCADE;
+ALTER TABLE ONLY "comments"
+ ADD CONSTRAINT "comments_task_id_fkey" FOREIGN KEY ("task_id") REFERENCES "tasks"("id") ON DELETE CASCADE;
--
-- Name: group_has_users_group_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
-ALTER TABLE ONLY group_has_users
- ADD CONSTRAINT group_has_users_group_id_fkey FOREIGN KEY (group_id) REFERENCES groups(id) ON DELETE CASCADE;
+ALTER TABLE ONLY "group_has_users"
+ ADD CONSTRAINT "group_has_users_group_id_fkey" FOREIGN KEY ("group_id") REFERENCES "groups"("id") ON DELETE CASCADE;
--
-- Name: group_has_users_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
-ALTER TABLE ONLY group_has_users
- ADD CONSTRAINT group_has_users_user_id_fkey FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE;
+ALTER TABLE ONLY "group_has_users"
+ ADD CONSTRAINT "group_has_users_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE CASCADE;
--
-- Name: last_logins_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
-ALTER TABLE ONLY last_logins
- ADD CONSTRAINT last_logins_user_id_fkey FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE;
+ALTER TABLE ONLY "last_logins"
+ ADD CONSTRAINT "last_logins_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE CASCADE;
--
-- Name: password_reset_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
-ALTER TABLE ONLY password_reset
- ADD CONSTRAINT password_reset_user_id_fkey FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE;
+ALTER TABLE ONLY "password_reset"
+ ADD CONSTRAINT "password_reset_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE CASCADE;
--
-- Name: project_activities_creator_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
-ALTER TABLE ONLY project_activities
- ADD CONSTRAINT project_activities_creator_id_fkey FOREIGN KEY (creator_id) REFERENCES users(id) ON DELETE CASCADE;
+ALTER TABLE ONLY "project_activities"
+ ADD CONSTRAINT "project_activities_creator_id_fkey" FOREIGN KEY ("creator_id") REFERENCES "users"("id") ON DELETE CASCADE;
--
-- Name: project_activities_project_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
-ALTER TABLE ONLY project_activities
- ADD CONSTRAINT project_activities_project_id_fkey FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE;
+ALTER TABLE ONLY "project_activities"
+ ADD CONSTRAINT "project_activities_project_id_fkey" FOREIGN KEY ("project_id") REFERENCES "projects"("id") ON DELETE CASCADE;
--
-- Name: project_activities_task_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
-ALTER TABLE ONLY project_activities
- ADD CONSTRAINT project_activities_task_id_fkey FOREIGN KEY (task_id) REFERENCES tasks(id) ON DELETE CASCADE;
+ALTER TABLE ONLY "project_activities"
+ ADD CONSTRAINT "project_activities_task_id_fkey" FOREIGN KEY ("task_id") REFERENCES "tasks"("id") ON DELETE CASCADE;
--
-- Name: project_daily_stats_project_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
-ALTER TABLE ONLY project_daily_stats
- ADD CONSTRAINT project_daily_stats_project_id_fkey FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE;
+ALTER TABLE ONLY "project_daily_stats"
+ ADD CONSTRAINT "project_daily_stats_project_id_fkey" FOREIGN KEY ("project_id") REFERENCES "projects"("id") ON DELETE CASCADE;
--
-- Name: project_daily_summaries_column_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
-ALTER TABLE ONLY project_daily_column_stats
- ADD CONSTRAINT project_daily_summaries_column_id_fkey FOREIGN KEY (column_id) REFERENCES columns(id) ON DELETE CASCADE;
+ALTER TABLE ONLY "project_daily_column_stats"
+ ADD CONSTRAINT "project_daily_summaries_column_id_fkey" FOREIGN KEY ("column_id") REFERENCES "columns"("id") ON DELETE CASCADE;
--
-- Name: project_daily_summaries_project_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
-ALTER TABLE ONLY project_daily_column_stats
- ADD CONSTRAINT project_daily_summaries_project_id_fkey FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE;
+ALTER TABLE ONLY "project_daily_column_stats"
+ ADD CONSTRAINT "project_daily_summaries_project_id_fkey" FOREIGN KEY ("project_id") REFERENCES "projects"("id") ON DELETE CASCADE;
--
-- Name: project_has_categories_project_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
-ALTER TABLE ONLY project_has_categories
- ADD CONSTRAINT project_has_categories_project_id_fkey FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE;
+ALTER TABLE ONLY "project_has_categories"
+ ADD CONSTRAINT "project_has_categories_project_id_fkey" FOREIGN KEY ("project_id") REFERENCES "projects"("id") ON DELETE CASCADE;
--
-- Name: project_has_files_project_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
-ALTER TABLE ONLY project_has_files
- ADD CONSTRAINT project_has_files_project_id_fkey FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE;
+ALTER TABLE ONLY "project_has_files"
+ ADD CONSTRAINT "project_has_files_project_id_fkey" FOREIGN KEY ("project_id") REFERENCES "projects"("id") ON DELETE CASCADE;
--
-- Name: project_has_groups_group_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
-ALTER TABLE ONLY project_has_groups
- ADD CONSTRAINT project_has_groups_group_id_fkey FOREIGN KEY (group_id) REFERENCES groups(id) ON DELETE CASCADE;
+ALTER TABLE ONLY "project_has_groups"
+ ADD CONSTRAINT "project_has_groups_group_id_fkey" FOREIGN KEY ("group_id") REFERENCES "groups"("id") ON DELETE CASCADE;
--
-- Name: project_has_groups_project_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
-ALTER TABLE ONLY project_has_groups
- ADD CONSTRAINT project_has_groups_project_id_fkey FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE;
+ALTER TABLE ONLY "project_has_groups"
+ ADD CONSTRAINT "project_has_groups_project_id_fkey" FOREIGN KEY ("project_id") REFERENCES "projects"("id") ON DELETE CASCADE;
--
-- Name: project_has_metadata_project_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
-ALTER TABLE ONLY project_has_metadata
- ADD CONSTRAINT project_has_metadata_project_id_fkey FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE;
+ALTER TABLE ONLY "project_has_metadata"
+ ADD CONSTRAINT "project_has_metadata_project_id_fkey" FOREIGN KEY ("project_id") REFERENCES "projects"("id") ON DELETE CASCADE;
--
-- Name: project_has_notification_types_project_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
-ALTER TABLE ONLY project_has_notification_types
- ADD CONSTRAINT project_has_notification_types_project_id_fkey FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE;
+ALTER TABLE ONLY "project_has_notification_types"
+ ADD CONSTRAINT "project_has_notification_types_project_id_fkey" FOREIGN KEY ("project_id") REFERENCES "projects"("id") ON DELETE CASCADE;
--
-- Name: project_has_users_project_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
-ALTER TABLE ONLY project_has_users
- ADD CONSTRAINT project_has_users_project_id_fkey FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE;
+ALTER TABLE ONLY "project_has_users"
+ ADD CONSTRAINT "project_has_users_project_id_fkey" FOREIGN KEY ("project_id") REFERENCES "projects"("id") ON DELETE CASCADE;
--
-- Name: project_has_users_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
-ALTER TABLE ONLY project_has_users
- ADD CONSTRAINT project_has_users_user_id_fkey FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE;
+ALTER TABLE ONLY "project_has_users"
+ ADD CONSTRAINT "project_has_users_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE CASCADE;
--
-- Name: remember_me_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
-ALTER TABLE ONLY remember_me
- ADD CONSTRAINT remember_me_user_id_fkey FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE;
+ALTER TABLE ONLY "remember_me"
+ ADD CONSTRAINT "remember_me_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE CASCADE;
--
-- Name: subtask_time_tracking_subtask_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
-ALTER TABLE ONLY subtask_time_tracking
- ADD CONSTRAINT subtask_time_tracking_subtask_id_fkey FOREIGN KEY (subtask_id) REFERENCES subtasks(id) ON DELETE CASCADE;
+ALTER TABLE ONLY "subtask_time_tracking"
+ ADD CONSTRAINT "subtask_time_tracking_subtask_id_fkey" FOREIGN KEY ("subtask_id") REFERENCES "subtasks"("id") ON DELETE CASCADE;
--
-- Name: subtask_time_tracking_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
-ALTER TABLE ONLY subtask_time_tracking
- ADD CONSTRAINT subtask_time_tracking_user_id_fkey FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE;
+ALTER TABLE ONLY "subtask_time_tracking"
+ ADD CONSTRAINT "subtask_time_tracking_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE CASCADE;
--
-- Name: swimlanes_project_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
-ALTER TABLE ONLY swimlanes
- ADD CONSTRAINT swimlanes_project_id_fkey FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE;
+ALTER TABLE ONLY "swimlanes"
+ ADD CONSTRAINT "swimlanes_project_id_fkey" FOREIGN KEY ("project_id") REFERENCES "projects"("id") ON DELETE CASCADE;
--
-- Name: task_has_external_links_task_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
-ALTER TABLE ONLY task_has_external_links
- ADD CONSTRAINT task_has_external_links_task_id_fkey FOREIGN KEY (task_id) REFERENCES tasks(id) ON DELETE CASCADE;
+ALTER TABLE ONLY "task_has_external_links"
+ ADD CONSTRAINT "task_has_external_links_task_id_fkey" FOREIGN KEY ("task_id") REFERENCES "tasks"("id") ON DELETE CASCADE;
--
-- Name: task_has_files_task_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
-ALTER TABLE ONLY task_has_files
- ADD CONSTRAINT task_has_files_task_id_fkey FOREIGN KEY (task_id) REFERENCES tasks(id) ON DELETE CASCADE;
+ALTER TABLE ONLY "task_has_files"
+ ADD CONSTRAINT "task_has_files_task_id_fkey" FOREIGN KEY ("task_id") REFERENCES "tasks"("id") ON DELETE CASCADE;
--
-- Name: task_has_links_link_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
-ALTER TABLE ONLY task_has_links
- ADD CONSTRAINT task_has_links_link_id_fkey FOREIGN KEY (link_id) REFERENCES links(id) ON DELETE CASCADE;
+ALTER TABLE ONLY "task_has_links"
+ ADD CONSTRAINT "task_has_links_link_id_fkey" FOREIGN KEY ("link_id") REFERENCES "links"("id") ON DELETE CASCADE;
--
-- Name: task_has_links_opposite_task_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
-ALTER TABLE ONLY task_has_links
- ADD CONSTRAINT task_has_links_opposite_task_id_fkey FOREIGN KEY (opposite_task_id) REFERENCES tasks(id) ON DELETE CASCADE;
+ALTER TABLE ONLY "task_has_links"
+ ADD CONSTRAINT "task_has_links_opposite_task_id_fkey" FOREIGN KEY ("opposite_task_id") REFERENCES "tasks"("id") ON DELETE CASCADE;
--
-- Name: task_has_links_task_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
-ALTER TABLE ONLY task_has_links
- ADD CONSTRAINT task_has_links_task_id_fkey FOREIGN KEY (task_id) REFERENCES tasks(id) ON DELETE CASCADE;
+ALTER TABLE ONLY "task_has_links"
+ ADD CONSTRAINT "task_has_links_task_id_fkey" FOREIGN KEY ("task_id") REFERENCES "tasks"("id") ON DELETE CASCADE;
--
-- Name: task_has_metadata_task_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
-ALTER TABLE ONLY task_has_metadata
- ADD CONSTRAINT task_has_metadata_task_id_fkey FOREIGN KEY (task_id) REFERENCES tasks(id) ON DELETE CASCADE;
+ALTER TABLE ONLY "task_has_metadata"
+ ADD CONSTRAINT "task_has_metadata_task_id_fkey" FOREIGN KEY ("task_id") REFERENCES "tasks"("id") ON DELETE CASCADE;
--
-- Name: task_has_subtasks_task_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
-ALTER TABLE ONLY subtasks
- ADD CONSTRAINT task_has_subtasks_task_id_fkey FOREIGN KEY (task_id) REFERENCES tasks(id) ON DELETE CASCADE;
+ALTER TABLE ONLY "subtasks"
+ ADD CONSTRAINT "task_has_subtasks_task_id_fkey" FOREIGN KEY ("task_id") REFERENCES "tasks"("id") ON DELETE CASCADE;
--
-- Name: tasks_column_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
-ALTER TABLE ONLY tasks
- ADD CONSTRAINT tasks_column_id_fkey FOREIGN KEY (column_id) REFERENCES columns(id) ON DELETE CASCADE;
+ALTER TABLE ONLY "tasks"
+ ADD CONSTRAINT "tasks_column_id_fkey" FOREIGN KEY ("column_id") REFERENCES "columns"("id") ON DELETE CASCADE;
--
-- Name: tasks_project_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
-ALTER TABLE ONLY tasks
- ADD CONSTRAINT tasks_project_id_fkey FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE;
+ALTER TABLE ONLY "tasks"
+ ADD CONSTRAINT "tasks_project_id_fkey" FOREIGN KEY ("project_id") REFERENCES "projects"("id") ON DELETE CASCADE;
--
-- Name: transitions_dst_column_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
-ALTER TABLE ONLY transitions
- ADD CONSTRAINT transitions_dst_column_id_fkey FOREIGN KEY (dst_column_id) REFERENCES columns(id) ON DELETE CASCADE;
+ALTER TABLE ONLY "transitions"
+ ADD CONSTRAINT "transitions_dst_column_id_fkey" FOREIGN KEY ("dst_column_id") REFERENCES "columns"("id") ON DELETE CASCADE;
--
-- Name: transitions_project_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
-ALTER TABLE ONLY transitions
- ADD CONSTRAINT transitions_project_id_fkey FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE;
+ALTER TABLE ONLY "transitions"
+ ADD CONSTRAINT "transitions_project_id_fkey" FOREIGN KEY ("project_id") REFERENCES "projects"("id") ON DELETE CASCADE;
--
-- Name: transitions_src_column_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
-ALTER TABLE ONLY transitions
- ADD CONSTRAINT transitions_src_column_id_fkey FOREIGN KEY (src_column_id) REFERENCES columns(id) ON DELETE CASCADE;
+ALTER TABLE ONLY "transitions"
+ ADD CONSTRAINT "transitions_src_column_id_fkey" FOREIGN KEY ("src_column_id") REFERENCES "columns"("id") ON DELETE CASCADE;
--
-- Name: transitions_task_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
-ALTER TABLE ONLY transitions
- ADD CONSTRAINT transitions_task_id_fkey FOREIGN KEY (task_id) REFERENCES tasks(id) ON DELETE CASCADE;
+ALTER TABLE ONLY "transitions"
+ ADD CONSTRAINT "transitions_task_id_fkey" FOREIGN KEY ("task_id") REFERENCES "tasks"("id") ON DELETE CASCADE;
--
-- Name: transitions_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
-ALTER TABLE ONLY transitions
- ADD CONSTRAINT transitions_user_id_fkey FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE;
+ALTER TABLE ONLY "transitions"
+ ADD CONSTRAINT "transitions_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE CASCADE;
--
-- Name: user_has_metadata_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
-ALTER TABLE ONLY user_has_metadata
- ADD CONSTRAINT user_has_metadata_user_id_fkey FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE;
+ALTER TABLE ONLY "user_has_metadata"
+ ADD CONSTRAINT "user_has_metadata_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE CASCADE;
--
-- Name: user_has_notification_types_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
-ALTER TABLE ONLY user_has_notification_types
- ADD CONSTRAINT user_has_notification_types_user_id_fkey FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE;
+ALTER TABLE ONLY "user_has_notification_types"
+ ADD CONSTRAINT "user_has_notification_types_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE CASCADE;
--
-- Name: user_has_notifications_project_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
-ALTER TABLE ONLY user_has_notifications
- ADD CONSTRAINT user_has_notifications_project_id_fkey FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE;
+ALTER TABLE ONLY "user_has_notifications"
+ ADD CONSTRAINT "user_has_notifications_project_id_fkey" FOREIGN KEY ("project_id") REFERENCES "projects"("id") ON DELETE CASCADE;
--
-- Name: user_has_notifications_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
-ALTER TABLE ONLY user_has_notifications
- ADD CONSTRAINT user_has_notifications_user_id_fkey FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE;
+ALTER TABLE ONLY "user_has_notifications"
+ ADD CONSTRAINT "user_has_notifications_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE CASCADE;
--
-- Name: user_has_unread_notifications_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
-ALTER TABLE ONLY user_has_unread_notifications
- ADD CONSTRAINT user_has_unread_notifications_user_id_fkey FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE;
+ALTER TABLE ONLY "user_has_unread_notifications"
+ ADD CONSTRAINT "user_has_unread_notifications_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE CASCADE;
--
@@ -2137,12 +2134,16 @@ ALTER TABLE ONLY user_has_unread_notifications
-- PostgreSQL database dump
--
+-- Dumped from database version 9.5.2
+-- Dumped by pg_dump version 9.5.2
+
SET statement_timeout = 0;
SET lock_timeout = 0;
SET client_encoding = 'UTF8';
SET standard_conforming_strings = on;
SET check_function_bodies = false;
SET client_min_messages = warning;
+SET row_security = off;
SET search_path = public, pg_catalog;
@@ -2154,8 +2155,8 @@ INSERT INTO settings (option, value, changed_by, changed_on) VALUES ('board_high
INSERT INTO settings (option, value, changed_by, changed_on) VALUES ('board_public_refresh_interval', '60', 0, 0);
INSERT INTO settings (option, value, changed_by, changed_on) VALUES ('board_private_refresh_interval', '10', 0, 0);
INSERT INTO settings (option, value, changed_by, changed_on) VALUES ('board_columns', '', 0, 0);
-INSERT INTO settings (option, value, changed_by, changed_on) VALUES ('webhook_token', '67545fef6a0a3f43d60c7d57632d6e4af9930f064c12e72266b1c9b42381', 0, 0);
-INSERT INTO settings (option, value, changed_by, changed_on) VALUES ('api_token', 'c16b1c5896b258409a5eb344152b5b33c8ef4c58902bc543fc1348c37975', 0, 0);
+INSERT INTO settings (option, value, changed_by, changed_on) VALUES ('webhook_token', '85b9f242e49f4c50176591a2f9b812c626384b89ff985a02068455a5be07', 0, 0);
+INSERT INTO settings (option, value, changed_by, changed_on) VALUES ('api_token', '207d1aaeb9d6d5c01f9ef1e6d61baca86c4c66fdd0b95e76b5c5953681e4', 0, 0);
INSERT INTO settings (option, value, changed_by, changed_on) VALUES ('application_language', 'en_US', 0, 0);
INSERT INTO settings (option, value, changed_by, changed_on) VALUES ('application_timezone', 'UTC', 0, 0);
INSERT INTO settings (option, value, changed_by, changed_on) VALUES ('application_url', '', 0, 0);
@@ -2183,12 +2184,16 @@ INSERT INTO settings (option, value, changed_by, changed_on) VALUES ('password_r
-- PostgreSQL database dump
--
+-- Dumped from database version 9.5.2
+-- Dumped by pg_dump version 9.5.2
+
SET statement_timeout = 0;
SET lock_timeout = 0;
SET client_encoding = 'UTF8';
SET standard_conforming_strings = on;
SET check_function_bodies = false;
SET client_min_messages = warning;
+SET row_security = off;
SET search_path = public, pg_catalog;
@@ -2220,4 +2225,4 @@ SELECT pg_catalog.setval('links_id_seq', 11, true);
-- PostgreSQL database dump complete
--
-INSERT INTO users (username, password, role) VALUES ('admin', '$2y$10$e.SftITKuBvXeNbxtmTKS.KAbIy4Mx09t254BAiEAuWOxkuS4xfLG', 'app-admin');INSERT INTO schema_version VALUES ('89');
+INSERT INTO users (username, password, role) VALUES ('admin', '$2y$10$kliMGeKgDYtx9Igek9jGDu0eZM.KXivgzvqtnMuWMkjvZiIc.8p8S', 'app-admin');INSERT INTO schema_version VALUES ('89');
diff --git a/app/ServiceProvider/ActionProvider.php b/app/ServiceProvider/ActionProvider.php
index 3692f190..34202052 100644
--- a/app/ServiceProvider/ActionProvider.php
+++ b/app/ServiceProvider/ActionProvider.php
@@ -2,6 +2,7 @@
namespace Kanboard\ServiceProvider;
+use Kanboard\Action\TaskAssignColorPriority;
use Pimple\Container;
use Pimple\ServiceProviderInterface;
use Kanboard\Core\Action\ActionManager;
@@ -35,7 +36,7 @@ use Kanboard\Action\TaskCloseNoActivity;
/**
* Action Provider
*
- * @package serviceProvider
+ * @package Kanboard\ServiceProvider
* @author Frederic Guillot
*/
class ActionProvider implements ServiceProviderInterface
@@ -59,6 +60,7 @@ class ActionProvider implements ServiceProviderInterface
$container['actionManager']->register(new TaskAssignColorColumn($container));
$container['actionManager']->register(new TaskAssignColorLink($container));
$container['actionManager']->register(new TaskAssignColorUser($container));
+ $container['actionManager']->register(new TaskAssignColorPriority($container));
$container['actionManager']->register(new TaskAssignCurrentUser($container));
$container['actionManager']->register(new TaskAssignCurrentUserColumn($container));
$container['actionManager']->register(new TaskAssignSpecificUser($container));
diff --git a/app/ServiceProvider/ApiProvider.php b/app/ServiceProvider/ApiProvider.php
new file mode 100644
index 00000000..19d945f6
--- /dev/null
+++ b/app/ServiceProvider/ApiProvider.php
@@ -0,0 +1,74 @@
+<?php
+
+namespace Kanboard\ServiceProvider;
+
+use JsonRPC\Server;
+use Kanboard\Api\ActionApi;
+use Kanboard\Api\AppApi;
+use Kanboard\Api\BoardApi;
+use Kanboard\Api\CategoryApi;
+use Kanboard\Api\ColumnApi;
+use Kanboard\Api\CommentApi;
+use Kanboard\Api\FileApi;
+use Kanboard\Api\GroupApi;
+use Kanboard\Api\GroupMemberApi;
+use Kanboard\Api\LinkApi;
+use Kanboard\Api\MeApi;
+use Kanboard\Api\Middleware\AuthenticationApiMiddleware;
+use Kanboard\Api\ProjectApi;
+use Kanboard\Api\ProjectPermissionApi;
+use Kanboard\Api\SubtaskApi;
+use Kanboard\Api\SwimlaneApi;
+use Kanboard\Api\TaskApi;
+use Kanboard\Api\TaskLinkApi;
+use Kanboard\Api\UserApi;
+use Pimple\Container;
+use Pimple\ServiceProviderInterface;
+
+/**
+ * Class ApiProvider
+ *
+ * @package Kanboard\ServiceProvider
+ * @author Frederic Guillot
+ */
+class ApiProvider implements ServiceProviderInterface
+{
+ /**
+ * Registers services on the given container.
+ *
+ * @param Container $container
+ * @return Container
+ */
+ public function register(Container $container)
+ {
+ $server = new Server();
+ $server->setAuthenticationHeader(API_AUTHENTICATION_HEADER);
+ $server->getMiddlewareHandler()
+ ->withMiddleware(new AuthenticationApiMiddleware($container))
+ ;
+
+ $server->getProcedureHandler()
+ ->withObject(new MeApi($container))
+ ->withObject(new ActionApi($container))
+ ->withObject(new AppApi($container))
+ ->withObject(new BoardApi($container))
+ ->withObject(new ColumnApi($container))
+ ->withObject(new CategoryApi($container))
+ ->withObject(new CommentApi($container))
+ ->withObject(new FileApi($container))
+ ->withObject(new LinkApi($container))
+ ->withObject(new ProjectApi($container))
+ ->withObject(new ProjectPermissionApi($container))
+ ->withObject(new SubtaskApi($container))
+ ->withObject(new SwimlaneApi($container))
+ ->withObject(new TaskApi($container))
+ ->withObject(new TaskLinkApi($container))
+ ->withObject(new UserApi($container))
+ ->withObject(new GroupApi($container))
+ ->withObject(new GroupMemberApi($container))
+ ;
+
+ $container['api'] = $server;
+ return $container;
+ }
+}
diff --git a/app/ServiceProvider/AuthenticationProvider.php b/app/ServiceProvider/AuthenticationProvider.php
index 776e65d5..2fad8a3a 100644
--- a/app/ServiceProvider/AuthenticationProvider.php
+++ b/app/ServiceProvider/AuthenticationProvider.php
@@ -17,7 +17,7 @@ use Kanboard\Auth\ReverseProxyAuth;
/**
* Authentication Provider
*
- * @package serviceProvider
+ * @package Kanboard\ServiceProvider
* @author Frederic Guillot
*/
class AuthenticationProvider implements ServiceProviderInterface
@@ -66,39 +66,43 @@ class AuthenticationProvider implements ServiceProviderInterface
$acl->setRoleHierarchy(Role::PROJECT_MANAGER, array(Role::PROJECT_MEMBER, Role::PROJECT_VIEWER));
$acl->setRoleHierarchy(Role::PROJECT_MEMBER, array(Role::PROJECT_VIEWER));
- $acl->add('Action', '*', Role::PROJECT_MANAGER);
- $acl->add('ActionProject', '*', Role::PROJECT_MANAGER);
- $acl->add('ActionCreation', '*', Role::PROJECT_MANAGER);
- $acl->add('Analytic', '*', Role::PROJECT_MANAGER);
- $acl->add('Board', 'save', Role::PROJECT_MEMBER);
- $acl->add('BoardPopover', '*', Role::PROJECT_MEMBER);
- $acl->add('Calendar', 'save', Role::PROJECT_MEMBER);
- $acl->add('Category', '*', Role::PROJECT_MANAGER);
- $acl->add('Column', '*', Role::PROJECT_MANAGER);
- $acl->add('Comment', '*', Role::PROJECT_MEMBER);
- $acl->add('Customfilter', '*', Role::PROJECT_MEMBER);
- $acl->add('Export', '*', Role::PROJECT_MANAGER);
- $acl->add('TaskFile', array('screenshot', 'create', 'save', 'remove', 'confirm'), Role::PROJECT_MEMBER);
- $acl->add('Gantt', '*', Role::PROJECT_MANAGER);
- $acl->add('Project', array('share', 'integrations', 'notifications', 'duplicate', 'disable', 'enable', 'remove'), Role::PROJECT_MANAGER);
- $acl->add('ProjectPermission', '*', Role::PROJECT_MANAGER);
- $acl->add('ProjectEdit', '*', Role::PROJECT_MANAGER);
- $acl->add('ProjectFile', '*', Role::PROJECT_MEMBER);
- $acl->add('Projectuser', '*', Role::PROJECT_MANAGER);
- $acl->add('Subtask', '*', Role::PROJECT_MEMBER);
- $acl->add('SubtaskRestriction', '*', Role::PROJECT_MEMBER);
- $acl->add('SubtaskStatus', '*', Role::PROJECT_MEMBER);
- $acl->add('Swimlane', '*', Role::PROJECT_MANAGER);
- $acl->add('Task', 'remove', Role::PROJECT_MEMBER);
- $acl->add('Taskcreation', '*', Role::PROJECT_MEMBER);
- $acl->add('Taskduplication', '*', Role::PROJECT_MEMBER);
- $acl->add('TaskRecurrence', '*', Role::PROJECT_MEMBER);
- $acl->add('TaskImport', '*', Role::PROJECT_MANAGER);
- $acl->add('TaskInternalLink', '*', Role::PROJECT_MEMBER);
- $acl->add('TaskExternalLink', '*', Role::PROJECT_MEMBER);
- $acl->add('Taskmodification', '*', Role::PROJECT_MEMBER);
- $acl->add('Taskstatus', '*', Role::PROJECT_MEMBER);
- $acl->add('UserHelper', array('mention'), Role::PROJECT_MEMBER);
+ $acl->add('ActionController', '*', Role::PROJECT_MANAGER);
+ $acl->add('ProjectActionDuplicationController', '*', Role::PROJECT_MANAGER);
+ $acl->add('ActionCreationController', '*', Role::PROJECT_MANAGER);
+ $acl->add('AnalyticController', '*', Role::PROJECT_MANAGER);
+ $acl->add('BoardAjaxController', 'save', Role::PROJECT_MEMBER);
+ $acl->add('BoardPopoverController', '*', Role::PROJECT_MEMBER);
+ $acl->add('TaskPopoverController', '*', Role::PROJECT_MEMBER);
+ $acl->add('CalendarController', 'save', Role::PROJECT_MEMBER);
+ $acl->add('CategoryController', '*', Role::PROJECT_MANAGER);
+ $acl->add('ColumnController', '*', Role::PROJECT_MANAGER);
+ $acl->add('CommentController', '*', Role::PROJECT_MEMBER);
+ $acl->add('CustomFilterController', '*', Role::PROJECT_MEMBER);
+ $acl->add('ExportController', '*', Role::PROJECT_MANAGER);
+ $acl->add('TaskFileController', array('screenshot', 'create', 'save', 'remove', 'confirm'), Role::PROJECT_MEMBER);
+ $acl->add('TaskGanttController', '*', Role::PROJECT_MANAGER);
+ $acl->add('TaskGanttCreationController', '*', Role::PROJECT_MANAGER);
+ $acl->add('ProjectViewController', array('share', 'updateSharing', 'integrations', 'updateIntegrations', 'notifications', 'updateNotifications', 'duplicate', 'doDuplication'), Role::PROJECT_MANAGER);
+ $acl->add('ProjectPermissionController', '*', Role::PROJECT_MANAGER);
+ $acl->add('ProjectEditController', '*', Role::PROJECT_MANAGER);
+ $acl->add('ProjectFileController', '*', Role::PROJECT_MEMBER);
+ $acl->add('ProjectUserOverviewController', '*', Role::PROJECT_MANAGER);
+ $acl->add('ProjectStatusController', '*', Role::PROJECT_MANAGER);
+ $acl->add('SubtaskController', '*', Role::PROJECT_MEMBER);
+ $acl->add('SubtaskRestrictionController', '*', Role::PROJECT_MEMBER);
+ $acl->add('SubtaskStatusController', '*', Role::PROJECT_MEMBER);
+ $acl->add('SwimlaneController', '*', Role::PROJECT_MANAGER);
+ $acl->add('TaskSuppressionController', '*', Role::PROJECT_MEMBER);
+ $acl->add('TaskCreationController', '*', Role::PROJECT_MEMBER);
+ $acl->add('TaskBulkController', '*', Role::PROJECT_MEMBER);
+ $acl->add('TaskDuplicationController', '*', Role::PROJECT_MEMBER);
+ $acl->add('TaskRecurrenceController', '*', Role::PROJECT_MEMBER);
+ $acl->add('TaskImportController', '*', Role::PROJECT_MANAGER);
+ $acl->add('TaskInternalLinkController', '*', Role::PROJECT_MEMBER);
+ $acl->add('TaskExternalLinkController', '*', Role::PROJECT_MEMBER);
+ $acl->add('TaskModificationController', '*', Role::PROJECT_MEMBER);
+ $acl->add('TaskStatusController', '*', Role::PROJECT_MEMBER);
+ $acl->add('UserAjaxController', array('mention'), Role::PROJECT_MEMBER);
return $acl;
}
@@ -117,27 +121,31 @@ class AuthenticationProvider implements ServiceProviderInterface
$acl->setRoleHierarchy(Role::APP_MANAGER, array(Role::APP_USER, Role::APP_PUBLIC));
$acl->setRoleHierarchy(Role::APP_USER, array(Role::APP_PUBLIC));
- $acl->add('Auth', array('login', 'check'), Role::APP_PUBLIC);
- $acl->add('Captcha', '*', Role::APP_PUBLIC);
- $acl->add('PasswordReset', '*', Role::APP_PUBLIC);
- $acl->add('Webhook', '*', Role::APP_PUBLIC);
- $acl->add('Task', 'readonly', Role::APP_PUBLIC);
- $acl->add('Board', 'readonly', Role::APP_PUBLIC);
- $acl->add('Ical', '*', Role::APP_PUBLIC);
- $acl->add('Feed', '*', Role::APP_PUBLIC);
- $acl->add('AvatarFile', 'show', Role::APP_PUBLIC);
+ $acl->add('AuthController', array('login', 'check'), Role::APP_PUBLIC);
+ $acl->add('CaptchaController', '*', Role::APP_PUBLIC);
+ $acl->add('PasswordResetController', '*', Role::APP_PUBLIC);
+ $acl->add('TaskViewController', 'readonly', Role::APP_PUBLIC);
+ $acl->add('BoardViewController', 'readonly', Role::APP_PUBLIC);
+ $acl->add('ICalendarController', '*', Role::APP_PUBLIC);
+ $acl->add('FeedController', '*', Role::APP_PUBLIC);
+ $acl->add('AvatarFileController', 'show', Role::APP_PUBLIC);
- $acl->add('Config', '*', Role::APP_ADMIN);
- $acl->add('Currency', '*', Role::APP_ADMIN);
- $acl->add('Gantt', array('projects', 'saveProjectDate'), Role::APP_MANAGER);
- $acl->add('Group', '*', Role::APP_ADMIN);
- $acl->add('Link', '*', Role::APP_ADMIN);
- $acl->add('ProjectCreation', 'create', Role::APP_MANAGER);
- $acl->add('Projectuser', '*', Role::APP_MANAGER);
- $acl->add('Twofactor', 'disable', Role::APP_ADMIN);
- $acl->add('UserImport', '*', Role::APP_ADMIN);
- $acl->add('User', array('index', 'create', 'save', 'authentication'), Role::APP_ADMIN);
- $acl->add('UserStatus', '*', Role::APP_ADMIN);
+ $acl->add('ConfigController', '*', Role::APP_ADMIN);
+ $acl->add('PluginController', '*', Role::APP_ADMIN);
+ $acl->add('CurrencyController', '*', Role::APP_ADMIN);
+ $acl->add('ProjectGanttController', '*', Role::APP_MANAGER);
+ $acl->add('GroupListController', '*', Role::APP_ADMIN);
+ $acl->add('GroupCreationController', '*', Role::APP_ADMIN);
+ $acl->add('GroupModificationController', '*', Role::APP_ADMIN);
+ $acl->add('LinkController', '*', Role::APP_ADMIN);
+ $acl->add('ProjectCreationController', 'create', Role::APP_MANAGER);
+ $acl->add('ProjectUserOverviewController', '*', Role::APP_MANAGER);
+ $acl->add('TwoFactorController', 'disable', Role::APP_ADMIN);
+ $acl->add('UserImportController', '*', Role::APP_ADMIN);
+ $acl->add('UserCreationController', '*', Role::APP_ADMIN);
+ $acl->add('UserListController', '*', Role::APP_ADMIN);
+ $acl->add('UserStatusController', '*', Role::APP_ADMIN);
+ $acl->add('UserCredentialController', array('changeAuthentication', 'saveAuthentication'), Role::APP_ADMIN);
return $acl;
}
diff --git a/app/ServiceProvider/AvatarProvider.php b/app/ServiceProvider/AvatarProvider.php
index aac4fcab..d17985ed 100644
--- a/app/ServiceProvider/AvatarProvider.php
+++ b/app/ServiceProvider/AvatarProvider.php
@@ -12,7 +12,7 @@ use Kanboard\User\Avatar\LetterAvatarProvider;
/**
* Avatar Provider
*
- * @package serviceProvider
+ * @package Kanboard\ServiceProvider
* @author Frederic Guillot
*/
class AvatarProvider implements ServiceProviderInterface
diff --git a/app/ServiceProvider/ClassProvider.php b/app/ServiceProvider/ClassProvider.php
index 18c1d578..3e6efb02 100644
--- a/app/ServiceProvider/ClassProvider.php
+++ b/app/ServiceProvider/ClassProvider.php
@@ -4,13 +4,18 @@ namespace Kanboard\ServiceProvider;
use Pimple\Container;
use Pimple\ServiceProviderInterface;
-use Kanboard\Core\Mail\Client as EmailClient;
use Kanboard\Core\ObjectStorage\FileStorage;
use Kanboard\Core\Paginator;
use Kanboard\Core\Http\OAuth2;
use Kanboard\Core\Tool;
use Kanboard\Core\Http\Client as HttpClient;
+/**
+ * Class ClassProvider
+ *
+ * @package Kanboard\ServiceProvider
+ * @author Frederic Guillot
+ */
class ClassProvider implements ServiceProviderInterface
{
private $classes = array(
@@ -22,59 +27,60 @@ class ClassProvider implements ServiceProviderInterface
'AverageTimeSpentColumnAnalytic',
),
'Model' => array(
- 'Action',
- 'ActionParameter',
- 'AvatarFile',
- 'Board',
- 'Category',
- 'Color',
- 'Column',
- 'Comment',
- 'Config',
- 'Currency',
- 'CustomFilter',
- 'Group',
- 'GroupMember',
- 'LastLogin',
- 'Link',
- 'Notification',
- 'PasswordReset',
- 'Project',
- 'ProjectFile',
- 'ProjectActivity',
- 'ProjectDuplication',
- 'ProjectDailyColumnStats',
- 'ProjectDailyStats',
- 'ProjectPermission',
- 'ProjectNotification',
- 'ProjectMetadata',
- 'ProjectGroupRole',
- 'ProjectUserRole',
- 'RememberMeSession',
- 'Subtask',
- 'SubtaskTimeTracking',
- 'Swimlane',
- 'Task',
- 'TaskAnalytic',
- 'TaskCreation',
- 'TaskDuplication',
- 'TaskExternalLink',
- 'TaskFinder',
- 'TaskFile',
- 'TaskLink',
- 'TaskModification',
- 'TaskPermission',
- 'TaskPosition',
- 'TaskStatus',
- 'TaskMetadata',
- 'Transition',
- 'User',
- 'UserLocking',
- 'UserMention',
- 'UserNotification',
- 'UserNotificationFilter',
- 'UserUnreadNotification',
- 'UserMetadata',
+ 'ActionModel',
+ 'ActionParameterModel',
+ 'AvatarFileModel',
+ 'BoardModel',
+ 'CategoryModel',
+ 'ColorModel',
+ 'ColumnModel',
+ 'CommentModel',
+ 'ConfigModel',
+ 'CurrencyModel',
+ 'CustomFilterModel',
+ 'GroupModel',
+ 'GroupMemberModel',
+ 'LanguageModel',
+ 'LastLoginModel',
+ 'LinkModel',
+ 'NotificationModel',
+ 'PasswordResetModel',
+ 'ProjectModel',
+ 'ProjectFileModel',
+ 'ProjectActivityModel',
+ 'ProjectDuplicationModel',
+ 'ProjectDailyColumnStatsModel',
+ 'ProjectDailyStatsModel',
+ 'ProjectPermissionModel',
+ 'ProjectNotificationModel',
+ 'ProjectMetadataModel',
+ 'ProjectGroupRoleModel',
+ 'ProjectUserRoleModel',
+ 'RememberMeSessionModel',
+ 'SubtaskModel',
+ 'SubtaskTimeTrackingModel',
+ 'SwimlaneModel',
+ 'TaskModel',
+ 'TaskAnalyticModel',
+ 'TaskCreationModel',
+ 'TaskDuplicationModel',
+ 'TaskExternalLinkModel',
+ 'TaskFinderModel',
+ 'TaskFileModel',
+ 'TaskLinkModel',
+ 'TaskModificationModel',
+ 'TaskPositionModel',
+ 'TaskStatusModel',
+ 'TaskMetadataModel',
+ 'TimezoneModel',
+ 'TransitionModel',
+ 'UserModel',
+ 'UserLockingModel',
+ 'UserMentionModel',
+ 'UserNotificationModel',
+ 'UserNotificationFilterModel',
+ 'UserUnreadNotificationModel',
+ 'UserMetadataModel',
),
'Validator' => array(
'ActionValidator',
@@ -154,14 +160,6 @@ class ClassProvider implements ServiceProviderInterface
return new FileStorage(FILES_DIR);
};
- $container['emailClient'] = function ($container) {
- $mailer = new EmailClient($container);
- $mailer->setTransport('smtp', '\Kanboard\Core\Mail\Transport\Smtp');
- $mailer->setTransport('sendmail', '\Kanboard\Core\Mail\Transport\Sendmail');
- $mailer->setTransport('mail', '\Kanboard\Core\Mail\Transport\Mail');
- return $mailer;
- };
-
$container['cspRules'] = array(
'default-src' => "'self'",
'style-src' => "'self' 'unsafe-inline'",
diff --git a/app/ServiceProvider/CommandProvider.php b/app/ServiceProvider/CommandProvider.php
new file mode 100644
index 00000000..55c2712b
--- /dev/null
+++ b/app/ServiceProvider/CommandProvider.php
@@ -0,0 +1,62 @@
+<?php
+
+namespace Kanboard\ServiceProvider;
+
+use Kanboard\Console\CronjobCommand;
+use Kanboard\Console\LocaleComparatorCommand;
+use Kanboard\Console\LocaleSyncCommand;
+use Kanboard\Console\PluginInstallCommand;
+use Kanboard\Console\PluginUninstallCommand;
+use Kanboard\Console\PluginUpgradeCommand;
+use Kanboard\Console\ProjectDailyColumnStatsExportCommand;
+use Kanboard\Console\ProjectDailyStatsCalculationCommand;
+use Kanboard\Console\ResetPasswordCommand;
+use Kanboard\Console\ResetTwoFactorCommand;
+use Kanboard\Console\SubtaskExportCommand;
+use Kanboard\Console\TaskExportCommand;
+use Kanboard\Console\TaskOverdueNotificationCommand;
+use Kanboard\Console\TaskTriggerCommand;
+use Kanboard\Console\TransitionExportCommand;
+use Kanboard\Console\WorkerCommand;
+use Pimple\Container;
+use Pimple\ServiceProviderInterface;
+use Symfony\Component\Console\Application;
+
+/**
+ * Class CommandProvider
+ *
+ * @package Kanboard\ServiceProvider
+ * @author Frederic Guillot
+ */
+class CommandProvider implements ServiceProviderInterface
+{
+ /**
+ * Registers services on the given container.
+ *
+ * @param Container $container
+ * @return Container
+ */
+ public function register(Container $container)
+ {
+ $application = new Application('Kanboard', APP_VERSION);
+ $application->add(new TaskOverdueNotificationCommand($container));
+ $application->add(new SubtaskExportCommand($container));
+ $application->add(new TaskExportCommand($container));
+ $application->add(new ProjectDailyStatsCalculationCommand($container));
+ $application->add(new ProjectDailyColumnStatsExportCommand($container));
+ $application->add(new TransitionExportCommand($container));
+ $application->add(new LocaleSyncCommand($container));
+ $application->add(new LocaleComparatorCommand($container));
+ $application->add(new TaskTriggerCommand($container));
+ $application->add(new CronjobCommand($container));
+ $application->add(new WorkerCommand($container));
+ $application->add(new ResetPasswordCommand($container));
+ $application->add(new ResetTwoFactorCommand($container));
+ $application->add(new PluginUpgradeCommand($container));
+ $application->add(new PluginInstallCommand($container));
+ $application->add(new PluginUninstallCommand($container));
+
+ $container['cli'] = $application;
+ return $container;
+ }
+}
diff --git a/app/ServiceProvider/DatabaseProvider.php b/app/ServiceProvider/DatabaseProvider.php
index d323807d..a3f57457 100644
--- a/app/ServiceProvider/DatabaseProvider.php
+++ b/app/ServiceProvider/DatabaseProvider.php
@@ -8,13 +8,31 @@ use Pimple\Container;
use Pimple\ServiceProviderInterface;
use PicoDb\Database;
+/**
+ * Class DatabaseProvider
+ *
+ * @package Kanboard\ServiceProvider
+ * @author Frederic Guillot
+ */
class DatabaseProvider implements ServiceProviderInterface
{
+ /**
+ * Register provider
+ *
+ * @access public
+ * @param Container $container
+ * @return Container
+ */
public function register(Container $container)
{
$container['db'] = $this->getInstance();
- $container['db']->stopwatch = DEBUG;
- $container['db']->logQueries = DEBUG;
+
+ if (DEBUG) {
+ $container['db']->getStatementHandler()
+ ->withLogging()
+ ->withStopWatch()
+ ;
+ }
return $container;
}
@@ -83,6 +101,9 @@ class DatabaseProvider implements ServiceProviderInterface
'database' => DB_NAME,
'charset' => 'utf8',
'port' => DB_PORT,
+ 'ssl_key' => DB_SSL_KEY,
+ 'ssl_ca' => DB_SSL_CA,
+ 'ssl_cert' => DB_SSL_CERT,
));
}
diff --git a/app/ServiceProvider/EventDispatcherProvider.php b/app/ServiceProvider/EventDispatcherProvider.php
index 880caa41..57543fe4 100644
--- a/app/ServiceProvider/EventDispatcherProvider.php
+++ b/app/ServiceProvider/EventDispatcherProvider.php
@@ -2,6 +2,7 @@
namespace Kanboard\ServiceProvider;
+use Kanboard\Subscriber\LdapUserPhotoSubscriber;
use Pimple\Container;
use Pimple\ServiceProviderInterface;
use Symfony\Component\EventDispatcher\EventDispatcher;
@@ -14,6 +15,12 @@ use Kanboard\Subscriber\SubtaskTimeTrackingSubscriber;
use Kanboard\Subscriber\TransitionSubscriber;
use Kanboard\Subscriber\RecurringTaskSubscriber;
+/**
+ * Class EventDispatcherProvider
+ *
+ * @package Kanboard\ServiceProvider
+ * @author Frederic Guillot
+ */
class EventDispatcherProvider implements ServiceProviderInterface
{
public function register(Container $container)
@@ -28,6 +35,10 @@ class EventDispatcherProvider implements ServiceProviderInterface
$container['dispatcher']->addSubscriber(new TransitionSubscriber($container));
$container['dispatcher']->addSubscriber(new RecurringTaskSubscriber($container));
+ if (LDAP_AUTH && LDAP_USER_ATTRIBUTE_PHOTO !== '') {
+ $container['dispatcher']->addSubscriber(new LdapUserPhotoSubscriber($container));
+ }
+
return $container;
}
}
diff --git a/app/ServiceProvider/ExternalLinkProvider.php b/app/ServiceProvider/ExternalLinkProvider.php
index 8b71ec81..2cec768d 100644
--- a/app/ServiceProvider/ExternalLinkProvider.php
+++ b/app/ServiceProvider/ExternalLinkProvider.php
@@ -12,7 +12,7 @@ use Kanboard\ExternalLink\FileLinkProvider;
/**
* External Link Provider
*
- * @package serviceProvider
+ * @package Kanboard\ServiceProvider
* @author Frederic Guillot
*/
class ExternalLinkProvider implements ServiceProviderInterface
diff --git a/app/ServiceProvider/FilterProvider.php b/app/ServiceProvider/FilterProvider.php
index f3918d77..cdef9ed8 100644
--- a/app/ServiceProvider/FilterProvider.php
+++ b/app/ServiceProvider/FilterProvider.php
@@ -27,17 +27,17 @@ use Kanboard\Filter\TaskStatusFilter;
use Kanboard\Filter\TaskSubtaskAssigneeFilter;
use Kanboard\Filter\TaskSwimlaneFilter;
use Kanboard\Filter\TaskTitleFilter;
-use Kanboard\Model\Project;
-use Kanboard\Model\ProjectGroupRole;
-use Kanboard\Model\ProjectUserRole;
-use Kanboard\Model\User;
+use Kanboard\Model\ProjectModel;
+use Kanboard\Model\ProjectGroupRoleModel;
+use Kanboard\Model\ProjectUserRoleModel;
+use Kanboard\Model\UserModel;
use Pimple\Container;
use Pimple\ServiceProviderInterface;
/**
* Filter Provider
*
- * @package serviceProvider
+ * @package Kanboard\ServiceProvider
* @author Frederic Guillot
*/
class FilterProvider implements ServiceProviderInterface
@@ -61,7 +61,7 @@ class FilterProvider implements ServiceProviderInterface
{
$container['userQuery'] = $container->factory(function ($c) {
$builder = new QueryBuilder();
- $builder->withQuery($c['db']->table(User::TABLE));
+ $builder->withQuery($c['db']->table(UserModel::TABLE));
return $builder;
});
@@ -72,26 +72,26 @@ class FilterProvider implements ServiceProviderInterface
{
$container['projectGroupRoleQuery'] = $container->factory(function ($c) {
$builder = new QueryBuilder();
- $builder->withQuery($c['db']->table(ProjectGroupRole::TABLE));
+ $builder->withQuery($c['db']->table(ProjectGroupRoleModel::TABLE));
return $builder;
});
$container['projectUserRoleQuery'] = $container->factory(function ($c) {
$builder = new QueryBuilder();
- $builder->withQuery($c['db']->table(ProjectUserRole::TABLE));
+ $builder->withQuery($c['db']->table(ProjectUserRoleModel::TABLE));
return $builder;
});
$container['projectQuery'] = $container->factory(function ($c) {
$builder = new QueryBuilder();
- $builder->withQuery($c['db']->table(Project::TABLE));
+ $builder->withQuery($c['db']->table(ProjectModel::TABLE));
return $builder;
});
$container['projectActivityLexer'] = $container->factory(function ($c) {
$builder = new LexerBuilder();
$builder
- ->withQuery($c['projectActivity']->getQuery())
+ ->withQuery($c['projectActivityModel']->getQuery())
->withFilter(new ProjectActivityTaskTitleFilter(), true)
->withFilter(new ProjectActivityTaskStatusFilter())
->withFilter(new ProjectActivityProjectNameFilter())
@@ -108,7 +108,7 @@ class FilterProvider implements ServiceProviderInterface
$container['projectActivityQuery'] = $container->factory(function ($c) {
$builder = new QueryBuilder();
- $builder->withQuery($c['projectActivity']->getQuery());
+ $builder->withQuery($c['projectActivityModel']->getQuery());
return $builder;
});
@@ -120,7 +120,7 @@ class FilterProvider implements ServiceProviderInterface
{
$container['taskQuery'] = $container->factory(function ($c) {
$builder = new QueryBuilder();
- $builder->withQuery($c['taskFinder']->getExtendedQuery());
+ $builder->withQuery($c['taskFinderModel']->getExtendedQuery());
return $builder;
});
@@ -128,13 +128,13 @@ class FilterProvider implements ServiceProviderInterface
$builder = new LexerBuilder();
$builder
- ->withQuery($c['taskFinder']->getExtendedQuery())
+ ->withQuery($c['taskFinderModel']->getExtendedQuery())
->withFilter(TaskAssigneeFilter::getInstance()
->setCurrentUserId($c['userSession']->getId())
)
->withFilter(new TaskCategoryFilter())
->withFilter(TaskColorFilter::getInstance()
- ->setColorModel($c['color'])
+ ->setColorModel($c['colorModel'])
)
->withFilter(new TaskColumnFilter())
->withFilter(new TaskCommentFilter())
diff --git a/app/ServiceProvider/GroupProvider.php b/app/ServiceProvider/GroupProvider.php
index b222b218..08548c73 100644
--- a/app/ServiceProvider/GroupProvider.php
+++ b/app/ServiceProvider/GroupProvider.php
@@ -11,7 +11,7 @@ use Kanboard\Group\LdapBackendGroupProvider;
/**
* Group Provider
*
- * @package serviceProvider
+ * @package Kanboard\ServiceProvider
* @author Frederic Guillot
*/
class GroupProvider implements ServiceProviderInterface
diff --git a/app/ServiceProvider/HelperProvider.php b/app/ServiceProvider/HelperProvider.php
index bf3956a2..a909e3cf 100644
--- a/app/ServiceProvider/HelperProvider.php
+++ b/app/ServiceProvider/HelperProvider.php
@@ -7,6 +7,12 @@ use Kanboard\Core\Template;
use Pimple\Container;
use Pimple\ServiceProviderInterface;
+/**
+ * Class HelperProvider
+ *
+ * @package Kanboard\ServiceProvider
+ * @author Frederic Guillot
+ */
class HelperProvider implements ServiceProviderInterface
{
public function register(Container $container)
@@ -31,6 +37,7 @@ class HelperProvider implements ServiceProviderInterface
$container['helper']->register('avatar', '\Kanboard\Helper\AvatarHelper');
$container['helper']->register('projectHeader', '\Kanboard\Helper\ProjectHeaderHelper');
$container['helper']->register('projectActivity', '\Kanboard\Helper\ProjectActivityHelper');
+ $container['helper']->register('mail', '\Kanboard\Helper\MailHelper');
$container['template'] = new Template($container['helper']);
diff --git a/app/ServiceProvider/LoggingProvider.php b/app/ServiceProvider/LoggingProvider.php
index 68c074f0..cb6d0baa 100644
--- a/app/ServiceProvider/LoggingProvider.php
+++ b/app/ServiceProvider/LoggingProvider.php
@@ -6,27 +6,48 @@ use Psr\Log\LogLevel;
use Pimple\Container;
use Pimple\ServiceProviderInterface;
use SimpleLogger\Logger;
+use SimpleLogger\Stderr;
+use SimpleLogger\Stdout;
use SimpleLogger\Syslog;
use SimpleLogger\File;
+/**
+ * Class LoggingProvider
+ *
+ * @package Kanboard\ServiceProvider
+ * @author Frederic Guillot
+ */
class LoggingProvider implements ServiceProviderInterface
{
public function register(Container $container)
{
$logger = new Logger;
+ $driver = null;
- if (ENABLE_SYSLOG) {
- $syslog = new Syslog('kanboard');
- $syslog->setLevel(LogLevel::ERROR);
- $logger->setLogger($syslog);
+ switch (LOG_DRIVER) {
+ case 'syslog':
+ $driver = new Syslog('kanboard');
+ break;
+ case 'stdout':
+ $driver = new Stdout();
+ break;
+ case 'stderr':
+ $driver = new Stderr();
+ break;
+ case 'file':
+ $driver = new File(LOG_FILE);
+ break;
}
- if (DEBUG) {
- $logger->setLogger(new File(DEBUG_FILE));
+ if ($driver !== null) {
+ if (! DEBUG) {
+ $driver->setLevel(LogLevel::INFO);
+ }
+
+ $logger->setLogger($driver);
}
$container['logger'] = $logger;
-
return $container;
}
}
diff --git a/app/ServiceProvider/MailProvider.php b/app/ServiceProvider/MailProvider.php
new file mode 100644
index 00000000..685709e3
--- /dev/null
+++ b/app/ServiceProvider/MailProvider.php
@@ -0,0 +1,34 @@
+<?php
+
+namespace Kanboard\ServiceProvider;
+
+use Kanboard\Core\Mail\Client as EmailClient;
+use Pimple\Container;
+use Pimple\ServiceProviderInterface;
+
+/**
+ * Mail Provider
+ *
+ * @package Kanboard\ServiceProvider
+ * @author Frederic Guillot
+ */
+class MailProvider implements ServiceProviderInterface
+{
+ /**
+ * Registers services on the given container.
+ *
+ * @param Container $container
+ */
+ public function register(Container $container)
+ {
+ $container['emailClient'] = function ($container) {
+ $mailer = new EmailClient($container);
+ $mailer->setTransport('smtp', '\Kanboard\Core\Mail\Transport\Smtp');
+ $mailer->setTransport('sendmail', '\Kanboard\Core\Mail\Transport\Sendmail');
+ $mailer->setTransport('mail', '\Kanboard\Core\Mail\Transport\Mail');
+ return $mailer;
+ };
+
+ return $container;
+ }
+}
diff --git a/app/ServiceProvider/NotificationProvider.php b/app/ServiceProvider/NotificationProvider.php
index 83daf65d..a0571209 100644
--- a/app/ServiceProvider/NotificationProvider.php
+++ b/app/ServiceProvider/NotificationProvider.php
@@ -4,15 +4,15 @@ namespace Kanboard\ServiceProvider;
use Pimple\Container;
use Pimple\ServiceProviderInterface;
-use Kanboard\Model\UserNotificationType;
-use Kanboard\Model\ProjectNotificationType;
-use Kanboard\Notification\Mail as MailNotification;
-use Kanboard\Notification\Web as WebNotification;
+use Kanboard\Model\UserNotificationTypeModel;
+use Kanboard\Model\ProjectNotificationTypeModel;
+use Kanboard\Notification\MailNotification as MailNotification;
+use Kanboard\Notification\WebNotification as WebNotification;
/**
* Notification Provider
*
- * @package serviceProvider
+ * @package Kanboard\ServiceProvider
* @author Frederic Guillot
*/
class NotificationProvider implements ServiceProviderInterface
@@ -26,17 +26,17 @@ class NotificationProvider implements ServiceProviderInterface
*/
public function register(Container $container)
{
- $container['userNotificationType'] = function ($container) {
- $type = new UserNotificationType($container);
- $type->setType(MailNotification::TYPE, t('Email'), '\Kanboard\Notification\Mail');
- $type->setType(WebNotification::TYPE, t('Web'), '\Kanboard\Notification\Web');
+ $container['userNotificationTypeModel'] = function ($container) {
+ $type = new UserNotificationTypeModel($container);
+ $type->setType(MailNotification::TYPE, t('Email'), '\Kanboard\Notification\MailNotification');
+ $type->setType(WebNotification::TYPE, t('Web'), '\Kanboard\Notification\WebNotification');
return $type;
};
- $container['projectNotificationType'] = function ($container) {
- $type = new ProjectNotificationType($container);
- $type->setType('webhook', 'Webhook', '\Kanboard\Notification\Webhook', true);
- $type->setType('activity_stream', 'ActivityStream', '\Kanboard\Notification\ActivityStream', true);
+ $container['projectNotificationTypeModel'] = function ($container) {
+ $type = new ProjectNotificationTypeModel($container);
+ $type->setType('webhook', 'Webhook', '\Kanboard\Notification\WebhookNotification', true);
+ $type->setType('activity_stream', 'ActivityStream', '\Kanboard\Notification\ActivityStreamNotification', true);
return $type;
};
diff --git a/app/ServiceProvider/PluginProvider.php b/app/ServiceProvider/PluginProvider.php
index d2f1666b..4cf57251 100644
--- a/app/ServiceProvider/PluginProvider.php
+++ b/app/ServiceProvider/PluginProvider.php
@@ -9,7 +9,7 @@ use Kanboard\Core\Plugin\Loader;
/**
* Plugin Provider
*
- * @package serviceProvider
+ * @package Kanboard\ServiceProvider
* @author Frederic Guillot
*/
class PluginProvider implements ServiceProviderInterface
diff --git a/app/ServiceProvider/QueueProvider.php b/app/ServiceProvider/QueueProvider.php
new file mode 100644
index 00000000..946b436a
--- /dev/null
+++ b/app/ServiceProvider/QueueProvider.php
@@ -0,0 +1,27 @@
+<?php
+
+namespace Kanboard\ServiceProvider;
+
+use Kanboard\Core\Queue\QueueManager;
+use Pimple\Container;
+use Pimple\ServiceProviderInterface;
+
+/**
+ * Class QueueProvider
+ *
+ * @package Kanboard\ServiceProvider
+ * @author Frederic Guillot
+ */
+class QueueProvider implements ServiceProviderInterface
+{
+ /**
+ * Registers services on the given container.
+ *
+ * @param Container $container
+ */
+ public function register(Container $container)
+ {
+ $container['queueManager'] = new QueueManager($container);
+ return $container;
+ }
+}
diff --git a/app/ServiceProvider/RouteProvider.php b/app/ServiceProvider/RouteProvider.php
index 30d23a51..3d1391df 100644
--- a/app/ServiceProvider/RouteProvider.php
+++ b/app/ServiceProvider/RouteProvider.php
@@ -10,7 +10,7 @@ use Kanboard\Core\Http\Router;
/**
* Route Provider
*
- * @package serviceProvider
+ * @package Kanboard\ServiceProvider
* @author Frederic Guillot
*/
class RouteProvider implements ServiceProviderInterface
@@ -31,168 +31,165 @@ class RouteProvider implements ServiceProviderInterface
$container['route']->enable();
// Dashboard
- $container['route']->addRoute('dashboard', 'app', 'index');
- $container['route']->addRoute('dashboard/:user_id', 'app', 'index');
- $container['route']->addRoute('dashboard/:user_id/projects', 'app', 'projects');
- $container['route']->addRoute('dashboard/:user_id/tasks', 'app', 'tasks');
- $container['route']->addRoute('dashboard/:user_id/subtasks', 'app', 'subtasks');
- $container['route']->addRoute('dashboard/:user_id/calendar', 'app', 'calendar');
- $container['route']->addRoute('dashboard/:user_id/activity', 'app', 'activity');
- $container['route']->addRoute('dashboard/:user_id/notifications', 'app', 'notifications');
+ $container['route']->addRoute('dashboard', 'DashboardController', 'show');
+ $container['route']->addRoute('dashboard/:user_id', 'DashboardController', 'show');
+ $container['route']->addRoute('dashboard/:user_id/projects', 'DashboardController', 'projects');
+ $container['route']->addRoute('dashboard/:user_id/tasks', 'DashboardController', 'tasks');
+ $container['route']->addRoute('dashboard/:user_id/subtasks', 'DashboardController', 'subtasks');
+ $container['route']->addRoute('dashboard/:user_id/calendar', 'DashboardController', 'calendar');
+ $container['route']->addRoute('dashboard/:user_id/activity', 'DashboardController', 'activity');
+ $container['route']->addRoute('dashboard/:user_id/notifications', 'DashboardController', 'notifications');
// Search routes
- $container['route']->addRoute('search', 'search', 'index');
- $container['route']->addRoute('search/activity', 'search', 'activity');
+ $container['route']->addRoute('search', 'SearchController', 'index');
+ $container['route']->addRoute('search/activity', 'SearchController', 'activity');
// ProjectCreation routes
- $container['route']->addRoute('project/create', 'ProjectCreation', 'create');
- $container['route']->addRoute('project/create/private', 'ProjectCreation', 'createPrivate');
+ $container['route']->addRoute('project/create', 'ProjectCreationController', 'create');
+ $container['route']->addRoute('project/create/private', 'ProjectCreationController', 'createPrivate');
// Project routes
- $container['route']->addRoute('projects', 'project', 'index');
- $container['route']->addRoute('project/:project_id', 'project', 'show');
- $container['route']->addRoute('p/:project_id', 'project', 'show');
- $container['route']->addRoute('project/:project_id/customer-filters', 'customfilter', 'index');
- $container['route']->addRoute('project/:project_id/share', 'project', 'share');
- $container['route']->addRoute('project/:project_id/notifications', 'project', 'notifications');
- $container['route']->addRoute('project/:project_id/integrations', 'project', 'integrations');
- $container['route']->addRoute('project/:project_id/duplicate', 'project', 'duplicate');
- $container['route']->addRoute('project/:project_id/remove', 'project', 'remove');
- $container['route']->addRoute('project/:project_id/disable', 'project', 'disable');
- $container['route']->addRoute('project/:project_id/enable', 'project', 'enable');
- $container['route']->addRoute('project/:project_id/permissions', 'ProjectPermission', 'index');
- $container['route']->addRoute('project/:project_id/import', 'taskImport', 'step1');
- $container['route']->addRoute('project/:project_id/activity', 'activity', 'project');
+ $container['route']->addRoute('projects', 'ProjectListController', 'show');
+ $container['route']->addRoute('project/:project_id', 'ProjectViewController', 'show');
+ $container['route']->addRoute('p/:project_id', 'ProjectViewController', 'show');
+ $container['route']->addRoute('project/:project_id/customer-filters', 'CustomFilterController', 'index');
+ $container['route']->addRoute('project/:project_id/share', 'ProjectViewController', 'share');
+ $container['route']->addRoute('project/:project_id/notifications', 'ProjectViewController', 'notifications');
+ $container['route']->addRoute('project/:project_id/integrations', 'ProjectViewController', 'integrations');
+ $container['route']->addRoute('project/:project_id/duplicate', 'ProjectViewController', 'duplicate');
+ $container['route']->addRoute('project/:project_id/permissions', 'ProjectPermissionController', 'index');
+ $container['route']->addRoute('project/:project_id/activity', 'ActivityController', 'project');
// Project Overview
- $container['route']->addRoute('project/:project_id/overview', 'ProjectOverview', 'show');
+ $container['route']->addRoute('project/:project_id/overview', 'ProjectOverviewController', 'show');
// ProjectEdit routes
- $container['route']->addRoute('project/:project_id/edit', 'ProjectEdit', 'edit');
- $container['route']->addRoute('project/:project_id/edit/dates', 'ProjectEdit', 'dates');
- $container['route']->addRoute('project/:project_id/edit/description', 'ProjectEdit', 'description');
- $container['route']->addRoute('project/:project_id/edit/priority', 'ProjectEdit', 'priority');
+ $container['route']->addRoute('project/:project_id/edit', 'ProjectEditController', 'edit');
+ $container['route']->addRoute('project/:project_id/edit/dates', 'ProjectEditController', 'dates');
+ $container['route']->addRoute('project/:project_id/edit/description', 'ProjectEditController', 'description');
+ $container['route']->addRoute('project/:project_id/edit/priority', 'ProjectEditController', 'priority');
// ProjectUser routes
- $container['route']->addRoute('projects/managers/:user_id', 'projectuser', 'managers');
- $container['route']->addRoute('projects/members/:user_id', 'projectuser', 'members');
- $container['route']->addRoute('projects/tasks/:user_id/opens', 'projectuser', 'opens');
- $container['route']->addRoute('projects/tasks/:user_id/closed', 'projectuser', 'closed');
- $container['route']->addRoute('projects/managers', 'projectuser', 'managers');
+ $container['route']->addRoute('projects/managers/:user_id', 'ProjectUserOverviewController', 'managers');
+ $container['route']->addRoute('projects/members/:user_id', 'ProjectUserOverviewController', 'members');
+ $container['route']->addRoute('projects/tasks/:user_id/opens', 'ProjectUserOverviewController', 'opens');
+ $container['route']->addRoute('projects/tasks/:user_id/closed', 'ProjectUserOverviewController', 'closed');
+ $container['route']->addRoute('projects/managers', 'ProjectUserOverviewController', 'managers');
// Action routes
- $container['route']->addRoute('project/:project_id/actions', 'action', 'index');
+ $container['route']->addRoute('project/:project_id/actions', 'ActionController', 'index');
// Column routes
- $container['route']->addRoute('project/:project_id/columns', 'column', 'index');
+ $container['route']->addRoute('project/:project_id/columns', 'ColumnController', 'index');
// Swimlane routes
- $container['route']->addRoute('project/:project_id/swimlanes', 'swimlane', 'index');
+ $container['route']->addRoute('project/:project_id/swimlanes', 'SwimlaneController', 'index');
// Category routes
- $container['route']->addRoute('project/:project_id/categories', 'category', 'index');
+ $container['route']->addRoute('project/:project_id/categories', 'CategoryController', 'index');
+
+ // Import routes
+ $container['route']->addRoute('project/:project_id/import', 'TaskImportController', 'show');
// Task routes
- $container['route']->addRoute('project/:project_id/task/:task_id', 'task', 'show');
- $container['route']->addRoute('t/:task_id', 'task', 'show');
- $container['route']->addRoute('public/task/:task_id/:token', 'task', 'readonly');
+ $container['route']->addRoute('project/:project_id/task/:task_id', 'TaskViewController', 'show');
+ $container['route']->addRoute('t/:task_id', 'TaskViewController', 'show');
+ $container['route']->addRoute('public/task/:task_id/:token', 'TaskViewController', 'readonly');
- $container['route']->addRoute('project/:project_id/task/:task_id/activity', 'activity', 'task');
- $container['route']->addRoute('project/:project_id/task/:task_id/transitions', 'task', 'transitions');
- $container['route']->addRoute('project/:project_id/task/:task_id/analytics', 'task', 'analytics');
- $container['route']->addRoute('project/:project_id/task/:task_id/subtasks', 'subtask', 'show');
- $container['route']->addRoute('project/:project_id/task/:task_id/time-tracking', 'task', 'timetracking');
+ $container['route']->addRoute('project/:project_id/task/:task_id/activity', 'ActivityController', 'task');
+ $container['route']->addRoute('project/:project_id/task/:task_id/transitions', 'TaskViewController', 'transitions');
+ $container['route']->addRoute('project/:project_id/task/:task_id/analytics', 'TaskViewController', 'analytics');
+ $container['route']->addRoute('project/:project_id/task/:task_id/time-tracking', 'TaskViewController', 'timetracking');
// Exports
- $container['route']->addRoute('export/tasks/:project_id', 'export', 'tasks');
- $container['route']->addRoute('export/subtasks/:project_id', 'export', 'subtasks');
- $container['route']->addRoute('export/transitions/:project_id', 'export', 'transitions');
- $container['route']->addRoute('export/summary/:project_id', 'export', 'summary');
+ $container['route']->addRoute('export/tasks/:project_id', 'ExportController', 'tasks');
+ $container['route']->addRoute('export/subtasks/:project_id', 'ExportController', 'subtasks');
+ $container['route']->addRoute('export/transitions/:project_id', 'ExportController', 'transitions');
+ $container['route']->addRoute('export/summary/:project_id', 'ExportController', 'summary');
// Analytics routes
- $container['route']->addRoute('analytics/tasks/:project_id', 'analytic', 'tasks');
- $container['route']->addRoute('analytics/users/:project_id', 'analytic', 'users');
- $container['route']->addRoute('analytics/cfd/:project_id', 'analytic', 'cfd');
- $container['route']->addRoute('analytics/burndown/:project_id', 'analytic', 'burndown');
- $container['route']->addRoute('analytics/average-time-column/:project_id', 'analytic', 'averageTimeByColumn');
- $container['route']->addRoute('analytics/lead-cycle-time/:project_id', 'analytic', 'leadAndCycleTime');
- $container['route']->addRoute('analytics/estimated-spent-time/:project_id', 'analytic', 'compareHours');
+ $container['route']->addRoute('analytics/tasks/:project_id', 'AnalyticController', 'tasks');
+ $container['route']->addRoute('analytics/users/:project_id', 'AnalyticController', 'users');
+ $container['route']->addRoute('analytics/cfd/:project_id', 'AnalyticController', 'cfd');
+ $container['route']->addRoute('analytics/burndown/:project_id', 'AnalyticController', 'burndown');
+ $container['route']->addRoute('analytics/average-time-column/:project_id', 'AnalyticController', 'averageTimeByColumn');
+ $container['route']->addRoute('analytics/lead-cycle-time/:project_id', 'AnalyticController', 'leadAndCycleTime');
+ $container['route']->addRoute('analytics/estimated-spent-time/:project_id', 'AnalyticController', 'compareHours');
// Board routes
- $container['route']->addRoute('board/:project_id', 'board', 'show');
- $container['route']->addRoute('b/:project_id', 'board', 'show');
- $container['route']->addRoute('public/board/:token', 'board', 'readonly');
+ $container['route']->addRoute('board/:project_id', 'BoardViewController', 'show');
+ $container['route']->addRoute('b/:project_id', 'BoardViewController', 'show');
+ $container['route']->addRoute('public/board/:token', 'BoardViewController', 'readonly');
// Calendar routes
- $container['route']->addRoute('calendar/:project_id', 'calendar', 'show');
- $container['route']->addRoute('c/:project_id', 'calendar', 'show');
+ $container['route']->addRoute('calendar/:project_id', 'CalendarController', 'show');
+ $container['route']->addRoute('c/:project_id', 'CalendarController', 'show');
// Listing routes
- $container['route']->addRoute('list/:project_id', 'listing', 'show');
- $container['route']->addRoute('l/:project_id', 'listing', 'show');
+ $container['route']->addRoute('list/:project_id', 'TaskListController', 'show');
+ $container['route']->addRoute('l/:project_id', 'TaskListController', 'show');
// Gantt routes
- $container['route']->addRoute('gantt/:project_id', 'gantt', 'project');
- $container['route']->addRoute('gantt/:project_id/sort/:sorting', 'gantt', 'project');
+ $container['route']->addRoute('gantt/:project_id', 'TaskGanttController', 'show');
+ $container['route']->addRoute('gantt/:project_id/sort/:sorting', 'TaskGanttController', 'show');
// Feed routes
- $container['route']->addRoute('feed/project/:token', 'feed', 'project');
- $container['route']->addRoute('feed/user/:token', 'feed', 'user');
+ $container['route']->addRoute('feed/project/:token', 'FeedController', 'project');
+ $container['route']->addRoute('feed/user/:token', 'FeedController', 'user');
// Ical routes
- $container['route']->addRoute('ical/project/:token', 'ical', 'project');
- $container['route']->addRoute('ical/user/:token', 'ical', 'user');
+ $container['route']->addRoute('ical/project/:token', 'ICalendarController', 'project');
+ $container['route']->addRoute('ical/user/:token', 'ICalendarController', 'user');
// Users
- $container['route']->addRoute('users', 'user', 'index');
- $container['route']->addRoute('user/profile/:user_id', 'user', 'profile');
- $container['route']->addRoute('user/show/:user_id', 'user', 'show');
- $container['route']->addRoute('user/show/:user_id/timesheet', 'user', 'timesheet');
- $container['route']->addRoute('user/show/:user_id/last-logins', 'user', 'last');
- $container['route']->addRoute('user/show/:user_id/sessions', 'user', 'sessions');
- $container['route']->addRoute('user/:user_id/edit', 'user', 'edit');
- $container['route']->addRoute('user/:user_id/password', 'user', 'password');
- $container['route']->addRoute('user/:user_id/share', 'user', 'share');
- $container['route']->addRoute('user/:user_id/notifications', 'user', 'notifications');
- $container['route']->addRoute('user/:user_id/accounts', 'user', 'external');
- $container['route']->addRoute('user/:user_id/integrations', 'user', 'integrations');
- $container['route']->addRoute('user/:user_id/authentication', 'user', 'authentication');
- $container['route']->addRoute('user/:user_id/2fa', 'twofactor', 'index');
+ $container['route']->addRoute('users', 'UserListController', 'show');
+ $container['route']->addRoute('user/profile/:user_id', 'UserViewController', 'profile');
+ $container['route']->addRoute('user/show/:user_id', 'UserViewController', 'show');
+ $container['route']->addRoute('user/show/:user_id/timesheet', 'UserViewController', 'timesheet');
+ $container['route']->addRoute('user/show/:user_id/last-logins', 'UserViewController', 'lastLogin');
+ $container['route']->addRoute('user/show/:user_id/sessions', 'UserViewController', 'sessions');
+ $container['route']->addRoute('user/:user_id/edit', 'UserModificationController', 'show');
+ $container['route']->addRoute('user/:user_id/password', 'UserCredentialController', 'changePassword');
+ $container['route']->addRoute('user/:user_id/share', 'UserViewController', 'share');
+ $container['route']->addRoute('user/:user_id/notifications', 'UserViewController', 'notifications');
+ $container['route']->addRoute('user/:user_id/accounts', 'UserViewController', 'external');
+ $container['route']->addRoute('user/:user_id/integrations', 'UserViewController', 'integrations');
+ $container['route']->addRoute('user/:user_id/authentication', 'UserCredentialController', 'changeAuthentication');
+ $container['route']->addRoute('user/:user_id/2fa', 'TwoFactorController', 'index');
+ $container['route']->addRoute('user/:user_id/avatar', 'AvatarFileController', 'show');
// Groups
- $container['route']->addRoute('groups', 'group', 'index');
- $container['route']->addRoute('groups/create', 'group', 'create');
- $container['route']->addRoute('group/:group_id/associate', 'group', 'associate');
- $container['route']->addRoute('group/:group_id/dissociate/:user_id', 'group', 'dissociate');
- $container['route']->addRoute('group/:group_id/edit', 'group', 'edit');
- $container['route']->addRoute('group/:group_id/members', 'group', 'users');
- $container['route']->addRoute('group/:group_id/remove', 'group', 'confirm');
+ $container['route']->addRoute('groups', 'GroupListController', 'index');
+ $container['route']->addRoute('group/:group_id/members', 'GroupListController', 'users');
// Config
- $container['route']->addRoute('settings', 'config', 'index');
- $container['route']->addRoute('settings/plugins', 'config', 'plugins');
- $container['route']->addRoute('settings/application', 'config', 'application');
- $container['route']->addRoute('settings/project', 'config', 'project');
- $container['route']->addRoute('settings/project', 'config', 'project');
- $container['route']->addRoute('settings/board', 'config', 'board');
- $container['route']->addRoute('settings/calendar', 'config', 'calendar');
- $container['route']->addRoute('settings/integrations', 'config', 'integrations');
- $container['route']->addRoute('settings/webhook', 'config', 'webhook');
- $container['route']->addRoute('settings/api', 'config', 'api');
- $container['route']->addRoute('settings/links', 'link', 'index');
- $container['route']->addRoute('settings/currencies', 'currency', 'index');
+ $container['route']->addRoute('settings', 'ConfigController', 'index');
+ $container['route']->addRoute('settings/application', 'ConfigController', 'application');
+ $container['route']->addRoute('settings/project', 'ConfigController', 'project');
+ $container['route']->addRoute('settings/project', 'ConfigController', 'project');
+ $container['route']->addRoute('settings/board', 'ConfigController', 'board');
+ $container['route']->addRoute('settings/calendar', 'ConfigController', 'calendar');
+ $container['route']->addRoute('settings/integrations', 'ConfigController', 'integrations');
+ $container['route']->addRoute('settings/webhook', 'ConfigController', 'webhook');
+ $container['route']->addRoute('settings/api', 'ConfigController', 'api');
+ $container['route']->addRoute('settings/links', 'LinkController', 'index');
+ $container['route']->addRoute('settings/currencies', 'CurrencyController', 'index');
+
+ // Plugins
+ $container['route']->addRoute('extensions', 'PluginController', 'show');
+ $container['route']->addRoute('extensions/directory', 'PluginController', 'directory');
// Doc
- $container['route']->addRoute('documentation/:file', 'doc', 'show');
- $container['route']->addRoute('documentation', 'doc', 'show');
+ $container['route']->addRoute('documentation/:file', 'DocumentationController', 'show');
+ $container['route']->addRoute('documentation', 'DocumentationController', 'show');
// Auth routes
- $container['route']->addRoute('login', 'auth', 'login');
- $container['route']->addRoute('logout', 'auth', 'logout');
+ $container['route']->addRoute('login', 'AuthController', 'login');
+ $container['route']->addRoute('logout', 'AuthController', 'logout');
// PasswordReset
- $container['route']->addRoute('forgot-password', 'PasswordReset', 'create');
- $container['route']->addRoute('forgot-password/change/:token', 'PasswordReset', 'change');
+ $container['route']->addRoute('forgot-password', 'PasswordResetController', 'create');
+ $container['route']->addRoute('forgot-password/change/:token', 'PasswordResetController', 'change');
}
return $container;
diff --git a/app/ServiceProvider/SessionProvider.php b/app/ServiceProvider/SessionProvider.php
index 0999d531..96dcac2e 100644
--- a/app/ServiceProvider/SessionProvider.php
+++ b/app/ServiceProvider/SessionProvider.php
@@ -11,7 +11,7 @@ use Kanboard\Core\Session\FlashMessage;
/**
* Session Provider
*
- * @package serviceProvider
+ * @package Kanboard\ServiceProvider
* @author Frederic Guillot
*/
class SessionProvider implements ServiceProviderInterface
diff --git a/app/Subscriber/AuthSubscriber.php b/app/Subscriber/AuthSubscriber.php
index dfb95a00..0097c407 100644
--- a/app/Subscriber/AuthSubscriber.php
+++ b/app/Subscriber/AuthSubscriber.php
@@ -45,9 +45,9 @@ class AuthSubscriber extends BaseSubscriber implements EventSubscriberInterface
$userAgent = $this->request->getUserAgent();
$ipAddress = $this->request->getIpAddress();
- $this->userLocking->resetFailedLogin($this->userSession->getUsername());
+ $this->userLockingModel->resetFailedLogin($this->userSession->getUsername());
- $this->lastLogin->create(
+ $this->lastLoginModel->create(
$event->getAuthType(),
$this->userSession->getId(),
$ipAddress,
@@ -59,7 +59,7 @@ class AuthSubscriber extends BaseSubscriber implements EventSubscriberInterface
}
if (isset($this->sessionStorage->hasRememberMe) && $this->sessionStorage->hasRememberMe) {
- $session = $this->rememberMeSession->create($this->userSession->getId(), $ipAddress, $userAgent);
+ $session = $this->rememberMeSessionModel->create($this->userSession->getId(), $ipAddress, $userAgent);
$this->rememberMeCookie->write($session['token'], $session['sequence'], $session['expiration']);
}
}
@@ -75,10 +75,10 @@ class AuthSubscriber extends BaseSubscriber implements EventSubscriberInterface
$credentials = $this->rememberMeCookie->read();
if ($credentials !== false) {
- $session = $this->rememberMeSession->find($credentials['token'], $credentials['sequence']);
+ $session = $this->rememberMeSessionModel->find($credentials['token'], $credentials['sequence']);
if (! empty($session)) {
- $this->rememberMeSession->remove($session['id']);
+ $this->rememberMeSessionModel->remove($session['id']);
}
$this->rememberMeCookie->remove();
@@ -97,10 +97,10 @@ class AuthSubscriber extends BaseSubscriber implements EventSubscriberInterface
$username = $event->getUsername();
if (! empty($username)) {
- $this->userLocking->incrementFailedLogin($username);
+ $this->userLockingModel->incrementFailedLogin($username);
- if ($this->userLocking->getFailedLogin($username) > BRUTEFORCE_LOCKDOWN) {
- $this->userLocking->lock($username, BRUTEFORCE_LOCKDOWN_DURATION);
+ if ($this->userLockingModel->getFailedLogin($username) > BRUTEFORCE_LOCKDOWN) {
+ $this->userLockingModel->lock($username, BRUTEFORCE_LOCKDOWN_DURATION);
}
}
}
diff --git a/app/Subscriber/BaseSubscriber.php b/app/Subscriber/BaseSubscriber.php
index 2e41da76..fdea29f6 100644
--- a/app/Subscriber/BaseSubscriber.php
+++ b/app/Subscriber/BaseSubscriber.php
@@ -34,7 +34,6 @@ class BaseSubscriber extends Base
}
$this->called[$key] = true;
-
return false;
}
}
diff --git a/app/Subscriber/BootstrapSubscriber.php b/app/Subscriber/BootstrapSubscriber.php
index ef0215f3..7d12e9ae 100644
--- a/app/Subscriber/BootstrapSubscriber.php
+++ b/app/Subscriber/BootstrapSubscriber.php
@@ -16,12 +16,12 @@ class BootstrapSubscriber extends BaseSubscriber implements EventSubscriberInter
public function execute()
{
$this->logger->debug('Subscriber executed: '.__METHOD__);
- $this->config->setupTranslations();
- $this->config->setupTimezone();
+ $this->languageModel->loadCurrentLanguage();
+ $this->timezoneModel->setCurrentTimezone();
$this->actionManager->attachEvents();
if ($this->userSession->isLogged()) {
- $this->sessionStorage->hasSubtaskInProgress = $this->subtask->hasSubtaskInProgress($this->userSession->getId());
+ $this->sessionStorage->hasSubtaskInProgress = $this->subtaskModel->hasSubtaskInProgress($this->userSession->getId());
}
}
@@ -29,13 +29,13 @@ class BootstrapSubscriber extends BaseSubscriber implements EventSubscriberInter
{
if (DEBUG) {
foreach ($this->db->getLogMessages() as $message) {
- $this->logger->debug($message);
+ $this->logger->debug('SQL: ' . $message);
}
- $this->logger->debug('SQL_QUERIES={nb}', array('nb' => $this->container['db']->nbQueries));
- $this->logger->debug('RENDERING={time}', array('time' => microtime(true) - $this->request->getStartTime()));
- $this->logger->debug('MEMORY='.$this->helper->text->bytes(memory_get_usage()));
- $this->logger->debug('URI='.$this->request->getUri());
+ $this->logger->debug('APP: nb_queries={nb}', array('nb' => $this->db->getStatementHandler()->getNbQueries()));
+ $this->logger->debug('APP: rendering_time={time}', array('time' => microtime(true) - $this->request->getStartTime()));
+ $this->logger->debug('APP: memory_usage='.$this->helper->text->bytes(memory_get_usage()));
+ $this->logger->debug('APP: uri='.$this->request->getUri());
$this->logger->debug('###############################################');
}
}
diff --git a/app/Subscriber/LdapUserPhotoSubscriber.php b/app/Subscriber/LdapUserPhotoSubscriber.php
new file mode 100644
index 00000000..93672cd1
--- /dev/null
+++ b/app/Subscriber/LdapUserPhotoSubscriber.php
@@ -0,0 +1,49 @@
+<?php
+
+namespace Kanboard\Subscriber;
+
+use Kanboard\Core\User\UserProfile;
+use Kanboard\Event\UserProfileSyncEvent;
+use Symfony\Component\EventDispatcher\EventSubscriberInterface;
+
+/**
+ * Class LdapUserPhotoSubscriber
+ *
+ * @package Kanboard\Subscriber
+ * @author Frederic Guillot
+ */
+class LdapUserPhotoSubscriber extends BaseSubscriber implements EventSubscriberInterface
+{
+ /**
+ * Get event listeners
+ *
+ * @static
+ * @access public
+ * @return array
+ */
+ public static function getSubscribedEvents()
+ {
+ return array(
+ UserProfile::EVENT_USER_PROFILE_AFTER_SYNC => 'syncUserPhoto',
+ );
+ }
+
+ /**
+ * Save the user profile photo from LDAP to the object storage
+ *
+ * @access public
+ * @param UserProfileSyncEvent $event
+ */
+ public function syncUserPhoto(UserProfileSyncEvent $event)
+ {
+ if (is_a($event->getUser(), 'Kanboard\User\LdapUserProvider')) {
+ $profile = $event->getProfile();
+ $photo = $event->getUser()->getPhoto();
+
+ if (empty($profile['avatar_path']) && ! empty($photo)) {
+ $this->logger->info('Saving user photo from LDAP profile');
+ $this->avatarFileModel->uploadImageContent($profile['id'], $photo);
+ }
+ }
+ }
+}
diff --git a/app/Subscriber/NotificationSubscriber.php b/app/Subscriber/NotificationSubscriber.php
index 651b8a96..db11e585 100644
--- a/app/Subscriber/NotificationSubscriber.php
+++ b/app/Subscriber/NotificationSubscriber.php
@@ -3,10 +3,11 @@
namespace Kanboard\Subscriber;
use Kanboard\Event\GenericEvent;
-use Kanboard\Model\Task;
-use Kanboard\Model\Comment;
-use Kanboard\Model\Subtask;
-use Kanboard\Model\TaskFile;
+use Kanboard\Job\NotificationJob;
+use Kanboard\Model\TaskModel;
+use Kanboard\Model\CommentModel;
+use Kanboard\Model\SubtaskModel;
+use Kanboard\Model\TaskFileModel;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class NotificationSubscriber extends BaseSubscriber implements EventSubscriberInterface
@@ -14,67 +15,32 @@ class NotificationSubscriber extends BaseSubscriber implements EventSubscriberIn
public static function getSubscribedEvents()
{
return array(
- Task::EVENT_USER_MENTION => 'handleEvent',
- Task::EVENT_CREATE => 'handleEvent',
- Task::EVENT_UPDATE => 'handleEvent',
- Task::EVENT_CLOSE => 'handleEvent',
- Task::EVENT_OPEN => 'handleEvent',
- Task::EVENT_MOVE_COLUMN => 'handleEvent',
- Task::EVENT_MOVE_POSITION => 'handleEvent',
- Task::EVENT_MOVE_SWIMLANE => 'handleEvent',
- Task::EVENT_ASSIGNEE_CHANGE => 'handleEvent',
- Subtask::EVENT_CREATE => 'handleEvent',
- Subtask::EVENT_UPDATE => 'handleEvent',
- Comment::EVENT_CREATE => 'handleEvent',
- Comment::EVENT_UPDATE => 'handleEvent',
- Comment::EVENT_USER_MENTION => 'handleEvent',
- TaskFile::EVENT_CREATE => 'handleEvent',
+ TaskModel::EVENT_USER_MENTION => 'handleEvent',
+ TaskModel::EVENT_CREATE => 'handleEvent',
+ TaskModel::EVENT_UPDATE => 'handleEvent',
+ TaskModel::EVENT_CLOSE => 'handleEvent',
+ TaskModel::EVENT_OPEN => 'handleEvent',
+ TaskModel::EVENT_MOVE_COLUMN => 'handleEvent',
+ TaskModel::EVENT_MOVE_POSITION => 'handleEvent',
+ TaskModel::EVENT_MOVE_SWIMLANE => 'handleEvent',
+ TaskModel::EVENT_ASSIGNEE_CHANGE => 'handleEvent',
+ SubtaskModel::EVENT_CREATE => 'handleEvent',
+ SubtaskModel::EVENT_UPDATE => 'handleEvent',
+ CommentModel::EVENT_CREATE => 'handleEvent',
+ CommentModel::EVENT_UPDATE => 'handleEvent',
+ CommentModel::EVENT_USER_MENTION => 'handleEvent',
+ TaskFileModel::EVENT_CREATE => 'handleEvent',
);
}
- public function handleEvent(GenericEvent $event, $event_name)
+ public function handleEvent(GenericEvent $event, $eventName)
{
- if (! $this->isExecuted($event_name)) {
- $this->logger->debug('Subscriber executed: '.__METHOD__);
- $event_data = $this->getEventData($event);
+ if (!$this->isExecuted($eventName)) {
+ $this->logger->debug('Subscriber executed: ' . __METHOD__);
- if (! empty($event_data)) {
- if (! empty($event['mention'])) {
- $this->userNotification->sendUserNotification($event['mention'], $event_name, $event_data);
- } else {
- $this->userNotification->sendNotifications($event_name, $event_data);
- $this->projectNotification->sendNotifications($event_data['task']['project_id'], $event_name, $event_data);
- }
- }
+ $this->queueManager->push(NotificationJob::getInstance($this->container)
+ ->withParams($event, $eventName, get_class($event))
+ );
}
}
-
- public function getEventData(GenericEvent $event)
- {
- $values = array();
-
- if (! empty($event['changes'])) {
- $values['changes'] = $event['changes'];
- }
-
- switch (get_class($event)) {
- case 'Kanboard\Event\TaskEvent':
- $values['task'] = $this->taskFinder->getDetails($event['task_id']);
- break;
- case 'Kanboard\Event\SubtaskEvent':
- $values['subtask'] = $this->subtask->getById($event['id'], true);
- $values['task'] = $this->taskFinder->getDetails($values['subtask']['task_id']);
- break;
- case 'Kanboard\Event\FileEvent':
- $values['file'] = $event->getAll();
- $values['task'] = $this->taskFinder->getDetails($values['file']['task_id']);
- break;
- case 'Kanboard\Event\CommentEvent':
- $values['comment'] = $this->comment->getById($event['id']);
- $values['task'] = $this->taskFinder->getDetails($values['comment']['task_id']);
- break;
- }
-
- return $values;
- }
}
diff --git a/app/Subscriber/ProjectDailySummarySubscriber.php b/app/Subscriber/ProjectDailySummarySubscriber.php
index 44138f43..6971a121 100644
--- a/app/Subscriber/ProjectDailySummarySubscriber.php
+++ b/app/Subscriber/ProjectDailySummarySubscriber.php
@@ -3,7 +3,8 @@
namespace Kanboard\Subscriber;
use Kanboard\Event\TaskEvent;
-use Kanboard\Model\Task;
+use Kanboard\Job\ProjectMetricJob;
+use Kanboard\Model\TaskModel;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class ProjectDailySummarySubscriber extends BaseSubscriber implements EventSubscriberInterface
@@ -11,11 +12,11 @@ class ProjectDailySummarySubscriber extends BaseSubscriber implements EventSubsc
public static function getSubscribedEvents()
{
return array(
- Task::EVENT_CREATE_UPDATE => 'execute',
- Task::EVENT_CLOSE => 'execute',
- Task::EVENT_OPEN => 'execute',
- Task::EVENT_MOVE_COLUMN => 'execute',
- Task::EVENT_MOVE_SWIMLANE => 'execute',
+ TaskModel::EVENT_CREATE_UPDATE => 'execute',
+ TaskModel::EVENT_CLOSE => 'execute',
+ TaskModel::EVENT_OPEN => 'execute',
+ TaskModel::EVENT_MOVE_COLUMN => 'execute',
+ TaskModel::EVENT_MOVE_SWIMLANE => 'execute',
);
}
@@ -23,8 +24,7 @@ class ProjectDailySummarySubscriber extends BaseSubscriber implements EventSubsc
{
if (isset($event['project_id']) && !$this->isExecuted()) {
$this->logger->debug('Subscriber executed: '.__METHOD__);
- $this->projectDailyColumnStats->updateTotals($event['project_id'], date('Y-m-d'));
- $this->projectDailyStats->updateTotals($event['project_id'], date('Y-m-d'));
+ $this->queueManager->push(ProjectMetricJob::getInstance($this->container)->withParams($event['project_id']));
}
}
}
diff --git a/app/Subscriber/ProjectModificationDateSubscriber.php b/app/Subscriber/ProjectModificationDateSubscriber.php
index 62804a84..fee04eaa 100644
--- a/app/Subscriber/ProjectModificationDateSubscriber.php
+++ b/app/Subscriber/ProjectModificationDateSubscriber.php
@@ -3,7 +3,7 @@
namespace Kanboard\Subscriber;
use Kanboard\Event\GenericEvent;
-use Kanboard\Model\Task;
+use Kanboard\Model\TaskModel;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class ProjectModificationDateSubscriber extends BaseSubscriber implements EventSubscriberInterface
@@ -11,14 +11,14 @@ class ProjectModificationDateSubscriber extends BaseSubscriber implements EventS
public static function getSubscribedEvents()
{
return array(
- Task::EVENT_CREATE_UPDATE => 'execute',
- Task::EVENT_CLOSE => 'execute',
- Task::EVENT_OPEN => 'execute',
- Task::EVENT_MOVE_SWIMLANE => 'execute',
- Task::EVENT_MOVE_COLUMN => 'execute',
- Task::EVENT_MOVE_POSITION => 'execute',
- Task::EVENT_MOVE_PROJECT => 'execute',
- Task::EVENT_ASSIGNEE_CHANGE => 'execute',
+ TaskModel::EVENT_CREATE_UPDATE => 'execute',
+ TaskModel::EVENT_CLOSE => 'execute',
+ TaskModel::EVENT_OPEN => 'execute',
+ TaskModel::EVENT_MOVE_SWIMLANE => 'execute',
+ TaskModel::EVENT_MOVE_COLUMN => 'execute',
+ TaskModel::EVENT_MOVE_POSITION => 'execute',
+ TaskModel::EVENT_MOVE_PROJECT => 'execute',
+ TaskModel::EVENT_ASSIGNEE_CHANGE => 'execute',
);
}
@@ -26,7 +26,7 @@ class ProjectModificationDateSubscriber extends BaseSubscriber implements EventS
{
if (isset($event['project_id']) && !$this->isExecuted()) {
$this->logger->debug('Subscriber executed: '.__METHOD__);
- $this->project->updateModificationDate($event['project_id']);
+ $this->projectModel->updateModificationDate($event['project_id']);
}
}
}
diff --git a/app/Subscriber/RecurringTaskSubscriber.php b/app/Subscriber/RecurringTaskSubscriber.php
index 09a5665a..75b7ff76 100644
--- a/app/Subscriber/RecurringTaskSubscriber.php
+++ b/app/Subscriber/RecurringTaskSubscriber.php
@@ -3,7 +3,7 @@
namespace Kanboard\Subscriber;
use Kanboard\Event\TaskEvent;
-use Kanboard\Model\Task;
+use Kanboard\Model\TaskModel;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class RecurringTaskSubscriber extends BaseSubscriber implements EventSubscriberInterface
@@ -11,8 +11,8 @@ class RecurringTaskSubscriber extends BaseSubscriber implements EventSubscriberI
public static function getSubscribedEvents()
{
return array(
- Task::EVENT_MOVE_COLUMN => 'onMove',
- Task::EVENT_CLOSE => 'onClose',
+ TaskModel::EVENT_MOVE_COLUMN => 'onMove',
+ TaskModel::EVENT_CLOSE => 'onClose',
);
}
@@ -20,11 +20,11 @@ class RecurringTaskSubscriber extends BaseSubscriber implements EventSubscriberI
{
$this->logger->debug('Subscriber executed: '.__METHOD__);
- if ($event['recurrence_status'] == Task::RECURRING_STATUS_PENDING) {
- if ($event['recurrence_trigger'] == Task::RECURRING_TRIGGER_FIRST_COLUMN && $this->column->getFirstColumnId($event['project_id']) == $event['src_column_id']) {
- $this->taskDuplication->duplicateRecurringTask($event['task_id']);
- } elseif ($event['recurrence_trigger'] == Task::RECURRING_TRIGGER_LAST_COLUMN && $this->column->getLastColumnId($event['project_id']) == $event['dst_column_id']) {
- $this->taskDuplication->duplicateRecurringTask($event['task_id']);
+ if ($event['recurrence_status'] == TaskModel::RECURRING_STATUS_PENDING) {
+ if ($event['recurrence_trigger'] == TaskModel::RECURRING_TRIGGER_FIRST_COLUMN && $this->columnModel->getFirstColumnId($event['project_id']) == $event['src_column_id']) {
+ $this->taskDuplicationModel->duplicateRecurringTask($event['task_id']);
+ } elseif ($event['recurrence_trigger'] == TaskModel::RECURRING_TRIGGER_LAST_COLUMN && $this->columnModel->getLastColumnId($event['project_id']) == $event['dst_column_id']) {
+ $this->taskDuplicationModel->duplicateRecurringTask($event['task_id']);
}
}
}
@@ -33,8 +33,8 @@ class RecurringTaskSubscriber extends BaseSubscriber implements EventSubscriberI
{
$this->logger->debug('Subscriber executed: '.__METHOD__);
- if ($event['recurrence_status'] == Task::RECURRING_STATUS_PENDING && $event['recurrence_trigger'] == Task::RECURRING_TRIGGER_CLOSE) {
- $this->taskDuplication->duplicateRecurringTask($event['task_id']);
+ if ($event['recurrence_status'] == TaskModel::RECURRING_STATUS_PENDING && $event['recurrence_trigger'] == TaskModel::RECURRING_TRIGGER_CLOSE) {
+ $this->taskDuplicationModel->duplicateRecurringTask($event['task_id']);
}
}
}
diff --git a/app/Subscriber/SubtaskTimeTrackingSubscriber.php b/app/Subscriber/SubtaskTimeTrackingSubscriber.php
index c0852bc8..7e39c126 100644
--- a/app/Subscriber/SubtaskTimeTrackingSubscriber.php
+++ b/app/Subscriber/SubtaskTimeTrackingSubscriber.php
@@ -3,7 +3,7 @@
namespace Kanboard\Subscriber;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
-use Kanboard\Model\Subtask;
+use Kanboard\Model\SubtaskModel;
use Kanboard\Event\SubtaskEvent;
class SubtaskTimeTrackingSubscriber extends BaseSubscriber implements EventSubscriberInterface
@@ -11,9 +11,9 @@ class SubtaskTimeTrackingSubscriber extends BaseSubscriber implements EventSubsc
public static function getSubscribedEvents()
{
return array(
- Subtask::EVENT_CREATE => 'updateTaskTime',
- Subtask::EVENT_DELETE => 'updateTaskTime',
- Subtask::EVENT_UPDATE => array(
+ SubtaskModel::EVENT_CREATE => 'updateTaskTime',
+ SubtaskModel::EVENT_DELETE => 'updateTaskTime',
+ SubtaskModel::EVENT_UPDATE => array(
array('logStartEnd', 10),
array('updateTaskTime', 0),
)
@@ -24,24 +24,24 @@ class SubtaskTimeTrackingSubscriber extends BaseSubscriber implements EventSubsc
{
if (isset($event['task_id'])) {
$this->logger->debug('Subscriber executed: '.__METHOD__);
- $this->subtaskTimeTracking->updateTaskTimeTracking($event['task_id']);
+ $this->subtaskTimeTrackingModel->updateTaskTimeTracking($event['task_id']);
}
}
public function logStartEnd(SubtaskEvent $event)
{
- if (isset($event['status']) && $this->config->get('subtask_time_tracking') == 1) {
+ if (isset($event['status']) && $this->configModel->get('subtask_time_tracking') == 1) {
$this->logger->debug('Subscriber executed: '.__METHOD__);
- $subtask = $this->subtask->getById($event['id']);
+ $subtask = $this->subtaskModel->getById($event['id']);
if (empty($subtask['user_id'])) {
return false;
}
- if ($subtask['status'] == Subtask::STATUS_INPROGRESS) {
- return $this->subtaskTimeTracking->logStartTime($subtask['id'], $subtask['user_id']);
+ if ($subtask['status'] == SubtaskModel::STATUS_INPROGRESS) {
+ return $this->subtaskTimeTrackingModel->logStartTime($subtask['id'], $subtask['user_id']);
} else {
- return $this->subtaskTimeTracking->logEndTime($subtask['id'], $subtask['user_id']);
+ return $this->subtaskTimeTrackingModel->logEndTime($subtask['id'], $subtask['user_id']);
}
}
}
diff --git a/app/Subscriber/TransitionSubscriber.php b/app/Subscriber/TransitionSubscriber.php
index bd537484..26d08f88 100644
--- a/app/Subscriber/TransitionSubscriber.php
+++ b/app/Subscriber/TransitionSubscriber.php
@@ -3,7 +3,7 @@
namespace Kanboard\Subscriber;
use Kanboard\Event\TaskEvent;
-use Kanboard\Model\Task;
+use Kanboard\Model\TaskModel;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class TransitionSubscriber extends BaseSubscriber implements EventSubscriberInterface
@@ -11,7 +11,7 @@ class TransitionSubscriber extends BaseSubscriber implements EventSubscriberInte
public static function getSubscribedEvents()
{
return array(
- Task::EVENT_MOVE_COLUMN => 'execute',
+ TaskModel::EVENT_MOVE_COLUMN => 'execute',
);
}
@@ -22,7 +22,7 @@ class TransitionSubscriber extends BaseSubscriber implements EventSubscriberInte
$user_id = $this->userSession->getId();
if (! empty($user_id)) {
- $this->transition->save($user_id, $event->getAll());
+ $this->transitionModel->save($user_id, $event->getAll());
}
}
}
diff --git a/app/Template/action/index.php b/app/Template/action/index.php
index 63d63887..0a94e4f0 100644
--- a/app/Template/action/index.php
+++ b/app/Template/action/index.php
@@ -3,11 +3,11 @@
<ul>
<li>
<i class="fa fa-plus fa-fw"></i>
- <?= $this->url->link(t('Add a new action'), 'ActionCreation', 'create', array('project_id' => $project['id']), false, 'popover') ?>
+ <?= $this->url->link(t('Add a new action'), 'ActionCreationController', 'create', array('project_id' => $project['id']), false, 'popover') ?>
</li>
<li>
<i class="fa fa-copy fa-fw"></i>
- <?= $this->url->link(t('Import from another project'), 'ActionProject', 'project', array('project_id' => $project['id']), false, 'popover') ?>
+ <?= $this->url->link(t('Import from another project'), 'ProjectActionDuplicationController', 'show', array('project_id' => $project['id']), false, 'popover') ?>
</li>
</ul>
</div>
@@ -63,9 +63,9 @@
</ul>
</td>
<td>
- <?= $this->url->link(t('Remove'), 'action', 'confirm', array('project_id' => $project['id'], 'action_id' => $action['id']), false, 'popover') ?>
+ <?= $this->url->link(t('Remove'), 'ActionController', 'confirm', array('project_id' => $project['id'], 'action_id' => $action['id']), false, 'popover') ?>
</td>
</tr>
<?php endforeach ?>
</table>
-<?php endif ?> \ No newline at end of file
+<?php endif ?>
diff --git a/app/Template/action/remove.php b/app/Template/action/remove.php
index 070a7918..384bec7a 100644
--- a/app/Template/action/remove.php
+++ b/app/Template/action/remove.php
@@ -8,8 +8,8 @@
</p>
<div class="form-actions">
- <?= $this->url->link(t('Yes'), 'action', 'remove', array('project_id' => $project['id'], 'action_id' => $action['id']), true, 'btn btn-red') ?>
+ <?= $this->url->link(t('Yes'), 'ActionController', 'remove', array('project_id' => $project['id'], 'action_id' => $action['id']), true, 'btn btn-red') ?>
<?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'action', 'index', array('project_id' => $project['id']), false, 'close-popover') ?>
+ <?= $this->url->link(t('cancel'), 'ActionController', 'index', array('project_id' => $project['id']), false, 'close-popover') ?>
</div>
-</div> \ No newline at end of file
+</div>
diff --git a/app/Template/action_creation/create.php b/app/Template/action_creation/create.php
index bccb19b3..c0d2880e 100644
--- a/app/Template/action_creation/create.php
+++ b/app/Template/action_creation/create.php
@@ -1,7 +1,7 @@
<div class="page-header">
<h2><?= t('Add an action') ?></h2>
</div>
-<form class="popover-form" method="post" action="<?= $this->url->href('ActionCreation', 'event', array('project_id' => $project['id'])) ?>">
+<form class="popover-form" method="post" action="<?= $this->url->href('ActionCreationController', 'event', array('project_id' => $project['id'])) ?>">
<?= $this->form->csrf() ?>
<?= $this->form->hidden('project_id', $values) ?>
@@ -11,6 +11,6 @@
<div class="form-actions">
<button type="submit" class="btn btn-blue"><?= t('Next step') ?></button>
<?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'Action', 'index', array(), false, 'close-popover') ?>
+ <?= $this->url->link(t('cancel'), 'ActionController', 'index', array(), false, 'close-popover') ?>
</div>
-</form> \ No newline at end of file
+</form>
diff --git a/app/Template/action_creation/event.php b/app/Template/action_creation/event.php
index e7e5aaf9..cdf00310 100644
--- a/app/Template/action_creation/event.php
+++ b/app/Template/action_creation/event.php
@@ -2,7 +2,7 @@
<h2><?= t('Choose an event') ?></h2>
</div>
-<form class="popover-form" method="post" action="<?= $this->url->href('ActionCreation', 'params', array('project_id' => $project['id'])) ?>">
+<form class="popover-form" method="post" action="<?= $this->url->href('ActionCreationController', 'params', array('project_id' => $project['id'])) ?>">
<?= $this->form->csrf() ?>
@@ -22,6 +22,6 @@
<div class="form-actions">
<button type="submit" class="btn btn-blue"><?= t('Next step') ?></button>
<?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'action', 'index', array('project_id' => $project['id']), false, 'close-popover') ?>
+ <?= $this->url->link(t('cancel'), 'ActionController', 'index', array('project_id' => $project['id']), false, 'close-popover') ?>
</div>
-</form> \ No newline at end of file
+</form>
diff --git a/app/Template/action_creation/params.php b/app/Template/action_creation/params.php
index 59ff6ce9..fa892177 100644
--- a/app/Template/action_creation/params.php
+++ b/app/Template/action_creation/params.php
@@ -2,7 +2,7 @@
<h2><?= t('Define action parameters') ?></h2>
</div>
-<form class="popover-form" method="post" action="<?= $this->url->href('ActionCreation', 'save', array('project_id' => $project['id'])) ?>" autocomplete="off">
+<form class="popover-form" method="post" action="<?= $this->url->href('ActionCreationController', 'save', array('project_id' => $project['id'])) ?>" autocomplete="off">
<?= $this->form->csrf() ?>
@@ -35,6 +35,9 @@
<?php elseif ($this->text->contains($param_name, 'link_id')): ?>
<?= $this->form->label($param_desc, $param_name) ?>
<?= $this->form->select('params['.$param_name.']', $links_list, $values) ?>
+ <?php elseif ($param_name === 'priority'): ?>
+ <?= $this->form->label($param_desc, $param_name) ?>
+ <?= $this->form->select('params['.$param_name.']', $priorities_list, $values) ?>
<?php elseif ($this->text->contains($param_name, 'duration')): ?>
<?= $this->form->label($param_desc, $param_name) ?>
<?= $this->form->number('params['.$param_name.']', $values) ?>
@@ -47,6 +50,6 @@
<div class="form-actions">
<button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
<?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'action', 'index', array('project_id' => $project['id']), false, 'close-popover') ?>
+ <?= $this->url->link(t('cancel'), 'ActionController', 'index', array('project_id' => $project['id']), false, 'close-popover') ?>
</div>
-</form> \ No newline at end of file
+</form>
diff --git a/app/Template/activity/project.php b/app/Template/activity/project.php
index 176d9b99..ce1c8c0f 100644
--- a/app/Template/activity/project.php
+++ b/app/Template/activity/project.php
@@ -1,14 +1,14 @@
<section id="main">
- <?= $this->projectHeader->render($project, 'Analytic', $this->app->getRouterAction()) ?>
+ <?= $this->projectHeader->render($project, 'AnalyticController', $this->app->getRouterAction()) ?>
<?php if ($project['is_public']): ?>
<div class="menu-inline pull-right">
<ul>
- <li><i class="fa fa-rss-square fa-fw"></i><?= $this->url->link(t('RSS feed'), 'feed', 'project', array('token' => $project['token']), false, '', '', true) ?></li>
- <li><i class="fa fa-calendar fa-fw"></i><?= $this->url->link(t('iCal feed'), 'ical', 'project', array('token' => $project['token'])) ?></li>
+ <li><i class="fa fa-rss-square fa-fw"></i><?= $this->url->link(t('RSS feed'), 'FeedController', 'project', array('token' => $project['token']), false, '', '', true) ?></li>
+ <li><i class="fa fa-calendar fa-fw"></i><?= $this->url->link(t('iCal feed'), 'ICalendarController', 'project', array('token' => $project['token'])) ?></li>
</ul>
</div>
<?php endif ?>
<?= $this->render('event/events', array('events' => $events)) ?>
-</section> \ No newline at end of file
+</section>
diff --git a/app/Template/analytic/burndown.php b/app/Template/analytic/burndown.php
index ed6c8aeb..e979595d 100644
--- a/app/Template/analytic/burndown.php
+++ b/app/Template/analytic/burndown.php
@@ -12,7 +12,7 @@
<hr/>
-<form method="post" class="form-inline" action="<?= $this->url->href('analytic', 'burndown', array('project_id' => $project['id'])) ?>" autocomplete="off">
+<form method="post" class="form-inline" action="<?= $this->url->href('AnalyticController', 'burndown', array('project_id' => $project['id'])) ?>" autocomplete="off">
<?= $this->form->csrf() ?>
diff --git a/app/Template/analytic/cfd.php b/app/Template/analytic/cfd.php
index ee259c70..8dfb5b00 100644
--- a/app/Template/analytic/cfd.php
+++ b/app/Template/analytic/cfd.php
@@ -12,7 +12,7 @@
<hr/>
-<form method="post" class="form-inline" action="<?= $this->url->href('analytic', 'cfd', array('project_id' => $project['id'])) ?>" autocomplete="off">
+<form method="post" class="form-inline" action="<?= $this->url->href('AnalyticController', 'cfd', array('project_id' => $project['id'])) ?>" autocomplete="off">
<?= $this->form->csrf() ?>
diff --git a/app/Template/analytic/compare_hours.php b/app/Template/analytic/compare_hours.php
index 8249e7ba..70d8d02b 100644
--- a/app/Template/analytic/compare_hours.php
+++ b/app/Template/analytic/compare_hours.php
@@ -34,13 +34,13 @@
<?php foreach ($paginator->getCollection() as $task): ?>
<tr>
<td class="task-table color-<?= $task['color_id'] ?>">
- <?= $this->url->link('#'.$this->text->e($task['id']), 'task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, '', t('View this task')) ?>
+ <?= $this->url->link('#'.$this->text->e($task['id']), 'TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, '', t('View this task')) ?>
</td>
<td>
- <?= $this->url->link($this->text->e($task['title']), 'task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, '', t('View this task')) ?>
+ <?= $this->url->link($this->text->e($task['title']), 'TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, '', t('View this task')) ?>
</td>
<td>
- <?php if ($task['is_active'] == \Kanboard\Model\Task::STATUS_OPEN): ?>
+ <?php if ($task['is_active'] == \Kanboard\Model\TaskModel::STATUS_OPEN): ?>
<?= t('Open') ?>
<?php else: ?>
<?= t('Closed') ?>
diff --git a/app/Template/analytic/layout.php b/app/Template/analytic/layout.php
index 35793cbb..e3c6099f 100644
--- a/app/Template/analytic/layout.php
+++ b/app/Template/analytic/layout.php
@@ -1,5 +1,5 @@
<section id="main">
- <?= $this->projectHeader->render($project, 'Listing', 'show') ?>
+ <?= $this->projectHeader->render($project, 'TaskListController', 'show') ?>
<section class="sidebar-container">
<?= $this->render($sidebar_template, array('project' => $project)) ?>
@@ -8,6 +8,3 @@
</div>
</section>
</section>
-
-<?= $this->asset->js('assets/js/vendor/d3.v3.min.js') ?>
-<?= $this->asset->js('assets/js/vendor/c3.min.js') ?> \ No newline at end of file
diff --git a/app/Template/analytic/lead_cycle_time.php b/app/Template/analytic/lead_cycle_time.php
index 82ffe534..2dccc136 100644
--- a/app/Template/analytic/lead_cycle_time.php
+++ b/app/Template/analytic/lead_cycle_time.php
@@ -16,7 +16,7 @@
<div id="chart" data-metrics='<?= json_encode($metrics, JSON_HEX_APOS) ?>' data-label-cycle="<?= t('Cycle Time') ?>" data-label-lead="<?= t('Lead Time') ?>"></div>
- <form method="post" class="form-inline" action="<?= $this->url->href('analytic', 'leadAndCycleTime', array('project_id' => $project['id'])) ?>" autocomplete="off">
+ <form method="post" class="form-inline" action="<?= $this->url->href('AnalyticController', 'leadAndCycleTime', array('project_id' => $project['id'])) ?>" autocomplete="off">
<?= $this->form->csrf() ?>
diff --git a/app/Template/analytic/sidebar.php b/app/Template/analytic/sidebar.php
index 76289b9f..de3dccf8 100644
--- a/app/Template/analytic/sidebar.php
+++ b/app/Template/analytic/sidebar.php
@@ -1,29 +1,29 @@
<div class="sidebar">
<h2><?= t('Reportings') ?></h2>
<ul>
- <li <?= $this->app->checkMenuSelection('analytic', 'tasks') ?>>
- <?= $this->url->link(t('Task distribution'), 'analytic', 'tasks', array('project_id' => $project['id'])) ?>
+ <li <?= $this->app->checkMenuSelection('AnalyticController', 'tasks') ?>>
+ <?= $this->url->link(t('Task distribution'), 'AnalyticController', 'tasks', array('project_id' => $project['id'])) ?>
</li>
- <li <?= $this->app->checkMenuSelection('analytic', 'users') ?>>
- <?= $this->url->link(t('User repartition'), 'analytic', 'users', array('project_id' => $project['id'])) ?>
+ <li <?= $this->app->checkMenuSelection('AnalyticController', 'users') ?>>
+ <?= $this->url->link(t('User repartition'), 'AnalyticController', 'users', array('project_id' => $project['id'])) ?>
</li>
- <li <?= $this->app->checkMenuSelection('analytic', 'cfd') ?>>
- <?= $this->url->link(t('Cumulative flow diagram'), 'analytic', 'cfd', array('project_id' => $project['id'])) ?>
+ <li <?= $this->app->checkMenuSelection('AnalyticController', 'cfd') ?>>
+ <?= $this->url->link(t('Cumulative flow diagram'), 'AnalyticController', 'cfd', array('project_id' => $project['id'])) ?>
</li>
- <li <?= $this->app->checkMenuSelection('analytic', 'burndown') ?>>
- <?= $this->url->link(t('Burndown chart'), 'analytic', 'burndown', array('project_id' => $project['id'])) ?>
+ <li <?= $this->app->checkMenuSelection('AnalyticController', 'burndown') ?>>
+ <?= $this->url->link(t('Burndown chart'), 'AnalyticController', 'burndown', array('project_id' => $project['id'])) ?>
</li>
- <li <?= $this->app->checkMenuSelection('analytic', 'averageTimeByColumn') ?>>
- <?= $this->url->link(t('Average time into each column'), 'analytic', 'averageTimeByColumn', array('project_id' => $project['id'])) ?>
+ <li <?= $this->app->checkMenuSelection('AnalyticController', 'averageTimeByColumn') ?>>
+ <?= $this->url->link(t('Average time into each column'), 'AnalyticController', 'averageTimeByColumn', array('project_id' => $project['id'])) ?>
</li>
- <li <?= $this->app->checkMenuSelection('analytic', 'leadAndCycleTime') ?>>
- <?= $this->url->link(t('Lead and cycle time'), 'analytic', 'leadAndCycleTime', array('project_id' => $project['id'])) ?>
+ <li <?= $this->app->checkMenuSelection('AnalyticController', 'leadAndCycleTime') ?>>
+ <?= $this->url->link(t('Lead and cycle time'), 'AnalyticController', 'leadAndCycleTime', array('project_id' => $project['id'])) ?>
</li>
- <li <?= $this->app->checkMenuSelection('analytic', 'compareHours') ?>>
- <?= $this->url->link(t('Estimated vs actual time'), 'analytic', 'compareHours', array('project_id' => $project['id'])) ?>
+ <li <?= $this->app->checkMenuSelection('AnalyticController', 'compareHours') ?>>
+ <?= $this->url->link(t('Estimated vs actual time'), 'AnalyticController', 'compareHours', array('project_id' => $project['id'])) ?>
</li>
-
+
<?= $this->hook->render('template:analytic:sidebar', array('project' => $project)) ?>
-
+
</ul>
</div>
diff --git a/app/Template/app/calendar.php b/app/Template/app/calendar.php
deleted file mode 100644
index a154203b..00000000
--- a/app/Template/app/calendar.php
+++ /dev/null
@@ -1,5 +0,0 @@
-<div id="calendar"
- data-check-url="<?= $this->url->href('calendar', 'user', array('user_id' => $user['id'])) ?>"
- data-save-url="<?= $this->url->href('calendar', 'save') ?>"
->
-</div>
diff --git a/app/Template/app/overview.php b/app/Template/app/overview.php
deleted file mode 100644
index 0b354791..00000000
--- a/app/Template/app/overview.php
+++ /dev/null
@@ -1,12 +0,0 @@
-<div class="filter-box">
- <form method="get" action="<?= $this->url->dir() ?>" class="search">
- <?= $this->form->hidden('controller', array('controller' => 'search')) ?>
- <?= $this->form->hidden('action', array('action' => 'index')) ?>
- <?= $this->form->text('search', array(), array(), array('placeholder="'.t('Search').'"'), 'form-input-large') ?>
- <?= $this->render('app/filters_helper') ?>
- </form>
-</div>
-
-<?= $this->render('app/projects', array('paginator' => $project_paginator, 'user' => $user)) ?>
-<?= $this->render('app/tasks', array('paginator' => $task_paginator, 'user' => $user)) ?>
-<?= $this->render('app/subtasks', array('paginator' => $subtask_paginator, 'user' => $user)) ?> \ No newline at end of file
diff --git a/app/Template/app/sidebar.php b/app/Template/app/sidebar.php
deleted file mode 100644
index 66d15b14..00000000
--- a/app/Template/app/sidebar.php
+++ /dev/null
@@ -1,27 +0,0 @@
-<div class="sidebar">
- <h2><?= $this->text->e($user['name'] ?: $user['username']) ?></h2>
- <ul>
- <li <?= $this->app->checkMenuSelection('app', 'index') ?>>
- <?= $this->url->link(t('Overview'), 'app', 'index', array('user_id' => $user['id'])) ?>
- </li>
- <li <?= $this->app->checkMenuSelection('app', 'projects') ?>>
- <?= $this->url->link(t('My projects'), 'app', 'projects', array('user_id' => $user['id'])) ?>
- </li>
- <li <?= $this->app->checkMenuSelection('app', 'tasks') ?>>
- <?= $this->url->link(t('My tasks'), 'app', 'tasks', array('user_id' => $user['id'])) ?>
- </li>
- <li <?= $this->app->checkMenuSelection('app', 'subtasks') ?>>
- <?= $this->url->link(t('My subtasks'), 'app', 'subtasks', array('user_id' => $user['id'])) ?>
- </li>
- <li <?= $this->app->checkMenuSelection('app', 'calendar') ?>>
- <?= $this->url->link(t('My calendar'), 'app', 'calendar', array('user_id' => $user['id'])) ?>
- </li>
- <li <?= $this->app->checkMenuSelection('app', 'activity') ?>>
- <?= $this->url->link(t('My activity stream'), 'app', 'activity', array('user_id' => $user['id'])) ?>
- </li>
- <li <?= $this->app->checkMenuSelection('app', 'notifications') ?>>
- <?= $this->url->link(t('My notifications'), 'app', 'notifications', array('user_id' => $user['id'])) ?>
- </li>
- <?= $this->hook->render('template:dashboard:sidebar') ?>
- </ul>
-</div> \ No newline at end of file
diff --git a/app/Template/auth/index.php b/app/Template/auth/index.php
index cc562170..45bbdb8e 100644
--- a/app/Template/auth/index.php
+++ b/app/Template/auth/index.php
@@ -7,7 +7,7 @@
<?php endif ?>
<?php if (! HIDE_LOGIN_FORM): ?>
- <form method="post" action="<?= $this->url->href('auth', 'check') ?>">
+ <form method="post" action="<?= $this->url->href('AuthController', 'check') ?>">
<?= $this->form->csrf() ?>
@@ -19,7 +19,7 @@
<?php if (isset($captcha) && $captcha): ?>
<?= $this->form->label(t('Enter the text below'), 'captcha') ?>
- <img src="<?= $this->url->href('Captcha', 'image') ?>"/>
+ <img src="<?= $this->url->href('CaptchaController', 'image') ?>" alt="Captcha">
<?= $this->form->text('captcha', array(), $errors, array('required')) ?>
<?php endif ?>
@@ -32,11 +32,11 @@
</div>
<?php if ($this->app->config('password_reset') == 1): ?>
<div class="reset-password">
- <?= $this->url->link(t('Forgot password?'), 'PasswordReset', 'create') ?>
+ <?= $this->url->link(t('Forgot password?'), 'PasswordResetController', 'create') ?>
</div>
<?php endif ?>
</form>
<?php endif ?>
<?= $this->hook->render('template:auth:login-form:after') ?>
-</div> \ No newline at end of file
+</div>
diff --git a/app/Template/avatar_file/show.php b/app/Template/avatar_file/show.php
index 266a2ccb..37c56cec 100644
--- a/app/Template/avatar_file/show.php
+++ b/app/Template/avatar_file/show.php
@@ -4,17 +4,20 @@
<?= $this->avatar->render($user['id'], $user['username'], $user['name'], $user['email'], $user['avatar_path'], '') ?>
-<form method="post" enctype="multipart/form-data" action="<?= $this->url->href('AvatarFile', 'upload', array('user_id' => $user['id'])) ?>">
+<div class="form-actions">
+<?php if (! empty($user['avatar_path'])): ?>
+ <?= $this->url->link(t('Remove my image'), 'AvatarFileController', 'remove', array('user_id' => $user['id']), true, 'btn btn-red') ?>
+<?php endif ?>
+</div>
+
+<hr>
+
+<h3><?= t('Upload my avatar image') ?></h3>
+<form method="post" enctype="multipart/form-data" action="<?= $this->url->href('AvatarFileController', 'upload', array('user_id' => $user['id'])) ?>">
<?= $this->form->csrf() ?>
- <?= $this->form->label(t('Upload my avatar image'), 'avatar') ?>
<?= $this->form->file('avatar') ?>
<div class="form-actions">
- <?php if (! empty($user['avatar_path'])): ?>
- <?= $this->url->link(t('Remove my image'), 'AvatarFile', 'remove', array('user_id' => $user['id']), true, 'btn btn-red') ?>
- <?php endif ?>
- <button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
- <?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'user', 'show', array('user_id' => $user['id'])) ?>
+ <button type="submit" class="btn btn-blue"><?= t('Upload my avatar image') ?></button>
</div>
</form>
diff --git a/app/Template/board/table_column.php b/app/Template/board/table_column.php
index 48538c88..f7a9f6ad 100644
--- a/app/Template/board/table_column.php
+++ b/app/Template/board/table_column.php
@@ -12,9 +12,9 @@
<!-- column in expanded mode -->
<div class="board-column-expanded">
- <?php if (! $not_editable && $this->user->hasProjectAccess('taskcreation', 'create', $column['project_id'])): ?>
+ <?php if (! $not_editable && $this->user->hasProjectAccess('TaskCreationController', 'show', $column['project_id'])): ?>
<div class="board-add-icon">
- <?= $this->url->link('+', 'taskcreation', 'create', array('project_id' => $column['project_id'], 'column_id' => $column['id'], 'swimlane_id' => $swimlane['id']), false, 'popover', t('Add a new task')) ?>
+ <?= $this->url->link('+', 'TaskCreationController', 'show', array('project_id' => $column['project_id'], 'column_id' => $column['id'], 'swimlane_id' => $swimlane['id']), false, 'popover', t('Add a new task')) ?>
</div>
<?php endif ?>
@@ -35,11 +35,17 @@
<i class="fa fa-minus-square fa-fw"></i>
<a href="#" class="board-toggle-column-view" data-column-id="<?= $column['id'] ?>"><?= t('Hide this column') ?></a>
</li>
- <?php if ($this->user->hasProjectAccess('BoardPopover', 'closeColumnTasks', $column['project_id']) && $column['nb_tasks'] > 0): ?>
+ <?php if ($this->user->hasProjectAccess('TaskCreationController', 'show', $column['project_id'])): ?>
<li>
- <i class="fa fa-close fa-fw"></i>
- <?= $this->url->link(t('Close all tasks of this column'), 'BoardPopover', 'confirmCloseColumnTasks', array('project_id' => $column['project_id'], 'column_id' => $column['id'], 'swimlane_id' => $swimlane['id']), false, 'popover') ?>
+ <i class="fa fa-align-justify fa-fw" aria-hidden="true"></i>
+ <?= $this->url->link(t('Create tasks in bulk'), 'TaskBulkController', 'show', array('project_id' => $column['project_id'], 'column_id' => $column['id'], 'swimlane_id' => $swimlane['id']), false, 'popover') ?>
</li>
+ <?php if ($column['nb_tasks'] > 0): ?>
+ <li>
+ <i class="fa fa-close fa-fw"></i>
+ <?= $this->url->link(t('Close all tasks of this column'), 'BoardPopoverController', 'confirmCloseColumnTasks', array('project_id' => $column['project_id'], 'column_id' => $column['id'], 'swimlane_id' => $swimlane['id']), false, 'popover') ?>
+ </li>
+ <?php endif ?>
<?php endif ?>
</ul>
</span>
@@ -47,7 +53,7 @@
</span>
<?php if (! $not_editable && ! empty($column['description'])): ?>
- <span class="tooltip pull-right" title='<?= $this->text->e($this->text->markdown($column['description'])) ?>'>
+ <span class="tooltip pull-right" title="<?= $this->text->markdownAttribute($column['description']) ?>">
&nbsp;<i class="fa fa-info-circle"></i>
</span>
<?php endif ?>
diff --git a/app/Template/board/table_container.php b/app/Template/board/table_container.php
index e30f9ce8..a93e7001 100644
--- a/app/Template/board/table_container.php
+++ b/app/Template/board/table_container.php
@@ -10,10 +10,10 @@
class="board-project-<?= $project['id'] ?>"
data-project-id="<?= $project['id'] ?>"
data-check-interval="<?= $board_private_refresh_interval ?>"
- data-save-url="<?= $this->url->href('board', 'save', array('project_id' => $project['id'])) ?>"
- data-reload-url="<?= $this->url->href('board', 'reload', array('project_id' => $project['id'])) ?>"
- data-check-url="<?= $this->url->href('board', 'check', array('project_id' => $project['id'], 'timestamp' => time())) ?>"
- data-task-creation-url="<?= $this->url->href('taskcreation', 'create', array('project_id' => $project['id'])) ?>"
+ data-save-url="<?= $this->url->href('BoardAjaxController', 'save', array('project_id' => $project['id'])) ?>"
+ data-reload-url="<?= $this->url->href('BoardAjaxController', 'reload', array('project_id' => $project['id'])) ?>"
+ data-check-url="<?= $this->url->href('BoardAjaxController', 'check', array('project_id' => $project['id'], 'timestamp' => time())) ?>"
+ data-task-creation-url="<?= $this->url->href('TaskCreationController', 'show', array('project_id' => $project['id'])) ?>"
>
<?php endif ?>
@@ -55,4 +55,4 @@
</table>
<?php endif ?>
-</div> \ No newline at end of file
+</div>
diff --git a/app/Template/board/table_swimlane.php b/app/Template/board/table_swimlane.php
index 349b9acb..c5937e01 100644
--- a/app/Template/board/table_swimlane.php
+++ b/app/Template/board/table_swimlane.php
@@ -14,7 +14,7 @@
<span
title="<?= t('Description') ?>"
class="tooltip"
- data-href="<?= $this->url->href('BoardTooltip', 'swimlane', array('swimlane_id' => $swimlane['id'], 'project_id' => $project['id'])) ?>">
+ data-href="<?= $this->url->href('BoardTooltipController', 'swimlane', array('swimlane_id' => $swimlane['id'], 'project_id' => $project['id'])) ?>">
<i class="fa fa-info-circle"></i>
</span>
<?php endif ?>
diff --git a/app/Template/board/task_avatar.php b/app/Template/board/task_avatar.php
index 39f6b54d..14b55476 100644
--- a/app/Template/board/task_avatar.php
+++ b/app/Template/board/task_avatar.php
@@ -1,9 +1,9 @@
<?php if (! empty($task['owner_id'])): ?>
<div class="task-board-avatars">
<span
- <?php if ($this->user->hasProjectAccess('taskmodification', 'edit', $task['project_id'])): ?>
+ <?php if ($this->user->hasProjectAccess('TaskModificationController', 'edit', $task['project_id'])): ?>
class="task-board-assignee task-board-change-assignee"
- data-url="<?= $this->url->href('BoardPopover', 'changeAssignee', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>">
+ data-url="<?= $this->url->href('TaskPopoverController', 'changeAssignee', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>">
<?php else: ?>
class="task-board-assignee">
<?php endif ?>
diff --git a/app/Template/board/task_footer.php b/app/Template/board/task_footer.php
index a9d381a3..11df8962 100644
--- a/app/Template/board/task_footer.php
+++ b/app/Template/board/task_footer.php
@@ -6,12 +6,12 @@
<?php else: ?>
<?= $this->url->link(
$this->text->e($task['category_name']),
- 'boardPopover',
+ 'TaskPopoverController',
'changeCategory',
array('task_id' => $task['id'], 'project_id' => $task['project_id']),
false,
'popover' . (! empty($task['category_description']) ? ' tooltip' : ''),
- ! empty($task['category_description']) ? $this->text->markdown($task['category_description']) : t('Change category')
+ ! empty($task['category_description']) ? $this->text->markdownAttribute($task['category_description']) : t('Change category')
) ?>
<?php endif ?>
</span>
@@ -33,36 +33,36 @@
</span>
<?php endif ?>
- <?php if ($task['recurrence_status'] == \Kanboard\Model\Task::RECURRING_STATUS_PENDING): ?>
- <span title="<?= t('Recurrence') ?>" class="tooltip" data-href="<?= $this->url->href('BoardTooltip', 'recurrence', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>"><i class="fa fa-refresh fa-rotate-90"></i></span>
+ <?php if ($task['recurrence_status'] == \Kanboard\Model\TaskModel::RECURRING_STATUS_PENDING): ?>
+ <span title="<?= t('Recurrence') ?>" class="tooltip" data-href="<?= $this->url->href('BoardTooltipController', 'recurrence', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>"><i class="fa fa-refresh fa-rotate-90"></i></span>
<?php endif ?>
- <?php if ($task['recurrence_status'] == \Kanboard\Model\Task::RECURRING_STATUS_PROCESSED): ?>
- <span title="<?= t('Recurrence') ?>" class="tooltip" data-href="<?= $this->url->href('BoardTooltip', 'recurrence', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>"><i class="fa fa-refresh fa-rotate-90 fa-inverse"></i></span>
+ <?php if ($task['recurrence_status'] == \Kanboard\Model\TaskModel::RECURRING_STATUS_PROCESSED): ?>
+ <span title="<?= t('Recurrence') ?>" class="tooltip" data-href="<?= $this->url->href('BoardTooltipController', 'recurrence', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>"><i class="fa fa-refresh fa-rotate-90 fa-inverse"></i></span>
<?php endif ?>
<?php if (! empty($task['nb_links'])): ?>
- <span title="<?= t('Links') ?>" class="tooltip" data-href="<?= $this->url->href('BoardTooltip', 'tasklinks', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>"><i class="fa fa-code-fork fa-fw"></i><?= $task['nb_links'] ?></span>
+ <span title="<?= t('Links') ?>" class="tooltip" data-href="<?= $this->url->href('BoardTooltipController', 'tasklinks', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>"><i class="fa fa-code-fork fa-fw"></i><?= $task['nb_links'] ?></span>
<?php endif ?>
<?php if (! empty($task['nb_external_links'])): ?>
- <span title="<?= t('External links') ?>" class="tooltip" data-href="<?= $this->url->href('BoardTooltip', 'externallinks', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>"><i class="fa fa-external-link fa-fw"></i><?= $task['nb_external_links'] ?></span>
+ <span title="<?= t('External links') ?>" class="tooltip" data-href="<?= $this->url->href('BoardTooltipController', 'externallinks', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>"><i class="fa fa-external-link fa-fw"></i><?= $task['nb_external_links'] ?></span>
<?php endif ?>
<?php if (! empty($task['nb_subtasks'])): ?>
- <span title="<?= t('Sub-Tasks') ?>" class="tooltip" data-href="<?= $this->url->href('BoardTooltip', 'subtasks', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>"><i class="fa fa-bars"></i>&nbsp;<?= round($task['nb_completed_subtasks']/$task['nb_subtasks']*100, 0).'%' ?></span>
+ <span title="<?= t('Sub-Tasks') ?>" class="tooltip" data-href="<?= $this->url->href('BoardTooltipController', 'subtasks', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>"><i class="fa fa-bars"></i>&nbsp;<?= round($task['nb_completed_subtasks']/$task['nb_subtasks']*100, 0).'%' ?></span>
<?php endif ?>
<?php if (! empty($task['nb_files'])): ?>
- <span title="<?= t('Attachments') ?>" class="tooltip" data-href="<?= $this->url->href('BoardTooltip', 'attachments', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>"><i class="fa fa-paperclip"></i>&nbsp;<?= $task['nb_files'] ?></span>
+ <span title="<?= t('Attachments') ?>" class="tooltip" data-href="<?= $this->url->href('BoardTooltipController', 'attachments', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>"><i class="fa fa-paperclip"></i>&nbsp;<?= $task['nb_files'] ?></span>
<?php endif ?>
<?php if (! empty($task['nb_comments'])): ?>
- <span title="<?= $task['nb_comments'] == 1 ? t('%d comment', $task['nb_comments']) : t('%d comments', $task['nb_comments']) ?>" class="tooltip" data-href="<?= $this->url->href('BoardTooltip', 'comments', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>"><i class="fa fa-comment-o"></i>&nbsp;<?= $task['nb_comments'] ?></span>
+ <span title="<?= $task['nb_comments'] == 1 ? t('%d comment', $task['nb_comments']) : t('%d comments', $task['nb_comments']) ?>" class="tooltip" data-href="<?= $this->url->href('BoardTooltipController', 'comments', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>"><i class="fa fa-comment-o"></i>&nbsp;<?= $task['nb_comments'] ?></span>
<?php endif ?>
<?php if (! empty($task['description'])): ?>
- <span title="<?= t('Description') ?>" class="tooltip" data-href="<?= $this->url->href('BoardTooltip', 'description', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>">
+ <span title="<?= t('Description') ?>" class="tooltip" data-href="<?= $this->url->href('BoardTooltipController', 'description', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>">
<i class="fa fa-file-text-o"></i>
</span>
<?php endif ?>
@@ -76,7 +76,7 @@
<i class="fa fa-flag flag-milestone"></i>
</span>
<?php endif ?>
-
+
<?= $this->hook->render('template:board:task:icons', array('task' => $task)) ?>
<?= $this->task->formatPriority($project, $task) ?>
diff --git a/app/Template/board/task_menu.php b/app/Template/board/task_menu.php
deleted file mode 100644
index c0d97cda..00000000
--- a/app/Template/board/task_menu.php
+++ /dev/null
@@ -1,18 +0,0 @@
-<span class="dropdown">
- <a href="#" class="dropdown-menu"><?= '#'.$task['id'] ?> <i class="fa fa-caret-down"></i></a>
- <ul>
- <li><i class="fa fa-user fa-fw"></i>&nbsp;<?= $this->url->link(t('Change assignee'), 'BoardPopover', 'changeAssignee', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?></li>
- <li><i class="fa fa-tag fa-fw"></i>&nbsp;<?= $this->url->link(t('Change category'), 'BoardPopover', 'changeCategory', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?></li>
- <li><i class="fa fa-align-left fa-fw"></i>&nbsp;<?= $this->url->link(t('Change description'), 'taskmodification', 'description', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?></li>
- <li><i class="fa fa-pencil-square-o fa-fw"></i>&nbsp;<?= $this->url->link(t('Edit this task'), 'taskmodification', 'edit', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?></li>
- <li><i class="fa fa-comment-o fa-fw"></i>&nbsp;<?= $this->url->link(t('Add a comment'), 'comment', 'create', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?></li>
- <li><i class="fa fa-code-fork fa-fw"></i>&nbsp;<?= $this->url->link(t('Add internal link'), 'TaskInternalLink', 'create', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?></li>
- <li><i class="fa fa-external-link fa-fw"></i>&nbsp;<?= $this->url->link(t('Add external link'), 'TaskExternalLink', 'find', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?></li>
- <li><i class="fa fa-camera fa-fw"></i>&nbsp;<?= $this->url->link(t('Add a screenshot'), 'BoardPopover', 'screenshot', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?></li>
- <?php if ($task['is_active'] == 1): ?>
- <li><i class="fa fa-close fa-fw"></i>&nbsp;<?= $this->url->link(t('Close this task'), 'taskstatus', 'close', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?></li>
- <?php else: ?>
- <li><i class="fa fa-check-square-o fa-fw"></i>&nbsp;<?= $this->url->link(t('Open this task'), 'taskstatus', 'open', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?></li>
- <?php endif ?>
- </ul>
-</span> \ No newline at end of file
diff --git a/app/Template/board/task_private.php b/app/Template/board/task_private.php
index 19bcbcfa..94b396a6 100644
--- a/app/Template/board/task_private.php
+++ b/app/Template/board/task_private.php
@@ -1,6 +1,6 @@
<div class="
task-board
- <?= $task['is_active'] == 1 ? ($this->user->hasProjectAccess('board', 'save', $task['project_id']) ? 'draggable-item ' : '').'task-board-status-open '.($task['date_modification'] > (time() - $board_highlight_period) ? 'task-board-recent' : '') : 'task-board-status-closed' ?>
+ <?= $task['is_active'] == 1 ? ($this->user->hasProjectAccess('BoardViewController', 'save', $task['project_id']) ? 'draggable-item ' : '').'task-board-status-open '.($task['date_modification'] > (time() - $board_highlight_period) ? 'task-board-recent' : '') : 'task-board-status-closed' ?>
color-<?= $task['color_id'] ?>"
data-task-id="<?= $task['id'] ?>"
data-column-id="<?= $task['column_id'] ?>"
@@ -9,15 +9,15 @@
data-owner-id="<?= $task['owner_id'] ?>"
data-category-id="<?= $task['category_id'] ?>"
data-due-date="<?= $task['date_due'] ?>"
- data-task-url="<?= $this->url->href('task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>">
+ data-task-url="<?= $this->url->href('TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>">
<div class="task-board-sort-handle" style="display: none;"><i class="fa fa-arrows-alt"></i></div>
<?php if ($this->board->isCollapsed($task['project_id'])): ?>
<div class="task-board-collapsed">
<div class="task-board-saving-icon" style="display: none;"><i class="fa fa-spinner fa-pulse"></i></div>
- <?php if ($this->user->hasProjectAccess('taskmodification', 'edit', $task['project_id'])): ?>
- <?= $this->render('board/task_menu', array('task' => $task)) ?>
+ <?php if ($this->user->hasProjectAccess('TaskModificationController', 'edit', $task['project_id'])): ?>
+ <?= $this->render('task/dropdown', array('task' => $task)) ?>
<?php else: ?>
<strong><?= '#'.$task['id'] ?></strong>
<?php endif ?>
@@ -27,13 +27,13 @@
<?= $this->text->e($this->user->getInitials($task['assignee_name'] ?: $task['assignee_username'])) ?>
</span> -
<?php endif ?>
- <?= $this->url->link($this->text->e($task['title']), 'task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'task-board-collapsed-title tooltip', $this->text->e($task['title'])) ?>
+ <?= $this->url->link($this->text->e($task['title']), 'TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'task-board-collapsed-title tooltip', $this->text->e($task['title'])) ?>
</div>
<?php else: ?>
<div class="task-board-expanded">
<div class="task-board-saving-icon" style="display: none;"><i class="fa fa-spinner fa-pulse fa-2x"></i></div>
- <?php if ($this->user->hasProjectAccess('taskmodification', 'edit', $task['project_id'])): ?>
- <?= $this->render('board/task_menu', array('task' => $task)) ?>
+ <?php if ($this->user->hasProjectAccess('TaskModificationController', 'edit', $task['project_id'])): ?>
+ <?= $this->render('task/dropdown', array('task' => $task)) ?>
<?php else: ?>
<strong><?= '#'.$task['id'] ?></strong>
<?php endif ?>
@@ -48,7 +48,7 @@
<?= $this->hook->render('template:board:private:task:before-title', array('task' => $task)) ?>
<div class="task-board-title">
- <?= $this->url->link($this->text->e($task['title']), 'task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, '', t('View this task')) ?>
+ <?= $this->url->link($this->text->e($task['title']), 'TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, '', t('View this task')) ?>
</div>
<?= $this->hook->render('template:board:private:task:after-title', array('task' => $task)) ?>
diff --git a/app/Template/board/task_public.php b/app/Template/board/task_public.php
index a53d42c8..82eb6535 100644
--- a/app/Template/board/task_public.php
+++ b/app/Template/board/task_public.php
@@ -1,6 +1,6 @@
<div class="task-board color-<?= $task['color_id'] ?> <?= $task['date_modification'] > time() - $board_highlight_period ? 'task-board-recent' : '' ?>">
- <?= $this->url->link('#'.$task['id'], 'task', 'readonly', array('task_id' => $task['id'], 'token' => $project['token'])) ?>
+ <?= $this->url->link('#'.$task['id'], 'TaskViewController', 'readonly', array('task_id' => $task['id'], 'token' => $project['token'])) ?>
<?php if ($task['reference']): ?>
<span class="task-board-reference" title="<?= t('Reference') ?>">
@@ -12,7 +12,7 @@
<?= $this->hook->render('template:board:public:task:before-title', array('task' => $task)) ?>
<div class="task-board-title">
- <?= $this->url->link($this->text->e($task['title']), 'task', 'readonly', array('task_id' => $task['id'], 'token' => $project['token'])) ?>
+ <?= $this->url->link($this->text->e($task['title']), 'TaskViewController', 'readonly', array('task_id' => $task['id'], 'token' => $project['token'])) ?>
</div>
<?= $this->hook->render('template:board:public:task:after-title', array('task' => $task)) ?>
@@ -21,4 +21,4 @@
'not_editable' => $not_editable,
'project' => $project,
)) ?>
-</div> \ No newline at end of file
+</div>
diff --git a/app/Template/board/tooltip_files.php b/app/Template/board/tooltip_files.php
index 5ade5b5b..6f9e2640 100644
--- a/app/Template/board/tooltip_files.php
+++ b/app/Template/board/tooltip_files.php
@@ -9,9 +9,9 @@
</tr>
<tr>
<td>
- <i class="fa fa-download fa-fw"></i><?= $this->url->link(t('download'), 'FileViewer', 'download', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'file_id' => $file['id'])) ?>
+ <i class="fa fa-download fa-fw"></i><?= $this->url->link(t('download'), 'FileViewerController', 'download', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'file_id' => $file['id'])) ?>
<?php if ($file['is_image'] == 1): ?>
- &nbsp;<i class="fa fa-eye"></i> <?= $this->url->link(t('open file'), 'FileViewer', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'file_id' => $file['id']), false, 'popover') ?>
+ &nbsp;<i class="fa fa-eye"></i> <?= $this->url->link(t('open file'), 'FileViewerController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'file_id' => $file['id']), false, 'popover') ?>
<?php endif ?>
</td>
</tr>
diff --git a/app/Template/board/tooltip_tasklinks.php b/app/Template/board/tooltip_tasklinks.php
index 6424c39d..d1156cbe 100644
--- a/app/Template/board/tooltip_tasklinks.php
+++ b/app/Template/board/tooltip_tasklinks.php
@@ -12,7 +12,7 @@
<td class="column-60">
<?= $this->url->link(
$this->text->e('#'.$link['task_id'].' '.$link['title']),
- 'task', 'show', array('task_id' => $link['task_id'], 'project_id' => $link['project_id']),
+ 'TaskViewController', 'show', array('task_id' => $link['task_id'], 'project_id' => $link['project_id']),
false,
$link['is_active'] ? '' : 'task-link-closed'
) ?>
@@ -31,4 +31,4 @@
<?php endforeach ?>
<?php endforeach ?>
</table>
-</div> \ No newline at end of file
+</div>
diff --git a/app/Template/board/view_private.php b/app/Template/board/view_private.php
index 13702273..a89e7d2b 100644
--- a/app/Template/board/view_private.php
+++ b/app/Template/board/view_private.php
@@ -1,6 +1,6 @@
<section id="main">
- <?= $this->projectHeader->render($project, 'Board', 'show', true) ?>
+ <?= $this->projectHeader->render($project, 'BoardViewController', 'show', true) ?>
<?= $this->render('board/table_container', array(
'project' => $project,
diff --git a/app/Template/board/popover_close_all_tasks_column.php b/app/Template/board_popover/close_all_tasks_column.php
index 5090f499..57f703e3 100644
--- a/app/Template/board/popover_close_all_tasks_column.php
+++ b/app/Template/board_popover/close_all_tasks_column.php
@@ -2,7 +2,7 @@
<div class="page-header">
<h2><?= t('Do you really want to close all tasks of this column?') ?></h2>
</div>
- <form method="post" action="<?= $this->url->href('BoardPopover', 'closeColumnTasks', array('project_id' => $project['id'])) ?>">
+ <form method="post" action="<?= $this->url->href('BoardPopoverController', 'closeColumnTasks', array('project_id' => $project['id'])) ?>">
<?= $this->form->csrf() ?>
<?= $this->form->hidden('column_id', $values) ?>
<?= $this->form->hidden('swimlane_id', $values) ?>
@@ -12,7 +12,7 @@
<div class="form-actions">
<button type="submit" class="btn btn-red"><?= t('Save') ?></button>
<?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'board', 'show', array('project_id' => $project['id']), false, 'close-popover') ?>
+ <?= $this->url->link(t('cancel'), 'BoardViewController', 'show', array('project_id' => $project['id']), false, 'close-popover') ?>
</div>
</form>
-</section> \ No newline at end of file
+</section>
diff --git a/app/Template/calendar/show.php b/app/Template/calendar/show.php
index f00e810b..3635f627 100644
--- a/app/Template/calendar/show.php
+++ b/app/Template/calendar/show.php
@@ -1,9 +1,9 @@
<section id="main">
- <?= $this->projectHeader->render($project, 'Calendar', 'show') ?>
+ <?= $this->projectHeader->render($project, 'CalendarController', 'show') ?>
<div id="calendar"
- data-save-url="<?= $this->url->href('calendar', 'save', array('project_id' => $project['id'])) ?>"
- data-check-url="<?= $this->url->href('calendar', 'project', array('project_id' => $project['id'])) ?>"
+ data-save-url="<?= $this->url->href('CalendarController', 'save', array('project_id' => $project['id'])) ?>"
+ data-check-url="<?= $this->url->href('CalendarController', 'project', array('project_id' => $project['id'])) ?>"
data-check-interval="<?= $check_interval ?>"
>
</div>
-</section> \ No newline at end of file
+</section>
diff --git a/app/Template/category/edit.php b/app/Template/category/edit.php
index 7b592689..fac56db3 100644
--- a/app/Template/category/edit.php
+++ b/app/Template/category/edit.php
@@ -2,7 +2,7 @@
<h2><?= t('Category modification for the project "%s"', $project['name']) ?></h2>
</div>
-<form class="popover-form" method="post" action="<?= $this->url->href('category', 'update', array('project_id' => $project['id'], 'category_id' => $values['id'])) ?>" autocomplete="off">
+<form class="popover-form" method="post" action="<?= $this->url->href('CategoryController', 'update', array('project_id' => $project['id'], 'category_id' => $values['id'])) ?>" autocomplete="off">
<?= $this->form->csrf() ?>
@@ -18,6 +18,6 @@
<div class="form-actions">
<button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
<?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'category', 'index', array('project_id' => $project['id']), false, 'close-popover') ?>
+ <?= $this->url->link(t('cancel'), 'CategoryController', 'index', array('project_id' => $project['id']), false, 'close-popover') ?>
</div>
-</form> \ No newline at end of file
+</form>
diff --git a/app/Template/category/index.php b/app/Template/category/index.php
index b3bdfd81..a103d89f 100644
--- a/app/Template/category/index.php
+++ b/app/Template/category/index.php
@@ -15,10 +15,10 @@
<a href="#" class="dropdown-menu dropdown-menu-link-icon"><i class="fa fa-cog fa-fw"></i><i class="fa fa-caret-down"></i></a>
<ul>
<li>
- <?= $this->url->link(t('Edit'), 'category', 'edit', array('project_id' => $project['id'], 'category_id' => $category_id), false, 'popover') ?>
+ <?= $this->url->link(t('Edit'), 'CategoryController', 'edit', array('project_id' => $project['id'], 'category_id' => $category_id), false, 'popover') ?>
</li>
<li>
- <?= $this->url->link(t('Remove'), 'category', 'confirm', array('project_id' => $project['id'], 'category_id' => $category_id), false, 'popover') ?>
+ <?= $this->url->link(t('Remove'), 'CategoryController', 'confirm', array('project_id' => $project['id'], 'category_id' => $category_id), false, 'popover') ?>
</li>
</ul>
</div>
@@ -31,7 +31,7 @@
<div class="page-header">
<h2><?= t('Add a new category') ?></h2>
</div>
-<form method="post" action="<?= $this->url->href('category', 'save', array('project_id' => $project['id'])) ?>" autocomplete="off">
+<form method="post" action="<?= $this->url->href('CategoryController', 'save', array('project_id' => $project['id'])) ?>" autocomplete="off">
<?= $this->form->csrf() ?>
<?= $this->form->hidden('project_id', $values) ?>
@@ -42,4 +42,4 @@
<div class="form-actions">
<button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
</div>
-</form> \ No newline at end of file
+</form>
diff --git a/app/Template/category/remove.php b/app/Template/category/remove.php
index cad58d37..e7b9c9b4 100644
--- a/app/Template/category/remove.php
+++ b/app/Template/category/remove.php
@@ -9,9 +9,9 @@
</p>
<div class="form-actions">
- <?= $this->url->link(t('Yes'), 'category', 'remove', array('project_id' => $project['id'], 'category_id' => $category['id']), true, 'btn btn-red') ?>
+ <?= $this->url->link(t('Yes'), 'CategoryController', 'remove', array('project_id' => $project['id'], 'category_id' => $category['id']), true, 'btn btn-red') ?>
<?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'category', 'index', array('project_id' => $project['id']), false, 'close-popover') ?>
+ <?= $this->url->link(t('cancel'), 'CategoryController', 'index', array('project_id' => $project['id']), false, 'close-popover') ?>
</div>
</div>
-</section> \ No newline at end of file
+</section>
diff --git a/app/Template/column/create.php b/app/Template/column/create.php
index 2d325f76..023de525 100644
--- a/app/Template/column/create.php
+++ b/app/Template/column/create.php
@@ -1,7 +1,7 @@
<div class="page-header">
<h2><?= t('Add a new column') ?></h2>
</div>
-<form class="popover-form" method="post" action="<?= $this->url->href('Column', 'save', array('project_id' => $project['id'])) ?>" autocomplete="off">
+<form class="popover-form" method="post" action="<?= $this->url->href('ColumnController', 'save', array('project_id' => $project['id'])) ?>" autocomplete="off">
<?= $this->form->csrf() ?>
@@ -21,4 +21,4 @@
<?= t('or') ?>
<?= $this->url->link(t('cancel'), 'column', 'index', array('project_id' => $project['id']), false, 'close-popover') ?>
</div>
-</form> \ No newline at end of file
+</form>
diff --git a/app/Template/column/edit.php b/app/Template/column/edit.php
index 412858a9..a742e4b9 100644
--- a/app/Template/column/edit.php
+++ b/app/Template/column/edit.php
@@ -2,7 +2,7 @@
<h2><?= t('Edit column "%s"', $column['title']) ?></h2>
</div>
-<form class="popover-form" method="post" action="<?= $this->url->href('column', 'update', array('project_id' => $project['id'], 'column_id' => $column['id'])) ?>" autocomplete="off">
+<form class="popover-form" method="post" action="<?= $this->url->href('ColumnController', 'update', array('project_id' => $project['id'], 'column_id' => $column['id'])) ?>" autocomplete="off">
<?= $this->form->csrf() ?>
@@ -21,6 +21,6 @@
<div class="form-actions">
<button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
<?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'column', 'index', array('project_id' => $project['id']), false, 'close-popover') ?>
+ <?= $this->url->link(t('cancel'), 'ColumnController', 'index', array('project_id' => $project['id']), false, 'close-popover') ?>
</div>
-</form> \ No newline at end of file
+</form>
diff --git a/app/Template/column/index.php b/app/Template/column/index.php
index eef176f3..4f5f0a60 100644
--- a/app/Template/column/index.php
+++ b/app/Template/column/index.php
@@ -3,7 +3,7 @@
<ul>
<li>
<i class="fa fa-plus fa-fw"></i>
- <?= $this->url->link(t('Add a new column'), 'Column', 'create', array('project_id' => $project['id']), false, 'popover') ?>
+ <?= $this->url->link(t('Add a new column'), 'ColumnController', 'create', array('project_id' => $project['id']), false, 'popover') ?>
</li>
</ul>
</div>
@@ -13,7 +13,7 @@
<?php else: ?>
<table
class="columns-table table-stripped"
- data-save-position-url="<?= $this->url->href('Column', 'move', array('project_id' => $project['id'])) ?>">
+ data-save-position-url="<?= $this->url->href('ColumnController', 'move', array('project_id' => $project['id'])) ?>">
<thead>
<tr>
<th class="column-70"><?= t('Column title') ?></th>
@@ -28,7 +28,7 @@
<i class="fa fa-arrows-alt draggable-row-handle" title="<?= t('Change column position') ?>"></i>
<?= $this->text->e($column['title']) ?>
<?php if (! empty($column['description'])): ?>
- <span class="tooltip" title='<?= $this->text->e($this->text->markdown($column['description'])) ?>'>
+ <span class="tooltip" title="<?= $this->text->markdownAttribute($column['description']) ?>">
<i class="fa fa-info-circle"></i>
</span>
<?php endif ?>
@@ -41,10 +41,10 @@
<a href="#" class="dropdown-menu dropdown-menu-link-icon"><i class="fa fa-cog fa-fw"></i><i class="fa fa-caret-down"></i></a>
<ul>
<li>
- <?= $this->url->link(t('Edit'), 'column', 'edit', array('project_id' => $project['id'], 'column_id' => $column['id']), false, 'popover') ?>
+ <?= $this->url->link(t('Edit'), 'ColumnController', 'edit', array('project_id' => $project['id'], 'column_id' => $column['id']), false, 'popover') ?>
</li>
<li>
- <?= $this->url->link(t('Remove'), 'column', 'confirm', array('project_id' => $project['id'], 'column_id' => $column['id']), false, 'popover') ?>
+ <?= $this->url->link(t('Remove'), 'ColumnController', 'confirm', array('project_id' => $project['id'], 'column_id' => $column['id']), false, 'popover') ?>
</li>
</ul>
</div>
diff --git a/app/Template/column/remove.php b/app/Template/column/remove.php
index ccab889d..b231a9a7 100644
--- a/app/Template/column/remove.php
+++ b/app/Template/column/remove.php
@@ -9,7 +9,7 @@
</p>
<div class="form-actions">
- <?= $this->url->link(t('Yes'), 'column', 'remove', array('project_id' => $project['id'], 'column_id' => $column['id'], 'remove' => 'yes'), true, 'btn btn-red') ?>
- <?= t('or') ?> <?= $this->url->link(t('cancel'), 'column', 'index', array('project_id' => $project['id']), false, 'close-popover') ?>
+ <?= $this->url->link(t('Yes'), 'ColumnController', 'remove', array('project_id' => $project['id'], 'column_id' => $column['id'], 'remove' => 'yes'), true, 'btn btn-red') ?>
+ <?= t('or') ?> <?= $this->url->link(t('cancel'), 'ColumnController', 'index', array('project_id' => $project['id']), false, 'close-popover') ?>
</div>
-</div> \ No newline at end of file
+</div>
diff --git a/app/Template/comment/create.php b/app/Template/comment/create.php
index b6c27ae0..0358107a 100644
--- a/app/Template/comment/create.php
+++ b/app/Template/comment/create.php
@@ -1,7 +1,7 @@
<div class="page-header">
<h2><?= t('Add a comment') ?></h2>
</div>
-<form class="popover-form" method="post" action="<?= $this->url->href('comment', 'save', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>" autocomplete="off">
+<form class="popover-form" method="post" action="<?= $this->url->href('CommentController', 'save', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>" autocomplete="off">
<?= $this->form->csrf() ?>
<?= $this->form->hidden('task_id', $values) ?>
<?= $this->form->hidden('user_id', $values) ?>
@@ -15,7 +15,7 @@
'autofocus',
'required',
'placeholder="'.t('Leave a comment').'"',
- 'data-mention-search-url="'.$this->url->href('UserHelper', 'mention', array('project_id' => $task['project_id'])).'"',
+ 'data-mention-search-url="'.$this->url->href('UserAjaxController', 'mention', array('project_id' => $task['project_id'])).'"',
),
'markdown-editor'
) ?>
@@ -24,6 +24,6 @@
<div class="form-actions">
<button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
<?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'close-popover') ?>
+ <?= $this->url->link(t('cancel'), 'TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'close-popover') ?>
</div>
</form>
diff --git a/app/Template/comment/edit.php b/app/Template/comment/edit.php
index 4036b673..f69fc0c1 100644
--- a/app/Template/comment/edit.php
+++ b/app/Template/comment/edit.php
@@ -2,7 +2,7 @@
<h2><?= t('Edit a comment') ?></h2>
</div>
-<form class="popover-form" method="post" action="<?= $this->url->href('comment', 'update', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'comment_id' => $comment['id'])) ?>" autocomplete="off">
+<form class="popover-form" method="post" action="<?= $this->url->href('CommentController', 'update', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'comment_id' => $comment['id'])) ?>" autocomplete="off">
<?= $this->form->csrf() ?>
<?= $this->form->hidden('id', $values) ?>
@@ -22,6 +22,6 @@
<div class="form-actions">
<button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
<?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'close-popover') ?>
+ <?= $this->url->link(t('cancel'), 'TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'close-popover') ?>
</div>
</form>
diff --git a/app/Template/comment/remove.php b/app/Template/comment/remove.php
index 3174df02..55587b67 100644
--- a/app/Template/comment/remove.php
+++ b/app/Template/comment/remove.php
@@ -14,8 +14,8 @@
)) ?>
<div class="form-actions">
- <?= $this->url->link(t('Yes'), 'comment', 'remove', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'comment_id' => $comment['id']), true, 'btn btn-red') ?>
+ <?= $this->url->link(t('Yes'), 'CommentController', 'remove', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'comment_id' => $comment['id']), true, 'btn btn-red') ?>
<?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'close-popover') ?>
+ <?= $this->url->link(t('cancel'), 'TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'close-popover') ?>
</div>
-</div> \ No newline at end of file
+</div>
diff --git a/app/Template/comment/show.php b/app/Template/comment/show.php
index 3f45e2e7..8419a14e 100644
--- a/app/Template/comment/show.php
+++ b/app/Template/comment/show.php
@@ -12,29 +12,7 @@
<div class="comment-content">
<div class="markdown">
- <?php if (isset($is_public) && $is_public): ?>
- <?= $this->text->markdown(
- $comment['comment'],
- array(
- 'controller' => 'task',
- 'action' => 'readonly',
- 'params' => array(
- 'token' => $project['token']
- )
- )
- ) ?>
- <?php else: ?>
- <?= $this->text->markdown(
- $comment['comment'],
- array(
- 'controller' => 'task',
- 'action' => 'show',
- 'params' => array(
- 'project_id' => $task['project_id']
- )
- )
- ) ?>
- <?php endif ?>
+ <?= $this->text->markdown($comment['comment'], isset($is_public) && $is_public) ?>
</div>
</div>
@@ -48,11 +26,11 @@
<?php if ($editable && ($this->user->isAdmin() || $this->user->isCurrentUser($comment['user_id']))): ?>
<li>
<i class="fa fa-remove fa-fw"></i>
- <?= $this->url->link(t('remove'), 'comment', 'confirm', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'comment_id' => $comment['id']), false, 'popover') ?>
+ <?= $this->url->link(t('remove'), 'CommentController', 'confirm', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'comment_id' => $comment['id']), false, 'popover') ?>
</li>
<li>
<i class="fa fa-edit fa-fw"></i>
- <?= $this->url->link(t('edit'), 'comment', 'edit', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'comment_id' => $comment['id']), false, 'popover') ?>
+ <?= $this->url->link(t('edit'), 'CommentController', 'edit', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'comment_id' => $comment['id']), false, 'popover') ?>
</li>
<?php endif ?>
</ul>
diff --git a/app/Template/comments/create.php b/app/Template/comments/create.php
index a638d3b8..3fa6ddc0 100644
--- a/app/Template/comments/create.php
+++ b/app/Template/comments/create.php
@@ -1,4 +1,4 @@
-<form method="post" action="<?= $this->url->href('comment', 'save', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>" autocomplete="off">
+<form method="post" action="<?= $this->url->href('CommentController', 'save', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>" autocomplete="off">
<?= $this->form->csrf() ?>
<?= $this->form->hidden('task_id', $values) ?>
<?= $this->form->hidden('user_id', $values) ?>
@@ -12,7 +12,7 @@
'data-markdown-editor-disable-toolbar="true"',
'required',
'placeholder="'.t('Leave a comment').'"',
- 'data-mention-search-url="'.$this->url->href('UserHelper', 'mention', array('project_id' => $task['project_id'])).'"',
+ 'data-mention-search-url="'.$this->url->href('UserAjaxController', 'mention', array('project_id' => $task['project_id'])).'"',
),
'markdown-editor'
) ?>
diff --git a/app/Template/comments/show.php b/app/Template/comments/show.php
index 76af5593..43f6b2c2 100644
--- a/app/Template/comments/show.php
+++ b/app/Template/comments/show.php
@@ -6,7 +6,7 @@
<?php if (!isset($is_public) || !$is_public): ?>
<div class="comment-sorting">
<i class="fa fa-sort"></i>
- <?= $this->url->link(t('change sorting'), 'comment', 'toggleSorting', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>
+ <?= $this->url->link(t('change sorting'), 'CommentController', 'toggleSorting', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>
</div>
<?php endif ?>
<?php foreach ($comments as $comment): ?>
@@ -30,4 +30,4 @@
)) ?>
<?php endif ?>
</div>
-</section> \ No newline at end of file
+</section>
diff --git a/app/Template/config/about.php b/app/Template/config/about.php
index 5c1f4b39..8e2d1325 100644
--- a/app/Template/config/about.php
+++ b/app/Template/config/about.php
@@ -5,7 +5,7 @@
<ul>
<li>
<?= t('Official website:') ?>
- <a href="http://kanboard.net/" target="_blank" rel="noreferer">http://kanboard.net/</a>
+ <a href="https://kanboard.net/" target="_blank" rel="noreferer">https://kanboard.net/</a>
</li>
<li>
<?= t('Author:') ?>
@@ -65,11 +65,11 @@
<strong><?= $this->text->bytes($db_size) ?></strong>
</li>
<li>
- <?= $this->url->link(t('Download the database'), 'config', 'downloadDb', array(), true) ?>&nbsp;
+ <?= $this->url->link(t('Download the database'), 'ConfigController', 'downloadDb', array(), true) ?>&nbsp;
<?= t('(Gzip compressed Sqlite file)') ?>
</li>
<li>
- <?= $this->url->link(t('Optimize the database'), 'config', 'optimizeDb', array(), true) ?>&nbsp;
+ <?= $this->url->link(t('Optimize the database'), 'ConfigController', 'optimizeDb', array(), true) ?>&nbsp;
<?= t('(VACUUM command)') ?>
</li>
</ul>
@@ -82,5 +82,5 @@
<h2><?= t('License') ?></h2>
</div>
<div class="listing">
-<?= nl2br(file_get_contents('LICENSE')) ?>
-</div> \ No newline at end of file
+<?= nl2br(file_get_contents(ROOT_DIR.DIRECTORY_SEPARATOR.'LICENSE')) ?>
+</div>
diff --git a/app/Template/config/api.php b/app/Template/config/api.php
index 3ebbb956..95f77355 100644
--- a/app/Template/config/api.php
+++ b/app/Template/config/api.php
@@ -12,7 +12,7 @@
<input type="text" class="auto-select" readonly="readonly" value="<?= $this->url->base().'jsonrpc.php' ?>">
</li>
<li>
- <?= $this->url->link(t('Reset token'), 'config', 'token', array('type' => 'api'), true) ?>
+ <?= $this->url->link(t('Reset token'), 'ConfigController', 'token', array('type' => 'api'), true) ?>
</li>
</ul>
-</section> \ No newline at end of file
+</section>
diff --git a/app/Template/config/application.php b/app/Template/config/application.php
index 259756bc..b66d0633 100644
--- a/app/Template/config/application.php
+++ b/app/Template/config/application.php
@@ -1,7 +1,7 @@
<div class="page-header">
<h2><?= t('Application settings') ?></h2>
</div>
-<form method="post" action="<?= $this->url->href('config', 'application') ?>" autocomplete="off">
+<form method="post" action="<?= $this->url->href('ConfigController', 'save', array('redirect' => 'application')) ?>" autocomplete="off">
<?= $this->form->csrf() ?>
@@ -9,6 +9,9 @@
<?= $this->form->text('application_url', $values, $errors, array('placeholder="http://example.kanboard.net/"')) ?>
<p class="form-help"><?= t('Example: http://example.kanboard.net/ (used to generate absolute URLs)') ?></p>
+ <?= $this->form->label(t('Email sender address'), 'mail_sender_address') ?>
+ <?= $this->form->text('mail_sender_address', $values, $errors, array('placeholder="'.MAIL_FROM.'"')) ?>
+
<?= $this->form->label(t('Language'), 'application_language') ?>
<?= $this->form->select('application_language', $languages, $values, $errors) ?>
diff --git a/app/Template/config/board.php b/app/Template/config/board.php
index ba1bab59..62a736e7 100644
--- a/app/Template/config/board.php
+++ b/app/Template/config/board.php
@@ -1,7 +1,7 @@
<div class="page-header">
<h2><?= t('Board settings') ?></h2>
</div>
-<form method="post" action="<?= $this->url->href('config', 'board') ?>" autocomplete="off">
+<form method="post" action="<?= $this->url->href('ConfigController', 'save', array('redirect' => 'board')) ?>" autocomplete="off">
<?= $this->form->csrf() ?>
diff --git a/app/Template/config/calendar.php b/app/Template/config/calendar.php
index b7b230df..90e034e9 100644
--- a/app/Template/config/calendar.php
+++ b/app/Template/config/calendar.php
@@ -2,7 +2,7 @@
<h2><?= t('Calendar settings') ?></h2>
</div>
<section>
-<form method="post" action="<?= $this->url->href('config', 'calendar') ?>" autocomplete="off">
+<form method="post" action="<?= $this->url->href('ConfigController', 'save', array('redirect' => 'calendar')) ?>" autocomplete="off">
<?= $this->form->csrf() ?>
@@ -31,4 +31,4 @@
<button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
</div>
</form>
-</section> \ No newline at end of file
+</section>
diff --git a/app/Template/config/integrations.php b/app/Template/config/integrations.php
index e404c52e..3ba4e865 100644
--- a/app/Template/config/integrations.php
+++ b/app/Template/config/integrations.php
@@ -2,7 +2,7 @@
<h2><?= t('Integration with third-party services') ?></h2>
</div>
-<form method="post" action="<?= $this->url->href('config', 'integrations') ?>" autocomplete="off">
+<form method="post" action="<?= $this->url->href('ConfigController', 'save', array('redirect' => 'integrations')) ?>" autocomplete="off">
<?= $this->form->csrf() ?>
<?= $this->hook->render('template:config:integrations', array('values' => $values)) ?>
@@ -14,4 +14,4 @@
<div class="form-actions">
<button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
</div>
-</form> \ No newline at end of file
+</form>
diff --git a/app/Template/config/layout.php b/app/Template/config/layout.php
index f34caaab..6eafa593 100644
--- a/app/Template/config/layout.php
+++ b/app/Template/config/layout.php
@@ -1,10 +1,9 @@
<section id="main">
<section class="sidebar-container" id="config-section">
-
<?= $this->render($sidebar_template) ?>
<div class="sidebar-content">
<?= $content_for_sublayout ?>
</div>
</section>
-</section> \ No newline at end of file
+</section>
diff --git a/app/Template/config/plugins.php b/app/Template/config/plugins.php
deleted file mode 100644
index 04b3f095..00000000
--- a/app/Template/config/plugins.php
+++ /dev/null
@@ -1,30 +0,0 @@
-<div class="page-header">
- <h2><?= t('Plugins') ?></h2>
-</div>
-
-<?php if (empty($plugins)): ?>
- <p class="alert"><?= t('There is no plugin loaded.') ?></p>
-<?php else: ?>
- <table class="table-stripped">
- <tr>
- <th class="column-20"><?= t('Name') ?></th>
- <th class="column-20"><?= t('Author') ?></th>
- <th class="column-10"><?= t('Version') ?></th>
- <th><?= t('Description') ?></th>
- </tr>
-
- <?php foreach ($plugins as $plugin): ?>
- <tr>
- <td>
- <?php if ($plugin->getPluginHomepage()): ?>
- <a href="<?= $plugin->getPluginHomepage() ?>" target="_blank" rel="noreferrer"><?= $this->text->e($plugin->getPluginName()) ?></a>
- <?php else: ?>
- <?= $this->text->e($plugin->getPluginName()) ?>
- <?php endif ?>
- </td>
- <td><?= $this->text->e($plugin->getPluginAuthor()) ?></td>
- <td><?= $this->text->e($plugin->getPluginVersion()) ?></td>
- <td><?= $this->text->e($plugin->getPluginDescription()) ?></td>
- </tr>
- <?php endforeach ?>
-<?php endif ?> \ No newline at end of file
diff --git a/app/Template/config/project.php b/app/Template/config/project.php
index b6b7ec25..6d8d131a 100644
--- a/app/Template/config/project.php
+++ b/app/Template/config/project.php
@@ -1,7 +1,7 @@
<div class="page-header">
<h2><?= t('Project settings') ?></h2>
</div>
-<form method="post" action="<?= $this->url->href('config', 'project') ?>" autocomplete="off">
+<form method="post" action="<?= $this->url->href('ConfigController', 'save', array('redirect' => 'project')) ?>" autocomplete="off">
<?= $this->form->csrf() ?>
diff --git a/app/Template/config/sidebar.php b/app/Template/config/sidebar.php
index dd51bc74..187ecd93 100644
--- a/app/Template/config/sidebar.php
+++ b/app/Template/config/sidebar.php
@@ -1,39 +1,36 @@
<div class="sidebar">
<h2><?= t('Actions') ?></h2>
<ul>
- <li <?= $this->app->checkMenuSelection('config', 'index') ?>>
- <?= $this->url->link(t('About'), 'config', 'index') ?>
+ <li <?= $this->app->checkMenuSelection('ConfigController', 'index') ?>>
+ <?= $this->url->link(t('About'), 'ConfigController', 'index') ?>
</li>
- <li <?= $this->app->checkMenuSelection('config', 'plugins') ?>>
- <?= $this->url->link(t('Plugins'), 'config', 'plugins') ?>
+ <li <?= $this->app->checkMenuSelection('ConfigController', 'application') ?>>
+ <?= $this->url->link(t('Application settings'), 'ConfigController', 'application') ?>
</li>
- <li <?= $this->app->checkMenuSelection('config', 'application') ?>>
- <?= $this->url->link(t('Application settings'), 'config', 'application') ?>
+ <li <?= $this->app->checkMenuSelection('ConfigController', 'project') ?>>
+ <?= $this->url->link(t('Project settings'), 'ConfigController', 'project') ?>
</li>
- <li <?= $this->app->checkMenuSelection('config', 'project') ?>>
- <?= $this->url->link(t('Project settings'), 'config', 'project') ?>
+ <li <?= $this->app->checkMenuSelection('ConfigController', 'board') ?>>
+ <?= $this->url->link(t('Board settings'), 'ConfigController', 'board') ?>
</li>
- <li <?= $this->app->checkMenuSelection('config', 'board') ?>>
- <?= $this->url->link(t('Board settings'), 'config', 'board') ?>
+ <li <?= $this->app->checkMenuSelection('ConfigController', 'calendar') ?>>
+ <?= $this->url->link(t('Calendar settings'), 'ConfigController', 'calendar') ?>
</li>
- <li <?= $this->app->checkMenuSelection('config', 'calendar') ?>>
- <?= $this->url->link(t('Calendar settings'), 'config', 'calendar') ?>
+ <li <?= $this->app->checkMenuSelection('LinkController') ?>>
+ <?= $this->url->link(t('Link settings'), 'LinkController', 'index') ?>
</li>
- <li <?= $this->app->checkMenuSelection('link') ?>>
- <?= $this->url->link(t('Link settings'), 'link', 'index') ?>
+ <li <?= $this->app->checkMenuSelection('CurrencyController', 'index') ?>>
+ <?= $this->url->link(t('Currency rates'), 'CurrencyController', 'index') ?>
</li>
- <li <?= $this->app->checkMenuSelection('currency', 'index') ?>>
- <?= $this->url->link(t('Currency rates'), 'currency', 'index') ?>
+ <li <?= $this->app->checkMenuSelection('ConfigController', 'integrations') ?>>
+ <?= $this->url->link(t('Integrations'), 'ConfigController', 'integrations') ?>
</li>
- <li <?= $this->app->checkMenuSelection('config', 'integrations') ?>>
- <?= $this->url->link(t('Integrations'), 'config', 'integrations') ?>
+ <li <?= $this->app->checkMenuSelection('ConfigController', 'webhook') ?>>
+ <?= $this->url->link(t('Webhooks'), 'ConfigController', 'webhook') ?>
</li>
- <li <?= $this->app->checkMenuSelection('config', 'webhook') ?>>
- <?= $this->url->link(t('Webhooks'), 'config', 'webhook') ?>
- </li>
- <li <?= $this->app->checkMenuSelection('config', 'api') ?>>
- <?= $this->url->link(t('API'), 'config', 'api') ?>
+ <li <?= $this->app->checkMenuSelection('ConfigController', 'api') ?>>
+ <?= $this->url->link(t('API'), 'ConfigController', 'api') ?>
</li>
<?= $this->hook->render('template:config:sidebar') ?>
</ul>
-</div> \ No newline at end of file
+</div>
diff --git a/app/Template/config/webhook.php b/app/Template/config/webhook.php
index b96979a0..e3245873 100644
--- a/app/Template/config/webhook.php
+++ b/app/Template/config/webhook.php
@@ -2,7 +2,7 @@
<h2><?= t('Webhook settings') ?></h2>
</div>
<section>
-<form method="post" action="<?= $this->url->href('config', 'webhook') ?>" autocomplete="off">
+<form method="post" action="<?= $this->url->href('ConfigController', 'save', array('redirect' => 'webhook')) ?>" autocomplete="off">
<?= $this->form->csrf() ?>
@@ -16,7 +16,7 @@
</section>
<div class="page-header">
- <h2><?= t('URL and token') ?></h2>
+ <h2><?= t('Webhook token') ?></h2>
</div>
<section class="listing">
<ul>
@@ -25,11 +25,7 @@
<strong><?= $this->text->e($values['webhook_token']) ?></strong>
</li>
<li>
- <?= t('URL for task creation:') ?>
- <input type="text" class="auto-select" readonly="readonly" value="<?= $this->url->href('webhook', 'task', array('token' => $values['webhook_token']), false, '', true) ?>">
- </li>
- <li>
- <?= $this->url->link(t('Reset token'), 'config', 'token', array('type' => 'webhook'), true) ?>
+ <?= $this->url->link(t('Reset token'), 'ConfigController', 'token', array('type' => 'webhook'), true) ?>
</li>
</ul>
-</section> \ No newline at end of file
+</section>
diff --git a/app/Template/currency/index.php b/app/Template/currency/index.php
index d35ac459..9881cee5 100644
--- a/app/Template/currency/index.php
+++ b/app/Template/currency/index.php
@@ -24,7 +24,7 @@
<hr/>
<h3><?= t('Change reference currency') ?></h3>
<?php endif ?>
-<form method="post" action="<?= $this->url->href('currency', 'reference') ?>" autocomplete="off">
+<form method="post" action="<?= $this->url->href('CurrencyController', 'reference') ?>" autocomplete="off">
<?= $this->form->csrf() ?>
@@ -38,7 +38,7 @@
<hr/>
<h3><?= t('Add a new currency rate') ?></h3>
-<form method="post" action="<?= $this->url->href('currency', 'create') ?>" autocomplete="off">
+<form method="post" action="<?= $this->url->href('CurrencyController', 'create') ?>" autocomplete="off">
<?= $this->form->csrf() ?>
diff --git a/app/Template/custom_filter/add.php b/app/Template/custom_filter/add.php
index e3e144ae..3801cc30 100644
--- a/app/Template/custom_filter/add.php
+++ b/app/Template/custom_filter/add.php
@@ -1,7 +1,7 @@
<div class="page-header">
<h2><?= t('Add a new filter') ?></h2>
</div>
-<form method="post" action="<?= $this->url->href('customfilter', 'save', array('project_id' => $project['id'])) ?>" autocomplete="off">
+<form method="post" action="<?= $this->url->href('CustomFilterController', 'save', array('project_id' => $project['id'])) ?>" autocomplete="off">
<?= $this->form->csrf() ?>
<?= $this->form->hidden('project_id', $values) ?>
@@ -12,7 +12,7 @@
<?= $this->form->label(t('Filter'), 'filter') ?>
<?= $this->form->text('filter', $values, $errors, array('required', 'maxlength="100"')) ?>
- <?php if ($this->user->hasProjectAccess('ProjectEdit', 'edit', $project['id'])): ?>
+ <?php if ($this->user->hasProjectAccess('ProjectEditController', 'edit', $project['id'])): ?>
<?= $this->form->checkbox('is_shared', t('Share with all project members'), 1) ?>
<?php endif ?>
@@ -21,4 +21,4 @@
<div class="form-actions">
<button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
</div>
-</form> \ No newline at end of file
+</form>
diff --git a/app/Template/custom_filter/edit.php b/app/Template/custom_filter/edit.php
index 5d07e8c2..26da8da2 100644
--- a/app/Template/custom_filter/edit.php
+++ b/app/Template/custom_filter/edit.php
@@ -2,7 +2,7 @@
<h2><?= t('Edit custom filter') ?></h2>
</div>
-<form class="form-popover" method="post" action="<?= $this->url->href('customfilter', 'update', array('project_id' => $filter['project_id'], 'filter_id' => $filter['id'])) ?>" autocomplete="off">
+<form class="form-popover" method="post" action="<?= $this->url->href('CustomFilterController', 'update', array('project_id' => $filter['project_id'], 'filter_id' => $filter['id'])) ?>" autocomplete="off">
<?= $this->form->csrf() ?>
@@ -16,7 +16,7 @@
<?= $this->form->label(t('Filter'), 'filter') ?>
<?= $this->form->text('filter', $values, $errors, array('required', 'maxlength="100"')) ?>
- <?php if ($this->user->hasProjectAccess('ProjectEdit', 'edit', $project['id'])): ?>
+ <?php if ($this->user->hasProjectAccess('ProjectEditController', 'edit', $project['id'])): ?>
<?= $this->form->checkbox('is_shared', t('Share with all project members'), 1, $values['is_shared'] == 1) ?>
<?php else: ?>
<?= $this->form->hidden('is_shared', $values) ?>
@@ -27,6 +27,6 @@
<div class="form-actions">
<button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
<?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'customfilter', 'index', array('project_id' => $project['id']), false, 'close-popover') ?>
+ <?= $this->url->link(t('cancel'), 'CustomFilterController', 'index', array('project_id' => $project['id']), false, 'close-popover') ?>
</div>
-</form> \ No newline at end of file
+</form>
diff --git a/app/Template/custom_filter/index.php b/app/Template/custom_filter/index.php
index 12a4eece..08c8040c 100644
--- a/app/Template/custom_filter/index.php
+++ b/app/Template/custom_filter/index.php
@@ -32,12 +32,12 @@
</td>
<td><?= $this->text->e($filter['owner_name'] ?: $filter['owner_username']) ?></td>
<td>
- <?php if ($filter['user_id'] == $this->user->getId() || $this->user->hasProjectAccess('customfilter', 'edit', $project['id'])): ?>
+ <?php if ($filter['user_id'] == $this->user->getId() || $this->user->hasProjectAccess('CustomFilterController', 'edit', $project['id'])): ?>
<div class="dropdown">
<a href="#" class="dropdown-menu dropdown-menu-link-icon"><i class="fa fa-cog fa-fw"></i><i class="fa fa-caret-down"></i></a>
<ul>
- <li><?= $this->url->link(t('Remove'), 'customfilter', 'confirm', array('project_id' => $filter['project_id'], 'filter_id' => $filter['id']), false, 'popover') ?></li>
- <li><?= $this->url->link(t('Edit'), 'customfilter', 'edit', array('project_id' => $filter['project_id'], 'filter_id' => $filter['id']), false, 'popover') ?></li>
+ <li><?= $this->url->link(t('Remove'), 'CustomFilterController', 'confirm', array('project_id' => $filter['project_id'], 'filter_id' => $filter['id']), false, 'popover') ?></li>
+ <li><?= $this->url->link(t('Edit'), 'CustomFilterController', 'edit', array('project_id' => $filter['project_id'], 'filter_id' => $filter['id']), false, 'popover') ?></li>
</ul>
</div>
<?php endif ?>
diff --git a/app/Template/custom_filter/remove.php b/app/Template/custom_filter/remove.php
index d4c67a2b..609f19b2 100644
--- a/app/Template/custom_filter/remove.php
+++ b/app/Template/custom_filter/remove.php
@@ -9,9 +9,9 @@
</p>
<div class="form-actions">
- <?= $this->url->link(t('Yes'), 'customfilter', 'remove', array('project_id' => $project['id'], 'filter_id' => $filter['id']), true, 'btn btn-red') ?>
+ <?= $this->url->link(t('Yes'), 'CustomFilterController', 'remove', array('project_id' => $project['id'], 'filter_id' => $filter['id']), true, 'btn btn-red') ?>
<?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'customfilter', 'index', array('project_id' => $project['id']), false, 'close-popover') ?>
+ <?= $this->url->link(t('cancel'), 'CustomFilterController', 'index', array('project_id' => $project['id']), false, 'close-popover') ?>
</div>
</div>
</section>
diff --git a/app/Template/app/activity.php b/app/Template/dashboard/activity.php
index 71a67fb2..71a67fb2 100644
--- a/app/Template/app/activity.php
+++ b/app/Template/dashboard/activity.php
diff --git a/app/Template/dashboard/calendar.php b/app/Template/dashboard/calendar.php
new file mode 100644
index 00000000..75c96d83
--- /dev/null
+++ b/app/Template/dashboard/calendar.php
@@ -0,0 +1,5 @@
+<div id="calendar"
+ data-check-url="<?= $this->url->href('CalendarController', 'user', array('user_id' => $user['id'])) ?>"
+ data-save-url="<?= $this->url->href('CalendarController', 'save') ?>"
+>
+</div>
diff --git a/app/Template/app/layout.php b/app/Template/dashboard/layout.php
index 2a32ac02..795537a6 100644
--- a/app/Template/app/layout.php
+++ b/app/Template/dashboard/layout.php
@@ -1,25 +1,25 @@
<section id="main">
<div class="page-header">
<ul>
- <?php if ($this->user->hasAccess('ProjectCreation', 'create')): ?>
+ <?php if ($this->user->hasAccess('ProjectCreationController', 'create')): ?>
<li>
<i class="fa fa-plus fa-fw"></i>
- <?= $this->url->link(t('New project'), 'ProjectCreation', 'create', array(), false, 'popover') ?>
+ <?= $this->url->link(t('New project'), 'ProjectCreationController', 'create', array(), false, 'popover') ?>
</li>
<?php endif ?>
<?php if ($this->app->config('disable_private_project', 0) == 0): ?>
<li>
<i class="fa fa-lock fa-fw"></i>
- <?= $this->url->link(t('New private project'), 'ProjectCreation', 'createPrivate', array(), false, 'popover') ?>
+ <?= $this->url->link(t('New private project'), 'ProjectCreationController', 'createPrivate', array(), false, 'popover') ?>
</li>
<?php endif ?>
<li>
<i class="fa fa-search fa-fw"></i>
- <?= $this->url->link(t('Search'), 'search', 'index') ?>
+ <?= $this->url->link(t('Search'), 'SearchController', 'index') ?>
</li>
<li>
<i class="fa fa-folder fa-fw"></i>
- <?= $this->url->link(t('Project management'), 'project', 'index') ?>
+ <?= $this->url->link(t('Project management'), 'ProjectListController', 'show') ?>
</li>
</ul>
</div>
@@ -29,4 +29,4 @@
<?= $content_for_sublayout ?>
</div>
</section>
-</section> \ No newline at end of file
+</section>
diff --git a/app/Template/app/notifications.php b/app/Template/dashboard/notifications.php
index b64eb0b7..e0e9b878 100644
--- a/app/Template/app/notifications.php
+++ b/app/Template/dashboard/notifications.php
@@ -8,7 +8,7 @@
<ul>
<li>
<i class="fa fa-check-square-o fa-fw"></i>
- <?= $this->url->link(t('Mark all as read'), 'webNotification', 'flush', array('user_id' => $user['id'])) ?>
+ <?= $this->url->link(t('Mark all as read'), 'WebNotificationController', 'flush', array('user_id' => $user['id'])) ?>
</li>
</ul>
</div>
@@ -36,16 +36,12 @@
<i class="fa fa-file-o fa-fw"></i>
<?php endif ?>
- <?php if ($this->text->contains($notification['event_name'], 'comment')): ?>
- <?= $this->url->link($notification['title'], 'task', 'show', array('task_id' => $notification['event_data']['task']['id'], 'project_id' => $notification['event_data']['task']['project_id']), false, '', '', false, 'comment-'.$notification['event_data']['comment']['id']) ?>
- <?php elseif ($this->text->contains($notification['event_name'], 'task.overdue')): ?>
+ <?php if ($this->text->contains($notification['event_name'], 'task.overdue')): ?>
<?php if (count($notification['event_data']['tasks']) > 1): ?>
<?= $notification['title'] ?>
- <?php else: ?>
- <?= $this->url->link($notification['title'], 'task', 'show', array('task_id' => $notification['event_data']['tasks'][0]['id'], 'project_id' => $notification['event_data']['tasks'][0]['project_id'])) ?>
<?php endif ?>
<?php else: ?>
- <?= $this->url->link($notification['title'], 'task', 'show', array('task_id' => $notification['event_data']['task']['id'], 'project_id' => $notification['event_data']['task']['project_id'])) ?>
+ <?= $this->url->link($notification['title'], 'WebNotificationController', 'redirect', array('notification_id' => $notification['id'], 'user_id' => $user['id'])) ?>
<?php endif ?>
</td>
<td>
@@ -53,9 +49,9 @@
</td>
<td>
<i class="fa fa-check fa-fw"></i>
- <?= $this->url->link(t('Mark as read'), 'webNotification', 'remove', array('user_id' => $user['id'], 'notification_id' => $notification['id'])) ?>
+ <?= $this->url->link(t('Mark as read'), 'WebNotificationController', 'remove', array('user_id' => $user['id'], 'notification_id' => $notification['id'])) ?>
</td>
</tr>
<?php endforeach ?>
</table>
-<?php endif ?> \ No newline at end of file
+<?php endif ?>
diff --git a/app/Template/app/projects.php b/app/Template/dashboard/projects.php
index 4ab8b106..5bf92980 100644
--- a/app/Template/app/projects.php
+++ b/app/Template/dashboard/projects.php
@@ -1,5 +1,5 @@
<div class="page-header">
- <h2><?= $this->url->link(t('My projects'), 'app', 'projects', array('user_id' => $user['id'])) ?> (<?= $paginator->getTotal() ?>)</h2>
+ <h2><?= $this->url->link(t('My projects'), 'DashboardController', 'projects', array('user_id' => $user['id'])) ?> (<?= $paginator->getTotal() ?>)</h2>
</div>
<?php if ($paginator->isEmpty()): ?>
<p class="alert"><?= t('Your are not member of any project.') ?></p>
@@ -8,13 +8,13 @@
<tr>
<th class="column-5"><?= $paginator->order('Id', 'id') ?></th>
<th class="column-3"><?= $paginator->order('<i class="fa fa-lock fa-fw" title="'.t('Private project').'"></i>', 'is_private') ?></th>
- <th class="column-25"><?= $paginator->order(t('Project'), \Kanboard\Model\Project::TABLE.'.name') ?></th>
+ <th class="column-25"><?= $paginator->order(t('Project'), \Kanboard\Model\ProjectModel::TABLE.'.name') ?></th>
<th><?= t('Columns') ?></th>
</tr>
<?php foreach ($paginator->getCollection() as $project): ?>
<tr>
<td>
- <?= $this->url->link('#'.$project['id'], 'board', 'show', array('project_id' => $project['id']), false, 'dashboard-table-link') ?>
+ <?= $this->render('project/dropdown', array('project' => $project)) ?>
</td>
<td>
<?php if ($project['is_private']): ?>
@@ -22,16 +22,16 @@
<?php endif ?>
</td>
<td>
- <?php if ($this->user->hasProjectAccess('gantt', 'project', $project['id'])): ?>
- <?= $this->url->link('<i class="fa fa-sliders fa-fw"></i>', 'gantt', 'project', array('project_id' => $project['id']), false, 'dashboard-table-link', t('Gantt chart')) ?>
+ <?php if ($this->user->hasProjectAccess('TaskGanttController', 'show', $project['id'])): ?>
+ <?= $this->url->link('<i class="fa fa-sliders fa-fw"></i>', 'TaskGanttController', 'show', array('project_id' => $project['id']), false, 'dashboard-table-link', t('Gantt chart')) ?>
<?php endif ?>
- <?= $this->url->link('<i class="fa fa-list"></i>', 'listing', 'show', array('project_id' => $project['id']), false, 'dashboard-table-link', t('List')) ?>&nbsp;
- <?= $this->url->link('<i class="fa fa-calendar"></i>', 'calendar', 'show', array('project_id' => $project['id']), false, 'dashboard-table-link', t('Calendar')) ?>&nbsp;
+ <?= $this->url->link('<i class="fa fa-list"></i>', 'TaskListController', 'show', array('project_id' => $project['id']), false, 'dashboard-table-link', t('List')) ?>&nbsp;
+ <?= $this->url->link('<i class="fa fa-calendar"></i>', 'CalendarController', 'show', array('project_id' => $project['id']), false, 'dashboard-table-link', t('Calendar')) ?>&nbsp;
- <?= $this->url->link($this->text->e($project['name']), 'board', 'show', array('project_id' => $project['id'])) ?>
+ <?= $this->url->link($this->text->e($project['name']), 'BoardViewController', 'show', array('project_id' => $project['id'])) ?>
<?php if (! empty($project['description'])): ?>
- <span class="tooltip" title='<?= $this->text->e($this->text->markdown($project['description'])) ?>'>
+ <span class="tooltip" title="<?= $this->text->markdownAttribute($project['description']) ?>">
<i class="fa fa-info-circle"></i>
</span>
<?php endif ?>
diff --git a/app/Template/dashboard/show.php b/app/Template/dashboard/show.php
new file mode 100644
index 00000000..917a6651
--- /dev/null
+++ b/app/Template/dashboard/show.php
@@ -0,0 +1,12 @@
+<div class="filter-box">
+ <form method="get" action="<?= $this->url->dir() ?>" class="search">
+ <?= $this->form->hidden('controller', array('controller' => 'search')) ?>
+ <?= $this->form->hidden('action', array('action' => 'index')) ?>
+ <?= $this->form->text('SearchController', array(), array(), array('placeholder="'.t('Search').'"'), 'form-input-large') ?>
+ <?= $this->render('app/filters_helper') ?>
+ </form>
+</div>
+
+<?= $this->render('dashboard/projects', array('paginator' => $project_paginator, 'user' => $user)) ?>
+<?= $this->render('dashboard/tasks', array('paginator' => $task_paginator, 'user' => $user)) ?>
+<?= $this->render('dashboard/subtasks', array('paginator' => $subtask_paginator, 'user' => $user)) ?>
diff --git a/app/Template/dashboard/sidebar.php b/app/Template/dashboard/sidebar.php
new file mode 100644
index 00000000..86cc20f8
--- /dev/null
+++ b/app/Template/dashboard/sidebar.php
@@ -0,0 +1,27 @@
+<div class="sidebar">
+ <h2><?= $this->text->e($user['name'] ?: $user['username']) ?></h2>
+ <ul>
+ <li <?= $this->app->checkMenuSelection('DashboardController', 'show') ?>>
+ <?= $this->url->link(t('Overview'), 'DashboardController', 'show', array('user_id' => $user['id'])) ?>
+ </li>
+ <li <?= $this->app->checkMenuSelection('DashboardController', 'projects') ?>>
+ <?= $this->url->link(t('My projects'), 'DashboardController', 'projects', array('user_id' => $user['id'])) ?>
+ </li>
+ <li <?= $this->app->checkMenuSelection('DashboardController', 'tasks') ?>>
+ <?= $this->url->link(t('My tasks'), 'DashboardController', 'tasks', array('user_id' => $user['id'])) ?>
+ </li>
+ <li <?= $this->app->checkMenuSelection('DashboardController', 'subtasks') ?>>
+ <?= $this->url->link(t('My subtasks'), 'DashboardController', 'subtasks', array('user_id' => $user['id'])) ?>
+ </li>
+ <li <?= $this->app->checkMenuSelection('DashboardController', 'calendar') ?>>
+ <?= $this->url->link(t('My calendar'), 'DashboardController', 'calendar', array('user_id' => $user['id'])) ?>
+ </li>
+ <li <?= $this->app->checkMenuSelection('DashboardController', 'activity') ?>>
+ <?= $this->url->link(t('My activity stream'), 'DashboardController', 'activity', array('user_id' => $user['id'])) ?>
+ </li>
+ <li <?= $this->app->checkMenuSelection('DashboardController', 'notifications') ?>>
+ <?= $this->url->link(t('My notifications'), 'DashboardController', 'notifications', array('user_id' => $user['id'])) ?>
+ </li>
+ <?= $this->hook->render('template:dashboard:sidebar') ?>
+ </ul>
+</div>
diff --git a/app/Template/app/subtasks.php b/app/Template/dashboard/subtasks.php
index cca09481..8e0aa3ce 100644
--- a/app/Template/app/subtasks.php
+++ b/app/Template/dashboard/subtasks.php
@@ -1,5 +1,5 @@
<div class="page-header">
- <h2><?= $this->url->link(t('My subtasks'), 'app', 'subtasks', array('user_id' => $user['id'])) ?> (<?= $paginator->getTotal() ?>)</h2>
+ <h2><?= $this->url->link(t('My subtasks'), 'DashboardController', 'subtasks', array('user_id' => $user['id'])) ?> (<?= $paginator->getTotal() ?>)</h2>
</div>
<?php if ($paginator->isEmpty()): ?>
<p class="alert"><?= t('There is nothing assigned to you.') ?></p>
@@ -18,10 +18,10 @@
<?= $this->render('task/dropdown', array('task' => array('id' => $subtask['task_id'], 'project_id' => $subtask['project_id']))) ?>
</td>
<td>
- <?= $this->url->link($this->text->e($subtask['project_name']), 'board', 'show', array('project_id' => $subtask['project_id'])) ?>
+ <?= $this->url->link($this->text->e($subtask['project_name']), 'BoardViewController', 'show', array('project_id' => $subtask['project_id'])) ?>
</td>
<td>
- <?= $this->url->link($this->text->e($subtask['task_name']), 'task', 'show', array('task_id' => $subtask['task_id'], 'project_id' => $subtask['project_id'])) ?>
+ <?= $this->url->link($this->text->e($subtask['task_name']), 'TaskViewController', 'show', array('task_id' => $subtask['task_id'], 'project_id' => $subtask['project_id'])) ?>
</td>
<td>
<?= $this->subtask->toggleStatus($subtask, $subtask['project_id']) ?>
@@ -40,4 +40,4 @@
</table>
<?= $paginator ?>
-<?php endif ?> \ No newline at end of file
+<?php endif ?>
diff --git a/app/Template/app/tasks.php b/app/Template/dashboard/tasks.php
index f0ed61e0..4b83a96a 100644
--- a/app/Template/app/tasks.php
+++ b/app/Template/dashboard/tasks.php
@@ -1,5 +1,5 @@
<div class="page-header">
- <h2><?= $this->url->link(t('My tasks'), 'app', 'tasks', array('user_id' => $user['id'])) ?> (<?= $paginator->getTotal() ?>)</h2>
+ <h2><?= $this->url->link(t('My tasks'), 'DashboardController', 'tasks', array('user_id' => $user['id'])) ?> (<?= $paginator->getTotal() ?>)</h2>
</div>
<?php if ($paginator->isEmpty()): ?>
<p class="alert"><?= t('There is nothing assigned to you.') ?></p>
@@ -11,7 +11,8 @@
<th><?= $paginator->order(t('Task'), 'title') ?></th>
<th class="column-5"><?= $paginator->order('Priority', 'tasks.priority') ?></th>
<th class="column-20"><?= t('Time tracking') ?></th>
- <th class="column-20"><?= $paginator->order(t('Due date'), 'date_due') ?></th>
+ <th class="column-10"><?= $paginator->order(t('Due date'), 'date_due') ?></th>
+ <th class="column-10"><?= $paginator->order(t('Column'), 'column_title') ?></th>
</tr>
<?php foreach ($paginator->getCollection() as $task): ?>
<tr>
@@ -19,10 +20,10 @@
<?= $this->render('task/dropdown', array('task' => $task)) ?>
</td>
<td>
- <?= $this->url->link($this->text->e($task['project_name']), 'board', 'show', array('project_id' => $task['project_id'])) ?>
+ <?= $this->url->link($this->text->e($task['project_name']), 'BoardViewController', 'show', array('project_id' => $task['project_id'])) ?>
</td>
<td>
- <?= $this->url->link($this->text->e($task['title']), 'task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>
+ <?= $this->url->link($this->text->e($task['title']), 'TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>
</td>
<td>
<?php if ($task['priority'] >= 0): ?>
@@ -41,6 +42,9 @@
<td>
<?= $this->dt->date($task['date_due']) ?>
</td>
+ <td>
+ <?= $this->text->e($task['column_title']) ?>
+ </td>
</tr>
<?php endforeach ?>
</table>
diff --git a/app/Template/doc/show.php b/app/Template/doc/show.php
index 8fbadc93..a8dbd762 100644
--- a/app/Template/doc/show.php
+++ b/app/Template/doc/show.php
@@ -3,11 +3,11 @@
<ul>
<li>
<i class="fa fa-life-ring fa-fw"></i>
- <?= $this->url->link(t('Table of contents'), 'doc', 'show', array('file' => 'index')) ?>
+ <?= $this->url->link(t('Table of contents'), 'DocumentationController', 'show', array('file' => 'index')) ?>
</li>
</ul>
</div>
<div class="markdown documentation">
<?= $content ?>
</div>
-</section> \ No newline at end of file
+</section>
diff --git a/app/Template/event/comment_create.php b/app/Template/event/comment_create.php
index 9869c94b..45132e6d 100644
--- a/app/Template/event/comment_create.php
+++ b/app/Template/event/comment_create.php
@@ -1,7 +1,7 @@
<p class="activity-title">
<?= e('%s commented the task %s',
$this->text->e($author),
- $this->url->link(t('#%d', $task['id']), 'task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']))
+ $this->url->link(t('#%d', $task['id']), 'TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']))
) ?>
<span class="activity-date"><?= $this->dt->datetime($date_creation) ?></span>
</p>
diff --git a/app/Template/event/comment_update.php b/app/Template/event/comment_update.php
index 19420cf9..5a0821bd 100644
--- a/app/Template/event/comment_update.php
+++ b/app/Template/event/comment_update.php
@@ -1,7 +1,7 @@
<p class="activity-title">
<?= e('%s updated a comment on the task %s',
$this->text->e($author),
- $this->url->link(t('#%d', $task['id']), 'task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']))
+ $this->url->link(t('#%d', $task['id']), 'TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']))
) ?>
<span class="activity-date"><?= $this->dt->datetime($date_creation) ?></span>
</p>
diff --git a/app/Template/event/subtask_create.php b/app/Template/event/subtask_create.php
index 7e41d5c9..1bf36c05 100644
--- a/app/Template/event/subtask_create.php
+++ b/app/Template/event/subtask_create.php
@@ -1,7 +1,7 @@
<p class="activity-title">
<?= e('%s created a subtask for the task %s',
$this->text->e($author),
- $this->url->link(t('#%d', $task['id']), 'task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']))
+ $this->url->link(t('#%d', $task['id']), 'TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']))
) ?>
<span class="activity-date"><?= $this->dt->datetime($date_creation) ?></span>
</p>
@@ -20,4 +20,4 @@
<?php endif ?>
</li>
</ul>
-</div> \ No newline at end of file
+</div>
diff --git a/app/Template/event/subtask_update.php b/app/Template/event/subtask_update.php
index 9fea4fe8..201402f6 100644
--- a/app/Template/event/subtask_update.php
+++ b/app/Template/event/subtask_update.php
@@ -1,7 +1,7 @@
<p class="activity-title">
<?= e('%s updated a subtask for the task %s',
$this->text->e($author),
- $this->url->link(t('#%d', $task['id']), 'task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']))
+ $this->url->link(t('#%d', $task['id']), 'TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']))
) ?>
<span class="activity-date"><?= $this->dt->datetime($date_creation) ?></span>
</p>
diff --git a/app/Template/event/task_assignee_change.php b/app/Template/event/task_assignee_change.php
index db78e7df..7c962223 100644
--- a/app/Template/event/task_assignee_change.php
+++ b/app/Template/event/task_assignee_change.php
@@ -4,14 +4,14 @@
<?php if (! empty($assignee)): ?>
<?= e('%s changed the assignee of the task %s to %s',
$this->text->e($author),
- $this->url->link(t('#%d', $task['id']), 'task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])),
+ $this->url->link(t('#%d', $task['id']), 'TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])),
$this->text->e($assignee)
) ?>
<?php else: ?>
- <?= e('%s remove the assignee of the task %s', $this->text->e($author), $this->url->link(t('#%d', $task['id']), 'task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']))) ?>
+ <?= e('%s remove the assignee of the task %s', $this->text->e($author), $this->url->link(t('#%d', $task['id']), 'TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']))) ?>
<?php endif ?>
<span class="activity-date"><?= $this->dt->datetime($date_creation) ?></span>
</p>
<div class="activity-description">
<p class="activity-task-title"><?= $this->text->e($task['title']) ?></p>
-</div> \ No newline at end of file
+</div>
diff --git a/app/Template/event/task_close.php b/app/Template/event/task_close.php
index 04157b0d..90ff9207 100644
--- a/app/Template/event/task_close.php
+++ b/app/Template/event/task_close.php
@@ -1,7 +1,7 @@
<p class="activity-title">
<?= e('%s closed the task %s',
$this->text->e($author),
- $this->url->link(t('#%d', $task['id']), 'task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']))
+ $this->url->link(t('#%d', $task['id']), 'TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']))
) ?>
<span class="activity-date"><?= $this->dt->datetime($date_creation) ?></span>
</p>
diff --git a/app/Template/event/task_create.php b/app/Template/event/task_create.php
index 6e26cdb8..017a5ada 100644
--- a/app/Template/event/task_create.php
+++ b/app/Template/event/task_create.php
@@ -1,7 +1,7 @@
<p class="activity-title">
<?= e('%s created the task %s',
$this->text->e($author),
- $this->url->link(t('#%d', $task['id']), 'task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']))
+ $this->url->link(t('#%d', $task['id']), 'TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']))
) ?>
<span class="activity-date"><?= $this->dt->datetime($date_creation) ?></span>
</p>
diff --git a/app/Template/event/task_file_create.php b/app/Template/event/task_file_create.php
index 0d8e545d..d329529a 100644
--- a/app/Template/event/task_file_create.php
+++ b/app/Template/event/task_file_create.php
@@ -1,7 +1,7 @@
<p class="activity-title">
<?= e('%s attached a new file to the task %s',
$this->text->e($author),
- $this->url->link(t('#%d', $task['id']), 'task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']))
+ $this->url->link(t('#%d', $task['id']), 'TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']))
) ?>
<span class="activity-date"><?= $this->dt->datetime($date_creation) ?></span>
</p>
diff --git a/app/Template/event/task_move_column.php b/app/Template/event/task_move_column.php
index 0a78bca7..f3155e47 100644
--- a/app/Template/event/task_move_column.php
+++ b/app/Template/event/task_move_column.php
@@ -1,7 +1,7 @@
<p class="activity-title">
<?= e('%s moved the task %s to the column "%s"',
$this->text->e($author),
- $this->url->link(t('#%d', $task['id']), 'task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])),
+ $this->url->link(t('#%d', $task['id']), 'TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])),
$this->text->e($task['column_title'])
) ?>
<span class="activity-date"><?= $this->dt->datetime($date_creation) ?></span>
diff --git a/app/Template/event/task_move_position.php b/app/Template/event/task_move_position.php
index eeadfa02..ecdd02b6 100644
--- a/app/Template/event/task_move_position.php
+++ b/app/Template/event/task_move_position.php
@@ -1,7 +1,7 @@
<p class="activity-title">
<?= e('%s moved the task %s to the position #%d in the column "%s"',
$this->text->e($author),
- $this->url->link(t('#%d', $task['id']), 'task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])),
+ $this->url->link(t('#%d', $task['id']), 'TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])),
$task['position'],
$this->text->e($task['column_title'])
) ?>
diff --git a/app/Template/event/task_move_swimlane.php b/app/Template/event/task_move_swimlane.php
index a190bc0a..fe9bfb55 100644
--- a/app/Template/event/task_move_swimlane.php
+++ b/app/Template/event/task_move_swimlane.php
@@ -2,12 +2,12 @@
<?php if ($task['swimlane_id'] == 0): ?>
<?= e('%s moved the task %s to the first swimlane',
$this->text->e($author),
- $this->url->link(t('#%d', $task['id']), 'task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']))
+ $this->url->link(t('#%d', $task['id']), 'TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']))
) ?>
<?php else: ?>
<?= e('%s moved the task %s to the swimlane "%s"',
$this->text->e($author),
- $this->url->link(t('#%d', $task['id']), 'task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])),
+ $this->url->link(t('#%d', $task['id']), 'TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])),
$this->text->e($task['swimlane_name'])
) ?>
<?php endif ?>
diff --git a/app/Template/event/task_open.php b/app/Template/event/task_open.php
index d9cd90b3..548aa98f 100644
--- a/app/Template/event/task_open.php
+++ b/app/Template/event/task_open.php
@@ -1,7 +1,7 @@
<p class="activity-title">
<?= e('%s opened the task %s',
$this->text->e($author),
- $this->url->link(t('#%d', $task['id']), 'task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']))
+ $this->url->link(t('#%d', $task['id']), 'TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']))
) ?>
<span class="activity-date"><?= $this->dt->datetime($date_creation) ?></span>
</p>
diff --git a/app/Template/event/task_update.php b/app/Template/event/task_update.php
index 07b94ff8..7c7507c0 100644
--- a/app/Template/event/task_update.php
+++ b/app/Template/event/task_update.php
@@ -1,7 +1,7 @@
<p class="activity-title">
<?= e('%s updated the task %s',
$this->text->e($author),
- $this->url->link(t('#%d', $task['id']), 'task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']))
+ $this->url->link(t('#%d', $task['id']), 'TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']))
) ?>
<span class="activity-date"><?= $this->dt->datetime($date_creation) ?></span>
</p>
diff --git a/app/Template/export/sidebar.php b/app/Template/export/sidebar.php
index 6a1de7e9..55fbaeef 100644
--- a/app/Template/export/sidebar.php
+++ b/app/Template/export/sidebar.php
@@ -1,18 +1,18 @@
<div class="sidebar">
<h2><?= t('Exports') ?></h2>
<ul>
- <li <?= $this->app->getRouterAction() === 'tasks' ? 'class="active"' : '' ?>>
- <?= $this->url->link(t('Tasks'), 'export', 'tasks', array('project_id' => $project['id'])) ?>
+ <li <?= $this->app->checkMenuSelection('ExportController', 'tasks') ?>>
+ <?= $this->url->link(t('Tasks'), 'ExportController', 'tasks', array('project_id' => $project['id'])) ?>
</li>
- <li <?= $this->app->getRouterAction() === 'subtasks' ? 'class="active"' : '' ?>>
- <?= $this->url->link(t('Subtasks'), 'export', 'subtasks', array('project_id' => $project['id'])) ?>
+ <li <?= $this->app->checkMenuSelection('ExportController', 'subtasks') ?>>
+ <?= $this->url->link(t('Subtasks'), 'ExportController', 'subtasks', array('project_id' => $project['id'])) ?>
</li>
- <li <?= $this->app->getRouterAction() === 'transitions' ? 'class="active"' : '' ?>>
- <?= $this->url->link(t('Task transitions'), 'export', 'transitions', array('project_id' => $project['id'])) ?>
+ <li <?= $this->app->checkMenuSelection('ExportController', 'transitions') ?>>
+ <?= $this->url->link(t('Task transitions'), 'ExportController', 'transitions', array('project_id' => $project['id'])) ?>
</li>
- <li <?= $this->app->getRouterAction() === 'summary' ? 'class="active"' : '' ?>>
- <?= $this->url->link(t('Daily project summary'), 'export', 'summary', array('project_id' => $project['id'])) ?>
+ <li <?= $this->app->checkMenuSelection('ExportController', 'summary') ?>>
+ <?= $this->url->link(t('Daily project summary'), 'ExportController', 'summary', array('project_id' => $project['id'])) ?>
</li>
<?= $this->hook->render('template:export:sidebar') ?>
</ul>
-</div> \ No newline at end of file
+</div>
diff --git a/app/Template/feed/project.php b/app/Template/feed/project.php
index 1c6d1166..213a04d4 100644
--- a/app/Template/feed/project.php
+++ b/app/Template/feed/project.php
@@ -2,15 +2,15 @@
<feed xml:lang="en-US" xmlns="http://www.w3.org/2005/Atom">
<title><?= t('%s\'s activity', $project['name']) ?></title>
<link rel="alternate" type="text/html" href="<?= $this->url->base() ?>"/>
- <link rel="self" type="application/atom+xml" href="<?= $this->url->href('feed', 'project', array('token' => $project['token']), false, '', true) ?>"/>
+ <link rel="self" type="application/atom+xml" href="<?= $this->url->href('FeedController', 'project', array('token' => $project['token']), false, '', true) ?>"/>
<updated><?= date(DATE_ATOM) ?></updated>
- <id><?= $this->url->href('feed', 'project', array('token' => $project['token']), false, '', true) ?></id>
+ <id><?= $this->url->href('FeedController', 'project', array('token' => $project['token']), false, '', true) ?></id>
<icon><?= $this->url->base() ?>assets/img/favicon.png</icon>
<?php foreach ($events as $e): ?>
<entry>
<title type="text"><?= $e['event_title'] ?></title>
- <link rel="alternate" href="<?= $this->url->href('task', 'show', array('task_id' => $e['task_id']), false, '', true) ?>"/>
+ <link rel="alternate" href="<?= $this->url->href('TaskViewController', 'show', array('task_id' => $e['task_id']), false, '', true) ?>"/>
<id><?= $e['id'].'-'.$e['event_name'].'-'.$e['task_id'].'-'.$e['date_creation'] ?></id>
<published><?= date(DATE_ATOM, $e['date_creation']) ?></published>
<updated><?= date(DATE_ATOM, $e['date_creation']) ?></updated>
@@ -24,4 +24,4 @@
</content>
</entry>
<?php endforeach ?>
-</feed> \ No newline at end of file
+</feed>
diff --git a/app/Template/feed/user.php b/app/Template/feed/user.php
index 28847f1f..0c45f03c 100644
--- a/app/Template/feed/user.php
+++ b/app/Template/feed/user.php
@@ -2,15 +2,15 @@
<feed xml:lang="en-US" xmlns="http://www.w3.org/2005/Atom">
<title><?= t('Project activities for %s', $user['name'] ?: $user['username']) ?></title>
<link rel="alternate" type="text/html" href="<?= $this->url->base() ?>"/>
- <link rel="self" type="application/atom+xml" href="<?= $this->url->href('feed', 'user', array('token' => $user['token']), false, '', true) ?>"/>
+ <link rel="self" type="application/atom+xml" href="<?= $this->url->href('FeedController', 'user', array('token' => $user['token']), false, '', true) ?>"/>
<updated><?= date(DATE_ATOM) ?></updated>
- <id><?= $this->url->href('feed', 'user', array('token' => $user['token']), false, '', true) ?></id>
+ <id><?= $this->url->href('FeedController', 'user', array('token' => $user['token']), false, '', true) ?></id>
<icon><?= $this->url->base() ?>assets/img/favicon.png</icon>
<?php foreach ($events as $e): ?>
<entry>
<title type="text"><?= $e['event_title'] ?></title>
- <link rel="alternate" href="<?= $this->url->href('task', 'show', array('task_id' => $e['task_id']), false, '', true) ?>"/>
+ <link rel="alternate" href="<?= $this->url->href('TaskViewController', 'show', array('task_id' => $e['task_id']), false, '', true) ?>"/>
<id><?= $e['id'].'-'.$e['event_name'].'-'.$e['task_id'].'-'.$e['date_creation'] ?></id>
<published><?= date(DATE_ATOM, $e['date_creation']) ?></published>
<updated><?= date(DATE_ATOM, $e['date_creation']) ?></updated>
@@ -24,4 +24,4 @@
</content>
</entry>
<?php endforeach ?>
-</feed> \ No newline at end of file
+</feed>
diff --git a/app/Template/file_viewer/show.php b/app/Template/file_viewer/show.php
index 191aaa6c..e829a178 100644
--- a/app/Template/file_viewer/show.php
+++ b/app/Template/file_viewer/show.php
@@ -3,7 +3,7 @@
</div>
<div class="file-viewer">
<?php if ($file['is_image']): ?>
- <img src="<?= $this->url->href('FileViewer', 'image', $params) ?>" alt="<?= $this->text->e($file['name']) ?>">
+ <img src="<?= $this->url->href('FileViewerController', 'image', $params) ?>" alt="<?= $this->text->e($file['name']) ?>">
<?php elseif ($type === 'markdown'): ?>
<article class="markdown">
<?= $this->text->markdown($content) ?>
@@ -11,4 +11,4 @@
<?php elseif ($type === 'text'): ?>
<pre><?= $content ?></pre>
<?php endif ?>
-</div> \ No newline at end of file
+</div>
diff --git a/app/Template/group/associate.php b/app/Template/group/associate.php
index 9de46f35..87787568 100644
--- a/app/Template/group/associate.php
+++ b/app/Template/group/associate.php
@@ -1,25 +1,20 @@
-<section id="main">
- <div class="page-header">
- <ul>
- <li><i class="fa fa-users fa-fw"></i><?= $this->url->link(t('View all groups'), 'group', 'index') ?></li>
- <li><i class="fa fa-user fa-fw"></i><?= $this->url->link(t('View group members'), 'group', 'users', array('group_id' => $group['id'])) ?></li>
- </ul>
- </div>
- <?php if (empty($users)): ?>
- <p class="alert"><?= t('There is no user available.') ?></p>
- <?php else: ?>
- <form method="post" action="<?= $this->url->href('group', 'addUser', array('group_id' => $group['id'])) ?>" autocomplete="off">
- <?= $this->form->csrf() ?>
- <?= $this->form->hidden('group_id', $values) ?>
+<div class="page-header">
+ <h2><?= t('Add group member to "%s"', $group['name']) ?></h2>
+</div>
+<?php if (empty($users)): ?>
+ <p class="alert"><?= t('There is no user available.') ?></p>
+<?php else: ?>
+ <form class="popover-form" method="post" action="<?= $this->url->href('GroupListController', 'addUser', array('group_id' => $group['id'])) ?>" autocomplete="off">
+ <?= $this->form->csrf() ?>
+ <?= $this->form->hidden('group_id', $values) ?>
- <?= $this->form->label(t('User'), 'user_id') ?>
- <?= $this->form->select('user_id', $users, $values, $errors, array('required'), 'chosen-select') ?>
+ <?= $this->form->label(t('User'), 'user_id') ?>
+ <?= $this->form->select('user_id', $users, $values, $errors, array('required'), 'chosen-select') ?>
- <div class="form-actions">
- <button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
- <?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'group', 'index') ?>
- </div>
- </form>
- <?php endif ?>
-</section>
+ <div class="form-actions">
+ <button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
+ <?= t('or') ?>
+ <?= $this->url->link(t('cancel'), 'GroupListController', 'index', array(), false, 'close-popover') ?>
+ </div>
+ </form>
+<?php endif ?>
diff --git a/app/Template/group/create.php b/app/Template/group/create.php
deleted file mode 100644
index 4ce6b1f3..00000000
--- a/app/Template/group/create.php
+++ /dev/null
@@ -1,19 +0,0 @@
-<section id="main">
- <div class="page-header">
- <ul>
- <li><i class="fa fa-users fa-fw"></i><?= $this->url->link(t('View all groups'), 'group', 'index') ?></li>
- </ul>
- </div>
- <form method="post" action="<?= $this->url->href('group', 'save') ?>" autocomplete="off">
- <?= $this->form->csrf() ?>
-
- <?= $this->form->label(t('Name'), 'name') ?>
- <?= $this->form->text('name', $values, $errors, array('autofocus', 'required', 'maxlength="100"')) ?>
-
- <div class="form-actions">
- <button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
- <?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'group', 'index') ?>
- </div>
- </form>
-</section>
diff --git a/app/Template/group/dissociate.php b/app/Template/group/dissociate.php
index e1c60764..50ef6d61 100644
--- a/app/Template/group/dissociate.php
+++ b/app/Template/group/dissociate.php
@@ -1,17 +1,12 @@
-<section id="main">
- <div class="page-header">
- <ul>
- <li><i class="fa fa-users fa-fw"></i><?= $this->url->link(t('View all groups'), 'group', 'index') ?></li>
- <li><i class="fa fa-user fa-fw"></i><?= $this->url->link(t('View group members'), 'group', 'users', array('group_id' => $group['id'])) ?></li>
- </ul>
- </div>
- <div class="confirm">
- <p class="alert alert-info"><?= t('Do you really want to remove the user "%s" from the group "%s"?', $user['name'] ?: $user['username'], $group['name']) ?></p>
+<div class="page-header">
+ <h2><?= t('Remove user from group "%s"', $group['name']) ?></h2>
+</div>
+<div class="confirm">
+ <p class="alert alert-info"><?= t('Do you really want to remove the user "%s" from the group "%s"?', $user['name'] ?: $user['username'], $group['name']) ?></p>
- <div class="form-actions">
- <?= $this->url->link(t('Yes'), 'group', 'removeUser', array('group_id' => $group['id'], 'user_id' => $user['id']), true, 'btn btn-red') ?>
- <?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'group', 'users', array('group_id' => $group['id'])) ?>
- </div>
+ <div class="form-actions">
+ <?= $this->url->link(t('Yes'), 'GroupListController', 'removeUser', array('group_id' => $group['id'], 'user_id' => $user['id']), true, 'btn btn-red') ?>
+ <?= t('or') ?>
+ <?= $this->url->link(t('cancel'), 'GroupListController', 'users', array('group_id' => $group['id']), false, 'close-popover') ?>
</div>
-</section>
+</div>
diff --git a/app/Template/group/edit.php b/app/Template/group/edit.php
deleted file mode 100644
index e9d9dd5a..00000000
--- a/app/Template/group/edit.php
+++ /dev/null
@@ -1,22 +0,0 @@
-<section id="main">
- <div class="page-header">
- <ul>
- <li><i class="fa fa-users fa-fw"></i><?= $this->url->link(t('View all groups'), 'group', 'index') ?></li>
- </ul>
- </div>
- <form method="post" action="<?= $this->url->href('group', 'update') ?>" autocomplete="off">
- <?= $this->form->csrf() ?>
-
- <?= $this->form->hidden('id', $values) ?>
- <?= $this->form->hidden('external_id', $values) ?>
-
- <?= $this->form->label(t('Name'), 'name') ?>
- <?= $this->form->text('name', $values, $errors, array('autofocus', 'required', 'maxlength="100"')) ?>
-
- <div class="form-actions">
- <button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
- <?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'group', 'index') ?>
- </div>
- </form>
-</section>
diff --git a/app/Template/group/index.php b/app/Template/group/index.php
index 8302e5a8..1062e18c 100644
--- a/app/Template/group/index.php
+++ b/app/Template/group/index.php
@@ -1,8 +1,8 @@
<section id="main">
<div class="page-header">
<ul>
- <li><i class="fa fa-user fa-fw"></i><?= $this->url->link(t('All users'), 'user', 'index') ?></li>
- <li><i class="fa fa-user-plus fa-fw"></i><?= $this->url->link(t('New group'), 'group', 'create') ?></li>
+ <li><i class="fa fa-user fa-fw"></i><?= $this->url->link(t('All users'), 'UserListController', 'show') ?></li>
+ <li><i class="fa fa-user-plus fa-fw"></i><?= $this->url->link(t('New group'), 'GroupCreationController', 'show', array(), false, 'popover') ?></li>
</ul>
</div>
<?php if ($paginator->isEmpty()): ?>
@@ -24,16 +24,16 @@
<?= $this->text->e($group['external_id']) ?>
</td>
<td>
- <?= $this->text->e($group['name']) ?>
+ <?= $this->url->link($this->text->e($group['name']), 'GroupListController', 'users', array('group_id' => $group['id'])) ?>
</td>
<td>
<div class="dropdown">
<a href="#" class="dropdown-menu dropdown-menu-link-icon"><i class="fa fa-cog fa-fw"></i><i class="fa fa-caret-down"></i></a>
<ul>
- <li><?= $this->url->link(t('Add group member'), 'group', 'associate', array('group_id' => $group['id'])) ?></li>
- <li><?= $this->url->link(t('Members'), 'group', 'users', array('group_id' => $group['id'])) ?></li>
- <li><?= $this->url->link(t('Edit'), 'group', 'edit', array('group_id' => $group['id'])) ?></li>
- <li><?= $this->url->link(t('Remove'), 'group', 'confirm', array('group_id' => $group['id'])) ?></li>
+ <li><?= $this->url->link(t('Add group member'), 'GroupListController', 'associate', array('group_id' => $group['id']), false, 'popover') ?></li>
+ <li><?= $this->url->link(t('Members'), 'GroupListController', 'users', array('group_id' => $group['id'])) ?></li>
+ <li><?= $this->url->link(t('Edit'), 'GroupModificationController', 'show', array('group_id' => $group['id']), false, 'popover') ?></li>
+ <li><?= $this->url->link(t('Remove'), 'GroupListController', 'confirm', array('group_id' => $group['id']), false, 'popover') ?></li>
</ul>
</div>
</td>
diff --git a/app/Template/group/remove.php b/app/Template/group/remove.php
index 1cb007b1..408b3d83 100644
--- a/app/Template/group/remove.php
+++ b/app/Template/group/remove.php
@@ -1,17 +1,12 @@
-<section id="main">
- <div class="page-header">
- <ul>
- <li><i class="fa fa-users fa-fw"></i><?= $this->url->link(t('View all groups'), 'group', 'index') ?></li>
- <li><i class="fa fa-user fa-fw"></i><?= $this->url->link(t('View group members'), 'group', 'users', array('group_id' => $group['id'])) ?></li>
- </ul>
- </div>
- <div class="confirm">
- <p class="alert alert-info"><?= t('Do you really want to remove this group: "%s"?', $group['name']) ?></p>
+<div class="page-header">
+ <h2><?= t('Remove group') ?></h2>
+</div>
+<div class="confirm">
+ <p class="alert alert-info"><?= t('Do you really want to remove this group: "%s"?', $group['name']) ?></p>
- <div class="form-actions">
- <?= $this->url->link(t('Yes'), 'group', 'remove', array('group_id' => $group['id']), true, 'btn btn-red') ?>
- <?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'group', 'index') ?>
- </div>
+ <div class="form-actions">
+ <?= $this->url->link(t('Yes'), 'GroupListController', 'remove', array('group_id' => $group['id']), true, 'btn btn-red') ?>
+ <?= t('or') ?>
+ <?= $this->url->link(t('cancel'), 'GroupListController', 'index', array(), false, 'close-popover') ?>
</div>
-</section>
+</div>
diff --git a/app/Template/group/users.php b/app/Template/group/users.php
index bbd41525..a4895ab7 100644
--- a/app/Template/group/users.php
+++ b/app/Template/group/users.php
@@ -1,8 +1,8 @@
<section id="main">
<div class="page-header">
<ul>
- <li><i class="fa fa-users fa-fw"></i><?= $this->url->link(t('View all groups'), 'group', 'index') ?></li>
- <li><i class="fa fa-plus fa-fw"></i><?= $this->url->link(t('Add group member'), 'group', 'associate', array('group_id' => $group['id'])) ?></li>
+ <li><i class="fa fa-users fa-fw"></i><?= $this->url->link(t('View all groups'), 'GroupListController', 'index') ?></li>
+ <li><i class="fa fa-plus fa-fw"></i><?= $this->url->link(t('Add group member'), 'GroupListController', 'associate', array('group_id' => $group['id']), false, 'popover') ?></li>
</ul>
</div>
<?php if ($paginator->isEmpty()): ?>
@@ -19,10 +19,10 @@
<?php foreach ($paginator->getCollection() as $user): ?>
<tr>
<td>
- <?= $this->url->link('#'.$user['id'], 'user', 'show', array('user_id' => $user['id'])) ?>
+ <?= $this->url->link('#'.$user['id'], 'UserViewController', 'show', array('user_id' => $user['id'])) ?>
</td>
<td>
- <?= $this->url->link($this->text->e($user['username']), 'user', 'show', array('user_id' => $user['id'])) ?>
+ <?= $this->url->link($this->text->e($user['username']), 'UserViewController', 'show', array('user_id' => $user['id'])) ?>
</td>
<td>
<?= $this->text->e($user['name']) ?>
@@ -31,7 +31,8 @@
<a href="mailto:<?= $this->text->e($user['email']) ?>"><?= $this->text->e($user['email']) ?></a>
</td>
<td>
- <?= $this->url->link(t('Remove this user'), 'group', 'dissociate', array('group_id' => $group['id'], 'user_id' => $user['id'])) ?>
+ <i class="fa fa-times fa-fw" aria-hidden="true"></i>
+ <?= $this->url->link(t('Remove this user'), 'GroupListController', 'dissociate', array('group_id' => $group['id'], 'user_id' => $user['id']), false, 'popover') ?>
</td>
</tr>
<?php endforeach ?>
diff --git a/app/Template/group_creation/show.php b/app/Template/group_creation/show.php
new file mode 100644
index 00000000..b219bd70
--- /dev/null
+++ b/app/Template/group_creation/show.php
@@ -0,0 +1,15 @@
+<div class="page-header">
+ <h2><?= t('New group') ?></h2>
+</div>
+<form class="popover-form" method="post" action="<?= $this->url->href('GroupCreationController', 'save') ?>" autocomplete="off">
+ <?= $this->form->csrf() ?>
+
+ <?= $this->form->label(t('Name'), 'name') ?>
+ <?= $this->form->text('name', $values, $errors, array('autofocus', 'required', 'maxlength="100"')) ?>
+
+ <div class="form-actions">
+ <button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
+ <?= t('or') ?>
+ <?= $this->url->link(t('cancel'), 'GroupListController', 'index', array(), false, 'close-popover') ?>
+ </div>
+</form>
diff --git a/app/Template/group_modification/show.php b/app/Template/group_modification/show.php
new file mode 100644
index 00000000..ddf07369
--- /dev/null
+++ b/app/Template/group_modification/show.php
@@ -0,0 +1,18 @@
+<div class="page-header">
+ <h2><?= t('Edit group') ?></h2>
+</div>
+<form class="popover-form" method="post" action="<?= $this->url->href('GroupModificationController', 'save') ?>" autocomplete="off">
+ <?= $this->form->csrf() ?>
+
+ <?= $this->form->hidden('id', $values) ?>
+ <?= $this->form->hidden('external_id', $values) ?>
+
+ <?= $this->form->label(t('Name'), 'name') ?>
+ <?= $this->form->text('name', $values, $errors, array('autofocus', 'required', 'maxlength="100"')) ?>
+
+ <div class="form-actions">
+ <button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
+ <?= t('or') ?>
+ <?= $this->url->link(t('cancel'), 'GroupListController', 'index', array(), false, 'close-popover') ?>
+ </div>
+</form>
diff --git a/app/Template/header.php b/app/Template/header.php
index a09d19c4..13521ae7 100644
--- a/app/Template/header.php
+++ b/app/Template/header.php
@@ -2,13 +2,17 @@
<nav>
<h1>
<span class="logo">
- <?= $this->url->link('K<span>B</span>', 'app', 'index', array(), false, '', t('Dashboard')) ?>
+ <?= $this->url->link('K<span>B</span>', 'DashboardController', 'show', array(), false, '', t('Dashboard')) ?>
</span>
<span class="title">
- <?= $this->text->e($title) ?>
+ <?php if (isset($project) && ! empty($project)): ?>
+ <?= $this->url->link($this->text->e($project['name']), 'BoardViewController', 'show', array('project_id' => $project['id'])) ?>
+ <?php else: ?>
+ <?= $this->text->e($title) ?>
+ <?php endif ?>
</span>
<?php if (! empty($description)): ?>
- <span class="tooltip" title='<?= $this->text->e($this->text->markdown($description)) ?>'>
+ <span class="tooltip" title="<?= $this->text->markdownAttribute($description) ?>">
<i class="fa fa-info-circle"></i>
</span>
<?php endif ?>
@@ -23,7 +27,7 @@
data-notfound="<?= t('No results match:') ?>"
data-placeholder="<?= t('Display another project') ?>"
data-redirect-regex="PROJECT_ID"
- data-redirect-url="<?= $this->url->href('board', 'show', array('project_id' => 'PROJECT_ID')) ?>">
+ data-redirect-url="<?= $this->url->href('BoardViewController', 'show', array('project_id' => 'PROJECT_ID')) ?>">
<option value=""></option>
<?php foreach ($board_selector as $board_id => $board_name): ?>
<option value="<?= $board_id ?>"><?= $this->text->e($board_name) ?></option>
@@ -34,11 +38,11 @@
<li class="user-links">
<?php if ($this->user->hasNotifications()): ?>
<span class="notification">
- <?= $this->url->link('<i class="fa fa-bell web-notification-icon"></i>', 'app', 'notifications', array('user_id' => $this->user->getId()), false, '', t('Unread notifications')) ?>
+ <?= $this->url->link('<i class="fa fa-bell web-notification-icon"></i>', 'DashboardController', 'notifications', array('user_id' => $this->user->getId()), false, '', t('Unread notifications')) ?>
</span>
<?php endif ?>
- <?php $has_project_creation_access = $this->user->hasAccess('ProjectCreation', 'create'); ?>
+ <?php $has_project_creation_access = $this->user->hasAccess('ProjectCreationController', 'create'); ?>
<?php $is_private_project_enabled = $this->app->config('disable_private_project', 0) == 0; ?>
<?php if ($has_project_creation_access || (!$has_project_creation_access && $is_private_project_enabled)): ?>
@@ -46,11 +50,13 @@
<a href="#" class="dropdown-menu dropdown-menu-link-icon"><i class="fa fa-plus fa-fw"></i><i class="fa fa-caret-down"></i></a>
<ul>
<?php if ($has_project_creation_access): ?>
- <li><i class="fa fa-plus fa-fw"></i><?= $this->url->link(t('New project'), 'ProjectCreation', 'create', array(), false, 'popover') ?></li>
+ <li><i class="fa fa-plus fa-fw"></i>
+ <?= $this->url->link(t('New project'), 'ProjectCreationController', 'create', array(), false, 'popover') ?></li>
<?php endif ?>
<?php if ($is_private_project_enabled): ?>
<li>
- <i class="fa fa-lock fa-fw"></i><?= $this->url->link(t('New private project'), 'ProjectCreation', 'createPrivate', array(), false, 'popover') ?>
+ <i class="fa fa-lock fa-fw"></i>
+ <?= $this->url->link(t('New private project'), 'ProjectCreationController', 'createPrivate', array(), false, 'popover') ?>
</li>
<?php endif ?>
</ul>
@@ -63,28 +69,32 @@
<li class="no-hover"><strong><?= $this->text->e($this->user->getFullname()) ?></strong></li>
<li>
<i class="fa fa-tachometer fa-fw"></i>
- <?= $this->url->link(t('My dashboard'), 'app', 'index', array('user_id' => $this->user->getId())) ?>
+ <?= $this->url->link(t('My dashboard'), 'DashboardController', 'show', array('user_id' => $this->user->getId())) ?>
</li>
<li>
<i class="fa fa-home fa-fw"></i>
- <?= $this->url->link(t('My profile'), 'user', 'show', array('user_id' => $this->user->getId())) ?>
+ <?= $this->url->link(t('My profile'), 'UserViewController', 'show', array('user_id' => $this->user->getId())) ?>
</li>
<li>
<i class="fa fa-folder fa-fw"></i>
- <?= $this->url->link(t('Projects management'), 'project', 'index') ?>
+ <?= $this->url->link(t('Projects management'), 'ProjectListController', 'show') ?>
</li>
- <?php if ($this->user->hasAccess('user', 'index')): ?>
+ <?php if ($this->user->hasAccess('UserListController', 'show')): ?>
<li>
<i class="fa fa-user fa-fw"></i>
- <?= $this->url->link(t('Users management'), 'user', 'index') ?>
+ <?= $this->url->link(t('Users management'), 'UserListController', 'show') ?>
</li>
<li>
<i class="fa fa-group fa-fw"></i>
- <?= $this->url->link(t('Groups management'), 'group', 'index') ?>
+ <?= $this->url->link(t('Groups management'), 'GroupListController', 'index') ?>
+ </li>
+ <li>
+ <i class="fa fa-cubes" aria-hidden="true"></i>
+ <?= $this->url->link(t('Plugins'), 'PluginController', 'show') ?>
</li>
<li>
<i class="fa fa-cog fa-fw"></i>
- <?= $this->url->link(t('Settings'), 'config', 'index') ?>
+ <?= $this->url->link(t('Settings'), 'ConfigController', 'index') ?>
</li>
<?php endif ?>
@@ -92,12 +102,12 @@
<li>
<i class="fa fa-life-ring fa-fw"></i>
- <?= $this->url->link(t('Documentation'), 'doc', 'show') ?>
+ <?= $this->url->link(t('Documentation'), 'DocumentationController', 'show') ?>
</li>
<?php if (! DISABLE_LOGOUT): ?>
<li>
<i class="fa fa-sign-out fa-fw"></i>
- <?= $this->url->link(t('Logout'), 'auth', 'logout') ?>
+ <?= $this->url->link(t('Logout'), 'AuthController', 'logout') ?>
</li>
<?php endif ?>
</ul>
diff --git a/app/Template/layout.php b/app/Template/layout.php
index 67924e3e..ebce6ffa 100644
--- a/app/Template/layout.php
+++ b/app/Template/layout.php
@@ -12,15 +12,17 @@
<meta http-equiv="refresh" content="<?= $board_public_refresh_interval ?>">
<?php endif ?>
- <?php if (! isset($not_editable)): ?>
- <?= $this->asset->js('assets/js/app.js') ?>
- <?php endif ?>
-
<?= $this->asset->colorCss() ?>
- <?= $this->asset->css('assets/css/app.css') ?>
- <?= $this->asset->css('assets/css/print.css', true, 'print') ?>
+ <?= $this->asset->css('assets/css/vendor.min.css') ?>
+ <?= $this->asset->css('assets/css/app.min.css') ?>
+ <?= $this->asset->css('assets/css/print.min.css', true, 'print') ?>
<?= $this->asset->customCss() ?>
+ <?php if (! isset($not_editable)): ?>
+ <?= $this->asset->js('assets/js/vendor.min.js') ?>
+ <?= $this->asset->js('assets/js/app.min.js') ?>
+ <?php endif ?>
+
<?= $this->hook->asset('css', 'template:layout:css') ?>
<?= $this->hook->asset('js', 'template:layout:js') ?>
@@ -30,13 +32,21 @@
<link rel="apple-touch-icon" sizes="114x114" href="<?= $this->url->dir() ?>assets/img/touch-icon-iphone-retina.png">
<link rel="apple-touch-icon" sizes="144x144" href="<?= $this->url->dir() ?>assets/img/touch-icon-ipad-retina.png">
- <title><?= isset($title) ? $this->text->e($title) : 'Kanboard' ?></title>
+ <title>
+ <?php if (isset($page_title)): ?>
+ <?= $this->text->e($page_title) ?>
+ <?php elseif (isset($title)): ?>
+ <?= $this->text->e($title) ?>
+ <?php else: ?>
+ Kanboard
+ <?php endif ?>
+ </title>
<?= $this->hook->render('template:layout:head') ?>
</head>
- <body data-status-url="<?= $this->url->href('app', 'status') ?>"
- data-login-url="<?= $this->url->href('auth', 'login') ?>"
- data-keyboard-shortcut-url="<?= $this->url->href('Doc', 'shortcuts') ?>"
+ <body data-status-url="<?= $this->url->href('UserAjaxController', 'status') ?>"
+ data-login-url="<?= $this->url->href('AuthController', 'login') ?>"
+ data-keyboard-shortcut-url="<?= $this->url->href('DocumentationController', 'shortcuts') ?>"
data-timezone="<?= $this->app->getTimezone() ?>"
data-js-lang="<?= $this->app->jsLang() ?>">
@@ -48,12 +58,13 @@
'title' => $title,
'description' => isset($description) ? $description : '',
'board_selector' => isset($board_selector) ? $board_selector : array(),
+ 'project' => isset($project) ? $project : array(),
)) ?>
<section class="page">
<?= $this->app->flashMessage() ?>
<?= $content_for_layout ?>
</section>
<?= $this->hook->render('template:layout:bottom') ?>
- <?php endif ?>
+ <?php endif ?>
</body>
</html>
diff --git a/app/Template/link/create.php b/app/Template/link/create.php
index 3b36abee..23990604 100644
--- a/app/Template/link/create.php
+++ b/app/Template/link/create.php
@@ -2,7 +2,7 @@
<h2><?= t('Add a new link') ?></h2>
</div>
-<form action="<?= $this->url->href('link', 'save') ?>" method="post" autocomplete="off">
+<form action="<?= $this->url->href('LinkController', 'save') ?>" method="post" autocomplete="off">
<?= $this->form->csrf() ?>
@@ -15,4 +15,4 @@
<div class="form-actions">
<button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
</div>
-</form> \ No newline at end of file
+</form>
diff --git a/app/Template/link/edit.php b/app/Template/link/edit.php
index e91422be..0ad73275 100644
--- a/app/Template/link/edit.php
+++ b/app/Template/link/edit.php
@@ -2,7 +2,7 @@
<h2><?= t('Link modification') ?></h2>
</div>
-<form action="<?= $this->url->href('link', 'update', array('link_id' => $link['id'])) ?>" method="post" autocomplete="off">
+<form action="<?= $this->url->href('LinkController', 'update', array('link_id' => $link['id'])) ?>" method="post" autocomplete="off">
<?= $this->form->csrf() ?>
<?= $this->form->hidden('id', $values) ?>
@@ -18,4 +18,4 @@
<?= t('or') ?>
<?= $this->url->link(t('cancel'), 'link', 'index') ?>
</div>
-</form> \ No newline at end of file
+</form>
diff --git a/app/Template/link/index.php b/app/Template/link/index.php
index 1475bd50..7e32069a 100644
--- a/app/Template/link/index.php
+++ b/app/Template/link/index.php
@@ -18,9 +18,9 @@
</td>
<td>
<ul>
- <?= $this->url->link(t('Edit'), 'link', 'edit', array('link_id' => $link['id'])) ?>
+ <?= $this->url->link(t('Edit'), 'LinkController', 'edit', array('link_id' => $link['id'])) ?>
<?= t('or') ?>
- <?= $this->url->link(t('Remove'), 'link', 'confirm', array('link_id' => $link['id'])) ?>
+ <?= $this->url->link(t('Remove'), 'LinkController', 'confirm', array('link_id' => $link['id'])) ?>
</ul>
</td>
</tr>
@@ -30,4 +30,4 @@
<?= t('There is no link.') ?>
<?php endif ?>
-<?= $this->render('link/create', array('values' => $values, 'errors' => $errors)) ?> \ No newline at end of file
+<?= $this->render('link/create', array('values' => $values, 'errors' => $errors)) ?>
diff --git a/app/Template/link/remove.php b/app/Template/link/remove.php
index 12ca14bb..b7fbef5e 100644
--- a/app/Template/link/remove.php
+++ b/app/Template/link/remove.php
@@ -8,8 +8,8 @@
</p>
<div class="form-actions">
- <?= $this->url->link(t('Yes'), 'link', 'remove', array('link_id' => $link['id']), true, 'btn btn-red') ?>
+ <?= $this->url->link(t('Yes'), 'LinkController', 'remove', array('link_id' => $link['id']), true, 'btn btn-red') ?>
<?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'link', 'index') ?>
+ <?= $this->url->link(t('cancel'), 'LinkController', 'index') ?>
</div>
-</div> \ No newline at end of file
+</div>
diff --git a/app/Template/notification/footer.php b/app/Template/notification/footer.php
index c3b37884..6ac260cb 100644
--- a/app/Template/notification/footer.php
+++ b/app/Template/notification/footer.php
@@ -2,6 +2,6 @@
Kanboard
<?php if (isset($application_url) && ! empty($application_url)): ?>
- - <a href="<?= $this->url->href('task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, '', true) ?>"><?= t('view the task on Kanboard') ?></a>
- - <a href="<?= $this->url->href('board', 'show', array('project_id' => $task['project_id']), false, '', true) ?>"><?= t('view the board on Kanboard') ?></a>
+ - <a href="<?= $this->url->href('TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, '', true) ?>"><?= t('view the task on Kanboard') ?></a>
+ - <a href="<?= $this->url->href('BoardViewController', 'show', array('project_id' => $task['project_id']), false, '', true) ?>"><?= t('view the board on Kanboard') ?></a>
<?php endif ?>
diff --git a/app/Template/notification/task_overdue.php b/app/Template/notification/task_overdue.php
index ee2ff379..406e41f7 100644
--- a/app/Template/notification/task_overdue.php
+++ b/app/Template/notification/task_overdue.php
@@ -2,7 +2,7 @@
<table style="font-size: .8em; table-layout: fixed; width: 100%; border-collapse: collapse; border-spacing: 0; margin-bottom: 20px;" cellpadding=5 cellspacing=1>
<tr style="background: #fbfbfb; text-align: left; padding-top: .5em; padding-bottom: .5em; padding-left: 3px; padding-right: 3px;">
- <th style="border: 1px solid #eee;"><?= t('ID') ?></th>
+ <th style="border: 1px solid #eee;"><?= t('Id') ?></th>
<th style="border: 1px solid #eee;"><?= t('Title') ?></th>
<th style="border: 1px solid #eee;"><?= t('Due date') ?></th>
<th style="border: 1px solid #eee;"><?= t('Project') ?></th>
@@ -14,7 +14,7 @@
<td style="border: 1px solid #eee;">#<?= $task['id'] ?></td>
<td style="border: 1px solid #eee;">
<?php if ($application_url): ?>
- <a href="<?= $this->url->href('task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, '', true) ?>"><?= $this->text->e($task['title']) ?></a>
+ <a href="<?= $this->url->href('TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, '', true) ?>"><?= $this->text->e($task['title']) ?></a>
<?php else: ?>
<?= $this->text->e($task['title']) ?>
<?php endif ?>
@@ -23,7 +23,7 @@
<td style="border: 1px solid #eee;"><?= $task['project_name'] ?></td>
<td style="border: 1px solid #eee;">
<?php if ($task['assignee_username']): ?>
- <?= t('%s', $task['assignee_name'] ?: $task['assignee_username']) ?>
+ <?= $this->text->e($task['assignee_name'] ?: $task['assignee_username']) ?>
<?php endif ?>
</td>
</tr>
diff --git a/app/Template/password_reset/change.php b/app/Template/password_reset/change.php
index 0a1d8de4..80a035da 100644
--- a/app/Template/password_reset/change.php
+++ b/app/Template/password_reset/change.php
@@ -1,6 +1,6 @@
<div class="form-login">
<h2><?= t('Password Reset') ?></h2>
- <form method="post" action="<?= $this->url->href('PasswordReset', 'update', array('token' => $token)) ?>">
+ <form method="post" action="<?= $this->url->href('PasswordResetController', 'update', array('token' => $token)) ?>">
<?= $this->form->csrf() ?>
<?= $this->form->label(t('New password'), 'password') ?>
@@ -13,4 +13,4 @@
<button type="submit" class="btn btn-blue"><?= t('Change Password') ?></button>
</div>
</form>
-</div> \ No newline at end of file
+</div>
diff --git a/app/Template/password_reset/create.php b/app/Template/password_reset/create.php
index 918a0eb4..f43d95fc 100644
--- a/app/Template/password_reset/create.php
+++ b/app/Template/password_reset/create.php
@@ -1,17 +1,17 @@
<div class="form-login">
<h2><?= t('Password Reset') ?></h2>
- <form method="post" action="<?= $this->url->href('PasswordReset', 'save') ?>">
+ <form method="post" action="<?= $this->url->href('PasswordResetController', 'save') ?>">
<?= $this->form->csrf() ?>
<?= $this->form->label(t('Username'), 'username') ?>
<?= $this->form->text('username', $values, $errors, array('autofocus', 'required')) ?>
<?= $this->form->label(t('Enter the text below'), 'captcha') ?>
- <img src="<?= $this->url->href('Captcha', 'image') ?>"/>
+ <img src="<?= $this->url->href('CaptchaController', 'image') ?>" alt="Captcha">
<?= $this->form->text('captcha', array(), $errors, array('required')) ?>
<div class="form-actions">
<button type="submit" class="btn btn-blue"><?= t('Change Password') ?></button>
</div>
</form>
-</div> \ No newline at end of file
+</div>
diff --git a/app/Template/password_reset/email.php b/app/Template/password_reset/email.php
index 62788b49..63b08e49 100644
--- a/app/Template/password_reset/email.php
+++ b/app/Template/password_reset/email.php
@@ -1,6 +1,6 @@
<p><?= t('To reset your password click on this link:') ?></p>
-<p><?= $this->url->to('PasswordReset', 'change', array('token' => $token), '', true) ?></p>
+<p><?= $this->url->to('PasswordResetController', 'change', array('token' => $token), '', true) ?></p>
<hr>
-Kanboard \ No newline at end of file
+Kanboard
diff --git a/app/Template/plugin/directory.php b/app/Template/plugin/directory.php
new file mode 100644
index 00000000..b6c6734c
--- /dev/null
+++ b/app/Template/plugin/directory.php
@@ -0,0 +1,55 @@
+<div class="page-header">
+ <h2><?= t('Plugin Directory') ?></h2>
+</div>
+
+<?php if (! $is_configured): ?>
+<p class="alert alert-error">
+ <?= t('Your Kanboard instance is not configured to install plugins from the user interface.') ?>
+</p>
+<?php endif ?>
+
+<?php if (empty($available_plugins)): ?>
+ <p class="alert"><?= t('There is no plugin available.') ?></p>
+<?php else: ?>
+ <?php foreach ($available_plugins as $plugin): ?>
+ <table>
+ <tr>
+ <th colspan="3">
+ <a href="<?= $plugin['homepage'] ?>" target="_blank" rel="noreferrer"><?= $this->text->e($plugin['title']) ?></a>
+ </th>
+ </tr>
+ <tr>
+ <td class="column-40">
+ <?= $this->text->e($plugin['author']) ?>
+ </td>
+ <td class="column-30">
+ <?= $this->text->e($plugin['version']) ?>
+ </td>
+ <td>
+ <?php if ($is_configured): ?>
+ <?php if (! isset($installed_plugins[$plugin['title']])): ?>
+ <i class="fa fa-cloud-download fa-fw" aria-hidden="true"></i>
+ <?= $this->url->link(t('Install'), 'PluginController', 'install', array('archive_url' => urlencode($plugin['download'])), true) ?>
+ <?php elseif ($installed_plugins[$plugin['title']] < $plugin['version']): ?>
+ <i class="fa fa-refresh fa-fw" aria-hidden="true"></i>
+ <?= $this->url->link(t('Update'), 'PluginController', 'update', array('archive_url' => urlencode($plugin['download'])), true) ?>
+ <?php else: ?>
+ <i class="fa fa-check-circle-o" aria-hidden="true"></i>
+ <?= t('Up to date') ?>
+ <?php endif ?>
+ <?php else: ?>
+ <i class="fa fa-ban fa-fw" aria-hidden="true"></i>
+ <?= t('Not available') ?>
+ <?php endif ?>
+ </td>
+ </tr>
+ <tr>
+ <td colspan="3">
+ <div class="markdown">
+ <?= $this->text->markdown($plugin['description']) ?>
+ </div>
+ </td>
+ </tr>
+ </table>
+ <?php endforeach ?>
+<?php endif ?>
diff --git a/app/Template/plugin/layout.php b/app/Template/plugin/layout.php
new file mode 100644
index 00000000..6eafa593
--- /dev/null
+++ b/app/Template/plugin/layout.php
@@ -0,0 +1,9 @@
+<section id="main">
+ <section class="sidebar-container" id="config-section">
+ <?= $this->render($sidebar_template) ?>
+
+ <div class="sidebar-content">
+ <?= $content_for_sublayout ?>
+ </div>
+ </section>
+</section>
diff --git a/app/Template/plugin/remove.php b/app/Template/plugin/remove.php
new file mode 100644
index 00000000..bd8f4eb8
--- /dev/null
+++ b/app/Template/plugin/remove.php
@@ -0,0 +1,13 @@
+<div class="page-header">
+ <h2><?= t('Remove plugin') ?></h2>
+</div>
+
+<div class="confirm">
+ <p class="alert alert-info"><?= t('Do you really want to remove this plugin: "%s"?', $plugin->getPluginName()) ?></p>
+
+ <div class="form-actions">
+ <?= $this->url->link(t('Yes'), 'PluginController', 'uninstall', array('pluginId' => $plugin_id), true, 'btn btn-red') ?>
+ <?= t('or') ?>
+ <?= $this->url->link(t('cancel'), 'PluginController', 'show', array(), false, 'close-popover') ?>
+ </div>
+</div>
diff --git a/app/Template/plugin/show.php b/app/Template/plugin/show.php
new file mode 100644
index 00000000..9c3d6d20
--- /dev/null
+++ b/app/Template/plugin/show.php
@@ -0,0 +1,41 @@
+<div class="page-header">
+ <h2><?= t('Installed Plugins') ?></h2>
+</div>
+
+<?php if (empty($plugins)): ?>
+ <p class="alert"><?= t('There is no plugin loaded.') ?></p>
+<?php else: ?>
+ <table>
+ <tr>
+ <th class="column-35"><?= t('Name') ?></th>
+ <th class="column-30"><?= t('Author') ?></th>
+ <th class="column-10"><?= t('Version') ?></th>
+ <?php if ($is_configured): ?>
+ <th><?= t('Action') ?></th>
+ <?php endif ?>
+ </tr>
+
+ <?php foreach ($plugins as $pluginFolder => $plugin): ?>
+ <tr>
+ <td>
+ <?php if ($plugin->getPluginHomepage()): ?>
+ <a href="<?= $plugin->getPluginHomepage() ?>" target="_blank" rel="noreferrer"><?= $this->text->e($plugin->getPluginName()) ?></a>
+ <?php else: ?>
+ <?= $this->text->e($plugin->getPluginName()) ?>
+ <?php endif ?>
+ </td>
+ <td><?= $this->text->e($plugin->getPluginAuthor()) ?></td>
+ <td><?= $this->text->e($plugin->getPluginVersion()) ?></td>
+ <?php if ($is_configured): ?>
+ <td>
+ <i class="fa fa-trash-o fa-fw" aria-hidden="true"></i>
+ <?= $this->url->link(t('Uninstall'), 'PluginController', 'confirm', array('pluginId' => $pluginFolder), false, 'popover') ?>
+ </td>
+ <?php endif ?>
+ </tr>
+ <tr>
+ <td colspan="<?= $is_configured ? 4 : 3 ?>"><?= $this->text->e($plugin->getPluginDescription()) ?></td>
+ </tr>
+ <?php endforeach ?>
+ </table>
+<?php endif ?>
diff --git a/app/Template/plugin/sidebar.php b/app/Template/plugin/sidebar.php
new file mode 100644
index 00000000..e1b47632
--- /dev/null
+++ b/app/Template/plugin/sidebar.php
@@ -0,0 +1,11 @@
+<div class="sidebar">
+ <h2><?= t('Actions') ?></h2>
+ <ul>
+ <li <?= $this->app->checkMenuSelection('PluginController', 'show') ?>>
+ <?= $this->url->link(t('Installed Plugins'), 'PluginController', 'show') ?>
+ </li>
+ <li <?= $this->app->checkMenuSelection('PluginController', 'directory') ?>>
+ <?= $this->url->link(t('Plugin Directory'), 'PluginController', 'directory') ?>
+ </li>
+ </ul>
+</div>
diff --git a/app/Template/project/disable.php b/app/Template/project/disable.php
deleted file mode 100644
index ddfcdca2..00000000
--- a/app/Template/project/disable.php
+++ /dev/null
@@ -1,14 +0,0 @@
-<div class="page-header">
- <h2><?= t('Project activation') ?></h2>
-</div>
-
-<div class="confirm">
- <p class="alert alert-info">
- <?= t('Do you really want to disable this project: "%s"?', $project['name']) ?>
- </p>
-
- <div class="form-actions">
- <?= $this->url->link(t('Yes'), 'project', 'disable', array('project_id' => $project['id'], 'disable' => 'yes'), true, 'btn btn-red') ?>
- <?= t('or') ?> <?= $this->url->link(t('cancel'), 'project', 'show', array('project_id' => $project['id'])) ?>
- </div>
-</div> \ No newline at end of file
diff --git a/app/Template/project/dropdown.php b/app/Template/project/dropdown.php
index 980f9a44..90dccf21 100644
--- a/app/Template/project/dropdown.php
+++ b/app/Template/project/dropdown.php
@@ -1,40 +1,44 @@
-<li>
- <i class="fa fa-dashboard fa-fw"></i>&nbsp;
- <?= $this->url->link(t('Activity'), 'activity', 'project', array('project_id' => $project['id'])) ?>
-</li>
+<div class="dropdown">
+ <a href="#" class="dropdown-menu dashboard-table-link">#<?= $project['id'] ?></a>
+ <ul>
+ <li>
+ <i class="fa fa-th fa-fw"></i>
+ <?= $this->url->link(t('Board'), 'BoardViewController', 'show', array('project_id' => $project['id'])) ?>
+ </li>
+ <li>
+ <i class="fa fa-calendar fa-fw"></i>
+ <?= $this->url->link(t('Calendar'), 'CalendarController', 'show', array('project_id' => $project['id'])) ?>
+ </li>
+ <li>
+ <i class="fa fa-list fa-fw"></i>
+ <?= $this->url->link(t('Listing'), 'TaskListController', 'show', array('project_id' => $project['id'])) ?>
+ </li>
+ <?php if ($this->user->hasProjectAccess('TaskGanttController', 'show', $project['id'])): ?>
+ <li>
+ <i class="fa fa-sliders fa-fw"></i>
+ <?= $this->url->link(t('Gantt'), 'TaskGanttController', 'show', array('project_id' => $project['id'])) ?>
+ </li>
+ <?php endif ?>
-<?php if ($this->user->hasProjectAccess('customfilter', 'index', $project['id'])): ?>
-<li>
- <i class="fa fa-filter fa-fw"></i>&nbsp;
- <?= $this->url->link(t('Custom filters'), 'customfilter', 'index', array('project_id' => $project['id'])) ?>
-</li>
-<?php endif ?>
+ <li>
+ <i class="fa fa-dashboard fa-fw"></i>&nbsp;
+ <?= $this->url->link(t('Activity'), 'ActivityController', 'project', array('project_id' => $project['id'])) ?>
+ </li>
-<?php if ($project['is_public']): ?>
-<li>
- <i class="fa fa-share-alt fa-fw"></i>&nbsp;<?= $this->url->link(t('Public link'), 'board', 'readonly', array('token' => $project['token']), false, '', '', true) ?>
-</li>
-<?php endif ?>
+ <?php if ($this->user->hasProjectAccess('AnalyticController', 'tasks', $project['id'])): ?>
+ <li>
+ <i class="fa fa-line-chart fa-fw"></i>&nbsp;
+ <?= $this->url->link(t('Analytics'), 'AnalyticController', 'tasks', array('project_id' => $project['id'])) ?>
+ </li>
+ <?php endif ?>
-<?= $this->hook->render('template:project:dropdown', array('project' => $project)) ?>
+ <?= $this->hook->render('template:project:dropdown', array('project' => $project)) ?>
-<?php if ($this->user->hasProjectAccess('analytic', 'tasks', $project['id'])): ?>
- <li>
- <i class="fa fa-line-chart fa-fw"></i>&nbsp;
- <?= $this->url->link(t('Analytics'), 'analytic', 'tasks', array('project_id' => $project['id'])) ?>
- </li>
-<?php endif ?>
-
-<?php if ($this->user->hasProjectAccess('export', 'tasks', $project['id'])): ?>
- <li>
- <i class="fa fa-download fa-fw"></i>&nbsp;
- <?= $this->url->link(t('Exports'), 'export', 'tasks', array('project_id' => $project['id'])) ?>
- </li>
-<?php endif ?>
-
-<?php if ($this->user->hasProjectAccess('ProjectEdit', 'edit', $project['id'])): ?>
- <li>
- <i class="fa fa-cog fa-fw"></i>&nbsp;
- <?= $this->url->link(t('Settings'), 'project', 'show', array('project_id' => $project['id'])) ?>
- </li>
-<?php endif ?>
+ <?php if ($this->user->hasProjectAccess('ProjectEditController', 'edit', $project['id'])): ?>
+ <li>
+ <i class="fa fa-cog fa-fw"></i>
+ <?= $this->url->link(t('Settings'), 'ProjectViewController', 'show', array('project_id' => $project['id'])) ?>
+ </li>
+ <?php endif ?>
+ </ul>
+</div>
diff --git a/app/Template/project/duplicate.php b/app/Template/project/duplicate.php
deleted file mode 100644
index 7cfa8969..00000000
--- a/app/Template/project/duplicate.php
+++ /dev/null
@@ -1,27 +0,0 @@
-<div class="page-header">
- <h2><?= t('Clone this project') ?></h2>
-</div>
-
-<div class="confirm">
- <p class="alert alert-info">
- <?= t('Which parts of the project do you want to duplicate?') ?>
- </p>
- <form method="post" action="<?= $this->url->href('project', 'duplicate', array('project_id' => $project['id'], 'duplicate' => 'yes')) ?>" autocomplete="off">
-
- <?= $this->form->csrf() ?>
-
- <?php if ($project['is_private'] == 0): ?>
- <?= $this->form->checkbox('projectPermission', t('Permissions'), 1, true) ?>
- <?php endif ?>
-
- <?= $this->form->checkbox('category', t('Categories'), 1, true) ?>
- <?= $this->form->checkbox('action', t('Actions'), 1, true) ?>
- <?= $this->form->checkbox('swimlane', t('Swimlanes'), 1, false) ?>
- <?= $this->form->checkbox('task', t('Tasks'), 1, false) ?>
-
- <div class="form-actions">
- <button type="submit" class="btn btn-red"><?= t('Duplicate') ?></button>
- <?= t('or') ?> <?= $this->url->link(t('cancel'), 'project', 'show', array('project_id' => $project['id'])) ?>
- </div>
- </form>
-</div> \ No newline at end of file
diff --git a/app/Template/project/enable.php b/app/Template/project/enable.php
deleted file mode 100644
index c10d2f12..00000000
--- a/app/Template/project/enable.php
+++ /dev/null
@@ -1,14 +0,0 @@
-<div class="page-header">
- <h2><?= t('Project activation') ?></h2>
-</div>
-
-<div class="confirm">
- <p class="alert alert-info">
- <?= t('Do you really want to enable this project: "%s"?', $project['name']) ?>
- </p>
-
- <div class="form-actions">
- <?= $this->url->link(t('Yes'), 'project', 'enable', array('project_id' => $project['id'], 'enable' => 'yes'), true, 'btn btn-red') ?>
- <?= t('or') ?> <?= $this->url->link(t('cancel'), 'project', 'show', array('project_id' => $project['id'])) ?>
- </div>
-</div> \ No newline at end of file
diff --git a/app/Template/project/layout.php b/app/Template/project/layout.php
index fcb3e5f3..ec039202 100644
--- a/app/Template/project/layout.php
+++ b/app/Template/project/layout.php
@@ -1,5 +1,5 @@
<section id="main">
- <?= $this->projectHeader->render($project, 'Listing', 'show') ?>
+ <?= $this->projectHeader->render($project, 'TaskListController', 'show') ?>
<section class="sidebar-container">
<?= $this->render($sidebar_template, array('project' => $project)) ?>
@@ -8,4 +8,4 @@
<?= $content_for_sublayout ?>
</div>
</section>
-</section> \ No newline at end of file
+</section>
diff --git a/app/Template/project/remove.php b/app/Template/project/remove.php
deleted file mode 100644
index fa43fc78..00000000
--- a/app/Template/project/remove.php
+++ /dev/null
@@ -1,14 +0,0 @@
-<div class="page-header">
- <h2><?= t('Remove project') ?></h2>
-</div>
-
-<div class="confirm">
- <p class="alert alert-info">
- <?= t('Do you really want to remove this project: "%s"?', $project['name']) ?>
- </p>
-
- <div class="form-actions">
- <?= $this->url->link(t('Yes'), 'project', 'remove', array('project_id' => $project['id'], 'remove' => 'yes'), true, 'btn btn-red') ?>
- <?= t('or') ?> <?= $this->url->link(t('cancel'), 'project', 'show', array('project_id' => $project['id'])) ?>
- </div>
-</div> \ No newline at end of file
diff --git a/app/Template/project/share.php b/app/Template/project/share.php
deleted file mode 100644
index 6f66c97e..00000000
--- a/app/Template/project/share.php
+++ /dev/null
@@ -1,19 +0,0 @@
-<div class="page-header">
- <h2><?= t('Public access') ?></h2>
-</div>
-
-<?php if ($project['is_public']): ?>
-
- <div class="listing">
- <ul class="no-bullet">
- <li><strong><i class="fa fa-share-alt"></i> <?= $this->url->link(t('Public link'), 'board', 'readonly', array('token' => $project['token']), false, '', '', true) ?></strong></li>
- <li><strong><i class="fa fa-rss-square"></i> <?= $this->url->link(t('RSS feed'), 'feed', 'project', array('token' => $project['token']), false, '', '', true) ?></strong></li>
- <li><strong><i class="fa fa-calendar"></i> <?= $this->url->link(t('iCal feed'), 'ical', 'project', array('token' => $project['token']), false, '', '', true) ?></strong></li>
- </ul>
- </div>
-
- <?= $this->url->link(t('Disable public access'), 'project', 'share', array('project_id' => $project['id'], 'switch' => 'disable'), true, 'btn btn-red') ?>
-
-<?php else: ?>
- <?= $this->url->link(t('Enable public access'), 'project', 'share', array('project_id' => $project['id'], 'switch' => 'enable'), true, 'btn btn-blue') ?>
-<?php endif ?>
diff --git a/app/Template/project/sidebar.php b/app/Template/project/sidebar.php
index 7fb7718d..9bc0c9c4 100644
--- a/app/Template/project/sidebar.php
+++ b/app/Template/project/sidebar.php
@@ -1,62 +1,59 @@
<div class="sidebar">
<h2><?= t('Actions') ?></h2>
<ul>
- <li <?= $this->app->checkMenuSelection('project', 'show') ?>>
- <?= $this->url->link(t('Summary'), 'project', 'show', array('project_id' => $project['id'])) ?>
+ <li <?= $this->app->checkMenuSelection('ProjectViewController', 'show') ?>>
+ <?= $this->url->link(t('Summary'), 'ProjectViewController', 'show', array('project_id' => $project['id'])) ?>
</li>
- <?php if ($this->user->hasProjectAccess('customfilter', 'index', $project['id'])): ?>
- <li <?= $this->app->checkMenuSelection('customfilter') ?>>
- <?= $this->url->link(t('Custom filters'), 'customfilter', 'index', array('project_id' => $project['id'])) ?>
+ <?php if ($this->user->hasProjectAccess('CustomFilterController', 'index', $project['id'])): ?>
+ <li <?= $this->app->checkMenuSelection('CustomFilterController') ?>>
+ <?= $this->url->link(t('Custom filters'), 'CustomFilterController', 'index', array('project_id' => $project['id'])) ?>
</li>
<?php endif ?>
- <?php if ($this->user->hasProjectAccess('ProjectEdit', 'edit', $project['id'])): ?>
- <li <?= $this->app->checkMenuSelection('ProjectEdit') ?>>
- <?= $this->url->link(t('Edit project'), 'ProjectEdit', 'edit', array('project_id' => $project['id'])) ?>
+ <?php if ($this->user->hasProjectAccess('ProjectEditController', 'edit', $project['id'])): ?>
+ <li <?= $this->app->checkMenuSelection('ProjectEditController') ?>>
+ <?= $this->url->link(t('Edit project'), 'ProjectEditController', 'edit', array('project_id' => $project['id'])) ?>
</li>
- <li <?= $this->app->checkMenuSelection('project', 'share') ?>>
- <?= $this->url->link(t('Public access'), 'project', 'share', array('project_id' => $project['id'])) ?>
+ <li <?= $this->app->checkMenuSelection('ProjectViewController', 'share') ?>>
+ <?= $this->url->link(t('Public access'), 'ProjectViewController', 'share', array('project_id' => $project['id'])) ?>
</li>
- <li <?= $this->app->checkMenuSelection('project', 'notifications') ?>>
- <?= $this->url->link(t('Notifications'), 'project', 'notifications', array('project_id' => $project['id'])) ?>
+ <li <?= $this->app->checkMenuSelection('ProjectViewController', 'notifications') ?>>
+ <?= $this->url->link(t('Notifications'), 'ProjectViewController', 'notifications', array('project_id' => $project['id'])) ?>
</li>
- <li <?= $this->app->checkMenuSelection('project', 'integrations') ?>>
- <?= $this->url->link(t('Integrations'), 'project', 'integrations', array('project_id' => $project['id'])) ?>
+ <li <?= $this->app->checkMenuSelection('ProjectViewController', 'integrations') ?>>
+ <?= $this->url->link(t('Integrations'), 'ProjectViewController', 'integrations', array('project_id' => $project['id'])) ?>
</li>
- <li <?= $this->app->checkMenuSelection('column') ?>>
- <?= $this->url->link(t('Columns'), 'column', 'index', array('project_id' => $project['id'])) ?>
+ <li <?= $this->app->checkMenuSelection('ColumnController') ?>>
+ <?= $this->url->link(t('Columns'), 'ColumnController', 'index', array('project_id' => $project['id'])) ?>
</li>
- <li <?= $this->app->checkMenuSelection('swimlane') ?>>
- <?= $this->url->link(t('Swimlanes'), 'swimlane', 'index', array('project_id' => $project['id'])) ?>
+ <li <?= $this->app->checkMenuSelection('SwimlaneController') ?>>
+ <?= $this->url->link(t('Swimlanes'), 'SwimlaneController', 'index', array('project_id' => $project['id'])) ?>
</li>
- <li <?= $this->app->checkMenuSelection('category') ?>>
- <?= $this->url->link(t('Categories'), 'category', 'index', array('project_id' => $project['id'])) ?>
+ <li <?= $this->app->checkMenuSelection('CategoryController') ?>>
+ <?= $this->url->link(t('Categories'), 'CategoryController', 'index', array('project_id' => $project['id'])) ?>
</li>
<?php if ($project['is_private'] == 0): ?>
- <li <?= $this->app->checkMenuSelection('ProjectPermission') ?>>
- <?= $this->url->link(t('Permissions'), 'ProjectPermission', 'index', array('project_id' => $project['id'])) ?>
+ <li <?= $this->app->checkMenuSelection('ProjectPermissionController') ?>>
+ <?= $this->url->link(t('Permissions'), 'ProjectPermissionController', 'index', array('project_id' => $project['id'])) ?>
</li>
<?php endif ?>
- <li <?= $this->app->checkMenuSelection('action') ?>>
- <?= $this->url->link(t('Automatic actions'), 'action', 'index', array('project_id' => $project['id'])) ?>
+ <li <?= $this->app->checkMenuSelection('ActionController') ?>>
+ <?= $this->url->link(t('Automatic actions'), 'ActionController', 'index', array('project_id' => $project['id'])) ?>
</li>
- <li <?= $this->app->checkMenuSelection('project', 'duplicate') ?>>
- <?= $this->url->link(t('Duplicate'), 'project', 'duplicate', array('project_id' => $project['id'])) ?>
+ <li <?= $this->app->checkMenuSelection('ProjectViewController', 'duplicate') ?>>
+ <?= $this->url->link(t('Duplicate'), 'ProjectViewController', 'duplicate', array('project_id' => $project['id'])) ?>
</li>
<?php if ($project['is_active']): ?>
- <li <?= $this->app->checkMenuSelection('project', 'disable') ?>>
- <?= $this->url->link(t('Disable'), 'project', 'disable', array('project_id' => $project['id']), true) ?>
+ <li>
+ <?= $this->url->link(t('Disable'), 'ProjectStatusController', 'confirmDisable', array('project_id' => $project['id']), false, 'popover') ?>
<?php else: ?>
- <li <?= $this->app->checkMenuSelection('project', 'enable') ?>>
- <?= $this->url->link(t('Enable'), 'project', 'enable', array('project_id' => $project['id']), true) ?>
+ <li>
+ <?= $this->url->link(t('Enable'), 'ProjectStatusController', 'confirmEnable', array('project_id' => $project['id']), false, 'popover') ?>
<?php endif ?>
</li>
- <li <?= $this->app->checkMenuSelection('taskImport') ?>>
- <?= $this->url->link(t('Import'), 'taskImport', 'step1', array('project_id' => $project['id'])) ?>
- </li>
- <?php if ($this->user->hasProjectAccess('project', 'remove', $project['id'])): ?>
- <li <?= $this->app->checkMenuSelection('project', 'remove') ?>>
- <?= $this->url->link(t('Remove'), 'project', 'remove', array('project_id' => $project['id'])) ?>
+ <?php if ($this->user->hasProjectAccess('ProjectStatusController', 'remove', $project['id'])): ?>
+ <li>
+ <?= $this->url->link(t('Remove'), 'ProjectStatusController', 'confirmRemove', array('project_id' => $project['id']), false, 'popover') ?>
</li>
<?php endif ?>
<?php endif ?>
diff --git a/app/Template/action_project/project.php b/app/Template/project_action_duplication/show.php
index 226f3b19..2eebb262 100644
--- a/app/Template/action_project/project.php
+++ b/app/Template/project_action_duplication/show.php
@@ -4,8 +4,7 @@
<?php if (empty($projects_list)): ?>
<p class="alert"><?= t('There is no available project.') ?></p>
<?php else: ?>
- <form class="popover-form" method="post" action="<?= $this->url->href('ActionProject', 'save', array('project_id' => $project['id'])) ?>" autocomplete="off">
-
+ <form class="popover-form" method="post" action="<?= $this->url->href('ProjectActionDuplicationController', 'save', array('project_id' => $project['id'])) ?>" autocomplete="off">
<?= $this->form->csrf() ?>
<?= $this->form->label(t('Create from another project'), 'src_project_id') ?>
@@ -17,4 +16,4 @@
<?= $this->url->link(t('cancel'), 'Action', 'index', array(), false, 'close-popover') ?>
</div>
</form>
-<?php endif ?> \ No newline at end of file
+<?php endif ?>
diff --git a/app/Template/project_creation/create.php b/app/Template/project_creation/create.php
index c34173a9..01d06bab 100644
--- a/app/Template/project_creation/create.php
+++ b/app/Template/project_creation/create.php
@@ -2,7 +2,7 @@
<div class="page-header">
<h2><?= $title ?></h2>
</div>
- <form class="popover-form" id="project-creation-form" method="post" action="<?= $this->url->href('ProjectCreation', 'save') ?>" autocomplete="off">
+ <form class="popover-form" id="project-creation-form" method="post" action="<?= $this->url->href('ProjectCreationController', 'save') ?>" autocomplete="off">
<?= $this->form->csrf() ?>
<?= $this->form->hidden('is_private', $values) ?>
@@ -22,16 +22,16 @@
<?= $this->form->checkbox('projectPermission', t('Permissions'), 1, true) ?>
<?php endif ?>
- <?= $this->form->checkbox('category', t('Categories'), 1, true) ?>
- <?= $this->form->checkbox('action', t('Actions'), 1, true) ?>
- <?= $this->form->checkbox('swimlane', t('Swimlanes'), 1, true) ?>
- <?= $this->form->checkbox('task', t('Tasks'), 1, false) ?>
+ <?= $this->form->checkbox('categoryModel', t('Categories'), 1, true) ?>
+ <?= $this->form->checkbox('actionModel', t('Actions'), 1, true) ?>
+ <?= $this->form->checkbox('swimlaneModel', t('Swimlanes'), 1, true) ?>
+ <?= $this->form->checkbox('taskModel', t('Tasks'), 1, false) ?>
</div>
<div class="form-actions">
<button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
<?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'project', 'index', array(), false, 'close-popover') ?>
+ <?= $this->url->link(t('cancel'), 'ProjectListController', 'show', array(), false, 'close-popover') ?>
</div>
</form>
<?php if ($is_private): ?>
@@ -39,4 +39,4 @@
<p><?= t('There is no user management for private projects.') ?></p>
</div>
<?php endif ?>
-</section> \ No newline at end of file
+</section>
diff --git a/app/Template/project_edit/dates.php b/app/Template/project_edit/dates.php
index f77b7260..48135ddc 100644
--- a/app/Template/project_edit/dates.php
+++ b/app/Template/project_edit/dates.php
@@ -1,13 +1,13 @@
<div class="page-header">
<h2><?= t('Edit project') ?></h2>
<ul>
- <li ><?= $this->url->link(t('General'), 'ProjectEdit', 'edit', array('project_id' => $project['id']), false, 'popover-link') ?></li>
- <li class="active"><?= $this->url->link(t('Dates'), 'ProjectEdit', 'dates', array('project_id' => $project['id']), false, 'popover-link') ?></li>
- <li><?= $this->url->link(t('Description'), 'ProjectEdit', 'description', array('project_id' => $project['id']), false, 'popover-link') ?></li>
- <li><?= $this->url->link(t('Task priority'), 'ProjectEdit', 'priority', array('project_id' => $project['id']), false, 'popover-link') ?></li>
+ <li ><?= $this->url->link(t('General'), 'ProjectEditController', 'edit', array('project_id' => $project['id']), false, 'popover-link') ?></li>
+ <li class="active"><?= $this->url->link(t('Dates'), 'ProjectEditController', 'dates', array('project_id' => $project['id']), false, 'popover-link') ?></li>
+ <li><?= $this->url->link(t('Description'), 'ProjectEditController', 'description', array('project_id' => $project['id']), false, 'popover-link') ?></li>
+ <li><?= $this->url->link(t('Task priority'), 'ProjectEditController', 'priority', array('project_id' => $project['id']), false, 'popover-link') ?></li>
</ul>
</div>
-<form method="post" class="popover-form" action="<?= $this->url->href('ProjectEdit', 'update', array('project_id' => $project['id'], 'redirect' => 'dates')) ?>" autocomplete="off">
+<form method="post" class="popover-form" action="<?= $this->url->href('ProjectEditController', 'update', array('project_id' => $project['id'], 'redirect' => 'dates')) ?>" autocomplete="off">
<?= $this->form->csrf() ?>
<?= $this->form->hidden('id', $values) ?>
<?= $this->form->hidden('name', $values) ?>
diff --git a/app/Template/project_edit/description.php b/app/Template/project_edit/description.php
index e6c42caf..f7e7be46 100644
--- a/app/Template/project_edit/description.php
+++ b/app/Template/project_edit/description.php
@@ -1,13 +1,13 @@
<div class="page-header">
<h2><?= t('Edit project') ?></h2>
<ul>
- <li><?= $this->url->link(t('General'), 'ProjectEdit', 'edit', array('project_id' => $project['id']), false, 'popover-link') ?></li>
- <li><?= $this->url->link(t('Dates'), 'ProjectEdit', 'dates', array('project_id' => $project['id']), false, 'popover-link') ?></li>
- <li class="active"><?= $this->url->link(t('Description'), 'ProjectEdit', 'description', array('project_id' => $project['id']), false, 'popover-link') ?></li>
- <li><?= $this->url->link(t('Task priority'), 'ProjectEdit', 'priority', array('project_id' => $project['id']), false, 'popover-link') ?></li>
+ <li><?= $this->url->link(t('General'), 'ProjectEditController', 'edit', array('project_id' => $project['id']), false, 'popover-link') ?></li>
+ <li><?= $this->url->link(t('Dates'), 'ProjectEditController', 'dates', array('project_id' => $project['id']), false, 'popover-link') ?></li>
+ <li class="active"><?= $this->url->link(t('Description'), 'ProjectEditController', 'description', array('project_id' => $project['id']), false, 'popover-link') ?></li>
+ <li><?= $this->url->link(t('Task priority'), 'ProjectEditController', 'priority', array('project_id' => $project['id']), false, 'popover-link') ?></li>
</ul>
</div>
-<form method="post" class="popover-form" action="<?= $this->url->href('ProjectEdit', 'update', array('project_id' => $project['id'], 'redirect' => 'description')) ?>" autocomplete="off">
+<form method="post" class="popover-form" action="<?= $this->url->href('ProjectEditController', 'update', array('project_id' => $project['id'], 'redirect' => 'description')) ?>" autocomplete="off">
<?= $this->form->csrf() ?>
<?= $this->form->hidden('id', $values) ?>
<?= $this->form->hidden('name', $values) ?>
diff --git a/app/Template/project_edit/general.php b/app/Template/project_edit/general.php
index 6c3fa68d..c7421477 100644
--- a/app/Template/project_edit/general.php
+++ b/app/Template/project_edit/general.php
@@ -1,13 +1,13 @@
<div class="page-header">
<h2><?= t('Edit project') ?></h2>
<ul>
- <li class="active"><?= $this->url->link(t('General'), 'ProjectEdit', 'edit', array('project_id' => $project['id']), false, 'popover-link') ?></li>
- <li><?= $this->url->link(t('Dates'), 'ProjectEdit', 'dates', array('project_id' => $project['id']), false, 'popover-link') ?></li>
- <li><?= $this->url->link(t('Description'), 'ProjectEdit', 'description', array('project_id' => $project['id']), false, 'popover-link') ?></li>
- <li><?= $this->url->link(t('Task priority'), 'ProjectEdit', 'priority', array('project_id' => $project['id']), false, 'popover-link') ?></li>
+ <li class="active"><?= $this->url->link(t('General'), 'ProjectEditController', 'edit', array('project_id' => $project['id']), false, 'popover-link') ?></li>
+ <li><?= $this->url->link(t('Dates'), 'ProjectEditController', 'dates', array('project_id' => $project['id']), false, 'popover-link') ?></li>
+ <li><?= $this->url->link(t('Description'), 'ProjectEditController', 'description', array('project_id' => $project['id']), false, 'popover-link') ?></li>
+ <li><?= $this->url->link(t('Task priority'), 'ProjectEditController', 'priority', array('project_id' => $project['id']), false, 'popover-link') ?></li>
</ul>
</div>
-<form method="post" class="popover-form" action="<?= $this->url->href('ProjectEdit', 'update', array('project_id' => $project['id'], 'redirect' => 'edit')) ?>" autocomplete="off">
+<form method="post" class="popover-form" action="<?= $this->url->href('ProjectEditController', 'update', array('project_id' => $project['id'], 'redirect' => 'edit')) ?>" autocomplete="off">
<?= $this->form->csrf() ?>
<?= $this->form->hidden('id', $values) ?>
@@ -24,7 +24,7 @@
<?= $this->form->select('owner_id', $owners, $values, $errors) ?>
</div>
- <?php if ($this->user->hasProjectAccess('ProjectCreation', 'create', $project['id'])): ?>
+ <?php if ($this->user->hasProjectAccess('ProjectCreationController', 'create', $project['id'])): ?>
<hr>
<?= $this->form->checkbox('is_private', t('Private project'), 1, $project['is_private'] == 1) ?>
<p class="form-help"><?= t('Private projects do not have users and groups management.') ?></p>
diff --git a/app/Template/project_edit/task_priority.php b/app/Template/project_edit/task_priority.php
index 56c25753..3ef4b3cb 100644
--- a/app/Template/project_edit/task_priority.php
+++ b/app/Template/project_edit/task_priority.php
@@ -1,13 +1,13 @@
<div class="page-header">
<h2><?= t('Edit project') ?></h2>
<ul>
- <li ><?= $this->url->link(t('General'), 'ProjectEdit', 'edit', array('project_id' => $project['id']), false, 'popover-link') ?></li>
- <li><?= $this->url->link(t('Dates'), 'ProjectEdit', 'dates', array('project_id' => $project['id']), false, 'popover-link') ?></li>
- <li><?= $this->url->link(t('Description'), 'ProjectEdit', 'description', array('project_id' => $project['id']), false, 'popover-link') ?></li>
- <li class="active"><?= $this->url->link(t('Task priority'), 'ProjectEdit', 'priority', array('project_id' => $project['id']), false, 'popover-link') ?></li>
+ <li ><?= $this->url->link(t('General'), 'ProjectEditController', 'edit', array('project_id' => $project['id']), false, 'popover-link') ?></li>
+ <li><?= $this->url->link(t('Dates'), 'ProjectEditController', 'dates', array('project_id' => $project['id']), false, 'popover-link') ?></li>
+ <li><?= $this->url->link(t('Description'), 'ProjectEditController', 'description', array('project_id' => $project['id']), false, 'popover-link') ?></li>
+ <li class="active"><?= $this->url->link(t('Task priority'), 'ProjectEditController', 'priority', array('project_id' => $project['id']), false, 'popover-link') ?></li>
</ul>
</div>
-<form method="post" class="popover-form" action="<?= $this->url->href('ProjectEdit', 'update', array('project_id' => $project['id'], 'redirect' => 'priority')) ?>" autocomplete="off">
+<form method="post" class="popover-form" action="<?= $this->url->href('ProjectEditController', 'update', array('project_id' => $project['id'], 'redirect' => 'priority')) ?>" autocomplete="off">
<?= $this->form->csrf() ?>
<?= $this->form->hidden('id', $values) ?>
<?= $this->form->hidden('name', $values) ?>
diff --git a/app/Template/project_file/create.php b/app/Template/project_file/create.php
index 67315285..e262799b 100644
--- a/app/Template/project_file/create.php
+++ b/app/Template/project_file/create.php
@@ -4,7 +4,7 @@
<div id="file-done" style="display:none">
<p class="alert alert-success">
<?= t('All files have been uploaded successfully.') ?>
- <?= $this->url->link(t('View uploaded files'), 'ProjectOverview', 'show', array('project_id' => $project['id'])) ?>
+ <?= $this->url->link(t('View uploaded files'), 'ProjectOverviewController', 'show', array('project_id' => $project['id'])) ?>
</p>
</div>
@@ -18,7 +18,7 @@
<div
id="file-dropzone"
data-max-size="<?= $max_size ?>"
- data-url="<?= $this->url->href('ProjectFile', 'save', array('project_id' => $project['id'])) ?>">
+ data-url="<?= $this->url->href('ProjectFileController', 'save', array('project_id' => $project['id'])) ?>">
<div id="file-dropzone-inner">
<?= t('Drag and drop your files here') ?> <?= t('or') ?> <a href="#" id="file-browser"><?= t('choose files') ?></a>
</div>
@@ -27,7 +27,7 @@
<input type="file" name="files[]" multiple style="display:none" id="file-form-element">
<div class="form-actions">
- <input type="submit" value="<?= t('Save') ?>" class="btn btn-blue" id="file-upload-button" disabled>
+ <input type="submit" value="<?= t('Upload files') ?>" class="btn btn-blue" id="file-upload-button" disabled>
<?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'ProjectOverview', 'show', array('project_id' => $project['id']), false, 'close-popover') ?>
+ <?= $this->url->link(t('cancel'), 'ProjectOverviewController', 'show', array('project_id' => $project['id']), false, 'close-popover') ?>
</div>
diff --git a/app/Template/project_file/remove.php b/app/Template/project_file/remove.php
index ba834288..0517a9e7 100644
--- a/app/Template/project_file/remove.php
+++ b/app/Template/project_file/remove.php
@@ -8,8 +8,8 @@
</p>
<div class="form-actions">
- <?= $this->url->link(t('Yes'), 'ProjectFile', 'remove', array('project_id' => $project['id'], 'file_id' => $file['id']), true, 'btn btn-red') ?>
+ <?= $this->url->link(t('Yes'), 'ProjectFileController', 'remove', array('project_id' => $project['id'], 'file_id' => $file['id']), true, 'btn btn-red') ?>
<?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'ProjectOverview', 'show', array('project_id' => $project['id']), false, 'close-popover') ?>
+ <?= $this->url->link(t('cancel'), 'ProjectOverviewController', 'show', array('project_id' => $project['id']), false, 'close-popover') ?>
</div>
-</div> \ No newline at end of file
+</div>
diff --git a/app/Template/gantt/projects.php b/app/Template/project_gantt/show.php
index 84b260bb..af22a6ed 100644
--- a/app/Template/gantt/projects.php
+++ b/app/Template/project_gantt/show.php
@@ -2,10 +2,10 @@
<div class="page-header">
<ul>
<li>
- <i class="fa fa-folder fa-fw"></i><?= $this->url->link(t('Projects list'), 'project', 'index') ?>
+ <i class="fa fa-folder fa-fw"></i><?= $this->url->link(t('Projects list'), 'ProjectListController', 'show') ?>
</li>
- <?php if ($this->user->hasAccess('projectuser', 'managers')): ?>
- <li><i class="fa fa-user fa-fw"></i><?= $this->url->link(t('Users overview'), 'projectuser', 'managers') ?></li>
+ <?php if ($this->user->hasAccess('ProjectUserOverviewController', 'managers')): ?>
+ <li><i class="fa fa-user fa-fw"></i><?= $this->url->link(t('Users overview'), 'ProjectUserOverviewController', 'managers') ?></li>
<?php endif ?>
</ul>
</div>
@@ -16,9 +16,9 @@
<div
id="gantt-chart"
data-records='<?= json_encode($projects, JSON_HEX_APOS) ?>'
- data-save-url="<?= $this->url->href('gantt', 'saveProjectDate') ?>"
- data-label-managers="<?= t('Project managers') ?>"
- data-label-members="<?= t('Project members') ?>"
+ data-save-url="<?= $this->url->href('ProjectGanttController', 'save') ?>"
+ data-label-project-manager="<?= t('Project managers') ?>"
+ data-label-project-member="<?= t('Project members') ?>"
data-label-gantt-link="<?= t('Gantt chart for this project') ?>"
data-label-board-link="<?= t('Project board') ?>"
data-label-start-date="<?= t('Start date:') ?>"
diff --git a/app/Template/project_header/dropdown.php b/app/Template/project_header/dropdown.php
index 759a5135..79a1b389 100644
--- a/app/Template/project_header/dropdown.php
+++ b/app/Template/project_header/dropdown.php
@@ -5,11 +5,11 @@
<li>
<span class="filter-display-mode" <?= $this->board->isCollapsed($project['id']) ? '' : 'style="display: none;"' ?>>
<i class="fa fa-expand fa-fw"></i>
- <?= $this->url->link(t('Expand tasks'), 'board', 'expand', array('project_id' => $project['id']), false, 'board-display-mode', t('Keyboard shortcut: "%s"', 's')) ?>
+ <?= $this->url->link(t('Expand tasks'), 'BoardAjaxController', 'expand', array('project_id' => $project['id']), false, 'board-display-mode', t('Keyboard shortcut: "%s"', 's')) ?>
</span>
<span class="filter-display-mode" <?= $this->board->isCollapsed($project['id']) ? 'style="display: none;"' : '' ?>>
<i class="fa fa-compress fa-fw"></i>
- <?= $this->url->link(t('Collapse tasks'), 'board', 'collapse', array('project_id' => $project['id']), false, 'board-display-mode', t('Keyboard shortcut: "%s"', 's')) ?>
+ <?= $this->url->link(t('Collapse tasks'), 'BoardAjaxController', 'collapse', array('project_id' => $project['id']), false, 'board-display-mode', t('Keyboard shortcut: "%s"', 's')) ?>
</span>
</li>
<li>
@@ -29,6 +29,66 @@
</span>
</li>
<?php endif ?>
- <?= $this->render('project/dropdown', array('project' => $project)) ?>
+
+ <?php if ($this->user->hasProjectAccess('TaskCreationController', 'show', $project['id'])): ?>
+ <li>
+ <i class="fa fa-plus fa-fw"></i>
+ <?= $this->url->link(t('Add a new task'), 'TaskCreationController', 'show', array('project_id' => $project['id']), false, 'popover') ?>
+ </li>
+ <?php endif ?>
+
+ <li>
+ <i class="fa fa-dashboard fa-fw"></i>
+ <?= $this->url->link(t('Activity'), 'ActivityController', 'project', array('project_id' => $project['id'])) ?>
+ </li>
+
+ <?php if ($this->user->hasProjectAccess('CustomFilterController', 'index', $project['id'])): ?>
+ <li>
+ <i class="fa fa-filter fa-fw"></i>
+ <?= $this->url->link(t('Custom filters'), 'CustomFilterController', 'index', array('project_id' => $project['id'])) ?>
+ </li>
+ <?php endif ?>
+
+ <?php if ($project['is_public']): ?>
+ <li>
+ <i class="fa fa-share-alt fa-fw"></i>
+ <?= $this->url->link(t('Public link'), 'BoardViewController', 'readonly', array('token' => $project['token']), false, '', '', true) ?>
+ </li>
+ <?php endif ?>
+
+ <?= $this->hook->render('template:project:dropdown', array('project' => $project)) ?>
+
+ <?php if ($this->user->hasProjectAccess('AnalyticController', 'tasks', $project['id'])): ?>
+ <li>
+ <i class="fa fa-line-chart fa-fw"></i>
+ <?= $this->url->link(t('Analytics'), 'AnalyticController', 'tasks', array('project_id' => $project['id'])) ?>
+ </li>
+ <?php endif ?>
+
+ <?php if ($this->user->hasProjectAccess('ExportController', 'tasks', $project['id'])): ?>
+ <li>
+ <i class="fa fa-upload fa-fw"></i>
+ <?= $this->url->link(t('Exports'), 'ExportController', 'tasks', array('project_id' => $project['id'])) ?>
+ </li>
+ <?php endif ?>
+
+ <?php if ($this->user->hasProjectAccess('TaskImportController', 'tasks', $project['id'])): ?>
+ <li>
+ <i class="fa fa-download fa-fw"></i>
+ <?= $this->url->link(t('Imports'), 'TaskImportController', 'show', array('project_id' => $project['id'])) ?>
+ </li>
+ <?php endif ?>
+
+ <?php if ($this->user->hasProjectAccess('ProjectEditController', 'edit', $project['id'])): ?>
+ <li>
+ <i class="fa fa-cog fa-fw"></i>
+ <?= $this->url->link(t('Settings'), 'ProjectViewController', 'show', array('project_id' => $project['id'])) ?>
+ </li>
+ <?php endif ?>
+
+ <li>
+ <i class="fa fa-folder fa-fw" aria-hidden="true"></i>
+ <?= $this->url->link(t('Manage projects'), 'ProjectListController', 'show') ?>
+ </li>
</ul>
-</div> \ No newline at end of file
+</div>
diff --git a/app/Template/project_header/views.php b/app/Template/project_header/views.php
index 353e4b62..3a41c91b 100644
--- a/app/Template/project_header/views.php
+++ b/app/Template/project_header/views.php
@@ -1,24 +1,24 @@
<ul class="views">
- <li <?= $this->app->getRouterController() === 'ProjectOverview' ? 'class="active"' : '' ?>>
+ <li <?= $this->app->checkMenuSelection('ProjectOverviewController') ?>>
<i class="fa fa-eye fa-fw"></i>
- <?= $this->url->link(t('Overview'), 'ProjectOverview', 'show', array('project_id' => $project['id'], 'search' => $filters['search']), false, 'view-overview', t('Keyboard shortcut: "%s"', 'v o')) ?>
+ <?= $this->url->link(t('Overview'), 'ProjectOverviewController', 'show', array('project_id' => $project['id'], 'search' => $filters['search']), false, 'view-overview', t('Keyboard shortcut: "%s"', 'v o')) ?>
</li>
- <li <?= $this->app->getRouterController() === 'Board' ? 'class="active"' : '' ?>>
+ <li <?= $this->app->checkMenuSelection('BoardViewController') ?>>
<i class="fa fa-th fa-fw"></i>
- <?= $this->url->link(t('Board'), 'board', 'show', array('project_id' => $project['id'], 'search' => $filters['search']), false, 'view-board', t('Keyboard shortcut: "%s"', 'v b')) ?>
+ <?= $this->url->link(t('Board'), 'BoardViewController', 'show', array('project_id' => $project['id'], 'search' => $filters['search']), false, 'view-board', t('Keyboard shortcut: "%s"', 'v b')) ?>
</li>
- <li <?= $this->app->getRouterController() === 'Calendar' ? 'class="active"' : '' ?>>
+ <li <?= $this->app->checkMenuSelection('Calendar') ?>>
<i class="fa fa-calendar fa-fw"></i>
- <?= $this->url->link(t('Calendar'), 'calendar', 'show', array('project_id' => $project['id'], 'search' => $filters['search']), false, 'view-calendar', t('Keyboard shortcut: "%s"', 'v c')) ?>
+ <?= $this->url->link(t('Calendar'), 'CalendarController', 'show', array('project_id' => $project['id'], 'search' => $filters['search']), false, 'view-calendar', t('Keyboard shortcut: "%s"', 'v c')) ?>
</li>
- <li <?= $this->app->getRouterController() === 'Listing' ? 'class="active"' : '' ?>>
+ <li <?= $this->app->checkMenuSelection('TaskListController') ?>>
<i class="fa fa-list fa-fw"></i>
- <?= $this->url->link(t('List'), 'listing', 'show', array('project_id' => $project['id'], 'search' => $filters['search']), false, 'view-listing', t('Keyboard shortcut: "%s"', 'v l')) ?>
+ <?= $this->url->link(t('List'), 'TaskListController', 'show', array('project_id' => $project['id'], 'search' => $filters['search']), false, 'view-listing', t('Keyboard shortcut: "%s"', 'v l')) ?>
</li>
- <?php if ($this->user->hasProjectAccess('gantt', 'project', $project['id'])): ?>
- <li <?= $this->app->getRouterController() === 'Gantt' ? 'class="active"' : '' ?>>
+ <?php if ($this->user->hasProjectAccess('TaskGanttController', 'show', $project['id'])): ?>
+ <li <?= $this->app->checkMenuSelection('TaskGanttController') ?>>
<i class="fa fa-sliders fa-fw"></i>
- <?= $this->url->link(t('Gantt'), 'gantt', 'project', array('project_id' => $project['id'], 'search' => $filters['search']), false, 'view-gantt', t('Keyboard shortcut: "%s"', 'v g')) ?>
+ <?= $this->url->link(t('Gantt'), 'TaskGanttController', 'show', array('project_id' => $project['id'], 'search' => $filters['search']), false, 'view-gantt', t('Keyboard shortcut: "%s"', 'v g')) ?>
</li>
<?php endif ?>
-</ul> \ No newline at end of file
+</ul>
diff --git a/app/Template/project/index.php b/app/Template/project_list/show.php
index 10d4aaa2..8b9f1396 100644
--- a/app/Template/project/index.php
+++ b/app/Template/project_list/show.php
@@ -1,11 +1,11 @@
<section id="main">
<div class="page-header">
<ul>
- <?php if ($this->user->hasAccess('projectuser', 'managers')): ?>
- <li><i class="fa fa-user fa-fw"></i><?= $this->url->link(t('Users overview'), 'projectuser', 'managers') ?></li>
+ <?php if ($this->user->hasAccess('ProjectUserOverviewController', 'managers')): ?>
+ <li><i class="fa fa-user fa-fw"></i><?= $this->url->link(t('Users overview'), 'ProjectUserOverviewController', 'managers') ?></li>
<?php endif ?>
- <?php if ($this->user->hasAccess('gantt', 'projects')): ?>
- <li><i class="fa fa-sliders fa-fw"></i><?= $this->url->link(t('Projects Gantt chart'), 'gantt', 'projects') ?></li>
+ <?php if ($this->user->hasAccess('ProjectGanttController', 'show')): ?>
+ <li><i class="fa fa-sliders fa-fw"></i><?= $this->url->link(t('Projects Gantt chart'), 'ProjectGanttController', 'show') ?></li>
<?php endif ?>
</ul>
</div>
@@ -20,7 +20,7 @@
<th class="column-8"><?= $paginator->order(t('Start date'), 'start_date') ?></th>
<th class="column-8"><?= $paginator->order(t('End date'), 'end_date') ?></th>
<th class="column-15"><?= $paginator->order(t('Owner'), 'owner_id') ?></th>
- <?php if ($this->user->hasAccess('projectuser', 'managers')): ?>
+ <?php if ($this->user->hasAccess('ProjectUserOverviewController', 'managers')): ?>
<th class="column-10"><?= t('Users') ?></th>
<?php endif ?>
<th><?= t('Columns') ?></th>
@@ -28,7 +28,7 @@
<?php foreach ($paginator->getCollection() as $project): ?>
<tr>
<td>
- <?= $this->url->link('#'.$project['id'], 'board', 'show', array('project_id' => $project['id']), false, 'dashboard-table-link') ?>
+ <?= $this->render('project/dropdown', array('project' => $project)) ?>
</td>
<td>
<?php if ($project['is_active']): ?>
@@ -38,8 +38,7 @@
<?php endif ?>
</td>
<td>
- <?= $this->url->link('<i class="fa fa-th"></i>', 'board', 'show', array('project_id' => $project['id']), false, 'dashboard-table-link', t('Board')) ?>
- <?= $this->url->link('<i class="fa fa-sliders fa-fw"></i>', 'gantt', 'project', array('project_id' => $project['id']), false, 'dashboard-table-link', t('Gantt chart')) ?>
+ <?= $this->url->link($this->text->e($project['name']), 'BoardViewController', 'show', array('project_id' => $project['id'])) ?>
<?php if ($project['is_public']): ?>
<i class="fa fa-share-alt fa-fw" title="<?= t('Shared project') ?>"></i>
@@ -49,12 +48,10 @@
<?php endif ?>
<?php if (! empty($project['description'])): ?>
- <span class="tooltip" title='<?= $this->text->e($this->text->markdown($project['description'])) ?>'>
+ <span class="tooltip" title="<?= $this->text->markdownAttribute($project['description']) ?>">
<i class="fa fa-info-circle"></i>
</span>
<?php endif ?>
-
- <?= $this->url->link($this->text->e($project['name']), 'project', 'show', array('project_id' => $project['id'])) ?>
</td>
<td>
<?= $this->dt->date($project['start_date']) ?>
@@ -67,10 +64,10 @@
<?= $this->text->e($project['owner_name'] ?: $project['owner_username']) ?>
<?php endif ?>
</td>
- <?php if ($this->user->hasAccess('projectuser', 'managers')): ?>
+ <?php if ($this->user->hasAccess('ProjectUserOverviewController', 'managers')): ?>
<td>
<i class="fa fa-users fa-fw"></i>
- <a href="#" class="tooltip" title="<?= t('Members') ?>" data-href="<?= $this->url->href('Projectuser', 'users', array('project_id' => $project['id'])) ?>"><?= t('Members') ?></a>
+ <span class="tooltip" title="<?= t('Members') ?>" data-href="<?= $this->url->href('ProjectUserOverviewController', 'users', array('project_id' => $project['id'])) ?>"><?= t('Members') ?></span>
</td>
<?php endif ?>
<td class="dashboard-project-stats">
diff --git a/app/Template/project_overview/attachments.php b/app/Template/project_overview/attachments.php
index eaabfd5f..ab8cf2ad 100644
--- a/app/Template/project_overview/attachments.php
+++ b/app/Template/project_overview/attachments.php
@@ -3,9 +3,9 @@
<h3><a href="#" class="fa accordion-toggle"></a> <?= t('Attachments') ?></h3>
</div>
<div class="accordion-content">
- <?php if ($this->user->hasProjectAccess('ProjectFile', 'create', $project['id'])): ?>
+ <?php if ($this->user->hasProjectAccess('ProjectFileController', 'create', $project['id'])): ?>
<div class="buttons-header">
- <?= $this->url->button('fa-plus', t('Upload a file'), 'ProjectFile', 'create', array('project_id' => $project['id']), 'popover') ?>
+ <?= $this->url->button('fa-plus', t('Upload a file'), 'ProjectFileController', 'create', array('project_id' => $project['id']), 'popover') ?>
</div>
<?php endif ?>
diff --git a/app/Template/project_overview/description.php b/app/Template/project_overview/description.php
index 72ccf06a..0c2027ed 100644
--- a/app/Template/project_overview/description.php
+++ b/app/Template/project_overview/description.php
@@ -3,9 +3,9 @@
<h3><a href="#" class="fa accordion-toggle"></a> <?= t('Description') ?></h3>
</div>
<div class="accordion-content">
- <?php if ($this->user->hasProjectAccess('ProjectEdit', 'description', $project['id'])): ?>
+ <?php if ($this->user->hasProjectAccess('ProjectEditController', 'description', $project['id'])): ?>
<div class="buttons-header">
- <?= $this->url->button('fa-edit', t('Edit description'), 'ProjectEdit', 'description', array('project_id' => $project['id']), 'popover') ?>
+ <?= $this->url->button('fa-edit', t('Edit description'), 'ProjectEditController', 'description', array('project_id' => $project['id']), 'popover') ?>
</div>
<?php endif ?>
<article class="markdown">
diff --git a/app/Template/project_overview/files.php b/app/Template/project_overview/files.php
index c570b771..fa870938 100644
--- a/app/Template/project_overview/files.php
+++ b/app/Template/project_overview/files.php
@@ -16,17 +16,17 @@
<?php if ($this->file->getPreviewType($file['name']) !== null): ?>
<li>
<i class="fa fa-eye fa-fw"></i>
- <?= $this->url->link(t('View file'), 'FileViewer', 'show', array('project_id' => $project['id'], 'file_id' => $file['id']), false, 'popover') ?>
+ <?= $this->url->link(t('View file'), 'FileViewerController', 'show', array('project_id' => $project['id'], 'file_id' => $file['id']), false, 'popover') ?>
</li>
<?php endif ?>
<li>
<i class="fa fa-download fa-fw"></i>
- <?= $this->url->link(t('Download'), 'FileViewer', 'download', array('project_id' => $project['id'], 'file_id' => $file['id'])) ?>
+ <?= $this->url->link(t('Download'), 'FileViewerController', 'download', array('project_id' => $project['id'], 'file_id' => $file['id'])) ?>
</li>
- <?php if ($this->user->hasProjectAccess('ProjectFile', 'remove', $project['id'])): ?>
+ <?php if ($this->user->hasProjectAccess('ProjectFileController', 'remove', $project['id'])): ?>
<li>
<i class="fa fa-trash fa-fw"></i>
- <?= $this->url->link(t('Remove'), 'ProjectFile', 'confirm', array('project_id' => $project['id'], 'file_id' => $file['id']), false, 'popover') ?>
+ <?= $this->url->link(t('Remove'), 'ProjectFileController', 'confirm', array('project_id' => $project['id'], 'file_id' => $file['id']), false, 'popover') ?>
</li>
<?php endif ?>
</ul>
diff --git a/app/Template/project_overview/images.php b/app/Template/project_overview/images.php
index f6937e12..7f38e2b1 100644
--- a/app/Template/project_overview/images.php
+++ b/app/Template/project_overview/images.php
@@ -2,7 +2,7 @@
<div class="file-thumbnails">
<?php foreach ($images as $file): ?>
<div class="file-thumbnail">
- <a href="<?= $this->url->href('FileViewer', 'show', array('project_id' => $project['id'], 'file_id' => $file['id'])) ?>" class="popover"><img src="<?= $this->url->href('FileViewer', 'thumbnail', array('file_id' => $file['id'], 'project_id' => $project['id'])) ?>" title="<?= $this->text->e($file['name']) ?>" alt="<?= $this->text->e($file['name']) ?>"></a>
+ <a href="<?= $this->url->href('FileViewerController', 'show', array('project_id' => $project['id'], 'file_id' => $file['id'])) ?>" class="popover"><img src="<?= $this->url->href('FileViewerController', 'thumbnail', array('file_id' => $file['id'], 'project_id' => $project['id'])) ?>" title="<?= $this->text->e($file['name']) ?>" alt="<?= $this->text->e($file['name']) ?>"></a>
<div class="file-thumbnail-content">
<div class="file-thumbnail-title">
<div class="dropdown">
@@ -10,12 +10,12 @@
<ul>
<li>
<i class="fa fa-download fa-fw"></i>
- <?= $this->url->link(t('Download'), 'FileViewer', 'download', array('project_id' => $project['id'], 'file_id' => $file['id'])) ?>
+ <?= $this->url->link(t('Download'), 'FileViewerController', 'download', array('project_id' => $project['id'], 'file_id' => $file['id'])) ?>
</li>
- <?php if ($this->user->hasProjectAccess('ProjectFile', 'remove', $project['id'])): ?>
+ <?php if ($this->user->hasProjectAccess('ProjectFileController', 'remove', $project['id'])): ?>
<li>
<i class="fa fa-trash fa-fw"></i>
- <?= $this->url->link(t('Remove'), 'ProjectFile', 'confirm', array('project_id' => $project['id'], 'file_id' => $file['id']), false, 'popover') ?>
+ <?= $this->url->link(t('Remove'), 'ProjectFileController', 'confirm', array('project_id' => $project['id'], 'file_id' => $file['id']), false, 'popover') ?>
</li>
<?php endif ?>
</ul>
diff --git a/app/Template/project_overview/information.php b/app/Template/project_overview/information.php
index 2032ed28..fdf0f753 100644
--- a/app/Template/project_overview/information.php
+++ b/app/Template/project_overview/information.php
@@ -29,9 +29,9 @@
<?php endif ?>
<?php if ($project['is_public']): ?>
- <li><i class="fa fa-share-alt"></i> <?= $this->url->link(t('Public link'), 'board', 'readonly', array('token' => $project['token']), false, '', '', true) ?></li>
- <li><i class="fa fa-rss-square"></i> <?= $this->url->link(t('RSS feed'), 'feed', 'project', array('token' => $project['token']), false, '', '', true) ?></li>
- <li><i class="fa fa-calendar"></i> <?= $this->url->link(t('iCal feed'), 'ical', 'project', array('token' => $project['token'])) ?></li>
+ <li><i class="fa fa-share-alt"></i> <?= $this->url->link(t('Public link'), 'BoardViewController', 'readonly', array('token' => $project['token']), false, '', '', true) ?></li>
+ <li><i class="fa fa-rss-square"></i> <?= $this->url->link(t('RSS feed'), 'FeedController', 'project', array('token' => $project['token']), false, '', '', true) ?></li>
+ <li><i class="fa fa-calendar"></i> <?= $this->url->link(t('iCal feed'), 'ICalendarController', 'project', array('token' => $project['token'])) ?></li>
<?php endif ?>
</ul>
</div>
diff --git a/app/Template/project_overview/show.php b/app/Template/project_overview/show.php
index 6fe815b3..6b2bc2cf 100644
--- a/app/Template/project_overview/show.php
+++ b/app/Template/project_overview/show.php
@@ -1,5 +1,5 @@
<section id="main">
- <?= $this->projectHeader->render($project, 'ProjectOverview', 'show') ?>
+ <?= $this->projectHeader->render($project, 'ProjectOverviewController', 'show') ?>
<?= $this->render('project_overview/columns', array('project' => $project)) ?>
<?= $this->render('project_overview/description', array('project' => $project)) ?>
<?= $this->render('project_overview/attachments', array('project' => $project, 'images' => $images, 'files' => $files)) ?>
diff --git a/app/Template/project_permission/index.php b/app/Template/project_permission/index.php
index a7d666a6..d850ec50 100644
--- a/app/Template/project_permission/index.php
+++ b/app/Template/project_permission/index.php
@@ -26,12 +26,12 @@
$roles,
array('role-'.$user['id'] => $user['role']),
array(),
- array('data-url="'.$this->url->href('ProjectPermission', 'changeUserRole', array('project_id' => $project['id'])).'"', 'data-id="'.$user['id'].'"'),
+ array('data-url="'.$this->url->href('ProjectPermissionController', 'changeUserRole', array('project_id' => $project['id'])).'"', 'data-id="'.$user['id'].'"'),
'project-change-role'
) ?>
</td>
<td>
- <?= $this->url->link(t('Remove'), 'ProjectPermission', 'removeUser', array('project_id' => $project['id'], 'user_id' => $user['id']), true) ?>
+ <?= $this->url->link(t('Remove'), 'ProjectPermissionController', 'removeUser', array('project_id' => $project['id'], 'user_id' => $user['id']), true) ?>
</td>
</tr>
<?php endforeach ?>
@@ -40,7 +40,7 @@
<?php if ($project['is_private'] == 0): ?>
<div class="listing">
- <form method="post" action="<?= $this->url->href('ProjectPermission', 'addUser', array('project_id' => $project['id'])) ?>" autocomplete="off" class="form-inline">
+ <form method="post" action="<?= $this->url->href('ProjectPermissionController', 'addUser', array('project_id' => $project['id'])) ?>" autocomplete="off" class="form-inline">
<?= $this->form->csrf() ?>
<?= $this->form->hidden('project_id', array('project_id' => $project['id'])) ?>
<?= $this->form->hidden('user_id', $values) ?>
@@ -51,7 +51,7 @@
'placeholder="'.t('Enter user name...').'"',
'title="'.t('Enter user name...').'"',
'data-dst-field="user_id"',
- 'data-search-url="'.$this->url->href('UserHelper', 'autocomplete').'"',
+ 'data-search-url="'.$this->url->href('UserAjaxController', 'autocomplete').'"',
),
'autocomplete') ?>
@@ -86,12 +86,12 @@
$roles,
array('role-'.$group['id'] => $group['role']),
array(),
- array('data-url="'.$this->url->href('ProjectPermission', 'changeGroupRole', array('project_id' => $project['id'])).'"', 'data-id="'.$group['id'].'"'),
+ array('data-url="'.$this->url->href('ProjectPermissionController', 'changeGroupRole', array('project_id' => $project['id'])).'"', 'data-id="'.$group['id'].'"'),
'project-change-role'
) ?>
</td>
<td>
- <?= $this->url->link(t('Remove'), 'ProjectPermission', 'removeGroup', array('project_id' => $project['id'], 'group_id' => $group['id']), true) ?>
+ <?= $this->url->link(t('Remove'), 'ProjectPermissionController', 'removeGroup', array('project_id' => $project['id'], 'group_id' => $group['id']), true) ?>
</td>
</tr>
<?php endforeach ?>
@@ -100,7 +100,7 @@
<?php if ($project['is_private'] == 0): ?>
<div class="listing">
- <form method="post" action="<?= $this->url->href('ProjectPermission', 'addGroup', array('project_id' => $project['id'])) ?>" autocomplete="off" class="form-inline">
+ <form method="post" action="<?= $this->url->href('ProjectPermissionController', 'addGroup', array('project_id' => $project['id'])) ?>" autocomplete="off" class="form-inline">
<?= $this->form->csrf() ?>
<?= $this->form->hidden('project_id', array('project_id' => $project['id'])) ?>
<?= $this->form->hidden('group_id', $values) ?>
@@ -113,7 +113,7 @@
'title="'.t('Enter group name...').'"',
'data-dst-field="group_id"',
'data-dst-extra-field="external_id"',
- 'data-search-url="'.$this->url->href('GroupHelper', 'autocomplete').'"',
+ 'data-search-url="'.$this->url->href('GroupAjaxController', 'autocomplete').'"',
),
'autocomplete') ?>
@@ -128,7 +128,7 @@
<?php if ($project['is_private'] == 0): ?>
<hr/>
-<form method="post" action="<?= $this->url->href('ProjectPermission', 'allowEverybody', array('project_id' => $project['id'])) ?>">
+<form method="post" action="<?= $this->url->href('ProjectPermissionController', 'allowEverybody', array('project_id' => $project['id'])) ?>">
<?= $this->form->csrf() ?>
<?= $this->form->hidden('id', array('id' => $project['id'])) ?>
diff --git a/app/Template/project_status/disable.php b/app/Template/project_status/disable.php
new file mode 100644
index 00000000..d8145d3c
--- /dev/null
+++ b/app/Template/project_status/disable.php
@@ -0,0 +1,14 @@
+<div class="page-header">
+ <h2><?= t('Project activation') ?></h2>
+</div>
+
+<div class="confirm">
+ <p class="alert alert-info">
+ <?= t('Do you really want to disable this project: "%s"?', $project['name']) ?>
+ </p>
+
+ <div class="form-actions">
+ <?= $this->url->link(t('Yes'), 'ProjectStatusController', 'disable', array('project_id' => $project['id']), true, 'btn btn-red') ?>
+ <?= t('or') ?> <?= $this->url->link(t('cancel'), 'ProjectViewController', 'show', array('project_id' => $project['id']), false, 'close-popover') ?>
+ </div>
+</div>
diff --git a/app/Template/project_status/enable.php b/app/Template/project_status/enable.php
new file mode 100644
index 00000000..1f76d093
--- /dev/null
+++ b/app/Template/project_status/enable.php
@@ -0,0 +1,14 @@
+<div class="page-header">
+ <h2><?= t('Project activation') ?></h2>
+</div>
+
+<div class="confirm">
+ <p class="alert alert-info">
+ <?= t('Do you really want to enable this project: "%s"?', $project['name']) ?>
+ </p>
+
+ <div class="form-actions">
+ <?= $this->url->link(t('Yes'), 'ProjectStatusController', 'enable', array('project_id' => $project['id']), true, 'btn btn-red') ?>
+ <?= t('or') ?> <?= $this->url->link(t('cancel'), 'ProjectViewController', 'show', array('project_id' => $project['id']), false, 'close-popover') ?>
+ </div>
+</div>
diff --git a/app/Template/project_status/remove.php b/app/Template/project_status/remove.php
new file mode 100644
index 00000000..8959ef75
--- /dev/null
+++ b/app/Template/project_status/remove.php
@@ -0,0 +1,14 @@
+<div class="page-header">
+ <h2><?= t('Remove project') ?></h2>
+</div>
+
+<div class="confirm">
+ <p class="alert alert-info">
+ <?= t('Do you really want to remove this project: "%s"?', $project['name']) ?>
+ </p>
+
+ <div class="form-actions">
+ <?= $this->url->link(t('Yes'), 'ProjectStatusController', 'remove', array('project_id' => $project['id']), true, 'btn btn-red') ?>
+ <?= t('or') ?> <?= $this->url->link(t('cancel'), 'ProjectViewController', 'show', array('project_id' => $project['id']), false, 'close-popover') ?>
+ </div>
+</div>
diff --git a/app/Template/project_user/sidebar.php b/app/Template/project_user/sidebar.php
deleted file mode 100644
index ff113ebb..00000000
--- a/app/Template/project_user/sidebar.php
+++ /dev/null
@@ -1,30 +0,0 @@
-<div class="sidebar">
- <h2><?= t('Actions') ?></h2>
-
- <?= $this->form->select(
- 'user_id',
- $users,
- $filter,
- array(),
- array('data-redirect-url="'.$this->url->href('projectuser', $this->app->getRouterAction(), array('user_id' => 'USER_ID')).'"', 'data-redirect-regex="USER_ID"'),
- 'chosen-select select-auto-redirect'
- ) ?>
-
- <br><br>
- <ul>
- <li <?= $this->app->checkMenuSelection('projectuser', 'managers') ?>>
- <?= $this->url->link(t('Project managers'), 'projectuser', 'managers', $filter) ?>
- </li>
- <li <?= $this->app->checkMenuSelection('projectuser', 'members') ?>>
- <?= $this->url->link(t('Project members'), 'projectuser', 'members', $filter) ?>
- </li>
- <li <?= $this->app->checkMenuSelection('projectuser', 'opens') ?>>
- <?= $this->url->link(t('Open tasks'), 'projectuser', 'opens', $filter) ?>
- </li>
- <li <?= $this->app->checkMenuSelection('projectuser', 'closed') ?>>
- <?= $this->url->link(t('Closed tasks'), 'projectuser', 'closed', $filter) ?>
- </li>
-
- <?= $this->hook->render('template:project-user:sidebar') ?>
- </ul>
-</div> \ No newline at end of file
diff --git a/app/Template/project_user/layout.php b/app/Template/project_user_overview/layout.php
index 1103e9bc..19b83436 100644
--- a/app/Template/project_user/layout.php
+++ b/app/Template/project_user_overview/layout.php
@@ -3,12 +3,12 @@
<ul>
<li>
<i class="fa fa-folder fa-fw"></i>
- <?= $this->url->link(t('Projects list'), 'project', 'index') ?>
+ <?= $this->url->link(t('Projects list'), 'ProjectListController', 'show') ?>
</li>
- <?php if ($this->user->hasAccess('gantt', 'projects')): ?>
+ <?php if ($this->user->hasAccess('ProjectGanttController', 'show')): ?>
<li>
<i class="fa fa-sliders fa-fw"></i>
- <?= $this->url->link(t('Projects Gantt chart'), 'gantt', 'projects') ?>
+ <?= $this->url->link(t('Projects Gantt chart'), 'ProjectGanttController', 'show') ?>
</li>
<?php endif ?>
</ul>
@@ -24,4 +24,4 @@
<?= $content_for_sublayout ?>
</div>
</section>
-</section> \ No newline at end of file
+</section>
diff --git a/app/Template/project_user/roles.php b/app/Template/project_user_overview/roles.php
index 17fb709b..87c8df85 100644
--- a/app/Template/project_user/roles.php
+++ b/app/Template/project_user_overview/roles.php
@@ -13,9 +13,9 @@
<?= $this->text->e($this->user->getFullname($project)) ?>
</td>
<td>
- <?= $this->url->link('<i class="fa fa-th"></i>', 'board', 'show', array('project_id' => $project['id']), false, 'dashboard-table-link', t('Board')) ?>
- <?= $this->url->link('<i class="fa fa-sliders fa-fw"></i>', 'gantt', 'project', array('project_id' => $project['id']), false, 'dashboard-table-link', t('Gantt chart')) ?>
- <?= $this->url->link('<i class="fa fa-cog fa-fw"></i>', 'project', 'show', array('project_id' => $project['id']), false, 'dashboard-table-link', t('Project settings')) ?>
+ <?= $this->url->link('<i class="fa fa-th"></i>', 'BoardViewController', 'show', array('project_id' => $project['id']), false, 'dashboard-table-link', t('Board')) ?>
+ <?= $this->url->link('<i class="fa fa-sliders fa-fw"></i>', 'TaskGanttController', 'show', array('project_id' => $project['id']), false, 'dashboard-table-link', t('Gantt chart')) ?>
+ <?= $this->url->link('<i class="fa fa-cog fa-fw"></i>', 'ProjectViewController', 'show', array('project_id' => $project['id']), false, 'dashboard-table-link', t('Project settings')) ?>
<?= $this->text->e($project['project_name']) ?>
</td>
@@ -30,4 +30,4 @@
</table>
<?= $paginator ?>
-<?php endif ?> \ No newline at end of file
+<?php endif ?>
diff --git a/app/Template/project_user_overview/sidebar.php b/app/Template/project_user_overview/sidebar.php
new file mode 100644
index 00000000..9a87d4eb
--- /dev/null
+++ b/app/Template/project_user_overview/sidebar.php
@@ -0,0 +1,30 @@
+<div class="sidebar">
+ <h2><?= t('Actions') ?></h2>
+
+ <?= $this->form->select(
+ 'user_id',
+ $users,
+ $filter,
+ array(),
+ array('data-redirect-url="'.$this->url->href('ProjectUserOverviewController', $this->app->getRouterAction(), array('user_id' => 'USER_ID')).'"', 'data-redirect-regex="USER_ID"'),
+ 'chosen-select select-auto-redirect'
+ ) ?>
+
+ <br><br>
+ <ul>
+ <li <?= $this->app->checkMenuSelection('ProjectUserOverviewController', 'managers') ?>>
+ <?= $this->url->link(t('Project managers'), 'ProjectUserOverviewController', 'managers', $filter) ?>
+ </li>
+ <li <?= $this->app->checkMenuSelection('ProjectUserOverviewController', 'members') ?>>
+ <?= $this->url->link(t('Project members'), 'ProjectUserOverviewController', 'members', $filter) ?>
+ </li>
+ <li <?= $this->app->checkMenuSelection('ProjectUserOverviewController', 'opens') ?>>
+ <?= $this->url->link(t('Open tasks'), 'ProjectUserOverviewController', 'opens', $filter) ?>
+ </li>
+ <li <?= $this->app->checkMenuSelection('ProjectUserOverviewController', 'closed') ?>>
+ <?= $this->url->link(t('Closed tasks'), 'ProjectUserOverviewController', 'closed', $filter) ?>
+ </li>
+
+ <?= $this->hook->render('template:project-user:sidebar') ?>
+ </ul>
+</div>
diff --git a/app/Template/project_user/tasks.php b/app/Template/project_user_overview/tasks.php
index 108d3b33..af0a3d97 100644
--- a/app/Template/project_user/tasks.php
+++ b/app/Template/project_user_overview/tasks.php
@@ -14,16 +14,16 @@
<?php foreach ($paginator->getCollection() as $task): ?>
<tr>
<td class="task-table color-<?= $task['color_id'] ?>">
- <?= $this->url->link('#'.$this->text->e($task['id']), 'task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, '', t('View this task')) ?>
+ <?= $this->url->link('#'.$this->text->e($task['id']), 'TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, '', t('View this task')) ?>
</td>
<td>
- <?= $this->url->link($this->text->e($task['project_name']), 'board', 'show', array('project_id' => $task['project_id'])) ?>
+ <?= $this->url->link($this->text->e($task['project_name']), 'BoardViewController', 'show', array('project_id' => $task['project_id'])) ?>
</td>
<td>
<?= $this->text->e($task['column_name']) ?>
</td>
<td>
- <?= $this->url->link($this->text->e($task['title']), 'task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, '', t('View this task')) ?>
+ <?= $this->url->link($this->text->e($task['title']), 'TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, '', t('View this task')) ?>
</td>
<td>
<?php if ($task['assignee_username']): ?>
diff --git a/app/Template/project_user/tooltip_users.php b/app/Template/project_user_overview/tooltip_users.php
index f75d964b..7117a87f 100644
--- a/app/Template/project_user/tooltip_users.php
+++ b/app/Template/project_user_overview/tooltip_users.php
@@ -1,14 +1,16 @@
<?php if (empty($users)): ?>
<p><?= t('There is no project member.') ?></p>
<?php else: ?>
+ <table>
<?php foreach ($roles as $role => $role_name): ?>
<?php if (isset($users[$role])): ?>
- <strong><?= $role_name ?></strong>
- <ul>
+ <tr><th><?= $role_name ?></th></tr>
<?php foreach ($users[$role] as $user_id => $user): ?>
- <li><?= $this->url->link($this->text->e($user), 'Projectuser', 'opens', array('user_id' => $user_id)) ?></li>
+ <tr><td>
+ <?= $this->url->link($this->text->e($user), 'ProjectUserOverviewController', 'opens', array('user_id' => $user_id)) ?>
+ </td></tr>
<?php endforeach ?>
- </ul>
<?php endif ?>
<?php endforeach ?>
-<?php endif ?> \ No newline at end of file
+ </table>
+<?php endif ?>
diff --git a/app/Template/project_view/duplicate.php b/app/Template/project_view/duplicate.php
new file mode 100644
index 00000000..d2cd127a
--- /dev/null
+++ b/app/Template/project_view/duplicate.php
@@ -0,0 +1,28 @@
+<div class="page-header">
+ <h2><?= t('Clone this project') ?></h2>
+</div>
+
+<div class="confirm">
+ <p class="alert alert-info">
+ <?= t('Which parts of the project do you want to duplicate?') ?>
+ </p>
+ <form method="post" action="<?= $this->url->href('ProjectViewController', 'doDuplication', array('project_id' => $project['id'], 'duplicate' => 'yes')) ?>" autocomplete="off">
+
+ <?= $this->form->csrf() ?>
+
+ <?php if ($project['is_private'] == 0): ?>
+ <?= $this->form->checkbox('projectPermission', t('Permissions'), 1, true) ?>
+ <?php endif ?>
+
+ <?= $this->form->checkbox('categoryModel', t('Categories'), 1, true) ?>
+ <?= $this->form->checkbox('actionModel', t('Actions'), 1, true) ?>
+ <?= $this->form->checkbox('swimlaneModel', t('Swimlanes'), 1, false) ?>
+ <?= $this->form->checkbox('taskModel', t('Tasks'), 1, false) ?>
+ <?= $this->form->checkbox('projectMetadataModel', t('Metadata'), 1, false) ?>
+
+ <div class="form-actions">
+ <button type="submit" class="btn btn-red"><?= t('Duplicate') ?></button>
+ <?= t('or') ?> <?= $this->url->link(t('cancel'), 'ProjectViewController', 'show', array('project_id' => $project['id'])) ?>
+ </div>
+ </form>
+</div>
diff --git a/app/Template/project/integrations.php b/app/Template/project_view/integrations.php
index 54720c69..f8bff7ea 100644
--- a/app/Template/project/integrations.php
+++ b/app/Template/project_view/integrations.php
@@ -2,7 +2,7 @@
<h2><?= t('Integration with third-party services') ?></h2>
</div>
-<form method="post" action="<?= $this->url->href('project', 'integrations', array('project_id' => $project['id'])) ?>" autocomplete="off">
+<form method="post" action="<?= $this->url->href('ProjectViewController', 'updateIntegrations', array('project_id' => $project['id'])) ?>" autocomplete="off">
<?= $this->form->csrf() ?>
<?php $integrations = $this->hook->render('template:project:integrations', array('project' => $project, 'values' => $values, 'webhook_token' => $webhook_token)) ?>
@@ -12,4 +12,4 @@
<?php else: ?>
<?= $integrations ?>
<?php endif ?>
-</form> \ No newline at end of file
+</form>
diff --git a/app/Template/project/notifications.php b/app/Template/project_view/notifications.php
index 494a322a..29cc088c 100644
--- a/app/Template/project/notifications.php
+++ b/app/Template/project_view/notifications.php
@@ -4,7 +4,7 @@
<?php if (empty($types)): ?>
<p class="alert"><?= t('No plugin has registered a project notification method. You can still configure individual notifications in your user profile.') ?></p>
<?php else: ?>
- <form method="post" action="<?= $this->url->href('project', 'notifications', array('project_id' => $project['id'])) ?>" autocomplete="off">
+ <form method="post" action="<?= $this->url->href('ProjectViewController', 'updateNotifications', array('project_id' => $project['id'])) ?>" autocomplete="off">
<?= $this->form->csrf() ?>
@@ -14,7 +14,7 @@
<div class="form-actions">
<button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
<?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'project', 'show', array('project_id' => $project['id'])) ?>
+ <?= $this->url->link(t('cancel'), 'ProjectViewController', 'show', array('project_id' => $project['id'])) ?>
</div>
</form>
-<?php endif ?> \ No newline at end of file
+<?php endif ?>
diff --git a/app/Template/project_view/share.php b/app/Template/project_view/share.php
new file mode 100644
index 00000000..409f37e6
--- /dev/null
+++ b/app/Template/project_view/share.php
@@ -0,0 +1,18 @@
+<div class="page-header">
+ <h2><?= t('Public access') ?></h2>
+</div>
+
+<?php if ($project['is_public']): ?>
+
+ <div class="listing">
+ <ul class="no-bullet">
+ <li><strong><i class="fa fa-share-alt"></i> <?= $this->url->link(t('Public link'), 'BoardViewController', 'readonly', array('token' => $project['token']), false, '', '', true) ?></strong></li>
+ <li><strong><i class="fa fa-rss-square"></i> <?= $this->url->link(t('RSS feed'), 'FeedController', 'project', array('token' => $project['token']), false, '', '', true) ?></strong></li>
+ <li><strong><i class="fa fa-calendar"></i> <?= $this->url->link(t('iCal feed'), 'ICalendarController', 'project', array('token' => $project['token']), false, '', '', true) ?></strong></li>
+ </ul>
+ </div>
+
+ <?= $this->url->link(t('Disable public access'), 'ProjectViewController', 'updateSharing', array('project_id' => $project['id'], 'switch' => 'disable'), true, 'btn btn-red') ?>
+<?php else: ?>
+ <?= $this->url->link(t('Enable public access'), 'ProjectViewController', 'updateSharing', array('project_id' => $project['id'], 'switch' => 'enable'), true, 'btn btn-blue') ?>
+<?php endif ?>
diff --git a/app/Template/project/show.php b/app/Template/project_view/show.php
index 42eeec4d..5efe8ce6 100644
--- a/app/Template/project/show.php
+++ b/app/Template/project_view/show.php
@@ -13,9 +13,9 @@
<?php endif ?>
<?php if ($project['is_public']): ?>
- <li><i class="fa fa-share-alt"></i> <?= $this->url->link(t('Public link'), 'board', 'readonly', array('token' => $project['token']), false, '', '', true) ?></li>
- <li><i class="fa fa-rss-square"></i> <?= $this->url->link(t('RSS feed'), 'feed', 'project', array('token' => $project['token']), false, '', '', true) ?></li>
- <li><i class="fa fa-calendar"></i> <?= $this->url->link(t('iCal feed'), 'ical', 'project', array('token' => $project['token'])) ?></li>
+ <li><i class="fa fa-share-alt"></i> <?= $this->url->link(t('Public link'), 'BoardViewController', 'readonly', array('token' => $project['token']), false, '', '', true) ?></li>
+ <li><i class="fa fa-rss-square"></i> <?= $this->url->link(t('RSS feed'), 'FeedController', 'project', array('token' => $project['token']), false, '', '', true) ?></li>
+ <li><i class="fa fa-calendar"></i> <?= $this->url->link(t('iCal feed'), 'ICalendarController', 'project', array('token' => $project['token'])) ?></li>
<?php else: ?>
<li><?= t('Public access disabled') ?></li>
<?php endif ?>
@@ -35,11 +35,11 @@
<?php if ($stats['nb_tasks'] > 0): ?>
<?php if ($stats['nb_active_tasks'] > 0): ?>
- <li><?= $this->url->link(t('%d tasks on the board', $stats['nb_active_tasks']), 'board', 'show', array('project_id' => $project['id'], 'search' => 'status:open')) ?></li>
+ <li><?= $this->url->link(t('%d tasks on the board', $stats['nb_active_tasks']), 'BoardViewController', 'show', array('project_id' => $project['id'], 'search' => 'status:open')) ?></li>
<?php endif ?>
<?php if ($stats['nb_inactive_tasks'] > 0): ?>
- <li><?= $this->url->link(t('%d closed tasks', $stats['nb_inactive_tasks']), 'listing', 'show', array('project_id' => $project['id'], 'search' => 'status:closed')) ?></li>
+ <li><?= $this->url->link(t('%d closed tasks', $stats['nb_inactive_tasks']), 'TaskListController', 'show', array('project_id' => $project['id'], 'search' => 'status:closed')) ?></li>
<?php endif ?>
<li><?= t('%d tasks in total', $stats['nb_tasks']) ?></li>
@@ -63,7 +63,7 @@
<td>
<?= $this->text->e($column['title']) ?>
<?php if (! empty($column['description'])): ?>
- <span class="tooltip" title='<?= $this->text->e($this->text->markdown($column['description'])) ?>'>
+ <span class="tooltip" title="<?= $this->text->markdownAttribute($column['description']) ?>">
<i class="fa fa-info-circle"></i>
</span>
<?php endif ?>
diff --git a/app/Template/search/activity.php b/app/Template/search/activity.php
index 60362215..9abc7d7e 100644
--- a/app/Template/search/activity.php
+++ b/app/Template/search/activity.php
@@ -3,7 +3,7 @@
<ul>
<li>
<i class="fa fa-search fa-fw"></i>
- <?= $this->url->link(t('Search tasks'), 'search', 'index') ?>
+ <?= $this->url->link(t('Search tasks'), 'SearchController', 'index') ?>
</li>
</ul>
</div>
@@ -36,4 +36,4 @@
<?= $this->render('event/events', array('events' => $events)) ?>
<?php endif ?>
-</section> \ No newline at end of file
+</section>
diff --git a/app/Template/search/index.php b/app/Template/search/index.php
index d5d07ed6..bc528af7 100644
--- a/app/Template/search/index.php
+++ b/app/Template/search/index.php
@@ -3,7 +3,7 @@
<ul>
<li>
<i class="fa fa-search fa-fw"></i>
- <?= $this->url->link(t('Activity stream search'), 'search', 'activity') ?>
+ <?= $this->url->link(t('Activity stream search'), 'SearchController', 'activity') ?>
</li>
</ul>
</div>
@@ -40,4 +40,4 @@
)) ?>
<?php endif ?>
-</section> \ No newline at end of file
+</section>
diff --git a/app/Template/search/results.php b/app/Template/search/results.php
index 79df3544..8376b9e8 100644
--- a/app/Template/search/results.php
+++ b/app/Template/search/results.php
@@ -13,10 +13,10 @@
<?php foreach ($paginator->getCollection() as $task): ?>
<tr>
<td>
- <?= $this->url->link($this->text->e($task['project_name']), 'board', 'show', array('project_id' => $task['project_id'])) ?>
+ <?= $this->url->link($this->text->e($task['project_name']), 'BoardViewController', 'show', array('project_id' => $task['project_id'])) ?>
</td>
<td class="task-table color-<?= $task['color_id'] ?>">
- <?= $this->url->link('#'.$this->text->e($task['id']), 'task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, '', t('View this task')) ?>
+ <?= $this->url->link('#'.$this->text->e($task['id']), 'TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, '', t('View this task')) ?>
</td>
<td>
<?= $this->text->e($task['swimlane_name'] ?: $task['default_swimlane']) ?>
@@ -28,7 +28,7 @@
<?= $this->text->e($task['category_name']) ?>
</td>
<td>
- <?= $this->url->link($this->text->e($task['title']), 'task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, '', t('View this task')) ?>
+ <?= $this->url->link($this->text->e($task['title']), 'TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, '', t('View this task')) ?>
</td>
<td>
<?php if ($task['assignee_username']): ?>
@@ -41,7 +41,7 @@
<?= $this->dt->date($task['date_due']) ?>
</td>
<td>
- <?php if ($task['is_active'] == \Kanboard\Model\Task::STATUS_OPEN): ?>
+ <?php if ($task['is_active'] == \Kanboard\Model\TaskModel::STATUS_OPEN): ?>
<?= t('Open') ?>
<?php else: ?>
<?= t('Closed') ?>
diff --git a/app/Template/subtask/create.php b/app/Template/subtask/create.php
index 029fddf5..3c080f7c 100644
--- a/app/Template/subtask/create.php
+++ b/app/Template/subtask/create.php
@@ -2,7 +2,7 @@
<h2><?= t('Add a sub-task') ?></h2>
</div>
-<form class="popover-form" method="post" action="<?= $this->url->href('subtask', 'save', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>" autocomplete="off">
+<form class="popover-form" method="post" action="<?= $this->url->href('SubtaskController', 'save', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>" autocomplete="off">
<?= $this->form->csrf() ?>
<?= $this->form->hidden('task_id', $values) ?>
@@ -15,6 +15,6 @@
<div class="form-actions">
<button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
<?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'close-popover') ?>
+ <?= $this->url->link(t('cancel'), 'TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'close-popover') ?>
</div>
</form>
diff --git a/app/Template/subtask/edit.php b/app/Template/subtask/edit.php
index 3c210f60..8f256cea 100644
--- a/app/Template/subtask/edit.php
+++ b/app/Template/subtask/edit.php
@@ -2,7 +2,7 @@
<h2><?= t('Edit a sub-task') ?></h2>
</div>
-<form class="popover-form" method="post" action="<?= $this->url->href('subtask', 'update', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'subtask_id' => $subtask['id'])) ?>" autocomplete="off">
+<form class="popover-form" method="post" action="<?= $this->url->href('SubtaskController', 'update', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'subtask_id' => $subtask['id'])) ?>" autocomplete="off">
<?= $this->form->csrf() ?>
<?= $this->form->hidden('id', $values) ?>
@@ -15,6 +15,6 @@
<div class="form-actions">
<button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
<?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'close-popover') ?>
+ <?= $this->url->link(t('cancel'), 'TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'close-popover') ?>
</div>
</form>
diff --git a/app/Template/subtask/menu.php b/app/Template/subtask/menu.php
index 6c98b951..d5d1bf85 100644
--- a/app/Template/subtask/menu.php
+++ b/app/Template/subtask/menu.php
@@ -2,10 +2,16 @@
<a href="#" class="dropdown-menu dropdown-menu-link-icon"><i class="fa fa-cog fa-fw"></i><i class="fa fa-caret-down"></i></a>
<ul>
<li>
- <?= $this->url->link(t('Edit'), 'subtask', 'edit', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'subtask_id' => $subtask['id']), false, 'popover') ?>
+ <i class="fa fa-pencil-square-o" aria-hidden="true"></i>
+ <?= $this->url->link(t('Edit'), 'SubtaskController', 'edit', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'subtask_id' => $subtask['id']), false, 'popover') ?>
</li>
<li>
- <?= $this->url->link(t('Remove'), 'subtask', 'confirm', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'subtask_id' => $subtask['id']), false, 'popover') ?>
+ <i class="fa fa-trash-o" aria-hidden="true"></i>
+ <?= $this->url->link(t('Remove'), 'SubtaskController', 'confirm', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'subtask_id' => $subtask['id']), false, 'popover') ?>
+ </li>
+ <li>
+ <i class="fa fa-clone" aria-hidden="true"></i>
+ <?= $this->url->link(t('Convert to task'), 'SubtaskConverterController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'subtask_id' => $subtask['id']), false, 'popover') ?>
</li>
</ul>
</div>
diff --git a/app/Template/subtask/remove.php b/app/Template/subtask/remove.php
index 374256fd..426c1a93 100644
--- a/app/Template/subtask/remove.php
+++ b/app/Template/subtask/remove.php
@@ -3,15 +3,18 @@
</div>
<div class="confirm">
- <p class="alert alert-info">
+ <div class="alert alert-info">
<?= t('Do you really want to remove this sub-task?') ?>
- </p>
-
- <p><strong><?= $this->text->e($subtask['title']) ?></strong></p>
+ <ul>
+ <li>
+ <strong><?= $this->text->e($subtask['title']) ?></strong>
+ </li>
+ </ul>
+ </div>
<div class="form-actions">
- <?= $this->url->link(t('Yes'), 'subtask', 'remove', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'subtask_id' => $subtask['id']), true, 'btn btn-red') ?>
+ <?= $this->url->link(t('Yes'), 'SubtaskController', 'remove', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'subtask_id' => $subtask['id']), true, 'btn btn-red') ?>
<?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'close-popover') ?>
+ <?= $this->url->link(t('cancel'), 'TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'close-popover') ?>
</div>
-</div> \ No newline at end of file
+</div>
diff --git a/app/Template/subtask/table.php b/app/Template/subtask/table.php
index 40510a2f..4c6484ef 100644
--- a/app/Template/subtask/table.php
+++ b/app/Template/subtask/table.php
@@ -1,7 +1,7 @@
<?php if (! empty($subtasks)): ?>
<table
class="subtasks-table table-stripped"
- data-save-position-url="<?= $this->url->href('Subtask', 'movePosition', array('project_id' => $task['project_id'], 'task_id' => $task['id'])) ?>"
+ data-save-position-url="<?= $this->url->href('SubtaskController', 'movePosition', array('project_id' => $task['project_id'], 'task_id' => $task['id'])) ?>"
>
<thead>
<tr>
@@ -44,11 +44,11 @@
<li>
<?php if ($subtask['is_timer_started']): ?>
<i class="fa fa-pause"></i>
- <?= $this->url->link(t('Stop timer'), 'SubtaskStatus', 'timer', array('timer' => 'stop', 'project_id' => $task['project_id'], 'task_id' => $subtask['task_id'], 'subtask_id' => $subtask['id']), false, 'subtask-toggle-timer') ?>
+ <?= $this->url->link(t('Stop timer'), 'SubtaskStatusController', 'timer', array('timer' => 'stop', 'project_id' => $task['project_id'], 'task_id' => $subtask['task_id'], 'subtask_id' => $subtask['id']), false, 'subtask-toggle-timer') ?>
(<?= $this->dt->age($subtask['timer_start_date']) ?>)
<?php else: ?>
<i class="fa fa-play-circle-o"></i>
- <?= $this->url->link(t('Start timer'), 'SubtaskStatus', 'timer', array('timer' => 'start', 'project_id' => $task['project_id'], 'task_id' => $subtask['task_id'], 'subtask_id' => $subtask['id']), false, 'subtask-toggle-timer') ?>
+ <?= $this->url->link(t('Start timer'), 'SubtaskStatusController', 'timer', array('timer' => 'start', 'project_id' => $task['project_id'], 'task_id' => $subtask['task_id'], 'subtask_id' => $subtask['id']), false, 'subtask-toggle-timer') ?>
<?php endif ?>
</li>
<?php endif ?>
diff --git a/app/Template/subtask_converter/show.php b/app/Template/subtask_converter/show.php
new file mode 100644
index 00000000..63f45482
--- /dev/null
+++ b/app/Template/subtask_converter/show.php
@@ -0,0 +1,20 @@
+<div class="page-header">
+ <h2><?= t('Convert sub-task to task') ?></h2>
+</div>
+
+<div class="confirm">
+ <div class="alert alert-info">
+ <?= t('Do you really want to convert this sub-task to a task?') ?>
+ <ul>
+ <li>
+ <strong><?= $this->text->e($subtask['title']) ?></strong>
+ </li>
+ </ul>
+ </div>
+
+ <div class="form-actions">
+ <?= $this->url->link(t('Yes'), 'SubtaskConverterController', 'save', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'subtask_id' => $subtask['id']), true, 'btn btn-red') ?>
+ <?= t('or') ?>
+ <?= $this->url->link(t('cancel'), 'TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'close-popover') ?>
+ </div>
+</div>
diff --git a/app/Template/subtask_restriction/popover.php b/app/Template/subtask_restriction/show.php
index 916a664e..ec8b8d5b 100644
--- a/app/Template/subtask_restriction/popover.php
+++ b/app/Template/subtask_restriction/show.php
@@ -1,7 +1,7 @@
<div class="page-header">
<h2><?= t('You already have one subtask in progress') ?></h2>
</div>
-<form class="popover-form" action="<?= $this->url->href('SubtaskRestriction', 'update', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'subtask_id' => $subtask['id'])) ?>" method="post">
+<form class="popover-form" action="<?= $this->url->href('SubtaskRestrictionController', 'save', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'subtask_id' => $subtask['id'])) ?>" method="post">
<?= $this->form->csrf() ?>
@@ -12,6 +12,6 @@
<div class="form-actions">
<button type="submit" class="btn btn-red"><?= t('Save') ?></button>
<?= t('or') ?>
- <a href="#" class="close-popover"><?= t('cancel') ?></a>
+ <?= $this->url->link(t('cancel'), 'TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'close-popover') ?>
</div>
-</form> \ No newline at end of file
+</form>
diff --git a/app/Template/swimlane/create.php b/app/Template/swimlane/create.php
index a9b4374b..f5aa1591 100644
--- a/app/Template/swimlane/create.php
+++ b/app/Template/swimlane/create.php
@@ -1,7 +1,7 @@
<div class="page-header">
<h2><?= t('Add a new swimlane') ?></h2>
</div>
-<form class="popover-form" method="post" action="<?= $this->url->href('swimlane', 'save', array('project_id' => $project['id'])) ?>" autocomplete="off">
+<form class="popover-form" method="post" action="<?= $this->url->href('SwimlaneController', 'save', array('project_id' => $project['id'])) ?>" autocomplete="off">
<?= $this->form->csrf() ?>
<?= $this->form->hidden('project_id', $values) ?>
@@ -15,6 +15,6 @@
<div class="form-actions">
<button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
<?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'Swimlane', 'index', array('project_id' => $project['id']), false, 'close-popover') ?>
+ <?= $this->url->link(t('cancel'), 'SwimlaneController', 'index', array('project_id' => $project['id']), false, 'close-popover') ?>
</div>
</form>
diff --git a/app/Template/swimlane/edit.php b/app/Template/swimlane/edit.php
index b08099ae..b10cdd52 100644
--- a/app/Template/swimlane/edit.php
+++ b/app/Template/swimlane/edit.php
@@ -2,7 +2,7 @@
<h2><?= t('Swimlane modification for the project "%s"', $project['name']) ?></h2>
</div>
-<form class="popover-form" method="post" action="<?= $this->url->href('swimlane', 'update', array('project_id' => $project['id'], 'swimlane_id' => $values['id'])) ?>" autocomplete="off">
+<form class="popover-form" method="post" action="<?= $this->url->href('SwimlaneController', 'update', array('project_id' => $project['id'], 'swimlane_id' => $values['id'])) ?>" autocomplete="off">
<?= $this->form->csrf() ?>
@@ -18,6 +18,6 @@
<div class="form-actions">
<button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
<?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'swimlane', 'index', array('project_id' => $project['id']), false, 'close-popover') ?>
+ <?= $this->url->link(t('cancel'), 'SwimlaneController', 'index', array('project_id' => $project['id']), false, 'close-popover') ?>
</div>
-</form> \ No newline at end of file
+</form>
diff --git a/app/Template/swimlane/edit_default.php b/app/Template/swimlane/edit_default.php
index 3bf82568..f271c513 100644
--- a/app/Template/swimlane/edit_default.php
+++ b/app/Template/swimlane/edit_default.php
@@ -1,7 +1,7 @@
<div class="page-header">
<h2><?= t('Change default swimlane') ?></h2>
</div>
-<form class="popover-form" method="post" action="<?= $this->url->href('swimlane', 'updateDefault', array('project_id' => $project['id'])) ?>" autocomplete="off">
+<form class="popover-form" method="post" action="<?= $this->url->href('SwimlaneController', 'updateDefault', array('project_id' => $project['id'])) ?>" autocomplete="off">
<?= $this->form->csrf() ?>
<?= $this->form->hidden('id', $values) ?>
@@ -13,6 +13,6 @@
<div class="form-actions">
<button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
<?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'Swimlane', 'index', array('project_id' => $project['id']), false, 'close-popover') ?>
+ <?= $this->url->link(t('cancel'), 'SwimlaneController', 'index', array('project_id' => $project['id']), false, 'close-popover') ?>
</div>
</form>
diff --git a/app/Template/swimlane/index.php b/app/Template/swimlane/index.php
index fad35306..4f78a405 100644
--- a/app/Template/swimlane/index.php
+++ b/app/Template/swimlane/index.php
@@ -3,7 +3,7 @@
<ul>
<li>
<i class="fa fa-plus fa-fw"></i>
- <?= $this->url->link(t('Add a new swimlane'), 'Swimlane', 'create', array('project_id' => $project['id']), false, 'popover') ?>
+ <?= $this->url->link(t('Add a new swimlane'), 'SwimlaneController', 'create', array('project_id' => $project['id']), false, 'popover') ?>
</li>
</ul>
</div>
diff --git a/app/Template/swimlane/remove.php b/app/Template/swimlane/remove.php
index 9be39ff8..f16b778c 100644
--- a/app/Template/swimlane/remove.php
+++ b/app/Template/swimlane/remove.php
@@ -9,9 +9,9 @@
</p>
<div class="form-actions">
- <?= $this->url->link(t('Yes'), 'swimlane', 'remove', array('project_id' => $project['id'], 'swimlane_id' => $swimlane['id']), true, 'btn btn-red') ?>
+ <?= $this->url->link(t('Yes'), 'SwimlaneController', 'remove', array('project_id' => $project['id'], 'swimlane_id' => $swimlane['id']), true, 'btn btn-red') ?>
<?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'swimlane', 'index', array('project_id' => $project['id']), false, 'close-popover') ?>
+ <?= $this->url->link(t('cancel'), 'SwimlaneController', 'index', array('project_id' => $project['id']), false, 'close-popover') ?>
</div>
</div>
-</section> \ No newline at end of file
+</section>
diff --git a/app/Template/swimlane/table.php b/app/Template/swimlane/table.php
index 17be6924..be123b08 100644
--- a/app/Template/swimlane/table.php
+++ b/app/Template/swimlane/table.php
@@ -1,6 +1,6 @@
<table
class="swimlanes-table table-stripped"
- data-save-position-url="<?= $this->url->href('Swimlane', 'move', array('project_id' => $project['id'])) ?>">
+ data-save-position-url="<?= $this->url->href('SwimlaneController', 'move', array('project_id' => $project['id'])) ?>">
<thead>
<tr>
<th><?= t('Name') ?></th>
@@ -20,13 +20,13 @@
<a href="#" class="dropdown-menu dropdown-menu-link-icon"><i class="fa fa-cog fa-fw"></i><i class="fa fa-caret-down"></i></a>
<ul>
<li>
- <?= $this->url->link(t('Edit'), 'Swimlane', 'editDefault', array('project_id' => $project['id']), false, 'popover') ?>
+ <?= $this->url->link(t('Edit'), 'SwimlaneController', 'editDefault', array('project_id' => $project['id']), false, 'popover') ?>
</li>
<li>
<?php if ($default_swimlane['show_default_swimlane'] == 1): ?>
- <?= $this->url->link(t('Disable'), 'Swimlane', 'disableDefault', array('project_id' => $project['id']), true) ?>
+ <?= $this->url->link(t('Disable'), 'SwimlaneController', 'disableDefault', array('project_id' => $project['id']), true) ?>
<?php else: ?>
- <?= $this->url->link(t('Enable'), 'Swimlane', 'enableDefault', array('project_id' => $project['id']), true) ?>
+ <?= $this->url->link(t('Enable'), 'SwimlaneController', 'enableDefault', array('project_id' => $project['id']), true) ?>
<?php endif ?>
</li>
</ul>
@@ -45,7 +45,7 @@
<?= $this->text->e($swimlane['name']) ?>
<?php if (! empty($swimlane['description'])): ?>
- <span class="tooltip" title='<?= $this->text->e($this->text->markdown($swimlane['description'])) ?>'>
+ <span class="tooltip" title="<?= $this->text->markdownAttribute($swimlane['description']) ?>">
<i class="fa fa-info-circle"></i>
</span>
<?php endif ?>
@@ -55,17 +55,17 @@
<a href="#" class="dropdown-menu dropdown-menu-link-icon"><i class="fa fa-cog fa-fw"></i><i class="fa fa-caret-down"></i></a>
<ul>
<li>
- <?= $this->url->link(t('Edit'), 'swimlane', 'edit', array('project_id' => $project['id'], 'swimlane_id' => $swimlane['id']), false, 'popover') ?>
+ <?= $this->url->link(t('Edit'), 'SwimlaneController', 'edit', array('project_id' => $project['id'], 'swimlane_id' => $swimlane['id']), false, 'popover') ?>
</li>
<li>
<?php if ($swimlane['is_active']): ?>
- <?= $this->url->link(t('Disable'), 'swimlane', 'disable', array('project_id' => $project['id'], 'swimlane_id' => $swimlane['id']), true) ?>
+ <?= $this->url->link(t('Disable'), 'SwimlaneController', 'disable', array('project_id' => $project['id'], 'swimlane_id' => $swimlane['id']), true) ?>
<?php else: ?>
- <?= $this->url->link(t('Enable'), 'swimlane', 'enable', array('project_id' => $project['id'], 'swimlane_id' => $swimlane['id']), true) ?>
+ <?= $this->url->link(t('Enable'), 'SwimlaneController', 'enable', array('project_id' => $project['id'], 'swimlane_id' => $swimlane['id']), true) ?>
<?php endif ?>
</li>
<li>
- <?= $this->url->link(t('Remove'), 'swimlane', 'confirm', array('project_id' => $project['id'], 'swimlane_id' => $swimlane['id']), false, 'popover') ?>
+ <?= $this->url->link(t('Remove'), 'SwimlaneController', 'confirm', array('project_id' => $project['id'], 'swimlane_id' => $swimlane['id']), false, 'popover') ?>
</li>
</ul>
</div>
diff --git a/app/Template/task/analytics.php b/app/Template/task/analytics.php
index 54eac2b7..db2d0cef 100644
--- a/app/Template/task/analytics.php
+++ b/app/Template/task/analytics.php
@@ -34,6 +34,3 @@
<li><?= t('If the task is not closed the current time is used instead of the completion date.') ?></li>
</ul>
</div>
-
-<?= $this->asset->js('assets/js/vendor/d3.v3.min.js') ?>
-<?= $this->asset->js('assets/js/vendor/c3.min.js') ?> \ No newline at end of file
diff --git a/app/Template/task/description.php b/app/Template/task/description.php
index 9ffe8589..f8e313dd 100644
--- a/app/Template/task/description.php
+++ b/app/Template/task/description.php
@@ -4,29 +4,7 @@
</div>
<div class="accordion-content">
<article class="markdown">
- <?php if (! isset($is_public)): ?>
- <?= $this->text->markdown(
- $task['description'],
- array(
- 'controller' => 'task',
- 'action' => 'show',
- 'params' => array(
- 'project_id' => $task['project_id']
- )
- )
- ) ?>
- <?php else: ?>
- <?= $this->text->markdown(
- $task['description'],
- array(
- 'controller' => 'task',
- 'action' => 'readonly',
- 'params' => array(
- 'token' => $project['token']
- )
- )
- ) ?>
- <?php endif ?>
+ <?= $this->text->markdown($task['description'], isset($is_public) && $is_public) ?>
</article>
</div>
-</section> \ No newline at end of file
+</section>
diff --git a/app/Template/task/details.php b/app/Template/task/details.php
index 5b8b7c6d..fe2bba67 100644
--- a/app/Template/task/details.php
+++ b/app/Template/task/details.php
@@ -32,13 +32,13 @@
<?php if ($project['is_public']): ?>
<li class="smaller">
<i class="fa fa-external-link fa-fw"></i>
- <?= $this->url->link(t('Public link'), 'task', 'readonly', array('task_id' => $task['id'], 'token' => $project['token']), false, '', '', true) ?>
+ <?= $this->url->link(t('Public link'), 'TaskViewController', 'readonly', array('task_id' => $task['id'], 'token' => $project['token']), false, '', '', true) ?>
</li>
<?php endif ?>
<?php if ($project['is_public'] && !$editable): ?>
<li class="smaller">
<i class="fa fa-th fa-fw"></i>
- <?= $this->url->link(t('Back to the board'), 'board', 'readonly', array('token' => $project['token'])) ?>
+ <?= $this->url->link(t('Back to the board'), 'BoardViewController', 'readonly', array('token' => $project['token'])) ?>
</li>
<?php endif ?>
<li class="smaller">
@@ -148,7 +148,7 @@
<?php if ($editable && empty($task['date_started'])): ?>
<div class="task-summary-buttons">
- <?= $this->url->button('fa-play', t('Set start date'), 'taskmodification', 'start', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>
+ <?= $this->url->button('fa-play', t('Set start date'), 'TaskModificationController', 'start', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>
</div>
<?php endif ?>
diff --git a/app/Template/task/dropdown.php b/app/Template/task/dropdown.php
index 6fea3728..b6b9c789 100644
--- a/app/Template/task/dropdown.php
+++ b/app/Template/task/dropdown.php
@@ -1,56 +1,74 @@
<div class="dropdown">
<a href="#" class="dropdown-menu">#<?= $task['id'] ?></a>
<ul>
- <?php if (isset($task['date_started']) && empty($task['date_started'])): ?>
+ <?php if (array_key_exists('date_started', $task) && empty($task['date_started'])): ?>
<li>
<i class="fa fa-play fa-fw"></i>
- <?= $this->url->link(t('Set automatically the start date'), 'taskmodification', 'start', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>
+ <?= $this->url->link(t('Set automatically the start date'), 'TaskModificationController', 'start', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>
</li>
<?php endif ?>
<li>
+ <i class="fa fa-user fa-fw"></i>
+ <?= $this->url->link(t('Change assignee'), 'TaskPopoverController', 'changeAssignee', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?>
+ </li>
+ <li>
+ <i class="fa fa-tag fa-fw"></i>
+ <?= $this->url->link(t('Change category'), 'TaskPopoverController', 'changeCategory', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?>
+ </li>
+ <li>
<i class="fa fa-pencil-square-o fa-fw"></i>
- <?= $this->url->link(t('Edit the task'), 'taskmodification', 'edit', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?>
+ <?= $this->url->link(t('Edit the task'), 'TaskModificationController', 'edit', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?>
</li>
<li>
<i class="fa fa-align-left fa-fw"></i>
- <?= $this->url->link(t('Edit the description'), 'taskmodification', 'description', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?>
+ <?= $this->url->link(t('Edit the description'), 'TaskModificationController', 'description', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?>
</li>
<li>
<i class="fa fa-plus fa-fw"></i>
- <?= $this->url->link(t('Add a sub-task'), 'subtask', 'create', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?>
+ <?= $this->url->link(t('Add a sub-task'), 'SubtaskController', 'create', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?>
</li>
<li>
<i class="fa fa-code-fork fa-fw"></i>
- <?= $this->url->link(t('Add internal link'), 'TaskInternalLink', 'create', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?>
+ <?= $this->url->link(t('Add internal link'), 'TaskInternalLinkController', 'create', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?>
</li>
<li>
<i class="fa fa-external-link fa-fw"></i>
- <?= $this->url->link(t('Add external link'), 'TaskExternalLink', 'find', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?>
+ <?= $this->url->link(t('Add external link'), 'TaskExternalLinkController', 'find', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?>
</li>
<li>
<i class="fa fa-comment-o fa-fw"></i>
- <?= $this->url->link(t('Add a comment'), 'comment', 'create', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?>
+ <?= $this->url->link(t('Add a comment'), 'CommentController', 'create', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?>
+ </li>
+ <li>
+ <i class="fa fa-camera fa-fw"></i>
+ <?= $this->url->link(t('Add a screenshot'), 'TaskPopoverController', 'screenshot', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?>
</li>
<li>
<i class="fa fa-files-o fa-fw"></i>
- <?= $this->url->link(t('Duplicate'), 'taskduplication', 'duplicate', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?>
+ <?= $this->url->link(t('Duplicate'), 'TaskDuplicationController', 'duplicate', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?>
</li>
<li>
<i class="fa fa-clipboard fa-fw"></i>
- <?= $this->url->link(t('Duplicate to another project'), 'taskduplication', 'copy', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?>
+ <?= $this->url->link(t('Duplicate to another project'), 'TaskDuplicationController', 'copy', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?>
</li>
<li>
<i class="fa fa-clone fa-fw"></i>
- <?= $this->url->link(t('Move to another project'), 'taskduplication', 'move', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?>
+ <?= $this->url->link(t('Move to another project'), 'TaskDuplicationController', 'move', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?>
</li>
+ <?php if ($this->user->canRemoveTask($task)): ?>
+ <li>
+ <i class="fa fa-trash-o fa-fw"></i>
+ <?= $this->url->link(t('Remove'), 'TaskSuppressionController', 'confirm', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?>
+ </li>
+ <?php endif ?>
<?php if (isset($task['is_active'])): ?>
<li>
<?php if ($task['is_active'] == 1): ?>
<i class="fa fa-times fa-fw"></i>
- <?= $this->url->link(t('Close this task'), 'taskstatus', 'close', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?>
+ <?= $this->url->link(t('Close this task'), 'TaskStatusController', 'close', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?>
<?php else: ?>
<i class="fa fa-check-square-o fa-fw"></i>
- <?= $this->url->link(t('Open this task'), 'taskstatus', 'open', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?>
+ <?= $this->url->link(t('Open this task'), 'TaskStatusController', 'open', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?>
<?php endif ?>
</li>
<?php endif ?>
diff --git a/app/Template/task/layout.php b/app/Template/task/layout.php
index ba2cd8d5..00e0e9ae 100644
--- a/app/Template/task/layout.php
+++ b/app/Template/task/layout.php
@@ -1,13 +1,13 @@
<section id="main">
- <?= $this->projectHeader->render($project, 'Listing', 'show') ?>
+ <?= $this->projectHeader->render($project, 'TaskListController', 'show') ?>
<?= $this->hook->render('template:task:layout:top', array('task' => $task)) ?>
<section
class="sidebar-container" id="task-view"
- data-edit-url="<?= $this->url->href('taskmodification', 'edit', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>"
- data-description-url="<?= $this->url->href('taskmodification', 'description', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>"
- data-subtask-url="<?= $this->url->href('subtask', 'create', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>"
- data-internal-link-url="<?= $this->url->href('TaskInternalLink', 'create', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>"
- data-comment-url="<?= $this->url->href('comment', 'create', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>">
+ data-edit-url="<?= $this->url->href('TaskModificationController', 'edit', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>"
+ data-description-url="<?= $this->url->href('TaskModificationController', 'description', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>"
+ data-subtask-url="<?= $this->url->href('SubtaskController', 'create', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>"
+ data-internal-link-url="<?= $this->url->href('TaskInternalLinkController', 'create', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>"
+ data-comment-url="<?= $this->url->href('CommentController', 'create', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>">
<?= $this->render($sidebar_template, array('task' => $task)) ?>
diff --git a/app/Template/task/remove.php b/app/Template/task/remove.php
deleted file mode 100644
index eb0809b1..00000000
--- a/app/Template/task/remove.php
+++ /dev/null
@@ -1,15 +0,0 @@
-<div class="page-header">
- <h2><?= t('Remove a task') ?></h2>
-</div>
-
-<div class="confirm">
- <p class="alert alert-info">
- <?= t('Do you really want to remove this task: "%s"?', $this->text->e($task['title'])) ?>
- </p>
-
- <div class="form-actions">
- <?= $this->url->link(t('Yes'), 'task', 'remove', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'confirmation' => 'yes'), true, 'btn btn-red') ?>
- <?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'close-popover') ?>
- </div>
-</div> \ No newline at end of file
diff --git a/app/Template/task/show.php b/app/Template/task/show.php
index 8f41d653..2b54eea8 100644
--- a/app/Template/task/show.php
+++ b/app/Template/task/show.php
@@ -3,7 +3,7 @@
<?= $this->render('task/details', array(
'task' => $task,
'project' => $project,
- 'editable' => $this->user->hasProjectAccess('taskmodification', 'edit', $project['id']),
+ 'editable' => $this->user->hasProjectAccess('TaskModificationController', 'edit', $project['id']),
)) ?>
<?= $this->hook->render('template:task:show:before-description', array('task' => $task, 'project' => $project)) ?>
@@ -46,7 +46,7 @@
'task' => $task,
'comments' => $comments,
'project' => $project,
- 'editable' => $this->user->hasProjectAccess('comment', 'edit', $project['id']),
+ 'editable' => $this->user->hasProjectAccess('CommentController', 'edit', $project['id']),
)) ?>
<?= $this->hook->render('template:task:show:bottom', array('task' => $task, 'project' => $project)) ?>
diff --git a/app/Template/task/sidebar.php b/app/Template/task/sidebar.php
index a2d73b8c..e77ec18a 100644
--- a/app/Template/task/sidebar.php
+++ b/app/Template/task/sidebar.php
@@ -1,96 +1,96 @@
<div class="sidebar sidebar-icons">
<h2><?= t('Task #%d', $task['id']) ?></h2>
<ul>
- <li <?= $this->app->checkMenuSelection('task', 'show') ?>>
+ <li <?= $this->app->checkMenuSelection('TaskViewController', 'show') ?>>
<i class="fa fa-newspaper-o fa-fw"></i>
- <?= $this->url->link(t('Summary'), 'task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>
+ <?= $this->url->link(t('Summary'), 'TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>
</li>
- <li <?= $this->app->checkMenuSelection('activity', 'task') ?>>
+ <li <?= $this->app->checkMenuSelection('ActivityController', 'task') ?>>
<i class="fa fa-dashboard fa-fw"></i>
- <?= $this->url->link(t('Activity stream'), 'activity', 'task', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>
+ <?= $this->url->link(t('Activity stream'), 'ActivityController', 'task', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>
</li>
- <li <?= $this->app->checkMenuSelection('task', 'transitions') ?>>
+ <li <?= $this->app->checkMenuSelection('TaskViewController', 'transitions') ?>>
<i class="fa fa-arrows-h fa-fw"></i>
- <?= $this->url->link(t('Transitions'), 'task', 'transitions', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>
+ <?= $this->url->link(t('Transitions'), 'TaskViewController', 'transitions', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>
</li>
- <li <?= $this->app->checkMenuSelection('task', 'analytics') ?>>
+ <li <?= $this->app->checkMenuSelection('TaskViewController', 'analytics') ?>>
<i class="fa fa-bar-chart fa-fw"></i>
- <?= $this->url->link(t('Analytics'), 'task', 'analytics', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>
+ <?= $this->url->link(t('Analytics'), 'TaskViewController', 'analytics', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>
</li>
<?php if ($task['time_estimated'] > 0 || $task['time_spent'] > 0): ?>
- <li <?= $this->app->checkMenuSelection('task', 'timetracking') ?>>
+ <li <?= $this->app->checkMenuSelection('TaskViewController', 'timetracking') ?>>
<i class="fa fa-clock-o fa-fw"></i>
- <?= $this->url->link(t('Time tracking'), 'task', 'timetracking', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>
+ <?= $this->url->link(t('Time tracking'), 'TaskViewController', 'timetracking', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>
</li>
<?php endif ?>
<?= $this->hook->render('template:task:sidebar:information', array('task' => $task)) ?>
</ul>
- <?php if ($this->user->hasProjectAccess('taskmodification', 'edit', $task['project_id'])): ?>
+ <?php if ($this->user->hasProjectAccess('TaskModificationController', 'edit', $task['project_id'])): ?>
<h2><?= t('Actions') ?></h2>
<ul>
<li>
<i class="fa fa-pencil-square-o fa-fw"></i>
- <?= $this->url->link(t('Edit the task'), 'taskmodification', 'edit', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?>
+ <?= $this->url->link(t('Edit the task'), 'TaskModificationController', 'edit', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?>
</li>
<li>
<i class="fa fa-align-left fa-fw"></i>
- <?= $this->url->link(t('Edit the description'), 'taskmodification', 'description', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?>
+ <?= $this->url->link(t('Edit the description'), 'TaskModificationController', 'description', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?>
</li>
<li>
<i class="fa fa-refresh fa-rotate-90 fa-fw"></i>
- <?= $this->url->link(t('Edit recurrence'), 'TaskRecurrence', 'edit', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?>
+ <?= $this->url->link(t('Edit recurrence'), 'TaskRecurrenceController', 'edit', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?>
</li>
<li>
<i class="fa fa-plus fa-fw"></i>
- <?= $this->url->link(t('Add a sub-task'), 'subtask', 'create', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?>
+ <?= $this->url->link(t('Add a sub-task'), 'SubtaskController', 'create', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?>
</li>
<li>
<i class="fa fa-code-fork fa-fw"></i>
- <?= $this->url->link(t('Add internal link'), 'TaskInternalLink', 'create', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?>
+ <?= $this->url->link(t('Add internal link'), 'TaskInternalLinkController', 'create', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?>
</li>
<li>
<i class="fa fa-external-link fa-fw"></i>
- <?= $this->url->link(t('Add external link'), 'TaskExternalLink', 'find', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?>
+ <?= $this->url->link(t('Add external link'), 'TaskExternalLinkController', 'find', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?>
</li>
<li>
<i class="fa fa-comment-o fa-fw"></i>
- <?= $this->url->link(t('Add a comment'), 'comment', 'create', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?>
+ <?= $this->url->link(t('Add a comment'), 'CommentController', 'create', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?>
</li>
<li>
<i class="fa fa-file fa-fw"></i>
- <?= $this->url->link(t('Attach a document'), 'TaskFile', 'create', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?>
+ <?= $this->url->link(t('Attach a document'), 'TaskFileController', 'create', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?>
</li>
<li>
<i class="fa fa-camera fa-fw"></i>
- <?= $this->url->link(t('Add a screenshot'), 'TaskFile', 'screenshot', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?>
+ <?= $this->url->link(t('Add a screenshot'), 'TaskFileController', 'screenshot', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?>
</li>
<li>
<i class="fa fa-files-o fa-fw"></i>
- <?= $this->url->link(t('Duplicate'), 'taskduplication', 'duplicate', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?>
+ <?= $this->url->link(t('Duplicate'), 'TaskDuplicationController', 'duplicate', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?>
</li>
<li>
<i class="fa fa-clipboard fa-fw"></i>
- <?= $this->url->link(t('Duplicate to another project'), 'taskduplication', 'copy', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?>
+ <?= $this->url->link(t('Duplicate to another project'), 'TaskDuplicationController', 'copy', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?>
</li>
<li>
<i class="fa fa-clone fa-fw"></i>
- <?= $this->url->link(t('Move to another project'), 'taskduplication', 'move', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?>
+ <?= $this->url->link(t('Move to another project'), 'TaskDuplicationController', 'move', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?>
</li>
<li>
<?php if ($task['is_active'] == 1): ?>
<i class="fa fa-times fa-fw"></i>
- <?= $this->url->link(t('Close this task'), 'taskstatus', 'close', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?>
+ <?= $this->url->link(t('Close this task'), 'TaskStatusController', 'close', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?>
<?php else: ?>
<i class="fa fa-check-square-o fa-fw"></i>
- <?= $this->url->link(t('Open this task'), 'taskstatus', 'open', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?>
+ <?= $this->url->link(t('Open this task'), 'TaskStatusController', 'open', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?>
<?php endif ?>
</li>
- <?php if ($this->task->canRemove($task)): ?>
+ <?php if ($this->user->canRemoveTask($task)): ?>
<li>
<i class="fa fa-trash-o fa-fw"></i>
- <?= $this->url->link(t('Remove'), 'task', 'remove', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?>
+ <?= $this->url->link(t('Remove'), 'TaskSuppressionController', 'confirm', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'redirect' => 'board'), false, 'popover') ?>
</li>
<?php endif ?>
diff --git a/app/Template/task/time_tracking_details.php b/app/Template/task/time_tracking_details.php
index c51b8f5a..1a179522 100644
--- a/app/Template/task/time_tracking_details.php
+++ b/app/Template/task/time_tracking_details.php
@@ -14,11 +14,11 @@
<th><?= $subtask_paginator->order(t('Subtask'), 'subtask_title') ?></th>
<th class="column-20"><?= $subtask_paginator->order(t('Start'), 'start') ?></th>
<th class="column-20"><?= $subtask_paginator->order(t('End'), 'end') ?></th>
- <th class="column-10"><?= $subtask_paginator->order(t('Time spent'), \Kanboard\Model\SubtaskTimeTracking::TABLE.'.time_spent') ?></th>
+ <th class="column-10"><?= $subtask_paginator->order(t('Time spent'), \Kanboard\Model\SubtaskTimeTrackingModel::TABLE.'.time_spent') ?></th>
</tr>
<?php foreach ($subtask_paginator->getCollection() as $record): ?>
<tr>
- <td><?= $this->url->link($this->text->e($record['user_fullname'] ?: $record['username']), 'user', 'show', array('user_id' => $record['user_id'])) ?></td>
+ <td><?= $this->url->link($this->text->e($record['user_fullname'] ?: $record['username']), 'UserViewController', 'show', array('user_id' => $record['user_id'])) ?></td>
<td><?= t($record['subtask_title']) ?></td>
<td><?= $this->dt->datetime($record['start']) ?></td>
<td><?= $this->dt->datetime($record['end']) ?></td>
@@ -28,4 +28,4 @@
</table>
<?= $subtask_paginator ?>
-<?php endif ?> \ No newline at end of file
+<?php endif ?>
diff --git a/app/Template/task/transitions.php b/app/Template/task/transitions.php
index 83040177..9e04c4e1 100644
--- a/app/Template/task/transitions.php
+++ b/app/Template/task/transitions.php
@@ -22,9 +22,9 @@
<td><?= $this->dt->datetime($transition['date']) ?></td>
<td><?= $this->text->e($transition['src_column']) ?></td>
<td><?= $this->text->e($transition['dst_column']) ?></td>
- <td><?= $this->url->link($this->text->e($transition['name'] ?: $transition['username']), 'user', 'show', array('user_id' => $transition['user_id'])) ?></td>
+ <td><?= $this->url->link($this->text->e($transition['name'] ?: $transition['username']), 'UserViewController', 'show', array('user_id' => $transition['user_id'])) ?></td>
<td><?= $this->dt->duration($transition['time_spent']) ?></td>
</tr>
<?php endforeach ?>
</table>
-<?php endif ?> \ No newline at end of file
+<?php endif ?>
diff --git a/app/Template/task_bulk/show.php b/app/Template/task_bulk/show.php
new file mode 100644
index 00000000..1391c2c1
--- /dev/null
+++ b/app/Template/task_bulk/show.php
@@ -0,0 +1,25 @@
+<div class="page-header">
+ <h2><?= t('Create tasks in bulk') ?></h2>
+</div>
+
+<form class="popover-form" method="post" action="<?= $this->url->href('TaskBulkController', 'save', array('project_id' => $project['id'])) ?>" autocomplete="off">
+ <?= $this->form->csrf() ?>
+ <?= $this->form->hidden('column_id', $values) ?>
+ <?= $this->form->hidden('swimlane_id', $values) ?>
+ <?= $this->form->hidden('project_id', $values) ?>
+
+ <?= $this->task->selectAssignee($users_list, $values, $errors) ?>
+ <?= $this->task->selectCategory($categories_list, $values, $errors) ?>
+
+ <?= $this->form->label(t('Tasks'), 'tasks') ?>
+ <?= $this->form->textarea('tasks', $values, $errors, array('placeholder="'.t('My task title').'"')) ?>
+ <p class="form-help"><?= t('Enter one task by line.') ?></p>
+
+ <?= $this->render('task/color_picker', array('colors_list' => $colors_list, 'values' => $values)) ?>
+
+ <div class="form-actions">
+ <button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
+ <?= t('or') ?> <?= $this->url->link(t('cancel'), 'BoardViewController', 'show', array('project_id' => $project['id']), false, 'close-popover') ?>
+ </div>
+</form>
+
diff --git a/app/Template/task_creation/form.php b/app/Template/task_creation/show.php
index c963bdcf..7bebbfe9 100644
--- a/app/Template/task_creation/form.php
+++ b/app/Template/task_creation/show.php
@@ -2,7 +2,7 @@
<h2><?= t('New task') ?></h2>
</div>
-<form class="popover-form" method="post" action="<?= $this->url->href('taskcreation', 'save', array('project_id' => $values['project_id'])) ?>" autocomplete="off">
+<form class="popover-form" method="post" action="<?= $this->url->href('TaskCreationController', 'save', array('project_id' => $values['project_id'])) ?>" autocomplete="off">
<?= $this->form->csrf() ?>
@@ -18,7 +18,7 @@
array(
'placeholder="'.t('Leave a description').'"',
'tabindex="2"',
- 'data-mention-search-url="'.$this->url->href('UserHelper', 'mention', array('project_id' => $values['project_id'])).'"'
+ 'data-mention-search-url="'.$this->url->href('UserAjaxController', 'mention', array('project_id' => $values['project_id'])).'"'
),
'markdown-editor'
) ?>
@@ -48,6 +48,6 @@
<div class="form-actions">
<button type="submit" class="btn btn-blue" tabindex="15"><?= t('Save') ?></button>
- <?= t('or') ?> <?= $this->url->link(t('cancel'), 'board', 'show', array('project_id' => $values['project_id']), false, 'close-popover') ?>
+ <?= t('or') ?> <?= $this->url->link(t('cancel'), 'BoardViewController', 'show', array('project_id' => $values['project_id']), false, 'close-popover') ?>
</div>
</form>
diff --git a/app/Template/task_duplication/copy.php b/app/Template/task_duplication/copy.php
index b7337a1e..58b4d837 100644
--- a/app/Template/task_duplication/copy.php
+++ b/app/Template/task_duplication/copy.php
@@ -6,7 +6,7 @@
<p class="alert"><?= t('There is no destination project available.') ?></p>
<?php else: ?>
- <form class="popover-form" method="post" action="<?= $this->url->href('taskduplication', 'copy', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>" autocomplete="off">
+ <form class="popover-form" method="post" action="<?= $this->url->href('TaskDuplicationController', 'copy', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>" autocomplete="off">
<?= $this->form->csrf() ?>
<?= $this->form->hidden('id', $values) ?>
@@ -17,7 +17,7 @@
$projects_list,
$values,
array(),
- array('data-redirect="'.$this->url->href('taskduplication', 'copy', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'dst_project_id' => 'PROJECT_ID')).'"'),
+ array('data-redirect="'.$this->url->href('TaskDuplicationController', 'copy', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'dst_project_id' => 'PROJECT_ID')).'"'),
'task-reload-project-destination'
) ?>
<span class="loading-icon" style="display: none">&nbsp;<i class="fa fa-spinner fa-spin"></i></span>
@@ -41,8 +41,8 @@
<div class="form-actions">
<button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
<?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'close-popover') ?>
+ <?= $this->url->link(t('cancel'), 'TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'close-popover') ?>
</div>
</form>
-<?php endif ?> \ No newline at end of file
+<?php endif ?>
diff --git a/app/Template/task_duplication/duplicate.php b/app/Template/task_duplication/duplicate.php
index 376f6b3b..c0baf94e 100644
--- a/app/Template/task_duplication/duplicate.php
+++ b/app/Template/task_duplication/duplicate.php
@@ -8,8 +8,8 @@
</p>
<div class="form-actions">
- <?= $this->url->link(t('Yes'), 'taskduplication', 'duplicate', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'confirmation' => 'yes'), true, 'btn btn-red') ?>
+ <?= $this->url->link(t('Yes'), 'TaskDuplicationController', 'duplicate', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'confirmation' => 'yes'), true, 'btn btn-red') ?>
<?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'close-popover') ?>
+ <?= $this->url->link(t('cancel'), 'TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'close-popover') ?>
</div>
-</div> \ No newline at end of file
+</div>
diff --git a/app/Template/task_duplication/move.php b/app/Template/task_duplication/move.php
index beebf9eb..8f01c4b9 100644
--- a/app/Template/task_duplication/move.php
+++ b/app/Template/task_duplication/move.php
@@ -6,7 +6,7 @@
<p class="alert"><?= t('There is no destination project available.') ?></p>
<?php else: ?>
- <form class="popover-form" method="post" action="<?= $this->url->href('taskduplication', 'move', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>" autocomplete="off">
+ <form class="popover-form" method="post" action="<?= $this->url->href('TaskDuplicationController', 'move', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>" autocomplete="off">
<?= $this->form->csrf() ?>
<?= $this->form->hidden('id', $values) ?>
@@ -17,7 +17,7 @@
$projects_list,
$values,
array(),
- array('data-redirect="'.$this->url->href('taskduplication', 'move', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'dst_project_id' => 'PROJECT_ID')).'"'),
+ array('data-redirect="'.$this->url->href('TaskDuplicationController', 'move', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'dst_project_id' => 'PROJECT_ID')).'"'),
'task-reload-project-destination'
) ?>
<span class="loading-icon" style="display: none">&nbsp;<i class="fa fa-spinner fa-spin"></i></span>
@@ -41,8 +41,8 @@
<div class="form-actions">
<button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
<?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'close-popover') ?>
+ <?= $this->url->link(t('cancel'), 'TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'close-popover') ?>
</div>
</form>
-<?php endif ?> \ No newline at end of file
+<?php endif ?>
diff --git a/app/Template/task_external_link/create.php b/app/Template/task_external_link/create.php
index 5d49eef0..beddfc90 100644
--- a/app/Template/task_external_link/create.php
+++ b/app/Template/task_external_link/create.php
@@ -2,12 +2,12 @@
<h2><?= t('Add a new external link') ?></h2>
</div>
-<form class="popover-form" action="<?= $this->url->href('TaskExternalLink', 'save', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>" method="post" autocomplete="off">
+<form class="popover-form" action="<?= $this->url->href('TaskExternalLinkController', 'save', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>" method="post" autocomplete="off">
<?= $this->render('task_external_link/form', array('task' => $task, 'dependencies' => $dependencies, 'values' => $values, 'errors' => $errors)) ?>
<div class="form-actions">
<button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
<?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'TaskExternalLink', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'close-popover') ?>
+ <?= $this->url->link(t('cancel'), 'TaskExternalLinkController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'close-popover') ?>
</div>
-</form> \ No newline at end of file
+</form>
diff --git a/app/Template/task_external_link/edit.php b/app/Template/task_external_link/edit.php
index dcbc2633..917a28b9 100644
--- a/app/Template/task_external_link/edit.php
+++ b/app/Template/task_external_link/edit.php
@@ -2,12 +2,12 @@
<h2><?= t('Edit external link') ?></h2>
</div>
-<form class="popover-form" action="<?= $this->url->href('TaskExternalLink', 'update', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>" method="post" autocomplete="off">
+<form class="popover-form" action="<?= $this->url->href('TaskExternalLinkController', 'update', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>" method="post" autocomplete="off">
<?= $this->render('task_external_link/form', array('task' => $task, 'dependencies' => $dependencies, 'values' => $values, 'errors' => $errors)) ?>
<div class="form-actions">
<button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
<?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'TaskExternalLink', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'close-popover') ?>
+ <?= $this->url->link(t('cancel'), 'TaskExternalLinkController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'close-popover') ?>
</div>
-</form> \ No newline at end of file
+</form>
diff --git a/app/Template/task_external_link/find.php b/app/Template/task_external_link/find.php
index 3977a66c..a88b29ce 100644
--- a/app/Template/task_external_link/find.php
+++ b/app/Template/task_external_link/find.php
@@ -2,7 +2,7 @@
<h2><?= t('Add a new external link') ?></h2>
</div>
-<form class="popover-form" action="<?= $this->url->href('TaskExternalLink', 'create', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>" method="post" autocomplete="off">
+<form class="popover-form" action="<?= $this->url->href('TaskExternalLinkController', 'create', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>" method="post" autocomplete="off">
<?= $this->form->csrf() ?>
<?= $this->form->hidden('task_id', array('task_id' => $task['id'])) ?>
@@ -23,6 +23,6 @@
<div class="form-actions">
<button type="submit" class="btn btn-blue"><?= t('Next') ?></button>
<?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'close-popover') ?>
+ <?= $this->url->link(t('cancel'), 'TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'close-popover') ?>
</div>
-</form> \ No newline at end of file
+</form>
diff --git a/app/Template/task_external_link/remove.php b/app/Template/task_external_link/remove.php
index 01535255..2a888a60 100644
--- a/app/Template/task_external_link/remove.php
+++ b/app/Template/task_external_link/remove.php
@@ -8,8 +8,8 @@
</p>
<div class="form-actions">
- <?= $this->url->link(t('Yes'), 'TaskExternalLink', 'remove', array('link_id' => $link['id'], 'task_id' => $task['id'], 'project_id' => $task['project_id']), true, 'btn btn-red') ?>
+ <?= $this->url->link(t('Yes'), 'TaskExternalLinkController', 'remove', array('link_id' => $link['id'], 'task_id' => $task['id'], 'project_id' => $task['project_id']), true, 'btn btn-red') ?>
<?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'TaskExternalLink', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'close-popover') ?>
+ <?= $this->url->link(t('cancel'), 'TaskExternalLinkController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'close-popover') ?>
</div>
-</div> \ No newline at end of file
+</div>
diff --git a/app/Template/task_external_link/table.php b/app/Template/task_external_link/table.php
index 1f32f4dd..56ef0363 100644
--- a/app/Template/task_external_link/table.php
+++ b/app/Template/task_external_link/table.php
@@ -6,7 +6,7 @@
<th class="column-10"><?= t('Dependency') ?></th>
<th class="column-15"><?= t('Creator') ?></th>
<th class="column-15"><?= t('Date') ?></th>
- <?php if ($this->user->hasProjectAccess('TaskExternalLink', 'edit', $task['project_id'])): ?>
+ <?php if ($this->user->hasProjectAccess('TaskExternalLinkController', 'edit', $task['project_id'])): ?>
<th class="column-5"><?= t('Action') ?></th>
<?php endif ?>
</tr>
@@ -27,13 +27,13 @@
<td>
<?= $this->dt->date($link['date_creation']) ?>
</td>
- <?php if ($this->user->hasProjectAccess('TaskExternalLink', 'edit', $task['project_id'])): ?>
+ <?php if ($this->user->hasProjectAccess('TaskExternalLinkController', 'edit', $task['project_id'])): ?>
<td>
<div class="dropdown">
<a href="#" class="dropdown-menu dropdown-menu-link-icon"><i class="fa fa-cog fa-fw"></i><i class="fa fa-caret-down"></i></a>
<ul>
- <li><?= $this->url->link(t('Edit'), 'TaskExternalLink', 'edit', array('link_id' => $link['id'], 'task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?></li>
- <li><?= $this->url->link(t('Remove'), 'TaskExternalLink', 'confirm', array('link_id' => $link['id'], 'task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?></li>
+ <li><?= $this->url->link(t('Edit'), 'TaskExternalLinkController', 'edit', array('link_id' => $link['id'], 'task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?></li>
+ <li><?= $this->url->link(t('Remove'), 'TaskExternalLinkController', 'confirm', array('link_id' => $link['id'], 'task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?></li>
</ul>
</div>
</td>
diff --git a/app/Template/task_file/create.php b/app/Template/task_file/create.php
index f03ce8dc..e05cf829 100644
--- a/app/Template/task_file/create.php
+++ b/app/Template/task_file/create.php
@@ -4,7 +4,7 @@
<div id="file-done" style="display:none">
<p class="alert alert-success">
<?= t('All files have been uploaded successfully.') ?>
- <?= $this->url->link(t('View uploaded files'), 'task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>
+ <?= $this->url->link(t('View uploaded files'), 'TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>
</p>
</div>
@@ -18,7 +18,7 @@
<div
id="file-dropzone"
data-max-size="<?= $max_size ?>"
- data-url="<?= $this->url->href('TaskFile', 'save', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>">
+ data-url="<?= $this->url->href('TaskFileController', 'save', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>">
<div id="file-dropzone-inner">
<?= t('Drag and drop your files here') ?> <?= t('or') ?> <a href="#" id="file-browser"><?= t('choose files') ?></a>
</div>
@@ -27,7 +27,7 @@
<input type="file" name="files[]" multiple style="display:none" id="file-form-element">
<div class="form-actions">
- <input type="submit" value="<?= t('Save') ?>" class="btn btn-blue" id="file-upload-button" disabled>
+ <input type="submit" value="<?= t('Upload files') ?>" class="btn btn-blue" id="file-upload-button" disabled>
<?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'close-popover') ?>
+ <?= $this->url->link(t('cancel'), 'TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'close-popover') ?>
</div>
diff --git a/app/Template/task_file/files.php b/app/Template/task_file/files.php
index 5603014e..7ca59b1c 100644
--- a/app/Template/task_file/files.php
+++ b/app/Template/task_file/files.php
@@ -16,17 +16,17 @@
<?php if ($this->file->getPreviewType($file['name']) !== null): ?>
<li>
<i class="fa fa-eye fa-fw"></i>
- <?= $this->url->link(t('View file'), 'FileViewer', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'file_id' => $file['id']), false, 'popover') ?>
+ <?= $this->url->link(t('View file'), 'FileViewerController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'file_id' => $file['id']), false, 'popover') ?>
</li>
<?php endif ?>
<li>
<i class="fa fa-download fa-fw"></i>
- <?= $this->url->link(t('Download'), 'FileViewer', 'download', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'file_id' => $file['id'])) ?>
+ <?= $this->url->link(t('Download'), 'FileViewerController', 'download', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'file_id' => $file['id'])) ?>
</li>
- <?php if ($this->user->hasProjectAccess('TaskFile', 'remove', $task['project_id'])): ?>
+ <?php if ($this->user->hasProjectAccess('TaskFileController', 'remove', $task['project_id'])): ?>
<li>
<i class="fa fa-trash fa-fw"></i>
- <?= $this->url->link(t('Remove'), 'TaskFile', 'confirm', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'file_id' => $file['id']), false, 'popover') ?>
+ <?= $this->url->link(t('Remove'), 'TaskFileController', 'confirm', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'file_id' => $file['id']), false, 'popover') ?>
</li>
<?php endif ?>
</ul>
@@ -44,4 +44,4 @@
</tr>
<?php endforeach ?>
</table>
-<?php endif ?> \ No newline at end of file
+<?php endif ?>
diff --git a/app/Template/task_file/images.php b/app/Template/task_file/images.php
index 55c098cb..81c33151 100644
--- a/app/Template/task_file/images.php
+++ b/app/Template/task_file/images.php
@@ -2,7 +2,7 @@
<div class="file-thumbnails">
<?php foreach ($images as $file): ?>
<div class="file-thumbnail">
- <a href="<?= $this->url->href('FileViewer', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'file_id' => $file['id'])) ?>" class="popover"><img src="<?= $this->url->href('FileViewer', 'thumbnail', array('file_id' => $file['id'], 'project_id' => $task['project_id'], 'task_id' => $file['task_id'])) ?>" title="<?= $this->text->e($file['name']) ?>" alt="<?= $this->text->e($file['name']) ?>"></a>
+ <a href="<?= $this->url->href('FileViewerController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'file_id' => $file['id'])) ?>" class="popover"><img src="<?= $this->url->href('FileViewerController', 'thumbnail', array('file_id' => $file['id'], 'project_id' => $task['project_id'], 'task_id' => $file['task_id'])) ?>" title="<?= $this->text->e($file['name']) ?>" alt="<?= $this->text->e($file['name']) ?>"></a>
<div class="file-thumbnail-content">
<div class="file-thumbnail-title">
<div class="dropdown">
@@ -10,12 +10,12 @@
<ul>
<li>
<i class="fa fa-download fa-fw"></i>
- <?= $this->url->link(t('Download'), 'FileViewer', 'download', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'file_id' => $file['id'])) ?>
+ <?= $this->url->link(t('Download'), 'FileViewerController', 'download', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'file_id' => $file['id'])) ?>
</li>
- <?php if ($this->user->hasProjectAccess('TaskFile', 'remove', $task['project_id'])): ?>
+ <?php if ($this->user->hasProjectAccess('TaskFileController', 'remove', $task['project_id'])): ?>
<li>
<i class="fa fa-trash fa-fw"></i>
- <?= $this->url->link(t('Remove'), 'TaskFile', 'confirm', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'file_id' => $file['id']), false, 'popover') ?>
+ <?= $this->url->link(t('Remove'), 'TaskFileController', 'confirm', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'file_id' => $file['id']), false, 'popover') ?>
</li>
<?php endif ?>
</ul>
@@ -31,4 +31,4 @@
</div>
<?php endforeach ?>
</div>
-<?php endif ?> \ No newline at end of file
+<?php endif ?>
diff --git a/app/Template/task_file/remove.php b/app/Template/task_file/remove.php
index fe601f6f..42894f05 100644
--- a/app/Template/task_file/remove.php
+++ b/app/Template/task_file/remove.php
@@ -8,8 +8,8 @@
</p>
<div class="form-actions">
- <?= $this->url->link(t('Yes'), 'TaskFile', 'remove', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'file_id' => $file['id']), true, 'btn btn-red') ?>
+ <?= $this->url->link(t('Yes'), 'TaskFileController', 'remove', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'file_id' => $file['id']), true, 'btn btn-red') ?>
<?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'close-popover') ?>
+ <?= $this->url->link(t('cancel'), 'TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'close-popover') ?>
</div>
-</div> \ No newline at end of file
+</div>
diff --git a/app/Template/task_file/screenshot.php b/app/Template/task_file/screenshot.php
index 2880478d..6300159f 100644
--- a/app/Template/task_file/screenshot.php
+++ b/app/Template/task_file/screenshot.php
@@ -6,14 +6,14 @@
<p id="screenshot-inner"><?= t('Take a screenshot and press CTRL+V or ⌘+V to paste here.') ?></p>
</div>
-<form class="popover-form" action="<?= $this->url->href('TaskFile', 'screenshot', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>" method="post">
+<form class="popover-form" action="<?= $this->url->href('TaskFileController', 'screenshot', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>" method="post">
<input type="hidden" name="screenshot"/>
<?= $this->form->csrf() ?>
<div class="form-actions">
<button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
<?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'close-popover') ?>
+ <?= $this->url->link(t('cancel'), 'TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'close-popover') ?>
</div>
</form>
-<p class="alert alert-info"><?= t('This feature does not work with all browsers.') ?></p> \ No newline at end of file
+<p class="alert alert-info"><?= t('This feature does not work with all browsers.') ?></p>
diff --git a/app/Template/gantt/project.php b/app/Template/task_gantt/show.php
index e6c8592f..c5d338fb 100644
--- a/app/Template/gantt/project.php
+++ b/app/Template/task_gantt/show.php
@@ -1,18 +1,18 @@
<section id="main">
- <?= $this->projectHeader->render($project, 'Gantt', 'project') ?>
+ <?= $this->projectHeader->render($project, 'TaskGanttController', 'show') ?>
<div class="menu-inline">
<ul>
<li <?= $sorting === 'board' ? 'class="active"' : '' ?>>
<i class="fa fa-sort-numeric-asc fa-fw"></i>
- <?= $this->url->link(t('Sort by position'), 'gantt', 'project', array('project_id' => $project['id'], 'sorting' => 'board')) ?>
+ <?= $this->url->link(t('Sort by position'), 'TaskGanttController', 'show', array('project_id' => $project['id'], 'sorting' => 'board')) ?>
</li>
<li <?= $sorting === 'date' ? 'class="active"' : '' ?>>
<i class="fa fa-sort-amount-asc fa-fw"></i>
- <?= $this->url->link(t('Sort by date'), 'gantt', 'project', array('project_id' => $project['id'], 'sorting' => 'date')) ?>
+ <?= $this->url->link(t('Sort by date'), 'TaskGanttController', 'show', array('project_id' => $project['id'], 'sorting' => 'date')) ?>
</li>
<li>
<i class="fa fa-plus fa-fw"></i>
- <?= $this->url->link(t('Add task'), 'gantt', 'task', array('project_id' => $project['id']), false, 'popover') ?>
+ <?= $this->url->link(t('Add task'), 'TaskGanttCreationController', 'show', array('project_id' => $project['id']), false, 'popover') ?>
</li>
</ul>
</div>
@@ -21,7 +21,7 @@
<div
id="gantt-chart"
data-records='<?= json_encode($tasks, JSON_HEX_APOS) ?>'
- data-save-url="<?= $this->url->href('gantt', 'saveTaskDate', array('project_id' => $project['id'])) ?>"
+ data-save-url="<?= $this->url->href('TaskGanttController', 'save', array('project_id' => $project['id'])) ?>"
data-label-start-date="<?= t('Start date:') ?>"
data-label-end-date="<?= t('Due date:') ?>"
data-label-assignee="<?= t('Assignee:') ?>"
@@ -31,4 +31,4 @@
<?php else: ?>
<p class="alert"><?= t('There is no task in your project.') ?></p>
<?php endif ?>
-</section> \ No newline at end of file
+</section>
diff --git a/app/Template/gantt/task_creation.php b/app/Template/task_gantt_creation/show.php
index 448a808d..683bc8c8 100644
--- a/app/Template/gantt/task_creation.php
+++ b/app/Template/task_gantt_creation/show.php
@@ -1,7 +1,7 @@
<div class="page-header">
<h2><?= t('New task') ?></h2>
</div>
-<form method="post" action="<?= $this->url->href('gantt', 'saveTask', array('project_id' => $values['project_id'])) ?>" autocomplete="off">
+<form method="post" action="<?= $this->url->href('TaskGanttCreationController', 'save', array('project_id' => $values['project_id'])) ?>" autocomplete="off">
<?= $this->form->csrf() ?>
<?= $this->form->hidden('project_id', $values) ?>
<?= $this->form->hidden('column_id', $values) ?>
@@ -30,6 +30,6 @@
<div class="form-actions">
<button type="submit" class="btn btn-blue" tabindex="15"><?= t('Save') ?></button>
<?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'board', 'show', array('project_id' => $values['project_id']), false, 'close-popover') ?>
+ <?= $this->url->link(t('cancel'), 'TaskGanttController', 'show', array('project_id' => $values['project_id']), false, 'close-popover') ?>
</div>
</form>
diff --git a/app/Template/task_import/step1.php b/app/Template/task_import/show.php
index abb43505..cc6a7b3a 100644
--- a/app/Template/task_import/step1.php
+++ b/app/Template/task_import/show.php
@@ -1,7 +1,7 @@
<div class="page-header">
<h2><?= t('Tasks Importation') ?></h2>
</div>
-<form action="<?= $this->url->href('taskImport', 'step2', array('project_id' => $project['id'])) ?>" method="post" enctype="multipart/form-data">
+<form action="<?= $this->url->href('TaskImportController', 'save', array('project_id' => $project['id'])) ?>" method="post" enctype="multipart/form-data">
<?= $this->form->csrf() ?>
<?= $this->form->label(t('Delimiter'), 'delimiter') ?>
@@ -31,4 +31,4 @@
<li><?= t('The due date must use the ISO format: YYYY-MM-DD') ?></li>
</ul>
</div>
-<p><i class="fa fa-download fa-fw"></i><?= $this->url->link(t('Download CSV template'), 'taskImport', 'template', array('project_id' => $project['id'])) ?></p> \ No newline at end of file
+<p><i class="fa fa-download fa-fw"></i><?= $this->url->link(t('Download CSV template'), 'TaskImportController', 'template', array('project_id' => $project['id'])) ?></p>
diff --git a/app/Template/task_import/sidebar.php b/app/Template/task_import/sidebar.php
new file mode 100644
index 00000000..4cd92af8
--- /dev/null
+++ b/app/Template/task_import/sidebar.php
@@ -0,0 +1,9 @@
+<div class="sidebar">
+ <h2><?= t('Imports') ?></h2>
+ <ul>
+ <li <?= $this->app->checkMenuSelection('TaskImportController', 'show') ?>>
+ <?= $this->url->link(t('Tasks').' (CSV)', 'TaskImportController', 'show', array('project_id' => $project['id'])) ?>
+ </li>
+ <?= $this->hook->render('template:task-import:sidebar') ?>
+ </ul>
+</div>
diff --git a/app/Template/task_internal_link/create.php b/app/Template/task_internal_link/create.php
index 94dcdd66..fed29605 100644
--- a/app/Template/task_internal_link/create.php
+++ b/app/Template/task_internal_link/create.php
@@ -2,7 +2,7 @@
<h2><?= t('Add a new link') ?></h2>
</div>
-<form class="popover-form" action="<?= $this->url->href('TaskInternalLink', 'save', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>" method="post" autocomplete="off">
+<form class="popover-form" action="<?= $this->url->href('TaskInternalLinkController', 'save', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>" method="post" autocomplete="off">
<?= $this->form->csrf() ?>
<?= $this->form->hidden('task_id', array('task_id' => $task['id'])) ?>
@@ -21,13 +21,13 @@
'placeholder="'.t('Start to type task title...').'"',
'title="'.t('Start to type task title...').'"',
'data-dst-field="opposite_task_id"',
- 'data-search-url="'.$this->url->href('TaskHelper', 'autocomplete', array('exclude_task_id' => $task['id'])).'"',
+ 'data-search-url="'.$this->url->href('TaskAjaxController', 'autocomplete', array('exclude_task_id' => $task['id'])).'"',
),
'autocomplete') ?>
<div class="form-actions">
<button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
<?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'close-popover') ?>
+ <?= $this->url->link(t('cancel'), 'TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'close-popover') ?>
</div>
-</form> \ No newline at end of file
+</form>
diff --git a/app/Template/task_internal_link/edit.php b/app/Template/task_internal_link/edit.php
index 03622df7..f4df57bd 100644
--- a/app/Template/task_internal_link/edit.php
+++ b/app/Template/task_internal_link/edit.php
@@ -2,7 +2,7 @@
<h2><?= t('Edit link') ?></h2>
</div>
-<form action="<?= $this->url->href('TaskInternalLink', 'update', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'link_id' => $task_link['id'])) ?>" method="post" autocomplete="off">
+<form action="<?= $this->url->href('TaskInternalLinkController', 'update', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'link_id' => $task_link['id'])) ?>" method="post" autocomplete="off">
<?= $this->form->csrf() ?>
<?= $this->form->hidden('id', $values) ?>
@@ -22,13 +22,13 @@
'placeholder="'.t('Start to type task title...').'"',
'title="'.t('Start to type task title...').'"',
'data-dst-field="opposite_task_id"',
- 'data-search-url="'.$this->url->href('TaskHelper', 'autocomplete', array('exclude_task_id' => $task['id'])).'"',
+ 'data-search-url="'.$this->url->href('TaskAjaxController', 'autocomplete', array('exclude_task_id' => $task['id'])).'"',
),
'autocomplete') ?>
<div class="form-actions">
<button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
<?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'close-popover') ?>
+ <?= $this->url->link(t('cancel'), 'TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'close-popover') ?>
</div>
-</form> \ No newline at end of file
+</form>
diff --git a/app/Template/task_internal_link/remove.php b/app/Template/task_internal_link/remove.php
index 82156ece..966ad116 100644
--- a/app/Template/task_internal_link/remove.php
+++ b/app/Template/task_internal_link/remove.php
@@ -8,8 +8,8 @@
</p>
<div class="form-actions">
- <?= $this->url->link(t('Yes'), 'TaskInternalLink', 'remove', array('link_id' => $link['id'], 'task_id' => $task['id'], 'project_id' => $task['project_id']), true, 'btn btn-red') ?>
+ <?= $this->url->link(t('Yes'), 'TaskInternalLinkController', 'remove', array('link_id' => $link['id'], 'task_id' => $task['id'], 'project_id' => $task['project_id']), true, 'btn btn-red') ?>
<?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'close-popover') ?>
+ <?= $this->url->link(t('cancel'), 'TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'close-popover') ?>
</div>
-</div> \ No newline at end of file
+</div>
diff --git a/app/Template/task_internal_link/table.php b/app/Template/task_internal_link/table.php
index 8f25b29b..424d4791 100644
--- a/app/Template/task_internal_link/table.php
+++ b/app/Template/task_internal_link/table.php
@@ -24,7 +24,7 @@
<?php if ($is_public): ?>
<?= $this->url->link(
$this->text->e('#'.$link['task_id'].' '.$link['title']),
- 'task',
+ 'TaskViewController',
'readonly',
array('task_id' => $link['task_id'], 'token' => $project['token']),
false,
@@ -33,7 +33,7 @@
<?php else: ?>
<?= $this->url->link(
$this->text->e('#'.$link['task_id'].' '.$link['title']),
- 'task',
+ 'TaskViewController',
'show',
array('task_id' => $link['task_id'], 'project_id' => $link['project_id']),
false,
@@ -52,7 +52,7 @@
<td>
<?php if (! empty($link['task_assignee_username'])): ?>
<?php if ($editable): ?>
- <?= $this->url->link($this->text->e($link['task_assignee_name'] ?: $link['task_assignee_username']), 'user', 'show', array('user_id' => $link['task_assignee_id'])) ?>
+ <?= $this->url->link($this->text->e($link['task_assignee_name'] ?: $link['task_assignee_username']), 'UserViewController', 'show', array('user_id' => $link['task_assignee_id'])) ?>
<?php else: ?>
<?= $this->text->e($link['task_assignee_name'] ?: $link['task_assignee_username']) ?>
<?php endif ?>
@@ -72,8 +72,8 @@
<div class="dropdown">
<a href="#" class="dropdown-menu dropdown-menu-link-icon"><i class="fa fa-cog fa-fw"></i><i class="fa fa-caret-down"></i></a>
<ul>
- <li><?= $this->url->link(t('Edit'), 'TaskInternalLink', 'edit', array('link_id' => $link['id'], 'task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?></li>
- <li><?= $this->url->link(t('Remove'), 'TaskInternalLink', 'confirm', array('link_id' => $link['id'], 'task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?></li>
+ <li><?= $this->url->link(t('Edit'), 'TaskInternalLinkController', 'edit', array('link_id' => $link['id'], 'task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?></li>
+ <li><?= $this->url->link(t('Remove'), 'TaskInternalLinkController', 'confirm', array('link_id' => $link['id'], 'task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?></li>
</ul>
</div>
</td>
@@ -82,4 +82,4 @@
<?php endforeach ?>
<?php endforeach ?>
</table>
-<?php endif ?> \ No newline at end of file
+<?php endif ?>
diff --git a/app/Template/listing/show.php b/app/Template/task_list/show.php
index 98b9528a..bb95b6a3 100644
--- a/app/Template/listing/show.php
+++ b/app/Template/task_list/show.php
@@ -1,5 +1,5 @@
<section id="main">
- <?= $this->projectHeader->render($project, 'Listing', 'show') ?>
+ <?= $this->projectHeader->render($project, 'TaskListController', 'show') ?>
<?php if ($paginator->isEmpty()): ?>
<p class="alert"><?= t('No tasks found.') ?></p>
@@ -18,7 +18,7 @@
<?php foreach ($paginator->getCollection() as $task): ?>
<tr>
<td class="task-table color-<?= $task['color_id'] ?>">
- <?php if ($this->user->hasProjectAccess('taskmodification', 'edit', $task['project_id'])): ?>
+ <?php if ($this->user->hasProjectAccess('TaskModificationController', 'edit', $task['project_id'])): ?>
<?= $this->render('task/dropdown', array('task' => $task)) ?>
<?php else: ?>
#<?= $task['id'] ?>
@@ -34,7 +34,7 @@
<?= $this->text->e($task['category_name']) ?>
</td>
<td>
- <?= $this->url->link($this->text->e($task['title']), 'task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, '', t('View this task')) ?>
+ <?= $this->url->link($this->text->e($task['title']), 'TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, '', t('View this task')) ?>
</td>
<td>
<?php if ($task['assignee_username']): ?>
@@ -47,7 +47,7 @@
<?= $this->dt->date($task['date_due']) ?>
</td>
<td>
- <?php if ($task['is_active'] == \Kanboard\Model\Task::STATUS_OPEN): ?>
+ <?php if ($task['is_active'] == \Kanboard\Model\TaskModel::STATUS_OPEN): ?>
<?= t('Open') ?>
<?php else: ?>
<?= t('Closed') ?>
@@ -59,4 +59,4 @@
<?= $paginator ?>
<?php endif ?>
-</section> \ No newline at end of file
+</section>
diff --git a/app/Template/task_modification/edit_description.php b/app/Template/task_modification/edit_description.php
index 8c149f4f..339ed036 100644
--- a/app/Template/task_modification/edit_description.php
+++ b/app/Template/task_modification/edit_description.php
@@ -2,7 +2,7 @@
<h2><?= t('Edit the description') ?></h2>
</div>
-<form class="popover-form" method="post" action="<?= $this->url->href('taskmodification', 'updateDescription', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>" autocomplete="off">
+<form class="popover-form" method="post" action="<?= $this->url->href('TaskModificationController', 'updateDescription', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>" autocomplete="off">
<?= $this->form->csrf() ?>
<?= $this->form->hidden('id', $values) ?>
@@ -14,7 +14,7 @@
array(
'autofocus',
'placeholder="'.t('Leave a description').'"',
- 'data-mention-search-url="'.$this->url->href('UserHelper', 'mention', array('project_id' => $task['project_id'])).'"'
+ 'data-mention-search-url="'.$this->url->href('UserAjaxController', 'mention', array('project_id' => $task['project_id'])).'"'
),
'markdown-editor'
) ?>
@@ -22,6 +22,6 @@
<div class="form-actions">
<button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
<?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'close-popover') ?>
+ <?= $this->url->link(t('cancel'), 'TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'close-popover') ?>
</div>
</form>
diff --git a/app/Template/task_modification/edit_task.php b/app/Template/task_modification/edit_task.php
index 5ddec5ea..0707fd9a 100644
--- a/app/Template/task_modification/edit_task.php
+++ b/app/Template/task_modification/edit_task.php
@@ -1,8 +1,7 @@
<div class="page-header">
<h2><?= t('Edit a task') ?></h2>
</div>
-<form class="popover-form" method="post" action="<?= $this->url->href('taskmodification', 'update', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>" autocomplete="off">
-
+<form class="popover-form" method="post" action="<?= $this->url->href('TaskModificationController', 'update', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>" autocomplete="off">
<?= $this->form->csrf() ?>
<?= $this->form->hidden('id', $values) ?>
<?= $this->form->hidden('project_id', $values) ?>
@@ -34,6 +33,6 @@
<div class="form-actions">
<button type="submit" class="btn btn-blue" tabindex="15"><?= t('Save') ?></button>
<?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'close-popover') ?>
+ <?= $this->url->link(t('cancel'), 'TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'close-popover') ?>
</div>
</form>
diff --git a/app/Template/board/popover_assignee.php b/app/Template/task_popover/change_assignee.php
index 87e16816..02f3e198 100644
--- a/app/Template/board/popover_assignee.php
+++ b/app/Template/task_popover/change_assignee.php
@@ -2,7 +2,7 @@
<div class="page-header">
<h2><?= t('Change assignee for the task "%s"', $values['title']) ?></h2>
</div>
- <form class="popover-form" method="post" action="<?= $this->url->href('BoardPopover', 'updateAssignee', array('task_id' => $values['id'], 'project_id' => $project['id'])) ?>">
+ <form class="popover-form" method="post" action="<?= $this->url->href('TaskPopoverController', 'updateAssignee', array('task_id' => $values['id'], 'project_id' => $project['id'])) ?>">
<?= $this->form->csrf() ?>
@@ -14,7 +14,7 @@
<div class="form-actions">
<button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
<?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'board', 'show', array('project_id' => $project['id']), false, 'close-popover') ?>
+ <?= $this->url->link(t('cancel'), 'BoardViewController', 'show', array('project_id' => $project['id']), false, 'close-popover') ?>
</div>
</form>
-</section> \ No newline at end of file
+</section>
diff --git a/app/Template/board/popover_category.php b/app/Template/task_popover/change_category.php
index e3794760..eb6a373d 100644
--- a/app/Template/board/popover_category.php
+++ b/app/Template/task_popover/change_category.php
@@ -2,7 +2,7 @@
<div class="page-header">
<h2><?= t('Change category for the task "%s"', $values['title']) ?></h2>
</div>
- <form class="popover-form" method="post" action="<?= $this->url->href('BoardPopover', 'updateCategory', array('task_id' => $values['id'], 'project_id' => $project['id'])) ?>">
+ <form class="popover-form" method="post" action="<?= $this->url->href('TaskPopoverController', 'updateCategory', array('task_id' => $values['id'], 'project_id' => $project['id'])) ?>">
<?= $this->form->csrf() ?>
@@ -14,7 +14,7 @@
<div class="form-actions">
<button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
<?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'board', 'show', array('project_id' => $project['id']), false, 'close-popover') ?>
+ <?= $this->url->link(t('cancel'), 'BoardViewController', 'show', array('project_id' => $project['id']), false, 'close-popover') ?>
</div>
</form>
-</section> \ No newline at end of file
+</section>
diff --git a/app/Template/task_recurrence/edit.php b/app/Template/task_recurrence/edit.php
index 0f5d611a..09d14826 100644
--- a/app/Template/task_recurrence/edit.php
+++ b/app/Template/task_recurrence/edit.php
@@ -2,7 +2,7 @@
<h2><?= t('Edit recurrence') ?></h2>
</div>
-<?php if ($task['recurrence_status'] != \Kanboard\Model\Task::RECURRING_STATUS_NONE): ?>
+<?php if ($task['recurrence_status'] != \Kanboard\Model\TaskModel::RECURRING_STATUS_NONE): ?>
<div class="listing">
<?= $this->render('task_recurrence/info', array(
'task' => $task,
@@ -13,9 +13,9 @@
</div>
<?php endif ?>
-<?php if ($task['recurrence_status'] != \Kanboard\Model\Task::RECURRING_STATUS_PROCESSED): ?>
+<?php if ($task['recurrence_status'] != \Kanboard\Model\TaskModel::RECURRING_STATUS_PROCESSED): ?>
- <form class="popover-form" method="post" action="<?= $this->url->href('TaskRecurrence', 'update', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>" autocomplete="off">
+ <form class="popover-form" method="post" action="<?= $this->url->href('TaskRecurrenceController', 'update', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>" autocomplete="off">
<?= $this->form->csrf() ?>
@@ -40,8 +40,8 @@
<div class="form-actions">
<button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
<?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'close-popover') ?>
+ <?= $this->url->link(t('cancel'), 'TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'close-popover') ?>
</div>
</form>
-<?php endif ?> \ No newline at end of file
+<?php endif ?>
diff --git a/app/Template/task_recurrence/info.php b/app/Template/task_recurrence/info.php
index 1a6574df..04d58c7f 100644
--- a/app/Template/task_recurrence/info.php
+++ b/app/Template/task_recurrence/info.php
@@ -1,7 +1,7 @@
<ul>
- <?php if ($task['recurrence_status'] == \Kanboard\Model\Task::RECURRING_STATUS_PENDING): ?>
+ <?php if ($task['recurrence_status'] == \Kanboard\Model\TaskModel::RECURRING_STATUS_PENDING): ?>
<li><?= t('Recurrent task is scheduled to be generated') ?></li>
- <?php elseif ($task['recurrence_status'] == \Kanboard\Model\Task::RECURRING_STATUS_PROCESSED): ?>
+ <?php elseif ($task['recurrence_status'] == \Kanboard\Model\TaskModel::RECURRING_STATUS_PROCESSED): ?>
<li><?= t('Recurrent task has been generated:') ?>
<ul>
<li>
@@ -24,14 +24,14 @@
<?php if ($task['recurrence_parent']): ?>
<li>
<?= t('This task has been created by: ') ?>
- <?= $this->url->link('#'.$task['recurrence_parent'], 'task', 'show', array('task_id' => $task['recurrence_parent'], 'project_id' => $task['project_id'])) ?>
+ <?= $this->url->link('#'.$task['recurrence_parent'], 'TaskViewController', 'show', array('task_id' => $task['recurrence_parent'], 'project_id' => $task['project_id'])) ?>
</li>
<?php endif ?>
<?php if ($task['recurrence_child']): ?>
<li>
<?= t('This task has created this child task: ') ?>
- <?= $this->url->link('#'.$task['recurrence_child'], 'task', 'show', array('task_id' => $task['recurrence_child'], 'project_id' => $task['project_id'])) ?>
+ <?= $this->url->link('#'.$task['recurrence_child'], 'TaskViewController', 'show', array('task_id' => $task['recurrence_child'], 'project_id' => $task['project_id'])) ?>
</li>
<?php endif ?>
<?php endif ?>
-</ul> \ No newline at end of file
+</ul>
diff --git a/app/Template/task_status/close.php b/app/Template/task_status/close.php
index 7d200544..2d7b0ce5 100644
--- a/app/Template/task_status/close.php
+++ b/app/Template/task_status/close.php
@@ -8,8 +8,8 @@
</p>
<div class="form-actions">
- <?= $this->url->link(t('Yes'), 'taskstatus', 'close', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'confirmation' => 'yes'), true, 'btn btn-red popover-link') ?>
+ <?= $this->url->link(t('Yes'), 'TaskStatusController', 'close', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'confirmation' => 'yes'), true, 'btn btn-red popover-link') ?>
<?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'close-popover') ?>
+ <?= $this->url->link(t('cancel'), 'TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'close-popover') ?>
</div>
-</div> \ No newline at end of file
+</div>
diff --git a/app/Template/task_status/open.php b/app/Template/task_status/open.php
index 5d19bfbe..242b5db5 100644
--- a/app/Template/task_status/open.php
+++ b/app/Template/task_status/open.php
@@ -8,8 +8,8 @@
</p>
<div class="form-actions">
- <?= $this->url->link(t('Yes'), 'taskstatus', 'open', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'confirmation' => 'yes'), true, 'btn btn-red popover-link') ?>
+ <?= $this->url->link(t('Yes'), 'TaskStatusController', 'open', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'confirmation' => 'yes'), true, 'btn btn-red popover-link') ?>
<?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'close-popover') ?>
+ <?= $this->url->link(t('cancel'), 'TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'close-popover') ?>
</div>
-</div> \ No newline at end of file
+</div>
diff --git a/app/Template/task_suppression/remove.php b/app/Template/task_suppression/remove.php
new file mode 100644
index 00000000..5d0f7720
--- /dev/null
+++ b/app/Template/task_suppression/remove.php
@@ -0,0 +1,15 @@
+<div class="page-header">
+ <h2><?= t('Remove a task') ?></h2>
+</div>
+
+<div class="confirm">
+ <p class="alert alert-info">
+ <?= t('Do you really want to remove this task: "%s"?', $this->text->e($task['title'])) ?>
+ </p>
+
+ <div class="form-actions">
+ <?= $this->url->link(t('Yes'), 'TaskSuppressionController', 'remove', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'redirect' => $redirect), true, 'btn btn-red popover-link') ?>
+ <?= t('or') ?>
+ <?= $this->url->link(t('cancel'), 'TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'close-popover') ?>
+ </div>
+</div>
diff --git a/app/Template/twofactor/check.php b/app/Template/twofactor/check.php
index b0cb4825..06801d50 100644
--- a/app/Template/twofactor/check.php
+++ b/app/Template/twofactor/check.php
@@ -1,4 +1,4 @@
-<form method="post" action="<?= $this->url->href('twofactor', 'check', array('user_id' => $this->user->getId())) ?>" autocomplete="off">
+<form method="post" action="<?= $this->url->href('TwoFactorController', 'check', array('user_id' => $this->user->getId())) ?>" autocomplete="off">
<?= $this->form->csrf() ?>
<?= $this->form->label(t('Code'), 'code') ?>
@@ -7,4 +7,4 @@
<div class="form-actions">
<button type="submit" class="btn btn-blue"><?= t('Check my code') ?></button>
</div>
-</form> \ No newline at end of file
+</form>
diff --git a/app/Template/twofactor/disable.php b/app/Template/twofactor/disable.php
index 36be4ef9..bc419181 100644
--- a/app/Template/twofactor/disable.php
+++ b/app/Template/twofactor/disable.php
@@ -8,7 +8,7 @@
</p>
<div class="form-actions">
- <?= $this->url->link(t('Yes'), 'twofactor', 'disable', array('user_id' => $user['id'], 'disable' => 'yes'), true, 'btn btn-red') ?>
- <?= t('or') ?> <?= $this->url->link(t('cancel'), 'user', 'show', array('user_id' => $user['id'])) ?>
+ <?= $this->url->link(t('Yes'), 'TwoFactorController', 'disable', array('user_id' => $user['id'], 'disable' => 'yes'), true, 'btn btn-red') ?>
+ <?= t('or') ?> <?= $this->url->link(t('cancel'), 'UserViewController', 'show', array('user_id' => $user['id'])) ?>
</div>
-</div> \ No newline at end of file
+</div>
diff --git a/app/Template/twofactor/index.php b/app/Template/twofactor/index.php
index 6de36514..1ed414ed 100644
--- a/app/Template/twofactor/index.php
+++ b/app/Template/twofactor/index.php
@@ -2,7 +2,7 @@
<h2><?= t('Two factor authentication') ?></h2>
</div>
-<form method="post" action="<?= $this->url->href('twofactor', $user['twofactor_activated'] == 1 ? 'deactivate' : 'show', array('user_id' => $user['id'])) ?>" autocomplete="off">
+<form method="post" action="<?= $this->url->href('TwoFactorController', $user['twofactor_activated'] == 1 ? 'deactivate' : 'show', array('user_id' => $user['id'])) ?>" autocomplete="off">
<?= $this->form->csrf() ?>
<p><?= t('Two-Factor Provider: ') ?><strong><?= $this->text->e($provider) ?></strong></p>
<div class="form-actions">
diff --git a/app/Template/twofactor/show.php b/app/Template/twofactor/show.php
index 59897e20..0aeef427 100644
--- a/app/Template/twofactor/show.php
+++ b/app/Template/twofactor/show.php
@@ -19,7 +19,7 @@
<?php endif ?>
<h3><?= t('Test your device') ?></h3>
-<form method="post" action="<?= $this->url->href('twofactor', 'test', array('user_id' => $user['id'])) ?>" autocomplete="off">
+<form method="post" action="<?= $this->url->href('TwoFactorController', 'test', array('user_id' => $user['id'])) ?>" autocomplete="off">
<?= $this->form->csrf() ?>
<?= $this->form->label(t('Code'), 'code') ?>
@@ -28,4 +28,4 @@
<div class="form-actions">
<button type="submit" class="btn btn-blue"><?= t('Check my code') ?></button>
</div>
-</form> \ No newline at end of file
+</form>
diff --git a/app/Template/user/create_local.php b/app/Template/user/create_local.php
deleted file mode 100644
index 7257456d..00000000
--- a/app/Template/user/create_local.php
+++ /dev/null
@@ -1,53 +0,0 @@
-<section id="main">
- <div class="page-header">
- <ul>
- <li><i class="fa fa-user fa-fw"></i><?= $this->url->link(t('All users'), 'user', 'index') ?></li>
- <li><i class="fa fa-plus fa-fw"></i><?= $this->url->link(t('New remote user'), 'user', 'create', array('remote' => 1)) ?></li>
- </ul>
- </div>
- <section>
- <form method="post" action="<?= $this->url->href('user', 'save') ?>" autocomplete="off">
-
- <?= $this->form->csrf() ?>
-
- <div class="form-column">
- <?= $this->form->label(t('Username'), 'username') ?>
- <?= $this->form->text('username', $values, $errors, array('autofocus', 'required', 'maxlength="50"')) ?>
-
- <?= $this->form->label(t('Name'), 'name') ?>
- <?= $this->form->text('name', $values, $errors) ?>
-
- <?= $this->form->label(t('Email'), 'email') ?>
- <?= $this->form->email('email', $values, $errors) ?>
-
- <?= $this->form->label(t('Password'), 'password') ?>
- <?= $this->form->password('password', $values, $errors, array('required')) ?>
-
- <?= $this->form->label(t('Confirmation'), 'confirmation') ?>
- <?= $this->form->password('confirmation', $values, $errors, array('required')) ?>
- </div>
-
- <div class="form-column">
- <?= $this->form->label(t('Add project member'), 'project_id') ?>
- <?= $this->form->select('project_id', $projects, $values, $errors) ?>
-
- <?= $this->form->label(t('Timezone'), 'timezone') ?>
- <?= $this->form->select('timezone', $timezones, $values, $errors) ?>
-
- <?= $this->form->label(t('Language'), 'language') ?>
- <?= $this->form->select('language', $languages, $values, $errors) ?>
-
- <?= $this->form->label(t('Role'), 'role') ?>
- <?= $this->form->select('role', $roles, $values, $errors) ?>
-
- <?= $this->form->checkbox('notifications_enabled', t('Enable email notifications'), 1, isset($values['notifications_enabled']) && $values['notifications_enabled'] == 1 ? true : false) ?>
- </div>
-
- <div class="form-actions">
- <button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
- <?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'user', 'index') ?>
- </div>
- </form>
- </section>
-</section>
diff --git a/app/Template/user/create_remote.php b/app/Template/user/create_remote.php
deleted file mode 100644
index 05acbba1..00000000
--- a/app/Template/user/create_remote.php
+++ /dev/null
@@ -1,55 +0,0 @@
-<section id="main">
- <div class="page-header">
- <ul>
- <li><i class="fa fa-user fa-fw"></i><?= $this->url->link(t('All users'), 'user', 'index') ?></li>
- <li><i class="fa fa-plus fa-fw"></i><?= $this->url->link(t('New local user'), 'user', 'create') ?></li>
- </ul>
- </div>
- <form method="post" action="<?= $this->url->href('user', 'save') ?>" autocomplete="off">
-
- <?= $this->form->csrf() ?>
- <?= $this->form->hidden('is_ldap_user', array('is_ldap_user' => 1)) ?>
-
- <div class="form-column">
- <?= $this->form->label(t('Username'), 'username') ?>
- <?= $this->form->text('username', $values, $errors, array('autofocus', 'required', 'maxlength="50"')) ?>
-
- <?= $this->form->label(t('Name'), 'name') ?>
- <?= $this->form->text('name', $values, $errors) ?>
-
- <?= $this->form->label(t('Email'), 'email') ?>
- <?= $this->form->email('email', $values, $errors) ?>
-
- <?= $this->hook->render('template:user:create-remote:form', array('values' => $values, 'errors' => $errors)) ?>
- </div>
-
- <div class="form-column">
- <?= $this->form->label(t('Add project member'), 'project_id') ?>
- <?= $this->form->select('project_id', $projects, $values, $errors) ?>
-
- <?= $this->form->label(t('Timezone'), 'timezone') ?>
- <?= $this->form->select('timezone', $timezones, $values, $errors) ?>
-
- <?= $this->form->label(t('Language'), 'language') ?>
- <?= $this->form->select('language', $languages, $values, $errors) ?>
-
- <?= $this->form->label(t('Role'), 'role') ?>
- <?= $this->form->select('role', $roles, $values, $errors) ?>
-
- <?= $this->form->checkbox('notifications_enabled', t('Enable email notifications'), 1, isset($values['notifications_enabled']) && $values['notifications_enabled'] == 1 ? true : false) ?>
- <?= $this->form->checkbox('disable_login_form', t('Disallow login form'), 1, isset($values['disable_login_form']) && $values['disable_login_form'] == 1) ?>
- </div>
-
- <div class="form-actions">
- <button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
- <?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'user', 'index') ?>
- </div>
- </form>
- <div class="alert alert-info">
- <ul>
- <li><?= t('Remote users do not store their password in Kanboard database, examples: LDAP, Google and Github accounts.') ?></li>
- <li><?= t('If you check the box "Disallow login form", credentials entered in the login form will be ignored.') ?></li>
- </ul>
- </div>
-</section> \ No newline at end of file
diff --git a/app/Template/user/dropdown.php b/app/Template/user/dropdown.php
deleted file mode 100644
index b74ed6e0..00000000
--- a/app/Template/user/dropdown.php
+++ /dev/null
@@ -1,27 +0,0 @@
-<div class="dropdown">
- <a href="#" class="dropdown-menu dropdown-menu-link-icon"><i class="fa fa-cog fa-fw"></i><i class="fa fa-caret-down"></i></a>
- <ul>
- <li>
- <i class="fa fa-user fa-fw"></i>
- <?= $this->url->link(t('View profile'), 'user', 'show', array('user_id' => $user['id'])) ?>
- </li>
- <?php if ($user['is_active'] == 1 && $this->user->hasAccess('UserStatus', 'disable') && ! $this->user->isCurrentUser($user['id'])): ?>
- <li>
- <i class="fa fa-times fa-fw"></i>
- <?= $this->url->link(t('Disable'), 'UserStatus', 'confirmDisable', array('user_id' => $user['id']), false, 'popover') ?>
- </li>
- <?php endif ?>
- <?php if ($user['is_active'] == 0 && $this->user->hasAccess('UserStatus', 'enable') && ! $this->user->isCurrentUser($user['id'])): ?>
- <li>
- <i class="fa fa-check-square-o fa-fw"></i>
- <?= $this->url->link(t('Enable'), 'UserStatus', 'confirmEnable', array('user_id' => $user['id']), false, 'popover') ?>
- </li>
- <?php endif ?>
- <?php if ($this->user->hasAccess('UserStatus', 'remove') && ! $this->user->isCurrentUser($user['id'])): ?>
- <li>
- <i class="fa fa-trash-o fa-fw"></i>
- <?= $this->url->link(t('Remove'), 'UserStatus', 'confirmRemove', array('user_id' => $user['id']), false, 'popover') ?>
- </li>
- <?php endif ?>
- </ul>
-</div> \ No newline at end of file
diff --git a/app/Template/user/layout.php b/app/Template/user/layout.php
deleted file mode 100644
index 3a0a5ba6..00000000
--- a/app/Template/user/layout.php
+++ /dev/null
@@ -1,19 +0,0 @@
-<section id="main">
- <div class="page-header">
- <?php if ($this->user->hasAccess('user', 'create')): ?>
- <ul>
- <li><i class="fa fa-user fa-fw"></i><?= $this->url->link(t('All users'), 'user', 'index') ?></li>
- <li><i class="fa fa-plus fa-fw"></i><?= $this->url->link(t('New local user'), 'user', 'create') ?></li>
- <li><i class="fa fa-plus fa-fw"></i><?= $this->url->link(t('New remote user'), 'user', 'create', array('remote' => 1)) ?></li>
- </ul>
- <?php endif ?>
- </div>
- <section class="sidebar-container" id="user-section">
-
- <?= $this->render('user/sidebar', array('user' => $user)) ?>
-
- <div class="sidebar-content">
- <?= $content_for_sublayout ?>
- </div>
- </section>
-</section> \ No newline at end of file
diff --git a/app/Template/user/share.php b/app/Template/user/share.php
deleted file mode 100644
index 56dc8675..00000000
--- a/app/Template/user/share.php
+++ /dev/null
@@ -1,18 +0,0 @@
-<div class="page-header">
- <h2><?= t('Public access') ?></h2>
-</div>
-
-<?php if (! empty($user['token'])): ?>
-
- <div class="listing">
- <ul class="no-bullet">
- <li><strong><i class="fa fa-rss-square"></i> <?= $this->url->link(t('RSS feed'), 'feed', 'user', array('token' => $user['token']), false, '', '', true) ?></strong></li>
- <li><strong><i class="fa fa-calendar"></i> <?= $this->url->link(t('iCal feed'), 'ical', 'user', array('token' => $user['token']), false, '', '', true) ?></strong></li>
- </ul>
- </div>
-
- <?= $this->url->link(t('Disable public access'), 'user', 'share', array('user_id' => $user['id'], 'switch' => 'disable'), true, 'btn btn-red') ?>
-
-<?php else: ?>
- <?= $this->url->link(t('Enable public access'), 'user', 'share', array('user_id' => $user['id'], 'switch' => 'enable'), true, 'btn btn-blue') ?>
-<?php endif ?>
diff --git a/app/Template/user/sidebar.php b/app/Template/user/sidebar.php
deleted file mode 100644
index 5ea2e355..00000000
--- a/app/Template/user/sidebar.php
+++ /dev/null
@@ -1,83 +0,0 @@
-<div class="sidebar">
- <h2><?= t('Information') ?></h2>
- <ul>
- <?php if ($this->user->hasAccess('user', 'show')): ?>
- <li <?= $this->app->checkMenuSelection('user', 'show') ?>>
- <?= $this->url->link(t('Summary'), 'user', 'show', array('user_id' => $user['id'])) ?>
- </li>
- <?php endif ?>
- <?php if ($this->user->isAdmin()): ?>
- <li>
- <?= $this->url->link(t('User dashboard'), 'app', 'index', array('user_id' => $user['id'])) ?>
- </li>
- <?php endif ?>
- <?php if ($this->user->isAdmin() || $this->user->isCurrentUser($user['id'])): ?>
- <li <?= $this->app->checkMenuSelection('user', 'timesheet') ?>>
- <?= $this->url->link(t('Time tracking'), 'user', 'timesheet', array('user_id' => $user['id'])) ?>
- </li>
- <li <?= $this->app->checkMenuSelection('user', 'last') ?>>
- <?= $this->url->link(t('Last logins'), 'user', 'last', array('user_id' => $user['id'])) ?>
- </li>
- <li <?= $this->app->checkMenuSelection('user', 'sessions') ?>>
- <?= $this->url->link(t('Persistent connections'), 'user', 'sessions', array('user_id' => $user['id'])) ?>
- </li>
- <li <?= $this->app->checkMenuSelection('user', 'passwordReset') ?>>
- <?= $this->url->link(t('Password reset history'), 'user', 'passwordReset', array('user_id' => $user['id'])) ?>
- </li>
- <?php endif ?>
-
- <?= $this->hook->render('template:user:sidebar:information', array('user' => $user)) ?>
- </ul>
-
- <h2><?= t('Actions') ?></h2>
- <ul>
- <?php if ($this->user->isAdmin() || $this->user->isCurrentUser($user['id'])): ?>
-
- <?php if ($this->user->hasAccess('user', 'edit')): ?>
- <li <?= $this->app->checkMenuSelection('user', 'edit') ?>>
- <?= $this->url->link(t('Edit profile'), 'user', 'edit', array('user_id' => $user['id'])) ?>
- </li>
- <li <?= $this->app->checkMenuSelection('AvatarFile') ?>>
- <?= $this->url->link(t('Avatar'), 'AvatarFile', 'show', array('user_id' => $user['id'])) ?>
- </li>
- <?php endif ?>
-
- <?php if ($user['is_ldap_user'] == 0): ?>
- <li <?= $this->app->checkMenuSelection('user', 'password') ?>>
- <?= $this->url->link(t('Change password'), 'user', 'password', array('user_id' => $user['id'])) ?>
- </li>
- <?php endif ?>
-
- <?php if ($this->user->isCurrentUser($user['id'])): ?>
- <li <?= $this->app->checkMenuSelection('twofactor', 'index') ?>>
- <?= $this->url->link(t('Two factor authentication'), 'twofactor', 'index', array('user_id' => $user['id'])) ?>
- </li>
- <?php elseif ($this->user->hasAccess('twofactor', 'disable') && $user['twofactor_activated'] == 1): ?>
- <li <?= $this->app->checkMenuSelection('twofactor', 'disable') ?>>
- <?= $this->url->link(t('Two factor authentication'), 'twofactor', 'disable', array('user_id' => $user['id'])) ?>
- </li>
- <?php endif ?>
-
- <li <?= $this->app->checkMenuSelection('user', 'share') ?>>
- <?= $this->url->link(t('Public access'), 'user', 'share', array('user_id' => $user['id'])) ?>
- </li>
- <li <?= $this->app->checkMenuSelection('user', 'notifications') ?>>
- <?= $this->url->link(t('Notifications'), 'user', 'notifications', array('user_id' => $user['id'])) ?>
- </li>
- <li <?= $this->app->checkMenuSelection('user', 'external') ?>>
- <?= $this->url->link(t('External accounts'), 'user', 'external', array('user_id' => $user['id'])) ?>
- </li>
- <li <?= $this->app->checkMenuSelection('user', 'integrations') ?>>
- <?= $this->url->link(t('Integrations'), 'user', 'integrations', array('user_id' => $user['id'])) ?>
- </li>
- <?php endif ?>
-
- <?php if ($this->user->hasAccess('user', 'authentication')): ?>
- <li <?= $this->app->checkMenuSelection('user', 'authentication') ?>>
- <?= $this->url->link(t('Edit Authentication'), 'user', 'authentication', array('user_id' => $user['id'])) ?>
- </li>
- <?php endif ?>
-
- <?= $this->hook->render('template:user:sidebar:actions', array('user' => $user)) ?>
- </ul>
-</div> \ No newline at end of file
diff --git a/app/Template/user_creation/local.php b/app/Template/user_creation/local.php
new file mode 100644
index 00000000..4c224cec
--- /dev/null
+++ b/app/Template/user_creation/local.php
@@ -0,0 +1,45 @@
+<div class="page-header">
+ <h2><?= t('New local user') ?></h2>
+</div>
+<form class="popover-form" method="post" action="<?= $this->url->href('UserCreationController', 'save') ?>" autocomplete="off">
+ <?= $this->form->csrf() ?>
+
+ <div class="form-column">
+ <?= $this->form->label(t('Username'), 'username') ?>
+ <?= $this->form->text('username', $values, $errors, array('autofocus', 'required', 'maxlength="50"')) ?>
+
+ <?= $this->form->label(t('Name'), 'name') ?>
+ <?= $this->form->text('name', $values, $errors) ?>
+
+ <?= $this->form->label(t('Email'), 'email') ?>
+ <?= $this->form->email('email', $values, $errors) ?>
+
+ <?= $this->form->label(t('Password'), 'password') ?>
+ <?= $this->form->password('password', $values, $errors, array('required')) ?>
+
+ <?= $this->form->label(t('Confirmation'), 'confirmation') ?>
+ <?= $this->form->password('confirmation', $values, $errors, array('required')) ?>
+ </div>
+
+ <div class="form-column">
+ <?= $this->form->label(t('Add project member'), 'project_id') ?>
+ <?= $this->form->select('project_id', $projects, $values, $errors) ?>
+
+ <?= $this->form->label(t('Timezone'), 'timezone') ?>
+ <?= $this->form->select('timezone', $timezones, $values, $errors) ?>
+
+ <?= $this->form->label(t('Language'), 'language') ?>
+ <?= $this->form->select('language', $languages, $values, $errors) ?>
+
+ <?= $this->form->label(t('Role'), 'role') ?>
+ <?= $this->form->select('role', $roles, $values, $errors) ?>
+
+ <?= $this->form->checkbox('notifications_enabled', t('Enable email notifications'), 1, isset($values['notifications_enabled']) && $values['notifications_enabled'] == 1 ? true : false) ?>
+ </div>
+
+ <div class="form-actions">
+ <button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
+ <?= t('or') ?>
+ <?= $this->url->link(t('cancel'), 'UserListController', 'show', array(), false, 'close-popover') ?>
+ </div>
+</form>
diff --git a/app/Template/user_creation/remote.php b/app/Template/user_creation/remote.php
new file mode 100644
index 00000000..dc4981a4
--- /dev/null
+++ b/app/Template/user_creation/remote.php
@@ -0,0 +1,50 @@
+<div class="page-header">
+ <h2><?= t('New remote user') ?></h2>
+</div>
+<form class="popover-form" method="post" action="<?= $this->url->href('UserCreationController', 'save') ?>" autocomplete="off">
+
+ <?= $this->form->csrf() ?>
+ <?= $this->form->hidden('is_ldap_user', array('is_ldap_user' => 1)) ?>
+
+ <div class="form-column">
+ <?= $this->form->label(t('Username'), 'username') ?>
+ <?= $this->form->text('username', $values, $errors, array('autofocus', 'required', 'maxlength="50"')) ?>
+
+ <?= $this->form->label(t('Name'), 'name') ?>
+ <?= $this->form->text('name', $values, $errors) ?>
+
+ <?= $this->form->label(t('Email'), 'email') ?>
+ <?= $this->form->email('email', $values, $errors) ?>
+
+ <?= $this->hook->render('template:user:create-remote:form', array('values' => $values, 'errors' => $errors)) ?>
+ </div>
+
+ <div class="form-column">
+ <?= $this->form->label(t('Add project member'), 'project_id') ?>
+ <?= $this->form->select('project_id', $projects, $values, $errors) ?>
+
+ <?= $this->form->label(t('Timezone'), 'timezone') ?>
+ <?= $this->form->select('timezone', $timezones, $values, $errors) ?>
+
+ <?= $this->form->label(t('Language'), 'language') ?>
+ <?= $this->form->select('language', $languages, $values, $errors) ?>
+
+ <?= $this->form->label(t('Role'), 'role') ?>
+ <?= $this->form->select('role', $roles, $values, $errors) ?>
+
+ <?= $this->form->checkbox('notifications_enabled', t('Enable email notifications'), 1, isset($values['notifications_enabled']) && $values['notifications_enabled'] == 1 ? true : false) ?>
+ <?= $this->form->checkbox('disable_login_form', t('Disallow login form'), 1, isset($values['disable_login_form']) && $values['disable_login_form'] == 1) ?>
+ </div>
+
+ <div class="form-actions">
+ <button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
+ <?= t('or') ?>
+ <?= $this->url->link(t('cancel'), 'UserListController', 'show', array(), false, 'close-popover') ?>
+ </div>
+</form>
+<div class="alert alert-info">
+ <ul>
+ <li><?= t('Remote users do not store their password in Kanboard database, examples: LDAP, Google and Github accounts.') ?></li>
+ <li><?= t('If you check the box "Disallow login form", credentials entered in the login form will be ignored.') ?></li>
+ </ul>
+</div>
diff --git a/app/Template/user/authentication.php b/app/Template/user_credential/authentication.php
index 6cfd4e57..fbe2e915 100644
--- a/app/Template/user/authentication.php
+++ b/app/Template/user_credential/authentication.php
@@ -1,8 +1,7 @@
<div class="page-header">
<h2><?= t('Edit Authentication') ?></h2>
</div>
-<form method="post" action="<?= $this->url->href('user', 'authentication', array('user_id' => $user['id'])) ?>" autocomplete="off">
-
+<form method="post" action="<?= $this->url->href('UserCredentialController', 'saveAuthentication', array('user_id' => $user['id'])) ?>" autocomplete="off">
<?= $this->form->csrf() ?>
<?= $this->form->hidden('id', $values) ?>
@@ -16,7 +15,7 @@
<div class="form-actions">
<button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
<?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'user', 'show', array('user_id' => $user['id'])) ?>
+ <?= $this->url->link(t('cancel'), 'UserViewController', 'show', array('user_id' => $user['id'])) ?>
</div>
<div class="alert alert-info">
@@ -25,4 +24,4 @@
<li><?= t('If you check the box "Disallow login form", credentials entered in the login form will be ignored.') ?></li>
</ul>
</div>
-</form> \ No newline at end of file
+</form>
diff --git a/app/Template/user/password.php b/app/Template/user_credential/password.php
index ea6e997d..5a6e4403 100644
--- a/app/Template/user/password.php
+++ b/app/Template/user_credential/password.php
@@ -2,15 +2,12 @@
<h2><?= t('Password modification') ?></h2>
</div>
-<form method="post" action="<?= $this->url->href('user', 'password', array('user_id' => $user['id'])) ?>" autocomplete="off">
-
+<form method="post" action="<?= $this->url->href('UserCredentialController', 'savePassword', array('user_id' => $user['id'])) ?>" autocomplete="off">
<?= $this->form->hidden('id', $values) ?>
<?= $this->form->csrf() ?>
- <div class="alert alert-error">
- <?= $this->form->label(t('Current password for the user "%s"', $this->user->getFullname()), 'current_password') ?>
- <?= $this->form->password('current_password', $values, $errors) ?>
- </div>
+ <?= $this->form->label(t('Current password for the user "%s"', $this->user->getFullname()), 'current_password') ?>
+ <?= $this->form->password('current_password', $values, $errors) ?>
<?= $this->form->label(t('New password for the user "%s"', $this->user->getFullname($user)), 'password') ?>
<?= $this->form->password('password', $values, $errors) ?>
@@ -21,6 +18,6 @@
<div class="form-actions">
<button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
<?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'user', 'show', array('user_id' => $user['id'])) ?>
+ <?= $this->url->link(t('cancel'), 'UserViewController', 'show', array('user_id' => $user['id'])) ?>
</div>
</form>
diff --git a/app/Template/user_import/show.php b/app/Template/user_import/show.php
new file mode 100644
index 00000000..663f107e
--- /dev/null
+++ b/app/Template/user_import/show.php
@@ -0,0 +1,41 @@
+<div class="page-header">
+ <h2><?= t('Import users from CSV file') ?></h2>
+ <ul>
+ <li>
+ <i class="fa fa-download fa-fw"></i>
+ <?= $this->url->link(t('Download CSV template'), 'UserImportController', 'template') ?>
+ </li>
+ </ul>
+</div>
+
+<div class="alert">
+ <ul>
+ <li><?= t('Your file must use the predefined CSV format') ?></li>
+ <li><?= t('Your file must be encoded in UTF-8') ?></li>
+ <li><?= t('The first row must be the header') ?></li>
+ <li><?= t('Duplicates are not imported') ?></li>
+ <li><?= t('Usernames must be lowercase and unique') ?></li>
+ <li><?= t('Passwords will be encrypted if present') ?></li>
+ </ul>
+</div>
+
+<form action="<?= $this->url->href('UserImportController', 'save') ?>" method="post" enctype="multipart/form-data">
+ <?= $this->form->csrf() ?>
+
+ <?= $this->form->label(t('Delimiter'), 'delimiter') ?>
+ <?= $this->form->select('delimiter', $delimiters, $values) ?>
+
+ <?= $this->form->label(t('Enclosure'), 'enclosure') ?>
+ <?= $this->form->select('enclosure', $enclosures, $values) ?>
+
+ <?= $this->form->label(t('CSV File'), 'file') ?>
+ <?= $this->form->file('file', $errors) ?>
+
+ <p class="form-help"><?= t('Maximum size: ') ?><?= is_integer($max_size) ? $this->text->bytes($max_size) : $max_size ?></p>
+
+ <div class="form-actions">
+ <button type="submit" class="btn btn-blue"><?= t('Import') ?></button>
+ <?= t('or') ?>
+ <?= $this->url->link(t('cancel'), 'UserListController', 'show', array(), false, 'close-popover') ?>
+ </div>
+</form>
diff --git a/app/Template/user_import/step1.php b/app/Template/user_import/step1.php
deleted file mode 100644
index 592587a3..00000000
--- a/app/Template/user_import/step1.php
+++ /dev/null
@@ -1,46 +0,0 @@
-<section id="main">
- <div class="page-header">
- <?php if ($this->user->hasAccess('user', 'create')): ?>
- <ul>
- <li><i class="fa fa-user fa-fw"></i><?= $this->url->link(t('All users'), 'user', 'index') ?></li>
- <li><i class="fa fa-plus fa-fw"></i><?= $this->url->link(t('New local user'), 'user', 'create') ?></li>
- <li><i class="fa fa-plus fa-fw"></i><?= $this->url->link(t('New remote user'), 'user', 'create', array('remote' => 1)) ?></li>
- </ul>
- <?php endif ?>
- </div>
- <div class="page-header">
- <h2><?= t('Import') ?></h2>
- </div>
- <form action="<?= $this->url->href('userImport', 'step2') ?>" method="post" enctype="multipart/form-data">
- <?= $this->form->csrf() ?>
-
- <?= $this->form->label(t('Delimiter'), 'delimiter') ?>
- <?= $this->form->select('delimiter', $delimiters, $values) ?>
-
- <?= $this->form->label(t('Enclosure'), 'enclosure') ?>
- <?= $this->form->select('enclosure', $enclosures, $values) ?>
-
- <?= $this->form->label(t('CSV File'), 'file') ?>
- <?= $this->form->file('file', $errors) ?>
-
- <p class="form-help"><?= t('Maximum size: ') ?><?= is_integer($max_size) ? $this->text->bytes($max_size) : $max_size ?></p>
-
- <div class="form-actions">
- <button type="submit" class="btn btn-blue"><?= t('Import') ?></button>
- </div>
- </form>
- <div class="page-header">
- <h2><?= t('Instructions') ?></h2>
- </div>
- <div class="alert">
- <ul>
- <li><?= t('Your file must use the predefined CSV format') ?></li>
- <li><?= t('Your file must be encoded in UTF-8') ?></li>
- <li><?= t('The first row must be the header') ?></li>
- <li><?= t('Duplicates are not imported') ?></li>
- <li><?= t('Usernames must be lowercase and unique') ?></li>
- <li><?= t('Passwords will be encrypted if present') ?></li>
- </ul>
- </div>
- <p><i class="fa fa-download fa-fw"></i><?= $this->url->link(t('Download CSV template'), 'userImport', 'template') ?></p>
-</section> \ No newline at end of file
diff --git a/app/Template/user_list/dropdown.php b/app/Template/user_list/dropdown.php
new file mode 100644
index 00000000..9e90c230
--- /dev/null
+++ b/app/Template/user_list/dropdown.php
@@ -0,0 +1,27 @@
+<div class="dropdown">
+ <a href="#" class="dropdown-menu dropdown-menu-link-icon"><i class="fa fa-cog fa-fw"></i><i class="fa fa-caret-down"></i></a>
+ <ul>
+ <li>
+ <i class="fa fa-user fa-fw"></i>
+ <?= $this->url->link(t('View profile'), 'UserViewController', 'show', array('user_id' => $user['id'])) ?>
+ </li>
+ <?php if ($user['is_active'] == 1 && $this->user->hasAccess('UserStatusController', 'disable') && ! $this->user->isCurrentUser($user['id'])): ?>
+ <li>
+ <i class="fa fa-times fa-fw"></i>
+ <?= $this->url->link(t('Disable'), 'UserStatusController', 'confirmDisable', array('user_id' => $user['id']), false, 'popover') ?>
+ </li>
+ <?php endif ?>
+ <?php if ($user['is_active'] == 0 && $this->user->hasAccess('UserStatusController', 'enable') && ! $this->user->isCurrentUser($user['id'])): ?>
+ <li>
+ <i class="fa fa-check-square-o fa-fw"></i>
+ <?= $this->url->link(t('Enable'), 'UserStatusController', 'confirmEnable', array('user_id' => $user['id']), false, 'popover') ?>
+ </li>
+ <?php endif ?>
+ <?php if ($this->user->hasAccess('UserStatusController', 'remove') && ! $this->user->isCurrentUser($user['id'])): ?>
+ <li>
+ <i class="fa fa-trash-o fa-fw"></i>
+ <?= $this->url->link(t('Remove'), 'UserStatusController', 'confirmRemove', array('user_id' => $user['id']), false, 'popover') ?>
+ </li>
+ <?php endif ?>
+ </ul>
+</div>
diff --git a/app/Template/user/index.php b/app/Template/user_list/show.php
index 0b5da17c..b2bd9377 100644
--- a/app/Template/user/index.php
+++ b/app/Template/user_list/show.php
@@ -1,11 +1,11 @@
<section id="main">
<div class="page-header">
- <?php if ($this->user->hasAccess('user', 'create')): ?>
+ <?php if ($this->user->hasAccess('UserCreationController', 'show')): ?>
<ul>
- <li><i class="fa fa-plus fa-fw"></i><?= $this->url->link(t('New local user'), 'user', 'create') ?></li>
- <li><i class="fa fa-plus fa-fw"></i><?= $this->url->link(t('New remote user'), 'user', 'create', array('remote' => 1)) ?></li>
- <li><i class="fa fa-upload fa-fw"></i><?= $this->url->link(t('Import'), 'userImport', 'step1') ?></li>
- <li><i class="fa fa-users fa-fw"></i><?= $this->url->link(t('View all groups'), 'group', 'index') ?></li>
+ <li><i class="fa fa-plus fa-fw"></i><?= $this->url->link(t('New local user'), 'UserCreationController', 'show', array(), false, 'popover') ?></li>
+ <li><i class="fa fa-plus fa-fw"></i><?= $this->url->link(t('New remote user'), 'UserCreationController', 'show', array('remote' => 1), false, 'popover') ?></li>
+ <li><i class="fa fa-upload fa-fw"></i><?= $this->url->link(t('Import'), 'UserImportController', 'show', array(), false, 'popover') ?></li>
+ <li><i class="fa fa-users fa-fw"></i><?= $this->url->link(t('View all groups'), 'GroupListController', 'index') ?></li>
</ul>
<?php endif ?>
</div>
@@ -30,7 +30,7 @@
<?= '#'.$user['id'] ?>
</td>
<td>
- <?= $this->url->link($this->text->e($user['username']), 'user', 'show', array('user_id' => $user['id'])) ?>
+ <?= $this->url->link($this->text->e($user['username']), 'UserViewController', 'show', array('user_id' => $user['id'])) ?>
</td>
<td>
<?= $this->text->e($user['name']) ?>
@@ -55,7 +55,7 @@
<?php endif ?>
</td>
<td>
- <?= $this->render('user/dropdown', array('user' => $user)) ?>
+ <?= $this->render('user_list/dropdown', array('user' => $user)) ?>
</td>
</tr>
<?php endforeach ?>
diff --git a/app/Template/user/edit.php b/app/Template/user_modification/show.php
index 7b51eb73..396d550d 100644
--- a/app/Template/user/edit.php
+++ b/app/Template/user_modification/show.php
@@ -1,7 +1,7 @@
<div class="page-header">
<h2><?= t('Edit user') ?></h2>
</div>
-<form method="post" action="<?= $this->url->href('user', 'edit', array('user_id' => $user['id'])) ?>" autocomplete="off">
+<form method="post" action="<?= $this->url->href('UserModificationController', 'save', array('user_id' => $user['id'])) ?>" autocomplete="off">
<?= $this->form->csrf() ?>
@@ -30,6 +30,6 @@
<div class="form-actions">
<button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
<?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'user', 'show', array('user_id' => $user['id'])) ?>
+ <?= $this->url->link(t('cancel'), 'UserViewController', 'show', array('user_id' => $user['id'])) ?>
</div>
-</form> \ No newline at end of file
+</form>
diff --git a/app/Template/user_status/disable.php b/app/Template/user_status/disable.php
index 90d8c757..d30b0c20 100644
--- a/app/Template/user_status/disable.php
+++ b/app/Template/user_status/disable.php
@@ -6,8 +6,8 @@
<p class="alert alert-info"><?= t('Do you really want to disable this user: "%s"?', $user['name'] ?: $user['username']) ?></p>
<div class="form-actions">
- <?= $this->url->link(t('Yes'), 'UserStatus', 'disable', array('user_id' => $user['id']), true, 'btn btn-red') ?>
+ <?= $this->url->link(t('Yes'), 'UserStatusController', 'disable', array('user_id' => $user['id']), true, 'btn btn-red') ?>
<?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'user', 'index', array(), false, 'close-popover') ?>
+ <?= $this->url->link(t('cancel'), 'UserListController', 'show', array(), false, 'close-popover') ?>
</div>
</div>
diff --git a/app/Template/user_status/enable.php b/app/Template/user_status/enable.php
index cd3d4947..29d25eee 100644
--- a/app/Template/user_status/enable.php
+++ b/app/Template/user_status/enable.php
@@ -6,8 +6,8 @@
<p class="alert alert-info"><?= t('Do you really want to enable this user: "%s"?', $user['name'] ?: $user['username']) ?></p>
<div class="form-actions">
- <?= $this->url->link(t('Yes'), 'UserStatus', 'enable', array('user_id' => $user['id']), true, 'btn btn-red') ?>
+ <?= $this->url->link(t('Yes'), 'UserStatusController', 'enable', array('user_id' => $user['id']), true, 'btn btn-red') ?>
<?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'user', 'index', array(), false, 'close-popover') ?>
+ <?= $this->url->link(t('cancel'), 'UserListController', 'show', array(), false, 'close-popover') ?>
</div>
</div>
diff --git a/app/Template/user_status/remove.php b/app/Template/user_status/remove.php
index cd5c09a6..2b8f2df5 100644
--- a/app/Template/user_status/remove.php
+++ b/app/Template/user_status/remove.php
@@ -6,8 +6,8 @@
<p class="alert alert-info"><?= t('Do you really want to remove this user: "%s"?', $user['name'] ?: $user['username']) ?></p>
<div class="form-actions">
- <?= $this->url->link(t('Yes'), 'UserStatus', 'remove', array('user_id' => $user['id']), true, 'btn btn-red') ?>
+ <?= $this->url->link(t('Yes'), 'UserStatusController', 'remove', array('user_id' => $user['id']), true, 'btn btn-red') ?>
<?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'user', 'index', array(), false, 'close-popover') ?>
+ <?= $this->url->link(t('cancel'), 'UserListController', 'show', array(), false, 'close-popover') ?>
</div>
</div>
diff --git a/app/Template/user/external.php b/app/Template/user_view/external.php
index 22c25af2..22c25af2 100644
--- a/app/Template/user/external.php
+++ b/app/Template/user_view/external.php
diff --git a/app/Template/user/integrations.php b/app/Template/user_view/integrations.php
index ef9d8e71..4a237346 100644
--- a/app/Template/user/integrations.php
+++ b/app/Template/user_view/integrations.php
@@ -2,7 +2,7 @@
<h2><?= t('Integrations') ?></h2>
</div>
-<form method="post" action="<?= $this->url->href('user', 'integrations', array('user_id' => $user['id'])) ?>" autocomplete="off">
+<form method="post" action="<?= $this->url->href('UserViewController', 'integrations', array('user_id' => $user['id'])) ?>" autocomplete="off">
<?= $this->form->csrf() ?>
<?php $hooks = $this->hook->render('template:user:integrations', array('values' => $values)) ?>
<?php if (! empty($hooks)): ?>
diff --git a/app/Template/user/last.php b/app/Template/user_view/last.php
index 3de4d5e2..3de4d5e2 100644
--- a/app/Template/user/last.php
+++ b/app/Template/user_view/last.php
diff --git a/app/Template/user_view/layout.php b/app/Template/user_view/layout.php
new file mode 100644
index 00000000..c3604b99
--- /dev/null
+++ b/app/Template/user_view/layout.php
@@ -0,0 +1,19 @@
+<section id="main">
+ <div class="page-header">
+ <?php if ($this->user->hasAccess('UserCreationController', 'show')): ?>
+ <ul>
+ <li><i class="fa fa-user fa-fw"></i><?= $this->url->link(t('All users'), 'UserListController', 'show') ?></li>
+ <li><i class="fa fa-plus fa-fw"></i><?= $this->url->link(t('New local user'), 'UserCreationController', 'show', array(), false, 'popover') ?></li>
+ <li><i class="fa fa-plus fa-fw"></i><?= $this->url->link(t('New remote user'), 'UserCreationController', 'show', array('remote' => 1), false, 'popover') ?></li>
+ <li><i class="fa fa-upload fa-fw"></i><?= $this->url->link(t('Import'), 'UserImportController', 'show', array(), false, 'popover') ?></li>
+ <li><i class="fa fa-users fa-fw"></i><?= $this->url->link(t('View all groups'), 'GroupListController', 'index') ?></li>
+ </ul>
+ <?php endif ?>
+ </div>
+ <section class="sidebar-container" id="user-section">
+ <?= $this->render('user_view/sidebar', array('user' => $user)) ?>
+ <div class="sidebar-content">
+ <?= $content_for_sublayout ?>
+ </div>
+ </section>
+</section>
diff --git a/app/Template/user/notifications.php b/app/Template/user_view/notifications.php
index 6e1a0004..84ca1282 100644
--- a/app/Template/user/notifications.php
+++ b/app/Template/user_view/notifications.php
@@ -2,7 +2,7 @@
<h2><?= t('Notifications') ?></h2>
</div>
-<form method="post" action="<?= $this->url->href('user', 'notifications', array('user_id' => $user['id'])) ?>" autocomplete="off">
+<form method="post" action="<?= $this->url->href('UserViewController', 'notifications', array('user_id' => $user['id'])) ?>" autocomplete="off">
<?= $this->form->csrf() ?>
<h4><?= t('Notification methods:') ?></h4>
@@ -21,6 +21,6 @@
<div class="form-actions">
<button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
<?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'user', 'show', array('user_id' => $user['id'])) ?>
+ <?= $this->url->link(t('cancel'), 'UserViewController', 'show', array('user_id' => $user['id'])) ?>
</div>
-</form> \ No newline at end of file
+</form>
diff --git a/app/Template/user/password_reset.php b/app/Template/user_view/password_reset.php
index 1371ce11..1371ce11 100644
--- a/app/Template/user/password_reset.php
+++ b/app/Template/user_view/password_reset.php
diff --git a/app/Template/user/profile.php b/app/Template/user_view/profile.php
index 9c9d3282..9c9d3282 100644
--- a/app/Template/user/profile.php
+++ b/app/Template/user_view/profile.php
diff --git a/app/Template/user/sessions.php b/app/Template/user_view/sessions.php
index d7fe895d..eda3ef7f 100644
--- a/app/Template/user/sessions.php
+++ b/app/Template/user_view/sessions.php
@@ -19,7 +19,7 @@
<td><?= $this->dt->datetime($session['expiration']) ?></td>
<td><?= $this->text->e($session['ip']) ?></td>
<td><?= $this->text->e($session['user_agent']) ?></td>
- <td><?= $this->url->link(t('Remove'), 'User', 'removeSession', array('user_id' => $user['id'], 'id' => $session['id']), true) ?></td>
+ <td><?= $this->url->link(t('Remove'), 'UserViewController', 'removeSession', array('user_id' => $user['id'], 'id' => $session['id']), true) ?></td>
</tr>
<?php endforeach ?>
</table>
diff --git a/app/Template/user_view/share.php b/app/Template/user_view/share.php
new file mode 100644
index 00000000..570b766e
--- /dev/null
+++ b/app/Template/user_view/share.php
@@ -0,0 +1,15 @@
+<div class="page-header">
+ <h2><?= t('Public access') ?></h2>
+</div>
+
+<?php if (! empty($user['token'])): ?>
+ <div class="listing">
+ <ul class="no-bullet">
+ <li><strong><i class="fa fa-rss-square"></i> <?= $this->url->link(t('RSS feed'), 'FeedController', 'user', array('token' => $user['token']), false, '', '', true) ?></strong></li>
+ <li><strong><i class="fa fa-calendar"></i> <?= $this->url->link(t('iCal feed'), 'ICalendarController', 'user', array('token' => $user['token']), false, '', '', true) ?></strong></li>
+ </ul>
+ </div>
+ <?= $this->url->link(t('Disable public access'), 'UserViewController', 'share', array('user_id' => $user['id'], 'switch' => 'disable'), true, 'btn btn-red') ?>
+<?php else: ?>
+ <?= $this->url->link(t('Enable public access'), 'UserViewController', 'share', array('user_id' => $user['id'], 'switch' => 'enable'), true, 'btn btn-blue') ?>
+<?php endif ?>
diff --git a/app/Template/user/show.php b/app/Template/user_view/show.php
index df0affb8..fc11f8a1 100644
--- a/app/Template/user/show.php
+++ b/app/Template/user_view/show.php
@@ -15,6 +15,10 @@
<li><?= t('Role:') ?> <strong><?= $this->user->getRoleName($user['role']) ?></strong></li>
<li><?= t('Account type:') ?> <strong><?= $user['is_ldap_user'] ? t('Remote') : t('Local') ?></strong></li>
<li><?= $user['twofactor_activated'] == 1 ? t('Two factor authentication enabled') : t('Two factor authentication disabled') ?></li>
+ <li><?= t('Number of failed login:') ?> <strong><?= $user['nb_failed_login'] ?></strong></li>
+ <?php if ($user['lock_expiration_date'] != 0): ?>
+ <li><?= t('Account locked until:') ?> <strong><?= $this->dt->datetime($user['lock_expiration_date']) ?></strong></li>
+ <?php endif ?>
</ul>
<div class="page-header">
@@ -33,8 +37,8 @@
<div class="listing">
<ul class="no-bullet">
- <li><strong><i class="fa fa-rss-square"></i> <?= $this->url->link(t('RSS feed'), 'feed', 'user', array('token' => $user['token']), false, '', '', true) ?></strong></li>
- <li><strong><i class="fa fa-calendar"></i> <?= $this->url->link(t('iCal feed'), 'ical', 'user', array('token' => $user['token']), false, '', '', true) ?></strong></li>
+ <li><strong><i class="fa fa-rss-square"></i> <?= $this->url->link(t('RSS feed'), 'FeedController', 'user', array('token' => $user['token']), false, '', '', true) ?></strong></li>
+ <li><strong><i class="fa fa-calendar"></i> <?= $this->url->link(t('iCal feed'), 'ICalendarController', 'user', array('token' => $user['token']), false, '', '', true) ?></strong></li>
</ul>
</div>
<?php endif ?>
diff --git a/app/Template/user_view/sidebar.php b/app/Template/user_view/sidebar.php
new file mode 100644
index 00000000..d200a7f5
--- /dev/null
+++ b/app/Template/user_view/sidebar.php
@@ -0,0 +1,83 @@
+<div class="sidebar">
+ <h2><?= t('Information') ?></h2>
+ <ul>
+ <?php if ($this->user->hasAccess('UserViewController', 'show')): ?>
+ <li <?= $this->app->checkMenuSelection('UserViewController', 'show') ?>>
+ <?= $this->url->link(t('Summary'), 'UserViewController', 'show', array('user_id' => $user['id'])) ?>
+ </li>
+ <?php endif ?>
+ <?php if ($this->user->isAdmin()): ?>
+ <li>
+ <?= $this->url->link(t('User dashboard'), 'DashboardController', 'show', array('user_id' => $user['id'])) ?>
+ </li>
+ <?php endif ?>
+ <?php if ($this->user->isAdmin() || $this->user->isCurrentUser($user['id'])): ?>
+ <li <?= $this->app->checkMenuSelection('UserViewController', 'timesheet') ?>>
+ <?= $this->url->link(t('Time tracking'), 'UserViewController', 'timesheet', array('user_id' => $user['id'])) ?>
+ </li>
+ <li <?= $this->app->checkMenuSelection('UserViewController', 'lastLogin') ?>>
+ <?= $this->url->link(t('Last logins'), 'UserViewController', 'lastLogin', array('user_id' => $user['id'])) ?>
+ </li>
+ <li <?= $this->app->checkMenuSelection('UserViewController', 'sessions') ?>>
+ <?= $this->url->link(t('Persistent connections'), 'UserViewController', 'sessions', array('user_id' => $user['id'])) ?>
+ </li>
+ <li <?= $this->app->checkMenuSelection('UserViewController', 'passwordReset') ?>>
+ <?= $this->url->link(t('Password reset history'), 'UserViewController', 'passwordReset', array('user_id' => $user['id'])) ?>
+ </li>
+ <?php endif ?>
+
+ <?= $this->hook->render('template:user:sidebar:information', array('user' => $user)) ?>
+ </ul>
+
+ <h2><?= t('Actions') ?></h2>
+ <ul>
+ <?php if ($this->user->isAdmin() || $this->user->isCurrentUser($user['id'])): ?>
+
+ <?php if ($this->user->hasAccess('UserModificationController', 'show')): ?>
+ <li <?= $this->app->checkMenuSelection('UserModificationController', 'show') ?>>
+ <?= $this->url->link(t('Edit profile'), 'UserModificationController', 'show', array('user_id' => $user['id'])) ?>
+ </li>
+ <li <?= $this->app->checkMenuSelection('AvatarFile') ?>>
+ <?= $this->url->link(t('Avatar'), 'AvatarFileController', 'show', array('user_id' => $user['id'])) ?>
+ </li>
+ <?php endif ?>
+
+ <?php if ($user['is_ldap_user'] == 0): ?>
+ <li <?= $this->app->checkMenuSelection('UserCredentialController', 'changePassword') ?>>
+ <?= $this->url->link(t('Change password'), 'UserCredentialController', 'changePassword', array('user_id' => $user['id'])) ?>
+ </li>
+ <?php endif ?>
+
+ <?php if ($this->user->isCurrentUser($user['id'])): ?>
+ <li <?= $this->app->checkMenuSelection('TwoFactorController', 'index') ?>>
+ <?= $this->url->link(t('Two factor authentication'), 'TwoFactorController', 'index', array('user_id' => $user['id'])) ?>
+ </li>
+ <?php elseif ($this->user->hasAccess('TwoFactorController', 'disable') && $user['twofactor_activated'] == 1): ?>
+ <li <?= $this->app->checkMenuSelection('TwoFactorController', 'disable') ?>>
+ <?= $this->url->link(t('Two factor authentication'), 'TwoFactorController', 'disable', array('user_id' => $user['id'])) ?>
+ </li>
+ <?php endif ?>
+
+ <li <?= $this->app->checkMenuSelection('UserViewController', 'share') ?>>
+ <?= $this->url->link(t('Public access'), 'UserViewController', 'share', array('user_id' => $user['id'])) ?>
+ </li>
+ <li <?= $this->app->checkMenuSelection('UserViewController', 'notifications') ?>>
+ <?= $this->url->link(t('Notifications'), 'UserViewController', 'notifications', array('user_id' => $user['id'])) ?>
+ </li>
+ <li <?= $this->app->checkMenuSelection('UserViewController', 'external') ?>>
+ <?= $this->url->link(t('External accounts'), 'UserViewController', 'external', array('user_id' => $user['id'])) ?>
+ </li>
+ <li <?= $this->app->checkMenuSelection('UserViewController', 'integrations') ?>>
+ <?= $this->url->link(t('Integrations'), 'UserViewController', 'integrations', array('user_id' => $user['id'])) ?>
+ </li>
+ <?php endif ?>
+
+ <?php if ($this->user->hasAccess('UserCredentialController', 'changeAuthentication')): ?>
+ <li <?= $this->app->checkMenuSelection('UserCredentialController', 'changeAuthentication') ?>>
+ <?= $this->url->link(t('Edit Authentication'), 'UserCredentialController', 'changeAuthentication', array('user_id' => $user['id'])) ?>
+ </li>
+ <?php endif ?>
+
+ <?= $this->hook->render('template:user:sidebar:actions', array('user' => $user)) ?>
+ </ul>
+</div>
diff --git a/app/Template/user/timesheet.php b/app/Template/user_view/timesheet.php
index 92ebafb5..3df57492 100644
--- a/app/Template/user/timesheet.php
+++ b/app/Template/user_view/timesheet.php
@@ -16,8 +16,8 @@
</tr>
<?php foreach ($subtask_paginator->getCollection() as $record): ?>
<tr>
- <td><?= $this->url->link($this->text->e($record['task_title']), 'task', 'show', array('project_id' => $record['project_id'], 'task_id' => $record['task_id'])) ?></td>
- <td><?= $this->url->link($this->text->e($record['subtask_title']), 'task', 'show', array('project_id' => $record['project_id'], 'task_id' => $record['task_id'])) ?></td>
+ <td><?= $this->url->link($this->text->e($record['task_title']), 'TaskViewController', 'show', array('project_id' => $record['project_id'], 'task_id' => $record['task_id'])) ?></td>
+ <td><?= $this->url->link($this->text->e($record['subtask_title']), 'TaskViewController', 'show', array('project_id' => $record['project_id'], 'task_id' => $record['task_id'])) ?></td>
<td><?= $this->dt->datetime($record['start']) ?></td>
<td><?= $this->dt->datetime($record['end']) ?></td>
<td><?= n($record['time_spent']).' '.t('hours') ?></td>
@@ -26,4 +26,4 @@
</table>
<?= $subtask_paginator ?>
-<?php endif ?> \ No newline at end of file
+<?php endif ?>
diff --git a/app/User/Avatar/AvatarFileProvider.php b/app/User/Avatar/AvatarFileProvider.php
index eea565f0..790245a4 100644
--- a/app/User/Avatar/AvatarFileProvider.php
+++ b/app/User/Avatar/AvatarFileProvider.php
@@ -23,7 +23,7 @@ class AvatarFileProvider extends Base implements AvatarProviderInterface
*/
public function render(array $user, $size)
{
- $url = $this->helper->url->href('AvatarFile', 'image', array('user_id' => $user['id'], 'size' => $size));
+ $url = $this->helper->url->href('AvatarFileController', 'image', array('user_id' => $user['id'], 'size' => $size));
$title = $this->helper->text->e($user['name'] ?: $user['username']);
return '<img src="' . $url . '" alt="' . $title . '" title="' . $title . '">';
}
diff --git a/app/User/Avatar/GravatarProvider.php b/app/User/Avatar/GravatarProvider.php
index 87ca51b1..e066d766 100644
--- a/app/User/Avatar/GravatarProvider.php
+++ b/app/User/Avatar/GravatarProvider.php
@@ -37,6 +37,6 @@ class GravatarProvider extends Base implements AvatarProviderInterface
*/
public function isActive(array $user)
{
- return !empty($user['email']) && $this->config->get('integration_gravatar') == 1;
+ return !empty($user['email']) && $this->configModel->get('integration_gravatar') == 1;
}
}
diff --git a/app/User/Avatar/LetterAvatarProvider.php b/app/User/Avatar/LetterAvatarProvider.php
index f9659e61..b7a95f41 100644
--- a/app/User/Avatar/LetterAvatarProvider.php
+++ b/app/User/Avatar/LetterAvatarProvider.php
@@ -144,12 +144,12 @@ class LetterAvatarProvider extends Base implements AvatarProviderInterface
$str .= 'x';
$max = intval(9007199254740991 / $seed2);
- for ($i = 0, $ilen = mb_strlen($str); $i < $ilen; $i++) {
+ for ($i = 0, $ilen = mb_strlen($str, 'UTF-8'); $i < $ilen; $i++) {
if ($hash > $max) {
$hash = intval($hash / $seed2);
}
- $hash = $hash * $seed + $this->getCharCode($str[$i]);
+ $hash = $hash * $seed + $this->getCharCode(mb_substr($str, $i, 1, 'UTF-8'));
}
return $hash;
diff --git a/app/User/LdapUserProvider.php b/app/User/LdapUserProvider.php
index 153450d9..8ea89763 100644
--- a/app/User/LdapUserProvider.php
+++ b/app/User/LdapUserProvider.php
@@ -3,6 +3,7 @@
namespace Kanboard\User;
use Kanboard\Core\User\UserProviderInterface;
+use Kanboard\Model\LanguageModel;
/**
* LDAP User Provider
@@ -61,6 +62,22 @@ class LdapUserProvider implements UserProviderInterface
protected $groupIds;
/**
+ * User photo
+ *
+ * @access protected
+ * @var string
+ */
+ protected $photo = '';
+
+ /**
+ * User language
+ *
+ * @access protected
+ * @var string
+ */
+ protected $language = '';
+
+ /**
* Constructor
*
* @access public
@@ -70,8 +87,10 @@ class LdapUserProvider implements UserProviderInterface
* @param string $email
* @param string $role
* @param string[] $groupIds
+ * @param string $photo
+ * @param string $language
*/
- public function __construct($dn, $username, $name, $email, $role, array $groupIds)
+ public function __construct($dn, $username, $name, $email, $role, array $groupIds, $photo = '', $language = '')
{
$this->dn = $dn;
$this->username = $username;
@@ -79,6 +98,8 @@ class LdapUserProvider implements UserProviderInterface
$this->email = $email;
$this->role = $role;
$this->groupIds = $groupIds;
+ $this->photo = $photo;
+ $this->language = $language;
}
/**
@@ -170,10 +191,10 @@ class LdapUserProvider implements UserProviderInterface
}
/**
- * Get groups
+ * Get groups DN
*
* @access public
- * @return array
+ * @return string[]
*/
public function getExternalGroupIds()
{
@@ -188,9 +209,13 @@ class LdapUserProvider implements UserProviderInterface
*/
public function getExtraAttributes()
{
- return array(
- 'is_ldap_user' => 1,
- );
+ $attributes = array('is_ldap_user' => 1);
+
+ if (! empty($this->language)) {
+ $attributes['language'] = LanguageModel::findCode($this->language);
+ }
+
+ return $attributes;
}
/**
@@ -203,4 +228,15 @@ class LdapUserProvider implements UserProviderInterface
{
return $this->dn;
}
+
+ /**
+ * Get user photo
+ *
+ * @access public
+ * @return string
+ */
+ public function getPhoto()
+ {
+ return $this->photo;
+ }
}
diff --git a/app/Validator/ActionValidator.php b/app/Validator/ActionValidator.php
index 95ee7d21..4ce5db46 100644
--- a/app/Validator/ActionValidator.php
+++ b/app/Validator/ActionValidator.php
@@ -8,10 +8,10 @@ use SimpleValidator\Validators;
/**
* Action Validator
*
- * @package validator
+ * @package Kanboard\Validator
* @author Frederic Guillot
*/
-class ActionValidator extends Base
+class ActionValidator extends BaseValidator
{
/**
* Validate action creation
diff --git a/app/Validator/AuthValidator.php b/app/Validator/AuthValidator.php
index cd6e04d5..03ff6f22 100644
--- a/app/Validator/AuthValidator.php
+++ b/app/Validator/AuthValidator.php
@@ -9,10 +9,10 @@ use Gregwar\Captcha\CaptchaBuilder;
/**
* Authentication Validator
*
- * @package validator
+ * @package Kanboard\Validator
* @author Frederic Guillot
*/
-class AuthValidator extends Base
+class AuthValidator extends BaseValidator
{
/**
* Validate user login form
@@ -59,7 +59,7 @@ class AuthValidator extends Base
$result = true;
$errors = array();
- if ($this->userLocking->isLocked($values['username'])) {
+ if ($this->userLockingModel->isLocked($values['username'])) {
$result = false;
$errors['login'] = t('Your account is locked for %d minutes', BRUTEFORCE_LOCKDOWN_DURATION);
$this->logger->error('Account locked: '.$values['username']);
@@ -100,7 +100,7 @@ class AuthValidator extends Base
$result = true;
$errors = array();
- if ($this->userLocking->hasCaptcha($values['username'])) {
+ if ($this->userLockingModel->hasCaptcha($values['username'])) {
if (! isset($this->sessionStorage->captcha)) {
$result = false;
} else {
diff --git a/app/Validator/Base.php b/app/Validator/BaseValidator.php
index ba32a503..6088538c 100644
--- a/app/Validator/Base.php
+++ b/app/Validator/BaseValidator.php
@@ -2,15 +2,16 @@
namespace Kanboard\Validator;
+use Kanboard\Core\Base;
use SimpleValidator\Validators;
/**
* Base Validator
*
- * @package validator
+ * @package Kanboard\Validator
* @author Frederic Guillot
*/
-class Base extends \Kanboard\Core\Base
+abstract class BaseValidator extends Base
{
/**
* Execute multiple validators
diff --git a/app/Validator/CategoryValidator.php b/app/Validator/CategoryValidator.php
index 715aed66..fc42d2e5 100644
--- a/app/Validator/CategoryValidator.php
+++ b/app/Validator/CategoryValidator.php
@@ -8,10 +8,10 @@ use SimpleValidator\Validators;
/**
* Category Validator
*
- * @package validator
+ * @package Kanboard\Validator
* @author Frederic Guillot
*/
-class CategoryValidator extends Base
+class CategoryValidator extends BaseValidator
{
/**
* Validate category creation
diff --git a/app/Validator/ColumnValidator.php b/app/Validator/ColumnValidator.php
index f0f1659b..25aa45d0 100644
--- a/app/Validator/ColumnValidator.php
+++ b/app/Validator/ColumnValidator.php
@@ -8,10 +8,10 @@ use SimpleValidator\Validators;
/**
* Column Validator
*
- * @package validator
+ * @package Kanboard\Validator
* @author Frederic Guillot
*/
-class ColumnValidator extends Base
+class ColumnValidator extends BaseValidator
{
/**
* Validate column modification
diff --git a/app/Validator/CommentValidator.php b/app/Validator/CommentValidator.php
index 4eb54206..fc8e6da8 100644
--- a/app/Validator/CommentValidator.php
+++ b/app/Validator/CommentValidator.php
@@ -8,10 +8,10 @@ use SimpleValidator\Validators;
/**
* Comment Validator
*
- * @package validator
+ * @package Kanboard\Validator
* @author Frederic Guillot
*/
-class CommentValidator extends Base
+class CommentValidator extends BaseValidator
{
/**
* Validate comment creation
diff --git a/app/Validator/CurrencyValidator.php b/app/Validator/CurrencyValidator.php
index ee191523..4f375c54 100644
--- a/app/Validator/CurrencyValidator.php
+++ b/app/Validator/CurrencyValidator.php
@@ -8,10 +8,10 @@ use SimpleValidator\Validators;
/**
* Currency Validator
*
- * @package validator
+ * @package Kanboard\Validator
* @author Frederic Guillot
*/
-class CurrencyValidator extends Base
+class CurrencyValidator extends BaseValidator
{
/**
* Validate
diff --git a/app/Validator/CustomFilterValidator.php b/app/Validator/CustomFilterValidator.php
index 07f2a1eb..1ab9303d 100644
--- a/app/Validator/CustomFilterValidator.php
+++ b/app/Validator/CustomFilterValidator.php
@@ -8,10 +8,10 @@ use SimpleValidator\Validators;
/**
* Custom Filter Validator
*
- * @package validator
+ * @package Kanboard\Validator
* @author Frederic Guillot
*/
-class CustomFilterValidator extends Base
+class CustomFilterValidator extends BaseValidator
{
/**
* Common validation rules
diff --git a/app/Validator/ExternalLinkValidator.php b/app/Validator/ExternalLinkValidator.php
index fff4133b..9c017708 100644
--- a/app/Validator/ExternalLinkValidator.php
+++ b/app/Validator/ExternalLinkValidator.php
@@ -8,10 +8,10 @@ use SimpleValidator\Validators;
/**
* External Link Validator
*
- * @package validator
+ * @package Kanboard\Validator
* @author Frederic Guillot
*/
-class ExternalLinkValidator extends Base
+class ExternalLinkValidator extends BaseValidator
{
/**
* Validate creation
diff --git a/app/Validator/GroupValidator.php b/app/Validator/GroupValidator.php
index 2226abd3..8b21c697 100644
--- a/app/Validator/GroupValidator.php
+++ b/app/Validator/GroupValidator.php
@@ -4,15 +4,15 @@ namespace Kanboard\Validator;
use SimpleValidator\Validator;
use SimpleValidator\Validators;
-use Kanboard\Model\Group;
+use Kanboard\Model\GroupModel;
/**
* Group Validator
*
- * @package validator
+ * @package Kanboard\Validator
* @author Frederic Guillot
*/
-class GroupValidator extends Base
+class GroupValidator extends BaseValidator
{
/**
* Validate creation
@@ -63,7 +63,7 @@ class GroupValidator extends Base
return array(
new Validators\Required('name', t('The name is required')),
new Validators\MaxLength('name', t('The maximum length is %d characters', 100), 100),
- new Validators\Unique('name', t('The name must be unique'), $this->db->getConnection(), Group::TABLE, 'id'),
+ new Validators\Unique('name', t('The name must be unique'), $this->db->getConnection(), GroupModel::TABLE, 'id'),
new Validators\MaxLength('external_id', t('The maximum length is %d characters', 255), 255),
new Validators\Integer('id', t('This value must be an integer')),
);
diff --git a/app/Validator/LinkValidator.php b/app/Validator/LinkValidator.php
index 10a826da..8e1c8780 100644
--- a/app/Validator/LinkValidator.php
+++ b/app/Validator/LinkValidator.php
@@ -4,15 +4,15 @@ namespace Kanboard\Validator;
use SimpleValidator\Validator;
use SimpleValidator\Validators;
-use Kanboard\Model\Link;
+use Kanboard\Model\LinkModel;
/**
* Link Validator
*
- * @package validator
+ * @package Kanboard\Validator
* @author Frederic Guillot
*/
-class LinkValidator extends Base
+class LinkValidator extends BaseValidator
{
/**
* Validate creation
@@ -25,7 +25,7 @@ class LinkValidator extends Base
{
$v = new Validator($values, array(
new Validators\Required('label', t('Field required')),
- new Validators\Unique('label', t('This label must be unique'), $this->db->getConnection(), Link::TABLE),
+ new Validators\Unique('label', t('This label must be unique'), $this->db->getConnection(), LinkModel::TABLE),
new Validators\NotEquals('label', 'opposite_label', t('The labels must be different')),
));
@@ -48,7 +48,7 @@ class LinkValidator extends Base
new Validators\Required('id', t('Field required')),
new Validators\Required('opposite_id', t('Field required')),
new Validators\Required('label', t('Field required')),
- new Validators\Unique('label', t('This label must be unique'), $this->db->getConnection(), Link::TABLE),
+ new Validators\Unique('label', t('This label must be unique'), $this->db->getConnection(), LinkModel::TABLE),
));
return array(
diff --git a/app/Validator/PasswordResetValidator.php b/app/Validator/PasswordResetValidator.php
index baf2d8d7..e44e5206 100644
--- a/app/Validator/PasswordResetValidator.php
+++ b/app/Validator/PasswordResetValidator.php
@@ -9,10 +9,10 @@ use Gregwar\Captcha\CaptchaBuilder;
/**
* Password Reset Validator
*
- * @package validator
+ * @package Kanboard\Validator
* @author Frederic Guillot
*/
-class PasswordResetValidator extends Base
+class PasswordResetValidator extends BaseValidator
{
/**
* Validate creation
@@ -87,6 +87,6 @@ class PasswordResetValidator extends Base
}
}
- return array($result, $errors);;
+ return array($result, $errors);
}
}
diff --git a/app/Validator/ProjectValidator.php b/app/Validator/ProjectValidator.php
index 1c6c90f8..9ef59111 100644
--- a/app/Validator/ProjectValidator.php
+++ b/app/Validator/ProjectValidator.php
@@ -4,15 +4,15 @@ namespace Kanboard\Validator;
use SimpleValidator\Validator;
use SimpleValidator\Validators;
-use Kanboard\Model\Project;
+use Kanboard\Model\ProjectModel;
/**
* Project Validator
*
- * @package validator
+ * @package Kanboard\Validator
* @author Frederic Guillot
*/
-class ProjectValidator extends Base
+class ProjectValidator extends BaseValidator
{
/**
* Common validation rules
@@ -34,7 +34,7 @@ class ProjectValidator extends Base
new Validators\MaxLength('start_date', t('The maximum length is %d characters', 10), 10),
new Validators\MaxLength('end_date', t('The maximum length is %d characters', 10), 10),
new Validators\AlphaNumeric('identifier', t('This value must be alphanumeric')) ,
- new Validators\Unique('identifier', t('The identifier must be unique'), $this->db->getConnection(), Project::TABLE),
+ new Validators\Unique('identifier', t('The identifier must be unique'), $this->db->getConnection(), ProjectModel::TABLE),
);
}
diff --git a/app/Validator/SubtaskValidator.php b/app/Validator/SubtaskValidator.php
index 1989b7f4..b80de41d 100644
--- a/app/Validator/SubtaskValidator.php
+++ b/app/Validator/SubtaskValidator.php
@@ -8,10 +8,10 @@ use SimpleValidator\Validators;
/**
* Subtask Validator
*
- * @package validator
+ * @package Kanboard\Validator
* @author Frederic Guillot
*/
-class SubtaskValidator extends Base
+class SubtaskValidator extends BaseValidator
{
/**
* Validate creation
diff --git a/app/Validator/SwimlaneValidator.php b/app/Validator/SwimlaneValidator.php
index 4cc780f9..16f8bfba 100644
--- a/app/Validator/SwimlaneValidator.php
+++ b/app/Validator/SwimlaneValidator.php
@@ -8,10 +8,10 @@ use SimpleValidator\Validators;
/**
* Swimlane Validator
*
- * @package validator
+ * @package Kanboard\Validator
* @author Frederic Guillot
*/
-class SwimlaneValidator extends Base
+class SwimlaneValidator extends BaseValidator
{
/**
* Validate creation
diff --git a/app/Validator/TaskLinkValidator.php b/app/Validator/TaskLinkValidator.php
index c88c2b16..6da257bf 100644
--- a/app/Validator/TaskLinkValidator.php
+++ b/app/Validator/TaskLinkValidator.php
@@ -4,15 +4,15 @@ namespace Kanboard\Validator;
use SimpleValidator\Validator;
use SimpleValidator\Validators;
-use Kanboard\Model\Task;
+use Kanboard\Model\TaskModel;
/**
* Task Link Validator
*
- * @package validator
+ * @package Kanboard\Validator
* @author Frederic Guillot
*/
-class TaskLinkValidator extends Base
+class TaskLinkValidator extends BaseValidator
{
/**
* Common validation rules
@@ -27,7 +27,7 @@ class TaskLinkValidator extends Base
new Validators\Required('opposite_task_id', t('Field required')),
new Validators\Required('link_id', t('Field required')),
new Validators\NotEquals('opposite_task_id', 'task_id', t('A task cannot be linked to itself')),
- new Validators\Exists('opposite_task_id', t('This linked task id doesn\'t exists'), $this->db->getConnection(), Task::TABLE, 'id')
+ new Validators\Exists('opposite_task_id', t('This linked task id doesn\'t exists'), $this->db->getConnection(), TaskModel::TABLE, 'id')
);
}
diff --git a/app/Validator/TaskValidator.php b/app/Validator/TaskValidator.php
index 1a77dd32..7c39ff51 100644
--- a/app/Validator/TaskValidator.php
+++ b/app/Validator/TaskValidator.php
@@ -8,10 +8,10 @@ use SimpleValidator\Validators;
/**
* Task Validator
*
- * @package validator
+ * @package Kanboard\Validator
* @author Frederic Guillot
*/
-class TaskValidator extends Base
+class TaskValidator extends BaseValidator
{
/**
* Common validation rules
@@ -70,6 +70,32 @@ class TaskValidator extends Base
}
/**
+ * Validate task creation
+ *
+ * @access public
+ * @param array $values Form values
+ * @return array $valid, $errors [0] = Success or not, [1] = List of errors
+ */
+ public function validateBulkCreation(array $values)
+ {
+ $rules = array(
+ new Validators\Required('project_id', t('The project is required')),
+ new Validators\Required('tasks', t('Field required')),
+ new Validators\Required('column_id', t('Field required')),
+ new Validators\Required('swimlane_id', t('Field required')),
+ new Validators\Integer('category_id', t('This value must be an integer')),
+ new Validators\Integer('swimlane_id', t('This value must be an integer')),
+ );
+
+ $v = new Validator($values, array_merge($rules, $this->commonValidationRules()));
+
+ return array(
+ $v->execute(),
+ $v->getErrors()
+ );
+ }
+
+ /**
* Validate description creation
*
* @access public
diff --git a/app/Validator/UserValidator.php b/app/Validator/UserValidator.php
index e5953f30..9911de50 100644
--- a/app/Validator/UserValidator.php
+++ b/app/Validator/UserValidator.php
@@ -4,15 +4,15 @@ namespace Kanboard\Validator;
use SimpleValidator\Validator;
use SimpleValidator\Validators;
-use Kanboard\Model\User;
+use Kanboard\Model\UserModel;
/**
* User Validator
*
- * @package validator
+ * @package Kanboard\Validator
* @author Frederic Guillot
*/
-class UserValidator extends Base
+class UserValidator extends BaseValidator
{
/**
* Common validation rules
@@ -25,7 +25,7 @@ class UserValidator extends Base
return array(
new Validators\MaxLength('role', t('The maximum length is %d characters', 25), 25),
new Validators\MaxLength('username', t('The maximum length is %d characters', 50), 50),
- new Validators\Unique('username', t('The username must be unique'), $this->db->getConnection(), User::TABLE, 'id'),
+ new Validators\Unique('username', t('The username must be unique'), $this->db->getConnection(), UserModel::TABLE, 'id'),
new Validators\Email('email', t('Email address invalid')),
new Validators\Integer('is_ldap_user', t('This value must be an integer')),
);
diff --git a/app/common.php b/app/common.php
index aed07a50..72be3603 100644
--- a/app/common.php
+++ b/app/common.php
@@ -2,16 +2,17 @@
require __DIR__.'/../vendor/autoload.php';
-// Automatically parse environment configuration (Heroku)
-if (getenv('DATABASE_URL')) {
- $dbopts = parse_url(getenv('DATABASE_URL'));
-
- define('DB_DRIVER', $dbopts['scheme']);
- define('DB_USERNAME', $dbopts["user"]);
- define('DB_PASSWORD', $dbopts["pass"]);
- define('DB_HOSTNAME', $dbopts["host"]);
- define('DB_PORT', isset($dbopts["port"]) ? $dbopts["port"] : null);
- define('DB_NAME', ltrim($dbopts["path"], '/'));
+$dbUrlParser = new PicoDb\UrlParser();
+
+if ($dbUrlParser->isEnvironmentVariableDefined()) {
+ $dbSettings = $dbUrlParser->getSettings();
+
+ define('DB_DRIVER', $dbSettings['driver']);
+ define('DB_USERNAME', $dbSettings['username']);
+ define('DB_PASSWORD', $dbSettings['password']);
+ define('DB_HOSTNAME', $dbSettings['hostname']);
+ define('DB_PORT', $dbSettings['port']);
+ define('DB_NAME', $dbSettings['database']);
}
$config_file = implode(DIRECTORY_SEPARATOR, array(__DIR__, '..', 'config.php'));
@@ -30,18 +31,22 @@ require __DIR__.'/constants.php';
require __DIR__.'/check_setup.php';
$container = new Pimple\Container;
-$container->register(new Kanboard\ServiceProvider\HelperProvider);
-$container->register(new Kanboard\ServiceProvider\SessionProvider);
-$container->register(new Kanboard\ServiceProvider\LoggingProvider);
-$container->register(new Kanboard\ServiceProvider\DatabaseProvider);
-$container->register(new Kanboard\ServiceProvider\AuthenticationProvider);
-$container->register(new Kanboard\ServiceProvider\NotificationProvider);
-$container->register(new Kanboard\ServiceProvider\ClassProvider);
-$container->register(new Kanboard\ServiceProvider\EventDispatcherProvider);
-$container->register(new Kanboard\ServiceProvider\GroupProvider);
-$container->register(new Kanboard\ServiceProvider\RouteProvider);
-$container->register(new Kanboard\ServiceProvider\ActionProvider);
-$container->register(new Kanboard\ServiceProvider\ExternalLinkProvider);
-$container->register(new Kanboard\ServiceProvider\AvatarProvider);
-$container->register(new Kanboard\ServiceProvider\FilterProvider);
-$container->register(new Kanboard\ServiceProvider\PluginProvider);
+$container->register(new Kanboard\ServiceProvider\MailProvider());
+$container->register(new Kanboard\ServiceProvider\HelperProvider());
+$container->register(new Kanboard\ServiceProvider\SessionProvider());
+$container->register(new Kanboard\ServiceProvider\LoggingProvider());
+$container->register(new Kanboard\ServiceProvider\DatabaseProvider());
+$container->register(new Kanboard\ServiceProvider\AuthenticationProvider());
+$container->register(new Kanboard\ServiceProvider\NotificationProvider());
+$container->register(new Kanboard\ServiceProvider\ClassProvider());
+$container->register(new Kanboard\ServiceProvider\EventDispatcherProvider());
+$container->register(new Kanboard\ServiceProvider\GroupProvider());
+$container->register(new Kanboard\ServiceProvider\RouteProvider());
+$container->register(new Kanboard\ServiceProvider\ActionProvider());
+$container->register(new Kanboard\ServiceProvider\ExternalLinkProvider());
+$container->register(new Kanboard\ServiceProvider\AvatarProvider());
+$container->register(new Kanboard\ServiceProvider\FilterProvider());
+$container->register(new Kanboard\ServiceProvider\QueueProvider());
+$container->register(new Kanboard\ServiceProvider\ApiProvider());
+$container->register(new Kanboard\ServiceProvider\CommandProvider());
+$container->register(new Kanboard\ServiceProvider\PluginProvider());
diff --git a/app/constants.php b/app/constants.php
index 3dd827b3..3c404d8b 100644
--- a/app/constants.php
+++ b/app/constants.php
@@ -1,17 +1,30 @@
<?php
+// Root directory
+define('ROOT_DIR', __DIR__.DIRECTORY_SEPARATOR.'..');
+
+// App directory
+define('APP_DIR', __DIR__);
+
// Data directory location
-defined('DATA_DIR') or define('DATA_DIR', implode(DIRECTORY_SEPARATOR, array(__DIR__, '..', 'data')));
+defined('DATA_DIR') or define('DATA_DIR', ROOT_DIR.DIRECTORY_SEPARATOR.'data');
// Files directory (attachments)
defined('FILES_DIR') or define('FILES_DIR', DATA_DIR.DIRECTORY_SEPARATOR.'files');
-// Plugins directory
-defined('PLUGINS_DIR') or define('PLUGINS_DIR', implode(DIRECTORY_SEPARATOR, array(__DIR__, '..', 'plugins')));
+// Plugins settings
+defined('PLUGINS_DIR') or define('PLUGINS_DIR', ROOT_DIR.DIRECTORY_SEPARATOR.'plugins');
+defined('PLUGIN_API_URL') or define('PLUGIN_API_URL', 'https://kanboard.net/plugins.json');
+defined('PLUGIN_INSTALLER') or define('PLUGIN_INSTALLER', true);
// Enable/disable debug
-defined('DEBUG') or define('DEBUG', getenv('DEBUG'));
-defined('DEBUG_FILE') or define('DEBUG_FILE', getenv('DEBUG_FILE') ?: DATA_DIR.DIRECTORY_SEPARATOR.'debug.log');
+defined('DEBUG') or define('DEBUG', strtolower(getenv('DEBUG')) === 'true');
+
+// Logging drivers: syslog, stdout, stderr or file
+defined('LOG_DRIVER') or define('LOG_DRIVER', getenv('LOG_DRIVER'));
+
+// Logging file
+defined('LOG_FILE') or define('LOG_FILE', DATA_DIR.DIRECTORY_SEPARATOR.'debug.log');
// Application version
defined('APP_VERSION') or define('APP_VERSION', build_app_version('$Format:%d$', '$Format:%H$'));
@@ -28,6 +41,9 @@ defined('DB_PASSWORD') or define('DB_PASSWORD', '');
defined('DB_HOSTNAME') or define('DB_HOSTNAME', 'localhost');
defined('DB_NAME') or define('DB_NAME', 'kanboard');
defined('DB_PORT') or define('DB_PORT', null);
+defined('DB_SSL_KEY') or define('DB_SSL_KEY', null);
+defined('DB_SSL_CERT') or define('DB_SSL_CERT', null);
+defined('DB_SSL_CA') or define('DB_SSL_CA', null);
// Database backend group provider
defined('DB_GROUP_PROVIDER') or define('DB_GROUP_PROVIDER', true);
@@ -50,6 +66,8 @@ defined('LDAP_USER_ATTRIBUTE_USERNAME') or define('LDAP_USER_ATTRIBUTE_USERNAME'
defined('LDAP_USER_ATTRIBUTE_FULLNAME') or define('LDAP_USER_ATTRIBUTE_FULLNAME', 'cn');
defined('LDAP_USER_ATTRIBUTE_EMAIL') or define('LDAP_USER_ATTRIBUTE_EMAIL', 'mail');
defined('LDAP_USER_ATTRIBUTE_GROUPS') or define('LDAP_USER_ATTRIBUTE_GROUPS', 'memberof');
+defined('LDAP_USER_ATTRIBUTE_PHOTO') or define('LDAP_USER_ATTRIBUTE_PHOTO', '');
+defined('LDAP_USER_ATTRIBUTE_LANGUAGE') or define('LDAP_USER_ATTRIBUTE_LANGUAGE', '');
defined('LDAP_USER_CREATION') or define('LDAP_USER_CREATION', true);
defined('LDAP_GROUP_ADMIN_DN') or define('LDAP_GROUP_ADMIN_DN', '');
@@ -58,6 +76,7 @@ defined('LDAP_GROUP_MANAGER_DN') or define('LDAP_GROUP_MANAGER_DN', '');
defined('LDAP_GROUP_PROVIDER') or define('LDAP_GROUP_PROVIDER', false);
defined('LDAP_GROUP_BASE_DN') or define('LDAP_GROUP_BASE_DN', '');
defined('LDAP_GROUP_FILTER') or define('LDAP_GROUP_FILTER', '');
+defined('LDAP_GROUP_USER_FILTER') or define('LDAP_GROUP_USER_FILTER', '');
defined('LDAP_GROUP_ATTRIBUTE_NAME') or define('LDAP_GROUP_ATTRIBUTE_NAME', 'cn');
// Proxy authentication
@@ -85,9 +104,6 @@ defined('ENABLE_HSTS') or define('ENABLE_HSTS', true);
// Enable or disable "X-Frame-Options: DENY" HTTP header
defined('ENABLE_XFRAME') or define('ENABLE_XFRAME', true);
-// Syslog
-defined('ENABLE_SYSLOG') or define('ENABLE_SYSLOG', getenv('ENABLE_SYSLOG'));
-
// Escape html inside markdown text
defined('MARKDOWN_ESCAPE_HTML') or define('MARKDOWN_ESCAPE_HTML', true);