init model rbac
This commit is contained in:
parent
0205f6b5c7
commit
a468f3db68
|
@ -17,7 +17,7 @@ import { NavPreMain } from "./navigations/nav-pre-main";
|
||||||
import { navData } from "@/prisma/data/nav";
|
import { navData } from "@/prisma/data/nav";
|
||||||
import { TeamSwitcher } from "../../../_components/team-switcher";
|
import { TeamSwitcher } from "../../../_components/team-switcher";
|
||||||
import { useGetCurrentUserQuery } from "../dashboard/user-management/_queries/queries";
|
import { useGetCurrentUserQuery } from "../dashboard/user-management/_queries/queries";
|
||||||
import { useUserStore } from "@/app/_utils/zustand/stores/user";
|
import { useUserStore } from "@/app/_lib/zustand/stores/user";
|
||||||
import { useUserActionsHandler } from "../dashboard/user-management/_handlers/actions/use-user-actions";
|
import { useUserActionsHandler } from "../dashboard/user-management/_handlers/actions/use-user-actions";
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -30,7 +30,7 @@ import { SettingsDialog } from "../settings/setting-dialog";
|
||||||
import { AlertDialog, AlertDialogTrigger, AlertDialogContent, AlertDialogHeader, AlertDialogFooter, AlertDialogTitle, AlertDialogDescription, AlertDialogCancel, AlertDialogAction } from "@/app/_components/ui/alert-dialog";
|
import { AlertDialog, AlertDialogTrigger, AlertDialogContent, AlertDialogHeader, AlertDialogFooter, AlertDialogTitle, AlertDialogDescription, AlertDialogCancel, AlertDialogAction } from "@/app/_components/ui/alert-dialog";
|
||||||
import { useSignOutHandler } from "@/app/(pages)/(auth)/_handlers/use-sign-out";
|
import { useSignOutHandler } from "@/app/(pages)/(auth)/_handlers/use-sign-out";
|
||||||
import { useGetCurrentUserQuery } from "../../dashboard/user-management/_queries/queries";
|
import { useGetCurrentUserQuery } from "../../dashboard/user-management/_queries/queries";
|
||||||
import { useUserStore } from "@/app/_utils/zustand/stores/user";
|
import { useUserStore } from "@/app/_lib/zustand/stores/user";
|
||||||
|
|
||||||
interface NavUserProps {
|
interface NavUserProps {
|
||||||
user: IUserSchema | null;
|
user: IUserSchema | null;
|
||||||
|
|
|
@ -30,7 +30,7 @@ import { ImageIcon, Loader2 } from "lucide-react";
|
||||||
import { createClient } from "@/app/_utils/supabase/client";
|
import { createClient } from "@/app/_utils/supabase/client";
|
||||||
import { getFullName, getInitials } from "@/app/_utils/common";
|
import { getFullName, getInitials } from "@/app/_utils/common";
|
||||||
import { useProfileFormHandlers } from "../dashboard/user-management/_handlers/use-profile-form";
|
import { useProfileFormHandlers } from "../dashboard/user-management/_handlers/use-profile-form";
|
||||||
import { CTexts } from "@/app/_lib/const/texts";
|
import { CTexts } from "@/app/_utils/const/texts";
|
||||||
|
|
||||||
// Profile update form schema
|
// Profile update form schema
|
||||||
const profileFormSchema = z.object({
|
const profileFormSchema = z.object({
|
||||||
|
|
|
@ -32,7 +32,7 @@ import {
|
||||||
updateUser,
|
updateUser,
|
||||||
} from "@/app/(pages)/(admin)/dashboard/user-management/action";
|
} from "@/app/(pages)/(admin)/dashboard/user-management/action";
|
||||||
import { useProfileFormHandlers } from "../../dashboard/user-management/_handlers/use-profile-form";
|
import { useProfileFormHandlers } from "../../dashboard/user-management/_handlers/use-profile-form";
|
||||||
import { CTexts } from "@/app/_lib/const/texts";
|
import { CTexts } from "@/app/_utils/const/texts";
|
||||||
|
|
||||||
const profileFormSchema = z.object({
|
const profileFormSchema = z.object({
|
||||||
username: z.string().nullable().optional(),
|
username: z.string().nullable().optional(),
|
||||||
|
|
|
@ -36,7 +36,7 @@ import NotificationsSetting from "./notification-settings";
|
||||||
import PreferencesSettings from "./preference-settings";
|
import PreferencesSettings from "./preference-settings";
|
||||||
import ImportData from "./import-data";
|
import ImportData from "./import-data";
|
||||||
import { IUserSchema } from "@/src/entities/models/users/users.model";
|
import { IUserSchema } from "@/src/entities/models/users/users.model";
|
||||||
import { useUserStore } from "@/app/_utils/zustand/stores/user";
|
import { useUserStore } from "@/app/_lib/zustand/stores/user";
|
||||||
|
|
||||||
interface SettingsDialogProps {
|
interface SettingsDialogProps {
|
||||||
trigger: React.ReactNode;
|
trigger: React.ReactNode;
|
||||||
|
|
|
@ -13,7 +13,7 @@ import { RadioGroup, RadioGroupItem } from "@/app/_components/ui/radio-group"
|
||||||
import { Label } from "@/app/_components/ui/label"
|
import { Label } from "@/app/_components/ui/label"
|
||||||
import { Input } from "@/app/_components/ui/input"
|
import { Input } from "@/app/_components/ui/input"
|
||||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/app/_components/ui/select"
|
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/app/_components/ui/select"
|
||||||
import { ValidBanDuration } from "@/app/_lib/types/ban-duration"
|
import { ValidBanDuration } from "@/app/_utils/types/ban-duration"
|
||||||
import { toast } from "sonner"
|
import { toast } from "sonner"
|
||||||
|
|
||||||
interface BanUserDialogProps {
|
interface BanUserDialogProps {
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
import { useState } from "react"
|
import { useState } from "react"
|
||||||
import { useBanUserMutation } from "../../_queries/mutations"
|
import { useBanUserMutation } from "../../_queries/mutations"
|
||||||
import type { ValidBanDuration } from "@/app/_lib/types/ban-duration"
|
import type { ValidBanDuration } from "@/app/_utils/types/ban-duration"
|
||||||
import { toast } from "sonner"
|
import { toast } from "sonner"
|
||||||
import { useUserActionsHandler } from "./use-user-actions"
|
import { useUserActionsHandler } from "./use-user-actions"
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { useState } from "react"
|
import { useState } from "react"
|
||||||
import { useBanUserMutation, useDeleteUserMutation, useUnbanUserMutation } from "../_queries/mutations"
|
import { useBanUserMutation, useDeleteUserMutation, useUnbanUserMutation } from "../_queries/mutations"
|
||||||
import { ValidBanDuration } from "@/app/_lib/types/ban-duration"
|
import { ValidBanDuration } from "@/app/_utils/types/ban-duration"
|
||||||
import { useQueryClient } from "@tanstack/react-query"
|
import { useQueryClient } from "@tanstack/react-query"
|
||||||
import { toast } from "sonner"
|
import { toast } from "sonner"
|
||||||
import { useForm } from "react-hook-form"
|
import { useForm } from "react-hook-form"
|
||||||
|
|
|
@ -2,7 +2,7 @@ import { IUserSchema } from "@/src/entities/models/users/users.model";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import { useBanUserMutation, useDeleteUserMutation, useUnbanUserMutation } from "../_queries/mutations";
|
import { useBanUserMutation, useDeleteUserMutation, useUnbanUserMutation } from "../_queries/mutations";
|
||||||
import { useSendMagicLinkMutation, useSendPasswordRecoveryMutation } from "@/app/(pages)/(auth)/_queries/mutations";
|
import { useSendMagicLinkMutation, useSendPasswordRecoveryMutation } from "@/app/(pages)/(auth)/_queries/mutations";
|
||||||
import { ValidBanDuration } from "@/app/_lib/types/ban-duration";
|
import { ValidBanDuration } from "@/app/_utils/types/ban-duration";
|
||||||
import { copyItem } from "@/app/_utils/common";
|
import { copyItem } from "@/app/_utils/common";
|
||||||
import { useQueryClient } from "@tanstack/react-query";
|
import { useQueryClient } from "@tanstack/react-query";
|
||||||
import { useUserActionsHandler } from "./actions/use-user-actions";
|
import { useUserActionsHandler } from "./actions/use-user-actions";
|
||||||
|
|
|
@ -11,8 +11,8 @@ import { z } from "zod"
|
||||||
import { useUnbanUserMutation, useUpdateUserMutation, useUploadAvatarMutation } from "../_queries/mutations"
|
import { useUnbanUserMutation, useUpdateUserMutation, useUploadAvatarMutation } from "../_queries/mutations"
|
||||||
import { useQueryClient } from "@tanstack/react-query"
|
import { useQueryClient } from "@tanstack/react-query"
|
||||||
import { toast } from "sonner"
|
import { toast } from "sonner"
|
||||||
import { CNumbers } from "@/app/_lib/const/numbers"
|
import { CNumbers } from "@/app/_utils/const/numbers"
|
||||||
import { CTexts } from "@/app/_lib/const/texts"
|
import { CTexts } from "@/app/_utils/const/texts"
|
||||||
import { useUserActionsHandler } from "./actions/use-user-actions"
|
import { useUserActionsHandler } from "./actions/use-user-actions"
|
||||||
|
|
||||||
// Profile update form schema
|
// Profile update form schema
|
||||||
|
|
|
@ -5,7 +5,7 @@ import { IUpdateUserSchema } from "@/src/entities/models/users/update-user.model
|
||||||
import { ICredentialsInviteUserSchema } from "@/src/entities/models/users/invite-user.model";
|
import { ICredentialsInviteUserSchema } from "@/src/entities/models/users/invite-user.model";
|
||||||
import { IBanUserSchema, ICredentialsBanUserSchema } from "@/src/entities/models/users/ban-user.model";
|
import { IBanUserSchema, ICredentialsBanUserSchema } from "@/src/entities/models/users/ban-user.model";
|
||||||
import { ICredentialsUnbanUserSchema } from "@/src/entities/models/users/unban-user.model";
|
import { ICredentialsUnbanUserSchema } from "@/src/entities/models/users/unban-user.model";
|
||||||
import { ValidBanDuration } from "@/app/_lib/types/ban-duration";
|
import { ValidBanDuration } from "@/app/_utils/types/ban-duration";
|
||||||
|
|
||||||
export const useCreateUserMutation = () => {
|
export const useCreateUserMutation = () => {
|
||||||
return useMutation({
|
return useMutation({
|
||||||
|
|
|
@ -6,7 +6,7 @@ import { useForm } from "react-hook-form";
|
||||||
import { ISignInPasswordlessSchema, SignInPasswordlessSchema } from "@/src/entities/models/auth/sign-in.model";
|
import { ISignInPasswordlessSchema, SignInPasswordlessSchema } from "@/src/entities/models/auth/sign-in.model";
|
||||||
import { zodResolver } from "@hookform/resolvers/zod";
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
import { createRoute } from "@/app/_utils/common";
|
import { createRoute } from "@/app/_utils/common";
|
||||||
import { ROUTES } from "@/app/_lib/const/routes";
|
import { ROUTES } from "@/app/_utils/const/routes";
|
||||||
|
|
||||||
export function useSignInPasswordlessHandler() {
|
export function useSignInPasswordlessHandler() {
|
||||||
const { mutateAsync: signIn, isPending, error: queryError } = useSignInPasswordlessMutation();
|
const { mutateAsync: signIn, isPending, error: queryError } = useSignInPasswordlessMutation();
|
||||||
|
|
|
@ -6,7 +6,7 @@ import { ISignInWithPasswordSchema, SignInWithPasswordSchema } from "@/src/entit
|
||||||
import { zodResolver } from "@hookform/resolvers/zod";
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import { createRoute } from "@/app/_utils/common";
|
import { createRoute } from "@/app/_utils/common";
|
||||||
import { ROUTES } from "@/app/_lib/const/routes";
|
import { ROUTES } from "@/app/_utils/const/routes";
|
||||||
|
|
||||||
export const useSignInWithPasswordHandler = () => {
|
export const useSignInWithPasswordHandler = () => {
|
||||||
const { mutateAsync: signInWithPassword, isPending, error: queryError } = useSignInWithPasswordMutation();
|
const { mutateAsync: signInWithPassword, isPending, error: queryError } = useSignInWithPasswordMutation();
|
||||||
|
|
|
@ -10,7 +10,7 @@ import { useSignInPasswordlessHandler } from "../../_handlers/use-sign-in-passwo
|
||||||
import { useSignInWithPasswordHandler } from "../../_handlers/use-sign-in-with-password";
|
import { useSignInWithPasswordHandler } from "../../_handlers/use-sign-in-with-password";
|
||||||
import { useNavigations } from "@/app/_hooks/use-navigations";
|
import { useNavigations } from "@/app/_hooks/use-navigations";
|
||||||
import { createRoute } from "@/app/_utils/common";
|
import { createRoute } from "@/app/_utils/common";
|
||||||
import { ROUTES } from "@/app/_lib/const/routes";
|
import { ROUTES } from "@/app/_utils/const/routes";
|
||||||
|
|
||||||
export function SignInWithPasswordForm({
|
export function SignInWithPasswordForm({
|
||||||
className,
|
className,
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { Geist } from "next/font/google";
|
import { Geist } from "next/font/google";
|
||||||
import { ThemeProvider } from "next-themes";
|
import { ThemeProvider } from "next-themes";
|
||||||
import "@/app/_styles/globals.css";
|
import "@/app/_styles/globals.css";
|
||||||
import ReactQueryProvider from "@/app/_utils/react-query-provider";
|
import ReactQueryProvider from "@/app/_lib/react-query-provider";
|
||||||
import { Toaster } from "@/app/_components/ui/sonner";
|
import { Toaster } from "@/app/_components/ui/sonner";
|
||||||
|
|
||||||
const defaultUrl = process.env.VERCEL_URL
|
const defaultUrl = process.env.VERCEL_URL
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
import { IUserSchema } from "@/src/entities/models/users/users.model"
|
import { IUserSchema } from "@/src/entities/models/users/users.model"
|
||||||
|
|
||||||
type Role = "viewer" | "editor" | "admin";
|
type Role = "viewer" | "staff" | "admin";
|
||||||
|
|
||||||
const PERMISSIONS: Record<Role, string[]> = {
|
const PERMISSIONS: Record<Role, string[]> = {
|
||||||
viewer: ["view:post"],
|
viewer: ["view:post"],
|
||||||
editor: ["view:post", "edit:post"],
|
staff: ["view:post", "edit:post"],
|
||||||
admin: ["view:post", "create:post", "edit:post", "delete:post"],
|
admin: ["view:post", "create:post", "edit:post", "delete:post"],
|
||||||
};
|
};
|
||||||
export const CheckPermission = (user: IUserSchema, action: string, resource: string) => {
|
export const CheckPermission = (user: IUserSchema, action: string, resource: string) => {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { format } from "date-fns";
|
import { format } from "date-fns";
|
||||||
import { redirect } from "next/navigation";
|
import { redirect } from "next/navigation";
|
||||||
import { DateFormatOptions, DateFormatPattern } from "../_lib/types/date-format.interface";
|
import { DateFormatOptions, DateFormatPattern } from "./types/date-format.interface";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import { IUserSchema } from "@/src/entities/models/users/users.model";
|
import { IUserSchema } from "@/src/entities/models/users/users.model";
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { CTexts } from "../_lib/const/texts";
|
import { CTexts } from "./const/texts";
|
||||||
import { CRegex } from "../_lib/const/regex";
|
import { CRegex } from "./const/regex";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validates if a given phone number starts with any of the predefined prefixes.
|
* Validates if a given phone number starts with any of the predefined prefixes.
|
||||||
|
|
|
@ -147,7 +147,7 @@ model profiles {
|
||||||
|
|
||||||
model users {
|
model users {
|
||||||
id String @id @default(dbgenerated("gen_random_uuid()")) @db.Uuid
|
id String @id @default(dbgenerated("gen_random_uuid()")) @db.Uuid
|
||||||
role roles @default(user)
|
roles_id String @db.Uuid
|
||||||
email String @unique @db.VarChar(255)
|
email String @unique @db.VarChar(255)
|
||||||
phone String? @unique @db.VarChar(20)
|
phone String? @unique @db.VarChar(20)
|
||||||
encrypted_password String? @db.VarChar(255)
|
encrypted_password String? @db.VarChar(255)
|
||||||
|
@ -163,11 +163,44 @@ model users {
|
||||||
banned_until DateTime? @db.Timestamptz(6)
|
banned_until DateTime? @db.Timestamptz(6)
|
||||||
is_anonymous Boolean @default(false)
|
is_anonymous Boolean @default(false)
|
||||||
profile profiles?
|
profile profiles?
|
||||||
|
role roles @relation(fields: [roles_id], references: [id])
|
||||||
|
|
||||||
@@index([is_anonymous])
|
@@index([is_anonymous])
|
||||||
@@index([created_at])
|
@@index([created_at])
|
||||||
@@index([updated_at])
|
@@index([updated_at])
|
||||||
@@index([role])
|
}
|
||||||
|
|
||||||
|
model roles {
|
||||||
|
id String @id @default(dbgenerated("gen_random_uuid()")) @db.Uuid
|
||||||
|
name String @unique @db.VarChar(255)
|
||||||
|
description String?
|
||||||
|
permissions permissions[]
|
||||||
|
users users[]
|
||||||
|
created_at DateTime @default(now()) @db.Timestamptz(6)
|
||||||
|
updated_at DateTime @default(now()) @db.Timestamptz(6)
|
||||||
|
}
|
||||||
|
|
||||||
|
model resources {
|
||||||
|
id String @id @default(dbgenerated("gen_random_uuid()")) @db.Uuid
|
||||||
|
name String @unique @db.VarChar(255)
|
||||||
|
description String?
|
||||||
|
instance_role String?
|
||||||
|
relations String?
|
||||||
|
attributes Json?
|
||||||
|
permissions permissions[]
|
||||||
|
created_at DateTime @default(now()) @db.Timestamptz(6)
|
||||||
|
updated_at DateTime @default(now()) @db.Timestamptz(6)
|
||||||
|
}
|
||||||
|
|
||||||
|
model permissions {
|
||||||
|
id String @id @default(dbgenerated("gen_random_uuid()")) @db.Uuid
|
||||||
|
action String
|
||||||
|
resource_id String
|
||||||
|
role_id String
|
||||||
|
resource resources @relation(fields: [resource_id], references: [id])
|
||||||
|
role roles @relation(fields: [role_id], references: [id])
|
||||||
|
created_at DateTime @default(now()) @db.Timestamptz(6)
|
||||||
|
updated_at DateTime @updatedAt @db.Timestamptz(6)
|
||||||
}
|
}
|
||||||
|
|
||||||
enum crime_rates {
|
enum crime_rates {
|
||||||
|
@ -182,11 +215,11 @@ enum crime_status {
|
||||||
resolved
|
resolved
|
||||||
}
|
}
|
||||||
|
|
||||||
enum roles {
|
// enum roles {
|
||||||
admin
|
// admin
|
||||||
staff
|
// staff
|
||||||
user
|
// user
|
||||||
}
|
// }
|
||||||
|
|
||||||
enum status_contact_messages {
|
enum status_contact_messages {
|
||||||
new
|
new
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { ServerActionErrorParams } from "@/app/_lib/types/error-server-action.interface";
|
import { ServerActionErrorParams } from "@/app/_utils/types/error-server-action.interface";
|
||||||
|
|
||||||
export class DatabaseOperationError extends Error {
|
export class DatabaseOperationError extends Error {
|
||||||
constructor(message: string, options?: ErrorOptions) {
|
constructor(message: string, options?: ErrorOptions) {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// Schema Zod untuk validasi runtime
|
// Schema Zod untuk validasi runtime
|
||||||
import { CRegex } from "@/app/_lib/const/regex";
|
import { CRegex } from "@/app/_utils/const/regex";
|
||||||
import { ValidBanDuration } from "@/app/_lib/types/ban-duration";
|
import { ValidBanDuration } from "@/app/_utils/types/ban-duration";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
export const BanDurationSchema = z.custom<ValidBanDuration>(
|
export const BanDurationSchema = z.custom<ValidBanDuration>(
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { CNumbers } from "@/app/_lib/const/numbers";
|
import { CNumbers } from "@/app/_utils/const/numbers";
|
||||||
import { CTexts } from "@/app/_lib/const/texts";
|
import { CTexts } from "@/app/_utils/const/texts";
|
||||||
import { phonePrefixValidation, phoneRegexValidation } from "@/app/_utils/validation";
|
import { phonePrefixValidation, phoneRegexValidation } from "@/app/_utils/validation";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { CNumbers } from "@/app/_lib/const/numbers";
|
import { CNumbers } from "@/app/_utils/const/numbers";
|
||||||
import { CTexts } from "@/app/_lib/const/texts";
|
import { CTexts } from "@/app/_utils/const/texts";
|
||||||
import { IInstrumentationService } from "@/src/application/services/instrumentation.service.interface";
|
import { IInstrumentationService } from "@/src/application/services/instrumentation.service.interface";
|
||||||
import { IUploadAvatarUseCase } from "@/src/application/use-cases/users/upload-avatar.use-case";
|
import { IUploadAvatarUseCase } from "@/src/application/use-cases/users/upload-avatar.use-case";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
Loading…
Reference in New Issue