1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-06-04 01:18:20 +02:00
unleash.unleash/src/lib/features/project/project-owners-read-model.ts
Thomas Heartman 79c3f8e975
refactor: switch projectStore.getProjects with projectReadModel.getProjectsForAdminUi in project service (#7904)
Hooks up the new project read model and updates the existing project
service to use it instead when the flag is on.

In doing:
- creates a composition root for the read model
- includes it in IUnleashStores
- updates some existing methods to accept either the old or the new
model
- updates the OpenAPI schema to deprecate the old properties
2024-08-19 08:46:50 +02:00

150 lines
4.5 KiB
TypeScript

import type { Db } from '../../db/db';
import { RoleName } from '../../types';
import { anonymise, generateImageUrl } from '../../util';
import type {
GroupProjectOwner,
IProjectOwnersReadModel,
IProjectForUiWithOwners,
ProjectOwnersDictionary,
UserProjectOwner,
} from './project-owners-read-model.type';
import type { ProjectForUi } from './project-read-model-type';
const T = {
ROLE_USER: 'role_user',
GROUP_ROLE: 'group_role',
ROLES: 'roles',
USERS: 'users',
};
export class ProjectOwnersReadModel implements IProjectOwnersReadModel {
private db: Db;
constructor(db: Db) {
this.db = db;
}
static addOwnerData(
projects: ProjectForUi[],
owners: ProjectOwnersDictionary,
): IProjectForUiWithOwners[] {
return projects.map((project) => ({
...project,
owners: owners[project.id] || [{ ownerType: 'system' }],
}));
}
private async getAllProjectUsersByRole(
roleId: number,
anonymizeProjectOwners: boolean = false,
): Promise<Record<string, UserProjectOwner[]>> {
const usersResult = await this.db
.select(
'user.id',
'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<string, UserProjectOwner[]> = {};
const processSensitiveData = anonymizeProjectOwners
? anonymise
: (x: string) => x;
usersResult.forEach((user) => {
const project = user.project as string;
const data: UserProjectOwner = {
ownerType: 'user',
name: user?.name || user?.username,
email: processSensitiveData(user?.email),
imageUrl: generateImageUrl(user),
};
if (project in usersDict) {
usersDict[project] = [...usersDict[project], data];
} else {
usersDict[project] = [data];
}
});
return usersDict;
}
private async getAllProjectGroupsByRole(
roleId: number,
): Promise<Record<string, GroupProjectOwner[]>> {
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<string, GroupProjectOwner[]> = {};
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(
anonymizeProjectOwners: boolean = false,
): Promise<ProjectOwnersDictionary> {
const ownerRole = await this.db(T.ROLES)
.where({ name: RoleName.OWNER })
.first();
const usersDict = await this.getAllProjectUsersByRole(
ownerRole.id,
anonymizeProjectOwners,
);
const groupsDict = await this.getAllProjectGroupsByRole(ownerRole.id);
const dict: Record<
string,
Array<UserProjectOwner | GroupProjectOwner>
> = 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: ProjectForUi[],
anonymizeProjectOwners: boolean = false,
): Promise<IProjectForUiWithOwners[]> {
const owners = await this.getAllProjectOwners(anonymizeProjectOwners);
return ProjectOwnersReadModel.addOwnerData(projects, owners);
}
}