sumba 2.31.0 → 2.32.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/extend/bajo/hook.js +28 -18
- package/extend/bajo/intl/en-US.json +3 -1
- package/extend/bajo/intl/id.json +3 -1
- package/extend/dobo/model.js +2 -2
- package/index.js +18 -12
- package/lib/create-new-site.js +2 -2
- package/package.json +1 -1
- package/wiki/CHANGES.md +8 -0
package/extend/bajo/hook.js
CHANGED
|
@@ -21,8 +21,9 @@ async function clearCacheUser (id, result) {
|
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
async function applyModelGuard ({ model, q, teamIds, options }) {
|
|
24
|
-
const {
|
|
24
|
+
const { set, orderBy } = this.app.lib._
|
|
25
25
|
const { includes } = this.app.lib.aneka
|
|
26
|
+
const { sanitizeByType } = this.app.dobo
|
|
26
27
|
const { req } = options
|
|
27
28
|
const results = []
|
|
28
29
|
|
|
@@ -31,24 +32,29 @@ async function applyModelGuard ({ model, q, teamIds, options }) {
|
|
|
31
32
|
const filterFn = item => {
|
|
32
33
|
const bySiteId = item.siteId === req.site.id + ''
|
|
33
34
|
const byModel = item.models.includes(model.name)
|
|
34
|
-
const byTeamId = includes(item.teamIds, teamIds)
|
|
35
35
|
const byFields = fields.includes(item.field)
|
|
36
|
-
return bySiteId && byModel &&
|
|
36
|
+
return bySiteId && byModel && byFields
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
const rules = orderBy(guards.filter(filterFn), ['field'])
|
|
40
40
|
for (const field of fields) {
|
|
41
|
-
|
|
41
|
+
if (!model.getNonVirtualProperties(true).includes(field)) continue // or, should it throws exception instead?
|
|
42
|
+
const prop = model.getProperty(field)
|
|
42
43
|
const items = rules.filter(item => item.field === field)
|
|
43
44
|
for (const item of items) {
|
|
44
|
-
|
|
45
|
-
|
|
45
|
+
const values = item.value.map(val => {
|
|
46
|
+
return sanitizeByType(val, prop.type, { strict: true, inputFormat: 'string', model: model.name })
|
|
47
|
+
})
|
|
48
|
+
const op = item.condition.toLowerCase()
|
|
49
|
+
let value
|
|
50
|
+
if (['in', 'nin'].includes(op)) value = set({}, '$' + op, values)
|
|
51
|
+
else if (op === 'between') value = { $gte: values[0], $lte: values[1] }
|
|
52
|
+
else value = set({}, '$' + op, values[0])
|
|
53
|
+
const teamOk = item.allTeams ? true : (item.teamIds.length === 0 ? false : includes(item.teamIds, teamIds))
|
|
54
|
+
if (!teamOk) throw this.error('_abortAction')
|
|
55
|
+
results.push(set({}, field, value))
|
|
46
56
|
}
|
|
47
|
-
if (values.length) results.push(set({}, field, { $in: values }))
|
|
48
57
|
}
|
|
49
|
-
|
|
50
|
-
const allowEmpty = get(this, `config.dobo.model.${model.name}.allowEmptyQuery`, true)
|
|
51
|
-
if (results.length === 0 && !allowEmpty) throw this.error('_emptyColumnQuery') // signal driver to about with no result immediately
|
|
52
58
|
q.$and.push(...results)
|
|
53
59
|
}
|
|
54
60
|
|
|
@@ -62,20 +68,19 @@ export async function applyAttribGuard ({ model, teamIds, options }) {
|
|
|
62
68
|
const filterFn = item => {
|
|
63
69
|
const bySiteId = item.siteId === req.site.id + ''
|
|
64
70
|
const byModel = item.models.includes(model.name)
|
|
65
|
-
const byTeamId = includes(item.teamIds, teamIds)
|
|
71
|
+
const byTeamId = item.allTeams ? true : includes(item.teamIds, teamIds)
|
|
66
72
|
return bySiteId && byModel && byTeamId
|
|
67
73
|
}
|
|
68
|
-
|
|
69
|
-
const item = guards.filter(filterFn)[0]
|
|
70
|
-
if (item) results.push(...item.hiddenFields)
|
|
74
|
+
guards.filter(filterFn).forEach(item => results.push(...item.hiddenFields))
|
|
71
75
|
options.hidden = options.hidden ?? []
|
|
72
|
-
|
|
76
|
+
options.hidden.push(...results)
|
|
73
77
|
options.hidden = uniq(options.hidden)
|
|
74
78
|
}
|
|
75
79
|
|
|
76
80
|
async function rebuildFilter (model, filter = {}, options = {}) {
|
|
77
81
|
const { isEmpty, get } = this.app.lib._
|
|
78
82
|
const { req } = options
|
|
83
|
+
const allowEmpty = !get(this, `app.${model.ns}.config.sumba.allowEmptyQuery`, []).includes(model.name)
|
|
79
84
|
const hasSiteId = model.hasProperty('siteId')
|
|
80
85
|
const hasUserId = model.hasProperty('userId')
|
|
81
86
|
const hasTeamId = model.hasProperty('teamId')
|
|
@@ -89,13 +94,17 @@ async function rebuildFilter (model, filter = {}, options = {}) {
|
|
|
89
94
|
if (filter.query.$and) q.$and.push(...filter.query.$and)
|
|
90
95
|
else q.$and.push(filter.query)
|
|
91
96
|
}
|
|
92
|
-
if (req.routeOptions.config.xSite)
|
|
97
|
+
if (req.routeOptions.config.xSite) {
|
|
98
|
+
filter.query = q
|
|
99
|
+
return
|
|
100
|
+
}
|
|
93
101
|
if (hasSiteId) q.$and.push({ siteId: req.site.id + '' })
|
|
94
102
|
if (aliases.includes('administrator')) {
|
|
95
103
|
filter.query = q
|
|
96
104
|
return
|
|
97
105
|
}
|
|
98
|
-
if (
|
|
106
|
+
if (isEmpty(req.user)) {
|
|
107
|
+
if (q.$and.length === 0 && !allowEmpty) throw this.error('_emptyColumnQuery')
|
|
99
108
|
filter.query = q
|
|
100
109
|
return
|
|
101
110
|
}
|
|
@@ -119,8 +128,9 @@ async function rebuildFilter (model, filter = {}, options = {}) {
|
|
|
119
128
|
else q.$and.push(condTeamId)
|
|
120
129
|
} else if (hasUserId) q.$and.push(condUserId)
|
|
121
130
|
|
|
122
|
-
await applyModelGuard.call(this, { model, q, teamIds, options })
|
|
131
|
+
await applyModelGuard.call(this, { model, q, teamIds, options, allowEmpty })
|
|
123
132
|
await applyAttribGuard.call(this, { model, teamIds, options })
|
|
133
|
+
if (q.$and.length === 0 && !allowEmpty) throw this.error('_emptyColumnQuery')
|
|
124
134
|
filter.query = q
|
|
125
135
|
}
|
|
126
136
|
|
|
@@ -173,7 +173,9 @@
|
|
|
173
173
|
"hiddenCols": "Hidden Columns",
|
|
174
174
|
"models": "Models",
|
|
175
175
|
"siteIds": "Sites",
|
|
176
|
-
"allTeams": "All Teams?"
|
|
176
|
+
"allTeams": "All Teams?",
|
|
177
|
+
"condition": "Condition",
|
|
178
|
+
"hiddenFields": "Hide Fields"
|
|
177
179
|
},
|
|
178
180
|
"validation": {
|
|
179
181
|
"password": {
|
package/extend/bajo/intl/id.json
CHANGED
|
@@ -179,7 +179,9 @@
|
|
|
179
179
|
"hiddenCols": "Kolom Tersembunyi",
|
|
180
180
|
"models": "Model",
|
|
181
181
|
"siteIds": "Situs",
|
|
182
|
-
"allTeams": "Semua Tim?"
|
|
182
|
+
"allTeams": "Semua Tim?",
|
|
183
|
+
"condition": "Kondisi",
|
|
184
|
+
"hiddenFields": "Sembunyikan Kolom"
|
|
183
185
|
},
|
|
184
186
|
"validation": {
|
|
185
187
|
"password": {
|
package/extend/dobo/model.js
CHANGED
|
@@ -76,11 +76,11 @@ async function model () {
|
|
|
76
76
|
},
|
|
77
77
|
'field,,50,true,true',
|
|
78
78
|
{
|
|
79
|
-
name: '
|
|
79
|
+
name: 'condition',
|
|
80
80
|
type: 'string',
|
|
81
81
|
maxLength: 20,
|
|
82
82
|
required: true,
|
|
83
|
-
values: ['IN', 'NIN'],
|
|
83
|
+
values: ['IN', 'NIN', 'EQ', 'NE', 'GT', 'GTE', 'LT', 'LTE', 'BETWEEN'],
|
|
84
84
|
default: 'IN'
|
|
85
85
|
},
|
|
86
86
|
'value,array,,,true',
|
package/index.js
CHANGED
|
@@ -174,8 +174,7 @@ async function factory (pkgName) {
|
|
|
174
174
|
}
|
|
175
175
|
|
|
176
176
|
init = async () => {
|
|
177
|
-
|
|
178
|
-
this.downloadDir = `${getPluginDataDir(this.ns)}/download`
|
|
177
|
+
this.downloadDir = `${this.app.getPluginDataDir(this.ns)}/download`
|
|
179
178
|
this.app.lib.fs.ensureDirSync(this.downloadDir)
|
|
180
179
|
if (this.config.multiSite === true) {
|
|
181
180
|
this.config.multiSite = cloneDeep(defMultiSite)
|
|
@@ -526,9 +525,8 @@ async function factory (pkgName) {
|
|
|
526
525
|
}
|
|
527
526
|
|
|
528
527
|
pushDownload = async ({ description, worker, data, source, req, file, type }) => {
|
|
529
|
-
const {
|
|
530
|
-
const {
|
|
531
|
-
const { push } = getPlugin('bajoQueue')
|
|
528
|
+
const { createRecord } = this.app.getPlugin('waibuDb')
|
|
529
|
+
const { push } = this.app.getPlugin('bajoQueue')
|
|
532
530
|
description = description ?? file
|
|
533
531
|
const jobQueue = {
|
|
534
532
|
worker,
|
|
@@ -638,13 +636,21 @@ async function factory (pkgName) {
|
|
|
638
636
|
_getGuards = (inputs = []) => {
|
|
639
637
|
const { routePath } = this.app.waibu
|
|
640
638
|
const { orderBy } = this.app.lib._
|
|
641
|
-
const normal = orderBy(inputs.filter(input =>
|
|
642
|
-
|
|
643
|
-
|
|
639
|
+
const normal = orderBy(inputs.filter(input => {
|
|
640
|
+
try {
|
|
641
|
+
input.path = routePath(input.path)
|
|
642
|
+
} catch (err) {
|
|
643
|
+
return false
|
|
644
|
+
}
|
|
645
|
+
return input.path[0] !== '!'
|
|
644
646
|
}), ['weight', 'path'], ['desc', 'asc'])
|
|
645
|
-
const inverse = orderBy(inputs.filter(input =>
|
|
646
|
-
|
|
647
|
-
|
|
647
|
+
const inverse = orderBy(inputs.filter(input => {
|
|
648
|
+
try {
|
|
649
|
+
input.path = routePath(input.path)
|
|
650
|
+
} catch (err) {
|
|
651
|
+
return false
|
|
652
|
+
}
|
|
653
|
+
return input.path[0] === '!'
|
|
648
654
|
}), ['weight', 'path'], ['desc', 'asc'])
|
|
649
655
|
return [...normal, ...inverse]
|
|
650
656
|
}
|
|
@@ -673,7 +679,7 @@ async function factory (pkgName) {
|
|
|
673
679
|
getAttribGuards = async (reread) => {
|
|
674
680
|
if (!reread) return this.attribGuards
|
|
675
681
|
|
|
676
|
-
this.attribGuards = await this._fetchGuards('
|
|
682
|
+
this.attribGuards = await this._fetchGuards('Attrib')
|
|
677
683
|
return this.attribGuards
|
|
678
684
|
}
|
|
679
685
|
|
package/lib/create-new-site.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import path from 'path'
|
|
2
2
|
|
|
3
3
|
export async function getAllFixtures (alias) {
|
|
4
|
-
const {
|
|
4
|
+
const { readConfig } = this.app.bajo
|
|
5
5
|
const { isEmpty, omit, kebabCase, isString } = this.app.lib._
|
|
6
6
|
const { getModel } = this.app.dobo
|
|
7
7
|
const { fastGlob } = this.app.lib
|
|
@@ -17,7 +17,7 @@ export async function getAllFixtures (alias) {
|
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
const formats = this.app.configHandlers.map(item => item.ext.slice(1))
|
|
20
|
-
const overrideBase = `${getPluginDataDir('sumba')}/create-new-site-fixtures/${alias}`
|
|
20
|
+
const overrideBase = `${this.app.getPluginDataDir('sumba')}/create-new-site-fixtures/${alias}`
|
|
21
21
|
const models = this.app.dobo.models.filter(m => {
|
|
22
22
|
const prop = m.properties.find(p => p.name === 'siteId')
|
|
23
23
|
return !!prop
|
package/package.json
CHANGED
package/wiki/CHANGES.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# Changes
|
|
2
2
|
|
|
3
|
+
## 2026-06-12
|
|
4
|
+
|
|
5
|
+
- [2.32.0] Necessary updates to ```bajo@2.18.0``` specs
|
|
6
|
+
- [2.32.0] Bug fix in ```_getGuards()```
|
|
7
|
+
- [2.32.0] Bug fix in ```getAttribGuards()```
|
|
8
|
+
- [2.32.0] Bug fix in ```hooks.js```
|
|
9
|
+
- [2.32.0] Change ```behavior``` to ```condition``` in ```SumbaModelGuard``` model
|
|
10
|
+
|
|
3
11
|
## 2026-06-11
|
|
4
12
|
|
|
5
13
|
- [2.31.0] Add ```status``` field on ```SumbaTeamUser```
|