Skip to content

Commit 1c2d59a

Browse files
authored
feat: detailed token permission (#1116)
* feat: detailed token permission * feat: add select all
1 parent ded96c4 commit 1c2d59a

File tree

19 files changed

+70
-27
lines changed

19 files changed

+70
-27
lines changed

apps/nestjs-backend/src/features/attachments/attachments.controller.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,12 @@ import type { INotifyVo, SignatureVo } from '@teable/openapi';
1717
import { Response, Request } from 'express';
1818
import { ZodValidationPipe } from '../../zod.validation.pipe';
1919
import { Public } from '../auth/decorators/public.decorator';
20-
import { TokenAccess } from '../auth/decorators/token.decorator';
2120
import { AuthGuard } from '../auth/guard/auth.guard';
2221
import { AttachmentsService } from './attachments.service';
2322
import { DynamicAuthGuardFactory } from './guard/auth.guard';
2423

2524
@Controller('api/attachments')
2625
@Public()
27-
@TokenAccess()
2826
export class AttachmentsController {
2927
constructor(private readonly attachmentsService: AttachmentsService) {}
3028

apps/nestjs-backend/src/features/base/base.controller.ts

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@ import { Events } from '../../event-emitter/events';
4545
import { ZodValidationPipe } from '../../zod.validation.pipe';
4646
import { Permissions } from '../auth/decorators/permissions.decorator';
4747
import { ResourceMeta } from '../auth/decorators/resource_meta.decorator';
48-
import { TokenAccess } from '../auth/decorators/token.decorator';
4948
import { CollaboratorService } from '../collaborator/collaborator.service';
5049
import { InvitationService } from '../invitation/invitation.service';
5150
import { BaseQueryService } from './base-query/base-query.service';
@@ -126,17 +125,12 @@ export class BaseController {
126125
return await this.baseService.getBaseById(baseId);
127126
}
128127

128+
@Permissions('base|read_all')
129129
@Get('access/all')
130130
async getAllBase(): Promise<IGetBaseAllVo> {
131131
return this.baseService.getAllBaseList();
132132
}
133133

134-
@Get('access/list')
135-
@TokenAccess()
136-
async getAccessBase(): Promise<{ id: string; name: string }[]> {
137-
return this.baseService.getAccessBaseList();
138-
}
139-
140134
@Delete(':baseId')
141135
@Permissions('base|delete')
142136
@EmitControllerEvent(Events.BASE_DELETE)

apps/nestjs-backend/src/features/comment/comment-open-api.controller.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,10 @@ import { ZodValidationPipe } from '../../zod.validation.pipe';
1717
import { AttachmentsStorageService } from '../attachments/attachments-storage.service';
1818
import StorageAdapter from '../attachments/plugins/adapter';
1919
import { Permissions } from '../auth/decorators/permissions.decorator';
20-
import { TokenAccess } from '../auth/decorators/token.decorator';
2120
import { TqlPipe } from '../record/open-api/tql.pipe';
2221
import { CommentOpenApiService } from './comment-open-api.service';
2322

2423
@Controller('api/comment/:tableId')
25-
@TokenAccess()
2624
export class CommentOpenApiController {
2725
constructor(
2826
private readonly commentOpenApiService: CommentOpenApiService,

apps/nextjs-app/src/features/app/blocks/setting/access-token/form/AccessSelect.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ export const AccessSelect = (props: IFormAccess) => {
115115
?.map(({ id, name }) => (
116116
<CommandGroup
117117
key={id}
118-
heading={<div className="truncate text-sm">{name}</div>}
118+
heading={<div className="truncate text-sm font-bold">{name}</div>}
119119
title={name}
120120
>
121121
<CommandItem

apps/nextjs-app/src/features/app/blocks/setting/access-token/form/AccessTokenForm.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@ export const AccessTokenForm = <T extends IFormType>(props: IAccessTokenForm<T>)
6666
ActionPrefix.View,
6767
ActionPrefix.Field,
6868
ActionPrefix.Record,
69+
ActionPrefix.TableRecordHistory,
70+
ActionPrefix.User,
6971
ActionPrefix.Automation,
7072
];
7173

apps/nextjs-app/src/features/app/blocks/setting/components/ScopesSelect.tsx

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import { actionPrefixMap } from '@teable/core';
22
import type { ActionPrefix, Action } from '@teable/core';
33
import { usePermissionActionsStatic } from '@teable/sdk/hooks';
4-
import { Checkbox, Label } from '@teable/ui-lib/shadcn';
4+
import { Checkbox, Label, Button } from '@teable/ui-lib/shadcn';
5+
import { useTranslation } from 'next-i18next';
56
import { useMemo, useState } from 'react';
67

78
interface IScopesSelectProps {
@@ -12,6 +13,7 @@ interface IScopesSelectProps {
1213

1314
export const ScopesSelect = (props: IScopesSelectProps) => {
1415
const { onChange, initValue, actionsPrefixes } = props;
16+
const { t } = useTranslation('token');
1517
const [value, setValue] = useState<Record<Action, boolean>>(() => {
1618
if (initValue) {
1719
return initValue.reduce(
@@ -34,6 +36,16 @@ export const ScopesSelect = (props: IScopesSelectProps) => {
3436
onChange?.(actions);
3537
};
3638

39+
const handleSelectAll = (prefix: ActionPrefix, shouldSelect: boolean) => {
40+
const actionMap = { ...value };
41+
actionPrefixMap[prefix].forEach((action) => {
42+
actionMap[action] = shouldSelect;
43+
});
44+
setValue(actionMap);
45+
const actions = Object.keys(actionMap).filter((key) => actionMap[key as Action]);
46+
onChange?.(actions);
47+
};
48+
3749
const actionsPrefix = useMemo(() => {
3850
if (actionsPrefixes) {
3951
return Object.keys(actionPrefixStaticMap).filter((key) =>
@@ -47,9 +59,19 @@ export const ScopesSelect = (props: IScopesSelectProps) => {
4759
<div className="space-y-3 pl-2">
4860
{actionsPrefix.map((actionPrefix) => {
4961
const actions = actionPrefixMap[actionPrefix];
62+
const isAllSelected = actions.every((action) => value[action]);
5063
return (
51-
<div key={actionPrefix} className="space-y-1">
52-
<Label>{actionPrefixStaticMap[actionPrefix].title}</Label>
64+
<div key={actionPrefix} className="group space-y-1">
65+
<div className="flex items-center">
66+
<Label>{actionPrefixStaticMap[actionPrefix].title}</Label>
67+
<Button
68+
variant="link"
69+
className="invisible h-6 px-2 text-xs text-muted-foreground group-hover:visible"
70+
onClick={() => handleSelectAll(actionPrefix, !isAllSelected)}
71+
>
72+
{isAllSelected ? t('edit.cancelSelectAll') : t('edit.selectAll')}
73+
</Button>
74+
</div>
5375
<div className="flex gap-3">
5476
{actions.map((action) => (
5577
<div className="flex items-center gap-1 text-sm" key={action}>

packages/common-i18n/src/locales/en/sdk.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,7 @@
256256
"baseCreate": "Create base",
257257
"baseDelete": "Delete base",
258258
"baseRead": "Read base",
259+
"baseReadAll": "Read all bases",
259260
"baseUpdate": "Update base",
260261
"baseInviteEmail": "Invite via email in base",
261262
"baseInviteLink": "Invite via link in base",
@@ -290,7 +291,8 @@
290291
"automationDelete": "Delete automation",
291292
"automationRead": "Read automation",
292293
"automationUpdate": "Update automation",
293-
"userEmailRead": "Read user email",
294+
"userProfileRead": "Read current user profile",
295+
"userEmailRead": "Read current user email",
294296
"recordHistoryRead": "Read record history",
295297
"baseQuery": "Query base",
296298
"instanceRead": "Read instance",

packages/common-i18n/src/locales/en/token.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
"new": {
1717
"headerTitle": "Create new token",
1818
"title": "Personal access tokens are required to use the Teable API.",
19-
"description": "This token will grant access to the data in the selected spaces and bases. This token will also allow usage of other, non-space/base API endpoints. Only use this token for your own development. Don’t share it with third-party services and applications.",
19+
"description": "This token will grant access to the data in the selected spaces and bases. And other, non-space/base API endpoints. Please only use this token for your own development. Please be cautious when sharing it with third-party services and applications.",
2020
"button": "Create new token",
2121
"success": {
2222
"title": "Token successfully generated",
@@ -31,7 +31,9 @@
3131
"edit": {
3232
"title": "Edit token",
3333
"name": "Name",
34-
"scopes": "Scopes"
34+
"scopes": "Scopes",
35+
"selectAll": "Select all",
36+
"cancelSelectAll": "Cancel select all"
3537
},
3638
"refresh": {
3739
"title": "Regenerate personal access token",

packages/common-i18n/src/locales/fr/sdk.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,7 @@
243243
"baseDelete": "Supprimer une base",
244244
"baseRead": "Lire une base",
245245
"baseUpdate": "Mettre à jour une base",
246+
"baseReadAll": "Lire toutes les bases",
246247
"baseInviteEmail": "Inviter par email dans la base",
247248
"baseInviteLink": "Inviter par lien dans la base",
248249
"baseTableImport": "Importer des données dans la base",
@@ -275,6 +276,7 @@
275276
"automationDelete": "Supprimer une automatisation",
276277
"automationRead": "Lire une automatisation",
277278
"automationUpdate": "Mettre à jour une automatisation",
279+
"userProfileRead": "Lire le profil de l'utilisateur",
278280
"userEmailRead": "Lire l'email de l'utilisateur",
279281
"recordHistoryRead": "Lire l'historique des enregistrements",
280282
"baseQuery": "Interroger la base",

packages/common-i18n/src/locales/fr/token.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
"new": {
1717
"headerTitle": "Créer un nouveau jeton",
1818
"title": "Les jetons d'accès personnel sont nécessaires pour utiliser l'API Teable.",
19-
"description": "Ce jeton permettra d'accéder aux données dans les espaces et bases sélectionnés. Ce jeton permettra également d'utiliser d'autres points de terminaison d'API non liés aux espaces/bases. Utilisez ce jeton uniquement pour votre propre développement. Ne le partagez pas avec des services et applications tiers.",
19+
"description": "Ce jeton permettra d'accéder aux données dans les espaces et bases sélectionnés. Et d'autres, non liés aux espaces/bases, points de terminaison d'API. Utilisez ce jeton uniquement pour votre propre développement. Soyez prudent lors de son partage avec des services et applications tiers.",
2020
"button": "Créer un nouveau jeton",
2121
"success": {
2222
"title": "Jeton généré avec succès",
@@ -31,7 +31,9 @@
3131
"edit": {
3232
"title": "Modifier le jeton",
3333
"name": "Nom",
34-
"scopes": "Périmètres"
34+
"scopes": "Périmètres",
35+
"selectAll": "Sélectionner tout",
36+
"cancelSelectAll": "Annuler la sélection de tout"
3537
},
3638
"refresh": {
3739
"title": "Régénérer le jeton d'accès personnel",

0 commit comments

Comments
 (0)