mirror of
https://github.com/HolgerHatGarKeineNode/einundzwanzig-app.git
synced 2026-06-11 02:50:29 +00:00
f5cf85b438
- 💾 Introduced `restore_point` JSON column in `meetups` table for saving and restoring master data. - 🛠️ Added methods `captureRestorePoint` and `restoreFromRestorePoint` to `Meetup` model for managing restore points. - 🔒 Implemented authorization for updating meetups via `updateViaPortal` policy to include pivot members. - 🔗 Created Artisan commands `meetups:snapshot` and `meetups:restore` for managing restore points from CLI. - 🚦 Added rate limiter to restrict excessive update attempts in Livewire meetup editing. - ✅ Developed exhaustive feature tests for snapshot and restore actions, portal editing rules, and rate limiting.
127 lines
4.0 KiB
PHP
127 lines
4.0 KiB
PHP
<?php
|
|
|
|
use App\Models\City;
|
|
use App\Models\Country;
|
|
use App\Models\Meetup;
|
|
use App\Models\User;
|
|
use Illuminate\Support\Facades\RateLimiter;
|
|
use Livewire\Livewire;
|
|
|
|
beforeEach(function () {
|
|
$country = Country::factory()->create(['code' => 'de']);
|
|
$this->city = City::factory()->create(['country_id' => $country->id]);
|
|
});
|
|
|
|
it('updates an existing Meetup name as the creator', function () {
|
|
$creator = actingAsUser();
|
|
$meetup = Meetup::factory()->create([
|
|
'city_id' => $this->city->id,
|
|
'name' => 'Original Name',
|
|
'created_by' => $creator->id,
|
|
]);
|
|
$meetup->users()->attach($creator);
|
|
|
|
Livewire::test('meetups.edit', ['meetup' => $meetup])
|
|
->set('name', 'Updated Name')
|
|
->set('city_id', $this->city->id)
|
|
->set('community', 'einundzwanzig')
|
|
->call('updateMeetup')
|
|
->assertHasNoErrors();
|
|
|
|
expect($meetup->refresh()->name)->toBe('Updated Name');
|
|
});
|
|
|
|
it('rejects update when name collides with another existing Meetup', function () {
|
|
$creator = actingAsUser();
|
|
$meetup = Meetup::factory()->create([
|
|
'city_id' => $this->city->id,
|
|
'name' => 'Original Name',
|
|
'created_by' => $creator->id,
|
|
]);
|
|
$meetup->users()->attach($creator);
|
|
Meetup::factory()->create(['name' => 'Other Name', 'city_id' => $this->city->id]);
|
|
|
|
Livewire::test('meetups.edit', ['meetup' => $meetup])
|
|
->set('name', 'Other Name')
|
|
->call('updateMeetup')
|
|
->assertHasErrors(['name' => 'unique']);
|
|
});
|
|
|
|
it('allows update when name is unchanged (Rule::unique ignores own id)', function () {
|
|
$creator = actingAsUser();
|
|
$meetup = Meetup::factory()->create([
|
|
'city_id' => $this->city->id,
|
|
'name' => 'Original Name',
|
|
'created_by' => $creator->id,
|
|
]);
|
|
$meetup->users()->attach($creator);
|
|
|
|
Livewire::test('meetups.edit', ['meetup' => $meetup])
|
|
->set('name', 'Original Name')
|
|
->set('community', 'einundzwanzig')
|
|
->call('updateMeetup')
|
|
->assertHasNoErrors();
|
|
});
|
|
|
|
it('allows updateMeetup for a member of the meetup_user pivot who is not the creator', function () {
|
|
$member = actingAsUser();
|
|
$meetup = Meetup::factory()->create([
|
|
'city_id' => $this->city->id,
|
|
'name' => 'Original Name',
|
|
'created_by' => User::factory()->create()->id,
|
|
]);
|
|
$meetup->users()->attach($member);
|
|
|
|
Livewire::test('meetups.edit', ['meetup' => $meetup])
|
|
->set('name', 'Updated By Member')
|
|
->set('city_id', $this->city->id)
|
|
->set('community', 'einundzwanzig')
|
|
->call('updateMeetup')
|
|
->assertHasNoErrors();
|
|
|
|
expect($meetup->refresh()->name)->toBe('Updated By Member');
|
|
});
|
|
|
|
it('blocks updateMeetup when the user is neither creator nor pivot member', function () {
|
|
actingAsUser();
|
|
$meetup = Meetup::factory()->create([
|
|
'city_id' => $this->city->id,
|
|
'name' => 'Original Name',
|
|
'created_by' => User::factory()->create()->id,
|
|
]);
|
|
|
|
Livewire::test('meetups.edit', ['meetup' => $meetup])
|
|
->assertStatus(403);
|
|
|
|
expect($meetup->refresh()->name)->toBe('Original Name');
|
|
});
|
|
|
|
it('blocks updateMeetup after exceeding the hourly rate limit', function () {
|
|
$creator = actingAsUser();
|
|
$meetup = Meetup::factory()->create([
|
|
'city_id' => $this->city->id,
|
|
'name' => 'Original Name',
|
|
'created_by' => $creator->id,
|
|
]);
|
|
$meetup->users()->attach($creator);
|
|
|
|
for ($i = 0; $i < 10; $i++) {
|
|
RateLimiter::hit(Meetup::updateRateLimitKey($creator->id), 3600);
|
|
}
|
|
|
|
Livewire::test('meetups.edit', ['meetup' => $meetup])
|
|
->set('name', 'Updated Name')
|
|
->set('city_id', $this->city->id)
|
|
->set('community', 'einundzwanzig')
|
|
->call('updateMeetup')
|
|
->assertHasErrors(['rateLimit']);
|
|
|
|
expect($meetup->refresh()->name)->toBe('Original Name');
|
|
});
|
|
|
|
it('redirects guests when accessing meetup-edit', function () {
|
|
$meetup = Meetup::factory()->create(['city_id' => $this->city->id]);
|
|
|
|
$this->get('/de/meetup-edit/'.$meetup->id)->assertRedirect(route('login'));
|
|
});
|