module salon

This commit is contained in:
2026-06-28 19:57:51 +03:30
parent 4fbb86663a
commit 043e80a139
7 changed files with 214 additions and 0 deletions
+2
View File
@@ -1,6 +1,7 @@
import { Module } from '@nestjs/common'; import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config'; import { ConfigModule } from '@nestjs/config';
import { TypeOrmModule } from '@nestjs/typeorm'; import { TypeOrmModule } from '@nestjs/typeorm';
import { SalonsModule } from './salons/salons.module';
import { UsersModule } from './users/users.module'; import { UsersModule } from './users/users.module';
@Module({ @Module({
@@ -17,6 +18,7 @@ import { UsersModule } from './users/users.module';
entities: [__dirname + '/**/*.entity.{js,ts}'], entities: [__dirname + '/**/*.entity.{js,ts}'],
}), }),
UsersModule, UsersModule,
SalonsModule,
], ],
controllers: [], controllers: [],
providers: [], providers: [],
+30
View File
@@ -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;
}
+21
View File
@@ -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;
}
+41
View File
@@ -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;
}
+46
View File
@@ -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);
}
}
+14
View File
@@ -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 {}
+60
View File
@@ -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<Salon>,
private readonly usersService: UsersService,
) {}
async create(createSalonDto: CreateSalonDto): Promise<Salon> {
await this.ensureOwnerIsSalonOwner(createSalonDto.ownerId);
const salon = this.salonsRepository.create(createSalonDto);
return this.salonsRepository.save(salon);
}
findAll(): Promise<Salon[]> {
return this.salonsRepository.find({ relations: { owner: true } });
}
async findOne(id: string): Promise<Salon> {
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<Salon> {
const salon = await this.findOne(id);
Object.assign(salon, updateSalonDto);
return this.salonsRepository.save(salon);
}
async remove(id: string): Promise<void> {
const salon = await this.findOne(id);
await this.salonsRepository.remove(salon);
}
private async ensureOwnerIsSalonOwner(ownerId: string): Promise<void> {
const owner = await this.usersService.findOne(ownerId);
if (owner.role !== UserRole.SALON) {
throw new BadRequestException('Owner must have salon-owner role');
}
}
}