Skip to content

Commit

Permalink
feat: archive project service (#7794)
Browse files Browse the repository at this point in the history
  • Loading branch information
kwasniew authored Aug 7, 2024
1 parent c36ead4 commit 0450bfe
Show file tree
Hide file tree
Showing 6 changed files with 95 additions and 4 deletions.
43 changes: 43 additions & 0 deletions src/lib/features/project/project-service.e2e.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,49 @@ test('should update project', async () => {
expect(updatedProject.defaultStickiness).toBe('userId');
});

test('should archive project', async () => {
const project = {
id: 'test-archive',
name: 'New project',
description: 'Blah',
mode: 'open' as const,
defaultStickiness: 'default',
};

await projectService.createProject(project, user, TEST_AUDIT_USER);
await projectService.archiveProject(project.id, TEST_AUDIT_USER);

const events = await stores.eventStore.getEvents();

expect(events[0]).toMatchObject({
type: 'project-archived',
createdBy: TEST_AUDIT_USER.username,
});
});

test('should not be able to archive project with flags', async () => {
const project = {
id: 'test-archive-with-flags',
name: 'New project',
description: 'Blah',
mode: 'open' as const,
defaultStickiness: 'default',
};
await projectService.createProject(project, user, auditUser);
await stores.featureToggleStore.create(project.id, {
name: 'test-project-archive',
createdByUserId: 9999,
});

try {
await projectService.archiveProject(project.id, auditUser);
} catch (err) {
expect(err.message).toBe(
'You can not archive a project with active feature flags',
);
}
});

test('should update project without existing settings', async () => {
const project = {
id: 'test-update-legacy',
Expand Down
31 changes: 28 additions & 3 deletions src/lib/features/project/project-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { nameType } from '../../routes/util';
import { projectSchema } from '../../services/project-schema';
import NotFoundError from '../../error/notfound-error';
import {
ADMIN,
ADMIN_TOKEN_USER,
type CreateProject,
DEFAULT_PROJECT,
Expand All @@ -27,6 +28,7 @@ import {
type IProjectApplications,
type IProjectHealth,
type IProjectOverview,
type IProjectOwnersReadModel,
type IProjectRoleUsage,
type IProjectStore,
type IProjectUpdate,
Expand All @@ -38,6 +40,8 @@ import {
ProjectAccessGroupRolesUpdated,
ProjectAccessUserRolesDeleted,
ProjectAccessUserRolesUpdated,
ProjectArchivedEvent,
type ProjectCreated,
ProjectCreatedEvent,
ProjectDeletedEvent,
ProjectGroupAddedEvent,
Expand All @@ -49,9 +53,6 @@ import {
ProjectUserUpdateRoleEvent,
RoleName,
SYSTEM_USER_ID,
type ProjectCreated,
type IProjectOwnersReadModel,
ADMIN,
} from '../../types';
import type {
IProjectAccessModel,
Expand Down Expand Up @@ -591,6 +592,30 @@ export default class ProjectService {
await this.accessService.removeDefaultProjectRoles(user, id);
}

async archiveProject(id: string, auditUser: IAuditUser): Promise<void> {
const flags = await this.featureToggleStore.getAll({
project: id,
archived: false,
});

// TODO: allow archiving project with unused flags

if (flags.length > 0) {
throw new InvalidOperationError(
'You can not archive a project with active feature flags',
);
}

await this.projectStore.archive(id);

await this.eventService.storeEvent(
new ProjectArchivedEvent({
project: id,
auditUser,
}),
);
}

async validateId(id: string): Promise<boolean> {
await nameType.validateAsync(id);
await this.validateUniqueId(id);
Expand Down
2 changes: 2 additions & 0 deletions src/lib/features/project/project-store-type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,4 +134,6 @@ export interface IProjectStore extends Store<IProject, string> {
getApplicationsByProject(
searchParams: IProjectApplicationsSearchParams,
): Promise<IProjectApplications>;

archive(projectId: string): Promise<void>;
}
5 changes: 5 additions & 0 deletions src/lib/features/project/project-store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,11 @@ class ProjectStore implements IProjectStore {
}
}

async archive(id: string): Promise<void> {
const now = new Date();
await this.db(TABLE).where({ id }).update({ archived_at: now });
}

async getProjectLinksForEnvironments(
environments: string[],
): Promise<IEnvironmentProjectLink[]> {
Expand Down
16 changes: 15 additions & 1 deletion src/lib/types/events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ export const ROLE_DELETED = 'role-deleted';
export const PROJECT_CREATED = 'project-created' as const;
export const PROJECT_UPDATED = 'project-updated' as const;
export const PROJECT_DELETED = 'project-deleted' as const;
export const PROJECT_ARCHIVED = 'project-archived' as const;
export const PROJECT_IMPORT = 'project-import' as const;
export const PROJECT_USER_ADDED = 'project-user-added' as const;
export const PROJECT_USER_REMOVED = 'project-user-removed' as const;
Expand Down Expand Up @@ -249,6 +250,7 @@ export const IEventTypes = [
PROJECT_CREATED,
PROJECT_UPDATED,
PROJECT_DELETED,
PROJECT_ARCHIVED,
PROJECT_IMPORT,
PROJECT_USER_ADDED,
PROJECT_USER_REMOVED,
Expand Down Expand Up @@ -574,7 +576,19 @@ export class ProjectDeletedEvent extends BaseEvent {
project: string;
auditUser: IAuditUser;
}) {
super(PROJECT_DELETED, eventData.auditUser);
super(PROJECT_ARCHIVED, eventData.auditUser);
this.project = eventData.project;
}
}

export class ProjectArchivedEvent extends BaseEvent {
readonly project: string;

constructor(eventData: {
project: string;
auditUser: IAuditUser;
}) {
super(PROJECT_ARCHIVED, eventData.auditUser);
this.project = eventData.project;
}
}
Expand Down
2 changes: 2 additions & 0 deletions src/test/fixtures/fake-project-store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -214,4 +214,6 @@ export default class FakeProjectStore implements IProjectStore {
): Promise<IProjectApplications> {
throw new Error('Method not implemented.');
}

async archive(id: string): Promise<void> {}
}

0 comments on commit 0450bfe

Please sign in to comment.