@adminforth/upload 1.0.29 → 1.0.31-next.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/ChangeLog.md +5 -0
- package/custom/uploader.vue +3 -0
- package/dist/custom/uploader.vue +3 -0
- package/dist/index.js +35 -22
- package/index.ts +31 -16
- package/package.json +2 -1
- package/types.ts +7 -2
package/ChangeLog.md
CHANGED
package/custom/uploader.vue
CHANGED
|
@@ -70,7 +70,9 @@ import { computed, ref, onMounted, watch } from 'vue'
|
|
|
70
70
|
import { callAdminForthApi } from '@/utils'
|
|
71
71
|
import { IconMagic } from '@iconify-prerendered/vue-mdi';
|
|
72
72
|
import { useI18n } from 'vue-i18n';
|
|
73
|
+
import { useRoute } from 'vue-router';
|
|
73
74
|
|
|
75
|
+
const route = useRoute();
|
|
74
76
|
const { t } = useI18n();
|
|
75
77
|
|
|
76
78
|
const inputId = computed(() => `dropzone-file-${props.meta.pluginInstanceId}`);
|
|
@@ -233,6 +235,7 @@ const onFileChange = async (e) => {
|
|
|
233
235
|
contentType: type,
|
|
234
236
|
size,
|
|
235
237
|
originalExtension: extension,
|
|
238
|
+
recordPk: route?.params?.primaryKey,
|
|
236
239
|
},
|
|
237
240
|
});
|
|
238
241
|
|
package/dist/custom/uploader.vue
CHANGED
|
@@ -70,7 +70,9 @@ import { computed, ref, onMounted, watch } from 'vue'
|
|
|
70
70
|
import { callAdminForthApi } from '@/utils'
|
|
71
71
|
import { IconMagic } from '@iconify-prerendered/vue-mdi';
|
|
72
72
|
import { useI18n } from 'vue-i18n';
|
|
73
|
+
import { useRoute } from 'vue-router';
|
|
73
74
|
|
|
75
|
+
const route = useRoute();
|
|
74
76
|
const { t } = useI18n();
|
|
75
77
|
|
|
76
78
|
const inputId = computed(() => `dropzone-file-${props.meta.pluginInstanceId}`);
|
|
@@ -233,6 +235,7 @@ const onFileChange = async (e) => {
|
|
|
233
235
|
contentType: type,
|
|
234
236
|
size,
|
|
235
237
|
originalExtension: extension,
|
|
238
|
+
recordPk: route?.params?.primaryKey,
|
|
236
239
|
},
|
|
237
240
|
});
|
|
238
241
|
|
package/dist/index.js
CHANGED
|
@@ -9,7 +9,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
9
9
|
};
|
|
10
10
|
import { getSignedUrl } from '@aws-sdk/s3-request-presigner';
|
|
11
11
|
import { ExpirationStatus, GetObjectCommand, PutObjectCommand, S3 } from '@aws-sdk/client-s3';
|
|
12
|
-
import { AdminForthPlugin, suggestIfTypo } from "adminforth";
|
|
12
|
+
import { AdminForthPlugin, Filters, suggestIfTypo } from "adminforth";
|
|
13
13
|
import { Readable } from "stream";
|
|
14
14
|
import { RateLimiter } from "adminforth";
|
|
15
15
|
const ADMINFORTH_NOT_YET_USED_TAG = 'adminforth-candidate-for-cleanup';
|
|
@@ -25,13 +25,20 @@ export default class UploadPlugin extends AdminForthPlugin {
|
|
|
25
25
|
return __awaiter(this, void 0, void 0, function* () {
|
|
26
26
|
// check that lifecyle rule "adminforth-unused-cleaner" exists
|
|
27
27
|
const CLEANUP_RULE_ID = 'adminforth-unused-cleaner';
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
28
|
+
let s3;
|
|
29
|
+
try {
|
|
30
|
+
s3 = new S3({
|
|
31
|
+
credentials: {
|
|
32
|
+
accessKeyId: this.options.s3AccessKeyId,
|
|
33
|
+
secretAccessKey: this.options.s3SecretAccessKey,
|
|
34
|
+
},
|
|
35
|
+
region: this.options.s3Region,
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
catch (e) {
|
|
39
|
+
console.error('Unable to connect to S3. Upload will not work. Skipping setup of lifecycle rule', e);
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
35
42
|
// check bucket exists
|
|
36
43
|
const bucketExists = s3.headBucket({ Bucket: this.options.s3Bucket });
|
|
37
44
|
if (!bucketExists) {
|
|
@@ -105,7 +112,7 @@ export default class UploadPlugin extends AdminForthPlugin {
|
|
|
105
112
|
const { pathColumnName } = this.options;
|
|
106
113
|
const pathColumnIndex = resourceConfig.columns.findIndex((column) => column.name === pathColumnName);
|
|
107
114
|
if (pathColumnIndex === -1) {
|
|
108
|
-
throw new Error(`Column with name "${pathColumnName}" not found in resource "${resourceConfig.
|
|
115
|
+
throw new Error(`Column with name "${pathColumnName}" not found in resource "${resourceConfig.label}"`);
|
|
109
116
|
}
|
|
110
117
|
if ((_a = this.options.generation) === null || _a === void 0 ? void 0 : _a.fieldsForContext) {
|
|
111
118
|
(_b = this.options.generation) === null || _b === void 0 ? void 0 : _b.fieldsForContext.forEach((field) => {
|
|
@@ -283,8 +290,8 @@ export default class UploadPlugin extends AdminForthPlugin {
|
|
|
283
290
|
return { ok: true };
|
|
284
291
|
}));
|
|
285
292
|
// add edit postSave hook to delete old file and remove tag from new file
|
|
286
|
-
resourceConfig.hooks.edit.afterSave.push((_s) => __awaiter(this, [_s], void 0, function* ({
|
|
287
|
-
if (
|
|
293
|
+
resourceConfig.hooks.edit.afterSave.push((_s) => __awaiter(this, [_s], void 0, function* ({ updates, oldRecord }) {
|
|
294
|
+
if (updates[virtualColumn.name] || updates[virtualColumn.name] === null) {
|
|
288
295
|
const s3 = new S3({
|
|
289
296
|
credentials: {
|
|
290
297
|
accessKeyId: this.options.s3AccessKeyId,
|
|
@@ -313,12 +320,12 @@ export default class UploadPlugin extends AdminForthPlugin {
|
|
|
313
320
|
console.error(`Error setting tag ${ADMINFORTH_NOT_YET_USED_TAG} to true for object ${oldRecord[pathColumnName]}. File will not be auto-cleaned up`, e);
|
|
314
321
|
}
|
|
315
322
|
}
|
|
316
|
-
if (
|
|
323
|
+
if (updates[virtualColumn.name] !== null) {
|
|
317
324
|
// remove tag from new file
|
|
318
325
|
// in this case we let it crash if it fails: this is a new file which just was uploaded.
|
|
319
326
|
yield s3.putObjectTagging({
|
|
320
327
|
Bucket: this.options.s3Bucket,
|
|
321
|
-
Key:
|
|
328
|
+
Key: updates[pathColumnName],
|
|
322
329
|
Tagging: {
|
|
323
330
|
TagSet: []
|
|
324
331
|
}
|
|
@@ -339,14 +346,20 @@ export default class UploadPlugin extends AdminForthPlugin {
|
|
|
339
346
|
method: 'POST',
|
|
340
347
|
path: `/plugin/${this.pluginInstanceId}/get_s3_upload_url`,
|
|
341
348
|
handler: (_a) => __awaiter(this, [_a], void 0, function* ({ body }) {
|
|
342
|
-
var _b;
|
|
343
|
-
const { originalFilename, contentType, size, originalExtension } = body;
|
|
349
|
+
var _b, _c;
|
|
350
|
+
const { originalFilename, contentType, size, originalExtension, recordPk } = body;
|
|
344
351
|
if (this.options.allowedFileExtensions && !this.options.allowedFileExtensions.includes(originalExtension)) {
|
|
345
352
|
return {
|
|
346
353
|
error: `File extension "${originalExtension}" is not allowed, allowed extensions are: ${this.options.allowedFileExtensions.join(', ')}`
|
|
347
354
|
};
|
|
348
355
|
}
|
|
349
|
-
|
|
356
|
+
let record = undefined;
|
|
357
|
+
if (recordPk) {
|
|
358
|
+
// get record by recordPk
|
|
359
|
+
const pkName = (_b = this.resourceConfig.columns.find((column) => column.primaryKey)) === null || _b === void 0 ? void 0 : _b.name;
|
|
360
|
+
record = yield this.adminforth.resource(this.resourceConfig.resourceId).get([Filters.EQ(pkName, recordPk)]);
|
|
361
|
+
}
|
|
362
|
+
const s3Path = this.options.s3Path({ originalFilename, originalExtension, contentType, record });
|
|
350
363
|
if (s3Path.startsWith('/')) {
|
|
351
364
|
throw new Error('s3Path should not start with /, please adjust s3path function to not return / at the start of the path');
|
|
352
365
|
}
|
|
@@ -370,7 +383,7 @@ export default class UploadPlugin extends AdminForthPlugin {
|
|
|
370
383
|
unhoistableHeaders: new Set(['x-amz-tagging']),
|
|
371
384
|
});
|
|
372
385
|
let previewUrl;
|
|
373
|
-
if ((
|
|
386
|
+
if ((_c = this.options.preview) === null || _c === void 0 ? void 0 : _c.previewUrl) {
|
|
374
387
|
previewUrl = this.options.preview.previewUrl({ s3Path });
|
|
375
388
|
}
|
|
376
389
|
else if (this.options.s3ACL === 'public-read') {
|
|
@@ -411,15 +424,15 @@ export default class UploadPlugin extends AdminForthPlugin {
|
|
|
411
424
|
server.endpoint({
|
|
412
425
|
method: 'POST',
|
|
413
426
|
path: `/plugin/${this.pluginInstanceId}/generate_images`,
|
|
414
|
-
handler: (
|
|
415
|
-
var
|
|
427
|
+
handler: (_d) => __awaiter(this, [_d], void 0, function* ({ body, headers }) {
|
|
428
|
+
var _e, _f;
|
|
416
429
|
const { prompt } = body;
|
|
417
430
|
if (this.options.generation.provider !== 'openai-dall-e') {
|
|
418
431
|
throw new Error(`Provider ${this.options.generation.provider} is not supported`);
|
|
419
432
|
}
|
|
420
|
-
if ((
|
|
433
|
+
if ((_e = this.options.generation.rateLimit) === null || _e === void 0 ? void 0 : _e.limit) {
|
|
421
434
|
// rate limit
|
|
422
|
-
const { error } = RateLimiter.checkRateLimit(this.pluginInstanceId, (
|
|
435
|
+
const { error } = RateLimiter.checkRateLimit(this.pluginInstanceId, (_f = this.options.generation.rateLimit) === null || _f === void 0 ? void 0 : _f.limit, this.adminforth.auth.getClientIp(headers));
|
|
423
436
|
if (error) {
|
|
424
437
|
return { error: this.options.generation.rateLimit.errorMessage };
|
|
425
438
|
}
|
|
@@ -455,7 +468,7 @@ export default class UploadPlugin extends AdminForthPlugin {
|
|
|
455
468
|
server.endpoint({
|
|
456
469
|
method: 'GET',
|
|
457
470
|
path: `/plugin/${this.pluginInstanceId}/cors-proxy`,
|
|
458
|
-
handler: (
|
|
471
|
+
handler: (_g) => __awaiter(this, [_g], void 0, function* ({ query, response }) {
|
|
459
472
|
const { url } = query;
|
|
460
473
|
const resp = yield fetch(url);
|
|
461
474
|
response.setHeader('Content-Type', resp.headers.get('Content-Type'));
|
package/index.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { PluginOptions } from './types.js';
|
|
3
3
|
import { getSignedUrl } from '@aws-sdk/s3-request-presigner';
|
|
4
4
|
import { ExpirationStatus, GetObjectCommand, ObjectCannedACL, PutObjectCommand, S3 } from '@aws-sdk/client-s3';
|
|
5
|
-
import { AdminForthPlugin, AdminForthResourceColumn,
|
|
5
|
+
import { AdminForthPlugin, AdminForthResourceColumn, AdminForthResource, Filters, IAdminForth, IHttpServer, suggestIfTypo } from "adminforth";
|
|
6
6
|
import { Readable } from "stream";
|
|
7
7
|
import { RateLimiter } from "adminforth";
|
|
8
8
|
|
|
@@ -25,14 +25,20 @@ export default class UploadPlugin extends AdminForthPlugin {
|
|
|
25
25
|
async setupLifecycleRule() {
|
|
26
26
|
// check that lifecyle rule "adminforth-unused-cleaner" exists
|
|
27
27
|
const CLEANUP_RULE_ID = 'adminforth-unused-cleaner';
|
|
28
|
-
const s3 = new S3({
|
|
29
|
-
credentials: {
|
|
30
|
-
accessKeyId: this.options.s3AccessKeyId,
|
|
31
|
-
secretAccessKey: this.options.s3SecretAccessKey,
|
|
32
|
-
},
|
|
33
28
|
|
|
34
|
-
|
|
35
|
-
|
|
29
|
+
let s3;
|
|
30
|
+
try {
|
|
31
|
+
s3 = new S3({
|
|
32
|
+
credentials: {
|
|
33
|
+
accessKeyId: this.options.s3AccessKeyId,
|
|
34
|
+
secretAccessKey: this.options.s3SecretAccessKey,
|
|
35
|
+
},
|
|
36
|
+
region: this.options.s3Region,
|
|
37
|
+
});
|
|
38
|
+
} catch (e) {
|
|
39
|
+
console.error('Unable to connect to S3. Upload will not work. Skipping setup of lifecycle rule', e);
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
36
42
|
// check bucket exists
|
|
37
43
|
const bucketExists = s3.headBucket({ Bucket: this.options.s3Bucket })
|
|
38
44
|
if (!bucketExists) {
|
|
@@ -94,7 +100,7 @@ export default class UploadPlugin extends AdminForthPlugin {
|
|
|
94
100
|
record[`previewUrl_${this.pluginInstanceId}`] = previewUrl;
|
|
95
101
|
}
|
|
96
102
|
|
|
97
|
-
async modifyResourceConfig(adminforth: IAdminForth, resourceConfig:
|
|
103
|
+
async modifyResourceConfig(adminforth: IAdminForth, resourceConfig: AdminForthResource) {
|
|
98
104
|
super.modifyResourceConfig(adminforth, resourceConfig);
|
|
99
105
|
// after column to store the path of the uploaded file, add new VirtualColumn,
|
|
100
106
|
// show only in edit and create views
|
|
@@ -102,7 +108,7 @@ export default class UploadPlugin extends AdminForthPlugin {
|
|
|
102
108
|
const { pathColumnName } = this.options;
|
|
103
109
|
const pathColumnIndex = resourceConfig.columns.findIndex((column: any) => column.name === pathColumnName);
|
|
104
110
|
if (pathColumnIndex === -1) {
|
|
105
|
-
throw new Error(`Column with name "${pathColumnName}" not found in resource "${resourceConfig.
|
|
111
|
+
throw new Error(`Column with name "${pathColumnName}" not found in resource "${resourceConfig.label}"`);
|
|
106
112
|
}
|
|
107
113
|
|
|
108
114
|
if (this.options.generation?.fieldsForContext) {
|
|
@@ -315,9 +321,9 @@ export default class UploadPlugin extends AdminForthPlugin {
|
|
|
315
321
|
|
|
316
322
|
|
|
317
323
|
// add edit postSave hook to delete old file and remove tag from new file
|
|
318
|
-
resourceConfig.hooks.edit.afterSave.push(async ({
|
|
324
|
+
resourceConfig.hooks.edit.afterSave.push(async ({ updates, oldRecord }: { updates: any, oldRecord: any }) => {
|
|
319
325
|
|
|
320
|
-
if (
|
|
326
|
+
if (updates[virtualColumn.name] || updates[virtualColumn.name] === null) {
|
|
321
327
|
const s3 = new S3({
|
|
322
328
|
credentials: {
|
|
323
329
|
accessKeyId: this.options.s3AccessKeyId,
|
|
@@ -347,12 +353,12 @@ export default class UploadPlugin extends AdminForthPlugin {
|
|
|
347
353
|
console.error(`Error setting tag ${ADMINFORTH_NOT_YET_USED_TAG} to true for object ${oldRecord[pathColumnName]}. File will not be auto-cleaned up`, e);
|
|
348
354
|
}
|
|
349
355
|
}
|
|
350
|
-
if (
|
|
356
|
+
if (updates[virtualColumn.name] !== null) {
|
|
351
357
|
// remove tag from new file
|
|
352
358
|
// in this case we let it crash if it fails: this is a new file which just was uploaded.
|
|
353
359
|
await s3.putObjectTagging({
|
|
354
360
|
Bucket: this.options.s3Bucket,
|
|
355
|
-
Key:
|
|
361
|
+
Key: updates[pathColumnName],
|
|
356
362
|
Tagging: {
|
|
357
363
|
TagSet: []
|
|
358
364
|
}
|
|
@@ -376,7 +382,7 @@ export default class UploadPlugin extends AdminForthPlugin {
|
|
|
376
382
|
method: 'POST',
|
|
377
383
|
path: `/plugin/${this.pluginInstanceId}/get_s3_upload_url`,
|
|
378
384
|
handler: async ({ body }) => {
|
|
379
|
-
const { originalFilename, contentType, size, originalExtension } = body;
|
|
385
|
+
const { originalFilename, contentType, size, originalExtension, recordPk } = body;
|
|
380
386
|
|
|
381
387
|
if (this.options.allowedFileExtensions && !this.options.allowedFileExtensions.includes(originalExtension)) {
|
|
382
388
|
return {
|
|
@@ -384,7 +390,16 @@ export default class UploadPlugin extends AdminForthPlugin {
|
|
|
384
390
|
};
|
|
385
391
|
}
|
|
386
392
|
|
|
387
|
-
|
|
393
|
+
let record = undefined;
|
|
394
|
+
if (recordPk) {
|
|
395
|
+
// get record by recordPk
|
|
396
|
+
const pkName = this.resourceConfig.columns.find((column: any) => column.primaryKey)?.name;
|
|
397
|
+
record = await this.adminforth.resource(this.resourceConfig.resourceId).get(
|
|
398
|
+
[Filters.EQ(pkName, recordPk)]
|
|
399
|
+
)
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
const s3Path: string = this.options.s3Path({ originalFilename, originalExtension, contentType, record });
|
|
388
403
|
if (s3Path.startsWith('/')) {
|
|
389
404
|
throw new Error('s3Path should not start with /, please adjust s3path function to not return / at the start of the path');
|
|
390
405
|
}
|
package/package.json
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adminforth/upload",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.31-next.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
7
|
"scripts": {
|
|
8
8
|
"rollout": "tsc && rsync -av --exclude 'node_modules' custom dist/ && npm version patch && npm publish --access public",
|
|
9
9
|
"prepare": "npm link adminforth",
|
|
10
|
+
"rollout-next": "npm run build && npm version prerelease --preid=next && npm publish --tag next",
|
|
10
11
|
"build": "tsc"
|
|
11
12
|
},
|
|
12
13
|
"type": "module",
|
package/types.ts
CHANGED
|
@@ -50,11 +50,16 @@ export type PluginOptions = {
|
|
|
50
50
|
* example:
|
|
51
51
|
*
|
|
52
52
|
* ```typescript
|
|
53
|
-
* s3Path: ({
|
|
53
|
+
* s3Path: ({originalFilename}) => `/aparts/${originalFilename}`
|
|
54
54
|
* ```
|
|
55
55
|
*
|
|
56
56
|
*/
|
|
57
|
-
s3Path: ({originalFilename, originalExtension, contentType}
|
|
57
|
+
s3Path: ({originalFilename, originalExtension, contentType, record }: {
|
|
58
|
+
originalFilename: string,
|
|
59
|
+
originalExtension: string,
|
|
60
|
+
contentType: string,
|
|
61
|
+
record?: any,
|
|
62
|
+
}) => string,
|
|
58
63
|
|
|
59
64
|
|
|
60
65
|
preview: {
|