Skip to content

Commit

Permalink
enh: warn about table use in app during manager demotion
Browse files Browse the repository at this point in the history
Signed-off-by: Cleopatra Enjeck M <[email protected]>
  • Loading branch information
enjeck committed Oct 29, 2024
1 parent 9bf572c commit 8cf9e5c
Show file tree
Hide file tree
Showing 6 changed files with 73 additions and 1 deletion.
1 change: 1 addition & 0 deletions appinfo/routes.php
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@
['name' => 'ApiTables#update', 'url' => '/api/2/tables/{id}', 'verb' => 'PUT'],
['name' => 'ApiTables#destroy', 'url' => '/api/2/tables/{id}', 'verb' => 'DELETE'],
['name' => 'ApiTables#transfer', 'url' => '/api/2/tables/{id}/transfer', 'verb' => 'PUT'],
['name' => 'ApiTables#indexContext', 'url' => '/api/2/tables/{id}/index-context', 'verb' => 'GET'],

['name' => 'ApiColumns#index', 'url' => '/api/2/columns/{nodeType}/{nodeId}', 'verb' => 'GET'],
['name' => 'ApiColumns#show', 'url' => '/api/2/columns/{id}', 'verb' => 'GET'],
Expand Down
27 changes: 27 additions & 0 deletions lib/Controller/ApiTablesController.php
Original file line number Diff line number Diff line change
Expand Up @@ -288,4 +288,31 @@ public function transfer(int $id, string $newOwnerUserId): DataResponse {
return $this->handleNotFoundError($e);
}
}


/**
* [api v2] Index contexts
*
* Index contexts used in a table
*
* @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{}>

Check failure on line 300 in lib/Controller/ApiTablesController.php

View workflow job for this annotation

GitHub Actions / static-psalm-analysis dev-master

InvalidReturnType

lib/Controller/ApiTablesController.php:300:13: InvalidReturnType: The declared return type 'OCP\AppFramework\Http\DataResponse<200|403|404|500, array{archived?: bool, columnsCount?: int, createdAt?: string, createdBy?: string, emoji?: null|string, favorite?: bool, hasShares?: bool, id?: int, isShared?: bool, lastEditAt?: string, lastEditBy?: string, message?: string, onSharePermissions?: array{create: bool, delete: bool, manage: bool, read: bool, update: bool}|null, ownerDisplayName?: string, ownership?: string, rowsCount?: int, title?: string, views?: array<array-key, array{columns: array<array-key, int>, createdAt: string, createdBy: string, description: null|string, emoji: null|string, favorite: bool, filter: list<list<array{columnId: int, operator: 'begins-with'|'contains'|'ends-with'|'is-empty'|'is-equal'|'is-greater-than'|'is-greater-than-or-equal'|'is-lower-than'|'is-lower-than-or-equal', value: float|int|string}>>, hasShares: bool, id: int, isShared: bool, lastEditAt: string, lastEditBy: string, onSharePermissions: array{create: bool, delete: bool, manage: bool, read: bool, update: bool}|null, ownerDisplayName: null|string, ownership: string, rowsCount: int, sort: list<array{columnId: int, mode: 'ASC'|'DESC'}>, tableId: int, title: string}>}, array<never, never>>' for OCA\Tables\Controller\ApiTablesController::indexContext is incorrect, got 'OCP\AppFramework\Http\DataResponse<200|403|404|500, array{contexts?: array<array-key, mixed>, message?: string}, array<never, never>>' (see https://psalm.dev/011)

Check failure on line 300 in lib/Controller/ApiTablesController.php

View workflow job for this annotation

GitHub Actions / static-psalm-analysis dev-stable28

InvalidReturnType

lib/Controller/ApiTablesController.php:300:13: InvalidReturnType: The declared return type 'OCP\AppFramework\Http\DataResponse<200|403|404|500, array{archived?: bool, columnsCount?: int, createdAt?: string, createdBy?: string, emoji?: null|string, favorite?: bool, hasShares?: bool, id?: int, isShared?: bool, lastEditAt?: string, lastEditBy?: string, message?: string, onSharePermissions?: array{create: bool, delete: bool, manage: bool, read: bool, update: bool}|null, ownerDisplayName?: string, ownership?: string, rowsCount?: int, title?: string, views?: array<array-key, array{columns: array<array-key, int>, createdAt: string, createdBy: string, description: null|string, emoji: null|string, favorite: bool, filter: list<list<array{columnId: int, operator: 'begins-with'|'contains'|'ends-with'|'is-empty'|'is-equal'|'is-greater-than'|'is-greater-than-or-equal'|'is-lower-than'|'is-lower-than-or-equal', value: float|int|string}>>, hasShares: bool, id: int, isShared: bool, lastEditAt: string, lastEditBy: string, onSharePermissions: array{create: bool, delete: bool, manage: bool, read: bool, update: bool}|null, ownerDisplayName: null|string, ownership: string, rowsCount: int, sort: list<array{columnId: int, mode: 'ASC'|'DESC'}>, tableId: int, title: string}>}, array<never, never>>' for OCA\Tables\Controller\ApiTablesController::indexContext is incorrect, got 'OCP\AppFramework\Http\DataResponse<200|403|404|500, array{contexts?: array<array-key, mixed>, message?: string}, array<never, never>>' (see https://psalm.dev/011)
*
* 200: Contexts listed
* 403: No permissions
* 404: Table not found
*/
#[NoAdminRequired]
public function indexContext(int $id): DataResponse {
try {
return new DataResponse(['contexts' => $this->service->listContextsByTable($id, $this->userId)]);

Check failure on line 309 in lib/Controller/ApiTablesController.php

View workflow job for this annotation

GitHub Actions / static-psalm-analysis dev-master

InvalidReturnStatement

lib/Controller/ApiTablesController.php:309:11: InvalidReturnStatement: The inferred type 'OCP\AppFramework\Http\DataResponse<200, array{contexts: array<array-key, mixed>}, array<never, never>>' does not match the declared return type 'OCP\AppFramework\Http\DataResponse<200|403|404|500, array{archived?: bool, columnsCount?: int, createdAt?: string, createdBy?: string, emoji?: null|string, favorite?: bool, hasShares?: bool, id?: int, isShared?: bool, lastEditAt?: string, lastEditBy?: string, message?: string, onSharePermissions?: array{create: bool, delete: bool, manage: bool, read: bool, update: bool}|null, ownerDisplayName?: string, ownership?: string, rowsCount?: int, title?: string, views?: array<array-key, array{columns: array<array-key, int>, createdAt: string, createdBy: string, description: null|string, emoji: null|string, favorite: bool, filter: list<list<array{columnId: int, operator: 'begins-with'|'contains'|'ends-with'|'is-empty'|'is-equal'|'is-greater-than'|'is-greater-than-or-equal'|'is-lower-than'|'is-lower-than-or-equal', value: float|int|string}>>, hasShares: bool, id: int, isShared: bool, lastEditAt: string, lastEditBy: string, onSharePermissions: array{create: bool, delete: bool, manage: bool, read: bool, update: bool}|null, ownerDisplayName: null|string, ownership: string, rowsCount: int, sort: list<array{columnId: int, mode: 'ASC'|'DESC'}>, tableId: int, title: string}>}, array<never, never>>' for OCA\Tables\Controller\ApiTablesController::indexContext (see https://psalm.dev/128)

Check failure on line 309 in lib/Controller/ApiTablesController.php

View workflow job for this annotation

GitHub Actions / static-psalm-analysis dev-stable28

InvalidReturnStatement

lib/Controller/ApiTablesController.php:309:11: InvalidReturnStatement: The inferred type 'OCP\AppFramework\Http\DataResponse<200, array{contexts: array<array-key, mixed>}, array<never, never>>' does not match the declared return type 'OCP\AppFramework\Http\DataResponse<200|403|404|500, array{archived?: bool, columnsCount?: int, createdAt?: string, createdBy?: string, emoji?: null|string, favorite?: bool, hasShares?: bool, id?: int, isShared?: bool, lastEditAt?: string, lastEditBy?: string, message?: string, onSharePermissions?: array{create: bool, delete: bool, manage: bool, read: bool, update: bool}|null, ownerDisplayName?: string, ownership?: string, rowsCount?: int, title?: string, views?: array<array-key, array{columns: array<array-key, int>, createdAt: string, createdBy: string, description: null|string, emoji: null|string, favorite: bool, filter: list<list<array{columnId: int, operator: 'begins-with'|'contains'|'ends-with'|'is-empty'|'is-equal'|'is-greater-than'|'is-greater-than-or-equal'|'is-lower-than'|'is-lower-than-or-equal', value: float|int|string}>>, hasShares: bool, id: int, isShared: bool, lastEditAt: string, lastEditBy: string, onSharePermissions: array{create: bool, delete: bool, manage: bool, read: bool, update: bool}|null, ownerDisplayName: null|string, ownership: string, rowsCount: int, sort: list<array{columnId: int, mode: 'ASC'|'DESC'}>, tableId: int, title: string}>}, array<never, never>>' for OCA\Tables\Controller\ApiTablesController::indexContext (see https://psalm.dev/128)
} catch (PermissionError $e) {
return $this->handlePermissionError($e);
} catch (InternalError $e) {
return $this->handleError($e);
} catch (NotFoundError $e) {
return $this->handleNotFoundError($e);
}
}
}
19 changes: 19 additions & 0 deletions lib/Service/ContextService.php
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,25 @@ public function findById(int $id, ?string $userId): Context {
return $this->contextMapper->findById($id, $userId);
}


/**
* @throws Exception
* @throws InternalError
* @throws NotFoundError
*/
public function findByTableId(int $tableId, ?string $userId): array {
if ($userId !== null && trim($userId) === '') {
$userId = null;
}
if ($userId === null && !$this->isCLI) {
$error = 'Try to set no user in context, but request is not allowed.';
$this->logger->warning($error);
throw new InternalError($error);
}

return $this->contextMapper->findAllContainingNode(Application::NODE_TYPE_TABLE, $tableId, $userId);
}

/**
* @psalm-param list<array{id: int, type: int, permissions?: int, order?: int}> $nodes
* @throws Exception|PermissionError|InvalidArgumentException
Expand Down
12 changes: 12 additions & 0 deletions lib/Service/TableService.php
Original file line number Diff line number Diff line change
Expand Up @@ -562,6 +562,18 @@ public function getScheme(int $id): TableScheme {
return new TableScheme($table->getTitle(), $table->getEmoji(), $columns, $table->getViews(), $table->getDescription(), $this->appManager->getAppVersion("tables"));
}


/**
* @throws PermissionError
* @throws NotFoundError
* @throws InternalError
*/
public function listContextsByTable(int $id, ?string $userId = null): array {
$contexts = $this->contextService->findByTableId($id, $userId);
return $contexts;
}


// PRIVATE FUNCTIONS ---------------------------------------------------------------

/**
Expand Down
10 changes: 9 additions & 1 deletion src/modules/sidebar/partials/ShareList.vue
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,8 @@ import Crown from 'vue-material-design-icons/Crown.vue'
import Information from 'vue-material-design-icons/Information.vue'
import Account from 'vue-material-design-icons/Account.vue'
import moment from '@nextcloud/moment'
import { showWarning } from '@nextcloud/dialogs'
import '@nextcloud/dialogs/style.css'

export default {
components: {
Expand Down Expand Up @@ -208,7 +210,13 @@ export default {
promoteToManager(share) {
this.$emit('update', { id: share.id, permission: 'manage', value: true })
},
demoteManager(share) {
async demoteManager(share) {
// TODO: might need to pass in the share receiver when fetching the contexts
// it seems like we only get the contexts for the currently logged in user
const contexts = await this.$store.dispatch('loadContextsForTable', { tableId: this.activeElement.id })
if (Array.isArray(contexts.contexts) && contexts.contexts.length && contexts.contexts.find(context => context.owner === share.receiver)) {
showWarning(t('tables', 'The account has created an application based on this table which will continue to consume its data'))
}
this.$emit('update', { id: share.id, permission: 'manage', value: false })
},
personHasTableManagePermission(userId) {
Expand Down
5 changes: 5 additions & 0 deletions src/store/store.js
Original file line number Diff line number Diff line change
Expand Up @@ -508,6 +508,11 @@ export default new Vuex.Store({
return res?.data
},

async loadContextsForTable({ commit, state, getters }, { tableId }) {
const res = await axios.get(generateOcsUrl('/apps/tables/api/2/tables/' + tableId + '/index-context'))
return res?.data.ocs.data
},

async transferContext({ state, commit, dispatch }, { id, data }) {
try {
await axios.put(generateOcsUrl('/apps/tables/api/2/contexts/' + id + '/transfer'), data)
Expand Down

0 comments on commit 8cf9e5c

Please sign in to comment.