rez_core 1.0.79 → 1.0.82
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/module/meta/service/entity-service-impl.service.d.ts +3 -1
- package/dist/module/meta/service/entity-service-impl.service.js +12 -0
- package/dist/module/meta/service/entity-service-impl.service.js.map +1 -1
- package/dist/module/meta/service/entity-validation.service.d.ts +5 -3
- package/dist/module/meta/service/entity-validation.service.js +26 -16
- package/dist/module/meta/service/entity-validation.service.js.map +1 -1
- package/dist/module/meta/service/media-data.service.d.ts +1 -1
- package/dist/module/user/repository/role.repository.d.ts +4 -1
- package/dist/module/user/repository/role.repository.js +8 -3
- package/dist/module/user/repository/role.repository.js.map +1 -1
- package/dist/module/user/repository/user.repository.d.ts +2 -2
- package/dist/module/user/repository/user.repository.js +16 -10
- package/dist/module/user/repository/user.repository.js.map +1 -1
- package/dist/module/user/service/role.service.js +2 -2
- package/dist/module/user/service/role.service.js.map +1 -1
- package/dist/module/user/service/user.service.d.ts +2 -2
- package/dist/module/user/service/user.service.js +22 -14
- package/dist/module/user/service/user.service.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/module/meta/service/entity-service-impl.service.ts +15 -1
- package/src/module/meta/service/entity-validation.service.ts +34 -18
- package/src/module/user/repository/role.repository.ts +15 -5
- package/src/module/user/repository/user.repository.ts +22 -13
- package/src/module/user/service/role.service.ts +2 -2
- package/src/module/user/service/user.service.ts +46 -16
package/package.json
CHANGED
|
@@ -16,6 +16,7 @@ import { ExcelsheetData } from '../../../utils/dto/excelsheet-data.dto';
|
|
|
16
16
|
import { EntityTableService } from './entity-table.service';
|
|
17
17
|
import { EntityTableColumnService } from './entity-table-column.service';
|
|
18
18
|
import { ENTITYTYPE_ENTITYMASTER } from '../../../constant/global.constant';
|
|
19
|
+
import { EntityValidationService } from './entity-validation.service';
|
|
19
20
|
|
|
20
21
|
@Injectable()
|
|
21
22
|
export class EntityServiceImpl implements EntityService<BaseEntity> {
|
|
@@ -26,12 +27,15 @@ export class EntityServiceImpl implements EntityService<BaseEntity> {
|
|
|
26
27
|
@Inject() protected readonly reflectionHelper: ReflectionHelper;
|
|
27
28
|
@Inject() protected readonly entityListService: EntityListService;
|
|
28
29
|
@Inject() protected readonly loggingService: LoggingService;
|
|
30
|
+
@Inject()
|
|
31
|
+
protected readonly entityValidationService: EntityValidationService;
|
|
32
|
+
|
|
29
33
|
|
|
30
34
|
async createEntity(
|
|
31
35
|
entityData: BaseEntity,
|
|
32
36
|
loggedInUser: UserData | null,
|
|
33
37
|
manager?: EntityManager,
|
|
34
|
-
)
|
|
38
|
+
){
|
|
35
39
|
if (!entityData.entity_type) {
|
|
36
40
|
throw new BadRequestException(`EntityType is missing`);
|
|
37
41
|
}
|
|
@@ -39,6 +43,16 @@ export class EntityServiceImpl implements EntityService<BaseEntity> {
|
|
|
39
43
|
entityData.entity_type,
|
|
40
44
|
);
|
|
41
45
|
|
|
46
|
+
const validationErrors = await this.entityValidationService.validateEntityData(entityData,entityMaster);
|
|
47
|
+
if (validationErrors.length > 0) {
|
|
48
|
+
|
|
49
|
+
return {
|
|
50
|
+
success: false,
|
|
51
|
+
errors: validationErrors,
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
}
|
|
55
|
+
|
|
42
56
|
const repo = manager
|
|
43
57
|
? manager.getRepository(entityMaster.entity_data_class) // <-- Use transaction-safe repo
|
|
44
58
|
: this.reflectionHelper.getRepoService(entityMaster.entity_data_class);
|
|
@@ -2,6 +2,7 @@ import { Injectable } from '@nestjs/common';
|
|
|
2
2
|
import { AttributeMasterService } from 'src/module/meta/service/attribute-master.service';
|
|
3
3
|
import { AttributeMaster } from '../entity/attribute-master.entity';
|
|
4
4
|
import { ReflectionHelper } from 'src/utils/service/reflection-helper.service';
|
|
5
|
+
import { DataSource } from 'typeorm';
|
|
5
6
|
|
|
6
7
|
interface ValidationError {
|
|
7
8
|
field: string;
|
|
@@ -12,7 +13,8 @@ interface ValidationError {
|
|
|
12
13
|
export class EntityValidationService {
|
|
13
14
|
constructor(
|
|
14
15
|
private readonly attributeMasterService: AttributeMasterService,
|
|
15
|
-
private readonly reflectionHelper: ReflectionHelper
|
|
16
|
+
private readonly reflectionHelper: ReflectionHelper,
|
|
17
|
+
private dataSource: DataSource
|
|
16
18
|
) {}
|
|
17
19
|
|
|
18
20
|
/**
|
|
@@ -27,11 +29,11 @@ export class EntityValidationService {
|
|
|
27
29
|
attributeData
|
|
28
30
|
.filter(attr => attr.required)
|
|
29
31
|
.forEach(attr => {
|
|
30
|
-
const value = entityData[attr.
|
|
32
|
+
const value = entityData[attr.attribute_key];
|
|
31
33
|
if (!this.hasValidValue(value)) {
|
|
32
34
|
errors.push({
|
|
33
|
-
field: attr.
|
|
34
|
-
message: `Field
|
|
35
|
+
field: attr.name,
|
|
36
|
+
message: `Field ${attr.name} is required.`,
|
|
35
37
|
});
|
|
36
38
|
}
|
|
37
39
|
});
|
|
@@ -45,24 +47,37 @@ export class EntityValidationService {
|
|
|
45
47
|
async validateUniqueFields(
|
|
46
48
|
entityData: Record<string, any>,
|
|
47
49
|
attributeData: AttributeMaster[],
|
|
48
|
-
entityType: string
|
|
50
|
+
entityType: string,
|
|
51
|
+
db_table_name: string
|
|
49
52
|
): Promise<ValidationError[]> {
|
|
50
53
|
const errors: ValidationError[] = [];
|
|
51
54
|
|
|
52
|
-
const repo = this.reflectionHelper.getRepoService(entityData.entity_type);
|
|
53
|
-
|
|
54
|
-
if (!repo) {
|
|
55
|
-
throw new Error(`Repository service not found for entityType: ${entityType}`);
|
|
56
|
-
}
|
|
57
|
-
|
|
58
55
|
for (const attr of attributeData.filter(a => a.is_unique)) {
|
|
59
|
-
const value = entityData[attr.
|
|
56
|
+
const value = entityData[attr.attribute_key];
|
|
57
|
+
|
|
60
58
|
if (this.hasValidValue(value)) {
|
|
61
|
-
|
|
59
|
+
let qb = this.dataSource
|
|
60
|
+
.createQueryBuilder()
|
|
61
|
+
.select('*')
|
|
62
|
+
.from(db_table_name, db_table_name)
|
|
63
|
+
.where(`${db_table_name}.${attr.attribute_key} = :value`, { value });
|
|
64
|
+
|
|
65
|
+
// Add AND condition for organization_id if present
|
|
66
|
+
const orgId = entityData.organization_id;
|
|
67
|
+
|
|
68
|
+
if (orgId !== undefined && orgId !== null) {
|
|
69
|
+
qb = qb.andWhere(`${db_table_name}.organization_id = :organization_id`, {
|
|
70
|
+
organization_id: orgId,
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
const existing = await qb.limit(1).getRawOne();
|
|
76
|
+
|
|
62
77
|
if (existing) {
|
|
63
78
|
errors.push({
|
|
64
|
-
field: attr.
|
|
65
|
-
message: `Field
|
|
79
|
+
field: attr.name,
|
|
80
|
+
message: `Field ${attr.name} must be unique. Value ${value} already exists.`,
|
|
66
81
|
});
|
|
67
82
|
}
|
|
68
83
|
}
|
|
@@ -71,17 +86,18 @@ export class EntityValidationService {
|
|
|
71
86
|
return errors;
|
|
72
87
|
}
|
|
73
88
|
|
|
74
|
-
|
|
89
|
+
|
|
75
90
|
/**
|
|
76
91
|
* Validates both required and unique fields for a given entity type.
|
|
77
92
|
*/
|
|
78
93
|
async validateEntityData(
|
|
79
|
-
entityData: Record<string, any
|
|
94
|
+
entityData: Record<string, any>,
|
|
95
|
+
entityMaster
|
|
80
96
|
): Promise<ValidationError[]> {
|
|
81
97
|
const attributes = await this.attributeMasterService.findAttributesByMappedEntityType(entityData.entity_type);
|
|
82
98
|
|
|
83
99
|
const requiredErrors = this.validateRequiredFields(entityData, attributes);
|
|
84
|
-
const uniqueErrors = await this.validateUniqueFields(entityData, attributes, entityData.entity_type);
|
|
100
|
+
const uniqueErrors = await this.validateUniqueFields(entityData, attributes, entityData.entity_type,entityMaster.db_table_name);
|
|
85
101
|
|
|
86
102
|
return [...requiredErrors, ...uniqueErrors];
|
|
87
103
|
}
|
|
@@ -17,16 +17,26 @@ export class RoleRepository {
|
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
|
|
20
|
-
public async isRoleNameExists(
|
|
20
|
+
public async isRoleNameExists(
|
|
21
|
+
name: string,
|
|
22
|
+
options?: { excludeRoleId?: number; organization_id?: number }
|
|
23
|
+
): Promise<boolean> {
|
|
21
24
|
const query = this.roleRepo
|
|
22
25
|
.createQueryBuilder('role')
|
|
23
26
|
.where('role.name = :name', { name });
|
|
24
|
-
|
|
25
|
-
if (excludeRoleId) {
|
|
26
|
-
query.andWhere('role.id != :excludeRoleId', { excludeRoleId });
|
|
27
|
+
|
|
28
|
+
if (options?.excludeRoleId) {
|
|
29
|
+
query.andWhere('role.id != :excludeRoleId', { excludeRoleId: options.excludeRoleId });
|
|
27
30
|
}
|
|
28
|
-
|
|
31
|
+
|
|
32
|
+
if (options?.organization_id !== undefined) {
|
|
33
|
+
query.andWhere('role.organization_id = :organization_id', {
|
|
34
|
+
organization_id: options.organization_id,
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
|
|
29
38
|
const existingRole = await query.getOne();
|
|
30
39
|
return !!existingRole;
|
|
31
40
|
}
|
|
41
|
+
|
|
32
42
|
}
|
|
@@ -9,23 +9,32 @@ export class UserRepository {
|
|
|
9
9
|
@InjectRepository(UserData) private userRepository: Repository<UserData>,
|
|
10
10
|
) {}
|
|
11
11
|
|
|
12
|
-
async
|
|
13
|
-
if (email) {
|
|
14
|
-
return this.userRepository.findOne({ where: { email_id: email } });
|
|
15
|
-
}
|
|
16
|
-
return null;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
async findById(userId: number): Promise<UserData | null> {
|
|
12
|
+
async findById(userId: number ): Promise<UserData | null> {
|
|
20
13
|
return this.userRepository.findOne({ where: { id: userId } });
|
|
21
14
|
}
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
15
|
+
async findByEmailId(email: string, organization_id?: number): Promise<UserData | null> {
|
|
16
|
+
if (!email) return null;
|
|
17
|
+
|
|
18
|
+
const where: any = { email_id: email };
|
|
19
|
+
if (organization_id !== undefined) {
|
|
20
|
+
where.organization_id = organization_id;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return this.userRepository.findOne({ where });
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
async findByMobile(mobile: string, organization_id?: number): Promise<UserData | null> {
|
|
27
|
+
if (!mobile) return null;
|
|
28
|
+
|
|
29
|
+
const where: any = { mobile: mobile };
|
|
30
|
+
if (organization_id !== undefined) {
|
|
31
|
+
where.organization_id = organization_id;
|
|
26
32
|
}
|
|
27
|
-
|
|
33
|
+
|
|
34
|
+
return this.userRepository.findOne({ where });
|
|
28
35
|
}
|
|
36
|
+
|
|
37
|
+
|
|
29
38
|
|
|
30
39
|
async saveUser(user: UserData): Promise<UserData> {
|
|
31
40
|
return this.userRepository.save(user);
|
|
@@ -27,7 +27,7 @@ export class RoleService extends EntityServiceImpl {
|
|
|
27
27
|
): Promise<BaseEntity> {
|
|
28
28
|
let role = entityData as Role;
|
|
29
29
|
|
|
30
|
-
if (await this.roleRepository.isRoleNameExists(role.name)) {
|
|
30
|
+
if (await this.roleRepository.isRoleNameExists(role.name,{organization_id:entityData.organization_id})) {
|
|
31
31
|
throw new BadRequestException('Role name already exists.');
|
|
32
32
|
}
|
|
33
33
|
|
|
@@ -98,7 +98,7 @@ export class RoleService extends EntityServiceImpl {
|
|
|
98
98
|
}
|
|
99
99
|
|
|
100
100
|
if (
|
|
101
|
-
await this.roleRepository.isRoleNameExists(entityData.name, entityData.id)
|
|
101
|
+
await this.roleRepository.isRoleNameExists(entityData.name, {excludeRoleId:entityData.id})
|
|
102
102
|
) {
|
|
103
103
|
throw new BadRequestException('Role name already exists.');
|
|
104
104
|
}
|
|
@@ -39,12 +39,16 @@ export class UserService extends EntityServiceImpl {
|
|
|
39
39
|
let userData = entityData as CreateUserDto;
|
|
40
40
|
let existingUser = await this.userRepository.findByEmailId(
|
|
41
41
|
userData.email_id,
|
|
42
|
+
userData.organization_id
|
|
42
43
|
);
|
|
43
44
|
if (existingUser) {
|
|
44
45
|
throw new BadRequestException('User already exists');
|
|
45
46
|
}
|
|
46
47
|
|
|
47
|
-
existingUser = await this.userRepository.findByMobile(
|
|
48
|
+
existingUser = await this.userRepository.findByMobile(
|
|
49
|
+
userData.mobile,
|
|
50
|
+
userData.organization_id
|
|
51
|
+
);
|
|
48
52
|
if (existingUser) {
|
|
49
53
|
throw new BadRequestException('User already exists');
|
|
50
54
|
}
|
|
@@ -113,37 +117,63 @@ export class UserService extends EntityServiceImpl {
|
|
|
113
117
|
entityData: BaseEntity,
|
|
114
118
|
loggedInUserData: UserData,
|
|
115
119
|
): Promise<BaseEntity> {
|
|
116
|
-
|
|
117
|
-
|
|
120
|
+
const userDto = entityData as UpdateUserDto;
|
|
121
|
+
|
|
122
|
+
// Fetch the current user data from DB to get the existing encrypted password
|
|
123
|
+
const existingUser = await this.userRepository.findById(entityData.id);
|
|
124
|
+
|
|
125
|
+
if (!existingUser) {
|
|
126
|
+
throw new BadRequestException('User not found');
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// If password is being updated, check if it's the same as existing one
|
|
118
130
|
if (userDto.password) {
|
|
119
|
-
const
|
|
131
|
+
const decryptedPassword = EncryptUtilService.decryptGCM(
|
|
132
|
+
existingUser.password,
|
|
133
|
+
this.masterKey,
|
|
134
|
+
this.masterIv,
|
|
135
|
+
);
|
|
136
|
+
|
|
137
|
+
if (decryptedPassword === userDto.password) {
|
|
138
|
+
throw new BadRequestException(
|
|
139
|
+
'New password cannot be the same as the current password',
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Encrypt new password
|
|
144
|
+
const encryptedPassword = EncryptUtilService.encryptGCM(
|
|
120
145
|
userDto.password,
|
|
121
146
|
this.masterKey,
|
|
122
147
|
this.masterIv,
|
|
123
148
|
);
|
|
124
|
-
userDto.password =
|
|
149
|
+
userDto.password = encryptedPassword;
|
|
125
150
|
}
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
151
|
+
|
|
152
|
+
const userData = plainToInstance(UserData, userDto);
|
|
153
|
+
|
|
154
|
+
const savedData = await super.updateEntity(userData, loggedInUserData);
|
|
155
|
+
|
|
156
|
+
// Update roles if provided
|
|
129
157
|
if (userDto.roles) {
|
|
130
|
-
|
|
131
|
-
for (const role
|
|
132
|
-
|
|
158
|
+
await this.userRoleMappingService.deleteByUserId(savedData.id); // prevent duplicates
|
|
159
|
+
for (const role of userDto.roles) {
|
|
160
|
+
const userRoleMapping = new UserRoleMapping(
|
|
133
161
|
savedData.id,
|
|
134
|
-
Number(
|
|
162
|
+
Number(role),
|
|
135
163
|
);
|
|
136
164
|
await this.userRoleMappingService.assignUserRole(userRoleMapping);
|
|
137
165
|
}
|
|
138
166
|
}
|
|
167
|
+
|
|
139
168
|
return savedData;
|
|
140
169
|
}
|
|
170
|
+
|
|
141
171
|
|
|
142
|
-
async findByEmailId(email_id: string): Promise<UserData | null> {
|
|
143
|
-
return await this.userRepository.findByEmailId(email_id);
|
|
172
|
+
async findByEmailId(email_id: string,organization_id?: number): Promise<UserData | null> {
|
|
173
|
+
return await this.userRepository.findByEmailId(email_id,organization_id);
|
|
144
174
|
}
|
|
145
175
|
|
|
146
|
-
async findByMobile(mobile: string) {
|
|
147
|
-
return await this.userRepository.findByMobile(mobile);
|
|
176
|
+
async findByMobile(mobile: string,organization_id: number): Promise<UserData | null> {
|
|
177
|
+
return await this.userRepository.findByMobile(mobile,organization_id);
|
|
148
178
|
}
|
|
149
179
|
}
|