@drax/identity-back 0.0.14 → 0.0.16
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/factory/TenantServiceFactory.js +24 -0
- package/dist/factory/UserServiceFactory.js +1 -1
- package/dist/graphql/resolvers/role.resolvers.js +19 -2
- package/dist/graphql/resolvers/tenant.resolvers.js +121 -0
- package/dist/graphql/resolvers/user.resolvers.js +14 -3
- package/dist/graphql/types/tenant.graphql +28 -0
- package/dist/graphql/types/user.graphql +3 -0
- package/dist/index.js +6 -3
- package/dist/interfaces/ITenant.js +1 -0
- package/dist/interfaces/ITenantRepository.js +1 -0
- package/dist/middleware/rbacMiddleware.js +2 -5
- package/dist/models/TenantModel.js +18 -0
- package/dist/models/UserModel.js +5 -0
- package/dist/permissions/IdentityPermissions.js +5 -0
- package/dist/rbac/Rbac.js +6 -0
- package/dist/repository/mongo/RoleMongoRepository.js +7 -6
- package/dist/repository/mongo/TenantMongoRepository.js +45 -0
- package/dist/repository/mongo/UserMongoRepository.js +19 -6
- package/dist/repository/sqlite/RoleSqliteRepository.js +24 -5
- package/dist/repository/sqlite/TenantSqliteRepository.js +106 -0
- package/dist/repository/sqlite/UserSqliteRepository.js +43 -37
- package/dist/routes/RoleRoutes.js +17 -2
- package/dist/routes/TenantRoutes.js +183 -0
- package/dist/routes/UserRoutes.js +14 -2
- package/dist/services/RoleService.js +0 -5
- package/dist/services/TenantService.js +59 -0
- package/dist/services/UserService.js +1 -1
- package/dist/utils/AuthUtils.js +4 -3
- package/dist/zod/TenantZod.js +8 -0
- package/package.json +2 -2
- package/src/factory/TenantServiceFactory.ts +33 -0
- package/src/factory/UserServiceFactory.ts +1 -1
- package/src/graphql/resolvers/role.resolvers.ts +21 -3
- package/src/graphql/resolvers/tenant.resolvers.ts +119 -0
- package/src/graphql/resolvers/user.resolvers.ts +14 -6
- package/src/graphql/types/tenant.graphql +28 -0
- package/src/graphql/types/user.graphql +3 -0
- package/src/index.ts +6 -0
- package/src/interfaces/ITenant.ts +9 -0
- package/src/interfaces/ITenantRepository.ts +15 -0
- package/src/interfaces/IUser.ts +4 -1
- package/src/middleware/rbacMiddleware.ts +6 -8
- package/src/models/TenantModel.ts +32 -0
- package/src/models/UserModel.ts +5 -0
- package/src/permissions/IdentityPermissions.ts +7 -0
- package/src/rbac/Rbac.ts +11 -3
- package/src/repository/mongo/RoleMongoRepository.ts +7 -6
- package/src/repository/mongo/TenantMongoRepository.ts +62 -0
- package/src/repository/mongo/UserMongoRepository.ts +20 -6
- package/src/repository/sqlite/RoleSqliteRepository.ts +27 -6
- package/src/repository/sqlite/TenantSqliteRepository.ts +139 -0
- package/src/repository/sqlite/UserSqliteRepository.ts +52 -40
- package/src/routes/RoleRoutes.ts +17 -3
- package/src/routes/TenantRoutes.ts +178 -0
- package/src/routes/UserRoutes.ts +14 -4
- package/src/services/RoleService.ts +1 -4
- package/src/services/TenantService.ts +74 -0
- package/src/services/UserService.ts +1 -1
- package/src/utils/AuthUtils.ts +4 -3
- package/src/zod/TenantZod.ts +14 -0
- package/tsconfig.tsbuildinfo +1 -1
- package/types/factory/TenantServiceFactory.d.ts +4 -0
- package/types/factory/TenantServiceFactory.d.ts.map +1 -0
- package/types/graphql/resolvers/role.resolvers.d.ts.map +1 -1
- package/types/graphql/resolvers/tenant.resolvers.d.ts +44 -0
- package/types/graphql/resolvers/tenant.resolvers.d.ts.map +1 -0
- package/types/graphql/resolvers/user.resolvers.d.ts +2 -1
- package/types/graphql/resolvers/user.resolvers.d.ts.map +1 -1
- package/types/index.d.ts +4 -1
- package/types/index.d.ts.map +1 -1
- package/types/interfaces/ITenant.d.ts +7 -0
- package/types/interfaces/ITenant.d.ts.map +1 -0
- package/types/interfaces/ITenantRepository.d.ts +15 -0
- package/types/interfaces/ITenantRepository.d.ts.map +1 -0
- package/types/interfaces/IUser.d.ts +4 -0
- package/types/interfaces/IUser.d.ts.map +1 -1
- package/types/middleware/rbacMiddleware.d.ts.map +1 -1
- package/types/models/TenantModel.d.ts +16 -0
- package/types/models/TenantModel.d.ts.map +1 -0
- package/types/models/UserModel.d.ts.map +1 -1
- package/types/permissions/IdentityPermissions.d.ts +6 -1
- package/types/permissions/IdentityPermissions.d.ts.map +1 -1
- package/types/rbac/Rbac.d.ts +4 -2
- package/types/rbac/Rbac.d.ts.map +1 -1
- package/types/repository/mongo/RoleMongoRepository.d.ts.map +1 -1
- package/types/repository/mongo/TenantMongoRepository.d.ts +15 -0
- package/types/repository/mongo/TenantMongoRepository.d.ts.map +1 -0
- package/types/repository/mongo/UserMongoRepository.d.ts +2 -2
- package/types/repository/mongo/UserMongoRepository.d.ts.map +1 -1
- package/types/repository/sqlite/RoleSqliteRepository.d.ts +2 -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 -0
- package/types/repository/sqlite/UserSqliteRepository.d.ts +4 -2
- package/types/repository/sqlite/UserSqliteRepository.d.ts.map +1 -1
- package/types/routes/RoleRoutes.d.ts.map +1 -1
- package/types/routes/TenantRoutes.d.ts +4 -0
- package/types/routes/TenantRoutes.d.ts.map +1 -0
- package/types/routes/UserRoutes.d.ts.map +1 -1
- package/types/services/RoleService.d.ts.map +1 -1
- package/types/services/TenantService.d.ts +16 -0
- package/types/services/TenantService.d.ts.map +1 -0
- package/types/utils/AuthUtils.d.ts +3 -2
- package/types/utils/AuthUtils.d.ts.map +1 -1
- package/types/zod/TenantZod.d.ts +10 -0
- package/types/zod/TenantZod.d.ts.map +1 -0
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { ZodErrorToValidationError } from "@drax/common-back";
|
|
2
|
+
import { tenantSchema } from "../zod/TenantZod.js";
|
|
3
|
+
import { ZodError } from "zod";
|
|
4
|
+
class TenantService {
|
|
5
|
+
constructor(tenantRepostitory) {
|
|
6
|
+
this._repository = tenantRepostitory;
|
|
7
|
+
console.log("TenantService constructor");
|
|
8
|
+
}
|
|
9
|
+
async create(tenantData) {
|
|
10
|
+
try {
|
|
11
|
+
tenantData.name = tenantData?.name?.trim();
|
|
12
|
+
await tenantSchema.parseAsync(tenantData);
|
|
13
|
+
const tenant = await this._repository.create(tenantData);
|
|
14
|
+
return tenant;
|
|
15
|
+
}
|
|
16
|
+
catch (e) {
|
|
17
|
+
if (e instanceof ZodError) {
|
|
18
|
+
throw ZodErrorToValidationError(e, tenantData);
|
|
19
|
+
}
|
|
20
|
+
throw e;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
async update(id, tenantData) {
|
|
24
|
+
try {
|
|
25
|
+
tenantData.name = tenantData?.name?.trim();
|
|
26
|
+
await tenantSchema.parseAsync(tenantData);
|
|
27
|
+
const tenant = await this._repository.update(id, tenantData);
|
|
28
|
+
return tenant;
|
|
29
|
+
}
|
|
30
|
+
catch (e) {
|
|
31
|
+
if (e instanceof ZodError) {
|
|
32
|
+
throw ZodErrorToValidationError(e, tenantData);
|
|
33
|
+
}
|
|
34
|
+
throw e;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
async delete(id) {
|
|
38
|
+
const currentTenant = await this.findById(id);
|
|
39
|
+
const deletedTenant = await this._repository.delete(id);
|
|
40
|
+
return deletedTenant;
|
|
41
|
+
}
|
|
42
|
+
async findById(id) {
|
|
43
|
+
const tenant = await this._repository.findById(id);
|
|
44
|
+
return tenant;
|
|
45
|
+
}
|
|
46
|
+
async findByName(name) {
|
|
47
|
+
const tenant = await this._repository.findByName(name);
|
|
48
|
+
return tenant;
|
|
49
|
+
}
|
|
50
|
+
async fetchAll() {
|
|
51
|
+
const tenants = await this._repository.fetchAll();
|
|
52
|
+
return tenants;
|
|
53
|
+
}
|
|
54
|
+
async paginate(page = 1, limit = 5, search, filters) {
|
|
55
|
+
const pagination = await this._repository.paginate(page, limit, search, filters);
|
|
56
|
+
return pagination;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
export default TenantService;
|
|
@@ -15,7 +15,7 @@ class UserService {
|
|
|
15
15
|
if (user && user.active && AuthUtils.checkPassword(password, user.password)) {
|
|
16
16
|
//TODO: Generar Sesion
|
|
17
17
|
const session = '123';
|
|
18
|
-
const accessToken = AuthUtils.generateToken(user.id.toString(), user.username, user.role.id, session);
|
|
18
|
+
const accessToken = AuthUtils.generateToken(user.id.toString(), user.username, user.role.id, user.tenant?.id, session);
|
|
19
19
|
return { accessToken: accessToken };
|
|
20
20
|
}
|
|
21
21
|
else {
|
package/dist/utils/AuthUtils.js
CHANGED
|
@@ -24,16 +24,17 @@ class AuthUtils {
|
|
|
24
24
|
static checkPassword(password, hashPassword) {
|
|
25
25
|
return bcryptjs.compareSync(password, hashPassword);
|
|
26
26
|
}
|
|
27
|
-
static tokenSignPayload(userId, username, roleId, session) {
|
|
27
|
+
static tokenSignPayload(userId, username, roleId, tenantId, session) {
|
|
28
28
|
return {
|
|
29
29
|
id: userId,
|
|
30
30
|
username: username,
|
|
31
31
|
roleId: roleId,
|
|
32
|
+
tenantId: tenantId,
|
|
32
33
|
session: session
|
|
33
34
|
};
|
|
34
35
|
}
|
|
35
|
-
static generateToken(userId, username, roleId, session) {
|
|
36
|
-
const payload = AuthUtils.tokenSignPayload(userId, username, roleId, session);
|
|
36
|
+
static generateToken(userId, username, roleId, tenantId, session) {
|
|
37
|
+
const payload = AuthUtils.tokenSignPayload(userId, username, roleId, tenantId, session);
|
|
37
38
|
const JWT_SECRET = DraxConfig.getOrLoad(IdentityConfig.JwtSecret);
|
|
38
39
|
if (!JWT_SECRET) {
|
|
39
40
|
throw new Error("JWT_SECRET ENV must be provided");
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { object, string } from "zod";
|
|
2
|
+
const tenantSchema = object({
|
|
3
|
+
name: string({ required_error: "validation.required" })
|
|
4
|
+
.min(1, "validation.required")
|
|
5
|
+
.regex(/^[A-Z]/, "validation.startWithUpperCase"),
|
|
6
|
+
});
|
|
7
|
+
export default tenantSchema;
|
|
8
|
+
export { tenantSchema };
|
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.16",
|
|
7
7
|
"description": "Identity module for user management, authentication and authorization.",
|
|
8
8
|
"main": "dist/index.js",
|
|
9
9
|
"types": "types/index.d.ts",
|
|
@@ -56,5 +56,5 @@
|
|
|
56
56
|
"debug": "0"
|
|
57
57
|
}
|
|
58
58
|
},
|
|
59
|
-
"gitHead": "
|
|
59
|
+
"gitHead": "edddb7a152dab85eb7bca07bd79c497bfd12c51f"
|
|
60
60
|
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import {DraxConfig} from "@drax/common-back"
|
|
2
|
+
import TenantService from "../services/TenantService.js";
|
|
3
|
+
import TenantMongoRepository from "../repository/mongo/TenantMongoRepository.js";
|
|
4
|
+
import TenantSqliteRepository from "../repository/sqlite/TenantSqliteRepository.js";
|
|
5
|
+
import {DbSetupUtils, DbEngine} from "../utils/DbSetupUtils.js";
|
|
6
|
+
import type {ITenantRepository} from "../interfaces/ITenantRepository";
|
|
7
|
+
|
|
8
|
+
let tenantService: TenantService
|
|
9
|
+
|
|
10
|
+
const TenantServiceFactory = () : TenantService => {
|
|
11
|
+
|
|
12
|
+
if(!tenantService){
|
|
13
|
+
let tenantRepository: ITenantRepository
|
|
14
|
+
|
|
15
|
+
switch (DbSetupUtils.getDbEngine()) {
|
|
16
|
+
case DbEngine.Mongo:
|
|
17
|
+
console.log("TenantServiceFactory DB ENGINE MONGODB")
|
|
18
|
+
tenantRepository = new TenantMongoRepository()
|
|
19
|
+
break;
|
|
20
|
+
case DbEngine.Sqlite:
|
|
21
|
+
console.log("TenantServiceFactory DB ENGINE SQLITE")
|
|
22
|
+
tenantRepository = new TenantSqliteRepository(DbSetupUtils.getDbConfig(), false)
|
|
23
|
+
tenantRepository.table()
|
|
24
|
+
break;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
tenantService = new TenantService(tenantRepository)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return tenantService
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export default TenantServiceFactory
|
|
@@ -17,7 +17,7 @@ const UserServiceFactory = () : UserService => {
|
|
|
17
17
|
break;
|
|
18
18
|
case DbEngine.Sqlite:
|
|
19
19
|
console.log("UserServiceFactory DB ENGINE SQLITE")
|
|
20
|
-
userRepository = new UserSqliteRepository(DbSetupUtils.getDbConfig(),
|
|
20
|
+
userRepository = new UserSqliteRepository(DbSetupUtils.getDbConfig(),true)
|
|
21
21
|
userRepository.table()
|
|
22
22
|
break;
|
|
23
23
|
}
|
|
@@ -5,12 +5,13 @@ import {GraphQLError} from "graphql";
|
|
|
5
5
|
import {PermissionService} from "../../services/PermissionService.js";
|
|
6
6
|
import UnauthorizedError from "../../errors/UnauthorizedError.js";
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
|
|
9
9
|
export default {
|
|
10
10
|
Query: {
|
|
11
11
|
findRoleById: async (_, {id}, {rbac}) => {
|
|
12
12
|
try {
|
|
13
13
|
rbac.assertPermission(IdentityPermissions.ViewRole)
|
|
14
|
+
const roleService = RoleServiceFactory()
|
|
14
15
|
return await roleService.findById(id)
|
|
15
16
|
} catch (e) {
|
|
16
17
|
if (e instanceof UnauthorizedError) {
|
|
@@ -22,6 +23,7 @@ export default {
|
|
|
22
23
|
findRoleByName: async (_, {name}, {rbac}) => {
|
|
23
24
|
try {
|
|
24
25
|
rbac.assertPermission(IdentityPermissions.ViewRole)
|
|
26
|
+
const roleService = RoleServiceFactory()
|
|
25
27
|
return await roleService.findByName(name)
|
|
26
28
|
} catch (e) {
|
|
27
29
|
if (e instanceof UnauthorizedError) {
|
|
@@ -33,8 +35,16 @@ export default {
|
|
|
33
35
|
fetchRole: async (_, {}, {rbac}) => {
|
|
34
36
|
try {
|
|
35
37
|
rbac.assertPermission(IdentityPermissions.ViewRole)
|
|
36
|
-
|
|
38
|
+
const roleService = RoleServiceFactory()
|
|
39
|
+
const roles = await roleService.fetchAll()
|
|
40
|
+
if(rbac.getRole?.childRoles?.length > 0) {
|
|
41
|
+
return roles.filter(role => rbac.getRole.childRoles.some(childRole => childRole.id === role.id));
|
|
42
|
+
}else{
|
|
43
|
+
return roles
|
|
44
|
+
}
|
|
45
|
+
|
|
37
46
|
} catch (e) {
|
|
47
|
+
console.error("fetchRole",e)
|
|
38
48
|
if (e instanceof UnauthorizedError) {
|
|
39
49
|
throw new GraphQLError(e.message)
|
|
40
50
|
}
|
|
@@ -55,6 +65,7 @@ export default {
|
|
|
55
65
|
paginateRole: async (_, {page, limit, seach}, {rbac}) => {
|
|
56
66
|
try {
|
|
57
67
|
rbac.assertPermission(IdentityPermissions.ViewRole)
|
|
68
|
+
const roleService = RoleServiceFactory()
|
|
58
69
|
return await roleService.paginate(page, limit, seach)
|
|
59
70
|
} catch (e) {
|
|
60
71
|
console.error("paginateRole",e)
|
|
@@ -69,6 +80,7 @@ export default {
|
|
|
69
80
|
createRole: async (_, {input}, {rbac}) => {
|
|
70
81
|
try {
|
|
71
82
|
rbac.assertPermission(IdentityPermissions.CreateRole)
|
|
83
|
+
const roleService = RoleServiceFactory()
|
|
72
84
|
return await roleService.create(input)
|
|
73
85
|
} catch (e) {
|
|
74
86
|
console.error("createRole",e)
|
|
@@ -85,7 +97,7 @@ export default {
|
|
|
85
97
|
updateRole: async (_, {id, input}, {rbac}) => {
|
|
86
98
|
try {
|
|
87
99
|
rbac.assertPermission(IdentityPermissions.UpdateRole)
|
|
88
|
-
|
|
100
|
+
const roleService = RoleServiceFactory()
|
|
89
101
|
const currentRole = await roleService.findById(id)
|
|
90
102
|
if(currentRole.readonly){
|
|
91
103
|
throw new ValidationError([{field:'name', reason:"role.readonly", value:input.name}])
|
|
@@ -106,6 +118,12 @@ export default {
|
|
|
106
118
|
deleteRole: async (_, {id}, {rbac}) => {
|
|
107
119
|
try {
|
|
108
120
|
rbac.assertPermission(IdentityPermissions.DeleteRole)
|
|
121
|
+
const roleService = RoleServiceFactory()
|
|
122
|
+
const currentRole = await roleService.findById(id)
|
|
123
|
+
if(currentRole.readonly){
|
|
124
|
+
throw new UnauthorizedError()
|
|
125
|
+
}
|
|
126
|
+
|
|
109
127
|
return await roleService.delete(id)
|
|
110
128
|
} catch (e) {
|
|
111
129
|
console.error("deleteRole",e)
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import TenantServiceFactory from "../../factory/TenantServiceFactory.js";
|
|
2
|
+
import {IdentityPermissions} from "../../permissions/IdentityPermissions.js";
|
|
3
|
+
import {ValidationError, ValidationErrorToGraphQLError} from "@drax/common-back";
|
|
4
|
+
import {GraphQLError} from "graphql";
|
|
5
|
+
import {PermissionService} from "../../services/PermissionService.js";
|
|
6
|
+
import UnauthorizedError from "../../errors/UnauthorizedError.js";
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
export default {
|
|
10
|
+
Query: {
|
|
11
|
+
findTenantById: async (_, {id}, {rbac}) => {
|
|
12
|
+
try {
|
|
13
|
+
rbac.assertPermission(IdentityPermissions.ViewTenant)
|
|
14
|
+
const tenantService = TenantServiceFactory()
|
|
15
|
+
return await tenantService.findById(id)
|
|
16
|
+
} catch (e) {
|
|
17
|
+
if (e instanceof UnauthorizedError) {
|
|
18
|
+
throw new GraphQLError(e.message)
|
|
19
|
+
}
|
|
20
|
+
throw new GraphQLError('error.server')
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
findTenantByName: async (_, {name}, {rbac}) => {
|
|
24
|
+
try {
|
|
25
|
+
rbac.assertPermission(IdentityPermissions.ViewTenant)
|
|
26
|
+
const tenantService = TenantServiceFactory()
|
|
27
|
+
return await tenantService.findByName(name)
|
|
28
|
+
} catch (e) {
|
|
29
|
+
if (e instanceof UnauthorizedError) {
|
|
30
|
+
throw new GraphQLError(e.message)
|
|
31
|
+
}
|
|
32
|
+
throw new GraphQLError('error.server')
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
fetchTenant: async (_, {}, {rbac}) => {
|
|
36
|
+
try {
|
|
37
|
+
rbac.assertPermission(IdentityPermissions.ViewTenant)
|
|
38
|
+
const tenantService = TenantServiceFactory()
|
|
39
|
+
const tenants = await tenantService.fetchAll()
|
|
40
|
+
if(rbac.getAuthUser.tenantId){
|
|
41
|
+
return tenants.filter(t => t.id === rbac.getAuthUser.tenantId)
|
|
42
|
+
}else{
|
|
43
|
+
return tenants
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
} catch (e) {
|
|
47
|
+
if (e instanceof UnauthorizedError) {
|
|
48
|
+
throw new GraphQLError(e.message)
|
|
49
|
+
}
|
|
50
|
+
throw new GraphQLError('error.server')
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
paginateTenant: async (_, {page, limit, seach}, {rbac}) => {
|
|
54
|
+
try {
|
|
55
|
+
rbac.assertPermission(IdentityPermissions.ViewTenant)
|
|
56
|
+
const tenantService = TenantServiceFactory()
|
|
57
|
+
return await tenantService.paginate(page, limit, seach)
|
|
58
|
+
} catch (e) {
|
|
59
|
+
console.error("paginateTenant",e)
|
|
60
|
+
if (e instanceof UnauthorizedError) {
|
|
61
|
+
throw new GraphQLError(e.message)
|
|
62
|
+
}
|
|
63
|
+
throw new GraphQLError('error.server')
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
Mutation: {
|
|
68
|
+
createTenant: async (_, {input}, {rbac}) => {
|
|
69
|
+
try {
|
|
70
|
+
rbac.assertPermission(IdentityPermissions.CreateTenant)
|
|
71
|
+
const tenantService = TenantServiceFactory()
|
|
72
|
+
return await tenantService.create(input)
|
|
73
|
+
} catch (e) {
|
|
74
|
+
console.error("createTenant",e)
|
|
75
|
+
if (e instanceof ValidationError) {
|
|
76
|
+
throw ValidationErrorToGraphQLError(e)
|
|
77
|
+
}
|
|
78
|
+
if (e instanceof UnauthorizedError) {
|
|
79
|
+
throw new GraphQLError(e.message)
|
|
80
|
+
}
|
|
81
|
+
throw new GraphQLError('error.server')
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
},
|
|
85
|
+
updateTenant: async (_, {id, input}, {rbac}) => {
|
|
86
|
+
try {
|
|
87
|
+
rbac.assertPermission(IdentityPermissions.UpdateTenant)
|
|
88
|
+
const tenantService = TenantServiceFactory()
|
|
89
|
+
return await tenantService.update(id, input)
|
|
90
|
+
} catch (e) {
|
|
91
|
+
console.error("updateTenant",e)
|
|
92
|
+
if (e instanceof ValidationError) {
|
|
93
|
+
throw ValidationErrorToGraphQLError(e)
|
|
94
|
+
}
|
|
95
|
+
if (e instanceof UnauthorizedError) {
|
|
96
|
+
throw new GraphQLError(e.message)
|
|
97
|
+
}
|
|
98
|
+
throw new GraphQLError('error.server')
|
|
99
|
+
}
|
|
100
|
+
},
|
|
101
|
+
deleteTenant: async (_, {id}, {rbac}) => {
|
|
102
|
+
try {
|
|
103
|
+
rbac.assertPermission(IdentityPermissions.DeleteTenant)
|
|
104
|
+
const tenantService = TenantServiceFactory()
|
|
105
|
+
return await tenantService.delete(id)
|
|
106
|
+
} catch (e) {
|
|
107
|
+
console.error("deleteTenant",e)
|
|
108
|
+
if (e instanceof ValidationError) {
|
|
109
|
+
throw ValidationErrorToGraphQLError(e)
|
|
110
|
+
}
|
|
111
|
+
if (e instanceof UnauthorizedError) {
|
|
112
|
+
throw new GraphQLError(e.message)
|
|
113
|
+
}
|
|
114
|
+
throw new GraphQLError('error.server')
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
@@ -5,13 +5,12 @@ import {IdentityPermissions} from "../../permissions/IdentityPermissions.js";
|
|
|
5
5
|
import UnauthorizedError from "../../errors/UnauthorizedError.js";
|
|
6
6
|
import BadCredentialsError from "../../errors/BadCredentialsError.js";
|
|
7
7
|
|
|
8
|
-
const userService = UserServiceFactory()
|
|
9
|
-
|
|
10
8
|
export default {
|
|
11
9
|
Query: {
|
|
12
10
|
me: async (_, {}, {authUser}) => {
|
|
13
11
|
try {
|
|
14
12
|
if (authUser) {
|
|
13
|
+
let userService= UserServiceFactory()
|
|
15
14
|
let user = await userService.findById(authUser.id)
|
|
16
15
|
delete user.password
|
|
17
16
|
return user
|
|
@@ -26,6 +25,7 @@ export default {
|
|
|
26
25
|
findUserById: async (_, {id}, {rbac}) => {
|
|
27
26
|
try {
|
|
28
27
|
rbac.assertPermission(IdentityPermissions.ViewUser)
|
|
28
|
+
let userService= UserServiceFactory()
|
|
29
29
|
return await userService.findById(id)
|
|
30
30
|
} catch (e) {
|
|
31
31
|
if (e instanceof UnauthorizedError) {
|
|
@@ -35,10 +35,14 @@ export default {
|
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
},
|
|
38
|
-
paginateUser: async (_, {page, limit, search}, {rbac}) => {
|
|
38
|
+
paginateUser: async (_, {page, limit, search, filters = []}, {rbac}) => {
|
|
39
39
|
try {
|
|
40
40
|
rbac.assertPermission(IdentityPermissions.ViewUser)
|
|
41
|
-
|
|
41
|
+
let userService= UserServiceFactory()
|
|
42
|
+
if(rbac.getAuthUser.tenantId){
|
|
43
|
+
filters.push({field: 'tenant', operator: '$eq', value: rbac.getAuthUser.tenantId})
|
|
44
|
+
}
|
|
45
|
+
return await userService.paginate(page, limit, search, filters)
|
|
42
46
|
} catch (e) {
|
|
43
47
|
if (e instanceof UnauthorizedError) {
|
|
44
48
|
throw new GraphQLError(e.message)
|
|
@@ -50,6 +54,7 @@ export default {
|
|
|
50
54
|
Mutation: {
|
|
51
55
|
auth: async (_, {input}) => {
|
|
52
56
|
try {
|
|
57
|
+
let userService= UserServiceFactory()
|
|
53
58
|
return await userService.auth(input.username, input.password)
|
|
54
59
|
} catch (e) {
|
|
55
60
|
console.error("auth", e)
|
|
@@ -63,6 +68,7 @@ export default {
|
|
|
63
68
|
createUser: async (_, {input}, {rbac}) => {
|
|
64
69
|
try {
|
|
65
70
|
rbac.assertPermission(IdentityPermissions.CreateUser)
|
|
71
|
+
let userService= UserServiceFactory()
|
|
66
72
|
const user = await userService.create(input)
|
|
67
73
|
return user
|
|
68
74
|
} catch (e) {
|
|
@@ -79,7 +85,7 @@ export default {
|
|
|
79
85
|
updateUser: async (_, {id, input}, {rbac}) => {
|
|
80
86
|
try {
|
|
81
87
|
rbac.assertPermission(IdentityPermissions.UpdateUser)
|
|
82
|
-
|
|
88
|
+
let userService= UserServiceFactory()
|
|
83
89
|
const user = await userService.update(id, input)
|
|
84
90
|
return user
|
|
85
91
|
} catch (e) {
|
|
@@ -94,6 +100,7 @@ export default {
|
|
|
94
100
|
deleteUser: async (_, {id}, {rbac}) => {
|
|
95
101
|
try {
|
|
96
102
|
rbac.assertPermission(IdentityPermissions.DeleteUser)
|
|
103
|
+
let userService= UserServiceFactory()
|
|
97
104
|
return await userService.delete(id)
|
|
98
105
|
} catch (e) {
|
|
99
106
|
console.error("deleteUser", e)
|
|
@@ -111,6 +118,7 @@ export default {
|
|
|
111
118
|
throw new UnauthorizedError()
|
|
112
119
|
}
|
|
113
120
|
let userId = authUser.id
|
|
121
|
+
let userService= UserServiceFactory()
|
|
114
122
|
return await userService.changeOwnPassword(userId, currentPassword, newPassword)
|
|
115
123
|
} catch (e) {
|
|
116
124
|
if (e instanceof ValidationError) {
|
|
@@ -124,7 +132,7 @@ export default {
|
|
|
124
132
|
changeUserPassword: async (_, {userId, newPassword}, {rbac}) => {
|
|
125
133
|
try {
|
|
126
134
|
rbac.assertPermission(IdentityPermissions.UpdateUser)
|
|
127
|
-
|
|
135
|
+
let userService= UserServiceFactory()
|
|
128
136
|
return await userService.changeUserPassword(userId, newPassword)
|
|
129
137
|
} catch (e) {
|
|
130
138
|
if (e instanceof ValidationError) {
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
type Tenant {
|
|
2
|
+
id: ID!
|
|
3
|
+
name: String
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
type TenantPaginated{
|
|
7
|
+
total: Int
|
|
8
|
+
page: Int
|
|
9
|
+
limit: Int
|
|
10
|
+
items: [Tenant]
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
type Query{
|
|
14
|
+
paginateTenant(page:Int, limit:Int, search:String): TenantPaginated
|
|
15
|
+
fetchTenant: [Tenant]
|
|
16
|
+
findTenantById(id: ID): Tenant
|
|
17
|
+
findTenantByName(name: String!): Tenant
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
input TenantInput{
|
|
21
|
+
name: String
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
type Mutation{
|
|
25
|
+
createTenant(input: TenantInput): Tenant
|
|
26
|
+
updateTenant(id: ID!, input: TenantInput): Tenant
|
|
27
|
+
deleteTenant(id: ID!): Boolean
|
|
28
|
+
}
|
|
@@ -4,6 +4,7 @@ type User {
|
|
|
4
4
|
name: String
|
|
5
5
|
email: String
|
|
6
6
|
role: Role
|
|
7
|
+
tenant: Tenant
|
|
7
8
|
phone: String
|
|
8
9
|
avatar: String
|
|
9
10
|
active: Boolean
|
|
@@ -28,6 +29,7 @@ input UserCreateInput{
|
|
|
28
29
|
username: String!
|
|
29
30
|
password: String!
|
|
30
31
|
role: ID
|
|
32
|
+
tenant: ID
|
|
31
33
|
email: String!
|
|
32
34
|
phone: String
|
|
33
35
|
active: Boolean
|
|
@@ -37,6 +39,7 @@ input UserUpdateInput{
|
|
|
37
39
|
name: String
|
|
38
40
|
username: String!
|
|
39
41
|
role: ID
|
|
42
|
+
tenant: ID
|
|
40
43
|
email: String!
|
|
41
44
|
phone: String
|
|
42
45
|
active: Boolean
|
package/src/index.ts
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
import GraphqlMerge from "./graphql/index.js"
|
|
2
2
|
import UserServiceFactory from "./factory/UserServiceFactory.js";
|
|
3
3
|
import RoleServiceFactory from "./factory/RoleServiceFactory.js";
|
|
4
|
+
import TenantServiceFactory from "./factory/TenantServiceFactory.js";
|
|
4
5
|
import RoleService from "./services/RoleService.js";
|
|
5
6
|
import UserService from "./services/UserService.js";
|
|
7
|
+
import TenantService from "./services/TenantService.js";
|
|
6
8
|
import PermissionService from "./services/PermissionService.js";
|
|
7
9
|
import Rbac from "./rbac/Rbac.js";
|
|
8
10
|
import {UserRoutes} from "./routes/UserRoutes.js";
|
|
9
11
|
import {RoleRoutes} from "./routes/RoleRoutes.js";
|
|
12
|
+
import {TenantRoutes} from "./routes/TenantRoutes.js";
|
|
10
13
|
import AuthUtils from "./utils/AuthUtils.js";
|
|
11
14
|
import {jwtMiddleware} from "./middleware/jwtMiddleware.js";
|
|
12
15
|
import {rbacMiddleware} from "./middleware/rbacMiddleware.js";
|
|
@@ -45,12 +48,14 @@ export {
|
|
|
45
48
|
//Service
|
|
46
49
|
UserService,
|
|
47
50
|
RoleService,
|
|
51
|
+
TenantService,
|
|
48
52
|
PermissionService,
|
|
49
53
|
Rbac,
|
|
50
54
|
|
|
51
55
|
//Factories
|
|
52
56
|
UserServiceFactory,
|
|
53
57
|
RoleServiceFactory,
|
|
58
|
+
TenantServiceFactory,
|
|
54
59
|
|
|
55
60
|
//GQL
|
|
56
61
|
identityTypeDefs,
|
|
@@ -59,6 +64,7 @@ export {
|
|
|
59
64
|
//API REST
|
|
60
65
|
UserRoutes,
|
|
61
66
|
RoleRoutes,
|
|
67
|
+
TenantRoutes,
|
|
62
68
|
|
|
63
69
|
AuthUtils,
|
|
64
70
|
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import {ITenant} from './ITenant'
|
|
2
|
+
import {IPaginateFilter, IPaginateResult} from "@drax/common-back";
|
|
3
|
+
import {IID} from "./IID";
|
|
4
|
+
interface ITenantRepository{
|
|
5
|
+
create(role: ITenant): Promise<ITenant>;
|
|
6
|
+
update(id: IID, updatedRole: ITenant): Promise<ITenant | null>;
|
|
7
|
+
delete(id: IID): Promise<boolean>;
|
|
8
|
+
findById(id: IID): Promise<ITenant | null>;
|
|
9
|
+
findByName(name: string): Promise<ITenant | null>;
|
|
10
|
+
fetchAll(): Promise<ITenant[]>;
|
|
11
|
+
paginate(page?: number, limit?: number, search?:string, filters?: IPaginateFilter[]): Promise<IPaginateResult>;
|
|
12
|
+
table?():void
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export {ITenantRepository}
|
package/src/interfaces/IUser.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {mongoose} from "@drax/common-back";
|
|
2
1
|
import {IRole} from "./IRole";
|
|
3
2
|
import {IUserGroup} from "./IUserGroup";
|
|
4
3
|
import {IID} from "./IID";
|
|
4
|
+
import {ITenant} from "./ITenant";
|
|
5
5
|
|
|
6
6
|
interface IUser {
|
|
7
7
|
id?: IID
|
|
@@ -14,6 +14,7 @@ interface IUser {
|
|
|
14
14
|
avatar?: string
|
|
15
15
|
code?: string
|
|
16
16
|
role: IRole | IID
|
|
17
|
+
tenant?: ITenant | IID
|
|
17
18
|
groups: IID[] | IUserGroup[] | string[] | string
|
|
18
19
|
toObject(): IUser;
|
|
19
20
|
}
|
|
@@ -27,6 +28,7 @@ interface IUserCreate {
|
|
|
27
28
|
active: boolean | number
|
|
28
29
|
phone: string
|
|
29
30
|
role: IID
|
|
31
|
+
tenant?: IID
|
|
30
32
|
groups: IID[] | string
|
|
31
33
|
}
|
|
32
34
|
|
|
@@ -38,6 +40,7 @@ interface IUserUpdate {
|
|
|
38
40
|
active: boolean
|
|
39
41
|
phone: string
|
|
40
42
|
role: IID
|
|
43
|
+
tenant?: IID
|
|
41
44
|
groups: IID[]
|
|
42
45
|
password?: string
|
|
43
46
|
}
|
|
@@ -1,20 +1,18 @@
|
|
|
1
1
|
import type {IJwtUser} from "../interfaces/IJwtUser";
|
|
2
|
-
import type {IRole
|
|
2
|
+
import type {IRole} from "../interfaces/IRole";
|
|
3
3
|
import {DraxCache, DraxConfig} from "@drax/common-back";
|
|
4
4
|
import RoleServiceFactory from "../factory/RoleServiceFactory.js";
|
|
5
5
|
import Rbac from "../rbac/Rbac.js";
|
|
6
6
|
import IdentityConfig from "../config/IdentityConfig.js";
|
|
7
7
|
|
|
8
8
|
const cacheTTL = DraxConfig.getOrLoad(IdentityConfig.RbacCacheTTL) ? parseInt(DraxConfig.getOrLoad(IdentityConfig.RbacCacheTTL)) : 10000;
|
|
9
|
-
const draxCache = new DraxCache<
|
|
10
|
-
const roleService = RoleServiceFactory()
|
|
9
|
+
const draxCache = new DraxCache<IRole>(cacheTTL);
|
|
11
10
|
|
|
12
|
-
|
|
11
|
+
|
|
12
|
+
async function roleLoader(k):Promise<IRole | null> {
|
|
13
|
+
const roleService = RoleServiceFactory()
|
|
13
14
|
const role: IRole = await roleService.findById(k)
|
|
14
|
-
|
|
15
|
-
return {id: role.id, name: role.name, permissions: role.permissions} as IRoleBase
|
|
16
|
-
}
|
|
17
|
-
return null
|
|
15
|
+
return role
|
|
18
16
|
}
|
|
19
17
|
|
|
20
18
|
async function rbacMiddleware (request, reply) {
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import {mongoose, MongooseSoftDelete} from '@drax/common-back';
|
|
2
|
+
import uniqueValidator from 'mongoose-unique-validator';
|
|
3
|
+
import mongoosePaginate from 'mongoose-paginate-v2'
|
|
4
|
+
import {ITenant} from '../interfaces/ITenant'
|
|
5
|
+
const Schema = mongoose.Schema
|
|
6
|
+
import {PaginateModel} from "mongoose";
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
const TenantSchema = new Schema<ITenant>({
|
|
10
|
+
name: {
|
|
11
|
+
type: String, unique: true, required: true, index: true,
|
|
12
|
+
},
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
TenantSchema.plugin(uniqueValidator, {message: 'validation.unique'});
|
|
16
|
+
TenantSchema.plugin(MongooseSoftDelete);
|
|
17
|
+
TenantSchema.plugin(mongoosePaginate);
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
TenantSchema.set('toJSON', {getters: true});
|
|
21
|
+
|
|
22
|
+
const TENANT_MODEL_NAME = 'Tenant';
|
|
23
|
+
const TENANT_COLLECTION_NAME = 'tenants';
|
|
24
|
+
const TenantModel = mongoose.model<ITenant, PaginateModel<ITenant>>(TENANT_MODEL_NAME, TenantSchema,TENANT_COLLECTION_NAME);
|
|
25
|
+
|
|
26
|
+
export {
|
|
27
|
+
TenantSchema,
|
|
28
|
+
TenantModel
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export default TenantModel
|
|
32
|
+
|
package/src/models/UserModel.ts
CHANGED
|
@@ -54,6 +54,11 @@ const UserSchema = new mongoose.Schema<IUser>({
|
|
|
54
54
|
ref: 'Role',
|
|
55
55
|
required: true,
|
|
56
56
|
},
|
|
57
|
+
tenant: {
|
|
58
|
+
type: mongoose.Schema.Types.ObjectId,
|
|
59
|
+
ref: 'Tenant',
|
|
60
|
+
required: false,
|
|
61
|
+
},
|
|
57
62
|
groups: [{
|
|
58
63
|
type: mongoose.Schema.Types.ObjectId,
|
|
59
64
|
ref: 'Group',
|