From eb8a321637b678a9e72972470931cfa3d21f751d Mon Sep 17 00:00:00 2001 From: Sergey Shliakhov Date: Thu, 21 May 2020 15:17:31 +0200 Subject: [PATCH 01/33] Add deck:transfer-ownership command Signed-off-by: Sergey Shliakhov --- appinfo/info.xml | 1 + lib/Command/TransferOwnership.php | 63 +++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+) create mode 100644 lib/Command/TransferOwnership.php diff --git a/appinfo/info.xml b/appinfo/info.xml index ee8d2cbb8..ae298067d 100644 --- a/appinfo/info.xml +++ b/appinfo/info.xml @@ -44,6 +44,7 @@ OCA\Deck\Command\UserExport + OCA\Deck\Command\TransferOwnership diff --git a/lib/Command/TransferOwnership.php b/lib/Command/TransferOwnership.php new file mode 100644 index 000000000..e7b242efb --- /dev/null +++ b/lib/Command/TransferOwnership.php @@ -0,0 +1,63 @@ +setName('deck:transfer-ownership') + ->setDescription('Change owner of deck entities') + ->addArgument( + 'owner', + InputArgument::REQUIRED, + 'Owner uid' + ) + ->addArgument( + 'newOwner', + InputArgument::REQUIRED, + 'New owner uid' + ); + } + + protected function execute(InputInterface $input, OutputInterface $output) { + $owner = $input->getArgument('owner'); + $newOwner = $input->getArgument('newOwner'); + $db = \OC::$server->getDatabaseConnection(); + + $output->writeln("Transfer deck entities from $owner to $newOwner"); + $params = [ + 'owner' => $owner, + 'newOwner' => $newOwner + ]; + + $output->writeln('update oc_deck_assigned_users'); + $stmt = $db->prepare('UPDATE `oc_deck_assigned_users` SET `participant` = :newOwner WHERE `participant` = :owner'); + $stmt->execute($params); + + $output->writeln('update oc_deck_attachment'); + $stmt = $db->prepare('UPDATE `oc_deck_attachment` SET `created_by` = :newOwner WHERE `created_by` = :owner'); + $stmt->execute($params); + + $output->writeln('update oc_deck_boards'); + $stmt = $db->prepare('UPDATE `oc_deck_boards` SET `owner` = :newOwner WHERE `owner` = :owner'); + $stmt->execute($params); + + $output->writeln('update oc_deck_board_acl'); + $stmt = $db->prepare('UPDATE `oc_deck_board_acl` SET `participant` = :newOwner WHERE `participant` = :owner'); + $stmt->execute($params); + + $output->writeln('update oc_deck_cards'); + $stmt = $db->prepare('UPDATE `oc_deck_cards` SET `owner` = :newOwner WHERE `owner` = :owner'); + $stmt->execute($params); + + $output->writeln("Transfer deck entities from $owner to $newOwner completed"); + } + +} From fc9fa5dc2598a7af67619ffc02e4940b3d30543b Mon Sep 17 00:00:00 2001 From: Sergey Shliakhov Date: Mon, 25 May 2020 09:46:57 +0200 Subject: [PATCH 02/33] Update docs Signed-off-by: Sergey Shliakhov fix: conflicts --- docs/User_documentation_en.md | 5 +++ lib/Command/TransferOwnership.php | 52 +++++++++++-------------------- lib/Db/AclMapper.php | 17 ++++++++++ lib/Db/AssignmentMapper.php | 16 ++++++++++ lib/Db/BoardMapper.php | 16 ++++++++++ lib/Db/CardMapper.php | 16 ++++++++++ lib/Service/BoardService.php | 18 +++++++++++ 7 files changed, 107 insertions(+), 33 deletions(-) diff --git a/docs/User_documentation_en.md b/docs/User_documentation_en.md index 25ea8f8ee..040808f62 100644 --- a/docs/User_documentation_en.md +++ b/docs/User_documentation_en.md @@ -14,6 +14,7 @@ Overall, Deck is easy to use. You can create boards, add users, share the Deck, 3. [Handle cards options](#3-handle-cards-options) 4. [Archive old tasks](#4-archive-old-tasks) 5. [Manage your board](#5-manage-your-board) +6. [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. @@ -91,3 +92,7 @@ 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"`. + +### 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` +`$ php occ deck:transfer-ownership owner newOwner` diff --git a/lib/Command/TransferOwnership.php b/lib/Command/TransferOwnership.php index e7b242efb..e2a7c67ce 100644 --- a/lib/Command/TransferOwnership.php +++ b/lib/Command/TransferOwnership.php @@ -1,8 +1,8 @@ boardService = $boardService; + } + protected function configure() { $this ->setName('deck:transfer-ownership') @@ -19,45 +28,22 @@ final class TransferOwnership extends Command { InputArgument::REQUIRED, 'Owner uid' ) - ->addArgument( - 'newOwner', - InputArgument::REQUIRED, - 'New owner uid' - ); + ->addArgument( + 'newOwner', + InputArgument::REQUIRED, + 'New owner uid' + ); } protected function execute(InputInterface $input, OutputInterface $output) { $owner = $input->getArgument('owner'); $newOwner = $input->getArgument('newOwner'); - $db = \OC::$server->getDatabaseConnection(); - $output->writeln("Transfer deck entities from $owner to $newOwner"); - $params = [ - 'owner' => $owner, - 'newOwner' => $newOwner - ]; + $output->writeln("Transfer deck entities from $owner to $newOwner"); - $output->writeln('update oc_deck_assigned_users'); - $stmt = $db->prepare('UPDATE `oc_deck_assigned_users` SET `participant` = :newOwner WHERE `participant` = :owner'); - $stmt->execute($params); + $this->boardService->transferOwnership($owner, $newOwner); - $output->writeln('update oc_deck_attachment'); - $stmt = $db->prepare('UPDATE `oc_deck_attachment` SET `created_by` = :newOwner WHERE `created_by` = :owner'); - $stmt->execute($params); - - $output->writeln('update oc_deck_boards'); - $stmt = $db->prepare('UPDATE `oc_deck_boards` SET `owner` = :newOwner WHERE `owner` = :owner'); - $stmt->execute($params); - - $output->writeln('update oc_deck_board_acl'); - $stmt = $db->prepare('UPDATE `oc_deck_board_acl` SET `participant` = :newOwner WHERE `participant` = :owner'); - $stmt->execute($params); - - $output->writeln('update oc_deck_cards'); - $stmt = $db->prepare('UPDATE `oc_deck_cards` SET `owner` = :newOwner WHERE `owner` = :owner'); - $stmt->execute($params); - - $output->writeln("Transfer deck entities from $owner to $newOwner completed"); - } + $output->writeln("Transfer deck entities from $owner to $newOwner completed"); + } } diff --git a/lib/Db/AclMapper.php b/lib/Db/AclMapper.php index 4eb6a59c6..721ff1b6e 100644 --- a/lib/Db/AclMapper.php +++ b/lib/Db/AclMapper.php @@ -57,4 +57,21 @@ class AclMapper extends DeckMapper implements IPermissionMapper { $sql = 'SELECT * from *PREFIX*deck_board_acl WHERE type = ? AND participant = ?'; return $this->findEntities($sql, [$type, $participant]); } + + /** + * @param $ownerId + * @param $newOwnerId + * @return void + */ + public function transferOwnership($ownerId, $newOwnerId) + { + $params = [ + 'owner' => $ownerId, + 'newOwner' => $newOwnerId, + 'type' => Acl::PERMISSION_TYPE_USER + ]; + $sql = "UPDATE `{$this->tableName}` SET `participant` = :newOwner WHERE `participant` = :owner AND `type` = :type"; + $stmt = $this->execute($sql, $params); + $stmt->closeCursor(); + } } diff --git a/lib/Db/AssignmentMapper.php b/lib/Db/AssignmentMapper.php index 275dd1f77..5ed3ce115 100644 --- a/lib/Db/AssignmentMapper.php +++ b/lib/Db/AssignmentMapper.php @@ -146,4 +146,20 @@ class AssignmentMapper extends QBMapper implements IPermissionMapper { } return null; } + + /** + * @param $ownerId + * @param $newOwnerId + * @return void + */ + public function transferOwnership($ownerId, $newOwnerId) + { + $params = [ + 'owner' => $ownerId, + 'newOwner' => $newOwnerId + ]; + $sql = "UPDATE `{$this->tableName}` SET `participant` = :newOwner WHERE `participant` = :owner"; + $stmt = $this->execute($sql, $params); + $stmt->closeCursor(); + } } diff --git a/lib/Db/BoardMapper.php b/lib/Db/BoardMapper.php index 6b08000ba..4e0af34fe 100644 --- a/lib/Db/BoardMapper.php +++ b/lib/Db/BoardMapper.php @@ -475,4 +475,20 @@ class BoardMapper extends QBMapper implements IPermissionMapper { return null; }); } + + /** + * @param $ownerId + * @param $newOwnerId + * @return void + */ + public function transferOwnership($ownerId, $newOwnerId) + { + $params = [ + 'owner' => $ownerId, + 'newOwner' => $newOwnerId + ]; + $sql = "UPDATE `{$this->tableName}` SET `owner` = :newOwner WHERE `owner` = :owner"; + $stmt = $this->execute($sql, $params); + $stmt->closeCursor(); + } } diff --git a/lib/Db/CardMapper.php b/lib/Db/CardMapper.php index 529808f55..432862b05 100644 --- a/lib/Db/CardMapper.php +++ b/lib/Db/CardMapper.php @@ -586,4 +586,20 @@ class CardMapper extends QBMapper implements IPermissionMapper { return null; }); } + + /** + * @param $ownerId + * @param $newOwnerId + * @return void + */ + public function transferOwnership($ownerId, $newOwnerId) + { + $params = [ + 'owner' => $ownerId, + 'newOwner' => $newOwnerId + ]; + $sql = "UPDATE `{$this->tableName}` SET `owner` = :newOwner WHERE `owner` = :owner"; + $stmt = $this->execute($sql, $params); + $stmt->closeCursor(); + } } diff --git a/lib/Service/BoardService.php b/lib/Service/BoardService.php index 568299c53..9f81cc4c7 100644 --- a/lib/Service/BoardService.php +++ b/lib/Service/BoardService.php @@ -30,6 +30,7 @@ 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 +70,8 @@ class BoardService { private $activityManager; private $eventDispatcher; private $changeHelper; + private $cardMapper; + private $boardsCache = null; private $urlGenerator; @@ -83,6 +86,7 @@ class BoardService { PermissionService $permissionService, NotificationHelper $notificationHelper, AssignmentMapper $assignedUsersMapper, + CardMapper $cardMapper, IUserManager $userManager, IGroupManager $groupManager, ActivityManager $activityManager, @@ -107,6 +111,7 @@ class BoardService { $this->changeHelper = $changeHelper; $this->userId = $userId; $this->urlGenerator = $urlGenerator; + $this->cardMapper = $cardMapper; } /** @@ -673,6 +678,19 @@ class BoardService { return $newBoard; } + /** + * @param $ownerId + * @param $newOwnerId + * @return void + */ + public function transferOwnership($owner, $newOwner) + { + $this->boardMapper->transferOwnership($owner, $newOwner); + $this->assignedUsersMapper->transferOwnership($owner, $newOwner); + $this->aclMapper->transferOwnership($owner, $newOwner); + $this->cardMapper->transferOwnership($owner, $newOwner); + } + private function enrichWithStacks($board, $since = -1) { $stacks = $this->stackMapper->findAll($board->getId(), null, null, $since); From 53d462b3da35effdaccb21dccc48895cd49ed499 Mon Sep 17 00:00:00 2001 From: Sergey Shliakhov Date: Sun, 7 Jun 2020 16:11:36 +0200 Subject: [PATCH 03/33] Add tests Signed-off-by: Sergey Shliakhov --- .../database/TransferOwnershipTest.php | 144 ++++++++++++++++++ 1 file changed, 144 insertions(+) create mode 100644 tests/integration/database/TransferOwnershipTest.php diff --git a/tests/integration/database/TransferOwnershipTest.php b/tests/integration/database/TransferOwnershipTest.php new file mode 100644 index 000000000..132a79202 --- /dev/null +++ b/tests/integration/database/TransferOwnershipTest.php @@ -0,0 +1,144 @@ +getUserManager()->registerBackend($backend); + $backend->createUser(self::TEST_OWNER, self::TEST_OWNER); + $backend->createUser(self::TEST_NEW_OWNER, self::TEST_NEW_OWNER); + // create group + $groupBackend = new \Test\Util\Group\Dummy(); + $groupBackend->createGroup(self::TEST_GROUP); + $groupBackend->addToGroup(self::TEST_OWNER, self::TEST_GROUP); + \OC::$server->getGroupManager()->addBackend($groupBackend); + } + + public function setUp(): void { + parent::setUp(); + \OC::$server->getUserSession()->login(self::TEST_OWNER, self::TEST_OWNER); + $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->assignedUsersMapper = \OC::$server->query(AssignedUsersMapper::class); + $this->createBoardWithExampleData(); + } + + public function createBoardWithExampleData() { + $stacks = []; + $board = $this->boardService->create('Test', self::TEST_OWNER, '000000'); + $id = $board->getId(); + $this->boardService->addAcl($id, Acl::PERMISSION_TYPE_USER, self::TEST_OWNER, true, true, true); + $this->boardService->addAcl($id, Acl::PERMISSION_TYPE_GROUP, self::TEST_GROUP, true, true, true); + $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_OWNER); + $cards[] = $this->cardService->create('Card 2', $stacks[0]->getId(), 'text', 0, self::TEST_OWNER); + $this->assignmentService->assignUser($cards[0]->getId(), self::TEST_OWNER); + $this->board = $board; + $this->cards = $cards; + $this->stacks = $stacks; + } + + /** + * @covers ::transferOwnership + */ + public function testTransferBoardOwnership() + { + $this->boardService->transferOwnership(self::TEST_OWNER, self::TEST_NEW_OWNER); + $board = $this->boardService->find($this->board->getId()); + $boardOwner = $board->getOwner(); + $this->assertEquals(self::TEST_NEW_OWNER, $boardOwner); + } + + /** + * @covers ::transferOwnership + */ + public function testTransferACLOwnership() + { + $this->boardService->transferOwnership(self::TEST_OWNER, self::TEST_NEW_OWNER); + $board = $this->boardService->find($this->board->getId()); + $acl = $board->getAcl(); + $isTargetInAcl = (bool)array_filter($acl, function ($item) { + return $item->getParticipant() === self::TEST_NEW_OWNER && $item->getType() === Acl::PERMISSION_TYPE_USER; + }); + $this->assertTrue($isTargetInAcl); + } + + /** + * @covers ::transferOwnership + */ + public function testNoTransferAclOwnershipIfGroupType() + { + $this->boardService->transferOwnership(self::TEST_OWNER, self::TEST_NEW_OWNER); + $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() + { + $this->boardService->transferOwnership(self::TEST_OWNER, self::TEST_NEW_OWNER); + $card = $this->cardService->find($this->cards[0]->getId()); + $cardOwner = $card->getOwner(); + $this->assertEquals(self::TEST_NEW_OWNER, $cardOwner); + } + + /** + * @covers ::transferOwnership + */ + public function testReassignCardToNewOwner() + { + $this->boardService->transferOwnership(self::TEST_OWNER, self::TEST_NEW_OWNER); + $assignedUsers = $this->assignedUsersMapper->find($this->cards[0]->getId()); + $participantsUIDs = []; + foreach ($assignedUsers as $user) { + $participantsUIDs[] = $user->getParticipant(); + } + $this->assertContains(self::TEST_NEW_OWNER, $participantsUIDs); + $this->assertNotContains(self::TEST_OWNER, $participantsUIDs); + } + + public function tearDown(): void { + $this->boardService->deleteForce($this->board->getId()); + parent::tearDown(); + } +} From d52697823d27e58d1293a18b43507c6fbfc2fa4e Mon Sep 17 00:00:00 2001 From: Sergey Shliakhov Date: Sun, 7 Jun 2020 16:18:38 +0200 Subject: [PATCH 04/33] Fix code style Signed-off-by: Sergey Shliakhov --- lib/Command/TransferOwnership.php | 5 +- lib/Db/AclMapper.php | 3 +- lib/Db/AssignmentMapper.php | 3 +- lib/Db/BoardMapper.php | 29 ++-- lib/Db/CardMapper.php | 3 +- lib/Service/BoardService.php | 3 +- .../database/TransferOwnershipTest.php | 133 +++++++++--------- 7 files changed, 83 insertions(+), 96 deletions(-) diff --git a/lib/Command/TransferOwnership.php b/lib/Command/TransferOwnership.php index e2a7c67ce..c3175477e 100644 --- a/lib/Command/TransferOwnership.php +++ b/lib/Command/TransferOwnership.php @@ -9,11 +9,9 @@ use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; final class TransferOwnership extends Command { - protected $boardService; - public function __construct(BoardService $boardService) - { + public function __construct(BoardService $boardService) { parent::__construct(); $this->boardService = $boardService; @@ -45,5 +43,4 @@ final class TransferOwnership extends Command { $output->writeln("Transfer deck entities from $owner to $newOwner completed"); } - } diff --git a/lib/Db/AclMapper.php b/lib/Db/AclMapper.php index 721ff1b6e..48237ce03 100644 --- a/lib/Db/AclMapper.php +++ b/lib/Db/AclMapper.php @@ -63,8 +63,7 @@ class AclMapper extends DeckMapper implements IPermissionMapper { * @param $newOwnerId * @return void */ - public function transferOwnership($ownerId, $newOwnerId) - { + public function transferOwnership($ownerId, $newOwnerId) { $params = [ 'owner' => $ownerId, 'newOwner' => $newOwnerId, diff --git a/lib/Db/AssignmentMapper.php b/lib/Db/AssignmentMapper.php index 5ed3ce115..7a7f368ae 100644 --- a/lib/Db/AssignmentMapper.php +++ b/lib/Db/AssignmentMapper.php @@ -152,8 +152,7 @@ class AssignmentMapper extends QBMapper implements IPermissionMapper { * @param $newOwnerId * @return void */ - public function transferOwnership($ownerId, $newOwnerId) - { + public function transferOwnership($ownerId, $newOwnerId) { $params = [ 'owner' => $ownerId, 'newOwner' => $newOwnerId diff --git a/lib/Db/BoardMapper.php b/lib/Db/BoardMapper.php index 4e0af34fe..fc5455ef4 100644 --- a/lib/Db/BoardMapper.php +++ b/lib/Db/BoardMapper.php @@ -476,19 +476,18 @@ class BoardMapper extends QBMapper implements IPermissionMapper { }); } - /** - * @param $ownerId - * @param $newOwnerId - * @return void - */ - public function transferOwnership($ownerId, $newOwnerId) - { - $params = [ - 'owner' => $ownerId, - 'newOwner' => $newOwnerId - ]; - $sql = "UPDATE `{$this->tableName}` SET `owner` = :newOwner WHERE `owner` = :owner"; - $stmt = $this->execute($sql, $params); - $stmt->closeCursor(); - } + /** + * @param $ownerId + * @param $newOwnerId + * @return void + */ + public function transferOwnership($ownerId, $newOwnerId) { + $params = [ + 'owner' => $ownerId, + 'newOwner' => $newOwnerId + ]; + $sql = "UPDATE `{$this->tableName}` SET `owner` = :newOwner WHERE `owner` = :owner"; + $stmt = $this->execute($sql, $params); + $stmt->closeCursor(); + } } diff --git a/lib/Db/CardMapper.php b/lib/Db/CardMapper.php index 432862b05..2b2469c87 100644 --- a/lib/Db/CardMapper.php +++ b/lib/Db/CardMapper.php @@ -592,8 +592,7 @@ class CardMapper extends QBMapper implements IPermissionMapper { * @param $newOwnerId * @return void */ - public function transferOwnership($ownerId, $newOwnerId) - { + public function transferOwnership($ownerId, $newOwnerId) { $params = [ 'owner' => $ownerId, 'newOwner' => $newOwnerId diff --git a/lib/Service/BoardService.php b/lib/Service/BoardService.php index 9f81cc4c7..1a9969e4f 100644 --- a/lib/Service/BoardService.php +++ b/lib/Service/BoardService.php @@ -683,8 +683,7 @@ class BoardService { * @param $newOwnerId * @return void */ - public function transferOwnership($owner, $newOwner) - { + public function transferOwnership($owner, $newOwner) { $this->boardMapper->transferOwnership($owner, $newOwner); $this->assignedUsersMapper->transferOwnership($owner, $newOwner); $this->aclMapper->transferOwnership($owner, $newOwner); diff --git a/tests/integration/database/TransferOwnershipTest.php b/tests/integration/database/TransferOwnershipTest.php index 132a79202..0a8132532 100644 --- a/tests/integration/database/TransferOwnershipTest.php +++ b/tests/integration/database/TransferOwnershipTest.php @@ -25,12 +25,12 @@ class AssignedUsersMapperTest extends \Test\TestCase { protected $assignedUsersMapper; /** @var AssignmentService */ private $assignmentService; - /** @var Board */ - private $board; - private $cards; - private $stacks; + /** @var Board */ + private $board; + private $cards; + private $stacks; - public static function setUpBeforeClass(): void { + public static function setUpBeforeClass(): void { parent::setUpBeforeClass(); $backend = new \Test\Util\User\Dummy(); @@ -60,82 +60,77 @@ class AssignedUsersMapperTest extends \Test\TestCase { $stacks = []; $board = $this->boardService->create('Test', self::TEST_OWNER, '000000'); $id = $board->getId(); - $this->boardService->addAcl($id, Acl::PERMISSION_TYPE_USER, self::TEST_OWNER, 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_OWNER, true, true, true); + $this->boardService->addAcl($id, Acl::PERMISSION_TYPE_GROUP, self::TEST_GROUP, true, true, true); $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_OWNER); $cards[] = $this->cardService->create('Card 2', $stacks[0]->getId(), 'text', 0, self::TEST_OWNER); - $this->assignmentService->assignUser($cards[0]->getId(), self::TEST_OWNER); - $this->board = $board; + $this->assignmentService->assignUser($cards[0]->getId(), self::TEST_OWNER); + $this->board = $board; $this->cards = $cards; $this->stacks = $stacks; } - /** - * @covers ::transferOwnership - */ - public function testTransferBoardOwnership() - { - $this->boardService->transferOwnership(self::TEST_OWNER, self::TEST_NEW_OWNER); - $board = $this->boardService->find($this->board->getId()); - $boardOwner = $board->getOwner(); - $this->assertEquals(self::TEST_NEW_OWNER, $boardOwner); - } + /** + * @covers ::transferOwnership + */ + public function testTransferBoardOwnership() { + $this->boardService->transferOwnership(self::TEST_OWNER, self::TEST_NEW_OWNER); + $board = $this->boardService->find($this->board->getId()); + $boardOwner = $board->getOwner(); + $this->assertEquals(self::TEST_NEW_OWNER, $boardOwner); + } - /** - * @covers ::transferOwnership - */ - public function testTransferACLOwnership() - { - $this->boardService->transferOwnership(self::TEST_OWNER, self::TEST_NEW_OWNER); - $board = $this->boardService->find($this->board->getId()); - $acl = $board->getAcl(); - $isTargetInAcl = (bool)array_filter($acl, function ($item) { - return $item->getParticipant() === self::TEST_NEW_OWNER && $item->getType() === Acl::PERMISSION_TYPE_USER; - }); - $this->assertTrue($isTargetInAcl); - } + /** + * @covers ::transferOwnership + */ + public function testTransferACLOwnership() { + $this->boardService->transferOwnership(self::TEST_OWNER, self::TEST_NEW_OWNER); + $board = $this->boardService->find($this->board->getId()); + $acl = $board->getAcl(); + $isTargetInAcl = (bool)array_filter($acl, function ($item) { + return $item->getParticipant() === self::TEST_NEW_OWNER && $item->getType() === Acl::PERMISSION_TYPE_USER; + }); + $this->assertTrue($isTargetInAcl); + } - /** - * @covers ::transferOwnership - */ - public function testNoTransferAclOwnershipIfGroupType() - { - $this->boardService->transferOwnership(self::TEST_OWNER, self::TEST_NEW_OWNER); - $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() - { - $this->boardService->transferOwnership(self::TEST_OWNER, self::TEST_NEW_OWNER); - $card = $this->cardService->find($this->cards[0]->getId()); - $cardOwner = $card->getOwner(); - $this->assertEquals(self::TEST_NEW_OWNER, $cardOwner); - } + /** + * @covers ::transferOwnership + */ + public function testNoTransferAclOwnershipIfGroupType() { + $this->boardService->transferOwnership(self::TEST_OWNER, self::TEST_NEW_OWNER); + $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() { + $this->boardService->transferOwnership(self::TEST_OWNER, self::TEST_NEW_OWNER); + $card = $this->cardService->find($this->cards[0]->getId()); + $cardOwner = $card->getOwner(); + $this->assertEquals(self::TEST_NEW_OWNER, $cardOwner); + } - /** - * @covers ::transferOwnership - */ - public function testReassignCardToNewOwner() - { - $this->boardService->transferOwnership(self::TEST_OWNER, self::TEST_NEW_OWNER); - $assignedUsers = $this->assignedUsersMapper->find($this->cards[0]->getId()); - $participantsUIDs = []; - foreach ($assignedUsers as $user) { - $participantsUIDs[] = $user->getParticipant(); - } - $this->assertContains(self::TEST_NEW_OWNER, $participantsUIDs); - $this->assertNotContains(self::TEST_OWNER, $participantsUIDs); - } + /** + * @covers ::transferOwnership + */ + public function testReassignCardToNewOwner() { + $this->boardService->transferOwnership(self::TEST_OWNER, self::TEST_NEW_OWNER); + $assignedUsers = $this->assignedUsersMapper->find($this->cards[0]->getId()); + $participantsUIDs = []; + foreach ($assignedUsers as $user) { + $participantsUIDs[] = $user->getParticipant(); + } + $this->assertContains(self::TEST_NEW_OWNER, $participantsUIDs); + $this->assertNotContains(self::TEST_OWNER, $participantsUIDs); + } public function tearDown(): void { $this->boardService->deleteForce($this->board->getId()); From ce85b4378f6c3f03288f3000719c375b136782ad Mon Sep 17 00:00:00 2001 From: Sergey Shliakhov Date: Mon, 8 Jun 2020 14:06:50 +0200 Subject: [PATCH 05/33] Fix wrong class name Signed-off-by: Sergey Shliakhov --- .../database/TransferOwnershipTest.php | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/tests/integration/database/TransferOwnershipTest.php b/tests/integration/database/TransferOwnershipTest.php index 0a8132532..e49e409b4 100644 --- a/tests/integration/database/TransferOwnershipTest.php +++ b/tests/integration/database/TransferOwnershipTest.php @@ -10,7 +10,7 @@ use OCA\Deck\Db\Board; * @group DB * @coversDefaultClass OCA\Deck\Service\BoardService */ -class AssignedUsersMapperTest extends \Test\TestCase { +class TransferOwnershipTest extends \Test\TestCase { private const TEST_OWNER = 'test-share-user1'; private const TEST_NEW_OWNER = 'target'; private const TEST_GROUP = 'test-share-user1'; @@ -132,6 +132,21 @@ class AssignedUsersMapperTest extends \Test\TestCase { $this->assertNotContains(self::TEST_OWNER, $participantsUIDs); } + /** + * @covers ::transferOwnership + */ + public function testReassignCardToNewParticipantOnlyIfParticipantHasUserType() { + $this->boardService->transferOwnership(self::TEST_OWNER, self::TEST_NEW_OWNER); + $this->assignmentService->ass($cards[0]->getId(), self::TEST_OWNER); + $assignedUsers = $this->assignedUsersMapper->find($this->cards[0]->getId()); + $participantsUIDs = []; + foreach ($assignedUsers as $user) { + $participantsUIDs[] = $user->getParticipant(); + } + $this->assertContains(self::TEST_NEW_OWNER, $participantsUIDs); + $this->assertNotContains(self::TEST_OWNER, $participantsUIDs); + } + public function tearDown(): void { $this->boardService->deleteForce($this->board->getId()); parent::tearDown(); From 36a9d2e95cec5cc735fa30c4bf07b9fadb34e35b Mon Sep 17 00:00:00 2001 From: Sergey Shliakhov Date: Tue, 9 Jun 2020 05:21:24 +0200 Subject: [PATCH 06/33] Check type before transfer card participants ownership Signed-off-by: Sergey Shliakhov temp --- Makefile | 3 +-- lib/Db/AssignmentMapper.php | 5 +++-- tests/integration/config/behat.yml | 2 +- .../database/TransferOwnershipTest.php | 21 ++++++++++++++++++- tests/integration/run.sh | 2 +- tests/unit/Service/BoardServiceTest.php | 5 +++++ 6 files changed, 31 insertions(+), 7 deletions(-) diff --git a/Makefile b/Makefile index 54930c6b6..8d428a7d3 100644 --- a/Makefile +++ b/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: diff --git a/lib/Db/AssignmentMapper.php b/lib/Db/AssignmentMapper.php index 7a7f368ae..5bc49e40d 100644 --- a/lib/Db/AssignmentMapper.php +++ b/lib/Db/AssignmentMapper.php @@ -155,9 +155,10 @@ class AssignmentMapper extends QBMapper implements IPermissionMapper { public function transferOwnership($ownerId, $newOwnerId) { $params = [ 'owner' => $ownerId, - 'newOwner' => $newOwnerId + 'newOwner' => $newOwnerId, + 'type' => AssignedUsers::TYPE_USER ]; - $sql = "UPDATE `{$this->tableName}` SET `participant` = :newOwner WHERE `participant` = :owner"; + $sql = "UPDATE `{$this->tableName}` SET `participant` = :newOwner WHERE `participant` = :owner AND `type`= :type"; $stmt = $this->execute($sql, $params); $stmt->closeCursor(); } diff --git a/tests/integration/config/behat.yml b/tests/integration/config/behat.yml index b8673a677..507138122 100644 --- a/tests/integration/config/behat.yml +++ b/tests/integration/config/behat.yml @@ -5,7 +5,7 @@ default: - '%paths.base%/../features/' contexts: - ServerContext: - baseUrl: http://localhost:8080/ + baseUrl: http://localhost:9090/ - RequestContext - BoardContext - CommentContext diff --git a/tests/integration/database/TransferOwnershipTest.php b/tests/integration/database/TransferOwnershipTest.php index e49e409b4..aff664640 100644 --- a/tests/integration/database/TransferOwnershipTest.php +++ b/tests/integration/database/TransferOwnershipTest.php @@ -13,6 +13,8 @@ use OCA\Deck\Db\Board; class TransferOwnershipTest extends \Test\TestCase { private const TEST_OWNER = 'test-share-user1'; private const TEST_NEW_OWNER = 'target'; + private const TEST_NEW_OWNER_PARTICIPANT = 'target-participant'; + private const TEST_NEW_OWNER_IN_ACL = 'target-in-acl'; private const TEST_GROUP = 'test-share-user1'; /** @var BoardService */ @@ -38,6 +40,7 @@ class TransferOwnershipTest extends \Test\TestCase { \OC::$server->getUserManager()->registerBackend($backend); $backend->createUser(self::TEST_OWNER, self::TEST_OWNER); $backend->createUser(self::TEST_NEW_OWNER, self::TEST_NEW_OWNER); + $backend->createUser(self::TEST_NEW_OWNER_PARTICIPANT, self::TEST_NEW_OWNER_PARTICIPANT); // create group $groupBackend = new \Test\Util\Group\Dummy(); $groupBackend->createGroup(self::TEST_GROUP); @@ -68,6 +71,7 @@ class TransferOwnershipTest extends \Test\TestCase { $cards[] = $this->cardService->create('Card 1', $stacks[0]->getId(), 'text', 0, self::TEST_OWNER); $cards[] = $this->cardService->create('Card 2', $stacks[0]->getId(), 'text', 0, self::TEST_OWNER); $this->assignmentService->assignUser($cards[0]->getId(), self::TEST_OWNER); + $this->assignmentService->assignUser($cards[0]->getId(), self::TEST_NEW_OWNER_PARTICIPANT); $this->board = $board; $this->cards = $cards; $this->stacks = $stacks; @@ -137,7 +141,22 @@ class TransferOwnershipTest extends \Test\TestCase { */ public function testReassignCardToNewParticipantOnlyIfParticipantHasUserType() { $this->boardService->transferOwnership(self::TEST_OWNER, self::TEST_NEW_OWNER); - $this->assignmentService->ass($cards[0]->getId(), self::TEST_OWNER); + $this->assignmentService->ass($this->cards[0]->getId(), self::TEST_OWNER); + $assignedUsers = $this->assignedUsersMapper->find($this->cards[0]->getId()); + $participantsUIDs = []; + foreach ($assignedUsers as $user) { + $participantsUIDs[] = $user->getParticipant(); + } + $this->assertContains(self::TEST_NEW_OWNER, $participantsUIDs); + $this->assertNotContains(self::TEST_OWNER, $participantsUIDs); + } + + /** + * @covers ::transferOwnership + */ + public function testTargetAlreadyParticipantOfTransferedCard() { + $this->boardService->transferOwnership(self::TEST_OWNER, self::TEST_NEW_OWNER_PARTICIPANT); + $this->assignmentService->assignUser($this->cards[0]->getId(), self::TEST_OWNER); $assignedUsers = $this->assignedUsersMapper->find($this->cards[0]->getId()); $participantsUIDs = []; foreach ($assignedUsers as $user) { diff --git a/tests/integration/run.sh b/tests/integration/run.sh index ab9790b26..de8b32563 100755 --- a/tests/integration/run.sh +++ b/tests/integration/run.sh @@ -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=$! diff --git a/tests/unit/Service/BoardServiceTest.php b/tests/unit/Service/BoardServiceTest.php index e59662489..c64422ff5 100644 --- a/tests/unit/Service/BoardServiceTest.php +++ b/tests/unit/Service/BoardServiceTest.php @@ -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, From e70e7128c017240f9dd3bc2e87ea5fe300270e28 Mon Sep 17 00:00:00 2001 From: Sergey Shliakhov Date: Sat, 18 Jul 2020 07:40:47 +0300 Subject: [PATCH 07/33] Transfer deck ownership even if target user already participant of a board https://github.com/nextcloud/deck/pull/1955#issuecomment-640392715 Signed-off-by: Sergey Shliakhov --- lib/Db/AclMapper.php | 36 ++++-- lib/Db/AssignmentMapper.php | 9 +- lib/Service/BoardService.php | 6 +- .../database/TransferOwnershipTest.php | 115 +++++++++++------- 4 files changed, 113 insertions(+), 53 deletions(-) diff --git a/lib/Db/AclMapper.php b/lib/Db/AclMapper.php index 48237ce03..42aec5c4a 100644 --- a/lib/Db/AclMapper.php +++ b/lib/Db/AclMapper.php @@ -64,13 +64,33 @@ class AclMapper extends DeckMapper implements IPermissionMapper { * @return void */ public function transferOwnership($ownerId, $newOwnerId) { - $params = [ - 'owner' => $ownerId, - 'newOwner' => $newOwnerId, - 'type' => Acl::PERMISSION_TYPE_USER - ]; - $sql = "UPDATE `{$this->tableName}` SET `participant` = :newOwner WHERE `participant` = :owner AND `type` = :type"; - $stmt = $this->execute($sql, $params); - $stmt->closeCursor(); + $params = [ + 'owner' => $ownerId, + 'newOwner' => $newOwnerId, + 'type' => Acl::PERMISSION_TYPE_USER + ]; + //We want preserve permissions from both users + $sql = "UPDATE `{$this->tableName}` AS `source` + LEFT JOIN `{$this->tableName}` AS `target` + ON `target`.`participant` = :newOwner AND `target`.`type` = :type + SET `source`.`permission_edit` =(`source`.`permission_edit` || `target`.`permission_edit`), + `source`.`permission_share` =(`source`.`permission_share` || `target`.`permission_share`), + `source`.`permission_manage` =(`source`.`permission_manage` || `target`.`permission_manage`) + WHERE `source`.`participant` = :owner AND `source`.`type` = :type"; + $stmt = $this->execute($sql, $params); + $stmt->closeCursor(); + //We can't transfer acl if target already in acl + $sql = "DELETE FROM `{$this->tableName}` + WHERE `participant` = :newOwner + AND `type` = :type + AND EXISTS (SELECT `id` FROM (SELECT `id` FROM `{$this->tableName}` + WHERE `participant` = :owner AND `type` = :type) as tmp)"; + $stmt = $this->execute($sql, $params); + $stmt->closeCursor(); + //Now we can transfer without errors + $sqlUpdate = "UPDATE `{$this->tableName}` + SET `participant` = :newOwner WHERE `participant` = :owner AND `type` = :type"; + $stmt = $this->execute($sqlUpdate, $params); + $stmt->closeCursor(); } } diff --git a/lib/Db/AssignmentMapper.php b/lib/Db/AssignmentMapper.php index 5bc49e40d..d783cdedb 100644 --- a/lib/Db/AssignmentMapper.php +++ b/lib/Db/AssignmentMapper.php @@ -154,10 +154,17 @@ class AssignmentMapper extends QBMapper implements IPermissionMapper { */ public function transferOwnership($ownerId, $newOwnerId) { $params = [ - 'owner' => $ownerId, 'newOwner' => $newOwnerId, 'type' => AssignedUsers::TYPE_USER ]; + $sql = "DELETE FROM `{$this->tableName}` WHERE `participant` = :newOwner AND `type`= :type"; + $stmt = $this->execute($sql, $params); + $stmt->closeCursor(); + $params = [ + 'owner' => $ownerId, + 'newOwner' => $newOwnerId, + 'type' => AssignedUsers::TYPE_USER + ]; $sql = "UPDATE `{$this->tableName}` SET `participant` = :newOwner WHERE `participant` = :owner AND `type`= :type"; $stmt = $this->execute($sql, $params); $stmt->closeCursor(); diff --git a/lib/Service/BoardService.php b/lib/Service/BoardService.php index 1a9969e4f..bbcc351e8 100644 --- a/lib/Service/BoardService.php +++ b/lib/Service/BoardService.php @@ -685,9 +685,9 @@ class BoardService { */ public function transferOwnership($owner, $newOwner) { $this->boardMapper->transferOwnership($owner, $newOwner); - $this->assignedUsersMapper->transferOwnership($owner, $newOwner); - $this->aclMapper->transferOwnership($owner, $newOwner); - $this->cardMapper->transferOwnership($owner, $newOwner); + $this->aclMapper->transferOwnership($owner, $newOwner); + $this->assignedUsersMapper->transferOwnership($owner, $newOwner); + $this->cardMapper->transferOwnership($owner, $newOwner); } private function enrichWithStacks($board, $since = -1) { diff --git a/tests/integration/database/TransferOwnershipTest.php b/tests/integration/database/TransferOwnershipTest.php index aff664640..459615860 100644 --- a/tests/integration/database/TransferOwnershipTest.php +++ b/tests/integration/database/TransferOwnershipTest.php @@ -3,6 +3,7 @@ namespace OCA\Deck\Service; use OCA\Deck\Db\Acl; +use OCA\Deck\Db\AssignedUsers; use OCA\Deck\Db\AssignedUsersMapper; use OCA\Deck\Db\Board; @@ -11,10 +12,9 @@ use OCA\Deck\Db\Board; * @coversDefaultClass OCA\Deck\Service\BoardService */ class TransferOwnershipTest extends \Test\TestCase { - private const TEST_OWNER = 'test-share-user1'; - private const TEST_NEW_OWNER = 'target'; - private const TEST_NEW_OWNER_PARTICIPANT = 'target-participant'; - private const TEST_NEW_OWNER_IN_ACL = 'target-in-acl'; + 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 */ @@ -38,19 +38,19 @@ class TransferOwnershipTest extends \Test\TestCase { $backend = new \Test\Util\User\Dummy(); \OC_User::useBackend($backend); \OC::$server->getUserManager()->registerBackend($backend); - $backend->createUser(self::TEST_OWNER, self::TEST_OWNER); - $backend->createUser(self::TEST_NEW_OWNER, self::TEST_NEW_OWNER); - $backend->createUser(self::TEST_NEW_OWNER_PARTICIPANT, self::TEST_NEW_OWNER_PARTICIPANT); + $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_OWNER, 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_OWNER, self::TEST_OWNER); + \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); @@ -61,17 +61,17 @@ class TransferOwnershipTest extends \Test\TestCase { public function createBoardWithExampleData() { $stacks = []; - $board = $this->boardService->create('Test', self::TEST_OWNER, '000000'); + $board = $this->boardService->create('Test', self::TEST_USER_1, '000000'); $id = $board->getId(); - $this->boardService->addAcl($id, Acl::PERMISSION_TYPE_USER, self::TEST_OWNER, true, true, true); + $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); - $stacks[] = $this->stackService->create('Stack A', $id, 1); + $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_OWNER); - $cards[] = $this->cardService->create('Card 2', $stacks[0]->getId(), 'text', 0, self::TEST_OWNER); - $this->assignmentService->assignUser($cards[0]->getId(), self::TEST_OWNER); - $this->assignmentService->assignUser($cards[0]->getId(), self::TEST_NEW_OWNER_PARTICIPANT); + $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; @@ -81,21 +81,21 @@ class TransferOwnershipTest extends \Test\TestCase { * @covers ::transferOwnership */ public function testTransferBoardOwnership() { - $this->boardService->transferOwnership(self::TEST_OWNER, self::TEST_NEW_OWNER); + $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_NEW_OWNER, $boardOwner); + $this->assertEquals(self::TEST_USER_2, $boardOwner); } /** * @covers ::transferOwnership */ public function testTransferACLOwnership() { - $this->boardService->transferOwnership(self::TEST_OWNER, self::TEST_NEW_OWNER); + $this->boardService->transferOwnership(self::TEST_USER_1, self::TEST_USER_2); $board = $this->boardService->find($this->board->getId()); $acl = $board->getAcl(); $isTargetInAcl = (bool)array_filter($acl, function ($item) { - return $item->getParticipant() === self::TEST_NEW_OWNER && $item->getType() === Acl::PERMISSION_TYPE_USER; + return $item->getParticipant() === self::TEST_USER_2 && $item->getType() === Acl::PERMISSION_TYPE_USER; }); $this->assertTrue($isTargetInAcl); } @@ -104,7 +104,7 @@ class TransferOwnershipTest extends \Test\TestCase { * @covers ::transferOwnership */ public function testNoTransferAclOwnershipIfGroupType() { - $this->boardService->transferOwnership(self::TEST_OWNER, self::TEST_NEW_OWNER); + $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) { @@ -116,54 +116,87 @@ class TransferOwnershipTest extends \Test\TestCase { * @covers ::transferOwnership */ public function testTransferCardOwnership() { - $this->boardService->transferOwnership(self::TEST_OWNER, self::TEST_NEW_OWNER); + $this->boardService->transferOwnership(self::TEST_USER_1, self::TEST_USER_2); $card = $this->cardService->find($this->cards[0]->getId()); $cardOwner = $card->getOwner(); - $this->assertEquals(self::TEST_NEW_OWNER, $cardOwner); + $this->assertEquals(self::TEST_USER_2, $cardOwner); } /** * @covers ::transferOwnership */ public function testReassignCardToNewOwner() { - $this->boardService->transferOwnership(self::TEST_OWNER, self::TEST_NEW_OWNER); + $this->boardService->transferOwnership(self::TEST_USER_1, self::TEST_USER_2); $assignedUsers = $this->assignedUsersMapper->find($this->cards[0]->getId()); $participantsUIDs = []; foreach ($assignedUsers as $user) { $participantsUIDs[] = $user->getParticipant(); } - $this->assertContains(self::TEST_NEW_OWNER, $participantsUIDs); - $this->assertNotContains(self::TEST_OWNER, $participantsUIDs); + $this->assertContains(self::TEST_USER_2, $participantsUIDs); + $this->assertNotContains(self::TEST_USER_1, $participantsUIDs); } /** * @covers ::transferOwnership */ public function testReassignCardToNewParticipantOnlyIfParticipantHasUserType() { - $this->boardService->transferOwnership(self::TEST_OWNER, self::TEST_NEW_OWNER); - $this->assignmentService->ass($this->cards[0]->getId(), self::TEST_OWNER); - $assignedUsers = $this->assignedUsersMapper->find($this->cards[0]->getId()); + $this->assignmentService->assignUser($this->cards[1]->getId(), self::TEST_USER_1, AssignedUsers::TYPE_GROUP); + $this->boardService->transferOwnership(self::TEST_USER_1, self::TEST_USER_2); + $assignedUsers = $this->assignedUsersMapper->find($this->cards[1]->getId()); $participantsUIDs = []; foreach ($assignedUsers as $user) { $participantsUIDs[] = $user->getParticipant(); } - $this->assertContains(self::TEST_NEW_OWNER, $participantsUIDs); - $this->assertNotContains(self::TEST_OWNER, $participantsUIDs); + $this->assertContains(self::TEST_USER_1, $participantsUIDs); + $this->assertNotContains(self::TEST_USER_2, $participantsUIDs); } /** * @covers ::transferOwnership */ - public function testTargetAlreadyParticipantOfTransferedCard() { - $this->boardService->transferOwnership(self::TEST_OWNER, self::TEST_NEW_OWNER_PARTICIPANT); - $this->assignmentService->assignUser($this->cards[0]->getId(), self::TEST_OWNER); - $assignedUsers = $this->assignedUsersMapper->find($this->cards[0]->getId()); - $participantsUIDs = []; - foreach ($assignedUsers as $user) { - $participantsUIDs[] = $user->getParticipant(); - } - $this->assertContains(self::TEST_NEW_OWNER, $participantsUIDs); - $this->assertNotContains(self::TEST_OWNER, $participantsUIDs); + public function testTargetAlreadyParticipantOfBoard() { + $this->expectNotToPerformAssertions(); + $this->boardService->transferOwnership(self::TEST_USER_1, self::TEST_USER_3); + } + + /** + * @covers ::transferOwnership + */ + public function testDontRemoveTargetFromAcl() { + $this->boardService->transferOwnership(self::TEST_USER_2, self::TEST_USER_3); + $board = $this->boardService->find($this->board->getId()); + $acl = $board->getAcl(); + $isOwnerInAcl = (bool)array_filter($acl, function ($item) { + return $item->getParticipant() === self::TEST_USER_3 && $item->getType() === Acl::PERMISSION_TYPE_USER; + }); + $this->assertTrue($isOwnerInAcl); + } + + /** + * @covers ::transferOwnership + */ + public function testMergePermissions() { + $this->boardService->addAcl($this->board->getId(), Acl::PERMISSION_TYPE_USER, self::TEST_USER_2, true, false, true); + $this->boardService->transferOwnership(self::TEST_USER_2, 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, AssignedUsers::TYPE_USER); + $this->boardService->transferOwnership(self::TEST_USER_1, self::TEST_USER_3); } public function tearDown(): void { From 16413735d215352f848c68ae46f1f0a9c40a3c35 Mon Sep 17 00:00:00 2001 From: Sergey Shliakhov Date: Sat, 18 Jul 2020 09:02:28 +0300 Subject: [PATCH 08/33] Fix coding styles MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julius Härtl Signed-off-by: Max --- lib/Db/AclMapper.php | 32 ++--- lib/Db/AssignmentMapper.php | 18 +-- lib/Service/BoardService.php | 6 +- .../database/TransferOwnershipTest.php | 118 +++++++++--------- tests/unit/Service/BoardServiceTest.php | 4 +- 5 files changed, 89 insertions(+), 89 deletions(-) diff --git a/lib/Db/AclMapper.php b/lib/Db/AclMapper.php index 42aec5c4a..d34738d82 100644 --- a/lib/Db/AclMapper.php +++ b/lib/Db/AclMapper.php @@ -64,33 +64,33 @@ class AclMapper extends DeckMapper implements IPermissionMapper { * @return void */ public function transferOwnership($ownerId, $newOwnerId) { - $params = [ - 'owner' => $ownerId, - 'newOwner' => $newOwnerId, - 'type' => Acl::PERMISSION_TYPE_USER - ]; + $params = [ + 'owner' => $ownerId, + 'newOwner' => $newOwnerId, + 'type' => Acl::PERMISSION_TYPE_USER + ]; //We want preserve permissions from both users - $sql = "UPDATE `{$this->tableName}` AS `source` + $sql = "UPDATE `{$this->tableName}` AS `source` LEFT JOIN `{$this->tableName}` AS `target` ON `target`.`participant` = :newOwner AND `target`.`type` = :type SET `source`.`permission_edit` =(`source`.`permission_edit` || `target`.`permission_edit`), `source`.`permission_share` =(`source`.`permission_share` || `target`.`permission_share`), `source`.`permission_manage` =(`source`.`permission_manage` || `target`.`permission_manage`) WHERE `source`.`participant` = :owner AND `source`.`type` = :type"; - $stmt = $this->execute($sql, $params); - $stmt->closeCursor(); - //We can't transfer acl if target already in acl - $sql = "DELETE FROM `{$this->tableName}` + $stmt = $this->execute($sql, $params); + $stmt->closeCursor(); + //We can't transfer acl if target already in acl + $sql = "DELETE FROM `{$this->tableName}` WHERE `participant` = :newOwner AND `type` = :type AND EXISTS (SELECT `id` FROM (SELECT `id` FROM `{$this->tableName}` WHERE `participant` = :owner AND `type` = :type) as tmp)"; - $stmt = $this->execute($sql, $params); - $stmt->closeCursor(); - //Now we can transfer without errors - $sqlUpdate = "UPDATE `{$this->tableName}` + $stmt = $this->execute($sql, $params); + $stmt->closeCursor(); + //Now we can transfer without errors + $sqlUpdate = "UPDATE `{$this->tableName}` SET `participant` = :newOwner WHERE `participant` = :owner AND `type` = :type"; - $stmt = $this->execute($sqlUpdate, $params); - $stmt->closeCursor(); + $stmt = $this->execute($sqlUpdate, $params); + $stmt->closeCursor(); } } diff --git a/lib/Db/AssignmentMapper.php b/lib/Db/AssignmentMapper.php index d783cdedb..1c5e43819 100644 --- a/lib/Db/AssignmentMapper.php +++ b/lib/Db/AssignmentMapper.php @@ -155,16 +155,16 @@ class AssignmentMapper extends QBMapper implements IPermissionMapper { public function transferOwnership($ownerId, $newOwnerId) { $params = [ 'newOwner' => $newOwnerId, - 'type' => AssignedUsers::TYPE_USER + 'type' => AssignedUsers::TYPE_USER + ]; + $sql = "DELETE FROM `{$this->tableName}` WHERE `participant` = :newOwner AND `type`= :type"; + $stmt = $this->execute($sql, $params); + $stmt->closeCursor(); + $params = [ + 'owner' => $ownerId, + 'newOwner' => $newOwnerId, + 'type' => AssignedUsers::TYPE_USER ]; - $sql = "DELETE FROM `{$this->tableName}` WHERE `participant` = :newOwner AND `type`= :type"; - $stmt = $this->execute($sql, $params); - $stmt->closeCursor(); - $params = [ - 'owner' => $ownerId, - 'newOwner' => $newOwnerId, - 'type' => AssignedUsers::TYPE_USER - ]; $sql = "UPDATE `{$this->tableName}` SET `participant` = :newOwner WHERE `participant` = :owner AND `type`= :type"; $stmt = $this->execute($sql, $params); $stmt->closeCursor(); diff --git a/lib/Service/BoardService.php b/lib/Service/BoardService.php index bbcc351e8..89652f286 100644 --- a/lib/Service/BoardService.php +++ b/lib/Service/BoardService.php @@ -685,9 +685,9 @@ class BoardService { */ public function transferOwnership($owner, $newOwner) { $this->boardMapper->transferOwnership($owner, $newOwner); - $this->aclMapper->transferOwnership($owner, $newOwner); - $this->assignedUsersMapper->transferOwnership($owner, $newOwner); - $this->cardMapper->transferOwnership($owner, $newOwner); + $this->aclMapper->transferOwnership($owner, $newOwner); + $this->assignedUsersMapper->transferOwnership($owner, $newOwner); + $this->cardMapper->transferOwnership($owner, $newOwner); } private function enrichWithStacks($board, $since = -1) { diff --git a/tests/integration/database/TransferOwnershipTest.php b/tests/integration/database/TransferOwnershipTest.php index 459615860..582fca85d 100644 --- a/tests/integration/database/TransferOwnershipTest.php +++ b/tests/integration/database/TransferOwnershipTest.php @@ -66,7 +66,7 @@ class TransferOwnershipTest extends \Test\TestCase { $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 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); @@ -136,68 +136,68 @@ class TransferOwnershipTest extends \Test\TestCase { $this->assertNotContains(self::TEST_USER_1, $participantsUIDs); } - /** - * @covers ::transferOwnership - */ - public function testReassignCardToNewParticipantOnlyIfParticipantHasUserType() { - $this->assignmentService->assignUser($this->cards[1]->getId(), self::TEST_USER_1, AssignedUsers::TYPE_GROUP); - $this->boardService->transferOwnership(self::TEST_USER_1, self::TEST_USER_2); - $assignedUsers = $this->assignedUsersMapper->find($this->cards[1]->getId()); - $participantsUIDs = []; - foreach ($assignedUsers as $user) { - $participantsUIDs[] = $user->getParticipant(); - } - $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, AssignedUsers::TYPE_GROUP); + $this->boardService->transferOwnership(self::TEST_USER_1, self::TEST_USER_2); + $assignedUsers = $this->assignedUsersMapper->find($this->cards[1]->getId()); + $participantsUIDs = []; + foreach ($assignedUsers as $user) { + $participantsUIDs[] = $user->getParticipant(); + } + $this->assertContains(self::TEST_USER_1, $participantsUIDs); + $this->assertNotContains(self::TEST_USER_2, $participantsUIDs); + } - /** - * @covers ::transferOwnership - */ - public function testTargetAlreadyParticipantOfBoard() { - $this->expectNotToPerformAssertions(); - $this->boardService->transferOwnership(self::TEST_USER_1, self::TEST_USER_3); - } + /** + * @covers ::transferOwnership + */ + public function testTargetAlreadyParticipantOfBoard() { + $this->expectNotToPerformAssertions(); + $this->boardService->transferOwnership(self::TEST_USER_1, self::TEST_USER_3); + } - /** - * @covers ::transferOwnership - */ - public function testDontRemoveTargetFromAcl() { - $this->boardService->transferOwnership(self::TEST_USER_2, self::TEST_USER_3); - $board = $this->boardService->find($this->board->getId()); - $acl = $board->getAcl(); - $isOwnerInAcl = (bool)array_filter($acl, function ($item) { - return $item->getParticipant() === self::TEST_USER_3 && $item->getType() === Acl::PERMISSION_TYPE_USER; - }); - $this->assertTrue($isOwnerInAcl); - } + /** + * @covers ::transferOwnership + */ + public function testDontRemoveTargetFromAcl() { + $this->boardService->transferOwnership(self::TEST_USER_2, self::TEST_USER_3); + $board = $this->boardService->find($this->board->getId()); + $acl = $board->getAcl(); + $isOwnerInAcl = (bool)array_filter($acl, function ($item) { + return $item->getParticipant() === self::TEST_USER_3 && $item->getType() === Acl::PERMISSION_TYPE_USER; + }); + $this->assertTrue($isOwnerInAcl); + } - /** - * @covers ::transferOwnership - */ - public function testMergePermissions() { - $this->boardService->addAcl($this->board->getId(), Acl::PERMISSION_TYPE_USER, self::TEST_USER_2, true, false, true); - $this->boardService->transferOwnership(self::TEST_USER_2, 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 testMergePermissions() { + $this->boardService->addAcl($this->board->getId(), Acl::PERMISSION_TYPE_USER, self::TEST_USER_2, true, false, true); + $this->boardService->transferOwnership(self::TEST_USER_2, 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, AssignedUsers::TYPE_USER); - $this->boardService->transferOwnership(self::TEST_USER_1, self::TEST_USER_3); - } + /** + * @covers ::transferOwnership + */ + public function testTargetAlreadyParticipantOfCard() { + $this->expectNotToPerformAssertions(); + $this->assignmentService->assignUser($this->cards[0]->getId(), self::TEST_USER_3, AssignedUsers::TYPE_USER); + $this->boardService->transferOwnership(self::TEST_USER_1, self::TEST_USER_3); + } public function tearDown(): void { $this->boardService->deleteForce($this->board->getId()); diff --git a/tests/unit/Service/BoardServiceTest.php b/tests/unit/Service/BoardServiceTest.php index c64422ff5..600f6a37c 100644 --- a/tests/unit/Service/BoardServiceTest.php +++ b/tests/unit/Service/BoardServiceTest.php @@ -59,8 +59,8 @@ class BoardServiceTest extends TestCase { private $boardMapper; /** @var StackMapper */ private $stackMapper; - /** @var CardMapper */ - private $cardMapper; + /** @var CardMapper */ + private $cardMapper; /** @var PermissionService */ private $permissionService; /** @var NotificationHelper */ From da745f93060b18d4e8df542a52102de361f1b9f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julius=20H=C3=A4rtl?= Date: Tue, 3 Nov 2020 15:06:47 +0100 Subject: [PATCH 09/33] Fix card mapper query for transfer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julius Härtl --- lib/Db/CardMapper.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/Db/CardMapper.php b/lib/Db/CardMapper.php index 2b2469c87..ae6fa9c0f 100644 --- a/lib/Db/CardMapper.php +++ b/lib/Db/CardMapper.php @@ -597,8 +597,8 @@ class CardMapper extends QBMapper implements IPermissionMapper { 'owner' => $ownerId, 'newOwner' => $newOwnerId ]; - $sql = "UPDATE `{$this->tableName}` SET `owner` = :newOwner WHERE `owner` = :owner"; - $stmt = $this->execute($sql, $params); + $sql = "UPDATE `*PREFIX*{$this->tableName}` SET `owner` = :newOwner WHERE `owner` = :owner"; + $stmt = $this->db->executeQuery($sql, $params); $stmt->closeCursor(); } } From 7c6841443501d1c9beed14e0345faecf51cd7763 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julius=20H=C3=A4rtl?= Date: Tue, 10 Nov 2020 12:53:47 +0100 Subject: [PATCH 10/33] Use proper description of what gets transferred MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julius Härtl --- lib/Command/TransferOwnership.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/Command/TransferOwnership.php b/lib/Command/TransferOwnership.php index c3175477e..2b06c4e1c 100644 --- a/lib/Command/TransferOwnership.php +++ b/lib/Command/TransferOwnership.php @@ -20,7 +20,7 @@ final class TransferOwnership extends Command { protected function configure() { $this ->setName('deck:transfer-ownership') - ->setDescription('Change owner of deck entities') + ->setDescription('Change owner of deck boards') ->addArgument( 'owner', InputArgument::REQUIRED, @@ -37,10 +37,10 @@ final class TransferOwnership extends Command { $owner = $input->getArgument('owner'); $newOwner = $input->getArgument('newOwner'); - $output->writeln("Transfer deck entities from $owner to $newOwner"); + $output->writeln("Transfer deck boards from $owner to $newOwner"); $this->boardService->transferOwnership($owner, $newOwner); - $output->writeln("Transfer deck entities from $owner to $newOwner completed"); + $output->writeln("Transfer deck boards from $owner to $newOwner completed"); } } From c0886cfc7ae18bc75169099e82e17ab14067a5d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julius=20H=C3=A4rtl?= Date: Tue, 10 Nov 2020 12:54:17 +0100 Subject: [PATCH 11/33] Just cleanup old ACL rules, there are none for the board owner so nothing to cleanup or persist there MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julius Härtl --- lib/Db/AclMapper.php | 20 +++----------------- 1 file changed, 3 insertions(+), 17 deletions(-) diff --git a/lib/Db/AclMapper.php b/lib/Db/AclMapper.php index d34738d82..327d8aa34 100644 --- a/lib/Db/AclMapper.php +++ b/lib/Db/AclMapper.php @@ -69,28 +69,14 @@ class AclMapper extends DeckMapper implements IPermissionMapper { 'newOwner' => $newOwnerId, 'type' => Acl::PERMISSION_TYPE_USER ]; - //We want preserve permissions from both users - $sql = "UPDATE `{$this->tableName}` AS `source` - LEFT JOIN `{$this->tableName}` AS `target` - ON `target`.`participant` = :newOwner AND `target`.`type` = :type - SET `source`.`permission_edit` =(`source`.`permission_edit` || `target`.`permission_edit`), - `source`.`permission_share` =(`source`.`permission_share` || `target`.`permission_share`), - `source`.`permission_manage` =(`source`.`permission_manage` || `target`.`permission_manage`) - WHERE `source`.`participant` = :owner AND `source`.`type` = :type"; - $stmt = $this->execute($sql, $params); - $stmt->closeCursor(); - //We can't transfer acl if target already in acl + + // Drop existing ACL rules for the new owner $sql = "DELETE FROM `{$this->tableName}` WHERE `participant` = :newOwner AND `type` = :type AND EXISTS (SELECT `id` FROM (SELECT `id` FROM `{$this->tableName}` - WHERE `participant` = :owner AND `type` = :type) as tmp)"; + WHERE `participant` = :newOwner AND `type` = :type) as tmp)"; $stmt = $this->execute($sql, $params); $stmt->closeCursor(); - //Now we can transfer without errors - $sqlUpdate = "UPDATE `{$this->tableName}` - SET `participant` = :newOwner WHERE `participant` = :owner AND `type` = :type"; - $stmt = $this->execute($sqlUpdate, $params); - $stmt->closeCursor(); } } From a8c22482f67a7440c88c7d450bba6fb04d2a71ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julius=20H=C3=A4rtl?= Date: Tue, 10 Nov 2020 12:54:36 +0100 Subject: [PATCH 12/33] Make queries work with the new base mapper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julius Härtl fix: conflicts --- lib/Db/AclMapper.php | 9 ++++----- lib/Db/AssignmentMapper.php | 9 +++++---- lib/Service/BoardService.php | 16 +++++++++------- .../database/TransferOwnershipTest.php | 9 +++++---- 4 files changed, 23 insertions(+), 20 deletions(-) diff --git a/lib/Db/AclMapper.php b/lib/Db/AclMapper.php index 327d8aa34..c45a2d421 100644 --- a/lib/Db/AclMapper.php +++ b/lib/Db/AclMapper.php @@ -63,19 +63,18 @@ class AclMapper extends DeckMapper implements IPermissionMapper { * @param $newOwnerId * @return void */ - public function transferOwnership($ownerId, $newOwnerId) { + public function transferOwnership($boardId, $ownerId, $newOwnerId) { $params = [ - 'owner' => $ownerId, 'newOwner' => $newOwnerId, - 'type' => Acl::PERMISSION_TYPE_USER + 'type' => Acl::PERMISSION_TYPE_USER, + 'boardId' => $boardId ]; // Drop existing ACL rules for the new owner $sql = "DELETE FROM `{$this->tableName}` WHERE `participant` = :newOwner AND `type` = :type - AND EXISTS (SELECT `id` FROM (SELECT `id` FROM `{$this->tableName}` - WHERE `participant` = :newOwner AND `type` = :type) as tmp)"; + AND `board_id` = :boardId"; $stmt = $this->execute($sql, $params); $stmt->closeCursor(); } diff --git a/lib/Db/AssignmentMapper.php b/lib/Db/AssignmentMapper.php index 1c5e43819..a5000184d 100644 --- a/lib/Db/AssignmentMapper.php +++ b/lib/Db/AssignmentMapper.php @@ -157,16 +157,17 @@ class AssignmentMapper extends QBMapper implements IPermissionMapper { 'newOwner' => $newOwnerId, 'type' => AssignedUsers::TYPE_USER ]; - $sql = "DELETE FROM `{$this->tableName}` WHERE `participant` = :newOwner AND `type`= :type"; - $stmt = $this->execute($sql, $params); + $qb = $this->db->getQueryBuilder(); + $sql = "DELETE FROM `*PREFIX*{$this->tableName}` WHERE `participant` = :newOwner AND `type`= :type"; + $stmt = $this->db->executeQuery($sql, $params); $stmt->closeCursor(); $params = [ 'owner' => $ownerId, 'newOwner' => $newOwnerId, 'type' => AssignedUsers::TYPE_USER ]; - $sql = "UPDATE `{$this->tableName}` SET `participant` = :newOwner WHERE `participant` = :owner AND `type`= :type"; - $stmt = $this->execute($sql, $params); + $sql = "UPDATE `*PREFIX*{$this->tableName}` SET `participant` = :newOwner WHERE `participant` = :owner AND `type`= :type"; + $stmt = $this->db->executeQuery($sql, $params); $stmt->closeCursor(); } } diff --git a/lib/Service/BoardService.php b/lib/Service/BoardService.php index 89652f286..671354905 100644 --- a/lib/Service/BoardService.php +++ b/lib/Service/BoardService.php @@ -678,14 +678,12 @@ class BoardService { return $newBoard; } - /** - * @param $ownerId - * @param $newOwnerId - * @return void - */ - public function transferOwnership($owner, $newOwner) { + public function transferOwnership(string $owner, string $newOwner): void { + $boards = $this->boardMapper->findAllByUser($owner); + foreach ($boards as $board) { + $this->aclMapper->transferOwnership($board->getId(), $owner, $newOwner); + } $this->boardMapper->transferOwnership($owner, $newOwner); - $this->aclMapper->transferOwnership($owner, $newOwner); $this->assignedUsersMapper->transferOwnership($owner, $newOwner); $this->cardMapper->transferOwnership($owner, $newOwner); } @@ -721,4 +719,8 @@ class BoardService { public function getBoardUrl($endpoint) { return $this->urlGenerator->linkToRouteAbsolute('deck.page.index') . '#' . $endpoint; } + + private function clearBoardsCache() { + $this->boardsCache = null; + } } diff --git a/tests/integration/database/TransferOwnershipTest.php b/tests/integration/database/TransferOwnershipTest.php index 582fca85d..fbfab856f 100644 --- a/tests/integration/database/TransferOwnershipTest.php +++ b/tests/integration/database/TransferOwnershipTest.php @@ -82,6 +82,7 @@ class TransferOwnershipTest extends \Test\TestCase { */ public function testTransferBoardOwnership() { $this->boardService->transferOwnership(self::TEST_USER_1, self::TEST_USER_2); + $this->invokePrivate($this->boardService, 'clearBoardsCache'); $board = $this->boardService->find($this->board->getId()); $boardOwner = $board->getOwner(); $this->assertEquals(self::TEST_USER_2, $boardOwner); @@ -94,10 +95,10 @@ class TransferOwnershipTest extends \Test\TestCase { $this->boardService->transferOwnership(self::TEST_USER_1, self::TEST_USER_2); $board = $this->boardService->find($this->board->getId()); $acl = $board->getAcl(); - $isTargetInAcl = (bool)array_filter($acl, function ($item) { - return $item->getParticipant() === self::TEST_USER_2 && $item->getType() === Acl::PERMISSION_TYPE_USER; - }); - $this->assertTrue($isTargetInAcl); + // Check if old owner is no longer in ACL + $this->assertTrue((bool)array_filter($acl, function ($item) { + return $item->getParticipant() === self::TEST_USER_1 && $item->getType() === Acl::PERMISSION_TYPE_USER; + })); } /** From 05dbf67531a03f6734d9198eb035c1a60dc4c9a0 Mon Sep 17 00:00:00 2001 From: Max Date: Wed, 9 Feb 2022 14:45:00 +0100 Subject: [PATCH 13/33] fix: Assignment is the new AssignedUsers Signed-off-by: Max --- lib/Db/AssignmentMapper.php | 4 ++-- .../database/TransferOwnershipTest.php | 22 +++++++++---------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/lib/Db/AssignmentMapper.php b/lib/Db/AssignmentMapper.php index a5000184d..8d193fad0 100644 --- a/lib/Db/AssignmentMapper.php +++ b/lib/Db/AssignmentMapper.php @@ -155,7 +155,7 @@ class AssignmentMapper extends QBMapper implements IPermissionMapper { public function transferOwnership($ownerId, $newOwnerId) { $params = [ 'newOwner' => $newOwnerId, - 'type' => AssignedUsers::TYPE_USER + 'type' => Assignment::TYPE_USER ]; $qb = $this->db->getQueryBuilder(); $sql = "DELETE FROM `*PREFIX*{$this->tableName}` WHERE `participant` = :newOwner AND `type`= :type"; @@ -164,7 +164,7 @@ class AssignmentMapper extends QBMapper implements IPermissionMapper { $params = [ 'owner' => $ownerId, 'newOwner' => $newOwnerId, - 'type' => AssignedUsers::TYPE_USER + 'type' => Assignment::TYPE_USER ]; $sql = "UPDATE `*PREFIX*{$this->tableName}` SET `participant` = :newOwner WHERE `participant` = :owner AND `type`= :type"; $stmt = $this->db->executeQuery($sql, $params); diff --git a/tests/integration/database/TransferOwnershipTest.php b/tests/integration/database/TransferOwnershipTest.php index fbfab856f..2b1e30403 100644 --- a/tests/integration/database/TransferOwnershipTest.php +++ b/tests/integration/database/TransferOwnershipTest.php @@ -3,8 +3,8 @@ namespace OCA\Deck\Service; use OCA\Deck\Db\Acl; -use OCA\Deck\Db\AssignedUsers; -use OCA\Deck\Db\AssignedUsersMapper; +use OCA\Deck\Db\Assignment; +use OCA\Deck\Db\AssignmentMapper; use OCA\Deck\Db\Board; /** @@ -23,8 +23,8 @@ class TransferOwnershipTest extends \Test\TestCase { protected $cardService; /** @var StackService */ protected $stackService; - /** @var AssignedUsersMapper */ - protected $assignedUsersMapper; + /** @var AssignmentMapper */ + protected $assignmentMapper; /** @var AssignmentService */ private $assignmentService; /** @var Board */ @@ -55,7 +55,7 @@ class TransferOwnershipTest extends \Test\TestCase { $this->stackService = \OC::$server->query(StackService::class); $this->cardService = \OC::$server->query(CardService::class); $this->assignmentService = \OC::$server->query(AssignmentService::class); - $this->assignedUsersMapper = \OC::$server->query(AssignedUsersMapper::class); + $this->assignmentMapper = \OC::$server->query(AssignmentMapper::class); $this->createBoardWithExampleData(); } @@ -128,9 +128,9 @@ class TransferOwnershipTest extends \Test\TestCase { */ public function testReassignCardToNewOwner() { $this->boardService->transferOwnership(self::TEST_USER_1, self::TEST_USER_2); - $assignedUsers = $this->assignedUsersMapper->find($this->cards[0]->getId()); + $users = $this->assignmentMapper->findAll($this->cards[0]->getId()); $participantsUIDs = []; - foreach ($assignedUsers as $user) { + foreach ($users as $user) { $participantsUIDs[] = $user->getParticipant(); } $this->assertContains(self::TEST_USER_2, $participantsUIDs); @@ -141,11 +141,11 @@ class TransferOwnershipTest extends \Test\TestCase { * @covers ::transferOwnership */ public function testReassignCardToNewParticipantOnlyIfParticipantHasUserType() { - $this->assignmentService->assignUser($this->cards[1]->getId(), self::TEST_USER_1, AssignedUsers::TYPE_GROUP); + $this->assignmentService->assignUser($this->cards[1]->getId(), self::TEST_USER_1, Assignment::TYPE_GROUP); $this->boardService->transferOwnership(self::TEST_USER_1, self::TEST_USER_2); - $assignedUsers = $this->assignedUsersMapper->find($this->cards[1]->getId()); + $users = $this->assignmentMapper->findAll($this->cards[1]->getId()); $participantsUIDs = []; - foreach ($assignedUsers as $user) { + foreach ($users as $user) { $participantsUIDs[] = $user->getParticipant(); } $this->assertContains(self::TEST_USER_1, $participantsUIDs); @@ -196,7 +196,7 @@ class TransferOwnershipTest extends \Test\TestCase { */ public function testTargetAlreadyParticipantOfCard() { $this->expectNotToPerformAssertions(); - $this->assignmentService->assignUser($this->cards[0]->getId(), self::TEST_USER_3, AssignedUsers::TYPE_USER); + $this->assignmentService->assignUser($this->cards[0]->getId(), self::TEST_USER_3, Assignment::TYPE_USER); $this->boardService->transferOwnership(self::TEST_USER_1, self::TEST_USER_3); } From b01d472745575dccdc62e065c9c30988e0ab4c13 Mon Sep 17 00:00:00 2001 From: Max Date: Wed, 9 Feb 2022 15:38:33 +0100 Subject: [PATCH 14/33] fix: queries with the new base mapper in BoardMapper Signed-off-by: Max --- lib/Db/BoardMapper.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/Db/BoardMapper.php b/lib/Db/BoardMapper.php index fc5455ef4..aea517e3b 100644 --- a/lib/Db/BoardMapper.php +++ b/lib/Db/BoardMapper.php @@ -486,8 +486,8 @@ class BoardMapper extends QBMapper implements IPermissionMapper { 'owner' => $ownerId, 'newOwner' => $newOwnerId ]; - $sql = "UPDATE `{$this->tableName}` SET `owner` = :newOwner WHERE `owner` = :owner"; - $stmt = $this->execute($sql, $params); + $sql = "UPDATE `*PREFIX*{$this->tableName}` SET `owner` = :newOwner WHERE `owner` = :owner"; + $stmt = $this->db->executeQuery($sql, $params); $stmt->closeCursor(); } } From b7f3c2d14069d08b32eb77cb83106f726aab2b59 Mon Sep 17 00:00:00 2001 From: Luka Trovic Date: Fri, 4 Mar 2022 18:06:08 +0100 Subject: [PATCH 15/33] fix: unit test & psalm static code analysis issues Signed-off-by: Luka Trovic --- lib/Command/TransferOwnership.php | 4 +- lib/Db/AssignmentMapper.php | 3 +- tests/unit/Activity/ActivityManagerTest.php | 16 +- tests/unit/Cron/DeleteCronTest.php | 18 +-- tests/unit/Cron/ScheduledNoificationsTest.php | 5 +- .../Notification/NotificationHelperTest.php | 149 +++++++----------- tests/unit/Service/AttachmentServiceTest.php | 92 +++++++++-- tests/unit/Service/BoardServiceTest.php | 39 +++-- tests/unit/Service/PermissionServiceTest.php | 29 ++-- 9 files changed, 200 insertions(+), 155 deletions(-) diff --git a/lib/Command/TransferOwnership.php b/lib/Command/TransferOwnership.php index 2b06c4e1c..9d3ae1b48 100644 --- a/lib/Command/TransferOwnership.php +++ b/lib/Command/TransferOwnership.php @@ -33,7 +33,7 @@ final class TransferOwnership extends Command { ); } - protected function execute(InputInterface $input, OutputInterface $output) { + protected function execute(InputInterface $input, OutputInterface $output): int { $owner = $input->getArgument('owner'); $newOwner = $input->getArgument('newOwner'); @@ -42,5 +42,7 @@ final class TransferOwnership extends Command { $this->boardService->transferOwnership($owner, $newOwner); $output->writeln("Transfer deck boards from $owner to $newOwner completed"); + + return 0; } } diff --git a/lib/Db/AssignmentMapper.php b/lib/Db/AssignmentMapper.php index 8d193fad0..836add105 100644 --- a/lib/Db/AssignmentMapper.php +++ b/lib/Db/AssignmentMapper.php @@ -148,11 +148,12 @@ class AssignmentMapper extends QBMapper implements IPermissionMapper { } /** + * @psalm-suppress InvalidScalarArgument * @param $ownerId * @param $newOwnerId * @return void */ - public function transferOwnership($ownerId, $newOwnerId) { + public function transferOwnership(string $ownerId, string $newOwnerId) { $params = [ 'newOwner' => $newOwnerId, 'type' => Assignment::TYPE_USER diff --git a/tests/unit/Activity/ActivityManagerTest.php b/tests/unit/Activity/ActivityManagerTest.php index 5e486731e..d292d9023 100644 --- a/tests/unit/Activity/ActivityManagerTest.php +++ b/tests/unit/Activity/ActivityManagerTest.php @@ -169,18 +169,15 @@ class ActivityManagerTest extends TestCase { $this->mockUser('user2'), ]; $event = $this->createMock(IEvent::class); - $event->expects($this->at(0)) + $event->expects($this->once()) ->method('getObjectType') ->willReturn($objectType); - $event->expects($this->at(0)) + $event->expects($this->once()) ->method('getObjectId') ->willReturn(1); - $event->expects($this->at(2)) + $event->expects($this->exactly(2)) ->method('setAffectedUser') - ->with('user1'); - $event->expects($this->at(3)) - ->method('setAffectedUser') - ->with('user2'); + ->withConsecutive(['user1'], ['user2']); $mapper = null; switch ($objectType) { case ActivityManager::DECK_OBJECT_BOARD: @@ -196,10 +193,7 @@ class ActivityManagerTest extends TestCase { $this->permissionService->expects($this->once()) ->method('findUsers') ->willReturn($users); - $this->manager->expects($this->at(0)) - ->method('publish') - ->with($event); - $this->manager->expects($this->at(1)) + $this->manager->expects($this->exactly(2)) ->method('publish') ->with($event); $this->invokePrivate($this->activityManager, 'sendToUsers', [$event]); diff --git a/tests/unit/Cron/DeleteCronTest.php b/tests/unit/Cron/DeleteCronTest.php index e7ba1c6b9..e411a5d31 100644 --- a/tests/unit/Cron/DeleteCronTest.php +++ b/tests/unit/Cron/DeleteCronTest.php @@ -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'); diff --git a/tests/unit/Cron/ScheduledNoificationsTest.php b/tests/unit/Cron/ScheduledNoificationsTest.php index ff7aad6a1..f44b91fa1 100644 --- a/tests/unit/Cron/ScheduledNoificationsTest.php +++ b/tests/unit/Cron/ScheduledNoificationsTest.php @@ -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); diff --git a/tests/unit/Notification/NotificationHelperTest.php b/tests/unit/Notification/NotificationHelperTest.php index 0d5b2527c..c4f0fd9cd 100644 --- a/tests/unit/Notification/NotificationHelperTest.php +++ b/tests/unit/Notification/NotificationHelperTest.php @@ -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); } diff --git a/tests/unit/Service/AttachmentServiceTest.php b/tests/unit/Service/AttachmentServiceTest.php index d76bb2c52..1a005c297 100644 --- a/tests/unit/Service/AttachmentServiceTest.php +++ b/tests/unit/Service/AttachmentServiceTest.php @@ -110,8 +110,22 @@ 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->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->application->expects($this->any()) ->method('getContainer') @@ -129,9 +143,27 @@ 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()); + + /* $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()); */ $application->expects($this->any()) ->method('getContainer') @@ -148,12 +180,32 @@ 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()); + + /* $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()); */ $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 +237,19 @@ class AttachmentServiceTest extends TestCase { ->with(123) ->willReturn($attachments); - $this->attachmentServiceImpl->expects($this->at(0)) + $this->attachmentServiceImpl->expects($this->exactly(2)) + ->method('extendData') + ->withConsecutive( + [$attachments[0]], + [$attachments[1]] + ); + + /* $this->attachmentServiceImpl->expects($this->at(0)) ->method('extendData') ->with($attachments[0]); $this->attachmentServiceImpl->expects($this->at(1)) ->method('extendData') - ->with($attachments[1]); + ->with($attachments[1]); */ $this->assertEquals($attachments, $this->attachmentService->findAll(123, false)); } @@ -215,12 +274,21 @@ class AttachmentServiceTest extends TestCase { ->with(123, false) ->willReturn($attachmentsDeleted); - $this->attachmentServiceImpl->expects($this->at(0)) + $this->attachmentServiceImpl->expects($this->exactly(4)) + ->method('extendData') + ->withConsecutive( + [$attachments[0]], + [$attachments[1]], + [$attachmentsDeleted[0]], + [$attachmentsDeleted[1]] + ); + + /* $this->attachmentServiceImpl->expects($this->at(0)) ->method('extendData') ->with($attachments[0]); $this->attachmentServiceImpl->expects($this->at(1)) ->method('extendData') - ->with($attachments[1]); + ->with($attachments[1]); */ $this->assertEquals(array_merge($attachments, $attachmentsDeleted), $this->attachmentService->findAll(123, true)); } diff --git a/tests/unit/Service/BoardServiceTest.php b/tests/unit/Service/BoardServiceTest.php index 600f6a37c..333b85116 100644 --- a/tests/unit/Service/BoardServiceTest.php +++ b/tests/unit/Service/BoardServiceTest.php @@ -300,22 +300,41 @@ 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') + ->willReturnOnConsecutiveCalls( + $currentUserAcl[0], + $currentUserAcl[1], + $currentUserAcl[2] + ); + + /* $this->permissionService->expects($this->at(2)) ->method('userCan') ->willReturn($currentUserAcl[0]); $this->permissionService->expects($this->at(3)) @@ -323,7 +342,7 @@ class BoardServiceTest extends TestCase { ->willReturn($currentUserAcl[1]); $this->permissionService->expects($this->at(4)) ->method('userCan') - ->willReturn($currentUserAcl[2]); + ->willReturn($currentUserAcl[2]); */ } $user = $this->createMock(IUser::class); diff --git a/tests/unit/Service/PermissionServiceTest.php b/tests/unit/Service/PermissionServiceTest.php index f92adc059..0994a778e 100644 --- a/tests/unit/Service/PermissionServiceTest.php +++ b/tests/unit/Service/PermissionServiceTest.php @@ -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') From 981fc8e16fd5a8b3003fc75538694ab95373fad9 Mon Sep 17 00:00:00 2001 From: Luka Trovic Date: Tue, 8 Mar 2022 10:27:06 +0100 Subject: [PATCH 16/33] fix: integration tests Signed-off-by: Luka Trovic --- lib/Db/AssignmentMapper.php | 14 +++++------ lib/Db/BoardMapper.php | 23 ++++++++++++++++++- lib/Service/BoardService.php | 18 +++++++++++++++ .../database/TransferOwnershipTest.php | 2 +- 4 files changed, 47 insertions(+), 10 deletions(-) diff --git a/lib/Db/AssignmentMapper.php b/lib/Db/AssignmentMapper.php index 836add105..222e556cc 100644 --- a/lib/Db/AssignmentMapper.php +++ b/lib/Db/AssignmentMapper.php @@ -154,19 +154,17 @@ class AssignmentMapper extends QBMapper implements IPermissionMapper { * @return void */ public function transferOwnership(string $ownerId, string $newOwnerId) { - $params = [ - 'newOwner' => $newOwnerId, - 'type' => Assignment::TYPE_USER - ]; - $qb = $this->db->getQueryBuilder(); - $sql = "DELETE FROM `*PREFIX*{$this->tableName}` WHERE `participant` = :newOwner AND `type`= :type"; - $stmt = $this->db->executeQuery($sql, $params); - $stmt->closeCursor(); $params = [ 'owner' => $ownerId, 'newOwner' => $newOwnerId, 'type' => Assignment::TYPE_USER ]; + $qb = $this->db->getQueryBuilder(); + $sql = "DELETE FROM `*PREFIX*{$this->tableName}` WHERE `participant` = :newOwner AND `type`= :type AND id IN + (SELECT id FROM `*PREFIX*{$this->tableName}` WHERE `participant` = :owner)"; + $stmt = $this->db->executeQuery($sql, $params); + $stmt->closeCursor(); + $sql = "UPDATE `*PREFIX*{$this->tableName}` SET `participant` = :newOwner WHERE `participant` = :owner AND `type`= :type"; $stmt = $this->db->executeQuery($sql, $params); $stmt->closeCursor(); diff --git a/lib/Db/BoardMapper.php b/lib/Db/BoardMapper.php index aea517e3b..4889cc56c 100644 --- a/lib/Db/BoardMapper.php +++ b/lib/Db/BoardMapper.php @@ -182,7 +182,7 @@ class BoardMapper extends QBMapper implements IPermissionMapper { // shared with user $qb->resetQueryParts(); - $qb->select('b.id', 'title', 'owner', 'color', 'archived', 'deleted_at', 'last_modified') + $qb->selectDistinct('b.id', 'title', 'owner', 'color', 'archived', 'deleted_at', 'last_modified') //->selectAlias('1', 'shared') ->from('deck_boards', 'b') ->innerJoin('b', 'deck_board_acl', 'acl', $qb->expr()->eq('b.id', 'acl.board_id')) @@ -490,4 +490,25 @@ class BoardMapper extends QBMapper implements IPermissionMapper { $stmt = $this->db->executeQuery($sql, $params); $stmt->closeCursor(); } + + /** + * Reset Cache for a + * given board or a given user + * + * @param int|null $boardId + * @param int|null $userId + */ + 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; + } + } } diff --git a/lib/Service/BoardService.php b/lib/Service/BoardService.php index 671354905..d7c6deb9a 100644 --- a/lib/Service/BoardService.php +++ b/lib/Service/BoardService.php @@ -528,6 +528,9 @@ class BoardService { $this->boardMapper->mapAcl($newAcl); $this->changeHelper->boardChanged($boardId); + $board = $this->find($boardId); + $this->clearBoardFromCache($board); + // TODO: use the dispatched event for this try { $resourceProvider = \OC::$server->query(\OCA\Deck\Collaboration\Resources\ResourceProvider::class); @@ -681,6 +684,7 @@ class BoardService { public function transferOwnership(string $owner, string $newOwner): void { $boards = $this->boardMapper->findAllByUser($owner); foreach ($boards as $board) { + $this->clearBoardFromCache($board); $this->aclMapper->transferOwnership($board->getId(), $owner, $newOwner); } $this->boardMapper->transferOwnership($owner, $newOwner); @@ -723,4 +727,18 @@ class BoardService { private function clearBoardsCache() { $this->boardsCache = null; } + + /** + * Clean a given board data + * from the Cache + * + * @param OCA\Deck\Db\Board $board + */ + private function clearBoardFromCache(Board $board) { + $boardId = $board->getId(); + $boardOwnerId = $board->getOwner(); + + $this->boardMapper->flushCache($boardId, $boardOwnerId); + unset($this->boardsCache[$boardId]); + } } diff --git a/tests/integration/database/TransferOwnershipTest.php b/tests/integration/database/TransferOwnershipTest.php index 2b1e30403..2c549e9c0 100644 --- a/tests/integration/database/TransferOwnershipTest.php +++ b/tests/integration/database/TransferOwnershipTest.php @@ -82,7 +82,7 @@ class TransferOwnershipTest extends \Test\TestCase { */ public function testTransferBoardOwnership() { $this->boardService->transferOwnership(self::TEST_USER_1, self::TEST_USER_2); - $this->invokePrivate($this->boardService, 'clearBoardsCache'); + /* $this->invokePrivate($this->boardService, 'clearBoardsCache'); */ $board = $this->boardService->find($this->board->getId()); $boardOwner = $board->getOwner(); $this->assertEquals(self::TEST_USER_2, $boardOwner); From c95c96fb401b2096f21f3b0f3a4d772e7cc993ba Mon Sep 17 00:00:00 2001 From: Luka Trovic Date: Thu, 10 Mar 2022 09:50:40 +0100 Subject: [PATCH 17/33] feat: add integration test for transferring board ownership with data Signed-off-by: Luka Trovic --- .../database/TransferOwnershipTest.php | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/tests/integration/database/TransferOwnershipTest.php b/tests/integration/database/TransferOwnershipTest.php index 2c549e9c0..7ffb4d135 100644 --- a/tests/integration/database/TransferOwnershipTest.php +++ b/tests/integration/database/TransferOwnershipTest.php @@ -6,6 +6,7 @@ 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 @@ -88,6 +89,25 @@ class TransferOwnershipTest extends \Test\TestCase { $this->assertEquals(self::TEST_USER_2, $boardOwner); } + /** + * @covers ::transferOwnership + */ + public function testTransferBoardOwnershipWithData() + { + $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 */ From 26c76fbb46b922cbe543825fc264e1dde420da4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julius=20H=C3=A4rtl?= Date: Mon, 14 Mar 2022 08:34:02 +0100 Subject: [PATCH 18/33] fix: unit tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julius Härtl --- lib/Db/BoardMapper.php | 6 +++--- lib/Service/BoardService.php | 4 ++-- lib/Service/PermissionService.php | 1 + tests/unit/Service/BoardServiceTest.php | 28 ++++++++++++------------- 4 files changed, 20 insertions(+), 19 deletions(-) diff --git a/lib/Db/BoardMapper.php b/lib/Db/BoardMapper.php index 4889cc56c..5cc5cbc00 100644 --- a/lib/Db/BoardMapper.php +++ b/lib/Db/BoardMapper.php @@ -182,7 +182,7 @@ class BoardMapper extends QBMapper implements IPermissionMapper { // shared with user $qb->resetQueryParts(); - $qb->selectDistinct('b.id', 'title', 'owner', 'color', 'archived', 'deleted_at', 'last_modified') + $qb->select('b.id', 'title', 'owner', 'color', 'archived', 'deleted_at', 'last_modified') //->selectAlias('1', 'shared') ->from('deck_boards', 'b') ->innerJoin('b', 'deck_board_acl', 'acl', $qb->expr()->eq('b.id', 'acl.board_id')) @@ -492,9 +492,9 @@ class BoardMapper extends QBMapper implements IPermissionMapper { } /** - * Reset Cache for a + * Reset Cache for a * given board or a given user - * + * * @param int|null $boardId * @param int|null $userId */ diff --git a/lib/Service/BoardService.php b/lib/Service/BoardService.php index d7c6deb9a..d09007390 100644 --- a/lib/Service/BoardService.php +++ b/lib/Service/BoardService.php @@ -528,7 +528,7 @@ class BoardService { $this->boardMapper->mapAcl($newAcl); $this->changeHelper->boardChanged($boardId); - $board = $this->find($boardId); + $board = $this->boardMapper->find($boardId); $this->clearBoardFromCache($board); // TODO: use the dispatched event for this @@ -731,7 +731,7 @@ class BoardService { /** * Clean a given board data * from the Cache - * + * * @param OCA\Deck\Db\Board $board */ private function clearBoardFromCache(Board $board) { diff --git a/lib/Service/PermissionService.php b/lib/Service/PermissionService.php index 498e8904c..e94d073df 100644 --- a/lib/Service/PermissionService.php +++ b/lib/Service/PermissionService.php @@ -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) { diff --git a/tests/unit/Service/BoardServiceTest.php b/tests/unit/Service/BoardServiceTest.php index 333b85116..0e8bfeb15 100644 --- a/tests/unit/Service/BoardServiceTest.php +++ b/tests/unit/Service/BoardServiceTest.php @@ -154,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', @@ -258,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 )); @@ -306,7 +311,7 @@ class BoardServiceTest extends TestCase { ->method('checkPermission') ->withConsecutive( [$this->boardMapper, 123, Acl::PERMISSION_SHARE, null], - [$this->boardMapper, 123, Acl::PERMISSION_MANAGE, null] + [$this->boardMapper, 123, Acl::PERMISSION_MANAGE, null] ); } else { $this->aclMapper->expects($this->once()) @@ -329,20 +334,10 @@ class BoardServiceTest extends TestCase { $this->permissionService->expects($this->exactly(3)) ->method('userCan') ->willReturnOnConsecutiveCalls( - $currentUserAcl[0], - $currentUserAcl[1], + $currentUserAcl[0], + $currentUserAcl[1], $currentUserAcl[2] ); - - /* $this->permissionService->expects($this->at(2)) - ->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]); */ } $user = $this->createMock(IUser::class); @@ -357,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; From 48ec97386c7b87931eb82ad3cf007409c00a09ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julius=20H=C3=A4rtl?= Date: Mon, 14 Mar 2022 08:37:22 +0100 Subject: [PATCH 19/33] fix: Psalm MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julius Härtl --- lib/Db/BoardMapper.php | 6 +----- lib/Service/BoardService.php | 5 +---- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/lib/Db/BoardMapper.php b/lib/Db/BoardMapper.php index 5cc5cbc00..81dc648bf 100644 --- a/lib/Db/BoardMapper.php +++ b/lib/Db/BoardMapper.php @@ -492,11 +492,7 @@ class BoardMapper extends QBMapper implements IPermissionMapper { } /** - * Reset Cache for a - * given board or a given user - * - * @param int|null $boardId - * @param int|null $userId + * Reset cache for a given board or a given user */ public function flushCache(?int $boardId = null, ?string $userId = null) { diff --git a/lib/Service/BoardService.php b/lib/Service/BoardService.php index d09007390..ceea63519 100644 --- a/lib/Service/BoardService.php +++ b/lib/Service/BoardService.php @@ -729,10 +729,7 @@ class BoardService { } /** - * Clean a given board data - * from the Cache - * - * @param OCA\Deck\Db\Board $board + * Clean a given board data from the Cache */ private function clearBoardFromCache(Board $board) { $boardId = $board->getId(); From 525a14c4281a377b2994f52a733403a16fb4f4c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julius=20H=C3=A4rtl?= Date: Mon, 14 Mar 2022 09:47:46 +0100 Subject: [PATCH 20/33] Allow transfer of single boards MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julius Härtl --- lib/Command/TransferOwnership.php | 51 +++++++++++++++++-- lib/Db/AclMapper.php | 2 +- lib/Db/AssignmentMapper.php | 4 +- lib/Db/BoardMapper.php | 24 ++++----- lib/Db/CardMapper.php | 7 +-- lib/Service/BoardService.php | 26 ++++++++-- .../database/TransferOwnershipTest.php | 35 ++++++++++--- tests/unit/Service/AttachmentServiceTest.php | 4 +- 8 files changed, 114 insertions(+), 39 deletions(-) diff --git a/lib/Command/TransferOwnership.php b/lib/Command/TransferOwnership.php index 9d3ae1b48..3b42132ca 100644 --- a/lib/Command/TransferOwnership.php +++ b/lib/Command/TransferOwnership.php @@ -4,17 +4,22 @@ namespace OCA\Deck\Command; use OCA\Deck\Service\BoardService; 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 $questionHelper; - public function __construct(BoardService $boardService) { + public function __construct(BoardService $boardService, QuestionHelper $questionHelper) { parent::__construct(); $this->boardService = $boardService; + $this->questionHelper = $questionHelper; } protected function configure() { @@ -30,18 +35,54 @@ final class TransferOwnership extends Command { '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'); - $output->writeln("Transfer deck boards from $owner to $newOwner"); + $remapAssignment = $input->getOption('remap'); - $this->boardService->transferOwnership($owner, $newOwner); + $board = $boardId ? $this->boardService->find($boardId) : null; - $output->writeln("Transfer deck boards from $owner to $newOwner completed"); + 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("Board " . $board->getTitle() . " from ". $board->getOwner() ." transferred to $newOwner completed"); + return 0; + } + + $this->boardService->transferOwnership($owner, $newOwner, $remapAssignment); + $output->writeln("All boards from $owner to $newOwner transferred"); return 0; } diff --git a/lib/Db/AclMapper.php b/lib/Db/AclMapper.php index c45a2d421..bc7784bdc 100644 --- a/lib/Db/AclMapper.php +++ b/lib/Db/AclMapper.php @@ -63,7 +63,7 @@ class AclMapper extends DeckMapper implements IPermissionMapper { * @param $newOwnerId * @return void */ - public function transferOwnership($boardId, $ownerId, $newOwnerId) { + public function transferOwnership($boardId, $newOwnerId) { $params = [ 'newOwner' => $newOwnerId, 'type' => Acl::PERMISSION_TYPE_USER, diff --git a/lib/Db/AssignmentMapper.php b/lib/Db/AssignmentMapper.php index 222e556cc..06c37e24d 100644 --- a/lib/Db/AssignmentMapper.php +++ b/lib/Db/AssignmentMapper.php @@ -153,7 +153,7 @@ class AssignmentMapper extends QBMapper implements IPermissionMapper { * @param $newOwnerId * @return void */ - public function transferOwnership(string $ownerId, string $newOwnerId) { + public function transferOwnership(string $ownerId, string $newOwnerId, int $boardId = null) { $params = [ 'owner' => $ownerId, 'newOwner' => $newOwnerId, @@ -164,7 +164,7 @@ class AssignmentMapper extends QBMapper implements IPermissionMapper { (SELECT id FROM `*PREFIX*{$this->tableName}` WHERE `participant` = :owner)"; $stmt = $this->db->executeQuery($sql, $params); $stmt->closeCursor(); - + $sql = "UPDATE `*PREFIX*{$this->tableName}` SET `participant` = :newOwner WHERE `participant` = :owner AND `type`= :type"; $stmt = $this->db->executeQuery($sql, $params); $stmt->closeCursor(); diff --git a/lib/Db/BoardMapper.php b/lib/Db/BoardMapper.php index 81dc648bf..93be76d7e 100644 --- a/lib/Db/BoardMapper.php +++ b/lib/Db/BoardMapper.php @@ -477,25 +477,23 @@ class BoardMapper extends QBMapper implements IPermissionMapper { } /** - * @param $ownerId - * @param $newOwnerId - * @return void + * @throws \OCP\DB\Exception */ - public function transferOwnership($ownerId, $newOwnerId) { - $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 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) - { + public function flushCache(?int $boardId = null, ?string $userId = null) { if ($boardId) { unset($this->boardCache[$boardId]); } else { diff --git a/lib/Db/CardMapper.php b/lib/Db/CardMapper.php index ae6fa9c0f..0904be74f 100644 --- a/lib/Db/CardMapper.php +++ b/lib/Db/CardMapper.php @@ -587,12 +587,7 @@ class CardMapper extends QBMapper implements IPermissionMapper { }); } - /** - * @param $ownerId - * @param $newOwnerId - * @return void - */ - public function transferOwnership($ownerId, $newOwnerId) { + public function transferOwnership(string $ownerId, string $newOwnerId, int $boardId = null): void { $params = [ 'owner' => $ownerId, 'newOwner' => $newOwnerId diff --git a/lib/Service/BoardService.php b/lib/Service/BoardService.php index ceea63519..7ac663db7 100644 --- a/lib/Service/BoardService.php +++ b/lib/Service/BoardService.php @@ -681,15 +681,33 @@ class BoardService { return $newBoard; } - public function transferOwnership(string $owner, string $newOwner): void { + public function transferBoardOwnership(int $boardId, string $newOwner, $changeContent = false): void { + $board = $this->boardMapper->find($boardId); + $previousOwner = $board->getOwner(); + $this->clearBoardFromCache($board); + $this->aclMapper->transferOwnership($boardId, $newOwner); + $this->boardMapper->transferOwnership($previousOwner, $newOwner, $boardId); + + // Optionally also change user assignments and card owner information + if ($changeContent) { + $this->assignedUsersMapper->transferOwnership($previousOwner, $newOwner, $boardId); + $this->cardMapper->transferOwnership($previousOwner, $newOwner, $boardId); + } + } + + public function transferOwnership(string $owner, string $newOwner, $changeContent = false): void { $boards = $this->boardMapper->findAllByUser($owner); foreach ($boards as $board) { $this->clearBoardFromCache($board); - $this->aclMapper->transferOwnership($board->getId(), $owner, $newOwner); + $this->aclMapper->transferOwnership($board->getId(), $newOwner); } $this->boardMapper->transferOwnership($owner, $newOwner); - $this->assignedUsersMapper->transferOwnership($owner, $newOwner); - $this->cardMapper->transferOwnership($owner, $newOwner); + + // Optionally also change user assignments and card owner information + if ($changeContent) { + $this->assignedUsersMapper->transferOwnership($owner, $newOwner); + $this->cardMapper->transferOwnership($owner, $newOwner); + } } private function enrichWithStacks($board, $since = -1) { diff --git a/tests/integration/database/TransferOwnershipTest.php b/tests/integration/database/TransferOwnershipTest.php index 7ffb4d135..8b55642d3 100644 --- a/tests/integration/database/TransferOwnershipTest.php +++ b/tests/integration/database/TransferOwnershipTest.php @@ -10,7 +10,7 @@ use OCA\Deck\Db\Card; /** * @group DB - * @coversDefaultClass OCA\Deck\Service\BoardService + * @coversDefaultClass \OCA\Deck\Service\BoardService */ class TransferOwnershipTest extends \Test\TestCase { private const TEST_USER_1 = 'test-share-user1'; @@ -92,8 +92,7 @@ class TransferOwnershipTest extends \Test\TestCase { /** * @covers ::transferOwnership */ - public function testTransferBoardOwnershipWithData() - { + public function testTransferBoardOwnershipWithData() { $this->boardService->transferOwnership(self::TEST_USER_1, self::TEST_USER_2); $board = $this->boardService->find($this->board->getId()); @@ -105,7 +104,7 @@ class TransferOwnershipTest extends \Test\TestCase { $cardUpdated = $this->cardService->find($card->getId()); return $cardUpdated->getOwner() === self::TEST_USER_2; })); - $this->assertTrue($newOwnerOwnsTheCards); + $this->assertTrue($newOwnerOwnsTheCards); } /** @@ -137,17 +136,27 @@ class TransferOwnershipTest extends \Test\TestCase { * @covers ::transferOwnership */ public function testTransferCardOwnership() { - $this->boardService->transferOwnership(self::TEST_USER_1, self::TEST_USER_2); + $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() { + $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() { - $this->boardService->transferOwnership(self::TEST_USER_1, self::TEST_USER_2); + $this->boardService->transferOwnership(self::TEST_USER_1, self::TEST_USER_2, true); $users = $this->assignmentMapper->findAll($this->cards[0]->getId()); $participantsUIDs = []; foreach ($users as $user) { @@ -157,6 +166,20 @@ class TransferOwnershipTest extends \Test\TestCase { $this->assertNotContains(self::TEST_USER_1, $participantsUIDs); } + /** + * @covers ::transferOwnership + */ + public function testNoReassignCardToNewOwner() { + $this->boardService->transferOwnership(self::TEST_USER_1, self::TEST_USER_2, false); + $users = $this->assignmentMapper->findAll($this->cards[0]->getId()); + $participantsUIDs = []; + foreach ($users as $user) { + $participantsUIDs[] = $user->getParticipant(); + } + $this->assertContains(self::TEST_USER_1, $participantsUIDs); + $this->assertNotContains(self::TEST_USER_2, $participantsUIDs); + } + /** * @covers ::transferOwnership */ diff --git a/tests/unit/Service/AttachmentServiceTest.php b/tests/unit/Service/AttachmentServiceTest.php index 1a005c297..287c31672 100644 --- a/tests/unit/Service/AttachmentServiceTest.php +++ b/tests/unit/Service/AttachmentServiceTest.php @@ -240,7 +240,7 @@ class AttachmentServiceTest extends TestCase { $this->attachmentServiceImpl->expects($this->exactly(2)) ->method('extendData') ->withConsecutive( - [$attachments[0]], + [$attachments[0]], [$attachments[1]] ); @@ -277,7 +277,7 @@ class AttachmentServiceTest extends TestCase { $this->attachmentServiceImpl->expects($this->exactly(4)) ->method('extendData') ->withConsecutive( - [$attachments[0]], + [$attachments[0]], [$attachments[1]], [$attachmentsDeleted[0]], [$attachmentsDeleted[1]] From 7f3a318fc5b4d41c437de32d9fd168c781bd6e3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julius=20H=C3=A4rtl?= Date: Mon, 14 Mar 2022 11:21:45 +0100 Subject: [PATCH 21/33] cleanup test cases MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julius Härtl --- docs/User_documentation_en.md | 18 ++++- tests/unit/Service/AttachmentServiceTest.php | 70 ++++++-------------- 2 files changed, 36 insertions(+), 52 deletions(-) diff --git a/docs/User_documentation_en.md b/docs/User_documentation_en.md index 040808f62..5bec5312b 100644 --- a/docs/User_documentation_en.md +++ b/docs/User_documentation_en.md @@ -91,8 +91,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` -`$ php occ deck:transfer-ownership owner newOwner` + +```bash +php occ deck:transfer-ownership owner 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 owner newOwner +``` + +Individual boards can be transferred by adding the id of the board to the command: + +```bash +php occ deck:transfer-ownership owner newOwner 123 +``` diff --git a/tests/unit/Service/AttachmentServiceTest.php b/tests/unit/Service/AttachmentServiceTest.php index 287c31672..e90692b8a 100644 --- a/tests/unit/Service/AttachmentServiceTest.php +++ b/tests/unit/Service/AttachmentServiceTest.php @@ -116,16 +116,10 @@ class AttachmentServiceTest extends TestCase { [FileService::class], [FilesAppService::class] ) - ->willReturnOnConsecutiveCalls($this->attachmentServiceImpl, $this->filesAppServiceImpl); - - /* $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); */ + ->willReturnOnConsecutiveCalls( + $this->attachmentServiceImpl, + $this->filesAppServiceImpl + ); $this->application->expects($this->any()) ->method('getContainer') @@ -150,20 +144,11 @@ class AttachmentServiceTest extends TestCase { [FilesAppService::class], [MyAttachmentService::class] ) - ->willReturnOnConsecutiveCalls($fileServiceMock, $fileAppServiceMock, new MyAttachmentService()); - - /* $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()); */ + ->willReturnOnConsecutiveCalls( + $fileServiceMock, + $fileAppServiceMock, + new MyAttachmentService() + ); $application->expects($this->any()) ->method('getContainer') @@ -188,20 +173,12 @@ class AttachmentServiceTest extends TestCase { [FilesAppService::class], [MyAttachmentService::class] ) - ->willReturnOnConsecutiveCalls($fileServiceMock, $fileAppServiceMock, new MyAttachmentService()); + ->willReturnOnConsecutiveCalls( + $fileServiceMock, + $fileAppServiceMock, + new MyAttachmentService() + ); - /* $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()); */ $application->expects($this->any()) ->method('getContainer') ->willReturn($appContainer); @@ -241,15 +218,13 @@ class AttachmentServiceTest extends TestCase { ->method('extendData') ->withConsecutive( [$attachments[0]], - [$attachments[1]] + [$attachments[1]], + ) + ->willReturnOnConsecutiveCalls( + $attachments[0], + $attachments[1], ); - /* $this->attachmentServiceImpl->expects($this->at(0)) - ->method('extendData') - ->with($attachments[0]); - $this->attachmentServiceImpl->expects($this->at(1)) - ->method('extendData') - ->with($attachments[1]); */ $this->assertEquals($attachments, $this->attachmentService->findAll(123, false)); } @@ -283,12 +258,6 @@ class AttachmentServiceTest extends TestCase { [$attachmentsDeleted[1]] ); - /* $this->attachmentServiceImpl->expects($this->at(0)) - ->method('extendData') - ->with($attachments[0]); - $this->attachmentServiceImpl->expects($this->at(1)) - ->method('extendData') - ->with($attachments[1]); */ $this->assertEquals(array_merge($attachments, $attachmentsDeleted), $this->attachmentService->findAll(123, true)); } @@ -464,5 +433,6 @@ class AttachmentServiceTest extends TestCase { ->method('allowUndo') ->willReturn(false); $actual = $this->attachmentService->restore(1, 1); + $this->assertEquals($expected, $actual); } } From 7786c86f47b7aef860d78e26b0de4026f2c2c2a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julius=20H=C3=A4rtl?= Date: Mon, 14 Mar 2022 17:25:06 +0100 Subject: [PATCH 22/33] fix: Properly handle limited scope for remapping users MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julius Härtl --- lib/Db/AclMapper.php | 26 +++----- lib/Db/AssignmentMapper.php | 53 +++++++++------ lib/Db/CardMapper.php | 33 ++++++++++ lib/Service/BoardService.php | 36 ++++++---- tests/integration/config/behat.yml | 2 +- .../database/TransferOwnershipTest.php | 65 ++++++++++++++----- 6 files changed, 149 insertions(+), 66 deletions(-) diff --git a/lib/Db/AclMapper.php b/lib/Db/AclMapper.php index bc7784bdc..5cf188aa0 100644 --- a/lib/Db/AclMapper.php +++ b/lib/Db/AclMapper.php @@ -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 { @@ -59,23 +60,14 @@ class AclMapper extends DeckMapper implements IPermissionMapper { } /** - * @param $ownerId - * @param $newOwnerId - * @return void + * @throws \OCP\DB\Exception */ - public function transferOwnership($boardId, $newOwnerId) { - $params = [ - 'newOwner' => $newOwnerId, - 'type' => Acl::PERMISSION_TYPE_USER, - 'boardId' => $boardId - ]; - - // Drop existing ACL rules for the new owner - $sql = "DELETE FROM `{$this->tableName}` - WHERE `participant` = :newOwner - AND `type` = :type - AND `board_id` = :boardId"; - $stmt = $this->execute($sql, $params); - $stmt->closeCursor(); + 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(); } } diff --git a/lib/Db/AssignmentMapper.php b/lib/Db/AssignmentMapper.php index 06c37e24d..fdbf80d85 100644 --- a/lib/Db/AssignmentMapper.php +++ b/lib/Db/AssignmentMapper.php @@ -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; @@ -147,26 +148,38 @@ class AssignmentMapper extends QBMapper implements IPermissionMapper { return null; } - /** - * @psalm-suppress InvalidScalarArgument - * @param $ownerId - * @param $newOwnerId - * @return void - */ - public function transferOwnership(string $ownerId, string $newOwnerId, int $boardId = null) { - $params = [ - 'owner' => $ownerId, - 'newOwner' => $newOwnerId, - 'type' => Assignment::TYPE_USER - ]; - $qb = $this->db->getQueryBuilder(); - $sql = "DELETE FROM `*PREFIX*{$this->tableName}` WHERE `participant` = :newOwner AND `type`= :type AND id IN - (SELECT id FROM `*PREFIX*{$this->tableName}` WHERE `participant` = :owner)"; - $stmt = $this->db->executeQuery($sql, $params); - $stmt->closeCursor(); + 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); - $sql = "UPDATE `*PREFIX*{$this->tableName}` SET `participant` = :newOwner WHERE `participant` = :owner AND `type`= :type"; - $stmt = $this->db->executeQuery($sql, $params); - $stmt->closeCursor(); + $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(); } } diff --git a/lib/Db/CardMapper.php b/lib/Db/CardMapper.php index 0904be74f..4accb8fd0 100644 --- a/lib/Db/CardMapper.php +++ b/lib/Db/CardMapper.php @@ -596,4 +596,37 @@ class CardMapper extends QBMapper implements IPermissionMapper { $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(); + } } diff --git a/lib/Service/BoardService.php b/lib/Service/BoardService.php index 7ac663db7..a8678f488 100644 --- a/lib/Service/BoardService.php +++ b/lib/Service/BoardService.php @@ -685,28 +685,38 @@ class BoardService { $board = $this->boardMapper->find($boardId); $previousOwner = $board->getOwner(); $this->clearBoardFromCache($board); - $this->aclMapper->transferOwnership($boardId, $newOwner); + $this->aclMapper->deleteParticipantFromBoard($boardId, Acl::PERMISSION_TYPE_USER, $newOwner); $this->boardMapper->transferOwnership($previousOwner, $newOwner, $boardId); // Optionally also change user assignments and card owner information if ($changeContent) { - $this->assignedUsersMapper->transferOwnership($previousOwner, $newOwner, $boardId); - $this->cardMapper->transferOwnership($previousOwner, $newOwner, $boardId); + $this->assignedUsersMapper->remapAssignedUser($boardId, $previousOwner, $newOwner); + $this->cardMapper->remapCardOwner($boardId, $previousOwner, $newOwner); } } public function transferOwnership(string $owner, string $newOwner, $changeContent = false): void { - $boards = $this->boardMapper->findAllByUser($owner); - foreach ($boards as $board) { - $this->clearBoardFromCache($board); - $this->aclMapper->transferOwnership($board->getId(), $newOwner); - } - $this->boardMapper->transferOwnership($owner, $newOwner); + \OC::$server->getDatabaseConnection()->beginTransaction(); + try { + $boards = $this->boardMapper->findAllByUser($owner); + foreach ($boards as $board) { + $this->clearBoardFromCache($board); + } - // Optionally also change user assignments and card owner information - if ($changeContent) { - $this->assignedUsersMapper->transferOwnership($owner, $newOwner); - $this->cardMapper->transferOwnership($owner, $newOwner); + $this->boardMapper->transferOwnership($owner, $newOwner); + // Optionally also change user assignments and card owner information + if ($changeContent) { + foreach ($boards as $board) { + $this->clearBoardFromCache($board); + $this->aclMapper->deleteParticipantFromBoard($board->getId(), Acl::PERMISSION_TYPE_USER, $newOwner); + $this->assignedUsersMapper->remapAssignedUser($board->getId(), $owner, $newOwner); + $this->cardMapper->remapCardOwner($board->getId(), $owner, $newOwner); + } + } + + \OC::$server->getDatabaseConnection()->commit(); + } catch (\Throwable $e) { + \OC::$server->getDatabaseConnection()->rollBack(); } } diff --git a/tests/integration/config/behat.yml b/tests/integration/config/behat.yml index 507138122..b8673a677 100644 --- a/tests/integration/config/behat.yml +++ b/tests/integration/config/behat.yml @@ -5,7 +5,7 @@ default: - '%paths.base%/../features/' contexts: - ServerContext: - baseUrl: http://localhost:9090/ + baseUrl: http://localhost:8080/ - RequestContext - BoardContext - CommentContext diff --git a/tests/integration/database/TransferOwnershipTest.php b/tests/integration/database/TransferOwnershipTest.php index 8b55642d3..a7e4fbf9e 100644 --- a/tests/integration/database/TransferOwnershipTest.php +++ b/tests/integration/database/TransferOwnershipTest.php @@ -157,11 +157,9 @@ class TransferOwnershipTest extends \Test\TestCase { */ public function testReassignCardToNewOwner() { $this->boardService->transferOwnership(self::TEST_USER_1, self::TEST_USER_2, true); - $users = $this->assignmentMapper->findAll($this->cards[0]->getId()); - $participantsUIDs = []; - foreach ($users as $user) { - $participantsUIDs[] = $user->getParticipant(); - } + $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); } @@ -171,11 +169,9 @@ class TransferOwnershipTest extends \Test\TestCase { */ public function testNoReassignCardToNewOwner() { $this->boardService->transferOwnership(self::TEST_USER_1, self::TEST_USER_2, false); - $users = $this->assignmentMapper->findAll($this->cards[0]->getId()); - $participantsUIDs = []; - foreach ($users as $user) { - $participantsUIDs[] = $user->getParticipant(); - } + $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); } @@ -186,11 +182,9 @@ class TransferOwnershipTest extends \Test\TestCase { public function testReassignCardToNewParticipantOnlyIfParticipantHasUserType() { $this->assignmentService->assignUser($this->cards[1]->getId(), self::TEST_USER_1, Assignment::TYPE_GROUP); $this->boardService->transferOwnership(self::TEST_USER_1, self::TEST_USER_2); - $users = $this->assignmentMapper->findAll($this->cards[1]->getId()); - $participantsUIDs = []; - foreach ($users as $user) { - $participantsUIDs[] = $user->getParticipant(); - } + $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); } @@ -243,6 +237,47 @@ class TransferOwnershipTest extends \Test\TestCase { $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(); From 3d925fb145f6efa9b1d28da4877e744edb625ac3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julius=20H=C3=A4rtl?= Date: Mon, 14 Mar 2022 17:56:07 +0100 Subject: [PATCH 23/33] Reuse single board transfer for all user boards MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julius Härtl --- lib/Command/TransferOwnership.php | 8 +++-- lib/Service/BoardService.php | 54 +++++++++++++------------------ 2 files changed, 27 insertions(+), 35 deletions(-) diff --git a/lib/Command/TransferOwnership.php b/lib/Command/TransferOwnership.php index 3b42132ca..715200f75 100644 --- a/lib/Command/TransferOwnership.php +++ b/lib/Command/TransferOwnership.php @@ -77,12 +77,14 @@ final class TransferOwnership extends Command { if ($boardId) { $this->boardService->transferBoardOwnership($boardId, $newOwner, $remapAssignment); - $output->writeln("Board " . $board->getTitle() . " from ". $board->getOwner() ." transferred to $newOwner completed"); + $output->writeln("Board " . $board->getTitle() . " from ". $board->getOwner() ." transferred to $newOwner completed"); return 0; } - $this->boardService->transferOwnership($owner, $newOwner, $remapAssignment); - $output->writeln("All boards from $owner to $newOwner transferred"); + foreach ($this->boardService->transferOwnership($owner, $newOwner, $remapAssignment) as $board) { + $output->writeln(" - " . $board->getTitle() . " transferred"); + } + $output->writeln("All boards from $owner to $newOwner transferred"); return 0; } diff --git a/lib/Service/BoardService.php b/lib/Service/BoardService.php index a8678f488..556408551 100644 --- a/lib/Service/BoardService.php +++ b/lib/Service/BoardService.php @@ -681,42 +681,32 @@ class BoardService { return $newBoard; } - public function transferBoardOwnership(int $boardId, string $newOwner, $changeContent = false): void { - $board = $this->boardMapper->find($boardId); - $previousOwner = $board->getOwner(); - $this->clearBoardFromCache($board); - $this->aclMapper->deleteParticipantFromBoard($boardId, Acl::PERMISSION_TYPE_USER, $newOwner); - $this->boardMapper->transferOwnership($previousOwner, $newOwner, $boardId); + 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); + $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); + // 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, $changeContent = false): void { - \OC::$server->getDatabaseConnection()->beginTransaction(); - try { - $boards = $this->boardMapper->findAllByUser($owner); - foreach ($boards as $board) { - $this->clearBoardFromCache($board); - } - - $this->boardMapper->transferOwnership($owner, $newOwner); - // Optionally also change user assignments and card owner information - if ($changeContent) { - foreach ($boards as $board) { - $this->clearBoardFromCache($board); - $this->aclMapper->deleteParticipantFromBoard($board->getId(), Acl::PERMISSION_TYPE_USER, $newOwner); - $this->assignedUsersMapper->remapAssignedUser($board->getId(), $owner, $newOwner); - $this->cardMapper->remapCardOwner($board->getId(), $owner, $newOwner); - } - } - - \OC::$server->getDatabaseConnection()->commit(); - } catch (\Throwable $e) { - \OC::$server->getDatabaseConnection()->rollBack(); + public function transferOwnership(string $owner, string $newOwner, bool $changeContent = false): \Generator { + $boards = $this->boardMapper->findAllByUser($owner); + foreach ($boards as $board) { + yield $this->transferBoardOwnership($board->getId(), $newOwner, $changeContent); } } From b75fb76c087866e07d2d5e4301a6a8e5e34f1adf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julius=20H=C3=A4rtl?= Date: Mon, 14 Mar 2022 19:12:04 +0100 Subject: [PATCH 24/33] fix: test cases using generator MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julius Härtl --- .../database/TransferOwnershipTest.php | 27 +++++++++---------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/tests/integration/database/TransferOwnershipTest.php b/tests/integration/database/TransferOwnershipTest.php index a7e4fbf9e..c7e9662d5 100644 --- a/tests/integration/database/TransferOwnershipTest.php +++ b/tests/integration/database/TransferOwnershipTest.php @@ -82,8 +82,7 @@ class TransferOwnershipTest extends \Test\TestCase { * @covers ::transferOwnership */ public function testTransferBoardOwnership() { - $this->boardService->transferOwnership(self::TEST_USER_1, self::TEST_USER_2); - /* $this->invokePrivate($this->boardService, 'clearBoardsCache'); */ + 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); @@ -93,7 +92,7 @@ class TransferOwnershipTest extends \Test\TestCase { * @covers ::transferOwnership */ public function testTransferBoardOwnershipWithData() { - $this->boardService->transferOwnership(self::TEST_USER_1, self::TEST_USER_2); + iterator_to_array($this->boardService->transferOwnership(self::TEST_USER_1, self::TEST_USER_2)); $board = $this->boardService->find($this->board->getId()); $boardOwner = $board->getOwner(); @@ -111,7 +110,7 @@ class TransferOwnershipTest extends \Test\TestCase { * @covers ::transferOwnership */ public function testTransferACLOwnership() { - $this->boardService->transferOwnership(self::TEST_USER_1, self::TEST_USER_2); + iterator_to_array($this->boardService->transferOwnership(self::TEST_USER_1, self::TEST_USER_2)); $board = $this->boardService->find($this->board->getId()); $acl = $board->getAcl(); // Check if old owner is no longer in ACL @@ -124,7 +123,7 @@ class TransferOwnershipTest extends \Test\TestCase { * @covers ::transferOwnership */ public function testNoTransferAclOwnershipIfGroupType() { - $this->boardService->transferOwnership(self::TEST_USER_1, self::TEST_USER_2); + 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) { @@ -136,7 +135,7 @@ class TransferOwnershipTest extends \Test\TestCase { * @covers ::transferOwnership */ public function testTransferCardOwnership() { - $this->boardService->transferOwnership(self::TEST_USER_1, self::TEST_USER_2, true); + 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); @@ -146,7 +145,7 @@ class TransferOwnershipTest extends \Test\TestCase { * @covers ::transferOwnership */ public function testTransferPreserveCardOwnership() { - $this->boardService->transferOwnership(self::TEST_USER_1, self::TEST_USER_2, false); + 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); @@ -156,7 +155,7 @@ class TransferOwnershipTest extends \Test\TestCase { * @covers ::transferOwnership */ public function testReassignCardToNewOwner() { - $this->boardService->transferOwnership(self::TEST_USER_1, self::TEST_USER_2, true); + 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())); @@ -168,7 +167,7 @@ class TransferOwnershipTest extends \Test\TestCase { * @covers ::transferOwnership */ public function testNoReassignCardToNewOwner() { - $this->boardService->transferOwnership(self::TEST_USER_1, self::TEST_USER_2, false); + 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())); @@ -181,7 +180,7 @@ class TransferOwnershipTest extends \Test\TestCase { */ public function testReassignCardToNewParticipantOnlyIfParticipantHasUserType() { $this->assignmentService->assignUser($this->cards[1]->getId(), self::TEST_USER_1, Assignment::TYPE_GROUP); - $this->boardService->transferOwnership(self::TEST_USER_1, self::TEST_USER_2); + 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())); @@ -194,14 +193,14 @@ class TransferOwnershipTest extends \Test\TestCase { */ public function testTargetAlreadyParticipantOfBoard() { $this->expectNotToPerformAssertions(); - $this->boardService->transferOwnership(self::TEST_USER_1, self::TEST_USER_3); + iterator_to_array($this->boardService->transferOwnership(self::TEST_USER_1, self::TEST_USER_3)); } /** * @covers ::transferOwnership */ public function testDontRemoveTargetFromAcl() { - $this->boardService->transferOwnership(self::TEST_USER_2, self::TEST_USER_3); + iterator_to_array($this->boardService->transferOwnership(self::TEST_USER_2, self::TEST_USER_3)); $board = $this->boardService->find($this->board->getId()); $acl = $board->getAcl(); $isOwnerInAcl = (bool)array_filter($acl, function ($item) { @@ -215,7 +214,7 @@ class TransferOwnershipTest extends \Test\TestCase { */ public function testMergePermissions() { $this->boardService->addAcl($this->board->getId(), Acl::PERMISSION_TYPE_USER, self::TEST_USER_2, true, false, true); - $this->boardService->transferOwnership(self::TEST_USER_2, self::TEST_USER_3); + iterator_to_array($this->boardService->transferOwnership(self::TEST_USER_2, self::TEST_USER_3)); $board = $this->boardService->find($this->board->getId()); $acl = $board->getAcl(); $isMerged = (bool)array_filter($acl, function ($item) { @@ -234,7 +233,7 @@ class TransferOwnershipTest extends \Test\TestCase { public function testTargetAlreadyParticipantOfCard() { $this->expectNotToPerformAssertions(); $this->assignmentService->assignUser($this->cards[0]->getId(), self::TEST_USER_3, Assignment::TYPE_USER); - $this->boardService->transferOwnership(self::TEST_USER_1, self::TEST_USER_3); + iterator_to_array($this->boardService->transferOwnership(self::TEST_USER_1, self::TEST_USER_3)); } /** From f46c31f1207815a9c5bcf7146daf332b1835da49 Mon Sep 17 00:00:00 2001 From: Luka Trovic Date: Mon, 14 Mar 2022 22:42:34 +0100 Subject: [PATCH 25/33] feat: add api endpoint and UI to transfer a board to a different user Signed-off-by: Luka Trovic --- appinfo/routes.php | 1 + lib/Controller/BoardController.php | 11 ++++++ lib/Service/BoardService.php | 6 ++++ src/components/board/SharingTabSidebar.vue | 39 +++++++++++++++++++++- src/store/main.js | 8 ++++- 5 files changed, 63 insertions(+), 2 deletions(-) diff --git a/appinfo/routes.php b/appinfo/routes.php index 0f553333a..8e43b417f 100644 --- a/appinfo/routes.php +++ b/appinfo/routes.php @@ -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'], diff --git a/lib/Controller/BoardController.php b/lib/Controller/BoardController.php index 9d0b9fcaf..086cf8a59 100644 --- a/lib/Controller/BoardController.php +++ b/lib/Controller/BoardController.php @@ -155,4 +155,15 @@ class BoardController extends ApiController { public function clone($boardId) { return $this->boardService->clone($boardId, $this->userId); } + + /** + * @NoAdminRequired + * @param $boardId + * @param $owner + * @param $newOwner + * * @return null|void + */ + public function transferOwner($boardId, $owner, $newOwner) { + return $this->boardService->transferOwnership($owner, $newOwner); + } } diff --git a/lib/Service/BoardService.php b/lib/Service/BoardService.php index 556408551..9f47afba7 100644 --- a/lib/Service/BoardService.php +++ b/lib/Service/BoardService.php @@ -746,6 +746,12 @@ class BoardService { $this->boardsCache = null; } + private function getBoardOwner($boardId) { + $board = $this->boardMapper->find($boardId); + + return $board->getOwner(); + } + /** * Clean a given board data from the Cache */ diff --git a/src/components/board/SharingTabSidebar.vue b/src/components/board/SharingTabSidebar.vue index b1f84bf91..d09c99afd 100644 --- a/src/components/board/SharingTabSidebar.vue +++ b/src/components/board/SharingTabSidebar.vue @@ -53,6 +53,9 @@ {{ t('deck', 'Can manage') }} + + {{ t('deck', 'Owner') }} + {{ t('deck', 'Delete') }} @@ -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,39 @@ export default { clickDeleteAcl(acl) { this.$store.dispatch('deleteAclFromCurrentBoard', acl) }, + clickTranserOwner(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, + owner: this.board.owner.uid, + }) + 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 + ) + }, }, } diff --git a/src/store/main.js b/src/store/main.js index c157423bf..d0e63cf0e 100644 --- a/src/store/main.js +++ b/src/store/main.js @@ -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' @@ -497,5 +497,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, + }) + }, }, }) From eb69512b5fb85fbe402efe4b9b22e883ac95ce84 Mon Sep 17 00:00:00 2001 From: Luka Trovic Date: Wed, 16 Mar 2022 17:13:29 +0100 Subject: [PATCH 26/33] fix: feedback Signed-off-by: Luka Trovic --- lib/Controller/BoardController.php | 10 ++++++++-- lib/Service/BoardService.php | 6 ------ src/components/board/SharingTabSidebar.vue | 7 +++---- 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/lib/Controller/BoardController.php b/lib/Controller/BoardController.php index 086cf8a59..b82629723 100644 --- a/lib/Controller/BoardController.php +++ b/lib/Controller/BoardController.php @@ -27,6 +27,8 @@ use OCA\Deck\Db\Acl; 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 { @@ -163,7 +165,11 @@ class BoardController extends ApiController { * @param $newOwner * * @return null|void */ - public function transferOwner($boardId, $owner, $newOwner) { - return $this->boardService->transferOwnership($owner, $newOwner); + 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); } } diff --git a/lib/Service/BoardService.php b/lib/Service/BoardService.php index 9f47afba7..556408551 100644 --- a/lib/Service/BoardService.php +++ b/lib/Service/BoardService.php @@ -746,12 +746,6 @@ class BoardService { $this->boardsCache = null; } - private function getBoardOwner($boardId) { - $board = $this->boardMapper->find($boardId); - - return $board->getOwner(); - } - /** * Clean a given board data from the Cache */ diff --git a/src/components/board/SharingTabSidebar.vue b/src/components/board/SharingTabSidebar.vue index d09c99afd..b51089eb6 100644 --- a/src/components/board/SharingTabSidebar.vue +++ b/src/components/board/SharingTabSidebar.vue @@ -53,7 +53,7 @@ {{ t('deck', 'Can manage') }} - + {{ t('deck', 'Owner') }} @@ -198,7 +198,7 @@ export default { clickDeleteAcl(acl) { this.$store.dispatch('deleteAclFromCurrentBoard', acl) }, - clickTranserOwner(newOwner) { + 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.'), @@ -214,8 +214,7 @@ export default { this.isLoading = true await this.$store.dispatch('transferOwnership', { boardId: this.board.id, - newOwner, - owner: this.board.owner.uid, + newOwner }) const successMessage = t('deck', 'Transfer the board for {user} successfully', { user: newOwner }) showSuccess(successMessage) From 379f1144b3624616e36f45e661b1e815b7f5007c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julius=20H=C3=A4rtl?= Date: Mon, 21 Mar 2022 13:42:15 +0100 Subject: [PATCH 27/33] Cover case where the owner is preserved MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julius Härtl --- lib/Controller/BoardController.php | 3 +- lib/Service/BoardService.php | 10 +++- src/components/board/SharingTabSidebar.vue | 2 +- .../database/TransferOwnershipTest.php | 58 ++++++++++++++----- 4 files changed, 56 insertions(+), 17 deletions(-) diff --git a/lib/Controller/BoardController.php b/lib/Controller/BoardController.php index b82629723..c5e2c62a0 100644 --- a/lib/Controller/BoardController.php +++ b/lib/Controller/BoardController.php @@ -24,6 +24,7 @@ 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; @@ -152,7 +153,7 @@ 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); diff --git a/lib/Service/BoardService.php b/lib/Service/BoardService.php index 556408551..ee0da6720 100644 --- a/lib/Service/BoardService.php +++ b/lib/Service/BoardService.php @@ -24,6 +24,7 @@ namespace OCA\Deck\Service; +use Doctrine\DBAL\Exception\UniqueConstraintViolationException; use OCA\Deck\Activity\ActivityManager; use OCA\Deck\Activity\ChangeSet; use OCA\Deck\AppInfo\Application; @@ -694,6 +695,11 @@ class BoardService { if ($changeContent) { $this->assignedUsersMapper->remapAssignedUser($boardId, $previousOwner, $newOwner); $this->cardMapper->remapCardOwner($boardId, $previousOwner, $newOwner); + } else { + try { + $this->addAcl($boardId, Acl::PERMISSION_TYPE_USER, $previousOwner, true, true, true); + } catch (UniqueConstraintViolationException $e) { + } } \OC::$server->getDatabaseConnection()->commit(); return $this->boardMapper->find($boardId); @@ -706,7 +712,9 @@ class BoardService { public function transferOwnership(string $owner, string $newOwner, bool $changeContent = false): \Generator { $boards = $this->boardMapper->findAllByUser($owner); foreach ($boards as $board) { - yield $this->transferBoardOwnership($board->getId(), $newOwner, $changeContent); + if ($board->getOwner() === $owner) { + yield $this->transferBoardOwnership($board->getId(), $newOwner, $changeContent); + } } } diff --git a/src/components/board/SharingTabSidebar.vue b/src/components/board/SharingTabSidebar.vue index b51089eb6..0aa2136d2 100644 --- a/src/components/board/SharingTabSidebar.vue +++ b/src/components/board/SharingTabSidebar.vue @@ -53,7 +53,7 @@ {{ t('deck', 'Can manage') }} - + {{ t('deck', 'Owner') }} diff --git a/tests/integration/database/TransferOwnershipTest.php b/tests/integration/database/TransferOwnershipTest.php index c7e9662d5..a88178c06 100644 --- a/tests/integration/database/TransferOwnershipTest.php +++ b/tests/integration/database/TransferOwnershipTest.php @@ -64,7 +64,6 @@ class TransferOwnershipTest extends \Test\TestCase { $stacks = []; $board = $this->boardService->create('Test', 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); @@ -110,13 +109,20 @@ class TransferOwnershipTest extends \Test\TestCase { * @covers ::transferOwnership */ public function testTransferACLOwnership() { - iterator_to_array($this->boardService->transferOwnership(self::TEST_USER_1, self::TEST_USER_2)); + 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(); - // Check if old owner is no longer in ACL - $this->assertTrue((bool)array_filter($acl, function ($item) { - return $item->getParticipant() === self::TEST_USER_1 && $item->getType() === Acl::PERMISSION_TYPE_USER; - })); + $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); } /** @@ -196,17 +202,41 @@ class TransferOwnershipTest extends \Test\TestCase { 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 testDontRemoveTargetFromAcl() { - iterator_to_array($this->boardService->transferOwnership(self::TEST_USER_2, self::TEST_USER_3)); + public function testDontRemoveOldOwnerFromAcl() { + iterator_to_array($this->boardService->transferOwnership(self::TEST_USER_1, self::TEST_USER_2)); $board = $this->boardService->find($this->board->getId()); - $acl = $board->getAcl(); - $isOwnerInAcl = (bool)array_filter($acl, function ($item) { - return $item->getParticipant() === self::TEST_USER_3 && $item->getType() === Acl::PERMISSION_TYPE_USER; - }); - $this->assertTrue($isOwnerInAcl); + + $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); } /** @@ -214,7 +244,7 @@ class TransferOwnershipTest extends \Test\TestCase { */ 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_2, self::TEST_USER_3)); + 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) { From a3336cb0a0d8b458308b0967c7e6f623e56f149c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julius=20H=C3=A4rtl?= Date: Tue, 22 Mar 2022 08:21:18 +0100 Subject: [PATCH 28/33] Handle board exceptions more gracefully MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julius Härtl --- lib/Command/TransferOwnership.php | 18 ++++++++++++++++-- lib/Controller/BoardController.php | 4 ---- lib/Service/BoardService.php | 13 +++++++------ lib/Service/PermissionService.php | 9 +++++++++ 4 files changed, 32 insertions(+), 12 deletions(-) diff --git a/lib/Command/TransferOwnership.php b/lib/Command/TransferOwnership.php index 715200f75..95a4f65bb 100644 --- a/lib/Command/TransferOwnership.php +++ b/lib/Command/TransferOwnership.php @@ -2,7 +2,9 @@ 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; @@ -13,12 +15,16 @@ use Symfony\Component\Console\Question\ConfirmationQuestion; final class TransferOwnership extends Command { protected $boardService; + protected $boardMapper; + protected $permissionService; protected $questionHelper; - public function __construct(BoardService $boardService, QuestionHelper $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; } @@ -57,7 +63,15 @@ final class TransferOwnership extends Command { $remapAssignment = $input->getOption('remap'); - $board = $boardId ? $this->boardService->find($boardId) : null; + $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() . ")"); diff --git a/lib/Controller/BoardController.php b/lib/Controller/BoardController.php index c5e2c62a0..0e909c305 100644 --- a/lib/Controller/BoardController.php +++ b/lib/Controller/BoardController.php @@ -161,10 +161,6 @@ class BoardController extends ApiController { /** * @NoAdminRequired - * @param $boardId - * @param $owner - * @param $newOwner - * * @return null|void */ public function transferOwner(int $boardId, string $newOwner): DataResponse { if ($this->permissionService->userIsBoardOwner($boardId, $this->userId)) { diff --git a/lib/Service/BoardService.php b/lib/Service/BoardService.php index ee0da6720..e1cfc8023 100644 --- a/lib/Service/BoardService.php +++ b/lib/Service/BoardService.php @@ -524,7 +524,7 @@ 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); @@ -689,17 +689,18 @@ class BoardService { $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); - } else { - try { - $this->addAcl($boardId, Acl::PERMISSION_TYPE_USER, $previousOwner, true, true, true); - } catch (UniqueConstraintViolationException $e) { - } } \OC::$server->getDatabaseConnection()->commit(); return $this->boardMapper->find($boardId); diff --git a/lib/Service/PermissionService.php b/lib/Service/PermissionService.php index e94d073df..6777eb910 100644 --- a/lib/Service/PermissionService.php +++ b/lib/Service/PermissionService.php @@ -333,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; + } } From cffcd4fd6655349b163499ed1837be104e56a981 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julius=20H=C3=A4rtl?= Date: Tue, 22 Mar 2022 08:22:29 +0100 Subject: [PATCH 29/33] Adjust documentaion wording MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julius Härtl --- docs/User_documentation_en.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/User_documentation_en.md b/docs/User_documentation_en.md index 5bec5312b..c2731687d 100644 --- a/docs/User_documentation_en.md +++ b/docs/User_documentation_en.md @@ -94,19 +94,19 @@ Other text tokens will be used to perform a case-insensitive search on the 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` +You can transfer ownership of boards, cards, etc to a new user, using `occ` command `deck:transfer-ownership` ```bash -php occ deck:transfer-ownership owner newOwner +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 owner newOwner +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 owner newOwner 123 +php occ deck:transfer-ownership previousOwner newOwner 123 ``` From f840bbba1159729d4986ae7c39c7fba3763d8d0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julius=20H=C3=A4rtl?= Date: Tue, 22 Mar 2022 14:32:55 +0100 Subject: [PATCH 30/33] PHP 7.2 compatbility MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julius Härtl --- tests/unit/Notification/NotificationHelperTest.php | 2 +- tests/unit/Service/AttachmentServiceTest.php | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/unit/Notification/NotificationHelperTest.php b/tests/unit/Notification/NotificationHelperTest.php index c4f0fd9cd..c831afebe 100644 --- a/tests/unit/Notification/NotificationHelperTest.php +++ b/tests/unit/Notification/NotificationHelperTest.php @@ -124,7 +124,7 @@ class NotificationHelperTest extends \Test\TestCase { ->withConsecutive( [$param1[0], $param2, $param3, $DUE_ASSIGNED], [$param1[1], $param2, $param3, $DUE_ASSIGNED], - [$param1[2], $param2, $param3, $DUE_ASSIGNED], + [$param1[2], $param2, $param3, $DUE_ASSIGNED] ) ->willReturn(ConfigService::SETTING_BOARD_NOTIFICATION_DUE_ALL); diff --git a/tests/unit/Service/AttachmentServiceTest.php b/tests/unit/Service/AttachmentServiceTest.php index e90692b8a..1abad585a 100644 --- a/tests/unit/Service/AttachmentServiceTest.php +++ b/tests/unit/Service/AttachmentServiceTest.php @@ -218,11 +218,11 @@ class AttachmentServiceTest extends TestCase { ->method('extendData') ->withConsecutive( [$attachments[0]], - [$attachments[1]], + [$attachments[1]] ) ->willReturnOnConsecutiveCalls( $attachments[0], - $attachments[1], + $attachments[1] ); $this->assertEquals($attachments, $this->attachmentService->findAll(123, false)); From 490cfb239671290f261b13dbc869e5a56608840c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julius=20H=C3=A4rtl?= Date: Tue, 22 Mar 2022 15:07:42 +0100 Subject: [PATCH 31/33] Fix tests and move to 7.3 as a min php version MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julius Härtl --- .github/workflows/lint.yml | 2 +- composer.json | 7 +- composer.lock | 1868 ++++++++++++----------- tests/unit/Service/BoardServiceTest.php | 6 + 4 files changed, 984 insertions(+), 899 deletions(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 28ee43de3..18e95644c 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -13,7 +13,7 @@ jobs: strategy: matrix: - php-versions: ['7.2', '7.3', '7.4'] + php-versions: ['7.3', '7.4'] name: php${{ matrix.php-versions }} lint steps: diff --git a/composer.json b/composer.json index 1110ce42b..f5b618eab 100644 --- a/composer.json +++ b/composer.json @@ -13,14 +13,17 @@ }, "require-dev": { "roave/security-advisories": "dev-master", - "christophwurst/nextcloud": "^21@dev", - "phpunit/phpunit": "^9", + "christophwurst/nextcloud": "^22@dev", + "phpunit/phpunit": "^8", "nextcloud/coding-standard": "^0.5.0", "symfony/event-dispatcher": "^4.0", "vimeo/psalm": "^4.3", "php-parallel-lint/php-parallel-lint": "^1.2" }, "config": { + "platform": { + "php": "7.3" + }, "optimize-autoloader": true, "classmap-authoritative": true }, diff --git a/composer.lock b/composer.lock index 80616ada1..08731c74c 100644 --- a/composer.lock +++ b/composer.lock @@ -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": "a4af2d671205bfc230250e69ead06492", + "content-hash": "bd041cd124789c31ce51141042fb8721", "packages": [ { "name": "cogpowered/finediff", @@ -59,22 +59,23 @@ "issues": "https://github.com/cogpowered/FineDiff/issues", "source": "https://github.com/cogpowered/FineDiff/tree/master" }, + "abandoned": true, "time": "2014-05-19T10:25:02+00:00" } ], "packages-dev": [ { "name": "amphp/amp", - "version": "v2.6.1", + "version": "v2.6.2", "source": { "type": "git", "url": "https://github.com/amphp/amp.git", - "reference": "c5fc66a78ee38d7ac9195a37bacaf940eb3f65ae" + "reference": "9d5100cebffa729aaffecd3ad25dc5aeea4f13bb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/amphp/amp/zipball/c5fc66a78ee38d7ac9195a37bacaf940eb3f65ae", - "reference": "c5fc66a78ee38d7ac9195a37bacaf940eb3f65ae", + "url": "https://api.github.com/repos/amphp/amp/zipball/9d5100cebffa729aaffecd3ad25dc5aeea4f13bb", + "reference": "9d5100cebffa729aaffecd3ad25dc5aeea4f13bb", "shasum": "" }, "require": { @@ -96,13 +97,13 @@ } }, "autoload": { - "psr-4": { - "Amp\\": "lib" - }, "files": [ "lib/functions.php", "lib/Internal/functions.php" - ] + ], + "psr-4": { + "Amp\\": "lib" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -127,7 +128,7 @@ } ], "description": "A non-blocking concurrency framework for PHP applications.", - "homepage": "http://amphp.org/amp", + "homepage": "https://amphp.org/amp", "keywords": [ "async", "asynchronous", @@ -142,7 +143,7 @@ "support": { "irc": "irc://irc.freenode.org/amphp", "issues": "https://github.com/amphp/amp/issues", - "source": "https://github.com/amphp/amp/tree/v2.6.1" + "source": "https://github.com/amphp/amp/tree/v2.6.2" }, "funding": [ { @@ -150,7 +151,7 @@ "type": "github" } ], - "time": "2021-09-23T18:43:08+00:00" + "time": "2022-02-20T17:52:18+00:00" }, { "name": "amphp/byte-stream", @@ -185,12 +186,12 @@ } }, "autoload": { - "psr-4": { - "Amp\\ByteStream\\": "lib" - }, "files": [ "lib/functions.php" - ] + ], + "psr-4": { + "Amp\\ByteStream\\": "lib" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -231,25 +232,28 @@ }, { "name": "christophwurst/nextcloud", - "version": "v21.0.0-beta8", + "version": "v22.1.1", "source": { "type": "git", "url": "https://github.com/ChristophWurst/nextcloud_composer.git", - "reference": "7c7a5bd142ec8799c8bff8c34abc0d22c97c6c87" + "reference": "8bb086cd016128b5ef8353662fd1852db3248d1e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ChristophWurst/nextcloud_composer/zipball/7c7a5bd142ec8799c8bff8c34abc0d22c97c6c87", - "reference": "7c7a5bd142ec8799c8bff8c34abc0d22c97c6c87", + "url": "https://api.github.com/repos/ChristophWurst/nextcloud_composer/zipball/8bb086cd016128b5ef8353662fd1852db3248d1e", + "reference": "8bb086cd016128b5ef8353662fd1852db3248d1e", "shasum": "" }, "require": { - "php": "^7.3 || ~8.0.0" + "php": "^7.3 || ~8.0.0", + "psr/container": "^1.0", + "psr/event-dispatcher": "^1.0", + "psr/log": "^1.1" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "21.0.0-dev" + "dev-master": "23.0.0-dev" } }, "notification-url": "https://packagist.org/downloads/", @@ -265,22 +269,22 @@ "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-beta8" + "source": "https://github.com/ChristophWurst/nextcloud_composer/tree/v22.1.1" }, - "time": "2021-02-03T07:55:40+00:00" + "time": "2021-11-11T14:01:42+00:00" }, { "name": "composer/package-versions-deprecated", - "version": "1.11.99.4", + "version": "1.11.99.5", "source": { "type": "git", "url": "https://github.com/composer/package-versions-deprecated.git", - "reference": "b174585d1fe49ceed21928a945138948cb394600" + "reference": "b4f54f74ef3453349c24a845d22392cd31e65f1d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/package-versions-deprecated/zipball/b174585d1fe49ceed21928a945138948cb394600", - "reference": "b174585d1fe49ceed21928a945138948cb394600", + "url": "https://api.github.com/repos/composer/package-versions-deprecated/zipball/b4f54f74ef3453349c24a845d22392cd31e65f1d", + "reference": "b4f54f74ef3453349c24a845d22392cd31e65f1d", "shasum": "" }, "require": { @@ -324,7 +328,7 @@ "description": "Composer plugin that provides efficient querying for installed package versions (no runtime IO)", "support": { "issues": "https://github.com/composer/package-versions-deprecated/issues", - "source": "https://github.com/composer/package-versions-deprecated/tree/1.11.99.4" + "source": "https://github.com/composer/package-versions-deprecated/tree/1.11.99.5" }, "funding": [ { @@ -340,27 +344,98 @@ "type": "tidelift" } ], - "time": "2021-09-13T08:41:34+00:00" + "time": "2022-01-17T14:14:24+00:00" }, { - "name": "composer/semver", - "version": "3.2.6", + "name": "composer/pcre", + "version": "1.0.1", "source": { "type": "git", - "url": "https://github.com/composer/semver.git", - "reference": "83e511e247de329283478496f7a1e114c9517506" + "url": "https://github.com/composer/pcre.git", + "reference": "67a32d7d6f9f560b726ab25a061b38ff3a80c560" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/semver/zipball/83e511e247de329283478496f7a1e114c9517506", - "reference": "83e511e247de329283478496f7a1e114c9517506", + "url": "https://api.github.com/repos/composer/pcre/zipball/67a32d7d6f9f560b726ab25a061b38ff3a80c560", + "reference": "67a32d7d6f9f560b726ab25a061b38ff3a80c560", "shasum": "" }, "require": { "php": "^5.3.2 || ^7.0 || ^8.0" }, "require-dev": { - "phpstan/phpstan": "^0.12.54", + "phpstan/phpstan": "^1.3", + "phpstan/phpstan-strict-rules": "^1.1", + "symfony/phpunit-bridge": "^4.2 || ^5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Composer\\Pcre\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + } + ], + "description": "PCRE wrapping library that offers type-safe preg_* replacements.", + "keywords": [ + "PCRE", + "preg", + "regex", + "regular expression" + ], + "support": { + "issues": "https://github.com/composer/pcre/issues", + "source": "https://github.com/composer/pcre/tree/1.0.1" + }, + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" + } + ], + "time": "2022-01-21T20:24:37+00:00" + }, + { + "name": "composer/semver", + "version": "3.3.1", + "source": { + "type": "git", + "url": "https://github.com/composer/semver.git", + "reference": "5d8e574bb0e69188786b8ef77d43341222a41a71" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/semver/zipball/5d8e574bb0e69188786b8ef77d43341222a41a71", + "reference": "5d8e574bb0e69188786b8ef77d43341222a41a71", + "shasum": "" + }, + "require": { + "php": "^5.3.2 || ^7.0 || ^8.0" + }, + "require-dev": { + "phpstan/phpstan": "^1.4", "symfony/phpunit-bridge": "^4.2 || ^5" }, "type": "library", @@ -405,7 +480,7 @@ "support": { "irc": "irc://irc.freenode.org/composer", "issues": "https://github.com/composer/semver/issues", - "source": "https://github.com/composer/semver/tree/3.2.6" + "source": "https://github.com/composer/semver/tree/3.3.1" }, "funding": [ { @@ -421,29 +496,31 @@ "type": "tidelift" } ], - "time": "2021-10-25T11:34:17+00:00" + "time": "2022-03-16T11:22:07+00:00" }, { "name": "composer/xdebug-handler", - "version": "1.4.6", + "version": "2.0.5", "source": { "type": "git", "url": "https://github.com/composer/xdebug-handler.git", - "reference": "f27e06cd9675801df441b3656569b328e04aa37c" + "reference": "9e36aeed4616366d2b690bdce11f71e9178c579a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/f27e06cd9675801df441b3656569b328e04aa37c", - "reference": "f27e06cd9675801df441b3656569b328e04aa37c", + "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/9e36aeed4616366d2b690bdce11f71e9178c579a", + "reference": "9e36aeed4616366d2b690bdce11f71e9178c579a", "shasum": "" }, "require": { + "composer/pcre": "^1", "php": "^5.3.2 || ^7.0 || ^8.0", - "psr/log": "^1.0" + "psr/log": "^1 || ^2 || ^3" }, "require-dev": { - "phpstan/phpstan": "^0.12.55", - "symfony/phpunit-bridge": "^4.2 || ^5" + "phpstan/phpstan": "^1.0", + "phpstan/phpstan-strict-rules": "^1.1", + "symfony/phpunit-bridge": "^4.2 || ^5.0 || ^6.0" }, "type": "library", "autoload": { @@ -469,7 +546,7 @@ "support": { "irc": "irc://irc.freenode.org/composer", "issues": "https://github.com/composer/xdebug-handler/issues", - "source": "https://github.com/composer/xdebug-handler/tree/1.4.6" + "source": "https://github.com/composer/xdebug-handler/tree/2.0.5" }, "funding": [ { @@ -485,7 +562,7 @@ "type": "tidelift" } ], - "time": "2021-03-25T17:01:18+00:00" + "time": "2022-02-24T20:20:32+00:00" }, { "name": "dnoegel/php-xdg-base-dir", @@ -526,35 +603,32 @@ }, { "name": "doctrine/annotations", - "version": "1.11.1", + "version": "1.13.2", "source": { "type": "git", "url": "https://github.com/doctrine/annotations.git", - "reference": "ce77a7ba1770462cd705a91a151b6c3746f9c6ad" + "reference": "5b668aef16090008790395c02c893b1ba13f7e08" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/annotations/zipball/ce77a7ba1770462cd705a91a151b6c3746f9c6ad", - "reference": "ce77a7ba1770462cd705a91a151b6c3746f9c6ad", + "url": "https://api.github.com/repos/doctrine/annotations/zipball/5b668aef16090008790395c02c893b1ba13f7e08", + "reference": "5b668aef16090008790395c02c893b1ba13f7e08", "shasum": "" }, "require": { "doctrine/lexer": "1.*", "ext-tokenizer": "*", - "php": "^7.1 || ^8.0" + "php": "^7.1 || ^8.0", + "psr/cache": "^1 || ^2 || ^3" }, "require-dev": { - "doctrine/cache": "1.*", + "doctrine/cache": "^1.11 || ^2.0", "doctrine/coding-standard": "^6.0 || ^8.1", "phpstan/phpstan": "^0.12.20", - "phpunit/phpunit": "^7.5 || ^9.1.5" + "phpunit/phpunit": "^7.5 || ^8.0 || ^9.1.5", + "symfony/cache": "^4.4 || ^5.2" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.11.x-dev" - } - }, "autoload": { "psr-4": { "Doctrine\\Common\\Annotations\\": "lib/Doctrine/Common/Annotations" @@ -595,35 +669,36 @@ ], "support": { "issues": "https://github.com/doctrine/annotations/issues", - "source": "https://github.com/doctrine/annotations/tree/1.11.1" + "source": "https://github.com/doctrine/annotations/tree/1.13.2" }, - "time": "2020-10-26T10:28:16+00:00" + "time": "2021-08-05T19:00:23+00:00" }, { "name": "doctrine/instantiator", - "version": "1.4.0", + "version": "1.4.1", "source": { "type": "git", "url": "https://github.com/doctrine/instantiator.git", - "reference": "d56bf6102915de5702778fe20f2de3b2fe570b5b" + "reference": "10dcfce151b967d20fde1b34ae6640712c3891bc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/instantiator/zipball/d56bf6102915de5702778fe20f2de3b2fe570b5b", - "reference": "d56bf6102915de5702778fe20f2de3b2fe570b5b", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/10dcfce151b967d20fde1b34ae6640712c3891bc", + "reference": "10dcfce151b967d20fde1b34ae6640712c3891bc", "shasum": "" }, "require": { "php": "^7.1 || ^8.0" }, "require-dev": { - "doctrine/coding-standard": "^8.0", + "doctrine/coding-standard": "^9", "ext-pdo": "*", "ext-phar": "*", - "phpbench/phpbench": "^0.13 || 1.0.0-alpha2", - "phpstan/phpstan": "^0.12", - "phpstan/phpstan-phpunit": "^0.12", - "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0" + "phpbench/phpbench": "^0.16 || ^1", + "phpstan/phpstan": "^1.4", + "phpstan/phpstan-phpunit": "^1", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", + "vimeo/psalm": "^4.22" }, "type": "library", "autoload": { @@ -650,7 +725,7 @@ ], "support": { "issues": "https://github.com/doctrine/instantiator/issues", - "source": "https://github.com/doctrine/instantiator/tree/1.4.0" + "source": "https://github.com/doctrine/instantiator/tree/1.4.1" }, "funding": [ { @@ -666,36 +741,32 @@ "type": "tidelift" } ], - "time": "2020-11-10T18:47:58+00:00" + "time": "2022-03-03T08:28:38+00:00" }, { "name": "doctrine/lexer", - "version": "1.2.1", + "version": "1.2.3", "source": { "type": "git", "url": "https://github.com/doctrine/lexer.git", - "reference": "e864bbf5904cb8f5bb334f99209b48018522f042" + "reference": "c268e882d4dbdd85e36e4ad69e02dc284f89d229" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/lexer/zipball/e864bbf5904cb8f5bb334f99209b48018522f042", - "reference": "e864bbf5904cb8f5bb334f99209b48018522f042", + "url": "https://api.github.com/repos/doctrine/lexer/zipball/c268e882d4dbdd85e36e4ad69e02dc284f89d229", + "reference": "c268e882d4dbdd85e36e4ad69e02dc284f89d229", "shasum": "" }, "require": { - "php": "^7.2 || ^8.0" + "php": "^7.1 || ^8.0" }, "require-dev": { - "doctrine/coding-standard": "^6.0", - "phpstan/phpstan": "^0.11.8", - "phpunit/phpunit": "^8.2" + "doctrine/coding-standard": "^9.0", + "phpstan/phpstan": "^1.3", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", + "vimeo/psalm": "^4.11" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.2.x-dev" - } - }, "autoload": { "psr-4": { "Doctrine\\Common\\Lexer\\": "lib/Doctrine/Common/Lexer" @@ -730,7 +801,7 @@ ], "support": { "issues": "https://github.com/doctrine/lexer/issues", - "source": "https://github.com/doctrine/lexer/tree/1.2.1" + "source": "https://github.com/doctrine/lexer/tree/1.2.3" }, "funding": [ { @@ -746,7 +817,7 @@ "type": "tidelift" } ], - "time": "2020-05-25T17:44:05+00:00" + "time": "2022-02-28T11:07:21+00:00" }, { "name": "felixfbecker/advanced-json-rpc", @@ -851,21 +922,21 @@ }, { "name": "friendsofphp/php-cs-fixer", - "version": "v2.18.2", + "version": "v2.19.3", "source": { "type": "git", "url": "https://github.com/FriendsOfPHP/PHP-CS-Fixer.git", - "reference": "18f8c9d184ba777380794a389fabc179896ba913" + "reference": "75ac86f33fab4714ea5a39a396784d83ae3b5ed8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/FriendsOfPHP/PHP-CS-Fixer/zipball/18f8c9d184ba777380794a389fabc179896ba913", - "reference": "18f8c9d184ba777380794a389fabc179896ba913", + "url": "https://api.github.com/repos/FriendsOfPHP/PHP-CS-Fixer/zipball/75ac86f33fab4714ea5a39a396784d83ae3b5ed8", + "reference": "75ac86f33fab4714ea5a39a396784d83ae3b5ed8", "shasum": "" }, "require": { "composer/semver": "^1.4 || ^2.0 || ^3.0", - "composer/xdebug-handler": "^1.2", + "composer/xdebug-handler": "^1.2 || ^2.0", "doctrine/annotations": "^1.2", "ext-json": "*", "ext-tokenizer": "*", @@ -908,6 +979,11 @@ "php-cs-fixer" ], "type": "application", + "extra": { + "branch-alias": { + "dev-master": "2.19-dev" + } + }, "autoload": { "psr-4": { "PhpCsFixer\\": "src/" @@ -922,6 +998,7 @@ "tests/Test/IntegrationCaseFactoryInterface.php", "tests/Test/InternalIntegrationCaseFactory.php", "tests/Test/IsIdenticalConstraint.php", + "tests/Test/TokensWithObservedTransformers.php", "tests/TestCase.php" ] }, @@ -942,7 +1019,7 @@ "description": "A tool to automatically fix PHP code style", "support": { "issues": "https://github.com/FriendsOfPHP/PHP-CS-Fixer/issues", - "source": "https://github.com/FriendsOfPHP/PHP-CS-Fixer/tree/v2.18.2" + "source": "https://github.com/FriendsOfPHP/PHP-CS-Fixer/tree/v2.19.3" }, "funding": [ { @@ -950,41 +1027,42 @@ "type": "github" } ], - "time": "2021-01-26T00:22:21+00:00" + "time": "2021-11-15T17:17:55+00:00" }, { "name": "myclabs/deep-copy", - "version": "1.10.2", + "version": "1.11.0", "source": { "type": "git", "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "776f831124e9c62e1a2c601ecc52e776d8bb7220" + "reference": "14daed4296fae74d9e3201d2c4925d1acb7aa614" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/776f831124e9c62e1a2c601ecc52e776d8bb7220", - "reference": "776f831124e9c62e1a2c601ecc52e776d8bb7220", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/14daed4296fae74d9e3201d2c4925d1acb7aa614", + "reference": "14daed4296fae74d9e3201d2c4925d1acb7aa614", "shasum": "" }, "require": { "php": "^7.1 || ^8.0" }, - "replace": { - "myclabs/deep-copy": "self.version" + "conflict": { + "doctrine/collections": "<1.6.8", + "doctrine/common": "<2.13.3 || >=3,<3.2.2" }, "require-dev": { - "doctrine/collections": "^1.0", - "doctrine/common": "^2.6", - "phpunit/phpunit": "^7.1" + "doctrine/collections": "^1.6.8", + "doctrine/common": "^2.13.3 || ^3.2.2", + "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13" }, "type": "library", "autoload": { - "psr-4": { - "DeepCopy\\": "src/DeepCopy/" - }, "files": [ "src/DeepCopy/deep_copy.php" - ] + ], + "psr-4": { + "DeepCopy\\": "src/DeepCopy/" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -1000,7 +1078,7 @@ ], "support": { "issues": "https://github.com/myclabs/DeepCopy/issues", - "source": "https://github.com/myclabs/DeepCopy/tree/1.10.2" + "source": "https://github.com/myclabs/DeepCopy/tree/1.11.0" }, "funding": [ { @@ -1008,7 +1086,7 @@ "type": "tidelift" } ], - "time": "2020-11-13T09:40:50+00:00" + "time": "2022-03-03T13:19:32+00:00" }, { "name": "netresearch/jsonmapper", @@ -1104,16 +1182,16 @@ }, { "name": "nikic/php-parser", - "version": "v4.13.0", + "version": "v4.13.2", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "50953a2691a922aa1769461637869a0a2faa3f53" + "reference": "210577fe3cf7badcc5814d99455df46564f3c077" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/50953a2691a922aa1769461637869a0a2faa3f53", - "reference": "50953a2691a922aa1769461637869a0a2faa3f53", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/210577fe3cf7badcc5814d99455df46564f3c077", + "reference": "210577fe3cf7badcc5814d99455df46564f3c077", "shasum": "" }, "require": { @@ -1154,9 +1232,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v4.13.0" + "source": "https://github.com/nikic/PHP-Parser/tree/v4.13.2" }, - "time": "2021-09-20T12:20:58+00:00" + "time": "2021-11-30T19:35:32+00:00" }, { "name": "openlss/lib-array2xml", @@ -1273,16 +1351,16 @@ }, { "name": "phar-io/version", - "version": "3.1.0", + "version": "3.2.1", "source": { "type": "git", "url": "https://github.com/phar-io/version.git", - "reference": "bae7c545bef187884426f042434e561ab1ddb182" + "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phar-io/version/zipball/bae7c545bef187884426f042434e561ab1ddb182", - "reference": "bae7c545bef187884426f042434e561ab1ddb182", + "url": "https://api.github.com/repos/phar-io/version/zipball/4f7fd7836c6f332bb2933569e566a0d6c4cbed74", + "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74", "shasum": "" }, "require": { @@ -1318,9 +1396,9 @@ "description": "Library for handling version information and constraints", "support": { "issues": "https://github.com/phar-io/version/issues", - "source": "https://github.com/phar-io/version/tree/3.1.0" + "source": "https://github.com/phar-io/version/tree/3.2.1" }, - "time": "2021-02-23T14:00:09+00:00" + "time": "2022-02-21T01:04:05+00:00" }, { "name": "php-cs-fixer/diff", @@ -1379,16 +1457,16 @@ }, { "name": "php-parallel-lint/php-parallel-lint", - "version": "v1.3.1", + "version": "v1.3.2", "source": { "type": "git", "url": "https://github.com/php-parallel-lint/PHP-Parallel-Lint.git", - "reference": "761f3806e30239b5fcd90a0a45d41dc2138de192" + "reference": "6483c9832e71973ed29cf71bd6b3f4fde438a9de" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-parallel-lint/PHP-Parallel-Lint/zipball/761f3806e30239b5fcd90a0a45d41dc2138de192", - "reference": "761f3806e30239b5fcd90a0a45d41dc2138de192", + "url": "https://api.github.com/repos/php-parallel-lint/PHP-Parallel-Lint/zipball/6483c9832e71973ed29cf71bd6b3f4fde438a9de", + "reference": "6483c9832e71973ed29cf71bd6b3f4fde438a9de", "shasum": "" }, "require": { @@ -1401,7 +1479,7 @@ }, "require-dev": { "nette/tester": "^1.3 || ^2.0", - "php-parallel-lint/php-console-highlighter": "~0.3", + "php-parallel-lint/php-console-highlighter": "0.* || ^1.0", "squizlabs/php_codesniffer": "^3.6" }, "suggest": { @@ -1413,7 +1491,7 @@ "type": "library", "autoload": { "classmap": [ - "./" + "./src/" ] }, "notification-url": "https://packagist.org/downloads/", @@ -1430,9 +1508,9 @@ "homepage": "https://github.com/php-parallel-lint/PHP-Parallel-Lint", "support": { "issues": "https://github.com/php-parallel-lint/PHP-Parallel-Lint/issues", - "source": "https://github.com/php-parallel-lint/PHP-Parallel-Lint/tree/v1.3.1" + "source": "https://github.com/php-parallel-lint/PHP-Parallel-Lint/tree/v1.3.2" }, - "time": "2021-08-13T05:35:13+00:00" + "time": "2022-02-21T12:50:22+00:00" }, { "name": "phpdocumentor/reflection-common", @@ -1546,16 +1624,16 @@ }, { "name": "phpdocumentor/type-resolver", - "version": "1.5.1", + "version": "1.6.0", "source": { "type": "git", "url": "https://github.com/phpDocumentor/TypeResolver.git", - "reference": "a12f7e301eb7258bb68acd89d4aefa05c2906cae" + "reference": "93ebd0014cab80c4ea9f5e297ea48672f1b87706" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/a12f7e301eb7258bb68acd89d4aefa05c2906cae", - "reference": "a12f7e301eb7258bb68acd89d4aefa05c2906cae", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/93ebd0014cab80c4ea9f5e297ea48672f1b87706", + "reference": "93ebd0014cab80c4ea9f5e297ea48672f1b87706", "shasum": "" }, "require": { @@ -1590,22 +1668,22 @@ "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", "support": { "issues": "https://github.com/phpDocumentor/TypeResolver/issues", - "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.5.1" + "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.6.0" }, - "time": "2021-10-02T14:08:47+00:00" + "time": "2022-01-04T19:58:01+00:00" }, { "name": "phpspec/prophecy", - "version": "1.14.0", + "version": "v1.15.0", "source": { "type": "git", "url": "https://github.com/phpspec/prophecy.git", - "reference": "d86dfc2e2a3cd366cee475e52c6bb3bbc371aa0e" + "reference": "bbcd7380b0ebf3961ee21409db7b38bc31d69a13" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpspec/prophecy/zipball/d86dfc2e2a3cd366cee475e52c6bb3bbc371aa0e", - "reference": "d86dfc2e2a3cd366cee475e52c6bb3bbc371aa0e", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/bbcd7380b0ebf3961ee21409db7b38bc31d69a13", + "reference": "bbcd7380b0ebf3961ee21409db7b38bc31d69a13", "shasum": "" }, "require": { @@ -1657,50 +1735,46 @@ ], "support": { "issues": "https://github.com/phpspec/prophecy/issues", - "source": "https://github.com/phpspec/prophecy/tree/1.14.0" + "source": "https://github.com/phpspec/prophecy/tree/v1.15.0" }, - "time": "2021-09-10T09:02:12+00:00" + "time": "2021-12-08T12:19:24+00:00" }, { "name": "phpunit/php-code-coverage", - "version": "9.2.7", + "version": "7.0.15", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "d4c798ed8d51506800b441f7a13ecb0f76f12218" + "reference": "819f92bba8b001d4363065928088de22f25a3a48" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/d4c798ed8d51506800b441f7a13ecb0f76f12218", - "reference": "d4c798ed8d51506800b441f7a13ecb0f76f12218", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/819f92bba8b001d4363065928088de22f25a3a48", + "reference": "819f92bba8b001d4363065928088de22f25a3a48", "shasum": "" }, "require": { "ext-dom": "*", - "ext-libxml": "*", "ext-xmlwriter": "*", - "nikic/php-parser": "^4.12.0", - "php": ">=7.3", - "phpunit/php-file-iterator": "^3.0.3", - "phpunit/php-text-template": "^2.0.2", - "sebastian/code-unit-reverse-lookup": "^2.0.2", - "sebastian/complexity": "^2.0", - "sebastian/environment": "^5.1.2", - "sebastian/lines-of-code": "^1.0.3", - "sebastian/version": "^3.0.1", - "theseer/tokenizer": "^1.2.0" + "php": ">=7.2", + "phpunit/php-file-iterator": "^2.0.2", + "phpunit/php-text-template": "^1.2.1", + "phpunit/php-token-stream": "^3.1.3 || ^4.0", + "sebastian/code-unit-reverse-lookup": "^1.0.1", + "sebastian/environment": "^4.2.2", + "sebastian/version": "^2.0.1", + "theseer/tokenizer": "^1.1.3" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^8.2.2" }, "suggest": { - "ext-pcov": "*", - "ext-xdebug": "*" + "ext-xdebug": "^2.7.2" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "9.2-dev" + "dev-master": "7.0-dev" } }, "autoload": { @@ -1728,7 +1802,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.7" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/7.0.15" }, "funding": [ { @@ -1736,32 +1810,32 @@ "type": "github" } ], - "time": "2021-09-17T05:39:03+00:00" + "time": "2021-07-26T12:20:09+00:00" }, { "name": "phpunit/php-file-iterator", - "version": "3.0.5", + "version": "2.0.5", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-file-iterator.git", - "reference": "aa4be8575f26070b100fccb67faabb28f21f66f8" + "reference": "42c5ba5220e6904cbfe8b1a1bda7c0cfdc8c12f5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/aa4be8575f26070b100fccb67faabb28f21f66f8", - "reference": "aa4be8575f26070b100fccb67faabb28f21f66f8", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/42c5ba5220e6904cbfe8b1a1bda7c0cfdc8c12f5", + "reference": "42c5ba5220e6904cbfe8b1a1bda7c0cfdc8c12f5", "shasum": "" }, "require": { - "php": ">=7.3" + "php": ">=7.1" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^8.5" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-master": "2.0.x-dev" } }, "autoload": { @@ -1788,7 +1862,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues", - "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/3.0.5" + "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/2.0.5" }, "funding": [ { @@ -1796,97 +1870,26 @@ "type": "github" } ], - "time": "2020-09-28T05:57:25+00:00" - }, - { - "name": "phpunit/php-invoker", - "version": "3.1.1", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-invoker.git", - "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/5a10147d0aaf65b58940a0b72f71c9ac0423cc67", - "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "require-dev": { - "ext-pcntl": "*", - "phpunit/phpunit": "^9.3" - }, - "suggest": { - "ext-pcntl": "*" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.1-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Invoke callables with a timeout", - "homepage": "https://github.com/sebastianbergmann/php-invoker/", - "keywords": [ - "process" - ], - "support": { - "issues": "https://github.com/sebastianbergmann/php-invoker/issues", - "source": "https://github.com/sebastianbergmann/php-invoker/tree/3.1.1" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-09-28T05:58:55+00:00" + "time": "2021-12-02T12:42:26+00:00" }, { "name": "phpunit/php-text-template", - "version": "2.0.4", + "version": "1.2.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-text-template.git", - "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28" + "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28", - "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686", + "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686", "shasum": "" }, "require": { - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" + "php": ">=5.3.3" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0-dev" - } - }, "autoload": { "classmap": [ "src/" @@ -1910,40 +1913,34 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/php-text-template/issues", - "source": "https://github.com/sebastianbergmann/php-text-template/tree/2.0.4" + "source": "https://github.com/sebastianbergmann/php-text-template/tree/1.2.1" }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-10-26T05:33:50+00:00" + "time": "2015-06-21T13:50:34+00:00" }, { "name": "phpunit/php-timer", - "version": "5.0.3", + "version": "2.1.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-timer.git", - "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2" + "reference": "2454ae1765516d20c4ffe103d85a58a9a3bd5662" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2", - "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/2454ae1765516d20c4ffe103d85a58a9a3bd5662", + "reference": "2454ae1765516d20c4ffe103d85a58a9a3bd5662", "shasum": "" }, "require": { - "php": ">=7.3" + "php": ">=7.1" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^8.5" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "5.0-dev" + "dev-master": "2.1-dev" } }, "autoload": { @@ -1969,7 +1966,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/php-timer/issues", - "source": "https://github.com/sebastianbergmann/php-timer/tree/5.0.3" + "source": "https://github.com/sebastianbergmann/php-timer/tree/2.1.3" }, "funding": [ { @@ -1977,20 +1974,80 @@ "type": "github" } ], - "time": "2020-10-26T13:16:10+00:00" + "time": "2020-11-30T08:20:02+00:00" }, { - "name": "phpunit/phpunit", - "version": "9.5.10", + "name": "phpunit/php-token-stream", + "version": "4.0.4", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "c814a05837f2edb0d1471d6e3f4ab3501ca3899a" + "url": "https://github.com/sebastianbergmann/php-token-stream.git", + "reference": "a853a0e183b9db7eed023d7933a858fa1c8d25a3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/c814a05837f2edb0d1471d6e3f4ab3501ca3899a", - "reference": "c814a05837f2edb0d1471d6e3f4ab3501ca3899a", + "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/a853a0e183b9db7eed023d7933a858fa1c8d25a3", + "reference": "a853a0e183b9db7eed023d7933a858fa1c8d25a3", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": "^7.3 || ^8.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Wrapper around PHP's tokenizer extension.", + "homepage": "https://github.com/sebastianbergmann/php-token-stream/", + "keywords": [ + "tokenizer" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-token-stream/issues", + "source": "https://github.com/sebastianbergmann/php-token-stream/tree/master" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "abandoned": true, + "time": "2020-08-04T08:28:15+00:00" + }, + { + "name": "phpunit/phpunit", + "version": "8.5.25", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit.git", + "reference": "9ff23f4dfde040ccd3b8db876192d1184b934158" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/9ff23f4dfde040ccd3b8db876192d1184b934158", + "reference": "9ff23f4dfde040ccd3b8db876192d1184b934158", "shasum": "" }, "require": { @@ -2001,35 +2058,32 @@ "ext-mbstring": "*", "ext-xml": "*", "ext-xmlwriter": "*", - "myclabs/deep-copy": "^1.10.1", + "myclabs/deep-copy": "^1.10.0", "phar-io/manifest": "^2.0.3", "phar-io/version": "^3.0.2", - "php": ">=7.3", - "phpspec/prophecy": "^1.12.1", - "phpunit/php-code-coverage": "^9.2.7", - "phpunit/php-file-iterator": "^3.0.5", - "phpunit/php-invoker": "^3.1.1", - "phpunit/php-text-template": "^2.0.3", - "phpunit/php-timer": "^5.0.2", - "sebastian/cli-parser": "^1.0.1", - "sebastian/code-unit": "^1.0.6", - "sebastian/comparator": "^4.0.5", - "sebastian/diff": "^4.0.3", - "sebastian/environment": "^5.1.3", - "sebastian/exporter": "^4.0.3", - "sebastian/global-state": "^5.0.1", - "sebastian/object-enumerator": "^4.0.3", - "sebastian/resource-operations": "^3.0.3", - "sebastian/type": "^2.3.4", - "sebastian/version": "^3.0.2" + "php": ">=7.2", + "phpspec/prophecy": "^1.10.3", + "phpunit/php-code-coverage": "^7.0.12", + "phpunit/php-file-iterator": "^2.0.4", + "phpunit/php-text-template": "^1.2.1", + "phpunit/php-timer": "^2.1.2", + "sebastian/comparator": "^3.0.2", + "sebastian/diff": "^3.0.2", + "sebastian/environment": "^4.2.3", + "sebastian/exporter": "^3.1.2", + "sebastian/global-state": "^3.0.0", + "sebastian/object-enumerator": "^3.0.3", + "sebastian/resource-operations": "^2.0.1", + "sebastian/type": "^1.1.3", + "sebastian/version": "^2.0.1" }, "require-dev": { - "ext-pdo": "*", - "phpspec/prophecy-phpunit": "^2.0.1" + "ext-pdo": "*" }, "suggest": { "ext-soap": "*", - "ext-xdebug": "*" + "ext-xdebug": "*", + "phpunit/php-invoker": "^2.0.0" }, "bin": [ "phpunit" @@ -2037,15 +2091,12 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "9.5-dev" + "dev-master": "8.5-dev" } }, "autoload": { "classmap": [ "src/" - ], - "files": [ - "src/Framework/Assert/Functions.php" ] }, "notification-url": "https://packagist.org/downloads/", @@ -2068,11 +2119,11 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", - "source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.10" + "source": "https://github.com/sebastianbergmann/phpunit/tree/8.5.25" }, "funding": [ { - "url": "https://phpunit.de/donate.html", + "url": "https://phpunit.de/sponsors.html", "type": "custom" }, { @@ -2080,7 +2131,56 @@ "type": "github" } ], - "time": "2021-09-25T07:38:51+00:00" + "time": "2022-03-16T16:24:13+00:00" + }, + { + "name": "psr/cache", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/cache.git", + "reference": "d11b50ad223250cf17b86e38383413f5a6764bf8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/cache/zipball/d11b50ad223250cf17b86e38383413f5a6764bf8", + "reference": "d11b50ad223250cf17b86e38383413f5a6764bf8", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Cache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for caching libraries", + "keywords": [ + "cache", + "psr", + "psr-6" + ], + "support": { + "source": "https://github.com/php-fig/cache/tree/master" + }, + "time": "2016-08-06T20:24:11+00:00" }, { "name": "psr/container", @@ -2130,6 +2230,56 @@ }, "time": "2021-03-05T17:36:06+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", @@ -2186,181 +2336,289 @@ "source": { "type": "git", "url": "https://github.com/Roave/SecurityAdvisories.git", - "reference": "5f40d4d577a71466f9723122251b46bdaf634709" + "reference": "a1696aadf99f7ff55d44c56e7ebf54eace85310c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/5f40d4d577a71466f9723122251b46bdaf634709", - "reference": "5f40d4d577a71466f9723122251b46bdaf634709", + "url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/a1696aadf99f7ff55d44c56e7ebf54eace85310c", + "reference": "a1696aadf99f7ff55d44c56e7ebf54eace85310c", "shasum": "" }, "conflict": { "3f/pygmentize": "<1.2", - "adodb/adodb-php": "<5.20.12", + "adodb/adodb-php": "<=5.20.20|>=5.21,<=5.21.3", + "akaunting/akaunting": "<2.1.13", + "alextselegidis/easyappointments": "<1.4.3", "alterphp/easyadmin-extension-bundle": ">=1.2,<1.2.11|>=1.3,<1.3.1", + "amazing/media2click": ">=1,<1.3.3", "amphp/artax": "<1.0.6|>=2,<2.0.6", "amphp/http": "<1.0.1", "amphp/http-client": ">=4,<4.4", + "anchorcms/anchor-cms": "<=0.12.7", + "andreapollastri/cipi": "<=3.1.15", "api-platform/core": ">=2.2,<2.2.10|>=2.3,<2.3.6", + "appwrite/server-ce": "<0.11.1|>=0.12,<0.12.2", + "area17/twill": "<1.2.5|>=2,<2.5.3", "asymmetricrypt/asymmetricrypt": ">=0,<9.9.99", "aws/aws-sdk-php": ">=3,<3.2.1", "bagisto/bagisto": "<0.1.5", "barrelstrength/sprout-base-email": "<1.2.7", "barrelstrength/sprout-forms": "<3.9", - "baserproject/basercms": ">=4,<=4.3.6|>=4.4,<4.4.1", - "bolt/bolt": "<3.7.1", + "barryvdh/laravel-translation-manager": "<0.6.2", + "baserproject/basercms": "<4.5.4", + "billz/raspap-webgui": "<=2.6.6", + "bk2k/bootstrap-package": ">=7.1,<7.1.2|>=8,<8.0.8|>=9,<9.0.4|>=9.1,<9.1.3|>=10,<10.0.10|>=11,<11.0.3", + "bolt/bolt": "<3.7.2", + "bolt/core": "<4.1.13", + "bottelet/flarepoint": "<2.2.1", "brightlocal/phpwhois": "<=4.2.5", - "buddypress/buddypress": "<5.1.2", + "buddypress/buddypress": "<7.2.1", "bugsnag/bugsnag-laravel": ">=2,<2.0.2", - "cakephp/cakephp": ">=1.3,<1.3.18|>=2,<2.4.99|>=2.5,<2.5.99|>=2.6,<2.6.12|>=2.7,<2.7.6|>=3,<3.5.18|>=3.6,<3.6.15|>=3.7,<3.7.7", + "bytefury/crater": "<6.0.2", + "cachethq/cachet": "<2.5.1", + "cakephp/cakephp": "<4.0.6", + "cardgate/magento2": "<2.0.33", "cart2quote/module-quotation": ">=4.1.6,<=4.4.5|>=5,<5.4.4", "cartalyst/sentry": "<=2.1.6", - "centreon/centreon": "<18.10.8|>=19,<19.4.5", + "catfan/medoo": "<1.7.5", + "centreon/centreon": "<20.10.7", "cesnet/simplesamlphp-module-proxystatistics": "<3.1", + "codeception/codeception": "<3.1.3|>=4,<4.1.22", "codeigniter/framework": "<=3.0.6", - "composer/composer": "<=1-alpha.11", + "codeigniter4/framework": "<4.1.9", + "codiad/codiad": "<=2.8.4", + "composer/composer": "<1.10.23|>=2-alpha.1,<2.1.9", + "concrete5/concrete5": "<9", + "concrete5/core": "<8.5.7", "contao-components/mediaelement": ">=2.14.2,<2.21.1", "contao/core": ">=2,<3.5.39", - "contao/core-bundle": ">=4,<4.4.52|>=4.5,<4.9.6|= 4.10.0", + "contao/core-bundle": "<4.9.18|>=4.10,<4.11.7|= 4.10.0", "contao/listing-bundle": ">=4,<4.4.8", + "craftcms/cms": "<3.7.14", + "croogo/croogo": "<3.0.7", "datadog/dd-trace": ">=0.30,<0.30.2", "david-garcia/phpwhois": "<=4.3.1", "derhansen/sf_event_mgt": "<4.3.1|>=5,<5.1.1", + "directmailteam/direct-mail": "<5.2.4", "doctrine/annotations": ">=1,<1.2.7", "doctrine/cache": ">=1,<1.3.2|>=1.4,<1.4.2", "doctrine/common": ">=2,<2.4.3|>=2.5,<2.5.1", - "doctrine/dbal": ">=2,<2.0.8|>=2.1,<2.1.2", + "doctrine/dbal": ">=2,<2.0.8|>=2.1,<2.1.2|>=3,<3.1.4", "doctrine/doctrine-bundle": "<1.5.2", "doctrine/doctrine-module": "<=0.7.1", "doctrine/mongodb-odm": ">=1,<1.0.2", "doctrine/mongodb-odm-bundle": ">=2,<3.0.1", - "doctrine/orm": ">=2,<2.4.8|>=2.5,<2.5.1", - "dolibarr/dolibarr": "<11.0.4", + "doctrine/orm": ">=2,<2.4.8|>=2.5,<2.5.1|>=2.8.3,<2.8.4", + "dolibarr/dolibarr": "<16|>= 3.3.beta1, < 13.0.2", "dompdf/dompdf": ">=0.6,<0.6.2", - "drupal/core": ">=7,<7.74|>=8,<8.8.11|>=8.9,<8.9.9|>=9,<9.0.8", - "drupal/drupal": ">=7,<7.74|>=8,<8.8.11|>=8.9,<8.9.9|>=9,<9.0.8", + "drupal/core": ">=7,<7.88|>=8,<9.2.13|>=9.3,<9.3.6", + "drupal/drupal": ">=7,<7.80|>=8,<8.9.16|>=9,<9.1.12|>=9.2,<9.2.4", + "dweeves/magmi": "<=0.7.24", + "ecodev/newsletter": "<=4", + "ectouch/ectouch": "<=2.7.2", + "elgg/elgg": "<3.3.24|>=4,<4.0.5", "endroid/qr-code-bundle": "<3.4.2", - "enshrined/svg-sanitize": "<0.13.1", + "enshrined/svg-sanitize": "<0.15", "erusev/parsedown": "<1.7.2", + "ether/logs": "<3.0.4", "ezsystems/demobundle": ">=5.4,<5.4.6.1", "ezsystems/ez-support-tools": ">=2.2,<2.2.3", "ezsystems/ezdemo-ls-extension": ">=5.4,<5.4.2.1", "ezsystems/ezfind-ls": ">=5.3,<5.3.6.1|>=5.4,<5.4.11.1|>=2017.12,<2017.12.0.1", - "ezsystems/ezplatform": ">=1.7,<1.7.9.1|>=1.13,<1.13.5.1|>=2.5,<2.5.4", - "ezsystems/ezplatform-admin-ui": ">=1.3,<1.3.5|>=1.4,<1.4.6", + "ezsystems/ezplatform": "<=1.13.6|>=2,<=2.5.24", + "ezsystems/ezplatform-admin-ui": ">=1.3,<1.3.5|>=1.4,<1.4.6|>=1.5,<=1.5.25", "ezsystems/ezplatform-admin-ui-assets": ">=4,<4.2.1|>=5,<5.0.1|>=5.1,<5.1.1", - "ezsystems/ezplatform-kernel": ">=1,<1.0.2.1", + "ezsystems/ezplatform-kernel": "<=1.2.5|>=1.3,<1.3.12", + "ezsystems/ezplatform-rest": ">=1.2,<=1.2.2|>=1.3,<1.3.8", + "ezsystems/ezplatform-richtext": ">=2.3,<=2.3.7", "ezsystems/ezplatform-user": ">=1,<1.0.1", - "ezsystems/ezpublish-kernel": ">=5.3,<5.3.12.1|>=5.4,<5.4.14.2|>=6,<6.7.9.1|>=6.8,<6.13.6.3|>=7,<7.2.4.1|>=7.3,<7.3.2.1|>=7.5,<7.5.7.1", - "ezsystems/ezpublish-legacy": ">=5.3,<5.3.12.6|>=5.4,<5.4.14.2|>=2011,<2017.12.7.3|>=2018.6,<2018.6.1.4|>=2018.9,<2018.9.1.3|>=2019.3,<2019.3.5.1", + "ezsystems/ezpublish-kernel": "<=6.13.8.1|>=7,<7.5.26", + "ezsystems/ezpublish-legacy": "<=2017.12.7.3|>=2018.6,<=2019.3.5.1", "ezsystems/platform-ui-assets-bundle": ">=4.2,<4.2.3", "ezsystems/repository-forms": ">=2.3,<2.3.2.1", "ezyang/htmlpurifier": "<4.1.1", + "facade/ignition": "<1.16.15|>=2,<2.4.2|>=2.5,<2.5.2", + "feehi/cms": "<=2.1.1", + "feehi/feehicms": "<=0.1.3", "firebase/php-jwt": "<2", + "flarum/core": ">=1,<=1.0.1", "flarum/sticky": ">=0.1-beta.14,<=0.1-beta.15", "flarum/tags": "<=0.1-beta.13", + "fluidtypo3/vhs": "<5.1.1", "fooman/tcpdf": "<6.2.22", + "forkcms/forkcms": "<=5.9.2", "fossar/tcpdf-parser": "<6.2.22", + "francoisjacquet/rosariosis": "<8.1.1", "friendsofsymfony/oauth2-php": "<1.3", "friendsofsymfony/rest-bundle": ">=1.2,<1.2.2", "friendsofsymfony/user-bundle": ">=1.2,<1.3.5", "friendsoftypo3/mediace": ">=7.6.2,<7.6.5", + "froala/wysiwyg-editor": "<3.2.7", "fuel/core": "<1.8.1", - "getgrav/grav": "<1.7-beta.8", - "getkirby/cms": ">=3,<3.4.5", + "gaoming13/wechat-php-sdk": "<=1.10.2", + "genix/cms": "<=1.1.11", + "getgrav/grav": "<1.7.31", + "getkirby/cms": "<3.5.8", "getkirby/panel": "<2.5.14", + "gilacms/gila": "<=1.11.4", + "globalpayments/php-sdk": "<2", + "google/protobuf": "<3.15", "gos/web-socket-bundle": "<1.10.4|>=2,<2.6.1|>=3,<3.3", "gree/jose": "<=2.2", "gregwar/rst": "<1.0.3", + "grumpydictator/firefly-iii": "<5.6.5", "guzzlehttp/guzzle": ">=4-rc.2,<4.2.4|>=5,<5.3.1|>=6,<6.2.1", + "guzzlehttp/psr7": "<1.8.4|>=2,<2.1.1", + "helloxz/imgurl": "<=2.31", + "hillelcoren/invoice-ninja": "<5.3.35", + "hjue/justwriting": "<=1", + "hov/jobfair": "<1.0.13|>=2,<2.0.2", + "hyn/multi-tenant": ">=5.6,<5.7.2", + "ibexa/post-install": "<=1.0.4", + "icecoder/icecoder": "<=8.1", "illuminate/auth": ">=4,<4.0.99|>=4.1,<=4.1.31|>=4.2,<=4.2.22|>=5,<=5.0.35|>=5.1,<=5.1.46|>=5.2,<=5.2.45|>=5.3,<=5.3.31|>=5.4,<=5.4.36|>=5.5,<5.5.10", "illuminate/cookie": ">=4,<=4.0.11|>=4.1,<=4.1.99999|>=4.2,<=4.2.99999|>=5,<=5.0.99999|>=5.1,<=5.1.99999|>=5.2,<=5.2.99999|>=5.3,<=5.3.99999|>=5.4,<=5.4.99999|>=5.5,<=5.5.49|>=5.6,<=5.6.99999|>=5.7,<=5.7.99999|>=5.8,<=5.8.99999|>=6,<6.18.31|>=7,<7.22.4", - "illuminate/database": "<6.20.14|>=7,<7.30.4|>=8,<8.24", + "illuminate/database": "<6.20.26|>=7,<7.30.5|>=8,<8.40", "illuminate/encryption": ">=4,<=4.0.11|>=4.1,<=4.1.31|>=4.2,<=4.2.22|>=5,<=5.0.35|>=5.1,<=5.1.46|>=5.2,<=5.2.45|>=5.3,<=5.3.31|>=5.4,<=5.4.36|>=5.5,<5.5.40|>=5.6,<5.6.15", - "illuminate/view": ">=7,<7.1.2", + "illuminate/view": "<6.20.42|>=7,<7.30.6|>=8,<8.75", + "impresscms/impresscms": "<=1.4.2", + "in2code/femanager": "<5.5.1|>=6,<6.3.1", + "intelliants/subrion": "<=4.2.1", "ivankristianto/phpwhois": "<=4.3", - "james-heinrich/getid3": "<1.9.9", + "jackalope/jackalope-doctrine-dbal": "<1.7.4", + "james-heinrich/getid3": "<1.9.21", + "joomla/archive": "<1.1.10", "joomla/session": "<1.3.1", + "jsdecena/laracom": "<2.0.9", "jsmitty12/phpwhois": "<5.1", "kazist/phpwhois": "<=4.2.6", + "kevinpapst/kimai2": "<1.16.7", "kitodo/presentation": "<3.1.2", + "klaviyo/magento2-extension": ">=1,<3", "kreait/firebase-php": ">=3.2,<3.8.1", "la-haute-societe/tcpdf": "<6.2.22", - "laravel/framework": "<6.20.14|>=7,<7.30.4|>=8,<8.24", + "laminas/laminas-form": "<2.17.1|>=3,<3.0.2|>=3.1,<3.1.1", + "laminas/laminas-http": "<2.14.2", + "laravel/fortify": "<1.11.1", + "laravel/framework": "<6.20.42|>=7,<7.30.6|>=8,<8.75", "laravel/socialite": ">=1,<1.0.99|>=2,<2.0.10", + "latte/latte": "<2.10.8", + "lavalite/cms": "<=5.8", + "lcobucci/jwt": ">=3.4,<3.4.6|>=4,<4.0.4|>=4.1,<4.1.5", "league/commonmark": "<0.18.3", - "librenms/librenms": "<1.53", + "league/flysystem": "<1.1.4|>=2,<2.1.1", + "lexik/jwt-authentication-bundle": "<2.10.7|>=2.11,<2.11.3", + "librenms/librenms": "<22.2.2", + "limesurvey/limesurvey": "<3.27.19", + "livehelperchat/livehelperchat": "<=3.91", "livewire/livewire": ">2.2.4,<2.2.6", + "lms/routes": "<2.1.1", + "localizationteam/l10nmgr": "<7.4|>=8,<8.7|>=9,<9.2", "magento/community-edition": ">=2,<2.2.10|>=2.3,<2.3.3", "magento/magento1ce": "<1.9.4.3", "magento/magento1ee": ">=1,<1.14.4.3", "magento/product-community-edition": ">=2,<2.2.10|>=2.3,<2.3.2-p.2", "marcwillmann/turn": "<0.3.3", - "mautic/core": "<2.16.5|>=3,<3.2.4|= 2.13.1", + "matyhtf/framework": "<3.0.6", + "mautic/core": "<4.2|= 2.13.1", "mediawiki/core": ">=1.27,<1.27.6|>=1.29,<1.29.3|>=1.30,<1.30.2|>=1.31,<1.31.9|>=1.32,<1.32.6|>=1.32.99,<1.33.3|>=1.33.99,<1.34.3|>=1.34.99,<1.35", + "microweber/microweber": "<1.3", + "miniorange/miniorange-saml": "<1.4.3", "mittwald/typo3_forum": "<1.2.1", + "modx/revolution": "<= 2.8.3-pl|<2.8", "monolog/monolog": ">=1.8,<1.12", + "moodle/moodle": "<3.9.11|>=3.10-beta,<3.10.8|>=3.11,<3.11.5", + "mustache/mustache": ">=2,<2.14.1", "namshi/jose": "<2.2", + "neoan3-apps/template": "<1.1.1", + "neos/flow": ">=1,<1.0.4|>=1.1,<1.1.1|>=2,<2.0.1|>=2.3,<2.3.16|>=3,<3.0.12|>=3.1,<3.1.10|>=3.2,<3.2.13|>=3.3,<3.3.13|>=4,<4.0.6", + "neos/form": ">=1.2,<4.3.3|>=5,<5.0.9|>=5.1,<5.1.3", + "neos/neos": ">=1.1,<1.1.3|>=1.2,<1.2.13|>=2,<2.0.4|>=2.3,<2.9.99|>=3,<3.0.20|>=3.1,<3.1.18|>=3.2,<3.2.14|>=3.3,<3.3.23|>=4,<4.0.17|>=4.1,<4.1.16|>=4.2,<4.2.12|>=4.3,<4.3.3", + "neos/swiftmailer": ">=4.1,<4.1.99|>=5.4,<5.4.5", + "netgen/tagsbundle": ">=3.4,<3.4.11|>=4,<4.0.15", "nette/application": ">=2,<2.0.19|>=2.1,<2.1.13|>=2.2,<2.2.10|>=2.3,<2.3.14|>=2.4,<2.4.16|>=3,<3.0.6", "nette/nette": ">=2,<2.0.19|>=2.1,<2.1.13", - "nystudio107/craft-seomatic": "<3.3", + "nilsteampassnet/teampass": "<=2.1.27.36", + "nukeviet/nukeviet": "<4.3.4", + "nystudio107/craft-seomatic": "<3.4.12", "nzo/url-encryptor-bundle": ">=4,<4.3.2|>=5,<5.0.1", - "october/backend": ">=1.0.319,<1.0.470", - "october/cms": "= 1.0.469|>=1.0.319,<1.0.469", - "october/october": ">=1.0.319,<1.0.466", + "october/backend": "<1.1.2", + "october/cms": "= 1.1.1|= 1.0.471|= 1.0.469|>=1.0.319,<1.0.469", + "october/october": ">=1.0.319,<1.0.466|>=2.1,<2.1.12", "october/rain": "<1.0.472|>=1.1,<1.1.2", + "october/system": "<1.0.475|>=1.1,<1.1.11|>=2,<2.1.27", "onelogin/php-saml": "<2.10.4", "oneup/uploader-bundle": "<1.9.3|>=2,<2.1.5", + "opencart/opencart": "<=3.0.3.2", "openid/php-openid": "<2.3", - "openmage/magento-lts": "<19.4.8|>=20,<20.0.4", + "openmage/magento-lts": "<19.4.15|>=20,<20.0.13", "orchid/platform": ">=9,<9.4.4", - "oro/crm": ">=1.7,<1.7.4", - "oro/platform": ">=1.7,<1.7.4", + "oro/crm": ">=1.7,<1.7.4|>=3.1,<4.1.17|>=4.2,<4.2.7", + "oro/platform": ">=1.7,<1.7.4|>=3.1,<3.1.29|>=4.1,<4.1.17|>=4.2,<4.2.8", "padraic/humbug_get_contents": "<1.1.2", "pagarme/pagarme-php": ">=0,<3", + "pagekit/pagekit": "<=1.0.18", "paragonie/random_compat": "<2", "passbolt/passbolt_api": "<2.11", "paypal/merchant-sdk-php": "<3.12", - "pear/archive_tar": "<1.4.12", + "pear/archive_tar": "<1.4.14", + "pear/crypt_gpg": "<1.6.7", + "pegasus/google-for-jobs": "<1.5.1|>=2,<2.1.1", "personnummer/personnummer": "<3.0.2", - "phpfastcache/phpfastcache": ">=5,<5.0.13", - "phpmailer/phpmailer": "<6.1.6", + "phanan/koel": "<5.1.4", + "phpfastcache/phpfastcache": "<6.1.5|>=7,<7.1.2|>=8,<8.0.7", + "phpmailer/phpmailer": "<6.5", "phpmussel/phpmussel": ">=1,<1.6", - "phpmyadmin/phpmyadmin": "<4.9.6|>=5,<5.0.3", - "phpoffice/phpexcel": "<1.8.2", + "phpmyadmin/phpmyadmin": "<5.1.3", + "phpoffice/phpexcel": "<1.8", "phpoffice/phpspreadsheet": "<1.16", + "phpseclib/phpseclib": "<2.0.31|>=3,<3.0.7", + "phpservermon/phpservermon": "<=3.5.2", "phpunit/phpunit": ">=4.8.19,<4.8.28|>=5.0.10,<5.6.3", "phpwhois/phpwhois": "<=4.2.5", "phpxmlrpc/extras": "<0.6.1", - "pimcore/pimcore": "<6.3", - "pocketmine/pocketmine-mp": "<3.15.4", + "pimcore/pimcore": "<=10.3.2", + "pocketmine/pocketmine-mp": "<4.2.4", + "pressbooks/pressbooks": "<5.18", "prestashop/autoupgrade": ">=4,<4.10.1", "prestashop/contactform": ">1.0.1,<4.3", "prestashop/gamification": "<2.3.2", + "prestashop/prestashop": ">=1.7,<=1.7.8.2", "prestashop/productcomments": ">=4,<4.2.1", + "prestashop/ps_emailsubscription": "<2.6.1", "prestashop/ps_facetedsearch": "<3.4.1", + "prestashop/ps_linklist": "<3.1", "privatebin/privatebin": "<1.2.2|>=1.3,<1.3.2", "propel/propel": ">=2-alpha.1,<=2-alpha.7", "propel/propel1": ">=1,<=1.7.1", - "pterodactyl/panel": "<0.7.19|>=1-rc.0,<=1-rc.6", + "pterodactyl/panel": "<1.7", + "ptrofimov/beanstalk_console": "<1.7.14", "pusher/pusher-php-server": "<2.2.1", + "pwweb/laravel-core": "<=0.3.6-beta", "rainlab/debugbar-plugin": "<3.1", + "remdex/livehelperchat": "<3.93", + "rmccue/requests": ">=1.6,<1.8", "robrichards/xmlseclibs": "<3.0.4", + "rudloff/alltube": "<3.0.3", + "s-cart/s-cart": "<6.7.2", "sabberworm/php-css-parser": ">=1,<1.0.1|>=2,<2.0.1|>=3,<3.0.1|>=4,<4.0.1|>=5,<5.0.9|>=5.1,<5.1.3|>=5.2,<5.2.1|>=6,<6.0.2|>=7,<7.0.4|>=8,<8.0.1|>=8.1,<8.1.1|>=8.2,<8.2.1|>=8.3,<8.3.1", "sabre/dav": ">=1.6,<1.6.99|>=1.7,<1.7.11|>=1.8,<1.8.9", "scheb/two-factor-bundle": ">=0,<3.26|>=4,<4.11", "sensiolabs/connect": "<4.2.3", "serluck/phpwhois": "<=4.2.6", - "shopware/core": "<=6.3.4", - "shopware/platform": "<=6.3.5", - "shopware/shopware": "<5.6.9", - "silverstripe/admin": ">=1.0.3,<1.0.4|>=1.1,<1.1.1", + "shopware/core": "<=6.4.8.1", + "shopware/platform": "<=6.4.8.1", + "shopware/production": "<=6.3.5.2", + "shopware/shopware": "<5.7.7", + "shopware/storefront": "<=6.4.8.1", + "showdoc/showdoc": "<2.10.4", + "silverstripe/admin": ">=1,<1.8.1", "silverstripe/assets": ">=1,<1.4.7|>=1.5,<1.5.2", "silverstripe/cms": "<4.3.6|>=4.4,<4.4.4", "silverstripe/comments": ">=1.3,<1.9.99|>=2,<2.9.99|>=3,<3.1.1", "silverstripe/forum": "<=0.6.1|>=0.7,<=0.7.3", - "silverstripe/framework": "<4.4.7|>=4.5,<4.5.4", - "silverstripe/graphql": ">=2,<2.0.5|>=3,<3.1.2|>=3.2,<3.2.4", + "silverstripe/framework": "<4.10.1", + "silverstripe/graphql": "<3.5.2|>=4-alpha.1,<4-alpha.2|= 4.0.0-alpha1", "silverstripe/registry": ">=2.1,<2.1.2|>=2.2,<2.2.1", "silverstripe/restfulserver": ">=1,<1.0.9|>=2,<2.0.4", "silverstripe/subsites": ">=2,<2.1.1", @@ -2372,79 +2630,109 @@ "simplesamlphp/simplesamlphp-module-infocard": "<1.0.1", "simplito/elliptic-php": "<1.0.6", "slim/slim": "<2.6", - "smarty/smarty": "<3.1.33", + "smarty/smarty": "<3.1.43|>=4,<4.0.3", + "snipe/snipe-it": "<5.3.11", "socalnick/scn-social-auth": "<1.15.2", "socialiteproviders/steam": "<1.1", + "spipu/html2pdf": "<5.2.4", "spoonity/tcpdf": "<6.2.22", "squizlabs/php_codesniffer": ">=1,<2.8.1|>=3,<3.0.1", - "ssddanbrown/bookstack": "<0.29.2", + "ssddanbrown/bookstack": "<22.2.3", "stormpath/sdk": ">=0,<9.9.99", - "studio-42/elfinder": "<2.1.49", - "sulu/sulu": "<1.6.34|>=2,<2.0.10|>=2.1,<2.1.1", + "studio-42/elfinder": "<2.1.59", + "subrion/cms": "<=4.2.1", + "sulu/sulu": "= 2.4.0-RC1|<1.6.44|>=2,<2.2.18|>=2.3,<2.3.8", "swiftmailer/swiftmailer": ">=4,<5.4.5", "sylius/admin-bundle": ">=1,<1.0.17|>=1.1,<1.1.9|>=1.2,<1.2.2", "sylius/grid": ">=1,<1.1.19|>=1.2,<1.2.18|>=1.3,<1.3.13|>=1.4,<1.4.5|>=1.5,<1.5.1", - "sylius/grid-bundle": ">=1,<1.1.19|>=1.2,<1.2.18|>=1.3,<1.3.13|>=1.4,<1.4.5|>=1.5,<1.5.1", + "sylius/grid-bundle": "<1.10.1", + "sylius/paypal-plugin": ">=1,<1.2.4|>=1.3,<1.3.1", "sylius/resource-bundle": "<1.3.14|>=1.4,<1.4.7|>=1.5,<1.5.2|>=1.6,<1.6.4", - "sylius/sylius": "<1.6.9|>=1.7,<1.7.9|>=1.8,<1.8.3", + "sylius/sylius": "<1.9.10|>=1.10,<1.10.11|>=1.11,<1.11.2", "symbiote/silverstripe-multivaluefield": ">=3,<3.0.99", + "symbiote/silverstripe-queuedjobs": ">=3,<3.0.2|>=3.1,<3.1.4|>=4,<4.0.7|>=4.1,<4.1.2|>=4.2,<4.2.4|>=4.3,<4.3.3|>=4.4,<4.4.3|>=4.5,<4.5.1|>=4.6,<4.6.4", "symbiote/silverstripe-versionedfiles": "<=2.0.3", + "symfont/process": ">=0,<4", "symfony/cache": ">=3.1,<3.4.35|>=4,<4.2.12|>=4.3,<4.3.8", "symfony/dependency-injection": ">=2,<2.0.17|>=2.7,<2.7.51|>=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.1.12|>=4.2,<4.2.7", "symfony/error-handler": ">=4.4,<4.4.4|>=5,<5.0.4", "symfony/form": ">=2.3,<2.3.35|>=2.4,<2.6.12|>=2.7,<2.7.50|>=2.8,<2.8.49|>=3,<3.4.20|>=4,<4.0.15|>=4.1,<4.1.9|>=4.2,<4.2.1", - "symfony/framework-bundle": ">=2,<2.3.18|>=2.4,<2.4.8|>=2.5,<2.5.2|>=2.7,<2.7.51|>=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.1.12|>=4.2,<4.2.7", + "symfony/framework-bundle": ">=2,<2.3.18|>=2.4,<2.4.8|>=2.5,<2.5.2|>=2.7,<2.7.51|>=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.1.12|>=4.2,<4.2.7|>=5.3.14,<=5.3.14|>=5.4.3,<=5.4.3|>=6.0.3,<=6.0.3|= 6.0.3|= 5.4.3|= 5.3.14", "symfony/http-foundation": ">=2,<2.8.52|>=3,<3.4.35|>=4,<4.2.12|>=4.3,<4.3.8|>=4.4,<4.4.7|>=5,<5.0.7", - "symfony/http-kernel": ">=2,<2.8.52|>=3,<3.4.35|>=4,<4.2.12|>=4.3,<4.4.13|>=5,<5.1.5", + "symfony/http-kernel": ">=2,<2.8.52|>=3,<3.4.35|>=4,<4.2.12|>=4.3,<4.4.13|>=5,<5.1.5|>=5.2,<5.3.12", "symfony/intl": ">=2.7,<2.7.38|>=2.8,<2.8.31|>=3,<3.2.14|>=3.3,<3.3.13", + "symfony/maker-bundle": ">=1.27,<1.29.2|>=1.30,<1.31.1", "symfony/mime": ">=4.3,<4.3.8", "symfony/phpunit-bridge": ">=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.1.12|>=4.2,<4.2.7", "symfony/polyfill": ">=1,<1.10", "symfony/polyfill-php55": ">=1,<1.10", "symfony/proxy-manager-bridge": ">=2.7,<2.7.51|>=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.1.12|>=4.2,<4.2.7", "symfony/routing": ">=2,<2.0.19", - "symfony/security": ">=2,<2.7.51|>=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.1.12|>=4.2,<4.2.7|>=4.4,<4.4.7|>=5,<5.0.7", - "symfony/security-bundle": ">=2,<2.7.48|>=2.8,<2.8.41|>=3,<3.3.17|>=3.4,<3.4.11|>=4,<4.0.11", - "symfony/security-core": ">=2.4,<2.6.13|>=2.7,<2.7.9|>=2.7.30,<2.7.32|>=2.8,<2.8.37|>=3,<3.3.17|>=3.4,<3.4.7|>=4,<4.0.7", + "symfony/security": ">=2,<2.7.51|>=2.8,<3.4.49|>=4,<4.4.24|>=5,<5.2.8", + "symfony/security-bundle": ">=2,<2.7.48|>=2.8,<2.8.41|>=3,<3.3.17|>=3.4,<3.4.11|>=4,<4.0.11|>=5.3,<5.3.12", + "symfony/security-core": ">=2.4,<2.6.13|>=2.7,<2.7.9|>=2.7.30,<2.7.32|>=2.8,<3.4.49|>=4,<4.4.24|>=5,<5.2.9", "symfony/security-csrf": ">=2.4,<2.7.48|>=2.8,<2.8.41|>=3,<3.3.17|>=3.4,<3.4.11|>=4,<4.0.11", - "symfony/security-guard": ">=2.8,<2.8.41|>=3,<3.3.17|>=3.4,<3.4.11|>=4,<4.0.11", - "symfony/security-http": ">=2.3,<2.3.41|>=2.4,<2.7.51|>=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.2.12|>=4.3,<4.3.8|>=4.4,<4.4.7|>=5,<5.0.7", - "symfony/serializer": ">=2,<2.0.11", - "symfony/symfony": ">=2,<2.8.52|>=3,<3.4.35|>=4,<4.2.12|>=4.3,<4.4.13|>=5,<5.1.5", + "symfony/security-guard": ">=2.8,<3.4.48|>=4,<4.4.23|>=5,<5.2.8", + "symfony/security-http": ">=2.3,<2.3.41|>=2.4,<2.7.51|>=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.2.12|>=4.3,<4.3.8|>=4.4,<4.4.7|>=5,<5.0.7|>=5.1,<5.2.8|>=5.3,<5.3.2", + "symfony/serializer": ">=2,<2.0.11|>=4.1,<4.4.35|>=5,<5.3.12", + "symfony/symfony": ">=2,<3.4.49|>=4,<4.4.35|>=5,<5.3.12|>=5.3.14,<=5.3.14|>=5.4.3,<=5.4.3|>=6.0.3,<=6.0.3", "symfony/translation": ">=2,<2.0.17", "symfony/validator": ">=2,<2.0.24|>=2.1,<2.1.12|>=2.2,<2.2.5|>=2.3,<2.3.3", "symfony/var-exporter": ">=4.2,<4.2.12|>=4.3,<4.3.8", "symfony/web-profiler-bundle": ">=2,<2.3.19|>=2.4,<2.4.9|>=2.5,<2.5.4", "symfony/yaml": ">=2,<2.0.22|>=2.1,<2.1.7", + "t3/dce": ">=2.2,<2.6.2", "t3g/svg-sanitizer": "<1.0.3", "tecnickcom/tcpdf": "<6.2.22", + "terminal42/contao-tablelookupwizard": "<3.3.5", "thelia/backoffice-default-template": ">=2.1,<2.1.2", "thelia/thelia": ">=2.1-beta.1,<2.1.3", "theonedemon/phpwhois": "<=4.2.5", + "tinymce/tinymce": "<5.10", "titon/framework": ">=0,<9.9.99", + "topthink/framework": "<6.0.9", + "topthink/think": "<=6.0.9", + "topthink/thinkphp": "<=3.2.3", + "tribalsystems/zenario": "<9.2.55826", "truckersmp/phpwhois": "<=4.3.1", - "twig/twig": "<1.38|>=2,<2.7", - "typo3/cms": ">=6.2,<6.2.30|>=7,<7.6.32|>=8,<8.7.38|>=9,<9.5.23|>=10,<10.4.10", - "typo3/cms-core": ">=8,<8.7.38|>=9,<9.5.23|>=10,<10.4.10", - "typo3/flow": ">=1,<1.0.4|>=1.1,<1.1.1|>=2,<2.0.1|>=2.3,<2.3.16|>=3,<3.0.10|>=3.1,<3.1.7|>=3.2,<3.2.7|>=3.3,<3.3.5", - "typo3/neos": ">=1.1,<1.1.3|>=1.2,<1.2.13|>=2,<2.0.4", + "twig/twig": "<1.38|>=2,<2.14.11|>=3,<3.3.8", + "typo3/cms": ">=6.2,<6.2.30|>=7,<7.6.32|>=8,<8.7.38|>=9,<9.5.29|>=10,<10.4.19|>=11,<11.5", + "typo3/cms-backend": ">=7,<=7.6.50|>=8,<=8.7.39|>=9,<=9.5.24|>=10,<=10.4.13|>=11,<=11.1", + "typo3/cms-core": ">=6.2,<=6.2.56|>=7,<=7.6.52|>=8,<=8.7.41|>=9,<9.5.29|>=10,<10.4.19|>=11,<11.5", + "typo3/cms-form": ">=8,<=8.7.39|>=9,<=9.5.24|>=10,<=10.4.13|>=11,<=11.1", + "typo3/flow": ">=1,<1.0.4|>=1.1,<1.1.1|>=2,<2.0.1|>=2.3,<2.3.16|>=3,<3.0.12|>=3.1,<3.1.10|>=3.2,<3.2.13|>=3.3,<3.3.13|>=4,<4.0.6", + "typo3/neos": ">=1.1,<1.1.3|>=1.2,<1.2.13|>=2,<2.0.4|>=2.3,<2.3.99|>=3,<3.0.20|>=3.1,<3.1.18|>=3.2,<3.2.14|>=3.3,<3.3.23|>=4,<4.0.17|>=4.1,<4.1.16|>=4.2,<4.2.12|>=4.3,<4.3.3", "typo3/phar-stream-wrapper": ">=1,<2.1.1|>=3,<3.1.1", + "typo3/swiftmailer": ">=4.1,<4.1.99|>=5.4,<5.4.5", "typo3fluid/fluid": ">=2,<2.0.8|>=2.1,<2.1.7|>=2.2,<2.2.4|>=2.3,<2.3.7|>=2.4,<2.4.4|>=2.5,<2.5.11|>=2.6,<2.6.10", "ua-parser/uap-php": "<3.8", + "unisharp/laravel-filemanager": "<=2.3", + "userfrosting/userfrosting": ">=0.3.1,<4.6.3", "usmanhalalit/pixie": "<1.0.3|>=2,<2.0.2", + "vanilla/safecurl": "<0.9.2", "verot/class.upload.php": "<=1.0.3|>=2,<=2.0.4", + "vrana/adminer": "<4.8.1", "wallabag/tcpdf": "<6.2.22", + "wanglelecc/laracms": "<=1.0.3", + "web-auth/webauthn-framework": ">=3.3,<3.3.4", + "webcoast/deferred-image-processing": "<1.0.2", + "wikimedia/parsoid": "<0.12.2", "willdurand/js-translation-bundle": "<2.1.1", + "wp-cli/wp-cli": "<2.5", + "yetiforce/yetiforce-crm": "<=6.3", + "yidashi/yii2cmf": "<=2", "yii2mod/yii2-cms": "<1.9.2", "yiisoft/yii": ">=1.1.14,<1.1.15", "yiisoft/yii2": "<2.0.38", "yiisoft/yii2-bootstrap": "<2.0.4", - "yiisoft/yii2-dev": "<2.0.15", + "yiisoft/yii2-dev": "<2.0.43", "yiisoft/yii2-elasticsearch": "<2.0.5", "yiisoft/yii2-gii": "<2.0.4", "yiisoft/yii2-jui": "<2.0.4", "yiisoft/yii2-redis": "<2.0.8", - "yourls/yourls": "<1.7.4", + "yoast-seo-for-typo3/yoast_seo": "<7.2.3", + "yourls/yourls": "<=1.8.2", + "zendesk/zendesk_api_client_php": "<2.2.11", "zendframework/zend-cache": ">=2.4,<2.4.8|>=2.5,<2.5.3", "zendframework/zend-captcha": ">=2,<2.4.9|>=2.5,<2.5.2", "zendframework/zend-crypt": ">=2,<2.4.9|>=2.5,<2.5.2", @@ -2462,14 +2750,15 @@ "zendframework/zend-validator": ">=2.3,<2.3.6", "zendframework/zend-view": ">=2,<2.2.7|>=2.3,<2.3.1", "zendframework/zend-xmlrpc": ">=2.1,<2.1.6|>=2.2,<2.2.6", - "zendframework/zendframework": "<2.5.1", + "zendframework/zendframework": "<=3", "zendframework/zendframework1": "<1.12.20", "zendframework/zendopenid": ">=2,<2.0.2", "zendframework/zendxml": ">=1,<1.0.1", "zetacomponents/mail": "<1.8.2", "zf-commons/zfc-user": "<1.2.2", "zfcampus/zf-apigility-doctrine": ">=1,<1.0.3", - "zfr/zfr-oauth2-server-module": "<0.1.2" + "zfr/zfr-oauth2-server-module": "<0.1.2", + "zoujingli/thinkadmin": "<6.0.22" }, "type": "metapackage", "notification-url": "https://packagist.org/downloads/", @@ -2503,144 +2792,32 @@ "type": "tidelift" } ], - "time": "2021-02-10T03:02:31+00:00" - }, - { - "name": "sebastian/cli-parser", - "version": "1.0.1", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/cli-parser.git", - "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/442e7c7e687e42adc03470c7b668bc4b2402c0b2", - "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Library for parsing CLI options", - "homepage": "https://github.com/sebastianbergmann/cli-parser", - "support": { - "issues": "https://github.com/sebastianbergmann/cli-parser/issues", - "source": "https://github.com/sebastianbergmann/cli-parser/tree/1.0.1" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-09-28T06:08:49+00:00" - }, - { - "name": "sebastian/code-unit", - "version": "1.0.8", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/code-unit.git", - "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/1fc9f64c0927627ef78ba436c9b17d967e68e120", - "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Collection of value objects that represent the PHP code units", - "homepage": "https://github.com/sebastianbergmann/code-unit", - "support": { - "issues": "https://github.com/sebastianbergmann/code-unit/issues", - "source": "https://github.com/sebastianbergmann/code-unit/tree/1.0.8" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-10-26T13:08:54+00:00" + "time": "2022-03-22T13:13:56+00:00" }, { "name": "sebastian/code-unit-reverse-lookup", - "version": "2.0.3", + "version": "1.0.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", - "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5" + "reference": "1de8cd5c010cb153fcd68b8d0f64606f523f7619" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5", - "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/1de8cd5c010cb153fcd68b8d0f64606f523f7619", + "reference": "1de8cd5c010cb153fcd68b8d0f64606f523f7619", "shasum": "" }, "require": { - "php": ">=7.3" + "php": ">=5.6" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^8.5" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0-dev" + "dev-master": "1.0.x-dev" } }, "autoload": { @@ -2662,7 +2839,7 @@ "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", "support": { "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues", - "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/2.0.3" + "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/1.0.2" }, "funding": [ { @@ -2670,34 +2847,34 @@ "type": "github" } ], - "time": "2020-09-28T05:30:19+00:00" + "time": "2020-11-30T08:15:22+00:00" }, { "name": "sebastian/comparator", - "version": "4.0.6", + "version": "3.0.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "55f4261989e546dc112258c7a75935a81a7ce382" + "reference": "1071dfcef776a57013124ff35e1fc41ccd294758" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/55f4261989e546dc112258c7a75935a81a7ce382", - "reference": "55f4261989e546dc112258c7a75935a81a7ce382", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/1071dfcef776a57013124ff35e1fc41ccd294758", + "reference": "1071dfcef776a57013124ff35e1fc41ccd294758", "shasum": "" }, "require": { - "php": ">=7.3", - "sebastian/diff": "^4.0", - "sebastian/exporter": "^4.0" + "php": ">=7.1", + "sebastian/diff": "^3.0", + "sebastian/exporter": "^3.1" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^8.5" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "4.0-dev" + "dev-master": "3.0-dev" } }, "autoload": { @@ -2736,7 +2913,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/comparator/issues", - "source": "https://github.com/sebastianbergmann/comparator/tree/4.0.6" + "source": "https://github.com/sebastianbergmann/comparator/tree/3.0.3" }, "funding": [ { @@ -2744,90 +2921,33 @@ "type": "github" } ], - "time": "2020-10-26T15:49:45+00:00" - }, - { - "name": "sebastian/complexity", - "version": "2.0.2", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/complexity.git", - "reference": "739b35e53379900cc9ac327b2147867b8b6efd88" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/739b35e53379900cc9ac327b2147867b8b6efd88", - "reference": "739b35e53379900cc9ac327b2147867b8b6efd88", - "shasum": "" - }, - "require": { - "nikic/php-parser": "^4.7", - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Library for calculating the complexity of PHP code units", - "homepage": "https://github.com/sebastianbergmann/complexity", - "support": { - "issues": "https://github.com/sebastianbergmann/complexity/issues", - "source": "https://github.com/sebastianbergmann/complexity/tree/2.0.2" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-10-26T15:52:27+00:00" + "time": "2020-11-30T08:04:30+00:00" }, { "name": "sebastian/diff", - "version": "4.0.4", + "version": "3.0.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "3461e3fccc7cfdfc2720be910d3bd73c69be590d" + "reference": "14f72dd46eaf2f2293cbe79c93cc0bc43161a211" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/3461e3fccc7cfdfc2720be910d3bd73c69be590d", - "reference": "3461e3fccc7cfdfc2720be910d3bd73c69be590d", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/14f72dd46eaf2f2293cbe79c93cc0bc43161a211", + "reference": "14f72dd46eaf2f2293cbe79c93cc0bc43161a211", "shasum": "" }, "require": { - "php": ">=7.3" + "php": ">=7.1" }, "require-dev": { - "phpunit/phpunit": "^9.3", - "symfony/process": "^4.2 || ^5" + "phpunit/phpunit": "^7.5 || ^8.0", + "symfony/process": "^2 || ^3.3 || ^4" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "4.0-dev" + "dev-master": "3.0-dev" } }, "autoload": { @@ -2859,7 +2979,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/diff/issues", - "source": "https://github.com/sebastianbergmann/diff/tree/4.0.4" + "source": "https://github.com/sebastianbergmann/diff/tree/3.0.3" }, "funding": [ { @@ -2867,27 +2987,27 @@ "type": "github" } ], - "time": "2020-10-26T13:10:38+00:00" + "time": "2020-11-30T07:59:04+00:00" }, { "name": "sebastian/environment", - "version": "5.1.3", + "version": "4.2.4", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/environment.git", - "reference": "388b6ced16caa751030f6a69e588299fa09200ac" + "reference": "d47bbbad83711771f167c72d4e3f25f7fcc1f8b0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/388b6ced16caa751030f6a69e588299fa09200ac", - "reference": "388b6ced16caa751030f6a69e588299fa09200ac", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/d47bbbad83711771f167c72d4e3f25f7fcc1f8b0", + "reference": "d47bbbad83711771f167c72d4e3f25f7fcc1f8b0", "shasum": "" }, "require": { - "php": ">=7.3" + "php": ">=7.1" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^7.5" }, "suggest": { "ext-posix": "*" @@ -2895,7 +3015,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "5.1-dev" + "dev-master": "4.2-dev" } }, "autoload": { @@ -2922,7 +3042,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/environment/issues", - "source": "https://github.com/sebastianbergmann/environment/tree/5.1.3" + "source": "https://github.com/sebastianbergmann/environment/tree/4.2.4" }, "funding": [ { @@ -2930,34 +3050,34 @@ "type": "github" } ], - "time": "2020-09-28T05:52:38+00:00" + "time": "2020-11-30T07:53:42+00:00" }, { "name": "sebastian/exporter", - "version": "4.0.3", + "version": "3.1.4", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "d89cc98761b8cb5a1a235a6b703ae50d34080e65" + "reference": "0c32ea2e40dbf59de29f3b49bf375176ce7dd8db" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/d89cc98761b8cb5a1a235a6b703ae50d34080e65", - "reference": "d89cc98761b8cb5a1a235a6b703ae50d34080e65", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/0c32ea2e40dbf59de29f3b49bf375176ce7dd8db", + "reference": "0c32ea2e40dbf59de29f3b49bf375176ce7dd8db", "shasum": "" }, "require": { - "php": ">=7.3", - "sebastian/recursion-context": "^4.0" + "php": ">=7.0", + "sebastian/recursion-context": "^3.0" }, "require-dev": { "ext-mbstring": "*", - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^8.5" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "4.0-dev" + "dev-master": "3.1.x-dev" } }, "autoload": { @@ -2999,7 +3119,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/exporter/issues", - "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.3" + "source": "https://github.com/sebastianbergmann/exporter/tree/3.1.4" }, "funding": [ { @@ -3007,30 +3127,30 @@ "type": "github" } ], - "time": "2020-09-28T05:24:23+00:00" + "time": "2021-11-11T13:51:24+00:00" }, { "name": "sebastian/global-state", - "version": "5.0.3", + "version": "3.0.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/global-state.git", - "reference": "23bd5951f7ff26f12d4e3242864df3e08dec4e49" + "reference": "de036ec91d55d2a9e0db2ba975b512cdb1c23921" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/23bd5951f7ff26f12d4e3242864df3e08dec4e49", - "reference": "23bd5951f7ff26f12d4e3242864df3e08dec4e49", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/de036ec91d55d2a9e0db2ba975b512cdb1c23921", + "reference": "de036ec91d55d2a9e0db2ba975b512cdb1c23921", "shasum": "" }, "require": { - "php": ">=7.3", - "sebastian/object-reflector": "^2.0", - "sebastian/recursion-context": "^4.0" + "php": ">=7.2", + "sebastian/object-reflector": "^1.1.1", + "sebastian/recursion-context": "^3.0" }, "require-dev": { "ext-dom": "*", - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^8.0" }, "suggest": { "ext-uopz": "*" @@ -3038,7 +3158,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "5.0-dev" + "dev-master": "3.0-dev" } }, "autoload": { @@ -3063,7 +3183,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/global-state/issues", - "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.3" + "source": "https://github.com/sebastianbergmann/global-state/tree/3.0.2" }, "funding": [ { @@ -3071,91 +3191,34 @@ "type": "github" } ], - "time": "2021-06-11T13:31:12+00:00" - }, - { - "name": "sebastian/lines-of-code", - "version": "1.0.3", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/lines-of-code.git", - "reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/c1c2e997aa3146983ed888ad08b15470a2e22ecc", - "reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc", - "shasum": "" - }, - "require": { - "nikic/php-parser": "^4.6", - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Library for counting the lines of code in PHP source code", - "homepage": "https://github.com/sebastianbergmann/lines-of-code", - "support": { - "issues": "https://github.com/sebastianbergmann/lines-of-code/issues", - "source": "https://github.com/sebastianbergmann/lines-of-code/tree/1.0.3" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-11-28T06:42:11+00:00" + "time": "2022-02-10T06:55:38+00:00" }, { "name": "sebastian/object-enumerator", - "version": "4.0.4", + "version": "3.0.4", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/object-enumerator.git", - "reference": "5c9eeac41b290a3712d88851518825ad78f45c71" + "reference": "e67f6d32ebd0c749cf9d1dbd9f226c727043cdf2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/5c9eeac41b290a3712d88851518825ad78f45c71", - "reference": "5c9eeac41b290a3712d88851518825ad78f45c71", + "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/e67f6d32ebd0c749cf9d1dbd9f226c727043cdf2", + "reference": "e67f6d32ebd0c749cf9d1dbd9f226c727043cdf2", "shasum": "" }, "require": { - "php": ">=7.3", - "sebastian/object-reflector": "^2.0", - "sebastian/recursion-context": "^4.0" + "php": ">=7.0", + "sebastian/object-reflector": "^1.1.1", + "sebastian/recursion-context": "^3.0" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^6.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "4.0-dev" + "dev-master": "3.0.x-dev" } }, "autoload": { @@ -3177,7 +3240,7 @@ "homepage": "https://github.com/sebastianbergmann/object-enumerator/", "support": { "issues": "https://github.com/sebastianbergmann/object-enumerator/issues", - "source": "https://github.com/sebastianbergmann/object-enumerator/tree/4.0.4" + "source": "https://github.com/sebastianbergmann/object-enumerator/tree/3.0.4" }, "funding": [ { @@ -3185,32 +3248,32 @@ "type": "github" } ], - "time": "2020-10-26T13:12:34+00:00" + "time": "2020-11-30T07:40:27+00:00" }, { "name": "sebastian/object-reflector", - "version": "2.0.4", + "version": "1.1.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/object-reflector.git", - "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7" + "reference": "9b8772b9cbd456ab45d4a598d2dd1a1bced6363d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/b4f479ebdbf63ac605d183ece17d8d7fe49c15c7", - "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7", + "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/9b8772b9cbd456ab45d4a598d2dd1a1bced6363d", + "reference": "9b8772b9cbd456ab45d4a598d2dd1a1bced6363d", "shasum": "" }, "require": { - "php": ">=7.3" + "php": ">=7.0" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^6.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0-dev" + "dev-master": "1.1-dev" } }, "autoload": { @@ -3232,7 +3295,7 @@ "homepage": "https://github.com/sebastianbergmann/object-reflector/", "support": { "issues": "https://github.com/sebastianbergmann/object-reflector/issues", - "source": "https://github.com/sebastianbergmann/object-reflector/tree/2.0.4" + "source": "https://github.com/sebastianbergmann/object-reflector/tree/1.1.2" }, "funding": [ { @@ -3240,32 +3303,32 @@ "type": "github" } ], - "time": "2020-10-26T13:14:26+00:00" + "time": "2020-11-30T07:37:18+00:00" }, { "name": "sebastian/recursion-context", - "version": "4.0.4", + "version": "3.0.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/recursion-context.git", - "reference": "cd9d8cf3c5804de4341c283ed787f099f5506172" + "reference": "367dcba38d6e1977be014dc4b22f47a484dac7fb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/cd9d8cf3c5804de4341c283ed787f099f5506172", - "reference": "cd9d8cf3c5804de4341c283ed787f099f5506172", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/367dcba38d6e1977be014dc4b22f47a484dac7fb", + "reference": "367dcba38d6e1977be014dc4b22f47a484dac7fb", "shasum": "" }, "require": { - "php": ">=7.3" + "php": ">=7.0" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^6.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "4.0-dev" + "dev-master": "3.0.x-dev" } }, "autoload": { @@ -3295,7 +3358,7 @@ "homepage": "http://www.github.com/sebastianbergmann/recursion-context", "support": { "issues": "https://github.com/sebastianbergmann/recursion-context/issues", - "source": "https://github.com/sebastianbergmann/recursion-context/tree/4.0.4" + "source": "https://github.com/sebastianbergmann/recursion-context/tree/3.0.1" }, "funding": [ { @@ -3303,32 +3366,29 @@ "type": "github" } ], - "time": "2020-10-26T13:17:30+00:00" + "time": "2020-11-30T07:34:24+00:00" }, { "name": "sebastian/resource-operations", - "version": "3.0.3", + "version": "2.0.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/resource-operations.git", - "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8" + "reference": "31d35ca87926450c44eae7e2611d45a7a65ea8b3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8", - "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8", + "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/31d35ca87926450c44eae7e2611d45a7a65ea8b3", + "reference": "31d35ca87926450c44eae7e2611d45a7a65ea8b3", "shasum": "" }, "require": { - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.0" + "php": ">=7.1" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-master": "2.0-dev" } }, "autoload": { @@ -3350,7 +3410,7 @@ "homepage": "https://www.github.com/sebastianbergmann/resource-operations", "support": { "issues": "https://github.com/sebastianbergmann/resource-operations/issues", - "source": "https://github.com/sebastianbergmann/resource-operations/tree/3.0.3" + "source": "https://github.com/sebastianbergmann/resource-operations/tree/2.0.2" }, "funding": [ { @@ -3358,32 +3418,32 @@ "type": "github" } ], - "time": "2020-09-28T06:45:17+00:00" + "time": "2020-11-30T07:30:19+00:00" }, { "name": "sebastian/type", - "version": "2.3.4", + "version": "1.1.4", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/type.git", - "reference": "b8cd8a1c753c90bc1a0f5372170e3e489136f914" + "reference": "0150cfbc4495ed2df3872fb31b26781e4e077eb4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/b8cd8a1c753c90bc1a0f5372170e3e489136f914", - "reference": "b8cd8a1c753c90bc1a0f5372170e3e489136f914", + "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/0150cfbc4495ed2df3872fb31b26781e4e077eb4", + "reference": "0150cfbc4495ed2df3872fb31b26781e4e077eb4", "shasum": "" }, "require": { - "php": ">=7.3" + "php": ">=7.2" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^8.2" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.3-dev" + "dev-master": "1.1-dev" } }, "autoload": { @@ -3406,7 +3466,7 @@ "homepage": "https://github.com/sebastianbergmann/type", "support": { "issues": "https://github.com/sebastianbergmann/type/issues", - "source": "https://github.com/sebastianbergmann/type/tree/2.3.4" + "source": "https://github.com/sebastianbergmann/type/tree/1.1.4" }, "funding": [ { @@ -3414,29 +3474,29 @@ "type": "github" } ], - "time": "2021-06-15T12:49:02+00:00" + "time": "2020-11-30T07:25:11+00:00" }, { "name": "sebastian/version", - "version": "3.0.2", + "version": "2.0.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/version.git", - "reference": "c6c1022351a901512170118436c764e473f6de8c" + "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c6c1022351a901512170118436c764e473f6de8c", - "reference": "c6c1022351a901512170118436c764e473f6de8c", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/99732be0ddb3361e16ad77b68ba41efc8e979019", + "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019", "shasum": "" }, "require": { - "php": ">=7.3" + "php": ">=5.6" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-master": "2.0.x-dev" } }, "autoload": { @@ -3459,38 +3519,32 @@ "homepage": "https://github.com/sebastianbergmann/version", "support": { "issues": "https://github.com/sebastianbergmann/version/issues", - "source": "https://github.com/sebastianbergmann/version/tree/3.0.2" + "source": "https://github.com/sebastianbergmann/version/tree/master" }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-09-28T06:39:44+00:00" + "time": "2016-10-03T07:35:21+00:00" }, { "name": "symfony/console", - "version": "v5.3.10", + "version": "v5.4.5", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "d4e409d9fbcfbf71af0e5a940abb7b0b4bad0bd3" + "reference": "d8111acc99876953f52fe16d4c50eb60940d49ad" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/d4e409d9fbcfbf71af0e5a940abb7b0b4bad0bd3", - "reference": "d4e409d9fbcfbf71af0e5a940abb7b0b4bad0bd3", + "url": "https://api.github.com/repos/symfony/console/zipball/d8111acc99876953f52fe16d4c50eb60940d49ad", + "reference": "d8111acc99876953f52fe16d4c50eb60940d49ad", "shasum": "" }, "require": { "php": ">=7.2.5", - "symfony/deprecation-contracts": "^2.1", + "symfony/deprecation-contracts": "^2.1|^3", "symfony/polyfill-mbstring": "~1.0", - "symfony/polyfill-php73": "^1.8", + "symfony/polyfill-php73": "^1.9", "symfony/polyfill-php80": "^1.16", - "symfony/service-contracts": "^1.1|^2", - "symfony/string": "^5.1" + "symfony/service-contracts": "^1.1|^2|^3", + "symfony/string": "^5.1|^6.0" }, "conflict": { "psr/log": ">=3", @@ -3505,12 +3559,12 @@ }, "require-dev": { "psr/log": "^1|^2", - "symfony/config": "^4.4|^5.0", - "symfony/dependency-injection": "^4.4|^5.0", - "symfony/event-dispatcher": "^4.4|^5.0", - "symfony/lock": "^4.4|^5.0", - "symfony/process": "^4.4|^5.0", - "symfony/var-dumper": "^4.4|^5.0" + "symfony/config": "^4.4|^5.0|^6.0", + "symfony/dependency-injection": "^4.4|^5.0|^6.0", + "symfony/event-dispatcher": "^4.4|^5.0|^6.0", + "symfony/lock": "^4.4|^5.0|^6.0", + "symfony/process": "^4.4|^5.0|^6.0", + "symfony/var-dumper": "^4.4|^5.0|^6.0" }, "suggest": { "psr/log": "For using the console logger", @@ -3550,7 +3604,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v5.3.10" + "source": "https://github.com/symfony/console/tree/v5.4.5" }, "funding": [ { @@ -3566,20 +3620,20 @@ "type": "tidelift" } ], - "time": "2021-10-26T09:30:15+00:00" + "time": "2022-02-24T12:45:35+00:00" }, { "name": "symfony/deprecation-contracts", - "version": "v2.4.0", + "version": "v2.5.0", "source": { "type": "git", "url": "https://github.com/symfony/deprecation-contracts.git", - "reference": "5f38c8804a9e97d23e0c8d63341088cd8a22d627" + "reference": "6f981ee24cf69ee7ce9736146d1c57c2780598a8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/5f38c8804a9e97d23e0c8d63341088cd8a22d627", - "reference": "5f38c8804a9e97d23e0c8d63341088cd8a22d627", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/6f981ee24cf69ee7ce9736146d1c57c2780598a8", + "reference": "6f981ee24cf69ee7ce9736146d1c57c2780598a8", "shasum": "" }, "require": { @@ -3588,7 +3642,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "2.4-dev" + "dev-main": "2.5-dev" }, "thanks": { "name": "symfony/contracts", @@ -3617,7 +3671,7 @@ "description": "A generic function and convention to trigger deprecation notices", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/deprecation-contracts/tree/v2.4.0" + "source": "https://github.com/symfony/deprecation-contracts/tree/v2.5.0" }, "funding": [ { @@ -3633,20 +3687,20 @@ "type": "tidelift" } ], - "time": "2021-03-23T23:28:01+00:00" + "time": "2021-07-12T14:48:14+00:00" }, { "name": "symfony/event-dispatcher", - "version": "v4.4.30", + "version": "v4.4.37", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "2fe81680070043c4c80e7cedceb797e34f377bac" + "reference": "3ccfcfb96ecce1217d7b0875a0736976bc6e63dc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/2fe81680070043c4c80e7cedceb797e34f377bac", - "reference": "2fe81680070043c4c80e7cedceb797e34f377bac", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/3ccfcfb96ecce1217d7b0875a0736976bc6e63dc", + "reference": "3ccfcfb96ecce1217d7b0875a0736976bc6e63dc", "shasum": "" }, "require": { @@ -3701,7 +3755,7 @@ "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/event-dispatcher/tree/v4.4.30" + "source": "https://github.com/symfony/event-dispatcher/tree/v4.4.37" }, "funding": [ { @@ -3717,20 +3771,20 @@ "type": "tidelift" } ], - "time": "2021-08-04T20:31:23+00:00" + "time": "2022-01-02T09:41:36+00:00" }, { "name": "symfony/event-dispatcher-contracts", - "version": "v1.1.9", + "version": "v1.1.11", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher-contracts.git", - "reference": "84e23fdcd2517bf37aecbd16967e83f0caee25a7" + "reference": "01e9a4efac0ee33a05dfdf93b346f62e7d0e998c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/84e23fdcd2517bf37aecbd16967e83f0caee25a7", - "reference": "84e23fdcd2517bf37aecbd16967e83f0caee25a7", + "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/01e9a4efac0ee33a05dfdf93b346f62e7d0e998c", + "reference": "01e9a4efac0ee33a05dfdf93b346f62e7d0e998c", "shasum": "" }, "require": { @@ -3743,7 +3797,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.1-dev" + "dev-main": "1.1-dev" }, "thanks": { "name": "symfony/contracts", @@ -3780,7 +3834,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v1.1.9" + "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v1.1.11" }, "funding": [ { @@ -3796,25 +3850,27 @@ "type": "tidelift" } ], - "time": "2020-07-06T13:19:58+00:00" + "time": "2021-03-23T15:25:38+00:00" }, { "name": "symfony/filesystem", - "version": "v5.2.3", + "version": "v5.4.6", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "262d033b57c73e8b59cd6e68a45c528318b15038" + "reference": "d53a45039974952af7f7ebc461ccdd4295e29440" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/262d033b57c73e8b59cd6e68a45c528318b15038", - "reference": "262d033b57c73e8b59cd6e68a45c528318b15038", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/d53a45039974952af7f7ebc461ccdd4295e29440", + "reference": "d53a45039974952af7f7ebc461ccdd4295e29440", "shasum": "" }, "require": { "php": ">=7.2.5", - "symfony/polyfill-ctype": "~1.8" + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-mbstring": "~1.8", + "symfony/polyfill-php80": "^1.16" }, "type": "library", "autoload": { @@ -3842,7 +3898,7 @@ "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/filesystem/tree/v5.2.3" + "source": "https://github.com/symfony/filesystem/tree/v5.4.6" }, "funding": [ { @@ -3858,24 +3914,26 @@ "type": "tidelift" } ], - "time": "2021-01-27T10:01:46+00:00" + "time": "2022-03-02T12:42:23+00:00" }, { "name": "symfony/finder", - "version": "v5.2.3", + "version": "v5.4.3", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "4adc8d172d602008c204c2e16956f99257248e03" + "reference": "231313534dded84c7ecaa79d14bc5da4ccb69b7d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/4adc8d172d602008c204c2e16956f99257248e03", - "reference": "4adc8d172d602008c204c2e16956f99257248e03", + "url": "https://api.github.com/repos/symfony/finder/zipball/231313534dded84c7ecaa79d14bc5da4ccb69b7d", + "reference": "231313534dded84c7ecaa79d14bc5da4ccb69b7d", "shasum": "" }, "require": { - "php": ">=7.2.5" + "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1|^3", + "symfony/polyfill-php80": "^1.16" }, "type": "library", "autoload": { @@ -3903,7 +3961,7 @@ "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/finder/tree/v5.2.3" + "source": "https://github.com/symfony/finder/tree/v5.4.3" }, "funding": [ { @@ -3919,27 +3977,27 @@ "type": "tidelift" } ], - "time": "2021-01-28T22:06:19+00:00" + "time": "2022-01-26T16:34:36+00:00" }, { "name": "symfony/options-resolver", - "version": "v5.2.3", + "version": "v5.4.3", "source": { "type": "git", "url": "https://github.com/symfony/options-resolver.git", - "reference": "5d0f633f9bbfcf7ec642a2b5037268e61b0a62ce" + "reference": "cc1147cb11af1b43f503ac18f31aa3bec213aba8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/options-resolver/zipball/5d0f633f9bbfcf7ec642a2b5037268e61b0a62ce", - "reference": "5d0f633f9bbfcf7ec642a2b5037268e61b0a62ce", + "url": "https://api.github.com/repos/symfony/options-resolver/zipball/cc1147cb11af1b43f503ac18f31aa3bec213aba8", + "reference": "cc1147cb11af1b43f503ac18f31aa3bec213aba8", "shasum": "" }, "require": { "php": ">=7.2.5", - "symfony/deprecation-contracts": "^2.1", + "symfony/deprecation-contracts": "^2.1|^3", "symfony/polyfill-php73": "~1.0", - "symfony/polyfill-php80": "^1.15" + "symfony/polyfill-php80": "^1.16" }, "type": "library", "autoload": { @@ -3972,7 +4030,7 @@ "options" ], "support": { - "source": "https://github.com/symfony/options-resolver/tree/v5.2.3" + "source": "https://github.com/symfony/options-resolver/tree/v5.4.3" }, "funding": [ { @@ -3988,25 +4046,28 @@ "type": "tidelift" } ], - "time": "2021-01-27T12:56:27+00:00" + "time": "2022-01-02T09:53:40+00:00" }, { "name": "symfony/polyfill-ctype", - "version": "v1.23.0", + "version": "v1.25.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "46cd95797e9df938fdd2b03693b5fca5e64b01ce" + "reference": "30885182c981ab175d4d034db0f6f469898070ab" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/46cd95797e9df938fdd2b03693b5fca5e64b01ce", - "reference": "46cd95797e9df938fdd2b03693b5fca5e64b01ce", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/30885182c981ab175d4d034db0f6f469898070ab", + "reference": "30885182c981ab175d4d034db0f6f469898070ab", "shasum": "" }, "require": { "php": ">=7.1" }, + "provide": { + "ext-ctype": "*" + }, "suggest": { "ext-ctype": "For best performance" }, @@ -4021,12 +4082,12 @@ } }, "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Ctype\\": "" - }, "files": [ "bootstrap.php" - ] + ], + "psr-4": { + "Symfony\\Polyfill\\Ctype\\": "" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -4051,7 +4112,7 @@ "portable" ], "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.23.0" + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.25.0" }, "funding": [ { @@ -4067,20 +4128,20 @@ "type": "tidelift" } ], - "time": "2021-02-19T12:13:01+00:00" + "time": "2021-10-20T20:35:02+00:00" }, { "name": "symfony/polyfill-intl-grapheme", - "version": "v1.23.1", + "version": "v1.25.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-grapheme.git", - "reference": "16880ba9c5ebe3642d1995ab866db29270b36535" + "reference": "81b86b50cf841a64252b439e738e97f4a34e2783" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/16880ba9c5ebe3642d1995ab866db29270b36535", - "reference": "16880ba9c5ebe3642d1995ab866db29270b36535", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/81b86b50cf841a64252b439e738e97f4a34e2783", + "reference": "81b86b50cf841a64252b439e738e97f4a34e2783", "shasum": "" }, "require": { @@ -4100,12 +4161,12 @@ } }, "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Intl\\Grapheme\\": "" - }, "files": [ "bootstrap.php" - ] + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Grapheme\\": "" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -4132,7 +4193,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.23.1" + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.25.0" }, "funding": [ { @@ -4148,11 +4209,11 @@ "type": "tidelift" } ], - "time": "2021-05-27T12:26:48+00:00" + "time": "2021-11-23T21:10:46+00:00" }, { "name": "symfony/polyfill-intl-normalizer", - "version": "v1.23.0", + "version": "v1.25.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-normalizer.git", @@ -4181,12 +4242,12 @@ } }, "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Intl\\Normalizer\\": "" - }, "files": [ "bootstrap.php" ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Normalizer\\": "" + }, "classmap": [ "Resources/stubs" ] @@ -4216,7 +4277,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.23.0" + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.25.0" }, "funding": [ { @@ -4236,21 +4297,24 @@ }, { "name": "symfony/polyfill-mbstring", - "version": "v1.23.1", + "version": "v1.25.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "9174a3d80210dca8daa7f31fec659150bbeabfc6" + "reference": "0abb51d2f102e00a4eefcf46ba7fec406d245825" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/9174a3d80210dca8daa7f31fec659150bbeabfc6", - "reference": "9174a3d80210dca8daa7f31fec659150bbeabfc6", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/0abb51d2f102e00a4eefcf46ba7fec406d245825", + "reference": "0abb51d2f102e00a4eefcf46ba7fec406d245825", "shasum": "" }, "require": { "php": ">=7.1" }, + "provide": { + "ext-mbstring": "*" + }, "suggest": { "ext-mbstring": "For best performance" }, @@ -4265,12 +4329,12 @@ } }, "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Mbstring\\": "" - }, "files": [ "bootstrap.php" - ] + ], + "psr-4": { + "Symfony\\Polyfill\\Mbstring\\": "" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -4296,7 +4360,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.23.1" + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.25.0" }, "funding": [ { @@ -4312,7 +4376,7 @@ "type": "tidelift" } ], - "time": "2021-05-27T12:26:48+00:00" + "time": "2021-11-30T18:21:41+00:00" }, { "name": "symfony/polyfill-php70", @@ -4384,16 +4448,16 @@ }, { "name": "symfony/polyfill-php72", - "version": "v1.22.1", + "version": "v1.25.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php72.git", - "reference": "cc6e6f9b39fe8075b3dabfbaf5b5f645ae1340c9" + "reference": "9a142215a36a3888e30d0a9eeea9766764e96976" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/cc6e6f9b39fe8075b3dabfbaf5b5f645ae1340c9", - "reference": "cc6e6f9b39fe8075b3dabfbaf5b5f645ae1340c9", + "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/9a142215a36a3888e30d0a9eeea9766764e96976", + "reference": "9a142215a36a3888e30d0a9eeea9766764e96976", "shasum": "" }, "require": { @@ -4402,7 +4466,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.22-dev" + "dev-main": "1.23-dev" }, "thanks": { "name": "symfony/polyfill", @@ -4410,12 +4474,12 @@ } }, "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Php72\\": "" - }, "files": [ "bootstrap.php" - ] + ], + "psr-4": { + "Symfony\\Polyfill\\Php72\\": "" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -4440,7 +4504,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php72/tree/v1.22.1" + "source": "https://github.com/symfony/polyfill-php72/tree/v1.25.0" }, "funding": [ { @@ -4456,20 +4520,20 @@ "type": "tidelift" } ], - "time": "2021-01-07T16:49:33+00:00" + "time": "2021-05-27T09:17:38+00:00" }, { "name": "symfony/polyfill-php73", - "version": "v1.23.0", + "version": "v1.25.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php73.git", - "reference": "fba8933c384d6476ab14fb7b8526e5287ca7e010" + "reference": "cc5db0e22b3cb4111010e48785a97f670b350ca5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/fba8933c384d6476ab14fb7b8526e5287ca7e010", - "reference": "fba8933c384d6476ab14fb7b8526e5287ca7e010", + "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/cc5db0e22b3cb4111010e48785a97f670b350ca5", + "reference": "cc5db0e22b3cb4111010e48785a97f670b350ca5", "shasum": "" }, "require": { @@ -4486,12 +4550,12 @@ } }, "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Php73\\": "" - }, "files": [ "bootstrap.php" ], + "psr-4": { + "Symfony\\Polyfill\\Php73\\": "" + }, "classmap": [ "Resources/stubs" ] @@ -4519,7 +4583,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php73/tree/v1.23.0" + "source": "https://github.com/symfony/polyfill-php73/tree/v1.25.0" }, "funding": [ { @@ -4535,20 +4599,20 @@ "type": "tidelift" } ], - "time": "2021-02-19T12:13:01+00:00" + "time": "2021-06-05T21:20:04+00:00" }, { "name": "symfony/polyfill-php80", - "version": "v1.23.1", + "version": "v1.25.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php80.git", - "reference": "1100343ed1a92e3a38f9ae122fc0eb21602547be" + "reference": "4407588e0d3f1f52efb65fbe92babe41f37fe50c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/1100343ed1a92e3a38f9ae122fc0eb21602547be", - "reference": "1100343ed1a92e3a38f9ae122fc0eb21602547be", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/4407588e0d3f1f52efb65fbe92babe41f37fe50c", + "reference": "4407588e0d3f1f52efb65fbe92babe41f37fe50c", "shasum": "" }, "require": { @@ -4565,12 +4629,12 @@ } }, "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Php80\\": "" - }, "files": [ "bootstrap.php" ], + "psr-4": { + "Symfony\\Polyfill\\Php80\\": "" + }, "classmap": [ "Resources/stubs" ] @@ -4602,7 +4666,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php80/tree/v1.23.1" + "source": "https://github.com/symfony/polyfill-php80/tree/v1.25.0" }, "funding": [ { @@ -4618,25 +4682,25 @@ "type": "tidelift" } ], - "time": "2021-07-28T13:41:28+00:00" + "time": "2022-03-04T08:16:47+00:00" }, { "name": "symfony/process", - "version": "v5.2.3", + "version": "v5.4.5", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "313a38f09c77fbcdc1d223e57d368cea76a2fd2f" + "reference": "95440409896f90a5f85db07a32b517ecec17fa4c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/313a38f09c77fbcdc1d223e57d368cea76a2fd2f", - "reference": "313a38f09c77fbcdc1d223e57d368cea76a2fd2f", + "url": "https://api.github.com/repos/symfony/process/zipball/95440409896f90a5f85db07a32b517ecec17fa4c", + "reference": "95440409896f90a5f85db07a32b517ecec17fa4c", "shasum": "" }, "require": { "php": ">=7.2.5", - "symfony/polyfill-php80": "^1.15" + "symfony/polyfill-php80": "^1.16" }, "type": "library", "autoload": { @@ -4664,7 +4728,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v5.2.3" + "source": "https://github.com/symfony/process/tree/v5.4.5" }, "funding": [ { @@ -4680,25 +4744,29 @@ "type": "tidelift" } ], - "time": "2021-01-27T10:15:41+00:00" + "time": "2022-01-30T18:16:22+00:00" }, { "name": "symfony/service-contracts", - "version": "v2.4.0", + "version": "v2.5.0", "source": { "type": "git", "url": "https://github.com/symfony/service-contracts.git", - "reference": "f040a30e04b57fbcc9c6cbcf4dbaa96bd318b9bb" + "reference": "1ab11b933cd6bc5464b08e81e2c5b07dec58b0fc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/f040a30e04b57fbcc9c6cbcf4dbaa96bd318b9bb", - "reference": "f040a30e04b57fbcc9c6cbcf4dbaa96bd318b9bb", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/1ab11b933cd6bc5464b08e81e2c5b07dec58b0fc", + "reference": "1ab11b933cd6bc5464b08e81e2c5b07dec58b0fc", "shasum": "" }, "require": { "php": ">=7.2.5", - "psr/container": "^1.1" + "psr/container": "^1.1", + "symfony/deprecation-contracts": "^2.1" + }, + "conflict": { + "ext-psr": "<1.1|>=2" }, "suggest": { "symfony/service-implementation": "" @@ -4706,7 +4774,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "2.4-dev" + "dev-main": "2.5-dev" }, "thanks": { "name": "symfony/contracts", @@ -4743,7 +4811,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/service-contracts/tree/v2.4.0" + "source": "https://github.com/symfony/service-contracts/tree/v2.5.0" }, "funding": [ { @@ -4759,25 +4827,25 @@ "type": "tidelift" } ], - "time": "2021-04-01T10:43:52+00:00" + "time": "2021-11-04T16:48:04+00:00" }, { "name": "symfony/stopwatch", - "version": "v5.2.3", + "version": "v5.4.5", "source": { "type": "git", "url": "https://github.com/symfony/stopwatch.git", - "reference": "b12274acfab9d9850c52583d136a24398cdf1a0c" + "reference": "4d04b5c24f3c9a1a168a131f6cbe297155bc0d30" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/stopwatch/zipball/b12274acfab9d9850c52583d136a24398cdf1a0c", - "reference": "b12274acfab9d9850c52583d136a24398cdf1a0c", + "url": "https://api.github.com/repos/symfony/stopwatch/zipball/4d04b5c24f3c9a1a168a131f6cbe297155bc0d30", + "reference": "4d04b5c24f3c9a1a168a131f6cbe297155bc0d30", "shasum": "" }, "require": { "php": ">=7.2.5", - "symfony/service-contracts": "^1.0|^2" + "symfony/service-contracts": "^1|^2|^3" }, "type": "library", "autoload": { @@ -4805,7 +4873,7 @@ "description": "Provides a way to profile code", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/stopwatch/tree/v5.2.3" + "source": "https://github.com/symfony/stopwatch/tree/v5.4.5" }, "funding": [ { @@ -4821,20 +4889,20 @@ "type": "tidelift" } ], - "time": "2021-01-27T10:15:41+00:00" + "time": "2022-02-18T16:06:09+00:00" }, { "name": "symfony/string", - "version": "v5.3.10", + "version": "v5.4.3", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "d70c35bb20bbca71fc4ab7921e3c6bda1a82a60c" + "reference": "92043b7d8383e48104e411bc9434b260dbeb5a10" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/d70c35bb20bbca71fc4ab7921e3c6bda1a82a60c", - "reference": "d70c35bb20bbca71fc4ab7921e3c6bda1a82a60c", + "url": "https://api.github.com/repos/symfony/string/zipball/92043b7d8383e48104e411bc9434b260dbeb5a10", + "reference": "92043b7d8383e48104e411bc9434b260dbeb5a10", "shasum": "" }, "require": { @@ -4845,20 +4913,23 @@ "symfony/polyfill-mbstring": "~1.0", "symfony/polyfill-php80": "~1.15" }, + "conflict": { + "symfony/translation-contracts": ">=3.0" + }, "require-dev": { - "symfony/error-handler": "^4.4|^5.0", - "symfony/http-client": "^4.4|^5.0", + "symfony/error-handler": "^4.4|^5.0|^6.0", + "symfony/http-client": "^4.4|^5.0|^6.0", "symfony/translation-contracts": "^1.1|^2", - "symfony/var-exporter": "^4.4|^5.0" + "symfony/var-exporter": "^4.4|^5.0|^6.0" }, "type": "library", "autoload": { - "psr-4": { - "Symfony\\Component\\String\\": "" - }, "files": [ "Resources/functions.php" ], + "psr-4": { + "Symfony\\Component\\String\\": "" + }, "exclude-from-classmap": [ "/Tests/" ] @@ -4888,7 +4959,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v5.3.10" + "source": "https://github.com/symfony/string/tree/v5.4.3" }, "funding": [ { @@ -4904,7 +4975,7 @@ "type": "tidelift" } ], - "time": "2021-10-27T18:21:46+00:00" + "time": "2022-01-02T09:53:40+00:00" }, { "name": "theseer/tokenizer", @@ -4958,16 +5029,16 @@ }, { "name": "vimeo/psalm", - "version": "4.11.2", + "version": "4.22.0", "source": { "type": "git", "url": "https://github.com/vimeo/psalm.git", - "reference": "6fba5eb554f9507b72932f9c75533d8af593688d" + "reference": "fc2c6ab4d5fa5d644d8617089f012f3bb84b8703" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/vimeo/psalm/zipball/6fba5eb554f9507b72932f9c75533d8af593688d", - "reference": "6fba5eb554f9507b72932f9c75533d8af593688d", + "url": "https://api.github.com/repos/vimeo/psalm/zipball/fc2c6ab4d5fa5d644d8617089f012f3bb84b8703", + "reference": "fc2c6ab4d5fa5d644d8617089f012f3bb84b8703", "shasum": "" }, "require": { @@ -4975,7 +5046,7 @@ "amphp/byte-stream": "^1.5", "composer/package-versions-deprecated": "^1.8.0", "composer/semver": "^1.4 || ^2.0 || ^3.0", - "composer/xdebug-handler": "^1.1 || ^2.0", + "composer/xdebug-handler": "^1.1 || ^2.0 || ^3.0", "dnoegel/php-xdg-base-dir": "^0.1.1", "ext-ctype": "*", "ext-dom": "*", @@ -4991,7 +5062,7 @@ "openlss/lib-array2xml": "^1.0", "php": "^7.1|^8", "sebastian/diff": "^3.0 || ^4.0", - "symfony/console": "^3.4.17 || ^4.1.6 || ^5.0", + "symfony/console": "^3.4.17 || ^4.1.6 || ^5.0 || ^6.0", "webmozart/path-util": "^2.3" }, "provide": { @@ -5009,11 +5080,12 @@ "psalm/plugin-phpunit": "^0.16", "slevomat/coding-standard": "^7.0", "squizlabs/php_codesniffer": "^3.5", - "symfony/process": "^4.3 || ^5.0", + "symfony/process": "^4.3 || ^5.0 || ^6.0", "weirdan/prophecy-shim": "^1.0 || ^2.0" }, "suggest": { - "ext-igbinary": "^2.0.5" + "ext-curl": "In order to send data to shepherd", + "ext-igbinary": "^2.0.5 is required, used to serialize caching data" }, "bin": [ "psalm", @@ -5032,13 +5104,13 @@ } }, "autoload": { - "psr-4": { - "Psalm\\": "src/Psalm/" - }, "files": [ "src/functions.php", "src/spl_object_id.php" - ] + ], + "psr-4": { + "Psalm\\": "src/Psalm/" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -5057,9 +5129,9 @@ ], "support": { "issues": "https://github.com/vimeo/psalm/issues", - "source": "https://github.com/vimeo/psalm/tree/4.11.2" + "source": "https://github.com/vimeo/psalm/tree/4.22.0" }, - "time": "2021-10-26T17:28:17+00:00" + "time": "2022-02-24T20:34:05+00:00" }, { "name": "webmozart/assert", @@ -5167,6 +5239,7 @@ "issues": "https://github.com/webmozart/path-util/issues", "source": "https://github.com/webmozart/path-util/tree/2.3.0" }, + "abandoned": "symfony/filesystem", "time": "2015-12-17T08:42:14+00:00" } ], @@ -5180,5 +5253,8 @@ "prefer-lowest": false, "platform": [], "platform-dev": [], - "plugin-api-version": "2.1.0" + "platform-overrides": { + "php": "7.3" + }, + "plugin-api-version": "2.2.0" } diff --git a/tests/unit/Service/BoardServiceTest.php b/tests/unit/Service/BoardServiceTest.php index 0e8bfeb15..0dcc4ec50 100644 --- a/tests/unit/Service/BoardServiceTest.php +++ b/tests/unit/Service/BoardServiceTest.php @@ -263,6 +263,9 @@ class BoardServiceTest extends TestCase { ->willReturn([ 'admin' => 'admin', ]); + $this->boardMapper->expects($this->once()) + ->method('find') + ->willReturn(new Board()); $this->assertEquals($acl, $this->service->addAcl( 123, 'user', 'admin', true, true, true )); @@ -352,6 +355,9 @@ class BoardServiceTest extends TestCase { $acl->resolveRelation('participant', function ($participant) use (&$user) { return null; }); + $this->boardMapper->expects($this->once()) + ->method('find') + ->willReturn(new Board()); $this->permissionService->expects($this->any()) ->method('findUsers') ->willReturn([ From 4dabc22f277f74376f4ee8bd834ad2deda9a53b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julius=20H=C3=A4rtl?= Date: Tue, 22 Mar 2022 15:58:28 +0100 Subject: [PATCH 32/33] lint: fix eslint MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julius Härtl --- src/components/board/SharingTabSidebar.vue | 2 +- src/components/cards/CardMenu.vue | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/board/SharingTabSidebar.vue b/src/components/board/SharingTabSidebar.vue index 0aa2136d2..f06972759 100644 --- a/src/components/board/SharingTabSidebar.vue +++ b/src/components/board/SharingTabSidebar.vue @@ -214,7 +214,7 @@ export default { this.isLoading = true await this.$store.dispatch('transferOwnership', { boardId: this.board.id, - newOwner + newOwner, }) const successMessage = t('deck', 'Transfer the board for {user} successfully', { user: newOwner }) showSuccess(successMessage) diff --git a/src/components/cards/CardMenu.vue b/src/components/cards/CardMenu.vue index c6974b687..a91513c16 100644 --- a/src/components/cards/CardMenu.vue +++ b/src/components/cards/CardMenu.vue @@ -131,7 +131,7 @@ export default { }, activeBoards() { return this.$store.getters.boards.filter((item) => item.deletedAt === 0 && item.archived === false) - } + }, }, methods: { openCard() { From 39784dc9404b6094ae23ca290c919f5e9bbed2b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julius=20H=C3=A4rtl?= Date: Mon, 11 Apr 2022 16:24:03 +0200 Subject: [PATCH 33/33] Remove unused argument MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julius Härtl --- src/store/main.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/store/main.js b/src/store/main.js index d0e63cf0e..ffc859c63 100644 --- a/src/store/main.js +++ b/src/store/main.js @@ -497,9 +497,8 @@ export default new Vuex.Store({ dispatch('loadBoardById', acl.boardId) }) }, - async transferOwnership({ commit }, { boardId, owner, newOwner }) { + async transferOwnership({ commit }, { boardId, newOwner }) { await axios.put(generateUrl(`apps/deck/boards/${boardId}/transferOwner`), { - owner, newOwner, }) },