@drax/identity-back 0.0.27 → 0.0.29
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/graphql/resolvers/role.resolvers.js +2 -2
- package/dist/graphql/resolvers/tenant.resolvers.js +2 -2
- package/dist/graphql/resolvers/user.resolvers.js +39 -4
- package/dist/graphql/types/user.graphql +2 -0
- package/dist/index.js +2 -2
- package/dist/rbac/Rbac.js +5 -0
- package/dist/repository/mongo/UserMongoRepository.js +10 -0
- package/dist/repository/sqlite/RoleSqliteRepository.js +1 -1
- package/dist/repository/sqlite/TenantSqliteRepository.js +1 -1
- package/dist/repository/sqlite/UserSqliteRepository.js +7 -0
- package/dist/routes/UserAvatarRoutes.js +69 -0
- package/dist/services/UserService.js +13 -0
- package/package.json +5 -5
- package/src/graphql/resolvers/role.resolvers.ts +2 -2
- package/src/graphql/resolvers/tenant.resolvers.ts +2 -2
- package/src/graphql/resolvers/user.resolvers.ts +56 -16
- package/src/graphql/types/user.graphql +2 -0
- package/src/index.ts +2 -1
- package/src/interfaces/IUserRepository.ts +1 -0
- package/src/rbac/Rbac.ts +6 -0
- package/src/repository/mongo/UserMongoRepository.ts +10 -0
- package/src/repository/sqlite/RoleSqliteRepository.ts +1 -1
- package/src/repository/sqlite/TenantSqliteRepository.ts +1 -1
- package/src/repository/sqlite/UserSqliteRepository.ts +8 -0
- package/src/routes/UserAvatarRoutes.ts +80 -0
- package/src/services/UserService.ts +17 -0
- package/test/data-obj/roles/admin-mongo-role.ts +1 -1
- package/test/repository/mongo/role-mongo-repository.test.ts +2 -3
- package/test/repository/mongo/user-mongo-repository.test.ts +2 -2
- package/test/repository/sqlite/role-sqlite-repository.test.ts +2 -2
- package/test/repository/sqlite/user-sqlite-repository.test.ts +1 -1
- package/tsconfig.json +1 -11
- package/tsconfig.tsbuildinfo +1 -1
- package/types/graphql/resolvers/role.resolvers.d.ts +9 -6
- package/types/graphql/resolvers/role.resolvers.d.ts.map +1 -1
- package/types/graphql/resolvers/tenant.resolvers.d.ts +9 -6
- package/types/graphql/resolvers/tenant.resolvers.d.ts.map +1 -1
- package/types/graphql/resolvers/user.resolvers.d.ts +15 -7
- package/types/graphql/resolvers/user.resolvers.d.ts.map +1 -1
- package/types/routes/UserAvatarRoutes.d.ts.map +1 -0
- package/types/services/UserService.d.ts.map +1 -1
- package/types/config/IdentityConfig.d.ts +0 -12
- package/types/config/IdentityConfig.d.ts.map +0 -1
- package/types/errors/BadCredentialsError.d.ts +0 -6
- package/types/errors/BadCredentialsError.d.ts.map +0 -1
- package/types/errors/UnauthorizedError.d.ts +0 -6
- package/types/errors/UnauthorizedError.d.ts.map +0 -1
- package/types/factory/RoleServiceFactory.d.ts +0 -4
- package/types/factory/RoleServiceFactory.d.ts.map +0 -1
- package/types/factory/TenantServiceFactory.d.ts +0 -4
- package/types/factory/TenantServiceFactory.d.ts.map +0 -1
- package/types/factory/UserServiceFactory.d.ts +0 -4
- package/types/factory/UserServiceFactory.d.ts.map +0 -1
- package/types/graphql/index.d.ts +0 -6
- package/types/graphql/index.d.ts.map +0 -1
- package/types/index.d.ts +0 -31
- package/types/index.d.ts.map +0 -1
- package/types/interfaces/IID.d.ts +0 -6
- package/types/interfaces/IID.d.ts.map +0 -1
- package/types/interfaces/IJwtUser.d.ts +0 -7
- package/types/interfaces/IJwtUser.d.ts.map +0 -1
- package/types/interfaces/IRole.d.ts +0 -18
- package/types/interfaces/IRole.d.ts.map +0 -1
- package/types/interfaces/IRoleRepository.d.ts +0 -9
- package/types/interfaces/IRoleRepository.d.ts.map +0 -1
- package/types/interfaces/ITenant.d.ts +0 -7
- package/types/interfaces/ITenant.d.ts.map +0 -1
- package/types/interfaces/ITenantRepository.d.ts +0 -9
- package/types/interfaces/ITenantRepository.d.ts.map +0 -1
- package/types/interfaces/IUser.d.ts +0 -45
- package/types/interfaces/IUser.d.ts.map +0 -1
- package/types/interfaces/IUserGroup.d.ts +0 -11
- package/types/interfaces/IUserGroup.d.ts.map +0 -1
- package/types/interfaces/IUserRepository.d.ts +0 -9
- package/types/interfaces/IUserRepository.d.ts.map +0 -1
- package/types/middleware/jwtMiddleware.d.ts +0 -4
- package/types/middleware/jwtMiddleware.d.ts.map +0 -1
- package/types/middleware/rbacMiddleware.d.ts +0 -4
- package/types/middleware/rbacMiddleware.d.ts.map +0 -1
- package/types/models/RoleModel.d.ts +0 -16
- package/types/models/RoleModel.d.ts.map +0 -1
- package/types/models/TenantModel.d.ts +0 -16
- package/types/models/TenantModel.d.ts.map +0 -1
- package/types/models/UserGroupModel.d.ts +0 -16
- package/types/models/UserGroupModel.d.ts.map +0 -1
- package/types/models/UserModel.d.ts +0 -16
- package/types/models/UserModel.d.ts.map +0 -1
- package/types/permissions/IdentityPermissions.d.ts +0 -21
- package/types/permissions/IdentityPermissions.d.ts.map +0 -1
- package/types/rbac/Rbac.d.ts +0 -13
- package/types/rbac/Rbac.d.ts.map +0 -1
- package/types/repository/mongo/RoleMongoRepository.d.ts +0 -14
- package/types/repository/mongo/RoleMongoRepository.d.ts.map +0 -1
- package/types/repository/mongo/TenantMongoRepository.d.ts +0 -14
- package/types/repository/mongo/TenantMongoRepository.d.ts.map +0 -1
- package/types/repository/mongo/UserMongoRepository.d.ts +0 -16
- package/types/repository/mongo/UserMongoRepository.d.ts.map +0 -1
- package/types/repository/sqlite/RoleSqliteRepository.d.ts +0 -21
- package/types/repository/sqlite/RoleSqliteRepository.d.ts.map +0 -1
- package/types/repository/sqlite/TenantSqliteRepository.d.ts +0 -18
- package/types/repository/sqlite/TenantSqliteRepository.d.ts.map +0 -1
- package/types/repository/sqlite/UserSqliteRepository.d.ts +0 -23
- package/types/repository/sqlite/UserSqliteRepository.d.ts.map +0 -1
- package/types/routes/RoleRoutes.d.ts +0 -4
- package/types/routes/RoleRoutes.d.ts.map +0 -1
- package/types/routes/TenantRoutes.d.ts +0 -4
- package/types/routes/TenantRoutes.d.ts.map +0 -1
- package/types/routes/UserRoutes.d.ts +0 -4
- package/types/routes/UserRoutes.d.ts.map +0 -1
- package/types/services/PermissionService.d.ts +0 -9
- package/types/services/PermissionService.d.ts.map +0 -1
- package/types/services/RoleService.d.ts +0 -16
- package/types/services/RoleService.d.ts.map +0 -1
- package/types/services/TenantService.d.ts +0 -16
- package/types/services/TenantService.d.ts.map +0 -1
- package/types/services/UserService.d.ts +0 -20
- package/types/setup/CreateOrUpdateRole.d.ts +0 -5
- package/types/setup/CreateOrUpdateRole.d.ts.map +0 -1
- package/types/setup/CreateUserIfNotExist.d.ts +0 -5
- package/types/setup/CreateUserIfNotExist.d.ts.map +0 -1
- package/types/setup/LoadConfigFromEnv.d.ts +0 -4
- package/types/setup/LoadConfigFromEnv.d.ts.map +0 -1
- package/types/setup/LoadIdentityConfigFromEnv.d.ts +0 -4
- package/types/setup/LoadIdentityConfigFromEnv.d.ts.map +0 -1
- package/types/setup/LoadPermissions.d.ts +0 -4
- package/types/setup/LoadPermissions.d.ts.map +0 -1
- package/types/setup/RecoveryUserPassword.d.ts +0 -4
- package/types/setup/RecoveryUserPassword.d.ts.map +0 -1
- package/types/utils/AuthUtils.d.ts +0 -16
- package/types/utils/AuthUtils.d.ts.map +0 -1
- package/types/utils/DbSetupUtils.d.ts +0 -10
- package/types/utils/DbSetupUtils.d.ts.map +0 -1
- package/types/zod/RoleZod.d.ts +0 -10
- package/types/zod/RoleZod.d.ts.map +0 -1
- package/types/zod/TenantZod.d.ts +0 -10
- package/types/zod/TenantZod.d.ts.map +0 -1
- package/types/zod/UserZod.d.ts +0 -53
- package/types/zod/UserZod.d.ts.map +0 -1
|
@@ -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(
|
|
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(
|
|
57
|
+
return await tenantService.paginate(options);
|
|
58
58
|
}
|
|
59
59
|
catch (e) {
|
|
60
60
|
console.error("paginateTenant", e);
|
|
@@ -1,9 +1,10 @@
|
|
|
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 } 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";
|
|
7
8
|
export default {
|
|
8
9
|
Query: {
|
|
9
10
|
me: async (_, {}, { authUser }) => {
|
|
@@ -34,14 +35,14 @@ export default {
|
|
|
34
35
|
throw new GraphQLError('error.server');
|
|
35
36
|
}
|
|
36
37
|
},
|
|
37
|
-
paginateUser: async (_, { page, limit, orderBy, orderDesc, search, filters
|
|
38
|
+
paginateUser: async (_, { options = { page: 1, limit: 5, orderBy: "", orderDesc: false, search: "", filters: [] } }, { rbac }) => {
|
|
38
39
|
try {
|
|
39
40
|
rbac.assertPermission(IdentityPermissions.ViewUser);
|
|
40
41
|
let userService = UserServiceFactory();
|
|
41
42
|
if (rbac.getAuthUser.tenantId) {
|
|
42
|
-
filters.push({ field: 'tenant', operator: '$eq', value: rbac.getAuthUser.tenantId });
|
|
43
|
+
options.filters.push({ field: 'tenant', operator: '$eq', value: rbac.getAuthUser.tenantId });
|
|
43
44
|
}
|
|
44
|
-
return await userService.paginate(
|
|
45
|
+
return await userService.paginate(options);
|
|
45
46
|
}
|
|
46
47
|
catch (e) {
|
|
47
48
|
if (e instanceof UnauthorizedError) {
|
|
@@ -158,5 +159,39 @@ export default {
|
|
|
158
159
|
throw new GraphQLError('error.server');
|
|
159
160
|
}
|
|
160
161
|
},
|
|
162
|
+
changeAvatar: async (_, { file }, { rbac, authUser }) => {
|
|
163
|
+
try {
|
|
164
|
+
rbac.assertAuthenticated();
|
|
165
|
+
const userId = authUser.id;
|
|
166
|
+
const FILE_DIR = process.env.DRAX_AVATAR_DIR || 'avatars';
|
|
167
|
+
const BASE_URL = process.env.DRAX_BASE_URL.replace(/\/$/, '') || '';
|
|
168
|
+
//console.log("FILE:", file)
|
|
169
|
+
let preFile;
|
|
170
|
+
//Yoga PonyfillFile
|
|
171
|
+
if (file.blobParts) {
|
|
172
|
+
preFile = {
|
|
173
|
+
filename: file.name,
|
|
174
|
+
fileStream: file.blobParts,
|
|
175
|
+
mimetype: file.type,
|
|
176
|
+
encoding: file.encoding,
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
const destinationPath = join(FILE_DIR);
|
|
180
|
+
const storedFile = await StoreManager.saveFile(preFile, destinationPath);
|
|
181
|
+
const urlFile = BASE_URL + '/api/user/avatar/' + storedFile.filename;
|
|
182
|
+
let userService = UserServiceFactory();
|
|
183
|
+
return await userService.changeAvatar(userId, urlFile);
|
|
184
|
+
}
|
|
185
|
+
catch (e) {
|
|
186
|
+
console.error("changeAvatar", e);
|
|
187
|
+
if (e instanceof ValidationError) {
|
|
188
|
+
throw ValidationErrorToGraphQLError(e);
|
|
189
|
+
}
|
|
190
|
+
else if (e instanceof UnauthorizedError) {
|
|
191
|
+
throw new GraphQLError(e.message);
|
|
192
|
+
}
|
|
193
|
+
throw new GraphQLError('error.server');
|
|
194
|
+
}
|
|
195
|
+
},
|
|
161
196
|
}
|
|
162
197
|
};
|
|
@@ -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
|
@@ -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 ?'
|
|
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 ?'
|
|
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,69 @@
|
|
|
1
|
+
import { join } from "path";
|
|
2
|
+
import { UnauthorizedError } from "@drax/identity-back";
|
|
3
|
+
import { StoreManager, UploadFileError } from "@drax/common-back";
|
|
4
|
+
import UserServiceFactory from "../factory/UserServiceFactory.js";
|
|
5
|
+
const FILE_DIR = process.env.DRAX_AVATAR_DIR || 'avatars';
|
|
6
|
+
const BASE_URL = process.env.DRAX_BASE_URL.replace(/\/$/, '') || '';
|
|
7
|
+
async function UserAvatarRoutes(fastify, options) {
|
|
8
|
+
fastify.post('/api/user/avatar', async (request, reply) => {
|
|
9
|
+
try {
|
|
10
|
+
request.rbac.assertAuthenticated();
|
|
11
|
+
const userId = request.rbac.getAuthUser.id;
|
|
12
|
+
const data = await request.file();
|
|
13
|
+
const file = {
|
|
14
|
+
filename: data.filename,
|
|
15
|
+
fileStream: data.file,
|
|
16
|
+
mimetype: data.mimetype
|
|
17
|
+
};
|
|
18
|
+
const destinationPath = join(FILE_DIR);
|
|
19
|
+
const storedFile = await StoreManager.saveFile(file, destinationPath);
|
|
20
|
+
const urlFile = BASE_URL + '/api/user/avatar/' + storedFile.filename;
|
|
21
|
+
//Save into DB
|
|
22
|
+
const userService = UserServiceFactory();
|
|
23
|
+
return await userService.changeAvatar(userId, urlFile);
|
|
24
|
+
return {
|
|
25
|
+
filename: storedFile.filename,
|
|
26
|
+
size: storedFile.size,
|
|
27
|
+
mimetype: storedFile.mimetype,
|
|
28
|
+
url: urlFile,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
catch (e) {
|
|
32
|
+
console.error(e);
|
|
33
|
+
if (e instanceof UploadFileError) {
|
|
34
|
+
reply.statusCode = e.statusCode;
|
|
35
|
+
reply.send({ error: e.message });
|
|
36
|
+
}
|
|
37
|
+
else if (e instanceof UnauthorizedError) {
|
|
38
|
+
reply.statusCode = e.statusCode;
|
|
39
|
+
reply.send({ error: e.message });
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
reply.statusCode = 500;
|
|
43
|
+
reply.send({ error: 'INTERNAL_SERVER_ERROR' });
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
fastify.get('/api/user/avatar/:filename', async (request, reply) => {
|
|
48
|
+
try {
|
|
49
|
+
const filename = request.params.filename;
|
|
50
|
+
const [year, month] = filename.split('-');
|
|
51
|
+
const fileDir = join(FILE_DIR, year, month);
|
|
52
|
+
console.log("FILE_DIR: ", fileDir, " FILENAME:", filename);
|
|
53
|
+
return reply.sendFile(filename, fileDir);
|
|
54
|
+
}
|
|
55
|
+
catch (e) {
|
|
56
|
+
console.error(e);
|
|
57
|
+
if (e instanceof UnauthorizedError) {
|
|
58
|
+
reply.statusCode = e.statusCode;
|
|
59
|
+
reply.send({ error: e.message });
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
reply.statusCode = 500;
|
|
63
|
+
reply.send({ error: 'INTERNAL_SERVER_ERROR' });
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
export default UserAvatarRoutes;
|
|
69
|
+
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.
|
|
6
|
+
"version": "0.0.29",
|
|
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.
|
|
30
|
-
"@drax/common-share": "^0.0.
|
|
31
|
-
"@drax/identity-share": "^0.0.
|
|
29
|
+
"@drax/common-back": "^0.0.29",
|
|
30
|
+
"@drax/common-share": "^0.0.29",
|
|
31
|
+
"@drax/identity-share": "^0.0.29",
|
|
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": "
|
|
62
|
+
"gitHead": "a067a1fc430dbc7d31835de79cfe385ba9935914"
|
|
63
63
|
}
|
|
@@ -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(
|
|
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(
|
|
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,17 @@
|
|
|
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} 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";
|
|
7
8
|
|
|
8
9
|
export default {
|
|
9
10
|
Query: {
|
|
10
11
|
me: async (_, {}, {authUser}) => {
|
|
11
12
|
try {
|
|
12
13
|
if (authUser) {
|
|
13
|
-
let userService= UserServiceFactory()
|
|
14
|
+
let userService = UserServiceFactory()
|
|
14
15
|
let user = await userService.findById(authUser.id)
|
|
15
16
|
delete user.password
|
|
16
17
|
return user
|
|
@@ -25,7 +26,7 @@ export default {
|
|
|
25
26
|
findUserById: async (_, {id}, {rbac}) => {
|
|
26
27
|
try {
|
|
27
28
|
rbac.assertPermission(IdentityPermissions.ViewUser)
|
|
28
|
-
let userService= UserServiceFactory()
|
|
29
|
+
let userService = UserServiceFactory()
|
|
29
30
|
return await userService.findById(id)
|
|
30
31
|
} catch (e) {
|
|
31
32
|
if (e instanceof UnauthorizedError) {
|
|
@@ -35,14 +36,14 @@ export default {
|
|
|
35
36
|
}
|
|
36
37
|
|
|
37
38
|
},
|
|
38
|
-
paginateUser: async (_, {page, limit, orderBy, orderDesc, search, filters
|
|
39
|
+
paginateUser: async (_, { options= {page:1, limit:5, orderBy:"", orderDesc:false, search:"", filters: []} }, {rbac}) => {
|
|
39
40
|
try {
|
|
40
41
|
rbac.assertPermission(IdentityPermissions.ViewUser)
|
|
41
|
-
let userService= UserServiceFactory()
|
|
42
|
-
if(rbac.getAuthUser.tenantId){
|
|
43
|
-
filters.push({field: 'tenant', operator: '$eq', value: rbac.getAuthUser.tenantId})
|
|
42
|
+
let userService = UserServiceFactory()
|
|
43
|
+
if (rbac.getAuthUser.tenantId) {
|
|
44
|
+
options.filters.push({field: 'tenant', operator: '$eq', value: rbac.getAuthUser.tenantId})
|
|
44
45
|
}
|
|
45
|
-
return await userService.paginate(
|
|
46
|
+
return await userService.paginate(options)
|
|
46
47
|
} catch (e) {
|
|
47
48
|
if (e instanceof UnauthorizedError) {
|
|
48
49
|
throw new GraphQLError(e.message)
|
|
@@ -54,7 +55,7 @@ export default {
|
|
|
54
55
|
Mutation: {
|
|
55
56
|
auth: async (_, {input}) => {
|
|
56
57
|
try {
|
|
57
|
-
let userService= UserServiceFactory()
|
|
58
|
+
let userService = UserServiceFactory()
|
|
58
59
|
return await userService.auth(input.username, input.password)
|
|
59
60
|
} catch (e) {
|
|
60
61
|
console.error("auth", e)
|
|
@@ -68,8 +69,8 @@ export default {
|
|
|
68
69
|
createUser: async (_, {input}, {rbac}) => {
|
|
69
70
|
try {
|
|
70
71
|
rbac.assertPermission(IdentityPermissions.CreateUser)
|
|
71
|
-
let userService= UserServiceFactory()
|
|
72
|
-
if(rbac.getAuthUser.tenantId){
|
|
72
|
+
let userService = UserServiceFactory()
|
|
73
|
+
if (rbac.getAuthUser.tenantId) {
|
|
73
74
|
input.tenant = rbac.getAuthUser.tenantId
|
|
74
75
|
}
|
|
75
76
|
const user = await userService.create(input)
|
|
@@ -88,8 +89,8 @@ export default {
|
|
|
88
89
|
updateUser: async (_, {id, input}, {rbac}) => {
|
|
89
90
|
try {
|
|
90
91
|
rbac.assertPermission(IdentityPermissions.UpdateUser)
|
|
91
|
-
let userService= UserServiceFactory()
|
|
92
|
-
if(rbac.getAuthUser.tenantId){
|
|
92
|
+
let userService = UserServiceFactory()
|
|
93
|
+
if (rbac.getAuthUser.tenantId) {
|
|
93
94
|
input.tenant = rbac.getAuthUser.tenantId
|
|
94
95
|
}
|
|
95
96
|
const user = await userService.update(id, input)
|
|
@@ -106,7 +107,7 @@ export default {
|
|
|
106
107
|
deleteUser: async (_, {id}, {rbac}) => {
|
|
107
108
|
try {
|
|
108
109
|
rbac.assertPermission(IdentityPermissions.DeleteUser)
|
|
109
|
-
let userService= UserServiceFactory()
|
|
110
|
+
let userService = UserServiceFactory()
|
|
110
111
|
return await userService.delete(id)
|
|
111
112
|
} catch (e) {
|
|
112
113
|
console.error("deleteUser", e)
|
|
@@ -124,7 +125,7 @@ export default {
|
|
|
124
125
|
throw new UnauthorizedError()
|
|
125
126
|
}
|
|
126
127
|
let userId = authUser.id
|
|
127
|
-
let userService= UserServiceFactory()
|
|
128
|
+
let userService = UserServiceFactory()
|
|
128
129
|
return await userService.changeOwnPassword(userId, currentPassword, newPassword)
|
|
129
130
|
} catch (e) {
|
|
130
131
|
if (e instanceof ValidationError) {
|
|
@@ -138,7 +139,7 @@ export default {
|
|
|
138
139
|
changeUserPassword: async (_, {userId, newPassword}, {rbac}) => {
|
|
139
140
|
try {
|
|
140
141
|
rbac.assertPermission(IdentityPermissions.UpdateUser)
|
|
141
|
-
let userService= UserServiceFactory()
|
|
142
|
+
let userService = UserServiceFactory()
|
|
142
143
|
return await userService.changeUserPassword(userId, newPassword)
|
|
143
144
|
} catch (e) {
|
|
144
145
|
if (e instanceof ValidationError) {
|
|
@@ -149,6 +150,45 @@ export default {
|
|
|
149
150
|
throw new GraphQLError('error.server')
|
|
150
151
|
}
|
|
151
152
|
},
|
|
153
|
+
changeAvatar: async (_, {file}, {rbac, authUser}) => {
|
|
154
|
+
try {
|
|
155
|
+
rbac.assertAuthenticated()
|
|
156
|
+
const userId = authUser.id
|
|
157
|
+
|
|
158
|
+
const FILE_DIR = process.env.DRAX_AVATAR_DIR || 'avatars';
|
|
159
|
+
const BASE_URL = process.env.DRAX_BASE_URL.replace(/\/$/, '') || ''
|
|
160
|
+
|
|
161
|
+
//console.log("FILE:", file)
|
|
162
|
+
|
|
163
|
+
let preFile
|
|
164
|
+
|
|
165
|
+
//Yoga PonyfillFile
|
|
166
|
+
if (file.blobParts) {
|
|
167
|
+
preFile = {
|
|
168
|
+
filename: file.name,
|
|
169
|
+
fileStream: file.blobParts,
|
|
170
|
+
mimetype: file.type,
|
|
171
|
+
encoding: file.encoding,
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
const destinationPath = join(FILE_DIR)
|
|
177
|
+
const storedFile = await StoreManager.saveFile(preFile, destinationPath)
|
|
178
|
+
const urlFile = BASE_URL + '/api/user/avatar/' + storedFile.filename
|
|
179
|
+
|
|
180
|
+
let userService = UserServiceFactory()
|
|
181
|
+
return await userService.changeAvatar(userId, urlFile)
|
|
182
|
+
} catch (e) {
|
|
183
|
+
console.error("changeAvatar", e)
|
|
184
|
+
if (e instanceof ValidationError) {
|
|
185
|
+
throw ValidationErrorToGraphQLError(e)
|
|
186
|
+
} else if (e instanceof UnauthorizedError) {
|
|
187
|
+
throw new GraphQLError(e.message)
|
|
188
|
+
}
|
|
189
|
+
throw new GraphQLError('error.server')
|
|
190
|
+
}
|
|
191
|
+
},
|
|
152
192
|
|
|
153
193
|
}
|
|
154
194
|
}
|
|
@@ -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
|
@@ -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 ?'
|
|
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 ?'
|
|
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
|