@drax/identity-back 0.0.14 → 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 +19 -2
  4. package/dist/graphql/resolvers/tenant.resolvers.js +121 -0
  5. package/dist/graphql/resolvers/user.resolvers.js +14 -3
  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 +2 -5
  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 +17 -2
  23. package/dist/routes/TenantRoutes.js +183 -0
  24. package/dist/routes/UserRoutes.js +14 -2
  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 +21 -3
  34. package/src/graphql/resolvers/tenant.resolvers.ts +119 -0
  35. package/src/graphql/resolvers/user.resolvers.ts +14 -6
  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 +6 -8
  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 +17 -3
  54. package/src/routes/TenantRoutes.ts +178 -0
  55. package/src/routes/UserRoutes.ts +14 -4
  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
@@ -14,6 +14,13 @@ enum IdentityPermissions {
14
14
  ManageRole = "role:manage",
15
15
  PermissionsRole = "role:permissions",
16
16
 
17
+
18
+ CreateTenant = "tenant:create",
19
+ UpdateTenant = "tenant:update",
20
+ DeleteTenant = "tenant:delete",
21
+ ViewTenant = "tenant:view",
22
+ ManageTenant = "tenant:manage",
23
+
17
24
  }
18
25
 
19
26
  export default IdentityPermissions;
package/src/rbac/Rbac.ts CHANGED
@@ -1,16 +1,24 @@
1
- import {IRoleBase} from "../interfaces/IRole";
1
+ import {IRole} from "../interfaces/IRole";
2
2
  import {IJwtUser} from "../interfaces/IJwtUser";
3
3
  import UnauthorizedError from "../errors/UnauthorizedError.js";
4
4
 
5
5
  class Rbac{
6
- private role: IRoleBase;
6
+ private role: IRole;
7
7
  private authUser: IJwtUser;
8
8
 
9
- constructor(authUser: IJwtUser, role: IRoleBase) {
9
+ constructor(authUser: IJwtUser, role: IRole) {
10
10
  this.authUser = authUser;
11
11
  this.role = role;
12
12
  }
13
13
 
14
+ get getRole() {
15
+ return this.role
16
+ }
17
+
18
+ get getAuthUser() {
19
+ return this.authUser
20
+ }
21
+
14
22
  hasPermission(requiredPermission: string): boolean {
15
23
  if (!this.authUser || !this.role || !this.role.permissions || this.role.permissions.length === 0) {
16
24
  return false;
@@ -10,31 +10,32 @@ class RoleMongoRepository implements IRoleRepository{
10
10
  async create(roleData: IRole): Promise<IRole> {
11
11
  const role : mongoose.HydratedDocument<IRole> = new RoleModel(roleData)
12
12
  await role.save()
13
+ await role.populate('childRoles')
13
14
  return role
14
15
  }
15
16
 
16
17
  async update(id: mongoose.Types.ObjectId | string, roleData: IRole): Promise<IRole> {
17
- const role : mongoose.HydratedDocument<IRole> = await RoleModel.findOneAndUpdate({_id: id}, roleData, {new: true}).exec()
18
+ const role : mongoose.HydratedDocument<IRole> = await RoleModel.findOneAndUpdate({_id: id}, roleData, {new: true}).populate('childRoles').exec()
18
19
  return role
19
20
  }
20
21
 
21
22
  async delete(id: mongoose.Types.ObjectId): Promise<boolean> {
22
- const result : DeleteResult = await RoleModel.deleteOne(id).exec()
23
+ const result : DeleteResult = await RoleModel.deleteOne({_id: id}).exec()
23
24
  return result.deletedCount == 1
24
25
  }
25
26
 
26
27
  async findById(id: mongoose.Types.ObjectId): Promise<IRole | null>{
27
- const role: mongoose.HydratedDocument<IRole> | null = await RoleModel.findById(id).exec()
28
+ const role: mongoose.HydratedDocument<IRole> | null = await RoleModel.findById(id).populate('childRoles').exec()
28
29
  return role
29
30
  }
30
31
 
31
32
  async findByName(name: string): Promise<IRole | null>{
32
- const role: mongoose.HydratedDocument<IRole> | null = await RoleModel.findOne({name}).exec()
33
+ const role: mongoose.HydratedDocument<IRole> | null = await RoleModel.findOne({name}).populate('childRoles').exec()
33
34
  return role
34
35
  }
35
36
 
36
37
  async fetchAll(): Promise<IRole[]>{
37
- const roles: mongoose.HydratedDocument<IRole>[] = await RoleModel.find().exec()
38
+ const roles: mongoose.HydratedDocument<IRole>[] = await RoleModel.find().populate('childRoles').exec()
38
39
  return roles
39
40
  }
40
41
 
@@ -48,7 +49,7 @@ class RoleMongoRepository implements IRoleRepository{
48
49
  ]
49
50
  }
50
51
 
51
- const options = {page, limit} as PaginateOptions
52
+ const options = {populate: ['childRoles'], page, limit} as PaginateOptions
52
53
  const roles: PaginateResult<IRole> = await RoleModel.paginate(query, options)
53
54
  return {
54
55
  page: page,
@@ -0,0 +1,62 @@
1
+ import {TenantModel} from "../../models/TenantModel.js";
2
+ import {ITenant} from '../../interfaces/ITenant'
3
+ import {ITenantRepository} from '../../interfaces/ITenantRepository'
4
+ import {IPaginateFilter, IPaginateResult, mongoose} from "@drax/common-back";
5
+ import {FilterQuery, PaginateOptions, PaginateResult} from "mongoose";
6
+ import {DeleteResult} from "mongodb";
7
+
8
+ class TenantMongoRepository implements ITenantRepository{
9
+
10
+ async create(tenantData: ITenant): Promise<ITenant> {
11
+ const tenant : mongoose.HydratedDocument<ITenant> = new TenantModel(tenantData)
12
+ await tenant.save()
13
+ return tenant
14
+ }
15
+
16
+ async update(id: mongoose.Types.ObjectId | string, tenantData: ITenant): Promise<ITenant> {
17
+ const tenant : mongoose.HydratedDocument<ITenant> = await TenantModel.findOneAndUpdate({_id: id}, tenantData, {new: true}).exec()
18
+ return tenant
19
+ }
20
+
21
+ async delete(id: mongoose.Types.ObjectId): Promise<boolean> {
22
+ const result : DeleteResult = await TenantModel.deleteOne({_id:id}).exec()
23
+ return result.deletedCount == 1
24
+ }
25
+
26
+ async findById(id: mongoose.Types.ObjectId): Promise<ITenant | null>{
27
+ const tenant: mongoose.HydratedDocument<ITenant> | null = await TenantModel.findById(id).exec()
28
+ return tenant
29
+ }
30
+
31
+ async findByName(name: string): Promise<ITenant | null>{
32
+ const tenant: mongoose.HydratedDocument<ITenant> | null = await TenantModel.findOne({name}).exec()
33
+ return tenant
34
+ }
35
+
36
+ async fetchAll(): Promise<ITenant[]>{
37
+ const tenants: mongoose.HydratedDocument<ITenant>[] = await TenantModel.find().exec()
38
+ return tenants
39
+ }
40
+
41
+ async paginate(page:number = 1, limit:number = 5, search:string): Promise<IPaginateResult>{
42
+
43
+ const query = {}
44
+
45
+ if(search){
46
+ query['$or'] = [
47
+ {name: new RegExp(search, 'i')},
48
+ ]
49
+ }
50
+
51
+ const options = {page, limit} as PaginateOptions
52
+ const tenants: PaginateResult<ITenant> = await TenantModel.paginate(query, options)
53
+ return {
54
+ page: page,
55
+ limit: limit,
56
+ total: tenants.totalDocs,
57
+ items: tenants.docs
58
+ }
59
+ }
60
+ }
61
+
62
+ export default TenantMongoRepository
@@ -24,7 +24,7 @@ class UserMongoRepository implements IUserRepository {
24
24
 
25
25
  const user: mongoose.HydratedDocument<IUser> = new UserModel(userData)
26
26
  await user.save()
27
- await user.populate('role')
27
+ await user.populate(['role','tenant'])
28
28
  return user
29
29
  }catch (e){
30
30
  if(e instanceof mongoose.Error.ValidationError){
@@ -37,7 +37,7 @@ class UserMongoRepository implements IUserRepository {
37
37
 
38
38
  async update(id: mongoose.Types.ObjectId, userData: IUserUpdate): Promise<IUser> {
39
39
  try{
40
- const user: mongoose.HydratedDocument<IUser> = await UserModel.findOneAndUpdate({_id: id}, userData, {new: true}).populate('role').exec()
40
+ const user: mongoose.HydratedDocument<IUser> = await UserModel.findOneAndUpdate({_id: id}, userData, {new: true}).populate(['role','tenant']).exec()
41
41
  return user
42
42
  }catch (e){
43
43
  if(e instanceof mongoose.Error.ValidationError){
@@ -57,16 +57,16 @@ class UserMongoRepository implements IUserRepository {
57
57
 
58
58
 
59
59
  async findById(id: mongoose.Types.ObjectId): Promise<IUser> {
60
- const user: mongoose.HydratedDocument<IUser> = await UserModel.findById(id).populate('role').exec()
60
+ const user: mongoose.HydratedDocument<IUser> = await UserModel.findById(id).populate(['role','tenant']).exec()
61
61
  return user
62
62
  }
63
63
 
64
64
  async findByUsername(username: string): Promise<IUser> {
65
- const user: mongoose.HydratedDocument<IUser> = await UserModel.findOne({username: username}).populate('role').exec()
65
+ const user: mongoose.HydratedDocument<IUser> = await UserModel.findOne({username: username}).populate(['role','tenant']).exec()
66
66
  return user
67
67
  }
68
68
 
69
- async paginate(page: number = 1, limit: number = 5, search?:string): Promise<IPaginateResult> {
69
+ async paginate(page: number = 1, limit: number = 5, search?:string, filters?:IPaginateFilter[]): Promise<IPaginateResult> {
70
70
 
71
71
 
72
72
  const query = {}
@@ -79,7 +79,21 @@ class UserMongoRepository implements IUserRepository {
79
79
  ]
80
80
  }
81
81
 
82
- const options = {populate: ['role'], page: page, limit: limit }
82
+ if(filters){
83
+ for(const filter of filters){
84
+ if(filter.operator === '$eq'){
85
+ query[filter.field] = {$eq: filter.value}
86
+ }
87
+ if(filter.operator === '$ne'){
88
+ query[filter.field] = {$ne: filter.value}
89
+ }
90
+ if(filter.operator === '$in'){
91
+ query[filter.field] = {$in: filter.value}
92
+ }
93
+ }
94
+ }
95
+
96
+ const options = {populate: ['role','tenant'], page: page, limit: limit }
83
97
 
84
98
  const userPaginated: PaginateResult<IUser> = await UserModel.paginate(query, options)
85
99
  return {
@@ -25,6 +25,7 @@ class RoleSqliteRepository implements IRoleRepository{
25
25
 
26
26
  constructor(DATABASE:string, verbose:boolean = false) {
27
27
  this.db = new sqlite(DATABASE, {verbose: verbose ? console.log : null});
28
+ this.table()
28
29
  }
29
30
 
30
31
  table() {
@@ -78,7 +79,7 @@ class RoleSqliteRepository implements IRoleRepository{
78
79
  async findById(id: IID): Promise<IRole | null>{
79
80
  const role = this.db.prepare('SELECT * FROM roles WHERE id = ?').get(id);
80
81
  if(role){
81
- role.permissions = role.permissions ? role.permissions.split(",") : []
82
+ await this.populateRole(role)
82
83
  return role
83
84
  }
84
85
  return undefined
@@ -87,7 +88,7 @@ class RoleSqliteRepository implements IRoleRepository{
87
88
  async findByName(name: string): Promise<IRole | null>{
88
89
  const role = this.db.prepare('SELECT * FROM roles WHERE name = ?').get(name);
89
90
  if(role){
90
- role.permissions = role.permissions ? role.permissions.split(",") : []
91
+ await this.populateRole(role)
91
92
  return role
92
93
  }
93
94
  return undefined
@@ -125,7 +126,7 @@ class RoleSqliteRepository implements IRoleRepository{
125
126
  async fetchAll(): Promise<IRole[]>{
126
127
  const roles = this.db.prepare('SELECT * FROM roles').all();
127
128
  for (const role of roles) {
128
- role.permissions = role.permissions? role.permissions.split(",") : []
129
+ await this.populateRole(role)
129
130
  }
130
131
  return roles
131
132
  }
@@ -133,7 +134,7 @@ class RoleSqliteRepository implements IRoleRepository{
133
134
  async paginate(page = 1, limit = 5, search=""): Promise<IPaginateResult>{
134
135
  const offset = page > 1 ? (page - 1) * limit : 0
135
136
 
136
- let where
137
+ let where=""
137
138
  if (search) {
138
139
  where = ` WHERE name LIKE '%${search}%'`
139
140
  }
@@ -142,10 +143,9 @@ class RoleSqliteRepository implements IRoleRepository{
142
143
  const roles = this.db.prepare('SELECT * FROM roles LIMIT ? OFFSET ?'+where).all([limit, offset]);
143
144
 
144
145
  for (const role of roles) {
145
- role.permissions = role.permissions? role.permissions.split(",") : []
146
+ await this.populateRole(role)
146
147
  }
147
148
 
148
-
149
149
  return {
150
150
  page: page,
151
151
  limit: limit,
@@ -154,6 +154,27 @@ class RoleSqliteRepository implements IRoleRepository{
154
154
  }
155
155
  }
156
156
 
157
+ async findWithoutPopulateById(id: IID): Promise<IRole | null>{
158
+ const role = this.db.prepare('SELECT * FROM roles WHERE id = ?').get(id);
159
+ if(role){
160
+ return role
161
+ }
162
+ return undefined
163
+ }
164
+
165
+ async populateRole(role){
166
+ role.permissions = role.permissions? role.permissions.split(",") : []
167
+ role.childRoles = role.childRoles? role.childRoles.split(",") : []
168
+
169
+ const childRoles = []
170
+ for(const childRoleId of role.childRoles){
171
+ const childRole:IRole = await this.findWithoutPopulateById(childRoleId)
172
+ childRoles.push(childRole)
173
+ }
174
+ role.childRoles = childRoles
175
+ return role
176
+ }
177
+
157
178
 
158
179
  }
159
180
 
@@ -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
@@ -5,7 +5,7 @@ import {IdentityPermissions} from "../permissions/IdentityPermissions.js";
5
5
  import {PermissionService} from "../services/PermissionService.js";
6
6
  import UnauthorizedError from "../errors/UnauthorizedError.js";
7
7
 
8
- const roleService = RoleServiceFactory()
8
+
9
9
 
10
10
  async function RoleRoutes(fastify, options) {
11
11
 
@@ -30,6 +30,7 @@ async function RoleRoutes(fastify, options) {
30
30
  try {
31
31
  request.rbac.assertPermission(IdentityPermissions.ViewRole)
32
32
  const id = request.params.id
33
+ const roleService = RoleServiceFactory()
33
34
  let role = await roleService.findById(id)
34
35
  return role
35
36
  } catch (e) {
@@ -51,6 +52,7 @@ async function RoleRoutes(fastify, options) {
51
52
  try {
52
53
  request.rbac.assertPermission(IdentityPermissions.ViewRole)
53
54
  const name = request.params.name
55
+ const roleService = RoleServiceFactory()
54
56
  let role = await roleService.findByName(name)
55
57
  return role
56
58
  } catch (e) {
@@ -71,8 +73,13 @@ async function RoleRoutes(fastify, options) {
71
73
  fastify.get('/api/roles/all', async (request, reply): Promise<IRole[]> => {
72
74
  try {
73
75
  request.rbac.assertPermission(IdentityPermissions.ViewRole)
76
+ const roleService = RoleServiceFactory()
74
77
  let roles = await roleService.fetchAll()
75
- 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
+ }
76
83
  } catch (e) {
77
84
  console.error(e)
78
85
  if (e instanceof ValidationError) {
@@ -94,6 +101,7 @@ async function RoleRoutes(fastify, options) {
94
101
  const page = request.query.page
95
102
  const limit = request.query.limit
96
103
  const search = request.query.search
104
+ const roleService = RoleServiceFactory()
97
105
  let paginateResult = await roleService.paginate(page, limit, search)
98
106
  return paginateResult
99
107
  } catch (e) {
@@ -115,6 +123,7 @@ async function RoleRoutes(fastify, options) {
115
123
  try {
116
124
  request.rbac.assertPermission(IdentityPermissions.CreateRole)
117
125
  const payload = request.body
126
+ const roleService = RoleServiceFactory()
118
127
  let role = await roleService.create(payload)
119
128
  return role
120
129
  } catch (e) {
@@ -138,7 +147,7 @@ async function RoleRoutes(fastify, options) {
138
147
  request.rbac.assertPermission(IdentityPermissions.UpdateRole)
139
148
  const id = request.params.id
140
149
  const payload = request.body
141
-
150
+ const roleService = RoleServiceFactory()
142
151
  const currentRole = await roleService.findById(id)
143
152
  if(currentRole.readonly){
144
153
  throw new ValidationError([{field:'name', reason:"role.readonly", value:payload.name}])
@@ -166,6 +175,11 @@ async function RoleRoutes(fastify, options) {
166
175
  try {
167
176
  request.rbac.assertPermission(IdentityPermissions.DeleteRole)
168
177
  const id = request.params.id
178
+ const roleService = RoleServiceFactory()
179
+ const currentRole = await roleService.findById(id)
180
+ if(currentRole.readonly){
181
+ throw new UnauthorizedError()
182
+ }
169
183
  let r = await roleService.delete(id)
170
184
  return r
171
185
  } catch (e) {