diff options
Diffstat (limited to 'app')
104 files changed, 1709 insertions, 701 deletions
diff --git a/app/Api/File.php b/app/Api/File.php index 269803e1..e4204e6d 100644 --- a/app/Api/File.php +++ b/app/Api/File.php @@ -2,6 +2,7 @@ namespace Kanboard\Api; +use Kanboard\Core\Base; use Kanboard\Core\ObjectStorage\ObjectStorageException; /** @@ -10,22 +11,22 @@ use Kanboard\Core\ObjectStorage\ObjectStorageException; * @package api * @author Frederic Guillot */ -class File extends \Kanboard\Core\Base +class File extends Base { - public function getFile($file_id) + public function getTaskFile($file_id) { - return $this->file->getById($file_id); + return $this->taskFile->getById($file_id); } - public function getAllFiles($task_id) + public function getAllTaskFiles($task_id) { - return $this->file->getAll($task_id); + return $this->taskFile->getAll($task_id); } - public function downloadFile($file_id) + public function downloadTaskFile($file_id) { try { - $file = $this->file->getById($file_id); + $file = $this->taskFile->getById($file_id); if (! empty($file)) { return base64_encode($this->objectStorage->get($file['path'])); @@ -36,23 +37,55 @@ class File extends \Kanboard\Core\Base } } - public function createFile($project_id, $task_id, $filename, $blob) + public function createTaskFile($project_id, $task_id, $filename, $blob) { try { - return $this->file->uploadContent($project_id, $task_id, $filename, $blob); + return $this->taskFile->uploadContent($task_id, $filename, $blob); } catch (ObjectStorageException $e) { $this->logger->error($e->getMessage()); return false; } } + public function removeTaskFile($file_id) + { + return $this->taskFile->remove($file_id); + } + + public function removeAllTaskFiles($task_id) + { + return $this->taskFile->removeAll($task_id); + } + + // Deprecated procedures + + public function getFile($file_id) + { + return $this->getTaskFile($file_id); + } + + public function getAllFiles($task_id) + { + return $this->getAllTaskFiles($task_id); + } + + public function downloadFile($file_id) + { + return $this->downloadTaskFile($file_id); + } + + public function createFile($project_id, $task_id, $filename, $blob) + { + return $this->createTaskFile($project_id, $task_id, $filename, $blob); + } + public function removeFile($file_id) { - return $this->file->remove($file_id); + return $this->removeTaskFile($file_id); } public function removeAllFiles($task_id) { - return $this->file->removeAll($task_id); + return $this->removeAllTaskFiles($task_id); } } diff --git a/app/Api/Me.php b/app/Api/Me.php index df8ec070..ccc809ed 100644 --- a/app/Api/Me.php +++ b/app/Api/Me.php @@ -38,6 +38,10 @@ class Me extends Base public function createMyPrivateProject($name, $description = null) { + if ($this->config->get('disable_private_project', 0) == 1) { + return false; + } + $values = array( 'name' => $name, 'description' => $description, diff --git a/app/Api/User.php b/app/Api/User.php index 9f26615d..48337ac6 100644 --- a/app/Api/User.php +++ b/app/Api/User.php @@ -36,6 +36,21 @@ class User extends \Kanboard\Core\Base return $this->user->remove($user_id); } + public function disableUser($user_id) + { + return $this->user->disable($user_id); + } + + public function enableUser($user_id) + { + return $this->user->enable($user_id); + } + + public function isActiveUser($user_id) + { + return $this->user->isActive($user_id); + } + public function createUser($username, $password, $name = '', $email = '', $role = Role::APP_USER) { $values = array( diff --git a/app/Auth/DatabaseAuth.php b/app/Auth/DatabaseAuth.php index 5a8ee64d..c13af687 100644 --- a/app/Auth/DatabaseAuth.php +++ b/app/Auth/DatabaseAuth.php @@ -65,6 +65,7 @@ class DatabaseAuth extends Base implements PasswordAuthenticationProviderInterfa ->eq('username', $this->username) ->eq('disable_login_form', 0) ->eq('is_ldap_user', 0) + ->eq('is_active', 1) ->findOne(); if (! empty($user) && password_verify($this->password, $user['password'])) { @@ -83,7 +84,7 @@ class DatabaseAuth extends Base implements PasswordAuthenticationProviderInterfa */ public function isValidSession() { - return $this->user->exists($this->userSession->getId()); + return $this->user->isActive($this->userSession->getId()); } /** diff --git a/app/Controller/Auth.php b/app/Controller/Auth.php index fef7f0e3..b98dff5d 100644 --- a/app/Controller/Auth.php +++ b/app/Controller/Auth.php @@ -55,8 +55,13 @@ class Auth extends Base */ public function logout() { - $this->sessionManager->close(); - $this->response->redirect($this->helper->url->to('auth', 'login')); + if (! DISABLE_LOGOUT) { + $this->sessionManager->close(); + $this->response->redirect($this->helper->url->to('auth', 'login')); + } + else { + $this->response->redirect($this->helper->url->to('auth', 'index')); + } } /** diff --git a/app/Controller/BoardPopover.php b/app/Controller/BoardPopover.php index f2b39d8d..965669ff 100644 --- a/app/Controller/BoardPopover.php +++ b/app/Controller/BoardPopover.php @@ -93,7 +93,7 @@ class BoardPopover extends Base { $task = $this->getTask(); - $this->response->html($this->template->render('file/screenshot', array( + $this->response->html($this->template->render('task_file/screenshot', array( 'task' => $task, ))); } diff --git a/app/Controller/BoardTooltip.php b/app/Controller/BoardTooltip.php index da07ec4e..bc07ce09 100644 --- a/app/Controller/BoardTooltip.php +++ b/app/Controller/BoardTooltip.php @@ -62,7 +62,7 @@ class BoardTooltip extends Base $task = $this->getTask(); $this->response->html($this->template->render('board/tooltip_files', array( - 'files' => $this->file->getAll($task['id']), + 'files' => $this->taskFile->getAll($task['id']), 'task' => $task, ))); } diff --git a/app/Controller/Config.php b/app/Controller/Config.php index 80522bbe..e811f870 100644 --- a/app/Controller/Config.php +++ b/app/Controller/Config.php @@ -26,7 +26,12 @@ class Config extends Base $values += array('password_reset' => 0); break; case 'project': - $values += array('subtask_restriction' => 0, 'subtask_time_tracking' => 0, 'cfd_include_closed_tasks' => 0); + $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); diff --git a/app/Controller/Customfilter.php b/app/Controller/Customfilter.php index da7eb77b..41da0b11 100644 --- a/app/Controller/Customfilter.php +++ b/app/Controller/Customfilter.php @@ -57,6 +57,23 @@ class Customfilter extends Base } /** + * Confirmation dialog before removing a custom filter + * + * @access public + */ + public function confirm() + { + $project = $this->getProject(); + $filter = $this->customFilter->getById($this->request->getIntegerParam('filter_id')); + + $this->response->html($this->helper->layout->project('custom_filter/remove', array( + 'project' => $project, + 'filter' => $filter, + 'title' => t('Remove a custom filter') + ))); + } + + /** * Remove a custom filter * * @access public diff --git a/app/Controller/Gantt.php b/app/Controller/Gantt.php index 2d1edc08..5dbd1243 100644 --- a/app/Controller/Gantt.php +++ b/app/Controller/Gantt.php @@ -108,6 +108,7 @@ class Gantt extends Base ); $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, diff --git a/app/Controller/Listing.php b/app/Controller/Listing.php index c7d3d9a8..c784dd50 100644 --- a/app/Controller/Listing.php +++ b/app/Controller/Listing.php @@ -32,6 +32,9 @@ class Listing extends Base $this->response->html($this->helper->layout->app('listing/show', $params + array( 'paginator' => $paginator, + 'categories_list' => $this->category->getList($params['project']['id'], false), + 'users_list' => $this->projectUserRole->getAssignableUsersList($params['project']['id'], false), + 'custom_filters_list' => $this->customFilter->getAll($params['project']['id'], $this->userSession->getId()), ))); } } diff --git a/app/Controller/Projectuser.php b/app/Controller/Projectuser.php index 9cd21021..a6d4fe4e 100644 --- a/app/Controller/Projectuser.php +++ b/app/Controller/Projectuser.php @@ -24,7 +24,7 @@ class Projectuser extends Base $project_ids = $this->projectPermission->getActiveProjectIds($this->userSession->getId()); } - return array($user_id, $project_ids, $this->user->getList(true)); + return array($user_id, $project_ids, $this->user->getActiveUsersList(true)); } private function role($role, $action, $title, $title_user) @@ -33,7 +33,7 @@ class Projectuser extends Base $query = $this->projectPermission->getQueryByRole($project_ids, $role)->callback(array($this->project, 'applyColumnStats')); - if ($user_id !== UserModel::EVERYBODY_ID) { + if ($user_id !== UserModel::EVERYBODY_ID && isset($users[$user_id])) { $query->eq(UserModel::TABLE.'.id', $user_id); $title = t($title_user, $users[$user_id]); } @@ -59,7 +59,7 @@ class Projectuser extends Base $query = $this->taskFinder->getProjectUserOverviewQuery($project_ids, $is_active); - if ($user_id !== UserModel::EVERYBODY_ID) { + if ($user_id !== UserModel::EVERYBODY_ID && isset($users[$user_id])) { $query->eq(TaskModel::TABLE.'.owner_id', $user_id); $title = t($title_user, $users[$user_id]); } diff --git a/app/Controller/Task.php b/app/Controller/Task.php index 4db8f86e..98b7a041 100644 --- a/app/Controller/Task.php +++ b/app/Controller/Task.php @@ -66,8 +66,8 @@ class Task extends Base $this->response->html($this->helper->layout->task('task/show', array( 'project' => $this->project->getById($task['project_id']), - 'files' => $this->file->getAllDocuments($task['id']), - 'images' => $this->file->getAllImages($task['id']), + 'files' => $this->taskFile->getAllDocuments($task['id']), + 'images' => $this->taskFile->getAllImages($task['id']), 'comments' => $this->comment->getAll($task['id'], $this->userSession->getCommentSorting()), 'subtasks' => $subtasks, 'links' => $this->taskLink->getAllGroupedByLabel($task['id']), diff --git a/app/Controller/File.php b/app/Controller/TaskFile.php index 50db3865..102fdc5c 100644 --- a/app/Controller/File.php +++ b/app/Controller/TaskFile.php @@ -5,12 +5,12 @@ namespace Kanboard\Controller; use Kanboard\Core\ObjectStorage\ObjectStorageException; /** - * File controller + * File File Controller * * @package controller * @author Frederic Guillot */ -class File extends Base +class TaskFile extends Base { /** * Screenshot @@ -21,12 +21,12 @@ class File extends Base { $task = $this->getTask(); - if ($this->request->isPost() && $this->file->uploadScreenshot($task['project_id'], $task['id'], $this->request->getValue('screenshot')) !== false) { + if ($this->request->isPost() && $this->taskFile->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); } - $this->response->html($this->helper->layout->task('file/screenshot', array( + $this->response->html($this->helper->layout->task('task_file/screenshot', array( 'task' => $task, ))); } @@ -40,9 +40,9 @@ class File extends Base { $task = $this->getTask(); - $this->response->html($this->helper->layout->task('file/new', array( + $this->response->html($this->helper->layout->task('task_file/new', array( 'task' => $task, - 'max_size' => ini_get('upload_max_filesize'), + 'max_size' => $this->helper->text->phpToBytes(ini_get('upload_max_filesize')), ))); } @@ -55,7 +55,7 @@ class File extends Base { $task = $this->getTask(); - if (! $this->file->uploadFiles($task['project_id'], $task['id'], 'files')) { + if (! $this->taskFile->uploadFiles($task['id'], $this->request->getFileInfo('files'))) { $this->flash->failure(t('Unable to upload the file.')); } @@ -71,7 +71,7 @@ class File extends Base { try { $task = $this->getTask(); - $file = $this->file->getById($this->request->getIntegerParam('file_id')); + $file = $this->taskFile->getById($this->request->getIntegerParam('file_id')); if ($file['task_id'] != $task['id']) { $this->response->redirect($this->helper->url->to('task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']))); @@ -92,10 +92,10 @@ class File extends Base public function open() { $task = $this->getTask(); - $file = $this->file->getById($this->request->getIntegerParam('file_id')); + $file = $this->taskFile->getById($this->request->getIntegerParam('file_id')); if ($file['task_id'] == $task['id']) { - $this->response->html($this->template->render('file/open', array( + $this->response->html($this->template->render('task_file/open', array( 'file' => $file, 'task' => $task, ))); @@ -111,10 +111,10 @@ class File extends Base { try { $task = $this->getTask(); - $file = $this->file->getById($this->request->getIntegerParam('file_id')); + $file = $this->taskFile->getById($this->request->getIntegerParam('file_id')); if ($file['task_id'] == $task['id']) { - $this->response->contentType($this->file->getImageMimeType($file['name'])); + $this->response->contentType($this->taskFile->getImageMimeType($file['name'])); $this->objectStorage->output($file['path']); } } catch (ObjectStorageException $e) { @@ -133,18 +133,18 @@ class File extends Base try { $task = $this->getTask(); - $file = $this->file->getById($this->request->getIntegerParam('file_id')); + $file = $this->taskFile->getById($this->request->getIntegerParam('file_id')); if ($file['task_id'] == $task['id']) { - $this->objectStorage->output($this->file->getThumbnailPath($file['path'])); + $this->objectStorage->output($this->taskFile->getThumbnailPath($file['path'])); } } 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->file->generateThumbnailFromData($file['path'], $data); - $this->objectStorage->output($this->file->getThumbnailPath($file['path'])); + $this->taskFile->generateThumbnailFromData($file['path'], $data); + $this->objectStorage->output($this->taskFile->getThumbnailPath($file['path'])); } } @@ -157,9 +157,9 @@ class File extends Base { $this->checkCSRFParam(); $task = $this->getTask(); - $file = $this->file->getById($this->request->getIntegerParam('file_id')); + $file = $this->taskFile->getById($this->request->getIntegerParam('file_id')); - if ($file['task_id'] == $task['id'] && $this->file->remove($file['id'])) { + if ($file['task_id'] == $task['id'] && $this->taskFile->remove($file['id'])) { $this->flash->success(t('File removed successfully.')); } else { $this->flash->failure(t('Unable to remove this file.')); @@ -176,9 +176,9 @@ class File extends Base public function confirm() { $task = $this->getTask(); - $file = $this->file->getById($this->request->getIntegerParam('file_id')); + $file = $this->taskFile->getById($this->request->getIntegerParam('file_id')); - $this->response->html($this->helper->layout->task('file/remove', array( + $this->response->html($this->helper->layout->task('task_file/remove', array( 'task' => $task, 'file' => $file, ))); diff --git a/app/Controller/Taskcreation.php b/app/Controller/Taskcreation.php index e661587c..f1ac7272 100644 --- a/app/Controller/Taskcreation.php +++ b/app/Controller/Taskcreation.php @@ -29,6 +29,7 @@ class Taskcreation extends Base ); $values = $this->hook->merge('controller:task:form:default', $values, array('default_values' => $values)); + $values = $this->hook->merge('controller:task-creation:form:default', $values, array('default_values' => $values)); } $this->response->html($this->template->render('task_creation/form', array( diff --git a/app/Controller/Taskmodification.php b/app/Controller/Taskmodification.php index a321322d..306d34c0 100644 --- a/app/Controller/Taskmodification.php +++ b/app/Controller/Taskmodification.php @@ -80,6 +80,7 @@ class Taskmodification extends Base if (empty($values)) { $values = $task; $values = $this->hook->merge('controller:task:form:default', $values, array('default_values' => $values)); + $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', 'm/d/Y')); diff --git a/app/Controller/User.php b/app/Controller/User.php index 881266d4..f7d7d2e0 100644 --- a/app/Controller/User.php +++ b/app/Controller/User.php @@ -32,7 +32,8 @@ class User extends Base $this->helper->layout->app('user/index', array( 'title' => t('Users').' ('.$paginator->getTotal().')', 'paginator' => $paginator, - ))); + ) + )); } /** @@ -404,30 +405,4 @@ class User extends Base 'user' => $user, ))); } - - /** - * Remove a user - * - * @access public - */ - public function remove() - { - $user = $this->getUser(); - - if ($this->request->getStringParam('confirmation') === 'yes') { - $this->checkCSRFParam(); - - if ($this->user->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->html($this->helper->layout->user('user/remove', array( - 'user' => $user, - ))); - } } diff --git a/app/Controller/UserStatus.php b/app/Controller/UserStatus.php new file mode 100644 index 00000000..b8ee5c91 --- /dev/null +++ b/app/Controller/UserStatus.php @@ -0,0 +1,111 @@ +<?php + +namespace Kanboard\Controller; + +/** + * User Status Controller + * + * @package controller + * @author Frederic Guillot + */ +class UserStatus extends Base +{ + /** + * Confirm remove a user + * + * @access public + */ + public function confirmRemove() + { + $user = $this->getUser(); + + $this->response->html($this->helper->layout->user('user_status/remove', array( + 'user' => $user, + ))); + } + + /** + * Remove a user + * + * @access public + */ + public function remove() + { + $user = $this->getUser(); + $this->checkCSRFParam(); + + if ($this->user->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')); + } + + /** + * Confirm enable a user + * + * @access public + */ + public function confirmEnable() + { + $user = $this->getUser(); + + $this->response->html($this->helper->layout->user('user_status/enable', array( + 'user' => $user, + ))); + } + + /** + * Enable a user + * + * @access public + */ + public function enable() + { + $user = $this->getUser(); + $this->checkCSRFParam(); + + if ($this->user->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')); + } + + /** + * Confirm disable a user + * + * @access public + */ + public function confirmDisable() + { + $user = $this->getUser(); + + $this->response->html($this->helper->layout->user('user_status/disable', array( + 'user' => $user, + ))); + } + + /** + * Disable a user + * + * @access public + */ + public function disable() + { + $user = $this->getUser(); + $this->checkCSRFParam(); + + if ($this->user->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')); + } +} diff --git a/app/Core/Base.php b/app/Core/Base.php index ab99fcea..31c07355 100644 --- a/app/Core/Base.php +++ b/app/Core/Base.php @@ -67,7 +67,8 @@ use Pimple\Container; * @property \Kanboard\Model\Config $config * @property \Kanboard\Model\Currency $currency * @property \Kanboard\Model\CustomFilter $customFilter - * @property \Kanboard\Model\File $file + * @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 diff --git a/app/Core/User/UserProfile.php b/app/Core/User/UserProfile.php index ccbc7f06..ef325801 100644 --- a/app/Core/User/UserProfile.php +++ b/app/Core/User/UserProfile.php @@ -52,7 +52,7 @@ class UserProfile extends Base $this->groupSync->synchronize($profile['id'], $user->getExternalGroupIds()); } - if (! empty($profile)) { + if (! empty($profile) && $profile['is_active'] == 1) { $this->userSession->initialize($profile); return true; } diff --git a/app/Helper/App.php b/app/Helper/App.php index 0593795f..79afa5b9 100644 --- a/app/Helper/App.php +++ b/app/Helper/App.php @@ -17,11 +17,12 @@ class App extends Base * * @access public * @param string $param + * @param mixed $default_value * @return mixed */ - public function config($param) + public function config($param, $default_value = '') { - return $this->config->get($param); + return $this->config->get($param, $default_value); } /** diff --git a/app/Helper/File.php b/app/Helper/File.php index d2cdfc6a..20eda1e3 100644 --- a/app/Helper/File.php +++ b/app/Helper/File.php @@ -38,15 +38,20 @@ class File extends \Kanboard\Core\Base return 'fa-file-powerpoint-o'; case 'zip': case 'rar': + case 'tar': + case 'bz2': + case 'xz': + case 'gz': return 'fa-file-archive-o'; case 'mp3': - return 'fa-audio-o'; + return 'fa-file-audio-o'; case 'avi': - return 'fa-video-o'; + case 'mov': + return 'fa-file-video-o'; case 'php': case 'html': case 'css': - return 'fa-code-o'; + return 'fa-file-code-o'; case 'pdf': return 'fa-file-pdf-o'; } diff --git a/app/Helper/Text.php b/app/Helper/Text.php index 59bfd997..83f1e3f9 100644 --- a/app/Helper/Text.php +++ b/app/Helper/Text.php @@ -43,6 +43,29 @@ class Text extends Base } /** + * Get the number of bytes from PHP size + * + * @param integer $val PHP size (example: 2M) + * @return integer + */ + public function phpToBytes($val) + { + $val = trim($val); + $last = strtolower($val[strlen($val)-1]); + + switch ($last) { + case 'g': + $val *= 1024; + case 'm': + $val *= 1024; + case 'k': + $val *= 1024; + } + + return $val; + } + + /** * Return true if needle is contained in the haystack * * @param string $haystack Haystack diff --git a/app/Locale/bs_BA/translations.php b/app/Locale/bs_BA/translations.php index e331d4a1..69b04c38 100644 --- a/app/Locale/bs_BA/translations.php +++ b/app/Locale/bs_BA/translations.php @@ -598,8 +598,6 @@ return array( 'Compact/wide view' => 'Skupi/raširi pregled', 'No results match:' => 'Nema rezultata:', 'Currency' => 'Valuta', - 'Files' => 'Fajlovi', - 'Images' => 'Slike', 'Private project' => 'Privatni projekat', 'AUD - Australian Dollar' => 'AUD - Australijski dolar', 'CAD - Canadian Dollar' => 'CAD - Kanadski dolar', @@ -645,9 +643,6 @@ return array( 'Test your device' => 'Testiraj svoj uređaj', 'Assign a color when the task is moved to a specific column' => 'Dodijeli boju kada je zadatak pomjeren u odabranu kolonu', '%s via Kanboard' => '%s uz pomoć Kanboard-a', - 'uploaded by: %s' => 'dodano od strane: %s', - 'uploaded on: %s' => 'dodano na: %s', - 'size: %s' => 'veličina: %s', 'Burndown chart for "%s"' => 'Grafikon izgaranja za "%s"', 'Burndown chart' => 'Grafikon izgaranja', 'This chart show the task complexity over the time (Work Remaining).' => 'Ovaj grafikon pokazuje kompleksnost zadatka u vremenu (Preostalo vremena)', @@ -1118,4 +1113,29 @@ return array( // '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' => '', ); diff --git a/app/Locale/cs_CZ/translations.php b/app/Locale/cs_CZ/translations.php index a495f01e..c4360d3a 100644 --- a/app/Locale/cs_CZ/translations.php +++ b/app/Locale/cs_CZ/translations.php @@ -598,8 +598,6 @@ return array( 'Compact/wide view' => 'Kompaktní/plné zobrazení', 'No results match:' => 'Žádná shoda:', 'Currency' => 'Měna', - 'Files' => 'Soubory', - 'Images' => 'Obrázky', 'Private project' => 'Soukromý projekt', // 'AUD - Australian Dollar' => '', // 'CAD - Canadian Dollar' => '', @@ -645,9 +643,6 @@ return array( 'Test your device' => 'Test Vašeho zařízení', 'Assign a color when the task is moved to a specific column' => 'Přiřadit barvu, když je úkol přesunut do konkrétního sloupce', '%s via Kanboard' => '%s via Kanboard', - 'uploaded by: %s' => 'Nahráno uživatelem: %s', - 'uploaded on: %s' => 'Nahráno dne: %s', - 'size: %s' => 'Velikost: %s', 'Burndown chart for "%s"' => 'Burndown-Chart für "%s"', 'Burndown chart' => 'Burndown-Chart', 'This chart show the task complexity over the time (Work Remaining).' => 'Graf zobrazuje složitost úkolů v čase (Zbývající práce).', @@ -1118,4 +1113,29 @@ return array( // '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' => '', ); diff --git a/app/Locale/da_DK/translations.php b/app/Locale/da_DK/translations.php index 537b6349..cc296df0 100644 --- a/app/Locale/da_DK/translations.php +++ b/app/Locale/da_DK/translations.php @@ -598,8 +598,6 @@ return array( // 'Compact/wide view' => '', // 'No results match:' => '', // 'Currency' => '', - // 'Files' => '', - // 'Images' => '', // 'Private project' => '', // 'AUD - Australian Dollar' => '', // 'CAD - Canadian Dollar' => '', @@ -645,9 +643,6 @@ return array( // 'Test your device' => '', // 'Assign a color when the task is moved to a specific column' => '', // '%s via Kanboard' => '', - // 'uploaded by: %s' => '', - // 'uploaded on: %s' => '', - // 'size: %s' => '', // 'Burndown chart for "%s"' => '', // 'Burndown chart' => '', // 'This chart show the task complexity over the time (Work Remaining).' => '', @@ -1118,4 +1113,29 @@ return array( // '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' => '', ); diff --git a/app/Locale/de_DE/translations.php b/app/Locale/de_DE/translations.php index ba6a1fd4..1431d79a 100644 --- a/app/Locale/de_DE/translations.php +++ b/app/Locale/de_DE/translations.php @@ -598,8 +598,6 @@ return array( 'Compact/wide view' => 'Kompakt/Breite-Ansicht', 'No results match:' => 'Keine Ergebnisse:', 'Currency' => 'Währung', - 'Files' => 'Dateien', - 'Images' => 'Bilder', 'Private project' => 'privates Projekt', 'AUD - Australian Dollar' => 'AUD - Australische Dollar', 'CAD - Canadian Dollar' => 'CAD - Kanadische Dollar', @@ -645,9 +643,6 @@ return array( 'Test your device' => 'Teste dein Gerät', 'Assign a color when the task is moved to a specific column' => 'Weise eine Farbe zu, wenn die Aufgabe zu einer bestimmten Spalte bewegt wird', '%s via Kanboard' => '%s via Kanboard', - 'uploaded by: %s' => 'Hochgeladen von: %s', - 'uploaded on: %s' => 'Hochgeladen am: %s', - 'size: %s' => 'Größe: %s', 'Burndown chart for "%s"' => 'Burndown-Diagramm für "%s"', 'Burndown chart' => 'Burndown-Diagramm', 'This chart show the task complexity over the time (Work Remaining).' => 'Dieses Diagramm zeigt die Aufgabenkomplexität über den Faktor Zeit (Verbleibende Arbeit).', @@ -1118,4 +1113,29 @@ return array( // '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' => '', ); diff --git a/app/Locale/el_GR/translations.php b/app/Locale/el_GR/translations.php index 01b31819..689d6b20 100644 --- a/app/Locale/el_GR/translations.php +++ b/app/Locale/el_GR/translations.php @@ -598,8 +598,6 @@ return array( 'Compact/wide view' => 'Συμπηκνωμένη/Ευρεία Προβολή', 'No results match:' => 'Δεν ταιριάζει κανένα αποτέλεσμα :', 'Currency' => 'Νόμισμα', - 'Files' => 'Αρχεία', - 'Images' => 'Εικόνες', 'Private project' => 'Ιδιωτικό έργο', 'AUD - Australian Dollar' => 'AUD - Australian Dollar', 'CAD - Canadian Dollar' => 'CAD - Canadian Dollar', @@ -645,9 +643,6 @@ return array( 'Test your device' => 'Ελέγξτε τη συσκευή σας', 'Assign a color when the task is moved to a specific column' => 'Αντιστοίχιση χρώματος όταν η εργασία κινείται σε μια συγκεκριμένη στήλη', '%s via Kanboard' => '%s via Kanboard', - 'uploaded by: %s' => 'ανέβασμα από %s', - 'uploaded on: %s' => 'ανέβασμα την %s', - 'size: %s' => 'μέγεθος : %s', 'Burndown chart for "%s"' => 'Δημιουργία διαγράμματος για « %s »', 'Burndown chart' => 'Δημιουργία διαγράμματος', 'This chart show the task complexity over the time (Work Remaining).' => 'Αυτό το γράφημα δείχνει την πολυπλοκότητα του έργου κατά την πάροδο του χρόνου (Εργασία που παραμένει).', @@ -1118,4 +1113,29 @@ return array( // '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' => '', ); diff --git a/app/Locale/es_ES/translations.php b/app/Locale/es_ES/translations.php index 9c7c6e41..5597f3a1 100644 --- a/app/Locale/es_ES/translations.php +++ b/app/Locale/es_ES/translations.php @@ -598,8 +598,6 @@ return array( 'Compact/wide view' => 'Vista compacta/amplia', 'No results match:' => 'No hay resultados coincidentes:', 'Currency' => 'Moneda', - 'Files' => 'Ficheros', - 'Images' => 'Imágenes', 'Private project' => 'Proyecto privado', 'AUD - Australian Dollar' => 'AUD - Dólar australiano', 'CAD - Canadian Dollar' => 'CAD - Dólar canadiense', @@ -645,9 +643,6 @@ return array( 'Test your device' => 'Probar su dispositivo', 'Assign a color when the task is moved to a specific column' => 'Asignar un color al mover la tarea a una columna específica', '%s via Kanboard' => '%s vía Kanboard', - 'uploaded by: %s' => 'cargado por: %s', - 'uploaded on: %s' => 'cargado en: %s', - 'size: %s' => 'tamaño: %s', 'Burndown chart for "%s"' => 'Trabajo pendiente para "%s"', 'Burndown chart' => 'Trabajo pendiente', 'This chart show the task complexity over the time (Work Remaining).' => 'Este diagrama mestra la complejidad de las tareas a lo largo del tiempo (Trabajo restante)', @@ -1118,4 +1113,29 @@ return array( // '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' => '', ); diff --git a/app/Locale/fi_FI/translations.php b/app/Locale/fi_FI/translations.php index d50765b6..d6aed20f 100644 --- a/app/Locale/fi_FI/translations.php +++ b/app/Locale/fi_FI/translations.php @@ -598,8 +598,6 @@ return array( // 'Compact/wide view' => '', // 'No results match:' => '', // 'Currency' => '', - // 'Files' => '', - // 'Images' => '', // 'Private project' => '', // 'AUD - Australian Dollar' => '', // 'CAD - Canadian Dollar' => '', @@ -645,9 +643,6 @@ return array( // 'Test your device' => '', // 'Assign a color when the task is moved to a specific column' => '', // '%s via Kanboard' => '', - // 'uploaded by: %s' => '', - // 'uploaded on: %s' => '', - // 'size: %s' => '', // 'Burndown chart for "%s"' => '', // 'Burndown chart' => '', // 'This chart show the task complexity over the time (Work Remaining).' => '', @@ -1118,4 +1113,29 @@ return array( // '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' => '', ); diff --git a/app/Locale/fr_FR/translations.php b/app/Locale/fr_FR/translations.php index 90d6dc3d..ac62f397 100644 --- a/app/Locale/fr_FR/translations.php +++ b/app/Locale/fr_FR/translations.php @@ -600,8 +600,6 @@ return array( 'Compact/wide view' => 'Basculer entre la vue compacte et étendue', 'No results match:' => 'Aucun résultat :', 'Currency' => 'Devise', - 'Files' => 'Fichiers', - 'Images' => 'Images', 'Private project' => 'Projet privé', 'AUD - Australian Dollar' => 'AUD - Dollar australien', 'CAD - Canadian Dollar' => 'CAD - Dollar canadien', @@ -647,9 +645,6 @@ return array( 'Test your device' => 'Testez votre appareil', 'Assign a color when the task is moved to a specific column' => 'Assigner une couleur lorsque la tâche est déplacée dans une colonne spécifique', '%s via Kanboard' => '%s via Kanboard', - 'uploaded by: %s' => 'Téléchargé par %s', - 'uploaded on: %s' => 'Téléchargé le %s', - 'size: %s' => 'Taille : %s', 'Burndown chart for "%s"' => 'Graphique d\'avancement pour « %s »', 'Burndown chart' => 'Graphique d\'avancement', 'This chart show the task complexity over the time (Work Remaining).' => 'Ce graphique représente la complexité des tâches en fonction du temps (travail restant).', @@ -1121,4 +1116,29 @@ return array( 'End date: ' => 'Date de fin : ', 'New due date: ' => 'Nouvelle date d\'échéance : ', 'Start date changed: ' => 'Date de début modifiée : ', + 'Disable private projects' => 'Désactiver les projets privés', + 'Do you really want to remove this custom filter: "%s"?' => 'Voulez-vous vraiment supprimer ce filtre personnalisé : « %s » ?', + 'Remove a custom filter' => 'Supprimer un filtre personnalisé', + 'User activated successfully.' => 'Utilisateur activé avec succès.', + 'Unable to enable this user.' => 'Impossible d\'activer cet utilisateur.', + 'User disabled successfully.' => 'Utilisateur désactivé avec succès.', + 'Unable to disable this user.' => 'Impossible de désactiver cet utilisateur.', + 'All files have been uploaded successfully.' => 'Tous les fichiers ont été uploadés avec succès.', + 'View uploaded files' => 'Voir les fichiers uploadés', + 'The maximum allowed file size is %sB.' => 'La taille maximale autorisée pour les fichiers est de %so.', + 'Choose files again' => 'Choisir de nouveau des fichiers', + 'Drag and drop your files here' => 'Glissez-déposez vos fichiers ici', + 'choose files' => 'choisissez des fichiers', + 'View profile' => 'Voir le profile', + 'Two Factor' => 'Deux-Facteurs', + 'Disable user' => 'Désactiver l\'utilisateur', + 'Do you really want to disable this user: "%s"?' => 'Voulez-vous vraiment désactiver cet utilisateur : « %s » ?', + 'Enable user' => 'Activer un utilisateur', + 'Do you really want to enable this user: "%s"?' => 'Voulez-vous vraiment activer cet utilisateur : « %s » ?', + 'Download' => 'Télécharger', + 'Uploaded: %s' => 'Uploadé : %s', + 'Size: %s' => 'Taille : %s', + 'Uploaded by %s' => 'Uploadé par %s', + 'Filename' => 'Nom du fichier', + 'Size' => 'Taille', ); diff --git a/app/Locale/hu_HU/translations.php b/app/Locale/hu_HU/translations.php index 447dafc9..2fd9587d 100644 --- a/app/Locale/hu_HU/translations.php +++ b/app/Locale/hu_HU/translations.php @@ -598,8 +598,6 @@ return array( 'Compact/wide view' => 'Kompakt/széles nézet', 'No results match:' => 'Nincs találat:', 'Currency' => 'Pénznem', - 'Files' => 'Fájlok', - 'Images' => 'Képek', 'Private project' => 'Privát projekt', 'AUD - Australian Dollar' => 'AUD - Ausztrál dollár', 'CAD - Canadian Dollar' => 'CAD - Kanadai dollár', @@ -645,9 +643,6 @@ return array( // 'Test your device' => '', // 'Assign a color when the task is moved to a specific column' => '', // '%s via Kanboard' => '', - // 'uploaded by: %s' => '', - // 'uploaded on: %s' => '', - // 'size: %s' => '', // 'Burndown chart for "%s"' => '', // 'Burndown chart' => '', // 'This chart show the task complexity over the time (Work Remaining).' => '', @@ -1118,4 +1113,29 @@ return array( // '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' => '', ); diff --git a/app/Locale/id_ID/translations.php b/app/Locale/id_ID/translations.php index 8c6db849..f8e465fb 100644 --- a/app/Locale/id_ID/translations.php +++ b/app/Locale/id_ID/translations.php @@ -598,8 +598,6 @@ return array( 'Compact/wide view' => 'Beralih antara tampilan kompak dan diperluas', 'No results match:' => 'Tidak ada hasil :', 'Currency' => 'Mata uang', - 'Files' => 'Arsip', - 'Images' => 'Gambar', 'Private project' => 'Proyek pribadi', 'AUD - Australian Dollar' => 'AUD - Dollar Australia', 'CAD - Canadian Dollar' => 'CAD - Dollar Kanada', @@ -645,9 +643,6 @@ return array( 'Test your device' => 'Menguji perangkat anda', 'Assign a color when the task is moved to a specific column' => 'Menetapkan warna ketika tugas tersebut dipindahkan ke kolom tertentu', '%s via Kanboard' => '%s via Kanboard', - 'uploaded by: %s' => 'diunggah oleh %s', - 'uploaded on: %s' => 'diunggah pada %s', - 'size: %s' => 'ukuran : %s', 'Burndown chart for "%s"' => 'Grafik Burndown untku « %s »', 'Burndown chart' => 'Grafik Burndown', 'This chart show the task complexity over the time (Work Remaining).' => 'Grafik ini menunjukkan kompleksitas tugas dari waktu ke waktu (Sisa Pekerjaan).', @@ -1118,4 +1113,29 @@ return array( // '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' => '', ); diff --git a/app/Locale/it_IT/translations.php b/app/Locale/it_IT/translations.php index 661e6c86..35b3334b 100644 --- a/app/Locale/it_IT/translations.php +++ b/app/Locale/it_IT/translations.php @@ -598,8 +598,6 @@ return array( 'Compact/wide view' => 'Vista compatta/estesa', 'No results match:' => 'Nessun risultato trovato:', 'Currency' => 'Valuta', - 'Files' => 'File', - 'Images' => 'Immagini', 'Private project' => 'Progetto privato', 'AUD - Australian Dollar' => 'AUD - Dollari Australiani', 'CAD - Canadian Dollar' => 'CAD - Dollari Canadesi', @@ -645,9 +643,6 @@ return array( 'Test your device' => 'Testa il tuo dispositivo', 'Assign a color when the task is moved to a specific column' => 'Assegna un colore quando il task viene spostato in una colonna specifica', '%s via Kanboard' => '%s tramite Kanboard', - 'uploaded by: %s' => 'caricato da: %s', - 'uploaded on: %s' => 'caricato su: %s', - 'size: %s' => 'Dimensione: %s', 'Burndown chart for "%s"' => 'Grafico Burndown per "%s"', 'Burndown chart' => 'Grafico Burndown', 'This chart show the task complexity over the time (Work Remaining).' => 'Questo grafico mostra la complessità dei task nel tempo (Lavoro residuo).', @@ -1118,4 +1113,29 @@ return array( // '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' => '', ); diff --git a/app/Locale/ja_JP/translations.php b/app/Locale/ja_JP/translations.php index 3609836b..a08a305e 100644 --- a/app/Locale/ja_JP/translations.php +++ b/app/Locale/ja_JP/translations.php @@ -598,8 +598,6 @@ return array( 'Compact/wide view' => 'コンパクト/ワイドビュー', 'No results match:' => '結果が一致しませんでした', 'Currency' => '通貨', - 'Files' => 'ファイル', - 'Images' => '画像', 'Private project' => 'プライベートプロジェクト', 'AUD - Australian Dollar' => 'AUD - 豪ドル', 'CAD - Canadian Dollar' => 'CAD - 加ドル', @@ -645,9 +643,6 @@ return array( 'Test your device' => 'デバイスをテストする', // 'Assign a color when the task is moved to a specific column' => '', // '%s via Kanboard' => '', - // 'uploaded by: %s' => '', - // 'uploaded on: %s' => '', - // 'size: %s' => '', // 'Burndown chart for "%s"' => '', // 'Burndown chart' => '', // 'This chart show the task complexity over the time (Work Remaining).' => '', @@ -1118,4 +1113,29 @@ return array( // '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' => '', ); diff --git a/app/Locale/my_MY/translations.php b/app/Locale/my_MY/translations.php index 5b1da7cd..d7d3f3cc 100644 --- a/app/Locale/my_MY/translations.php +++ b/app/Locale/my_MY/translations.php @@ -598,8 +598,6 @@ return array( 'Compact/wide view' => 'Beralih antara tampilan kompak dan diperluas', 'No results match:' => 'Tidak ada hasil :', 'Currency' => 'Mata uang', - 'Files' => 'Arsip', - 'Images' => 'Gambar', 'Private project' => 'projek pribadi', 'AUD - Australian Dollar' => 'AUD - Dollar Australia', 'CAD - Canadian Dollar' => 'CAD - Dollar Kanada', @@ -645,9 +643,6 @@ return array( 'Test your device' => 'Menguji perangkat anda', 'Assign a color when the task is moved to a specific column' => 'Menetapkan warna ketika tugas tersebut dipindahkan ke kolom tertentu', '%s via Kanboard' => '%s via Kanboard', - 'uploaded by: %s' => 'diunggah oleh %s', - 'uploaded on: %s' => 'diunggah pada %s', - 'size: %s' => 'ukuran : %s', 'Burndown chart for "%s"' => 'Grafik Burndown untku « %s »', 'Burndown chart' => 'Grafik Burndown', 'This chart show the task complexity over the time (Work Remaining).' => 'Grafik ini menunjukkan kompleksitas tugas dari waktu ke waktu (Sisa Pekerjaan).', @@ -1118,4 +1113,29 @@ return array( // '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' => '', ); diff --git a/app/Locale/nb_NO/translations.php b/app/Locale/nb_NO/translations.php index 335c699b..b55b846e 100644 --- a/app/Locale/nb_NO/translations.php +++ b/app/Locale/nb_NO/translations.php @@ -598,8 +598,6 @@ return array( 'Compact/wide view' => 'Kompakt/bred visning', 'No results match:' => 'Ingen resultater', 'Currency' => 'Valuta', - 'Files' => 'Filer', - 'Images' => 'Bilder', 'Private project' => 'Privat prosjekt', // 'AUD - Australian Dollar' => '', // 'CAD - Canadian Dollar' => '', @@ -645,9 +643,6 @@ return array( // 'Test your device' => '', 'Assign a color when the task is moved to a specific column' => 'Endre til en valgt farge hvis en oppgave flyttes til en spesifikk kolonne', // '%s via Kanboard' => '', - // 'uploaded by: %s' => '', - // 'uploaded on: %s' => '', - // 'size: %s' => '', // 'Burndown chart for "%s"' => '', // 'Burndown chart' => '', // 'This chart show the task complexity over the time (Work Remaining).' => '', @@ -1118,4 +1113,29 @@ return array( // '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' => '', ); diff --git a/app/Locale/nl_NL/translations.php b/app/Locale/nl_NL/translations.php index 0d9d9608..21b95446 100644 --- a/app/Locale/nl_NL/translations.php +++ b/app/Locale/nl_NL/translations.php @@ -598,8 +598,6 @@ return array( // 'Compact/wide view' => '', // 'No results match:' => '', // 'Currency' => '', - // 'Files' => '', - // 'Images' => '', // 'Private project' => '', // 'AUD - Australian Dollar' => '', // 'CAD - Canadian Dollar' => '', @@ -645,9 +643,6 @@ return array( // 'Test your device' => '', // 'Assign a color when the task is moved to a specific column' => '', // '%s via Kanboard' => '', - // 'uploaded by: %s' => '', - // 'uploaded on: %s' => '', - // 'size: %s' => '', // 'Burndown chart for "%s"' => '', // 'Burndown chart' => '', // 'This chart show the task complexity over the time (Work Remaining).' => '', @@ -1118,4 +1113,29 @@ return array( // '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' => '', ); diff --git a/app/Locale/pl_PL/translations.php b/app/Locale/pl_PL/translations.php index 28ed2b3a..ec5918b4 100644 --- a/app/Locale/pl_PL/translations.php +++ b/app/Locale/pl_PL/translations.php @@ -598,8 +598,6 @@ return array( 'Compact/wide view' => 'Pełny/Kompaktowy widok', 'No results match:' => 'Brak wyników:', 'Currency' => 'Waluta', - 'Files' => 'Pliki', - 'Images' => 'Obrazy', 'Private project' => 'Projekt prywatny', 'AUD - Australian Dollar' => 'AUD - Dolar australijski', 'CAD - Canadian Dollar' => 'CAD - Dolar kanadyjski', @@ -645,9 +643,6 @@ return array( 'Test your device' => 'Przetestuj urządzenie', 'Assign a color when the task is moved to a specific column' => 'Przypisz kolor gdy zadanie jest przeniesione do danej kolumny', '%s via Kanboard' => '%s poprzez Kanboard', - 'uploaded by: %s' => 'Dodane przez: %s', - 'uploaded on: %s' => 'Data dodania: %s', - 'size: %s' => 'Rozmiar: %s', 'Burndown chart for "%s"' => 'Wykres Burndown dla "%s"', 'Burndown chart' => 'Wykres Burndown', // 'This chart show the task complexity over the time (Work Remaining).' => '', @@ -1118,4 +1113,29 @@ return array( // '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' => '', ); diff --git a/app/Locale/pt_BR/translations.php b/app/Locale/pt_BR/translations.php index d29f9f88..ea4a028c 100644 --- a/app/Locale/pt_BR/translations.php +++ b/app/Locale/pt_BR/translations.php @@ -598,8 +598,6 @@ return array( 'Compact/wide view' => 'Alternar entre a vista compacta e ampliada', 'No results match:' => 'Nenhum resultado:', 'Currency' => 'Moeda', - 'Files' => 'Arquivos', - 'Images' => 'Imagens', 'Private project' => 'Projeto privado', 'AUD - Australian Dollar' => 'AUD - Dólar australiano', 'CAD - Canadian Dollar' => 'CAD - Dólar canadense', @@ -645,9 +643,6 @@ return array( 'Test your device' => 'Teste o seu dispositivo', 'Assign a color when the task is moved to a specific column' => 'Atribuir uma cor quando a tarefa é movida em uma coluna específica', '%s via Kanboard' => '%s via Kanboard', - 'uploaded by: %s' => 'carregado por: %s', - 'uploaded on: %s' => 'carregado em: %s', - 'size: %s' => 'tamanho: %s', 'Burndown chart for "%s"' => 'Gráfico de Burndown para "%s"', 'Burndown chart' => 'Gráfico de Burndown', 'This chart show the task complexity over the time (Work Remaining).' => 'Este gráfico mostra a complexidade da tarefa ao longo do tempo (Trabalho Restante).', @@ -954,57 +949,57 @@ return array( 'Duplicates are not imported' => 'Registros duplicados não são importados', 'Usernames must be lowercase and unique' => 'Nomes de usuário devem ser únicos e em letras minúsculas', 'Passwords will be encrypted if present' => 'Senhas serão encriptadas, se presentes', - // '%s attached a new file to the task %s' => '', - // '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:' => '', + '%s attached a new file to the task %s' => '%s anexou um novo arquivo a tarefa %s', + 'Assign automatically a category based on a link' => 'Atribuir automaticamente uma categoria baseada num link', + 'BAM - Konvertible Mark' => 'BAM - Mark conversível', + 'Assignee Username' => 'Usuário designado', + 'Assignee Name' => 'Nome do designado', + 'Groups' => 'Grupos', + 'Members of %s' => 'Membros do %s', + 'New group' => 'Novo grupo', + 'Group created successfully.' => 'Grupo criado com sucesso.', + 'Unable to create your group.' => 'Não foi possível de criar o seu grupo.', + 'Edit group' => 'Editar o grupo', + 'Group updated successfully.' => 'Grupo atualizado com sucesso.', + 'Unable to update your group.' => 'Não foi possível atualizar o seu grupo.', + 'Add group member to "%s"' => 'Adicionar um membro ao grupo "%s"', + 'Group member added successfully.' => 'Membro adicionado com sucesso ao o grupo.', + 'Unable to add group member.' => 'Não foi possivel adicionar esse membro ao grupo.', + 'Remove user from group "%s"' => 'Remover usuário do grupo "%s"', + 'User removed successfully from this group.' => 'Usuário removido com sucesso deste grupo.', + 'Unable to remove this user from the group.' => 'Não foi possivel remover este Usuário do grupo.', + 'Remove group' => 'Remover o grupo', + 'Group removed successfully.' => 'Grupo removido com sucesso.', + 'Unable to remove this group.' => 'Não foi possível remover este grupo.', + 'Project Permissions' => 'Permissões do projeto', + 'Manager' => 'Gerente', + 'Project Manager' => 'Gerente de projeto', + 'Project Member' => 'Membro de projeto', + 'Project Viewer' => '', + 'Your account is locked for %d minutes' => 'A sua conta está bloqueada por %d minutos', + 'Invalid captcha' => 'Captcha inválido', + 'The name must be unique' => 'O nome deve ser único', + 'View all groups' => 'Ver todos os grupos', + 'View group members' => 'Ver os membros do grupo', + 'There is no user available.' => 'Não há nenhum usuário disponível', + 'Do you really want to remove the user "%s" from the group "%s"?' => 'Você realmente deseja remover o usuário "%s" do grupo "%s"?', + 'There is no group.' => 'Não há nenhum grupo.', + 'External Id' => 'Id externo', + 'Add group member' => 'Adicionar um membro ao grupo', + 'Do you really want to remove this group: "%s"?' => 'Você realmente deseja excluir este grupo: "%s"?', + 'There is no user in this group.' => 'Não há usuários neste grupo.', + 'Remove this user' => 'Remover este usuário', + 'Permissions' => 'Permissões', + 'Allowed Users' => 'Usuários autorizados', + 'No user have been allowed specifically.' => 'Nenhum usuário foi especificamente autorizado.', + 'Role' => 'Função', + 'Enter user name...' => 'Digite o nome do usuário...', + 'Allowed Groups' => 'Grupos autorizados', + 'No group have been allowed specifically.' => 'Nenhum grupo foi especificamente autorizado.', + 'Group' => 'Grupo', + 'Group Name' => 'Nome do grupo', + 'Enter group name...' => 'Digite o nome do grupo', + 'Role:' => 'Função:', 'Project members' => 'Membros de projeto', // 'Compare hours for "%s"' => '', // '%s mentioned you in the task #%d' => '', @@ -1118,4 +1113,29 @@ return array( // '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' => '', ); diff --git a/app/Locale/pt_PT/translations.php b/app/Locale/pt_PT/translations.php index b197a1dc..cecae5fe 100644 --- a/app/Locale/pt_PT/translations.php +++ b/app/Locale/pt_PT/translations.php @@ -598,8 +598,6 @@ return array( 'Compact/wide view' => 'Alternar entre a vista compacta e ampliada', 'No results match:' => 'Nenhum resultado:', 'Currency' => 'Moeda', - 'Files' => 'Arquivos', - 'Images' => 'Imagens', 'Private project' => 'Projecto privado', 'AUD - Australian Dollar' => 'AUD - Dólar australiano', 'CAD - Canadian Dollar' => 'CAD - Dólar canadense', @@ -645,9 +643,6 @@ return array( 'Test your device' => 'Teste o seu dispositivo', 'Assign a color when the task is moved to a specific column' => 'Atribuir uma cor quando a tarefa é movida em uma coluna específica', '%s via Kanboard' => '%s via Kanboard', - 'uploaded by: %s' => 'carregado por: %s', - 'uploaded on: %s' => 'carregado em: %s', - 'size: %s' => 'tamanho: %s', 'Burndown chart for "%s"' => 'Gráfico de Burndown para "%s"', 'Burndown chart' => 'Gráfico de Burndown', 'This chart show the task complexity over the time (Work Remaining).' => 'Este gráfico mostra a complexidade da tarefa ao longo do tempo (Trabalho Restante).', @@ -1118,4 +1113,29 @@ return array( 'End date: ' => 'Data final: ', 'New due date: ' => 'Nova data estimada: ', 'Start date changed: ' => 'Data inicio alterada: ', + 'Disable private projects' => 'Desactivar projectos privados', + 'Do you really want to remove this custom filter: "%s"?' => 'Tem a certeza que quer remover este filtro personalizado: "%s"?', + 'Remove a custom filter' => 'Remover o filtro personalizado', + 'User activated successfully.' => 'Utilizador activado com sucesso.', + 'Unable to enable this user.' => 'Não foi possivel activar este utilizador.', + 'User disabled successfully.' => 'Utilizador desactivado com sucesso.', + 'Unable to disable this user.' => 'Não foi possivel desactivar este utilizador.', + 'All files have been uploaded successfully.' => 'Todos os ficheiros foram enviados com sucesso.', + 'View uploaded files' => 'Ver ficheiros enviados', + 'The maximum allowed file size is %sB.' => 'O tamanho máximo permitido é %sB.', + 'Choose files again' => 'Escolher ficheiros novamente', + 'Drag and drop your files here' => 'Arraste e deixe os ficheiros para aqui', + 'choose files' => 'escolher ficheiros', + 'View profile' => 'Ver perfil', + 'Two Factor' => 'Dois Factores', + 'Disable user' => 'Desactivar utilizador', + 'Do you really want to disable this user: "%s"?' => 'Tem a certeza que quer desactivar este utilizador: "%s"?', + 'Enable user' => 'Activar utilizador', + 'Do you really want to enable this user: "%s"?' => 'Tem a certeza que quer activar este utilizador: "%s"?', + 'Download' => 'Transferir', + 'Uploaded: %s' => 'Enviado: %s', + 'Size: %s' => 'Tamanho: %s', + 'Uploaded by %s' => 'Enviado por %s', + 'Filename' => 'Nome do ficheiro', + 'Size' => 'Tamanho', ); diff --git a/app/Locale/ru_RU/translations.php b/app/Locale/ru_RU/translations.php index f971acc1..4f231397 100644 --- a/app/Locale/ru_RU/translations.php +++ b/app/Locale/ru_RU/translations.php @@ -598,8 +598,6 @@ return array( 'Compact/wide view' => 'Компактный/широкий вид', 'No results match:' => 'Отсутствуют результаты:', 'Currency' => 'Валюта', - 'Files' => 'Файлы', - 'Images' => 'Изображения', 'Private project' => 'Приватный проект', 'AUD - Australian Dollar' => 'AUD - Австралийский доллар', 'CAD - Canadian Dollar' => 'CAD - Канадский доллар', @@ -645,9 +643,6 @@ return array( 'Test your device' => 'Проверьте свое устройство', 'Assign a color when the task is moved to a specific column' => 'Назначить цвет, когда задача перемещается в определенную колонку', '%s via Kanboard' => '%s через Канборд', - 'uploaded by: %s' => 'загружено: %s', - 'uploaded on: %s' => 'загружено в: %s', - 'size: %s' => 'размер: %s', 'Burndown chart for "%s"' => 'Диаграмма сгорания для « %s »', 'Burndown chart' => 'Диаграмма сгорания', 'This chart show the task complexity over the time (Work Remaining).' => 'Эта диаграмма показывают сложность задачи по времени (оставшейся работы).', @@ -1112,10 +1107,35 @@ return array( 'Moved:' => 'Перемещена:', 'Task #%d' => 'Задача #%d', 'Sub-tasks' => 'Подзадачи', - // 'Date and time format' => '', - // 'Time format' => '', - // 'Start date: ' => '', - // 'End date: ' => '', - // 'New due date: ' => '', - // 'Start date changed: ' => '', + '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.' => 'Пользователь был успешно выключен.', + 'Unable to disable this user.' => 'Не удалось выключить пользователя.', + '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' => 'Размер', ); diff --git a/app/Locale/sr_Latn_RS/translations.php b/app/Locale/sr_Latn_RS/translations.php index 3551c281..3442b970 100644 --- a/app/Locale/sr_Latn_RS/translations.php +++ b/app/Locale/sr_Latn_RS/translations.php @@ -598,8 +598,6 @@ return array( // 'Compact/wide view' => '', // 'No results match:' => '', // 'Currency' => '', - // 'Files' => '', - // 'Images' => '', // 'Private project' => '', // 'AUD - Australian Dollar' => '', // 'CAD - Canadian Dollar' => '', @@ -645,9 +643,6 @@ return array( // 'Test your device' => '', // 'Assign a color when the task is moved to a specific column' => '', // '%s via Kanboard' => '', - // 'uploaded by: %s' => '', - // 'uploaded on: %s' => '', - // 'size: %s' => '', // 'Burndown chart for "%s"' => '', // 'Burndown chart' => '', // 'This chart show the task complexity over the time (Work Remaining).' => '', @@ -1118,4 +1113,29 @@ return array( // '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' => '', ); diff --git a/app/Locale/sv_SE/translations.php b/app/Locale/sv_SE/translations.php index c0aa883c..96bf437a 100644 --- a/app/Locale/sv_SE/translations.php +++ b/app/Locale/sv_SE/translations.php @@ -598,8 +598,6 @@ return array( 'Compact/wide view' => 'Kompakt/bred vy', 'No results match:' => 'Inga matchande resultat', 'Currency' => 'Valuta', - 'Files' => 'Filer', - 'Images' => 'Bilder', 'Private project' => 'Privat projekt', 'AUD - Australian Dollar' => 'AUD - Australiska dollar', 'CAD - Canadian Dollar' => 'CAD - Kanadensiska dollar', @@ -645,9 +643,6 @@ return array( 'Test your device' => 'Testa din enhet', 'Assign a color when the task is moved to a specific column' => 'Tilldela en färg när uppgiften flyttas till en specifik kolumn', '%s via Kanboard' => '%s via Kanboard', - 'uploaded by: %s' => 'uppladdad av: %s', - 'uploaded on: %s' => 'uppladdad på: %s', - 'size: %s' => 'storlek: %s', 'Burndown chart for "%s"' => 'Burndown diagram för "%s"', 'Burndown chart' => 'Burndown diagram', 'This chart show the task complexity over the time (Work Remaining).' => 'Diagrammet visar uppgiftens svårighet över tid (återstående arbete).', @@ -1118,4 +1113,29 @@ return array( // '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' => '', ); diff --git a/app/Locale/th_TH/translations.php b/app/Locale/th_TH/translations.php index 1ccc2d90..041cd852 100644 --- a/app/Locale/th_TH/translations.php +++ b/app/Locale/th_TH/translations.php @@ -598,8 +598,6 @@ return array( 'Compact/wide view' => 'พอดี/กว้าง มุมมอง', 'No results match:' => 'ไม่มีผลลัพท์ที่ตรง', 'Currency' => 'สกุลเงิน', - 'Files' => 'ไฟล์', - 'Images' => 'รูปภาพ', 'Private project' => 'โปรเจคส่วนตัว', // 'AUD - Australian Dollar' => '', // 'CAD - Canadian Dollar' => '', @@ -645,9 +643,6 @@ return array( 'Test your device' => 'ทดสอบอุปกรณ์ของคุณ', 'Assign a color when the task is moved to a specific column' => 'กำหนดสีเมื่องานถูกย้ายไปคอลัมน์ที่กำหนดไว้', // '%s via Kanboard' => '', - // 'uploaded by: %s' => '', - // 'uploaded on: %s' => '', - 'size: %s' => 'ขนาด: %s', 'Burndown chart for "%s"' => 'แผนภูมิงานกับเวลา "%s"', 'Burndown chart' => 'แผนภูมิงานกับเวลา', // 'This chart show the task complexity over the time (Work Remaining).' => '', @@ -1118,4 +1113,29 @@ return array( // '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' => '', ); diff --git a/app/Locale/tr_TR/translations.php b/app/Locale/tr_TR/translations.php index 10153331..f2210dd7 100644 --- a/app/Locale/tr_TR/translations.php +++ b/app/Locale/tr_TR/translations.php @@ -598,8 +598,6 @@ return array( 'Compact/wide view' => 'Ekrana sığdır / Geniş görünüm', 'No results match:' => 'Uygun sonuç bulunamadı', 'Currency' => 'Para birimi', - 'Files' => 'Dosyalar', - 'Images' => 'Resimler', 'Private project' => 'Özel proje', // 'AUD - Australian Dollar' => '', // 'CAD - Canadian Dollar' => '', @@ -645,9 +643,6 @@ return array( 'Test your device' => 'Cihazınızı test edin', 'Assign a color when the task is moved to a specific column' => 'Görev belirli bir sütuna taşındığında rengini değiştir', '%s via Kanboard' => '%s Kanboard ile', - 'uploaded by: %s' => '%s tarafından yüklendi', - 'uploaded on: %s' => '%s tarihinda yüklendi', - 'size: %s' => 'Boyut: %s', 'Burndown chart for "%s"' => '%s icin kalan iş grafiği', 'Burndown chart' => 'Kalan iş grafiği', 'This chart show the task complexity over the time (Work Remaining).' => 'Bu grafik zorluk seviyesini zamana göre gösterir (kalan iş)', @@ -1118,4 +1113,29 @@ return array( // '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' => '', ); diff --git a/app/Locale/zh_CN/translations.php b/app/Locale/zh_CN/translations.php index acdcdf30..5bcf01dc 100644 --- a/app/Locale/zh_CN/translations.php +++ b/app/Locale/zh_CN/translations.php @@ -598,8 +598,6 @@ return array( 'Compact/wide view' => '紧凑/宽视图', 'No results match:' => '无匹配结果:', 'Currency' => '货币', - 'Files' => '文件', - 'Images' => '图片', 'Private project' => '私人项目', 'AUD - Australian Dollar' => '澳元', 'CAD - Canadian Dollar' => '加元', @@ -645,9 +643,6 @@ return array( 'Test your device' => '测试设备', 'Assign a color when the task is moved to a specific column' => '任务移动到指定栏目时设置颜色', '%s via Kanboard' => '%s 通过KanBoard', - 'uploaded by: %s' => '由: %s 上传', - 'uploaded on: %s' => '上传于 %s', - 'size: %s' => '大小:%s', 'Burndown chart for "%s"' => '燃尽图:"%s"', 'Burndown chart' => '燃尽图', 'This chart show the task complexity over the time (Work Remaining).' => '图表显示任务随时间(剩余时间)的复杂度', @@ -1085,37 +1080,62 @@ return array( 'There is no external link for the moment.' => '当前没有外部关联。', 'Internal links' => '内部关联', 'There is no internal link for the moment.' => '当前没有内部关联。', - // 'Assign to me' => '', - // 'Me' => '', - // 'Do not duplicate anything' => '', - // 'Projects management' => '', - // 'Users management' => '', - // 'Groups management' => '', - // 'Create from another project' => '', - // 'There is no subtask at the moment.' => '', - // 'open' => '', - // 'closed' => '', - // 'Priority:' => '', - // 'Reference:' => '', - // 'Complexity:' => '', - // 'Swimlane:' => '', - // 'Column:' => '', - // 'Position:' => '', - // 'Creator:' => '', - // 'Time estimated:' => '', - // '%s hours' => '', - // 'Time spent:' => '', - // 'Created:' => '', - // 'Modified:' => '', - // 'Completed:' => '', - // 'Started:' => '', - // 'Moved:' => '', - // 'Task #%d' => '', - // 'Sub-tasks' => '', - // 'Date and time format' => '', - // 'Time format' => '', - // 'Start date: ' => '', - // 'End date: ' => '', - // 'New due date: ' => '', - // 'Start date changed: ' => '', + 'Assign to me' => '指派给我', + 'Me' => '我', + 'Do not duplicate anything' => '不再重复', + 'Projects management' => '项目管理', + 'Users management' => '用户管理', + 'Groups management' => '用户组管理', + 'Create from another project' => '从另一个项目中创建', + 'There is no subtask at the moment.' => '当前没有子任务。', + 'open' => '打开', + 'closed' => '已关闭', + 'Priority:' => '优先级:', + 'Reference:' => '引用:', + 'Complexity:' => '复杂度:', + 'Swimlane:' => '里程碑:', + 'Column:' => '列:', + 'Position:' => '位置:', + 'Creator:' => '创建者:', + 'Time estimated:' => '时间已过去:', + '%s hours' => '%s 小时', + 'Time spent:' => '时间消耗:', + 'Created:' => '已创建:', + 'Modified:' => '已修改:', + 'Completed:' => '已完成:', + 'Started:' => '已开始:', + 'Moved:' => '已移走', + 'Task #%d' => '任务#%d', + 'Sub-tasks' => '子任务', + '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.' => '用户已禁用。', + 'Unable to disable this user.' => '无法禁用该用户。', + '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' => '大小', ); diff --git a/app/Model/File.php b/app/Model/File.php index 46fc4bb9..e17ecb2b 100644 --- a/app/Model/File.php +++ b/app/Model/File.php @@ -2,31 +2,44 @@ namespace Kanboard\Model; +use Exception; use Kanboard\Event\FileEvent; use Kanboard\Core\Tool; use Kanboard\Core\ObjectStorage\ObjectStorageException; /** - * File model + * Base File Model * * @package model * @author Frederic Guillot */ -class File extends Base +abstract class File extends Base { /** - * SQL table name - * - * @var string - */ - const TABLE = 'files'; - - /** - * Events + * Get PicoDb query to get all files * - * @var string + * @access protected + * @return \PicoDb\Table */ - const EVENT_CREATE = 'file.create'; + protected function getQuery() + { + return $this->db + ->table(static::TABLE) + ->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' + ) + ->join(User::TABLE, 'id', 'user_id') + ->asc(static::TABLE.'.name'); + } /** * Get a file by the id @@ -37,146 +50,120 @@ class File extends Base */ public function getById($file_id) { - return $this->db->table(self::TABLE)->eq('id', $file_id)->findOne(); + return $this->db->table(static::TABLE)->eq('id', $file_id)->findOne(); } /** - * Remove a file + * Get all files * * @access public - * @param integer $file_id File id - * @return bool + * @param integer $id + * @return array */ - public function remove($file_id) + public function getAll($id) { - try { - $file = $this->getbyId($file_id); - $this->objectStorage->remove($file['path']); - - if ($file['is_image'] == 1) { - $this->objectStorage->remove($this->getThumbnailPath($file['path'])); - } - - return $this->db->table(self::TABLE)->eq('id', $file['id'])->remove(); - } catch (ObjectStorageException $e) { - $this->logger->error($e->getMessage()); - return false; - } + return $this->getQuery()->eq(static::FOREIGN_KEY, $id)->findAll(); } /** - * Remove all files for a given task + * Get all images * * @access public - * @param integer $task_id Task id - * @return bool + * @param integer $id + * @return array */ - public function removeAll($task_id) + public function getAllImages($id) { - $file_ids = $this->db->table(self::TABLE)->eq('task_id', $task_id)->asc('id')->findAllByColumn('id'); - $results = array(); - - foreach ($file_ids as $file_id) { - $results[] = $this->remove($file_id); - } + return $this->getQuery()->eq(static::FOREIGN_KEY, $id)->eq('is_image', 1)->findAll(); + } - return ! in_array(false, $results, true); + /** + * Get all files without images + * + * @access public + * @param integer $id + * @return array + */ + public function getAllDocuments($id) + { + return $this->getQuery()->eq(static::FOREIGN_KEY, $id)->eq('is_image', 0)->findAll(); } /** * Create a file entry in the database * * @access public - * @param integer $task_id Task id + * @param integer $id Foreign key * @param string $name Filename * @param string $path Path on the disk * @param integer $size File size * @return bool|integer */ - public function create($task_id, $name, $path, $size) + public function create($id, $name, $path, $size) { - $result = $this->db->table(self::TABLE)->save(array( - 'task_id' => $task_id, + $values = array( + static::FOREIGN_KEY => $id, 'name' => substr($name, 0, 255), 'path' => $path, 'is_image' => $this->isImage($name) ? 1 : 0, 'size' => $size, 'user_id' => $this->userSession->getId() ?: 0, 'date' => time(), - )); + ); - if ($result) { - $this->container['dispatcher']->dispatch( - self::EVENT_CREATE, - new FileEvent(array('task_id' => $task_id, 'name' => $name)) - ); + $result = $this->db->table(static::TABLE)->insert($values); - return (int) $this->db->getLastId(); + if ($result) { + $file_id = (int) $this->db->getLastId(); + $event = new FileEvent($values + array('file_id' => $file_id)); + $this->dispatcher->dispatch(static::EVENT_CREATE, $event); + return $file_id; } return false; } /** - * Get PicoDb query to get all files + * Remove all files * * @access public - * @return \PicoDb\Table + * @param integer $id + * @return bool */ - public function getQuery() + public function removeAll($id) { - return $this->db - ->table(self::TABLE) - ->columns( - self::TABLE.'.id', - self::TABLE.'.name', - self::TABLE.'.path', - self::TABLE.'.is_image', - self::TABLE.'.task_id', - self::TABLE.'.date', - self::TABLE.'.user_id', - self::TABLE.'.size', - User::TABLE.'.username', - User::TABLE.'.name as user_name' - ) - ->join(User::TABLE, 'id', 'user_id') - ->asc(self::TABLE.'.name'); - } + $file_ids = $this->db->table(static::TABLE)->eq(static::FOREIGN_KEY, $id)->asc('id')->findAllByColumn('id'); + $results = array(); - /** - * Get all files for a given task - * - * @access public - * @param integer $task_id Task id - * @return array - */ - public function getAll($task_id) - { - return $this->getQuery()->eq('task_id', $task_id)->findAll(); - } + foreach ($file_ids as $file_id) { + $results[] = $this->remove($file_id); + } - /** - * Get all images for a given task - * - * @access public - * @param integer $task_id Task id - * @return array - */ - public function getAllImages($task_id) - { - return $this->getQuery()->eq('task_id', $task_id)->eq('is_image', 1)->findAll(); + return ! in_array(false, $results, true); } /** - * Get all files without images for a given task + * Remove a file * * @access public - * @param integer $task_id Task id - * @return array + * @param integer $file_id File id + * @return bool */ - public function getAllDocuments($task_id) + public function remove($file_id) { - return $this->getQuery()->eq('task_id', $task_id)->eq('is_image', 0)->findAll(); + try { + $file = $this->getById($file_id); + $this->objectStorage->remove($file['path']); + + if ($file['is_image'] == 1) { + $this->objectStorage->remove($this->getThumbnailPath($file['path'])); + } + + return $this->db->table(static::TABLE)->eq('id', $file['id'])->remove(); + } catch (ObjectStorageException $e) { + $this->logger->error($e->getMessage()); + return false; + } } /** @@ -226,103 +213,96 @@ class File extends Base } /** - * Generate the path for a new filename + * Generate the path for a thumbnails * * @access public - * @param integer $project_id Project id - * @param integer $task_id Task id - * @param string $filename Filename + * @param string $key Storage key * @return string */ - public function generatePath($project_id, $task_id, $filename) + public function getThumbnailPath($key) { - return $project_id.DIRECTORY_SEPARATOR.$task_id.DIRECTORY_SEPARATOR.hash('sha1', $filename.time()); + return 'thumbnails'.DIRECTORY_SEPARATOR.$key; } /** - * Generate the path for a thumbnails + * Generate the path for a new filename * * @access public - * @param string $key Storage key + * @param integer $id Foreign key + * @param string $filename Filename * @return string */ - public function getThumbnailPath($key) + public function generatePath($id, $filename) { - return 'thumbnails'.DIRECTORY_SEPARATOR.$key; + return static::PATH_PREFIX.DIRECTORY_SEPARATOR.$id.DIRECTORY_SEPARATOR.hash('sha1', $filename.time()); } /** - * Handle file upload + * Upload multiple files * * @access public - * @param integer $project_id Project id - * @param integer $task_id Task id - * @param string $form_name File form name + * @param integer $id + * @param array $files * @return bool */ - public function uploadFiles($project_id, $task_id, $form_name) + public function uploadFiles($id, array $files) { try { - $file = $this->request->getFileInfo($form_name); - - if (empty($file)) { + if (empty($files)) { return false; } - foreach ($file['error'] as $key => $error) { - if ($error == UPLOAD_ERR_OK && $file['size'][$key] > 0) { - $original_filename = $file['name'][$key]; - $uploaded_filename = $file['tmp_name'][$key]; - $destination_filename = $this->generatePath($project_id, $task_id, $original_filename); - - if ($this->isImage($original_filename)) { - $this->generateThumbnailFromFile($uploaded_filename, $destination_filename); - } + foreach (array_keys($files['error']) as $key) { + $file = array( + 'name' => $files['name'][$key], + 'tmp_name' => $files['tmp_name'][$key], + 'size' => $files['size'][$key], + 'error' => $files['error'][$key], + ); - $this->objectStorage->moveUploadedFile($uploaded_filename, $destination_filename); - - $this->create( - $task_id, - $original_filename, - $destination_filename, - $file['size'][$key] - ); - } + $this->uploadFile($id, $file); } return true; - } catch (ObjectStorageException $e) { + } catch (Exception $e) { $this->logger->error($e->getMessage()); return false; } } /** - * Handle screenshot upload + * Upload a file * * @access public - * @param integer $project_id Project id - * @param integer $task_id Task id - * @param string $blob Base64 encoded image - * @return bool|integer + * @param integer $id + * @param array $file */ - public function uploadScreenshot($project_id, $task_id, $blob) + public function uploadFile($id, array $file) { - $original_filename = e('Screenshot taken %s', $this->helper->dt->datetime(time())).'.png'; - return $this->uploadContent($project_id, $task_id, $original_filename, $blob); + if ($file['error'] == UPLOAD_ERR_OK && $file['size'] > 0) { + $destination_filename = $this->generatePath($id, $file['name']); + + if ($this->isImage($file['name'])) { + $this->generateThumbnailFromFile($file['tmp_name'], $destination_filename); + } + + $this->objectStorage->moveUploadedFile($file['tmp_name'], $destination_filename); + $this->create($id, $file['name'], $destination_filename, $file['size']); + } else { + throw new Exception('File not uploaded: '.var_export($file['error'], true)); + } } /** * Handle file upload (base64 encoded content) * * @access public - * @param integer $project_id Project id - * @param integer $task_id Task id - * @param string $original_filename Filename - * @param string $blob Base64 encoded file + * @param integer $id + * @param string $original_filename + * @param string $blob * @return bool|integer */ - public function uploadContent($project_id, $task_id, $original_filename, $blob) + public function uploadContent($id, $original_filename, $blob) { try { $data = base64_decode($blob); @@ -331,7 +311,7 @@ class File extends Base return false; } - $destination_filename = $this->generatePath($project_id, $task_id, $original_filename); + $destination_filename = $this->generatePath($id, $original_filename); $this->objectStorage->put($destination_filename, $data); if ($this->isImage($original_filename)) { @@ -339,7 +319,7 @@ class File extends Base } return $this->create( - $task_id, + $id, $original_filename, $destination_filename, strlen($data) diff --git a/app/Model/Notification.php b/app/Model/Notification.php index 87c1a796..c252aa31 100644 --- a/app/Model/Notification.php +++ b/app/Model/Notification.php @@ -72,7 +72,7 @@ class Notification extends Base return e('%s updated a comment on the task #%d', $event_author, $event_data['task']['id']); case Comment::EVENT_CREATE: return e('%s commented on the task #%d', $event_author, $event_data['task']['id']); - case File::EVENT_CREATE: + case TaskFile::EVENT_CREATE: return e('%s attached a file to the task #%d', $event_author, $event_data['task']['id']); case Task::EVENT_USER_MENTION: return e('%s mentioned you in the task #%d', $event_author, $event_data['task']['id']); @@ -94,7 +94,7 @@ class Notification extends Base public function getTitleWithoutAuthor($event_name, array $event_data) { switch ($event_name) { - case File::EVENT_CREATE: + case TaskFile::EVENT_CREATE: return e('New attachment on task #%d: %s', $event_data['file']['task_id'], $event_data['file']['name']); case Comment::EVENT_CREATE: return e('New comment on task #%d', $event_data['comment']['task_id']); diff --git a/app/Model/ProjectFile.php b/app/Model/ProjectFile.php new file mode 100644 index 00000000..aa9bf15b --- /dev/null +++ b/app/Model/ProjectFile.php @@ -0,0 +1,40 @@ +<?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/ProjectGroupRole.php b/app/Model/ProjectGroupRole.php index 591b28c6..750ba7fb 100644 --- a/app/Model/ProjectGroupRole.php +++ b/app/Model/ProjectGroupRole.php @@ -106,6 +106,7 @@ class ProjectGroupRole extends Base ->join(GroupMember::TABLE, 'user_id', 'id', User::TABLE) ->join(self::TABLE, 'group_id', 'group_id', GroupMember::TABLE) ->eq(self::TABLE.'.project_id', $project_id) + ->eq(User::TABLE.'.is_active', 1) ->in(self::TABLE.'.role', array(Role::PROJECT_MANAGER, Role::PROJECT_MEMBER)) ->asc(User::TABLE.'.username') ->findAll(); diff --git a/app/Model/ProjectPermission.php b/app/Model/ProjectPermission.php index cea62e13..db1573ae 100644 --- a/app/Model/ProjectPermission.php +++ b/app/Model/ProjectPermission.php @@ -107,7 +107,8 @@ class ProjectPermission extends Base */ public function isAssignable($project_id, $user_id) { - return in_array($this->projectUserRole->getUserRole($project_id, $user_id), array(Role::PROJECT_MEMBER, Role::PROJECT_MANAGER)); + return $this->user->isActive($user_id) && + in_array($this->projectUserRole->getUserRole($project_id, $user_id), array(Role::PROJECT_MEMBER, Role::PROJECT_MANAGER)); } /** diff --git a/app/Model/ProjectUserRole.php b/app/Model/ProjectUserRole.php index 8149a253..56da679c 100644 --- a/app/Model/ProjectUserRole.php +++ b/app/Model/ProjectUserRole.php @@ -152,13 +152,14 @@ class ProjectUserRole extends Base public function getAssignableUsers($project_id) { if ($this->projectPermission->isEverybodyAllowed($project_id)) { - return $this->user->getList(); + return $this->user->getActiveUsersList(); } $userMembers = $this->db->table(self::TABLE) ->columns(User::TABLE.'.id', User::TABLE.'.username', User::TABLE.'.name') ->join(User::TABLE, 'id', 'user_id') - ->eq('project_id', $project_id) + ->eq(User::TABLE.'.is_active', 1) + ->eq(self::TABLE.'.project_id', $project_id) ->in(self::TABLE.'.role', array(Role::PROJECT_MANAGER, Role::PROJECT_MEMBER)) ->findAll(); diff --git a/app/Model/Task.php b/app/Model/Task.php index 38fdd0d5..f8b41b9f 100644 --- a/app/Model/Task.php +++ b/app/Model/Task.php @@ -92,7 +92,7 @@ class Task extends Base return false; } - $this->file->removeAll($task_id); + $this->taskFile->removeAll($task_id); return $this->db->table(self::TABLE)->eq('id', $task_id)->remove(); } diff --git a/app/Model/TaskFile.php b/app/Model/TaskFile.php new file mode 100644 index 00000000..45a3b97f --- /dev/null +++ b/app/Model/TaskFile.php @@ -0,0 +1,54 @@ +<?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/TaskFinder.php b/app/Model/TaskFinder.php index 4d673097..95ddc12f 100644 --- a/app/Model/TaskFinder.php +++ b/app/Model/TaskFinder.php @@ -89,7 +89,7 @@ class TaskFinder extends Base ->table(Task::TABLE) ->columns( '(SELECT COUNT(*) FROM '.Comment::TABLE.' WHERE task_id=tasks.id) AS nb_comments', - '(SELECT COUNT(*) FROM '.File::TABLE.' WHERE task_id=tasks.id) AS nb_files', + '(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', diff --git a/app/Model/User.php b/app/Model/User.php index dd622207..e2494c4c 100644 --- a/app/Model/User.php +++ b/app/Model/User.php @@ -41,6 +41,18 @@ class User extends Base } /** + * Return true if the user is active + * + * @access public + * @param integer $user_id User id + * @return boolean + */ + public function isActive($user_id) + { + return $this->db->table(self::TABLE)->eq('id', $user_id)->eq('is_active', 1)->exists(); + } + + /** * Get query to fetch all users * * @access public @@ -193,9 +205,9 @@ class User extends Base * @param boolean $prepend Prepend "All users" * @return array */ - public function getList($prepend = false) + public function getActiveUsersList($prepend = false) { - $users = $this->db->table(self::TABLE)->columns('id', 'username', 'name')->findAll(); + $users = $this->db->table(self::TABLE)->eq('is_active', 1)->columns('id', 'username', 'name')->findAll(); $listing = $this->prepareList($users); if ($prepend) { @@ -281,6 +293,30 @@ class User extends Base } /** + * Disable a specific user + * + * @access public + * @param integer $user_id + * @return boolean + */ + public function disable($user_id) + { + return $this->db->table(self::TABLE)->eq('id', $user_id)->update(array('is_active' => 0)); + } + + /** + * Enable a specific user + * + * @access public + * @param integer $user_id + * @return boolean + */ + public function enable($user_id) + { + return $this->db->table(self::TABLE)->eq('id', $user_id)->update(array('is_active' => 1)); + } + + /** * Remove a specific user * * @access public diff --git a/app/Notification/Mail.php b/app/Notification/Mail.php index d05dbdf2..c924fb50 100644 --- a/app/Notification/Mail.php +++ b/app/Notification/Mail.php @@ -4,7 +4,7 @@ namespace Kanboard\Notification; use Kanboard\Core\Base; use Kanboard\Model\Task; -use Kanboard\Model\File; +use Kanboard\Model\TaskFile; use Kanboard\Model\Comment; use Kanboard\Model\Subtask; @@ -82,7 +82,7 @@ class Mail extends Base implements NotificationInterface public function getMailSubject($event_name, array $event_data) { switch ($event_name) { - case File::EVENT_CREATE: + case TaskFile::EVENT_CREATE: $subject = $this->getStandardMailSubject(e('New attachment'), $event_data); break; case Comment::EVENT_CREATE: diff --git a/app/Schema/Mysql.php b/app/Schema/Mysql.php index 036958b6..c85dde6f 100644 --- a/app/Schema/Mysql.php +++ b/app/Schema/Mysql.php @@ -6,7 +6,32 @@ use PDO; use Kanboard\Core\Security\Token; use Kanboard\Core\Security\Role; -const VERSION = 104; +const VERSION = 106; + +function version_106(PDO $pdo) +{ + $pdo->exec('RENAME TABLE files TO task_has_files'); + + $pdo->exec(" + CREATE TABLE project_has_files ( + `id` INT NOT NULL AUTO_INCREMENT, + `project_id` INT NOT NULL, + `name` VARCHAR(255) NOT NULL, + `path` VARCHAR(255) NOT NULL, + `is_image` TINYINT(1) DEFAULT 0, + `size` INT DEFAULT 0 NOT NULL, + `user_id` INT DEFAULT 0 NOT NULL, + `date` INT DEFAULT 0 NOT NULL, + FOREIGN KEY(project_id) REFERENCES projects(id) ON DELETE CASCADE, + PRIMARY KEY(id) + ) ENGINE=InnoDB CHARSET=utf8" + ); +} + +function version_105(PDO $pdo) +{ + $pdo->exec("ALTER TABLE users ADD COLUMN is_active TINYINT(1) DEFAULT 1"); +} function version_104(PDO $pdo) { diff --git a/app/Schema/Postgres.php b/app/Schema/Postgres.php index 363b633b..dc8de510 100644 --- a/app/Schema/Postgres.php +++ b/app/Schema/Postgres.php @@ -6,13 +6,37 @@ use PDO; use Kanboard\Core\Security\Token; use Kanboard\Core\Security\Role; -const VERSION = 84; +const VERSION = 86; + +function version_86(PDO $pdo) +{ + $pdo->exec('ALTER TABLE files RENAME TO task_has_files'); + + $pdo->exec(" + CREATE TABLE project_has_files ( + id SERIAL PRIMARY KEY, + project_id INTEGER NOT NULL, + name VARCHAR(255) NOT NULL, + path VARCHAR(255) NOT NULL, + is_image BOOLEAN DEFAULT '0', + size INTEGER DEFAULT 0 NOT NULL, + user_id INTEGER DEFAULT 0 NOT NULL, + date INTEGER DEFAULT 0 NOT NULL, + FOREIGN KEY(project_id) REFERENCES projects(id) ON DELETE CASCADE + )" + ); +} + +function version_85(PDO $pdo) +{ + $pdo->exec("ALTER TABLE users ADD COLUMN is_active BOOLEAN DEFAULT '1'"); +} function version_84(PDO $pdo) { $pdo->exec(" CREATE TABLE task_has_external_links ( - id SERIAL, + id SERIAL PRIMARY KEY, link_type VARCHAR(100) NOT NULL, dependency VARCHAR(100) NOT NULL, title VARCHAR(255) NOT NULL, diff --git a/app/Schema/Sqlite.php b/app/Schema/Sqlite.php index bc701341..e88f621f 100644 --- a/app/Schema/Sqlite.php +++ b/app/Schema/Sqlite.php @@ -6,7 +6,31 @@ use Kanboard\Core\Security\Token; use Kanboard\Core\Security\Role; use PDO; -const VERSION = 96; +const VERSION = 98; + +function version_98(PDO $pdo) +{ + $pdo->exec('ALTER TABLE files RENAME TO task_has_files'); + + $pdo->exec(" + CREATE TABLE project_has_files ( + id INTEGER PRIMARY KEY, + project_id INTEGER NOT NULL, + name TEXT COLLATE NOCASE NOT NULL, + path TEXT NOT NULL, + is_image INTEGER DEFAULT 0, + size INTEGER DEFAULT 0 NOT NULL, + user_id INTEGER DEFAULT 0 NOT NULL, + date INTEGER DEFAULT 0 NOT NULL, + FOREIGN KEY(project_id) REFERENCES projects(id) ON DELETE CASCADE + )" + ); +} + +function version_97(PDO $pdo) +{ + $pdo->exec("ALTER TABLE users ADD COLUMN is_active INTEGER DEFAULT 1"); +} function version_96(PDO $pdo) { diff --git a/app/ServiceProvider/AuthenticationProvider.php b/app/ServiceProvider/AuthenticationProvider.php index 9b5cdbe9..cc7b9302 100644 --- a/app/ServiceProvider/AuthenticationProvider.php +++ b/app/ServiceProvider/AuthenticationProvider.php @@ -76,7 +76,7 @@ class AuthenticationProvider implements ServiceProviderInterface $acl->add('Comment', '*', Role::PROJECT_MEMBER); $acl->add('Customfilter', '*', Role::PROJECT_MEMBER); $acl->add('Export', '*', Role::PROJECT_MANAGER); - $acl->add('File', array('screenshot', 'create', 'save', 'remove', 'confirm'), Role::PROJECT_MEMBER); + $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); @@ -134,7 +134,8 @@ class AuthenticationProvider implements ServiceProviderInterface $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', 'remove'), Role::APP_ADMIN); + $acl->add('User', array('index', 'create', 'save', 'authentication'), Role::APP_ADMIN); + $acl->add('UserStatus', '*', Role::APP_ADMIN); return $acl; } diff --git a/app/ServiceProvider/ClassProvider.php b/app/ServiceProvider/ClassProvider.php index 61a4c512..a4fa1ff2 100644 --- a/app/ServiceProvider/ClassProvider.php +++ b/app/ServiceProvider/ClassProvider.php @@ -31,7 +31,6 @@ class ClassProvider implements ServiceProviderInterface 'Config', 'Currency', 'CustomFilter', - 'File', 'Group', 'GroupMember', 'LastLogin', @@ -40,6 +39,7 @@ class ClassProvider implements ServiceProviderInterface 'OverdueNotification', 'PasswordReset', 'Project', + 'ProjectFile', 'ProjectActivity', 'ProjectDuplication', 'ProjectDailyColumnStats', @@ -63,6 +63,7 @@ class ClassProvider implements ServiceProviderInterface 'TaskExport', 'TaskExternalLink', 'TaskFinder', + 'TaskFile', 'TaskFilter', 'TaskLink', 'TaskModification', diff --git a/app/ServiceProvider/GroupProvider.php b/app/ServiceProvider/GroupProvider.php index dff4b23a..b222b218 100644 --- a/app/ServiceProvider/GroupProvider.php +++ b/app/ServiceProvider/GroupProvider.php @@ -26,7 +26,10 @@ class GroupProvider implements ServiceProviderInterface public function register(Container $container) { $container['groupManager'] = new GroupManager; - $container['groupManager']->register(new DatabaseBackendGroupProvider($container)); + + if (DB_GROUP_PROVIDER) { + $container['groupManager']->register(new DatabaseBackendGroupProvider($container)); + } if (LDAP_AUTH && LDAP_GROUP_PROVIDER) { $container['groupManager']->register(new LdapBackendGroupProvider($container)); diff --git a/app/ServiceProvider/RouteProvider.php b/app/ServiceProvider/RouteProvider.php index 683ea1c1..c723140e 100644 --- a/app/ServiceProvider/RouteProvider.php +++ b/app/ServiceProvider/RouteProvider.php @@ -94,8 +94,6 @@ class RouteProvider implements ServiceProviderInterface $container['route']->addRoute('public/task/:task_id/:token', 'task', 'readonly'); $container['route']->addRoute('project/:project_id/task/:task_id/activity', 'activity', 'task'); - $container['route']->addRoute('project/:project_id/task/:task_id/screenshot', 'file', 'screenshot'); - $container['route']->addRoute('project/:project_id/task/:task_id/upload', 'file', 'create'); $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'); @@ -157,7 +155,6 @@ class RouteProvider implements ServiceProviderInterface $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/remove', 'user', 'remove'); $container['route']->addRoute('user/:user_id/2fa', 'twofactor', 'index'); // Groups diff --git a/app/Subscriber/NotificationSubscriber.php b/app/Subscriber/NotificationSubscriber.php index 07660050..651b8a96 100644 --- a/app/Subscriber/NotificationSubscriber.php +++ b/app/Subscriber/NotificationSubscriber.php @@ -6,7 +6,7 @@ use Kanboard\Event\GenericEvent; use Kanboard\Model\Task; use Kanboard\Model\Comment; use Kanboard\Model\Subtask; -use Kanboard\Model\File; +use Kanboard\Model\TaskFile; use Symfony\Component\EventDispatcher\EventSubscriberInterface; class NotificationSubscriber extends BaseSubscriber implements EventSubscriberInterface @@ -28,7 +28,7 @@ class NotificationSubscriber extends BaseSubscriber implements EventSubscriberIn Comment::EVENT_CREATE => 'handleEvent', Comment::EVENT_UPDATE => 'handleEvent', Comment::EVENT_USER_MENTION => 'handleEvent', - File::EVENT_CREATE => 'handleEvent', + TaskFile::EVENT_CREATE => 'handleEvent', ); } diff --git a/app/Template/app/filters_helper.php b/app/Template/app/filters_helper.php index e4cbb942..c16c2251 100644 --- a/app/Template/app/filters_helper.php +++ b/app/Template/app/filters_helper.php @@ -1,6 +1,6 @@ <?= $this->hook->render('template:app:filters-helper:before', isset($project) ? array('project' => $project) : array()) ?> -<div class="dropdown filters"> - <i class="fa fa-caret-down"></i> <a href="#" class="dropdown-menu"><?= t('Filters') ?></a> +<div class="dropdown"> + <a href="#" class="dropdown-menu dropdown-menu-link-icon" title="<?= t('Default filters') ?>"><i class="fa fa-filter fa-fw"></i><i class="fa fa-caret-down"></i></a> <ul> <li><a href="#" class="filter-helper filter-reset" data-filter="<?= isset($reset) ? $reset : '' ?>" title="<?= t('Keyboard shortcut: "%s"', 'r') ?>"><?= t('Reset filters') ?></a></li> <li><a href="#" class="filter-helper" data-filter="status:open assignee:me"><?= t('My tasks') ?></a></li> diff --git a/app/Template/app/layout.php b/app/Template/app/layout.php index 0550cef4..200cb0d7 100644 --- a/app/Template/app/layout.php +++ b/app/Template/app/layout.php @@ -7,10 +7,12 @@ <?= $this->url->link(t('New project'), 'ProjectCreation', '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') ?> </li> + <?php endif ?> <li> <i class="fa fa-search fa-fw"></i> <?= $this->url->link(t('Search'), 'search', 'index') ?> diff --git a/app/Template/app/overview.php b/app/Template/app/overview.php index ebb3b412..0b354791 100644 --- a/app/Template/app/overview.php +++ b/app/Template/app/overview.php @@ -1,11 +1,10 @@ -<div class="search"> +<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> - - <?= $this->render('app/filters_helper') ?> </div> <?= $this->render('app/projects', array('paginator' => $project_paginator, 'user' => $user)) ?> diff --git a/app/Template/board/tooltip_files.php b/app/Template/board/tooltip_files.php index 407309b3..4fa14b57 100644 --- a/app/Template/board/tooltip_files.php +++ b/app/Template/board/tooltip_files.php @@ -8,9 +8,9 @@ </tr> <tr> <td> - <i class="fa fa-download fa-fw"></i><?= $this->url->link(t('download'), 'file', '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'), 'TaskFile', 'download', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'file_id' => $file['id'])) ?> <?php if ($file['is_image'] == 1): ?> - <i class="fa fa-eye"></i> <?= $this->url->link(t('open file'), 'file', 'open', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'file_id' => $file['id']), false, 'popover') ?> + <i class="fa fa-eye"></i> <?= $this->url->link(t('open file'), 'TaskFile', 'open', 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/view_private.php b/app/Template/board/view_private.php index 63d261f6..b5e38c66 100644 --- a/app/Template/board/view_private.php +++ b/app/Template/board/view_private.php @@ -1,6 +1,6 @@ <section id="main"> - <?= $this->render('project/filters', array( + <?= $this->render('project_header/header', array( 'project' => $project, 'filters' => $filters, 'categories_list' => $categories_list, diff --git a/app/Template/calendar/show.php b/app/Template/calendar/show.php index d74e945e..7085b51e 100644 --- a/app/Template/calendar/show.php +++ b/app/Template/calendar/show.php @@ -1,5 +1,5 @@ <section id="main"> - <?= $this->render('project/filters', array( + <?= $this->render('project_header/header', array( 'project' => $project, 'filters' => $filters, )) ?> diff --git a/app/Template/config/project.php b/app/Template/config/project.php index a212f65f..1d32a14f 100644 --- a/app/Template/config/project.php +++ b/app/Template/config/project.php @@ -16,6 +16,7 @@ <?= $this->form->text('project_categories', $values, $errors) ?> <p class="form-help"><?= t('Example: "Bug, Feature Request, Improvement"') ?></p> + <?= $this->form->checkbox('disable_private_project', t('Disable private projects'), 1, isset($values['disable_private_project']) && $values['disable_private_project'] == 1) ?> <?= $this->form->checkbox('subtask_restriction', t('Allow only one subtask in progress at the same time for a user'), 1, $values['subtask_restriction'] == 1) ?> <?= $this->form->checkbox('subtask_time_tracking', t('Trigger automatically subtask time tracking'), 1, $values['subtask_time_tracking'] == 1) ?> <?= $this->form->checkbox('cfd_include_closed_tasks', t('Include closed tasks in the cumulative flow diagram'), 1, $values['cfd_include_closed_tasks'] == 1) ?> diff --git a/app/Template/custom_filter/index.php b/app/Template/custom_filter/index.php index 2994ae25..28b6a878 100644 --- a/app/Template/custom_filter/index.php +++ b/app/Template/custom_filter/index.php @@ -36,7 +36,7 @@ <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', 'remove', array('project_id' => $filter['project_id'], 'filter_id' => $filter['id']), true, 'popover') ?></li> + <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> </ul> </div> diff --git a/app/Template/custom_filter/remove.php b/app/Template/custom_filter/remove.php new file mode 100644 index 00000000..d4c67a2b --- /dev/null +++ b/app/Template/custom_filter/remove.php @@ -0,0 +1,17 @@ +<section id="main"> + <div class="page-header"> + <h2><?= t('Remove a custom filter') ?></h2> + </div> + + <div class="confirm"> + <p class="alert alert-info"> + <?= t('Do you really want to remove this custom filter: "%s"?', $filter['name']) ?> + </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') ?> + <?= t('or') ?> + <?= $this->url->link(t('cancel'), 'customfilter', 'index', array('project_id' => $project['id']), false, 'close-popover') ?> + </div> + </div> +</section> diff --git a/app/Template/event/file_create.php b/app/Template/event/task_file_create.php index 1a36bc8f..1a36bc8f 100644 --- a/app/Template/event/file_create.php +++ b/app/Template/event/task_file_create.php diff --git a/app/Template/file/new.php b/app/Template/file/new.php deleted file mode 100644 index 1702638d..00000000 --- a/app/Template/file/new.php +++ /dev/null @@ -1,14 +0,0 @@ -<div class="page-header"> - <h2><?= t('Attach a document') ?></h2> -</div> - -<form action="<?= $this->url->href('file', 'save', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>" method="post" enctype="multipart/form-data"> - <?= $this->form->csrf() ?> - <input type="file" name="files[]" multiple /> - <div class="form-help"><?= t('Maximum size: ') ?><?= is_integer($max_size) ? $this->text->bytes($max_size) : $max_size ?></div> - <div class="form-actions"> - <input type="submit" value="<?= t('Save') ?>" class="btn btn-blue"> - <?= t('or') ?> - <?= $this->url->link(t('cancel'), 'task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'close-popover') ?> - </div> -</form>
\ No newline at end of file diff --git a/app/Template/file/open.php b/app/Template/file/open.php deleted file mode 100644 index 3df012b6..00000000 --- a/app/Template/file/open.php +++ /dev/null @@ -1,6 +0,0 @@ -<div class="page-header"> - <h2><?= $this->e($file['name']) ?></h2> - <div class="task-file-viewer"> - <img src="<?= $this->url->href('file', 'image', array('file_id' => $file['id'], 'project_id' => $task['project_id'], 'task_id' => $file['task_id'])) ?>" alt="<?= $this->e($file['name']) ?>"/> - </div> -</div>
\ No newline at end of file diff --git a/app/Template/file/show.php b/app/Template/file/show.php deleted file mode 100644 index 7a4d38b4..00000000 --- a/app/Template/file/show.php +++ /dev/null @@ -1,58 +0,0 @@ -<?php if (! empty($files) || ! empty($images)): ?> -<div id="attachments" class="task-show-section"> - - <div class="page-header"> - <h2><?= t('Attachments') ?></h2> - </div> - <?php if (! empty($images)): ?> - <h3><?= t('Images') ?></h3> - <ul class="task-show-images"> - <?php foreach ($images as $file): ?> - <li> - <div class="img_container"> - <img src="<?= $this->url->href('file', 'thumbnail', array('file_id' => $file['id'], 'project_id' => $task['project_id'], 'task_id' => $file['task_id'])) ?>" alt="<?= $this->e($file['name']) ?>"/> - </div> - <p> - <?= $this->e($file['name']) ?> - <span class="tooltip" title='<?= t('uploaded by: %s', $file['user_name'] ?: $file['username']).'<br>'.t('uploaded on: %s', $this->dt->datetime($file['date'])).'<br>'.t('size: %s', $this->text->bytes($file['size'])) ?>'> - <i class="fa fa-info-circle"></i> - </span> - </p> - <span class="task-show-file-actions task-show-image-actions"> - <i class="fa fa-eye"></i> <?= $this->url->link(t('open file'), 'file', 'open', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'file_id' => $file['id']), false, 'popover') ?> - <?php if ($this->user->hasProjectAccess('file', 'remove', $task['project_id'])): ?> - <i class="fa fa-trash"></i> <?= $this->url->link(t('remove'), 'file', 'confirm', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'file_id' => $file['id'])) ?> - <?php endif ?> - <i class="fa fa-download"></i> <?= $this->url->link(t('download'), 'file', 'download', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'file_id' => $file['id'])) ?> - </span> - </li> - <?php endforeach ?> - </ul> - <?php endif ?> - - <?php if (! empty($files)): ?> - <h3><?= t('Files') ?></h3> - <table class="task-show-file-table"> - <?php foreach ($files as $file): ?> - <tr> - <td><i class="fa <?= $this->file->icon($file['name']) ?> fa-fw"></i></td> - <td> - <?= $this->e($file['name']) ?> - <span class="tooltip" title='<?= t('uploaded by: %s', $file['user_name'] ?: $file['username']).'<br>'.t('uploaded on: %s', $this->dt->datetime($file['date'])).'<br>'.t('size: %s', $this->text->bytes($file['size'])) ?>'> - <i class="fa fa-info-circle"></i> - </span> - </td> - <td> - <span class="task-show-file-actions"> - <?php if ($this->user->hasProjectAccess('file', 'remove', $task['project_id'])): ?> - <i class="fa fa-trash"></i> <?= $this->url->link(t('remove'), 'file', 'confirm', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'file_id' => $file['id'])) ?> - <?php endif ?> - <i class="fa fa-download"></i> <?= $this->url->link(t('download'), 'file', 'download', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'file_id' => $file['id'])) ?> - </span> - </td> - </tr> - <?php endforeach ?> - </table> - <?php endif ?> -</div> -<?php endif ?>
\ No newline at end of file diff --git a/app/Template/gantt/project.php b/app/Template/gantt/project.php index 1face3b8..fe193c2b 100644 --- a/app/Template/gantt/project.php +++ b/app/Template/gantt/project.php @@ -1,5 +1,5 @@ <section id="main"> - <?= $this->render('project/filters', array( + <?= $this->render('project_header/header', array( 'project' => $project, 'filters' => $filters, 'users_list' => $users_list, diff --git a/app/Template/header.php b/app/Template/header.php index fd9ff24d..a945411e 100644 --- a/app/Template/header.php +++ b/app/Template/header.php @@ -44,9 +44,11 @@ <?php if ($this->user->hasAccess('ProjectCreation', 'create')): ?> <li><i class="fa fa-plus fa-fw"></i><?= $this->url->link(t('New project'), 'ProjectCreation', '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') ?> </li> + <?php endif ?> </ul> </div> @@ -84,13 +86,15 @@ <i class="fa fa-life-ring fa-fw"></i> <?= $this->url->link(t('Documentation'), 'doc', 'show') ?> </li> - <li> - <i class="fa fa-sign-out fa-fw"></i> - <?= $this->url->link(t('Logout'), 'auth', 'logout') ?> - </li> + <?php if (! DISABLE_LOGOUT): ?> + <li> + <i class="fa fa-sign-out fa-fw"></i> + <?= $this->url->link(t('Logout'), 'auth', 'logout') ?> + </li> + <?php endif ?> </ul> </div> </li> </ul> </nav> -</header>
\ No newline at end of file +</header> diff --git a/app/Template/listing/show.php b/app/Template/listing/show.php index e7aa5947..9a5992e3 100644 --- a/app/Template/listing/show.php +++ b/app/Template/listing/show.php @@ -1,7 +1,10 @@ <section id="main"> - <?= $this->render('project/filters', array( + <?= $this->render('project_header/header', array( 'project' => $project, 'filters' => $filters, + 'custom_filters_list' => $custom_filters_list, + 'users_list' => $users_list, + 'categories_list' => $categories_list, )) ?> <?php if ($paginator->isEmpty()): ?> diff --git a/app/Template/notification/file_create.php b/app/Template/notification/task_file_create.php index 63f7d1b8..63f7d1b8 100644 --- a/app/Template/notification/file_create.php +++ b/app/Template/notification/task_file_create.php diff --git a/app/Template/project/filters.php b/app/Template/project/filters.php deleted file mode 100644 index 78794e1c..00000000 --- a/app/Template/project/filters.php +++ /dev/null @@ -1,106 +0,0 @@ -<div class="page-header"> - <?= $this->hook->render('template:project:header:before', array('project' => $project)) ?> - - <div class="dropdown"> - <i class="fa fa-caret-down"></i> <a href="#" class="dropdown-menu"><?= t('Actions') ?></a> - <ul> - <?php if (isset($is_board)): ?> - <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')) ?> - </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')) ?> - </span> - </li> - <li> - <span class="filter-compact"> - <i class="fa fa-th fa-fw"></i> <a href="#" class="filter-toggle-scrolling" title="<?= t('Keyboard shortcut: "%s"', 'c') ?>"><?= t('Compact view') ?></a> - </span> - <span class="filter-wide" style="display: none"> - <i class="fa fa-arrows-h fa-fw"></i> <a href="#" class="filter-toggle-scrolling" title="<?= t('Keyboard shortcut: "%s"', 'c') ?>"><?= t('Horizontal scrolling') ?></a> - </span> - </li> - <li> - <span class="filter-max-height" style="display: none"> - <i class="fa fa-arrows-v fa-fw"></i> <a href="#" class="filter-toggle-height"><?= t('Set maximum column height') ?></a> - </span> - <span class="filter-min-height"> - <i class="fa fa-arrows-v fa-fw"></i> <a href="#" class="filter-toggle-height"><?= t('Remove maximum column height') ?></a> - </span> - </li> - <?php endif ?> - <?= $this->render('project/dropdown', array('project' => $project)) ?> - </ul> - </div> - <ul class="views"> - <li <?= $filters['controller'] === 'board' ? 'class="active"' : '' ?>> - <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')) ?> - </li> - <li <?= $filters['controller'] === 'calendar' ? 'class="active"' : '' ?>> - <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')) ?> - </li> - <li <?= $filters['controller'] === 'listing' ? 'class="active"' : '' ?>> - <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')) ?> - </li> - <?php if ($this->user->hasProjectAccess('gantt', 'project', $project['id'])): ?> - <li <?= $filters['controller'] === 'gantt' ? 'class="active"' : '' ?>> - <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')) ?> - </li> - <?php endif ?> - </ul> - <form method="get" action="<?= $this->url->dir() ?>" class="search"> - <?= $this->form->hidden('controller', $filters) ?> - <?= $this->form->hidden('action', $filters) ?> - <?= $this->form->hidden('project_id', $filters) ?> - <?= $this->form->text('search', $filters, array(), array('placeholder="'.t('Filter').'"'), 'form-input-large') ?> - </form> - - <div class="filter-dropdowns"> - - <?= $this->render('app/filters_helper', array('reset' => 'status:open', 'project' => $project)) ?> - - <?php if (isset($custom_filters_list) && ! empty($custom_filters_list)): ?> - <div class="dropdown filters"> - <i class="fa fa-caret-down"></i> <a href="#" class="dropdown-menu"><?= t('My filters') ?></a> - <ul> - <?php foreach ($custom_filters_list as $filter): ?> - <li><a href="#" class="filter-helper" data-<?php if ($filter['append']): ?><?= 'append-' ?><?php endif ?>filter='<?= $this->e($filter['filter']) ?>'><?= $this->e($filter['name']) ?></a></li> - <?php endforeach ?> - </ul> - </div> - <?php endif ?> - - <?php if (isset($users_list)): ?> - <div class="dropdown filters"> - <i class="fa fa-caret-down"></i> <a href="#" class="dropdown-menu"><?= t('Users') ?></a> - <ul> - <li><a href="#" class="filter-helper" data-append-filter="assignee:nobody"><?= t('Not assigned') ?></a></li> - <?php foreach ($users_list as $user): ?> - <li><a href="#" class="filter-helper" data-append-filter='assignee:"<?= $this->e($user) ?>"'><?= $this->e($user) ?></a></li> - <?php endforeach ?> - </ul> - </div> - <?php endif ?> - - <?php if (isset($categories_list) && ! empty($categories_list)): ?> - <div class="dropdown filters"> - <i class="fa fa-caret-down"></i> <a href="#" class="dropdown-menu"><?= t('Categories') ?></a> - <ul> - <li><a href="#" class="filter-helper" data-append-filter="category:none"><?= t('No category') ?></a></li> - <?php foreach ($categories_list as $category): ?> - <li><a href="#" class="filter-helper" data-append-filter='category:"<?= $this->e($category) ?>"'><?= $this->e($category) ?></a></li> - <?php endforeach ?> - </ul> - </div> - <?php endif ?> - </div> - - <?= $this->hook->render('template:project:header:after', array('project' => $project)) ?> -</div>
\ No newline at end of file diff --git a/app/Template/project_header/dropdown.php b/app/Template/project_header/dropdown.php new file mode 100644 index 00000000..bbc033bf --- /dev/null +++ b/app/Template/project_header/dropdown.php @@ -0,0 +1,34 @@ +<div class="dropdown"> + <i class="fa fa-caret-down"></i> <a href="#" class="dropdown-menu"><?= t('Actions') ?></a> + <ul> + <?php if ($is_board): ?> + <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')) ?> + </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')) ?> + </span> + </li> + <li> + <span class="filter-compact"> + <i class="fa fa-th fa-fw"></i> <a href="#" class="filter-toggle-scrolling" title="<?= t('Keyboard shortcut: "%s"', 'c') ?>"><?= t('Compact view') ?></a> + </span> + <span class="filter-wide" style="display: none"> + <i class="fa fa-arrows-h fa-fw"></i> <a href="#" class="filter-toggle-scrolling" title="<?= t('Keyboard shortcut: "%s"', 'c') ?>"><?= t('Horizontal scrolling') ?></a> + </span> + </li> + <li> + <span class="filter-max-height" style="display: none"> + <i class="fa fa-arrows-v fa-fw"></i> <a href="#" class="filter-toggle-height"><?= t('Set maximum column height') ?></a> + </span> + <span class="filter-min-height"> + <i class="fa fa-arrows-v fa-fw"></i> <a href="#" class="filter-toggle-height"><?= t('Remove maximum column height') ?></a> + </span> + </li> + <?php endif ?> + <?= $this->render('project/dropdown', array('project' => $project)) ?> + </ul> +</div>
\ No newline at end of file diff --git a/app/Template/project_header/header.php b/app/Template/project_header/header.php new file mode 100644 index 00000000..f6e5af9e --- /dev/null +++ b/app/Template/project_header/header.php @@ -0,0 +1,15 @@ +<div class="project-header"> + <?= $this->hook->render('template:project:header:before', array('project' => $project)) ?> + + <?= $this->render('project_header/dropdown', array('project' => $project, 'is_board' => isset($is_board))) ?> + <?= $this->render('project_header/views', array('project' => $project, 'filters' => $filters)) ?> + <?= $this->render('project_header/search', array( + 'project' => $project, + 'filters' => $filters, + 'custom_filters_list' => isset($custom_filters_list) ? $custom_filters_list : array(), + 'users_list' => isset($users_list) ? $users_list : array(), + 'categories_list' => isset($categories_list) ? $categories_list : array(), + )) ?> + + <?= $this->hook->render('template:project:header:after', array('project' => $project)) ?> +</div>
\ No newline at end of file diff --git a/app/Template/project_header/search.php b/app/Template/project_header/search.php new file mode 100644 index 00000000..2b2a2c39 --- /dev/null +++ b/app/Template/project_header/search.php @@ -0,0 +1,45 @@ +<div class="filter-box"> + <form method="get" action="<?= $this->url->dir() ?>" class="search"> + <?= $this->form->hidden('controller', $filters) ?> + <?= $this->form->hidden('action', $filters) ?> + <?= $this->form->hidden('project_id', $filters) ?> + <?= $this->form->text('search', $filters, array(), array('placeholder="'.t('Filter').'"')) ?> + + <?= $this->render('app/filters_helper', array('reset' => 'status:open', 'project' => $project)) ?> + + <?php if (isset($custom_filters_list) && ! empty($custom_filters_list)): ?> + <div class="dropdown"> + <a href="#" class="dropdown-menu dropdown-menu-link-icon" title="<?= t('Custom filters') ?>"><i class="fa fa-bookmark fa-fw"></i><i class="fa fa-caret-down"></i></a> + <ul> + <?php foreach ($custom_filters_list as $filter): ?> + <li><a href="#" class="filter-helper" data-<?php if ($filter['append']): ?><?= 'append-' ?><?php endif ?>filter='<?= $this->e($filter['filter']) ?>'><?= $this->e($filter['name']) ?></a></li> + <?php endforeach ?> + </ul> + </div> + <?php endif ?> + + <?php if (isset($users_list)): ?> + <div class="dropdown"> + <a href="#" class="dropdown-menu dropdown-menu-link-icon" title="<?= t('User filters') ?>"><i class="fa fa-users fa-fw"></i> <i class="fa fa-caret-down"></i></a> + <ul> + <li><a href="#" class="filter-helper" data-append-filter="assignee:nobody"><?= t('Not assigned') ?></a></li> + <?php foreach ($users_list as $user): ?> + <li><a href="#" class="filter-helper" data-append-filter='assignee:"<?= $this->e($user) ?>"'><?= $this->e($user) ?></a></li> + <?php endforeach ?> + </ul> + </div> + <?php endif ?> + + <?php if (isset($categories_list) && ! empty($categories_list)): ?> + <div class="dropdown"> + <a href="#" class="dropdown-menu dropdown-menu-link-icon" title="<?= t('Category filters') ?>"><i class="fa fa-tags fa-fw"></i><i class="fa fa-caret-down"></i></a> + <ul> + <li><a href="#" class="filter-helper" data-append-filter="category:none"><?= t('No category') ?></a></li> + <?php foreach ($categories_list as $category): ?> + <li><a href="#" class="filter-helper" data-append-filter='category:"<?= $this->e($category) ?>"'><?= $this->e($category) ?></a></li> + <?php endforeach ?> + </ul> + </div> + <?php endif ?> + </form> +</div> diff --git a/app/Template/project_header/views.php b/app/Template/project_header/views.php new file mode 100644 index 00000000..1219a213 --- /dev/null +++ b/app/Template/project_header/views.php @@ -0,0 +1,20 @@ +<ul class="views"> + <li <?= $filters['controller'] === 'board' ? 'class="active"' : '' ?>> + <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')) ?> + </li> + <li <?= $filters['controller'] === 'calendar' ? 'class="active"' : '' ?>> + <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')) ?> + </li> + <li <?= $filters['controller'] === 'listing' ? 'class="active"' : '' ?>> + <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')) ?> + </li> + <?php if ($this->user->hasProjectAccess('gantt', 'project', $project['id'])): ?> + <li <?= $filters['controller'] === 'gantt' ? 'class="active"' : '' ?>> + <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')) ?> + </li> + <?php endif ?> +</ul>
\ No newline at end of file diff --git a/app/Template/search/index.php b/app/Template/search/index.php index 329c072a..9231a6f3 100644 --- a/app/Template/search/index.php +++ b/app/Template/search/index.php @@ -8,14 +8,13 @@ </ul> </div> - <div class="search"> + <div class="filter-box"> <form method="get" action="<?= $this->url->dir() ?>" class="search"> <?= $this->form->hidden('controller', $values) ?> <?= $this->form->hidden('action', $values) ?> <?= $this->form->text('search', $values, array(), array(empty($values['search']) ? 'autofocus' : '', 'placeholder="'.t('Search').'"'), 'form-input-large') ?> + <?= $this->render('app/filters_helper') ?> </form> - - <?= $this->render('app/filters_helper') ?> </div> <?php if (empty($values['search'])): ?> diff --git a/app/Template/task/menu.php b/app/Template/task/menu.php index e997a6ad..cddd930a 100644 --- a/app/Template/task/menu.php +++ b/app/Template/task/menu.php @@ -38,11 +38,11 @@ </li> <li> <i class="fa fa-file fa-fw"></i> - <?= $this->url->link(t('Attach a document'), 'file', 'create', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?> + <?= $this->url->link(t('Attach a document'), 'TaskFile', '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'), 'file', 'screenshot', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?> + <?= $this->url->link(t('Add a screenshot'), 'TaskFile', 'screenshot', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?> </li> <li> <i class="fa fa-files-o fa-fw"></i> diff --git a/app/Template/task/show.php b/app/Template/task/show.php index 43906a81..a32232ae 100644 --- a/app/Template/task/show.php +++ b/app/Template/task/show.php @@ -25,7 +25,7 @@ <?= $this->render('task/time_tracking_summary', array('task' => $task)) ?> -<?= $this->render('file/show', array( +<?= $this->render('task_file/show', array( 'task' => $task, 'files' => $files, 'images' => $images diff --git a/app/Template/task_file/new.php b/app/Template/task_file/new.php new file mode 100644 index 00000000..f03ce8dc --- /dev/null +++ b/app/Template/task_file/new.php @@ -0,0 +1,33 @@ +<div class="page-header"> + <h2><?= t('Attach a document') ?></h2> +</div> +<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'])) ?> + </p> +</div> + +<div id="file-error-max-size" style="display:none"> + <p class="alert alert-error"> + <?= t('The maximum allowed file size is %sB.', $this->text->bytes($max_size)) ?> + <a href="#" id="file-browser"><?= t('Choose files again') ?></a> + </p> +</div> + +<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'])) ?>"> + <div id="file-dropzone-inner"> + <?= t('Drag and drop your files here') ?> <?= t('or') ?> <a href="#" id="file-browser"><?= t('choose files') ?></a> + </div> +</div> + +<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> + <?= t('or') ?> + <?= $this->url->link(t('cancel'), 'task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'close-popover') ?> +</div> diff --git a/app/Template/task_file/open.php b/app/Template/task_file/open.php new file mode 100644 index 00000000..e3721b59 --- /dev/null +++ b/app/Template/task_file/open.php @@ -0,0 +1,6 @@ +<div class="page-header"> + <h2><?= $this->e($file['name']) ?></h2> + <div class="task-file-viewer"> + <img src="<?= $this->url->href('TaskFile', 'image', array('file_id' => $file['id'], 'project_id' => $task['project_id'], 'task_id' => $file['task_id'])) ?>" alt="<?= $this->e($file['name']) ?>"/> + </div> +</div>
\ No newline at end of file diff --git a/app/Template/file/remove.php b/app/Template/task_file/remove.php index 37f648eb..5e6c83f2 100644 --- a/app/Template/file/remove.php +++ b/app/Template/task_file/remove.php @@ -8,8 +8,8 @@ </p> <div class="form-actions"> - <?= $this->url->link(t('Yes'), 'file', 'remove', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'file_id' => $file['id']), true, 'btn btn-red') ?> + <?= $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') ?> <?= t('or') ?> - <?= $this->url->link(t('cancel'), 'task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?> + <?= $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/file/screenshot.php b/app/Template/task_file/screenshot.php index 58b93ac3..72214362 100644 --- a/app/Template/file/screenshot.php +++ b/app/Template/task_file/screenshot.php @@ -6,7 +6,7 @@ <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('file', 'screenshot', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>" method="post"> +<form class="popover-form" action="<?= $this->url->href('TaskFile', '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"> diff --git a/app/Template/task_file/show.php b/app/Template/task_file/show.php new file mode 100644 index 00000000..98f26c33 --- /dev/null +++ b/app/Template/task_file/show.php @@ -0,0 +1,84 @@ +<?php if (! empty($files) || ! empty($images)): ?> +<div id="attachments" class="task-show-section"> + + <div class="page-header"> + <h2><?= t('Attachments') ?></h2> + </div> + <?php if (! empty($images)): ?> + <div class="file-thumbnails"> + <?php foreach ($images as $file): ?> + <div class="file-thumbnail"> + <a href="<?= $this->url->href('TaskFile', 'open', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'file_id' => $file['id'])) ?>" class="popover"><img src="<?= $this->url->href('TaskFile', 'thumbnail', array('file_id' => $file['id'], 'project_id' => $task['project_id'], 'task_id' => $file['task_id'])) ?>" title="<?= $this->e($file['name']) ?>" alt="<?= $this->e($file['name']) ?>"></a> + <div class="file-thumbnail-content"> + <div class="file-thumbnail-title"> + <div class="dropdown"> + <a href="#" class="dropdown-menu dropdown-menu-link-text"><?= $this->e($file['name']) ?> <i class="fa fa-caret-down"></i></a> + <ul> + <?php if ($this->user->hasProjectAccess('TaskFile', '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') ?> + </li> + <?php endif ?> + <li> + <i class="fa fa-download fa-fw"></i> + <?= $this->url->link(t('Download'), 'TaskFile', 'download', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'file_id' => $file['id'])) ?> + </li> + </ul> + </div> + </div> + <div class="file-thumbnail-description"> + <span class="tooltip" title='<?= t('Uploaded: %s', $this->dt->datetime($file['date'])).'<br>'.t('Size: %s', $this->text->bytes($file['size'])) ?>'> + <i class="fa fa-info-circle"></i> + </span> + <?= t('Uploaded by %s', $file['user_name'] ?: $file['username']) ?> + </div> + </div> + </div> + <?php endforeach ?> + </div> + <?php endif ?> + + <?php if (! empty($files)): ?> + <table class="table-stripped"> + <tr> + <th><?= t('Filename') ?></th> + <th><?= t('Creator') ?></th> + <th><?= t('Date') ?></th> + <th><?= t('Size') ?></th> + </tr> + <?php foreach ($files as $file): ?> + <tr> + <td> + <i class="fa <?= $this->file->icon($file['name']) ?> fa-fw"></i> + <div class="dropdown"> + <a href="#" class="dropdown-menu dropdown-menu-link-text"><?= $this->e($file['name']) ?> <i class="fa fa-caret-down"></i></a> + <ul> + <?php if ($this->user->hasProjectAccess('TaskFile', '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') ?> + </li> + <?php endif ?> + <li> + <i class="fa fa-download fa-fw"></i> + <?= $this->url->link(t('Download'), 'TaskFile', 'download', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'file_id' => $file['id'])) ?> + </li> + </ul> + </div> + </td> + <td> + <?= $this->e($file['user_name'] ?: $file['username']) ?> + </td> + <td> + <?= $this->dt->date($file['date']) ?> + </td> + <td> + <?= $this->text->bytes($file['size']) ?> + </td> + </tr> + <?php endforeach ?> + </table> + <?php endif ?> +</div> +<?php endif ?>
\ No newline at end of file diff --git a/app/Template/user/dropdown.php b/app/Template/user/dropdown.php new file mode 100644 index 00000000..b74ed6e0 --- /dev/null +++ b/app/Template/user/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'), '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/index.php b/app/Template/user/index.php index cb7416d6..494c1465 100644 --- a/app/Template/user/index.php +++ b/app/Template/user/index.php @@ -12,23 +12,21 @@ <?php if ($paginator->isEmpty()): ?> <p class="alert"><?= t('No user') ?></p> <?php else: ?> - <table> + <table class="table-stripped"> <tr> - <th><?= $paginator->order(t('Id'), 'id') ?></th> - <th><?= $paginator->order(t('Username'), 'username') ?></th> - <th><?= $paginator->order(t('Name'), 'name') ?></th> - <th><?= $paginator->order(t('Email'), 'email') ?></th> - <th><?= $paginator->order(t('Role'), 'role') ?></th> - <th><?= $paginator->order(t('Two factor authentication'), 'twofactor_activated') ?></th> - <th><?= $paginator->order(t('Notifications'), 'notifications_enabled') ?></th> - <th><?= $paginator->order(t('Account type'), 'is_ldap_user') ?></th> + <th class="column-18"><?= $paginator->order(t('Username'), 'username') ?></th> + <th class="column-18"><?= $paginator->order(t('Name'), 'name') ?></th> + <th class="column-15"><?= $paginator->order(t('Email'), 'email') ?></th> + <th class="column-15"><?= $paginator->order(t('Role'), 'role') ?></th> + <th class="column-10"><?= $paginator->order(t('Two Factor'), 'twofactor_activated') ?></th> + <th class="column-10"><?= $paginator->order(t('Account type'), 'is_ldap_user') ?></th> + <th class="column-10"><?= $paginator->order(t('Status'), 'is_active') ?></th> + <th class="column-5"><?= t('Actions') ?></th> </tr> <?php foreach ($paginator->getCollection() as $user): ?> <tr> <td> - <?= $this->url->link('#'.$user['id'], 'user', 'show', array('user_id' => $user['id'])) ?> - </td> - <td> + <?= '#'.$user['id'] ?> <?= $this->url->link($this->e($user['username']), 'user', 'show', array('user_id' => $user['id'])) ?> </td> <td> @@ -44,14 +42,17 @@ <?= $user['twofactor_activated'] ? t('Yes') : t('No') ?> </td> <td> - <?php if ($user['notifications_enabled'] == 1): ?> - <?= t('Enabled') ?> + <?= $user['is_ldap_user'] ? t('Remote') : t('Local') ?> + </td> + <td> + <?php if ($user['is_active'] == 1): ?> + <?= t('Active') ?> <?php else: ?> - <?= t('Disabled') ?> + <?= t('Inactive') ?> <?php endif ?> </td> <td> - <?= $user['is_ldap_user'] ? t('Remote') : t('Local') ?> + <?= $this->render('user/dropdown', array('user' => $user)) ?> </td> </tr> <?php endforeach ?> diff --git a/app/Template/user/show.php b/app/Template/user/show.php index 89c6b36b..9da56666 100644 --- a/app/Template/user/show.php +++ b/app/Template/user/show.php @@ -5,6 +5,7 @@ <li><?= t('Username:') ?> <strong><?= $this->e($user['username']) ?></strong></li> <li><?= t('Name:') ?> <strong><?= $this->e($user['name']) ?: t('None') ?></strong></li> <li><?= t('Email:') ?> <strong><?= $this->e($user['email']) ?: t('None') ?></strong></li> + <li><?= t('Status:') ?> <strong><?= $user['is_active'] ? t('Active') : t('Inactive') ?></strong></li> </ul> <div class="page-header"> diff --git a/app/Template/user/sidebar.php b/app/Template/user/sidebar.php index 7e367443..2faf8220 100644 --- a/app/Template/user/sidebar.php +++ b/app/Template/user/sidebar.php @@ -1,9 +1,11 @@ <div class="sidebar"> <h2><?= t('Information') ?></h2> <ul> - <li <?= $this->app->checkMenuSelection('user', 'show') ?>> - <?= $this->url->link(t('Summary'), 'user', 'show', array('user_id' => $user['id'])) ?> - </li> + <?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'])) ?> @@ -30,9 +32,12 @@ <h2><?= t('Actions') ?></h2> <ul> <?php if ($this->user->isAdmin() || $this->user->isCurrentUser($user['id'])): ?> - <li <?= $this->app->checkMenuSelection('user', 'edit') ?>> - <?= $this->url->link(t('Edit profile'), 'user', 'edit', array('user_id' => $user['id'])) ?> - </li> + + <?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> + <?php endif ?> <?php if ($user['is_ldap_user'] == 0): ?> <li <?= $this->app->checkMenuSelection('user', 'password') ?>> @@ -71,11 +76,5 @@ <?php endif ?> <?= $this->hook->render('template:user:sidebar:actions', array('user' => $user)) ?> - - <?php if ($this->user->hasAccess('user', 'remove') && ! $this->user->isCurrentUser($user['id'])): ?> - <li <?= $this->app->checkMenuSelection('user', 'remove') ?>> - <?= $this->url->link(t('Remove'), 'user', 'remove', array('user_id' => $user['id'])) ?> - </li> - <?php endif ?> </ul> </div>
\ No newline at end of file diff --git a/app/Template/user_status/disable.php b/app/Template/user_status/disable.php new file mode 100644 index 00000000..90d8c757 --- /dev/null +++ b/app/Template/user_status/disable.php @@ -0,0 +1,13 @@ +<div class="page-header"> + <h2><?= t('Disable user') ?></h2> +</div> + +<div class="confirm"> + <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') ?> + <?= t('or') ?> + <?= $this->url->link(t('cancel'), 'user', 'index', array(), false, 'close-popover') ?> + </div> +</div> diff --git a/app/Template/user_status/enable.php b/app/Template/user_status/enable.php new file mode 100644 index 00000000..cd3d4947 --- /dev/null +++ b/app/Template/user_status/enable.php @@ -0,0 +1,13 @@ +<div class="page-header"> + <h2><?= t('Enable user') ?></h2> +</div> + +<div class="confirm"> + <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') ?> + <?= t('or') ?> + <?= $this->url->link(t('cancel'), 'user', 'index', array(), false, 'close-popover') ?> + </div> +</div> diff --git a/app/Template/user/remove.php b/app/Template/user_status/remove.php index 810a3a3f..cd5c09a6 100644 --- a/app/Template/user/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'), 'user', 'remove', array('user_id' => $user['id'], 'confirmation' => 'yes'), true, 'btn btn-red') ?> + <?= $this->url->link(t('Yes'), 'UserStatus', 'remove', array('user_id' => $user['id']), true, 'btn btn-red') ?> <?= t('or') ?> - <?= $this->url->link(t('cancel'), 'user', 'show', array('user_id' => $user['id'])) ?> + <?= $this->url->link(t('cancel'), 'user', 'index', array(), false, 'close-popover') ?> </div> -</div>
\ No newline at end of file +</div> diff --git a/app/constants.php b/app/constants.php index be9bb6a7..011fa784 100644 --- a/app/constants.php +++ b/app/constants.php @@ -23,6 +23,9 @@ defined('DB_HOSTNAME') or define('DB_HOSTNAME', 'localhost'); defined('DB_NAME') or define('DB_NAME', 'kanboard'); defined('DB_PORT') or define('DB_PORT', null); +// Database backend group provider +defined('DB_GROUP_PROVIDER') or define('DB_GROUP_PROVIDER', true); + // LDAP configuration defined('LDAP_AUTH') or define('LDAP_AUTH', false); defined('LDAP_SERVER') or define('LDAP_SERVER', ''); @@ -94,6 +97,9 @@ defined('ENABLE_URL_REWRITE') or define('ENABLE_URL_REWRITE', isset($_SERVER['HT // Hide login form defined('HIDE_LOGIN_FORM') or define('HIDE_LOGIN_FORM', false); +// Disabling logout (for external SSO authentication) +defined('DISABLE_LOGOUT') or define('DISABLE_LOGOUT', false); + // Bruteforce protection defined('BRUTEFORCE_CAPTCHA') or define('BRUTEFORCE_CAPTCHA', 3); defined('BRUTEFORCE_LOCKDOWN') or define('BRUTEFORCE_LOCKDOWN', 6); |
