Files
opnform-host-nginx/api/app/Http/Controllers/Forms/FormSubmissionController.php
Chirag Chhatrala ff1a4d17d8 Partial submissions (#705)
* Implement partial form submissions feature

* Add status filtering for form submissions

* Add Partial Submission in Analytics

* improve partial submission

* fix lint

* Add type checking for submission ID in form submission job

* on form stats Partial Submissions only if enable

* Partial Submissions is PRO Feature

* Partial Submissions is PRO Feature

* improvement migration

* Update form submission status labels to 'Submitted' and 'In Progress'

* start partial sync when dataFormValue update

* badge size xs

* Refactor partial submission hash management

* Refactor partial form submission handling in PublicFormController

* fix submissiona

* Refactor form submission ID handling and metadata processing

- Improve submission ID extraction and decoding across controllers
- Add robust handling for submission hash and ID conversion
- Enhance metadata processing in StoreFormSubmissionJob
- Simplify submission storage logic with clearer metadata extraction
- Minor UI improvements in FormSubmissions and OpenTable components

* Enhance form submission settings UI with advanced partial submission options

- Restructure partial submissions toggle with more descriptive label
- Add advanced submission options section with Pro tag
- Improve help text for partial submissions feature
- Update ProTag with more detailed upgrade modal description

* Refactor partial form submission sync mechanism

- Improve partial submission synchronization in usePartialSubmission composable
- Replace interval-based sync with Vue's reactive watch
- Add robust handling for different form data input patterns
- Implement onBeforeUnmount hook for final sync attempt
- Enhance data synchronization reliability and performance

* Improve partial form submission validation and synchronization

* fix lint

* Refactor submission identifier processing in PublicFormController

- Updated the docblock for the method responsible for processing submission identifiers to clarify its functionality. The method now explicitly states that it converts a submission hash or string ID into a numeric submission_id, ensuring consistent internal storage format.

These changes aim to improve code documentation and enhance understanding of the method's purpose and behavior.

* Enhance Form Logic Condition Checker to Exclude Partial Submissions

- Updated the query in FormLogicConditionChecker to exclude submissions with a status of 'partial', ensuring that only complete submissions are processed.
- Minor formatting adjustment in the docblock of PublicFormController for improved clarity.

These changes aim to refine submission handling and enhance the accuracy of form logic evaluations.

* Partial Submission Test

* Refactor FormSubmissionController and PartialSubmissionTest for Consistency

- Updated the `FormSubmissionController` to improve code consistency by adjusting the formatting of anonymous functions in the `filter` and `first` methods.
- Modified `PartialSubmissionTest` to simplify the `Storage::fake()` method call, removing the unnecessary 'local' parameter for better clarity.

These changes aim to enhance code readability and maintainability across the form submission handling and testing components.

* Enhance FormSubmissionController and EditSubmissionTest for Clarity

- Added validation to the `FormSubmissionController` by introducing `$submissionData = $request->validated();` to ensure that only validated data is processed for form submissions.
- Improved code readability in the `FormSubmissionController` by adjusting the formatting of anonymous functions in the `filter` and `first` methods.
- Removed unnecessary blank lines in the `EditSubmissionTest` to streamline the test setup.

These changes aim to enhance data integrity during form submissions and improve overall code clarity and maintainability.

---------

Co-authored-by: Julien Nahum <julien@nahum.net>
2025-04-28 17:33:55 +02:00

109 lines
3.6 KiB
PHP

<?php
namespace App\Http\Controllers\Forms;
use App\Exports\FormSubmissionExport;
use App\Http\Controllers\Controller;
use App\Http\Requests\AnswerFormRequest;
use App\Http\Requests\FormSubmissionExportRequest;
use App\Http\Resources\FormSubmissionResource;
use App\Jobs\Form\StoreFormSubmissionJob;
use App\Models\Forms\Form;
use App\Models\Forms\FormSubmission;
use App\Service\Forms\FormSubmissionFormatter;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
use Maatwebsite\Excel\Facades\Excel;
use Vinkla\Hashids\Facades\Hashids;
class FormSubmissionController extends Controller
{
public function __construct()
{
$this->middleware('auth', ['except' => ['submissionFile']]);
$this->middleware('signed', ['only' => ['submissionFile']]);
}
public function submissions(string $id)
{
$form = Form::findOrFail((int) $id);
$this->authorize('view', $form);
return FormSubmissionResource::collection($form->submissions()->paginate(100));
}
public function update(AnswerFormRequest $request, $id, $submissionId)
{
$form = $request->form;
$this->authorize('update', $form);
$submissionData = $request->validated();
$submissionData['submission_id'] = $submissionId;
$job = new StoreFormSubmissionJob($request->form, $submissionData);
$job->handle();
$data = new FormSubmissionResource(FormSubmission::findOrFail($submissionId));
return $this->success([
'message' => 'Record successfully updated.',
'data' => $data,
]);
}
public function export(FormSubmissionExportRequest $request, string $id)
{
$form = $request->form;
$this->authorize('view', $form);
$allRows = [];
$displayColumns = collect($request->columns)->filter(fn ($value, $key) => $value === true)->toArray();
foreach ($form->submissions->toArray() as $row) {
$formatter = (new FormSubmissionFormatter($form, $row['data']))
->outputStringsOnly()
->setEmptyForNoValue()
->showRemovedFields()
->showHiddenFields()
->useSignedUrlForFiles();
$formattedData = $formatter->getCleanKeyValue();
$filteredData = ['id' => Hashids::encode($row['id'])];
foreach ($displayColumns as $column => $value) {
$key = collect($formattedData)->keys()->first(fn ($key) => str_contains($key, $column));
if ($key) {
$filteredData[$key] = $formattedData[$key];
}
}
if (isset($displayColumns['created_at'])) {
$filteredData['created_at'] = date('Y-m-d H:i', strtotime($row['created_at']));
}
$allRows[] = $filteredData;
}
$csvExport = (new FormSubmissionExport($allRows));
return Excel::download(
$csvExport,
$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);
if (! Storage::exists($fileName)) {
return $this->error([
'message' => 'File not found.',
], 404);
}
if (config('filesystems.default') !== 's3') {
return response()->file(Storage::path($fileName));
}
return redirect(
Storage::temporaryUrl($fileName, now()->addMinute())
);
}
}