@flowerforce/flowerbase 1.0.1-beta.8 → 1.0.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/CHANGELOG.md +17 -0
- package/LICENSE +1 -1
- package/README.md +466 -7
- package/dist/auth/controller.d.ts.map +1 -1
- package/dist/auth/controller.js +11 -1
- package/dist/auth/providers/local-userpass/controller.d.ts.map +1 -1
- package/dist/auth/providers/local-userpass/controller.js +15 -15
- package/dist/auth/utils.d.ts +2 -1
- package/dist/auth/utils.d.ts.map +1 -1
- package/dist/auth/utils.js +14 -10
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +3 -3
- package/dist/features/endpoints/utils.d.ts +1 -1
- package/dist/features/endpoints/utils.d.ts.map +1 -1
- package/dist/features/endpoints/utils.js +5 -2
- package/dist/features/functions/controller.d.ts.map +1 -1
- package/dist/features/functions/controller.js +12 -8
- package/dist/features/functions/dtos.d.ts +2 -1
- package/dist/features/functions/dtos.d.ts.map +1 -1
- package/dist/features/functions/interface.d.ts +2 -1
- package/dist/features/functions/interface.d.ts.map +1 -1
- package/dist/features/functions/utils.d.ts +1 -1
- package/dist/features/functions/utils.d.ts.map +1 -1
- package/dist/features/functions/utils.js +4 -4
- package/dist/features/triggers/index.d.ts.map +1 -1
- package/dist/features/triggers/index.js +9 -3
- package/dist/features/triggers/interface.d.ts +4 -4
- package/dist/features/triggers/interface.d.ts.map +1 -1
- package/dist/features/triggers/utils.d.ts.map +1 -1
- package/dist/features/triggers/utils.js +25 -14
- package/dist/global.d.ts +9 -0
- package/dist/global.d.ts.map +1 -0
- package/dist/global.js +2 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +13 -9
- package/dist/model.d.ts +1 -0
- package/dist/model.d.ts.map +1 -1
- package/dist/model.js +15 -0
- package/dist/services/api/index.d.ts.map +1 -1
- package/dist/services/api/index.js +6 -1
- package/dist/services/aws/index.d.ts.map +1 -1
- package/dist/services/aws/index.js +5 -5
- package/dist/services/index.d.ts.map +1 -1
- package/dist/services/mongodb-atlas/index.d.ts.map +1 -1
- package/dist/services/mongodb-atlas/index.js +76 -71
- package/dist/services/mongodb-atlas/model.d.ts +3 -3
- package/dist/services/mongodb-atlas/model.d.ts.map +1 -1
- package/dist/services/mongodb-atlas/utils.d.ts.map +1 -1
- package/dist/state.d.ts +2 -2
- package/dist/state.d.ts.map +1 -1
- package/dist/utils/context/helpers.d.ts +4 -4
- package/dist/utils/context/helpers.d.ts.map +1 -1
- package/dist/utils/context/helpers.js +1 -1
- package/dist/utils/context/index.d.ts.map +1 -1
- package/dist/utils/context/index.js +6 -5
- package/dist/utils/helpers/someAsync.d.ts.map +1 -1
- package/dist/utils/initializer/exposeRoutes.d.ts.map +1 -1
- package/dist/utils/initializer/exposeRoutes.js +44 -1
- package/dist/utils/initializer/registerPlugins.d.ts.map +1 -1
- package/dist/utils/initializer/registerPlugins.js +9 -9
- package/dist/utils/roles/helpers.d.ts.map +1 -1
- package/dist/utils/roles/helpers.js +9 -7
- package/dist/utils/roles/interface.d.ts.map +1 -1
- package/dist/utils/roles/machines/commonValidators.d.ts +2 -2
- package/dist/utils/roles/machines/commonValidators.d.ts.map +1 -1
- package/dist/utils/roles/machines/commonValidators.js +5 -6
- package/dist/utils/roles/machines/index.d.ts.map +1 -1
- package/dist/utils/roles/machines/interface.d.ts.map +1 -1
- package/dist/utils/roles/machines/machine.d.ts +3 -3
- package/dist/utils/roles/machines/machine.d.ts.map +1 -1
- package/dist/utils/roles/machines/machine.js +12 -4
- package/dist/utils/roles/machines/read/A/index.d.ts.map +1 -1
- package/dist/utils/roles/machines/read/A/index.js +12 -2
- package/dist/utils/roles/machines/read/B/index.d.ts.map +1 -1
- package/dist/utils/roles/machines/read/B/index.js +20 -5
- package/dist/utils/roles/machines/read/C/index.d.ts.map +1 -1
- package/dist/utils/roles/machines/read/C/index.js +20 -5
- package/dist/utils/roles/machines/read/D/index.d.ts.map +1 -1
- package/dist/utils/roles/machines/read/D/index.js +13 -3
- package/dist/utils/roles/machines/read/D/validators.d.ts +1 -1
- package/dist/utils/roles/machines/read/D/validators.d.ts.map +1 -1
- package/dist/utils/roles/machines/read/D/validators.js +8 -4
- package/dist/utils/roles/machines/utils.d.ts +4 -4
- package/dist/utils/roles/machines/utils.d.ts.map +1 -1
- package/dist/utils/roles/machines/utils.js +5 -1
- package/dist/utils/roles/machines/write/A/index.d.ts.map +1 -1
- package/dist/utils/roles/machines/write/A/index.js +13 -3
- package/dist/utils/roles/machines/write/B/index.d.ts.map +1 -1
- package/dist/utils/roles/machines/write/B/index.js +37 -10
- package/dist/utils/roles/machines/write/C/index.d.ts.map +1 -1
- package/dist/utils/roles/machines/write/C/index.js +13 -3
- package/dist/utils/roles/machines/write/C/validators.d.ts +1 -1
- package/dist/utils/roles/machines/write/C/validators.d.ts.map +1 -1
- package/dist/utils/roles/machines/write/C/validators.js +8 -4
- package/dist/utils/rules-matcher/interface.d.ts.map +1 -1
- package/dist/utils/rules-matcher/utils.d.ts.map +1 -1
- package/dist/utils/rules.d.ts.map +1 -1
- package/package.json +9 -2
- package/src/auth/controller.ts +12 -1
- package/src/auth/providers/local-userpass/controller.ts +47 -39
- package/src/auth/providers/local-userpass/dtos.ts +1 -1
- package/src/auth/utils.ts +24 -18
- package/src/constants.ts +7 -3
- package/src/features/endpoints/utils.ts +6 -4
- package/src/features/functions/controller.ts +23 -22
- package/src/features/functions/dtos.ts +9 -9
- package/src/features/functions/interface.ts +2 -1
- package/src/features/functions/utils.ts +12 -12
- package/src/features/triggers/index.ts +9 -6
- package/src/features/triggers/interface.ts +9 -10
- package/src/features/triggers/utils.ts +57 -29
- package/src/global.ts +9 -0
- package/src/index.ts +16 -11
- package/src/model.ts +3 -1
- package/src/services/api/index.ts +6 -1
- package/src/services/aws/index.ts +19 -17
- package/src/services/mongodb-atlas/index.ts +204 -163
- package/src/services/mongodb-atlas/model.ts +13 -13
- package/src/services/mongodb-atlas/utils.ts +6 -4
- package/src/state.ts +32 -20
- package/src/utils/__tests__/STEP_A_STATES.test.ts +78 -47
- package/src/utils/__tests__/STEP_B_STATES.test.ts +168 -105
- package/src/utils/__tests__/STEP_C_STATES.test.ts +150 -78
- package/src/utils/__tests__/STEP_D_STATES.test.ts +129 -86
- package/src/utils/__tests__/checkAdditionalFieldsFn.test.ts +35 -35
- package/src/utils/__tests__/checkApplyWhen.test.ts +40 -41
- package/src/utils/__tests__/checkFieldsPropertyExists.test.ts +40 -40
- package/src/utils/__tests__/checkIsValidFieldNameFn.test.ts +185 -184
- package/src/utils/__tests__/comparePassword.test.ts +27 -30
- package/src/utils/__tests__/evaluateDocumentsFiltersReadFn.test.ts +55 -47
- package/src/utils/__tests__/evaluateDocumentsFiltersWriteFn.test.ts +61 -47
- package/src/utils/__tests__/evaluateTopLevelReadFn.test.ts +48 -48
- package/src/utils/__tests__/evaluateTopLevelWriteFn.test.ts +56 -56
- package/src/utils/__tests__/exposeRoutes.test.ts +46 -44
- package/src/utils/__tests__/generateContextData.test.ts +57 -51
- package/src/utils/__tests__/getDefaultRule.test.ts +32 -27
- package/src/utils/__tests__/getKey.test.ts +10 -10
- package/src/utils/__tests__/getKeys.test.ts +10 -9
- package/src/utils/__tests__/getWinningRole.test.ts +57 -50
- package/src/utils/__tests__/hashPassword.test.ts +24 -25
- package/src/utils/__tests__/isEmpty.test.ts +14 -15
- package/src/utils/__tests__/logMachineInfo.test.ts +12 -12
- package/src/utils/__tests__/operators.test.ts +94 -96
- package/src/utils/__tests__/readFileContent.test.ts +28 -28
- package/src/utils/__tests__/registerPlugins.test.ts +44 -32
- package/src/utils/__tests__/rule.test.ts +47 -49
- package/src/utils/__tests__/rulesMatcherInterfaces.test.ts +57 -52
- package/src/utils/__tests__/rulesMatcherUtils.test.ts +64 -53
- package/src/utils/__tests__/someAsync.test.ts +46 -49
- package/src/utils/context/helpers.ts +1 -1
- package/src/utils/context/index.ts +9 -10
- package/src/utils/crypto/index.ts +2 -2
- package/src/utils/helpers/someAsync.ts +11 -11
- package/src/utils/initializer/exposeRoutes.ts +56 -2
- package/src/utils/initializer/registerPlugins.ts +11 -13
- package/src/utils/roles/helpers.ts +22 -15
- package/src/utils/roles/interface.ts +2 -3
- package/src/utils/roles/machines/commonValidators.ts +23 -14
- package/src/utils/roles/machines/index.ts +7 -4
- package/src/utils/roles/machines/interface.ts +17 -5
- package/src/utils/roles/machines/machine.ts +97 -72
- package/src/utils/roles/machines/read/A/index.ts +12 -4
- package/src/utils/roles/machines/read/B/index.ts +20 -7
- package/src/utils/roles/machines/read/C/index.ts +24 -8
- package/src/utils/roles/machines/read/D/index.ts +14 -8
- package/src/utils/roles/machines/read/D/validators.ts +21 -13
- package/src/utils/roles/machines/read/index.ts +5 -5
- package/src/utils/roles/machines/utils.ts +30 -13
- package/src/utils/roles/machines/write/A/index.ts +13 -5
- package/src/utils/roles/machines/write/B/index.ts +42 -16
- package/src/utils/roles/machines/write/C/index.ts +14 -8
- package/src/utils/roles/machines/write/C/validators.ts +21 -13
- package/src/utils/roles/machines/write/index.ts +4 -4
- package/src/utils/rules-matcher/interface.ts +4 -4
- package/src/utils/rules-matcher/utils.ts +10 -6
- package/src/utils/rules.ts +12 -5
- package/src/global.d.ts +0 -0
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { uptime } from 'node:process'
|
|
2
2
|
import { FastifyInstance } from 'fastify'
|
|
3
|
-
import {
|
|
3
|
+
import { RegistrationDto } from '../../auth/providers/local-userpass/dtos'
|
|
4
|
+
import { AUTH_ENDPOINTS, PROVIDER_TYPE, REGISTRATION_SCHEMA } from '../../auth/utils'
|
|
5
|
+
import { API_VERSION, AUTH_CONFIG, DB_NAME, DEFAULT_CONFIG } from '../../constants'
|
|
6
|
+
import { hashPassword } from '../crypto'
|
|
4
7
|
|
|
5
8
|
/**
|
|
6
9
|
* > Used to expose all app routes
|
|
@@ -13,14 +16,65 @@ export const exposeRoutes = async (fastify: FastifyInstance) => {
|
|
|
13
16
|
deployment_model: 'LOCAL',
|
|
14
17
|
location: 'IE',
|
|
15
18
|
hostname: `${DEFAULT_CONFIG.HTTPS_SCHEMA}://${req.headers.host}`,
|
|
16
|
-
ws_hostname: `${DEFAULT_CONFIG.HTTPS_SCHEMA ===
|
|
19
|
+
ws_hostname: `${DEFAULT_CONFIG.HTTPS_SCHEMA === 'https' ? 'wss' : 'ws'}://${req.headers.host}`
|
|
17
20
|
}))
|
|
18
21
|
|
|
19
22
|
fastify.get('/health', async () => ({
|
|
20
23
|
status: 'ok',
|
|
21
24
|
uptime: uptime()
|
|
22
25
|
}))
|
|
26
|
+
|
|
27
|
+
fastify.post<RegistrationDto>(AUTH_ENDPOINTS.FIRST_USER, {
|
|
28
|
+
schema: REGISTRATION_SCHEMA
|
|
29
|
+
}, async function (req, res) {
|
|
30
|
+
const { authCollection } = AUTH_CONFIG
|
|
31
|
+
const db = fastify.mongo.client.db(DB_NAME)
|
|
32
|
+
const { email, password } = req.body
|
|
33
|
+
const hashedPassword = await hashPassword(password)
|
|
34
|
+
|
|
35
|
+
const users = db.collection(authCollection!).find()
|
|
36
|
+
|
|
37
|
+
const list = await users?.toArray()
|
|
38
|
+
|
|
39
|
+
if (list?.length) {
|
|
40
|
+
res.status(409)
|
|
41
|
+
return {
|
|
42
|
+
error: `The ${authCollection} collection is not empty`
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const result = await db.collection(authCollection!).insertOne({
|
|
47
|
+
email: email,
|
|
48
|
+
password: hashedPassword,
|
|
49
|
+
custom_data: {}
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
await db?.collection(authCollection!).updateOne(
|
|
53
|
+
{
|
|
54
|
+
email: email
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
$set: {
|
|
58
|
+
identities: [
|
|
59
|
+
{
|
|
60
|
+
id: result?.insertedId.toString(),
|
|
61
|
+
provider_id: result?.insertedId.toString(),
|
|
62
|
+
provider_type: PROVIDER_TYPE,
|
|
63
|
+
provider_data: { email }
|
|
64
|
+
}
|
|
65
|
+
]
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
res.status(201)
|
|
71
|
+
return {
|
|
72
|
+
userId: result?.insertedId
|
|
73
|
+
}
|
|
74
|
+
})
|
|
23
75
|
} catch (e) {
|
|
24
76
|
console.error('Error while exposing routes', (e as Error).message)
|
|
25
77
|
}
|
|
26
78
|
}
|
|
79
|
+
|
|
80
|
+
|
|
@@ -46,13 +46,11 @@ export const registerPlugins = async ({
|
|
|
46
46
|
registersConfig.forEach(({ plugin, options, pluginName }) => {
|
|
47
47
|
try {
|
|
48
48
|
register(plugin, options)
|
|
49
|
-
console.log(
|
|
49
|
+
console.log('registration COMPLETED --->', pluginName)
|
|
50
|
+
} catch (e) {
|
|
51
|
+
console.log('Registration FAILED --->', pluginName)
|
|
52
|
+
console.log('Error --->', e)
|
|
50
53
|
}
|
|
51
|
-
catch (e) {
|
|
52
|
-
console.log("Registration FAILED --->", pluginName)
|
|
53
|
-
console.log("Error --->", e)
|
|
54
|
-
}
|
|
55
|
-
|
|
56
54
|
})
|
|
57
55
|
} catch (e) {
|
|
58
56
|
console.error('Error while registering plugins', (e as Error).message)
|
|
@@ -63,7 +61,7 @@ export const registerPlugins = async ({
|
|
|
63
61
|
* > Used to generate the register congig
|
|
64
62
|
* @param mongodbUrl -> the database connection string
|
|
65
63
|
* @param jwtSecret -> connection jwt
|
|
66
|
-
* @testable
|
|
64
|
+
* @testable
|
|
67
65
|
*/
|
|
68
66
|
const getRegisterConfig = async ({
|
|
69
67
|
mongodbUrl,
|
|
@@ -73,15 +71,15 @@ const getRegisterConfig = async ({
|
|
|
73
71
|
> => {
|
|
74
72
|
return [
|
|
75
73
|
{
|
|
76
|
-
pluginName:
|
|
74
|
+
pluginName: 'cors',
|
|
77
75
|
plugin: cors,
|
|
78
76
|
options: {
|
|
79
77
|
origin: '*',
|
|
80
|
-
methods: ['POST', 'GET']
|
|
78
|
+
methods: ['POST', 'GET', 'DELETE']
|
|
81
79
|
}
|
|
82
80
|
},
|
|
83
81
|
{
|
|
84
|
-
pluginName:
|
|
82
|
+
pluginName: 'fastifyMongodb',
|
|
85
83
|
plugin: fastifyMongodb,
|
|
86
84
|
options: {
|
|
87
85
|
forceClose: true,
|
|
@@ -89,19 +87,19 @@ const getRegisterConfig = async ({
|
|
|
89
87
|
}
|
|
90
88
|
},
|
|
91
89
|
{
|
|
92
|
-
pluginName:
|
|
90
|
+
pluginName: 'jwtAuthPlugin',
|
|
93
91
|
plugin: jwtAuthPlugin,
|
|
94
92
|
options: {
|
|
95
93
|
secret: jwtSecret
|
|
96
94
|
}
|
|
97
95
|
},
|
|
98
96
|
{
|
|
99
|
-
pluginName:
|
|
97
|
+
pluginName: 'authController',
|
|
100
98
|
plugin: authController,
|
|
101
99
|
options: { prefix: `${API_VERSION}/auth` }
|
|
102
100
|
},
|
|
103
101
|
{
|
|
104
|
-
pluginName:
|
|
102
|
+
pluginName: 'localUserPassController',
|
|
105
103
|
plugin: localUserPassController,
|
|
106
104
|
options: {
|
|
107
105
|
prefix: `${API_VERSION}/app/:appId/auth/providers/local-userpass`
|
|
@@ -6,29 +6,40 @@ import rulesMatcherUtils from '../rules-matcher/utils'
|
|
|
6
6
|
import { PermissionExpression } from './interface'
|
|
7
7
|
import { MachineContext } from './machines/interface'
|
|
8
8
|
|
|
9
|
-
const functionsConditions = [
|
|
9
|
+
const functionsConditions = ['%%true', '%%false']
|
|
10
10
|
|
|
11
|
-
export const evaluateExpression = async (
|
|
11
|
+
export const evaluateExpression = async (
|
|
12
|
+
params: MachineContext['params'],
|
|
13
|
+
expression?: PermissionExpression,
|
|
14
|
+
user?: MachineContext['user']
|
|
15
|
+
): Promise<boolean> => {
|
|
12
16
|
if (!expression || typeof expression === 'boolean') return !!expression
|
|
13
17
|
|
|
14
18
|
const value = {
|
|
15
19
|
...params.expansions,
|
|
16
20
|
...params.cursor,
|
|
17
|
-
|
|
21
|
+
'%%user': user,
|
|
18
22
|
'%%true': true
|
|
19
23
|
}
|
|
20
24
|
const conditions = expandQuery(expression, value)
|
|
21
|
-
const complexCondition = Object.entries<Record<string, any>>(conditions).find(([key]) =>
|
|
22
|
-
|
|
23
|
-
|
|
25
|
+
const complexCondition = Object.entries<Record<string, any>>(conditions).find(([key]) =>
|
|
26
|
+
functionsConditions.includes(key)
|
|
27
|
+
)
|
|
28
|
+
return complexCondition
|
|
29
|
+
? await evaluateComplexExpression(complexCondition, params, user)
|
|
30
|
+
: rulesMatcherUtils.checkRule(conditions, value, {})
|
|
24
31
|
}
|
|
25
32
|
|
|
26
|
-
const evaluateComplexExpression = async (
|
|
33
|
+
const evaluateComplexExpression = async (
|
|
34
|
+
condition: [string, Record<string, any>],
|
|
35
|
+
params: MachineContext['params'],
|
|
36
|
+
user: MachineContext['user']
|
|
37
|
+
) => {
|
|
27
38
|
const [key, config] = condition
|
|
28
39
|
|
|
29
|
-
const { name } = config[
|
|
30
|
-
const functionsList = StateManager.select(
|
|
31
|
-
const app = StateManager.select(
|
|
40
|
+
const { name } = config['%function']
|
|
41
|
+
const functionsList = StateManager.select('functions')
|
|
42
|
+
const app = StateManager.select('app')
|
|
32
43
|
const currentFunction = functionsList[name]
|
|
33
44
|
const response = await GenerateContext({
|
|
34
45
|
args: [params.cursor],
|
|
@@ -39,9 +50,5 @@ const evaluateComplexExpression = async (condition: [string, Record<string, any>
|
|
|
39
50
|
functionsList,
|
|
40
51
|
services
|
|
41
52
|
})
|
|
42
|
-
return key ===
|
|
43
|
-
|
|
53
|
+
return key === '%%true' ? response : !response
|
|
44
54
|
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export type PermissionExpression = boolean // TODO: add complex condition (%%true: %function)
|
|
2
2
|
|
|
3
3
|
export type FieldPermissionExpression = {
|
|
4
|
-
read?: boolean
|
|
4
|
+
read?: boolean
|
|
5
5
|
write?: boolean
|
|
6
6
|
}
|
|
7
7
|
|
|
@@ -37,6 +37,5 @@ export interface Params {
|
|
|
37
37
|
type: 'insert' | 'read' | 'delete' | 'search' | 'write'
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
|
|
41
40
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
42
|
-
export type Condition = Record<string, any>
|
|
41
|
+
export type Condition = Record<string, any>
|
|
@@ -1,24 +1,33 @@
|
|
|
1
|
-
import { someAsync } from
|
|
2
|
-
import { evaluateExpression } from
|
|
3
|
-
import { DocumentFiltersPermissions } from
|
|
4
|
-
import { MachineContext } from
|
|
1
|
+
import { someAsync } from '../../helpers/someAsync'
|
|
2
|
+
import { evaluateExpression } from '../helpers'
|
|
3
|
+
import { DocumentFiltersPermissions } from '../interface'
|
|
4
|
+
import { MachineContext } from './interface'
|
|
5
5
|
|
|
6
6
|
const readOnlyPermissions = ['read']
|
|
7
7
|
const readWritePermissions = ['write', 'delete', 'insert', ...readOnlyPermissions]
|
|
8
8
|
|
|
9
|
-
export const evaluateDocumentFiltersFn = async (
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
9
|
+
export const evaluateDocumentFiltersFn = async (
|
|
10
|
+
{ params, role, user }: MachineContext,
|
|
11
|
+
currentType: keyof DocumentFiltersPermissions
|
|
12
|
+
) => {
|
|
13
|
+
const permissions = currentType === 'read' ? readOnlyPermissions : readWritePermissions
|
|
14
|
+
return await someAsync(
|
|
15
|
+
[permissions.includes(params.type) && role.document_filters?.[currentType]].filter(
|
|
16
|
+
Boolean
|
|
17
|
+
),
|
|
18
|
+
async (expr) => evaluateExpression(params, expr, user)
|
|
19
|
+
)
|
|
15
20
|
}
|
|
16
21
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
22
|
+
export const evaluateTopLevelPermissionsFn = async (
|
|
23
|
+
{ params, role, user }: MachineContext,
|
|
24
|
+
currentType: MachineContext['params']['type']
|
|
25
|
+
) => {
|
|
26
|
+
return role[currentType]
|
|
27
|
+
? await evaluateExpression(params, role[currentType], user)
|
|
28
|
+
: undefined
|
|
20
29
|
}
|
|
21
30
|
|
|
22
31
|
export const checkFieldsPropertyExists = ({ role }: MachineContext) => {
|
|
23
|
-
|
|
32
|
+
return !!Object.keys(role.fields ?? {}).length
|
|
24
33
|
}
|
|
@@ -9,12 +9,15 @@ import { StateMachine } from './machine'
|
|
|
9
9
|
* @param {Role} role - The role configuration for validation.
|
|
10
10
|
* @param {Params} params - The parameters relevant to the validation process.
|
|
11
11
|
* @param {User} user - The user for whom the validation is being performed.
|
|
12
|
-
*
|
|
12
|
+
*
|
|
13
13
|
* @returns {Promise<StepResult>} - The result of the state machine's validation process.
|
|
14
14
|
*/
|
|
15
|
-
export const checkValidation = async (
|
|
15
|
+
export const checkValidation = async (
|
|
16
|
+
role: Role,
|
|
17
|
+
params: Params,
|
|
18
|
+
user: User,
|
|
19
|
+
enableLog?: boolean
|
|
20
|
+
): Promise<StepResult> => {
|
|
16
21
|
const stateMachine = new StateMachine(role, params, user, enableLog)
|
|
17
22
|
return await stateMachine.runValidation()
|
|
18
23
|
}
|
|
19
|
-
|
|
20
|
-
|
|
@@ -17,7 +17,13 @@ type StateFunction = (
|
|
|
17
17
|
context: MachineContext
|
|
18
18
|
} & {
|
|
19
19
|
next: (step: string, params?: Record<string, any>) => void
|
|
20
|
-
endValidation: ({
|
|
20
|
+
endValidation: ({
|
|
21
|
+
success,
|
|
22
|
+
document
|
|
23
|
+
}: {
|
|
24
|
+
success: boolean
|
|
25
|
+
document?: Document
|
|
26
|
+
}) => void
|
|
21
27
|
goToNextValidationStage: (initialStep?: string | null) => void
|
|
22
28
|
}
|
|
23
29
|
) => Promise<void>
|
|
@@ -33,14 +39,20 @@ export interface ValidationStatus {
|
|
|
33
39
|
document?: Document
|
|
34
40
|
}
|
|
35
41
|
|
|
42
|
+
export interface StepResult {
|
|
43
|
+
status: boolean | null
|
|
44
|
+
nextInitialStep: string | null
|
|
45
|
+
document?: Document
|
|
46
|
+
}
|
|
36
47
|
|
|
37
|
-
export interface
|
|
38
|
-
|
|
39
|
-
|
|
48
|
+
export interface EndValidationParams {
|
|
49
|
+
success: boolean
|
|
50
|
+
document?: Document
|
|
51
|
+
}
|
|
40
52
|
|
|
41
53
|
export type LogMachineInfoParams = {
|
|
42
54
|
enabled?: boolean
|
|
43
55
|
machine: string
|
|
44
56
|
step: number
|
|
45
57
|
stepName: string
|
|
46
|
-
}
|
|
58
|
+
}
|
|
@@ -1,85 +1,110 @@
|
|
|
1
|
-
import { Document } from
|
|
2
|
-
import { User } from
|
|
3
|
-
import { Params, Role } from
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
import { Document } from 'mongodb'
|
|
2
|
+
import { User } from '../../../auth/dtos'
|
|
3
|
+
import { Params, Role } from '../interface'
|
|
4
|
+
import {
|
|
5
|
+
MachineContext,
|
|
6
|
+
PrevParams,
|
|
7
|
+
States,
|
|
8
|
+
StepResult,
|
|
9
|
+
ValidationStatus
|
|
10
|
+
} from './interface'
|
|
11
|
+
import { READ_MACHINE } from './read'
|
|
12
|
+
import { WRITE_MACHINE } from './write'
|
|
7
13
|
|
|
8
14
|
export class StateMachine {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
}
|
|
15
|
+
private _context: MachineContext
|
|
16
|
+
private _validation: StepResult = {
|
|
17
|
+
status: null,
|
|
18
|
+
nextInitialStep: null
|
|
19
|
+
}
|
|
20
|
+
private _machines: States[]
|
|
21
|
+
private _currentStep: {
|
|
22
|
+
names: readonly string[]
|
|
23
|
+
states: States
|
|
24
|
+
validation: ValidationStatus
|
|
25
|
+
completed?: boolean
|
|
26
|
+
initialStep: string | null
|
|
27
|
+
}
|
|
28
|
+
constructor(role: Role, params: Params, user: User, enableLog?: boolean) {
|
|
29
|
+
this._context = { role, params, user, enableLog }
|
|
30
|
+
this._machines = params.type === 'read' ? READ_MACHINE : WRITE_MACHINE
|
|
31
|
+
this._currentStep = {
|
|
32
|
+
names: [],
|
|
33
|
+
states: {},
|
|
34
|
+
validation: {
|
|
35
|
+
status: null
|
|
36
|
+
},
|
|
37
|
+
initialStep: null
|
|
33
38
|
}
|
|
39
|
+
}
|
|
34
40
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
41
|
+
async runValidation() {
|
|
42
|
+
for await (const machine of this._machines) {
|
|
43
|
+
this._currentStep = {
|
|
44
|
+
names: Object.freeze(Object.keys(machine)) as readonly (keyof typeof machine)[],
|
|
45
|
+
states: machine,
|
|
46
|
+
validation: { status: null },
|
|
47
|
+
initialStep: null
|
|
48
|
+
}
|
|
49
|
+
await this.runMachine(this._validation.nextInitialStep)
|
|
39
50
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
}
|
|
47
|
-
return this._validation;
|
|
51
|
+
this._validation.nextInitialStep = this._currentStep.initialStep
|
|
52
|
+
if (this._currentStep.validation.status !== null) {
|
|
53
|
+
this._validation.status = this._currentStep.validation.status
|
|
54
|
+
this._validation.document = this._currentStep.validation.document
|
|
55
|
+
break
|
|
56
|
+
}
|
|
48
57
|
}
|
|
58
|
+
return this._validation
|
|
59
|
+
}
|
|
49
60
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
goToNextValidationStage: this.goToNextValidationStage.bind(this),
|
|
61
|
-
initialStep
|
|
62
|
-
})
|
|
61
|
+
private async runMachine(initialStep: string | null) {
|
|
62
|
+
const executeStep = async (
|
|
63
|
+
step: keyof typeof this._currentStep.states,
|
|
64
|
+
params?: PrevParams
|
|
65
|
+
) => {
|
|
66
|
+
const currentStep = this._currentStep.states[step]
|
|
67
|
+
const next = (
|
|
68
|
+
nextStep: keyof typeof this._currentStep.states,
|
|
69
|
+
params?: PrevParams
|
|
70
|
+
) => executeStep(nextStep, params)
|
|
63
71
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
72
|
+
await currentStep({
|
|
73
|
+
context: { ...this._context, prevParams: params },
|
|
74
|
+
next,
|
|
75
|
+
endValidation: this.endValidation.bind(this),
|
|
76
|
+
goToNextValidationStage: this.goToNextValidationStage.bind(this),
|
|
77
|
+
initialStep
|
|
78
|
+
})
|
|
70
79
|
|
|
71
|
-
|
|
72
|
-
this._currentStep.validation.status
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
}
|
|
80
|
+
if (
|
|
81
|
+
this._currentStep.validation.status !== null ||
|
|
82
|
+
this._currentStep.completed !== undefined
|
|
83
|
+
)
|
|
84
|
+
return { isValid: this._currentStep.validation.status, ...this._currentStep }
|
|
76
85
|
}
|
|
86
|
+
const nextStep =
|
|
87
|
+
initialStep && this._currentStep.states[initialStep]
|
|
88
|
+
? initialStep
|
|
89
|
+
: this._currentStep.names[0]
|
|
90
|
+
await executeStep(nextStep)
|
|
91
|
+
}
|
|
77
92
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
93
|
+
private endValidation({
|
|
94
|
+
success,
|
|
95
|
+
document
|
|
96
|
+
}: {
|
|
97
|
+
success: boolean
|
|
98
|
+
document?: Document
|
|
99
|
+
}) {
|
|
100
|
+
this._currentStep.validation.status = success
|
|
101
|
+
if (success) {
|
|
102
|
+
this._currentStep.validation.document = document || this._context.params.cursor
|
|
82
103
|
}
|
|
104
|
+
}
|
|
83
105
|
|
|
84
|
-
|
|
85
|
-
|
|
106
|
+
private goToNextValidationStage(initialStep: string | null = null) {
|
|
107
|
+
this._currentStep.completed = true
|
|
108
|
+
this._currentStep.initialStep = initialStep
|
|
109
|
+
}
|
|
110
|
+
}
|
|
@@ -3,17 +3,25 @@ import { logMachineInfo } from '../../utils'
|
|
|
3
3
|
|
|
4
4
|
export const STEP_A_STATES: States = {
|
|
5
5
|
checkSearchRequest: async ({ context, next, goToNextValidationStage }) => {
|
|
6
|
-
logMachineInfo({
|
|
6
|
+
logMachineInfo({
|
|
7
|
+
enabled: context.enableLog,
|
|
8
|
+
machine: 'A',
|
|
9
|
+
step: 1,
|
|
10
|
+
stepName: 'checkSearchRequest'
|
|
11
|
+
})
|
|
7
12
|
if (context.params.type === 'search') {
|
|
8
13
|
return next('evaluateSearch')
|
|
9
14
|
}
|
|
10
15
|
return goToNextValidationStage()
|
|
11
16
|
},
|
|
12
17
|
evaluateSearch: async ({ context, endValidation }) => {
|
|
13
|
-
logMachineInfo({
|
|
18
|
+
logMachineInfo({
|
|
19
|
+
enabled: context.enableLog,
|
|
20
|
+
machine: 'A',
|
|
21
|
+
step: 2,
|
|
22
|
+
stepName: 'evaluateSearch'
|
|
23
|
+
})
|
|
14
24
|
// NOTE -> we don't support search operations
|
|
15
25
|
return endValidation({ success: false })
|
|
16
26
|
}
|
|
17
27
|
}
|
|
18
|
-
|
|
19
|
-
|
|
@@ -4,7 +4,12 @@ import { logMachineInfo } from '../../utils'
|
|
|
4
4
|
|
|
5
5
|
export const STEP_B_STATES: States = {
|
|
6
6
|
checkDocumentsFilters: async ({ context, next, goToNextValidationStage }) => {
|
|
7
|
-
logMachineInfo({
|
|
7
|
+
logMachineInfo({
|
|
8
|
+
enabled: context.enableLog,
|
|
9
|
+
machine: 'B',
|
|
10
|
+
step: 1,
|
|
11
|
+
stepName: 'checkDocumentsFilters'
|
|
12
|
+
})
|
|
8
13
|
const { role } = context
|
|
9
14
|
if (role.document_filters) {
|
|
10
15
|
return next('evaluateDocumentsFiltersRead')
|
|
@@ -12,8 +17,13 @@ export const STEP_B_STATES: States = {
|
|
|
12
17
|
return goToNextValidationStage()
|
|
13
18
|
},
|
|
14
19
|
evaluateDocumentsFiltersRead: async ({ context, next, goToNextValidationStage }) => {
|
|
15
|
-
logMachineInfo({
|
|
16
|
-
|
|
20
|
+
logMachineInfo({
|
|
21
|
+
enabled: context.enableLog,
|
|
22
|
+
machine: 'B',
|
|
23
|
+
step: 2,
|
|
24
|
+
stepName: 'evaluateDocumentsFiltersRead'
|
|
25
|
+
})
|
|
26
|
+
const hasDocumentFiltersRead = await evaluateDocumentFiltersFn(context, 'read')
|
|
17
27
|
if (!hasDocumentFiltersRead) return next('evaluateDocumentsFiltersWrite')
|
|
18
28
|
return goToNextValidationStage()
|
|
19
29
|
},
|
|
@@ -22,10 +32,13 @@ export const STEP_B_STATES: States = {
|
|
|
22
32
|
endValidation,
|
|
23
33
|
goToNextValidationStage
|
|
24
34
|
}) => {
|
|
25
|
-
logMachineInfo({
|
|
26
|
-
|
|
35
|
+
logMachineInfo({
|
|
36
|
+
enabled: context.enableLog,
|
|
37
|
+
machine: 'B',
|
|
38
|
+
step: 3,
|
|
39
|
+
stepName: 'evaluateDocumentsFiltersWrite'
|
|
40
|
+
})
|
|
41
|
+
const check = await evaluateDocumentFiltersFn(context, 'write')
|
|
27
42
|
return check ? goToNextValidationStage() : endValidation({ success: false })
|
|
28
43
|
}
|
|
29
44
|
}
|
|
30
|
-
|
|
31
|
-
|
|
@@ -1,30 +1,46 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
checkFieldsPropertyExists,
|
|
3
|
+
evaluateTopLevelPermissionsFn
|
|
4
|
+
} from '../../commonValidators'
|
|
2
5
|
import { States } from '../../interface'
|
|
3
6
|
import { logMachineInfo } from '../../utils'
|
|
4
7
|
|
|
5
|
-
|
|
6
8
|
export const STEP_C_STATES: States = {
|
|
7
9
|
evaluateTopLevelRead: async ({ context, next, endValidation }) => {
|
|
8
|
-
logMachineInfo({
|
|
9
|
-
|
|
10
|
+
logMachineInfo({
|
|
11
|
+
enabled: context.enableLog,
|
|
12
|
+
machine: 'C',
|
|
13
|
+
step: 1,
|
|
14
|
+
stepName: 'evaluateTopLevelRead'
|
|
15
|
+
})
|
|
16
|
+
const check = await evaluateTopLevelPermissionsFn(context, 'read')
|
|
10
17
|
return check
|
|
11
18
|
? endValidation({ success: true })
|
|
12
19
|
: next('evaluateTopLevelWrite', { check })
|
|
13
20
|
},
|
|
14
21
|
evaluateTopLevelWrite: async ({ context, next, endValidation }) => {
|
|
15
|
-
logMachineInfo({
|
|
16
|
-
|
|
22
|
+
logMachineInfo({
|
|
23
|
+
enabled: context.enableLog,
|
|
24
|
+
machine: 'C',
|
|
25
|
+
step: 2,
|
|
26
|
+
stepName: 'evaluateTopLevelWrite'
|
|
27
|
+
})
|
|
28
|
+
const check = await evaluateTopLevelPermissionsFn(context, 'write')
|
|
17
29
|
if (check) return endValidation({ success: true })
|
|
18
30
|
return context?.prevParams?.check === false
|
|
19
31
|
? endValidation({ success: false })
|
|
20
32
|
: next('checkFieldsProperty')
|
|
21
33
|
},
|
|
22
34
|
checkFieldsProperty: async ({ context, goToNextValidationStage }) => {
|
|
23
|
-
logMachineInfo({
|
|
35
|
+
logMachineInfo({
|
|
36
|
+
enabled: context.enableLog,
|
|
37
|
+
machine: 'C',
|
|
38
|
+
step: 3,
|
|
39
|
+
stepName: 'checkFieldsProperty'
|
|
40
|
+
})
|
|
24
41
|
const check = checkFieldsPropertyExists(context)
|
|
25
42
|
return goToNextValidationStage(
|
|
26
43
|
check ? 'checkIsValidFieldName' : 'checkAdditionalFields'
|
|
27
44
|
)
|
|
28
45
|
}
|
|
29
46
|
}
|
|
30
|
-
|