From f6aef7cee546c10a75eb38c0cedf1d4910fe256e Mon Sep 17 00:00:00 2001 From: philipp lang Date: Thu, 24 Oct 2024 22:42:30 +0200 Subject: [PATCH] Add data type cast for Mailgateway --- app/Mailgateway/Casts/TypeCast.php | 42 --------------- app/Mailgateway/Models/Mailgateway.php | 4 +- .../Resources/MailgatewayResource.php | 1 - app/Mailgateway/Types/Type.php | 19 +++---- .../Mailgateway/Models/MailgatewayFactory.php | 17 ++---- modules/Mailgateway/Components/Form.php | 44 +++++++-------- modules/Mailgateway/IndexTest.php | 7 ++- modules/Mailgateway/StoreTest.php | 54 +++++++++---------- modules/Mailgateway/UpdateTest.php | 51 ++++++++++-------- 9 files changed, 91 insertions(+), 148 deletions(-) delete mode 100644 app/Mailgateway/Casts/TypeCast.php diff --git a/app/Mailgateway/Casts/TypeCast.php b/app/Mailgateway/Casts/TypeCast.php deleted file mode 100644 index 7fa30867..00000000 --- a/app/Mailgateway/Casts/TypeCast.php +++ /dev/null @@ -1,42 +0,0 @@ - - */ -class TypeCast implements CastsAttributes -{ - /** - * Cast the given value. - * - * @param \Illuminate\Database\Eloquent\Model $model - * @param mixed $value - * @param array $attributes - * - * @return mixed - */ - public function get($model, string $key, $value, array $attributes) - { - $value = json_decode($value, true); - - return app($value['cls'])->setParams($value['params']); - } - - /** - * Prepare the given value for storage. - * - * @param \Illuminate\Database\Eloquent\Model $model - * @param mixed $value - * @param array $attributes - * - * @return mixed - */ - public function set($model, string $key, $value, array $attributes) - { - return json_encode($value); - } -} diff --git a/app/Mailgateway/Models/Mailgateway.php b/app/Mailgateway/Models/Mailgateway.php index 5f9a5aa1..2dd41b04 100644 --- a/app/Mailgateway/Models/Mailgateway.php +++ b/app/Mailgateway/Models/Mailgateway.php @@ -2,7 +2,7 @@ namespace App\Mailgateway\Models; -use App\Mailgateway\Casts\TypeCast; +use App\Mailgateway\Types\Type; use Database\Factories\Mailgateway\Models\MailgatewayFactory; use Illuminate\Database\Eloquent\Concerns\HasUuids; use Illuminate\Database\Eloquent\Factories\HasFactory; @@ -14,6 +14,6 @@ class Mailgateway extends Model use HasFactory; use HasUuids; - public $casts = ['type' => TypeCast::class]; + public $casts = ['type' => Type::class]; public $guarded = []; } diff --git a/app/Mailgateway/Resources/MailgatewayResource.php b/app/Mailgateway/Resources/MailgatewayResource.php index a77fc8cd..d27a838f 100644 --- a/app/Mailgateway/Resources/MailgatewayResource.php +++ b/app/Mailgateway/Resources/MailgatewayResource.php @@ -28,7 +28,6 @@ class MailgatewayResource extends JsonResource 'domain' => $this->domain, 'type_human' => $this->type::name(), 'works' => $this->type->works(), - 'type' => $this->type->toResource(), 'id' => $this->id, 'links' => [ 'update' => route('mailgateway.update', ['mailgateway' => $this->getModel()]), diff --git a/app/Mailgateway/Types/Type.php b/app/Mailgateway/Types/Type.php index 7fd3dce0..6611da10 100644 --- a/app/Mailgateway/Types/Type.php +++ b/app/Mailgateway/Types/Type.php @@ -4,9 +4,15 @@ namespace App\Mailgateway\Types; use App\Maildispatcher\Data\MailEntry; use Illuminate\Support\Collection; +use Livewire\Wireable; +use Spatie\LaravelData\Concerns\WireableData; +use Spatie\LaravelData\Data; -abstract class Type +abstract class Type extends Data implements Wireable { + + use WireableData; + abstract public static function name(): string; /** @@ -67,17 +73,6 @@ abstract class Type ])->toArray(); } - /** - * @return array> - */ - public function toResource(): array - { - return [ - 'cls' => get_class($this), - 'params' => get_object_vars($this), - ]; - } - /** * @param Collection $results */ diff --git a/database/factories/Mailgateway/Models/MailgatewayFactory.php b/database/factories/Mailgateway/Models/MailgatewayFactory.php index 485b303a..968599a4 100644 --- a/database/factories/Mailgateway/Models/MailgatewayFactory.php +++ b/database/factories/Mailgateway/Models/MailgatewayFactory.php @@ -3,6 +3,7 @@ namespace Database\Factories\Mailgateway\Models; use App\Mailgateway\Models\Mailgateway; +use App\Mailgateway\Types\LocalType; use App\Mailgateway\Types\Type; use Illuminate\Database\Eloquent\Factories\Factory; @@ -22,24 +23,14 @@ class MailgatewayFactory extends Factory { return [ 'name' => $this->faker->words(5, true), - 'type' => [ - 'cls' => app('mail-gateways')->random(), - 'params' => [], - ], + 'type' => new LocalType(), 'domain' => $this->faker->safeEmailDomain(), ]; } - /** - * @param class-string $type - * @param array $params - */ - public function type(string $type, array $params): self + public function type(Type $type): self { - return $this->state(['type' => [ - 'cls' => $type, - 'params' => $params, - ]]); + return $this->state(['type' => $type]); } public function name(string $name): self diff --git a/modules/Mailgateway/Components/Form.php b/modules/Mailgateway/Components/Form.php index c24b3ff7..b9adde5f 100644 --- a/modules/Mailgateway/Components/Form.php +++ b/modules/Mailgateway/Components/Form.php @@ -3,8 +3,8 @@ namespace Modules\Mailgateway\Components; use App\Mailgateway\Models\Mailgateway; +use App\Mailgateway\Types\Type; use Illuminate\Support\Collection; -use Illuminate\Validation\Rule; use Illuminate\Validation\ValidationException; use Livewire\Attributes\On; use Livewire\Attributes\Validate; @@ -15,9 +15,9 @@ class Form extends Component public string $name = ''; public string $domain = ''; - public array $params = []; - #[Validate('required')] - public ?string $cls = null; + public ?Type $type = null; + #[Validate('required|string')] + public ?string $typeClass = null; public Collection $types; public ?Mailgateway $model = null; @@ -26,19 +26,17 @@ class Form extends Component return [ 'name' => 'required|string|max:255', 'domain' => 'required|string|max:255', - 'cls' => ['required', 'string', 'max:255', Rule::in(app('mail-gateways'))], - 'params' => 'present|array', - ...$this->cls ? collect($this->cls::rules())->mapWithKeys(fn ($rules, $key) => ["params.{$key}" => $rules]) : [], + ...$this->type ? collect($this->type::rules())->mapWithKeys(fn ($rules, $key) => ["type.{$key}" => $rules]) : [], ]; } public function validationAttributes(): array { return [ - 'cls' => 'Typ', + 'type' => 'Typ', 'name' => 'Beschreibung', 'domain' => 'Domain', - ...$this->cls ? collect($this->cls::fieldNames())->mapWithKeys(fn ($attribute, $key) => ["params.{$key}" => $attribute]) : [], + ...$this->type ? collect($this->type::fieldNames())->mapWithKeys(fn ($attribute, $key) => ["params.{$key}" => $attribute]) : [], ]; } @@ -53,19 +51,23 @@ class Form extends Component $this->model = Mailgateway::find($id); $this->name = $this->model->name; $this->domain = $this->model->domain; - $this->cls = get_class($this->model->type); - $this->params = (array) $this->model->type; + $this->type = $this->model->type; + $this->typeClass = get_class($this->model->type); } } - public function updatedType(string $type): void - { - $this->params = $type::defaults(); - } - public function fields(): array { - return $this->cls ? $this->cls::fields() : []; + return $this->type ? $this->type::fields() : []; + } + + public function updatedTypeClass(?string $type): void + { + if (!$type) { + return; + } + + $this->type = $type::from([]); } #[On('onStoreFromModal')] @@ -73,14 +75,14 @@ class Form extends Component { $this->validate(); - if (!app($this->cls)->setParams($this->params)->works()) { + if (!$this->type->works()) { throw ValidationException::withMessages(['connection' => 'Verbindung fehlgeschlagen.']); } $payload = [ 'name' => $this->name, 'domain' => $this->domain, - 'type' => ['cls' => $this->cls, 'params' => $this->params], + 'type' => $this->type, ]; if ($this->model) { $this->model->update($payload); @@ -99,11 +101,11 @@ class Form extends Component
- + @foreach($this->fields() as $index => $field) withoutExceptionHandling()->login()->loginNami(); - Mailgateway::factory()->type(LocalType::class, [])->name('Lore')->domain('example.com')->create(); + Mailgateway::factory()->type(LocalType::from([]))->name('Lore')->domain('example.com')->create(); Livewire::test(SettingView::class) ->assertSeeHtml('example.com') @@ -32,8 +31,8 @@ it('test it displays local gateways', function () { it('displays mailman gateways', function () { test()->withoutExceptionHandling()->login()->loginNami(); - $typeParams = MailmanTypeRequest::new()->succeeds()->create(['url' => 'https://mailman.example.com', 'user' => 'user', 'password' => 'password', 'owner' => 'owner']); - Mailgateway::factory()->type(MailmanType::class, $typeParams)->create(); + $typeParams = MailmanTypeRequest::new()->succeeds()->state(['url' => 'https://mailman.example.com', 'user' => 'user', 'password' => 'password', 'owner' => 'owner']); + Mailgateway::factory()->type($typeParams->toData())->create(); Livewire::test(SettingView::class)->assertSeeHtml('Verbindung erfolgreich'); }); diff --git a/modules/Mailgateway/StoreTest.php b/modules/Mailgateway/StoreTest.php index 0798225c..69c8445b 100644 --- a/modules/Mailgateway/StoreTest.php +++ b/modules/Mailgateway/StoreTest.php @@ -17,39 +17,32 @@ it('test it saves a mail gateway', function () { test()->withoutExceptionHandling()->login()->loginNami(); Livewire::test(Form::class) + ->set('typeClass', LocalType::class) ->set('name', 'lala') ->set('domain', 'example.com') - ->set('cls', LocalType::class) ->call('onSave') + ->assertHasNoErrors() ->assertDispatched('closeModal') ->assertDispatched('refresh-page') ->assertDispatched('success'); - $this->assertDatabaseHas('mailgateways', [ + test()->assertDatabaseHas('mailgateways', [ 'domain' => 'example.com', 'name' => 'lala', 'type' => json_encode([ - 'cls' => LocalType::class, - 'params' => [], + 'type' => LocalType::class, + 'data' => [], ]), ]); }); -it('validates type', function () { - test()->withoutExceptionHandling()->login()->loginNami(); - - Livewire::test(Form::class) - ->set('cls', '') - ->assertHasErrors(['cls' => 'required']); -}); - it('test it validates mail gateway', function (array $attributes, array $errors) { test()->withoutExceptionHandling()->login()->loginNami(); Livewire::test(Form::class) ->set('name', 'lala') ->set('domain', 'example.com') - ->set('cls', LocalType::class) + ->set('typeClass', LocalType::class) ->setArray($attributes) ->call('onSave') ->assertHasErrors($errors) @@ -59,6 +52,7 @@ it('test it validates mail gateway', function (array $attributes, array $errors) })->with([ [['name' => ''], ['name' => 'required']], [['domain' => ''], ['domain' => 'required']], + [['typeClass' => ''], ['typeClass' => 'required']], ]); it('test it validates mailman type', function (array $attributes, array $errors) { @@ -67,20 +61,20 @@ it('test it validates mailman type', function (array $attributes, array $errors) Livewire::test(Form::class) ->set('name', 'lala') ->set('domain', 'example.com') - ->set('cls', MailmanType::class) - ->set('params.url', 'exampl.com') - ->set('params.user', '::user::') - ->set('params.password', 'password') + ->set('typeClass', MailmanType::class) + ->set('type.url', 'exampl.com') + ->set('type.user', '::user::') + ->set('type.password', 'password') ->setArray($attributes) ->call('onSave') ->assertHasErrors($errors) ->assertNotDispatched('closeModal'); })->with([ - [['params.url' => ''], ['params.url' => 'required']], - [['params.user' => ''], ['params.user' => 'required']], - [['params.password' => ''], ['params.password' => 'required']], - [['params.owner' => ''], ['params.owner' => 'required']], - [['params.owner' => 'aaa'], ['params.owner' => 'email']], + [['type.url' => ''], ['type.url' => 'required']], + [['type.user' => ''], ['type.user' => 'required']], + [['type.password' => ''], ['type.password' => 'required']], + [['type.owner' => ''], ['type.owner' => 'required']], + [['type.owner' => 'aaa'], ['type.owner' => 'email']], ]); it('test it stores mailman gateway', function () { @@ -92,16 +86,16 @@ it('test it stores mailman gateway', function () { ->setArray([ 'name' => 'lala', 'domain' => 'https://example.com', - 'cls' => MailmanType::class, - 'params' => $typeParams + 'typeClass' => MailmanType::class, ]) + ->setArray('type', $typeParams) ->call('onSave') ->assertDispatched('closeModal'); - $this->assertDatabaseHas('mailgateways', [ + test()->assertDatabaseHas('mailgateways', [ 'type' => json_encode([ - 'cls' => MailmanType::class, - 'params' => $typeParams, + 'type' => MailmanType::class, + 'data' => $typeParams, ]), 'name' => 'lala', 'domain' => 'https://example.com', @@ -117,12 +111,12 @@ it('test it checks mailman connection', function () { ->setArray([ 'name' => 'lala', 'domain' => 'https://example.com', - 'cls' => MailmanType::class, - 'params' => $typeParams + 'typeClass' => MailmanType::class, ]) + ->setArray('type', $typeParams) ->call('onSave') ->assertHasErrors('connection') ->assertNotDispatched('closeModal'); - $this->assertDatabaseCount('mailgateways', 0); + test()->assertDatabaseCount('mailgateways', 0); }); diff --git a/modules/Mailgateway/UpdateTest.php b/modules/Mailgateway/UpdateTest.php index dd4e3907..8526d9fb 100644 --- a/modules/Mailgateway/UpdateTest.php +++ b/modules/Mailgateway/UpdateTest.php @@ -17,47 +17,52 @@ uses(TestCase::class); it('test it sets attributes for mailman', function () { test()->withoutExceptionHandling()->login()->loginNami(); - $typeParams = MailmanTypeRequest::new()->create(['url' => 'https://mailman.example.com', 'user' => 'user', 'password' => 'password', 'owner' => 'owner']); - $mailgateway = Mailgateway::factory()->type(MailmanType::class, $typeParams)->create(['name' => '::name::', 'domain' => 'example.com']); + $typeParams = MailmanTypeRequest::new()->state(['url' => 'https://mailman.example.com', 'user' => 'user', 'password' => 'password', 'owner' => 'owner']); + $mailgateway = Mailgateway::factory()->type($typeParams->toData())->create(['name' => '::name::', 'domain' => 'example.com']); Livewire::test(Form::class, ['id' => $mailgateway->id]) ->assertSet('model', fn ($m) => $m->is($mailgateway)) ->assertSet('name', '::name::') ->assertSet('domain', 'example.com') - ->assertSet('cls', MailmanType::class) - ->assertSet('params.url', 'https://mailman.example.com') - ->assertSet('params.user', 'user') - ->assertSet('params.password', 'password') - ->assertSet('params.owner', 'owner'); + ->assertSet( + 'type', + fn ($type) => $type instanceof MailmanType + && $type->url === 'https://mailman.example.com' + && $type->user === 'user' && + $type->password === 'password' + && $type->owner === 'owner' + ); }); it('test it sets attributes for local', function () { test()->withoutExceptionHandling()->login()->loginNami(); - $mailgateway = Mailgateway::factory()->type(LocalType::class, [])->create(['name' => '::name::', 'domain' => 'example.com']); + $mailgateway = Mailgateway::factory()->create(['name' => '::name::', 'domain' => 'example.com']); Livewire::test(Form::class, ['id' => $mailgateway->id]) ->assertSet('name', '::name::') ->assertSet('domain', 'example.com') - ->assertSet('cls', LocalType::class) - ->assertSet('params', []); + ->assertSet('type', fn ($type) => $type instanceof LocalType); }); it('test it validates type', function () { test()->withoutExceptionHandling()->login()->loginNami(); - $mailgateway = Mailgateway::factory()->type(LocalType::class, [])->create(['name' => '::name::', 'domain' => 'example.com']); + $mailgateway = Mailgateway::factory()->create(['name' => '::name::', 'domain' => 'example.com']); Livewire::test(Form::class, ['id' => $mailgateway->id]) - ->set('cls', '') - ->assertHasErrors(['cls' => 'required']); + ->set('typeClass', '') + ->assertHasErrors(['typeClass' => 'required']); }); it('test it updates a mailman gateway without updating password', function () { test()->withoutExceptionHandling()->login()->loginNami(); - $typeParams = MailmanTypeRequest::new()->succeeds()->create(['url' => 'https://mailman.example.com', 'user' => 'user', 'password' => 'password', 'owner' => 'owner@example.com']); - $mailgateway = Mailgateway::factory()->type(MailmanType::class, $typeParams)->create(['name' => '::name::', 'domain' => 'example.com']); + $typeParams = MailmanTypeRequest::new() + ->succeeds() + ->state(['url' => 'https://mailman.example.com', 'user' => 'user', 'password' => 'password', 'owner' => 'owner@example.com']) + ->toData(); + $mailgateway = Mailgateway::factory()->type($typeParams)->create(['name' => '::name::', 'domain' => 'example.com']); Livewire::test(Form::class, ['id' => $mailgateway->id]) ->set('name', '::newname::') @@ -70,37 +75,37 @@ it('test it updates a mailman gateway without updating password', function () { $this->assertDatabaseCount('mailgateways', 1); $this->assertDatabaseHas('mailgateways', [ 'name' => '::newname::', - 'type' => json_encode(['cls' => MailmanType::class, 'params' => $typeParams]), + 'type' => json_encode(['type' => MailmanType::class, 'data' => $typeParams]), ]); }); it('test it updates a mailman gateway with password', function () { test()->withoutExceptionHandling()->login()->loginNami(); - $typeParams = MailmanTypeRequest::new()->create(['url' => 'https://mailman.example.com', 'user' => 'user', 'password' => 'password', 'owner' => 'owner@example.com']); + $typeParams = MailmanTypeRequest::new()->state(['url' => 'https://mailman.example.com', 'user' => 'user', 'password' => 'password', 'owner' => 'owner@example.com']); $newTypeParams = MailmanTypeRequest::new()->succeeds()->create(['url' => 'https://mailman.example.com', 'user' => 'newuser', 'password' => 'password', 'owner' => 'owner@example.com']); - $mailgateway = Mailgateway::factory()->type(MailmanType::class, $typeParams)->create(); + $mailgateway = Mailgateway::factory()->type($typeParams->toData())->create(); Livewire::test(Form::class, ['id' => $mailgateway->id]) - ->set('params.user', 'newuser') + ->set('type.user', 'newuser') ->call('onSave') ->assertHasNoErrors(); $this->assertDatabaseCount('mailgateways', 1); $this->assertDatabaseHas('mailgateways', [ - 'type' => json_encode(['cls' => MailmanType::class, 'params' => $newTypeParams]), + 'type' => json_encode(['type' => MailmanType::class, 'data' => $newTypeParams]), ]); }); it('test it checks mailgateway connection when updating', function () { test()->withoutExceptionHandling()->login()->loginNami(); - $typeParams = MailmanTypeRequest::new()->create(['url' => 'https://mailman.example.com', 'user' => 'user', 'password' => 'password', 'owner' => 'owner@example.com']); + $typeParams = MailmanTypeRequest::new()->state(['url' => 'https://mailman.example.com', 'user' => 'user', 'password' => 'password', 'owner' => 'owner@example.com']); MailmanTypeRequest::new()->fails()->create(['url' => 'https://mailman.example.com', 'user' => 'newuser', 'password' => 'password', 'owner' => 'owner@example.com']); - $mailgateway = Mailgateway::factory()->type(MailmanType::class, $typeParams)->create(); + $mailgateway = Mailgateway::factory()->type($typeParams->toData())->create(); Livewire::test(Form::class, ['id' => $mailgateway->id]) - ->set('params.user', 'newuser') + ->set('type.user', 'newuser') ->call('onSave') ->assertHasErrors('connection'); });