refactor: Fix psalm issues

- Add typing for most of the services, controllers and mappers
- Add api doc for mappers
- Use vendor-bin for psalm
- Use attributes for controllers
- Fix upload of attachments

Signed-off-by: Carl Schwan <carl.schwan@nextcloud.com>
This commit is contained in:
Carl Schwan
2025-09-23 16:59:09 +02:00
parent 64741e455d
commit 5cf486150a
77 changed files with 4257 additions and 1393 deletions

View File

@@ -9,31 +9,35 @@
} }
], ],
"require": { "require": {
"justinrainbow/json-schema": "^6.0" "justinrainbow/json-schema": "^6.0",
"bamarni/composer-bin-plugin": "^1.8"
}, },
"require-dev": { "require-dev": {
"roave/security-advisories": "dev-master", "roave/security-advisories": "dev-master",
"phpunit/phpunit": "^9", "phpunit/phpunit": "^9",
"nextcloud/coding-standard": "^1.1", "nextcloud/coding-standard": "^1.1",
"nextcloud/ocp": "dev-master", "nextcloud/ocp": "dev-master"
"psalm/phar": "^5.13"
}, },
"config": { "config": {
"optimize-autoloader": true, "optimize-autoloader": true,
"allow-plugins": { "allow-plugins": {
"composer/package-versions-deprecated": true "composer/package-versions-deprecated": true,
"bamarni/composer-bin-plugin": true
}, },
"platform": { "platform": {
"php": "8.1" "php": "8.1"
} }
}, },
"scripts": { "scripts": {
"post-install-cmd": [
"@composer bin all install --ansi"
],
"lint": "find . -name \\*.php -not -path './vendor/*' -print0 | xargs -0 -n1 php -l", "lint": "find . -name \\*.php -not -path './vendor/*' -print0 | xargs -0 -n1 php -l",
"cs:check": "php-cs-fixer fix --dry-run --diff", "cs:check": "php-cs-fixer fix --dry-run --diff",
"cs:fix": "php-cs-fixer fix", "cs:fix": "php-cs-fixer fix",
"psalm": "psalm.phar", "psalm": "psalm",
"psalm:update-baseline": "psalm.phar --update-baseline", "psalm:update-baseline": "psalm --threads=$(nproc) --no-cache --update-baseline",
"psalm:fix": "psalm.phar --alter --issues=InvalidReturnType,InvalidNullableReturnType,MismatchingDocblockParamType,MismatchingDocblockReturnType,MissingParamType,InvalidFalsableReturnType", "psalm:fix": "psalm --alter --issues=InvalidReturnType,InvalidNullableReturnType,MismatchingDocblockParamType,MismatchingDocblockReturnType,MissingParamType,InvalidFalsableReturnType",
"test": [ "test": [
"@test:unit", "@test:unit",
"@test:integration" "@test:integration"

94
composer.lock generated
View File

@@ -4,8 +4,65 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "6950663d9d213151028e780637480220", "content-hash": "263f9ff9e6a13d50ab09bc9f4e06b749",
"packages": [ "packages": [
{
"name": "bamarni/composer-bin-plugin",
"version": "1.8.2",
"source": {
"type": "git",
"url": "https://github.com/bamarni/composer-bin-plugin.git",
"reference": "92fd7b1e6e9cdae19b0d57369d8ad31a37b6a880"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/bamarni/composer-bin-plugin/zipball/92fd7b1e6e9cdae19b0d57369d8ad31a37b6a880",
"reference": "92fd7b1e6e9cdae19b0d57369d8ad31a37b6a880",
"shasum": ""
},
"require": {
"composer-plugin-api": "^2.0",
"php": "^7.2.5 || ^8.0"
},
"require-dev": {
"composer/composer": "^2.0",
"ext-json": "*",
"phpstan/extension-installer": "^1.1",
"phpstan/phpstan": "^1.8",
"phpstan/phpstan-phpunit": "^1.1",
"phpunit/phpunit": "^8.5 || ^9.5",
"symfony/console": "^2.8.52 || ^3.4.35 || ^4.4 || ^5.0 || ^6.0",
"symfony/finder": "^2.8.52 || ^3.4.35 || ^4.4 || ^5.0 || ^6.0",
"symfony/process": "^2.8.52 || ^3.4.35 || ^4.4 || ^5.0 || ^6.0"
},
"type": "composer-plugin",
"extra": {
"class": "Bamarni\\Composer\\Bin\\BamarniBinPlugin"
},
"autoload": {
"psr-4": {
"Bamarni\\Composer\\Bin\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"description": "No conflicts for your bin dependencies",
"keywords": [
"composer",
"conflict",
"dependency",
"executable",
"isolation",
"tool"
],
"support": {
"issues": "https://github.com/bamarni/composer-bin-plugin/issues",
"source": "https://github.com/bamarni/composer-bin-plugin/tree/1.8.2"
},
"time": "2022-10-31T08:38:03+00:00"
},
{ {
"name": "justinrainbow/json-schema", "name": "justinrainbow/json-schema",
"version": "6.4.2", "version": "6.4.2",
@@ -1073,41 +1130,6 @@
], ],
"time": "2024-12-05T13:48:26+00:00" "time": "2024-12-05T13:48:26+00:00"
}, },
{
"name": "psalm/phar",
"version": "5.26.1",
"source": {
"type": "git",
"url": "https://github.com/psalm/phar.git",
"reference": "8a38e7ad04499a0ccd2c506fd1da6fc01fff4547"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/psalm/phar/zipball/8a38e7ad04499a0ccd2c506fd1da6fc01fff4547",
"reference": "8a38e7ad04499a0ccd2c506fd1da6fc01fff4547",
"shasum": ""
},
"require": {
"php": "^7.1 || ^8.0"
},
"conflict": {
"vimeo/psalm": "*"
},
"bin": [
"psalm.phar"
],
"type": "library",
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"description": "Composer-based Psalm Phar",
"support": {
"issues": "https://github.com/psalm/phar/issues",
"source": "https://github.com/psalm/phar/tree/5.26.1"
},
"time": "2024-09-09T16:22:43+00:00"
},
{ {
"name": "psr/clock", "name": "psr/clock",
"version": "1.0.0", "version": "1.0.0",

View File

@@ -516,7 +516,7 @@ class ActivityManager {
]; ];
} }
private function findDetailsForCard($cardId, $subject = null) { private function findDetailsForCard(int $cardId, ?string $subject = null): array {
$card = $this->cardMapper->find($cardId); $card = $this->cardMapper->find($cardId);
$stack = $this->stackMapper->find($card->getStackId()); $stack = $this->stackMapper->find($card->getStackId());
$board = $this->boardMapper->find($stack->getBoardId()); $board = $this->boardMapper->find($stack->getBoardId());

View File

@@ -7,6 +7,9 @@
namespace OCA\Deck\Activity; namespace OCA\Deck\Activity;
/**
* @psalm-api SettingComment
*/
class SettingComment extends SettingBase { class SettingComment extends SettingBase {
/** /**

View File

@@ -6,9 +6,13 @@
*/ */
namespace OCA\Deck\Controller; namespace OCA\Deck\Controller;
use OCA\Deck\Db\Attachment;
use OCA\Deck\Service\AttachmentService; use OCA\Deck\Service\AttachmentService;
use OCP\AppFramework\ApiController; use OCP\AppFramework\ApiController;
use OCP\AppFramework\Http; use OCP\AppFramework\Http;
use OCP\AppFramework\Http\Attribute\CORS;
use OCP\AppFramework\Http\Attribute\NoAdminRequired;
use OCP\AppFramework\Http\Attribute\NoCSRFRequired;
use OCP\AppFramework\Http\DataResponse; use OCP\AppFramework\Http\DataResponse;
use OCP\IRequest; use OCP\IRequest;
@@ -21,72 +25,52 @@ class AttachmentApiController extends ApiController {
parent::__construct($appName, $request); parent::__construct($appName, $request);
} }
/** #[NoAdminRequired]
* @NoAdminRequired #[CORS]
* @CORS #[NoCSRFRequired]
* @NoCSRFRequired public function getAll(string $apiVersion): DataResponse {
*
*/
public function getAll($apiVersion) {
$attachment = $this->attachmentService->findAll($this->request->getParam('cardId'), true); $attachment = $this->attachmentService->findAll($this->request->getParam('cardId'), true);
if ($apiVersion === '1.0') { if ($apiVersion === '1.0') {
$attachment = array_filter($attachment, function ($attachment) { $attachment = array_filter($attachment, fn (Attachment $attachment): bool => $attachment->getType() === 'deck_file');
return $attachment->getType() === 'deck_file';
});
} }
return new DataResponse($attachment, HTTP::STATUS_OK); return new DataResponse($attachment, HTTP::STATUS_OK);
} }
/** #[NoAdminRequired]
* @NoAdminRequired #[CORS]
* @CORS #[NoCSRFRequired]
* @NoCSRFRequired public function display(int $cardId, int $attachmentId, string $type = 'deck_file') {
*
*/
public function display($cardId, $attachmentId, $type = 'deck_file') {
return $this->attachmentService->display($cardId, $attachmentId, $type); return $this->attachmentService->display($cardId, $attachmentId, $type);
} }
/** #[NoAdminRequired]
* @NoAdminRequired #[CORS]
* @CORS #[NoCSRFRequired]
* @NoCSRFRequired public function create(int $cardId, string $type, string $data): DataResponse {
*
*/
public function create($cardId, $type, $data) {
$attachment = $this->attachmentService->create($cardId, $type, $data); $attachment = $this->attachmentService->create($cardId, $type, $data);
return new DataResponse($attachment, HTTP::STATUS_OK); return new DataResponse($attachment, HTTP::STATUS_OK);
} }
/** #[NoAdminRequired]
* @NoAdminRequired #[CORS]
* @CORS #[NoCSRFRequired]
* @NoCSRFRequired public function update(int $cardId, int $attachmentId, string $data, string $type = 'deck_file'): DataResponse {
*
*/
public function update($cardId, $attachmentId, $data, $type = 'deck_file') {
$attachment = $this->attachmentService->update($cardId, $attachmentId, $data, $type); $attachment = $this->attachmentService->update($cardId, $attachmentId, $data, $type);
return new DataResponse($attachment, HTTP::STATUS_OK); return new DataResponse($attachment, HTTP::STATUS_OK);
} }
/** #[NoAdminRequired]
* @NoAdminRequired #[CORS]
* @CORS #[NoCSRFRequired]
* @NoCSRFRequired public function delete(int $cardId, int $attachmentId, string $type = 'deck_file'): DataResponse {
*
*/
public function delete($cardId, $attachmentId, $type = 'deck_file') {
$attachment = $this->attachmentService->delete($cardId, $attachmentId, $type); $attachment = $this->attachmentService->delete($cardId, $attachmentId, $type);
return new DataResponse($attachment, HTTP::STATUS_OK); return new DataResponse($attachment, HTTP::STATUS_OK);
} }
/** #[NoAdminRequired]
* @NoAdminRequired #[CORS]
* @CORS #[NoCSRFRequired]
* @NoCSRFRequired public function restore(int $cardId, int $attachmentId, string $type = 'deck_file'): DataResponse {
*
*/
public function restore($cardId, $attachmentId, $type = 'deck_file') {
$attachment = $this->attachmentService->restore($cardId, $attachmentId, $type); $attachment = $this->attachmentService->restore($cardId, $attachmentId, $type);
return new DataResponse($attachment, HTTP::STATUS_OK); return new DataResponse($attachment, HTTP::STATUS_OK);
} }

View File

@@ -7,8 +7,13 @@
namespace OCA\Deck\Controller; namespace OCA\Deck\Controller;
use OCA\Deck\BadRequestException;
use OCA\Deck\Db\Attachment;
use OCA\Deck\Service\AttachmentService; use OCA\Deck\Service\AttachmentService;
use OCP\AppFramework\Controller; use OCP\AppFramework\Controller;
use OCP\AppFramework\Http\Attribute\NoAdminRequired;
use OCP\AppFramework\Http\Attribute\NoCSRFRequired;
use OCP\AppFramework\Http\Response;
use OCP\IRequest; use OCP\IRequest;
class AttachmentController extends Controller { class AttachmentController extends Controller {
@@ -20,74 +25,66 @@ class AttachmentController extends Controller {
parent::__construct($appName, $request); parent::__construct($appName, $request);
} }
/** #[NoAdminRequired]
* @NoAdminRequired public function getAll(int $cardId): array {
*/
public function getAll($cardId) {
return $this->attachmentService->findAll($cardId, true); return $this->attachmentService->findAll($cardId, true);
} }
/** /**
* @param $cardId
* @param $attachmentId
* @NoCSRFRequired
* @NoAdminRequired
* @return \OCP\AppFramework\Http\Response
* @throws \OCA\Deck\NotFoundException * @throws \OCA\Deck\NotFoundException
*/ */
public function display($cardId, $attachmentId) { #[NoAdminRequired]
if (!str_contains($attachmentId, ':')) { #[NoCSRFRequired]
$type = 'deck_file'; public function display(int $cardId, string $attachmentId): Response {
} else { ['type' => $type, 'attachmentId' => $attachmentId] = $this->extractTypeAndAttachmentId($attachmentId);
[$type, $attachmentId] = explode(':', $attachmentId);
}
return $this->attachmentService->display($cardId, $attachmentId, $type); return $this->attachmentService->display($cardId, $attachmentId, $type);
} }
/** #[NoAdminRequired]
* @NoAdminRequired public function create(int $cardId): Attachment {
*/
public function create($cardId) {
return $this->attachmentService->create( return $this->attachmentService->create(
$cardId, $cardId,
$this->request->getParam('type'), $this->request->getParam('type'),
$this->request->getParam('data') $this->request->getParam('data') ?? '',
); );
} }
/** #[NoAdminRequired]
* @NoAdminRequired public function update(int $cardId, string $attachmentId): Attachment {
*/ ['type' => $type, 'attachmentId' => $attachmentId] = $this->extractTypeAndAttachmentId($attachmentId);
public function update($cardId, $attachmentId) { return $this->attachmentService->update($cardId, $attachmentId, $this->request->getParam('data') ?? '', $type);
if (!str_contains($attachmentId, ':')) {
$type = 'deck_file';
} else {
[$type, $attachmentId] = explode(':', $attachmentId);
}
return $this->attachmentService->update($cardId, $attachmentId, $this->request->getParam('data'), $type);
} }
/** #[NoAdminRequired]
* @NoAdminRequired public function delete(int $cardId, string $attachmentId): Attachment {
*/ ['type' => $type, 'attachmentId' => $attachmentId] = $this->extractTypeAndAttachmentId($attachmentId);
public function delete($cardId, $attachmentId) {
if (!str_contains($attachmentId, ':')) {
$type = 'deck_file';
} else {
[$type, $attachmentId] = explode(':', $attachmentId);
}
return $this->attachmentService->delete($cardId, $attachmentId, $type); return $this->attachmentService->delete($cardId, $attachmentId, $type);
} }
#[NoAdminRequired]
public function restore(int $cardId, string $attachmentId): Attachment {
['type' => $type, 'attachmentId' => $attachmentId] = $this->extractTypeAndAttachmentId($attachmentId);
return $this->attachmentService->restore($cardId, $attachmentId, $type);
}
/** /**
* @NoAdminRequired * @return array{type: string, attachmentId: int}
* @throws BadRequestException
*/ */
public function restore($cardId, $attachmentId) { private function extractTypeAndAttachmentId(string $attachmentId): array {
if (!str_contains($attachmentId, ':')) { if (!str_contains($attachmentId, ':')) {
$type = 'deck_file'; $type = 'deck_file';
} else { } else {
[$type, $attachmentId] = explode(':', $attachmentId); [$type, $attachmentId] = [...explode(':', $attachmentId), '', ''];
} }
return $this->attachmentService->restore($cardId, $attachmentId, $type);
if ($type === '' || !is_numeric($attachmentId)) {
throw new BadRequestException('Invalid attachment id');
}
return [
'type' => $type,
'attachmentId' => (int)$attachmentId,
];
} }
} }

View File

@@ -12,10 +12,13 @@ use OCA\Deck\Service\BoardService;
use OCA\Deck\StatusException; use OCA\Deck\StatusException;
use OCP\AppFramework\ApiController; use OCP\AppFramework\ApiController;
use OCP\AppFramework\Http; use OCP\AppFramework\Http;
use OCP\AppFramework\Http\Attribute\CORS;
use OCP\AppFramework\Http\Attribute\NoAdminRequired;
use OCP\AppFramework\Http\Attribute\NoCSRFRequired;
use OCP\AppFramework\Http\DataResponse; use OCP\AppFramework\Http\DataResponse;
use OCP\IRequest; use OCP\IRequest;
use Sabre\HTTP\Util;
use function Sabre\HTTP\parseDate;
/** /**
* Class BoardApiController * Class BoardApiController
@@ -36,21 +39,18 @@ class BoardApiController extends ApiController {
} }
/** /**
* @NoAdminRequired * Return all the boards that the current user has access to.
* @CORS
* @NoCSRFRequired
*
* Return all of the boards that the current user has access to.
*
* @param bool $details
* @throws StatusException * @throws StatusException
*/ */
public function index(bool $details = false) { #[NoAdminRequired]
#[NoCSRFRequired]
#[CORS]
public function index(bool $details = false): DataResponse {
$modified = $this->request->getHeader('If-Modified-Since'); $modified = $this->request->getHeader('If-Modified-Since');
if ($modified === null || $modified === '') { if ($modified === '') {
$boards = $this->boardService->findAll(0, $details === true); $boards = $this->boardService->findAll(0, $details === true);
} else { } else {
$date = Util::parseHTTPDate($modified); $date = parseDate($modified);
if (!$date) { if (!$date) {
throw new StatusException('Invalid If-Modified-Since header provided.'); throw new StatusException('Invalid If-Modified-Since header provided.');
} }
@@ -64,14 +64,12 @@ class BoardApiController extends ApiController {
} }
/** /**
* @NoAdminRequired
* @CORS
* @NoCSRFRequired
*
*
* Return the board specified by $this->request->getParam('boardId'). * Return the board specified by $this->request->getParam('boardId').
*/ */
public function get() { #[NoAdminRequired]
#[NoCSRFRequired]
#[CORS]
public function get(): DataResponse {
$board = $this->boardService->find($this->request->getParam('boardId')); $board = $this->boardService->find($this->request->getParam('boardId'));
$response = new DataResponse($board, HTTP::STATUS_OK); $response = new DataResponse($board, HTTP::STATUS_OK);
$response->setETag($board->getEtag()); $response->setETag($board->getEtag());
@@ -79,68 +77,53 @@ class BoardApiController extends ApiController {
} }
/** /**
* @NoAdminRequired
* @CORS
* @NoCSRFRequired
*
* @params $title
* @params $color
*
* Create a board with the specified title and color. * Create a board with the specified title and color.
*/ */
public function create($title, $color) { #[NoAdminRequired]
#[NoCSRFRequired]
#[CORS]
public function create(string $title, string $color): DataResponse {
$board = $this->boardService->create($title, $this->userId, $color); $board = $this->boardService->create($title, $this->userId, $color);
return new DataResponse($board, HTTP::STATUS_OK); return new DataResponse($board, HTTP::STATUS_OK);
} }
/** /**
* @NoAdminRequired
* @CORS
* @NoCSRFRequired
*
* @params $title
* @params $color
* @params $archived
*
* Update a board with the specified boardId, title and color, and archived state. * Update a board with the specified boardId, title and color, and archived state.
*/ */
public function update($title, $color, $archived = false) { #[NoAdminRequired]
#[NoCSRFRequired]
#[CORS]
public function update(string $title, string $color, bool $archived = false): DataResponse {
$board = $this->boardService->update($this->request->getParam('boardId'), $title, $color, $archived); $board = $this->boardService->update($this->request->getParam('boardId'), $title, $color, $archived);
return new DataResponse($board, HTTP::STATUS_OK); return new DataResponse($board, HTTP::STATUS_OK);
} }
/** /**
* @NoAdminRequired
* @CORS
* @NoCSRFRequired
*
*
* Delete the board specified by $boardId. Return the board that was deleted. * Delete the board specified by $boardId. Return the board that was deleted.
*/ */
public function delete() { #[NoAdminRequired]
#[NoCSRFRequired]
#[CORS]
public function delete(): DataResponse {
$board = $this->boardService->delete($this->request->getParam('boardId')); $board = $this->boardService->delete($this->request->getParam('boardId'));
return new DataResponse($board, HTTP::STATUS_OK); return new DataResponse($board, HTTP::STATUS_OK);
} }
/** /**
* @NoAdminRequired
* @CORS
* @NoCSRFRequired
*
*
* Undo the deletion of the board specified by $boardId. * Undo the deletion of the board specified by $boardId.
*/ */
public function undoDelete() { #[NoAdminRequired]
#[NoCSRFRequired]
#[CORS]
public function undoDelete(): DataResponse {
$board = $this->boardService->deleteUndo($this->request->getParam('boardId')); $board = $this->boardService->deleteUndo($this->request->getParam('boardId'));
return new DataResponse($board, HTTP::STATUS_OK); return new DataResponse($board, HTTP::STATUS_OK);
} }
/** #[NoAdminRequired]
* @NoAdminRequired #[NoCSRFRequired]
* @CORS #[CORS]
* @NoCSRFRequired public function addAcl(int $boardId, $type, $participant, $permissionEdit, $permissionShare, $permissionManage) {
*/
public function addAcl($boardId, $type, $participant, $permissionEdit, $permissionShare, $permissionManage) {
$acl = $this->boardService->addAcl($boardId, $type, $participant, $permissionEdit, $permissionShare, $permissionManage); $acl = $this->boardService->addAcl($boardId, $type, $participant, $permissionEdit, $permissionShare, $permissionManage);
return new DataResponse($acl, HTTP::STATUS_OK); return new DataResponse($acl, HTTP::STATUS_OK);
} }

View File

@@ -14,6 +14,7 @@ use OCA\Deck\Service\Importer\BoardImportService;
use OCA\Deck\Service\PermissionService; use OCA\Deck\Service\PermissionService;
use OCP\AppFramework\ApiController; use OCP\AppFramework\ApiController;
use OCP\AppFramework\Http; use OCP\AppFramework\Http;
use OCP\AppFramework\Http\Attribute\NoAdminRequired;
use OCP\AppFramework\Http\DataResponse; use OCP\AppFramework\Http\DataResponse;
use OCP\IL10N; use OCP\IL10N;
use OCP\IRequest; use OCP\IRequest;
@@ -31,68 +32,38 @@ class BoardController extends ApiController {
parent::__construct($appName, $request); parent::__construct($appName, $request);
} }
/** #[NoAdminRequired]
* @NoAdminRequired
*/
public function index() { public function index() {
return $this->boardService->findAll(); return $this->boardService->findAll();
} }
/** #[NoAdminRequired]
* @NoAdminRequired public function read(int $boardId): Board {
* @param $boardId
* @return \OCP\AppFramework\Db\Entity
*/
public function read(int $boardId) {
return $this->boardService->find($boardId); return $this->boardService->find($boardId);
} }
/** #[NoAdminRequired]
* @NoAdminRequired public function create(string $title, string $color): Board {
* @param $title
* @param $color
* @return \OCP\AppFramework\Db\Entity
*/
public function create($title, $color) {
return $this->boardService->create($title, $this->userId, $color); return $this->boardService->create($title, $this->userId, $color);
} }
/** #[NoAdminRequired]
* @NoAdminRequired public function update(int $id, string $title, string $color, bool $archived): Board {
* @param $id
* @param $title
* @param $color
* @param $archived
* @return \OCP\AppFramework\Db\Entity
*/
public function update($id, $title, $color, $archived) {
return $this->boardService->update($id, $title, $color, $archived); return $this->boardService->update($id, $title, $color, $archived);
} }
/** #[NoAdminRequired]
* @NoAdminRequired public function delete(int $boardId): Board {
* @param $boardId
* @return \OCP\AppFramework\Db\Entity
*/
public function delete($boardId) {
return $this->boardService->delete($boardId); return $this->boardService->delete($boardId);
} }
/**
* @NoAdminRequired #[NoAdminRequired]
* @param $boardId public function deleteUndo(int $boardId): Board {
* @return \OCP\AppFramework\Db\Entity
*/
public function deleteUndo($boardId) {
return $this->boardService->deleteUndo($boardId); return $this->boardService->deleteUndo($boardId);
} }
/** #[NoAdminRequired]
* @NoAdminRequired public function getUserPermissions(int $boardId): array {
* @param $boardId
* @return array|bool
* @internal param $userId
*/
public function getUserPermissions($boardId) {
$permissions = $this->permissionService->getPermissions($boardId); $permissions = $this->permissionService->getPermissions($boardId);
return [ return [
'PERMISSION_READ' => $permissions[Acl::PERMISSION_READ], 'PERMISSION_READ' => $permissions[Acl::PERMISSION_READ],
@@ -103,16 +74,10 @@ class BoardController extends ApiController {
} }
/** /**
* @NoAdminRequired
* @param $boardId
* @param $type
* @param $participant * @param $participant
* @param $permissionEdit
* @param $permissionShare
* @param $permissionManage
* @return \OCP\AppFramework\Db\Entity
*/ */
public function addAcl($boardId, $type, $participant, $permissionEdit, $permissionShare, $permissionManage) { #[NoAdminRequired]
public function addAcl(int $boardId, int $type, $participant, bool $permissionEdit, bool $permissionShare, bool $permissionManage): Acl {
return $this->boardService->addAcl($boardId, $type, $participant, $permissionEdit, $permissionShare, $permissionManage); return $this->boardService->addAcl($boardId, $type, $participant, $permissionEdit, $permissionShare, $permissionManage);
} }

View File

@@ -9,6 +9,9 @@ namespace OCA\Deck\Controller;
use OCA\Deck\Service\Importer\BoardImportService; use OCA\Deck\Service\Importer\BoardImportService;
use OCP\AppFramework\Http; use OCP\AppFramework\Http;
use OCP\AppFramework\Http\Attribute\CORS;
use OCP\AppFramework\Http\Attribute\NoAdminRequired;
use OCP\AppFramework\Http\Attribute\NoCSRFRequired;
use OCP\AppFramework\Http\DataResponse; use OCP\AppFramework\Http\DataResponse;
use OCP\AppFramework\OCSController; use OCP\AppFramework\OCSController;
use OCP\IRequest; use OCP\IRequest;
@@ -23,11 +26,9 @@ class BoardImportApiController extends OCSController {
parent::__construct($appName, $request); parent::__construct($appName, $request);
} }
/** #[NoAdminRequired]
* @NoAdminRequired #[CORS]
* @CORS #[NoCSRFRequired]
* @NoCSRFRequired
*/
public function import(string $system, array $config, array $data): DataResponse { public function import(string $system, array $config, array $data): DataResponse {
$this->boardImportService->setSystem($system); $this->boardImportService->setSystem($system);
$config = json_decode(json_encode($config)); $config = json_decode(json_encode($config));
@@ -38,21 +39,17 @@ class BoardImportApiController extends OCSController {
return new DataResponse($this->boardImportService->getBoard(), Http::STATUS_OK); return new DataResponse($this->boardImportService->getBoard(), Http::STATUS_OK);
} }
/** #[NoAdminRequired]
* @NoAdminRequired #[CORS]
* @CORS #[NoCSRFRequired]
* @NoCSRFRequired
*/
public function getAllowedSystems(): DataResponse { public function getAllowedSystems(): DataResponse {
$allowedSystems = $this->boardImportService->getAllowedImportSystems(); $allowedSystems = $this->boardImportService->getAllowedImportSystems();
return new DataResponse($allowedSystems, Http::STATUS_OK); return new DataResponse($allowedSystems, Http::STATUS_OK);
} }
/** #[NoAdminRequired]
* @NoAdminRequired #[CORS]
* @CORS #[NoCSRFRequired]
* @NoCSRFRequired
*/
public function getConfigSchema(string $name): DataResponse { public function getConfigSchema(string $name): DataResponse {
$this->boardImportService->setSystem($name); $this->boardImportService->setSystem($name);
$this->boardImportService->validateSystem(); $this->boardImportService->validateSystem();

View File

@@ -12,6 +12,9 @@ use OCA\Deck\Service\AssignmentService;
use OCA\Deck\Service\CardService; use OCA\Deck\Service\CardService;
use OCP\AppFramework\ApiController; use OCP\AppFramework\ApiController;
use OCP\AppFramework\Http; use OCP\AppFramework\Http;
use OCP\AppFramework\Http\Attribute\CORS;
use OCP\AppFramework\Http\Attribute\NoAdminRequired;
use OCP\AppFramework\Http\Attribute\NoCSRFRequired;
use OCP\AppFramework\Http\DataResponse; use OCP\AppFramework\Http\DataResponse;
use OCP\IRequest; use OCP\IRequest;
@@ -27,7 +30,7 @@ class CardApiController extends ApiController {
* @param IRequest $request * @param IRequest $request
* @param CardService $cardService * @param CardService $cardService
* @param AssignmentService $assignmentService * @param AssignmentService $assignmentService
* @param $userId * @param string $userId
*/ */
public function __construct( public function __construct(
string $appName, string $appName,
@@ -80,112 +83,102 @@ class CardApiController extends ApiController {
} }
/** /**
* @NoAdminRequired
* @CORS
* @NoCSRFRequired
*
*
* Update a card * Update a card
*/ */
public function update($title, $type, $owner, $description = '', $order = 0, $duedate = null, $archived = null) { #[NoAdminRequired]
#[CORS]
#[NoCSRFRequired]
public function update(string $title, $type, string $owner, string $description = '', int $order = 0, $duedate = null, $archived = null): DataResponse {
$done = array_key_exists('done', $this->request->getParams()) ? new OptionalNullableValue($this->request->getParam('done', null)) : null; $done = array_key_exists('done', $this->request->getParams()) ? new OptionalNullableValue($this->request->getParam('done', null)) : null;
$card = $this->cardService->update($this->request->getParam('cardId'), $title, $this->request->getParam('stackId'), $type, $owner, $description, $order, $duedate, 0, $archived, $done); $card = $this->cardService->update($this->request->getParam('cardId'), $title, $this->request->getParam('stackId'), $type, $owner, $description, $order, $duedate, 0, $archived, $done);
return new DataResponse($card, HTTP::STATUS_OK); return new DataResponse($card, HTTP::STATUS_OK);
} }
/** /**
* @NoAdminRequired
* @CORS
* @NoCSRFRequired
*
* Delete a specific card. * Delete a specific card.
*/ */
public function delete() { #[NoAdminRequired]
#[CORS]
#[NoCSRFRequired]
public function delete(): DataResponse {
$card = $this->cardService->delete($this->request->getParam('cardId')); $card = $this->cardService->delete($this->request->getParam('cardId'));
return new DataResponse($card, HTTP::STATUS_OK); return new DataResponse($card, HTTP::STATUS_OK);
} }
/** /**
* @NoAdminRequired
* @CORS
* @NoCSRFRequired
*
* Assign a label to a card. * Assign a label to a card.
*/ */
public function assignLabel($labelId) { #[NoAdminRequired]
#[CORS]
#[NoCSRFRequired]
public function assignLabel(int $labelId): DataResponse {
$card = $this->cardService->assignLabel($this->request->getParam('cardId'), $labelId); $card = $this->cardService->assignLabel($this->request->getParam('cardId'), $labelId);
return new DataResponse($card, HTTP::STATUS_OK); return new DataResponse($card, HTTP::STATUS_OK);
} }
/** /**
* @NoAdminRequired
* @CORS
* @NoCSRFRequired
*
* Assign a label to a card. * Assign a label to a card.
*/ */
public function removeLabel($labelId) { #[NoAdminRequired]
#[CORS]
#[NoCSRFRequired]
public function removeLabel(int $labelId): DataResponse {
$card = $this->cardService->removeLabel($this->request->getParam('cardId'), $labelId); $card = $this->cardService->removeLabel($this->request->getParam('cardId'), $labelId);
return new DataResponse($card, HTTP::STATUS_OK); return new DataResponse($card, HTTP::STATUS_OK);
} }
/** /**
* @NoAdminRequired
* @CORS
* @NoCSRFRequired
*
* Assign a user to a card * Assign a user to a card
*/ */
public function assignUser($cardId, $userId, $type = 0) { #[NoAdminRequired]
#[CORS]
#[NoCSRFRequired]
public function assignUser(int $cardId, string $userId, int $type = 0): DataResponse {
$card = $this->assignmentService->assignUser($cardId, $userId, $type); $card = $this->assignmentService->assignUser($cardId, $userId, $type);
return new DataResponse($card, HTTP::STATUS_OK); return new DataResponse($card, HTTP::STATUS_OK);
} }
/** /**
* @NoAdminRequired
* @CORS
* @NoCSRFRequired
*
* Unassign a user from a card * Unassign a user from a card
*/ */
public function unassignUser($cardId, $userId, $type = 0) { #[NoAdminRequired]
#[CORS]
#[NoCSRFRequired]
public function unassignUser(int $cardId, string $userId, int $type = 0): DataResponse {
$card = $this->assignmentService->unassignUser($cardId, $userId, $type); $card = $this->assignmentService->unassignUser($cardId, $userId, $type);
return new DataResponse($card, HTTP::STATUS_OK); return new DataResponse($card, HTTP::STATUS_OK);
} }
/** /**
* @NoAdminRequired
* @CORS
* @NoCSRFRequired
*
* Archive card * Archive card
*/ */
public function archive($cardId) { #[NoAdminRequired]
#[CORS]
#[NoCSRFRequired]
public function archive(int $cardId): DataResponse {
$card = $this->cardService->archive($cardId); $card = $this->cardService->archive($cardId);
return new DataResponse($card, HTTP::STATUS_OK); return new DataResponse($card, HTTP::STATUS_OK);
} }
/** /**
* @NoAdminRequired
* @CORS
* @NoCSRFRequired
*
* Unarchive card * Unarchive card
*/ */
public function unarchive($cardId) { #[NoAdminRequired]
#[CORS]
#[NoCSRFRequired]
public function unarchive(int $cardId): DataResponse {
$card = $this->cardService->unarchive($cardId); $card = $this->cardService->unarchive($cardId);
return new DataResponse($card, HTTP::STATUS_OK); return new DataResponse($card, HTTP::STATUS_OK);
} }
/** /**
* @NoAdminRequired
* @CORS
* @NoCSRFRequired
*
* Reorder cards * Reorder cards
*/ */
public function reorder($stackId, $order) { #[NoAdminRequired]
$card = $this->cardService->reorder((int)$this->request->getParam('cardId'), (int)$stackId, (int)$order); #[CORS]
#[NoCSRFRequired]
public function reorder(int $stackId, int $order): DataResponse {
$card = $this->cardService->reorder((int)$this->request->getParam('cardId'), $stackId, $order);
return new DataResponse($card, HTTP::STATUS_OK); return new DataResponse($card, HTTP::STATUS_OK);
} }
} }

View File

@@ -7,9 +7,12 @@
namespace OCA\Deck\Controller; namespace OCA\Deck\Controller;
use OCA\Deck\Db\Assignment;
use OCA\Deck\Db\Card;
use OCA\Deck\Service\AssignmentService; use OCA\Deck\Service\AssignmentService;
use OCA\Deck\Service\CardService; use OCA\Deck\Service\CardService;
use OCP\AppFramework\Controller; use OCP\AppFramework\Controller;
use OCP\AppFramework\Http\Attribute\NoAdminRequired;
use OCP\IRequest; use OCP\IRequest;
class CardController extends Controller { class CardController extends Controller {
@@ -23,45 +26,26 @@ class CardController extends Controller {
parent::__construct($appName, $request); parent::__construct($appName, $request);
} }
/** #[NoAdminRequired]
* @NoAdminRequired public function read(int $cardId): Card {
* @param $cardId
* @return \OCP\AppFramework\Db\Entity
*/
public function read($cardId) {
return $this->cardService->find($cardId); return $this->cardService->find($cardId);
} }
/** /**
* @NoAdminRequired * @return Card[]
* @param $cardId
* @param $stackId
* @param $order
* @return array
*/ */
public function reorder($cardId, $stackId, $order) { #[NoAdminRequired]
return $this->cardService->reorder((int)$cardId, (int)$stackId, (int)$order); public function reorder(int $cardId, int $stackId, int $order): array {
return $this->cardService->reorder($cardId, $stackId, $order);
} }
/** #[NoAdminRequired]
* @NoAdminRequired public function rename(int $cardId, string $title): Card {
* @param $cardId
* @param $title
* @return \OCP\AppFramework\Db\Entity
*/
public function rename($cardId, $title) {
return $this->cardService->rename($cardId, $title); return $this->cardService->rename($cardId, $title);
} }
/** #[NoAdminRequired]
* @NoAdminRequired public function create(string $title, int $stackId, string $type = 'plain', int $order = 999, string $description = '', $duedate = null, array $labels = [], array $users = []): Card {
* @param $title
* @param $stackId
* @param $type
* @param int $order
* @return \OCP\AppFramework\Db\Entity
*/
public function create($title, $stackId, $type = 'plain', $order = 999, string $description = '', $duedate = null, $labels = [], $users = []) {
$card = $this->cardService->create($title, $stackId, $type, $order, $this->userId, $description, $duedate); $card = $this->cardService->create($title, $stackId, $type, $order, $this->userId, $description, $duedate);
foreach ($labels as $label) { foreach ($labels as $label) {
@@ -76,113 +60,68 @@ class CardController extends Controller {
} }
/** /**
* @NoAdminRequired
* @param $id
* @param $title
* @param $stackId
* @param $type
* @param $order
* @param $description
* @param $duedate * @param $duedate
* @param $deletedAt
* @return \OCP\AppFramework\Db\Entity
*/ */
public function update($id, $title, $stackId, $type, $order, $description, $duedate, $deletedAt) { #[NoAdminRequired]
public function update(int $id, string $title, int $stackId, string $type, int $order, string $description, $duedate, $deletedAt): Card {
return $this->cardService->update($id, $title, $stackId, $type, $this->userId, $description, $order, $duedate, $deletedAt); return $this->cardService->update($id, $title, $stackId, $type, $this->userId, $description, $order, $duedate, $deletedAt);
} }
/**
* @NoAdminRequired #[NoAdminRequired]
* @param $cardId public function clone(int $cardId, ?int $targetStackId = null): Card {
* @param $targetStackId
* @return \OCP\AppFramework\Db\Entity
*/
public function clone(int $cardId, ?int $targetStackId = null) {
return $this->cardService->cloneCard($cardId, $targetStackId); return $this->cardService->cloneCard($cardId, $targetStackId);
} }
/** #[NoAdminRequired]
* @NoAdminRequired public function delete(int $cardId): Card {
* @param $cardId
* @return \OCP\AppFramework\Db\Entity
*/
public function delete($cardId) {
return $this->cardService->delete($cardId); return $this->cardService->delete($cardId);
} }
/** /**
* @NoAdminRequired * @return Card[]
* @param $boardId
* @return \OCP\AppFramework\Db\Entity
*/ */
public function deleted($boardId) { #[NoAdminRequired]
public function deleted(int $boardId): array {
return $this->cardService->fetchDeleted($boardId); return $this->cardService->fetchDeleted($boardId);
} }
/** #[NoAdminRequired]
* @NoAdminRequired
* @param $cardId
* @return \OCP\AppFramework\Db\Entity
*/
public function archive($cardId) { public function archive($cardId) {
return $this->cardService->archive($cardId); return $this->cardService->archive($cardId);
} }
/** #[NoAdminRequired]
* @NoAdminRequired public function unarchive(int $cardId): Card {
* @param $cardId
* @return \OCP\AppFramework\Db\Entity
*/
public function unarchive($cardId) {
return $this->cardService->unarchive($cardId); return $this->cardService->unarchive($cardId);
} }
/** #[NoAdminRequired]
* @NoAdminRequired public function done(int $cardId): Card {
* @param $cardId
* @return \OCP\AppFramework\Db\Entity
*/
public function done(int $cardId) {
return $this->cardService->done($cardId); return $this->cardService->done($cardId);
} }
/** #[NoAdminRequired]
* @NoAdminRequired public function undone(int $cardId): Card {
* @param $cardId
* @return \OCP\AppFramework\Db\Entity
*/
public function undone(int $cardId) {
return $this->cardService->undone($cardId); return $this->cardService->undone($cardId);
} }
/** #[NoAdminRequired]
* @NoAdminRequired public function assignLabel(int $cardId, int $labelId): void {
* @param $cardId
* @param $labelId
*/
public function assignLabel($cardId, $labelId) {
$this->cardService->assignLabel($cardId, $labelId); $this->cardService->assignLabel($cardId, $labelId);
} }
/** #[NoAdminRequired]
* @NoAdminRequired public function removeLabel(int $cardId, int $labelId): void {
* @param $cardId
* @param $labelId
*/
public function removeLabel($cardId, $labelId) {
$this->cardService->removeLabel($cardId, $labelId); $this->cardService->removeLabel($cardId, $labelId);
} }
/** #[NoAdminRequired]
* @NoAdminRequired public function assignUser(int $cardId, string $userId, int $type = 0): Assignment {
*/
public function assignUser($cardId, $userId, $type = 0) {
return $this->assignmentService->assignUser($cardId, $userId, $type); return $this->assignmentService->assignUser($cardId, $userId, $type);
} }
/** #[NoAdminRequired]
* @NoAdminRequired public function unassignUser(int $cardId, string $userId, int $type = 0): Assignment {
*/
public function unassignUser($cardId, $userId, $type = 0) {
return $this->assignmentService->unassignUser($cardId, $userId, $type); return $this->assignmentService->unassignUser($cardId, $userId, $type);
} }
} }

View File

@@ -9,11 +9,15 @@ namespace OCA\Deck\Controller;
use OCA\Deck\Service\CommentService; use OCA\Deck\Service\CommentService;
use OCA\Deck\StatusException; use OCA\Deck\StatusException;
use OCP\AppFramework\Http\Attribute\NoAdminRequired;
use OCP\AppFramework\Http\DataResponse; use OCP\AppFramework\Http\DataResponse;
use OCP\AppFramework\OCSController; use OCP\AppFramework\OCSController;
use OCP\IRequest; use OCP\IRequest;
/**
* @psalm-api
*/
class CommentsApiController extends OCSController { class CommentsApiController extends OCSController {
public function __construct( public function __construct(
string $appName, string $appName,
@@ -27,33 +31,33 @@ class CommentsApiController extends OCSController {
} }
/** /**
* @NoAdminRequired
* @throws StatusException * @throws StatusException
*/ */
public function list(string $cardId, int $limit = 20, int $offset = 0): DataResponse { #[NoAdminRequired]
public function list(int $cardId, int $limit = 20, int $offset = 0): DataResponse {
return $this->commentService->list($cardId, $limit, $offset); return $this->commentService->list($cardId, $limit, $offset);
} }
/** /**
* @NoAdminRequired
* @throws StatusException * @throws StatusException
*/ */
#[NoAdminRequired]
public function create(int $cardId, string $message, int $parentId = 0): DataResponse { public function create(int $cardId, string $message, int $parentId = 0): DataResponse {
return $this->commentService->create($cardId, $message, $parentId); return $this->commentService->create($cardId, $message, $parentId);
} }
/** /**
* @NoAdminRequired
* @throws StatusException * @throws StatusException
*/ */
#[NoAdminRequired]
public function update(int $cardId, int $commentId, string $message): DataResponse { public function update(int $cardId, int $commentId, string $message): DataResponse {
return $this->commentService->update($cardId, $commentId, $message); return $this->commentService->update($cardId, $commentId, $message);
} }
/** /**
* @NoAdminRequired
* @throws StatusException * @throws StatusException
*/ */
#[NoAdminRequired]
public function delete(int $cardId, int $commentId): DataResponse { public function delete(int $cardId, int $commentId): DataResponse {
return $this->commentService->delete($cardId, $commentId); return $this->commentService->delete($cardId, $commentId);
} }

View File

@@ -8,6 +8,8 @@
namespace OCA\Deck\Controller; namespace OCA\Deck\Controller;
use OCA\Deck\Service\ConfigService; use OCA\Deck\Service\ConfigService;
use OCP\AppFramework\Http\Attribute\NoAdminRequired;
use OCP\AppFramework\Http\Attribute\NoCSRFRequired;
use OCP\AppFramework\Http\DataResponse; use OCP\AppFramework\Http\DataResponse;
use OCP\AppFramework\Http\NotFoundResponse; use OCP\AppFramework\Http\NotFoundResponse;
use OCP\AppFramework\OCSController; use OCP\AppFramework\OCSController;
@@ -22,19 +24,15 @@ class ConfigController extends OCSController {
parent::__construct($AppName, $request); parent::__construct($AppName, $request);
} }
/** #[NoAdminRequired]
* @NoCSRFRequired #[NoCSRFRequired]
* @NoAdminRequired
*/
public function get(): DataResponse { public function get(): DataResponse {
return new DataResponse($this->configService->getAll()); return new DataResponse($this->configService->getAll());
} }
/** #[NoAdminRequired]
* @NoCSRFRequired #[NoCSRFRequired]
* @NoAdminRequired public function setValue(string $key, mixed $value): DataResponse|NotFoundResponse {
*/
public function setValue(string $key, $value) {
$result = $this->configService->set($key, $value); $result = $this->configService->set($key, $value);
if ($result === null) { if ($result === null) {
return new NotFoundResponse(); return new NotFoundResponse();

View File

@@ -10,6 +10,9 @@ namespace OCA\Deck\Controller;
use OCA\Deck\Service\LabelService; use OCA\Deck\Service\LabelService;
use OCP\AppFramework\ApiController; use OCP\AppFramework\ApiController;
use OCP\AppFramework\Http; use OCP\AppFramework\Http;
use OCP\AppFramework\Http\Attribute\CORS;
use OCP\AppFramework\Http\Attribute\NoAdminRequired;
use OCP\AppFramework\Http\Attribute\NoCSRFRequired;
use OCP\AppFramework\Http\DataResponse; use OCP\AppFramework\Http\DataResponse;
use OCP\IRequest; use OCP\IRequest;
@@ -26,59 +29,50 @@ class LabelApiController extends ApiController {
$appName, $appName,
IRequest $request, IRequest $request,
private LabelService $labelService, private LabelService $labelService,
private $userId,
) { ) {
parent::__construct($appName, $request); parent::__construct($appName, $request);
} }
/** /**
* @NoAdminRequired
* @CORS
* @NoCSRFRequired
*
* Get a specific label. * Get a specific label.
*/ */
public function get() { #[NoAdminRequired]
#[NoCSRFRequired]
#[CORS]
public function get(): DataResponse {
$label = $this->labelService->find($this->request->getParam('labelId')); $label = $this->labelService->find($this->request->getParam('labelId'));
return new DataResponse($label, HTTP::STATUS_OK); return new DataResponse($label, HTTP::STATUS_OK);
} }
/** /**
* @NoAdminRequired
* @CORS
* @NoCSRFRequired
*
* @params $title
* @params $color
* Create a new label * Create a new label
*/ */
public function create($title, $color) { #[NoAdminRequired]
#[NoCSRFRequired]
#[CORS]
public function create(string $title, string $color): DataResponse {
$label = $this->labelService->create($title, $color, $this->request->getParam('boardId')); $label = $this->labelService->create($title, $color, $this->request->getParam('boardId'));
return new DataResponse($label, HTTP::STATUS_OK); return new DataResponse($label, HTTP::STATUS_OK);
} }
/** /**
* @NoAdminRequired
* @CORS
* @NoCSRFRequired
*
* @params $title
* @params $color
* Update a specific label * Update a specific label
*/ */
public function update($title, $color) { #[NoAdminRequired]
#[NoCSRFRequired]
#[CORS]
public function update(string $title, string $color): DataResponse {
$label = $this->labelService->update($this->request->getParam('labelId'), $title, $color); $label = $this->labelService->update($this->request->getParam('labelId'), $title, $color);
return new DataResponse($label, HTTP::STATUS_OK); return new DataResponse($label, HTTP::STATUS_OK);
} }
/** /**
* @NoAdminRequired
* @CORS
* @NoCSRFRequired
*
* Delete a specific label * Delete a specific label
*/ */
public function delete() { #[NoAdminRequired]
#[NoCSRFRequired]
#[CORS]
public function delete(): DataResponse {
$label = $this->labelService->delete($this->request->getParam('labelId')); $label = $this->labelService->delete($this->request->getParam('labelId'));
return new DataResponse($label, HTTP::STATUS_OK); return new DataResponse($label, HTTP::STATUS_OK);
} }

View File

@@ -7,8 +7,10 @@
namespace OCA\Deck\Controller; namespace OCA\Deck\Controller;
use OCA\Deck\Db\Label;
use OCA\Deck\Service\LabelService; use OCA\Deck\Service\LabelService;
use OCP\AppFramework\Controller; use OCP\AppFramework\Controller;
use OCP\AppFramework\Http\Attribute\NoAdminRequired;
use OCP\IRequest; use OCP\IRequest;
class LabelController extends Controller { class LabelController extends Controller {
@@ -20,34 +22,18 @@ class LabelController extends Controller {
parent::__construct($appName, $request); parent::__construct($appName, $request);
} }
/** #[NoAdminRequired]
* @NoAdminRequired public function create(string $title, string $color, int $boardId): Label {
* @param $title
* @param $color
* @param $boardId
* @return \OCP\AppFramework\Db\Entity
*/
public function create($title, $color, $boardId) {
return $this->labelService->create($title, $color, $boardId); return $this->labelService->create($title, $color, $boardId);
} }
/** #[NoAdminRequired]
* @NoAdminRequired public function update(int $id, string $title, string $color): Label {
* @param $id
* @param $title
* @param $color
* @return \OCP\AppFramework\Db\Entity
*/
public function update($id, $title, $color) {
return $this->labelService->update($id, $title, $color); return $this->labelService->update($id, $title, $color);
} }
/** #[NoAdminRequired]
* @NoAdminRequired public function delete(int $labelId): Label {
* @param $labelId
* @return \OCP\AppFramework\Db\Entity
*/
public function delete($labelId) {
return $this->labelService->delete($labelId); return $this->labelService->delete($labelId);
} }
} }

View File

@@ -10,6 +10,7 @@ declare(strict_types=1);
namespace OCA\Deck\Controller; namespace OCA\Deck\Controller;
use OCA\Deck\Service\OverviewService; use OCA\Deck\Service\OverviewService;
use OCP\AppFramework\Http\Attribute\NoAdminRequired;
use OCP\AppFramework\Http\DataResponse; use OCP\AppFramework\Http\DataResponse;
use OCP\AppFramework\OCSController; use OCP\AppFramework\OCSController;
use OCP\IRequest; use OCP\IRequest;
@@ -24,9 +25,7 @@ class OverviewApiController extends OCSController {
parent::__construct($appName, $request); parent::__construct($appName, $request);
} }
/** #[NoAdminRequired]
* @NoAdminRequired
*/
public function upcomingCards(): DataResponse { public function upcomingCards(): DataResponse {
return new DataResponse($this->dashboardService->findUpcomingCards($this->userId)); return new DataResponse($this->dashboardService->findUpcomingCards($this->userId));
} }

View File

@@ -13,6 +13,7 @@ namespace OCA\Deck\Controller;
use OCA\Deck\Db\Card; use OCA\Deck\Db\Card;
use OCA\Deck\Model\CardDetails; use OCA\Deck\Model\CardDetails;
use OCA\Deck\Service\SearchService; use OCA\Deck\Service\SearchService;
use OCP\AppFramework\Http\Attribute\NoAdminRequired;
use OCP\AppFramework\Http\DataResponse; use OCP\AppFramework\Http\DataResponse;
use OCP\AppFramework\OCSController; use OCP\AppFramework\OCSController;
use OCP\IRequest; use OCP\IRequest;
@@ -26,9 +27,7 @@ class SearchController extends OCSController {
parent::__construct($appName, $request); parent::__construct($appName, $request);
} }
/** #[NoAdminRequired]
* @NoAdminRequired
*/
public function search(string $term, ?int $limit = null, ?int $cursor = null): DataResponse { public function search(string $term, ?int $limit = null, ?int $cursor = null): DataResponse {
$cards = $this->searchService->searchCards($term, $limit, $cursor); $cards = $this->searchService->searchCards($term, $limit, $cursor);
return new DataResponse(array_map(function (Card $card) { return new DataResponse(array_map(function (Card $card) {

View File

@@ -7,14 +7,16 @@
namespace OCA\Deck\Controller; namespace OCA\Deck\Controller;
use OCA\Deck\Service\BoardService;
use OCA\Deck\Service\StackService; use OCA\Deck\Service\StackService;
use OCA\Deck\StatusException; use OCA\Deck\StatusException;
use OCP\AppFramework\ApiController; use OCP\AppFramework\ApiController;
use OCP\AppFramework\Http; use OCP\AppFramework\Http;
use OCP\AppFramework\Http\Attribute\CORS;
use OCP\AppFramework\Http\Attribute\NoAdminRequired;
use OCP\AppFramework\Http\Attribute\NoCSRFRequired;
use OCP\AppFramework\Http\DataResponse; use OCP\AppFramework\Http\DataResponse;
use OCP\IRequest; use OCP\IRequest;
use Sabre\HTTP\Util; use function Sabre\HTTP\parseDate;
/** /**
* Class StackApiController * Class StackApiController
@@ -29,23 +31,21 @@ class StackApiController extends ApiController {
$appName, $appName,
IRequest $request, IRequest $request,
private StackService $stackService, private StackService $stackService,
private BoardService $boardService,
) { ) {
parent::__construct($appName, $request); parent::__construct($appName, $request);
} }
/** /**
* @NoAdminRequired * Return all the stacks in the specified board.
* @CORS
* @NoCSRFRequired
*
* Return all of the stacks in the specified board.
*/ */
public function index() { #[NoAdminRequired]
#[CORS]
#[NoCSRFRequired]
public function index(): DataResponse {
$since = 0; $since = 0;
$modified = $this->request->getHeader('If-Modified-Since'); $modified = $this->request->getHeader('If-Modified-Since');
if ($modified !== null && $modified !== '') { if ($modified !== '') {
$date = Util::parseHTTPDate($modified); $date = parseDate($modified);
if (!$date) { if (!$date) {
throw new StatusException('Invalid If-Modified-Since header provided.'); throw new StatusException('Invalid If-Modified-Since header provided.');
} }
@@ -56,13 +56,12 @@ class StackApiController extends ApiController {
} }
/** /**
* @NoAdminRequired * Return all the stacks in the specified board.
* @CORS
* @NoCSRFRequired
*
* Return all of the stacks in the specified board.
*/ */
public function get() { #[NoAdminRequired]
#[CORS]
#[NoCSRFRequired]
public function get(): DataResponse {
$stack = $this->stackService->find($this->request->getParam('stackId')); $stack = $this->stackService->find($this->request->getParam('stackId'));
$response = new DataResponse($stack, HTTP::STATUS_OK); $response = new DataResponse($stack, HTTP::STATUS_OK);
$response->setETag($stack->getETag()); $response->setETag($stack->getETag());
@@ -70,55 +69,45 @@ class StackApiController extends ApiController {
} }
/** /**
* @NoAdminRequired
* @CORS
* @NoCSRFRequired
*
* @params $title
* @params $order
*
* Create a stack with the specified title and order. * Create a stack with the specified title and order.
*/ */
public function create($title, $order) { #[NoAdminRequired]
#[CORS]
#[NoCSRFRequired]
public function create(string $title, int $order): DataResponse {
$stack = $this->stackService->create($title, $this->request->getParam('boardId'), $order); $stack = $this->stackService->create($title, $this->request->getParam('boardId'), $order);
return new DataResponse($stack, HTTP::STATUS_OK); return new DataResponse($stack, HTTP::STATUS_OK);
} }
/** /**
* @NoAdminRequired
* @CORS
* @NoCSRFRequired
*
* @params $title
* @params $order
*
* Update a stack by the specified stackId and boardId with the values that were put. * Update a stack by the specified stackId and boardId with the values that were put.
*/ */
public function update($title, $order) { #[NoAdminRequired]
#[CORS]
#[NoCSRFRequired]
public function update(string $title, int $order) {
$stack = $this->stackService->update($this->request->getParam('stackId'), $title, $this->request->getParam('boardId'), $order, 0); $stack = $this->stackService->update($this->request->getParam('stackId'), $title, $this->request->getParam('boardId'), $order, 0);
return new DataResponse($stack, HTTP::STATUS_OK); return new DataResponse($stack, HTTP::STATUS_OK);
} }
/** /**
* @NoAdminRequired
* @CORS
* @NoCSRFRequired
*
* Delete the stack specified by $this->request->getParam('stackId'). * Delete the stack specified by $this->request->getParam('stackId').
*/ */
public function delete() { #[NoAdminRequired]
#[CORS]
#[NoCSRFRequired]
public function delete(): DataResponse {
$stack = $this->stackService->delete($this->request->getParam('stackId')); $stack = $this->stackService->delete($this->request->getParam('stackId'));
return new DataResponse($stack, HTTP::STATUS_OK); return new DataResponse($stack, HTTP::STATUS_OK);
} }
/** /**
* @NoAdminRequired * Get the stacks that have been archived.
* @CORS
* @NoCSRFRequired
*
* get the stacks that have been archived.
*/ */
public function getArchived() { #[NoAdminRequired]
#[CORS]
#[NoCSRFRequired]
public function getArchived(): DataResponse {
$stacks = $this->stackService->findAllArchived($this->request->getParam('boardId')); $stacks = $this->stackService->findAllArchived($this->request->getParam('boardId'));
return new DataResponse($stacks, HTTP::STATUS_OK); return new DataResponse($stacks, HTTP::STATUS_OK);
} }

View File

@@ -7,10 +7,12 @@
namespace OCA\Deck\Controller; namespace OCA\Deck\Controller;
use OCA\Deck\Db\Stack;
use OCA\Deck\Service\StackService; use OCA\Deck\Service\StackService;
use OCP\AppFramework\Controller; use OCP\AppFramework\Controller;
use OCP\AppFramework\Http\Attribute\NoAdminRequired;
use OCP\IRequest; use OCP\IRequest;
class StackController extends Controller { class StackController extends Controller {
@@ -18,78 +20,54 @@ class StackController extends Controller {
string $appName, string $appName,
IRequest $request, IRequest $request,
private StackService $stackService, private StackService $stackService,
private $userId,
) { ) {
parent::__construct($appName, $request); parent::__construct($appName, $request);
} }
/** /**
* @NoAdminRequired * @return Stack[]
* @param $boardId
* @return array
*/ */
public function index($boardId) { #[NoAdminRequired]
public function index(int $boardId): array {
return $this->stackService->findAll($boardId); return $this->stackService->findAll($boardId);
} }
/** /**
* @NoAdminRequired * @return Stack[]
* @param $boardId
* @return array
*/ */
public function archived($boardId) { #[NoAdminRequired]
public function archived(int $boardId): array {
return $this->stackService->findAllArchived($boardId); return $this->stackService->findAllArchived($boardId);
} }
/** #[NoAdminRequired]
* @NoAdminRequired public function create(string $title, int $boardId, int $order = 999): Stack {
* @param $title
* @param $boardId
* @param int $order
* @return \OCP\AppFramework\Db\Entity
*/
public function create($title, $boardId, $order = 999) {
return $this->stackService->create($title, $boardId, $order); return $this->stackService->create($title, $boardId, $order);
} }
/** #[NoAdminRequired]
* @NoAdminRequired public function update(int $id, string $title, int $boardId, int $order, ?int $deletedAt = null): Stack {
* @param $id
* @param $title
* @param $boardId
* @param $order
* @param $deletedAt
* @return \OCP\AppFramework\Db\Entity
*/
public function update($id, $title, $boardId, $order, $deletedAt) {
return $this->stackService->update($id, $title, $boardId, $order, $deletedAt); return $this->stackService->update($id, $title, $boardId, $order, $deletedAt);
} }
/** /**
* @NoAdminRequired * @return array<int, Stack>
* @param $stackId
* @param $order
* @return array
*/ */
public function reorder($stackId, $order) { #[NoAdminRequired]
return $this->stackService->reorder((int)$stackId, (int)$order); public function reorder(int $stackId, int $order): array {
return $this->stackService->reorder($stackId, $order);
} }
/** #[NoAdminRequired]
* @NoAdminRequired public function delete(int $stackId): Stack {
* @param $stackId
* @return \OCP\AppFramework\Db\Entity
*/
public function delete($stackId) {
return $this->stackService->delete($stackId); return $this->stackService->delete($stackId);
} }
/** /**
* @NoAdminRequired * @return Stack[]
* @param $boardId
* @return \OCP\AppFramework\Db\Entity
*/ */
public function deleted($boardId) { #[NoAdminRequired]
public function deleted(int $boardId): array {
return $this->stackService->fetchDeleted($boardId); return $this->stackService->fetchDeleted($boardId);
} }
} }

View File

@@ -7,6 +7,20 @@
namespace OCA\Deck\Db; namespace OCA\Deck\Db;
/**
* @method int getBoardId()
* @method bool isPermissionEdit()
* @method void setPermissionEdit(bool $permissionEdit)
* @method bool isPermissionShare()
* @method void setPermissionShare(bool $permissionShare)
* @method bool isPermissionManage()
* @method void setPermissionManage(bool $permissionManage)
* @method int getType()
* @method void setType(int $type)
* @method bool isOwner()
* @method void setOwner(int $owner)
*
*/
class Acl extends RelationalEntity { class Acl extends RelationalEntity {
public const PERMISSION_READ = 0; public const PERMISSION_READ = 0;
public const PERMISSION_EDIT = 1; public const PERMISSION_EDIT = 1;
@@ -37,17 +51,13 @@ class Acl extends RelationalEntity {
$this->addResolvable('participant'); $this->addResolvable('participant');
} }
public function getPermission($permission) { public function getPermission(int $permission): bool {
switch ($permission) { return match ($permission) {
case self::PERMISSION_READ: self::PERMISSION_READ => true,
return true; self::PERMISSION_EDIT => $this->getPermissionEdit(),
case self::PERMISSION_EDIT: self::PERMISSION_SHARE => $this->getPermissionShare(),
return $this->getPermissionEdit(); self::PERMISSION_MANAGE => $this->getPermissionManage(),
case self::PERMISSION_SHARE: default => false,
return $this->getPermissionShare(); };
case self::PERMISSION_MANAGE:
return $this->getPermissionManage();
}
return false;
} }
} }

View File

@@ -19,13 +19,10 @@ class AclMapper extends DeckMapper implements IPermissionMapper {
} }
/** /**
* @param numeric $boardId
* @param int|null $limit
* @param int|null $offset
* @return Acl[] * @return Acl[]
* @throws \OCP\DB\Exception * @throws \OCP\DB\Exception
*/ */
public function findAll($boardId, $limit = null, $offset = null) { public function findAll(int $boardId, ?int $limit = null, ?int $offset = null) {
$qb = $this->db->getQueryBuilder(); $qb = $this->db->getQueryBuilder();
$qb->select('id', 'board_id', 'type', 'participant', 'permission_edit', 'permission_share', 'permission_manage') $qb->select('id', 'board_id', 'type', 'participant', 'permission_edit', 'permission_share', 'permission_manage')
->from('deck_board_acl') ->from('deck_board_acl')
@@ -51,12 +48,9 @@ class AclMapper extends DeckMapper implements IPermissionMapper {
} }
/** /**
* @param numeric $userId
* @param numeric $id
* @return bool
* @throws \OCP\DB\Exception * @throws \OCP\DB\Exception
*/ */
public function isOwner($userId, $id): bool { public function isOwner(string $userId, int $id): bool {
$aclId = $id; $aclId = $id;
$qb = $this->db->getQueryBuilder(); $qb = $this->db->getQueryBuilder();
$qb->select('acl.id') $qb->select('acl.id')
@@ -68,11 +62,7 @@ class AclMapper extends DeckMapper implements IPermissionMapper {
return count($qb->executeQuery()->fetchAll()) > 0; return count($qb->executeQuery()->fetchAll()) > 0;
} }
/** public function findBoardId(int $id): ?int {
* @param numeric $id
* @return int|null
*/
public function findBoardId($id): ?int {
try { try {
$entity = $this->find($id); $entity = $this->find($id);
return $entity->getBoardId(); return $entity->getBoardId();
@@ -87,7 +77,7 @@ class AclMapper extends DeckMapper implements IPermissionMapper {
* @return Acl[] * @return Acl[]
* @throws \OCP\DB\Exception * @throws \OCP\DB\Exception
*/ */
public function findByParticipant($type, $participant): array { public function findByParticipant(int $type, string $participant): array {
$qb = $this->db->getQueryBuilder(); $qb = $this->db->getQueryBuilder();
$qb->select('*') $qb->select('*')

View File

@@ -107,11 +107,11 @@ class AssignmentMapper extends DeckMapper implements IPermissionMapper {
} }
public function isOwner($userId, $id): bool { public function isOwner(string $userId, int $id): bool {
return $this->cardMapper->isOwner($userId, $id); return $this->cardMapper->isOwner($userId, $id);
} }
public function findBoardId($id): ?int { public function findBoardId(int $id): ?int {
return $this->cardMapper->findBoardId($id); return $this->cardMapper->findBoardId($id);
} }
@@ -123,6 +123,9 @@ class AssignmentMapper extends DeckMapper implements IPermissionMapper {
* @throws NotFoundException * @throws NotFoundException
*/ */
public function insert(Entity $entity): Entity { public function insert(Entity $entity): Entity {
if (!($entity instanceof Assignment)) {
throw new \LogicException('Trying to insert a ' . get_class($entity) . ' in the assignment mapper');
}
$origin = $this->getOrigin($entity); $origin = $this->getOrigin($entity);
if ($origin === null) { if ($origin === null) {
throw new NotFoundException('No origin found for assignment'); throw new NotFoundException('No origin found for assignment');
@@ -141,7 +144,7 @@ class AssignmentMapper extends DeckMapper implements IPermissionMapper {
}); });
} }
public function isUserAssigned($cardId, $userId): bool { public function isUserAssigned(int $cardId, string $userId): bool {
$assignments = $this->findAll($cardId); $assignments = $this->findAll($cardId);
foreach ($assignments as $assignment) { foreach ($assignments as $assignment) {
$origin = $this->getOrigin($assignment); $origin = $this->getOrigin($assignment);

View File

@@ -36,13 +36,11 @@ class AttachmentMapper extends DeckMapper implements IPermissionMapper {
} }
/** /**
* @param int $id
* @return Attachment
* @throws DoesNotExistException * @throws DoesNotExistException
* @throws MultipleObjectsReturnedException * @throws MultipleObjectsReturnedException
* @throws \OCP\DB\Exception * @throws \OCP\DB\Exception
*/ */
public function find($id) { public function find(int $id): Attachment {
$qb = $this->db->getQueryBuilder(); $qb = $this->db->getQueryBuilder();
$qb->select('*') $qb->select('*')
->from($this->getTableName()) ->from($this->getTableName())
@@ -52,14 +50,11 @@ class AttachmentMapper extends DeckMapper implements IPermissionMapper {
} }
/** /**
* @param int $cardId
* @param string $data
* @return Attachment
* @throws DoesNotExistException * @throws DoesNotExistException
* @throws MultipleObjectsReturnedException * @throws MultipleObjectsReturnedException
* @throws \OCP\DB\Exception * @throws \OCP\DB\Exception
*/ */
public function findByData($cardId, $data) { public function findByData(int $cardId, string $data): Attachment {
$qb = $this->db->getQueryBuilder(); $qb = $this->db->getQueryBuilder();
$qb->select('*') $qb->select('*')
->from($this->getTableName()) ->from($this->getTableName())
@@ -70,11 +65,10 @@ class AttachmentMapper extends DeckMapper implements IPermissionMapper {
} }
/** /**
* @param $cardId
* @return Entity[] * @return Entity[]
* @throws \OCP\DB\Exception * @throws \OCP\DB\Exception
*/ */
public function findAll($cardId) { public function findAll(int $cardId): array {
$qb = $this->db->getQueryBuilder(); $qb = $this->db->getQueryBuilder();
$qb->select('*') $qb->select('*')
->from($this->getTableName()) ->from($this->getTableName())
@@ -86,11 +80,9 @@ class AttachmentMapper extends DeckMapper implements IPermissionMapper {
} }
/** /**
* @param null $cardId * @return Attachment[]
* @param bool $withOffset
* @return array
*/ */
public function findToDelete($cardId = null, $withOffset = true) { public function findToDelete(?int $cardId = null, bool $withOffset = true): array {
// add buffer of 5 min // add buffer of 5 min
$timeLimit = time() - (60 * 5); $timeLimit = time() - (60 * 5);
$qb = $this->db->getQueryBuilder(); $qb = $this->db->getQueryBuilder();
@@ -112,12 +104,8 @@ class AttachmentMapper extends DeckMapper implements IPermissionMapper {
/** /**
* Check if $userId is owner of Entity with $id * Check if $userId is owner of Entity with $id
*
* @param $userId string userId
* @param $id int|string unique entity identifier
* @return boolean
*/ */
public function isOwner($userId, $id): bool { public function isOwner(string $userId, int $id): bool {
try { try {
$attachment = $this->find($id); $attachment = $this->find($id);
return $this->cardMapper->isOwner($userId, $attachment->getCardId()); return $this->cardMapper->isOwner($userId, $attachment->getCardId());
@@ -130,10 +118,10 @@ class AttachmentMapper extends DeckMapper implements IPermissionMapper {
/** /**
* Query boardId for Entity of given $id * Query boardId for Entity of given $id
* *
* @param $id int|string unique entity identifier * @param $id int unique entity identifier
* @return int|null id of Board * @return int|null id of Board
*/ */
public function findBoardId($id): ?int { public function findBoardId(int $id): ?int {
try { try {
$attachment = $this->find($id); $attachment = $this->find($id);
} catch (\Exception $e) { } catch (\Exception $e) {

View File

@@ -10,10 +10,20 @@ namespace OCA\Deck\Db;
/** /**
* @method int getId() * @method int getId()
* @method string getTitle() * @method string getTitle()
* @method void setTitle(string $title)
* @method int getShared() * @method int getShared()
* @method void setShared(int $shared)
* @method bool isArchived()
* @method bool getArchived() * @method bool getArchived()
* @method void setArchived(bool $archived)
* @method int getDeletedAt() * @method int getDeletedAt()
* @method void setDeletedAt(int $deletedAt)
* @method int getLastModified() * @method int getLastModified()
* @method void setLastModified(int $lastModified)
* @method string getOwner()
* @method void setOwner(string $owner)
* @method string getColor()
* @method void setColor(string $color)
*/ */
class Board extends RelationalEntity { class Board extends RelationalEntity {
protected $title; protected $title;

View File

@@ -469,16 +469,16 @@ class BoardMapper extends QBMapper implements IPermissionMapper {
return parent::delete($entity); return parent::delete($entity);
} }
public function isOwner($userId, $id): bool { public function isOwner(string $userId, int $id): bool {
$board = $this->find($id); $board = $this->find($id);
return ($board->getOwner() === $userId); return ($board->getOwner() === $userId);
} }
public function findBoardId($id): ?int { public function findBoardId(int $id): ?int {
return $id; return $id;
} }
public function mapAcl(Acl &$acl) { public function mapAcl(Acl &$acl): void {
$acl->resolveRelation('participant', function ($participant) use (&$acl) { $acl->resolveRelation('participant', function ($participant) use (&$acl) {
if ($acl->getType() === Acl::PERMISSION_TYPE_USER) { if ($acl->getType() === Acl::PERMISSION_TYPE_USER) {
if ($this->userManager->userExists($acl->getParticipant())) { if ($this->userManager->userExists($acl->getParticipant())) {

View File

@@ -15,13 +15,18 @@ use Sabre\VObject\Component\VCalendar;
/** /**
* @method string getTitle() * @method string getTitle()
* @method void setTitle(string $title)
* @method string getDescription() * @method string getDescription()
* @method string getDescriptionPrev() * @method string getDescriptionPrev()
* @method int getStackId() * @method int getStackId()
* @method void setStackId(int $stackId)
* @method int getOrder() * @method int getOrder()
* @method void setOrder(int $order)
* @method int getLastModified() * @method int getLastModified()
* @method int getCreatedAt() * @method int getCreatedAt()
* @method bool getArchived() * @method bool getArchived()
* @method string getType()
* @method void setType(string $type)
* @method int getDeletedAt() * @method int getDeletedAt()
* @method void setDeletedAt(int $deletedAt) * @method void setDeletedAt(int $deletedAt)
* @method bool getNotified() * @method bool getNotified()
@@ -68,8 +73,8 @@ class Card extends RelationalEntity {
protected $createdAt; protected $createdAt;
protected $labels; protected $labels;
protected $assignedUsers; protected $assignedUsers;
protected $attachments; protected array $attachments = [];
protected $attachmentCount; protected int $attachmentCount = 0;
protected $owner; protected $owner;
protected $order; protected $order;
protected $archived = false; protected $archived = false;

View File

@@ -86,16 +86,15 @@ class CardMapper extends QBMapper implements IPermissionMapper {
$updatedFields = $entity->getUpdatedFields(); $updatedFields = $entity->getUpdatedFields();
if (isset($updatedFields['duedate']) && $updatedFields['duedate']) { if (isset($updatedFields['duedate']) && $updatedFields['duedate']) {
try { try {
/** @var Card $existing */
$existing = $this->find($entity->getId()); $existing = $this->find($entity->getId());
if ($existing && $entity->getDuedate() !== $existing->getDuedate()) { if ($entity->getDueDate() !== $existing->getDueDate()) {
$entity->setNotified(false); $entity->setNotified(false);
} }
// remove pending notifications // remove pending notifications
$notification = $this->notificationManager->createNotification(); $notification = $this->notificationManager->createNotification();
$notification $notification
->setApp('deck') ->setApp('deck')
->setObject('card', $entity->getId()); ->setObject('card', (string)$entity->getId());
$this->notificationManager->markProcessed($notification); $this->notificationManager->markProcessed($notification);
} catch (Exception $e) { } catch (Exception $e) {
} }
@@ -135,7 +134,7 @@ class CardMapper extends QBMapper implements IPermissionMapper {
* @return Card[] * @return Card[]
* @throws \OCP\DB\Exception * @throws \OCP\DB\Exception
*/ */
public function findAll($stackId, ?int $limit = null, ?int $offset = null, int $since = -1) { public function findAll($stackId, ?int $limit = null, int $offset = 0, int $since = -1) {
$qb = $this->db->getQueryBuilder(); $qb = $this->db->getQueryBuilder();
$qb->select('*') $qb->select('*')
->from('deck_cards') ->from('deck_cards')
@@ -155,7 +154,7 @@ class CardMapper extends QBMapper implements IPermissionMapper {
* @return array<int, null|Card[]> * @return array<int, null|Card[]>
* @throws \OCP\DB\Exception * @throws \OCP\DB\Exception
*/ */
public function findAllForStacks(array $stackIds, ?int $limit = null, ?int $offset = null, int $since = -1): array { public function findAllForStacks(array $stackIds, ?int $limit = null, int $offset = 0, int $since = -1): array {
$qb = $this->db->getQueryBuilder(); $qb = $this->db->getQueryBuilder();
$qb->select('*') $qb->select('*')
->from('deck_cards') ->from('deck_cards')
@@ -194,7 +193,10 @@ class CardMapper extends QBMapper implements IPermissionMapper {
return $qb; return $qb;
} }
public function findToDelete($timeLimit, $limit = null) { /**
* @return Card[]
*/
public function findToDelete(int $timeLimit, ?int $limit = null): array {
$qb = $this->db->getQueryBuilder(); $qb = $this->db->getQueryBuilder();
$qb->select('id', 'title', 'owner', 'archived', 'deleted_at', 'last_modified') $qb->select('id', 'title', 'owner', 'archived', 'deleted_at', 'last_modified')
->from('deck_cards') ->from('deck_cards')
@@ -205,7 +207,10 @@ class CardMapper extends QBMapper implements IPermissionMapper {
return $this->findEntities($qb); return $this->findEntities($qb);
} }
public function findDeleted($boardId, $limit = null, $offset = null) { /**
* @return Card[]
*/
public function findDeleted(int $boardId, ?int $limit = null, int $offset = 0): array {
$qb = $this->queryCardsByBoard($boardId); $qb = $this->queryCardsByBoard($boardId);
$qb->andWhere($qb->expr()->neq('c.deleted_at', $qb->createNamedParameter(0, IQueryBuilder::PARAM_INT))) $qb->andWhere($qb->expr()->neq('c.deleted_at', $qb->createNamedParameter(0, IQueryBuilder::PARAM_INT)))
->setMaxResults($limit) ->setMaxResults($limit)
@@ -215,7 +220,10 @@ class CardMapper extends QBMapper implements IPermissionMapper {
return $this->findEntities($qb); return $this->findEntities($qb);
} }
public function findCalendarEntries($boardId, $limit = null, $offset = null) { /**
* @return Card[]
*/
public function findCalendarEntries(int $boardId, ?int $limit = null, $offset = 0): array {
$qb = $this->db->getQueryBuilder(); $qb = $this->db->getQueryBuilder();
$qb->select('c.*') $qb->select('c.*')
->from('deck_cards', 'c') ->from('deck_cards', 'c')
@@ -270,7 +278,11 @@ class CardMapper extends QBMapper implements IPermissionMapper {
return $this->findEntities($qb); return $this->findEntities($qb);
} }
public function findAllWithDue(array $boardIds) { /**
* @param int[] $boardIds
* @return Card[]
*/
public function findAllWithDue(array $boardIds): array {
$qb = $this->db->getQueryBuilder(); $qb = $this->db->getQueryBuilder();
$qb->select('c.*') $qb->select('c.*')
->from('deck_cards', 'c') ->from('deck_cards', 'c')
@@ -287,7 +299,11 @@ class CardMapper extends QBMapper implements IPermissionMapper {
return $this->findEntities($qb); return $this->findEntities($qb);
} }
public function findToMeOrNotAssignedCards(array $boardIds, string $username) { /**
* @param int[] $boardIds
* @return Card[]
*/
public function findToMeOrNotAssignedCards(array $boardIds, string $username): array {
$qb = $this->db->getQueryBuilder(); $qb = $this->db->getQueryBuilder();
$qb->select('c.*') $qb->select('c.*')
->from('deck_cards', 'c') ->from('deck_cards', 'c')
@@ -309,7 +325,10 @@ class CardMapper extends QBMapper implements IPermissionMapper {
return $this->findEntities($qb); return $this->findEntities($qb);
} }
public function findOverdue() { /**
* @return Card[]
*/
public function findOverdue(): array {
$qb = $this->db->getQueryBuilder(); $qb = $this->db->getQueryBuilder();
$qb->select('id', 'title', 'duedate', 'notified') $qb->select('id', 'title', 'duedate', 'notified')
->from('deck_cards') ->from('deck_cards')
@@ -321,6 +340,9 @@ class CardMapper extends QBMapper implements IPermissionMapper {
return $this->findEntities($qb); return $this->findEntities($qb);
} }
/**
* @return Card[]
*/
public function findUnexposedDescriptionChances() { public function findUnexposedDescriptionChances() {
$qb = $this->db->getQueryBuilder(); $qb = $this->db->getQueryBuilder();
$qb->select('id', 'title', 'duedate', 'notified', 'description_prev', 'last_editor', 'description') $qb->select('id', 'title', 'duedate', 'notified', 'description_prev', 'last_editor', 'description')
@@ -329,6 +351,9 @@ class CardMapper extends QBMapper implements IPermissionMapper {
return $this->findEntities($qb); return $this->findEntities($qb);
} }
/**
* @return Card[]
*/
public function search(array $boardIds, SearchQuery $query, ?int $limit = null, ?int $offset = null): array { public function search(array $boardIds, SearchQuery $query, ?int $limit = null, ?int $offset = null): array {
$qb = $this->queryCardsByBoards($boardIds); $qb = $this->queryCardsByBoards($boardIds);
$this->extendQueryByFilter($qb, $query); $this->extendQueryByFilter($qb, $query);
@@ -363,7 +388,7 @@ class CardMapper extends QBMapper implements IPermissionMapper {
$qb->andWhere($qb->expr()->lt('c.last_modified', $qb->createNamedParameter($offset, IQueryBuilder::PARAM_INT))); $qb->andWhere($qb->expr()->lt('c.last_modified', $qb->createNamedParameter($offset, IQueryBuilder::PARAM_INT)));
} }
$result = $qb->execute(); $result = $qb->executeQuery();
$entities = []; $entities = [];
while ($row = $result->fetch()) { while ($row = $result->fetch()) {
$entities[] = Card::fromRow($row); $entities[] = Card::fromRow($row);
@@ -406,7 +431,7 @@ class CardMapper extends QBMapper implements IPermissionMapper {
$qb->andWhere($qb->expr()->lt('comments.id', $qb->createNamedParameter($offset, IQueryBuilder::PARAM_INT))); $qb->andWhere($qb->expr()->lt('comments.id', $qb->createNamedParameter($offset, IQueryBuilder::PARAM_INT)));
} }
$result = $qb->execute(); $result = $qb->executeQuery();
$entities = $result->fetchAll(); $entities = $result->fetchAll();
$result->closeCursor(); $result->closeCursor();
return $entities; return $entities;
@@ -502,7 +527,7 @@ class CardMapper extends QBMapper implements IPermissionMapper {
}); });
$groups = $this->groupManager->search($assignment->getValue()); $groups = $this->groupManager->search($assignment->getValue());
foreach ($searchUsers as $user) { foreach ($searchUsers as $user) {
$groups = array_merge($groups, $this->groupManager->getUserIdGroups($user->getUID())); $groups = array_merge($groups, $this->groupManager->getUserGroups($user));
} }
$assignmentSearches = []; $assignmentSearches = [];
@@ -555,7 +580,7 @@ class CardMapper extends QBMapper implements IPermissionMapper {
if ($offset !== null) { if ($offset !== null) {
$qb->setFirstResult($offset); $qb->setFirstResult($offset);
} }
$result = $qb->execute(); $result = $qb->executeQuery();
$all = $result->fetchAll(); $all = $result->fetchAll();
$result->closeCursor(); $result->closeCursor();
return $all; return $all;
@@ -567,32 +592,32 @@ class CardMapper extends QBMapper implements IPermissionMapper {
return parent::delete($entity); return parent::delete($entity);
} }
public function deleteByStack($stackId) { public function deleteByStack($stackId): void {
$cards = $this->findAllByStack($stackId); $cards = $this->findAllByStack($stackId);
foreach ($cards as $card) { foreach ($cards as $card) {
$this->delete($card); $this->delete($card);
} }
} }
public function assignLabel($card, $label) { public function assignLabel(int $card, int $label): void {
$qb = $this->db->getQueryBuilder(); $qb = $this->db->getQueryBuilder();
$qb->insert('deck_assigned_labels') $qb->insert('deck_assigned_labels')
->values([ ->values([
'label_id' => $qb->createNamedParameter($label, IQueryBuilder::PARAM_INT), 'label_id' => $qb->createNamedParameter($label, IQueryBuilder::PARAM_INT),
'card_id' => $qb->createNamedParameter($card, IQueryBuilder::PARAM_INT), 'card_id' => $qb->createNamedParameter($card, IQueryBuilder::PARAM_INT),
]); ]);
$qb->execute(); $qb->executeStatement();
} }
public function removeLabel($card, $label) { public function removeLabel(int $card, int $label): void {
$qb = $this->db->getQueryBuilder(); $qb = $this->db->getQueryBuilder();
$qb->delete('deck_assigned_labels') $qb->delete('deck_assigned_labels')
->where($qb->expr()->eq('card_id', $qb->createNamedParameter($card, IQueryBuilder::PARAM_INT))) ->where($qb->expr()->eq('card_id', $qb->createNamedParameter($card, IQueryBuilder::PARAM_INT)))
->andWhere($qb->expr()->eq('label_id', $qb->createNamedParameter($label, IQueryBuilder::PARAM_INT))); ->andWhere($qb->expr()->eq('label_id', $qb->createNamedParameter($label, IQueryBuilder::PARAM_INT)));
$qb->execute(); $qb->executeStatement();
} }
public function isOwner($userId, $id): bool { public function isOwner(string $userId, int $id): bool {
$qb = $this->db->getQueryBuilder(); $qb = $this->db->getQueryBuilder();
$qb->select('c.id') $qb->select('c.id')
->from($this->getTableName(), 'c') ->from($this->getTableName(), 'c')
@@ -604,7 +629,7 @@ class CardMapper extends QBMapper implements IPermissionMapper {
return count($qb->executeQuery()->fetchAll()) > 0; return count($qb->executeQuery()->fetchAll()) > 0;
} }
public function findBoardId($id): ?int { public function findBoardId(int $id): ?int {
$result = $this->cache->get('findBoardId:' . $id); $result = $this->cache->get('findBoardId:' . $id);
if ($result === null) { if ($result === null) {
try { try {
@@ -634,13 +659,11 @@ class CardMapper extends QBMapper implements IPermissionMapper {
} }
public function transferOwnership(string $ownerId, string $newOwnerId, ?int $boardId = null): void { public function transferOwnership(string $ownerId, string $newOwnerId, ?int $boardId = null): void {
$params = [ $qb = $this->db->getQueryBuilder();
'owner' => $ownerId, $qb->update($this->getTableName())
'newOwner' => $newOwnerId ->set('owner', $qb->createNamedParameter($newOwnerId, IQueryBuilder::PARAM_STR))
]; ->where('owner', $qb->createNamedParameter($ownerId, IQueryBuilder::PARAM_STR))
$sql = "UPDATE `*PREFIX*{$this->tableName}` SET `owner` = :newOwner WHERE `owner` = :owner"; ->executeStatement();
$stmt = $this->db->executeQuery($sql, $params);
$stmt->closeCursor();
} }
public function remapCardOwner(int $boardId, string $userId, string $newUserId): void { public function remapCardOwner(int $boardId, string $userId, string $newUserId): void {

View File

@@ -19,12 +19,11 @@ use OCP\DB\QueryBuilder\IQueryBuilder;
abstract class DeckMapper extends QBMapper { abstract class DeckMapper extends QBMapper {
/** /**
* @param $id
* @return T * @return T
* @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException
* @throws \OCP\AppFramework\Db\DoesNotExistException * @throws \OCP\AppFramework\Db\DoesNotExistException
*/ */
public function find($id) { public function find(int $id): Entity {
$qb = $this->db->getQueryBuilder(); $qb = $this->db->getQueryBuilder();
$qb->select('*') $qb->select('*')
->from($this->getTableName()) ->from($this->getTableName())
@@ -37,7 +36,7 @@ abstract class DeckMapper extends QBMapper {
* Helper function to split passed array into chunks of 1000 elements and * Helper function to split passed array into chunks of 1000 elements and
* call a given callback for fetching query results * call a given callback for fetching query results
* *
* Can be useful to limit to 1000 results per query for oracle compatiblity * Can be useful to limit to 1000 results per query for oracle compatibility
* but still iterate over all results * but still iterate over all results
*/ */
public function chunkQuery(array $ids, callable $callback): Generator { public function chunkQuery(array $ids, callable $callback): Generator {

View File

@@ -8,22 +8,25 @@
namespace OCA\Deck\Db; namespace OCA\Deck\Db;
/**
*
*/
interface IPermissionMapper { interface IPermissionMapper {
/** /**
* Check if $userId is owner of Entity with $id * Check if $userId is owner of Entity with $id
* *
* @param $userId string userId * @param $userId string userId
* @param $id int|string unique entity identifier * @param $id int unique entity identifier
* @return boolean * @return boolean
*/ */
public function isOwner($userId, $id): bool; public function isOwner(string $userId, int $id): bool;
/** /**
* Query boardId for Entity of given $id * Query boardId for Entity of given $id
* *
* @param $id int|string unique entity identifier * @param $id int unique entity identifier
* @return int|null id of Board * @return ?int id of Board
*/ */
public function findBoardId($id): ?int; public function findBoardId(int $id): ?int;
} }

View File

@@ -8,7 +8,16 @@
namespace OCA\Deck\Db; namespace OCA\Deck\Db;
/** /**
* @method getTitle(): string * @method string getTitle()
* @method void setTitle(string $title)
* @method string getColor()
* @method void setColor(string $color)
* @method int getBoardId()
* @method void setBoardId(int $boardId)
* @method int getCardId()
* @method void setCardId(int $cardId)
* @method int getLastModified()
* @method void setLastModified(int $lastModified)
*/ */
class Label extends RelationalEntity { class Label extends RelationalEntity {
protected $title; protected $title;
@@ -24,7 +33,7 @@ class Label extends RelationalEntity {
$this->addType('lastModified', 'integer'); $this->addType('lastModified', 'integer');
} }
public function getETag() { public function getETag(): string {
return md5((string)$this->getLastModified()); return md5((string)$this->getLastModified());
} }
} }

View File

@@ -20,13 +20,10 @@ class LabelMapper extends DeckMapper implements IPermissionMapper {
} }
/** /**
* @param numeric $boardId
* @param int|null $limit
* @param int|null $offset
* @return Label[] * @return Label[]
* @throws \OCP\DB\Exception * @throws \OCP\DB\Exception
*/ */
public function findAll($boardId, $limit = null, $offset = null): array { public function findAll(int $boardId, ?int $limit = null, int $offset = 0): array {
$qb = $this->db->getQueryBuilder(); $qb = $this->db->getQueryBuilder();
$qb->select('*') $qb->select('*')
->from($this->getTableName()) ->from($this->getTableName())
@@ -44,13 +41,10 @@ class LabelMapper extends DeckMapper implements IPermissionMapper {
} }
/** /**
* @param numeric $cardId
* @param int|null $limit
* @param int|null $offset
* @return Label[] * @return Label[]
* @throws \OCP\DB\Exception * @throws \OCP\DB\Exception
*/ */
public function findAssignedLabelsForCard($cardId, $limit = null, $offset = null): array { public function findAssignedLabelsForCard(int $cardId, ?int $limit = null, int $offset = 0): array {
$qb = $this->db->getQueryBuilder(); $qb = $this->db->getQueryBuilder();
$qb->select('l.*', 'card_id') $qb->select('l.*', 'card_id')
->from($this->getTableName(), 'l') ->from($this->getTableName(), 'l')
@@ -63,7 +57,7 @@ class LabelMapper extends DeckMapper implements IPermissionMapper {
return $this->findEntities($qb); return $this->findEntities($qb);
} }
public function findAssignedLabelsForCards($cardIds, $limit = null, $offset = null): array { public function findAssignedLabelsForCards(array $cardIds, ?int $limit = null, int $offset = 0): array {
$qb = $this->db->getQueryBuilder(); $qb = $this->db->getQueryBuilder();
$qb->select('l.*', 'card_id') $qb->select('l.*', 'card_id')
->from($this->getTableName(), 'l') ->from($this->getTableName(), 'l')
@@ -77,13 +71,10 @@ class LabelMapper extends DeckMapper implements IPermissionMapper {
} }
/** /**
* @param numeric $boardId
* @param int|null $limit
* @param int|null $offset
* @return Label[] * @return Label[]
* @throws \OCP\DB\Exception * @throws \OCP\DB\Exception
*/ */
public function findAssignedLabelsForBoard($boardId, $limit = null, $offset = null): array { public function findAssignedLabelsForBoard(int $boardId, ?int $limit = null, int $offset = 0): array {
$qb = $this->db->getQueryBuilder(); $qb = $this->db->getQueryBuilder();
$qb->select('l.id as id', 'l.title as title', 'l.color as color') $qb->select('l.id as id', 'l.title as title', 'l.color as color')
->selectAlias('c.id', 'card_id') ->selectAlias('c.id', 'card_id')
@@ -113,11 +104,10 @@ class LabelMapper extends DeckMapper implements IPermissionMapper {
} }
/** /**
* @param numeric $boardId * @return array<int, list<Label>>
* @return array
* @throws \OCP\DB\Exception * @throws \OCP\DB\Exception
*/ */
public function getAssignedLabelsForBoard($boardId) { public function getAssignedLabelsForBoard(int $boardId): array {
$labels = $this->findAssignedLabelsForBoard($boardId); $labels = $this->findAssignedLabelsForBoard($boardId);
$result = []; $result = [];
foreach ($labels as $label) { foreach ($labels as $label) {
@@ -130,11 +120,9 @@ class LabelMapper extends DeckMapper implements IPermissionMapper {
} }
/** /**
* @param numeric $labelId
* @return void
* @throws \OCP\DB\Exception * @throws \OCP\DB\Exception
*/ */
public function deleteLabelAssignments($labelId) { public function deleteLabelAssignments(int $labelId): void {
$qb = $this->db->getQueryBuilder(); $qb = $this->db->getQueryBuilder();
$qb->delete('deck_assigned_labels') $qb->delete('deck_assigned_labels')
->where($qb->expr()->eq('label_id', $qb->createNamedParameter($labelId, IQueryBuilder::PARAM_INT))); ->where($qb->expr()->eq('label_id', $qb->createNamedParameter($labelId, IQueryBuilder::PARAM_INT)));
@@ -142,11 +130,9 @@ class LabelMapper extends DeckMapper implements IPermissionMapper {
} }
/** /**
* @param numeric $cardId
* @return void
* @throws \OCP\DB\Exception * @throws \OCP\DB\Exception
*/ */
public function deleteLabelAssignmentsForCard($cardId) { public function deleteLabelAssignmentsForCard(int $cardId): void {
$qb = $this->db->getQueryBuilder(); $qb = $this->db->getQueryBuilder();
$qb->delete('deck_assigned_labels') $qb->delete('deck_assigned_labels')
->where($qb->expr()->eq('card_id', $qb->createNamedParameter($cardId, IQueryBuilder::PARAM_INT))); ->where($qb->expr()->eq('card_id', $qb->createNamedParameter($cardId, IQueryBuilder::PARAM_INT)));
@@ -154,33 +140,25 @@ class LabelMapper extends DeckMapper implements IPermissionMapper {
} }
/** /**
* @param string $userId
* @param numeric $labelId
* @return bool
* @throws \OCP\DB\Exception * @throws \OCP\DB\Exception
*/ */
public function isOwner($userId, $labelId): bool { public function isOwner(string $userId, int $id): bool {
$qb = $this->db->getQueryBuilder(); $qb = $this->db->getQueryBuilder();
$qb->select('l.id') $qb->select('l.id')
->from($this->getTableName(), 'l') ->from($this->getTableName(), 'l')
->innerJoin('l', 'deck_boards', 'b', 'l.board_id = b.id') ->innerJoin('l', 'deck_boards', 'b', 'l.board_id = b.id')
->where($qb->expr()->eq('l.id', $qb->createNamedParameter($labelId, IQueryBuilder::PARAM_INT))) ->where($qb->expr()->eq('l.id', $qb->createNamedParameter($id, IQueryBuilder::PARAM_INT)))
->andWhere($qb->expr()->eq('b.owner', $qb->createNamedParameter($userId, IQueryBuilder::PARAM_STR))); ->andWhere($qb->expr()->eq('b.owner', $qb->createNamedParameter($userId, IQueryBuilder::PARAM_STR)));
return count($qb->executeQuery()->fetchAll()) > 0; return count($qb->executeQuery()->fetchAll()) > 0;
} }
/** public function findBoardId(int $id): ?int {
* @param numeric $id
* @return int|null
*/
public function findBoardId($id): ?int {
try { try {
$entity = $this->find($id); $entity = $this->find($id);
return $entity->getBoardId(); return $entity->getBoardId();
} catch (DoesNotExistException $e) { } catch (DoesNotExistException|MultipleObjectsReturnedException) {
} catch (MultipleObjectsReturnedException $e) { return null;
} }
return null;
} }
} }

View File

@@ -11,10 +11,16 @@ use Sabre\VObject\Component\VCalendar;
/** /**
* @method int getId() * @method int getId()
* @method string getTitle()
* @method void setTitle(string $title)
* @method int getBoardId() * @method int getBoardId()
* @method void setBoardId(int $boardId)
* @method int getDeletedAt() * @method int getDeletedAt()
* @method void setDeletedAt(int $deletedAt)
* @method int getLastModified() * @method int getLastModified()
* @method int getOrder() * @method void setLastModified(int $lastModified)
* @method \int getOrder()
* @method void setOrder(int $order)
* @method Card[] getCards() * @method Card[] getCards()
*/ */
class Stack extends RelationalEntity { class Stack extends RelationalEntity {

View File

@@ -35,13 +35,11 @@ class StackMapper extends DeckMapper implements IPermissionMapper {
/** /**
* @param numeric $id
* @return Stack
* @throws DoesNotExistException * @throws DoesNotExistException
* @throws MultipleObjectsReturnedException * @throws MultipleObjectsReturnedException
* @throws \OCP\DB\Exception * @throws \OCP\DB\Exception
*/ */
public function find($id): Stack { public function find(int $id): Stack {
if (isset($this->stackCache[(string)$id])) { if (isset($this->stackCache[(string)$id])) {
return $this->stackCache[(string)$id]; return $this->stackCache[(string)$id];
} }
@@ -56,11 +54,9 @@ class StackMapper extends DeckMapper implements IPermissionMapper {
} }
/** /**
* @param $cardId
* @return Stack|null
* @throws \OCP\DB\Exception * @throws \OCP\DB\Exception
*/ */
public function findStackFromCardId($cardId): ?Stack { public function findStackFromCardId(int $cardId): ?Stack {
$qb = $this->db->getQueryBuilder(); $qb = $this->db->getQueryBuilder();
$qb->select('s.*') $qb->select('s.*')
->from($this->getTableName(), 's') ->from($this->getTableName(), 's')
@@ -76,11 +72,10 @@ class StackMapper extends DeckMapper implements IPermissionMapper {
} }
/** /**
* @param numeric $boardId
* @return Stack[] * @return Stack[]
* @throws \OCP\DB\Exception * @throws \OCP\DB\Exception
*/ */
public function findAll($boardId, ?int $limit = null, ?int $offset = null): array { public function findAll(int $boardId, ?int $limit = null, int $offset = 0): array {
$qb = $this->db->getQueryBuilder(); $qb = $this->db->getQueryBuilder();
$qb->select('*') $qb->select('*')
->from($this->getTableName()) ->from($this->getTableName())
@@ -93,13 +88,9 @@ class StackMapper extends DeckMapper implements IPermissionMapper {
} }
/** /**
* @param numeric $boardId
* @param int|null $limit
* @param int|null $offset
* @return Stack[]
* @throws \OCP\DB\Exception * @throws \OCP\DB\Exception
*/ */
public function findDeleted($boardId, $limit = null, $offset = null) { public function findDeleted(int $boardId, ?int $limit = null, int $offset = 0): array {
$qb = $this->db->getQueryBuilder(); $qb = $this->db->getQueryBuilder();
$qb->select('*') $qb->select('*')
->from($this->getTableName()) ->from($this->getTableName())
@@ -125,12 +116,9 @@ class StackMapper extends DeckMapper implements IPermissionMapper {
} }
/** /**
* @param numeric $userId
* @param numeric $stackId
* @return bool
* @throws \OCP\DB\Exception * @throws \OCP\DB\Exception
*/ */
public function isOwner($userId, $id): bool { public function isOwner(string $userId, int $id): bool {
$qb = $this->db->getQueryBuilder(); $qb = $this->db->getQueryBuilder();
$qb->select('s.id') $qb->select('s.id')
->from($this->getTableName(), 's') ->from($this->getTableName(), 's')
@@ -142,11 +130,9 @@ class StackMapper extends DeckMapper implements IPermissionMapper {
} }
/** /**
* @param numeric $id
* @return int|null
* @throws \OCP\DB\Exception * @throws \OCP\DB\Exception
*/ */
public function findBoardId($id): ?int { public function findBoardId(int $id): ?int {
$result = $this->cache->get('findBoardId:' . $id); $result = $this->cache->get('findBoardId:' . $id);
if ($result !== null) { if ($result !== null) {
return $result !== false ? $result : null; return $result !== false ? $result : null;
@@ -163,6 +149,10 @@ class StackMapper extends DeckMapper implements IPermissionMapper {
return $result !== false ? $result : null; return $result !== false ? $result : null;
} }
/**
* @return array<Stack>
* @throws \OCP\DB\Exception
*/
public function findToDelete(): array { public function findToDelete(): array {
// add buffer of 5 min // add buffer of 5 min
$timeLimit = time() - (60 * 5); $timeLimit = time() - (60 * 5);

View File

@@ -35,6 +35,10 @@ class BeforeTemplateRenderedListener implements IEventListener {
Util::addStyle('deck', 'deck'); Util::addStyle('deck', 'deck');
$pathInfo = $this->request->getPathInfo(); $pathInfo = $this->request->getPathInfo();
if (!$pathInfo) {
return;
}
if (str_starts_with($pathInfo, '/apps/calendar')) { if (str_starts_with($pathInfo, '/apps/calendar')) {
Util::addScript('deck', 'deck-calendar'); Util::addScript('deck', 'deck-calendar');
} }

View File

@@ -18,14 +18,10 @@ use OCP\EventDispatcher\IEventListener;
/** @template-implements IEventListener<Event|AclDeletedEvent|AclCreatedEvent> */ /** @template-implements IEventListener<Event|AclDeletedEvent|AclCreatedEvent> */
class ResourceListener implements IEventListener { class ResourceListener implements IEventListener {
/** @var IManager */ public function __construct(
private $resourceManager; private readonly IManager $resourceManager,
/** @var ResourceProviderCard */ private readonly ResourceProviderCard $resourceProviderCard,
private $resourceProviderCard; ) {
public function __construct(IManager $resourceManager, ResourceProviderCard $resourceProviderCard) {
$this->resourceManager = $resourceManager;
$this->resourceProviderCard = $resourceProviderCard;
} }
public function handle(Event $event): void { public function handle(Event $event): void {
@@ -38,10 +34,10 @@ class ResourceListener implements IEventListener {
$this->resourceManager->invalidateAccessCacheForProvider($this->resourceProviderCard); $this->resourceManager->invalidateAccessCacheForProvider($this->resourceProviderCard);
try { try {
$resource = $this->resourceManager->getResourceForUser(ResourceProvider::RESOURCE_TYPE, $boardId, null); $resource = $this->resourceManager->getResourceForUser(ResourceProvider::RESOURCE_TYPE, (string)$boardId, null);
$this->resourceManager->invalidateAccessCacheForResource($resource); $this->resourceManager->invalidateAccessCacheForResource($resource);
} catch (ResourceException $e) { } catch (ResourceException $e) {
// If there is no resource we don't need to invalidate anything, but this should not happen anyways // If there is no resource we don't need to invalidate anything, but this should not happen anyway
} }
} }
} }

View File

@@ -11,6 +11,7 @@ use OCA\Deck\Db\Board;
class BoardSummary extends Board { class BoardSummary extends Board {
private Board $board; private Board $board;
/** @psalm-suppress ConstructorSignatureMismatch */
public function __construct(Board $board) { public function __construct(Board $board) {
parent::__construct(); parent::__construct();
$this->board = $board; $this->board = $board;
@@ -27,7 +28,7 @@ class BoardSummary extends Board {
return $this->board->getter($name); return $this->board->getter($name);
} }
public function __call($name, $arguments) { public function __call($methodName, $args) {
return $this->board->__call($name, $arguments); return $this->board->__call($methodName, $args);
} }
} }

View File

@@ -15,6 +15,7 @@ class CardDetails extends Card {
private ?Board $board; private ?Board $board;
private ?Reference $referenceData = null; private ?Reference $referenceData = null;
/** @psalm-suppress ConstructorSignatureMismatch */
public function __construct(Card $card, ?Board $board = null) { public function __construct(Card $card, ?Board $board = null) {
parent::__construct(); parent::__construct();
$this->card = $card; $this->card = $card;

View File

@@ -95,7 +95,7 @@ class NotificationHelper {
$shouldNotify = $notificationSetting === ConfigService::SETTING_BOARD_NOTIFICATION_DUE_ALL; $shouldNotify = $notificationSetting === ConfigService::SETTING_BOARD_NOTIFICATION_DUE_ALL;
if ($user->getUID() === $board->getOwner() && count($board->getAcl()) === 0) { if ($user->getUID() === $board->getOwner() && count($board->getAcl() ?? []) === 0) {
// Notify if all or assigned is configured for unshared boards // Notify if all or assigned is configured for unshared boards
$shouldNotify = true; $shouldNotify = true;
} elseif ($notificationSetting === ConfigService::SETTING_BOARD_NOTIFICATION_DUE_ASSIGNED && $this->assignmentMapper->isUserAssigned($card->getId(), $user->getUID())) { } elseif ($notificationSetting === ConfigService::SETTING_BOARD_NOTIFICATION_DUE_ASSIGNED && $this->assignmentMapper->isUserAssigned($card->getId(), $user->getUID())) {

View File

@@ -21,7 +21,6 @@ use OCA\Deck\NotFoundException;
use OCA\Deck\Notification\NotificationHelper; use OCA\Deck\Notification\NotificationHelper;
use OCA\Deck\Validators\AssignmentServiceValidator; use OCA\Deck\Validators\AssignmentServiceValidator;
use OCP\AppFramework\Db\DoesNotExistException; use OCP\AppFramework\Db\DoesNotExistException;
use OCP\AppFramework\Db\Entity;
use OCP\AppFramework\Db\MultipleObjectsReturnedException; use OCP\AppFramework\Db\MultipleObjectsReturnedException;
use OCP\EventDispatcher\IEventDispatcher; use OCP\EventDispatcher\IEventDispatcher;
@@ -92,15 +91,12 @@ class AssignmentService {
} }
/** /**
* @param $cardId
* @param $userId
* @return bool|null|Entity
* @throws BadRequestException * @throws BadRequestException
* @throws NoPermissionException * @throws NoPermissionException
* @throws MultipleObjectsReturnedException * @throws MultipleObjectsReturnedException
* @throws DoesNotExistException * @throws DoesNotExistException
*/ */
public function assignUser($cardId, $userId, int $type = Assignment::TYPE_USER) { public function assignUser(int $cardId, string $userId, int $type = Assignment::TYPE_USER): Assignment {
$this->assignmentServiceValidator->check(compact('cardId', 'userId')); $this->assignmentServiceValidator->check(compact('cardId', 'userId'));
if ($type !== Assignment::TYPE_USER && $type !== Assignment::TYPE_GROUP) { if ($type !== Assignment::TYPE_USER && $type !== Assignment::TYPE_GROUP) {
@@ -144,16 +140,13 @@ class AssignmentService {
} }
/** /**
* @param $cardId
* @param $userId
* @return Entity
* @throws BadRequestException * @throws BadRequestException
* @throws NotFoundException * @throws NotFoundException
* @throws NoPermissionException * @throws NoPermissionException
* @throws DoesNotExistException * @throws DoesNotExistException
* @throws MultipleObjectsReturnedException * @throws MultipleObjectsReturnedException
*/ */
public function unassignUser($cardId, $userId, $type = 0) { public function unassignUser(int $cardId, string $userId, int $type = 0): Assignment {
$this->assignmentServiceValidator->check(compact('cardId', 'userId')); $this->assignmentServiceValidator->check(compact('cardId', 'userId'));
$this->permissionService->checkPermission($this->cardMapper, $cardId, Acl::PERMISSION_EDIT); $this->permissionService->checkPermission($this->cardMapper, $cardId, Acl::PERMISSION_EDIT);

View File

@@ -25,6 +25,7 @@ use OCP\AppFramework\Db\IMapperException;
use OCP\AppFramework\Http\Response; use OCP\AppFramework\Http\Response;
use OCP\IL10N; use OCP\IL10N;
use OCP\IUserManager; use OCP\IUserManager;
use Psr\Container\ContainerExceptionInterface;
class AttachmentService { class AttachmentService {
private $attachmentMapper; private $attachmentMapper;
@@ -80,20 +81,16 @@ class AttachmentService {
} }
/** /**
* @param string $type * @throws ContainerExceptionInterface
* @param string $class
* @throws \OCP\AppFramework\QueryException
*/ */
public function registerAttachmentService($type, $class) { public function registerAttachmentService(string $type, string $class): void {
$this->services[$type] = $this->application->getContainer()->query($class); $this->services[$type] = $this->application->getContainer()->get($class);
} }
/** /**
* @param string $type
* @return IAttachmentService
* @throws InvalidAttachmentType * @throws InvalidAttachmentType
*/ */
public function getService($type) { public function getService(string $type): IAttachmentService {
if (isset($this->services[$type])) { if (isset($this->services[$type])) {
return $this->services[$type]; return $this->services[$type];
} }
@@ -101,16 +98,11 @@ class AttachmentService {
} }
/** /**
* @param $cardId * @return Attachment[]
* @return array
* @throws \OCA\Deck\NoPermissionException * @throws \OCA\Deck\NoPermissionException
* @throws BadRequestException * @throws BadRequestException
*/ */
public function findAll($cardId, $withDeleted = false) { public function findAll(int $cardId, bool $withDeleted = false): array {
if (is_numeric($cardId) === false) {
throw new BadRequestException('card id must be a number');
}
$this->permissionService->checkPermission($this->cardMapper, $cardId, Acl::PERMISSION_READ); $this->permissionService->checkPermission($this->cardMapper, $cardId, Acl::PERMISSION_READ);
$attachments = $this->attachmentMapper->findAll($cardId); $attachments = $this->attachmentMapper->findAll($cardId);
@@ -122,7 +114,7 @@ class AttachmentService {
/** @var IAttachmentService $service */ /** @var IAttachmentService $service */
$service = $this->getService($attachmentType); $service = $this->getService($attachmentType);
if ($service instanceof ICustomAttachmentService) { if ($service instanceof ICustomAttachmentService) {
$attachments = array_merge($attachments, $service->listAttachments((int)$cardId)); $attachments = array_merge($attachments, $service->listAttachments($cardId));
} }
} }
@@ -140,49 +132,40 @@ class AttachmentService {
} }
/** /**
* @param $cardId
* @return int|mixed
* @throws BadRequestException * @throws BadRequestException
* @throws InvalidAttachmentType * @throws InvalidAttachmentType
* @throws \OCP\DB\Exception * @throws \OCP\DB\Exception
*/ */
public function count($cardId) { public function count(int $cardId): int {
if (is_numeric($cardId) === false) { $count = $this->attachmentCacheHelper->getAttachmentCount($cardId);
throw new BadRequestException('card id must be a number');
}
$count = $this->attachmentCacheHelper->getAttachmentCount((int)$cardId);
if ($count === null) { if ($count === null) {
$count = count($this->attachmentMapper->findAll($cardId)); $count = count($this->attachmentMapper->findAll($cardId));
foreach (array_keys($this->services) as $attachmentType) { foreach (array_keys($this->services) as $attachmentType) {
$service = $this->getService($attachmentType); $service = $this->getService($attachmentType);
if ($service instanceof ICustomAttachmentService) { if ($service instanceof ICustomAttachmentService) {
$count += $service->getAttachmentCount((int)$cardId); $count += $service->getAttachmentCount($cardId);
} }
} }
$this->attachmentCacheHelper->setAttachmentCount((int)$cardId, $count); $this->attachmentCacheHelper->setAttachmentCount($cardId, $count);
} }
return $count; return $count;
} }
/** /**
* @param $cardId
* @param $type
* @param $data
* @return Attachment|\OCP\AppFramework\Db\Entity * @return Attachment|\OCP\AppFramework\Db\Entity
* @throws NoPermissionException * @throws NoPermissionException
* @throws StatusException * @throws StatusException
* @throws BadRequestException * @throws BadRequestException
*/ */
public function create($cardId, $type, $data) { public function create(int $cardId, string $type, string $data) {
$this->attachmentServiceValidator->check(compact('cardId', 'type')); $this->attachmentServiceValidator->check(compact('cardId', 'type'));
$this->permissionService->checkPermission($this->cardMapper, $cardId, Acl::PERMISSION_EDIT); $this->permissionService->checkPermission($this->cardMapper, $cardId, Acl::PERMISSION_EDIT);
$this->attachmentCacheHelper->clearAttachmentCount((int)$cardId); $this->attachmentCacheHelper->clearAttachmentCount($cardId);
$attachment = new Attachment(); $attachment = new Attachment();
$attachment->setCardId($cardId); $attachment->setCardId($cardId);
$attachment->setType($type); $attachment->setType($type);
@@ -218,12 +201,10 @@ class AttachmentService {
/** /**
* Display the attachment * Display the attachment
* *
* @param $attachmentId
* @return Response
* @throws NoPermissionException * @throws NoPermissionException
* @throws NotFoundException * @throws NotFoundException
*/ */
public function display($cardId, $attachmentId, $type = 'deck_file') { public function display(int $cardId, int $attachmentId, string $type = 'deck_file'): Response {
try { try {
$service = $this->getService($type); $service = $this->getService($type);
} catch (InvalidAttachmentType $e) { } catch (InvalidAttachmentType $e) {
@@ -257,13 +238,10 @@ class AttachmentService {
/** /**
* Update an attachment with custom data * Update an attachment with custom data
* *
* @param $attachmentId
* @param $data
* @return mixed
* @throws BadRequestException * @throws BadRequestException
* @throws NoPermissionException * @throws NoPermissionException
*/ */
public function update($cardId, $attachmentId, $data, $type = 'deck_file') { public function update(int $cardId, int $attachmentId, string $data, string $type = 'deck_file'): Attachment {
$this->attachmentServiceValidator->check(compact('cardId', 'type', 'data')); $this->attachmentServiceValidator->check(compact('cardId', 'type', 'data'));
try { try {
@@ -384,8 +362,6 @@ class AttachmentService {
} }
/** /**
* @param Attachment $attachment
* @return Attachment
* @throws \ReflectionException * @throws \ReflectionException
*/ */
private function addCreator(Attachment $attachment): Attachment { private function addCreator(Attachment $attachment): Attachment {

View File

@@ -75,8 +75,6 @@ class BoardService {
/** /**
* Set a different user than the current one, e.g. when no user is available in occ * 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 { public function setUserId(string $userId): void {
$this->userId = $userId; $this->userId = $userId;
@@ -117,22 +115,18 @@ class BoardService {
} }
$this->permissionService->checkPermission($this->boardMapper, $boardId, Acl::PERMISSION_READ); $this->permissionService->checkPermission($this->boardMapper, $boardId, Acl::PERMISSION_READ);
/** @var Board $board */
$board = $this->boardMapper->find($boardId, true, true, $allowDeleted); $board = $this->boardMapper->find($boardId, true, true, $allowDeleted);
[$board] = $this->enrichBoards([$board], $fullDetails); [$board] = $this->enrichBoards([$board], $fullDetails);
return $board; return $board;
} }
/** /**
* @param $mapper
* @param $id
* @return bool
* @throws DoesNotExistException * @throws DoesNotExistException
* @throws NoPermissionException * @throws NoPermissionException
* @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException
* @throws BadRequestException * @throws BadRequestException
*/ */
public function isArchived($mapper, $id) { public function isArchived($mapper, int $id): bool {
$this->boardServiceValidator->check(compact('id')); $this->boardServiceValidator->check(compact('id'));
try { try {
@@ -151,15 +145,12 @@ class BoardService {
} }
/** /**
* @param $mapper
* @param $id
* @return bool
* @throws DoesNotExistException * @throws DoesNotExistException
* @throws NoPermissionException * @throws NoPermissionException
* @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException
* @throws BadRequestException * @throws BadRequestException
*/ */
public function isDeleted($mapper, $id) { public function isDeleted($mapper, int $id): bool {
$this->boardServiceValidator->check(compact('mapper', 'id')); $this->boardServiceValidator->check(compact('mapper', 'id'));
try { try {
@@ -179,13 +170,9 @@ class BoardService {
/** /**
* @param $title
* @param $userId
* @param $color
* @return \OCP\AppFramework\Db\Entity
* @throws BadRequestException * @throws BadRequestException
*/ */
public function create($title, $userId, $color) { public function create(string $title, string $userId, string $color): Board {
$this->boardServiceValidator->check(compact('title', 'userId', 'color')); $this->boardServiceValidator->check(compact('title', 'userId', 'color'));
if (!$this->permissionService->canCreate()) { if (!$this->permissionService->canCreate()) {
@@ -196,7 +183,8 @@ class BoardService {
$board->setTitle($title); $board->setTitle($title);
$board->setOwner($userId); $board->setOwner($userId);
$board->setColor($color); $board->setColor($color);
$new_board = $this->boardMapper->insert($board); /** @var Board $board */
$board = $this->boardMapper->insert($board);
// create new labels // create new labels
$default_labels = [ $default_labels = [
@@ -210,33 +198,31 @@ class BoardService {
$label = new Label(); $label = new Label();
$label->setColor($labelColor); $label->setColor($labelColor);
$label->setTitle($labelTitle); $label->setTitle($labelTitle);
$label->setBoardId($new_board->getId()); $label->setBoardId($board->getId());
$labels[] = $this->labelMapper->insert($label); $labels[] = $this->labelMapper->insert($label);
} }
$new_board->setLabels($labels); $board->setLabels($labels);
$this->boardMapper->mapOwner($new_board); $this->boardMapper->mapOwner($board);
$permissions = $this->permissionService->matchPermissions($new_board); $permissions = $this->permissionService->matchPermissions($board);
$new_board->setPermissions([ $board->setPermissions([
'PERMISSION_READ' => $permissions[Acl::PERMISSION_READ] ?? false, 'PERMISSION_READ' => $permissions[Acl::PERMISSION_READ] ?? false,
'PERMISSION_EDIT' => $permissions[Acl::PERMISSION_EDIT] ?? false, 'PERMISSION_EDIT' => $permissions[Acl::PERMISSION_EDIT] ?? false,
'PERMISSION_MANAGE' => $permissions[Acl::PERMISSION_MANAGE] ?? false, 'PERMISSION_MANAGE' => $permissions[Acl::PERMISSION_MANAGE] ?? false,
'PERMISSION_SHARE' => $permissions[Acl::PERMISSION_SHARE] ?? false 'PERMISSION_SHARE' => $permissions[Acl::PERMISSION_SHARE] ?? false
]); ]);
$this->activityManager->triggerEvent(ActivityManager::DECK_OBJECT_BOARD, $new_board, ActivityManager::SUBJECT_BOARD_CREATE, [], $userId); $this->activityManager->triggerEvent(ActivityManager::DECK_OBJECT_BOARD, $board, ActivityManager::SUBJECT_BOARD_CREATE, [], $userId);
$this->changeHelper->boardChanged($new_board->getId()); $this->changeHelper->boardChanged($board->getId());
return $new_board; return $board;
} }
/** /**
* @param $id
* @return Board
* @throws DoesNotExistException * @throws DoesNotExistException
* @throws NoPermissionException * @throws NoPermissionException
* @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException
* @throws BadRequestException * @throws BadRequestException
*/ */
public function delete($id) { public function delete(int $id): Board {
$this->boardServiceValidator->check(compact('id')); $this->boardServiceValidator->check(compact('id'));
$this->permissionService->checkPermission($this->boardMapper, $id, Acl::PERMISSION_MANAGE); $this->permissionService->checkPermission($this->boardMapper, $id, Acl::PERMISSION_MANAGE);
@@ -253,13 +239,11 @@ class BoardService {
} }
/** /**
* @param $id
* @return \OCP\AppFramework\Db\Entity
* @throws DoesNotExistException * @throws DoesNotExistException
* @throws NoPermissionException * @throws NoPermissionException
* @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException
*/ */
public function deleteUndo($id) { public function deleteUndo(int $id): Board {
$this->boardServiceValidator->check(compact('id')); $this->boardServiceValidator->check(compact('id'));
$this->permissionService->checkPermission($this->boardMapper, $id, Acl::PERMISSION_MANAGE); $this->permissionService->checkPermission($this->boardMapper, $id, Acl::PERMISSION_MANAGE);
@@ -273,14 +257,12 @@ class BoardService {
} }
/** /**
* @param $id
* @return \OCP\AppFramework\Db\Entity
* @throws DoesNotExistException * @throws DoesNotExistException
* @throws NoPermissionException * @throws NoPermissionException
* @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException
* @throws BadRequestException * @throws BadRequestException
*/ */
public function deleteForce($id) { public function deleteForce(int $id): Board {
$this->boardServiceValidator->check(compact('id')); $this->boardServiceValidator->check(compact('id'));
$this->permissionService->checkPermission($this->boardMapper, $id, Acl::PERMISSION_MANAGE); $this->permissionService->checkPermission($this->boardMapper, $id, Acl::PERMISSION_MANAGE);
@@ -291,17 +273,12 @@ class BoardService {
} }
/** /**
* @param $id
* @param $title
* @param $color
* @param $archived
* @return \OCP\AppFramework\Db\Entity
* @throws DoesNotExistException * @throws DoesNotExistException
* @throws NoPermissionException * @throws NoPermissionException
* @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException
* @throws BadRequestException * @throws BadRequestException
*/ */
public function update($id, $title, $color, $archived) { public function update(int $id, string $title, string $color, bool $archived): Board {
$this->boardServiceValidator->check(compact('id', 'title', 'color', 'archived')); $this->boardServiceValidator->check(compact('id', 'title', 'color', 'archived'));
$this->permissionService->checkPermission($this->boardMapper, $id, Acl::PERMISSION_MANAGE); $this->permissionService->checkPermission($this->boardMapper, $id, Acl::PERMISSION_MANAGE);
@@ -320,7 +297,7 @@ class BoardService {
return $board; return $board;
} }
private function applyPermissions($boardId, $edit, $share, $manage, $oldAcl = null) { private function applyPermissions(int $boardId, bool $edit, bool $share, bool $manage, ?Acl $oldAcl = null): array {
try { try {
$this->permissionService->checkPermission($this->boardMapper, $boardId, Acl::PERMISSION_MANAGE); $this->permissionService->checkPermission($this->boardMapper, $boardId, Acl::PERMISSION_MANAGE);
} catch (NoPermissionException $e) { } catch (NoPermissionException $e) {
@@ -332,7 +309,7 @@ class BoardService {
return [$edit, $share, $manage]; return [$edit, $share, $manage];
} }
public function enrichWithBoardSettings(Board $board) { public function enrichWithBoardSettings(Board $board): void {
$globalCalendarConfig = (bool)$this->config->getUserValue($this->userId, Application::APP_ID, 'calendar', true); $globalCalendarConfig = (bool)$this->config->getUserValue($this->userId, Application::APP_ID, 'calendar', true);
$settings = [ $settings = [
'notify-due' => $this->config->getUserValue($this->userId, Application::APP_ID, 'board:' . $board->getId() . ':notify-due', ConfigService::SETTING_BOARD_NOTIFICATION_DUE_ASSIGNED), 'notify-due' => $this->config->getUserValue($this->userId, Application::APP_ID, 'board:' . $board->getId() . ':notify-due', ConfigService::SETTING_BOARD_NOTIFICATION_DUE_ASSIGNED),
@@ -341,7 +318,7 @@ class BoardService {
$board->setSettings($settings); $board->setSettings($settings);
} }
public function enrichWithActiveSessions(Board $board) { public function enrichWithActiveSessions(Board $board): void {
$sessions = $this->sessionMapper->findAllActive($board->getId()); $sessions = $this->sessionMapper->findAllActive($board->getId());
$board->setActiveSessions(array_values( $board->setActiveSessions(array_values(
@@ -354,17 +331,11 @@ class BoardService {
} }
/** /**
* @param $boardId * @param Acl::PERMISSION_TYPE_* $type
* @param $type
* @param $participant
* @param $edit
* @param $share
* @param $manage
* @return \OCP\AppFramework\Db\Entity
* @throws BadRequestException * @throws BadRequestException
* @throws NoPermissionException * @throws NoPermissionException
*/ */
public function addAcl($boardId, $type, $participant, $edit, $share, $manage) { public function addAcl(int $boardId, int $type, $participant, bool $edit, bool $share, bool $manage): Acl {
$this->boardServiceValidator->check(compact('boardId', 'type', 'participant', 'edit', 'share', 'manage')); $this->boardServiceValidator->check(compact('boardId', 'type', 'participant', 'edit', 'share', 'manage'));
$this->permissionService->checkPermission($this->boardMapper, $boardId, Acl::PERMISSION_SHARE); $this->permissionService->checkPermission($this->boardMapper, $boardId, Acl::PERMISSION_SHARE);
@@ -400,17 +371,12 @@ class BoardService {
} }
/** /**
* @param $id
* @param $edit
* @param $share
* @param $manage
* @return \OCP\AppFramework\Db\Entity
* @throws DoesNotExistException * @throws DoesNotExistException
* @throws NoPermissionException * @throws NoPermissionException
* @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException
* @throws BadRequestException * @throws BadRequestException
*/ */
public function updateAcl($id, $edit, $share, $manage) { public function updateAcl(int $id, bool $edit, bool $share, bool $manage): Acl {
$this->boardServiceValidator->check(compact('id', 'edit', 'share', 'manage')); $this->boardServiceValidator->check(compact('id', 'edit', 'share', 'manage'));
$this->permissionService->checkPermission($this->aclMapper, $id, Acl::PERMISSION_SHARE); $this->permissionService->checkPermission($this->aclMapper, $id, Acl::PERMISSION_SHARE);
@@ -422,12 +388,12 @@ class BoardService {
$acl->setPermissionShare($share); $acl->setPermissionShare($share);
$acl->setPermissionManage($manage); $acl->setPermissionManage($manage);
$this->boardMapper->mapAcl($acl); $this->boardMapper->mapAcl($acl);
$board = $this->aclMapper->update($acl); $acl = $this->aclMapper->update($acl);
$this->changeHelper->boardChanged($acl->getBoardId()); $this->changeHelper->boardChanged($acl->getBoardId());
$this->eventDispatcher->dispatchTyped(new AclUpdatedEvent($acl)); $this->eventDispatcher->dispatchTyped(new AclUpdatedEvent($acl));
return $board; return $acl;
} }
/** /**
@@ -579,27 +545,23 @@ class BoardService {
} }
/** /**
* @param $id
* @return Board
* @throws DoesNotExistException * @throws DoesNotExistException
* @throws NoPermissionException * @throws NoPermissionException
* @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException
* @throws BadRequestException
*/ */
public function export($id) : Board { public function export(int $id): Board {
if (is_numeric($id) === false) {
throw new BadRequestException('board id must be a number');
}
$this->permissionService->checkPermission($this->boardMapper, $id, Acl::PERMISSION_READ); $this->permissionService->checkPermission($this->boardMapper, $id, Acl::PERMISSION_READ);
$board = $this->boardMapper->find((int)$id); $board = $this->boardMapper->find($id);
$this->enrichWithCards($board); $this->enrichWithCards($board);
$this->enrichWithLabels($board); $this->enrichWithLabels($board);
return $board; return $board;
} }
/** @param Board[] $boards */ /**
* @param Board[] $boards
* @return Board[]
*/
private function enrichBoards(array $boards, bool $fullDetails = true): array { private function enrichBoards(array $boards, bool $fullDetails = true): array {
$result = []; $result = [];
foreach ($boards as $board) { foreach ($boards as $board) {
@@ -715,8 +677,8 @@ class BoardService {
} }
} }
private function enrichWithStacks($board, $since = -1) { private function enrichWithStacks(Board $board): void {
$stacks = $this->stackMapper->findAll($board->getId(), null, null, $since); $stacks = $this->stackMapper->findAll($board->getId());
if (\count($stacks) === 0) { if (\count($stacks) === 0) {
return; return;
@@ -725,8 +687,8 @@ class BoardService {
$board->setStacks($stacks); $board->setStacks($stacks);
} }
private function enrichWithLabels($board, $since = -1) { private function enrichWithLabels(Board $board): void {
$labels = $this->labelMapper->findAll($board->getId(), null, null, $since); $labels = $this->labelMapper->findAll($board->getId());
if (\count($labels) === 0) { if (\count($labels) === 0) {
return; return;
@@ -735,7 +697,7 @@ class BoardService {
$board->setLabels($labels); $board->setLabels($labels);
} }
private function enrichWithUsers($board, $since = -1) { private function enrichWithUsers(Board $board): void {
$boardUsers = $this->permissionService->findUsers($board->getId()); $boardUsers = $this->permissionService->findUsers($board->getId());
if ($boardUsers === null || \count($boardUsers) === 0) { if ($boardUsers === null || \count($boardUsers) === 0) {
return; return;
@@ -746,7 +708,7 @@ class BoardService {
/** /**
* Clean a given board data from the Cache * Clean a given board data from the Cache
*/ */
private function clearBoardFromCache(Board $board) { private function clearBoardFromCache(Board $board): void {
$boardId = $board->getId(); $boardId = $board->getId();
$boardOwnerId = $board->getOwner(); $boardOwnerId = $board->getOwner();
@@ -755,7 +717,7 @@ class BoardService {
unset($this->boardsCachePartial[$boardId]); unset($this->boardsCachePartial[$boardId]);
} }
private function enrichWithCards($board) { private function enrichWithCards(Board $board): void {
$stacks = $this->stackMapper->findAll($board->getId()); $stacks = $this->stackMapper->findAll($board->getId());
foreach ($stacks as $stack) { foreach ($stacks as $stack) {
$cards = $this->cardMapper->findAllByStack($stack->getId()); $cards = $this->cardMapper->findAllByStack($stack->getId());

View File

@@ -64,10 +64,14 @@ class CardService {
) { ) {
} }
public function enrichCards($cards) { /**
* @param Card[] $cards
* @return CardDetails[]
*/
public function enrichCards(array $cards): array {
$user = $this->userManager->get($this->userId); $user = $this->userManager->get($this->userId);
$cardIds = array_map(function (Card $card) use ($user) { $cardIds = array_map(function (Card $card) use ($user): int {
// Everything done in here might be heavy as it is executed for every card // Everything done in here might be heavy as it is executed for every card
$cardId = $card->getId(); $cardId = $card->getId();
$this->cardMapper->mapOwner($card); $this->cardMapper->mapOwner($card);
@@ -120,7 +124,8 @@ class CardService {
); );
} }
public function fetchDeleted($boardId) { /** @return Card[] */
public function fetchDeleted($boardId): array {
$this->cardServiceValidator->check(compact('boardId')); $this->cardServiceValidator->check(compact('boardId'));
$this->permissionService->checkPermission($this->boardMapper, $boardId, Acl::PERMISSION_READ); $this->permissionService->checkPermission($this->boardMapper, $boardId, Acl::PERMISSION_READ);
$cards = $this->cardMapper->findDeleted($boardId); $cards = $this->cardMapper->findDeleted($boardId);
@@ -129,13 +134,12 @@ class CardService {
} }
/** /**
* @return \OCA\Deck\Db\RelationalEntity
* @throws \OCA\Deck\NoPermissionException * @throws \OCA\Deck\NoPermissionException
* @throws \OCP\AppFramework\Db\DoesNotExistException * @throws \OCP\AppFramework\Db\DoesNotExistException
* @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException
* @throws BadRequestException * @throws BadRequestException
*/ */
public function find(int $cardId) { public function find(int $cardId): Card {
$this->permissionService->checkPermission($this->cardMapper, $cardId, Acl::PERMISSION_READ); $this->permissionService->checkPermission($this->cardMapper, $cardId, Acl::PERMISSION_READ);
$card = $this->cardMapper->find($cardId); $card = $this->cardMapper->find($cardId);
[$card] = $this->enrichCards([$card]); [$card] = $this->enrichCards([$card]);
@@ -152,7 +156,10 @@ class CardService {
return $card; return $card;
} }
public function findCalendarEntries($boardId) { /**
* @return Card[]
*/
public function findCalendarEntries(int $boardId): array {
try { try {
$this->permissionService->checkPermission($this->boardMapper, $boardId, Acl::PERMISSION_READ); $this->permissionService->checkPermission($this->boardMapper, $boardId, Acl::PERMISSION_READ);
} catch (NoPermissionException $e) { } catch (NoPermissionException $e) {
@@ -163,20 +170,13 @@ class CardService {
} }
/** /**
* @param $title
* @param $stackId
* @param $type
* @param integer $order
* @param $description
* @param $owner
* @return \OCP\AppFramework\Db\Entity
* @throws StatusException * @throws StatusException
* @throws \OCA\Deck\NoPermissionException * @throws \OCA\Deck\NoPermissionException
* @throws \OCP\AppFramework\Db\DoesNotExistException * @throws \OCP\AppFramework\Db\DoesNotExistException
* @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException
* @throws BadrequestException * @throws BadrequestException
*/ */
public function create($title, $stackId, $type, $order, $owner, $description = '', $duedate = null) { public function create(string $title, int $stackId, string $type, int $order, string $owner, string $description = '', $duedate = null): Card {
$this->cardServiceValidator->check(compact('title', 'stackId', 'type', 'order', 'owner')); $this->cardServiceValidator->check(compact('title', 'stackId', 'type', 'order', 'owner'));
$this->permissionService->checkPermission($this->stackMapper, $stackId, Acl::PERMISSION_EDIT); $this->permissionService->checkPermission($this->stackMapper, $stackId, Acl::PERMISSION_EDIT);
@@ -203,19 +203,13 @@ class CardService {
} }
/** /**
* @param $id
* @return \OCP\AppFramework\Db\Entity
* @throws StatusException * @throws StatusException
* @throws \OCA\Deck\NoPermissionException * @throws \OCA\Deck\NoPermissionException
* @throws \OCP\AppFramework\Db\DoesNotExistException * @throws \OCP\AppFramework\Db\DoesNotExistException
* @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException
* @throws BadRequestException * @throws BadRequestException
*/ */
public function delete($id) { public function delete(int $id): Card {
if (is_numeric($id) === false) {
throw new BadRequestException('card id must be a number');
}
$this->permissionService->checkPermission($this->cardMapper, $id, Acl::PERMISSION_EDIT); $this->permissionService->checkPermission($this->cardMapper, $id, Acl::PERMISSION_EDIT);
if ($this->boardService->isArchived($this->cardMapper, $id)) { if ($this->boardService->isArchived($this->cardMapper, $id)) {
throw new StatusException('Operation not allowed. This board is archived.'); throw new StatusException('Operation not allowed. This board is archived.');
@@ -233,25 +227,13 @@ class CardService {
} }
/** /**
* @param $id
* @param $title
* @param $stackId
* @param $type
* @param $owner
* @param $description
* @param $order
* @param $duedate
* @param $deletedAt
* @param $archived
* @param $done
* @return \OCP\AppFramework\Db\Entity
* @throws StatusException * @throws StatusException
* @throws \OCA\Deck\NoPermissionException * @throws \OCA\Deck\NoPermissionException
* @throws \OCP\AppFramework\Db\DoesNotExistException * @throws \OCP\AppFramework\Db\DoesNotExistException
* @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException
* @throws BadRequestException * @throws BadRequestException
*/ */
public function update($id, $title, $stackId, $type, $owner, $description = '', $order = 0, $duedate = null, $deletedAt = null, $archived = null, ?OptionalNullableValue $done = null) { public function update(int $id, string $title, int $stackId, string $type, string $owner, string $description = '', int $order = 0, ?string $duedate = null, ?int $deletedAt = null, ?bool $archived = null, ?OptionalNullableValue $done = null): Card {
$this->cardServiceValidator->check(compact('id', 'title', 'stackId', 'type', 'owner', 'order')); $this->cardServiceValidator->check(compact('id', 'title', 'stackId', 'type', 'owner', 'order'));
$this->permissionService->checkPermission($this->cardMapper, $id, Acl::PERMISSION_EDIT, allowDeletedCard: true); $this->permissionService->checkPermission($this->cardMapper, $id, Acl::PERMISSION_EDIT, allowDeletedCard: true);
@@ -398,16 +380,13 @@ class CardService {
} }
/** /**
* @param $id
* @param $title
* @return \OCP\AppFramework\Db\Entity
* @throws StatusException * @throws StatusException
* @throws \OCA\Deck\NoPermissionException * @throws \OCA\Deck\NoPermissionException
* @throws \OCP\AppFramework\Db\DoesNotExistException * @throws \OCP\AppFramework\Db\DoesNotExistException
* @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException
* @throws BadRequestException * @throws BadRequestException
*/ */
public function rename($id, $title) { public function rename(int $id, string $title): Card {
$this->cardServiceValidator->check(compact('id', 'title')); $this->cardServiceValidator->check(compact('id', 'title'));
$this->permissionService->checkPermission($this->cardMapper, $id, Acl::PERMISSION_EDIT); $this->permissionService->checkPermission($this->cardMapper, $id, Acl::PERMISSION_EDIT);
@@ -429,17 +408,14 @@ class CardService {
} }
/** /**
* @param $id * @return list<Card>
* @param $stackId
* @param $order
* @return array
* @throws StatusException * @throws StatusException
* @throws \OCA\Deck\NoPermissionException * @throws \OCA\Deck\NoPermissionException
* @throws \OCP\AppFramework\Db\DoesNotExistException * @throws \OCP\AppFramework\Db\DoesNotExistException
* @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException
* @throws BadRequestException * @throws BadRequestException
*/ */
public function reorder(int $id, int $stackId, int $order) { public function reorder(int $id, int $stackId, int $order): array {
$this->cardServiceValidator->check(compact('id', 'stackId', 'order')); $this->cardServiceValidator->check(compact('id', 'stackId', 'order'));
$this->permissionService->checkPermission($this->cardMapper, $id, Acl::PERMISSION_EDIT); $this->permissionService->checkPermission($this->cardMapper, $id, Acl::PERMISSION_EDIT);
@@ -488,15 +464,13 @@ class CardService {
} }
/** /**
* @param $id
* @return \OCP\AppFramework\Db\Entity
* @throws StatusException * @throws StatusException
* @throws \OCA\Deck\NoPermissionException * @throws \OCA\Deck\NoPermissionException
* @throws \OCP\AppFramework\Db\DoesNotExistException * @throws \OCP\AppFramework\Db\DoesNotExistException
* @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException
* @throws BadRequestException * @throws BadRequestException
*/ */
public function archive($id) { public function archive(int $id): Card {
$this->cardServiceValidator->check(compact('id')); $this->cardServiceValidator->check(compact('id'));
$this->permissionService->checkPermission($this->cardMapper, $id, Acl::PERMISSION_EDIT); $this->permissionService->checkPermission($this->cardMapper, $id, Acl::PERMISSION_EDIT);
@@ -517,15 +491,13 @@ class CardService {
} }
/** /**
* @param $id
* @return \OCP\AppFramework\Db\Entity
* @throws StatusException * @throws StatusException
* @throws \OCA\Deck\NoPermissionException * @throws \OCA\Deck\NoPermissionException
* @throws \OCP\AppFramework\Db\DoesNotExistException * @throws \OCP\AppFramework\Db\DoesNotExistException
* @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException
* @throws BadRequestException * @throws BadRequestException
*/ */
public function unarchive($id) { public function unarchive(int $id): Card {
$this->cardServiceValidator->check(compact('id')); $this->cardServiceValidator->check(compact('id'));
@@ -546,8 +518,6 @@ class CardService {
} }
/** /**
* @param $id
* @return \OCA\Deck\Db\Card
* @throws StatusException * @throws StatusException
* @throws \OCA\Deck\NoPermissionException * @throws \OCA\Deck\NoPermissionException
* @throws \OCP\AppFramework\Db\DoesNotExistException * @throws \OCP\AppFramework\Db\DoesNotExistException
@@ -599,15 +569,13 @@ class CardService {
} }
/** /**
* @param $cardId
* @param $labelId
* @throws StatusException * @throws StatusException
* @throws \OCA\Deck\NoPermissionException * @throws \OCA\Deck\NoPermissionException
* @throws \OCP\AppFramework\Db\DoesNotExistException * @throws \OCP\AppFramework\Db\DoesNotExistException
* @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException
* @throws BadRequestException * @throws BadRequestException
*/ */
public function assignLabel($cardId, $labelId) { public function assignLabel(int $cardId, int $labelId): Card {
$this->cardServiceValidator->check(compact('cardId', 'labelId')); $this->cardServiceValidator->check(compact('cardId', 'labelId'));
$this->permissionService->checkPermission($this->cardMapper, $cardId, Acl::PERMISSION_EDIT); $this->permissionService->checkPermission($this->cardMapper, $cardId, Acl::PERMISSION_EDIT);
@@ -629,18 +597,16 @@ class CardService {
$this->activityManager->triggerEvent(ActivityManager::DECK_OBJECT_CARD, $card, ActivityManager::SUBJECT_LABEL_ASSIGN, ['label' => $label]); $this->activityManager->triggerEvent(ActivityManager::DECK_OBJECT_CARD, $card, ActivityManager::SUBJECT_LABEL_ASSIGN, ['label' => $label]);
$this->eventDispatcher->dispatchTyped(new CardUpdatedEvent($card)); $this->eventDispatcher->dispatchTyped(new CardUpdatedEvent($card));
return $card;
} }
/** /**
* @param $cardId
* @param $labelId
* @throws StatusException
* @throws \OCA\Deck\NoPermissionException * @throws \OCA\Deck\NoPermissionException
* @throws \OCP\AppFramework\Db\DoesNotExistException * @throws \OCP\AppFramework\Db\DoesNotExistException
* @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException
* @throws BadRequestException * @throws BadRequestException
*/ */
public function removeLabel($cardId, $labelId) { public function removeLabel(int $cardId, int $labelId): Card {
$this->cardServiceValidator->check(compact('cardId', 'labelId')); $this->cardServiceValidator->check(compact('cardId', 'labelId'));
@@ -660,6 +626,7 @@ class CardService {
$this->activityManager->triggerEvent(ActivityManager::DECK_OBJECT_CARD, $card, ActivityManager::SUBJECT_LABEL_UNASSING, ['label' => $label]); $this->activityManager->triggerEvent(ActivityManager::DECK_OBJECT_CARD, $card, ActivityManager::SUBJECT_LABEL_UNASSING, ['label' => $label]);
$this->eventDispatcher->dispatchTyped(new CardUpdatedEvent($card)); $this->eventDispatcher->dispatchTyped(new CardUpdatedEvent($card));
return $card;
} }
public function getCardUrl(int $cardId): string { public function getCardUrl(int $cardId): string {

View File

@@ -66,7 +66,7 @@ class CirclesService {
$circlesManager->startSession($federatedUser); $circlesManager->startSession($federatedUser);
$circle = $circlesManager->getCircle($circleId); $circle = $circlesManager->getCircle($circleId);
$member = $circle->getInitiator(); $member = $circle->getInitiator();
$isUserInCircle = $member !== null && $member->getLevel() >= Member::LEVEL_MEMBER; $isUserInCircle = $member->getLevel() >= Member::LEVEL_MEMBER;
if (!isset($this->userCircleCache[$circleId])) { if (!isset($this->userCircleCache[$circleId])) {
$this->userCircleCache[$circleId] = []; $this->userCircleCache[$circleId] = [];

View File

@@ -22,8 +22,6 @@ use OCP\IUserManager;
use OutOfBoundsException; use OutOfBoundsException;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
use function is_numeric;
class CommentService { class CommentService {
public function __construct( public function __construct(
@@ -36,12 +34,9 @@ class CommentService {
) { ) {
} }
public function list(string $cardId, int $limit = 20, int $offset = 0): DataResponse { public function list(int $cardId, int $limit = 20, int $offset = 0): DataResponse {
if (!is_numeric($cardId)) {
throw new BadRequestException('A valid card id must be provided');
}
$this->permissionService->checkPermission($this->cardMapper, $cardId, Acl::PERMISSION_READ); $this->permissionService->checkPermission($this->cardMapper, $cardId, Acl::PERMISSION_READ);
$comments = $this->commentsManager->getForObject(Application::COMMENT_ENTITY_TYPE, $cardId, $limit, $offset); $comments = $this->commentsManager->getForObject(Application::COMMENT_ENTITY_TYPE, (string)$cardId, $limit, $offset);
$result = []; $result = [];
foreach ($comments as $comment) { foreach ($comments as $comment) {
$formattedComment = $this->formatComment($comment); $formattedComment = $this->formatComment($comment);
@@ -96,13 +91,13 @@ class CommentService {
* @throws BadRequestException * @throws BadRequestException
* @throws NotFoundException|NoPermissionException * @throws NotFoundException|NoPermissionException
*/ */
public function create(int $cardId, string $message, string $replyTo = '0'): DataResponse { public function create(int $cardId, string $message, int $replyTo = 0): DataResponse {
$this->permissionService->checkPermission($this->cardMapper, $cardId, Acl::PERMISSION_READ); $this->permissionService->checkPermission($this->cardMapper, $cardId, Acl::PERMISSION_READ);
// Check if parent is a comment on the same card // Check if parent is a comment on the same card
if ($replyTo !== '0') { if ($replyTo !== 0) {
try { try {
$comment = $this->commentsManager->get($replyTo); $comment = $this->commentsManager->get((string)$replyTo);
if ($comment->getObjectType() !== Application::COMMENT_ENTITY_TYPE || (int)$comment->getObjectId() !== $cardId) { if ($comment->getObjectType() !== Application::COMMENT_ENTITY_TYPE || (int)$comment->getObjectId() !== $cardId) {
throw new CommentNotFoundException(); throw new CommentNotFoundException();
} }
@@ -115,7 +110,7 @@ class CommentService {
$comment = $this->commentsManager->create('users', $this->userId, Application::COMMENT_ENTITY_TYPE, (string)$cardId); $comment = $this->commentsManager->create('users', $this->userId, Application::COMMENT_ENTITY_TYPE, (string)$cardId);
$comment->setMessage($message); $comment->setMessage($message);
$comment->setVerb('comment'); $comment->setVerb('comment');
$comment->setParentId($replyTo); $comment->setParentId((string)$replyTo);
$this->commentsManager->save($comment); $this->commentsManager->save($comment);
return new DataResponse($this->formatComment($comment, true)); return new DataResponse($this->formatComment($comment, true));
} catch (\InvalidArgumentException $e) { } catch (\InvalidArgumentException $e) {
@@ -128,14 +123,8 @@ class CommentService {
} }
} }
public function update(string $cardId, string $commentId, string $message): DataResponse { public function update(int $cardId, int $commentId, string $message): DataResponse {
if (!is_numeric($cardId)) { $comment = $this->get($cardId, $commentId);
throw new BadRequestException('A valid card id must be provided');
}
if (!is_numeric($commentId)) {
throw new BadRequestException('A valid comment id must be provided');
}
$comment = $this->get((int)$cardId, (int)$commentId);
if ($comment->getActorType() !== 'users' || $comment->getActorId() !== $this->userId) { if ($comment->getActorType() !== 'users' || $comment->getActorId() !== $this->userId) {
throw new NoPermissionException('Only authors are allowed to edit their comment.'); throw new NoPermissionException('Only authors are allowed to edit their comment.');
} }
@@ -145,18 +134,12 @@ class CommentService {
return new DataResponse($this->formatComment($comment)); return new DataResponse($this->formatComment($comment));
} }
public function delete(string $cardId, string $commentId): DataResponse { public function delete(int $cardId, int $commentId): DataResponse {
if (!is_numeric($cardId)) {
throw new BadRequestException('A valid card id must be provided');
}
if (!is_numeric($commentId)) {
throw new BadRequestException('A valid comment id must be provided');
}
$this->permissionService->checkPermission($this->cardMapper, $cardId, Acl::PERMISSION_READ); $this->permissionService->checkPermission($this->cardMapper, $cardId, Acl::PERMISSION_READ);
try { try {
$comment = $this->commentsManager->get($commentId); $comment = $this->commentsManager->get((string)$commentId);
if ($comment->getObjectType() !== Application::COMMENT_ENTITY_TYPE || $comment->getObjectId() !== $cardId) { if ($comment->getObjectType() !== Application::COMMENT_ENTITY_TYPE || (int)$comment->getObjectId() !== $cardId) {
throw new CommentNotFoundException(); throw new CommentNotFoundException();
} }
} catch (CommentNotFoundException $e) { } catch (CommentNotFoundException $e) {
@@ -165,11 +148,11 @@ class CommentService {
if ($comment->getActorType() !== 'users' || $comment->getActorId() !== $this->userId) { if ($comment->getActorType() !== 'users' || $comment->getActorId() !== $this->userId) {
throw new NoPermissionException('Only authors are allowed to edit their comment.'); throw new NoPermissionException('Only authors are allowed to edit their comment.');
} }
$this->commentsManager->delete($commentId); $this->commentsManager->delete((string)$commentId);
return new DataResponse([]); return new DataResponse([]);
} }
private function formatComment(IComment $comment, $addReplyTo = false): array { private function formatComment(IComment $comment, bool $addReplyTo = false): array {
$actorDisplayName = $this->userManager->getDisplayName($comment->getActorId()) ?? $comment->getActorId(); $actorDisplayName = $this->userManager->getDisplayName($comment->getActorId()) ?? $comment->getActorId();
$formattedComment = [ $formattedComment = [

View File

@@ -48,7 +48,8 @@ class ConfigService {
} }
public function getAll(): array { public function getAll(): array {
if ($this->getUserId() === null) { $userId = $this->getUserId();
if ($userId === null) {
return []; return [];
} }
@@ -57,7 +58,7 @@ class ConfigService {
'cardDetailsInModal' => $this->isCardDetailsInModal(), 'cardDetailsInModal' => $this->isCardDetailsInModal(),
'cardIdBadge' => $this->isCardIdBadgeEnabled() 'cardIdBadge' => $this->isCardIdBadgeEnabled()
]; ];
if ($this->groupManager->isAdmin($this->getUserId())) { if ($this->groupManager->isAdmin($userId)) {
$data['groupLimit'] = $this->get('groupLimit'); $data['groupLimit'] = $this->get('groupLimit');
} }
return $data; return $data;
@@ -95,44 +96,48 @@ class ConfigService {
} }
public function isCalendarEnabled(?int $boardId = null): bool { public function isCalendarEnabled(?int $boardId = null): bool {
if ($this->getUserId() === null) { $userId = $this->getUserId();
if ($userId === null) {
return false; return false;
} }
$appConfigState = $this->config->getAppValue(Application::APP_ID, 'calendar', 'yes') === 'yes'; $appConfigState = $this->config->getAppValue(Application::APP_ID, 'calendar', 'yes') === 'yes';
$defaultState = (bool)$this->config->getUserValue($this->getUserId(), Application::APP_ID, 'calendar', $appConfigState); $defaultState = (bool)$this->config->getUserValue($userId, Application::APP_ID, 'calendar', $appConfigState);
if ($boardId === null) { if ($boardId === null) {
return $defaultState; return $defaultState;
} }
return (bool)$this->config->getUserValue($this->getUserId(), Application::APP_ID, 'board:' . $boardId . ':calendar', $defaultState); return (bool)$this->config->getUserValue($userId, Application::APP_ID, 'board:' . $boardId . ':calendar', $defaultState);
} }
public function isCardDetailsInModal(?int $boardId = null): bool { public function isCardDetailsInModal(?int $boardId = null): bool {
if ($this->getUserId() === null) { $userId = $this->getUserId();
if ($userId === null) {
return false; return false;
} }
$defaultState = (bool)$this->config->getUserValue($this->getUserId(), Application::APP_ID, 'cardDetailsInModal', true); $defaultState = (bool)$this->config->getUserValue($userId, Application::APP_ID, 'cardDetailsInModal', true);
if ($boardId === null) { if ($boardId === null) {
return $defaultState; return $defaultState;
} }
return (bool)$this->config->getUserValue($this->getUserId(), Application::APP_ID, 'board:' . $boardId . ':cardDetailsInModal', $defaultState); return (bool)$this->config->getUserValue($userId, Application::APP_ID, 'board:' . $boardId . ':cardDetailsInModal', $defaultState);
} }
public function isCardIdBadgeEnabled(): bool { public function isCardIdBadgeEnabled(): bool {
if ($this->getUserId() === null) { $userId = $this->getUserId();
if ($userId === null) {
return false; return false;
} }
$appConfigState = $this->config->getAppValue(Application::APP_ID, 'cardIdBadge', 'yes') === 'no'; $appConfigState = $this->config->getAppValue(Application::APP_ID, 'cardIdBadge', 'yes') === 'no';
$defaultState = (bool)$this->config->getUserValue($this->getUserId(), Application::APP_ID, 'cardIdBadge', $appConfigState); $defaultState = (bool)$this->config->getUserValue($userId, Application::APP_ID, 'cardIdBadge', $appConfigState);
return (bool)$this->config->getUserValue($this->getUserId(), Application::APP_ID, 'cardIdBadge', $defaultState); return (bool)$this->config->getUserValue($userId, Application::APP_ID, 'cardIdBadge', $defaultState);
} }
public function set($key, $value) { public function set($key, $value) {
if ($this->getUserId() === null) { $userId = $this->getUserId();
if ($userId === null) {
throw new NoPermissionException('Must be logged in to set user config'); throw new NoPermissionException('Must be logged in to set user config');
} }
@@ -140,21 +145,21 @@ class ConfigService {
[$scope] = explode(':', $key, 2); [$scope] = explode(':', $key, 2);
switch ($scope) { switch ($scope) {
case 'groupLimit': case 'groupLimit':
if (!$this->groupManager->isAdmin($this->getUserId())) { if (!$this->groupManager->isAdmin($userId)) {
throw new NoPermissionException('You must be admin to set the group limit'); throw new NoPermissionException('You must be admin to set the group limit');
} }
$result = $this->setGroupLimit($value); $result = $this->setGroupLimit($value);
break; break;
case 'calendar': case 'calendar':
$this->config->setUserValue($this->getUserId(), Application::APP_ID, 'calendar', (string)$value); $this->config->setUserValue($userId, Application::APP_ID, 'calendar', (string)$value);
$result = $value; $result = $value;
break; break;
case 'cardDetailsInModal': case 'cardDetailsInModal':
$this->config->setUserValue($this->getUserId(), Application::APP_ID, 'cardDetailsInModal', (string)$value); $this->config->setUserValue($userId, Application::APP_ID, 'cardDetailsInModal', (string)$value);
$result = $value; $result = $value;
break; break;
case 'cardIdBadge': case 'cardIdBadge':
$this->config->setUserValue($this->getUserId(), Application::APP_ID, 'cardIdBadge', (string)$value); $this->config->setUserValue($userId, Application::APP_ID, 'cardIdBadge', (string)$value);
$result = $value; $result = $value;
break; break;
case 'board': case 'board':
@@ -162,7 +167,7 @@ class ConfigService {
if ($boardConfigKey === 'notify-due' && !in_array($value, [self::SETTING_BOARD_NOTIFICATION_DUE_ALL, self::SETTING_BOARD_NOTIFICATION_DUE_ASSIGNED, self::SETTING_BOARD_NOTIFICATION_DUE_OFF], true)) { if ($boardConfigKey === 'notify-due' && !in_array($value, [self::SETTING_BOARD_NOTIFICATION_DUE_ALL, self::SETTING_BOARD_NOTIFICATION_DUE_ASSIGNED, self::SETTING_BOARD_NOTIFICATION_DUE_OFF], true)) {
throw new BadRequestException('Board notification option must be one of: off, assigned, all'); throw new BadRequestException('Board notification option must be one of: off, assigned, all');
} }
$this->config->setUserValue($this->getUserId(), Application::APP_ID, $key, (string)$value); $this->config->setUserValue($userId, Application::APP_ID, $key, (string)$value);
$result = $value; $result = $value;
} }
return $result; return $result;

View File

@@ -124,18 +124,15 @@ class FullTextSearchService {
/** /**
* @param int $cardId
*
* @return Board
* @throws DoesNotExistException * @throws DoesNotExistException
* @throws MultipleObjectsReturnedException * @throws MultipleObjectsReturnedException
*/ */
public function getBoardFromCardId(int $cardId): Board { public function getBoardFromCardId(int $cardId): Board {
$boardId = (int)$this->cardMapper->findBoardId($cardId); $boardId = $this->cardMapper->findBoardId($cardId);
/** @var Board $board */ if ($boardId === null) {
$board = $this->boardMapper->find($boardId); throw new DoesNotExistException("Board '$cardId' does not exist");
}
return $board; return $this->boardMapper->find($boardId);
} }
@@ -145,7 +142,7 @@ class FullTextSearchService {
* @return Card[] * @return Card[]
*/ */
private function getCardsFromStack(int $stackId): array { private function getCardsFromStack(int $stackId): array {
return $this->cardMapper->findAll($stackId, null, null); return $this->cardMapper->findAll($stackId);
} }
@@ -155,7 +152,7 @@ class FullTextSearchService {
* @return Stack[] * @return Stack[]
*/ */
private function getStacksFromBoard(int $boardId): array { private function getStacksFromBoard(int $boardId): array {
return $this->stackMapper->findAll($boardId, null, null); return $this->stackMapper->findAll($boardId);
} }
@@ -165,6 +162,6 @@ class FullTextSearchService {
* @return Board[] * @return Board[]
*/ */
private function getBoardsFromUser(string $userId): array { private function getBoardsFromUser(string $userId): array {
return $this->boardMapper->findAllByUser($userId, null, null, null); return $this->boardMapper->findAllByUser($userId);
} }
} }

View File

@@ -19,29 +19,25 @@ use OCP\Comments\IComment;
abstract class ABoardImportService { abstract class ABoardImportService {
/** @var string */ /** @var string */
public static $name = ''; public static $name = '';
/** @var BoardImportService */ private BoardImportService $boardImportService;
private $boardImportService; protected bool $needValidateData = true;
/** @var bool */
protected $needValidateData = true;
/** @var Stack[] */ /** @var Stack[] */
protected $stacks = []; protected array $stacks = [];
/** @var Label[] */ /** @var Label[] */
protected $labels = []; protected array $labels = [];
/** @var Card[] */ /** @var Card[] */
protected $cards = []; protected array $cards = [];
/** @var Acl[] */ /** @var Acl[] */
protected $acls = []; protected array $acls = [];
/** @var IComment[][] */ /** @var IComment[][] */
protected $comments = []; protected array $comments = [];
/** @var Assignment[] */ /** @var Assignment[] */
protected $assignments = []; protected array $assignments = [];
/** @var string[][] */ /** @var int[][] */
protected $labelCardAssignments = []; protected array $labelCardAssignments = [];
/** /**
* Configure import service * Configure import service
*
* @return void
*/ */
abstract public function bootstrap(): void; abstract public function bootstrap(): void;
@@ -68,10 +64,13 @@ abstract class ABoardImportService {
abstract public function getCardAssignments(): array; abstract public function getCardAssignments(): array;
/**
* @return array<int, array<int, int>>
*/
abstract public function getCardLabelAssignment(): array; abstract public function getCardLabelAssignment(): array;
/** /**
* @return IComment[][]|array * @return array<int, array<string, IComment>>
*/ */
abstract public function getComments(): array; abstract public function getComments(): array;
@@ -98,16 +97,16 @@ abstract class ABoardImportService {
$this->acls[$code] = $acl; $this->acls[$code] = $acl;
} }
public function updateComment(string $cardId, string $commentId, IComment $comment): void { public function updateComment(int $cardId, string $commentId, IComment $comment): void {
$this->comments[$cardId][$commentId] = $comment; $this->comments[$cardId][$commentId] = $comment;
} }
public function updateCardAssignment(string $cardId, string $assignmentId, Entity $assignment): void { public function updateCardAssignment(int $cardId, int $assignmentId, Entity $assignment): void {
$this->assignments[$cardId][$assignmentId] = $assignment; $this->assignments[$cardId][$assignmentId] = $assignment;
} }
public function updateCardLabelsAssignment(string $cardId, string $assignmentId, string $assignment): void { public function updateCardLabelsAssignment(int $cardId, int $assignmentId, int $labelId): void {
$this->labelCardAssignments[$cardId][$assignmentId] = $assignment; $this->labelCardAssignments[$cardId][$assignmentId] = $labelId;
} }
public function setImportService(BoardImportService $service): void { public function setImportService(BoardImportService $service): void {

View File

@@ -209,14 +209,15 @@ class BoardImportService {
public function importBoard(): void { public function importBoard(): void {
$board = $this->getImportSystem()->getBoard(); $board = $this->getImportSystem()->getBoard();
if ($board === null) {
throw new \LogicException('Import board not found');
}
if (!$this->userManager->userExists($board->getOwner())) { if (!$this->userManager->userExists($board->getOwner())) {
throw new \Exception('Target owner ' . $board->getOwner() . ' not found. Please provide a mapping through the import config.'); throw new \Exception('Target owner ' . $board->getOwner() . ' not found. Please provide a mapping through the import config.');
} }
if ($board) { $this->boardMapper->insert($board);
$this->boardMapper->insert($board); $this->board = $board;
$this->board = $board;
}
} }
public function getBoard(bool $reset = false): Board { public function getBoard(bool $reset = false): Board {
@@ -292,12 +293,7 @@ class BoardImportService {
} }
} }
/** public function assignCardToLabel(int $cardId, int $labelId): self {
* @param mixed $cardId
* @param mixed $labelId
* @return self
*/
public function assignCardToLabel($cardId, $labelId): self {
$this->cardMapper->assignLabel( $this->cardMapper->assignLabel(
$cardId, $cardId,
$labelId $labelId
@@ -307,14 +303,14 @@ class BoardImportService {
public function assignCardsToLabels(): void { public function assignCardsToLabels(): void {
$data = $this->getImportSystem()->getCardLabelAssignment(); $data = $this->getImportSystem()->getCardLabelAssignment();
foreach ($data as $cardId => $assignemnt) { foreach ($data as $cardId => $assignment) {
foreach ($assignemnt as $assignmentId => $labelId) { foreach ($assignment as $assignmentId => $labelId) {
try { try {
$this->assignCardToLabel( $this->assignCardToLabel(
$cardId, (int)$cardId,
$labelId $labelId
); );
$this->getImportSystem()->updateCardLabelsAssignment($cardId, $assignmentId, $labelId); $this->getImportSystem()->updateCardLabelsAssignment((int)$cardId, (int)$assignmentId, $labelId);
} catch (\Exception $e) { } catch (\Exception $e) {
$this->addError('Failed to assign label ' . $labelId . ' to ' . $cardId, $e); $this->addError('Failed to assign label ' . $labelId . ' to ' . $cardId, $e);
} }
@@ -326,20 +322,20 @@ class BoardImportService {
$allComments = $this->getImportSystem()->getComments(); $allComments = $this->getImportSystem()->getComments();
foreach ($allComments as $cardId => $comments) { foreach ($allComments as $cardId => $comments) {
foreach ($comments as $commentId => $comment) { foreach ($comments as $commentId => $comment) {
$this->insertComment($cardId, $comment); $this->insertComment((int)$cardId, $comment);
$this->getImportSystem()->updateComment($cardId, $commentId, $comment); $this->getImportSystem()->updateComment((int)$cardId, $commentId, $comment);
} }
} }
} }
private function insertComment(string $cardId, IComment $comment): void { private function insertComment(int $cardId, IComment $comment): void {
$comment->setObject('deckCard', $cardId); $comment->setObject('deckCard', (string)$cardId);
$comment->setVerb('comment'); $comment->setVerb('comment');
// Check if parent is a comment on the same card // Check if parent is a comment on the same card
if ($comment->getParentId() !== '0') { if ($comment->getParentId() !== '0') {
try { try {
$parent = $this->commentsManager->get($comment->getParentId()); $parent = $this->commentsManager->get($comment->getParentId());
if ($parent->getObjectType() !== Application::COMMENT_ENTITY_TYPE || $parent->getObjectId() !== $cardId) { if ($parent->getObjectType() !== Application::COMMENT_ENTITY_TYPE || (int)$parent->getObjectId() !== $cardId) {
throw new CommentNotFoundException(); throw new CommentNotFoundException();
} }
} catch (CommentNotFoundException $e) { } catch (CommentNotFoundException $e) {
@@ -362,7 +358,7 @@ class BoardImportService {
foreach ($assignments as $assignment) { foreach ($assignments as $assignment) {
try { try {
$assignment = $this->assignmentMapper->insert($assignment); $assignment = $this->assignmentMapper->insert($assignment);
$this->getImportSystem()->updateCardAssignment($cardId, (string)$assignment->getId(), $assignment); $this->getImportSystem()->updateCardAssignment((int)$cardId, $assignment->getId(), $assignment);
$this->addOutput('Assignment ' . $assignment->getParticipant() . ' added'); $this->addOutput('Assignment ' . $assignment->getParticipant() . ' added');
} catch (NotFoundException $e) { } catch (NotFoundException $e) {
$this->addError('No origin or mapping found for card "' . $cardId . '" and ' . $assignment->getTypeString() . ' assignment "' . $assignment->getParticipant(), $e); $this->addError('No origin or mapping found for card "' . $cardId . '" and ' . $assignment->getTypeString() . ' assignment "' . $assignment->getParticipant(), $e);

View File

@@ -16,6 +16,7 @@ use OCA\Deck\Db\Card;
use OCA\Deck\Db\Label; use OCA\Deck\Db\Label;
use OCA\Deck\Db\Stack; use OCA\Deck\Db\Stack;
use OCA\Deck\Service\Importer\ABoardImportService; use OCA\Deck\Service\Importer\ABoardImportService;
use OCP\Comments\IComment;
use OCP\IUser; use OCP\IUser;
use OCP\IUserManager; use OCP\IUserManager;
@@ -118,6 +119,7 @@ class DeckJsonService extends ABoardImportService {
$comments[$this->cards[$sourceCard->id]->getId()][$commentOriginal->id] = $comment; $comments[$this->cards[$sourceCard->id]->getId()][$commentOriginal->id] = $comment;
} }
} }
/** @var array<int, array<string, IComment>> */
return $comments; return $comments;
} }

View File

@@ -17,7 +17,7 @@ use Psr\Log\LoggerInterface;
class TrelloApiService extends TrelloJsonService { class TrelloApiService extends TrelloJsonService {
/** @var string */ /** @var string */
public static $name = 'Trello API'; public static $name = 'Trello API';
protected $needValidateData = false; protected bool $needValidateData = false;
/** @var IClient */ /** @var IClient */
private $httpClient; private $httpClient;
/** @var LoggerInterface */ /** @var LoggerInterface */
@@ -176,7 +176,7 @@ class TrelloApiService extends TrelloJsonService {
if (empty($queryString['limit'])) { if (empty($queryString['limit'])) {
return []; return [];
} }
if (count($data) < $queryString['limit']) { if ((count($data) < $queryString['limit']) || (count($data) === 0)) {
return []; return [];
} }
$queryString['before'] = end($data)->id; $queryString['before'] = end($data)->id;

View File

@@ -159,6 +159,7 @@ class TrelloJsonService extends ABoardImportService {
$comments[$cardId][$commentId] = $comment; $comments[$cardId][$commentId] = $comment;
} }
} }
/** @var array<int, array<string, IComment>> */
return $comments; return $comments;
} }

View File

@@ -43,33 +43,24 @@ class LabelService {
} }
/** /**
* @param $labelId
* @return \OCP\AppFramework\Db\Entity
* @throws \OCA\Deck\NoPermissionException * @throws \OCA\Deck\NoPermissionException
* @throws \OCP\AppFramework\Db\DoesNotExistException * @throws \OCP\AppFramework\Db\DoesNotExistException
* @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException
* @throws BadRequestException * @throws BadRequestException
*/ */
public function find($labelId) { public function find(int $labelId): Label {
if (is_numeric($labelId) === false) {
throw new BadRequestException('label id must be a number');
}
$this->permissionService->checkPermission($this->labelMapper, $labelId, Acl::PERMISSION_READ); $this->permissionService->checkPermission($this->labelMapper, $labelId, Acl::PERMISSION_READ);
return $this->labelMapper->find($labelId); return $this->labelMapper->find($labelId);
} }
/** /**
* @param $title
* @param $color
* @param $boardId
* @return \OCP\AppFramework\Db\Entity
* @throws StatusException * @throws StatusException
* @throws \OCA\Deck\NoPermissionException * @throws \OCA\Deck\NoPermissionException
* @throws \OCP\AppFramework\Db\DoesNotExistException * @throws \OCP\AppFramework\Db\DoesNotExistException
* @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException
* @throws BadRequestException * @throws BadRequestException
*/ */
public function create($title, $color, $boardId) { public function create(string $title, string $color, int $boardId): Label {
$this->labelServiceValidator->check(compact('title', 'color', 'boardId')); $this->labelServiceValidator->check(compact('title', 'color', 'boardId'));
$this->permissionService->checkPermission(null, $boardId, Acl::PERMISSION_MANAGE); $this->permissionService->checkPermission(null, $boardId, Acl::PERMISSION_MANAGE);
@@ -106,15 +97,13 @@ class LabelService {
} }
/** /**
* @param $id
* @return \OCP\AppFramework\Db\Entity
* @throws StatusException * @throws StatusException
* @throws \OCA\Deck\NoPermissionException * @throws \OCA\Deck\NoPermissionException
* @throws \OCP\AppFramework\Db\DoesNotExistException * @throws \OCP\AppFramework\Db\DoesNotExistException
* @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException
* @throws BadRequestException * @throws BadRequestException
*/ */
public function delete($id) { public function delete(int $id): Label {
$this->labelServiceValidator->check(compact('id')); $this->labelServiceValidator->check(compact('id'));
$this->permissionService->checkPermission($this->labelMapper, $id, Acl::PERMISSION_MANAGE); $this->permissionService->checkPermission($this->labelMapper, $id, Acl::PERMISSION_MANAGE);
@@ -127,17 +116,13 @@ class LabelService {
} }
/** /**
* @param $id
* @param $title
* @param $color
* @return \OCP\AppFramework\Db\Entity
* @throws StatusException * @throws StatusException
* @throws \OCA\Deck\NoPermissionException * @throws \OCA\Deck\NoPermissionException
* @throws \OCP\AppFramework\Db\DoesNotExistException * @throws \OCP\AppFramework\Db\DoesNotExistException
* @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException
* @throws BadRequestException * @throws BadRequestException
*/ */
public function update($id, $title, $color) { public function update(int $id, string $title, string $color): Label {
$this->labelServiceValidator->check(compact('title', 'color', 'id')); $this->labelServiceValidator->check(compact('title', 'color', 'id'));
$this->permissionService->checkPermission($this->labelMapper, $id, Acl::PERMISSION_MANAGE); $this->permissionService->checkPermission($this->labelMapper, $id, Acl::PERMISSION_MANAGE);

View File

@@ -9,53 +9,28 @@ declare(strict_types=1);
namespace OCA\Deck\Service; namespace OCA\Deck\Service;
use OCA\Deck\Db\AssignmentMapper;
use OCA\Deck\Db\Board; use OCA\Deck\Db\Board;
use OCA\Deck\Db\BoardMapper; use OCA\Deck\Db\BoardMapper;
use OCA\Deck\Db\CardMapper; use OCA\Deck\Db\CardMapper;
use OCA\Deck\Db\LabelMapper;
use OCA\Deck\Model\CardDetails; use OCA\Deck\Model\CardDetails;
use OCP\Comments\ICommentsManager;
use OCP\IUserManager;
class OverviewService { class OverviewService {
private CardService $cardService;
private BoardMapper $boardMapper;
private LabelMapper $labelMapper;
private CardMapper $cardMapper;
private AssignmentMapper $assignedUsersMapper;
private IUserManager $userManager;
private ICommentsManager $commentsManager;
private AttachmentService $attachmentService;
public function __construct( public function __construct(
CardService $cardService, private readonly CardService $cardService,
BoardMapper $boardMapper, private readonly BoardMapper $boardMapper,
LabelMapper $labelMapper, private readonly CardMapper $cardMapper,
CardMapper $cardMapper,
AssignmentMapper $assignedUsersMapper,
IUserManager $userManager,
ICommentsManager $commentsManager,
AttachmentService $attachmentService,
) { ) {
$this->cardService = $cardService;
$this->boardMapper = $boardMapper;
$this->labelMapper = $labelMapper;
$this->cardMapper = $cardMapper;
$this->assignedUsersMapper = $assignedUsersMapper;
$this->userManager = $userManager;
$this->commentsManager = $commentsManager;
$this->attachmentService = $attachmentService;
} }
public function findUpcomingCards(string $userId): array { public function findUpcomingCards(string $userId): array {
$userBoards = $this->boardMapper->findAllForUser($userId); $userBoards = $this->boardMapper->findAllForUser($userId);
$boardOwnerIds = array_filter(array_map(function (Board $board) { $boardOwnerIds = array_filter(array_map(function (Board $board) {
return count($board->getAcl()) === 0 ? $board->getId() : null; return count($board->getAcl() ?? []) === 0 ? $board->getId() : null;
}, $userBoards)); }, $userBoards));
$boardSharedIds = array_filter(array_map(function (Board $board) { $boardSharedIds = array_filter(array_map(function (Board $board) {
return count($board->getAcl()) > 0 ? $board->getId() : null; return count($board->getAcl() ?? []) > 0 ? $board->getId() : null;
}, $userBoards)); }, $userBoards));
$foundCards = array_merge( $foundCards = array_merge(

View File

@@ -29,6 +29,7 @@ class PermissionService {
private array $users = []; private array $users = [];
private CappedMemoryCache $boardCache; private CappedMemoryCache $boardCache;
/** @var CappedMemoryCache<array<Acl::PERMISSION_*, bool>> */
private CappedMemoryCache $permissionCache; private CappedMemoryCache $permissionCache;
public function __construct( public function __construct(
@@ -49,15 +50,16 @@ class PermissionService {
/** /**
* Get current user permissions for a board by id * Get current user permissions for a board by id
* *
* @return bool|array * @return array<Acl::PERMISSION_*, bool>
*/ */
public function getPermissions(int $boardId, ?string $userId = null) { public function getPermissions(int $boardId, ?string $userId = null): array {
if ($userId === null) { if ($userId === null) {
$userId = $this->userId; $userId = $this->userId;
} }
$cacheKey = $boardId . '-' . $userId; $cacheKey = $boardId . '-' . $userId;
if ($cached = $this->permissionCache->get($cacheKey)) { if ($cached = $this->permissionCache->get($cacheKey)) {
/** @var array<Acl::PERMISSION_*, bool> $cached */
return $cached; return $cached;
} }

View File

@@ -77,7 +77,7 @@ class StackService {
/** @param Stack[] $stacks */ /** @param Stack[] $stacks */
private function enrichStacksWithCards(array $stacks, $since = -1): void { private function enrichStacksWithCards(array $stacks, $since = -1): void {
$cardsByStackId = $this->cardMapper->findAllForStacks(array_map(fn (Stack $stack) => $stack->getId(), $stacks), null, null, $since); $cardsByStackId = $this->cardMapper->findAllForStacks(array_map(fn (Stack $stack) => $stack->getId(), $stacks), null, 0, $since);
foreach ($cardsByStackId as $stackId => $cards) { foreach ($cardsByStackId as $stackId => $cards) {
if (!$cards) { if (!$cards) {
@@ -95,18 +95,11 @@ class StackService {
} }
/** /**
* @param $stackId
*
* @return \OCP\AppFramework\Db\Entity
* @throws \OCP\AppFramework\Db\DoesNotExistException * @throws \OCP\AppFramework\Db\DoesNotExistException
* @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException
* @throws BadRequestException * @throws BadRequestException
*/ */
public function find($stackId) { public function find(int $stackId): Stack {
if (is_numeric($stackId) === false) {
throw new BadRequestException('stack id must be a number');
}
$this->permissionService->checkPermission($this->stackMapper, $stackId, Acl::PERMISSION_READ); $this->permissionService->checkPermission($this->stackMapper, $stackId, Acl::PERMISSION_READ);
$stack = $this->stackMapper->find($stackId); $stack = $this->stackMapper->find($stackId);
@@ -127,17 +120,11 @@ class StackService {
} }
/** /**
* @param mixed $boardId
*
* @return Stack[] * @return Stack[]
* @throws \OCA\Deck\NoPermissionException * @throws \OCA\Deck\NoPermissionException
* @throws BadRequestException * @throws BadRequestException
*/ */
public function findAll($boardId, $since = -1) { public function findAll(int $boardId, int $since = -1): array {
if (is_numeric($boardId) === false) {
throw new BadRequestException('boardId must be a number');
}
$this->permissionService->checkPermission(null, $boardId, Acl::PERMISSION_READ); $this->permissionService->checkPermission(null, $boardId, Acl::PERMISSION_READ);
$stacks = $this->stackMapper->findAll($boardId); $stacks = $this->stackMapper->findAll($boardId);
$this->enrichStacksWithCards($stacks, $since); $this->enrichStacksWithCards($stacks, $since);
@@ -145,7 +132,11 @@ class StackService {
return $stacks; return $stacks;
} }
public function findCalendarEntries($boardId) { /**
* @return Stack[]
* @throws \OCP\DB\Exception
*/
public function findCalendarEntries(int $boardId): array {
try { try {
$this->permissionService->checkPermission(null, $boardId, Acl::PERMISSION_READ); $this->permissionService->checkPermission(null, $boardId, Acl::PERMISSION_READ);
} catch (NoPermissionException $e) { } catch (NoPermissionException $e) {
@@ -155,7 +146,11 @@ class StackService {
return $this->stackMapper->findAll($boardId); return $this->stackMapper->findAll($boardId);
} }
public function fetchDeleted($boardId) { /**
* @return Stack[]
* @throws \OCP\DB\Exception
*/
public function fetchDeleted(int $boardId): array {
$this->permissionService->checkPermission($this->boardMapper, $boardId, Acl::PERMISSION_READ); $this->permissionService->checkPermission($this->boardMapper, $boardId, Acl::PERMISSION_READ);
$stacks = $this->stackMapper->findDeleted($boardId); $stacks = $this->stackMapper->findDeleted($boardId);
$this->enrichStacksWithCards($stacks); $this->enrichStacksWithCards($stacks);
@@ -164,17 +159,11 @@ class StackService {
} }
/** /**
* @param $boardId * @return Stack[]
*
* @return array
* @throws \OCA\Deck\NoPermissionException * @throws \OCA\Deck\NoPermissionException
* @throws BadRequestException * @throws BadRequestException
*/ */
public function findAllArchived($boardId) { public function findAllArchived(int $boardId): array {
if (is_numeric($boardId) === false) {
throw new BadRequestException('board id must be a number');
}
$this->permissionService->checkPermission(null, $boardId, Acl::PERMISSION_READ); $this->permissionService->checkPermission(null, $boardId, Acl::PERMISSION_READ);
$stacks = $this->stackMapper->findAll($boardId); $stacks = $this->stackMapper->findAll($boardId);
$labels = $this->labelMapper->getAssignedLabelsForBoard($boardId); $labels = $this->labelMapper->getAssignedLabelsForBoard($boardId);
@@ -189,22 +178,18 @@ class StackService {
$stacks[$stackIndex]->setCards($cards); $stacks[$stackIndex]->setCards($cards);
} }
/** @var Stack[] $stacks */
return $stacks; return $stacks;
} }
/** /**
* @param $title
* @param $boardId
* @param integer $order
*
* @return \OCP\AppFramework\Db\Entity
* @throws StatusException * @throws StatusException
* @throws \OCA\Deck\NoPermissionException * @throws \OCA\Deck\NoPermissionException
* @throws \OCP\AppFramework\Db\DoesNotExistException * @throws \OCP\AppFramework\Db\DoesNotExistException
* @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException
* @throws BadRequestException * @throws BadRequestException
*/ */
public function create($title, $boardId, $order) { public function create(string $title, int $boardId, int $order): Stack {
$this->stackServiceValidator->check(compact('title', 'boardId', 'order')); $this->stackServiceValidator->check(compact('title', 'boardId', 'order'));
$this->permissionService->checkPermission(null, $boardId, Acl::PERMISSION_MANAGE); $this->permissionService->checkPermission(null, $boardId, Acl::PERMISSION_MANAGE);
@@ -226,19 +211,13 @@ class StackService {
} }
/** /**
* @param $id * @return Stack The deleted stack.
*
* @return \OCP\AppFramework\Db\Entity
* @throws \OCA\Deck\NoPermissionException * @throws \OCA\Deck\NoPermissionException
* @throws \OCP\AppFramework\Db\DoesNotExistException * @throws \OCP\AppFramework\Db\DoesNotExistException
* @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException
* @throws BadRequestException * @throws BadRequestException
*/ */
public function delete($id) { public function delete(int $id): Stack {
if (is_numeric($id) === false) {
throw new BadRequestException('stack id must be a number');
}
$this->permissionService->checkPermission($this->stackMapper, $id, Acl::PERMISSION_MANAGE); $this->permissionService->checkPermission($this->stackMapper, $id, Acl::PERMISSION_MANAGE);
$stack = $this->stackMapper->find($id); $stack = $this->stackMapper->find($id);
@@ -256,20 +235,13 @@ class StackService {
} }
/** /**
* @param $id
* @param $title
* @param $boardId
* @param $order
* @param $deletedAt
*
* @return \OCP\AppFramework\Db\Entity
* @throws StatusException * @throws StatusException
* @throws \OCA\Deck\NoPermissionException * @throws \OCA\Deck\NoPermissionException
* @throws \OCP\AppFramework\Db\DoesNotExistException * @throws \OCP\AppFramework\Db\DoesNotExistException
* @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException
* @throws BadRequestException * @throws BadRequestException
*/ */
public function update($id, $title, $boardId, $order, $deletedAt) { public function update(int $id, string $title, int $boardId, int $order, ?int $deletedAt): Stack {
$this->stackServiceValidator->check(compact('id', 'title', 'boardId', 'order')); $this->stackServiceValidator->check(compact('id', 'title', 'boardId', 'order'));
$this->permissionService->checkPermission($this->stackMapper, $id, Acl::PERMISSION_MANAGE); $this->permissionService->checkPermission($this->stackMapper, $id, Acl::PERMISSION_MANAGE);
@@ -297,16 +269,13 @@ class StackService {
} }
/** /**
* @param $id * @return array<int, Stack> The stacks in the correct order.
* @param $order
*
* @return array
* @throws \OCA\Deck\NoPermissionException * @throws \OCA\Deck\NoPermissionException
* @throws \OCP\AppFramework\Db\DoesNotExistException * @throws \OCP\AppFramework\Db\DoesNotExistException
* @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException
* @throws BadRequestException * @throws BadRequestException
*/ */
public function reorder($id, $order) { public function reorder(int $id, int $order): array {
$this->stackServiceValidator->check(compact('id', 'order')); $this->stackServiceValidator->check(compact('id', 'order'));
$this->permissionService->checkPermission($this->stackMapper, $id, Acl::PERMISSION_MANAGE); $this->permissionService->checkPermission($this->stackMapper, $id, Acl::PERMISSION_MANAGE);
@@ -327,7 +296,7 @@ class StackService {
if ($stack->id !== $id) { if ($stack->id !== $id) {
$stack->setOrder($i++); $stack->setOrder($i++);
} }
$this->stackMapper->update($stack); $stack = $this->stackMapper->update($stack);
$result[$stack->getOrder()] = $stack; $result[$stack->getOrder()] = $stack;
} }
$this->changeHelper->boardChanged($stackToSort->getBoardId()); $this->changeHelper->boardChanged($stackToSort->getBoardId());

View File

@@ -13,7 +13,6 @@ namespace OCA\Deck\Sharing;
use OC\Files\Cache\Cache; use OC\Files\Cache\Cache;
use OCA\Deck\Cache\AttachmentCacheHelper; use OCA\Deck\Cache\AttachmentCacheHelper;
use OCA\Deck\Db\Acl; use OCA\Deck\Db\Acl;
use OCA\Deck\Db\Board;
use OCA\Deck\Db\BoardMapper; use OCA\Deck\Db\BoardMapper;
use OCA\Deck\Db\CardMapper; use OCA\Deck\Db\CardMapper;
use OCA\Deck\Db\User; use OCA\Deck\Db\User;
@@ -99,9 +98,13 @@ class DeckShareProvider implements \OCP\Share\IShareProvider {
* @inheritDoc * @inheritDoc
*/ */
public function create(IShare $share) { public function create(IShare $share) {
$cardId = $share->getSharedWith(); $cardId = (int)$share->getSharedWith();
$boardId = $this->cardMapper->findBoardId($cardId); $boardId = $this->cardMapper->findBoardId($cardId);
$valid = $boardId !== null; $valid = $boardId !== null;
if (!$valid) {
throw new GenericShareException('Card not found', $this->l->t('Card not found'), 404);
}
try { try {
$this->permissionService->checkPermission(null, $boardId, Acl::PERMISSION_EDIT); $this->permissionService->checkPermission(null, $boardId, Acl::PERMISSION_EDIT);
} catch (NoPermissionException $e) { } catch (NoPermissionException $e) {
@@ -147,7 +150,7 @@ class DeckShareProvider implements \OCP\Share\IShareProvider {
); );
$data = $this->getRawShare($shareId); $data = $this->getRawShare($shareId);
$this->attachmentCacheHelper->clearAttachmentCount((int)$cardId); $this->attachmentCacheHelper->clearAttachmentCount($cardId);
return $this->createShareObject($data); return $this->createShareObject($data);
} }
@@ -213,7 +216,7 @@ class DeckShareProvider implements \OCP\Share\IShareProvider {
->from('share') ->from('share')
->where($qb->expr()->eq('id', $qb->createNamedParameter($id))); ->where($qb->expr()->eq('id', $qb->createNamedParameter($id)));
$cursor = $qb->execute(); $cursor = $qb->executeQuery();
$data = $cursor->fetch(); $data = $cursor->fetch();
$cursor->closeCursor(); $cursor->closeCursor();
@@ -297,7 +300,7 @@ class DeckShareProvider implements \OCP\Share\IShareProvider {
->set('item_source', $qb->createNamedParameter($share->getNode()->getId())) ->set('item_source', $qb->createNamedParameter($share->getNode()->getId()))
->set('file_source', $qb->createNamedParameter($share->getNode()->getId())) ->set('file_source', $qb->createNamedParameter($share->getNode()->getId()))
->set('expiration', $qb->createNamedParameter($share->getExpirationDate(), IQueryBuilder::PARAM_DATE)) ->set('expiration', $qb->createNamedParameter($share->getExpirationDate(), IQueryBuilder::PARAM_DATE))
->execute(); ->executeStatement();
/* /*
* Update all user defined group shares * Update all user defined group shares
@@ -310,7 +313,7 @@ class DeckShareProvider implements \OCP\Share\IShareProvider {
->set('item_source', $qb->createNamedParameter($share->getNode()->getId())) ->set('item_source', $qb->createNamedParameter($share->getNode()->getId()))
->set('file_source', $qb->createNamedParameter($share->getNode()->getId())) ->set('file_source', $qb->createNamedParameter($share->getNode()->getId()))
->set('expiration', $qb->createNamedParameter($share->getExpirationDate(), IQueryBuilder::PARAM_DATE)) ->set('expiration', $qb->createNamedParameter($share->getExpirationDate(), IQueryBuilder::PARAM_DATE))
->execute(); ->executeStatement();
/* /*
* Now update the permissions for all children that have not set it to 0 * Now update the permissions for all children that have not set it to 0
@@ -320,7 +323,7 @@ class DeckShareProvider implements \OCP\Share\IShareProvider {
->where($qb->expr()->eq('parent', $qb->createNamedParameter($share->getId()))) ->where($qb->expr()->eq('parent', $qb->createNamedParameter($share->getId())))
->andWhere($qb->expr()->neq('permissions', $qb->createNamedParameter(0))) ->andWhere($qb->expr()->neq('permissions', $qb->createNamedParameter(0)))
->set('permissions', $qb->createNamedParameter($share->getPermissions())) ->set('permissions', $qb->createNamedParameter($share->getPermissions()))
->execute(); ->executeStatement();
return $share; return $share;
} }
@@ -335,7 +338,7 @@ class DeckShareProvider implements \OCP\Share\IShareProvider {
$qb->orWhere($qb->expr()->eq('parent', $qb->createNamedParameter($share->getId()))); $qb->orWhere($qb->expr()->eq('parent', $qb->createNamedParameter($share->getId())));
$qb->execute(); $qb->executeStatement();
$this->attachmentCacheHelper->clearAttachmentCount((int)$share->getSharedWith()); $this->attachmentCacheHelper->clearAttachmentCount((int)$share->getSharedWith());
} }
@@ -355,7 +358,7 @@ class DeckShareProvider implements \OCP\Share\IShareProvider {
$qb->expr()->eq('item_type', $qb->createNamedParameter('file')), $qb->expr()->eq('item_type', $qb->createNamedParameter('file')),
$qb->expr()->eq('item_type', $qb->createNamedParameter('folder')) $qb->expr()->eq('item_type', $qb->createNamedParameter('folder'))
)) ))
->execute(); ->executeQuery();
$data = $stmt->fetch(); $data = $stmt->fetch();
$stmt->closeCursor(); $stmt->closeCursor();
@@ -376,14 +379,14 @@ class DeckShareProvider implements \OCP\Share\IShareProvider {
'file_target' => $qb->createNamedParameter($share->getTarget()), 'file_target' => $qb->createNamedParameter($share->getTarget()),
'permissions' => $qb->createNamedParameter(0), 'permissions' => $qb->createNamedParameter(0),
'stime' => $qb->createNamedParameter($share->getShareTime()->getTimestamp()), 'stime' => $qb->createNamedParameter($share->getShareTime()->getTimestamp()),
])->execute(); ])->executeStatement();
} elseif ($data['permissions'] !== 0) { } elseif ($data['permissions'] !== 0) {
// Already a userroom share. Update it. // Already a userroom share. Update it.
$qb = $this->dbConnection->getQueryBuilder(); $qb = $this->dbConnection->getQueryBuilder();
$qb->update('share') $qb->update('share')
->set('permissions', $qb->createNamedParameter(0)) ->set('permissions', $qb->createNamedParameter(0))
->where($qb->expr()->eq('id', $qb->createNamedParameter($data['id']))) ->where($qb->expr()->eq('id', $qb->createNamedParameter($data['id'])))
->execute(); ->executeStatement();
} }
} }
@@ -397,7 +400,7 @@ class DeckShareProvider implements \OCP\Share\IShareProvider {
->where( ->where(
$qb->expr()->eq('id', $qb->createNamedParameter($share->getId())) $qb->expr()->eq('id', $qb->createNamedParameter($share->getId()))
); );
$cursor = $qb->execute(); $cursor = $qb->executeQuery();
$data = $cursor->fetch(); $data = $cursor->fetch();
$cursor->closeCursor(); $cursor->closeCursor();
@@ -414,7 +417,7 @@ class DeckShareProvider implements \OCP\Share\IShareProvider {
$qb->expr()->eq('share_with', $qb->createNamedParameter($recipient)) $qb->expr()->eq('share_with', $qb->createNamedParameter($recipient))
); );
$qb->execute(); $qb->executeStatement();
return $this->getShareById((int)$share->getId(), $recipient); return $this->getShareById((int)$share->getId(), $recipient);
} }
@@ -435,7 +438,7 @@ class DeckShareProvider implements \OCP\Share\IShareProvider {
$qb->expr()->eq('item_type', $qb->createNamedParameter('folder')) $qb->expr()->eq('item_type', $qb->createNamedParameter('folder'))
)) ))
->setMaxResults(1) ->setMaxResults(1)
->execute(); ->executeQuery();
$data = $stmt->fetch(); $data = $stmt->fetch();
$stmt->closeCursor(); $stmt->closeCursor();
@@ -509,7 +512,7 @@ class DeckShareProvider implements \OCP\Share\IShareProvider {
$qb->orderBy('s.id'); $qb->orderBy('s.id');
$cursor = $qb->execute(); $cursor = $qb->executeQuery();
$shares = []; $shares = [];
while ($data = $cursor->fetch()) { while ($data = $cursor->fetch()) {
$shares[$data['fileid']][] = $this->createShareObject($data); $shares[$data['fileid']][] = $this->createShareObject($data);
@@ -554,7 +557,7 @@ class DeckShareProvider implements \OCP\Share\IShareProvider {
$qb->setFirstResult($offset); $qb->setFirstResult($offset);
$qb->orderBy('id'); $qb->orderBy('id');
$cursor = $qb->execute(); $cursor = $qb->executeQuery();
$shares = []; $shares = [];
while ($data = $cursor->fetch()) { while ($data = $cursor->fetch()) {
$shares[] = $this->createShareObject($data); $shares[] = $this->createShareObject($data);
@@ -582,7 +585,7 @@ class DeckShareProvider implements \OCP\Share\IShareProvider {
->where($qb->expr()->eq('s.id', $qb->createNamedParameter($id))) ->where($qb->expr()->eq('s.id', $qb->createNamedParameter($id)))
->andWhere($qb->expr()->eq('s.share_type', $qb->createNamedParameter(IShare::TYPE_DECK))); ->andWhere($qb->expr()->eq('s.share_type', $qb->createNamedParameter(IShare::TYPE_DECK)));
$cursor = $qb->execute(); $cursor = $qb->executeQuery();
$data = $cursor->fetch(); $data = $cursor->fetch();
$cursor->closeCursor(); $cursor->closeCursor();
@@ -647,7 +650,7 @@ class DeckShareProvider implements \OCP\Share\IShareProvider {
$qb->expr()->eq('item_type', $qb->createNamedParameter('folder')) $qb->expr()->eq('item_type', $qb->createNamedParameter('folder'))
)); ));
$stmt = $query->execute(); $stmt = $query->executeQuery();
while ($data = $stmt->fetch()) { while ($data = $stmt->fetch()) {
$this->applyBoardPermission($shareMap[$data['parent']], (int)$data['permissions'], $userId); $this->applyBoardPermission($shareMap[$data['parent']], (int)$data['permissions'], $userId);
@@ -677,7 +680,7 @@ class DeckShareProvider implements \OCP\Share\IShareProvider {
->from('share') ->from('share')
->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($path->getId()))) ->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($path->getId())))
->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(IShare::TYPE_DECK))) ->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(IShare::TYPE_DECK)))
->execute(); ->executeQuery();
$shares = []; $shares = [];
while ($data = $cursor->fetch()) { while ($data = $cursor->fetch()) {
@@ -749,7 +752,7 @@ class DeckShareProvider implements \OCP\Share\IShareProvider {
$qb->andWhere($qb->expr()->eq('dc.deleted_at', $qb->createNamedParameter(0, IQueryBuilder::PARAM_INT))); $qb->andWhere($qb->expr()->eq('dc.deleted_at', $qb->createNamedParameter(0, IQueryBuilder::PARAM_INT)));
$cursor = $qb->execute(); $cursor = $qb->executeQuery();
while ($data = $cursor->fetch()) { while ($data = $cursor->fetch()) {
if (!$this->isAccessibleResult($data)) { if (!$this->isAccessibleResult($data)) {
continue; continue;
@@ -842,6 +845,7 @@ class DeckShareProvider implements \OCP\Share\IShareProvider {
/** /**
* @inheritDoc * @inheritDoc
* @psalm-suppress InvalidReturnType Not returning anything
*/ */
public function getShareByToken($token) { public function getShareByToken($token) {
throw new ShareNotFound(); throw new ShareNotFound();
@@ -851,7 +855,7 @@ class DeckShareProvider implements \OCP\Share\IShareProvider {
->from('share') ->from('share')
->where($qb->expr()->eq('share_type', $qb->createNamedParameter(IShare::TYPE_ROOM))) ->where($qb->expr()->eq('share_type', $qb->createNamedParameter(IShare::TYPE_ROOM)))
->andWhere($qb->expr()->eq('token', $qb->createNamedParameter($token))) ->andWhere($qb->expr()->eq('token', $qb->createNamedParameter($token)))
->execute(); ->executeQuery();
$data = $cursor->fetch(); $data = $cursor->fetch();
@@ -1015,7 +1019,7 @@ class DeckShareProvider implements \OCP\Share\IShareProvider {
->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(IShare::TYPE_DECK))) ->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(IShare::TYPE_DECK)))
->orderBy('id'); ->orderBy('id');
$cursor = $qb->execute(); $cursor = $qb->executeQuery();
while ($data = $cursor->fetch()) { while ($data = $cursor->fetch()) {
$children[] = $this->createShareObject($data); $children[] = $this->createShareObject($data);
} }
@@ -1038,7 +1042,7 @@ class DeckShareProvider implements \OCP\Share\IShareProvider {
) )
); );
$cursor = $qb->execute(); $cursor = $qb->executeQuery();
while ($data = $cursor->fetch()) { while ($data = $cursor->fetch()) {
$share = $this->createShareObject($data); $share = $this->createShareObject($data);
@@ -1055,7 +1059,7 @@ class DeckShareProvider implements \OCP\Share\IShareProvider {
->where($qb->expr()->eq('s.share_type', $qb->createNamedParameter(IShare::TYPE_DECK))) ->where($qb->expr()->eq('s.share_type', $qb->createNamedParameter(IShare::TYPE_DECK)))
->andWhere($qb->expr()->notIn('s.share_with', $qb->createNamedParameter($allCardIds, IQueryBuilder::PARAM_STR_ARRAY))); ->andWhere($qb->expr()->notIn('s.share_with', $qb->createNamedParameter($allCardIds, IQueryBuilder::PARAM_STR_ARRAY)));
$cursor = $qb->execute(); $cursor = $qb->executeQuery();
$shares = []; $shares = [];
while ($data = $cursor->fetch()) { while ($data = $cursor->fetch()) {
$shares[] = $this->createShareObject($data); $shares[] = $this->createShareObject($data);

View File

@@ -6,6 +6,8 @@
xmlns="https://getpsalm.org/schema/config" xmlns="https://getpsalm.org/schema/config"
xsi:schemaLocation="https://getpsalm.org/schema/config" xsi:schemaLocation="https://getpsalm.org/schema/config"
errorBaseline="tests/psalm-baseline.xml" errorBaseline="tests/psalm-baseline.xml"
findUnusedBaselineEntry="true"
findUnusedCode="false"
phpVersion="8.1" phpVersion="8.1"
> >
<stubs> <stubs>
@@ -15,6 +17,7 @@
<directory name="lib" /> <directory name="lib" />
<ignoreFiles> <ignoreFiles>
<directory name="vendor" /> <directory name="vendor" />
<directory name="vendor-bin" />
</ignoreFiles> </ignoreFiles>
</projectFiles> </projectFiles>
<extraFiles> <extraFiles>
@@ -26,13 +29,6 @@
<referencedMethod name="/Db\\.*::.*/" /> <referencedMethod name="/Db\\.*::.*/" />
</errorLevel> </errorLevel>
</UndefinedMagicMethod> </UndefinedMagicMethod>
<UndefinedInterfaceMethod>
<errorLevel type="suppress">
<!-- FIXME Deprecated event handling -->
<referencedMethod name="OCP\IUserManager::listen" />
<referencedMethod name="OCP\IGroupManager::listen" />
</errorLevel>
</UndefinedInterfaceMethod>
<UndefinedClass> <UndefinedClass>
<errorLevel type="suppress"> <errorLevel type="suppress">
<referencedClass name="OC\*" /> <referencedClass name="OC\*" />

View File

@@ -90,8 +90,8 @@
} }
], ],
"assignedUsers": [], "assignedUsers": [],
"attachments": null, "attachments": [],
"attachmentCount": null, "attachmentCount": 0,
"owner": { "owner": {
"primaryKey": "admin", "primaryKey": "admin",
"uid": "admin", "uid": "admin",
@@ -123,8 +123,8 @@
"createdAt": 1689667572, "createdAt": 1689667572,
"labels": [], "labels": [],
"assignedUsers": [], "assignedUsers": [],
"attachments": null, "attachments": [],
"attachmentCount": null, "attachmentCount": 0,
"owner": { "owner": {
"primaryKey": "admin", "primaryKey": "admin",
"uid": "admin", "uid": "admin",
@@ -168,8 +168,8 @@
"type": 0 "type": 0
} }
], ],
"attachments": null, "attachments": [],
"attachmentCount": null, "attachmentCount": 0,
"owner": { "owner": {
"primaryKey": "admin", "primaryKey": "admin",
"uid": "admin", "uid": "admin",
@@ -240,8 +240,8 @@
} }
], ],
"assignedUsers": [], "assignedUsers": [],
"attachments": null, "attachments": [],
"attachmentCount": null, "attachmentCount": 0,
"owner": { "owner": {
"primaryKey": "admin", "primaryKey": "admin",
"uid": "admin", "uid": "admin",
@@ -283,8 +283,8 @@
} }
], ],
"assignedUsers": [], "assignedUsers": [],
"attachments": null, "attachments": [],
"attachmentCount": null, "attachmentCount": 0,
"owner": { "owner": {
"primaryKey": "admin", "primaryKey": "admin",
"uid": "admin", "uid": "admin",
@@ -328,8 +328,8 @@
"type": 0 "type": 0
} }
], ],
"attachments": null, "attachments": [],
"attachmentCount": null, "attachmentCount": 0,
"owner": { "owner": {
"primaryKey": "admin", "primaryKey": "admin",
"uid": "admin", "uid": "admin",
@@ -493,8 +493,8 @@
"createdAt": 1689667483, "createdAt": 1689667483,
"labels": [], "labels": [],
"assignedUsers": [], "assignedUsers": [],
"attachments": null, "attachments": [],
"attachmentCount": null, "attachmentCount": 0,
"owner": { "owner": {
"primaryKey": "admin", "primaryKey": "admin",
"uid": "admin", "uid": "admin",
@@ -526,8 +526,8 @@
"createdAt": 1689667518, "createdAt": 1689667518,
"labels": [], "labels": [],
"assignedUsers": [], "assignedUsers": [],
"attachments": null, "attachments": [],
"attachmentCount": null, "attachmentCount": 0,
"owner": { "owner": {
"primaryKey": "admin", "primaryKey": "admin",
"uid": "admin", "uid": "admin",
@@ -559,8 +559,8 @@
"createdAt": 1689667527, "createdAt": 1689667527,
"labels": [], "labels": [],
"assignedUsers": [], "assignedUsers": [],
"attachments": null, "attachments": [],
"attachmentCount": null, "attachmentCount": 0,
"owner": { "owner": {
"primaryKey": "admin", "primaryKey": "admin",
"uid": "admin", "uid": "admin",
@@ -592,8 +592,8 @@
"createdAt": 1689667537, "createdAt": 1689667537,
"labels": [], "labels": [],
"assignedUsers": [], "assignedUsers": [],
"attachments": null, "attachments": [],
"attachmentCount": null, "attachmentCount": 0,
"owner": { "owner": {
"primaryKey": "admin", "primaryKey": "admin",
"uid": "admin", "uid": "admin",
@@ -636,8 +636,8 @@
"createdAt": 1689667488, "createdAt": 1689667488,
"labels": [], "labels": [],
"assignedUsers": [], "assignedUsers": [],
"attachments": null, "attachments": [],
"attachmentCount": null, "attachmentCount": 0,
"owner": { "owner": {
"primaryKey": "admin", "primaryKey": "admin",
"uid": "admin", "uid": "admin",
@@ -680,8 +680,8 @@
"createdAt": 1689667493, "createdAt": 1689667493,
"labels": [], "labels": [],
"assignedUsers": [], "assignedUsers": [],
"attachments": null, "attachments": [],
"attachmentCount": null, "attachmentCount": 0,
"owner": { "owner": {
"primaryKey": "admin", "primaryKey": "admin",
"uid": "admin", "uid": "admin",
@@ -713,8 +713,8 @@
"createdAt": 1689667502, "createdAt": 1689667502,
"labels": [], "labels": [],
"assignedUsers": [], "assignedUsers": [],
"attachments": null, "attachments": [],
"attachmentCount": null, "attachmentCount": 0,
"owner": { "owner": {
"primaryKey": "admin", "primaryKey": "admin",
"uid": "admin", "uid": "admin",

View File

@@ -1 +1 @@
82773 82774

View File

@@ -1,152 +1,78 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<files psalm-version="5.6.0@e784128902dfe01d489c4123d69918a9f3c1eac5"> <files psalm-version="6.5.0@38fc8444edf0cebc9205296ee6e30e906ade783b">
<file src="lib/Activity/Filter.php"> <file src="lib/Activity/Filter.php">
<MethodSignatureMismatch> <MethodSignatureMismatch>
<code>$types</code> <code><![CDATA[$types]]></code>
</MethodSignatureMismatch> </MethodSignatureMismatch>
</file> </file>
<file src="lib/Command/UserExport.php">
<ImplementedReturnTypeMismatch>
<code>void</code>
</ImplementedReturnTypeMismatch>
<UndefinedThisPropertyAssignment>
<code>$this-&gt;boardMapper</code>
<code>$this-&gt;stackMapper</code>
</UndefinedThisPropertyAssignment>
<UndefinedThisPropertyFetch>
<code>$this-&gt;boardMapper</code>
<code>$this-&gt;stackMapper</code>
</UndefinedThisPropertyFetch>
</file>
<file src="lib/Controller/BoardApiController.php"> <file src="lib/Controller/BoardApiController.php">
<TypeDoesNotContainNull> <UndefinedFunction>
<code>$modified === null</code> <code><![CDATA[parseDate($modified)]]></code>
<code>$modified === null</code> </UndefinedFunction>
</TypeDoesNotContainNull>
<UndefinedClass>
<code>Util</code>
</UndefinedClass>
<UndefinedThisPropertyAssignment>
<code>$this-&gt;userId</code>
</UndefinedThisPropertyAssignment>
<UndefinedThisPropertyFetch>
<code>$this-&gt;userId</code>
</UndefinedThisPropertyFetch>
</file>
<file src="lib/Controller/CommentsApiController.php">
<InvalidScalarArgument>
<code>$cardId</code>
<code>$cardId</code>
<code>$cardId</code>
<code>$commentId</code>
<code>$commentId</code>
<code>$parentId</code>
</InvalidScalarArgument>
</file> </file>
<file src="lib/Controller/PageController.php"> <file src="lib/Controller/PageController.php">
<UndefinedClass> <UndefinedClass>
<code>LoadSidebar</code> <code><![CDATA[LoadSidebar]]></code>
</UndefinedClass> </UndefinedClass>
</file> </file>
<file src="lib/Controller/StackApiController.php"> <file src="lib/Controller/StackApiController.php">
<RedundantCondition> <UndefinedFunction>
<code>$modified !== null</code> <code><![CDATA[parseDate($modified)]]></code>
</RedundantCondition> </UndefinedFunction>
<UndefinedClass>
<code>Util</code>
</UndefinedClass>
</file> </file>
<file src="lib/DAV/Calendar.php"> <file src="lib/DAV/Calendar.php">
<UndefinedClass> <UndefinedClass>
<code>ExternalCalendar</code> <code><![CDATA[ExternalCalendar]]></code>
</UndefinedClass> </UndefinedClass>
</file> </file>
<file src="lib/DAV/CalendarObject.php"> <file src="lib/DAV/CalendarObject.php">
<UndefinedClass> <UndefinedClass>
<code>ICalendarObject</code> <code><![CDATA[ICalendarObject]]></code>
</UndefinedClass> </UndefinedClass>
</file> </file>
<file src="lib/DAV/CalendarPlugin.php"> <file src="lib/DAV/CalendarPlugin.php">
<UndefinedClass> <UndefinedClass>
<code>ICalendarProvider</code> <code><![CDATA[ICalendarProvider]]></code>
</UndefinedClass> </UndefinedClass>
</file> </file>
<file src="lib/DAV/DeckCalendarBackend.php"> <file src="lib/DAV/DeckCalendarBackend.php">
<UndefinedClass> <UndefinedClass>
<code>NotFound</code> <code><![CDATA[NotFound]]></code>
</UndefinedClass> </UndefinedClass>
</file> </file>
<file src="lib/Db/Card.php"> <file src="lib/Db/Card.php">
<UndefinedClass> <UndefinedClass>
<code>VCalendar</code> <code><![CDATA[VCalendar]]></code>
<code>VCalendar</code> <code><![CDATA[VCalendar]]></code>
</UndefinedClass> </UndefinedClass>
</file> </file>
<file src="lib/Db/CardMapper.php">
<InvalidScalarArgument>
<code>$entity-&gt;getId()</code>
</InvalidScalarArgument>
<UndefinedInterfaceMethod>
<code>getUserIdGroups</code>
</UndefinedInterfaceMethod>
</file>
<file src="lib/Db/LabelMapper.php">
<ParamNameMismatch>
<code>$labelId</code>
</ParamNameMismatch>
</file>
<file src="lib/Db/Stack.php"> <file src="lib/Db/Stack.php">
<UndefinedClass> <UndefinedClass>
<code>VCalendar</code> <code><![CDATA[VCalendar]]></code>
<code>VCalendar</code> <code><![CDATA[VCalendar]]></code>
</UndefinedClass> </UndefinedClass>
</file> </file>
<file src="lib/Model/BoardSummary.php">
<ConstructorSignatureMismatch>
<code>public function __construct(Board $board) {</code>
<code>public function __construct(Board $board) {</code>
</ConstructorSignatureMismatch>
</file>
<file src="lib/Model/CardDetails.php">
<ConstructorSignatureMismatch>
<code>public function __construct(Card $card, ?Board $board = null) {</code>
<code>public function __construct(Card $card, ?Board $board = null) {</code>
</ConstructorSignatureMismatch>
</file>
<file src="lib/Service/AttachmentService.php">
<InvalidCatch>
<code>try {
$attachment = $this-&gt;attachmentMapper-&gt;find($attachmentId);
} catch (IMapperException $e) {
throw new NoPermissionException('Permission denied');
}</code>
</InvalidCatch>
</file>
<file src="lib/Service/BoardService.php">
<TooManyArguments>
<code>findAll</code>
<code>findAll</code>
</TooManyArguments>
</file>
<file src="lib/Service/CirclesService.php">
<RedundantCondition>
<code>$member !== null</code>
</RedundantCondition>
</file>
<file src="lib/Service/FileService.php"> <file src="lib/Service/FileService.php">
<RedundantCondition> <RedundantCondition>
<code>is_resource($content)</code> <code><![CDATA[is_resource($content)]]></code>
<code>is_resource($content)</code> <code><![CDATA[is_resource($content)]]></code>
</RedundantCondition> </RedundantCondition>
</file> </file>
<file src="lib/Sharing/DeckShareProvider.php"> <file src="lib/Service/Importer/BoardImportCommandService.php">
<InvalidReturnType> <UndefinedInterfaceMethod>
<code>getShareByToken</code> <code><![CDATA[ask]]></code>
</InvalidReturnType> <code><![CDATA[ask]]></code>
<code><![CDATA[ask]]></code>
</UndefinedInterfaceMethod>
</file> </file>
<file src="lib/Sharing/Listener.php"> <file src="lib/Service/Importer/Systems/TrelloJsonService.php">
<InvalidArgument> <InvalidPropertyFetch>
<code>[self::class, 'listenPreShare']</code> <code><![CDATA[$createCardDate->date]]></code>
</InvalidArgument> </InvalidPropertyFetch>
</file>
<file src="lib/Teams/DeckTeamResourceProvider.php">
<FalsableReturnStatement>
<code><![CDATA[file_get_contents(__DIR__ . '/../../img/deck-current.svg')]]></code>
</FalsableReturnStatement>
</file> </file>
</files> </files>

View File

@@ -160,6 +160,7 @@ class ActivityManagerTest extends TestCase {
'id' => 123, 'id' => 123,
'title' => 'My card', 'title' => 'My card',
'description' => str_repeat('A', 1000), 'description' => str_repeat('A', 1000),
'stackId' => 42,
]); ]);
$this->cardMapper->expects(self::any()) $this->cardMapper->expects(self::any())
->method('find') ->method('find')
@@ -170,6 +171,7 @@ class ActivityManagerTest extends TestCase {
]); ]);
$this->stackMapper->expects(self::any()) $this->stackMapper->expects(self::any())
->method('find') ->method('find')
->with(42)
->willReturn($stack); ->willReturn($stack);
$expectedCard = $card->jsonSerialize(); $expectedCard = $card->jsonSerialize();
@@ -207,6 +209,7 @@ class ActivityManagerTest extends TestCase {
$card->setDescription(str_repeat('A', 5000)); $card->setDescription(str_repeat('A', 5000));
$card->setTitle('My card'); $card->setTitle('My card');
$card->setId(123); $card->setId(123);
$card->setStackId(42);
$this->cardMapper->expects(self::any()) $this->cardMapper->expects(self::any())
->method('find') ->method('find')
->willReturn($card); ->willReturn($card);
@@ -254,6 +257,7 @@ class ActivityManagerTest extends TestCase {
$card->setDescription(str_repeat('A', 5000)); $card->setDescription(str_repeat('A', 5000));
$card->setTitle('My card'); $card->setTitle('My card');
$card->setId(123); $card->setId(123);
$card->setStackId(42);
$this->cardMapper->expects(self::any()) $this->cardMapper->expects(self::any())
->method('find') ->method('find')
->willReturn($card); ->willReturn($card);

View File

@@ -119,7 +119,7 @@ class AttachmentMapperTest extends TestCase {
->method('isOwner') ->method('isOwner')
->with('admin', 1) ->with('admin', 1)
->willReturn(true); ->willReturn(true);
$this->assertTrue($this->attachmentMapper->isOwner('admin', (string)$this->attachments[0]->getId())); $this->assertTrue($this->attachmentMapper->isOwner('admin', $this->attachments[0]->getId()));
} }
public function testIsOwnerInvalid() { public function testIsOwnerInvalid() {
@@ -127,7 +127,7 @@ class AttachmentMapperTest extends TestCase {
->method('isOwner') ->method('isOwner')
->with('admin', 1) ->with('admin', 1)
->will($this->throwException(new DoesNotExistException('does not exist'))); ->will($this->throwException(new DoesNotExistException('does not exist')));
$this->assertFalse($this->attachmentMapper->isOwner('admin', (string)$this->attachments[0]->getId())); $this->assertFalse($this->attachmentMapper->isOwner('admin', $this->attachments[0]->getId()));
} }
public function testFindBoardId() { public function testFindBoardId() {

View File

@@ -81,8 +81,8 @@ class CardTest extends TestCase {
'duedate' => null, 'duedate' => null,
'overdue' => 0, 'overdue' => 0,
'archived' => false, 'archived' => false,
'attachments' => null, 'attachments' => [],
'attachmentCount' => null, 'attachmentCount' => 0,
'assignedUsers' => null, 'assignedUsers' => null,
'deletedAt' => 0, 'deletedAt' => 0,
'commentsUnread' => 0, 'commentsUnread' => 0,
@@ -110,8 +110,8 @@ class CardTest extends TestCase {
'duedate' => null, 'duedate' => null,
'overdue' => 0, 'overdue' => 0,
'archived' => false, 'archived' => false,
'attachments' => null, 'attachments' => [],
'attachmentCount' => null, 'attachmentCount' => 0,
'assignedUsers' => null, 'assignedUsers' => null,
'deletedAt' => 0, 'deletedAt' => 0,
'commentsUnread' => 0, 'commentsUnread' => 0,
@@ -141,8 +141,8 @@ class CardTest extends TestCase {
'duedate' => null, 'duedate' => null,
'overdue' => 0, 'overdue' => 0,
'archived' => false, 'archived' => false,
'attachments' => null, 'attachments' => [],
'attachmentCount' => null, 'attachmentCount' => 0,
'assignedUsers' => ['user1'], 'assignedUsers' => ['user1'],
'deletedAt' => 0, 'deletedAt' => 0,
'commentsUnread' => 0, 'commentsUnread' => 0,

View File

@@ -1,5 +1,7 @@
<?php <?php
declare(strict_types=1);
/** /**
* @copyright Copyright (c) 2018 Julius Härtl <jus@bitgrid.net> * @copyright Copyright (c) 2018 Julius Härtl <jus@bitgrid.net>
* *
@@ -116,7 +118,7 @@ class AttachmentServiceTest extends TestCase {
$this->activityManager = $this->createMock(ActivityManager::class); $this->activityManager = $this->createMock(ActivityManager::class);
$this->appContainer->expects($this->exactly(2)) $this->appContainer->expects($this->exactly(2))
->method('query') ->method('get')
->withConsecutive( ->withConsecutive(
[FileService::class], [FileService::class],
[FilesAppService::class] [FilesAppService::class]
@@ -156,7 +158,7 @@ class AttachmentServiceTest extends TestCase {
$fileAppServiceMock = $this->createMock(FilesAppService::class); $fileAppServiceMock = $this->createMock(FilesAppService::class);
$appContainer->expects($this->exactly(3)) $appContainer->expects($this->exactly(3))
->method('query') ->method('get')
->withConsecutive( ->withConsecutive(
[FileService::class], [FileService::class],
[FilesAppService::class], [FilesAppService::class],
@@ -185,7 +187,7 @@ class AttachmentServiceTest extends TestCase {
$fileAppServiceMock = $this->createMock(FilesAppService::class); $fileAppServiceMock = $this->createMock(FilesAppService::class);
$appContainer->expects($this->exactly(3)) $appContainer->expects($this->exactly(3))
->method('query') ->method('get')
->withConsecutive( ->withConsecutive(
[FileService::class], [FileService::class],
[FilesAppService::class], [FilesAppService::class],

View File

@@ -1,5 +1,7 @@
<?php <?php
declare(strict_types=1);
/** /**
* @copyright Copyright (c) 2016 Julius Härtl <jus@bitgrid.net> * @copyright Copyright (c) 2016 Julius Härtl <jus@bitgrid.net>
* *
@@ -240,6 +242,7 @@ class BoardServiceTest extends TestCase {
public function testDelete() { public function testDelete() {
$board = new Board(); $board = new Board();
$board->setId(42);
$board->setOwner('admin'); $board->setOwner('admin');
$board->setDeletedAt(0); $board->setDeletedAt(0);
$this->boardMapper->expects($this->once()) $this->boardMapper->expects($this->once())
@@ -252,7 +255,7 @@ class BoardServiceTest extends TestCase {
]); ]);
$this->sessionMapper->expects($this->once()) $this->sessionMapper->expects($this->once())
->method('findAllActive') ->method('findAllActive')
->with(null) ->with(42)
->willReturn([]); ->willReturn([]);
$boardDeleted = clone $board; $boardDeleted = clone $board;
$boardDeleted->setDeletedAt(1); $boardDeleted->setDeletedAt(1);
@@ -267,7 +270,7 @@ class BoardServiceTest extends TestCase {
$user->method('getUID')->willReturn('admin'); $user->method('getUID')->willReturn('admin');
$acl = new Acl(); $acl = new Acl();
$acl->setBoardId(123); $acl->setBoardId(123);
$acl->setType('user'); $acl->setType(Acl::PERMISSION_TYPE_USER);
$acl->setParticipant('admin'); $acl->setParticipant('admin');
$acl->setPermissionEdit(true); $acl->setPermissionEdit(true);
$acl->setPermissionShare(true); $acl->setPermissionShare(true);
@@ -287,7 +290,7 @@ class BoardServiceTest extends TestCase {
'admin' => 'admin', 'admin' => 'admin',
]); ]);
$this->assertEquals($acl, $this->service->addAcl( $this->assertEquals($acl, $this->service->addAcl(
123, 'user', 'admin', true, true, true 123, Acl::PERMISSION_TYPE_USER, 'admin', true, true, true
)); ));
} }
@@ -323,7 +326,7 @@ class BoardServiceTest extends TestCase {
public function testAddAclExtendPermission($currentUserAcl, $providedAcl, $resultingAcl) { public function testAddAclExtendPermission($currentUserAcl, $providedAcl, $resultingAcl) {
$existingAcl = new Acl(); $existingAcl = new Acl();
$existingAcl->setBoardId(123); $existingAcl->setBoardId(123);
$existingAcl->setType('user'); $existingAcl->setType(Acl::PERMISSION_TYPE_USER);
$existingAcl->setParticipant('admin'); $existingAcl->setParticipant('admin');
$existingAcl->setPermissionEdit($currentUserAcl[0]); $existingAcl->setPermissionEdit($currentUserAcl[0]);
$existingAcl->setPermissionShare($currentUserAcl[1]); $existingAcl->setPermissionShare($currentUserAcl[1]);
@@ -391,14 +394,14 @@ class BoardServiceTest extends TestCase {
->method('dispatchTyped') ->method('dispatchTyped')
->with(new AclCreatedEvent($acl)); ->with(new AclCreatedEvent($acl));
$this->assertEquals($expected, $this->service->addAcl( $this->assertEquals($expected, $this->service->addAcl(
123, 'user', 'admin', $providedAcl[0], $providedAcl[1], $providedAcl[2] 123, Acl::PERMISSION_TYPE_USER, 'admin', $providedAcl[0], $providedAcl[1], $providedAcl[2]
)); ));
} }
public function testUpdateAcl() { public function testUpdateAcl() {
$acl = new Acl(); $acl = new Acl();
$acl->setBoardId(123); $acl->setBoardId(123);
$acl->setType('user'); $acl->setType(Acl::PERMISSION_TYPE_USER);
$acl->setParticipant('admin'); $acl->setParticipant('admin');
$acl->setPermissionEdit(true); $acl->setPermissionEdit(true);
$acl->setPermissionShare(true); $acl->setPermissionShare(true);

View File

@@ -183,6 +183,7 @@ class CardServiceTest extends TestCase {
->willReturn($boardMock); ->willReturn($boardMock);
$card = new Card(); $card = new Card();
$card->setId(1337); $card->setId(1337);
$card->setStackId(123);
$this->cardMapper->expects($this->any()) $this->cardMapper->expects($this->any())
->method('find') ->method('find')
->with(123) ->with(123)
@@ -200,6 +201,7 @@ class CardServiceTest extends TestCase {
->with([1337]) ->with([1337])
->willReturn([$a1, $a2]); ->willReturn([$a1, $a2]);
$cardExpected = new Card(); $cardExpected = new Card();
$cardExpected->setStackId(123);
$cardExpected->setId(1337); $cardExpected->setId(1337);
$cardExpected->setAssignedUsers([$a1, $a2]); $cardExpected->setAssignedUsers([$a1, $a2]);
$cardExpected->setRelatedBoard($boardMock); $cardExpected->setRelatedBoard($boardMock);
@@ -218,6 +220,7 @@ class CardServiceTest extends TestCase {
'stackId' => 123, 'stackId' => 123,
'order' => 999, 'order' => 999,
'type' => 'text', 'type' => 'text',
'id' => 0,
]); ]);
$stack = Stack::fromParams([ $stack = Stack::fromParams([
'id' => 123, 'id' => 123,
@@ -243,6 +246,8 @@ class CardServiceTest extends TestCase {
$card = new Card(); $card = new Card();
$card->setId(1); $card->setId(1);
$card->setTitle('Card title'); $card->setTitle('Card title');
$card->setType('test');
$card->setOrder(0);
$card->setOwner('admin'); $card->setOwner('admin');
$card->setStackId(12345); $card->setStackId(12345);
$clonedCard = clone $card; $clonedCard = clone $card;
@@ -290,8 +295,7 @@ class CardServiceTest extends TestCase {
->willReturn([$label]); ->willReturn([$label]);
$this->cardMapper->expects($this->once()) $this->cardMapper->expects($this->once())
->method('assignLabel') ->method('assignLabel')
->with($clonedCard->getId(), $label->getId()) ->with($clonedCard->getId(), $label->getId());
->willReturn($label);
$stackMock = new Stack(); $stackMock = new Stack();
$stackMock->setBoardId(1234); $stackMock->setBoardId(1234);
@@ -329,6 +333,7 @@ class CardServiceTest extends TestCase {
]); ]);
$this->cardMapper->expects($this->once())->method('find')->willReturn($card); $this->cardMapper->expects($this->once())->method('find')->willReturn($card);
$this->cardMapper->expects($this->once())->method('update')->willReturnCallback(function ($c) { $this->cardMapper->expects($this->once())->method('update')->willReturnCallback(function ($c) {
$c->setId(1);
return $c; return $c;
}); });
$this->stackMapper->expects($this->once()) $this->stackMapper->expects($this->once())

View File

@@ -220,8 +220,9 @@ class DefaultBoardServiceTest extends TestCase {
return $stack; return $stack;
} }
private function assembleTestCard($title, $stackId, $userId) { private function assembleTestCard(string $title, int $stackId, string $userId): Card {
$card = new Card(); $card = new Card();
$card->setId(1);
$card->setTitle($title); $card->setTitle($title);
$card->setStackId($stackId); $card->setStackId($stackId);
$card->setType('text'); $card->setType('text');

View File

@@ -192,14 +192,17 @@ class BoardImportServiceTest extends \Test\TestCase {
->expects($this->once()) ->expects($this->once())
->method('save'); ->method('save');
$assignment = new Assignment();
$assignment->setId(1);
$this->trelloJsonService $this->trelloJsonService
->method('getCardAssignments') ->method('getCardAssignments')
->willReturn([ ->willReturn([
'fakecardid' => [new Assignment()] 'fakecardid' => [$assignment]
]); ]);
$this->assignmentMapper $this->assignmentMapper
->expects($this->once()) ->expects($this->once())
->method('insert'); ->method('insert')
->willReturn($assignment);
$this->boardImportService->import(); $this->boardImportService->import();
self::assertTrue(true); self::assertTrue(true);

View File

@@ -1,5 +1,7 @@
<?php <?php
declare(strict_types=1);
/** /**
* @copyright Copyright (c) 2016 Julius Härtl <jus@bitgrid.net> * @copyright Copyright (c) 2016 Julius Härtl <jus@bitgrid.net>
* *
@@ -29,6 +31,7 @@ use OCA\Deck\Db\ChangeHelper;
use OCA\Deck\Db\Label; use OCA\Deck\Db\Label;
use OCA\Deck\Db\LabelMapper; use OCA\Deck\Db\LabelMapper;
use OCA\Deck\Validators\LabelServiceValidator; use OCA\Deck\Validators\LabelServiceValidator;
use PHPUnit\Framework\MockObject\MockObject;
use Test\TestCase; use Test\TestCase;
class LabelServiceTest extends TestCase { class LabelServiceTest extends TestCase {
@@ -42,9 +45,8 @@ class LabelServiceTest extends TestCase {
/** @var BoardService|\PHPUnit\Framework\MockObject\MockObject */ /** @var BoardService|\PHPUnit\Framework\MockObject\MockObject */
private $boardService; private $boardService;
/** @var ChangeHelper|\PHPUnit\Framework\MockObject\MockObject */ /** @var ChangeHelper|\PHPUnit\Framework\MockObject\MockObject */
private $changeHelper; private ChangeHelper&MockObject $changeHelper;
/** @var LabelServiceValidator\MockObject */ private LabelServiceValidator&MockObject $labelServiceValidator;
private $labelServiceValidator;
public function setUp(): void { public function setUp(): void {
parent::setUp(); parent::setUp();
@@ -66,8 +68,9 @@ class LabelServiceTest extends TestCase {
} }
public function testFind() { public function testFind() {
$this->labelMapper->expects($this->once())->method('find')->willReturn(true); $label = $this->createMock(Label::class);
$this->assertTrue($this->labelService->find(123)); $this->labelMapper->expects($this->once())->method('find')->willReturn($label);
$this->assertEquals($label, $this->labelService->find(123));
} }
public function testCreate() { public function testCreate() {

View File

@@ -1,5 +1,7 @@
<?php <?php
declare(strict_types=1);
/** /**
* @copyright Copyright (c) 2016 Julius Härtl <jus@bitgrid.net> * @copyright Copyright (c) 2016 Julius Härtl <jus@bitgrid.net>
* *
@@ -48,8 +50,7 @@ use Test\TestCase;
*/ */
class StackServiceTest extends TestCase { class StackServiceTest extends TestCase {
/** @var StackService */ private StackService $stackService;
private $stackService;
/** @var \PHPUnit\Framework\MockObject\MockObject|StackMapper */ /** @var \PHPUnit\Framework\MockObject\MockObject|StackMapper */
private $stackMapper; private $stackMapper;
/** @var \PHPUnit\Framework\MockObject\MockObject|CardMapper */ /** @var \PHPUnit\Framework\MockObject\MockObject|CardMapper */
@@ -251,6 +252,9 @@ class StackServiceTest extends TestCase {
$this->stackMapper->expects($this->once()) $this->stackMapper->expects($this->once())
->method('findAll') ->method('findAll')
->willReturn($stacks); ->willReturn($stacks);
$this->stackMapper->expects($this->any())
->method('update')
->willReturnCallback(fn (Stack $stack): Stack => $stack);
$actual = $this->stackService->reorder(1, 2); $actual = $this->stackService->reorder(1, 2);
$a = $this->createStack(1, 2); $a = $this->createStack(1, 2);
$b = $this->createStack(2, 0); $b = $this->createStack(2, 0);
@@ -259,7 +263,7 @@ class StackServiceTest extends TestCase {
$this->assertEquals($expected, $actual); $this->assertEquals($expected, $actual);
} }
private function createStack($id, $order) { private function createStack(int $id, int $order) {
$stack = new Stack(); $stack = new Stack();
$stack->setId($id); $stack->setId($id);
$stack->setBoardId(1); $stack->setBoardId(1);

View File

@@ -1,5 +1,7 @@
<?php <?php
declare(strict_types=1);
/** /**
* @copyright Copyright (c) 2016 Julius Härtl <jus@bitgrid.net> * @copyright Copyright (c) 2016 Julius Härtl <jus@bitgrid.net>
* *
@@ -26,46 +28,47 @@ namespace OCA\Deck\Controller;
use OCA\Deck\Db\Acl; use OCA\Deck\Db\Acl;
use OCA\Deck\Db\Board; use OCA\Deck\Db\Board;
use OCA\Deck\Service\BoardService;
use OCA\Deck\Service\Importer\BoardImportService;
use OCA\Deck\Service\PermissionService;
use OCP\IGroupManager;
use OCP\IL10N;
use OCP\IRequest;
use OCP\IUser; use OCP\IUser;
use OCP\IUserManager;
use PHPUnit\Framework\MockObject\MockObject;
class BoardControllerTest extends \Test\TestCase { class BoardControllerTest extends \Test\TestCase {
private $l10n; private IL10N&MockObject $l10n;
private $controller; private BoardController $controller;
private $request; private IRequest&MockObject $request;
private $userManager; private IUserManager&MockObject $userManager;
private $groupManager; private IGroupManager&MockObject $groupManager;
private $boardService; private BoardService&MockObject $boardService;
private $permissionService; private PermissionService&MockObject $permissionService;
private $boardImportService; private BoardImportService&MockObject $boardImportService;
private $userId = 'user'; private $userId = 'user';
public function setUp(): void { public function setUp(): void {
$this->l10n = $this->request = $this->getMockBuilder( $this->l10n = $this->getMockBuilder(IL10N::class)
'\OCP\IL10n')
->disableOriginalConstructor() ->disableOriginalConstructor()
->getMock(); ->getMock();
$this->request = $this->getMockBuilder( $this->request = $this->getMockBuilder(IRequest::class)
'\OCP\IRequest')
->disableOriginalConstructor() ->disableOriginalConstructor()
->getMock(); ->getMock();
$this->userManager = $this->getMockBuilder( $this->userManager = $this->getMockBuilder(IUserManager::class)
'\OCP\IUserManager')
->disableOriginalConstructor() ->disableOriginalConstructor()
->getMock(); ->getMock();
$this->groupManager = $this->getMockBuilder( $this->groupManager = $this->getMockBuilder(IGroupManager::class)
'\OCP\IGroupManager')
->disableOriginalConstructor() ->disableOriginalConstructor()
->getMock(); ->getMock();
$this->boardService = $this->getMockBuilder( $this->boardService = $this->getMockBuilder(BoardService::class)
'\OCA\Deck\Service\BoardService')
->disableOriginalConstructor() ->disableOriginalConstructor()
->getMock(); ->getMock();
$this->permissionService = $this->getMockBuilder( $this->permissionService = $this->getMockBuilder(PermissionService::class)
'\OCA\Deck\Service\PermissionService')
->disableOriginalConstructor() ->disableOriginalConstructor()
->getMock(); ->getMock();
$this->boardImportService = $this->getMockBuilder( $this->boardImportService = $this->getMockBuilder(BoardImportService::class)
'\OCA\Deck\Service\Importer\BoardImportService')
->disableOriginalConstructor() ->disableOriginalConstructor()
->getMock(); ->getMock();
@@ -107,35 +110,39 @@ class BoardControllerTest extends \Test\TestCase {
} }
public function testCreate() { public function testCreate() {
$board = $this->createMock(Board::class);
$this->boardService->expects($this->once()) $this->boardService->expects($this->once())
->method('create') ->method('create')
->with(1, 'user', 3) ->with('abc', 'user', 'green')
->willReturn(1); ->willReturn($board);
$this->assertEquals(1, $this->controller->create(1, 3)); $this->assertEquals($board, $this->controller->create('abc', 'green'));
} }
public function testUpdate() { public function testUpdate(): void {
$board = $this->createMock(Board::class);
$this->boardService->expects($this->once()) $this->boardService->expects($this->once())
->method('update') ->method('update')
->with(1, 2, 3, false) ->with(1, 'abc', 'green', false)
->willReturn(1); ->willReturn($board);
$this->assertEquals(1, $this->controller->update(1, 2, 3, false)); $this->assertEquals($board, $this->controller->update(1, 'abc', 'green', false));
} }
public function testDelete() { public function testDelete(): void {
$board = $this->createMock(Board::class);
$this->boardService->expects($this->once()) $this->boardService->expects($this->once())
->method('delete') ->method('delete')
->with(123) ->with(123)
->willReturn(1); ->willReturn($board);
$this->assertEquals(1, $this->controller->delete(123)); $this->assertEquals($board, $this->controller->delete(123));
} }
public function testDeleteUndo() { public function testDeleteUndo() {
$board = $this->createMock(Board::class);
$this->boardService->expects($this->once()) $this->boardService->expects($this->once())
->method('deleteUndo') ->method('deleteUndo')
->with(123) ->with(123)
->willReturn(1); ->willReturn($board);
$this->assertEquals(1, $this->controller->deleteUndo(123)); $this->assertEquals($board, $this->controller->deleteUndo(123));
} }
public function testGetUserPermissions() { public function testGetUserPermissions() {
@@ -158,20 +165,22 @@ class BoardControllerTest extends \Test\TestCase {
$this->assertEquals($expected, $this->controller->getUserPermissions(123)); $this->assertEquals($expected, $this->controller->getUserPermissions(123));
} }
public function testAddAcl() { public function testAddAcl(): void {
$acl = $this->createMock(Acl::class);
$this->boardService->expects($this->once()) $this->boardService->expects($this->once())
->method('addAcl') ->method('addAcl')
->with(1, 2, 3, 4, 5, 6) ->with(1, 2, 'user1', true, true, true)
->willReturn(1); ->willReturn($acl);
$this->assertEquals(1, $this->controller->addAcl(1, 2, 3, 4, 5, 6)); $this->assertEquals($acl, $this->controller->addAcl(1, 2, 'user1', true, true, true));
} }
public function testUpdateAcl() { public function testUpdateAcl(): void {
$acl = $this->createMock(Acl::class);
$this->boardService->expects($this->once()) $this->boardService->expects($this->once())
->method('updateAcl') ->method('updateAcl')
->with(1, 2, 3, 4) ->with(1, true, true, true)
->willReturn(1); ->willReturn($acl);
$this->assertEquals(1, $this->controller->updateAcl(1, 2, 3, 4)); $this->assertEquals($acl, $this->controller->updateAcl(1, true, true, true));
} }
public function testDeleteAcl() { public function testDeleteAcl() {

View File

@@ -1,5 +1,7 @@
<?php <?php
declare(strict_types=1);
/** /**
* @copyright Copyright (c) 2018 Ryan Fletcher <ryan.fletcher@codepassion.ca> * @copyright Copyright (c) 2018 Ryan Fletcher <ryan.fletcher@codepassion.ca>
* *
@@ -30,15 +32,16 @@ use OCP\AppFramework\Http;
use OCP\AppFramework\Http\DataResponse; use OCP\AppFramework\Http\DataResponse;
use OCP\IRequest; use OCP\IRequest;
use PHPUnit\Framework\MockObject\MockObject;
class CardApiControllerTest extends \Test\TestCase { class CardApiControllerTest extends \Test\TestCase {
private $controller; private CardApiController $controller;
private $request; private IRequest&MockObject $request;
private $cardService; private CardService&MockObject $cardService;
private $userId = 'admin'; private string $userId = 'admin';
private $cardExample; private array $cardExample;
private $stackExample; private array $stackExample;
private $assignmentService; private AssignmentService&MockObject $assignmentService;
public function setUp(): void { public function setUp(): void {
parent::setUp(); parent::setUp();
@@ -51,7 +54,7 @@ class CardApiControllerTest extends \Test\TestCase {
$this->stackExample['id'] = 1; $this->stackExample['id'] = 1;
$this->controller = new CardApiController( $this->controller = new CardApiController(
$appName = 'deck', 'deck',
$this->request, $this->request,
$this->cardService, $this->cardService,
$this->assignmentService, $this->assignmentService,
@@ -59,7 +62,7 @@ class CardApiControllerTest extends \Test\TestCase {
); );
} }
public function testGet() { public function testGet(): void {
$card = new Card(); $card = new Card();
$card->setId($this->cardExample['id']); $card->setId($this->cardExample['id']);
@@ -116,7 +119,7 @@ class CardApiControllerTest extends \Test\TestCase {
->willReturn($card); ->willReturn($card);
$expected = new DataResponse($card, HTTP::STATUS_OK); $expected = new DataResponse($card, HTTP::STATUS_OK);
$actual = $this->controller->update('title', 'plain', 0, 'description', $this->userId, null); $actual = $this->controller->update('title', 'plain', $this->userId, 'description', 0, null);
$this->assertEquals($expected, $actual); $this->assertEquals($expected, $actual);
} }

View File

@@ -1,5 +1,7 @@
<?php <?php
declare(strict_types=1);
/** /**
* @copyright Copyright (c) 2016 Julius Härtl <jus@bitgrid.net> * @copyright Copyright (c) 2016 Julius Härtl <jus@bitgrid.net>
* *
@@ -24,6 +26,7 @@
namespace OCA\Deck\Controller; namespace OCA\Deck\Controller;
use OCA\Deck\Db\Card;
use OCA\Deck\Service\AssignmentService; use OCA\Deck\Service\AssignmentService;
use OCA\Deck\Service\CardService; use OCA\Deck\Service\CardService;
use OCP\IRequest; use OCP\IRequest;
@@ -32,17 +35,11 @@ use Test\TestCase;
class CardControllerTest extends TestCase { class CardControllerTest extends TestCase {
/** @var CardController|MockObject */ private CardController $controller;
private $controller; private IRequest&MockObject $request;
/** @var IRequest|MockObject */ private CardService&MockObject $cardService;
private $request; private AssignmentService&MockObject $assignmentService;
/** @var CardService|MockObject */ private string $userId = 'user';
private $cardService;
/** @var AssignmentService|MockObject */
private $assignmentService;
/** @var string */
private $userId = 'user';
public function setUp(): void { public function setUp(): void {
$this->request = $this->createMock(IRequest::class); $this->request = $this->createMock(IRequest::class);
@@ -58,39 +55,43 @@ class CardControllerTest extends TestCase {
} }
public function testRead() { public function testRead() {
$card = $this->createMock(Card::class);
$this->cardService->expects($this->once()) $this->cardService->expects($this->once())
->method('find') ->method('find')
->with(123) ->with(123)
->willReturn(1); ->willReturn($card);
$this->assertEquals(1, $this->controller->read(123)); $this->assertEquals($card, $this->controller->read(123));
} }
public function testCreate() { public function testCreate(): void {
$card = $this->createMock(Card::class);
$this->cardService->expects($this->once()) $this->cardService->expects($this->once())
->method('create') ->method('create')
->with('foo', 1, 'text', 3, $this->userId) ->with('foo', 1, 'text', 3, $this->userId)
->willReturn(1); ->willReturn($card);
$this->assertEquals(1, $this->controller->create('foo', 1, 'text', 3)); $this->assertEquals($card, $this->controller->create('foo', 1, 'text', 3));
} }
public function testUpdate() { public function testUpdate(): void {
$card = $this->createMock(Card::class);
$this->cardService->expects($this->once()) $this->cardService->expects($this->once())
->method('update') ->method('update')
->with(1, 'title', 3, 'text', $this->userId, 'foo', 5, '2017-01-01 00:00:00') ->with(1, 'title', 3, 'text', $this->userId, 'foo', 5, '2017-01-01 00:00:00')
->willReturn(1); ->willReturn($card);
$this->assertEquals(1, $this->controller->update(1, 'title', 3, 'text', 5, 'foo', '2017-01-01 00:00:00', null)); $this->assertEquals($card, $this->controller->update(1, 'title', 3, 'text', 5, 'foo', '2017-01-01 00:00:00', null));
} }
public function testDelete() { public function testDelete(): void {
$card = $this->createMock(Card::class);
$this->cardService->expects($this->once()) $this->cardService->expects($this->once())
->method('delete') ->method('delete')
->with(123) ->with(123)
->willReturn(1); ->willReturn($card);
$this->assertEquals(1, $this->controller->delete(123)); $this->assertEquals($card, $this->controller->delete(123));
} }
public function testArchive() { public function testArchive() {
$this->cardService->expects($this->once())->method('archive')->willReturn(true); $this->cardService->expects($this->once())->method('archive');
$this->controller->archive(1); $this->controller->archive(1);
} }
public function testUnarchive() { public function testUnarchive() {

View File

@@ -24,6 +24,7 @@
namespace OCA\Deck\Controller; namespace OCA\Deck\Controller;
use OCA\Deck\Db\Label;
use OCA\Deck\Service\LabelService; use OCA\Deck\Service\LabelService;
use OCP\AppFramework\Controller; use OCP\AppFramework\Controller;
use OCP\IRequest; use OCP\IRequest;
@@ -56,27 +57,30 @@ class LabelControllerTest extends \Test\TestCase {
} }
public function testCreate() { public function testCreate(): void {
$label = $this->createMock(Label::class);
$this->labelService->expects($this->once()) $this->labelService->expects($this->once())
->method('create') ->method('create')
->with(1, 2, 3) ->with(1, 2, 3)
->willReturn(1); ->willReturn($label);
$this->assertEquals(1, $this->controller->create(1, 2, 3)); $this->assertEquals($label, $this->controller->create(1, 2, 3));
} }
public function testUpdate() { public function testUpdate(): void {
$label = $this->createMock(Label::class);
$this->labelService->expects($this->once()) $this->labelService->expects($this->once())
->method('update') ->method('update')
->with(1, 2, 3) ->with(1, 2, 3)
->willReturn(1); ->willReturn($label);
$this->assertEquals(1, $this->controller->update(1, 2, 3)); $this->assertEquals($label, $this->controller->update(1, 2, 3));
} }
public function testDelete() { public function testDelete(): void {
$label = $this->createMock(Label::class);
$this->labelService->expects($this->once()) $this->labelService->expects($this->once())
->method('delete') ->method('delete')
->with(123) ->with(123)
->willReturn(1); ->willReturn($label);
$this->assertEquals(1, $this->controller->delete(123)); $this->assertEquals($label, $this->controller->delete(123));
} }
} }

View File

@@ -1,5 +1,7 @@
<?php <?php
declare(strict_types=1);
/** /**
* @copyright Copyright (c) 2016 Julius Härtl <jus@bitgrid.net> * @copyright Copyright (c) 2016 Julius Härtl <jus@bitgrid.net>
* *
@@ -24,6 +26,7 @@
namespace OCA\Deck\Controller; namespace OCA\Deck\Controller;
use OCA\Deck\Db\Stack;
use OCA\Deck\Service\StackService; use OCA\Deck\Service\StackService;
use OCP\AppFramework\Controller; use OCP\AppFramework\Controller;
use OCP\IRequest; use OCP\IRequest;
@@ -67,34 +70,38 @@ class StackControllerTest extends \Test\TestCase {
} }
public function testCreate() { public function testCreate() {
$stack = $this->createMock(Stack::class);
$this->stackService->expects($this->once()) $this->stackService->expects($this->once())
->method('create') ->method('create')
->with(1, 2, 3) ->with('abc', 2, 3)
->willReturn(1); ->willReturn($stack);
$this->assertEquals(1, $this->controller->create(1, 2, 3)); $this->assertEquals($stack, $this->controller->create('abc', 2, 3));
} }
public function testUpdate() { public function testUpdate() {
$stack = $this->createMock(Stack::class);
$this->stackService->expects($this->once()) $this->stackService->expects($this->once())
->method('update') ->method('update')
->with(1, 2, 3, 4) ->with(1, 'abc', 3, 4)
->willReturn(1); ->willReturn($stack);
$this->assertEquals(1, $this->controller->update(1, 2, 3, 4, null)); $this->assertEquals($stack, $this->controller->update(1, 'abc', 3, 4, null));
} }
public function testReorder() { public function testReorder() {
$stack = $this->createMock(Stack::class);
$this->stackService->expects($this->once()) $this->stackService->expects($this->once())
->method('reorder') ->method('reorder')
->with(1, 2) ->with(1, 2)
->willReturn(1); ->willReturn([$stack]);
$this->assertEquals(1, $this->controller->reorder(1, 2)); $this->assertEquals([$stack], $this->controller->reorder(1, 2));
} }
public function testDelete() { public function testDelete() {
$stack = $this->createMock(Stack::class);
$this->stackService->expects($this->once()) $this->stackService->expects($this->once())
->method('delete') ->method('delete')
->with(123) ->with(123)
->willReturn(1); ->willReturn($stack);
$this->assertEquals(1, $this->controller->delete(123)); $this->assertEquals($stack, $this->controller->delete(123));
} }
} }

View File

@@ -0,0 +1,10 @@
{
"require-dev": {
"vimeo/psalm": "^6.4"
},
"config": {
"platform": {
"php": "8.1.17"
}
}
}

3217
vendor-bin/psalm/composer.lock generated Normal file

File diff suppressed because it is too large Load Diff