feat: images controller

This commit is contained in:
Sergey Yarkov 2021-08-15 19:44:13 +03:00
parent 18819024b2
commit 4cd2140e17
12 changed files with 201 additions and 18 deletions

View 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);

View File

@ -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

View File

@ -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;

View File

@ -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,

View 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);

View File

@ -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' })]),
});

View 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 = {};
}

View File

@ -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');

View File

@ -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
View 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');

View File

@ -48,6 +48,13 @@ Route.group(() => {
*
*/
require('./lessons');
/**
*
* Images module
*
*/
require('./images');
}).middleware('auth');
})
.prefix('v1')