added invitations
This commit is contained in:
@@ -0,0 +1,103 @@
|
||||
<?php
|
||||
|
||||
use App\Models\User;
|
||||
use App\Models\Dynamic;
|
||||
use App\Models\DynamicInvitation;
|
||||
use App\Mail\DynamicInvitationMail;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
use Illuminate\Support\Facades\URL;
|
||||
|
||||
test('only owners can invite other users to a dynamic', function () {
|
||||
Mail::fake();
|
||||
|
||||
$owner = User::factory()->create();
|
||||
$participant = User::factory()->create();
|
||||
$dynamic = Dynamic::factory()->create();
|
||||
|
||||
$dynamic->participants()->attach($owner->id, ['role' => 'owner']);
|
||||
$dynamic->participants()->attach($participant->id, ['role' => 'participant']);
|
||||
|
||||
// 1. Participant tries to send an invite (forbidden)
|
||||
$response = $this->actingAs($participant)
|
||||
->post(route('dynamics.invitations.store', $dynamic), [
|
||||
'email' => 'invitee@example.com',
|
||||
'role' => 'participant',
|
||||
]);
|
||||
|
||||
$response->assertStatus(403);
|
||||
Mail::assertNothingSent();
|
||||
|
||||
// 2. Owner sends a valid invite (allowed)
|
||||
$response = $this->actingAs($owner)
|
||||
->post(route('dynamics.invitations.store', $dynamic), [
|
||||
'email' => 'invitee@example.com',
|
||||
'role' => 'participant',
|
||||
]);
|
||||
|
||||
$response->assertRedirect();
|
||||
$response->assertSessionHasNoErrors();
|
||||
|
||||
// Verify invitation is stored
|
||||
$invitation = DynamicInvitation::firstWhere('email', 'invitee@example.com');
|
||||
expect($invitation)->not->toBeNull();
|
||||
expect($invitation->role)->toBe('participant');
|
||||
expect($invitation->dynamic_id)->toBe($dynamic->id);
|
||||
|
||||
// Verify email was dispatched
|
||||
Mail::assertSent(DynamicInvitationMail::class, function ($mail) use ($invitation) {
|
||||
return $mail->hasTo($invitation->email);
|
||||
});
|
||||
});
|
||||
|
||||
test('only the user with the specified email address can accept the link', function () {
|
||||
$owner = User::factory()->create();
|
||||
$invitee = User::factory()->create(['email' => 'matching@example.com']);
|
||||
$hijacker = User::factory()->create(['email' => 'hijacker@example.com']);
|
||||
$dynamic = Dynamic::factory()->create();
|
||||
|
||||
$dynamic->participants()->attach($owner->id, ['role' => 'owner']);
|
||||
|
||||
// Create a pending invitation
|
||||
$invitation = $dynamic->invitations()->create([
|
||||
'email' => 'matching@example.com',
|
||||
'role' => 'editor',
|
||||
'token' => 'secure_test_token_123',
|
||||
'expires_at' => now()->addDays(7),
|
||||
]);
|
||||
|
||||
// Generate a secure, valid signed URL
|
||||
$signedUrl = URL::temporarySignedRoute(
|
||||
'dynamics.invitations.accept',
|
||||
$invitation->expires_at,
|
||||
['token' => $invitation->token]
|
||||
);
|
||||
|
||||
// 1. Unauthenticated user tries to accept (redirected to login)
|
||||
$response = $this->get($signedUrl);
|
||||
$response->assertRedirect('/login');
|
||||
|
||||
// 2. Different user (hijacker) tries to accept (forbidden / 403)
|
||||
$response = $this->actingAs($hijacker)->get($signedUrl);
|
||||
$response->assertStatus(403);
|
||||
expect($dynamic->participants()->where('user_id', $hijacker->id)->exists())->toBeFalse();
|
||||
|
||||
// 3. Intended user accepts the signed invitation link (success)
|
||||
$response = $this->actingAs($invitee)->get($signedUrl);
|
||||
$response->assertRedirect(route('dynamics.show', $dynamic));
|
||||
|
||||
// Verify invitee is joined as a participant with the specified role
|
||||
$isJoined = $dynamic->participants()
|
||||
->where('user_id', $invitee->id)
|
||||
->wherePivot('role', 'editor')
|
||||
->exists();
|
||||
|
||||
expect($isJoined)->toBeTrue();
|
||||
|
||||
// Verify invitation is deleted from the database
|
||||
expect(DynamicInvitation::where('token', 'secure_test_token_123')->exists())->toBeFalse();
|
||||
|
||||
// Verify system notification is added to Dynamic activity chat
|
||||
$chatMessages = $dynamic->chat->messages;
|
||||
expect($chatMessages)->not->toBeEmpty();
|
||||
expect($chatMessages->last()->content)->toBe("System: {$invitee->name} joined the Dynamic as a EDITOR after accepting an invitation.");
|
||||
});
|
||||
Reference in New Issue
Block a user