chore: add industry crud
This commit is contained in:
@@ -42,9 +42,9 @@ export class AuthService {
|
||||
};
|
||||
}
|
||||
const otpCode = await this.otpService.generateAndSetInCache(phone, "REGISTER");
|
||||
|
||||
//
|
||||
await this.notificationQueue.addOtpNotification(phone, { userPhone: phone, otp: otpCode });
|
||||
await this.smsService.sendSmsVerifyCode(phone, otpCode);
|
||||
|
||||
return {
|
||||
message: AuthMessage.OTP_SENT,
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
import { Controller } from "@nestjs/common";
|
||||
|
||||
@Controller("companies")
|
||||
export class CompaniesController {}
|
||||
@@ -0,0 +1,14 @@
|
||||
import { MikroOrmModule } from "@mikro-orm/nestjs";
|
||||
import { Module } from "@nestjs/common";
|
||||
|
||||
import { CompaniesController } from "./companies.controller";
|
||||
import { Company } from "./entities/company.entity";
|
||||
import { CompaniesService } from "./services/companies.service";
|
||||
|
||||
@Module({
|
||||
imports: [MikroOrmModule.forFeature([Company])],
|
||||
providers: [CompaniesService],
|
||||
controllers: [CompaniesController],
|
||||
exports: [CompaniesService],
|
||||
})
|
||||
export class CompaniesModule {}
|
||||
@@ -0,0 +1,52 @@
|
||||
import { Entity, EntityRepositoryType, ManyToOne, Opt, Property } from "@mikro-orm/core";
|
||||
|
||||
import { BaseEntity } from "../../../common/entities/base.entity";
|
||||
import { Industry } from "../../industries/entities/industry.entity";
|
||||
import { CompanyRepository } from "../repositories/company.repository";
|
||||
|
||||
@Entity({ repository: () => CompanyRepository })
|
||||
export class Company extends BaseEntity {
|
||||
@Property({ type: "varchar", length: 255, unique: true })
|
||||
name!: string;
|
||||
|
||||
@Property({ type: "varchar", length: 255 })
|
||||
chiefExecutive!: string;
|
||||
|
||||
@Property({ type: "varchar", length: 255, unique: true })
|
||||
phone!: string;
|
||||
|
||||
@Property({ type: "varchar", length: 255, unique: true })
|
||||
email!: string;
|
||||
|
||||
@Property({ type: "varchar", length: 255, unique: true })
|
||||
identificationNumber!: string;
|
||||
|
||||
@Property({ type: "date" })
|
||||
dateOfEstablishment!: Date;
|
||||
|
||||
@Property({ type: "varchar", length: 255 })
|
||||
address!: string;
|
||||
|
||||
@Property({ type: "varchar", length: 255 })
|
||||
mapAddressLink!: string;
|
||||
|
||||
@Property({ type: "text", nullable: false })
|
||||
description!: string;
|
||||
|
||||
@Property({ type: "varchar", length: 255 })
|
||||
websiteUrl!: string;
|
||||
|
||||
@Property({ type: "varchar", length: 255 })
|
||||
profileImageUrl!: string;
|
||||
|
||||
@Property({ type: "varchar", length: 255 })
|
||||
coverImageUrl!: string;
|
||||
|
||||
@Property({ type: "boolean", default: true })
|
||||
isActive!: boolean & Opt;
|
||||
|
||||
@ManyToOne(() => Industry, { deleteRule: "restrict" })
|
||||
industry!: Industry;
|
||||
|
||||
[EntityRepositoryType]?: CompanyRepository;
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
import { EntityRepository } from "@mikro-orm/core";
|
||||
|
||||
import { Company } from "../entities/company.entity";
|
||||
|
||||
export class CompanyRepository extends EntityRepository<Company> {}
|
||||
@@ -0,0 +1,8 @@
|
||||
import { Injectable } from "@nestjs/common";
|
||||
|
||||
import { CompanyRepository } from "../repositories/company.repository";
|
||||
|
||||
@Injectable()
|
||||
export class CompaniesService {
|
||||
constructor(private readonly companyRepository: CompanyRepository) {}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
import { ApiProperty } from "@nestjs/swagger";
|
||||
import { IsBoolean, IsNotEmpty, IsOptional, IsString, IsUrl, Length } from "class-validator";
|
||||
|
||||
import { IndustryMessage } from "../../../common/enums/message.enum";
|
||||
|
||||
export class CreateIndustryDto {
|
||||
@IsNotEmpty({ message: IndustryMessage.TITLE_REQUIRED })
|
||||
@IsString({ message: IndustryMessage.TITLE_MUST_BE_A_STRING })
|
||||
@Length(3, 100, { message: IndustryMessage.TITLE_LENGTH })
|
||||
@ApiProperty({ description: "The title of the industry", example: "Industry" })
|
||||
title: string;
|
||||
|
||||
@IsNotEmpty({ message: IndustryMessage.ICON_URL_REQUIRED })
|
||||
@IsUrl({ protocols: ["http", "https"] }, { message: IndustryMessage.ICON_URL_MUST_BE_A_URL })
|
||||
@ApiProperty({ description: "The icon url of the industry", example: "https://example.com/icon.png" })
|
||||
iconUrl: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsNotEmpty({ message: IndustryMessage.IS_ACTIVE_REQUIRED })
|
||||
@IsBoolean({ message: IndustryMessage.IS_ACTIVE_MUST_BE_A_BOOLEAN })
|
||||
@ApiProperty({ description: "The active status of the industry", example: true })
|
||||
isActive?: boolean;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
import { ApiPropertyOptional } from "@nestjs/swagger";
|
||||
import { Type } from "class-transformer";
|
||||
import { IsIn, IsOptional, IsString } from "class-validator";
|
||||
|
||||
import { PaginationDto } from "../../../common/DTO/pagination.dto";
|
||||
import { CommonMessage } from "../../../common/enums/message.enum";
|
||||
|
||||
export class IndustryListQueryDto extends PaginationDto {
|
||||
@IsOptional()
|
||||
@Type(() => Number)
|
||||
@IsIn([1, 0], { message: CommonMessage.IS_ACTIVE_SHOULD_BE_1_0 })
|
||||
@ApiPropertyOptional({ description: "ads status", example: 1 })
|
||||
isActive?: number;
|
||||
|
||||
@IsOptional()
|
||||
@IsString({ message: CommonMessage.SEARCH_QUERY_STRING })
|
||||
@ApiPropertyOptional({ description: "Search query", example: "search query" })
|
||||
q?: string;
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
import { PartialType } from "@nestjs/swagger";
|
||||
|
||||
import { CreateIndustryDto } from "./create-industry.dto";
|
||||
|
||||
export class UpdateIndustryDto extends PartialType(CreateIndustryDto) {}
|
||||
@@ -0,0 +1,22 @@
|
||||
import { Collection, Entity, EntityRepositoryType, OneToMany, Opt, Property } from "@mikro-orm/core";
|
||||
|
||||
import { BaseEntity } from "../../../common/entities/base.entity";
|
||||
import { Company } from "../../companies/entities/company.entity";
|
||||
import { IndustryRepository } from "../repositories/industry.repository";
|
||||
|
||||
@Entity({ repository: () => IndustryRepository })
|
||||
export class Industry extends BaseEntity {
|
||||
@Property({ type: "varchar", length: 255, unique: true })
|
||||
title!: string;
|
||||
|
||||
@Property({ type: "varchar", length: 255 })
|
||||
iconUrl!: string;
|
||||
|
||||
@Property({ type: "boolean", default: true })
|
||||
isActive!: boolean & Opt;
|
||||
|
||||
@OneToMany(() => Company, (company) => company.industry)
|
||||
companies = new Collection<Company>(this);
|
||||
|
||||
[EntityRepositoryType]?: IndustryRepository;
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
import { Body, Controller, Delete, Get, Param, Patch, Post, Query } from "@nestjs/common";
|
||||
|
||||
import { CreateIndustryDto } from "./DTO/create-industry.dto";
|
||||
import { IndustryListQueryDto } from "./DTO/industry-list-query.dto";
|
||||
import { UpdateIndustryDto } from "./DTO/update-industry.dto";
|
||||
import { IndustriesService } from "./services/industries.service";
|
||||
import { ParamDto } from "../../common/DTO/param.dto";
|
||||
|
||||
@Controller("industries")
|
||||
export class IndustriesController {
|
||||
constructor(private readonly industriesService: IndustriesService) {}
|
||||
|
||||
@Post()
|
||||
create(@Body() createIndustryDto: CreateIndustryDto) {
|
||||
return this.industriesService.create(createIndustryDto);
|
||||
}
|
||||
|
||||
@Get(":id")
|
||||
getIndustryById(@Param() paramDto: ParamDto) {
|
||||
return this.industriesService.getIndustriesById(paramDto.id);
|
||||
}
|
||||
|
||||
@Patch(":id")
|
||||
updateIndustry(@Param() paramDto: ParamDto, @Body() updateIndustryDto: UpdateIndustryDto) {
|
||||
return this.industriesService.updateIndustry(paramDto.id, updateIndustryDto);
|
||||
}
|
||||
|
||||
@Delete(":id")
|
||||
deleteIndustry(@Param() paramDto: ParamDto) {
|
||||
return this.industriesService.deleteIndustry(paramDto.id);
|
||||
}
|
||||
|
||||
@Get("list")
|
||||
getIndustriesForAdmin(@Query() query: IndustryListQueryDto) {
|
||||
return this.industriesService.getIndustriesListForAdmin(query);
|
||||
}
|
||||
|
||||
@Patch(":id/toggle-status")
|
||||
toggleStatus(@Param() paramDto: ParamDto) {
|
||||
return this.industriesService.toggleStatus(paramDto.id);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
import { MikroOrmModule } from "@mikro-orm/nestjs";
|
||||
import { Module } from "@nestjs/common";
|
||||
|
||||
import { Industry } from "./entities/industry.entity";
|
||||
import { IndustriesController } from "./industries.controller";
|
||||
import { IndustriesService } from "./services/industries.service";
|
||||
|
||||
@Module({
|
||||
imports: [MikroOrmModule.forFeature([Industry])],
|
||||
controllers: [IndustriesController],
|
||||
providers: [IndustriesService],
|
||||
exports: [IndustriesService],
|
||||
})
|
||||
export class IndustriesModule {}
|
||||
@@ -0,0 +1,29 @@
|
||||
import { EntityRepository } from "@mikro-orm/postgresql";
|
||||
|
||||
import { PaginationUtils } from "../../utils/providers/pagination.utils";
|
||||
import { IndustryListQueryDto } from "../DTO/industry-list-query.dto";
|
||||
import { Industry } from "../entities/industry.entity";
|
||||
|
||||
export class IndustryRepository extends EntityRepository<Industry> {
|
||||
//
|
||||
async getIndustriesListForAdmin(queryDto: IndustryListQueryDto) {
|
||||
const { limit, skip } = PaginationUtils(queryDto);
|
||||
|
||||
const queryBuilder = this.createQueryBuilder("i")
|
||||
.leftJoinAndSelect("i.companies", "c")
|
||||
.where({ deletedAt: null })
|
||||
.orderBy({ createdAt: "DESC" })
|
||||
.limit(limit)
|
||||
.offset(skip);
|
||||
|
||||
if (queryDto.q) {
|
||||
queryBuilder.andWhere({ name: { $ilike: `%${queryDto.q}%` } });
|
||||
}
|
||||
|
||||
if (queryDto.isActive !== undefined) {
|
||||
queryBuilder.andWhere({ isActive: queryDto.isActive === 1 });
|
||||
}
|
||||
|
||||
return queryBuilder.getResultAndCount();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
import { EntityManager } from "@mikro-orm/postgresql";
|
||||
import { BadRequestException, Injectable } from "@nestjs/common";
|
||||
import dayjs from "dayjs";
|
||||
|
||||
import { IndustryMessage } from "../../../common/enums/message.enum";
|
||||
import { CreateIndustryDto } from "../DTO/create-industry.dto";
|
||||
import { IndustryListQueryDto } from "../DTO/industry-list-query.dto";
|
||||
import { UpdateIndustryDto } from "../DTO/update-industry.dto";
|
||||
import { IndustryRepository } from "../repositories/industry.repository";
|
||||
|
||||
@Injectable()
|
||||
export class IndustriesService {
|
||||
constructor(
|
||||
private readonly industryRepository: IndustryRepository,
|
||||
private readonly em: EntityManager,
|
||||
) {}
|
||||
|
||||
//-----------------------------------
|
||||
|
||||
async create(createIndustryDto: CreateIndustryDto) {
|
||||
const existingIndustry = await this.industryRepository.findOne({ title: createIndustryDto.title });
|
||||
if (existingIndustry) throw new BadRequestException(IndustryMessage.INDUSTRY_ALREADY_EXISTS);
|
||||
|
||||
const industry = this.industryRepository.create(createIndustryDto);
|
||||
this.em.persistAndFlush(industry);
|
||||
|
||||
return {
|
||||
message: IndustryMessage.INDUSTRY_CREATED_SUCCESSFULLY,
|
||||
industry,
|
||||
};
|
||||
}
|
||||
//-----------------------------------
|
||||
|
||||
async getIndustriesById(id: string) {
|
||||
const industry = await this.industryRepository.findOne({ id, deletedAt: null });
|
||||
if (!industry) throw new BadRequestException(IndustryMessage.INDUSTRY_NOT_FOUND);
|
||||
|
||||
return { industry };
|
||||
}
|
||||
//-----------------------------------
|
||||
|
||||
async updateIndustry(id: string, updateIndustryDto: UpdateIndustryDto) {
|
||||
const industry = await this.industryRepository.findOne({ id, deletedAt: null });
|
||||
if (!industry) throw new BadRequestException(IndustryMessage.INDUSTRY_NOT_FOUND);
|
||||
|
||||
this.industryRepository.assign(industry, updateIndustryDto);
|
||||
this.em.persistAndFlush(industry);
|
||||
|
||||
return {
|
||||
message: IndustryMessage.UPDATED_SUCCESSFULLY,
|
||||
industry,
|
||||
};
|
||||
}
|
||||
|
||||
//-----------------------------------
|
||||
|
||||
async deleteIndustry(id: string) {
|
||||
const industry = await this.industryRepository.findOne({ id, deletedAt: null });
|
||||
if (!industry) throw new BadRequestException(IndustryMessage.INDUSTRY_NOT_FOUND);
|
||||
|
||||
industry.deletedAt = dayjs().toDate();
|
||||
|
||||
this.em.flush();
|
||||
|
||||
return {
|
||||
message: IndustryMessage.INDUSTRY_DELETED_SUCCESSFULLY,
|
||||
};
|
||||
}
|
||||
//-----------------------------------
|
||||
|
||||
async getIndustriesListForAdmin(queryDto: IndustryListQueryDto) {
|
||||
const [industries, count] = await this.industryRepository.getIndustriesListForAdmin(queryDto);
|
||||
return { industries, count, paginate: true };
|
||||
}
|
||||
//-----------------------------------
|
||||
|
||||
async toggleStatus(id: string) {
|
||||
const industry = await this.industryRepository.findOne({ id, deletedAt: null });
|
||||
if (!industry) throw new BadRequestException(IndustryMessage.INDUSTRY_NOT_FOUND);
|
||||
|
||||
industry.isActive = !industry.isActive;
|
||||
this.em.flush();
|
||||
|
||||
return {
|
||||
message: IndustryMessage.UPDATED_SUCCESSFULLY,
|
||||
};
|
||||
}
|
||||
}
|
||||
Executable
+20
@@ -0,0 +1,20 @@
|
||||
import { ApiProperty } from "@nestjs/swagger";
|
||||
|
||||
import { IFile } from "../../utils/interfaces/IFile";
|
||||
|
||||
export class UploadSingleFileDto {
|
||||
@ApiProperty({ type: "string", format: "binary", nullable: false })
|
||||
file: IFile;
|
||||
}
|
||||
|
||||
export class UploadMultipleFileDto {
|
||||
@ApiProperty({
|
||||
required: true,
|
||||
type: "array",
|
||||
items: {
|
||||
type: "string",
|
||||
format: "binary",
|
||||
},
|
||||
})
|
||||
files: IFile[];
|
||||
}
|
||||
Executable
+32
@@ -0,0 +1,32 @@
|
||||
import { FileInterceptor, FilesInterceptor } from "@nest-lab/fastify-multer";
|
||||
import { Controller, Post, UploadedFile, UploadedFiles, UseInterceptors } from "@nestjs/common";
|
||||
import { ApiBody, ApiConsumes, ApiOperation, ApiTags } from "@nestjs/swagger";
|
||||
|
||||
import { UploadMultipleFileDto, UploadSingleFileDto } from "./DTO/upload-file.dto";
|
||||
import { UploaderService } from "./uploader.service";
|
||||
import { IFile } from "../utils/interfaces/IFile";
|
||||
|
||||
@ApiTags("Uploader")
|
||||
@Controller("uploader")
|
||||
// @AuthGuards()
|
||||
export class UploaderController {
|
||||
constructor(private readonly uploaderService: UploaderService) {}
|
||||
|
||||
@ApiOperation({ summary: "Uploads a single file" })
|
||||
@ApiConsumes("multipart/form-data")
|
||||
@UseInterceptors(FileInterceptor("file"))
|
||||
@ApiBody({ type: UploadSingleFileDto })
|
||||
@Post("single-file")
|
||||
uploadFile(@UploadedFile() file: IFile) {
|
||||
return this.uploaderService.upload(file);
|
||||
}
|
||||
|
||||
@ApiOperation({ summary: "Uploads multiple files" })
|
||||
@ApiConsumes("multipart/form-data")
|
||||
@UseInterceptors(FilesInterceptor("files"))
|
||||
@ApiBody({ type: UploadMultipleFileDto })
|
||||
@Post("multi-file")
|
||||
uploadFiles(@UploadedFiles() files: IFile[]) {
|
||||
return this.uploaderService.uploadMultiple(files);
|
||||
}
|
||||
}
|
||||
Executable
+14
@@ -0,0 +1,14 @@
|
||||
import { Module } from "@nestjs/common";
|
||||
|
||||
import { UploaderController } from "./uploader.controller";
|
||||
import { UploaderService } from "./uploader.service";
|
||||
import { S3Service } from "../utils/providers/s3.service";
|
||||
import { UtilsModule } from "../utils/utils.module";
|
||||
|
||||
@Module({
|
||||
imports: [UtilsModule],
|
||||
providers: [UploaderService, S3Service],
|
||||
controllers: [UploaderController],
|
||||
exports: [UploaderService],
|
||||
})
|
||||
export class UploaderModule {}
|
||||
Executable
+20
@@ -0,0 +1,20 @@
|
||||
import { Injectable } from "@nestjs/common";
|
||||
|
||||
import { IFile } from "../utils/interfaces/IFile";
|
||||
import { S3Service } from "../utils/providers/s3.service";
|
||||
|
||||
@Injectable()
|
||||
export class UploaderService {
|
||||
constructor(private s3Service: S3Service) {}
|
||||
|
||||
async upload(file: IFile) {
|
||||
return await this.s3Service.upload(file);
|
||||
}
|
||||
|
||||
async uploadMultiple(files: IFile[]) {
|
||||
// const uploadPromises = files.map((file) => this.s3Service.upload(file));
|
||||
|
||||
// return await Promise.all(uploadPromises);
|
||||
return this.s3Service.uploadMultiple(files);
|
||||
}
|
||||
}
|
||||
@@ -43,7 +43,6 @@ export class SmsService {
|
||||
}),
|
||||
),
|
||||
);
|
||||
console.log(data, "================");
|
||||
|
||||
return data;
|
||||
} catch (error) {
|
||||
|
||||
Reference in New Issue
Block a user