11import type { VercelRequest , VercelResponse } from '@vercel/node' ;
2- import { execSync } from 'child_process' ;
2+ import { PrismaClient } from '@prisma/client' ;
3+ import * as bcrypt from 'bcryptjs' ;
34
4- export default async function handler ( req : VercelRequest , res : VercelResponse ) {
5- // Verify the request is from Vercel Cron
5+ const prisma = new PrismaClient ( ) ;
6+
7+ // 验证 Vercel Cron 请求
8+ function isValidCronRequest ( req : VercelRequest ) : boolean {
9+ // 方式1: 验证 Vercel Cron 的 Authorization header
610 const authHeader = req . headers . authorization ;
7- if ( authHeader !== `Bearer ${ process . env . CRON_SECRET } ` ) {
8- return res . status ( 401 ) . json ( { error : 'Unauthorized' } ) ;
11+ const cronSecret = process . env . CRON_SECRET ;
12+
13+ if ( ! cronSecret ) {
14+ console . error ( 'CRON_SECRET not configured' ) ;
15+ return false ;
916 }
1017
11- try {
12- console . log ( '🔄 Starting database reset...' ) ;
18+ if ( authHeader !== `Bearer ${ cronSecret } ` ) {
19+ return false ;
20+ }
21+
22+ // 方式2: 验证请求来源 (Vercel Cron 内部调用会带有这个 header)
23+ const userAgent = req . headers [ 'user-agent' ] ;
24+ if ( ! userAgent ?. includes ( 'vercel-cron' ) ) {
25+ // 如果不是来自 Vercel Cron,需要额外验证
26+ const forwardedFor = req . headers [ 'x-forwarded-for' ] ;
27+ const vercelId = req . headers [ 'x-vercel-id' ] ;
28+
29+ // 确保请求来自 Vercel 内部
30+ if ( ! vercelId ) {
31+ console . warn ( 'Request not from Vercel internal' ) ;
32+ // 在生产环境中,可以选择拒绝非 Vercel 内部请求
33+ // return false;
34+ }
35+ }
36+
37+ return true ;
38+ }
39+
40+ async function resetDatabase ( ) : Promise < void > {
41+ // 清除所有数据(按依赖顺序)
42+ await prisma . refreshToken . deleteMany ( ) ;
43+ await prisma . activityLog . deleteMany ( ) ;
44+ await prisma . notification . deleteMany ( ) ;
45+ await prisma . message . deleteMany ( ) ;
46+ await prisma . conversationParticipant . deleteMany ( ) ;
47+ await prisma . conversation . deleteMany ( ) ;
48+ await prisma . eventReminder . deleteMany ( ) ;
49+ await prisma . eventAttendee . deleteMany ( ) ;
50+ await prisma . calendarEvent . deleteMany ( ) ;
51+ await prisma . file . deleteMany ( ) ;
52+ await prisma . folder . deleteMany ( ) ;
53+ await prisma . documentTag . deleteMany ( ) ;
54+ await prisma . tag . deleteMany ( ) ;
55+ await prisma . documentShare . deleteMany ( ) ;
56+ await prisma . document . deleteMany ( ) ;
57+ await prisma . teamMember . deleteMany ( ) ;
58+ await prisma . team . deleteMany ( ) ;
59+ await prisma . userRole . deleteMany ( ) ;
60+ await prisma . rolePermission . deleteMany ( ) ;
61+ await prisma . permission . deleteMany ( ) ;
62+ await prisma . role . deleteMany ( ) ;
63+ await prisma . user . deleteMany ( ) ;
64+
65+ // 创建权限
66+ const permissions = await Promise . all ( [
67+ prisma . permission . create ( { data : { action : '*' , resource : '*' , description : 'Full system access' } } ) ,
68+ prisma . permission . create ( { data : { action : 'users:*' , resource : 'users' , description : 'Full user management' } } ) ,
69+ prisma . permission . create ( { data : { action : 'users:read' , resource : 'users' , description : 'View users' } } ) ,
70+ prisma . permission . create ( { data : { action : 'documents:*' , resource : 'documents' , description : 'Full document management' } } ) ,
71+ prisma . permission . create ( { data : { action : 'documents:read' , resource : 'documents' , description : 'View documents' } } ) ,
72+ prisma . permission . create ( { data : { action : 'teams:read' , resource : 'teams' , description : 'View teams' } } ) ,
73+ prisma . permission . create ( { data : { action : 'dashboard:read' , resource : 'dashboard' , description : 'View dashboard' } } ) ,
74+ ] ) ;
75+
76+ // 创建角色
77+ const adminRole = await prisma . role . create ( {
78+ data : { name : 'admin' , label : '系统管理员' , description : '拥有系统全部权限' } ,
79+ } ) ;
80+ const userRole = await prisma . role . create ( {
81+ data : { name : 'user' , label : '普通用户' , description : '基本操作权限' } ,
82+ } ) ;
83+
84+ // 分配权限
85+ await prisma . rolePermission . create ( { data : { roleId : adminRole . id , permissionId : permissions [ 0 ] . id } } ) ;
86+ await prisma . rolePermission . createMany ( {
87+ data : [
88+ { roleId : userRole . id , permissionId : permissions [ 2 ] . id } ,
89+ { roleId : userRole . id , permissionId : permissions [ 4 ] . id } ,
90+ { roleId : userRole . id , permissionId : permissions [ 5 ] . id } ,
91+ { roleId : userRole . id , permissionId : permissions [ 6 ] . id } ,
92+ ] ,
93+ } ) ;
94+
95+ // 创建用户
96+ const hashedPassword = await bcrypt . hash ( 'Demo@123' , 10 ) ;
97+
98+ const adminUser = await prisma . user . create ( {
99+ data : {
100+ email : 'admin@halolight.cn' ,
101+ username : 'admin' ,
102+ password : hashedPassword ,
103+ name : '系统管理员' ,
104+ avatar : 'https://api.dicebear.com/7.x/avataaars/svg?seed=admin' ,
105+ status : 'ACTIVE' ,
106+ department : '技术部' ,
107+ position : 'CTO' ,
108+ } ,
109+ } ) ;
13110
14- // Run prisma seed
15- execSync ( 'npx prisma db seed' , {
16- cwd : process . cwd ( ) ,
17- stdio : 'inherit' ,
18- env : {
19- ...process . env ,
20- DATABASE_URL : process . env . DATABASE_URL ,
111+ const demoUser = await prisma . user . create ( {
112+ data : {
113+ email : 'demo@halolight.cn' ,
114+ username : 'demo' ,
115+ password : hashedPassword ,
116+ name : '演示用户' ,
117+ avatar : 'https://api.dicebear.com/7.x/avataaars/svg?seed=demo' ,
118+ status : 'ACTIVE' ,
119+ department : '研发部' ,
120+ position : '前端工程师' ,
121+ } ,
122+ } ) ;
123+
124+ // 分配角色
125+ await prisma . userRole . createMany ( {
126+ data : [
127+ { userId : adminUser . id , roleId : adminRole . id } ,
128+ { userId : demoUser . id , roleId : userRole . id } ,
129+ ] ,
130+ } ) ;
131+
132+ // 创建团队
133+ const devTeam = await prisma . team . create ( {
134+ data : {
135+ name : '研发团队' ,
136+ description : '负责产品研发和技术创新' ,
137+ ownerId : adminUser . id ,
138+ } ,
139+ } ) ;
140+
141+ await prisma . teamMember . createMany ( {
142+ data : [
143+ { teamId : devTeam . id , userId : adminUser . id , roleId : adminRole . id } ,
144+ { teamId : devTeam . id , userId : demoUser . id , roleId : userRole . id } ,
145+ ] ,
146+ } ) ;
147+
148+ // 创建文档
149+ await prisma . document . create ( {
150+ data : {
151+ title : 'HaloLight API 使用指南' ,
152+ content : '# HaloLight API 使用指南\n\n欢迎使用 HaloLight API...' ,
153+ type : 'markdown' ,
154+ size : BigInt ( 2048 ) ,
155+ views : 128 ,
156+ ownerId : adminUser . id ,
157+ teamId : devTeam . id ,
158+ } ,
159+ } ) ;
160+
161+ // 创建通知
162+ await prisma . notification . createMany ( {
163+ data : [
164+ {
165+ userId : demoUser . id ,
166+ type : 'system' ,
167+ title : '欢迎使用 HaloLight' ,
168+ content : '感谢您使用 HaloLight 管理后台,这是演示环境,每天自动重置数据。' ,
169+ read : false ,
170+ } ,
171+ {
172+ userId : adminUser . id ,
173+ type : 'system' ,
174+ title : '系统初始化完成' ,
175+ content : '数据库已重置为初始状态。' ,
176+ read : false ,
21177 } ,
178+ ] ,
179+ } ) ;
180+ }
181+
182+ export default async function handler ( req : VercelRequest , res : VercelResponse ) {
183+ // 只允许 POST 或 GET 请求(Vercel Cron 使用 GET)
184+ if ( req . method !== 'GET' && req . method !== 'POST' ) {
185+ return res . status ( 405 ) . json ( { error : 'Method not allowed' } ) ;
186+ }
187+
188+ // 验证请求合法性
189+ if ( ! isValidCronRequest ( req ) ) {
190+ console . error ( 'Unauthorized cron request attempt' ) ;
191+ return res . status ( 401 ) . json ( {
192+ error : 'Unauthorized' ,
193+ message : 'Invalid or missing CRON_SECRET' ,
22194 } ) ;
195+ }
196+
197+ try {
198+ console . log ( '🔄 Starting database reset...' ) ;
199+ const startTime = Date . now ( ) ;
200+
201+ await resetDatabase ( ) ;
23202
24- console . log ( '✅ Database reset completed' ) ;
203+ const duration = Date . now ( ) - startTime ;
204+ console . log ( `✅ Database reset completed in ${ duration } ms` ) ;
25205
26206 return res . status ( 200 ) . json ( {
27207 success : true ,
28208 message : 'Database reset completed successfully' ,
209+ duration : `${ duration } ms` ,
29210 timestamp : new Date ( ) . toISOString ( ) ,
211+ accounts : [
212+ { email : 'admin@halolight.cn' , password : 'Demo@123' , role : 'admin' } ,
213+ { email : 'demo@halolight.cn' , password : 'Demo@123' , role : 'user' } ,
214+ ] ,
30215 } ) ;
31216 } catch ( error ) {
32217 console . error ( '❌ Database reset failed:' , error ) ;
@@ -35,5 +220,7 @@ export default async function handler(req: VercelRequest, res: VercelResponse) {
35220 error : 'Database reset failed' ,
36221 message : error instanceof Error ? error . message : 'Unknown error' ,
37222 } ) ;
223+ } finally {
224+ await prisma . $disconnect ( ) ;
38225 }
39226}
0 commit comments