1
0
Fork 0
mirror of https://github.com/YunoHost-Apps/kanboard_ynh.git synced 2024-09-03 19:36:17 +02:00

Update kanboard to v1.0.31

This commit is contained in:
mbugeia 2016-07-23 14:11:39 +02:00
parent 918986f169
commit 6cc879dffe
1229 changed files with 39417 additions and 16044 deletions

View file

@ -33,7 +33,7 @@ From command line:
Infos
-----
Kanboard v1.0.27
Kanboard v1.0.31
Yunohost forum thread: <https://forum.yunohost.org/t/kanboard-package/78>
@ -63,7 +63,7 @@ Test it
Test or upgrade to dev version:
```
su - admin
git clone -b dev https://github.com/mbugeia/kanboard_ynh
git clone -b dev https://github.com/YunoHost-Apps/kanboard_ynh
# to install
sudo yunohost app install -l Kanboard /home/admin/kanboard_ynh
# to upgrade

View file

@ -3,8 +3,11 @@
// Enable/Disable debug
define('DEBUG', false);
// Debug file path
define('DEBUG_FILE', __DIR__.DIRECTORY_SEPARATOR.'data'.DIRECTORY_SEPARATOR.'debug.log');
// Available log drivers: syslog, stderr, stdout or file
define('LOG_DRIVER', '');
// Log filename if the log driver is "file"
define('LOG_FILE', __DIR__.DIRECTORY_SEPARATOR.'data'.DIRECTORY_SEPARATOR.'debug.log');
// Plugins directory
define('PLUGINS_DIR', 'plugins');
@ -46,6 +49,15 @@ define('DB_NAME', 'yuno_dbuser');
// Mysql/Postgres custom port (null = default port)
define('DB_PORT', null);
// Mysql SSL key
define('DB_SSL_KEY', null);
// Mysql SSL certificate
define('DB_SSL_CERT', null);
// Mysql SSL CA
define('DB_SSL_CA', null);
// Enable LDAP authentication (false by default)
define('LDAP_AUTH', false);
@ -101,6 +113,13 @@ define('LDAP_USER_ATTRIBUTE_EMAIL', 'mail');
// LDAP attribute to find groups in user profile
define('LDAP_USER_ATTRIBUTE_GROUPS', 'memberof');
// LDAP attribute for user avatar image: thumbnailPhoto or jpegPhoto
define('LDAP_USER_ATTRIBUTE_PHOTO', '');
// LDAP attribute for user language, example: 'preferredlanguage'
// Put an empty string to disable language sync
define('LDAP_USER_ATTRIBUTE_LANGUAGE', '');
// Allow automatic LDAP user creation
define('LDAP_USER_CREATION', true);
@ -123,6 +142,11 @@ define('LDAP_GROUP_BASE_DN', '');
// Example for ActiveDirectory: (&(objectClass=group)(sAMAccountName=%s*))
define('LDAP_GROUP_FILTER', '');
// LDAP user group filter
// If this filter is configured, Kanboard will search user groups in LDAP_GROUP_BASE_DN with this filter
// Example for OpenLDAP: (&(objectClass=posixGroup)(memberUid=%s))
define('LDAP_GROUP_USER_FILTER', '');
// LDAP attribute for the group name
define('LDAP_GROUP_ATTRIBUTE_NAME', 'cn');
@ -147,9 +171,6 @@ define('ENABLE_HSTS', false);
// Enable or disable "X-Frame-Options: DENY" HTTP header
define('ENABLE_XFRAME', true);
// Enable syslog logging
define('ENABLE_SYSLOG', true);
// Escape html inside markdown text
define('MARKDOWN_ESCAPE_HTML', true);

26
sources/.htaccess Normal file
View file

@ -0,0 +1,26 @@
<IfModule mod_rewrite.c>
Options -MultiViews
SetEnv HTTP_MOD_REWRITE On
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [QSA,L]
</IfModule>
<FilesMatch "(kanboard|config.php|config.default.php)">
<IfModule mod_version.c>
<IfVersion >= 2.3>
Require all denied
</IfVersion>
<IfVersion < 2.3>
Order allow,deny
Deny from all
</IfVersion>
</IfModule>
<IfModule !mod_version.c>
Order allow,deny
Deny from all
</IfModule>
</FilesMatch>

View file

@ -1,3 +1,135 @@
Version 1.0.31
--------------
New features:
* Added tags: global and specific by project
* Added application and project roles validation for API procedure calls
* Added new API call: "getProjectByIdentifier"
* Added new API calls for external task links, project attachments and subtask time tracking
Improvements:
* Use PHP 7 for the Docker image
* Preserve role for existing users when using ReverseProxy authentication
* Handle priority for task and project duplication
* Expose task reference field to the user interface
* Improve ICal export
* Added argument owner_id and identifier to project API calls
* Rewrite integration tests to run with Docker containers
* Use the same task form layout everywhere
* Removed some tasks dropdown menus that are now available with task edit form
* Make embedded documentation readable in multiple languages (if a translation is available)
* Added acceptance tests (browser tests)
Bug fixes:
* Fixed broken CSV exports
* Fixed identical background color for LetterAvatar on 32bits platforms (Hash greater than PHP_MAX_INT)
* Fixed lexer issue with non word characters
* Flush memory cache in worker to get latest config values
* Fixed empty title for web notification with only one overdue task
* Take default swimlane into consideration for SwimlaneModel::getFirstActiveSwimlane()
* Fixed "due today" highlighting
Version 1.0.30
--------------
Improvements:
* Show tasks that are due today in a different color
Bug fixes:
* Fixed wrong controller for search in dashboard
* Fixed plural form in alert message
* Fixed CSS cosmetic issue with popover and tooltips
Version 1.0.29
--------------
New features:
* Manage plugin from the user interface and from the command line
* Added support for background workers
* Added the possibility to convert a subtask to a task
* Added menu entry to add tasks from all project views
* Add tasks in bulk from the board
* Add dropdown for projects
* Added config parameter to allow self-signed certificates for the HTTP client
Improvements:
* Display local date format in date picker
* Configure email settings with the user interface in addition to config file
* Upgrade Docker image to Alpine Linux 3.4
* Move task import to a separate section
* Mark web notification as read when clicking on it
* Support strtotime strings for date search
* Reset failed login counter and unlock user when changing password
* Task do not open anymore in a new window on the Gantt chart
* Do not display task progress for tasks with no start/end date
* Use Gulp and Bower to manage assets
* Controller and Middleware refactoring
* Replace jQuery mobile detection by the library isMobile
Bug fixes:
* Fixed user date format parsing for dates that can be valid in multiple formats
* Do not sync user role if LDAP groups are not configured
* Fixed issue with unicode handling for letter based avatars and user initials
* Do not send notifications to disabled users
* Fixed wrong redirect when removing a task from the task view page
Breaking changes:
* Webhook to create tasks have been removed, use the API instead
* All controllers have been renamed, people who are not using URL rewriting will see different URLs
* All models have been renamed, plugin maintainers will have to update their plugins
Version 1.0.28
--------------
New features:
* Added automated action to change task color based on the priority
* Added support for LDAP Posix Groups (OpenLDAP with memberUid or groupOfNames)
* Added support for LDAP user photo attribute (Avatar image)
* Added support for language LDAP attribute
* Added support for Mysql SSL connection
* Search in activity stream
* Search in comments
* Search by task creator
* Added command line utility to reset user password and to disable 2FA
Improvements:
* Improve Avatar upload form
* User roles are now synced with LDAP at each login
* Improve web page title on the task view
* Unify task drop-down menu between different views
* Improve LDAP user group membership synchronization
* Category and user filters do not append anymore in search field
* Added more template hooks
* Added tasks search with the API
* Added priority field to API procedures
* Added API procedure "getMemberGroups"
* Added parameters for overdue tasks notifications: group by projects and send only to managers
* Allow people to install Kanboard outside of the DocumentRoot
* Allow plugins to be loaded from another folder
* Filter/Lexer/QueryBuilder refactoring
Bug fixes:
* Allow a project owner to manage his own public project
* Fixed PHP warning when removing a user with no Avatar image
* Fixed improper Markdown escaping for some tooltips
* Closing all tasks by column, also update closed tasks
* Fixed wrong task link generation within Markdown text
* Fixed wrong URL on comment toggle link for sorting
* Fixed form submission with Meta+Enter keyboard shortcut
* Removed PHP notices in comment suppression view
Version 1.0.27
--------------

View file

@ -65,11 +65,11 @@ class CommentCreation extends Base
*/
public function doAction(array $data)
{
return (bool) $this->comment->create(array(
return (bool) $this->commentModel->create(array(
'reference' => isset($data['reference']) ? $data['reference'] : '',
'comment' => $data['comment'],
'task_id' => $data['task_id'],
'user_id' => isset($data['user_id']) && $this->projectPermission->isAssignable($this->getProjectId(), $data['user_id']) ? $data['user_id'] : 0,
'user_id' => isset($data['user_id']) && $this->projectPermissionModel->isAssignable($this->getProjectId(), $data['user_id']) ? $data['user_id'] : 0,
));
}

View file

@ -2,7 +2,7 @@
namespace Kanboard\Action;
use Kanboard\Model\Task;
use Kanboard\Model\TaskModel;
/**
* Add a comment of the triggering event to the task description.
@ -32,7 +32,7 @@ class CommentCreationMoveTaskColumn extends Base
public function getCompatibleEvents()
{
return array(
Task::EVENT_MOVE_COLUMN,
TaskModel::EVENT_MOVE_COLUMN,
);
}
@ -71,9 +71,9 @@ class CommentCreationMoveTaskColumn extends Base
return false;
}
$column = $this->column->getById($data['column_id']);
$column = $this->columnModel->getById($data['column_id']);
return (bool) $this->comment->create(array(
return (bool) $this->commentModel->create(array(
'comment' => t('Moved to column %s', $column['title']),
'task_id' => $data['task_id'],
'user_id' => $this->userSession->getId(),

View file

@ -2,7 +2,7 @@
namespace Kanboard\Action;
use Kanboard\Model\Task;
use Kanboard\Model\TaskModel;
/**
* Set a category automatically according to the color
@ -32,7 +32,7 @@ class TaskAssignCategoryColor extends Base
public function getCompatibleEvents()
{
return array(
Task::EVENT_CREATE_UPDATE,
TaskModel::EVENT_CREATE_UPDATE,
);
}
@ -78,7 +78,7 @@ class TaskAssignCategoryColor extends Base
'category_id' => $this->getParam('category_id'),
);
return $this->taskModification->update($values);
return $this->taskModificationModel->update($values);
}
/**

View file

@ -74,7 +74,7 @@ class TaskAssignCategoryLabel extends Base
'category_id' => $this->getParam('category_id'),
);
return $this->taskModification->update($values);
return $this->taskModificationModel->update($values);
}
/**

View file

@ -2,7 +2,7 @@
namespace Kanboard\Action;
use Kanboard\Model\TaskLink;
use Kanboard\Model\TaskLinkModel;
/**
* Set a category automatically according to a task link
@ -33,7 +33,7 @@ class TaskAssignCategoryLink extends Base
public function getCompatibleEvents()
{
return array(
TaskLink::EVENT_CREATE_UPDATE,
TaskLinkModel::EVENT_CREATE_UPDATE,
);
}
@ -79,7 +79,7 @@ class TaskAssignCategoryLink extends Base
'category_id' => $this->getParam('category_id'),
);
return $this->taskModification->update($values);
return $this->taskModificationModel->update($values);
}
/**
@ -92,7 +92,7 @@ class TaskAssignCategoryLink extends Base
public function hasRequiredCondition(array $data)
{
if ($data['link_id'] == $this->getParam('link_id')) {
$task = $this->taskFinder->getById($data['task_id']);
$task = $this->taskFinderModel->getById($data['task_id']);
return empty($task['category_id']);
}

View file

@ -2,7 +2,7 @@
namespace Kanboard\Action;
use Kanboard\Model\Task;
use Kanboard\Model\TaskModel;
/**
* Assign a color to a specific category
@ -32,7 +32,7 @@ class TaskAssignColorCategory extends Base
public function getCompatibleEvents()
{
return array(
Task::EVENT_CREATE_UPDATE,
TaskModel::EVENT_CREATE_UPDATE,
);
}
@ -78,7 +78,7 @@ class TaskAssignColorCategory extends Base
'color_id' => $this->getParam('color_id'),
);
return $this->taskModification->update($values, false);
return $this->taskModificationModel->update($values, false);
}
/**

View file

@ -2,7 +2,7 @@
namespace Kanboard\Action;
use Kanboard\Model\Task;
use Kanboard\Model\TaskModel;
/**
* Assign a color to a task
@ -32,8 +32,8 @@ class TaskAssignColorColumn extends Base
public function getCompatibleEvents()
{
return array(
Task::EVENT_CREATE,
Task::EVENT_MOVE_COLUMN,
TaskModel::EVENT_CREATE,
TaskModel::EVENT_MOVE_COLUMN,
);
}
@ -79,7 +79,7 @@ class TaskAssignColorColumn extends Base
'color_id' => $this->getParam('color_id'),
);
return $this->taskModification->update($values, false);
return $this->taskModificationModel->update($values, false);
}
/**

View file

@ -2,7 +2,7 @@
namespace Kanboard\Action;
use Kanboard\Model\TaskLink;
use Kanboard\Model\TaskLinkModel;
/**
* Assign a color to a specific task link
@ -32,7 +32,7 @@ class TaskAssignColorLink extends Base
public function getCompatibleEvents()
{
return array(
TaskLink::EVENT_CREATE_UPDATE,
TaskLinkModel::EVENT_CREATE_UPDATE,
);
}
@ -78,7 +78,7 @@ class TaskAssignColorLink extends Base
'color_id' => $this->getParam('color_id'),
);
return $this->taskModification->update($values, false);
return $this->taskModificationModel->update($values, false);
}
/**

View file

@ -0,0 +1,95 @@
<?php
namespace Kanboard\Action;
use Kanboard\Model\TaskModel;
/**
* Assign a color to a priority
*
* @package action
* @author Frederic Guillot
*/
class TaskAssignColorPriority extends Base
{
/**
* Get automatic action description
*
* @access public
* @return string
*/
public function getDescription()
{
return t('Assign automatically a color based on a priority');
}
/**
* Get the list of compatible events
*
* @access public
* @return array
*/
public function getCompatibleEvents()
{
return array(
TaskModel::EVENT_CREATE_UPDATE,
);
}
/**
* Get the required parameter for the action (defined by the user)
*
* @access public
* @return array
*/
public function getActionRequiredParameters()
{
return array(
'color_id' => t('Color'),
'priority' => t('Priority'),
);
}
/**
* Get the required parameter for the event
*
* @access public
* @return string[]
*/
public function getEventRequiredParameters()
{
return array(
'task_id',
'priority',
);
}
/**
* Execute the action (change the task color)
*
* @access public
* @param array $data Event data dictionary
* @return bool True if the action was executed or false when not executed
*/
public function doAction(array $data)
{
$values = array(
'id' => $data['task_id'],
'color_id' => $this->getParam('color_id'),
);
return $this->taskModificationModel->update($values, false);
}
/**
* Check if the event data meet the action condition
*
* @access public
* @param array $data Event data dictionary
* @return bool
*/
public function hasRequiredCondition(array $data)
{
return $data['priority'] == $this->getParam('priority');
}
}

View file

@ -2,7 +2,7 @@
namespace Kanboard\Action;
use Kanboard\Model\Task;
use Kanboard\Model\TaskModel;
/**
* Assign a color to a specific user
@ -32,8 +32,8 @@ class TaskAssignColorUser extends Base
public function getCompatibleEvents()
{
return array(
Task::EVENT_CREATE,
Task::EVENT_ASSIGNEE_CHANGE,
TaskModel::EVENT_CREATE,
TaskModel::EVENT_ASSIGNEE_CHANGE,
);
}
@ -79,7 +79,7 @@ class TaskAssignColorUser extends Base
'color_id' => $this->getParam('color_id'),
);
return $this->taskModification->update($values, false);
return $this->taskModificationModel->update($values, false);
}
/**

View file

@ -2,7 +2,7 @@
namespace Kanboard\Action;
use Kanboard\Model\Task;
use Kanboard\Model\TaskModel;
/**
* Assign a task to the logged user
@ -32,7 +32,7 @@ class TaskAssignCurrentUser extends Base
public function getCompatibleEvents()
{
return array(
Task::EVENT_CREATE,
TaskModel::EVENT_CREATE,
);
}
@ -78,7 +78,7 @@ class TaskAssignCurrentUser extends Base
'owner_id' => $this->userSession->getId(),
);
return $this->taskModification->update($values);
return $this->taskModificationModel->update($values);
}
/**

View file

@ -2,7 +2,7 @@
namespace Kanboard\Action;
use Kanboard\Model\Task;
use Kanboard\Model\TaskModel;
/**
* Assign a task to the logged user on column change
@ -32,7 +32,7 @@ class TaskAssignCurrentUserColumn extends Base
public function getCompatibleEvents()
{
return array(
Task::EVENT_MOVE_COLUMN,
TaskModel::EVENT_MOVE_COLUMN,
);
}
@ -81,7 +81,7 @@ class TaskAssignCurrentUserColumn extends Base
'owner_id' => $this->userSession->getId(),
);
return $this->taskModification->update($values);
return $this->taskModificationModel->update($values);
}
/**

View file

@ -2,7 +2,7 @@
namespace Kanboard\Action;
use Kanboard\Model\Task;
use Kanboard\Model\TaskModel;
/**
* Assign a task to a specific user
@ -32,8 +32,8 @@ class TaskAssignSpecificUser extends Base
public function getCompatibleEvents()
{
return array(
Task::EVENT_CREATE_UPDATE,
Task::EVENT_MOVE_COLUMN,
TaskModel::EVENT_CREATE_UPDATE,
TaskModel::EVENT_MOVE_COLUMN,
);
}
@ -79,7 +79,7 @@ class TaskAssignSpecificUser extends Base
'owner_id' => $this->getParam('user_id'),
);
return $this->taskModification->update($values);
return $this->taskModificationModel->update($values);
}
/**

View file

@ -71,7 +71,7 @@ class TaskAssignUser extends Base
'owner_id' => $data['owner_id'],
);
return $this->taskModification->update($values);
return $this->taskModificationModel->update($values);
}
/**
@ -83,6 +83,6 @@ class TaskAssignUser extends Base
*/
public function hasRequiredCondition(array $data)
{
return $this->projectPermission->isAssignable($this->getProjectId(), $data['owner_id']);
return $this->projectPermissionModel->isAssignable($this->getProjectId(), $data['owner_id']);
}
}

View file

@ -63,7 +63,7 @@ class TaskClose extends Base
*/
public function doAction(array $data)
{
return $this->taskStatus->close($data['task_id']);
return $this->taskStatusModel->close($data['task_id']);
}
/**

View file

@ -2,7 +2,7 @@
namespace Kanboard\Action;
use Kanboard\Model\Task;
use Kanboard\Model\TaskModel;
/**
* Close automatically a task in a specific column
@ -32,7 +32,7 @@ class TaskCloseColumn extends Base
public function getCompatibleEvents()
{
return array(
Task::EVENT_MOVE_COLUMN,
TaskModel::EVENT_MOVE_COLUMN,
);
}
@ -67,7 +67,7 @@ class TaskCloseColumn extends Base
*/
public function doAction(array $data)
{
return $this->taskStatus->close($data['task_id']);
return $this->taskStatusModel->close($data['task_id']);
}
/**

View file

@ -2,7 +2,7 @@
namespace Kanboard\Action;
use Kanboard\Model\Task;
use Kanboard\Model\TaskModel;
/**
* Close automatically a task after when inactive
@ -31,7 +31,7 @@ class TaskCloseNoActivity extends Base
*/
public function getCompatibleEvents()
{
return array(Task::EVENT_DAILY_CRONJOB);
return array(TaskModel::EVENT_DAILY_CRONJOB);
}
/**
@ -74,7 +74,7 @@ class TaskCloseNoActivity extends Base
$duration = time() - $task['date_modification'];
if ($duration > $max) {
$results[] = $this->taskStatus->close($task['id']);
$results[] = $this->taskStatusModel->close($task['id']);
}
}

View file

@ -66,7 +66,7 @@ class TaskCreation extends Base
*/
public function doAction(array $data)
{
return (bool) $this->taskCreation->create(array(
return (bool) $this->taskCreationModel->create(array(
'project_id' => $data['project_id'],
'title' => $data['title'],
'reference' => $data['reference'],

View file

@ -2,7 +2,7 @@
namespace Kanboard\Action;
use Kanboard\Model\Task;
use Kanboard\Model\TaskModel;
/**
* Duplicate a task to another project
@ -32,8 +32,9 @@ class TaskDuplicateAnotherProject extends Base
public function getCompatibleEvents()
{
return array(
Task::EVENT_MOVE_COLUMN,
Task::EVENT_CLOSE,
TaskModel::EVENT_MOVE_COLUMN,
TaskModel::EVENT_CLOSE,
TaskModel::EVENT_CREATE,
);
}
@ -74,8 +75,8 @@ class TaskDuplicateAnotherProject extends Base
*/
public function doAction(array $data)
{
$destination_column_id = $this->column->getFirstColumnId($this->getParam('project_id'));
return (bool) $this->taskDuplication->duplicateToProject($data['task_id'], $this->getParam('project_id'), null, $destination_column_id);
$destination_column_id = $this->columnModel->getFirstColumnId($this->getParam('project_id'));
return (bool) $this->taskProjectDuplicationModel->duplicateToProject($data['task_id'], $this->getParam('project_id'), null, $destination_column_id);
}
/**

View file

@ -2,7 +2,7 @@
namespace Kanboard\Action;
use Kanboard\Model\Task;
use Kanboard\Model\TaskModel;
/**
* Email a task to someone
@ -32,8 +32,8 @@ class TaskEmail extends Base
public function getCompatibleEvents()
{
return array(
Task::EVENT_MOVE_COLUMN,
Task::EVENT_CLOSE,
TaskModel::EVENT_MOVE_COLUMN,
TaskModel::EVENT_CLOSE,
);
}
@ -75,16 +75,16 @@ class TaskEmail extends Base
*/
public function doAction(array $data)
{
$user = $this->user->getById($this->getParam('user_id'));
$user = $this->userModel->getById($this->getParam('user_id'));
if (! empty($user['email'])) {
$task = $this->taskFinder->getDetails($data['task_id']);
$task = $this->taskFinderModel->getDetails($data['task_id']);
$this->emailClient->send(
$user['email'],
$user['name'] ?: $user['username'],
$this->getParam('subject'),
$this->template->render('notification/task_create', array('task' => $task, 'application_url' => $this->config->get('application_url')))
$this->template->render('notification/task_create', array('task' => $task, 'application_url' => $this->configModel->get('application_url')))
);
return true;

View file

@ -2,7 +2,7 @@
namespace Kanboard\Action;
use Kanboard\Model\Task;
use Kanboard\Model\TaskModel;
/**
* Email a task with no activity
@ -32,7 +32,7 @@ class TaskEmailNoActivity extends Base
public function getCompatibleEvents()
{
return array(
Task::EVENT_DAILY_CRONJOB,
TaskModel::EVENT_DAILY_CRONJOB,
);
}
@ -85,7 +85,7 @@ class TaskEmailNoActivity extends Base
{
$results = array();
$max = $this->getParam('duration') * 86400;
$user = $this->user->getById($this->getParam('user_id'));
$user = $this->userModel->getById($this->getParam('user_id'));
if (! empty($user['email'])) {
foreach ($data['tasks'] as $task) {
@ -110,13 +110,13 @@ class TaskEmailNoActivity extends Base
*/
private function sendEmail($task_id, array $user)
{
$task = $this->taskFinder->getDetails($task_id);
$task = $this->taskFinderModel->getDetails($task_id);
$this->emailClient->send(
$user['email'],
$user['name'] ?: $user['username'],
$this->getParam('subject'),
$this->template->render('notification/task_create', array('task' => $task, 'application_url' => $this->config->get('application_url')))
$this->template->render('notification/task_create', array('task' => $task, 'application_url' => $this->configModel->get('application_url')))
);
return true;

View file

@ -2,7 +2,7 @@
namespace Kanboard\Action;
use Kanboard\Model\Task;
use Kanboard\Model\TaskModel;
/**
* Move a task to another project
@ -32,8 +32,8 @@ class TaskMoveAnotherProject extends Base
public function getCompatibleEvents()
{
return array(
Task::EVENT_MOVE_COLUMN,
Task::EVENT_CLOSE,
TaskModel::EVENT_MOVE_COLUMN,
TaskModel::EVENT_CLOSE,
);
}
@ -75,7 +75,7 @@ class TaskMoveAnotherProject extends Base
*/
public function doAction(array $data)
{
return $this->taskDuplication->moveToProject($data['task_id'], $this->getParam('project_id'));
return $this->taskProjectMoveModel->moveToProject($data['task_id'], $this->getParam('project_id'));
}
/**

View file

@ -2,7 +2,7 @@
namespace Kanboard\Action;
use Kanboard\Model\Task;
use Kanboard\Model\TaskModel;
/**
* Move a task to another column when an assignee is set
@ -32,8 +32,8 @@ class TaskMoveColumnAssigned extends Base
public function getCompatibleEvents()
{
return array(
Task::EVENT_ASSIGNEE_CHANGE,
Task::EVENT_UPDATE,
TaskModel::EVENT_ASSIGNEE_CHANGE,
TaskModel::EVENT_UPDATE,
);
}
@ -75,9 +75,9 @@ class TaskMoveColumnAssigned extends Base
*/
public function doAction(array $data)
{
$original_task = $this->taskFinder->getById($data['task_id']);
$original_task = $this->taskFinderModel->getById($data['task_id']);
return $this->taskPosition->movePosition(
return $this->taskPositionModel->movePosition(
$data['project_id'],
$data['task_id'],
$this->getParam('dest_column_id'),

View file

@ -2,7 +2,7 @@
namespace Kanboard\Action;
use Kanboard\Model\Task;
use Kanboard\Model\TaskModel;
/**
* Move a task to another column when the category is changed
@ -32,7 +32,7 @@ class TaskMoveColumnCategoryChange extends Base
public function getCompatibleEvents()
{
return array(
Task::EVENT_UPDATE,
TaskModel::EVENT_UPDATE,
);
}
@ -74,9 +74,9 @@ class TaskMoveColumnCategoryChange extends Base
*/
public function doAction(array $data)
{
$original_task = $this->taskFinder->getById($data['task_id']);
$original_task = $this->taskFinderModel->getById($data['task_id']);
return $this->taskPosition->movePosition(
return $this->taskPositionModel->movePosition(
$data['project_id'],
$data['task_id'],
$this->getParam('dest_column_id'),

View file

@ -2,7 +2,7 @@
namespace Kanboard\Action;
use Kanboard\Model\Task;
use Kanboard\Model\TaskModel;
/**
* Move a task to another column when an assignee is cleared
@ -32,8 +32,8 @@ class TaskMoveColumnUnAssigned extends Base
public function getCompatibleEvents()
{
return array(
Task::EVENT_ASSIGNEE_CHANGE,
Task::EVENT_UPDATE,
TaskModel::EVENT_ASSIGNEE_CHANGE,
TaskModel::EVENT_UPDATE,
);
}
@ -75,9 +75,9 @@ class TaskMoveColumnUnAssigned extends Base
*/
public function doAction(array $data)
{
$original_task = $this->taskFinder->getById($data['task_id']);
$original_task = $this->taskFinderModel->getById($data['task_id']);
return $this->taskPosition->movePosition(
return $this->taskPositionModel->movePosition(
$data['project_id'],
$data['task_id'],
$this->getParam('dest_column_id'),

View file

@ -63,7 +63,7 @@ class TaskOpen extends Base
*/
public function doAction(array $data)
{
return $this->taskStatus->open($data['task_id']);
return $this->taskStatusModel->open($data['task_id']);
}
/**

View file

@ -2,7 +2,7 @@
namespace Kanboard\Action;
use Kanboard\Model\Task;
use Kanboard\Model\TaskModel;
/**
* Set the start date of task
@ -32,7 +32,7 @@ class TaskUpdateStartDate extends Base
public function getCompatibleEvents()
{
return array(
Task::EVENT_MOVE_COLUMN,
TaskModel::EVENT_MOVE_COLUMN,
);
}
@ -77,7 +77,7 @@ class TaskUpdateStartDate extends Base
'date_started' => time(),
);
return $this->taskModification->update($values, false);
return $this->taskModificationModel->update($values, false);
}
/**

View file

@ -3,7 +3,7 @@
namespace Kanboard\Analytic;
use Kanboard\Core\Base;
use Kanboard\Model\Task;
use Kanboard\Model\TaskModel;
/**
* Average Lead and Cycle Time
@ -106,7 +106,7 @@ class AverageLeadCycleTimeAnalytic extends Base
private function getTasks($project_id)
{
return $this->db
->table(Task::TABLE)
->table(TaskModel::TABLE)
->columns('date_completed', 'date_creation', 'date_started')
->eq('project_id', $project_id)
->desc('id')

View file

@ -3,7 +3,7 @@
namespace Kanboard\Analytic;
use Kanboard\Core\Base;
use Kanboard\Model\Task;
use Kanboard\Model\TaskModel;
/**
* Average Time Spent by Column
@ -40,7 +40,7 @@ class AverageTimeSpentColumnAnalytic extends Base
private function initialize($project_id)
{
$stats = array();
$columns = $this->column->getList($project_id);
$columns = $this->columnModel->getList($project_id);
foreach ($columns as $column_id => $column_title) {
$stats[$column_id] = array(
@ -110,7 +110,7 @@ class AverageTimeSpentColumnAnalytic extends Base
*/
private function getTaskTimeByColumns(array &$task)
{
$columns = $this->transition->getTimeSpentByTask($task['id']);
$columns = $this->transitionModel->getTimeSpentByTask($task['id']);
if (! isset($columns[$task['column_id']])) {
$columns[$task['column_id']] = 0;
@ -144,7 +144,7 @@ class AverageTimeSpentColumnAnalytic extends Base
private function getTasks($project_id)
{
return $this->db
->table(Task::TABLE)
->table(TaskModel::TABLE)
->columns('id', 'date_completed', 'date_moved', 'column_id')
->eq('project_id', $project_id)
->desc('id')

View file

@ -3,7 +3,7 @@
namespace Kanboard\Analytic;
use Kanboard\Core\Base;
use Kanboard\Model\Task;
use Kanboard\Model\TaskModel;
/**
* Estimated/Spent Time Comparison
@ -22,7 +22,7 @@ class EstimatedTimeComparisonAnalytic extends Base
*/
public function build($project_id)
{
$rows = $this->db->table(Task::TABLE)
$rows = $this->db->table(TaskModel::TABLE)
->columns('SUM(time_estimated) AS time_estimated', 'SUM(time_spent) AS time_spent', 'is_active')
->eq('project_id', $project_id)
->groupBy('is_active')
@ -40,7 +40,7 @@ class EstimatedTimeComparisonAnalytic extends Base
);
foreach ($rows as $row) {
$key = $row['is_active'] == Task::STATUS_OPEN ? 'open' : 'closed';
$key = $row['is_active'] == TaskModel::STATUS_OPEN ? 'open' : 'closed';
$metrics[$key]['time_spent'] = $row['time_spent'];
$metrics[$key]['time_estimated'] = $row['time_estimated'];
}

View file

@ -23,10 +23,10 @@ class TaskDistributionAnalytic extends Base
{
$metrics = array();
$total = 0;
$columns = $this->column->getAll($project_id);
$columns = $this->columnModel->getAll($project_id);
foreach ($columns as $column) {
$nb_tasks = $this->taskFinder->countByColumnId($project_id, $column['id']);
$nb_tasks = $this->taskFinderModel->countByColumnId($project_id, $column['id']);
$total += $nb_tasks;
$metrics[] = array(

View file

@ -23,8 +23,8 @@ class UserDistributionAnalytic extends Base
{
$metrics = array();
$total = 0;
$tasks = $this->taskFinder->getAll($project_id);
$users = $this->projectUserRole->getAssignableUsersList($project_id);
$tasks = $this->taskFinderModel->getAll($project_id);
$users = $this->projectUserRoleModel->getAssignableUsersList($project_id);
foreach ($tasks as $task) {
$user = isset($users[$task['owner_id']]) ? $users[$task['owner_id']] : $users[0];

View file

@ -0,0 +1,19 @@
<?php
namespace Kanboard\Api\Authorization;
/**
* Class ActionAuthorization
*
* @package Kanboard\Api\Authorization
* @author Frederic Guillot
*/
class ActionAuthorization extends ProjectAuthorization
{
public function check($class, $method, $action_id)
{
if ($this->userSession->isLogged()) {
$this->checkProjectPermission($class, $method, $this->actionModel->getProjectId($action_id));
}
}
}

View file

@ -0,0 +1,19 @@
<?php
namespace Kanboard\Api\Authorization;
/**
* Class CategoryAuthorization
*
* @package Kanboard\Api\Authorization
* @author Frederic Guillot
*/
class CategoryAuthorization extends ProjectAuthorization
{
public function check($class, $method, $category_id)
{
if ($this->userSession->isLogged()) {
$this->checkProjectPermission($class, $method, $this->categoryModel->getProjectId($category_id));
}
}
}

View file

@ -0,0 +1,19 @@
<?php
namespace Kanboard\Api\Authorization;
/**
* Class ColumnAuthorization
*
* @package Kanboard\Api\Authorization
* @author Frederic Guillot
*/
class ColumnAuthorization extends ProjectAuthorization
{
public function check($class, $method, $column_id)
{
if ($this->userSession->isLogged()) {
$this->checkProjectPermission($class, $method, $this->columnModel->getProjectId($column_id));
}
}
}

View file

@ -0,0 +1,19 @@
<?php
namespace Kanboard\Api\Authorization;
/**
* Class CommentAuthorization
*
* @package Kanboard\Api\Authorization
* @author Frederic Guillot
*/
class CommentAuthorization extends ProjectAuthorization
{
public function check($class, $method, $comment_id)
{
if ($this->userSession->isLogged()) {
$this->checkProjectPermission($class, $method, $this->commentModel->getProjectId($comment_id));
}
}
}

View file

@ -0,0 +1,32 @@
<?php
namespace Kanboard\Api\Authorization;
use JsonRPC\Exception\AccessDeniedException;
use Kanboard\Core\Base;
/**
* Class ProcedureAuthorization
*
* @package Kanboard\Api\Authorization
* @author Frederic Guillot
*/
class ProcedureAuthorization extends Base
{
private $userSpecificProcedures = array(
'getMe',
'getMyDashboard',
'getMyActivityStream',
'createMyPrivateProject',
'getMyProjectsList',
'getMyProjects',
'getMyOverdueTasks',
);
public function check($procedure)
{
if (! $this->userSession->isLogged() && in_array($procedure, $this->userSpecificProcedures)) {
throw new AccessDeniedException('This procedure is not available with the API credentials');
}
}
}

View file

@ -0,0 +1,35 @@
<?php
namespace Kanboard\Api\Authorization;
use JsonRPC\Exception\AccessDeniedException;
use Kanboard\Core\Base;
/**
* Class ProjectAuthorization
*
* @package Kanboard\Api\Authorization
* @author Frederic Guillot
*/
class ProjectAuthorization extends Base
{
public function check($class, $method, $project_id)
{
if ($this->userSession->isLogged()) {
$this->checkProjectPermission($class, $method, $project_id);
}
}
protected function checkProjectPermission($class, $method, $project_id)
{
if (empty($project_id)) {
throw new AccessDeniedException('Project not found');
}
$role = $this->projectUserRoleModel->getUserRole($project_id, $this->userSession->getId());
if (! $this->apiProjectAuthorization->isAllowed($class, $method, $role)) {
throw new AccessDeniedException('Project access denied');
}
}
}

View file

@ -0,0 +1,19 @@
<?php
namespace Kanboard\Api\Authorization;
/**
* Class SubtaskAuthorization
*
* @package Kanboard\Api\Authorization
* @author Frederic Guillot
*/
class SubtaskAuthorization extends ProjectAuthorization
{
public function check($class, $method, $subtask_id)
{
if ($this->userSession->isLogged()) {
$this->checkProjectPermission($class, $method, $this->subtaskModel->getProjectId($subtask_id));
}
}
}

View file

@ -0,0 +1,19 @@
<?php
namespace Kanboard\Api\Authorization;
/**
* Class TaskAuthorization
*
* @package Kanboard\Api\Authorization
* @author Frederic Guillot
*/
class TaskAuthorization extends ProjectAuthorization
{
public function check($class, $method, $category_id)
{
if ($this->userSession->isLogged()) {
$this->checkProjectPermission($class, $method, $this->taskFinderModel->getProjectId($category_id));
}
}
}

View file

@ -0,0 +1,19 @@
<?php
namespace Kanboard\Api\Authorization;
/**
* Class TaskFileAuthorization
*
* @package Kanboard\Api\Authorization
* @author Frederic Guillot
*/
class TaskFileAuthorization extends ProjectAuthorization
{
public function check($class, $method, $file_id)
{
if ($this->userSession->isLogged()) {
$this->checkProjectPermission($class, $method, $this->taskFileModel->getProjectId($file_id));
}
}
}

View file

@ -0,0 +1,19 @@
<?php
namespace Kanboard\Api\Authorization;
/**
* Class TaskLinkAuthorization
*
* @package Kanboard\Api\Authorization
* @author Frederic Guillot
*/
class TaskLinkAuthorization extends ProjectAuthorization
{
public function check($class, $method, $task_link_id)
{
if ($this->userSession->isLogged()) {
$this->checkProjectPermission($class, $method, $this->taskLinkModel->getProjectId($task_link_id));
}
}
}

View file

@ -0,0 +1,22 @@
<?php
namespace Kanboard\Api\Authorization;
use JsonRPC\Exception\AccessDeniedException;
use Kanboard\Core\Base;
/**
* Class UserAuthorization
*
* @package Kanboard\Api\Authorization
* @author Frederic Guillot
*/
class UserAuthorization extends Base
{
public function check($class, $method)
{
if ($this->userSession->isLogged() && ! $this->apiAuthorization->isAllowed($class, $method, $this->userSession->getRole())) {
throw new AccessDeniedException('You are not allowed to access to this resource');
}
}
}

View file

@ -1,117 +0,0 @@
<?php
namespace Kanboard\Api;
use JsonRPC\AccessDeniedException;
/**
* Base class
*
* @package api
* @author Frederic Guillot
*/
abstract class Base extends \Kanboard\Core\Base
{
private $user_allowed_procedures = array(
'getMe',
'getMyDashboard',
'getMyActivityStream',
'createMyPrivateProject',
'getMyProjectsList',
'getMyProjects',
'getMyOverdueTasks',
);
private $both_allowed_procedures = array(
'getTimezone',
'getVersion',
'getDefaultTaskColor',
'getDefaultTaskColors',
'getColorList',
'getProjectById',
'getTask',
'getTaskByReference',
'getAllTasks',
'openTask',
'closeTask',
'moveTaskPosition',
'createTask',
'updateTask',
'getBoard',
'getProjectActivity',
'getOverdueTasksByProject',
);
public function checkProcedurePermission($is_user, $procedure)
{
$is_both_procedure = in_array($procedure, $this->both_allowed_procedures);
$is_user_procedure = in_array($procedure, $this->user_allowed_procedures);
if ($is_user && ! $is_both_procedure && ! $is_user_procedure) {
throw new AccessDeniedException('Permission denied');
} elseif (! $is_user && ! $is_both_procedure && $is_user_procedure) {
throw new AccessDeniedException('Permission denied');
}
$this->logger->debug('API call: '.$procedure);
}
public function checkProjectPermission($project_id)
{
if ($this->userSession->isLogged() && ! $this->projectPermission->isUserAllowed($project_id, $this->userSession->getId())) {
throw new AccessDeniedException('Permission denied');
}
}
public function checkTaskPermission($task_id)
{
if ($this->userSession->isLogged()) {
$this->checkProjectPermission($this->taskFinder->getProjectId($task_id));
}
}
protected function formatTask($task)
{
if (! empty($task)) {
$task['url'] = $this->helper->url->to('task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), '', true);
$task['color'] = $this->color->getColorProperties($task['color_id']);
}
return $task;
}
protected function formatTasks($tasks)
{
if (! empty($tasks)) {
foreach ($tasks as &$task) {
$task = $this->formatTask($task);
}
}
return $tasks;
}
protected function formatProject($project)
{
if (! empty($project)) {
$project['url'] = array(
'board' => $this->helper->url->to('board', 'show', array('project_id' => $project['id']), '', true),
'calendar' => $this->helper->url->to('calendar', 'show', array('project_id' => $project['id']), '', true),
'list' => $this->helper->url->to('listing', 'show', array('project_id' => $project['id']), '', true),
);
}
return $project;
}
protected function formatProjects($projects)
{
if (! empty($projects)) {
foreach ($projects as &$project) {
$project = $this->formatProject($project);
}
}
return $projects;
}
}

View file

@ -1,18 +0,0 @@
<?php
namespace Kanboard\Api;
/**
* Board API controller
*
* @package api
* @author Frederic Guillot
*/
class Board extends Base
{
public function getBoard($project_id)
{
$this->checkProjectPermission($project_id);
return $this->board->getBoard($project_id);
}
}

View file

@ -1,49 +0,0 @@
<?php
namespace Kanboard\Api;
/**
* Category API controller
*
* @package api
* @author Frederic Guillot
*/
class Category extends \Kanboard\Core\Base
{
public function getCategory($category_id)
{
return $this->category->getById($category_id);
}
public function getAllCategories($project_id)
{
return $this->category->getAll($project_id);
}
public function removeCategory($category_id)
{
return $this->category->remove($category_id);
}
public function createCategory($project_id, $name)
{
$values = array(
'project_id' => $project_id,
'name' => $name,
);
list($valid, ) = $this->categoryValidator->validateCreation($values);
return $valid ? $this->category->create($values) : false;
}
public function updateCategory($id, $name)
{
$values = array(
'id' => $id,
'name' => $name,
);
list($valid, ) = $this->categoryValidator->validateModification($values);
return $valid && $this->category->update($values);
}
}

View file

@ -1,42 +0,0 @@
<?php
namespace Kanboard\Api;
/**
* Column API controller
*
* @package api
* @author Frederic Guillot
*/
class Column extends Base
{
public function getColumns($project_id)
{
return $this->column->getAll($project_id);
}
public function getColumn($column_id)
{
return $this->column->getById($column_id);
}
public function updateColumn($column_id, $title, $task_limit = 0, $description = '')
{
return $this->column->update($column_id, $title, $task_limit, $description);
}
public function addColumn($project_id, $title, $task_limit = 0, $description = '')
{
return $this->column->create($project_id, $title, $task_limit, $description);
}
public function removeColumn($column_id)
{
return $this->column->remove($column_id);
}
public function changeColumnPosition($project_id, $column_id, $position)
{
return $this->column->changePosition($project_id, $column_id, $position);
}
}

View file

@ -1,52 +0,0 @@
<?php
namespace Kanboard\Api;
/**
* Comment API controller
*
* @package api
* @author Frederic Guillot
*/
class Comment extends \Kanboard\Core\Base
{
public function getComment($comment_id)
{
return $this->comment->getById($comment_id);
}
public function getAllComments($task_id)
{
return $this->comment->getAll($task_id);
}
public function removeComment($comment_id)
{
return $this->comment->remove($comment_id);
}
public function createComment($task_id, $user_id, $content, $reference = '')
{
$values = array(
'task_id' => $task_id,
'user_id' => $user_id,
'comment' => $content,
'reference' => $reference,
);
list($valid, ) = $this->commentValidator->validateCreation($values);
return $valid ? $this->comment->create($values) : false;
}
public function updateComment($id, $content)
{
$values = array(
'id' => $id,
'comment' => $content,
);
list($valid, ) = $this->commentValidator->validateModification($values);
return $valid && $this->comment->update($values);
}
}

View file

@ -1,90 +0,0 @@
<?php
namespace Kanboard\Api;
use Kanboard\Core\ObjectStorage\ObjectStorageException;
/**
* File API controller
*
* @package api
* @author Frederic Guillot
*/
class File extends Base
{
public function getTaskFile($file_id)
{
return $this->taskFile->getById($file_id);
}
public function getAllTaskFiles($task_id)
{
return $this->taskFile->getAll($task_id);
}
public function downloadTaskFile($file_id)
{
try {
$file = $this->taskFile->getById($file_id);
if (! empty($file)) {
return base64_encode($this->objectStorage->get($file['path']));
}
} catch (ObjectStorageException $e) {
$this->logger->error($e->getMessage());
return '';
}
}
public function createTaskFile($project_id, $task_id, $filename, $blob)
{
try {
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->removeTaskFile($file_id);
}
public function removeAllFiles($task_id)
{
return $this->removeAllTaskFiles($task_id);
}
}

View file

@ -1,32 +0,0 @@
<?php
namespace Kanboard\Api;
/**
* Group Member API controller
*
* @package api
* @author Frederic Guillot
*/
class GroupMember extends \Kanboard\Core\Base
{
public function getGroupMembers($group_id)
{
return $this->groupMember->getMembers($group_id);
}
public function addGroupMember($group_id, $user_id)
{
return $this->groupMember->addUser($group_id, $user_id);
}
public function removeGroupMember($group_id, $user_id)
{
return $this->groupMember->removeUser($group_id, $user_id);
}
public function isGroupMember($group_id, $user_id)
{
return $this->groupMember->isMember($group_id, $user_id);
}
}

View file

@ -1,72 +0,0 @@
<?php
namespace Kanboard\Api;
use Kanboard\Model\Subtask as SubtaskModel;
/**
* Me API controller
*
* @package api
* @author Frederic Guillot
*/
class Me extends Base
{
public function getMe()
{
return $this->sessionStorage->user;
}
public function getMyDashboard()
{
$user_id = $this->userSession->getId();
$projects = $this->project->getQueryColumnStats($this->projectPermission->getActiveProjectIds($user_id))->findAll();
$tasks = $this->taskFinder->getUserQuery($user_id)->findAll();
return array(
'projects' => $this->formatProjects($projects),
'tasks' => $this->formatTasks($tasks),
'subtasks' => $this->subtask->getUserQuery($user_id, array(SubTaskModel::STATUS_TODO, SubtaskModel::STATUS_INPROGRESS))->findAll(),
);
}
public function getMyActivityStream()
{
$project_ids = $this->projectPermission->getActiveProjectIds($this->userSession->getId());
return $this->projectActivity->getProjects($project_ids, 100);
}
public function createMyPrivateProject($name, $description = null)
{
if ($this->config->get('disable_private_project', 0) == 1) {
return false;
}
$values = array(
'name' => $name,
'description' => $description,
'is_private' => 1,
);
list($valid, ) = $this->projectValidator->validateCreation($values);
return $valid ? $this->project->create($values, $this->userSession->getId(), true) : false;
}
public function getMyProjectsList()
{
return $this->projectUserRole->getProjectsByUser($this->userSession->getId());
}
public function getMyOverdueTasks()
{
return $this->taskFinder->getOverdueTasksByUser($this->userSession->getId());
}
public function getMyProjects()
{
$project_ids = $this->projectPermission->getActiveProjectIds($this->userSession->getId());
$projects = $this->project->getAllByIds($project_ids);
return $this->formatProjects($projects);
}
}

View file

@ -1,38 +1,39 @@
<?php
namespace Kanboard\Api;
namespace Kanboard\Api\Middleware;
use JsonRPC\AuthenticationFailure;
use JsonRPC\Exception\AccessDeniedException;
use JsonRPC\Exception\AuthenticationFailureException;
use JsonRPC\MiddlewareInterface;
use Kanboard\Core\Base;
/**
* Base class
* Class AuthenticationApiMiddleware
*
* @package api
* @author Frederic Guillot
* @package Kanboard\Api\Middleware
* @author Frederic Guillot
*/
class Auth extends Base
class AuthenticationMiddleware extends Base implements MiddlewareInterface
{
/**
* Check api credentials
* Execute Middleware
*
* @access public
* @param string $username
* @param string $password
* @param string $class
* @param string $method
* @param string $username
* @param string $password
* @param string $procedureName
* @throws AccessDeniedException
* @throws AuthenticationFailureException
*/
public function checkCredentials($username, $password, $class, $method)
public function execute($username, $password, $procedureName)
{
$this->dispatcher->dispatch('app.bootstrap');
if ($this->isUserAuthenticated($username, $password)) {
$this->checkProcedurePermission(true, $method);
$this->userSession->initialize($this->user->getByUsername($username));
} elseif ($this->isAppAuthenticated($username, $password)) {
$this->checkProcedurePermission(false, $method);
} else {
$this->userSession->initialize($this->userModel->getByUsername($username));
} elseif (! $this->isAppAuthenticated($username, $password)) {
$this->logger->error('API authentication failure for '.$username);
throw new AuthenticationFailure('Wrong credentials');
throw new AuthenticationFailureException('Wrong credentials');
}
}
@ -47,8 +48,8 @@ class Auth extends Base
private function isUserAuthenticated($username, $password)
{
return $username !== 'jsonrpc' &&
! $this->userLocking->isLocked($username) &&
$this->authenticationManager->passwordAuthentication($username, $password);
! $this->userLockingModel->isLocked($username) &&
$this->authenticationManager->passwordAuthentication($username, $password);
}
/**
@ -76,6 +77,6 @@ class Auth extends Base
return API_AUTHENTICATION_TOKEN;
}
return $this->config->get('api_token');
return $this->configModel->get('api_token');
}
}

View file

@ -1,14 +1,17 @@
<?php
namespace Kanboard\Api;
namespace Kanboard\Api\Procedure;
use Kanboard\Api\Authorization\ActionAuthorization;
use Kanboard\Api\Authorization\ProjectAuthorization;
/**
* Action API controller
*
* @package api
* @package Kanboard\Api\Procedure
* @author Frederic Guillot
*/
class Action extends \Kanboard\Core\Base
class ActionProcedure extends BaseProcedure
{
public function getAvailableActions()
{
@ -27,16 +30,19 @@ class Action extends \Kanboard\Core\Base
public function removeAction($action_id)
{
return $this->action->remove($action_id);
ActionAuthorization::getInstance($this->container)->check($this->getClassName(), 'removeAction', $action_id);
return $this->actionModel->remove($action_id);
}
public function getActions($project_id)
{
return $this->action->getAllByProject($project_id);
ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'getActions', $project_id);
return $this->actionModel->getAllByProject($project_id);
}
public function createAction($project_id, $event_name, $action_name, array $params)
{
ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'createAction', $project_id);
$values = array(
'project_id' => $project_id,
'event_name' => $event_name,
@ -80,6 +86,6 @@ class Action extends \Kanboard\Core\Base
}
}
return $this->action->create($values);
return $this->actionModel->create($values);
}
}

View file

@ -1,18 +1,18 @@
<?php
namespace Kanboard\Api;
namespace Kanboard\Api\Procedure;
/**
* App API controller
*
* @package api
* @package Kanboard\Api\Procedure
* @author Frederic Guillot
*/
class App extends \Kanboard\Core\Base
class AppProcedure extends BaseProcedure
{
public function getTimezone()
{
return $this->config->get('application_timezone');
return $this->timezoneModel->getCurrentTimezone();
}
public function getVersion()
@ -22,17 +22,17 @@ class App extends \Kanboard\Core\Base
public function getDefaultTaskColor()
{
return $this->color->getDefaultColor();
return $this->colorModel->getDefaultColor();
}
public function getDefaultTaskColors()
{
return $this->color->getDefaultColors();
return $this->colorModel->getDefaultColors();
}
public function getColorList()
{
return $this->color->getList();
return $this->colorModel->getList();
}
public function getApplicationRoles()

View file

@ -0,0 +1,85 @@
<?php
namespace Kanboard\Api\Procedure;
use Kanboard\Api\Authorization\ProcedureAuthorization;
use Kanboard\Api\Authorization\UserAuthorization;
use Kanboard\Core\Base;
use ReflectionClass;
/**
* Base class
*
* @package Kanboard\Api\Procedure
* @author Frederic Guillot
*/
abstract class BaseProcedure extends Base
{
public function beforeProcedure($procedure)
{
ProcedureAuthorization::getInstance($this->container)->check($procedure);
UserAuthorization::getInstance($this->container)->check($this->getClassName(), $procedure);
}
protected function formatTask($task)
{
if (! empty($task)) {
$task['url'] = $this->helper->url->to('TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), '', true);
$task['color'] = $this->colorModel->getColorProperties($task['color_id']);
}
return $task;
}
protected function formatTasks($tasks)
{
if (! empty($tasks)) {
foreach ($tasks as &$task) {
$task = $this->formatTask($task);
}
}
return $tasks;
}
protected function formatProject($project)
{
if (! empty($project)) {
$project['url'] = array(
'board' => $this->helper->url->to('BoardViewController', 'show', array('project_id' => $project['id']), '', true),
'calendar' => $this->helper->url->to('CalendarController', 'show', array('project_id' => $project['id']), '', true),
'list' => $this->helper->url->to('TaskListController', 'show', array('project_id' => $project['id']), '', true),
);
}
return $project;
}
protected function formatProjects($projects)
{
if (! empty($projects)) {
foreach ($projects as &$project) {
$project = $this->formatProject($project);
}
}
return $projects;
}
protected function filterValues(array $values)
{
foreach ($values as $key => $value) {
if (is_null($value)) {
unset($values[$key]);
}
}
return $values;
}
protected function getClassName()
{
$reflection = new ReflectionClass(get_called_class());
return $reflection->getShortName();
}
}

View file

@ -0,0 +1,25 @@
<?php
namespace Kanboard\Api\Procedure;
use Kanboard\Api\Authorization\ProjectAuthorization;
use Kanboard\Formatter\BoardFormatter;
/**
* Board API controller
*
* @package Kanboard\Api\Procedure
* @author Frederic Guillot
*/
class BoardProcedure extends BaseProcedure
{
public function getBoard($project_id)
{
ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'getBoard', $project_id);
return BoardFormatter::getInstance($this->container)
->withProjectId($project_id)
->withQuery($this->taskFinderModel->getExtendedQuery())
->format();
}
}

View file

@ -0,0 +1,59 @@
<?php
namespace Kanboard\Api\Procedure;
use Kanboard\Api\Authorization\CategoryAuthorization;
use Kanboard\Api\Authorization\ProjectAuthorization;
/**
* Category API controller
*
* @package Kanboard\Api\Procedure
* @author Frederic Guillot
*/
class CategoryProcedure extends BaseProcedure
{
public function getCategory($category_id)
{
CategoryAuthorization::getInstance($this->container)->check($this->getClassName(), 'getCategory', $category_id);
return $this->categoryModel->getById($category_id);
}
public function getAllCategories($project_id)
{
ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'getAllCategories', $project_id);
return $this->categoryModel->getAll($project_id);
}
public function removeCategory($category_id)
{
CategoryAuthorization::getInstance($this->container)->check($this->getClassName(), 'removeCategory', $category_id);
return $this->categoryModel->remove($category_id);
}
public function createCategory($project_id, $name)
{
ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'createCategory', $project_id);
$values = array(
'project_id' => $project_id,
'name' => $name,
);
list($valid, ) = $this->categoryValidator->validateCreation($values);
return $valid ? $this->categoryModel->create($values) : false;
}
public function updateCategory($id, $name)
{
CategoryAuthorization::getInstance($this->container)->check($this->getClassName(), 'updateCategory', $id);
$values = array(
'id' => $id,
'name' => $name,
);
list($valid, ) = $this->categoryValidator->validateModification($values);
return $valid && $this->categoryModel->update($values);
}
}

View file

@ -0,0 +1,51 @@
<?php
namespace Kanboard\Api\Procedure;
use Kanboard\Api\Authorization\ColumnAuthorization;
use Kanboard\Api\Authorization\ProjectAuthorization;
/**
* Column API controller
*
* @package Kanboard\Api\Procedure
* @author Frederic Guillot
*/
class ColumnProcedure extends BaseProcedure
{
public function getColumns($project_id)
{
ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'getColumns', $project_id);
return $this->columnModel->getAll($project_id);
}
public function getColumn($column_id)
{
ColumnAuthorization::getInstance($this->container)->check($this->getClassName(), 'getColumn', $column_id);
return $this->columnModel->getById($column_id);
}
public function updateColumn($column_id, $title, $task_limit = 0, $description = '')
{
ColumnAuthorization::getInstance($this->container)->check($this->getClassName(), 'updateColumn', $column_id);
return $this->columnModel->update($column_id, $title, $task_limit, $description);
}
public function addColumn($project_id, $title, $task_limit = 0, $description = '')
{
ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'addColumn', $project_id);
return $this->columnModel->create($project_id, $title, $task_limit, $description);
}
public function removeColumn($column_id)
{
ColumnAuthorization::getInstance($this->container)->check($this->getClassName(), 'removeColumn', $column_id);
return $this->columnModel->remove($column_id);
}
public function changeColumnPosition($project_id, $column_id, $position)
{
ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'changeColumnPosition', $project_id);
return $this->columnModel->changePosition($project_id, $column_id, $position);
}
}

View file

@ -0,0 +1,62 @@
<?php
namespace Kanboard\Api\Procedure;
use Kanboard\Api\Authorization\CommentAuthorization;
use Kanboard\Api\Authorization\TaskAuthorization;
/**
* Comment API controller
*
* @package Kanboard\Api\Procedure
* @author Frederic Guillot
*/
class CommentProcedure extends BaseProcedure
{
public function getComment($comment_id)
{
CommentAuthorization::getInstance($this->container)->check($this->getClassName(), 'getComment', $comment_id);
return $this->commentModel->getById($comment_id);
}
public function getAllComments($task_id)
{
TaskAuthorization::getInstance($this->container)->check($this->getClassName(), 'getAllComments', $task_id);
return $this->commentModel->getAll($task_id);
}
public function removeComment($comment_id)
{
CommentAuthorization::getInstance($this->container)->check($this->getClassName(), 'removeComment', $comment_id);
return $this->commentModel->remove($comment_id);
}
public function createComment($task_id, $user_id, $content, $reference = '')
{
TaskAuthorization::getInstance($this->container)->check($this->getClassName(), 'createComment', $task_id);
$values = array(
'task_id' => $task_id,
'user_id' => $user_id,
'comment' => $content,
'reference' => $reference,
);
list($valid, ) = $this->commentValidator->validateCreation($values);
return $valid ? $this->commentModel->create($values) : false;
}
public function updateComment($id, $content)
{
CommentAuthorization::getInstance($this->container)->check($this->getClassName(), 'updateComment', $id);
$values = array(
'id' => $id,
'comment' => $content,
);
list($valid, ) = $this->commentValidator->validateModification($values);
return $valid && $this->commentModel->update($values);
}
}

View file

@ -0,0 +1,37 @@
<?php
namespace Kanboard\Api\Procedure;
/**
* Group Member API controller
*
* @package Kanboard\Api\Procedure
* @author Frederic Guillot
*/
class GroupMemberProcedure extends BaseProcedure
{
public function getMemberGroups($user_id)
{
return $this->groupMemberModel->getGroups($user_id);
}
public function getGroupMembers($group_id)
{
return $this->groupMemberModel->getMembers($group_id);
}
public function addGroupMember($group_id, $user_id)
{
return $this->groupMemberModel->addUser($group_id, $user_id);
}
public function removeGroupMember($group_id, $user_id)
{
return $this->groupMemberModel->removeUser($group_id, $user_id);
}
public function isGroupMember($group_id, $user_id)
{
return $this->groupMemberModel->isMember($group_id, $user_id);
}
}

View file

@ -1,18 +1,18 @@
<?php
namespace Kanboard\Api;
namespace Kanboard\Api\Procedure;
/**
* Group API controller
*
* @package api
* @package Kanboard\Api\Procedure
* @author Frederic Guillot
*/
class Group extends \Kanboard\Core\Base
class GroupProcedure extends BaseProcedure
{
public function createGroup($name, $external_id = '')
{
return $this->group->create($name, $external_id);
return $this->groupModel->create($name, $external_id);
}
public function updateGroup($group_id, $name = null, $external_id = null)
@ -29,21 +29,21 @@ class Group extends \Kanboard\Core\Base
}
}
return $this->group->update($values);
return $this->groupModel->update($values);
}
public function removeGroup($group_id)
{
return $this->group->remove($group_id);
return $this->groupModel->remove($group_id);
}
public function getGroup($group_id)
{
return $this->group->getById($group_id);
return $this->groupModel->getById($group_id);
}
public function getAllGroups()
{
return $this->group->getAll();
return $this->groupModel->getAll();
}
}

View file

@ -1,14 +1,14 @@
<?php
namespace Kanboard\Api;
namespace Kanboard\Api\Procedure;
/**
* Link API controller
*
* @package api
* @package Kanboard\Api\Procedure
* @author Frederic Guillot
*/
class Link extends \Kanboard\Core\Base
class LinkProcedure extends BaseProcedure
{
/**
* Get a link by id
@ -19,7 +19,7 @@ class Link extends \Kanboard\Core\Base
*/
public function getLinkById($link_id)
{
return $this->link->getById($link_id);
return $this->linkModel->getById($link_id);
}
/**
@ -31,7 +31,7 @@ class Link extends \Kanboard\Core\Base
*/
public function getLinkByLabel($label)
{
return $this->link->getByLabel($label);
return $this->linkModel->getByLabel($label);
}
/**
@ -43,7 +43,7 @@ class Link extends \Kanboard\Core\Base
*/
public function getOppositeLinkId($link_id)
{
return $this->link->getOppositeLinkId($link_id);
return $this->linkModel->getOppositeLinkId($link_id);
}
/**
@ -54,7 +54,7 @@ class Link extends \Kanboard\Core\Base
*/
public function getAllLinks()
{
return $this->link->getAll();
return $this->linkModel->getAll();
}
/**
@ -73,7 +73,7 @@ class Link extends \Kanboard\Core\Base
);
list($valid, ) = $this->linkValidator->validateCreation($values);
return $valid ? $this->link->create($label, $opposite_label) : false;
return $valid ? $this->linkModel->create($label, $opposite_label) : false;
}
/**
@ -94,7 +94,7 @@ class Link extends \Kanboard\Core\Base
);
list($valid, ) = $this->linkValidator->validateModification($values);
return $valid && $this->link->update($values);
return $valid && $this->linkModel->update($values);
}
/**
@ -106,6 +106,6 @@ class Link extends \Kanboard\Core\Base
*/
public function removeLink($link_id)
{
return $this->link->remove($link_id);
return $this->linkModel->remove($link_id);
}
}

View file

@ -0,0 +1,72 @@
<?php
namespace Kanboard\Api\Procedure;
use Kanboard\Model\SubtaskModel;
/**
* Me API controller
*
* @package Kanboard\Api\Procedure
* @author Frederic Guillot
*/
class MeProcedure extends BaseProcedure
{
public function getMe()
{
return $this->sessionStorage->user;
}
public function getMyDashboard()
{
$user_id = $this->userSession->getId();
$projects = $this->projectModel->getQueryColumnStats($this->projectPermissionModel->getActiveProjectIds($user_id))->findAll();
$tasks = $this->taskFinderModel->getUserQuery($user_id)->findAll();
return array(
'projects' => $this->formatProjects($projects),
'tasks' => $this->formatTasks($tasks),
'subtasks' => $this->subtaskModel->getUserQuery($user_id, array(SubtaskModel::STATUS_TODO, SubtaskModel::STATUS_INPROGRESS))->findAll(),
);
}
public function getMyActivityStream()
{
$project_ids = $this->projectPermissionModel->getActiveProjectIds($this->userSession->getId());
return $this->helper->projectActivity->getProjectsEvents($project_ids, 100);
}
public function createMyPrivateProject($name, $description = null)
{
if ($this->configModel->get('disable_private_project', 0) == 1) {
return false;
}
$values = array(
'name' => $name,
'description' => $description,
'is_private' => 1,
);
list($valid, ) = $this->projectValidator->validateCreation($values);
return $valid ? $this->projectModel->create($values, $this->userSession->getId(), true) : false;
}
public function getMyProjectsList()
{
return $this->projectUserRoleModel->getProjectsByUser($this->userSession->getId());
}
public function getMyOverdueTasks()
{
return $this->taskFinderModel->getOverdueTasksByUser($this->userSession->getId());
}
public function getMyProjects()
{
$project_ids = $this->projectPermissionModel->getActiveProjectIds($this->userSession->getId());
$projects = $this->projectModel->getAllByIds($project_ids);
return $this->formatProjects($projects);
}
}

View file

@ -0,0 +1,68 @@
<?php
namespace Kanboard\Api\Procedure;
use Kanboard\Api\Authorization\ProjectAuthorization;
use Kanboard\Core\ObjectStorage\ObjectStorageException;
/**
* Project File API controller
*
* @package Kanboard\Api\Procedure
* @author Frederic Guillot
*/
class ProjectFileProcedure extends BaseProcedure
{
public function getProjectFile($project_id, $file_id)
{
ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'getProjectFile', $project_id);
return $this->projectFileModel->getById($file_id);
}
public function getAllProjectFiles($project_id)
{
ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'getAllProjectFiles', $project_id);
return $this->projectFileModel->getAll($project_id);
}
public function downloadProjectFile($project_id, $file_id)
{
ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'downloadProjectFile', $project_id);
try {
$file = $this->projectFileModel->getById($file_id);
if (! empty($file)) {
return base64_encode($this->objectStorage->get($file['path']));
}
} catch (ObjectStorageException $e) {
$this->logger->error($e->getMessage());
}
return '';
}
public function createProjectFile($project_id, $filename, $blob)
{
ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'createProjectFile', $project_id);
try {
return $this->projectFileModel->uploadContent($project_id, $filename, $blob);
} catch (ObjectStorageException $e) {
$this->logger->error(__METHOD__.': '.$e->getMessage());
return false;
}
}
public function removeProjectFile($project_id, $file_id)
{
ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'removeProjectFile', $project_id);
return $this->projectFileModel->remove($file_id);
}
public function removeAllProjectFiles($project_id)
{
ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'removeAllProjectFiles', $project_id);
return $this->projectFileModel->removeAll($project_id);
}
}

View file

@ -0,0 +1,69 @@
<?php
namespace Kanboard\Api\Procedure;
use Kanboard\Api\Authorization\ProjectAuthorization;
use Kanboard\Core\Security\Role;
/**
* Project Permission API controller
*
* @package Kanboard\Api\Procedure
* @author Frederic Guillot
*/
class ProjectPermissionProcedure extends BaseProcedure
{
public function getProjectUsers($project_id)
{
ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'getProjectUsers', $project_id);
return $this->projectUserRoleModel->getAllUsers($project_id);
}
public function getAssignableUsers($project_id, $prepend_unassigned = false)
{
ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'getAssignableUsers', $project_id);
return $this->projectUserRoleModel->getAssignableUsersList($project_id, $prepend_unassigned);
}
public function addProjectUser($project_id, $user_id, $role = Role::PROJECT_MEMBER)
{
ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'addProjectUser', $project_id);
return $this->projectUserRoleModel->addUser($project_id, $user_id, $role);
}
public function addProjectGroup($project_id, $group_id, $role = Role::PROJECT_MEMBER)
{
ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'addProjectGroup', $project_id);
return $this->projectGroupRoleModel->addGroup($project_id, $group_id, $role);
}
public function removeProjectUser($project_id, $user_id)
{
ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'removeProjectUser', $project_id);
return $this->projectUserRoleModel->removeUser($project_id, $user_id);
}
public function removeProjectGroup($project_id, $group_id)
{
ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'removeProjectGroup', $project_id);
return $this->projectGroupRoleModel->removeGroup($project_id, $group_id);
}
public function changeProjectUserRole($project_id, $user_id, $role)
{
ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'changeProjectUserRole', $project_id);
return $this->projectUserRoleModel->changeUserRole($project_id, $user_id, $role);
}
public function changeProjectGroupRole($project_id, $group_id, $role)
{
ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'changeProjectGroupRole', $project_id);
return $this->projectGroupRoleModel->changeGroupRole($project_id, $group_id, $role);
}
public function getProjectUserRole($project_id, $user_id)
{
ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'getProjectUserRole', $project_id);
return $this->projectUserRoleModel->getUserRole($project_id, $user_id);
}
}

View file

@ -0,0 +1,113 @@
<?php
namespace Kanboard\Api\Procedure;
use Kanboard\Api\Authorization\ProjectAuthorization;
/**
* Project API controller
*
* @package Kanboard\Api\Procedure
* @author Frederic Guillot
*/
class ProjectProcedure extends BaseProcedure
{
public function getProjectById($project_id)
{
ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'getProjectById', $project_id);
return $this->formatProject($this->projectModel->getById($project_id));
}
public function getProjectByName($name)
{
$project = $this->projectModel->getByName($name);
ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'getProjectByName', $project['id']);
return $this->formatProject($project);
}
public function getProjectByIdentifier($identifier)
{
$project = $this->formatProject($this->projectModel->getByIdentifier($identifier));
ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'getProjectByIdentifier', $project['id']);
return $this->formatProject($project);
}
public function getAllProjects()
{
return $this->formatProjects($this->projectModel->getAll());
}
public function removeProject($project_id)
{
ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'removeProject', $project_id);
return $this->projectModel->remove($project_id);
}
public function enableProject($project_id)
{
ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'enableProject', $project_id);
return $this->projectModel->enable($project_id);
}
public function disableProject($project_id)
{
ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'disableProject', $project_id);
return $this->projectModel->disable($project_id);
}
public function enableProjectPublicAccess($project_id)
{
ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'enableProjectPublicAccess', $project_id);
return $this->projectModel->enablePublicAccess($project_id);
}
public function disableProjectPublicAccess($project_id)
{
ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'disableProjectPublicAccess', $project_id);
return $this->projectModel->disablePublicAccess($project_id);
}
public function getProjectActivities(array $project_ids)
{
foreach ($project_ids as $project_id) {
ProjectAuthorization::getInstance($this->container)
->check($this->getClassName(), 'getProjectActivities', $project_id);
}
return $this->helper->projectActivity->getProjectsEvents($project_ids);
}
public function getProjectActivity($project_id)
{
ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'getProjectActivity', $project_id);
return $this->helper->projectActivity->getProjectEvents($project_id);
}
public function createProject($name, $description = null, $owner_id = 0, $identifier = null)
{
$values = $this->filterValues(array(
'name' => $name,
'description' => $description,
'identifier' => $identifier,
));
list($valid, ) = $this->projectValidator->validateCreation($values);
return $valid ? $this->projectModel->create($values, $owner_id, $this->userSession->isLogged()) : false;
}
public function updateProject($project_id, $name = null, $description = null, $owner_id = null, $identifier = null)
{
ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'updateProject', $project_id);
$values = $this->filterValues(array(
'id' => $project_id,
'name' => $name,
'description' => $description,
'owner_id' => $owner_id,
'identifier' => $identifier,
));
list($valid, ) = $this->projectValidator->validateModification($values);
return $valid && $this->projectModel->update($values);
}
}

View file

@ -1,32 +1,40 @@
<?php
namespace Kanboard\Api;
namespace Kanboard\Api\Procedure;
use Kanboard\Api\Authorization\SubtaskAuthorization;
use Kanboard\Api\Authorization\TaskAuthorization;
/**
* Subtask API controller
*
* @package api
* @package Kanboard\Api\Procedure
* @author Frederic Guillot
*/
class Subtask extends \Kanboard\Core\Base
class SubtaskProcedure extends BaseProcedure
{
public function getSubtask($subtask_id)
{
return $this->subtask->getById($subtask_id);
SubtaskAuthorization::getInstance($this->container)->check($this->getClassName(), 'getSubtask', $subtask_id);
return $this->subtaskModel->getById($subtask_id);
}
public function getAllSubtasks($task_id)
{
return $this->subtask->getAll($task_id);
TaskAuthorization::getInstance($this->container)->check($this->getClassName(), 'getAllSubtasks', $task_id);
return $this->subtaskModel->getAll($task_id);
}
public function removeSubtask($subtask_id)
{
return $this->subtask->remove($subtask_id);
SubtaskAuthorization::getInstance($this->container)->check($this->getClassName(), 'removeSubtask', $subtask_id);
return $this->subtaskModel->remove($subtask_id);
}
public function createSubtask($task_id, $title, $user_id = 0, $time_estimated = 0, $time_spent = 0, $status = 0)
{
TaskAuthorization::getInstance($this->container)->check($this->getClassName(), 'createSubtask', $task_id);
$values = array(
'title' => $title,
'task_id' => $task_id,
@ -37,11 +45,13 @@ class Subtask extends \Kanboard\Core\Base
);
list($valid, ) = $this->subtaskValidator->validateCreation($values);
return $valid ? $this->subtask->create($values) : false;
return $valid ? $this->subtaskModel->create($values) : false;
}
public function updateSubtask($id, $task_id, $title = null, $user_id = null, $time_estimated = null, $time_spent = null, $status = null)
{
TaskAuthorization::getInstance($this->container)->check($this->getClassName(), 'updateSubtask', $task_id);
$values = array(
'id' => $id,
'task_id' => $task_id,
@ -59,6 +69,6 @@ class Subtask extends \Kanboard\Core\Base
}
list($valid, ) = $this->subtaskValidator->validateApiModification($values);
return $valid && $this->subtask->update($values);
return $valid && $this->subtaskModel->update($values);
}
}

View file

@ -0,0 +1,39 @@
<?php
namespace Kanboard\Api\Procedure;
use Kanboard\Api\Authorization\SubtaskAuthorization;
/**
* Subtask Time Tracking API controller
*
* @package Kanboard\Api\Procedure
* @author Frederic Guillot
* @author Nikolaos Georgakis
*/
class SubtaskTimeTrackingProcedure extends BaseProcedure
{
public function hasSubtaskTimer($subtask_id, $user_id)
{
SubtaskAuthorization::getInstance($this->container)->check($this->getClassName(), 'hasSubtaskTimer', $subtask_id);
return $this->subtaskTimeTrackingModel->hasTimer($subtask_id, $user_id);
}
public function setSubtaskStartTime($subtask_id, $user_id)
{
SubtaskAuthorization::getInstance($this->container)->check($this->getClassName(), 'setSubtaskStartTime', $subtask_id);
return $this->subtaskTimeTrackingModel->logStartTime($subtask_id, $user_id);
}
public function setSubtaskEndTime($subtask_id, $user_id)
{
SubtaskAuthorization::getInstance($this->container)->check($this->getClassName(), 'setSubtaskEndTime', $subtask_id);
return $this->subtaskTimeTrackingModel->logEndTime($subtask_id, $user_id);
}
public function getSubtaskTimeSpent($subtask_id, $user_id)
{
SubtaskAuthorization::getInstance($this->container)->check($this->getClassName(), 'getSubtaskTimeSpent', $subtask_id);
return $this->subtaskTimeTrackingModel->getTimeSpent($subtask_id, $user_id);
}
}

View file

@ -0,0 +1,91 @@
<?php
namespace Kanboard\Api\Procedure;
use Kanboard\Api\Authorization\ProjectAuthorization;
/**
* Swimlane API controller
*
* @package Kanboard\Api\Procedure
* @author Frederic Guillot
*/
class SwimlaneProcedure extends BaseProcedure
{
public function getActiveSwimlanes($project_id)
{
ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'getActiveSwimlanes', $project_id);
return $this->swimlaneModel->getSwimlanes($project_id);
}
public function getAllSwimlanes($project_id)
{
ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'getAllSwimlanes', $project_id);
return $this->swimlaneModel->getAll($project_id);
}
public function getSwimlaneById($swimlane_id)
{
$swimlane = $this->swimlaneModel->getById($swimlane_id);
ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'getSwimlaneById', $swimlane['project_id']);
return $swimlane;
}
public function getSwimlaneByName($project_id, $name)
{
ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'getSwimlaneByName', $project_id);
return $this->swimlaneModel->getByName($project_id, $name);
}
public function getSwimlane($swimlane_id)
{
return $this->swimlaneModel->getById($swimlane_id);
}
public function getDefaultSwimlane($project_id)
{
ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'getDefaultSwimlane', $project_id);
return $this->swimlaneModel->getDefault($project_id);
}
public function addSwimlane($project_id, $name, $description = '')
{
ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'addSwimlane', $project_id);
return $this->swimlaneModel->create(array('project_id' => $project_id, 'name' => $name, 'description' => $description));
}
public function updateSwimlane($swimlane_id, $name, $description = null)
{
$values = array('id' => $swimlane_id, 'name' => $name);
if (!is_null($description)) {
$values['description'] = $description;
}
return $this->swimlaneModel->update($values);
}
public function removeSwimlane($project_id, $swimlane_id)
{
ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'removeSwimlane', $project_id);
return $this->swimlaneModel->remove($project_id, $swimlane_id);
}
public function disableSwimlane($project_id, $swimlane_id)
{
ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'disableSwimlane', $project_id);
return $this->swimlaneModel->disable($project_id, $swimlane_id);
}
public function enableSwimlane($project_id, $swimlane_id)
{
ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'enableSwimlane', $project_id);
return $this->swimlaneModel->enable($project_id, $swimlane_id);
}
public function changeSwimlanePosition($project_id, $swimlane_id, $position)
{
ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'changeSwimlanePosition', $project_id);
return $this->swimlaneModel->changePosition($project_id, $swimlane_id, $position);
}
}

View file

@ -0,0 +1,106 @@
<?php
namespace Kanboard\Api\Procedure;
use Kanboard\Api\Authorization\TaskAuthorization;
use Kanboard\Core\ExternalLink\ExternalLinkManager;
use Kanboard\Core\ExternalLink\ExternalLinkProviderNotFound;
/**
* Task External Link API controller
*
* @package Kanboard\Api\Procedure
* @author Frederic Guillot
*/
class TaskExternalLinkProcedure extends BaseProcedure
{
public function getExternalTaskLinkTypes()
{
return $this->externalLinkManager->getTypes();
}
public function getExternalTaskLinkProviderDependencies($providerName)
{
try {
return $this->externalLinkManager->getProvider($providerName)->getDependencies();
} catch (ExternalLinkProviderNotFound $e) {
$this->logger->error(__METHOD__.': '.$e->getMessage());
return false;
}
}
public function getExternalTaskLinkById($task_id, $link_id)
{
TaskAuthorization::getInstance($this->container)->check($this->getClassName(), 'getExternalTaskLink', $task_id);
return $this->taskExternalLinkModel->getById($link_id);
}
public function getAllExternalTaskLinks($task_id)
{
TaskAuthorization::getInstance($this->container)->check($this->getClassName(), 'getExternalTaskLinks', $task_id);
return $this->taskExternalLinkModel->getAll($task_id);
}
public function createExternalTaskLink($task_id, $url, $dependency, $type = ExternalLinkManager::TYPE_AUTO, $title = '')
{
TaskAuthorization::getInstance($this->container)->check($this->getClassName(), 'createExternalTaskLink', $task_id);
try {
$provider = $this->externalLinkManager
->setUserInputText($url)
->setUserInputType($type)
->find();
$link = $provider->getLink();
$values = array(
'task_id' => $task_id,
'title' => $title ?: $link->getTitle(),
'url' => $link->getUrl(),
'link_type' => $provider->getType(),
'dependency' => $dependency,
);
list($valid, $errors) = $this->externalLinkValidator->validateCreation($values);
if (! $valid) {
$this->logger->error(__METHOD__.': '.var_export($errors));
return false;
}
return $this->taskExternalLinkModel->create($values);
} catch (ExternalLinkProviderNotFound $e) {
$this->logger->error(__METHOD__.': '.$e->getMessage());
}
return false;
}
public function updateExternalTaskLink($task_id, $link_id, $title = null, $url = null, $dependency = null)
{
TaskAuthorization::getInstance($this->container)->check($this->getClassName(), 'updateExternalTaskLink', $task_id);
$link = $this->taskExternalLinkModel->getById($link_id);
$values = $this->filterValues(array(
'title' => $title,
'url' => $url,
'dependency' => $dependency,
));
$values = array_merge($link, $values);
list($valid, $errors) = $this->externalLinkValidator->validateModification($values);
if (! $valid) {
$this->logger->error(__METHOD__.': '.var_export($errors));
return false;
}
return $this->taskExternalLinkModel->update($values);
}
public function removeExternalTaskLink($task_id, $link_id)
{
TaskAuthorization::getInstance($this->container)->check($this->getClassName(), 'removeExternalTaskLink', $task_id);
return $this->taskExternalLinkModel->remove($link_id);
}
}

View file

@ -0,0 +1,70 @@
<?php
namespace Kanboard\Api\Procedure;
use Kanboard\Api\Authorization\ProjectAuthorization;
use Kanboard\Api\Authorization\TaskAuthorization;
use Kanboard\Api\Authorization\TaskFileAuthorization;
use Kanboard\Core\ObjectStorage\ObjectStorageException;
/**
* Task File API controller
*
* @package Kanboard\Api\Procedure
* @author Frederic Guillot
*/
class TaskFileProcedure extends BaseProcedure
{
public function getTaskFile($file_id)
{
TaskFileAuthorization::getInstance($this->container)->check($this->getClassName(), 'getTaskFile', $file_id);
return $this->taskFileModel->getById($file_id);
}
public function getAllTaskFiles($task_id)
{
TaskAuthorization::getInstance($this->container)->check($this->getClassName(), 'getAllTaskFiles', $task_id);
return $this->taskFileModel->getAll($task_id);
}
public function downloadTaskFile($file_id)
{
TaskFileAuthorization::getInstance($this->container)->check($this->getClassName(), 'downloadTaskFile', $file_id);
try {
$file = $this->taskFileModel->getById($file_id);
if (! empty($file)) {
return base64_encode($this->objectStorage->get($file['path']));
}
} catch (ObjectStorageException $e) {
$this->logger->error($e->getMessage());
}
return '';
}
public function createTaskFile($project_id, $task_id, $filename, $blob)
{
ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'createTaskFile', $project_id);
try {
return $this->taskFileModel->uploadContent($task_id, $filename, $blob);
} catch (ObjectStorageException $e) {
$this->logger->error(__METHOD__.': '.$e->getMessage());
return false;
}
}
public function removeTaskFile($file_id)
{
TaskFileAuthorization::getInstance($this->container)->check($this->getClassName(), 'removeTaskFile', $file_id);
return $this->taskFileModel->remove($file_id);
}
public function removeAllTaskFiles($task_id)
{
TaskAuthorization::getInstance($this->container)->check($this->getClassName(), 'removeAllTaskFiles', $task_id);
return $this->taskFileModel->removeAll($task_id);
}
}

View file

@ -1,14 +1,17 @@
<?php
namespace Kanboard\Api;
namespace Kanboard\Api\Procedure;
use Kanboard\Api\Authorization\TaskAuthorization;
use Kanboard\Api\Authorization\TaskLinkAuthorization;
/**
* TaskLink API controller
*
* @package api
* @package Kanboard\Api\Procedure
* @author Frederic Guillot
*/
class TaskLink extends \Kanboard\Core\Base
class TaskLinkProcedure extends BaseProcedure
{
/**
* Get a task link
@ -19,7 +22,8 @@ class TaskLink extends \Kanboard\Core\Base
*/
public function getTaskLinkById($task_link_id)
{
return $this->taskLink->getById($task_link_id);
TaskLinkAuthorization::getInstance($this->container)->check($this->getClassName(), 'getTaskLinkById', $task_link_id);
return $this->taskLinkModel->getById($task_link_id);
}
/**
@ -31,7 +35,8 @@ class TaskLink extends \Kanboard\Core\Base
*/
public function getAllTaskLinks($task_id)
{
return $this->taskLink->getAll($task_id);
TaskAuthorization::getInstance($this->container)->check($this->getClassName(), 'getAllTaskLinks', $task_id);
return $this->taskLinkModel->getAll($task_id);
}
/**
@ -45,7 +50,8 @@ class TaskLink extends \Kanboard\Core\Base
*/
public function createTaskLink($task_id, $opposite_task_id, $link_id)
{
return $this->taskLink->create($task_id, $opposite_task_id, $link_id);
TaskAuthorization::getInstance($this->container)->check($this->getClassName(), 'createTaskLink', $task_id);
return $this->taskLinkModel->create($task_id, $opposite_task_id, $link_id);
}
/**
@ -60,7 +66,8 @@ class TaskLink extends \Kanboard\Core\Base
*/
public function updateTaskLink($task_link_id, $task_id, $opposite_task_id, $link_id)
{
return $this->taskLink->update($task_link_id, $task_id, $opposite_task_id, $link_id);
TaskAuthorization::getInstance($this->container)->check($this->getClassName(), 'updateTaskLink', $task_id);
return $this->taskLinkModel->update($task_link_id, $task_id, $opposite_task_id, $link_id);
}
/**
@ -72,6 +79,7 @@ class TaskLink extends \Kanboard\Core\Base
*/
public function removeTaskLink($task_link_id)
{
return $this->taskLink->remove($task_link_id);
TaskLinkAuthorization::getInstance($this->container)->check($this->getClassName(), 'removeTaskLink', $task_link_id);
return $this->taskLinkModel->remove($task_link_id);
}
}

View file

@ -1,87 +1,99 @@
<?php
namespace Kanboard\Api;
namespace Kanboard\Api\Procedure;
use Kanboard\Model\Task as TaskModel;
use Kanboard\Api\Authorization\ProjectAuthorization;
use Kanboard\Api\Authorization\TaskAuthorization;
use Kanboard\Filter\TaskProjectFilter;
use Kanboard\Model\TaskModel;
/**
* Task API controller
*
* @package api
* @package Kanboard\Api\Procedure
* @author Frederic Guillot
*/
class Task extends Base
class TaskProcedure extends BaseProcedure
{
public function searchTasks($project_id, $query)
{
ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'searchTasks', $project_id);
return $this->taskLexer->build($query)->withFilter(new TaskProjectFilter($project_id))->toArray();
}
public function getTask($task_id)
{
$this->checkTaskPermission($task_id);
return $this->formatTask($this->taskFinder->getById($task_id));
TaskAuthorization::getInstance($this->container)->check($this->getClassName(), 'getTask', $task_id);
return $this->formatTask($this->taskFinderModel->getById($task_id));
}
public function getTaskByReference($project_id, $reference)
{
$this->checkProjectPermission($project_id);
return $this->formatTask($this->taskFinder->getByReference($project_id, $reference));
ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'getTaskByReference', $project_id);
return $this->formatTask($this->taskFinderModel->getByReference($project_id, $reference));
}
public function getAllTasks($project_id, $status_id = TaskModel::STATUS_OPEN)
{
$this->checkProjectPermission($project_id);
return $this->formatTasks($this->taskFinder->getAll($project_id, $status_id));
ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'getAllTasks', $project_id);
return $this->formatTasks($this->taskFinderModel->getAll($project_id, $status_id));
}
public function getOverdueTasks()
{
return $this->taskFinder->getOverdueTasks();
return $this->taskFinderModel->getOverdueTasks();
}
public function getOverdueTasksByProject($project_id)
{
$this->checkProjectPermission($project_id);
return $this->taskFinder->getOverdueTasksByProject($project_id);
ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'getOverdueTasksByProject', $project_id);
return $this->taskFinderModel->getOverdueTasksByProject($project_id);
}
public function openTask($task_id)
{
$this->checkTaskPermission($task_id);
return $this->taskStatus->open($task_id);
TaskAuthorization::getInstance($this->container)->check($this->getClassName(), 'openTask', $task_id);
return $this->taskStatusModel->open($task_id);
}
public function closeTask($task_id)
{
$this->checkTaskPermission($task_id);
return $this->taskStatus->close($task_id);
TaskAuthorization::getInstance($this->container)->check($this->getClassName(), 'closeTask', $task_id);
return $this->taskStatusModel->close($task_id);
}
public function removeTask($task_id)
{
return $this->task->remove($task_id);
TaskAuthorization::getInstance($this->container)->check($this->getClassName(), 'removeTask', $task_id);
return $this->taskModel->remove($task_id);
}
public function moveTaskPosition($project_id, $task_id, $column_id, $position, $swimlane_id = 0)
{
$this->checkProjectPermission($project_id);
return $this->taskPosition->movePosition($project_id, $task_id, $column_id, $position, $swimlane_id);
ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'moveTaskPosition', $project_id);
return $this->taskPositionModel->movePosition($project_id, $task_id, $column_id, $position, $swimlane_id);
}
public function moveTaskToProject($task_id, $project_id, $swimlane_id = null, $column_id = null, $category_id = null, $owner_id = null)
{
return $this->taskDuplication->moveToProject($task_id, $project_id, $swimlane_id, $column_id, $category_id, $owner_id);
ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'moveTaskToProject', $project_id);
return $this->taskProjectMoveModel->moveToProject($task_id, $project_id, $swimlane_id, $column_id, $category_id, $owner_id);
}
public function duplicateTaskToProject($task_id, $project_id, $swimlane_id = null, $column_id = null, $category_id = null, $owner_id = null)
{
return $this->taskDuplication->duplicateToProject($task_id, $project_id, $swimlane_id, $column_id, $category_id, $owner_id);
ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'duplicateTaskToProject', $project_id);
return $this->taskProjectDuplicationModel->duplicateToProject($task_id, $project_id, $swimlane_id, $column_id, $category_id, $owner_id);
}
public function createTask($title, $project_id, $color_id = '', $column_id = 0, $owner_id = 0, $creator_id = 0,
$date_due = '', $description = '', $category_id = 0, $score = 0, $swimlane_id = 0,
$date_due = '', $description = '', $category_id = 0, $score = 0, $swimlane_id = 0, $priority = 0,
$recurrence_status = 0, $recurrence_trigger = 0, $recurrence_factor = 0, $recurrence_timeframe = 0,
$recurrence_basedate = 0, $reference = '')
{
$this->checkProjectPermission($project_id);
if ($owner_id !== 0 && ! $this->projectPermission->isAssignable($project_id, $owner_id)) {
ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'createTask', $project_id);
if ($owner_id !== 0 && ! $this->projectPermissionModel->isAssignable($project_id, $owner_id)) {
return false;
}
@ -107,31 +119,31 @@ class Task extends Base
'recurrence_timeframe' => $recurrence_timeframe,
'recurrence_basedate' => $recurrence_basedate,
'reference' => $reference,
'priority' => $priority,
);
list($valid, ) = $this->taskValidator->validateCreation($values);
return $valid ? $this->taskCreation->create($values) : false;
return $valid ? $this->taskCreationModel->create($values) : false;
}
public function updateTask($id, $title = null, $color_id = null, $owner_id = null,
$date_due = null, $description = null, $category_id = null, $score = null,
$date_due = null, $description = null, $category_id = null, $score = null, $priority = null,
$recurrence_status = null, $recurrence_trigger = null, $recurrence_factor = null,
$recurrence_timeframe = null, $recurrence_basedate = null, $reference = null)
{
$this->checkTaskPermission($id);
$project_id = $this->taskFinder->getProjectId($id);
TaskAuthorization::getInstance($this->container)->check($this->getClassName(), 'updateTask', $id);
$project_id = $this->taskFinderModel->getProjectId($id);
if ($project_id === 0) {
return false;
}
if ($owner_id !== null && $owner_id != 0 && ! $this->projectPermission->isAssignable($project_id, $owner_id)) {
if ($owner_id !== null && $owner_id != 0 && ! $this->projectPermissionModel->isAssignable($project_id, $owner_id)) {
return false;
}
$values = array(
$values = $this->filterValues(array(
'id' => $id,
'title' => $title,
'color_id' => $color_id,
@ -146,15 +158,10 @@ class Task extends Base
'recurrence_timeframe' => $recurrence_timeframe,
'recurrence_basedate' => $recurrence_basedate,
'reference' => $reference,
);
foreach ($values as $key => $value) {
if (is_null($value)) {
unset($values[$key]);
}
}
'priority' => $priority,
));
list($valid) = $this->taskValidator->validateApiModification($values);
return $valid && $this->taskModification->update($values);
return $valid && $this->taskModificationModel->update($values);
}
}

View file

@ -1,6 +1,6 @@
<?php
namespace Kanboard\Api;
namespace Kanboard\Api\Procedure;
use LogicException;
use Kanboard\Core\Security\Role;
@ -11,44 +11,44 @@ use Kanboard\Core\Ldap\User as LdapUser;
/**
* User API controller
*
* @package api
* @package Kanboard\Api\Procedure
* @author Frederic Guillot
*/
class User extends \Kanboard\Core\Base
class UserProcedure extends BaseProcedure
{
public function getUser($user_id)
{
return $this->user->getById($user_id);
return $this->userModel->getById($user_id);
}
public function getUserByName($username)
{
return $this->user->getByUsername($username);
return $this->userModel->getByUsername($username);
}
public function getAllUsers()
{
return $this->user->getAll();
return $this->userModel->getAll();
}
public function removeUser($user_id)
{
return $this->user->remove($user_id);
return $this->userModel->remove($user_id);
}
public function disableUser($user_id)
{
return $this->user->disable($user_id);
return $this->userModel->disable($user_id);
}
public function enableUser($user_id)
{
return $this->user->enable($user_id);
return $this->userModel->enable($user_id);
}
public function isActiveUser($user_id)
{
return $this->user->isActive($user_id);
return $this->userModel->isActive($user_id);
}
public function createUser($username, $password, $name = '', $email = '', $role = Role::APP_USER)
@ -63,7 +63,7 @@ class User extends \Kanboard\Core\Base
);
list($valid, ) = $this->userValidator->validateCreation($values);
return $valid ? $this->user->create($values) : false;
return $valid ? $this->userModel->create($values) : false;
}
/**
@ -107,7 +107,7 @@ class User extends \Kanboard\Core\Base
'is_ldap_user' => 1,
);
return $this->user->create($values);
return $this->userModel->create($values);
} catch (LdapException $e) {
$this->logger->error($e->getMessage());
@ -117,21 +117,15 @@ class User extends \Kanboard\Core\Base
public function updateUser($id, $username = null, $name = null, $email = null, $role = null)
{
$values = array(
$values = $this->filterValues(array(
'id' => $id,
'username' => $username,
'name' => $name,
'email' => $email,
'role' => $role,
);
foreach ($values as $key => $value) {
if (is_null($value)) {
unset($values[$key]);
}
}
));
list($valid, ) = $this->userValidator->validateApiModification($values);
return $valid && $this->user->update($values);
return $valid && $this->userModel->update($values);
}
}

View file

@ -1,87 +0,0 @@
<?php
namespace Kanboard\Api;
/**
* Project API controller
*
* @package api
* @author Frederic Guillot
*/
class Project extends Base
{
public function getProjectById($project_id)
{
$this->checkProjectPermission($project_id);
return $this->formatProject($this->project->getById($project_id));
}
public function getProjectByName($name)
{
return $this->formatProject($this->project->getByName($name));
}
public function getAllProjects()
{
return $this->formatProjects($this->project->getAll());
}
public function removeProject($project_id)
{
return $this->project->remove($project_id);
}
public function enableProject($project_id)
{
return $this->project->enable($project_id);
}
public function disableProject($project_id)
{
return $this->project->disable($project_id);
}
public function enableProjectPublicAccess($project_id)
{
return $this->project->enablePublicAccess($project_id);
}
public function disableProjectPublicAccess($project_id)
{
return $this->project->disablePublicAccess($project_id);
}
public function getProjectActivities(array $project_ids)
{
return $this->projectActivity->getProjects($project_ids);
}
public function getProjectActivity($project_id)
{
$this->checkProjectPermission($project_id);
return $this->projectActivity->getProject($project_id);
}
public function createProject($name, $description = null)
{
$values = array(
'name' => $name,
'description' => $description
);
list($valid, ) = $this->projectValidator->validateCreation($values);
return $valid ? $this->project->create($values) : false;
}
public function updateProject($id, $name, $description = null)
{
$values = array(
'id' => $id,
'name' => $name,
'description' => $description
);
list($valid, ) = $this->projectValidator->validateModification($values);
return $valid && $this->project->update($values);
}
}

View file

@ -1,72 +0,0 @@
<?php
namespace Kanboard\Api;
use Kanboard\Core\Security\Role;
/**
* Project Permission API controller
*
* @package api
* @author Frederic Guillot
*/
class ProjectPermission extends \Kanboard\Core\Base
{
public function getProjectUsers($project_id)
{
return $this->projectUserRole->getAllUsers($project_id);
}
public function getAssignableUsers($project_id, $prepend_unassigned = false)
{
return $this->projectUserRole->getAssignableUsersList($project_id, $prepend_unassigned);
}
public function addProjectUser($project_id, $user_id, $role = Role::PROJECT_MEMBER)
{
return $this->projectUserRole->addUser($project_id, $user_id, $role);
}
public function addProjectGroup($project_id, $group_id, $role = Role::PROJECT_MEMBER)
{
return $this->projectGroupRole->addGroup($project_id, $group_id, $role);
}
public function removeProjectUser($project_id, $user_id)
{
return $this->projectUserRole->removeUser($project_id, $user_id);
}
public function removeProjectGroup($project_id, $group_id)
{
return $this->projectGroupRole->removeGroup($project_id, $group_id);
}
public function changeProjectUserRole($project_id, $user_id, $role)
{
return $this->projectUserRole->changeUserRole($project_id, $user_id, $role);
}
public function changeProjectGroupRole($project_id, $group_id, $role)
{
return $this->projectGroupRole->changeGroupRole($project_id, $group_id, $role);
}
// Deprecated
public function getMembers($project_id)
{
return $this->getProjectUsers($project_id);
}
// Deprecated
public function revokeUser($project_id, $user_id)
{
return $this->removeProjectUser($project_id, $user_id);
}
// Deprecated
public function allowUser($project_id, $user_id)
{
return $this->addProjectUser($project_id, $user_id);
}
}

View file

@ -1,78 +0,0 @@
<?php
namespace Kanboard\Api;
/**
* Swimlane API controller
*
* @package api
* @author Frederic Guillot
*/
class Swimlane extends \Kanboard\Core\Base
{
public function getActiveSwimlanes($project_id)
{
return $this->swimlane->getSwimlanes($project_id);
}
public function getAllSwimlanes($project_id)
{
return $this->swimlane->getAll($project_id);
}
public function getSwimlaneById($swimlane_id)
{
return $this->swimlane->getById($swimlane_id);
}
public function getSwimlaneByName($project_id, $name)
{
return $this->swimlane->getByName($project_id, $name);
}
public function getSwimlane($swimlane_id)
{
return $this->swimlane->getById($swimlane_id);
}
public function getDefaultSwimlane($project_id)
{
return $this->swimlane->getDefault($project_id);
}
public function addSwimlane($project_id, $name, $description = '')
{
return $this->swimlane->create(array('project_id' => $project_id, 'name' => $name, 'description' => $description));
}
public function updateSwimlane($swimlane_id, $name, $description = null)
{
$values = array('id' => $swimlane_id, 'name' => $name);
if (!is_null($description)) {
$values['description'] = $description;
}
return $this->swimlane->update($values);
}
public function removeSwimlane($project_id, $swimlane_id)
{
return $this->swimlane->remove($project_id, $swimlane_id);
}
public function disableSwimlane($project_id, $swimlane_id)
{
return $this->swimlane->disable($project_id, $swimlane_id);
}
public function enableSwimlane($project_id, $swimlane_id)
{
return $this->swimlane->enable($project_id, $swimlane_id);
}
public function changeSwimlanePosition($project_id, $swimlane_id, $position)
{
return $this->swimlane->changePosition($project_id, $swimlane_id, $position);
}
}

View file

@ -5,7 +5,7 @@ namespace Kanboard\Auth;
use Kanboard\Core\Base;
use Kanboard\Core\Security\PasswordAuthenticationProviderInterface;
use Kanboard\Core\Security\SessionCheckProviderInterface;
use Kanboard\Model\User;
use Kanboard\Model\UserModel;
use Kanboard\User\DatabaseUserProvider;
/**
@ -60,7 +60,7 @@ class DatabaseAuth extends Base implements PasswordAuthenticationProviderInterfa
public function authenticate()
{
$user = $this->db
->table(User::TABLE)
->table(UserModel::TABLE)
->columns('id', 'password')
->eq('username', $this->username)
->eq('disable_login_form', 0)
@ -84,7 +84,7 @@ class DatabaseAuth extends Base implements PasswordAuthenticationProviderInterfa
*/
public function isValidSession()
{
return $this->user->isActive($this->userSession->getId());
return $this->userModel->isActive($this->userSession->getId());
}
/**

View file

@ -76,7 +76,7 @@ class LdapAuth extends Base implements PasswordAuthenticationProviderInterface
throw new LogicException('Username not found in LDAP profile, check the parameter LDAP_USER_ATTRIBUTE_USERNAME');
}
$this->logger->info('Authenticate user: '.$user->getDn());
$this->logger->info('Authenticate this user: '.$user->getDn());
if ($client->authenticate($user->getDn(), $this->password)) {
$this->userInfo = $user;

View file

@ -44,16 +44,16 @@ class RememberMeAuth extends Base implements PreAuthenticationProviderInterface
$credentials = $this->rememberMeCookie->read();
if ($credentials !== false) {
$session = $this->rememberMeSession->find($credentials['token'], $credentials['sequence']);
$session = $this->rememberMeSessionModel->find($credentials['token'], $credentials['sequence']);
if (! empty($session)) {
$this->rememberMeCookie->write(
$session['token'],
$this->rememberMeSession->updateSequence($session['token']),
$this->rememberMeSessionModel->updateSequence($session['token']),
$session['expiration']
);
$this->userInfo = $this->user->getById($session['user_id']);
$this->userInfo = $this->userModel->getById($session['user_id']);
return true;
}

View file

@ -45,7 +45,8 @@ class ReverseProxyAuth extends Base implements PreAuthenticationProviderInterfac
$username = $this->request->getRemoteUser();
if (! empty($username)) {
$this->userInfo = new ReverseProxyUserProvider($username);
$userProfile = $this->userModel->getByUsername($username);
$this->userInfo = new ReverseProxyUserProvider($username, $userProfile ?: array());
return true;
}

View file

@ -1,61 +0,0 @@
<?php
namespace Kanboard\Console;
use Pimple\Container;
use Symfony\Component\Console\Command\Command;
/**
* Base command class
*
* @package console
* @author Frederic Guillot
*
* @property \Kanboard\Export\SubtaskExport $subtaskExport
* @property \Kanboard\Export\TaskExport $taskExport
* @property \Kanboard\Export\TransitionExport $transitionExport
* @property \Kanboard\Model\Notification $notification
* @property \Kanboard\Model\Project $project
* @property \Kanboard\Model\ProjectPermission $projectPermission
* @property \Kanboard\Model\ProjectDailyColumnStats $projectDailyColumnStats
* @property \Kanboard\Model\ProjectDailyStats $projectDailyStats
* @property \Kanboard\Model\Task $task
* @property \Kanboard\Model\TaskFinder $taskFinder
* @property \Kanboard\Model\UserNotification $userNotification
* @property \Kanboard\Model\UserNotificationFilter $userNotificationFilter
* @property \Symfony\Component\EventDispatcher\EventDispatcher $dispatcher
*/
abstract class Base extends Command
{
/**
* Container instance
*
* @access protected
* @var \Pimple\Container
*/
protected $container;
/**
* Constructor
*
* @access public
* @param \Pimple\Container $container
*/
public function __construct(Container $container)
{
parent::__construct();
$this->container = $container;
}
/**
* Load automatically models
*
* @access public
* @param string $name Model name
* @return mixed
*/
public function __get($name)
{
return $this->container[$name];
}
}

View file

@ -0,0 +1,67 @@
<?php
namespace Kanboard\Console;
use Pimple\Container;
use Symfony\Component\Console\Command\Command;
/**
* Base command class
*
* @package console
* @author Frederic Guillot
*
* @property \Kanboard\Validator\PasswordResetValidator $passwordResetValidator
* @property \Kanboard\Export\SubtaskExport $subtaskExport
* @property \Kanboard\Export\TaskExport $taskExport
* @property \Kanboard\Export\TransitionExport $transitionExport
* @property \Kanboard\Model\NotificationModel $notificationModel
* @property \Kanboard\Model\ProjectModel $projectModel
* @property \Kanboard\Model\ProjectPermissionModel $projectPermissionModel
* @property \Kanboard\Model\ProjectDailyColumnStatsModel $projectDailyColumnStatsModel
* @property \Kanboard\Model\ProjectDailyStatsModel $projectDailyStatsModel
* @property \Kanboard\Model\TaskModel $taskModel
* @property \Kanboard\Model\TaskFinderModel $taskFinderModel
* @property \Kanboard\Model\UserModel $userModel
* @property \Kanboard\Model\UserNotificationModel $userNotificationModel
* @property \Kanboard\Model\UserNotificationFilterModel $userNotificationFilterModel
* @property \Kanboard\Model\ProjectUserRoleModel $projectUserRoleModel
* @property \Kanboard\Core\Plugin\Loader $pluginLoader
* @property \Kanboard\Core\Http\Client $httpClient
* @property \Kanboard\Core\Queue\QueueManager $queueManager
* @property \Symfony\Component\EventDispatcher\EventDispatcher $dispatcher
*/
abstract class BaseCommand extends Command
{
/**
* Container instance
*
* @access protected
* @var \Pimple\Container
*/
protected $container;
/**
* Constructor
*
* @access public
* @param \Pimple\Container $container
*/
public function __construct(Container $container)
{
parent::__construct();
$this->container = $container;
}
/**
* Load automatically models
*
* @access public
* @param string $name Model name
* @return mixed
*/
public function __get($name)
{
return $this->container[$name];
}
}

View file

@ -7,7 +7,7 @@ use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Output\NullOutput;
class Cronjob extends Base
class CronjobCommand extends BaseCommand
{
private $commands = array(
'projects:daily-stats',

View file

@ -7,7 +7,7 @@ use RecursiveDirectoryIterator;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
class LocaleComparator extends Base
class LocaleComparatorCommand extends BaseCommand
{
const REF_LOCALE = 'fr_FR';

View file

@ -6,7 +6,7 @@ use DirectoryIterator;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
class LocaleSync extends Base
class LocaleSyncCommand extends BaseCommand
{
const REF_LOCALE = 'fr_FR';

View file

@ -0,0 +1,36 @@
<?php
namespace Kanboard\Console;
use Kanboard\Core\Plugin\Installer;
use Kanboard\Core\Plugin\PluginInstallerException;
use LogicException;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
class PluginInstallCommand extends BaseCommand
{
protected function configure()
{
$this
->setName('plugin:install')
->setDescription('Install a plugin from a remote Zip archive')
->addArgument('url', InputArgument::REQUIRED, 'Archive URL');
}
protected function execute(InputInterface $input, OutputInterface $output)
{
if (!Installer::isConfigured()) {
throw new LogicException('Kanboard is not configured to install plugins itself');
}
try {
$installer = new Installer($this->container);
$installer->install($input->getArgument('url'));
$output->writeln('<info>Plugin installed successfully</info>');
} catch (PluginInstallerException $e) {
$output->writeln('<error>'.$e->getMessage().'</error>');
}
}
}

View file

@ -0,0 +1,36 @@
<?php
namespace Kanboard\Console;
use Kanboard\Core\Plugin\Installer;
use Kanboard\Core\Plugin\PluginInstallerException;
use LogicException;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
class PluginUninstallCommand extends BaseCommand
{
protected function configure()
{
$this
->setName('plugin:uninstall')
->setDescription('Remove a plugin')
->addArgument('pluginId', InputArgument::REQUIRED, 'Plugin directory name');
}
protected function execute(InputInterface $input, OutputInterface $output)
{
if (!Installer::isConfigured()) {
throw new LogicException('Kanboard is not configured to install plugins itself');
}
try {
$installer = new Installer($this->container);
$installer->uninstall($input->getArgument('pluginId'));
$output->writeln('<info>Plugin removed successfully</info>');
} catch (PluginInstallerException $e) {
$output->writeln('<error>'.$e->getMessage().'</error>');
}
}
}

View file

@ -0,0 +1,55 @@
<?php
namespace Kanboard\Console;
use Kanboard\Core\Plugin\Base as BasePlugin;
use Kanboard\Core\Plugin\Directory;
use Kanboard\Core\Plugin\Installer;
use LogicException;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
class PluginUpgradeCommand extends BaseCommand
{
protected function configure()
{
$this
->setName('plugin:upgrade')
->setDescription('Update all installed plugins')
;
}
protected function execute(InputInterface $input, OutputInterface $output)
{
if (!Installer::isConfigured()) {
throw new LogicException('Kanboard is not configured to install plugins itself');
}
$installer = new Installer($this->container);
$availablePlugins = Directory::getInstance($this->container)->getAvailablePlugins();
foreach ($this->pluginLoader->getPlugins() as $installedPlugin) {
$pluginDetails = $this->getPluginDetails($availablePlugins, $installedPlugin);
if ($pluginDetails === null) {
$output->writeln('<error>* Plugin not available in the directory: '.$installedPlugin->getPluginName().'</error>');
} elseif ($pluginDetails['version'] > $installedPlugin->getPluginVersion()) {
$output->writeln('<comment>* Updating plugin: '.$installedPlugin->getPluginName().'</comment>');
$installer->update($pluginDetails['download']);
} else {
$output->writeln('<info>* Plugin up to date: '.$installedPlugin->getPluginName().'</info>');
}
}
}
protected function getPluginDetails(array $availablePlugins, BasePlugin $installedPlugin)
{
foreach ($availablePlugins as $availablePlugin) {
if ($availablePlugin['title'] === $installedPlugin->getPluginName()) {
return $availablePlugin;
}
}
return null;
}
}

View file

@ -7,7 +7,7 @@ use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
class ProjectDailyColumnStatsExport extends Base
class ProjectDailyColumnStatsExportCommand extends BaseCommand
{
protected function configure()
{
@ -21,7 +21,7 @@ class ProjectDailyColumnStatsExport extends Base
protected function execute(InputInterface $input, OutputInterface $output)
{
$data = $this->projectDailyColumnStats->getAggregatedMetrics(
$data = $this->projectDailyColumnStatsModel->getAggregatedMetrics(
$input->getArgument('project_id'),
$input->getArgument('start_date'),
$input->getArgument('end_date')

View file

@ -2,11 +2,11 @@
namespace Kanboard\Console;
use Kanboard\Model\Project;
use Kanboard\Model\ProjectModel;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
class ProjectDailyStatsCalculation extends Base
class ProjectDailyStatsCalculationCommand extends BaseCommand
{
protected function configure()
{
@ -17,12 +17,12 @@ class ProjectDailyStatsCalculation extends Base
protected function execute(InputInterface $input, OutputInterface $output)
{
$projects = $this->project->getAllByStatus(Project::ACTIVE);
$projects = $this->projectModel->getAllByStatus(ProjectModel::ACTIVE);
foreach ($projects as $project) {
$output->writeln('Run calculation for '.$project['name']);
$this->projectDailyColumnStats->updateTotals($project['id'], date('Y-m-d'));
$this->projectDailyStats->updateTotals($project['id'], date('Y-m-d'));
$this->projectDailyColumnStatsModel->updateTotals($project['id'], date('Y-m-d'));
$this->projectDailyStatsModel->updateTotals($project['id'], date('Y-m-d'));
}
}
}

View file

@ -0,0 +1,79 @@
<?php
namespace Kanboard\Console;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Question\Question;
class ResetPasswordCommand extends BaseCommand
{
protected function configure()
{
$this
->setName('user:reset-password')
->setDescription('Change user password')
->addArgument('username', InputArgument::REQUIRED, 'Username')
;
}
protected function execute(InputInterface $input, OutputInterface $output)
{
$helper = $this->getHelper('question');
$username = $input->getArgument('username');
$passwordQuestion = new Question('What is the new password for '.$username.'? (characters are not printed)'.PHP_EOL);
$passwordQuestion->setHidden(true);
$passwordQuestion->setHiddenFallback(false);
$password = $helper->ask($input, $output, $passwordQuestion);
$confirmationQuestion = new Question('Confirmation:'.PHP_EOL);
$confirmationQuestion->setHidden(true);
$confirmationQuestion->setHiddenFallback(false);
$confirmation = $helper->ask($input, $output, $confirmationQuestion);
if ($this->validatePassword($output, $password, $confirmation)) {
$this->resetPassword($output, $username, $password);
}
}
private function validatePassword(OutputInterface $output, $password, $confirmation)
{
list($valid, $errors) = $this->passwordResetValidator->validateModification(array(
'password' => $password,
'confirmation' => $confirmation,
));
if (!$valid) {
foreach ($errors as $error_list) {
foreach ($error_list as $error) {
$output->writeln('<error>'.$error.'</error>');
}
}
}
return $valid;
}
private function resetPassword(OutputInterface $output, $username, $password)
{
$userId = $this->userModel->getIdByUsername($username);
if (empty($userId)) {
$output->writeln('<error>User not found</error>');
return false;
}
if (!$this->userModel->update(array('id' => $userId, 'password' => $password))) {
$output->writeln('<error>Unable to update password</error>');
return false;
}
$output->writeln('<info>Password updated successfully</info>');
return true;
}
}

View file

@ -0,0 +1,38 @@
<?php
namespace Kanboard\Console;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
class ResetTwoFactorCommand extends BaseCommand
{
protected function configure()
{
$this
->setName('user:reset-2fa')
->setDescription('Remove two-factor authentication for a user')
->addArgument('username', InputArgument::REQUIRED, 'Username');
}
protected function execute(InputInterface $input, OutputInterface $output)
{
$username = $input->getArgument('username');
$userId = $this->userModel->getIdByUsername($username);
if (empty($userId)) {
$output->writeln('<error>User not found</error>');
return false;
}
if (!$this->userModel->update(array('id' => $userId, 'twofactor_activated' => 0, 'twofactor_secret' => ''))) {
$output->writeln('<error>Unable to update user profile</error>');
return false;
}
$output->writeln('<info>Two-factor authentication disabled</info>');
return true;
}
}

View file

@ -7,7 +7,7 @@ use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
class SubtaskExport extends Base
class SubtaskExportCommand extends BaseCommand
{
protected function configure()
{

View file

@ -7,7 +7,7 @@ use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
class TaskExport extends Base
class TaskExportCommand extends BaseCommand
{
protected function configure()
{

View file

@ -1,116 +0,0 @@
<?php
namespace Kanboard\Console;
use Kanboard\Model\Task;
use Symfony\Component\Console\Helper\Table;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
class TaskOverdueNotification extends Base
{
protected function configure()
{
$this
->setName('notification:overdue-tasks')
->setDescription('Send notifications for overdue tasks')
->addOption('show', null, InputOption::VALUE_NONE, 'Show sent overdue tasks');
}
protected function execute(InputInterface $input, OutputInterface $output)
{
$tasks = $this->sendOverdueTaskNotifications();
if ($input->getOption('show')) {
$this->showTable($output, $tasks);
}
}
public function showTable(OutputInterface $output, array $tasks)
{
$rows = array();
foreach ($tasks as $task) {
$rows[] = array(
$task['id'],
$task['title'],
date('Y-m-d', $task['date_due']),
$task['project_id'],
$task['project_name'],
$task['assignee_name'] ?: $task['assignee_username'],
);
}
$table = new Table($output);
$table
->setHeaders(array('Id', 'Title', 'Due date', 'Project Id', 'Project name', 'Assignee'))
->setRows($rows)
->render();
}
/**
* Send overdue tasks
*
* @access public
*/
public function sendOverdueTaskNotifications()
{
$tasks = $this->taskFinder->getOverdueTasks();
foreach ($this->groupByColumn($tasks, 'project_id') as $project_id => $project_tasks) {
$users = $this->userNotification->getUsersWithNotificationEnabled($project_id);
foreach ($users as $user) {
$this->sendUserOverdueTaskNotifications($user, $project_tasks);
}
}
return $tasks;
}
/**
* Send overdue tasks for a given user
*
* @access public
* @param array $user
* @param array $tasks
*/
public function sendUserOverdueTaskNotifications(array $user, array $tasks)
{
$user_tasks = array();
foreach ($tasks as $task) {
if ($this->userNotificationFilter->shouldReceiveNotification($user, array('task' => $task))) {
$user_tasks[] = $task;
}
}
if (! empty($user_tasks)) {
$this->userNotification->sendUserNotification(
$user,
Task::EVENT_OVERDUE,
array('tasks' => $user_tasks, 'project_name' => $tasks[0]['project_name'])
);
}
}
/**
* Group a collection of records by a column
*
* @access public
* @param array $collection
* @param string $column
* @return array
*/
public function groupByColumn(array $collection, $column)
{
$result = array();
foreach ($collection as $item) {
$result[$item[$column]][] = $item;
}
return $result;
}
}

Some files were not shown because too many files have changed in this diff Show more