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

teableio / teable / 21057835990

16 Jan 2026 06:28AM UTC coverage: 64.512% (-0.5%) from 64.969%
21057835990

Pull #2441

github

web-flow
Merge 0cef47938 into eb157a355
Pull Request #2441: [sync] feat: Make the SVG in the table clearer T1686 (#1044)

4731 of 6116 branches covered (77.35%)

22 of 304 new or added lines in 9 files covered. (7.24%)

3 existing lines in 2 files now uncovered.

21829 of 33837 relevant lines covered (64.51%)

5429.35 hits per line

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

31.25
/apps/nestjs-backend/src/features/setting/open-api/setting-open-api.controller.ts
1
/* eslint-disable sonarjs/no-duplicate-string */
2
import {
3
  BadRequestException,
4
  Body,
5
  Controller,
6
  Get,
7
  Patch,
8
  Post,
9
  Put,
10
  UploadedFile,
11
  UseInterceptors,
12
} from '@nestjs/common';
13
import { FileInterceptor } from '@nestjs/platform-express';
14
import type {
15
  IPublicSettingVo,
16
  ISetSettingMailTransportConfigVo,
17
  ISettingVo,
18
  ITestLLMVo,
19
  IUploadLogoVo,
20
  IBatchTestLLMVo,
21
  ITestApiKeyVo,
22
} from '@teable/openapi';
23
import {
24
  IUpdateSettingRo,
25
  testLLMRoSchema,
26
  updateSettingRoSchema,
27
  ITestLLMRo,
28
  setSettingMailTransportConfigRoSchema,
29
  ISetSettingMailTransportConfigRo,
30
  SettingKey,
31
  batchTestLLMRoSchema,
32
  IBatchTestLLMRo,
33
  testApiKeyRoSchema,
34
  ITestApiKeyRo,
35
} from '@teable/openapi';
36
import { IThresholdConfig, ThresholdConfig } from '../../../configs/threshold.config';
37
import { ZodValidationPipe } from '../../../zod.validation.pipe';
38
import { Permissions } from '../../auth/decorators/permissions.decorator';
39
import { Public } from '../../auth/decorators/public.decorator';
40
import { TurnstileService } from '../../auth/turnstile/turnstile.service';
41
import { SettingOpenApiService } from './setting-open-api.service';
42

43
@Controller('api/admin/setting')
44
export class SettingOpenApiController {
45
  constructor(
46
    private readonly settingOpenApiService: SettingOpenApiService,
318✔
47
    private readonly turnstileService: TurnstileService,
318✔
48
    @ThresholdConfig() private readonly thresholdConfig: IThresholdConfig
318✔
49
  ) {}
50

51
  /**
52
   * Get the instance settings, now we have config for AI, there are some sensitive fields, we need check the permission before return.
53
   */
54
  @Permissions('instance|read')
55
  @Get()
56
  async getSetting(): Promise<ISettingVo> {
57
    return await this.settingOpenApiService.getSetting();
3✔
58
  }
59

60
  /**
61
   * Public endpoint for getting public settings without authentication
62
   */
63
  @Public()
64
  @Get('public')
65
  async getPublicSetting(): Promise<IPublicSettingVo> {
66
    const setting = await this.settingOpenApiService.getSetting([
×
67
      SettingKey.INSTANCE_ID,
68
      SettingKey.BRAND_NAME,
69
      SettingKey.BRAND_LOGO,
70
      SettingKey.DISALLOW_SIGN_UP,
71
      SettingKey.DISALLOW_SPACE_CREATION,
72
      SettingKey.DISALLOW_SPACE_INVITATION,
73
      SettingKey.DISALLOW_DASHBOARD,
74
      SettingKey.ENABLE_EMAIL_VERIFICATION,
75
      SettingKey.ENABLE_WAITLIST,
76
      SettingKey.ENABLE_CREDIT_REWARD,
77
      SettingKey.AI_CONFIG,
78
      SettingKey.APP_CONFIG,
79
    ]);
NEW
80
    const { aiConfig, appConfig, enableCreditReward, ...rest } = setting;
×
81
    return {
×
82
      ...rest,
83
      enableCreditReward: enableCreditReward ?? undefined,
84
      aiConfig: {
85
        enable: aiConfig?.enable ?? false,
86
        llmProviders:
87
          aiConfig?.llmProviders?.map((provider) => ({
×
88
            type: provider.type,
89
            name: provider.name,
90
            models: provider.models,
91
          })) ?? [],
92
        chatModel: aiConfig?.chatModel,
93
        capabilities: aiConfig?.capabilities,
94
      },
95
      appGenerationEnabled: Boolean(appConfig?.apiKey),
96
      turnstileSiteKey: this.turnstileService.getTurnstileSiteKey(),
97
      changeEmailSendCodeMailRate: this.thresholdConfig.changeEmailSendCodeMailRate,
98
      resetPasswordSendMailRate: this.thresholdConfig.resetPasswordSendMailRate,
99
      signupVerificationSendCodeMailRate: this.thresholdConfig.signupVerificationSendCodeMailRate,
100
    };
101
  }
102

103
  @Patch()
104
  @Permissions('instance|update')
105
  async updateSetting(
106
    @Body(new ZodValidationPipe(updateSettingRoSchema))
107
    updateSettingRo: IUpdateSettingRo
108
  ): Promise<ISettingVo> {
109
    return await this.settingOpenApiService.updateSetting(updateSettingRo);
19✔
110
  }
111

112
  @UseInterceptors(
113
    FileInterceptor('file', {
114
      fileFilter: (_req, file, callback) => {
115
        if (file.mimetype.startsWith('image/')) {
116
          callback(null, true);
117
        } else {
118
          callback(new BadRequestException('Invalid file type'), false);
119
        }
120
      },
121
      limits: {
122
        fileSize: 500 * 1024, // limit file size is 500KB
123
      },
124
    })
125
  )
126
  @Patch('logo')
127
  @Permissions('instance|update')
128
  async uploadLogo(@UploadedFile() file: Express.Multer.File): Promise<IUploadLogoVo> {
129
    return this.settingOpenApiService.uploadLogo(file);
×
130
  }
131

132
  @Permissions('instance|update')
133
  @Post('test-llm')
134
  async testLLM(
135
    @Body(new ZodValidationPipe(testLLMRoSchema)) testLLMRo: ITestLLMRo
136
  ): Promise<ITestLLMVo> {
137
    return await this.settingOpenApiService.testLLM(testLLMRo);
×
138
  }
139

140
  @Permissions('instance|update')
141
  @Post('batch-test-llm')
142
  async batchTestLLM(
143
    @Body(new ZodValidationPipe(batchTestLLMRoSchema.optional())) batchTestLLMRo?: IBatchTestLLMRo
144
  ): Promise<IBatchTestLLMVo> {
145
    return await this.settingOpenApiService.batchTestLLM(batchTestLLMRo);
×
146
  }
147

148
  @Permissions('instance|update')
149
  @Post('test-api-key')
150
  async testApiKey(
151
    @Body(new ZodValidationPipe(testApiKeyRoSchema)) testApiKeyRo: ITestApiKeyRo
152
  ): Promise<ITestApiKeyVo> {
NEW
153
    return await this.settingOpenApiService.testApiKey(testApiKeyRo);
×
154
  }
155

156
  @Permissions('instance|update')
157
  @Put('set-mail-transport-config')
158
  async setMailTransportConfig(
159
    @Body(new ZodValidationPipe(setSettingMailTransportConfigRoSchema))
160
    setMailTransportConfigRo: ISetSettingMailTransportConfigRo
161
  ): Promise<ISetSettingMailTransportConfigVo> {
162
    await this.settingOpenApiService.setMailTransportConfig(setMailTransportConfigRo);
×
163

164
    return {
×
165
      ...setMailTransportConfigRo,
166
      transportConfig: {
167
        ...setMailTransportConfigRo.transportConfig,
168
        auth: {
169
          user: setMailTransportConfigRo.transportConfig.auth.user,
170
          pass: '',
171
        },
172
      },
173
    };
174
  }
175

176
  /**
177
   * Get available models from AI Gateway
178
   * Returns configured=false if gateway is not set up
179
   */
180
  @Public()
181
  @Get('gateway-models')
182
  async getGatewayModels() {
NEW
183
    return await this.settingOpenApiService.getGatewayModels();
×
184
  }
185
}
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