chore: add slider module
This commit is contained in:
@@ -23,6 +23,7 @@ import { IndustriesModule } from "./modules/industries/industries.module";
|
|||||||
import { InvoicesModule } from "./modules/invoices/invoices.module";
|
import { InvoicesModule } from "./modules/invoices/invoices.module";
|
||||||
import { NotificationModule } from "./modules/notifications/notifications.module";
|
import { NotificationModule } from "./modules/notifications/notifications.module";
|
||||||
import { PaymentsModule } from "./modules/payments/payments.module";
|
import { PaymentsModule } from "./modules/payments/payments.module";
|
||||||
|
import { SlidersModule } from "./modules/sliders/sliders.module";
|
||||||
import { TicketsModule } from "./modules/tickets/tickets.module";
|
import { TicketsModule } from "./modules/tickets/tickets.module";
|
||||||
import { UploaderModule } from "./modules/uploader/uploader.module";
|
import { UploaderModule } from "./modules/uploader/uploader.module";
|
||||||
import { UsersModule } from "./modules/users/users.module";
|
import { UsersModule } from "./modules/users/users.module";
|
||||||
@@ -59,6 +60,7 @@ import { UtilsModule } from "./modules/utils/utils.module";
|
|||||||
AnnouncementsModule,
|
AnnouncementsModule,
|
||||||
CriticismModule,
|
CriticismModule,
|
||||||
PaymentsModule,
|
PaymentsModule,
|
||||||
|
SlidersModule,
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
export class AppModule implements NestModule {
|
export class AppModule implements NestModule {
|
||||||
|
|||||||
@@ -650,3 +650,19 @@ export const enum BusinessMessage {
|
|||||||
DOMAIN_SETUP_TROUBLESHOOTING_5 = "- برخی از ارائهدهندگان DNS ممکن است نیاز به تنظیمات خاص برای رکوردهای TXT داشته باشند",
|
DOMAIN_SETUP_TROUBLESHOOTING_5 = "- برخی از ارائهدهندگان DNS ممکن است نیاز به تنظیمات خاص برای رکوردهای TXT داشته باشند",
|
||||||
DOMAIN_SETUP_TROUBLESHOOTING_6 = "- اگر از Cloudflare استفاده میکنید، مطمئن شوید که رکوردهای TXT را بدون پروکسی تنظیم کردهاید",
|
DOMAIN_SETUP_TROUBLESHOOTING_6 = "- اگر از Cloudflare استفاده میکنید، مطمئن شوید که رکوردهای TXT را بدون پروکسی تنظیم کردهاید",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const enum SliderMessage {
|
||||||
|
TITLE_REQUIRED = "عنوان اسلایدر الزامی است",
|
||||||
|
TITLE_STRING = "عنوان اسلایدر باید یک رشته باشد",
|
||||||
|
TITLE_MAX_LENGTH = "عنوان اسلایدر باید حداکثر ۱۰۰ کاراکتر باشد",
|
||||||
|
DESCRIPTION_STRING = "توضیحات اسلایدر باید یک رشته باشد",
|
||||||
|
DESCRIPTION_MAX_LENGTH = "توضیحات اسلایدر باید حداکثر ۲۵۵ کاراکتر باشد",
|
||||||
|
IMAGE_URL_REQUIRED = "آدرس تصویر اسلایدر الزامی است",
|
||||||
|
IMAGE_URL_STRING = "آدرس تصویر اسلایدر باید یک رشته باشد",
|
||||||
|
IMAGE_URL_MAX_LENGTH = "آدرس تصویر اسلایدر باید حداکثر ۲۵۵ کاراکتر باشد",
|
||||||
|
LINK_STRING = "لینک اسلایدر باید یک رشته باشد",
|
||||||
|
LINK_MAX_LENGTH = "لینک اسلایدر باید حداکثر ۲۵۵ کاراکتر باشد",
|
||||||
|
ORDER_NUMBER = "ترتیب اسلایدر باید یک عدد باشد",
|
||||||
|
IS_ACTIVE_SHOULD_BE_A_BOOLEAN = "وضعیت فعال بودن اسلایدر باید یک مقدار بولی باشد",
|
||||||
|
SLIDER_NOT_FOUND = "SLIDER_NOT_FOUND",
|
||||||
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import { Company } from "../../companies/entities/company.entity";
|
|||||||
import { Criticism } from "../../criticisms/entities/criticism.entity";
|
import { Criticism } from "../../criticisms/entities/criticism.entity";
|
||||||
import { Industry } from "../../industries/entities/industry.entity";
|
import { Industry } from "../../industries/entities/industry.entity";
|
||||||
import { Invoice } from "../../invoices/entities/invoice.entity";
|
import { Invoice } from "../../invoices/entities/invoice.entity";
|
||||||
|
import { Slider } from "../../sliders/entities/slider.entity";
|
||||||
import { TicketCategory } from "../../tickets/entities/ticket-category.entity";
|
import { TicketCategory } from "../../tickets/entities/ticket-category.entity";
|
||||||
import { Ticket } from "../../tickets/entities/ticket.entity";
|
import { Ticket } from "../../tickets/entities/ticket.entity";
|
||||||
import { User } from "../../users/entities/user.entity";
|
import { User } from "../../users/entities/user.entity";
|
||||||
@@ -65,6 +66,9 @@ export class Business extends BaseEntity {
|
|||||||
@OneToMany(() => Criticism, (criticism) => criticism.business)
|
@OneToMany(() => Criticism, (criticism) => criticism.business)
|
||||||
criticisms = new Collection<Criticism>(this);
|
criticisms = new Collection<Criticism>(this);
|
||||||
|
|
||||||
|
@OneToMany(() => Slider, (slider) => slider.business)
|
||||||
|
sliders = new Collection<Slider>(this);
|
||||||
|
|
||||||
@OneToMany(() => User, (user) => user.business)
|
@OneToMany(() => User, (user) => user.business)
|
||||||
users = new Collection<User>(this);
|
users = new Collection<User>(this);
|
||||||
|
|
||||||
|
|||||||
Executable
+40
@@ -0,0 +1,40 @@
|
|||||||
|
import { ApiProperty, ApiPropertyOptional } from "@nestjs/swagger";
|
||||||
|
import { IsBoolean, IsNotEmpty, IsNumber, IsOptional, IsString, MaxLength } from "class-validator";
|
||||||
|
|
||||||
|
import { SliderMessage } from "../../../common/enums/message.enum";
|
||||||
|
|
||||||
|
export class CreateSliderDto {
|
||||||
|
@ApiProperty({ description: "Title of the slider", example: "Summer Sale" })
|
||||||
|
@IsNotEmpty({ message: SliderMessage.TITLE_REQUIRED })
|
||||||
|
@IsString({ message: SliderMessage.TITLE_STRING })
|
||||||
|
@MaxLength(150, { message: SliderMessage.TITLE_MAX_LENGTH })
|
||||||
|
title: string;
|
||||||
|
|
||||||
|
@ApiPropertyOptional({ description: "Description of the slider", example: "Get up to 50% off" })
|
||||||
|
@IsOptional()
|
||||||
|
@IsString({ message: SliderMessage.DESCRIPTION_STRING })
|
||||||
|
@MaxLength(255, { message: SliderMessage.DESCRIPTION_MAX_LENGTH })
|
||||||
|
description?: string;
|
||||||
|
|
||||||
|
@ApiProperty({ description: "URL of the slider image", example: "https://example.com/image.jpg" })
|
||||||
|
@IsNotEmpty({ message: SliderMessage.IMAGE_URL_REQUIRED })
|
||||||
|
@IsString({ message: SliderMessage.IMAGE_URL_STRING })
|
||||||
|
@MaxLength(255, { message: SliderMessage.IMAGE_URL_MAX_LENGTH })
|
||||||
|
imageUrl: string;
|
||||||
|
|
||||||
|
@ApiPropertyOptional({ description: "Link URL for the slider", example: "https://example.com/sale" })
|
||||||
|
@IsOptional()
|
||||||
|
@IsString({ message: SliderMessage.LINK_STRING })
|
||||||
|
@MaxLength(255, { message: SliderMessage.LINK_MAX_LENGTH })
|
||||||
|
link?: string;
|
||||||
|
|
||||||
|
@ApiPropertyOptional({ description: "Order of the slider", example: 1, default: 0 })
|
||||||
|
@IsOptional()
|
||||||
|
@IsNumber({}, { message: SliderMessage.ORDER_NUMBER })
|
||||||
|
order?: number;
|
||||||
|
|
||||||
|
@ApiPropertyOptional({ description: "Whether the slider is active", example: true, default: true })
|
||||||
|
@IsOptional()
|
||||||
|
@IsBoolean({ message: SliderMessage.IS_ACTIVE_SHOULD_BE_A_BOOLEAN })
|
||||||
|
isActive?: boolean;
|
||||||
|
}
|
||||||
Executable
+5
@@ -0,0 +1,5 @@
|
|||||||
|
import { PartialType } from "@nestjs/swagger";
|
||||||
|
|
||||||
|
import { CreateSliderDto } from "./create-slider.dto";
|
||||||
|
|
||||||
|
export class UpdateSliderDto extends PartialType(CreateSliderDto) {}
|
||||||
+33
@@ -0,0 +1,33 @@
|
|||||||
|
import { Entity, EntityRepositoryType, ManyToOne, Opt, Property } from "@mikro-orm/core";
|
||||||
|
|
||||||
|
import { BaseEntity } from "../../../common/entities/base.entity";
|
||||||
|
import { Business } from "../../businesses/entities/business.entity";
|
||||||
|
import { SliderRepository } from "../repositories/sliders.repository";
|
||||||
|
|
||||||
|
@Entity({ repository: () => SliderRepository })
|
||||||
|
export class Slider extends BaseEntity {
|
||||||
|
@Property({ type: "varchar", length: 150 })
|
||||||
|
title: string;
|
||||||
|
|
||||||
|
@Property({ type: "varchar", length: 255, nullable: true })
|
||||||
|
description?: string;
|
||||||
|
|
||||||
|
@Property({ type: "varchar", length: 255 })
|
||||||
|
imageUrl: string;
|
||||||
|
|
||||||
|
@Property({ type: "varchar", length: 255, nullable: true })
|
||||||
|
link?: string;
|
||||||
|
|
||||||
|
@Property({ type: "int", default: 0 })
|
||||||
|
order: number & Opt;
|
||||||
|
|
||||||
|
@Property({ type: "boolean", default: true })
|
||||||
|
isActive: boolean & Opt;
|
||||||
|
|
||||||
|
@ManyToOne(() => Business, { deleteRule: "restrict" })
|
||||||
|
business!: Business;
|
||||||
|
|
||||||
|
//-----------------------------
|
||||||
|
|
||||||
|
[EntityRepositoryType]?: SliderRepository;
|
||||||
|
}
|
||||||
+85
@@ -0,0 +1,85 @@
|
|||||||
|
import { EntityManager } from "@mikro-orm/postgresql";
|
||||||
|
import { BadRequestException, Injectable } from "@nestjs/common";
|
||||||
|
|
||||||
|
import { PaginationDto } from "../../../common/DTO/pagination.dto";
|
||||||
|
import { CommonMessage, SliderMessage } from "../../../common/enums/message.enum";
|
||||||
|
import { Business } from "../../businesses/entities/business.entity";
|
||||||
|
import { CreateSliderDto } from "../DTO/create-slider.dto";
|
||||||
|
import { UpdateSliderDto } from "../DTO/update-slider.dto";
|
||||||
|
import { SliderRepository } from "../repositories/sliders.repository";
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class SlidersService {
|
||||||
|
constructor(
|
||||||
|
private readonly slidersRepository: SliderRepository,
|
||||||
|
private readonly em: EntityManager,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
async create(createSliderDto: CreateSliderDto, business: Business) {
|
||||||
|
const slider = this.slidersRepository.create({ ...createSliderDto, business });
|
||||||
|
await this.em.persistAndFlush(slider);
|
||||||
|
return {
|
||||||
|
message: CommonMessage.CREATED,
|
||||||
|
slider,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
//*************************** */
|
||||||
|
async getSlidersList(queryDto: PaginationDto, businessId: string) {
|
||||||
|
const [sliders, count] = await this.slidersRepository.getSlidersListForAdmin(queryDto, businessId);
|
||||||
|
return {
|
||||||
|
sliders,
|
||||||
|
count,
|
||||||
|
paginate: true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
//************************* */
|
||||||
|
|
||||||
|
async getSliderListPublic(businessId: string) {
|
||||||
|
const sliders = await this.slidersRepository.find({ isActive: true, deletedAt: null, business: { id: businessId } });
|
||||||
|
return { sliders };
|
||||||
|
}
|
||||||
|
//************************* */
|
||||||
|
async getSliderById(id: string, businessId: string) {
|
||||||
|
const slider = await this.slidersRepository.findOne({ id, business: { id: businessId }, deletedAt: null });
|
||||||
|
if (!slider) throw new BadRequestException(SliderMessage.SLIDER_NOT_FOUND);
|
||||||
|
|
||||||
|
return {
|
||||||
|
slider,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
//****************** */
|
||||||
|
async update(id: string, updateSliderDto: UpdateSliderDto, businessId: string) {
|
||||||
|
const { slider } = await this.getSliderById(id, businessId);
|
||||||
|
|
||||||
|
this.slidersRepository.assign(slider, updateSliderDto);
|
||||||
|
|
||||||
|
await this.em.persistAndFlush(slider);
|
||||||
|
return {
|
||||||
|
message: CommonMessage.UPDATE_SUCCESS,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
//****************** */
|
||||||
|
async remove(id: string, businessId: string) {
|
||||||
|
const { slider } = await this.getSliderById(id, businessId);
|
||||||
|
|
||||||
|
slider.deletedAt = new Date();
|
||||||
|
await this.em.flush();
|
||||||
|
|
||||||
|
return {
|
||||||
|
message: CommonMessage.DELETED,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
//****************** */
|
||||||
|
|
||||||
|
async toggleSliderStatus(id: string, businessId: string) {
|
||||||
|
const { slider } = await this.getSliderById(id, businessId);
|
||||||
|
|
||||||
|
slider.isActive = !slider.isActive;
|
||||||
|
|
||||||
|
await this.em.flush();
|
||||||
|
return {
|
||||||
|
message: CommonMessage.UPDATE_SUCCESS,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
//****************** */
|
||||||
|
}
|
||||||
+13
@@ -0,0 +1,13 @@
|
|||||||
|
import { EntityRepository } from "@mikro-orm/postgresql";
|
||||||
|
|
||||||
|
import { PaginationDto } from "../../../common/DTO/pagination.dto";
|
||||||
|
import { PaginationUtils } from "../../utils/providers/pagination.utils";
|
||||||
|
import { Slider } from "../entities/slider.entity";
|
||||||
|
|
||||||
|
export class SliderRepository extends EntityRepository<Slider> {
|
||||||
|
async getSlidersListForAdmin(queryDto: PaginationDto, businessId: string) {
|
||||||
|
const { skip, limit } = PaginationUtils(queryDto);
|
||||||
|
|
||||||
|
return this.findAndCount({ deletedAt: null, business: { id: businessId } }, { offset: skip, limit, orderBy: { order: "ASC" } });
|
||||||
|
}
|
||||||
|
}
|
||||||
Executable
+57
@@ -0,0 +1,57 @@
|
|||||||
|
import { Body, Controller, Delete, Get, Param, Patch, Post, Query, UseInterceptors } from "@nestjs/common";
|
||||||
|
import { ApiOperation } from "@nestjs/swagger";
|
||||||
|
|
||||||
|
import { CreateSliderDto } from "./DTO/create-slider.dto";
|
||||||
|
import { UpdateSliderDto } from "./DTO/update-slider.dto";
|
||||||
|
import { SlidersService } from "./providers/sliders.service";
|
||||||
|
import { AuthGuards } from "../../common/decorators/auth-guard.decorator";
|
||||||
|
import { BusinessDec } from "../../common/decorators/business.decorator";
|
||||||
|
import { SkipAuth } from "../../common/decorators/skip-auth.decorator";
|
||||||
|
import { PaginationDto } from "../../common/DTO/pagination.dto";
|
||||||
|
import { ParamDto } from "../../common/DTO/param.dto";
|
||||||
|
import { BusinessInterceptor } from "../../core/interceptors/business.interceptor";
|
||||||
|
import { Business } from "../businesses/entities/business.entity";
|
||||||
|
|
||||||
|
@Controller("sliders")
|
||||||
|
@AuthGuards()
|
||||||
|
@UseInterceptors(BusinessInterceptor)
|
||||||
|
export class SlidersController {
|
||||||
|
constructor(private readonly slidersService: SlidersService) {}
|
||||||
|
|
||||||
|
@ApiOperation({ summary: "create slider (admin route)" })
|
||||||
|
@Post()
|
||||||
|
create(@Body() createSliderDto: CreateSliderDto, @BusinessDec() business: Business) {
|
||||||
|
return this.slidersService.create(createSliderDto, business);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation({ summary: "Get all sliders (admin route)" })
|
||||||
|
@Get()
|
||||||
|
getSlidersList(@Query() queryDto: PaginationDto, @BusinessDec("id") businessId: string) {
|
||||||
|
return this.slidersService.getSlidersList(queryDto, businessId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Get("list/public")
|
||||||
|
@SkipAuth()
|
||||||
|
@ApiOperation({ summary: "get all slider public" })
|
||||||
|
getSliderListPublic(@BusinessDec("id") businessId: string) {
|
||||||
|
return this.slidersService.getSliderListPublic(businessId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation({ summary: "Get a slider by id (admin route)" })
|
||||||
|
@Get(":id")
|
||||||
|
getSliderById(@Param() paramDto: ParamDto, @BusinessDec("id") businessId: string) {
|
||||||
|
return this.slidersService.getSliderById(paramDto.id, businessId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation({ summary: "Update a slider (admin route)" })
|
||||||
|
@Patch(":id")
|
||||||
|
update(@Param() paramDto: ParamDto, @Body() updateSliderDto: UpdateSliderDto, @BusinessDec("id") businessId: string) {
|
||||||
|
return this.slidersService.update(paramDto.id, updateSliderDto, businessId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation({ summary: "Delete a slider (admin route)" })
|
||||||
|
@Delete(":id")
|
||||||
|
remove(@Param() paramDto: ParamDto, @BusinessDec("id") businessId: string) {
|
||||||
|
return this.slidersService.remove(paramDto.id, businessId);
|
||||||
|
}
|
||||||
|
}
|
||||||
Executable
+15
@@ -0,0 +1,15 @@
|
|||||||
|
import { MikroOrmModule } from "@mikro-orm/nestjs";
|
||||||
|
import { Module } from "@nestjs/common";
|
||||||
|
|
||||||
|
import { Slider } from "./entities/slider.entity";
|
||||||
|
import { SlidersService } from "./providers/sliders.service";
|
||||||
|
import { SlidersController } from "./sliders.controller";
|
||||||
|
import { BusinessesModule } from "../businesses/businesses.module";
|
||||||
|
|
||||||
|
@Module({
|
||||||
|
imports: [MikroOrmModule.forFeature([Slider]), BusinessesModule],
|
||||||
|
controllers: [SlidersController],
|
||||||
|
providers: [SlidersService],
|
||||||
|
exports: [SlidersService],
|
||||||
|
})
|
||||||
|
export class SlidersModule {}
|
||||||
@@ -94,22 +94,22 @@ export class UsersService {
|
|||||||
|
|
||||||
/*******************************/
|
/*******************************/
|
||||||
|
|
||||||
async updateUser(id: string, updateData: Partial<User>, em: EntityManager) {
|
async updateUser(userId: string, updateData: Partial<User>, em: EntityManager) {
|
||||||
const user = await em.findOne(User, { id, deletedAt: null });
|
const user = await em.findOne(User, { id: userId, deletedAt: null });
|
||||||
if (!user) throw new BadRequestException(UserMessage.USER_NOT_FOUND);
|
if (!user) throw new BadRequestException(UserMessage.USER_NOT_FOUND);
|
||||||
|
|
||||||
if (updateData.phone) {
|
if (updateData.phone) {
|
||||||
const existingUser = await em.findOne(User, { phone: updateData.phone, deletedAt: null, id: { $ne: id } });
|
const existingUser = await em.findOne(User, { phone: updateData.phone, deletedAt: null, id: { $ne: userId } });
|
||||||
if (existingUser) throw new BadRequestException(UserMessage.PHONE_EXIST);
|
if (existingUser) throw new BadRequestException(UserMessage.PHONE_EXIST);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (updateData.email) {
|
if (updateData.email) {
|
||||||
const existingUser = await em.findOne(User, { email: updateData.email, deletedAt: null, id: { $ne: id } });
|
const existingUser = await em.findOne(User, { email: updateData.email, deletedAt: null, id: { $ne: userId } });
|
||||||
if (existingUser) throw new BadRequestException(UserMessage.EMAIL_EXIST);
|
if (existingUser) throw new BadRequestException(UserMessage.EMAIL_EXIST);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (updateData.nationalCode) {
|
if (updateData.nationalCode) {
|
||||||
const existingUser = await em.findOne(User, { nationalCode: updateData.nationalCode, deletedAt: null, id: { $ne: id } });
|
const existingUser = await em.findOne(User, { nationalCode: updateData.nationalCode, deletedAt: null, id: { $ne: userId } });
|
||||||
if (existingUser) throw new BadRequestException(UserMessage.NATIONAL_CODE_EXIST);
|
if (existingUser) throw new BadRequestException(UserMessage.NATIONAL_CODE_EXIST);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user