Compare commits

...

5 Commits

Author SHA1 Message Date
philipp lang 7095c6ee22 Fixed tests
continuous-integration/drone/push Build is passing Details
2024-08-01 12:13:02 +02:00
philipp lang 69bfcf6c37 Remove viewable interface
continuous-integration/drone/push Build is failing Details
2024-08-01 11:32:14 +02:00
philipp lang 0eb93385d4 Add SettingView action
continuous-integration/drone/push Build is failing Details
2024-08-01 11:17:49 +02:00
philipp lang c2ce15957e Fix user principal 2024-08-01 10:28:35 +02:00
philipp lang 7eac71d424 Move Indexable to Viewable 2024-08-01 10:25:48 +02:00
25 changed files with 178 additions and 370 deletions

View File

@ -178,7 +178,7 @@ class Principal implements PrincipalBackendInterface
private function userToPrincipal(User $user): array private function userToPrincipal(User $user): array
{ {
return [ return [
'{DAV:}displayname' => $user->name, '{DAV:}displayname' => $user->firstname . ' ' . $user->lastname,
'uri' => 'principals/' . $user->email, 'uri' => 'principals/' . $user->email,
'{http://sabredav.org/ns}email-address' => $user->email, '{http://sabredav.org/ns}email-address' => $user->email,
]; ];

View File

@ -1,24 +0,0 @@
<?php
namespace App\Fileshare\Actions;
use App\Fileshare\Models\Fileshare;
use App\Fileshare\Resources\FileshareResource;
use Inertia\Inertia;
use Inertia\Response;
use Lorisleiva\Actions\Concerns\AsAction;
class FileshareIndexAction
{
use AsAction;
public function handle(): Response
{
session()->put('menu', 'setting');
session()->put('title', 'Datei-Verbindungen');
return Inertia::render('fileshare/Index', [
'data' => FileshareResource::collection(Fileshare::paginate(15)),
]);
}
}

View File

@ -2,29 +2,29 @@
namespace App\Fileshare; namespace App\Fileshare;
use App\Fileshare\Actions\FileshareIndexAction; use App\Fileshare\Models\Fileshare;
use App\Setting\Contracts\Indexable; use App\Fileshare\Resources\FileshareResource;
use App\Setting\LocalSettings; use App\Setting\LocalSettings;
class FileshareSettings extends LocalSettings implements Indexable class FileshareSettings extends LocalSettings
{ {
public static function group(): string public static function group(): string
{ {
return 'fileshare'; return 'fileshare';
} }
public static function slug(): string
{
return 'fileshare';
}
public static function indexAction(): string
{
return FileshareIndexAction::class;
}
public static function title(): string public static function title(): string
{ {
return 'Datei-Verbindungen'; return 'Datei-Verbindungen';
} }
/**
* @inheritdoc
*/
public function viewData(): array
{
return [
'data' => FileshareResource::collection(Fileshare::paginate(15))
];
}
} }

View File

@ -1,36 +0,0 @@
<?php
namespace App\Form\Actions;
use App\Form\FormSettings;
use Inertia\Inertia;
use Inertia\Response;
use Lorisleiva\Actions\Concerns\AsAction;
class SettingIndexAction
{
use AsAction;
/**
* @return array<string, mixed>
*/
public function handle(FormSettings $settings): array
{
return [
'data' => [
'register_url' => $settings->registerUrl,
'clear_cache_url' => $settings->clearCacheUrl,
],
];
}
public function asController(FormSettings $settings): Response
{
session()->put('menu', 'setting');
session()->put('title', 'Module');
return Inertia::render('setting/Form', [
'data' => $this->handle($settings),
]);
}
}

View File

@ -2,13 +2,11 @@
namespace App\Form; namespace App\Form;
use App\Form\Actions\SettingIndexAction;
use App\Form\Actions\SettingStoreAction; use App\Form\Actions\SettingStoreAction;
use App\Setting\Contracts\Indexable;
use App\Setting\Contracts\Storeable; use App\Setting\Contracts\Storeable;
use App\Setting\LocalSettings; use App\Setting\LocalSettings;
class FormSettings extends LocalSettings implements Indexable, Storeable class FormSettings extends LocalSettings implements Storeable
{ {
public string $registerUrl; public string $registerUrl;
public string $clearCacheUrl; public string $clearCacheUrl;
@ -18,23 +16,28 @@ class FormSettings extends LocalSettings implements Indexable, Storeable
return 'form'; return 'form';
} }
public static function slug(): string
{
return 'form';
}
public static function title(): string public static function title(): string
{ {
return 'Formulare'; return 'Formulare';
} }
public static function indexAction(): string
{
return SettingIndexAction::class;
}
public static function storeAction(): string public static function storeAction(): string
{ {
return SettingStoreAction::class; return SettingStoreAction::class;
} }
/**
* @inheritdoc
*/
public function viewData(): array
{
return [
'data' => [
'data' => [
'register_url' => $this->registerUrl,
'clear_cache_url' => $this->clearCacheUrl,
]
]
];
}
} }

View File

@ -2,11 +2,10 @@
namespace App\Invoice; namespace App\Invoice;
use App\Setting\Contracts\Indexable;
use App\Setting\Contracts\Storeable; use App\Setting\Contracts\Storeable;
use App\Setting\LocalSettings; use App\Setting\LocalSettings;
class InvoiceSettings extends LocalSettings implements Indexable, Storeable class InvoiceSettings extends LocalSettings implements Storeable
{ {
public string $from_long; public string $from_long;
@ -35,14 +34,26 @@ class InvoiceSettings extends LocalSettings implements Indexable, Storeable
return 'bill'; return 'bill';
} }
public static function slug(): string /**
* @inheritdoc
*/
public function viewData(): array
{ {
return 'bill'; return [
} 'data' => [
'from_long' => $this->from_long,
public static function indexAction(): string 'from' => $this->from,
{ 'mobile' => $this->mobile,
return SettingIndexAction::class; 'email' => $this->email,
'website' => $this->website,
'address' => $this->address,
'place' => $this->place,
'zip' => $this->zip,
'iban' => $this->iban,
'bic' => $this->bic,
'remember_weeks' => $this->rememberWeeks,
]
];
} }
public static function storeAction(): string public static function storeAction(): string

View File

@ -1,42 +0,0 @@
<?php
namespace App\Invoice;
use Inertia\Inertia;
use Inertia\Response;
use Lorisleiva\Actions\Concerns\AsAction;
class SettingIndexAction
{
use AsAction;
/**
* @return array<string, string>
*/
public function handle(InvoiceSettings $settings): array
{
return [
'from_long' => $settings->from_long,
'from' => $settings->from,
'mobile' => $settings->mobile,
'email' => $settings->email,
'website' => $settings->website,
'address' => $settings->address,
'place' => $settings->place,
'zip' => $settings->zip,
'iban' => $settings->iban,
'bic' => $settings->bic,
'remember_weeks' => $settings->rememberWeeks,
];
}
public function asController(InvoiceSettings $settings): Response
{
session()->put('menu', 'setting');
session()->put('title', 'Rechnungs-Einstellungen');
return Inertia::render('setting/Bill', [
'data' => $this->handle($settings),
]);
}
}

View File

@ -1,33 +0,0 @@
<?php
namespace App\Mailgateway\Actions;
use App\Mailgateway\Models\Mailgateway;
use App\Mailgateway\Resources\MailgatewayResource;
use Illuminate\Database\Eloquent\Builder;
use Inertia\Inertia;
use Inertia\Response;
use Lorisleiva\Actions\Concerns\AsAction;
class IndexAction
{
use AsAction;
/**
* @return Builder<Mailgateway>
*/
public function handle(): Builder
{
return (new Mailgateway())->newQuery();
}
public function asController(): Response
{
session()->put('menu', 'setting');
session()->put('title', 'E-Mail-Verbindungen');
return Inertia::render('mailgateway/Index', [
'data' => MailgatewayResource::collection($this->handle()->paginate(10)),
]);
}
}

View File

@ -2,29 +2,29 @@
namespace App\Mailgateway; namespace App\Mailgateway;
use App\Mailgateway\Actions\IndexAction; use App\Mailgateway\Models\Mailgateway;
use App\Setting\Contracts\Indexable; use App\Mailgateway\Resources\MailgatewayResource;
use App\Setting\LocalSettings; use App\Setting\LocalSettings;
class MailgatewaySettings extends LocalSettings implements Indexable class MailgatewaySettings extends LocalSettings
{ {
public static function group(): string public static function group(): string
{ {
return 'mailgateway'; return 'mailgateway';
} }
public static function slug(): string
{
return 'mailgateway';
}
public static function indexAction(): string
{
return IndexAction::class;
}
public static function title(): string public static function title(): string
{ {
return 'E-Mail-Verbindungen'; return 'E-Mail-Verbindungen';
} }
/**
* @inheritdoc
*/
public function viewData(): array
{
return [
'data' => MailgatewayResource::collection(Mailgateway::paginate(10)),
];
}
} }

View File

@ -1,35 +0,0 @@
<?php
namespace App\Module;
use Inertia\Inertia;
use Inertia\Response;
use Lorisleiva\Actions\Concerns\AsAction;
class ModuleIndexAction
{
use AsAction;
/**
* @return array<string, mixed>
*/
public function handle(ModuleSettings $settings): array
{
return [
'data' => [
'modules' => $settings->modules,
],
'meta' => ['modules' => Module::forSelect()],
];
}
public function asController(ModuleSettings $settings): Response
{
session()->put('menu', 'setting');
session()->put('title', 'Module');
return Inertia::render('setting/Module', [
'data' => $this->handle($settings),
]);
}
}

View File

@ -2,11 +2,10 @@
namespace App\Module; namespace App\Module;
use App\Setting\Contracts\Indexable;
use App\Setting\Contracts\Storeable; use App\Setting\Contracts\Storeable;
use App\Setting\LocalSettings; use App\Setting\LocalSettings;
class ModuleSettings extends LocalSettings implements Indexable, Storeable class ModuleSettings extends LocalSettings implements Storeable
{ {
/** @var array<int, string> */ /** @var array<int, string> */
public array $modules; public array $modules;
@ -16,21 +15,11 @@ class ModuleSettings extends LocalSettings implements Indexable, Storeable
return 'module'; return 'module';
} }
public static function slug(): string
{
return 'module';
}
public static function title(): string public static function title(): string
{ {
return 'Module'; return 'Module';
} }
public static function indexAction(): string
{
return ModuleIndexAction::class;
}
public static function storeAction(): string public static function storeAction(): string
{ {
return ModuleStoreAction::class; return ModuleStoreAction::class;
@ -40,4 +29,19 @@ class ModuleSettings extends LocalSettings implements Indexable, Storeable
{ {
return in_array($module, $this->modules); return in_array($module, $this->modules);
} }
/**
* @inheritdoc
*/
public function viewData(): array
{
return [
'data' => [
'data' => [
'modules' => $this->modules,
],
'meta' => ['modules' => Module::forSelect()],
]
];
}
} }

View File

@ -1,35 +0,0 @@
<?php
namespace App\Nami\Actions;
use App\Setting\NamiSettings;
use Inertia\Inertia;
use Inertia\Response;
use Lorisleiva\Actions\Concerns\AsAction;
class SettingIndexAction
{
use AsAction;
/**
* @return array<string, string>
*/
public function handle(NamiSettings $settings): array
{
return [
'mglnr' => $settings->mglnr,
'password' => '',
'default_group_id' => $settings->default_group_id,
];
}
public function asController(NamiSettings $settings): Response
{
session()->put('menu', 'setting');
session()->put('title', 'NaMi-Settings');
return Inertia::render('setting/Nami', [
'data' => $this->handle($settings),
]);
}
}

View File

@ -1,20 +0,0 @@
<?php
namespace App\Prevention\Actions;
use Inertia\Inertia;
use Inertia\Response;
use Lorisleiva\Actions\Concerns\AsAction;
class PreventionIndexAction
{
use AsAction;
public function handle(): Response
{
session()->put('menu', 'setting');
session()->put('title', 'Prävention');
return Inertia::render('setting/Prevention');
}
}

View File

@ -3,11 +3,9 @@
namespace App\Prevention; namespace App\Prevention;
use App\Lib\Editor\EditorData; use App\Lib\Editor\EditorData;
use App\Prevention\Actions\PreventionIndexAction;
use App\Setting\Contracts\Indexable;
use App\Setting\LocalSettings; use App\Setting\LocalSettings;
class PreventionSettings extends LocalSettings implements Indexable class PreventionSettings extends LocalSettings
{ {
public EditorData $formmail; public EditorData $formmail;
@ -17,18 +15,16 @@ class PreventionSettings extends LocalSettings implements Indexable
return 'prevention'; return 'prevention';
} }
public static function slug(): string
{
return 'prevention';
}
public static function indexAction(): string
{
return PreventionIndexAction::class;
}
public static function title(): string public static function title(): string
{ {
return 'Prävention'; return 'Prävention';
} }
/**
* @inheritdoc
*/
public function viewData(): array
{
return [];
}
} }

View File

@ -0,0 +1,21 @@
<?php
namespace App\Setting\Actions;
use App\Setting\LocalSettings;
use Inertia\Inertia;
use Inertia\Response;
use Lorisleiva\Actions\Concerns\AsAction;
class ViewAction
{
use AsAction;
public function handle(LocalSettings $settingGroup): Response
{
session()->put('menu', 'setting');
session()->put('title', $settingGroup::title());
return Inertia::render('setting/' . ucfirst($settingGroup::group()), $settingGroup->viewData());
}
}

View File

@ -1,11 +0,0 @@
<?php
namespace App\Setting\Contracts;
interface Indexable
{
/**
* @return class-string
*/
public static function indexAction(): string;
}

View File

@ -8,4 +8,6 @@ interface Storeable
* @return class-string * @return class-string
*/ */
public static function storeAction(): string; public static function storeAction(): string;
public static function url(): string;
} }

View File

@ -6,12 +6,15 @@ use Spatie\LaravelSettings\Settings;
abstract class LocalSettings extends Settings abstract class LocalSettings extends Settings
{ {
abstract public static function slug(): string;
abstract public static function title(): string; abstract public static function title(): string;
public static function url(): string public static function url(): string
{ {
return '/setting/'.static::slug(); return '/setting/' . static::group();
} }
/**
* @return array<string, mixed>
*/
abstract public function viewData(): array;
} }

View File

@ -3,14 +3,12 @@
namespace App\Setting; namespace App\Setting;
use App\Group; use App\Group;
use App\Nami\Actions\SettingIndexAction;
use App\Nami\Actions\SettingSaveAction; use App\Nami\Actions\SettingSaveAction;
use App\Setting\Contracts\Indexable;
use App\Setting\Contracts\Storeable; use App\Setting\Contracts\Storeable;
use Zoomyboy\LaravelNami\Api; use Zoomyboy\LaravelNami\Api;
use Zoomyboy\LaravelNami\Nami; use Zoomyboy\LaravelNami\Nami;
class NamiSettings extends LocalSettings implements Indexable, Storeable class NamiSettings extends LocalSettings implements Storeable
{ {
public int $mglnr; public int $mglnr;
@ -36,16 +34,6 @@ class NamiSettings extends LocalSettings implements Indexable, Storeable
return Group::firstWhere('nami_id', $this->default_group_id); return Group::firstWhere('nami_id', $this->default_group_id);
} }
public static function slug(): string
{
return 'nami';
}
public static function indexAction(): string
{
return SettingIndexAction::class;
}
public static function storeAction(): string public static function storeAction(): string
{ {
return SettingSaveAction::class; return SettingSaveAction::class;
@ -55,4 +43,18 @@ class NamiSettings extends LocalSettings implements Indexable, Storeable
{ {
return 'NaMi-Login'; return 'NaMi-Login';
} }
/**
* @inheritdoc
*/
public function viewData(): array
{
return [
'data' => [
'mglnr' => $this->mglnr,
'password' => '',
'default_group_id' => $this->default_group_id,
]
];
}
} }

View File

@ -2,7 +2,7 @@
namespace App\Setting; namespace App\Setting;
use App\Setting\Contracts\Indexable; use App\Invoice\InvoiceSettings;
use App\Setting\Contracts\Storeable; use App\Setting\Contracts\Storeable;
use Illuminate\Routing\Router; use Illuminate\Routing\Router;
@ -14,22 +14,18 @@ class SettingFactory
private array $settings = []; private array $settings = [];
/** /**
* @param class-string $setting * @param class-string<LocalSettings> $setting
*/ */
public function register(string $setting): void public function register(string $setting): void
{ {
$this->settings[] = $setting; $this->settings[] = $setting;
if (new $setting() instanceof Indexable) { if (new $setting instanceof Storeable) {
app(Router::class)->middleware(['web', 'auth:web', SettingMiddleware::class])->get($setting::url(), $setting::indexAction()); $this->registerStoreRoute(new $setting);
}
if (new $setting() instanceof Storeable) {
app(Router::class)->middleware(['web', 'auth:web', SettingMiddleware::class])->post($setting::url(), $setting::storeAction());
} }
if (1 === count($this->settings)) { if (1 === count($this->settings)) {
app(Router::class)->redirect('/setting', '/setting/'.$setting::slug()); app(Router::class)->redirect('/setting', '/setting/' . $setting::group());
} }
} }
@ -45,4 +41,16 @@ class SettingFactory
]) ])
->toArray(); ->toArray();
} }
public function resolveGroupName(string $name): LocalSettings
{
$settingClass = collect($this->settings)->first(fn ($setting) => $setting::group() === $name);
return app($settingClass);
}
protected function registerStoreRoute(Storeable $setting): void
{
app(Router::class)->middleware(['web', 'auth:web'])->post($setting::url(), $setting::storeAction());
}
} }

View File

@ -8,6 +8,8 @@ use App\Invoice\InvoiceSettings;
use App\Mailgateway\MailgatewaySettings; use App\Mailgateway\MailgatewaySettings;
use App\Module\ModuleSettings; use App\Module\ModuleSettings;
use App\Prevention\PreventionSettings; use App\Prevention\PreventionSettings;
use App\Setting\Actions\ViewAction;
use Illuminate\Routing\Router;
use Illuminate\Support\ServiceProvider; use Illuminate\Support\ServiceProvider;
class SettingServiceProvider extends ServiceProvider class SettingServiceProvider extends ServiceProvider
@ -20,6 +22,8 @@ class SettingServiceProvider extends ServiceProvider
public function register() public function register()
{ {
app()->singleton(SettingFactory::class, fn () => new SettingFactory()); app()->singleton(SettingFactory::class, fn () => new SettingFactory());
app(Router::class)->bind('settingGroup', fn ($param) => app(SettingFactory::class)->resolveGroupName($param));
app(Router::class)->middleware(['web', 'auth:web', SettingMiddleware::class])->get('/setting/{settingGroup}', ViewAction::class);
} }
/** /**

View File

@ -10,10 +10,10 @@ class SettingTest extends TestCase
{ {
use DatabaseTransactions; use DatabaseTransactions;
public function testSettingIndex(): void public function testDisplaySettings(): void
{ {
$this->withoutExceptionHandling()->login()->loginNami(); $this->withoutExceptionHandling()->login()->loginNami();
InvoiceSettings::fake([ app(InvoiceSettings::class)->fill([
'from_long' => 'DPSG Stamm Muster', 'from_long' => 'DPSG Stamm Muster',
'from' => 'Stamm Muster', 'from' => 'Stamm Muster',
'mobile' => '+49 176 55555', 'mobile' => '+49 176 55555',
@ -25,43 +25,33 @@ class SettingTest extends TestCase
'iban' => 'DE05', 'iban' => 'DE05',
'bic' => 'SOLSDE', 'bic' => 'SOLSDE',
'rememberWeeks' => 6 'rememberWeeks' => 6
]); ])->save();
$response = $this->get('/setting/bill'); $this->get('/setting/bill')
->assertOk()
$response->assertOk(); ->assertComponent('setting/Bill')
$this->assertInertiaHas([ ->assertInertiaPath('data.from_long', 'DPSG Stamm Muster')
'from_long' => 'DPSG Stamm Muster', ->assertInertiaPath('data.from', 'Stamm Muster')
'from' => 'Stamm Muster', ->assertInertiaPath('data.mobile', '+49 176 55555')
'mobile' => '+49 176 55555', ->assertInertiaPath('data.email', 'max@muster.de')
'email' => 'max@muster.de', ->assertInertiaPath('data.website', 'https://example.com')
'website' => 'https://example.com', ->assertInertiaPath('data.address', 'Musterstr 4')
'address' => 'Musterstr 4', ->assertInertiaPath('data.place', 'Solingen')
'place' => 'Solingen', ->assertInertiaPath('data.zip', '12345')
'zip' => '12345', ->assertInertiaPath('data.iban', 'DE05')
'iban' => 'DE05', ->assertInertiaPath('data.bic', 'SOLSDE')
'bic' => 'SOLSDE', ->assertInertiaPath('data.remember_weeks', 6);
'remember_weeks' => 6
], $response, 'data');
} }
public function testItReturnsTabs(): void public function testItReturnsTabs(): void
{ {
$this->withoutExceptionHandling()->login()->loginNami(); $this->withoutExceptionHandling()->login()->loginNami();
$response = $this->get('/setting/bill'); $this->get('/setting/bill')
->assertInertiaPath('setting_menu.1.title', 'Rechnung')
/** @var array<int, array{url: string, title: string, is_active: bool}> */ ->assertInertiaPath('setting_menu.1.url', '/setting/bill')
$menus = $this->inertia($response, 'setting_menu'); ->assertInertiaPath('setting_menu.1.is_active', true)
$this->assertTrue( ->assertInertiaPath('setting_menu.0.is_active', false);
collect($menus)
->pluck('url')
->contains('/setting/bill')
);
$settingMenu = collect($menus)->first(fn ($menu) => '/setting/bill' === $menu['url']);
$this->assertTrue($settingMenu['is_active']);
$this->assertEquals('Rechnung', $settingMenu['title']);
} }
public function testItCanChangeSettings(): void public function testItCanChangeSettings(): void

View File

@ -42,6 +42,6 @@ class FileshareIndexActionTest extends FileshareTestCase
{ {
$this->withoutExceptionHandling()->login()->loginNami(); $this->withoutExceptionHandling()->login()->loginNami();
$this->get('/setting/fileshare')->assertComponent('fileshare/Index'); $this->get('/setting/fileshare')->assertComponent('setting/Fileshare');
} }
} }