From a4b663c7719571d5cff1da65e8b34a4403f8665c Mon Sep 17 00:00:00 2001 From: Sergey Yarkov Date: Mon, 9 Aug 2021 21:21:41 +0300 Subject: [PATCH] refactor: courses controller --- .../Http/Api/v1/CoursesController.ts | 56 ++------ app/Repositories/CourseRepository.ts | 1 + app/Services/CourseService.ts | 128 ++++++++++++++++++ 3 files changed, 142 insertions(+), 43 deletions(-) diff --git a/app/Controllers/Http/Api/v1/CoursesController.ts b/app/Controllers/Http/Api/v1/CoursesController.ts index f0562f8..20218a3 100644 --- a/app/Controllers/Http/Api/v1/CoursesController.ts +++ b/app/Controllers/Http/Api/v1/CoursesController.ts @@ -1,11 +1,6 @@ import { Exception, inject, Ioc } from '@adonisjs/core/build/standalone'; import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'; -/** - * Datatype - */ -import Role from 'App/Datatypes/Enums/RoleEnum'; - /** * Models */ @@ -170,54 +165,29 @@ export default class CoursesController extends BaseController { * Attach student to course * POST /courses/:id/attach-student */ - public async attachStudent({ response, request, params }: HttpContextContract) { - try { - const payload = await request.validate(AddCourseToUserValidator); - const student = await this.User.findOrFail(payload.student_id); - const course = await this.Course.findOrFail(params.id); + public async attachStudent(ctx: HttpContextContract) { + const payload = await ctx.request.validate(AddCourseToUserValidator); + const result = await this.courseService.attachUserCourse(ctx.params.id, payload.student_id); - await course.load('students'); - await student.load('roles'); - - const studentRoles = student.roles.map(r => r.slug); - - if (!studentRoles.includes(Role.STUDENT)) { - throw new Exception(`User cannot be attached to the course without "student" role.`, 400, 'E_USER_ROLE'); - } - - await course.related('students').attach([student.id]); - - return response.ok({ - message: 'Student attached', - data: 'SUCCESS', - }); - } catch (error) { - if (error?.code === '23505') - throw new Exception('Student already attached to that course', 400, 'E_STUDENT_ATTACHED'); - - throw error; + if (!result.success && result.error) { + throw new Exception(result.message, result.status, result.error.code); } + + return this.sendResponse(ctx, result.data, result.message, result.status); } /** * Detach student from course */ - public async detachStudent({ response, request, params }: HttpContextContract) { - const payload = await request.validate(DelCourseFromUserValidator); - const course = await this.Course.query().preload('students').where('id', params.id).firstOrFail(); - const candidate = course.students.find(student => student.id === payload.student_id); + public async detachStudent(ctx: HttpContextContract) { + const payload = await ctx.request.validate(DelCourseFromUserValidator); + const result = await this.courseService.detachUserCourse(ctx.params.id, payload.student_id); - if (!candidate) { - throw new Exception('Student not attached to that course', 400, 'E_STUDENT_NOT_ATTACHED'); + if (!result.success && result.error) { + throw new Exception(result.message, result.status, result.error.code); } - const student = await this.User.findOrFail(payload.student_id); - await course.related('students').detach([student.id]); - - return response.ok({ - message: 'Student detached', - data: 'SUCCESS', - }); + return this.sendResponse(ctx, result.data, result.message, result.status); } } diff --git a/app/Repositories/CourseRepository.ts b/app/Repositories/CourseRepository.ts index e06dee0..226897c 100644 --- a/app/Repositories/CourseRepository.ts +++ b/app/Repositories/CourseRepository.ts @@ -40,6 +40,7 @@ export default class CourseRepository { .preload('teacher') .preload('category') .preload('lessons') + .preload('students') .where('id', id) .first(); diff --git a/app/Services/CourseService.ts b/app/Services/CourseService.ts index db56ed4..f18d3dd 100644 --- a/app/Services/CourseService.ts +++ b/app/Services/CourseService.ts @@ -322,6 +322,134 @@ export default class CourseService { data: course, }; } + + /** + * Attach student to course + * + * @param id Course id + * @param studentId Student id + * @returns Response + */ + public async attachUserCourse(id: string | number, studentId: string | number): Promise { + const course = await this.courseRepository.getById(id); + + if (!course) { + return { + success: false, + status: StatusCodeEnum.NOT_FOUND, + message: 'Course not found.', + data: {}, + error: { + code: 'E_NOT_FOUND', + }, + }; + } + + const student = await this.userRepository.getById(studentId); + + if (!student) { + return { + success: false, + status: StatusCodeEnum.NOT_FOUND, + message: 'Student not found.', + data: {}, + error: { + code: 'E_NOT_FOUND', + }, + }; + } + + const isStudent = RoleHelper.userHasRoles(student.roles, [RoleEnum.STUDENT]); + + if (!isStudent) { + return { + success: false, + status: StatusCodeEnum.BAD_REQUEST, + message: `User cannot be added to the course without "${RoleEnum.STUDENT}" role.`, + data: {}, + error: { + code: 'E_BAD_REQUEST', + }, + }; + } + + try { + await course.related('students').attach([student.id]); + } catch (error) { + if (error.code === '23505') { + return { + success: false, + status: StatusCodeEnum.BAD_REQUEST, + message: 'Student already attached to that course.', + data: {}, + error: { + code: 'E_BAD_REQUEST', + }, + }; + } + throw new Error(error); + } + + return { + success: true, + status: StatusCodeEnum.OK, + message: 'Student attached.', + data: {}, + }; + } + + public async detachUserCourse(id: string | number, studentId: string | number): Promise { + const course = await this.courseRepository.getById(id); + + if (!course) { + return { + success: false, + status: StatusCodeEnum.NOT_FOUND, + message: 'Course not found.', + data: {}, + error: { + code: 'E_NOT_FOUND', + }, + }; + } + + const isAttached = course.students.find(student => student.id === studentId); + + if (!isAttached) { + return { + success: false, + status: StatusCodeEnum.BAD_REQUEST, + message: 'Student not attached to that course.', + data: {}, + error: { + code: 'E_BAD_REQUEST', + }, + }; + } + + const student = await this.userRepository.getById(studentId); + + if (!student) { + return { + success: false, + status: StatusCodeEnum.NOT_FOUND, + message: 'Student not found.', + data: {}, + error: { + code: 'E_NOT_FOUND', + }, + }; + } + + await course.related('students').detach([student.id]); + + return { + success: true, + status: StatusCodeEnum.OK, + message: 'Student detached.', + data: {}, + }; + } } new Ioc().make(CourseService);