Multi-environment and multi-user construction

This commit is contained in:
2026-09-15 21:37:58 +03:30
parent e61fad95c6
commit d3f97b9dc4
37 changed files with 1349 additions and 201 deletions
+28 -32
View File
@@ -23,13 +23,24 @@ type RoleRow = {
color: string;
permissions: string[];
systemKey: string | null;
users: Array<{
id: string;
fullName: string;
avatarStorageKey: string | null;
memberships: Array<{
user: {
id: string;
fullName: string;
avatarStorageKey: string | null;
};
}>;
};
const ROLE_MEMBERS_INCLUDE = {
memberships: {
include: {
user: { select: { id: true, fullName: true, avatarStorageKey: true } },
},
orderBy: { createdAt: 'asc' as const },
},
};
@Injectable()
export class OrgRolesService {
constructor(private readonly prisma: PrismaService) {}
@@ -38,12 +49,7 @@ export class OrgRolesService {
await this.ensureDefaultRoles(organizationId);
const rows = await this.prisma.orgRole.findMany({
where: { organizationId },
include: {
users: {
select: { id: true, fullName: true, avatarStorageKey: true },
orderBy: { fullName: 'asc' },
},
},
include: ROLE_MEMBERS_INCLUDE,
orderBy: [{ systemKey: 'asc' }, { createdAt: 'asc' }],
});
return rows.map((row) => this.toDto(row));
@@ -73,12 +79,7 @@ export class OrgRolesService {
color: dto.color ?? 'teal',
permissions: dto.permissions?.length ? dto.permissions : [...ALL_ROLE_PERMISSIONS],
},
include: {
users: {
select: { id: true, fullName: true, avatarStorageKey: true },
orderBy: { fullName: 'asc' },
},
},
include: ROLE_MEMBERS_INCLUDE,
});
return this.toDto(row);
} catch (e) {
@@ -122,12 +123,7 @@ export class OrgRolesService {
const row = await this.prisma.orgRole.update({
where: { id: existing.id },
data,
include: {
users: {
select: { id: true, fullName: true, avatarStorageKey: true },
orderBy: { fullName: 'asc' },
},
},
include: ROLE_MEMBERS_INCLUDE,
});
return this.toDto(row);
} catch (e) {
@@ -189,15 +185,15 @@ export class OrgRolesService {
byKey.set(seed.systemKey, created);
}
const unassigned = await this.prisma.user.findMany({
const unassigned = await this.prisma.membership.findMany({
where: { organizationId, orgRoleId: null },
select: { id: true, role: true },
});
for (const user of unassigned) {
const role = byKey.get(user.role);
for (const membership of unassigned) {
const role = byKey.get(membership.role);
if (!role) continue;
await this.prisma.user.update({
where: { id: user.id },
await this.prisma.membership.update({
where: { id: membership.id },
data: { orgRoleId: role.id },
});
}
@@ -253,11 +249,11 @@ export class OrgRolesService {
color: row.color,
permissions: sanitizePermissions(row.permissions),
systemKey,
userCount: row.users.length,
members: row.users.map((user) => ({
id: user.id,
fullName: user.fullName,
hasAvatar: Boolean(user.avatarStorageKey),
userCount: row.memberships.length,
members: row.memberships.map((membership) => ({
id: membership.user.id,
fullName: membership.user.fullName,
hasAvatar: Boolean(membership.user.avatarStorageKey),
})),
};
}