@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.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
|
|
@@ -34,6 +47,29 @@ function authorize({ allowOwner, query = {}, required, user }) {
|
|
|
34
47
|
;// ./lib/helpers/authorize/index.js
|
|
35
48
|
|
|
36
49
|
|
|
50
|
+
;// ./lib/helpers/changeCreatorOwner/changeCreatorOwner.js
|
|
51
|
+
function changeCreatorOwner(that, { source, target }) {
|
|
52
|
+
if (that.meta) {
|
|
53
|
+
if (!that.meta.creator || that.meta.creator === source.getId()) {
|
|
54
|
+
that.meta.creator = target.getId()
|
|
55
|
+
}
|
|
56
|
+
if (!that.meta.owner || that.meta.owner === source.getId()) {
|
|
57
|
+
that.meta.owner = target.getId()
|
|
58
|
+
}
|
|
59
|
+
} else {
|
|
60
|
+
if (!that.creator || that.creator === source.getId()) {
|
|
61
|
+
that.creator = target.getId()
|
|
62
|
+
}
|
|
63
|
+
if (!that.owner || that.owner === source.getId()) {
|
|
64
|
+
that.owner = target.getId()
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return that
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
;// ./lib/helpers/changeCreatorOwner/index.js
|
|
71
|
+
|
|
72
|
+
|
|
37
73
|
;// ./lib/helpers/getValidation/getValidation.js
|
|
38
74
|
function getValidation(rule, data, getDataByKey, KeyValueObject) {
|
|
39
75
|
if (!rule) {
|
|
@@ -42,10 +78,10 @@ function getValidation(rule, data, getDataByKey, KeyValueObject) {
|
|
|
42
78
|
if (typeof getDataByKey !== 'function' || (KeyValueObject && typeof KeyValueObject !== 'function')) {
|
|
43
79
|
return false
|
|
44
80
|
}
|
|
45
|
-
const { key = '', value, keyValuePath = '' } = rule
|
|
81
|
+
const { key = '', value, placeholder, keyValuePath = '' } = rule
|
|
46
82
|
const [valueAttribute] = Object.keys(value)
|
|
47
83
|
|
|
48
|
-
if (!key) {
|
|
84
|
+
if (!key && typeof placeholder === 'undefined') {
|
|
49
85
|
switch (valueAttribute) {
|
|
50
86
|
case '$and': {
|
|
51
87
|
return value['$and'].reduce((acc, item) => (acc && getValidation(item, data, getDataByKey, KeyValueObject)), true)
|
|
@@ -57,14 +93,10 @@ function getValidation(rule, data, getDataByKey, KeyValueObject) {
|
|
|
57
93
|
return false
|
|
58
94
|
}
|
|
59
95
|
}
|
|
60
|
-
|
|
61
|
-
let rowValue = getDataByKey(key, data)
|
|
62
|
-
|
|
63
|
-
// debugger
|
|
96
|
+
let rowValue = typeof placeholder === 'undefined' ? getDataByKey(key, data) : placeholder
|
|
64
97
|
|
|
65
98
|
// if KeyValue object
|
|
66
99
|
if (keyValuePath) {
|
|
67
|
-
console.log('keyValuePath', keyValuePath)
|
|
68
100
|
const rowValueData = KeyValueObject.toObject(rowValue)
|
|
69
101
|
rowValue = getDataByKey(keyValuePath, rowValueData)
|
|
70
102
|
}
|
|
@@ -83,6 +115,9 @@ function getValidation(rule, data, getDataByKey, KeyValueObject) {
|
|
|
83
115
|
case '$gte': {
|
|
84
116
|
return rowValue >= value['$gte']
|
|
85
117
|
}
|
|
118
|
+
case '$hasOverlap': {
|
|
119
|
+
return _hasOverlap(rowValue, value['$hasOverlap'])
|
|
120
|
+
}
|
|
86
121
|
case '$lt': {
|
|
87
122
|
return rowValue < value['$lt']
|
|
88
123
|
}
|
|
@@ -159,6 +194,20 @@ function getValidation(rule, data, getDataByKey, KeyValueObject) {
|
|
|
159
194
|
default:
|
|
160
195
|
return false
|
|
161
196
|
}
|
|
197
|
+
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
function _hasOverlap(item1, item2) {
|
|
201
|
+
let arr1 = item1
|
|
202
|
+
let arr2 = item2
|
|
203
|
+
if (typeof arr1 === 'string') {
|
|
204
|
+
arr1 = arr1.split(',')
|
|
205
|
+
}
|
|
206
|
+
if (typeof arr2 === 'string') {
|
|
207
|
+
arr2 = arr2.split(',')
|
|
208
|
+
}
|
|
209
|
+
const set1 = new Set(arr1)
|
|
210
|
+
return arr2.find((i) => (set1.has(i)))
|
|
162
211
|
}
|
|
163
212
|
|
|
164
213
|
/* harmony default export */ const getValidation_getValidation = ({
|
|
@@ -1362,7 +1411,7 @@ function convertString(string, patternMatch = /\$\{(.+?)\}/g, value, getValueByK
|
|
|
1362
1411
|
if (!string) {
|
|
1363
1412
|
return ''
|
|
1364
1413
|
}
|
|
1365
|
-
let _getValueByKeys = typeof getValueByKeys
|
|
1414
|
+
let _getValueByKeys = typeof getValueByKeys === 'function' ? getValueByKeys : getValueByKeys_getValueByKeys
|
|
1366
1415
|
const reg = new RegExp(patternMatch, 'g')
|
|
1367
1416
|
return string.replace(reg, (match, key) => {
|
|
1368
1417
|
const result = _getValueByKeys({ keys: key.split('.'), obj: value })
|
|
@@ -1381,6 +1430,161 @@ function convertString(string, patternMatch = /\$\{(.+?)\}/g, value, getValueByK
|
|
|
1381
1430
|
;// ./lib/helpers/convertString/index.js
|
|
1382
1431
|
|
|
1383
1432
|
|
|
1433
|
+
;// ./lib/helpers/escapeRegex/escapeRegex.js
|
|
1434
|
+
function escapeRegex(string) {
|
|
1435
|
+
return String(string).replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&')
|
|
1436
|
+
}
|
|
1437
|
+
|
|
1438
|
+
;// ./lib/helpers/escapeRegex/index.js
|
|
1439
|
+
|
|
1440
|
+
|
|
1441
|
+
;// ./lib/helpers/expressHelper/customHandler.js
|
|
1442
|
+
function customHandler({ responseHelper, handler, ignoreError = false }) {
|
|
1443
|
+
return async (req, res, next) => {
|
|
1444
|
+
try {
|
|
1445
|
+
await handler({ req, res })
|
|
1446
|
+
await next()
|
|
1447
|
+
} catch (err) {
|
|
1448
|
+
if (ignoreError) {
|
|
1449
|
+
await next()
|
|
1450
|
+
} else {
|
|
1451
|
+
res.status(400).json(responseHelper.standardizeResponse({ err, message: err.message || err }))
|
|
1452
|
+
}
|
|
1453
|
+
}
|
|
1454
|
+
}
|
|
1455
|
+
}
|
|
1456
|
+
|
|
1457
|
+
;// ./lib/helpers/expressHelper/findAllResult.js
|
|
1458
|
+
function findAllResult({ responseHelper, service }) {
|
|
1459
|
+
return async (req, res, next) => {
|
|
1460
|
+
try {
|
|
1461
|
+
const { query } = req
|
|
1462
|
+
const result = await service.findAll({ query })
|
|
1463
|
+
res.locals.findAllResult = result
|
|
1464
|
+
await next()
|
|
1465
|
+
} catch (err) {
|
|
1466
|
+
res.status(400).json(responseHelper.standardizeResponse({ err, message: err.message || err }))
|
|
1467
|
+
}
|
|
1468
|
+
}
|
|
1469
|
+
}
|
|
1470
|
+
|
|
1471
|
+
;// ./lib/helpers/expressHelper/findOneResult.js
|
|
1472
|
+
function findOneResult({ responseHelper, service }) {
|
|
1473
|
+
return async (req, res, next) => {
|
|
1474
|
+
try {
|
|
1475
|
+
const { params, query } = req
|
|
1476
|
+
const { id } = params
|
|
1477
|
+
const result = await service.findOne({
|
|
1478
|
+
query: {
|
|
1479
|
+
...query,
|
|
1480
|
+
id
|
|
1481
|
+
}
|
|
1482
|
+
})
|
|
1483
|
+
res.locals.findOneResult = result
|
|
1484
|
+
await next()
|
|
1485
|
+
} catch (err) {
|
|
1486
|
+
res.status(400).json(responseHelper.standardizeResponse({ err, message: err.message || err }))
|
|
1487
|
+
}
|
|
1488
|
+
}
|
|
1489
|
+
}
|
|
1490
|
+
|
|
1491
|
+
;// ./lib/helpers/expressHelper/postResult.js
|
|
1492
|
+
function postResult({ responseHelper, service }) {
|
|
1493
|
+
return async (req, res, next) => {
|
|
1494
|
+
try {
|
|
1495
|
+
const { body } = req
|
|
1496
|
+
let result
|
|
1497
|
+
if (Array.isArray(body)) {
|
|
1498
|
+
result = await service.saveAll({ docs: body })
|
|
1499
|
+
} else {
|
|
1500
|
+
result = await service.saveOne({ doc: body })
|
|
1501
|
+
}
|
|
1502
|
+
res.locals.postResult = result
|
|
1503
|
+
await next()
|
|
1504
|
+
} catch (err) {
|
|
1505
|
+
res.status(400).json(responseHelper.standardizeResponse({ err, message: err.message || err }))
|
|
1506
|
+
}
|
|
1507
|
+
}
|
|
1508
|
+
}
|
|
1509
|
+
|
|
1510
|
+
;// ./lib/helpers/expressHelper/updateOneResult.js
|
|
1511
|
+
function updateOneResult({ responseHelper, service }) {
|
|
1512
|
+
return async (req, res, next) => {
|
|
1513
|
+
try {
|
|
1514
|
+
const { body, params } = req
|
|
1515
|
+
const { id } = params
|
|
1516
|
+
if (id !== body.id) {
|
|
1517
|
+
throw new Error('id in params and body must be same')
|
|
1518
|
+
}
|
|
1519
|
+
const { data } = await service.findOne({ query: { id } })
|
|
1520
|
+
const doc = data[0]
|
|
1521
|
+
doc.update(body)
|
|
1522
|
+
const result = await service.saveOne({ doc })
|
|
1523
|
+
res.locals.updateOneResult = result
|
|
1524
|
+
await next()
|
|
1525
|
+
} catch (err) {
|
|
1526
|
+
res.status(400).json(responseHelper.standardizeResponse({ err, message: err.message || err }))
|
|
1527
|
+
}
|
|
1528
|
+
}
|
|
1529
|
+
}
|
|
1530
|
+
|
|
1531
|
+
;// ./lib/helpers/expressHelper/index.js
|
|
1532
|
+
|
|
1533
|
+
|
|
1534
|
+
|
|
1535
|
+
|
|
1536
|
+
|
|
1537
|
+
|
|
1538
|
+
|
|
1539
|
+
const expressHelper = {
|
|
1540
|
+
customHandler: customHandler,
|
|
1541
|
+
findAllResult: findAllResult,
|
|
1542
|
+
findOneResult: findOneResult,
|
|
1543
|
+
postResult: postResult,
|
|
1544
|
+
updateOneResult: updateOneResult,
|
|
1545
|
+
}
|
|
1546
|
+
|
|
1547
|
+
;// ./lib/helpers/extractEmails/extractEmails.js
|
|
1548
|
+
/**
|
|
1549
|
+
* Extracts and normalizes unique email addresses from an array containing messy entries
|
|
1550
|
+
* @param {Array} dirtyArray - Array that may contain emails in various formats (may include null/empty entries)
|
|
1551
|
+
* @returns {Array} Sorted array of unique, lowercase email addresses
|
|
1552
|
+
*/
|
|
1553
|
+
function extractEmails(dirtyArray) {
|
|
1554
|
+
const emailRegex = /[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/g
|
|
1555
|
+
const emails = new Set()
|
|
1556
|
+
|
|
1557
|
+
// Handle null/undefined input array
|
|
1558
|
+
if (!dirtyArray) return []
|
|
1559
|
+
|
|
1560
|
+
dirtyArray.forEach(entry => {
|
|
1561
|
+
// Skip null, undefined, empty, or whitespace-only entries
|
|
1562
|
+
if (!entry || typeof entry !== 'string' || !entry.trim()) return
|
|
1563
|
+
|
|
1564
|
+
try {
|
|
1565
|
+
const cleanEntry = entry
|
|
1566
|
+
.replace(/[\u200B-\u200D\uFEFF\u202A-\u202E]/g, '') // Remove hidden chars
|
|
1567
|
+
.replace(/[<>]/g, ' ') // Convert email delimiters to spaces
|
|
1568
|
+
.replace(/\s+/g, ' ') // Collapse multiple whitespace
|
|
1569
|
+
.trim()
|
|
1570
|
+
|
|
1571
|
+
// Extract all email matches
|
|
1572
|
+
const matches = cleanEntry.match(emailRegex)
|
|
1573
|
+
if (matches) {
|
|
1574
|
+
matches.forEach(email => emails.add(email.toLowerCase())) // Normalize to lowercase
|
|
1575
|
+
}
|
|
1576
|
+
} catch (e) {
|
|
1577
|
+
console.warn('Failed to process entry:', entry, e)
|
|
1578
|
+
}
|
|
1579
|
+
})
|
|
1580
|
+
|
|
1581
|
+
// Convert Set to array and sort alphabetically
|
|
1582
|
+
return Array.from(emails).sort((a, b) => a.localeCompare(b))
|
|
1583
|
+
}
|
|
1584
|
+
|
|
1585
|
+
;// ./lib/helpers/extractEmails/index.js
|
|
1586
|
+
|
|
1587
|
+
|
|
1384
1588
|
;// ./lib/helpers/objectHelper/objectHelper.js
|
|
1385
1589
|
const objectHelper = {
|
|
1386
1590
|
get(obj, path) {
|
|
@@ -1664,19 +1868,19 @@ class Repo {
|
|
|
1664
1868
|
})
|
|
1665
1869
|
}
|
|
1666
1870
|
|
|
1667
|
-
saveAll({ docs, systemLog }) {
|
|
1871
|
+
saveAll({ config = {}, docs, systemLog }) {
|
|
1668
1872
|
let isNew
|
|
1669
1873
|
const log = _makeLog({
|
|
1670
1874
|
systemLog,
|
|
1671
1875
|
label: 'REPO_WRITE',
|
|
1672
1876
|
message: `fn ${this._classname}.prototype.saveAll`,
|
|
1673
|
-
input: [{ docs: [...docs], systemLog: { ...systemLog } }]
|
|
1877
|
+
input: [{ config, docs: [...docs], systemLog: { ...systemLog } }]
|
|
1674
1878
|
})
|
|
1675
1879
|
const promise = typeof this.model.saveAll === 'function'
|
|
1676
|
-
? this.model.saveAll({ docs })
|
|
1880
|
+
? this.model.saveAll({ config, docs })
|
|
1677
1881
|
: Promise.all(docs.map(async (doc) => {
|
|
1678
1882
|
if (doc) {
|
|
1679
|
-
const result = await this.saveOne({ doc })
|
|
1883
|
+
const result = await this.saveOne({ config, doc })
|
|
1680
1884
|
isNew = result.isNew
|
|
1681
1885
|
const _data = result._data || result.data
|
|
1682
1886
|
return _data[0]
|
|
@@ -1698,15 +1902,19 @@ class Repo {
|
|
|
1698
1902
|
})
|
|
1699
1903
|
}
|
|
1700
1904
|
|
|
1701
|
-
saveOne({ doc, systemLog }) {
|
|
1905
|
+
saveOne({ config = {}, doc, systemLog }) {
|
|
1702
1906
|
const log = _makeLog({
|
|
1703
1907
|
systemLog,
|
|
1704
1908
|
label: 'REPO_WRITE',
|
|
1705
1909
|
message: `fn ${this._classname}.prototype.saveOne`,
|
|
1706
|
-
input: [{ doc: { ...doc }, systemLog: { ...systemLog } }]
|
|
1910
|
+
input: [{ config, doc: { ...doc }, systemLog: { ...systemLog } }]
|
|
1707
1911
|
})
|
|
1912
|
+
const saveOptions = {
|
|
1913
|
+
...this.saveOptions,
|
|
1914
|
+
...config,
|
|
1915
|
+
}
|
|
1708
1916
|
return new Promise((resolve, reject) => {
|
|
1709
|
-
this.model.saveOne(doc,
|
|
1917
|
+
this.model.saveOne(doc, saveOptions, (err, result) => {
|
|
1710
1918
|
if (err) {
|
|
1711
1919
|
log({ level: 'warn', output: err.toString() })
|
|
1712
1920
|
reject(err)
|
|
@@ -1848,11 +2056,11 @@ class Service {
|
|
|
1848
2056
|
return this.initFromArray(arr).filter((i) => i)
|
|
1849
2057
|
}
|
|
1850
2058
|
|
|
1851
|
-
async saveAll({
|
|
2059
|
+
async saveAll({ config = {}, docs = [], systemLog } = {}) {
|
|
1852
2060
|
const copies = docs.map((doc) => {
|
|
1853
2061
|
return config.skipInit ? doc : this.init(doc)
|
|
1854
2062
|
})
|
|
1855
|
-
const result = await this.repo.saveAll({ docs: copies, systemLog })
|
|
2063
|
+
const result = await this.repo.saveAll({ config, docs: copies, systemLog })
|
|
1856
2064
|
return makeApiResponse({
|
|
1857
2065
|
repo: this.repo,
|
|
1858
2066
|
result
|
|
@@ -1860,10 +2068,10 @@ class Service {
|
|
|
1860
2068
|
}
|
|
1861
2069
|
|
|
1862
2070
|
// set skipInit to true if we want to use POST for query
|
|
1863
|
-
async saveOne({
|
|
2071
|
+
async saveOne({ config = {}, doc = {}, systemLog } = {}) {
|
|
1864
2072
|
const copy = config.skipInit ? doc : this.init(doc)
|
|
1865
2073
|
if (copy) {
|
|
1866
|
-
const result = await this.repo.saveOne({ doc: copy, systemLog })
|
|
2074
|
+
const result = await this.repo.saveOne({ config, doc: copy, systemLog })
|
|
1867
2075
|
return makeApiResponse({
|
|
1868
2076
|
repo: this.repo,
|
|
1869
2077
|
result
|
|
@@ -1992,6 +2200,64 @@ function initOnlyValidFromArray(_class, arr) {
|
|
|
1992
2200
|
;// ./lib/helpers/initOnlyValidFromArray/index.js
|
|
1993
2201
|
|
|
1994
2202
|
|
|
2203
|
+
;// ./lib/helpers/mergeArraysByKey/mergeArraysByKey.js
|
|
2204
|
+
function mergeArraysByKey(arr1, arr2) {
|
|
2205
|
+
// Handle undefined/null inputs by defaulting to empty arrays
|
|
2206
|
+
const safeArr1 = Array.isArray(arr1) ? arr1 : []
|
|
2207
|
+
const safeArr2 = Array.isArray(arr2) ? arr2 : []
|
|
2208
|
+
|
|
2209
|
+
const mergedMap = new Map()
|
|
2210
|
+
|
|
2211
|
+
// Helper function to merge values based on their type
|
|
2212
|
+
const mergeValues = (existingValue, newValue) => {
|
|
2213
|
+
if (existingValue === undefined) return newValue
|
|
2214
|
+
|
|
2215
|
+
// Handle arrays by concatenating
|
|
2216
|
+
if (Array.isArray(existingValue) && Array.isArray(newValue)) {
|
|
2217
|
+
return [...new Set([...existingValue, ...newValue])]
|
|
2218
|
+
}
|
|
2219
|
+
|
|
2220
|
+
// Handle objects by merging
|
|
2221
|
+
if (typeof existingValue === 'object' && typeof newValue === 'object' &&
|
|
2222
|
+
!Array.isArray(existingValue) && !Array.isArray(newValue)) {
|
|
2223
|
+
return { ...existingValue, ...newValue }
|
|
2224
|
+
}
|
|
2225
|
+
|
|
2226
|
+
// // Handle numbers by adding
|
|
2227
|
+
// if (typeof existingValue === 'number' && typeof newValue === 'number') {
|
|
2228
|
+
// return existingValue
|
|
2229
|
+
// }
|
|
2230
|
+
|
|
2231
|
+
// // Handle strings by concatenating
|
|
2232
|
+
// if (typeof existingValue === 'string' && typeof newValue === 'string') {
|
|
2233
|
+
// return existingValue
|
|
2234
|
+
// }
|
|
2235
|
+
|
|
2236
|
+
// Default: use the new value
|
|
2237
|
+
return newValue
|
|
2238
|
+
}
|
|
2239
|
+
|
|
2240
|
+
// Process first array
|
|
2241
|
+
safeArr1.forEach(item => {
|
|
2242
|
+
mergedMap.set(item.key, item.value)
|
|
2243
|
+
})
|
|
2244
|
+
|
|
2245
|
+
// Process second array and merge values
|
|
2246
|
+
safeArr2.forEach(item => {
|
|
2247
|
+
const existingValue = mergedMap.get(item.key)
|
|
2248
|
+
mergedMap.set(item.key, mergeValues(existingValue, item.value))
|
|
2249
|
+
})
|
|
2250
|
+
|
|
2251
|
+
// Convert back to array format
|
|
2252
|
+
return Array.from(mergedMap.entries()).map(([key, value]) => ({
|
|
2253
|
+
key,
|
|
2254
|
+
value
|
|
2255
|
+
}))
|
|
2256
|
+
}
|
|
2257
|
+
|
|
2258
|
+
;// ./lib/helpers/mergeArraysByKey/index.js
|
|
2259
|
+
|
|
2260
|
+
|
|
1995
2261
|
;// ./lib/helpers/padZeros/padZeros.js
|
|
1996
2262
|
function padZeros(num, minLength = 6) {
|
|
1997
2263
|
num = num.toString()
|
|
@@ -2013,6 +2279,102 @@ function padZeros(num, minLength = 6) {
|
|
|
2013
2279
|
|
|
2014
2280
|
|
|
2015
2281
|
|
|
2282
|
+
;// ./lib/helpers/replacePlaceholders/replacePlaceholders.js
|
|
2283
|
+
function replacePlaceholders({ content, mapping }) {
|
|
2284
|
+
let isObjectMode = false
|
|
2285
|
+
|
|
2286
|
+
if (typeof content === 'object' && content !== null) {
|
|
2287
|
+
content = JSON.stringify(content)
|
|
2288
|
+
isObjectMode = true
|
|
2289
|
+
}
|
|
2290
|
+
|
|
2291
|
+
// [[ eventRegistration.eventRegistrationCode | 0 ]]
|
|
2292
|
+
const regex = /(\[*)\[\[\s*([\w.\-_]+)(?:\s*\|\s*([^:\]\s]+))?(?:\s*:\s*([^\]\s]+))?\s*\]\](\]*)/g;
|
|
2293
|
+
|
|
2294
|
+
const result = content.replace(regex, (match, leadingBrackets, path, defaultValue, type, trailingBrackets) => {
|
|
2295
|
+
|
|
2296
|
+
// Split the path into parts
|
|
2297
|
+
const keys = path.trim().split('.')
|
|
2298
|
+
|
|
2299
|
+
// Traverse the nested object structure
|
|
2300
|
+
let value = mapping
|
|
2301
|
+
for (const key of keys) {
|
|
2302
|
+
// Handle empty keys (in case of double dots or leading/trailing dots)
|
|
2303
|
+
if (!key) continue
|
|
2304
|
+
|
|
2305
|
+
value = value?.[key]
|
|
2306
|
+
if (value === undefined) {
|
|
2307
|
+
break
|
|
2308
|
+
}
|
|
2309
|
+
}
|
|
2310
|
+
|
|
2311
|
+
// Apply default if missing
|
|
2312
|
+
if (value === undefined) value = defaultValue?.trim();
|
|
2313
|
+
if (value === undefined) return isObjectMode ? undefined : match;
|
|
2314
|
+
|
|
2315
|
+
value = value !== undefined
|
|
2316
|
+
? leadingBrackets + value + trailingBrackets
|
|
2317
|
+
: match
|
|
2318
|
+
|
|
2319
|
+
// Return replacement or original if not found
|
|
2320
|
+
return value
|
|
2321
|
+
})
|
|
2322
|
+
|
|
2323
|
+
if (isObjectMode) {
|
|
2324
|
+
return JSON.parse(result)
|
|
2325
|
+
}
|
|
2326
|
+
return result
|
|
2327
|
+
}
|
|
2328
|
+
|
|
2329
|
+
;// ./lib/helpers/replacePlaceholders/index.js
|
|
2330
|
+
|
|
2331
|
+
|
|
2332
|
+
;// ./lib/helpers/sanitizeText/sanitizeText.js
|
|
2333
|
+
/**
|
|
2334
|
+
* Sanitizes input by removing hidden/control characters with customizable whitespace handling.
|
|
2335
|
+
* @param {string} input - The string to sanitize.
|
|
2336
|
+
* @param {Object} [options] - Configuration options.
|
|
2337
|
+
* @param {boolean} [options.normalizeWhitespace=true] - Collapse multiple spaces/tabs into one space.
|
|
2338
|
+
* @param {boolean} [options.removeNewlines=false] - If true, replaces newlines with spaces.
|
|
2339
|
+
* @param {boolean} [options.trim=true] - If true, trims leading/trailing whitespace.
|
|
2340
|
+
* @returns {string} The sanitized string.
|
|
2341
|
+
*/
|
|
2342
|
+
function sanitizeText(input, options = {}) {
|
|
2343
|
+
const {
|
|
2344
|
+
normalizeWhitespace = true,
|
|
2345
|
+
removeNewlines = false,
|
|
2346
|
+
trim = true,
|
|
2347
|
+
} = options
|
|
2348
|
+
|
|
2349
|
+
if (typeof input !== 'string') {
|
|
2350
|
+
return input
|
|
2351
|
+
}
|
|
2352
|
+
|
|
2353
|
+
let result = input
|
|
2354
|
+
|
|
2355
|
+
// Phase 1: Remove hidden/control characters
|
|
2356
|
+
result = result.replace(/[\u200B-\u200D\uFEFF\u202A-\u202E]/g, '')
|
|
2357
|
+
|
|
2358
|
+
// Phase 2: Handle whitespace transformations
|
|
2359
|
+
if (removeNewlines) {
|
|
2360
|
+
result = result.replace(/[\r\n]+/g, ' ') // Convert newlines to spaces
|
|
2361
|
+
}
|
|
2362
|
+
|
|
2363
|
+
if (normalizeWhitespace) {
|
|
2364
|
+
result = result.replace(/[ \t]+/g, ' ') // Collapse spaces/tabs to single space
|
|
2365
|
+
}
|
|
2366
|
+
|
|
2367
|
+
// Phase 3: Final trimming
|
|
2368
|
+
if (trim) {
|
|
2369
|
+
result = result.trim()
|
|
2370
|
+
}
|
|
2371
|
+
|
|
2372
|
+
return result
|
|
2373
|
+
}
|
|
2374
|
+
|
|
2375
|
+
;// ./lib/helpers/sanitizeText/index.js
|
|
2376
|
+
|
|
2377
|
+
|
|
2016
2378
|
;// ./lib/helpers/stringFormatter/stringFormatter.js
|
|
2017
2379
|
function stringFormatter(str, delimiter = '_') {
|
|
2018
2380
|
if (str === null || typeof str === 'undefined' || typeof str.toString === 'undefined') {
|
|
@@ -2138,10 +2500,18 @@ function toCamelCase(str) {
|
|
|
2138
2500
|
.join('')
|
|
2139
2501
|
}
|
|
2140
2502
|
|
|
2503
|
+
function toLowerCase(str) {
|
|
2504
|
+
if (!str) return ''
|
|
2505
|
+
return str
|
|
2506
|
+
.trim()
|
|
2507
|
+
.toLowerCase()
|
|
2508
|
+
}
|
|
2509
|
+
|
|
2141
2510
|
const stringHelper = {
|
|
2142
2511
|
isSame,
|
|
2143
2512
|
setCode,
|
|
2144
2513
|
toCamelCase,
|
|
2514
|
+
toLowerCase,
|
|
2145
2515
|
}
|
|
2146
2516
|
|
|
2147
2517
|
|
|
@@ -2171,6 +2541,19 @@ function trackingPlugin(schema, options) {
|
|
|
2171
2541
|
next()
|
|
2172
2542
|
})
|
|
2173
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
|
+
|
|
2174
2557
|
// Optional: Add helper methods
|
|
2175
2558
|
// schema.methods.touch = function(userId) {
|
|
2176
2559
|
// this.meta.updatedAt = new Date()
|
|
@@ -2178,6 +2561,57 @@ function trackingPlugin(schema, options) {
|
|
|
2178
2561
|
// }
|
|
2179
2562
|
}
|
|
2180
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
|
+
|
|
2181
2615
|
;// ./lib/helpers/trackingPlugin/index.js
|
|
2182
2616
|
|
|
2183
2617
|
|
|
@@ -2194,6 +2628,14 @@ function trackingPlugin(schema, options) {
|
|
|
2194
2628
|
|
|
2195
2629
|
|
|
2196
2630
|
|
|
2631
|
+
|
|
2632
|
+
|
|
2633
|
+
|
|
2634
|
+
|
|
2635
|
+
|
|
2636
|
+
|
|
2637
|
+
|
|
2638
|
+
|
|
2197
2639
|
|
|
2198
2640
|
|
|
2199
2641
|
|
|
@@ -2205,6 +2647,196 @@ function trackingPlugin(schema, options) {
|
|
|
2205
2647
|
|
|
2206
2648
|
|
|
2207
2649
|
|
|
2650
|
+
;// ./lib/models/awsStsS3Client/awsStsS3Client.js
|
|
2651
|
+
class AwsStsS3Client {
|
|
2652
|
+
constructor(options) {
|
|
2653
|
+
options = options || {}
|
|
2654
|
+
|
|
2655
|
+
this.expiration = options.expiration || null
|
|
2656
|
+
this.s3Client = options.s3Client || null
|
|
2657
|
+
this.getIdToken = options.getIdToken
|
|
2658
|
+
this.region = options.region || 'ap-east-1'
|
|
2659
|
+
this.roleArn = options.roleArn
|
|
2660
|
+
this.roleSessionName = options.roleSessionName || 'web-identity-session'
|
|
2661
|
+
this.durationSession = options.durationSession || 3600
|
|
2662
|
+
this.awsClientSts = options.awsClientSts
|
|
2663
|
+
this.awsClientS3 = options.awsClientS3
|
|
2664
|
+
}
|
|
2665
|
+
|
|
2666
|
+
static dummyData() {
|
|
2667
|
+
return {
|
|
2668
|
+
getIdToken: () => 'mock-web-identity-token',
|
|
2669
|
+
roleArn: 'arn:aws:iam::846252828949:role/oidcS3Jccpa',
|
|
2670
|
+
awsClientSts: {
|
|
2671
|
+
STSClient: class {},
|
|
2672
|
+
AssumeRoleWithWebIdentityCommand: class {}
|
|
2673
|
+
},
|
|
2674
|
+
awsClientS3: {
|
|
2675
|
+
S3Client: class {},
|
|
2676
|
+
PutObjectCommand: class {},
|
|
2677
|
+
GetObjectCommand: class {},
|
|
2678
|
+
DeleteObjectCommand: class {}
|
|
2679
|
+
}
|
|
2680
|
+
}
|
|
2681
|
+
}
|
|
2682
|
+
|
|
2683
|
+
static init(options = {}) {
|
|
2684
|
+
if (options instanceof this) {
|
|
2685
|
+
return options
|
|
2686
|
+
}
|
|
2687
|
+
try {
|
|
2688
|
+
const instance = new this(options)
|
|
2689
|
+
if (!instance.isValid) {
|
|
2690
|
+
return null
|
|
2691
|
+
}
|
|
2692
|
+
return instance
|
|
2693
|
+
} catch (error) {
|
|
2694
|
+
return null
|
|
2695
|
+
}
|
|
2696
|
+
}
|
|
2697
|
+
|
|
2698
|
+
get isExpired() {
|
|
2699
|
+
if (!this.expiration) return true;
|
|
2700
|
+
const now = new Date();
|
|
2701
|
+
const bufferMs = 1 * 60 * 1000; // 一分钟缓冲
|
|
2702
|
+
return now >= new Date(this.expiration.getTime() - bufferMs);
|
|
2703
|
+
}
|
|
2704
|
+
|
|
2705
|
+
get isValid() {
|
|
2706
|
+
if (!this.getIdToken) {
|
|
2707
|
+
throw new Error('Missing required configuration: getIdToken function')
|
|
2708
|
+
}
|
|
2709
|
+
if (!this.roleArn) {
|
|
2710
|
+
throw new Error('Missing required configuration: roleArn')
|
|
2711
|
+
}
|
|
2712
|
+
if (!this.awsClientSts) {
|
|
2713
|
+
throw new Error('Missing required AWS awsClientSts client configuration')
|
|
2714
|
+
}
|
|
2715
|
+
if (!this.awsClientSts.STSClient) {
|
|
2716
|
+
throw new Error('Missing STSClient in AWS awsClientSts client configuration')
|
|
2717
|
+
}
|
|
2718
|
+
if (!this.awsClientSts.AssumeRoleWithWebIdentityCommand) {
|
|
2719
|
+
throw new Error('Missing AssumeRoleWithWebIdentityCommand in AWS awsClientSts client configuration')
|
|
2720
|
+
}
|
|
2721
|
+
if (!this.awsClientS3) {
|
|
2722
|
+
throw new Error('Missing required AWS awsClientS3 client configuration')
|
|
2723
|
+
}
|
|
2724
|
+
|
|
2725
|
+
const requiredS3Components = [
|
|
2726
|
+
'S3Client',
|
|
2727
|
+
'PutObjectCommand',
|
|
2728
|
+
'GetObjectCommand',
|
|
2729
|
+
'DeleteObjectCommand'
|
|
2730
|
+
]
|
|
2731
|
+
|
|
2732
|
+
for (const component of requiredS3Components) {
|
|
2733
|
+
if (!this.awsClientS3[component]) {
|
|
2734
|
+
throw new Error(`Missing ${component} in AWS awsClientS3 client configuration`)
|
|
2735
|
+
}
|
|
2736
|
+
}
|
|
2737
|
+
|
|
2738
|
+
return true
|
|
2739
|
+
}
|
|
2740
|
+
|
|
2741
|
+
async refreshCredentials() {
|
|
2742
|
+
try {
|
|
2743
|
+
const webIdentityToken = await this.getIdToken()
|
|
2744
|
+
if (!webIdentityToken) {
|
|
2745
|
+
throw new Error('getIdToken function returned empty or invalid token')
|
|
2746
|
+
}
|
|
2747
|
+
|
|
2748
|
+
const stsClient = new this.awsClientSts.STSClient({ region: this.region })
|
|
2749
|
+
|
|
2750
|
+
const stsResponse = await stsClient.send(
|
|
2751
|
+
new this.awsClientSts.AssumeRoleWithWebIdentityCommand({
|
|
2752
|
+
RoleArn: this.roleArn,
|
|
2753
|
+
RoleSessionName: this.roleSessionName,
|
|
2754
|
+
WebIdentityToken: await this.getIdToken(),
|
|
2755
|
+
DurationSeconds: this.durationSession,
|
|
2756
|
+
})
|
|
2757
|
+
)
|
|
2758
|
+
|
|
2759
|
+
const credentials = stsResponse.Credentials
|
|
2760
|
+
if (!credentials) {
|
|
2761
|
+
throw new Error('No credentials returned from awsClientSts')
|
|
2762
|
+
}
|
|
2763
|
+
|
|
2764
|
+
this.expiration = credentials.Expiration
|
|
2765
|
+
|
|
2766
|
+
this.s3Client = new this.awsClientS3.S3Client({
|
|
2767
|
+
region: this.region,
|
|
2768
|
+
credentials: {
|
|
2769
|
+
accessKeyId: credentials.AccessKeyId,
|
|
2770
|
+
secretAccessKey: credentials.SecretAccessKey,
|
|
2771
|
+
sessionToken: credentials.SessionToken,
|
|
2772
|
+
}
|
|
2773
|
+
})
|
|
2774
|
+
|
|
2775
|
+
return this
|
|
2776
|
+
} catch (error) {
|
|
2777
|
+
throw new Error(`Failed to refresh credentials: ${error.message}`)
|
|
2778
|
+
}
|
|
2779
|
+
}
|
|
2780
|
+
|
|
2781
|
+
async getS3Client() {
|
|
2782
|
+
if (this.isExpired || !this.s3Client) {
|
|
2783
|
+
await this.refreshCredentials()
|
|
2784
|
+
}
|
|
2785
|
+
return this.s3Client
|
|
2786
|
+
}
|
|
2787
|
+
|
|
2788
|
+
async putObject(params) {
|
|
2789
|
+
try {
|
|
2790
|
+
const client = await this.getS3Client()
|
|
2791
|
+
const command = new this.awsClientS3.PutObjectCommand(params)
|
|
2792
|
+
await client.send(command)
|
|
2793
|
+
const fileArr = params.Key.split('/')
|
|
2794
|
+
return {
|
|
2795
|
+
url: `https://s3.${this.region}.amazonaws.com/${params.Bucket}/${params.Key}`,
|
|
2796
|
+
filename: fileArr.pop(),
|
|
2797
|
+
folder: params.Bucket,
|
|
2798
|
+
subFolders: fileArr
|
|
2799
|
+
}
|
|
2800
|
+
} catch (error) {
|
|
2801
|
+
throw new Error(`Failed to put object: ${error.message}`)
|
|
2802
|
+
}
|
|
2803
|
+
}
|
|
2804
|
+
|
|
2805
|
+
async getObject(params) {
|
|
2806
|
+
try {
|
|
2807
|
+
const client = await this.getS3Client()
|
|
2808
|
+
const command = new this.awsClientS3.GetObjectCommand(params)
|
|
2809
|
+
const response = await client.send(command)
|
|
2810
|
+
return {
|
|
2811
|
+
body: response.Body,
|
|
2812
|
+
contentType: response.ContentType,
|
|
2813
|
+
lastModified: response.LastModified,
|
|
2814
|
+
contentLength: response.ContentLength,
|
|
2815
|
+
}
|
|
2816
|
+
} catch (error) {
|
|
2817
|
+
throw new Error(`Failed to get object: ${error.message}`)
|
|
2818
|
+
}
|
|
2819
|
+
}
|
|
2820
|
+
|
|
2821
|
+
async deleteObject(params) {
|
|
2822
|
+
try {
|
|
2823
|
+
const client = await this.getS3Client()
|
|
2824
|
+
const command = new this.awsClientS3.DeleteObjectCommand(params)
|
|
2825
|
+
await client.send(command)
|
|
2826
|
+
return true
|
|
2827
|
+
} catch (error) {
|
|
2828
|
+
throw new Error(`Failed to delete object: ${error.message}`)
|
|
2829
|
+
}
|
|
2830
|
+
}
|
|
2831
|
+
}
|
|
2832
|
+
|
|
2833
|
+
|
|
2834
|
+
|
|
2835
|
+
;// ./lib/models/awsStsS3Client/index.js
|
|
2836
|
+
|
|
2837
|
+
|
|
2838
|
+
|
|
2839
|
+
|
|
2208
2840
|
;// ./lib/models/keyValueObject/keyValueObject.js
|
|
2209
2841
|
class KeyValueObject {
|
|
2210
2842
|
constructor(options = {}) {
|
|
@@ -2332,7 +2964,7 @@ class KeyValueObject {
|
|
|
2332
2964
|
return to.key === from.key
|
|
2333
2965
|
})
|
|
2334
2966
|
if (found) {
|
|
2335
|
-
found.value = (
|
|
2967
|
+
found.value = _mergeValues(from.value, found.value)
|
|
2336
2968
|
} else {
|
|
2337
2969
|
toArr.push(from)
|
|
2338
2970
|
}
|
|
@@ -2348,7 +2980,10 @@ class KeyValueObject {
|
|
|
2348
2980
|
}, [])
|
|
2349
2981
|
}
|
|
2350
2982
|
static sameKey(item, key) {
|
|
2351
|
-
|
|
2983
|
+
if (item) {
|
|
2984
|
+
return _isSame(item.key, key)
|
|
2985
|
+
}
|
|
2986
|
+
return false
|
|
2352
2987
|
}
|
|
2353
2988
|
static toObject(arr = []) {
|
|
2354
2989
|
if (Array.isArray(arr)) {
|
|
@@ -2417,6 +3052,34 @@ class KeyValueObject {
|
|
|
2417
3052
|
}
|
|
2418
3053
|
}
|
|
2419
3054
|
|
|
3055
|
+
function _mergeValues(existingValue, newValue) {
|
|
3056
|
+
if (existingValue === undefined) return newValue
|
|
3057
|
+
|
|
3058
|
+
// Handle arrays by concatenating
|
|
3059
|
+
if (Array.isArray(existingValue) && Array.isArray(newValue)) {
|
|
3060
|
+
return [...new Set([...existingValue, ...newValue])]
|
|
3061
|
+
}
|
|
3062
|
+
|
|
3063
|
+
// Handle objects by merging
|
|
3064
|
+
if (typeof existingValue === 'object' && typeof newValue === 'object' &&
|
|
3065
|
+
!Array.isArray(existingValue) && !Array.isArray(newValue)) {
|
|
3066
|
+
return { ...existingValue, ...newValue }
|
|
3067
|
+
}
|
|
3068
|
+
|
|
3069
|
+
// // Handle numbers by adding
|
|
3070
|
+
// if (typeof existingValue === 'number' && typeof newValue === 'number') {
|
|
3071
|
+
// return existingValue
|
|
3072
|
+
// }
|
|
3073
|
+
|
|
3074
|
+
// // Handle strings by concatenating
|
|
3075
|
+
// if (typeof existingValue === 'string' && typeof newValue === 'string') {
|
|
3076
|
+
// return existingValue
|
|
3077
|
+
// }
|
|
3078
|
+
|
|
3079
|
+
// Default: use the new value
|
|
3080
|
+
return newValue
|
|
3081
|
+
}
|
|
3082
|
+
|
|
2420
3083
|
function _isSame(key1, key2) {
|
|
2421
3084
|
return key1 === key2
|
|
2422
3085
|
}
|
|
@@ -2455,7 +3118,7 @@ class Metadata extends KeyValueObject {
|
|
|
2455
3118
|
return metadata_isSame(to.key, from.key)
|
|
2456
3119
|
})
|
|
2457
3120
|
if (found) {
|
|
2458
|
-
found.value = (
|
|
3121
|
+
found.value = metadata_mergeValues(from.value, found.value)
|
|
2459
3122
|
} else {
|
|
2460
3123
|
toArr.push(from)
|
|
2461
3124
|
}
|
|
@@ -2471,6 +3134,34 @@ function metadata_isSame(key1, key2) {
|
|
|
2471
3134
|
return stringFormatter(key1, DELIMITER) === stringFormatter(key2, DELIMITER)
|
|
2472
3135
|
}
|
|
2473
3136
|
|
|
3137
|
+
function metadata_mergeValues(existingValue, newValue) {
|
|
3138
|
+
if (existingValue === undefined) return newValue
|
|
3139
|
+
|
|
3140
|
+
// Handle arrays by concatenating
|
|
3141
|
+
if (Array.isArray(existingValue) && Array.isArray(newValue)) {
|
|
3142
|
+
return [...new Set([...existingValue, ...newValue])]
|
|
3143
|
+
}
|
|
3144
|
+
|
|
3145
|
+
// Handle objects by merging
|
|
3146
|
+
if (typeof existingValue === 'object' && typeof newValue === 'object' &&
|
|
3147
|
+
!Array.isArray(existingValue) && !Array.isArray(newValue)) {
|
|
3148
|
+
return { ...existingValue, ...newValue }
|
|
3149
|
+
}
|
|
3150
|
+
|
|
3151
|
+
// // Handle numbers by adding
|
|
3152
|
+
// if (typeof existingValue === 'number' && typeof newValue === 'number') {
|
|
3153
|
+
// return existingValue
|
|
3154
|
+
// }
|
|
3155
|
+
|
|
3156
|
+
// // Handle strings by concatenating
|
|
3157
|
+
// if (typeof existingValue === 'string' && typeof newValue === 'string') {
|
|
3158
|
+
// return existingValue
|
|
3159
|
+
// }
|
|
3160
|
+
|
|
3161
|
+
// Default: use the new value
|
|
3162
|
+
return newValue
|
|
3163
|
+
}
|
|
3164
|
+
|
|
2474
3165
|
|
|
2475
3166
|
|
|
2476
3167
|
;// ./lib/models/metadata/index.js
|
|
@@ -2546,17 +3237,19 @@ class TrackedEntity {
|
|
|
2546
3237
|
constructor(options = {}) {
|
|
2547
3238
|
options = options || {}
|
|
2548
3239
|
const timestamp = Date.now()
|
|
2549
|
-
|
|
2550
|
-
active: options.active ?? true,
|
|
2551
|
-
created: options.created ??
|
|
2552
|
-
|
|
2553
|
-
|
|
2554
|
-
|
|
2555
|
-
|
|
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 ?? '',
|
|
2556
3251
|
}
|
|
2557
3252
|
|
|
2558
|
-
this.meta = { ..._tracking, ...options.meta }
|
|
2559
|
-
|
|
2560
3253
|
// if (trackFlat) {
|
|
2561
3254
|
// Object.assign(this, _tracking)
|
|
2562
3255
|
// } else {
|
|
@@ -2608,6 +3301,9 @@ class TrackedEntity {
|
|
|
2608
3301
|
get owner() {
|
|
2609
3302
|
return this.meta?.owner ?? this.owner
|
|
2610
3303
|
}
|
|
3304
|
+
changeCreatorOwner({ source, target }) {
|
|
3305
|
+
return changeCreatorOwner(this, { source, target }).setModified()
|
|
3306
|
+
}
|
|
2611
3307
|
delete() {
|
|
2612
3308
|
return this.setDeleted()
|
|
2613
3309
|
}
|
|
@@ -2814,6 +3510,7 @@ function _makeSetCode(fieldName, options) {
|
|
|
2814
3510
|
|
|
2815
3511
|
|
|
2816
3512
|
|
|
3513
|
+
|
|
2817
3514
|
;// ./lib/index.js
|
|
2818
3515
|
|
|
2819
3516
|
|
|
@@ -2821,4 +3518,4 @@ function _makeSetCode(fieldName, options) {
|
|
|
2821
3518
|
;// ./index.js
|
|
2822
3519
|
|
|
2823
3520
|
|
|
2824
|
-
export { ApiResponse, KeyValueObject, Metadata, QMeta, Repo, Service, TemplateCompiler, TenantAwareEntity, TrackedEntity, UniqueKeyGenerator, authorize, concatStringByArray, convertString, formatDate, generalPost, getValidation, getValueByKeys_getValueByKeys as getValueByKeys, init, initFromArray, initOnlyValidFromArray, makeApiResponse, makeService, objectHelper, pReduce, padZeros, 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 };
|