From e165242e5717eb2beadb9ee8e1a6a4e6de2a5442 Mon Sep 17 00:00:00 2001 From: Chirag Chhatrala <60499540+chiragchhatrala@users.noreply.github.com> Date: Wed, 26 Apr 2023 20:35:02 +0530 Subject: [PATCH] Editable submission File input support (#120) --- app/Http/Requests/AnswerFormRequest.php | 4 ++-- app/Jobs/Form/StoreFormSubmissionJob.php | 11 +++++++++++ app/Rules/StorageFile.php | 11 ++++++++++- resources/js/components/forms/FileInput.vue | 22 ++++++++++++++++++++- 4 files changed, 44 insertions(+), 4 deletions(-) diff --git a/app/Http/Requests/AnswerFormRequest.php b/app/Http/Requests/AnswerFormRequest.php index 436ea0a..b5bd53f 100644 --- a/app/Http/Requests/AnswerFormRequest.php +++ b/app/Http/Requests/AnswerFormRequest.php @@ -168,7 +168,7 @@ class AnswerFormRequest extends FormRequest return ['boolean']; case 'url': if (isset($property['file_upload']) && $property['file_upload']) { - $this->requestRules[$property['id'].'.*'] = [new StorageFile($this->maxFileSize)]; + $this->requestRules[$property['id'].'.*'] = [new StorageFile($this->maxFileSize, [], $this->form)]; return ['array']; } return ['url']; @@ -177,7 +177,7 @@ class AnswerFormRequest extends FormRequest if($this->form->is_pro && !empty($property['allowed_file_types'])){ $allowedFileTypes = explode(",", $property['allowed_file_types']); } - $this->requestRules[$property['id'].'.*'] = [new StorageFile($this->maxFileSize, $allowedFileTypes)]; + $this->requestRules[$property['id'].'.*'] = [new StorageFile($this->maxFileSize, $allowedFileTypes, $this->form)]; return ['array']; case 'email': return ['email:filter']; diff --git a/app/Jobs/Form/StoreFormSubmissionJob.php b/app/Jobs/Form/StoreFormSubmissionJob.php index f305360..aa9c992 100644 --- a/app/Jobs/Form/StoreFormSubmissionJob.php +++ b/app/Jobs/Form/StoreFormSubmissionJob.php @@ -136,6 +136,13 @@ class StoreFormSubmissionJob implements ShouldQueue return $finalData; } + // This is use when updating a record, and file uploads aren't changed. + private function isSkipForUpload($value) + { + $newPath = Str::of(PublicFormController::FILE_UPLOAD_PATH)->replace('?', $this->form->id); + return Storage::disk('s3')->exists($newPath.'/'.$value); + } + /** * Custom Back-end Value formatting. Use case: * - File uploads (move file from tmp storage to persistent) @@ -150,6 +157,10 @@ class StoreFormSubmissionJob implements ShouldQueue return null; } + if($this->isSkipForUpload($value)) { + return $value; + } + $fileNameParser = StorageFileNameParser::parse($value); // Make sure we retrieve the file in tmp storage, move it to persistent diff --git a/app/Rules/StorageFile.php b/app/Rules/StorageFile.php index fb64cf0..49e67a9 100644 --- a/app/Rules/StorageFile.php +++ b/app/Rules/StorageFile.php @@ -7,6 +7,7 @@ use App\Service\Storage\StorageFileNameParser; use Illuminate\Contracts\Validation\Rule; use Illuminate\Support\Facades\Storage; use Illuminate\Support\Str; +use App\Models\Forms\Form; class StorageFile implements Rule { @@ -21,7 +22,7 @@ class StorageFile implements Rule * @param int $maxSize * @param string[] $fileTypes */ - public function __construct(int $maxSize, array $fileTypes = []) + public function __construct(int $maxSize, array $fileTypes = [], public ?Form $form = null) { $this->maxSize = $maxSize; @@ -39,6 +40,14 @@ class StorageFile implements Rule */ public function passes($attribute, $value): bool { + // This is use when updating a record, and file uploads aren't changed. + if($this->form){ + $newPath = Str::of(PublicFormController::FILE_UPLOAD_PATH)->replace('?', $this->form->id); + if(Storage::disk('s3')->exists($newPath.'/'.$value)){ + return true; + } + } + $fileNameParser = StorageFileNameParser::parse($value); if (!$uuid = $fileNameParser->uuid) { return false; diff --git a/resources/js/components/forms/FileInput.vue b/resources/js/components/forms/FileInput.vue index 7f7104f..d5197cd 100644 --- a/resources/js/components/forms/FileInput.vue +++ b/resources/js/components/forms/FileInput.vue @@ -208,7 +208,19 @@ export default { } }, - created () { + async created () { + if(this.compVal && this.compVal.length > 0) { + let tmpFiles = [] + for (let i = 0; i < this.compVal.length; i++) { + await this.getFileFromUrl(this.compVal[i]).then((fileObj) => { + tmpFiles.push({ + file: fileObj, + url: this.compVal[i] + }) + }) + } + this.files = tmpFiles + } }, methods: { @@ -262,6 +274,14 @@ export default { this.showUploadModal = false this.loading = false }) + }, + async getFileFromUrl(url, defaultType='image/jpeg'){ + const response = await fetch(url) + const data = await response.blob() + const name = url.replace(/^.*(\\|\/|\:)/, '') + return new File([data], name, { + type: data.type || defaultType, + }) } } }