diff --git a/README.md b/README.md index 85ed353..a1cc357 100644 --- a/README.md +++ b/README.md @@ -126,7 +126,16 @@ class User extends Authenticatable The package automatically saves user devices when the `Authenticated` event is fired (on every authenticated request). No manual setup required—just add the `HasUserDevices` trait to your User model. -To ignore the new login notification via request context (e.g. in middleware or controller before authentication): +To skip saving the device entirely for a request (e.g. in middleware or controller before authentication): + +```php +use UserDevices\DeviceCreator; + +// In middleware or controller—call before the user is authenticated +DeviceCreator::ignoreListener(); +``` + +To ignore only the new login notification (device is still saved, but no email is sent): ```php use UserDevices\DeviceCreator; @@ -154,7 +163,7 @@ This will: - Create or update the device record (IP + user agent) - Update last activity timestamp -- Send a notification email on **first login** from that device (unless `ignoreNotification()` was called or `shouldSendNotificationUsing()` returns false) +- Send a notification email on **first login** from that device (unless `ignoreListener()` was called, or `ignoreNotification()` was called, or `shouldSendNotificationUsing()` returns false) #### 3. Block Device Route @@ -226,8 +235,9 @@ DeviceCreator::useUserDeviceModel(string $model): void DeviceCreator::userAgentUsing(Closure $callback): void DeviceCreator::shouldSendNotificationUsing(Closure $callback): void // (user, device) => bool -// Methods -DeviceCreator::ignoreNotification(): void // Add to Context to skip notification for current request +// Request context (call before authentication) +DeviceCreator::ignoreListener(): void // Skip saving the device for the current request +DeviceCreator::ignoreNotification(): void // Skip the new login notification for the current request ``` #### UserDevice Model diff --git a/src/DeviceCreator.php b/src/DeviceCreator.php index 952ee88..11a9b5f 100644 --- a/src/DeviceCreator.php +++ b/src/DeviceCreator.php @@ -41,6 +41,17 @@ class DeviceCreator */ public static string $userDeviceModel = UserDevice::class; + /** + * Add a flag to the request context so the new login device listener is skipped. + * + * Call this before authentication (e.g. in middleware or controller) when you + * want to skip saving the device for this request. + */ + public static function ignoreListener(): void + { + Context::add('user_devices.ignore_listener', true); + } + /** * Add a flag to the request context to ignore the new login device notification. * diff --git a/src/Listeners/SaveUserDevice.php b/src/Listeners/SaveUserDevice.php index ad1fcfe..516f653 100644 --- a/src/Listeners/SaveUserDevice.php +++ b/src/Listeners/SaveUserDevice.php @@ -20,6 +20,10 @@ public function handle(Authenticated $event): void /** @var mixed $user */ $user = $event->user; + if (Context::get('user_devices.ignore_listener', false)) { + return; + } + if (! in_array(HasUserDevices::class, class_uses_recursive($user))) { return; } diff --git a/tests/Feature/UserDevicesTest.php b/tests/Feature/UserDevicesTest.php index 27245a9..4d12b96 100644 --- a/tests/Feature/UserDevicesTest.php +++ b/tests/Feature/UserDevicesTest.php @@ -19,6 +19,19 @@ expect($user->userDevices)->toHaveCount(1); }); +test('it should not save user device when ignoreListener is called via context', function () { + $user = User::factory()->create(); + + expect($user->userDevices)->toHaveCount(0); + + DeviceCreator::ignoreListener(); + + $this->actingAs($user)->get('/dashboard'); + + $user->refresh(); + expect($user->userDevices)->toHaveCount(0); +}); + test('it should not send notification when ignoreNotification is called via context', function () { Notification::fake(); diff --git a/tests/Unit/DeviceCreatorTest.php b/tests/Unit/DeviceCreatorTest.php index 0d27981..3ec4988 100644 --- a/tests/Unit/DeviceCreatorTest.php +++ b/tests/Unit/DeviceCreatorTest.php @@ -41,6 +41,12 @@ expect(DeviceCreator::$userAgent)->toBe($callback); }); +test('it should add ignore listener flag to context', function () { + DeviceCreator::ignoreListener(); + + expect(Context::get('user_devices.ignore_listener'))->toBeTrue(); +}); + test('it should add ignore notification flag to context', function () { DeviceCreator::ignoreNotification();