@questwork/q-utilities 0.1.15 → 0.1.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.min.cjs +117 -29
- package/dist/q-utilities.esm.js +117 -30
- package/dist/q-utilities.min.js +117 -29
- package/package.json +1 -1
package/dist/index.min.cjs
CHANGED
|
@@ -84,20 +84,21 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
84
84
|
sanitizeText: () => (/* reexport */ sanitizeText),
|
|
85
85
|
stringFormatter: () => (/* reexport */ stringFormatter),
|
|
86
86
|
stringHelper: () => (/* reexport */ stringHelper),
|
|
87
|
+
tenantPlugin: () => (/* reexport */ tenantPlugin),
|
|
87
88
|
trackingPlugin: () => (/* reexport */ trackingPlugin)
|
|
88
89
|
});
|
|
89
90
|
|
|
90
91
|
;// ./lib/helpers/authorize/authorize.js
|
|
91
|
-
function authorize({ allowOwner, query = {}, required, user }) {
|
|
92
|
+
function authorize({ allowCoordinator, allowOwner, query = {}, required, user }) {
|
|
92
93
|
if (!user) {
|
|
93
94
|
throw new Error('Require login.')
|
|
94
95
|
}
|
|
95
96
|
if (!user.permission) {
|
|
96
|
-
throw new Error('You do not have any permission.')
|
|
97
|
+
// throw new Error('You do not have any permission.')
|
|
97
98
|
}
|
|
98
|
-
const scopes = user.permission.getScopes(required || {})
|
|
99
|
+
const scopes = user.permission.getScopes(required || {}) || []
|
|
99
100
|
if (!scopes || scopes.length === 0) {
|
|
100
|
-
throw new Error('You are not allowed in this scope.')
|
|
101
|
+
// throw new Error('You are not allowed in this scope.')
|
|
101
102
|
}
|
|
102
103
|
if (!scopes.includes('*')) {
|
|
103
104
|
query.tenantCode = user.tenantCode
|
|
@@ -105,8 +106,21 @@ function authorize({ allowOwner, query = {}, required, user }) {
|
|
|
105
106
|
if (!scopes.includes('TENANT')) {
|
|
106
107
|
query.eventShortCode = user.eventShortCode
|
|
107
108
|
}
|
|
108
|
-
if (!scopes.includes('EVENT')) {
|
|
109
|
-
|
|
109
|
+
// if (!scopes.includes('EVENT')) {
|
|
110
|
+
// query.eventRegistrationCode = user.eventRegistrationCode
|
|
111
|
+
// }
|
|
112
|
+
if (allowCoordinator) {
|
|
113
|
+
if (query.registrationGroupCode && user.myManagedRegistrationGroupCodes.includes(query.registrationGroupCode)) {
|
|
114
|
+
query.__ALLOW_COORDINATOR = true
|
|
115
|
+
} else {
|
|
116
|
+
if (!scopes.includes('EVENT')) {
|
|
117
|
+
query.eventRegistrationCode = user.eventRegistrationCode
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
} else {
|
|
121
|
+
if (!scopes.includes('EVENT')) {
|
|
122
|
+
query.eventRegistrationCode = user.eventRegistrationCode
|
|
123
|
+
}
|
|
110
124
|
}
|
|
111
125
|
if (allowOwner) {
|
|
112
126
|
query.__ALLOW_OWNER = true
|
|
@@ -1486,7 +1500,7 @@ function convertString(string, patternMatch = /\$\{(.+?)\}/g, value, getValueByK
|
|
|
1486
1500
|
if (!string) {
|
|
1487
1501
|
return ''
|
|
1488
1502
|
}
|
|
1489
|
-
let _getValueByKeys = typeof getValueByKeys
|
|
1503
|
+
let _getValueByKeys = typeof getValueByKeys === 'function' ? getValueByKeys : getValueByKeys_getValueByKeys
|
|
1490
1504
|
const reg = new RegExp(patternMatch, 'g')
|
|
1491
1505
|
return string.replace(reg, (match, key) => {
|
|
1492
1506
|
const result = _getValueByKeys({ keys: key.split('.'), obj: value })
|
|
@@ -1507,7 +1521,7 @@ function convertString(string, patternMatch = /\$\{(.+?)\}/g, value, getValueByK
|
|
|
1507
1521
|
|
|
1508
1522
|
;// ./lib/helpers/escapeRegex/escapeRegex.js
|
|
1509
1523
|
function escapeRegex(string) {
|
|
1510
|
-
return string.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&')
|
|
1524
|
+
return String(string).replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&')
|
|
1511
1525
|
}
|
|
1512
1526
|
|
|
1513
1527
|
;// ./lib/helpers/escapeRegex/index.js
|
|
@@ -1943,19 +1957,19 @@ class Repo {
|
|
|
1943
1957
|
})
|
|
1944
1958
|
}
|
|
1945
1959
|
|
|
1946
|
-
saveAll({ docs, systemLog }) {
|
|
1960
|
+
saveAll({ config = {}, docs, systemLog }) {
|
|
1947
1961
|
let isNew
|
|
1948
1962
|
const log = _makeLog({
|
|
1949
1963
|
systemLog,
|
|
1950
1964
|
label: 'REPO_WRITE',
|
|
1951
1965
|
message: `fn ${this._classname}.prototype.saveAll`,
|
|
1952
|
-
input: [{ docs: [...docs], systemLog: { ...systemLog } }]
|
|
1966
|
+
input: [{ config, docs: [...docs], systemLog: { ...systemLog } }]
|
|
1953
1967
|
})
|
|
1954
1968
|
const promise = typeof this.model.saveAll === 'function'
|
|
1955
|
-
? this.model.saveAll({ docs })
|
|
1969
|
+
? this.model.saveAll({ config, docs })
|
|
1956
1970
|
: Promise.all(docs.map(async (doc) => {
|
|
1957
1971
|
if (doc) {
|
|
1958
|
-
const result = await this.saveOne({ doc })
|
|
1972
|
+
const result = await this.saveOne({ config, doc })
|
|
1959
1973
|
isNew = result.isNew
|
|
1960
1974
|
const _data = result._data || result.data
|
|
1961
1975
|
return _data[0]
|
|
@@ -1977,15 +1991,19 @@ class Repo {
|
|
|
1977
1991
|
})
|
|
1978
1992
|
}
|
|
1979
1993
|
|
|
1980
|
-
saveOne({ doc, systemLog }) {
|
|
1994
|
+
saveOne({ config = {}, doc, systemLog }) {
|
|
1981
1995
|
const log = _makeLog({
|
|
1982
1996
|
systemLog,
|
|
1983
1997
|
label: 'REPO_WRITE',
|
|
1984
1998
|
message: `fn ${this._classname}.prototype.saveOne`,
|
|
1985
|
-
input: [{ doc: { ...doc }, systemLog: { ...systemLog } }]
|
|
1999
|
+
input: [{ config, doc: { ...doc }, systemLog: { ...systemLog } }]
|
|
1986
2000
|
})
|
|
2001
|
+
const saveOptions = {
|
|
2002
|
+
...this.saveOptions,
|
|
2003
|
+
...config,
|
|
2004
|
+
}
|
|
1987
2005
|
return new Promise((resolve, reject) => {
|
|
1988
|
-
this.model.saveOne(doc,
|
|
2006
|
+
this.model.saveOne(doc, saveOptions, (err, result) => {
|
|
1989
2007
|
if (err) {
|
|
1990
2008
|
log({ level: 'warn', output: err.toString() })
|
|
1991
2009
|
reject(err)
|
|
@@ -2127,11 +2145,11 @@ class Service {
|
|
|
2127
2145
|
return this.initFromArray(arr).filter((i) => i)
|
|
2128
2146
|
}
|
|
2129
2147
|
|
|
2130
|
-
async saveAll({
|
|
2148
|
+
async saveAll({ config = {}, docs = [], systemLog } = {}) {
|
|
2131
2149
|
const copies = docs.map((doc) => {
|
|
2132
2150
|
return config.skipInit ? doc : this.init(doc)
|
|
2133
2151
|
})
|
|
2134
|
-
const result = await this.repo.saveAll({ docs: copies, systemLog })
|
|
2152
|
+
const result = await this.repo.saveAll({ config, docs: copies, systemLog })
|
|
2135
2153
|
return makeApiResponse({
|
|
2136
2154
|
repo: this.repo,
|
|
2137
2155
|
result
|
|
@@ -2139,10 +2157,10 @@ class Service {
|
|
|
2139
2157
|
}
|
|
2140
2158
|
|
|
2141
2159
|
// set skipInit to true if we want to use POST for query
|
|
2142
|
-
async saveOne({
|
|
2160
|
+
async saveOne({ config = {}, doc = {}, systemLog } = {}) {
|
|
2143
2161
|
const copy = config.skipInit ? doc : this.init(doc)
|
|
2144
2162
|
if (copy) {
|
|
2145
|
-
const result = await this.repo.saveOne({ doc: copy, systemLog })
|
|
2163
|
+
const result = await this.repo.saveOne({ config, doc: copy, systemLog })
|
|
2146
2164
|
return makeApiResponse({
|
|
2147
2165
|
repo: this.repo,
|
|
2148
2166
|
result
|
|
@@ -2612,6 +2630,19 @@ function trackingPlugin(schema, options) {
|
|
|
2612
2630
|
next()
|
|
2613
2631
|
})
|
|
2614
2632
|
|
|
2633
|
+
// Add core indexes
|
|
2634
|
+
schema.index({
|
|
2635
|
+
'meta.active': 1,
|
|
2636
|
+
'meta.deleted': 1
|
|
2637
|
+
}, {
|
|
2638
|
+
name: 'tracking_status_index',
|
|
2639
|
+
background: true,
|
|
2640
|
+
partialFilterExpression: {
|
|
2641
|
+
'meta.active': true,
|
|
2642
|
+
'meta.deleted': false
|
|
2643
|
+
}
|
|
2644
|
+
})
|
|
2645
|
+
|
|
2615
2646
|
// Optional: Add helper methods
|
|
2616
2647
|
// schema.methods.touch = function(userId) {
|
|
2617
2648
|
// this.meta.updatedAt = new Date()
|
|
@@ -2619,6 +2650,57 @@ function trackingPlugin(schema, options) {
|
|
|
2619
2650
|
// }
|
|
2620
2651
|
}
|
|
2621
2652
|
|
|
2653
|
+
;// ./lib/helpers/tenantPlugin/tenantPlugin.js
|
|
2654
|
+
|
|
2655
|
+
|
|
2656
|
+
function tenantPlugin(schema, options) {
|
|
2657
|
+
// Apply tracking plugin first if not already present
|
|
2658
|
+
if (!schema.path('meta')) {
|
|
2659
|
+
trackingPlugin(schema, options)
|
|
2660
|
+
}
|
|
2661
|
+
|
|
2662
|
+
// Add tenant-specific fields
|
|
2663
|
+
schema.add({
|
|
2664
|
+
metadata: [{ type: Object }], // Instead of Schema.Types.Mixed
|
|
2665
|
+
remarks: [{ type: Object }],
|
|
2666
|
+
tenantCode: { type: String, required: true }
|
|
2667
|
+
})
|
|
2668
|
+
|
|
2669
|
+
// Add core indexes
|
|
2670
|
+
schema.index({
|
|
2671
|
+
'tenantCode': 1
|
|
2672
|
+
}, {
|
|
2673
|
+
name: 'tenant_core_index',
|
|
2674
|
+
background: true
|
|
2675
|
+
})
|
|
2676
|
+
|
|
2677
|
+
// 1. ENHANCE EXISTING TRACKING INDEXES
|
|
2678
|
+
const existingIndexes = schema.indexes()
|
|
2679
|
+
|
|
2680
|
+
// Check if tracking_status_index exists
|
|
2681
|
+
const hasTenantStatusIndex = existingIndexes.some(idx =>
|
|
2682
|
+
idx.name === 'tenant_status_index' // Check by name for reliability
|
|
2683
|
+
)
|
|
2684
|
+
|
|
2685
|
+
if (!hasTenantStatusIndex) {
|
|
2686
|
+
schema.index({
|
|
2687
|
+
'tenantCode': 1, // Unique field first
|
|
2688
|
+
_type: 1, // Low-cardinality field last
|
|
2689
|
+
}, {
|
|
2690
|
+
name: 'tenant_status_index',
|
|
2691
|
+
background: true,
|
|
2692
|
+
partialFilterExpression: {
|
|
2693
|
+
'_type': 'Tenant',
|
|
2694
|
+
'meta.active': true,
|
|
2695
|
+
'meta.deleted': false
|
|
2696
|
+
}
|
|
2697
|
+
})
|
|
2698
|
+
}
|
|
2699
|
+
}
|
|
2700
|
+
|
|
2701
|
+
;// ./lib/helpers/tenantPlugin/index.js
|
|
2702
|
+
|
|
2703
|
+
|
|
2622
2704
|
;// ./lib/helpers/trackingPlugin/index.js
|
|
2623
2705
|
|
|
2624
2706
|
|
|
@@ -2645,6 +2727,7 @@ function trackingPlugin(schema, options) {
|
|
|
2645
2727
|
|
|
2646
2728
|
|
|
2647
2729
|
|
|
2730
|
+
|
|
2648
2731
|
|
|
2649
2732
|
|
|
2650
2733
|
;// ./lib/models/apiResponse/index.js
|
|
@@ -2986,7 +3069,10 @@ class KeyValueObject {
|
|
|
2986
3069
|
}, [])
|
|
2987
3070
|
}
|
|
2988
3071
|
static sameKey(item, key) {
|
|
2989
|
-
|
|
3072
|
+
if (item) {
|
|
3073
|
+
return _isSame(item.key, key)
|
|
3074
|
+
}
|
|
3075
|
+
return false
|
|
2990
3076
|
}
|
|
2991
3077
|
static toObject(arr = []) {
|
|
2992
3078
|
if (Array.isArray(arr)) {
|
|
@@ -3240,17 +3326,19 @@ class TrackedEntity {
|
|
|
3240
3326
|
constructor(options = {}) {
|
|
3241
3327
|
options = options || {}
|
|
3242
3328
|
const timestamp = Date.now()
|
|
3243
|
-
|
|
3244
|
-
active: options.active ?? true,
|
|
3245
|
-
created: options.created ??
|
|
3246
|
-
|
|
3247
|
-
|
|
3248
|
-
|
|
3249
|
-
|
|
3329
|
+
this.meta = {
|
|
3330
|
+
active: options.meta?.active ?? options.active ?? true,
|
|
3331
|
+
created: options.meta?.created ?? (options.created
|
|
3332
|
+
? new Date(options.created).getTime()
|
|
3333
|
+
: timestamp),
|
|
3334
|
+
creator: options.meta?.creator ?? options.creator ?? '',
|
|
3335
|
+
deleted: options.meta?.deleted ?? options.deleted ?? false,
|
|
3336
|
+
modified: options.meta?.modified ?? (options.modified
|
|
3337
|
+
? new Date(options.modified).getTime()
|
|
3338
|
+
: timestamp),
|
|
3339
|
+
owner: options.meta?.owner ?? options.owner ?? '',
|
|
3250
3340
|
}
|
|
3251
3341
|
|
|
3252
|
-
this.meta = { ..._tracking, ...options.meta }
|
|
3253
|
-
|
|
3254
3342
|
// if (trackFlat) {
|
|
3255
3343
|
// Object.assign(this, _tracking)
|
|
3256
3344
|
// } else {
|
package/dist/q-utilities.esm.js
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
|
|
2
2
|
;// ./lib/helpers/authorize/authorize.js
|
|
3
|
-
function authorize({ allowOwner, query = {}, required, user }) {
|
|
3
|
+
function authorize({ allowCoordinator, allowOwner, query = {}, required, user }) {
|
|
4
4
|
if (!user) {
|
|
5
5
|
throw new Error('Require login.')
|
|
6
6
|
}
|
|
7
7
|
if (!user.permission) {
|
|
8
|
-
throw new Error('You do not have any permission.')
|
|
8
|
+
// throw new Error('You do not have any permission.')
|
|
9
9
|
}
|
|
10
|
-
const scopes = user.permission.getScopes(required || {})
|
|
10
|
+
const scopes = user.permission.getScopes(required || {}) || []
|
|
11
11
|
if (!scopes || scopes.length === 0) {
|
|
12
|
-
throw new Error('You are not allowed in this scope.')
|
|
12
|
+
// throw new Error('You are not allowed in this scope.')
|
|
13
13
|
}
|
|
14
14
|
if (!scopes.includes('*')) {
|
|
15
15
|
query.tenantCode = user.tenantCode
|
|
@@ -17,8 +17,21 @@ function authorize({ allowOwner, query = {}, required, user }) {
|
|
|
17
17
|
if (!scopes.includes('TENANT')) {
|
|
18
18
|
query.eventShortCode = user.eventShortCode
|
|
19
19
|
}
|
|
20
|
-
if (!scopes.includes('EVENT')) {
|
|
21
|
-
|
|
20
|
+
// if (!scopes.includes('EVENT')) {
|
|
21
|
+
// query.eventRegistrationCode = user.eventRegistrationCode
|
|
22
|
+
// }
|
|
23
|
+
if (allowCoordinator) {
|
|
24
|
+
if (query.registrationGroupCode && user.myManagedRegistrationGroupCodes.includes(query.registrationGroupCode)) {
|
|
25
|
+
query.__ALLOW_COORDINATOR = true
|
|
26
|
+
} else {
|
|
27
|
+
if (!scopes.includes('EVENT')) {
|
|
28
|
+
query.eventRegistrationCode = user.eventRegistrationCode
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
} else {
|
|
32
|
+
if (!scopes.includes('EVENT')) {
|
|
33
|
+
query.eventRegistrationCode = user.eventRegistrationCode
|
|
34
|
+
}
|
|
22
35
|
}
|
|
23
36
|
if (allowOwner) {
|
|
24
37
|
query.__ALLOW_OWNER = true
|
|
@@ -1398,7 +1411,7 @@ function convertString(string, patternMatch = /\$\{(.+?)\}/g, value, getValueByK
|
|
|
1398
1411
|
if (!string) {
|
|
1399
1412
|
return ''
|
|
1400
1413
|
}
|
|
1401
|
-
let _getValueByKeys = typeof getValueByKeys
|
|
1414
|
+
let _getValueByKeys = typeof getValueByKeys === 'function' ? getValueByKeys : getValueByKeys_getValueByKeys
|
|
1402
1415
|
const reg = new RegExp(patternMatch, 'g')
|
|
1403
1416
|
return string.replace(reg, (match, key) => {
|
|
1404
1417
|
const result = _getValueByKeys({ keys: key.split('.'), obj: value })
|
|
@@ -1419,7 +1432,7 @@ function convertString(string, patternMatch = /\$\{(.+?)\}/g, value, getValueByK
|
|
|
1419
1432
|
|
|
1420
1433
|
;// ./lib/helpers/escapeRegex/escapeRegex.js
|
|
1421
1434
|
function escapeRegex(string) {
|
|
1422
|
-
return string.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&')
|
|
1435
|
+
return String(string).replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&')
|
|
1423
1436
|
}
|
|
1424
1437
|
|
|
1425
1438
|
;// ./lib/helpers/escapeRegex/index.js
|
|
@@ -1855,19 +1868,19 @@ class Repo {
|
|
|
1855
1868
|
})
|
|
1856
1869
|
}
|
|
1857
1870
|
|
|
1858
|
-
saveAll({ docs, systemLog }) {
|
|
1871
|
+
saveAll({ config = {}, docs, systemLog }) {
|
|
1859
1872
|
let isNew
|
|
1860
1873
|
const log = _makeLog({
|
|
1861
1874
|
systemLog,
|
|
1862
1875
|
label: 'REPO_WRITE',
|
|
1863
1876
|
message: `fn ${this._classname}.prototype.saveAll`,
|
|
1864
|
-
input: [{ docs: [...docs], systemLog: { ...systemLog } }]
|
|
1877
|
+
input: [{ config, docs: [...docs], systemLog: { ...systemLog } }]
|
|
1865
1878
|
})
|
|
1866
1879
|
const promise = typeof this.model.saveAll === 'function'
|
|
1867
|
-
? this.model.saveAll({ docs })
|
|
1880
|
+
? this.model.saveAll({ config, docs })
|
|
1868
1881
|
: Promise.all(docs.map(async (doc) => {
|
|
1869
1882
|
if (doc) {
|
|
1870
|
-
const result = await this.saveOne({ doc })
|
|
1883
|
+
const result = await this.saveOne({ config, doc })
|
|
1871
1884
|
isNew = result.isNew
|
|
1872
1885
|
const _data = result._data || result.data
|
|
1873
1886
|
return _data[0]
|
|
@@ -1889,15 +1902,19 @@ class Repo {
|
|
|
1889
1902
|
})
|
|
1890
1903
|
}
|
|
1891
1904
|
|
|
1892
|
-
saveOne({ doc, systemLog }) {
|
|
1905
|
+
saveOne({ config = {}, doc, systemLog }) {
|
|
1893
1906
|
const log = _makeLog({
|
|
1894
1907
|
systemLog,
|
|
1895
1908
|
label: 'REPO_WRITE',
|
|
1896
1909
|
message: `fn ${this._classname}.prototype.saveOne`,
|
|
1897
|
-
input: [{ doc: { ...doc }, systemLog: { ...systemLog } }]
|
|
1910
|
+
input: [{ config, doc: { ...doc }, systemLog: { ...systemLog } }]
|
|
1898
1911
|
})
|
|
1912
|
+
const saveOptions = {
|
|
1913
|
+
...this.saveOptions,
|
|
1914
|
+
...config,
|
|
1915
|
+
}
|
|
1899
1916
|
return new Promise((resolve, reject) => {
|
|
1900
|
-
this.model.saveOne(doc,
|
|
1917
|
+
this.model.saveOne(doc, saveOptions, (err, result) => {
|
|
1901
1918
|
if (err) {
|
|
1902
1919
|
log({ level: 'warn', output: err.toString() })
|
|
1903
1920
|
reject(err)
|
|
@@ -2039,11 +2056,11 @@ class Service {
|
|
|
2039
2056
|
return this.initFromArray(arr).filter((i) => i)
|
|
2040
2057
|
}
|
|
2041
2058
|
|
|
2042
|
-
async saveAll({
|
|
2059
|
+
async saveAll({ config = {}, docs = [], systemLog } = {}) {
|
|
2043
2060
|
const copies = docs.map((doc) => {
|
|
2044
2061
|
return config.skipInit ? doc : this.init(doc)
|
|
2045
2062
|
})
|
|
2046
|
-
const result = await this.repo.saveAll({ docs: copies, systemLog })
|
|
2063
|
+
const result = await this.repo.saveAll({ config, docs: copies, systemLog })
|
|
2047
2064
|
return makeApiResponse({
|
|
2048
2065
|
repo: this.repo,
|
|
2049
2066
|
result
|
|
@@ -2051,10 +2068,10 @@ class Service {
|
|
|
2051
2068
|
}
|
|
2052
2069
|
|
|
2053
2070
|
// set skipInit to true if we want to use POST for query
|
|
2054
|
-
async saveOne({
|
|
2071
|
+
async saveOne({ config = {}, doc = {}, systemLog } = {}) {
|
|
2055
2072
|
const copy = config.skipInit ? doc : this.init(doc)
|
|
2056
2073
|
if (copy) {
|
|
2057
|
-
const result = await this.repo.saveOne({ doc: copy, systemLog })
|
|
2074
|
+
const result = await this.repo.saveOne({ config, doc: copy, systemLog })
|
|
2058
2075
|
return makeApiResponse({
|
|
2059
2076
|
repo: this.repo,
|
|
2060
2077
|
result
|
|
@@ -2524,6 +2541,19 @@ function trackingPlugin(schema, options) {
|
|
|
2524
2541
|
next()
|
|
2525
2542
|
})
|
|
2526
2543
|
|
|
2544
|
+
// Add core indexes
|
|
2545
|
+
schema.index({
|
|
2546
|
+
'meta.active': 1,
|
|
2547
|
+
'meta.deleted': 1
|
|
2548
|
+
}, {
|
|
2549
|
+
name: 'tracking_status_index',
|
|
2550
|
+
background: true,
|
|
2551
|
+
partialFilterExpression: {
|
|
2552
|
+
'meta.active': true,
|
|
2553
|
+
'meta.deleted': false
|
|
2554
|
+
}
|
|
2555
|
+
})
|
|
2556
|
+
|
|
2527
2557
|
// Optional: Add helper methods
|
|
2528
2558
|
// schema.methods.touch = function(userId) {
|
|
2529
2559
|
// this.meta.updatedAt = new Date()
|
|
@@ -2531,6 +2561,57 @@ function trackingPlugin(schema, options) {
|
|
|
2531
2561
|
// }
|
|
2532
2562
|
}
|
|
2533
2563
|
|
|
2564
|
+
;// ./lib/helpers/tenantPlugin/tenantPlugin.js
|
|
2565
|
+
|
|
2566
|
+
|
|
2567
|
+
function tenantPlugin(schema, options) {
|
|
2568
|
+
// Apply tracking plugin first if not already present
|
|
2569
|
+
if (!schema.path('meta')) {
|
|
2570
|
+
trackingPlugin(schema, options)
|
|
2571
|
+
}
|
|
2572
|
+
|
|
2573
|
+
// Add tenant-specific fields
|
|
2574
|
+
schema.add({
|
|
2575
|
+
metadata: [{ type: Object }], // Instead of Schema.Types.Mixed
|
|
2576
|
+
remarks: [{ type: Object }],
|
|
2577
|
+
tenantCode: { type: String, required: true }
|
|
2578
|
+
})
|
|
2579
|
+
|
|
2580
|
+
// Add core indexes
|
|
2581
|
+
schema.index({
|
|
2582
|
+
'tenantCode': 1
|
|
2583
|
+
}, {
|
|
2584
|
+
name: 'tenant_core_index',
|
|
2585
|
+
background: true
|
|
2586
|
+
})
|
|
2587
|
+
|
|
2588
|
+
// 1. ENHANCE EXISTING TRACKING INDEXES
|
|
2589
|
+
const existingIndexes = schema.indexes()
|
|
2590
|
+
|
|
2591
|
+
// Check if tracking_status_index exists
|
|
2592
|
+
const hasTenantStatusIndex = existingIndexes.some(idx =>
|
|
2593
|
+
idx.name === 'tenant_status_index' // Check by name for reliability
|
|
2594
|
+
)
|
|
2595
|
+
|
|
2596
|
+
if (!hasTenantStatusIndex) {
|
|
2597
|
+
schema.index({
|
|
2598
|
+
'tenantCode': 1, // Unique field first
|
|
2599
|
+
_type: 1, // Low-cardinality field last
|
|
2600
|
+
}, {
|
|
2601
|
+
name: 'tenant_status_index',
|
|
2602
|
+
background: true,
|
|
2603
|
+
partialFilterExpression: {
|
|
2604
|
+
'_type': 'Tenant',
|
|
2605
|
+
'meta.active': true,
|
|
2606
|
+
'meta.deleted': false
|
|
2607
|
+
}
|
|
2608
|
+
})
|
|
2609
|
+
}
|
|
2610
|
+
}
|
|
2611
|
+
|
|
2612
|
+
;// ./lib/helpers/tenantPlugin/index.js
|
|
2613
|
+
|
|
2614
|
+
|
|
2534
2615
|
;// ./lib/helpers/trackingPlugin/index.js
|
|
2535
2616
|
|
|
2536
2617
|
|
|
@@ -2557,6 +2638,7 @@ function trackingPlugin(schema, options) {
|
|
|
2557
2638
|
|
|
2558
2639
|
|
|
2559
2640
|
|
|
2641
|
+
|
|
2560
2642
|
|
|
2561
2643
|
|
|
2562
2644
|
;// ./lib/models/apiResponse/index.js
|
|
@@ -2898,7 +2980,10 @@ class KeyValueObject {
|
|
|
2898
2980
|
}, [])
|
|
2899
2981
|
}
|
|
2900
2982
|
static sameKey(item, key) {
|
|
2901
|
-
|
|
2983
|
+
if (item) {
|
|
2984
|
+
return _isSame(item.key, key)
|
|
2985
|
+
}
|
|
2986
|
+
return false
|
|
2902
2987
|
}
|
|
2903
2988
|
static toObject(arr = []) {
|
|
2904
2989
|
if (Array.isArray(arr)) {
|
|
@@ -3152,17 +3237,19 @@ class TrackedEntity {
|
|
|
3152
3237
|
constructor(options = {}) {
|
|
3153
3238
|
options = options || {}
|
|
3154
3239
|
const timestamp = Date.now()
|
|
3155
|
-
|
|
3156
|
-
active: options.active ?? true,
|
|
3157
|
-
created: options.created ??
|
|
3158
|
-
|
|
3159
|
-
|
|
3160
|
-
|
|
3161
|
-
|
|
3240
|
+
this.meta = {
|
|
3241
|
+
active: options.meta?.active ?? options.active ?? true,
|
|
3242
|
+
created: options.meta?.created ?? (options.created
|
|
3243
|
+
? new Date(options.created).getTime()
|
|
3244
|
+
: timestamp),
|
|
3245
|
+
creator: options.meta?.creator ?? options.creator ?? '',
|
|
3246
|
+
deleted: options.meta?.deleted ?? options.deleted ?? false,
|
|
3247
|
+
modified: options.meta?.modified ?? (options.modified
|
|
3248
|
+
? new Date(options.modified).getTime()
|
|
3249
|
+
: timestamp),
|
|
3250
|
+
owner: options.meta?.owner ?? options.owner ?? '',
|
|
3162
3251
|
}
|
|
3163
3252
|
|
|
3164
|
-
this.meta = { ..._tracking, ...options.meta }
|
|
3165
|
-
|
|
3166
3253
|
// if (trackFlat) {
|
|
3167
3254
|
// Object.assign(this, _tracking)
|
|
3168
3255
|
// } else {
|
|
@@ -3431,4 +3518,4 @@ function _makeSetCode(fieldName, options) {
|
|
|
3431
3518
|
;// ./index.js
|
|
3432
3519
|
|
|
3433
3520
|
|
|
3434
|
-
export { ApiResponse, AwsStsS3Client, KeyValueObject, Metadata, QMeta, Repo, Service, TemplateCompiler, TenantAwareEntity, TrackedEntity, UniqueKeyGenerator, authorize, changeCreatorOwner, concatStringByArray, convertString, escapeRegex, expressHelper, extractEmails, formatDate, generalPost, getValidation, getValueByKeys_getValueByKeys as getValueByKeys, init, initFromArray, initOnlyValidFromArray, makeApiResponse, makeService, mergeArraysByKey, objectHelper, pReduce, padZeros, replacePlaceholders, sanitizeText, stringFormatter, stringHelper, trackingPlugin };
|
|
3521
|
+
export { ApiResponse, AwsStsS3Client, KeyValueObject, Metadata, QMeta, Repo, Service, TemplateCompiler, TenantAwareEntity, TrackedEntity, UniqueKeyGenerator, authorize, changeCreatorOwner, concatStringByArray, convertString, escapeRegex, expressHelper, extractEmails, formatDate, generalPost, getValidation, getValueByKeys_getValueByKeys as getValueByKeys, init, initFromArray, initOnlyValidFromArray, makeApiResponse, makeService, mergeArraysByKey, objectHelper, pReduce, padZeros, replacePlaceholders, sanitizeText, stringFormatter, stringHelper, tenantPlugin, trackingPlugin };
|
package/dist/q-utilities.min.js
CHANGED
|
@@ -83,20 +83,21 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
83
83
|
sanitizeText: () => (/* reexport */ sanitizeText),
|
|
84
84
|
stringFormatter: () => (/* reexport */ stringFormatter),
|
|
85
85
|
stringHelper: () => (/* reexport */ stringHelper),
|
|
86
|
+
tenantPlugin: () => (/* reexport */ tenantPlugin),
|
|
86
87
|
trackingPlugin: () => (/* reexport */ trackingPlugin)
|
|
87
88
|
});
|
|
88
89
|
|
|
89
90
|
;// ./lib/helpers/authorize/authorize.js
|
|
90
|
-
function authorize({ allowOwner, query = {}, required, user }) {
|
|
91
|
+
function authorize({ allowCoordinator, allowOwner, query = {}, required, user }) {
|
|
91
92
|
if (!user) {
|
|
92
93
|
throw new Error('Require login.')
|
|
93
94
|
}
|
|
94
95
|
if (!user.permission) {
|
|
95
|
-
throw new Error('You do not have any permission.')
|
|
96
|
+
// throw new Error('You do not have any permission.')
|
|
96
97
|
}
|
|
97
|
-
const scopes = user.permission.getScopes(required || {})
|
|
98
|
+
const scopes = user.permission.getScopes(required || {}) || []
|
|
98
99
|
if (!scopes || scopes.length === 0) {
|
|
99
|
-
throw new Error('You are not allowed in this scope.')
|
|
100
|
+
// throw new Error('You are not allowed in this scope.')
|
|
100
101
|
}
|
|
101
102
|
if (!scopes.includes('*')) {
|
|
102
103
|
query.tenantCode = user.tenantCode
|
|
@@ -104,8 +105,21 @@ function authorize({ allowOwner, query = {}, required, user }) {
|
|
|
104
105
|
if (!scopes.includes('TENANT')) {
|
|
105
106
|
query.eventShortCode = user.eventShortCode
|
|
106
107
|
}
|
|
107
|
-
if (!scopes.includes('EVENT')) {
|
|
108
|
-
|
|
108
|
+
// if (!scopes.includes('EVENT')) {
|
|
109
|
+
// query.eventRegistrationCode = user.eventRegistrationCode
|
|
110
|
+
// }
|
|
111
|
+
if (allowCoordinator) {
|
|
112
|
+
if (query.registrationGroupCode && user.myManagedRegistrationGroupCodes.includes(query.registrationGroupCode)) {
|
|
113
|
+
query.__ALLOW_COORDINATOR = true
|
|
114
|
+
} else {
|
|
115
|
+
if (!scopes.includes('EVENT')) {
|
|
116
|
+
query.eventRegistrationCode = user.eventRegistrationCode
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
} else {
|
|
120
|
+
if (!scopes.includes('EVENT')) {
|
|
121
|
+
query.eventRegistrationCode = user.eventRegistrationCode
|
|
122
|
+
}
|
|
109
123
|
}
|
|
110
124
|
if (allowOwner) {
|
|
111
125
|
query.__ALLOW_OWNER = true
|
|
@@ -1485,7 +1499,7 @@ function convertString(string, patternMatch = /\$\{(.+?)\}/g, value, getValueByK
|
|
|
1485
1499
|
if (!string) {
|
|
1486
1500
|
return ''
|
|
1487
1501
|
}
|
|
1488
|
-
let _getValueByKeys = typeof getValueByKeys
|
|
1502
|
+
let _getValueByKeys = typeof getValueByKeys === 'function' ? getValueByKeys : getValueByKeys_getValueByKeys
|
|
1489
1503
|
const reg = new RegExp(patternMatch, 'g')
|
|
1490
1504
|
return string.replace(reg, (match, key) => {
|
|
1491
1505
|
const result = _getValueByKeys({ keys: key.split('.'), obj: value })
|
|
@@ -1506,7 +1520,7 @@ function convertString(string, patternMatch = /\$\{(.+?)\}/g, value, getValueByK
|
|
|
1506
1520
|
|
|
1507
1521
|
;// ./lib/helpers/escapeRegex/escapeRegex.js
|
|
1508
1522
|
function escapeRegex(string) {
|
|
1509
|
-
return string.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&')
|
|
1523
|
+
return String(string).replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&')
|
|
1510
1524
|
}
|
|
1511
1525
|
|
|
1512
1526
|
;// ./lib/helpers/escapeRegex/index.js
|
|
@@ -1942,19 +1956,19 @@ class Repo {
|
|
|
1942
1956
|
})
|
|
1943
1957
|
}
|
|
1944
1958
|
|
|
1945
|
-
saveAll({ docs, systemLog }) {
|
|
1959
|
+
saveAll({ config = {}, docs, systemLog }) {
|
|
1946
1960
|
let isNew
|
|
1947
1961
|
const log = _makeLog({
|
|
1948
1962
|
systemLog,
|
|
1949
1963
|
label: 'REPO_WRITE',
|
|
1950
1964
|
message: `fn ${this._classname}.prototype.saveAll`,
|
|
1951
|
-
input: [{ docs: [...docs], systemLog: { ...systemLog } }]
|
|
1965
|
+
input: [{ config, docs: [...docs], systemLog: { ...systemLog } }]
|
|
1952
1966
|
})
|
|
1953
1967
|
const promise = typeof this.model.saveAll === 'function'
|
|
1954
|
-
? this.model.saveAll({ docs })
|
|
1968
|
+
? this.model.saveAll({ config, docs })
|
|
1955
1969
|
: Promise.all(docs.map(async (doc) => {
|
|
1956
1970
|
if (doc) {
|
|
1957
|
-
const result = await this.saveOne({ doc })
|
|
1971
|
+
const result = await this.saveOne({ config, doc })
|
|
1958
1972
|
isNew = result.isNew
|
|
1959
1973
|
const _data = result._data || result.data
|
|
1960
1974
|
return _data[0]
|
|
@@ -1976,15 +1990,19 @@ class Repo {
|
|
|
1976
1990
|
})
|
|
1977
1991
|
}
|
|
1978
1992
|
|
|
1979
|
-
saveOne({ doc, systemLog }) {
|
|
1993
|
+
saveOne({ config = {}, doc, systemLog }) {
|
|
1980
1994
|
const log = _makeLog({
|
|
1981
1995
|
systemLog,
|
|
1982
1996
|
label: 'REPO_WRITE',
|
|
1983
1997
|
message: `fn ${this._classname}.prototype.saveOne`,
|
|
1984
|
-
input: [{ doc: { ...doc }, systemLog: { ...systemLog } }]
|
|
1998
|
+
input: [{ config, doc: { ...doc }, systemLog: { ...systemLog } }]
|
|
1985
1999
|
})
|
|
2000
|
+
const saveOptions = {
|
|
2001
|
+
...this.saveOptions,
|
|
2002
|
+
...config,
|
|
2003
|
+
}
|
|
1986
2004
|
return new Promise((resolve, reject) => {
|
|
1987
|
-
this.model.saveOne(doc,
|
|
2005
|
+
this.model.saveOne(doc, saveOptions, (err, result) => {
|
|
1988
2006
|
if (err) {
|
|
1989
2007
|
log({ level: 'warn', output: err.toString() })
|
|
1990
2008
|
reject(err)
|
|
@@ -2126,11 +2144,11 @@ class Service {
|
|
|
2126
2144
|
return this.initFromArray(arr).filter((i) => i)
|
|
2127
2145
|
}
|
|
2128
2146
|
|
|
2129
|
-
async saveAll({
|
|
2147
|
+
async saveAll({ config = {}, docs = [], systemLog } = {}) {
|
|
2130
2148
|
const copies = docs.map((doc) => {
|
|
2131
2149
|
return config.skipInit ? doc : this.init(doc)
|
|
2132
2150
|
})
|
|
2133
|
-
const result = await this.repo.saveAll({ docs: copies, systemLog })
|
|
2151
|
+
const result = await this.repo.saveAll({ config, docs: copies, systemLog })
|
|
2134
2152
|
return makeApiResponse({
|
|
2135
2153
|
repo: this.repo,
|
|
2136
2154
|
result
|
|
@@ -2138,10 +2156,10 @@ class Service {
|
|
|
2138
2156
|
}
|
|
2139
2157
|
|
|
2140
2158
|
// set skipInit to true if we want to use POST for query
|
|
2141
|
-
async saveOne({
|
|
2159
|
+
async saveOne({ config = {}, doc = {}, systemLog } = {}) {
|
|
2142
2160
|
const copy = config.skipInit ? doc : this.init(doc)
|
|
2143
2161
|
if (copy) {
|
|
2144
|
-
const result = await this.repo.saveOne({ doc: copy, systemLog })
|
|
2162
|
+
const result = await this.repo.saveOne({ config, doc: copy, systemLog })
|
|
2145
2163
|
return makeApiResponse({
|
|
2146
2164
|
repo: this.repo,
|
|
2147
2165
|
result
|
|
@@ -2611,6 +2629,19 @@ function trackingPlugin(schema, options) {
|
|
|
2611
2629
|
next()
|
|
2612
2630
|
})
|
|
2613
2631
|
|
|
2632
|
+
// Add core indexes
|
|
2633
|
+
schema.index({
|
|
2634
|
+
'meta.active': 1,
|
|
2635
|
+
'meta.deleted': 1
|
|
2636
|
+
}, {
|
|
2637
|
+
name: 'tracking_status_index',
|
|
2638
|
+
background: true,
|
|
2639
|
+
partialFilterExpression: {
|
|
2640
|
+
'meta.active': true,
|
|
2641
|
+
'meta.deleted': false
|
|
2642
|
+
}
|
|
2643
|
+
})
|
|
2644
|
+
|
|
2614
2645
|
// Optional: Add helper methods
|
|
2615
2646
|
// schema.methods.touch = function(userId) {
|
|
2616
2647
|
// this.meta.updatedAt = new Date()
|
|
@@ -2618,6 +2649,57 @@ function trackingPlugin(schema, options) {
|
|
|
2618
2649
|
// }
|
|
2619
2650
|
}
|
|
2620
2651
|
|
|
2652
|
+
;// ./lib/helpers/tenantPlugin/tenantPlugin.js
|
|
2653
|
+
|
|
2654
|
+
|
|
2655
|
+
function tenantPlugin(schema, options) {
|
|
2656
|
+
// Apply tracking plugin first if not already present
|
|
2657
|
+
if (!schema.path('meta')) {
|
|
2658
|
+
trackingPlugin(schema, options)
|
|
2659
|
+
}
|
|
2660
|
+
|
|
2661
|
+
// Add tenant-specific fields
|
|
2662
|
+
schema.add({
|
|
2663
|
+
metadata: [{ type: Object }], // Instead of Schema.Types.Mixed
|
|
2664
|
+
remarks: [{ type: Object }],
|
|
2665
|
+
tenantCode: { type: String, required: true }
|
|
2666
|
+
})
|
|
2667
|
+
|
|
2668
|
+
// Add core indexes
|
|
2669
|
+
schema.index({
|
|
2670
|
+
'tenantCode': 1
|
|
2671
|
+
}, {
|
|
2672
|
+
name: 'tenant_core_index',
|
|
2673
|
+
background: true
|
|
2674
|
+
})
|
|
2675
|
+
|
|
2676
|
+
// 1. ENHANCE EXISTING TRACKING INDEXES
|
|
2677
|
+
const existingIndexes = schema.indexes()
|
|
2678
|
+
|
|
2679
|
+
// Check if tracking_status_index exists
|
|
2680
|
+
const hasTenantStatusIndex = existingIndexes.some(idx =>
|
|
2681
|
+
idx.name === 'tenant_status_index' // Check by name for reliability
|
|
2682
|
+
)
|
|
2683
|
+
|
|
2684
|
+
if (!hasTenantStatusIndex) {
|
|
2685
|
+
schema.index({
|
|
2686
|
+
'tenantCode': 1, // Unique field first
|
|
2687
|
+
_type: 1, // Low-cardinality field last
|
|
2688
|
+
}, {
|
|
2689
|
+
name: 'tenant_status_index',
|
|
2690
|
+
background: true,
|
|
2691
|
+
partialFilterExpression: {
|
|
2692
|
+
'_type': 'Tenant',
|
|
2693
|
+
'meta.active': true,
|
|
2694
|
+
'meta.deleted': false
|
|
2695
|
+
}
|
|
2696
|
+
})
|
|
2697
|
+
}
|
|
2698
|
+
}
|
|
2699
|
+
|
|
2700
|
+
;// ./lib/helpers/tenantPlugin/index.js
|
|
2701
|
+
|
|
2702
|
+
|
|
2621
2703
|
;// ./lib/helpers/trackingPlugin/index.js
|
|
2622
2704
|
|
|
2623
2705
|
|
|
@@ -2644,6 +2726,7 @@ function trackingPlugin(schema, options) {
|
|
|
2644
2726
|
|
|
2645
2727
|
|
|
2646
2728
|
|
|
2729
|
+
|
|
2647
2730
|
|
|
2648
2731
|
|
|
2649
2732
|
;// ./lib/models/apiResponse/index.js
|
|
@@ -2985,7 +3068,10 @@ class KeyValueObject {
|
|
|
2985
3068
|
}, [])
|
|
2986
3069
|
}
|
|
2987
3070
|
static sameKey(item, key) {
|
|
2988
|
-
|
|
3071
|
+
if (item) {
|
|
3072
|
+
return _isSame(item.key, key)
|
|
3073
|
+
}
|
|
3074
|
+
return false
|
|
2989
3075
|
}
|
|
2990
3076
|
static toObject(arr = []) {
|
|
2991
3077
|
if (Array.isArray(arr)) {
|
|
@@ -3239,17 +3325,19 @@ class TrackedEntity {
|
|
|
3239
3325
|
constructor(options = {}) {
|
|
3240
3326
|
options = options || {}
|
|
3241
3327
|
const timestamp = Date.now()
|
|
3242
|
-
|
|
3243
|
-
active: options.active ?? true,
|
|
3244
|
-
created: options.created ??
|
|
3245
|
-
|
|
3246
|
-
|
|
3247
|
-
|
|
3248
|
-
|
|
3328
|
+
this.meta = {
|
|
3329
|
+
active: options.meta?.active ?? options.active ?? true,
|
|
3330
|
+
created: options.meta?.created ?? (options.created
|
|
3331
|
+
? new Date(options.created).getTime()
|
|
3332
|
+
: timestamp),
|
|
3333
|
+
creator: options.meta?.creator ?? options.creator ?? '',
|
|
3334
|
+
deleted: options.meta?.deleted ?? options.deleted ?? false,
|
|
3335
|
+
modified: options.meta?.modified ?? (options.modified
|
|
3336
|
+
? new Date(options.modified).getTime()
|
|
3337
|
+
: timestamp),
|
|
3338
|
+
owner: options.meta?.owner ?? options.owner ?? '',
|
|
3249
3339
|
}
|
|
3250
3340
|
|
|
3251
|
-
this.meta = { ..._tracking, ...options.meta }
|
|
3252
|
-
|
|
3253
3341
|
// if (trackFlat) {
|
|
3254
3342
|
// Object.assign(this, _tracking)
|
|
3255
3343
|
// } else {
|