mirror of
https://github.com/sergeyyarkov/educt-server.git
synced 2026-10-11 18:29:15 +03:00
feat: assets controller & serve course image
This commit is contained in:
parent
30fdfa08b6
commit
ee25d495e1
39
app/Controllers/Http/Api/AssetsController.ts
Normal file
39
app/Controllers/Http/Api/AssetsController.ts
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext';
|
||||||
|
import { Exception, inject, Ioc } from '@adonisjs/core/build/standalone';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Services
|
||||||
|
*/
|
||||||
|
import AssetsService from 'App/Services/AssetsService';
|
||||||
|
|
||||||
|
import BaseController from '../BaseController';
|
||||||
|
|
||||||
|
@inject()
|
||||||
|
export default class AssetsController extends BaseController {
|
||||||
|
private assetsService: AssetsService;
|
||||||
|
|
||||||
|
constructor(assetsService: AssetsService) {
|
||||||
|
super();
|
||||||
|
this.assetsService = assetsService;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send background image of course
|
||||||
|
* GET /media/images/courses/:fileName
|
||||||
|
*/
|
||||||
|
public async serveCourseImage(ctx: HttpContextContract) {
|
||||||
|
const result = await this.assetsService.getCourseImagePath(ctx.params.fileName);
|
||||||
|
|
||||||
|
if (typeof result !== 'string') {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.sendFile(ctx, result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
new Ioc().make(AssetsController);
|
||||||
@ -12,4 +12,8 @@ export default class BaseController {
|
|||||||
|
|
||||||
return ctx.response.status(response.status).send(response);
|
return ctx.response.status(response.status).send(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public sendFile(ctx: HttpContextContract, path: string) {
|
||||||
|
return ctx.response.download(path);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,7 +5,7 @@ export default class Image extends BaseModel {
|
|||||||
@column({ isPrimary: true })
|
@column({ isPrimary: true })
|
||||||
public id: number;
|
public id: number;
|
||||||
|
|
||||||
@column()
|
@column({ serializeAs: null })
|
||||||
public path: string;
|
public path: string;
|
||||||
|
|
||||||
@column()
|
@column()
|
||||||
|
|||||||
@ -209,9 +209,11 @@ export default class CourseRepository {
|
|||||||
*/
|
*/
|
||||||
public async delete(id: string | number): Promise<Course | null> {
|
public async delete(id: string | number): Promise<Course | null> {
|
||||||
const course = await this.Course.query()
|
const course = await this.Course.query()
|
||||||
.preload('teacher')
|
|
||||||
.preload('category')
|
.preload('category')
|
||||||
.preload('lessons')
|
.preload('image')
|
||||||
|
.withCount('students')
|
||||||
|
.withCount('likes')
|
||||||
|
.withCount('lessons')
|
||||||
.where('id', id)
|
.where('id', id)
|
||||||
.first();
|
.first();
|
||||||
|
|
||||||
|
|||||||
@ -15,14 +15,26 @@ export default class ImageRepository {
|
|||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async getByFileName(name: string): Promise<Image | null> {
|
||||||
|
const image = await this.Image.query().where('name', name).first();
|
||||||
|
return image;
|
||||||
|
}
|
||||||
|
|
||||||
public async getAll(): Promise<Image[]> {
|
public async getAll(): Promise<Image[]> {
|
||||||
const images = await this.Image.query();
|
const images = await this.Image.query();
|
||||||
return images;
|
return images;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async create(file: MultipartFileContract): Promise<Image> {
|
public async create(file: MultipartFileContract): Promise<Image> {
|
||||||
await file.moveToDisk('./images');
|
/**
|
||||||
const image = await this.Image.create({ name: file.clientName, path: file.filePath, ext: file.extname });
|
* Save image to disk
|
||||||
|
*/
|
||||||
|
await file.moveToDisk('images/courses');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save image to database
|
||||||
|
*/
|
||||||
|
const image = await this.Image.create({ name: file.fileName, path: file.filePath, ext: file.extname });
|
||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -30,7 +42,14 @@ export default class ImageRepository {
|
|||||||
const image = await this.Image.query().where('id', id).first();
|
const image = await this.Image.query().where('id', id).first();
|
||||||
|
|
||||||
if (image) {
|
if (image) {
|
||||||
|
/**
|
||||||
|
* Delete from drive
|
||||||
|
*/
|
||||||
await Drive.delete(image.path);
|
await Drive.delete(image.path);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete from database
|
||||||
|
*/
|
||||||
await image.delete();
|
await image.delete();
|
||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
|
|||||||
47
app/Services/AssetsService.ts
Normal file
47
app/Services/AssetsService.ts
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
import { inject, Ioc } from '@adonisjs/core/build/standalone';
|
||||||
|
import Application from '@ioc:Adonis/Core/Application';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Datatypes
|
||||||
|
*/
|
||||||
|
import IResponse from 'App/Datatypes/Interfaces/IResponse';
|
||||||
|
import HttpStatusEnum from 'App/Datatypes/Enums/HttpStatusEnum';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reposirories
|
||||||
|
*/
|
||||||
|
import ImageRepository from 'App/Repositories/ImageRepository';
|
||||||
|
|
||||||
|
@inject()
|
||||||
|
export default class AssetsService {
|
||||||
|
private imageRepository: ImageRepository;
|
||||||
|
|
||||||
|
constructor(imageRepository: ImageRepository) {
|
||||||
|
this.imageRepository = imageRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param name Image name
|
||||||
|
* @returns Pathname
|
||||||
|
*/
|
||||||
|
public async getCourseImagePath(name: string): Promise<IResponse | string> {
|
||||||
|
const image = await this.imageRepository.getByFileName(name);
|
||||||
|
|
||||||
|
if (!image) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
status: HttpStatusEnum.NOT_FOUND,
|
||||||
|
message: 'Image not found.',
|
||||||
|
data: {},
|
||||||
|
error: {
|
||||||
|
code: 'E_NOT_FOUND',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return Application.tmpPath(`uploads/images/courses/${image.name}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
new Ioc().make(AssetsService);
|
||||||
@ -2,7 +2,15 @@
|
|||||||
import Route from '@ioc:Adonis/Core/Route';
|
import Route from '@ioc:Adonis/Core/Route';
|
||||||
|
|
||||||
Route.group(() => {
|
Route.group(() => {
|
||||||
|
/**
|
||||||
|
* v1
|
||||||
|
*/
|
||||||
require('./apis/v1/index');
|
require('./apis/v1/index');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assets routes
|
||||||
|
*/
|
||||||
|
require('./apis/assets/index');
|
||||||
})
|
})
|
||||||
.prefix('api')
|
.prefix('api')
|
||||||
.as('api');
|
.as('api');
|
||||||
|
|||||||
10
routes/apis/assets/index.ts
Normal file
10
routes/apis/assets/index.ts
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
import Route from '@ioc:Adonis/Core/Route';
|
||||||
|
|
||||||
|
Route.group(() => {
|
||||||
|
/**
|
||||||
|
* Serve background image for course
|
||||||
|
*/
|
||||||
|
Route.get('/images/courses/:fileName', 'Api/AssetsController.serveCourseImage').as('serve.course.image');
|
||||||
|
})
|
||||||
|
.prefix('assets')
|
||||||
|
.as('assets');
|
||||||
@ -22,5 +22,8 @@ import Route from '@ioc:Adonis/Core/Route';
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
Route.group(() => {
|
Route.group(() => {
|
||||||
|
/**
|
||||||
|
* Api routes
|
||||||
|
*/
|
||||||
require('./api');
|
require('./api');
|
||||||
});
|
});
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user