260318:1237 Fix UUID #4
Build and Deploy / deploy (push) Successful in 11m17s

This commit is contained in:
admin
2026-03-18 12:37:29 +07:00
parent 5d89079c2a
commit ba642e7e42
71 changed files with 533 additions and 319 deletions
@@ -5,7 +5,6 @@ import {
MinLength,
IsOptional,
IsBoolean,
IsInt,
} from 'class-validator';
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
@@ -44,10 +43,12 @@ export class CreateUserDto {
@IsOptional()
lineId?: string;
@ApiPropertyOptional({ description: 'Primary Organization ID', example: 1 })
@IsInt()
@ApiPropertyOptional({
description: 'Primary Organization ID or UUID',
example: 1,
})
@IsOptional()
primaryOrganizationId?: number; // รับเป็น ID ของ Organization
primaryOrganizationId?: number | string; // ADR-019: Accept INT or UUID
@ApiPropertyOptional({ description: 'Is user active?', default: true })
@IsBoolean()
@@ -16,11 +16,9 @@ export class SearchUserDto {
@Type(() => Number)
roleId?: number;
@ApiPropertyOptional({ description: 'Filter by Organization ID' })
@ApiPropertyOptional({ description: 'Filter by Organization ID or UUID' })
@IsOptional()
@IsInt()
@Type(() => Number)
primaryOrganizationId?: number;
primaryOrganizationId?: number | string; // ADR-019: Accept INT or UUID
@ApiPropertyOptional({ description: 'Page number', default: 1 })
@IsOptional()
+40 -2
View File
@@ -17,6 +17,7 @@ import { Role } from './entities/role.entity';
import { Permission } from './entities/permission.entity';
import { CreateUserDto } from './dto/create-user.dto';
import { UpdateUserDto } from './dto/update-user.dto';
import { Organization } from '../organization/entities/organization.entity';
@Injectable()
export class UserService {
@@ -30,13 +31,35 @@ export class UserService {
@Inject(CACHE_MANAGER) private cacheManager: Cache
) {}
/**
* ADR-019: Resolve organizationId (INT or UUID string) to internal INT ID
*/
private async resolveOrganizationId(orgId: number | string): Promise<number> {
if (typeof orgId === 'number') return orgId;
const num = Number(orgId);
if (!isNaN(num)) return num;
const org = await this.usersRepository.manager.findOne(Organization, {
where: { uuid: orgId },
select: ['id'],
});
if (!org)
throw new NotFoundException(`Organization with UUID ${orgId} not found`);
return org.id;
}
// 1. สร้างผู้ใช้ (Hash Password ก่อนบันทึก)
async create(createUserDto: CreateUserDto): Promise<User> {
const salt = await bcrypt.genSalt();
const hashedPassword = await bcrypt.hash(createUserDto.password, salt);
// ADR-019: Resolve UUID→INT for primaryOrganizationId
const resolvedOrgId = createUserDto.primaryOrganizationId
? await this.resolveOrganizationId(createUserDto.primaryOrganizationId)
: undefined;
const newUser = this.usersRepository.create({
...createUserDto,
primaryOrganizationId: resolvedOrgId,
password: hashedPassword,
});
@@ -91,8 +114,12 @@ export class UserService {
}
if (primaryOrganizationId) {
// ADR-019: Resolve UUID→INT for filtering
const resolvedOrgId = await this.resolveOrganizationId(
primaryOrganizationId
);
query.andWhere('user.primaryOrganizationId = :orgId', {
orgId: primaryOrganizationId,
orgId: resolvedOrgId,
});
}
@@ -164,7 +191,18 @@ export class UserService {
updateUserDto.password = await bcrypt.hash(updateUserDto.password, salt);
}
const updatedUser = this.usersRepository.merge(user, updateUserDto);
// ADR-019: Resolve UUID→INT for primaryOrganizationId before merge
const resolvedDto: Record<string, unknown> = { ...updateUserDto };
if (updateUserDto.primaryOrganizationId !== undefined) {
resolvedDto.primaryOrganizationId = await this.resolveOrganizationId(
updateUserDto.primaryOrganizationId
);
}
const updatedUser = this.usersRepository.merge(
user,
resolvedDto as Partial<User>
);
const savedUser = await this.usersRepository.save(updatedUser);
// ⚠️ สำคัญ: เมื่อมีการแก้ไขข้อมูล User ต้องเคลียร์ Cache สิทธิ์เสมอ