not-node 6.3.0 → 6.3.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/index.js +2 -0
- package/package.json +2 -2
- package/src/auth/const.js +17 -0
- package/src/auth/fields.js +10 -5
- package/src/auth/roles.js +2 -2
- package/src/auth/rules.js +49 -13
- package/src/bootstrap/logic.js +12 -11
- package/src/bootstrap/route.js +1 -1
- package/src/common.js +7 -0
- package/src/fields/filter.js +326 -0
- package/src/fields/index.js +2 -2
- package/src/form/env_extractors/activeUser.js +1 -1
- package/src/form/env_extractors/activeUserId.js +6 -0
- package/src/form/env_extractors/index.js +3 -0
- package/src/form/env_extractors/query.js +6 -0
- package/src/form/fabric.js +3 -3
- package/src/form/form.js +37 -10
- package/src/generic/form.authorizedAction.js +6 -8
- package/src/generic/form.getByID.js +8 -10
- package/src/generic/form.getById.js +8 -9
- package/src/generic/form.listAndCount.js +28 -26
- package/src/generic/logic.js +31 -85
- package/src/identity/index.js +6 -2
- package/src/identity/providers/session.js +14 -12
- package/src/identity/providers/token.js +14 -7
- package/src/init/lib/sessions/index.js +1 -1
- package/src/manifest/manifest.filter.js +118 -17
- package/src/manifest/manifest.js +8 -2
- package/src/manifest/module.js +21 -16
- package/src/manifest/registrator/fields.js +8 -1
- package/src/manifest/registrator/forms.js +1 -0
- package/src/manifest/registrator/locales.js +9 -1
- package/src/manifest/registrator/logics.js +2 -2
- package/src/manifest/registrator/models.js +2 -2
- package/src/manifest/registrator/routes.js +8 -8
- package/src/manifest/result.filter.js +3 -2
- package/src/manifest/route.js +42 -14
- package/src/model/default.js +1 -1
- package/src/model/proto.js +1 -1
- package/src/obsolete.js +23 -7
- package/src/types.js +83 -0
- package/test/auth/fields.js +2 -2
- package/test/auth/obsolete.js +16 -9
- package/test/extractors.js +60 -0
- package/test/filter.js +286 -0
- package/test/init/sessions.js +14 -2
- package/test/notManifestFilter.js +358 -19
- package/test/notModule.js +41 -1
- package/test/transformers.js +21 -0
- package/tmpl/files/module.server/layers/routes.manifest.ejs +9 -0
package/index.js
CHANGED
|
@@ -35,6 +35,8 @@ module.exports.Routine = require("./src/model/routine");
|
|
|
35
35
|
module.exports.Common = require("./src/common");
|
|
36
36
|
/** Fields library manager */
|
|
37
37
|
module.exports.Fields = require("./src/fields");
|
|
38
|
+
/** Application generic helpers */
|
|
39
|
+
module.exports.notFieldsFilter = require("./src/fields/filter.js");
|
|
38
40
|
module.exports.Forms = require("./src/form");
|
|
39
41
|
/** Form validation template **/
|
|
40
42
|
module.exports.Form = require("./src/form").Form;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "not-node",
|
|
3
|
-
"version": "6.3.
|
|
3
|
+
"version": "6.3.2",
|
|
4
4
|
"description": "node complimentary part for client side notFramework.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -68,7 +68,6 @@
|
|
|
68
68
|
"not-log": "*",
|
|
69
69
|
"not-monitor": "*",
|
|
70
70
|
"not-path": "*",
|
|
71
|
-
"not-validation": "*",
|
|
72
71
|
"rate-limiter-flexible": "^2.4.1",
|
|
73
72
|
"redis": "^4.5.1",
|
|
74
73
|
"redlock": "^5.0.0-beta.2",
|
|
@@ -94,6 +93,7 @@
|
|
|
94
93
|
"mocha": "*",
|
|
95
94
|
"mocha-suppress-logs": "^0.3.1",
|
|
96
95
|
"mongodb-memory-server": "^8.11.0",
|
|
96
|
+
"not-validation": "^0.0.9",
|
|
97
97
|
"npm-run-all": "^4.1.5",
|
|
98
98
|
"nyc": "^15.1.0",
|
|
99
99
|
"retire": "^3.2.1"
|
package/src/auth/const.js
CHANGED
|
@@ -1,13 +1,30 @@
|
|
|
1
1
|
const DEFAULT_USER_ROLE_FOR_ADMIN = "root";
|
|
2
2
|
const DEFAULT_USER_ROLE_FOR_GUEST = "guest";
|
|
3
3
|
|
|
4
|
+
const ACTION_SIGNATURE_CREATE = "create";
|
|
5
|
+
const ACTION_SIGNATURE_READ = "read";
|
|
6
|
+
const ACTION_SIGNATURE_UPDATE = "update";
|
|
7
|
+
const ACTION_SIGNATURE_DELETE = "delete";
|
|
8
|
+
const ACTION_SIGNATURE_ANY = "any";
|
|
9
|
+
|
|
10
|
+
const ACTION_SIGNATURES = {
|
|
11
|
+
CREATE: ACTION_SIGNATURE_CREATE,
|
|
12
|
+
READ: ACTION_SIGNATURE_READ,
|
|
13
|
+
UPDATE: ACTION_SIGNATURE_UPDATE,
|
|
14
|
+
DELETE: ACTION_SIGNATURE_DELETE,
|
|
15
|
+
ANY: ACTION_SIGNATURE_ANY,
|
|
16
|
+
};
|
|
17
|
+
|
|
4
18
|
const OBJECT_STRING = "[object String]";
|
|
5
19
|
|
|
6
20
|
const DOCUMENT_OWNER_FIELD_NAME = "owner";
|
|
21
|
+
const TOKEN_TTL = 3600;
|
|
7
22
|
|
|
8
23
|
module.exports = {
|
|
24
|
+
TOKEN_TTL,
|
|
9
25
|
OBJECT_STRING,
|
|
10
26
|
DEFAULT_USER_ROLE_FOR_GUEST,
|
|
11
27
|
DEFAULT_USER_ROLE_FOR_ADMIN,
|
|
12
28
|
DOCUMENT_OWNER_FIELD_NAME,
|
|
29
|
+
ACTION_SIGNATURES,
|
|
13
30
|
};
|
package/src/auth/fields.js
CHANGED
|
@@ -6,7 +6,7 @@ const { objHas } = require("../common");
|
|
|
6
6
|
/**
|
|
7
7
|
* Get data owner ObjectId
|
|
8
8
|
* @param {Object} data Document Object
|
|
9
|
-
* @return {ObjectId|undefined} owner ObjectId or undefined if field is not found
|
|
9
|
+
* @return {import('mongoose').Schema.Types.ObjectId|undefined} owner ObjectId or undefined if field is not found
|
|
10
10
|
*/
|
|
11
11
|
function getOwnerId(data, ownerFieldName = CONST.DOCUMENT_OWNER_FIELD_NAME) {
|
|
12
12
|
if (typeof data !== "object") {
|
|
@@ -24,7 +24,7 @@ function getOwnerId(data, ownerFieldName = CONST.DOCUMENT_OWNER_FIELD_NAME) {
|
|
|
24
24
|
/**
|
|
25
25
|
* Check if data is belongs to user
|
|
26
26
|
* @param {Object} data object
|
|
27
|
-
* @param {ObjectId} user_id possible owner
|
|
27
|
+
* @param {import('mongoose').Schema.Types.ObjectId} user_id possible owner
|
|
28
28
|
* @return {boolean} true - belongs, false - not belongs
|
|
29
29
|
**/
|
|
30
30
|
|
|
@@ -34,7 +34,12 @@ function isOwner(
|
|
|
34
34
|
ownerFieldName = CONST.DOCUMENT_OWNER_FIELD_NAME
|
|
35
35
|
) {
|
|
36
36
|
const ownerId = getOwnerId(data, ownerFieldName);
|
|
37
|
-
|
|
37
|
+
console.log("ownerId", ownerId, typeof ownerId);
|
|
38
|
+
if (typeof ownerId !== "undefined") {
|
|
39
|
+
return COMMON.compareObjectIds(ownerId, user_id);
|
|
40
|
+
} else {
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
38
43
|
}
|
|
39
44
|
|
|
40
45
|
/**
|
|
@@ -57,7 +62,7 @@ function ruleIsWildcard(safeFor) {
|
|
|
57
62
|
* @param {Object} field description of field from schema
|
|
58
63
|
* @param {string} action action to check against
|
|
59
64
|
* @param {Array<string>} roles actor roles
|
|
60
|
-
* @param {string} special special relations of actor and target (@owner, @system)
|
|
65
|
+
* @param {Array<string>} special special relations of actor and target (@owner, @system)
|
|
61
66
|
* @return {boolean} true - safe
|
|
62
67
|
**/
|
|
63
68
|
function fieldIsSafe(field, action, roles, special) {
|
|
@@ -130,7 +135,7 @@ function getSafeFieldsForRoleAction(schema, action, roles, owner, system) {
|
|
|
130
135
|
* @param {string} action action to check against
|
|
131
136
|
* @param {Object} data source of data to extract from
|
|
132
137
|
* @param {Array<string>} roles actor roles
|
|
133
|
-
* @param {
|
|
138
|
+
* @param {import('mongoose').Schema.Types.ObjectId} actorId actor objectId
|
|
134
139
|
* @param {boolean} system true if actor is a system procedure
|
|
135
140
|
* @return {Object} object containing only data from safe fields
|
|
136
141
|
**/
|
package/src/auth/roles.js
CHANGED
|
@@ -26,8 +26,8 @@ function compareRolesStrict(userRoles, actionRoles) {
|
|
|
26
26
|
|
|
27
27
|
/**
|
|
28
28
|
* Compares two list of roles
|
|
29
|
-
* @param {array|string} userRoles roles of user
|
|
30
|
-
* @param {array|string} actionRoles roles of action
|
|
29
|
+
* @param {array|string|undefined} userRoles roles of user
|
|
30
|
+
* @param {array|string|undefined} actionRoles roles of action
|
|
31
31
|
* @param {boolean} strict if true userRoles should contain all of actionRoles. else atleast one
|
|
32
32
|
* @return {boolean} if user roles comply to action roles
|
|
33
33
|
**/
|
package/src/auth/rules.js
CHANGED
|
@@ -2,21 +2,43 @@ const ROLES = require("./roles");
|
|
|
2
2
|
const postWarning = require("../obsolete");
|
|
3
3
|
const { objHas } = require("../common");
|
|
4
4
|
|
|
5
|
+
/**
|
|
6
|
+
* check if rule contains requirement about root/admin(obs) status of requester
|
|
7
|
+
*
|
|
8
|
+
* @param {import('../types').notRouteRule} rule
|
|
9
|
+
* @return {boolean}
|
|
10
|
+
*/
|
|
5
11
|
function ruleHasRootDirective(rule) {
|
|
6
12
|
return (
|
|
7
|
-
(objHas(rule, "admin") && rule.admin) ||
|
|
8
|
-
(objHas(rule, "root") && rule.root)
|
|
13
|
+
(objHas(rule, "admin") && typeof rule.admin !== "undefined") ||
|
|
14
|
+
(objHas(rule, "root") && typeof rule.root !== "undefined")
|
|
9
15
|
);
|
|
10
16
|
}
|
|
11
17
|
|
|
18
|
+
/**
|
|
19
|
+
* checks if requester `root` state comply rule of route action
|
|
20
|
+
*
|
|
21
|
+
* @param {import('../types').notRouteRule} rule rule to comply
|
|
22
|
+
* @param {boolean} root actual requester state
|
|
23
|
+
* @return {boolean}
|
|
24
|
+
*/
|
|
12
25
|
function compareWithRoot(rule, root) {
|
|
13
26
|
if (objHas(rule, "admin")) {
|
|
14
|
-
return rule.admin && root;
|
|
27
|
+
return typeof rule.admin !== "undefined" && rule.admin && root;
|
|
15
28
|
} else {
|
|
16
|
-
return rule.root && root;
|
|
29
|
+
return typeof rule.root !== "undefined" && rule.root && root;
|
|
17
30
|
}
|
|
18
31
|
}
|
|
19
32
|
|
|
33
|
+
/**
|
|
34
|
+
* checks roles list (in strict mode) then if auth state check needed performs it
|
|
35
|
+
* returns true if all checks passed or false if needed failed
|
|
36
|
+
*
|
|
37
|
+
* @param {import('../types').notRouteRule} actionRule rule to comply
|
|
38
|
+
* @param {Array<string>} userRole array of user roles
|
|
39
|
+
* @param {boolean} auth if user authenticated
|
|
40
|
+
* @return {boolean}
|
|
41
|
+
*/
|
|
20
42
|
function compareRuleRoles(actionRule, userRole, auth) {
|
|
21
43
|
if (ROLES.compareRoles(userRole, actionRule.role)) {
|
|
22
44
|
if (objHas(actionRule, "auth")) {
|
|
@@ -33,14 +55,31 @@ function compareRuleRoles(actionRule, userRole, auth) {
|
|
|
33
55
|
}
|
|
34
56
|
}
|
|
35
57
|
|
|
58
|
+
/**
|
|
59
|
+
* checks if user in required state of authetification
|
|
60
|
+
*
|
|
61
|
+
* @param {boolean} requiredAuth
|
|
62
|
+
* @param {boolean} userAuth
|
|
63
|
+
* @return {boolean}
|
|
64
|
+
*/
|
|
36
65
|
function roleRequireAuthState(requiredAuth, userAuth) {
|
|
66
|
+
//to pass
|
|
67
|
+
//or true and true
|
|
37
68
|
if (requiredAuth && userAuth) {
|
|
38
69
|
return true;
|
|
39
70
|
} else {
|
|
71
|
+
//or !false && !false
|
|
40
72
|
return !requiredAuth && !userAuth;
|
|
41
73
|
}
|
|
42
74
|
}
|
|
43
75
|
|
|
76
|
+
/**
|
|
77
|
+
* default outcome - true, if no requirements in rule
|
|
78
|
+
*
|
|
79
|
+
* @param {import('../types').notRouteRule} rule rule to comply
|
|
80
|
+
* @param {boolean} auth actual state of requester
|
|
81
|
+
* @return {boolean}
|
|
82
|
+
*/
|
|
44
83
|
function compareAuthStatus(rule, auth) {
|
|
45
84
|
if (objHas(rule, "auth")) {
|
|
46
85
|
return roleRequireAuthState(rule.auth, auth);
|
|
@@ -53,14 +92,11 @@ function compareAuthStatus(rule, auth) {
|
|
|
53
92
|
|
|
54
93
|
/**
|
|
55
94
|
* Check rule against presented credentials
|
|
56
|
-
* @param {
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
* @
|
|
61
|
-
* @param {String|Array} role user state of role
|
|
62
|
-
* @param {Boolean} root user state of root
|
|
63
|
-
* @return {boolean} pass or not
|
|
95
|
+
* @param {import('../types').notRouteRule} rule action rule
|
|
96
|
+
* @param {boolean} auth user state of auth
|
|
97
|
+
* @param {string|Array<string>} role user state of role
|
|
98
|
+
* @param {boolean} root user state of root
|
|
99
|
+
* @return {boolean} pass or not
|
|
64
100
|
*/
|
|
65
101
|
function checkCredentials(rule, auth, role, root) {
|
|
66
102
|
//no rule - no access
|
|
@@ -68,7 +104,7 @@ function checkCredentials(rule, auth, role, root) {
|
|
|
68
104
|
return false;
|
|
69
105
|
} else {
|
|
70
106
|
//posting message about obsolete options keys if found
|
|
71
|
-
postWarning(rule);
|
|
107
|
+
postWarning.obsoleteRuleFields(rule);
|
|
72
108
|
//start comparing from top tier flags
|
|
73
109
|
//if we have root/admin(obsolete) field field in rule compare only it
|
|
74
110
|
if (ruleHasRootDirective(rule)) {
|
package/src/bootstrap/logic.js
CHANGED
|
@@ -15,17 +15,18 @@ module.exports = ({
|
|
|
15
15
|
const config = configInit.readerForModule(MODULE_NAME);
|
|
16
16
|
|
|
17
17
|
const LogAction = ({ action, by, role, ip, root }, params = {}) => {
|
|
18
|
-
Log
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
18
|
+
Log &&
|
|
19
|
+
Log.log({
|
|
20
|
+
time: new Date(),
|
|
21
|
+
module: MODULE_NAME,
|
|
22
|
+
logic: MODEL_NAME,
|
|
23
|
+
action,
|
|
24
|
+
root,
|
|
25
|
+
by,
|
|
26
|
+
role,
|
|
27
|
+
ip,
|
|
28
|
+
params,
|
|
29
|
+
});
|
|
29
30
|
};
|
|
30
31
|
|
|
31
32
|
return {
|
package/src/bootstrap/route.js
CHANGED
|
@@ -85,7 +85,7 @@ module.exports = ({
|
|
|
85
85
|
}
|
|
86
86
|
};
|
|
87
87
|
|
|
88
|
-
const createDefaultForm = function ({ actionName }) {
|
|
88
|
+
const createDefaultForm = function ({ actionName, MODULE_NAME }) {
|
|
89
89
|
const FIELDS = [
|
|
90
90
|
["activeUser", "not-node//requiredObject"],
|
|
91
91
|
["data", `${MODULE_NAME}//_data`],
|
package/src/common.js
CHANGED
|
@@ -44,6 +44,9 @@ module.exports.validateObjectId = (id) => {
|
|
|
44
44
|
*/
|
|
45
45
|
module.exports.compareObjectIds = (firstId, secondId) => {
|
|
46
46
|
try {
|
|
47
|
+
if (typeof firstId === "undefined" || typeof secondId === "undefined") {
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
47
50
|
let a = firstId,
|
|
48
51
|
b = secondId;
|
|
49
52
|
if (typeof firstId !== "string") {
|
|
@@ -182,6 +185,10 @@ module.exports.executeObjectFunction = async (obj, name, params) => {
|
|
|
182
185
|
}
|
|
183
186
|
};
|
|
184
187
|
|
|
188
|
+
module.exports.isNotEmptyString = (str) => {
|
|
189
|
+
return typeof str === "string" && str.length > 0 && str.trim().length > 0;
|
|
190
|
+
};
|
|
191
|
+
|
|
185
192
|
/**
|
|
186
193
|
* Executes method of object in apropriate way inside Promise
|
|
187
194
|
* @param {Object} from original object
|
|
@@ -0,0 +1,326 @@
|
|
|
1
|
+
const {
|
|
2
|
+
isFunc,
|
|
3
|
+
firstLetterToLower,
|
|
4
|
+
objHas,
|
|
5
|
+
isNotEmptyString,
|
|
6
|
+
} = require("../common");
|
|
7
|
+
const { getSafeFieldsForRoleAction } = require("../auth/fields");
|
|
8
|
+
const { DEFAULT_USER_ROLE_FOR_GUEST } = require("../auth/const");
|
|
9
|
+
/**
|
|
10
|
+
* notFilterFilter.filter(fields, getApp().getModelSchema(MODEL_NAME), {action});
|
|
11
|
+
*
|
|
12
|
+
* usage:
|
|
13
|
+
* manifest = {
|
|
14
|
+
* ...
|
|
15
|
+
* actions:{
|
|
16
|
+
* ...
|
|
17
|
+
* list:{
|
|
18
|
+
* rules:[{
|
|
19
|
+
* root: true,
|
|
20
|
+
* fields: notFilterFilter.filter(['@*'], getApp().getModelSchema(MODEL_NAME), {action:read});
|
|
21
|
+
* }]
|
|
22
|
+
* },
|
|
23
|
+
* profile:{
|
|
24
|
+
* method: 'get',
|
|
25
|
+
* rules:[{
|
|
26
|
+
* auth: true
|
|
27
|
+
* fields: []
|
|
28
|
+
* },{
|
|
29
|
+
* root: true
|
|
30
|
+
* }]
|
|
31
|
+
* },
|
|
32
|
+
* }
|
|
33
|
+
* ...
|
|
34
|
+
* }
|
|
35
|
+
*/
|
|
36
|
+
|
|
37
|
+
const OPERATOR_EXCLUDE = "-";
|
|
38
|
+
const SPECIAL_SET_PREFIX = "@";
|
|
39
|
+
|
|
40
|
+
//system special fields sets aka system specials
|
|
41
|
+
const SPECIAL_SET_ALL = "*";
|
|
42
|
+
const SPECIAL_SET_SAFE = "safe";
|
|
43
|
+
const SPECIAL_SET_UNSAFE = "unsafe";
|
|
44
|
+
const SPECIAL_SET_TIMESTAMPS = "timestamps";
|
|
45
|
+
const SPECIAL_SET_OWNAGE = "ownage";
|
|
46
|
+
const SPECIAL_SET_VERSIONING = "versioning";
|
|
47
|
+
const SPECIAL_SET_ID_NUMERIC = "ID";
|
|
48
|
+
const SPECIAL_SET_ID_UUID = "id";
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* @typedef {Object} FieldsFilteringModificators
|
|
52
|
+
* @property {string} [action] read, update
|
|
53
|
+
* @property {string} [modelName] name of the schema model
|
|
54
|
+
* @property {Array<string>} [roles] roles set
|
|
55
|
+
* @property {boolean} [owner] owner initiated action
|
|
56
|
+
* @property {boolean} [system] system initiated action
|
|
57
|
+
* @property {boolean} [root] root initiated action
|
|
58
|
+
* @property {boolean} [auth] authenticated user initiated action
|
|
59
|
+
*/
|
|
60
|
+
|
|
61
|
+
class notFieldsFilter {
|
|
62
|
+
static #USER_DEFINED_SETS = {};
|
|
63
|
+
|
|
64
|
+
static get userSets() {
|
|
65
|
+
return structuredClone(this.#USER_DEFINED_SETS);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
static addSet(name, fields) {
|
|
69
|
+
if (
|
|
70
|
+
!Object.values(this.specials).includes(name) &&
|
|
71
|
+
fields.every(isNotEmptyString)
|
|
72
|
+
) {
|
|
73
|
+
this.#USER_DEFINED_SETS[name] = fields;
|
|
74
|
+
return true;
|
|
75
|
+
}
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
static removeSet(name) {
|
|
80
|
+
if (objHas(this.#USER_DEFINED_SETS, name)) {
|
|
81
|
+
delete this.#USER_DEFINED_SETS[name];
|
|
82
|
+
return true;
|
|
83
|
+
}
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
static get specials() {
|
|
88
|
+
return {
|
|
89
|
+
ALL: SPECIAL_SET_ALL,
|
|
90
|
+
SAFE: SPECIAL_SET_SAFE,
|
|
91
|
+
UNSAFE: SPECIAL_SET_UNSAFE,
|
|
92
|
+
TIMESTAMPS: SPECIAL_SET_TIMESTAMPS,
|
|
93
|
+
OWNAGE: SPECIAL_SET_OWNAGE,
|
|
94
|
+
VERSIONING: SPECIAL_SET_VERSIONING,
|
|
95
|
+
ID_NUMERIC: SPECIAL_SET_ID_NUMERIC,
|
|
96
|
+
ID_UUID: SPECIAL_SET_ID_UUID,
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
static get specialSets() {
|
|
101
|
+
return {
|
|
102
|
+
...this.#USER_DEFINED_SETS,
|
|
103
|
+
[SPECIAL_SET_ALL]: (schema) => {
|
|
104
|
+
return [
|
|
105
|
+
`${SPECIAL_SET_PREFIX}${SPECIAL_SET_ID_UUID}`,
|
|
106
|
+
`${SPECIAL_SET_PREFIX}${SPECIAL_SET_ID_NUMERIC}`,
|
|
107
|
+
...Object.keys(schema),
|
|
108
|
+
];
|
|
109
|
+
},
|
|
110
|
+
[SPECIAL_SET_SAFE]: (
|
|
111
|
+
schema,
|
|
112
|
+
{
|
|
113
|
+
action = "",
|
|
114
|
+
roles = [DEFAULT_USER_ROLE_FOR_GUEST],
|
|
115
|
+
owner = false,
|
|
116
|
+
system = false,
|
|
117
|
+
}
|
|
118
|
+
) => {
|
|
119
|
+
return getSafeFieldsForRoleAction(
|
|
120
|
+
schema,
|
|
121
|
+
action,
|
|
122
|
+
roles,
|
|
123
|
+
owner,
|
|
124
|
+
system
|
|
125
|
+
);
|
|
126
|
+
},
|
|
127
|
+
[SPECIAL_SET_UNSAFE]: ["salt", "password"],
|
|
128
|
+
[SPECIAL_SET_TIMESTAMPS]: ["createdAt", "updatedAt"],
|
|
129
|
+
[SPECIAL_SET_OWNAGE]: ["owner", "ownerId", "ownerModel"],
|
|
130
|
+
[SPECIAL_SET_VERSIONING]: [
|
|
131
|
+
"__version",
|
|
132
|
+
"__versions",
|
|
133
|
+
"__closed",
|
|
134
|
+
"__latest",
|
|
135
|
+
"__v",
|
|
136
|
+
],
|
|
137
|
+
[SPECIAL_SET_ID_NUMERIC]: (schema, { modelName }) => {
|
|
138
|
+
return [`${firstLetterToLower(modelName)}ID`];
|
|
139
|
+
},
|
|
140
|
+
[SPECIAL_SET_ID_UUID]: ["_id"],
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
static getSpecialSetContent(setName, schema, mods) {
|
|
145
|
+
const setGenerator = this.specialSets[setName];
|
|
146
|
+
if (isFunc(setGenerator)) {
|
|
147
|
+
return [...setGenerator(schema, mods)];
|
|
148
|
+
} else {
|
|
149
|
+
return [...setGenerator];
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
static DEFAULT_SET = [`${SPECIAL_SET_PREFIX}${SPECIAL_SET_ALL}`];
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
*
|
|
157
|
+
*
|
|
158
|
+
* @static
|
|
159
|
+
* @param {Array<string>} fieldsSet
|
|
160
|
+
* @return {boolean}
|
|
161
|
+
* @memberof notFieldsFilter
|
|
162
|
+
*/
|
|
163
|
+
static isContainingSpecialSets(fieldsSet) {
|
|
164
|
+
return this.getFirstSpecialSetIndex(fieldsSet) > -1;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
static isExcludeOperation(fieldItem) {
|
|
168
|
+
return fieldItem.indexOf(OPERATOR_EXCLUDE) === 0;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
static getFirstExcludeOperationIndex(fieldsSet) {
|
|
172
|
+
return fieldsSet.findIndex((item) => this.isExcludeOperation(item));
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
static isContainingExcludeOperation(fieldsSet) {
|
|
176
|
+
return this.getFirstExcludeOperationIndex(fieldsSet) > -1;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
*
|
|
181
|
+
*
|
|
182
|
+
* @static
|
|
183
|
+
* @param {Array<string>} fieldsSet
|
|
184
|
+
* @return {number}
|
|
185
|
+
* @memberof notFieldsFilter
|
|
186
|
+
*/
|
|
187
|
+
static getFirstSpecialSetIndex(fieldsSet) {
|
|
188
|
+
return fieldsSet.findIndex((item) => this.isSpecialSet(item));
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
static isSpecialSet(name) {
|
|
192
|
+
// @something or -@something
|
|
193
|
+
return (
|
|
194
|
+
name.indexOf(SPECIAL_SET_PREFIX) === 0 ||
|
|
195
|
+
(name.indexOf(SPECIAL_SET_PREFIX) === 1 &&
|
|
196
|
+
name.indexOf(OPERATOR_EXCLUDE) === 0)
|
|
197
|
+
);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
*
|
|
202
|
+
*
|
|
203
|
+
* @static
|
|
204
|
+
* @param {string} name
|
|
205
|
+
* @return {string}
|
|
206
|
+
* @memberof notFieldsFilter
|
|
207
|
+
*/
|
|
208
|
+
static getSpecialSetNameFromFieldsSetItem(name) {
|
|
209
|
+
return name.substring(name.indexOf(SPECIAL_SET_PREFIX) + 1);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
static fieldsListIsNotPlain(fieldsList) {
|
|
213
|
+
return (
|
|
214
|
+
this.isContainingSpecialSets(fieldsList) ||
|
|
215
|
+
this.isContainingExcludeOperation(fieldsList)
|
|
216
|
+
);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
static applyExcludeOperationToFieldItem(fieldItem) {
|
|
220
|
+
if (this.isExcludeOperation(fieldItem)) {
|
|
221
|
+
return this.unmarkFieldToExlude(fieldItem);
|
|
222
|
+
} else {
|
|
223
|
+
return this.markFieldToExlude(fieldItem);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
static applyExludeOperationToFieldsItems(fields) {
|
|
228
|
+
return fields.map((item) =>
|
|
229
|
+
this.applyExcludeOperationToFieldItem(item)
|
|
230
|
+
);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* input field item marked to be included
|
|
235
|
+
* output field item marked to be exluded
|
|
236
|
+
* @static
|
|
237
|
+
* @param {string} field field
|
|
238
|
+
* @return {string} -field
|
|
239
|
+
* @memberof notFieldsFilter
|
|
240
|
+
*/
|
|
241
|
+
static markFieldToExlude(field) {
|
|
242
|
+
return `${OPERATOR_EXCLUDE}${field}`;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* input field item marked to be exluded
|
|
247
|
+
* output field item marked to be included
|
|
248
|
+
* @static
|
|
249
|
+
* @param {string} field -field
|
|
250
|
+
* @return {string} field
|
|
251
|
+
* @memberof notFieldsFilter
|
|
252
|
+
*/
|
|
253
|
+
static unmarkFieldToExlude(field) {
|
|
254
|
+
return field.substring(1);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* translates fields items with specials to plain fields names
|
|
259
|
+
*
|
|
260
|
+
* @static
|
|
261
|
+
* @param {Array<string>} fields
|
|
262
|
+
* @param {import('mongoose').SchemaDefinition} schema
|
|
263
|
+
* @param {FieldsFilteringModificators} [mods]
|
|
264
|
+
* @return {Array<string>}
|
|
265
|
+
* @memberof notFieldsFilter
|
|
266
|
+
*/
|
|
267
|
+
static specialsToPlain(fields, schema, mods) {
|
|
268
|
+
while (this.isContainingSpecialSets(fields)) {
|
|
269
|
+
const index = this.getFirstSpecialSetIndex(fields);
|
|
270
|
+
const specialSetItem = fields[index];
|
|
271
|
+
const specialSetName =
|
|
272
|
+
this.getSpecialSetNameFromFieldsSetItem(specialSetItem);
|
|
273
|
+
const exclude = this.isExcludeOperation(specialSetItem);
|
|
274
|
+
const fieldsToInsert = this.getSpecialSetContent(
|
|
275
|
+
specialSetName,
|
|
276
|
+
schema,
|
|
277
|
+
mods
|
|
278
|
+
);
|
|
279
|
+
const operationAppliedFieldsList = exclude
|
|
280
|
+
? this.applyExludeOperationToFieldsItems(fieldsToInsert)
|
|
281
|
+
: fieldsToInsert;
|
|
282
|
+
fields.splice(index, 1, ...operationAppliedFieldsList);
|
|
283
|
+
}
|
|
284
|
+
return fields;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
static removeExcludedFields(fields) {
|
|
288
|
+
const result = [...fields];
|
|
289
|
+
while (this.isContainingExcludeOperation(result)) {
|
|
290
|
+
let index = this.getFirstExcludeOperationIndex(result);
|
|
291
|
+
const fieldNameToExclude = this.unmarkFieldToExlude(result[index]);
|
|
292
|
+
result.splice(index, 1);
|
|
293
|
+
while (
|
|
294
|
+
result.indexOf(fieldNameToExclude) > -1 &&
|
|
295
|
+
result.indexOf(fieldNameToExclude) < index
|
|
296
|
+
) {
|
|
297
|
+
result.splice(result.indexOf(fieldNameToExclude), 1);
|
|
298
|
+
index--;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
return result;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
* Creates plain fields list from fields list with fields, synonyms, fields sets
|
|
306
|
+
* and exlude operations
|
|
307
|
+
* schema = {name, description, country, __versions, __version, __closed, __latest, __v}
|
|
308
|
+
* ['*','-@versioning'] -> [_id, name, description, country]
|
|
309
|
+
* exlude X exlude -> include
|
|
310
|
+
* some @fieldsSet = ['-name', 'country']
|
|
311
|
+
* ['-@fieldsSet'] -> ['name', '-country']
|
|
312
|
+
* @static
|
|
313
|
+
* @param {Array<string>} fieldsSet
|
|
314
|
+
* @param {import('mongoose').SchemaDefinition} schema
|
|
315
|
+
* @param {FieldsFilteringModificators} mods
|
|
316
|
+
* @return {Array<string>}
|
|
317
|
+
* @memberof notFieldsFilter
|
|
318
|
+
*/
|
|
319
|
+
static filter(fieldsSet, schema = {}, mods = { action: undefined }) {
|
|
320
|
+
const fields = [...fieldsSet];
|
|
321
|
+
this.specialsToPlain(fields, schema, mods);
|
|
322
|
+
return this.removeExcludedFields(fields);
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
module.exports = notFieldsFilter;
|
package/src/fields/index.js
CHANGED
|
@@ -17,7 +17,7 @@ module.exports.initFileSchemaFromFields = ({
|
|
|
17
17
|
to = DEFAULT_TO,
|
|
18
18
|
moduleName = "",
|
|
19
19
|
}) => {
|
|
20
|
-
const FIELDS = notPath.get(from, mod);
|
|
20
|
+
const FIELDS = notPath.get(from, mod, {});
|
|
21
21
|
if (FIELDS && Array.isArray(FIELDS)) {
|
|
22
22
|
const schema = module.exports.createSchemaFromFields(
|
|
23
23
|
app,
|
|
@@ -25,7 +25,7 @@ module.exports.initFileSchemaFromFields = ({
|
|
|
25
25
|
type,
|
|
26
26
|
moduleName
|
|
27
27
|
);
|
|
28
|
-
notPath.set(to, mod, schema);
|
|
28
|
+
notPath.set(to, mod, schema, undefined);
|
|
29
29
|
}
|
|
30
30
|
};
|
|
31
31
|
|
|
@@ -4,8 +4,11 @@
|
|
|
4
4
|
|
|
5
5
|
module.exports = {
|
|
6
6
|
ID: require("./ID.js"),
|
|
7
|
+
targetID: require("./ID.js"),
|
|
7
8
|
_id: require("./_id.js"),
|
|
9
|
+
targetId: require("./_id.js"),
|
|
8
10
|
activeUser: require("./activeUser.js"),
|
|
11
|
+
activeUserId: require("./activeUserId.js"),
|
|
9
12
|
ip: require("./ip.js"),
|
|
10
13
|
modelNameID: require("./modelNameID.js"),
|
|
11
14
|
query: require("./query.js"),
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
const notFilter = require("not-filter");
|
|
2
2
|
const getApp = require("../../getApp");
|
|
3
3
|
|
|
4
|
+
/**
|
|
5
|
+
*
|
|
6
|
+
* @param {import('../form')} form
|
|
7
|
+
* @param {import('../../types').notNodeExpressRequest} req
|
|
8
|
+
* @returns
|
|
9
|
+
*/
|
|
4
10
|
module.exports = (form, req) => {
|
|
5
11
|
const MODULE_NAME = form.getModuleName();
|
|
6
12
|
const MODEL_NAME = form.getModelName(req);
|