Skip to content

Commit bc2a394

Browse files
authored
Merge branch 'main' into AdminForth/802
2 parents 7348aa5 + d0dfb0c commit bc2a394

File tree

5 files changed

+101
-72
lines changed

5 files changed

+101
-72
lines changed

custom/tsconfig.json

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,14 @@
11
{
22
"compilerOptions": {
3-
"baseUrl": ".", // This should point to your project root
3+
"baseUrl": ".",
44
"paths": {
55
"@/*": [
6-
// "node_modules/adminforth/dist/spa/src/*"
76
"../../../adminforth/spa/src/*"
87
],
98
"*": [
10-
// "node_modules/adminforth/dist/spa/node_modules/*"
119
"../../../adminforth/spa/node_modules/*"
1210
],
1311
"@@/*": [
14-
// "node_modules/adminforth/dist/spa/src/*"
1512
"."
1613
]
1714
}

custom/uploader.vue

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,8 @@ const progress = ref(0);
103103
const uploaded = ref(false);
104104
const uploadedSize = ref(0);
105105
106+
const downloadFileUrl = ref('');
107+
106108
watch(() => uploaded, (value) => {
107109
emit('update:emptiness', !value);
108110
});
@@ -118,9 +120,50 @@ function uploadGeneratedImage(imgBlob) {
118120
});
119121
}
120122
121-
onMounted(() => {
123+
onMounted(async () => {
122124
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]) {
124167
imgPreview.value = props.record[previewColumnName];
125168
uploaded.value = true;
126169
emit('update:emptiness', false);

index.ts

Lines changed: 50 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import { AdminForthPlugin, AdminForthResourceColumn, AdminForthResource, Filters
44
import { Readable } from "stream";
55
import { RateLimiter } from "adminforth";
66
import { randomUUID } from "crypto";
7+
import { interpretResource } from 'adminforth';
8+
import { ActionCheckSource } from 'adminforth';
79

810
const ADMINFORTH_NOT_YET_USED_TAG = 'adminforth-candidate-for-cleanup';
911
const jobs = new Map();
@@ -164,32 +166,11 @@ export default class UploadPlugin extends AdminForthPlugin {
164166
minShowWidth: this.options.preview?.minShowWidth,
165167
generationPrompt: this.options.generation?.generationPrompt,
166168
recorPkFieldName: this.resourceConfig.columns.find((column: any) => column.primaryKey)?.name,
169+
pathColumnName: this.options.pathColumnName,
167170
};
168171
// define components which will be imported from other components
169172
this.componentPath('imageGenerator.vue');
170173

171-
const virtualColumn: AdminForthResourceColumn = {
172-
virtual: true,
173-
name: `uploader_${this.pluginInstanceId}`,
174-
components: {
175-
edit: {
176-
file: this.componentPath('uploader.vue'),
177-
meta: pluginFrontendOptions,
178-
},
179-
create: {
180-
file: this.componentPath('uploader.vue'),
181-
meta: pluginFrontendOptions,
182-
},
183-
},
184-
showIn: {
185-
create: true,
186-
edit: true,
187-
list: false,
188-
show: false,
189-
filter: false,
190-
},
191-
};
192-
193174
if (!resourceConfig.columns[pathColumnIndex].components) {
194175
resourceConfig.columns[pathColumnIndex].components = {};
195176
}
@@ -208,38 +189,18 @@ export default class UploadPlugin extends AdminForthPlugin {
208189
};
209190
}
210191

211-
// insert virtual column after path column if it is not already there
212-
const virtualColumnIndex = resourceConfig.columns.findIndex((column: any) => column.name === virtualColumn.name);
213-
if (virtualColumnIndex === -1) {
214-
resourceConfig.columns.splice(pathColumnIndex + 1, 0, virtualColumn);
215-
}
216-
217-
218-
// if showIn of path column has 'create' or 'edit' remove it but use it for virtual column
219-
if (pathColumn.showIn && (pathColumn.showIn.create !== undefined)) {
220-
virtualColumn.showIn = { ...virtualColumn.showIn, create: pathColumn.showIn.create };
221-
pathColumn.showIn = { ...pathColumn.showIn, create: false };
192+
resourceConfig.columns[pathColumnIndex].components.create = {
193+
file: this.componentPath('uploader.vue'),
194+
meta: pluginFrontendOptions,
222195
}
223196

224-
if (pathColumn.showIn && (pathColumn.showIn.edit !== undefined)) {
225-
virtualColumn.showIn = { ...virtualColumn.showIn, edit: pathColumn.showIn.edit };
226-
pathColumn.showIn = { ...pathColumn.showIn, edit: false };
197+
resourceConfig.columns[pathColumnIndex].components.edit = {
198+
file: this.componentPath('uploader.vue'),
199+
meta: pluginFrontendOptions,
227200
}
228201

229-
virtualColumn.required = pathColumn.required;
230-
virtualColumn.label = pathColumn.label;
231-
virtualColumn.editingNote = pathColumn.editingNote;
232-
233202
// ** HOOKS FOR CREATE **//
234203

235-
// add beforeSave hook to save virtual column to path column
236-
resourceConfig.hooks.create.beforeSave.push(async ({ record }: { record: any }) => {
237-
if (record[virtualColumn.name]) {
238-
record[pathColumnName] = record[virtualColumn.name];
239-
delete record[virtualColumn.name];
240-
}
241-
return { ok: true };
242-
});
243204

244205
// in afterSave hook, aremove tag adminforth-not-yet-used from the file
245206
resourceConfig.hooks.create.afterSave.push(async ({ record }: { record: any }) => {
@@ -248,7 +209,11 @@ export default class UploadPlugin extends AdminForthPlugin {
248209
if (record[pathColumnName]) {
249210
process.env.HEAVY_DEBUG && console.log('🪥🪥 remove ObjectTagging', record[pathColumnName]);
250211
// let it crash if it fails: this is a new file which just was uploaded.
251-
await this.options.storageAdapter.markKeyForNotDeletation(record[pathColumnName]);
212+
if (this.options.storageAdapter.markKeyForNotDeletion !== undefined) {
213+
await this.options.storageAdapter.markKeyForNotDeletion(record[pathColumnName]);
214+
} else {
215+
await this.options.storageAdapter.markKeyForNotDeletation(record[pathColumnName]);
216+
}
252217
}
253218
return { ok: true };
254219
});
@@ -291,7 +256,11 @@ export default class UploadPlugin extends AdminForthPlugin {
291256
resourceConfig.hooks.delete.afterSave.push(async ({ record }: { record: any }) => {
292257
if (record[pathColumnName]) {
293258
try {
294-
await this.options.storageAdapter.markKeyForDeletation(record[pathColumnName]);
259+
if (this.options.storageAdapter.markKeyForDeletion !== undefined) {
260+
await this.options.storageAdapter.markKeyForDeletion(record[pathColumnName]);
261+
} else {
262+
await this.options.storageAdapter.markKeyForDeletation(record[pathColumnName]);
263+
}
295264
} catch (e) {
296265
// file might be e.g. already deleted, so we catch error
297266
console.error(`Error setting tag ${ADMINFORTH_NOT_YET_USED_TAG} to true for object ${record[pathColumnName]}. File will not be auto-cleaned up`, e);
@@ -303,34 +272,34 @@ export default class UploadPlugin extends AdminForthPlugin {
303272

304273
// ** HOOKS FOR EDIT **//
305274

306-
// beforeSave
307-
resourceConfig.hooks.edit.beforeSave.push(async ({ record }: { record: any }) => {
308-
// null is when value is removed
309-
if (record[virtualColumn.name] || record[virtualColumn.name] === null) {
310-
record[pathColumnName] = record[virtualColumn.name];
311-
}
312-
return { ok: true };
313-
})
314275

315276

316277
// add edit postSave hook to delete old file and remove tag from new file
317278
resourceConfig.hooks.edit.afterSave.push(async ({ updates, oldRecord }: { updates: any, oldRecord: any }) => {
318279

319-
if (updates[virtualColumn.name] || updates[virtualColumn.name] === null) {
280+
if (updates[pathColumnName] || updates[pathColumnName] === null) {
320281
if (oldRecord[pathColumnName]) {
321282
// put tag to delete old file
322283
try {
323-
await this.options.storageAdapter.markKeyForDeletation(oldRecord[pathColumnName]);
284+
if (this.options.storageAdapter.markKeyForDeletion !== undefined) {
285+
await this.options.storageAdapter.markKeyForDeletion(oldRecord[pathColumnName]);
286+
} else {
287+
await this.options.storageAdapter.markKeyForDeletation(oldRecord[pathColumnName]);
288+
}
324289
} catch (e) {
325290
// file might be e.g. already deleted, so we catch error
326291
console.error(`Error setting tag ${ADMINFORTH_NOT_YET_USED_TAG} to true for object ${oldRecord[pathColumnName]}. File will not be auto-cleaned up`, e);
327292
}
328293
}
329-
if (updates[virtualColumn.name] !== null) {
294+
if (updates[pathColumnName] !== null) {
330295
// remove tag from new file
331296
// in this case we let it crash if it fails: this is a new file which just was uploaded.
297+
if (this.options.storageAdapter.markKeyForNotDeletion !== undefined) {
298+
await this.options.storageAdapter.markKeyForNotDeletion(updates[pathColumnName]);
299+
} else {
332300
await this.options.storageAdapter.markKeyForNotDeletation(updates[pathColumnName]);
333301
}
302+
}
334303
}
335304
return { ok: true };
336305
});
@@ -492,6 +461,26 @@ export default class UploadPlugin extends AdminForthPlugin {
492461
},
493462
});
494463

464+
server.endpoint({
465+
method: 'POST',
466+
path: `/plugin/${this.pluginInstanceId}/get-file-download-url`,
467+
handler: async ({ body, adminUser }) => {
468+
const { filePath } = body;
469+
if (!filePath) {
470+
return { error: 'Missing filePath' };
471+
}
472+
const allowedActions = await interpretResource( adminUser, this.resourceConfig, '', ActionCheckSource.CustomActionRequest, this.adminforth )
473+
if (allowedActions.allowedActions.create === true || allowedActions.allowedActions.edit === true) {
474+
const url = await this.options.storageAdapter.getDownloadUrl(filePath, 1800);
475+
476+
return {
477+
url,
478+
};
479+
}
480+
return { error: 'You do not have permission to download this file' };
481+
},
482+
});
483+
495484
}
496485

497486

package-lock.json

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
"dependencies": {
2323
"@aws-sdk/client-s3": "^3.629.0",
2424
"@aws-sdk/s3-request-presigner": "^3.629.0",
25-
"adminforth": "^2.4.0-next.237"
25+
"adminforth": "^2.13.0-next.51"
2626
},
2727
"keywords": [
2828
"adminforth",

0 commit comments

Comments
 (0)