Merge pull request #6628 from heavygee/fix/team-invitation-email-case-sensitivity
Fix team invitation email case sensitivity bug
This commit is contained in:
commit
3f71f7becf
4 changed files with 113 additions and 1 deletions
|
|
@ -10,6 +10,7 @@
|
||||||
use App\Traits\HasNotificationSettings;
|
use App\Traits\HasNotificationSettings;
|
||||||
use App\Traits\HasSafeStringAttribute;
|
use App\Traits\HasSafeStringAttribute;
|
||||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Illuminate\Notifications\Notifiable;
|
use Illuminate\Notifications\Notifiable;
|
||||||
use OpenApi\Attributes as OA;
|
use OpenApi\Attributes as OA;
|
||||||
|
|
@ -37,7 +38,7 @@
|
||||||
|
|
||||||
class Team extends Model implements SendsDiscord, SendsEmail, SendsPushover, SendsSlack
|
class Team extends Model implements SendsDiscord, SendsEmail, SendsPushover, SendsSlack
|
||||||
{
|
{
|
||||||
use HasNotificationSettings, HasSafeStringAttribute, Notifiable;
|
use HasFactory, HasNotificationSettings, HasSafeStringAttribute, Notifiable;
|
||||||
|
|
||||||
protected $guarded = [];
|
protected $guarded = [];
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,14 @@ class TeamInvitation extends Model
|
||||||
'via',
|
'via',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the email attribute to lowercase.
|
||||||
|
*/
|
||||||
|
public function setEmailAttribute($value)
|
||||||
|
{
|
||||||
|
$this->attributes['email'] = strtolower($value);
|
||||||
|
}
|
||||||
|
|
||||||
public function team()
|
public function team()
|
||||||
{
|
{
|
||||||
return $this->belongsTo(Team::class);
|
return $this->belongsTo(Team::class);
|
||||||
|
|
|
||||||
40
database/factories/TeamFactory.php
Normal file
40
database/factories/TeamFactory.php
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Database\Factories;
|
||||||
|
|
||||||
|
use App\Models\Team;
|
||||||
|
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Team>
|
||||||
|
*/
|
||||||
|
class TeamFactory extends Factory
|
||||||
|
{
|
||||||
|
protected $model = Team::class;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Define the model's default state.
|
||||||
|
*
|
||||||
|
* @return array<string, mixed>
|
||||||
|
*/
|
||||||
|
public function definition(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'name' => $this->faker->company() . ' Team',
|
||||||
|
'description' => $this->faker->sentence(),
|
||||||
|
'personal_team' => false,
|
||||||
|
'show_boarding' => false,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicate that the team is a personal team.
|
||||||
|
*/
|
||||||
|
public function personal(): static
|
||||||
|
{
|
||||||
|
return $this->state(fn (array $attributes) => [
|
||||||
|
'personal_team' => true,
|
||||||
|
'name' => $this->faker->firstName() . "'s Team",
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
63
tests/Feature/TeamInvitationEmailNormalizationTest.php
Normal file
63
tests/Feature/TeamInvitationEmailNormalizationTest.php
Normal file
|
|
@ -0,0 +1,63 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Tests\Feature;
|
||||||
|
|
||||||
|
use App\Models\Team;
|
||||||
|
use App\Models\TeamInvitation;
|
||||||
|
use App\Models\User;
|
||||||
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||||
|
use Tests\TestCase;
|
||||||
|
|
||||||
|
class TeamInvitationEmailNormalizationTest extends TestCase
|
||||||
|
{
|
||||||
|
use RefreshDatabase;
|
||||||
|
|
||||||
|
public function test_team_invitation_normalizes_email_to_lowercase()
|
||||||
|
{
|
||||||
|
// Create a team
|
||||||
|
$team = Team::factory()->create();
|
||||||
|
|
||||||
|
// Create invitation with mixed case email
|
||||||
|
$invitation = TeamInvitation::create([
|
||||||
|
'team_id' => $team->id,
|
||||||
|
'uuid' => 'test-uuid-123',
|
||||||
|
'email' => 'Test@Example.com', // Mixed case
|
||||||
|
'role' => 'member',
|
||||||
|
'link' => 'https://example.com/invite/test-uuid-123',
|
||||||
|
'via' => 'link'
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Verify email was normalized to lowercase
|
||||||
|
$this->assertEquals('test@example.com', $invitation->email);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_team_invitation_works_with_existing_user_email()
|
||||||
|
{
|
||||||
|
// Create a team
|
||||||
|
$team = Team::factory()->create();
|
||||||
|
|
||||||
|
// Create a user with lowercase email
|
||||||
|
$user = User::factory()->create([
|
||||||
|
'email' => 'test@example.com',
|
||||||
|
'name' => 'Test User'
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Create invitation with mixed case email
|
||||||
|
$invitation = TeamInvitation::create([
|
||||||
|
'team_id' => $team->id,
|
||||||
|
'uuid' => 'test-uuid-123',
|
||||||
|
'email' => 'Test@Example.com', // Mixed case
|
||||||
|
'role' => 'member',
|
||||||
|
'link' => 'https://example.com/invite/test-uuid-123',
|
||||||
|
'via' => 'link'
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Verify the invitation email matches the user email (both normalized)
|
||||||
|
$this->assertEquals($user->email, $invitation->email);
|
||||||
|
|
||||||
|
// Verify user lookup works
|
||||||
|
$foundUser = User::whereEmail($invitation->email)->first();
|
||||||
|
$this->assertNotNull($foundUser);
|
||||||
|
$this->assertEquals($user->id, $foundUser->id);
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue