Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin' into BC-5522-impl-of-deletion-api
Browse files Browse the repository at this point in the history
  • Loading branch information
sszafGCA committed Nov 8, 2023
2 parents cce8684 + e82f2d7 commit aa32e24
Show file tree
Hide file tree
Showing 24 changed files with 716 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export const enum DeletionDomainModel {
FILE = 'file',
LESSONS = 'lessons',
PSEUDONYMS = 'pseudonyms',
ROCKETCHATUSER = 'rocketChatUser',
TEAMS = 'teams',
USER = 'user',
}
52 changes: 52 additions & 0 deletions apps/server/src/modules/deletion/uc/deletion-request.uc.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ import { LessonService } from '@modules/lesson/service';
import { PseudonymService } from '@modules/pseudonym';
import { TeamService } from '@modules/teams';
import { UserService } from '@modules/user';
import { RocketChatService } from '@modules/rocketchat';
import { rocketChatUserFactory } from '@modules/rocketchat-user/domain/testing';
import { RocketChatUser, RocketChatUserService } from '@modules/rocketchat-user';
import { DeletionDomainModel } from '../domain/types/deletion-domain-model.enum';
import { DeletionLogService } from '../services/deletion-log.service';
import { DeletionRequestService } from '../services';
Expand All @@ -32,6 +35,8 @@ describe(DeletionRequestUc.name, () => {
let pseudonymService: DeepMocked<PseudonymService>;
let teamService: DeepMocked<TeamService>;
let userService: DeepMocked<UserService>;
let rocketChatUserService: DeepMocked<RocketChatUserService>;
let rocketChatService: DeepMocked<RocketChatService>;

beforeAll(async () => {
module = await Test.createTestingModule({
Expand Down Expand Up @@ -81,6 +86,14 @@ describe(DeletionRequestUc.name, () => {
provide: UserService,
useValue: createMock<UserService>(),
},
{
provide: RocketChatUserService,
useValue: createMock<RocketChatUserService>(),
},
{
provide: RocketChatService,
useValue: createMock<RocketChatService>(),
},
],
}).compile();

Expand All @@ -96,6 +109,8 @@ describe(DeletionRequestUc.name, () => {
pseudonymService = module.get(PseudonymService);
teamService = module.get(TeamService);
userService = module.get(UserService);
rocketChatUserService = module.get(RocketChatUserService);
rocketChatService = module.get(RocketChatService);
await setupEntities();
});

Expand Down Expand Up @@ -153,6 +168,9 @@ describe(DeletionRequestUc.name, () => {
const setup = () => {
jest.clearAllMocks();
const deletionRequestToExecute = deletionRequestFactory.build({ deleteAfter: new Date('2023-01-01') });
const rocketChatUser: RocketChatUser = rocketChatUserFactory.build({
userId: deletionRequestToExecute.targetRefId,
});

classService.deleteUserDataFromClasses.mockResolvedValueOnce(1);
courseGroupService.deleteUserDataFromCourseGroup.mockResolvedValueOnce(2);
Expand All @@ -163,9 +181,11 @@ describe(DeletionRequestUc.name, () => {
pseudonymService.deleteByUserId.mockResolvedValueOnce(2);
teamService.deleteUserDataFromTeams.mockResolvedValueOnce(2);
userService.deleteUser.mockResolvedValueOnce(1);
rocketChatUserService.deleteByUserId.mockResolvedValueOnce(1);

return {
deletionRequestToExecute,
rocketChatUser,
};
};

Expand Down Expand Up @@ -287,6 +307,38 @@ describe(DeletionRequestUc.name, () => {
expect(userService.deleteUser).toHaveBeenCalledWith(deletionRequestToExecute.targetRefId);
});

it('should call rocketChatUserService.findByUserId to find rocketChatUser in rocketChatUser module', async () => {
const { deletionRequestToExecute } = setup();

deletionRequestService.findAllItemsToExecute.mockResolvedValueOnce([deletionRequestToExecute]);

await uc.executeDeletionRequests();

expect(rocketChatUserService.findByUserId).toHaveBeenCalledWith(deletionRequestToExecute.targetRefId);
});

it('should call rocketChatUserService.deleteByUserId to delete rocketChatUser in rocketChatUser module', async () => {
const { deletionRequestToExecute, rocketChatUser } = setup();

deletionRequestService.findAllItemsToExecute.mockResolvedValueOnce([deletionRequestToExecute]);
rocketChatUserService.findByUserId.mockResolvedValueOnce(rocketChatUser);

await uc.executeDeletionRequests();

expect(rocketChatUserService.deleteByUserId).toHaveBeenCalledWith(deletionRequestToExecute.targetRefId);
});

it('should call rocketChatService.deleteUser to delete rocketChatUser in rocketChat external module', async () => {
const { deletionRequestToExecute, rocketChatUser } = setup();

deletionRequestService.findAllItemsToExecute.mockResolvedValueOnce([deletionRequestToExecute]);
rocketChatUserService.findByUserId.mockResolvedValueOnce(rocketChatUser);

await uc.executeDeletionRequests();

expect(rocketChatService.deleteUser).toHaveBeenCalledWith(rocketChatUser.username);
});

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

Expand Down
18 changes: 17 additions & 1 deletion apps/server/src/modules/deletion/uc/deletion-request.uc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import { LessonService } from '@modules/lesson/service';
import { CourseGroupService, CourseService } from '@modules/learnroom/service';
import { FilesService } from '@modules/files/service';
import { AccountService } from '@modules/account/services';
import { RocketChatUserService } from '@modules/rocketchat-user';
import { RocketChatService } from '@modules/rocketchat';
import { DeletionRequestService } from '../services/deletion-request.service';
import { DeletionDomainModel } from '../domain/types/deletion-domain-model.enum';
import { DeletionLogService } from '../services/deletion-log.service';
Expand All @@ -34,7 +36,9 @@ export class DeletionRequestUc {
private readonly lessonService: LessonService,
private readonly pseudonymService: PseudonymService,
private readonly teamService: TeamService,
private readonly userService: UserService
private readonly userService: UserService,
private readonly rocketChatUserService: RocketChatUserService,
private readonly rocketChatService: RocketChatService
) {}

async createDeletionRequest(deletionRequest: DeletionRequestBodyProps): Promise<DeletionRequestResponse> {
Expand Down Expand Up @@ -92,6 +96,7 @@ export class DeletionRequestUc {
this.removeUsersPseudonyms(deletionRequest),
this.removeUserFromTeams(deletionRequest),
this.removeUser(deletionRequest),
this.removeUserFromRocketChat(deletionRequest),
]);
await this.deletionRequestService.markDeletionRequestAsExecuted(deletionRequest.id);
} catch (error) {
Expand Down Expand Up @@ -202,4 +207,15 @@ export class DeletionRequestUc {
const userDeleted: number = await this.userService.deleteUser(deletionRequest.targetRefId);
await this.logDeletion(deletionRequest, DeletionDomainModel.USER, DeletionOperationModel.DELETE, 0, userDeleted);
}

private async removeUserFromRocketChat(deletionRequest: DeletionRequest): Promise<number> {
const rocketChatUser = await this.rocketChatUserService.findByUserId(deletionRequest.targetRefId);

const [, rocketChatUserDeleted] = await Promise.all([
this.rocketChatService.deleteUser(rocketChatUser.username),
this.rocketChatUserService.deleteByUserId(rocketChatUser.userId),
]);

return rocketChatUserDeleted;
}
}
1 change: 1 addition & 0 deletions apps/server/src/modules/rocketchat-user/domain/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './rocket-chat-user.do';
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { ObjectId } from '@mikro-orm/mongodb';
import { RocketChatUser } from './rocket-chat-user.do';
import { rocketChatUserFactory } from './testing/rocket-chat-user.factory';

describe(RocketChatUser.name, () => {
describe('constructor', () => {
describe('When constructor is called', () => {
it('should create a rocketChatUser by passing required properties', () => {
const domainObject: RocketChatUser = rocketChatUserFactory.build();

expect(domainObject instanceof RocketChatUser).toEqual(true);
});
});

describe('when passed a valid id', () => {
const setup = () => {
const domainObject: RocketChatUser = rocketChatUserFactory.build();

return { domainObject };
};

it('should set the id', () => {
const { domainObject } = setup();

const rocketChatUserObject: RocketChatUser = new RocketChatUser(domainObject);

expect(rocketChatUserObject.id).toEqual(domainObject.id);
});
});
});

describe('getters', () => {
describe('When getters are used', () => {
const setup = () => {
const props = {
id: new ObjectId().toHexString(),
userId: new ObjectId().toHexString(),
username: 'Test.User.shls',
rcId: 'JfMJXua6t29KYXdDc',
authToken: 'OL8e5YCZHy3agGnLS-gHAx1wU4ZCG8-DXU_WZnUxUu6',
createdAt: new Date(),
updatedAt: new Date(),
};

const rocketChatUserDo = new RocketChatUser(props);

return { props, rocketChatUserDo };
};

it('getters should return proper values', () => {
const { props, rocketChatUserDo } = setup();

const gettersValues = {
id: rocketChatUserDo.id,
userId: rocketChatUserDo.userId,
username: rocketChatUserDo.username,
rcId: rocketChatUserDo.rcId,
authToken: rocketChatUserDo.authToken,
createdAt: rocketChatUserDo.createdAt,
updatedAt: rocketChatUserDo.updatedAt,
};

expect(gettersValues).toEqual(props);
});
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { EntityId } from '@shared/domain/types';
import { AuthorizableObject, DomainObject } from '@shared/domain/domain-object';

export interface RocketChatUserProps extends AuthorizableObject {
userId: EntityId;
username: string;
rcId: string;
authToken?: string;
createdAt?: Date;
updatedAt?: Date;
}

export class RocketChatUser extends DomainObject<RocketChatUserProps> {
get userId(): EntityId {
return this.props.userId;
}

get username(): string {
return this.props.username;
}

get rcId(): string {
return this.props.rcId;
}

get authToken(): string | undefined {
return this.props.authToken;
}

get createdAt(): Date | undefined {
return this.props.createdAt;
}

get updatedAt(): Date | undefined {
return this.props.updatedAt;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './rocket-chat-user.factory';
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { ObjectId } from '@mikro-orm/mongodb';
import { BaseFactory } from '@shared/testing';
import { RocketChatUser, RocketChatUserProps } from '../rocket-chat-user.do';

export const rocketChatUserFactory = BaseFactory.define<RocketChatUser, RocketChatUserProps>(
RocketChatUser,
({ sequence }) => {
return {
id: new ObjectId().toHexString(),
userId: new ObjectId().toHexString(),
username: `username-${sequence}`,
rcId: `rcId-${sequence}`,
authToken: `aythToken-${sequence}`,
createdAt: new Date(),
updatedAt: new Date(),
};
}
);
1 change: 1 addition & 0 deletions apps/server/src/modules/rocketchat-user/entity/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './rocket-chat-user.entity';
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { setupEntities } from '@shared/testing';
import { ObjectId } from '@mikro-orm/mongodb';
import { RocketChatUserEntity } from '@src/modules/rocketchat-user/entity';

describe(RocketChatUserEntity.name, () => {
beforeAll(async () => {
await setupEntities();
});

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

const setup = () => {
const props = {
id: new ObjectId().toHexString(),
userId: new ObjectId(),
username: 'Test.User.shls',
rcId: 'JfMJXua6t29KYXdDc',
authToken: 'OL8e5YCZHy3agGnLS-gHAx1wU4ZCG8-DXU_WZnUxUu6',
createdAt: new Date(),
updatedAt: new Date(),
};

return { props };
};

describe('constructor', () => {
describe('When constructor is called', () => {
it('should throw an error by empty constructor', () => {
// @ts-expect-error: Test case
const test = () => new RocketChatUserEntity();
expect(test).toThrow();
});

it('should create a rocketChatUser by passing required properties', () => {
const { props } = setup();
const entity: RocketChatUserEntity = new RocketChatUserEntity(props);

expect(entity instanceof RocketChatUserEntity).toEqual(true);
});

it(`should return a valid object with fields values set from the provided complete props object`, () => {
const { props } = setup();
const entity: RocketChatUserEntity = new RocketChatUserEntity(props);

const entityProps = {
id: entity.id,
userId: entity.userId,
username: entity.username,
rcId: entity.rcId,
authToken: entity.authToken,
createdAt: entity.createdAt,
updatedAt: entity.updatedAt,
};

expect(entityProps).toEqual(props);
});
});
});
});
Loading

0 comments on commit aa32e24

Please sign in to comment.