@drax/identity-back 0.11.5 → 0.12.2
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/controllers/RoleController.js +8 -39
- package/dist/controllers/TenantController.js +1 -28
- package/dist/controllers/UserApiKeyController.js +3 -3
- package/dist/controllers/UserController.js +48 -209
- package/dist/errors/BadCredentialsError.js +12 -0
- package/dist/factory/RoleServiceFactory.js +1 -0
- package/dist/factory/TenantServiceFactory.js +1 -0
- package/dist/factory/UserApiKeyServiceFactory.js +5 -4
- package/dist/factory/UserServiceFactory.js +1 -0
- package/dist/graphql/resolvers/role.resolvers.js +2 -2
- package/dist/graphql/resolvers/tenant.resolvers.js +2 -2
- package/dist/graphql/resolvers/user-api-key.resolvers.js +2 -2
- package/dist/graphql/resolvers/user.resolvers.js +1 -1
- package/dist/index.js +6 -0
- package/dist/middleware/apiKeyMiddleware.js +2 -2
- package/dist/models/RoleModel.js +10 -7
- package/dist/models/TenantModel.js +11 -8
- package/dist/models/UserApiKeyModel.js +10 -7
- package/dist/models/UserGroupModel.js +7 -7
- package/dist/models/UserModel.js +10 -8
- package/dist/rbac/Rbac.js +10 -8
- package/dist/repository/mongo/RoleMongoRepository.js +20 -65
- package/dist/repository/mongo/TenantMongoRepository.js +18 -66
- package/dist/repository/mongo/UserApiKeyMongoRepository.js +29 -47
- package/dist/repository/mongo/UserMongoRepository.js +56 -85
- package/dist/repository/sqlite/RoleSqliteRepository.js +30 -115
- package/dist/repository/sqlite/TenantSqliteRepository.js +15 -105
- package/dist/repository/sqlite/UserApiKeySqliteRepository.js +42 -117
- package/dist/repository/sqlite/UserSqliteRepository.js +49 -130
- package/dist/routes/RoleRoutes.js +35 -10
- package/dist/routes/TenantRoutes.js +18 -9
- package/dist/routes/UserApiKeyRoutes.js +20 -4
- package/dist/routes/UserRoutes.js +92 -17
- package/dist/schemas/LoginSchema.js +9 -0
- package/dist/schemas/PasswordSchema.js +12 -0
- package/dist/schemas/RegisterSchema.js +19 -0
- package/dist/schemas/RoleSchema.js +23 -0
- package/dist/schemas/TenantSchema.js +13 -0
- package/dist/schemas/UserApiKeySchema.js +14 -0
- package/dist/schemas/UserSchema.js +39 -0
- package/dist/services/PermissionService.js +5 -5
- package/dist/services/RoleService.js +6 -6
- package/dist/services/TenantService.js +6 -6
- package/dist/services/UserApiKeyService.js +5 -5
- package/dist/services/UserService.js +14 -14
- package/dist/setup/CreateOrUpdateRole.js +5 -2
- package/dist/setup/CreateUserIfNotExist.js +3 -1
- package/dist/setup/RecoveryUserPassword.js +1 -1
- package/dist/zod/EndpointZod.js +9 -0
- package/dist/zod/TenantSchema.js +12 -0
- package/dist/zod/TenantZod.js +5 -3
- package/dist/zod/UserApiKeyZod.js +7 -3
- package/package.json +10 -9
- package/src/controllers/RoleController.ts +8 -36
- package/src/controllers/TenantController.ts +2 -25
- package/src/controllers/UserApiKeyController.ts +3 -3
- package/src/controllers/UserController.ts +50 -183
- package/src/errors/BadCredentialsError.ts +18 -1
- package/src/factory/RoleServiceFactory.ts +1 -0
- package/src/factory/TenantServiceFactory.ts +1 -0
- package/src/factory/UserApiKeyServiceFactory.ts +5 -4
- package/src/factory/UserServiceFactory.ts +1 -0
- package/src/graphql/resolvers/role.resolvers.ts +3 -2
- package/src/graphql/resolvers/tenant.resolvers.ts +3 -2
- package/src/graphql/resolvers/user-api-key.resolvers.ts +3 -2
- package/src/graphql/resolvers/user.resolvers.ts +2 -1
- package/src/index.ts +16 -0
- package/src/interfaces/ITenantRepository.ts +2 -2
- package/src/interfaces/IUserApiKeyRepository.ts +2 -2
- package/src/interfaces/IUserRepository.ts +3 -2
- package/src/middleware/apiKeyMiddleware.ts +2 -2
- package/src/models/RoleModel.ts +12 -7
- package/src/models/TenantModel.ts +13 -8
- package/src/models/UserApiKeyModel.ts +12 -7
- package/src/models/UserGroupModel.ts +7 -7
- package/src/models/UserModel.ts +10 -8
- package/src/rbac/Rbac.ts +12 -9
- package/src/repository/mongo/RoleMongoRepository.ts +23 -94
- package/src/repository/mongo/TenantMongoRepository.ts +19 -98
- package/src/repository/mongo/UserApiKeyMongoRepository.ts +31 -56
- package/src/repository/mongo/UserMongoRepository.ts +71 -130
- package/src/repository/sqlite/RoleSqliteRepository.ts +37 -146
- package/src/repository/sqlite/TenantSqliteRepository.ts +16 -156
- package/src/repository/sqlite/UserApiKeySqliteRepository.ts +46 -151
- package/src/repository/sqlite/UserSqliteRepository.ts +59 -173
- package/src/routes/RoleRoutes.ts +35 -12
- package/src/routes/TenantRoutes.ts +25 -9
- package/src/routes/UserApiKeyRoutes.ts +23 -7
- package/src/routes/UserRoutes.ts +117 -34
- package/src/schemas/LoginSchema.ts +12 -0
- package/src/schemas/PasswordSchema.ts +16 -0
- package/src/{zod/UserZod.ts → schemas/RegisterSchema.ts} +7 -10
- package/src/schemas/RoleSchema.ts +29 -0
- package/src/schemas/TenantSchema.ts +22 -0
- package/src/{zod/UserApiKeyZod.ts → schemas/UserApiKeySchema.ts} +8 -3
- package/src/schemas/UserSchema.ts +57 -0
- package/src/services/PermissionService.ts +6 -5
- package/src/services/RoleService.ts +6 -6
- package/src/services/TenantService.ts +10 -10
- package/src/services/UserApiKeyService.ts +5 -5
- package/src/services/UserService.ts +15 -16
- package/src/setup/CreateOrUpdateRole.ts +7 -4
- package/src/setup/CreateUserIfNotExist.ts +5 -3
- package/src/setup/RecoveryUserPassword.ts +1 -1
- package/test/data-obj/apikey/root-mongo-user-apikey.ts +2 -1
- package/test/data-obj/roles/admin-sqlite-role.ts +2 -2
- package/test/data-obj/roles/operator-sqlite-role.ts +1 -1
- package/test/data-obj/tenants/company-sqlite-tenant.ts +6 -0
- package/test/data-obj/users/root-sqlite-user.ts +2 -2
- package/test/initializers/RoleSqliteInitializer.ts +1 -1
- package/test/repository/mongo/role-mongo-repository.test.ts +3 -3
- package/test/repository/mongo/user-apikey-mongo-repository.test.ts +5 -4
- package/test/repository/mongo/user-mongo-repository.test.ts +4 -4
- package/test/repository/sqlite/role-sqlite-repository.test.ts +21 -9
- package/test/repository/sqlite/tenant-sqlite-repository.test.ts +74 -0
- package/test/repository/sqlite/user-sqlite-repository.test.ts +15 -9
- package/test/routes/data/admin-role.ts +10 -0
- package/test/routes/data/root-user.ts +13 -0
- package/test/routes/helpers/CreateRootUserAndAdminRole.ts +17 -0
- package/test/routes/helpers/FastifyTestServerFactory.ts +34 -0
- package/test/routes/helpers/InitializePermissions.ts +23 -0
- package/test/routes/helpers/SetupIdentityDrax.ts +22 -0
- package/test/routes/tenant-route.test.ts +336 -0
- package/test/routes/user-route.test.ts +186 -0
- package/test/schemas/lab-schema.test.ts +110 -0
- package/test/service/mock-service.test.ts +3 -3
- package/test/service/role-service.test.ts +3 -3
- package/test/service/user-service.test.ts +16 -25
- package/test.db +0 -0
- package/tsconfig.tsbuildinfo +1 -1
- package/types/controllers/RoleController.d.ts +0 -1
- package/types/controllers/RoleController.d.ts.map +1 -1
- package/types/controllers/TenantController.d.ts +0 -1
- package/types/controllers/TenantController.d.ts.map +1 -1
- package/types/controllers/UserController.d.ts +11 -4
- package/types/controllers/UserController.d.ts.map +1 -1
- package/types/errors/BadCredentialsError.d.ts +9 -1
- package/types/errors/BadCredentialsError.d.ts.map +1 -1
- package/types/factory/RoleServiceFactory.d.ts.map +1 -1
- package/types/factory/TenantServiceFactory.d.ts.map +1 -1
- package/types/factory/UserApiKeyServiceFactory.d.ts.map +1 -1
- package/types/factory/UserServiceFactory.d.ts.map +1 -1
- package/types/graphql/resolvers/role.resolvers.d.ts +3 -9
- package/types/graphql/resolvers/role.resolvers.d.ts.map +1 -1
- package/types/graphql/resolvers/tenant.resolvers.d.ts +3 -9
- package/types/graphql/resolvers/tenant.resolvers.d.ts.map +1 -1
- package/types/graphql/resolvers/user-api-key.resolvers.d.ts +3 -9
- package/types/graphql/resolvers/user-api-key.resolvers.d.ts.map +1 -1
- package/types/graphql/resolvers/user.resolvers.d.ts +3 -9
- package/types/graphql/resolvers/user.resolvers.d.ts.map +1 -1
- package/types/index.d.ts +5 -1
- package/types/index.d.ts.map +1 -1
- package/types/interfaces/ITenantRepository.d.ts +2 -2
- package/types/interfaces/ITenantRepository.d.ts.map +1 -1
- package/types/interfaces/IUserApiKeyRepository.d.ts +2 -2
- package/types/interfaces/IUserApiKeyRepository.d.ts.map +1 -1
- package/types/interfaces/IUserRepository.d.ts +3 -2
- package/types/interfaces/IUserRepository.d.ts.map +1 -1
- package/types/models/RoleModel.d.ts +7 -7
- package/types/models/RoleModel.d.ts.map +1 -1
- package/types/models/TenantModel.d.ts +7 -7
- package/types/models/TenantModel.d.ts.map +1 -1
- package/types/models/UserApiKeyModel.d.ts +7 -7
- package/types/models/UserApiKeyModel.d.ts.map +1 -1
- package/types/models/UserGroupModel.d.ts +2 -2
- package/types/models/UserGroupModel.d.ts.map +1 -1
- package/types/models/UserModel.d.ts +7 -7
- package/types/models/UserModel.d.ts.map +1 -1
- package/types/rbac/Rbac.d.ts +1 -1
- package/types/rbac/Rbac.d.ts.map +1 -1
- package/types/repository/mongo/RoleMongoRepository.d.ts +9 -11
- package/types/repository/mongo/RoleMongoRepository.d.ts.map +1 -1
- package/types/repository/mongo/TenantMongoRepository.d.ts +8 -11
- package/types/repository/mongo/TenantMongoRepository.d.ts.map +1 -1
- package/types/repository/mongo/UserApiKeyMongoRepository.d.ts +12 -5
- package/types/repository/mongo/UserApiKeyMongoRepository.d.ts.map +1 -1
- package/types/repository/mongo/UserMongoRepository.d.ts +11 -12
- package/types/repository/mongo/UserMongoRepository.d.ts.map +1 -1
- package/types/repository/sqlite/RoleSqliteRepository.d.ts +14 -14
- package/types/repository/sqlite/RoleSqliteRepository.d.ts.map +1 -1
- package/types/repository/sqlite/TenantSqliteRepository.d.ts +12 -14
- package/types/repository/sqlite/TenantSqliteRepository.d.ts.map +1 -1
- package/types/repository/sqlite/UserApiKeySqliteRepository.d.ts +15 -11
- package/types/repository/sqlite/UserApiKeySqliteRepository.d.ts.map +1 -1
- package/types/repository/sqlite/UserSqliteRepository.d.ts +15 -12
- 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.map +1 -1
- package/types/routes/UserApiKeyRoutes.d.ts.map +1 -1
- package/types/routes/UserRoutes.d.ts.map +1 -1
- package/types/schemas/LoginSchema.d.ts +20 -0
- package/types/schemas/LoginSchema.d.ts.map +1 -0
- package/types/schemas/PasswordSchema.d.ts +27 -0
- package/types/schemas/PasswordSchema.d.ts.map +1 -0
- package/types/schemas/RegisterSchema.d.ts +32 -0
- package/types/schemas/RegisterSchema.d.ts.map +1 -0
- package/types/schemas/RoleSchema.d.ts +67 -0
- package/types/schemas/RoleSchema.d.ts.map +1 -0
- package/types/schemas/TenantSchema.d.ts +29 -0
- package/types/schemas/TenantSchema.d.ts.map +1 -0
- package/types/schemas/UserApiKeySchema.d.ts +39 -0
- package/types/schemas/UserApiKeySchema.d.ts.map +1 -0
- package/types/schemas/UserSchema.d.ts +161 -0
- package/types/schemas/UserSchema.d.ts.map +1 -0
- package/types/services/PermissionService.d.ts +1 -0
- package/types/services/PermissionService.d.ts.map +1 -1
- package/types/services/TenantService.d.ts +3 -3
- package/types/services/TenantService.d.ts.map +1 -1
- package/types/services/UserService.d.ts.map +1 -1
- package/types/setup/CreateOrUpdateRole.d.ts +2 -2
- package/types/setup/CreateOrUpdateRole.d.ts.map +1 -1
- package/types/setup/CreateUserIfNotExist.d.ts +2 -2
- package/types/setup/CreateUserIfNotExist.d.ts.map +1 -1
- package/types/zod/EndpointZod.d.ts +20 -0
- package/types/zod/EndpointZod.d.ts.map +1 -0
- package/types/zod/TenantSchema.d.ts +26 -0
- package/types/zod/TenantSchema.d.ts.map +1 -0
- package/types/zod/TenantZod.d.ts +13 -3
- package/types/zod/TenantZod.d.ts.map +1 -1
- package/types/zod/UserApiKeyZod.d.ts +23 -3
- package/types/zod/UserApiKeyZod.d.ts.map +1 -1
- package/types/zod/UserZod.d.ts +6 -6
- package/src/zod/RoleZod.ts +0 -14
- package/src/zod/TenantZod.ts +0 -14
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import {LoadPermissions,
|
|
2
|
+
UserPermissions, RolePermissions, TenantPermissions, UserApiKeyPermissions
|
|
3
|
+
} from "../../../src/index.js";
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
function InitializePermissions() {
|
|
7
|
+
|
|
8
|
+
//Merge All Permissions
|
|
9
|
+
const permissions = [
|
|
10
|
+
...Object.values(UserPermissions),
|
|
11
|
+
...Object.values(RolePermissions),
|
|
12
|
+
...Object.values(TenantPermissions),
|
|
13
|
+
...Object.values(UserApiKeyPermissions),
|
|
14
|
+
]
|
|
15
|
+
|
|
16
|
+
//Load All Permissions
|
|
17
|
+
LoadPermissions(permissions)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export default InitializePermissions
|
|
21
|
+
|
|
22
|
+
export {InitializePermissions}
|
|
23
|
+
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { LoadCommonConfigFromEnv} from "@drax/common-back";
|
|
2
|
+
import {LoadIdentityConfigFromEnv} from "@drax/identity-back";
|
|
3
|
+
import InitializePermissions from "./InitializePermissions.js";
|
|
4
|
+
import CreateRootUserAndAdminRole from "./CreateRootUserAndAdminRole.js";
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
async function SetupIdentityDrax(){
|
|
8
|
+
|
|
9
|
+
//Load Identity Drax Config from enviroment variables
|
|
10
|
+
LoadCommonConfigFromEnv()
|
|
11
|
+
LoadIdentityConfigFromEnv()
|
|
12
|
+
|
|
13
|
+
//Setup Permissions
|
|
14
|
+
InitializePermissions()
|
|
15
|
+
|
|
16
|
+
//Create Root User and Admin Role
|
|
17
|
+
return await CreateRootUserAndAdminRole()
|
|
18
|
+
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export default SetupIdentityDrax
|
|
22
|
+
export {SetupIdentityDrax}
|
|
@@ -0,0 +1,336 @@
|
|
|
1
|
+
import {describe, it, beforeAll, afterAll, expect} from "vitest"
|
|
2
|
+
import MongoInMemory from "../db/MongoInMemory";
|
|
3
|
+
import TenantRoute from "../../src/routes/TenantRoutes";
|
|
4
|
+
|
|
5
|
+
process.env.DRAX_DB_ENGINE = "mongo"
|
|
6
|
+
import TenantServiceFactory from "../../src/factory/TenantServiceFactory";
|
|
7
|
+
import {FastifyTestServerFactory} from './helpers/FastifyTestServerFactory'
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
describe("Tenant Route Test", function () {
|
|
11
|
+
|
|
12
|
+
let FastifyTestServer = FastifyTestServerFactory()
|
|
13
|
+
FastifyTestServer.register(TenantRoute)
|
|
14
|
+
|
|
15
|
+
beforeAll(async () => {
|
|
16
|
+
await MongoInMemory.connect()
|
|
17
|
+
console.log("BEFORE MOCK", MongoInMemory.mongooseStatus, MongoInMemory.serverStatus)
|
|
18
|
+
// const tenantService = TenantServiceFactory()
|
|
19
|
+
// await tenantService.create({name: "TestTenant"})
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
return
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
afterAll(async () => {
|
|
26
|
+
await MongoInMemory.DropAndClose()
|
|
27
|
+
console.log("AFTER MOCK", MongoInMemory.status, MongoInMemory.serverStatus)
|
|
28
|
+
return
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
it("Should paginate tenant", async () => {
|
|
33
|
+
// First, create a few tenants
|
|
34
|
+
const tenantData = [
|
|
35
|
+
{name: "Tenant1"},
|
|
36
|
+
{name: "Tenant2"},
|
|
37
|
+
{name: "Tenant3"}
|
|
38
|
+
];
|
|
39
|
+
|
|
40
|
+
for (const data of tenantData) {
|
|
41
|
+
await FastifyTestServer.inject({
|
|
42
|
+
method: 'POST',
|
|
43
|
+
url: '/api/tenants',
|
|
44
|
+
payload: data
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const resp = await FastifyTestServer.inject({
|
|
49
|
+
method: 'GET',
|
|
50
|
+
url: '/api/tenants',
|
|
51
|
+
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
const result = await resp.json()
|
|
55
|
+
expect(resp.statusCode).toBe(200)
|
|
56
|
+
expect(result.items.length).toBe(3)
|
|
57
|
+
expect(result.items[0].name).toBe("Tenant1")
|
|
58
|
+
expect(result.page).toBe(1)
|
|
59
|
+
expect(result.limit).toBe(10)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
it("should create a new tenant", async () => {
|
|
65
|
+
const newTenant = {
|
|
66
|
+
name: "NewTestTenant"
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
const resp = await FastifyTestServer.inject({
|
|
70
|
+
method: 'POST',
|
|
71
|
+
url: '/api/tenants',
|
|
72
|
+
payload: newTenant
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
const result = await resp.json();
|
|
76
|
+
expect(resp.statusCode).toBe(200);
|
|
77
|
+
expect(result.name).toBe("NewTestTenant");
|
|
78
|
+
expect(result._id).toBeDefined();
|
|
79
|
+
|
|
80
|
+
// Verify tenant was created by fetching it
|
|
81
|
+
const getResp = await FastifyTestServer.inject({
|
|
82
|
+
method: 'GET',
|
|
83
|
+
url: '/api/tenants/' + result.id
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
const getTenant = await getResp.json();
|
|
87
|
+
expect(getResp.statusCode).toBe(200);
|
|
88
|
+
expect(getTenant.name).toBe("NewTestTenant");
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
it("should update an existing tenant", async () => {
|
|
92
|
+
|
|
93
|
+
const newTenant = {
|
|
94
|
+
name: "ExistTenant"
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
const resp = await FastifyTestServer.inject({
|
|
98
|
+
method: 'POST',
|
|
99
|
+
url: '/api/tenants',
|
|
100
|
+
payload: newTenant
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
// First, get existing tenants to extract the id
|
|
104
|
+
const getResp = await FastifyTestServer.inject({
|
|
105
|
+
method: 'GET',
|
|
106
|
+
url: '/api/tenants',
|
|
107
|
+
})
|
|
108
|
+
|
|
109
|
+
const result = await getResp.json()
|
|
110
|
+
const tenantId = result.items[0].id
|
|
111
|
+
|
|
112
|
+
// Prepare update data
|
|
113
|
+
const updateData = {
|
|
114
|
+
name: "UpdatedTenantName"
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Send update request
|
|
118
|
+
const updateResp = await FastifyTestServer.inject({
|
|
119
|
+
method: 'PUT',
|
|
120
|
+
url: `/api/tenants/${tenantId}`,
|
|
121
|
+
payload: updateData
|
|
122
|
+
})
|
|
123
|
+
|
|
124
|
+
// Verify update response
|
|
125
|
+
expect(updateResp.statusCode).toBe(200)
|
|
126
|
+
const updatedTenant = await updateResp.json()
|
|
127
|
+
expect(updatedTenant.name).toBe("UpdatedTenantName")
|
|
128
|
+
|
|
129
|
+
// Verify the tenant was actually updated by fetching it again
|
|
130
|
+
const verifyResp = await FastifyTestServer.inject({
|
|
131
|
+
method: 'GET',
|
|
132
|
+
url: `/api/tenants/${tenantId}`,
|
|
133
|
+
})
|
|
134
|
+
|
|
135
|
+
const verifiedTenant = await verifyResp.json()
|
|
136
|
+
expect(verifyResp.statusCode).toBe(200)
|
|
137
|
+
expect(verifiedTenant.name).toBe("UpdatedTenantName")
|
|
138
|
+
|
|
139
|
+
// Send update inexistingId should return 404
|
|
140
|
+
const updateRespNotFound = await FastifyTestServer.inject({
|
|
141
|
+
method: 'PUT',
|
|
142
|
+
url: `/api/tenants/66761bed94d57a42c3277bab`,
|
|
143
|
+
payload: updateData
|
|
144
|
+
})
|
|
145
|
+
|
|
146
|
+
// Verify update response
|
|
147
|
+
expect(updateRespNotFound.statusCode).toBe(404)
|
|
148
|
+
|
|
149
|
+
})
|
|
150
|
+
|
|
151
|
+
it("should delete an existing tenant", async () => {
|
|
152
|
+
// First create a tenant to be deleted
|
|
153
|
+
const newTenant = {
|
|
154
|
+
name: "TenantToDelete"
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
const createResp = await FastifyTestServer.inject({
|
|
158
|
+
method: 'POST',
|
|
159
|
+
url: '/api/tenants',
|
|
160
|
+
payload: newTenant
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
const createdTenant = await createResp.json();
|
|
164
|
+
expect(createResp.statusCode).toBe(200);
|
|
165
|
+
const tenantId = createdTenant.id;
|
|
166
|
+
|
|
167
|
+
// Delete the tenant
|
|
168
|
+
const deleteResp = await FastifyTestServer.inject({
|
|
169
|
+
method: 'DELETE',
|
|
170
|
+
url: `/api/tenants/${tenantId}`
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
// Verify delete response
|
|
174
|
+
expect(deleteResp.statusCode).toBe(200);
|
|
175
|
+
const deleteResult = await deleteResp.json();
|
|
176
|
+
expect(deleteResult.deleted).toBe(true);
|
|
177
|
+
|
|
178
|
+
// Verify the tenant was actually deleted by trying to fetch it
|
|
179
|
+
const verifyResp = await FastifyTestServer.inject({
|
|
180
|
+
method: 'GET',
|
|
181
|
+
url: `/api/tenants/${tenantId}`
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
// Should return 404 or empty response
|
|
185
|
+
expect(verifyResp.statusCode).toBe(404);
|
|
186
|
+
})
|
|
187
|
+
|
|
188
|
+
it("should find a tenant by ID", async () => {
|
|
189
|
+
// First create a tenant to ensure we have one with known ID
|
|
190
|
+
const newTenant = {
|
|
191
|
+
name: "FindByIdTenant"
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
const createResp = await FastifyTestServer.inject({
|
|
195
|
+
method: 'POST',
|
|
196
|
+
url: '/api/tenants',
|
|
197
|
+
payload: newTenant
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
const createdTenant = await createResp.json();
|
|
201
|
+
expect(createResp.statusCode).toBe(200);
|
|
202
|
+
const tenantId = createdTenant.id;
|
|
203
|
+
|
|
204
|
+
// Now fetch the tenant by ID
|
|
205
|
+
const getResp = await FastifyTestServer.inject({
|
|
206
|
+
method: 'GET',
|
|
207
|
+
url: `/api/tenants/${tenantId}`
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
// Verify the response
|
|
211
|
+
expect(getResp.statusCode).toBe(200);
|
|
212
|
+
const fetchedTenant = await getResp.json();
|
|
213
|
+
expect(fetchedTenant._id).toBe(tenantId);
|
|
214
|
+
expect(fetchedTenant.name).toBe("FindByIdTenant");
|
|
215
|
+
})
|
|
216
|
+
|
|
217
|
+
it("should search for tenants ", async () => {
|
|
218
|
+
// First, create a few tenants for search testing
|
|
219
|
+
const tenantData = [
|
|
220
|
+
{name: "SearchTenant1"},
|
|
221
|
+
{name: "SearchTenant2"},
|
|
222
|
+
{name: "DifferentTenant"}
|
|
223
|
+
];
|
|
224
|
+
|
|
225
|
+
// Create the test tenants
|
|
226
|
+
for (const data of tenantData) {
|
|
227
|
+
await FastifyTestServer.inject({
|
|
228
|
+
method: 'POST',
|
|
229
|
+
url: '/api/tenants',
|
|
230
|
+
payload: data
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// Test searching with a matching term
|
|
235
|
+
const searchResp = await FastifyTestServer.inject({
|
|
236
|
+
method: 'GET',
|
|
237
|
+
url: '/api/tenants/search?search=Search',
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
const searchResult = await searchResp.json();
|
|
241
|
+
console.log("searchResult",searchResult)
|
|
242
|
+
|
|
243
|
+
expect(searchResp.statusCode).toBe(200);
|
|
244
|
+
expect(searchResult.length).toBe(2); // Should find the two tenants with "Search" in their name
|
|
245
|
+
expect(searchResult.some(tenant => tenant.name === "SearchTenant1")).toBe(true);
|
|
246
|
+
expect(searchResult.some(tenant => tenant.name === "SearchTenant2")).toBe(true);
|
|
247
|
+
expect(searchResult.some(tenant => tenant.name === "DifferentTenant")).toBe(false);
|
|
248
|
+
|
|
249
|
+
})
|
|
250
|
+
|
|
251
|
+
it("Should get all tenants", async () => {
|
|
252
|
+
// First, create a few tenants
|
|
253
|
+
const tenantData = [
|
|
254
|
+
{name: "SearchTenant1"},
|
|
255
|
+
{name: "SearchTenant2"},
|
|
256
|
+
{name: "SearchTenant3"}
|
|
257
|
+
];
|
|
258
|
+
|
|
259
|
+
for (const data of tenantData) {
|
|
260
|
+
await FastifyTestServer.inject({
|
|
261
|
+
method: 'POST',
|
|
262
|
+
url: '/api/tenants',
|
|
263
|
+
payload: data
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// Get all tenants
|
|
268
|
+
const resp = await FastifyTestServer.inject({
|
|
269
|
+
method: 'GET',
|
|
270
|
+
url: '/api/tenants/all',
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
const result = await resp.json();
|
|
274
|
+
console.log("result",result)
|
|
275
|
+
|
|
276
|
+
expect(resp.statusCode).toBe(200);
|
|
277
|
+
|
|
278
|
+
// Should be an array with at least 2 tenants
|
|
279
|
+
expect(Array.isArray(result)).toBe(true);
|
|
280
|
+
expect(result.length).toBeGreaterThanOrEqual(3);
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
})
|
|
284
|
+
|
|
285
|
+
it("should find tenants by specific field-value pair", async () => {
|
|
286
|
+
// First create tenants with specific field values for testing
|
|
287
|
+
const tenantData = [
|
|
288
|
+
{name: "FieldTenantA"},
|
|
289
|
+
{name: "FieldTenantB"},
|
|
290
|
+
{name: "ASD"}
|
|
291
|
+
];
|
|
292
|
+
|
|
293
|
+
// Create the test tenants
|
|
294
|
+
for (const data of tenantData) {
|
|
295
|
+
await FastifyTestServer.inject({
|
|
296
|
+
method: 'POST',
|
|
297
|
+
url: '/api/tenants',
|
|
298
|
+
payload: data
|
|
299
|
+
});
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
// Test finding by description field with value "Special"
|
|
303
|
+
const findByResp = await FastifyTestServer.inject({
|
|
304
|
+
method: 'GET',
|
|
305
|
+
url: '/api/tenants/find-by/name/FieldTenantA',
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
const findByResult = await findByResp.json();
|
|
309
|
+
expect(findByResp.statusCode).toBe(200);
|
|
310
|
+
expect(Array.isArray(findByResult)).toBe(true);
|
|
311
|
+
expect(findByResult.length).toBe(1); // Should find the two tenants with "Special" description
|
|
312
|
+
expect(findByResult.some(tenant => tenant.name === "FieldTenantA")).toBe(true);
|
|
313
|
+
expect(findByResult.some(tenant => tenant.name === "FieldTenantB")).toBe(false);
|
|
314
|
+
expect(findByResult.some(tenant => tenant.name === "FieldTenantC")).toBe(false);
|
|
315
|
+
})
|
|
316
|
+
|
|
317
|
+
it("should handle error responses correctly when tenant is not found", async () => {
|
|
318
|
+
// Try to fetch a non-existent tenant
|
|
319
|
+
const nonExistentId = "123456789012345678901234"; // Valid MongoDB ObjectId that doesn't exist
|
|
320
|
+
|
|
321
|
+
const resp = await FastifyTestServer.inject({
|
|
322
|
+
method: 'GET',
|
|
323
|
+
url: `/api/tenants/${nonExistentId}`
|
|
324
|
+
});
|
|
325
|
+
|
|
326
|
+
// Verify response status code should be 404 Not Found
|
|
327
|
+
expect(resp.statusCode).toBe(404);
|
|
328
|
+
|
|
329
|
+
const result = await resp.json();
|
|
330
|
+
expect(result.error).toBeDefined();
|
|
331
|
+
expect(result.message).toContain("Not found");
|
|
332
|
+
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
|
|
336
|
+
})
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import {describe, it, beforeAll, afterAll, expect} from "vitest"
|
|
2
|
+
import MongoInMemory from "../db/MongoInMemory";
|
|
3
|
+
|
|
4
|
+
process.env.DRAX_DB_ENGINE = "mongo"
|
|
5
|
+
process.env.DRAX_JWT_SECRET = "asdasdasd"
|
|
6
|
+
|
|
7
|
+
// import {InitializePermissions} from "./helpers/InitializePermissions.js"
|
|
8
|
+
// import {CreateRootUserAndAdminRole} from "./helpers/CreateRootUserAndAdminRole.js"
|
|
9
|
+
import {SetupIdentityDrax} from "./helpers/SetupIdentityDrax.js"
|
|
10
|
+
import {FastifyTestServerFactory} from './helpers/FastifyTestServerFactory.js'
|
|
11
|
+
import {IRoleBase, IUserCreate} from "@drax/identity-share";
|
|
12
|
+
import {UserRoutes, RoleServiceFactory, UserServiceFactory, PermissionService} from "../../src/index.js"
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
const USER1: IUserCreate = {
|
|
16
|
+
active: true,
|
|
17
|
+
password: "12345678",
|
|
18
|
+
phone: "",
|
|
19
|
+
role: "",
|
|
20
|
+
name: "John Wick",
|
|
21
|
+
username: "johnwick",
|
|
22
|
+
email: "johnwick@example.com"
|
|
23
|
+
}
|
|
24
|
+
const USER2: IUserCreate = {
|
|
25
|
+
active: true,
|
|
26
|
+
password: "12345678",
|
|
27
|
+
phone: "",
|
|
28
|
+
role: "",
|
|
29
|
+
name: "John Rambo",
|
|
30
|
+
username: "rambo",
|
|
31
|
+
email: "rambo@example.com"
|
|
32
|
+
}
|
|
33
|
+
const USER3: IUserCreate = {
|
|
34
|
+
active: true,
|
|
35
|
+
password: "12345678",
|
|
36
|
+
phone: "",
|
|
37
|
+
role: "",
|
|
38
|
+
name: "John Depp",
|
|
39
|
+
username: "depp",
|
|
40
|
+
email: "depp@example.com"
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
describe("User Route Test", async function () {
|
|
44
|
+
|
|
45
|
+
let FastifyTestServer;
|
|
46
|
+
let adminUser, roleAdmin
|
|
47
|
+
let accessToken;
|
|
48
|
+
|
|
49
|
+
async function login() {
|
|
50
|
+
const resp = await FastifyTestServer.inject({
|
|
51
|
+
method: 'POST',
|
|
52
|
+
url: '/api/auth/login',
|
|
53
|
+
payload: {username: 'root', password: "root.123"}
|
|
54
|
+
});
|
|
55
|
+
console.log("login", resp.statusCode)
|
|
56
|
+
let body = resp.json()
|
|
57
|
+
accessToken = body.accessToken;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
beforeAll(async () => {
|
|
61
|
+
await MongoInMemory.connect()
|
|
62
|
+
// console.log("BEFORE MOCK", MongoInMemory.mongooseStatus, MongoInMemory.serverStatus)
|
|
63
|
+
let {user, role} = await SetupIdentityDrax()
|
|
64
|
+
adminUser = user
|
|
65
|
+
roleAdmin = role
|
|
66
|
+
FastifyTestServer = FastifyTestServerFactory()
|
|
67
|
+
FastifyTestServer.register(UserRoutes)
|
|
68
|
+
await login()
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
afterAll(async () => {
|
|
72
|
+
await MongoInMemory.DropAndClose()
|
|
73
|
+
// console.log("AFTER MOCK", MongoInMemory.status, MongoInMemory.serverStatus)
|
|
74
|
+
return
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
it("Me", async () => {
|
|
78
|
+
// console.log("user", adminUser)
|
|
79
|
+
// console.log("role", roleAdmin)
|
|
80
|
+
// console.log("accessToken", accessToken)
|
|
81
|
+
|
|
82
|
+
const resp = await FastifyTestServer.inject({
|
|
83
|
+
method: 'get',
|
|
84
|
+
url: '/api/auth/me',
|
|
85
|
+
headers: {Authorization: `Bearer ${accessToken}`}
|
|
86
|
+
});
|
|
87
|
+
let body = resp.json()
|
|
88
|
+
console.log("me", body)
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
it("should create a new user", async () => {
|
|
93
|
+
|
|
94
|
+
const resp = await FastifyTestServer.inject({
|
|
95
|
+
method: 'POST',
|
|
96
|
+
url: '/api/users',
|
|
97
|
+
payload: {...USER1, ...{role: roleAdmin._id}},
|
|
98
|
+
headers: {Authorization: `Bearer ${accessToken}`}
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
const result = await resp.json();
|
|
102
|
+
expect(resp.statusCode).toBe(200);
|
|
103
|
+
expect(result.name).toBe(USER1.name);
|
|
104
|
+
expect(result._id).toBeDefined();
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
// Verify tenant was created by fetching it
|
|
108
|
+
const getResp = await FastifyTestServer.inject({
|
|
109
|
+
method: 'GET',
|
|
110
|
+
url: '/api/users/search?search=' + result._id,
|
|
111
|
+
headers: {Authorization: `Bearer ${accessToken}`}
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
const items = await getResp.json();
|
|
115
|
+
expect(getResp.statusCode).toBe(200);
|
|
116
|
+
expect(items[0].name).toBe(USER1.name);
|
|
117
|
+
})
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
it("Should paginate user", async () => {
|
|
121
|
+
// First, create a few Users
|
|
122
|
+
const users = [
|
|
123
|
+
USER1, USER2, USER3
|
|
124
|
+
];
|
|
125
|
+
|
|
126
|
+
for (const data of users) {
|
|
127
|
+
await FastifyTestServer.inject({
|
|
128
|
+
method: 'POST',
|
|
129
|
+
url: '/api/users',
|
|
130
|
+
payload: {...data, ...{role: roleAdmin._id.toString()}},
|
|
131
|
+
headers: {Authorization: `Bearer ${accessToken}`}
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const resp = await FastifyTestServer.inject({
|
|
136
|
+
method: 'GET',
|
|
137
|
+
url: '/api/users',
|
|
138
|
+
headers: {Authorization: `Bearer ${accessToken}`}
|
|
139
|
+
})
|
|
140
|
+
|
|
141
|
+
const result = await resp.json()
|
|
142
|
+
expect(resp.statusCode).toBe(200)
|
|
143
|
+
expect(result.items.length).toBe(4)
|
|
144
|
+
expect(result.items[0].name).toBe(adminUser.name)
|
|
145
|
+
expect(result.page).toBe(1)
|
|
146
|
+
expect(result.limit).toBe(10)
|
|
147
|
+
expect(result.total).toBe(4)
|
|
148
|
+
|
|
149
|
+
})
|
|
150
|
+
|
|
151
|
+
it("should change my password", async () => {
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
const respPassword = await FastifyTestServer.inject({
|
|
155
|
+
method: 'POST',
|
|
156
|
+
url: '/api/users/password/change',
|
|
157
|
+
payload: {currentPassword: "root.123", newPassword: "newpass"},
|
|
158
|
+
headers: {Authorization: `Bearer ${accessToken}`}
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
const resultPassword = await respPassword.json();
|
|
162
|
+
expect(respPassword.statusCode).toBe(200);
|
|
163
|
+
|
|
164
|
+
console.log("resultPassword", resultPassword)
|
|
165
|
+
|
|
166
|
+
})
|
|
167
|
+
|
|
168
|
+
it("should change password", async () => {
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
const respPassword = await FastifyTestServer.inject({
|
|
172
|
+
method: 'POST',
|
|
173
|
+
url: '/api/users/password/change/'+adminUser._id,
|
|
174
|
+
payload: {currentPassword: "root.123", newPassword: "newpass"},
|
|
175
|
+
headers: {Authorization: `Bearer ${accessToken}`}
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
const resultPassword = await respPassword.json();
|
|
179
|
+
expect(respPassword.statusCode).toBe(200);
|
|
180
|
+
|
|
181
|
+
console.log("resultPassword", resultPassword)
|
|
182
|
+
|
|
183
|
+
})
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
})
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import {describe, it, beforeAll, afterAll} from "vitest"
|
|
2
|
+
import {MongooseConector} from "@drax/common-back";
|
|
3
|
+
import {UserSchema} from "../../src/schemas/UserSchema";
|
|
4
|
+
import { zodToJsonSchema } from 'zod-to-json-schema';
|
|
5
|
+
import TenantServiceFactory from "../../src/factory/TenantServiceFactory";
|
|
6
|
+
import UserServiceFactory from "../../src/factory/UserServiceFactory";
|
|
7
|
+
import fastJson from "fast-json-stringify"
|
|
8
|
+
import z from "zod"
|
|
9
|
+
import {TenantModel, TenantMongoSchema} from "../../src/models/TenantModel";
|
|
10
|
+
|
|
11
|
+
process.env.DRAX_DB_ENGINE = "mongo"
|
|
12
|
+
let mongooseUri = "mongodb://127.0.0.1:27017/drax"
|
|
13
|
+
const mongooseConector = new MongooseConector(mongooseUri)
|
|
14
|
+
|
|
15
|
+
const tenantService = TenantServiceFactory()
|
|
16
|
+
const userService = UserServiceFactory()
|
|
17
|
+
|
|
18
|
+
describe("Test Schema", function () {
|
|
19
|
+
|
|
20
|
+
beforeAll(async () => {
|
|
21
|
+
|
|
22
|
+
await mongooseConector.connect()
|
|
23
|
+
return
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
afterAll(async () => {
|
|
27
|
+
await mongooseConector.disconnect()
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
it("Lab Schema", async () => {
|
|
31
|
+
|
|
32
|
+
const zSchema = z.object({
|
|
33
|
+
name: z.string(),
|
|
34
|
+
tenant: z.object({
|
|
35
|
+
_id: z.string(),
|
|
36
|
+
name: z.string()
|
|
37
|
+
}).optional().nullable()
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
let jsonSchema = zodToJsonSchema(zSchema,{target:'openApi3'})
|
|
41
|
+
console.log("jsonUserSchema", JSON.stringify(jsonSchema, null,4))
|
|
42
|
+
|
|
43
|
+
let row1 = {
|
|
44
|
+
name: "mock-tenant",
|
|
45
|
+
lastname:"mock-lastname",
|
|
46
|
+
tenant: {
|
|
47
|
+
_id: "667618bfcd0dd6f880b90d82",
|
|
48
|
+
name: "mock-tenant"
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
let row2 = {
|
|
53
|
+
name: "mock-tenant",
|
|
54
|
+
lastname:"mock-lastname",
|
|
55
|
+
tenant: {
|
|
56
|
+
_id: "667618bfcd0dd6f880b90d82",
|
|
57
|
+
name: "mock-tenant",
|
|
58
|
+
createdAt: new Date(),
|
|
59
|
+
updatedAt: new Date()
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
let row3 = {
|
|
64
|
+
name: "mock-tenant",
|
|
65
|
+
lastname:"mock-lastname",
|
|
66
|
+
tenant: null
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
let row4 = {
|
|
70
|
+
name: "mock-tenant",
|
|
71
|
+
lastname:"mock-lastname",
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
//@ts-ignore
|
|
77
|
+
const stringify = fastJson(jsonSchema )
|
|
78
|
+
|
|
79
|
+
const r1 = stringify(row1)
|
|
80
|
+
console.log("r1",r1)
|
|
81
|
+
const r2 = stringify(row2)
|
|
82
|
+
console.log("r2",r2)
|
|
83
|
+
const r3 = stringify(row3)
|
|
84
|
+
console.log("r3",r3)
|
|
85
|
+
const r4 = stringify(row4)
|
|
86
|
+
console.log("r4",r4)
|
|
87
|
+
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
it("should create MOCK", async () => {
|
|
92
|
+
console.log("should create mock")
|
|
93
|
+
|
|
94
|
+
let jsonUserSchema = zodToJsonSchema(UserSchema)
|
|
95
|
+
console.log("jsonUserSchema", JSON.stringify(jsonUserSchema, null,4))
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
let user = await userService.search('667618bfcd0dd6f880b90d82')
|
|
101
|
+
console.log("user",user)
|
|
102
|
+
|
|
103
|
+
//@ts-ignore
|
|
104
|
+
const stringify = fastJson(jsonUserSchema)
|
|
105
|
+
let ruser = stringify(user[0])
|
|
106
|
+
|
|
107
|
+
console.log("ruser",ruser)
|
|
108
|
+
|
|
109
|
+
})
|
|
110
|
+
})
|
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
import {describe, it,
|
|
1
|
+
import {describe, it, beforeAll, afterAll} from "vitest"
|
|
2
2
|
import MongoInMemory from "../db/MongoInMemory";
|
|
3
3
|
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
describe("MockTest", function () {
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
beforeAll(async () => {
|
|
9
9
|
await MongoInMemory.connect()
|
|
10
10
|
console.log("BEFORE MOCK", MongoInMemory.mongooseStatus, MongoInMemory.serverStatus)
|
|
11
11
|
return
|
|
12
12
|
})
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
afterAll(async () => {
|
|
15
15
|
await MongoInMemory.DropAndClose()
|
|
16
16
|
console.log("AFTER MOCK", MongoInMemory.status, MongoInMemory.serverStatus)
|
|
17
17
|
return
|