feat(songs): 歌曲管理支持批量驳回、投稿留言自动审查与排期范围可见性过滤
- 新增 /api/admin/songs/batch-reject.post 批量驳回接口(事务清排期/投票/扣接纳数/黑名单去重/异步通知) - requireSongAdmin 三角色校验 + createApiError 统一错误包装 - scheduleDaysBefore/After 四字段排期可见范围限制(开放 API 与公开排期接口三处缓存路径 + DB 条件过滤) - submissionNoteAutoModeration 基于黑名单 KEYWORD/LANGUAGE/GENRE 自动判定留言 publicStatus,命中自动关闭 submissionNotePublic - 更新 songs/request.post 与 songs/[id]/update.put 接入自动审查逻辑
This commit is contained in:
+63
-3
@@ -51,9 +51,16 @@ export const authSessions = pgTable('auth_sessions', {
|
||||
userAgent: text('user_agent'),
|
||||
lastActiveAt: timestamp('last_active_at', { withTimezone: true }).defaultNow().notNull(),
|
||||
isRevoked: boolean('is_revoked').default(false).notNull(),
|
||||
browser: text('browser'),
|
||||
operatingSystem: text('operating_system'),
|
||||
device: text('device'),
|
||||
loginMethod: text('login_method').default('password').notNull(),
|
||||
revokedAt: timestamp('revoked_at', { withTimezone: true }),
|
||||
revokedReason: text('revoked_reason')
|
||||
}, (table) => [
|
||||
index('auth_sessions_user_id_idx').on(table.userId),
|
||||
index('auth_sessions_user_active_idx').on(table.userId, table.isRevoked, table.expiresAt),
|
||||
index('auth_sessions_expires_at_idx').on(table.expiresAt),
|
||||
index('auth_sessions_last_active_idx').on(table.lastActiveAt),
|
||||
uniqueIndex('auth_sessions_session_token_unique').on(table.sessionToken),
|
||||
]);
|
||||
|
||||
@@ -258,16 +265,29 @@ export const systemSettings = pgTable('SystemSettings', {
|
||||
enableReplayRequests: boolean('enableReplayRequests').default(false).notNull(),
|
||||
enableCollaborativeSubmission: boolean('enableCollaborativeSubmission').default(true).notNull(),
|
||||
enableSubmissionRemarks: boolean('enableSubmissionRemarks').default(false).notNull(),
|
||||
submissionNoteRequiresApproval: boolean('submissionNoteRequiresApproval').default(false).notNull(),
|
||||
instanceId: text('instanceId'),
|
||||
telemetryEnabled: boolean('telemetryEnabled').default(true).notNull(),
|
||||
showBeianIcon: boolean('showBeianIcon').default(true).notNull(),
|
||||
scheduleDaysDisplay: integer('scheduleDaysDisplay').default(7).notNull(),
|
||||
scheduleDaysEditable: integer('scheduleDaysEditable').default(3).notNull(),
|
||||
scheduleDaysRequestable: integer('scheduleDaysRequestable').default(14).notNull(),
|
||||
scheduleDaysBeforeEnabled: boolean('scheduleDaysBeforeEnabled').default(false).notNull(),
|
||||
scheduleDaysBefore: integer('scheduleDaysBefore').default(1).notNull(),
|
||||
scheduleDaysAfterEnabled: boolean('scheduleDaysAfterEnabled').default(false).notNull(),
|
||||
scheduleDaysAfter: integer('scheduleDaysAfter').default(1).notNull(),
|
||||
forcePasswordChangeOnFirstLogin: boolean('forcePasswordChangeOnFirstLogin').default(false).notNull(),
|
||||
enableSubmissionRestriction: boolean('enableSubmissionRestriction').default(false).notNull(),
|
||||
submissionRestrictionScope: text('submissionRestrictionScope').default('all').notNull(),
|
||||
sameSongRestrictionHours: integer('sameSongRestrictionHours'),
|
||||
sameArtistRestrictionHours: integer('sameArtistRestrictionHours'),
|
||||
cardCodeEnabled: boolean('cardCodeEnabled').default(false).notNull(),
|
||||
cardCodeSubmissionRequired: boolean('cardCodeSubmissionRequired').default(false).notNull(),
|
||||
cardCodeVoteEnabled: boolean('cardCodeVoteEnabled').default(false).notNull(),
|
||||
cardCodeReplayEnabled: boolean('cardCodeReplayEnabled').default(false).notNull(),
|
||||
enableCardCodeRequests: boolean('enableCardCodeRequests').default(false).notNull(),
|
||||
requireCardCodeForRequests: boolean('requireCardCodeForRequests').default(false).notNull(),
|
||||
enableCardCodeLimitBypass: boolean('enableCardCodeLimitBypass').default(false).notNull(),
|
||||
submissionRestrictionEnabled: boolean('submissionRestrictionEnabled').default(false).notNull(),
|
||||
submissionRestrictionGradeEnabled: boolean('submissionRestrictionGradeEnabled').default(false).notNull(),
|
||||
submissionRestrictionClassEnabled: boolean('submissionRestrictionClassEnabled').default(false).notNull(),
|
||||
@@ -282,16 +302,56 @@ export const systemSettings = pgTable('SystemSettings', {
|
||||
registerRequireEmailVerify: boolean('registerRequireEmailVerify').default(false).notNull(),
|
||||
registerDefaultRole: text('registerDefaultRole').default('USER'),
|
||||
registerEnabledGradeClasses: text('registerEnabledGradeClasses'),
|
||||
registerRequiresApproval: boolean('registerRequiresApproval').default(false).notNull(),
|
||||
oauthRegisterRequiresApproval: boolean('oauthRegisterRequiresApproval').default(false).notNull(),
|
||||
registerEmailRequired: boolean('registerEmailRequired').default(false).notNull(),
|
||||
registerRequiresGradeClass: boolean('registerRequiresGradeClass').default(false).notNull(),
|
||||
oauthEnabled: boolean('oauthEnabled').default(false).notNull(),
|
||||
oauthAllowRegister: boolean('oauthAllowRegister').default(true).notNull(),
|
||||
oauthAllowLogin: boolean('oauthAllowLogin').default(true).notNull(),
|
||||
oauthAllowBind: boolean('oauthAllowBind').default(true).notNull(),
|
||||
allowOAuthRegistration: boolean('allowOAuthRegistration').default(false).notNull(),
|
||||
oauthRedirectUri: text('oauthRedirectUri'),
|
||||
oauthStateSecret: text('oauthStateSecret'),
|
||||
oauthProviders: text('oauthProviders').default('[]'),
|
||||
githubOAuthEnabled: boolean('githubOAuthEnabled').default(false).notNull(),
|
||||
githubClientId: text('githubClientId'),
|
||||
githubClientSecret: text('githubClientSecret'),
|
||||
casdoorOAuthEnabled: boolean('casdoorOAuthEnabled').default(false).notNull(),
|
||||
casdoorServerUrl: text('casdoorServerUrl'),
|
||||
casdoorClientId: text('casdoorClientId'),
|
||||
casdoorClientSecret: text('casdoorClientSecret'),
|
||||
casdoorOrganizationName: text('casdoorOrganizationName'),
|
||||
googleOAuthEnabled: boolean('googleOAuthEnabled').default(false).notNull(),
|
||||
googleClientId: text('googleClientId'),
|
||||
googleClientSecret: text('googleClientSecret'),
|
||||
aggregateOAuthEnabled: boolean('aggregateOAuthEnabled').default(false).notNull(),
|
||||
aggregateOAuthAppId: text('aggregateOAuthAppId'),
|
||||
aggregateOAuthAppKey: text('aggregateOAuthAppKey'),
|
||||
aggregateOAuthLoginType: text('aggregateOAuthLoginType').default('qq'),
|
||||
aggregateOAuthEndpoint: text('aggregateOAuthEndpoint'),
|
||||
customOAuthEnabled: boolean('customOAuthEnabled').default(false).notNull(),
|
||||
customOAuthDisplayName: text('customOAuthDisplayName'),
|
||||
customOAuthAuthorizeUrl: text('customOAuthAuthorizeUrl'),
|
||||
customOAuthTokenUrl: text('customOAuthTokenUrl'),
|
||||
customOAuthUserInfoUrl: text('customOAuthUserInfoUrl'),
|
||||
customOAuthScope: text('customOAuthScope'),
|
||||
customOAuthClientId: text('customOAuthClientId'),
|
||||
customOAuthClientSecret: text('customOAuthClientSecret'),
|
||||
customOAuthUserIdField: text('customOAuthUserIdField'),
|
||||
customOAuthUsernameField: text('customOAuthUsernameField'),
|
||||
customOAuthNameField: text('customOAuthNameField'),
|
||||
customOAuthEmailField: text('customOAuthEmailField'),
|
||||
customOAuthAvatarField: text('customOAuthAvatarField'),
|
||||
captchaMaxFailures: integer('captchaMaxFailures').default(3).notNull(),
|
||||
autoBackupEnabled: boolean('autoBackupEnabled').default(false).notNull(),
|
||||
autoBackupIntervalHours: integer('autoBackupIntervalHours').default(24).notNull(),
|
||||
autoBackupRetentionDays: integer('autoBackupRetentionDays').default(30).notNull(),
|
||||
autoBackupConfig: text('autoBackupConfig'),
|
||||
statisticsCode: text('statisticsCode'),
|
||||
defaultTheme: text('defaultTheme').default('light'),
|
||||
enabledThemes: text('enabledThemes').default('light,dark'),
|
||||
statisticsCodeEnabled: boolean('statisticsCodeEnabled').default(false).notNull(),
|
||||
defaultTheme: text('defaultTheme').default('System').notNull(),
|
||||
enabledThemes: text('enabledThemes').default('[\"System\",\"ClassicDark\",\"ClassicLight\",\"ModernLight\"]').notNull(),
|
||||
enabledPlatforms: text('enabledPlatforms'),
|
||||
platformOrder: text('platformOrder'),
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user