Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds customizable email address #2

Merged
merged 1 commit into from
May 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,17 @@ If you would like to further customize the notifications, you can configure the
],
```

#### Customizing Email Address

By default, this package assumes that the user model has an `email` attribute. If you would like to customize the email address that notifications are sent to, you can override the `sendSecurityEmailsTo` method on the models that utilize the `Securable` trait.

```php
public function sendSecurityEmailsTo(): string
{
return $this->getOriginal('alternate_email') ?? $this->alternate_email;
}
````

### Custom IP Address Driver

If you would like to have full control over IP address and login handling, you can create a custom driver by implementing the `Zaengle\LaravelSecurityNotifications\Services\DigestIPAddress` interface like the example below.
Expand Down Expand Up @@ -174,4 +185,4 @@ The MIT License (MIT). Please see [License File](LICENSE.md) for more informatio

## Credits

- [Header Image](https://unsplash.com/photos/a-blurry-photo-of-lights-in-the-dark-AHBNGvRTm_A)
- [Header Image](https://unsplash.com/photos/a-blurry-photo-of-lights-in-the-dark-AHBNGvRTm_A)
3 changes: 2 additions & 1 deletion database/migrations/create_users_table.php.stub
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ class CreateUsersTable extends Migration
$table->string('username')->unique();
$table->string('email')->unique();
$table->timestamp('email_verified_at')->nullable();
$table->string('alternate_email')->unique();
$table->string('password');
$table->rememberToken();
$table->timestamps();
Expand All @@ -24,4 +25,4 @@ class CreateUsersTable extends Migration
{
Schema::dropIfExists('users');
}
}
}
7 changes: 6 additions & 1 deletion src/Traits/Securable.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,19 @@ public static function bootSecurable(): void
event(new SecureFieldsUpdated(
$model,
$changedSecureFields->toArray(),
$model->getOriginal('email') ?? $model->email,
$model->sendSecurityEmailsTo(),
$model->refresh()->updated_at,
));
}
}
});
}

public function sendSecurityEmailsTo(): string
{
return $this->getOriginal('email') ?? $this->email;
}

public function getSecureFields(): array
{
return $this->secureFields;
Expand Down
3 changes: 2 additions & 1 deletion tests/Setup/Factories/UserFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,10 @@ public function definition(): array
'name' => $this->faker->name,
'username' => $this->faker->unique()->userName,
'email' => $this->faker->unique()->safeEmail,
'alternate_email' => $this->faker->unique()->safeEmail,
'email_verified_at' => now(),
'password' => bcrypt('password'),
'remember_token' => Str::random(10),
];
}
}
}
22 changes: 22 additions & 0 deletions tests/Setup/Models/CustomUser.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php

namespace Zaengle\LaravelSecurityNotifications\Tests\Setup\Models;

use Illuminate\Auth\Authenticatable;
use Illuminate\Contracts\Auth\Access\Authorizable as AuthorizableContract;
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Foundation\Auth\Access\Authorizable;
use Illuminate\Notifications\Notifiable;
use Zaengle\LaravelSecurityNotifications\Tests\Setup\Factories\UserFactory;
use Zaengle\LaravelSecurityNotifications\Traits\Securable;

class CustomUser extends User
{
public function sendSecurityEmailsTo(): string
{
return $this->getOriginal('alternate_email') ?? $this->alternate_email;
}
}
36 changes: 35 additions & 1 deletion tests/Unit/Events/SecureFieldsUpdatedTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\Event;
use Zaengle\LaravelSecurityNotifications\Events\SecureFieldsUpdated;
use Zaengle\LaravelSecurityNotifications\Tests\Setup\Models\CustomUser;
use Zaengle\LaravelSecurityNotifications\Tests\Setup\Models\User;

it('emits event when secure fields are updated', function () {
Expand All @@ -13,15 +14,48 @@

$user = User::factory()->create();

$originalEmail = $user->email;

$user->update([
'name' => 'New Name', // Not a secure field
'email' => 'new@email.com',
'username' => 'newusername',
'password' => bcrypt('newpassword'),
]);

Event::assertDispatched(SecureFieldsUpdated::class, function ($event) use ($user) {
Event::assertDispatched(SecureFieldsUpdated::class, function (SecureFieldsUpdated $event) use ($user, $originalEmail) {
return $event->model->is($user)
&& $event->original_email === $originalEmail
&& Arr::has($event->fields, 'email')
&& Arr::has($event->fields, 'username')
&& Arr::has($event->fields, 'password')
&& ! Arr::has($event->fields, 'name');
});
});

it('emits event when secure fields are updated and sends notification to configured email', function () {
Event::fake([
SecureFieldsUpdated::class,
]);

$customUser = new CustomUser();
$customUser->setRawAttributes(
User::factory()->make([
'alternate_email' => 'alternate_email@example.com',
])->getAttributes()
);
$customUser->save();

$customUser->update([
'name' => 'New Name', // Not a secure field
'email' => 'new@email.com',
'username' => 'newusername',
'password' => bcrypt('newpassword'),
]);

Event::assertDispatched(SecureFieldsUpdated::class, function (SecureFieldsUpdated $event) use ($customUser) {
return $event->model->is($customUser)
&& $event->original_email === 'alternate_email@example.com'
&& Arr::has($event->fields, 'email')
&& Arr::has($event->fields, 'username')
&& Arr::has($event->fields, 'password')
Expand Down
Loading