@questwork/q-utilities 0.1.14 → 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 +743 -37
- package/dist/q-utilities.esm.js +735 -38
- package/dist/q-utilities.min.js +743 -37
- package/package.json +5 -1
package/dist/index.min.cjs
CHANGED
|
@@ -50,6 +50,7 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
50
50
|
// EXPORTS
|
|
51
51
|
__webpack_require__.d(__webpack_exports__, {
|
|
52
52
|
ApiResponse: () => (/* reexport */ ApiResponse),
|
|
53
|
+
AwsStsS3Client: () => (/* reexport */ AwsStsS3Client),
|
|
53
54
|
KeyValueObject: () => (/* reexport */ KeyValueObject),
|
|
54
55
|
Metadata: () => (/* reexport */ Metadata),
|
|
55
56
|
QMeta: () => (/* reexport */ QMeta),
|
|
@@ -60,8 +61,12 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
60
61
|
TrackedEntity: () => (/* reexport */ TrackedEntity),
|
|
61
62
|
UniqueKeyGenerator: () => (/* reexport */ UniqueKeyGenerator),
|
|
62
63
|
authorize: () => (/* reexport */ authorize),
|
|
64
|
+
changeCreatorOwner: () => (/* reexport */ changeCreatorOwner),
|
|
63
65
|
concatStringByArray: () => (/* reexport */ concatStringByArray),
|
|
64
66
|
convertString: () => (/* reexport */ convertString),
|
|
67
|
+
escapeRegex: () => (/* reexport */ escapeRegex),
|
|
68
|
+
expressHelper: () => (/* reexport */ expressHelper),
|
|
69
|
+
extractEmails: () => (/* reexport */ extractEmails),
|
|
65
70
|
formatDate: () => (/* reexport */ formatDate),
|
|
66
71
|
generalPost: () => (/* reexport */ generalPost),
|
|
67
72
|
getValidation: () => (/* reexport */ getValidation),
|
|
@@ -71,25 +76,29 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
71
76
|
initOnlyValidFromArray: () => (/* reexport */ initOnlyValidFromArray),
|
|
72
77
|
makeApiResponse: () => (/* reexport */ makeApiResponse),
|
|
73
78
|
makeService: () => (/* reexport */ makeService),
|
|
79
|
+
mergeArraysByKey: () => (/* reexport */ mergeArraysByKey),
|
|
74
80
|
objectHelper: () => (/* reexport */ objectHelper),
|
|
75
81
|
pReduce: () => (/* reexport */ pReduce),
|
|
76
82
|
padZeros: () => (/* reexport */ padZeros),
|
|
83
|
+
replacePlaceholders: () => (/* reexport */ replacePlaceholders),
|
|
84
|
+
sanitizeText: () => (/* reexport */ sanitizeText),
|
|
77
85
|
stringFormatter: () => (/* reexport */ stringFormatter),
|
|
78
86
|
stringHelper: () => (/* reexport */ stringHelper),
|
|
87
|
+
tenantPlugin: () => (/* reexport */ tenantPlugin),
|
|
79
88
|
trackingPlugin: () => (/* reexport */ trackingPlugin)
|
|
80
89
|
});
|
|
81
90
|
|
|
82
91
|
;// ./lib/helpers/authorize/authorize.js
|
|
83
|
-
function authorize({ allowOwner, query = {}, required, user }) {
|
|
92
|
+
function authorize({ allowCoordinator, allowOwner, query = {}, required, user }) {
|
|
84
93
|
if (!user) {
|
|
85
94
|
throw new Error('Require login.')
|
|
86
95
|
}
|
|
87
96
|
if (!user.permission) {
|
|
88
|
-
throw new Error('You do not have any permission.')
|
|
97
|
+
// throw new Error('You do not have any permission.')
|
|
89
98
|
}
|
|
90
|
-
const scopes = user.permission.getScopes(required || {})
|
|
99
|
+
const scopes = user.permission.getScopes(required || {}) || []
|
|
91
100
|
if (!scopes || scopes.length === 0) {
|
|
92
|
-
throw new Error('You are not allowed in this scope.')
|
|
101
|
+
// throw new Error('You are not allowed in this scope.')
|
|
93
102
|
}
|
|
94
103
|
if (!scopes.includes('*')) {
|
|
95
104
|
query.tenantCode = user.tenantCode
|
|
@@ -97,8 +106,21 @@ function authorize({ allowOwner, query = {}, required, user }) {
|
|
|
97
106
|
if (!scopes.includes('TENANT')) {
|
|
98
107
|
query.eventShortCode = user.eventShortCode
|
|
99
108
|
}
|
|
100
|
-
if (!scopes.includes('EVENT')) {
|
|
101
|
-
|
|
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
|
+
}
|
|
102
124
|
}
|
|
103
125
|
if (allowOwner) {
|
|
104
126
|
query.__ALLOW_OWNER = true
|
|
@@ -114,6 +136,29 @@ function authorize({ allowOwner, query = {}, required, user }) {
|
|
|
114
136
|
;// ./lib/helpers/authorize/index.js
|
|
115
137
|
|
|
116
138
|
|
|
139
|
+
;// ./lib/helpers/changeCreatorOwner/changeCreatorOwner.js
|
|
140
|
+
function changeCreatorOwner(that, { source, target }) {
|
|
141
|
+
if (that.meta) {
|
|
142
|
+
if (!that.meta.creator || that.meta.creator === source.getId()) {
|
|
143
|
+
that.meta.creator = target.getId()
|
|
144
|
+
}
|
|
145
|
+
if (!that.meta.owner || that.meta.owner === source.getId()) {
|
|
146
|
+
that.meta.owner = target.getId()
|
|
147
|
+
}
|
|
148
|
+
} else {
|
|
149
|
+
if (!that.creator || that.creator === source.getId()) {
|
|
150
|
+
that.creator = target.getId()
|
|
151
|
+
}
|
|
152
|
+
if (!that.owner || that.owner === source.getId()) {
|
|
153
|
+
that.owner = target.getId()
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
return that
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
;// ./lib/helpers/changeCreatorOwner/index.js
|
|
160
|
+
|
|
161
|
+
|
|
117
162
|
;// ./lib/helpers/getValidation/getValidation.js
|
|
118
163
|
function getValidation(rule, data, getDataByKey, KeyValueObject) {
|
|
119
164
|
if (!rule) {
|
|
@@ -122,10 +167,10 @@ function getValidation(rule, data, getDataByKey, KeyValueObject) {
|
|
|
122
167
|
if (typeof getDataByKey !== 'function' || (KeyValueObject && typeof KeyValueObject !== 'function')) {
|
|
123
168
|
return false
|
|
124
169
|
}
|
|
125
|
-
const { key = '', value, keyValuePath = '' } = rule
|
|
170
|
+
const { key = '', value, placeholder, keyValuePath = '' } = rule
|
|
126
171
|
const [valueAttribute] = Object.keys(value)
|
|
127
172
|
|
|
128
|
-
if (!key) {
|
|
173
|
+
if (!key && typeof placeholder === 'undefined') {
|
|
129
174
|
switch (valueAttribute) {
|
|
130
175
|
case '$and': {
|
|
131
176
|
return value['$and'].reduce((acc, item) => (acc && getValidation(item, data, getDataByKey, KeyValueObject)), true)
|
|
@@ -137,14 +182,10 @@ function getValidation(rule, data, getDataByKey, KeyValueObject) {
|
|
|
137
182
|
return false
|
|
138
183
|
}
|
|
139
184
|
}
|
|
140
|
-
|
|
141
|
-
let rowValue = getDataByKey(key, data)
|
|
142
|
-
|
|
143
|
-
// debugger
|
|
185
|
+
let rowValue = typeof placeholder === 'undefined' ? getDataByKey(key, data) : placeholder
|
|
144
186
|
|
|
145
187
|
// if KeyValue object
|
|
146
188
|
if (keyValuePath) {
|
|
147
|
-
console.log('keyValuePath', keyValuePath)
|
|
148
189
|
const rowValueData = KeyValueObject.toObject(rowValue)
|
|
149
190
|
rowValue = getDataByKey(keyValuePath, rowValueData)
|
|
150
191
|
}
|
|
@@ -163,6 +204,9 @@ function getValidation(rule, data, getDataByKey, KeyValueObject) {
|
|
|
163
204
|
case '$gte': {
|
|
164
205
|
return rowValue >= value['$gte']
|
|
165
206
|
}
|
|
207
|
+
case '$hasOverlap': {
|
|
208
|
+
return _hasOverlap(rowValue, value['$hasOverlap'])
|
|
209
|
+
}
|
|
166
210
|
case '$lt': {
|
|
167
211
|
return rowValue < value['$lt']
|
|
168
212
|
}
|
|
@@ -239,6 +283,20 @@ function getValidation(rule, data, getDataByKey, KeyValueObject) {
|
|
|
239
283
|
default:
|
|
240
284
|
return false
|
|
241
285
|
}
|
|
286
|
+
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
function _hasOverlap(item1, item2) {
|
|
290
|
+
let arr1 = item1
|
|
291
|
+
let arr2 = item2
|
|
292
|
+
if (typeof arr1 === 'string') {
|
|
293
|
+
arr1 = arr1.split(',')
|
|
294
|
+
}
|
|
295
|
+
if (typeof arr2 === 'string') {
|
|
296
|
+
arr2 = arr2.split(',')
|
|
297
|
+
}
|
|
298
|
+
const set1 = new Set(arr1)
|
|
299
|
+
return arr2.find((i) => (set1.has(i)))
|
|
242
300
|
}
|
|
243
301
|
|
|
244
302
|
/* harmony default export */ const getValidation_getValidation = ({
|
|
@@ -1442,7 +1500,7 @@ function convertString(string, patternMatch = /\$\{(.+?)\}/g, value, getValueByK
|
|
|
1442
1500
|
if (!string) {
|
|
1443
1501
|
return ''
|
|
1444
1502
|
}
|
|
1445
|
-
let _getValueByKeys = typeof getValueByKeys
|
|
1503
|
+
let _getValueByKeys = typeof getValueByKeys === 'function' ? getValueByKeys : getValueByKeys_getValueByKeys
|
|
1446
1504
|
const reg = new RegExp(patternMatch, 'g')
|
|
1447
1505
|
return string.replace(reg, (match, key) => {
|
|
1448
1506
|
const result = _getValueByKeys({ keys: key.split('.'), obj: value })
|
|
@@ -1461,6 +1519,161 @@ function convertString(string, patternMatch = /\$\{(.+?)\}/g, value, getValueByK
|
|
|
1461
1519
|
;// ./lib/helpers/convertString/index.js
|
|
1462
1520
|
|
|
1463
1521
|
|
|
1522
|
+
;// ./lib/helpers/escapeRegex/escapeRegex.js
|
|
1523
|
+
function escapeRegex(string) {
|
|
1524
|
+
return String(string).replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&')
|
|
1525
|
+
}
|
|
1526
|
+
|
|
1527
|
+
;// ./lib/helpers/escapeRegex/index.js
|
|
1528
|
+
|
|
1529
|
+
|
|
1530
|
+
;// ./lib/helpers/expressHelper/customHandler.js
|
|
1531
|
+
function customHandler({ responseHelper, handler, ignoreError = false }) {
|
|
1532
|
+
return async (req, res, next) => {
|
|
1533
|
+
try {
|
|
1534
|
+
await handler({ req, res })
|
|
1535
|
+
await next()
|
|
1536
|
+
} catch (err) {
|
|
1537
|
+
if (ignoreError) {
|
|
1538
|
+
await next()
|
|
1539
|
+
} else {
|
|
1540
|
+
res.status(400).json(responseHelper.standardizeResponse({ err, message: err.message || err }))
|
|
1541
|
+
}
|
|
1542
|
+
}
|
|
1543
|
+
}
|
|
1544
|
+
}
|
|
1545
|
+
|
|
1546
|
+
;// ./lib/helpers/expressHelper/findAllResult.js
|
|
1547
|
+
function findAllResult({ responseHelper, service }) {
|
|
1548
|
+
return async (req, res, next) => {
|
|
1549
|
+
try {
|
|
1550
|
+
const { query } = req
|
|
1551
|
+
const result = await service.findAll({ query })
|
|
1552
|
+
res.locals.findAllResult = result
|
|
1553
|
+
await next()
|
|
1554
|
+
} catch (err) {
|
|
1555
|
+
res.status(400).json(responseHelper.standardizeResponse({ err, message: err.message || err }))
|
|
1556
|
+
}
|
|
1557
|
+
}
|
|
1558
|
+
}
|
|
1559
|
+
|
|
1560
|
+
;// ./lib/helpers/expressHelper/findOneResult.js
|
|
1561
|
+
function findOneResult({ responseHelper, service }) {
|
|
1562
|
+
return async (req, res, next) => {
|
|
1563
|
+
try {
|
|
1564
|
+
const { params, query } = req
|
|
1565
|
+
const { id } = params
|
|
1566
|
+
const result = await service.findOne({
|
|
1567
|
+
query: {
|
|
1568
|
+
...query,
|
|
1569
|
+
id
|
|
1570
|
+
}
|
|
1571
|
+
})
|
|
1572
|
+
res.locals.findOneResult = result
|
|
1573
|
+
await next()
|
|
1574
|
+
} catch (err) {
|
|
1575
|
+
res.status(400).json(responseHelper.standardizeResponse({ err, message: err.message || err }))
|
|
1576
|
+
}
|
|
1577
|
+
}
|
|
1578
|
+
}
|
|
1579
|
+
|
|
1580
|
+
;// ./lib/helpers/expressHelper/postResult.js
|
|
1581
|
+
function postResult({ responseHelper, service }) {
|
|
1582
|
+
return async (req, res, next) => {
|
|
1583
|
+
try {
|
|
1584
|
+
const { body } = req
|
|
1585
|
+
let result
|
|
1586
|
+
if (Array.isArray(body)) {
|
|
1587
|
+
result = await service.saveAll({ docs: body })
|
|
1588
|
+
} else {
|
|
1589
|
+
result = await service.saveOne({ doc: body })
|
|
1590
|
+
}
|
|
1591
|
+
res.locals.postResult = result
|
|
1592
|
+
await next()
|
|
1593
|
+
} catch (err) {
|
|
1594
|
+
res.status(400).json(responseHelper.standardizeResponse({ err, message: err.message || err }))
|
|
1595
|
+
}
|
|
1596
|
+
}
|
|
1597
|
+
}
|
|
1598
|
+
|
|
1599
|
+
;// ./lib/helpers/expressHelper/updateOneResult.js
|
|
1600
|
+
function updateOneResult({ responseHelper, service }) {
|
|
1601
|
+
return async (req, res, next) => {
|
|
1602
|
+
try {
|
|
1603
|
+
const { body, params } = req
|
|
1604
|
+
const { id } = params
|
|
1605
|
+
if (id !== body.id) {
|
|
1606
|
+
throw new Error('id in params and body must be same')
|
|
1607
|
+
}
|
|
1608
|
+
const { data } = await service.findOne({ query: { id } })
|
|
1609
|
+
const doc = data[0]
|
|
1610
|
+
doc.update(body)
|
|
1611
|
+
const result = await service.saveOne({ doc })
|
|
1612
|
+
res.locals.updateOneResult = result
|
|
1613
|
+
await next()
|
|
1614
|
+
} catch (err) {
|
|
1615
|
+
res.status(400).json(responseHelper.standardizeResponse({ err, message: err.message || err }))
|
|
1616
|
+
}
|
|
1617
|
+
}
|
|
1618
|
+
}
|
|
1619
|
+
|
|
1620
|
+
;// ./lib/helpers/expressHelper/index.js
|
|
1621
|
+
|
|
1622
|
+
|
|
1623
|
+
|
|
1624
|
+
|
|
1625
|
+
|
|
1626
|
+
|
|
1627
|
+
|
|
1628
|
+
const expressHelper = {
|
|
1629
|
+
customHandler: customHandler,
|
|
1630
|
+
findAllResult: findAllResult,
|
|
1631
|
+
findOneResult: findOneResult,
|
|
1632
|
+
postResult: postResult,
|
|
1633
|
+
updateOneResult: updateOneResult,
|
|
1634
|
+
}
|
|
1635
|
+
|
|
1636
|
+
;// ./lib/helpers/extractEmails/extractEmails.js
|
|
1637
|
+
/**
|
|
1638
|
+
* Extracts and normalizes unique email addresses from an array containing messy entries
|
|
1639
|
+
* @param {Array} dirtyArray - Array that may contain emails in various formats (may include null/empty entries)
|
|
1640
|
+
* @returns {Array} Sorted array of unique, lowercase email addresses
|
|
1641
|
+
*/
|
|
1642
|
+
function extractEmails(dirtyArray) {
|
|
1643
|
+
const emailRegex = /[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/g
|
|
1644
|
+
const emails = new Set()
|
|
1645
|
+
|
|
1646
|
+
// Handle null/undefined input array
|
|
1647
|
+
if (!dirtyArray) return []
|
|
1648
|
+
|
|
1649
|
+
dirtyArray.forEach(entry => {
|
|
1650
|
+
// Skip null, undefined, empty, or whitespace-only entries
|
|
1651
|
+
if (!entry || typeof entry !== 'string' || !entry.trim()) return
|
|
1652
|
+
|
|
1653
|
+
try {
|
|
1654
|
+
const cleanEntry = entry
|
|
1655
|
+
.replace(/[\u200B-\u200D\uFEFF\u202A-\u202E]/g, '') // Remove hidden chars
|
|
1656
|
+
.replace(/[<>]/g, ' ') // Convert email delimiters to spaces
|
|
1657
|
+
.replace(/\s+/g, ' ') // Collapse multiple whitespace
|
|
1658
|
+
.trim()
|
|
1659
|
+
|
|
1660
|
+
// Extract all email matches
|
|
1661
|
+
const matches = cleanEntry.match(emailRegex)
|
|
1662
|
+
if (matches) {
|
|
1663
|
+
matches.forEach(email => emails.add(email.toLowerCase())) // Normalize to lowercase
|
|
1664
|
+
}
|
|
1665
|
+
} catch (e) {
|
|
1666
|
+
console.warn('Failed to process entry:', entry, e)
|
|
1667
|
+
}
|
|
1668
|
+
})
|
|
1669
|
+
|
|
1670
|
+
// Convert Set to array and sort alphabetically
|
|
1671
|
+
return Array.from(emails).sort((a, b) => a.localeCompare(b))
|
|
1672
|
+
}
|
|
1673
|
+
|
|
1674
|
+
;// ./lib/helpers/extractEmails/index.js
|
|
1675
|
+
|
|
1676
|
+
|
|
1464
1677
|
;// ./lib/helpers/objectHelper/objectHelper.js
|
|
1465
1678
|
const objectHelper = {
|
|
1466
1679
|
get(obj, path) {
|
|
@@ -1744,19 +1957,19 @@ class Repo {
|
|
|
1744
1957
|
})
|
|
1745
1958
|
}
|
|
1746
1959
|
|
|
1747
|
-
saveAll({ docs, systemLog }) {
|
|
1960
|
+
saveAll({ config = {}, docs, systemLog }) {
|
|
1748
1961
|
let isNew
|
|
1749
1962
|
const log = _makeLog({
|
|
1750
1963
|
systemLog,
|
|
1751
1964
|
label: 'REPO_WRITE',
|
|
1752
1965
|
message: `fn ${this._classname}.prototype.saveAll`,
|
|
1753
|
-
input: [{ docs: [...docs], systemLog: { ...systemLog } }]
|
|
1966
|
+
input: [{ config, docs: [...docs], systemLog: { ...systemLog } }]
|
|
1754
1967
|
})
|
|
1755
1968
|
const promise = typeof this.model.saveAll === 'function'
|
|
1756
|
-
? this.model.saveAll({ docs })
|
|
1969
|
+
? this.model.saveAll({ config, docs })
|
|
1757
1970
|
: Promise.all(docs.map(async (doc) => {
|
|
1758
1971
|
if (doc) {
|
|
1759
|
-
const result = await this.saveOne({ doc })
|
|
1972
|
+
const result = await this.saveOne({ config, doc })
|
|
1760
1973
|
isNew = result.isNew
|
|
1761
1974
|
const _data = result._data || result.data
|
|
1762
1975
|
return _data[0]
|
|
@@ -1778,15 +1991,19 @@ class Repo {
|
|
|
1778
1991
|
})
|
|
1779
1992
|
}
|
|
1780
1993
|
|
|
1781
|
-
saveOne({ doc, systemLog }) {
|
|
1994
|
+
saveOne({ config = {}, doc, systemLog }) {
|
|
1782
1995
|
const log = _makeLog({
|
|
1783
1996
|
systemLog,
|
|
1784
1997
|
label: 'REPO_WRITE',
|
|
1785
1998
|
message: `fn ${this._classname}.prototype.saveOne`,
|
|
1786
|
-
input: [{ doc: { ...doc }, systemLog: { ...systemLog } }]
|
|
1999
|
+
input: [{ config, doc: { ...doc }, systemLog: { ...systemLog } }]
|
|
1787
2000
|
})
|
|
2001
|
+
const saveOptions = {
|
|
2002
|
+
...this.saveOptions,
|
|
2003
|
+
...config,
|
|
2004
|
+
}
|
|
1788
2005
|
return new Promise((resolve, reject) => {
|
|
1789
|
-
this.model.saveOne(doc,
|
|
2006
|
+
this.model.saveOne(doc, saveOptions, (err, result) => {
|
|
1790
2007
|
if (err) {
|
|
1791
2008
|
log({ level: 'warn', output: err.toString() })
|
|
1792
2009
|
reject(err)
|
|
@@ -1928,11 +2145,11 @@ class Service {
|
|
|
1928
2145
|
return this.initFromArray(arr).filter((i) => i)
|
|
1929
2146
|
}
|
|
1930
2147
|
|
|
1931
|
-
async saveAll({
|
|
2148
|
+
async saveAll({ config = {}, docs = [], systemLog } = {}) {
|
|
1932
2149
|
const copies = docs.map((doc) => {
|
|
1933
2150
|
return config.skipInit ? doc : this.init(doc)
|
|
1934
2151
|
})
|
|
1935
|
-
const result = await this.repo.saveAll({ docs: copies, systemLog })
|
|
2152
|
+
const result = await this.repo.saveAll({ config, docs: copies, systemLog })
|
|
1936
2153
|
return makeApiResponse({
|
|
1937
2154
|
repo: this.repo,
|
|
1938
2155
|
result
|
|
@@ -1940,10 +2157,10 @@ class Service {
|
|
|
1940
2157
|
}
|
|
1941
2158
|
|
|
1942
2159
|
// set skipInit to true if we want to use POST for query
|
|
1943
|
-
async saveOne({
|
|
2160
|
+
async saveOne({ config = {}, doc = {}, systemLog } = {}) {
|
|
1944
2161
|
const copy = config.skipInit ? doc : this.init(doc)
|
|
1945
2162
|
if (copy) {
|
|
1946
|
-
const result = await this.repo.saveOne({ doc: copy, systemLog })
|
|
2163
|
+
const result = await this.repo.saveOne({ config, doc: copy, systemLog })
|
|
1947
2164
|
return makeApiResponse({
|
|
1948
2165
|
repo: this.repo,
|
|
1949
2166
|
result
|
|
@@ -2072,6 +2289,64 @@ function initOnlyValidFromArray(_class, arr) {
|
|
|
2072
2289
|
;// ./lib/helpers/initOnlyValidFromArray/index.js
|
|
2073
2290
|
|
|
2074
2291
|
|
|
2292
|
+
;// ./lib/helpers/mergeArraysByKey/mergeArraysByKey.js
|
|
2293
|
+
function mergeArraysByKey(arr1, arr2) {
|
|
2294
|
+
// Handle undefined/null inputs by defaulting to empty arrays
|
|
2295
|
+
const safeArr1 = Array.isArray(arr1) ? arr1 : []
|
|
2296
|
+
const safeArr2 = Array.isArray(arr2) ? arr2 : []
|
|
2297
|
+
|
|
2298
|
+
const mergedMap = new Map()
|
|
2299
|
+
|
|
2300
|
+
// Helper function to merge values based on their type
|
|
2301
|
+
const mergeValues = (existingValue, newValue) => {
|
|
2302
|
+
if (existingValue === undefined) return newValue
|
|
2303
|
+
|
|
2304
|
+
// Handle arrays by concatenating
|
|
2305
|
+
if (Array.isArray(existingValue) && Array.isArray(newValue)) {
|
|
2306
|
+
return [...new Set([...existingValue, ...newValue])]
|
|
2307
|
+
}
|
|
2308
|
+
|
|
2309
|
+
// Handle objects by merging
|
|
2310
|
+
if (typeof existingValue === 'object' && typeof newValue === 'object' &&
|
|
2311
|
+
!Array.isArray(existingValue) && !Array.isArray(newValue)) {
|
|
2312
|
+
return { ...existingValue, ...newValue }
|
|
2313
|
+
}
|
|
2314
|
+
|
|
2315
|
+
// // Handle numbers by adding
|
|
2316
|
+
// if (typeof existingValue === 'number' && typeof newValue === 'number') {
|
|
2317
|
+
// return existingValue
|
|
2318
|
+
// }
|
|
2319
|
+
|
|
2320
|
+
// // Handle strings by concatenating
|
|
2321
|
+
// if (typeof existingValue === 'string' && typeof newValue === 'string') {
|
|
2322
|
+
// return existingValue
|
|
2323
|
+
// }
|
|
2324
|
+
|
|
2325
|
+
// Default: use the new value
|
|
2326
|
+
return newValue
|
|
2327
|
+
}
|
|
2328
|
+
|
|
2329
|
+
// Process first array
|
|
2330
|
+
safeArr1.forEach(item => {
|
|
2331
|
+
mergedMap.set(item.key, item.value)
|
|
2332
|
+
})
|
|
2333
|
+
|
|
2334
|
+
// Process second array and merge values
|
|
2335
|
+
safeArr2.forEach(item => {
|
|
2336
|
+
const existingValue = mergedMap.get(item.key)
|
|
2337
|
+
mergedMap.set(item.key, mergeValues(existingValue, item.value))
|
|
2338
|
+
})
|
|
2339
|
+
|
|
2340
|
+
// Convert back to array format
|
|
2341
|
+
return Array.from(mergedMap.entries()).map(([key, value]) => ({
|
|
2342
|
+
key,
|
|
2343
|
+
value
|
|
2344
|
+
}))
|
|
2345
|
+
}
|
|
2346
|
+
|
|
2347
|
+
;// ./lib/helpers/mergeArraysByKey/index.js
|
|
2348
|
+
|
|
2349
|
+
|
|
2075
2350
|
;// ./lib/helpers/padZeros/padZeros.js
|
|
2076
2351
|
function padZeros(num, minLength = 6) {
|
|
2077
2352
|
num = num.toString()
|
|
@@ -2093,6 +2368,102 @@ function padZeros(num, minLength = 6) {
|
|
|
2093
2368
|
|
|
2094
2369
|
|
|
2095
2370
|
|
|
2371
|
+
;// ./lib/helpers/replacePlaceholders/replacePlaceholders.js
|
|
2372
|
+
function replacePlaceholders({ content, mapping }) {
|
|
2373
|
+
let isObjectMode = false
|
|
2374
|
+
|
|
2375
|
+
if (typeof content === 'object' && content !== null) {
|
|
2376
|
+
content = JSON.stringify(content)
|
|
2377
|
+
isObjectMode = true
|
|
2378
|
+
}
|
|
2379
|
+
|
|
2380
|
+
// [[ eventRegistration.eventRegistrationCode | 0 ]]
|
|
2381
|
+
const regex = /(\[*)\[\[\s*([\w.\-_]+)(?:\s*\|\s*([^:\]\s]+))?(?:\s*:\s*([^\]\s]+))?\s*\]\](\]*)/g;
|
|
2382
|
+
|
|
2383
|
+
const result = content.replace(regex, (match, leadingBrackets, path, defaultValue, type, trailingBrackets) => {
|
|
2384
|
+
|
|
2385
|
+
// Split the path into parts
|
|
2386
|
+
const keys = path.trim().split('.')
|
|
2387
|
+
|
|
2388
|
+
// Traverse the nested object structure
|
|
2389
|
+
let value = mapping
|
|
2390
|
+
for (const key of keys) {
|
|
2391
|
+
// Handle empty keys (in case of double dots or leading/trailing dots)
|
|
2392
|
+
if (!key) continue
|
|
2393
|
+
|
|
2394
|
+
value = value?.[key]
|
|
2395
|
+
if (value === undefined) {
|
|
2396
|
+
break
|
|
2397
|
+
}
|
|
2398
|
+
}
|
|
2399
|
+
|
|
2400
|
+
// Apply default if missing
|
|
2401
|
+
if (value === undefined) value = defaultValue?.trim();
|
|
2402
|
+
if (value === undefined) return isObjectMode ? undefined : match;
|
|
2403
|
+
|
|
2404
|
+
value = value !== undefined
|
|
2405
|
+
? leadingBrackets + value + trailingBrackets
|
|
2406
|
+
: match
|
|
2407
|
+
|
|
2408
|
+
// Return replacement or original if not found
|
|
2409
|
+
return value
|
|
2410
|
+
})
|
|
2411
|
+
|
|
2412
|
+
if (isObjectMode) {
|
|
2413
|
+
return JSON.parse(result)
|
|
2414
|
+
}
|
|
2415
|
+
return result
|
|
2416
|
+
}
|
|
2417
|
+
|
|
2418
|
+
;// ./lib/helpers/replacePlaceholders/index.js
|
|
2419
|
+
|
|
2420
|
+
|
|
2421
|
+
;// ./lib/helpers/sanitizeText/sanitizeText.js
|
|
2422
|
+
/**
|
|
2423
|
+
* Sanitizes input by removing hidden/control characters with customizable whitespace handling.
|
|
2424
|
+
* @param {string} input - The string to sanitize.
|
|
2425
|
+
* @param {Object} [options] - Configuration options.
|
|
2426
|
+
* @param {boolean} [options.normalizeWhitespace=true] - Collapse multiple spaces/tabs into one space.
|
|
2427
|
+
* @param {boolean} [options.removeNewlines=false] - If true, replaces newlines with spaces.
|
|
2428
|
+
* @param {boolean} [options.trim=true] - If true, trims leading/trailing whitespace.
|
|
2429
|
+
* @returns {string} The sanitized string.
|
|
2430
|
+
*/
|
|
2431
|
+
function sanitizeText(input, options = {}) {
|
|
2432
|
+
const {
|
|
2433
|
+
normalizeWhitespace = true,
|
|
2434
|
+
removeNewlines = false,
|
|
2435
|
+
trim = true,
|
|
2436
|
+
} = options
|
|
2437
|
+
|
|
2438
|
+
if (typeof input !== 'string') {
|
|
2439
|
+
return input
|
|
2440
|
+
}
|
|
2441
|
+
|
|
2442
|
+
let result = input
|
|
2443
|
+
|
|
2444
|
+
// Phase 1: Remove hidden/control characters
|
|
2445
|
+
result = result.replace(/[\u200B-\u200D\uFEFF\u202A-\u202E]/g, '')
|
|
2446
|
+
|
|
2447
|
+
// Phase 2: Handle whitespace transformations
|
|
2448
|
+
if (removeNewlines) {
|
|
2449
|
+
result = result.replace(/[\r\n]+/g, ' ') // Convert newlines to spaces
|
|
2450
|
+
}
|
|
2451
|
+
|
|
2452
|
+
if (normalizeWhitespace) {
|
|
2453
|
+
result = result.replace(/[ \t]+/g, ' ') // Collapse spaces/tabs to single space
|
|
2454
|
+
}
|
|
2455
|
+
|
|
2456
|
+
// Phase 3: Final trimming
|
|
2457
|
+
if (trim) {
|
|
2458
|
+
result = result.trim()
|
|
2459
|
+
}
|
|
2460
|
+
|
|
2461
|
+
return result
|
|
2462
|
+
}
|
|
2463
|
+
|
|
2464
|
+
;// ./lib/helpers/sanitizeText/index.js
|
|
2465
|
+
|
|
2466
|
+
|
|
2096
2467
|
;// ./lib/helpers/stringFormatter/stringFormatter.js
|
|
2097
2468
|
function stringFormatter(str, delimiter = '_') {
|
|
2098
2469
|
if (str === null || typeof str === 'undefined' || typeof str.toString === 'undefined') {
|
|
@@ -2218,10 +2589,18 @@ function toCamelCase(str) {
|
|
|
2218
2589
|
.join('')
|
|
2219
2590
|
}
|
|
2220
2591
|
|
|
2592
|
+
function toLowerCase(str) {
|
|
2593
|
+
if (!str) return ''
|
|
2594
|
+
return str
|
|
2595
|
+
.trim()
|
|
2596
|
+
.toLowerCase()
|
|
2597
|
+
}
|
|
2598
|
+
|
|
2221
2599
|
const stringHelper = {
|
|
2222
2600
|
isSame,
|
|
2223
2601
|
setCode,
|
|
2224
2602
|
toCamelCase,
|
|
2603
|
+
toLowerCase,
|
|
2225
2604
|
}
|
|
2226
2605
|
|
|
2227
2606
|
|
|
@@ -2251,6 +2630,19 @@ function trackingPlugin(schema, options) {
|
|
|
2251
2630
|
next()
|
|
2252
2631
|
})
|
|
2253
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
|
+
|
|
2254
2646
|
// Optional: Add helper methods
|
|
2255
2647
|
// schema.methods.touch = function(userId) {
|
|
2256
2648
|
// this.meta.updatedAt = new Date()
|
|
@@ -2258,6 +2650,57 @@ function trackingPlugin(schema, options) {
|
|
|
2258
2650
|
// }
|
|
2259
2651
|
}
|
|
2260
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
|
+
|
|
2261
2704
|
;// ./lib/helpers/trackingPlugin/index.js
|
|
2262
2705
|
|
|
2263
2706
|
|
|
@@ -2274,6 +2717,14 @@ function trackingPlugin(schema, options) {
|
|
|
2274
2717
|
|
|
2275
2718
|
|
|
2276
2719
|
|
|
2720
|
+
|
|
2721
|
+
|
|
2722
|
+
|
|
2723
|
+
|
|
2724
|
+
|
|
2725
|
+
|
|
2726
|
+
|
|
2727
|
+
|
|
2277
2728
|
|
|
2278
2729
|
|
|
2279
2730
|
|
|
@@ -2285,6 +2736,196 @@ function trackingPlugin(schema, options) {
|
|
|
2285
2736
|
|
|
2286
2737
|
|
|
2287
2738
|
|
|
2739
|
+
;// ./lib/models/awsStsS3Client/awsStsS3Client.js
|
|
2740
|
+
class AwsStsS3Client {
|
|
2741
|
+
constructor(options) {
|
|
2742
|
+
options = options || {}
|
|
2743
|
+
|
|
2744
|
+
this.expiration = options.expiration || null
|
|
2745
|
+
this.s3Client = options.s3Client || null
|
|
2746
|
+
this.getIdToken = options.getIdToken
|
|
2747
|
+
this.region = options.region || 'ap-east-1'
|
|
2748
|
+
this.roleArn = options.roleArn
|
|
2749
|
+
this.roleSessionName = options.roleSessionName || 'web-identity-session'
|
|
2750
|
+
this.durationSession = options.durationSession || 3600
|
|
2751
|
+
this.awsClientSts = options.awsClientSts
|
|
2752
|
+
this.awsClientS3 = options.awsClientS3
|
|
2753
|
+
}
|
|
2754
|
+
|
|
2755
|
+
static dummyData() {
|
|
2756
|
+
return {
|
|
2757
|
+
getIdToken: () => 'mock-web-identity-token',
|
|
2758
|
+
roleArn: 'arn:aws:iam::846252828949:role/oidcS3Jccpa',
|
|
2759
|
+
awsClientSts: {
|
|
2760
|
+
STSClient: class {},
|
|
2761
|
+
AssumeRoleWithWebIdentityCommand: class {}
|
|
2762
|
+
},
|
|
2763
|
+
awsClientS3: {
|
|
2764
|
+
S3Client: class {},
|
|
2765
|
+
PutObjectCommand: class {},
|
|
2766
|
+
GetObjectCommand: class {},
|
|
2767
|
+
DeleteObjectCommand: class {}
|
|
2768
|
+
}
|
|
2769
|
+
}
|
|
2770
|
+
}
|
|
2771
|
+
|
|
2772
|
+
static init(options = {}) {
|
|
2773
|
+
if (options instanceof this) {
|
|
2774
|
+
return options
|
|
2775
|
+
}
|
|
2776
|
+
try {
|
|
2777
|
+
const instance = new this(options)
|
|
2778
|
+
if (!instance.isValid) {
|
|
2779
|
+
return null
|
|
2780
|
+
}
|
|
2781
|
+
return instance
|
|
2782
|
+
} catch (error) {
|
|
2783
|
+
return null
|
|
2784
|
+
}
|
|
2785
|
+
}
|
|
2786
|
+
|
|
2787
|
+
get isExpired() {
|
|
2788
|
+
if (!this.expiration) return true;
|
|
2789
|
+
const now = new Date();
|
|
2790
|
+
const bufferMs = 1 * 60 * 1000; // 一分钟缓冲
|
|
2791
|
+
return now >= new Date(this.expiration.getTime() - bufferMs);
|
|
2792
|
+
}
|
|
2793
|
+
|
|
2794
|
+
get isValid() {
|
|
2795
|
+
if (!this.getIdToken) {
|
|
2796
|
+
throw new Error('Missing required configuration: getIdToken function')
|
|
2797
|
+
}
|
|
2798
|
+
if (!this.roleArn) {
|
|
2799
|
+
throw new Error('Missing required configuration: roleArn')
|
|
2800
|
+
}
|
|
2801
|
+
if (!this.awsClientSts) {
|
|
2802
|
+
throw new Error('Missing required AWS awsClientSts client configuration')
|
|
2803
|
+
}
|
|
2804
|
+
if (!this.awsClientSts.STSClient) {
|
|
2805
|
+
throw new Error('Missing STSClient in AWS awsClientSts client configuration')
|
|
2806
|
+
}
|
|
2807
|
+
if (!this.awsClientSts.AssumeRoleWithWebIdentityCommand) {
|
|
2808
|
+
throw new Error('Missing AssumeRoleWithWebIdentityCommand in AWS awsClientSts client configuration')
|
|
2809
|
+
}
|
|
2810
|
+
if (!this.awsClientS3) {
|
|
2811
|
+
throw new Error('Missing required AWS awsClientS3 client configuration')
|
|
2812
|
+
}
|
|
2813
|
+
|
|
2814
|
+
const requiredS3Components = [
|
|
2815
|
+
'S3Client',
|
|
2816
|
+
'PutObjectCommand',
|
|
2817
|
+
'GetObjectCommand',
|
|
2818
|
+
'DeleteObjectCommand'
|
|
2819
|
+
]
|
|
2820
|
+
|
|
2821
|
+
for (const component of requiredS3Components) {
|
|
2822
|
+
if (!this.awsClientS3[component]) {
|
|
2823
|
+
throw new Error(`Missing ${component} in AWS awsClientS3 client configuration`)
|
|
2824
|
+
}
|
|
2825
|
+
}
|
|
2826
|
+
|
|
2827
|
+
return true
|
|
2828
|
+
}
|
|
2829
|
+
|
|
2830
|
+
async refreshCredentials() {
|
|
2831
|
+
try {
|
|
2832
|
+
const webIdentityToken = await this.getIdToken()
|
|
2833
|
+
if (!webIdentityToken) {
|
|
2834
|
+
throw new Error('getIdToken function returned empty or invalid token')
|
|
2835
|
+
}
|
|
2836
|
+
|
|
2837
|
+
const stsClient = new this.awsClientSts.STSClient({ region: this.region })
|
|
2838
|
+
|
|
2839
|
+
const stsResponse = await stsClient.send(
|
|
2840
|
+
new this.awsClientSts.AssumeRoleWithWebIdentityCommand({
|
|
2841
|
+
RoleArn: this.roleArn,
|
|
2842
|
+
RoleSessionName: this.roleSessionName,
|
|
2843
|
+
WebIdentityToken: await this.getIdToken(),
|
|
2844
|
+
DurationSeconds: this.durationSession,
|
|
2845
|
+
})
|
|
2846
|
+
)
|
|
2847
|
+
|
|
2848
|
+
const credentials = stsResponse.Credentials
|
|
2849
|
+
if (!credentials) {
|
|
2850
|
+
throw new Error('No credentials returned from awsClientSts')
|
|
2851
|
+
}
|
|
2852
|
+
|
|
2853
|
+
this.expiration = credentials.Expiration
|
|
2854
|
+
|
|
2855
|
+
this.s3Client = new this.awsClientS3.S3Client({
|
|
2856
|
+
region: this.region,
|
|
2857
|
+
credentials: {
|
|
2858
|
+
accessKeyId: credentials.AccessKeyId,
|
|
2859
|
+
secretAccessKey: credentials.SecretAccessKey,
|
|
2860
|
+
sessionToken: credentials.SessionToken,
|
|
2861
|
+
}
|
|
2862
|
+
})
|
|
2863
|
+
|
|
2864
|
+
return this
|
|
2865
|
+
} catch (error) {
|
|
2866
|
+
throw new Error(`Failed to refresh credentials: ${error.message}`)
|
|
2867
|
+
}
|
|
2868
|
+
}
|
|
2869
|
+
|
|
2870
|
+
async getS3Client() {
|
|
2871
|
+
if (this.isExpired || !this.s3Client) {
|
|
2872
|
+
await this.refreshCredentials()
|
|
2873
|
+
}
|
|
2874
|
+
return this.s3Client
|
|
2875
|
+
}
|
|
2876
|
+
|
|
2877
|
+
async putObject(params) {
|
|
2878
|
+
try {
|
|
2879
|
+
const client = await this.getS3Client()
|
|
2880
|
+
const command = new this.awsClientS3.PutObjectCommand(params)
|
|
2881
|
+
await client.send(command)
|
|
2882
|
+
const fileArr = params.Key.split('/')
|
|
2883
|
+
return {
|
|
2884
|
+
url: `https://s3.${this.region}.amazonaws.com/${params.Bucket}/${params.Key}`,
|
|
2885
|
+
filename: fileArr.pop(),
|
|
2886
|
+
folder: params.Bucket,
|
|
2887
|
+
subFolders: fileArr
|
|
2888
|
+
}
|
|
2889
|
+
} catch (error) {
|
|
2890
|
+
throw new Error(`Failed to put object: ${error.message}`)
|
|
2891
|
+
}
|
|
2892
|
+
}
|
|
2893
|
+
|
|
2894
|
+
async getObject(params) {
|
|
2895
|
+
try {
|
|
2896
|
+
const client = await this.getS3Client()
|
|
2897
|
+
const command = new this.awsClientS3.GetObjectCommand(params)
|
|
2898
|
+
const response = await client.send(command)
|
|
2899
|
+
return {
|
|
2900
|
+
body: response.Body,
|
|
2901
|
+
contentType: response.ContentType,
|
|
2902
|
+
lastModified: response.LastModified,
|
|
2903
|
+
contentLength: response.ContentLength,
|
|
2904
|
+
}
|
|
2905
|
+
} catch (error) {
|
|
2906
|
+
throw new Error(`Failed to get object: ${error.message}`)
|
|
2907
|
+
}
|
|
2908
|
+
}
|
|
2909
|
+
|
|
2910
|
+
async deleteObject(params) {
|
|
2911
|
+
try {
|
|
2912
|
+
const client = await this.getS3Client()
|
|
2913
|
+
const command = new this.awsClientS3.DeleteObjectCommand(params)
|
|
2914
|
+
await client.send(command)
|
|
2915
|
+
return true
|
|
2916
|
+
} catch (error) {
|
|
2917
|
+
throw new Error(`Failed to delete object: ${error.message}`)
|
|
2918
|
+
}
|
|
2919
|
+
}
|
|
2920
|
+
}
|
|
2921
|
+
|
|
2922
|
+
|
|
2923
|
+
|
|
2924
|
+
;// ./lib/models/awsStsS3Client/index.js
|
|
2925
|
+
|
|
2926
|
+
|
|
2927
|
+
|
|
2928
|
+
|
|
2288
2929
|
;// ./lib/models/keyValueObject/keyValueObject.js
|
|
2289
2930
|
class KeyValueObject {
|
|
2290
2931
|
constructor(options = {}) {
|
|
@@ -2412,7 +3053,7 @@ class KeyValueObject {
|
|
|
2412
3053
|
return to.key === from.key
|
|
2413
3054
|
})
|
|
2414
3055
|
if (found) {
|
|
2415
|
-
found.value = (
|
|
3056
|
+
found.value = _mergeValues(from.value, found.value)
|
|
2416
3057
|
} else {
|
|
2417
3058
|
toArr.push(from)
|
|
2418
3059
|
}
|
|
@@ -2428,7 +3069,10 @@ class KeyValueObject {
|
|
|
2428
3069
|
}, [])
|
|
2429
3070
|
}
|
|
2430
3071
|
static sameKey(item, key) {
|
|
2431
|
-
|
|
3072
|
+
if (item) {
|
|
3073
|
+
return _isSame(item.key, key)
|
|
3074
|
+
}
|
|
3075
|
+
return false
|
|
2432
3076
|
}
|
|
2433
3077
|
static toObject(arr = []) {
|
|
2434
3078
|
if (Array.isArray(arr)) {
|
|
@@ -2497,6 +3141,34 @@ class KeyValueObject {
|
|
|
2497
3141
|
}
|
|
2498
3142
|
}
|
|
2499
3143
|
|
|
3144
|
+
function _mergeValues(existingValue, newValue) {
|
|
3145
|
+
if (existingValue === undefined) return newValue
|
|
3146
|
+
|
|
3147
|
+
// Handle arrays by concatenating
|
|
3148
|
+
if (Array.isArray(existingValue) && Array.isArray(newValue)) {
|
|
3149
|
+
return [...new Set([...existingValue, ...newValue])]
|
|
3150
|
+
}
|
|
3151
|
+
|
|
3152
|
+
// Handle objects by merging
|
|
3153
|
+
if (typeof existingValue === 'object' && typeof newValue === 'object' &&
|
|
3154
|
+
!Array.isArray(existingValue) && !Array.isArray(newValue)) {
|
|
3155
|
+
return { ...existingValue, ...newValue }
|
|
3156
|
+
}
|
|
3157
|
+
|
|
3158
|
+
// // Handle numbers by adding
|
|
3159
|
+
// if (typeof existingValue === 'number' && typeof newValue === 'number') {
|
|
3160
|
+
// return existingValue
|
|
3161
|
+
// }
|
|
3162
|
+
|
|
3163
|
+
// // Handle strings by concatenating
|
|
3164
|
+
// if (typeof existingValue === 'string' && typeof newValue === 'string') {
|
|
3165
|
+
// return existingValue
|
|
3166
|
+
// }
|
|
3167
|
+
|
|
3168
|
+
// Default: use the new value
|
|
3169
|
+
return newValue
|
|
3170
|
+
}
|
|
3171
|
+
|
|
2500
3172
|
function _isSame(key1, key2) {
|
|
2501
3173
|
return key1 === key2
|
|
2502
3174
|
}
|
|
@@ -2535,7 +3207,7 @@ class Metadata extends KeyValueObject {
|
|
|
2535
3207
|
return metadata_isSame(to.key, from.key)
|
|
2536
3208
|
})
|
|
2537
3209
|
if (found) {
|
|
2538
|
-
found.value = (
|
|
3210
|
+
found.value = metadata_mergeValues(from.value, found.value)
|
|
2539
3211
|
} else {
|
|
2540
3212
|
toArr.push(from)
|
|
2541
3213
|
}
|
|
@@ -2551,6 +3223,34 @@ function metadata_isSame(key1, key2) {
|
|
|
2551
3223
|
return stringFormatter(key1, DELIMITER) === stringFormatter(key2, DELIMITER)
|
|
2552
3224
|
}
|
|
2553
3225
|
|
|
3226
|
+
function metadata_mergeValues(existingValue, newValue) {
|
|
3227
|
+
if (existingValue === undefined) return newValue
|
|
3228
|
+
|
|
3229
|
+
// Handle arrays by concatenating
|
|
3230
|
+
if (Array.isArray(existingValue) && Array.isArray(newValue)) {
|
|
3231
|
+
return [...new Set([...existingValue, ...newValue])]
|
|
3232
|
+
}
|
|
3233
|
+
|
|
3234
|
+
// Handle objects by merging
|
|
3235
|
+
if (typeof existingValue === 'object' && typeof newValue === 'object' &&
|
|
3236
|
+
!Array.isArray(existingValue) && !Array.isArray(newValue)) {
|
|
3237
|
+
return { ...existingValue, ...newValue }
|
|
3238
|
+
}
|
|
3239
|
+
|
|
3240
|
+
// // Handle numbers by adding
|
|
3241
|
+
// if (typeof existingValue === 'number' && typeof newValue === 'number') {
|
|
3242
|
+
// return existingValue
|
|
3243
|
+
// }
|
|
3244
|
+
|
|
3245
|
+
// // Handle strings by concatenating
|
|
3246
|
+
// if (typeof existingValue === 'string' && typeof newValue === 'string') {
|
|
3247
|
+
// return existingValue
|
|
3248
|
+
// }
|
|
3249
|
+
|
|
3250
|
+
// Default: use the new value
|
|
3251
|
+
return newValue
|
|
3252
|
+
}
|
|
3253
|
+
|
|
2554
3254
|
|
|
2555
3255
|
|
|
2556
3256
|
;// ./lib/models/metadata/index.js
|
|
@@ -2626,17 +3326,19 @@ class TrackedEntity {
|
|
|
2626
3326
|
constructor(options = {}) {
|
|
2627
3327
|
options = options || {}
|
|
2628
3328
|
const timestamp = Date.now()
|
|
2629
|
-
|
|
2630
|
-
active: options.active ?? true,
|
|
2631
|
-
created: options.created ??
|
|
2632
|
-
|
|
2633
|
-
|
|
2634
|
-
|
|
2635
|
-
|
|
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 ?? '',
|
|
2636
3340
|
}
|
|
2637
3341
|
|
|
2638
|
-
this.meta = { ..._tracking, ...options.meta }
|
|
2639
|
-
|
|
2640
3342
|
// if (trackFlat) {
|
|
2641
3343
|
// Object.assign(this, _tracking)
|
|
2642
3344
|
// } else {
|
|
@@ -2688,6 +3390,9 @@ class TrackedEntity {
|
|
|
2688
3390
|
get owner() {
|
|
2689
3391
|
return this.meta?.owner ?? this.owner
|
|
2690
3392
|
}
|
|
3393
|
+
changeCreatorOwner({ source, target }) {
|
|
3394
|
+
return changeCreatorOwner(this, { source, target }).setModified()
|
|
3395
|
+
}
|
|
2691
3396
|
delete() {
|
|
2692
3397
|
return this.setDeleted()
|
|
2693
3398
|
}
|
|
@@ -2894,6 +3599,7 @@ function _makeSetCode(fieldName, options) {
|
|
|
2894
3599
|
|
|
2895
3600
|
|
|
2896
3601
|
|
|
3602
|
+
|
|
2897
3603
|
;// ./lib/index.js
|
|
2898
3604
|
|
|
2899
3605
|
|