refactor: courses controller

This commit is contained in:
Sergey Yarkov 2021-08-09 21:21:41 +03:00
parent 2b8658072c
commit a4b663c771
3 changed files with 142 additions and 43 deletions

View File

@ -1,11 +1,6 @@
import { Exception, inject, Ioc } from '@adonisjs/core/build/standalone'; import { Exception, inject, Ioc } from '@adonisjs/core/build/standalone';
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'; import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext';
/**
* Datatype
*/
import Role from 'App/Datatypes/Enums/RoleEnum';
/** /**
* Models * Models
*/ */
@ -170,54 +165,29 @@ export default class CoursesController extends BaseController {
* Attach student to course * Attach student to course
* POST /courses/:id/attach-student * POST /courses/:id/attach-student
*/ */
public async attachStudent({ response, request, params }: HttpContextContract) { public async attachStudent(ctx: HttpContextContract) {
try { const payload = await ctx.request.validate(AddCourseToUserValidator);
const payload = await request.validate(AddCourseToUserValidator); const result = await this.courseService.attachUserCourse(ctx.params.id, payload.student_id);
const student = await this.User.findOrFail(payload.student_id);
const course = await this.Course.findOrFail(params.id);
await course.load('students'); if (!result.success && result.error) {
await student.load('roles'); throw new Exception(result.message, result.status, result.error.code);
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;
} }
return this.sendResponse(ctx, result.data, result.message, result.status);
} }
/** /**
* Detach student from course * Detach student from course
*/ */
public async detachStudent({ response, request, params }: HttpContextContract) { public async detachStudent(ctx: HttpContextContract) {
const payload = await request.validate(DelCourseFromUserValidator); const payload = await ctx.request.validate(DelCourseFromUserValidator);
const course = await this.Course.query().preload('students').where('id', params.id).firstOrFail(); const result = await this.courseService.detachUserCourse(ctx.params.id, payload.student_id);
const candidate = course.students.find(student => student.id === payload.student_id);
if (!candidate) { if (!result.success && result.error) {
throw new Exception('Student not attached to that course', 400, 'E_STUDENT_NOT_ATTACHED'); throw new Exception(result.message, result.status, result.error.code);
} }
const student = await this.User.findOrFail(payload.student_id); return this.sendResponse(ctx, result.data, result.message, result.status);
await course.related('students').detach([student.id]);
return response.ok({
message: 'Student detached',
data: 'SUCCESS',
});
} }
} }

View File

@ -40,6 +40,7 @@ export default class CourseRepository {
.preload('teacher') .preload('teacher')
.preload('category') .preload('category')
.preload('lessons') .preload('lessons')
.preload('students')
.where('id', id) .where('id', id)
.first(); .first();

View File

@ -322,6 +322,134 @@ export default class CourseService {
data: course, 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<IResponse> {
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<IResponse> {
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); new Ioc().make(CourseService);