import type { Db } from '../../db/db'; import { RoleName, type IProjectWithCount, type IRoleStore } from '../../types'; const T = { ROLE_USER: 'role_user', GROUP_ROLE: 'group_role', ROLES: 'roles', USERS: 'users', }; type SystemOwner = { ownerType: 'system' }; type UserProjectOwner = { ownerType: 'user'; name: string; email?: string; imageUrl?: string; }; type GroupProjectOwner = { ownerType: 'group'; name: string; }; type ProjectOwners = | [SystemOwner] | Array; export type ProjectOwnersDictionary = Record; type IProjectWithCountAndOwners = IProjectWithCount & { owners: ProjectOwners; }; export class ProjectOwnersReadModel { private db: Db; roleStore: IRoleStore; constructor(db: Db, roleStore: IRoleStore) { this.db = db; this.roleStore = roleStore; } static addOwnerData( projects: IProjectWithCount[], owners: ProjectOwnersDictionary, ): IProjectWithCountAndOwners[] { return projects.map((project) => ({ ...project, owners: owners[project.name] || [{ ownerType: 'system' }], })); } private async getAllProjectUsersByRole( roleId: number, ): Promise> { const usersResult = await this.db .select( 'user.username', 'user.name', 'user.email', 'user.image_url', 'ru.created_at', 'ru.project', ) .from(`${T.ROLE_USER} as ru`) .orderBy('ru.created_at', 'asc') .join(`${T.ROLES} as r`, 'ru.role_id', 'r.id') .where('r.id', roleId) .join(`${T.USERS} as user`, 'ru.user_id', 'user.id'); const usersDict: Record = {}; usersResult.forEach((user) => { const project = user.project as string; const data: UserProjectOwner = { ownerType: 'user', name: user?.name || user?.username, email: user?.email, imageUrl: user?.image_url, }; if (project in usersDict) { usersDict[project] = [...usersDict[project], data]; } else { usersDict[project] = [data]; } }); return usersDict; } private async getAllProjectGroupsByRole( roleId: number, ): Promise> { const groupsResult = await this.db .select('groups.name', 'gr.created_at', 'gr.project') .from(`${T.GROUP_ROLE} as gr`) .orderBy('gr.created_at', 'asc') .join(`${T.ROLES} as r`, 'gr.role_id', 'r.id') .where('r.id', roleId) .join('groups', 'gr.group_id', 'groups.id'); const groupsDict: Record = {}; groupsResult.forEach((group) => { const project = group.project as string; const data: GroupProjectOwner = { ownerType: 'group', name: group?.name, }; if (project in groupsDict) { groupsDict[project] = [...groupsDict[project], data]; } else { groupsDict[project] = [data]; } }); return groupsDict; } async getAllProjectOwners(): Promise { const ownerRole = await this.roleStore.getRoleByName(RoleName.OWNER); const usersDict = await this.getAllProjectUsersByRole(ownerRole.id); const groupsDict = await this.getAllProjectGroupsByRole(ownerRole.id); const dict: Record< string, Array > = usersDict; Object.keys(groupsDict).forEach((project) => { if (project in dict) { dict[project] = dict[project].concat(groupsDict[project]); } else { dict[project] = groupsDict[project]; } }); return dict; } async addOwners( projects: IProjectWithCount[], ): Promise { const owners = await this.getAllProjectOwners(); return ProjectOwnersReadModel.addOwnerData(projects, owners); } }