@drax/identity-back 0.0.31 → 0.1.2

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 (156) hide show
  1. package/dist/config/IdentityConfig.js +2 -3
  2. package/dist/factory/RoleServiceFactory.js +8 -7
  3. package/dist/factory/TenantServiceFactory.js +8 -7
  4. package/dist/factory/UserApiKeyServiceFactory.js +24 -0
  5. package/dist/factory/UserServiceFactory.js +8 -7
  6. package/dist/graphql/resolvers/user-api-key.resolvers.js +89 -0
  7. package/dist/graphql/resolvers/user.resolvers.js +7 -2
  8. package/dist/graphql/types/userApiKey.graphql +33 -0
  9. package/dist/index.js +4 -2
  10. package/dist/interfaces/IUserApiKeyRepository.js +1 -0
  11. package/dist/middleware/apiKeyMiddleware.js +30 -0
  12. package/dist/middleware/rbacMiddleware.js +0 -1
  13. package/dist/models/UserApiKeyModel.js +44 -0
  14. package/dist/permissions/IdentityPermissions.js +6 -0
  15. package/dist/rbac/Rbac.js +8 -0
  16. package/dist/repository/mongo/UserApiKeyMongoRepository.js +82 -0
  17. package/dist/repository/mongo/UserMongoRepository.js +3 -3
  18. package/dist/repository/sqlite/RoleSqliteRepository.js +16 -18
  19. package/dist/repository/sqlite/TenantSqliteRepository.js +13 -11
  20. package/dist/repository/sqlite/UserApiKeySqliteRepository.js +147 -0
  21. package/dist/repository/sqlite/UserSqliteRepository.js +29 -26
  22. package/dist/routes/UserApiKeyRoutes.js +119 -0
  23. package/dist/routes/UserRoutes.js +5 -1
  24. package/dist/services/TenantService.js +42 -11
  25. package/dist/services/UserApiKeyService.js +90 -0
  26. package/dist/services/UserService.js +34 -8
  27. package/dist/setup/LoadIdentityConfigFromEnv.js +3 -3
  28. package/dist/utils/AuthUtils.js +10 -0
  29. package/dist/zod/UserApiKeyZod.js +9 -0
  30. package/package.json +7 -6
  31. package/src/config/IdentityConfig.ts +4 -3
  32. package/src/factory/RoleServiceFactory.ts +11 -11
  33. package/src/factory/TenantServiceFactory.ts +11 -11
  34. package/src/factory/UserApiKeyServiceFactory.ts +30 -0
  35. package/src/factory/UserServiceFactory.ts +8 -7
  36. package/src/graphql/resolvers/tenant.resolvers.ts +0 -1
  37. package/src/graphql/resolvers/user-api-key.resolvers.ts +94 -0
  38. package/src/graphql/resolvers/user.resolvers.ts +9 -2
  39. package/src/graphql/types/userApiKey.graphql +33 -0
  40. package/src/index.ts +10 -0
  41. package/src/interfaces/IUserApiKeyRepository.ts +8 -0
  42. package/src/middleware/apiKeyMiddleware.ts +35 -0
  43. package/src/middleware/rbacMiddleware.ts +1 -2
  44. package/src/models/UserApiKeyModel.ts +59 -0
  45. package/src/permissions/IdentityPermissions.ts +7 -0
  46. package/src/rbac/Rbac.ts +13 -2
  47. package/src/repository/mongo/UserApiKeyMongoRepository.ts +114 -0
  48. package/src/repository/mongo/UserMongoRepository.ts +3 -3
  49. package/src/repository/sqlite/RoleSqliteRepository.ts +28 -20
  50. package/src/repository/sqlite/TenantSqliteRepository.ts +25 -11
  51. package/src/repository/sqlite/UserApiKeySqliteRepository.ts +197 -0
  52. package/src/repository/sqlite/UserSqliteRepository.ts +37 -27
  53. package/src/routes/UserApiKeyRoutes.ts +128 -0
  54. package/src/routes/UserRoutes.ts +5 -1
  55. package/src/services/TenantService.ts +49 -17
  56. package/src/services/UserApiKeyService.ts +111 -0
  57. package/src/services/UserService.ts +74 -48
  58. package/src/setup/LoadIdentityConfigFromEnv.ts +5 -3
  59. package/src/utils/AuthUtils.ts +11 -0
  60. package/src/zod/UserApiKeyZod.ts +15 -0
  61. package/test/data-obj/apikey/root-mongo-user-apikey.ts +10 -0
  62. package/test/data-obj/roles/admin-mongo-role.ts +0 -3
  63. package/test/initializers/RoleMongoInitializer.ts +1 -0
  64. package/test/initializers/RoleSqliteInitializer.ts +1 -0
  65. package/test/initializers/UserMongoInitializer.ts +18 -0
  66. package/test/repository/mongo/user-apikey-mongo-repository.test.ts +73 -0
  67. package/tsconfig.tsbuildinfo +1 -1
  68. package/types/config/IdentityConfig.d.ts +2 -3
  69. package/types/config/IdentityConfig.d.ts.map +1 -1
  70. package/types/errors/BadCredentialsError.d.ts +6 -0
  71. package/types/errors/BadCredentialsError.d.ts.map +1 -0
  72. package/types/errors/UnauthorizedError.d.ts +6 -0
  73. package/types/errors/UnauthorizedError.d.ts.map +1 -0
  74. package/types/factory/RoleServiceFactory.d.ts +4 -0
  75. package/types/factory/RoleServiceFactory.d.ts.map +1 -1
  76. package/types/factory/TenantServiceFactory.d.ts +4 -0
  77. package/types/factory/TenantServiceFactory.d.ts.map +1 -1
  78. package/types/factory/UserApiKeyServiceFactory.d.ts +4 -0
  79. package/types/factory/UserApiKeyServiceFactory.d.ts.map +1 -0
  80. package/types/factory/UserServiceFactory.d.ts +4 -0
  81. package/types/factory/UserServiceFactory.d.ts.map +1 -1
  82. package/types/graphql/index.d.ts +6 -0
  83. package/types/graphql/resolvers/tenant.resolvers.d.ts.map +1 -1
  84. package/types/graphql/resolvers/user-api-key.resolvers.d.ts +37 -0
  85. package/types/graphql/resolvers/user-api-key.resolvers.d.ts.map +1 -0
  86. package/types/graphql/resolvers/user.resolvers.d.ts.map +1 -1
  87. package/types/index.d.ts +35 -0
  88. package/types/index.d.ts.map +1 -1
  89. package/types/interfaces/IRoleRepository.d.ts +9 -0
  90. package/types/interfaces/ITenantRepository.d.ts +9 -0
  91. package/types/interfaces/IUserApiKeyRepository.d.ts +7 -0
  92. package/types/interfaces/IUserApiKeyRepository.d.ts.map +1 -0
  93. package/types/interfaces/IUserRepository.d.ts +10 -0
  94. package/types/middleware/apiKeyMiddleware.d.ts +4 -0
  95. package/types/middleware/apiKeyMiddleware.d.ts.map +1 -0
  96. package/types/middleware/jwtMiddleware.d.ts +4 -0
  97. package/types/middleware/rbacMiddleware.d.ts +4 -0
  98. package/types/middleware/rbacMiddleware.d.ts.map +1 -1
  99. package/types/models/RoleModel.d.ts +16 -0
  100. package/types/models/TenantModel.d.ts +16 -0
  101. package/types/models/UserApiKeyModel.d.ts +16 -0
  102. package/types/models/UserApiKeyModel.d.ts.map +1 -0
  103. package/types/models/UserGroupModel.d.ts +16 -0
  104. package/types/models/UserModel.d.ts +16 -0
  105. package/types/permissions/IdentityPermissions.d.ts +27 -0
  106. package/types/permissions/IdentityPermissions.d.ts.map +1 -0
  107. package/types/rbac/Rbac.d.ts +15 -0
  108. package/types/rbac/Rbac.d.ts.map +1 -1
  109. package/types/repository/mongo/RoleMongoRepository.d.ts +14 -0
  110. package/types/repository/mongo/TenantMongoRepository.d.ts +14 -0
  111. package/types/repository/mongo/UserApiKeyMongoRepository.d.ts +14 -0
  112. package/types/repository/mongo/UserApiKeyMongoRepository.d.ts.map +1 -0
  113. package/types/repository/mongo/UserMongoRepository.d.ts +17 -0
  114. package/types/repository/sqlite/RoleSqliteRepository.d.ts +22 -0
  115. package/types/repository/sqlite/RoleSqliteRepository.d.ts.map +1 -1
  116. package/types/repository/sqlite/TenantSqliteRepository.d.ts +19 -0
  117. package/types/repository/sqlite/TenantSqliteRepository.d.ts.map +1 -1
  118. package/types/repository/sqlite/UserApiKeySqliteRepository.d.ts +19 -0
  119. package/types/repository/sqlite/UserApiKeySqliteRepository.d.ts.map +1 -0
  120. package/types/repository/sqlite/UserSqliteRepository.d.ts +25 -0
  121. package/types/repository/sqlite/UserSqliteRepository.d.ts.map +1 -1
  122. package/types/routes/RoleRoutes.d.ts +4 -0
  123. package/types/routes/TenantRoutes.d.ts +4 -0
  124. package/types/routes/UserApiKeyRoutes.d.ts +4 -0
  125. package/types/routes/UserApiKeyRoutes.d.ts.map +1 -0
  126. package/types/routes/UserAvatarRoutes.d.ts +4 -0
  127. package/types/routes/UserRoutes.d.ts +4 -0
  128. package/types/routes/UserRoutes.d.ts.map +1 -1
  129. package/types/services/PermissionService.d.ts +9 -0
  130. package/types/services/PermissionService.d.ts.map +1 -0
  131. package/types/services/RoleService.d.ts +16 -0
  132. package/types/services/TenantService.d.ts +16 -0
  133. package/types/services/TenantService.d.ts.map +1 -1
  134. package/types/services/UserApiKeyService.d.ts +15 -0
  135. package/types/services/UserApiKeyService.d.ts.map +1 -0
  136. package/types/services/UserService.d.ts +21 -0
  137. package/types/services/UserService.d.ts.map +1 -1
  138. package/types/setup/CreateOrUpdateRole.d.ts +5 -0
  139. package/types/setup/CreateUserIfNotExist.d.ts +5 -0
  140. package/types/setup/LoadIdentityConfigFromEnv.d.ts +4 -0
  141. package/types/setup/LoadIdentityConfigFromEnv.d.ts.map +1 -1
  142. package/types/setup/LoadPermissions.d.ts +4 -0
  143. package/types/setup/LoadPermissions.d.ts.map +1 -0
  144. package/types/setup/RecoveryUserPassword.d.ts +4 -0
  145. package/types/utils/AuthUtils.d.ts +18 -0
  146. package/types/utils/AuthUtils.d.ts.map +1 -1
  147. package/types/zod/RoleZod.d.ts +10 -0
  148. package/types/zod/RoleZod.d.ts.map +1 -0
  149. package/types/zod/TenantZod.d.ts +10 -0
  150. package/types/zod/TenantZod.d.ts.map +1 -0
  151. package/types/zod/UserApiKeyZod.d.ts +16 -0
  152. package/types/zod/UserApiKeyZod.d.ts.map +1 -0
  153. package/types/zod/UserZod.d.ts +53 -0
  154. package/types/zod/UserZod.d.ts.map +1 -0
  155. package/src/utils/DbSetupUtils.ts +0 -41
  156. package/types/utils/DbSetupUtils.d.ts.map +0 -1
@@ -0,0 +1,114 @@
1
+ import {UserApiKeyModel} from "../../models/UserApiKeyModel.js";
2
+ import {
3
+ mongoose,
4
+ MongooseErrorToValidationError,
5
+ MongoServerErrorToValidationError,
6
+ ValidationError
7
+ } from "@drax/common-back"
8
+ import type {IUserApiKey, IUserApiKeyBase, IUserApiKeySoftDelete} from "@drax/identity-share";
9
+ import {DeleteResult, MongoServerError} from "mongodb";
10
+ import {PaginateResult} from "mongoose";
11
+ import {IDraxPaginateOptions, IDraxPaginateResult} from "@drax/common-share";
12
+ import {IUserApiKeyRepository} from "../../interfaces/IUserApiKeyRepository";
13
+
14
+ class UserMongoRepository implements IUserApiKeyRepository {
15
+
16
+
17
+ constructor() {
18
+ }
19
+
20
+ async create(data: IUserApiKeyBase): Promise<IUserApiKey> {
21
+ try {
22
+
23
+ const userApiKey: mongoose.HydratedDocument<IUserApiKey> = new UserApiKeyModel(data)
24
+ await userApiKey.save()
25
+ await userApiKey.populate({path: 'user', populate: {path: 'tenant role'} })
26
+ return userApiKey
27
+ } catch (e) {
28
+ if (e instanceof mongoose.Error.ValidationError) {
29
+ throw MongooseErrorToValidationError(e)
30
+ }
31
+ throw e
32
+ }
33
+
34
+ }
35
+
36
+ async update(id: string, data: IUserApiKeyBase): Promise<IUserApiKey> {
37
+ try {
38
+ delete data.secret
39
+ const userApiKey: mongoose.HydratedDocument<IUserApiKey> = await UserApiKeyModel.findOneAndUpdate({_id: id}, data, {new: true}).populate({path: 'user', populate: {path: 'tenant role'} }).exec()
40
+ return userApiKey
41
+ } catch (e) {
42
+ if (e instanceof mongoose.Error.ValidationError) {
43
+ throw MongooseErrorToValidationError(e)
44
+ }
45
+ if (e instanceof MongoServerError || e.name === 'MongoServerError') {
46
+ throw MongoServerErrorToValidationError(e)
47
+ }
48
+ throw e
49
+ }
50
+ }
51
+
52
+ async delete(id: string): Promise<boolean> {
53
+ const userApiKey: mongoose.HydratedDocument<IUserApiKeySoftDelete> = await UserApiKeyModel.findById(id)
54
+ userApiKey.softDelete()
55
+ return true
56
+ }
57
+
58
+ async findById(id: string): Promise<IUserApiKey> {
59
+ const userApiKey: mongoose.HydratedDocument<IUserApiKey> = await UserApiKeyModel.findById(id).populate({path: 'user', populate: {path: 'tenant role'} }).exec()
60
+ return userApiKey
61
+ }
62
+
63
+ async findBySecret(secret: string): Promise<IUserApiKey> {
64
+ const userApiKey: mongoose.HydratedDocument<IUserApiKey> = await UserApiKeyModel.findOne({secret: secret}).populate({path: 'user', populate: {path: 'tenant role'}}).exec()
65
+ return userApiKey
66
+ }
67
+
68
+ async paginate({
69
+ page = 1,
70
+ limit = 5,
71
+ orderBy = '',
72
+ orderDesc = false,
73
+ search = '',
74
+ filters = []
75
+ }: IDraxPaginateOptions): Promise<IDraxPaginateResult<IUserApiKey>> {
76
+
77
+ const query = {
78
+ deleted: false
79
+ }
80
+
81
+ if (search) {
82
+ query['$or'] = [
83
+ {name: new RegExp(search, 'i')},
84
+ ]
85
+ }
86
+
87
+ if(filters){
88
+ for(const filter of filters){
89
+ if(['eq','$eq'].includes(filter.operator)){
90
+ query[filter.field] = {$eq: filter.value}
91
+ }
92
+ if(['ne','$ne'].includes(filter.operator)){
93
+ query[filter.field] = {$ne: filter.value}
94
+ }
95
+ if(['in','$in'].includes(filter.operator)){
96
+ query[filter.field] = {$in: filter.value}
97
+ }
98
+ }
99
+ }
100
+
101
+ const options = {populate: ['user', 'user.tenant', 'user.role'], page: page, limit: limit}
102
+
103
+ const userApiKeyPaginated: PaginateResult<IUserApiKey> = await UserApiKeyModel.paginate(query, options)
104
+ return {
105
+ page: page,
106
+ limit: limit,
107
+ total: userApiKeyPaginated.totalDocs,
108
+ items: userApiKeyPaginated.docs
109
+ }
110
+ }
111
+
112
+ }
113
+
114
+ export default UserMongoRepository
@@ -86,13 +86,13 @@ class UserMongoRepository implements IUserRepository {
86
86
 
87
87
  if(filters){
88
88
  for(const filter of filters){
89
- if(filter.operator === '$eq'){
89
+ if(['eq','$eq'].includes(filter.operator)){
90
90
  query[filter.field] = {$eq: filter.value}
91
91
  }
92
- if(filter.operator === '$ne'){
92
+ if(['ne','$ne'].includes(filter.operator)){
93
93
  query[filter.field] = {$ne: filter.value}
94
94
  }
95
- if(filter.operator === '$in'){
95
+ if(['in','$in'].includes(filter.operator)){
96
96
  query[filter.field] = {$in: filter.value}
97
97
  }
98
98
  }
@@ -4,31 +4,36 @@ import sqlite from "better-sqlite3";
4
4
  import {randomUUID} from "node:crypto";
5
5
  import {IDraxPaginateResult, IDraxPaginateOptions} from "@drax/common-share";
6
6
  import {IRole, IRoleBase} from "@drax/identity-share";
7
- import {SqliteErrorToValidationError} from "@drax/common-back";
8
-
9
- const roleTableSQL: string = `
10
- CREATE TABLE IF NOT EXISTS roles
11
- (
12
- id TEXT PRIMARY KEY,
13
- name TEXT,
14
- permissions TEXT,
15
- readonly INTEGER,
16
- childRoles TEXT
17
-
18
- );
19
- `;
7
+ import {SqliteErrorToValidationError, SqliteTableBuilder, SqliteTableField} from "@drax/common-back";
8
+
9
+ const tableFields: SqliteTableField[] = [
10
+ {name: "name", type: "TEXT", unique: true, primary: false},
11
+ {name: "permissions", type: "TEXT", unique: false, primary: false},
12
+ {name: "childRoles", type: "TEXT", unique: false, primary: false},
13
+ {name: "readonly", type: "INTEGER", unique: false, primary: false},
14
+ {name: "createdAt", type: "TEXT", unique: false, primary: false},
15
+ {name: "updatedAt", type: "TEXT", unique: false, primary: false},
16
+ ]
17
+
20
18
 
21
19
  class RoleSqliteRepository implements IRoleRepository{
22
20
 
23
21
  private db: any;
22
+ private dataBaseFile: string;
24
23
 
25
- constructor(DATABASE:string, verbose:boolean = false) {
26
- this.db = new sqlite(DATABASE, {verbose: verbose ? console.log : null});
24
+ constructor(dataBaseFile:string, verbose:boolean = false) {
25
+ this.dataBaseFile = dataBaseFile;
26
+ this.db = new sqlite(dataBaseFile, {verbose: verbose ? console.log : null});
27
27
  this.table()
28
28
  }
29
29
 
30
30
  table() {
31
- this.db.exec(roleTableSQL);
31
+ const builder = new SqliteTableBuilder(
32
+ this.dataBaseFile,
33
+ 'roles',
34
+ tableFields,
35
+ false);
36
+ builder.build('id')
32
37
  }
33
38
 
34
39
  normalizeData(roleData: IRoleBase){
@@ -52,7 +57,7 @@ class RoleSqliteRepository implements IRoleRepository{
52
57
  }
53
58
 
54
59
  this.normalizeData(roleData)
55
-
60
+ roleData.createdAt = (new Date().toISOString())
56
61
 
57
62
  const fields = Object.keys(roleData)
58
63
  .map(field => `${field}`)
@@ -62,9 +67,6 @@ class RoleSqliteRepository implements IRoleRepository{
62
67
  .map(field => `@${field}`)
63
68
  .join(', ');
64
69
 
65
- /* console.log("fields", fields)
66
- console.log("values",values)
67
- console.log("userData",roleData)*/
68
70
 
69
71
  const stmt = this.db.prepare(`INSERT INTO roles (${fields}) VALUES (${values})`);
70
72
  stmt.run(roleData)
@@ -80,12 +82,18 @@ class RoleSqliteRepository implements IRoleRepository{
80
82
  async update(id: string, roleData: IRoleBase): Promise<IRole> {
81
83
  try{
82
84
  this.normalizeData(roleData)
85
+ roleData.updatedAt = (new Date().toISOString())
86
+
83
87
  const setClauses = Object.keys(roleData)
84
88
  .map(field => `${field} = @${field}`)
85
89
  .join(', ');
90
+
86
91
  roleData.id = id
92
+
87
93
  const stmt = this.db.prepare( `UPDATE roles SET ${setClauses} WHERE id = @id `);
94
+
88
95
  stmt.run(roleData);
96
+
89
97
  return this.findById(id)
90
98
  }catch (e){
91
99
  console.log(e)
@@ -4,27 +4,35 @@ import {UUID} from "crypto";
4
4
  import sqlite from "better-sqlite3";
5
5
  import {randomUUID} from "node:crypto";
6
6
  import {IDraxPaginateResult, IDraxPaginateOptions} from "@drax/common-share";
7
- import {SqliteErrorToValidationError} from "@drax/common-back";
7
+ import {SqliteErrorToValidationError, SqliteTableBuilder} from "@drax/common-back";
8
+ import type {SqliteTableField} from "@drax/common-back";
9
+
10
+
11
+ const tableFields: SqliteTableField[] = [
12
+ {name: "name", type: "TEXT", unique: false, primary: false},
13
+ {name: "createdAt", type: "TEXT", unique: false, primary: false},
14
+ {name: "updatedAt", type: "TEXT", unique: false, primary: false},
15
+ ]
8
16
 
9
- const tenantTableSQL: string = `
10
- CREATE TABLE IF NOT EXISTS tenants
11
- (
12
- id TEXT PRIMARY KEY,
13
- name TEXT
14
- );
15
- `;
16
17
 
17
18
  class TenantSqliteRepository implements ITenantRepository{
18
19
 
19
20
  private db: any;
21
+ private dataBaseFile: string;
20
22
 
21
- constructor(DATABASE:string, verbose:boolean = false) {
22
- this.db = new sqlite(DATABASE, {verbose: verbose ? console.log : null});
23
+ constructor(dataBaseFile:string, verbose:boolean = false) {
24
+ this.dataBaseFile = dataBaseFile;
25
+ this.db = new sqlite(this.dataBaseFile, {verbose: verbose ? console.log : null});
23
26
  this.table()
24
27
  }
25
28
 
26
29
  table() {
27
- this.db.exec(tenantTableSQL);
30
+ const builder = new SqliteTableBuilder(
31
+ this.dataBaseFile,
32
+ 'tenants',
33
+ tableFields,
34
+ false);
35
+ builder.build('id')
28
36
  }
29
37
 
30
38
 
@@ -36,6 +44,7 @@ class TenantSqliteRepository implements ITenantRepository{
36
44
  tenantData.id = randomUUID()
37
45
  }
38
46
 
47
+ tenantData.createdAt = (new Date().toISOString())
39
48
 
40
49
  const fields = Object.keys(tenantData)
41
50
  .map(field => `${field}`)
@@ -66,10 +75,15 @@ class TenantSqliteRepository implements ITenantRepository{
66
75
 
67
76
  async update(id: string, tenantData: ITenantBase): Promise<ITenant> {
68
77
  try{
78
+
79
+ tenantData.updatedAt = (new Date().toISOString())
80
+
69
81
  const setClauses = Object.keys(tenantData)
70
82
  .map(field => `${field} = @${field}`)
71
83
  .join(', ');
84
+
72
85
  tenantData.id = id
86
+
73
87
  const stmt = this.db.prepare( `UPDATE tenants SET ${setClauses} WHERE id = @id `);
74
88
  stmt.run(tenantData);
75
89
  return this.findById(id)
@@ -0,0 +1,197 @@
1
+ import {IUserApiKey, IUserApiKeyBase} from '@drax/identity-share'
2
+ import {IUserApiKeyRepository} from '../../interfaces/IUserApiKeyRepository'
3
+ import {UUID} from "crypto";
4
+ import sqlite from "better-sqlite3";
5
+ import {randomUUID} from "node:crypto";
6
+ import {IDraxPaginateResult, IDraxPaginateOptions} from "@drax/common-share";
7
+ import {SqliteErrorToValidationError, SqliteTableBuilder} from "@drax/common-back";
8
+ import type {SqliteTableField} from "@drax/common-back";
9
+ import UserSqliteRepository from "./UserSqliteRepository.js";
10
+
11
+
12
+ const tableFields: SqliteTableField[] = [
13
+ {name: "secret", type: "TEXT", unique: true, primary: false},
14
+ {name: "name", type: "TEXT", unique: false, primary: false},
15
+ {name: "user", type: "TEXT", unique: false, primary: false},
16
+ {name: "ipv4", type: "TEXT", unique: false, primary: false},
17
+ {name: "ipv6", type: "TEXT", unique: false, primary: false},
18
+ {name: "createdAt", type: "TEXT", unique: false, primary: false}
19
+ ]
20
+
21
+ class UserApiKeySqliteRepository implements IUserApiKeyRepository {
22
+
23
+ private db: any;
24
+ private dataBaseFile: string;
25
+ private userRepository: UserSqliteRepository;
26
+
27
+ constructor(dataBaseFile: string, verbose: boolean = false) {
28
+ this.dataBaseFile = dataBaseFile
29
+ this.userRepository = new UserSqliteRepository(dataBaseFile, verbose)
30
+ this.db = new sqlite(dataBaseFile, {verbose: verbose ? console.log : null});
31
+ this.table()
32
+ }
33
+
34
+ async findUserById(id: string) {
35
+ return await this.userRepository.findById(id)
36
+ }
37
+
38
+ table() {
39
+ const builder = new SqliteTableBuilder(
40
+ this.dataBaseFile,
41
+ 'user_api_keys',
42
+ tableFields,
43
+ false);
44
+ builder.build('id')
45
+ }
46
+
47
+
48
+ async create(userApiKeyData: IUserApiKeyBase): Promise<IUserApiKey> {
49
+ try {
50
+
51
+ if (!userApiKeyData.id) {
52
+ userApiKeyData.id = randomUUID()
53
+ }
54
+
55
+ if (userApiKeyData.ipv4 && Array.isArray(userApiKeyData.ipv4) && userApiKeyData.ipv4.length > 0) {
56
+ userApiKeyData.ipv4 = userApiKeyData.ipv4.join(',')
57
+ }else{
58
+ userApiKeyData.ipv4 = ""
59
+ }
60
+
61
+ if (userApiKeyData.ipv6 && Array.isArray(userApiKeyData.ipv6) && userApiKeyData.ipv6.length > 0) {
62
+ userApiKeyData.ipv6 = userApiKeyData.ipv6.join(',')
63
+ }else{
64
+ userApiKeyData.ipv6 = ""
65
+ }
66
+
67
+ userApiKeyData.createdAt = (new Date().toISOString())
68
+
69
+ const fields = Object.keys(userApiKeyData)
70
+ .map(field => `${field}`)
71
+ .join(', ');
72
+
73
+ const values = Object.keys(userApiKeyData)
74
+ .map(field => `@${field}`)
75
+ .join(', ');
76
+
77
+ const stmt = this.db.prepare(`INSERT INTO user_api_keys (${fields})
78
+ VALUES (${values})`);
79
+ stmt.run(userApiKeyData)
80
+ return this.findById(userApiKeyData.id as UUID)
81
+ } catch (e) {
82
+ console.log(e)
83
+ throw SqliteErrorToValidationError(e, userApiKeyData)
84
+ }
85
+ }
86
+
87
+ async findById(id: string): Promise<IUserApiKey | null> {
88
+ const userApiKey = this.db.prepare('SELECT * FROM user_api_keys WHERE id = ?').get(id);
89
+ userApiKey.ipv4 = userApiKey.ipv4 != "" ? userApiKey.ipv4.split(',') : []
90
+ userApiKey.ipv6 = userApiKey.ipv6 != "" ? userApiKey.ipv6.split(',') : []
91
+ userApiKey.user = await this.findUserById(userApiKey.user)
92
+ return userApiKey
93
+ }
94
+
95
+ async findBySecret(secret: string): Promise<IUserApiKey | null> {
96
+ const userApiKey = this.db.prepare('SELECT * FROM user_api_keys WHERE secret = ?').get(secret);
97
+ userApiKey.ipv4 = userApiKey.ipv4 != "" ? userApiKey.ipv4.split(',') : []
98
+ userApiKey.ipv6 = userApiKey.ipv6 != "" ? userApiKey.ipv6.split(',') : []
99
+ userApiKey.user = await this.findUserById(userApiKey.user)
100
+ return userApiKey
101
+ }
102
+
103
+ async update(id: string, userApiKeyData: IUserApiKeyBase): Promise<IUserApiKey> {
104
+ try {
105
+
106
+ if (userApiKeyData.ipv4 && Array.isArray(userApiKeyData.ipv4) && userApiKeyData.ipv4.length > 0) {
107
+ userApiKeyData.ipv4 = userApiKeyData.ipv4.join(',')
108
+ }else{
109
+ userApiKeyData.ipv4 = ""
110
+ }
111
+
112
+ if (userApiKeyData.ipv6 && Array.isArray(userApiKeyData.ipv6) && userApiKeyData.ipv6.length > 0) {
113
+ userApiKeyData.ipv6 = userApiKeyData.ipv6.join(',')
114
+ }else{
115
+ userApiKeyData.ipv6 = ""
116
+ }
117
+
118
+ delete userApiKeyData.secret
119
+
120
+ const setClauses = Object.keys(userApiKeyData)
121
+ .map(field => `${field} = @${field}`)
122
+ .join(', ');
123
+
124
+ userApiKeyData.id = id
125
+
126
+ const stmt = this.db.prepare(`UPDATE user_api_keys
127
+ SET ${setClauses}
128
+ WHERE id = @id `);
129
+ stmt.run(userApiKeyData);
130
+ return this.findById(id)
131
+ } catch (e) {
132
+ console.log(e)
133
+ throw SqliteErrorToValidationError(e, userApiKeyData)
134
+ }
135
+
136
+ }
137
+
138
+ async delete(id: string): Promise<boolean> {
139
+ const stmt = this.db.prepare('DELETE FROM user_api_keys WHERE id = ?');
140
+ stmt.run(id);
141
+ return true
142
+ }
143
+
144
+
145
+ async paginate({
146
+ page = 1,
147
+ limit = 5,
148
+ orderBy = '',
149
+ orderDesc = false,
150
+ search = '',
151
+ filters = []
152
+ }: IDraxPaginateOptions): Promise<IDraxPaginateResult<IUserApiKey>> {
153
+ const offset = page > 1 ? (page - 1) * limit : 0
154
+
155
+ let where = ""
156
+ if (search) {
157
+ where = ` WHERE name LIKE '%${search}%'`
158
+ }
159
+
160
+ let whereFilters= []
161
+ if(filters && filters.length > 0 ){
162
+ where = where ? ` AND ` : ` WHERE `
163
+ for(const filter of filters){
164
+ if(['eq','$eq'].includes(filter.operator)){
165
+ whereFilters.push(` ${filter.field} = '${filter.value}' `)
166
+ }
167
+ if(['ne','$ne'].includes(filter.operator)){
168
+ whereFilters.push(` ${filter.field} != '${filter.value}' `)
169
+ }
170
+ if(['in','$in'].includes(filter.operator)){
171
+ whereFilters.push(` ${filter.field} LIKE '%${filter.value}%' `)
172
+ }
173
+ }
174
+ where += whereFilters.join(" AND ")
175
+ }
176
+
177
+ const rCount = this.db.prepare('SELECT COUNT(*) as count FROM user_api_keys' + where).get();
178
+ const userApiKeys = this.db.prepare('SELECT * FROM user_api_keys ' + where + ' LIMIT ? OFFSET ?').all([limit, offset]);
179
+
180
+ for (const userApiKey of userApiKeys) {
181
+ userApiKey.ipv4 = userApiKey.ipv4 != "" ? userApiKey.ipv4.split(',') : []
182
+ userApiKey.ipv6 = userApiKey.ipv6 != "" ? userApiKey.ipv6.split(',') : []
183
+ userApiKey.user = await this.findUserById(userApiKey.user)
184
+ }
185
+
186
+ return {
187
+ page: page,
188
+ limit: limit,
189
+ total: rCount.count,
190
+ items: userApiKeys
191
+ }
192
+ }
193
+
194
+
195
+ }
196
+
197
+ export default UserApiKeySqliteRepository
@@ -4,42 +4,48 @@ import {randomUUID} from "node:crypto";
4
4
  import {UUID} from "crypto";
5
5
  import {IUserRepository} from "../../interfaces/IUserRepository";
6
6
  import {IDraxPaginateResult, IDraxPaginateOptions} from "@drax/common-share";
7
- import { SqliteErrorToValidationError, ValidationError} from "@drax/common-back";
7
+ import {SqliteErrorToValidationError, SqliteTableBuilder, ValidationError} from "@drax/common-back";
8
+ import type {SqliteTableField} from "@drax/common-back";
8
9
  import RoleSqliteRepository from "./RoleSqliteRepository.js";
9
10
  import TenantSqliteRepository from "./TenantSqliteRepository.js";
10
11
 
11
-
12
- const userTableSQL: string = `
13
- CREATE TABLE IF NOT EXISTS users
14
- (
15
- id TEXT PRIMARY KEY,
16
- name TEXT,
17
- username TEXT UNIQUE,
18
- active INTEGER,
19
- password TEXT,
20
- email TEXT UNIQUE,
21
- phone TEXT,
22
- role TEXT,
23
- tenant TEXT,
24
- groups TEXT,
25
- avatar TEXT
26
- );
27
- `;
12
+ const tableFields: SqliteTableField[] = [
13
+ {name: "name", type: "TEXT", unique: false, primary: false},
14
+ {name: "username", type: "TEXT", unique: true, primary: false},
15
+ {name: "active", type: "INTEGER", unique: false, primary: false},
16
+ {name: "active", type: "INTEGER", unique: false, primary: false},
17
+ {name: "password", type: "TEXT", unique: false, primary: false},
18
+ {name: "email", type: "TEXT", unique: true, primary: false},
19
+ {name: "phone", type: "TEXT", unique: false, primary: false},
20
+ {name: "role", type: "TEXT", unique: false, primary: false},
21
+ {name: "tenant", type: "TEXT", unique: false, primary: false},
22
+ {name: "groups", type: "TEXT", unique: false, primary: false},
23
+ {name: "avatar", type: "TEXT", unique: false, primary: false},
24
+ {name: "createdAt", type: "TEXT", unique: false, primary: false},
25
+ {name: "updatedAt", type: "TEXT", unique: false, primary: false}
26
+ ]
28
27
 
29
28
  class UserSqliteRepository implements IUserRepository {
30
29
  private db: any;
31
30
  private roleRepository: RoleSqliteRepository;
32
31
  private tenantRepository: TenantSqliteRepository;
32
+ private dataBaseFile: string;
33
33
 
34
- constructor(DATABASE: string, verbose: boolean = false) {
35
- this.db = new sqlite(DATABASE, {verbose: verbose ? console.log : null});
36
- this.roleRepository = new RoleSqliteRepository(DATABASE, verbose)
37
- this.tenantRepository = new TenantSqliteRepository(DATABASE, verbose)
34
+ constructor(dataBaseFile: string, verbose: boolean = false) {
35
+ this.dataBaseFile = dataBaseFile
36
+ this.db = new sqlite(dataBaseFile, {verbose: verbose ? console.log : null});
37
+ this.roleRepository = new RoleSqliteRepository(dataBaseFile, verbose)
38
+ this.tenantRepository = new TenantSqliteRepository(dataBaseFile, verbose)
38
39
  this.table()
39
40
  }
40
41
 
41
42
  table() {
42
- this.db.exec(userTableSQL);
43
+ const builder = new SqliteTableBuilder(
44
+ this.dataBaseFile,
45
+ 'users',
46
+ tableFields,
47
+ false);
48
+ builder.build('id')
43
49
  }
44
50
 
45
51
  normalizeData(userData: IUserCreate | IUserUpdate): void {
@@ -58,6 +64,8 @@ class UserSqliteRepository implements IUserRepository {
58
64
  throw new ValidationError([{field: 'role', reason: 'validation.notfound', value: userData.role}])
59
65
  }
60
66
 
67
+ userData.createdAt = (new Date().toISOString())
68
+
61
69
  this.normalizeData(userData)
62
70
 
63
71
  try {
@@ -86,6 +94,8 @@ class UserSqliteRepository implements IUserRepository {
86
94
  throw new ValidationError([{field: 'role', reason: 'validation.notfound', value: userData.role}])
87
95
  }
88
96
 
97
+ userData.updatedAt = (new Date().toISOString())
98
+
89
99
  this.normalizeData(userData)
90
100
 
91
101
  const setClauses = Object.keys(userData)
@@ -153,20 +163,20 @@ class UserSqliteRepository implements IUserRepository {
153
163
  if(filters && filters.length > 0 ){
154
164
  where = where ? ` AND ` : ` WHERE `
155
165
  for(const filter of filters){
156
- if(filter.operator === '$eq'){
166
+ if(['eq','$eq'].includes(filter.operator)){
157
167
  whereFilters.push(` ${filter.field} = '${filter.value}' `)
158
168
  }
159
- if(filter.operator === '$ne'){
169
+ if(['ne','$ne'].includes(filter.operator)){
160
170
  whereFilters.push(` ${filter.field} != '${filter.value}' `)
161
171
  }
162
- if(filter.operator === '$in'){
172
+ if(['in','$in'].includes(filter.operator)){
163
173
  whereFilters.push(` ${filter.field} LIKE '%${filter.value}%' `)
164
174
  }
165
175
  }
166
176
  where += whereFilters.join(" AND ")
167
177
  }
168
178
 
169
- // console.log("paginate where ", where, "search", search, "filters", filters, "whereFilters", whereFilters)
179
+ console.log("paginate where ", where, "search", search, "filters", filters, "whereFilters", whereFilters)
170
180
 
171
181
  const rCount = this.db.prepare('SELECT COUNT(*) as count FROM users' + where).get();
172
182