diff --git a/.github/workflows/appbuild.yml b/.github/workflows/appbuild.yml deleted file mode 100644 index 4566f2e23..000000000 --- a/.github/workflows/appbuild.yml +++ /dev/null @@ -1,39 +0,0 @@ -name: Package build - -on: - pull_request: - -jobs: - build: - runs-on: ubuntu-latest - - strategy: - matrix: - node-version: [14.x] - - steps: - - uses: actions/checkout@v3 - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 - with: - node-version: ${{ matrix.node-version }} - - name: Set up npm7 - run: npm i -g npm@7 - - name: Setup PHP - uses: shivammathur/setup-php@2.18.0 - with: - php-version: '7.4' - tools: composer - - name: install dependencies - run: | - wget https://github.com/ChristophWurst/krankerl/releases/download/v0.12.2/krankerl_0.12.2_amd64.deb - sudo dpkg -i krankerl_0.12.2_amd64.deb - - name: package - run: | - uname -a - RUST_BACKTRACE=1 krankerl --version - RUST_BACKTRACE=1 krankerl package - - uses: actions/upload-artifact@v3 - with: - name: Deck app tarball - path: build/artifacts/deck.tar.gz diff --git a/.github/workflows/phpunit.yml b/.github/workflows/phpunit.yml index eb8f7d7c4..a7a97f9ea 100644 --- a/.github/workflows/phpunit.yml +++ b/.github/workflows/phpunit.yml @@ -62,11 +62,12 @@ jobs: path: apps/${{ env.APP_NAME }} - name: Set up php ${{ matrix.php-versions }} - uses: shivammathur/setup-php@2.18.0 + uses: shivammathur/setup-php@2.24.0 with: php-version: ${{ matrix.php-versions }} tools: phpunit extensions: zip, gd, mbstring, iconv, fileinfo, intl, sqlite, pdo_sqlite, mysql, pdo_mysql, pgsql, pdo_pgsql + ini-file: development coverage: none - name: Set up PHPUnit diff --git a/lib/Collaboration/Resources/ResourceProvider.php b/lib/Collaboration/Resources/ResourceProvider.php index b4677148d..974976b0f 100644 --- a/lib/Collaboration/Resources/ResourceProvider.php +++ b/lib/Collaboration/Resources/ResourceProvider.php @@ -108,7 +108,7 @@ public function canAccessResource(IResource $resource, ?IUser $user): bool { private function getBoard(IResource $resource) { try { - return $this->boardMapper->find($resource->getId(), false, true); + return $this->boardMapper->find((int)$resource->getId(), false, true); } catch (DoesNotExistException $e) { } catch (MultipleObjectsReturnedException $e) { return null; diff --git a/lib/Db/BoardMapper.php b/lib/Db/BoardMapper.php index 93be76d7e..5b1e6407e 100644 --- a/lib/Db/BoardMapper.php +++ b/lib/Db/BoardMapper.php @@ -79,12 +79,14 @@ public function __construct( * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException * @throws DoesNotExistException */ - public function find($id, $withLabels = false, $withAcl = false): Board { + public function find(int $id, bool $withLabels = false, bool $withAcl = false, bool $allowDeleted = false): Board { if (!isset($this->boardCache[$id])) { $qb = $this->db->getQueryBuilder(); + $deletedWhere = $allowDeleted ? $qb->expr()->gte('deleted_at', $qb->createNamedParameter(0, IQueryBuilder::PARAM_INT)) : $qb->expr()->eq('deleted_at', $qb->createNamedParameter(0, IQueryBuilder::PARAM_INT)); $qb->select('*') ->from('deck_boards') ->where($qb->expr()->eq('id', $qb->createNamedParameter($id, IQueryBuilder::PARAM_INT))) + ->andWhere($deletedWhere) ->orderBy('id'); $this->boardCache[$id] = $this->findEntity($qb); } diff --git a/lib/Service/BoardService.php b/lib/Service/BoardService.php index 9a98decbf..f1cf2b55f 100644 --- a/lib/Service/BoardService.php +++ b/lib/Service/BoardService.php @@ -181,7 +181,7 @@ public function findAll($since = -1, $details = null, $includeArchived = true) { * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException * @throws BadRequestException */ - public function find($boardId) { + public function find($boardId, bool $allowDeleted = false) { $this->boardServiceValidator->check(compact('boardId')); if ($this->boardsCache && isset($this->boardsCache[$boardId])) { return $this->boardsCache[$boardId]; @@ -192,7 +192,7 @@ public function find($boardId) { $this->permissionService->checkPermission($this->boardMapper, $boardId, Acl::PERMISSION_READ); /** @var Board $board */ - $board = $this->boardMapper->find($boardId, true, true); + $board = $this->boardMapper->find((int)$boardId, true, true, $allowDeleted); $this->boardMapper->mapOwner($board); if ($board->getAcl() !== null) { foreach ($board->getAcl() as $acl) { @@ -367,7 +367,7 @@ public function deleteUndo($id) { $this->boardServiceValidator->check(compact('id')); $this->permissionService->checkPermission($this->boardMapper, $id, Acl::PERMISSION_MANAGE); - $board = $this->find($id); + $board = $this->find($id, true); $board->setDeletedAt(0); $board = $this->boardMapper->update($board); $this->activityManager->triggerEvent(ActivityManager::DECK_OBJECT_BOARD, $board, ActivityManager::SUBJECT_BOARD_RESTORE); @@ -388,7 +388,7 @@ public function deleteForce($id) { $this->boardServiceValidator->check(compact('id')); $this->permissionService->checkPermission($this->boardMapper, $id, Acl::PERMISSION_MANAGE); - $board = $this->find($id); + $board = $this->find($id, true); $delete = $this->boardMapper->delete($board); return $delete; diff --git a/lib/Service/CardService.php b/lib/Service/CardService.php index 17fc539f4..717b0b15d 100644 --- a/lib/Service/CardService.php +++ b/lib/Service/CardService.php @@ -274,6 +274,14 @@ public function update($id, $title, $stackId, $type, $owner, $description = '', if ($archived !== null && $card->getArchived() && $archived === true) { throw new StatusException('Operation not allowed. This card is archived.'); } + + if ($card->getDeletedAt() !== 0) { + if ($deletedAt === null) { + // Only allow operations when restoring the card + throw new StatusException('Operation not allowed. This card was deleted.'); + } + } + $changes = new ChangeSet($card); if ($card->getLastEditor() !== $this->currentUser && $card->getLastEditor() !== null) { $this->activityManager->triggerEvent( diff --git a/lib/Service/PermissionService.php b/lib/Service/PermissionService.php index 06a6da62d..c42ca8045 100644 --- a/lib/Service/PermissionService.php +++ b/lib/Service/PermissionService.php @@ -194,11 +194,11 @@ public function userIsBoardOwner($boardId, $userId = null) { * @throws MultipleObjectsReturnedException * @throws DoesNotExistException */ - private function getBoard($boardId): Board { - if (!isset($this->boardCache[$boardId])) { - $this->boardCache[$boardId] = $this->boardMapper->find($boardId, false, true); + private function getBoard(int $boardId): Board { + if (!isset($this->boardCache[(string)$boardId])) { + $this->boardCache[(string)$boardId] = $this->boardMapper->find($boardId, false, true); } - return $this->boardCache[$boardId]; + return $this->boardCache[(string)$boardId]; } /** diff --git a/tests/integration/base-query-count.txt b/tests/integration/base-query-count.txt new file mode 100644 index 000000000..4fe36e923 --- /dev/null +++ b/tests/integration/base-query-count.txt @@ -0,0 +1 @@ +68024 diff --git a/tests/unit/Activity/ActivityManagerTest.php b/tests/unit/Activity/ActivityManagerTest.php index 700d72b19..0e277f35c 100644 --- a/tests/unit/Activity/ActivityManagerTest.php +++ b/tests/unit/Activity/ActivityManagerTest.php @@ -131,6 +131,7 @@ private function expectEventCreation($subject, $subjectParams) { public function testCreateEvent() { $board = new Board(); + $board->setId(123); $board->setTitle(''); $this->boardMapper->expects(self::once()) ->method('find') @@ -148,6 +149,7 @@ public function testCreateEvent() { public function testCreateEventDescription() { $board = new Board(); + $board->setId(123); $board->setTitle(''); $this->boardMapper->expects(self::once()) ->method('find') @@ -162,7 +164,9 @@ public function testCreateEventDescription() { ->method('find') ->willReturn($card); - $stack = Stack::fromRow([]); + $stack = Stack::fromRow([ + 'boardId' => 123, + ]); $this->stackMapper->expects(self::any()) ->method('find') ->willReturn($stack); @@ -192,6 +196,7 @@ public function testCreateEventDescription() { public function testCreateEventLongDescription() { $board = new Board(); + $board->setId(123); $board->setTitle(''); $this->boardMapper->expects(self::once()) ->method('find') @@ -205,7 +210,9 @@ public function testCreateEventLongDescription() { ->method('find') ->willReturn($card); - $stack = new Stack(); + $stack = Stack::fromRow([ + 'boardId' => 123, + ]); $this->stackMapper->expects(self::any()) ->method('find') ->willReturn($stack); @@ -235,6 +242,7 @@ public function testCreateEventLongDescription() { public function testCreateEventLabel() { $board = Board::fromRow([ + 'id' => 123, 'title' => 'My board' ]); $this->boardMapper->expects(self::once()) @@ -249,7 +257,9 @@ public function testCreateEventLabel() { ->method('find') ->willReturn($card); - $stack = Stack::fromParams([]); + $stack = Stack::fromRow([ + 'boardId' => 123, + ]); $this->stackMapper->expects(self::any()) ->method('find') ->willReturn($stack);