1
0
mirror of https://github.com/Unleash/unleash.git synced 2024-11-01 19:07:38 +01:00
unleash.unleash/src/lib/services/project-service.ts

896 lines
27 KiB
TypeScript
Raw Normal View History

import { subDays } from 'date-fns';
import User, { IUser } from '../types/user';
import { AccessService } from './access-service';
import NameExistsError from '../error/name-exists-error';
import InvalidOperationError from '../error/invalid-operation-error';
import { nameType } from '../routes/util';
2021-09-14 20:43:05 +02:00
import { projectSchema } from './project-schema';
import NotFoundError from '../error/notfound-error';
2021-04-29 10:21:29 +02:00
import {
DEFAULT_PROJECT,
2023-03-14 10:32:00 +01:00
FEATURE_ENVIRONMENT_ENABLED,
FeatureToggle,
IAccountStore,
IEnvironmentStore,
IEventStore,
IFeatureEnvironmentStore,
IFeatureToggleStore,
IFeatureTypeStore,
IProject,
IProjectOverview,
IProjectWithCount,
IUnleashConfig,
IUnleashStores,
IUserWithRole,
MOVE_FEATURE_TOGGLE,
2021-04-29 10:21:29 +02:00
PROJECT_CREATED,
PROJECT_DELETED,
PROJECT_UPDATED,
ProjectGroupAddedEvent,
ProjectGroupRemovedEvent,
ProjectGroupUpdateRoleEvent,
ProjectMode,
2023-03-14 10:32:00 +01:00
ProjectUserAddedEvent,
ProjectUserRemovedEvent,
ProjectUserUpdateRoleEvent,
RoleName,
IFlagResolver,
} from '../types';
import {
IProjectQuery,
IProjectSettings,
IProjectStore,
} from '../types/stores/project-store';
import {
IProjectAccessModel,
IRoleDescriptor,
} from '../types/stores/access-store';
import FeatureToggleService from './feature-toggle-service';
2021-08-25 13:38:00 +02:00
import NoAccessError from '../error/no-access-error';
import IncompatibleProjectError from '../error/incompatible-project-error';
feat: custom project roles (#1220) * wip: environment for permissions * fix: add migration for roles * fix: connect environment with access service * feat: add tests * chore: Implement scaffolding for new rbac * fix: add fake store * feat: Add api endpoints for roles and permissions list * feat: Add ability to provide permissions when creating a role and rename environmentName to name in the list permissions datastructure * fix: Make project roles resolve correctly against new environments permissions structure * fix: Patch migration to also populate permission names * fix: Make permissions actually work with new environments * fix: Add back to get permissions working for editor role * fix: Removed ability to set role type through api during creation - it's now always custom * feat: Return permissions on get role endpoint * feat: Add in support for updating roles * fix: Get a bunch of tests working and delete a few that make no sense anymore * chore: A few small cleanups - remove logging and restore default on dev server config * chore: Refactor role/access stores into more logical domains * feat: Add in validation for roles * feat: Patch db migration to handle old stucture * fix: migration for project roles * fix: patch a few broken tests * fix: add permissions to editor * fix: update test name * fix: update user permission mapping * fix: create new user * fix: update root role test * fix: update tests * feat: Validation now works when updating a role * fix: Add in very barebones down migration for rbac so that tests work * fix: Improve responses from role resolution - getting a non existant role will throw a NotFound error * fix: remove unused permissions * fix: add test for connecting roles and deleting project * fix: add test for adding a project member with a custom role * fix: add test for changing user role * fix: add guard for deleting role if the role is in use * fix: alter migration * chore: Minor code cleanups * chore: Small code cleanups * chore: More minor cleanups of code * chore: Trim some dead code to make the linter happy * feat: Schema validation for roles * fix: setup permission for variant * fix: remove unused import * feat: Add cascading delete for role_permissions when deleting a role * feat: add configuration option for disabling legacy api * chore: update frontend to beta version * 4.6.0-beta.0 * fix: export default project constant * fix: update snapshot * fix: module pattern ../../lib * fix: move DEFAULT_PROJECT to types * fix: remove debug logging * fix: remove debug log state * fix: Change permission descriptions * fix: roles should have unique name * fix: root roles should be connected to the default project * fix: typo in role-schema.ts * fix: Role permission empty string for non environment type * feat: new permission for moving project * fix: add event for changeProject * fix: Removing a user from a project will now check to see if that project has an owner, rather than checking if any project has an owner * fix: add tests for move project * fix: Add in missing create/delete tag permissions * fix: Removed duplicate impl caused by multiple good samaritans putting it back in! * fix: Trim out add tag permissions, for now at least * chore: Trim out new add and delete tag permissions - we're going with update feature instead * chore: update frontend * 4.6.0-beta.1 * feat: Prevent editing of built in roles * fix: Patch an issue where permissions for variants/environments didn't match the front end * fix: lint Co-authored-by: Ivar Conradi Østhus <ivarconr@gmail.com> Co-authored-by: Fredrik Oseberg <fredrik.no@gmail.com>
2022-01-13 11:14:17 +01:00
import { IFeatureTagStore } from 'lib/types/stores/feature-tag-store';
import ProjectWithoutOwnerError from '../error/project-without-owner-error';
import { arraysHaveSameItems } from '../util';
import { GroupService } from './group-service';
import { IGroupModelWithProjectRole, IGroupRole } from 'lib/types/group';
import { FavoritesService } from './favorites-service';
import { TimeToProduction } from '../read-models/time-to-production/time-to-production';
import { IProjectStatsStore } from 'lib/types/stores/project-stats-store-type';
import { uniqueByKey } from '../util/unique';
2023-03-14 10:32:00 +01:00
const getCreatedBy = (user: IUser) => user.email || user.username || 'unknown';
export interface AccessWithRoles {
users: IUserWithRole[];
feat: custom project roles (#1220) * wip: environment for permissions * fix: add migration for roles * fix: connect environment with access service * feat: add tests * chore: Implement scaffolding for new rbac * fix: add fake store * feat: Add api endpoints for roles and permissions list * feat: Add ability to provide permissions when creating a role and rename environmentName to name in the list permissions datastructure * fix: Make project roles resolve correctly against new environments permissions structure * fix: Patch migration to also populate permission names * fix: Make permissions actually work with new environments * fix: Add back to get permissions working for editor role * fix: Removed ability to set role type through api during creation - it's now always custom * feat: Return permissions on get role endpoint * feat: Add in support for updating roles * fix: Get a bunch of tests working and delete a few that make no sense anymore * chore: A few small cleanups - remove logging and restore default on dev server config * chore: Refactor role/access stores into more logical domains * feat: Add in validation for roles * feat: Patch db migration to handle old stucture * fix: migration for project roles * fix: patch a few broken tests * fix: add permissions to editor * fix: update test name * fix: update user permission mapping * fix: create new user * fix: update root role test * fix: update tests * feat: Validation now works when updating a role * fix: Add in very barebones down migration for rbac so that tests work * fix: Improve responses from role resolution - getting a non existant role will throw a NotFound error * fix: remove unused permissions * fix: add test for connecting roles and deleting project * fix: add test for adding a project member with a custom role * fix: add test for changing user role * fix: add guard for deleting role if the role is in use * fix: alter migration * chore: Minor code cleanups * chore: Small code cleanups * chore: More minor cleanups of code * chore: Trim some dead code to make the linter happy * feat: Schema validation for roles * fix: setup permission for variant * fix: remove unused import * feat: Add cascading delete for role_permissions when deleting a role * feat: add configuration option for disabling legacy api * chore: update frontend to beta version * 4.6.0-beta.0 * fix: export default project constant * fix: update snapshot * fix: module pattern ../../lib * fix: move DEFAULT_PROJECT to types * fix: remove debug logging * fix: remove debug log state * fix: Change permission descriptions * fix: roles should have unique name * fix: root roles should be connected to the default project * fix: typo in role-schema.ts * fix: Role permission empty string for non environment type * feat: new permission for moving project * fix: add event for changeProject * fix: Removing a user from a project will now check to see if that project has an owner, rather than checking if any project has an owner * fix: add tests for move project * fix: Add in missing create/delete tag permissions * fix: Removed duplicate impl caused by multiple good samaritans putting it back in! * fix: Trim out add tag permissions, for now at least * chore: Trim out new add and delete tag permissions - we're going with update feature instead * chore: update frontend * 4.6.0-beta.1 * feat: Prevent editing of built in roles * fix: Patch an issue where permissions for variants/environments didn't match the front end * fix: lint Co-authored-by: Ivar Conradi Østhus <ivarconr@gmail.com> Co-authored-by: Fredrik Oseberg <fredrik.no@gmail.com>
2022-01-13 11:14:17 +01:00
roles: IRoleDescriptor[];
groups: IGroupModelWithProjectRole[];
}
type Days = number;
type Count = number;
export interface IProjectStats {
avgTimeToProdCurrentWindow: Days;
createdCurrentWindow: Count;
createdPastWindow: Count;
archivedCurrentWindow: Count;
archivedPastWindow: Count;
projectActivityCurrentWindow: Count;
projectActivityPastWindow: Count;
projectMembersAddedCurrentWindow: Count;
}
interface ICalculateStatus {
projectId: string;
updates: IProjectStats;
}
export default class ProjectService {
private store: IProjectStore;
private accessService: AccessService;
private eventStore: IEventStore;
private featureToggleStore: IFeatureToggleStore;
private featureTypeStore: IFeatureTypeStore;
private featureEnvironmentStore: IFeatureEnvironmentStore;
private environmentStore: IEnvironmentStore;
private groupService: GroupService;
private logger: any;
private featureToggleService: FeatureToggleService;
feat: custom project roles (#1220) * wip: environment for permissions * fix: add migration for roles * fix: connect environment with access service * feat: add tests * chore: Implement scaffolding for new rbac * fix: add fake store * feat: Add api endpoints for roles and permissions list * feat: Add ability to provide permissions when creating a role and rename environmentName to name in the list permissions datastructure * fix: Make project roles resolve correctly against new environments permissions structure * fix: Patch migration to also populate permission names * fix: Make permissions actually work with new environments * fix: Add back to get permissions working for editor role * fix: Removed ability to set role type through api during creation - it's now always custom * feat: Return permissions on get role endpoint * feat: Add in support for updating roles * fix: Get a bunch of tests working and delete a few that make no sense anymore * chore: A few small cleanups - remove logging and restore default on dev server config * chore: Refactor role/access stores into more logical domains * feat: Add in validation for roles * feat: Patch db migration to handle old stucture * fix: migration for project roles * fix: patch a few broken tests * fix: add permissions to editor * fix: update test name * fix: update user permission mapping * fix: create new user * fix: update root role test * fix: update tests * feat: Validation now works when updating a role * fix: Add in very barebones down migration for rbac so that tests work * fix: Improve responses from role resolution - getting a non existant role will throw a NotFound error * fix: remove unused permissions * fix: add test for connecting roles and deleting project * fix: add test for adding a project member with a custom role * fix: add test for changing user role * fix: add guard for deleting role if the role is in use * fix: alter migration * chore: Minor code cleanups * chore: Small code cleanups * chore: More minor cleanups of code * chore: Trim some dead code to make the linter happy * feat: Schema validation for roles * fix: setup permission for variant * fix: remove unused import * feat: Add cascading delete for role_permissions when deleting a role * feat: add configuration option for disabling legacy api * chore: update frontend to beta version * 4.6.0-beta.0 * fix: export default project constant * fix: update snapshot * fix: module pattern ../../lib * fix: move DEFAULT_PROJECT to types * fix: remove debug logging * fix: remove debug log state * fix: Change permission descriptions * fix: roles should have unique name * fix: root roles should be connected to the default project * fix: typo in role-schema.ts * fix: Role permission empty string for non environment type * feat: new permission for moving project * fix: add event for changeProject * fix: Removing a user from a project will now check to see if that project has an owner, rather than checking if any project has an owner * fix: add tests for move project * fix: Add in missing create/delete tag permissions * fix: Removed duplicate impl caused by multiple good samaritans putting it back in! * fix: Trim out add tag permissions, for now at least * chore: Trim out new add and delete tag permissions - we're going with update feature instead * chore: update frontend * 4.6.0-beta.1 * feat: Prevent editing of built in roles * fix: Patch an issue where permissions for variants/environments didn't match the front end * fix: lint Co-authored-by: Ivar Conradi Østhus <ivarconr@gmail.com> Co-authored-by: Fredrik Oseberg <fredrik.no@gmail.com>
2022-01-13 11:14:17 +01:00
private tagStore: IFeatureTagStore;
private accountStore: IAccountStore;
private favoritesService: FavoritesService;
private projectStatsStore: IProjectStatsStore;
private flagResolver: IFlagResolver;
constructor(
{
projectStore,
eventStore,
featureToggleStore,
featureTypeStore,
environmentStore,
featureEnvironmentStore,
feat: custom project roles (#1220) * wip: environment for permissions * fix: add migration for roles * fix: connect environment with access service * feat: add tests * chore: Implement scaffolding for new rbac * fix: add fake store * feat: Add api endpoints for roles and permissions list * feat: Add ability to provide permissions when creating a role and rename environmentName to name in the list permissions datastructure * fix: Make project roles resolve correctly against new environments permissions structure * fix: Patch migration to also populate permission names * fix: Make permissions actually work with new environments * fix: Add back to get permissions working for editor role * fix: Removed ability to set role type through api during creation - it's now always custom * feat: Return permissions on get role endpoint * feat: Add in support for updating roles * fix: Get a bunch of tests working and delete a few that make no sense anymore * chore: A few small cleanups - remove logging and restore default on dev server config * chore: Refactor role/access stores into more logical domains * feat: Add in validation for roles * feat: Patch db migration to handle old stucture * fix: migration for project roles * fix: patch a few broken tests * fix: add permissions to editor * fix: update test name * fix: update user permission mapping * fix: create new user * fix: update root role test * fix: update tests * feat: Validation now works when updating a role * fix: Add in very barebones down migration for rbac so that tests work * fix: Improve responses from role resolution - getting a non existant role will throw a NotFound error * fix: remove unused permissions * fix: add test for connecting roles and deleting project * fix: add test for adding a project member with a custom role * fix: add test for changing user role * fix: add guard for deleting role if the role is in use * fix: alter migration * chore: Minor code cleanups * chore: Small code cleanups * chore: More minor cleanups of code * chore: Trim some dead code to make the linter happy * feat: Schema validation for roles * fix: setup permission for variant * fix: remove unused import * feat: Add cascading delete for role_permissions when deleting a role * feat: add configuration option for disabling legacy api * chore: update frontend to beta version * 4.6.0-beta.0 * fix: export default project constant * fix: update snapshot * fix: module pattern ../../lib * fix: move DEFAULT_PROJECT to types * fix: remove debug logging * fix: remove debug log state * fix: Change permission descriptions * fix: roles should have unique name * fix: root roles should be connected to the default project * fix: typo in role-schema.ts * fix: Role permission empty string for non environment type * feat: new permission for moving project * fix: add event for changeProject * fix: Removing a user from a project will now check to see if that project has an owner, rather than checking if any project has an owner * fix: add tests for move project * fix: Add in missing create/delete tag permissions * fix: Removed duplicate impl caused by multiple good samaritans putting it back in! * fix: Trim out add tag permissions, for now at least * chore: Trim out new add and delete tag permissions - we're going with update feature instead * chore: update frontend * 4.6.0-beta.1 * feat: Prevent editing of built in roles * fix: Patch an issue where permissions for variants/environments didn't match the front end * fix: lint Co-authored-by: Ivar Conradi Østhus <ivarconr@gmail.com> Co-authored-by: Fredrik Oseberg <fredrik.no@gmail.com>
2022-01-13 11:14:17 +01:00
featureTagStore,
accountStore,
projectStatsStore,
}: Pick<
IUnleashStores,
| 'projectStore'
| 'eventStore'
| 'featureToggleStore'
| 'featureTypeStore'
| 'environmentStore'
| 'featureEnvironmentStore'
feat: custom project roles (#1220) * wip: environment for permissions * fix: add migration for roles * fix: connect environment with access service * feat: add tests * chore: Implement scaffolding for new rbac * fix: add fake store * feat: Add api endpoints for roles and permissions list * feat: Add ability to provide permissions when creating a role and rename environmentName to name in the list permissions datastructure * fix: Make project roles resolve correctly against new environments permissions structure * fix: Patch migration to also populate permission names * fix: Make permissions actually work with new environments * fix: Add back to get permissions working for editor role * fix: Removed ability to set role type through api during creation - it's now always custom * feat: Return permissions on get role endpoint * feat: Add in support for updating roles * fix: Get a bunch of tests working and delete a few that make no sense anymore * chore: A few small cleanups - remove logging and restore default on dev server config * chore: Refactor role/access stores into more logical domains * feat: Add in validation for roles * feat: Patch db migration to handle old stucture * fix: migration for project roles * fix: patch a few broken tests * fix: add permissions to editor * fix: update test name * fix: update user permission mapping * fix: create new user * fix: update root role test * fix: update tests * feat: Validation now works when updating a role * fix: Add in very barebones down migration for rbac so that tests work * fix: Improve responses from role resolution - getting a non existant role will throw a NotFound error * fix: remove unused permissions * fix: add test for connecting roles and deleting project * fix: add test for adding a project member with a custom role * fix: add test for changing user role * fix: add guard for deleting role if the role is in use * fix: alter migration * chore: Minor code cleanups * chore: Small code cleanups * chore: More minor cleanups of code * chore: Trim some dead code to make the linter happy * feat: Schema validation for roles * fix: setup permission for variant * fix: remove unused import * feat: Add cascading delete for role_permissions when deleting a role * feat: add configuration option for disabling legacy api * chore: update frontend to beta version * 4.6.0-beta.0 * fix: export default project constant * fix: update snapshot * fix: module pattern ../../lib * fix: move DEFAULT_PROJECT to types * fix: remove debug logging * fix: remove debug log state * fix: Change permission descriptions * fix: roles should have unique name * fix: root roles should be connected to the default project * fix: typo in role-schema.ts * fix: Role permission empty string for non environment type * feat: new permission for moving project * fix: add event for changeProject * fix: Removing a user from a project will now check to see if that project has an owner, rather than checking if any project has an owner * fix: add tests for move project * fix: Add in missing create/delete tag permissions * fix: Removed duplicate impl caused by multiple good samaritans putting it back in! * fix: Trim out add tag permissions, for now at least * chore: Trim out new add and delete tag permissions - we're going with update feature instead * chore: update frontend * 4.6.0-beta.1 * feat: Prevent editing of built in roles * fix: Patch an issue where permissions for variants/environments didn't match the front end * fix: lint Co-authored-by: Ivar Conradi Østhus <ivarconr@gmail.com> Co-authored-by: Fredrik Oseberg <fredrik.no@gmail.com>
2022-01-13 11:14:17 +01:00
| 'featureTagStore'
| 'accountStore'
| 'projectStatsStore'
>,
config: IUnleashConfig,
accessService: AccessService,
featureToggleService: FeatureToggleService,
groupService: GroupService,
favoriteService: FavoritesService,
) {
this.store = projectStore;
this.environmentStore = environmentStore;
this.featureEnvironmentStore = featureEnvironmentStore;
this.accessService = accessService;
this.eventStore = eventStore;
this.featureToggleStore = featureToggleStore;
this.featureTypeStore = featureTypeStore;
this.featureToggleService = featureToggleService;
this.favoritesService = favoriteService;
feat: custom project roles (#1220) * wip: environment for permissions * fix: add migration for roles * fix: connect environment with access service * feat: add tests * chore: Implement scaffolding for new rbac * fix: add fake store * feat: Add api endpoints for roles and permissions list * feat: Add ability to provide permissions when creating a role and rename environmentName to name in the list permissions datastructure * fix: Make project roles resolve correctly against new environments permissions structure * fix: Patch migration to also populate permission names * fix: Make permissions actually work with new environments * fix: Add back to get permissions working for editor role * fix: Removed ability to set role type through api during creation - it's now always custom * feat: Return permissions on get role endpoint * feat: Add in support for updating roles * fix: Get a bunch of tests working and delete a few that make no sense anymore * chore: A few small cleanups - remove logging and restore default on dev server config * chore: Refactor role/access stores into more logical domains * feat: Add in validation for roles * feat: Patch db migration to handle old stucture * fix: migration for project roles * fix: patch a few broken tests * fix: add permissions to editor * fix: update test name * fix: update user permission mapping * fix: create new user * fix: update root role test * fix: update tests * feat: Validation now works when updating a role * fix: Add in very barebones down migration for rbac so that tests work * fix: Improve responses from role resolution - getting a non existant role will throw a NotFound error * fix: remove unused permissions * fix: add test for connecting roles and deleting project * fix: add test for adding a project member with a custom role * fix: add test for changing user role * fix: add guard for deleting role if the role is in use * fix: alter migration * chore: Minor code cleanups * chore: Small code cleanups * chore: More minor cleanups of code * chore: Trim some dead code to make the linter happy * feat: Schema validation for roles * fix: setup permission for variant * fix: remove unused import * feat: Add cascading delete for role_permissions when deleting a role * feat: add configuration option for disabling legacy api * chore: update frontend to beta version * 4.6.0-beta.0 * fix: export default project constant * fix: update snapshot * fix: module pattern ../../lib * fix: move DEFAULT_PROJECT to types * fix: remove debug logging * fix: remove debug log state * fix: Change permission descriptions * fix: roles should have unique name * fix: root roles should be connected to the default project * fix: typo in role-schema.ts * fix: Role permission empty string for non environment type * feat: new permission for moving project * fix: add event for changeProject * fix: Removing a user from a project will now check to see if that project has an owner, rather than checking if any project has an owner * fix: add tests for move project * fix: Add in missing create/delete tag permissions * fix: Removed duplicate impl caused by multiple good samaritans putting it back in! * fix: Trim out add tag permissions, for now at least * chore: Trim out new add and delete tag permissions - we're going with update feature instead * chore: update frontend * 4.6.0-beta.1 * feat: Prevent editing of built in roles * fix: Patch an issue where permissions for variants/environments didn't match the front end * fix: lint Co-authored-by: Ivar Conradi Østhus <ivarconr@gmail.com> Co-authored-by: Fredrik Oseberg <fredrik.no@gmail.com>
2022-01-13 11:14:17 +01:00
this.tagStore = featureTagStore;
this.accountStore = accountStore;
this.groupService = groupService;
this.projectStatsStore = projectStatsStore;
this.logger = config.getLogger('services/project-service.js');
this.flagResolver = config.flagResolver;
}
async getProjects(
query?: IProjectQuery,
userId?: number,
): Promise<IProjectWithCount[]> {
return this.store.getProjectsWithCounts(query, userId);
}
async getProject(id: string): Promise<IProject> {
return this.store.get(id);
}
async createProject(
newProject: Pick<
IProject,
'id' | 'name' | 'mode' | 'defaultStickiness'
>,
user: IUser,
): Promise<IProject> {
2021-09-14 20:36:40 +02:00
const data = await projectSchema.validateAsync(newProject);
await this.validateUniqueId(data.id);
await this.store.create(data);
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,
);
}),
);
await this.accessService.createDefaultProjectRoles(user, data.id);
await this.eventStore.store({
2021-04-29 10:21:29 +02:00
type: PROJECT_CREATED,
createdBy: getCreatedBy(user),
data,
project: newProject.id,
});
return data;
}
async updateProject(updatedProject: IProject, user: User): Promise<void> {
const preData = await this.store.get(updatedProject.id);
2021-09-14 20:36:40 +02:00
const project = await projectSchema.validateAsync(updatedProject);
await this.store.update(project);
await this.eventStore.store({
2021-04-29 10:21:29 +02:00
type: PROJECT_UPDATED,
project: project.id,
createdBy: getCreatedBy(user),
data: project,
preData,
});
}
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 arraysHaveSameItems(
featureEnvs.map((env) => env.environment),
newEnvs,
);
}
async addEnvironmentToProject(
project: string,
environment: string,
): Promise<void> {
await this.store.addEnvironmentToProject(project, 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) {
feat: custom project roles (#1220) * wip: environment for permissions * fix: add migration for roles * fix: connect environment with access service * feat: add tests * chore: Implement scaffolding for new rbac * fix: add fake store * feat: Add api endpoints for roles and permissions list * feat: Add ability to provide permissions when creating a role and rename environmentName to name in the list permissions datastructure * fix: Make project roles resolve correctly against new environments permissions structure * fix: Patch migration to also populate permission names * fix: Make permissions actually work with new environments * fix: Add back to get permissions working for editor role * fix: Removed ability to set role type through api during creation - it's now always custom * feat: Return permissions on get role endpoint * feat: Add in support for updating roles * fix: Get a bunch of tests working and delete a few that make no sense anymore * chore: A few small cleanups - remove logging and restore default on dev server config * chore: Refactor role/access stores into more logical domains * feat: Add in validation for roles * feat: Patch db migration to handle old stucture * fix: migration for project roles * fix: patch a few broken tests * fix: add permissions to editor * fix: update test name * fix: update user permission mapping * fix: create new user * fix: update root role test * fix: update tests * feat: Validation now works when updating a role * fix: Add in very barebones down migration for rbac so that tests work * fix: Improve responses from role resolution - getting a non existant role will throw a NotFound error * fix: remove unused permissions * fix: add test for connecting roles and deleting project * fix: add test for adding a project member with a custom role * fix: add test for changing user role * fix: add guard for deleting role if the role is in use * fix: alter migration * chore: Minor code cleanups * chore: Small code cleanups * chore: More minor cleanups of code * chore: Trim some dead code to make the linter happy * feat: Schema validation for roles * fix: setup permission for variant * fix: remove unused import * feat: Add cascading delete for role_permissions when deleting a role * feat: add configuration option for disabling legacy api * chore: update frontend to beta version * 4.6.0-beta.0 * fix: export default project constant * fix: update snapshot * fix: module pattern ../../lib * fix: move DEFAULT_PROJECT to types * fix: remove debug logging * fix: remove debug log state * fix: Change permission descriptions * fix: roles should have unique name * fix: root roles should be connected to the default project * fix: typo in role-schema.ts * fix: Role permission empty string for non environment type * feat: new permission for moving project * fix: add event for changeProject * fix: Removing a user from a project will now check to see if that project has an owner, rather than checking if any project has an owner * fix: add tests for move project * fix: Add in missing create/delete tag permissions * fix: Removed duplicate impl caused by multiple good samaritans putting it back in! * fix: Trim out add tag permissions, for now at least * chore: Trim out new add and delete tag permissions - we're going with update feature instead * chore: update frontend * 4.6.0-beta.1 * feat: Prevent editing of built in roles * fix: Patch an issue where permissions for variants/environments didn't match the front end * fix: lint Co-authored-by: Ivar Conradi Østhus <ivarconr@gmail.com> Co-authored-by: Fredrik Oseberg <fredrik.no@gmail.com>
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,
feat: custom project roles (#1220) * wip: environment for permissions * fix: add migration for roles * fix: connect environment with access service * feat: add tests * chore: Implement scaffolding for new rbac * fix: add fake store * feat: Add api endpoints for roles and permissions list * feat: Add ability to provide permissions when creating a role and rename environmentName to name in the list permissions datastructure * fix: Make project roles resolve correctly against new environments permissions structure * fix: Patch migration to also populate permission names * fix: Make permissions actually work with new environments * fix: Add back to get permissions working for editor role * fix: Removed ability to set role type through api during creation - it's now always custom * feat: Return permissions on get role endpoint * feat: Add in support for updating roles * fix: Get a bunch of tests working and delete a few that make no sense anymore * chore: A few small cleanups - remove logging and restore default on dev server config * chore: Refactor role/access stores into more logical domains * feat: Add in validation for roles * feat: Patch db migration to handle old stucture * fix: migration for project roles * fix: patch a few broken tests * fix: add permissions to editor * fix: update test name * fix: update user permission mapping * fix: create new user * fix: update root role test * fix: update tests * feat: Validation now works when updating a role * fix: Add in very barebones down migration for rbac so that tests work * fix: Improve responses from role resolution - getting a non existant role will throw a NotFound error * fix: remove unused permissions * fix: add test for connecting roles and deleting project * fix: add test for adding a project member with a custom role * fix: add test for changing user role * fix: add guard for deleting role if the role is in use * fix: alter migration * chore: Minor code cleanups * chore: Small code cleanups * chore: More minor cleanups of code * chore: Trim some dead code to make the linter happy * feat: Schema validation for roles * fix: setup permission for variant * fix: remove unused import * feat: Add cascading delete for role_permissions when deleting a role * feat: add configuration option for disabling legacy api * chore: update frontend to beta version * 4.6.0-beta.0 * fix: export default project constant * fix: update snapshot * fix: module pattern ../../lib * fix: move DEFAULT_PROJECT to types * fix: remove debug logging * fix: remove debug log state * fix: Change permission descriptions * fix: roles should have unique name * fix: root roles should be connected to the default project * fix: typo in role-schema.ts * fix: Role permission empty string for non environment type * feat: new permission for moving project * fix: add event for changeProject * fix: Removing a user from a project will now check to see if that project has an owner, rather than checking if any project has an owner * fix: add tests for move project * fix: Add in missing create/delete tag permissions * fix: Removed duplicate impl caused by multiple good samaritans putting it back in! * fix: Trim out add tag permissions, for now at least * chore: Trim out new add and delete tag permissions - we're going with update feature instead * chore: update frontend * 4.6.0-beta.1 * feat: Prevent editing of built in roles * fix: Patch an issue where permissions for variants/environments didn't match the front end * fix: lint Co-authored-by: Ivar Conradi Østhus <ivarconr@gmail.com> Co-authored-by: Fredrik Oseberg <fredrik.no@gmail.com>
2022-01-13 11:14:17 +01:00
MOVE_FEATURE_TOGGLE,
2021-08-25 13:38:00 +02:00
newProjectId,
);
if (!authorized) {
feat: custom project roles (#1220) * wip: environment for permissions * fix: add migration for roles * fix: connect environment with access service * feat: add tests * chore: Implement scaffolding for new rbac * fix: add fake store * feat: Add api endpoints for roles and permissions list * feat: Add ability to provide permissions when creating a role and rename environmentName to name in the list permissions datastructure * fix: Make project roles resolve correctly against new environments permissions structure * fix: Patch migration to also populate permission names * fix: Make permissions actually work with new environments * fix: Add back to get permissions working for editor role * fix: Removed ability to set role type through api during creation - it's now always custom * feat: Return permissions on get role endpoint * feat: Add in support for updating roles * fix: Get a bunch of tests working and delete a few that make no sense anymore * chore: A few small cleanups - remove logging and restore default on dev server config * chore: Refactor role/access stores into more logical domains * feat: Add in validation for roles * feat: Patch db migration to handle old stucture * fix: migration for project roles * fix: patch a few broken tests * fix: add permissions to editor * fix: update test name * fix: update user permission mapping * fix: create new user * fix: update root role test * fix: update tests * feat: Validation now works when updating a role * fix: Add in very barebones down migration for rbac so that tests work * fix: Improve responses from role resolution - getting a non existant role will throw a NotFound error * fix: remove unused permissions * fix: add test for connecting roles and deleting project * fix: add test for adding a project member with a custom role * fix: add test for changing user role * fix: add guard for deleting role if the role is in use * fix: alter migration * chore: Minor code cleanups * chore: Small code cleanups * chore: More minor cleanups of code * chore: Trim some dead code to make the linter happy * feat: Schema validation for roles * fix: setup permission for variant * fix: remove unused import * feat: Add cascading delete for role_permissions when deleting a role * feat: add configuration option for disabling legacy api * chore: update frontend to beta version * 4.6.0-beta.0 * fix: export default project constant * fix: update snapshot * fix: module pattern ../../lib * fix: move DEFAULT_PROJECT to types * fix: remove debug logging * fix: remove debug log state * fix: Change permission descriptions * fix: roles should have unique name * fix: root roles should be connected to the default project * fix: typo in role-schema.ts * fix: Role permission empty string for non environment type * feat: new permission for moving project * fix: add event for changeProject * fix: Removing a user from a project will now check to see if that project has an owner, rather than checking if any project has an owner * fix: add tests for move project * fix: Add in missing create/delete tag permissions * fix: Removed duplicate impl caused by multiple good samaritans putting it back in! * fix: Trim out add tag permissions, for now at least * chore: Trim out new add and delete tag permissions - we're going with update feature instead * chore: update frontend * 4.6.0-beta.1 * feat: Prevent editing of built in roles * fix: Patch an issue where permissions for variants/environments didn't match the front end * fix: lint Co-authored-by: Ivar Conradi Østhus <ivarconr@gmail.com> Co-authored-by: Fredrik Oseberg <fredrik.no@gmail.com>
2022-01-13 11:14:17 +01:00
throw new NoAccessError(MOVE_FEATURE_TOGGLE);
2021-08-25 13:38:00 +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,
getCreatedBy(user),
2021-08-25 13:38:00 +02:00
);
await this.featureToggleService.updateFeatureStrategyProject(
featureName,
newProjectId,
);
2021-08-25 13:38:00 +02:00
return updatedFeature;
}
async deleteProject(id: string, user: User): Promise<void> {
if (id === DEFAULT_PROJECT) {
throw new InvalidOperationError(
'You can not delete the default project!',
);
}
const toggles = await this.featureToggleStore.getAll({
project: id,
archived: false,
});
if (toggles.length > 0) {
throw new InvalidOperationError(
'You can not delete a project with active feature toggles',
);
}
await this.store.delete(id);
await this.eventStore.store({
2021-04-29 10:21:29 +02:00
type: PROJECT_DELETED,
createdBy: getCreatedBy(user),
project: id,
});
await this.accessService.removeDefaultProjectRoles(user, id);
}
async validateId(id: string): Promise<boolean> {
await nameType.validateAsync(id);
await this.validateUniqueId(id);
return true;
}
async validateUniqueId(id: string): Promise<void> {
const exists = await this.store.hasProject(id);
if (exists) {
throw new NameExistsError('A project with this id already exists.');
}
}
// RBAC methods
async getAccessToProject(projectId: string): Promise<AccessWithRoles> {
const [roles, users, groups] =
await this.accessService.getProjectRoleAccess(projectId);
return {
roles,
users,
groups,
};
}
async addUser(
projectId: string,
roleId: number,
userId: number,
createdBy: string,
): Promise<void> {
const [roles, users] = await this.accessService.getProjectRoleAccess(
projectId,
);
const user = await this.accountStore.get(userId);
const role = roles.find((r) => r.id === roleId);
if (!role) {
throw new NotFoundError(
`Could not find roleId=${roleId} on project=${projectId}`,
);
}
const alreadyHasAccess = users.some((u) => u.id === userId);
if (alreadyHasAccess) {
feat: custom project roles (#1220) * wip: environment for permissions * fix: add migration for roles * fix: connect environment with access service * feat: add tests * chore: Implement scaffolding for new rbac * fix: add fake store * feat: Add api endpoints for roles and permissions list * feat: Add ability to provide permissions when creating a role and rename environmentName to name in the list permissions datastructure * fix: Make project roles resolve correctly against new environments permissions structure * fix: Patch migration to also populate permission names * fix: Make permissions actually work with new environments * fix: Add back to get permissions working for editor role * fix: Removed ability to set role type through api during creation - it's now always custom * feat: Return permissions on get role endpoint * feat: Add in support for updating roles * fix: Get a bunch of tests working and delete a few that make no sense anymore * chore: A few small cleanups - remove logging and restore default on dev server config * chore: Refactor role/access stores into more logical domains * feat: Add in validation for roles * feat: Patch db migration to handle old stucture * fix: migration for project roles * fix: patch a few broken tests * fix: add permissions to editor * fix: update test name * fix: update user permission mapping * fix: create new user * fix: update root role test * fix: update tests * feat: Validation now works when updating a role * fix: Add in very barebones down migration for rbac so that tests work * fix: Improve responses from role resolution - getting a non existant role will throw a NotFound error * fix: remove unused permissions * fix: add test for connecting roles and deleting project * fix: add test for adding a project member with a custom role * fix: add test for changing user role * fix: add guard for deleting role if the role is in use * fix: alter migration * chore: Minor code cleanups * chore: Small code cleanups * chore: More minor cleanups of code * chore: Trim some dead code to make the linter happy * feat: Schema validation for roles * fix: setup permission for variant * fix: remove unused import * feat: Add cascading delete for role_permissions when deleting a role * feat: add configuration option for disabling legacy api * chore: update frontend to beta version * 4.6.0-beta.0 * fix: export default project constant * fix: update snapshot * fix: module pattern ../../lib * fix: move DEFAULT_PROJECT to types * fix: remove debug logging * fix: remove debug log state * fix: Change permission descriptions * fix: roles should have unique name * fix: root roles should be connected to the default project * fix: typo in role-schema.ts * fix: Role permission empty string for non environment type * feat: new permission for moving project * fix: add event for changeProject * fix: Removing a user from a project will now check to see if that project has an owner, rather than checking if any project has an owner * fix: add tests for move project * fix: Add in missing create/delete tag permissions * fix: Removed duplicate impl caused by multiple good samaritans putting it back in! * fix: Trim out add tag permissions, for now at least * chore: Trim out new add and delete tag permissions - we're going with update feature instead * chore: update frontend * 4.6.0-beta.1 * feat: Prevent editing of built in roles * fix: Patch an issue where permissions for variants/environments didn't match the front end * fix: lint Co-authored-by: Ivar Conradi Østhus <ivarconr@gmail.com> Co-authored-by: Fredrik Oseberg <fredrik.no@gmail.com>
2022-01-13 11:14:17 +01:00
throw new Error(`User already has access to project=${projectId}`);
}
feat: custom project roles (#1220) * wip: environment for permissions * fix: add migration for roles * fix: connect environment with access service * feat: add tests * chore: Implement scaffolding for new rbac * fix: add fake store * feat: Add api endpoints for roles and permissions list * feat: Add ability to provide permissions when creating a role and rename environmentName to name in the list permissions datastructure * fix: Make project roles resolve correctly against new environments permissions structure * fix: Patch migration to also populate permission names * fix: Make permissions actually work with new environments * fix: Add back to get permissions working for editor role * fix: Removed ability to set role type through api during creation - it's now always custom * feat: Return permissions on get role endpoint * feat: Add in support for updating roles * fix: Get a bunch of tests working and delete a few that make no sense anymore * chore: A few small cleanups - remove logging and restore default on dev server config * chore: Refactor role/access stores into more logical domains * feat: Add in validation for roles * feat: Patch db migration to handle old stucture * fix: migration for project roles * fix: patch a few broken tests * fix: add permissions to editor * fix: update test name * fix: update user permission mapping * fix: create new user * fix: update root role test * fix: update tests * feat: Validation now works when updating a role * fix: Add in very barebones down migration for rbac so that tests work * fix: Improve responses from role resolution - getting a non existant role will throw a NotFound error * fix: remove unused permissions * fix: add test for connecting roles and deleting project * fix: add test for adding a project member with a custom role * fix: add test for changing user role * fix: add guard for deleting role if the role is in use * fix: alter migration * chore: Minor code cleanups * chore: Small code cleanups * chore: More minor cleanups of code * chore: Trim some dead code to make the linter happy * feat: Schema validation for roles * fix: setup permission for variant * fix: remove unused import * feat: Add cascading delete for role_permissions when deleting a role * feat: add configuration option for disabling legacy api * chore: update frontend to beta version * 4.6.0-beta.0 * fix: export default project constant * fix: update snapshot * fix: module pattern ../../lib * fix: move DEFAULT_PROJECT to types * fix: remove debug logging * fix: remove debug log state * fix: Change permission descriptions * fix: roles should have unique name * fix: root roles should be connected to the default project * fix: typo in role-schema.ts * fix: Role permission empty string for non environment type * feat: new permission for moving project * fix: add event for changeProject * fix: Removing a user from a project will now check to see if that project has an owner, rather than checking if any project has an owner * fix: add tests for move project * fix: Add in missing create/delete tag permissions * fix: Removed duplicate impl caused by multiple good samaritans putting it back in! * fix: Trim out add tag permissions, for now at least * chore: Trim out new add and delete tag permissions - we're going with update feature instead * chore: update frontend * 4.6.0-beta.1 * feat: Prevent editing of built in roles * fix: Patch an issue where permissions for variants/environments didn't match the front end * fix: lint Co-authored-by: Ivar Conradi Østhus <ivarconr@gmail.com> Co-authored-by: Fredrik Oseberg <fredrik.no@gmail.com>
2022-01-13 11:14:17 +01:00
await this.accessService.addUserToRole(userId, role.id, projectId);
await this.eventStore.store(
new ProjectUserAddedEvent({
project: projectId,
createdBy: createdBy || 'system-user',
data: {
roleId,
userId,
roleName: role.name,
email: user.email,
},
}),
);
}
async removeUser(
projectId: string,
roleId: number,
userId: number,
createdBy: string,
): Promise<void> {
const role = await this.findProjectRole(projectId, roleId);
await this.validateAtLeastOneOwner(projectId, role);
await this.accessService.removeUserFromRole(userId, role.id, projectId);
const user = await this.accountStore.get(userId);
await this.eventStore.store(
new ProjectUserRemovedEvent({
project: projectId,
createdBy,
preData: {
roleId,
userId,
roleName: role.name,
email: user.email,
},
}),
);
}
async addGroup(
projectId: string,
roleId: number,
groupId: number,
modifiedBy: string,
): Promise<void> {
const role = await this.accessService.getRole(roleId);
const group = await this.groupService.getGroup(groupId);
const project = await this.getProject(projectId);
2023-03-14 10:32:00 +01:00
if (group.id == null) throw new TypeError('Unexpected empty group id');
await this.accessService.addGroupToRole(
group.id,
role.id,
modifiedBy,
project.id,
);
await this.eventStore.store(
new ProjectGroupAddedEvent({
project: project.id,
createdBy: modifiedBy,
data: {
groupId: group.id,
projectId: project.id,
roleName: role.name,
},
}),
);
}
async removeGroup(
projectId: string,
roleId: number,
groupId: number,
modifiedBy: string,
): Promise<void> {
const group = await this.groupService.getGroup(groupId);
const role = await this.accessService.getRole(roleId);
const project = await this.getProject(projectId);
2023-03-14 10:32:00 +01:00
if (group.id == null) throw new TypeError('Unexpected empty group id');
await this.accessService.removeGroupFromRole(
group.id,
role.id,
project.id,
);
await this.eventStore.store(
new ProjectGroupRemovedEvent({
project: projectId,
createdBy: modifiedBy,
preData: {
groupId: group.id,
projectId: project.id,
roleName: role.name,
},
}),
);
}
async addAccess(
projectId: string,
roleId: number,
usersAndGroups: IProjectAccessModel,
createdBy: string,
): Promise<void> {
return this.accessService.addAccessToProject(
usersAndGroups.users,
usersAndGroups.groups,
projectId,
roleId,
createdBy,
);
}
async findProjectGroupRole(
projectId: string,
roleId: number,
): Promise<IGroupRole> {
const roles = await this.groupService.getRolesForProject(projectId);
const role = roles.find((r) => r.roleId === roleId);
if (!role) {
throw new NotFoundError(
`Couldn't find roleId=${roleId} on project=${projectId}`,
);
}
return role;
}
async findProjectRole(
projectId: string,
roleId: number,
): Promise<IRoleDescriptor> {
const roles = await this.accessService.getRolesForProject(projectId);
const role = roles.find((r) => r.id === roleId);
if (!role) {
throw new NotFoundError(
`Couldn't find roleId=${roleId} on project=${projectId}`,
);
}
return role;
}
async validateAtLeastOneOwner(
projectId: string,
currentRole: IRoleDescriptor,
): Promise<void> {
if (currentRole.name === RoleName.OWNER) {
feat: custom project roles (#1220) * wip: environment for permissions * fix: add migration for roles * fix: connect environment with access service * feat: add tests * chore: Implement scaffolding for new rbac * fix: add fake store * feat: Add api endpoints for roles and permissions list * feat: Add ability to provide permissions when creating a role and rename environmentName to name in the list permissions datastructure * fix: Make project roles resolve correctly against new environments permissions structure * fix: Patch migration to also populate permission names * fix: Make permissions actually work with new environments * fix: Add back to get permissions working for editor role * fix: Removed ability to set role type through api during creation - it's now always custom * feat: Return permissions on get role endpoint * feat: Add in support for updating roles * fix: Get a bunch of tests working and delete a few that make no sense anymore * chore: A few small cleanups - remove logging and restore default on dev server config * chore: Refactor role/access stores into more logical domains * feat: Add in validation for roles * feat: Patch db migration to handle old stucture * fix: migration for project roles * fix: patch a few broken tests * fix: add permissions to editor * fix: update test name * fix: update user permission mapping * fix: create new user * fix: update root role test * fix: update tests * feat: Validation now works when updating a role * fix: Add in very barebones down migration for rbac so that tests work * fix: Improve responses from role resolution - getting a non existant role will throw a NotFound error * fix: remove unused permissions * fix: add test for connecting roles and deleting project * fix: add test for adding a project member with a custom role * fix: add test for changing user role * fix: add guard for deleting role if the role is in use * fix: alter migration * chore: Minor code cleanups * chore: Small code cleanups * chore: More minor cleanups of code * chore: Trim some dead code to make the linter happy * feat: Schema validation for roles * fix: setup permission for variant * fix: remove unused import * feat: Add cascading delete for role_permissions when deleting a role * feat: add configuration option for disabling legacy api * chore: update frontend to beta version * 4.6.0-beta.0 * fix: export default project constant * fix: update snapshot * fix: module pattern ../../lib * fix: move DEFAULT_PROJECT to types * fix: remove debug logging * fix: remove debug log state * fix: Change permission descriptions * fix: roles should have unique name * fix: root roles should be connected to the default project * fix: typo in role-schema.ts * fix: Role permission empty string for non environment type * feat: new permission for moving project * fix: add event for changeProject * fix: Removing a user from a project will now check to see if that project has an owner, rather than checking if any project has an owner * fix: add tests for move project * fix: Add in missing create/delete tag permissions * fix: Removed duplicate impl caused by multiple good samaritans putting it back in! * fix: Trim out add tag permissions, for now at least * chore: Trim out new add and delete tag permissions - we're going with update feature instead * chore: update frontend * 4.6.0-beta.1 * feat: Prevent editing of built in roles * fix: Patch an issue where permissions for variants/environments didn't match the front end * fix: lint Co-authored-by: Ivar Conradi Østhus <ivarconr@gmail.com> Co-authored-by: Fredrik Oseberg <fredrik.no@gmail.com>
2022-01-13 11:14:17 +01:00
const users = await this.accessService.getProjectUsersForRole(
currentRole.id,
feat: custom project roles (#1220) * wip: environment for permissions * fix: add migration for roles * fix: connect environment with access service * feat: add tests * chore: Implement scaffolding for new rbac * fix: add fake store * feat: Add api endpoints for roles and permissions list * feat: Add ability to provide permissions when creating a role and rename environmentName to name in the list permissions datastructure * fix: Make project roles resolve correctly against new environments permissions structure * fix: Patch migration to also populate permission names * fix: Make permissions actually work with new environments * fix: Add back to get permissions working for editor role * fix: Removed ability to set role type through api during creation - it's now always custom * feat: Return permissions on get role endpoint * feat: Add in support for updating roles * fix: Get a bunch of tests working and delete a few that make no sense anymore * chore: A few small cleanups - remove logging and restore default on dev server config * chore: Refactor role/access stores into more logical domains * feat: Add in validation for roles * feat: Patch db migration to handle old stucture * fix: migration for project roles * fix: patch a few broken tests * fix: add permissions to editor * fix: update test name * fix: update user permission mapping * fix: create new user * fix: update root role test * fix: update tests * feat: Validation now works when updating a role * fix: Add in very barebones down migration for rbac so that tests work * fix: Improve responses from role resolution - getting a non existant role will throw a NotFound error * fix: remove unused permissions * fix: add test for connecting roles and deleting project * fix: add test for adding a project member with a custom role * fix: add test for changing user role * fix: add guard for deleting role if the role is in use * fix: alter migration * chore: Minor code cleanups * chore: Small code cleanups * chore: More minor cleanups of code * chore: Trim some dead code to make the linter happy * feat: Schema validation for roles * fix: setup permission for variant * fix: remove unused import * feat: Add cascading delete for role_permissions when deleting a role * feat: add configuration option for disabling legacy api * chore: update frontend to beta version * 4.6.0-beta.0 * fix: export default project constant * fix: update snapshot * fix: module pattern ../../lib * fix: move DEFAULT_PROJECT to types * fix: remove debug logging * fix: remove debug log state * fix: Change permission descriptions * fix: roles should have unique name * fix: root roles should be connected to the default project * fix: typo in role-schema.ts * fix: Role permission empty string for non environment type * feat: new permission for moving project * fix: add event for changeProject * fix: Removing a user from a project will now check to see if that project has an owner, rather than checking if any project has an owner * fix: add tests for move project * fix: Add in missing create/delete tag permissions * fix: Removed duplicate impl caused by multiple good samaritans putting it back in! * fix: Trim out add tag permissions, for now at least * chore: Trim out new add and delete tag permissions - we're going with update feature instead * chore: update frontend * 4.6.0-beta.1 * feat: Prevent editing of built in roles * fix: Patch an issue where permissions for variants/environments didn't match the front end * fix: lint Co-authored-by: Ivar Conradi Østhus <ivarconr@gmail.com> Co-authored-by: Fredrik Oseberg <fredrik.no@gmail.com>
2022-01-13 11:14:17 +01:00
projectId,
);
const groups = await this.groupService.getProjectGroups(projectId);
const roleGroups = groups.filter((g) => g.roleId == currentRole.id);
if (users.length + roleGroups.length < 2) {
throw new ProjectWithoutOwnerError();
}
}
}
async changeRole(
projectId: string,
roleId: number,
userId: number,
createdBy: string,
): Promise<void> {
const usersWithRoles = await this.getAccessToProject(projectId);
2022-03-02 23:48:43 +01:00
const user = usersWithRoles.users.find((u) => u.id === userId);
2023-03-14 10:32:00 +01:00
if (!user) throw new TypeError('Unexpected empty user');
const currentRole = usersWithRoles.roles.find(
2022-03-02 23:48:43 +01:00
(r) => r.id === user.roleId,
);
2023-03-14 10:32:00 +01:00
if (!currentRole) throw new TypeError('Unexpected empty current role');
if (currentRole.id === roleId) {
// Nothing to do....
return;
}
await this.validateAtLeastOneOwner(projectId, currentRole);
await this.accessService.updateUserProjectRole(
userId,
roleId,
projectId,
);
const role = await this.findProjectRole(projectId, roleId);
await this.eventStore.store(
new ProjectUserUpdateRoleEvent({
project: projectId,
createdBy,
preData: {
userId,
roleId: currentRole.id,
roleName: currentRole.name,
email: user.email,
},
data: {
userId,
roleId,
roleName: role.name,
email: user.email,
},
}),
);
}
async changeGroupRole(
projectId: string,
roleId: number,
userId: number,
createdBy: string,
): Promise<void> {
const usersWithRoles = await this.getAccessToProject(projectId);
const user = usersWithRoles.groups.find((u) => u.id === userId);
2023-03-14 10:32:00 +01:00
if (!user) throw new TypeError('Unexpected empty user');
const currentRole = usersWithRoles.roles.find(
(r) => r.id === user.roleId,
);
2023-03-14 10:32:00 +01:00
if (!currentRole) throw new TypeError('Unexpected empty current role');
if (currentRole.id === roleId) {
// Nothing to do....
return;
}
await this.validateAtLeastOneOwner(projectId, currentRole);
await this.accessService.updateGroupProjectRole(
userId,
roleId,
projectId,
);
const role = await this.findProjectGroupRole(projectId, roleId);
await this.eventStore.store(
new ProjectGroupUpdateRoleEvent({
project: projectId,
createdBy,
preData: {
userId,
roleId: currentRole.id,
roleName: currentRole.name,
},
data: {
userId,
roleId,
roleName: role.name,
},
}),
);
}
async getMembers(projectId: string): Promise<number> {
return this.store.getMembersCountByProject(projectId);
}
async getProjectUsers(
projectId: string,
): Promise<Array<Pick<IUser, 'id' | 'email' | 'username'>>> {
const [, users, groups] = await this.accessService.getProjectRoleAccess(
projectId,
);
const actualUsers = users.map((user) => ({
id: user.id,
email: user.email,
username: user.username,
}));
const actualGroupUsers = groups
.flatMap((group) => group.users)
.map((user) => user.user)
.map((user) => ({
id: user.id,
email: user.email,
username: user.username,
}));
return uniqueByKey([...actualUsers, ...actualGroupUsers], 'id');
}
async isProjectUser(userId: number, projectId: string): Promise<boolean> {
const users = await this.getProjectUsers(projectId);
return Boolean(users.find((user) => user.id === userId));
}
async getProjectsByUser(userId: number): Promise<string[]> {
return this.store.getProjectsByUser(userId);
}
async statusJob(): Promise<void> {
if (this.flagResolver.isEnabled('projectStatusApi')) {
const projects = await this.store.getAll();
const statusUpdates = await Promise.all(
projects.map((project) => this.getStatusUpdates(project.id)),
);
await Promise.all(
statusUpdates.map((statusUpdate) => {
return this.projectStatsStore.updateProjectStats(
statusUpdate.projectId,
statusUpdate.updates,
);
}),
);
} else {
this.logger.info('Project status API is disabled');
}
}
async getStatusUpdates(projectId: string): Promise<ICalculateStatus> {
// Get all features for project with type release
// todo: remove after release of the improved query
const features = await this.featureToggleStore.getAll({
type: 'release',
project: projectId,
});
// todo: remove after release of the improved query
const archivedFeatures = await this.featureToggleStore.getAll({
archived: true,
type: 'release',
project: projectId,
});
const dateMinusThirtyDays = subDays(new Date(), 30).toISOString();
const dateMinusSixtyDays = subDays(new Date(), 60).toISOString();
const [
createdCurrentWindow,
createdPastWindow,
archivedCurrentWindow,
archivedPastWindow,
] = await Promise.all([
await this.featureToggleStore.countByDate({
project: projectId,
dateAccessor: 'created_at',
date: dateMinusThirtyDays,
}),
await this.featureToggleStore.countByDate({
project: projectId,
dateAccessor: 'created_at',
range: [dateMinusSixtyDays, dateMinusThirtyDays],
}),
await this.featureToggleStore.countByDate({
project: projectId,
archived: true,
dateAccessor: 'archived_at',
date: dateMinusThirtyDays,
}),
await this.featureToggleStore.countByDate({
project: projectId,
archived: true,
dateAccessor: 'archived_at',
range: [dateMinusSixtyDays, dateMinusThirtyDays],
}),
]);
const [projectActivityCurrentWindow, projectActivityPastWindow] =
await Promise.all([
this.eventStore.queryCount([
{ op: 'where', parameters: { project: projectId } },
{
op: 'beforeDate',
parameters: {
dateAccessor: 'created_at',
date: dateMinusThirtyDays,
},
},
]),
this.eventStore.queryCount([
{ op: 'where', parameters: { project: projectId } },
{
op: 'betweenDate',
parameters: {
dateAccessor: 'created_at',
range: [dateMinusSixtyDays, dateMinusThirtyDays],
},
},
]),
]);
// Get all project environments with type of production
// todo: remove after release of the improved query
const productionEnvironments =
await this.environmentStore.getProjectEnvironments(projectId, {
type: 'production',
});
// Get all events for features that correspond to feature toggle environment ON
// Filter out events that are not a production evironment
// todo: remove after release of the improved query
const allFeatures = [...features, ...archivedFeatures];
// todo: remove after release of the improved query
const eventsData = await this.eventStore.query([
{
op: 'forFeatures',
parameters: {
features: allFeatures.map((feature) => feature.name),
environments: productionEnvironments.map((env) => env.name),
type: FEATURE_ENVIRONMENT_ENABLED,
projectId,
},
},
]);
// todo: remove after release of the improved query
const timeToProduction = new TimeToProduction(
allFeatures,
productionEnvironments,
eventsData,
);
const avgTimeToProdCurrentWindowFast =
TimeToProduction.calculateAverageTimeToProd(
await this.projectStatsStore.getTimeToProdDates(projectId),
);
const avgTimeToProdCurrentWindowSlow =
timeToProduction.calculateAverageTimeToProd();
const avgTimeToProdCurrentWindow = this.flagResolver.isEnabled(
'projectStatusApiImprovements',
)
? avgTimeToProdCurrentWindowFast
: avgTimeToProdCurrentWindowSlow;
if (avgTimeToProdCurrentWindowFast != avgTimeToProdCurrentWindowSlow) {
this.logger.warn(
`Lead time calculation difference, old ${avgTimeToProdCurrentWindowSlow}, new ${avgTimeToProdCurrentWindowFast}`,
);
}
const projectMembersAddedCurrentWindow =
await this.store.getMembersCountByProjectAfterDate(
projectId,
dateMinusThirtyDays,
);
return {
projectId,
updates: {
avgTimeToProdCurrentWindow,
createdCurrentWindow,
createdPastWindow,
archivedCurrentWindow,
archivedPastWindow,
projectActivityCurrentWindow,
projectActivityPastWindow,
projectMembersAddedCurrentWindow,
},
};
}
async getProjectOverview(
projectId: string,
archived: boolean = false,
userId?: number,
): Promise<IProjectOverview> {
const [
project,
environments,
features,
members,
favorite,
projectStats,
] = await Promise.all([
this.store.get(projectId),
this.store.getEnvironmentsForProject(projectId),
this.featureToggleService.getFeatureOverview({
projectId,
archived,
userId,
}),
this.store.getMembersCountByProject(projectId),
2023-03-14 10:32:00 +01:00
userId
? this.favoritesService.isFavoriteProject({
project: projectId,
userId,
})
: Promise.resolve(false),
this.projectStatsStore.getProjectStats(projectId),
]);
return {
stats: projectStats,
name: project.name,
description: project.description,
2023-03-16 15:29:52 +01:00
mode: project.mode,
defaultStickiness: project.defaultStickiness || 'default',
2023-03-14 10:32:00 +01:00
health: project.health || 0,
favorite: favorite,
updatedAt: project.updatedAt,
environments,
features,
members,
version: 1,
};
}
async getProjectSettings(projectId: string): Promise<IProjectSettings> {
return this.store.getProjectSettings(projectId);
}
async setProjectSettings(
projectId: string,
defaultStickiness: string,
mode: ProjectMode,
): Promise<void> {
return this.store.setProjectSettings(
projectId,
defaultStickiness,
mode,
);
}
}