mirror of
https://github.com/sergeyyarkov/educt-server.git
synced 2026-10-11 18:29:15 +03:00
feat: upd deps & image attaching to course
This commit is contained in:
parent
98a67f1744
commit
987fafd440
@ -23,7 +23,11 @@
|
|||||||
"Database": "database",
|
"Database": "database",
|
||||||
"Contracts": "contracts"
|
"Contracts": "contracts"
|
||||||
},
|
},
|
||||||
"preloads": ["./routes/index", "./start/kernel", "./start/event"],
|
"preloads": [
|
||||||
|
"./routes/index",
|
||||||
|
"./start/kernel",
|
||||||
|
"./start/event"
|
||||||
|
],
|
||||||
"providers": [
|
"providers": [
|
||||||
"./providers/AppProvider",
|
"./providers/AppProvider",
|
||||||
"./providers/CloudinaryProvider",
|
"./providers/CloudinaryProvider",
|
||||||
@ -32,9 +36,12 @@
|
|||||||
"@adonisjs/auth",
|
"@adonisjs/auth",
|
||||||
"@adonisjs/redis",
|
"@adonisjs/redis",
|
||||||
"@adonisjs/mail",
|
"@adonisjs/mail",
|
||||||
"@adonisjs/view"
|
"@adonisjs/view",
|
||||||
|
"@adonisjs/attachment-lite"
|
||||||
|
],
|
||||||
|
"aceProviders": [
|
||||||
|
"@adonisjs/repl"
|
||||||
],
|
],
|
||||||
"aceProviders": ["@adonisjs/repl"],
|
|
||||||
"metaFiles": [
|
"metaFiles": [
|
||||||
{
|
{
|
||||||
"pattern": "resources/views/**/*.edge",
|
"pattern": "resources/views/**/*.edge",
|
||||||
|
|||||||
1
.gitignore
vendored
1
.gitignore
vendored
@ -5,3 +5,4 @@ coverage
|
|||||||
.DS_STORE
|
.DS_STORE
|
||||||
.env
|
.env
|
||||||
tmp
|
tmp
|
||||||
|
uploads
|
||||||
|
|||||||
@ -1,39 +0,0 @@
|
|||||||
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 /assets/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);
|
|
||||||
@ -13,18 +13,18 @@ import {
|
|||||||
ManyToMany,
|
ManyToMany,
|
||||||
manyToMany,
|
manyToMany,
|
||||||
} from '@ioc:Adonis/Lucid/Orm';
|
} from '@ioc:Adonis/Lucid/Orm';
|
||||||
|
import { attachment, AttachmentContract } from '@ioc:Adonis/Addons/AttachmentLite';
|
||||||
import Category from 'App/Models/Category';
|
import Category from 'App/Models/Category';
|
||||||
import Lesson from 'App/Models/Lesson';
|
import Lesson from 'App/Models/Lesson';
|
||||||
import User from 'App/Models/User';
|
import User from 'App/Models/User';
|
||||||
import CourseStatusEnum from 'App/Datatypes/Enums/CourseStatusEnum';
|
import CourseStatusEnum from 'App/Datatypes/Enums/CourseStatusEnum';
|
||||||
// import Image from './Image';
|
|
||||||
|
|
||||||
export default class Course extends BaseModel {
|
export default class Course extends BaseModel {
|
||||||
@column({ isPrimary: true })
|
@column({ isPrimary: true })
|
||||||
public id: string;
|
public id: string;
|
||||||
|
|
||||||
@column()
|
@attachment({ folder: 'images/courses', preComputeUrl: true })
|
||||||
public bg_image_path: string;
|
public image: AttachmentContract | null;
|
||||||
|
|
||||||
@column()
|
@column()
|
||||||
public title: string;
|
public title: string;
|
||||||
@ -46,11 +46,6 @@ export default class Course extends BaseModel {
|
|||||||
})
|
})
|
||||||
public category: BelongsTo<typeof Category>;
|
public category: BelongsTo<typeof Category>;
|
||||||
|
|
||||||
// @belongsTo(() => Image, {
|
|
||||||
// foreignKey: 'bg_image_id',
|
|
||||||
// })
|
|
||||||
// public image: BelongsTo<typeof Image>;
|
|
||||||
|
|
||||||
@belongsTo(() => User, {
|
@belongsTo(() => User, {
|
||||||
foreignKey: 'teacher_id',
|
foreignKey: 'teacher_id',
|
||||||
})
|
})
|
||||||
|
|||||||
@ -1,8 +1,10 @@
|
|||||||
/* eslint-disable @typescript-eslint/naming-convention */
|
/* eslint-disable @typescript-eslint/naming-convention */
|
||||||
|
import Database from '@ioc:Adonis/Lucid/Database';
|
||||||
|
import { Attachment } from '@ioc:Adonis/Addons/AttachmentLite';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Datatypes
|
* Datatypes
|
||||||
*/
|
*/
|
||||||
import Database from '@ioc:Adonis/Lucid/Database';
|
|
||||||
import CourseStatusEnum from 'App/Datatypes/Enums/CourseStatusEnum';
|
import CourseStatusEnum from 'App/Datatypes/Enums/CourseStatusEnum';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -183,14 +185,19 @@ export default class CourseRepository {
|
|||||||
/**
|
/**
|
||||||
* Create new course
|
* Create new course
|
||||||
*/
|
*/
|
||||||
const course = await this.Course.create({
|
const course = new this.Course();
|
||||||
bg_image_path: data.image?.filePath,
|
|
||||||
title: data.title,
|
course.title = data.title;
|
||||||
description: data.description,
|
course.description = data.description;
|
||||||
status: data.status,
|
course.status = data.status;
|
||||||
teacher_id: data.teacher_id,
|
course.teacher_id = data.teacher_id;
|
||||||
category_id: data.category_id,
|
course.category_id = data.category_id;
|
||||||
});
|
|
||||||
|
if (data.image) {
|
||||||
|
course.image = Attachment.fromFile(data.image);
|
||||||
|
}
|
||||||
|
|
||||||
|
await course.save();
|
||||||
|
|
||||||
return course;
|
return course;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,47 +0,0 @@
|
|||||||
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);
|
|
||||||
@ -42,7 +42,7 @@ const driveConfig: DriveConfig = {
|
|||||||
*/
|
*/
|
||||||
local: {
|
local: {
|
||||||
driver: 'local',
|
driver: 'local',
|
||||||
visibility: 'public',
|
visibility: 'private',
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
@ -53,7 +53,7 @@ const driveConfig: DriveConfig = {
|
|||||||
| files.
|
| files.
|
||||||
|
|
|
|
||||||
*/
|
*/
|
||||||
root: Application.tmpPath('uploads'),
|
root: Application.makePath('uploads'),
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
|
|||||||
@ -16,33 +16,27 @@ import LessonContent from 'App/Models/LessonContent';
|
|||||||
import Role from 'App/Models/Role';
|
import Role from 'App/Models/Role';
|
||||||
import User from 'App/Models/User';
|
import User from 'App/Models/User';
|
||||||
|
|
||||||
|
const makeFakeUser = (faker: Faker.FakerStatic) => {
|
||||||
|
return {
|
||||||
|
first_name: faker.name.firstName(),
|
||||||
|
last_name: faker.name.lastName(),
|
||||||
|
login: `${faker.lorem.word(12)}${faker.datatype.number(100)}`,
|
||||||
|
email: faker.internet.exampleEmail(),
|
||||||
|
password: '123456',
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
export const ContactFactory = Factory.define(Contact, ({ faker }) => {
|
export const ContactFactory = Factory.define(Contact, ({ faker }) => {
|
||||||
return {
|
return {
|
||||||
phone_number: faker.phone.phoneNumber(),
|
phone_number: faker.phone.phoneNumber(),
|
||||||
};
|
};
|
||||||
}).build();
|
}).build();
|
||||||
|
|
||||||
export const UserFactory = Factory.define(User, ({ faker }) => {
|
export const UserFactory = Factory.define(User, ({ faker }) => makeFakeUser(faker))
|
||||||
return {
|
|
||||||
first_name: faker.name.firstName(),
|
|
||||||
last_name: faker.name.lastName(),
|
|
||||||
login: `${faker.lorem.word(12)}${faker.datatype.number(100)}`,
|
|
||||||
email: faker.internet.exampleEmail(),
|
|
||||||
password: '123456',
|
|
||||||
};
|
|
||||||
})
|
|
||||||
.relation('contacts', () => ContactFactory)
|
.relation('contacts', () => ContactFactory)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
export const TeacherFactory = Factory.define(User, ({ faker }) => {
|
export const TeacherFactory = Factory.define(User, ({ faker }) => makeFakeUser(faker))
|
||||||
return {
|
|
||||||
first_name: faker.name.firstName(),
|
|
||||||
last_name: faker.name.lastName(),
|
|
||||||
login: `${faker.lorem.word(12)}${faker.datatype.number(100)}`,
|
|
||||||
email: faker.internet.exampleEmail(),
|
|
||||||
password: '123456',
|
|
||||||
};
|
|
||||||
})
|
|
||||||
.relation('contacts', () => ContactFactory)
|
.relation('contacts', () => ContactFactory)
|
||||||
.after('create', async (_, user: User) => {
|
.after('create', async (_, user: User) => {
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -11,11 +11,11 @@ export default class Courses extends BaseSchema {
|
|||||||
public async up() {
|
public async up() {
|
||||||
this.schema.createTable(this.tableName, table => {
|
this.schema.createTable(this.tableName, table => {
|
||||||
table.string('id', 21).primary();
|
table.string('id', 21).primary();
|
||||||
table.string('bg_image_path');
|
table.json('image');
|
||||||
table.string('title').notNullable();
|
table.string('title').notNullable();
|
||||||
table.string('description').notNullable();
|
table.string('description').notNullable();
|
||||||
table.string('teacher_id', 21).unsigned().references('users.id').onDelete('CASCADE');
|
table.string('teacher_id', 21).unsigned().references('users.id').notNullable().onDelete('CASCADE');
|
||||||
table.string('category_id', 21).unsigned().references('categories.id').onDelete('CASCADE');
|
table.string('category_id', 21).unsigned().references('categories.id').notNullable().onDelete('CASCADE');
|
||||||
table
|
table
|
||||||
.enu('status', Object.values(CourseStatusEnum), {
|
.enu('status', Object.values(CourseStatusEnum), {
|
||||||
useNative: true,
|
useNative: true,
|
||||||
|
|||||||
545
package-lock.json
generated
545
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
13
package.json
13
package.json
@ -32,14 +32,15 @@
|
|||||||
"youch-terminal": "^1.1.1"
|
"youch-terminal": "^1.1.1"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@adonisjs/auth": "^8.0.9",
|
"@adonisjs/attachment-lite": "^1.0.1",
|
||||||
"@adonisjs/core": "^5.3.2",
|
"@adonisjs/auth": "^8.0.10",
|
||||||
"@adonisjs/drive": "^2.0.6",
|
"@adonisjs/core": "^5.4.0",
|
||||||
"@adonisjs/lucid": "^16.0.2",
|
"@adonisjs/drive": "^2.0.7",
|
||||||
|
"@adonisjs/lucid": "^16.2.1",
|
||||||
"@adonisjs/mail": "^7.2.4",
|
"@adonisjs/mail": "^7.2.4",
|
||||||
"@adonisjs/redis": "^7.0.9",
|
"@adonisjs/redis": "^7.0.9",
|
||||||
"@adonisjs/repl": "^3.1.6",
|
"@adonisjs/repl": "^3.1.7",
|
||||||
"@adonisjs/view": "^6.1.0",
|
"@adonisjs/view": "^6.1.1",
|
||||||
"cloudinary": "^1.26.3",
|
"cloudinary": "^1.26.3",
|
||||||
"luxon": "^1.28.0",
|
"luxon": "^1.28.0",
|
||||||
"nanoid": "^3.1.25",
|
"nanoid": "^3.1.25",
|
||||||
|
|||||||
@ -1,10 +0,0 @@
|
|||||||
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');
|
|
||||||
@ -26,9 +26,4 @@ Route.group(() => {
|
|||||||
* Api routes
|
* Api routes
|
||||||
*/
|
*/
|
||||||
require('./api');
|
require('./api');
|
||||||
|
|
||||||
/**
|
|
||||||
* Serve assets
|
|
||||||
*/
|
|
||||||
require('./assets');
|
|
||||||
});
|
});
|
||||||
|
|||||||
@ -33,7 +33,8 @@
|
|||||||
"@adonisjs/auth",
|
"@adonisjs/auth",
|
||||||
"@adonisjs/redis",
|
"@adonisjs/redis",
|
||||||
"@adonisjs/mail",
|
"@adonisjs/mail",
|
||||||
"@adonisjs/view"
|
"@adonisjs/view",
|
||||||
|
"@adonisjs/attachment-lite"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user