Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
10 changes: 5 additions & 5 deletions backend/src/application/controllers/pendingInviteController.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Controller } from './controllerExpress';
import { Request, HttpMethod, RouteHandlers } from '../types';
import { defaultExtractor } from './helpersExpress';
import * as PendingInviteServices from '../../core/services/pending_invite';
import * as PendingInviteServices from '../../core/services/join_request';

/**
* Controller responsible for pending invite-related API endpoints including CRUD operations
Expand All @@ -14,10 +14,10 @@ import * as PendingInviteServices from '../../core/services/pending_invite';
*/
export class PendingInviteController extends Controller {
constructor(
get: PendingInviteServices.GetInvite,
getUserInvites: PendingInviteServices.GetUserInvites,
remove: PendingInviteServices.DeleteInvite,
create: PendingInviteServices.CreateInvite
get: PendingInviteServices.GetJoinRequest,
getUserInvites: PendingInviteServices.GetUserJoinRequest,
remove: PendingInviteServices.DeleteJoinRequest,
create: PendingInviteServices.CreateJoinRequest
) {
const handlers: RouteHandlers = {
[HttpMethod.GET]: [
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Service, ServiceParams } from "../../../config/service";

export class CreateInvite implements Service<ServiceParams> {
export class AcceptJoinRequest implements Service<ServiceParams> {
constructor() {}

async execute(input: ServiceParams): Promise<object> {
Expand Down
72 changes: 72 additions & 0 deletions backend/src/core/services/join_request/createJoinRequest.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { ApiError, ErrorCode } from '../../../application/types';
import { Service, ServiceParams } from '../../../config/service';
import { Class } from '../../entities/class';
import { JoinRequest, JoinRequestType } from '../../entities/joinRequest';
import { IClassRepository } from '../../repositories/classRepositoryInterface';
import { IJoinRequestRepository } from '../../repositories/joinRequestRepositoryInterface';

export class CreateJoinRequestParams implements ServiceParams {
constructor(
private _requesterId: string,
private _classId: string,
private _type: JoinRequestType,
) {}

async fromObject(
joinRequestRepository: IJoinRequestRepository,
classRepository: IClassRepository,
): Promise<JoinRequest> {
// Check if user hasn't already requested to join the class
const classRequests: JoinRequest[] =
await joinRequestRepository.getJoinRequestByClassId(this._classId);
for (const req of classRequests) {
if (req.requester == this._requesterId) {
throw {
code: ErrorCode.CONFLICT,
message: 'User already has a join request for this class.',
} as ApiError;
}
}

// Check if user isn't already part of this class
let classes: Class[];
if (this._type === JoinRequestType.STUDENT) {
classes = await classRepository.getAllClassesByStudentId(
this._requesterId,
);
} else {
classes = await classRepository.getAllClassesByTeacherId(
this._requesterId,
);
}
for (const c of classes) {
if (this._classId === c.id!) {
throw {
code: ErrorCode.CONFLICT,
message: 'User is already part of this class.',
} as ApiError;
}
}
return new JoinRequest(this._requesterId, this._classId, this._type);
}
}

export class CreateJoinRequest implements Service<CreateJoinRequestParams> {
constructor(
private _joinRequestRepository: IJoinRequestRepository,
private _classRepository: IClassRepository,
) {}

async execute(input: CreateJoinRequestParams): Promise<object> {
const joinRequest: JoinRequest =
await this._joinRequestRepository.createJoinRequest(
await input.fromObject(
this._joinRequestRepository,
this._classRepository,
),
);

await this._joinRequestRepository.createJoinRequest(joinRequest);
return { id: joinRequest.id };
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Service, ServiceParams } from "../../../config/service";

export class DeleteInvite implements Service<ServiceParams> {
export class DeleteJoinRequest implements Service<ServiceParams> {
Comment thread
thomasdejaeghere marked this conversation as resolved.
constructor() {}

async execute(input: ServiceParams): Promise<object> {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Service, ServiceParams } from "../../../config/service";

export class AcceptInvite implements Service<ServiceParams> {
export class GetJoinRequest implements Service<ServiceParams> {
constructor() {}

async execute(input: ServiceParams): Promise<object> {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Service, ServiceParams } from "../../../config/service";

export class GetUserInvites implements Service<ServiceParams> {
export class GetUserJoinRequest implements Service<ServiceParams> {
constructor() {}

async execute(input: ServiceParams): Promise<object> {
Expand Down
4 changes: 4 additions & 0 deletions backend/src/core/services/join_request/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export * from './createJoinRequest';
export * from './deleteJoinRequest';
export * from './getJoinRequest';
export * from './getUserJoinRequest';
9 changes: 0 additions & 9 deletions backend/src/core/services/pending_invite/getInvite.ts

This file was deleted.

4 changes: 0 additions & 4 deletions backend/src/core/services/pending_invite/index.ts

This file was deleted.

63 changes: 0 additions & 63 deletions backend/test/application/routes/pendingInviteRoutes.test.ts

This file was deleted.

73 changes: 73 additions & 0 deletions backend/test/core/services/joinRequest/createJoinRequest.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import { ApiError, ErrorCode } from "../../../../src/application/types";
import { Class } from "../../../../src/core/entities/class";
import { JoinRequest, JoinRequestType } from "../../../../src/core/entities/joinRequest";
import { IClassRepository } from "../../../../src/core/repositories/classRepositoryInterface";
import { IJoinRequestRepository } from "../../../../src/core/repositories/joinRequestRepositoryInterface";
import { CreateJoinRequest, CreateJoinRequestParams } from "../../../../src/core/services/join_request";

describe('CreateJoinRequest', () => {
let joinRequestRepository: jest.Mocked<IJoinRequestRepository>;
let classRepository: jest.Mocked<IClassRepository>;
let service: CreateJoinRequest;

beforeEach(() => {
joinRequestRepository = {
createJoinRequest: jest.fn(),
getJoinRequestById: jest.fn(),
getJoinRequestByRequesterId: jest.fn(),
getJoinRequestByClassId: jest.fn(),
deleteJoinRequestById: jest.fn(),
} as unknown as jest.Mocked<IJoinRequestRepository>;

classRepository = {
createClass: jest.fn(),
updateClass: jest.fn(),
getClassById: jest.fn(),
getClassByName: jest.fn(),
getAllClasses: jest.fn(),
getUserClasses: jest.fn(),
getAllClassesByTeacherId: jest.fn(),
getAllClassesByStudentId: jest.fn(),
deleteClassById: jest.fn(),
} as unknown as jest.Mocked<IClassRepository>;

service = new CreateJoinRequest(joinRequestRepository, classRepository);
});

it('should throw an error if user already has a join request for the class', async () => {
const params = new CreateJoinRequestParams('user1', 'class1', JoinRequestType.STUDENT);
joinRequestRepository.getJoinRequestByClassId.mockResolvedValue([
new JoinRequest('user1', 'class1', JoinRequestType.STUDENT),
]);

await expect(params.fromObject(joinRequestRepository, classRepository)).rejects.toEqual({
code: ErrorCode.CONFLICT,
message: 'User already has a join request for this class.',
} as ApiError);
});

it('should throw an error if user is already part of the class', async () => {
const params = new CreateJoinRequestParams('user1', 'class1', JoinRequestType.STUDENT);
joinRequestRepository.getJoinRequestByClassId.mockResolvedValue([]);
classRepository.getAllClassesByStudentId.mockResolvedValue([
{ id: 'class1' } as Class,
]);

await expect(params.fromObject(joinRequestRepository, classRepository)).rejects.toEqual({
code: ErrorCode.CONFLICT,
message: 'User is already part of this class.',
} as ApiError);
});

it('should create a join request successfully', async () => {
const params = new CreateJoinRequestParams('user1', 'class1', JoinRequestType.STUDENT);
joinRequestRepository.getJoinRequestByClassId.mockResolvedValue([]);
classRepository.getAllClassesByStudentId.mockResolvedValue([]);
joinRequestRepository.createJoinRequest.mockResolvedValue(new JoinRequest('user1', 'class1', JoinRequestType.STUDENT));

const result = await service.execute(params);

expect(result).toEqual({ id: undefined });
expect(joinRequestRepository.createJoinRequest).toHaveBeenCalledTimes(2);
});
});