chore: compelete danak category service
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import { Logger } from "@nestjs/common";
|
||||
import { hash } from "bcrypt";
|
||||
import { DataSource, DeepPartial } from "typeorm";
|
||||
|
||||
import { Role } from "../../src/modules/users/entities/role.entity";
|
||||
@@ -23,7 +24,9 @@ export const seedAdmin = async (dataSource: DataSource, logger: Logger) => {
|
||||
const adminRole = await roleRepo.findOneBy({ name: RoleEnum.ADMIN });
|
||||
if (!adminRole) throw new Error("Role not found");
|
||||
|
||||
const admin = userRepo.create({ ...defaultAdmin, role: adminRole });
|
||||
const hashedPassword = await hash(defaultAdmin.password!, 10);
|
||||
|
||||
const admin = userRepo.create({ ...defaultAdmin, password: hashedPassword, role: adminRole });
|
||||
await userRepo.save(admin);
|
||||
logger.log("admin created successfully");
|
||||
} catch (error) {
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
import { ApiPropertyOptional } from "@nestjs/swagger";
|
||||
import { Type } from "class-transformer";
|
||||
import { IsNotEmpty, IsNumber, IsOptional, Max, Min } from "class-validator";
|
||||
|
||||
export class PaginationDto {
|
||||
@IsOptional()
|
||||
@IsNotEmpty()
|
||||
@IsNumber()
|
||||
@Min(1)
|
||||
@Type(() => Number)
|
||||
@ApiPropertyOptional({ type: "number", required: false })
|
||||
page?: number;
|
||||
|
||||
@IsOptional()
|
||||
@IsNotEmpty()
|
||||
@IsNumber()
|
||||
@Min(1)
|
||||
@Max(50)
|
||||
@Type(() => Number)
|
||||
@ApiPropertyOptional({ type: "number", required: false })
|
||||
limit?: number;
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
import { ApiProperty } from "@nestjs/swagger";
|
||||
import { IsNotEmpty, IsUUID } from "class-validator";
|
||||
|
||||
import { CommonMessage } from "../enums/message.enum";
|
||||
|
||||
export class ParamDto {
|
||||
@IsNotEmpty({ message: CommonMessage.ID_REQUIRED })
|
||||
@IsUUID("4", { message: CommonMessage.ID_SHOULD_BE_UUID })
|
||||
@ApiProperty({ description: "Id of the entity", example: "8b1e8b1e-8b1e-8b1e-8b1e-8b1e8b1e8b1e" })
|
||||
id: string;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
import { applyDecorators } from "@nestjs/common";
|
||||
import { ApiQuery } from "@nestjs/swagger";
|
||||
|
||||
export function Pagination() {
|
||||
return applyDecorators(
|
||||
ApiQuery({ name: "page", example: 1, required: false, type: "number" }),
|
||||
ApiQuery({ name: "limit", example: 10, required: false, type: "number" }),
|
||||
);
|
||||
}
|
||||
@@ -68,6 +68,8 @@ export const enum CommonMessage {
|
||||
VALID_FOR_CHOOSE = "معتبر برای انتخاب",
|
||||
UPDATE_SUCCESS = "با موفقیت به روز رسانی شد",
|
||||
CREATED = "با موفقیت ایجاد شد",
|
||||
ID_REQUIRED = "شناسه مورد نیاز است",
|
||||
ID_SHOULD_BE_UUID = "شناسه باید یک یو یو آی دی باشد",
|
||||
}
|
||||
|
||||
export const enum CategoryMessage {
|
||||
@@ -79,6 +81,40 @@ export const enum CategoryMessage {
|
||||
PARENT_ID_REQUIRED = "شناسه والد دسته بندی مورد نیاز است",
|
||||
PARENT_ID_SHOULD_BE_UUID = "شناسه والد باید یک یو یو آی دی باشد",
|
||||
TITLE_EXIST = "دسته بندی با این نام قبلا ثبت شده است",
|
||||
IS_ACTIVE_REQUIRED = "وضعیت دسته بندی مورد نیاز است",
|
||||
CAT_ID_SHOULD_BE_UUID = "شناسه دسته بندی باید یک یو یو آی دی باشد",
|
||||
CAT_ID_NOT_EMPTY = "شناسه دسته بندی نمیتواند خالی باشد",
|
||||
CATEGORY_NOT_EXIST = "دسته بندی مورد نظر یافت نشد",
|
||||
IS_ACTIVE_SHOULD_BE_BOOLEAN = "وضعیت دسته بندی باید یک بولین باشد",
|
||||
SEARCH_QUERY_STRING = "رشته جستجو باید یک رشته باشد",
|
||||
}
|
||||
|
||||
export const enum ServiceMessage {
|
||||
NAME_REQUIRED = "نام سرویس مورد نیاز است",
|
||||
NAME_STRING = "نام سرویس باید یک رشته باشد",
|
||||
NAME_LENGTH = "نام سرویس باید بین ۳ تا ۵۰ کاراکتر باشد",
|
||||
DESCRIPTION_REQUIRED = "توضیحات سرویس مورد نیاز است",
|
||||
DESCRIPTION_STRING = "توضیحات سرویس باید یک رشته باشد",
|
||||
AUTHOR_REQUIRED = "نویسنده سرویس مورد نیاز است",
|
||||
AUTHOR_STRING = "نویسنده سرویس باید یک رشته باشد",
|
||||
CREATE_DATE_REQUIRED = "تاریخ ایجاد سرویس مورد نیاز است",
|
||||
CREATE_DATE_STRING = "تاریخ ایجاد سرویس باید یک رشته باشد",
|
||||
USER_COUNT_REQUIRED = "تعداد کاربران سرویس مورد نیاز است",
|
||||
USER_COUNT_INT = "تعداد کاربران سرویس باید یک عدد صحیح باشد",
|
||||
SERVICE_LANGUAGE_REQUIRED = "زبان سرویس مورد نیاز است",
|
||||
SOFTWARE_LANGUAGE_REQUIRED = "زبان نرم افزار سرویس مورد نیاز است",
|
||||
SOFTWARE_LANGUAGE_STRING = "زبان نرم افزار سرویس باید یک رشته باشد",
|
||||
META_DESCRIPTION_REQUIRED = "متا توضیحات سرویس مورد نیاز است",
|
||||
LINK_REQUIRED = "لینک سرویس مورد نیاز است",
|
||||
IS_DANAK_SUGGEST_REQUIRED = "آیا سرویس پیشنهادی داناک است؟",
|
||||
IS_DANAK_SUGGEST_BOOLEAN = "وضعیت سرویس پیشنهادی داناک باید یک بولین باشد",
|
||||
ICON_REQUIRED = "آیکون سرویس مورد نیاز است",
|
||||
LINK_SHOULD_BE_URL = "لینک باید یک آدرس یو آر ال باشد",
|
||||
ICON_SHOULD_BE_URL = "آیکون باید یک آدرس یو آر ال باشد",
|
||||
IMAGES_REQUIRED = "تصاویر سرویس مورد نیاز است",
|
||||
DESCRIPTION_LENGTH = "توضیحات سرویس باید بین ۱۰ تا ۵۰۰ کاراکتر باشد",
|
||||
SOFTWARE_LANGUAGE_LENGTH = "زبان نرم افزار سرویس باید بین ۳ تا ۱۵۰ کاراکتر باشد",
|
||||
AUTHOR_LENGTH = "نویسنده سرویس باید بین 3 تا 100 کاراکتر باشد",
|
||||
}
|
||||
|
||||
export const enum AnnouncementMessage {
|
||||
|
||||
@@ -19,7 +19,7 @@ export class RoleGuard implements CanActivate {
|
||||
|
||||
if (!user) throw new ForbiddenException(AuthMessage.UNAUTHORIZED_ACCESS);
|
||||
|
||||
const hasRequiredRole = requiredRole.includes(user.role.name);
|
||||
const hasRequiredRole = requiredRole.includes(user.role as unknown as RoleEnum);
|
||||
if (!hasRequiredRole) throw new ForbiddenException(AuthMessage.UNAUTHORIZED_ACCESS);
|
||||
|
||||
return true;
|
||||
|
||||
@@ -98,11 +98,14 @@ export class AuthService {
|
||||
}
|
||||
|
||||
//****************** */
|
||||
async requestLoginOtp(requestOtpDto: RequestOtpDto) {
|
||||
async requestLoginOtp(requestOtpDto: RequestOtpDto, isAdmin: boolean = false) {
|
||||
const { phone } = requestOtpDto;
|
||||
const user = await this.usersService.findOneWithPhone(phone);
|
||||
if (!user) throw new BadRequestException(AuthMessage.PHONE_NOT_FOUND);
|
||||
|
||||
//check the if the method call is from admin or not
|
||||
if (isAdmin && user.role.name !== RoleEnum.ADMIN) throw new BadRequestException(AuthMessage.NOT_ADMIN);
|
||||
|
||||
const existCode = await this.otpService.checkExistOtp(phone, "LOGIN");
|
||||
if (existCode) {
|
||||
return {
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
import { ApiPropertyOptional } from "@nestjs/swagger";
|
||||
import { Type } from "class-transformer";
|
||||
import { IsOptional, IsString, IsUUID } from "class-validator";
|
||||
|
||||
import { PaginationDto } from "../../../common/DTO/pagination.dto";
|
||||
import { CategoryMessage } from "../../../common/enums/message.enum";
|
||||
|
||||
export class CategorySearchQueryDto {
|
||||
@IsOptional()
|
||||
@IsUUID("4", { message: CategoryMessage.PARENT_ID_SHOULD_BE_UUID })
|
||||
@ApiPropertyOptional({ description: "Parent category id", example: "8b1e8b1e-8b1e-8b1e-8b1e-8b1e8b1e8b1e" })
|
||||
parentId?: string;
|
||||
}
|
||||
|
||||
export class CategoryListSearchQueryDto extends PaginationDto {
|
||||
@IsOptional()
|
||||
@Type(() => Number)
|
||||
// @IsBoolean({ message: CategoryMessage.IS_ACTIVE_SHOULD_BE_BOOLEAN })
|
||||
@ApiPropertyOptional({ description: "Category status", example: 1 })
|
||||
isActive?: number;
|
||||
|
||||
@IsOptional()
|
||||
@IsString({ message: CategoryMessage.SEARCH_QUERY_STRING })
|
||||
@ApiPropertyOptional({ description: "Search query", example: "search query" })
|
||||
q?: string;
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
import { ApiProperty, ApiPropertyOptional } from "@nestjs/swagger";
|
||||
import { IsNotEmpty, IsOptional, IsString, IsUUID, IsUrl, Length } from "class-validator";
|
||||
import { IsBoolean, IsNotEmpty, IsOptional, IsString, IsUUID, IsUrl, Length } from "class-validator";
|
||||
|
||||
import { CategoryMessage } from "../../../common/enums/message.enum";
|
||||
|
||||
@@ -15,6 +15,11 @@ export class CreateCategoryDto {
|
||||
@ApiProperty({ description: "Category icon", example: "https://example.com/icon.png" })
|
||||
icon: string;
|
||||
|
||||
@IsNotEmpty({ message: CategoryMessage.IS_ACTIVE_REQUIRED })
|
||||
@IsBoolean({ message: CategoryMessage.IS_ACTIVE_REQUIRED })
|
||||
@ApiProperty({ description: "Category status", example: true })
|
||||
isActive: boolean;
|
||||
|
||||
@IsOptional()
|
||||
@IsNotEmpty({ message: CategoryMessage.PARENT_ID_REQUIRED })
|
||||
@IsUUID("4", { message: CategoryMessage.PARENT_ID_SHOULD_BE_UUID })
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
import { ApiProperty } from "@nestjs/swagger";
|
||||
import { IsBoolean, IsDateString, IsEnum, IsInt, IsNotEmpty, IsString, IsUUID, IsUrl, Length, MaxLength } from "class-validator";
|
||||
|
||||
import { CategoryMessage, ServiceMessage } from "../../../common/enums/message.enum";
|
||||
import { ServicesLanguage } from "../enums/services-language.enum";
|
||||
|
||||
export class CreateServiceDto {
|
||||
@IsNotEmpty({ message: CategoryMessage.CAT_ID_NOT_EMPTY })
|
||||
@IsUUID("4", { message: CategoryMessage.CAT_ID_SHOULD_BE_UUID })
|
||||
@ApiProperty({ description: "The category id of the service", example: "00000000-0000-0000-0000-000000000000" })
|
||||
categoryId: string;
|
||||
|
||||
@IsNotEmpty({ message: ServiceMessage.NAME_REQUIRED })
|
||||
@IsString({ message: ServiceMessage.NAME_STRING })
|
||||
@Length(3, 50, { message: ServiceMessage.NAME_LENGTH })
|
||||
@ApiProperty({ description: "The name of the service", example: "Service Name" })
|
||||
name: string;
|
||||
|
||||
@IsNotEmpty({ message: ServiceMessage.DESCRIPTION_REQUIRED })
|
||||
@IsString({ message: ServiceMessage.DESCRIPTION_STRING })
|
||||
@Length(10, 500, { message: ServiceMessage.DESCRIPTION_LENGTH })
|
||||
@ApiProperty({ description: "The description of the service", example: "Service Description" })
|
||||
description: string;
|
||||
|
||||
@IsNotEmpty({ message: ServiceMessage.AUTHOR_REQUIRED })
|
||||
@IsString({ message: ServiceMessage.AUTHOR_STRING })
|
||||
@Length(3, 100, { message: ServiceMessage.AUTHOR_LENGTH })
|
||||
@ApiProperty({ description: "The author of the service", example: "danak corp" })
|
||||
author: string;
|
||||
|
||||
@IsNotEmpty({ message: ServiceMessage.CREATE_DATE_REQUIRED })
|
||||
@IsDateString({}, { message: ServiceMessage.CREATE_DATE_STRING })
|
||||
@ApiProperty({ description: "The create date of the service", example: "2021-08-01T00:00:00.000Z" })
|
||||
createDate: Date;
|
||||
|
||||
@IsNotEmpty({ message: ServiceMessage.USER_COUNT_REQUIRED })
|
||||
@IsInt({ message: ServiceMessage.USER_COUNT_INT })
|
||||
@ApiProperty({ description: "The user count of the service", example: 1000 })
|
||||
userCount: number;
|
||||
|
||||
@IsNotEmpty({ message: ServiceMessage.SERVICE_LANGUAGE_REQUIRED })
|
||||
@IsEnum(ServicesLanguage)
|
||||
@ApiProperty({ enum: ServicesLanguage, description: "The language of the service", example: ServicesLanguage.ENGLISH })
|
||||
serviceLanguage: ServicesLanguage;
|
||||
|
||||
@IsNotEmpty({ message: ServiceMessage.SOFTWARE_LANGUAGE_REQUIRED })
|
||||
@IsString({ message: ServiceMessage.SOFTWARE_LANGUAGE_STRING })
|
||||
@MaxLength(150, { message: ServiceMessage.SOFTWARE_LANGUAGE_LENGTH })
|
||||
@ApiProperty({ description: "The software language of the service", example: "Python" })
|
||||
softwareLanguage: string;
|
||||
|
||||
@IsNotEmpty({ message: ServiceMessage.META_DESCRIPTION_REQUIRED })
|
||||
@IsString({ message: ServiceMessage.META_DESCRIPTION_REQUIRED })
|
||||
@ApiProperty({ description: "The meta description of the service", example: "Service Meta Description" })
|
||||
metaDescription: string;
|
||||
|
||||
@IsNotEmpty({ message: ServiceMessage.LINK_REQUIRED })
|
||||
@IsUrl({ protocols: ["http", "https"], require_protocol: true }, { message: ServiceMessage.LINK_SHOULD_BE_URL })
|
||||
@ApiProperty({ description: "The status of the service", example: "https://example.com" })
|
||||
link: string;
|
||||
|
||||
@IsNotEmpty({ message: ServiceMessage.IS_DANAK_SUGGEST_REQUIRED })
|
||||
@IsBoolean({ message: ServiceMessage.IS_DANAK_SUGGEST_BOOLEAN })
|
||||
@ApiProperty({ description: "Is the service a Danak suggest?", example: true })
|
||||
isDanakSuggest: boolean;
|
||||
|
||||
@IsNotEmpty({ message: ServiceMessage.ICON_REQUIRED })
|
||||
@IsUrl({ protocols: ["http", "https"], require_protocol: true }, { message: ServiceMessage.ICON_SHOULD_BE_URL })
|
||||
@ApiProperty({ description: "The icon url of the service", example: "https://example.com/icon.png" })
|
||||
icon: string;
|
||||
|
||||
@IsNotEmpty({ message: ServiceMessage.IMAGES_REQUIRED })
|
||||
@IsString({ each: true })
|
||||
@ApiProperty({ description: "The images of the service", example: ["https://example.com/image1.png", "https://example.com/image2.png"] })
|
||||
images: string[];
|
||||
}
|
||||
@@ -1,18 +1,61 @@
|
||||
import { Body, Controller, Post } from "@nestjs/common";
|
||||
import { Body, Controller, Get, HttpCode, HttpStatus, Param, Post, Query } from "@nestjs/common";
|
||||
import { ApiOperation, ApiTags } from "@nestjs/swagger";
|
||||
|
||||
import { CategoryListSearchQueryDto, CategorySearchQueryDto } from "./DTO/category-search-query.dto";
|
||||
import { CreateCategoryDto } from "./DTO/create-category.dto";
|
||||
import { CreateServiceDto } from "./DTO/create-service.dto";
|
||||
import { DanakServicesService } from "./providers/danak-services.service";
|
||||
import { AuthGuards } from "../../common/decorators/auth-guard.decorator";
|
||||
import { Pagination } from "../../common/decorators/pagination.decorator";
|
||||
import { Roles } from "../../common/decorators/roles.decorator";
|
||||
import { ParamDto } from "../../common/DTO/param.dto";
|
||||
import { RoleEnum } from "../users/enums/role.enum";
|
||||
|
||||
@Controller("services")
|
||||
@ApiTags("Danak-Services")
|
||||
export class DanakServicesController {
|
||||
constructor(private readonly danakServicesService: DanakServicesService) {}
|
||||
|
||||
//
|
||||
@AuthGuards()
|
||||
@Roles(RoleEnum.ADMIN)
|
||||
@ApiOperation({ summary: "Create a new service category" })
|
||||
@Post("category")
|
||||
createCategory(@Body() createDto: CreateCategoryDto) {
|
||||
return this.danakServicesService.createCategory(createDto);
|
||||
}
|
||||
|
||||
@AuthGuards()
|
||||
@Roles(RoleEnum.ADMIN)
|
||||
@ApiOperation({ summary: "Get all service categories" })
|
||||
@Get("category")
|
||||
getCategories(@Query() queryDto: CategorySearchQueryDto) {
|
||||
return this.danakServicesService.getCategories(queryDto);
|
||||
}
|
||||
|
||||
@AuthGuards()
|
||||
@Roles(RoleEnum.ADMIN)
|
||||
@ApiOperation({ summary: "Get all service categories" })
|
||||
@Pagination()
|
||||
@Get("category-list")
|
||||
getCategoryList(@Query() queryDto: CategoryListSearchQueryDto) {
|
||||
return this.danakServicesService.getCategoryList(queryDto);
|
||||
}
|
||||
|
||||
@AuthGuards()
|
||||
@Roles(RoleEnum.ADMIN)
|
||||
@ApiOperation({ summary: "toggle status of categories" })
|
||||
@HttpCode(HttpStatus.OK)
|
||||
@Post("category/toggle-status/:id")
|
||||
toggleCategoryStatus(@Param() paramDto: ParamDto) {
|
||||
return this.danakServicesService.toggleCategoryStatus(paramDto);
|
||||
}
|
||||
|
||||
@AuthGuards()
|
||||
@Roles(RoleEnum.ADMIN)
|
||||
@ApiOperation({ summary: "create new danak services" })
|
||||
@Post()
|
||||
createService(@Body() createDto: CreateServiceDto) {
|
||||
return this.danakServicesService.createService(createDto);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,9 @@ export class DanakServiceCategory extends BaseEntity {
|
||||
@Column({ type: "varchar", length: 150, nullable: false })
|
||||
icon: string;
|
||||
|
||||
@Column({ type: "boolean", default: true })
|
||||
isActive: boolean;
|
||||
|
||||
@ManyToOne(() => DanakServiceCategory, (category) => category.children)
|
||||
@JoinColumn({ name: "parentId" })
|
||||
parent: DanakServiceCategory;
|
||||
@@ -19,7 +22,7 @@ export class DanakServiceCategory extends BaseEntity {
|
||||
children: DanakServiceCategory[];
|
||||
|
||||
@Column({ nullable: true })
|
||||
parentId: string;
|
||||
parentId: string | null;
|
||||
|
||||
@OneToMany(() => DanakService, (danakService) => danakService.category)
|
||||
danakService: DanakService[];
|
||||
|
||||
@@ -8,9 +8,12 @@ import { ServicesLanguage } from "../enums/services-language.enum";
|
||||
|
||||
@Entity()
|
||||
export class DanakService extends BaseEntity {
|
||||
@Column({ type: "varchar", length: 255, nullable: false })
|
||||
@Column({ type: "varchar", length: 100, nullable: false })
|
||||
name: string;
|
||||
|
||||
@Column({ type: "boolean", nullable: false, default: false })
|
||||
isDanakSuggest: boolean;
|
||||
|
||||
@Column({ type: "text", nullable: false })
|
||||
description: string;
|
||||
|
||||
@@ -41,7 +44,7 @@ export class DanakService extends BaseEntity {
|
||||
@Column({ type: "varchar", length: 255, nullable: false })
|
||||
icon: string;
|
||||
|
||||
@OneToMany(() => DanakServiceImage, (danakServiceImage) => danakServiceImage.danakService, { eager: true })
|
||||
@OneToMany(() => DanakServiceImage, (danakServiceImage) => danakServiceImage.danakService, { eager: true, cascade: true })
|
||||
images: DanakServiceImage[];
|
||||
|
||||
@ManyToOne(() => DanakServiceCategory, (danakServiceCategory) => danakServiceCategory.danakService, {
|
||||
|
||||
@@ -1,17 +1,27 @@
|
||||
import { BadRequestException, Injectable, Logger } from "@nestjs/common";
|
||||
import { BadRequestException, Injectable } from "@nestjs/common";
|
||||
import { FindOptionsWhere, IsNull } from "typeorm";
|
||||
|
||||
import { ParamDto } from "../../../common/DTO/param.dto";
|
||||
import { CategoryMessage, CommonMessage } from "../../../common/enums/message.enum";
|
||||
import { PaginationUtils } from "../../utils/providers/pagination.utils";
|
||||
import { CategoryListSearchQueryDto, CategorySearchQueryDto } from "../DTO/category-search-query.dto";
|
||||
import { CreateCategoryDto } from "../DTO/create-category.dto";
|
||||
import { CreateServiceDto } from "../DTO/create-service.dto";
|
||||
import { DanakServiceCategory } from "../entities/danak-service-category.entity";
|
||||
import { DanakServicesCategoryRepository } from "../repositories/danak-services-category.repository";
|
||||
import { DanakServicesRepository } from "../repositories/danak-services.repository";
|
||||
|
||||
@Injectable()
|
||||
export class DanakServicesService {
|
||||
private readonly logger = new Logger(DanakServicesService.name);
|
||||
constructor(private readonly danakServicesCategoryRepository: DanakServicesCategoryRepository) {}
|
||||
/********** */
|
||||
// private readonly logger = new Logger(DanakServicesService.name);
|
||||
constructor(
|
||||
private readonly danakServicesRepository: DanakServicesRepository,
|
||||
private readonly danakServicesCategoryRepository: DanakServicesCategoryRepository,
|
||||
) {}
|
||||
/******************************************** */
|
||||
|
||||
async createCategory(createDto: CreateCategoryDto) {
|
||||
this.logger.log(`Creating a new category with title: ${createDto.title}`);
|
||||
const existCategory = await this.danakServicesCategoryRepository.findOneBy({ title: createDto.title });
|
||||
const existCategory = await this.danakServicesCategoryRepository.findOneByTitle(createDto.title);
|
||||
if (existCategory) throw new BadRequestException(CategoryMessage.TITLE_EXIST);
|
||||
const category = this.danakServicesCategoryRepository.create(createDto);
|
||||
await this.danakServicesCategoryRepository.save(category);
|
||||
@@ -20,5 +30,81 @@ export class DanakServicesService {
|
||||
category,
|
||||
};
|
||||
}
|
||||
/********** */
|
||||
/******************************************** */
|
||||
async getCategories(queryDto: CategorySearchQueryDto) {
|
||||
const where: FindOptionsWhere<DanakServiceCategory> = {
|
||||
isActive: true,
|
||||
};
|
||||
|
||||
if (queryDto.parentId === undefined) {
|
||||
where.parentId = IsNull();
|
||||
} else {
|
||||
// If parentId is provided, use it
|
||||
where.parentId = queryDto.parentId;
|
||||
}
|
||||
|
||||
const categories = await this.danakServicesCategoryRepository.find({
|
||||
where,
|
||||
order: { createdAt: "ASC" },
|
||||
});
|
||||
|
||||
return { categories };
|
||||
}
|
||||
|
||||
/******************************************** */
|
||||
async getCategoryList(queryDto: CategoryListSearchQueryDto) {
|
||||
const { limit, skip } = PaginationUtils(queryDto);
|
||||
const queryBuilder = this.danakServicesCategoryRepository
|
||||
.createQueryBuilder("category")
|
||||
.loadRelationCountAndMap("category.servicesCount", "category.danakService")
|
||||
.loadRelationCountAndMap("category.childrenCount", "category.children");
|
||||
|
||||
if (queryDto.isActive !== undefined) {
|
||||
queryBuilder.andWhere("category.isActive = :isActive", { isActive: queryDto.isActive === 1 });
|
||||
}
|
||||
|
||||
if (queryDto.q) {
|
||||
queryBuilder.andWhere("category.title LIKE :q", { q: `%${queryDto.q}%` });
|
||||
}
|
||||
|
||||
queryBuilder
|
||||
.leftJoinAndSelect("category.parent", "parent")
|
||||
.select(["category", "parent.id", "parent.title"])
|
||||
.orderBy("category.createdAt", "DESC");
|
||||
|
||||
const [categories, count] = await queryBuilder.skip(skip).take(limit).getManyAndCount();
|
||||
|
||||
return { categories, count };
|
||||
}
|
||||
/******************************************** */
|
||||
|
||||
async toggleCategoryStatus(paramDto: ParamDto) {
|
||||
const category = await this.danakServicesCategoryRepository.findOneById(paramDto.id);
|
||||
if (!category) throw new BadRequestException(CategoryMessage.CATEGORY_NOT_EXIST);
|
||||
category.isActive = !category.isActive;
|
||||
await this.danakServicesCategoryRepository.save(category);
|
||||
return {
|
||||
message: CommonMessage.UPDATE_SUCCESS,
|
||||
isActive: category.isActive,
|
||||
};
|
||||
}
|
||||
/******************************************** */
|
||||
async createService(createDto: CreateServiceDto) {
|
||||
const category = await this.danakServicesCategoryRepository.findOneById(createDto.categoryId);
|
||||
if (!category) throw new BadRequestException(CategoryMessage.CATEGORY_NOT_EXIST);
|
||||
|
||||
const images = createDto.images.map((image) => {
|
||||
return { imageUrl: image };
|
||||
});
|
||||
|
||||
const service = this.danakServicesRepository.create({ ...createDto, category, images });
|
||||
await this.danakServicesRepository.save(service);
|
||||
return {
|
||||
message: CommonMessage.CREATED,
|
||||
service,
|
||||
};
|
||||
}
|
||||
|
||||
/******************************************** */
|
||||
/******************************************** */
|
||||
}
|
||||
|
||||
@@ -9,4 +9,12 @@ export class DanakServicesCategoryRepository extends Repository<DanakServiceCate
|
||||
constructor(@InjectRepository(DanakServiceCategory) danakServicesCategoryRepository: Repository<DanakServiceCategory>) {
|
||||
super(danakServicesCategoryRepository.target, danakServicesCategoryRepository.manager, danakServicesCategoryRepository.queryRunner);
|
||||
}
|
||||
|
||||
async findOneByTitle(title: string): Promise<DanakServiceCategory | null> {
|
||||
return this.findOneBy({ title });
|
||||
}
|
||||
|
||||
async findOneById(id: string): Promise<DanakServiceCategory | null> {
|
||||
return this.findOneBy({ id });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ import { BadRequestException, Injectable, Logger } from "@nestjs/common";
|
||||
import slugify from "slugify";
|
||||
import { In, Not } from "typeorm";
|
||||
|
||||
import { RoleRepository } from "../repositories/roles.repository";
|
||||
// import { roles } from "../../../../database/seeders/role.seeder";
|
||||
import { CommonMessage, UserMessage } from "../../../common/enums/message.enum";
|
||||
import { CompleteRegistrationDto } from "../../auth/DTO/complete-register.dto";
|
||||
@@ -12,6 +11,7 @@ import { CreateUserGroupDto } from "../DTO/user-group.dto";
|
||||
import { User } from "../entities/user.entity";
|
||||
import { RoleEnum } from "../enums/role.enum";
|
||||
import { ValidityType } from "../enums/validity-type.enum";
|
||||
import { RoleRepository } from "../repositories/roles.repository";
|
||||
import { UserRepository } from "../repositories/users.repository";
|
||||
|
||||
@Injectable()
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
import { PaginationDto } from "../../../common/DTO/pagination.dto";
|
||||
|
||||
export function PaginationUtils(paginationData: PaginationDto) {
|
||||
const { limit = 10, page = 1 } = paginationData;
|
||||
|
||||
// const pageN = Number.parseInt(page) || 1;
|
||||
// const limitN = Number.parseInt(limit) || 10;
|
||||
|
||||
const skip = (page - 1) * limit;
|
||||
|
||||
return {
|
||||
// page: page,
|
||||
// limit: limit > 50 ? 50 : limit,
|
||||
limit: limit,
|
||||
skip: skip,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user