255 lines
9.3 KiB
TypeScript
255 lines
9.3 KiB
TypeScript
import { createError, defineEventHandler } from 'h3'
|
|
import { db } from '~/drizzle/db'
|
|
import { CacheService } from '../../../services/cacheService'
|
|
import {
|
|
apiKeyPermissions,
|
|
apiKeys,
|
|
apiLogs,
|
|
collaborationLogs,
|
|
emailTemplates,
|
|
notificationSettings,
|
|
notifications,
|
|
playTimes,
|
|
requestTimes,
|
|
schedules,
|
|
semesters,
|
|
songBlacklists,
|
|
songCollaborators,
|
|
songReplayRequests,
|
|
songs,
|
|
systemSettings,
|
|
userIdentities,
|
|
users,
|
|
userStatusLogs,
|
|
votes
|
|
} from '~/drizzle/schema'
|
|
import { ne, sql } from 'drizzle-orm'
|
|
|
|
// 重置所有表的自增序列
|
|
async function resetAutoIncrementSequences() {
|
|
const tables = [
|
|
{ name: 'users', dbName: 'User' },
|
|
{ name: 'songs', dbName: 'Song' },
|
|
{ name: 'votes', dbName: 'Vote' },
|
|
{ name: 'schedules', dbName: 'Schedule' },
|
|
{ name: 'notifications', dbName: 'Notification' },
|
|
{ name: 'notificationSettings', dbName: 'NotificationSettings' },
|
|
{ name: 'playTimes', dbName: 'PlayTime' },
|
|
{ name: 'semesters', dbName: 'Semester' },
|
|
{ name: 'systemSettings', dbName: 'SystemSettings' },
|
|
{ name: 'songBlacklists', dbName: 'SongBlacklist' },
|
|
{ name: 'userStatusLogs', dbName: 'user_status_logs' },
|
|
{ name: 'userIdentities', dbName: 'UserIdentity' },
|
|
{ name: 'requestTimes', dbName: 'RequestTime' },
|
|
{ name: 'songReplayRequests', dbName: 'song_replay_requests' },
|
|
{ name: 'emailTemplates', dbName: 'EmailTemplate' }
|
|
]
|
|
|
|
const results = []
|
|
|
|
for (const table of tables) {
|
|
try {
|
|
// 获取序列名称
|
|
const sequenceNameResult = await db.execute(
|
|
sql.raw(`SELECT pg_get_serial_sequence('"${table.dbName}"', 'id') as sequence_name`)
|
|
)
|
|
const sequenceName = (sequenceNameResult as any)[0]?.sequence_name
|
|
|
|
if (sequenceName) {
|
|
// 重置序列值到 1
|
|
await db.execute(sql.raw(`ALTER SEQUENCE ${sequenceName} RESTART WITH 1`))
|
|
results.push({ table: table.name, success: true })
|
|
} else {
|
|
results.push({ table: table.name, success: false, message: 'Sequence not found' })
|
|
}
|
|
} catch (error) {
|
|
console.warn(`重置 ${table.name} 表序列失败: ${error.message}`)
|
|
results.push({ table: table.name, success: false, error: error.message })
|
|
}
|
|
}
|
|
return results
|
|
}
|
|
|
|
export default defineEventHandler(async (event) => {
|
|
try {
|
|
// 验证管理员权限
|
|
const user = event.context.user
|
|
if (!user || !['ADMIN', 'SUPER_ADMIN'].includes(user.role)) {
|
|
throw createError({
|
|
statusCode: 403,
|
|
statusMessage: '权限不足'
|
|
})
|
|
}
|
|
|
|
const resetResults = {
|
|
success: true,
|
|
message: '数据库重置完成',
|
|
details: {
|
|
tablesCleared: 0,
|
|
recordsDeleted: 0,
|
|
sequencesReset: 0,
|
|
errors: [],
|
|
preservedData: []
|
|
}
|
|
}
|
|
|
|
try {
|
|
// 使用事务确保数据一致性
|
|
await db.transaction(async (tx) => {
|
|
// 按照外键依赖顺序删除数据
|
|
|
|
// 1. API 日志与权限 (依赖于 API 密钥)
|
|
const deletedApiLogs = await tx.delete(apiLogs).returning({ id: apiLogs.id })
|
|
resetResults.details.recordsDeleted += deletedApiLogs.length
|
|
resetResults.details.tablesCleared++
|
|
|
|
const deletedApiKeyPermissions = await tx
|
|
.delete(apiKeyPermissions)
|
|
.returning({ id: apiKeyPermissions.id })
|
|
resetResults.details.recordsDeleted += deletedApiKeyPermissions.length
|
|
resetResults.details.tablesCleared++
|
|
|
|
// 2. API 密钥 (依赖于用户)
|
|
const deletedApiKeys = await tx.delete(apiKeys).returning({ id: apiKeys.id })
|
|
resetResults.details.recordsDeleted += deletedApiKeys.length
|
|
resetResults.details.tablesCleared++
|
|
|
|
// 3. 通知与设置 (依赖于用户、歌曲)
|
|
const deletedNotifications = await tx
|
|
.delete(notifications)
|
|
.returning({ id: notifications.id })
|
|
resetResults.details.recordsDeleted += deletedNotifications.length
|
|
resetResults.details.tablesCleared++
|
|
|
|
const deletedNotificationSettings = await tx
|
|
.delete(notificationSettings)
|
|
.returning({ id: notificationSettings.id })
|
|
resetResults.details.recordsDeleted += deletedNotificationSettings.length
|
|
resetResults.details.tablesCleared++
|
|
|
|
// 4. 协作日志 (依赖于歌曲协作者)
|
|
const deletedCollaborationLogs = await tx
|
|
.delete(collaborationLogs)
|
|
.returning({ id: collaborationLogs.id })
|
|
resetResults.details.recordsDeleted += deletedCollaborationLogs.length
|
|
resetResults.details.tablesCleared++
|
|
|
|
// 5. 歌曲协作者 (依赖于歌曲、用户)
|
|
const deletedSongCollaborators = await tx
|
|
.delete(songCollaborators)
|
|
.returning({ id: songCollaborators.id })
|
|
resetResults.details.recordsDeleted += deletedSongCollaborators.length
|
|
resetResults.details.tablesCleared++
|
|
|
|
// 6. 歌曲重播申请 (依赖于歌曲、用户)
|
|
const deletedReplayRequests = await tx
|
|
.delete(songReplayRequests)
|
|
.returning({ id: songReplayRequests.id })
|
|
resetResults.details.recordsDeleted += deletedReplayRequests.length
|
|
resetResults.details.tablesCleared++
|
|
|
|
// 7. 排期 (依赖于歌曲、播出时段)
|
|
const deletedSchedules = await tx.delete(schedules).returning({ id: schedules.id })
|
|
resetResults.details.recordsDeleted += deletedSchedules.length
|
|
resetResults.details.tablesCleared++
|
|
|
|
// 8. 投票 (依赖于歌曲、用户)
|
|
const deletedVotes = await tx.delete(votes).returning({ id: votes.id })
|
|
resetResults.details.recordsDeleted += deletedVotes.length
|
|
resetResults.details.tablesCleared++
|
|
|
|
// 9. 歌曲 (依赖于用户、播出时段)
|
|
const deletedSongs = await tx.delete(songs).returning({ id: songs.id })
|
|
resetResults.details.recordsDeleted += deletedSongs.length
|
|
resetResults.details.tablesCleared++
|
|
|
|
// 10. 黑名单 (依赖于用户 [创建者])
|
|
const deletedBlacklists = await tx
|
|
.delete(songBlacklists)
|
|
.returning({ id: songBlacklists.id })
|
|
resetResults.details.recordsDeleted += deletedBlacklists.length
|
|
resetResults.details.tablesCleared++
|
|
|
|
// 11. 用户状态日志 (依赖于用户)
|
|
const deletedStatusLogs = await tx
|
|
.delete(userStatusLogs)
|
|
.returning({ id: userStatusLogs.id })
|
|
resetResults.details.recordsDeleted += deletedStatusLogs.length
|
|
resetResults.details.tablesCleared++
|
|
|
|
// 12. 第三方身份关联 (依赖于用户)
|
|
const deletedUserIdentities = await tx
|
|
.delete(userIdentities)
|
|
.returning({ id: userIdentities.id })
|
|
resetResults.details.recordsDeleted += deletedUserIdentities.length
|
|
resetResults.details.tablesCleared++
|
|
|
|
// 13. 邮件模板 (依赖于用户 [更新者])
|
|
const deletedEmailTemplates = await tx
|
|
.delete(emailTemplates)
|
|
.returning({ id: emailTemplates.id })
|
|
resetResults.details.recordsDeleted += deletedEmailTemplates.length
|
|
resetResults.details.tablesCleared++
|
|
|
|
// 14. 用户 (除自己外)
|
|
const deletedUsers = await tx
|
|
.delete(users)
|
|
.where(ne(users.id, user.id))
|
|
.returning({ id: users.id })
|
|
resetResults.details.recordsDeleted += deletedUsers.length
|
|
resetResults.details.tablesCleared++
|
|
resetResults.details.preservedData.push(`保留当前管理员账户: ${user.name}`)
|
|
|
|
// 15. 播出时段
|
|
const deletedPlayTimes = await tx.delete(playTimes).returning({ id: playTimes.id })
|
|
resetResults.details.recordsDeleted += deletedPlayTimes.length
|
|
resetResults.details.tablesCleared++
|
|
|
|
// 16. 学期
|
|
const deletedSemesters = await tx.delete(semesters).returning({ id: semesters.id })
|
|
resetResults.details.recordsDeleted += deletedSemesters.length
|
|
resetResults.details.tablesCleared++
|
|
|
|
// 17. 请求时段
|
|
const deletedRequestTimes = await tx.delete(requestTimes).returning({ id: requestTimes.id })
|
|
resetResults.details.recordsDeleted += deletedRequestTimes.length
|
|
resetResults.details.tablesCleared++
|
|
|
|
// 18. 系统设置
|
|
const deletedSystemSettings = await tx
|
|
.delete(systemSettings)
|
|
.returning({ id: systemSettings.id })
|
|
resetResults.details.recordsDeleted += deletedSystemSettings.length
|
|
resetResults.details.tablesCleared++
|
|
})
|
|
|
|
// 重置自增序列
|
|
const sequenceResults = await resetAutoIncrementSequences()
|
|
resetResults.details.sequencesReset = sequenceResults.filter((r) => r.success).length
|
|
|
|
// 清除缓存
|
|
try {
|
|
const cacheService = CacheService.getInstance()
|
|
await cacheService.clearAllCache()
|
|
} catch (error) {
|
|
console.warn('清除缓存失败:', error)
|
|
resetResults.details.warnings = resetResults.details.warnings || []
|
|
resetResults.details.warnings.push('清除缓存失败')
|
|
}
|
|
} catch (error) {
|
|
console.error('重置数据库失败:', error)
|
|
throw createError({
|
|
statusCode: 500,
|
|
statusMessage: `重置数据库失败: ${error.message}`
|
|
})
|
|
}
|
|
|
|
return resetResults
|
|
} catch (error) {
|
|
throw createError({
|
|
statusCode: error.statusCode || 500,
|
|
statusMessage: error.statusMessage || '服务器内部错误'
|
|
})
|
|
}
|
|
})
|