Skip to content

Commit 33ee115

Browse files
author
teable-bot
committed
[sync] feat: add node permissions T1149 (#937)
Synced from teableio/teable-ee@7bc149e
1 parent afb5f32 commit 33ee115

File tree

127 files changed

+4381
-1867
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

127 files changed

+4381
-1867
lines changed

.github/workflows/templates/preview-template.yaml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -179,8 +179,6 @@ spec:
179179
- name: BACKEND_CACHE_REDIS_URI
180180
value: >-
181181
redis://$(REDIS_USERNAME):$(REDIS_PASSWORD)@$(REDIS_HOST).ns-__NAMESPACE__.svc:$(REDIS_PORT)/1
182-
- name: NEXT_ENV_IMAGES_ALL_REMOTE
183-
value: 'true'
184182
resources:
185183
requests:
186184
cpu: 200m

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ node_modules
2929
/build
3030
/dist/
3131

32+
# Next.js auto-generated type definitions
33+
**/next-env.d.ts
34+
3235
# Cache
3336
*.tsbuildinfo
3437
**/.eslintcache

apps/nestjs-backend/package.json

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@
9898
"dotenv-flow-cli": "1.1.1",
9999
"es-check": "7.1.1",
100100
"eslint": "8.57.0",
101-
"eslint-config-next": "14.2.14",
101+
"eslint-config-next": "15.5.9",
102102
"get-tsconfig": "4.7.3",
103103
"istanbul-merge": "2.0.0",
104104
"npm-run-all2": "6.1.2",
@@ -138,7 +138,7 @@
138138
"@keyv/sqlite": "3.6.7",
139139
"@nestjs-modules/mailer": "1.11.2",
140140
"@nestjs/axios": "3.0.2",
141-
"@nestjs/bullmq": "10.2.1",
141+
"@nestjs/bullmq": "11.0.4",
142142
"@nestjs/common": "10.3.5",
143143
"@nestjs/config": "3.2.1",
144144
"@nestjs/core": "10.3.5",
@@ -179,7 +179,7 @@
179179
"archiver": "7.0.1",
180180
"axios": "1.7.7",
181181
"bcrypt": "5.1.1",
182-
"bullmq": "5.21.2",
182+
"bullmq": "5.66.5",
183183
"class-transformer": "0.5.1",
184184
"class-validator": "0.14.1",
185185
"cookie": "0.6.0",
@@ -197,7 +197,7 @@
197197
"handlebars": "4.7.8",
198198
"helmet": "7.1.0",
199199
"http-proxy-middleware": "3.0.3",
200-
"ioredis": "5.4.1",
200+
"ioredis": "5.9.1",
201201
"is-port-reachable": "3.1.0",
202202
"joi": "17.12.2",
203203
"keyv": "4.5.4",
@@ -213,7 +213,7 @@
213213
"nestjs-i18n": "10.5.1",
214214
"nestjs-pino": "4.4.1",
215215
"nestjs-redoc": "2.2.2",
216-
"next": "14.2.35",
216+
"next": "16.1.3",
217217
"node-fetch": "2.7.0",
218218
"node-sql-parser": "5.3.8",
219219
"nodemailer": "6.9.13",

apps/nestjs-backend/src/configs/threshold.config.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,11 @@ export const thresholdConfig = registerAs('threshold', () => ({
2525
maxOpenapiAttachmentUploadSize: Number(
2626
process.env.MAX_OPENAPI_ATTACHMENT_UPLOAD_SIZE ?? Infinity
2727
),
28+
webhook: {
29+
bodyLimitBytes: Number(process.env.WEBHOOK_BODY_LIMIT_BYTES ?? 4 * 1024 * 1024),
30+
baseRateLimit: Number(process.env.WEBHOOK_BASE_RATE_LIMIT ?? 50),
31+
workflowRateLimit: Number(process.env.WEBHOOK_WORKFLOW_RATE_LIMIT ?? 2),
32+
},
2833
dbDeadlock: {
2934
maxRetries: Number(process.env.BACKEND_DB_DEADLOCK_MAX_RETRIES ?? 3),
3035
initialBackoff: Number(process.env.BACKEND_DB_DEADLOCK_INITIAL_BACKOFF ?? 100),

apps/nestjs-backend/src/custom.exception.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ export const getDefaultCodeByStatus = (status: HttpStatus) => {
3939
return HttpErrorCode.DATABASE_CONNECTION_UNAVAILABLE;
4040
case HttpStatus.REQUEST_TIMEOUT:
4141
return HttpErrorCode.REQUEST_TIMEOUT;
42+
case HttpStatus.PAYLOAD_TOO_LARGE:
43+
return HttpErrorCode.PAYLOAD_TOO_LARGE;
4244
default:
4345
return HttpErrorCode.UNKNOWN_ERROR_CODE;
4446
}

apps/nestjs-backend/src/event-emitter/event-job/fallback/fallback-queue.service.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ export class FallbackQueueService implements OnModuleInit {
5252
});
5353
}
5454

55-
private handleListener(
55+
private async handleListener(
5656
// eslint-disable-next-line @typescript-eslint/no-explicit-any
5757
wrapper: InstanceWrapper,
5858
job: Job<unknown>
@@ -63,6 +63,10 @@ export class FallbackQueueService implements OnModuleInit {
6363
this.logger.warn(`${instance.constructor.name} has no method ${methodName}`);
6464
return;
6565
}
66-
instance[methodName].call(instance, job);
66+
try {
67+
await instance[methodName].call(instance, job);
68+
} catch (error) {
69+
this.logger.error(`Error processing job ${job.name}:`, error);
70+
}
6771
}
6872
}

apps/nestjs-backend/src/features/auth/guard/base-node-permission.guard.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
checkBaseNodePermission,
1212
checkBaseNodePermissionCreate,
1313
} from '../../base-node/base-node.permission.helper';
14+
import type { IBaseNodePermissionContext } from '../../base-node/types';
1415
import { BaseNodeAction } from '../../base-node/types';
1516
import { BASE_NODE_PERMISSIONS_KEY } from '../decorators/base-node-permissions.decorator';
1617
import { IS_DISABLED_PERMISSION } from '../decorators/disabled-permission.decorator';
@@ -59,10 +60,7 @@ export class BaseNodePermissionGuard extends PermissionGuard {
5960
async checkActivate(
6061
context: ExecutionContext,
6162
baseId: string,
62-
permissionContext: {
63-
permissionSet: Set<string>;
64-
tablePermissionMap?: Record<string, string[]>;
65-
}
63+
permissionContext: IBaseNodePermissionContext
6664
) {
6765
const baseNodePermissions = this.reflectorInner.getAllAndOverride<BaseNodeAction[] | undefined>(
6866
BASE_NODE_PERMISSIONS_KEY,

apps/nestjs-backend/src/features/base-node/base-node.permission.helper.ts

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
/* eslint-disable sonarjs/no-duplicate-string */
2+
import type { TableAction, AppAction, AutomationAction } from '@teable/core';
23
import { HttpErrorCode } from '@teable/core';
34
import { BaseNodeResourceType } from '@teable/openapi';
45
import { CustomHttpException } from '../../custom.exception';
6+
import type { IBaseNodePermissionContext } from './types';
57
import { BaseNodeAction } from './types';
68

79
const map: Record<BaseNodeResourceType, Record<BaseNodeAction, string>> = {
@@ -40,28 +42,29 @@ const map: Record<BaseNodeResourceType, Record<BaseNodeAction, string>> = {
4042
export const checkBaseNodePermission = (
4143
node: { resourceType: BaseNodeResourceType; resourceId: string },
4244
action: BaseNodeAction,
43-
permissionContext: {
44-
tablePermissionMap?: Record<string, string[]>;
45-
permissionSet: Set<string>;
46-
}
45+
permissionContext: IBaseNodePermissionContext
4746
): boolean => {
4847
const { resourceType } = node;
4948
const { resourceId } = node;
50-
const { tablePermissionMap, permissionSet } = permissionContext;
49+
const { tablePermissionMap, permissionSet, appPermissionMap, workflowPermissionMap } =
50+
permissionContext;
5151
const checkAction = map[resourceType][action];
5252
if (resourceType === BaseNodeResourceType.Table && tablePermissionMap) {
53-
return tablePermissionMap[resourceId]?.includes(checkAction) ?? false;
53+
return tablePermissionMap[resourceId]?.includes(checkAction as TableAction) ?? false;
54+
}
55+
if (resourceType === BaseNodeResourceType.App && appPermissionMap) {
56+
return appPermissionMap[resourceId]?.includes(checkAction as AppAction) ?? false;
57+
}
58+
if (resourceType === BaseNodeResourceType.Workflow && workflowPermissionMap) {
59+
return workflowPermissionMap[resourceId]?.includes(checkAction as AutomationAction) ?? false;
5460
}
5561
return permissionSet.has(checkAction);
5662
};
5763

5864
export const checkBaseNodePermissionCreate = (
5965
node: { resourceType: BaseNodeResourceType; resourceId: string },
6066
baseNodePermissions: BaseNodeAction[],
61-
permissionContext: {
62-
tablePermissionMap?: Record<string, string[]>;
63-
permissionSet: Set<string>;
64-
}
67+
permissionContext: IBaseNodePermissionContext
6568
): boolean => {
6669
const checkCreate = baseNodePermissions.includes(BaseNodeAction.Create);
6770
if (!checkCreate) {
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,15 @@
1+
import type { AppAction, AutomationAction, TableAction } from '@teable/core';
2+
13
export enum BaseNodeAction {
24
Read = 'base_node|read',
35
Create = 'base_node|create',
46
Update = 'base_node|update',
57
Delete = 'base_node|delete',
68
}
9+
10+
export type IBaseNodePermissionContext = {
11+
tablePermissionMap?: Record<string, TableAction[]>;
12+
permissionSet: Set<string>;
13+
appPermissionMap?: Record<string, AppAction[]>;
14+
workflowPermissionMap?: Record<string, AutomationAction[]>;
15+
};

apps/nestjs-backend/src/features/next/next.service.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,13 @@ import { ConfigService } from '@nestjs/config';
44
import { generateQueryId } from '@teable/core';
55
import type { IQueryParamsRo, IQueryParamsVo } from '@teable/openapi';
66
import createServer from 'next';
7-
import type { NextServer } from 'next/dist/server/next';
87
import { CacheService } from '../../cache/cache.service';
98
import type { ICacheStore } from '../../cache/types';
109

1110
@Injectable()
1211
export class NextService implements OnModuleInit, OnModuleDestroy {
1312
private logger = new Logger(NextService.name);
14-
public server!: NextServer;
13+
public server!: ReturnType<typeof createServer>;
1514
constructor(
1615
private configService: ConfigService,
1716
private readonly cacheService: CacheService<ICacheStore>

0 commit comments

Comments
 (0)