From 10f72f3090a56a26359bebfe112918c82ac0cdff Mon Sep 17 00:00:00 2001 From: Sergey Yarkov Date: Sun, 21 Nov 2021 20:51:26 +0300 Subject: [PATCH] feat: added colors to category model & added some helper funcs --- app/Helpers/ColorHelper.ts | 10 +++++++++ app/Models/Category.ts | 21 ++++++++++++++++++- app/Models/Course.ts | 19 +++++++++++++++++ app/Models/Lesson.ts | 2 +- app/Repositories/CategoryRepository.ts | 4 ++-- app/Repositories/CourseRepository.ts | 11 +++++++++- app/Services/MeService.ts | 2 +- app/Utils/index.ts | 4 ++++ database/factories/index.ts | 3 ++- database/migrations/1617351321869_colors.ts | 2 +- .../migrations/1627295886598_categories.ts | 1 + database/migrations/1627300211260_courses.ts | 3 ++- 12 files changed, 73 insertions(+), 9 deletions(-) create mode 100644 app/Helpers/ColorHelper.ts create mode 100644 app/Utils/index.ts diff --git a/app/Helpers/ColorHelper.ts b/app/Helpers/ColorHelper.ts new file mode 100644 index 0000000..f700d8e --- /dev/null +++ b/app/Helpers/ColorHelper.ts @@ -0,0 +1,10 @@ +import Color from 'App/Models/Color'; +import * as utils from 'App/Utils'; + +export default class ColorHelper { + public static async generateRandomColor(): Promise { + const colors = await Color.query(); + if (colors.length === 0) return null; + return colors[utils.generateRandomInt({ min: 0, max: colors.length - 1 })]; + } +} diff --git a/app/Models/Category.ts b/app/Models/Category.ts index 9254650..ee832c8 100644 --- a/app/Models/Category.ts +++ b/app/Models/Category.ts @@ -2,7 +2,9 @@ /* eslint-disable import/no-cycle */ import { DateTime } from 'luxon'; import { nanoid } from 'nanoid'; -import { BaseModel, beforeCreate, column } from '@ioc:Adonis/Lucid/Orm'; +import { BaseModel, beforeCreate, belongsTo, BelongsTo, column } from '@ioc:Adonis/Lucid/Orm'; +import ColorHelper from 'App/Helpers/ColorHelper'; +import Color from './Color'; export default class Category extends BaseModel { @column({ isPrimary: true }) @@ -14,6 +16,14 @@ export default class Category extends BaseModel { @column() public description: string; + @column({ serializeAs: null }) + public color_id: number | null; + + @belongsTo(() => Color, { + foreignKey: 'color_id', + }) + public color: BelongsTo; + @column.dateTime({ autoCreate: true, serializeAs: null }) public createdAt: DateTime; @@ -28,4 +38,13 @@ export default class Category extends BaseModel { public static assignCategoryId(category: Category) { category.id = nanoid(); } + + @beforeCreate() + public static async assignRandomColor(category: Category) { + const color = await ColorHelper.generateRandomColor(); + + if (color) { + category.color_id = color.id; + } + } } diff --git a/app/Models/Course.ts b/app/Models/Course.ts index adf5744..e8f0a9b 100644 --- a/app/Models/Course.ts +++ b/app/Models/Course.ts @@ -14,10 +14,12 @@ import { manyToMany, } from '@ioc:Adonis/Lucid/Orm'; import { attachment, AttachmentContract } from '@ioc:Adonis/Addons/AttachmentLite'; +import ColorHelper from 'App/Helpers/ColorHelper'; import Category from 'App/Models/Category'; import Lesson from 'App/Models/Lesson'; import User from 'App/Models/User'; import CourseStatusEnum from 'App/Datatypes/Enums/CourseStatusEnum'; +import Color from './Color'; export default class Course extends BaseModel { @column({ isPrimary: true }) @@ -38,6 +40,14 @@ export default class Course extends BaseModel { @column({ serializeAs: null }) public category_id: string; + @column({ serializeAs: null }) + public color_id: number | null; + + @belongsTo(() => Color, { + foreignKey: 'color_id', + }) + public color: BelongsTo; + @column() public status: CourseStatusEnum; @@ -86,6 +96,15 @@ export default class Course extends BaseModel { course.id = nanoid(); } + @beforeCreate() + public static async assignRandomColor(course: Course) { + const color = await ColorHelper.generateRandomColor(); + + if (color) { + course.color_id = color.id; + } + } + /** * Serialize the `$extras` object */ diff --git a/app/Models/Lesson.ts b/app/Models/Lesson.ts index bf21314..8c1cd5f 100644 --- a/app/Models/Lesson.ts +++ b/app/Models/Lesson.ts @@ -29,7 +29,7 @@ export default class Lesson extends BaseModel { public course: BelongsTo; @column({ serializeAs: null }) - public color_id: number; + public color_id: number | null; @belongsTo(() => Color, { foreignKey: 'color_id', diff --git a/app/Repositories/CategoryRepository.ts b/app/Repositories/CategoryRepository.ts index a4f3912..fe2c83a 100644 --- a/app/Repositories/CategoryRepository.ts +++ b/app/Repositories/CategoryRepository.ts @@ -21,7 +21,7 @@ export default class CategoryRepository { * @returns Array of categories */ public async getAll(): Promise { - const categories = await this.Category.query(); + const categories = await this.Category.query().preload('color'); return categories; } @@ -32,7 +32,7 @@ export default class CategoryRepository { * @returns Category or null */ public async getById(id: string | number): Promise { - const category = await this.Category.query().where('id', id).first(); + const category = await this.Category.query().preload('color').where('id', id).first(); return category; } diff --git a/app/Repositories/CourseRepository.ts b/app/Repositories/CourseRepository.ts index dff103d..a9fa990 100644 --- a/app/Repositories/CourseRepository.ts +++ b/app/Repositories/CourseRepository.ts @@ -61,7 +61,12 @@ export default class CourseRepository { query.andWhere('status', status); } - const courses = await query.preload('category').withCount('students').withCount('likes').withCount('lessons'); + const courses = await query + .preload('color') + .preload('category') + .withCount('students') + .withCount('likes') + .withCount('lessons'); return courses; } @@ -75,6 +80,7 @@ export default class CourseRepository { public async getById(id: string | number): Promise { const course = await this.Course.query() .preload('teacher') + .preload('color') .preload('category') .preload('lessons', q => q.preload('color')) .preload('students') @@ -192,6 +198,9 @@ export default class CourseRepository { course.teacher_id = data.teacher_id; course.category_id = data.category_id; + /** + * Attach image + */ if (data.image) { course.image = Attachment.fromFile(data.image); } diff --git a/app/Services/MeService.ts b/app/Services/MeService.ts index 1087db6..f10032e 100644 --- a/app/Services/MeService.ts +++ b/app/Services/MeService.ts @@ -45,7 +45,7 @@ export default class MeService { */ if (RoleHelper.userHasRoles(user.roles, [RoleEnum.STUDENT])) { await user.load('courses', q => { - q.preload('category'); + q.preload('category', loader => loader.preload('color')); q.withCount('students'); q.withCount('likes'); q.withCount('lessons'); diff --git a/app/Utils/index.ts b/app/Utils/index.ts new file mode 100644 index 0000000..9fc70e1 --- /dev/null +++ b/app/Utils/index.ts @@ -0,0 +1,4 @@ +// eslint-disable-next-line import/prefer-default-export +export const generateRandomInt = ({ min, max }: { min: number; max: number }): number => { + return Math.floor(Math.random() * (max - min + 1) + min); +}; diff --git a/database/factories/index.ts b/database/factories/index.ts index e0f4c04..18f2dc0 100644 --- a/database/factories/index.ts +++ b/database/factories/index.ts @@ -1,4 +1,5 @@ import Factory from '@ioc:Adonis/Lucid/Factory'; +import { string } from '@ioc:Adonis/Core/Helpers'; /** * Datatypes @@ -21,7 +22,7 @@ const makeFakeUser = (faker: Faker.FakerStatic, loginPrefix?: string) => { return { first_name: faker.name.firstName(), last_name: faker.name.lastName(), - login: `${loginPrefix || 'user'}${faker.datatype.number(10000)}`, + login: `${loginPrefix || 'user'}-${string.generateRandom(5)}`, email: faker.internet.exampleEmail(), password: '123456', }; diff --git a/database/migrations/1617351321869_colors.ts b/database/migrations/1617351321869_colors.ts index 6d315f1..b531583 100644 --- a/database/migrations/1617351321869_colors.ts +++ b/database/migrations/1617351321869_colors.ts @@ -11,7 +11,7 @@ export default class Colors extends BaseSchema { .enu('name', Object.keys(ColorEnum), { useNative: true, enumName: 'color_name_enum', - existingType: false, + existingType: true, schemaName: 'public', }) .notNullable(); diff --git a/database/migrations/1627295886598_categories.ts b/database/migrations/1627295886598_categories.ts index c5a02d2..4dd2864 100644 --- a/database/migrations/1627295886598_categories.ts +++ b/database/migrations/1627295886598_categories.ts @@ -8,6 +8,7 @@ export default class Categories extends BaseSchema { table.string('id', 21).primary(); table.string('title').notNullable(); table.string('description'); + table.integer('color_id').unsigned().references('colors.id'); table.timestamp('created_at', { useTz: true }); table.timestamp('updated_at', { useTz: true }); }); diff --git a/database/migrations/1627300211260_courses.ts b/database/migrations/1627300211260_courses.ts index 0e889e4..be8408e 100644 --- a/database/migrations/1627300211260_courses.ts +++ b/database/migrations/1627300211260_courses.ts @@ -16,11 +16,12 @@ export default class Courses extends BaseSchema { table.string('description').notNullable(); table.string('teacher_id', 21).unsigned().references('users.id').notNullable().onDelete('CASCADE'); table.string('category_id', 21).unsigned().references('categories.id').notNullable().onDelete('CASCADE'); + table.integer('color_id').unsigned().references('colors.id'); table .enu('status', Object.values(CourseStatusEnum), { useNative: true, enumName: 'course_status_enum', - existingType: false, + existingType: true, schemaName: 'public', }) .notNullable();