From e85e4df7fe10b4674825a5cdef6e56de0c2af23e Mon Sep 17 00:00:00 2001
From: Julien Nahum
Date: Fri, 23 Feb 2024 10:50:35 +0100
Subject: [PATCH] Fix CSV exports (missing data, add id, column name clash)
---
app/Exports/FormSubmissionExport.php | 9 +++++-
.../Forms/FormSubmissionController.php | 30 +++++++++++--------
app/Service/Forms/FormSubmissionFormatter.php | 28 ++++++++++++++---
.../open/forms/components/FormSubmissions.vue | 13 +++++++-
4 files changed, 61 insertions(+), 19 deletions(-)
diff --git a/app/Exports/FormSubmissionExport.php b/app/Exports/FormSubmissionExport.php
index e8c5a8c..9e60e95 100644
--- a/app/Exports/FormSubmissionExport.php
+++ b/app/Exports/FormSubmissionExport.php
@@ -16,7 +16,7 @@ class FormSubmissionExport implements FromArray, WithHeadingRow
$contentRow = [];
foreach ($submissionData as $i => $row) {
if($i==0){
- $headingRow[] = array_keys($row);
+ $headingRow[] = $this->cleanColumnNames(array_keys($row));
}
$contentRow[] = array_values($row);
}
@@ -27,6 +27,13 @@ class FormSubmissionExport implements FromArray, WithHeadingRow
];
}
+ private function cleanColumnNames(array $columnNames): array
+ {
+ return collect($columnNames)->map(function ($columnName) {
+ return preg_replace('/\s\(.*\)/', '', $columnName);
+ })->toArray();
+ }
+
public function array(): array
{
return $this->submissionData;
diff --git a/app/Http/Controllers/Forms/FormSubmissionController.php b/app/Http/Controllers/Forms/FormSubmissionController.php
index 1c4e007..8b44624 100644
--- a/app/Http/Controllers/Forms/FormSubmissionController.php
+++ b/app/Http/Controllers/Forms/FormSubmissionController.php
@@ -14,6 +14,7 @@ use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
use Maatwebsite\Excel\Facades\Excel;
+use Vinkla\Hashids\Facades\Hashids;
class FormSubmissionController extends Controller
{
@@ -25,29 +26,29 @@ class FormSubmissionController extends Controller
public function submissions(string $id)
{
- $form = Form::findOrFail((int) $id);
+ $form = Form::findOrFail((int)$id);
$this->authorize('view', $form);
return FormSubmissionResource::collection($form->submissions()->paginate(100));
}
- public function update(AnswerFormRequest $request, $id, $submissionId)
+ public function update(AnswerFormRequest $request, $id, $submissionId)
{
- $form = $request->form;
+ $form = $request->form;
$this->authorize('update', $form);
$job = new StoreFormSubmissionJob($request->form, $request->validated());
$job->setSubmissionId($submissionId)->handle();
- $data = new FormSubmissionResource(FormSubmission::findOrFail($submissionId));
+ $data = new FormSubmissionResource(FormSubmission::findOrFail($submissionId));
return $this->success([
'message' => 'Record successfully updated.',
- 'data' => $data
+ 'data' => $data
]);
}
public function export(string $id)
{
- $form = Form::findOrFail((int) $id);
+ $form = Form::findOrFail((int)$id);
$this->authorize('view', $form);
$allRows = [];
@@ -56,23 +57,26 @@ class FormSubmissionController extends Controller
->outputStringsOnly()
->setEmptyForNoValue()
->showRemovedFields()
+ ->showHiddenFields()
->useSignedUrlForFiles();
- $tmp = $formatter->getCleanKeyValue();
- $tmp['Create Date'] = date("Y-m-d H:i", strtotime($row['created_at']));
- $allRows[] = $tmp;
+ $allRows[] = [
+ 'id' => Hashids::encode($row['id']),
+ 'created_at' => date("Y-m-d H:i", strtotime($row['created_at'])),
+ ...$formatter->getCleanKeyValue()
+ ];
}
$csvExport = (new FormSubmissionExport($allRows));
return Excel::download(
$csvExport,
- $form->slug.'-submission-data.csv',
+ $form->slug . '-submission-data.csv',
\Maatwebsite\Excel\Excel::CSV
);
}
public function submissionFile($id, $fileName)
{
- $fileName = Str::of(PublicFormController::FILE_UPLOAD_PATH)->replace('?', $id).'/'
- .urldecode($fileName);
+ $fileName = Str::of(PublicFormController::FILE_UPLOAD_PATH)->replace('?', $id) . '/'
+ . urldecode($fileName);
if (!Storage::exists($fileName)) {
return $this->error([
@@ -85,7 +89,7 @@ class FormSubmissionController extends Controller
}
return redirect(
- Storage::temporaryUrl($fileName, now()->addMinute())
+ Storage::temporaryUrl($fileName, now()->addMinute())
);
}
}
diff --git a/app/Service/Forms/FormSubmissionFormatter.php b/app/Service/Forms/FormSubmissionFormatter.php
index d46fe50..8fbab0d 100644
--- a/app/Service/Forms/FormSubmissionFormatter.php
+++ b/app/Service/Forms/FormSubmissionFormatter.php
@@ -85,15 +85,35 @@ class FormSubmissionFormatter
public function getCleanKeyValue()
{
$data = $this->formData;
- $fields = ($this->showRemovedFields) ? array_merge($this->form->properties, $this->form->removed_properties) : $this->form->properties;
+
+ $fields = collect($this->form->properties);
+ $removeFields = collect($this->form->removed_properties)->map(function ($field) {
+ return [
+ ...$field,
+ 'removed' => true
+ ];
+ });
+ if ($this->showRemovedFields) {
+ $fields = $fields->merge($removeFields);
+ }
+ $fields = $fields->filter(function ($field) {
+ return !in_array($field['type'],['nf-text', 'nf-code', 'nf-page-break', 'nf-divider', 'nf-image']);
+ })->values();
$returnArray = [];
- foreach ($fields as &$field) {
- $isRemoved = in_array($field['id'], array_column($this->form->removed_properties, 'id')) ?? false;
- if($isRemoved){
+ foreach ($fields as $field) {
+
+ if (in_array($field['id'],['nf-text', 'nf-code', 'nf-page-break', 'nf-divider', 'nf-image'])) {
+ continue;
+ }
+
+ if($field['removed'] ?? false) {
$field['name'] = $field['name']." (deleted)";
}
+ // Add ID to avoid name clashes
+ $field['name'] = $field['name'].' ('.\Str::of($field['id']).')';
+
// If not present skip
if (!isset($data[$field['id']])) {
if ($this->setEmptyForNoValue) {
diff --git a/client/components/open/forms/components/FormSubmissions.vue b/client/components/open/forms/components/FormSubmissions.vue
index 9459b8b..b104a30 100644
--- a/client/components/open/forms/components/FormSubmissions.vue
+++ b/client/components/open/forms/components/FormSubmissions.vue
@@ -71,9 +71,10 @@
>Display columns
- Export as CSV
+
@@ -136,6 +137,7 @@ export default {
properties: [],
removed_properties: [],
displayColumns: {},
+ exportLoading: false,
searchForm: useForm({
search: ''
}),
@@ -184,6 +186,9 @@ export default {
watch: {
'form.id'() {
this.onFormChange()
+ },
+ 'searchForm.search'() {
+ this.dataChanged()
}
},
mounted() {
@@ -271,6 +276,10 @@ export default {
this.dataChanged()
},
downloadAsCsv() {
+ if (this.exportLoading) {
+ return
+ }
+ this.exportLoading = true
opnFetch(this.exportUrl, {responseType: "blob"})
.then(blob => {
const filename = `${this.form.slug}-${Date.now()}-submissions.csv`
@@ -284,6 +293,8 @@ export default {
window.URL.revokeObjectURL(url)
}).catch((error) => {
console.error(error)
+ }).finally(() => {
+ this.exportLoading = false
})
}
}