summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
Diffstat (limited to 'app')
-rw-r--r--app/Api/File.php55
-rw-r--r--app/Api/Me.php4
-rw-r--r--app/Api/User.php15
-rw-r--r--app/Auth/DatabaseAuth.php3
-rw-r--r--app/Controller/Auth.php9
-rw-r--r--app/Controller/BoardPopover.php2
-rw-r--r--app/Controller/BoardTooltip.php2
-rw-r--r--app/Controller/Config.php7
-rw-r--r--app/Controller/Customfilter.php17
-rw-r--r--app/Controller/Gantt.php1
-rw-r--r--app/Controller/Listing.php3
-rw-r--r--app/Controller/Projectuser.php6
-rw-r--r--app/Controller/Task.php4
-rw-r--r--app/Controller/TaskFile.php (renamed from app/Controller/File.php)40
-rw-r--r--app/Controller/Taskcreation.php1
-rw-r--r--app/Controller/Taskmodification.php1
-rw-r--r--app/Controller/User.php29
-rw-r--r--app/Controller/UserStatus.php111
-rw-r--r--app/Core/Base.php3
-rw-r--r--app/Core/User/UserProfile.php2
-rw-r--r--app/Helper/App.php5
-rw-r--r--app/Helper/File.php11
-rw-r--r--app/Helper/Text.php23
-rw-r--r--app/Locale/bs_BA/translations.php30
-rw-r--r--app/Locale/cs_CZ/translations.php30
-rw-r--r--app/Locale/da_DK/translations.php30
-rw-r--r--app/Locale/de_DE/translations.php30
-rw-r--r--app/Locale/el_GR/translations.php30
-rw-r--r--app/Locale/es_ES/translations.php30
-rw-r--r--app/Locale/fi_FI/translations.php30
-rw-r--r--app/Locale/fr_FR/translations.php30
-rw-r--r--app/Locale/hu_HU/translations.php30
-rw-r--r--app/Locale/id_ID/translations.php30
-rw-r--r--app/Locale/it_IT/translations.php30
-rw-r--r--app/Locale/ja_JP/translations.php30
-rw-r--r--app/Locale/my_MY/translations.php30
-rw-r--r--app/Locale/nb_NO/translations.php30
-rw-r--r--app/Locale/nl_NL/translations.php30
-rw-r--r--app/Locale/pl_PL/translations.php30
-rw-r--r--app/Locale/pt_BR/translations.php132
-rw-r--r--app/Locale/pt_PT/translations.php30
-rw-r--r--app/Locale/ru_RU/translations.php42
-rw-r--r--app/Locale/sr_Latn_RS/translations.php30
-rw-r--r--app/Locale/sv_SE/translations.php30
-rw-r--r--app/Locale/th_TH/translations.php30
-rw-r--r--app/Locale/tr_TR/translations.php30
-rw-r--r--app/Locale/zh_CN/translations.php96
-rw-r--r--app/Model/File.php280
-rw-r--r--app/Model/Notification.php4
-rw-r--r--app/Model/ProjectFile.php40
-rw-r--r--app/Model/ProjectGroupRole.php1
-rw-r--r--app/Model/ProjectPermission.php3
-rw-r--r--app/Model/ProjectUserRole.php5
-rw-r--r--app/Model/Task.php2
-rw-r--r--app/Model/TaskFile.php54
-rw-r--r--app/Model/TaskFinder.php2
-rw-r--r--app/Model/User.php40
-rw-r--r--app/Notification/Mail.php4
-rw-r--r--app/Schema/Mysql.php27
-rw-r--r--app/Schema/Postgres.php28
-rw-r--r--app/Schema/Sqlite.php26
-rw-r--r--app/ServiceProvider/AuthenticationProvider.php5
-rw-r--r--app/ServiceProvider/ClassProvider.php3
-rw-r--r--app/ServiceProvider/GroupProvider.php5
-rw-r--r--app/ServiceProvider/RouteProvider.php3
-rw-r--r--app/Subscriber/NotificationSubscriber.php4
-rw-r--r--app/Template/app/filters_helper.php4
-rw-r--r--app/Template/app/layout.php2
-rw-r--r--app/Template/app/overview.php5
-rw-r--r--app/Template/board/tooltip_files.php4
-rw-r--r--app/Template/board/view_private.php2
-rw-r--r--app/Template/calendar/show.php2
-rw-r--r--app/Template/config/project.php1
-rw-r--r--app/Template/custom_filter/index.php2
-rw-r--r--app/Template/custom_filter/remove.php17
-rw-r--r--app/Template/event/task_file_create.php (renamed from app/Template/event/file_create.php)0
-rw-r--r--app/Template/file/new.php14
-rw-r--r--app/Template/file/open.php6
-rw-r--r--app/Template/file/show.php58
-rw-r--r--app/Template/gantt/project.php2
-rw-r--r--app/Template/header.php14
-rw-r--r--app/Template/listing/show.php5
-rw-r--r--app/Template/notification/task_file_create.php (renamed from app/Template/notification/file_create.php)0
-rw-r--r--app/Template/project/filters.php106
-rw-r--r--app/Template/project_header/dropdown.php34
-rw-r--r--app/Template/project_header/header.php15
-rw-r--r--app/Template/project_header/search.php45
-rw-r--r--app/Template/project_header/views.php20
-rw-r--r--app/Template/search/index.php5
-rw-r--r--app/Template/task/menu.php4
-rw-r--r--app/Template/task/show.php2
-rw-r--r--app/Template/task_file/new.php33
-rw-r--r--app/Template/task_file/open.php6
-rw-r--r--app/Template/task_file/remove.php (renamed from app/Template/file/remove.php)4
-rw-r--r--app/Template/task_file/screenshot.php (renamed from app/Template/file/screenshot.php)2
-rw-r--r--app/Template/task_file/show.php84
-rw-r--r--app/Template/user/dropdown.php27
-rw-r--r--app/Template/user/index.php33
-rw-r--r--app/Template/user/show.php1
-rw-r--r--app/Template/user/sidebar.php23
-rw-r--r--app/Template/user_status/disable.php13
-rw-r--r--app/Template/user_status/enable.php13
-rw-r--r--app/Template/user_status/remove.php (renamed from app/Template/user/remove.php)6
-rw-r--r--app/constants.php6
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): ?>
- &nbsp;<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') ?>
+ &nbsp;<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'] ?>&nbsp;
<?= $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);