add RBAC on applications

This commit is contained in:
vergiLgood1 2025-04-11 18:32:46 +07:00
parent cca250b275
commit 31e2fe590a
18 changed files with 213 additions and 105 deletions

View File

@ -42,11 +42,13 @@ export function SettingsDialog({ trigger, defaultTab = "account", open, onOpenCh
const [selectedTab, setSelectedTab] = useState(defaultTab) const [selectedTab, setSelectedTab] = useState(defaultTab)
if (!user || !user.profile) return <div className="text-red-500">User not found</div>
// Get user display name // Get user display name
const preferredName = user?.profile?.username || "" const preferredName = user.profile.username || ""
const userEmail = user?.email || "" const userEmail = user.email || ""
const displayName = preferredName || userEmail?.split("@")[0] || "User" const displayName = preferredName || userEmail.split("@")[0] || "User"
const userAvatar = user?.profile?.avatar || "" const userAvatar = user.profile.avatar || ""
const sections: SettingsSection[] = [ const sections: SettingsSection[] = [
{ {

View File

@ -1,6 +1,6 @@
// cells/actions-cell.tsx // cells/actions-cell.tsx
import React, { useState } from "react" import React, { useEffect, useState } from "react"
import { MoreHorizontal, PenIcon as UserPen, Trash2, ShieldAlert, ShieldCheck } from "lucide-react" import { MoreHorizontal, PenIcon as UserPen, Trash2, ShieldAlert, ShieldCheck } from "lucide-react"
import { import {
DropdownMenu, DropdownMenu,
@ -15,7 +15,10 @@ import { IUserSchema } from "@/src/entities/models/users/users.model"
import { useUserActionsHandler } from "../../../_handlers/actions/use-user-actions" import { useUserActionsHandler } from "../../../_handlers/actions/use-user-actions"
import { BanUserDialog } from "../../dialogs/ban-user-dialog" import { BanUserDialog } from "../../dialogs/ban-user-dialog"
import { useCreateUserColumn } from "../../../_handlers/use-create-user-column" import { useCreateUserColumn } from "../../../_handlers/use-create-user-column"
import { useCheckPermissionsHandler } from "@/app/(pages)/(auth)/_handlers/use-check-permissions"
import { useCheckPermissionsNewQuery } from "@/app/(pages)/(auth)/_queries/mutations"
import { useGetCurrentUserQuery } from "../../../_queries/queries"
import { Badge } from "@/app/_components/ui/badge"
interface ActionsCellProps { interface ActionsCellProps {
user: IUserSchema user: IUserSchema
@ -23,7 +26,6 @@ interface ActionsCellProps {
} }
export const ActionsCell: React.FC<ActionsCellProps> = ({ user, onUpdate }) => { export const ActionsCell: React.FC<ActionsCellProps> = ({ user, onUpdate }) => {
const { const {
deleteDialogOpen, deleteDialogOpen,
setDeleteDialogOpen, setDeleteDialogOpen,
@ -41,6 +43,13 @@ export const ActionsCell: React.FC<ActionsCellProps> = ({ user, onUpdate }) => {
setSelectedUser, setSelectedUser,
} = useCreateUserColumn() } = useCreateUserColumn()
const { data: currentUser, isPending } = useGetCurrentUserQuery()
if (!currentUser) return <Badge variant={"destructive"}>user not found</Badge>
let { data: isAllowedToDelete } = useCheckPermissionsNewQuery(currentUser.email, "delete", "users")
let { data: isAllowedToUpdate } = useCheckPermissionsNewQuery(currentUser.email, "update", "users")
return ( return (
<div onClick={(e) => e.stopPropagation()}> <div onClick={(e) => e.stopPropagation()}>
<DropdownMenu> <DropdownMenu>
@ -50,19 +59,24 @@ export const ActionsCell: React.FC<ActionsCellProps> = ({ user, onUpdate }) => {
</Button> </Button>
</DropdownMenuTrigger> </DropdownMenuTrigger>
<DropdownMenuContent align="end"> <DropdownMenuContent align="end">
{isAllowedToUpdate && (
<DropdownMenuItem onClick={() => onUpdate(user)}> <DropdownMenuItem onClick={() => onUpdate(user)}>
<UserPen className="h-4 w-4 mr-2 text-blue-500" /> <UserPen className="h-4 w-4 mr-2 text-blue-500" />
Update Update
</DropdownMenuItem> </DropdownMenuItem>
<DropdownMenuItem )}
onClick={(e) => { {isAllowedToDelete && (
setSelectedUser({ id: user.id, email: user.email! }) <DropdownMenuItem
setDeleteDialogOpen(true) onClick={(e) => {
}} setSelectedUser({ id: user.id, email: user.email! })
> setDeleteDialogOpen(true)
<Trash2 className="h-4 w-4 mr-2 text-destructive" /> }}
Delete >
</DropdownMenuItem> <Trash2 className="h-4 w-4 mr-2 text-destructive" />
Delete
</DropdownMenuItem>
)}
{isAllowedToUpdate && user.banned_until != null && (
<DropdownMenuItem <DropdownMenuItem
onClick={(e) => { onClick={(e) => {
if (user.banned_until != null) { if (user.banned_until != null) {
@ -77,6 +91,7 @@ export const ActionsCell: React.FC<ActionsCellProps> = ({ user, onUpdate }) => {
<ShieldAlert className="h-4 w-4 mr-2 text-yellow-500" /> <ShieldAlert className="h-4 w-4 mr-2 text-yellow-500" />
{user.banned_until != null ? "Unban" : "Ban"} {user.banned_until != null ? "Unban" : "Ban"}
</DropdownMenuItem> </DropdownMenuItem>
)}
</DropdownMenuContent> </DropdownMenuContent>
</DropdownMenu> </DropdownMenu>

View File

@ -1,5 +1,5 @@
// columns/actions-column.tsx // columns/actions-column.tsx
"use client"
import React from "react" import React from "react"
import { IUserSchema } from "@/src/entities/models/users/users.model" import { IUserSchema } from "@/src/entities/models/users/users.model"

View File

@ -1,5 +1,5 @@
// columns/index.ts // columns/index.ts
"use client"
import type { ColumnDef } from "@tanstack/react-table" import type { ColumnDef } from "@tanstack/react-table"
import { IUserSchema, IUserFilterOptionsSchema } from "@/src/entities/models/users/users.model" import { IUserSchema, IUserFilterOptionsSchema } from "@/src/entities/models/users/users.model"

View File

@ -1,5 +1,5 @@
// filters/column-filter.tsx // filters/column-filter.tsx
"use client"
import React from "react" import React from "react"
import { ListFilter } from "lucide-react" import { ListFilter } from "lucide-react"

View File

@ -1,43 +1,17 @@
"use client"; "use client";
import { useState, useMemo, useEffect } from "react"; import { useState, useMemo, useEffect } from "react";
import {
PlusCircle,
Search,
MoreHorizontal,
X,
ChevronDown,
UserPlus,
Mail,
ShieldAlert,
ListFilter,
Trash2,
PenIcon as UserPen,
ShieldCheck,
} from "lucide-react";
import { Button } from "@/app/_components/ui/button";
import { Input } from "@/app/_components/ui/input";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/app/_components/ui/dropdown-menu";
import { DataTable } from "../../../../../_components/data-table"; import { DataTable } from "../../../../../_components/data-table";
import { UserInformationSheet } from "./sheets/user-information-sheet"; import { UserInformationSheet } from "./sheets/user-information-sheet";
import { useGetUsersQuery } from "../_queries/queries"; import { useGetUsersQuery } from "../_queries/queries";
import { filterUsers, useUserManagementHandlers } from "../_handlers/use-user-management"; import { filterUsers, useUserManagementHandlers } from "../_handlers/use-user-management";
import { UserDialogs } from "./dialogs/user-dialogs";
import { useAddUserDialogHandler } from "../_handlers/use-add-user-dialog"; import { useAddUserDialogHandler } from "../_handlers/use-add-user-dialog";
import { useInviteUserHandler } from "../_handlers/use-invite-user"; import { useInviteUserHandler } from "../_handlers/use-invite-user";
import { AddUserDialog } from "./dialogs/add-user-dialog"; import { AddUserDialog } from "./dialogs/add-user-dialog";
import { InviteUserDialog } from "./dialogs/invite-user-dialog"; import { InviteUserDialog } from "./dialogs/invite-user-dialog";
import { ConfirmDialog } from "@/app/_components/confirm-dialog";
import { BanUserDialog } from "./dialogs/ban-user-dialog";
import { useBanUserHandler } from "../_handlers/actions/use-ban-user";
import { useDeleteUserHandler } from "../_handlers/actions/use-delete-user";
import { useUnbanUserHandler } from "../_handlers/actions/use-unban-user";
import { createUserColumns } from "./table/columns"; import { createUserColumns } from "./table/columns";
import { UserManagementToolbar } from "./toolbars/user-management-toolbar"; import { UserManagementToolbar } from "./toolbars/user-management-toolbar";
import { UpdateUserSheet } from "./sheets/update-user-sheet"; import { UpdateUserSheet } from "./sheets/update-user-sheet";

View File

@ -8,7 +8,7 @@ export const useCheckPermissionsHandler = () => {
} }
return { return {
handleCheckPermissions, checkPermissions: handleCheckPermissions,
isPending, isPending,
} }
} }

View File

@ -1,51 +1,58 @@
import { useMutation } from "@tanstack/react-query" import { useMutation, useQueries, useQuery } from "@tanstack/react-query"
import { checkPermissions, sendMagicLink, sendPasswordRecovery, signInPasswordless, signInWithPassword, signOut, verifyOtp } from "../action" import { checkPermissionNew, checkPermissions, sendMagicLink, sendPasswordRecovery, signInPasswordless, signInWithPassword, signOut, verifyOtp } from "../action"
export const useSignInPasswordlessMutation = () => { export const useSignInPasswordlessMutation = () => {
return useMutation({ return useMutation({
mutationKey: ["signIn"], mutationKey: ["signin"],
mutationFn: async (formData: FormData) => await signInPasswordless(formData), mutationFn: async (formData: FormData) => await signInPasswordless(formData),
}) })
} }
export const useSignInWithPasswordMutation = () => { export const useSignInWithPasswordMutation = () => {
return useMutation({ return useMutation({
mutationKey: ["signInWithCredentials"], mutationKey: ["signin", "credentials"],
mutationFn: async (formData: FormData) => await signInWithPassword(formData), mutationFn: async (formData: FormData) => await signInWithPassword(formData),
}) })
} }
export const useSignOutMutation = () => { export const useSignOutMutation = () => {
return useMutation({ return useMutation({
mutationKey: ["signOut"], mutationKey: ["signout"],
mutationFn: async () => await signOut(), mutationFn: async () => await signOut(),
}) })
} }
export const useSendMagicLinkMutation = () => { export const useSendMagicLinkMutation = () => {
return useMutation({ return useMutation({
mutationKey: ["sendMagicLink"], mutationKey: ["send-magic-link"],
mutationFn: async (email: string) => await sendMagicLink(email), mutationFn: async (email: string) => await sendMagicLink(email),
}) })
} }
export const useSendPasswordRecoveryMutation = () => { export const useSendPasswordRecoveryMutation = () => {
return useMutation({ return useMutation({
mutationKey: ["sendPasswordRecovery"], mutationKey: ["send-password-recovery"],
mutationFn: async (email: string) => await sendPasswordRecovery(email), mutationFn: async (email: string) => await sendPasswordRecovery(email),
}) })
} }
export const useVerifyOtpMutation = () => { export const useVerifyOtpMutation = () => {
return useMutation({ return useMutation({
mutationKey: ["verifyOtp"], mutationKey: ["verify-otp"],
mutationFn: async (formData: FormData) => await verifyOtp(formData), mutationFn: async (formData: FormData) => await verifyOtp(formData),
}) })
} }
export const useCheckPermissionsMutation = () => { export const useCheckPermissionsMutation = () => {
return useMutation({ return useMutation({
mutationKey: ["checkPermissions"], mutationKey: ["check-permissions"],
mutationFn: async ({ userId, action, resource }: { userId: string; action: string; resource: string }) => await checkPermissions(userId, action, resource), mutationFn: async ({ userId, action, resource }: { userId: string; action: string; resource: string }) => await checkPermissions(userId, action, resource),
}) })
} }
export const useCheckPermissionsNewQuery = (email: string, action: string, resource: string) => {
return useQuery({
queryKey: ["check-permissions", email, action, resource],
queryFn: async () => await checkPermissionNew(email, action, resource),
})
}

View File

@ -7,6 +7,7 @@ import { revalidatePath } from "next/cache"
import { InputParseError, NotFoundError } from "@/src/entities/errors/common" import { InputParseError, NotFoundError } from "@/src/entities/errors/common"
import { AuthenticationError, UnauthenticatedError } from "@/src/entities/errors/auth" import { AuthenticationError, UnauthenticatedError } from "@/src/entities/errors/auth"
import { createClient } from "@/app/_utils/supabase/server" import { createClient } from "@/app/_utils/supabase/server"
import db from "@/prisma/db";
export async function signInPasswordless(formData: FormData) { export async function signInPasswordless(formData: FormData) {
const instrumentationService = getInjection("IInstrumentationService") const instrumentationService = getInjection("IInstrumentationService")
@ -234,8 +235,77 @@ export async function checkPermissions(userId: string, action: string, resource:
recordResponse: true recordResponse: true
}, async () => { }, async () => {
try { try {
const checkPermissionsController = getInjection("ICheckPermissionsController")
return await checkPermissionsController({ userId, action, resource }) const user = await db.users.findUnique({
where: { id: userId },
include: {
role: true
}
})
console.log("Checking permissions for user:", user?.role.name, "action:", action, "resource:", resource)
const permission = await db.permissions.findFirst({
where: {
role_id: user?.role.id,
action: action,
resource: {
name: resource
}
}
})
return !!permission
} catch (err) {
if (err instanceof InputParseError) {
return { error: err.message }
}
const crashReporterService = getInjection("ICrashReporterService")
crashReporterService.report(err)
return {
error: "An error occurred during permissions check. Please try again later.",
}
}
})
}
export async function checkPermissionNew(email: string, action: string, resource: string) {
const instrumentationService = getInjection("IInstrumentationService")
return await instrumentationService.instrumentServerAction("checkPermissionNew", {
recordResponse: true
}, async () => {
try {
const user = await db.users.findUnique({
where: { email },
include: { role: true }
})
if (!user) {
return { error: "User not found" }
}
console.log("Checking permissions for user:", user?.role.name, "action:", action, "resource:", resource)
const permission = await db.permissions.findFirst({
where: {
role_id: user.role.id,
action: action,
resource: {
name: resource
}
}
})
if (!permission) {
return false
}
return !!permission
} catch (err) { } catch (err) {
if (err instanceof InputParseError) { if (err instanceof InputParseError) {
return { error: err.message } return { error: err.message }

View File

@ -96,6 +96,13 @@ export function createAuthenticationModule() {
DI_SYMBOLS.IUsersRepository, DI_SYMBOLS.IUsersRepository,
]); ]);
authenticationModule
.bind(DI_SYMBOLS.ICheckPermissionsUseCase)
.toHigherOrderFunction(signUpUseCase, [
DI_SYMBOLS.IInstrumentationService,
DI_SYMBOLS.IAuthenticationService,
]);
// Controllers // Controllers
authenticationModule authenticationModule
@ -141,6 +148,15 @@ export function createAuthenticationModule() {
DI_SYMBOLS.ISendPasswordRecoveryUseCase, DI_SYMBOLS.ISendPasswordRecoveryUseCase,
]); ]);
authenticationModule
.bind(DI_SYMBOLS.ICheckPermissionsController)
.toHigherOrderFunction(signUpUseCase, [
DI_SYMBOLS.IInstrumentationService,
DI_SYMBOLS.IAuthenticationService,
DI_SYMBOLS.IUsersRepository,
]);
return authenticationModule; return authenticationModule;
} }

View File

@ -77,6 +77,7 @@ import { IDeleteResourceController } from '@/src/interface-adapters/controllers/
import { IUpdateResourceController } from '@/src/interface-adapters/controllers/resources/update-resource.controller'; import { IUpdateResourceController } from '@/src/interface-adapters/controllers/resources/update-resource.controller';
import { ICreateResourceController } from '@/src/interface-adapters/controllers/resources/create-resource.controller'; import { ICreateResourceController } from '@/src/interface-adapters/controllers/resources/create-resource.controller';
import { ICheckPermissionsUseCase } from '@/src/application/use-cases/auth/check-permissions.use-case'; import { ICheckPermissionsUseCase } from '@/src/application/use-cases/auth/check-permissions.use-case';
import { ISignInWithPasswordUseCase } from '@/src/application/use-cases/auth/sign-in-with-password.use-case';
// Pastikan DI_SYMBOLS memiliki tipe yang sesuai dengan DI_RETURN_TYPES // Pastikan DI_SYMBOLS memiliki tipe yang sesuai dengan DI_RETURN_TYPES
export const DI_SYMBOLS: { [K in keyof DI_RETURN_TYPES]: symbol } = { export const DI_SYMBOLS: { [K in keyof DI_RETURN_TYPES]: symbol } = {
@ -96,6 +97,7 @@ export const DI_SYMBOLS: { [K in keyof DI_RETURN_TYPES]: symbol } = {
// Auth Use Cases // Auth Use Cases
ISignInPasswordlessUseCase: Symbol.for('ISignInPasswordlessUseCase'), ISignInPasswordlessUseCase: Symbol.for('ISignInPasswordlessUseCase'),
ISignInWithPasswordUseCase: Symbol.for('ISignInWithPasswordUseCase'),
ISignUpUseCase: Symbol.for('ISignUpUseCase'), ISignUpUseCase: Symbol.for('ISignUpUseCase'),
IVerifyOtpUseCase: Symbol.for('IVerifyOtpUseCase'), IVerifyOtpUseCase: Symbol.for('IVerifyOtpUseCase'),
ISignOutUseCase: Symbol.for('ISignOutUseCase'), ISignOutUseCase: Symbol.for('ISignOutUseCase'),
@ -204,6 +206,7 @@ export interface DI_RETURN_TYPES {
// Auth Use Cases // Auth Use Cases
ISignInPasswordlessUseCase: ISignInPasswordlessUseCase; ISignInPasswordlessUseCase: ISignInPasswordlessUseCase;
ISignInWithPasswordUseCase: ISignInWithPasswordUseCase;
ISignUpUseCase: ISignUpUseCase; ISignUpUseCase: ISignUpUseCase;
IVerifyOtpUseCase: IVerifyOtpUseCase; IVerifyOtpUseCase: IVerifyOtpUseCase;
ISignOutUseCase: ISignOutUseCase; ISignOutUseCase: ISignOutUseCase;

View File

@ -19,8 +19,8 @@ export interface IUsersRepository {
createUser(input: ICreateUserSchema, tx?: ITransaction): Promise<IUserSupabaseSchema>; createUser(input: ICreateUserSchema, tx?: ITransaction): Promise<IUserSupabaseSchema>;
inviteUser(credential: ICredentialsInviteUserSchema, tx?: ITransaction): Promise<IUserSupabaseSchema>; inviteUser(credential: ICredentialsInviteUserSchema, tx?: ITransaction): Promise<IUserSupabaseSchema>;
updateUser(credential: ICredentialUpdateUserSchema, input: Partial<IUpdateUserSchema>, tx?: ITransaction): Promise<IUserSchema>; updateUser(credential: ICredentialUpdateUserSchema, input: Partial<IUpdateUserSchema>, tx?: ITransaction): Promise<IUserSchema>;
deleteUser(credential: ICredentialsDeleteUserSchema, tx?: ITransaction): Promise<IUserSchema>; deleteUser(credential: ICredentialsDeleteUserSchema, tx?: ITransaction): Promise<void>;
banUser(credential: ICredentialsBanUserSchema, input: IBanUserSchema, tx?: ITransaction): Promise<IUserSchema>; banUser(credential: ICredentialsBanUserSchema, input: IBanUserSchema, tx?: ITransaction): Promise<void>;
unbanUser(credential: ICredentialsUnbanUserSchema, tx?: ITransaction): Promise<IUserSchema>; unbanUser(credential: ICredentialsUnbanUserSchema, tx?: ITransaction): Promise<void>;
uploadAvatar(userId: string, file: File): Promise<string>; uploadAvatar(userId: string, file: File): Promise<string>;
} }

View File

@ -2,10 +2,10 @@ import { z } from "zod";
import { UserSchema } from "@/src/entities/models/users/users.model"; import { UserSchema } from "@/src/entities/models/users/users.model";
export const SessionSchema = z.object({ export const SessionSchema = z.object({
user: UserSchema.pick({ user: z.object({
id: true, id: z.string(),
email: true, email: z.string().email().optional(),
roles_id: true, role_id: z.string().optional(),
}), }),
expiresAt: z.number().optional(), expiresAt: z.number().optional(),
}); });

View File

@ -39,7 +39,7 @@ const timestampSchema = z.union([z.string(), z.date()]).nullable();
export const UserSchema = z.object({ export const UserSchema = z.object({
id: z.string(), id: z.string(),
roles_id: z.string().optional(), // Sesuaikan dengan field di Prisma roles_id: z.string().optional(), // Sesuaikan dengan field di Prisma
email: z.string().email().optional(), email: z.string().email(),
email_confirmed_at: z.union([z.string(), z.date()]).nullable().optional(), email_confirmed_at: z.union([z.string(), z.date()]).nullable().optional(),
encrypted_password: z.string().nullable().optional(), encrypted_password: z.string().nullable().optional(),
invited_at: z.union([z.string(), z.date()]).nullable().optional(), invited_at: z.union([z.string(), z.date()]).nullable().optional(),

View File

@ -69,18 +69,28 @@ export class PermissionsRepository implements IPermissionsRepository {
} }
async checkPermission(role: string, action: string, resource: string): Promise<boolean> { async checkPermission(role: string, action: string, resource: string): Promise<boolean> {
const result = await db.permissions.findFirst({ return await this.instrumentationService.startSpan({ name: "Check Permission" },
where: { async () => {
role: { try {
name: role
}, const result = await db.permissions.findFirst({
action: action, where: {
resource: { role: {
name: resource name: role
},
action: action,
resource: {
name: resource
}
}
});
return !!result;
} catch (err) {
this.crashReporterService.report(err);
throw err;
} }
} }
}); )
return !!result;
} }
} }

View File

@ -412,7 +412,7 @@ export class UsersRepository implements IUsersRepository {
}) })
} }
async deleteUser(credential: ICredentialsDeleteUserSchema, tx?: ITransaction): Promise<IUserSchema> { async deleteUser(credential: ICredentialsDeleteUserSchema, tx?: ITransaction): Promise<void> {
return await this.instrumentationService.startSpan({ return await this.instrumentationService.startSpan({
name: "UsersRepository > deleteUser", name: "UsersRepository > deleteUser",
}, async () => { }, async () => {
@ -435,10 +435,7 @@ export class UsersRepository implements IUsersRepository {
throw new DatabaseOperationError("Failed to delete user"); throw new DatabaseOperationError("Failed to delete user");
} }
return { return;
...user,
id: credential.id,
};
} catch (err) { } catch (err) {
this.crashReporterService.report(err); this.crashReporterService.report(err);
@ -447,7 +444,7 @@ export class UsersRepository implements IUsersRepository {
}) })
} }
async banUser(credential: ICredentialsBanUserSchema, input: IBanUserSchema, tx?: ITransaction): Promise<IUserSchema> { async banUser(credential: ICredentialsBanUserSchema, input: IBanUserSchema, tx?: ITransaction): Promise<void> {
return await this.instrumentationService.startSpan({ return await this.instrumentationService.startSpan({
name: "UsersRepository > banUser", name: "UsersRepository > banUser",
}, async () => { }, async () => {
@ -472,10 +469,7 @@ export class UsersRepository implements IUsersRepository {
throw new DatabaseOperationError("Failed to ban user"); throw new DatabaseOperationError("Failed to ban user");
} }
return { return;
...user,
id: credential.id,
};
} catch (err) { } catch (err) {
this.crashReporterService.report(err); this.crashReporterService.report(err);
@ -485,7 +479,7 @@ export class UsersRepository implements IUsersRepository {
} }
async unbanUser(credential: ICredentialsUnbanUserSchema, tx?: ITransaction): Promise<IUserSchema> { async unbanUser(credential: ICredentialsUnbanUserSchema, tx?: ITransaction): Promise<void> {
return await this.instrumentationService.startSpan({ return await this.instrumentationService.startSpan({
name: "UsersRepository > unbanUser", name: "UsersRepository > unbanUser",
}, async () => { }, async () => {
@ -510,10 +504,7 @@ export class UsersRepository implements IUsersRepository {
throw new DatabaseOperationError("Failed to unban user"); throw new DatabaseOperationError("Failed to unban user");
} }
return { return;
...user,
id: credential.id,
};
} catch (err) { } catch (err) {
this.crashReporterService.report(err); this.crashReporterService.report(err);

View File

@ -279,22 +279,33 @@ export class AuthenticationService implements IAuthenticationService {
async checkPermission(userId: string, action: string, resource: string): Promise<boolean> { async checkPermission(userId: string, action: string, resource: string): Promise<boolean> {
return await this.instrumentationService.startSpan({ return await this.instrumentationService.startSpan({
name: "checkPermission Use Case", name: "",
}, async () => { }, async () => {
try { try {
const user = await db.users.findUnique({
where: { id: userId },
include: { role: true }
});
if (!user) { // const user = await db.users.findUnique({
return false; // where: { id: userId },
} // include: { role: true }
// });
const role = user.role.name; // if (!user) {
// return false;
// }
return await this.permissionRepository.checkPermission(role, action, resource); // const role = user.role.name;
// const permission = await db.permissions.findFirst({
// where: {
// role: { name: role },
// action,
// resource: {
// name: resource
// }
// }
// })
return true
} catch (err) { } catch (err) {
this.crashReporterService.report(err) this.crashReporterService.report(err)

View File

@ -1,3 +1,4 @@
import { IUsersRepository } from "@/src/application/repositories/users.repository.interface";
import { IInstrumentationService } from "@/src/application/services/instrumentation.service.interface"; import { IInstrumentationService } from "@/src/application/services/instrumentation.service.interface";
import { ICheckPermissionsUseCase } from "@/src/application/use-cases/auth/check-permissions.use-case"; import { ICheckPermissionsUseCase } from "@/src/application/use-cases/auth/check-permissions.use-case";
import { InputParseError } from "@/src/entities/errors/common"; import { InputParseError } from "@/src/entities/errors/common";
@ -15,11 +16,19 @@ export type ICheckPermissionsController = ReturnType<typeof checkPermissionsCont
export const checkPermissionsController = export const checkPermissionsController =
( (
instrumentationService: IInstrumentationService, instrumentationService: IInstrumentationService,
checkPermissionUseCase: ICheckPermissionsUseCase checkPermissionUseCase: ICheckPermissionsUseCase,
usersRpository: IUsersRepository
) => ) =>
async (input: Partial<z.infer<typeof checkPermissionInputSchema>>) => { async (input: Partial<z.infer<typeof checkPermissionInputSchema>>) => {
return await instrumentationService.startSpan({ name: "checkPermission Controller" }, return await instrumentationService.startSpan({ name: "checkPermission Controller" },
async () => { async () => {
// const session = await usersRpository.getCurrentUser()
// if (!session) {
// throw new InputParseError("User not found")
// }
const { data, error: inputParseError } = checkPermissionInputSchema.safeParse(input) const { data, error: inputParseError } = checkPermissionInputSchema.safeParse(input)
if (inputParseError) { if (inputParseError) {