@drax/identity-back 0.0.15 → 0.0.17

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