mirror of
https://github.com/hanzoai/calendar.git
synced 2026-10-30 14:46:43 +00:00
163 lines
5.0 KiB
TypeScript
163 lines
5.0 KiB
TypeScript
import { v4 as uuidv4 } from "uuid";
|
|
|
|
import type { PrismaClient as PrismaWithExtensions } from "@calcom/prisma";
|
|
import db from "@calcom/prisma";
|
|
|
|
import type { Role, RolePermission, PermissionChange, CreateRoleData } from "../../domain/models/Role";
|
|
import { RoleType } from "../../domain/models/Role";
|
|
import { parsePermissionString } from "../../domain/types/permission-registry";
|
|
import { RoleOutputMapper } from "../mappers/RoleOutputMapper";
|
|
|
|
export class RoleRepository {
|
|
constructor(private readonly client: PrismaWithExtensions = db) {}
|
|
|
|
async findByName(name: string, teamId?: number): Promise<Role | null> {
|
|
const role = await this.client.role.findFirst({
|
|
where: { name, teamId: teamId ?? null },
|
|
include: { permissions: true },
|
|
});
|
|
return role ? RoleOutputMapper.toDomain(role) : null;
|
|
}
|
|
|
|
async findByTeamId(teamId: number): Promise<Role[]> {
|
|
const roles = await this.client.role.findMany({
|
|
where: {
|
|
OR: [
|
|
{ teamId }, // Team-specific custom roles
|
|
{ teamId: null, type: "SYSTEM" }, // Default/system roles available to all teams
|
|
],
|
|
},
|
|
include: { permissions: true },
|
|
});
|
|
return RoleOutputMapper.toDomainList(roles);
|
|
}
|
|
|
|
async roleBelongsToTeam(roleId: string, teamId: number): Promise<boolean> {
|
|
const role = await this.client.role.findUnique({
|
|
where: { id: roleId },
|
|
select: { teamId: true },
|
|
});
|
|
return role?.teamId === teamId;
|
|
}
|
|
|
|
async create(data: CreateRoleData): Promise<Role> {
|
|
const roleId = await this.client.$transaction(async (trx) => {
|
|
const role = await trx.role.create({
|
|
data: {
|
|
id: uuidv4(),
|
|
name: data.name,
|
|
color: data.color ?? null,
|
|
description: data.description ?? null,
|
|
teamId: data.teamId ?? null,
|
|
type: data.type ?? RoleType.CUSTOM,
|
|
},
|
|
});
|
|
|
|
if (data.permissions.length > 0) {
|
|
const permissionData = data.permissions.map((permission) => {
|
|
const { resource, action } = parsePermissionString(permission);
|
|
return {
|
|
id: uuidv4(),
|
|
roleId: role.id,
|
|
resource,
|
|
action,
|
|
};
|
|
});
|
|
|
|
await trx.rolePermission.createMany({ data: permissionData });
|
|
}
|
|
return role.id;
|
|
});
|
|
|
|
const completeRole = await this.findById(roleId);
|
|
if (!completeRole) throw new Error("Failed to create role");
|
|
|
|
return completeRole;
|
|
}
|
|
|
|
async delete(id: string): Promise<void> {
|
|
await this.client.$transaction([
|
|
this.client.rolePermission.deleteMany({ where: { roleId: id } }),
|
|
this.client.role.delete({ where: { id } }),
|
|
]);
|
|
}
|
|
|
|
async reassignUsersToRole(fromRoleId: string, toRoleId: string): Promise<void> {
|
|
await this.client.membership.updateMany({
|
|
where: { customRoleId: fromRoleId },
|
|
data: { customRoleId: toRoleId },
|
|
});
|
|
}
|
|
|
|
async update(
|
|
roleId: string,
|
|
permissionChanges: {
|
|
toAdd: PermissionChange[];
|
|
toRemove: PermissionChange[];
|
|
},
|
|
updates?: {
|
|
color?: string;
|
|
name?: string;
|
|
description?: string;
|
|
}
|
|
) {
|
|
await this.client.$transaction(async (trx) => {
|
|
// Update role metadata if provided
|
|
if (updates) {
|
|
const updateData: Record<string, any> = {};
|
|
if (updates.color !== undefined) updateData.color = updates.color || null;
|
|
if (updates.name !== undefined) updateData.name = updates.name;
|
|
if (updates.description !== undefined) updateData.description = updates.description || null;
|
|
await trx.role.update({ where: { id: roleId }, data: updateData });
|
|
}
|
|
|
|
// Remove permissions that are no longer needed
|
|
if (permissionChanges.toRemove.length > 0) {
|
|
await trx.rolePermission.deleteMany({
|
|
where: {
|
|
roleId,
|
|
OR: permissionChanges.toRemove.map((p) => ({
|
|
resource: p.resource,
|
|
action: p.action,
|
|
})),
|
|
},
|
|
});
|
|
}
|
|
|
|
// Add new permissions
|
|
if (permissionChanges.toAdd.length > 0) {
|
|
const permissionData = permissionChanges.toAdd.map((permission) => ({
|
|
id: uuidv4(),
|
|
roleId,
|
|
resource: permission.resource,
|
|
action: permission.action,
|
|
}));
|
|
|
|
await trx.rolePermission.createMany({ data: permissionData });
|
|
}
|
|
});
|
|
|
|
// Fetch complete role with permissions
|
|
const completeRole = await this.findById(roleId);
|
|
if (!completeRole) throw new Error("Failed to update role");
|
|
return completeRole;
|
|
}
|
|
|
|
async findById(roleId: string): Promise<Role | null> {
|
|
const role = await this.client.role.findUnique({
|
|
where: { id: roleId },
|
|
include: {
|
|
permissions: true,
|
|
},
|
|
});
|
|
return role ? RoleOutputMapper.toDomain(role) : null;
|
|
}
|
|
|
|
async getPermissions(roleId: string): Promise<RolePermission[]> {
|
|
const permissions = await this.client.rolePermission.findMany({
|
|
where: { roleId },
|
|
});
|
|
return permissions.map(RoleOutputMapper.toDomainPermission);
|
|
}
|
|
}
|