feat(notify): convert email lists to NotifyEmailEntry struct with toggle support

- Change balance_notify_extra_emails and account_quota_notify_emails
  from []string to []NotifyEmailEntry{email, disabled, verified}
- Add per-email enable/disable toggle for both user and admin notifications
- Add PUT /user/notify-email/toggle API endpoint
- Fix critical bug: API key auth cache snapshot missing balance notify
  fields (Email, Username, BalanceNotifyEnabled, etc.), causing
  notifications to never fire on cached request paths
- Bump cache snapshot version 3→4 to invalidate stale entries
- Add SQL migration 104 to convert old format data
- Backward compatible: parseNotifyEmails auto-detects old/new format
- User balance notify: max 3 emails (primary + 2 extra)
- Admin quota notify: unlimited emails, each with toggle
This commit is contained in:
erio
2026-04-13 00:52:42 +08:00
parent 61aa197b0b
commit 915b7a4a56
25 changed files with 448 additions and 95 deletions

View File

@@ -4,7 +4,7 @@
*/
import { apiClient } from './client'
import type { User, ChangePasswordRequest } from '@/types'
import type { User, ChangePasswordRequest, NotifyEmailEntry } from '@/types'
/**
* Get current user profile
@@ -24,7 +24,7 @@ export async function updateProfile(profile: {
username?: string
balance_notify_enabled?: boolean
balance_notify_threshold?: number | null
balance_notify_extra_emails?: string[]
balance_notify_extra_emails?: NotifyEmailEntry[]
}): Promise<User> {
const { data } = await apiClient.put<User>('/user', profile)
return data
@@ -73,13 +73,24 @@ export async function removeNotifyEmail(email: string): Promise<void> {
await apiClient.delete('/user/notify-email', { data: { email } })
}
/**
* Toggle a notify email's disabled state
* @param email - Email address (empty string for primary email placeholder)
* @param disabled - Whether to disable the email
*/
export async function toggleNotifyEmail(email: string, disabled: boolean): Promise<User> {
const { data } = await apiClient.put<User>('/user/notify-email/toggle', { email, disabled })
return data
}
export const userAPI = {
getProfile,
updateProfile,
changePassword,
sendNotifyEmailCode,
verifyNotifyEmail,
removeNotifyEmail
removeNotifyEmail,
toggleNotifyEmail
}
export default userAPI