@drax/identity-back 0.0.28 → 0.0.30

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 (115) hide show
  1. package/dist/config/IdentityConfig.js +1 -0
  2. package/dist/graphql/resolvers/role.resolvers.js +2 -2
  3. package/dist/graphql/resolvers/tenant.resolvers.js +2 -2
  4. package/dist/graphql/resolvers/user.resolvers.js +40 -4
  5. package/dist/graphql/types/user.graphql +2 -0
  6. package/dist/index.js +2 -2
  7. package/dist/rbac/Rbac.js +5 -0
  8. package/dist/repository/mongo/UserMongoRepository.js +10 -0
  9. package/dist/repository/sqlite/RoleSqliteRepository.js +1 -1
  10. package/dist/repository/sqlite/TenantSqliteRepository.js +1 -1
  11. package/dist/repository/sqlite/UserSqliteRepository.js +7 -0
  12. package/dist/routes/UserAvatarRoutes.js +70 -0
  13. package/dist/services/UserService.js +13 -0
  14. package/package.json +5 -5
  15. package/src/config/IdentityConfig.ts +2 -0
  16. package/src/graphql/resolvers/role.resolvers.ts +2 -2
  17. package/src/graphql/resolvers/tenant.resolvers.ts +2 -2
  18. package/src/graphql/resolvers/user.resolvers.ts +63 -16
  19. package/src/graphql/types/user.graphql +2 -0
  20. package/src/index.ts +2 -1
  21. package/src/interfaces/IUserRepository.ts +1 -0
  22. package/src/rbac/Rbac.ts +6 -0
  23. package/src/repository/mongo/UserMongoRepository.ts +10 -0
  24. package/src/repository/sqlite/RoleSqliteRepository.ts +1 -1
  25. package/src/repository/sqlite/TenantSqliteRepository.ts +1 -1
  26. package/src/repository/sqlite/UserSqliteRepository.ts +8 -0
  27. package/src/routes/UserAvatarRoutes.ts +82 -0
  28. package/src/services/UserService.ts +17 -0
  29. package/test/data-obj/roles/admin-mongo-role.ts +1 -1
  30. package/test/repository/mongo/role-mongo-repository.test.ts +2 -3
  31. package/test/repository/mongo/user-mongo-repository.test.ts +2 -2
  32. package/test/repository/sqlite/role-sqlite-repository.test.ts +2 -2
  33. package/test/repository/sqlite/user-sqlite-repository.test.ts +1 -1
  34. package/tsconfig.json +1 -11
  35. package/tsconfig.tsbuildinfo +1 -1
  36. package/types/config/IdentityConfig.d.ts +2 -1
  37. package/types/config/IdentityConfig.d.ts.map +1 -1
  38. package/types/graphql/resolvers/role.resolvers.d.ts +9 -6
  39. package/types/graphql/resolvers/role.resolvers.d.ts.map +1 -1
  40. package/types/graphql/resolvers/tenant.resolvers.d.ts +9 -6
  41. package/types/graphql/resolvers/tenant.resolvers.d.ts.map +1 -1
  42. package/types/graphql/resolvers/user.resolvers.d.ts +15 -7
  43. package/types/graphql/resolvers/user.resolvers.d.ts.map +1 -1
  44. package/types/index.d.ts.map +1 -1
  45. package/types/repository/mongo/UserMongoRepository.d.ts.map +1 -1
  46. package/types/repository/sqlite/UserSqliteRepository.d.ts.map +1 -1
  47. package/types/routes/UserAvatarRoutes.d.ts.map +1 -0
  48. package/types/services/UserService.d.ts.map +1 -1
  49. package/types/errors/BadCredentialsError.d.ts +0 -6
  50. package/types/errors/BadCredentialsError.d.ts.map +0 -1
  51. package/types/errors/UnauthorizedError.d.ts +0 -6
  52. package/types/errors/UnauthorizedError.d.ts.map +0 -1
  53. package/types/factory/RoleServiceFactory.d.ts +0 -4
  54. package/types/factory/TenantServiceFactory.d.ts +0 -4
  55. package/types/factory/UserServiceFactory.d.ts +0 -4
  56. package/types/graphql/index.d.ts +0 -6
  57. package/types/index.d.ts +0 -31
  58. package/types/interfaces/IID.d.ts +0 -6
  59. package/types/interfaces/IID.d.ts.map +0 -1
  60. package/types/interfaces/IJwtUser.d.ts +0 -7
  61. package/types/interfaces/IJwtUser.d.ts.map +0 -1
  62. package/types/interfaces/IRole.d.ts +0 -18
  63. package/types/interfaces/IRole.d.ts.map +0 -1
  64. package/types/interfaces/IRoleRepository.d.ts +0 -9
  65. package/types/interfaces/IRoleRepository.d.ts.map +0 -1
  66. package/types/interfaces/ITenant.d.ts +0 -7
  67. package/types/interfaces/ITenant.d.ts.map +0 -1
  68. package/types/interfaces/ITenantRepository.d.ts +0 -9
  69. package/types/interfaces/ITenantRepository.d.ts.map +0 -1
  70. package/types/interfaces/IUser.d.ts +0 -45
  71. package/types/interfaces/IUser.d.ts.map +0 -1
  72. package/types/interfaces/IUserGroup.d.ts +0 -11
  73. package/types/interfaces/IUserGroup.d.ts.map +0 -1
  74. package/types/interfaces/IUserRepository.d.ts +0 -9
  75. package/types/interfaces/IUserRepository.d.ts.map +0 -1
  76. package/types/middleware/jwtMiddleware.d.ts +0 -4
  77. package/types/middleware/rbacMiddleware.d.ts +0 -4
  78. package/types/models/RoleModel.d.ts +0 -16
  79. package/types/models/TenantModel.d.ts +0 -16
  80. package/types/models/UserGroupModel.d.ts +0 -16
  81. package/types/models/UserModel.d.ts +0 -16
  82. package/types/permissions/IdentityPermissions.d.ts +0 -21
  83. package/types/permissions/IdentityPermissions.d.ts.map +0 -1
  84. package/types/rbac/Rbac.d.ts +0 -13
  85. package/types/rbac/Rbac.d.ts.map +0 -1
  86. package/types/repository/mongo/RoleMongoRepository.d.ts +0 -14
  87. package/types/repository/mongo/TenantMongoRepository.d.ts +0 -14
  88. package/types/repository/mongo/UserMongoRepository.d.ts +0 -16
  89. package/types/repository/sqlite/RoleSqliteRepository.d.ts +0 -21
  90. package/types/repository/sqlite/TenantSqliteRepository.d.ts +0 -18
  91. package/types/repository/sqlite/UserSqliteRepository.d.ts +0 -23
  92. package/types/routes/RoleRoutes.d.ts +0 -4
  93. package/types/routes/TenantRoutes.d.ts +0 -4
  94. package/types/routes/UserRoutes.d.ts +0 -4
  95. package/types/services/PermissionService.d.ts +0 -9
  96. package/types/services/PermissionService.d.ts.map +0 -1
  97. package/types/services/RoleService.d.ts +0 -16
  98. package/types/services/TenantService.d.ts +0 -16
  99. package/types/services/UserService.d.ts +0 -20
  100. package/types/setup/CreateOrUpdateRole.d.ts +0 -5
  101. package/types/setup/CreateUserIfNotExist.d.ts +0 -5
  102. package/types/setup/LoadConfigFromEnv.d.ts +0 -4
  103. package/types/setup/LoadConfigFromEnv.d.ts.map +0 -1
  104. package/types/setup/LoadIdentityConfigFromEnv.d.ts +0 -4
  105. package/types/setup/LoadPermissions.d.ts +0 -4
  106. package/types/setup/LoadPermissions.d.ts.map +0 -1
  107. package/types/setup/RecoveryUserPassword.d.ts +0 -4
  108. package/types/utils/AuthUtils.d.ts +0 -16
  109. package/types/utils/DbSetupUtils.d.ts +0 -10
  110. package/types/zod/RoleZod.d.ts +0 -10
  111. package/types/zod/RoleZod.d.ts.map +0 -1
  112. package/types/zod/TenantZod.d.ts +0 -10
  113. package/types/zod/TenantZod.d.ts.map +0 -1
  114. package/types/zod/UserZod.d.ts +0 -53
  115. package/types/zod/UserZod.d.ts.map +0 -1
@@ -7,6 +7,7 @@ var IdentityConfig;
7
7
  IdentityConfig["JwtExpiration"] = "DRAX_JWT_EXPIRATION";
8
8
  IdentityConfig["JwtIssuer"] = "DRAX_JWT_ISSUER";
9
9
  IdentityConfig["RbacCacheTTL"] = "DRAX_RBAC_CACHE_TTL";
10
+ IdentityConfig["AvatarDir"] = "DRAX_AVATAR_DIR";
10
11
  })(IdentityConfig || (IdentityConfig = {}));
11
12
  export default IdentityConfig;
12
13
  export { IdentityConfig };
@@ -64,11 +64,11 @@ export default {
64
64
  throw new GraphQLError('error.server');
65
65
  }
66
66
  },
67
- paginateRole: async (_, { page, limit, orderBy, orderDesc, search }, { rbac }) => {
67
+ paginateRole: async (_, { options = { page: 1, limit: 5, orderBy: "", orderDesc: false, search: "", filters: [] } }, { rbac }) => {
68
68
  try {
69
69
  rbac.assertPermission(IdentityPermissions.ViewRole);
70
70
  const roleService = RoleServiceFactory();
71
- return await roleService.paginate({ page, limit, orderBy, orderDesc, search });
71
+ return await roleService.paginate(options);
72
72
  }
73
73
  catch (e) {
74
74
  console.error("paginateRole", e);
@@ -50,11 +50,11 @@ export default {
50
50
  throw new GraphQLError('error.server');
51
51
  }
52
52
  },
53
- paginateTenant: async (_, { page, limit, orderBy, orderDesc, search }, { rbac }) => {
53
+ paginateTenant: async (_, { options = { page: 1, limit: 5, orderBy: "", orderDesc: false, search: "", filters: [] } }, { rbac }) => {
54
54
  try {
55
55
  rbac.assertPermission(IdentityPermissions.ViewTenant);
56
56
  const tenantService = TenantServiceFactory();
57
- return await tenantService.paginate({ page, limit, orderBy, orderDesc, search });
57
+ return await tenantService.paginate(options);
58
58
  }
59
59
  catch (e) {
60
60
  console.error("paginateTenant", e);
@@ -1,9 +1,11 @@
1
1
  import UserServiceFactory from "../../factory/UserServiceFactory.js";
2
2
  import { GraphQLError } from "graphql";
3
- import { ValidationErrorToGraphQLError, ValidationError } from "@drax/common-back";
3
+ import { ValidationErrorToGraphQLError, ValidationError, StoreManager, DraxConfig, CommonConfig } from "@drax/common-back";
4
4
  import { IdentityPermissions } from "../../permissions/IdentityPermissions.js";
5
5
  import UnauthorizedError from "../../errors/UnauthorizedError.js";
6
6
  import BadCredentialsError from "../../errors/BadCredentialsError.js";
7
+ import { join } from "path";
8
+ import IdentityConfig from "../../config/IdentityConfig.js";
7
9
  export default {
8
10
  Query: {
9
11
  me: async (_, {}, { authUser }) => {
@@ -34,14 +36,14 @@ export default {
34
36
  throw new GraphQLError('error.server');
35
37
  }
36
38
  },
37
- paginateUser: async (_, { page, limit, orderBy, orderDesc, search, filters = [] }, { rbac }) => {
39
+ paginateUser: async (_, { options = { page: 1, limit: 5, orderBy: "", orderDesc: false, search: "", filters: [] } }, { rbac }) => {
38
40
  try {
39
41
  rbac.assertPermission(IdentityPermissions.ViewUser);
40
42
  let userService = UserServiceFactory();
41
43
  if (rbac.getAuthUser.tenantId) {
42
- filters.push({ field: 'tenant', operator: '$eq', value: rbac.getAuthUser.tenantId });
44
+ options.filters.push({ field: 'tenant', operator: '$eq', value: rbac.getAuthUser.tenantId });
43
45
  }
44
- return await userService.paginate({ page, limit, orderBy, orderDesc, search, filters });
46
+ return await userService.paginate(options);
45
47
  }
46
48
  catch (e) {
47
49
  if (e instanceof UnauthorizedError) {
@@ -158,5 +160,39 @@ export default {
158
160
  throw new GraphQLError('error.server');
159
161
  }
160
162
  },
163
+ changeAvatar: async (_, { file }, { rbac, authUser }) => {
164
+ try {
165
+ rbac.assertAuthenticated();
166
+ const userId = authUser.id;
167
+ const FILE_DIR = DraxConfig.getOrLoad(IdentityConfig.AvatarDir) || 'avatars';
168
+ const BASE_URL = DraxConfig.getOrLoad(CommonConfig.BaseUrl) ? DraxConfig.get(CommonConfig.BaseUrl).replace(/\/$/, '') : '';
169
+ //console.log("FILE:", file)
170
+ let preFile;
171
+ //Yoga PonyfillFile
172
+ if (file.blobParts) {
173
+ preFile = {
174
+ filename: file.name,
175
+ fileStream: file.blobParts,
176
+ mimetype: file.type,
177
+ encoding: file.encoding,
178
+ };
179
+ }
180
+ const destinationPath = join(FILE_DIR);
181
+ const storedFile = await StoreManager.saveFile(preFile, destinationPath);
182
+ const urlFile = BASE_URL + '/api/user/avatar/' + storedFile.filename;
183
+ let userService = UserServiceFactory();
184
+ return await userService.changeAvatar(userId, urlFile);
185
+ }
186
+ catch (e) {
187
+ console.error("changeAvatar", e);
188
+ if (e instanceof ValidationError) {
189
+ throw ValidationErrorToGraphQLError(e);
190
+ }
191
+ else if (e instanceof UnauthorizedError) {
192
+ throw new GraphQLError(e.message);
193
+ }
194
+ throw new GraphQLError('error.server');
195
+ }
196
+ },
161
197
  }
162
198
  };
@@ -54,6 +54,7 @@ input AuthInput{
54
54
  password: String!
55
55
  }
56
56
 
57
+
57
58
  type Mutation{
58
59
  auth(input: AuthInput): Auth
59
60
  createUser(input: UserCreateInput): User
@@ -61,4 +62,5 @@ type Mutation{
61
62
  deleteUser(id: ID!): Boolean
62
63
  changeOwnPassword(currentPassword:String!, newPassword: String!): Boolean
63
64
  changeUserPassword(userId:ID!, newPassword:String!): Boolean
65
+ changeAvatar(file: File!): Boolean
64
66
  }
package/dist/index.js CHANGED
@@ -8,6 +8,7 @@ import TenantService from "./services/TenantService.js";
8
8
  import PermissionService from "./services/PermissionService.js";
9
9
  import Rbac from "./rbac/Rbac.js";
10
10
  import { UserRoutes } from "./routes/UserRoutes.js";
11
+ import { UserAvatarRoutes } from "./routes/UserAvatarRoutes.js";
11
12
  import { RoleRoutes } from "./routes/RoleRoutes.js";
12
13
  import { TenantRoutes } from "./routes/TenantRoutes.js";
13
14
  import AuthUtils from "./utils/AuthUtils.js";
@@ -33,7 +34,7 @@ UserServiceFactory, RoleServiceFactory, TenantServiceFactory,
33
34
  //GQL
34
35
  identityTypeDefs, identityResolvers,
35
36
  //API REST
36
- UserRoutes, RoleRoutes, TenantRoutes, AuthUtils,
37
+ UserRoutes, RoleRoutes, TenantRoutes, UserAvatarRoutes, AuthUtils,
37
38
  //API MIDDLEWARE
38
39
  jwtMiddleware, rbacMiddleware,
39
40
  //Permissions
@@ -44,4 +45,3 @@ IdentityConfig,
44
45
  UnauthorizedError, BadCredentialsError,
45
46
  //Setup
46
47
  LoadIdentityConfigFromEnv, LoadPermissions, CreateOrUpdateRole, CreateUserIfNotExist, RecoveryUserPassword };
47
- /// <reference types="index.d.ts" />
package/dist/rbac/Rbac.js CHANGED
@@ -21,6 +21,11 @@ class Rbac {
21
21
  throw new UnauthorizedError();
22
22
  }
23
23
  }
24
+ assertAuthenticated() {
25
+ if (!this.authUser) {
26
+ throw new UnauthorizedError();
27
+ }
28
+ }
24
29
  }
25
30
  export default Rbac;
26
31
  export { Rbac };
@@ -91,5 +91,15 @@ class UserMongoRepository {
91
91
  return false;
92
92
  }
93
93
  }
94
+ async changeAvatar(id, avatar) {
95
+ try {
96
+ await UserModel.findOneAndUpdate({ _id: id }, { avatar }).exec();
97
+ return true;
98
+ }
99
+ catch (e) {
100
+ console.error(e);
101
+ return false;
102
+ }
103
+ }
94
104
  }
95
105
  export default UserMongoRepository;
@@ -76,7 +76,7 @@ class RoleSqliteRepository {
76
76
  where = ` WHERE name LIKE '%${search}%'`;
77
77
  }
78
78
  const rCount = this.db.prepare('SELECT COUNT(*) as count FROM roles' + where).get();
79
- const roles = this.db.prepare('SELECT * FROM roles LIMIT ? OFFSET ?' + where).all([limit, offset]);
79
+ const roles = this.db.prepare('SELECT * FROM roles ' + where + ' LIMIT ? OFFSET ?').all([limit, offset]);
80
80
  for (const role of roles) {
81
81
  await this.populateRole(role);
82
82
  }
@@ -83,7 +83,7 @@ class TenantSqliteRepository {
83
83
  where = ` WHERE name LIKE '%${search}%'`;
84
84
  }
85
85
  const rCount = this.db.prepare('SELECT COUNT(*) as count FROM tenants' + where).get();
86
- const tenants = this.db.prepare('SELECT * FROM tenants LIMIT ? OFFSET ?' + where).all([limit, offset]);
86
+ const tenants = this.db.prepare('SELECT * FROM tenants ' + where + ' LIMIT ? OFFSET ?').all([limit, offset]);
87
87
  return {
88
88
  page: page,
89
89
  limit: limit,
@@ -159,5 +159,12 @@ class UserSqliteRepository {
159
159
  stmt.run({ id: id, password: password });
160
160
  return true;
161
161
  }
162
+ async changeAvatar(id, avatar) {
163
+ const stmt = this.db.prepare(`UPDATE users
164
+ SET avatar = @avatar
165
+ WHERE id = @id `);
166
+ stmt.run({ id: id, avatar: avatar });
167
+ return true;
168
+ }
162
169
  }
163
170
  export default UserSqliteRepository;
@@ -0,0 +1,70 @@
1
+ import { join } from "path";
2
+ import { UnauthorizedError } from "@drax/identity-back";
3
+ import { StoreManager, UploadFileError, DraxConfig, CommonConfig } from "@drax/common-back";
4
+ import UserServiceFactory from "../factory/UserServiceFactory.js";
5
+ import IdentityConfig from "../config/IdentityConfig.js";
6
+ const FILE_DIR = DraxConfig.getOrLoad(IdentityConfig.AvatarDir) || 'avatars';
7
+ const BASE_URL = DraxConfig.getOrLoad(CommonConfig.BaseUrl) ? DraxConfig.get(CommonConfig.BaseUrl).replace(/\/$/, '') : '';
8
+ async function UserAvatarRoutes(fastify, options) {
9
+ fastify.post('/api/user/avatar', async (request, reply) => {
10
+ try {
11
+ request.rbac.assertAuthenticated();
12
+ const userId = request.rbac.getAuthUser.id;
13
+ const data = await request.file();
14
+ const file = {
15
+ filename: data.filename,
16
+ fileStream: data.file,
17
+ mimetype: data.mimetype
18
+ };
19
+ const destinationPath = join(FILE_DIR);
20
+ const storedFile = await StoreManager.saveFile(file, destinationPath);
21
+ const urlFile = BASE_URL + '/api/user/avatar/' + storedFile.filename;
22
+ //Save into DB
23
+ const userService = UserServiceFactory();
24
+ return await userService.changeAvatar(userId, urlFile);
25
+ return {
26
+ filename: storedFile.filename,
27
+ size: storedFile.size,
28
+ mimetype: storedFile.mimetype,
29
+ url: urlFile,
30
+ };
31
+ }
32
+ catch (e) {
33
+ console.error(e);
34
+ if (e instanceof UploadFileError) {
35
+ reply.statusCode = e.statusCode;
36
+ reply.send({ error: e.message });
37
+ }
38
+ else if (e instanceof UnauthorizedError) {
39
+ reply.statusCode = e.statusCode;
40
+ reply.send({ error: e.message });
41
+ }
42
+ else {
43
+ reply.statusCode = 500;
44
+ reply.send({ error: 'INTERNAL_SERVER_ERROR' });
45
+ }
46
+ }
47
+ });
48
+ fastify.get('/api/user/avatar/:filename', async (request, reply) => {
49
+ try {
50
+ const filename = request.params.filename;
51
+ const [year, month] = filename.split('-');
52
+ const fileDir = join(FILE_DIR, year, month);
53
+ //console.log("FILE_DIR: ",fileDir, " FILENAME:", filename)
54
+ return reply.sendFile(filename, fileDir);
55
+ }
56
+ catch (e) {
57
+ console.error(e);
58
+ if (e instanceof UnauthorizedError) {
59
+ reply.statusCode = e.statusCode;
60
+ reply.send({ error: e.message });
61
+ }
62
+ else {
63
+ reply.statusCode = 500;
64
+ reply.send({ error: 'INTERNAL_SERVER_ERROR' });
65
+ }
66
+ }
67
+ });
68
+ }
69
+ export default UserAvatarRoutes;
70
+ export { UserAvatarRoutes };
@@ -36,6 +36,9 @@ class UserService {
36
36
  async changeOwnPassword(userId, currentPassword, newPassword) {
37
37
  const user = await this.findById(userId);
38
38
  if (user && user.active) {
39
+ if (currentPassword === newPassword) {
40
+ throw new ValidationError([{ field: 'newPassword', reason: 'validation.password.currentDifferent' }]);
41
+ }
39
42
  if (AuthUtils.checkPassword(currentPassword, user.password)) {
40
43
  newPassword = AuthUtils.hashPassword(newPassword);
41
44
  await this._repository.changePassword(userId, newPassword);
@@ -49,6 +52,16 @@ class UserService {
49
52
  throw new BadCredentialsError();
50
53
  }
51
54
  }
55
+ async changeAvatar(userId, avatar) {
56
+ const user = await this.findById(userId);
57
+ if (user && user.active) {
58
+ await this._repository.changeAvatar(userId, avatar);
59
+ return true;
60
+ }
61
+ else {
62
+ throw new BadCredentialsError();
63
+ }
64
+ }
52
65
  async create(userData) {
53
66
  try {
54
67
  userData.name = userData?.name?.trim();
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "0.0.28",
6
+ "version": "0.0.30",
7
7
  "description": "Identity module for user management, authentication and authorization.",
8
8
  "main": "dist/index.js",
9
9
  "types": "types/index.d.ts",
@@ -26,9 +26,9 @@
26
26
  "author": "Cristian Incarnato & Drax Team",
27
27
  "license": "ISC",
28
28
  "dependencies": {
29
- "@drax/common-back": "^0.0.28",
30
- "@drax/common-share": "^0.0.28",
31
- "@drax/identity-share": "^0.0.28",
29
+ "@drax/common-back": "^0.0.30",
30
+ "@drax/common-share": "^0.0.30",
31
+ "@drax/identity-share": "^0.0.30",
32
32
  "bcryptjs": "^2.4.3",
33
33
  "express-jwt": "^8.4.1",
34
34
  "graphql": "^16.8.2",
@@ -59,5 +59,5 @@
59
59
  "debug": "0"
60
60
  }
61
61
  },
62
- "gitHead": "5444ae9e996bbedbc2fab1827d2bf52cbd3703a1"
62
+ "gitHead": "b0882d3ace0d0004cbc850e8d86381b9d6432535"
63
63
  }
@@ -10,6 +10,8 @@ enum IdentityConfig {
10
10
 
11
11
  RbacCacheTTL = "DRAX_RBAC_CACHE_TTL",
12
12
 
13
+ AvatarDir = "DRAX_AVATAR_DIR",
14
+
13
15
 
14
16
  }
15
17
 
@@ -62,11 +62,11 @@ export default {
62
62
  throw new GraphQLError('error.server')
63
63
  }
64
64
  },
65
- paginateRole: async (_, {page, limit, orderBy, orderDesc, search}, {rbac}) => {
65
+ paginateRole: async (_, {options= {page:1, limit:5, orderBy:"", orderDesc:false, search:"", filters: []} }, {rbac}) => {
66
66
  try {
67
67
  rbac.assertPermission(IdentityPermissions.ViewRole)
68
68
  const roleService = RoleServiceFactory()
69
- return await roleService.paginate({page, limit, orderBy, orderDesc, search})
69
+ return await roleService.paginate(options)
70
70
  } catch (e) {
71
71
  console.error("paginateRole",e)
72
72
  if (e instanceof UnauthorizedError) {
@@ -50,11 +50,11 @@ export default {
50
50
  throw new GraphQLError('error.server')
51
51
  }
52
52
  },
53
- paginateTenant: async (_, {page, limit, orderBy, orderDesc, search}, {rbac}) => {
53
+ paginateTenant: async (_, {options= {page:1, limit:5, orderBy:"", orderDesc:false, search:"", filters: []} }, {rbac}) => {
54
54
  try {
55
55
  rbac.assertPermission(IdentityPermissions.ViewTenant)
56
56
  const tenantService = TenantServiceFactory()
57
- return await tenantService.paginate({page, limit, orderBy, orderDesc, search})
57
+ return await tenantService.paginate(options)
58
58
  } catch (e) {
59
59
  console.error("paginateTenant",e)
60
60
  if (e instanceof UnauthorizedError) {
@@ -1,16 +1,24 @@
1
1
  import UserServiceFactory from "../../factory/UserServiceFactory.js";
2
2
  import {GraphQLError} from "graphql";
3
- import {ValidationErrorToGraphQLError, ValidationError} from "@drax/common-back";
3
+ import {
4
+ ValidationErrorToGraphQLError,
5
+ ValidationError,
6
+ StoreManager,
7
+ DraxConfig,
8
+ CommonConfig
9
+ } from "@drax/common-back";
4
10
  import {IdentityPermissions} from "../../permissions/IdentityPermissions.js";
5
11
  import UnauthorizedError from "../../errors/UnauthorizedError.js";
6
12
  import BadCredentialsError from "../../errors/BadCredentialsError.js";
13
+ import {join} from "path";
14
+ import IdentityConfig from "../../config/IdentityConfig.js";
7
15
 
8
16
  export default {
9
17
  Query: {
10
18
  me: async (_, {}, {authUser}) => {
11
19
  try {
12
20
  if (authUser) {
13
- let userService= UserServiceFactory()
21
+ let userService = UserServiceFactory()
14
22
  let user = await userService.findById(authUser.id)
15
23
  delete user.password
16
24
  return user
@@ -25,7 +33,7 @@ export default {
25
33
  findUserById: async (_, {id}, {rbac}) => {
26
34
  try {
27
35
  rbac.assertPermission(IdentityPermissions.ViewUser)
28
- let userService= UserServiceFactory()
36
+ let userService = UserServiceFactory()
29
37
  return await userService.findById(id)
30
38
  } catch (e) {
31
39
  if (e instanceof UnauthorizedError) {
@@ -35,14 +43,14 @@ export default {
35
43
  }
36
44
 
37
45
  },
38
- paginateUser: async (_, {page, limit, orderBy, orderDesc, search, filters = []}, {rbac}) => {
46
+ paginateUser: async (_, { options= {page:1, limit:5, orderBy:"", orderDesc:false, search:"", filters: []} }, {rbac}) => {
39
47
  try {
40
48
  rbac.assertPermission(IdentityPermissions.ViewUser)
41
- let userService= UserServiceFactory()
42
- if(rbac.getAuthUser.tenantId){
43
- filters.push({field: 'tenant', operator: '$eq', value: rbac.getAuthUser.tenantId})
49
+ let userService = UserServiceFactory()
50
+ if (rbac.getAuthUser.tenantId) {
51
+ options.filters.push({field: 'tenant', operator: '$eq', value: rbac.getAuthUser.tenantId})
44
52
  }
45
- return await userService.paginate({page, limit, orderBy, orderDesc, search, filters})
53
+ return await userService.paginate(options)
46
54
  } catch (e) {
47
55
  if (e instanceof UnauthorizedError) {
48
56
  throw new GraphQLError(e.message)
@@ -54,7 +62,7 @@ export default {
54
62
  Mutation: {
55
63
  auth: async (_, {input}) => {
56
64
  try {
57
- let userService= UserServiceFactory()
65
+ let userService = UserServiceFactory()
58
66
  return await userService.auth(input.username, input.password)
59
67
  } catch (e) {
60
68
  console.error("auth", e)
@@ -68,8 +76,8 @@ export default {
68
76
  createUser: async (_, {input}, {rbac}) => {
69
77
  try {
70
78
  rbac.assertPermission(IdentityPermissions.CreateUser)
71
- let userService= UserServiceFactory()
72
- if(rbac.getAuthUser.tenantId){
79
+ let userService = UserServiceFactory()
80
+ if (rbac.getAuthUser.tenantId) {
73
81
  input.tenant = rbac.getAuthUser.tenantId
74
82
  }
75
83
  const user = await userService.create(input)
@@ -88,8 +96,8 @@ export default {
88
96
  updateUser: async (_, {id, input}, {rbac}) => {
89
97
  try {
90
98
  rbac.assertPermission(IdentityPermissions.UpdateUser)
91
- let userService= UserServiceFactory()
92
- if(rbac.getAuthUser.tenantId){
99
+ let userService = UserServiceFactory()
100
+ if (rbac.getAuthUser.tenantId) {
93
101
  input.tenant = rbac.getAuthUser.tenantId
94
102
  }
95
103
  const user = await userService.update(id, input)
@@ -106,7 +114,7 @@ export default {
106
114
  deleteUser: async (_, {id}, {rbac}) => {
107
115
  try {
108
116
  rbac.assertPermission(IdentityPermissions.DeleteUser)
109
- let userService= UserServiceFactory()
117
+ let userService = UserServiceFactory()
110
118
  return await userService.delete(id)
111
119
  } catch (e) {
112
120
  console.error("deleteUser", e)
@@ -124,7 +132,7 @@ export default {
124
132
  throw new UnauthorizedError()
125
133
  }
126
134
  let userId = authUser.id
127
- let userService= UserServiceFactory()
135
+ let userService = UserServiceFactory()
128
136
  return await userService.changeOwnPassword(userId, currentPassword, newPassword)
129
137
  } catch (e) {
130
138
  if (e instanceof ValidationError) {
@@ -138,7 +146,7 @@ export default {
138
146
  changeUserPassword: async (_, {userId, newPassword}, {rbac}) => {
139
147
  try {
140
148
  rbac.assertPermission(IdentityPermissions.UpdateUser)
141
- let userService= UserServiceFactory()
149
+ let userService = UserServiceFactory()
142
150
  return await userService.changeUserPassword(userId, newPassword)
143
151
  } catch (e) {
144
152
  if (e instanceof ValidationError) {
@@ -149,6 +157,45 @@ export default {
149
157
  throw new GraphQLError('error.server')
150
158
  }
151
159
  },
160
+ changeAvatar: async (_, {file}, {rbac, authUser}) => {
161
+ try {
162
+ rbac.assertAuthenticated()
163
+ const userId = authUser.id
164
+
165
+ const FILE_DIR = DraxConfig.getOrLoad(IdentityConfig.AvatarDir) || 'avatars';
166
+ const BASE_URL = DraxConfig.getOrLoad(CommonConfig.BaseUrl) ? DraxConfig.get(CommonConfig.BaseUrl).replace(/\/$/, '') : ''
167
+
168
+ //console.log("FILE:", file)
169
+
170
+ let preFile
171
+
172
+ //Yoga PonyfillFile
173
+ if (file.blobParts) {
174
+ preFile = {
175
+ filename: file.name,
176
+ fileStream: file.blobParts,
177
+ mimetype: file.type,
178
+ encoding: file.encoding,
179
+ }
180
+ }
181
+
182
+
183
+ const destinationPath = join(FILE_DIR)
184
+ const storedFile = await StoreManager.saveFile(preFile, destinationPath)
185
+ const urlFile = BASE_URL + '/api/user/avatar/' + storedFile.filename
186
+
187
+ let userService = UserServiceFactory()
188
+ return await userService.changeAvatar(userId, urlFile)
189
+ } catch (e) {
190
+ console.error("changeAvatar", e)
191
+ if (e instanceof ValidationError) {
192
+ throw ValidationErrorToGraphQLError(e)
193
+ } else if (e instanceof UnauthorizedError) {
194
+ throw new GraphQLError(e.message)
195
+ }
196
+ throw new GraphQLError('error.server')
197
+ }
198
+ },
152
199
 
153
200
  }
154
201
  }
@@ -54,6 +54,7 @@ input AuthInput{
54
54
  password: String!
55
55
  }
56
56
 
57
+
57
58
  type Mutation{
58
59
  auth(input: AuthInput): Auth
59
60
  createUser(input: UserCreateInput): User
@@ -61,4 +62,5 @@ type Mutation{
61
62
  deleteUser(id: ID!): Boolean
62
63
  changeOwnPassword(currentPassword:String!, newPassword: String!): Boolean
63
64
  changeUserPassword(userId:ID!, newPassword:String!): Boolean
65
+ changeAvatar(file: File!): Boolean
64
66
  }
package/src/index.ts CHANGED
@@ -8,6 +8,7 @@ import TenantService from "./services/TenantService.js";
8
8
  import PermissionService from "./services/PermissionService.js";
9
9
  import Rbac from "./rbac/Rbac.js";
10
10
  import {UserRoutes} from "./routes/UserRoutes.js";
11
+ import {UserAvatarRoutes} from "./routes/UserAvatarRoutes.js";
11
12
  import {RoleRoutes} from "./routes/RoleRoutes.js";
12
13
  import {TenantRoutes} from "./routes/TenantRoutes.js";
13
14
  import AuthUtils from "./utils/AuthUtils.js";
@@ -62,6 +63,7 @@ export {
62
63
  UserRoutes,
63
64
  RoleRoutes,
64
65
  TenantRoutes,
66
+ UserAvatarRoutes,
65
67
 
66
68
  AuthUtils,
67
69
 
@@ -88,4 +90,3 @@ export {
88
90
  }
89
91
 
90
92
 
91
- /// <reference types="index.d.ts" />
@@ -5,6 +5,7 @@ interface IUserRepository extends IDraxCrud<IUser, IUserCreate, IUserUpdate>{
5
5
  findById(id: string): Promise<IUser | null>;
6
6
  findByUsername(username: string): Promise<IUser | null>;
7
7
  changePassword(id: string, password:string):Promise<Boolean>;
8
+ changeAvatar(id: string, avatarUrl: string): Promise<Boolean>;
8
9
  }
9
10
 
10
11
  export {IUserRepository}
package/src/rbac/Rbac.ts CHANGED
@@ -32,6 +32,12 @@ class Rbac{
32
32
  }
33
33
  }
34
34
 
35
+ assertAuthenticated() {
36
+ if (!this.authUser) {
37
+ throw new UnauthorizedError()
38
+ }
39
+ }
40
+
35
41
  }
36
42
 
37
43
  export default Rbac;
@@ -118,6 +118,16 @@ class UserMongoRepository implements IUserRepository {
118
118
  return false
119
119
  }
120
120
  }
121
+
122
+ async changeAvatar(id: string, avatar: string):Promise<boolean> {
123
+ try{
124
+ await UserModel.findOneAndUpdate({_id: id}, {avatar}).exec()
125
+ return true
126
+ }catch (e){
127
+ console.error(e)
128
+ return false
129
+ }
130
+ }
121
131
  }
122
132
 
123
133
  export default UserMongoRepository
@@ -109,7 +109,7 @@ class RoleSqliteRepository implements IRoleRepository{
109
109
  }
110
110
 
111
111
  const rCount = this.db.prepare('SELECT COUNT(*) as count FROM roles'+where).get();
112
- const roles = this.db.prepare('SELECT * FROM roles LIMIT ? OFFSET ?'+where).all([limit, offset]);
112
+ const roles = this.db.prepare('SELECT * FROM roles ' + where + ' LIMIT ? OFFSET ?').all([limit, offset]);
113
113
 
114
114
  for (const role of roles) {
115
115
  await this.populateRole(role)
@@ -115,7 +115,7 @@ class TenantSqliteRepository implements ITenantRepository{
115
115
  }
116
116
 
117
117
  const rCount = this.db.prepare('SELECT COUNT(*) as count FROM tenants'+where).get();
118
- const tenants = this.db.prepare('SELECT * FROM tenants LIMIT ? OFFSET ?'+where).all([limit, offset]);
118
+ const tenants = this.db.prepare('SELECT * FROM tenants ' + where + ' LIMIT ? OFFSET ?').all([limit, offset]);
119
119
 
120
120
  return {
121
121
  page: page,
@@ -206,6 +206,14 @@ class UserSqliteRepository implements IUserRepository {
206
206
  stmt.run({id: id, password: password});
207
207
  return true
208
208
  }
209
+
210
+ async changeAvatar(id: string, avatar: string): Promise<boolean> {
211
+ const stmt = this.db.prepare(`UPDATE users
212
+ SET avatar = @avatar
213
+ WHERE id = @id `);
214
+ stmt.run({id: id, avatar: avatar});
215
+ return true
216
+ }
209
217
  }
210
218
 
211
219
  export default UserSqliteRepository