fix: remove course files from drive after deleting user or category

This commit is contained in:
Sergey Yarkov 2022-06-09 23:50:40 +03:00
parent 30fb10b338
commit 7149a0f3eb
5 changed files with 136 additions and 3 deletions

View File

@ -0,0 +1,28 @@
import Course from 'App/Models/Course';
export type FileEntry = {
path: string;
name: string;
};
export default class CourseHelper {
public static getVideoFileNames(course: Course): Array<FileEntry | null> {
const data = course.lessons.map(l => {
if (!l.video) return null;
return { path: 'videos/', name: l.video.name };
});
return data;
}
public static getMaterialFileNames(course: Course): FileEntry[] {
const data = course.lessons.map(l => l.materials.map(m => ({ path: 'materials/', name: m.name }))).flat();
return data;
}
public static getImageFileName(course: Course): FileEntry | null {
if (!course.image) return null;
const data = { path: 'images/courses/', name: course.image.name };
return data;
}
}

View File

@ -32,6 +32,32 @@ export default class CourseRepository {
this.Course = Course; this.Course = Course;
} }
/**
* Get list of courses by teacher id
*
* @param id Teacher id
* @returns Array of courses
*/
public async getByTeacherId(id: string | number): Promise<Course[]> {
const data = await this.Course.query()
.preload('lessons', q => q.preload('video').preload('materials'))
.where('teacher_id', id);
return data;
}
/**
* Get list of courses by category id
*
* @param id Category id
* @returns Array of courses
*/
public async getByCategoryId(id: string | number): Promise<Course[]> {
const data = await this.Course.query()
.preload('lessons', q => q.preload('video').preload('materials'))
.where('category_id', id);
return data;
}
/** /**
* Set status on course * Set status on course
* *

View File

@ -10,6 +10,7 @@ import HttpStatusEnum from 'App/Datatypes/Enums/HttpStatusEnum';
* Repositories * Repositories
*/ */
import CategoryRepository from 'App/Repositories/CategoryRepository'; import CategoryRepository from 'App/Repositories/CategoryRepository';
import CourseRepository from 'App/Repositories/CourseRepository';
/** /**
* Validators * Validators
@ -17,12 +18,27 @@ import CategoryRepository from 'App/Repositories/CategoryRepository';
import CreateCategoryValidator from 'App/Validators/Category/CreateCategoryValidator'; import CreateCategoryValidator from 'App/Validators/Category/CreateCategoryValidator';
import UpdateCategoryValidator from 'App/Validators/Category/UpdateCategoryValidator'; import UpdateCategoryValidator from 'App/Validators/Category/UpdateCategoryValidator';
/**
* Services
*/
import CourseService from 'App/Services/CourseService';
@inject() @inject()
export default class CategoryService { export default class CategoryService {
private categoryRepository: CategoryRepository; private categoryRepository: CategoryRepository;
constructor(categoryRepository: CategoryRepository) { private courseRepository: CourseRepository;
private courseService: CourseService;
constructor(
categoryRepository: CategoryRepository,
courseRepository: CourseRepository,
courseService: CourseService
) {
this.categoryRepository = categoryRepository; this.categoryRepository = categoryRepository;
this.courseRepository = courseRepository;
this.courseService = courseService;
} }
/** /**
@ -94,7 +110,7 @@ export default class CategoryService {
* @returns Deleted category * @returns Deleted category
*/ */
public async deleteCategory(id: string | number): Promise<IResponse> { public async deleteCategory(id: string | number): Promise<IResponse> {
const data = await this.categoryRepository.delete(id); const data = await this.categoryRepository.getById(id);
if (!data) { if (!data) {
return { return {
@ -108,6 +124,10 @@ export default class CategoryService {
}; };
} }
const courses = await this.courseRepository.getByCategoryId(id);
await this.courseService.deleteAllFiles(courses);
await this.categoryRepository.delete(id);
return { return {
success: true, success: true,
status: HttpStatusEnum.OK, status: HttpStatusEnum.OK,

View File

@ -26,6 +26,7 @@ import UpdateCourseValidator from 'App/Validators/Course/UpdateCourseValidator';
import FetchCoursesValidator from 'App/Validators/Course/FetchCoursesValidator'; import FetchCoursesValidator from 'App/Validators/Course/FetchCoursesValidator';
import Course from 'App/Models/Course'; import Course from 'App/Models/Course';
import Drive from '@ioc:Adonis/Core/Drive'; import Drive from '@ioc:Adonis/Core/Drive';
import CourseHelper, { FileEntry } from 'App/Helpers/CourseHelper';
@inject() @inject()
export default class CourseService { export default class CourseService {
@ -720,6 +721,32 @@ export default class CourseService {
data: { count }, data: { count },
}; };
} }
/**
* This function will delete all associated course files on disk
*
* @param courses List of courses
*/
public async deleteAllFiles(courses: Course[]): Promise<void> {
/**
* Collect file names
*/
const images = courses.map(course => CourseHelper.getImageFileName(course)).filter(Boolean) as FileEntry[];
const videos = courses
.map(course => CourseHelper.getVideoFileNames(course))
.flat()
.filter(Boolean) as FileEntry[];
const materials = courses.map(course => CourseHelper.getMaterialFileNames(course)).flat();
/**
* Remove files from disk
*/
const promises = videos
.concat(images, materials)
.map(file => Drive.delete(`${file.path}${file.name.substring(file.name.lastIndexOf('/') + 1)}`));
await Promise.all(promises);
}
} }
new Ioc().make(CourseService); new Ioc().make(CourseService);

View File

@ -22,22 +22,48 @@ import Role from 'App/Models/Role';
import RoleRepository from 'App/Repositories/RoleRepository'; import RoleRepository from 'App/Repositories/RoleRepository';
import UserRepository from 'App/Repositories/UserRepository'; import UserRepository from 'App/Repositories/UserRepository';
/**
* Services
*/
import CourseService from './CourseService';
/** /**
* Validators * Validators
*/ */
import CreateUserValidator from 'App/Validators/User/CreateUserValidator'; import CreateUserValidator from 'App/Validators/User/CreateUserValidator';
import UpdateUserValidator from 'App/Validators/User/UpdateUserValidator'; import UpdateUserValidator from 'App/Validators/User/UpdateUserValidator';
/**
* Datatypes
*/
import RoleEnum from 'App/Datatypes/Enums/RoleEnum'; import RoleEnum from 'App/Datatypes/Enums/RoleEnum';
/**
* Helpers
*/
import RoleHelper from 'App/Helpers/RoleHelper';
import CourseRepository from 'App/Repositories/CourseRepository';
@inject() @inject()
export default class UserService { export default class UserService {
private userRepository: UserRepository; private userRepository: UserRepository;
private roleRepository: RoleRepository; private roleRepository: RoleRepository;
constructor(userRepository: UserRepository, roleRepository: RoleRepository) { private courseRepository: CourseRepository;
private courseService: CourseService;
constructor(
userRepository: UserRepository,
roleRepository: RoleRepository,
courseRepository: CourseRepository,
courseService: CourseService
) {
this.userRepository = userRepository; this.userRepository = userRepository;
this.roleRepository = roleRepository; this.roleRepository = roleRepository;
this.courseRepository = courseRepository;
this.courseService = courseService;
} }
/** /**
@ -213,6 +239,12 @@ export default class UserService {
} }
await ctx.bouncer.with('RolePolicy').authorize('manage', user.roles.map(r => r.slug) as [RoleEnum]); await ctx.bouncer.with('RolePolicy').authorize('manage', user.roles.map(r => r.slug) as [RoleEnum]);
if (RoleHelper.userContainRoles(user.roles, [RoleEnum.TEACHER, RoleEnum.ADMIN])) {
const courses = await this.courseRepository.getByTeacherId(id);
await this.courseService.deleteAllFiles(courses);
}
await this.userRepository.delete(id); await this.userRepository.delete(id);
return { return {