@drax/identity-back 0.0.15 → 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 +12 -1
- package/dist/graphql/resolvers/tenant.resolvers.js +121 -0
- package/dist/graphql/resolvers/user.resolvers.js +5 -2
- 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 +1 -4
- 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 +10 -1
- package/dist/routes/TenantRoutes.js +183 -0
- package/dist/routes/UserRoutes.js +6 -1
- 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 +13 -1
- package/src/graphql/resolvers/tenant.resolvers.ts +119 -0
- package/src/graphql/resolvers/user.resolvers.ts +5 -2
- 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 +4 -7
- 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 +9 -1
- package/src/routes/TenantRoutes.ts +178 -0
- package/src/routes/UserRoutes.ts +6 -1
- 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,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
|
+
}
|
|
@@ -35,11 +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
|
-
|
|
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)
|
|
43
46
|
} catch (e) {
|
|
44
47
|
if (e instanceof UnauthorizedError) {
|
|
45
48
|
throw new GraphQLError(e.message)
|
|
@@ -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,21 +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<
|
|
9
|
+
const draxCache = new DraxCache<IRole>(cacheTTL);
|
|
10
10
|
|
|
11
11
|
|
|
12
|
-
async function roleLoader(k):Promise<
|
|
12
|
+
async function roleLoader(k):Promise<IRole | null> {
|
|
13
13
|
const roleService = RoleServiceFactory()
|
|
14
14
|
const role: IRole = await roleService.findById(k)
|
|
15
|
-
|
|
16
|
-
return {id: role.id, name: role.name, permissions: role.permissions} as IRoleBase
|
|
17
|
-
}
|
|
18
|
-
return null
|
|
15
|
+
return role
|
|
19
16
|
}
|
|
20
17
|
|
|
21
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',
|
|
@@ -14,6 +14,13 @@ enum IdentityPermissions {
|
|
|
14
14
|
ManageRole = "role:manage",
|
|
15
15
|
PermissionsRole = "role:permissions",
|
|
16
16
|
|
|
17
|
+
|
|
18
|
+
CreateTenant = "tenant:create",
|
|
19
|
+
UpdateTenant = "tenant:update",
|
|
20
|
+
DeleteTenant = "tenant:delete",
|
|
21
|
+
ViewTenant = "tenant:view",
|
|
22
|
+
ManageTenant = "tenant:manage",
|
|
23
|
+
|
|
17
24
|
}
|
|
18
25
|
|
|
19
26
|
export default IdentityPermissions;
|
package/src/rbac/Rbac.ts
CHANGED
|
@@ -1,16 +1,24 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {IRole} from "../interfaces/IRole";
|
|
2
2
|
import {IJwtUser} from "../interfaces/IJwtUser";
|
|
3
3
|
import UnauthorizedError from "../errors/UnauthorizedError.js";
|
|
4
4
|
|
|
5
5
|
class Rbac{
|
|
6
|
-
private role:
|
|
6
|
+
private role: IRole;
|
|
7
7
|
private authUser: IJwtUser;
|
|
8
8
|
|
|
9
|
-
constructor(authUser: IJwtUser, role:
|
|
9
|
+
constructor(authUser: IJwtUser, role: IRole) {
|
|
10
10
|
this.authUser = authUser;
|
|
11
11
|
this.role = role;
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
+
get getRole() {
|
|
15
|
+
return this.role
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
get getAuthUser() {
|
|
19
|
+
return this.authUser
|
|
20
|
+
}
|
|
21
|
+
|
|
14
22
|
hasPermission(requiredPermission: string): boolean {
|
|
15
23
|
if (!this.authUser || !this.role || !this.role.permissions || this.role.permissions.length === 0) {
|
|
16
24
|
return false;
|
|
@@ -10,31 +10,32 @@ class RoleMongoRepository implements IRoleRepository{
|
|
|
10
10
|
async create(roleData: IRole): Promise<IRole> {
|
|
11
11
|
const role : mongoose.HydratedDocument<IRole> = new RoleModel(roleData)
|
|
12
12
|
await role.save()
|
|
13
|
+
await role.populate('childRoles')
|
|
13
14
|
return role
|
|
14
15
|
}
|
|
15
16
|
|
|
16
17
|
async update(id: mongoose.Types.ObjectId | string, roleData: IRole): Promise<IRole> {
|
|
17
|
-
const role : mongoose.HydratedDocument<IRole> = await RoleModel.findOneAndUpdate({_id: id}, roleData, {new: true}).exec()
|
|
18
|
+
const role : mongoose.HydratedDocument<IRole> = await RoleModel.findOneAndUpdate({_id: id}, roleData, {new: true}).populate('childRoles').exec()
|
|
18
19
|
return role
|
|
19
20
|
}
|
|
20
21
|
|
|
21
22
|
async delete(id: mongoose.Types.ObjectId): Promise<boolean> {
|
|
22
|
-
const result : DeleteResult = await RoleModel.deleteOne(id).exec()
|
|
23
|
+
const result : DeleteResult = await RoleModel.deleteOne({_id: id}).exec()
|
|
23
24
|
return result.deletedCount == 1
|
|
24
25
|
}
|
|
25
26
|
|
|
26
27
|
async findById(id: mongoose.Types.ObjectId): Promise<IRole | null>{
|
|
27
|
-
const role: mongoose.HydratedDocument<IRole> | null = await RoleModel.findById(id).exec()
|
|
28
|
+
const role: mongoose.HydratedDocument<IRole> | null = await RoleModel.findById(id).populate('childRoles').exec()
|
|
28
29
|
return role
|
|
29
30
|
}
|
|
30
31
|
|
|
31
32
|
async findByName(name: string): Promise<IRole | null>{
|
|
32
|
-
const role: mongoose.HydratedDocument<IRole> | null = await RoleModel.findOne({name}).exec()
|
|
33
|
+
const role: mongoose.HydratedDocument<IRole> | null = await RoleModel.findOne({name}).populate('childRoles').exec()
|
|
33
34
|
return role
|
|
34
35
|
}
|
|
35
36
|
|
|
36
37
|
async fetchAll(): Promise<IRole[]>{
|
|
37
|
-
const roles: mongoose.HydratedDocument<IRole>[] = await RoleModel.find().exec()
|
|
38
|
+
const roles: mongoose.HydratedDocument<IRole>[] = await RoleModel.find().populate('childRoles').exec()
|
|
38
39
|
return roles
|
|
39
40
|
}
|
|
40
41
|
|
|
@@ -48,7 +49,7 @@ class RoleMongoRepository implements IRoleRepository{
|
|
|
48
49
|
]
|
|
49
50
|
}
|
|
50
51
|
|
|
51
|
-
const options = {page, limit} as PaginateOptions
|
|
52
|
+
const options = {populate: ['childRoles'], page, limit} as PaginateOptions
|
|
52
53
|
const roles: PaginateResult<IRole> = await RoleModel.paginate(query, options)
|
|
53
54
|
return {
|
|
54
55
|
page: page,
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import {TenantModel} from "../../models/TenantModel.js";
|
|
2
|
+
import {ITenant} from '../../interfaces/ITenant'
|
|
3
|
+
import {ITenantRepository} from '../../interfaces/ITenantRepository'
|
|
4
|
+
import {IPaginateFilter, IPaginateResult, mongoose} from "@drax/common-back";
|
|
5
|
+
import {FilterQuery, PaginateOptions, PaginateResult} from "mongoose";
|
|
6
|
+
import {DeleteResult} from "mongodb";
|
|
7
|
+
|
|
8
|
+
class TenantMongoRepository implements ITenantRepository{
|
|
9
|
+
|
|
10
|
+
async create(tenantData: ITenant): Promise<ITenant> {
|
|
11
|
+
const tenant : mongoose.HydratedDocument<ITenant> = new TenantModel(tenantData)
|
|
12
|
+
await tenant.save()
|
|
13
|
+
return tenant
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
async update(id: mongoose.Types.ObjectId | string, tenantData: ITenant): Promise<ITenant> {
|
|
17
|
+
const tenant : mongoose.HydratedDocument<ITenant> = await TenantModel.findOneAndUpdate({_id: id}, tenantData, {new: true}).exec()
|
|
18
|
+
return tenant
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
async delete(id: mongoose.Types.ObjectId): Promise<boolean> {
|
|
22
|
+
const result : DeleteResult = await TenantModel.deleteOne({_id:id}).exec()
|
|
23
|
+
return result.deletedCount == 1
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
async findById(id: mongoose.Types.ObjectId): Promise<ITenant | null>{
|
|
27
|
+
const tenant: mongoose.HydratedDocument<ITenant> | null = await TenantModel.findById(id).exec()
|
|
28
|
+
return tenant
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
async findByName(name: string): Promise<ITenant | null>{
|
|
32
|
+
const tenant: mongoose.HydratedDocument<ITenant> | null = await TenantModel.findOne({name}).exec()
|
|
33
|
+
return tenant
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
async fetchAll(): Promise<ITenant[]>{
|
|
37
|
+
const tenants: mongoose.HydratedDocument<ITenant>[] = await TenantModel.find().exec()
|
|
38
|
+
return tenants
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
async paginate(page:number = 1, limit:number = 5, search:string): Promise<IPaginateResult>{
|
|
42
|
+
|
|
43
|
+
const query = {}
|
|
44
|
+
|
|
45
|
+
if(search){
|
|
46
|
+
query['$or'] = [
|
|
47
|
+
{name: new RegExp(search, 'i')},
|
|
48
|
+
]
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const options = {page, limit} as PaginateOptions
|
|
52
|
+
const tenants: PaginateResult<ITenant> = await TenantModel.paginate(query, options)
|
|
53
|
+
return {
|
|
54
|
+
page: page,
|
|
55
|
+
limit: limit,
|
|
56
|
+
total: tenants.totalDocs,
|
|
57
|
+
items: tenants.docs
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export default TenantMongoRepository
|
|
@@ -24,7 +24,7 @@ class UserMongoRepository implements IUserRepository {
|
|
|
24
24
|
|
|
25
25
|
const user: mongoose.HydratedDocument<IUser> = new UserModel(userData)
|
|
26
26
|
await user.save()
|
|
27
|
-
await user.populate('role')
|
|
27
|
+
await user.populate(['role','tenant'])
|
|
28
28
|
return user
|
|
29
29
|
}catch (e){
|
|
30
30
|
if(e instanceof mongoose.Error.ValidationError){
|
|
@@ -37,7 +37,7 @@ class UserMongoRepository implements IUserRepository {
|
|
|
37
37
|
|
|
38
38
|
async update(id: mongoose.Types.ObjectId, userData: IUserUpdate): Promise<IUser> {
|
|
39
39
|
try{
|
|
40
|
-
const user: mongoose.HydratedDocument<IUser> = await UserModel.findOneAndUpdate({_id: id}, userData, {new: true}).populate('role').exec()
|
|
40
|
+
const user: mongoose.HydratedDocument<IUser> = await UserModel.findOneAndUpdate({_id: id}, userData, {new: true}).populate(['role','tenant']).exec()
|
|
41
41
|
return user
|
|
42
42
|
}catch (e){
|
|
43
43
|
if(e instanceof mongoose.Error.ValidationError){
|
|
@@ -57,16 +57,16 @@ class UserMongoRepository implements IUserRepository {
|
|
|
57
57
|
|
|
58
58
|
|
|
59
59
|
async findById(id: mongoose.Types.ObjectId): Promise<IUser> {
|
|
60
|
-
const user: mongoose.HydratedDocument<IUser> = await UserModel.findById(id).populate('role').exec()
|
|
60
|
+
const user: mongoose.HydratedDocument<IUser> = await UserModel.findById(id).populate(['role','tenant']).exec()
|
|
61
61
|
return user
|
|
62
62
|
}
|
|
63
63
|
|
|
64
64
|
async findByUsername(username: string): Promise<IUser> {
|
|
65
|
-
const user: mongoose.HydratedDocument<IUser> = await UserModel.findOne({username: username}).populate('role').exec()
|
|
65
|
+
const user: mongoose.HydratedDocument<IUser> = await UserModel.findOne({username: username}).populate(['role','tenant']).exec()
|
|
66
66
|
return user
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
-
async paginate(page: number = 1, limit: number = 5, search?:string): Promise<IPaginateResult> {
|
|
69
|
+
async paginate(page: number = 1, limit: number = 5, search?:string, filters?:IPaginateFilter[]): Promise<IPaginateResult> {
|
|
70
70
|
|
|
71
71
|
|
|
72
72
|
const query = {}
|
|
@@ -79,7 +79,21 @@ class UserMongoRepository implements IUserRepository {
|
|
|
79
79
|
]
|
|
80
80
|
}
|
|
81
81
|
|
|
82
|
-
|
|
82
|
+
if(filters){
|
|
83
|
+
for(const filter of filters){
|
|
84
|
+
if(filter.operator === '$eq'){
|
|
85
|
+
query[filter.field] = {$eq: filter.value}
|
|
86
|
+
}
|
|
87
|
+
if(filter.operator === '$ne'){
|
|
88
|
+
query[filter.field] = {$ne: filter.value}
|
|
89
|
+
}
|
|
90
|
+
if(filter.operator === '$in'){
|
|
91
|
+
query[filter.field] = {$in: filter.value}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const options = {populate: ['role','tenant'], page: page, limit: limit }
|
|
83
97
|
|
|
84
98
|
const userPaginated: PaginateResult<IUser> = await UserModel.paginate(query, options)
|
|
85
99
|
return {
|
|
@@ -25,6 +25,7 @@ class RoleSqliteRepository implements IRoleRepository{
|
|
|
25
25
|
|
|
26
26
|
constructor(DATABASE:string, verbose:boolean = false) {
|
|
27
27
|
this.db = new sqlite(DATABASE, {verbose: verbose ? console.log : null});
|
|
28
|
+
this.table()
|
|
28
29
|
}
|
|
29
30
|
|
|
30
31
|
table() {
|
|
@@ -78,7 +79,7 @@ class RoleSqliteRepository implements IRoleRepository{
|
|
|
78
79
|
async findById(id: IID): Promise<IRole | null>{
|
|
79
80
|
const role = this.db.prepare('SELECT * FROM roles WHERE id = ?').get(id);
|
|
80
81
|
if(role){
|
|
81
|
-
|
|
82
|
+
await this.populateRole(role)
|
|
82
83
|
return role
|
|
83
84
|
}
|
|
84
85
|
return undefined
|
|
@@ -87,7 +88,7 @@ class RoleSqliteRepository implements IRoleRepository{
|
|
|
87
88
|
async findByName(name: string): Promise<IRole | null>{
|
|
88
89
|
const role = this.db.prepare('SELECT * FROM roles WHERE name = ?').get(name);
|
|
89
90
|
if(role){
|
|
90
|
-
|
|
91
|
+
await this.populateRole(role)
|
|
91
92
|
return role
|
|
92
93
|
}
|
|
93
94
|
return undefined
|
|
@@ -125,7 +126,7 @@ class RoleSqliteRepository implements IRoleRepository{
|
|
|
125
126
|
async fetchAll(): Promise<IRole[]>{
|
|
126
127
|
const roles = this.db.prepare('SELECT * FROM roles').all();
|
|
127
128
|
for (const role of roles) {
|
|
128
|
-
|
|
129
|
+
await this.populateRole(role)
|
|
129
130
|
}
|
|
130
131
|
return roles
|
|
131
132
|
}
|
|
@@ -133,7 +134,7 @@ class RoleSqliteRepository implements IRoleRepository{
|
|
|
133
134
|
async paginate(page = 1, limit = 5, search=""): Promise<IPaginateResult>{
|
|
134
135
|
const offset = page > 1 ? (page - 1) * limit : 0
|
|
135
136
|
|
|
136
|
-
let where
|
|
137
|
+
let where=""
|
|
137
138
|
if (search) {
|
|
138
139
|
where = ` WHERE name LIKE '%${search}%'`
|
|
139
140
|
}
|
|
@@ -142,10 +143,9 @@ class RoleSqliteRepository implements IRoleRepository{
|
|
|
142
143
|
const roles = this.db.prepare('SELECT * FROM roles LIMIT ? OFFSET ?'+where).all([limit, offset]);
|
|
143
144
|
|
|
144
145
|
for (const role of roles) {
|
|
145
|
-
|
|
146
|
+
await this.populateRole(role)
|
|
146
147
|
}
|
|
147
148
|
|
|
148
|
-
|
|
149
149
|
return {
|
|
150
150
|
page: page,
|
|
151
151
|
limit: limit,
|
|
@@ -154,6 +154,27 @@ class RoleSqliteRepository implements IRoleRepository{
|
|
|
154
154
|
}
|
|
155
155
|
}
|
|
156
156
|
|
|
157
|
+
async findWithoutPopulateById(id: IID): Promise<IRole | null>{
|
|
158
|
+
const role = this.db.prepare('SELECT * FROM roles WHERE id = ?').get(id);
|
|
159
|
+
if(role){
|
|
160
|
+
return role
|
|
161
|
+
}
|
|
162
|
+
return undefined
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
async populateRole(role){
|
|
166
|
+
role.permissions = role.permissions? role.permissions.split(",") : []
|
|
167
|
+
role.childRoles = role.childRoles? role.childRoles.split(",") : []
|
|
168
|
+
|
|
169
|
+
const childRoles = []
|
|
170
|
+
for(const childRoleId of role.childRoles){
|
|
171
|
+
const childRole:IRole = await this.findWithoutPopulateById(childRoleId)
|
|
172
|
+
childRoles.push(childRole)
|
|
173
|
+
}
|
|
174
|
+
role.childRoles = childRoles
|
|
175
|
+
return role
|
|
176
|
+
}
|
|
177
|
+
|
|
157
178
|
|
|
158
179
|
}
|
|
159
180
|
|