Apply column restrictions to the board

This commit is contained in:
Frederic Guillot 2016-09-08 22:33:16 -04:00
parent fedf4ea2de
commit 75470c7242
No known key found for this signature in database
GPG Key ID: 92D77191BA7FBC99
14 changed files with 383 additions and 169 deletions

View File

@ -28,11 +28,21 @@ class BoardAjaxController extends BaseController
}
$values = $this->request->getJson();
$canMoveTask = $this->columnMoveRestrictionModel->isAllowed(
$project_id,
$this->helper->user->getProjectUserRole($project_id),
$values['src_column_id'],
$values['dst_column_id']
);
if (! $canMoveTask) {
throw new AccessForbiddenException("You don't have the permission to move this task");
}
$result =$this->taskPositionModel->movePosition(
$project_id,
$values['task_id'],
$values['column_id'],
$values['dst_column_id'],
$values['position'],
$values['swimlane_id']
);

View File

@ -10,168 +10,171 @@ use Pimple\Container;
* @package core
* @author Frederic Guillot
*
* @property \Kanboard\Analytic\TaskDistributionAnalytic $taskDistributionAnalytic
* @property \Kanboard\Analytic\UserDistributionAnalytic $userDistributionAnalytic
* @property \Kanboard\Analytic\EstimatedTimeComparisonAnalytic $estimatedTimeComparisonAnalytic
* @property \Kanboard\Analytic\AverageLeadCycleTimeAnalytic $averageLeadCycleTimeAnalytic
* @property \Kanboard\Analytic\AverageTimeSpentColumnAnalytic $averageTimeSpentColumnAnalytic
* @property \Kanboard\Core\Action\ActionManager $actionManager
* @property \Kanboard\Core\ExternalLink\ExternalLinkManager $externalLinkManager
* @property \Kanboard\Core\Cache\MemoryCache $memoryCache
* @property \Kanboard\Core\Cache\BaseCache $cacheDriver
* @property \Kanboard\Core\Event\EventManager $eventManager
* @property \Kanboard\Core\Group\GroupManager $groupManager
* @property \Kanboard\Core\Http\Client $httpClient
* @property \Kanboard\Core\Http\OAuth2 $oauth
* @property \Kanboard\Core\Http\RememberMeCookie $rememberMeCookie
* @property \Kanboard\Core\Http\Request $request
* @property \Kanboard\Core\Http\Response $response
* @property \Kanboard\Core\Http\Router $router
* @property \Kanboard\Core\Http\Route $route
* @property \Kanboard\Core\Queue\QueueManager $queueManager
* @property \Kanboard\Core\Mail\Client $emailClient
* @property \Kanboard\Core\ObjectStorage\ObjectStorageInterface $objectStorage
* @property \Kanboard\Core\Plugin\Hook $hook
* @property \Kanboard\Core\Plugin\Loader $pluginLoader
* @property \Kanboard\Core\Security\AuthenticationManager $authenticationManager
* @property \Kanboard\Core\Security\AccessMap $applicationAccessMap
* @property \Kanboard\Core\Security\AccessMap $projectAccessMap
* @property \Kanboard\Core\Security\AccessMap $apiAccessMap
* @property \Kanboard\Core\Security\AccessMap $apiProjectAccessMap
* @property \Kanboard\Core\Security\Authorization $applicationAuthorization
* @property \Kanboard\Core\Security\Authorization $projectAuthorization
* @property \Kanboard\Core\Security\Authorization $apiAuthorization
* @property \Kanboard\Core\Security\Authorization $apiProjectAuthorization
* @property \Kanboard\Core\Security\Role $role
* @property \Kanboard\Core\Security\Token $token
* @property \Kanboard\Core\Session\FlashMessage $flash
* @property \Kanboard\Core\Session\SessionManager $sessionManager
* @property \Kanboard\Core\Session\SessionStorage $sessionStorage
* @property \Kanboard\Core\User\Avatar\AvatarManager $avatarManager
* @property \Kanboard\Core\User\GroupSync $groupSync
* @property \Kanboard\Core\User\UserProfile $userProfile
* @property \Kanboard\Core\User\UserSync $userSync
* @property \Kanboard\Core\User\UserSession $userSession
* @property \Kanboard\Core\DateParser $dateParser
* @property \Kanboard\Core\Helper $helper
* @property \Kanboard\Core\Paginator $paginator
* @property \Kanboard\Core\Template $template
* @property \Kanboard\Decorator\MetadataCacheDecorator $userMetadataCacheDecorator
* @property \Kanboard\Model\ActionModel $actionModel
* @property \Kanboard\Model\ActionParameterModel $actionParameterModel
* @property \Kanboard\Model\AvatarFileModel $avatarFileModel
* @property \Kanboard\Model\BoardModel $boardModel
* @property \Kanboard\Model\CategoryModel $categoryModel
* @property \Kanboard\Model\ColorModel $colorModel
* @property \Kanboard\Model\ColumnModel $columnModel
* @property \Kanboard\Model\CommentModel $commentModel
* @property \Kanboard\Model\ConfigModel $configModel
* @property \Kanboard\Model\CurrencyModel $currencyModel
* @property \Kanboard\Model\CustomFilterModel $customFilterModel
* @property \Kanboard\Model\TaskFileModel $taskFileModel
* @property \Kanboard\Model\ProjectFileModel $projectFileModel
* @property \Kanboard\Model\GroupModel $groupModel
* @property \Kanboard\Model\GroupMemberModel $groupMemberModel
* @property \Kanboard\Model\LanguageModel $languageModel
* @property \Kanboard\Model\LastLoginModel $lastLoginModel
* @property \Kanboard\Model\LinkModel $linkModel
* @property \Kanboard\Model\NotificationModel $notificationModel
* @property \Kanboard\Model\PasswordResetModel $passwordResetModel
* @property \Kanboard\Model\ProjectModel $projectModel
* @property \Kanboard\Model\ProjectActivityModel $projectActivityModel
* @property \Kanboard\Model\ProjectDuplicationModel $projectDuplicationModel
* @property \Kanboard\Model\ProjectDailyColumnStatsModel $projectDailyColumnStatsModel
* @property \Kanboard\Model\ProjectDailyStatsModel $projectDailyStatsModel
* @property \Kanboard\Model\ProjectMetadataModel $projectMetadataModel
* @property \Kanboard\Model\ProjectPermissionModel $projectPermissionModel
* @property \Kanboard\Model\ProjectUserRoleModel $projectUserRoleModel
* @property \Kanboard\Model\ProjectGroupRoleModel $projectGroupRoleModel
* @property \Kanboard\Model\ProjectNotificationModel $projectNotificationModel
* @property \Kanboard\Model\ProjectNotificationTypeModel $projectNotificationTypeModel
* @property \Kanboard\Model\ProjectTaskDuplicationModel $projectTaskDuplicationModel
* @property \Kanboard\Model\ProjectTaskPriorityModel $projectTaskPriorityModel
* @property \Kanboard\Model\RememberMeSessionModel $rememberMeSessionModel
* @property \Kanboard\Model\SubtaskModel $subtaskModel
* @property \Kanboard\Model\SubtaskPositionModel $subtaskPositionModel
* @property \Kanboard\Model\SubtaskStatusModel $subtaskStatusModel
* @property \Kanboard\Model\SubtaskTaskConversionModel $subtaskTaskConversionModel
* @property \Kanboard\Model\SubtaskTimeTrackingModel $subtaskTimeTrackingModel
* @property \Kanboard\Model\SwimlaneModel $swimlaneModel
* @property \Kanboard\Model\TagDuplicationModel $tagDuplicationModel
* @property \Kanboard\Model\TagModel $tagModel
* @property \Kanboard\Model\TaskModel $taskModel
* @property \Kanboard\Model\TaskAnalyticModel $taskAnalyticModel
* @property \Kanboard\Model\TaskCreationModel $taskCreationModel
* @property \Kanboard\Model\TaskDuplicationModel $taskDuplicationModel
* @property \Kanboard\Model\TaskProjectDuplicationModel $taskProjectDuplicationModel
* @property \Kanboard\Model\TaskProjectMoveModel $taskProjectMoveModel
* @property \Kanboard\Model\TaskRecurrenceModel $taskRecurrenceModel
* @property \Kanboard\Model\TaskExternalLinkModel $taskExternalLinkModel
* @property \Kanboard\Model\TaskFinderModel $taskFinderModel
* @property \Kanboard\Model\TaskLinkModel $taskLinkModel
* @property \Kanboard\Model\TaskModificationModel $taskModificationModel
* @property \Kanboard\Model\TaskPositionModel $taskPositionModel
* @property \Kanboard\Model\TaskStatusModel $taskStatusModel
* @property \Kanboard\Model\TaskTagModel $taskTagModel
* @property \Kanboard\Model\TaskMetadataModel $taskMetadataModel
* @property \Kanboard\Model\TimezoneModel $timezoneModel
* @property \Kanboard\Model\TransitionModel $transitionModel
* @property \Kanboard\Model\UserModel $userModel
* @property \Kanboard\Model\UserLockingModel $userLockingModel
* @property \Kanboard\Model\UserMentionModel $userMentionModel
* @property \Kanboard\Model\UserNotificationModel $userNotificationModel
* @property \Kanboard\Model\UserNotificationTypeModel $userNotificationTypeModel
* @property \Kanboard\Model\UserNotificationFilterModel $userNotificationFilterModel
* @property \Kanboard\Model\UserUnreadNotificationModel $userUnreadNotificationModel
* @property \Kanboard\Model\UserMetadataModel $userMetadataModel
* @property \Kanboard\Pagination\TaskPagination $taskPagination
* @property \Kanboard\Pagination\SubtaskPagination $subtaskPagination
* @property \Kanboard\Pagination\ProjectPagination $projectPagination
* @property \Kanboard\Pagination\UserPagination $userPagination
* @property \Kanboard\Validator\ActionValidator $actionValidator
* @property \Kanboard\Validator\AuthValidator $authValidator
* @property \Kanboard\Validator\ColumnValidator $columnValidator
* @property \Kanboard\Validator\CategoryValidator $categoryValidator
* @property \Kanboard\Validator\CommentValidator $commentValidator
* @property \Kanboard\Validator\CurrencyValidator $currencyValidator
* @property \Kanboard\Validator\CustomFilterValidator $customFilterValidator
* @property \Kanboard\Validator\ExternalLinkValidator $externalLinkValidator
* @property \Kanboard\Validator\GroupValidator $groupValidator
* @property \Kanboard\Validator\LinkValidator $linkValidator
* @property \Kanboard\Validator\PasswordResetValidator $passwordResetValidator
* @property \Kanboard\Validator\ProjectValidator $projectValidator
* @property \Kanboard\Validator\SubtaskValidator $subtaskValidator
* @property \Kanboard\Validator\SwimlaneValidator $swimlaneValidator
* @property \Kanboard\Validator\TagValidator $tagValidator
* @property \Kanboard\Validator\TaskLinkValidator $taskLinkValidator
* @property \Kanboard\Validator\TaskValidator $taskValidator
* @property \Kanboard\Validator\UserValidator $userValidator
* @property \Kanboard\Import\TaskImport $taskImport
* @property \Kanboard\Import\UserImport $userImport
* @property \Kanboard\Export\SubtaskExport $subtaskExport
* @property \Kanboard\Export\TaskExport $taskExport
* @property \Kanboard\Export\TransitionExport $transitionExport
* @property \Kanboard\Core\Filter\QueryBuilder $projectGroupRoleQuery
* @property \Kanboard\Core\Filter\QueryBuilder $projectUserRoleQuery
* @property \Kanboard\Core\Filter\QueryBuilder $projectActivityQuery
* @property \Kanboard\Core\Filter\QueryBuilder $userQuery
* @property \Kanboard\Core\Filter\QueryBuilder $projectQuery
* @property \Kanboard\Core\Filter\QueryBuilder $taskQuery
* @property \Kanboard\Core\Filter\LexerBuilder $taskLexer
* @property \Kanboard\Core\Filter\LexerBuilder $projectActivityLexer
* @property \Kanboard\Job\CommentEventJob $commentEventJob
* @property \Kanboard\Job\SubtaskEventJob $subtaskEventJob
* @property \Kanboard\Job\TaskEventJob $taskEventJob
* @property \Kanboard\Job\TaskFileEventJob $taskFileEventJob
* @property \Kanboard\Job\TaskLinkEventJob $taskLinkEventJob
* @property \Kanboard\Job\ProjectFileEventJob $projectFileEventJob
* @property \Kanboard\Job\NotificationJob $notificationJob
* @property \Kanboard\Job\ProjectMetricJob $projectMetricJob
* @property \Psr\Log\LoggerInterface $logger
* @property \PicoDb\Database $db
* @property \Symfony\Component\EventDispatcher\EventDispatcher $dispatcher
* @property \Symfony\Component\Console\Application $cli
* @property \JsonRPC\Server $api
* @property \Kanboard\Analytic\TaskDistributionAnalytic $taskDistributionAnalytic
* @property \Kanboard\Analytic\UserDistributionAnalytic $userDistributionAnalytic
* @property \Kanboard\Analytic\EstimatedTimeComparisonAnalytic $estimatedTimeComparisonAnalytic
* @property \Kanboard\Analytic\AverageLeadCycleTimeAnalytic $averageLeadCycleTimeAnalytic
* @property \Kanboard\Analytic\AverageTimeSpentColumnAnalytic $averageTimeSpentColumnAnalytic
* @property \Kanboard\Core\Action\ActionManager $actionManager
* @property \Kanboard\Core\ExternalLink\ExternalLinkManager $externalLinkManager
* @property \Kanboard\Core\Cache\MemoryCache $memoryCache
* @property \Kanboard\Core\Cache\BaseCache $cacheDriver
* @property \Kanboard\Core\Event\EventManager $eventManager
* @property \Kanboard\Core\Group\GroupManager $groupManager
* @property \Kanboard\Core\Http\Client $httpClient
* @property \Kanboard\Core\Http\OAuth2 $oauth
* @property \Kanboard\Core\Http\RememberMeCookie $rememberMeCookie
* @property \Kanboard\Core\Http\Request $request
* @property \Kanboard\Core\Http\Response $response
* @property \Kanboard\Core\Http\Router $router
* @property \Kanboard\Core\Http\Route $route
* @property \Kanboard\Core\Queue\QueueManager $queueManager
* @property \Kanboard\Core\Mail\Client $emailClient
* @property \Kanboard\Core\ObjectStorage\ObjectStorageInterface $objectStorage
* @property \Kanboard\Core\Plugin\Hook $hook
* @property \Kanboard\Core\Plugin\Loader $pluginLoader
* @property \Kanboard\Core\Security\AuthenticationManager $authenticationManager
* @property \Kanboard\Core\Security\AccessMap $applicationAccessMap
* @property \Kanboard\Core\Security\AccessMap $projectAccessMap
* @property \Kanboard\Core\Security\AccessMap $apiAccessMap
* @property \Kanboard\Core\Security\AccessMap $apiProjectAccessMap
* @property \Kanboard\Core\Security\Authorization $applicationAuthorization
* @property \Kanboard\Core\Security\Authorization $projectAuthorization
* @property \Kanboard\Core\Security\Authorization $apiAuthorization
* @property \Kanboard\Core\Security\Authorization $apiProjectAuthorization
* @property \Kanboard\Core\Security\Role $role
* @property \Kanboard\Core\Security\Token $token
* @property \Kanboard\Core\Session\FlashMessage $flash
* @property \Kanboard\Core\Session\SessionManager $sessionManager
* @property \Kanboard\Core\Session\SessionStorage $sessionStorage
* @property \Kanboard\Core\User\Avatar\AvatarManager $avatarManager
* @property \Kanboard\Core\User\GroupSync $groupSync
* @property \Kanboard\Core\User\UserProfile $userProfile
* @property \Kanboard\Core\User\UserSync $userSync
* @property \Kanboard\Core\User\UserSession $userSession
* @property \Kanboard\Core\DateParser $dateParser
* @property \Kanboard\Core\Helper $helper
* @property \Kanboard\Core\Paginator $paginator
* @property \Kanboard\Core\Template $template
* @property \Kanboard\Decorator\MetadataCacheDecorator $userMetadataCacheDecorator
* @property \Kanboard\Decorator\ColumnMoveRestrictionCacheDecorator $columnMoveRestrictionCacheDecorator
* @property \Kanboard\Model\ActionModel $actionModel
* @property \Kanboard\Model\ActionParameterModel $actionParameterModel
* @property \Kanboard\Model\AvatarFileModel $avatarFileModel
* @property \Kanboard\Model\BoardModel $boardModel
* @property \Kanboard\Model\CategoryModel $categoryModel
* @property \Kanboard\Model\ColorModel $colorModel
* @property \Kanboard\Model\ColumnModel $columnModel
* @property \Kanboard\Model\ColumnMoveRestrictionModel $columnMoveRestrictionModel
* @property \Kanboard\Model\CommentModel $commentModel
* @property \Kanboard\Model\ConfigModel $configModel
* @property \Kanboard\Model\CurrencyModel $currencyModel
* @property \Kanboard\Model\CustomFilterModel $customFilterModel
* @property \Kanboard\Model\TaskFileModel $taskFileModel
* @property \Kanboard\Model\ProjectFileModel $projectFileModel
* @property \Kanboard\Model\GroupModel $groupModel
* @property \Kanboard\Model\GroupMemberModel $groupMemberModel
* @property \Kanboard\Model\LanguageModel $languageModel
* @property \Kanboard\Model\LastLoginModel $lastLoginModel
* @property \Kanboard\Model\LinkModel $linkModel
* @property \Kanboard\Model\NotificationModel $notificationModel
* @property \Kanboard\Model\PasswordResetModel $passwordResetModel
* @property \Kanboard\Model\ProjectModel $projectModel
* @property \Kanboard\Model\ProjectActivityModel $projectActivityModel
* @property \Kanboard\Model\ProjectDuplicationModel $projectDuplicationModel
* @property \Kanboard\Model\ProjectDailyColumnStatsModel $projectDailyColumnStatsModel
* @property \Kanboard\Model\ProjectDailyStatsModel $projectDailyStatsModel
* @property \Kanboard\Model\ProjectMetadataModel $projectMetadataModel
* @property \Kanboard\Model\ProjectPermissionModel $projectPermissionModel
* @property \Kanboard\Model\ProjectUserRoleModel $projectUserRoleModel
* @property \Kanboard\Model\ProjectGroupRoleModel $projectGroupRoleModel
* @property \Kanboard\Model\ProjectNotificationModel $projectNotificationModel
* @property \Kanboard\Model\ProjectNotificationTypeModel $projectNotificationTypeModel
* @property \Kanboard\Model\ProjectRoleModel $projectRoleModel
* @property \Kanboard\Model\ProjectTaskDuplicationModel $projectTaskDuplicationModel
* @property \Kanboard\Model\ProjectTaskPriorityModel $projectTaskPriorityModel
* @property \Kanboard\Model\RememberMeSessionModel $rememberMeSessionModel
* @property \Kanboard\Model\SubtaskModel $subtaskModel
* @property \Kanboard\Model\SubtaskPositionModel $subtaskPositionModel
* @property \Kanboard\Model\SubtaskStatusModel $subtaskStatusModel
* @property \Kanboard\Model\SubtaskTaskConversionModel $subtaskTaskConversionModel
* @property \Kanboard\Model\SubtaskTimeTrackingModel $subtaskTimeTrackingModel
* @property \Kanboard\Model\SwimlaneModel $swimlaneModel
* @property \Kanboard\Model\TagDuplicationModel $tagDuplicationModel
* @property \Kanboard\Model\TagModel $tagModel
* @property \Kanboard\Model\TaskModel $taskModel
* @property \Kanboard\Model\TaskAnalyticModel $taskAnalyticModel
* @property \Kanboard\Model\TaskCreationModel $taskCreationModel
* @property \Kanboard\Model\TaskDuplicationModel $taskDuplicationModel
* @property \Kanboard\Model\TaskProjectDuplicationModel $taskProjectDuplicationModel
* @property \Kanboard\Model\TaskProjectMoveModel $taskProjectMoveModel
* @property \Kanboard\Model\TaskRecurrenceModel $taskRecurrenceModel
* @property \Kanboard\Model\TaskExternalLinkModel $taskExternalLinkModel
* @property \Kanboard\Model\TaskFinderModel $taskFinderModel
* @property \Kanboard\Model\TaskLinkModel $taskLinkModel
* @property \Kanboard\Model\TaskModificationModel $taskModificationModel
* @property \Kanboard\Model\TaskPositionModel $taskPositionModel
* @property \Kanboard\Model\TaskStatusModel $taskStatusModel
* @property \Kanboard\Model\TaskTagModel $taskTagModel
* @property \Kanboard\Model\TaskMetadataModel $taskMetadataModel
* @property \Kanboard\Model\TimezoneModel $timezoneModel
* @property \Kanboard\Model\TransitionModel $transitionModel
* @property \Kanboard\Model\UserModel $userModel
* @property \Kanboard\Model\UserLockingModel $userLockingModel
* @property \Kanboard\Model\UserMentionModel $userMentionModel
* @property \Kanboard\Model\UserNotificationModel $userNotificationModel
* @property \Kanboard\Model\UserNotificationTypeModel $userNotificationTypeModel
* @property \Kanboard\Model\UserNotificationFilterModel $userNotificationFilterModel
* @property \Kanboard\Model\UserUnreadNotificationModel $userUnreadNotificationModel
* @property \Kanboard\Model\UserMetadataModel $userMetadataModel
* @property \Kanboard\Pagination\TaskPagination $taskPagination
* @property \Kanboard\Pagination\SubtaskPagination $subtaskPagination
* @property \Kanboard\Pagination\ProjectPagination $projectPagination
* @property \Kanboard\Pagination\UserPagination $userPagination
* @property \Kanboard\Validator\ActionValidator $actionValidator
* @property \Kanboard\Validator\AuthValidator $authValidator
* @property \Kanboard\Validator\ColumnValidator $columnValidator
* @property \Kanboard\Validator\CategoryValidator $categoryValidator
* @property \Kanboard\Validator\CommentValidator $commentValidator
* @property \Kanboard\Validator\CurrencyValidator $currencyValidator
* @property \Kanboard\Validator\CustomFilterValidator $customFilterValidator
* @property \Kanboard\Validator\ExternalLinkValidator $externalLinkValidator
* @property \Kanboard\Validator\GroupValidator $groupValidator
* @property \Kanboard\Validator\LinkValidator $linkValidator
* @property \Kanboard\Validator\PasswordResetValidator $passwordResetValidator
* @property \Kanboard\Validator\ProjectValidator $projectValidator
* @property \Kanboard\Validator\SubtaskValidator $subtaskValidator
* @property \Kanboard\Validator\SwimlaneValidator $swimlaneValidator
* @property \Kanboard\Validator\TagValidator $tagValidator
* @property \Kanboard\Validator\TaskLinkValidator $taskLinkValidator
* @property \Kanboard\Validator\TaskValidator $taskValidator
* @property \Kanboard\Validator\UserValidator $userValidator
* @property \Kanboard\Import\TaskImport $taskImport
* @property \Kanboard\Import\UserImport $userImport
* @property \Kanboard\Export\SubtaskExport $subtaskExport
* @property \Kanboard\Export\TaskExport $taskExport
* @property \Kanboard\Export\TransitionExport $transitionExport
* @property \Kanboard\Core\Filter\QueryBuilder $projectGroupRoleQuery
* @property \Kanboard\Core\Filter\QueryBuilder $projectUserRoleQuery
* @property \Kanboard\Core\Filter\QueryBuilder $projectActivityQuery
* @property \Kanboard\Core\Filter\QueryBuilder $userQuery
* @property \Kanboard\Core\Filter\QueryBuilder $projectQuery
* @property \Kanboard\Core\Filter\QueryBuilder $taskQuery
* @property \Kanboard\Core\Filter\LexerBuilder $taskLexer
* @property \Kanboard\Core\Filter\LexerBuilder $projectActivityLexer
* @property \Kanboard\Job\CommentEventJob $commentEventJob
* @property \Kanboard\Job\SubtaskEventJob $subtaskEventJob
* @property \Kanboard\Job\TaskEventJob $taskEventJob
* @property \Kanboard\Job\TaskFileEventJob $taskFileEventJob
* @property \Kanboard\Job\TaskLinkEventJob $taskLinkEventJob
* @property \Kanboard\Job\ProjectFileEventJob $projectFileEventJob
* @property \Kanboard\Job\NotificationJob $notificationJob
* @property \Kanboard\Job\ProjectMetricJob $projectMetricJob
* @property \Psr\Log\LoggerInterface $logger
* @property \PicoDb\Database $db
* @property \Symfony\Component\EventDispatcher\EventDispatcher $dispatcher
* @property \Symfony\Component\Console\Application $cli
* @property \JsonRPC\Server $api
*/
abstract class Base
{

View File

@ -12,6 +12,7 @@ use Pimple\Container;
*
* @property \Kanboard\Helper\AppHelper $app
* @property \Kanboard\Helper\AssetHelper $asset
* @property \Kanboard\Helper\BoardHelper $board
* @property \Kanboard\Helper\CalendarHelper $calendar
* @property \Kanboard\Helper\DateHelper $dt
* @property \Kanboard\Helper\FileHelper $file

View File

@ -0,0 +1,57 @@
<?php
namespace Kanboard\Decorator;
use Kanboard\Core\Cache\CacheInterface;
use Kanboard\Model\ColumnMoveRestrictionModel;
/**
* Class ColumnMoveRestrictionCacheDecorator
*
* @package Kanboard\Decorator
* @author Frederic Guillot
*/
class ColumnMoveRestrictionCacheDecorator
{
protected $cachePrefix = 'column_move_restriction:';
/**
* @var CacheInterface
*/
protected $cache;
/**
* @var ColumnMoveRestrictionModel
*/
protected $columnMoveRestrictionModel;
/**
* ColumnMoveRestrictionDecorator constructor.
*
* @param CacheInterface $cache
* @param ColumnMoveRestrictionModel $columnMoveRestrictionModel
*/
public function __construct(CacheInterface $cache, ColumnMoveRestrictionModel $columnMoveRestrictionModel)
{
$this->cache = $cache;
$this->columnMoveRestrictionModel = $columnMoveRestrictionModel;
}
/**
* Proxy method to get column Ids
* @param int $project_id
* @return array|mixed
*/
public function getAllSrcColumns($project_id)
{
$key = $this->cachePrefix.$project_id;
$columnIds = $this->cache->get($key);
if ($columnIds === null) {
$columnIds = $this->columnMoveRestrictionModel->getAllSrcColumns($project_id);
$this->cache->set($key, $columnIds);
}
return $columnIds;
}
}

View File

@ -79,6 +79,11 @@ class BoardTaskFormatter extends BaseFormatter implements FormatterInterface
{
$tasks = array_values(array_filter($this->tasks, array($this, 'filterTasks')));
array_merge_relation($tasks, $this->tags, 'tags', 'id');
foreach ($tasks as &$task) {
$task['is_draggable'] = $this->helper->board->isDraggable($task);
}
return $tasks;
}

View File

@ -24,4 +24,20 @@ class BoardHelper extends Base
{
return $this->userMetadataCacheDecorator->get(UserMetadataModel::KEY_BOARD_COLLAPSED.$project_id, 0) == 1;
}
/**
* Return true if the task can be moved by the connected user
*
* @param array $task
* @return bool
*/
public function isDraggable(array $task)
{
if ($task['is_active'] == 1 && $this->helper->user->hasProjectAccess('BoardViewController', 'save', $task['project_id'])) {
$srcColumnIds = $this->columnMoveRestrictionCacheDecorator->getAllSrcColumns($task['project_id']);
return ! isset($srcColumnIds[$task['column_id']]);
}
return false;
}
}

View File

@ -42,7 +42,8 @@ class ColumnMoveRestrictionModel extends Base
*/
public function getAll($project_id)
{
return $this->db->table(self::TABLE)
return $this->db
->table(self::TABLE)
->columns(
'restriction_id',
'src_column_id',
@ -58,6 +59,20 @@ class ColumnMoveRestrictionModel extends Base
->findAll();
}
/**
* Get all source column Ids
*
* @param int $project_id
* @return array
*/
public function getAllSrcColumns($project_id)
{
return $this->db
->hashtable(self::TABLE)
->eq(self::TABLE.'.project_id', $project_id)
->getAll('src_column_id', 'src_column_id');
}
/**
* Create a new column restriction
*

View File

@ -4,6 +4,7 @@ namespace Kanboard\ServiceProvider;
use Kanboard\Core\Cache\FileCache;
use Kanboard\Core\Cache\MemoryCache;
use Kanboard\Decorator\ColumnMoveRestrictionCacheDecorator;
use Kanboard\Decorator\MetadataCacheDecorator;
use Pimple\Container;
use Pimple\ServiceProviderInterface;
@ -46,6 +47,13 @@ class CacheProvider implements ServiceProviderInterface
);
};
$container['columnMoveRestrictionCacheDecorator'] = function($c) {
return new ColumnMoveRestrictionCacheDecorator(
$c['memoryCache'],
$c['columnMoveRestrictionModel']
);
};
return $container;
}
}

View File

@ -34,6 +34,7 @@ class ClassProvider implements ServiceProviderInterface
'CategoryModel',
'ColorModel',
'ColumnModel',
'ColumnMoveRestrictionModel',
'CommentModel',
'ConfigModel',
'CurrencyModel',
@ -55,6 +56,7 @@ class ClassProvider implements ServiceProviderInterface
'ProjectNotificationModel',
'ProjectMetadataModel',
'ProjectGroupRoleModel',
'ProjectRoleModel',
'ProjectTaskDuplicationModel',
'ProjectTaskPriorityModel',
'ProjectUserRoleModel',

View File

@ -1,6 +1,7 @@
<div class="
task-board
<?= $task['is_active'] == 1 ? ($this->user->hasProjectAccess('BoardViewController', 'save', $task['project_id']) ? 'draggable-item ' : '').'task-board-status-open '.($task['date_modification'] > (time() - $board_highlight_period) ? 'task-board-recent' : '') : 'task-board-status-closed' ?>
<?= $task['is_draggable'] ? 'draggable-item ' : '' ?>
<?= $task['is_active'] == 1 ? 'task-board-status-open '.($task['date_modification'] > (time() - $board_highlight_period) ? 'task-board-recent' : '') : 'task-board-status-closed' ?>
color-<?= $task['color_id'] ?>"
data-task-id="<?= $task['id'] ?>"
data-column-id="<?= $task['column_id'] ?>"

File diff suppressed because one or more lines are too long

View File

@ -34,7 +34,7 @@ Kanboard.BoardDragAndDrop.prototype.dragAndDrop = function() {
if (newColumnId != taskColumnId || newSwimlaneId != taskSwimlaneId || newPosition != taskPosition) {
self.changeTaskState(taskId);
self.save(taskId, newColumnId, newPosition, newSwimlaneId);
self.save(taskId, taskColumnId, newColumnId, newPosition, newSwimlaneId);
}
},
start: function(event, ui) {
@ -62,7 +62,7 @@ Kanboard.BoardDragAndDrop.prototype.changeTaskState = function(taskId) {
task.find('.task-board-saving-icon').show();
};
Kanboard.BoardDragAndDrop.prototype.save = function(taskId, columnId, position, swimlaneId) {
Kanboard.BoardDragAndDrop.prototype.save = function(taskId, srcColumnId, dstColumnId, position, swimlaneId) {
var self = this;
self.app.showLoadingIcon();
self.savingInProgress = true;
@ -75,7 +75,8 @@ Kanboard.BoardDragAndDrop.prototype.save = function(taskId, columnId, position,
processData: false,
data: JSON.stringify({
"task_id": taskId,
"column_id": columnId,
"src_column_id": srcColumnId,
"dst_column_id": dstColumnId,
"swimlane_id": swimlaneId,
"position": position
}),

View File

@ -123,6 +123,7 @@ class BoardFormatterTest extends Base
$this->assertSame(0, $board[2]['columns'][3]['nb_tasks']);
$this->assertEquals('Task 8', $board[2]['columns'][2]['tasks'][0]['title']);
$this->assertArrayHasKey('is_draggable', $board[2]['columns'][2]['tasks'][0]);
}
public function testFormatWithoutDefaultSwimlane()

View File

@ -0,0 +1,94 @@
<?php
use Kanboard\Core\Security\Role;
use Kanboard\Helper\BoardHelper;
use Kanboard\Model\ColumnMoveRestrictionModel;
use Kanboard\Model\ProjectModel;
use Kanboard\Model\ProjectRoleModel;
use Kanboard\Model\ProjectUserRoleModel;
use Kanboard\Model\TaskCreationModel;
use Kanboard\Model\TaskFinderModel;
use Kanboard\Model\TaskStatusModel;
use Kanboard\Model\UserModel;
require_once __DIR__.'/../Base.php';
class BoardHelperTest extends Base
{
public function testIsDraggableWithProjectMember()
{
$boardHelper = new BoardHelper($this->container);
$projectModel = new ProjectModel($this->container);
$taskCreationModel = new TaskCreationModel($this->container);
$taskFinderModel = new TaskFinderModel($this->container);
$projectUserRole = new ProjectUserRoleModel($this->container);
$userModel = new UserModel($this->container);
$this->container['sessionStorage']->user = array(
'id' => 2,
'role' => Role::APP_USER,
);
$this->assertEquals(2, $userModel->create(array('username' => 'user')));
$this->assertEquals(1, $projectModel->create(array('name' => 'Test')));
$this->assertTrue($projectUserRole->addUser(1, 2, Role::PROJECT_MEMBER));
$this->assertEquals(1, $taskCreationModel->create(array('project_id' => 1, 'title' => 'test')));
$task = $taskFinderModel->getById(1);
$this->assertTrue($boardHelper->isDraggable($task));
}
public function testIsDraggableWithClosedTask()
{
$boardHelper = new BoardHelper($this->container);
$projectModel = new ProjectModel($this->container);
$taskCreationModel = new TaskCreationModel($this->container);
$taskFinderModel = new TaskFinderModel($this->container);
$taskStatusModel = new TaskStatusModel($this->container);
$projectUserRole = new ProjectUserRoleModel($this->container);
$userModel = new UserModel($this->container);
$this->container['sessionStorage']->user = array(
'id' => 2,
'role' => Role::APP_USER,
);
$this->assertEquals(2, $userModel->create(array('username' => 'user')));
$this->assertEquals(1, $projectModel->create(array('name' => 'Test')));
$this->assertTrue($projectUserRole->addUser(1, 2, Role::PROJECT_MEMBER));
$this->assertEquals(1, $taskCreationModel->create(array('project_id' => 1, 'title' => 'test')));
$this->assertTrue($taskStatusModel->close(1));
$task = $taskFinderModel->getById(1);
$this->assertFalse($boardHelper->isDraggable($task));
}
public function testIsDraggableWithColumnRestrictions()
{
$boardHelper = new BoardHelper($this->container);
$projectModel = new ProjectModel($this->container);
$taskCreationModel = new TaskCreationModel($this->container);
$taskFinderModel = new TaskFinderModel($this->container);
$projectUserRole = new ProjectUserRoleModel($this->container);
$userModel = new UserModel($this->container);
$projectRoleModel = new ProjectRoleModel($this->container);
$columnMoveRestrictionModel = new ColumnMoveRestrictionModel($this->container);
$this->container['sessionStorage']->user = array(
'id' => 2,
'role' => Role::APP_USER,
);
$this->assertEquals(2, $userModel->create(array('username' => 'user')));
$this->assertEquals(1, $projectModel->create(array('name' => 'Test')));
$this->assertEquals(1, $projectRoleModel->create(1, 'Custom Role'));
$this->assertEquals(1, $columnMoveRestrictionModel->create(1, 1, 2, 3));
$this->assertTrue($projectUserRole->addUser(1, 2, 'Custom Role'));
$this->assertEquals(1, $taskCreationModel->create(array('project_id' => 1, 'title' => 'test', 'column_id' => 2)));
$task = $taskFinderModel->getById(1);
$this->assertFalse($boardHelper->isDraggable($task));
}
}