This commit is contained in:
2026-03-08 12:25:27 +03:30
parent ec04fa6158
commit 4b4b6a1f63
4 changed files with 147 additions and 7 deletions
+45
View File
@@ -0,0 +1,45 @@
import { ApiProperty } from "@nestjs/swagger";
import { IsNotEmpty, IsNumberString, IsString, Length, MinLength } from "class-validator";
import { IsMobilePhone } from "class-validator";
import { IsNationalCode } from "../../../common/decorators/is-national-code.decorator";
import { AuthMessage } from "../../../common/enums/message.enum";
export class CreateWatcherDto {
@IsNotEmpty({ message: AuthMessage.PHONE_NOT_EMPTY })
@IsMobilePhone("fa-IR", {}, { message: AuthMessage.INVALID_PHONE_FORMAT })
@Length(11, 11, { message: AuthMessage.PHONE_SHOULD_BE_11_DIGIT })
@ApiProperty({ description: "phone number", default: "09922320740" })
phone: string;
@IsNotEmpty({ message: AuthMessage.FIRST_NAME_NOT_EMPTY })
@IsString({ message: AuthMessage.FIRST_NAME_NOT_EMPTY })
@Length(2, 50, { message: AuthMessage.FIRST_NAME_SHOULD_BE_BETWEEN_2_AND_50 })
@ApiProperty({ description: "First name", example: "mahyar" })
firstName: string;
@IsNotEmpty({ message: AuthMessage.LAST_NAME_NOT_EMPTY })
@IsString({ message: AuthMessage.LAST_NAME_NOT_EMPTY })
@Length(2, 50, { message: AuthMessage.LAST_NAME_SHOULD_BE_BETWEEN_2_AND_50 })
@ApiProperty({ description: "Last name", example: "jamshidi" })
lastName: string;
@IsNotEmpty({ message: AuthMessage.BIRTH_DATE_NOT_EMPTY })
@IsString({ message: AuthMessage.BIRTH_DATE_NOT_EMPTY })
@ApiProperty({ description: "Birth date", example: "1403/01/01" })
birthDate: string;
@IsNotEmpty({ message: AuthMessage.NATIONAL_NOT_EMPTY })
@IsNumberString({ no_symbols: true }, { message: AuthMessage.NATIONAL_CODE_INCORRECT })
@Length(10, 10, { message: AuthMessage.NATIONAL_CODE_INCORRECT })
@IsNationalCode({ message: AuthMessage.NATIONAL_CODE_INVALID })
@ApiProperty({ description: "iranian format (10 char)", example: "4569852169" })
nationalCode: string;
@IsNotEmpty({ message: AuthMessage.PASSWORD_NOT_EMPTY })
@IsString({ message: AuthMessage.PASSWORD_FORMAT_INVALID })
@ApiProperty({ description: "password", example: "12S345SS678" })
@MinLength(8, { message: AuthMessage.PASSWORD_LENGTH })
password: string;
}
+69 -1
View File
@@ -10,12 +10,15 @@ import { Role } from "../entities/role.entity";
import { User } from "../entities/user.entity"; import { User } from "../entities/user.entity";
import { RoleEnum } from "../enums/role.enum"; import { RoleEnum } from "../enums/role.enum";
import { UserRepository } from "../repositories/user.repository"; import { UserRepository } from "../repositories/user.repository";
import { CreateWatcherDto } from "../DTO/create-watcher.dto";
import { PasswordService } from "../../utils/providers/password.service";
@Injectable() @Injectable()
export class UsersService { export class UsersService {
constructor( constructor(
private readonly userRepository: UserRepository, private readonly userRepository: UserRepository,
private readonly passwordService: PasswordService,
private readonly em: EntityManager, private readonly em: EntityManager,
) {} ) { }
/*******************************/ /*******************************/
@@ -135,4 +138,69 @@ export class UsersService {
return user; return user;
} }
/*******************************/
async createWatcher(dto: CreateWatcherDto, business: Business) {
const em = this.em.fork();
try {
await em.begin();
const hashedPassword = await this.passwordService.hashPassword(dto.password);
const [role, existPhone, existUser] = await Promise.all([
em.findOne(Role, { name: RoleEnum.WATCHER }),
em.findOne(User, { phone: dto.phone, business: { id: business.id } }),
em.findOne(User, { nationalCode: dto.nationalCode, business: { id: business.id } }),
]);
if (!role) throw new BadRequestException(UserMessage.ROLE_NOT_FOUND);
if (existPhone) throw new BadRequestException(UserMessage.PHONE_EXIST);
if (existUser) throw new BadRequestException(UserMessage.NATIONAL_CODE_EXIST);
const userName = slugify(`${dto.firstName} ${Date.now().toString().slice(-5)}`, { lower: true, trim: true });
const watcher = em.create(User, {
...dto,
userName,
password: hashedPassword,
role,
business,
});
await em.persistAndFlush(watcher);
await em.commit();
return watcher;
} catch (error) {
await em.rollback();
throw error;
}
}
/*******************************/
async getWatchers(business: Business) {
return this.userRepository.find({ business: { id: business.id } })
}
/*******************************/
async getWatcherById(id: string, business: Business) {
return this.userRepository.find({ id, business: { id: business.id } })
}
/*******************************/
async deleteWatcherById(id: string, business: Business) {
const watcher = await this.userRepository.findOne({ id, business: { id: business.id } })
if (!watcher) {
throw new BadRequestException("Not found")
}
watcher.deletedAt = new Date()
await this.em.flush()
return watcher
}
} }
+30 -4
View File
@@ -1,21 +1,47 @@
import { Controller, Get } from "@nestjs/common"; import { Body, Controller, Delete, Get, Param, Post } from "@nestjs/common";
import { ApiOperation } from "@nestjs/swagger"; import { ApiOperation } from "@nestjs/swagger";
import { UsersService } from "./services/users.service"; import { UsersService } from "./services/users.service";
import { AuthGuards } from "../../common/decorators/auth-guard.decorator"; import { AuthGuards } from "../../common/decorators/auth-guard.decorator";
// import { BusinessDec } from "../../common/decorators/business.decorator";
import { UserDec } from "../../common/decorators/user.decorator"; import { UserDec } from "../../common/decorators/user.decorator";
// import { BusinessInterceptor } from "../../core/interceptors/business.interceptor"; import { CreateWatcherDto } from "./DTO/create-watcher.dto";
import { BusinessDec } from "../../common/decorators/business.decorator";
import { Business } from "../businesses/entities/business.entity";
@Controller("users") @Controller("users")
@AuthGuards() @AuthGuards()
// @UseInterceptors(BusinessInterceptor) // @UseInterceptors(BusinessInterceptor)
export class UsersController { export class UsersController {
constructor(private readonly usersService: UsersService) {} constructor(private readonly usersService: UsersService) { }
@ApiOperation({ summary: "Get user profile" }) @ApiOperation({ summary: "Get user profile" })
@Get("me") @Get("me")
getMe(@UserDec("id") userId: string) { getMe(@UserDec("id") userId: string) {
return this.usersService.getMe(userId); return this.usersService.getMe(userId);
} }
@ApiOperation({ summary: "Create Watcher" })
@Post("watcher")
createWatcher(@Body() dto: CreateWatcherDto, @BusinessDec() business: Business) {
return this.usersService.createWatcher(dto, business);
}
@ApiOperation({ summary: "Get Watchers" })
@Get("watcher")
getWatcherList(@BusinessDec() business: Business) {
return this.usersService.getWatchers(business);
}
@ApiOperation({ summary: "Get Watcher by id" })
@Get("watcher/:id")
getWatcher(@Param("id") watcherId: string, @BusinessDec() business: Business) {
return this.usersService.getWatcherById(watcherId, business);
}
@ApiOperation({ summary: "delete Watcher by id" })
@Delete("watcher/:id")
deleteWatcher(@Param("id") watcherId: string, @BusinessDec() business: Business) {
return this.usersService.getWatcherById(watcherId, business);
}
} }
+3 -2
View File
@@ -6,11 +6,12 @@ import { User } from "./entities/user.entity";
import { UsersService } from "./services/users.service"; import { UsersService } from "./services/users.service";
import { UsersController } from "./users.controller"; import { UsersController } from "./users.controller";
import { BusinessesModule } from "../businesses/businesses.module"; import { BusinessesModule } from "../businesses/businesses.module";
import { UtilsModule } from "../utils/utils.module";
@Module({ @Module({
imports: [MikroOrmModule.forFeature([User, Role]), BusinessesModule], imports: [MikroOrmModule.forFeature([User, Role]), BusinessesModule, UtilsModule],
controllers: [UsersController], controllers: [UsersController],
providers: [UsersService], providers: [UsersService],
exports: [UsersService], exports: [UsersService],
}) })
export class UsersModule {} export class UsersModule { }