@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 CHANGED
@@ -11,5 +11,5 @@ custom/preview.vue
11
11
  custom/tsconfig.json
12
12
  custom/uploader.vue
13
13
 
14
- sent 47,144 bytes received 134 bytes 94,556.00 bytes/sec
15
- total size is 46,662 speedup is 0.99
14
+ sent 48,314 bytes received 134 bytes 96,896.00 bytes/sec
15
+ total size is 47,825 speedup is 0.99
@@ -1,17 +1,14 @@
1
1
  {
2
2
  "compilerOptions": {
3
- "baseUrl": ".", // This should point to your project root
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
  }
@@ -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
- if (props.record[previewColumnName]) {
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": ".", // This should point to your project root
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
  }
@@ -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
- if (props.record[previewColumnName]) {
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
- yield this.options.storageAdapter.markKeyForNotDeletation(record[pathColumnName]);
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
- yield this.options.storageAdapter.markKeyForDeletation(record[pathColumnName]);
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
- yield this.options.storageAdapter.markKeyForDeletation(oldRecord[pathColumnName]);
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
- yield this.options.storageAdapter.markKeyForNotDeletation(updates[pathColumnName]);
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
- await this.options.storageAdapter.markKeyForNotDeletation(record[pathColumnName]);
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
- await this.options.storageAdapter.markKeyForDeletation(record[pathColumnName]);
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
- await this.options.storageAdapter.markKeyForDeletation(oldRecord[pathColumnName]);
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.7",
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.237"
25
+ "adminforth": "^2.4.0-next.315"
26
26
  },
27
27
  "keywords": [
28
28
  "adminforth",