import { Injectable } from "@nestjs/common"; import { eq } from "drizzle-orm"; import { DatabaseService } from "../../database/database.service"; import { permissions, roles, rolesToPermissions, usersToRoles, } from "../../database/schemas"; @Injectable() export class RbacRepository { constructor(private readonly databaseService: DatabaseService) {} async findRolesByUserId(userId: string) { const result = await this.databaseService.db .select({ slug: roles.slug, }) .from(usersToRoles) .innerJoin(roles, eq(usersToRoles.roleId, roles.id)) .where(eq(usersToRoles.userId, userId)); return result.map((r) => r.slug); } async findPermissionsByUserId(userId: string) { const result = await this.databaseService.db .select({ slug: permissions.slug, }) .from(usersToRoles) .innerJoin( rolesToPermissions, eq(usersToRoles.roleId, rolesToPermissions.roleId), ) .innerJoin(permissions, eq(rolesToPermissions.permissionId, permissions.id)) .where(eq(usersToRoles.userId, userId)); return Array.from(new Set(result.map((p) => p.slug))); } async countRoles(): Promise { const result = await this.databaseService.db .select({ count: roles.id }) .from(roles); return result.length; } async countAdmins(): Promise { const result = await this.databaseService.db .select({ count: usersToRoles.userId }) .from(usersToRoles) .innerJoin(roles, eq(usersToRoles.roleId, roles.id)) .where(eq(roles.slug, "admin")); return result.length; } async createRole(name: string, slug: string, description?: string) { return this.databaseService.db .insert(roles) .values({ name, slug, description, }) .returning(); } async assignRole(userId: string, roleSlug: string) { const role = await this.databaseService.db .select() .from(roles) .where(eq(roles.slug, roleSlug)) .limit(1); if (!role[0]) { throw new Error(`Role with slug ${roleSlug} not found`); } return this.databaseService.db .insert(usersToRoles) .values({ userId, roleId: role[0].id, }) .onConflictDoNothing() .returning(); } }