From b1d898e29825c48654ec0fd63bae1d1aa1f59886 Mon Sep 17 00:00:00 2001 From: beilunyang <786220806@qq.com> Date: Fri, 28 Feb 2025 00:16:06 +0800 Subject: [PATCH] feat: Add configurable maximum email limit for users --- app/api/config/route.ts | 17 +++++++++++------ app/api/emails/generate/route.ts | 8 +++++--- app/components/emails/email-list.tsx | 18 +++++++++++++++++- app/components/profile/config-panel.tsx | 25 +++++++++++++++++++++++-- middleware.ts | 4 ++++ 5 files changed, 60 insertions(+), 12 deletions(-) diff --git a/app/api/config/route.ts b/app/api/config/route.ts index 678d78b..f492a40 100644 --- a/app/api/config/route.ts +++ b/app/api/config/route.ts @@ -1,28 +1,32 @@ import { Role, ROLES } from "@/lib/permissions" import { getRequestContext } from "@cloudflare/next-on-pages" +import { EMAIL_CONFIG } from "@/config" export const runtime = "edge" export async function GET() { const env = getRequestContext().env - const [defaultRole, emailDomains, adminContact] = await Promise.all([ + const [defaultRole, emailDomains, adminContact, maxEmails] = await Promise.all([ env.SITE_CONFIG.get("DEFAULT_ROLE"), env.SITE_CONFIG.get("EMAIL_DOMAINS"), - env.SITE_CONFIG.get("ADMIN_CONTACT") + env.SITE_CONFIG.get("ADMIN_CONTACT"), + env.SITE_CONFIG.get("MAX_EMAILS") ]) return Response.json({ defaultRole: defaultRole || ROLES.CIVILIAN, emailDomains: emailDomains || "", - adminContact: adminContact || "" + adminContact: adminContact || "", + maxEmails: maxEmails || EMAIL_CONFIG.MAX_ACTIVE_EMAILS.toString() }) } export async function POST(request: Request) { - const { defaultRole, emailDomains, adminContact } = await request.json() as { + const { defaultRole, emailDomains, adminContact, maxEmails } = await request.json() as { defaultRole: Exclude, emailDomains: string, - adminContact: string + adminContact: string, + maxEmails: string } if (![ROLES.DUKE, ROLES.KNIGHT, ROLES.CIVILIAN].includes(defaultRole)) { @@ -33,7 +37,8 @@ export async function POST(request: Request) { await Promise.all([ env.SITE_CONFIG.put("DEFAULT_ROLE", defaultRole), env.SITE_CONFIG.put("EMAIL_DOMAINS", emailDomains), - env.SITE_CONFIG.put("ADMIN_CONTACT", adminContact) + env.SITE_CONFIG.put("ADMIN_CONTACT", adminContact), + env.SITE_CONFIG.put("MAX_EMAILS", maxEmails) ]) return Response.json({ success: true }) diff --git a/app/api/emails/generate/route.ts b/app/api/emails/generate/route.ts index 2cea299..d0162df 100644 --- a/app/api/emails/generate/route.ts +++ b/app/api/emails/generate/route.ts @@ -14,12 +14,14 @@ export const runtime = "edge" export async function POST(request: Request) { const db = createDb() + const env = getRequestContext().env const userId = await getUserId() const userRole = await getUserRole(userId!) try { if (userRole !== ROLES.EMPEROR) { + const maxEmails = await env.SITE_CONFIG.get("MAX_EMAILS") || EMAIL_CONFIG.MAX_ACTIVE_EMAILS.toString() const activeEmailsCount = await db .select({ count: sql`count(*)` }) .from(emails) @@ -30,9 +32,9 @@ export async function POST(request: Request) { ) ) - if (Number(activeEmailsCount[0].count) >= EMAIL_CONFIG.MAX_ACTIVE_EMAILS) { + if (Number(activeEmailsCount[0].count) >= Number(maxEmails)) { return NextResponse.json( - { error: `已达到最大邮箱数量限制 (${EMAIL_CONFIG.MAX_ACTIVE_EMAILS})` }, + { error: `已达到最大邮箱数量限制 (${maxEmails})` }, { status: 403 } ) } @@ -51,7 +53,7 @@ export async function POST(request: Request) { ) } - const domainString = await getRequestContext().env.SITE_CONFIG.get("EMAIL_DOMAINS") + const domainString = await env.SITE_CONFIG.get("EMAIL_DOMAINS") const domains = domainString ? domainString.split(',') : ["moemail.app"] if (!domains || !domains.includes(domain)) { diff --git a/app/components/emails/email-list.tsx b/app/components/emails/email-list.tsx index b304538..7aaa503 100644 --- a/app/components/emails/email-list.tsx +++ b/app/components/emails/email-list.tsx @@ -49,9 +49,22 @@ export function EmailList({ onEmailSelect, selectedEmailId }: EmailListProps) { const [nextCursor, setNextCursor] = useState(null) const [loadingMore, setLoadingMore] = useState(false) const [total, setTotal] = useState(0) + const [maxEmails, setMaxEmails] = useState(EMAIL_CONFIG.MAX_ACTIVE_EMAILS) const [emailToDelete, setEmailToDelete] = useState(null) const { toast } = useToast() + const fetchMaxEmails = async () => { + try { + const res = await fetch("/api/config") + if (res.ok) { + const data = await res.json() as { maxEmails: string } + setMaxEmails(Number(data.maxEmails)) + } + } catch (error) { + console.error("Failed to fetch max emails:", error) + } + } + const fetchEmails = async (cursor?: string) => { try { const url = new URL("/api/emails", window.location.origin) @@ -112,6 +125,9 @@ export function EmailList({ onEmailSelect, selectedEmailId }: EmailListProps) { useEffect(() => { if (session) fetchEmails() + if (session && role !== ROLES.EMPEROR) { + fetchMaxEmails() + } // eslint-disable-next-line react-hooks/exhaustive-deps }, [session]) @@ -173,7 +189,7 @@ export function EmailList({ onEmailSelect, selectedEmailId }: EmailListProps) { {role === ROLES.EMPEROR ? ( `${total}/∞ 个邮箱` ) : ( - `${total}/${EMAIL_CONFIG.MAX_ACTIVE_EMAILS} 个邮箱` + `${total}/${maxEmails} 个邮箱` )} diff --git a/app/components/profile/config-panel.tsx b/app/components/profile/config-panel.tsx index 37b83ea..cc19b47 100644 --- a/app/components/profile/config-panel.tsx +++ b/app/components/profile/config-panel.tsx @@ -13,11 +13,13 @@ import { SelectTrigger, SelectValue, } from "@/components/ui/select" +import { EMAIL_CONFIG } from "@/config" export function ConfigPanel() { const [defaultRole, setDefaultRole] = useState("") const [emailDomains, setEmailDomains] = useState("") const [adminContact, setAdminContact] = useState("") + const [maxEmails, setMaxEmails] = useState(EMAIL_CONFIG.MAX_ACTIVE_EMAILS.toString()) const [loading, setLoading] = useState(false) const { toast } = useToast() @@ -31,10 +33,14 @@ export function ConfigPanel() { if (res.ok) { const data = await res.json() as { defaultRole: Exclude, - emailDomains: string + emailDomains: string, + adminContact: string, + maxEmails: string } setDefaultRole(data.defaultRole) setEmailDomains(data.emailDomains) + setAdminContact(data.adminContact) + setMaxEmails(data.maxEmails || EMAIL_CONFIG.MAX_ACTIVE_EMAILS.toString()) } } @@ -47,7 +53,8 @@ export function ConfigPanel() { body: JSON.stringify({ defaultRole, emailDomains, - adminContact + adminContact, + maxEmails: maxEmails || EMAIL_CONFIG.MAX_ACTIVE_EMAILS.toString() }), }) @@ -112,6 +119,20 @@ export function ConfigPanel() { +
+ 最大邮箱数量: +
+ setMaxEmails(e.target.value)} + placeholder={`默认为 ${EMAIL_CONFIG.MAX_ACTIVE_EMAILS}`} + /> +
+
+