import Drive from '@ioc:Adonis/Core/Drive'; import { cuid } from '@ioc:Adonis/Core/Helpers'; /** * Models */ import Course from 'App/Models/Course'; import Lesson from 'App/Models/Lesson'; import LessonMaterial from 'App/Models/LessonMaterial'; import LessonVideo from 'App/Models/LessonVideo'; /** * Validators */ import CreateLessonValidator from 'App/Validators/Lesson/CreateLessonValidator'; import UpdateLessonValidator from 'App/Validators/Lesson/UpdateLessonValidator'; export default class LessonRepository { private Lesson: typeof Lesson; private LessonMaterial: typeof LessonMaterial; private LessonVideo: typeof LessonVideo; private Drive: typeof Drive; constructor() { this.Lesson = Lesson; this.LessonMaterial = LessonMaterial; this.LessonVideo = LessonVideo; this.Drive = Drive; } /** * Get all lessons * * @returns Lessons */ public async getAll(): Promise { const lessons = await this.Lesson.query(); return lessons; } /** * Get one lesson by id * * @param id Lesson id * @returns Lesson or null */ public async getById(id: string | number): Promise { const lesson = await this.Lesson.query().where('id', id).preload('color').withCount('materials').first(); return lesson; } /** * Get content of lesson by id * * @param id Lesson id * @returns Content of lesson or null */ public async getContentById(id: string | number): Promise { const lesson = await this.Lesson.query().preload('content').where('id', id).first(); return lesson && lesson.content; } /** * Get lesson material by name * * @param fileName Name of file * @returns Lesson material or null */ public async getMaterialFileByName(fileName: string): Promise { const material = await this.LessonMaterial.query().where('name', fileName).first(); return material; } /** * Get lesson material by id * * @param id Material id * @returns Lesson material or null */ public async getMaterialFileById(id: number): Promise { const material = await this.LessonMaterial.query().where('id', id).first(); return material; } public async getVideoFileByName(fileName: string): Promise { const video = await this.LessonVideo.query().where('name', fileName).first(); return video; } /** * Create lesson * * @param course Course of lesson * @returns Lesson */ public async create(course: Course, data: CreateLessonValidator['schema']['props']): Promise { await course.loadCount('lessons'); const lesson = await this.Lesson.create({ title: data.title, description: data.description, duration: data.duration.toFormat('HH:mm:ss'), display_order: Number.parseInt(course.$extras.lessons_count, 10) + 1, course_id: course.id, }); /** * Create content */ await lesson.related('content').create({ video_url: data.video_url }); /** * Move video file to disk and save to database */ const videoName = `${cuid()}.${data.video.extname}`; 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 */ if (data.materials) { /** * Move each file to disk */ const files = await Promise.all( data.materials.map(async file => { const name = `${cuid()}.${file.extname}`; await file.moveToDisk('materials', { name }); return { file, name }; }) ); /** * Create lesson material */ const materials = await Promise.all( files.map(async ({ file, name }) => { if (file.state === 'moved' && file.fileName && file.extname) { const material = new LessonMaterial(); material.name = name; material.size = file.size; material.clientName = file.clientName; material.ext = file.extname; return material; } return null; }) ); /** * Save lesson materials to database */ await lesson.related('materials').createMany(materials.filter((l): l is LessonMaterial => l !== null)); } /** * Load data */ await lesson.load(loader => loader.load('content').load('materials').load('video')); return lesson; } /** * Update lesson * * @param id Lesson id * @returns Updated lesson */ public async update(id: string | number, data: UpdateLessonValidator['schema']['props']): Promise { 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 { 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( lesson.materials.map(async material => { await this.Drive.delete(`materials/${material.name}`); }) ); /** * Delete lesson from database */ await lesson.delete(); return lesson; } return null; } }