Files
ClassHelper/packages/server/src/modules/courseware/courseware.schemas.ts
T

55 lines
1.8 KiB
TypeScript
Raw Normal View History

import { z } from 'zod';
import { COURSEWARE_MAX_BYTES } from '@classhelper/shared';
export const coursewareScopeSchema = z.object({ classIds: z.array(z.string().min(1).max(100)).max(100) });
const folderPath = z
.string()
.trim()
.min(1)
.max(240)
.refine(
(value) =>
value
.split('/')
.every(
(part) =>
part.length > 0 &&
part.length <= 60 &&
!/[<>:"\\|?*\u0000-\u001f]/.test(part) &&
!/[. ]$/.test(part) &&
!/^(con|prn|aux|nul|com[0-9]|lpt[0-9])(?:\.|$)/i.test(part),
),
'文件夹名称无效,请使用 / 分隔子文件夹',
);
export const coursewareFolderSchema = z.object({ path: folderPath });
export const coursewareMoveSchema = z.object({ folderPath: folderPath.or(z.literal('')) });
export const coursewareUploadSchema = coursewareScopeSchema
.extend({
name: z
.string()
.trim()
.min(1)
.max(180)
.refine(
(name) => !/[<>:"/\\|?*\u0000-\u001f]/.test(name) && !name.endsWith('.') && !name.endsWith(' '),
'文件名含无效字符',
),
size: z.number().int().min(1).max(COURSEWARE_MAX_BYTES),
mode: z.enum(['cloud', 'push']),
folderPath: folderPath.or(z.literal('')).optional(),
})
.refine((input) => input.mode !== 'push' || input.classIds.length > 0, '推送时请选择授课班级');
export const coursewareUploadQuery = z.object({
metadata: z
.string()
.transform((value, ctx): unknown => {
try {
return JSON.parse(value);
} catch {
ctx.addIssue({ code: 'custom', message: '上传信息格式错误' });
return z.NEVER;
}
})
.pipe(coursewareUploadSchema),
});
export const coursewareDeviceQuery = z.object({ deviceKey: z.string().min(1).max(100) });