Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BC-5834-Add-Dashboard-Entities-Deletion-to-the-Main-User-Deletion-Use-Case #4622

Merged
merged 19 commits into from
Dec 18, 2023
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
778fe21
add method in dashboard repo
WojciechGrancow Dec 7, 2023
829f42f
add dashboard service
WojciechGrancow Dec 7, 2023
5571ff2
modify service, add some test
WojciechGrancow Dec 12, 2023
73d1ea7
Merge branch 'main' into BC-58340-Add-Dashboard-to-KNLDeletion
WojciechGrancow Dec 12, 2023
d2c64b4
add test for dashboardService
WojciechGrancow Dec 12, 2023
fb66e90
Merge branch 'main' into BC-58340-Add-Dashboard-to-KNLDeletion
WojciechGrancow Dec 12, 2023
eb5ec13
Update apps/server/src/modules/learnroom/service/dashboard.service.sp…
WojciechGrancow Dec 12, 2023
e7b8934
Merge branch 'main' into BC-58340-Add-Dashboard-to-KNLDeletion
WojciechGrancow Dec 13, 2023
e34073d
Update apps/server/src/modules/deletion/uc/deletion-request.uc.ts
WojciechGrancow Dec 14, 2023
053562d
Update apps/server/src/modules/learnroom/service/dashboard.service.ts
WojciechGrancow Dec 14, 2023
146cff6
Merge branch 'BC-58340-Add-Dashboard-to-KNLDeletion' of https://githu…
WojciechGrancow Dec 15, 2023
3ca12c4
changes after revieew
WojciechGrancow Dec 15, 2023
baad763
Merge remote-tracking branch 'origin' into BC-58340-Add-Dashboard-to-…
WojciechGrancow Dec 15, 2023
59c273e
change name of variable
WojciechGrancow Dec 15, 2023
5f1218d
Merge branch 'main' into BC-58340-Add-Dashboard-to-KNLDeletion
WojciechGrancow Dec 15, 2023
43b4708
add imports
WojciechGrancow Dec 15, 2023
ea95dcb
Merge branch 'main' into BC-58340-Add-Dashboard-to-KNLDeletion
WojciechGrancow Dec 16, 2023
438147e
fix imports
WojciechGrancow Dec 16, 2023
50d34e4
add test to DashboardGridElementModelRepo
WojciechGrancow Dec 18, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ export const enum DeletionDomainModel {
CLASS = 'class',
COURSEGROUP = 'courseGroup',
COURSE = 'course',
DASHBOARD = 'dashboard',
FILE = 'file',
LESSONS = 'lessons',
PSEUDONYMS = 'pseudonyms',
Expand Down
21 changes: 19 additions & 2 deletions apps/server/src/modules/deletion/uc/deletion-request.uc.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { DeepMocked, createMock } from '@golevelup/ts-jest';
import { setupEntities, userDoFactory } from '@shared/testing';
import { AccountService } from '@modules/account';
import { ClassService } from '@modules/class';
import { CourseGroupService, CourseService } from '@modules/learnroom';
import { CourseGroupService, CourseService, DashboardService } from '@modules/learnroom';
import { FilesService } from '@modules/files';
import { LessonService } from '@modules/lesson';
import { PseudonymService } from '@modules/pseudonym';
Expand Down Expand Up @@ -40,6 +40,7 @@ describe(DeletionRequestUc.name, () => {
let rocketChatUserService: DeepMocked<RocketChatUserService>;
let rocketChatService: DeepMocked<RocketChatService>;
let registrationPinService: DeepMocked<RegistrationPinService>;
let dashboardService: DeepMocked<DashboardService>;

beforeAll(async () => {
module = await Test.createTestingModule({
Expand Down Expand Up @@ -105,6 +106,10 @@ describe(DeletionRequestUc.name, () => {
provide: RegistrationPinService,
useValue: createMock<RegistrationPinService>(),
},
{
provide: DashboardService,
useValue: createMock<DashboardService>(),
},
],
}).compile();

Expand All @@ -123,6 +128,7 @@ describe(DeletionRequestUc.name, () => {
rocketChatUserService = module.get(RocketChatUserService);
rocketChatService = module.get(RocketChatService);
registrationPinService = module.get(RegistrationPinService);
dashboardService = module.get(DashboardService);
await setupEntities();
});

Expand Down Expand Up @@ -199,6 +205,7 @@ describe(DeletionRequestUc.name, () => {
teamService.deleteUserDataFromTeams.mockResolvedValueOnce(2);
userService.deleteUser.mockResolvedValueOnce(1);
rocketChatUserService.deleteByUserId.mockResolvedValueOnce(1);
dashboardService.deleteDashboardByUserId.mockResolvedValueOnce(1);

return {
deletionRequestToExecute,
Expand Down Expand Up @@ -381,14 +388,24 @@ describe(DeletionRequestUc.name, () => {
expect(rocketChatService.deleteUser).toHaveBeenCalledWith(rocketChatUser.username);
});

it('should call dashboardService.deleteDashboardByUserId to delete USERS DASHBOARD', async () => {
const { deletionRequestToExecute } = setup();

deletionRequestService.findAllItemsToExecute.mockResolvedValueOnce([deletionRequestToExecute]);

await uc.executeDeletionRequests();

expect(dashboardService.deleteDashboardByUserId).toHaveBeenCalledWith(deletionRequestToExecute.targetRefId);
});

it('should call deletionLogService.createDeletionLog to create logs for deletionRequest', async () => {
const { deletionRequestToExecute } = setup();

deletionRequestService.findAllItemsToExecute.mockResolvedValueOnce([deletionRequestToExecute]);

await uc.executeDeletionRequests();

expect(deletionLogService.createDeletionLog).toHaveBeenCalledTimes(10);
expect(deletionLogService.createDeletionLog).toHaveBeenCalledTimes(11);
});
});

Expand Down
20 changes: 18 additions & 2 deletions apps/server/src/modules/deletion/uc/deletion-request.uc.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { AccountService } from '@modules/account/services';
import { ClassService } from '@modules/class';
import { FilesService } from '@modules/files/service';
import { CourseGroupService, CourseService } from '@modules/learnroom/service';
import { CourseGroupService, CourseService, DashboardService } from '@modules/learnroom/service';
WojciechGrancow marked this conversation as resolved.
Show resolved Hide resolved
import { LessonService } from '@modules/lesson/service';
import { PseudonymService } from '@modules/pseudonym';
import { RegistrationPinService } from '@modules/registration-pin';
Expand Down Expand Up @@ -38,7 +38,8 @@ export class DeletionRequestUc {
private readonly rocketChatUserService: RocketChatUserService,
private readonly rocketChatService: RocketChatService,
private readonly logger: LegacyLogger,
private readonly registrationPinService: RegistrationPinService
private readonly registrationPinService: RegistrationPinService,
private readonly dashboardService: DashboardService
) {
this.logger.setContext(DeletionRequestUc.name);
}
Expand Down Expand Up @@ -71,6 +72,7 @@ export class DeletionRequestUc {
this.logger.debug({ action: 'deletionRequestId', deletionRequestId });

const deletionRequest: DeletionRequest = await this.deletionRequestService.findById(deletionRequestId);
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
WojciechGrancow marked this conversation as resolved.
Show resolved Hide resolved
let response: DeletionRequestLogResponse = DeletionRequestLogResponseBuilder.build(
DeletionTargetRefBuilder.build(deletionRequest.targetRefDomain, deletionRequest.targetRefId),
deletionRequest.deleteAfter
Expand Down Expand Up @@ -107,6 +109,7 @@ export class DeletionRequestUc {
this.removeUser(deletionRequest),
this.removeUserFromRocketChat(deletionRequest),
this.removeUserRegistrationPin(deletionRequest),
this.removeUsersDashboard(deletionRequest),
]);
await this.deletionRequestService.markDeletionRequestAsExecuted(deletionRequest.id);
} catch (error) {
Expand Down Expand Up @@ -200,6 +203,19 @@ export class DeletionRequestUc {
);
}

private async removeUsersDashboard(deletionRequest: DeletionRequest) {
this.logger.debug({ action: 'removeUsersDashboard', deletionRequest });

const dashboardDeleted: number = await this.dashboardService.deleteDashboardByUserId(deletionRequest.targetRefId);
await this.logDeletion(
deletionRequest,
DeletionDomainModel.DASHBOARD,
DeletionOperationModel.DELETE,
0,
dashboardDeleted
);
}

private async removeUsersFilesAndPermissions(deletionRequest: DeletionRequest) {
this.logger.debug({ action: 'removeUsersFilesAndPermissions', deletionRequest });

Expand Down
1 change: 1 addition & 0 deletions apps/server/src/modules/learnroom/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ export {
CourseService,
RoomsService,
CourseGroupService,
DashboardService,
} from './service';
118 changes: 118 additions & 0 deletions apps/server/src/modules/learnroom/service/dashboard.service.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
import { createMock, DeepMocked } from '@golevelup/ts-jest';
import { Test, TestingModule } from '@nestjs/testing';
import { DashboardElementRepo, IDashboardRepo, UserRepo } from '@shared/repo';
import { setupEntities, userFactory } from '@shared/testing';
import { LearnroomMetadata, LearnroomTypes } from '@shared/domain/types';
import { DashboardEntity, GridElement } from '@shared/domain/entity';
import { DashboardService } from '.';

const learnroomMock = (id: string, name: string) => {
return {
getMetadata(): LearnroomMetadata {
return {
id,
type: LearnroomTypes.Course,
title: name,
shortTitle: name.substr(0, 2),
displayColor: '#ACACAC',
};
},
};
};

describe(DashboardService.name, () => {
let module: TestingModule;
let userRepo: DeepMocked<UserRepo>;
let dashboardRepo: IDashboardRepo;
let dashboardElementRepo: DeepMocked<DashboardElementRepo>;
let dashboardService: DeepMocked<DashboardService>;

beforeAll(async () => {
await setupEntities();
module = await Test.createTestingModule({
providers: [
DashboardService,
{
provide: UserRepo,
useValue: createMock<UserRepo>(),
},
{
provide: 'DASHBOARD_REPO',
useValue: createMock<DashboardService>(),
},
{
provide: DashboardElementRepo,
useValue: createMock<DashboardElementRepo>(),
},
],
}).compile();
dashboardService = module.get(DashboardService);
userRepo = module.get(UserRepo);
dashboardRepo = module.get('DASHBOARD_REPO');
dashboardElementRepo = module.get(DashboardElementRepo);
});

afterAll(async () => {
await module.close();
});

beforeEach(() => {
jest.clearAllMocks();
});

describe('when deleting by userId', () => {
const setup = () => {
const user = userFactory.buildWithId();
userRepo.findById.mockResolvedValue(user);

return { user };
};

it('should call dashboardRepo.getUsersDashboard', async () => {
const { user } = setup();
const spy = jest.spyOn(dashboardRepo, 'getUsersDashboard');

await dashboardService.deleteDashboardByUserId(user.id);

expect(spy).toHaveBeenCalledWith(user.id);
});

it('should call dashboardElementRepo.deleteByDashboardId', async () => {
const { user } = setup();
jest.spyOn(dashboardRepo, 'getUsersDashboard').mockResolvedValueOnce(
new DashboardEntity('dashboardId', {
grid: [
{
pos: { x: 1, y: 2 },
gridElement: GridElement.FromPersistedReference('elementId', learnroomMock('referenceId', 'Mathe')),
},
],
userId: 'userId',
})
);
const spy = jest.spyOn(dashboardElementRepo, 'deleteByDashboardId');

await dashboardService.deleteDashboardByUserId(user.id);

expect(spy).toHaveBeenCalledWith('dashboardId');
});

it('should call dashboardRepo.deleteDashboardByUserId', async () => {
const { user } = setup();
const spy = jest.spyOn(dashboardRepo, 'deleteDashboardByUserId');

await dashboardService.deleteDashboardByUserId(user.id);

expect(spy).toHaveBeenCalledWith(user.id);
});

it('should delete users dashboard', async () => {
const { user } = setup();
jest.spyOn(dashboardRepo, 'deleteDashboardByUserId').mockImplementation(() => Promise.resolve(1));

const result = await dashboardService.deleteDashboardByUserId(user.id);

expect(result).toEqual(1);
});
});
});
20 changes: 20 additions & 0 deletions apps/server/src/modules/learnroom/service/dashboard.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { Inject, Injectable } from '@nestjs/common';
import { EntityId } from '@shared/domain/types';
import { IDashboardRepo } from '@shared/repo';
import { DashboardElementRepo } from '@shared/repo/dashboard/dashboardElement.repo';
WojciechGrancow marked this conversation as resolved.
Show resolved Hide resolved

@Injectable()
export class DashboardService {
constructor(
@Inject('DASHBOARD_REPO') private readonly dashboardRepo: IDashboardRepo,
private readonly dashboardElementRepo: DashboardElementRepo
) {}

async deleteDashboardByUserId(userId: EntityId): Promise<number> {
const usersDashboard = await this.dashboardRepo.getUsersDashboard(userId);
await this.dashboardElementRepo.deleteByDashboardId(usersDashboard.id);
const promise = await this.dashboardRepo.deleteDashboardByUserId(userId);

return promise;
WojciechGrancow marked this conversation as resolved.
Show resolved Hide resolved
}
}
1 change: 1 addition & 0 deletions apps/server/src/modules/learnroom/service/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ export * from './common-cartridge-export.service';
export * from './course.service';
export * from './rooms.service';
export * from './coursegroup.service';
export * from './dashboard.service';
Original file line number Diff line number Diff line change
Expand Up @@ -244,4 +244,46 @@ describe('dashboard repo', () => {
});
});
});

describe('deleteDashboardByUserId', () => {
const setup = async () => {
const userWithoutDashoard = userFactory.build();
const user = userFactory.build();
const course = courseFactory.build({ students: [user], name: 'Mathe' });
await em.persistAndFlush([userWithoutDashoard, user, course]);
const dashboard = new DashboardEntity(new ObjectId().toString(), {
grid: [
{
pos: { x: 1, y: 3 },
gridElement: GridElement.FromSingleReference(course),
},
],
userId: user.id,
});
await repo.persistAndFlush(dashboard);

return { userWithoutDashoard, user };
};
describe('when user has no dashboard ', () => {
it('should return 0', async () => {
const { userWithoutDashoard } = await setup();

const result = await repo.deleteDashboardByUserId(userWithoutDashoard.id);
expect(result).toEqual(0);
});
});

describe('when user has dashboard ', () => {
it('should return 1', async () => {
const { user } = await setup();

const result1 = await repo.deleteDashboardByUserId(user.id);
expect(result1).toEqual(1);

const result2 = await repo.getUsersDashboard(user.id);
expect(result2 instanceof DashboardEntity).toEqual(true);
expect(result2.getGrid().length).toEqual(0);
});
});
});
});
7 changes: 7 additions & 0 deletions apps/server/src/shared/repo/dashboard/dashboard.repo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export interface IDashboardRepo {
getUsersDashboard(userId: EntityId): Promise<DashboardEntity>;
getDashboardById(id: EntityId): Promise<DashboardEntity>;
persistAndFlush(entity: DashboardEntity): Promise<DashboardEntity>;
deleteDashboardByUserId(userId: EntityId): Promise<number>;
}

@Injectable()
Expand Down Expand Up @@ -51,4 +52,10 @@ export class DashboardRepo implements IDashboardRepo {

return dashboard;
}

async deleteDashboardByUserId(userId: EntityId): Promise<number> {
const promise: Promise<number> = this.em.nativeDelete(DashboardModelEntity, { user: userId });

return promise;
}
}
Loading
Loading