mirror of
https://github.com/beilunyang/moemail.git
synced 2026-05-11 18:11:27 +08:00
feat: implement email sending functionality via Resend service
This commit is contained in:
@@ -55,13 +55,18 @@ export const messages = sqliteTable("message", {
|
||||
emailId: text("emailId")
|
||||
.notNull()
|
||||
.references(() => emails.id, { onDelete: "cascade" }),
|
||||
fromAddress: text("from_address").notNull(),
|
||||
fromAddress: text("from_address"),
|
||||
toAddress: text("to_address"),
|
||||
subject: text("subject").notNull(),
|
||||
content: text("content").notNull(),
|
||||
html: text("html"),
|
||||
type: text("type"),
|
||||
receivedAt: integer("received_at", { mode: "timestamp_ms" })
|
||||
.notNull()
|
||||
.$defaultFn(() => new Date()),
|
||||
sentAt: integer("sent_at", { mode: "timestamp_ms" })
|
||||
.notNull()
|
||||
.$defaultFn(() => new Date()),
|
||||
}, (table) => ({
|
||||
emailIdIdx: index("message_email_id_idx").on(table.emailId),
|
||||
}))
|
||||
@@ -109,6 +114,8 @@ export const apiKeys = sqliteTable('api_keys', {
|
||||
nameUserIdUnique: uniqueIndex('name_user_id_unique').on(table.name, table.userId)
|
||||
}));
|
||||
|
||||
|
||||
|
||||
export const apiKeysRelations = relations(apiKeys, ({ one }) => ({
|
||||
user: one(users, {
|
||||
fields: [apiKeys.userId],
|
||||
|
||||
125
app/lib/send-permissions.ts
Normal file
125
app/lib/send-permissions.ts
Normal file
@@ -0,0 +1,125 @@
|
||||
import { createDb } from "@/lib/db"
|
||||
import { userRoles, roles, messages, emails } from "@/lib/schema"
|
||||
import { eq, and, gte } from "drizzle-orm"
|
||||
import { getRequestContext } from "@cloudflare/next-on-pages"
|
||||
import { EMAIL_CONFIG } from "@/config"
|
||||
|
||||
export interface SendPermissionResult {
|
||||
canSend: boolean
|
||||
error?: string
|
||||
remainingEmails?: number
|
||||
}
|
||||
|
||||
export async function checkSendPermission(
|
||||
userId: string,
|
||||
skipDailyLimitCheck = false
|
||||
): Promise<SendPermissionResult> {
|
||||
try {
|
||||
const env = getRequestContext().env
|
||||
const enabled = await env.SITE_CONFIG.get("EMAIL_SERVICE_ENABLED")
|
||||
|
||||
if (enabled !== "true") {
|
||||
return {
|
||||
canSend: false,
|
||||
error: "邮件发送服务未启用"
|
||||
}
|
||||
}
|
||||
|
||||
const userDailyLimit = await getUserDailyLimit(userId)
|
||||
|
||||
if (userDailyLimit === -1) {
|
||||
return {
|
||||
canSend: false,
|
||||
error: "您的角色没有发件权限"
|
||||
}
|
||||
}
|
||||
|
||||
if (skipDailyLimitCheck || userDailyLimit === 0) {
|
||||
return {
|
||||
canSend: true
|
||||
}
|
||||
}
|
||||
|
||||
const db = createDb()
|
||||
const today = new Date()
|
||||
today.setHours(0, 0, 0, 0)
|
||||
|
||||
const sentToday = await db
|
||||
.select()
|
||||
.from(messages)
|
||||
.innerJoin(emails, eq(messages.emailId, emails.id))
|
||||
.where(
|
||||
and(
|
||||
eq(emails.userId, userId),
|
||||
eq(messages.type, "sent"),
|
||||
gte(messages.receivedAt, today)
|
||||
)
|
||||
)
|
||||
|
||||
const remainingEmails = Math.max(0, userDailyLimit - sentToday.length)
|
||||
|
||||
if (sentToday.length >= userDailyLimit) {
|
||||
return {
|
||||
canSend: false,
|
||||
error: `您今天已达到发件限制 (${userDailyLimit} 封),请明天再试`,
|
||||
remainingEmails: 0
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
canSend: true,
|
||||
remainingEmails
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to check send permission:', error)
|
||||
return {
|
||||
canSend: false,
|
||||
error: "权限检查失败"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function getUserDailyLimit(userId: string): Promise<number> {
|
||||
try {
|
||||
const db = createDb()
|
||||
|
||||
const userRoleData = await db
|
||||
.select({ roleName: roles.name })
|
||||
.from(userRoles)
|
||||
.innerJoin(roles, eq(userRoles.roleId, roles.id))
|
||||
.where(eq(userRoles.userId, userId))
|
||||
|
||||
const userRoleNames = userRoleData.map(r => r.roleName)
|
||||
|
||||
const env = getRequestContext().env
|
||||
const roleLimitsStr = await env.SITE_CONFIG.get("EMAIL_ROLE_LIMITS")
|
||||
|
||||
const customLimits = roleLimitsStr ? JSON.parse(roleLimitsStr) : {}
|
||||
|
||||
const finalLimits = {
|
||||
emperor: EMAIL_CONFIG.DEFAULT_DAILY_SEND_LIMITS.emperor,
|
||||
duke: customLimits.duke !== undefined ? customLimits.duke : EMAIL_CONFIG.DEFAULT_DAILY_SEND_LIMITS.duke,
|
||||
knight: customLimits.knight !== undefined ? customLimits.knight : EMAIL_CONFIG.DEFAULT_DAILY_SEND_LIMITS.knight,
|
||||
civilian: EMAIL_CONFIG.DEFAULT_DAILY_SEND_LIMITS.civilian,
|
||||
}
|
||||
|
||||
if (userRoleNames.includes("emperor")) {
|
||||
return finalLimits.emperor
|
||||
} else if (userRoleNames.includes("duke")) {
|
||||
return finalLimits.duke
|
||||
} else if (userRoleNames.includes("knight")) {
|
||||
return finalLimits.knight
|
||||
} else if (userRoleNames.includes("civilian")) {
|
||||
return finalLimits.civilian
|
||||
}
|
||||
|
||||
return -1
|
||||
} catch (error) {
|
||||
console.error('Failed to get user daily limit:', error)
|
||||
return -1
|
||||
}
|
||||
}
|
||||
|
||||
export async function checkBasicSendPermission(userId: string): Promise<SendPermissionResult> {
|
||||
return checkSendPermission(userId, true)
|
||||
}
|
||||
Reference in New Issue
Block a user