add schema validation for PUT requests
This commit is contained in:
parent
1cf7421b76
commit
ff6e71d494
|
@ -1,15 +1,32 @@
|
||||||
import { prisma } from "@/lib/api/db";
|
import { prisma } from "@/lib/api/db";
|
||||||
import { CollectionIncludingMembersAndLinkCount } from "@/types/global";
|
import { CollectionIncludingMembersAndLinkCount } from "@/types/global";
|
||||||
import getPermission from "@/lib/api/getPermission";
|
import getPermission from "@/lib/api/getPermission";
|
||||||
|
import {
|
||||||
|
UpdateCollectionSchema,
|
||||||
|
UpdateCollectionSchemaType,
|
||||||
|
} from "@/lib/shared/schemaValidation";
|
||||||
|
|
||||||
export default async function updateCollection(
|
export default async function updateCollection(
|
||||||
userId: number,
|
userId: number,
|
||||||
collectionId: number,
|
collectionId: number,
|
||||||
data: CollectionIncludingMembersAndLinkCount
|
body: UpdateCollectionSchemaType
|
||||||
) {
|
) {
|
||||||
if (!collectionId)
|
if (!collectionId)
|
||||||
return { response: "Please choose a valid collection.", status: 401 };
|
return { response: "Please choose a valid collection.", status: 401 };
|
||||||
|
|
||||||
|
const dataValidation = UpdateCollectionSchema.safeParse(body);
|
||||||
|
|
||||||
|
if (!dataValidation.success) {
|
||||||
|
return {
|
||||||
|
response: `Error: ${
|
||||||
|
dataValidation.error.issues[0].message
|
||||||
|
} [${dataValidation.error.issues[0].path.join(", ")}]`,
|
||||||
|
status: 400,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = dataValidation.data;
|
||||||
|
|
||||||
const collectionIsAccessible = await getPermission({
|
const collectionIsAccessible = await getPermission({
|
||||||
userId,
|
userId,
|
||||||
collectionId,
|
collectionId,
|
||||||
|
@ -76,7 +93,7 @@ export default async function updateCollection(
|
||||||
: undefined,
|
: undefined,
|
||||||
members: {
|
members: {
|
||||||
create: data.members.map((e) => ({
|
create: data.members.map((e) => ({
|
||||||
user: { connect: { id: e.user.id || e.userId } },
|
user: { connect: { id: e.userId } },
|
||||||
canCreate: e.canCreate,
|
canCreate: e.canCreate,
|
||||||
canUpdate: e.canUpdate,
|
canUpdate: e.canUpdate,
|
||||||
canDelete: e.canDelete,
|
canDelete: e.canDelete,
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
import { LinkIncludingShortenedCollectionAndTags } from "@/types/global";
|
import { LinkIncludingShortenedCollectionAndTags } from "@/types/global";
|
||||||
import updateLinkById from "../linkId/updateLinkById";
|
import updateLinkById from "../linkId/updateLinkById";
|
||||||
|
import { UpdateLinkSchemaType } from "@/lib/shared/schemaValidation";
|
||||||
|
|
||||||
export default async function updateLinks(
|
export default async function updateLinks(
|
||||||
userId: number,
|
userId: number,
|
||||||
links: LinkIncludingShortenedCollectionAndTags[],
|
links: UpdateLinkSchemaType[],
|
||||||
removePreviousTags: boolean,
|
removePreviousTags: boolean,
|
||||||
newData: Pick<
|
newData: Pick<
|
||||||
LinkIncludingShortenedCollectionAndTags,
|
LinkIncludingShortenedCollectionAndTags,
|
||||||
|
@ -22,7 +23,7 @@ export default async function updateLinks(
|
||||||
updatedTags = [...(newData.tags ?? [])];
|
updatedTags = [...(newData.tags ?? [])];
|
||||||
}
|
}
|
||||||
|
|
||||||
const updatedData: LinkIncludingShortenedCollectionAndTags = {
|
const updatedData: UpdateLinkSchemaType = {
|
||||||
...link,
|
...link,
|
||||||
tags: updatedTags,
|
tags: updatedTags,
|
||||||
collection: {
|
collection: {
|
||||||
|
|
|
@ -1,20 +1,30 @@
|
||||||
import { prisma } from "@/lib/api/db";
|
import { prisma } from "@/lib/api/db";
|
||||||
import { LinkIncludingShortenedCollectionAndTags } from "@/types/global";
|
|
||||||
import { UsersAndCollections } from "@prisma/client";
|
import { UsersAndCollections } from "@prisma/client";
|
||||||
import getPermission from "@/lib/api/getPermission";
|
import getPermission from "@/lib/api/getPermission";
|
||||||
import { moveFiles, removeFiles } from "@/lib/api/manageLinkFiles";
|
import { moveFiles, removeFiles } from "@/lib/api/manageLinkFiles";
|
||||||
import isValidUrl from "@/lib/shared/isValidUrl";
|
import isValidUrl from "@/lib/shared/isValidUrl";
|
||||||
|
import {
|
||||||
|
UpdateLinkSchema,
|
||||||
|
UpdateLinkSchemaType,
|
||||||
|
} from "@/lib/shared/schemaValidation";
|
||||||
|
|
||||||
export default async function updateLinkById(
|
export default async function updateLinkById(
|
||||||
userId: number,
|
userId: number,
|
||||||
linkId: number,
|
linkId: number,
|
||||||
data: LinkIncludingShortenedCollectionAndTags
|
body: UpdateLinkSchemaType
|
||||||
) {
|
) {
|
||||||
if (!data || !data.collection.id)
|
const dataValidation = UpdateLinkSchema.safeParse(body);
|
||||||
|
|
||||||
|
if (!dataValidation.success) {
|
||||||
return {
|
return {
|
||||||
response: "Please choose a valid link and collection.",
|
response: `Error: ${
|
||||||
status: 401,
|
dataValidation.error.issues[0].message
|
||||||
|
} [${dataValidation.error.issues[0].path.join(", ")}]`,
|
||||||
|
status: 400,
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = dataValidation.data;
|
||||||
|
|
||||||
const collectionIsAccessible = await getPermission({ userId, linkId });
|
const collectionIsAccessible = await getPermission({ userId, linkId });
|
||||||
|
|
||||||
|
@ -33,10 +43,11 @@ export default async function updateLinkById(
|
||||||
id: linkId,
|
id: linkId,
|
||||||
},
|
},
|
||||||
data: {
|
data: {
|
||||||
pinnedBy:
|
pinnedBy: data?.pinnedBy
|
||||||
data?.pinnedBy && data.pinnedBy[0].id === userId
|
? data.pinnedBy[0]?.id === userId
|
||||||
? { connect: { id: userId } }
|
? { connect: { id: userId } }
|
||||||
: { disconnect: { id: userId } },
|
: { disconnect: { id: userId } }
|
||||||
|
: undefined,
|
||||||
},
|
},
|
||||||
include: {
|
include: {
|
||||||
collection: true,
|
collection: true,
|
||||||
|
@ -63,8 +74,6 @@ export default async function updateLinkById(
|
||||||
|
|
||||||
const targetCollectionMatchesData = data.collection.id
|
const targetCollectionMatchesData = data.collection.id
|
||||||
? data.collection.id === targetCollectionIsAccessible?.id
|
? data.collection.id === targetCollectionIsAccessible?.id
|
||||||
: true && data.collection.name
|
|
||||||
? data.collection.name === targetCollectionIsAccessible?.name
|
|
||||||
: true && data.collection.ownerId
|
: true && data.collection.ownerId
|
||||||
? data.collection.ownerId === targetCollectionIsAccessible?.ownerId
|
? data.collection.ownerId === targetCollectionIsAccessible?.ownerId
|
||||||
: true;
|
: true;
|
||||||
|
@ -149,10 +158,11 @@ export default async function updateLinkById(
|
||||||
},
|
},
|
||||||
})),
|
})),
|
||||||
},
|
},
|
||||||
pinnedBy:
|
pinnedBy: data?.pinnedBy
|
||||||
data?.pinnedBy && data.pinnedBy[0]?.id === userId
|
? data.pinnedBy[0]?.id === userId
|
||||||
? { connect: { id: userId } }
|
? { connect: { id: userId } }
|
||||||
: { disconnect: { id: userId } },
|
: { disconnect: { id: userId } }
|
||||||
|
: undefined,
|
||||||
},
|
},
|
||||||
include: {
|
include: {
|
||||||
tags: true,
|
tags: true,
|
||||||
|
|
|
@ -1,18 +1,31 @@
|
||||||
import { prisma } from "@/lib/api/db";
|
import { prisma } from "@/lib/api/db";
|
||||||
import { Tag } from "@prisma/client";
|
import {
|
||||||
|
UpdateTagSchema,
|
||||||
|
UpdateTagSchemaType,
|
||||||
|
} from "@/lib/shared/schemaValidation";
|
||||||
|
|
||||||
export default async function updeteTagById(
|
export default async function updeteTagById(
|
||||||
userId: number,
|
userId: number,
|
||||||
tagId: number,
|
tagId: number,
|
||||||
data: Tag
|
body: UpdateTagSchemaType
|
||||||
) {
|
) {
|
||||||
if (!tagId || !data.name)
|
const dataValidation = UpdateTagSchema.safeParse(body);
|
||||||
return { response: "Please choose a valid name for the tag.", status: 401 };
|
|
||||||
|
if (!dataValidation.success) {
|
||||||
|
return {
|
||||||
|
response: `Error: ${
|
||||||
|
dataValidation.error.issues[0].message
|
||||||
|
} [${dataValidation.error.issues[0].path.join(", ")}]`,
|
||||||
|
status: 400,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const { name } = dataValidation.data;
|
||||||
|
|
||||||
const tagNameIsTaken = await prisma.tag.findFirst({
|
const tagNameIsTaken = await prisma.tag.findFirst({
|
||||||
where: {
|
where: {
|
||||||
ownerId: userId,
|
ownerId: userId,
|
||||||
name: data.name,
|
name: name,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -39,7 +52,7 @@ export default async function updeteTagById(
|
||||||
id: tagId,
|
id: tagId,
|
||||||
},
|
},
|
||||||
data: {
|
data: {
|
||||||
name: data.name,
|
name: name,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -6,42 +6,27 @@ import createFile from "@/lib/api/storage/createFile";
|
||||||
import createFolder from "@/lib/api/storage/createFolder";
|
import createFolder from "@/lib/api/storage/createFolder";
|
||||||
import sendChangeEmailVerificationRequest from "@/lib/api/sendChangeEmailVerificationRequest";
|
import sendChangeEmailVerificationRequest from "@/lib/api/sendChangeEmailVerificationRequest";
|
||||||
import { i18n } from "next-i18next.config";
|
import { i18n } from "next-i18next.config";
|
||||||
|
import { UpdateUserSchema } from "@/lib/shared/schemaValidation";
|
||||||
|
|
||||||
const emailEnabled =
|
const emailEnabled =
|
||||||
process.env.EMAIL_FROM && process.env.EMAIL_SERVER ? true : false;
|
process.env.EMAIL_FROM && process.env.EMAIL_SERVER ? true : false;
|
||||||
|
|
||||||
export default async function updateUserById(
|
export default async function updateUserById(
|
||||||
userId: number,
|
userId: number,
|
||||||
data: AccountSettings
|
body: AccountSettings
|
||||||
) {
|
) {
|
||||||
if (emailEnabled && !data.email)
|
const dataValidation = UpdateUserSchema().safeParse(body);
|
||||||
return {
|
|
||||||
response: "Email invalid.",
|
|
||||||
status: 400,
|
|
||||||
};
|
|
||||||
else if (!data.username)
|
|
||||||
return {
|
|
||||||
response: "Username invalid.",
|
|
||||||
status: 400,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Check email (if enabled)
|
if (!dataValidation.success) {
|
||||||
const checkEmail =
|
|
||||||
/^(([^<>()[\]\.,;:\s@\"]+(\.[^<>()[\]\.,;:\s@\"]+)*)|(\".+\"))@(([^<>()[\]\.,;:\s@\"]+\.)+[^<>()[\]\.,;:\s@\"]{2,})$/i;
|
|
||||||
if (emailEnabled && !checkEmail.test(data.email?.toLowerCase() || ""))
|
|
||||||
return {
|
return {
|
||||||
response: "Please enter a valid email.",
|
response: `Error: ${
|
||||||
|
dataValidation.error.issues[0].message
|
||||||
|
} [${dataValidation.error.issues[0].path.join(", ")}]`,
|
||||||
status: 400,
|
status: 400,
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
const checkUsername = RegExp("^[a-z0-9_-]{3,31}$");
|
const data = dataValidation.data;
|
||||||
|
|
||||||
if (!checkUsername.test(data.username.toLowerCase()))
|
|
||||||
return {
|
|
||||||
response:
|
|
||||||
"Username has to be between 3-30 characters, no spaces and special characters are allowed.",
|
|
||||||
status: 400,
|
|
||||||
};
|
|
||||||
|
|
||||||
const userIsTaken = await prisma.user.findFirst({
|
const userIsTaken = await prisma.user.findFirst({
|
||||||
where: {
|
where: {
|
||||||
|
@ -116,7 +101,7 @@ export default async function updateUserById(
|
||||||
|
|
||||||
const user = await prisma.user.findUnique({
|
const user = await prisma.user.findUnique({
|
||||||
where: { id: userId },
|
where: { id: userId },
|
||||||
select: { email: true, password: true },
|
select: { email: true, password: true, name: true },
|
||||||
});
|
});
|
||||||
|
|
||||||
if (user && user.email && data.email && data.email !== user.email) {
|
if (user && user.email && data.email && data.email !== user.email) {
|
||||||
|
@ -148,7 +133,7 @@ export default async function updateUserById(
|
||||||
sendChangeEmailVerificationRequest(
|
sendChangeEmailVerificationRequest(
|
||||||
user.email,
|
user.email,
|
||||||
data.email,
|
data.email,
|
||||||
data.name.trim()
|
data.name?.trim() || user.name
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -193,8 +178,8 @@ export default async function updateUserById(
|
||||||
id: userId,
|
id: userId,
|
||||||
},
|
},
|
||||||
data: {
|
data: {
|
||||||
name: data.name.trim(),
|
name: data.name,
|
||||||
username: data.username?.toLowerCase().trim(),
|
username: data.username,
|
||||||
isPrivate: data.isPrivate,
|
isPrivate: data.isPrivate,
|
||||||
image:
|
image:
|
||||||
data.image && data.image.startsWith("http")
|
data.image && data.image.startsWith("http")
|
||||||
|
@ -202,10 +187,10 @@ export default async function updateUserById(
|
||||||
: data.image
|
: data.image
|
||||||
? `uploads/avatar/${userId}.jpg`
|
? `uploads/avatar/${userId}.jpg`
|
||||||
: "",
|
: "",
|
||||||
collectionOrder: data.collectionOrder.filter(
|
collectionOrder: data.collectionOrder?.filter(
|
||||||
(value, index, self) => self.indexOf(value) === index
|
(value, index, self) => self.indexOf(value) === index
|
||||||
),
|
),
|
||||||
locale: i18n.locales.includes(data.locale) ? data.locale : "en",
|
locale: i18n.locales.includes(data.locale || "") ? data.locale : "en",
|
||||||
archiveAsScreenshot: data.archiveAsScreenshot,
|
archiveAsScreenshot: data.archiveAsScreenshot,
|
||||||
archiveAsMonolith: data.archiveAsMonolith,
|
archiveAsMonolith: data.archiveAsMonolith,
|
||||||
archiveAsPDF: data.archiveAsPDF,
|
archiveAsPDF: data.archiveAsPDF,
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import { ArchivedFormat, TokenExpiry } from "@/types/global";
|
import { ArchivedFormat, TokenExpiry } from "@/types/global";
|
||||||
|
import { LinksRouteTo } from "@prisma/client";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
// const stringField = z.string({
|
// const stringField = z.string({
|
||||||
|
@ -33,19 +34,53 @@ export const PostUserSchema = () => {
|
||||||
|
|
||||||
return z.object({
|
return z.object({
|
||||||
name: z.string().trim().min(1).max(50),
|
name: z.string().trim().min(1).max(50),
|
||||||
password: z.string().min(8),
|
password: z.string().min(8).max(2048),
|
||||||
email: emailEnabled
|
email: emailEnabled
|
||||||
? z.string().trim().email().toLowerCase()
|
? z.string().trim().email().toLowerCase()
|
||||||
: z.string().optional(),
|
: z.string().optional(),
|
||||||
username: z
|
username: z
|
||||||
.string()
|
.string()
|
||||||
.trim()
|
.trim()
|
||||||
|
.toLowerCase()
|
||||||
.min(3)
|
.min(3)
|
||||||
.max(50)
|
.max(50)
|
||||||
.regex(/^[a-z0-9_-]{3,50}$/),
|
.regex(/^[a-z0-9_-]{3,50}$/),
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
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().optional(),
|
||||||
|
username: z
|
||||||
|
.string()
|
||||||
|
.trim()
|
||||||
|
.toLowerCase()
|
||||||
|
.min(3)
|
||||||
|
.max(30)
|
||||||
|
.regex(/^[a-z0-9_-]{3,30}$/),
|
||||||
|
image: z.string().optional(),
|
||||||
|
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(),
|
||||||
|
archiveAsPDF: z.boolean().optional(),
|
||||||
|
archiveAsMonolith: z.boolean().optional(),
|
||||||
|
archiveAsWaybackMachine: 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.nativeEnum(LinksRouteTo).optional(),
|
||||||
|
whitelistedUsers: z.array(z.string().max(50)).optional(),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
export const PostSessionSchema = z.object({
|
export const PostSessionSchema = z.object({
|
||||||
username: z.string().min(3).max(50),
|
username: z.string().min(3).max(50),
|
||||||
password: z.string().min(8),
|
password: z.string().min(8),
|
||||||
|
@ -54,13 +89,13 @@ export const PostSessionSchema = z.object({
|
||||||
|
|
||||||
export const PostLinkSchema = z.object({
|
export const PostLinkSchema = z.object({
|
||||||
type: z.enum(["url", "pdf", "image"]),
|
type: z.enum(["url", "pdf", "image"]),
|
||||||
url: z.string().trim().max(255).url().optional(),
|
url: z.string().trim().max(2048).url().optional(),
|
||||||
name: z.string().trim().max(255).optional(),
|
name: z.string().trim().max(2048).optional(),
|
||||||
description: z.string().trim().max(255).optional(),
|
description: z.string().trim().max(2048).optional(),
|
||||||
collection: z
|
collection: z
|
||||||
.object({
|
.object({
|
||||||
id: z.number().optional(),
|
id: z.number().optional(),
|
||||||
name: z.string().trim().max(255).optional(),
|
name: z.string().trim().max(2048).optional(),
|
||||||
})
|
})
|
||||||
.optional(),
|
.optional(),
|
||||||
tags:
|
tags:
|
||||||
|
@ -76,6 +111,35 @@ export const PostLinkSchema = z.object({
|
||||||
|
|
||||||
export type PostLinkSchemaType = z.infer<typeof PostLinkSchema>;
|
export type PostLinkSchemaType = z.infer<typeof PostLinkSchema>;
|
||||||
|
|
||||||
|
export const UpdateLinkSchema = z.object({
|
||||||
|
id: z.number(),
|
||||||
|
name: z.string().trim().max(2048).optional(),
|
||||||
|
url: z.string().trim().max(2048).optional(),
|
||||||
|
description: z.string().trim().max(2048).optional(),
|
||||||
|
icon: z.string().trim().max(50).nullish(),
|
||||||
|
iconWeight: z.string().trim().max(50).nullish(),
|
||||||
|
color: z.string().trim().max(10).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(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export type UpdateLinkSchemaType = z.infer<typeof UpdateLinkSchema>;
|
||||||
|
|
||||||
const ACCEPTED_TYPES = [
|
const ACCEPTED_TYPES = [
|
||||||
"image/jpeg",
|
"image/jpeg",
|
||||||
"image/jpg",
|
"image/jpg",
|
||||||
|
@ -103,12 +167,39 @@ export const UploadFileSchema = z.object({
|
||||||
});
|
});
|
||||||
|
|
||||||
export const PostCollectionSchema = z.object({
|
export const PostCollectionSchema = z.object({
|
||||||
name: z.string().trim().max(255),
|
name: z.string().trim().max(2048),
|
||||||
description: z.string().trim().max(255).optional(),
|
description: z.string().trim().max(2048).optional(),
|
||||||
color: z.string().trim().max(7).optional(),
|
color: z.string().trim().max(10).optional(),
|
||||||
icon: z.string().trim().max(50).optional(),
|
icon: z.string().trim().max(50).optional(),
|
||||||
iconWeight: z.string().trim().max(50).optional(),
|
iconWeight: z.string().trim().max(50).optional(),
|
||||||
parentId: z.number().optional(),
|
parentId: z.number().optional(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export type PostCollectionSchemaType = z.infer<typeof PostCollectionSchema>;
|
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(10).optional(),
|
||||||
|
isPublic: z.boolean().optional(),
|
||||||
|
icon: z.string().trim().max(50).nullish(),
|
||||||
|
iconWeight: z.string().trim().max(50).nullish(),
|
||||||
|
parentId: z.number().nullish(),
|
||||||
|
members: z.array(
|
||||||
|
z.object({
|
||||||
|
userId: z.number(),
|
||||||
|
canCreate: z.boolean(),
|
||||||
|
canUpdate: z.boolean(),
|
||||||
|
canDelete: z.boolean(),
|
||||||
|
})
|
||||||
|
),
|
||||||
|
});
|
||||||
|
|
||||||
|
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>;
|
||||||
|
|
|
@ -60,6 +60,7 @@ export default async function links(req: NextApiRequest, res: NextApiResponse) {
|
||||||
req.body.removePreviousTags,
|
req.body.removePreviousTags,
|
||||||
req.body.newData
|
req.body.newData
|
||||||
);
|
);
|
||||||
|
|
||||||
return res.status(updated.status).json({
|
return res.status(updated.status).json({
|
||||||
response: updated.response,
|
response: updated.response,
|
||||||
});
|
});
|
||||||
|
|
|
@ -9,6 +9,11 @@ export default async function tags(req: NextApiRequest, res: NextApiResponse) {
|
||||||
|
|
||||||
const tagId = Number(req.query.id);
|
const tagId = Number(req.query.id);
|
||||||
|
|
||||||
|
if (!tagId)
|
||||||
|
return res.status(400).json({
|
||||||
|
response: "Please choose a valid name for the tag.",
|
||||||
|
});
|
||||||
|
|
||||||
if (req.method === "PUT") {
|
if (req.method === "PUT") {
|
||||||
if (process.env.NEXT_PUBLIC_DEMO === "true")
|
if (process.env.NEXT_PUBLIC_DEMO === "true")
|
||||||
return res.status(400).json({
|
return res.status(400).json({
|
||||||
|
|
|
@ -17,6 +17,7 @@ import { i18n } from "next-i18next.config";
|
||||||
import { useTranslation } from "next-i18next";
|
import { useTranslation } from "next-i18next";
|
||||||
import getServerSideProps from "@/lib/client/getServerSideProps";
|
import getServerSideProps from "@/lib/client/getServerSideProps";
|
||||||
import { useUpdateUser, useUser } from "@/hooks/store/user";
|
import { useUpdateUser, useUser } from "@/hooks/store/user";
|
||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
const emailEnabled = process.env.NEXT_PUBLIC_EMAIL_PROVIDER;
|
const emailEnabled = process.env.NEXT_PUBLIC_EMAIL_PROVIDER;
|
||||||
|
|
||||||
|
@ -80,6 +81,16 @@ export default function Account() {
|
||||||
};
|
};
|
||||||
|
|
||||||
const submit = async (password?: string) => {
|
const submit = async (password?: string) => {
|
||||||
|
if (!/^[a-z0-9_-]{3,50}$/.test(user.username || "")) {
|
||||||
|
return toast.error(t("username_invalid_guide"));
|
||||||
|
}
|
||||||
|
|
||||||
|
const emailSchema = z.string().trim().email().toLowerCase();
|
||||||
|
const emailValidation = emailSchema.safeParse(user.email || "");
|
||||||
|
if (!emailValidation.success) {
|
||||||
|
return toast.error(t("email_invalid"));
|
||||||
|
}
|
||||||
|
|
||||||
setSubmitLoader(true);
|
setSubmitLoader(true);
|
||||||
|
|
||||||
const load = toast.loading(t("applying_settings"));
|
const load = toast.loading(t("applying_settings"));
|
||||||
|
@ -207,6 +218,7 @@ export default function Account() {
|
||||||
<p className="mb-2">{t("email")}</p>
|
<p className="mb-2">{t("email")}</p>
|
||||||
<TextInput
|
<TextInput
|
||||||
value={user.email || ""}
|
value={user.email || ""}
|
||||||
|
type="email"
|
||||||
className="bg-base-200"
|
className="bg-base-200"
|
||||||
onChange={(e) => setUser({ ...user, email: e.target.value })}
|
onChange={(e) => setUser({ ...user, email: e.target.value })}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -394,5 +394,7 @@
|
||||||
"upload_preview_image": "Upload Preview Image",
|
"upload_preview_image": "Upload Preview Image",
|
||||||
"columns": "Columns",
|
"columns": "Columns",
|
||||||
"default": "Default",
|
"default": "Default",
|
||||||
"invalid_url_guide":"Please enter a valid Address for the Link. (It should start with http/https)"
|
"invalid_url_guide":"Please enter a valid Address for the Link. (It should start with http/https)",
|
||||||
|
"email_invalid": "Please enter a valid email address.",
|
||||||
|
"username_invalid_guide": "Username has to be at least 3 characters, no spaces and special characters are allowed."
|
||||||
}
|
}
|
Ŝarĝante…
Reference in New Issue