Add backend for copying forms

This commit is contained in:
philipp lang 2025-06-17 00:01:07 +02:00
parent 5be7987d80
commit ccef61352d
6 changed files with 137 additions and 0 deletions

View File

@ -0,0 +1,41 @@
<?php
namespace App\Form\Actions;
use App\Form\Models\Form;
use App\Lib\Events\Succeeded;
use Illuminate\Http\JsonResponse;
use Lorisleiva\Actions\Concerns\AsAction;
class FormCopyAction
{
use AsAction;
/**
* @param array<string, mixed> $attributes
*/
public function handle(Form $form): Form
{
$newForm = $form->replicate();
$newForm->save();
$newForm->update(['name' => $form->name.' - Kopie', 'is_active' => false]);
foreach ($form->getRegisteredMediaCollections() as $collection) {
foreach ($form->getMedia($collection->name) as $media) {
$media->copy($newForm, $collection->name);
}
}
ClearFrontendCacheAction::run();
return $form;
}
public function asController(Form $form): JsonResponse
{
$this->handle($form);
Succeeded::message('Veranstaltung kopiert.')->dispatch();
return response()->json([]);
}
}

View File

@ -61,6 +61,7 @@ class FormResource extends JsonResource
'is_dirty' => route('form.is-dirty', $this->getModel()),
'frontend' => str(app(FormSettings::class)->registerUrl)->replace('{slug}', $this->slug),
'export' => route('form.export', $this->getModel()),
'copy' => route('form.copy', $this->getModel()),
]
];
}

View File

@ -23,6 +23,7 @@ use App\Fileshare\Actions\FileshareStoreAction;
use App\Fileshare\Actions\FileshareUpdateAction;
use App\Fileshare\Actions\ListFilesAction;
use App\Form\Actions\ExportAction as ActionsExportAction;
use App\Form\Actions\FormCopyAction;
use App\Form\Actions\FormDestroyAction;
use App\Form\Actions\FormIndexAction;
use App\Group\Actions\GroupBulkstoreAction;
@ -179,6 +180,7 @@ Route::group(['middleware' => 'auth:web'], function (): void {
Route::get('/participant/{participant}/fields', ParticipantFieldsAction::class)->name('participant.fields');
Route::patch('/participant/{participant}', ParticipantUpdateAction::class)->name('participant.update');
Route::post('/form/{form}/participant', ParticipantStoreAction::class)->name('form.participant.store');
Route::post('/form/{form}/copy', FormCopyAction::class)->name('form.copy');
// ------------------------------------ fileshare -----------------------------------
Route::post('/fileshare', FileshareStoreAction::class)->name('fileshare.store');

View File

@ -145,6 +145,15 @@ class FormIndexActionTest extends FormTestCase
$this->callFilter('form.index', [])->assertInertiaPath('data.data.0.links.frontend', 'https://example.com/form/zem-2024/register');
}
public function testItDisplaysCopyUrl(): void
{
$this->withoutExceptionHandling()->login()->loginNami();
$form = Form::factory()->create();
sleep(1);
$this->callFilter('form.index', [])->assertInertiaPath('data.data.0.links.copy', route('form.copy', $form));
}
public function testItDoesntReturnInactiveForms(): void
{
$this->withoutExceptionHandling()->login()->loginNami();

View File

@ -0,0 +1,70 @@
<?php
namespace Tests\Feature\Form;
use App\Form\Models\Form;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Support\Arr;
use Tests\Lib\CreatesFormFields;
uses(DatabaseTransactions::class);
uses(CreatesFormFields::class);
beforeEach(function () {
test()->fakeMessages();
test()->setUpForm();
});
dataset('media', fn () => [
['mailattachments'],
['headerImage'],
]);
it('copies a form', function () {
test()->login()->loginNami()->withoutExceptionHandling();
$form = Form::factory()->name('Lager')->create();
test()->post(route('form.copy', ['form' => $form]))
->assertOk();
test()->assertDatabaseCount('forms', 2);
$newForm = Form::where('name', 'Lager - Kopie')->firstOrFail();
test()->assertEquals(
Arr::except($form->fresh()->toArray(), ['id', 'name', 'slug', 'created_at', 'updated_at', 'is_active']),
Arr::except($newForm->fresh()->toArray(), ['id', 'name', 'slug', 'created_at', 'updated_at', 'is_active'])
);
});
it('copies the forms media', function (string $collectionName) {
test()->login()->loginNami()->withoutExceptionHandling();
$form = Form::factory()->withImage($collectionName, 'lala.jpg')->name('Lager')->create();
test()->post(route('form.copy', ['form' => $form]))->assertOk();
test()->assertDatabaseCount('forms', 2);
$newForm = Form::where('name', 'Lager - Kopie')->firstOrFail();
test()->assertEquals($form->getMedia($collectionName)->first()->name, $newForm->getMedia($collectionName)->first()->name);
test()->assertNotEquals($form->getMedia($collectionName)->first()->id, $newForm->getMedia($collectionName)->first()->id);
test()->assertNotEquals($form->getMedia($collectionName)->first()->getFullUrl(), $newForm->getMedia($collectionName)->first()->getFullUrl());
})->with('media');
it('deactivates a copied form', function () {
test()->login()->loginNami()->withoutExceptionHandling();
$form = Form::factory()->name('Lager')->create(['is_active' => true]);
test()->post(route('form.copy', ['form' => $form]))->assertOk();
$newForm = Form::where('name', 'Lager - Kopie')->firstOrFail();
test()->assertEquals(false, $newForm->is_active);
});
it('shows success message', function () {
test()->login()->loginNami()->withoutExceptionHandling();
$form = Form::factory()->create();
test()->post(route('form.copy', ['form' => $form]))->assertOk();
test()->assertSuccessMessage('Veranstaltung kopiert.');
});

View File

@ -3,12 +3,14 @@
namespace Tests;
use App\Group;
use App\Lib\Events\Succeeded;
use App\Member\Member;
use App\Setting\NamiSettings;
use App\User;
use Illuminate\Foundation\Testing\TestCase as BaseTestCase;
use Illuminate\Http\RedirectResponse;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\Facades\Http;
use Illuminate\Testing\AssertableJsonString;
use Illuminate\Testing\TestResponse;
@ -192,4 +194,16 @@ class TestCase extends BaseTestCase
return $this;
});
}
public function fakeMessages() {
Event::fake([Succeeded::class]);
return $this;
}
public function assertSuccessMessage(string $message) {
Event::assertDispatched(Succeeded::class, fn ($event) => $event->message === $message);
return $this;
}
}