added zod for post requests
This commit is contained in:
@@ -1,16 +1,26 @@
|
||||
import { prisma } from "@/lib/api/db";
|
||||
import { CollectionIncludingMembersAndLinkCount } from "@/types/global";
|
||||
import createFolder from "@/lib/api/storage/createFolder";
|
||||
import {
|
||||
PostCollectionSchema,
|
||||
PostCollectionSchemaType,
|
||||
} from "@/lib/shared/schemaValidation";
|
||||
|
||||
export default async function postCollection(
|
||||
collection: CollectionIncludingMembersAndLinkCount,
|
||||
body: PostCollectionSchemaType,
|
||||
userId: number
|
||||
) {
|
||||
if (!collection || collection.name.trim() === "")
|
||||
const dataValidation = PostCollectionSchema.safeParse(body);
|
||||
|
||||
if (!dataValidation.success) {
|
||||
return {
|
||||
response: "Please enter a valid collection.",
|
||||
response: `Error: ${
|
||||
dataValidation.error.issues[0].message
|
||||
} [${dataValidation.error.issues[0].path.join(", ")}]`,
|
||||
status: 400,
|
||||
};
|
||||
}
|
||||
|
||||
const collection = dataValidation.data;
|
||||
|
||||
if (collection.parentId) {
|
||||
const findParentCollection = await prisma.collection.findUnique({
|
||||
|
||||
@@ -1,27 +1,31 @@
|
||||
import { prisma } from "@/lib/api/db";
|
||||
import { LinkIncludingShortenedCollectionAndTags } from "@/types/global";
|
||||
import fetchTitleAndHeaders from "@/lib/shared/fetchTitleAndHeaders";
|
||||
import createFolder from "@/lib/api/storage/createFolder";
|
||||
import setLinkCollection from "../../setLinkCollection";
|
||||
import {
|
||||
PostLinkSchema,
|
||||
PostLinkSchemaType,
|
||||
} from "@/lib/shared/schemaValidation";
|
||||
|
||||
const MAX_LINKS_PER_USER = Number(process.env.MAX_LINKS_PER_USER) || 30000;
|
||||
|
||||
export default async function postLink(
|
||||
link: LinkIncludingShortenedCollectionAndTags,
|
||||
body: PostLinkSchemaType,
|
||||
userId: number
|
||||
) {
|
||||
if (link.url || link.type === "url") {
|
||||
try {
|
||||
new URL(link.url || "");
|
||||
} catch (error) {
|
||||
return {
|
||||
response:
|
||||
"Please enter a valid Address for the Link. (It should start with http/https)",
|
||||
status: 400,
|
||||
};
|
||||
}
|
||||
const dataValidation = PostLinkSchema.safeParse(body);
|
||||
|
||||
if (!dataValidation.success) {
|
||||
return {
|
||||
response: `Error: ${
|
||||
dataValidation.error.issues[0].message
|
||||
} [${dataValidation.error.issues[0].path.join(", ")}]`,
|
||||
status: 400,
|
||||
};
|
||||
}
|
||||
|
||||
const link = dataValidation.data;
|
||||
|
||||
const linkCollection = await setLinkCollection(link, userId);
|
||||
|
||||
if (!linkCollection)
|
||||
|
||||
@@ -2,7 +2,6 @@ import { prisma } from "@/lib/api/db";
|
||||
import createFolder from "@/lib/api/storage/createFolder";
|
||||
import { JSDOM } from "jsdom";
|
||||
import { parse, Node, Element, TextNode } from "himalaya";
|
||||
import { writeFileSync } from "fs";
|
||||
|
||||
const MAX_LINKS_PER_USER = Number(process.env.MAX_LINKS_PER_USER) || 30000;
|
||||
|
||||
@@ -155,6 +154,8 @@ const createCollection = async (
|
||||
collectionName: string,
|
||||
parentId?: number
|
||||
) => {
|
||||
collectionName = collectionName.trim().slice(0, 254);
|
||||
|
||||
const findCollection = await prisma.collection.findFirst({
|
||||
where: {
|
||||
parentId,
|
||||
@@ -199,6 +200,22 @@ const createLink = async (
|
||||
tags?: string[],
|
||||
importDate?: Date
|
||||
) => {
|
||||
url = url.trim().slice(0, 254);
|
||||
try {
|
||||
new URL(url);
|
||||
} catch (e) {
|
||||
return;
|
||||
}
|
||||
tags = tags?.map((tag) => tag.trim().slice(0, 49));
|
||||
name = name?.trim().slice(0, 254);
|
||||
description = description?.trim().slice(0, 254);
|
||||
if (importDate) {
|
||||
const dateString = importDate.toISOString();
|
||||
if (dateString.length > 50) {
|
||||
importDate = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
await prisma.link.create({
|
||||
data: {
|
||||
name: name || "",
|
||||
|
||||
@@ -44,9 +44,9 @@ export default async function importFromLinkwarden(
|
||||
id: userId,
|
||||
},
|
||||
},
|
||||
name: e.name,
|
||||
description: e.description,
|
||||
color: e.color,
|
||||
name: e.name?.trim().slice(0, 254),
|
||||
description: e.description?.trim().slice(0, 254),
|
||||
color: e.color?.trim().slice(0, 50),
|
||||
},
|
||||
});
|
||||
|
||||
@@ -54,11 +54,19 @@ export default async function importFromLinkwarden(
|
||||
|
||||
// Import Links
|
||||
for (const link of e.links) {
|
||||
if (link.url) {
|
||||
try {
|
||||
new URL(link.url.trim());
|
||||
} catch (err) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
await prisma.link.create({
|
||||
data: {
|
||||
url: link.url,
|
||||
name: link.name,
|
||||
description: link.description,
|
||||
url: link.url?.trim().slice(0, 254),
|
||||
name: link.name?.trim().slice(0, 254),
|
||||
description: link.description?.trim().slice(0, 254),
|
||||
collection: {
|
||||
connect: {
|
||||
id: newCollection.id,
|
||||
@@ -69,12 +77,12 @@ export default async function importFromLinkwarden(
|
||||
connectOrCreate: link.tags.map((tag) => ({
|
||||
where: {
|
||||
name_ownerId: {
|
||||
name: tag.name.trim(),
|
||||
name: tag.name?.slice(0, 49),
|
||||
ownerId: userId,
|
||||
},
|
||||
},
|
||||
create: {
|
||||
name: tag.name.trim(),
|
||||
name: tag.name?.trim().slice(0, 49),
|
||||
owner: {
|
||||
connect: {
|
||||
id: userId,
|
||||
|
||||
@@ -67,14 +67,22 @@ export default async function importFromWallabag(
|
||||
createFolder({ filePath: `archives/${newCollection.id}` });
|
||||
|
||||
for (const link of backup) {
|
||||
if (link.url) {
|
||||
try {
|
||||
new URL(link.url.trim());
|
||||
} catch (err) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
await prisma.link.create({
|
||||
data: {
|
||||
pinnedBy: link.is_starred
|
||||
? { connect: { id: userId } }
|
||||
: undefined,
|
||||
url: link.url,
|
||||
name: link.title || "",
|
||||
textContent: link.content || "",
|
||||
url: link.url?.trim().slice(0, 254),
|
||||
name: link.title?.trim().slice(0, 254) || "",
|
||||
textContent: link.content?.trim() || "",
|
||||
importDate: link.created_at || null,
|
||||
collection: {
|
||||
connect: {
|
||||
@@ -87,12 +95,12 @@ export default async function importFromWallabag(
|
||||
connectOrCreate: link.tags.map((tag) => ({
|
||||
where: {
|
||||
name_ownerId: {
|
||||
name: tag.trim(),
|
||||
name: tag?.trim().slice(0, 49),
|
||||
ownerId: userId,
|
||||
},
|
||||
},
|
||||
create: {
|
||||
name: tag.trim(),
|
||||
name: tag?.trim().slice(0, 49),
|
||||
owner: {
|
||||
connect: {
|
||||
id: userId,
|
||||
|
||||
@@ -1,28 +1,32 @@
|
||||
import { prisma } from "@/lib/api/db";
|
||||
import {
|
||||
PostTokenSchemaType,
|
||||
PostTokenSchema,
|
||||
} from "@/lib/shared/schemaValidation";
|
||||
import { TokenExpiry } from "@/types/global";
|
||||
import crypto from "crypto";
|
||||
import { decode, encode } from "next-auth/jwt";
|
||||
|
||||
export default async function postToken(
|
||||
body: {
|
||||
name: string;
|
||||
expires: TokenExpiry;
|
||||
},
|
||||
body: PostTokenSchemaType,
|
||||
userId: number
|
||||
) {
|
||||
console.log(body);
|
||||
const dataValidation = PostTokenSchema.safeParse(body);
|
||||
|
||||
const checkHasEmptyFields = !body.name || body.expires === undefined;
|
||||
|
||||
if (checkHasEmptyFields)
|
||||
if (!dataValidation.success) {
|
||||
return {
|
||||
response: "Please fill out all the fields.",
|
||||
response: `Error: ${
|
||||
dataValidation.error.issues[0].message
|
||||
} [${dataValidation.error.issues[0].path.join(", ")}]`,
|
||||
status: 400,
|
||||
};
|
||||
}
|
||||
|
||||
const { name, expires } = dataValidation.data;
|
||||
|
||||
const checkIfTokenExists = await prisma.accessToken.findFirst({
|
||||
where: {
|
||||
name: body.name,
|
||||
name: name,
|
||||
revoked: false,
|
||||
userId,
|
||||
},
|
||||
@@ -40,16 +44,16 @@ export default async function postToken(
|
||||
const oneDayInSeconds = 86400;
|
||||
let expiryDateSecond = 7 * oneDayInSeconds;
|
||||
|
||||
if (body.expires === TokenExpiry.oneMonth) {
|
||||
if (expires === TokenExpiry.oneMonth) {
|
||||
expiryDate.setDate(expiryDate.getDate() + 30);
|
||||
expiryDateSecond = 30 * oneDayInSeconds;
|
||||
} else if (body.expires === TokenExpiry.twoMonths) {
|
||||
} else if (expires === TokenExpiry.twoMonths) {
|
||||
expiryDate.setDate(expiryDate.getDate() + 60);
|
||||
expiryDateSecond = 60 * oneDayInSeconds;
|
||||
} else if (body.expires === TokenExpiry.threeMonths) {
|
||||
} else if (expires === TokenExpiry.threeMonths) {
|
||||
expiryDate.setDate(expiryDate.getDate() + 90);
|
||||
expiryDateSecond = 90 * oneDayInSeconds;
|
||||
} else if (body.expires === TokenExpiry.never) {
|
||||
} else if (expires === TokenExpiry.never) {
|
||||
expiryDate.setDate(expiryDate.getDate() + 73000); // 200 years (not really never)
|
||||
expiryDateSecond = 73050 * oneDayInSeconds;
|
||||
} else {
|
||||
@@ -75,7 +79,7 @@ export default async function postToken(
|
||||
|
||||
const createToken = await prisma.accessToken.create({
|
||||
data: {
|
||||
name: body.name,
|
||||
name: name,
|
||||
userId,
|
||||
token: tokenBody?.jti as string,
|
||||
expires: expiryDate,
|
||||
|
||||
@@ -2,6 +2,7 @@ import { prisma } from "@/lib/api/db";
|
||||
import type { NextApiRequest, NextApiResponse } from "next";
|
||||
import bcrypt from "bcrypt";
|
||||
import isServerAdmin from "../../isServerAdmin";
|
||||
import { PostUserSchema } from "@/lib/shared/schemaValidation";
|
||||
|
||||
const emailEnabled =
|
||||
process.env.EMAIL_FROM && process.env.EMAIL_SERVER ? true : false;
|
||||
@@ -12,13 +13,6 @@ interface Data {
|
||||
status: number;
|
||||
}
|
||||
|
||||
interface User {
|
||||
name: string;
|
||||
username?: string;
|
||||
email?: string;
|
||||
password: string;
|
||||
}
|
||||
|
||||
export default async function postUser(
|
||||
req: NextApiRequest,
|
||||
res: NextApiResponse
|
||||
@@ -29,49 +23,34 @@ export default async function postUser(
|
||||
return { response: "Registration is disabled.", status: 400 };
|
||||
}
|
||||
|
||||
const body: User = req.body;
|
||||
const dataValidation = PostUserSchema().safeParse(req.body);
|
||||
|
||||
const checkHasEmptyFields = emailEnabled
|
||||
? !body.password || !body.name || !body.email
|
||||
: !body.username || !body.password || !body.name;
|
||||
if (!dataValidation.success) {
|
||||
return {
|
||||
response: `Error: ${
|
||||
dataValidation.error.issues[0].message
|
||||
} [${dataValidation.error.issues[0].path.join(", ")}]`,
|
||||
status: 400,
|
||||
};
|
||||
}
|
||||
|
||||
if (!body.password || body.password.length < 8)
|
||||
return { response: "Password must be at least 8 characters.", status: 400 };
|
||||
|
||||
if (checkHasEmptyFields)
|
||||
return { response: "Please fill out all the fields.", status: 400 };
|
||||
|
||||
// Check email (if enabled)
|
||||
const checkEmail =
|
||||
/^(([^<>()[\]\.,;:\s@\"]+(\.[^<>()[\]\.,;:\s@\"]+)*)|(\".+\"))@(([^<>()[\]\.,;:\s@\"]+\.)+[^<>()[\]\.,;:\s@\"]{2,})$/i;
|
||||
if (emailEnabled && !checkEmail.test(body.email?.toLowerCase() || ""))
|
||||
return { response: "Please enter a valid email.", status: 400 };
|
||||
|
||||
// Check username (if email was disabled)
|
||||
const checkUsername = RegExp("^[a-z0-9_-]{3,31}$");
|
||||
const { name, email, password } = dataValidation.data;
|
||||
let { username } = dataValidation.data;
|
||||
|
||||
const autoGeneratedUsername = "user" + Math.round(Math.random() * 1000000000);
|
||||
|
||||
if (body.username && !checkUsername.test(body.username?.toLowerCase()))
|
||||
return {
|
||||
response:
|
||||
"Username has to be between 3-30 characters, no spaces and special characters are allowed.",
|
||||
status: 400,
|
||||
};
|
||||
else if (!body.username) {
|
||||
body.username = autoGeneratedUsername;
|
||||
if (!username) {
|
||||
username = autoGeneratedUsername;
|
||||
}
|
||||
|
||||
const checkIfUserExists = await prisma.user.findFirst({
|
||||
where: {
|
||||
OR: [
|
||||
{
|
||||
email: body.email ? body.email.toLowerCase().trim() : undefined,
|
||||
email: email ? email.toLowerCase().trim() : undefined,
|
||||
},
|
||||
{
|
||||
username: body.username
|
||||
? body.username.toLowerCase().trim()
|
||||
: undefined,
|
||||
username: username ? username.toLowerCase().trim() : undefined,
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -83,7 +62,7 @@ export default async function postUser(
|
||||
|
||||
const saltRounds = 10;
|
||||
|
||||
const hashedPassword = bcrypt.hashSync(body.password, saltRounds);
|
||||
const hashedPassword = bcrypt.hashSync(password, saltRounds);
|
||||
|
||||
// Subscription dates
|
||||
const currentPeriodStart = new Date();
|
||||
@@ -93,12 +72,11 @@ export default async function postUser(
|
||||
if (isAdmin) {
|
||||
const user = await prisma.user.create({
|
||||
data: {
|
||||
name: body.name,
|
||||
name: name,
|
||||
username: emailEnabled
|
||||
? (body.username as string).toLowerCase().trim() ||
|
||||
autoGeneratedUsername
|
||||
: (body.username as string).toLowerCase().trim(),
|
||||
email: emailEnabled ? body.email?.toLowerCase().trim() : undefined,
|
||||
? (username as string) || autoGeneratedUsername
|
||||
: (username as string),
|
||||
email: emailEnabled ? email : undefined,
|
||||
password: hashedPassword,
|
||||
emailVerified: new Date(),
|
||||
subscriptions: stripeEnabled
|
||||
@@ -131,11 +109,9 @@ export default async function postUser(
|
||||
} else {
|
||||
await prisma.user.create({
|
||||
data: {
|
||||
name: body.name,
|
||||
username: emailEnabled
|
||||
? autoGeneratedUsername
|
||||
: (body.username as string).toLowerCase().trim(),
|
||||
email: emailEnabled ? body.email?.toLowerCase().trim() : undefined,
|
||||
name: name,
|
||||
username: emailEnabled ? autoGeneratedUsername : (username as string),
|
||||
email: emailEnabled ? email : undefined,
|
||||
password: hashedPassword,
|
||||
},
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user