Repository navigation
🗃️ Make archiving tables/applications a personal option #2476
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
073e7e4
aa47bb7
27e02ab
b22b7ff
bb2d5fc
27113d1
408f6b8
49bf195
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,59 @@ | ||
| <?php | ||
|
|
||
| declare(strict_types=1); | ||
|
|
||
| /** | ||
| * SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors | ||
| * SPDX-License-Identifier: AGPL-3.0-or-later | ||
| */ | ||
|
|
||
| namespace OCA\Tables\BackgroundJob; | ||
|
|
||
| use OCA\Tables\AppInfo\Application; | ||
| use OCA\Tables\Service\ArchiveCleanupService; | ||
| use OCP\AppFramework\Utility\ITimeFactory; | ||
| use OCP\BackgroundJob\QueuedJob; | ||
| use Psr\Log\LoggerInterface; | ||
|
|
||
| /** | ||
| * Drops the archive overrides of users who lost access to a node. | ||
| * | ||
| * Deciding this per user costs a full permission resolution, so it runs out | ||
| * of band: the triggering request (a share deletion, a group or team removal) | ||
| * only records which users to check for which node. | ||
| */ | ||
| class CleanupArchiveOverridesJob extends QueuedJob { | ||
| public function __construct( | ||
| ITimeFactory $time, | ||
| private readonly ArchiveCleanupService $archiveCleanupService, | ||
| private readonly LoggerInterface $logger, | ||
| ) { | ||
| parent::__construct($time); | ||
| } | ||
|
|
||
| /** | ||
| * @param mixed $argument array{nodeType: int, nodeId: int, userIds: list<string>} | ||
| */ | ||
| protected function run($argument): void { | ||
| if (!is_array($argument)) { | ||
| $this->logger->warning('Cannot clean up archive overrides: invalid argument'); | ||
| return; | ||
| } | ||
|
|
||
| $nodeType = (int)($argument['nodeType'] ?? -1); | ||
| $nodeId = (int)($argument['nodeId'] ?? 0); | ||
| $userIds = $argument['userIds'] ?? []; | ||
|
|
||
| if ($nodeId <= 0 || !is_array($userIds) || $userIds === []) { | ||
| return; | ||
| } | ||
| if (!in_array($nodeType, [Application::NODE_TYPE_TABLE, Application::NODE_TYPE_CONTEXT], true)) { | ||
| $this->logger->warning('Cannot clean up archive overrides: unsupported node type ' . $nodeType); | ||
| return; | ||
| } | ||
|
|
||
| foreach ($userIds as $userId) { | ||
| $this->archiveCleanupService->removeOverrideIfStale((string)$userId, $nodeType, $nodeId); | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -29,6 +29,7 @@ | |
| use OCP\App\IAppManager; | ||
| use OCP\AppFramework\Http; | ||
| use OCP\AppFramework\Http\Attribute\NoAdminRequired; | ||
| use OCP\AppFramework\Http\Attribute\UserRateLimit; | ||
| use OCP\AppFramework\Http\DataResponse; | ||
| use OCP\IDBConnection; | ||
| use OCP\IL10N; | ||
|
|
@@ -87,7 +88,7 @@ public function index(): DataResponse { | |
| #[RequirePermission(permission: Application::PERMISSION_READ, type: Application::NODE_TYPE_TABLE, idParam: 'id')] | ||
| public function show(int $id): DataResponse { | ||
| try { | ||
| return new DataResponse($this->service->find($id)->jsonSerialize()); | ||
| return new DataResponse($this->service->getTableForUser($id, $this->userId)->jsonSerialize()); | ||
| } catch (PermissionError $e) { | ||
| return $this->handlePermissionError($e); | ||
| } catch (InternalError $e) { | ||
|
|
@@ -479,6 +480,64 @@ public function destroy(int $id): DataResponse { | |
| } | ||
| } | ||
|
|
||
| /** | ||
| * [api v2] Archive a table for the requesting user | ||
| * | ||
| * Owners archive the table for all users (clears per-user overrides). | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This seems misleading, since the owner archive path does not clear personal rows. |
||
| * Non-owners archive only for themselves. | ||
| * | ||
| * @param int $id Table ID | ||
| * @return DataResponse<Http::STATUS_OK, TablesTable, array{}>|DataResponse<Http::STATUS_FORBIDDEN|Http::STATUS_INTERNAL_SERVER_ERROR|Http::STATUS_NOT_FOUND, array{message: string}, array{}> | ||
| * | ||
| * 200: Table returned with updated archived state | ||
| * 403: No permissions | ||
| * 404: Not found | ||
| */ | ||
| #[NoAdminRequired] | ||
| #[UserRateLimit(limit: 20, period: 60)] | ||
| #[RequirePermission(permission: Application::PERMISSION_READ, type: Application::NODE_TYPE_TABLE, idParam: 'id')] | ||
| public function archiveTable(int $id): DataResponse { | ||
| return $this->archiveResponse($id, true); | ||
| } | ||
|
|
||
| /** | ||
| * [api v2] Unarchive a table for the requesting user | ||
| * | ||
| * Owners unarchive the table for all users (clears per-user overrides). | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. similar as at https://github.com/nextcloud/tables/pull/2476/changes#r4309477879 . The owner archive path does not clear personal rows. |
||
| * Non-owners remove only their personal archive override. | ||
| * | ||
| * @param int $id Table ID | ||
| * @return DataResponse<Http::STATUS_OK, TablesTable, array{}>|DataResponse<Http::STATUS_FORBIDDEN|Http::STATUS_INTERNAL_SERVER_ERROR|Http::STATUS_NOT_FOUND, array{message: string}, array{}> | ||
| * | ||
| * 200: Table returned with updated archived state | ||
| * 403: No permissions | ||
| * 404: Not found | ||
| */ | ||
| #[NoAdminRequired] | ||
| #[UserRateLimit(limit: 20, period: 60)] | ||
| #[RequirePermission(permission: Application::PERMISSION_READ, type: Application::NODE_TYPE_TABLE, idParam: 'id')] | ||
| public function unarchiveTable(int $id): DataResponse { | ||
| return $this->archiveResponse($id, false); | ||
| } | ||
|
|
||
| /** | ||
| * @return DataResponse<Http::STATUS_OK, TablesTable, array{}>|DataResponse<Http::STATUS_FORBIDDEN|Http::STATUS_INTERNAL_SERVER_ERROR|Http::STATUS_NOT_FOUND, array{message: string}, array{}> | ||
| */ | ||
| private function archiveResponse(int $id, bool $archived): DataResponse { | ||
| try { | ||
| $table = $archived | ||
| ? $this->service->archiveTable($id, $this->userId) | ||
| : $this->service->unarchiveTable($id, $this->userId); | ||
| return new DataResponse($table->jsonSerialize()); | ||
| } catch (PermissionError $e) { | ||
| return $this->handlePermissionError($e); | ||
| } catch (InternalError $e) { | ||
| return $this->handleError($e); | ||
| } catch (NotFoundError $e) { | ||
| return $this->handleNotFoundError($e); | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * [api v2] Transfer table | ||
| * | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -25,6 +25,7 @@ | |
| use OCP\AppFramework\Db\MultipleObjectsReturnedException; | ||
| use OCP\AppFramework\Http; | ||
| use OCP\AppFramework\Http\Attribute\NoAdminRequired; | ||
| use OCP\AppFramework\Http\Attribute\UserRateLimit; | ||
| use OCP\AppFramework\Http\DataResponse; | ||
| use OCP\DB\Exception; | ||
| use OCP\IDBConnection; | ||
|
|
@@ -255,6 +256,64 @@ public function transfer(int $contextId, string $newOwnerId, int $newOwnerType = | |
| } | ||
| } | ||
|
|
||
| /** | ||
| * [api v2] Archive a context for the requesting user | ||
| * | ||
| * Owners archive the context for all users (clears per-user overrides). | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. similar as at https://github.com/nextcloud/tables/pull/2476/changes#r4309477879 . The owner archive path does not clear personal rows. |
||
| * Non-owners archive only for themselves. | ||
| * | ||
| * @param int $contextId ID of the context | ||
| * @return DataResponse<Http::STATUS_OK, TablesContext, array{}>|DataResponse<Http::STATUS_FORBIDDEN|Http::STATUS_INTERNAL_SERVER_ERROR|Http::STATUS_NOT_FOUND, array{message: string}, array{}> | ||
| * | ||
| * 200: Context returned with updated archived state | ||
| * 403: No permissions | ||
| * 404: Context not found or not available | ||
| */ | ||
| #[NoAdminRequired] | ||
| #[UserRateLimit(limit: 20, period: 60)] | ||
| #[RequirePermission(permission: Application::PERMISSION_READ, typeParam: 'context', idParam: 'contextId')] | ||
| public function archiveContext(int $contextId): DataResponse { | ||
| return $this->archiveResponse($contextId, true); | ||
| } | ||
|
|
||
| /** | ||
| * [api v2] Unarchive a context for the requesting user | ||
| * | ||
| * Owners unarchive the context for all users (clears per-user overrides). | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. similar as at https://github.com/nextcloud/tables/pull/2476/changes#r4309477879 . The owner archive path does not clear personal rows. |
||
| * Non-owners remove only their personal archive override. | ||
| * | ||
| * @param int $contextId ID of the context | ||
| * @return DataResponse<Http::STATUS_OK, TablesContext, array{}>|DataResponse<Http::STATUS_FORBIDDEN|Http::STATUS_INTERNAL_SERVER_ERROR|Http::STATUS_NOT_FOUND, array{message: string}, array{}> | ||
| * | ||
| * 200: Context returned with updated archived state | ||
| * 403: No permissions | ||
| * 404: Context not found or not available | ||
| */ | ||
| #[NoAdminRequired] | ||
| #[UserRateLimit(limit: 20, period: 60)] | ||
| #[RequirePermission(permission: Application::PERMISSION_READ, typeParam: 'context', idParam: 'contextId')] | ||
| public function unarchiveContext(int $contextId): DataResponse { | ||
| return $this->archiveResponse($contextId, false); | ||
| } | ||
|
|
||
| /** | ||
| * @return DataResponse<Http::STATUS_OK, TablesContext, array{}>|DataResponse<Http::STATUS_FORBIDDEN|Http::STATUS_INTERNAL_SERVER_ERROR|Http::STATUS_NOT_FOUND, array{message: string}, array{}> | ||
| */ | ||
| private function archiveResponse(int $contextId, bool $archived): DataResponse { | ||
| try { | ||
| $context = $archived | ||
| ? $this->contextService->archiveContext($contextId, $this->userId) | ||
| : $this->contextService->unarchiveContext($contextId, $this->userId); | ||
| return new DataResponse($context->jsonSerialize()); | ||
| } catch (PermissionError $e) { | ||
| return $this->handlePermissionError($e); | ||
| } catch (NotFoundError $e) { | ||
| return $this->handleNotFoundError($e); | ||
| } catch (InternalError|Exception $e) { | ||
| return $this->handleError($e); | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * [api v2] Update the order on a page of a context | ||
| * | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So there is now no way to unarchive a table with
occ tables:rename?