From bb5f2ef2b3ae3c25bd1693925cf16aa082b741a9 Mon Sep 17 00:00:00 2001 From: Mahdi Date: Sat, 13 Jun 2026 16:50:46 +0330 Subject: [PATCH] edit ios & api --- src/modules/users/dto/create-user.dto.ts | 27 ++++++++++++++++++ src/modules/users/users.controller.ts | 7 +++++ src/modules/users/users.service.ts | 36 ++++++++++++++++++++++-- 3 files changed, 68 insertions(+), 2 deletions(-) create mode 100644 src/modules/users/dto/create-user.dto.ts diff --git a/src/modules/users/dto/create-user.dto.ts b/src/modules/users/dto/create-user.dto.ts new file mode 100644 index 0000000..94d83db --- /dev/null +++ b/src/modules/users/dto/create-user.dto.ts @@ -0,0 +1,27 @@ +import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; +import { IsBoolean, IsEnum, IsOptional, IsString, MaxLength } from 'class-validator'; +import { IsIranMobile } from '../../../common/decorators/is-iran-mobile.decorator'; +import { UserRole } from '../../../entities/user.entity'; + +export class CreateUserDto { + @ApiProperty({ example: '09121234567' }) + @IsString() + @IsIranMobile() + mobile!: string; + + @ApiPropertyOptional({ example: 'علی رضایی', nullable: true }) + @IsOptional() + @IsString() + @MaxLength(150) + fullName?: string | null; + + @ApiPropertyOptional({ enum: UserRole, default: UserRole.CUSTOMER }) + @IsOptional() + @IsEnum(UserRole) + role?: UserRole; + + @ApiPropertyOptional({ default: true }) + @IsOptional() + @IsBoolean() + isActive?: boolean; +} diff --git a/src/modules/users/users.controller.ts b/src/modules/users/users.controller.ts index 698e444..1fe2c5f 100644 --- a/src/modules/users/users.controller.ts +++ b/src/modules/users/users.controller.ts @@ -4,6 +4,7 @@ import { Get, Param, Patch, + Post, UseGuards, } from '@nestjs/common'; import { PublicUser } from '../../common/utils/user-serialize.util'; @@ -12,6 +13,7 @@ import { Roles } from '../auth/decorators/roles.decorator'; import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard'; import { RolesGuard } from '../auth/guards/roles.guard'; import { AdminSetUserPasswordDto } from './dto/admin-set-user-password.dto'; +import { CreateUserDto } from './dto/create-user.dto'; import { UpdateUserDto } from './dto/update-user.dto'; import { UsersService } from './users.service'; @@ -26,6 +28,11 @@ export class UsersController { return this.service.findAll(); } + @Post() + create(@Body() payload: CreateUserDto): Promise { + return this.service.create(payload); + } + @Get(':id') findOne(@Param('id') id: string): Promise { return this.service.findOne(id); diff --git a/src/modules/users/users.service.ts b/src/modules/users/users.service.ts index d50d997..a0317ba 100644 --- a/src/modules/users/users.service.ts +++ b/src/modules/users/users.service.ts @@ -1,10 +1,20 @@ -import { BadRequestException, Injectable, NotFoundException } from '@nestjs/common'; +import { + BadRequestException, + ConflictException, + Injectable, + NotFoundException, +} from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; import { hashPassword } from '../../common/utils/password.util'; +import { + isValidIranMobile, + normalizeIranMobile, +} from '../../common/utils/iran-mobile.util'; import { PublicUser, serializeUser } from '../../common/utils/user-serialize.util'; -import { UserEntity } from '../../entities/user.entity'; +import { UserEntity, UserRole } from '../../entities/user.entity'; import { AdminSetUserPasswordDto } from './dto/admin-set-user-password.dto'; +import { CreateUserDto } from './dto/create-user.dto'; import { UpdateUserDto } from './dto/update-user.dto'; @Injectable() @@ -23,6 +33,28 @@ export class UsersService { return users.map(serializeUser); } + async create(dto: CreateUserDto): Promise { + const mobile = normalizeIranMobile(dto.mobile); + if (!isValidIranMobile(mobile)) { + throw new BadRequestException('Invalid mobile number'); + } + + const existing = await this.repo.findOne({ where: { mobile } }); + if (existing) { + throw new ConflictException('کاربری با این شماره موبایل قبلاً ثبت شده است'); + } + + const user = this.repo.create({ + mobile, + fullName: dto.fullName ?? null, + role: dto.role ?? UserRole.CUSTOMER, + isActive: dto.isActive ?? true, + }); + + const saved = await this.repo.save(user); + return serializeUser(saved); + } + async findOne(id: string): Promise { const user = await this.repo .createQueryBuilder('user')