@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.
- package/dist/config/IdentityConfig.js +2 -3
- package/dist/factory/RoleServiceFactory.js +8 -7
- package/dist/factory/TenantServiceFactory.js +8 -7
- package/dist/factory/UserApiKeyServiceFactory.js +24 -0
- package/dist/factory/UserServiceFactory.js +8 -7
- package/dist/graphql/resolvers/user-api-key.resolvers.js +89 -0
- package/dist/graphql/resolvers/user.resolvers.js +7 -2
- package/dist/graphql/types/userApiKey.graphql +33 -0
- package/dist/index.js +4 -2
- package/dist/interfaces/IUserApiKeyRepository.js +1 -0
- package/dist/middleware/apiKeyMiddleware.js +30 -0
- package/dist/middleware/rbacMiddleware.js +0 -1
- package/dist/models/UserApiKeyModel.js +44 -0
- package/dist/permissions/IdentityPermissions.js +6 -0
- package/dist/rbac/Rbac.js +8 -0
- package/dist/repository/mongo/UserApiKeyMongoRepository.js +82 -0
- package/dist/repository/mongo/UserMongoRepository.js +3 -3
- package/dist/repository/sqlite/RoleSqliteRepository.js +16 -18
- package/dist/repository/sqlite/TenantSqliteRepository.js +13 -11
- package/dist/repository/sqlite/UserApiKeySqliteRepository.js +147 -0
- package/dist/repository/sqlite/UserSqliteRepository.js +29 -26
- package/dist/routes/UserApiKeyRoutes.js +119 -0
- package/dist/routes/UserRoutes.js +5 -1
- package/dist/services/TenantService.js +42 -11
- package/dist/services/UserApiKeyService.js +90 -0
- package/dist/services/UserService.js +34 -8
- package/dist/setup/LoadIdentityConfigFromEnv.js +3 -3
- package/dist/utils/AuthUtils.js +10 -0
- package/dist/zod/UserApiKeyZod.js +9 -0
- package/package.json +7 -6
- package/src/config/IdentityConfig.ts +4 -3
- package/src/factory/RoleServiceFactory.ts +11 -11
- package/src/factory/TenantServiceFactory.ts +11 -11
- package/src/factory/UserApiKeyServiceFactory.ts +30 -0
- package/src/factory/UserServiceFactory.ts +8 -7
- package/src/graphql/resolvers/tenant.resolvers.ts +0 -1
- package/src/graphql/resolvers/user-api-key.resolvers.ts +94 -0
- package/src/graphql/resolvers/user.resolvers.ts +9 -2
- package/src/graphql/types/userApiKey.graphql +33 -0
- package/src/index.ts +10 -0
- package/src/interfaces/IUserApiKeyRepository.ts +8 -0
- package/src/middleware/apiKeyMiddleware.ts +35 -0
- package/src/middleware/rbacMiddleware.ts +1 -2
- package/src/models/UserApiKeyModel.ts +59 -0
- package/src/permissions/IdentityPermissions.ts +7 -0
- package/src/rbac/Rbac.ts +13 -2
- package/src/repository/mongo/UserApiKeyMongoRepository.ts +114 -0
- package/src/repository/mongo/UserMongoRepository.ts +3 -3
- package/src/repository/sqlite/RoleSqliteRepository.ts +28 -20
- package/src/repository/sqlite/TenantSqliteRepository.ts +25 -11
- package/src/repository/sqlite/UserApiKeySqliteRepository.ts +197 -0
- package/src/repository/sqlite/UserSqliteRepository.ts +37 -27
- package/src/routes/UserApiKeyRoutes.ts +128 -0
- package/src/routes/UserRoutes.ts +5 -1
- package/src/services/TenantService.ts +49 -17
- package/src/services/UserApiKeyService.ts +111 -0
- package/src/services/UserService.ts +74 -48
- package/src/setup/LoadIdentityConfigFromEnv.ts +5 -3
- package/src/utils/AuthUtils.ts +11 -0
- package/src/zod/UserApiKeyZod.ts +15 -0
- package/test/data-obj/apikey/root-mongo-user-apikey.ts +10 -0
- package/test/data-obj/roles/admin-mongo-role.ts +0 -3
- package/test/initializers/RoleMongoInitializer.ts +1 -0
- package/test/initializers/RoleSqliteInitializer.ts +1 -0
- package/test/initializers/UserMongoInitializer.ts +18 -0
- package/test/repository/mongo/user-apikey-mongo-repository.test.ts +73 -0
- package/tsconfig.tsbuildinfo +1 -1
- package/types/config/IdentityConfig.d.ts +2 -3
- package/types/config/IdentityConfig.d.ts.map +1 -1
- package/types/errors/BadCredentialsError.d.ts +6 -0
- package/types/errors/BadCredentialsError.d.ts.map +1 -0
- package/types/errors/UnauthorizedError.d.ts +6 -0
- package/types/errors/UnauthorizedError.d.ts.map +1 -0
- package/types/factory/RoleServiceFactory.d.ts +4 -0
- package/types/factory/RoleServiceFactory.d.ts.map +1 -1
- package/types/factory/TenantServiceFactory.d.ts +4 -0
- package/types/factory/TenantServiceFactory.d.ts.map +1 -1
- package/types/factory/UserApiKeyServiceFactory.d.ts +4 -0
- package/types/factory/UserApiKeyServiceFactory.d.ts.map +1 -0
- package/types/factory/UserServiceFactory.d.ts +4 -0
- package/types/factory/UserServiceFactory.d.ts.map +1 -1
- package/types/graphql/index.d.ts +6 -0
- package/types/graphql/resolvers/tenant.resolvers.d.ts.map +1 -1
- package/types/graphql/resolvers/user-api-key.resolvers.d.ts +37 -0
- package/types/graphql/resolvers/user-api-key.resolvers.d.ts.map +1 -0
- package/types/graphql/resolvers/user.resolvers.d.ts.map +1 -1
- package/types/index.d.ts +35 -0
- package/types/index.d.ts.map +1 -1
- package/types/interfaces/IRoleRepository.d.ts +9 -0
- package/types/interfaces/ITenantRepository.d.ts +9 -0
- package/types/interfaces/IUserApiKeyRepository.d.ts +7 -0
- package/types/interfaces/IUserApiKeyRepository.d.ts.map +1 -0
- package/types/interfaces/IUserRepository.d.ts +10 -0
- package/types/middleware/apiKeyMiddleware.d.ts +4 -0
- package/types/middleware/apiKeyMiddleware.d.ts.map +1 -0
- package/types/middleware/jwtMiddleware.d.ts +4 -0
- package/types/middleware/rbacMiddleware.d.ts +4 -0
- package/types/middleware/rbacMiddleware.d.ts.map +1 -1
- package/types/models/RoleModel.d.ts +16 -0
- package/types/models/TenantModel.d.ts +16 -0
- package/types/models/UserApiKeyModel.d.ts +16 -0
- package/types/models/UserApiKeyModel.d.ts.map +1 -0
- package/types/models/UserGroupModel.d.ts +16 -0
- package/types/models/UserModel.d.ts +16 -0
- package/types/permissions/IdentityPermissions.d.ts +27 -0
- package/types/permissions/IdentityPermissions.d.ts.map +1 -0
- package/types/rbac/Rbac.d.ts +15 -0
- package/types/rbac/Rbac.d.ts.map +1 -1
- package/types/repository/mongo/RoleMongoRepository.d.ts +14 -0
- package/types/repository/mongo/TenantMongoRepository.d.ts +14 -0
- package/types/repository/mongo/UserApiKeyMongoRepository.d.ts +14 -0
- package/types/repository/mongo/UserApiKeyMongoRepository.d.ts.map +1 -0
- package/types/repository/mongo/UserMongoRepository.d.ts +17 -0
- package/types/repository/sqlite/RoleSqliteRepository.d.ts +22 -0
- package/types/repository/sqlite/RoleSqliteRepository.d.ts.map +1 -1
- package/types/repository/sqlite/TenantSqliteRepository.d.ts +19 -0
- package/types/repository/sqlite/TenantSqliteRepository.d.ts.map +1 -1
- package/types/repository/sqlite/UserApiKeySqliteRepository.d.ts +19 -0
- package/types/repository/sqlite/UserApiKeySqliteRepository.d.ts.map +1 -0
- package/types/repository/sqlite/UserSqliteRepository.d.ts +25 -0
- package/types/repository/sqlite/UserSqliteRepository.d.ts.map +1 -1
- package/types/routes/RoleRoutes.d.ts +4 -0
- package/types/routes/TenantRoutes.d.ts +4 -0
- package/types/routes/UserApiKeyRoutes.d.ts +4 -0
- package/types/routes/UserApiKeyRoutes.d.ts.map +1 -0
- package/types/routes/UserAvatarRoutes.d.ts +4 -0
- package/types/routes/UserRoutes.d.ts +4 -0
- package/types/routes/UserRoutes.d.ts.map +1 -1
- package/types/services/PermissionService.d.ts +9 -0
- package/types/services/PermissionService.d.ts.map +1 -0
- package/types/services/RoleService.d.ts +16 -0
- package/types/services/TenantService.d.ts +16 -0
- package/types/services/TenantService.d.ts.map +1 -1
- package/types/services/UserApiKeyService.d.ts +15 -0
- package/types/services/UserApiKeyService.d.ts.map +1 -0
- package/types/services/UserService.d.ts +21 -0
- package/types/services/UserService.d.ts.map +1 -1
- package/types/setup/CreateOrUpdateRole.d.ts +5 -0
- package/types/setup/CreateUserIfNotExist.d.ts +5 -0
- package/types/setup/LoadIdentityConfigFromEnv.d.ts +4 -0
- package/types/setup/LoadIdentityConfigFromEnv.d.ts.map +1 -1
- package/types/setup/LoadPermissions.d.ts +4 -0
- package/types/setup/LoadPermissions.d.ts.map +1 -0
- package/types/setup/RecoveryUserPassword.d.ts +4 -0
- package/types/utils/AuthUtils.d.ts +18 -0
- package/types/utils/AuthUtils.d.ts.map +1 -1
- package/types/zod/RoleZod.d.ts +10 -0
- package/types/zod/RoleZod.d.ts.map +1 -0
- package/types/zod/TenantZod.d.ts +10 -0
- package/types/zod/TenantZod.d.ts.map +1 -0
- package/types/zod/UserApiKeyZod.d.ts +16 -0
- package/types/zod/UserApiKeyZod.d.ts.map +1 -0
- package/types/zod/UserZod.d.ts +53 -0
- package/types/zod/UserZod.d.ts.map +1 -0
- package/src/utils/DbSetupUtils.ts +0 -41
- 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(
|
|
89
|
+
if(['eq','$eq'].includes(filter.operator)){
|
|
90
90
|
query[filter.field] = {$eq: filter.value}
|
|
91
91
|
}
|
|
92
|
-
if(
|
|
92
|
+
if(['ne','$ne'].includes(filter.operator)){
|
|
93
93
|
query[filter.field] = {$ne: filter.value}
|
|
94
94
|
}
|
|
95
|
-
if(
|
|
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
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
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(
|
|
26
|
-
this.
|
|
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
|
-
|
|
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(
|
|
22
|
-
this.
|
|
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
|
-
|
|
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 {
|
|
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
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
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(
|
|
35
|
-
this.
|
|
36
|
-
this.
|
|
37
|
-
this.
|
|
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
|
-
|
|
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(
|
|
166
|
+
if(['eq','$eq'].includes(filter.operator)){
|
|
157
167
|
whereFilters.push(` ${filter.field} = '${filter.value}' `)
|
|
158
168
|
}
|
|
159
|
-
if(
|
|
169
|
+
if(['ne','$ne'].includes(filter.operator)){
|
|
160
170
|
whereFilters.push(` ${filter.field} != '${filter.value}' `)
|
|
161
171
|
}
|
|
162
|
-
if(
|
|
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
|
-
|
|
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
|
|