• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

teableio / teable / 20325548907

18 Dec 2025 03:58AM UTC coverage: 71.443% (-0.3%) from 71.775%
20325548907

Pull #2293

github

web-flow
Merge 64bff337d into 61c0e3184
Pull Request #2293: feat: template with app

23595 of 26444 branches covered (89.23%)

360 of 811 new or added lines in 10 files covered. (44.39%)

47 existing lines in 5 files now uncovered.

58822 of 82334 relevant lines covered (71.44%)

4169.63 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

84.52
/apps/nestjs-backend/src/features/base/base.controller.ts
1
/* eslint-disable sonarjs/no-duplicate-string */
8✔
2
import { Body, Controller, Delete, Get, Param, Patch, Post, Put, Query } from '@nestjs/common';
3
import type { IBaseRole } from '@teable/core';
4
import {
5
  createBaseRoSchema,
6
  duplicateBaseRoSchema,
7
  ICreateBaseRo,
8
  IUpdateBaseRo,
9
  updateBaseRoSchema,
10
  IDuplicateBaseRo,
11
  createBaseFromTemplateRoSchema,
12
  ICreateBaseFromTemplateRo,
13
  updateOrderRoSchema,
14
  IUpdateOrderRo,
15
  createBaseInvitationLinkRoSchema,
16
  CreateBaseInvitationLinkRo,
17
  updateBaseInvitationLinkRoSchema,
18
  emailBaseInvitationRoSchema,
19
  updateBaseCollaborateRoSchema,
20
  EmailBaseInvitationRo,
21
  UpdateBaseCollaborateRo,
22
  UpdateBaseInvitationLinkRo,
23
  CollaboratorType,
24
  listBaseCollaboratorRoSchema,
25
  ListBaseCollaboratorRo,
26
  deleteBaseCollaboratorRoSchema,
27
  DeleteBaseCollaboratorRo,
28
  addBaseCollaboratorRoSchema,
29
  AddBaseCollaboratorRo,
30
  listBaseCollaboratorUserRoSchema,
31
  IListBaseCollaboratorUserRo,
32
  ImportBaseRo,
33
  importBaseRoSchema,
34
  moveBaseRoSchema,
35
  IMoveBaseRo,
36
  publishBaseRoSchema,
37
  IPublishBaseRo,
38
} from '@teable/openapi';
39
import type {
40
  CreateBaseInvitationLinkVo,
41
  EmailInvitationVo,
42
  IBaseErdVo,
43
  ICreateBaseVo,
44
  IDbConnectionVo,
45
  IGetBaseAllVo,
46
  IGetBasePermissionVo,
47
  IGetBaseVo,
48
  IGetSharedBaseVo,
49
  IImportBaseVo,
50
  IListBaseCollaboratorUserVo,
51
  IUpdateBaseVo,
52
  ListBaseCollaboratorVo,
53
  ListBaseInvitationLinkVo,
54
  UpdateBaseInvitationLinkVo,
55
  ICreateBaseFromTemplateVo,
56
} from '@teable/openapi';
57
import { EmitControllerEvent } from '../../event-emitter/decorators/emit-controller-event.decorator';
58
import { Events } from '../../event-emitter/events';
59
import { ZodValidationPipe } from '../../zod.validation.pipe';
60
import { Permissions } from '../auth/decorators/permissions.decorator';
61
import { ResourceMeta } from '../auth/decorators/resource_meta.decorator';
62
import { CollaboratorService } from '../collaborator/collaborator.service';
63
import { InvitationService } from '../invitation/invitation.service';
64
import { BaseExportService } from './base-export.service';
65
import { BaseImportService } from './base-import.service';
66
import { BaseQueryService } from './base-query/base-query.service';
67
import { BaseService } from './base.service';
68
import { DbConnectionService } from './db-connection.service';
69

70
@Controller('api/base/')
71
export class BaseController {
8✔
72
  constructor(
138✔
73
    private readonly baseService: BaseService,
138✔
74
    private readonly baseExportService: BaseExportService,
138✔
75
    private readonly baseImportService: BaseImportService,
138✔
76
    private readonly dbConnectionService: DbConnectionService,
138✔
77
    private readonly collaboratorService: CollaboratorService,
138✔
78
    private readonly baseQueryService: BaseQueryService,
138✔
79
    private readonly invitationService: InvitationService
138✔
80
  ) {}
138✔
81

82
  @Post()
138✔
83
  @Permissions('base|create')
84
  @ResourceMeta('spaceId', 'body')
85
  @EmitControllerEvent(Events.BASE_CREATE)
184✔
86
  async createBase(
184✔
87
    @Body(new ZodValidationPipe(createBaseRoSchema))
184✔
88
    createBaseRo: ICreateBaseRo
184✔
89
  ) {
184✔
90
    return await this.baseService.createBase(createBaseRo);
184✔
91
  }
184✔
92

93
  @Post('import')
138✔
94
  @Permissions('base|create')
95
  @ResourceMeta('spaceId', 'body')
96
  @EmitControllerEvent(Events.BASE_CREATE)
5✔
97
  async importBase(
5✔
98
    @Body(new ZodValidationPipe(importBaseRoSchema))
5✔
99
    importBaseRo: ImportBaseRo
5✔
100
  ): Promise<IImportBaseVo> {
5✔
101
    return await this.baseImportService.importBase(importBaseRo);
5✔
102
  }
5✔
103

104
  @Post('duplicate')
138✔
105
  @Permissions('base|create')
106
  @ResourceMeta('spaceId', 'body')
107
  @EmitControllerEvent(Events.BASE_CREATE)
12✔
108
  async duplicateBase(
12✔
109
    @Body(new ZodValidationPipe(duplicateBaseRoSchema))
12✔
110
    duplicateBaseRo: IDuplicateBaseRo
12✔
111
  ): Promise<ICreateBaseVo> {
12✔
112
    return await this.baseService.duplicateBase(duplicateBaseRo);
12✔
113
  }
12✔
114

115
  @Post('create-from-template')
138✔
116
  @Permissions('base|create')
117
  @ResourceMeta('spaceId', 'body')
118
  @EmitControllerEvent(Events.BASE_CREATE)
2✔
119
  async createBaseFromTemplate(
2✔
120
    @Body(new ZodValidationPipe(createBaseFromTemplateRoSchema))
2✔
121
    createBaseFromTemplateRo: ICreateBaseFromTemplateRo
2✔
122
  ): Promise<ICreateBaseFromTemplateVo> {
2✔
123
    return await this.baseService.createBaseFromTemplate(createBaseFromTemplateRo);
2✔
124
  }
2✔
125

126
  @Patch(':baseId')
138✔
127
  @Permissions('base|update')
128
  @EmitControllerEvent(Events.BASE_UPDATE)
×
129
  async updateBase(
×
130
    @Param('baseId') baseId: string,
×
131
    @Body(new ZodValidationPipe(updateBaseRoSchema))
×
132
    updateBaseRo: IUpdateBaseRo
×
133
  ): Promise<IUpdateBaseVo> {
×
134
    return await this.baseService.updateBase(baseId, updateBaseRo);
×
135
  }
×
136

137
  @Put(':baseId/order')
138✔
138
  @Permissions('base|update')
139
  async updateOrder(
4✔
140
    @Param('baseId') baseId: string,
4✔
141
    @Body(new ZodValidationPipe(updateOrderRoSchema)) updateOrderRo: IUpdateOrderRo
4✔
142
  ) {
4✔
143
    return await this.baseService.updateOrder(baseId, updateOrderRo);
4✔
144
  }
4✔
145

146
  @Get('shared-base')
138✔
147
  async getSharedBase(): Promise<IGetSharedBaseVo> {
×
148
    return this.collaboratorService.getSharedBase();
×
149
  }
×
150

151
  @Permissions('base|read')
138✔
152
  @Get(':baseId')
153
  async getBaseById(@Param('baseId') baseId: string): Promise<IGetBaseVo> {
1✔
154
    return await this.baseService.getBaseById(baseId);
1✔
155
  }
1✔
156

157
  @Permissions('base|read_all')
138✔
158
  @Get('access/all')
159
  async getAllBase(): Promise<IGetBaseAllVo> {
2✔
160
    return this.baseService.getAllBaseList();
2✔
161
  }
2✔
162

163
  @Delete(':baseId')
138✔
164
  @Permissions('base|delete')
165
  @EmitControllerEvent(Events.BASE_DELETE)
88✔
166
  async deleteBase(@Param('baseId') baseId: string) {
88✔
167
    return await this.baseService.deleteBase(baseId);
88✔
168
  }
88✔
169

170
  @Permissions('base|db_connection')
138✔
171
  @Post(':baseId/connection')
172
  async createDbConnection(@Param('baseId') baseId: string): Promise<IDbConnectionVo | null> {
×
173
    return await this.dbConnectionService.create(baseId);
×
174
  }
×
175

176
  @Permissions('base|db_connection')
138✔
177
  @Get(':baseId/connection')
178
  async getDBConnection(@Param('baseId') baseId: string): Promise<IDbConnectionVo | null> {
×
179
    return await this.dbConnectionService.retrieve(baseId);
×
180
  }
×
181

182
  @Permissions('base|db_connection')
138✔
183
  @Delete(':baseId/connection')
184
  async deleteDbConnection(@Param('baseId') baseId: string) {
×
185
    await this.dbConnectionService.remove(baseId);
×
186
    return null;
×
187
  }
×
188

189
  @Permissions('base|read')
138✔
190
  @Get(':baseId/collaborators')
191
  async listCollaborator(
9✔
192
    @Param('baseId') baseId: string,
9✔
193
    @Query(new ZodValidationPipe(listBaseCollaboratorRoSchema)) options: ListBaseCollaboratorRo
9✔
194
  ): Promise<ListBaseCollaboratorVo> {
9✔
195
    return {
9✔
196
      collaborators: await this.collaboratorService.getListByBase(baseId, options),
9✔
197
      total: await this.collaboratorService.getTotalBase(baseId, options),
9✔
198
    };
9✔
199
  }
9✔
200

201
  @Permissions('base|read')
138✔
202
  @Get(':baseId/permission')
203
  async getPermission(): Promise<IGetBasePermissionVo> {
×
204
    return await this.baseService.getPermission();
×
205
  }
×
206

207
  @Permissions('base|invite_link')
138✔
208
  @Post(':baseId/invitation/link')
209
  async createInvitationLink(
4✔
210
    @Param('baseId') baseId: string,
4✔
211
    @Body(new ZodValidationPipe(createBaseInvitationLinkRoSchema))
4✔
212
    baseInvitationLinkRo: CreateBaseInvitationLinkRo
4✔
213
  ): Promise<CreateBaseInvitationLinkVo> {
4✔
214
    const res = await this.invitationService.generateInvitationLink({
4✔
215
      resourceId: baseId,
4✔
216
      resourceType: CollaboratorType.Base,
4✔
217
      role: baseInvitationLinkRo.role,
4✔
218
    });
4✔
219
    return {
4✔
220
      ...res,
4✔
221
      role: res.role as IBaseRole,
4✔
222
    };
4✔
223
  }
4✔
224

225
  @Permissions('base|invite_link')
138✔
226
  @Delete(':baseId/invitation/link/:invitationId')
227
  async deleteInvitationLink(
1✔
228
    @Param('baseId') baseId: string,
1✔
229
    @Param('invitationId') invitationId: string
1✔
230
  ): Promise<void> {
1✔
231
    return this.invitationService.deleteInvitationLink({
1✔
232
      resourceId: baseId,
1✔
233
      resourceType: CollaboratorType.Base,
1✔
234
      invitationId,
1✔
235
    });
1✔
236
  }
1✔
237

238
  @Permissions('base|invite_link')
138✔
239
  @Patch(':baseId/invitation/link/:invitationId')
240
  async updateInvitationLink(
1✔
241
    @Param('baseId') baseId: string,
1✔
242
    @Param('invitationId') invitationId: string,
1✔
243
    @Body(new ZodValidationPipe(updateBaseInvitationLinkRoSchema))
1✔
244
    updateSpaceInvitationLinkRo: UpdateBaseInvitationLinkRo
1✔
245
  ): Promise<UpdateBaseInvitationLinkVo> {
1✔
246
    const res = await this.invitationService.updateInvitationLink({
1✔
247
      resourceId: baseId,
1✔
248
      resourceType: CollaboratorType.Base,
1✔
249
      invitationId,
1✔
250
      role: updateSpaceInvitationLinkRo.role,
1✔
251
    });
1✔
252

253
    return {
1✔
254
      ...res,
1✔
255
      role: res.role as IBaseRole,
1✔
256
    };
1✔
257
  }
1✔
258

259
  @Permissions('base|invite_link')
138✔
260
  @Get(':baseId/invitation/link')
261
  async listInvitationLink(@Param('baseId') baseId: string): Promise<ListBaseInvitationLinkVo> {
2✔
262
    const res = this.invitationService.getInvitationLink(baseId, CollaboratorType.Base);
2✔
263
    return res as unknown as ListBaseInvitationLinkVo;
2✔
264
  }
2✔
265

266
  @Permissions('base|invite_email')
138✔
267
  @Post(':baseId/invitation/email')
268
  async emailInvitation(
57✔
269
    @Param('baseId') baseId: string,
57✔
270
    @Body(new ZodValidationPipe(emailBaseInvitationRoSchema))
57✔
271
    emailBaseInvitationRo: EmailBaseInvitationRo
57✔
272
  ): Promise<EmailInvitationVo> {
57✔
273
    return this.invitationService.emailInvitationByBase(baseId, emailBaseInvitationRo);
57✔
274
  }
57✔
275

276
  @Patch(':baseId/collaborators')
138✔
277
  async updateCollaborator(
8✔
278
    @Param('baseId') baseId: string,
8✔
279
    @Body(new ZodValidationPipe(updateBaseCollaborateRoSchema))
8✔
280
    updateBaseCollaborateRo: UpdateBaseCollaborateRo
8✔
281
  ): Promise<void> {
8✔
282
    await this.collaboratorService.updateCollaborator({
8✔
283
      resourceId: baseId,
8✔
284
      resourceType: CollaboratorType.Base,
8✔
285
      ...updateBaseCollaborateRo,
8✔
286
    });
8✔
287
  }
6✔
288

289
  @Delete(':baseId/collaborators')
138✔
290
  async deleteCollaborator(
8✔
291
    @Param('baseId') baseId: string,
8✔
292
    @Query(new ZodValidationPipe(deleteBaseCollaboratorRoSchema))
8✔
293
    deleteBaseCollaboratorRo: DeleteBaseCollaboratorRo
8✔
294
  ): Promise<void> {
8✔
295
    await this.collaboratorService.deleteCollaborator({
8✔
296
      resourceId: baseId,
8✔
297
      resourceType: CollaboratorType.Base,
8✔
298
      ...deleteBaseCollaboratorRo,
8✔
299
    });
8✔
300
  }
7✔
301

302
  @Delete(':baseId/permanent')
138✔
303
  @EmitControllerEvent(Events.BASE_DELETE)
81✔
304
  async permanentDeleteBase(@Param('baseId') baseId: string) {
81✔
305
    await this.baseService.permanentDeleteBase(baseId);
81✔
306
    return { baseId, permanent: true };
81✔
307
  }
81✔
308

309
  @Post(':baseId/collaborator')
138✔
310
  async addCollaborators(
×
311
    @Param('baseId') baseId: string,
×
312
    @Body(new ZodValidationPipe(addBaseCollaboratorRoSchema))
×
313
    addBaseCollaboratorRo: AddBaseCollaboratorRo
×
314
  ) {
×
315
    return await this.collaboratorService.addBaseCollaborators(baseId, addBaseCollaboratorRo);
×
316
  }
×
317

318
  @Permissions('base|read')
138✔
319
  @Get(':baseId/collaborators/users')
320
  async getUserCollaborators(
3✔
321
    @Param('baseId') baseId: string,
3✔
322
    @Query(new ZodValidationPipe(listBaseCollaboratorUserRoSchema))
3✔
323
    listBaseCollaboratorUserRo: IListBaseCollaboratorUserRo
3✔
324
  ): Promise<IListBaseCollaboratorUserVo> {
3✔
325
    return {
3✔
326
      users: await this.collaboratorService.getUserCollaborators(
3✔
327
        baseId,
3✔
328
        listBaseCollaboratorUserRo
3✔
329
      ),
330
      total: await this.collaboratorService.getUserCollaboratorsTotal(
3✔
331
        baseId,
3✔
332
        listBaseCollaboratorUserRo
3✔
333
      ),
334
    };
3✔
335
  }
3✔
336

337
  @Permissions('base|read')
138✔
338
  @Get(':baseId/export')
339
  async exportBase(@Param('baseId') baseId: string, @Query('includeData') includeData?: string) {
5✔
340
    const includeDataValue =
5✔
341
      includeData === undefined ? true : !['false', '0'].includes(includeData.toLowerCase());
5✔
342
    return await this.baseExportService.exportBaseZip(baseId, includeDataValue);
5✔
343
  }
5✔
344

345
  @Put(':baseId/move')
138✔
346
  @Permissions('space|update')
347
  async moveBase(
1✔
348
    @Param('baseId') baseId: string,
1✔
349
    @Body(new ZodValidationPipe(moveBaseRoSchema)) moveBaseRo: IMoveBaseRo
1✔
350
  ) {
1✔
351
    await this.baseService.moveBase(baseId, moveBaseRo);
1✔
352
  }
1✔
353

354
  @Permissions('base|update')
138✔
355
  @Get(':baseId/erd')
356
  async generateBaseErd(@Param('baseId') baseId: string): Promise<IBaseErdVo> {
4✔
357
    return await this.baseService.generateBaseErd(baseId);
4✔
358
  }
4✔
359

360
  @Permissions('base|update')
138✔
361
  @Post(':baseId/publish')
NEW
362
  async publishBase(
×
NEW
363
    @Param('baseId') baseId: string,
×
NEW
364
    @Body(new ZodValidationPipe(publishBaseRoSchema)) publishBaseRo: IPublishBaseRo
×
NEW
365
  ) {
×
NEW
366
    return await this.baseService.publishBase(baseId, publishBaseRo);
×
NEW
367
  }
×
368
}
138✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc