Skip to content

Commit b747e98

Browse files
committed
feat: system config logic integrate
1 parent e495272 commit b747e98

11 files changed

Lines changed: 59 additions & 22 deletions

File tree

apps/backend/src/auth/auth.module.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,18 @@ import { Module } from '@nestjs/common'
22
import { AuthGuard } from '@/common/guards/auth.guard'
33
import { CookieModule } from '@/cookie/cookie.module'
44
import { PrismaModule } from '@/infra/prisma/prisma.module'
5+
import { SystemConfigModule } from '@/infra/system-config/system-config.module'
56
import { SessionModule } from '@/session/session.module'
67
import { AuthController } from './auth.controller'
78
import { AuthService } from './auth.service'
89

910
@Module({
10-
imports: [SessionModule, PrismaModule, CookieModule],
11+
imports: [
12+
SessionModule,
13+
PrismaModule,
14+
CookieModule,
15+
SystemConfigModule,
16+
],
1117
controllers: [AuthController],
1218
providers: [AuthService, AuthGuard],
1319
exports: [AuthService, AuthGuard, CookieModule],

apps/backend/src/auth/auth.service.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1+
import { SystemConfigKey } from '@apiplayer/shared'
12
import { Injectable, Logger } from '@nestjs/common'
23
import { compare, hash } from 'bcrypt'
34
import { HanaException } from '@/common/exceptions/hana.exception'
45
import { DEFAULT_COOKIE_MAX_AGE, REMEMBER_ME_COOKIE_MAX_AGE } from '@/constants/cookie'
56
import { RoleName } from '@/constants/role'
67
import { PrismaService } from '@/infra/prisma/prisma.service'
8+
import { SystemConfigService } from '@/infra/system-config/system-config.service'
79
import { SessionService } from '@/session/session.service'
810
import { CheckAvailabilityReqDto, LoginReqDto, RegisterReqDto } from './dto'
911

@@ -15,6 +17,7 @@ export class AuthService {
1517
constructor(
1618
private readonly prisma: PrismaService,
1719
private readonly sessionService: SessionService,
20+
private readonly systemConfigService: SystemConfigService,
1821
) {}
1922

2023
/** 对密码进行哈希处理 */
@@ -206,6 +209,11 @@ export class AuthService {
206209

207210
/** 用户注册 */
208211
async register(dto: RegisterReqDto) {
212+
const registerEnabled = this.systemConfigService.get<boolean>(SystemConfigKey.REGISTER_ENABLED)
213+
if (!registerEnabled) {
214+
throw new HanaException('REGISTER_DISABLED')
215+
}
216+
209217
const { email, username, name, password, confirmPassword } = dto
210218

211219
try {

apps/backend/src/infra/system-config/system-config.controller.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ export class SystemConfigController {
5050

5151
/** 获取所有配置详细信息列表 */
5252
@Get('all-with-metadata')
53-
@RequireSystemAdmin()
53+
@Public()
5454
async getConfigsDetail(): Promise<SystemConfigItemDto[]> {
5555
const result = this.systemConfigService.getAllWithMetadata()
5656
return plainToInstance(SystemConfigItemDto, result)

apps/backend/src/infra/system-config/system-config.module.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
1-
import { Global, Module } from '@nestjs/common'
1+
import { forwardRef, Global, Module } from '@nestjs/common'
22
import { AuthModule } from '@/auth/auth.module'
33
import { PermissionModule } from '@/permission/permission.module'
44
import { SystemConfigController } from './system-config.controller'
55
import { SystemConfigService } from './system-config.service'
66

77
@Global()
88
@Module({
9-
imports: [AuthModule, PermissionModule],
9+
imports: [
10+
forwardRef(() => AuthModule),
11+
PermissionModule,
12+
],
1013
controllers: [SystemConfigController],
1114
providers: [SystemConfigService],
1215
exports: [SystemConfigService],

apps/backend/src/permission/permission.module.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Module } from '@nestjs/common'
1+
import { forwardRef, Module } from '@nestjs/common'
22
import { AuthModule } from '@/auth/auth.module'
33
import { PermissionsGuard } from '@/common/guards/permissions.guard'
44
import { PrismaModule } from '@/infra/prisma/prisma.module'
@@ -7,7 +7,10 @@ import { PermissionController } from './permission.controller'
77
import { PermissionService } from './permission.service'
88

99
@Module({
10-
imports: [PrismaModule, AuthModule],
10+
imports: [
11+
forwardRef(() => AuthModule),
12+
PrismaModule,
13+
],
1114
controllers: [PermissionController],
1215
providers: [PermissionService, PermissionCheckerService, PermissionsGuard],
1316
exports: [PermissionService, PermissionCheckerService, PermissionsGuard],

apps/frontend/src/components/settings/menu/System.vue

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,12 @@ const onSubmit = form.handleSubmit(async (values) => {
7272
<form id="system-config-form" class="space-y-6" @submit="onSubmit">
7373
<template v-for="(item, index) in systemConfigArr" :key="item.key">
7474
<Item :label="item.description">
75-
<FormField v-slot="{ componentField, value }" type="checkbox" :name="item.key">
75+
<FormField
76+
v-slot="{ componentField, value }"
77+
:name="item.key"
78+
:type="item.type === 'boolean' ? 'checkbox' : undefined"
79+
:unchecked-value="item.type === 'boolean' ? false : undefined"
80+
>
7681
<FormItem>
7782
<div class="flex items-center justify-between">
7883
<FormLabel class="text-xs text-muted-foreground font-mono">

apps/frontend/src/router/index.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import type { RouteRecordRaw } from 'vue-router'
22
import { createRouter, createWebHistory } from 'vue-router'
3+
import { toast } from 'vue-sonner'
34
import { AUTH_REDIRECT_ROUTES, PUBLIC_ROUTES } from '@/constants'
5+
import { useGlobalStore } from '@/stores/useGlobalStore'
46
import { useUserStore } from '@/stores/useUserStore'
57

68
const routes: RouteRecordRaw[] = [
@@ -75,6 +77,8 @@ const router = createRouter({
7577

7678
router.beforeEach((to, _, next) => {
7779
const userStore = useUserStore()
80+
const globalStore = useGlobalStore()
81+
7882
const isPublicRoute = PUBLIC_ROUTES.includes(to.name as string)
7983
const goToDashboard = AUTH_REDIRECT_ROUTES.includes(to.name as string)
8084

@@ -90,6 +94,14 @@ router.beforeEach((to, _, next) => {
9094
else {
9195
next({ name: 'Login' })
9296
}
97+
98+
if (to.name === 'Register' && !globalStore.systemConfig.register_enabled) {
99+
next({ name: 'Login' })
100+
toast.error('注册功能已关闭', { description: '请联系管理员注册新账号' })
101+
}
102+
else {
103+
next()
104+
}
93105
})
94106

95107
export default router

apps/frontend/src/validators/system.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,20 @@ import { toTypedSchema } from '@vee-validate/zod'
22
import z from 'zod'
33

44
export const systemConfigFormSchema = toTypedSchema(z.object({
5-
register_enabled: z.boolean({ required_error: '请选择是否允许用户注册' }),
6-
register_email_verify: z.boolean({ required_error: '请选择是否需要邮箱验证' }),
7-
team_max_members: z.number({ required_error: '请输入团队最大成员数量' })
5+
register_enabled: z.boolean(),
6+
register_email_verify: z.boolean(),
7+
team_max_members: z.number({ required_error: '请输入团队最大成员数量', invalid_type_error: '请输入有效数字' })
88
.min(1, '团队最大成员数量不能小于 1')
99
.max(1000, '团队最大成员数量不能大于 1000'),
1010
invite_mode: z.enum(['direct', 'email'], { required_error: '请选择团队邀请模式' }),
11-
invite_expires_days: z.number({ required_error: '请输入邀请链接过期天数' })
11+
invite_expires_days: z.number({ required_error: '请输入邀请链接过期天数', invalid_type_error: '请输入有效数字' })
1212
.min(1, '邀请链接过期天数不能小于 1')
1313
.max(30, '邀请链接过期天数不能大于 14'),
14-
project_max_apis: z.number({ required_error: '请输入单个项目最大 API 数量' })
14+
project_max_apis: z.number({ required_error: '请输入单个项目最大 API 数量', invalid_type_error: '请输入有效数字' })
1515
.min(1, '单个项目最大 API 数量不能小于 1')
1616
.max(10000, '单个项目最大 API 数量不能大于 10000'),
1717
api_max_versions: z.number({ required_error: '请输入单个 API 最大版本数量' })
1818
.min(1, '单个 API 最大版本数量不能小于 1')
1919
.max(100, '单个 API 最大版本数量不能大于 100'),
20-
api_version_auto_inc: z.boolean({ required_error: '请选择是否自动递增 API 版本号' }),
20+
api_version_auto_inc: z.boolean(),
2121
}))

apps/frontend/src/views/auth/LoginView.vue

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,22 @@
11
<script setup lang="ts">
22
import { Loader2 } from 'lucide-vue-next'
3+
import { storeToRefs } from 'pinia'
34
import { useForm } from 'vee-validate'
45
import { ref } from 'vue'
56
import { Button } from '@/components/ui/button'
67
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from '@/components/ui/card'
78
import { Checkbox } from '@/components/ui/checkbox'
89
import { FormControl, FormField, FormItem, FormLabel, FormMessage } from '@/components/ui/form'
910
import { Input } from '@/components/ui/input'
11+
import { useGlobalStore } from '@/stores/useGlobalStore'
1012
import { useUserStore } from '@/stores/useUserStore'
1113
import { loginFormSchema } from '@/validators/login'
1214
1315
const userStore = useUserStore()
16+
17+
const globalStore = useGlobalStore()
18+
const { systemConfig } = storeToRefs(globalStore)
19+
1420
const isLoading = ref(false)
1521
1622
const form = useForm({
@@ -80,7 +86,7 @@ const onSubmit = form.handleSubmit(async (values) => {
8086
</Button>
8187
</form>
8288
</CardContent>
83-
<CardFooter class="flex justify-center">
89+
<CardFooter v-if="systemConfig.register_enabled" class="flex justify-center">
8490
<div class="text-sm text-muted-foreground">
8591
还没有账号?
8692
<router-link to="/auth/register" class="text-primary hover:underline">

apps/frontend/src/views/dashboard/DashboardView.vue

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import type { ProjectVisibility } from '@/constants'
33
import type { ProjectItem } from '@/types/project'
44
import { FolderKanban, Inbox, Plus, RefreshCw, Search } from 'lucide-vue-next'
5-
import { computed, onMounted, ref, useTemplateRef, watch } from 'vue'
5+
import { computed, onMounted, ref, useTemplateRef } from 'vue'
66
import { projectApi } from '@/api/project'
77
import CreateTeamDialog from '@/components/dashboard/dialogs/CreateTeamDialog.vue'
88
import DeleteProjectDialog from '@/components/dashboard/dialogs/DeleteProjectDialog.vue'
@@ -134,13 +134,6 @@ function handleProjectDeleted(projectId: string) {
134134
recentProjectsRef.value?.refresh()
135135
}
136136
137-
watch(
138-
() => teamStore.curTeamId,
139-
() => {
140-
fetchProjects()
141-
},
142-
)
143-
144137
onMounted(() => {
145138
fetchProjects()
146139
})

0 commit comments

Comments
 (0)