not-node 6.5.18 → 6.5.21
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/.husky/pre-commit +0 -3
- package/eslint.config.cjs +2 -2
- package/index.js +2 -0
- package/package.json +5 -5
- package/src/auth/const.js +4 -0
- package/src/core/locales/ru.json +1 -0
- package/src/domain.js +2 -3
- package/src/exceptions/form.js +13 -0
- package/src/fields/filter.js +6 -1
- package/src/generic/form.js +2 -1
- package/src/generic/forms/form._data.js +31 -5
- package/src/generic/forms/form.list.js +33 -19
- package/src/generic/forms/form.listAndCount.js +6 -61
- package/src/task.runner.js +95 -0
- package/.eslintignore +0 -4
package/.husky/pre-commit
CHANGED
package/eslint.config.cjs
CHANGED
package/index.js
CHANGED
|
@@ -37,6 +37,8 @@ module.exports.Enrich = require("./src/model/enrich");
|
|
|
37
37
|
module.exports.Routine = require("./src/model/routine");
|
|
38
38
|
/** Common functions */
|
|
39
39
|
module.exports.Common = require("./src/common");
|
|
40
|
+
/** Task Runner */
|
|
41
|
+
module.exports.TaskRunner = require("./src/task.runner.js");
|
|
40
42
|
/** Fields library manager */
|
|
41
43
|
module.exports.Fields = require("./src/fields");
|
|
42
44
|
/** Application generic helpers */
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "not-node",
|
|
3
|
-
"version": "6.5.
|
|
3
|
+
"version": "6.5.21",
|
|
4
4
|
"description": "node complimentary part for client side notFramework.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
7
|
-
"test": "mocha --require mocha-suppress-logs --reporter spec --timeout 12000",
|
|
7
|
+
"test": "mocha --exit --require mocha-suppress-logs --reporter spec --timeout 12000",
|
|
8
8
|
"lint": "eslint ./src --fix",
|
|
9
9
|
"pretest": "eslint ./src",
|
|
10
10
|
"docs": "jsdoc -c jsdoc.json",
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"watch:build:cover:dev": "npm-run-all --parallel js-watch",
|
|
13
13
|
"cover": "nyc npm test",
|
|
14
14
|
"clear:playground": "rm -rf ./playground",
|
|
15
|
-
"prepare": "husky
|
|
15
|
+
"prepare": "husky"
|
|
16
16
|
},
|
|
17
17
|
"bin": {
|
|
18
18
|
"not-node": "bin/not-node.js",
|
|
@@ -59,7 +59,7 @@
|
|
|
59
59
|
"mongoose-validator": "*",
|
|
60
60
|
"nconf": "*",
|
|
61
61
|
"not-config": "*",
|
|
62
|
-
"not-filter": "
|
|
62
|
+
"not-filter": "^0.3.15",
|
|
63
63
|
"not-inform": "*",
|
|
64
64
|
"not-locale": "^0.0.22",
|
|
65
65
|
"not-log": "*",
|
|
@@ -135,4 +135,4 @@
|
|
|
135
135
|
]
|
|
136
136
|
}
|
|
137
137
|
}
|
|
138
|
-
}
|
|
138
|
+
}
|
package/src/auth/const.js
CHANGED
|
@@ -29,7 +29,10 @@ const METHOD_SIGNAURES = {
|
|
|
29
29
|
|
|
30
30
|
const OBJECT_STRING = "[object String]";
|
|
31
31
|
|
|
32
|
+
//document owned by registered user
|
|
32
33
|
const DOCUMENT_OWNER_FIELD_NAME = "owner";
|
|
34
|
+
//document owned by guest user
|
|
35
|
+
const DOCUMENT_SESSION_FIELD_NAME = "session";
|
|
33
36
|
const TOKEN_TTL = 3600;
|
|
34
37
|
|
|
35
38
|
module.exports = {
|
|
@@ -39,6 +42,7 @@ module.exports = {
|
|
|
39
42
|
DEFAULT_USER_ROLE_FOR_ROOT,
|
|
40
43
|
DEFAULT_USER_ROLE_FOR_ADMIN,
|
|
41
44
|
DOCUMENT_OWNER_FIELD_NAME,
|
|
45
|
+
DOCUMENT_SESSION_FIELD_NAME,
|
|
42
46
|
ACTION_SIGNATURES,
|
|
43
47
|
METHOD_SIGNAURES,
|
|
44
48
|
};
|
package/src/core/locales/ru.json
CHANGED
|
@@ -76,5 +76,6 @@
|
|
|
76
76
|
"select_from_list_label": "Выберите из списка...",
|
|
77
77
|
"field_actions_label": "Действия",
|
|
78
78
|
"form_exception_field_extractor_is_undefined": "Экстрактор для поля входных данных отсутствует",
|
|
79
|
+
"form_exception_identity_or_query_is_undefined": "Identity или Query отсутствуют",
|
|
79
80
|
"versioning_error_same_old_data": "Данные не изменились, сохранение отклонено."
|
|
80
81
|
}
|
package/src/domain.js
CHANGED
|
@@ -59,7 +59,6 @@ class notDomain extends EventEmitter {
|
|
|
59
59
|
constructor(options) {
|
|
60
60
|
super();
|
|
61
61
|
this.#options = options;
|
|
62
|
-
|
|
63
62
|
return this;
|
|
64
63
|
}
|
|
65
64
|
|
|
@@ -138,8 +137,8 @@ class notDomain extends EventEmitter {
|
|
|
138
137
|
|
|
139
138
|
/**
|
|
140
139
|
* Returns route
|
|
141
|
-
* @param
|
|
142
|
-
* @return
|
|
140
|
+
* @param {string} name 'moduleName//routeName//functionName' ('not-user//user//add')
|
|
141
|
+
* @return {function} route
|
|
143
142
|
**/
|
|
144
143
|
getRoute(name) {
|
|
145
144
|
if (name.indexOf("//") > 0) {
|
package/src/exceptions/form.js
CHANGED
|
@@ -34,3 +34,16 @@ class FormExceptionTooManyRequests extends HttpExceptionTooManyRequests {
|
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
module.exports.FormExceptionTooManyRequests = FormExceptionTooManyRequests;
|
|
37
|
+
|
|
38
|
+
Error("no prepared identity or query");
|
|
39
|
+
|
|
40
|
+
class FormExceptionIdentityOrQueryIsUndefined extends notRequestError {
|
|
41
|
+
constructor(formName) {
|
|
42
|
+
super("not-node:form_exception_identity_or_query_is_undefined", {
|
|
43
|
+
params: { formName },
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
module.exports.FormExceptionIdentityOrQueryIsUndefined =
|
|
49
|
+
FormExceptionIdentityOrQueryIsUndefined;
|
package/src/fields/filter.js
CHANGED
|
@@ -8,6 +8,7 @@ const { getSafeFieldsForRoleAction } = require("../auth/fields");
|
|
|
8
8
|
const {
|
|
9
9
|
DEFAULT_USER_ROLE_FOR_GUEST,
|
|
10
10
|
ACTION_SIGNATURES,
|
|
11
|
+
DOCUMENT_SESSION_FIELD_NAME,
|
|
11
12
|
} = require("../auth/const");
|
|
12
13
|
/**
|
|
13
14
|
* notFieldsFilter.filter(fields, getApp().getModelSchema(MODEL_NAME), {action});
|
|
@@ -144,7 +145,11 @@ class notFieldsFilter {
|
|
|
144
145
|
system
|
|
145
146
|
);
|
|
146
147
|
},
|
|
147
|
-
[SPECIAL_SET_UNSAFE]: [
|
|
148
|
+
[SPECIAL_SET_UNSAFE]: [
|
|
149
|
+
"salt",
|
|
150
|
+
"password",
|
|
151
|
+
DOCUMENT_SESSION_FIELD_NAME,
|
|
152
|
+
],
|
|
148
153
|
[SPECIAL_SET_TIMESTAMPS]: ["createdAt", "updatedAt"],
|
|
149
154
|
[SPECIAL_SET_OWNAGE]: (schema) => {
|
|
150
155
|
const inSchema = Object.keys(schema);
|
package/src/generic/form.js
CHANGED
|
@@ -15,6 +15,7 @@ function createDefaultInstance({
|
|
|
15
15
|
MODULE_NAME,
|
|
16
16
|
MODEL_NAME,
|
|
17
17
|
actionName,
|
|
18
|
+
config,
|
|
18
19
|
/* validators = [],
|
|
19
20
|
dataValidators = [],*/
|
|
20
21
|
}) {
|
|
@@ -23,7 +24,7 @@ function createDefaultInstance({
|
|
|
23
24
|
["data", `${MODULE_NAME}//_${Common.firstLetterToLower(MODEL_NAME)}`],
|
|
24
25
|
];
|
|
25
26
|
const FORM_NAME = Form.createName(MODULE_NAME, MODEL_NAME, actionName);
|
|
26
|
-
return new Form({ FIELDS, FORM_NAME, app, MODULE_NAME });
|
|
27
|
+
return new Form({ FIELDS, FORM_NAME, app, MODULE_NAME, config });
|
|
27
28
|
}
|
|
28
29
|
|
|
29
30
|
module.exports = createDefaultInstance;
|
|
@@ -5,9 +5,16 @@ const Form = require("../../form/form");
|
|
|
5
5
|
* @param {object} param0
|
|
6
6
|
* @param {string} param0.MODULE_NAME
|
|
7
7
|
* @param {string} param0.MODEL_NAME
|
|
8
|
-
* @param {string} param0.actionName
|
|
9
|
-
* @param {Array<function>} param0.validators
|
|
10
|
-
* @param {function} param0.afterExtract
|
|
8
|
+
* @param {string} [param0.actionName = '_data']
|
|
9
|
+
* @param {Array<function>} [param0.validators=[]]
|
|
10
|
+
* @param {function} [param0.afterExtract = async (input, req = null) => input || req]
|
|
11
|
+
* @param {import('../../types.js').notAppConfigReader} [param0.config]
|
|
12
|
+
* @param {Object.<string, Function>} [param0.EXTRACTORS]
|
|
13
|
+
* @param {Object.<string, Function>} [param0.TRANSFORMERS]
|
|
14
|
+
* @param {import('../../types.js').notAppFormProcessingPipe} [param0.INSTRUCTIONS]
|
|
15
|
+
* @param {Array<Function>} [param0.AFTER_EXTRACT_TRANSFORMERS]
|
|
16
|
+
* @param {Object.<string, import('../../types.js').notAppFormEnvExtractor>} [param0.ENV_EXTRACTORS]
|
|
17
|
+
* @param {import('../../types.js').notAppFormRateLimiterOptions} [param0.rate]
|
|
11
18
|
* @returns
|
|
12
19
|
*/
|
|
13
20
|
module.exports = ({
|
|
@@ -16,15 +23,34 @@ module.exports = ({
|
|
|
16
23
|
actionName = "_data",
|
|
17
24
|
validators = [],
|
|
18
25
|
afterExtract = async (input, req = null) => input || req,
|
|
26
|
+
EXTRACTORS = {},
|
|
27
|
+
ENV_EXTRACTORS = {},
|
|
28
|
+
TRANSFORMERS = {},
|
|
29
|
+
INSTRUCTIONS = undefined,
|
|
30
|
+
AFTER_EXTRACT_TRANSFORMERS = [],
|
|
31
|
+
rate = undefined,
|
|
19
32
|
}) => {
|
|
20
33
|
return class extends Form {
|
|
21
34
|
/**
|
|
22
35
|
*
|
|
23
36
|
* @param {object} param0
|
|
24
37
|
* @param {import('../../app')} param0.app
|
|
38
|
+
* @param {import('../../types.js').notAppConfigReader} param0.config
|
|
25
39
|
*/
|
|
26
|
-
constructor({ app }) {
|
|
27
|
-
super({
|
|
40
|
+
constructor({ app, config }) {
|
|
41
|
+
super({
|
|
42
|
+
app,
|
|
43
|
+
config,
|
|
44
|
+
MODULE_NAME,
|
|
45
|
+
MODEL_NAME,
|
|
46
|
+
actionName,
|
|
47
|
+
EXTRACTORS,
|
|
48
|
+
ENV_EXTRACTORS,
|
|
49
|
+
TRANSFORMERS,
|
|
50
|
+
INSTRUCTIONS,
|
|
51
|
+
AFTER_EXTRACT_TRANSFORMERS,
|
|
52
|
+
rate,
|
|
53
|
+
});
|
|
28
54
|
}
|
|
29
55
|
|
|
30
56
|
extract(data) {
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
const Form = require("../../form/form");
|
|
2
|
-
|
|
2
|
+
const {
|
|
3
|
+
DOCUMENT_OWNER_FIELD_NAME,
|
|
4
|
+
DOCUMENT_SESSION_FIELD_NAME,
|
|
5
|
+
} = require("../../auth/const");
|
|
3
6
|
const notFilter = require("not-filter");
|
|
4
|
-
const
|
|
5
|
-
|
|
7
|
+
const FormExceptions = require("../../exceptions/form");
|
|
6
8
|
const FIELDS = [
|
|
7
9
|
["query", `not-filter//_filterQuery`],
|
|
8
10
|
["identity", "not-node//identity"],
|
|
@@ -30,29 +32,41 @@ const FactoryFormList = ({ MODULE_NAME, MODEL_NAME, actionName = "list" }) => {
|
|
|
30
32
|
}
|
|
31
33
|
|
|
32
34
|
/**
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
+
* Adds owner id or session to query.filter
|
|
36
|
+
* @param {import('../../types').PreparedData} prepared
|
|
35
37
|
* @param {import('../../types').notNodeExpressRequest} req
|
|
36
38
|
* @return {Promise<import('../../types').PreparedData>}
|
|
37
39
|
*/
|
|
38
|
-
async
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
40
|
+
async afterExtract(prepared, req) {
|
|
41
|
+
prepared = await super.afterExtract(prepared, req);
|
|
42
|
+
if (!prepared.identity || !prepared.query) {
|
|
43
|
+
throw new FormExceptions.FormExceptionIdentityOrQueryIsUndefined(
|
|
44
|
+
this.FORM_NAME
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
if (!prepared.query.filter) {
|
|
48
|
+
prepared.query.filter = notFilter.filter.createANDFilter();
|
|
49
|
+
}
|
|
50
|
+
if (
|
|
51
|
+
prepared.identity.auth &&
|
|
52
|
+
!prepared.identity.root &&
|
|
53
|
+
!prepared.identity.admin
|
|
54
|
+
) {
|
|
55
|
+
prepared.query.filter = notFilter.filter.modifyRules(
|
|
56
|
+
prepared.query.filter,
|
|
47
57
|
{
|
|
48
|
-
|
|
58
|
+
[DOCUMENT_OWNER_FIELD_NAME]: prepared.identity.uid,
|
|
59
|
+
}
|
|
60
|
+
);
|
|
61
|
+
} else if (!prepared.identity.auth && prepared.identity.sid) {
|
|
62
|
+
prepared.query.filter = notFilter.filter.modifyRules(
|
|
63
|
+
prepared.query.filter,
|
|
64
|
+
{
|
|
65
|
+
[DOCUMENT_SESSION_FIELD_NAME]: prepared.identity.sid,
|
|
49
66
|
}
|
|
50
67
|
);
|
|
51
68
|
}
|
|
52
|
-
|
|
53
|
-
return {
|
|
54
|
-
...envs,
|
|
55
|
-
};
|
|
69
|
+
return prepared;
|
|
56
70
|
}
|
|
57
71
|
};
|
|
58
72
|
};
|
|
@@ -1,63 +1,8 @@
|
|
|
1
|
-
const
|
|
1
|
+
const FactoryFormList = require("./form.list");
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
["identity", "not-node//identity"],
|
|
9
|
-
];
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Generates generic form to get perform list and count action
|
|
13
|
-
*
|
|
14
|
-
* @param {object} params
|
|
15
|
-
* @param {string} params.MODULE_NAME //module name
|
|
16
|
-
* @param {string} params.MODEL_NAME //model name
|
|
17
|
-
* @param {string} params.actionName //action name
|
|
18
|
-
* @return {Form} form class definition
|
|
19
|
-
*/
|
|
20
|
-
const FactoryFormListAndCount = ({
|
|
21
|
-
MODULE_NAME,
|
|
22
|
-
MODEL_NAME,
|
|
23
|
-
actionName = "listAndCount",
|
|
24
|
-
}) => {
|
|
25
|
-
return class extends Form {
|
|
26
|
-
constructor(params) {
|
|
27
|
-
super({
|
|
28
|
-
...params,
|
|
29
|
-
FIELDS,
|
|
30
|
-
MODULE_NAME,
|
|
31
|
-
MODEL_NAME,
|
|
32
|
-
actionName,
|
|
33
|
-
});
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
* @param {import('../../types').notNodeExpressRequest} req
|
|
40
|
-
* @return {Promise<import('../../types').PreparedData>}
|
|
41
|
-
*/
|
|
42
|
-
async extract(req) {
|
|
43
|
-
const envs = this.extractRequestEnvs(req);
|
|
44
|
-
const user = notAppIdentity.extractAuthData(req);
|
|
45
|
-
if (user.auth && !user.root && !user.admin) {
|
|
46
|
-
if (!envs.query.filter) {
|
|
47
|
-
envs.query.filter = notFilter.filter.createFilter();
|
|
48
|
-
}
|
|
49
|
-
envs.query.filter = notFilter.filter.modifyRules(
|
|
50
|
-
envs.query.filter,
|
|
51
|
-
{
|
|
52
|
-
owner: user.uid,
|
|
53
|
-
}
|
|
54
|
-
);
|
|
55
|
-
}
|
|
56
|
-
return {
|
|
57
|
-
...envs,
|
|
58
|
-
};
|
|
59
|
-
}
|
|
60
|
-
};
|
|
3
|
+
module.exports = (params) => {
|
|
4
|
+
if (!params.actionName) {
|
|
5
|
+
params.actionName = "listAndCount";
|
|
6
|
+
}
|
|
7
|
+
return FactoryFormList(params);
|
|
61
8
|
};
|
|
62
|
-
|
|
63
|
-
module.exports = FactoryFormListAndCount;
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
const MIN_TASK_CHECK_INTERVAL = 3600;
|
|
2
|
+
|
|
3
|
+
class TaskRunner {
|
|
4
|
+
static #logger = console;
|
|
5
|
+
static #runEvery = 3600;
|
|
6
|
+
static #checkEvery = 3500; //every hour
|
|
7
|
+
static #int = setInterval(TaskRunner.#check, TaskRunner.#checkEvery * 1000);
|
|
8
|
+
static #tasks = [];
|
|
9
|
+
|
|
10
|
+
static setLogger(logger) {
|
|
11
|
+
TaskRunner.#logger = logger;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
static #create(id, task, tag) {
|
|
15
|
+
return {
|
|
16
|
+
id,
|
|
17
|
+
task,
|
|
18
|
+
tag,
|
|
19
|
+
count: 0,
|
|
20
|
+
lastRunnedAt: -1,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
static add(task, tag) {
|
|
25
|
+
const id = Math.random();
|
|
26
|
+
if (!tag) {
|
|
27
|
+
tag = `task#${TaskRunner.#tasks.length + 1}`;
|
|
28
|
+
}
|
|
29
|
+
TaskRunner.#tasks.push(TaskRunner.#create(id, task, tag));
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
static remove(id) {
|
|
33
|
+
const task = TaskRunner.#tasks.find((item) => item.id === id);
|
|
34
|
+
if (task) {
|
|
35
|
+
TaskRunner.#tasks.splice(TaskRunner.#tasks.indexOf(task), 1);
|
|
36
|
+
return true;
|
|
37
|
+
}
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
static clear() {
|
|
42
|
+
this.#tasks = [];
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
static async #check() {
|
|
46
|
+
try {
|
|
47
|
+
const runners = TaskRunner.#tasks
|
|
48
|
+
.filter(TaskRunner.#taskShouldBeRunned)
|
|
49
|
+
.map(TaskRunner.#taskToPromise);
|
|
50
|
+
await Promise.allSettled(runners);
|
|
51
|
+
} catch (e) {
|
|
52
|
+
TaskRunner.#logger.error("Task Set Failed", new Date(), e);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
static async #taskToPromise(taskItem) {
|
|
57
|
+
const { tag } = taskItem;
|
|
58
|
+
try {
|
|
59
|
+
await taskItem.task();
|
|
60
|
+
taskItem.lastRunnedAt = Date.now();
|
|
61
|
+
taskItem.count += 1;
|
|
62
|
+
} catch (e) {
|
|
63
|
+
TaskRunner.#logger.error("Task Failed", tag, new Date(), e);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
static #taskShouldBeRunned(taskItem) {
|
|
68
|
+
if (taskItem.count === 0) {
|
|
69
|
+
return true;
|
|
70
|
+
}
|
|
71
|
+
return taskItem.lastRunnedAt < Date.now() - TaskRunner.#runEvery;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
static stop() {
|
|
75
|
+
clearInterval(TaskRunner.#int);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
static start() {
|
|
79
|
+
TaskRunner.#int = setInterval(
|
|
80
|
+
TaskRunner.#check,
|
|
81
|
+
TaskRunner.#checkEvery * 1000
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
static setInterval(int = MIN_TASK_CHECK_INTERVAL) {
|
|
86
|
+
if (isNaN(int) || int < MIN_TASK_CHECK_INTERVAL) {
|
|
87
|
+
return false;
|
|
88
|
+
}
|
|
89
|
+
TaskRunner.#checkEvery = int;
|
|
90
|
+
TaskRunner.stop();
|
|
91
|
+
TaskRunner.start();
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
module.exports = TaskRunner;
|
package/.eslintignore
DELETED