diff --git a/lib/Db/Table.php b/lib/Db/Table.php index 8877d04bb..9f5b1411f 100644 --- a/lib/Db/Table.php +++ b/lib/Db/Table.php @@ -3,6 +3,7 @@ namespace OCA\Tables\Db; use JsonSerializable; +use OCA\Tables\Model\Permissions; use OCA\Tables\ResponseDefinitions; use OCP\AppFramework\Db\Entity; @@ -25,8 +26,8 @@ * @method setOwnerDisplayName(string $ownerDisplayName) * @method getIsShared(): bool * @method setIsShared(bool $isShared) - * @method getOnSharePermissions(): array - * @method setOnSharePermissions(array $onSharePermissions) + * @method getOnSharePermissions(): ?Permissions + * @method setOnSharePermissions(Permissions $onSharePermissions) * @method getHasShares(): bool * @method setHasShares(bool $hasShares) * @method getFavorite(): bool @@ -59,7 +60,7 @@ class Table extends Entity implements JsonSerializable { protected ?string $lastEditAt = null; protected bool $archived = false; protected ?bool $isShared = null; - protected ?array $onSharePermissions = null; + protected ?Permissions $onSharePermissions = null; protected ?bool $hasShares = false; protected ?bool $favorite = false; @@ -91,7 +92,7 @@ public function jsonSerialize(): array { 'archived' => $this->archived, 'isShared' => !!$this->isShared, 'favorite' => $this->favorite, - 'onSharePermissions' => $this->getSharePermissions(), + 'onSharePermissions' => $this->getSharePermissions()?->jsonSerialize(), 'hasShares' => !!$this->hasShares, 'rowsCount' => $this->rowsCount ?: 0, 'columnsCount' => $this->columnsCount ?: 0, @@ -100,11 +101,7 @@ public function jsonSerialize(): array { ]; } - /** - * @psalm-suppress MismatchingDocblockReturnType - * @return array{read: bool, create: bool, update: bool, delete: bool, manage: bool}|null - */ - private function getSharePermissions(): ?array { + private function getSharePermissions(): ?Permissions { return $this->onSharePermissions; } diff --git a/lib/Db/View.php b/lib/Db/View.php index a5f2627b1..e3dc83e66 100644 --- a/lib/Db/View.php +++ b/lib/Db/View.php @@ -3,6 +3,7 @@ namespace OCA\Tables\Db; use JsonSerializable; +use OCA\Tables\Model\Permissions; use OCA\Tables\ResponseDefinitions; use OCP\AppFramework\Db\Entity; @@ -35,8 +36,8 @@ * @method setDescription(string $description) * @method getIsShared(): bool * @method setIsShared(bool $isShared) - * @method getOnSharePermissions(): array{create: bool,delete: bool,manage: bool,read: bool,update: bool}|null - * @method setOnSharePermissions(array $onSharePermissions) + * @method getOnSharePermissions(): ?Permissions + * @method setOnSharePermissions(Permissions $onSharePermissions) * @method getHasShares(): bool * @method setHasShares(bool $hasShares) * @method getFavorite(): bool @@ -61,7 +62,7 @@ class View extends Entity implements JsonSerializable { protected ?string $sort = null; // json protected ?string $filter = null; // json protected ?bool $isShared = null; - protected ?array $onSharePermissions = null; + protected ?Permissions $onSharePermissions = null; protected ?bool $hasShares = false; protected bool $favorite = false; protected ?int $rowsCount = 0; @@ -117,11 +118,7 @@ public function setFilterArray(array $array):void { $this->setFilter(\json_encode($array)); } - /** - * @psalm-suppress MismatchingDocblockReturnType - * @return array{create: bool, delete: bool, manage: bool, read: bool, update: bool}|null - */ - private function getSharePermissions(): ?array { + private function getSharePermissions(): ?Permissions { return $this->getOnSharePermissions(); } @@ -152,7 +149,7 @@ public function jsonSerialize(): array { 'sort' => $this->getSortArray(), 'isShared' => !!$this->isShared, 'favorite' => $this->favorite, - 'onSharePermissions' => $this->getSharePermissions(), + 'onSharePermissions' => $this->getSharePermissions()?->jsonSerialize(), 'hasShares' => !!$this->hasShares, 'rowsCount' => $this->rowsCount ?: 0, 'ownerDisplayName' => $this->ownerDisplayName, diff --git a/lib/Model/Permissions.php b/lib/Model/Permissions.php index b881ca0f5..3087ccf27 100644 --- a/lib/Model/Permissions.php +++ b/lib/Model/Permissions.php @@ -2,7 +2,9 @@ namespace OCA\Tables\Model; -class Permissions { +use JsonSerializable; + +class Permissions implements JsonSerializable { public function __construct( public bool $read = false, public bool $create = false, @@ -12,4 +14,18 @@ public function __construct( public bool $manageTable = false, ) { } + + /** + * @return array{read: bool, create: bool, update: bool, delete: bool, manage: bool} + */ + public function jsonSerialize(): array { + // manageTable is not serialized as it is used in the backend only + return [ + 'read' => $this->read, + 'create' => $this->create, + 'update' => $this->update, + 'delete' => $this->delete, + 'manage' => $this->manage, + ]; + } } diff --git a/lib/ResponseDefinitions.php b/lib/ResponseDefinitions.php index 554c14940..c53be07a1 100644 --- a/lib/ResponseDefinitions.php +++ b/lib/ResponseDefinitions.php @@ -53,7 +53,7 @@ * create: bool, * update: bool, * delete: bool, - * manage: bool + * manage: bool, * }, * hasShares: bool, * rowsCount: int, diff --git a/lib/Service/PermissionsService.php b/lib/Service/PermissionsService.php index 19313f9be..2a4bdb7d8 100644 --- a/lib/Service/PermissionsService.php +++ b/lib/Service/PermissionsService.php @@ -15,6 +15,7 @@ use OCA\Tables\Errors\NotFoundError; use OCA\Tables\Helper\ConversionHelper; use OCA\Tables\Helper\UserHelper; +use OCA\Tables\Model\Permissions; use OCP\AppFramework\Db\DoesNotExistException; use OCP\AppFramework\Db\MultipleObjectsReturnedException; use OCP\DB\Exception; @@ -414,31 +415,32 @@ public function canReadShare(Share $share, ?string $userId = null): bool { * @param int $elementId * @param 'table'|'view' $elementType * @param string $userId - * @return array * @throws NotFoundError */ - public function getSharedPermissionsIfSharedWithMe(int $elementId, string $elementType, string $userId): array { + public function getSharedPermissionsIfSharedWithMe(int $elementId, string $elementType, string $userId): Permissions { try { $shares = $this->shareMapper->findAllSharesForNodeFor($elementType, $elementId, $userId); } catch (Exception $e) { $this->logger->warning('Exception occurred: '.$e->getMessage().' Permission denied.'); - return []; + return new Permissions(); } try { $userGroups = $this->userHelper->getGroupsForUser($userId); } catch (InternalError $e) { $this->logger->warning('Exception occurred: '.$e->getMessage().' Permission denied.'); - return []; + return new Permissions(); } + $additionalShares = []; foreach ($userGroups as $userGroup) { try { - $shares = array_merge($shares, $this->shareMapper->findAllSharesForNodeFor($elementType, $elementId, $userGroup->getGid(), 'group')); + $additionalShares[] = $this->shareMapper->findAllSharesForNodeFor($elementType, $elementId, $userGroup->getGid(), 'group'); } catch (Exception $e) { $this->logger->warning('Exception occurred: '.$e->getMessage().' Permission denied.'); - return []; + return new Permissions(); } } + $shares = array_merge($shares, ...$additionalShares); if (count($shares) > 0) { $read = array_reduce($shares, function ($carry, $share) { return $carry || ($share->getPermissionRead()); @@ -456,13 +458,13 @@ public function getSharedPermissionsIfSharedWithMe(int $elementId, string $eleme return $carry || ($share->getPermissionManage()); }, false); - return [ - 'read' => $read || $update || $delete || $manage, - 'create' => $create || $manage, - 'update' => $update || $manage, - 'delete' => $delete || $manage, - 'manage' => $manage, - ]; + return new Permissions( + read: $read || $update || $delete || $manage, + create: $create || $manage, + update: $update || $manage, + delete: $delete || $manage, + manage: $manage, + ); } throw new NotFoundError('No share for '.$elementType.' and given user ID found.'); } @@ -498,15 +500,15 @@ public function getPermissionIfAvailableThroughContext(int $nodeId, string $node /** * @throws NotFoundError */ - public function getPermissionArrayForNodeFromContexts(int $nodeId, string $nodeType, string $userId) { + public function getPermissionArrayForNodeFromContexts(int $nodeId, string $nodeType, string $userId): Permissions { $permissions = $this->getPermissionIfAvailableThroughContext($nodeId, $nodeType, $userId); - return [ - 'read' => (bool)($permissions & Application::PERMISSION_READ), - 'create' => (bool)($permissions & Application::PERMISSION_CREATE), - 'update' => (bool)($permissions & Application::PERMISSION_UPDATE), - 'delete' => (bool)($permissions & Application::PERMISSION_DELETE), - 'manage' => (bool)($permissions & Application::PERMISSION_MANAGE), - ]; + return new Permissions( + read: (bool)($permissions & Application::PERMISSION_READ), + create: (bool)($permissions & Application::PERMISSION_CREATE), + update: (bool)($permissions & Application::PERMISSION_UPDATE), + delete: (bool)($permissions & Application::PERMISSION_DELETE), + manage: (bool)($permissions & Application::PERMISSION_MANAGE), + ); } private function hasPermission(int $existingPermissions, string $permissionName): bool { @@ -527,7 +529,7 @@ private function hasPermission(int $existingPermissions, string $permissionName) /** * @param Table|View|Context $element * @param 'table'|'view'|'context' $nodeType - * @param string $permission + * @param 'read'|'create'|'update'|'delete'|'manage'|'manageTable' $permission * @param string|null $userId * @return bool */ @@ -541,7 +543,7 @@ private function checkPermission(Table|View|Context $element, string $nodeType, } try { - return $this->getSharedPermissionsIfSharedWithMe($element->getId(), $nodeType, $userId)[$permission]; + return $this->getSharedPermissionsIfSharedWithMe($element->getId(), $nodeType, $userId)->$permission; } catch (NotFoundError $e) { try { if ($nodeType !== 'context' @@ -560,7 +562,7 @@ private function checkPermission(Table|View|Context $element, string $nodeType, /** * @param int $elementId * @param 'table'|'view' $nodeType - * @param string $permission + * @param 'read'|'create'|'update'|'delete'|'manage'|'manageTable' $permission * @param string|null $userId * @return bool */ @@ -570,7 +572,7 @@ private function checkPermissionById(int $elementId, string $nodeType, string $p } if ($userId) { try { - return $this->getSharedPermissionsIfSharedWithMe($elementId, $nodeType, $userId)[$permission]; + return $this->getSharedPermissionsIfSharedWithMe($elementId, $nodeType, $userId)->$permission; } catch (NotFoundError $e) { try { if ($this->hasPermission($this->getPermissionIfAvailableThroughContext($elementId, $nodeType, $userId), $permission)) { @@ -602,7 +604,7 @@ private function basisCheck(Table|View|Context $element, string $nodeType, ?stri } try { $permissions = $this->getSharedPermissionsIfSharedWithMe($nodeType === 'view' ? $element->getTableId() : $element->getId(), 'table', $userId); - if($permissions['manage']) { + if ($permissions->manage) { return true; } } catch (NotFoundError $e) { diff --git a/lib/Service/ShareService.php b/lib/Service/ShareService.php index 56927c13a..a90da2dc1 100644 --- a/lib/Service/ShareService.php +++ b/lib/Service/ShareService.php @@ -22,6 +22,7 @@ use OCA\Tables\Helper\GroupHelper; use OCA\Tables\Helper\UserHelper; +use OCA\Tables\Model\Permissions; use OCA\Tables\ResponseDefinitions; use OCP\AppFramework\Db\DoesNotExistException; use OCP\AppFramework\Db\MultipleObjectsReturnedException; @@ -186,15 +187,14 @@ private function findElementsSharedWithMe(string $elementType = 'table', ?string * @param int $elementId * @param 'table'|'view' $elementType * @param string|null $userId - * @return array * @throws NotFoundError */ - public function getSharedPermissionsIfSharedWithMe(int $elementId, string $elementType = 'table', ?string $userId = null): array { + public function getSharedPermissionsIfSharedWithMe(int $elementId, string $elementType = 'table', ?string $userId = null): Permissions { try { $userId = $this->permissionsService->preCheckUserId($userId); } catch (InternalError $e) { $this->logger->warning('Could not pre check user: '.$e->getMessage().' Permission denied.'); - return []; + return new Permissions(); } return $this->permissionsService->getSharedPermissionsIfSharedWithMe($elementId, $elementType, $userId); } diff --git a/lib/Service/TableService.php b/lib/Service/TableService.php index 892f7debc..2d86a33ca 100644 --- a/lib/Service/TableService.php +++ b/lib/Service/TableService.php @@ -222,7 +222,7 @@ private function enhanceTable(Table $table, string $userId): void { } } - if (!$table->getIsShared() || $table->getOnSharePermissions()['manage']) { + if (!$table->getIsShared() || $table->getOnSharePermissions()->manage) { // add the corresponding views if it is an own table, or you have table manage rights $table->setViews($this->viewService->findAll($table)); } diff --git a/lib/Service/ViewService.php b/lib/Service/ViewService.php index 2c545886c..f24a3f44d 100644 --- a/lib/Service/ViewService.php +++ b/lib/Service/ViewService.php @@ -18,6 +18,7 @@ use OCA\Tables\Errors\PermissionError; use OCA\Tables\Event\ViewDeletedEvent; use OCA\Tables\Helper\UserHelper; +use OCA\Tables\Model\Permissions; use OCA\Tables\ResponseDefinitions; use OCP\AppFramework\Db\DoesNotExistException; use OCP\AppFramework\Db\MultipleObjectsReturnedException; @@ -374,7 +375,9 @@ private function enhanceView(View $view, string $userId): void { } catch (NotFoundError) { $manageTableShare = $this->permissionsService->getPermissionArrayForNodeFromContexts($view->getTableId(), 'table', $userId); } finally { - $permissions['manageTable'] = $manageTableShare['manage'] ?? false; + if ($manageTableShare->manage) { + $permissions->manageTable = true; + } } } catch (NotFoundError $e) { } catch (\Exception $e) { @@ -384,14 +387,7 @@ private function enhanceView(View $view, string $userId): void { } catch (NotFoundError $e) { } catch (\Exception $e) { $this->logger->warning('Exception occurred while setting shared permissions: ' . $e->getMessage() . ' No permissions granted.'); - $view->setOnSharePermissions([ - 'read' => false, - 'create' => false, - 'update' => false, - 'delete' => false, - 'manage' => false, - 'manageTable' => false - ]); + $view->setOnSharePermissions(new Permissions()); } } else { // set hasShares if this table is shared by you (you share it with somebody else) @@ -414,31 +410,29 @@ private function enhanceView(View $view, string $userId): void { } catch (InternalError|PermissionError $e) { } - if ($view->getIsShared()) { - // Remove detailed view filtering and sorting information if necessary - if (!$view->getOnSharePermissions()['manageTable']) { - $rawFilterArray = $view->getFilterArray(); - if ($rawFilterArray) { - $view->setFilterArray( - array_map(static function ($filterGroup) { - // Instead of filter just indicate that there is a filter, but hide details - return array_map(null, $filterGroup); - }, - $rawFilterArray)); - } - $rawSortArray = $view->getSortArray(); - if ($rawSortArray) { - $view->setSortArray( - array_map(static function ($sortRule) use ($view) { - $columnsArray = $view->getColumnsArray(); - if (isset($sortRule['columnId']) && $columnsArray && in_array($sortRule['columnId'], $columnsArray, true)) { - return $sortRule; - } - // Instead of sort rule just indicate that there is a rule, but hide details - return null; - }, - $rawSortArray)); - } + // Remove detailed view filtering and sorting information if necessary + if ($view->getIsShared() && !$view->getOnSharePermissions()->manageTable) { + $rawFilterArray = $view->getFilterArray(); + if ($rawFilterArray) { + $view->setFilterArray( + array_map(static function ($filterGroup) { + // Instead of filter just indicate that there is a filter, but hide details + return array_map(null, $filterGroup); + }, + $rawFilterArray)); + } + $rawSortArray = $view->getSortArray(); + if ($rawSortArray) { + $view->setSortArray( + array_map(static function ($sortRule) use ($view) { + $columnsArray = $view->getColumnsArray(); + if (isset($sortRule['columnId']) && $columnsArray && in_array($sortRule['columnId'], $columnsArray, true)) { + return $sortRule; + } + // Instead of sort rule just indicate that there is a rule, but hide details + return null; + }, + $rawSortArray)); } }