mirror of
https://github.com/linkwarden/linkwarden.git
synced 2026-06-28 14:55:49 +00:00
324 lines
9.3 KiB
TypeScript
324 lines
9.3 KiB
TypeScript
import { ArchivedFormat, TokenExpiry } from "@linkwarden/types/global";
|
|
import {
|
|
AiTaggingMethod,
|
|
LinksRouteTo,
|
|
DashboardSectionType,
|
|
Theme,
|
|
} from "@linkwarden/prisma/client";
|
|
import { number, z } from "zod";
|
|
|
|
// const stringField = z.string({
|
|
// errorMap: (e) => ({
|
|
// message: `Invalid ${e.path}.`,
|
|
// }),
|
|
// });
|
|
|
|
export const ForgotPasswordSchema = z.object({
|
|
email: z.string().email(),
|
|
});
|
|
|
|
export const ResetPasswordSchema = z.object({
|
|
token: z.string(),
|
|
password: z.string().min(8),
|
|
});
|
|
|
|
export const VerifyEmailSchema = z.object({
|
|
token: z.string(),
|
|
});
|
|
|
|
export const PostTokenSchema = z.object({
|
|
name: z.string().max(50),
|
|
expires: z.enum(TokenExpiry),
|
|
});
|
|
|
|
export type PostTokenSchemaType = z.infer<typeof PostTokenSchema>;
|
|
|
|
export const PostUserSchema = () => {
|
|
const emailEnabled =
|
|
process.env.EMAIL_FROM && process.env.EMAIL_SERVER ? true : false;
|
|
|
|
return z.object({
|
|
name: z.string().trim().min(1).max(50).optional(),
|
|
password: z.string().min(8).max(2048).optional(),
|
|
email: emailEnabled
|
|
? z.string().trim().email().toLowerCase()
|
|
: z.string().nullish(),
|
|
username: emailEnabled
|
|
? z.string().optional()
|
|
: z
|
|
.string()
|
|
.trim()
|
|
.toLowerCase()
|
|
.min(3)
|
|
.max(50)
|
|
.regex(/^[a-z0-9_-]{3,50}$/),
|
|
invite: z.boolean().default(false),
|
|
acceptPromotionalEmails: z.boolean().default(false),
|
|
});
|
|
};
|
|
|
|
export const UpdateUserSchema = () => {
|
|
const emailEnabled =
|
|
process.env.EMAIL_FROM && process.env.EMAIL_SERVER ? true : false;
|
|
|
|
return z.object({
|
|
name: z.string().trim().min(1).max(50).optional(),
|
|
email: emailEnabled
|
|
? z.string().trim().email().toLowerCase()
|
|
: z.string().nullish(),
|
|
username: z
|
|
.string()
|
|
.trim()
|
|
.toLowerCase()
|
|
.min(3)
|
|
.max(50)
|
|
.regex(/^[a-z0-9_-]{3,50}$/),
|
|
image: z.string().nullish(),
|
|
password: z.string().min(8).max(2048).optional(),
|
|
newPassword: z.string().min(8).max(2048).optional(),
|
|
oldPassword: z.string().min(8).max(2048).optional(),
|
|
archiveAsScreenshot: z.boolean().optional(),
|
|
archiveAsMonolith: z.boolean().optional(),
|
|
archiveAsPDF: z.boolean().optional(),
|
|
archiveAsReadable: z.boolean().optional(),
|
|
archiveAsWaybackMachine: z.boolean().optional(),
|
|
aiTaggingMethod: z.enum(AiTaggingMethod).optional(),
|
|
aiPredefinedTags: z.array(z.string().max(20).trim()).max(20).optional(),
|
|
aiTagExistingLinks: z.boolean().optional(),
|
|
locale: z.string().max(20).optional(),
|
|
isPrivate: z.boolean().optional(),
|
|
preventDuplicateLinks: z.boolean().optional(),
|
|
collectionOrder: z.array(z.number()).optional(),
|
|
linksRouteTo: z.enum(LinksRouteTo).optional(),
|
|
referredBy: z.string().max(100).nullish(),
|
|
});
|
|
};
|
|
|
|
export const UpdateUserPreferenceSchema = z.object({
|
|
theme: z.enum(Theme).optional(),
|
|
readableFontFamily: z.string().trim().max(100).optional(),
|
|
readableFontSize: z.string().trim().max(100).optional(),
|
|
readableLineHeight: z.string().trim().max(100).optional(),
|
|
readableLineWidth: z.string().trim().max(100).optional(),
|
|
// archiveAsScreenshot: z.boolean().optional(),
|
|
// archiveAsMonolith: z.boolean().optional(),
|
|
// archiveAsPDF: z.boolean().optional(),
|
|
// archiveAsReadable: z.boolean().optional(),
|
|
// archiveAsWaybackMachine: z.boolean().optional(),
|
|
// aiTaggingMethod: z.enum(AiTaggingMethod).optional(),
|
|
// aiPredefinedTags: z.array(z.string().max(20).trim()).max(20).optional(),
|
|
// aiTagExistingLinks: z.boolean().optional(),
|
|
// preventDuplicateLinks: z.boolean().optional(),
|
|
// linksRouteTo: z.enum(LinksRouteTo).optional(),
|
|
});
|
|
|
|
export type UpdateUserPreferenceSchemaType = z.infer<
|
|
typeof UpdateUserPreferenceSchema
|
|
>;
|
|
|
|
export const PostSessionSchema = z.object({
|
|
username: z.string().min(3).max(50),
|
|
password: z.string().min(8),
|
|
sessionName: z.string().trim().max(50).optional(),
|
|
});
|
|
|
|
export const PostLinkSchema = z.object({
|
|
type: z.enum(["url", "pdf", "image"]).nullish(),
|
|
url: z.string().trim().max(2048).url().optional(),
|
|
name: z.string().trim().max(2048).optional(),
|
|
description: z.string().trim().max(2048).optional(),
|
|
image: z.enum(["jpeg", "png"]).optional(),
|
|
collection: z
|
|
.object({
|
|
id: z.number().optional(),
|
|
name: z.string().trim().max(2048).optional(),
|
|
})
|
|
.optional(),
|
|
tags:
|
|
z
|
|
.array(
|
|
z.object({
|
|
id: z.number().optional(),
|
|
name: z.string().trim().max(50),
|
|
})
|
|
)
|
|
.optional() || [],
|
|
});
|
|
|
|
export type PostLinkSchemaType = z.infer<typeof PostLinkSchema>;
|
|
|
|
export const UpdateLinkSchema = z.object({
|
|
id: z.number(),
|
|
name: z.string().trim().max(2048).nullish(),
|
|
url: z.string().trim().max(2048).nullish(),
|
|
description: z.string().trim().max(2048).nullish(),
|
|
icon: z.string().trim().max(50).nullish(),
|
|
iconWeight: z.string().trim().max(50).nullish(),
|
|
color: z.string().trim().max(50).nullish(),
|
|
collection: z.object({
|
|
id: z.number(),
|
|
ownerId: z.number(),
|
|
}),
|
|
tags: z.array(
|
|
z.object({
|
|
id: z.number().optional(),
|
|
name: z.string().trim().max(50),
|
|
})
|
|
),
|
|
pinnedBy: z
|
|
.array(
|
|
z
|
|
.object({
|
|
id: z.number().optional(),
|
|
})
|
|
.optional()
|
|
)
|
|
.optional(),
|
|
});
|
|
|
|
export type UpdateLinkSchemaType = z.infer<typeof UpdateLinkSchema>;
|
|
|
|
const ACCEPTED_TYPES = [
|
|
"image/jpeg",
|
|
"image/jpg",
|
|
"image/png",
|
|
"application/pdf",
|
|
"text/plain",
|
|
"text/html",
|
|
];
|
|
const NEXT_PUBLIC_MAX_FILE_BUFFER = Number(
|
|
process.env.NEXT_PUBLIC_MAX_FILE_BUFFER || 10
|
|
);
|
|
const MAX_FILE_SIZE = NEXT_PUBLIC_MAX_FILE_BUFFER * 1024 * 1024;
|
|
export const UploadFileSchema = z.object({
|
|
file: z
|
|
.any()
|
|
.refine((files) => files?.length == 1, "File is required.")
|
|
.refine(
|
|
(files) => files?.[0]?.size <= MAX_FILE_SIZE,
|
|
`Max file size is ${MAX_FILE_SIZE}MB.`
|
|
)
|
|
.refine(
|
|
(files) => ACCEPTED_TYPES.includes(files?.[0]?.mimetype),
|
|
`Only ${ACCEPTED_TYPES.join(", ")} files are accepted.`
|
|
),
|
|
id: z.number().optional(),
|
|
url: z.string().trim().max(2048).url().optional(),
|
|
format: z.enum(ArchivedFormat),
|
|
});
|
|
|
|
export const PostCollectionSchema = z.object({
|
|
name: z.string().trim().max(2048),
|
|
description: z.string().trim().max(2048).optional(),
|
|
color: z.string().trim().max(50).optional(),
|
|
icon: z.string().trim().max(50).optional(),
|
|
iconWeight: z.string().trim().max(50).optional(),
|
|
parentId: z.number().optional(),
|
|
});
|
|
|
|
export type PostCollectionSchemaType = z.infer<typeof PostCollectionSchema>;
|
|
|
|
export const UpdateCollectionSchema = z.object({
|
|
id: z.number(),
|
|
name: z.string().trim().max(2048),
|
|
description: z.string().trim().max(2048).optional(),
|
|
color: z.string().trim().max(50).optional(),
|
|
isPublic: z.boolean().optional(),
|
|
icon: z.string().trim().max(50).nullish(),
|
|
iconWeight: z.string().trim().max(50).nullish(),
|
|
parentId: z.union([z.number(), z.literal("root")]).nullish(),
|
|
members: z.array(
|
|
z.object({
|
|
userId: z.number(),
|
|
canCreate: z.boolean(),
|
|
canUpdate: z.boolean(),
|
|
canDelete: z.boolean(),
|
|
})
|
|
),
|
|
propagateToSubcollections: z.boolean().optional(),
|
|
});
|
|
|
|
export type UpdateCollectionSchemaType = z.infer<typeof UpdateCollectionSchema>;
|
|
|
|
export const UpdateTagSchema = z.object({
|
|
name: z.string().trim().max(50),
|
|
});
|
|
|
|
export type UpdateTagSchemaType = z.infer<typeof UpdateTagSchema>;
|
|
|
|
export const PostRssSubscriptionSchema = z.object({
|
|
name: z.string().max(50),
|
|
url: z.string().url().max(2048),
|
|
collectionId: z.number().optional(),
|
|
collectionName: z.string().max(50).optional(),
|
|
});
|
|
|
|
export const PostTagSchema = z.object({
|
|
tags: z.array(
|
|
z.object({
|
|
label: z.string().trim().max(50),
|
|
archiveAsScreenshot: z.boolean().nullish(),
|
|
archiveAsMonolith: z.boolean().nullish(),
|
|
archiveAsPDF: z.boolean().nullish(),
|
|
archiveAsReadable: z.boolean().nullish(),
|
|
archiveAsWaybackMachine: z.boolean().nullish(),
|
|
aiTag: z.boolean().nullish(),
|
|
})
|
|
),
|
|
});
|
|
|
|
export type PostTagSchemaType = z.infer<typeof PostTagSchema>;
|
|
|
|
export const TagBulkDeletionSchema = z.object({
|
|
tagIds: z.array(z.number()).min(1),
|
|
});
|
|
|
|
export type TagBulkDeletionSchemaType = z.infer<typeof TagBulkDeletionSchema>;
|
|
|
|
export const MergeTagsSchema = z.object({
|
|
newTagName: z.string().trim().max(50),
|
|
tagIds: z.array(z.number()).min(1),
|
|
});
|
|
|
|
export type MergeTagsSchemaType = z.infer<typeof MergeTagsSchema>;
|
|
|
|
export const PostHighlightSchema = z.object({
|
|
color: z.string().trim().max(50),
|
|
comment: z.string().trim().max(2048).nullish(),
|
|
startOffset: z.number(),
|
|
endOffset: z.number(),
|
|
text: z.string().trim().max(2048),
|
|
linkId: z.number(),
|
|
});
|
|
|
|
export type PostHighlightSchemaType = z.infer<typeof PostHighlightSchema>;
|
|
|
|
export const LinkArchiveActionSchema = z.object({
|
|
linkIds: z.array(z.number()).optional(),
|
|
});
|
|
|
|
export type LinkArchiveActionSchemaType = z.infer<
|
|
typeof LinkArchiveActionSchema
|
|
>;
|
|
|
|
export const DeletePreservationsSchema = z.object({
|
|
action: z.enum(["allAndRePreserve", "allBroken"]),
|
|
});
|
|
|
|
export type DeletePreservationsSchemaType = z.infer<
|
|
typeof DeletePreservationsSchema
|
|
>;
|
|
|
|
export const UpdateDashboardLayoutSchema = z.array(
|
|
z.object({
|
|
type: z.enum(DashboardSectionType),
|
|
collectionId: z.number().optional(),
|
|
enabled: z.boolean(),
|
|
order: z.number().optional(),
|
|
})
|
|
);
|
|
|
|
export type UpdateDashboardLayoutSchemaType = z.infer<
|
|
typeof UpdateDashboardLayoutSchema
|
|
>;
|