Add filter for mail top and mail bottom
This commit is contained in:
parent
21dfc4f0b2
commit
1929c8c216
|
@ -0,0 +1,51 @@
|
|||
<?php
|
||||
|
||||
namespace App\Form\Editor;
|
||||
|
||||
use App\Form\Models\Participant;
|
||||
use App\Lib\Editor\ConditionResolver;
|
||||
|
||||
class FormConditionResolver extends ConditionResolver
|
||||
{
|
||||
|
||||
private Participant $participant;
|
||||
|
||||
public function forParticipant(Participant $participant): self
|
||||
{
|
||||
$this->participant = $participant;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function filterBlock(array $block): bool
|
||||
{
|
||||
$mode = data_get($block, 'tunes.condition.mode', 'any');
|
||||
$ifs = data_get($block, 'tunes.condition.ifs', []);
|
||||
|
||||
if (count($ifs) === 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
foreach ($ifs as $if) {
|
||||
$field = $this->participant->getFields()->findByKey($if['field']);
|
||||
$matches = $field->matches($if['comparator'], $if['value']);
|
||||
if ($matches && $mode === 'any') {
|
||||
return true;
|
||||
}
|
||||
if (!$matches && $mode === 'all') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if ($mode === 'any') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($mode === 'all') {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
namespace App\Form\Fields;
|
||||
|
||||
use App\Form\Matchers\BooleanMatcher;
|
||||
use App\Form\Matchers\Matcher;
|
||||
use App\Form\Models\Form;
|
||||
use App\Form\Models\Participant;
|
||||
use App\Form\Presenters\BooleanPresenter;
|
||||
|
@ -79,4 +81,9 @@ class CheckboxField extends Field
|
|||
{
|
||||
return app(BooleanPresenter::class);
|
||||
}
|
||||
|
||||
public function getMatcher(): Matcher
|
||||
{
|
||||
return app(BooleanMatcher::class);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
namespace App\Form\Fields;
|
||||
|
||||
use App\Form\Matchers\Matcher;
|
||||
use App\Form\Matchers\SingleValueMatcher;
|
||||
use App\Form\Models\Form;
|
||||
use App\Form\Models\Participant;
|
||||
use Faker\Generator;
|
||||
|
@ -80,4 +82,9 @@ class DropdownField extends Field
|
|||
public function afterRegistration(Form $form, Participant $participant, array $input): void
|
||||
{
|
||||
}
|
||||
|
||||
public function getMatcher(): Matcher
|
||||
{
|
||||
return app(SingleValueMatcher::class);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -165,4 +165,9 @@ abstract class Field extends Data
|
|||
{
|
||||
return $this->key . '_display';
|
||||
}
|
||||
|
||||
public function matches(string $comparator, mixed $value): bool
|
||||
{
|
||||
return $this->getMatcher()->setValue($this->value)->matches($comparator, $value);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
namespace App\Form\Fields;
|
||||
|
||||
use App\Form\Matchers\Matcher;
|
||||
use App\Form\Matchers\SingleValueMatcher;
|
||||
use App\Form\Models\Form;
|
||||
use App\Form\Models\Participant;
|
||||
use Faker\Generator;
|
||||
|
@ -80,4 +82,9 @@ class RadioField extends Field
|
|||
public function afterRegistration(Form $form, Participant $participant, array $input): void
|
||||
{
|
||||
}
|
||||
|
||||
public function getMatcher(): Matcher
|
||||
{
|
||||
return app(SingleValueMatcher::class);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
namespace App\Form\Mails;
|
||||
|
||||
use App\Form\Data\FormConfigData;
|
||||
use App\Form\Editor\FormConditionResolver;
|
||||
use App\Form\Models\Participant;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Mail\Attachment;
|
||||
|
@ -10,7 +11,6 @@ use Illuminate\Mail\Mailable;
|
|||
use Illuminate\Mail\Mailables\Content;
|
||||
use Illuminate\Mail\Mailables\Envelope;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
|
||||
class ConfirmRegistrationMail extends Mailable
|
||||
{
|
||||
|
@ -18,6 +18,10 @@ class ConfirmRegistrationMail extends Mailable
|
|||
|
||||
public string $fullname;
|
||||
public FormConfigData $config;
|
||||
/** @var array<string, mixed> */
|
||||
public array $topText;
|
||||
/** @var array<string, mixed> */
|
||||
public array $bottomText;
|
||||
|
||||
/**
|
||||
* Create a new message instance.
|
||||
|
@ -26,8 +30,11 @@ class ConfirmRegistrationMail extends Mailable
|
|||
*/
|
||||
public function __construct(public Participant $participant)
|
||||
{
|
||||
$conditionResolver = app(FormConditionResolver::class)->forParticipant($participant);
|
||||
$this->fullname = $participant->getFields()->getFullname();
|
||||
$this->config = $participant->getConfig();
|
||||
$this->topText = $conditionResolver->make($participant->form->mail_top);
|
||||
$this->bottomText = $conditionResolver->make($participant->form->mail_bottom);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
<?php
|
||||
|
||||
namespace App\Form\Matchers;
|
||||
|
||||
class BooleanMatcher extends SingleValueMatcher
|
||||
{
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
<?php
|
||||
|
||||
namespace App\Form\Matchers;
|
||||
|
||||
abstract class Matcher
|
||||
{
|
||||
|
||||
public mixed $value;
|
||||
|
||||
public function setValue(mixed $value): self
|
||||
{
|
||||
$this->value = $value;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
abstract public function matches(string $comparator, mixed $value): bool;
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
|
||||
namespace App\Form\Matchers;
|
||||
|
||||
class SingleValueMatcher extends Matcher
|
||||
{
|
||||
|
||||
public function matches(string $comparator, mixed $value): bool
|
||||
{
|
||||
if ($comparator === 'isEqual' && $value === $this->value) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($comparator === 'isNotEqual' && $value !== $this->value) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($comparator === 'isIn' && in_array($this->value, $value)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($comparator === 'isNotIn' && !in_array($this->value, $value)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
<?php
|
||||
|
||||
namespace App\Lib\Editor;
|
||||
|
||||
abstract class ConditionResolver
|
||||
{
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $block
|
||||
*/
|
||||
abstract public function filterBlock(array $block): bool;
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $content
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function make(array $content): array
|
||||
{
|
||||
return array_filter($content['blocks'], fn ($block) => $this->filterBlock($block));
|
||||
}
|
||||
}
|
|
@ -7,6 +7,7 @@ use App\Mailgateway\Types\LocalType;
|
|||
use App\Mailgateway\Types\MailmanType;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
use Illuminate\Support\Facades\Blade;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
use Laravel\Telescope\Telescope;
|
||||
|
||||
|
@ -36,6 +37,8 @@ class AppServiceProvider extends ServiceProvider
|
|||
]));
|
||||
|
||||
app()->extend('media-library-helpers', fn ($p) => $p->put('form', Form::class));
|
||||
|
||||
Blade::componentNamespace('App\\View\\Mail', 'mail-view');
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
|
||||
namespace App\View\Mail;
|
||||
|
||||
use Illuminate\View\Component;
|
||||
|
||||
class Editor extends Component
|
||||
{
|
||||
/**
|
||||
* Create a new component instance.
|
||||
*
|
||||
* @param array<int, mixed> $content
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(public array $content)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the view / contents that represent the component.
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\View|\Closure|string
|
||||
*/
|
||||
public function render()
|
||||
{
|
||||
return view('components.mail.editor');
|
||||
}
|
||||
}
|
|
@ -7,16 +7,15 @@ use Database\Factories\Traits\FakesMedia;
|
|||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
use Tests\Feature\Form\FormtemplateFieldRequest;
|
||||
use Tests\Feature\Form\FormtemplateSectionRequest;
|
||||
use Tests\RequestFactories\EditorRequestFactory;
|
||||
|
||||
/**
|
||||
* @extends Factory<Form>
|
||||
* @method self name(string $name)
|
||||
* @method self from(string $from)
|
||||
* @method self to(string $to)
|
||||
* @method self mailTop(string $content)
|
||||
* @method self mailBottom(string $content)
|
||||
* @method self excerpt(string $excerpt)
|
||||
* @method self description(string $description)
|
||||
* @method self description(EditorRequestFactory $description)
|
||||
* @method self registrationFrom(string|null $date)
|
||||
* @method self registrationUntil(string|null $date)
|
||||
*/
|
||||
|
@ -40,15 +39,15 @@ class FormFactory extends Factory
|
|||
{
|
||||
return [
|
||||
'name' => $this->faker->words(4, true),
|
||||
'description' => $this->faker->text(),
|
||||
'description' => EditorRequestFactory::new()->create(),
|
||||
'excerpt' => $this->faker->words(10, true),
|
||||
'config' => ['sections' => []],
|
||||
'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'),
|
||||
'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'),
|
||||
'mail_top' => $this->faker->text(),
|
||||
'mail_bottom' => $this->faker->text(),
|
||||
'mail_top' => EditorRequestFactory::new()->create(),
|
||||
'mail_bottom' => EditorRequestFactory::new()->create(),
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -75,4 +74,14 @@ class FormFactory extends Factory
|
|||
{
|
||||
return $this->state([str($method)->snake()->toString() => $parameters[0]]);
|
||||
}
|
||||
|
||||
public function mailTop(EditorRequestFactory $factory): self
|
||||
{
|
||||
return $this->state(['mail_top' => $factory->create()]);
|
||||
}
|
||||
|
||||
public function mailBottom(EditorRequestFactory $factory): self
|
||||
{
|
||||
return $this->state(['mail_bottom' => $factory->create()]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
@foreach ($content as $block)
|
||||
|
||||
@if ($block['type'] === 'paragraph')
|
||||
{!! $block['data']['text'] !!}
|
||||
@endif
|
||||
|
||||
@if ($block['type'] === 'heading' && data_get($block, 'data.level', 2) === 2)
|
||||
## {!! data_get($block, 'data.text') !!}
|
||||
@endif
|
||||
|
||||
@if ($block['type'] === 'heading' && data_get($block, 'data.level', 2) === 3)
|
||||
### {!! data_get($block, 'data.text') !!}
|
||||
@endif
|
||||
|
||||
@if ($block['type'] === 'heading' && data_get($block, 'data.level', 2) === 4)
|
||||
#### {!! data_get($block, 'data.text') !!}
|
||||
@endif
|
||||
|
||||
@if ($block['type'] === 'list' && data_get($block, 'data.style', 'unordered') === 'unordered')
|
||||
{!! collect(data_get($block, 'data.items', []))->map(fn ($item) => '* '.$item['content'])->implode("\n") !!}
|
||||
@endif
|
||||
|
||||
@if ($block['type'] === 'list' && data_get($block, 'data.style', 'unordered') === 'ordered')
|
||||
{!! collect(data_get($block, 'data.items', []))->map(fn ($item) => '1. '.$item['content'])->implode("\n") !!}
|
||||
@endif
|
||||
|
||||
@if ($block['type'] === 'alert')
|
||||
<x-mail::panel :type="$block['data']['type']">{!! data_get($block, 'data.message') !!}</x-mail::panel>
|
||||
@endif
|
||||
|
||||
@endforeach
|
|
@ -1,9 +1,8 @@
|
|||
@component('mail::message')
|
||||
<x-mail::message>
|
||||
|
||||
# Hallo {{$fullname}},
|
||||
|
||||
{{ $participant->form->mail_top }}
|
||||
|
||||
# Deine Daten
|
||||
<x-mail-view::editor :content="$topText"></x-mail-view::editor>
|
||||
|
||||
@foreach($config->sections as $section)
|
||||
## {{$section->name}}
|
||||
|
@ -12,6 +11,6 @@
|
|||
@endforeach
|
||||
@endforeach
|
||||
|
||||
{{ $participant->form->mail_bottom }}
|
||||
<x-mail-view::editor :content="$bottomText"></x-mail-view::editor>
|
||||
|
||||
@endcomponent
|
||||
</x-mail::message>
|
||||
|
|
|
@ -6,6 +6,7 @@ use App\Form\Enums\SpecialType;
|
|||
use App\Form\Mails\ConfirmRegistrationMail;
|
||||
use App\Form\Models\Form;
|
||||
use App\Form\Models\Participant;
|
||||
use Generator;
|
||||
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
||||
use Tests\RequestFactories\EditorRequestFactory;
|
||||
|
||||
|
@ -75,4 +76,166 @@ class FormRegisterMailTest extends FormTestCase
|
|||
$mail->assertHasAttachedData('content1', 'beispiel.pdf', ['mime' => 'application/pdf']);
|
||||
$mail->assertHasAttachedData('content2', 'beispiel2.pdf', ['mime' => 'application/pdf']);
|
||||
}
|
||||
|
||||
public function blockDataProvider(): Generator
|
||||
{
|
||||
yield [
|
||||
['mode' => 'all', 'ifs' => []],
|
||||
$this->dropdownField('fieldkey')->options(['A', 'B']),
|
||||
['fieldkey' => 'A'],
|
||||
true,
|
||||
];
|
||||
|
||||
yield [
|
||||
['mode' => 'any', 'ifs' => []],
|
||||
$this->dropdownField('fieldkey')->options(['A', 'B']),
|
||||
['fieldkey' => 'A'],
|
||||
true,
|
||||
];
|
||||
|
||||
yield [
|
||||
['mode' => 'any', 'ifs' => []],
|
||||
$this->dropdownField('fieldkey')->options(['A', 'B']),
|
||||
['fieldkey' => 'A'],
|
||||
true,
|
||||
];
|
||||
|
||||
yield [
|
||||
['mode' => 'any', 'ifs' => [
|
||||
['field' => 'fieldkey', 'comparator' => 'isEqual', 'value' => 'A']
|
||||
]],
|
||||
$this->dropdownField('fieldkey')->options(['A', 'B']),
|
||||
['fieldkey' => 'A'],
|
||||
true,
|
||||
];
|
||||
|
||||
yield [
|
||||
['mode' => 'any', 'ifs' => [
|
||||
['field' => 'fieldkey', 'comparator' => 'isEqual', 'value' => 'B']
|
||||
]],
|
||||
$this->dropdownField('fieldkey')->options(['A', 'B']),
|
||||
['fieldkey' => 'A'],
|
||||
false,
|
||||
];
|
||||
|
||||
yield [
|
||||
['mode' => 'any', 'ifs' => [
|
||||
['field' => 'fieldkey', 'comparator' => 'isEqual', 'value' => 'B'],
|
||||
['field' => 'fieldkey', 'comparator' => 'isEqual', 'value' => 'A']
|
||||
]],
|
||||
$this->dropdownField('fieldkey')->options(['A', 'B']),
|
||||
['fieldkey' => 'A'],
|
||||
true,
|
||||
];
|
||||
|
||||
yield [
|
||||
['mode' => 'any', 'ifs' => [
|
||||
['field' => 'fieldkey', 'comparator' => 'isEqual', 'value' => 'B'],
|
||||
['field' => 'fieldkey', 'comparator' => 'isEqual', 'value' => 'A']
|
||||
]],
|
||||
$this->dropdownField('fieldkey')->options(['A', 'B']),
|
||||
['fieldkey' => 'B'],
|
||||
true,
|
||||
];
|
||||
|
||||
yield [
|
||||
['mode' => 'all', 'ifs' => [
|
||||
['field' => 'fieldkey', 'comparator' => 'isEqual', 'value' => 'B'],
|
||||
['field' => 'fieldkey', 'comparator' => 'isEqual', 'value' => 'A']
|
||||
]],
|
||||
$this->dropdownField('fieldkey')->options(['A', 'B']),
|
||||
['fieldkey' => 'B'],
|
||||
false,
|
||||
];
|
||||
|
||||
yield [
|
||||
['mode' => 'all', 'ifs' => [
|
||||
['field' => 'fieldkey', 'comparator' => 'isEqual', 'value' => 'B']
|
||||
]],
|
||||
$this->dropdownField('fieldkey')->options(['A', 'B']),
|
||||
['fieldkey' => 'B'],
|
||||
true,
|
||||
];
|
||||
|
||||
yield [
|
||||
['mode' => 'all', 'ifs' => [
|
||||
['field' => 'fieldkey', 'comparator' => 'isNotEqual', 'value' => 'A']
|
||||
]],
|
||||
$this->dropdownField('fieldkey')->options(['A', 'B']),
|
||||
['fieldkey' => 'B'],
|
||||
true,
|
||||
];
|
||||
|
||||
yield [
|
||||
['mode' => 'all', 'ifs' => [
|
||||
['field' => 'fieldkey', 'comparator' => 'isIn', 'value' => ['A']]
|
||||
]],
|
||||
$this->dropdownField('fieldkey')->options(['A', 'B']),
|
||||
['fieldkey' => 'A'],
|
||||
true,
|
||||
];
|
||||
|
||||
yield [
|
||||
['mode' => 'all', 'ifs' => [
|
||||
['field' => 'fieldkey', 'comparator' => 'isNotIn', 'value' => ['B']]
|
||||
]],
|
||||
$this->dropdownField('fieldkey')->options(['A', 'B']),
|
||||
['fieldkey' => 'A'],
|
||||
true,
|
||||
];
|
||||
|
||||
yield [
|
||||
['mode' => 'all', 'ifs' => [
|
||||
['field' => 'fieldkey', 'comparator' => 'isNotIn', 'value' => ['B']]
|
||||
]],
|
||||
$this->radioField('fieldkey')->options(['A', 'B']),
|
||||
['fieldkey' => 'A'],
|
||||
true,
|
||||
];
|
||||
|
||||
yield [
|
||||
['mode' => 'all', 'ifs' => [
|
||||
['field' => 'fieldkey', 'comparator' => 'isEqual', 'value' => true]
|
||||
]],
|
||||
$this->checkboxField('fieldkey'),
|
||||
['fieldkey' => true],
|
||||
true,
|
||||
];
|
||||
|
||||
yield [
|
||||
['mode' => 'all', 'ifs' => [
|
||||
['field' => 'fieldkey', 'comparator' => 'isEqual', 'value' => false]
|
||||
]],
|
||||
$this->checkboxField('fieldkey'),
|
||||
['fieldkey' => true],
|
||||
false,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider blockDataProvider
|
||||
*/
|
||||
public function testItFiltersForBlockConditions(array $conditions, FormtemplateFieldRequest $field, array $participantValues, bool $result): void
|
||||
{
|
||||
$this->login()->loginNami()->withoutExceptionHandling();
|
||||
|
||||
$participant = Participant::factory()->for(
|
||||
Form::factory()
|
||||
->fields([
|
||||
$field,
|
||||
$this->textField('firstname')->specialType(SpecialType::FIRSTNAME),
|
||||
$this->textField('lastname')->specialType(SpecialType::LASTNAME),
|
||||
])
|
||||
->mailTop(EditorRequestFactory::new()->text(10, '::content::', $conditions))
|
||||
)
|
||||
->data(['firstname' => 'Max', 'lastname' => 'Muster', ...$participantValues])
|
||||
->create();
|
||||
|
||||
$mail = new ConfirmRegistrationMail($participant);
|
||||
if ($result) {
|
||||
$mail->assertSeeInText('::content::');
|
||||
} else {
|
||||
$mail->assertDontSeeInText('::content::');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,21 +20,28 @@ class EditorRequestFactory extends RequestFactory
|
|||
];
|
||||
}
|
||||
|
||||
public function text(int $id, string $text): self
|
||||
public function text(int $id, string $text, array $conditions = ['mode' => 'all', 'ifs' => []]): self
|
||||
{
|
||||
return $this->state($this->paragraphBlock($id, $text));
|
||||
return $this->state($this->paragraphBlock($id, $text, $conditions));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function paragraphBlock(int $id, string $text): array
|
||||
public function paragraphBlock(int $id, string $text, array $conditions = ['mode' => 'all', 'ifs' => []]): array
|
||||
{
|
||||
return [
|
||||
'time' => 1,
|
||||
'version' => '1.0',
|
||||
'blocks' => [
|
||||
['id' => $id, 'type' => 'paragraph', 'data' => ['text' => $text]]
|
||||
[
|
||||
'id' => $id,
|
||||
'type' => 'paragraph',
|
||||
'data' => ['text' => $text],
|
||||
'tunes' => [
|
||||
'condition' => $conditions
|
||||
]
|
||||
]
|
||||
],
|
||||
];
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue