@drax/identity-back 0.5.3 → 0.5.5

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 (71) hide show
  1. package/dist/controllers/RoleController.js +84 -0
  2. package/dist/controllers/TenantController.js +1 -2
  3. package/dist/controllers/UserApiKeyController.js +127 -0
  4. package/dist/controllers/UserController.js +295 -0
  5. package/dist/index.js +1 -2
  6. package/dist/repository/mongo/RoleMongoRepository.js +35 -3
  7. package/dist/repository/mongo/TenantMongoRepository.js +25 -2
  8. package/dist/repository/mongo/UserMongoRepository.js +23 -0
  9. package/dist/repository/sqlite/TenantSqliteRepository.js +1 -1
  10. package/dist/routes/RoleRoutes.js +12 -207
  11. package/dist/routes/TenantRoutes.js +1 -0
  12. package/dist/routes/UserApiKeyRoutes.js +6 -114
  13. package/dist/routes/UserRoutes.js +13 -218
  14. package/dist/services/RoleService.js +42 -2
  15. package/dist/services/TenantService.js +5 -0
  16. package/dist/services/UserApiKeyService.js +9 -1
  17. package/dist/services/UserService.js +14 -4
  18. package/dist/setup/CreateOrUpdateRole.js +1 -1
  19. package/package.json +4 -4
  20. package/src/controllers/RoleController.ts +94 -0
  21. package/src/controllers/TenantController.ts +1 -2
  22. package/src/controllers/UserApiKeyController.ts +144 -0
  23. package/src/controllers/UserController.ts +300 -0
  24. package/src/index.ts +0 -2
  25. package/src/interfaces/IRoleRepository.ts +2 -2
  26. package/src/repository/mongo/RoleMongoRepository.ts +75 -19
  27. package/src/repository/mongo/TenantMongoRepository.ts +36 -3
  28. package/src/repository/mongo/UserMongoRepository.ts +49 -2
  29. package/src/repository/sqlite/TenantSqliteRepository.ts +0 -1
  30. package/src/routes/RoleRoutes.ts +22 -195
  31. package/src/routes/TenantRoutes.ts +2 -0
  32. package/src/routes/UserApiKeyRoutes.ts +6 -113
  33. package/src/routes/UserRoutes.ts +13 -201
  34. package/src/services/RoleService.ts +45 -4
  35. package/src/services/TenantService.ts +7 -1
  36. package/src/services/UserApiKeyService.ts +11 -1
  37. package/src/services/UserService.ts +16 -4
  38. package/src/setup/CreateOrUpdateRole.ts +1 -1
  39. package/tsconfig.tsbuildinfo +1 -1
  40. package/types/controllers/RoleController.d.ts +14 -0
  41. package/types/controllers/RoleController.d.ts.map +1 -0
  42. package/types/controllers/TenantController.d.ts.map +1 -1
  43. package/types/controllers/UserApiKeyController.d.ts +14 -0
  44. package/types/controllers/UserApiKeyController.d.ts.map +1 -0
  45. package/types/controllers/UserController.d.ts +27 -0
  46. package/types/controllers/UserController.d.ts.map +1 -0
  47. package/types/index.d.ts +1 -2
  48. package/types/index.d.ts.map +1 -1
  49. package/types/interfaces/IRoleRepository.d.ts +2 -2
  50. package/types/interfaces/IRoleRepository.d.ts.map +1 -1
  51. package/types/repository/mongo/RoleMongoRepository.d.ts +33 -1
  52. package/types/repository/mongo/RoleMongoRepository.d.ts.map +1 -1
  53. package/types/repository/mongo/TenantMongoRepository.d.ts +32 -1
  54. package/types/repository/mongo/TenantMongoRepository.d.ts.map +1 -1
  55. package/types/repository/mongo/UserMongoRepository.d.ts +31 -1
  56. package/types/repository/mongo/UserMongoRepository.d.ts.map +1 -1
  57. package/types/repository/sqlite/TenantSqliteRepository.d.ts +1 -1
  58. package/types/repository/sqlite/TenantSqliteRepository.d.ts.map +1 -1
  59. package/types/routes/RoleRoutes.d.ts.map +1 -1
  60. package/types/routes/TenantRoutes.d.ts.map +1 -1
  61. package/types/routes/UserApiKeyRoutes.d.ts.map +1 -1
  62. package/types/routes/UserRoutes.d.ts.map +1 -1
  63. package/types/services/RoleService.d.ts +5 -1
  64. package/types/services/RoleService.d.ts.map +1 -1
  65. package/types/services/TenantService.d.ts +1 -0
  66. package/types/services/TenantService.d.ts.map +1 -1
  67. package/types/services/UserApiKeyService.d.ts +2 -1
  68. package/types/services/UserApiKeyService.d.ts.map +1 -1
  69. package/types/services/UserService.d.ts +3 -1
  70. package/types/services/UserService.d.ts.map +1 -1
  71. package/src/routes/UserAvatarRoutes.ts +0 -82
@@ -1,218 +1,30 @@
1
- import UserServiceFactory from "../factory/UserServiceFactory.js";
2
- import {IUser} from "@drax/identity-share";
3
- import {ValidationError, UnauthorizedError} from "@drax/common-back";
4
- import {IdentityPermissions} from "../permissions/IdentityPermissions.js";
5
- import BadCredentialsError from "../errors/BadCredentialsError.js";
6
- import {IDraxPaginateResult} from "@drax/crud-share";
1
+ import UserController from "../controllers/UserController.js";
7
2
 
8
3
  async function UserRoutes(fastify, options) {
9
- fastify.post('/api/auth', async (request, reply) => {
10
- try {
11
- const username = request.body.username
12
- const password = request.body.password
13
- const userService = UserServiceFactory()
14
- return await userService.auth(username, password)
15
- } catch (e) {
16
- console.error('/api/auth error', e)
17
- if (e instanceof BadCredentialsError) {
18
- reply.code(401)
19
- reply.send({error: e.message})
20
- }
21
- reply.code(500)
22
- reply.send({error: 'error.server'})
23
- }
24
- })
25
4
 
5
+ const controller: UserController = new UserController()
26
6
 
7
+ fastify.post('/api/auth', (req,rep) => controller.auth(req,rep))
27
8
 
9
+ fastify.get('/api/me', (req,rep) => controller.me(req,rep))
28
10
 
29
- fastify.get('/api/me', async (request, reply): Promise<IUser | null> => {
30
- try {
31
- if (request.authUser) {
32
- const userService = UserServiceFactory()
33
- let user = await userService.findById(request.authUser.id)
34
- user.password = undefined
35
- delete user.password
36
- return user
37
- } else {
38
- throw new UnauthorizedError()
11
+ fastify.get('/api/users/export', (req,rep) => controller.export(req,rep) )
39
12
 
40
- }
41
- } catch (e) {
42
- if (e instanceof UnauthorizedError) {
43
- reply.code(401)
44
- reply.send({error: "Unauthorized"})
45
- } else if (e instanceof UnauthorizedError) {
46
- reply.statusCode = e.statusCode
47
- reply.send({error: e.message})
48
- } else {
49
- reply.statusCode = 500
50
- reply.send({error: 'error.server'})
51
- }
52
- }
13
+ fastify.get('/api/users', (req,rep) => controller.paginate(req,rep))
53
14
 
15
+ fastify.post('/api/users', (req,rep) => controller.create(req,rep))
54
16
 
55
- })
17
+ fastify.put('/api/users/:id', (req,rep) => controller.update(req,rep))
56
18
 
57
- fastify.get('/api/users', async (request, reply): Promise<IDraxPaginateResult<IUser>> => {
19
+ fastify.delete('/api/users/:id', (req,rep) => controller.delete(req,rep))
58
20
 
59
- try {
60
- request.rbac.assertPermission(IdentityPermissions.ViewUser)
61
- const page = request.query.page
62
- const limit = request.query.limit
63
- const orderBy = request.query.orderBy
64
- const order = request.query.order
65
- const search = request.query.search
66
- const userService = UserServiceFactory()
67
- const filters = []
68
- if(request.rbac.getAuthUser.tenantId){
69
- filters.push({field: 'tenant', operator: 'eq', value: request.rbac.getAuthUser.tenantId})
70
- }
71
- let paginateResult = await userService.paginate({page, limit, orderBy, order, search, filters})
72
- for(let item of paginateResult.items){
73
- item.password = undefined
74
- delete item.password
75
- }
76
- return paginateResult
77
- } catch (e) {
78
- if (e instanceof ValidationError) {
79
- reply.statusCode = e.statusCode
80
- reply.send({error: e.message, inputErrors: e.errors})
81
- } else if (e instanceof UnauthorizedError) {
82
- reply.statusCode = e.statusCode
83
- reply.send({error: e.message})
84
- } else {
85
- reply.statusCode = 500
86
- reply.send({error: 'error.server'})
87
- }
88
- }
89
- })
21
+ fastify.post('/api/password', (req,rep) => controller.myPassword(req,rep))
90
22
 
91
- fastify.post('/api/users', async (request, reply): Promise<IUser> => {
92
- try {
93
- request.rbac.assertPermission(IdentityPermissions.CreateUser)
94
- const payload = request.body
95
- const userService = UserServiceFactory()
96
- if(request.rbac.getAuthUser.tenantId){
97
- payload.tenant = request.rbac.getAuthUser.tenantId
98
- }
99
- let user = await userService.create(payload)
100
- return user
101
- } catch (e) {
102
- if (e instanceof ValidationError) {
103
- reply.statusCode = e.statusCode
104
- reply.send({error: e.message, inputErrors: e.errors})
105
- } else if (e instanceof UnauthorizedError) {
106
- reply.statusCode = e.statusCode
107
- reply.send({error: e.message})
108
- } else {
109
- reply.statusCode = 500
110
- reply.send({error: 'error.server'})
111
- }
112
- }
23
+ fastify.post('/api/password/:id', (req,rep) => controller.password(req,rep))
113
24
 
114
- })
25
+ fastify.post('/api/user/avatar', (req,rep) => controller.updateAvatar(req,rep))
115
26
 
116
- fastify.put('/api/users/:id', async (request, reply): Promise<IUser> => {
117
- try {
118
- request.rbac.assertPermission(IdentityPermissions.UpdateUser)
119
- const id = request.params.id
120
- const payload = request.body
121
- const userService = UserServiceFactory()
122
- if(request.rbac.getAuthUser.tenantId){
123
- payload.tenant = request.rbac.getAuthUser.tenantId
124
- }
125
- let user = await userService.update(id, payload)
126
- return user
127
- } catch (e) {
128
- if (e instanceof ValidationError) {
129
- reply.statusCode = e.statusCode
130
- reply.send({error: e.message, inputErrors: e.errors})
131
- }
132
- if (e instanceof UnauthorizedError) {
133
- reply.statusCode = e.statusCode
134
- reply.send({error: e.message})
135
- } else if (e instanceof UnauthorizedError) {
136
- reply.statusCode = e.statusCode
137
- reply.send({error: e.message})
138
- } else {
139
- reply.statusCode = 500
140
- reply.send({error: 'error.server'})
141
- }
142
- }
143
- })
144
-
145
- fastify.delete('/api/users/:id', async (request, reply): Promise<any> => {
146
- try {
147
- request.rbac.assertPermission(IdentityPermissions.DeleteUser)
148
- const id = request.params.id
149
- const userService = UserServiceFactory()
150
- let r = await userService.delete(id)
151
- return r
152
- } catch (e) {
153
- if (e instanceof ValidationError) {
154
- reply.statusCode = e.statusCode
155
- reply.send({error: e.message, inputErrors: e.errors})
156
- } else if (e instanceof UnauthorizedError) {
157
- reply.statusCode = e.statusCode
158
- reply.send({error: e.message})
159
- } else {
160
- reply.statusCode = 500
161
- reply.send({error: 'error.server'})
162
- }
163
- }
164
- })
165
-
166
- fastify.post('/api/password', async (request, reply) => {
167
- try {
168
- if(!request.authUser){
169
- throw new UnauthorizedError()
170
- }
171
- const userId = request.authUser.id
172
- const currentPassword = request.body.currentPassword
173
- const newPassword = request.body.newPassword
174
- const userService = UserServiceFactory()
175
- return await userService.changeOwnPassword(userId, currentPassword, newPassword)
176
- } catch (e) {
177
- console.error('/api/password error', e)
178
- if (e instanceof ValidationError) {
179
- reply.statusCode = e.statusCode
180
- reply.send({error: e.message, inputErrors: e.errors})
181
- } else if (e instanceof UnauthorizedError) {
182
- reply.statusCode = e.statusCode
183
- reply.send({error: e.message})
184
- } else {
185
- reply.statusCode = 500
186
- reply.send({error: 'error.server'})
187
- }
188
- }
189
- })
190
-
191
-
192
- fastify.post('/api/password/:id', async (request, reply) => {
193
- try {
194
- request.rbac.assertPermission(IdentityPermissions.UpdateUser)
195
- const userId = request.params.id
196
- if(!userId){
197
- throw new UnauthorizedError()
198
- }
199
- const newPassword = request.body.newPassword
200
- const userService = UserServiceFactory()
201
- return await userService.changeUserPassword(userId, newPassword)
202
- } catch (e) {
203
- console.error('/api/password error', e)
204
- if (e instanceof ValidationError) {
205
- reply.statusCode = e.statusCode
206
- reply.send({error: e.message, inputErrors: e.errors})
207
- } else if (e instanceof UnauthorizedError) {
208
- reply.statusCode = e.statusCode
209
- reply.send({error: e.message})
210
- } else {
211
- reply.statusCode = 500
212
- reply.send({error: 'error.server'})
213
- }
214
- }
215
- })
27
+ fastify.get('/api/user/avatar/:filename', (req,rep) => controller.getAvatar(req,rep))
216
28
 
217
29
  }
218
30
 
@@ -1,15 +1,17 @@
1
1
  import {IRoleRepository} from "../interfaces/IRoleRepository";
2
- import { ZodErrorToValidationError} from "@drax/common-back"
2
+ import {UnauthorizedError, ValidationError, ZodErrorToValidationError} from "@drax/common-back"
3
+ import { AbstractService } from "@drax/crud-back"
3
4
  import {roleSchema} from "../zod/RoleZod.js";
4
5
  import {ZodError} from "zod";
5
6
  import {IDraxPaginateOptions, IDraxPaginateResult} from "@drax/crud-share";
6
7
  import type {IRoleBase, IRole} from "@drax/identity-share";
7
8
 
8
- class RoleService {
9
+ class RoleService extends AbstractService<IRole, IRoleBase, IRoleBase> {
9
10
 
10
11
  _repository: IRoleRepository
11
12
 
12
13
  constructor(roleRepostitory: IRoleRepository) {
14
+ super(roleRepostitory, roleSchema)
13
15
  this._repository = roleRepostitory
14
16
  console.log("RoleService constructor")
15
17
  }
@@ -29,11 +31,15 @@ class RoleService {
29
31
  }
30
32
  }
31
33
 
32
- async update(id: string, roleData: IRoleBase) {
34
+ async update(id: string, roleData: IRoleBase): Promise<IRole> {
33
35
  try {
34
36
  roleData.name = roleData?.name?.trim()
35
37
  await roleSchema.parseAsync(roleData)
36
- const role = await this._repository.update(id, roleData)
38
+ const currentRole = await this.findById(id)
39
+ if(currentRole.readonly){
40
+ throw new ValidationError([{field:'name', reason:"role.readonly", value:roleData.name}])
41
+ }
42
+ const role: IRole = await this._repository.update(id, roleData)
37
43
  return role
38
44
  } catch (e) {
39
45
  console.error("Error updating role", e)
@@ -44,7 +50,36 @@ class RoleService {
44
50
  }
45
51
  }
46
52
 
53
+ async systemUpdate(id: string, roleData: IRoleBase): Promise<IRole> {
54
+ try {
55
+ roleData.name = roleData?.name?.trim()
56
+ await roleSchema.parseAsync(roleData)
57
+ const role: IRole = await this._repository.update(id, roleData)
58
+ return role
59
+ } catch (e) {
60
+ console.error("Error systemUpdating role", e)
61
+ if (e instanceof ZodError) {
62
+ throw ZodErrorToValidationError(e, roleData)
63
+ }
64
+ throw e
65
+ }
66
+ }
67
+
47
68
  async delete(id: string): Promise<boolean> {
69
+ try {
70
+ const currentRole = await this.findById(id)
71
+ if(currentRole.readonly){
72
+ throw new UnauthorizedError()
73
+ }
74
+ const deletedRole = await this._repository.delete(id);
75
+ return deletedRole;
76
+ } catch (e) {
77
+ console.error("Error deleting role", e)
78
+ throw e
79
+ }
80
+ }
81
+
82
+ async systemDelete(id: string): Promise<boolean> {
48
83
  try {
49
84
  const deletedRole = await this._repository.delete(id);
50
85
  return deletedRole;
@@ -81,6 +116,12 @@ class RoleService {
81
116
  return roles
82
117
  }
83
118
 
119
+ async search(value: any): Promise<IRole[]> {
120
+ const limit = 100
121
+ const roles: IRole[] = await this._repository.search(value, limit);
122
+ return roles;
123
+ }
124
+
84
125
  async paginate({
85
126
  page = 1,
86
127
  limit = 5,
@@ -2,7 +2,7 @@ import {ITenantRepository} from "../interfaces/ITenantRepository";
2
2
  import {ValidationError, ZodErrorToValidationError} from "@drax/common-back"
3
3
  import {tenantSchema} from "../zod/TenantZod.js";
4
4
  import {ZodError} from "zod";
5
- import {ITenantBase, ITenant} from "@drax/identity-share";
5
+ import {ITenantBase, ITenant, IRole} from "@drax/identity-share";
6
6
  import {IDraxPaginateOptions, IDraxPaginateResult} from "@drax/crud-share";
7
7
  import {AbstractService} from "@drax/crud-back";
8
8
 
@@ -90,6 +90,12 @@ class TenantService extends AbstractService<ITenant,ITenantBase,ITenantBase> {
90
90
 
91
91
  }
92
92
 
93
+ async search(value: any): Promise<ITenant[]> {
94
+ const limit = 100
95
+ const tenants: ITenant[] = await this._repository.search(value, limit);
96
+ return tenants;
97
+ }
98
+
93
99
  async paginate({
94
100
  page = 1,
95
101
  limit = 5,
@@ -7,12 +7,14 @@ import {IDraxPaginateOptions, IDraxPaginateResult} from "@drax/crud-share";
7
7
  import crypto from "node:crypto";
8
8
  import AuthUtils from "../utils/AuthUtils.js";
9
9
  import IdentityConfig from "../config/IdentityConfig.js";
10
+ import {AbstractService} from "@drax/crud-back";
10
11
 
11
- class UserApiKeyService {
12
+ class UserApiKeyService extends AbstractService<IUserApiKey, IUserApiKeyBase, IUserApiKeyBase>{
12
13
 
13
14
  _repository: IUserApiKeyRepository
14
15
 
15
16
  constructor(userApiKeyRepostitory: IUserApiKeyRepository) {
17
+ super(userApiKeyRepostitory,userApiKeySchema)
16
18
  this._repository = userApiKeyRepostitory
17
19
  console.log("UserApiKeyService constructor")
18
20
  }
@@ -22,6 +24,9 @@ class UserApiKeyService {
22
24
  userApiKeyData.name = userApiKeyData?.name?.trim()
23
25
  const secret = crypto.randomUUID()
24
26
  const APIKEY_SECRET = DraxConfig.getOrLoad(IdentityConfig.ApiKeySecret)
27
+ if(!APIKEY_SECRET){
28
+ throw new Error('ApiKey miss configuration')
29
+ }
25
30
  userApiKeyData.secret = AuthUtils.generateHMAC(APIKEY_SECRET, secret)
26
31
  await userApiKeySchema.parseAsync(userApiKeyData)
27
32
  const userApiKey = await this._repository.create(userApiKeyData)
@@ -74,9 +79,14 @@ class UserApiKeyService {
74
79
 
75
80
  }
76
81
 
82
+
83
+
77
84
  async findBySecret(secret: string): Promise<IUserApiKey | null> {
78
85
  try{
79
86
  const APIKEY_SECRET = DraxConfig.getOrLoad(IdentityConfig.ApiKeySecret)
87
+ if(!APIKEY_SECRET){
88
+ throw new Error('ApiKey miss configuration')
89
+ }
80
90
  const hashedSecret = AuthUtils.generateHMAC(APIKEY_SECRET, secret)
81
91
  const userApiKey: IUserApiKey = await this._repository.findBySecret(hashedSecret);
82
92
  return userApiKey
@@ -3,15 +3,18 @@ import type {IUserRepository} from "../interfaces/IUserRepository";
3
3
  import {ZodError} from "zod";
4
4
  import {ValidationError, ZodErrorToValidationError} from "@drax/common-back";
5
5
  import AuthUtils from "../utils/AuthUtils.js";
6
- import {createUserSchema, editUserSchema,} from "../zod/UserZod.js";
6
+ import {createUserSchema, editUserSchema, userBaseSchema} from "../zod/UserZod.js";
7
7
  import BadCredentialsError from "../errors/BadCredentialsError.js";
8
8
  import {IDraxPaginateOptions, IDraxPaginateResult} from "@drax/crud-share";
9
+ import {AbstractService} from "@drax/crud-back";
10
+ import {ITenant} from "@drax/identity-share";
9
11
 
10
- class UserService {
12
+ class UserService extends AbstractService<IUser, IUserCreate, IUserUpdate>{
11
13
 
12
14
  _repository: IUserRepository
13
15
 
14
16
  constructor(userRepository: IUserRepository) {
17
+ super(userRepository,userBaseSchema);
15
18
  this._repository = userRepository;
16
19
  console.log("UserService constructor")
17
20
  }
@@ -123,8 +126,11 @@ class UserService {
123
126
 
124
127
  async delete(id: string): Promise<boolean> {
125
128
  try {
126
- const deletedRole: boolean = await this._repository.delete(id);
127
- return deletedRole;
129
+ const result: boolean = await this._repository.delete(id);
130
+ if(!result){
131
+ throw new Error("error.deletionFailed")
132
+ }
133
+ return result;
128
134
  } catch (e) {
129
135
  console.error("Error deleting user", e)
130
136
  throw e
@@ -171,6 +177,12 @@ class UserService {
171
177
  }
172
178
 
173
179
  }
180
+
181
+ async search(value: any): Promise<IUser[]> {
182
+ const limit = 100
183
+ const users: IUser[] = await this._repository.search(value, limit);
184
+ return users;
185
+ }
174
186
  }
175
187
 
176
188
  export default UserService
@@ -18,7 +18,7 @@ async function CreateOrUpdateRole(roleData: IRoleBase) {
18
18
  }
19
19
 
20
20
  if(role){
21
- const r = await roleService.update(role.id, roleData)
21
+ const r = await roleService.systemUpdate(role.id, roleData)
22
22
  console.log("Role Updated. Name: "+ roleData.name)
23
23
  }else{
24
24
  const r = await roleService.create(roleData)