mirror of
https://github.com/sergeyyarkov/educt-server.git
synced 2026-10-11 02:09:07 +03:00
feat: likes system in courses
This commit is contained in:
parent
d96a54351e
commit
4c1572a9d8
@ -170,6 +170,7 @@ export default class CoursesController extends BaseController {
|
||||
|
||||
/**
|
||||
* Detach student from course
|
||||
* DELETE /courses/:id/detach-student
|
||||
*/
|
||||
public async detachStudent(ctx: HttpContextContract) {
|
||||
const payload = await ctx.request.validate(DelCourseFromUserValidator);
|
||||
@ -182,6 +183,10 @@ export default class CoursesController extends BaseController {
|
||||
return this.sendResponse(ctx, result.data, result.message, result.status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch count of students of course
|
||||
* GET /courses/:id/students/count
|
||||
*/
|
||||
public async studentsCount(ctx: HttpContextContract) {
|
||||
const result = await this.courseService.fetchStudentsCount(ctx.params.id);
|
||||
|
||||
@ -191,6 +196,34 @@ export default class CoursesController extends BaseController {
|
||||
|
||||
return this.sendResponse(ctx, result.data, result.message, result.status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set like on course by authorized user
|
||||
* PUT /courses/:id/likes
|
||||
*/
|
||||
public async setLike(ctx: HttpContextContract) {
|
||||
const result = await this.courseService.attachUserLike(ctx.params.id, ctx.auth);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unset like on course by authorized user
|
||||
* DELETE /courses/:id/likes
|
||||
*/
|
||||
public async unsetLike(ctx: HttpContextContract) {
|
||||
const result = await this.courseService.detachUserLike(ctx.params.id, ctx.auth);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
new Ioc().make(CoursesController);
|
||||
|
||||
@ -53,6 +53,16 @@ export default class Course extends BaseModel {
|
||||
})
|
||||
public students: ManyToMany<typeof User>;
|
||||
|
||||
@manyToMany(() => User, {
|
||||
pivotTable: 'courses_likes',
|
||||
pivotTimestamps: {
|
||||
createdAt: 'liked_on',
|
||||
updatedAt: false,
|
||||
},
|
||||
pivotColumns: ['liked_on'],
|
||||
})
|
||||
public likes: ManyToMany<typeof User>;
|
||||
|
||||
@column.dateTime({ autoCreate: true })
|
||||
public createdAt: DateTime;
|
||||
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import { inject, Ioc } from '@adonisjs/core/build/standalone';
|
||||
import { AuthContract } from '@ioc:Adonis/Addons/Auth';
|
||||
import RoleEnum from 'App/Datatypes/Enums/RoleEnum';
|
||||
|
||||
/**
|
||||
@ -7,13 +8,17 @@ import RoleEnum from 'App/Datatypes/Enums/RoleEnum';
|
||||
import StatusCodeEnum from 'App/Datatypes/Enums/StatusCodeEnum';
|
||||
import IResponse from 'App/Datatypes/Interfaces/IResponse';
|
||||
import RoleHelper from 'App/Helpers/RoleHelper';
|
||||
import CategoryRepository from 'App/Repositories/CategoryRepository';
|
||||
|
||||
/**
|
||||
* Repositories
|
||||
*/
|
||||
import CourseRepository from 'App/Repositories/CourseRepository';
|
||||
import UserRepository from 'App/Repositories/UserRepository';
|
||||
import CategoryRepository from 'App/Repositories/CategoryRepository';
|
||||
|
||||
/**
|
||||
* Validators
|
||||
*/
|
||||
import CreateCourseValidator from 'App/Validators/Course/CreateCourseValidator';
|
||||
import UpdateCourseValidator from 'App/Validators/Course/UpdateCourseValidator';
|
||||
|
||||
@ -479,6 +484,77 @@ export default class CourseService {
|
||||
data: {},
|
||||
};
|
||||
}
|
||||
|
||||
public async attachUserLike(id: string | number, auth: AuthContract): Promise<any> {
|
||||
const user = await auth.use('api').authenticate();
|
||||
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',
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
try {
|
||||
await course.related('likes').attach([user.id]);
|
||||
} catch (error) {
|
||||
if (error.code === '23505') {
|
||||
return {
|
||||
success: false,
|
||||
status: StatusCodeEnum.BAD_REQUEST,
|
||||
message: 'You are already liked this course.',
|
||||
data: {},
|
||||
error: {
|
||||
code: 'E_BAD_REQUEST',
|
||||
},
|
||||
};
|
||||
}
|
||||
throw new Error(error);
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
status: StatusCodeEnum.OK,
|
||||
message: 'Like attached.',
|
||||
data: {},
|
||||
};
|
||||
}
|
||||
|
||||
public async detachUserLike(id: string | number, auth: AuthContract): Promise<any> {
|
||||
const user = await auth.use('api').authenticate();
|
||||
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',
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
try {
|
||||
await course.related('likes').detach([user.id]);
|
||||
} catch (error) {
|
||||
throw new Error(error);
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
status: StatusCodeEnum.OK,
|
||||
message: 'Like detached.',
|
||||
data: {},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
new Ioc().make(CourseService);
|
||||
|
||||
19
database/migrations/1628622517837_courses_likes.ts
Normal file
19
database/migrations/1628622517837_courses_likes.ts
Normal file
@ -0,0 +1,19 @@
|
||||
import BaseSchema from '@ioc:Adonis/Lucid/Schema';
|
||||
|
||||
export default class CoursesLikes extends BaseSchema {
|
||||
protected tableName = 'courses_likes';
|
||||
|
||||
public async up() {
|
||||
this.schema.createTable(this.tableName, table => {
|
||||
table.increments('id');
|
||||
table.string('user_id', 21).unsigned().references('users.id').onDelete('CASCADE');
|
||||
table.string('course_id', 21).unsigned().references('courses.id').onDelete('CASCADE');
|
||||
table.timestamp('liked_on', { useTz: true });
|
||||
table.unique(['user_id', 'course_id']);
|
||||
});
|
||||
}
|
||||
|
||||
public async down() {
|
||||
this.schema.dropTable(this.tableName);
|
||||
}
|
||||
}
|
||||
@ -33,4 +33,12 @@ Route.group(() => {
|
||||
Route.delete('/:id/detach-student', 'Api/v1/CoursesController.detachStudent')
|
||||
.middleware('role:admin,teacher')
|
||||
.as('courses.detach-student');
|
||||
|
||||
Route.put('/:id/likes', 'Api/v1/CoursesController.setLike')
|
||||
.middleware('role:admin,teacher,student')
|
||||
.as('courses.set-like');
|
||||
|
||||
Route.delete('/:id/likes', 'Api/v1/CoursesController.unsetLike')
|
||||
.middleware('role:admin,teacher,student')
|
||||
.as('courses.unset-like');
|
||||
}).prefix('courses');
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user