Add update member

This commit is contained in:
philipp lang 2021-11-20 00:48:42 +01:00
parent 3186b00a0d
commit 2cd75fe502
13 changed files with 250 additions and 14 deletions

View File

@ -2,7 +2,9 @@
namespace App\Course\Controllers; namespace App\Course\Controllers;
use App\Course\Models\CourseMember;
use App\Course\Requests\StoreRequest; use App\Course\Requests\StoreRequest;
use App\Course\Requests\UpdateRequest;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use App\Member\Member; use App\Member\Member;
use Illuminate\Http\RedirectResponse; use Illuminate\Http\RedirectResponse;
@ -16,4 +18,11 @@ class CourseController extends Controller
return redirect()->route('member.index'); return redirect()->route('member.index');
} }
public function update(Member $member, CourseMember $course, UpdateRequest $request): RedirectResponse
{
$request->persist($member, $course);
return redirect()->route('member.index');
}
} }

View File

@ -0,0 +1,19 @@
<?php
namespace App\Course\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class CourseMember extends Model
{
use HasFactory;
public $guarded = [];
public function course(): BelongsTo
{
return $this->belongsTo(Course::class);
}
}

View File

@ -40,7 +40,7 @@ class StoreRequest extends FormRequest
{ {
$course = Course::where('id', $this->input('course_id'))->firstOrFail(); $course = Course::where('id', $this->input('course_id'))->firstOrFail();
$payload = array_merge( $payload = array_merge(
$this->only(['event_name', 'completed_at', 'course_id', 'organizer']), $this->only(['event_name', 'completed_at', 'organizer']),
['course_id' => $course->nami_id], ['course_id' => $course->nami_id],
); );
@ -50,9 +50,6 @@ class StoreRequest extends FormRequest
throw ValidationException::withMessages(['id' => 'Unbekannter Fehler']); throw ValidationException::withMessages(['id' => 'Unbekannter Fehler']);
} }
$member->courses()->attach( $member->courses()->create($this->safe()->collect()->put('nami_id', $namiId)->toArray());
$course,
$this->safe()->collect()->put('nami_id', $namiId)->except(['course_id'])->toArray(),
);
} }
} }

View File

@ -0,0 +1,50 @@
<?php
namespace App\Course\Requests;
use App\Course\Models\Course;
use App\Course\Models\CourseMember;
use App\Member\Member;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Arr;
use Illuminate\Validation\ValidationException;
use Zoomyboy\LaravelNami\NamiException;
class UpdateRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array<string, string>
*/
public function rules()
{
return [
'organizer' => 'required|max:255',
'event_name' => 'required|max:255',
'completed_at' => 'required|date',
'course_id' => 'required|exists:courses,id',
];
}
public function persist(Member $member, CourseMember $course): void
{
try {
auth()->user()->api()->updateCourse($member->nami_id, $course->nami_id, $this->safe()->merge(['course_id' => Course::find($this->input('course_id'))->nami_id])->toArray());
} catch(NamiException $e) {
throw ValidationException::withMessages(['id' => 'Unbekannter Fehler']);
}
$course->update($this->safe()->toArray());
}
}

View File

@ -75,7 +75,8 @@ class InitializeMembers {
]); ]);
foreach ($this->api->coursesFor($member->id) as $course) { foreach ($this->api->coursesFor($member->id) as $course) {
$m->courses()->attach(Course::where('nami_id', $course->course_id)->firstOrFail(), [ $m->courses()->create([
'course_id' => Course::where('nami_id', $course->course_id)->firstOrFail()->id,
'organizer' => $course->organizer, 'organizer' => $course->organizer,
'event_name' => $course->event_name, 'event_name' => $course->event_name,
'completed_at' => $course->completed_at, 'completed_at' => $course->completed_at,

View File

@ -6,7 +6,7 @@ use App\Activity;
use App\Bill\BillKind; use App\Bill\BillKind;
use App\Confession; use App\Confession;
use App\Country; use App\Country;
use App\Course\Models\Course; use App\Course\Models\CourseMember;
use App\Group; use App\Group;
use App\Nationality; use App\Nationality;
use App\Payment\Payment; use App\Payment\Payment;
@ -149,9 +149,9 @@ class Member extends Model
return $this->belongsTo(Subactivity::class, 'first_subactivity_id'); return $this->belongsTo(Subactivity::class, 'first_subactivity_id');
} }
public function courses(): BelongsToMany public function courses(): HasMany
{ {
return $this->belongsToMany(Course::class)->withPivot(['organizer', 'completed_at', 'event_name']); return $this->hasMany(CourseMember::class);
} }
public static function booted() public static function booted()

View File

@ -27,6 +27,7 @@ class CourseFactory extends Factory
{ {
return [ return [
'name' => $this->faker->words(5, true), 'name' => $this->faker->words(5, true),
'nami_id' => $this->faker->numberBetween(1111, 9999),
]; ];
} }

View File

@ -0,0 +1,32 @@
<?php
namespace Database\Factories\Course\Models;
use App\Course\Models\CourseMember;
use Illuminate\Database\Eloquent\Factories\Factory;
class CourseMemberFactory extends Factory
{
public $model = CourseMember::class;
/**
* Define the model's default state.
*
* @return array<string, mixed>
*/
public function definition()
{
return [
'organizer' => $this->faker->words(5, true),
'event_name' => $this->faker->words(5, true),
'nami_id' => $this->faker->numberBetween(1111, 9999),
'completed_at' => $this->faker->date(),
];
}
public function inNami(int $namiId): self
{
return $this->state(['nami_id' => $namiId]);
}
}

View File

@ -18,13 +18,15 @@ class CreateCoursesTable extends Migration
$table->unsignedInteger('nami_id'); $table->unsignedInteger('nami_id');
$table->string('name'); $table->string('name');
}); });
Schema::create('course_member', function($table) { Schema::create('course_members', function($table) {
$table->id();
$table->foreignId('member_id')->constrained(); $table->foreignId('member_id')->constrained();
$table->foreignId('course_id')->constrained(); $table->foreignId('course_id')->constrained();
$table->string('organizer'); $table->string('organizer');
$table->string('event_name'); $table->string('event_name');
$table->unsignedInteger('nami_id'); $table->unsignedInteger('nami_id');
$table->date('completed_at'); $table->date('completed_at');
$table->timestamps();
}); });
} }

@ -1 +1 @@
Subproject commit 1238309006a18aa1de37bbaac74c3089c128c582 Subproject commit 8614f81eca34143732a1618492c13e674ce7e224

View File

@ -85,7 +85,7 @@ class StoreTest extends TestCase
]); ]);
$response->assertRedirect("/member"); $response->assertRedirect("/member");
$this->assertDatabaseHas('course_member', [ $this->assertDatabaseHas('course_members', [
'member_id' => $member->id, 'member_id' => $member->id,
'course_id' => $course->id, 'course_id' => $course->id,
'completed_at' => '2021-01-02', 'completed_at' => '2021-01-02',
@ -116,7 +116,7 @@ class StoreTest extends TestCase
]); ]);
$response->assertSessionHasErrors(['id' => 'Unbekannter Fehler']); $response->assertSessionHasErrors(['id' => 'Unbekannter Fehler']);
$this->assertDatabaseCount('course_member', 0); $this->assertDatabaseCount('course_members', 0);
} }
} }

View File

@ -0,0 +1,125 @@
<?php
namespace Tests\Feature\Course;
use App\Course\Models\Course;
use App\Course\Models\CourseMember;
use App\Member\Member;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithFaker;
use Tests\TestCase;
use Zoomyboy\LaravelNami\Backend\FakeBackend;
use Zoomyboy\LaravelNami\Fakes\CourseFake;
class UpdateTest extends TestCase
{
use RefreshDatabase;
/**
* @return array<string, array{payload: array<string, mixed>, errors: array<string, mixed>}>
*/
public function validationDataProvider(): array
{
return [
'course_id_missing' => [
'payload' => ['course_id' => null],
'errors' => ['course_id' => 'Baustein ist erforderlich.'],
],
'course_id_invalid' => [
'payload' => ['course_id' => 999],
'errors' => ['course_id' => 'Baustein ist nicht vorhanden.'],
],
'completed_at_required' => [
'payload' => ['completed_at' => ''],
'errors' => ['completed_at' => 'Datum ist erforderlich.'],
],
'completed_at_not_date' => [
'payload' => ['completed_at' => '123'],
'errors' => ['completed_at' => 'Datum muss ein gültiges Datum sein.'],
],
'event_name_required' => [
'payload' => ['event_name' => ''],
'errors' => ['event_name' => 'Veranstaltung ist erforderlich.'],
],
'organizer' => [
'payload' => ['organizer' => ''],
'errors' => ['organizer' => 'Veranstalter ist erforderlich.'],
],
];
}
/**
* @param array<string, string> $payload
* @param array<string, string> $errors
* @dataProvider validationDataProvider
*/
public function testItValidatesInput(array $payload, array $errors): void
{
$this->login()->init();
$member = Member::factory()->defaults()->inNami(123)->has(CourseMember::factory()->for(Course::factory()), 'courses')->createOne();
$newCourse = Course::factory()->inNami(789)->create();
$response = $this->patch("/member/{$member->id}/course/{$member->courses->first()->id}", array_merge([
'course_id' => $newCourse->id,
'completed_at' => '1999-02-03',
'event_name' => '::newevent::',
'organizer' => '::org::',
], $payload));
$response->assertSessionHasErrors($errors);
}
public function testItUpdatesACourse(): void
{
$this->withoutExceptionHandling();
$this->login()->init();
app(CourseFake::class)->updatesSuccessful(123, 999);
$member = Member::factory()->defaults()->inNami(123)->has(CourseMember::factory()->inNami(999)->for(Course::factory()), 'courses')->createOne();
$newCourse = Course::factory()->inNami(789)->create();
$response = $this->patch("/member/{$member->id}/course/{$member->courses->first()->id}", array_merge([
'course_id' => $newCourse->id,
'completed_at' => '1999-02-03',
'event_name' => '::newevent::',
'organizer' => '::neworg::',
]));
$response->assertRedirect("/member");
$this->assertDatabaseHas('course_members', [
'member_id' => $member->id,
'course_id' => $newCourse->id,
'event_name' => '::newevent::',
'organizer' => '::neworg::',
'completed_at' => '1999-02-03',
'nami_id' => 999,
]);
app(CourseFake::class)->assertUpdated(123, 999, [
'bausteinId' => 789,
'veranstalter' => '::neworg::',
'vstgName' => '::newevent::',
'vstgTag' => '1999-02-03T00:00:00',
]);
}
/*
public function testItReceivesUnknownErrors(): void
{
$this->login()->init();
$member = Member::factory()->defaults()->inNami(123)->createOne();
$course = Course::factory()->inNami(456)->createOne();
app(CourseFake::class)->doesntCreateWithError(123);
$response = $this->post("/member/{$member->id}/course", [
'course_id' => $course->id,
'completed_at' => '2021-01-02',
'event_name' => '::event::',
'organizer' => '::org::',
]);
$response->assertSessionHasErrors(['id' => 'Unbekannter Fehler']);
$this->assertDatabaseCount('course_member', 0);
}
*/
}

View File

@ -136,7 +136,7 @@ class InitializeTest extends TestCase
$this->post('/initialize'); $this->post('/initialize');
$this->assertDatabaseHas('course_member', [ $this->assertDatabaseHas('course_members', [
'member_id' => Member::where('firstname', '::firstname::')->firstOrFail()->id, 'member_id' => Member::where('firstname', '::firstname::')->firstOrFail()->id,
'course_id' => Course::where('name', '1a')->firstOrFail()->id, 'course_id' => Course::where('name', '1a')->firstOrFail()->id,
'event_name' => 'eventname', 'event_name' => 'eventname',