2021-04-22 23:40:52 +02:00
|
|
|
import User from '../types/user';
|
2021-08-12 15:04:37 +02:00
|
|
|
import { AccessService } from './access-service';
|
2021-04-20 12:32:02 +02:00
|
|
|
import NameExistsError from '../error/name-exists-error';
|
|
|
|
import InvalidOperationError from '../error/invalid-operation-error';
|
2021-08-13 10:36:19 +02:00
|
|
|
import { nameType } from '../routes/util';
|
2021-09-14 20:43:05 +02:00
|
|
|
import { projectSchema } from './project-schema';
|
2021-04-20 12:32:02 +02:00
|
|
|
import NotFoundError from '../error/notfound-error';
|
2021-04-29 10:21:29 +02:00
|
|
|
import {
|
2022-01-14 12:14:02 +01:00
|
|
|
ProjectUserAddedEvent,
|
|
|
|
ProjectUserRemovedEvent,
|
2022-02-21 14:39:59 +01:00
|
|
|
ProjectUserUpdateRoleEvent,
|
2021-04-29 10:21:29 +02:00
|
|
|
PROJECT_CREATED,
|
|
|
|
PROJECT_DELETED,
|
|
|
|
PROJECT_UPDATED,
|
|
|
|
} from '../types/events';
|
2021-04-30 12:51:46 +02:00
|
|
|
import { IUnleashStores } from '../types/stores';
|
|
|
|
import { IUnleashConfig } from '../types/option';
|
2021-08-19 13:25:36 +02:00
|
|
|
import {
|
|
|
|
IProject,
|
|
|
|
IProjectOverview,
|
|
|
|
IProjectWithCount,
|
|
|
|
IUserWithRole,
|
2021-10-21 10:29:09 +02:00
|
|
|
FeatureToggle,
|
2021-08-19 13:25:36 +02:00
|
|
|
RoleName,
|
|
|
|
} from '../types/model';
|
2021-08-12 15:04:37 +02:00
|
|
|
import { IEnvironmentStore } from '../types/stores/environment-store';
|
|
|
|
import { IFeatureTypeStore } from '../types/stores/feature-type-store';
|
|
|
|
import { IFeatureToggleStore } from '../types/stores/feature-toggle-store';
|
2021-09-13 10:23:57 +02:00
|
|
|
import { IFeatureEnvironmentStore } from '../types/stores/feature-environment-store';
|
2021-10-01 10:59:43 +02:00
|
|
|
import { IProjectQuery, IProjectStore } from '../types/stores/project-store';
|
2022-01-13 11:14:17 +01:00
|
|
|
import { IRoleDescriptor } from '../types/stores/access-store';
|
2021-08-12 15:04:37 +02:00
|
|
|
import { IEventStore } from '../types/stores/event-store';
|
2021-11-12 13:15:51 +01:00
|
|
|
import FeatureToggleService from './feature-toggle-service';
|
2022-01-13 11:14:17 +01:00
|
|
|
import { MOVE_FEATURE_TOGGLE } from '../types/permissions';
|
2021-08-25 13:38:00 +02:00
|
|
|
import NoAccessError from '../error/no-access-error';
|
2021-10-21 10:29:09 +02:00
|
|
|
import IncompatibleProjectError from '../error/incompatible-project-error';
|
2022-01-13 11:14:17 +01:00
|
|
|
import { DEFAULT_PROJECT } from '../types/project';
|
|
|
|
import { IFeatureTagStore } from 'lib/types/stores/feature-tag-store';
|
2021-03-11 22:51:58 +01:00
|
|
|
|
|
|
|
const getCreatedBy = (user: User) => user.email || user.username;
|
|
|
|
|
2021-04-20 12:32:02 +02:00
|
|
|
export interface UsersWithRoles {
|
|
|
|
users: IUserWithRole[];
|
2022-01-13 11:14:17 +01:00
|
|
|
roles: IRoleDescriptor[];
|
2021-04-20 12:32:02 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
export default class ProjectService {
|
2021-08-19 13:25:36 +02:00
|
|
|
private store: IProjectStore;
|
2021-03-11 22:51:58 +01:00
|
|
|
|
|
|
|
private accessService: AccessService;
|
|
|
|
|
2021-08-12 15:04:37 +02:00
|
|
|
private eventStore: IEventStore;
|
2021-03-11 22:51:58 +01:00
|
|
|
|
2021-08-12 15:04:37 +02:00
|
|
|
private featureToggleStore: IFeatureToggleStore;
|
2021-03-11 22:51:58 +01:00
|
|
|
|
2021-08-12 15:04:37 +02:00
|
|
|
private featureTypeStore: IFeatureTypeStore;
|
2021-07-07 10:46:50 +02:00
|
|
|
|
2021-09-13 10:23:57 +02:00
|
|
|
private featureEnvironmentStore: IFeatureEnvironmentStore;
|
|
|
|
|
2021-08-12 15:04:37 +02:00
|
|
|
private environmentStore: IEnvironmentStore;
|
2021-07-14 13:20:36 +02:00
|
|
|
|
2021-03-11 22:51:58 +01:00
|
|
|
private logger: any;
|
|
|
|
|
2021-11-12 13:15:51 +01:00
|
|
|
private featureToggleService: FeatureToggleService;
|
2021-08-19 13:25:36 +02:00
|
|
|
|
2022-01-13 11:14:17 +01:00
|
|
|
private tagStore: IFeatureTagStore;
|
|
|
|
|
2021-03-11 22:51:58 +01:00
|
|
|
constructor(
|
2021-04-30 12:51:46 +02:00
|
|
|
{
|
|
|
|
projectStore,
|
|
|
|
eventStore,
|
|
|
|
featureToggleStore,
|
2021-07-07 10:46:50 +02:00
|
|
|
featureTypeStore,
|
2021-07-14 13:20:36 +02:00
|
|
|
environmentStore,
|
2021-09-13 10:23:57 +02:00
|
|
|
featureEnvironmentStore,
|
2022-01-13 11:14:17 +01:00
|
|
|
featureTagStore,
|
2021-04-30 12:51:46 +02:00
|
|
|
}: Pick<
|
2021-07-07 10:46:50 +02:00
|
|
|
IUnleashStores,
|
|
|
|
| 'projectStore'
|
|
|
|
| 'eventStore'
|
|
|
|
| 'featureToggleStore'
|
|
|
|
| 'featureTypeStore'
|
2021-07-14 13:20:36 +02:00
|
|
|
| 'environmentStore'
|
2021-09-13 10:23:57 +02:00
|
|
|
| 'featureEnvironmentStore'
|
2022-01-13 11:14:17 +01:00
|
|
|
| 'featureTagStore'
|
2021-04-30 12:51:46 +02:00
|
|
|
>,
|
|
|
|
config: IUnleashConfig,
|
2021-03-11 22:51:58 +01:00
|
|
|
accessService: AccessService,
|
2021-11-12 13:15:51 +01:00
|
|
|
featureToggleService: FeatureToggleService,
|
2021-03-11 22:51:58 +01:00
|
|
|
) {
|
2021-08-19 13:25:36 +02:00
|
|
|
this.store = projectStore;
|
2021-07-14 13:20:36 +02:00
|
|
|
this.environmentStore = environmentStore;
|
2021-09-13 10:23:57 +02:00
|
|
|
this.featureEnvironmentStore = featureEnvironmentStore;
|
2021-03-11 22:51:58 +01:00
|
|
|
this.accessService = accessService;
|
|
|
|
this.eventStore = eventStore;
|
|
|
|
this.featureToggleStore = featureToggleStore;
|
2021-07-07 10:46:50 +02:00
|
|
|
this.featureTypeStore = featureTypeStore;
|
2021-08-19 13:25:36 +02:00
|
|
|
this.featureToggleService = featureToggleService;
|
2022-01-13 11:14:17 +01:00
|
|
|
this.tagStore = featureTagStore;
|
2021-03-11 22:51:58 +01:00
|
|
|
this.logger = config.getLogger('services/project-service.js');
|
|
|
|
}
|
|
|
|
|
2021-10-01 10:59:43 +02:00
|
|
|
async getProjects(query?: IProjectQuery): Promise<IProjectWithCount[]> {
|
2022-02-21 12:46:28 +01:00
|
|
|
return this.store.getProjectsWithCounts(query);
|
2021-03-11 22:51:58 +01:00
|
|
|
}
|
|
|
|
|
2021-04-30 12:51:46 +02:00
|
|
|
async getProject(id: string): Promise<IProject> {
|
2021-08-19 13:25:36 +02:00
|
|
|
return this.store.get(id);
|
2021-03-11 22:51:58 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
async createProject(newProject: IProject, user: User): Promise<IProject> {
|
2021-09-14 20:36:40 +02:00
|
|
|
const data = await projectSchema.validateAsync(newProject);
|
2021-03-11 22:51:58 +01:00
|
|
|
await this.validateUniqueId(data.id);
|
|
|
|
|
2021-08-19 13:25:36 +02:00
|
|
|
await this.store.create(data);
|
2021-03-11 22:51:58 +01:00
|
|
|
|
2021-11-26 15:31:36 +01:00
|
|
|
const enabledEnvironments = await this.environmentStore.getAll({
|
|
|
|
enabled: true,
|
|
|
|
});
|
|
|
|
|
|
|
|
// TODO: Only if enabled!
|
|
|
|
await Promise.all(
|
|
|
|
enabledEnvironments.map(async (e) => {
|
|
|
|
await this.featureEnvironmentStore.connectProject(
|
|
|
|
e.name,
|
|
|
|
data.id,
|
|
|
|
);
|
|
|
|
}),
|
|
|
|
);
|
2021-07-14 13:20:36 +02:00
|
|
|
|
2021-04-12 20:25:03 +02:00
|
|
|
await this.accessService.createDefaultProjectRoles(user, data.id);
|
2021-03-11 22:51:58 +01:00
|
|
|
|
|
|
|
await this.eventStore.store({
|
2021-04-29 10:21:29 +02:00
|
|
|
type: PROJECT_CREATED,
|
2021-03-11 22:51:58 +01:00
|
|
|
createdBy: getCreatedBy(user),
|
|
|
|
data,
|
2021-09-20 12:13:38 +02:00
|
|
|
project: newProject.id,
|
2021-03-11 22:51:58 +01:00
|
|
|
});
|
|
|
|
|
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
|
|
|
async updateProject(updatedProject: IProject, user: User): Promise<void> {
|
2021-11-12 13:15:51 +01:00
|
|
|
const preData = await this.store.get(updatedProject.id);
|
2021-09-14 20:36:40 +02:00
|
|
|
const project = await projectSchema.validateAsync(updatedProject);
|
2021-03-11 22:51:58 +01:00
|
|
|
|
2021-08-19 13:25:36 +02:00
|
|
|
await this.store.update(project);
|
2021-03-11 22:51:58 +01:00
|
|
|
|
|
|
|
await this.eventStore.store({
|
2021-04-29 10:21:29 +02:00
|
|
|
type: PROJECT_UPDATED,
|
2021-11-12 13:15:51 +01:00
|
|
|
project: project.id,
|
2021-03-11 22:51:58 +01:00
|
|
|
createdBy: getCreatedBy(user),
|
|
|
|
data: project,
|
2021-11-12 13:15:51 +01:00
|
|
|
preData,
|
2021-03-11 22:51:58 +01:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2021-10-21 10:29:09 +02:00
|
|
|
async checkProjectsCompatibility(
|
|
|
|
feature: FeatureToggle,
|
|
|
|
newProjectId: string,
|
|
|
|
): Promise<boolean> {
|
|
|
|
const featureEnvs = await this.featureEnvironmentStore.getAll({
|
|
|
|
feature_name: feature.name,
|
|
|
|
});
|
|
|
|
const newEnvs = await this.store.getEnvironmentsForProject(
|
|
|
|
newProjectId,
|
|
|
|
);
|
|
|
|
return featureEnvs.every(
|
|
|
|
(e) => !e.enabled || newEnvs.includes(e.environment),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2021-08-25 13:38:00 +02:00
|
|
|
async changeProject(
|
|
|
|
newProjectId: string,
|
|
|
|
featureName: string,
|
|
|
|
user: User,
|
|
|
|
currentProjectId: string,
|
|
|
|
): Promise<any> {
|
|
|
|
const feature = await this.featureToggleStore.get(featureName);
|
|
|
|
|
|
|
|
if (feature.project !== currentProjectId) {
|
2022-01-13 11:14:17 +01:00
|
|
|
throw new NoAccessError(MOVE_FEATURE_TOGGLE);
|
2021-08-25 13:38:00 +02:00
|
|
|
}
|
|
|
|
const project = await this.getProject(newProjectId);
|
|
|
|
|
|
|
|
if (!project) {
|
|
|
|
throw new NotFoundError(`Project ${newProjectId} not found`);
|
|
|
|
}
|
|
|
|
|
|
|
|
const authorized = await this.accessService.hasPermission(
|
|
|
|
user,
|
2022-01-13 11:14:17 +01:00
|
|
|
MOVE_FEATURE_TOGGLE,
|
2021-08-25 13:38:00 +02:00
|
|
|
newProjectId,
|
|
|
|
);
|
|
|
|
|
|
|
|
if (!authorized) {
|
2022-01-13 11:14:17 +01:00
|
|
|
throw new NoAccessError(MOVE_FEATURE_TOGGLE);
|
2021-08-25 13:38:00 +02:00
|
|
|
}
|
|
|
|
|
2021-10-21 10:29:09 +02:00
|
|
|
const isCompatibleWithTargetProject =
|
|
|
|
await this.checkProjectsCompatibility(feature, newProjectId);
|
|
|
|
if (!isCompatibleWithTargetProject) {
|
|
|
|
throw new IncompatibleProjectError(newProjectId);
|
|
|
|
}
|
2021-10-21 21:06:56 +02:00
|
|
|
const updatedFeature = await this.featureToggleService.changeProject(
|
2021-08-25 13:38:00 +02:00
|
|
|
featureName,
|
|
|
|
newProjectId,
|
|
|
|
user.username,
|
|
|
|
);
|
2021-10-19 09:49:43 +02:00
|
|
|
await this.featureToggleService.updateFeatureStrategyProject(
|
|
|
|
featureName,
|
|
|
|
newProjectId,
|
|
|
|
);
|
2021-08-25 13:38:00 +02:00
|
|
|
|
|
|
|
return updatedFeature;
|
|
|
|
}
|
|
|
|
|
2021-03-11 22:51:58 +01:00
|
|
|
async deleteProject(id: string, user: User): Promise<void> {
|
|
|
|
if (id === DEFAULT_PROJECT) {
|
|
|
|
throw new InvalidOperationError(
|
|
|
|
'You can not delete the default project!',
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2021-09-13 10:23:57 +02:00
|
|
|
const toggles = await this.featureToggleStore.getAll({
|
2021-03-11 22:51:58 +01:00
|
|
|
project: id,
|
2021-07-07 10:46:50 +02:00
|
|
|
archived: false,
|
2021-03-11 22:51:58 +01:00
|
|
|
});
|
|
|
|
|
|
|
|
if (toggles.length > 0) {
|
|
|
|
throw new InvalidOperationError(
|
2021-07-07 10:46:50 +02:00
|
|
|
'You can not delete a project with active feature toggles',
|
2021-03-11 22:51:58 +01:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2021-08-19 13:25:36 +02:00
|
|
|
await this.store.delete(id);
|
2021-03-11 22:51:58 +01:00
|
|
|
|
|
|
|
await this.eventStore.store({
|
2021-04-29 10:21:29 +02:00
|
|
|
type: PROJECT_DELETED,
|
2021-03-11 22:51:58 +01:00
|
|
|
createdBy: getCreatedBy(user),
|
2021-09-20 12:13:38 +02:00
|
|
|
project: id,
|
2021-03-11 22:51:58 +01:00
|
|
|
});
|
|
|
|
|
2021-09-20 12:13:38 +02:00
|
|
|
await this.accessService.removeDefaultProjectRoles(user, id);
|
2021-03-11 22:51:58 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
async validateId(id: string): Promise<boolean> {
|
|
|
|
await nameType.validateAsync(id);
|
|
|
|
await this.validateUniqueId(id);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
async validateUniqueId(id: string): Promise<void> {
|
2021-08-19 13:25:36 +02:00
|
|
|
const exists = await this.store.hasProject(id);
|
2021-08-12 15:04:37 +02:00
|
|
|
if (exists) {
|
|
|
|
throw new NameExistsError('A project with this id already exists.');
|
2021-03-11 22:51:58 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// RBAC methods
|
2021-04-20 12:32:02 +02:00
|
|
|
async getUsersWithAccess(projectId: string): Promise<UsersWithRoles> {
|
2021-03-11 22:51:58 +01:00
|
|
|
const [roles, users] = await this.accessService.getProjectRoleUsers(
|
|
|
|
projectId,
|
|
|
|
);
|
|
|
|
|
|
|
|
return {
|
|
|
|
roles,
|
|
|
|
users,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2022-01-14 12:14:02 +01:00
|
|
|
// TODO: Remove the optional nature of createdBy - this in place to make sure enterprise is compatible
|
2021-03-11 22:51:58 +01:00
|
|
|
async addUser(
|
|
|
|
projectId: string,
|
|
|
|
roleId: number,
|
|
|
|
userId: number,
|
2022-01-14 12:14:02 +01:00
|
|
|
createdBy?: string,
|
2021-03-11 22:51:58 +01:00
|
|
|
): Promise<void> {
|
|
|
|
const [roles, users] = await this.accessService.getProjectRoleUsers(
|
|
|
|
projectId,
|
|
|
|
);
|
|
|
|
|
2021-08-12 15:04:37 +02:00
|
|
|
const role = roles.find((r) => r.id === roleId);
|
2021-03-11 22:51:58 +01:00
|
|
|
if (!role) {
|
|
|
|
throw new NotFoundError(
|
|
|
|
`Could not find roleId=${roleId} on project=${projectId}`,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2021-08-12 15:04:37 +02:00
|
|
|
const alreadyHasAccess = users.some((u) => u.id === userId);
|
2021-03-11 22:51:58 +01:00
|
|
|
if (alreadyHasAccess) {
|
2022-01-13 11:14:17 +01:00
|
|
|
throw new Error(`User already has access to project=${projectId}`);
|
2021-03-11 22:51:58 +01:00
|
|
|
}
|
|
|
|
|
2022-01-13 11:14:17 +01:00
|
|
|
await this.accessService.addUserToRole(userId, role.id, projectId);
|
2022-01-14 12:14:02 +01:00
|
|
|
|
|
|
|
await this.eventStore.store(
|
|
|
|
new ProjectUserAddedEvent({
|
|
|
|
project: projectId,
|
|
|
|
createdBy,
|
|
|
|
data: { roleId, userId, roleName: role.name },
|
|
|
|
}),
|
|
|
|
);
|
2021-03-11 22:51:58 +01:00
|
|
|
}
|
|
|
|
|
2022-01-14 12:14:02 +01:00
|
|
|
// TODO: Remove the optional nature of createdBy - this in place to make sure enterprise is compatible
|
2021-03-11 22:51:58 +01:00
|
|
|
async removeUser(
|
|
|
|
projectId: string,
|
|
|
|
roleId: number,
|
|
|
|
userId: number,
|
2022-01-14 12:14:02 +01:00
|
|
|
createdBy?: string,
|
2021-03-11 22:51:58 +01:00
|
|
|
): Promise<void> {
|
2022-02-21 14:39:59 +01:00
|
|
|
const role = await this.findProjectRole(projectId, roleId);
|
|
|
|
|
|
|
|
await this.validateAtLeastOneOwner(projectId, role);
|
|
|
|
|
|
|
|
await this.accessService.removeUserFromRole(userId, role.id, projectId);
|
|
|
|
|
|
|
|
await this.eventStore.store(
|
|
|
|
new ProjectUserRemovedEvent({
|
|
|
|
project: projectId,
|
|
|
|
createdBy,
|
|
|
|
preData: { roleId, userId, roleName: role.name },
|
|
|
|
}),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
async findProjectRole(
|
|
|
|
projectId: string,
|
|
|
|
roleId: number,
|
|
|
|
): Promise<IRoleDescriptor> {
|
2021-03-11 22:51:58 +01:00
|
|
|
const roles = await this.accessService.getRolesForProject(projectId);
|
2021-08-12 15:04:37 +02:00
|
|
|
const role = roles.find((r) => r.id === roleId);
|
2021-03-11 22:51:58 +01:00
|
|
|
if (!role) {
|
|
|
|
throw new NotFoundError(
|
|
|
|
`Couldn't find roleId=${roleId} on project=${projectId}`,
|
|
|
|
);
|
|
|
|
}
|
2022-02-21 14:39:59 +01:00
|
|
|
return role;
|
|
|
|
}
|
2021-03-11 22:51:58 +01:00
|
|
|
|
2022-02-21 14:39:59 +01:00
|
|
|
async validateAtLeastOneOwner(
|
|
|
|
projectId: string,
|
|
|
|
currentRole: IRoleDescriptor,
|
|
|
|
): Promise<void> {
|
|
|
|
if (currentRole.name === RoleName.OWNER) {
|
2022-01-13 11:14:17 +01:00
|
|
|
const users = await this.accessService.getProjectUsersForRole(
|
2022-02-21 14:39:59 +01:00
|
|
|
currentRole.id,
|
2022-01-13 11:14:17 +01:00
|
|
|
projectId,
|
|
|
|
);
|
2021-03-11 22:51:58 +01:00
|
|
|
if (users.length < 2) {
|
2021-05-25 19:28:29 +02:00
|
|
|
throw new Error('A project must have at least one owner');
|
2021-03-11 22:51:58 +01:00
|
|
|
}
|
|
|
|
}
|
2022-02-21 14:39:59 +01:00
|
|
|
}
|
2021-03-11 22:51:58 +01:00
|
|
|
|
2022-02-21 14:39:59 +01:00
|
|
|
async changeRole(
|
|
|
|
projectId: string,
|
|
|
|
roleId: number,
|
|
|
|
userId: number,
|
|
|
|
createdBy: string,
|
|
|
|
): Promise<void> {
|
|
|
|
const role = await this.findProjectRole(projectId, roleId);
|
|
|
|
|
|
|
|
const usersWithRoles = await this.getUsersWithAccess(projectId);
|
2022-02-24 14:58:54 +01:00
|
|
|
const user = usersWithRoles.users.find((user) => user.id === userId);
|
2022-02-21 14:39:59 +01:00
|
|
|
const currentRole = usersWithRoles.roles.find(
|
|
|
|
(r) => r.id === user.roleId,
|
|
|
|
);
|
|
|
|
|
|
|
|
if (currentRole.id === roleId) {
|
|
|
|
// Nothing to do....
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
await this.validateAtLeastOneOwner(projectId, currentRole);
|
|
|
|
|
|
|
|
await this.accessService.updateUserProjectRole(
|
|
|
|
userId,
|
|
|
|
roleId,
|
|
|
|
projectId,
|
|
|
|
);
|
2022-01-14 12:14:02 +01:00
|
|
|
|
|
|
|
await this.eventStore.store(
|
2022-02-21 14:39:59 +01:00
|
|
|
new ProjectUserUpdateRoleEvent({
|
2022-01-14 12:14:02 +01:00
|
|
|
project: projectId,
|
|
|
|
createdBy,
|
2022-02-21 14:39:59 +01:00
|
|
|
preData: {
|
|
|
|
userId,
|
|
|
|
roleId: currentRole.id,
|
|
|
|
roleName: currentRole.name,
|
|
|
|
},
|
|
|
|
data: { userId, roleId, roleName: role.name },
|
2022-01-14 12:14:02 +01:00
|
|
|
}),
|
|
|
|
);
|
2021-03-11 22:51:58 +01:00
|
|
|
}
|
2021-07-07 10:46:50 +02:00
|
|
|
|
|
|
|
async getMembers(projectId: string): Promise<number> {
|
2021-08-19 13:25:36 +02:00
|
|
|
return this.store.getMembers(projectId);
|
2021-07-07 10:46:50 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
async getProjectOverview(
|
|
|
|
projectId: string,
|
|
|
|
archived: boolean = false,
|
|
|
|
): Promise<IProjectOverview> {
|
2021-08-19 13:25:36 +02:00
|
|
|
const project = await this.store.get(projectId);
|
2021-09-29 12:22:04 +02:00
|
|
|
const environments = await this.store.getEnvironmentsForProject(
|
|
|
|
projectId,
|
|
|
|
);
|
2021-09-13 10:23:57 +02:00
|
|
|
const features = await this.featureToggleService.getFeatureOverview(
|
2021-07-07 10:46:50 +02:00
|
|
|
projectId,
|
|
|
|
archived,
|
|
|
|
);
|
2021-08-19 13:25:36 +02:00
|
|
|
const members = await this.store.getMembers(projectId);
|
2021-07-07 10:46:50 +02:00
|
|
|
return {
|
|
|
|
name: project.name,
|
2021-09-29 12:22:04 +02:00
|
|
|
environments,
|
2021-07-07 10:46:50 +02:00
|
|
|
description: project.description,
|
|
|
|
health: project.health,
|
|
|
|
features,
|
|
|
|
members,
|
|
|
|
version: 1,
|
|
|
|
};
|
|
|
|
}
|
2021-03-11 22:51:58 +01:00
|
|
|
}
|