rez_core 2.0.53 → 2.0.55

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rez_core",
3
- "version": "2.0.53",
3
+ "version": "2.0.55",
4
4
  "description": "",
5
5
  "author": "",
6
6
  "private": false,
@@ -9,8 +9,8 @@ export class MenuController {
9
9
  @UseGuards(JwtAuthGuard)
10
10
  @Get()
11
11
  async getMenu(@Request() req) {
12
- const userId = req.user.userData?.id;
13
- const appcode = req.user.userData?.appcode;
14
- return this.menuService.getUserMenu(userId, appcode);
12
+ const { id: userId, appcode, level_type, level_id } = req.user.userData;
13
+ return this.menuService.getUserMenu(userId, appcode, level_type, level_id);
15
14
  }
15
+
16
16
  }
@@ -37,4 +37,7 @@ export class MenuData {
37
37
 
38
38
  @Column({ type: 'varchar', nullable: true })
39
39
  appcode: string;
40
+
41
+ @Column({ type: 'varchar', nullable: true })
42
+ level_type: string;
40
43
  }
@@ -4,21 +4,21 @@ import { MenuData } from '../entity/menu.entity';
4
4
  import { ModuleAccess } from '../entity/module-access.entity';
5
5
  import { UserRoleMapping } from 'src/module/user/entity/user-role-mapping.entity';
6
6
  import { Role } from 'src/module/user/entity/role.entity';
7
+ import { InjectRepository } from '@nestjs/typeorm';
7
8
 
8
9
  @Injectable()
9
10
  export class MenuRepository extends Repository<MenuData> {
10
- constructor(private readonly dataSource: DataSource) {
11
+ constructor(private readonly dataSource: DataSource,
12
+ @InjectRepository(MenuData) private readonly menuData: Repository<MenuData>
13
+ ) {
11
14
  super(MenuData, dataSource.createEntityManager());
12
15
  }
13
16
 
14
- /**
15
- * Get all role IDs assigned to a user.
16
- */
17
17
  async getUserRoles(userId: number, appcode: string): Promise<number[]> {
18
18
  const roles = await this.dataSource
19
19
  .getRepository(UserRoleMapping)
20
20
  .createQueryBuilder('urm')
21
- .innerJoin('cr_role', 'role', 'role.id = urm.role_id') // manual join
21
+ .innerJoin('cr_role', 'role', 'role.id = urm.role_id')
22
22
  .select('urm.role_id')
23
23
  .where('urm.user_id = :userId', { userId })
24
24
  .andWhere('role.appcode = :appcode', { appcode })
@@ -27,13 +27,7 @@ export class MenuRepository extends Repository<MenuData> {
27
27
  return roles.map((r) => r.urm_role_id);
28
28
  }
29
29
 
30
- /**
31
- * Get module codes that the user has access to based on their role IDs.
32
- */ async getAccessibleModules(
33
- roleIds: number[],
34
- appCode: string,
35
- ): Promise<string[]> {
36
- // Get role codes from role IDs
30
+ async getAccessibleModules(roleIds: number[], appCode: string): Promise<string[]> {
37
31
  const roleCodes = await this.dataSource
38
32
  .getRepository(Role)
39
33
  .createQueryBuilder('role')
@@ -42,32 +36,29 @@ export class MenuRepository extends Repository<MenuData> {
42
36
  .getMany();
43
37
 
44
38
  const codes = roleCodes.map((role) => role.code);
39
+ if (codes.length === 0) return [];
45
40
 
46
- if (codes.length === 0) {
47
- return [];
48
- }
49
-
50
- // Get accessible modules using role codes and appCode
51
41
  const modules = await this.dataSource
52
42
  .getRepository(ModuleAccess)
53
43
  .createQueryBuilder('moduleAccess')
54
44
  .select('moduleAccess.module_code')
55
45
  .where('moduleAccess.role_code IN (:...codes)', { codes })
56
46
  .andWhere('moduleAccess.access_flag > 0')
57
- .andWhere('LOWER(moduleAccess.appcode) = LOWER(:appCode)', { appCode }) // case-insensitive
47
+ .andWhere('LOWER(moduleAccess.appcode) = LOWER(:appCode)', { appCode })
58
48
  .getMany();
59
49
 
60
50
  return modules.map((module) => module.module_code);
61
51
  }
62
52
 
63
- async getMenuItems(
64
- moduleCodes: string[],
65
- appcode: string,
66
- ): Promise<MenuData[]> {
67
- const menuItems = await this.createQueryBuilder('menu')
53
+ /**
54
+ * ✅ FIXED: Use this.createQueryBuilder() instead of this.menuData.createQueryBuilder()
55
+ */
56
+ async getMenuItems(moduleCodes: string[], appcode: string, levelType: string) {
57
+ return await this.menuData.createQueryBuilder('menu')
68
58
  .leftJoin('cr_module', 'module', 'menu.module_code = module.module_code')
69
59
  .where('menu.module_code IN (:...moduleCodes)', { moduleCodes })
70
- .andWhere('LOWER(module.appcode) = LOWER(:appcode)', { appcode }) // appcode filter
60
+ .andWhere('LOWER(module.appcode) = LOWER(:appcode)', { appcode })
61
+ .andWhere('menu.level_type = :levelType', { levelType })
71
62
  .select([
72
63
  'menu.*',
73
64
  'module.component_name AS component',
@@ -77,7 +68,68 @@ export class MenuRepository extends Repository<MenuData> {
77
68
  'module.ui_config AS ui_config',
78
69
  ])
79
70
  .getRawMany();
71
+ }
72
+
73
+
74
+ async resolveUserRoles(
75
+ userId: number,
76
+ appcode: string,
77
+ levelType: string,
78
+ levelId: number,
79
+ ): Promise<number[]> {
80
+ const repo = this.dataSource.getRepository(UserRoleMapping);
81
+
82
+ // 1. Try exact level match
83
+ let roles = await repo.createQueryBuilder('urm')
84
+ .innerJoin('cr_role', 'role', 'role.id = urm.role_id')
85
+ .select('urm.role_id')
86
+ .where('urm.user_id = :userId', { userId })
87
+ .andWhere('urm.level_type = :levelType', { levelType })
88
+ .andWhere('urm.level_id = :levelId', { levelId })
89
+ .andWhere('role.appcode = :appcode', { appcode })
90
+ .getRawMany();
91
+
92
+ if (roles.length) return roles.map(r => r.urm_role_id);
93
+
94
+ // 2. If SCH fallback → BRN → ORG
95
+ if (levelType === 'SCH') {
96
+ const [sch] = await this.dataSource.query(`
97
+ SELECT s.brn_id, b.org_id
98
+ FROM cr_school s
99
+ LEFT JOIN cr_branch b ON s.brn_id = b.id
100
+ WHERE s.id = $1
101
+ `, [levelId]);
102
+
103
+ const branchId = sch?.brn_id;
104
+ const orgId = sch?.org_id;
105
+
106
+ if (branchId) {
107
+ roles = await repo.createQueryBuilder('urm')
108
+ .innerJoin('cr_role', 'role', 'role.id = urm.role_id')
109
+ .select('urm.role_id')
110
+ .where('urm.user_id = :userId', { userId })
111
+ .andWhere('urm.level_type = :levelType', { levelType: 'BRN' })
112
+ .andWhere('urm.level_id = :levelId', { levelId: branchId })
113
+ .andWhere('role.appcode = :appcode', { appcode })
114
+ .getRawMany();
115
+
116
+ if (roles.length) return roles.map(r => r.urm_role_id);
117
+ }
118
+
119
+ if (orgId) {
120
+ roles = await repo.createQueryBuilder('urm')
121
+ .innerJoin('cr_role', 'role', 'role.id = urm.role_id')
122
+ .select('urm.role_id')
123
+ .where('urm.user_id = :userId', { userId })
124
+ .andWhere('urm.level_type = :levelType', { levelType: 'ORG' })
125
+ .andWhere('urm.level_id = :levelId', { levelId: orgId })
126
+ .andWhere('role.appcode = :appcode', { appcode })
127
+ .getRawMany();
128
+
129
+ if (roles.length) return roles.map(r => r.urm_role_id);
130
+ }
131
+ }
80
132
 
81
- return menuItems;
133
+ return [];
82
134
  }
83
135
  }
@@ -1,42 +1,40 @@
1
1
  import { Injectable } from '@nestjs/common';
2
2
  import { MenuRepository } from '../repository/menu.repository';
3
3
  import { MenuData } from '../entity/menu.entity';
4
+ import { DataSource } from 'typeorm';
5
+ import { UserRoleMapping } from 'src/module/user/entity/user-role-mapping.entity';
4
6
 
5
7
  @Injectable()
6
8
  export class MenuService {
7
- constructor(private readonly menuRepository: MenuRepository) {}
9
+ constructor(private readonly menuRepository: MenuRepository,
10
+ private readonly datasource:DataSource
11
+ ) {}
8
12
 
9
13
  /**
10
14
  * Fetch and construct menu hierarchy for a given user.
11
15
  */
12
- async getUserMenu(userId: number, appcode: string): Promise<{ menu: any[] }> {
13
- // Step 1: Get the roles of the user
14
- const roleCodes = await this.menuRepository.getUserRoles(userId, appcode);
15
- if (!roleCodes.length) {
16
- return { menu: [] }; // Return empty menu if user has no roles
17
- }
18
-
19
- // Step 2: Get the modules the user has access to
20
- const moduleCodes = await this.menuRepository.getAccessibleModules(
21
- roleCodes,
22
- appcode,
23
- );
24
- if (!moduleCodes.length) {
25
- return { menu: [] }; // Return empty menu if no accessible modules
26
- }
27
-
28
- // Step 3: Get the menu items based on accessible modules
29
- const menuItems = await this.menuRepository.getMenuItems(
30
- moduleCodes,
31
- appcode,
32
- );
33
-
34
- // Step 4: Build hierarchical menu structure
16
+ async getUserMenu(
17
+ userId: number,
18
+ appcode: string,
19
+ levelType: 'ORG' | 'SCH',
20
+ levelId: number,
21
+ ): Promise<{ menu: any[] }> {
22
+ // Step 1: Resolve roles (with fallback logic inside)
23
+ const roleCodes = await this.menuRepository.resolveUserRoles(userId, appcode, levelType, levelId);
24
+ if (!roleCodes.length) return { menu: [] };
25
+
26
+ // Step 2: Get accessible modules
27
+ const moduleCodes = await this.menuRepository.getAccessibleModules(roleCodes, appcode);
28
+ if (!moduleCodes.length) return { menu: [] };
29
+
30
+ // Step 3: Get menu items for the given level type
31
+ const menuItems = await this.menuRepository.getMenuItems(moduleCodes, appcode, levelType);
32
+
33
+ // Step 4: Build hierarchy
35
34
  const menuTree = this.buildMenuHierarchy(menuItems);
36
-
37
35
  return { menu: menuTree };
38
36
  }
39
-
37
+
40
38
  /**
41
39
  * Converts a flat list of menu items into a hierarchical tree.
42
40
  */
@@ -67,4 +65,8 @@ export class MenuService {
67
65
  async getUserRoles(userId: number, appcode: string): Promise<any> {
68
66
  return this.menuRepository.getUserRoles(userId, appcode);
69
67
  }
68
+
69
+
70
+
71
+
70
72
  }
@@ -89,7 +89,7 @@ export class LoginService {
89
89
 
90
90
  const token = await this.userSessionService.createSession(
91
91
  user,
92
- user.appcode,
92
+ appcode,
93
93
  {
94
94
  level_type: defaultAccess.level_type,
95
95
  level_id: defaultAccess.level_id,