mirror of
https://github.com/Portabase/portabase.git
synced 2026-07-14 11:16:13 +02:00
User role access.
This commit is contained in:
@@ -0,0 +1,12 @@
|
||||
/*
|
||||
Warnings:
|
||||
|
||||
- Added the required column `role` to the `users` table without a default value. This is not possible if the table is not empty.
|
||||
|
||||
*/
|
||||
-- CreateEnum
|
||||
CREATE TYPE "Role" AS ENUM ('pending', 'user', 'admin');
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "users" DROP COLUMN "role",
|
||||
ADD COLUMN "role" "Role" NOT NULL;
|
||||
@@ -59,7 +59,7 @@ model User {
|
||||
email String? @unique
|
||||
emailVerified DateTime? @map("email_verified")
|
||||
image String?
|
||||
role String?
|
||||
role Role
|
||||
password String?
|
||||
authMethod String? @map("auth_method")
|
||||
createdAt DateTime @default(now()) @map("created_at")
|
||||
@@ -71,6 +71,12 @@ model User {
|
||||
@@map("users")
|
||||
}
|
||||
|
||||
enum Role {
|
||||
pending
|
||||
user
|
||||
admin
|
||||
}
|
||||
|
||||
model Agent {
|
||||
id String @id @default(cuid())
|
||||
slug String @unique
|
||||
|
||||
+41
-21
@@ -5,9 +5,7 @@ import Credentials from "next-auth/providers/credentials";
|
||||
import {env} from "@/env.mjs";
|
||||
import GoogleProvider from "next-auth/providers/google";
|
||||
|
||||
class InvalidLoginError extends CredentialsSignin {
|
||||
code = "Invalid identifier or password"
|
||||
}
|
||||
|
||||
|
||||
export const {handlers, auth: baseAuth, signIn, signOut} = NextAuth({
|
||||
adapter: PrismaAdapter(prisma),
|
||||
@@ -32,7 +30,7 @@ export const {handlers, auth: baseAuth, signIn, signOut} = NextAuth({
|
||||
email: credentials.email,
|
||||
}
|
||||
})
|
||||
if (!user) {
|
||||
if (!user || user.role === "pending") {
|
||||
return null
|
||||
}
|
||||
const isValid = await argon2.verify(user.password, credentials.password)
|
||||
@@ -46,12 +44,22 @@ export const {handlers, auth: baseAuth, signIn, signOut} = NextAuth({
|
||||
clientId: env.AUTH_GOOGLE_ID,
|
||||
clientSecret: env.AUTH_GOOGLE_SECRET,
|
||||
allowDangerousEmailAccountLinking: true,
|
||||
profile(profile) {
|
||||
async profile(profile) {
|
||||
|
||||
const users = await prisma.user.findMany({
|
||||
where: {
|
||||
deleted: {not: true},
|
||||
}
|
||||
})
|
||||
const role = users.length > 0 ? "pending" : "admin"
|
||||
|
||||
|
||||
return {
|
||||
// role: profile.email === "soluce.technologies@gmail.com" ? "admin" : "user",
|
||||
role: role,
|
||||
name: profile.name,
|
||||
email: profile.email,
|
||||
image: profile.picture,
|
||||
email_verified: profile.email_verified,
|
||||
authMethod: "google",
|
||||
}
|
||||
},
|
||||
@@ -81,26 +89,38 @@ export const {handlers, auth: baseAuth, signIn, signOut} = NextAuth({
|
||||
session.user = token;
|
||||
return session;
|
||||
},
|
||||
async signIn({ account, user }) {
|
||||
console.log(account)
|
||||
// const authMethod = account.provider === 'credentials' ? 'credentials' : 'oauth';
|
||||
user = await prisma.user.findFirst({
|
||||
where: {
|
||||
email: user.email,
|
||||
}
|
||||
})
|
||||
if (!user) {
|
||||
return true
|
||||
async signIn({ account, user, profile }) {
|
||||
const existingUser = await prisma.user.findFirst({
|
||||
where: { email: user.email },
|
||||
});
|
||||
|
||||
if (!existingUser) {
|
||||
// Create a new user with a pending role
|
||||
await prisma.user.create({
|
||||
data: {
|
||||
email: user.email,
|
||||
name: user.name,
|
||||
image: user.image,
|
||||
role: "pending",
|
||||
authMethod: account.provider,
|
||||
},
|
||||
});
|
||||
return false; // Prevent login if role is pending
|
||||
}
|
||||
console.log(user)
|
||||
// Update the user in the database with the auth method
|
||||
|
||||
if (existingUser.role === "pending") {
|
||||
return false; // Prevent login if role is pending
|
||||
}
|
||||
|
||||
// Update auth method if user exists
|
||||
await prisma.user.update({
|
||||
where: { id: user.id },
|
||||
where: { id: existingUser.id },
|
||||
data: {
|
||||
authMethod: account.provider
|
||||
authMethod: account.provider,
|
||||
},
|
||||
});
|
||||
return true;
|
||||
|
||||
return true; // Allow login
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -11,11 +11,20 @@ export const registerUserAction = action
|
||||
const user = await prisma.user.findUnique({ where: { email: parsedInput.email } });
|
||||
console.log(user);
|
||||
if (!user && parsedInput.password === parsedInput.confirmPassword) {
|
||||
|
||||
const users = await prisma.user.findMany({
|
||||
where:{
|
||||
deleted: { not: true },
|
||||
}
|
||||
})
|
||||
const role = users.length > 0 ? "pending" : "admin"
|
||||
|
||||
const new_user = await prisma.user.create({
|
||||
data: {
|
||||
name: parsedInput.name,
|
||||
email: parsedInput.email,
|
||||
password: await hashPassword(parsedInput.password),
|
||||
role: role
|
||||
},
|
||||
});
|
||||
return {
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import {z} from "zod";
|
||||
|
||||
export const UserSchema = z.object({
|
||||
name: z.string(),
|
||||
email: z.string(),
|
||||
name: z.string().optional(),
|
||||
email: z.string().optional(),
|
||||
role: z.string().optional(),
|
||||
});
|
||||
|
||||
export type UserType = z.infer<typeof UserSchema>;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"use client"
|
||||
import {Tabs, TabsContent, TabsList, TabsTrigger} from "@/components/ui/tabs";
|
||||
import {DataTableWithPagination} from "@/components/wrappers/table/data-table-with-pagination";
|
||||
import {usersColumns} from "@/components/wrappers/Dashboard/Settings/SettingsTabs/columns-users";
|
||||
import {usersColumns} from "@/components/wrappers/Dashboard/Settings/SettingsUsersTab/columns-users";
|
||||
import {User, Settings} from "@prisma/client";
|
||||
import {backupColumns} from "@/features/backup/columns";
|
||||
import {SettingsEmailTab} from "@/components/wrappers/Dashboard/Settings/SettingsEmailTab/SettingsEmailTab";
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
"use client"
|
||||
|
||||
import {ColumnDef} from "@tanstack/react-table"
|
||||
import {Badge} from "@/components/ui/badge";
|
||||
import {User} from "@prisma/client";
|
||||
|
||||
export const usersColumns: ColumnDef<User>[] = [
|
||||
{
|
||||
accessorKey: "name",
|
||||
header: "Name"
|
||||
},
|
||||
{
|
||||
accessorKey: "email",
|
||||
header: "Email"
|
||||
},
|
||||
{
|
||||
accessorKey: "createdAt",
|
||||
header: "Created At",
|
||||
cell: ({row}) => {
|
||||
return new Date(row.getValue("createdAt")).toLocaleString("fr-FR");
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "authMethod",
|
||||
header: "Method",
|
||||
cell: ({row}) => {
|
||||
return <Badge variant="outline">{row.getValue("authMethod")}</Badge>
|
||||
},
|
||||
}
|
||||
]
|
||||
@@ -1,5 +1,5 @@
|
||||
import {DataTableWithPagination} from "@/components/wrappers/table/data-table-with-pagination";
|
||||
import {usersColumns} from "@/components/wrappers/Dashboard/Settings/SettingsTabs/columns-users";
|
||||
import {usersColumns} from "@/components/wrappers/Dashboard/Settings/SettingsUsersTab/columns-users";
|
||||
import {User} from "@prisma/client";
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
"use client"
|
||||
|
||||
import {ColumnDef} from "@tanstack/react-table"
|
||||
import {Badge} from "@/components/ui/badge";
|
||||
import {User} from "@prisma/client";
|
||||
import {updateUserAction} from "@/components/wrappers/Dashboard/Profile/UserForm/user-form.action";
|
||||
import {useMutation} from "@tanstack/react-query";
|
||||
import {toast} from "sonner";
|
||||
import {useRouter} from "next/navigation";
|
||||
import {useState} from "react";
|
||||
|
||||
export const usersColumns: ColumnDef<User>[] = [
|
||||
{
|
||||
accessorKey: "role",
|
||||
header: "Role",
|
||||
cell: ({row}) => {
|
||||
const router = useRouter();
|
||||
const [role, setRole] = useState<string>(row.getValue("role"))
|
||||
|
||||
const updateMutation = useMutation({
|
||||
mutationFn: () => updateUserAction({id: row.original.id, data: {role: role}}),
|
||||
onSuccess: () => {
|
||||
toast.success(`User updated successfully.`);
|
||||
router.refresh()
|
||||
|
||||
},
|
||||
onError: () => {
|
||||
toast.error(`An error occurred while updating user information.`);
|
||||
},
|
||||
});
|
||||
|
||||
const handleUpdateRole = async () => {
|
||||
const nextRole = role === "admin" ? "pending"
|
||||
: role === "pending" ? "user"
|
||||
: "admin";
|
||||
setRole(nextRole);
|
||||
await updateMutation.mutateAsync()
|
||||
};
|
||||
|
||||
return <Badge
|
||||
className="cursor-pointer"
|
||||
onClick={() => handleUpdateRole()}
|
||||
variant="outline">{role}</Badge>
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "name",
|
||||
header: "Name"
|
||||
},
|
||||
{
|
||||
accessorKey: "email",
|
||||
header: "Email"
|
||||
},
|
||||
{
|
||||
accessorKey: "createdAt",
|
||||
header: "Created At",
|
||||
cell: ({row}) => {
|
||||
return new Date(row.getValue("createdAt")).toLocaleString("fr-FR");
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "authMethod",
|
||||
header: "Method",
|
||||
cell: ({row}) => {
|
||||
return <Badge variant="outline">{row.getValue("authMethod")}</Badge>
|
||||
},
|
||||
}
|
||||
]
|
||||
Reference in New Issue
Block a user