Change permission into action-service pattern
This commit is contained in:
parent
d40ec6b5aa
commit
854b1f9b34
|
|
@ -1,24 +1,15 @@
|
|||
import checkMultiplePermissions from "@/modules/auth/utils/checkMultiplePermissions";
|
||||
import getAllPermissions from "@/modules/permission/actions/getAllPermissions";
|
||||
import getAllPermissions from "@/modules/permission/services/getAllPermissions";
|
||||
import PermissionsTable from "@/modules/permission/tables/PermissionTable/PermissionTable";
|
||||
import { Card, Stack, Title } from "@mantine/core";
|
||||
import { Metadata } from "next";
|
||||
import React from "react";
|
||||
|
||||
interface Props {
|
||||
searchParams: {
|
||||
detail?: string;
|
||||
edit?: string;
|
||||
delete?: string;
|
||||
create?: string;
|
||||
};
|
||||
}
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Permissions - Dashboard",
|
||||
};
|
||||
|
||||
export default async function RolesPage({ searchParams }: Props) {
|
||||
export default async function RolesPage() {
|
||||
const permissions = await checkMultiplePermissions({
|
||||
create: "permissions.create",
|
||||
readAll: "permissions.readAll",
|
||||
|
|
@ -27,14 +18,13 @@ export default async function RolesPage({ searchParams }: Props) {
|
|||
delete: "permissions.delete",
|
||||
});
|
||||
|
||||
const res = await getAllPermissions();
|
||||
if (!res.success) throw new Error("Error while fetch permission");
|
||||
const permissionsData = await getAllPermissions();
|
||||
|
||||
return (
|
||||
<Stack>
|
||||
<Title order={1}>Permissions</Title>
|
||||
<Card>
|
||||
<PermissionsTable permissions={permissions} permissionData={res.data} />
|
||||
<PermissionsTable permissions={permissions} data={permissionsData} />
|
||||
</Card>
|
||||
</Stack>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,28 +0,0 @@
|
|||
"use server";
|
||||
|
||||
import db from "@/core/db";
|
||||
import prisma from "@/db";
|
||||
import checkPermission from "@/modules/dashboard/services/checkPermission";
|
||||
import ServerResponseAction from "@/modules/dashboard/types/ServerResponseAction";
|
||||
import handleCatch from "@/modules/dashboard/utils/handleCatch";
|
||||
import unauthorized from "@/modules/dashboard/utils/unauthorized";
|
||||
import { revalidatePath } from "next/cache";
|
||||
|
||||
export default async function deletePermission(id: string): Promise<ServerResponseAction> {
|
||||
try {
|
||||
if (!(await checkPermission("permission.delete"))) unauthorized();
|
||||
const permission = await db.permission.delete({
|
||||
where: { id },
|
||||
});
|
||||
|
||||
|
||||
revalidatePath(".")
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: "The permission has been deleted successfully",
|
||||
};
|
||||
} catch (e: unknown) {
|
||||
return handleCatch(e)
|
||||
}
|
||||
}
|
||||
26
src/modules/permission/actions/deletePermissionAction.ts
Normal file
26
src/modules/permission/actions/deletePermissionAction.ts
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
"use server";
|
||||
|
||||
import ServerResponseAction from "@/modules/dashboard/types/ServerResponseAction";
|
||||
import handleCatch from "@/modules/dashboard/utils/handleCatch";
|
||||
import unauthorized from "@/modules/dashboard/utils/unauthorized";
|
||||
import { revalidatePath } from "next/cache";
|
||||
import deletePermission from "../services/deletePermission";
|
||||
import checkPermission from "@/modules/auth/utils/checkPermission";
|
||||
|
||||
export default async function deletePermissionAction(
|
||||
id: string
|
||||
): Promise<ServerResponseAction> {
|
||||
try {
|
||||
if (!(await checkPermission("permissions.delete"))) unauthorized();
|
||||
|
||||
await deletePermission(id);
|
||||
revalidatePath(".");
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: "The permission has been deleted successfully",
|
||||
};
|
||||
} catch (e: unknown) {
|
||||
return handleCatch(e);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,57 +0,0 @@
|
|||
"use server"
|
||||
import prisma from "@/db";
|
||||
import checkPermission from "@/modules/dashboard/services/checkPermission";
|
||||
import ServerResponseAction from "@/modules/dashboard/types/ServerResponseAction";
|
||||
import handleCatch from "@/modules/dashboard/utils/handleCatch";
|
||||
import unauthorized from "@/modules/dashboard/utils/unauthorized";
|
||||
import "server-only";
|
||||
import Permission from "../types/Permission";
|
||||
import db from "@/core/db";
|
||||
|
||||
/**
|
||||
* Retrieves all permissions along with the count of associated permissions and users.
|
||||
* Authorization check is performed for the operation.
|
||||
*
|
||||
* @returns An array of permission objects each including details and counts of related permissions and users.
|
||||
*/
|
||||
export default async function getAllPermissions(): Promise<ServerResponseAction<Permission[]>> {
|
||||
// Authorization check
|
||||
if (!(await checkPermission("permissions.readAll"))) {
|
||||
unauthorized();
|
||||
}
|
||||
|
||||
try {
|
||||
// Fetch permissions from the database
|
||||
const permissions = await db.permission.findMany({
|
||||
include: {
|
||||
_count: {
|
||||
select: {
|
||||
roles: true,
|
||||
directUsers: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// Transform the data into the desired format
|
||||
const permissionsData = permissions.map(
|
||||
({ id, code, name, description, isActive, _count }) => ({
|
||||
id,
|
||||
code,
|
||||
name,
|
||||
description,
|
||||
isActive,
|
||||
roleCount: _count.roles,
|
||||
//User count counts only direct user
|
||||
userCount: _count.directUsers,
|
||||
})
|
||||
);
|
||||
|
||||
return {
|
||||
success: true,
|
||||
data: permissionsData
|
||||
}
|
||||
} catch (error) {
|
||||
return handleCatch(error)
|
||||
}
|
||||
}
|
||||
34
src/modules/permission/actions/getAllPermissionsAction.ts
Normal file
34
src/modules/permission/actions/getAllPermissionsAction.ts
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
"use server";
|
||||
import ServerResponseAction from "@/modules/dashboard/types/ServerResponseAction";
|
||||
import handleCatch from "@/modules/dashboard/utils/handleCatch";
|
||||
import unauthorized from "@/modules/dashboard/utils/unauthorized";
|
||||
import Permission from "../types/Permission";
|
||||
import getAllPermissions from "../services/getAllPermissions";
|
||||
import checkPermission from "@/modules/auth/utils/checkPermission";
|
||||
|
||||
/**
|
||||
* Retrieves all permissions along with the count of associated permissions and users.
|
||||
* Authorization check is performed for the operation.
|
||||
*
|
||||
* @returns An array of permission objects each including details and counts of related permissions and users.
|
||||
*/
|
||||
export default async function getAllPermissionsAction(): Promise<
|
||||
ServerResponseAction<Permission[]>
|
||||
> {
|
||||
// Authorization check
|
||||
if (!(await checkPermission("permissions.readAll"))) {
|
||||
unauthorized();
|
||||
}
|
||||
|
||||
try {
|
||||
// Fetch permissions from the database
|
||||
const permissionsData = await getAllPermissions();
|
||||
|
||||
return {
|
||||
success: true,
|
||||
data: permissionsData,
|
||||
};
|
||||
} catch (error) {
|
||||
return handleCatch(error);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +1,10 @@
|
|||
"use server";
|
||||
|
||||
import db from "@/core/db";
|
||||
import prisma from "@/db";
|
||||
import checkPermission from "@/modules/dashboard/services/checkPermission";
|
||||
import checkPermission from "@/modules/auth/utils/checkPermission";
|
||||
import ServerResponseAction from "@/modules/dashboard/types/ServerResponseAction";
|
||||
import handleCatch from "@/modules/dashboard/utils/handleCatch";
|
||||
import unauthorized from "@/modules/dashboard/utils/unauthorized";
|
||||
import getPermissionById from "../services/getPermissionById";
|
||||
|
||||
interface Permission {
|
||||
id: string;
|
||||
|
|
@ -15,33 +14,16 @@ interface Permission {
|
|||
isActive: boolean;
|
||||
}
|
||||
|
||||
export default async function getPermissionById(
|
||||
export default async function getPermissionByIdAction(
|
||||
id: string
|
||||
): Promise<ServerResponseAction<Permission>> {
|
||||
try {
|
||||
if (!(await checkPermission("permissions.read"))) unauthorized();
|
||||
|
||||
const permission = await db.permission.findFirst({
|
||||
where: { id },
|
||||
select: {
|
||||
code: true,
|
||||
description: true,
|
||||
id: true,
|
||||
isActive: true,
|
||||
name: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (!permission) {
|
||||
return {
|
||||
success: false,
|
||||
message: "Permission not found",
|
||||
} as const;
|
||||
}
|
||||
const permission = await getPermissionById(id);
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: "Permission fetched successfully",
|
||||
data: permission,
|
||||
} as const;
|
||||
} catch (e) {
|
||||
|
|
@ -1,84 +0,0 @@
|
|||
"use server";
|
||||
|
||||
import permissionFormDataSchema, { PermissionFormData } from "../formSchemas/PermissionFormData";
|
||||
import mapObjectToFirstValue from "@/utils/mapObjectToFirstValue";
|
||||
import prisma from "@/db";
|
||||
import { revalidatePath } from "next/cache";
|
||||
import ServerResponseAction from "@/modules/dashboard/types/ServerResponseAction";
|
||||
import checkPermission from "@/modules/dashboard/services/checkPermission";
|
||||
import unauthorized from "@/modules/dashboard/utils/unauthorized";
|
||||
import DashboardError from "@/modules/dashboard/errors/DashboardError";
|
||||
import handleCatch from "@/modules/dashboard/utils/handleCatch";
|
||||
import db from "@/core/db";
|
||||
|
||||
/**
|
||||
* Upserts a permission based on the provided PermissionFormData.
|
||||
* If the permission already exists (determined by `id`), it updates the permission; otherwise, it creates a new permission.
|
||||
* Authorization checks are performed based on whether it's a create or update operation.
|
||||
*
|
||||
* @param data - The data for creating or updating the permission.
|
||||
* @returns An object containing the success status, message, and any errors.
|
||||
*/
|
||||
export default async function upsertPermission(
|
||||
data: PermissionFormData
|
||||
): Promise<ServerResponseAction> {
|
||||
try {
|
||||
const isInsert = !data.id;
|
||||
|
||||
// Authorization check
|
||||
const permissionType = isInsert ? "permission.create" : "permission.update";
|
||||
if (!(await checkPermission(permissionType))) {
|
||||
unauthorized();
|
||||
}
|
||||
|
||||
// Validate form data
|
||||
const validatedFields = permissionFormDataSchema.safeParse(data);
|
||||
if (!validatedFields.success) {
|
||||
throw new DashboardError({
|
||||
errorCode: "INVALID_FORM_DATA",
|
||||
formErrors: mapObjectToFirstValue(validatedFields.error.flatten().fieldErrors)
|
||||
})
|
||||
}
|
||||
const permissionData = {
|
||||
code: validatedFields.data.code,
|
||||
description: validatedFields.data.description,
|
||||
name: validatedFields.data.name,
|
||||
isActive: validatedFields.data.isActive,
|
||||
};
|
||||
|
||||
// Database operation
|
||||
if (isInsert) {
|
||||
if (await db.permission.findFirst({
|
||||
where: {
|
||||
code: permissionData.code
|
||||
}
|
||||
})){
|
||||
throw new DashboardError({
|
||||
errorCode: "INVALID_FORM_DATA",
|
||||
formErrors: {
|
||||
code: "The code is already exists"
|
||||
}
|
||||
})
|
||||
}
|
||||
await db.permission.create({ data: permissionData });
|
||||
} else {
|
||||
await db.permission.update({
|
||||
where: { id: validatedFields.data.id! },
|
||||
data: permissionData,
|
||||
});
|
||||
}
|
||||
|
||||
// Revalidate the cache
|
||||
revalidatePath(".");
|
||||
|
||||
// Return success message
|
||||
return {
|
||||
success: true,
|
||||
message: `Permission ${validatedFields.data.name} has been successfully ${
|
||||
isInsert ? "created" : "updated"
|
||||
}.`,
|
||||
};
|
||||
} catch (error) {
|
||||
return handleCatch(error)
|
||||
}
|
||||
}
|
||||
48
src/modules/permission/actions/upsertPermissionAction.ts
Normal file
48
src/modules/permission/actions/upsertPermissionAction.ts
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
"use server";
|
||||
|
||||
import { PermissionFormData } from "../formSchemas/PermissionFormData";
|
||||
import { revalidatePath } from "next/cache";
|
||||
import ServerResponseAction from "@/modules/dashboard/types/ServerResponseAction";
|
||||
import unauthorized from "@/modules/dashboard/utils/unauthorized";
|
||||
import handleCatch from "@/modules/dashboard/utils/handleCatch";
|
||||
import checkPermission from "@/modules/auth/utils/checkPermission";
|
||||
import upsertPermission from "../services/upsertPermission";
|
||||
|
||||
/**
|
||||
* Upserts a permission based on the provided PermissionFormData.
|
||||
* If the permission already exists (determined by `id`), it updates the permission; otherwise, it creates a new permission.
|
||||
* Authorization checks are performed based on whether it's a create or update operation.
|
||||
*
|
||||
* @param data - The data for creating or updating the permission.
|
||||
* @returns An object containing the success status, message, and any errors.
|
||||
*/
|
||||
export default async function upsertPermissionAction(
|
||||
data: PermissionFormData
|
||||
): Promise<ServerResponseAction> {
|
||||
try {
|
||||
const isInsert = !data.id;
|
||||
|
||||
// Authorization check
|
||||
const permissionType = isInsert
|
||||
? "permissions.create"
|
||||
: "permissions.update";
|
||||
if (!(await checkPermission(permissionType))) {
|
||||
unauthorized();
|
||||
}
|
||||
|
||||
const result = await upsertPermission(data);
|
||||
|
||||
// Revalidate the cache
|
||||
revalidatePath(".");
|
||||
|
||||
// Return success message
|
||||
return {
|
||||
success: true,
|
||||
message: `Permission ${result.name} has been successfully ${
|
||||
isInsert ? "created" : "updated"
|
||||
}.`,
|
||||
};
|
||||
} catch (error) {
|
||||
return handleCatch(error);
|
||||
}
|
||||
}
|
||||
|
|
@ -9,7 +9,7 @@ import {
|
|||
} from "@mantine/core";
|
||||
import { showNotification } from "@/utils/notifications";
|
||||
import withServerAction from "@/modules/dashboard/utils/withServerAction";
|
||||
import deletePermission from "../actions/deletePermission";
|
||||
import deletePermissionAction from "../actions/deletePermissionAction";
|
||||
import ClientError from "@/core/error/ClientError";
|
||||
|
||||
export interface DeleteModalProps {
|
||||
|
|
@ -37,7 +37,7 @@ export default function DeleteModal(props: DeleteModalProps) {
|
|||
if (!props.data?.id) return;
|
||||
setSubmitting(true);
|
||||
|
||||
withServerAction(deletePermission, props.data!.id)
|
||||
withServerAction(deletePermissionAction, props.data!.id)
|
||||
.then((response) => {
|
||||
showNotification(
|
||||
response.message ?? "Permission deleted successfully"
|
||||
|
|
|
|||
|
|
@ -17,9 +17,9 @@ import { useRouter } from "next/navigation";
|
|||
import React, { useEffect, useState } from "react";
|
||||
import { TbDeviceFloppy } from "react-icons/tb";
|
||||
import permissionFormDataSchema, { PermissionFormData } from "../formSchemas/PermissionFormData";
|
||||
import getPermissionById from "../actions/getPermissionById";
|
||||
import getPermissionByIdAction from "../actions/getPermissionByIdAction";
|
||||
import withServerAction from "@/modules/dashboard/utils/withServerAction";
|
||||
import upsertPermission from "../actions/upsertPermission";
|
||||
import upsertPermissionAction from "../actions/upsertPermissionAction";
|
||||
import ClientError from "@/core/error/ClientError";
|
||||
|
||||
export interface ModalProps {
|
||||
|
|
@ -66,7 +66,7 @@ export default function FormModal(props: ModalProps) {
|
|||
}
|
||||
|
||||
setFetching(true);
|
||||
getPermissionById(props.id)
|
||||
withServerAction(getPermissionByIdAction, props.id)
|
||||
.then((response) => {
|
||||
if (response.success) {
|
||||
const data = response.data;
|
||||
|
|
@ -95,7 +95,7 @@ export default function FormModal(props: ModalProps) {
|
|||
|
||||
const handleSubmit = (values: PermissionFormData) => {
|
||||
setSubmitting(true);
|
||||
withServerAction(upsertPermission, values)
|
||||
withServerAction(upsertPermissionAction, values)
|
||||
.then((response) => {
|
||||
showNotification(response.message!, "success");
|
||||
closeModal();
|
||||
|
|
|
|||
15
src/modules/permission/services/deletePermission.ts
Normal file
15
src/modules/permission/services/deletePermission.ts
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
import "server-only"
|
||||
import db from "@/core/db";
|
||||
import notFound from "@/modules/dashboard/utils/notFound";
|
||||
|
||||
export default async function deletePermission(id: string) {
|
||||
const permission = await db.permission.delete({
|
||||
where: { id },
|
||||
});
|
||||
|
||||
if (!permission) return notFound({
|
||||
message: "The permission does not exists"
|
||||
});
|
||||
|
||||
return true as const;
|
||||
}
|
||||
32
src/modules/permission/services/getAllPermissions.ts
Normal file
32
src/modules/permission/services/getAllPermissions.ts
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
import db from "@/core/db";
|
||||
import "server-only";
|
||||
import Permission from "../types/Permission";
|
||||
|
||||
export default async function getAllPermissions(): Promise<Permission[]> {
|
||||
const permissions = await db.permission.findMany({
|
||||
include: {
|
||||
_count: {
|
||||
select: {
|
||||
roles: true,
|
||||
directUsers: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// Transform the data into the desired format
|
||||
const permissionsData = permissions.map(
|
||||
({ id, code, name, description, isActive, _count }) => ({
|
||||
id,
|
||||
code,
|
||||
name,
|
||||
description,
|
||||
isActive,
|
||||
roleCount: _count.roles,
|
||||
//User count counts only direct user
|
||||
userCount: _count.directUsers,
|
||||
})
|
||||
);
|
||||
|
||||
return permissionsData;
|
||||
}
|
||||
22
src/modules/permission/services/getPermissionById.ts
Normal file
22
src/modules/permission/services/getPermissionById.ts
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
import db from "@/core/db";
|
||||
import notFound from "@/modules/dashboard/utils/notFound";
|
||||
import "server-only"
|
||||
|
||||
export default async function getPermissionById(id: string){
|
||||
const permission = await db.permission.findFirst({
|
||||
where: { id },
|
||||
select: {
|
||||
code: true,
|
||||
description: true,
|
||||
id: true,
|
||||
isActive: true,
|
||||
name: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (!permission) return notFound({
|
||||
message: "The permission does not exists"
|
||||
})
|
||||
|
||||
return permission;
|
||||
}
|
||||
50
src/modules/permission/services/upsertPermission.ts
Normal file
50
src/modules/permission/services/upsertPermission.ts
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
import "server-only";
|
||||
import permissionFormDataSchema, { PermissionFormData } from "../formSchemas/PermissionFormData";
|
||||
import DashboardError from "@/modules/dashboard/errors/DashboardError";
|
||||
import mapObjectToFirstValue from "@/utils/mapObjectToFirstValue";
|
||||
import db from "@/core/db";
|
||||
|
||||
export default async function upsertPermission(data: PermissionFormData) {
|
||||
const isInsert = !data.id;
|
||||
|
||||
// Validate form data
|
||||
const validatedFields = permissionFormDataSchema.safeParse(data);
|
||||
if (!validatedFields.success) {
|
||||
throw new DashboardError({
|
||||
errorCode: "INVALID_FORM_DATA",
|
||||
formErrors: mapObjectToFirstValue(
|
||||
validatedFields.error.flatten().fieldErrors
|
||||
),
|
||||
});
|
||||
}
|
||||
const permissionData = {
|
||||
code: validatedFields.data.code,
|
||||
description: validatedFields.data.description,
|
||||
name: validatedFields.data.name,
|
||||
isActive: validatedFields.data.isActive,
|
||||
};
|
||||
|
||||
// Database operation
|
||||
if (isInsert) {
|
||||
if (
|
||||
await db.permission.findFirst({
|
||||
where: {
|
||||
code: permissionData.code,
|
||||
},
|
||||
})
|
||||
) {
|
||||
throw new DashboardError({
|
||||
errorCode: "INVALID_FORM_DATA",
|
||||
formErrors: {
|
||||
code: "The code is already exists",
|
||||
},
|
||||
});
|
||||
}
|
||||
return await db.permission.create({ data: permissionData });
|
||||
} else {
|
||||
return await db.permission.update({
|
||||
where: { id: validatedFields.data.id! },
|
||||
data: permissionData,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -15,7 +15,7 @@ import DashboardTable from "@/modules/dashboard/components/DashboardTable";
|
|||
|
||||
interface Props {
|
||||
permissions: Partial<CrudPermissions>;
|
||||
permissionData: Permission[];
|
||||
data: Permission[];
|
||||
}
|
||||
|
||||
export default function PermissionsTable(props: Props) {
|
||||
|
|
@ -31,7 +31,7 @@ export default function PermissionsTable(props: Props) {
|
|||
});
|
||||
|
||||
const table = useReactTable({
|
||||
data: props.permissionData,
|
||||
data: props.data,
|
||||
columns: createColumns({
|
||||
permissions: props.permissions,
|
||||
actions: {
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user