Files
2025-06-08 14:54:28 +08:00

547 lines
12 KiB
TypeScript

import { ForwardEmail, UserEmail, UserRole } from "@prisma/client";
import { prisma } from "@/lib/db";
export type EmailAddress = {
name: string;
address?: string;
group?: EmailAddress[];
};
export type EmailHeader = Record<string, string>;
export interface OriginalEmail {
from: string;
fromName: string;
to: string;
cc?: string;
subject?: string;
text?: string;
html?: string;
date?: string;
messageId?: string;
replyTo?: string;
headers?: string;
attachments?: {
filename: string;
mimeType: string;
r2Path: string;
size: number;
}[];
}
export interface UserEmailList extends UserEmail {
count: number;
unreadCount: number;
user: string;
email: string;
}
export async function saveForwardEmail(emailData: OriginalEmail) {
const user_email = await prisma.userEmail.findFirst({
where: {
emailAddress: emailData.to,
},
});
if (!user_email) return null;
const res = await prisma.forwardEmail.create({
data: {
from: emailData.from,
fromName: emailData.fromName,
to: emailData.to,
subject: emailData.subject,
text: emailData.text,
html: emailData.html,
date: emailData.date,
messageId: emailData.messageId,
replyTo: emailData.replyTo,
cc: emailData.cc,
headers: "[]",
attachments: JSON.stringify(emailData.attachments),
readAt: null,
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
},
});
if (!res) {
return null;
}
return res.id;
}
// 查询所有 UserEmail
export async function getAllUserEmails(
userId: string,
page: number,
size: number,
search: string,
admin: boolean,
onlyUnread: boolean = false,
) {
let whereOptions: any = {};
if (admin) {
whereOptions = {
emailAddress: { contains: search, mode: "insensitive" },
};
} else {
whereOptions = {
userId,
deletedAt: null,
emailAddress: { contains: search, mode: "insensitive" },
};
}
if (onlyUnread) {
whereOptions.forwardEmails = {
some: {
readAt: null,
},
};
}
// Fetch paginated UserEmail records
const userEmailsPromise = prisma.userEmail.findMany({
where: whereOptions,
select: {
id: true,
userId: true,
emailAddress: true,
createdAt: true,
updatedAt: true,
deletedAt: true,
_count: { select: { forwardEmails: true } },
user: { select: { name: true, email: true } },
forwardEmails: {
select: {
readAt: true,
},
},
},
skip: (page - 1) * size,
take: size,
orderBy: {
updatedAt: "desc",
},
});
const totalPromise = prisma.userEmail.count({
where: whereOptions,
});
const emailAddressesPromise = prisma.userEmail.findMany({
where: whereOptions,
select: { emailAddress: true },
});
const [userEmails, total, emailAddresses] = await Promise.all([
userEmailsPromise,
totalPromise,
emailAddressesPromise,
]);
const emailAddressList = emailAddresses.map((e) => e.emailAddress);
const [totalInboxCount, totalUnreadCount] = await Promise.all([
prisma.forwardEmail.count({
where: {
to: { in: emailAddressList },
},
}),
prisma.forwardEmail.count({
where: {
to: { in: emailAddressList },
readAt: null,
},
}),
]);
const result = userEmails.map((email) => {
const unreadCount = email.forwardEmails.filter(
(mail) => mail.readAt === null,
).length;
return {
...email,
count: email._count.forwardEmails,
unreadCount,
user: email.user.name,
email: email.user.email,
forwardEmails: undefined,
};
});
return {
list: result,
total,
totalInboxCount,
totalUnreadCount,
};
}
// 查询所有 UserEmail 数量
export async function getAllUserEmailsCount(
userId: string,
role: UserRole = "USER",
) {
const now = new Date();
const start = new Date(now.getFullYear(), now.getMonth(), 1);
const end = new Date(
now.getFullYear(),
now.getMonth() + 1,
0,
23,
59,
59,
999,
);
const [total, month_total] = await prisma.$transaction([
prisma.userEmail.count({
where:
role === "USER" ? { userId, deletedAt: null } : { deletedAt: null },
}),
prisma.userEmail.count({
where:
role === "USER"
? { userId, createdAt: { gte: start, lte: end }, deletedAt: null }
: { createdAt: { gte: start, lte: end }, deletedAt: null },
}),
]);
return { total, month_total };
}
// 查询所有 inbox 数量
export async function getAllUserInboxEmailsCount() {
const now = new Date();
const start = new Date(now.getFullYear(), now.getMonth(), 1);
const end = new Date(
now.getFullYear(),
now.getMonth() + 1,
0,
23,
59,
59,
999,
);
const [total, month_total] = await prisma.$transaction([
prisma.forwardEmail.count(),
prisma.forwardEmail.count({
where: { createdAt: { gte: start, lte: end } },
}),
]);
return { total, month_total };
}
// 创建 UserEmail
export async function createUserEmail(
userId: string,
emailAddress: string,
): Promise<UserEmail> {
const user = await prisma.user.findUnique({ where: { id: userId } });
if (!user) {
throw new Error("Invalid userId");
}
return prisma.userEmail.create({
data: {
userId,
emailAddress,
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
deletedAt: null,
},
});
}
// 查询单个 UserEmail
export async function getUserEmailById(id: string): Promise<UserEmail | null> {
return prisma.userEmail.findUnique({
where: { id, deletedAt: null },
});
}
// 更新 UserEmail
export async function updateUserEmail(
id: string,
emailAddress: string,
): Promise<UserEmail> {
return prisma.userEmail.update({
where: { id, deletedAt: null },
data: { emailAddress, updatedAt: new Date().toISOString() },
});
}
// 删除 UserEmail (软删除)
export async function deleteUserEmail(id: string) {
const userEmail = await prisma.userEmail.findFirst({
where: { id, deletedAt: null },
});
if (userEmail) {
await prisma.userEmail.update({
where: { id },
data: { deletedAt: new Date() }, // 设置删除时间
});
}
}
// 删除 UserEmail (软删除)
export async function deleteUserEmailByAddress(email: string) {
const userEmail = await prisma.userEmail.findFirst({
where: { emailAddress: email, deletedAt: null },
});
if (userEmail) {
await prisma.userEmail.update({
where: { emailAddress: email },
data: { deletedAt: new Date() },
});
} else {
throw new Error("User email not found or already deleted");
}
}
// 通过 emailAddress 查询邮件列表
export async function getEmailsByEmailAddress(
emailAddress: string,
page: number,
pageSize: number,
): Promise<{ list: ForwardEmail[]; total: number }> {
const userEmail = await prisma.userEmail.findUnique({
where: { emailAddress, deletedAt: null },
});
if (!userEmail) {
throw new Error("Email address not found");
}
const list = await prisma.forwardEmail.findMany({
where: { to: emailAddress },
orderBy: { createdAt: "desc" },
skip: (page - 1) * pageSize, // 从第 (page-1)*pageSize 条开始
take: pageSize, // 取 pageSize 条
});
const total = await prisma.forwardEmail.count({
where: { to: emailAddress },
});
return {
list,
total,
};
}
/**
* 将邮件标记为已读
* @param emailId 需要标记为已读的邮件ID
* @param userId 当前用户ID (用于权限验证)
* @returns 更新后的邮件信息
*/
export async function markEmailAsRead(emailId: string, userId: string) {
try {
// 首先查询邮件是否存在,并检查权限
const email = await prisma.forwardEmail.findFirst({
where: {
id: emailId,
UserEmail: {
userId,
},
readAt: null,
},
include: {
UserEmail: true,
},
});
if (!email) {
throw new Error(
"There are no valid emails to mark as read or you do not have permission",
);
}
// 更新邮件的 readAt 字段为当前时间
const updatedEmail = await prisma.forwardEmail.update({
where: {
id: emailId,
},
data: {
readAt: new Date(),
},
});
return updatedEmail;
} catch (error) {
console.error("标记邮件为已读失败:", error);
throw error;
}
}
/**
* 批量将邮件标记为已读
* @param emailIds 需要标记为已读的邮件ID数组
* @param userId 当前用户ID (用于权限验证)
* @returns 更新的邮件数量
*/
export async function markEmailsAsRead(emailIds: string[], userId: string) {
try {
// 验证所有邮件是否属于该用户
const emails = await prisma.forwardEmail.findMany({
where: {
id: { in: emailIds },
UserEmail: {
userId: userId,
},
},
});
// 获取有效的邮件IDs (用户有权限的)
const validEmailIds = emails.map((email) => email.id);
if (validEmailIds.length === 0) {
throw new Error(
"There are no valid emails to mark as read or you do not have permission",
);
}
// 批量更新邮件的 readAt 字段
const updateResult = await prisma.forwardEmail.updateMany({
where: {
id: { in: validEmailIds },
},
data: {
readAt: new Date(),
},
});
return {
updatedCount: updateResult.count,
message: `Successfully marked ${updateResult.count} emails as read`,
};
} catch (error) {
console.error("批量标记邮件为已读失败:", error);
throw error;
}
}
/**
* 将指定用户邮箱的所有邮件标记为已读
* @param userEmailId 用户邮箱ID
* @param userId 当前用户ID (用于权限验证)
* @returns 更新的邮件数量
*/
export async function markAllEmailsAsRead(userEmailId: string, userId: string) {
try {
// 验证用户邮箱是否属于该用户
const userEmail = await prisma.userEmail.findFirst({
where: {
id: userEmailId,
userId: userId,
},
});
if (!userEmail) {
throw new Error(
"There are no valid emails or you do not have permission",
);
}
// 更新该邮箱下所有未读邮件
const updateResult = await prisma.forwardEmail.updateMany({
where: {
to: userEmail.emailAddress,
readAt: null,
},
data: {
readAt: new Date(),
},
});
return {
updatedCount: updateResult.count,
message: `Successfully marked ${updateResult.count} emails as read`,
};
} catch (error) {
console.error("标记所有邮件为已读失败:", error);
throw error;
}
}
// 删除邮件
export async function deleteEmailsByIds(ids: string[]) {
return prisma.forwardEmail.deleteMany({
where: { id: { in: ids } },
});
}
export async function saveUserSendEmail(
userId: string,
from: string,
to: string,
subject: string,
html: string,
) {
return prisma.userSendEmail.create({
data: {
userId,
from,
to,
subject,
html,
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
},
});
}
export async function getUserSendEmailCount(userId: string, admin: boolean) {
if (admin) {
return prisma.userSendEmail.count();
}
return prisma.userSendEmail.count({ where: { userId } });
}
export async function getUserSendEmailList(
userId: string,
admin: boolean,
page: number,
size: number,
search: string,
) {
const select = {
from: true,
to: true,
subject: true,
html: true,
createdAt: true,
};
let where: any = {};
if (admin) {
where = {
to: { contains: search, mode: "insensitive" },
};
} else {
where = {
userId,
to: { contains: search, mode: "insensitive" },
};
}
const listPromise = prisma.userSendEmail.findMany({
where,
select,
skip: (page - 1) * size,
take: size,
orderBy: {
updatedAt: "desc",
},
});
const totalPromise = prisma.userSendEmail.count({
where,
});
const [list, total] = await Promise.all([listPromise, totalPromise]);
return { list, total };
}