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 */ import Course from 'App/Models/Course'; import User from 'App/Models/User'; import CourseService from 'App/Services/CourseService'; /** * Validators */ import AddCourseToUserValidator from 'App/Validators/Course/AddCourseToUserValidator'; import CreateCourseValidator from 'App/Validators/Course/CreateCourseValidator'; import DelCourseFromUserValidator from 'App/Validators/Course/DelCourseFromUserValidator'; import UpdateCourseValidator from 'App/Validators/Course/UpdateCourseValidator'; import BaseController from '../../BaseController'; @inject() export default class CoursesController extends BaseController { private courseService: CourseService; private readonly Course: typeof Course; private readonly User: typeof User; constructor(courseService: CourseService) { super(); this.courseService = courseService; this.Course = Course; this.User = User; } /** * List of all Courses * GET /courses */ public async list(ctx: HttpContextContract) { const result = await this.courseService.fetchCourses(); 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); } /** * Show Course by "id" * GET /courses/:id */ public async show(ctx: HttpContextContract) { const result = await this.courseService.fetchCourse(ctx.params.id); 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); } /** * Show Teacher of Course with "id" * GET /courses/:id/teacher */ public async showTeacher(ctx: HttpContextContract) { const result = await this.courseService.fetchCourseTeacher(ctx.params.id); 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); } /** * Show Category of Course with "id" * GET /courses/:id/category */ public async showCategory(ctx: HttpContextContract) { const result = await this.courseService.fetchCourseCategory(ctx.params.id); 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); } /** * Show Lessons of ourse with "id" * GET /courses/:id/lessons */ public async showLessons(ctx: HttpContextContract) { const result = await this.courseService.fetchCourseLessons(ctx.params.id); 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); } /** * Show Students of Course with "id" * GET /courses/:id/students */ public async showStudents(ctx: HttpContextContract) { const result = await this.courseService.fetchCourseStudents(ctx.params.id); 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); } /** * Create new Course in a system * POST /courses */ public async create(ctx: HttpContextContract) { const payload = await ctx.request.validate(CreateCourseValidator); const result = await this.courseService.createCourse(payload); 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); } /** * Delete Course by "id" * DELETE /courses/:id */ public async delete(ctx: HttpContextContract) { const result = await this.courseService.deleteCourse(ctx.params.id); 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); } /** * Update Course by "id" * PATCH /courses/:id */ public async update({ response, request, params }: HttpContextContract) { const payload = await request.validate(UpdateCourseValidator); const course = await this.Course.findOrFail(params.id); /** * Update course */ Object.keys(payload).forEach(k => { if (payload[k] !== undefined) { course[k] = payload[k]; } }); await course.save(); await course.load('category'); await course.load('lessons'); await course.load('teacher'); return response.ok({ message: `Course with id: "${course.id}" was successfully updated.`, data: course, }); } /** * 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); 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; } } /** * 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); if (!candidate) { throw new Exception('Student not attached to that course', 400, 'E_STUDENT_NOT_ATTACHED'); } const student = await this.User.findOrFail(payload.student_id); await course.related('students').detach([student.id]); return response.ok({ message: 'Student detached', data: 'SUCCESS', }); } } new Ioc().make(CoursesController);