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