mirror of
https://github.com/sergeyyarkov/educt-server.git
synced 2026-10-11 18:29:15 +03:00
feat: images controller
This commit is contained in:
parent
18819024b2
commit
4cd2140e17
58
app/Controllers/Http/Api/v1/ImagesController.ts
Normal file
58
app/Controllers/Http/Api/v1/ImagesController.ts
Normal file
@ -0,0 +1,58 @@
|
||||
import { Exception, inject, Ioc } from '@adonisjs/core/build/standalone';
|
||||
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext';
|
||||
import ImageService from 'App/Services/ImageService';
|
||||
import CreateImageValidator from 'App/Validators/Image/CreateImageValidator';
|
||||
import BaseController from '../../BaseController';
|
||||
|
||||
@inject()
|
||||
export default class ImagesController extends BaseController {
|
||||
private imageService: ImageService;
|
||||
|
||||
constructor(imageService: ImageService) {
|
||||
super();
|
||||
this.imageService = imageService;
|
||||
}
|
||||
|
||||
public async list(ctx: HttpContextContract) {
|
||||
const result = await this.imageService.fetchImages();
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
public async show(ctx: HttpContextContract) {
|
||||
const result = await this.imageService.fetchImage(ctx.params.id);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
public async create(ctx: HttpContextContract) {
|
||||
const payload = await ctx.request.validate(CreateImageValidator);
|
||||
const result = await this.imageService.createImage(payload);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
public async delete(ctx: HttpContextContract) {
|
||||
const result = await this.imageService.deleteImage(ctx.params.id);
|
||||
|
||||
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(ImagesController);
|
||||
@ -49,7 +49,8 @@ export default class CourseRepository {
|
||||
.preload('teacher')
|
||||
.preload('category')
|
||||
.preload('lessons')
|
||||
.where('status', CourseStatusEnum.PUBLISHED);
|
||||
.preload('image');
|
||||
// .where('status', CourseStatusEnum.PUBLISHED);
|
||||
return courses;
|
||||
}
|
||||
|
||||
@ -65,8 +66,9 @@ export default class CourseRepository {
|
||||
.preload('category')
|
||||
.preload('lessons')
|
||||
.preload('students')
|
||||
.preload('image')
|
||||
.where('id', id)
|
||||
.where('status', CourseStatusEnum.PUBLISHED)
|
||||
// .where('status', CourseStatusEnum.PUBLISHED)
|
||||
.first();
|
||||
|
||||
return course;
|
||||
@ -154,6 +156,7 @@ export default class CourseRepository {
|
||||
* Create new course
|
||||
*/
|
||||
const course = await this.Course.create({
|
||||
bg_image_id: data.bg_image_id,
|
||||
title: data.title,
|
||||
description: data.description,
|
||||
status: CourseStatusEnum.DRAFT, // make course DRAFT before adding lessons
|
||||
|
||||
@ -9,6 +9,16 @@ export default class ImageRepository {
|
||||
this.Image = Image;
|
||||
}
|
||||
|
||||
public async getById(id: number): Promise<Image | null> {
|
||||
const image = await this.Image.query().where('id', id).first();
|
||||
return image;
|
||||
}
|
||||
|
||||
public async getAll(): Promise<Image[]> {
|
||||
const images = await this.Image.query();
|
||||
return images;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create image in cloudinary cloud
|
||||
*
|
||||
@ -28,13 +38,13 @@ export default class ImageRepository {
|
||||
* @param id Image id
|
||||
* @returns Result or null
|
||||
*/
|
||||
public async deleteFormCloudinaryCloud(id: number): Promise<any> {
|
||||
public async deleteFormCloudinaryCloud(id: number): Promise<Image | null> {
|
||||
const image = await this.Image.query().where('id', id).first();
|
||||
|
||||
if (image) {
|
||||
const result = await CloudinaryService.destroy(image.name);
|
||||
await CloudinaryService.destroy(image.name);
|
||||
await image.delete();
|
||||
return result;
|
||||
return image;
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
import { cuid } from '@ioc:Adonis/Core/Helpers';
|
||||
import { inject, Ioc } from '@adonisjs/core/build/standalone';
|
||||
import { AuthContract } from '@ioc:Adonis/Addons/Auth';
|
||||
|
||||
@ -283,12 +282,6 @@ export default class CourseService {
|
||||
/* Create course */
|
||||
const course = await this.courseRepository.create(data);
|
||||
|
||||
/* Create image if provided */
|
||||
if (data.background_image) {
|
||||
const bgImage = await this.imageRepository.createInCloudinaryCloud(data.background_image, cuid());
|
||||
await course.related('image').associate(bgImage);
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
status: StatusCodeEnum.CREATED,
|
||||
|
||||
85
app/Services/ImageService.ts
Normal file
85
app/Services/ImageService.ts
Normal file
@ -0,0 +1,85 @@
|
||||
import { inject, Ioc } from '@adonisjs/core/build/standalone';
|
||||
import { cuid } from '@ioc:Adonis/Core/Helpers';
|
||||
import StatusCodeEnum from 'App/Datatypes/Enums/StatusCodeEnum';
|
||||
import IResponse from 'App/Datatypes/Interfaces/IResponse';
|
||||
import ImageRepository from 'App/Repositories/ImageRepository';
|
||||
import CreateImageValidator from 'App/Validators/Image/CreateImageValidator';
|
||||
|
||||
@inject()
|
||||
export default class ImageService {
|
||||
private imageRepository: ImageRepository;
|
||||
|
||||
constructor(imageRepository: ImageRepository) {
|
||||
this.imageRepository = imageRepository;
|
||||
}
|
||||
|
||||
public async fetchImages(): Promise<IResponse> {
|
||||
const images = await this.imageRepository.getAll();
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: 'Fetched all images.',
|
||||
status: StatusCodeEnum.OK,
|
||||
data: images,
|
||||
};
|
||||
}
|
||||
|
||||
public async fetchImage(id: number): Promise<IResponse> {
|
||||
const image = await this.imageRepository.getById(id);
|
||||
|
||||
if (!image) {
|
||||
return {
|
||||
success: false,
|
||||
status: StatusCodeEnum.NOT_FOUND,
|
||||
message: 'Image not found.',
|
||||
data: {},
|
||||
error: {
|
||||
code: 'E_NOT_FOUND',
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: 'Fetched image.',
|
||||
status: StatusCodeEnum.OK,
|
||||
data: image,
|
||||
};
|
||||
}
|
||||
|
||||
public async createImage(data: CreateImageValidator['schema']['props']): Promise<IResponse> {
|
||||
const image = await this.imageRepository.createInCloudinaryCloud(data.image, cuid());
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: 'Image created.',
|
||||
status: StatusCodeEnum.OK,
|
||||
data: image,
|
||||
};
|
||||
}
|
||||
|
||||
public async deleteImage(id: number): Promise<IResponse> {
|
||||
const image = await this.imageRepository.deleteFormCloudinaryCloud(id);
|
||||
|
||||
if (!image) {
|
||||
return {
|
||||
success: false,
|
||||
status: StatusCodeEnum.NOT_FOUND,
|
||||
message: 'Image not found.',
|
||||
data: {},
|
||||
error: {
|
||||
code: 'E_NOT_FOUND',
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: 'Image deleted.',
|
||||
status: StatusCodeEnum.OK,
|
||||
data: image,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
new Ioc().make(ImageService);
|
||||
@ -7,10 +7,7 @@ export default class CreateCourseValidator {
|
||||
public schema = schema.create({
|
||||
title: schema.string(),
|
||||
description: schema.string(),
|
||||
background_image: schema.file.optional({
|
||||
size: '2mb',
|
||||
extnames: ['jpg', 'jpeg', 'png'],
|
||||
}),
|
||||
bg_image_id: schema.number.optional([rules.exists({ table: 'images', column: 'id' })]),
|
||||
teacher_id: schema.string({}, [rules.exists({ table: 'users', column: 'id' })]),
|
||||
category_id: schema.string({}, [rules.exists({ table: 'categories', column: 'id' })]),
|
||||
});
|
||||
|
||||
15
app/Validators/Image/CreateImageValidator.ts
Normal file
15
app/Validators/Image/CreateImageValidator.ts
Normal file
@ -0,0 +1,15 @@
|
||||
import { schema } from '@ioc:Adonis/Core/Validator';
|
||||
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext';
|
||||
|
||||
export default class CreateImageValidator {
|
||||
constructor(protected ctx: HttpContextContract) {}
|
||||
|
||||
public schema = schema.create({
|
||||
image: schema.file({
|
||||
size: '10mb',
|
||||
extnames: ['jpg', 'jpeg', 'png'],
|
||||
}),
|
||||
});
|
||||
|
||||
public messages = {};
|
||||
}
|
||||
@ -11,7 +11,7 @@ export default class Courses extends BaseSchema {
|
||||
public async up() {
|
||||
this.schema.createTable(this.tableName, table => {
|
||||
table.string('id', 21).primary();
|
||||
table.string('bg_image_id');
|
||||
table.integer('bg_image_id').unsigned().references('images.id').onDelete('SET NULL');
|
||||
table.string('title').notNullable();
|
||||
table.string('description').notNullable();
|
||||
table.string('teacher_id', 21).unsigned().references('users.id').onDelete('CASCADE');
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
/* eslint-disable class-methods-use-this */
|
||||
import BaseSeeder from '@ioc:Adonis/Lucid/Seeder';
|
||||
import Role from 'App/Models/Role';
|
||||
import User from 'App/Models/User';
|
||||
import { UserFactory } from 'Database/factories';
|
||||
|
||||
export default class UserSeeder extends BaseSeeder {
|
||||
@ -17,7 +18,13 @@ export default class UserSeeder extends BaseSeeder {
|
||||
/**
|
||||
* Administrator
|
||||
*/
|
||||
const userAdmin = await UserFactory.with('contacts').create();
|
||||
const userAdmin = await User.create({
|
||||
first_name: 'John',
|
||||
last_name: 'Doe',
|
||||
login: 'admin',
|
||||
password: '12345',
|
||||
email: 'example.email@mail.com',
|
||||
});
|
||||
await userAdmin.related('roles').attach([roles.admin.id]);
|
||||
|
||||
/**
|
||||
|
||||
8
routes/apis/v1/images.ts
Normal file
8
routes/apis/v1/images.ts
Normal file
@ -0,0 +1,8 @@
|
||||
import Route from '@ioc:Adonis/Core/Route';
|
||||
|
||||
Route.group(() => {
|
||||
Route.post('/', 'Api/v1/ImagesController.create').as('images.create');
|
||||
Route.delete('/:id', 'Api/v1/ImagesController.delete').as('images.delete');
|
||||
Route.get('/', 'Api/v1/ImagesController.list').as('images.list');
|
||||
Route.get('/:id', 'Api/v1/ImagesController.show').as('images.show');
|
||||
}).prefix('images');
|
||||
@ -48,6 +48,13 @@ Route.group(() => {
|
||||
*
|
||||
*/
|
||||
require('./lessons');
|
||||
|
||||
/**
|
||||
*
|
||||
* Images module
|
||||
*
|
||||
*/
|
||||
require('./images');
|
||||
}).middleware('auth');
|
||||
})
|
||||
.prefix('v1')
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user