From 043e80a139066511399cf2e19069f80cb022527c Mon Sep 17 00:00:00 2001 From: hamid zarghami Date: Sun, 28 Jun 2026 19:57:51 +0330 Subject: [PATCH] module salon --- src/app.module.ts | 2 + src/salons/dto/create-salon.dto.ts | 30 +++++++++++++++ src/salons/dto/update-salon.dto.ts | 21 ++++++++++ src/salons/entities/salon.entity.ts | 41 ++++++++++++++++++++ src/salons/salons.controller.ts | 46 ++++++++++++++++++++++ src/salons/salons.module.ts | 14 +++++++ src/salons/salons.service.ts | 60 +++++++++++++++++++++++++++++ 7 files changed, 214 insertions(+) create mode 100644 src/salons/dto/create-salon.dto.ts create mode 100644 src/salons/dto/update-salon.dto.ts create mode 100644 src/salons/entities/salon.entity.ts create mode 100644 src/salons/salons.controller.ts create mode 100644 src/salons/salons.module.ts create mode 100644 src/salons/salons.service.ts diff --git a/src/app.module.ts b/src/app.module.ts index b66cc54..f6b95d5 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -1,6 +1,7 @@ import { Module } from '@nestjs/common'; import { ConfigModule } from '@nestjs/config'; import { TypeOrmModule } from '@nestjs/typeorm'; +import { SalonsModule } from './salons/salons.module'; import { UsersModule } from './users/users.module'; @Module({ @@ -17,6 +18,7 @@ import { UsersModule } from './users/users.module'; entities: [__dirname + '/**/*.entity.{js,ts}'], }), UsersModule, + SalonsModule, ], controllers: [], providers: [], diff --git a/src/salons/dto/create-salon.dto.ts b/src/salons/dto/create-salon.dto.ts new file mode 100644 index 0000000..ac9baee --- /dev/null +++ b/src/salons/dto/create-salon.dto.ts @@ -0,0 +1,30 @@ +import { + IsNotEmpty, + IsOptional, + IsString, + IsUUID, + Length, + Matches, +} from 'class-validator'; + +export class CreateSalonDto { + @IsString() + @Length(1, 200) + @IsNotEmpty() + name: string; + + @IsOptional() + @IsString() + description?: string; + + @IsString() + @Length(1, 500) + @IsNotEmpty() + address: string; + + @Matches(/^09\d{9}$/) + phone: string; + + @IsUUID() + ownerId: string; +} diff --git a/src/salons/dto/update-salon.dto.ts b/src/salons/dto/update-salon.dto.ts new file mode 100644 index 0000000..5ba2710 --- /dev/null +++ b/src/salons/dto/update-salon.dto.ts @@ -0,0 +1,21 @@ +import { IsOptional, IsString, Length, Matches } from 'class-validator'; + +export class UpdateSalonDto { + @IsOptional() + @IsString() + @Length(1, 200) + name?: string; + + @IsOptional() + @IsString() + description?: string; + + @IsOptional() + @IsString() + @Length(1, 500) + address?: string; + + @IsOptional() + @Matches(/^09\d{9}$/) + phone?: string; +} diff --git a/src/salons/entities/salon.entity.ts b/src/salons/entities/salon.entity.ts new file mode 100644 index 0000000..28add99 --- /dev/null +++ b/src/salons/entities/salon.entity.ts @@ -0,0 +1,41 @@ +import { + Column, + CreateDateColumn, + Entity, + JoinColumn, + ManyToOne, + PrimaryGeneratedColumn, + UpdateDateColumn, +} from 'typeorm'; +import { User } from '../../users/entities/user.entity'; + +@Entity('salons') +export class Salon { + @PrimaryGeneratedColumn('uuid') + id: string; + + @Column({ length: 200 }) + name: string; + + @Column({ type: 'text', nullable: true }) + description: string | null; + + @Column({ length: 500 }) + address: string; + + @Column({ length: 11 }) + phone: string; + + @Column() + ownerId: string; + + @ManyToOne(() => User, { onDelete: 'CASCADE' }) + @JoinColumn({ name: 'ownerId' }) + owner: User; + + @CreateDateColumn() + createdAt: Date; + + @UpdateDateColumn() + updatedAt: Date; +} diff --git a/src/salons/salons.controller.ts b/src/salons/salons.controller.ts new file mode 100644 index 0000000..9f58ab0 --- /dev/null +++ b/src/salons/salons.controller.ts @@ -0,0 +1,46 @@ +import { + Body, + Controller, + Delete, + Get, + Param, + ParseUUIDPipe, + Patch, + Post, +} from '@nestjs/common'; +import { CreateSalonDto } from './dto/create-salon.dto'; +import { UpdateSalonDto } from './dto/update-salon.dto'; +import { SalonsService } from './salons.service'; + +@Controller('salons') +export class SalonsController { + constructor(private readonly salonsService: SalonsService) {} + + @Post() + create(@Body() createSalonDto: CreateSalonDto) { + return this.salonsService.create(createSalonDto); + } + + @Get() + findAll() { + return this.salonsService.findAll(); + } + + @Get(':id') + findOne(@Param('id', ParseUUIDPipe) id: string) { + return this.salonsService.findOne(id); + } + + @Patch(':id') + update( + @Param('id', ParseUUIDPipe) id: string, + @Body() updateSalonDto: UpdateSalonDto, + ) { + return this.salonsService.update(id, updateSalonDto); + } + + @Delete(':id') + remove(@Param('id', ParseUUIDPipe) id: string) { + return this.salonsService.remove(id); + } +} diff --git a/src/salons/salons.module.ts b/src/salons/salons.module.ts new file mode 100644 index 0000000..ec15bbf --- /dev/null +++ b/src/salons/salons.module.ts @@ -0,0 +1,14 @@ +import { Module } from '@nestjs/common'; +import { TypeOrmModule } from '@nestjs/typeorm'; +import { UsersModule } from '../users/users.module'; +import { Salon } from './entities/salon.entity'; +import { SalonsController } from './salons.controller'; +import { SalonsService } from './salons.service'; + +@Module({ + imports: [TypeOrmModule.forFeature([Salon]), UsersModule], + controllers: [SalonsController], + providers: [SalonsService], + exports: [SalonsService], +}) +export class SalonsModule {} diff --git a/src/salons/salons.service.ts b/src/salons/salons.service.ts new file mode 100644 index 0000000..c1ba22c --- /dev/null +++ b/src/salons/salons.service.ts @@ -0,0 +1,60 @@ +import { + BadRequestException, + Injectable, + NotFoundException, +} from '@nestjs/common'; +import { InjectRepository } from '@nestjs/typeorm'; +import { Repository } from 'typeorm'; +import { UserRole } from '../users/enums/user-role.enum'; +import { UsersService } from '../users/users.service'; +import { CreateSalonDto } from './dto/create-salon.dto'; +import { UpdateSalonDto } from './dto/update-salon.dto'; +import { Salon } from './entities/salon.entity'; + +@Injectable() +export class SalonsService { + constructor( + @InjectRepository(Salon) + private readonly salonsRepository: Repository, + private readonly usersService: UsersService, + ) {} + + async create(createSalonDto: CreateSalonDto): Promise { + await this.ensureOwnerIsSalonOwner(createSalonDto.ownerId); + const salon = this.salonsRepository.create(createSalonDto); + return this.salonsRepository.save(salon); + } + + findAll(): Promise { + return this.salonsRepository.find({ relations: { owner: true } }); + } + + async findOne(id: string): Promise { + const salon = await this.salonsRepository.findOne({ + where: { id }, + relations: { owner: true }, + }); + if (!salon) { + throw new NotFoundException(`Salon #${id} not found`); + } + return salon; + } + + async update(id: string, updateSalonDto: UpdateSalonDto): Promise { + const salon = await this.findOne(id); + Object.assign(salon, updateSalonDto); + return this.salonsRepository.save(salon); + } + + async remove(id: string): Promise { + const salon = await this.findOne(id); + await this.salonsRepository.remove(salon); + } + + private async ensureOwnerIsSalonOwner(ownerId: string): Promise { + const owner = await this.usersService.findOne(ownerId); + if (owner.role !== UserRole.SALON) { + throw new BadRequestException('Owner must have salon-owner role'); + } + } +}