@vulkano/core 1.15.6 → 1.17.0
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/README.md +318 -51
- package/app.js +5 -7
- package/bootstrap/express.js +2 -1
- package/bootstrap/server.js +49 -20
- package/controllers/ScaffoldController.js +18 -0
- package/controllers/controllers.js +3 -3
- package/database/mongodb.js +6 -12
- package/database/scaffold.js +19 -5
- package/libs/ApiClient.js +44 -72
- package/libs/Encrypter.js +7 -3
- package/libs/Filter.js +5 -5
- package/libs/Jwt.js +3 -4
- package/libs/Merge.js +109 -0
- package/libs/Paginate.js +49 -38
- package/libs/VSError.js +0 -2
- package/libs/i18n.js +0 -16
- package/package.json +16 -26
- package/public/.gitignore +3 -0
- package/responses/vsr.js +12 -10
- package/.eslintignore +0 -8
- package/.gitattributes +0 -108
- package/.nvmrc +0 -1
- package/bun.lockb +0 -0
package/database/mongodb.js
CHANGED
|
@@ -2,13 +2,9 @@
|
|
|
2
2
|
* Database connection
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
const Promise = require('bluebird');
|
|
6
|
-
const paginate = require('mongoose-paginate-v2');
|
|
7
|
-
const merge = require('deepmerge');
|
|
8
|
-
|
|
9
5
|
const mongoose = require('mongoose');
|
|
10
|
-
|
|
11
|
-
|
|
6
|
+
const paginate = require('mongoose-paginate-v2');
|
|
7
|
+
const merge = require('../libs/Merge');
|
|
12
8
|
|
|
13
9
|
global.mongoose = mongoose;
|
|
14
10
|
global.Virtual = 'Virtual';
|
|
@@ -45,15 +41,13 @@ module.exports = async function loadDatabaseApplication() {
|
|
|
45
41
|
: (connection || null);
|
|
46
42
|
|
|
47
43
|
if (!toConnect) {
|
|
48
|
-
throw `Invalid
|
|
44
|
+
throw new Error(`Invalid connection to MongoDB with source "${connection}"`);
|
|
49
45
|
}
|
|
50
46
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
};
|
|
54
|
-
|
|
47
|
+
// Build connection props from user config; family defaults to 4 (IPv4)
|
|
48
|
+
// unless explicitly set to another value in database.config
|
|
55
49
|
const connectionProps = merge.all([
|
|
56
|
-
|
|
50
|
+
{ family: 4 },
|
|
57
51
|
(database ? database.config || {} : {})
|
|
58
52
|
]);
|
|
59
53
|
|
package/database/scaffold.js
CHANGED
|
@@ -80,13 +80,30 @@ module.exports = {
|
|
|
80
80
|
*/
|
|
81
81
|
update(_id, data) {
|
|
82
82
|
|
|
83
|
+
// Blocklist: these fields are never writable from outside
|
|
84
|
+
const BLOCKED = ['_id', 'createdAt', '__v'];
|
|
85
|
+
const sanitized = { ...data };
|
|
86
|
+
BLOCKED.forEach((field) => delete sanitized[field]);
|
|
87
|
+
|
|
88
|
+
// Allowlist: if fillable is defined and non-empty, only those fields pass through
|
|
89
|
+
const { fillable } = this;
|
|
90
|
+
let filtered = sanitized;
|
|
91
|
+
if (Array.isArray(fillable) && fillable.length > 0) {
|
|
92
|
+
filtered = {};
|
|
93
|
+
fillable.forEach((field) => {
|
|
94
|
+
if (sanitized[field] !== undefined) {
|
|
95
|
+
filtered[field] = sanitized[field];
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
|
|
83
100
|
return this.getByField(_id)
|
|
84
101
|
.then( (record) => {
|
|
85
102
|
|
|
86
103
|
// Merge current info with incoming values
|
|
87
104
|
const merged = {
|
|
88
105
|
...record,
|
|
89
|
-
...
|
|
106
|
+
...filtered,
|
|
90
107
|
updatedAt: Date.now()
|
|
91
108
|
};
|
|
92
109
|
|
|
@@ -110,10 +127,7 @@ module.exports = {
|
|
|
110
127
|
*/
|
|
111
128
|
delete(id) {
|
|
112
129
|
|
|
113
|
-
//
|
|
114
|
-
// const Model = global[modelName];
|
|
115
|
-
|
|
116
|
-
// Soft delete
|
|
130
|
+
// Soft delete: set active=false instead of removing the document
|
|
117
131
|
return this.update(id, { active: false });
|
|
118
132
|
|
|
119
133
|
},
|
package/libs/ApiClient.js
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
const
|
|
2
|
-
const https = require('https');
|
|
3
|
-
const axios = require('axios');
|
|
1
|
+
const { Agent } = require('undici');
|
|
4
2
|
|
|
5
3
|
module.exports = {
|
|
6
4
|
|
|
@@ -12,13 +10,7 @@ module.exports = {
|
|
|
12
10
|
* @returns {Promise}
|
|
13
11
|
*/
|
|
14
12
|
get(url, props) {
|
|
15
|
-
|
|
16
|
-
return this.send({
|
|
17
|
-
url,
|
|
18
|
-
...props,
|
|
19
|
-
method: 'GET'
|
|
20
|
-
});
|
|
21
|
-
|
|
13
|
+
return this.send({ url, ...props, method: 'GET' });
|
|
22
14
|
},
|
|
23
15
|
|
|
24
16
|
/**
|
|
@@ -30,14 +22,7 @@ module.exports = {
|
|
|
30
22
|
* @returns {Promise}
|
|
31
23
|
*/
|
|
32
24
|
post(url, body, props) {
|
|
33
|
-
|
|
34
|
-
return this.send({
|
|
35
|
-
url,
|
|
36
|
-
body,
|
|
37
|
-
...props,
|
|
38
|
-
method: 'POST'
|
|
39
|
-
});
|
|
40
|
-
|
|
25
|
+
return this.send({ url, body, ...props, method: 'POST' });
|
|
41
26
|
},
|
|
42
27
|
|
|
43
28
|
/**
|
|
@@ -49,32 +34,18 @@ module.exports = {
|
|
|
49
34
|
* @returns {Promise}
|
|
50
35
|
*/
|
|
51
36
|
put(url, body, props) {
|
|
52
|
-
|
|
53
|
-
return this.send({
|
|
54
|
-
url,
|
|
55
|
-
body,
|
|
56
|
-
...props,
|
|
57
|
-
method: 'PUT'
|
|
58
|
-
});
|
|
59
|
-
|
|
37
|
+
return this.send({ url, body, ...props, method: 'PUT' });
|
|
60
38
|
},
|
|
61
39
|
|
|
62
40
|
/**
|
|
63
41
|
* Method to make a DELETE request
|
|
64
42
|
*
|
|
65
43
|
* @param {String} url
|
|
66
|
-
* @param {Object} body
|
|
67
44
|
* @param {Object} props { headers }
|
|
68
45
|
* @returns {Promise}
|
|
69
46
|
*/
|
|
70
47
|
delete(url, props) {
|
|
71
|
-
|
|
72
|
-
return this.send({
|
|
73
|
-
url,
|
|
74
|
-
...props,
|
|
75
|
-
method: 'DELETE'
|
|
76
|
-
});
|
|
77
|
-
|
|
48
|
+
return this.send({ url, ...props, method: 'DELETE' });
|
|
78
49
|
},
|
|
79
50
|
|
|
80
51
|
/**
|
|
@@ -83,77 +54,78 @@ module.exports = {
|
|
|
83
54
|
* @param {Object} props
|
|
84
55
|
* @returns {Promise}
|
|
85
56
|
*/
|
|
86
|
-
send(props) {
|
|
57
|
+
async send(props) {
|
|
87
58
|
|
|
88
59
|
const {
|
|
89
60
|
url,
|
|
90
61
|
body,
|
|
91
62
|
method,
|
|
92
63
|
responseType,
|
|
93
|
-
headers
|
|
64
|
+
headers,
|
|
65
|
+
rejectUnauthorized
|
|
94
66
|
} = typeof props === 'string'
|
|
95
|
-
? {
|
|
67
|
+
? { url: props, method: 'GET' }
|
|
96
68
|
: (props || {});
|
|
97
69
|
|
|
70
|
+
// SSL verification is enabled by default; pass rejectUnauthorized: false to disable
|
|
71
|
+
const sslVerify = rejectUnauthorized !== false;
|
|
72
|
+
|
|
98
73
|
const optHeaders = {
|
|
99
74
|
'Content-Type': 'application/json',
|
|
100
|
-
Accept: 'application/json'
|
|
75
|
+
Accept: 'application/json',
|
|
76
|
+
...(headers || {})
|
|
101
77
|
};
|
|
102
78
|
|
|
103
79
|
const options = {
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
httpAgent: new http.Agent({ keepAlive: true, rejectUnauthorized: false }),
|
|
108
|
-
httpsAgent: new https.Agent({ keepAlive: true, rejectUnauthorized: false }),
|
|
109
|
-
responseType: responseType || 'json'
|
|
80
|
+
method: (method || 'GET').toUpperCase(),
|
|
81
|
+
headers: optHeaders,
|
|
82
|
+
dispatcher: new Agent({ connect: { rejectUnauthorized: sslVerify } })
|
|
110
83
|
};
|
|
111
84
|
|
|
112
85
|
if (body) {
|
|
113
|
-
|
|
114
|
-
options.data = JSON.parse(JSON.stringify(body || {}));
|
|
86
|
+
options.body = JSON.stringify(body);
|
|
115
87
|
}
|
|
116
88
|
|
|
117
|
-
|
|
118
|
-
.then( (response) => {
|
|
89
|
+
const target = `${options.method} ${url}`;
|
|
119
90
|
|
|
120
|
-
|
|
121
|
-
data
|
|
122
|
-
} = response;
|
|
91
|
+
try {
|
|
123
92
|
|
|
124
|
-
|
|
93
|
+
const response = await fetch(url, options);
|
|
125
94
|
|
|
126
|
-
|
|
127
|
-
.catch( (err) => {
|
|
95
|
+
if (!response.ok) {
|
|
128
96
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
} = err || {};
|
|
97
|
+
let errorData = {};
|
|
98
|
+
try { errorData = await response.json(); } catch (_) {}
|
|
132
99
|
|
|
133
|
-
const {
|
|
134
|
-
|
|
135
|
-
status: statusCode
|
|
136
|
-
} = response || {};
|
|
137
|
-
|
|
138
|
-
const target = options.baseURL ? `${options.method} ${options.baseURL}/${options.url}` : `${options.method} ${options.url}`;
|
|
100
|
+
const { msg, message: errorMessage, error: errorMessage2 } = errorData || {};
|
|
101
|
+
const message = msg || errorMessage || errorMessage2 || 'Unable to connect to the Request Service';
|
|
139
102
|
|
|
140
|
-
console.log('');
|
|
141
103
|
console.log('');
|
|
142
104
|
console.log('---------------------');
|
|
143
105
|
console.log('ApiClient', target);
|
|
144
106
|
console.log('---------------------');
|
|
145
107
|
|
|
146
|
-
|
|
147
|
-
msg,
|
|
148
|
-
message: errorMessage,
|
|
149
|
-
error: errorMessage2
|
|
150
|
-
} = errorData || {};
|
|
108
|
+
return VSError.reject(message, response.status || 500);
|
|
151
109
|
|
|
152
|
-
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (responseType === 'arraybuffer') return response.arrayBuffer();
|
|
113
|
+
if (responseType === 'text') return response.text();
|
|
114
|
+
if (responseType === 'stream') return response.body;
|
|
115
|
+
|
|
116
|
+
const data = await response.json();
|
|
117
|
+
return data || {};
|
|
153
118
|
|
|
154
|
-
|
|
119
|
+
} catch (err) {
|
|
155
120
|
|
|
156
|
-
|
|
121
|
+
console.log('');
|
|
122
|
+
console.log('---------------------');
|
|
123
|
+
console.log('ApiClient', target);
|
|
124
|
+
console.log('---------------------');
|
|
125
|
+
|
|
126
|
+
return VSError.reject(err.message || 'Unable to connect to the Request Service', 500);
|
|
127
|
+
|
|
128
|
+
}
|
|
157
129
|
|
|
158
130
|
}
|
|
159
131
|
|
package/libs/Encrypter.js
CHANGED
|
@@ -2,10 +2,14 @@ const crypto = require('crypto');
|
|
|
2
2
|
|
|
3
3
|
class Encrypter {
|
|
4
4
|
|
|
5
|
-
constructor(encryptionKey) {
|
|
5
|
+
constructor(encryptionKey, opts = {}) {
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
const { encryption } = (typeof app !== 'undefined' && app.config) ? app.config : {};
|
|
8
|
+
const salt = opts.salt || (encryption && encryption.salt) || process.env.ENCRYPTION_SALT || 'vulkano-salt-v1';
|
|
9
|
+
const algorithm = opts.algorithm || (encryption && encryption.algorithm) || process.env.ENCRYPTION_ALGORITHM || 'aes-256-cbc';
|
|
10
|
+
|
|
11
|
+
this.algorithm = algorithm;
|
|
12
|
+
this.key = crypto.scryptSync(encryptionKey, salt, 32);
|
|
9
13
|
|
|
10
14
|
}
|
|
11
15
|
|
package/libs/Filter.js
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
const path = require('path');
|
|
9
9
|
|
|
10
|
-
//
|
|
10
|
+
// Load built-in core filters and app-level custom filters
|
|
11
11
|
const coreFilters = require('include-all')({
|
|
12
12
|
dirname: path.join(CORE_PATH, '/libs/filters'),
|
|
13
13
|
filter: /(.+)\.js$/,
|
|
@@ -24,14 +24,14 @@ const allFilters = { ...coreFilters, ...appFilters };
|
|
|
24
24
|
|
|
25
25
|
module.exports = {
|
|
26
26
|
|
|
27
|
-
get(str, filters, opts) {
|
|
27
|
+
get(str, filters, opts) {
|
|
28
28
|
|
|
29
29
|
if (Array.isArray(filters)) {
|
|
30
30
|
|
|
31
31
|
let result = str;
|
|
32
|
-
|
|
32
|
+
|
|
33
33
|
filters.forEach((filter) => {
|
|
34
|
-
const f =
|
|
34
|
+
const f = this.load(filter);
|
|
35
35
|
result = (!f) ? '' : f.exec(result, opts);
|
|
36
36
|
});
|
|
37
37
|
|
|
@@ -39,7 +39,7 @@ module.exports = {
|
|
|
39
39
|
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
-
const f =
|
|
42
|
+
const f = this.load(filters);
|
|
43
43
|
return (!f) ? '' : f.exec(str, opts);
|
|
44
44
|
|
|
45
45
|
},
|
package/libs/Jwt.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
const { expressjwt: JWT } = require('express-jwt');
|
|
2
2
|
const jwtSimple = require('jwt-simple');
|
|
3
|
-
const moment = require('moment');
|
|
4
3
|
|
|
5
4
|
module.exports = {
|
|
6
5
|
|
|
@@ -13,7 +12,7 @@ module.exports = {
|
|
|
13
12
|
|
|
14
13
|
const {
|
|
15
14
|
jwt,
|
|
16
|
-
// Express config folder in app/
|
|
15
|
+
// Express config folder in app/config/express
|
|
17
16
|
express
|
|
18
17
|
} = app.config || {};
|
|
19
18
|
|
|
@@ -143,7 +142,7 @@ module.exports = {
|
|
|
143
142
|
expiration
|
|
144
143
|
} = data || {};
|
|
145
144
|
|
|
146
|
-
const now =
|
|
145
|
+
const now = String(Date.now());
|
|
147
146
|
|
|
148
147
|
// Token expired
|
|
149
148
|
if (expiration && ( Number(now) > Number(expiration) )) {
|
|
@@ -166,7 +165,7 @@ module.exports = {
|
|
|
166
165
|
},
|
|
167
166
|
|
|
168
167
|
/**
|
|
169
|
-
*
|
|
168
|
+
* Decrypt token payload
|
|
170
169
|
*
|
|
171
170
|
* @param {String} str
|
|
172
171
|
* @returns {String}
|
package/libs/Merge.js
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
function isMergeableObject(value) {
|
|
2
|
+
return value !== null
|
|
3
|
+
&& typeof value === 'object'
|
|
4
|
+
&& !(value instanceof RegExp)
|
|
5
|
+
&& !(value instanceof Date);
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
function emptyTarget(val) {
|
|
9
|
+
return Array.isArray(val) ? [] : {};
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function cloneUnlessOtherwiseSpecified(value, options) {
|
|
13
|
+
return (options.clone !== false && options.isMergeableObject(value))
|
|
14
|
+
? merge(emptyTarget(value), value, options) // eslint-disable-line no-use-before-define
|
|
15
|
+
: value;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function defaultArrayMerge(target, source, options) {
|
|
19
|
+
return target.concat(source).map((element) => cloneUnlessOtherwiseSpecified(element, options));
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function getMergeFunction(key, options) {
|
|
23
|
+
if (!options.customMerge) return merge; // eslint-disable-line no-use-before-define
|
|
24
|
+
const custom = options.customMerge(key);
|
|
25
|
+
return typeof custom === 'function' ? custom : merge; // eslint-disable-line no-use-before-define
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function getKeys(target) {
|
|
29
|
+
const keys = Object.keys(target);
|
|
30
|
+
if (Object.getOwnPropertySymbols) {
|
|
31
|
+
Object.getOwnPropertySymbols(target).forEach((sym) => {
|
|
32
|
+
if (Object.propertyIsEnumerable.call(target, sym)) {
|
|
33
|
+
keys.push(sym);
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
return keys;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function propertyIsOnObject(object, property) {
|
|
41
|
+
try {
|
|
42
|
+
return property in object;
|
|
43
|
+
} catch (_) {
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function propertyIsUnsafe(target, key) {
|
|
49
|
+
return propertyIsOnObject(target, key)
|
|
50
|
+
&& !(Object.prototype.hasOwnProperty.call(target, key)
|
|
51
|
+
&& Object.propertyIsEnumerable.call(target, key));
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function mergeObject(target, source, options) {
|
|
55
|
+
|
|
56
|
+
const destination = {};
|
|
57
|
+
|
|
58
|
+
if (options.isMergeableObject(target)) {
|
|
59
|
+
getKeys(target).forEach((key) => {
|
|
60
|
+
destination[key] = cloneUnlessOtherwiseSpecified(target[key], options);
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
getKeys(source).forEach((key) => {
|
|
65
|
+
|
|
66
|
+
if (propertyIsUnsafe(target, key)) return;
|
|
67
|
+
|
|
68
|
+
if (propertyIsOnObject(target, key) && options.isMergeableObject(source[key])) {
|
|
69
|
+
destination[key] = getMergeFunction(key, options)(target[key], source[key], options);
|
|
70
|
+
} else {
|
|
71
|
+
destination[key] = cloneUnlessOtherwiseSpecified(source[key], options);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
return destination;
|
|
77
|
+
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function merge(target, source, options) {
|
|
81
|
+
|
|
82
|
+
const opts = options || {};
|
|
83
|
+
opts.arrayMerge = opts.arrayMerge || defaultArrayMerge;
|
|
84
|
+
opts.isMergeableObject = opts.isMergeableObject || isMergeableObject;
|
|
85
|
+
opts.cloneUnlessOtherwiseSpecified = cloneUnlessOtherwiseSpecified;
|
|
86
|
+
|
|
87
|
+
const sourceIsArray = Array.isArray(source);
|
|
88
|
+
const targetIsArray = Array.isArray(target);
|
|
89
|
+
|
|
90
|
+
if (sourceIsArray !== targetIsArray) {
|
|
91
|
+
return cloneUnlessOtherwiseSpecified(source, opts);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (sourceIsArray) {
|
|
95
|
+
return opts.arrayMerge(target, source, opts);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return mergeObject(target, source, opts);
|
|
99
|
+
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
merge.all = function mergeAll(array, options) {
|
|
103
|
+
if (!Array.isArray(array)) {
|
|
104
|
+
throw new Error('first argument should be an array');
|
|
105
|
+
}
|
|
106
|
+
return array.reduce((prev, next) => merge(prev, next, options), {});
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
module.exports = merge;
|
package/libs/Paginate.js
CHANGED
|
@@ -1,34 +1,43 @@
|
|
|
1
|
-
|
|
1
|
+
// Built once when the module loads: maps each base letter to a character class
|
|
2
|
+
// containing all its accented variants. Pre-compiling the RegExp objects avoids
|
|
3
|
+
// rebuilding them on every accentToRegex() call.
|
|
4
|
+
const _ACCENT_MAP = (() => {
|
|
5
|
+
|
|
6
|
+
const from = 'ŠŒŽšœžŸ¥µÀÁÂÃÄÅÆÇÈÉÊËẼÌÍÎÏĨÐÑÒÓÔÕÖØÙÚÛÜÝßàáâãäåæçèéêëẽìíîïĩðñòóôõöøùúûüýÿ'.split('');
|
|
7
|
+
const to = 'SOZsozYYuAAAAAAACEEEEEIIIIIDNOOOOOOUUUUYsaaaaaaaceeeeeiiiiionoooooouuuuyy'.split('');
|
|
8
|
+
|
|
9
|
+
const groups = [];
|
|
10
|
+
|
|
11
|
+
to.forEach((letter, key) => {
|
|
12
|
+
const exist = groups.indexOf(letter);
|
|
13
|
+
if (exist >= 0) {
|
|
14
|
+
groups[exist] += from[key];
|
|
15
|
+
} else {
|
|
16
|
+
groups.push(letter);
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
return groups.map((rg, key) => ({
|
|
21
|
+
charClass: new RegExp(`[${rg}]`),
|
|
22
|
+
placeholder: new RegExp(`_${key}_`),
|
|
23
|
+
expanded: `[${rg}]`,
|
|
24
|
+
key
|
|
25
|
+
}));
|
|
26
|
+
|
|
27
|
+
})();
|
|
2
28
|
|
|
3
29
|
module.exports = {
|
|
4
30
|
|
|
5
31
|
accentToRegex(_text) {
|
|
6
32
|
|
|
7
|
-
const ACCENT_STRINGS = 'ŠŒŽšœžŸ¥µÀÁÂÃÄÅÆÇÈÉÊËẼÌÍÎÏĨÐÑÒÓÔÕÖØÙÚÛÜÝßàáâãäåæçèéêëẽìíîïĩðñòóôõöøùúûüýÿ';
|
|
8
|
-
const NO_ACCENT_STRINGS = 'SOZsozYYuAAAAAAACEEEEEIIIIIDNOOOOOOUUUUYsaaaaaaaceeeeeiiiiionoooooouuuuyy';
|
|
9
|
-
|
|
10
|
-
const from = ACCENT_STRINGS.split('');
|
|
11
|
-
const to = NO_ACCENT_STRINGS.split('');
|
|
12
|
-
const result = [];
|
|
13
33
|
let text = _text;
|
|
14
34
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
if (exist >= 0) {
|
|
18
|
-
result[exist] += from[key];
|
|
19
|
-
} else {
|
|
20
|
-
result.push(letter);
|
|
21
|
-
}
|
|
35
|
+
_ACCENT_MAP.forEach(({ charClass, key }) => {
|
|
36
|
+
text = text.replace(charClass, `_${key}_`);
|
|
22
37
|
});
|
|
23
38
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
text = text.replace(regex, `_${key}_`);
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
result.forEach( (rg, key) => {
|
|
30
|
-
const regex = new RegExp(`_${key}_`);
|
|
31
|
-
text = text.replace(regex, `[${rg}]`);
|
|
39
|
+
_ACCENT_MAP.forEach(({ placeholder, expanded }) => {
|
|
40
|
+
text = text.replace(placeholder, expanded);
|
|
32
41
|
});
|
|
33
42
|
|
|
34
43
|
return text;
|
|
@@ -50,13 +59,11 @@ module.exports = {
|
|
|
50
59
|
const search = query.search || props.search || null;
|
|
51
60
|
const searchType = (query.searchType || '').toLowerCase().replace('-', '');
|
|
52
61
|
|
|
53
|
-
const result =
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
search
|
|
59
|
-
}, (value) => !value );
|
|
62
|
+
const result = Object.fromEntries(
|
|
63
|
+
Object.entries({
|
|
64
|
+
page, perPage, fields, sort, search
|
|
65
|
+
}).filter(([, v]) => v)
|
|
66
|
+
);
|
|
60
67
|
|
|
61
68
|
// Filter by search
|
|
62
69
|
const searchBy = props.searchBy || [];
|
|
@@ -77,12 +84,16 @@ module.exports = {
|
|
|
77
84
|
|
|
78
85
|
if (type === String) {
|
|
79
86
|
|
|
87
|
+
const safeSearch = this.accentToRegex(
|
|
88
|
+
search.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&')
|
|
89
|
+
);
|
|
90
|
+
|
|
80
91
|
if (searchType === 'startwith' || searchType === 'start') {
|
|
81
|
-
row[item] = new RegExp(
|
|
92
|
+
row[item] = new RegExp(`^${safeSearch}`, 'i');
|
|
82
93
|
} else if (searchType === 'endwith' || searchType === 'end') {
|
|
83
|
-
row[item] = new RegExp(
|
|
94
|
+
row[item] = new RegExp(`${safeSearch}$`, 'i');
|
|
84
95
|
} else {
|
|
85
|
-
row[item] = new RegExp(
|
|
96
|
+
row[item] = new RegExp(safeSearch, 'i');
|
|
86
97
|
}
|
|
87
98
|
|
|
88
99
|
} else if (type === Number) {
|
|
@@ -199,7 +210,7 @@ module.exports = {
|
|
|
199
210
|
|
|
200
211
|
const populate = hasPopulate || [];
|
|
201
212
|
|
|
202
|
-
|
|
213
|
+
const criteria = query || {};
|
|
203
214
|
|
|
204
215
|
// Setup
|
|
205
216
|
const page = criteria.page === 'all' ? 'all' : ( parseInt(criteria.page, 10) || 1);
|
|
@@ -236,16 +247,16 @@ module.exports = {
|
|
|
236
247
|
delete criteria.sort;
|
|
237
248
|
|
|
238
249
|
if (criteria.search) {
|
|
239
|
-
|
|
250
|
+
Object.assign(criteria, criteria.search);
|
|
240
251
|
delete criteria.search;
|
|
241
252
|
}
|
|
242
253
|
|
|
243
254
|
const optPopulate = this.getPopulatedCollections(populate || []);
|
|
244
|
-
const queryModel =
|
|
255
|
+
const queryModel = { ...criteria };
|
|
245
256
|
|
|
246
257
|
if (page === 'all') {
|
|
247
258
|
|
|
248
|
-
const optsModel =
|
|
259
|
+
const optsModel = { ...sort, populate: optPopulate };
|
|
249
260
|
return Model.find(queryModel, fields.join(' '), optsModel);
|
|
250
261
|
|
|
251
262
|
}
|
|
@@ -265,7 +276,7 @@ module.exports = {
|
|
|
265
276
|
|
|
266
277
|
opts.populate = optPopulate;
|
|
267
278
|
|
|
268
|
-
const optsModel =
|
|
279
|
+
const optsModel = { ...opts, ...sort };
|
|
269
280
|
|
|
270
281
|
return Model
|
|
271
282
|
.paginate(queryModel, optsModel)
|
|
@@ -282,7 +293,7 @@ module.exports = {
|
|
|
282
293
|
|
|
283
294
|
let cursor = (page > 1) ? ((page * perPage) - (perPage - 1)) : 1;
|
|
284
295
|
|
|
285
|
-
const tmpNext = (((perPage * (page - 1)) + perPage)
|
|
296
|
+
const tmpNext = (((perPage * (page - 1)) + perPage) < total);
|
|
286
297
|
const next = tmpNext ? (page + 1) : false;
|
|
287
298
|
let prev = (page > 1) ? (page - 1) : false;
|
|
288
299
|
const totalPages = Math.ceil(total / perPage);
|
package/libs/VSError.js
CHANGED
package/libs/i18n.js
CHANGED
|
@@ -1,9 +1,4 @@
|
|
|
1
1
|
const i18next = require('i18next');
|
|
2
|
-
const moment = require('moment');
|
|
3
|
-
|
|
4
|
-
require('moment/min/locales.min');
|
|
5
|
-
|
|
6
|
-
moment.locale('en');
|
|
7
2
|
|
|
8
3
|
module.exports = (() => {
|
|
9
4
|
|
|
@@ -35,17 +30,6 @@ module.exports = (() => {
|
|
|
35
30
|
resources: Object.fromEntries(resources)
|
|
36
31
|
});
|
|
37
32
|
|
|
38
|
-
// catch the event and make changes accordingly
|
|
39
|
-
i18next.on('languageChanged', (lng) => {
|
|
40
|
-
|
|
41
|
-
try {
|
|
42
|
-
moment.locale(lng);
|
|
43
|
-
} catch (err) {
|
|
44
|
-
console.log(err);
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
});
|
|
48
|
-
|
|
49
33
|
return i18next;
|
|
50
34
|
|
|
51
35
|
})();
|