diff --git a/package-lock.json b/package-lock.json index d564d96..bcd74d3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,10 +9,12 @@ "version": "0.1.0", "dependencies": { "@prisma/client": "^6.6.0", + "bcryptjs": "^3.0.2", "next": "15.3.0", "prisma": "^6.6.0", "react": "^19.0.0", - "react-dom": "^19.0.0" + "react-dom": "^19.0.0", + "slugify": "^1.6.6" }, "devDependencies": { "@eslint/eslintrc": "^3", @@ -2461,6 +2463,15 @@ "dev": true, "license": "MIT" }, + "node_modules/bcryptjs": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-3.0.2.tgz", + "integrity": "sha512-k38b3XOZKv60C4E2hVsXTolJWfkGRMbILBIe2IBITXciy5bOsTKot5kDrf3ZfufQtQOUN5mXceUEpU1rTl9Uog==", + "license": "BSD-3-Clause", + "bin": { + "bcrypt": "bin/bcrypt" + } + }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -5787,6 +5798,15 @@ "is-arrayish": "^0.3.1" } }, + "node_modules/slugify": { + "version": "1.6.6", + "resolved": "https://registry.npmjs.org/slugify/-/slugify-1.6.6.tgz", + "integrity": "sha512-h+z7HKHYXj6wJU+AnS/+IH8Uh9fdcX1Lrhg1/VMdf9PwoBQXFcXiAdsy2tSK0P6gKwJLXp02r90ahUCqHk9rrw==", + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, "node_modules/source-map-js": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", diff --git a/package.json b/package.json index a0db5e9..2f4d4fb 100644 --- a/package.json +++ b/package.json @@ -6,14 +6,17 @@ "dev": "next dev --turbopack", "build": "next build", "start": "next start", - "lint": "next lint" + "lint": "next lint", + "start:migrate:prod" : "npx prisma migrate deploy && npm run start" }, "dependencies": { "@prisma/client": "^6.6.0", + "bcryptjs": "^3.0.2", "next": "15.3.0", "prisma": "^6.6.0", "react": "^19.0.0", - "react-dom": "^19.0.0" + "react-dom": "^19.0.0", + "slugify": "^1.6.6" }, "devDependencies": { "@eslint/eslintrc": "^3", diff --git a/src/actions/session/session.ts b/src/actions/session/session.ts new file mode 100644 index 0000000..a5992c4 --- /dev/null +++ b/src/actions/session/session.ts @@ -0,0 +1,179 @@ +"use server" + +import prisma from "@/lib/db"; +import bcrypt from "bcryptjs"; +import { cookies } from "next/headers"; +import slugify from "slugify"; + +export async function register(formData : FormData){ + //Permet de récupérer les données demandées à l'utilisateur lors de l'inscription + const {email,password,passwordRepeat} = Object.fromEntries(formData) + + if(password !== passwordRepeat){ + throw new Error("Le passwords ne correspond pas") + } + + try{ + + //Vérification du mail + const verifUser = await prisma.utilisateur.findFirst({ + where : { + ut_mail : email.toString() + } + }) + if(verifUser){ + throw new Error("Utilisateur déjà inscrit") + } + + + //slugify de l'email + const slug = slugify(email.toString().substring(0,email.toString().indexOf("@")),{lower:true,strict:true}) + + //hash du mdp + const salt = await bcrypt.genSalt(10) + const hashedPassword = await bcrypt.hash(password.toString(),salt) + + //creation de l'utilisateur + const result = await prisma.utilisateur.create({ + data :{ + ut_mail : email.toString(), + ut_mdp : hashedPassword.toString(), + ut_slug : slug + } + }) + + if(result){ + return {success: true} + } + throw new Error("Anomalie lors de la création du user") + + }catch(err){ + const error = err as Error + throw new Error(error.message || "une erreur à été rencontrée lors de la création de l'utilisateur") + } +} + +export async function login(formData : FormData){ + const {email,password} = Object.fromEntries(formData) + + try{ + //vérification si l'utilisateur est trouvé + const user = await prisma.utilisateur.findFirst({ + where : { + ut_mail : email.toString() + } + }) + if(!user){ + throw new Error("Invalide crédential") + } + //vérification du mdp + const isPasswordValid = await bcrypt.compare(password.toString(), user.ut_mdp) + if(!isPasswordValid){ + throw new Error("Invalide crédential") + } + + //vérification si une session de connexion existe + const existingSession = await prisma.session.findFirst({ + where : { + se_ut_id : user.ut_id + } + }) + + //vérification si la session existe mais expiré + // delete de l'enreg pour le recréer + let verifDeleteSession = false + if(existingSession && new Date() > existingSession.expireAt ){ + const deleteSession = await prisma.session.delete({ + where : { + se_id : existingSession.se_id + } + }) + if(deleteSession){ + verifDeleteSession = true + } + } + + //vérification si une session de connexion existe et tjr actif + // on regenere le cookie ensuite + let verifValiditeSession = false + if(existingSession && new Date() < existingSession.expireAt){ + verifValiditeSession = true + } + + let sessionidCreate = "" + if(!existingSession || verifDeleteSession){ + const createSession = await prisma.session.create({ + data : { + se_ut_id : user.ut_id, + expireAt : new Date(Date.now() + 7*24*60*60*1000) + } + }) + if(createSession){ + sessionidCreate = createSession.se_id + } + } + + const cookieStore = await cookies() + + if(sessionidCreate !== ""){ + cookieStore.set("sessionId",sessionidCreate,{ + httpOnly : true, + secure: process.env.NODE_ENV ==="production", + path:"/", + maxAge: 24*60*60, + sameSite: "lax" + }) + } + if(verifValiditeSession && existingSession?.se_id){ + cookieStore.set("sessionId",existingSession?.se_id,{ + httpOnly : true, + secure: process.env.NODE_ENV ==="production", + path:"/", + maxAge: 24*60*60, + sameSite: "lax" + }) + } + + return {success : true} + }catch(err){ + const error = err as Error + throw new Error(error.message || "une erreur à été rencontrée lors de la connexion de l'utilisateur") + } +} + + +export async function verifSession(){ + try{ + const cookie = await cookies() + const verif = cookie.get("sessionId") + if(verif){ + const verifExpireSession = await prisma.session.findUnique({ + where : { + se_id : verif.value + } + }) + if(verifExpireSession && new Date() > verifExpireSession.expireAt){ + await prisma.session.delete({ + where : { + se_id : verifExpireSession.se_id + } + }) + return {success : false} + }else{ + cookie.set("sessionId",verif.value,{ + httpOnly : true, + secure: process.env.NODE_ENV ==="production", + path:"/", + maxAge: 24*60*60, + sameSite: "lax" + }) + return {success : true} + } + } + return {success : false} + + }catch(err){ + const error = err as Error + throw new Error(error.message || "une erreur à été rencontrée lors de la vérification de la session") + } +} diff --git a/src/actions/user/user.ts b/src/actions/user/user.ts new file mode 100644 index 0000000..682e50f --- /dev/null +++ b/src/actions/user/user.ts @@ -0,0 +1,42 @@ +import prisma from "@/lib/db"; + +export async function getInfoUser(slug : string){ + try{ + const user = await prisma.utilisateur.findFirst({ + where : { + ut_slug : slug + } + }) + if(user){ + return {success : true, user} + } + return {success : false, message : "Impossible de trouver les infos de l'utilisateur"} + }catch(err){ + const error = err as Error + throw new Error(error.message || "une erreur à été rencontrée lors de la recherche de l'utilisateur") + } +} + +export async function deleteUser(slug : string){ + try{ + + const user = await prisma.utilisateur.findFirst({ + where : { + ut_slug : slug + } + }) + if(user){ + await prisma.utilisateur.delete({ + where : { + ut_id : user.ut_id + } + }) + return {success : true} + } + return {success : false, message : "Impossible de supprimer l'utilisateur"} + }catch(err){ + const error = err as Error + throw new Error(error.message || "une erreur à été rencontrée lors suppression de l'utilisateur") + } +} +