feat(wip): create models to access db data

This commit is contained in:
Sonny
2023-05-31 19:27:48 +02:00
parent e7e7e0c950
commit a89fa471e0
19 changed files with 213 additions and 88 deletions

40
package-lock.json generated
View File

@@ -22,7 +22,8 @@
"react-select": "^5.7.3",
"sass": "^1.62.1",
"sharp": "^0.32.1",
"toastr": "^2.1.4"
"toastr": "^2.1.4",
"yup": "^1.2.0"
},
"devDependencies": {
"@types/node": "^20.2.4",
@@ -6005,6 +6006,11 @@
"react-is": "^16.13.1"
}
},
"node_modules/property-expr": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/property-expr/-/property-expr-2.0.5.tgz",
"integrity": "sha512-IJUkICM5dP5znhCckHSv30Q4b5/JA5enCtkRHYaOVOAocnH/1BQEYTC5NMfT3AVl/iXKdr3aqQbQn9DxyWknwA=="
},
"node_modules/proxy-from-env": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
@@ -6811,6 +6817,11 @@
"integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==",
"dev": true
},
"node_modules/tiny-case": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/tiny-case/-/tiny-case-1.0.3.tgz",
"integrity": "sha512-Eet/eeMhkO6TX8mnUteS9zgPbUMQa4I6Kkp5ORiBD5476/m+PIRiumP5tmh5ioJpH7k51Kehawy2UDfsnxxY8Q=="
},
"node_modules/tiny-glob": {
"version": "0.2.9",
"resolved": "https://registry.npmjs.org/tiny-glob/-/tiny-glob-0.2.9.tgz",
@@ -6848,6 +6859,11 @@
"jquery": ">=1.12.0"
}
},
"node_modules/toposort": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/toposort/-/toposort-2.0.2.tgz",
"integrity": "sha512-0a5EOkAUp8D4moMi2W8ZF8jcga7BgZd91O/yabJCFY8az+XSzeGyTKs0Aoo897iV1Nj6guFq8orWDS96z91oGg=="
},
"node_modules/tsconfig-paths": {
"version": "3.14.1",
"resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz",
@@ -7161,6 +7177,28 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/yup": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/yup/-/yup-1.2.0.tgz",
"integrity": "sha512-PPqYKSAXjpRCgLgLKVGPA33v5c/WgEx3wi6NFjIiegz90zSwyMpvTFp/uGcVnnbx6to28pgnzp/q8ih3QRjLMQ==",
"dependencies": {
"property-expr": "^2.0.5",
"tiny-case": "^1.0.3",
"toposort": "^2.0.2",
"type-fest": "^2.19.0"
}
},
"node_modules/yup/node_modules/type-fest": {
"version": "2.19.0",
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz",
"integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==",
"engines": {
"node": ">=12.20"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/zod": {
"version": "3.21.4",
"resolved": "https://registry.npmjs.org/zod/-/zod-3.21.4.tgz",

View File

@@ -24,7 +24,8 @@
"react-select": "^5.7.3",
"sass": "^1.62.1",
"sharp": "^0.32.1",
"toastr": "^2.1.4"
"toastr": "^2.1.4",
"yup": "^1.2.0"
},
"devDependencies": {
"@types/node": "^20.2.4",

View File

@@ -0,0 +1,17 @@
import { User } from "@prisma/client";
import prisma from "utils/prisma";
export default async function getUserCategories(user: User) {
return await prisma.category.findMany({
where: {
authorId: user.id,
},
include: {
links: {
where: {
authorId: user.id,
},
},
},
});
}

View File

@@ -0,0 +1,14 @@
import { Link, User } from "@prisma/client";
import prisma from "utils/prisma";
export default async function getUserLink(user: User, id: Link["id"]) {
return await prisma.link.findFirst({
where: {
id,
authorId: user.id,
},
include: {
category: true,
},
});
}

View File

@@ -0,0 +1,10 @@
import { User } from "@prisma/client";
import prisma from "utils/prisma";
export default async function getUserLinks(user: User) {
return await prisma.link.findMany({
where: {
authorId: user.id,
},
});
}

View File

@@ -0,0 +1,10 @@
import { Session } from "next-auth";
import prisma from "utils/prisma";
export default async function getUserOrThrow(session: Session) {
return await prisma.user.findFirstOrThrow({
where: {
email: session?.user?.email,
},
});
}

View File

@@ -33,6 +33,7 @@ export const authOptions = {
"[AUTH]",
"User",
profile.name,
profile.sub,
"attempt to log in with",
accountParam.provider
);

View File

@@ -1,64 +1,40 @@
import { NextApiRequest, NextApiResponse } from "next";
import { getServerSession } from "next-auth/next";
import { authOptions } from "../auth/[...nextauth]";
import { checkMethodAllowedOrThrow } from "utils/api";
import prisma from "utils/prisma";
import { getSessionOrThrow } from "utils/session";
export default async function POST(req: NextApiRequest, res: NextApiResponse) {
await checkMethodAllowedOrThrow(req, ["post"]);
const session = await getSessionOrThrow(req, res);
export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
const session = await getServerSession(req, res, authOptions); // je sais plus d'où ça vient
console.log("session", session);
const name = req.body?.name as string;
if (!name) {
return res.status(400).send({ error: "Nom de catégorie manquant" });
throw new Error("Categorie name missing");
}
try {
const category = await prisma.category.findFirst({
where: { name },
});
if (category) {
return res
.status(400)
.send({ error: "Une catégorie avec ce nom existe déjà" });
}
} catch (error) {
console.error(error);
return res.status(400).send({
error:
"Une erreur est survenue lors de la création de la catégorie (category/create->findCategory)",
});
const category = await prisma.category.findFirst({
where: { name },
});
if (category) {
throw new Error("Category name already used");
}
try {
const { id: authorId } = await prisma.user.findFirst({
where: {
email: session.user.email,
},
select: {
id: true,
},
});
if (!authorId) {
throw new Error("Unable to find user");
}
const { id: authorId } = await prisma.user.findFirstOrThrow({
where: {
email: session.user.email,
},
select: {
id: true,
},
});
const category = await prisma.category.create({
data: { name, authorId },
});
return res.status(200).send({
success: "Catégorie créée avec succès",
categoryId: category.id,
});
} catch (error) {
console.error(error);
return res.status(400).send({
error:
"Une erreur est survenue lors de la création de la catégorie (category/create->createCategory)",
});
}
const categoryCreated = await prisma.category.create({
data: { name, authorId },
});
console.log("là");
return res.status(200).send({
success: "Category successfully created",
categoryId: categoryCreated.id,
});
}

View File

@@ -1,10 +1,19 @@
import { NextApiRequest, NextApiResponse } from "next";
import { getServerSession } from "next-auth/next";
import prisma from "utils/prisma";
import { authOptions } from "../auth/[...nextauth]";
export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
const session = await getServerSession(req, res, authOptions); // je sais plus d'où ça vient
console.log("session", session);
if (!session?.user) {
return res.status(400).send({ error: "You must be connected" });
}
const name = req.body?.name as string;
const url = req.body?.url as string;
const favorite = Boolean(req.body?.favorite) || false;
@@ -57,12 +66,16 @@ export default async function handler(
}
try {
const { id: authorId } = await prisma.user.findFirstOrThrow({
where: { email: session.user.email },
});
await prisma.link.create({
data: {
name,
url,
categoryId,
favorite,
authorId,
},
});
return res

View File

@@ -79,7 +79,7 @@ export async function getServerSideProps({ query }) {
const { cid } = query;
const categoryDB = await prisma.category.findFirst({
where: { id: Number(cid) },
include: { links: true },
include: { links: true, author: true },
});
if (!categoryDB) {

View File

@@ -84,7 +84,7 @@ export async function getServerSideProps({ query }) {
const { cid } = query;
const categoryDB = await prisma.category.findFirst({
where: { id: Number(cid) },
include: { links: true },
include: { links: true, author: true },
});
if (!categoryDB) {

View File

@@ -16,6 +16,7 @@ import { Category, Link, SearchItem } from "types";
import { BuildCategory } from "utils/front";
import { pushStateVanilla } from "utils/link";
import prisma from "utils/prisma";
import { getSessionOrThrow } from "utils/session";
interface HomePageProps {
categories: Category[];
@@ -185,10 +186,27 @@ function Home(props: HomePageProps) {
);
}
export async function getServerSideProps({ query }) {
export async function getServerSideProps({ req, res, query }) {
const session = await getSessionOrThrow(req, res);
const queryCategoryId = (query?.categoryId as string) || "";
const user = await prisma.user.findFirstOrThrow({
where: {
email: session.user.email,
},
});
const categoriesDB = await prisma.category.findMany({
include: { links: true },
include: {
links: {
where: {
authorId: user.id,
},
},
author: true,
},
where: {
authorId: user.id,
},
});
if (categoriesDB.length === 0) {

View File

@@ -111,7 +111,9 @@ CreateLink.authRequired = true;
export default CreateLink;
export async function getServerSideProps() {
const categoriesDB = await prisma.category.findMany();
const categoriesDB = await prisma.category.findMany({
include: { author: true },
});
const categories = categoriesDB.map((categoryDB) =>
BuildCategory(categoryDB)
);

View File

@@ -11,15 +11,13 @@ import TextBox from "components/TextBox";
import useAutoFocus from "hooks/useAutoFocus";
import { Category, Link } from "types";
import {
BuildCategory,
BuildLink,
HandleAxiosError,
IsValidURL,
} from "utils/front";
import prisma from "utils/prisma";
import { HandleAxiosError, IsValidURL } from "utils/front";
import getUserCategories from "lib/category/getUserCategories";
import getUserLink from "lib/link/getUserLink";
import getUserOrThrow from "lib/user/getUserOrThrow";
import styles from "styles/create.module.scss";
import { getSessionOrThrow } from "utils/session";
function EditLink({
link,
@@ -133,20 +131,15 @@ function EditLink({
EditLink.authRequired = true;
export default EditLink;
export async function getServerSideProps({ query }) {
export async function getServerSideProps({ req, res, query }) {
const { lid } = query;
const categoriesDB = await prisma.category.findMany();
const categories = categoriesDB.map((categoryDB) =>
BuildCategory(categoryDB)
);
const session = await getSessionOrThrow(req, res);
const user = await getUserOrThrow(session);
const categories = await getUserCategories(user);
const linkDB = await prisma.link.findFirst({
where: { id: Number(lid) },
include: { category: true },
});
if (!linkDB) {
const link = await getUserLink(user, Number(lid));
if (!link) {
return {
redirect: {
destination: "/",
@@ -154,10 +147,6 @@ export async function getServerSideProps({ query }) {
};
}
const link = BuildLink(linkDB, {
categoryId: linkDB.categoryId,
categoryName: linkDB.category.name,
});
return {
props: {
link: JSON.parse(JSON.stringify(link)),

View File

@@ -98,7 +98,7 @@ export async function getServerSideProps({ query }) {
const { lid } = query;
const linkDB = await prisma.link.findFirst({
where: { id: Number(lid) },
include: { category: true },
include: { category: true, author: true },
});
if (!linkDB) {

8
src/types.d.ts vendored
View File

@@ -1,9 +1,12 @@
import { User } from "@prisma/client";
export interface Category {
id: number;
name: string;
links: Link[];
nextCategoryId: number;
authorId: User["id"];
author: User;
createdAt: Date;
updatedAt: Date;
@@ -20,7 +23,8 @@ export interface Link {
name: string;
};
nextLinkId: number;
authorId: User["id"];
author: User;
favorite: boolean;
createdAt: Date;

12
src/utils/api.ts Normal file
View File

@@ -0,0 +1,12 @@
import { NextApiRequest } from "next";
export function checkMethodAllowedOrThrow(
req: NextApiRequest,
methods: Array<RequestInit["method"]>
) {
const isMethodAllowed = methods.includes(req.method.toLowerCase());
if (!isMethodAllowed) {
throw new Error(`Method ${req.method} not allowed`);
}
return isMethodAllowed;
}

View File

@@ -5,7 +5,8 @@ import { Category, Link } from "types";
export function BuildCategory({
id,
name,
nextCategoryId,
authorId,
author,
links = [],
createdAt,
updatedAt,
@@ -16,14 +17,15 @@ export function BuildCategory({
links: links.map((link) =>
BuildLink(link, { categoryId: id, categoryName: name })
),
nextCategoryId,
authorId,
author,
createdAt,
updatedAt,
};
}
export function BuildLink(
{ id, name, url, nextLinkId, favorite, createdAt, updatedAt },
{ id, name, url, authorId, author, favorite, createdAt, updatedAt },
{ categoryId, categoryName }
): Link {
return {
@@ -34,7 +36,8 @@ export function BuildLink(
id: categoryId,
name: categoryName,
},
nextLinkId,
authorId,
author,
favorite,
createdAt,
updatedAt,

17
src/utils/session.ts Normal file
View File

@@ -0,0 +1,17 @@
import { NextApiRequest, NextApiResponse } from "next";
import { getServerSession } from "next-auth/next";
import { authOptions } from "pages/api/auth/[...nextauth]";
export async function getSessionOrThrow(
req: NextApiRequest,
res: NextApiResponse
) {
const session = await getServerSession(req, res, authOptions);
if (!session) {
throw new Error("You must be connected");
}
return session;
}