dobo 1.1.15 → 1.1.17

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dobo",
3
- "version": "1.1.15",
3
+ "version": "1.1.17",
4
4
  "description": "Database ORM/ODM for Bajo Framework",
5
5
  "main": "index.js",
6
6
  "scripts": {
package/plugin/factory.js CHANGED
@@ -5,6 +5,7 @@ import collectSchemas from '../lib/collect-schemas.js'
5
5
  import memDbStart from '../lib/mem-db/start.js'
6
6
  import memDbInstantiate from '../lib/mem-db/instantiate.js'
7
7
  import nql from '@tryghost/nql'
8
+ import path from 'path'
8
9
 
9
10
  async function factory (pkgName) {
10
11
  const me = this
@@ -360,6 +361,34 @@ async function factory (pkgName) {
360
361
  if (fields.length === 0) return all
361
362
  return map(all, item => pick(item, fields))
362
363
  }
364
+
365
+ listAttachments = async ({ model, id = '*', field = '*', file = '*' } = {}, { uriEncoded = true } = {}) => {
366
+ const { map, kebabCase } = this.lib._
367
+ const { importPkg, getPluginDataDir, pascalCase } = this.app.bajo
368
+ const mime = await importPkg('waibu:mime')
369
+ const { fastGlob } = this.lib
370
+ const root = `${getPluginDataDir('dobo')}/attachment`
371
+ model = pascalCase(model)
372
+ let pattern = `${root}/${model}/${id}/${field}/${file}`
373
+ if (uriEncoded) pattern = pattern.split('/').map(p => decodeURI(p)).join('/')
374
+ return map(await fastGlob(pattern), f => {
375
+ const mimeType = mime.getType(path.extname(f)) ?? ''
376
+ const fullPath = f.replace(root, '')
377
+ const row = {
378
+ file: f,
379
+ fileName: path.basename(fullPath),
380
+ fullPath,
381
+ mimeType,
382
+ params: { model, id, field, file }
383
+ }
384
+ if (this.app.waibuMpa) {
385
+ const { routePath } = this.app.waibu
386
+ const [, _model, _id, _field, _file] = fullPath.split('/')
387
+ row.url = routePath(`dobo:/attachment/${kebabCase(_model)}/${_id}/${_field}/${_file}`)
388
+ }
389
+ return row
390
+ })
391
+ }
363
392
  }
364
393
  }
365
394
 
@@ -20,8 +20,9 @@ async function copyUploaded (name, id, options = {}) {
20
20
  if (parts.length === 0) continue
21
21
  field = setField ?? field
22
22
  const file = setFile ?? parts.join('@')
23
- const opts = { source: f, field, file, mimeType, stats, req }
23
+ const opts = { source: f, field, file, mimeType, stats, req, silent: true }
24
24
  const rec = await this.attachmentCreate(name, id, opts)
25
+ if (!rec) continue
25
26
  delete rec.dir
26
27
  result.push(rec)
27
28
  if (setField || setFile) break
@@ -2,9 +2,11 @@ import mergeAttachmentInfo from '../../../lib/merge-attachment-info.js'
2
2
 
3
3
  async function create (name, id, options = {}) {
4
4
  const { fs } = this.lib
5
+ const { isEmpty } = this.lib._
5
6
  name = this.attachmentPreCheck(name)
6
7
  if (!name) return
7
- const { source, field, file } = options
8
+ const { source, field = 'file', file } = options
9
+ if (isEmpty(file)) return
8
10
  if (!source) throw this.error('isMissing%s', this.print.write('field.source'))
9
11
  const baseDir = await this.attachmentGetPath(name, id, field, file, { dirOnly: true })
10
12
  const { fullPath, stats, mimeType, req } = options
@@ -20,7 +22,7 @@ async function create (name, id, options = {}) {
20
22
  file
21
23
  }
22
24
  await mergeAttachmentInfo.call(this, rec, dest, { mimeType, fullPath, stats })
23
- if (req && req.flash) req.flash('notify', req.t('attachmentUploaded'))
25
+ if (!options.silent && req && req.flash) req.flash('notify', req.t('attachmentUploaded'))
24
26
  return rec
25
27
  }
26
28
 
@@ -16,6 +16,7 @@ async function findOne (name, filter = {}, opts = {}) {
16
16
  options.dataOnly = false
17
17
  await this.modelExists(name, true)
18
18
  filter.limit = 1
19
+ filter.page = 1
19
20
  const { handler, schema, driver } = await resolveMethod.call(this, name, 'record-find', options)
20
21
  if (!schema.cacheable) noCache = true
21
22
  filter.query = await this.buildQuery({ filter, schema, options }) ?? {}
@@ -34,6 +35,7 @@ async function findOne (name, filter = {}, opts = {}) {
34
35
  }
35
36
  }
36
37
  filter.limit = 1
38
+ filter.page = 1
37
39
  const record = options.record ?? (await handler.call(this.app[driver.ns], { schema, filter, options }))
38
40
  delete options.record
39
41
  record.data = record.data[0]
@@ -1,25 +1,34 @@
1
1
  import path from 'path'
2
2
 
3
3
  async function attachment (req, reply) {
4
- const { isString, isEmpty } = this.lib._
5
- const { importPkg, getPluginDataDir, pascalCase } = this.app.bajo
4
+ const { isString, isEmpty, find } = this.lib._
5
+ const { pascalCase } = this.app.bajo
6
6
  const { routePath } = this.app.waibu
7
- const mime = await importPkg('waibu:mime')
8
- const { fs, fastGlob } = this.lib
9
- let file = `${getPluginDataDir('dobo')}/attachment/${pascalCase(req.params.model)}/${req.params.id}/${req.params.field}/${req.params.file}`
10
- if (path.basename(file) === '_first') {
11
- const files = await fastGlob(`${path.dirname(file)}/*`)
12
- if (files.length > 0) file = files[0]
7
+ const { fs } = this.lib
8
+ const items = await this.listAttachments({
9
+ model: req.params.model,
10
+ id: req.params.id,
11
+ field: req.params.field,
12
+ file: '*'
13
+ })
14
+ let item = req.params.file === '_first' ? items[0] : undefined
15
+ if (!item) {
16
+ item = find(items, i => {
17
+ const [, model, id, field, file] = i.fullPath.split('/')
18
+ return model === pascalCase(req.params.model) &&
19
+ id === decodeURI(req.params.id) &&
20
+ field === decodeURI(req.params.field) &&
21
+ file === decodeURI(req.params.file)
22
+ })
13
23
  }
14
- const mimeType = mime.getType(path.extname(file)) ?? ''
15
- if (!fs.existsSync(file)) {
24
+ if (!item) {
16
25
  if (!req.query.notfound) throw this.error('_notFound', { noContent: true })
17
- const [, ext] = mimeType.split('/')
18
- const replacer = isString(req.query.notfound) ? req.query.notfound : `waibuStatic.asset:/not-found.${ext ?? 'png'}`
26
+ const ext = path.extname(req.params.file)
27
+ const replacer = isString(req.query.notfound) ? req.query.notfound : `waibuStatic.asset:/not-found${isEmpty(ext) ? '.png' : ext}`
19
28
  return reply.redirectTo(routePath(replacer))
20
29
  }
21
- if (!isEmpty(mimeType)) reply.header('Content-Type', mimeType)
22
- const stream = fs.createReadStream(file)
30
+ if (!isEmpty(item.mimeType)) reply.header('Content-Type', item.mimeType)
31
+ const stream = fs.createReadStream(item.file)
23
32
  reply.send(stream)
24
33
  return reply
25
34
  }