mirror of
https://github.com/HolgerHatGarKeineNode/einundzwanzig-app.git
synced 2026-06-17 16:40:31 +00:00
✨ Add lecturer cleanup job and update profile update functionality
- 🧹 Introduce `lecturers:cleanup` command to delete lecturers without associated courses or events, merging their items into "Einundzwanzig." - ⚙️ Add `update` method to `UserController` for handling profile updates, allowing name changes while restricting role modifications. - 🌐 Register `PATCH /api/user` route for profile updates and update related API tests. - 🧪 Add feature and console tests for `lecturers:cleanup`, covering dry-run, forced deletion, and edge cases.
This commit is contained in:
@@ -225,6 +225,36 @@ it('denies /api/user without a token', function () {
|
||||
$this->getJson('/api/user')->assertUnauthorized();
|
||||
});
|
||||
|
||||
it('updates the token owner display name', function () {
|
||||
$user = User::factory()->create(['name' => 'Old Name']);
|
||||
Sanctum::actingAs($user);
|
||||
|
||||
$this->patchJson('/api/user', ['name' => 'Satoshi'])
|
||||
->assertOk()
|
||||
->assertJsonPath('name', 'Satoshi');
|
||||
|
||||
expect($user->fresh()->name)->toBe('Satoshi');
|
||||
});
|
||||
|
||||
it('does not let the user change roles via the profile update', function () {
|
||||
$user = User::factory()->create(['is_lecturer' => false]);
|
||||
Sanctum::actingAs($user);
|
||||
|
||||
$this->patchJson('/api/user', ['name' => 'Satoshi', 'is_lecturer' => true])
|
||||
->assertOk();
|
||||
|
||||
expect((bool) $user->fresh()->is_lecturer)->toBeFalse();
|
||||
});
|
||||
|
||||
it('rejects an empty display name', function () {
|
||||
$user = User::factory()->create();
|
||||
Sanctum::actingAs($user);
|
||||
|
||||
$this->patchJson('/api/user', ['name' => ''])
|
||||
->assertUnprocessable()
|
||||
->assertJsonValidationErrors('name');
|
||||
});
|
||||
|
||||
it('revokes the requesting token on mobile logout', function () {
|
||||
$user = User::factory()->create();
|
||||
$plainTextToken = $user->createToken('Pixel 10')->plainTextToken;
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
use App\Models\Course;
|
||||
use App\Models\Lecturer;
|
||||
use App\Models\LibraryItem;
|
||||
|
||||
it('aborts when the merge target is missing', function () {
|
||||
Lecturer::factory()->create(['name' => 'Orphan']);
|
||||
|
||||
$this->artisan('lecturers:cleanup', ['--force' => true])->assertExitCode(1);
|
||||
|
||||
expect(Lecturer::query()->where('name', 'Orphan')->exists())->toBeTrue();
|
||||
});
|
||||
|
||||
it('does nothing on a dry-run', function () {
|
||||
Lecturer::factory()->create(['name' => 'Einundzwanzig']);
|
||||
$empty = Lecturer::factory()->create();
|
||||
|
||||
$this->artisan('lecturers:cleanup')->assertExitCode(0);
|
||||
|
||||
expect(Lecturer::query()->find($empty->id))->not->toBeNull();
|
||||
});
|
||||
|
||||
it('merges library items and deletes empty lecturers with --force', function () {
|
||||
$target = Lecturer::factory()->create(['name' => 'Einundzwanzig']);
|
||||
$empty = Lecturer::factory()->create();
|
||||
$item = LibraryItem::factory()->create(['lecturer_id' => $empty->id]);
|
||||
|
||||
$this->artisan('lecturers:cleanup', ['--force' => true])
|
||||
->expectsConfirmation('This permanently deletes lecturers on this database. Continue?', 'yes')
|
||||
->assertExitCode(0);
|
||||
|
||||
expect(Lecturer::query()->find($empty->id))->toBeNull();
|
||||
expect($item->fresh()->lecturer_id)->toBe($target->id);
|
||||
});
|
||||
|
||||
it('keeps lecturers that have a course', function () {
|
||||
Lecturer::factory()->create(['name' => 'Einundzwanzig']);
|
||||
$withCourse = Lecturer::factory()->create();
|
||||
Course::factory()->create(['lecturer_id' => $withCourse->id]);
|
||||
|
||||
$this->artisan('lecturers:cleanup', ['--force' => true])->assertExitCode(0);
|
||||
|
||||
expect(Lecturer::query()->find($withCourse->id))->not->toBeNull();
|
||||
});
|
||||
Reference in New Issue
Block a user