@drax/identity-back 0.0.15 → 0.0.16

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.
Files changed (106) hide show
  1. package/dist/factory/TenantServiceFactory.js +24 -0
  2. package/dist/factory/UserServiceFactory.js +1 -1
  3. package/dist/graphql/resolvers/role.resolvers.js +12 -1
  4. package/dist/graphql/resolvers/tenant.resolvers.js +121 -0
  5. package/dist/graphql/resolvers/user.resolvers.js +5 -2
  6. package/dist/graphql/types/tenant.graphql +28 -0
  7. package/dist/graphql/types/user.graphql +3 -0
  8. package/dist/index.js +6 -3
  9. package/dist/interfaces/ITenant.js +1 -0
  10. package/dist/interfaces/ITenantRepository.js +1 -0
  11. package/dist/middleware/rbacMiddleware.js +1 -4
  12. package/dist/models/TenantModel.js +18 -0
  13. package/dist/models/UserModel.js +5 -0
  14. package/dist/permissions/IdentityPermissions.js +5 -0
  15. package/dist/rbac/Rbac.js +6 -0
  16. package/dist/repository/mongo/RoleMongoRepository.js +7 -6
  17. package/dist/repository/mongo/TenantMongoRepository.js +45 -0
  18. package/dist/repository/mongo/UserMongoRepository.js +19 -6
  19. package/dist/repository/sqlite/RoleSqliteRepository.js +24 -5
  20. package/dist/repository/sqlite/TenantSqliteRepository.js +106 -0
  21. package/dist/repository/sqlite/UserSqliteRepository.js +43 -37
  22. package/dist/routes/RoleRoutes.js +10 -1
  23. package/dist/routes/TenantRoutes.js +183 -0
  24. package/dist/routes/UserRoutes.js +6 -1
  25. package/dist/services/RoleService.js +0 -5
  26. package/dist/services/TenantService.js +59 -0
  27. package/dist/services/UserService.js +1 -1
  28. package/dist/utils/AuthUtils.js +4 -3
  29. package/dist/zod/TenantZod.js +8 -0
  30. package/package.json +2 -2
  31. package/src/factory/TenantServiceFactory.ts +33 -0
  32. package/src/factory/UserServiceFactory.ts +1 -1
  33. package/src/graphql/resolvers/role.resolvers.ts +13 -1
  34. package/src/graphql/resolvers/tenant.resolvers.ts +119 -0
  35. package/src/graphql/resolvers/user.resolvers.ts +5 -2
  36. package/src/graphql/types/tenant.graphql +28 -0
  37. package/src/graphql/types/user.graphql +3 -0
  38. package/src/index.ts +6 -0
  39. package/src/interfaces/ITenant.ts +9 -0
  40. package/src/interfaces/ITenantRepository.ts +15 -0
  41. package/src/interfaces/IUser.ts +4 -1
  42. package/src/middleware/rbacMiddleware.ts +4 -7
  43. package/src/models/TenantModel.ts +32 -0
  44. package/src/models/UserModel.ts +5 -0
  45. package/src/permissions/IdentityPermissions.ts +7 -0
  46. package/src/rbac/Rbac.ts +11 -3
  47. package/src/repository/mongo/RoleMongoRepository.ts +7 -6
  48. package/src/repository/mongo/TenantMongoRepository.ts +62 -0
  49. package/src/repository/mongo/UserMongoRepository.ts +20 -6
  50. package/src/repository/sqlite/RoleSqliteRepository.ts +27 -6
  51. package/src/repository/sqlite/TenantSqliteRepository.ts +139 -0
  52. package/src/repository/sqlite/UserSqliteRepository.ts +52 -40
  53. package/src/routes/RoleRoutes.ts +9 -1
  54. package/src/routes/TenantRoutes.ts +178 -0
  55. package/src/routes/UserRoutes.ts +6 -1
  56. package/src/services/RoleService.ts +1 -4
  57. package/src/services/TenantService.ts +74 -0
  58. package/src/services/UserService.ts +1 -1
  59. package/src/utils/AuthUtils.ts +4 -3
  60. package/src/zod/TenantZod.ts +14 -0
  61. package/tsconfig.tsbuildinfo +1 -1
  62. package/types/factory/TenantServiceFactory.d.ts +4 -0
  63. package/types/factory/TenantServiceFactory.d.ts.map +1 -0
  64. package/types/graphql/resolvers/role.resolvers.d.ts.map +1 -1
  65. package/types/graphql/resolvers/tenant.resolvers.d.ts +44 -0
  66. package/types/graphql/resolvers/tenant.resolvers.d.ts.map +1 -0
  67. package/types/graphql/resolvers/user.resolvers.d.ts +2 -1
  68. package/types/graphql/resolvers/user.resolvers.d.ts.map +1 -1
  69. package/types/index.d.ts +4 -1
  70. package/types/index.d.ts.map +1 -1
  71. package/types/interfaces/ITenant.d.ts +7 -0
  72. package/types/interfaces/ITenant.d.ts.map +1 -0
  73. package/types/interfaces/ITenantRepository.d.ts +15 -0
  74. package/types/interfaces/ITenantRepository.d.ts.map +1 -0
  75. package/types/interfaces/IUser.d.ts +4 -0
  76. package/types/interfaces/IUser.d.ts.map +1 -1
  77. package/types/middleware/rbacMiddleware.d.ts.map +1 -1
  78. package/types/models/TenantModel.d.ts +16 -0
  79. package/types/models/TenantModel.d.ts.map +1 -0
  80. package/types/models/UserModel.d.ts.map +1 -1
  81. package/types/permissions/IdentityPermissions.d.ts +6 -1
  82. package/types/permissions/IdentityPermissions.d.ts.map +1 -1
  83. package/types/rbac/Rbac.d.ts +4 -2
  84. package/types/rbac/Rbac.d.ts.map +1 -1
  85. package/types/repository/mongo/RoleMongoRepository.d.ts.map +1 -1
  86. package/types/repository/mongo/TenantMongoRepository.d.ts +15 -0
  87. package/types/repository/mongo/TenantMongoRepository.d.ts.map +1 -0
  88. package/types/repository/mongo/UserMongoRepository.d.ts +2 -2
  89. package/types/repository/mongo/UserMongoRepository.d.ts.map +1 -1
  90. package/types/repository/sqlite/RoleSqliteRepository.d.ts +2 -0
  91. package/types/repository/sqlite/RoleSqliteRepository.d.ts.map +1 -1
  92. package/types/repository/sqlite/TenantSqliteRepository.d.ts +19 -0
  93. package/types/repository/sqlite/TenantSqliteRepository.d.ts.map +1 -0
  94. package/types/repository/sqlite/UserSqliteRepository.d.ts +4 -2
  95. package/types/repository/sqlite/UserSqliteRepository.d.ts.map +1 -1
  96. package/types/routes/RoleRoutes.d.ts.map +1 -1
  97. package/types/routes/TenantRoutes.d.ts +4 -0
  98. package/types/routes/TenantRoutes.d.ts.map +1 -0
  99. package/types/routes/UserRoutes.d.ts.map +1 -1
  100. package/types/services/RoleService.d.ts.map +1 -1
  101. package/types/services/TenantService.d.ts +16 -0
  102. package/types/services/TenantService.d.ts.map +1 -0
  103. package/types/utils/AuthUtils.d.ts +3 -2
  104. package/types/utils/AuthUtils.d.ts.map +1 -1
  105. package/types/zod/TenantZod.d.ts +10 -0
  106. package/types/zod/TenantZod.d.ts.map +1 -0
@@ -0,0 +1,139 @@
1
+ import {ITenant} from '../../interfaces/ITenant'
2
+ import {ITenantRepository} from '../../interfaces/ITenantRepository'
3
+ import {UUID} from "crypto";
4
+ import sqlite from "better-sqlite3";
5
+ import {randomUUID} from "node:crypto";
6
+ import {IPaginateFilter, IPaginateResult, ValidationError} from "@drax/common-back";
7
+ import {SqliteErrorToValidationError} from "@drax/common-back";
8
+ import {IID} from "../../interfaces/IID";
9
+
10
+ const tenantTableSQL: string = `
11
+ CREATE TABLE IF NOT EXISTS tenants
12
+ (
13
+ id TEXT PRIMARY KEY,
14
+ name TEXT
15
+ );
16
+ `;
17
+
18
+ class TenantSqliteRepository implements ITenantRepository{
19
+
20
+ private db: any;
21
+
22
+ constructor(DATABASE:string, verbose:boolean = false) {
23
+ this.db = new sqlite(DATABASE, {verbose: verbose ? console.log : null});
24
+ this.table()
25
+ }
26
+
27
+ table() {
28
+ this.db.exec(tenantTableSQL);
29
+ }
30
+
31
+
32
+
33
+ async create(tenantData: ITenant): Promise<ITenant> {
34
+ try{
35
+
36
+ if(!tenantData.id){
37
+ tenantData.id = randomUUID()
38
+ }
39
+
40
+
41
+ const fields = Object.keys(tenantData)
42
+ .map(field => `${field}`)
43
+ .join(', ');
44
+
45
+ const values = Object.keys(tenantData)
46
+ .map(field => `@${field}`)
47
+ .join(', ');
48
+
49
+ const stmt = this.db.prepare(`INSERT INTO tenants (${fields}) VALUES (${values})`);
50
+ stmt.run(tenantData)
51
+ return this.findById(tenantData.id as UUID)
52
+ }catch (e){
53
+ console.log(e)
54
+ throw SqliteErrorToValidationError(e, tenantData)
55
+ }
56
+ }
57
+
58
+ async findById(id: IID): Promise<ITenant | null>{
59
+ const tenant = this.db.prepare('SELECT * FROM tenants WHERE id = ?').get(id);
60
+ if(tenant){
61
+ tenant.permissions = tenant.permissions ? tenant.permissions.split(",") : []
62
+ return tenant
63
+ }
64
+ return undefined
65
+ }
66
+
67
+ async findByName(name: string): Promise<ITenant | null>{
68
+ const tenant = this.db.prepare('SELECT * FROM tenants WHERE name = ?').get(name);
69
+ if(tenant){
70
+ tenant.permissions = tenant.permissions ? tenant.permissions.split(",") : []
71
+ return tenant
72
+ }
73
+ return undefined
74
+ }
75
+
76
+ async update(id: IID, tenantData: ITenant): Promise<ITenant> {
77
+ try{
78
+ const setClauses = Object.keys(tenantData)
79
+ .map(field => `${field} = @${field}`)
80
+ .join(', ');
81
+ tenantData.id = id
82
+ const stmt = this.db.prepare( `UPDATE tenants SET ${setClauses} WHERE id = @id `);
83
+ stmt.run(tenantData);
84
+ return this.findById(id)
85
+ }catch (e){
86
+ console.log(e)
87
+ throw SqliteErrorToValidationError(e, tenantData)
88
+ }
89
+
90
+ }
91
+
92
+ async delete(id: IID): Promise<boolean> {
93
+ const stmt = this.db.prepare('DELETE FROM tenants WHERE id = ?');
94
+ stmt.run(id);
95
+ return true
96
+ }
97
+
98
+ async deleteAll(): Promise<boolean> {
99
+ const stmt = this.db.prepare('DELETE FROM tenants');
100
+ stmt.run();
101
+ return true
102
+ }
103
+
104
+ async fetchAll(): Promise<ITenant[]>{
105
+ const tenants = this.db.prepare('SELECT * FROM tenants').all();
106
+ for (const tenant of tenants) {
107
+ tenant.permissions = tenant.permissions? tenant.permissions.split(",") : []
108
+ }
109
+ return tenants
110
+ }
111
+
112
+ async paginate(page = 1, limit = 5, search=""): Promise<IPaginateResult>{
113
+ const offset = page > 1 ? (page - 1) * limit : 0
114
+
115
+ let where=""
116
+ if (search) {
117
+ where = ` WHERE name LIKE '%${search}%'`
118
+ }
119
+
120
+ const rCount = this.db.prepare('SELECT COUNT(*) as count FROM tenants'+where).get();
121
+ const tenants = this.db.prepare('SELECT * FROM tenants LIMIT ? OFFSET ?'+where).all([limit, offset]);
122
+
123
+ for (const tenant of tenants) {
124
+ tenant.permissions = tenant.permissions? tenant.permissions.split(",") : []
125
+ }
126
+
127
+
128
+ return {
129
+ page: page,
130
+ limit: limit,
131
+ total: rCount.count,
132
+ items: tenants
133
+ }
134
+ }
135
+
136
+
137
+ }
138
+
139
+ export default TenantSqliteRepository
@@ -3,50 +3,40 @@ import sqlite from "better-sqlite3";
3
3
  import {randomUUID} from "node:crypto";
4
4
  import {UUID} from "crypto";
5
5
  import {IUserRepository} from "../../interfaces/IUserRepository";
6
- import type {IPaginateResult} from "@drax/common-back";
7
- import {mongoose, SqliteErrorToValidationError, ValidationError} from "@drax/common-back";
6
+ import type {IPaginateFilter, IPaginateResult} from "@drax/common-back";
7
+ import { SqliteErrorToValidationError, ValidationError} from "@drax/common-back";
8
8
  import RoleSqliteRepository from "./RoleSqliteRepository.js";
9
+ import TenantSqliteRepository from "./TenantSqliteRepository.js";
9
10
  import {IID} from "../../interfaces/IID";
10
11
 
11
12
 
12
13
  const userTableSQL: string = `
13
14
  CREATE TABLE IF NOT EXISTS users
14
15
  (
15
- id
16
- TEXT
17
- PRIMARY
18
- KEY,
19
- name
20
- TEXT,
21
- username
22
- TEXT
23
- UNIQUE,
24
- active
25
- INTEGER,
26
- password
27
- TEXT,
28
- email
29
- TEXT
30
- UNIQUE,
31
- phone
32
- TEXT,
33
- role
34
- TEXT,
35
- groups
36
- TEXT,
37
- avatar
38
- TEXT
16
+ id TEXT PRIMARY KEY,
17
+ name TEXT,
18
+ username TEXT UNIQUE,
19
+ active INTEGER,
20
+ password TEXT,
21
+ email TEXT UNIQUE,
22
+ phone TEXT,
23
+ role TEXT,
24
+ tenant TEXT,
25
+ groups TEXT,
26
+ avatar TEXT
39
27
  );
40
28
  `;
41
29
 
42
30
  class UserSqliteRepository implements IUserRepository {
43
31
  private db: any;
44
32
  private roleRepository: RoleSqliteRepository;
33
+ private tenantRepository: TenantSqliteRepository;
45
34
 
46
35
  constructor(DATABASE: string, verbose: boolean = false) {
47
36
  this.db = new sqlite(DATABASE, {verbose: verbose ? console.log : null});
48
37
  this.roleRepository = new RoleSqliteRepository(DATABASE, verbose)
49
-
38
+ this.tenantRepository = new TenantSqliteRepository(DATABASE, verbose)
39
+ this.table()
50
40
  }
51
41
 
52
42
  table() {
@@ -81,10 +71,6 @@ class UserSqliteRepository implements IUserRepository {
81
71
  .map(field => `@${field}`)
82
72
  .join(', ');
83
73
 
84
- /*console.log("fields", fields)
85
- console.log("values",values)
86
- console.log("userData",userData)*/
87
-
88
74
  const stmt = this.db.prepare(`INSERT INTO users (${fields})
89
75
  VALUES (${values})`);
90
76
  stmt.run(userData)
@@ -135,6 +121,7 @@ class UserSqliteRepository implements IUserRepository {
135
121
  return null
136
122
  }
137
123
  user.role = await this.findRoleById(user.role)
124
+ user.tenant = await this.findTenantById(user.tenant)
138
125
  return user
139
126
  }
140
127
 
@@ -144,28 +131,49 @@ class UserSqliteRepository implements IUserRepository {
144
131
  return null
145
132
  }
146
133
  user.role = await this.findRoleById(user.role)
134
+ user.tenant = await this.findTenantById(user.tenant)
147
135
  return user
148
136
  }
149
137
 
150
- async paginate(page: number = 1, limit: number = 5, search?: string): Promise<IPaginateResult> {
138
+ async paginate(page: number = 1, limit: number = 5, search: string = "", filters:IPaginateFilter[] = []): Promise<IPaginateResult> {
151
139
 
152
140
  const offset = page > 1 ? (page - 1) * limit : 0
153
141
 
154
- let where
142
+ let where=""
155
143
  if (search) {
156
- where = ` WHERE name LIKE '%${search}%' OR username LIKE '%${search}%'`
144
+ where = ` WHERE (name LIKE '%${search}%' OR username LIKE '%${search}%') `
145
+ }
146
+
147
+ let whereFilters= []
148
+ if(filters && filters.length > 0 ){
149
+ where = where ? ` AND ` : ` WHERE `
150
+ for(const filter of filters){
151
+ if(filter.operator === '$eq'){
152
+ whereFilters.push(` ${filter.field} = '${filter.value}' `)
153
+ }
154
+ if(filter.operator === '$ne'){
155
+ whereFilters.push(` ${filter.field} != '${filter.value}' `)
156
+ }
157
+ if(filter.operator === '$in'){
158
+ whereFilters.push(` ${filter.field} LIKE '%${filter.value}%' `)
159
+ }
160
+ }
161
+ where += whereFilters.join(" AND ")
157
162
  }
158
163
 
164
+ // console.log("paginate where ", where, "search", search, "filters", filters, "whereFilters", whereFilters)
165
+
159
166
  const rCount = this.db.prepare('SELECT COUNT(*) as count FROM users' + where).get();
160
- const users = this.db.prepare('SELECT * FROM users LIMIT ? OFFSET ?' + where).all([limit, offset]);
167
+
168
+ const users = this.db.prepare('SELECT * FROM users' + where + ' LIMIT ? OFFSET ?').all([limit, offset]);
161
169
 
162
170
  for (const user of users) {
171
+
163
172
  let role = await this.findRoleById(user.role)
164
- if (role) {
165
- user.role = role
166
- } else {
167
- user.role = null
168
- }
173
+ user.role = role ? role : null
174
+
175
+ let tenant = await this.findTenantById(user.tenant)
176
+ user.tenant = tenant ? tenant : null
169
177
 
170
178
  user.active = user.active === 1
171
179
  }
@@ -182,6 +190,10 @@ class UserSqliteRepository implements IUserRepository {
182
190
  return await this.roleRepository.findById(id)
183
191
  }
184
192
 
193
+ async findTenantById(id: IID) {
194
+ return await this.tenantRepository.findById(id)
195
+ }
196
+
185
197
  async changePassword(id: IID, password: string): Promise<boolean> {
186
198
  const stmt = this.db.prepare(`UPDATE users
187
199
  SET password = @password
@@ -75,7 +75,11 @@ async function RoleRoutes(fastify, options) {
75
75
  request.rbac.assertPermission(IdentityPermissions.ViewRole)
76
76
  const roleService = RoleServiceFactory()
77
77
  let roles = await roleService.fetchAll()
78
- return roles
78
+ if(request.rbac.getRole?.childRoles?.length > 0) {
79
+ return roles.filter(role => request.rbac.getRole.childRoles.some(childRole => childRole.id === role.id));
80
+ }else{
81
+ return roles
82
+ }
79
83
  } catch (e) {
80
84
  console.error(e)
81
85
  if (e instanceof ValidationError) {
@@ -172,6 +176,10 @@ async function RoleRoutes(fastify, options) {
172
176
  request.rbac.assertPermission(IdentityPermissions.DeleteRole)
173
177
  const id = request.params.id
174
178
  const roleService = RoleServiceFactory()
179
+ const currentRole = await roleService.findById(id)
180
+ if(currentRole.readonly){
181
+ throw new UnauthorizedError()
182
+ }
175
183
  let r = await roleService.delete(id)
176
184
  return r
177
185
  } catch (e) {
@@ -0,0 +1,178 @@
1
+ import {IPaginateResult, ValidationError} from "@drax/common-back";
2
+ import TenantServiceFactory from "../factory/TenantServiceFactory.js";
3
+ import {ITenant} from "../interfaces/ITenant";
4
+ import {IdentityPermissions} from "../permissions/IdentityPermissions.js";
5
+ import {PermissionService} from "../services/PermissionService.js";
6
+ import UnauthorizedError from "../errors/UnauthorizedError.js";
7
+
8
+
9
+
10
+ async function TenantRoutes(fastify, options) {
11
+
12
+ fastify.get('/api/tenants/:id', async (request, reply): Promise<ITenant> => {
13
+ try {
14
+ request.rbac.assertPermission(IdentityPermissions.ViewTenant)
15
+ const id = request.params.id
16
+ const tenantService = TenantServiceFactory()
17
+ let tenant = await tenantService.findById(id)
18
+ return tenant
19
+ } catch (e) {
20
+ console.error(e)
21
+ if (e instanceof ValidationError) {
22
+ reply.statusCode = e.statusCode
23
+ reply.send({error: e.message, inputErrors: e.errors})
24
+ } else if (e instanceof UnauthorizedError) {
25
+ reply.statusCode = e.statusCode
26
+ reply.send({error: e.message})
27
+ } else {
28
+ reply.statusCode = 500
29
+ reply.send({error: 'INTERNAL_SERVER_ERROR'})
30
+ }
31
+ }
32
+ })
33
+
34
+ fastify.get('/api/tenants/name/:name', async (request, reply): Promise<ITenant> => {
35
+ try {
36
+ request.rbac.assertPermission(IdentityPermissions.ViewTenant)
37
+ const name = request.params.name
38
+ const tenantService = TenantServiceFactory()
39
+ let tenant = await tenantService.findByName(name)
40
+ return tenant
41
+ } catch (e) {
42
+ console.error(e)
43
+ if (e instanceof ValidationError) {
44
+ reply.statusCode = e.statusCode
45
+ reply.send({error: e.message, inputErrors: e.errors})
46
+ } else if (e instanceof UnauthorizedError) {
47
+ reply.statusCode = e.statusCode
48
+ reply.send({error: e.message})
49
+ } else {
50
+ reply.statusCode = 500
51
+ reply.send({error: 'INTERNAL_SERVER_ERROR'})
52
+ }
53
+ }
54
+ })
55
+
56
+ fastify.get('/api/tenants/all', async (request, reply): Promise<ITenant[]> => {
57
+ try {
58
+ request.rbac.assertPermission(IdentityPermissions.ViewTenant)
59
+ const tenantService = TenantServiceFactory()
60
+ let tenants = await tenantService.fetchAll()
61
+ if(request.rbac.getAuthUser.tenantId){
62
+ return tenants.filter(t => t.id === request.rbac.getAuthUser.tenantId)
63
+ }else{
64
+ return tenants
65
+ }
66
+ } catch (e) {
67
+ console.error(e)
68
+ if (e instanceof ValidationError) {
69
+ reply.statusCode = e.statusCode
70
+ reply.send({error: e.message, inputErrors: e.errors})
71
+ } else if (e instanceof UnauthorizedError) {
72
+ reply.statusCode = e.statusCode
73
+ reply.send({error: e.message})
74
+ } else {
75
+ reply.statusCode = 500
76
+ reply.send({error: 'INTERNAL_SERVER_ERROR'})
77
+ }
78
+ }
79
+ })
80
+
81
+ fastify.get('/api/tenants', async (request, reply): Promise<IPaginateResult> => {
82
+ try {
83
+ request.rbac.assertPermission(IdentityPermissions.ViewTenant)
84
+ const page = request.query.page
85
+ const limit = request.query.limit
86
+ const search = request.query.search
87
+ const tenantService = TenantServiceFactory()
88
+ let paginateResult = await tenantService.paginate(page, limit, search)
89
+ return paginateResult
90
+ } catch (e) {
91
+ console.error(e)
92
+ if (e instanceof ValidationError) {
93
+ reply.statusCode = e.statusCode
94
+ reply.send({error: e.message, inputErrors: e.errors})
95
+ } else if (e instanceof UnauthorizedError) {
96
+ reply.statusCode = e.statusCode
97
+ reply.send({error: e.message})
98
+ } else {
99
+ reply.statusCode = 500
100
+ reply.send({error: 'INTERNAL_SERVER_ERROR'})
101
+ }
102
+ }
103
+ })
104
+
105
+ fastify.post('/api/tenants', async (request, reply): Promise<ITenant> => {
106
+ try {
107
+ request.rbac.assertPermission(IdentityPermissions.CreateTenant)
108
+ const payload = request.body
109
+ const tenantService = TenantServiceFactory()
110
+ let tenant = await tenantService.create(payload)
111
+ return tenant
112
+ } catch (e) {
113
+ console.error(e)
114
+ if (e instanceof ValidationError) {
115
+ reply.statusCode = e.statusCode
116
+ reply.send({error: e.message, inputErrors: e.errors})
117
+ } else if (e instanceof UnauthorizedError) {
118
+ reply.statusCode = e.statusCode
119
+ reply.send({error: e.message})
120
+ } else {
121
+ reply.statusCode = 500
122
+ reply.send({error: 'INTERNAL_SERVER_ERROR'})
123
+ }
124
+ }
125
+
126
+ })
127
+
128
+ fastify.put('/api/tenants/:id', async (request, reply): Promise<ITenant> => {
129
+ try {
130
+ request.rbac.assertPermission(IdentityPermissions.UpdateTenant)
131
+ const id = request.params.id
132
+ const payload = request.body
133
+ const tenantService = TenantServiceFactory()
134
+
135
+ let tenant = await tenantService.update(id, payload)
136
+ return tenant
137
+ } catch (e) {
138
+ console.error(e)
139
+ if (e instanceof ValidationError) {
140
+ reply.statusCode = e.statusCode
141
+ reply.send({error: e.message, inputErrors: e.errors})
142
+ } else if (e instanceof UnauthorizedError) {
143
+ reply.statusCode = e.statusCode
144
+ reply.send({error: e.message})
145
+ } else {
146
+ reply.statusCode = 500
147
+ reply.send({error: 'INTERNAL_SERVER_ERROR'})
148
+ }
149
+ }
150
+
151
+ })
152
+
153
+ fastify.delete('/api/tenants/:id', async (request, reply): Promise<any> => {
154
+ try {
155
+ request.rbac.assertPermission(IdentityPermissions.DeleteTenant)
156
+ const id = request.params.id
157
+ const tenantService = TenantServiceFactory()
158
+ let r = await tenantService.delete(id)
159
+ return r
160
+ } catch (e) {
161
+ console.error(e)
162
+ if (e instanceof ValidationError) {
163
+ reply.statusCode = e.statusCode
164
+ reply.send({error: e.message, inputErrors: e.errors})
165
+ } else if (e instanceof UnauthorizedError) {
166
+ reply.statusCode = e.statusCode
167
+ reply.send({error: e.message})
168
+ } else {
169
+ reply.statusCode = 500
170
+ reply.send({error: 'INTERNAL_SERVER_ERROR'})
171
+ }
172
+ }
173
+ })
174
+
175
+ }
176
+
177
+ export default TenantRoutes;
178
+ export {TenantRoutes}
@@ -61,9 +61,14 @@ async function UserRoutes(fastify, options) {
61
61
  const limit = request.query.limit
62
62
  const search = request.query.search
63
63
  const userService = UserServiceFactory()
64
- let paginateResult = await userService.paginate(page, limit, search)
64
+ const filters = []
65
+ if(request.rbac.getAuthUser.tenantId){
66
+ filters.push({field: 'tenant', operator: '$eq', value: request.rbac.getAuthUser.tenantId})
67
+ }
68
+ let paginateResult = await userService.paginate(page, limit, search, filters)
65
69
  return paginateResult
66
70
  } catch (e) {
71
+ console.log("/api/users",e)
67
72
  if (e instanceof ValidationError) {
68
73
  reply.statusCode = e.statusCode
69
74
  reply.send({error: e.message, inputErrors: e.errors})
@@ -43,10 +43,7 @@ class RoleService {
43
43
  }
44
44
 
45
45
  async delete(id: any): Promise<boolean> {
46
- const currentRole = await this.findById(id)
47
- if(currentRole.readonly){
48
- throw new UnauthorizedError()
49
- }
46
+
50
47
  const deletedRole = await this._repository.delete(id);
51
48
  return deletedRole;
52
49
  }
@@ -0,0 +1,74 @@
1
+ import {ITenant} from "../interfaces/ITenant";
2
+ import {ITenantRepository} from "../interfaces/ITenantRepository";
3
+ import {IPaginateFilter, IPaginateResult, ValidationError, ZodErrorToValidationError} from "@drax/common-back"
4
+ import {tenantSchema} from "../zod/TenantZod.js";
5
+ import {ZodError} from "zod";
6
+ import UnauthorizedError from "../errors/UnauthorizedError.js";
7
+
8
+ class TenantService {
9
+
10
+ _repository: ITenantRepository
11
+
12
+ constructor(tenantRepostitory: ITenantRepository) {
13
+ this._repository = tenantRepostitory
14
+ console.log("TenantService constructor")
15
+ }
16
+
17
+ async create(tenantData: ITenant): Promise<ITenant> {
18
+ try {
19
+ tenantData.name = tenantData?.name?.trim()
20
+ await tenantSchema.parseAsync(tenantData)
21
+ const tenant = await this._repository.create(tenantData)
22
+ return tenant
23
+ } catch (e) {
24
+ if (e instanceof ZodError) {
25
+ throw ZodErrorToValidationError(e, tenantData)
26
+ }
27
+ throw e
28
+ }
29
+ }
30
+
31
+ async update(id: any, tenantData: ITenant) {
32
+ try {
33
+ tenantData.name = tenantData?.name?.trim()
34
+ await tenantSchema.parseAsync(tenantData)
35
+ const tenant = await this._repository.update(id, tenantData)
36
+ return tenant
37
+ } catch (e) {
38
+ if (e instanceof ZodError) {
39
+ throw ZodErrorToValidationError(e, tenantData)
40
+ }
41
+ throw e
42
+ }
43
+ }
44
+
45
+ async delete(id: any): Promise<boolean> {
46
+ const currentTenant = await this.findById(id)
47
+ const deletedTenant = await this._repository.delete(id);
48
+ return deletedTenant;
49
+ }
50
+
51
+ async findById(id: any): Promise<ITenant | null> {
52
+ const tenant: ITenant = await this._repository.findById(id);
53
+ return tenant
54
+ }
55
+
56
+ async findByName(name: string): Promise<ITenant | null> {
57
+ const tenant: ITenant = await this._repository.findByName(name);
58
+ return tenant
59
+ }
60
+
61
+ async fetchAll(): Promise<ITenant[]> {
62
+ const tenants: ITenant[] = await this._repository.fetchAll();
63
+ return tenants
64
+ }
65
+
66
+ async paginate(page: number = 1, limit: number = 5, search?:string, filters ?: IPaginateFilter[]): Promise<IPaginateResult> {
67
+ const pagination = await this._repository.paginate(page, limit, search, filters);
68
+ return pagination;
69
+ }
70
+
71
+
72
+ }
73
+
74
+ export default TenantService
@@ -23,7 +23,7 @@ class UserService {
23
23
  if (user && user.active && AuthUtils.checkPassword(password, user.password)) {
24
24
  //TODO: Generar Sesion
25
25
  const session = '123'
26
- const accessToken = AuthUtils.generateToken(user.id.toString(), user.username, user.role.id, session)
26
+ const accessToken = AuthUtils.generateToken(user.id.toString(), user.username, user.role.id, user.tenant?.id, session)
27
27
  return {accessToken: accessToken}
28
28
  }else{
29
29
  throw new BadCredentialsError()
@@ -30,17 +30,18 @@ class AuthUtils{
30
30
  return bcryptjs.compareSync(password, hashPassword);
31
31
  }
32
32
 
33
- static tokenSignPayload(userId : string, username: string, roleId: string, session : string) {
33
+ static tokenSignPayload(userId : string, username: string, roleId: string, tenantId: string, session : string) {
34
34
  return {
35
35
  id: userId,
36
36
  username: username,
37
37
  roleId: roleId,
38
+ tenantId: tenantId,
38
39
  session: session
39
40
  };
40
41
  }
41
42
 
42
- static generateToken(userId : string, username: string, roleId: string, session : string) {
43
- const payload = AuthUtils.tokenSignPayload(userId, username, roleId, session)
43
+ static generateToken(userId : string, username: string, roleId: string, tenantId: string, session : string) {
44
+ const payload = AuthUtils.tokenSignPayload(userId, username, roleId, tenantId, session)
44
45
 
45
46
  const JWT_SECRET = DraxConfig.getOrLoad(IdentityConfig.JwtSecret)
46
47
  if(!JWT_SECRET){
@@ -0,0 +1,14 @@
1
+ import { object, string } from "zod"
2
+
3
+ const tenantSchema = object({
4
+ name: string({ required_error: "validation.required" })
5
+ .min(1, "validation.required")
6
+ .regex(/^[A-Z]/, "validation.startWithUpperCase"),
7
+
8
+
9
+ })
10
+
11
+
12
+ export default tenantSchema
13
+
14
+ export {tenantSchema}