@adminforth/upload 2.3.7 → 2.4.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/build.log +2 -2
- package/custom/tsconfig.json +1 -4
- package/custom/uploader.vue +45 -2
- package/dist/custom/tsconfig.json +1 -4
- package/dist/custom/uploader.vue +45 -2
- package/dist/index.js +45 -4
- package/index.ts +42 -3
- package/package.json +2 -2
package/build.log
CHANGED
|
@@ -11,5 +11,5 @@ custom/preview.vue
|
|
|
11
11
|
custom/tsconfig.json
|
|
12
12
|
custom/uploader.vue
|
|
13
13
|
|
|
14
|
-
sent
|
|
15
|
-
total size is
|
|
14
|
+
sent 48,314 bytes received 134 bytes 96,896.00 bytes/sec
|
|
15
|
+
total size is 47,825 speedup is 0.99
|
package/custom/tsconfig.json
CHANGED
|
@@ -1,17 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"compilerOptions": {
|
|
3
|
-
"baseUrl": ".",
|
|
3
|
+
"baseUrl": ".",
|
|
4
4
|
"paths": {
|
|
5
5
|
"@/*": [
|
|
6
|
-
// "node_modules/adminforth/dist/spa/src/*"
|
|
7
6
|
"../../../adminforth/spa/src/*"
|
|
8
7
|
],
|
|
9
8
|
"*": [
|
|
10
|
-
// "node_modules/adminforth/dist/spa/node_modules/*"
|
|
11
9
|
"../../../adminforth/spa/node_modules/*"
|
|
12
10
|
],
|
|
13
11
|
"@@/*": [
|
|
14
|
-
// "node_modules/adminforth/dist/spa/src/*"
|
|
15
12
|
"."
|
|
16
13
|
]
|
|
17
14
|
}
|
package/custom/uploader.vue
CHANGED
|
@@ -103,6 +103,8 @@ const progress = ref(0);
|
|
|
103
103
|
const uploaded = ref(false);
|
|
104
104
|
const uploadedSize = ref(0);
|
|
105
105
|
|
|
106
|
+
const downloadFileUrl = ref('');
|
|
107
|
+
|
|
106
108
|
watch(() => uploaded, (value) => {
|
|
107
109
|
emit('update:emptiness', !value);
|
|
108
110
|
});
|
|
@@ -118,9 +120,50 @@ function uploadGeneratedImage(imgBlob) {
|
|
|
118
120
|
});
|
|
119
121
|
}
|
|
120
122
|
|
|
121
|
-
onMounted(() => {
|
|
123
|
+
onMounted(async () => {
|
|
122
124
|
const previewColumnName = `previewUrl_${props.meta.pluginInstanceId}`;
|
|
123
|
-
|
|
125
|
+
let queryValues;
|
|
126
|
+
try {
|
|
127
|
+
queryValues = JSON.parse(atob(route.query.values as string));
|
|
128
|
+
} catch (e) {
|
|
129
|
+
queryValues = {};
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
if (queryValues[props.meta.pathColumnName]) {
|
|
133
|
+
downloadFileUrl.value = queryValues[props.meta.pathColumnName];
|
|
134
|
+
|
|
135
|
+
const resp = await callAdminForthApi({
|
|
136
|
+
path: `/plugin/${props.meta.pluginInstanceId}/get-file-download-url`,
|
|
137
|
+
method: 'POST',
|
|
138
|
+
body: {
|
|
139
|
+
filePath: queryValues[props.meta.pathColumnName]
|
|
140
|
+
},
|
|
141
|
+
});
|
|
142
|
+
if (resp.error) {
|
|
143
|
+
adminforth.alert({
|
|
144
|
+
message: t('Error getting file url for field {field}:', { field: props.meta.pathColumnName }),
|
|
145
|
+
variant: 'danger'
|
|
146
|
+
});
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
const filename = resp.url.split('/').pop()?.split('?')[0] || `file`;
|
|
150
|
+
const filenameParts = filename.split('.');
|
|
151
|
+
const extension = filenameParts.length > 1 ? filenameParts.pop() : '';
|
|
152
|
+
const nameWithoutExt = filenameParts.join('.');
|
|
153
|
+
const newFileName = extension
|
|
154
|
+
? `${nameWithoutExt}_copy_${Date.now()}.${extension}`
|
|
155
|
+
: `${filename}_copy_${Date.now()}`;
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
const res = await fetch(resp.url);
|
|
159
|
+
const fileBlob = await res.blob();
|
|
160
|
+
const file = new File([fileBlob], newFileName, { type: fileBlob.type });
|
|
161
|
+
onFileChange({
|
|
162
|
+
target: {
|
|
163
|
+
files: [file],
|
|
164
|
+
},
|
|
165
|
+
});
|
|
166
|
+
} else if (props.record[previewColumnName]) {
|
|
124
167
|
imgPreview.value = props.record[previewColumnName];
|
|
125
168
|
uploaded.value = true;
|
|
126
169
|
emit('update:emptiness', false);
|
|
@@ -1,17 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"compilerOptions": {
|
|
3
|
-
"baseUrl": ".",
|
|
3
|
+
"baseUrl": ".",
|
|
4
4
|
"paths": {
|
|
5
5
|
"@/*": [
|
|
6
|
-
// "node_modules/adminforth/dist/spa/src/*"
|
|
7
6
|
"../../../adminforth/spa/src/*"
|
|
8
7
|
],
|
|
9
8
|
"*": [
|
|
10
|
-
// "node_modules/adminforth/dist/spa/node_modules/*"
|
|
11
9
|
"../../../adminforth/spa/node_modules/*"
|
|
12
10
|
],
|
|
13
11
|
"@@/*": [
|
|
14
|
-
// "node_modules/adminforth/dist/spa/src/*"
|
|
15
12
|
"."
|
|
16
13
|
]
|
|
17
14
|
}
|
package/dist/custom/uploader.vue
CHANGED
|
@@ -103,6 +103,8 @@ const progress = ref(0);
|
|
|
103
103
|
const uploaded = ref(false);
|
|
104
104
|
const uploadedSize = ref(0);
|
|
105
105
|
|
|
106
|
+
const downloadFileUrl = ref('');
|
|
107
|
+
|
|
106
108
|
watch(() => uploaded, (value) => {
|
|
107
109
|
emit('update:emptiness', !value);
|
|
108
110
|
});
|
|
@@ -118,9 +120,50 @@ function uploadGeneratedImage(imgBlob) {
|
|
|
118
120
|
});
|
|
119
121
|
}
|
|
120
122
|
|
|
121
|
-
onMounted(() => {
|
|
123
|
+
onMounted(async () => {
|
|
122
124
|
const previewColumnName = `previewUrl_${props.meta.pluginInstanceId}`;
|
|
123
|
-
|
|
125
|
+
let queryValues;
|
|
126
|
+
try {
|
|
127
|
+
queryValues = JSON.parse(atob(route.query.values as string));
|
|
128
|
+
} catch (e) {
|
|
129
|
+
queryValues = {};
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
if (queryValues[props.meta.pathColumnName]) {
|
|
133
|
+
downloadFileUrl.value = queryValues[props.meta.pathColumnName];
|
|
134
|
+
|
|
135
|
+
const resp = await callAdminForthApi({
|
|
136
|
+
path: `/plugin/${props.meta.pluginInstanceId}/get-file-download-url`,
|
|
137
|
+
method: 'POST',
|
|
138
|
+
body: {
|
|
139
|
+
filePath: queryValues[props.meta.pathColumnName]
|
|
140
|
+
},
|
|
141
|
+
});
|
|
142
|
+
if (resp.error) {
|
|
143
|
+
adminforth.alert({
|
|
144
|
+
message: t('Error getting file url for field {field}:', { field: props.meta.pathColumnName }),
|
|
145
|
+
variant: 'danger'
|
|
146
|
+
});
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
const filename = resp.url.split('/').pop()?.split('?')[0] || `file`;
|
|
150
|
+
const filenameParts = filename.split('.');
|
|
151
|
+
const extension = filenameParts.length > 1 ? filenameParts.pop() : '';
|
|
152
|
+
const nameWithoutExt = filenameParts.join('.');
|
|
153
|
+
const newFileName = extension
|
|
154
|
+
? `${nameWithoutExt}_copy_${Date.now()}.${extension}`
|
|
155
|
+
: `${filename}_copy_${Date.now()}`;
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
const res = await fetch(resp.url);
|
|
159
|
+
const fileBlob = await res.blob();
|
|
160
|
+
const file = new File([fileBlob], newFileName, { type: fileBlob.type });
|
|
161
|
+
onFileChange({
|
|
162
|
+
target: {
|
|
163
|
+
files: [file],
|
|
164
|
+
},
|
|
165
|
+
});
|
|
166
|
+
} else if (props.record[previewColumnName]) {
|
|
124
167
|
imgPreview.value = props.record[previewColumnName];
|
|
125
168
|
uploaded.value = true;
|
|
126
169
|
emit('update:emptiness', false);
|
package/dist/index.js
CHANGED
|
@@ -10,6 +10,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
10
10
|
import { AdminForthPlugin, Filters, suggestIfTypo } from "adminforth";
|
|
11
11
|
import { Readable } from "stream";
|
|
12
12
|
import { RateLimiter } from "adminforth";
|
|
13
|
+
import { interpretResource } from 'adminforth';
|
|
14
|
+
import { ActionCheckSource } from 'adminforth';
|
|
13
15
|
const ADMINFORTH_NOT_YET_USED_TAG = 'adminforth-candidate-for-cleanup';
|
|
14
16
|
export default class UploadPlugin extends AdminForthPlugin {
|
|
15
17
|
constructor(options) {
|
|
@@ -83,6 +85,7 @@ export default class UploadPlugin extends AdminForthPlugin {
|
|
|
83
85
|
minShowWidth: (_h = this.options.preview) === null || _h === void 0 ? void 0 : _h.minShowWidth,
|
|
84
86
|
generationPrompt: (_j = this.options.generation) === null || _j === void 0 ? void 0 : _j.generationPrompt,
|
|
85
87
|
recorPkFieldName: (_k = this.resourceConfig.columns.find((column) => column.primaryKey)) === null || _k === void 0 ? void 0 : _k.name,
|
|
88
|
+
pathColumnName: this.options.pathColumnName,
|
|
86
89
|
};
|
|
87
90
|
// define components which will be imported from other components
|
|
88
91
|
this.componentPath('imageGenerator.vue');
|
|
@@ -116,7 +119,12 @@ export default class UploadPlugin extends AdminForthPlugin {
|
|
|
116
119
|
if (record[pathColumnName]) {
|
|
117
120
|
process.env.HEAVY_DEBUG && console.log('🪥🪥 remove ObjectTagging', record[pathColumnName]);
|
|
118
121
|
// let it crash if it fails: this is a new file which just was uploaded.
|
|
119
|
-
|
|
122
|
+
if (this.options.storageAdapter.markKeyForNotDeletion !== undefined) {
|
|
123
|
+
yield this.options.storageAdapter.markKeyForNotDeletion(record[pathColumnName]);
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
yield this.options.storageAdapter.markKeyForNotDeletation(record[pathColumnName]);
|
|
127
|
+
}
|
|
120
128
|
}
|
|
121
129
|
return { ok: true };
|
|
122
130
|
}));
|
|
@@ -150,7 +158,12 @@ export default class UploadPlugin extends AdminForthPlugin {
|
|
|
150
158
|
resourceConfig.hooks.delete.afterSave.push((_a) => __awaiter(this, [_a], void 0, function* ({ record }) {
|
|
151
159
|
if (record[pathColumnName]) {
|
|
152
160
|
try {
|
|
153
|
-
|
|
161
|
+
if (this.options.storageAdapter.markKeyForDeletion !== undefined) {
|
|
162
|
+
yield this.options.storageAdapter.markKeyForDeletion(record[pathColumnName]);
|
|
163
|
+
}
|
|
164
|
+
else {
|
|
165
|
+
yield this.options.storageAdapter.markKeyForDeletation(record[pathColumnName]);
|
|
166
|
+
}
|
|
154
167
|
}
|
|
155
168
|
catch (e) {
|
|
156
169
|
// file might be e.g. already deleted, so we catch error
|
|
@@ -166,7 +179,12 @@ export default class UploadPlugin extends AdminForthPlugin {
|
|
|
166
179
|
if (oldRecord[pathColumnName]) {
|
|
167
180
|
// put tag to delete old file
|
|
168
181
|
try {
|
|
169
|
-
|
|
182
|
+
if (this.options.storageAdapter.markKeyForDeletion !== undefined) {
|
|
183
|
+
yield this.options.storageAdapter.markKeyForDeletion(oldRecord[pathColumnName]);
|
|
184
|
+
}
|
|
185
|
+
else {
|
|
186
|
+
yield this.options.storageAdapter.markKeyForDeletation(oldRecord[pathColumnName]);
|
|
187
|
+
}
|
|
170
188
|
}
|
|
171
189
|
catch (e) {
|
|
172
190
|
// file might be e.g. already deleted, so we catch error
|
|
@@ -176,7 +194,12 @@ export default class UploadPlugin extends AdminForthPlugin {
|
|
|
176
194
|
if (updates[pathColumnName] !== null) {
|
|
177
195
|
// remove tag from new file
|
|
178
196
|
// in this case we let it crash if it fails: this is a new file which just was uploaded.
|
|
179
|
-
|
|
197
|
+
if (this.options.storageAdapter.markKeyForNotDeletion !== undefined) {
|
|
198
|
+
yield this.options.storageAdapter.markKeyForNotDeletion(updates[pathColumnName]);
|
|
199
|
+
}
|
|
200
|
+
else {
|
|
201
|
+
yield this.options.storageAdapter.markKeyForNotDeletation(updates[pathColumnName]);
|
|
202
|
+
}
|
|
180
203
|
}
|
|
181
204
|
}
|
|
182
205
|
return { ok: true };
|
|
@@ -354,5 +377,23 @@ export default class UploadPlugin extends AdminForthPlugin {
|
|
|
354
377
|
};
|
|
355
378
|
}),
|
|
356
379
|
});
|
|
380
|
+
server.endpoint({
|
|
381
|
+
method: 'POST',
|
|
382
|
+
path: `/plugin/${this.pluginInstanceId}/get-file-download-url`,
|
|
383
|
+
handler: (_a) => __awaiter(this, [_a], void 0, function* ({ body, adminUser }) {
|
|
384
|
+
const { filePath } = body;
|
|
385
|
+
if (!filePath) {
|
|
386
|
+
return { error: 'Missing filePath' };
|
|
387
|
+
}
|
|
388
|
+
const allowedActions = yield interpretResource(adminUser, this.resourceConfig, '', ActionCheckSource.CustomActionRequest, this.adminforth);
|
|
389
|
+
if (allowedActions.allowedActions.create === true || allowedActions.allowedActions.edit === true) {
|
|
390
|
+
const url = yield this.options.storageAdapter.getDownloadUrl(filePath, 1800);
|
|
391
|
+
return {
|
|
392
|
+
url,
|
|
393
|
+
};
|
|
394
|
+
}
|
|
395
|
+
return { error: 'You do not have permission to download this file' };
|
|
396
|
+
}),
|
|
397
|
+
});
|
|
357
398
|
}
|
|
358
399
|
}
|
package/index.ts
CHANGED
|
@@ -3,6 +3,8 @@ import { PluginOptions } from './types.js';
|
|
|
3
3
|
import { AdminForthPlugin, AdminForthResourceColumn, AdminForthResource, Filters, IAdminForth, IHttpServer, suggestIfTypo } from "adminforth";
|
|
4
4
|
import { Readable } from "stream";
|
|
5
5
|
import { RateLimiter } from "adminforth";
|
|
6
|
+
import { interpretResource } from 'adminforth';
|
|
7
|
+
import { ActionCheckSource } from 'adminforth';
|
|
6
8
|
|
|
7
9
|
const ADMINFORTH_NOT_YET_USED_TAG = 'adminforth-candidate-for-cleanup';
|
|
8
10
|
|
|
@@ -86,6 +88,7 @@ export default class UploadPlugin extends AdminForthPlugin {
|
|
|
86
88
|
minShowWidth: this.options.preview?.minShowWidth,
|
|
87
89
|
generationPrompt: this.options.generation?.generationPrompt,
|
|
88
90
|
recorPkFieldName: this.resourceConfig.columns.find((column: any) => column.primaryKey)?.name,
|
|
91
|
+
pathColumnName: this.options.pathColumnName,
|
|
89
92
|
};
|
|
90
93
|
// define components which will be imported from other components
|
|
91
94
|
this.componentPath('imageGenerator.vue');
|
|
@@ -128,7 +131,11 @@ export default class UploadPlugin extends AdminForthPlugin {
|
|
|
128
131
|
if (record[pathColumnName]) {
|
|
129
132
|
process.env.HEAVY_DEBUG && console.log('🪥🪥 remove ObjectTagging', record[pathColumnName]);
|
|
130
133
|
// let it crash if it fails: this is a new file which just was uploaded.
|
|
131
|
-
|
|
134
|
+
if (this.options.storageAdapter.markKeyForNotDeletion !== undefined) {
|
|
135
|
+
await this.options.storageAdapter.markKeyForNotDeletion(record[pathColumnName]);
|
|
136
|
+
} else {
|
|
137
|
+
await this.options.storageAdapter.markKeyForNotDeletation(record[pathColumnName]);
|
|
138
|
+
}
|
|
132
139
|
}
|
|
133
140
|
return { ok: true };
|
|
134
141
|
});
|
|
@@ -171,7 +178,11 @@ export default class UploadPlugin extends AdminForthPlugin {
|
|
|
171
178
|
resourceConfig.hooks.delete.afterSave.push(async ({ record }: { record: any }) => {
|
|
172
179
|
if (record[pathColumnName]) {
|
|
173
180
|
try {
|
|
174
|
-
|
|
181
|
+
if (this.options.storageAdapter.markKeyForDeletion !== undefined) {
|
|
182
|
+
await this.options.storageAdapter.markKeyForDeletion(record[pathColumnName]);
|
|
183
|
+
} else {
|
|
184
|
+
await this.options.storageAdapter.markKeyForDeletation(record[pathColumnName]);
|
|
185
|
+
}
|
|
175
186
|
} catch (e) {
|
|
176
187
|
// file might be e.g. already deleted, so we catch error
|
|
177
188
|
console.error(`Error setting tag ${ADMINFORTH_NOT_YET_USED_TAG} to true for object ${record[pathColumnName]}. File will not be auto-cleaned up`, e);
|
|
@@ -192,7 +203,11 @@ export default class UploadPlugin extends AdminForthPlugin {
|
|
|
192
203
|
if (oldRecord[pathColumnName]) {
|
|
193
204
|
// put tag to delete old file
|
|
194
205
|
try {
|
|
195
|
-
|
|
206
|
+
if (this.options.storageAdapter.markKeyForDeletion !== undefined) {
|
|
207
|
+
await this.options.storageAdapter.markKeyForDeletion(oldRecord[pathColumnName]);
|
|
208
|
+
} else {
|
|
209
|
+
await this.options.storageAdapter.markKeyForDeletation(oldRecord[pathColumnName]);
|
|
210
|
+
}
|
|
196
211
|
} catch (e) {
|
|
197
212
|
// file might be e.g. already deleted, so we catch error
|
|
198
213
|
console.error(`Error setting tag ${ADMINFORTH_NOT_YET_USED_TAG} to true for object ${oldRecord[pathColumnName]}. File will not be auto-cleaned up`, e);
|
|
@@ -201,8 +216,12 @@ export default class UploadPlugin extends AdminForthPlugin {
|
|
|
201
216
|
if (updates[pathColumnName] !== null) {
|
|
202
217
|
// remove tag from new file
|
|
203
218
|
// in this case we let it crash if it fails: this is a new file which just was uploaded.
|
|
219
|
+
if (this.options.storageAdapter.markKeyForNotDeletion !== undefined) {
|
|
220
|
+
await this.options.storageAdapter.markKeyForNotDeletion(updates[pathColumnName]);
|
|
221
|
+
} else {
|
|
204
222
|
await this.options.storageAdapter.markKeyForNotDeletation(updates[pathColumnName]);
|
|
205
223
|
}
|
|
224
|
+
}
|
|
206
225
|
}
|
|
207
226
|
return { ok: true };
|
|
208
227
|
});
|
|
@@ -411,6 +430,26 @@ export default class UploadPlugin extends AdminForthPlugin {
|
|
|
411
430
|
},
|
|
412
431
|
});
|
|
413
432
|
|
|
433
|
+
server.endpoint({
|
|
434
|
+
method: 'POST',
|
|
435
|
+
path: `/plugin/${this.pluginInstanceId}/get-file-download-url`,
|
|
436
|
+
handler: async ({ body, adminUser }) => {
|
|
437
|
+
const { filePath } = body;
|
|
438
|
+
if (!filePath) {
|
|
439
|
+
return { error: 'Missing filePath' };
|
|
440
|
+
}
|
|
441
|
+
const allowedActions = await interpretResource( adminUser, this.resourceConfig, '', ActionCheckSource.CustomActionRequest, this.adminforth )
|
|
442
|
+
if (allowedActions.allowedActions.create === true || allowedActions.allowedActions.edit === true) {
|
|
443
|
+
const url = await this.options.storageAdapter.getDownloadUrl(filePath, 1800);
|
|
444
|
+
|
|
445
|
+
return {
|
|
446
|
+
url,
|
|
447
|
+
};
|
|
448
|
+
}
|
|
449
|
+
return { error: 'You do not have permission to download this file' };
|
|
450
|
+
},
|
|
451
|
+
});
|
|
452
|
+
|
|
414
453
|
}
|
|
415
454
|
|
|
416
455
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adminforth/upload",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.4.0",
|
|
4
4
|
"description": "Plugin for uploading files for adminforth",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"dependencies": {
|
|
23
23
|
"@aws-sdk/client-s3": "^3.629.0",
|
|
24
24
|
"@aws-sdk/s3-request-presigner": "^3.629.0",
|
|
25
|
-
"adminforth": "^2.4.0-next.
|
|
25
|
+
"adminforth": "^2.4.0-next.315"
|
|
26
26
|
},
|
|
27
27
|
"keywords": [
|
|
28
28
|
"adminforth",
|