81 lines
2.2 KiB
TypeScript
81 lines
2.2 KiB
TypeScript
import { BadRequestException, ForbiddenException } from '@nestjs/common';
|
|
import { PrismaClient } from '@prisma/client';
|
|
|
|
type Delegate = {
|
|
findUnique(args: { where: any }): Promise<any>;
|
|
findFirst(args: { where: any }): Promise<any>;
|
|
};
|
|
|
|
export async function findByIdAndUserId<T extends Delegate>(
|
|
delegate: T,
|
|
id: number | bigint,
|
|
userId: number | bigint,
|
|
resourceName: string,
|
|
) {
|
|
const record = await delegate.findUnique({ where: { id } } as any);
|
|
if (!record) {
|
|
throw new BadRequestException(`${resourceName}不存在`);
|
|
}
|
|
if (record.userId !== userId) {
|
|
throw new ForbiddenException(`无权访问该${resourceName}`);
|
|
}
|
|
return record;
|
|
}
|
|
|
|
export function ensureOwnership(
|
|
record: any,
|
|
userId: number | bigint,
|
|
resourceName: string,
|
|
) {
|
|
if (!record) {
|
|
throw new BadRequestException(`${resourceName}不存在`);
|
|
}
|
|
if (record.userId !== userId) {
|
|
throw new ForbiddenException(`无权访问该${resourceName}`);
|
|
}
|
|
return record;
|
|
}
|
|
|
|
export function sanitizeFilename(originalName: string): string {
|
|
const ext = originalName.split('.').pop()?.toLowerCase() || '';
|
|
const safeExt = ext.replace(/[^a-z0-9]/g, '');
|
|
const randomName =
|
|
Date.now().toString(36) + Math.random().toString(36).substring(2, 15);
|
|
return `${randomName}.${safeExt}`;
|
|
}
|
|
|
|
export const ALLOWED_FILE_TYPES = [
|
|
'application/pdf',
|
|
'text/plain',
|
|
'text/markdown',
|
|
'text/csv',
|
|
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
|
'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
|
'image/png',
|
|
'image/jpeg',
|
|
'image/webp',
|
|
];
|
|
|
|
export const MAX_FILE_SIZE = 20 * 1024 * 1024;
|
|
|
|
export function validateFileUpload(
|
|
mimeType: string,
|
|
sizeBytes: number,
|
|
): void {
|
|
if (!ALLOWED_FILE_TYPES.includes(mimeType)) {
|
|
throw new BadRequestException(
|
|
`不支持的文件类型: ${mimeType},仅支持 PDF/Word/Excel/文本/图片`,
|
|
);
|
|
}
|
|
if (sizeBytes > MAX_FILE_SIZE) {
|
|
throw new BadRequestException(
|
|
`文件大小不能超过 ${MAX_FILE_SIZE / 1024 / 1024}MB`,
|
|
);
|
|
}
|
|
}
|
|
|
|
export function maskSecret(secret: string): string {
|
|
if (!secret || secret.length < 8) return '***';
|
|
return secret.slice(0, 4) + '***' + secret.slice(-4);
|
|
}
|