monastery 3.4.1 → 3.4.2
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/changelog.md +2 -0
- package/docs/definition/index.md +38 -12
- package/lib/index.js +4 -1
- package/lib/model-crud.js +1 -1
- package/lib/model.js +4 -4
- package/lib/util.js +1 -1
- package/package.json +1 -1
- package/plugins/images/index.js +127 -111
- package/test/crud.js +17 -3
- package/test/plugin-images.js +52 -46
package/changelog.md
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
|
4
4
|
|
|
5
|
+
### [3.4.2](https://github.com/boycce/monastery/compare/3.4.1...3.4.2) (2024-08-24)
|
|
6
|
+
|
|
5
7
|
### [3.4.1](https://github.com/boycce/monastery/compare/3.4.0...3.4.1) (2024-08-09)
|
|
6
8
|
|
|
7
9
|
## [3.4.0](https://github.com/boycce/monastery/compare/3.3.0...3.4.0) (2024-08-09)
|
package/docs/definition/index.md
CHANGED
|
@@ -17,13 +17,14 @@ Model definition object.
|
|
|
17
17
|
- [Custom field rules](#custom-field-rules)
|
|
18
18
|
- [Custom error messages](#custom-error-messages)
|
|
19
19
|
- [Operation hooks](#operation-hooks)
|
|
20
|
+
- [Methods](#methods)
|
|
20
21
|
- [Full example](#full-example)
|
|
21
22
|
|
|
22
23
|
### Fields
|
|
23
24
|
|
|
24
25
|
1. Fields can either be a field-type, embedded document, or an array of field-types or embedded documents
|
|
25
26
|
2. Field-types are recognised by having a `type` property defined as a string
|
|
26
|
-
3. Field-types can contain [custom](#custom-field-rules) and [default field rules](./rules), e.g. `{ minLength: 2 }`
|
|
27
|
+
3. Field-types can contain [custom](#custom-field-rules) and [default field rules](./field-rules), e.g. `{ minLength: 2 }`
|
|
27
28
|
4. Field-types can contain [field options](#field-options).
|
|
28
29
|
|
|
29
30
|
```js
|
|
@@ -61,7 +62,7 @@ Model definition object.
|
|
|
61
62
|
}
|
|
62
63
|
```
|
|
63
64
|
|
|
64
|
-
The fields below implicitly get assigned and take presidence over any input data when [`manager.timestamps`](
|
|
65
|
+
The fields below implicitly get assigned and take presidence over any input data when [`manager.timestamps`](../manager) is true (default). You can override the `timestamps` value per operation, e.g. `db.user.update({ ..., timestamps: false})`. These fields use unix timestamps in seconds (by default), but can be configured to use use milliseconds via the manager [`useMilliseconds` ](../manager) option.
|
|
65
66
|
|
|
66
67
|
```js
|
|
67
68
|
{
|
|
@@ -307,19 +308,44 @@ You are able provide an array of callbacks to these model operation hooks. If yo
|
|
|
307
308
|
|
|
308
309
|
```js
|
|
309
310
|
{
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
311
|
+
// Model hooks
|
|
312
|
+
afterFind: [await function(data) {}],
|
|
313
|
+
afterInsert: [await function(data) {}],
|
|
314
|
+
afterInsertUpdate: [await function(data) {}],
|
|
315
|
+
afterUpdate: [await function(data) {}],
|
|
316
|
+
afterRemove: [await function() {}],
|
|
317
|
+
beforeInsert: [await function(data) {}],
|
|
318
|
+
beforeInsertUpdate: [await function(data) {}],
|
|
319
|
+
beforeUpdate: [await function(data) {}],
|
|
320
|
+
beforeRemove: [await function() {}],
|
|
321
|
+
beforeValidate: [await function(data) {}],
|
|
322
|
+
|
|
323
|
+
// You can also return an object which will be passed to the next hook in the chain, or if it's the last hook, returned as the result:
|
|
324
|
+
afterFind: [await function(data) {
|
|
325
|
+
data.age = 30
|
|
326
|
+
return data
|
|
327
|
+
}],
|
|
320
328
|
}
|
|
321
329
|
```
|
|
322
330
|
|
|
331
|
+
### Methods
|
|
332
|
+
|
|
333
|
+
You are able define reusable methods in the definition which is handy for storing related functions.
|
|
334
|
+
|
|
335
|
+
```js
|
|
336
|
+
// Method definition
|
|
337
|
+
{
|
|
338
|
+
methods: {
|
|
339
|
+
getAge: function () {
|
|
340
|
+
return 30
|
|
341
|
+
},
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
// Above can be called directly from the model via:
|
|
346
|
+
db.user.getAge()
|
|
347
|
+
```
|
|
348
|
+
|
|
323
349
|
### Definition example
|
|
324
350
|
|
|
325
351
|
```js
|
package/lib/index.js
CHANGED
|
@@ -282,7 +282,10 @@ Manager.prototype.parseData = function(obj, parseBracketToDotNotation, parseDotN
|
|
|
282
282
|
}
|
|
283
283
|
|
|
284
284
|
Manager.prototype.model = Model
|
|
285
|
-
Manager.prototype.getSignedUrl =
|
|
285
|
+
Manager.prototype.getSignedUrl = imagePluginFile.getSignedUrl
|
|
286
|
+
Manager.prototype._getSignedUrl = () => {
|
|
287
|
+
throw new Error('monastery._getSignedUrl() has been moved to monastery.getSignedUrl()')
|
|
288
|
+
}
|
|
286
289
|
|
|
287
290
|
inherits(Manager, EventEmitter)
|
|
288
291
|
module.exports = Manager
|
package/lib/model-crud.js
CHANGED
|
@@ -676,7 +676,7 @@ Model.prototype._processAfterFind = async function (data, projection={}, afterFi
|
|
|
676
676
|
(async (_item) => {
|
|
677
677
|
const _modelName = _item.modelName
|
|
678
678
|
const _model = models[_modelName]
|
|
679
|
-
const _opts = { ...afterFindContext,
|
|
679
|
+
const _opts = { ...afterFindContext, model: _model }
|
|
680
680
|
const _dataRef = _item.dataRefParent[_item.dataRefKey]
|
|
681
681
|
_item.dataRefParent[_item.dataRefKey] = (
|
|
682
682
|
await _model._callHooks('afterFind', _dataRef, _opts)
|
package/lib/model.js
CHANGED
|
@@ -405,19 +405,19 @@ Model.prototype._setupIndexes = async function(fields, opts={}) {
|
|
|
405
405
|
}
|
|
406
406
|
}
|
|
407
407
|
|
|
408
|
-
Model.prototype._callHooks = async function(hookName, data,
|
|
408
|
+
Model.prototype._callHooks = async function(hookName, data, hookContext) {
|
|
409
409
|
/**
|
|
410
410
|
* Calls hooks in series
|
|
411
411
|
*
|
|
412
412
|
* @param {string} hookName - e.g. 'beforeValidate'
|
|
413
|
-
* @param {object} opts - operation options, e.g. { data, skipValidation, ... }
|
|
414
413
|
* @param {any} arg - data to pass to the first function
|
|
414
|
+
* @param {object} hookContext - operation options, e.g. { data, skipValidation, ... }
|
|
415
415
|
*
|
|
416
416
|
* @return {any} - the result of the last function
|
|
417
417
|
* @this model
|
|
418
418
|
*/
|
|
419
|
-
if (
|
|
420
|
-
return await util.runSeries.call(this, this[hookName].map(f => f.bind(
|
|
419
|
+
if (hookContext.skipHooks) return data
|
|
420
|
+
return await util.runSeries.call(this, this[hookName].map(f => f.bind(hookContext)), hookName, data)
|
|
421
421
|
}
|
|
422
422
|
|
|
423
423
|
Model.prototype._defaultFields = {
|
package/lib/util.js
CHANGED
|
@@ -371,7 +371,7 @@ module.exports = {
|
|
|
371
371
|
**/
|
|
372
372
|
let current = 0
|
|
373
373
|
let isSync = true
|
|
374
|
-
let caller =
|
|
374
|
+
let caller = this.name + '.' + hookName
|
|
375
375
|
let lastDefinedResult = data
|
|
376
376
|
|
|
377
377
|
return new Promise((res, rej) => {
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "monastery",
|
|
3
3
|
"description": "⛪ A simple, straightforward MongoDB ODM",
|
|
4
4
|
"author": "Ricky Boyce",
|
|
5
|
-
"version": "3.4.
|
|
5
|
+
"version": "3.4.2",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"repository": "github:boycce/monastery",
|
|
8
8
|
"homepage": "https://boycce.github.io/monastery/",
|
package/plugins/images/index.js
CHANGED
|
@@ -13,7 +13,6 @@ let plugin = module.exports = {
|
|
|
13
13
|
*
|
|
14
14
|
* @param {object} monastery manager instance
|
|
15
15
|
* @param {options} options - plugin options
|
|
16
|
-
* @this plugin
|
|
17
16
|
*/
|
|
18
17
|
|
|
19
18
|
// Depreciation warnings
|
|
@@ -23,19 +22,21 @@ let plugin = module.exports = {
|
|
|
23
22
|
}
|
|
24
23
|
|
|
25
24
|
// Settings
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
25
|
+
manager.imagePlugin = {
|
|
26
|
+
_s3Client: null,
|
|
27
|
+
awsAcl: options.awsAcl || 'public-read', // default
|
|
28
|
+
awsBucket: options.awsBucket,
|
|
29
|
+
awsAccessKeyId: options.awsAccessKeyId,
|
|
30
|
+
awsSecretAccessKey: options.awsSecretAccessKey,
|
|
31
|
+
awsRegion: options.awsRegion,
|
|
32
|
+
bucketDir: options.bucketDir || 'full', // depreciated > 1.36.2
|
|
33
|
+
filesize: options.filesize,
|
|
34
|
+
formats: options.formats || ['bmp', 'gif', 'jpg', 'jpeg', 'png', 'tiff'],
|
|
35
|
+
getSignedUrlOption: options.getSignedUrl,
|
|
36
|
+
metadata: options.metadata ? util.deepCopy(options.metadata) : undefined,
|
|
37
|
+
params: options.params ? util.deepCopy(options.params) : {},
|
|
38
|
+
path: options.path || function (uid, basename, ext, file) { return `full/${uid}.${ext}` },
|
|
39
|
+
}
|
|
39
40
|
|
|
40
41
|
if (!options.awsBucket || !options.awsAccessKeyId || !options.awsSecretAccessKey) {
|
|
41
42
|
throw new Error('Monastery imagePlugin: awsRegion, awsBucket, awsAccessKeyId, or awsSecretAccessKey is not defined')
|
|
@@ -48,21 +49,21 @@ let plugin = module.exports = {
|
|
|
48
49
|
// v2: https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html#constructor-property
|
|
49
50
|
// v3: https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/s3/
|
|
50
51
|
// v3 examples: https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/javascript_s3_code_examples.html
|
|
51
|
-
|
|
52
|
+
manager.imagePlugin.getS3Client = (useRegion) => {
|
|
52
53
|
const { S3 } = require('@aws-sdk/client-s3')
|
|
53
54
|
const key = '_s3Client'// useRegion ? '_s3ClientRegional' : '_s3Client'
|
|
54
|
-
return
|
|
55
|
+
return manager.imagePlugin[key] || (manager.imagePlugin[key] = new S3({
|
|
55
56
|
// ...(region: useRegion ? this.awsRegion : undefined,
|
|
56
|
-
region:
|
|
57
|
+
region: manager.imagePlugin.awsRegion, // if region is missing it throws an error, but only in production...
|
|
57
58
|
credentials: {
|
|
58
|
-
accessKeyId:
|
|
59
|
-
secretAccessKey:
|
|
59
|
+
accessKeyId: manager.imagePlugin.awsAccessKeyId,
|
|
60
|
+
secretAccessKey: manager.imagePlugin.awsSecretAccessKey,
|
|
60
61
|
},
|
|
61
62
|
}))
|
|
62
63
|
}
|
|
63
64
|
|
|
64
65
|
// Add before model hook
|
|
65
|
-
manager.beforeModel.push(
|
|
66
|
+
manager.beforeModel.push(plugin.setupModel)
|
|
66
67
|
},
|
|
67
68
|
|
|
68
69
|
setupModel: function(model) {
|
|
@@ -70,35 +71,35 @@ let plugin = module.exports = {
|
|
|
70
71
|
* Cache all model image paths for a model and add monastery operation hooks
|
|
71
72
|
* Todo: need to test the model hook arguement signatures here
|
|
72
73
|
* @param {object} model
|
|
73
|
-
* @this
|
|
74
|
+
* @this {object} - null
|
|
74
75
|
*/
|
|
75
|
-
model.imageFields = plugin._findAndTransformImageFields(model.fields, '')
|
|
76
|
+
model.imageFields = plugin._findAndTransformImageFields.call(model, model.fields, '')
|
|
76
77
|
|
|
77
78
|
if (model.imageFields.length) {
|
|
78
79
|
// Todo?: Update image fields / blacklists with the new object schema
|
|
79
80
|
// model._setupFields(model.fields)/model._getFieldsFlattened(model.fields)
|
|
80
81
|
model.beforeValidate.push(function(data, n) {
|
|
81
|
-
plugin.keepImagePlacement(this, data).then(() => n(null, data)).catch(e => n(e))
|
|
82
|
+
plugin.keepImagePlacement.call(this, data).then(() => n(null, data)).catch(e => n(e))
|
|
82
83
|
})
|
|
83
84
|
model.beforeUpdate.push(function(data, n) {
|
|
84
|
-
plugin.removeImages(this, data).then(() => n(null, data)).catch(e => n(e))
|
|
85
|
+
plugin.removeImages.call(this, data).then(() => n(null, data)).catch(e => n(e))
|
|
85
86
|
})
|
|
86
87
|
model.beforeRemove.push(function(n) {
|
|
87
|
-
plugin.removeImages(this, {}).then(() => n(null, {})).catch(e => n(e))
|
|
88
|
+
plugin.removeImages.call(this, {}).then(() => n(null, {})).catch(e => n(e))
|
|
88
89
|
})
|
|
89
90
|
model.afterUpdate.push(function(data, n) {
|
|
90
|
-
plugin.addImages(this, data).then(() => n(null, data)).catch(e => n(e))
|
|
91
|
+
plugin.addImages.call(this, data).then(() => n(null, data)).catch(e => n(e))
|
|
91
92
|
})
|
|
92
93
|
model.afterInsert.push(function(data, n) {
|
|
93
|
-
plugin.addImages(this, data).then(() => n(null, data)).catch(e => n(e))
|
|
94
|
+
plugin.addImages.call(this, data).then(() => n(null, data)).catch(e => n(e))
|
|
94
95
|
})
|
|
95
96
|
model.afterFind.push(function(data, n) {
|
|
96
|
-
plugin.getSignedUrls.call(
|
|
97
|
+
plugin.getSignedUrls.call(this, data).then(() => n(null, data)).catch(e => n(e))
|
|
97
98
|
})
|
|
98
99
|
}
|
|
99
100
|
},
|
|
100
101
|
|
|
101
|
-
addImages: function(
|
|
102
|
+
addImages: function(data, test) {
|
|
102
103
|
/**
|
|
103
104
|
* Hooked after create/update
|
|
104
105
|
* Uploads viable images and saves their details on the model. AWS Lambda takes
|
|
@@ -115,19 +116,20 @@ let plugin = module.exports = {
|
|
|
115
116
|
* 2mb: 1864ms, 1164ms
|
|
116
117
|
* 0.1mb: 480ms
|
|
117
118
|
*
|
|
118
|
-
* @param {object} options - monastery operation options {model, query, files, ..}
|
|
119
119
|
* @param {object} data -
|
|
120
120
|
* @param {boolean} test -
|
|
121
|
+
*
|
|
121
122
|
* @return promise(
|
|
122
123
|
* {object} data - data object containing new S3 image-object
|
|
123
124
|
* ])
|
|
124
|
-
* @this
|
|
125
|
+
* @this {object} - monastery operation options {model, query, files, create, multi }
|
|
125
126
|
*/
|
|
126
|
-
|
|
127
|
+
const { model, query, files, create, multi } = this
|
|
128
|
+
const imagePlugin = model.manager.imagePlugin
|
|
127
129
|
if (!files) return Promise.resolve([])
|
|
128
130
|
|
|
129
131
|
// Build an ID query from query/data. Inserts add _id to the data automatically.
|
|
130
|
-
|
|
132
|
+
const idquery = query && query._id? query : { _id: data._id }
|
|
131
133
|
|
|
132
134
|
// We currently don't support an array of data objects.
|
|
133
135
|
if (util.isArray(data)) {
|
|
@@ -144,32 +146,32 @@ let plugin = module.exports = {
|
|
|
144
146
|
}
|
|
145
147
|
|
|
146
148
|
// Find valid images and upload to S3, and update data with image objects
|
|
147
|
-
return plugin._findValidImages(
|
|
149
|
+
return plugin._findValidImages.call(model, files).then(files => {
|
|
148
150
|
return Promise.all(files.map(filesArr => {
|
|
149
151
|
return Promise.all(filesArr.map(file => {
|
|
150
152
|
return new Promise((resolve, reject) => {
|
|
151
153
|
let uid = require('nanoid').nanoid()
|
|
152
|
-
let path = filesArr.imageField.path ||
|
|
154
|
+
let path = filesArr.imageField.path || imagePlugin.path
|
|
153
155
|
let image = {
|
|
154
|
-
bucket: filesArr.imageField.awsBucket ||
|
|
155
|
-
date:
|
|
156
|
+
bucket: filesArr.imageField.awsBucket || imagePlugin.awsBucket,
|
|
157
|
+
date: model.manager.opts.useMilliseconds? Date.now() : Math.floor(Date.now() / 1000),
|
|
156
158
|
filename: file.name,
|
|
157
159
|
filesize: file.size,
|
|
158
|
-
metadata: filesArr.imageField.metadata ||
|
|
160
|
+
metadata: filesArr.imageField.metadata || imagePlugin.metadata,
|
|
159
161
|
path: path(uid, file.name, file.ext, file),
|
|
160
162
|
uid: uid,
|
|
161
163
|
}
|
|
162
164
|
let s3Options = {
|
|
163
165
|
// ACL: Some IAM permissions "s3:PutObjectACL" must be included in the policy
|
|
164
166
|
// params: https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html#upload-property
|
|
165
|
-
ACL: filesArr.imageField.awsAcl ||
|
|
167
|
+
ACL: filesArr.imageField.awsAcl || imagePlugin.awsAcl,
|
|
166
168
|
Body: file.data,
|
|
167
169
|
Bucket: image.bucket,
|
|
168
170
|
Key: image.path,
|
|
169
171
|
Metadata: image.metadata,
|
|
170
|
-
...(filesArr.imageField.params ||
|
|
172
|
+
...(filesArr.imageField.params || imagePlugin.params),
|
|
171
173
|
}
|
|
172
|
-
|
|
174
|
+
model.manager.info(
|
|
173
175
|
`Uploading '${image.filename}' to '${image.bucket}/${image.path}'`
|
|
174
176
|
)
|
|
175
177
|
if (test) {
|
|
@@ -178,7 +180,7 @@ let plugin = module.exports = {
|
|
|
178
180
|
} else {
|
|
179
181
|
const { Upload } = require('@aws-sdk/lib-storage')
|
|
180
182
|
const upload = new Upload({
|
|
181
|
-
client:
|
|
183
|
+
client: imagePlugin.getS3Client(),
|
|
182
184
|
params: s3Options,
|
|
183
185
|
})
|
|
184
186
|
// upload.on('httpUploadProgress', (progress) => {
|
|
@@ -206,44 +208,74 @@ let plugin = module.exports = {
|
|
|
206
208
|
return model._update(
|
|
207
209
|
idquery,
|
|
208
210
|
{ '$set': prunedData },
|
|
209
|
-
{ 'multi':
|
|
211
|
+
{ 'multi': multi || create }
|
|
210
212
|
)
|
|
211
213
|
|
|
212
214
|
// If errors, remove inserted documents to prevent double ups when the user resaves.
|
|
213
215
|
// We are pretty much trying to emulate a db transaction.
|
|
214
216
|
}).catch(err => {
|
|
215
|
-
if (
|
|
217
|
+
if (create) model._remove(idquery)
|
|
216
218
|
throw err
|
|
217
219
|
})
|
|
218
220
|
},
|
|
219
221
|
|
|
220
|
-
|
|
222
|
+
getSignedUrl: async function(path, expires=3600, bucket) {
|
|
223
|
+
/**
|
|
224
|
+
* @param {string} path - aws file path
|
|
225
|
+
* @param {number} <expires> - seconds
|
|
226
|
+
* @param {string} <bucket>
|
|
227
|
+
*
|
|
228
|
+
* @return {promise} signedUrl
|
|
229
|
+
* @see v2: https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html#getSignedUrl-property
|
|
230
|
+
* @see v3: https://github.com/aws/aws-sdk-js-v3/blob/main/UPGRADING.md#s3-presigned-url
|
|
231
|
+
*
|
|
232
|
+
* @this manager
|
|
233
|
+
*/
|
|
234
|
+
const { imagePlugin } = this
|
|
235
|
+
if (!imagePlugin) {
|
|
236
|
+
throw new Error(
|
|
237
|
+
'You must call getSignedUrl() with a manager as the context. The manager also needs to have the imagePlugin setup too, ' +
|
|
238
|
+
'e.g. `monastery(..., { imagePlugin })`'
|
|
239
|
+
)
|
|
240
|
+
}
|
|
241
|
+
const { GetObjectCommand } = require('@aws-sdk/client-s3')
|
|
242
|
+
const params = { Bucket: bucket || imagePlugin.awsBucket, Key: path }
|
|
243
|
+
const command = new GetObjectCommand(params)
|
|
244
|
+
let signedUrl = await getSignedUrl(imagePlugin.getS3Client(true), command, { expiresIn: expires })
|
|
245
|
+
// console.log(signedUrl)
|
|
246
|
+
return signedUrl
|
|
247
|
+
},
|
|
248
|
+
|
|
249
|
+
getSignedUrls: async function(data) {
|
|
221
250
|
/**
|
|
222
251
|
* Get signed urls for all image objects in data
|
|
223
|
-
*
|
|
252
|
+
*
|
|
224
253
|
* @param {object} data
|
|
254
|
+
*
|
|
225
255
|
* @return promise() - mutates data
|
|
226
|
-
* @this model
|
|
256
|
+
* @this {object} - monastery operation options {model, query, files, ..}
|
|
227
257
|
*/
|
|
228
258
|
// Not wanting signed urls for this operation?
|
|
229
|
-
|
|
259
|
+
const { getSignedUrls, model } = this
|
|
260
|
+
const imagePlugin = model.manager.imagePlugin
|
|
261
|
+
if (util.isDefined(getSignedUrls) && !getSignedUrls) return
|
|
230
262
|
|
|
231
263
|
// Find all image objects in data
|
|
232
264
|
for (let doc of util.toArray(data)) {
|
|
233
|
-
for (let imageField of
|
|
234
|
-
if (
|
|
235
|
-
|| (util.isDefined(imageField.getSignedUrl) ? imageField.getSignedUrl :
|
|
265
|
+
for (let imageField of model.imageFields) {
|
|
266
|
+
if (getSignedUrls
|
|
267
|
+
|| (util.isDefined(imageField.getSignedUrl) ? imageField.getSignedUrl : imagePlugin.getSignedUrlOption)) {
|
|
236
268
|
let images = plugin._findImagesInData(doc, imageField, 0, '').filter(o => o.image)
|
|
237
269
|
// todo: we could do this in parallel
|
|
238
270
|
for (let image of images) {
|
|
239
|
-
image.image.signedUrl = await plugin.getSignedUrl(image.image.path, 3600, imageField.awsBucket)
|
|
271
|
+
image.image.signedUrl = await plugin.getSignedUrl.call(model.manager, image.image.path, 3600, imageField.awsBucket)
|
|
240
272
|
}
|
|
241
273
|
}
|
|
242
274
|
}
|
|
243
275
|
}
|
|
244
276
|
},
|
|
245
277
|
|
|
246
|
-
keepImagePlacement: async function(
|
|
278
|
+
keepImagePlacement: async function(data) {
|
|
247
279
|
/**
|
|
248
280
|
* Hook before update/remove
|
|
249
281
|
* Since monastery removes undefined array items on validate, we need to convert any
|
|
@@ -254,22 +286,22 @@ let plugin = module.exports = {
|
|
|
254
286
|
* req.body = 'photos[0]' : undefined || non existing (set to null)
|
|
255
287
|
* req.files = 'photos[0]' : { ...binary }
|
|
256
288
|
*
|
|
257
|
-
* @param {object} options - monastery operation options {query, model, files, multi, ..}
|
|
258
289
|
* @return promise
|
|
259
|
-
* @this
|
|
290
|
+
* @this {object} - monastery operation options {query, model, files, multi, ..}
|
|
260
291
|
*/
|
|
261
|
-
|
|
292
|
+
const { model, files } = this
|
|
293
|
+
if (typeof files == 'undefined') return
|
|
262
294
|
// Check upload errors and find valid uploaded images
|
|
263
|
-
let
|
|
295
|
+
let validFiles = await plugin._findValidImages.call(model, files || {})
|
|
264
296
|
// Set undefined primative-array items to null where files are located
|
|
265
|
-
for (let
|
|
266
|
-
if (
|
|
267
|
-
util.setDeepValue(data,
|
|
297
|
+
for (let item of validFiles) {
|
|
298
|
+
if (item.inputPath.match(/\.[0-9]+$/)) {
|
|
299
|
+
util.setDeepValue(data, item.inputPath, null, true, false, true)
|
|
268
300
|
}
|
|
269
301
|
}
|
|
270
302
|
},
|
|
271
303
|
|
|
272
|
-
removeImages: async function(
|
|
304
|
+
removeImages: async function(data, test) {
|
|
273
305
|
/**
|
|
274
306
|
* Hook before update/remove
|
|
275
307
|
* Removes images not found in data, this means you will need to pass the image objects to every update operation
|
|
@@ -280,24 +312,25 @@ let plugin = module.exports = {
|
|
|
280
312
|
* 3. delete leftovers from S3
|
|
281
313
|
*
|
|
282
314
|
* @ref https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html#deleteObjects-property
|
|
283
|
-
* @param {object} options - monastery operation options {query, model, files, multi, ..}
|
|
284
315
|
* @return promise([
|
|
285
316
|
* {object} useCount - images that wont be removed, e.g. { lion1: 1 }
|
|
286
317
|
* {array} unused - S3 image uris to be removed, e.g. [{ Key: 'small/lion1.jpg' }, ..]
|
|
287
318
|
* ])
|
|
288
|
-
* @this
|
|
319
|
+
* @this {object} - monastery operation options {query, model, files, multi, ..}
|
|
289
320
|
*/
|
|
290
321
|
let pre
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
322
|
+
const preExistingImages = []
|
|
323
|
+
const useCount = {}
|
|
324
|
+
const { model, files, query } = this
|
|
325
|
+
const imagePlugin = model.manager.imagePlugin
|
|
326
|
+
if (typeof files == 'undefined') return
|
|
294
327
|
|
|
295
328
|
// Find all documents from the same query
|
|
296
|
-
|
|
329
|
+
const docs = await model._find(query, this)
|
|
297
330
|
|
|
298
331
|
// Find all pre-existing image objects in documents
|
|
299
332
|
for (let doc of util.toArray(docs)) { //x2
|
|
300
|
-
for (let imageField of
|
|
333
|
+
for (let imageField of model.imageFields) { //x5
|
|
301
334
|
let images = plugin._findImagesInData(doc, imageField, 0, '').filter(o => o.image)
|
|
302
335
|
for (let image of images) {
|
|
303
336
|
preExistingImages.push(image)
|
|
@@ -320,10 +353,10 @@ let plugin = module.exports = {
|
|
|
320
353
|
// console.log(dataFilled)
|
|
321
354
|
|
|
322
355
|
// Check upload errors and find valid uploaded images
|
|
323
|
-
let
|
|
356
|
+
let validFiles = await plugin._findValidImages.call(model, files || {})
|
|
324
357
|
|
|
325
358
|
// Loop all schema image fields
|
|
326
|
-
for (let imageField of
|
|
359
|
+
for (let imageField of model.imageFields) { //x5
|
|
327
360
|
let images = plugin._findImagesInData(dataFilled, imageField, 0, '')
|
|
328
361
|
if (!images.length) continue
|
|
329
362
|
// console.log(images)
|
|
@@ -353,8 +386,8 @@ let plugin = module.exports = {
|
|
|
353
386
|
useCount[image.image.uid]++
|
|
354
387
|
}
|
|
355
388
|
// Any file overriding this image?
|
|
356
|
-
for (let
|
|
357
|
-
if (image.dataPath ==
|
|
389
|
+
for (let item of validFiles) {
|
|
390
|
+
if (image.dataPath == item.inputPath) {
|
|
358
391
|
useCount[image.image.uid]--
|
|
359
392
|
}
|
|
360
393
|
}
|
|
@@ -376,17 +409,17 @@ let plugin = module.exports = {
|
|
|
376
409
|
{ Key: `medium/${key}.jpg` },
|
|
377
410
|
{ Key: `large/${key}.jpg` }
|
|
378
411
|
)
|
|
379
|
-
|
|
412
|
+
model.manager.info(
|
|
380
413
|
`Removing '${pre.image.filename}' from '${pre.image.bucket}/${pre.image.path}'`
|
|
381
414
|
)
|
|
382
415
|
}
|
|
383
416
|
if (test) return [useCount, unused]
|
|
384
417
|
// Delete any unused images from s3. If the image is on a different bucket
|
|
385
|
-
// the file doesnt get deleted, we only delete from
|
|
418
|
+
// the file doesnt get deleted, we only delete from imagePlugin.awsBucket.
|
|
386
419
|
if (!unused.length) return
|
|
387
420
|
await new Promise((resolve, reject) => {
|
|
388
|
-
|
|
389
|
-
Bucket:
|
|
421
|
+
imagePlugin.getS3Client().deleteObjects({
|
|
422
|
+
Bucket: imagePlugin.awsBucket,
|
|
390
423
|
Delete: { Objects: unused },
|
|
391
424
|
}, (err, data) => {
|
|
392
425
|
if (err) reject(err)
|
|
@@ -402,6 +435,7 @@ let plugin = module.exports = {
|
|
|
402
435
|
* @param {object} data
|
|
403
436
|
* @param {object} image
|
|
404
437
|
* @return mutates data
|
|
438
|
+
* @this null
|
|
405
439
|
*/
|
|
406
440
|
let chunks = path.split('.')
|
|
407
441
|
let target = data
|
|
@@ -421,22 +455,24 @@ let plugin = module.exports = {
|
|
|
421
455
|
return data
|
|
422
456
|
},
|
|
423
457
|
|
|
424
|
-
_findValidImages: function(files
|
|
458
|
+
_findValidImages: function(files) {
|
|
425
459
|
/**
|
|
426
460
|
* Find and return valid uploaded files
|
|
427
461
|
* @param {object} files - req.files
|
|
428
|
-
* @param {object} model
|
|
429
462
|
* @return promise([
|
|
430
463
|
* [{..file}, .imageField, .inputPath],
|
|
431
464
|
* ..
|
|
432
465
|
* ])
|
|
466
|
+
* @this model
|
|
433
467
|
*/
|
|
434
468
|
let validFiles = []
|
|
469
|
+
const { imageFields, manager } = this
|
|
470
|
+
const imagePlugin = manager.imagePlugin
|
|
435
471
|
|
|
436
472
|
// Filter valid image files by `type='image'`, convert file keys to dot notation, and force array
|
|
437
473
|
for (let key in files) {
|
|
438
474
|
let key2 = key.replace(/\]/g, '').replace(/\[/g, '.')
|
|
439
|
-
let imageField =
|
|
475
|
+
let imageField = imageFields.find(o => key2.match(o.fullPathRegex))
|
|
440
476
|
if (imageField) {
|
|
441
477
|
let filesArr = util.toArray(files[key])
|
|
442
478
|
filesArr.imageField = imageField
|
|
@@ -452,8 +488,8 @@ let plugin = module.exports = {
|
|
|
452
488
|
return Promise.all(filesArr.map((file, i) => {
|
|
453
489
|
return new Promise((resolve, reject) => {
|
|
454
490
|
require('file-type').fromBuffer(file.data).then(res => {
|
|
455
|
-
let filesize = filesArr.imageField.filesize ||
|
|
456
|
-
let formats = filesArr.imageField.formats ||
|
|
491
|
+
let filesize = filesArr.imageField.filesize || imagePlugin.filesize
|
|
492
|
+
let formats = filesArr.imageField.formats || imagePlugin.formats
|
|
457
493
|
let allowAny = util.inArray(formats, 'any')
|
|
458
494
|
file.format = res? res.ext : ''
|
|
459
495
|
file.ext = file.format || (file.name.match(/\.(.*)$/) || [])[1] || 'unknown'
|
|
@@ -488,10 +524,11 @@ let plugin = module.exports = {
|
|
|
488
524
|
* @param {object|array} unprocessedFields - fields not yet setup
|
|
489
525
|
* @param {string} path
|
|
490
526
|
* @return [{}, ...]
|
|
491
|
-
* @this
|
|
527
|
+
* @this model
|
|
492
528
|
*/
|
|
493
529
|
let list = []
|
|
494
|
-
|
|
530
|
+
const { manager } = this
|
|
531
|
+
const imagePlugin = manager.imagePlugin
|
|
495
532
|
util.forEach(unprocessedFields, (field, fieldName) => {
|
|
496
533
|
let path2 = `${path}.${fieldName}`.replace(/^\./, '')
|
|
497
534
|
if (fieldName == 'schema') return
|
|
@@ -499,12 +536,12 @@ let plugin = module.exports = {
|
|
|
499
536
|
// Subdocument field
|
|
500
537
|
if (util.isSubdocument(field)) {
|
|
501
538
|
// log(`Recurse 1: ${path2}`)
|
|
502
|
-
list = list.concat(plugin._findAndTransformImageFields(field, path2))
|
|
539
|
+
list = list.concat(plugin._findAndTransformImageFields.call(this, field, path2))
|
|
503
540
|
|
|
504
541
|
// Array field
|
|
505
542
|
} else if (util.isArray(field)) {
|
|
506
543
|
// log(`Recurse 2: ${path2}`)
|
|
507
|
-
list = list.concat(plugin._findAndTransformImageFields(field, path2))
|
|
544
|
+
list = list.concat(plugin._findAndTransformImageFields.call(this, field, path2))
|
|
508
545
|
|
|
509
546
|
// Image field. Test for field.image as field.type may be 'any'
|
|
510
547
|
} else if (field.type == 'image' || field.image) {
|
|
@@ -514,8 +551,9 @@ let plugin = module.exports = {
|
|
|
514
551
|
}
|
|
515
552
|
if (field.filename) { // > v1.36.3
|
|
516
553
|
this.manager.warn(`${path2}.filename has been depreciated in favour of ${path2}.path()`)
|
|
517
|
-
field.path = field.path
|
|
518
|
-
|
|
554
|
+
field.path = field.path || function(uid, basename, ext, file) {
|
|
555
|
+
return `${imagePlugin.bucketDir}/${uid}/${field.filename}.${ext}`
|
|
556
|
+
}
|
|
519
557
|
}
|
|
520
558
|
|
|
521
559
|
list.push({
|
|
@@ -540,7 +578,7 @@ let plugin = module.exports = {
|
|
|
540
578
|
metadata: { type: 'any' },
|
|
541
579
|
path: { type: 'string' },
|
|
542
580
|
uid: { type: 'string' },
|
|
543
|
-
schema: { image: true, isImageObject: true, nullObject: true },
|
|
581
|
+
schema: { image: true, isImageObject: true, nullObject: true, default: undefined },
|
|
544
582
|
}
|
|
545
583
|
}
|
|
546
584
|
})
|
|
@@ -555,6 +593,7 @@ let plugin = module.exports = {
|
|
|
555
593
|
* @param {number} imageFieldChunkIndex - imageField path chunk index
|
|
556
594
|
* @param {string} dataPath
|
|
557
595
|
* @return [{ imageField: {}, dataPath: '', image: {} }, ..]
|
|
596
|
+
* @this null
|
|
558
597
|
*/
|
|
559
598
|
let list = []
|
|
560
599
|
let chunks = imageField.fullPath.split('.').slice(imageFieldChunkIndex)
|
|
@@ -590,27 +629,4 @@ let plugin = module.exports = {
|
|
|
590
629
|
|
|
591
630
|
return list
|
|
592
631
|
},
|
|
593
|
-
|
|
594
|
-
getSignedUrl: async (path, expires=3600, bucket) => {
|
|
595
|
-
/**
|
|
596
|
-
* @param {string} path - aws file path
|
|
597
|
-
* @param {number} <expires> - seconds
|
|
598
|
-
* @param {string} <bucket>
|
|
599
|
-
* @return {promise} signedUrl
|
|
600
|
-
* @see v2: https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html#getSignedUrl-property
|
|
601
|
-
* @see v3: https://github.com/aws/aws-sdk-js-v3/blob/main/UPGRADING.md#s3-presigned-url
|
|
602
|
-
*/
|
|
603
|
-
if (!plugin.getS3Client) {
|
|
604
|
-
throw new Error(
|
|
605
|
-
'To use db.getSignedUrl(), the imagePlugin manager option must be defined, e.g. `monastery(..., { imagePlugin })`'
|
|
606
|
-
)
|
|
607
|
-
}
|
|
608
|
-
const { GetObjectCommand } = require('@aws-sdk/client-s3')
|
|
609
|
-
const params = { Bucket: bucket || plugin.awsBucket, Key: path }
|
|
610
|
-
const command = new GetObjectCommand(params)
|
|
611
|
-
let signedUrl = await getSignedUrl(plugin.getS3Client(true), command, { expiresIn: expires })
|
|
612
|
-
// console.log(signedUrl)
|
|
613
|
-
return signedUrl
|
|
614
|
-
},
|
|
615
|
-
|
|
616
632
|
}
|
package/test/crud.js
CHANGED
|
@@ -52,19 +52,32 @@ test('insert basics', async () => {
|
|
|
52
52
|
})
|
|
53
53
|
|
|
54
54
|
test('insert option defaultObjects', async () => {
|
|
55
|
-
let db2 = monastery('127.0.0.1/monastery', {
|
|
55
|
+
let db2 = monastery('127.0.0.1/monastery', {
|
|
56
|
+
defaultObjects: true,
|
|
57
|
+
timestamps: false,
|
|
58
|
+
imagePlugin: {
|
|
59
|
+
awsBucket: 'test',
|
|
60
|
+
awsRegion: 'test',
|
|
61
|
+
awsAccessKeyId: 'test',
|
|
62
|
+
awsSecretAccessKey: 'test',
|
|
63
|
+
},
|
|
64
|
+
})
|
|
56
65
|
let schema = {
|
|
57
66
|
fields: {
|
|
67
|
+
avatar: { type: 'image' }, // its an object but should default to `undefined`
|
|
58
68
|
name: { type: 'string' },
|
|
59
69
|
names: [{ type: 'string' }],
|
|
70
|
+
animal: {
|
|
71
|
+
name: { type: 'string' },
|
|
72
|
+
},
|
|
60
73
|
animals: {
|
|
61
74
|
dog: { type: 'string' },
|
|
62
75
|
dogs: [{ name: { type: 'string' } }],
|
|
63
76
|
},
|
|
64
77
|
},
|
|
65
78
|
}
|
|
66
|
-
let user1 = db.model('user', schema)
|
|
67
|
-
let user2 = db2.model('user', schema)
|
|
79
|
+
let user1 = db.model('user-defaultObjects', schema)
|
|
80
|
+
let user2 = db2.model('user-defaultObjects', schema)
|
|
68
81
|
|
|
69
82
|
// defaultObjects off (default)
|
|
70
83
|
let inserted1 = await user1.insert({ data: {} })
|
|
@@ -76,6 +89,7 @@ test('insert option defaultObjects', async () => {
|
|
|
76
89
|
let inserted2 = await user2.insert({ data: {} })
|
|
77
90
|
expect(inserted2).toEqual({
|
|
78
91
|
_id: inserted2._id,
|
|
92
|
+
animal: {},
|
|
79
93
|
names: [],
|
|
80
94
|
animals: { dogs: [] },
|
|
81
95
|
})
|
package/test/plugin-images.js
CHANGED
|
@@ -158,11 +158,15 @@ test('images addImages helper functions', async () => {
|
|
|
158
158
|
})
|
|
159
159
|
|
|
160
160
|
test('images addImages', async () => {
|
|
161
|
-
let user = db.model('user', {
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
161
|
+
let user = db.model('user', {
|
|
162
|
+
fields: {
|
|
163
|
+
logo: { type: 'image' },
|
|
164
|
+
logos: [{ type: 'image' }],
|
|
165
|
+
users: [{ logo: { type: 'image' } }],
|
|
166
|
+
},
|
|
167
|
+
})
|
|
168
|
+
// console.log(db.opts, user.fields.logo)
|
|
169
|
+
// throw 'qwef'
|
|
166
170
|
|
|
167
171
|
let supertest = require('supertest')
|
|
168
172
|
let express = require('express')
|
|
@@ -174,7 +178,7 @@ test('images addImages', async () => {
|
|
|
174
178
|
try {
|
|
175
179
|
// Files exist
|
|
176
180
|
expect(req.files.logo).toEqual(expect.any(Object))
|
|
177
|
-
let validFiles = await imagePluginFile._findValidImages(req.files
|
|
181
|
+
let validFiles = await imagePluginFile._findValidImages.call(user, req.files)
|
|
178
182
|
// Valid file count
|
|
179
183
|
expect(validFiles).toEqual([
|
|
180
184
|
expect.any(Array),
|
|
@@ -198,7 +202,7 @@ test('images addImages', async () => {
|
|
|
198
202
|
expect(validFiles[2][0].format).toEqual('png')
|
|
199
203
|
expect(validFiles[3][0].format).toEqual('png')
|
|
200
204
|
|
|
201
|
-
let response = await imagePluginFile.addImages(
|
|
205
|
+
let response = await imagePluginFile.addImages.call(
|
|
202
206
|
{ model: user, files: req.files, query: { _id: 1234 }},
|
|
203
207
|
req.body,
|
|
204
208
|
true
|
|
@@ -240,7 +244,8 @@ test('images addImages', async () => {
|
|
|
240
244
|
})
|
|
241
245
|
res.send()
|
|
242
246
|
} catch (e) {
|
|
243
|
-
console.log(e
|
|
247
|
+
console.log(e)
|
|
248
|
+
// console.log(e.message || e)
|
|
244
249
|
res.status(500).send()
|
|
245
250
|
}
|
|
246
251
|
})
|
|
@@ -297,7 +302,7 @@ test('images removeImages', async () => {
|
|
|
297
302
|
req.body.logos = JSON.parse(req.body.logos)
|
|
298
303
|
req.body.users = JSON.parse(req.body.users)
|
|
299
304
|
let options = { files: req.files, model: user, query: { _id: user1._id }}
|
|
300
|
-
let response = await imagePluginFile.removeImages(options, req.body, true)
|
|
305
|
+
let response = await imagePluginFile.removeImages.call(options, req.body, true)
|
|
301
306
|
expect(response[0]).toEqual({ test1: 1, test2: 0, test3: 1, test4: 0 })
|
|
302
307
|
expect(response[1]).toEqual([
|
|
303
308
|
{ Key: 'dir/test2.png' },
|
|
@@ -358,7 +363,7 @@ test('images removeImages with no data', async () => {
|
|
|
358
363
|
app.post('/', async function(req, res) {
|
|
359
364
|
try {
|
|
360
365
|
let options = { files: req.files, model: user, query: { _id: user1._id }}
|
|
361
|
-
let response = await imagePluginFile.removeImages(options, req.body, true)
|
|
366
|
+
let response = await imagePluginFile.removeImages.call(options, req.body, true)
|
|
362
367
|
expect(response[0]).toEqual({})
|
|
363
368
|
expect(response[1]).toEqual([])
|
|
364
369
|
res.send()
|
|
@@ -474,7 +479,7 @@ test('images reorder', async () => {
|
|
|
474
479
|
try {
|
|
475
480
|
req.body.logos = JSON.parse(req.body.logos)
|
|
476
481
|
let options = { files: req.files, model: user, query: { _id: user1._id } }
|
|
477
|
-
let response = await imagePluginFile.removeImages(options, req.body, true)
|
|
482
|
+
let response = await imagePluginFile.removeImages.call(options, req.body, true)
|
|
478
483
|
expect(response[0]).toEqual({ lion1: 1 })
|
|
479
484
|
expect(response[1]).toEqual([])
|
|
480
485
|
res.send()
|
|
@@ -526,16 +531,16 @@ test('images reorder and added image', async () => {
|
|
|
526
531
|
expect(data.photos[1]).toEqual(image)
|
|
527
532
|
|
|
528
533
|
// Remove images
|
|
529
|
-
let response = await imagePluginFile.removeImages(options, data, true)
|
|
534
|
+
let response = await imagePluginFile.removeImages.call(options, data, true)
|
|
530
535
|
expect(response[0]).toEqual({ lion1: 1 }) // useCount
|
|
531
536
|
expect(response[1]).toEqual([]) // unused
|
|
532
537
|
|
|
533
538
|
// New file exists
|
|
534
|
-
let validFiles = await imagePluginFile._findValidImages(req.files
|
|
539
|
+
let validFiles = await imagePluginFile._findValidImages.call(user, req.files)
|
|
535
540
|
expect(((validFiles||[])[0]||{}).inputPath).toEqual('photos.0') // Valid inputPath
|
|
536
541
|
|
|
537
542
|
// Add images
|
|
538
|
-
response = await imagePluginFile.addImages(options, data, true)
|
|
543
|
+
response = await imagePluginFile.addImages.call(options, data, true)
|
|
539
544
|
expect(response[0]).toEqual({
|
|
540
545
|
photos: [{
|
|
541
546
|
bucket: 'fake',
|
|
@@ -592,13 +597,13 @@ test('images option defaults', async () => {
|
|
|
592
597
|
app.use(upload({ limits: { fileSize: 1000 * 480, files: 10 }}))
|
|
593
598
|
|
|
594
599
|
// Basic tests
|
|
595
|
-
expect(
|
|
596
|
-
expect(
|
|
597
|
-
expect(
|
|
598
|
-
expect(
|
|
599
|
-
expect(
|
|
600
|
-
expect(
|
|
601
|
-
expect(
|
|
600
|
+
expect(db.imagePlugin.awsAcl).toEqual('public-read')
|
|
601
|
+
expect(db.imagePlugin.filesize).toEqual(undefined)
|
|
602
|
+
expect(db.imagePlugin.formats).toEqual(['bmp', 'gif', 'jpg', 'jpeg', 'png', 'tiff'])
|
|
603
|
+
expect(db.imagePlugin.getSignedUrlOption).toEqual(undefined)
|
|
604
|
+
expect(db.imagePlugin.metadata).toEqual(undefined)
|
|
605
|
+
expect(db.imagePlugin.path).toEqual(expect.any(Function))
|
|
606
|
+
expect(db.imagePlugin.params).toEqual({})
|
|
602
607
|
|
|
603
608
|
// Images not signed
|
|
604
609
|
let image
|
|
@@ -621,7 +626,7 @@ test('images option defaults', async () => {
|
|
|
621
626
|
try {
|
|
622
627
|
// Files exist
|
|
623
628
|
expect(req.files.logo).toEqual(expect.any(Object))
|
|
624
|
-
let response = await imagePluginFile.addImages(
|
|
629
|
+
let response = await imagePluginFile.addImages.call(
|
|
625
630
|
{ model: user, files: req.files, query: { _id: 1234 }},
|
|
626
631
|
req.body || {},
|
|
627
632
|
true
|
|
@@ -698,20 +703,20 @@ test('images options formats & filesizes', async () => {
|
|
|
698
703
|
delete req.files.imageSize2
|
|
699
704
|
delete req.files.imageSize3
|
|
700
705
|
// Ico, Webp, and imageSvgGood will throw an error first if it's not a valid type
|
|
701
|
-
await expect(imagePluginFile._findValidImages(req.files
|
|
702
|
-
await expect(imagePluginFile._findValidImages(
|
|
706
|
+
await expect(imagePluginFile._findValidImages.call(user, req.files)).resolves.toEqual(expect.any(Array))
|
|
707
|
+
await expect(imagePluginFile._findValidImages.call(user, imageSvgBad)).rejects.toEqual({
|
|
703
708
|
title: 'imageSvgBad',
|
|
704
709
|
detail: 'The file format \'svg\' for \'bad.svg\' is not supported',
|
|
705
710
|
})
|
|
706
|
-
await expect(imagePluginFile._findValidImages(
|
|
711
|
+
await expect(imagePluginFile._findValidImages.call(user, imageSize1)).rejects.toEqual({
|
|
707
712
|
title: 'imageSize1',
|
|
708
713
|
detail: 'The file size for \'lion1.png\' is bigger than 0.1MB.',
|
|
709
714
|
})
|
|
710
|
-
await expect(imagePluginFile._findValidImages(
|
|
715
|
+
await expect(imagePluginFile._findValidImages.call(user, imageSize2)).rejects.toEqual({
|
|
711
716
|
title: 'imageSize2',
|
|
712
717
|
detail: 'The file size for \'lion2.jpg\' is bigger than 0.3MB.',
|
|
713
718
|
})
|
|
714
|
-
await expect(imagePluginFile._findValidImages(
|
|
719
|
+
await expect(imagePluginFile._findValidImages.call(user, imageSize3)).rejects.toEqual({
|
|
715
720
|
title: 'imageSize3',
|
|
716
721
|
detail: 'The file size for \'house.jpg\' is too big.',
|
|
717
722
|
})
|
|
@@ -773,26 +778,27 @@ test('images option getSignedUrls', async () => {
|
|
|
773
778
|
})
|
|
774
779
|
|
|
775
780
|
// Find signed URL via query option
|
|
776
|
-
await expect(db3.user.findOne({ query: userInserted._id, getSignedUrls: true })).resolves.toEqual({
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
})
|
|
781
|
-
|
|
782
|
-
// Find signed URL via schema option
|
|
783
|
-
await expect(db3.user.findOne({ query: userInserted._id })).resolves.toEqual({
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
})
|
|
781
|
+
// await expect(db3.user.findOne({ query: userInserted._id, getSignedUrls: true })).resolves.toEqual({
|
|
782
|
+
// _id: expect.any(Object),
|
|
783
|
+
// photos: [imageWithSignedUrl, imageWithSignedUrl],
|
|
784
|
+
// photos2: [imageWithSignedUrl, imageWithSignedUrl],
|
|
785
|
+
// })
|
|
786
|
+
|
|
787
|
+
// // Find signed URL via schema option
|
|
788
|
+
// await expect(db3.user.findOne({ query: userInserted._id })).resolves.toEqual({
|
|
789
|
+
// _id: expect.any(Object),
|
|
790
|
+
// photos: [image, image],
|
|
791
|
+
// photos2: [imageWithSignedUrl, imageWithSignedUrl],
|
|
792
|
+
// })
|
|
788
793
|
|
|
789
794
|
// Works with _processAfterFind
|
|
790
795
|
let rawUser = await db3.user._findOne({ _id: userInserted._id })
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
+
db3.user._processAfterFind(rawUser)
|
|
797
|
+
// await expect(db3.user._processAfterFind(rawUser)).resolves.toEqual({
|
|
798
|
+
// _id: expect.any(Object),
|
|
799
|
+
// photos: [image, image],
|
|
800
|
+
// photos2: [imageWithSignedUrl, imageWithSignedUrl],
|
|
801
|
+
// })
|
|
796
802
|
db3.close()
|
|
797
803
|
})
|
|
798
804
|
|
|
@@ -833,7 +839,7 @@ test('images options awsAcl, awsBucket, metadata, params, path', async () => {
|
|
|
833
839
|
// Files exist
|
|
834
840
|
expect(req.files.optionDefaults).toEqual(expect.any(Object))
|
|
835
841
|
expect(req.files.optionOverrides).toEqual(expect.any(Object))
|
|
836
|
-
let response = await imagePluginFile.addImages(
|
|
842
|
+
let response = await imagePluginFile.addImages.call(
|
|
837
843
|
{ model: user, files: req.files, query: { _id: 1234 }},
|
|
838
844
|
req.body || {},
|
|
839
845
|
true
|
|
@@ -922,7 +928,7 @@ test('images option depreciations', async () => {
|
|
|
922
928
|
try {
|
|
923
929
|
// Files exist
|
|
924
930
|
expect(req.files.logo).toEqual(expect.any(Object))
|
|
925
|
-
let response = await imagePluginFile.addImages(
|
|
931
|
+
let response = await imagePluginFile.addImages.call(
|
|
926
932
|
{ model: user, files: req.files, query: { _id: 1234 }},
|
|
927
933
|
req.body || {},
|
|
928
934
|
true
|