Files
wr.do/lib/dto/files.ts

398 lines
9.3 KiB
TypeScript

import { Prisma, UserFile } from "@prisma/client";
import { prisma } from "../db";
import { bytesToStorageValue, storageValueToBytes } from "../utils";
export interface UserFileData extends UserFile {
user: {
name: string;
email: string;
};
}
export interface CreateUserFileInput {
userId: string;
name: string;
originalName?: string;
mimeType: string;
size: number;
path: string;
etag?: string;
storageClass?: string;
channel: string;
platform: string;
providerName: string;
bucket: string;
shortUrlId?: string;
lastModified: Date;
}
export interface UpdateUserFileInput {
name?: string;
originalName?: string;
mimeType?: string;
size?: number;
path?: string;
etag?: string;
storageClass?: string;
channel?: string;
platform?: string;
providerName?: string;
bucket?: string;
shortUrlId?: string;
status?: number;
lastModified?: Date;
}
export interface QueryUserFileOptions {
bucket?: string;
userId?: string;
providerName?: string;
status?: number;
channel?: string;
platform?: string;
shortUrlId?: string;
name?: string;
size?: number;
mimeType?: string;
page?: number;
limit?: number;
orderBy?: "createdAt" | "lastModified" | "size";
order?: "asc" | "desc";
}
// 创建文件记录
export async function createUserFile(data: CreateUserFileInput) {
try {
const userFile = await prisma.userFile.create({
data: {
...data,
updatedAt: new Date(),
},
include: {
user: {
select: {
name: true,
email: true,
},
},
},
});
return { success: true, data: userFile };
} catch (error) {
console.error("Failed to create file record:", error);
return { success: false, error: "Failed to create file record" };
}
}
// 根据ID查询文件记录
export async function getUserFileById(id: string) {
try {
const userFile = await prisma.userFile.findUnique({
where: { id },
include: {
user: {
select: {
name: true,
email: true,
},
},
},
});
return { success: true, data: userFile };
} catch (error) {
console.error("Failed to query file record:", error);
return { success: false, error: "Failed to query file record" };
}
}
// 条件查询文件记录
export async function getUserFiles(options: QueryUserFileOptions = {}) {
try {
const {
bucket,
userId,
providerName,
status,
channel,
platform,
shortUrlId,
name,
size,
mimeType,
page = 1,
limit = 20,
orderBy = "createdAt",
order = "desc",
} = options;
const where: Prisma.UserFileWhereInput = {
bucket,
...(status !== undefined && { status }),
...(userId && { userId }),
...(providerName && { providerName }),
...(channel && { channel }),
...(platform && { platform }),
...(shortUrlId && { shortUrlId }),
...(name && { name: { contains: name, mode: "insensitive" } }),
...(size && { size: { gte: bytesToStorageValue(size) } }),
...(mimeType && {
mimeType: { contains: mimeType, mode: "insensitive" },
}),
};
const [files, total, totalSize] = await Promise.all([
prisma.userFile.findMany({
where,
include: {
user: {
select: {
name: true,
email: true,
},
},
},
orderBy: { [orderBy]: order },
skip: (page - 1) * limit,
take: limit,
}),
prisma.userFile.count({ where }),
prisma.userFile.aggregate({
where: {
// bucket,
// providerName,
status: 1,
...(userId && { userId }),
},
_sum: { size: true },
}),
]);
return {
total,
totalSize: storageValueToBytes(totalSize._sum.size || 0),
list: files,
};
} catch (error) {
console.error("[GetUserFiles Error]", error);
return { success: false, error: "[GetUserFiles Error]" };
}
}
// 更新文件记录
export async function updateUserFile(id: string, data: UpdateUserFileInput) {
try {
const userFile = await prisma.userFile.update({
where: { id },
data: {
...data,
updatedAt: new Date(),
},
include: {
user: {
select: {
name: true,
email: true,
},
},
},
});
return { success: true, data: userFile };
} catch (error) {
console.error("Failed to update file record:", error);
return { success: false, error: "Failed to update file record" };
}
}
// 软删除文件记录
export async function softDeleteUserFile(id: string) {
try {
const userFile = await prisma.userFile.update({
where: { id },
data: {
status: 0,
updatedAt: new Date(),
},
});
return { success: true, data: userFile };
} catch (error) {
console.error("Delete file record failed:", error);
return { success: false, error: "Delete file record failed" };
}
}
// 批量软删除
export async function softDeleteUserFiles(ids: string[]) {
try {
const result = await prisma.userFile.updateMany({
where: {
id: { in: ids },
},
data: {
status: 0,
updatedAt: new Date(),
},
});
return { success: true, data: result };
} catch (error) {
console.error("Delete file records failed:", error);
return { success: false, error: "Delete file records failed" };
}
}
// 物理删除文件记录
export async function deleteUserFile(id: string) {
try {
const userFile = await prisma.userFile.delete({
where: { id },
});
return { success: true, data: userFile };
} catch (error) {
console.error("Delete file record failed:", error);
return { success: false, error: "Delete file record failed" };
}
}
// 获取用户文件统计
export async function getUserFileStats(userId: string) {
try {
const [totalFiles, totalSize, filesByProvider] = await Promise.all([
prisma.userFile.count({
where: { userId, status: 1 },
}),
prisma.userFile.aggregate({
where: { userId, status: 1 },
_sum: { size: true },
}),
prisma.userFile.groupBy({
by: ["providerName"],
where: { userId, status: 1 },
_count: { id: true },
_sum: { size: true },
}),
]);
return {
success: true,
data: {
totalFiles,
totalSize: storageValueToBytes(totalSize._sum.size || 0),
filesByProvider,
},
};
} catch (error) {
console.error("Failed to get file statistics:", error);
return { success: false, error: "Failed to get file statistics" };
}
}
// 根据路径查找文件
export async function getUserFileByPath(path: string, providerName?: string) {
try {
const where: Prisma.UserFileWhereInput = {
path,
status: 1,
...(providerName && { providerName }),
};
const userFile = await prisma.userFile.findFirst({
where,
include: {
user: {
select: {
name: true,
email: true,
},
},
},
});
return { success: true, data: userFile };
} catch (error) {
console.error("Failed to query file record:", error);
return { success: false, error: "Failed to query file record" };
}
}
// 根据短链接ID查询文件
export async function getUserFileByShortUrlId(shortUrlId: string) {
try {
const userFile = await prisma.userFile.findFirst({
where: {
shortUrlId,
status: 1,
},
include: {
user: {
select: {
name: true,
email: true,
},
},
},
});
return { success: true, data: userFile };
} catch (error) {
console.error("Failed to query file record:", error);
return { success: false, error: "Failed to query file record" };
}
}
// 清理过期文件记录
export async function cleanupExpiredFiles(days: number = 30) {
try {
const expiredDate = new Date();
expiredDate.setDate(expiredDate.getDate() - days);
const result = await prisma.userFile.deleteMany({
where: {
status: 0,
updatedAt: {
lt: expiredDate,
},
},
});
return { success: true, data: result };
} catch (error) {
console.error("Failed to clean up expired files:", error);
return { success: false, error: "Failed to clean up expired files" };
}
}
// 获取特定存储桶的使用量统计
export async function getBucketStorageUsage(
bucket: string,
providerName: string,
): Promise<
| { success: true; data: { totalSize: number; totalFiles: number } }
| { success: false; error: string }
> {
try {
const result = await prisma.userFile.aggregate({
where: {
bucket,
providerName,
status: 1,
},
_sum: {
size: true,
},
_count: {
id: true,
},
});
return {
success: true,
data: {
totalSize: storageValueToBytes(result._sum.size || 0),
totalFiles: result._count.id || 0,
},
};
} catch (error) {
console.error("Failed to get bucket storage usage:", error);
return { success: false, error: "Failed to get bucket storage usage" };
}
}