Add backend for updating subactivities

This commit is contained in:
philipp lang 2023-03-07 00:22:01 +01:00
parent 13c9d2f2c1
commit 9315dafbfb
5 changed files with 310 additions and 0 deletions

View File

@ -3,6 +3,7 @@
namespace App\Activity\Actions;
use App\Activity;
use App\Member\Membership;
use App\Subactivity;
use Illuminate\Http\RedirectResponse;
use Illuminate\Support\Facades\DB;
@ -46,6 +47,12 @@ class ActivityUpdateAction
$this->validateNami($activity, $request->validated());
}
$removingSubactivities = $activity->subactivities()->whereNotIn('id', $request->validated('subactivities'))->pluck('id');
if ($removingSubactivities->first(fn ($subactivity) => Membership::firstWhere(['activity_id' => $activity->id, 'subactivity_id' => $subactivity]))) {
throw ValidationException::withMessages(['subactivities' => 'Untergliederung hat noch Mitglieder.']);
}
$this->handle($activity, $request->validated());
return redirect()->route('activity.index');

View File

@ -0,0 +1,93 @@
<?php
namespace App\Activity\Api;
use App\Activity;
use App\Member\Membership;
use App\Subactivity;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Arr;
use Illuminate\Validation\Rule;
use Illuminate\Validation\ValidationException;
use Lorisleiva\Actions\ActionRequest;
use Lorisleiva\Actions\Concerns\AsAction;
class SubactivityUpdateAction
{
use AsAction;
/**
* @param array<string, string|array<int, int>> $payload
*/
public function handle(Subactivity $subactivity, array $payload): Subactivity
{
$subactivity->update(Arr::except($payload, 'activities'));
if (null !== data_get($payload, 'activities')) {
$subactivity->activities()->sync($payload['activities']);
}
return $subactivity;
}
/**
* @return array<string, string>
*/
public function rules(): array
{
return [
'name' => ['required', 'string', 'max:255', Rule::unique('subactivities', 'name')->ignore(request()->route('subactivity')->id)],
'activities' => ['present', 'array', 'min:1'],
'is_filterable' => 'present|boolean',
];
}
/**
* @return array<string, string>
*/
public function getValidationAttributes(): array
{
return [
'activities' => 'Tätigkeiten',
];
}
public function asController(ActionRequest $request, Subactivity $subactivity): JsonResponse
{
if ($subactivity->hasNami) {
$this->validateNami($subactivity, $request->validated());
}
$removingActivities = $subactivity->activities()->whereNotIn('id', $request->validated('activities'))->pluck('id');
if ($removingActivities->first(fn ($activity) => Membership::firstWhere(['activity_id' => $activity, 'subactivity_id' => $subactivity->id]))) {
throw ValidationException::withMessages(['activities' => 'Tätigkeit hat noch Mitglieder.']);
}
return response()->json($this->handle($subactivity, $request->validated()));
}
/**
* @todo handle this with a model event on the pivot model
*
* @param Payload $payload
*/
private function validateNami(Subactivity $subactivity, array $payload): void
{
if ($subactivity->name !== $payload['name']) {
throw ValidationException::withMessages(['name' => 'Untertätigkeit ist in NaMi. Update des Namens nicht möglich.']);
}
$removingActivities = $subactivity->activities()->whereNotIn('id', $payload['activities'])->pluck('id');
if ($removingActivities->first(fn ($activity) => Activity::find($activity)->hasNami)) {
throw ValidationException::withMessages(['activities' => 'Tätigkeit kann nicht entfernt werden.']);
}
$addingActivities = collect($payload['activities'])->filter(fn ($activityId) => $subactivity->activities->doesntContain($activityId));
if ($addingActivities->first(fn ($activity) => Activity::find($activity)->hasNami)) {
throw ValidationException::withMessages(['activities' => 'Tätigkeit kann nicht hinzugefügt werden.']);
}
}
}

View File

@ -7,6 +7,7 @@ use App\Activity\Actions\DestroyAction as ActivityDestroyAction;
use App\Activity\Actions\EditAction as ActivityEditAction;
use App\Activity\Actions\IndexAction as ActivityIndexAction;
use App\Activity\Api\SubactivityStoreAction;
use App\Activity\Api\SubactivityUpdateAction;
use App\Contribution\Actions\FormAction as ContributionFormAction;
use App\Contribution\ContributionController;
use App\Course\Controllers\CourseController;
@ -62,4 +63,5 @@ Route::group(['middleware' => 'auth:web'], function (): void {
Route::patch('/activity/{activity}', ActivityUpdateAction::class)->name('activity.update');
Route::delete('/activity/{activity}', ActivityDestroyAction::class)->name('activity.destroy');
Route::post('/subactivity', SubactivityStoreAction::class)->name('api.subactivity.store');
Route::patch('/subactivity/{subactivity}', SubactivityUpdateAction::class)->name('api.subactivity.update');
});

View File

@ -3,6 +3,8 @@
namespace Tests\Feature\Activity;
use App\Activity;
use App\Member\Member;
use App\Member\Membership;
use App\Subactivity;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Tests\TestCase;
@ -86,4 +88,191 @@ class SubactivityTest extends TestCase
]);
$this->assertDatabaseMissing('subactivities', ['nami_id' => 556]);
}
public function testItCannotUpdateNameIfInNami(): void
{
$this->login()->loginNami();
$activity = Activity::factory()->inNami(123)->create();
$subactivity = Subactivity::factory()->hasAttached($activity)->name('abc')->inNami(777)->create();
$response = $this->patchJson(route('api.subactivity.update', ['subactivity' => $subactivity->id]), [
'name' => 'aaaa',
'nami_id' => 777,
'activities' => [$activity->id],
'is_filterable' => false,
]);
$response->assertJsonValidationErrors(['name' => 'Untertätigkeit ist in NaMi. Update des Namens nicht möglich.']);
}
public function testItCannotUpdateNamiId(): void
{
$this->login()->loginNami();
$activity = Activity::factory()->inNami(123)->create();
$subactivity = Subactivity::factory()->hasAttached($activity)->name('abc')->inNami(777)->create();
$response = $this->patchJson(route('api.subactivity.update', ['subactivity' => $subactivity->id]), [
'name' => 'abc',
'nami_id' => 556,
'activities' => [$activity->id],
'is_filterable' => false,
]);
$this->assertDatabaseHas('subactivities', [
'id' => $subactivity->id,
'nami_id' => 777,
]);
}
public function testItCannotSetNamiId(): void
{
$this->login()->loginNami();
$activity = Activity::factory()->inNami(123)->create();
$subactivity = Subactivity::factory()->hasAttached($activity)->name('abc')->create();
$response = $this->patchJson(route('api.subactivity.update', ['subactivity' => $subactivity->id]), [
'name' => 'abc',
'nami_id' => 556,
'activities' => [$activity->id],
'is_filterable' => false,
]);
$this->assertDatabaseHas('subactivities', [
'id' => $subactivity->id,
'nami_id' => null,
]);
}
public function testItCanUpdateIsFilterableIfInNami(): void
{
$this->login()->loginNami();
$activity = Activity::factory()->inNami(123)->create();
$subactivity = Subactivity::factory()->hasAttached($activity)->name('abc')->filterable()->inNami(777)->create();
$response = $this->patchJson(route('api.subactivity.update', ['subactivity' => $subactivity->id]), [
'name' => 'abc',
'activities' => [$activity->id],
'is_filterable' => false,
]);
$this->assertDatabaseHas('subactivities', [
'id' => $subactivity->id,
'is_filterable' => false,
]);
}
public function testItCanUpdateNameWhenNotInNami(): void
{
$this->login()->loginNami();
$activity = Activity::factory()->inNami(123)->create();
$subactivity = Subactivity::factory()->hasAttached($activity)->name('abc')->create();
$response = $this->patchJson(route('api.subactivity.update', ['subactivity' => $subactivity->id]), [
'name' => 'def',
'activities' => [$activity->id],
'is_filterable' => false,
]);
$this->assertDatabaseHas('subactivities', [
'id' => $subactivity->id,
'name' => 'def',
]);
}
public function testNameShouldBeUnique(): void
{
$this->login()->loginNami();
$activity = Activity::factory()->inNami(123)->create();
$subactivity = Subactivity::factory()->hasAttached($activity)->name('abc')->create();
Subactivity::factory()->hasAttached($activity)->name('def')->create();
$response = $this->patchJson(route('api.subactivity.update', ['subactivity' => $subactivity->id]), [
'name' => 'def',
'activities' => [$activity->id],
'is_filterable' => false,
]);
$response->assertJsonValidationErrors(['name' => 'Name ist bereits vergeben']);
}
public function testItCanSetAnotherActivity(): void
{
$this->login()->loginNami();
$activity = Activity::factory()->create();
$newActivity = Activity::factory()->create();
$subactivity = Subactivity::factory()->hasAttached($activity)->create();
$response = $this->patchJson(route('api.subactivity.update', ['subactivity' => $subactivity->id]), [
'name' => 'abc',
'activities' => [$activity->id, $newActivity->id],
'is_filterable' => false,
]);
$this->assertDatabaseHas('activity_subactivity', ['activity_id' => $activity->id, 'subactivity_id' => $subactivity->id]);
$this->assertDatabaseHas('activity_subactivity', ['activity_id' => $newActivity->id, 'subactivity_id' => $subactivity->id]);
}
public function testItCannotSetAnotherNamiActivity(): void
{
$this->login()->loginNami();
$activity = Activity::factory()->create();
$newActivity = Activity::factory()->inNami(556)->create();
$subactivity = Subactivity::factory()->hasAttached($activity)->name('abc')->inNami(667)->create();
$response = $this->patchJson(route('api.subactivity.update', ['subactivity' => $subactivity->id]), [
'name' => 'abc',
'activities' => [$activity->id, $newActivity->id],
'is_filterable' => false,
]);
$response->assertJsonValidationErrors(['activities' => 'Tätigkeit kann nicht hinzugefügt werden.']);
}
public function testItCannotRemoveANamiActivity(): void
{
$this->login()->loginNami();
$activity = Activity::factory()->create();
$newActivity = Activity::factory()->inNami(556)->create();
$subactivity = Subactivity::factory()->hasAttached($activity)->hasAttached($newActivity)->name('abc')->inNami(667)->create();
$response = $this->patchJson(route('api.subactivity.update', ['subactivity' => $subactivity->id]), [
'name' => 'abc',
'activities' => [$activity->id],
'is_filterable' => false,
]);
$response->assertJsonValidationErrors(['activities' => 'Tätigkeit kann nicht entfernt werden.']);
}
public function testItCannotRemoveActivityIfMembershipsHasMembers(): void
{
$this->login()->loginNami();
$activity = Activity::factory()->create();
$newActivity = Activity::factory()->create();
$subactivity = Subactivity::factory()->hasAttached($activity)->create();
Member::factory()->defaults()->has(Membership::factory()->for($activity)->for($subactivity))->create();
$response = $this->patchJson(route('api.subactivity.update', ['subactivity' => $subactivity->id]), [
'name' => 'abc',
'activities' => [$newActivity->id],
'is_filterable' => false,
]);
$response->assertJsonValidationErrors(['activities' => 'Tätigkeit hat noch Mitglieder.']);
}
public function testItCannotSetNoActivity(): void
{
$this->login()->loginNami();
$activity = Activity::factory()->create();
$subactivity = Subactivity::factory()->hasAttached($activity)->create();
$response = $this->patchJson(route('api.subactivity.update', ['subactivity' => $subactivity->id]), [
'name' => 'abc',
'activities' => [],
'is_filterable' => false,
]);
$response->assertJsonValidationErrors(['activities' => 'Tätigkeiten muss mindestens 1 Elemente haben.']);
}
}

View File

@ -3,6 +3,8 @@
namespace Tests\Feature\Activity;
use App\Activity;
use App\Member\Member;
use App\Member\Membership;
use App\Subactivity;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Tests\TestCase;
@ -158,4 +160,21 @@ class UpdateTest extends TestCase
$this->assertDatabaseEmpty('activity_subactivity');
}
public function testItCannotSetSubactivityIfItStillHasMembers(): void
{
$this->login()->loginNami();
$activity = Activity::factory()->create();
$subactivity = Subactivity::factory()->hasAttached($activity)->create();
$newSubactivity = Subactivity::factory()->create();
Member::factory()->defaults()->has(Membership::factory()->for($activity)->for($subactivity))->create();
$response = $this->patch(route('activity.update', ['activity' => $activity]), [
'name' => 'abc',
'is_filterable' => false,
'subactivities' => [$newSubactivity->id],
]);
$response->assertSessionHasErrors(['subactivities' => 'Untergliederung hat noch Mitglieder.']);
}
}