mirror of
https://github.com/Sonny93/my-links.git
synced 2025-12-10 07:25:35 +00:00
feat(wip): add support for multi user in instance
This commit is contained in:
@@ -0,0 +1,17 @@
|
|||||||
|
/*
|
||||||
|
Warnings:
|
||||||
|
|
||||||
|
- You are about to drop the column `nextCategoryId` on the `category` table. All the data in the column will be lost.
|
||||||
|
- You are about to drop the column `nextLinkId` on the `link` table. All the data in the column will be lost.
|
||||||
|
- Added the required column `authorId` to the `category` table without a default value. This is not possible if the table is not empty.
|
||||||
|
|
||||||
|
*/
|
||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE `category` DROP COLUMN `nextCategoryId`,
|
||||||
|
ADD COLUMN `authorId` INTEGER NOT NULL;
|
||||||
|
|
||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE `link` DROP COLUMN `nextLinkId`;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE `category` ADD CONSTRAINT `category_authorId_fkey` FOREIGN KEY (`authorId`) REFERENCES `user`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
/*
|
||||||
|
Warnings:
|
||||||
|
|
||||||
|
- Added the required column `authorId` to the `link` table without a default value. This is not possible if the table is not empty.
|
||||||
|
|
||||||
|
*/
|
||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE `link` ADD COLUMN `authorId` INTEGER NOT NULL;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE `link` ADD CONSTRAINT `link_authorId_fkey` FOREIGN KEY (`authorId`) REFERENCES `user`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
@@ -8,12 +8,17 @@ generator client {
|
|||||||
datasource db {
|
datasource db {
|
||||||
provider = "mysql"
|
provider = "mysql"
|
||||||
url = env("DATABASE_URL")
|
url = env("DATABASE_URL")
|
||||||
|
shadowDatabaseUrl = env("SHADOW_DATABASE_URL")
|
||||||
}
|
}
|
||||||
|
|
||||||
model User {
|
model User {
|
||||||
id Int @id @default(autoincrement())
|
id Int @id @default(autoincrement())
|
||||||
google_id String @unique
|
google_id String @unique
|
||||||
email String @unique
|
email String @unique
|
||||||
|
|
||||||
|
categories Category[]
|
||||||
|
links Link[]
|
||||||
|
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
updatedAt DateTime @updatedAt
|
updatedAt DateTime @updatedAt
|
||||||
|
|
||||||
@@ -24,7 +29,10 @@ model Category {
|
|||||||
id Int @id @default(autoincrement())
|
id Int @id @default(autoincrement())
|
||||||
name String @unique @db.VarChar(255)
|
name String @unique @db.VarChar(255)
|
||||||
links Link[]
|
links Link[]
|
||||||
nextCategoryId Int @default(0)
|
|
||||||
|
author User @relation(fields: [authorId], references: [id])
|
||||||
|
authorId Int
|
||||||
|
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
updatedAt DateTime @updatedAt
|
updatedAt DateTime @updatedAt
|
||||||
|
|
||||||
@@ -35,9 +43,13 @@ model Link {
|
|||||||
id Int @id @default(autoincrement())
|
id Int @id @default(autoincrement())
|
||||||
name String @db.VarChar(255)
|
name String @db.VarChar(255)
|
||||||
url String @db.Text
|
url String @db.Text
|
||||||
|
|
||||||
category Category @relation(fields: [categoryId], references: [id])
|
category Category @relation(fields: [categoryId], references: [id])
|
||||||
categoryId Int
|
categoryId Int
|
||||||
nextLinkId Int @default(0)
|
|
||||||
|
author User @relation(fields: [authorId], references: [id])
|
||||||
|
authorId Int
|
||||||
|
|
||||||
favorite Boolean @default(false)
|
favorite Boolean @default(false)
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
updatedAt DateTime @updatedAt
|
updatedAt DateTime @updatedAt
|
||||||
|
|||||||
29
src/_middleware.ts
Normal file
29
src/_middleware.ts
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
import PATHS from "constants/paths";
|
||||||
|
|
||||||
|
export { default } from "next-auth/middleware";
|
||||||
|
|
||||||
|
// WAIT: for fix - Next.js@13.4.4 seems to be broken
|
||||||
|
// cf: https://github.com/nextauthjs/next-auth/issues/7650
|
||||||
|
// (this file must renamed "middleware.ts")
|
||||||
|
|
||||||
|
export const config = {
|
||||||
|
matcher: [
|
||||||
|
PATHS.HOME,
|
||||||
|
|
||||||
|
PATHS.LINK.CREATE,
|
||||||
|
PATHS.LINK.EDIT,
|
||||||
|
PATHS.LINK.REMOVE,
|
||||||
|
|
||||||
|
PATHS.CATEGORY.CREATE,
|
||||||
|
PATHS.CATEGORY.EDIT,
|
||||||
|
PATHS.CATEGORY.REMOVE,
|
||||||
|
|
||||||
|
PATHS.API.CATEGORY.CREATE,
|
||||||
|
PATHS.API.CATEGORY.EDIT,
|
||||||
|
PATHS.API.CATEGORY.REMOVE,
|
||||||
|
|
||||||
|
PATHS.API.LINK.CREATE,
|
||||||
|
PATHS.API.LINK.EDIT,
|
||||||
|
PATHS.API.LINK.REMOVE,
|
||||||
|
],
|
||||||
|
};
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
const PATHS = {
|
const PATHS = {
|
||||||
LOGIN: "/signin",
|
LOGIN: "/signin",
|
||||||
|
LOGOUT: "/signout",
|
||||||
HOME: "/",
|
HOME: "/",
|
||||||
CATEGORY: {
|
CATEGORY: {
|
||||||
CREATE: "/category/create",
|
CREATE: "/category/create",
|
||||||
@@ -13,14 +14,14 @@ const PATHS = {
|
|||||||
},
|
},
|
||||||
API: {
|
API: {
|
||||||
CATEGORY: {
|
CATEGORY: {
|
||||||
CREATE: "/category/create",
|
CREATE: "/api/category/create",
|
||||||
EDIT: "/category/edit",
|
EDIT: "/api/category/edit",
|
||||||
REMOVE: "/category/remove",
|
REMOVE: "/api/category/remove",
|
||||||
},
|
},
|
||||||
LINK: {
|
LINK: {
|
||||||
CREATE: "/link/create",
|
CREATE: "/api/link/create",
|
||||||
EDIT: "/link/edit",
|
EDIT: "/api/link/edit",
|
||||||
REMOVE: "/link/remove",
|
REMOVE: "/api/link/remove",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
NOT_FOUND: "/404",
|
NOT_FOUND: "/404",
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
import { PrismaClient } from "@prisma/client";
|
import { PrismaClient } from "@prisma/client";
|
||||||
import PATHS from "constants/paths";
|
import PATHS from "constants/paths";
|
||||||
import NextAuth from "next-auth";
|
import NextAuth, { NextAuthOptions } from "next-auth";
|
||||||
import GoogleProvider from "next-auth/providers/google";
|
import GoogleProvider from "next-auth/providers/google";
|
||||||
|
|
||||||
const prisma = new PrismaClient();
|
const prisma = new PrismaClient();
|
||||||
|
|
||||||
export default NextAuth({
|
// TODO: refactor auth
|
||||||
|
export const authOptions = {
|
||||||
providers: [
|
providers: [
|
||||||
GoogleProvider({
|
GoogleProvider({
|
||||||
clientId: process.env.GOOGLE_CLIENT_ID,
|
clientId: process.env.GOOGLE_CLIENT_ID,
|
||||||
@@ -20,24 +21,33 @@ export default NextAuth({
|
|||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
callbacks: {
|
callbacks: {
|
||||||
|
async session({ session }) {
|
||||||
|
// check if stored in session still exist in db
|
||||||
|
await prisma.user.findFirstOrThrow({
|
||||||
|
where: { email: session.user.email },
|
||||||
|
});
|
||||||
|
return session;
|
||||||
|
},
|
||||||
async signIn({ account: accountParam, profile }) {
|
async signIn({ account: accountParam, profile }) {
|
||||||
// TODO: Auth
|
|
||||||
console.log(
|
console.log(
|
||||||
"Connexion via",
|
"[AUTH]",
|
||||||
accountParam.provider,
|
"User",
|
||||||
accountParam.providerAccountId,
|
profile.name,
|
||||||
profile.email,
|
"attempt to log in with",
|
||||||
profile.name
|
accountParam.provider
|
||||||
);
|
);
|
||||||
if (accountParam.provider !== "google") {
|
if (accountParam.provider !== "google") {
|
||||||
|
console.log("[AUTH]", "User", profile.name, "rejeced : bad provider");
|
||||||
return (
|
return (
|
||||||
PATHS.LOGIN +
|
PATHS.LOGIN +
|
||||||
"?error=" +
|
"?error=" +
|
||||||
encodeURI("Authentitifcation via Google requise")
|
encodeURI("Authentitifcation via Google requise")
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const email = profile?.email;
|
const email = profile?.email;
|
||||||
if (email === "") {
|
if (email === "") {
|
||||||
|
console.log("[AUTH]", "User", profile.name, "rejeced : missing email");
|
||||||
return (
|
return (
|
||||||
PATHS.LOGIN +
|
PATHS.LOGIN +
|
||||||
"?error=" +
|
"?error=" +
|
||||||
@@ -48,6 +58,12 @@ export default NextAuth({
|
|||||||
}
|
}
|
||||||
const googleId = profile?.sub;
|
const googleId = profile?.sub;
|
||||||
if (googleId === "") {
|
if (googleId === "") {
|
||||||
|
console.log(
|
||||||
|
"[AUTH]",
|
||||||
|
"User",
|
||||||
|
profile.name,
|
||||||
|
"rejeced : missing google id"
|
||||||
|
);
|
||||||
return (
|
return (
|
||||||
PATHS.LOGIN +
|
PATHS.LOGIN +
|
||||||
"?error=" +
|
"?error=" +
|
||||||
@@ -74,6 +90,13 @@ export default NextAuth({
|
|||||||
});
|
});
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.log(
|
||||||
|
"[AUTH]",
|
||||||
|
"User",
|
||||||
|
profile.name,
|
||||||
|
"rejeced : not authorized"
|
||||||
|
);
|
||||||
return (
|
return (
|
||||||
PATHS.LOGIN +
|
PATHS.LOGIN +
|
||||||
"?error=" +
|
"?error=" +
|
||||||
@@ -82,9 +105,11 @@ export default NextAuth({
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
|
console.log("[AUTH]", "User", profile.name, "success");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
console.log("[AUTH]", "User", profile.name, "unhandled error");
|
||||||
console.error(error);
|
console.error(error);
|
||||||
return (
|
return (
|
||||||
PATHS.LOGIN +
|
PATHS.LOGIN +
|
||||||
@@ -97,8 +122,10 @@ export default NextAuth({
|
|||||||
pages: {
|
pages: {
|
||||||
signIn: PATHS.LOGIN,
|
signIn: PATHS.LOGIN,
|
||||||
error: PATHS.LOGIN,
|
error: PATHS.LOGIN,
|
||||||
|
signOut: PATHS.LOGOUT,
|
||||||
},
|
},
|
||||||
session: {
|
session: {
|
||||||
maxAge: 60 * 60 * 6, // Session de 6 heures
|
maxAge: 60 * 60 * 6, // Session de 6 heures
|
||||||
},
|
},
|
||||||
});
|
} as NextAuthOptions;
|
||||||
|
export default NextAuth(authOptions);
|
||||||
|
|||||||
@@ -1,10 +1,15 @@
|
|||||||
import { NextApiRequest, NextApiResponse } from "next";
|
import { NextApiRequest, NextApiResponse } from "next";
|
||||||
|
import { getServerSession } from "next-auth/next";
|
||||||
|
import { authOptions } from "../auth/[...nextauth]";
|
||||||
|
|
||||||
import prisma from "utils/prisma";
|
import prisma from "utils/prisma";
|
||||||
|
|
||||||
export default async function handler(
|
export default async function handler(
|
||||||
req: NextApiRequest,
|
req: NextApiRequest,
|
||||||
res: NextApiResponse
|
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;
|
const name = req.body?.name as string;
|
||||||
|
|
||||||
if (!name) {
|
if (!name) {
|
||||||
@@ -30,8 +35,20 @@ export default async function handler(
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
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 category = await prisma.category.create({
|
const category = await prisma.category.create({
|
||||||
data: { name },
|
data: { name, authorId },
|
||||||
});
|
});
|
||||||
return res.status(200).send({
|
return res.status(200).send({
|
||||||
success: "Catégorie créée avec succès",
|
success: "Catégorie créée avec succès",
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
|
import { getServerSession } from "next-auth/next";
|
||||||
import { Provider } from "next-auth/providers";
|
import { Provider } from "next-auth/providers";
|
||||||
import { getProviders, getSession, signIn } from "next-auth/react";
|
import { getProviders, signIn } from "next-auth/react";
|
||||||
import { NextSeo } from "next-seo";
|
import { NextSeo } from "next-seo";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
|
|
||||||
@@ -7,6 +8,7 @@ import MessageManager from "components/MessageManager/MessageManager";
|
|||||||
import PATHS from "constants/paths";
|
import PATHS from "constants/paths";
|
||||||
|
|
||||||
import styles from "styles/login.module.scss";
|
import styles from "styles/login.module.scss";
|
||||||
|
import { authOptions } from "./api/auth/[...nextauth]";
|
||||||
|
|
||||||
interface SignInProps {
|
interface SignInProps {
|
||||||
providers: Provider[];
|
providers: Provider[];
|
||||||
@@ -36,8 +38,8 @@ export default function SignIn({ providers }: SignInProps) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getServerSideProps(context) {
|
export async function getServerSideProps({ req, res }) {
|
||||||
const session = await getSession(context);
|
const session = await getServerSession(req, res, authOptions);
|
||||||
if (session) {
|
if (session) {
|
||||||
return {
|
return {
|
||||||
redirect: {
|
redirect: {
|
||||||
|
|||||||
Reference in New Issue
Block a user