- Updated `FormController.php` to correct the file path concatenation for temporary file retrieval, enhancing clarity in file management. - Modified `FormSubmissionResource.php` to improve the filtering logic for file fields, ensuring only valid files are processed. - Streamlined the constructor in `StoreFormSubmissionJob.php` for better readability and consistency. - Enhanced file handling in `StoreFormSubmissionJob.php` by refining the logic for moving files from temporary to permanent storage, ensuring accurate file management. - Improved the `FormSubmissionFormatter.php` to handle file URLs more robustly with error handling for signed routes. - Updated `PartialSubmissionTest.php` to remove the hardcoded success message, improving test reliability. - Refactored `OpenFormField.vue` to simplify the disabled state logic for form fields, enhancing maintainability. - Adjusted `usePartialSubmission.js` to improve the synchronization mechanism during visibility changes, ensuring data integrity. These changes aim to enhance the overall functionality, maintainability, and reliability of the form submission process and file handling logic.
237 lines
8.6 KiB
PHP
237 lines
8.6 KiB
PHP
<?php
|
|
|
|
use App\Models\Forms\Form;
|
|
use App\Models\Forms\FormSubmission;
|
|
use Illuminate\Http\UploadedFile;
|
|
use Illuminate\Support\Facades\Storage;
|
|
|
|
it('can submit form partially and complete it later using submission hash', function () {
|
|
$user = $this->actingAsProUser();
|
|
$workspace = $this->createUserWorkspace($user);
|
|
$form = $this->createForm($user, $workspace, [
|
|
'enable_partial_submissions' => true
|
|
]);
|
|
|
|
// Initial partial submission
|
|
$formData = $this->generateFormSubmissionData($form, ['text' => 'Initial Text']);
|
|
$formData['is_partial'] = true;
|
|
|
|
$partialResponse = $this->postJson(route('forms.answer', $form->slug), $formData)
|
|
->assertSuccessful()
|
|
->assertJson([
|
|
'type' => 'success',
|
|
]);
|
|
|
|
$submissionHash = $partialResponse->json('submission_hash');
|
|
expect($submissionHash)->not->toBeEmpty();
|
|
|
|
// Complete the submission using the hash
|
|
$completeData = $this->generateFormSubmissionData($form, [
|
|
'text' => 'Complete Text',
|
|
'email' => 'test@example.com'
|
|
]);
|
|
$completeData['submission_hash'] = $submissionHash;
|
|
|
|
$this->postJson(route('forms.answer', $form->slug), $completeData)
|
|
->assertSuccessful()
|
|
->assertJson([
|
|
'type' => 'success',
|
|
'message' => 'Form submission saved.',
|
|
]);
|
|
|
|
// Verify final submission state
|
|
$submission = FormSubmission::first();
|
|
expect($submission->status)->toBe(FormSubmission::STATUS_COMPLETED);
|
|
expect($submission->data)->toHaveKey(array_key_first($completeData));
|
|
});
|
|
|
|
it('can update partial submission multiple times', function () {
|
|
$user = $this->actingAsProUser();
|
|
$workspace = $this->createUserWorkspace($user);
|
|
$form = $this->createForm($user, $workspace, [
|
|
'enable_partial_submissions' => true
|
|
]);
|
|
$targetField = collect($form->properties)->where('name', 'Name')->first();
|
|
|
|
// First partial submission
|
|
$formData = $this->generateFormSubmissionData($form, [$targetField['id'] => 'First Draft']);
|
|
$formData['is_partial'] = true;
|
|
|
|
$firstResponse = $this->postJson(route('forms.answer', $form->slug), $formData)
|
|
->assertSuccessful();
|
|
|
|
$submissionHash = $firstResponse->json('submission_hash');
|
|
|
|
// Second partial update
|
|
$secondData = $this->generateFormSubmissionData($form, [$targetField['id'] => 'Second Draft']);
|
|
$secondData['is_partial'] = true;
|
|
$secondData['submission_hash'] = $submissionHash;
|
|
|
|
$this->postJson(route('forms.answer', $form->slug), $secondData)
|
|
->assertSuccessful();
|
|
|
|
// Verify submission was updated
|
|
$submission = FormSubmission::first();
|
|
expect($submission->status)->toBe(FormSubmission::STATUS_PARTIAL);
|
|
expect($submission->data)->toHaveKey(array_key_first($secondData));
|
|
expect($submission->data[array_key_first($secondData)])->toBe('Second Draft');
|
|
});
|
|
|
|
it('calculates stats correctly for partial vs completed submissions', function () {
|
|
$user = $this->actingAsProUser();
|
|
$workspace = $this->createUserWorkspace($user);
|
|
$form = $this->createForm($user, $workspace, [
|
|
'enable_partial_submissions' => true
|
|
]);
|
|
|
|
// Create partial submission
|
|
$partialData = $this->generateFormSubmissionData($form, ['text' => 'Partial']);
|
|
$partialData['is_partial'] = true;
|
|
$this->postJson(route('forms.answer', $form->slug), $partialData);
|
|
|
|
// Create completed submission
|
|
$completeData = $this->generateFormSubmissionData($form, ['text' => 'Complete']);
|
|
$this->postJson(route('forms.answer', $form->slug), $completeData);
|
|
|
|
// Verify stats
|
|
$form->refresh();
|
|
expect($form->submissions()->where('status', FormSubmission::STATUS_PARTIAL)->count())->toBe(1);
|
|
expect($form->submissions()->where('status', FormSubmission::STATUS_COMPLETED)->count())->toBe(1);
|
|
});
|
|
|
|
it('handles file uploads in partial submissions', function () {
|
|
Storage::fake();
|
|
|
|
$user = $this->actingAsProUser();
|
|
$workspace = $this->createUserWorkspace($user);
|
|
$form = $this->createForm($user, $workspace, [
|
|
'enable_partial_submissions' => true
|
|
]);
|
|
|
|
// Create a fake file
|
|
$file = UploadedFile::fake()->create('test.pdf', 100);
|
|
|
|
// First partial submission with file
|
|
$formData = $this->generateFormSubmissionData($form);
|
|
$fileFieldId = collect($form->properties)->where('type', 'files')->first()['id'];
|
|
$formData[$fileFieldId] = $file;
|
|
$formData['is_partial'] = true;
|
|
|
|
$response = $this->postJson(route('forms.answer', $form->slug), $formData)
|
|
->assertSuccessful();
|
|
|
|
$submissionHash = $response->json('submission_hash');
|
|
|
|
// Complete the submission
|
|
$completeData = $this->generateFormSubmissionData($form, ['text' => 'Complete']);
|
|
$completeData['submission_hash'] = $submissionHash;
|
|
|
|
$this->postJson(route('forms.answer', $form->slug), $completeData)
|
|
->assertSuccessful();
|
|
|
|
// Verify file was preserved
|
|
$submission = FormSubmission::first();
|
|
expect($submission->data)->toHaveKey($fileFieldId);
|
|
$filePath = str_replace('storage/', '', $submission->data[$fileFieldId]);
|
|
expect(Storage::disk('local')->exists($filePath))->toBeTrue();
|
|
});
|
|
|
|
it('handles signature field in partial submissions', function () {
|
|
Storage::fake();
|
|
|
|
$user = $this->actingAsProUser();
|
|
$workspace = $this->createUserWorkspace($user);
|
|
$form = $this->createForm($user, $workspace, [
|
|
'enable_partial_submissions' => true
|
|
]);
|
|
|
|
// Create partial submission with signature
|
|
$formData = $this->generateFormSubmissionData($form);
|
|
$signatureFieldId = collect($form->properties)->where('type', 'files')->first()['id'];
|
|
$formData[$signatureFieldId] = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA...'; // Base64 signature data
|
|
$formData['is_partial'] = true;
|
|
|
|
$response = $this->postJson(route('forms.answer', $form->slug), $formData)
|
|
->assertSuccessful();
|
|
|
|
$submissionHash = $response->json('submission_hash');
|
|
|
|
// Complete the submission
|
|
$completeData = $this->generateFormSubmissionData($form, ['text' => 'Complete']);
|
|
$completeData['submission_hash'] = $submissionHash;
|
|
|
|
$this->postJson(route('forms.answer', $form->slug), $completeData)
|
|
->assertSuccessful();
|
|
|
|
// Verify signature was preserved
|
|
$submission = FormSubmission::first();
|
|
expect($submission->data)->toHaveKey($signatureFieldId);
|
|
$filePath = str_replace('storage/', '', $submission->data[$signatureFieldId]);
|
|
expect(Storage::disk('local')->exists($filePath))->toBeTrue();
|
|
});
|
|
|
|
it('requires at least one field with value for partial submission', function () {
|
|
$user = $this->actingAsProUser();
|
|
$workspace = $this->createUserWorkspace($user);
|
|
$form = $this->createForm($user, $workspace, [
|
|
'enable_partial_submissions' => true
|
|
]);
|
|
|
|
// Try to submit with empty data
|
|
$formData = ['is_partial' => true];
|
|
|
|
$this->postJson(route('forms.answer', $form->slug), $formData)
|
|
->assertStatus(422)
|
|
->assertJson([
|
|
'message' => 'At least one field must have a value for partial submissions.'
|
|
]);
|
|
});
|
|
|
|
it('submits as completed when partial feature is disabled', function () {
|
|
$user = $this->actingAsProUser();
|
|
$workspace = $this->createUserWorkspace($user);
|
|
|
|
// Create form with partial submissions disabled
|
|
$form = $this->createForm($user, $workspace, [
|
|
'enable_partial_submissions' => false
|
|
]);
|
|
|
|
$formData = $this->generateFormSubmissionData($form, ['text' => 'Test']);
|
|
$formData['is_partial'] = true;
|
|
|
|
$this->postJson(route('forms.answer', $form->slug), $formData)
|
|
->assertSuccessful()
|
|
->assertJson([
|
|
'type' => 'success',
|
|
'message' => 'Form submission saved.',
|
|
]);
|
|
|
|
// Verify submission was saved as completed
|
|
$submission = FormSubmission::first();
|
|
expect($submission->status)->toBe(FormSubmission::STATUS_COMPLETED);
|
|
});
|
|
|
|
it('submits as completed on non-pro forms', function () {
|
|
$user = $this->actingAsUser();
|
|
$workspace = $this->createUserWorkspace($user);
|
|
|
|
// Create non-pro form with partial submissions enabled
|
|
$form = $this->createForm($user, $workspace, [
|
|
'enable_partial_submissions' => true
|
|
]);
|
|
|
|
$formData = $this->generateFormSubmissionData($form, ['text' => 'Test']);
|
|
$formData['is_partial'] = true;
|
|
|
|
$this->postJson(route('forms.answer', $form->slug), $formData)
|
|
->assertSuccessful()
|
|
->assertJson([
|
|
'type' => 'success',
|
|
'message' => 'Form submission saved.',
|
|
]);
|
|
|
|
// Verify submission was saved as completed
|
|
$submission = FormSubmission::first();
|
|
expect($submission->status)->toBe(FormSubmission::STATUS_COMPLETED);
|
|
});
|