feat: detaching students list

This commit is contained in:
Sergey Yarkov 2021-12-11 23:49:39 +03:00
parent 9eaca99e3b
commit e3575caab3
6 changed files with 167 additions and 0 deletions

View File

@ -10,6 +10,8 @@ import CourseService from 'App/Services/CourseService';
* Validators * Validators
*/ */
import AddCourseToUserValidator from 'App/Validators/Course/AddCourseToUserValidator'; import AddCourseToUserValidator from 'App/Validators/Course/AddCourseToUserValidator';
import AttachStudentsValitator from 'App/Validators/Course/AttachStudentsValitator';
import DetachStudentstValitator from 'App/Validators/Course/DetachStudentstValitator';
import CreateCourseValidator from 'App/Validators/Course/CreateCourseValidator'; import CreateCourseValidator from 'App/Validators/Course/CreateCourseValidator';
import DelCourseFromUserValidator from 'App/Validators/Course/DelCourseFromUserValidator'; import DelCourseFromUserValidator from 'App/Validators/Course/DelCourseFromUserValidator';
import SetCourseStatusValidator from 'App/Validators/Course/SetCourseStatusValidator'; import SetCourseStatusValidator from 'App/Validators/Course/SetCourseStatusValidator';
@ -171,6 +173,21 @@ export default class CoursesController extends BaseController {
return this.sendResponse(ctx, result.data, result.message, result.status); return this.sendResponse(ctx, result.data, result.message, result.status);
} }
/**
* Attach list of students to course
* POST /courses/:id/attach-student-list
*/
public async attachStudentList(ctx: HttpContextContract) {
const payload = await ctx.request.validate(AttachStudentsValitator);
const result = await this.courseService.attachStudentList(ctx.params.id, payload.students);
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 * Detach student from course
* DELETE /courses/:id/detach-student * DELETE /courses/:id/detach-student
@ -186,6 +203,21 @@ export default class CoursesController extends BaseController {
return this.sendResponse(ctx, result.data, result.message, result.status); return this.sendResponse(ctx, result.data, result.message, result.status);
} }
/**
* Detach list of students to course
* POST /courses/:id/detach-student-list
*/
public async detachStudentList(ctx: HttpContextContract) {
const payload = await ctx.request.validate(DetachStudentstValitator);
const result = await this.courseService.detachStudentList(ctx.params.id, payload.students);
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);
}
/** /**
* Fetch count of students of course * Fetch count of students of course
* GET /courses/:id/students/count * GET /courses/:id/students/count

View File

@ -30,6 +30,11 @@ export default class UserRepository {
return data; return data;
} }
public async getByIds(ids: Array<string>): Promise<Array<User>> {
const data = await this.User.query().preload('contacts').preload('roles').whereIn('id', ids);
return data;
}
/** /**
* Get user by column * Get user by column
* *

View File

@ -420,6 +420,93 @@ export default class CourseService {
}; };
} }
/**
* Attach list of students from course
*
* @param id Course id
* @param ids Student ids
* @returns Response
*/
public async attachStudentList(id: string | number, ids: Array<string>): Promise<IResponse> {
const course = await this.courseRepository.getById(id);
if (!course) {
return {
success: false,
status: HttpStatusEnum.NOT_FOUND,
message: 'Course not found.',
data: {},
error: {
code: 'E_NOT_FOUND',
},
};
}
const students = await this.userRepository.getByIds(ids);
try {
await course.related('students').attach(students.map(s => s.id));
} catch (error) {
if (error.code === '23505') {
return {
success: false,
status: HttpStatusEnum.BAD_REQUEST,
message: 'Some student already attached to that course.',
data: {},
error: {
code: 'E_BAD_REQUEST',
},
};
}
throw new Error(error);
}
return {
success: true,
status: HttpStatusEnum.OK,
message: 'Student list successfully attached.',
data: {},
};
}
/**
* Detach list of students from course
*
* @param id Course id
* @param ids Student ids
* @returns Response
*/
public async detachStudentList(id: string | number, ids: Array<string>): Promise<IResponse> {
const course = await this.courseRepository.getById(id);
if (!course) {
return {
success: false,
status: HttpStatusEnum.NOT_FOUND,
message: 'Course not found.',
data: {},
error: {
code: 'E_NOT_FOUND',
},
};
}
const students = await this.userRepository.getByIds(ids);
try {
await course.related('students').detach(students.map(s => s.id));
} catch (error) {
throw new Error(error);
}
return {
success: true,
status: HttpStatusEnum.OK,
message: 'Student list successfully detached from course.',
data: {},
};
}
public async detachUserCourse(id: string | number, studentId: string | number): Promise<IResponse> { public async detachUserCourse(id: string | number, studentId: string | number): Promise<IResponse> {
const course = await this.courseRepository.getById(id); const course = await this.courseRepository.getById(id);

View File

@ -0,0 +1,23 @@
import { schema, rules } from '@ioc:Adonis/Core/Validator';
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext';
export default class AttachStudentsValitator {
constructor(protected ctx: HttpContextContract) {}
public schema = schema.create({
students: schema.array().members(
schema.string({}, [
rules.exists({ table: 'users', column: 'id' }),
rules.unique({
table: 'users_courses',
column: 'user_id',
where: {
course_id: this.ctx.params.id,
},
}),
])
),
});
public messages = {};
}

View File

@ -0,0 +1,12 @@
import { schema, rules } from '@ioc:Adonis/Core/Validator';
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext';
export default class DetachStudentstValitator {
constructor(protected ctx: HttpContextContract) {}
public schema = schema.create({
students: schema.array().members(schema.string({}, [rules.exists({ table: 'users', column: 'id' })])),
});
public messages = {};
}

View File

@ -30,6 +30,14 @@ Route.group(() => {
.middleware('role:admin,teacher') .middleware('role:admin,teacher')
.as('courses.attach-student'); .as('courses.attach-student');
Route.post('/:id/attach-student-list', 'Api/v1/CoursesController.attachStudentList')
.middleware('role:admin,teacher')
.as('courses.attach-student-list');
Route.patch('/:id/detach-student-list', 'Api/v1/CoursesController.detachStudentList')
.middleware('role:admin,teacher')
.as('courses.detach-student-list');
Route.delete('/:id/detach-student', 'Api/v1/CoursesController.detachStudent') Route.delete('/:id/detach-student', 'Api/v1/CoursesController.detachStudent')
.middleware('role:admin,teacher') .middleware('role:admin,teacher')
.as('courses.detach-student'); .as('courses.detach-student');