Compare commits

..

No commits in common. "5641006e2bcb31bf05457cd3b80bbbfa06960f61" and "1ef7995ec27827fe83b22d687aa0c1bbc31ad12b" have entirely different histories.

25 changed files with 99 additions and 293 deletions

View File

@ -28,6 +28,8 @@ class FormStoreAction
'to' => 'required|date', 'to' => 'required|date',
'registration_from' => 'present|nullable|date', 'registration_from' => 'present|nullable|date',
'registration_until' => 'present|nullable|date', 'registration_until' => 'present|nullable|date',
'mail_top' => 'array',
'mail_bottom' => 'array',
'header_image' => 'required|exclude', 'header_image' => 'required|exclude',
'mailattachments' => 'present|array|exclude', 'mailattachments' => 'present|array|exclude',
'is_active' => 'boolean', 'is_active' => 'boolean',

View File

@ -30,6 +30,8 @@ class FormUpdateAction
'to' => 'required|date', 'to' => 'required|date',
'registration_from' => 'present|nullable|date', 'registration_from' => 'present|nullable|date',
'registration_until' => 'present|nullable|date', 'registration_until' => 'present|nullable|date',
'mail_top' => 'array',
'mail_bottom' => 'array',
'is_active' => 'boolean', 'is_active' => 'boolean',
'is_private' => 'boolean', 'is_private' => 'boolean',
'export' => 'nullable|array', 'export' => 'nullable|array',

View File

@ -28,8 +28,6 @@ trait HasValidation
'config.sections.*.fields.*.columns.mobile' => 'required|numeric|gt:0|lte:2', 'config.sections.*.fields.*.columns.mobile' => 'required|numeric|gt:0|lte:2',
'config.sections.*.fields.*.columns.tablet' => 'required|numeric|gt:0|lte:4', 'config.sections.*.fields.*.columns.tablet' => 'required|numeric|gt:0|lte:4',
'config.sections.*.fields.*.columns.desktop' => 'required|numeric|gt:0|lte:6', 'config.sections.*.fields.*.columns.desktop' => 'required|numeric|gt:0|lte:6',
'mail_top' => 'array',
'mail_bottom' => 'array',
]; ];
} }

View File

@ -19,9 +19,9 @@ class ConfirmRegistrationMail extends Mailable
public string $fullname; public string $fullname;
public FormConfigData $config; public FormConfigData $config;
/** @var array<int, mixed> */ /** @var array<string, mixed> */
public array $topText; public array $topText;
/** @var array<int, mixed> */ /** @var array<string, mixed> */
public array $bottomText; public array $bottomText;
/** /**

View File

@ -32,9 +32,9 @@ class Form extends Model implements HasMedia
public $casts = [ public $casts = [
'config' => FormConfigData::class, 'config' => FormConfigData::class,
'meta' => 'json', 'meta' => 'json',
'description' => EditorData::class, 'description' => 'json',
'mail_top' => EditorData::class, 'mail_top' => 'json',
'mail_bottom' => EditorData::class, 'mail_bottom' => 'json',
'is_active' => 'boolean', 'is_active' => 'boolean',
'is_private' => 'boolean', 'is_private' => 'boolean',
'export' => ExportData::class, 'export' => ExportData::class,

View File

@ -3,7 +3,6 @@
namespace App\Form\Models; namespace App\Form\Models;
use App\Form\Data\FormConfigData; use App\Form\Data\FormConfigData;
use App\Lib\Editor\EditorData;
use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
@ -18,7 +17,5 @@ class Formtemplate extends Model
public $casts = [ public $casts = [
'config' => FormConfigData::class, 'config' => FormConfigData::class,
'mail_top' => EditorData::class,
'mail_bottom' => EditorData::class,
]; ];
} }

View File

@ -7,7 +7,6 @@ use App\Form\Enums\SpecialType;
use App\Form\Fields\Field; use App\Form\Fields\Field;
use App\Form\Models\Formtemplate; use App\Form\Models\Formtemplate;
use App\Group; use App\Group;
use App\Lib\Editor\EditorData;
use App\Lib\HasMeta; use App\Lib\HasMeta;
use Illuminate\Http\Resources\Json\JsonResource; use Illuminate\Http\Resources\Json\JsonResource;
@ -53,8 +52,6 @@ class FormtemplateResource extends JsonResource
], ],
'default' => [ 'default' => [
'name' => '', 'name' => '',
'mail_top' => EditorData::default(),
'mail_bottom' => EditorData::default(),
'config' => [ 'config' => [
'sections' => [], 'sections' => [],
] ]

View File

@ -8,11 +8,12 @@ abstract class ConditionResolver
abstract public function filterCondition(Condition $condition): bool; abstract public function filterCondition(Condition $condition): bool;
/** /**
* @return array<int, mixed> * @param array<string, mixed> $content
* @return array<string, mixed>
*/ */
public function makeBlocks(EditorData $data): array public function makeBlocks(array $content): array
{ {
return array_filter($data->blocks, fn ($block) => $this->filterBlock($block)); return array_filter(data_get($content, 'blocks', []), fn ($block) => $this->filterBlock($block));
} }
/** /**

View File

@ -43,15 +43,15 @@ class FormFactory extends Factory
{ {
return [ return [
'name' => $this->faker->words(4, true), 'name' => $this->faker->words(4, true),
'description' => EditorRequestFactory::new()->toData(), 'description' => EditorRequestFactory::new()->create(),
'excerpt' => $this->faker->words(10, true), 'excerpt' => $this->faker->words(10, true),
'config' => ['sections' => []], 'config' => ['sections' => []],
'from' => $this->faker->dateTimeBetween('+1 week', '+4 weeks')->format('Y-m-d H:i:s'), 'from' => $this->faker->dateTimeBetween('+1 week', '+4 weeks')->format('Y-m-d H:i:s'),
'to' => $this->faker->dateTimeBetween('+1 week', '+4 weeks')->format('Y-m-d H:i:s'), 'to' => $this->faker->dateTimeBetween('+1 week', '+4 weeks')->format('Y-m-d H:i:s'),
'registration_from' => $this->faker->dateTimeBetween('-2 weeks', 'now')->format('Y-m-d H:i:s'), 'registration_from' => $this->faker->dateTimeBetween('-2 weeks', 'now')->format('Y-m-d H:i:s'),
'registration_until' => $this->faker->dateTimeBetween('now', '+2 weeks')->format('Y-m-d H:i:s'), 'registration_until' => $this->faker->dateTimeBetween('now', '+2 weeks')->format('Y-m-d H:i:s'),
'mail_top' => EditorRequestFactory::new()->toData(), 'mail_top' => EditorRequestFactory::new()->create(),
'mail_bottom' => EditorRequestFactory::new()->toData(), 'mail_bottom' => EditorRequestFactory::new()->create(),
'is_active' => true, 'is_active' => true,
'is_private' => false, 'is_private' => false,
'export' => ExportData::from([]), 'export' => ExportData::from([]),
@ -85,16 +85,16 @@ class FormFactory extends Factory
public function mailTop(EditorRequestFactory $factory): self public function mailTop(EditorRequestFactory $factory): self
{ {
return $this->state(['mail_top' => $factory->toData()]); return $this->state(['mail_top' => $factory->create()]);
} }
public function mailBottom(EditorRequestFactory $factory): self public function mailBottom(EditorRequestFactory $factory): self
{ {
return $this->state(['mail_bottom' => $factory->toData()]); return $this->state(['mail_bottom' => $factory->create()]);
} }
public function description(EditorRequestFactory $factory): self public function description(EditorRequestFactory $factory): self
{ {
return $this->state(['description' => $factory->toData()]); return $this->state(['description' => $factory->create()]);
} }
} }

View File

@ -5,7 +5,6 @@ namespace Database\Factories\Form\Models;
use App\Form\Models\Formtemplate; use App\Form\Models\Formtemplate;
use Illuminate\Database\Eloquent\Factories\Factory; use Illuminate\Database\Eloquent\Factories\Factory;
use Tests\Feature\Form\FormtemplateSectionRequest; use Tests\Feature\Form\FormtemplateSectionRequest;
use Tests\RequestFactories\EditorRequestFactory;
/** /**
* @extends Factory<Formtemplate> * @extends Factory<Formtemplate>
@ -25,8 +24,6 @@ class FormtemplateFactory extends Factory
{ {
return [ return [
'name' => $this->faker->words(4, true), 'name' => $this->faker->words(4, true),
'mail_top' => EditorRequestFactory::new()->toData(),
'mail_bottom' => EditorRequestFactory::new()->toData(),
'config' => [ 'config' => [
'sections' => [], 'sections' => [],
], ],
@ -48,14 +45,4 @@ class FormtemplateFactory extends Factory
{ {
return $this->state([str($method)->snake()->toString() => $parameters[0]]); return $this->state([str($method)->snake()->toString() => $parameters[0]]);
} }
public function mailTop(EditorRequestFactory $factory): self
{
return $this->state(['mail_top' => $factory->toData()]);
}
public function mailBottom(EditorRequestFactory $factory): self
{
return $this->state(['mail_bottom' => $factory->toData()]);
}
} }

View File

@ -1,7 +1,10 @@
<?php <?php
use App\Form\Models\Form;
use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
return new class extends Migration return new class extends Migration
{ {

View File

@ -1,57 +0,0 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
foreach (DB::table('forms')->get() as $form) {
$mailTop = json_decode($form->mail_top, true);
if (!$mailTop || !count($mailTop)) {
DB::table('forms')->where('id', $form->id)->update(['mail_top' => $this->default()]);
}
$mailBottom = json_decode($form->mail_bottom, true);
if (!$mailBottom || !count($mailBottom)) {
DB::table('forms')->where('id', $form->id)->update(['mail_bottom' => $this->default()]);
}
$description = json_decode($form->description, true);
if (!$description || !count($description)) {
DB::table('forms')->where('id', $form->id)->update(['description' => $this->default()]);
}
}
Schema::table('forms', function (Blueprint $table) {
$table->json('description')->default($this->default())->change();
$table->json('mail_top')->default($this->default())->nullable(false)->change();
$table->json('mail_bottom')->default($this->default())->nullable(false)->change();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('forms', function (Blueprint $table) {
$table->json('description')->default(null)->change();
$table->json('mail_top')->default(null)->nullable(true)->change();
$table->json('mail_bottom')->default(null)->nullable(true)->change();
});
}
protected function default(): string
{
return json_encode(['time' => 4, 'blocks' => [], 'version' => '1.0']);
}
};

View File

@ -1,34 +0,0 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('formtemplates', function (Blueprint $table) {
$table->json('mail_top')->after('name')->default(json_encode(['time' => 4, 'blocks' => [], 'version' => '1.0']));
$table->json('mail_bottom')->after('name')->default(json_encode(['time' => 4, 'blocks' => [], 'version' => '1.0']));
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('formtemplates', function (Blueprint $table) {
$table->dropColumn('mail_top');
$table->dropColumn('mail_bottom');
});
}
};

View File

@ -53,8 +53,8 @@
</div> </div>
</template> </template>
<script setup> <script lang="js" setup>
import {ref, inject, computed} from 'vue'; import { ref, inject, computed } from 'vue';
const axios = inject('axios'); const axios = inject('axios');
const emit = defineEmits(['update:modelValue']); const emit = defineEmits(['update:modelValue']);
@ -70,19 +70,19 @@ const props = defineProps({
id: { id: {
required: true, required: true,
type: String, type: String,
}, }
}); });
const comparatorOptions = ref([ const comparatorOptions = ref([
{id: 'isEqual', name: 'ist gleich', defaultValue: {DropdownField: null, RadioField: null, CheckboxField: false}}, { id: 'isEqual', name: 'ist gleich', defaultValue: { DropdownField: null, RadioField: null, CheckboxField: false } },
{id: 'isNotEqual', name: 'ist ungleich', defaultValue: {DropdownField: null, RadioField: null, CheckboxField: false}}, { id: 'isNotEqual', name: 'ist ungleich', defaultValue: { DropdownField: null, RadioField: null, CheckboxField: false } },
{id: 'isIn', name: 'ist in', defaultValue: {DropdownField: [], RadioField: [], CheckboxField: false}}, { id: 'isIn', name: 'ist in', defaultValue: { DropdownField: [], RadioField: [], CheckboxField: false } },
{id: 'isNotIn', name: 'ist nicht in', defaultValue: {DropdownField: [], RadioField: [], CheckboxField: false}}, { id: 'isNotIn', name: 'ist nicht in', defaultValue: { DropdownField: [], RadioField: [], CheckboxField: false } },
]); ]);
const modeOptions = ref([ const modeOptions = ref([
{id: 'all', name: 'alle Bedingungen müssen zutreffen'}, { id: 'all', name: 'alle Bedingungen müssen zutreffen' },
{id: 'any', name: 'mindestens eine Bedingung muss zutreffen'}, { id: 'any', name: 'mindestens eine Bedingung muss zutreffen' },
]); ]);
const fields = computed(() => { const fields = computed(() => {
@ -133,39 +133,34 @@ function getField(fieldName) {
function getOptions(fieldName) { function getOptions(fieldName) {
return getField(fieldName).options.map((o) => { return getField(fieldName).options.map((o) => {
return {id: o, name: o}; return { id: o, name: o };
}); });
} }
const fieldOptions = computed(() => const fieldOptions = computed(() =>
fields.value.map((field) => { fields.value.map((field) => {
return {id: field.key, name: field.name}; return { id: field.key, name: field.name };
}) })
); );
function addCondition() { function addCondition() {
emit('update:modelValue', { emit('update:modelValue', {...props.modelValue, ifs: [
...props.modelValue, ...props.modelValue.ifs,
ifs: [ {
...props.modelValue.ifs, field: null,
{ comparator: null,
field: null, value: null,
comparator: null, }
value: null, ]});
},
],
});
} }
const locked = ref(false); const locked = ref(false);
async function checkIfDirty() { async function checkIfDirty() {
const response = await axios.post(props.single.links.is_dirty, {config: props.single.config}); const response = await axios.post(props.single.links.is_dirty, { config: props.single.config });
locked.value = response.data.result; locked.value = response.data.result;
} }
if (props.single.links && props.single.links.is_dirty) { checkIfDirty();
checkIfDirty();
}
</script> </script>

View File

@ -201,12 +201,12 @@ var { meta, data, reloadPage, create, single, edit, cancel, submit, remove, getF
const axios = inject('axios'); const axios = inject('axios');
const toast = useToast(); const toast = useToast();
const active = ref(0);
const activeMailTab = ref(0);
const deleting = ref(null); const deleting = ref(null);
const showing = ref(null); const showing = ref(null);
const fileSettingPopup = ref(null); const fileSettingPopup = ref(null);
const active = ref(0);
const activeMailTab = ref(0);
const tabs = [{ title: 'Allgemeines' }, { title: 'Formular' }, { title: 'Bestätigungs-E-Mail' }, { title: 'Export' }, { title: 'Prävention' }]; const tabs = [{ title: 'Allgemeines' }, { title: 'Formular' }, { title: 'Bestätigungs-E-Mail' }, { title: 'Export' }, { title: 'Prävention' }];
const mailTabs = [{ title: 'vor Daten' }, { title: 'nach Daten' }]; const mailTabs = [{ title: 'vor Daten' }, { title: 'nach Daten' }];
@ -228,8 +228,6 @@ const allFields = computed(() => {
function setTemplate(template) { function setTemplate(template) {
active.value = 0; active.value = 0;
single.value.config = template.config; single.value.config = template.config;
single.value.mail_top = template.mail_top;
single.value.mail_bottom = template.mail_bottom;
} }
async function saveFileConditions(conditions) { async function saveFileConditions(conditions) {

View File

@ -24,33 +24,11 @@
</ui-popup> </ui-popup>
<ui-popup v-if="single !== null" :heading="`Vorlage ${single.id ? 'bearbeiten' : 'erstellen'}`" full @close="cancel"> <ui-popup v-if="single !== null" :heading="`Vorlage ${single.id ? 'bearbeiten' : 'erstellen'}`" full @close="cancel">
<div class="flex flex-col mt-3"> <form-builder v-model="single.config" :meta="meta">
<ui-tabs v-model="activeTab" :entries="tabs"></ui-tabs> <template #meta>
<form-builder v-if="activeTab === 0" v-model="single.config" :meta="meta"> <f-text id="name" v-model="single.name" label="Name" required></f-text>
<template #meta> </template>
<f-text id="name" v-model="single.name" label="Name" required></f-text> </form-builder>
</template>
</form-builder>
<div v-show="activeTab === 1" class="grid gap-3">
<ui-note class="mt-2 col-span-full">
Hier kannst du die E-Mail anpassen, die nach der Anmeldung an den Teilnehmer verschickt wird.<br />
Es gibt dafür einen ersten E-Mail-Teil und einen zweiten E-Mail-Teil. Dazwischen werden die Daten des Teilnehmers aufgelistet.<br />
Die Anrede ("Hallo Max Mustermann") wird automatisch an den Anfang gesetzt.<br />
Außerdem kannst du Dateien hochladen, die automatisch mit angehangen werden.
</ui-note>
<ui-tabs v-model="activeMailTab" :entries="mailTabs"></ui-tabs>
<f-editor v-if="activeMailTab === 0" id="mail_top" v-model="single.mail_top" name="mail_top" label="E-Mail-Teil 1" :rows="8" conditions required>
<template #conditions="{data, resolve}">
<conditions-form id="mail_top_conditions" :single="single" :value="data" @save="resolve"> </conditions-form>
</template>
</f-editor>
<f-editor v-if="activeMailTab === 1" id="mail_bottom" v-model="single.mail_bottom" name="mail_bottom" label="E-Mail-Teil 2" :rows="8" conditions required>
<template #conditions="{data, resolve}">
<conditions-form id="mail_bottom_conditions" :single="single" :value="data" @save="resolve"> </conditions-form>
</template>
</f-editor>
</div>
</div>
<template #actions> <template #actions>
<a href="#" @click.prevent="submit"> <a href="#" @click.prevent="submit">
<ui-sprite src="save" class="text-zinc-400 w-6 h-6"></ui-sprite> <ui-sprite src="save" class="text-zinc-400 w-6 h-6"></ui-sprite>
@ -84,13 +62,8 @@
import { ref } from 'vue'; import { ref } from 'vue';
import { indexProps, useIndex } from '../../composables/useInertiaApiIndex.js'; import { indexProps, useIndex } from '../../composables/useInertiaApiIndex.js';
import FormBuilder from './FormBuilder.vue'; import FormBuilder from './FormBuilder.vue';
import ConditionsForm from '../form/ConditionsForm.vue';
const deleting = ref(null); const deleting = ref(null);
const activeTab = ref(0);
const activeMailTab = ref(0);
const tabs = [{ title: 'Formular' }, { title: 'Bestätigungs-E-Mail' }];
const mailTabs = [{ title: 'vor Daten' }, { title: 'nach Daten' }];
const props = defineProps(indexProps); const props = defineProps(indexProps);
var { meta, data, reloadPage, create, remove, single, edit, cancel, submit } = useIndex(props.data, 'invoice'); var { meta, data, reloadPage, create, remove, single, edit, cancel, submit } = useIndex(props.data, 'invoice');

View File

@ -19,6 +19,7 @@ class FormIndexActionTest extends FormTestCase
{ {
Carbon::setTestNow(Carbon::parse('2023-03-03')); Carbon::setTestNow(Carbon::parse('2023-03-03'));
$this->login()->loginNami()->withoutExceptionHandling(); $this->login()->loginNami()->withoutExceptionHandling();
Formtemplate::factory()->name('tname')->sections([FormtemplateSectionRequest::new()->name('sname')])->create();
$form = Form::factory() $form = Form::factory()
->name('lala') ->name('lala')
->excerpt('fff') ->excerpt('fff')
@ -57,6 +58,8 @@ class FormIndexActionTest extends FormTestCase
->assertInertiaPath('data.data.0.links.export', route('form.export', ['form' => $form])) ->assertInertiaPath('data.data.0.links.export', route('form.export', ['form' => $form]))
->assertInertiaPath('data.meta.links.store', route('form.store')) ->assertInertiaPath('data.meta.links.store', route('form.store'))
->assertInertiaPath('data.meta.links.formtemplate_index', route('formtemplate.index')) ->assertInertiaPath('data.meta.links.formtemplate_index', route('formtemplate.index'))
->assertInertiaPath('data.meta.templates.0.name', 'tname')
->assertInertiaPath('data.meta.templates.0.config.sections.0.name', 'sname')
->assertInertiaPath('data.meta.default.name', '') ->assertInertiaPath('data.meta.default.name', '')
->assertInertiaPath('data.meta.default.prevention_conditions', ['mode' => 'all', 'ifs' => []]) ->assertInertiaPath('data.meta.default.prevention_conditions', ['mode' => 'all', 'ifs' => []])
->assertInertiaPath('data.meta.default.prevention_text.version', '1.0') ->assertInertiaPath('data.meta.default.prevention_text.version', '1.0')
@ -73,27 +76,6 @@ class FormIndexActionTest extends FormTestCase
->assertInertiaPath('data.meta.section_default.name', ''); ->assertInertiaPath('data.meta.section_default.name', '');
} }
public function testFormtemplatesHaveData(): void
{
$this->login()->loginNami()->withoutExceptionHandling();
Formtemplate::factory()->name('tname')->sections([FormtemplateSectionRequest::new()->name('sname')->fields([
$this->textField('vorname')
])])
->mailTop(EditorRequestFactory::new()->text(10, 'lala'))
->mailBottom(EditorRequestFactory::new()->text(10, 'lalb'))
->create();
sleep(1);
$this->get(route('form.index'))
->assertOk()
->assertInertiaPath('data.meta.templates.0.name', 'tname')
->assertInertiaPath('data.meta.templates.0.name', 'tname')
->assertInertiaPath('data.meta.templates.0.config.sections.0.name', 'sname')
->assertInertiaPath('data.meta.templates.0.config.sections.0.fields.0.key', 'vorname')
->assertInertiaPath('data.meta.templates.0.mail_top.blocks.0.data.text', 'lala')
->assertInertiaPath('data.meta.templates.0.mail_bottom.blocks.0.data.text', 'lalb');
}
public function testItDisplaysExport(): void public function testItDisplaysExport(): void
{ {
$this->login()->loginNami()->withoutExceptionHandling(); $this->login()->loginNami()->withoutExceptionHandling();

View File

@ -241,6 +241,24 @@ class FormRegisterMailTest extends FormTestCase
} }
} }
public function testItSendsEmailWhenMailTopIsEmpty(): void
{
$this->login()->loginNami()->withoutExceptionHandling();
$participant = Participant::factory()->for(
Form::factory()
->fields([
$this->textField('firstname')->specialType(SpecialType::FIRSTNAME),
$this->textField('lastname')->specialType(SpecialType::LASTNAME),
])->state(['mail_top' => []])
)
->data(['firstname' => 'Max', 'lastname' => 'Muster'])
->create();
$mail = new ConfirmRegistrationMail($participant);
$mail->assertSeeInText('Max');
}
/** /**
* @dataProvider blockDataProvider * @dataProvider blockDataProvider
* @param array<string, mixed> $conditions * @param array<string, mixed> $conditions

View File

@ -73,14 +73,6 @@ class FormRequest extends RequestFactory
return $this->state([str($method)->snake()->toString() => $args[0]]); return $this->state([str($method)->snake()->toString() => $args[0]]);
} }
/**
* @param array<int, FormtemplateFieldRequest> $fields
*/
public function fields(array $fields): self
{
return $this->sections([FormtemplateSectionRequest::new()->fields($fields)]);
}
public function headerImage(string $fileName): self public function headerImage(string $fileName): self
{ {
UploadedFile::fake()->image($fileName, 1000, 1000)->storeAs('media-library', $fileName, 'temp'); UploadedFile::fake()->image($fileName, 1000, 1000)->storeAs('media-library', $fileName, 'temp');

View File

@ -41,9 +41,9 @@ class FormStoreActionTest extends FormTestCase
$this->assertEquals('formname', $form->name); $this->assertEquals('formname', $form->name);
$this->assertEquals('lorem ipsum', $form->prevention_text->blocks[0]['data']['text']); $this->assertEquals('lorem ipsum', $form->prevention_text->blocks[0]['data']['text']);
$this->assertEquals('avff', $form->excerpt); $this->assertEquals('avff', $form->excerpt);
$this->assertEquals('Lorem', $form->description->blocks[0]['data']['text']); $this->assertEquals($description->paragraphBlock(10, 'Lorem'), $form->description);
$this->assertEquals('lala', $form->mail_top->blocks[0]['data']['text']); $this->assertEquals(json_decode('{"time":1,"blocks":[{"id":11,"type":"paragraph","data":{"text":"lala"},"tunes":{"condition":{"mode":"all","ifs":[]}}}],"version":"1.0"}', true), $form->mail_top);
$this->assertEquals('lalab', $form->mail_bottom->blocks[0]['data']['text']); $this->assertEquals(json_decode('{"time":1,"blocks":[{"id":12,"type":"paragraph","data":{"text":"lalab"},"tunes":{"condition":{"mode":"all","ifs":[]}}}],"version":"1.0"}', true), $form->mail_bottom);
$this->assertEquals('2023-05-04 01:00', $form->registration_from->format('Y-m-d H:i')); $this->assertEquals('2023-05-04 01:00', $form->registration_from->format('Y-m-d H:i'));
$this->assertEquals(true, $form->is_active); $this->assertEquals(true, $form->is_active);
$this->assertEquals('2023-07-07 01:00', $form->registration_until->format('Y-m-d H:i')); $this->assertEquals('2023-07-07 01:00', $form->registration_until->format('Y-m-d H:i'));

View File

@ -19,8 +19,10 @@ class FormUpdateActionTest extends FormTestCase
{ {
$this->login()->loginNami()->withoutExceptionHandling(); $this->login()->loginNami()->withoutExceptionHandling();
$form = Form::factory()->create(); $form = Form::factory()->create();
$payload = FormRequest::new()->fields([ $payload = FormRequest::new()->sections([
$this->dateField()->state(['max_today' => true]), FormtemplateSectionRequest::new()->fields([
$this->dateField()->state(['max_today' => true]),
])
])->create(); ])->create();
$this->patchJson(route('form.update', ['form' => $form]), $payload) $this->patchJson(route('form.update', ['form' => $form]), $payload)
@ -31,24 +33,6 @@ class FormUpdateActionTest extends FormTestCase
$this->assertTrue($form->config->sections->get(0)->fields->get(0)->maxToday); $this->assertTrue($form->config->sections->get(0)->fields->get(0)->maxToday);
} }
public function testItSetsTexts(): void
{
$this->login()->loginNami()->withoutExceptionHandling();
$form = Form::factory()->create();
$payload = FormRequest::new()->fields([])
->mailTop(EditorRequestFactory::new()->text(11, 'lala'))
->mailBottom(EditorRequestFactory::new()->text(12, 'lalab'))
->description(EditorRequestFactory::new()->text(12, 'desc'))
->create();
$this->patchJson(route('form.update', ['form' => $form]), $payload)
->assertOk();
$this->assertEquals('lala', $form->fresh()->mail_top->blocks[0]['data']['text']);
$this->assertEquals('lalab', $form->fresh()->mail_bottom->blocks[0]['data']['text']);
$this->assertEquals('desc', $form->fresh()->description->blocks[0]['data']['text']);
}
public function testItClearsFrontendCacheWhenFormUpdated(): void public function testItClearsFrontendCacheWhenFormUpdated(): void
{ {
$this->login()->loginNami()->withoutExceptionHandling(); $this->login()->loginNami()->withoutExceptionHandling();
@ -72,14 +56,17 @@ class FormUpdateActionTest extends FormTestCase
public function testItUpdatesActiveColumnsWhenFieldRemoved(): void public function testItUpdatesActiveColumnsWhenFieldRemoved(): void
{ {
$this->login()->loginNami()->withoutExceptionHandling(); $this->login()->loginNami()->withoutExceptionHandling();
$form = Form::factory()->fields([ $form = Form::factory()
$this->textField('firstname'), ->sections([FormtemplateSectionRequest::new()->fields([
$this->textField('geb'), $this->textField('firstname'),
$this->textField('lastname'), $this->textField('geb'),
]) $this->textField('lastname'),
])])
->create(); ->create();
$payload = FormRequest::new()->fields([ $payload = FormRequest::new()->sections([
$this->textField('firstname'), FormtemplateSectionRequest::new()->fields([
$this->textField('firstname'),
])
])->create(); ])->create();
$this->patchJson(route('form.update', ['form' => $form]), $payload)->assertSessionDoesntHaveErrors()->assertOk(); $this->patchJson(route('form.update', ['form' => $form]), $payload)->assertSessionDoesntHaveErrors()->assertOk();
@ -126,12 +113,14 @@ class FormUpdateActionTest extends FormTestCase
{ {
$this->login()->loginNami()->withoutExceptionHandling(); $this->login()->loginNami()->withoutExceptionHandling();
$form = Form::factory() $form = Form::factory()
->fields([]) ->sections([FormtemplateSectionRequest::new()->fields([])])
->create(); ->create();
$payload = FormRequest::new()->fields([ $payload = FormRequest::new()->sections([
$this->textField('firstname'), FormtemplateSectionRequest::new()->fields([
$this->textField('geb'), $this->textField('firstname'),
$this->textField('lastname'), $this->textField('geb'),
$this->textField('lastname'),
])
])->create(); ])->create();
$this->patchJson(route('form.update', ['form' => $form]), $payload)->assertSessionDoesntHaveErrors()->assertOk(); $this->patchJson(route('form.update', ['form' => $form]), $payload)->assertSessionDoesntHaveErrors()->assertOk();

View File

@ -83,16 +83,6 @@ class FormtemplateIndexActionTest extends TestCase
]) ])
->assertInertiaPath('data.meta.default', [ ->assertInertiaPath('data.meta.default', [
'name' => '', 'name' => '',
'mail_top' => [
'version' => '1.0',
'blocks' => [],
'time' => 0,
],
'mail_bottom' => [
'version' => '1.0',
'blocks' => [],
'time' => 0,
],
'config' => [ 'config' => [
'sections' => [], 'sections' => [],
] ]

View File

@ -2,13 +2,10 @@
namespace Tests\Feature\Form; namespace Tests\Feature\Form;
use Tests\RequestFactories\EditorRequestFactory;
use Worksome\RequestFactories\RequestFactory; use Worksome\RequestFactories\RequestFactory;
/** /**
* @method self name(string $name) * @method self name(string $name)
* @method self mailTop(?EditorRequestFactory $content)
* @method self mailBottom(?EditorRequestFactory $content)
*/ */
class FormtemplateRequest extends RequestFactory class FormtemplateRequest extends RequestFactory
{ {
@ -36,6 +33,6 @@ class FormtemplateRequest extends RequestFactory
*/ */
public function __call(string $method, $args): self public function __call(string $method, $args): self
{ {
return $this->state([str($method)->snake()->toString() => $args[0]]); return $this->state([$method => $args[0]]);
} }
} }

View File

@ -10,7 +10,6 @@ use App\Lib\Events\Succeeded;
use Illuminate\Foundation\Testing\DatabaseTransactions; use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Support\Facades\Event; use Illuminate\Support\Facades\Event;
use Generator; use Generator;
use Tests\RequestFactories\EditorRequestFactory;
class FormtemplateStoreActionTest extends FormTestCase class FormtemplateStoreActionTest extends FormTestCase
{ {
@ -21,17 +20,14 @@ class FormtemplateStoreActionTest extends FormTestCase
{ {
Event::fake([Succeeded::class]); Event::fake([Succeeded::class]);
$this->login()->loginNami()->withoutExceptionHandling(); $this->login()->loginNami()->withoutExceptionHandling();
$payload = FormtemplateRequest::new()->name('testname')->sections([ FormtemplateRequest::new()->name('testname')->sections([
FormtemplateSectionRequest::new()->name('Persönliches')->fields([ FormtemplateSectionRequest::new()->name('Persönliches')->fields([
$this->textField('a')->name('lala1')->columns(['mobile' => 2, 'tablet' => 2, 'desktop' => 1])->required(false)->hint('hhh')->intro('intro'), $this->textField('a')->name('lala1')->columns(['mobile' => 2, 'tablet' => 2, 'desktop' => 1])->required(false)->hint('hhh')->intro('intro'),
$this->textareaField('b')->name('lala2')->required(false)->specialType(SpecialType::FIRSTNAME)->rows(10), $this->textareaField('b')->name('lala2')->required(false)->specialType(SpecialType::FIRSTNAME)->rows(10),
]), ]),
]) ])->fake();
->mailTop(EditorRequestFactory::new()->text(10, 'lala'))
->mailBottom(EditorRequestFactory::new()->text(10, 'lblb'))
->create();
$this->postJson(route('formtemplate.store'), $payload)->assertOk(); $this->postJson(route('formtemplate.store'))->assertOk();
$formtemplate = Formtemplate::latest()->first(); $formtemplate = Formtemplate::latest()->first();
$this->assertEquals('Persönliches', $formtemplate->config->sections->get(0)->name); $this->assertEquals('Persönliches', $formtemplate->config->sections->get(0)->name);
@ -45,8 +41,6 @@ class FormtemplateStoreActionTest extends FormTestCase
$this->assertEquals(SpecialType::FIRSTNAME, $formtemplate->config->sections->get(0)->fields->get(1)->specialType); $this->assertEquals(SpecialType::FIRSTNAME, $formtemplate->config->sections->get(0)->fields->get(1)->specialType);
$this->assertEquals(['mobile' => 2, 'tablet' => 2, 'desktop' => 1], $formtemplate->config->sections->get(0)->fields->get(0)->columns->toArray()); $this->assertEquals(['mobile' => 2, 'tablet' => 2, 'desktop' => 1], $formtemplate->config->sections->get(0)->fields->get(0)->columns->toArray());
$this->assertEquals(10, $formtemplate->config->sections->get(0)->fields->get(1)->rows); $this->assertEquals(10, $formtemplate->config->sections->get(0)->fields->get(1)->rows);
$this->assertEquals('lala', $formtemplate->mail_top->blocks[0]['data']['text']);
$this->assertEquals('lblb', $formtemplate->mail_bottom->blocks[0]['data']['text']);
$this->assertFalse($formtemplate->config->sections->get(0)->fields->get(0)->required); $this->assertFalse($formtemplate->config->sections->get(0)->fields->get(0)->required);
Event::assertDispatched(Succeeded::class, fn (Succeeded $event) => $event->message === 'Vorlage gespeichert.'); Event::assertDispatched(Succeeded::class, fn (Succeeded $event) => $event->message === 'Vorlage gespeichert.');
} }

View File

@ -2,12 +2,10 @@
namespace Tests\Feature\Form; namespace Tests\Feature\Form;
use App\Form\Models\Form;
use App\Form\Models\Formtemplate; use App\Form\Models\Formtemplate;
use App\Lib\Events\Succeeded; use App\Lib\Events\Succeeded;
use Illuminate\Foundation\Testing\DatabaseTransactions; use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Support\Facades\Event; use Illuminate\Support\Facades\Event;
use Tests\RequestFactories\EditorRequestFactory;
use Tests\TestCase; use Tests\TestCase;
class FormtemplateUpdateActionTest extends TestCase class FormtemplateUpdateActionTest extends TestCase
@ -31,22 +29,6 @@ class FormtemplateUpdateActionTest extends TestCase
Event::assertDispatched(Succeeded::class, fn (Succeeded $event) => $event->message === 'Vorlage aktualisiert.'); Event::assertDispatched(Succeeded::class, fn (Succeeded $event) => $event->message === 'Vorlage aktualisiert.');
} }
public function testItUpdatesTexts(): void
{
$this->login()->loginNami()->withoutExceptionHandling();
$formtemplate = Formtemplate::factory()->create();
$payload = FormtemplateRequest::new()
->mailTop(EditorRequestFactory::new()->text(10, 'lala'))
->mailBottom(EditorRequestFactory::new()->text(10, 'lalb'))
->create();
$this->patchJson(route('formtemplate.update', ['formtemplate' => $formtemplate]), $payload)
->assertOk();
$this->assertEquals('lala', Formtemplate::first()->mail_top->blocks[0]['data']['text']);
$this->assertEquals('lalb', Formtemplate::first()->mail_bottom->blocks[0]['data']['text']);
}
public function testNameIsRequired(): void public function testNameIsRequired(): void
{ {
$this->login()->loginNami(); $this->login()->loginNami();