diff --git a/app/Lib/Events/JobEvent.php b/app/Lib/Events/JobEvent.php new file mode 100644 index 00000000..0e4c7782 --- /dev/null +++ b/app/Lib/Events/JobEvent.php @@ -0,0 +1,50 @@ +message = $message; + + return $this; + } + + /** + * Get the channels the event should broadcast on. + * + * @return \Illuminate\Broadcasting\Channel + */ + public function broadcastOn() + { + return new Channel($this->channel); + } + + public function shouldReload(): static + { + $this->reload = true; + + return $this; + } +} diff --git a/app/Lib/Events/JobFinished.php b/app/Lib/Events/JobFinished.php new file mode 100644 index 00000000..6ddb4d28 --- /dev/null +++ b/app/Lib/Events/JobFinished.php @@ -0,0 +1,7 @@ +beforeMessage = JobStarted::on($this->channel)->withMessage($message); + + return $this; + } + + public function after(string $message): self + { + $this->afterMessage = JobFinished::on($this->channel)->withMessage($message); + + return $this; + } + + public function shouldReload(): self + { + $this->afterMessage->shouldReload(); + + return $this; + } + + public function handle(JobDecorator $job, Closure $next): void + { + event($this->beforeMessage); + $next($job); + event($this->afterMessage); + } +} diff --git a/app/Member/Actions/MemberDeleteAction.php b/app/Member/Actions/MemberDeleteAction.php index d99b4c57..31372a57 100644 --- a/app/Member/Actions/MemberDeleteAction.php +++ b/app/Member/Actions/MemberDeleteAction.php @@ -2,7 +2,7 @@ namespace App\Member\Actions; -use App\Lib\Events\ClientMessage; +use App\Lib\JobMiddleware\WithJobState; use App\Maildispatcher\Actions\ResyncAction; use App\Member\Member; use Illuminate\Http\RedirectResponse; @@ -13,16 +13,37 @@ class MemberDeleteAction use AsAction; - public function handle(Member $member): RedirectResponse + public function handle(int $memberId): void { + $member = Member::findOrFail($memberId); + if ($member->nami_id) { - NamiDeleteMemberAction::dispatch($member->nami_id); + NamiDeleteMemberAction::run($member->nami_id); } $member->delete(); - ResyncAction::dispatch(); - ClientMessage::make('Mitglied ' . $member->fullname . ' gelöscht.')->shouldReload()->dispatch(); + ResyncAction::run(); + } + + public function asController(Member $member): RedirectResponse + { + static::dispatch($member->id); return redirect()->back(); } + + /** + * @return array + */ + public function getJobMiddleware(int $memberId): array + { + $member = Member::findOrFail($memberId); + + return [ + WithJobState::make('member') + ->before('Lösche Mitglied ' . $member->fullname) + ->after('Mitglied ' . $member->fullname . ' gelöscht') + ->shouldReload(), + ]; + } } diff --git a/composer.json b/composer.json index 3bf06fce..616d0046 100644 --- a/composer.json +++ b/composer.json @@ -60,6 +60,7 @@ "mockery/mockery": "^1.4.4", "nunomaduro/larastan": "^2.0", "orchestra/testbench": "^7.0", + "phpstan/phpstan-mockery": "^1.1", "phpunit/phpunit": "^9.5.10" }, "config": { diff --git a/composer.lock b/composer.lock index 0e273331..9fa1bc27 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "62586d4169459f71189b880d8a86e1ec", + "content-hash": "9b301aa44118f3ff66ba16b8688726a3", "packages": [ { "name": "beyondcode/laravel-dump-server", @@ -10700,7 +10700,7 @@ "dist": { "type": "path", "url": "./packages/tex", - "reference": "48251272de62e3fea044a7ad31e1a411c15eb4c6" + "reference": "6f162102ef7ceca41822d18c3e694abd926f550b" }, "type": "library", "extra": { @@ -11618,6 +11618,56 @@ ], "time": "2023-08-08T12:33:42+00:00" }, + { + "name": "phpstan/phpstan-mockery", + "version": "1.1.1", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpstan-mockery.git", + "reference": "6aa86bd8e9c9a1be97baf0558d4a2ed1374736a6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpstan-mockery/zipball/6aa86bd8e9c9a1be97baf0558d4a2ed1374736a6", + "reference": "6aa86bd8e9c9a1be97baf0558d4a2ed1374736a6", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0", + "phpstan/phpstan": "^1.10" + }, + "require-dev": { + "mockery/mockery": "^1.2.4", + "nikic/php-parser": "^4.13.0", + "php-parallel-lint/php-parallel-lint": "^1.2", + "phpstan/phpstan-phpunit": "^1.0", + "phpstan/phpstan-strict-rules": "^1.0", + "phpunit/phpunit": "^9.5" + }, + "type": "phpstan-extension", + "extra": { + "phpstan": { + "includes": [ + "extension.neon" + ] + } + }, + "autoload": { + "psr-4": { + "PHPStan\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHPStan Mockery extension", + "support": { + "issues": "https://github.com/phpstan/phpstan-mockery/issues", + "source": "https://github.com/phpstan/phpstan-mockery/tree/1.1.1" + }, + "time": "2023-02-18T13:54:03+00:00" + }, { "name": "phpunit/php-code-coverage", "version": "9.2.27", diff --git a/phpstan.neon b/phpstan.neon index 1ef7fa8f..23cd4431 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -1,5 +1,6 @@ includes: - ./vendor/nunomaduro/larastan/extension.neon + - ./vendor/phpstan/phpstan-mockery/extension.neon parameters: @@ -127,7 +128,7 @@ parameters: count: 1 path: app/Member/Member.php - - + - message: "#^Unsafe usage of new static\\(\\)\\.$#" count: 1 path: app/Member/Member.php @@ -558,16 +559,6 @@ parameters: count: 1 path: packages/laravel-nami/tests/TestCase.php - - - message: "#^Call to an undefined method Mockery\\\\ExpectationInterface\\|Mockery\\\\HigherOrderMessage\\:\\:never\\(\\)\\.$#" - count: 1 - path: tests/Feature/Initialize/InitializeActionTest.php - - - - message: "#^Call to an undefined method Mockery\\\\ExpectationInterface\\|Mockery\\\\HigherOrderMessage\\:\\:once\\(\\)\\.$#" - count: 2 - path: tests/Feature/Initialize/InitializeMembersTest.php - - message: "#^Parameter \\#1 \\$mock of static method Phake\\:\\:verify\\(\\) expects Phake\\\\IMock, App\\\\Actions\\\\PullMemberAction given\\.$#" count: 1 diff --git a/resources/js/composables/useIndex.js b/resources/js/composables/useIndex.js index 70da8c34..a833d427 100644 --- a/resources/js/composables/useIndex.js +++ b/resources/js/composables/useIndex.js @@ -1,9 +1,9 @@ -import {ref, computed} from 'vue'; +import {ref, computed, onBeforeUnmount} from 'vue'; import {router} from '@inertiajs/vue3'; -import Toast, {useToast} from 'vue-toastification'; +import {useToast} from 'vue-toastification'; const toast = useToast(); -export function useIndex(props) { +export function useIndex(props, siteName) { const rawProps = JSON.parse(JSON.stringify(props)); const inner = { data: ref(rawProps.data), @@ -61,14 +61,21 @@ export function useIndex(props) { }; } - window.Echo.channel('jobs').listen('\\App\\Lib\\Events\\ClientMessage', (e) => { - if (e.message) { - toast.success(e.message); + function handleJobEvent(event) { + if (event.message) { + toast.success(event.message); } - if (e.reload) { + if (event.reload) { reload(false); } - }); + } + + window.Echo.channel('jobs').listen('\\App\\Lib\\Events\\ClientMessage', (e) => handleJobEvent(e)); + window.Echo.channel(siteName) + .listen('\\App\\Lib\\Events\\JobStarted', (e) => handleJobEvent(e)) + .listen('\\App\\Lib\\Events\\JobFinished', (e) => handleJobEvent(e)); + onBeforeUnmount(() => window.Echo.leave(siteName)); + onBeforeUnmount(() => window.Echo.leave('jobs')); return { data: inner.data, diff --git a/resources/js/views/activity/VIndex.vue b/resources/js/views/activity/VIndex.vue index 666656dd..2246a07f 100644 --- a/resources/js/views/activity/VIndex.vue +++ b/resources/js/views/activity/VIndex.vue @@ -1,7 +1,8 @@