sumba 2.31.0 → 2.32.1

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.
@@ -21,8 +21,9 @@ async function clearCacheUser (id, result) {
21
21
  }
22
22
 
23
23
  async function applyModelGuard ({ model, q, teamIds, options }) {
24
- const { get, set, orderBy, without } = this.app.lib._
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 && byTeamId && byFields
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
- let values = []
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
- if (item.behavior === 'NIN') values = without(values, ...item.value)
45
- else if (item.behavior === 'IN') values.push(...item.value)
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
- if (results.length > 0) options.hidden.push(...results)
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.noEmptyQuery`, []).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) return
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 (!req.user) {
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": {
@@ -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": {
@@ -76,11 +76,11 @@ async function model () {
76
76
  },
77
77
  'field,,50,true,true',
78
78
  {
79
- name: 'behavior',
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
- const { getPluginDataDir } = this.app.bajo
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 { getPlugin } = this.app.bajo
530
- const { createRecord } = getPlugin('waibuDb')
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 => input.path[0] !== '!').map(result => {
642
- result.path = routePath(result.path)
643
- return result
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 => input.path[0] === '!').map(result => {
646
- result.path = routePath(result.path)
647
- return result
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('Model')
682
+ this.attribGuards = await this._fetchGuards('Attrib')
677
683
  return this.attribGuards
678
684
  }
679
685
 
@@ -1,7 +1,7 @@
1
1
  import path from 'path'
2
2
 
3
3
  export async function getAllFixtures (alias) {
4
- const { getPluginDataDir, readConfig } = this.app.bajo
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sumba",
3
- "version": "2.31.0",
3
+ "version": "2.32.1",
4
4
  "description": "Biz Suite for Bajo Framework",
5
5
  "main": "index.js",
6
6
  "scripts": {
package/wiki/CHANGES.md CHANGED
@@ -1,5 +1,14 @@
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
+ - [2.32.1] Bug fix in ```allowEmptyQuery``` options
11
+
3
12
  ## 2026-06-11
4
13
 
5
14
  - [2.31.0] Add ```status``` field on ```SumbaTeamUser```