import { ok, err } from "@tailor-platform/erp-kit/core"; import type { Transaction } from "../generated/kysely-tailordb"; import { AssignmentNotFoundError, RoleNotFoundError, UserNotFoundError, } from "../lib/errors.generated"; import { recomputeUserPermissions } from "../lib/recomputeUserPermissions"; export interface RevokeRoleFromUserInput { userId: string; roleId: string; } /** * Function: revokeRoleFromUser * * Removes a role from a user. * Throws an error if the assignment does not exist. */ export async function run(db: Transaction, input: RevokeRoleFromUserInput) { const user = await db .selectFrom("User") .selectAll() .where("id", "=", input.userId) .executeTakeFirst(); if (!user) { return err(new UserNotFoundError(input.userId)); } const role = await db .selectFrom("Role") .selectAll() .where("id", "=", input.roleId) .executeTakeFirst(); if (!role) { return err(new RoleNotFoundError(input.roleId)); } const existingAssignment = await db .selectFrom("UserRole") .selectAll() .where("userId", "=", input.userId) .where("roleId", "=", input.roleId) .forUpdate() .executeTakeFirst(); if (!existingAssignment) { return err(new AssignmentNotFoundError(`User ${input.userId} -> Role ${input.roleId}`)); } await db .deleteFrom("UserRole") .where("id", "=", existingAssignment.id) .returningAll() .executeTakeFirst(); const updatedUser = await recomputeUserPermissions(db, input.userId); return ok({ user: updatedUser }); }