Skip to content

Commit

Permalink
feat(Context): add share logic for contexts
Browse files Browse the repository at this point in the history
Signed-off-by: Arthur Schiwon <blizzz@arthur-schiwon.de>
  • Loading branch information
blizzz committed Apr 18, 2024
1 parent 82d1518 commit 9da4369
Show file tree
Hide file tree
Showing 10 changed files with 506 additions and 10 deletions.
2 changes: 2 additions & 0 deletions appinfo/routes.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
['name' => 'api1#createShare', 'url' => '/api/1/shares', 'verb' => 'POST'],
['name' => 'api1#deleteShare', 'url' => '/api/1/shares/{shareId}', 'verb' => 'DELETE'],
['name' => 'api1#updateSharePermissions', 'url' => '/api/1/shares/{shareId}', 'verb' => 'PUT'],
['name' => 'api1#updateShareDisplayMode', 'url' => '/api/1/shares/{shareId}/display-mode', 'verb' => 'PUT'],
['name' => 'api1#createTableShare', 'url' => '/api/1/tables/{tableId}/shares', 'verb' => 'POST'],
// -> columns
['name' => 'api1#indexTableColumns', 'url' => '/api/1/tables/{tableId}/columns', 'verb' => 'GET'],
Expand Down Expand Up @@ -97,6 +98,7 @@
['name' => 'share#show', 'url' => '/share/{id}', 'verb' => 'GET'],
['name' => 'share#create', 'url' => '/share', 'verb' => 'POST'],
['name' => 'share#updatePermission', 'url' => '/share/{id}/permission', 'verb' => 'PUT'],
['name' => 'share#updateDisplayMode', 'url' => '/share/{id}/display-mode', 'verb' => 'PUT'],
['name' => 'share#destroy', 'url' => '/share/{id}', 'verb' => 'DELETE'],

// import
Expand Down
68 changes: 65 additions & 3 deletions lib/Controller/Api1Controller.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
* @psalm-import-type TablesColumn from ResponseDefinitions
* @psalm-import-type TablesRow from ResponseDefinitions
* @psalm-import-type TablesImportState from ResponseDefinitions
* @psalm-import-type TablesContextNavigation from ResponseDefinitions
*/
class Api1Controller extends ApiController {
private TableService $tableService;
Expand Down Expand Up @@ -483,15 +484,27 @@ public function indexTableShares(int $tableId): DataResponse {
* @param bool $permissionUpdate Permission if receiver can update data
* @param bool $permissionDelete Permission if receiver can delete data
* @param bool $permissionManage Permission if receiver can manage node
* @param int $displayMode context shares only, whether it should appear in nav bar. 0: no, 1: recipients, 2: all
* @return DataResponse<Http::STATUS_OK, TablesShare, array{}>|DataResponse<Http::STATUS_FORBIDDEN|Http::STATUS_INTERNAL_SERVER_ERROR|Http::STATUS_NOT_FOUND, array{message: string}, array{}>
*
* 200: Share returned
* 403: No permissions
* 404: Not found
*/
public function createShare(int $nodeId, string $nodeType, string $receiver, string $receiverType, bool $permissionRead = false, bool $permissionCreate = false, bool $permissionUpdate = false, bool $permissionDelete = false, bool $permissionManage = false): DataResponse {
public function createShare(
int $nodeId,
string $nodeType,
string $receiver,
string $receiverType,
bool $permissionRead = false,
bool $permissionCreate = false,
bool $permissionUpdate = false,
bool $permissionDelete = false,
bool $permissionManage = false,
int $displayMode = 0,
): DataResponse {
try {
return new DataResponse($this->shareService->create($nodeId, $nodeType, $receiver, $receiverType, $permissionRead, $permissionCreate, $permissionUpdate, $permissionDelete, $permissionManage)->jsonSerialize());
return new DataResponse($this->shareService->create($nodeId, $nodeType, $receiver, $receiverType, $permissionRead, $permissionCreate, $permissionUpdate, $permissionDelete, $permissionManage, $displayMode)->jsonSerialize());
} catch (PermissionError $e) {
$this->logger->warning('A permission error occurred: '.$e->getMessage());
$message = ['message' => $e->getMessage()];
Expand Down Expand Up @@ -573,6 +586,55 @@ public function updateSharePermissions(int $shareId, string $permissionType, boo
}
}

/**
* Updates the display mode of a context share
*
* @NoAdminRequired
* @CORS
* @NoCSRFRequired
*
* @param int $shareId Share ID
* @param int $displayMode The new value for the display mode of the nav bar icon. 0: hidden, 1: visible for recipients, 2: visible for all
* @param string $target "default" to set the default, "self" to set an override for the authenticated user
* @return DataResponse<Http::STATUS_OK, TablesContextNavigation, array{}>|DataResponse<Http::STATUS_BAD_REQUEST|Http::STATUS_FORBIDDEN|Http::STATUS_INTERNAL_SERVER_ERROR|Http::STATUS_NOT_FOUND, array{message: string}, array{}>
*
* 200: Display mode updated
* 400: Invalid parameter
* 403: No permissions
* 404: Share not found
*
* @psalm-param int<0, 2> $displayMode
* @psalm-param ("default"|"self") $target
*/
public function updateShareDisplayMode(int $shareId, int $displayMode, string $target = 'default'): DataResponse {
if ($target === 'default') {
$userId = '';
} elseif ($target === 'self') {
$userId = $this->userId;
} else {
$error = 'target parameter must be either "default" or "self"';
$this->logger->warning(sprintf('An internal error or exception occurred: %s', $error));
$message = ['message' => $error];
return new DataResponse($message, Http::STATUS_BAD_REQUEST);
}

try {
return new DataResponse($this->shareService->updateDisplayMode($shareId, $displayMode, $userId)->jsonSerialize());
} catch (InternalError $e) {
$this->logger->warning('An internal error or exception occurred: '.$e->getMessage());
$message = ['message' => $e->getMessage()];
return new DataResponse($message, Http::STATUS_INTERNAL_SERVER_ERROR);
} catch (NotFoundError $e) {
$this->logger->warning('A not found error occurred: ' . $e->getMessage());
$message = ['message' => $e->getMessage()];
return new DataResponse($message, Http::STATUS_NOT_FOUND);
} catch (PermissionError $e) {
$this->logger->warning('A permission error occurred: '.$e->getMessage());
$message = ['message' => $e->getMessage()];
return new DataResponse($message, Http::STATUS_FORBIDDEN);
}
}

// Columns

/**
Expand Down Expand Up @@ -1303,7 +1365,7 @@ public function importInView(int $viewId, string $path, bool $createMissingColum
*/
public function createTableShare(int $tableId, string $receiver, string $receiverType, bool $permissionRead, bool $permissionCreate, bool $permissionUpdate, bool $permissionDelete, bool $permissionManage): DataResponse {
try {
return new DataResponse($this->shareService->create($tableId, 'table', $receiver, $receiverType, $permissionRead, $permissionCreate, $permissionUpdate, $permissionDelete, $permissionManage)->jsonSerialize());
return new DataResponse($this->shareService->create($tableId, 'table', $receiver, $receiverType, $permissionRead, $permissionCreate, $permissionUpdate, $permissionDelete, $permissionManage, 0)->jsonSerialize());
} catch (PermissionError $e) {
$this->logger->warning('A permission error occurred: '.$e->getMessage());
$message = ['message' => $e->getMessage()];
Expand Down
36 changes: 33 additions & 3 deletions lib/Controller/ShareController.php
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,20 @@ public function show(int $id): DataResponse {
/**
* @NoAdminRequired
*/
public function create(int $nodeId, string $nodeType, string $receiver, string $receiverType, bool $permissionRead = false, bool $permissionCreate = false, bool $permissionUpdate = false, bool $permissionDelete = false, bool $permissionManage = false): DataResponse {
return $this->handleError(function () use ($nodeId, $nodeType, $receiver, $receiverType, $permissionRead, $permissionCreate, $permissionUpdate, $permissionDelete, $permissionManage) {
return $this->service->create($nodeId, $nodeType, $receiver, $receiverType, $permissionRead, $permissionCreate, $permissionUpdate, $permissionDelete, $permissionManage);
public function create(
int $nodeId,
string $nodeType,
string $receiver,
string $receiverType,
bool $permissionRead = false,
bool $permissionCreate = false,
bool $permissionUpdate = false,
bool $permissionDelete = false,
bool $permissionManage = false,
int $displayMode = 0,
): DataResponse {
return $this->handleError(function () use ($nodeId, $nodeType, $receiver, $receiverType, $permissionRead, $permissionCreate, $permissionUpdate, $permissionDelete, $permissionManage, $displayMode) {
return $this->service->create($nodeId, $nodeType, $receiver, $receiverType, $permissionRead, $permissionCreate, $permissionUpdate, $permissionDelete, $permissionManage, $displayMode);
});
}

Expand All @@ -76,6 +87,25 @@ public function updatePermission(int $id, string $permission, bool $value): Data
});
}

/**
* @NoAdminRequired
* @psalm-param int<0, 2> $displayMode
* @psalm-param ("default"|"self") $target
*/
public function updateDisplayMode(int $id, int $displayMode, string $target = 'default') {
return $this->handleError(function () use ($id, $displayMode, $target) {
if ($target === 'default') {
$userId = '';
} elseif ($target === 'self') {
$userId = $this->userId;
} else {
throw new \InvalidArgumentException('target parameter must be either "default" or "self"');
}

return $this->service->updateDisplayMode($id, $displayMode, $userId);
});
}

/**
* @NoAdminRequired
*/
Expand Down
35 changes: 35 additions & 0 deletions lib/Db/ContextNavigation.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php

declare(strict_types=1);

namespace OCA\Tables\Db;

use OCP\AppFramework\Db\Entity;

/**
* @method getShareId(): int
* @method setShareId(int $value): void
* @method getUserId(): string
* @method setUserId(string $value): void
* @method getDisplayMode(): int
* @method setDisplayMode(int $value): void
*/
class ContextNavigation extends Entity implements \JsonSerializable {
protected ?int $shareId;
protected ?string $userId;
protected ?int $displayMode;

public function __construct() {
$this->addType('shareId', 'integer');
$this->addType('displayMode', 'integer');
}

public function jsonSerialize(): array {
return [
'id' => $this->getId(),
'shareId' => $this->getShareId(),
'displayMode' => $this->getDisplayMode(),
'userId' => $this->getUserId(),
];
}
}
41 changes: 41 additions & 0 deletions lib/Db/ContextNavigationMapper.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?php

declare(strict_types=1);

namespace OCA\Tables\Db;

use OCP\AppFramework\Db\QBMapper;
use OCP\DB\Exception;
use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\IDBConnection;

/** @template-extends QBMapper<ContextNavigation> */
class ContextNavigationMapper extends QBMapper {
protected string $table = 'tables_contexts_navigation';

public function __construct(IDBConnection $db) {
parent::__construct($db, $this->table, ContextNavigation::class);
}

/**
* @throws Exception
*/
public function deleteByShareId(int $shareId): int {
$qb = $this->db->getQueryBuilder();
$qb->delete($this->table)
->where($qb->expr()->eq('share_id', $qb->createNamedParameter($shareId, IQueryBuilder::PARAM_INT)));
return $qb->executeStatement();
}

/**
* @throws Exception
*/
public function setDisplayModeByShareId(int $shareId, int $displayMode, string $userId): ContextNavigation {
$entity = new ContextNavigation();
$entity->setShareId($shareId);
$entity->setDisplayMode($displayMode);
$entity->setUserId($userId);

return $this->insertOrUpdate($entity);
}
}
7 changes: 7 additions & 0 deletions lib/ResponseDefinitions.php
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,13 @@
* owner: string,
* ownerType: int,
* }
*
* @psalm-type TablesContextNavigation = array{
* id: int,
* shareId: int,
* displayMode: int,
* userId: string,
* }
*/
class ResponseDefinitions {
}
12 changes: 12 additions & 0 deletions lib/Service/PermissionsService.php
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,18 @@ public function canManageContextById(int $contextId, ?string $userId = null): bo
return $context->getOwnerId() === $userId;
}

/**
* @throws Exception
*/
public function canAccessContextById(int $contextId, ?string $userId = null): bool {
try {
$this->contextMapper->findById($contextId, $userId ?? $this->userId);
return true;
} catch (NotFoundError $e) {
return false;
}
}

public function canAccessView(View $view, ?string $userId = null): bool {
return $this->canAccessNodeById(Application::NODE_TYPE_VIEW, $view->getId(), $userId);
}
Expand Down
Loading

0 comments on commit 9da4369

Please sign in to comment.