mirror of
https://github.com/sergeyyarkov/educt-server.git
synced 2026-10-11 02:09:07 +03:00
feat: lesson updating
This commit is contained in:
parent
cb80f507cc
commit
81e511ed19
@ -88,7 +88,7 @@ export default class LessonsController extends BaseController {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Update lesson by id.
|
* Update lesson by id.
|
||||||
* PUT /lessons/:id
|
* PATCH /lessons/:id
|
||||||
*/
|
*/
|
||||||
public async update(ctx: HttpContextContract) {
|
public async update(ctx: HttpContextContract) {
|
||||||
const payload = await ctx.request.validate(UpdateLessonValidator);
|
const payload = await ctx.request.validate(UpdateLessonValidator);
|
||||||
|
|||||||
@ -283,10 +283,11 @@ export default class CourseRepository {
|
|||||||
/**
|
/**
|
||||||
* Load other updated data
|
* Load other updated data
|
||||||
*/
|
*/
|
||||||
course.load('category');
|
await course.load('category');
|
||||||
course.load('teacher');
|
await course.load('teacher');
|
||||||
|
|
||||||
await course.save();
|
await course.save();
|
||||||
|
|
||||||
return course;
|
return course;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
import Drive from '@ioc:Adonis/Core/Drive';
|
import Drive from '@ioc:Adonis/Core/Drive';
|
||||||
|
import { MultipartFileContract } from '@ioc:Adonis/Core/BodyParser';
|
||||||
import { cuid } from '@ioc:Adonis/Core/Helpers';
|
import { cuid } from '@ioc:Adonis/Core/Helpers';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -115,27 +116,123 @@ export default class LessonRepository {
|
|||||||
/**
|
/**
|
||||||
* Move video file to disk and save to database
|
* Move video file to disk and save to database
|
||||||
*/
|
*/
|
||||||
const videoName = `${cuid()}.${data.video.extname}`;
|
await this.createVideo(lesson, data.video);
|
||||||
await data.video.moveToDisk('videos', { name: videoName });
|
|
||||||
if (data.video.state === 'moved') {
|
|
||||||
await lesson.related('video').create({
|
|
||||||
name: videoName,
|
|
||||||
clientName: data.video.clientName,
|
|
||||||
ext: data.video.extname,
|
|
||||||
size: data.video.size,
|
|
||||||
url: `/video/${videoName}`,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create materials
|
* Create materials
|
||||||
*/
|
*/
|
||||||
if (data.materials) {
|
if (data.materials) {
|
||||||
|
await this.createMaterials(lesson, data.materials);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load data
|
||||||
|
*/
|
||||||
|
await lesson.load(loader => loader.load('content').load('materials').load('video').load('progress'));
|
||||||
|
|
||||||
|
return lesson;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update lesson
|
||||||
|
*
|
||||||
|
* @param id Lesson id
|
||||||
|
* @returns Updated lesson
|
||||||
|
*/
|
||||||
|
public async update(id: string | number, data: UpdateLessonValidator['schema']['props']): Promise<Lesson | null> {
|
||||||
|
const lesson = await this.Lesson.query().preload('video').preload('color').where('id', id).first();
|
||||||
|
|
||||||
|
if (lesson) {
|
||||||
|
/**
|
||||||
|
* Update files
|
||||||
|
*/
|
||||||
|
lesson.merge({
|
||||||
|
title: data.title,
|
||||||
|
description: data.description,
|
||||||
|
course_id: data.course_id,
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update video
|
||||||
|
*/
|
||||||
|
if (data.video) {
|
||||||
|
/**
|
||||||
|
* Delete video from drive and database
|
||||||
|
*/
|
||||||
|
await this.Drive.delete(`videos/${lesson.video.name}`);
|
||||||
|
await lesson.related('video').query().delete();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Upload new video to drive and save to database
|
||||||
|
*/
|
||||||
|
await this.createVideo(lesson, data.video);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update materials
|
||||||
|
*/
|
||||||
|
if (data.materials && data.materials !== null) {
|
||||||
|
await this.deleteMaterials(lesson);
|
||||||
|
await this.createMaterials(lesson, data.materials);
|
||||||
|
} else if (data.materials === null) await this.deleteMaterials(lesson);
|
||||||
|
|
||||||
|
await lesson.load(loader => loader.load('video').load('materials'));
|
||||||
|
await lesson.save();
|
||||||
|
|
||||||
|
return lesson;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete lesson
|
||||||
|
*
|
||||||
|
* @param id Lesson id
|
||||||
|
* @returns Deleted lesson or null
|
||||||
|
*/
|
||||||
|
public async delete(id: string | number): Promise<Lesson | null> {
|
||||||
|
const lesson = await this.Lesson.query().where('id', id).preload('video').preload('color').first();
|
||||||
|
|
||||||
|
if (lesson) {
|
||||||
|
/**
|
||||||
|
* Delete files from disk
|
||||||
|
*/
|
||||||
|
await this.Drive.delete(`videos/${lesson.video.name}`);
|
||||||
|
await this.deleteMaterials(lesson);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete lesson from database
|
||||||
|
*/
|
||||||
|
await lesson.delete();
|
||||||
|
return lesson;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line class-methods-use-this
|
||||||
|
public async createVideo(lesson: Lesson, video: MultipartFileContract): Promise<void> {
|
||||||
|
const videoName = `${cuid()}.${video.extname}`;
|
||||||
|
await video.moveToDisk('videos', { name: videoName });
|
||||||
|
if (video.state === 'moved') {
|
||||||
|
await lesson.related('video').create({
|
||||||
|
name: videoName,
|
||||||
|
clientName: video.clientName,
|
||||||
|
ext: video.extname,
|
||||||
|
size: video.size,
|
||||||
|
url: `/video/${videoName}`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line class-methods-use-this
|
||||||
|
public async createMaterials(lesson: Lesson, materials: MultipartFileContract[]): Promise<void> {
|
||||||
/**
|
/**
|
||||||
* Move each file to disk
|
* Move each file to disk
|
||||||
*/
|
*/
|
||||||
const files = await Promise.all(
|
const files = await Promise.all(
|
||||||
data.materials.map(async file => {
|
materials.map(async file => {
|
||||||
const name = `${cuid()}.${file.extname}`;
|
const name = `${cuid()}.${file.extname}`;
|
||||||
await file.moveToDisk('materials', { name });
|
await file.moveToDisk('materials', { name });
|
||||||
return { file, name };
|
return { file, name };
|
||||||
@ -145,7 +242,7 @@ export default class LessonRepository {
|
|||||||
/**
|
/**
|
||||||
* Create lesson material
|
* Create lesson material
|
||||||
*/
|
*/
|
||||||
const materials = await Promise.all(
|
const promises = await Promise.all(
|
||||||
files.map(async ({ file, name }) => {
|
files.map(async ({ file, name }) => {
|
||||||
if (file.state === 'moved' && file.fileName && file.extname) {
|
if (file.state === 'moved' && file.fileName && file.extname) {
|
||||||
const material = new LessonMaterial();
|
const material = new LessonMaterial();
|
||||||
@ -165,71 +262,16 @@ export default class LessonRepository {
|
|||||||
/**
|
/**
|
||||||
* Save lesson materials to database
|
* Save lesson materials to database
|
||||||
*/
|
*/
|
||||||
await lesson.related('materials').createMany(materials.filter((l): l is LessonMaterial => l !== null));
|
await lesson.related('materials').createMany(promises.filter((l): l is LessonMaterial => l !== null));
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Load data
|
|
||||||
*/
|
|
||||||
await lesson.load(loader => loader.load('content').load('materials').load('video').load('progress'));
|
|
||||||
|
|
||||||
return lesson;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public async deleteMaterials(lesson: Lesson) {
|
||||||
* Update lesson
|
await lesson.load('materials');
|
||||||
*
|
|
||||||
* @param id Lesson id
|
|
||||||
* @returns Updated lesson
|
|
||||||
*/
|
|
||||||
public async update(id: string | number, data: UpdateLessonValidator['schema']['props']): Promise<Lesson | null> {
|
|
||||||
const lesson = await this.Lesson.query().where('id', id).first();
|
|
||||||
|
|
||||||
if (lesson) {
|
|
||||||
await lesson
|
|
||||||
.merge({
|
|
||||||
course_id: data.course_id,
|
|
||||||
title: data.title,
|
|
||||||
description: data.description,
|
|
||||||
})
|
|
||||||
.save();
|
|
||||||
|
|
||||||
return lesson;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delete lesson
|
|
||||||
*
|
|
||||||
* @param id Lesson id
|
|
||||||
* @returns Deleted lesson or null
|
|
||||||
*/
|
|
||||||
public async delete(id: string | number): Promise<Lesson | null> {
|
|
||||||
const lesson = await this.Lesson.query()
|
|
||||||
.where('id', id)
|
|
||||||
.preload('video')
|
|
||||||
.preload('materials')
|
|
||||||
.preload('color')
|
|
||||||
.first();
|
|
||||||
|
|
||||||
if (lesson) {
|
|
||||||
/**
|
|
||||||
* Delete files from disk
|
|
||||||
*/
|
|
||||||
await this.Drive.delete(`videos/${lesson.video.name}`);
|
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
lesson.materials.map(async material => {
|
lesson.materials.map(async material => {
|
||||||
await this.Drive.delete(`materials/${material.name}`);
|
await this.Drive.delete(`materials/${material.name}`);
|
||||||
|
await material.delete();
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
|
||||||
* Delete lesson from database
|
|
||||||
*/
|
|
||||||
await lesson.delete();
|
|
||||||
return lesson;
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,9 +5,20 @@ export default class UpdateLessonValidator {
|
|||||||
constructor(protected ctx: HttpContextContract) {}
|
constructor(protected ctx: HttpContextContract) {}
|
||||||
|
|
||||||
public schema = schema.create({
|
public schema = schema.create({
|
||||||
course_id: schema.string({}, [rules.exists({ table: 'courses', column: 'id' })]),
|
course_id: schema.string.optional({}, [rules.exists({ table: 'courses', column: 'id' })]),
|
||||||
title: schema.string({}, [rules.maxLength(255)]),
|
title: schema.string.optional({}, [rules.maxLength(255)]),
|
||||||
description: schema.string(),
|
description: schema.string.optional(),
|
||||||
|
duration: schema.date.optional({ format: 'HH:mm:ss' }),
|
||||||
|
video: schema.file.optional({
|
||||||
|
size: '5000mb',
|
||||||
|
extnames: ['mp4', 'mov', 'avi', 'wmv', 'webm', 'flv'],
|
||||||
|
}),
|
||||||
|
materials: schema.array.nullableAndOptional().members(
|
||||||
|
schema.file({
|
||||||
|
size: '100mb',
|
||||||
|
extnames: ['pdf', 'zip', 'rar', 'doc', 'docx'],
|
||||||
|
})
|
||||||
|
),
|
||||||
});
|
});
|
||||||
|
|
||||||
public messages = {};
|
public messages = {};
|
||||||
|
|||||||
@ -8,7 +8,7 @@ Route.group(() => {
|
|||||||
.as('lessons.update-order');
|
.as('lessons.update-order');
|
||||||
Route.get('/:id', 'Api/v1/LessonsController.show').middleware('role:admin,teacher,student').as('lessons.show');
|
Route.get('/:id', 'Api/v1/LessonsController.show').middleware('role:admin,teacher,student').as('lessons.show');
|
||||||
Route.delete('/:id', 'Api/v1/LessonsController.delete').middleware('role:admin,teacher').as('lessons.delete');
|
Route.delete('/:id', 'Api/v1/LessonsController.delete').middleware('role:admin,teacher').as('lessons.delete');
|
||||||
Route.put('/:id', 'Api/v1/LessonsController.update').middleware('role:admin,teacher').as('lessons.update');
|
Route.patch('/:id', 'Api/v1/LessonsController.update').middleware('role:admin,teacher').as('lessons.update');
|
||||||
Route.get('/:id/content', 'Api/v1/LessonsController.getContent')
|
Route.get('/:id/content', 'Api/v1/LessonsController.getContent')
|
||||||
.middleware('role:admin,teacher,student')
|
.middleware('role:admin,teacher,student')
|
||||||
.as('lessons.get-content');
|
.as('lessons.get-content');
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user