Merge branch 'master' of next.github.com:nextcloud/deck into feature/update-card-modal-ui
This commit is contained in:
3
Makefile
3
Makefile
@@ -50,8 +50,7 @@ ifeq (, $(shell which phpunit 2> /dev/null))
|
||||
php $(build_tools_directory)/phpunit.phar -c tests/phpunit.xml --coverage-clover build/php-unit.coverage.xml
|
||||
php $(build_tools_directory)/phpunit.phar -c tests/phpunit.integration.xml --coverage-clover build/php-integration.coverage.xml
|
||||
else
|
||||
phpunit -c tests/phpunit.xml --coverage-clover build/php-unit.coverage.xml
|
||||
phpunit -c tests/phpunit.integration.xml --coverage-clover build/php-integration.coverage.xml
|
||||
phpunit -c tests/phpunit.integration.xml --testsuite=integration-database --coverage-clover build/php-integration.coverage.xml
|
||||
endif
|
||||
|
||||
test-integration:
|
||||
|
||||
@@ -44,6 +44,7 @@
|
||||
<commands>
|
||||
<command>OCA\Deck\Command\UserExport</command>
|
||||
<command>OCA\Deck\Command\BoardImport</command>
|
||||
<command>OCA\Deck\Command\TransferOwnership</command>
|
||||
</commands>
|
||||
<activity>
|
||||
<settings>
|
||||
|
||||
@@ -39,6 +39,7 @@ return [
|
||||
['name' => 'board#updateAcl', 'url' => '/boards/{boardId}/acl/{aclId}', 'verb' => 'PUT'],
|
||||
['name' => 'board#deleteAcl', 'url' => '/boards/{boardId}/acl/{aclId}', 'verb' => 'DELETE'],
|
||||
['name' => 'board#clone', 'url' => '/boards/{boardId}/clone', 'verb' => 'POST'],
|
||||
['name' => 'board#transferOwner', 'url' => '/boards/{boardId}/transferOwner', 'verb' => 'PUT'],
|
||||
|
||||
// stacks
|
||||
['name' => 'stack#index', 'url' => '/stacks/{boardId}', 'verb' => 'GET'],
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
},
|
||||
"require-dev": {
|
||||
"roave/security-advisories": "dev-master",
|
||||
"christophwurst/nextcloud": "^21@dev",
|
||||
"christophwurst/nextcloud": "dev-master",
|
||||
"phpunit/phpunit": "^9",
|
||||
"nextcloud/coding-standard": "^1.0.0",
|
||||
"symfony/event-dispatcher": "^4.0",
|
||||
|
||||
72
composer.lock
generated
72
composer.lock
generated
@@ -4,7 +4,7 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "c3c765fb5379719b5ab8824e9fbb03f9",
|
||||
"content-hash": "33c2fe0cccf29841e021001c6430310a",
|
||||
"packages": [
|
||||
{
|
||||
"name": "cogpowered/finediff",
|
||||
@@ -301,25 +301,29 @@
|
||||
},
|
||||
{
|
||||
"name": "christophwurst/nextcloud",
|
||||
"version": "v21.0.0",
|
||||
"version": "dev-master",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/ChristophWurst/nextcloud_composer.git",
|
||||
"reference": "41e1476b4aed5bce7371895054049eca353729c5"
|
||||
"reference": "cd35b7f4519d9b1c836443ec5dcd973d7f0f9cdd"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/ChristophWurst/nextcloud_composer/zipball/41e1476b4aed5bce7371895054049eca353729c5",
|
||||
"reference": "41e1476b4aed5bce7371895054049eca353729c5",
|
||||
"url": "https://api.github.com/repos/ChristophWurst/nextcloud_composer/zipball/cd35b7f4519d9b1c836443ec5dcd973d7f0f9cdd",
|
||||
"reference": "cd35b7f4519d9b1c836443ec5dcd973d7f0f9cdd",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.3 || ~8.0.0"
|
||||
"php": "^7.4 || ~8.0 || ~8.1",
|
||||
"psr/container": "^1.0",
|
||||
"psr/event-dispatcher": "^1.0",
|
||||
"psr/log": "^1.1"
|
||||
},
|
||||
"default-branch": true,
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "21.0.0-dev"
|
||||
"dev-master": "24.0.0-dev"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
@@ -335,9 +339,9 @@
|
||||
"description": "Composer package containing Nextcloud's public API (classes, interfaces)",
|
||||
"support": {
|
||||
"issues": "https://github.com/ChristophWurst/nextcloud_composer/issues",
|
||||
"source": "https://github.com/ChristophWurst/nextcloud_composer/tree/v21.0.0"
|
||||
"source": "https://github.com/ChristophWurst/nextcloud_composer/tree/master"
|
||||
},
|
||||
"time": "2021-03-01T08:42:25+00:00"
|
||||
"time": "2022-03-11T01:33:55+00:00"
|
||||
},
|
||||
{
|
||||
"name": "composer/package-versions-deprecated",
|
||||
@@ -2304,6 +2308,56 @@
|
||||
},
|
||||
"time": "2021-11-05T16:50:12+00:00"
|
||||
},
|
||||
{
|
||||
"name": "psr/event-dispatcher",
|
||||
"version": "1.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/php-fig/event-dispatcher.git",
|
||||
"reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/php-fig/event-dispatcher/zipball/dbefd12671e8a14ec7f180cab83036ed26714bb0",
|
||||
"reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=7.2.0"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.0.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Psr\\EventDispatcher\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "PHP-FIG",
|
||||
"homepage": "http://www.php-fig.org/"
|
||||
}
|
||||
],
|
||||
"description": "Standard interfaces for event handling.",
|
||||
"keywords": [
|
||||
"events",
|
||||
"psr",
|
||||
"psr-14"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/php-fig/event-dispatcher/issues",
|
||||
"source": "https://github.com/php-fig/event-dispatcher/tree/1.0.0"
|
||||
},
|
||||
"time": "2019-01-08T18:20:26+00:00"
|
||||
},
|
||||
{
|
||||
"name": "psr/log",
|
||||
"version": "1.1.4",
|
||||
|
||||
@@ -16,6 +16,7 @@ Overall, Deck is easy to use. You can create boards, add users, share the Deck,
|
||||
5. [Manage your board](#5-manage-your-board)
|
||||
6. [Import boards](#6-import-boards)
|
||||
7. [Search](#7-search)
|
||||
8. [New owner for the deck entities](#8-new-owner-for-the-deck-entities)
|
||||
|
||||
### 1. Create my first board
|
||||
In this example, we're going to create a board and share it with an other nextcloud user.
|
||||
@@ -158,4 +159,22 @@ For example the search `project tag:ToDo assigned:alice assigned:bob` will retur
|
||||
|
||||
Other text tokens will be used to perform a case-insensitive search on the card title and description
|
||||
|
||||
In addition wuotes can be used to pass a query with spaces, e.g. `"Exact match with spaces"` or `title:"My card"`.
|
||||
In addition, quotes can be used to pass a query with spaces, e.g. `"Exact match with spaces"` or `title:"My card"`.
|
||||
|
||||
### 8. New owner for the deck entities
|
||||
You can transfer ownership of boards, cards, etc to a new user, using `occ` command `deck:transfer-ownership`
|
||||
|
||||
```bash
|
||||
php occ deck:transfer-ownership previousOwner newOwner
|
||||
```
|
||||
|
||||
The transfer will preserve card details linked to the old owner, which can also be remapped by using the `--remap` option on the occ command.
|
||||
```bash
|
||||
php occ deck:transfer-ownership --remap previousOwner newOwner
|
||||
```
|
||||
|
||||
Individual boards can be transferred by adding the id of the board to the command:
|
||||
|
||||
```bash
|
||||
php occ deck:transfer-ownership previousOwner newOwner 123
|
||||
```
|
||||
|
||||
@@ -31,7 +31,6 @@ use OCA\Deck\Db\Acl;
|
||||
use OCA\Deck\Db\AclMapper;
|
||||
use OCA\Deck\Db\Assignment;
|
||||
use OCA\Deck\Db\Attachment;
|
||||
use OCA\Deck\Db\AttachmentMapper;
|
||||
use OCA\Deck\Db\Board;
|
||||
use OCA\Deck\Db\BoardMapper;
|
||||
use OCA\Deck\Db\Card;
|
||||
@@ -50,12 +49,15 @@ use OCP\L10N\IFactory;
|
||||
|
||||
class ActivityManager {
|
||||
public const DECK_NOAUTHOR_COMMENT_SYSTEM_ENFORCED = 'DECK_NOAUTHOR_COMMENT_SYSTEM_ENFORCED';
|
||||
|
||||
public const SUBJECT_PARAMS_MAX_LENGTH = 4000;
|
||||
public const SHORTENED_DESCRIPTION_MAX_LENGTH = 2000;
|
||||
|
||||
private $manager;
|
||||
private $userId;
|
||||
private $permissionService;
|
||||
private $boardMapper;
|
||||
private $cardMapper;
|
||||
private $attachmentMapper;
|
||||
private $aclMapper;
|
||||
private $stackMapper;
|
||||
private $l10nFactory;
|
||||
@@ -110,7 +112,6 @@ class ActivityManager {
|
||||
BoardMapper $boardMapper,
|
||||
CardMapper $cardMapper,
|
||||
StackMapper $stackMapper,
|
||||
AttachmentMapper $attachmentMapper,
|
||||
AclMapper $aclMapper,
|
||||
IFactory $l10nFactory,
|
||||
$userId
|
||||
@@ -120,7 +121,6 @@ class ActivityManager {
|
||||
$this->boardMapper = $boardMapper;
|
||||
$this->cardMapper = $cardMapper;
|
||||
$this->stackMapper = $stackMapper;
|
||||
$this->attachmentMapper = $attachmentMapper;
|
||||
$this->aclMapper = $aclMapper;
|
||||
$this->l10nFactory = $l10nFactory;
|
||||
$this->userId = $userId;
|
||||
@@ -249,19 +249,6 @@ class ActivityManager {
|
||||
try {
|
||||
$event = $this->createEvent($objectType, $entity, $subject, $additionalParams, $author);
|
||||
if ($event !== null) {
|
||||
$json = json_encode($event->getSubjectParameters());
|
||||
if (mb_strlen($json) > 4000) {
|
||||
$params = json_decode(json_encode($event->getSubjectParameters()), true);
|
||||
|
||||
$newContent = $params['after'];
|
||||
unset($params['before'], $params['after'], $params['card']['description']);
|
||||
|
||||
$params['after'] = mb_substr($newContent, 0, 2000);
|
||||
if (mb_strlen($newContent) > 2000) {
|
||||
$params['after'] .= '...';
|
||||
}
|
||||
$event->setSubject($event->getSubject(), $params);
|
||||
}
|
||||
$this->sendToUsers($event);
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
@@ -410,12 +397,31 @@ class ActivityManager {
|
||||
|
||||
$subjectParams['author'] = $author === null ? $this->userId : $author;
|
||||
|
||||
$subjectParams = array_merge($subjectParams, $additionalParams);
|
||||
$json = json_encode($subjectParams);
|
||||
if (mb_strlen($json) > self::SUBJECT_PARAMS_MAX_LENGTH) {
|
||||
$params = json_decode(json_encode($subjectParams), true);
|
||||
|
||||
if ($subject === self::SUBJECT_CARD_UPDATE_DESCRIPTION && isset($params['after'])) {
|
||||
$newContent = $params['after'];
|
||||
unset($params['before'], $params['after'], $params['card']['description']);
|
||||
|
||||
$params['after'] = mb_substr($newContent, 0, self::SHORTENED_DESCRIPTION_MAX_LENGTH);
|
||||
if (mb_strlen($newContent) > self::SHORTENED_DESCRIPTION_MAX_LENGTH) {
|
||||
$params['after'] .= '...';
|
||||
}
|
||||
$subjectParams = $params;
|
||||
} else {
|
||||
throw new \Exception('Subject parameters too long');
|
||||
}
|
||||
}
|
||||
|
||||
$event = $this->manager->generateEvent();
|
||||
$event->setApp('deck')
|
||||
->setType($eventType)
|
||||
->setAuthor($subjectParams['author'])
|
||||
->setObject($objectType, (int)$object->getId(), $object->getTitle())
|
||||
->setSubject($subject, array_merge($subjectParams, $additionalParams))
|
||||
->setSubject($subject, $subjectParams)
|
||||
->setTimestamp(time());
|
||||
|
||||
if ($message !== null) {
|
||||
|
||||
105
lib/Command/TransferOwnership.php
Normal file
105
lib/Command/TransferOwnership.php
Normal file
@@ -0,0 +1,105 @@
|
||||
<?php
|
||||
|
||||
namespace OCA\Deck\Command;
|
||||
|
||||
use OCA\Deck\Db\BoardMapper;
|
||||
use OCA\Deck\Service\BoardService;
|
||||
use OCA\Deck\Service\PermissionService;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Helper\QuestionHelper;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Question\ConfirmationQuestion;
|
||||
|
||||
final class TransferOwnership extends Command {
|
||||
protected $boardService;
|
||||
protected $boardMapper;
|
||||
protected $permissionService;
|
||||
protected $questionHelper;
|
||||
|
||||
public function __construct(BoardService $boardService, BoardMapper $boardMapper, PermissionService $permissionService, QuestionHelper $questionHelper) {
|
||||
parent::__construct();
|
||||
|
||||
$this->boardService = $boardService;
|
||||
$this->boardMapper = $boardMapper;
|
||||
$this->permissionService = $permissionService;
|
||||
$this->questionHelper = $questionHelper;
|
||||
}
|
||||
|
||||
protected function configure() {
|
||||
$this
|
||||
->setName('deck:transfer-ownership')
|
||||
->setDescription('Change owner of deck boards')
|
||||
->addArgument(
|
||||
'owner',
|
||||
InputArgument::REQUIRED,
|
||||
'Owner uid'
|
||||
)
|
||||
->addArgument(
|
||||
'newOwner',
|
||||
InputArgument::REQUIRED,
|
||||
'New owner uid'
|
||||
)
|
||||
->addArgument(
|
||||
'boardId',
|
||||
InputArgument::OPTIONAL,
|
||||
'Single board ID'
|
||||
)
|
||||
->addOption(
|
||||
'remap',
|
||||
'r',
|
||||
InputOption::VALUE_NONE,
|
||||
'Reassign card details of the old owner to the new one'
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int {
|
||||
$owner = $input->getArgument('owner');
|
||||
$newOwner = $input->getArgument('newOwner');
|
||||
$boardId = $input->getArgument('boardId');
|
||||
|
||||
$remapAssignment = $input->getOption('remap');
|
||||
|
||||
$this->boardService->setUserId($owner);
|
||||
$this->permissionService->setUserId($owner);
|
||||
|
||||
try {
|
||||
$board = $boardId ? $this->boardMapper->find($boardId) : null;
|
||||
} catch (\Exception $e) {
|
||||
$output->writeln("Could not find a board for the provided id.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ($boardId !== null && $board->getOwner() !== $owner) {
|
||||
$output->writeln("$owner is not the owner of the board $boardId (" . $board->getTitle() . ")");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ($boardId) {
|
||||
$output->writeln("Transfer board " . $board->getTitle() . " from ". $board->getOwner() ." to $newOwner");
|
||||
} else {
|
||||
$output->writeln("Transfer all boards from $owner to $newOwner");
|
||||
}
|
||||
|
||||
$question = new ConfirmationQuestion('Do you really want to continue? (y/n) ', false);
|
||||
if (!$this->questionHelper->ask($input, $output, $question)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ($boardId) {
|
||||
$this->boardService->transferBoardOwnership($boardId, $newOwner, $remapAssignment);
|
||||
$output->writeln("<info>Board " . $board->getTitle() . " from ". $board->getOwner() ." transferred to $newOwner completed</info>");
|
||||
return 0;
|
||||
}
|
||||
|
||||
foreach ($this->boardService->transferOwnership($owner, $newOwner, $remapAssignment) as $board) {
|
||||
$output->writeln(" - " . $board->getTitle() . " transferred");
|
||||
}
|
||||
$output->writeln("<info>All boards from $owner to $newOwner transferred</info>");
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -24,9 +24,12 @@
|
||||
namespace OCA\Deck\Controller;
|
||||
|
||||
use OCA\Deck\Db\Acl;
|
||||
use OCA\Deck\Db\Board;
|
||||
use OCA\Deck\Service\BoardService;
|
||||
use OCA\Deck\Service\PermissionService;
|
||||
use OCP\AppFramework\ApiController;
|
||||
use OCP\AppFramework\Http;
|
||||
use OCP\AppFramework\Http\DataResponse;
|
||||
use OCP\IRequest;
|
||||
|
||||
class BoardController extends ApiController {
|
||||
@@ -150,9 +153,20 @@ class BoardController extends ApiController {
|
||||
/**
|
||||
* @NoAdminRequired
|
||||
* @param $boardId
|
||||
* @return \OCP\Deck\DB\Board
|
||||
* @return Board
|
||||
*/
|
||||
public function clone($boardId) {
|
||||
return $this->boardService->clone($boardId, $this->userId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @NoAdminRequired
|
||||
*/
|
||||
public function transferOwner(int $boardId, string $newOwner): DataResponse {
|
||||
if ($this->permissionService->userIsBoardOwner($boardId, $this->userId)) {
|
||||
return new DataResponse($this->boardService->transferBoardOwnership($boardId, $newOwner), HTTP::STATUS_OK);
|
||||
}
|
||||
|
||||
return new DataResponse([], HTTP::STATUS_UNAUTHORIZED);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ namespace OCA\Deck\Db;
|
||||
|
||||
use OCP\AppFramework\Db\DoesNotExistException;
|
||||
use OCP\AppFramework\Db\MultipleObjectsReturnedException;
|
||||
use OCP\DB\QueryBuilder\IQueryBuilder;
|
||||
use OCP\IDBConnection;
|
||||
|
||||
class AclMapper extends DeckMapper implements IPermissionMapper {
|
||||
@@ -57,4 +58,16 @@ class AclMapper extends DeckMapper implements IPermissionMapper {
|
||||
$sql = 'SELECT * from *PREFIX*deck_board_acl WHERE type = ? AND participant = ?';
|
||||
return $this->findEntities($sql, [$type, $participant]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \OCP\DB\Exception
|
||||
*/
|
||||
public function deleteParticipantFromBoard(int $boardId, int $type, string $participant): void {
|
||||
$qb = $this->db->getQueryBuilder();
|
||||
$qb->delete('deck_board_acl')
|
||||
->where($qb->expr()->eq('type', $qb->createNamedParameter($type, IQueryBuilder::PARAM_INT)))
|
||||
->andWhere($qb->expr()->eq('participant', $qb->createNamedParameter($participant, IQueryBuilder::PARAM_STR)))
|
||||
->andWhere($qb->expr()->eq('board_id', $qb->createNamedParameter($boardId, IQueryBuilder::PARAM_INT)));
|
||||
$qb->executeStatement();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ use OCA\Deck\NotFoundException;
|
||||
use OCA\Deck\Service\CirclesService;
|
||||
use OCP\AppFramework\Db\Entity;
|
||||
use OCP\AppFramework\Db\QBMapper;
|
||||
use OCP\DB\QueryBuilder\IQueryBuilder;
|
||||
use OCP\IDBConnection;
|
||||
use OCP\IGroupManager;
|
||||
use OCP\IUserManager;
|
||||
@@ -146,4 +147,39 @@ class AssignmentMapper extends QBMapper implements IPermissionMapper {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public function remapAssignedUser(int $boardId, string $userId, string $newUserId): void {
|
||||
$subQuery = $this->db->getQueryBuilder();
|
||||
$subQuery->selectAlias('a.id', 'id')
|
||||
->from('deck_assigned_users', 'a')
|
||||
->innerJoin('a', 'deck_cards', 'c', 'c.id = a.card_id')
|
||||
->innerJoin('c', 'deck_stacks', 's', 's.id = c.stack_id')
|
||||
->where($subQuery->expr()->eq('a.type', $subQuery->createNamedParameter(Assignment::TYPE_USER, IQueryBuilder::PARAM_INT)))
|
||||
->andWhere($subQuery->expr()->eq('a.participant', $subQuery->createNamedParameter($userId, IQueryBuilder::PARAM_STR)))
|
||||
->andWhere($subQuery->expr()->eq('s.board_id', $subQuery->createNamedParameter($boardId, IQueryBuilder::PARAM_INT)))
|
||||
->setMaxResults(1000);
|
||||
|
||||
$qb = $this->db->getQueryBuilder();
|
||||
$qb->update('deck_assigned_users')
|
||||
->set('participant', $qb->createParameter('participant'))
|
||||
->where($qb->expr()->in('id', $qb->createParameter('ids')));
|
||||
|
||||
$moreResults = true;
|
||||
do {
|
||||
$result = $subQuery->executeQuery();
|
||||
$ids = array_map(function ($item) {
|
||||
return $item['id'];
|
||||
}, $result->fetchAll());
|
||||
|
||||
if (count($ids) === 0 || $result->rowCount() === 0) {
|
||||
$moreResults = false;
|
||||
}
|
||||
|
||||
$qb->setParameter('participant', $newUserId, IQueryBuilder::PARAM_STR);
|
||||
$qb->setParameter('ids', $ids, IQueryBuilder::PARAM_INT_ARRAY);
|
||||
$qb->executeStatement();
|
||||
} while ($moreResults === true);
|
||||
|
||||
$result->closeCursor();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -475,4 +475,34 @@ class BoardMapper extends QBMapper implements IPermissionMapper {
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \OCP\DB\Exception
|
||||
*/
|
||||
public function transferOwnership(string $ownerId, string $newOwnerId, $boardId = null): void {
|
||||
$qb = $this->db->getQueryBuilder();
|
||||
$qb->update('deck_boards')
|
||||
->set('owner', $qb->createNamedParameter($newOwnerId, IQueryBuilder::PARAM_STR))
|
||||
->where($qb->expr()->eq('owner', $qb->createNamedParameter($ownerId, IQueryBuilder::PARAM_STR)));
|
||||
if ($boardId !== null) {
|
||||
$qb->andWhere($qb->expr()->eq('id', $qb->createNamedParameter($boardId, IQueryBuilder::PARAM_INT)));
|
||||
}
|
||||
$qb->executeStatement();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset cache for a given board or a given user
|
||||
*/
|
||||
public function flushCache(?int $boardId = null, ?string $userId = null) {
|
||||
if ($boardId) {
|
||||
unset($this->boardCache[$boardId]);
|
||||
} else {
|
||||
$this->boardCache = null;
|
||||
}
|
||||
if ($userId) {
|
||||
unset($this->userBoardCache[$userId]);
|
||||
} else {
|
||||
$this->userBoardCache = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -586,4 +586,47 @@ class CardMapper extends QBMapper implements IPermissionMapper {
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
public function transferOwnership(string $ownerId, string $newOwnerId, int $boardId = null): void {
|
||||
$params = [
|
||||
'owner' => $ownerId,
|
||||
'newOwner' => $newOwnerId
|
||||
];
|
||||
$sql = "UPDATE `*PREFIX*{$this->tableName}` SET `owner` = :newOwner WHERE `owner` = :owner";
|
||||
$stmt = $this->db->executeQuery($sql, $params);
|
||||
$stmt->closeCursor();
|
||||
}
|
||||
|
||||
public function remapCardOwner(int $boardId, string $userId, string $newUserId): void {
|
||||
$subQuery = $this->db->getQueryBuilder();
|
||||
$subQuery->selectAlias('c.id', 'id')
|
||||
->from('deck_cards', 'c')
|
||||
->innerJoin('c', 'deck_stacks', 's', 's.id = c.stack_id')
|
||||
->where($subQuery->expr()->eq('c.owner', $subQuery->createNamedParameter($userId, IQueryBuilder::PARAM_STR)))
|
||||
->andWhere($subQuery->expr()->eq('s.board_id', $subQuery->createNamedParameter($boardId, IQueryBuilder::PARAM_INT)))
|
||||
->setMaxResults(1000);
|
||||
|
||||
$qb = $this->db->getQueryBuilder();
|
||||
$qb->update('deck_cards')
|
||||
->set('owner', $qb->createParameter('owner'))
|
||||
->where($qb->expr()->in('id', $qb->createParameter('ids')));
|
||||
|
||||
$moreResults = true;
|
||||
do {
|
||||
$result = $subQuery->executeQuery();
|
||||
$ids = array_map(function ($item) {
|
||||
return $item['id'];
|
||||
}, $result->fetchAll());
|
||||
|
||||
if (count($ids) === 0 || $result->rowCount() === 0) {
|
||||
$moreResults = false;
|
||||
}
|
||||
|
||||
$qb->setParameter('owner', $newUserId, IQueryBuilder::PARAM_STR);
|
||||
$qb->setParameter('ids', $ids, IQueryBuilder::PARAM_INT_ARRAY);
|
||||
$qb->executeStatement();
|
||||
} while ($moreResults === true);
|
||||
|
||||
$result->closeCursor();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,12 +24,14 @@
|
||||
|
||||
namespace OCA\Deck\Service;
|
||||
|
||||
use Doctrine\DBAL\Exception\UniqueConstraintViolationException;
|
||||
use OCA\Deck\Activity\ActivityManager;
|
||||
use OCA\Deck\Activity\ChangeSet;
|
||||
use OCA\Deck\AppInfo\Application;
|
||||
use OCA\Deck\Db\Acl;
|
||||
use OCA\Deck\Db\AclMapper;
|
||||
use OCA\Deck\Db\AssignmentMapper;
|
||||
use OCA\Deck\Db\CardMapper;
|
||||
use OCA\Deck\Db\ChangeHelper;
|
||||
use OCA\Deck\Db\IPermissionMapper;
|
||||
use OCA\Deck\Db\Label;
|
||||
@@ -69,6 +71,8 @@ class BoardService {
|
||||
private $activityManager;
|
||||
private $eventDispatcher;
|
||||
private $changeHelper;
|
||||
private $cardMapper;
|
||||
|
||||
private $boardsCache = null;
|
||||
private $urlGenerator;
|
||||
|
||||
@@ -83,6 +87,7 @@ class BoardService {
|
||||
PermissionService $permissionService,
|
||||
NotificationHelper $notificationHelper,
|
||||
AssignmentMapper $assignedUsersMapper,
|
||||
CardMapper $cardMapper,
|
||||
IUserManager $userManager,
|
||||
IGroupManager $groupManager,
|
||||
ActivityManager $activityManager,
|
||||
@@ -107,6 +112,7 @@ class BoardService {
|
||||
$this->changeHelper = $changeHelper;
|
||||
$this->userId = $userId;
|
||||
$this->urlGenerator = $urlGenerator;
|
||||
$this->cardMapper = $cardMapper;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -518,11 +524,14 @@ class BoardService {
|
||||
$acl->setPermissionManage($manage);
|
||||
$newAcl = $this->aclMapper->insert($acl);
|
||||
|
||||
$this->activityManager->triggerEvent(ActivityManager::DECK_OBJECT_BOARD, $newAcl, ActivityManager::SUBJECT_BOARD_SHARE);
|
||||
$this->activityManager->triggerEvent(ActivityManager::DECK_OBJECT_BOARD, $newAcl, ActivityManager::SUBJECT_BOARD_SHARE, [], $this->userId);
|
||||
$this->notificationHelper->sendBoardShared((int)$boardId, $acl);
|
||||
$this->boardMapper->mapAcl($newAcl);
|
||||
$this->changeHelper->boardChanged($boardId);
|
||||
|
||||
$board = $this->boardMapper->find($boardId);
|
||||
$this->clearBoardFromCache($board);
|
||||
|
||||
// TODO: use the dispatched event for this
|
||||
try {
|
||||
$resourceProvider = \OC::$server->query(\OCA\Deck\Collaboration\Resources\ResourceProvider::class);
|
||||
@@ -673,6 +682,43 @@ class BoardService {
|
||||
return $newBoard;
|
||||
}
|
||||
|
||||
public function transferBoardOwnership(int $boardId, string $newOwner, bool $changeContent = false): Board {
|
||||
\OC::$server->getDatabaseConnection()->beginTransaction();
|
||||
try {
|
||||
$board = $this->boardMapper->find($boardId);
|
||||
$previousOwner = $board->getOwner();
|
||||
$this->clearBoardFromCache($board);
|
||||
$this->aclMapper->deleteParticipantFromBoard($boardId, Acl::PERMISSION_TYPE_USER, $newOwner);
|
||||
if (!$changeContent) {
|
||||
try {
|
||||
$this->addAcl($boardId, Acl::PERMISSION_TYPE_USER, $previousOwner, true, true, true);
|
||||
} catch (UniqueConstraintViolationException $e) {
|
||||
}
|
||||
}
|
||||
$this->boardMapper->transferOwnership($previousOwner, $newOwner, $boardId);
|
||||
|
||||
// Optionally also change user assignments and card owner information
|
||||
if ($changeContent) {
|
||||
$this->assignedUsersMapper->remapAssignedUser($boardId, $previousOwner, $newOwner);
|
||||
$this->cardMapper->remapCardOwner($boardId, $previousOwner, $newOwner);
|
||||
}
|
||||
\OC::$server->getDatabaseConnection()->commit();
|
||||
return $this->boardMapper->find($boardId);
|
||||
} catch (\Throwable $e) {
|
||||
\OC::$server->getDatabaseConnection()->rollBack();
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
public function transferOwnership(string $owner, string $newOwner, bool $changeContent = false): \Generator {
|
||||
$boards = $this->boardMapper->findAllByUser($owner);
|
||||
foreach ($boards as $board) {
|
||||
if ($board->getOwner() === $owner) {
|
||||
yield $this->transferBoardOwnership($board->getId(), $newOwner, $changeContent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function enrichWithStacks($board, $since = -1) {
|
||||
$stacks = $this->stackMapper->findAll($board->getId(), null, null, $since);
|
||||
|
||||
@@ -704,4 +750,19 @@ class BoardService {
|
||||
public function getBoardUrl($endpoint) {
|
||||
return $this->urlGenerator->linkToRouteAbsolute('deck.page.index') . '#' . $endpoint;
|
||||
}
|
||||
|
||||
private function clearBoardsCache() {
|
||||
$this->boardsCache = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean a given board data from the Cache
|
||||
*/
|
||||
private function clearBoardFromCache(Board $board) {
|
||||
$boardId = $board->getId();
|
||||
$boardOwnerId = $board->getOwner();
|
||||
|
||||
$this->boardMapper->flushCache($boardId, $boardOwnerId);
|
||||
unset($this->boardsCache[$boardId]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -241,6 +241,7 @@ class PermissionService {
|
||||
if (array_key_exists((string) $boardId, $this->users) && !$refresh) {
|
||||
return $this->users[(string) $boardId];
|
||||
}
|
||||
|
||||
try {
|
||||
$board = $this->boardMapper->find($boardId);
|
||||
} catch (DoesNotExistException $e) {
|
||||
@@ -332,4 +333,13 @@ class PermissionService {
|
||||
}
|
||||
return $groups;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a different user than the current one, e.g. when no user is available in occ
|
||||
*
|
||||
* @param string $userId
|
||||
*/
|
||||
public function setUserId(string $userId): void {
|
||||
$this->userId = $userId;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,6 +77,7 @@ import Controls from '../Controls'
|
||||
import Stack from './Stack'
|
||||
import { EmptyContent } from '@nextcloud/vue'
|
||||
import GlobalSearchResults from '../search/GlobalSearchResults'
|
||||
import { showError } from '../../helpers/errors'
|
||||
|
||||
export default {
|
||||
name: 'Board',
|
||||
@@ -139,6 +140,7 @@ export default {
|
||||
await this.$store.dispatch('loadStacks', this.id)
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
showError(e)
|
||||
}
|
||||
this.loading = false
|
||||
},
|
||||
|
||||
@@ -53,6 +53,9 @@
|
||||
<ActionCheckbox v-if="canManage" :checked="acl.permissionManage" @change="clickManageAcl(acl)">
|
||||
{{ t('deck', 'Can manage') }}
|
||||
</ActionCheckbox>
|
||||
<ActionCheckbox v-if="acl.type === 0 && isCurrentUser(board.owner.uid)" :checked="acl.owner" @change="clickTransferOwner(acl.participant.uid)">
|
||||
{{ t('deck', 'Owner') }}
|
||||
</ActionCheckbox>
|
||||
<ActionButton v-if="canManage" icon="icon-delete" @click="clickDeleteAcl(acl)">
|
||||
{{ t('deck', 'Delete') }}
|
||||
</ActionButton>
|
||||
@@ -72,7 +75,7 @@ import { Avatar, Multiselect, Actions, ActionButton, ActionCheckbox } from '@nex
|
||||
import { CollectionList } from 'nextcloud-vue-collections'
|
||||
import { mapGetters, mapState } from 'vuex'
|
||||
import { getCurrentUser } from '@nextcloud/auth'
|
||||
import { showError } from '@nextcloud/dialogs'
|
||||
import { showError, showSuccess } from '@nextcloud/dialogs'
|
||||
import debounce from 'lodash/debounce'
|
||||
|
||||
export default {
|
||||
@@ -97,6 +100,7 @@ export default {
|
||||
isSearching: false,
|
||||
addAcl: null,
|
||||
addAclForAPI: null,
|
||||
newOwner: null,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@@ -194,6 +198,38 @@ export default {
|
||||
clickDeleteAcl(acl) {
|
||||
this.$store.dispatch('deleteAclFromCurrentBoard', acl)
|
||||
},
|
||||
clickTransferOwner(newOwner) {
|
||||
OC.dialogs.confirmDestructive(
|
||||
t('deck', 'Are you sure you want to transfer the board {title} for {user}?', { title: this.board.title, user: newOwner }),
|
||||
t('deck', 'Transfer the board.'),
|
||||
{
|
||||
type: OC.dialogs.YES_NO_BUTTONS,
|
||||
confirm: t('deck', 'Transfer'),
|
||||
confirmClasses: 'error',
|
||||
cancel: t('deck', 'Cancel'),
|
||||
},
|
||||
async (result) => {
|
||||
if (result) {
|
||||
try {
|
||||
this.isLoading = true
|
||||
await this.$store.dispatch('transferOwnership', {
|
||||
boardId: this.board.id,
|
||||
newOwner
|
||||
})
|
||||
const successMessage = t('deck', 'Transfer the board for {user} successfully', { user: newOwner })
|
||||
showSuccess(successMessage)
|
||||
this.$router.push({ name: 'main' })
|
||||
} catch (e) {
|
||||
const errorMessage = t('deck', 'Failed to transfer the board for {user}', { user: newOwner.user })
|
||||
showError(errorMessage)
|
||||
} finally {
|
||||
this.isLoading = false
|
||||
}
|
||||
}
|
||||
},
|
||||
true
|
||||
)
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -78,7 +78,7 @@ export default {
|
||||
},
|
||||
computed: {
|
||||
boardsSorted() {
|
||||
return [...this.boards].sort((a, b) => (a.title < b.title) ? -1 : 1)
|
||||
return [...this.boards].sort((a, b) => a.title.localeCompare(b.title))
|
||||
},
|
||||
collapsible() {
|
||||
return this.boards.length > 0
|
||||
|
||||
27
src/helpers/errors.js
Normal file
27
src/helpers/errors.js
Normal file
@@ -0,0 +1,27 @@
|
||||
import { showError as errorDialog } from '@nextcloud/dialogs'
|
||||
|
||||
const showAxiosError = err => {
|
||||
const response = err?.response || {}
|
||||
const message = response?.data.message
|
||||
|
||||
if (message) {
|
||||
errorDialog(message)
|
||||
return
|
||||
}
|
||||
|
||||
errorDialog(err.message)
|
||||
}
|
||||
|
||||
const showError = err => {
|
||||
// axios error
|
||||
if (err.response) {
|
||||
showAxiosError(err)
|
||||
return
|
||||
}
|
||||
|
||||
errorDialog(err.message)
|
||||
}
|
||||
|
||||
export {
|
||||
showError,
|
||||
}
|
||||
@@ -26,7 +26,7 @@ import { loadState } from '@nextcloud/initial-state'
|
||||
import Vue from 'vue'
|
||||
import Vuex from 'vuex'
|
||||
import axios from '@nextcloud/axios'
|
||||
import { generateOcsUrl } from '@nextcloud/router'
|
||||
import { generateOcsUrl, generateUrl } from '@nextcloud/router'
|
||||
import { BoardApi } from '../services/BoardApi'
|
||||
import actions from './actions'
|
||||
import stack from './stack'
|
||||
@@ -486,5 +486,11 @@ export default new Vuex.Store({
|
||||
dispatch('loadBoardById', acl.boardId)
|
||||
})
|
||||
},
|
||||
async transferOwnership({ commit }, { boardId, owner, newOwner }) {
|
||||
await axios.put(generateUrl(`apps/deck/boards/${boardId}/transferOwner`), {
|
||||
owner,
|
||||
newOwner,
|
||||
})
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
314
tests/integration/database/TransferOwnershipTest.php
Normal file
314
tests/integration/database/TransferOwnershipTest.php
Normal file
@@ -0,0 +1,314 @@
|
||||
<?php
|
||||
|
||||
namespace OCA\Deck\Service;
|
||||
|
||||
use OCA\Deck\Db\Acl;
|
||||
use OCA\Deck\Db\Assignment;
|
||||
use OCA\Deck\Db\AssignmentMapper;
|
||||
use OCA\Deck\Db\Board;
|
||||
use OCA\Deck\Db\Card;
|
||||
|
||||
/**
|
||||
* @group DB
|
||||
* @coversDefaultClass \OCA\Deck\Service\BoardService
|
||||
*/
|
||||
class TransferOwnershipTest extends \Test\TestCase {
|
||||
private const TEST_USER_1 = 'test-share-user1';
|
||||
private const TEST_USER_2 = 'test-user2';
|
||||
private const TEST_USER_3 = 'test-user3';
|
||||
private const TEST_GROUP = 'test-share-user1';
|
||||
|
||||
/** @var BoardService */
|
||||
protected $boardService;
|
||||
/** @var CardService */
|
||||
protected $cardService;
|
||||
/** @var StackService */
|
||||
protected $stackService;
|
||||
/** @var AssignmentMapper */
|
||||
protected $assignmentMapper;
|
||||
/** @var AssignmentService */
|
||||
private $assignmentService;
|
||||
/** @var Board */
|
||||
private $board;
|
||||
private $cards;
|
||||
private $stacks;
|
||||
|
||||
public static function setUpBeforeClass(): void {
|
||||
parent::setUpBeforeClass();
|
||||
|
||||
$backend = new \Test\Util\User\Dummy();
|
||||
\OC_User::useBackend($backend);
|
||||
\OC::$server->getUserManager()->registerBackend($backend);
|
||||
$backend->createUser(self::TEST_USER_1, self::TEST_USER_1);
|
||||
$backend->createUser(self::TEST_USER_2, self::TEST_USER_2);
|
||||
$backend->createUser(self::TEST_USER_3, self::TEST_USER_3);
|
||||
// create group
|
||||
$groupBackend = new \Test\Util\Group\Dummy();
|
||||
$groupBackend->createGroup(self::TEST_GROUP);
|
||||
$groupBackend->addToGroup(self::TEST_USER_1, self::TEST_GROUP);
|
||||
\OC::$server->getGroupManager()->addBackend($groupBackend);
|
||||
}
|
||||
|
||||
public function setUp(): void {
|
||||
parent::setUp();
|
||||
\OC::$server->getUserSession()->login(self::TEST_USER_1, self::TEST_USER_1);
|
||||
$this->boardService = \OC::$server->query(BoardService::class);
|
||||
$this->stackService = \OC::$server->query(StackService::class);
|
||||
$this->cardService = \OC::$server->query(CardService::class);
|
||||
$this->assignmentService = \OC::$server->query(AssignmentService::class);
|
||||
$this->assignmentMapper = \OC::$server->query(AssignmentMapper::class);
|
||||
$this->createBoardWithExampleData();
|
||||
}
|
||||
|
||||
public function createBoardWithExampleData() {
|
||||
$stacks = [];
|
||||
$board = $this->boardService->create('Test', self::TEST_USER_1, '000000');
|
||||
$id = $board->getId();
|
||||
$this->boardService->addAcl($id, Acl::PERMISSION_TYPE_GROUP, self::TEST_GROUP, true, true, true);
|
||||
$this->boardService->addAcl($id, Acl::PERMISSION_TYPE_USER, self::TEST_USER_3, false, true, false);
|
||||
$stacks[] = $this->stackService->create('Stack A', $id, 1);
|
||||
$stacks[] = $this->stackService->create('Stack B', $id, 1);
|
||||
$stacks[] = $this->stackService->create('Stack C', $id, 1);
|
||||
$cards[] = $this->cardService->create('Card 1', $stacks[0]->getId(), 'text', 0, self::TEST_USER_1);
|
||||
$cards[] = $this->cardService->create('Card 2', $stacks[0]->getId(), 'text', 0, self::TEST_USER_1);
|
||||
$this->assignmentService->assignUser($cards[0]->getId(), self::TEST_USER_1);
|
||||
$this->board = $board;
|
||||
$this->cards = $cards;
|
||||
$this->stacks = $stacks;
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::transferOwnership
|
||||
*/
|
||||
public function testTransferBoardOwnership() {
|
||||
iterator_to_array($this->boardService->transferOwnership(self::TEST_USER_1, self::TEST_USER_2));
|
||||
$board = $this->boardService->find($this->board->getId());
|
||||
$boardOwner = $board->getOwner();
|
||||
$this->assertEquals(self::TEST_USER_2, $boardOwner);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::transferOwnership
|
||||
*/
|
||||
public function testTransferBoardOwnershipWithData() {
|
||||
iterator_to_array($this->boardService->transferOwnership(self::TEST_USER_1, self::TEST_USER_2));
|
||||
$board = $this->boardService->find($this->board->getId());
|
||||
|
||||
$boardOwner = $board->getOwner();
|
||||
$this->assertEquals(self::TEST_USER_2, $boardOwner);
|
||||
|
||||
$cards = $this->cards;
|
||||
$newOwnerOwnsTheCards = (bool)array_product(array_filter($cards, function (Card $card) {
|
||||
$cardUpdated = $this->cardService->find($card->getId());
|
||||
return $cardUpdated->getOwner() === self::TEST_USER_2;
|
||||
}));
|
||||
$this->assertTrue($newOwnerOwnsTheCards);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::transferOwnership
|
||||
*/
|
||||
public function testTransferACLOwnership() {
|
||||
iterator_to_array($this->boardService->transferOwnership(self::TEST_USER_1, self::TEST_USER_2, true));
|
||||
$board = $this->boardService->find($this->board->getId());
|
||||
$acl = $board->getAcl();
|
||||
$this->assertBoardDoesNotHaveAclUser($board, self::TEST_USER_1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::transferOwnership
|
||||
*/
|
||||
public function testTransferACLOwnershipPreserveOwner() {
|
||||
iterator_to_array($this->boardService->transferOwnership(self::TEST_USER_1, self::TEST_USER_2, false));
|
||||
$board = $this->boardService->find($this->board->getId());
|
||||
$acl = $board->getAcl();
|
||||
$this->assertBoardHasAclUser($board, self::TEST_USER_1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::transferOwnership
|
||||
*/
|
||||
public function testNoTransferAclOwnershipIfGroupType() {
|
||||
iterator_to_array($this->boardService->transferOwnership(self::TEST_USER_1, self::TEST_USER_2));
|
||||
$board = $this->boardService->find($this->board->getId());
|
||||
$acl = $board->getAcl();
|
||||
$isGroupInAcl = (bool)array_filter($acl, function ($item) {
|
||||
return $item->getParticipant() === self::TEST_GROUP && $item->getType() === Acl::PERMISSION_TYPE_GROUP;
|
||||
});
|
||||
$this->assertTrue($isGroupInAcl);
|
||||
}
|
||||
/**
|
||||
* @covers ::transferOwnership
|
||||
*/
|
||||
public function testTransferCardOwnership() {
|
||||
iterator_to_array($this->boardService->transferOwnership(self::TEST_USER_1, self::TEST_USER_2, true));
|
||||
$card = $this->cardService->find($this->cards[0]->getId());
|
||||
$cardOwner = $card->getOwner();
|
||||
$this->assertEquals(self::TEST_USER_2, $cardOwner);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::transferOwnership
|
||||
*/
|
||||
public function testTransferPreserveCardOwnership() {
|
||||
iterator_to_array($this->boardService->transferOwnership(self::TEST_USER_1, self::TEST_USER_2, false));
|
||||
$card = $this->cardService->find($this->cards[0]->getId());
|
||||
$cardOwner = $card->getOwner();
|
||||
$this->assertEquals(self::TEST_USER_1, $cardOwner);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::transferOwnership
|
||||
*/
|
||||
public function testReassignCardToNewOwner() {
|
||||
iterator_to_array($this->boardService->transferOwnership(self::TEST_USER_1, self::TEST_USER_2, true));
|
||||
$participantsUIDs = array_map(function ($user) {
|
||||
return $user->getParticipant();
|
||||
}, $this->assignmentMapper->findAll($this->cards[0]->getId()));
|
||||
$this->assertContains(self::TEST_USER_2, $participantsUIDs);
|
||||
$this->assertNotContains(self::TEST_USER_1, $participantsUIDs);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::transferOwnership
|
||||
*/
|
||||
public function testNoReassignCardToNewOwner() {
|
||||
iterator_to_array($this->boardService->transferOwnership(self::TEST_USER_1, self::TEST_USER_2, false));
|
||||
$participantsUIDs = array_map(function ($user) {
|
||||
return $user->getParticipant();
|
||||
}, $this->assignmentMapper->findAll($this->cards[0]->getId()));
|
||||
$this->assertContains(self::TEST_USER_1, $participantsUIDs);
|
||||
$this->assertNotContains(self::TEST_USER_2, $participantsUIDs);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::transferOwnership
|
||||
*/
|
||||
public function testReassignCardToNewParticipantOnlyIfParticipantHasUserType() {
|
||||
$this->assignmentService->assignUser($this->cards[1]->getId(), self::TEST_USER_1, Assignment::TYPE_GROUP);
|
||||
iterator_to_array($this->boardService->transferOwnership(self::TEST_USER_1, self::TEST_USER_2));
|
||||
$participantsUIDs = array_map(function ($user) {
|
||||
return $user->getParticipant();
|
||||
}, $this->assignmentMapper->findAll($this->cards[1]->getId()));
|
||||
$this->assertContains(self::TEST_USER_1, $participantsUIDs);
|
||||
$this->assertNotContains(self::TEST_USER_2, $participantsUIDs);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::transferOwnership
|
||||
*/
|
||||
public function testTargetAlreadyParticipantOfBoard() {
|
||||
$this->expectNotToPerformAssertions();
|
||||
iterator_to_array($this->boardService->transferOwnership(self::TEST_USER_1, self::TEST_USER_3));
|
||||
}
|
||||
|
||||
private function assertBoardHasAclUser($board, $userId) {
|
||||
$hasUser = (bool)array_filter($board->getAcl(), function ($item) use ($userId) {
|
||||
return $item->getParticipant() === $userId && $item->getType() === Acl::PERMISSION_TYPE_USER;
|
||||
});
|
||||
self::assertTrue($hasUser, 'user ' . $userId . ' should be in the board acl list');
|
||||
}
|
||||
|
||||
private function assertBoardDoesNotHaveAclUser($board, $userId) {
|
||||
$hasUser = (bool)array_filter($board->getAcl(), function ($item) use ($userId) {
|
||||
return $item->getParticipant() === $userId && $item->getType() === Acl::PERMISSION_TYPE_USER;
|
||||
});
|
||||
self::assertFalse($hasUser, 'user ' . $userId . ' should not be in the board acl list');
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::transferOwnership
|
||||
*/
|
||||
public function testDontRemoveOldOwnerFromAcl() {
|
||||
iterator_to_array($this->boardService->transferOwnership(self::TEST_USER_1, self::TEST_USER_2));
|
||||
$board = $this->boardService->find($this->board->getId());
|
||||
|
||||
$this->assertBoardDoesNotHaveAclUser($board, self::TEST_USER_2);
|
||||
$this->assertBoardHasAclUser($board, self::TEST_USER_3);
|
||||
$this->assertBoardHasAclUser($board, self::TEST_USER_1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::transferOwnership
|
||||
*/
|
||||
public function testRemoveOldOwnerFromAclForChange() {
|
||||
iterator_to_array($this->boardService->transferOwnership(self::TEST_USER_1, self::TEST_USER_2, true));
|
||||
$board = $this->boardService->find($this->board->getId());
|
||||
$this->assertBoardDoesNotHaveAclUser($board, self::TEST_USER_2);
|
||||
$this->assertBoardHasAclUser($board, self::TEST_USER_3);
|
||||
$this->assertBoardDoesNotHaveAclUser($board, self::TEST_USER_1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::transferOwnership
|
||||
*/
|
||||
public function testMergePermissions() {
|
||||
$this->boardService->addAcl($this->board->getId(), Acl::PERMISSION_TYPE_USER, self::TEST_USER_2, true, false, true);
|
||||
iterator_to_array($this->boardService->transferOwnership(self::TEST_USER_1, self::TEST_USER_3));
|
||||
$board = $this->boardService->find($this->board->getId());
|
||||
$acl = $board->getAcl();
|
||||
$isMerged = (bool)array_filter($acl, function ($item) {
|
||||
return $item->getParticipant() === self::TEST_USER_1
|
||||
&& $item->getType() === Acl::PERMISSION_TYPE_USER
|
||||
&& $item->getPermission(Acl::PERMISSION_EDIT)
|
||||
&& $item->getPermission(Acl::PERMISSION_SHARE)
|
||||
&& $item->getPermission(Acl::PERMISSION_MANAGE);
|
||||
});
|
||||
$this->assertTrue($isMerged);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::transferOwnership
|
||||
*/
|
||||
public function testTargetAlreadyParticipantOfCard() {
|
||||
$this->expectNotToPerformAssertions();
|
||||
$this->assignmentService->assignUser($this->cards[0]->getId(), self::TEST_USER_3, Assignment::TYPE_USER);
|
||||
iterator_to_array($this->boardService->transferOwnership(self::TEST_USER_1, self::TEST_USER_3));
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::transferOwnership
|
||||
*/
|
||||
public function testTransferSingleBoardAssignment() {
|
||||
// Arrange separate board next to the one being transferred
|
||||
$board = $this->boardService->create('Test 2', self::TEST_USER_1, '000000');
|
||||
$id = $board->getId();
|
||||
$this->boardService->addAcl($id, Acl::PERMISSION_TYPE_USER, self::TEST_USER_1, true, true, true);
|
||||
$this->boardService->addAcl($id, Acl::PERMISSION_TYPE_GROUP, self::TEST_GROUP, true, true, true);
|
||||
$this->boardService->addAcl($id, Acl::PERMISSION_TYPE_USER, self::TEST_USER_3, false, true, false);
|
||||
$stacks[] = $this->stackService->create('Stack A', $id, 1);
|
||||
$stacks[] = $this->stackService->create('Stack B', $id, 1);
|
||||
$stacks[] = $this->stackService->create('Stack C', $id, 1);
|
||||
$cards[] = $this->cardService->create('Card 1', $stacks[0]->getId(), 'text', 0, self::TEST_USER_1);
|
||||
$cards[] = $this->cardService->create('Card 2', $stacks[0]->getId(), 'text', 0, self::TEST_USER_1);
|
||||
$this->assignmentService->assignUser($cards[0]->getId(), self::TEST_USER_1);
|
||||
|
||||
// Act
|
||||
$this->boardService->transferBoardOwnership($this->board->getId(), self::TEST_USER_2, true);
|
||||
|
||||
// Assert that the selected board was transferred
|
||||
$card = $this->cardService->find($this->cards[0]->getId());
|
||||
$this->assertEquals(self::TEST_USER_2, $card->getOwner());
|
||||
|
||||
$participantsUIDs = array_map(function ($assignment) {
|
||||
return $assignment->getParticipant();
|
||||
}, $this->assignmentMapper->findAll($this->cards[0]->getId()));
|
||||
$this->assertContains(self::TEST_USER_2, $participantsUIDs);
|
||||
$this->assertNotContains(self::TEST_USER_1, $participantsUIDs);
|
||||
|
||||
// Assert that other board remained unchanged
|
||||
$card = $this->cardService->find($cards[0]->getId());
|
||||
$this->assertEquals(self::TEST_USER_1, $card->getOwner());
|
||||
|
||||
$participantsUIDs = array_map(function ($assignment) {
|
||||
return $assignment->getParticipant();
|
||||
}, $this->assignmentMapper->findAll($cards[0]->getId()));
|
||||
$this->assertContains(self::TEST_USER_1, $participantsUIDs);
|
||||
$this->assertNotContains(self::TEST_USER_2, $participantsUIDs);
|
||||
}
|
||||
|
||||
public function tearDown(): void {
|
||||
$this->boardService->deleteForce($this->board->getId());
|
||||
parent::tearDown();
|
||||
}
|
||||
}
|
||||
@@ -26,7 +26,7 @@ composer dump-autoload
|
||||
if [ -z "$EXECUTOR_NUMBER" ]; then
|
||||
EXECUTOR_NUMBER=0
|
||||
fi
|
||||
PORT=$((8080 + $EXECUTOR_NUMBER))
|
||||
PORT=$((9090 + $EXECUTOR_NUMBER))
|
||||
echo $PORT
|
||||
php -S localhost:$PORT -t $OC_PATH &
|
||||
PHPPID=$!
|
||||
|
||||
@@ -26,7 +26,6 @@ namespace OCA\Deck\Activity;
|
||||
use OCA\Deck\Db\AclMapper;
|
||||
use OCA\Deck\Db\Assignment;
|
||||
use OCA\Deck\Db\Attachment;
|
||||
use OCA\Deck\Db\AttachmentMapper;
|
||||
use OCA\Deck\Db\Board;
|
||||
use OCA\Deck\Db\BoardMapper;
|
||||
use OCA\Deck\Db\Card;
|
||||
@@ -41,7 +40,7 @@ use OCP\IL10N;
|
||||
use OCP\IUser;
|
||||
use OCP\L10N\IFactory;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use PHPUnit_Framework_MockObject_MockObject as MockObject;
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
|
||||
class ActivityManagerTest extends TestCase {
|
||||
|
||||
@@ -57,8 +56,6 @@ class ActivityManagerTest extends TestCase {
|
||||
private $cardMapper;
|
||||
/** @var StackMapper|MockObject */
|
||||
private $stackMapper;
|
||||
/** @var AttachmentMapper|MockObject */
|
||||
private $attachmentMapper;
|
||||
/** @var AclMapper|MockObject */
|
||||
private $aclMapper;
|
||||
/** @var IFactory|MockObject */
|
||||
@@ -74,7 +71,6 @@ class ActivityManagerTest extends TestCase {
|
||||
$this->boardMapper = $this->createMock(BoardMapper::class);
|
||||
$this->cardMapper = $this->createMock(CardMapper::class);
|
||||
$this->stackMapper = $this->createMock(StackMapper::class);
|
||||
$this->attachmentMapper = $this->createMock(AttachmentMapper::class);
|
||||
$this->aclMapper = $this->createMock(AclMapper::class);
|
||||
$this->l10nFactory = $this->createMock(IFactory::class);
|
||||
$this->l10n = $this->createMock(IL10N::class);
|
||||
@@ -84,7 +80,6 @@ class ActivityManagerTest extends TestCase {
|
||||
$this->boardMapper,
|
||||
$this->cardMapper,
|
||||
$this->stackMapper,
|
||||
$this->attachmentMapper,
|
||||
$this->aclMapper,
|
||||
$this->l10nFactory,
|
||||
$this->userId
|
||||
@@ -93,7 +88,7 @@ class ActivityManagerTest extends TestCase {
|
||||
|
||||
public function testGetActivityFormatOwn() {
|
||||
$managerClass = new \ReflectionClass(ActivityManager::class);
|
||||
$this->l10n->expects($this->any())
|
||||
$this->l10n->expects(self::any())
|
||||
->method('t')
|
||||
->will($this->returnCallback(function ($s) {
|
||||
return $s;
|
||||
@@ -122,22 +117,29 @@ class ActivityManagerTest extends TestCase {
|
||||
}
|
||||
}
|
||||
|
||||
private function expectEventCreation($subject, $subjectParams) {
|
||||
$event = $this->createMock(IEvent::class);
|
||||
$this->manager->expects(self::once())
|
||||
->method('generateEvent')
|
||||
->willReturn($event);
|
||||
$event->expects(self::once())->method('setApp')->willReturn($event);
|
||||
$event->expects(self::once())->method('setType')->willReturn($event);
|
||||
$event->expects(self::once())->method('setAuthor')->willReturn($event);
|
||||
$event->expects(self::once())->method('setObject')->willReturn($event);
|
||||
$event->expects(self::once())->method('setSubject')->with($subject, $subjectParams)->willReturn($event);
|
||||
$event->expects(self::once())->method('setTimestamp')->willReturn($event);
|
||||
return $event;
|
||||
}
|
||||
|
||||
public function testCreateEvent() {
|
||||
$board = new Board();
|
||||
$board->setTitle('');
|
||||
$this->boardMapper->expects($this->once())
|
||||
$this->boardMapper->expects(self::once())
|
||||
->method('find')
|
||||
->willReturn($board);
|
||||
$event = $this->createMock(IEvent::class);
|
||||
$this->manager->expects($this->once())
|
||||
->method('generateEvent')
|
||||
->willReturn($event);
|
||||
$event->expects($this->once())->method('setApp')->willReturn($event);
|
||||
$event->expects($this->once())->method('setType')->willReturn($event);
|
||||
$event->expects($this->once())->method('setAuthor')->willReturn($event);
|
||||
$event->expects($this->once())->method('setObject')->willReturn($event);
|
||||
$event->expects($this->once())->method('setSubject')->willReturn($event);
|
||||
$event->expects($this->once())->method('setTimestamp')->willReturn($event);
|
||||
$event = $this->expectEventCreation(ActivityManager::SUBJECT_BOARD_CREATE, [
|
||||
'author' => 'admin'
|
||||
]);
|
||||
$actual = $this->invokePrivate($this->activityManager, 'createEvent', [
|
||||
ActivityManager::DECK_OBJECT_BOARD,
|
||||
$board,
|
||||
@@ -146,6 +148,133 @@ class ActivityManagerTest extends TestCase {
|
||||
$this->assertEquals($event, $actual);
|
||||
}
|
||||
|
||||
public function testCreateEventDescription() {
|
||||
$board = new Board();
|
||||
$board->setTitle('');
|
||||
$this->boardMapper->expects(self::once())
|
||||
->method('find')
|
||||
->willReturn($board);
|
||||
|
||||
$card = Card::fromRow([
|
||||
'id' => 123,
|
||||
'title' => 'My card',
|
||||
'description' => str_repeat('A', 1000),
|
||||
]);
|
||||
$this->cardMapper->expects(self::any())
|
||||
->method('find')
|
||||
->willReturn($card);
|
||||
|
||||
$stack = Stack::fromRow([]);
|
||||
$this->stackMapper->expects(self::any())
|
||||
->method('find')
|
||||
->willReturn($stack);
|
||||
|
||||
$expectedCard = $card->jsonSerialize();
|
||||
unset($expectedCard['description']);
|
||||
$event = $this->expectEventCreation(ActivityManager::SUBJECT_CARD_UPDATE_DESCRIPTION, [
|
||||
'card' => $expectedCard,
|
||||
'stack' => $stack->jsonSerialize(),
|
||||
'board' => $board->jsonSerialize(),
|
||||
'diff' => true,
|
||||
'author' => 'admin',
|
||||
'after' => str_repeat('C', 2000),
|
||||
]);
|
||||
|
||||
$actual = $this->invokePrivate($this->activityManager, 'createEvent', [
|
||||
ActivityManager::DECK_OBJECT_CARD,
|
||||
$card,
|
||||
ActivityManager::SUBJECT_CARD_UPDATE_DESCRIPTION,
|
||||
[
|
||||
'before' => str_repeat('B', 2000),
|
||||
'after' => str_repeat('C', 2000)
|
||||
],
|
||||
]);
|
||||
$this->assertEquals($event, $actual);
|
||||
}
|
||||
|
||||
public function testCreateEventLongDescription() {
|
||||
$board = new Board();
|
||||
$board->setTitle('');
|
||||
$this->boardMapper->expects(self::once())
|
||||
->method('find')
|
||||
->willReturn($board);
|
||||
|
||||
$card = new Card();
|
||||
$card->setDescription(str_repeat('A', 5000));
|
||||
$card->setTitle('My card');
|
||||
$card->setId(123);
|
||||
$this->cardMapper->expects(self::any())
|
||||
->method('find')
|
||||
->willReturn($card);
|
||||
|
||||
$stack = new Stack();
|
||||
$this->stackMapper->expects(self::any())
|
||||
->method('find')
|
||||
->willReturn($stack);
|
||||
|
||||
$expectedCard = $card->jsonSerialize();
|
||||
unset($expectedCard['description']);
|
||||
$event = $this->expectEventCreation(ActivityManager::SUBJECT_CARD_UPDATE_DESCRIPTION, [
|
||||
'card' => $expectedCard,
|
||||
'stack' => $stack->jsonSerialize(),
|
||||
'board' => $board->jsonSerialize(),
|
||||
'diff' => true,
|
||||
'author' => 'admin',
|
||||
'after' => str_repeat('C', 2000) . '...',
|
||||
]);
|
||||
|
||||
$actual = $this->invokePrivate($this->activityManager, 'createEvent', [
|
||||
ActivityManager::DECK_OBJECT_CARD,
|
||||
$card,
|
||||
ActivityManager::SUBJECT_CARD_UPDATE_DESCRIPTION,
|
||||
[
|
||||
'before' => str_repeat('B', 5000),
|
||||
'after' => str_repeat('C', 5000)
|
||||
],
|
||||
]);
|
||||
$this->assertEquals($event, $actual);
|
||||
}
|
||||
|
||||
public function testCreateEventLabel() {
|
||||
$board = Board::fromRow([
|
||||
'title' => 'My board'
|
||||
]);
|
||||
$this->boardMapper->expects(self::once())
|
||||
->method('find')
|
||||
->willReturn($board);
|
||||
|
||||
$card = Card::fromParams([]);
|
||||
$card->setDescription(str_repeat('A', 5000));
|
||||
$card->setTitle('My card');
|
||||
$card->setId(123);
|
||||
$this->cardMapper->expects(self::any())
|
||||
->method('find')
|
||||
->willReturn($card);
|
||||
|
||||
$stack = Stack::fromParams([]);
|
||||
$this->stackMapper->expects(self::any())
|
||||
->method('find')
|
||||
->willReturn($stack);
|
||||
|
||||
$event = $this->expectEventCreation(ActivityManager::SUBJECT_CARD_UPDATE_TITLE, [
|
||||
'card' => [
|
||||
'id' => 123,
|
||||
'title' => 'My card',
|
||||
'archived' => false,
|
||||
],
|
||||
'stack' => $stack,
|
||||
'board' => $board,
|
||||
'author' => 'admin',
|
||||
]);
|
||||
|
||||
$actual = $this->invokePrivate($this->activityManager, 'createEvent', [
|
||||
ActivityManager::DECK_OBJECT_CARD,
|
||||
$card,
|
||||
ActivityManager::SUBJECT_CARD_UPDATE_TITLE
|
||||
]);
|
||||
$this->assertEquals($event, $actual);
|
||||
}
|
||||
|
||||
public function dataSendToUsers() {
|
||||
return [
|
||||
[ActivityManager::DECK_OBJECT_BOARD],
|
||||
@@ -155,7 +284,7 @@ class ActivityManagerTest extends TestCase {
|
||||
|
||||
private function mockUser($uid) {
|
||||
$user = $this->createMock(IUser::class);
|
||||
$user->expects($this->any())
|
||||
$user->expects(self::any())
|
||||
->method('getUID')
|
||||
->willReturn($uid);
|
||||
return $user;
|
||||
@@ -169,18 +298,21 @@ class ActivityManagerTest extends TestCase {
|
||||
$this->mockUser('user2'),
|
||||
];
|
||||
$event = $this->createMock(IEvent::class);
|
||||
$event->expects($this->at(0))
|
||||
|
||||
$event->expects(self::once())
|
||||
->method('getObjectType')
|
||||
->willReturn($objectType);
|
||||
$event->expects($this->at(0))
|
||||
$event->expects(self::once())
|
||||
->method('getObjectId')
|
||||
->willReturn(1);
|
||||
$event->expects($this->at(2))
|
||||
$event->expects(self::exactly(2))
|
||||
->method('setAffectedUser')
|
||||
->with('user1');
|
||||
$event->expects($this->at(3))
|
||||
->method('setAffectedUser')
|
||||
->with('user2');
|
||||
->withConsecutive(
|
||||
['user1'],
|
||||
['user2'],
|
||||
)
|
||||
->willReturnSelf();
|
||||
|
||||
$mapper = null;
|
||||
switch ($objectType) {
|
||||
case ActivityManager::DECK_OBJECT_BOARD:
|
||||
@@ -190,16 +322,14 @@ class ActivityManagerTest extends TestCase {
|
||||
$mapper = $this->cardMapper;
|
||||
break;
|
||||
}
|
||||
$mapper->expects($this->once())
|
||||
$mapper->expects(self::once())
|
||||
->method('findBoardId')
|
||||
->willReturn(123);
|
||||
$this->permissionService->expects($this->once())
|
||||
$this->permissionService->expects(self::once())
|
||||
->method('findUsers')
|
||||
->willReturn($users);
|
||||
$this->manager->expects($this->at(0))
|
||||
->method('publish')
|
||||
->with($event);
|
||||
$this->manager->expects($this->at(1))
|
||||
|
||||
$this->manager->expects(self::exactly(2))
|
||||
->method('publish')
|
||||
->with($event);
|
||||
$this->invokePrivate($this->activityManager, 'sendToUsers', [$event]);
|
||||
@@ -243,14 +373,14 @@ class ActivityManagerTest extends TestCase {
|
||||
$card->setId(3);
|
||||
$expected = null;
|
||||
if ($objectType === ActivityManager::DECK_OBJECT_BOARD) {
|
||||
$this->boardMapper->expects($this->once())
|
||||
$this->boardMapper->expects(self::once())
|
||||
->method('find')
|
||||
->with(1)
|
||||
->willReturn($board);
|
||||
$expected = $board;
|
||||
}
|
||||
if ($objectType === ActivityManager::DECK_OBJECT_CARD) {
|
||||
$this->cardMapper->expects($this->once())
|
||||
$this->cardMapper->expects(self::once())
|
||||
->method('find')
|
||||
->with(3)
|
||||
->willReturn($card);
|
||||
@@ -266,11 +396,11 @@ class ActivityManagerTest extends TestCase {
|
||||
$stack->setBoardId(999);
|
||||
$board = new Board();
|
||||
$board->setId(999);
|
||||
$this->stackMapper->expects($this->once())
|
||||
$this->stackMapper->expects(self::once())
|
||||
->method('find')
|
||||
->with(123)
|
||||
->willReturn($stack);
|
||||
$this->boardMapper->expects($this->once())->method('find')
|
||||
$this->boardMapper->expects(self::once())->method('find')
|
||||
->with(999)
|
||||
->willReturn($board);
|
||||
$this->assertEquals([
|
||||
@@ -289,15 +419,15 @@ class ActivityManagerTest extends TestCase {
|
||||
$stack->setBoardId(999);
|
||||
$board = new Board();
|
||||
$board->setId(999);
|
||||
$this->cardMapper->expects($this->once())
|
||||
$this->cardMapper->expects(self::once())
|
||||
->method('find')
|
||||
->with(555)
|
||||
->willReturn($card);
|
||||
$this->stackMapper->expects($this->once())
|
||||
$this->stackMapper->expects(self::once())
|
||||
->method('find')
|
||||
->with(123)
|
||||
->willReturn($stack);
|
||||
$this->boardMapper->expects($this->once())->method('find')
|
||||
$this->boardMapper->expects(self::once())->method('find')
|
||||
->with(999)
|
||||
->willReturn($board);
|
||||
$this->assertEquals([
|
||||
@@ -323,15 +453,15 @@ class ActivityManagerTest extends TestCase {
|
||||
$stack->setBoardId(999);
|
||||
$board = new Board();
|
||||
$board->setId(999);
|
||||
$this->cardMapper->expects($this->once())
|
||||
$this->cardMapper->expects(self::once())
|
||||
->method('find')
|
||||
->with(555)
|
||||
->willReturn($card);
|
||||
$this->stackMapper->expects($this->once())
|
||||
$this->stackMapper->expects(self::once())
|
||||
->method('find')
|
||||
->with(123)
|
||||
->willReturn($stack);
|
||||
$this->boardMapper->expects($this->once())->method('find')
|
||||
$this->boardMapper->expects(self::once())->method('find')
|
||||
->with(999)
|
||||
->willReturn($board);
|
||||
$this->assertEquals([
|
||||
|
||||
@@ -66,18 +66,14 @@ class DeleteCronTest extends \Test\TestCase {
|
||||
$this->boardMapper->expects($this->once())
|
||||
->method('findToDelete')
|
||||
->willReturn($boards);
|
||||
$this->boardMapper->expects($this->at(1))
|
||||
$this->boardMapper->expects($this->exactly(count($boards)))
|
||||
->method('delete')
|
||||
->with($boards[0]);
|
||||
$this->boardMapper->expects($this->at(2))
|
||||
->method('delete')
|
||||
->with($boards[1]);
|
||||
$this->boardMapper->expects($this->at(3))
|
||||
->method('delete')
|
||||
->with($boards[2]);
|
||||
$this->boardMapper->expects($this->at(4))
|
||||
->method('delete')
|
||||
->with($boards[3]);
|
||||
->withConsecutive(
|
||||
[$boards[0]],
|
||||
[$boards[1]],
|
||||
[$boards[2]],
|
||||
[$boards[3]]
|
||||
);
|
||||
|
||||
$attachment = new Attachment();
|
||||
$attachment->setType('deck_file');
|
||||
|
||||
@@ -54,10 +54,7 @@ class ScheduledNoificationsTest extends \Test\TestCase {
|
||||
$this->cardMapper->expects($this->once())
|
||||
->method('findOverdue')
|
||||
->willReturn($cards);
|
||||
$this->notificationHelper->expects($this->at(0))
|
||||
->method('sendCardDuedate')
|
||||
->with($c1);
|
||||
$this->notificationHelper->expects($this->at(1))
|
||||
$this->notificationHelper->expects($this->exactly(2))
|
||||
->method('sendCardDuedate')
|
||||
->with($c1);
|
||||
$this->scheduledNotifications->run(null);
|
||||
|
||||
@@ -114,17 +114,18 @@ class NotificationHelperTest extends \Test\TestCase {
|
||||
}
|
||||
|
||||
public function testSendCardDuedate() {
|
||||
$this->config->expects($this->at(0))
|
||||
$param1 = ['foo', 'bar', 'asd'];
|
||||
$param2 = 'deck';
|
||||
$param3 = 'board:234:notify-due';
|
||||
$DUE_ASSIGNED = ConfigService::SETTING_BOARD_NOTIFICATION_DUE_ASSIGNED;
|
||||
|
||||
$this->config->expects($this->exactly(3))
|
||||
->method('getUserValue')
|
||||
->with('foo', 'deck', 'board:234:notify-due', ConfigService::SETTING_BOARD_NOTIFICATION_DUE_ASSIGNED)
|
||||
->willReturn(ConfigService::SETTING_BOARD_NOTIFICATION_DUE_ALL);
|
||||
$this->config->expects($this->at(1))
|
||||
->method('getUserValue')
|
||||
->with('bar', 'deck', 'board:234:notify-due', ConfigService::SETTING_BOARD_NOTIFICATION_DUE_ASSIGNED)
|
||||
->willReturn(ConfigService::SETTING_BOARD_NOTIFICATION_DUE_ALL);
|
||||
$this->config->expects($this->at(2))
|
||||
->method('getUserValue')
|
||||
->with('asd', 'deck', 'board:234:notify-due', ConfigService::SETTING_BOARD_NOTIFICATION_DUE_ASSIGNED)
|
||||
->withConsecutive(
|
||||
[$param1[0], $param2, $param3, $DUE_ASSIGNED],
|
||||
[$param1[1], $param2, $param3, $DUE_ASSIGNED],
|
||||
[$param1[2], $param2, $param3, $DUE_ASSIGNED],
|
||||
)
|
||||
->willReturn(ConfigService::SETTING_BOARD_NOTIFICATION_DUE_ALL);
|
||||
|
||||
$card = Card::fromParams([
|
||||
@@ -180,24 +181,12 @@ class NotificationHelperTest extends \Test\TestCase {
|
||||
$n3->expects($this->once())->method('setSubject')->with('card-overdue', ['MyCardTitle', 'MyBoardTitle'])->willReturn($n3);
|
||||
$n3->expects($this->once())->method('setDateTime')->willReturn($n3);
|
||||
|
||||
$this->notificationManager->expects($this->at(0))
|
||||
$this->notificationManager->expects($this->exactly(3))
|
||||
->method('createNotification')
|
||||
->willReturn($n1);
|
||||
$this->notificationManager->expects($this->at(1))
|
||||
->willReturnOnConsecutiveCalls($n1, $n2, $n3);
|
||||
$this->notificationManager->expects($this->exactly(3))
|
||||
->method('notify')
|
||||
->with($n1);
|
||||
$this->notificationManager->expects($this->at(2))
|
||||
->method('createNotification')
|
||||
->willReturn($n2);
|
||||
$this->notificationManager->expects($this->at(3))
|
||||
->method('notify')
|
||||
->with($n2);
|
||||
$this->notificationManager->expects($this->at(4))
|
||||
->method('createNotification')
|
||||
->willReturn($n3);
|
||||
$this->notificationManager->expects($this->at(5))
|
||||
->method('notify')
|
||||
->with($n3);
|
||||
->withConsecutive([$n1], [$n2], [$n3]);
|
||||
|
||||
$this->cardMapper->expects($this->once())
|
||||
->method('markNotified')
|
||||
@@ -207,18 +196,19 @@ class NotificationHelperTest extends \Test\TestCase {
|
||||
}
|
||||
|
||||
public function testSendCardDuedateAssigned() {
|
||||
$this->config->expects($this->at(0))
|
||||
$param1 = ['foo', 'bar', 'asd'];
|
||||
$param2 = 'deck';
|
||||
$param3 = 'board:234:notify-due';
|
||||
$DUE_ASSIGNED = ConfigService::SETTING_BOARD_NOTIFICATION_DUE_ASSIGNED;
|
||||
|
||||
$this->config->expects($this->exactly(3))
|
||||
->method('getUserValue')
|
||||
->with('foo', 'deck', 'board:234:notify-due', ConfigService::SETTING_BOARD_NOTIFICATION_DUE_ASSIGNED)
|
||||
->willReturn(ConfigService::SETTING_BOARD_NOTIFICATION_DUE_ASSIGNED);
|
||||
$this->config->expects($this->at(1))
|
||||
->method('getUserValue')
|
||||
->with('bar', 'deck', 'board:234:notify-due', ConfigService::SETTING_BOARD_NOTIFICATION_DUE_ASSIGNED)
|
||||
->willReturn(ConfigService::SETTING_BOARD_NOTIFICATION_DUE_ASSIGNED);
|
||||
$this->config->expects($this->at(2))
|
||||
->method('getUserValue')
|
||||
->with('asd', 'deck', 'board:234:notify-due', ConfigService::SETTING_BOARD_NOTIFICATION_DUE_ASSIGNED)
|
||||
->willReturn(ConfigService::SETTING_BOARD_NOTIFICATION_DUE_ASSIGNED);
|
||||
->withConsecutive(
|
||||
[$param1[0], $param2, $param3, $DUE_ASSIGNED],
|
||||
[$param1[1], $param2, $param3, $DUE_ASSIGNED],
|
||||
[$param1[2], $param2, $param3, $DUE_ASSIGNED]
|
||||
)
|
||||
->willReturn($DUE_ASSIGNED);
|
||||
|
||||
$users = [
|
||||
new DummyUser('foo'), new DummyUser('bar'), new DummyUser('asd')
|
||||
@@ -278,24 +268,12 @@ class NotificationHelperTest extends \Test\TestCase {
|
||||
$n3->expects($this->once())->method('setSubject')->with('card-overdue', ['MyCardTitle', 'MyBoardTitle'])->willReturn($n3);
|
||||
$n3->expects($this->once())->method('setDateTime')->willReturn($n3);
|
||||
|
||||
$this->notificationManager->expects($this->at(0))
|
||||
$this->notificationManager->expects($this->exactly(3))
|
||||
->method('createNotification')
|
||||
->willReturn($n1);
|
||||
$this->notificationManager->expects($this->at(1))
|
||||
->willReturnOnConsecutiveCalls($n1, $n2, $n3);
|
||||
$this->notificationManager->expects($this->exactly(3))
|
||||
->method('notify')
|
||||
->with($n1);
|
||||
$this->notificationManager->expects($this->at(2))
|
||||
->method('createNotification')
|
||||
->willReturn($n2);
|
||||
$this->notificationManager->expects($this->at(3))
|
||||
->method('notify')
|
||||
->with($n2);
|
||||
$this->notificationManager->expects($this->at(4))
|
||||
->method('createNotification')
|
||||
->willReturn($n3);
|
||||
$this->notificationManager->expects($this->at(5))
|
||||
->method('notify')
|
||||
->with($n3);
|
||||
->withConsecutive([$n1], [$n2], [$n3]);
|
||||
|
||||
$this->cardMapper->expects($this->once())
|
||||
->method('markNotified')
|
||||
@@ -306,18 +284,20 @@ class NotificationHelperTest extends \Test\TestCase {
|
||||
|
||||
|
||||
public function testSendCardDuedateNever() {
|
||||
$this->config->expects($this->at(0))
|
||||
$param1 = ['foo', 'bar', 'asd'];
|
||||
$param2 = 'deck';
|
||||
$param3 = 'board:234:notify-due';
|
||||
$DUE_ASSIGNED = ConfigService::SETTING_BOARD_NOTIFICATION_DUE_ASSIGNED;
|
||||
$DUE_OFF = ConfigService::SETTING_BOARD_NOTIFICATION_DUE_OFF;
|
||||
|
||||
$this->config->expects($this->exactly(3))
|
||||
->method('getUserValue')
|
||||
->with('foo', 'deck', 'board:234:notify-due', ConfigService::SETTING_BOARD_NOTIFICATION_DUE_ASSIGNED)
|
||||
->willReturn(ConfigService::SETTING_BOARD_NOTIFICATION_DUE_ASSIGNED);
|
||||
$this->config->expects($this->at(1))
|
||||
->method('getUserValue')
|
||||
->with('bar', 'deck', 'board:234:notify-due', ConfigService::SETTING_BOARD_NOTIFICATION_DUE_ASSIGNED)
|
||||
->willReturn(ConfigService::SETTING_BOARD_NOTIFICATION_DUE_ASSIGNED);
|
||||
$this->config->expects($this->at(2))
|
||||
->method('getUserValue')
|
||||
->with('asd', 'deck', 'board:234:notify-due', ConfigService::SETTING_BOARD_NOTIFICATION_DUE_ASSIGNED)
|
||||
->willReturn(ConfigService::SETTING_BOARD_NOTIFICATION_DUE_OFF);
|
||||
->withConsecutive(
|
||||
[$param1[0], $param2, $param3, $DUE_ASSIGNED],
|
||||
[$param1[1], $param2, $param3, $DUE_ASSIGNED],
|
||||
[$param1[2], $param2, $param3, $DUE_ASSIGNED]
|
||||
)
|
||||
->willReturnOnConsecutiveCalls($DUE_ASSIGNED, $DUE_ASSIGNED, $DUE_OFF);
|
||||
|
||||
$users = [
|
||||
new DummyUser('foo'), new DummyUser('bar'), new DummyUser('asd')
|
||||
@@ -370,18 +350,12 @@ class NotificationHelperTest extends \Test\TestCase {
|
||||
$n2->expects($this->once())->method('setSubject')->with('card-overdue', ['MyCardTitle', 'MyBoardTitle'])->willReturn($n2);
|
||||
$n2->expects($this->once())->method('setDateTime')->willReturn($n2);
|
||||
|
||||
$this->notificationManager->expects($this->at(0))
|
||||
$this->notificationManager->expects($this->exactly(2))
|
||||
->method('createNotification')
|
||||
->willReturn($n1);
|
||||
$this->notificationManager->expects($this->at(1))
|
||||
->willReturnOnConsecutiveCalls($n1, $n2);
|
||||
$this->notificationManager->expects($this->exactly(2))
|
||||
->method('notify')
|
||||
->with($n1);
|
||||
$this->notificationManager->expects($this->at(2))
|
||||
->method('createNotification')
|
||||
->willReturn($n2);
|
||||
$this->notificationManager->expects($this->at(3))
|
||||
->method('notify')
|
||||
->with($n2);
|
||||
->withConsecutive([$n1], [$n2]);
|
||||
|
||||
$this->cardMapper->expects($this->once())
|
||||
->method('markNotified')
|
||||
@@ -423,10 +397,10 @@ class NotificationHelperTest extends \Test\TestCase {
|
||||
$notification->expects($this->once())->method('setSubject')->with('card-assigned', ['MyCardTitle', 'MyBoardTitle', 'admin'])->willReturn($notification);
|
||||
$notification->expects($this->once())->method('setDateTime')->willReturn($notification);
|
||||
|
||||
$this->notificationManager->expects($this->at(0))
|
||||
$this->notificationManager->expects($this->once())
|
||||
->method('createNotification')
|
||||
->willReturn($notification);
|
||||
$this->notificationManager->expects($this->at(1))
|
||||
$this->notificationManager->expects($this->once())
|
||||
->method('notify')
|
||||
->with($notification);
|
||||
|
||||
@@ -451,10 +425,10 @@ class NotificationHelperTest extends \Test\TestCase {
|
||||
$notification->expects($this->once())->method('setSubject')->with('board-shared', ['MyBoardTitle', 'admin'])->willReturn($notification);
|
||||
$notification->expects($this->once())->method('setDateTime')->willReturn($notification);
|
||||
|
||||
$this->notificationManager->expects($this->at(0))
|
||||
$this->notificationManager->expects($this->once())
|
||||
->method('createNotification')
|
||||
->willReturn($notification);
|
||||
$this->notificationManager->expects($this->at(1))
|
||||
$this->notificationManager->expects($this->once())
|
||||
->method('notify')
|
||||
->with($notification);
|
||||
|
||||
@@ -490,10 +464,10 @@ class NotificationHelperTest extends \Test\TestCase {
|
||||
$notification->expects($this->once())->method('setSubject')->with('board-shared', ['MyBoardTitle', 'admin'])->willReturn($notification);
|
||||
$notification->expects($this->once())->method('setDateTime')->willReturn($notification);
|
||||
|
||||
$this->notificationManager->expects($this->at(0))
|
||||
$this->notificationManager->expects($this->once())
|
||||
->method('createNotification')
|
||||
->willReturn($notification);
|
||||
$this->notificationManager->expects($this->at(1))
|
||||
$this->notificationManager->expects($this->once())
|
||||
->method('notify')
|
||||
->with($notification);
|
||||
|
||||
@@ -540,19 +514,12 @@ class NotificationHelperTest extends \Test\TestCase {
|
||||
$notification2->expects($this->once())->method('setSubject')->with('card-comment-mentioned', ['MyCard', 1, 'admin'])->willReturn($notification2);
|
||||
$notification2->expects($this->once())->method('setDateTime')->willReturn($notification2);
|
||||
|
||||
$this->notificationManager->expects($this->at(0))
|
||||
$this->notificationManager->expects($this->exactly(2))
|
||||
->method('createNotification')
|
||||
->willReturn($notification1);
|
||||
$this->notificationManager->expects($this->at(1))
|
||||
->willReturnOnConsecutiveCalls($notification1, $notification2);
|
||||
$this->notificationManager->expects($this->exactly(2))
|
||||
->method('notify')
|
||||
->with($notification1);
|
||||
|
||||
$this->notificationManager->expects($this->at(2))
|
||||
->method('createNotification')
|
||||
->willReturn($notification2);
|
||||
$this->notificationManager->expects($this->at(3))
|
||||
->method('notify')
|
||||
->with($notification2);
|
||||
->withConsecutive([$notification1], [$notification2]);
|
||||
|
||||
$this->notificationHelper->sendMention($comment);
|
||||
}
|
||||
|
||||
@@ -110,8 +110,16 @@ class AttachmentServiceTest extends TestCase {
|
||||
$this->cache = $this->createMock(ICache::class);
|
||||
$this->cacheFactory->expects($this->any())->method('createDistributed')->willReturn($this->cache);
|
||||
|
||||
$this->appContainer->expects($this->at(0))->method('query')->with(FileService::class)->willReturn($this->attachmentServiceImpl);
|
||||
$this->appContainer->expects($this->at(1))->method('query')->with(FilesAppService::class)->willReturn($this->filesAppServiceImpl);
|
||||
$this->appContainer->expects($this->exactly(2))
|
||||
->method('query')
|
||||
->withConsecutive(
|
||||
[FileService::class],
|
||||
[FilesAppService::class]
|
||||
)
|
||||
->willReturnOnConsecutiveCalls(
|
||||
$this->attachmentServiceImpl,
|
||||
$this->filesAppServiceImpl
|
||||
);
|
||||
|
||||
$this->application->expects($this->any())
|
||||
->method('getContainer')
|
||||
@@ -129,9 +137,18 @@ class AttachmentServiceTest extends TestCase {
|
||||
$fileServiceMock = $this->createMock(FileService::class);
|
||||
$fileAppServiceMock = $this->createMock(FilesAppService::class);
|
||||
|
||||
$appContainer->expects($this->at(0))->method('query')->with(FileService::class)->willReturn($fileServiceMock);
|
||||
$appContainer->expects($this->at(1))->method('query')->with(FilesAppService::class)->willReturn($fileAppServiceMock);
|
||||
$appContainer->expects($this->at(2))->method('query')->with(MyAttachmentService::class)->willReturn(new MyAttachmentService());
|
||||
$appContainer->expects($this->exactly(3))
|
||||
->method('query')
|
||||
->withConsecutive(
|
||||
[FileService::class],
|
||||
[FilesAppService::class],
|
||||
[MyAttachmentService::class]
|
||||
)
|
||||
->willReturnOnConsecutiveCalls(
|
||||
$fileServiceMock,
|
||||
$fileAppServiceMock,
|
||||
new MyAttachmentService()
|
||||
);
|
||||
|
||||
$application->expects($this->any())
|
||||
->method('getContainer')
|
||||
@@ -148,12 +165,24 @@ class AttachmentServiceTest extends TestCase {
|
||||
$appContainer = $this->createMock(IAppContainer::class);
|
||||
$fileServiceMock = $this->createMock(FileService::class);
|
||||
$fileAppServiceMock = $this->createMock(FilesAppService::class);
|
||||
$appContainer->expects($this->at(0))->method('query')->with(FileService::class)->willReturn($fileServiceMock);
|
||||
$appContainer->expects($this->at(1))->method('query')->with(FilesAppService::class)->willReturn($fileAppServiceMock);
|
||||
$appContainer->expects($this->at(2))->method('query')->with(MyAttachmentService::class)->willReturn(new MyAttachmentService());
|
||||
|
||||
$appContainer->expects($this->exactly(3))
|
||||
->method('query')
|
||||
->withConsecutive(
|
||||
[FileService::class],
|
||||
[FilesAppService::class],
|
||||
[MyAttachmentService::class]
|
||||
)
|
||||
->willReturnOnConsecutiveCalls(
|
||||
$fileServiceMock,
|
||||
$fileAppServiceMock,
|
||||
new MyAttachmentService()
|
||||
);
|
||||
|
||||
$application->expects($this->any())
|
||||
->method('getContainer')
|
||||
->willReturn($appContainer);
|
||||
|
||||
$attachmentService = new AttachmentService($this->attachmentMapper, $this->cardMapper, $this->changeHelper, $this->permissionService, $application, $this->cacheFactory, $this->userId, $this->l10n, $this->activityManager);
|
||||
$attachmentService->registerAttachmentService('custom', MyAttachmentService::class);
|
||||
$attachmentService->getService('deck_file_invalid');
|
||||
@@ -185,12 +214,17 @@ class AttachmentServiceTest extends TestCase {
|
||||
->with(123)
|
||||
->willReturn($attachments);
|
||||
|
||||
$this->attachmentServiceImpl->expects($this->at(0))
|
||||
$this->attachmentServiceImpl->expects($this->exactly(2))
|
||||
->method('extendData')
|
||||
->with($attachments[0]);
|
||||
$this->attachmentServiceImpl->expects($this->at(1))
|
||||
->method('extendData')
|
||||
->with($attachments[1]);
|
||||
->withConsecutive(
|
||||
[$attachments[0]],
|
||||
[$attachments[1]],
|
||||
)
|
||||
->willReturnOnConsecutiveCalls(
|
||||
$attachments[0],
|
||||
$attachments[1],
|
||||
);
|
||||
|
||||
$this->assertEquals($attachments, $this->attachmentService->findAll(123, false));
|
||||
}
|
||||
|
||||
@@ -215,12 +249,15 @@ class AttachmentServiceTest extends TestCase {
|
||||
->with(123, false)
|
||||
->willReturn($attachmentsDeleted);
|
||||
|
||||
$this->attachmentServiceImpl->expects($this->at(0))
|
||||
$this->attachmentServiceImpl->expects($this->exactly(4))
|
||||
->method('extendData')
|
||||
->with($attachments[0]);
|
||||
$this->attachmentServiceImpl->expects($this->at(1))
|
||||
->method('extendData')
|
||||
->with($attachments[1]);
|
||||
->withConsecutive(
|
||||
[$attachments[0]],
|
||||
[$attachments[1]],
|
||||
[$attachmentsDeleted[0]],
|
||||
[$attachmentsDeleted[1]]
|
||||
);
|
||||
|
||||
$this->assertEquals(array_merge($attachments, $attachmentsDeleted), $this->attachmentService->findAll(123, true));
|
||||
}
|
||||
|
||||
@@ -396,5 +433,6 @@ class AttachmentServiceTest extends TestCase {
|
||||
->method('allowUndo')
|
||||
->willReturn(false);
|
||||
$actual = $this->attachmentService->restore(1, 1);
|
||||
$this->assertEquals($expected, $actual);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ use OCA\Deck\Db\Assignment;
|
||||
use OCA\Deck\Db\AssignmentMapper;
|
||||
use OCA\Deck\Db\Board;
|
||||
use OCA\Deck\Db\BoardMapper;
|
||||
use OCA\Deck\Db\CardMapper;
|
||||
use OCA\Deck\Db\ChangeHelper;
|
||||
use OCA\Deck\Db\LabelMapper;
|
||||
use OCA\Deck\Db\StackMapper;
|
||||
@@ -58,6 +59,8 @@ class BoardServiceTest extends TestCase {
|
||||
private $boardMapper;
|
||||
/** @var StackMapper */
|
||||
private $stackMapper;
|
||||
/** @var CardMapper */
|
||||
private $cardMapper;
|
||||
/** @var PermissionService */
|
||||
private $permissionService;
|
||||
/** @var NotificationHelper */
|
||||
@@ -85,6 +88,7 @@ class BoardServiceTest extends TestCase {
|
||||
$this->boardMapper = $this->createMock(BoardMapper::class);
|
||||
$this->stackMapper = $this->createMock(StackMapper::class);
|
||||
$this->config = $this->createMock(IConfig::class);
|
||||
$this->cardMapper = $this->createMock(CardMapper::class);
|
||||
$this->labelMapper = $this->createMock(LabelMapper::class);
|
||||
$this->permissionService = $this->createMock(PermissionService::class);
|
||||
$this->notificationHelper = $this->createMock(NotificationHelper::class);
|
||||
@@ -106,6 +110,7 @@ class BoardServiceTest extends TestCase {
|
||||
$this->permissionService,
|
||||
$this->notificationHelper,
|
||||
$this->assignedUsersMapper,
|
||||
$this->cardMapper,
|
||||
$this->userManager,
|
||||
$this->groupManager,
|
||||
$this->activityManager,
|
||||
@@ -149,7 +154,7 @@ class BoardServiceTest extends TestCase {
|
||||
->method('find')
|
||||
->with(1)
|
||||
->willReturn($b1);
|
||||
$this->permissionService->expects($this->once())
|
||||
$this->permissionService->expects($this->any())
|
||||
->method('findUsers')
|
||||
->willReturn([
|
||||
'admin' => 'admin',
|
||||
@@ -253,6 +258,11 @@ class BoardServiceTest extends TestCase {
|
||||
->method('insert')
|
||||
->with($acl)
|
||||
->willReturn($acl);
|
||||
$this->permissionService->expects($this->any())
|
||||
->method('findUsers')
|
||||
->willReturn([
|
||||
'admin' => 'admin',
|
||||
]);
|
||||
$this->assertEquals($acl, $this->service->addAcl(
|
||||
123, 'user', 'admin', true, true, true
|
||||
));
|
||||
@@ -295,30 +305,39 @@ class BoardServiceTest extends TestCase {
|
||||
$existingAcl->setPermissionEdit($currentUserAcl[0]);
|
||||
$existingAcl->setPermissionShare($currentUserAcl[1]);
|
||||
$existingAcl->setPermissionManage($currentUserAcl[2]);
|
||||
$this->permissionService->expects($this->at(0))
|
||||
->method('checkPermission')
|
||||
->with($this->boardMapper, 123, Acl::PERMISSION_SHARE, null);
|
||||
|
||||
if ($currentUserAcl[2]) {
|
||||
$this->permissionService->expects($this->at(1))
|
||||
$this->permissionService->expects($this->exactly(2))
|
||||
->method('checkPermission')
|
||||
->with($this->boardMapper, 123, Acl::PERMISSION_MANAGE, null);
|
||||
->withConsecutive(
|
||||
[$this->boardMapper, 123, Acl::PERMISSION_SHARE, null],
|
||||
[$this->boardMapper, 123, Acl::PERMISSION_MANAGE, null]
|
||||
);
|
||||
} else {
|
||||
$this->aclMapper->expects($this->once())
|
||||
->method('findAll')
|
||||
->willReturn([$existingAcl]);
|
||||
$this->permissionService->expects($this->at(1))
|
||||
|
||||
$this->permissionService->expects($this->exactly(2))
|
||||
->method('checkPermission')
|
||||
->with($this->boardMapper, 123, Acl::PERMISSION_MANAGE, null)
|
||||
->willThrowException(new NoPermissionException('No permission'));
|
||||
$this->permissionService->expects($this->at(2))
|
||||
->withConsecutive(
|
||||
[$this->boardMapper, 123, Acl::PERMISSION_SHARE, null],
|
||||
[$this->boardMapper, 123, Acl::PERMISSION_MANAGE, null]
|
||||
)
|
||||
->will(
|
||||
$this->onConsecutiveCalls(
|
||||
true,
|
||||
$this->throwException(new NoPermissionException('No permission'))
|
||||
)
|
||||
);
|
||||
|
||||
$this->permissionService->expects($this->exactly(3))
|
||||
->method('userCan')
|
||||
->willReturn($currentUserAcl[0]);
|
||||
$this->permissionService->expects($this->at(3))
|
||||
->method('userCan')
|
||||
->willReturn($currentUserAcl[1]);
|
||||
$this->permissionService->expects($this->at(4))
|
||||
->method('userCan')
|
||||
->willReturn($currentUserAcl[2]);
|
||||
->willReturnOnConsecutiveCalls(
|
||||
$currentUserAcl[0],
|
||||
$currentUserAcl[1],
|
||||
$currentUserAcl[2]
|
||||
);
|
||||
}
|
||||
|
||||
$user = $this->createMock(IUser::class);
|
||||
@@ -333,6 +352,11 @@ class BoardServiceTest extends TestCase {
|
||||
$acl->resolveRelation('participant', function ($participant) use (&$user) {
|
||||
return null;
|
||||
});
|
||||
$this->permissionService->expects($this->any())
|
||||
->method('findUsers')
|
||||
->willReturn([
|
||||
'admin' => 'admin',
|
||||
]);
|
||||
$this->notificationHelper->expects($this->once())
|
||||
->method('sendBoardShared');
|
||||
$expected = clone $acl;
|
||||
|
||||
@@ -139,13 +139,17 @@ class PermissionServiceTest extends \Test\TestCase {
|
||||
}
|
||||
|
||||
public function testUserIsBoardOwner() {
|
||||
$board = new Board();
|
||||
$board->setOwner('admin');
|
||||
$this->boardMapper->expects($this->at(0))->method('find')->with(123)->willReturn($board);
|
||||
$adminBoard = new Board();
|
||||
$adminBoard->setOwner('admin');
|
||||
$userBoard = new Board();
|
||||
$userBoard->setOwner('user1');
|
||||
|
||||
$this->boardMapper->expects($this->exactly(2))
|
||||
->method('find')
|
||||
->withConsecutive([123], [234])
|
||||
->willReturnOnConsecutiveCalls($adminBoard, $userBoard);
|
||||
|
||||
$this->assertEquals(true, $this->service->userIsBoardOwner(123));
|
||||
$board = new Board();
|
||||
$board->setOwner('user1');
|
||||
$this->boardMapper->expects($this->at(0))->method('find')->with(234)->willReturn($board);
|
||||
$this->assertEquals(false, $this->service->userIsBoardOwner(234));
|
||||
}
|
||||
|
||||
@@ -336,7 +340,7 @@ class PermissionServiceTest extends \Test\TestCase {
|
||||
$aclGroup->setParticipant('group1');
|
||||
|
||||
$board = $this->createMock(Board::class);
|
||||
$board->expects($this->at(0))
|
||||
$board->expects($this->once())
|
||||
->method('__call')
|
||||
->with('getOwner', [])
|
||||
->willReturn('user1');
|
||||
@@ -348,14 +352,11 @@ class PermissionServiceTest extends \Test\TestCase {
|
||||
->method('find')
|
||||
->with(123)
|
||||
->willReturn($board);
|
||||
$this->userManager->expects($this->at(0))
|
||||
$this->userManager->expects($this->exactly(2))
|
||||
->method('get')
|
||||
->with('user1')
|
||||
->willReturn($user1);
|
||||
$this->userManager->expects($this->at(1))
|
||||
->method('get')
|
||||
->with('user2')
|
||||
->willReturn($user2);
|
||||
->withConsecutive(['user1'], ['user2'])
|
||||
->willReturnOnConsecutiveCalls($user1, $user2);
|
||||
|
||||
$group = $this->createMock(IGroup::class);
|
||||
$group->expects($this->once())
|
||||
->method('getUsers')
|
||||
|
||||
Reference in New Issue
Block a user