Change role into action-service pattern
This commit is contained in:
parent
e33a7b5e9c
commit
b94f2c6aad
|
|
@ -1,6 +1,6 @@
|
||||||
import checkMultiplePermissions from "@/modules/auth/utils/checkMultiplePermissions";
|
import checkMultiplePermissions from "@/modules/auth/utils/checkMultiplePermissions";
|
||||||
import unauthorized from "@/modules/dashboard/utils/unauthorized";
|
import unauthorized from "@/modules/dashboard/utils/unauthorized";
|
||||||
import getAllRoles from "@/modules/role/actions/getAllRoles";
|
import getAllRoles from "@/modules/role/services/getAllRoles";
|
||||||
import RolesTable from "@/modules/role/tables/RolesTable/RolesTable";
|
import RolesTable from "@/modules/role/tables/RolesTable/RolesTable";
|
||||||
import { Card, Stack, Title } from "@mantine/core";
|
import { Card, Stack, Title } from "@mantine/core";
|
||||||
import { Metadata } from "next";
|
import { Metadata } from "next";
|
||||||
|
|
@ -21,14 +21,13 @@ export default async function RolesPage() {
|
||||||
|
|
||||||
if (!permissions.readAll) unauthorized()
|
if (!permissions.readAll) unauthorized()
|
||||||
|
|
||||||
const res = await getAllRoles();
|
const roles = await getAllRoles();
|
||||||
if (!res.success) throw new Error("Error while fetch roles");
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Stack>
|
<Stack>
|
||||||
<Title order={1}>Roles</Title>
|
<Title order={1}>Roles</Title>
|
||||||
<Card>
|
<Card>
|
||||||
<RolesTable permissions={permissions} roles={res.data} />
|
<RolesTable permissions={permissions} data={roles} />
|
||||||
</Card>
|
</Card>
|
||||||
</Stack>
|
</Stack>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1,45 +0,0 @@
|
||||||
import getCurrentUser from "@/modules/auth/utils/getCurrentUser";
|
|
||||||
import "server-only";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if the current user has the specified permissions.
|
|
||||||
*
|
|
||||||
* Deprecated. Use `checkPermission()` from auth module instead.
|
|
||||||
*
|
|
||||||
* @deprecated
|
|
||||||
* @param permission - The specific permission to check. If it's "guest-only", the function returns true if the user is not authenticated. If it's "authenticated-only", it returns true if the user is authenticated. For other permissions, it checks against the user's roles and direct permissions.
|
|
||||||
* @param currentUser - Optional. The current user object. If not provided, the function retrieves the current user.
|
|
||||||
* @returns true if the user has the required permission, otherwise false.
|
|
||||||
*/
|
|
||||||
export default async function checkPermission(
|
|
||||||
permission?: "guest-only" | "authenticated-only" | (string & {}),
|
|
||||||
currentUser?: Awaited<ReturnType<typeof getCurrentUser>>
|
|
||||||
): Promise<boolean> {
|
|
||||||
// Allow if no specific permission is required.
|
|
||||||
if (!permission) return true;
|
|
||||||
|
|
||||||
// Retrieve current user if not provided.
|
|
||||||
const user = currentUser ?? (await getCurrentUser());
|
|
||||||
|
|
||||||
// Handle non-authenticated users.
|
|
||||||
if (!user) {
|
|
||||||
return permission === "guest-only";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Allow authenticated users if the permission is 'authenticated-only'.
|
|
||||||
if (permission === "authenticated-only") {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Short-circuit for super-admin role to allow all permissions.
|
|
||||||
if (user.roles.some((role) => role.code === "super-admin")) return true;
|
|
||||||
|
|
||||||
// Aggregate all role codes and direct permissions into a set for efficient lookup.
|
|
||||||
const permissions = new Set<string>([
|
|
||||||
...user.roles.map((role) => role.code),
|
|
||||||
...user.directPermissions.map((dp) => dp.code),
|
|
||||||
]);
|
|
||||||
|
|
||||||
// Check if the user has the required permission.
|
|
||||||
return permissions.has(permission);
|
|
||||||
}
|
|
||||||
|
|
@ -1,22 +1,19 @@
|
||||||
"use server";
|
"use server";
|
||||||
|
|
||||||
import db from "@/core/db";
|
import checkPermission from "@/modules/auth/utils/checkPermission";
|
||||||
import prisma from "@/db";
|
|
||||||
import checkPermission from "@/modules/dashboard/services/checkPermission";
|
|
||||||
import ServerResponseAction from "@/modules/dashboard/types/ServerResponseAction";
|
import ServerResponseAction from "@/modules/dashboard/types/ServerResponseAction";
|
||||||
import handleCatch from "@/modules/dashboard/utils/handleCatch";
|
import handleCatch from "@/modules/dashboard/utils/handleCatch";
|
||||||
import unauthorized from "@/modules/dashboard/utils/unauthorized";
|
import unauthorized from "@/modules/dashboard/utils/unauthorized";
|
||||||
import { revalidatePath } from "next/cache";
|
import { revalidatePath } from "next/cache";
|
||||||
import { notFound } from "next/navigation";
|
import deleteRole from "../services/deleteRole";
|
||||||
|
|
||||||
export default async function deleteRole(
|
export default async function deleteRoleAction(
|
||||||
id: string
|
id: string
|
||||||
): Promise<ServerResponseAction> {
|
): Promise<ServerResponseAction> {
|
||||||
try {
|
try {
|
||||||
if (!(await checkPermission("roles.delete"))) return unauthorized();
|
if (!(await checkPermission("roles.delete"))) return unauthorized();
|
||||||
const role = await db.role.delete({
|
|
||||||
where: { id },
|
await deleteRole(id);
|
||||||
});
|
|
||||||
|
|
||||||
revalidatePath(".");
|
revalidatePath(".");
|
||||||
|
|
||||||
|
|
@ -1,58 +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 Role from "../types/Role";
|
|
||||||
import db from "@/core/db";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves all roles along with the count of associated permissions and users.
|
|
||||||
* Authorization check is performed for the operation.
|
|
||||||
*
|
|
||||||
* @returns An array of role objects each including details and counts of related permissions and users.
|
|
||||||
*/
|
|
||||||
export default async function getAllRoles(): Promise<
|
|
||||||
ServerResponseAction<Role[]>
|
|
||||||
> {
|
|
||||||
try {
|
|
||||||
// Authorization check
|
|
||||||
if (!(await checkPermission("roles.getAll"))) {
|
|
||||||
unauthorized();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fetch roles from the database
|
|
||||||
const roles = await db.role.findMany({
|
|
||||||
include: {
|
|
||||||
_count: {
|
|
||||||
select: {
|
|
||||||
permissions: true,
|
|
||||||
users: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
// Transform the data into the desired format
|
|
||||||
const result = roles.map(
|
|
||||||
({ id, code, name, description, isActive, _count }) => ({
|
|
||||||
id,
|
|
||||||
code,
|
|
||||||
name,
|
|
||||||
description,
|
|
||||||
isActive,
|
|
||||||
permissionCount: _count.permissions,
|
|
||||||
userCount: _count.users,
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
return {
|
|
||||||
success: true,
|
|
||||||
data: result
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
return handleCatch(error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
34
src/modules/role/actions/getAllRolesAction.ts
Normal file
34
src/modules/role/actions/getAllRolesAction.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 Role from "../types/Role";
|
||||||
|
import checkPermission from "@/modules/auth/utils/checkPermission";
|
||||||
|
import getAllRoles from "../services/getAllRoles";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves all roles along with the count of associated permissions and users.
|
||||||
|
* Authorization check is performed for the operation.
|
||||||
|
*
|
||||||
|
* @returns An array of role objects each including details and counts of related permissions and users.
|
||||||
|
*/
|
||||||
|
export default async function getAllRolesAction(): Promise<
|
||||||
|
ServerResponseAction<Role[]>
|
||||||
|
> {
|
||||||
|
try {
|
||||||
|
// Authorization check
|
||||||
|
if (!(await checkPermission("roles.readAll"))) {
|
||||||
|
return unauthorized();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fetch roles from the database
|
||||||
|
const roles = await getAllRoles()
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
data: roles
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
return handleCatch(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,58 +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";
|
|
||||||
|
|
||||||
type RoleData = {
|
|
||||||
id: string;
|
|
||||||
code: string;
|
|
||||||
name: string;
|
|
||||||
description: string;
|
|
||||||
isActive: boolean;
|
|
||||||
permissions: {
|
|
||||||
id: string;
|
|
||||||
code: string;
|
|
||||||
name: string;
|
|
||||||
}[]
|
|
||||||
}
|
|
||||||
|
|
||||||
export default async function getRoleById(id: string): Promise<ServerResponseAction<RoleData>>{
|
|
||||||
try{
|
|
||||||
|
|
||||||
if (!(await checkPermission("roles.read"))) return unauthorized();
|
|
||||||
|
|
||||||
const role = await db.role.findFirst({
|
|
||||||
where: { id },
|
|
||||||
select: {
|
|
||||||
code: true,
|
|
||||||
description: true,
|
|
||||||
id: true,
|
|
||||||
isActive: true,
|
|
||||||
name: true,
|
|
||||||
permissions: {
|
|
||||||
select: {
|
|
||||||
id: true,
|
|
||||||
code: true,
|
|
||||||
name: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!role) {
|
|
||||||
throw new Error("Permission not found")
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
success: true,
|
|
||||||
message: "Role fetched successfully",
|
|
||||||
data: role,
|
|
||||||
};
|
|
||||||
} catch (e){
|
|
||||||
return handleCatch(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
24
src/modules/role/actions/getRoleByIdAction.ts
Normal file
24
src/modules/role/actions/getRoleByIdAction.ts
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
"use server";
|
||||||
|
|
||||||
|
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 getRoleById from "../services/getRoleById";
|
||||||
|
|
||||||
|
export default async function getRoleByIdAction(id: string): Promise<ServerResponseAction<Awaited<ReturnType<typeof getRoleById>>>>{
|
||||||
|
try{
|
||||||
|
|
||||||
|
if (!(await checkPermission("roles.read"))) return unauthorized();
|
||||||
|
|
||||||
|
const role = await getRoleById(id)
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
message: "Role fetched successfully",
|
||||||
|
data: role,
|
||||||
|
};
|
||||||
|
} catch (e){
|
||||||
|
return handleCatch(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,99 +0,0 @@
|
||||||
"use server";
|
|
||||||
|
|
||||||
import roleFormDataSchema, { RoleFormData } from "../formSchemas/RoleFormData";
|
|
||||||
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 role based on the provided RoleFormData.
|
|
||||||
* If the role already exists (determined by `id`), it updates the role; otherwise, it creates a new role.
|
|
||||||
* Authorization checks are performed based on whether it's a create or update operation.
|
|
||||||
*
|
|
||||||
* @param data - The data for creating or updating the role.
|
|
||||||
* @returns An object containing the success status, message, and any errors.
|
|
||||||
*/
|
|
||||||
export default async function upsertRole(
|
|
||||||
data: RoleFormData
|
|
||||||
): Promise<ServerResponseAction> {
|
|
||||||
try {
|
|
||||||
const isInsert = !data.id;
|
|
||||||
|
|
||||||
// Authorization check
|
|
||||||
const permissionType = isInsert ? "role.create" : "role.update";
|
|
||||||
if (!(await checkPermission(permissionType))) {
|
|
||||||
return unauthorized();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validate form data
|
|
||||||
const validatedFields = roleFormDataSchema.safeParse(data);
|
|
||||||
if (!validatedFields.success) {
|
|
||||||
throw new DashboardError({
|
|
||||||
errorCode: "INVALID_FORM_DATA",
|
|
||||||
formErrors: mapObjectToFirstValue(
|
|
||||||
validatedFields.error.flatten().fieldErrors
|
|
||||||
),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
const roleData = {
|
|
||||||
code: validatedFields.data.code,
|
|
||||||
description: validatedFields.data.description,
|
|
||||||
name: validatedFields.data.name,
|
|
||||||
isActive: validatedFields.data.isActive,
|
|
||||||
};
|
|
||||||
|
|
||||||
const permissionIds = validatedFields.data.permissions.map(
|
|
||||||
(permission) => ({ code: permission })
|
|
||||||
);
|
|
||||||
|
|
||||||
// Database operation
|
|
||||||
if (isInsert) {
|
|
||||||
if (
|
|
||||||
await db.role.findFirst({
|
|
||||||
where: {
|
|
||||||
code: roleData.code,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
) {
|
|
||||||
throw new DashboardError({
|
|
||||||
errorCode: "INVALID_FORM_DATA",
|
|
||||||
formErrors: {
|
|
||||||
code: "The code is already exists",
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
await db.role.create({
|
|
||||||
data: {
|
|
||||||
...roleData,
|
|
||||||
permissions: {
|
|
||||||
connect: permissionIds,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
await db.role.update({
|
|
||||||
where: { id: validatedFields.data.id! },
|
|
||||||
data: { ...roleData, permissions: { connect: permissionIds } },
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Revalidate the cache
|
|
||||||
revalidatePath(".");
|
|
||||||
|
|
||||||
// Return success message
|
|
||||||
return {
|
|
||||||
success: true,
|
|
||||||
message: `Role ${validatedFields.data.name} has been successfully ${
|
|
||||||
isInsert ? "created" : "updated"
|
|
||||||
}.`,
|
|
||||||
};
|
|
||||||
} catch (error) {
|
|
||||||
return handleCatch(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
50
src/modules/role/actions/upsertRoleAction.ts
Normal file
50
src/modules/role/actions/upsertRoleAction.ts
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
"use server";
|
||||||
|
|
||||||
|
import roleFormDataSchema, { RoleFormData } from "../formSchemas/RoleFormData";
|
||||||
|
import mapObjectToFirstValue from "@/utils/mapObjectToFirstValue";
|
||||||
|
import { revalidatePath } from "next/cache";
|
||||||
|
import ServerResponseAction from "@/modules/dashboard/types/ServerResponseAction";
|
||||||
|
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";
|
||||||
|
import checkPermission from "@/modules/auth/utils/checkPermission";
|
||||||
|
import upsertRole from "../services/upsertRole";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Upserts a role based on the provided RoleFormData.
|
||||||
|
* If the role already exists (determined by `id`), it updates the role; otherwise, it creates a new role.
|
||||||
|
* Authorization checks are performed based on whether it's a create or update operation.
|
||||||
|
*
|
||||||
|
* @param data - The data for creating or updating the role.
|
||||||
|
* @returns An object containing the success status, message, and any errors.
|
||||||
|
*/
|
||||||
|
export default async function upsertRoleAction(
|
||||||
|
data: RoleFormData
|
||||||
|
): Promise<ServerResponseAction> {
|
||||||
|
try {
|
||||||
|
const isInsert = !data.id;
|
||||||
|
|
||||||
|
// Authorization check
|
||||||
|
const permissionType = isInsert ? "roles.create" : "roles.update";
|
||||||
|
if (!(await checkPermission(permissionType))) {
|
||||||
|
return unauthorized();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate form data
|
||||||
|
const result = await upsertRole(data);
|
||||||
|
|
||||||
|
// Revalidate the cache
|
||||||
|
revalidatePath(".");
|
||||||
|
|
||||||
|
// Return success message
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
message: `Role ${result.name} has been successfully ${
|
||||||
|
isInsert ? "created" : "updated"
|
||||||
|
}.`,
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
return handleCatch(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -9,7 +9,7 @@ import {
|
||||||
} from "@mantine/core";
|
} from "@mantine/core";
|
||||||
import { showNotification } from "@/utils/notifications";
|
import { showNotification } from "@/utils/notifications";
|
||||||
import withServerAction from "@/modules/dashboard/utils/withServerAction";
|
import withServerAction from "@/modules/dashboard/utils/withServerAction";
|
||||||
import deleteRole from "../actions/deleteRole";
|
import deleteRoleAction from "../actions/deleteRoleAction";
|
||||||
import ClientError from "@/core/error/ClientError";
|
import ClientError from "@/core/error/ClientError";
|
||||||
|
|
||||||
export interface DeleteModalProps {
|
export interface DeleteModalProps {
|
||||||
|
|
@ -38,7 +38,7 @@ export default function DeleteModal(props: DeleteModalProps) {
|
||||||
if (!props.data?.id) return;
|
if (!props.data?.id) return;
|
||||||
setSubmitting(true);
|
setSubmitting(true);
|
||||||
|
|
||||||
withServerAction(deleteRole, props.data!.id)
|
withServerAction(deleteRoleAction, props.data!.id)
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
showNotification(
|
showNotification(
|
||||||
response.message ?? "Role deleted successfully"
|
response.message ?? "Role deleted successfully"
|
||||||
|
|
|
||||||
|
|
@ -21,8 +21,8 @@ import { TbDeviceFloppy } from "react-icons/tb";
|
||||||
import roleFormDataSchema, { RoleFormData } from "../formSchemas/RoleFormData";
|
import roleFormDataSchema, { RoleFormData } from "../formSchemas/RoleFormData";
|
||||||
import getAllPermissions from "@/modules/permission/actions/getAllPermissions";
|
import getAllPermissions from "@/modules/permission/actions/getAllPermissions";
|
||||||
import withServerAction from "@/modules/dashboard/utils/withServerAction";
|
import withServerAction from "@/modules/dashboard/utils/withServerAction";
|
||||||
import getRoleById from "../actions/getRoleById";
|
import getRoleByIdAction from "../actions/getRoleByIdAction";
|
||||||
import upsertRole from "../actions/upsertRole";
|
import upsertRoleAction from "../actions/upsertRoleAction";
|
||||||
import ClientError from "@/core/error/ClientError";
|
import ClientError from "@/core/error/ClientError";
|
||||||
|
|
||||||
export interface ModalProps {
|
export interface ModalProps {
|
||||||
|
|
@ -96,7 +96,7 @@ export default function FormModal(props: ModalProps) {
|
||||||
}
|
}
|
||||||
|
|
||||||
setFetching(true);
|
setFetching(true);
|
||||||
withServerAction(getRoleById, props.id)
|
withServerAction(getRoleByIdAction, props.id)
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
const data = response.data;
|
const data = response.data;
|
||||||
form.setValues({
|
form.setValues({
|
||||||
|
|
@ -133,7 +133,7 @@ export default function FormModal(props: ModalProps) {
|
||||||
|
|
||||||
const handleSubmit = (values: RoleFormData) => {
|
const handleSubmit = (values: RoleFormData) => {
|
||||||
setSubmitting(true);
|
setSubmitting(true);
|
||||||
withServerAction(upsertRole, values)
|
withServerAction(upsertRoleAction, values)
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
showNotification(response.message!, "success");
|
showNotification(response.message!, "success");
|
||||||
closeModal();
|
closeModal();
|
||||||
|
|
|
||||||
12
src/modules/role/services/deleteRole.ts
Normal file
12
src/modules/role/services/deleteRole.ts
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
import db from "@/core/db";
|
||||||
|
import notFound from "@/modules/dashboard/utils/notFound";
|
||||||
|
|
||||||
|
export default async function deleteRole(id: string) {
|
||||||
|
const role = await db.role.delete({
|
||||||
|
where: { id },
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!role) notFound({message: "The role doesn't exists"})
|
||||||
|
|
||||||
|
return true as const;
|
||||||
|
}
|
||||||
32
src/modules/role/services/getAllRoles.ts
Normal file
32
src/modules/role/services/getAllRoles.ts
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
import db from "@/core/db";
|
||||||
|
import "server-only"
|
||||||
|
import Role from "../types/Role";
|
||||||
|
|
||||||
|
export default async function getAllRoles(): Promise<Role[]>{
|
||||||
|
|
||||||
|
const roles = await db.role.findMany({
|
||||||
|
include: {
|
||||||
|
_count: {
|
||||||
|
select: {
|
||||||
|
permissions: true,
|
||||||
|
users: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
//data transformation
|
||||||
|
const result = roles.map(
|
||||||
|
({ id, code, name, description, isActive, _count }) => ({
|
||||||
|
id,
|
||||||
|
code,
|
||||||
|
name,
|
||||||
|
description,
|
||||||
|
isActive,
|
||||||
|
permissionCount: _count.permissions,
|
||||||
|
userCount: _count.users,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
40
src/modules/role/services/getRoleById.ts
Normal file
40
src/modules/role/services/getRoleById.ts
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
import "server-only";
|
||||||
|
import db from "@/core/db";
|
||||||
|
import notFound from "@/modules/dashboard/utils/notFound";
|
||||||
|
|
||||||
|
type RoleData = {
|
||||||
|
id: string;
|
||||||
|
code: string;
|
||||||
|
name: string;
|
||||||
|
description: string;
|
||||||
|
isActive: boolean;
|
||||||
|
permissions: {
|
||||||
|
id: string;
|
||||||
|
code: string;
|
||||||
|
name: string;
|
||||||
|
}[];
|
||||||
|
};
|
||||||
|
|
||||||
|
export default async function getRoleById(id: string): Promise<RoleData> {
|
||||||
|
const role = await db.role.findFirst({
|
||||||
|
where: { id },
|
||||||
|
select: {
|
||||||
|
code: true,
|
||||||
|
description: true,
|
||||||
|
id: true,
|
||||||
|
isActive: true,
|
||||||
|
name: true,
|
||||||
|
permissions: {
|
||||||
|
select: {
|
||||||
|
id: true,
|
||||||
|
code: true,
|
||||||
|
name: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!role) return notFound({ message: "Role doesn't exists" });
|
||||||
|
|
||||||
|
return role;
|
||||||
|
}
|
||||||
59
src/modules/role/services/upsertRole.ts
Normal file
59
src/modules/role/services/upsertRole.ts
Normal file
|
|
@ -0,0 +1,59 @@
|
||||||
|
import DashboardError from "@/modules/dashboard/errors/DashboardError";
|
||||||
|
import roleFormDataSchema, { RoleFormData } from "../formSchemas/RoleFormData";
|
||||||
|
import mapObjectToFirstValue from "@/utils/mapObjectToFirstValue";
|
||||||
|
import db from "@/core/db";
|
||||||
|
|
||||||
|
export default async function upsertRole(data: RoleFormData) {
|
||||||
|
const isInsert = !data.id;
|
||||||
|
|
||||||
|
const validatedFields = roleFormDataSchema.safeParse(data);
|
||||||
|
if (!validatedFields.success) {
|
||||||
|
throw new DashboardError({
|
||||||
|
errorCode: "INVALID_FORM_DATA",
|
||||||
|
formErrors: mapObjectToFirstValue(
|
||||||
|
validatedFields.error.flatten().fieldErrors
|
||||||
|
),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
const roleData = {
|
||||||
|
code: validatedFields.data.code,
|
||||||
|
description: validatedFields.data.description,
|
||||||
|
name: validatedFields.data.name,
|
||||||
|
isActive: validatedFields.data.isActive,
|
||||||
|
};
|
||||||
|
|
||||||
|
const permissionIds = validatedFields.data.permissions.map(
|
||||||
|
(permission) => ({ code: permission })
|
||||||
|
);
|
||||||
|
|
||||||
|
// Database operation
|
||||||
|
if (isInsert) {
|
||||||
|
if (
|
||||||
|
await db.role.findFirst({
|
||||||
|
where: {
|
||||||
|
code: roleData.code,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
) {
|
||||||
|
throw new DashboardError({
|
||||||
|
errorCode: "INVALID_FORM_DATA",
|
||||||
|
formErrors: {
|
||||||
|
code: "The code is already exists",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return await db.role.create({
|
||||||
|
data: {
|
||||||
|
...roleData,
|
||||||
|
permissions: {
|
||||||
|
connect: permissionIds,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
return await db.role.update({
|
||||||
|
where: { id: validatedFields.data.id! },
|
||||||
|
data: { ...roleData, permissions: { connect: permissionIds } },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -12,7 +12,7 @@ import Role from "../../types/Role";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
permissions: Partial<CrudPermissions>;
|
permissions: Partial<CrudPermissions>;
|
||||||
roles: Role[];
|
data: Role[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function RolesTable(props: Props) {
|
export default function RolesTable(props: Props) {
|
||||||
|
|
@ -28,7 +28,7 @@ export default function RolesTable(props: Props) {
|
||||||
});
|
});
|
||||||
|
|
||||||
const table = useReactTable({
|
const table = useReactTable({
|
||||||
data: props.roles,
|
data: props.data,
|
||||||
columns: createColumns({
|
columns: createColumns({
|
||||||
permissions: props.permissions,
|
permissions: props.permissions,
|
||||||
actions: {
|
actions: {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user