Skip to content
Open
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
4 changes: 2 additions & 2 deletions .github/workflows/run-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ jobs:
strategy:
fail-fast: true
matrix:
os: [ubuntu-latest, windows-latest]
os: [ubuntu-latest]
php: [8.3, 8.2]
laravel: [11.*, 10.*]
stability: [prefer-lowest, prefer-stable]
stability: [prefer-stable]
include:
- laravel: 11.*
testbench: 9.*
Expand Down
3 changes: 1 addition & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,7 @@
"pestphp/pest-plugin-laravel": "^2.3",
"phpstan/extension-installer": "^1.3",
"phpstan/phpstan-deprecation-rules": "^1.1",
"phpstan/phpstan-phpunit": "^1.3",
"spatie/laravel-ray": "^1.35"
"phpstan/phpstan-phpunit": "^1.3"
},
"autoload": {
"psr-4": {
Expand Down
16 changes: 11 additions & 5 deletions config/users.php
Original file line number Diff line number Diff line change
@@ -1,24 +1,30 @@
<?php

use Backstage\Laravel\Users\Eloquent\Models\User;
use Backstage\Laravel\Users\Eloquent\Models\UserLogin;
use Backstage\Laravel\Users\Eloquent\Models\UserNotificationPreference;
use Backstage\Laravel\Users\Eloquent\Observers\UserObserver;
use Backstage\Laravel\Users\Notifications\Invitation;

/**
* Laravel Users Configuration
*/

return [
'eloquent' => [
'user' => [
'model' => \Backstage\Laravel\Users\Eloquent\Models\User::class,
'model' => User::class,
'table' => 'users',
'observer' => \Backstage\Laravel\Users\Eloquent\Observers\UserObserver::class,
'observer' => UserObserver::class,
],

'user_login' => [
'model' => \Backstage\Laravel\Users\Eloquent\Models\UserLogin::class,
'model' => UserLogin::class,
'table' => 'user_logins',
],

'user_notification_preferences' => [
'model' => \Backstage\Laravel\Users\Eloquent\Models\UserNotificationPreference::class,
'model' => UserNotificationPreference::class,
'table' => 'user_notification_preferences',
],
],
Expand All @@ -27,7 +33,7 @@
'auth' => [
'user_created' => [
// Or set Backstage\Filament\Users\Notifications\UserInvitationNotification
'invitation_notification' => \Backstage\Laravel\Users\Notifications\Invitation::class,
'invitation_notification' => Invitation::class,
'notification_delivery_channels' => [
'mail',
],
Expand Down
9 changes: 6 additions & 3 deletions helpers.php
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
<?php

use Backstage\Laravel\Users\Domain\Email\Actions\ValidateEmail;
use Backstage\Laravel\Users\Domain\Password\Actions\GeneratePassword;

if (! function_exists('geo')) {
function geo($attribute = '')
{
if (! session('geo')) {
$geo = json_decode(@file_get_contents('https://pro.ip-api.com/json/' . request()->ip() . '?key=' . config('services.ip-api.key')));
$geo = json_decode(@file_get_contents('https://pro.ip-api.com/json/'.request()->ip().'?key='.config('services.ip-api.key')));

session()->put('geo', $geo);
} else {
Expand All @@ -18,13 +21,13 @@ function geo($attribute = '')
if (! function_exists('generate_password')) {
function generate_password(...$args)
{
return \Backstage\Laravel\Users\Domain\Password\Actions\GeneratePassword::run(...$args);
return GeneratePassword::run(...$args);
}
}

if (! function_exists('validate_email')) {
function validate_email(...$args)
{
return \Backstage\Laravel\Users\Domain\Email\Actions\ValidateEmail::run(...$args);
return ValidateEmail::run(...$args);
}
}
6 changes: 3 additions & 3 deletions src/Console/Commands/DeleteUser.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class DeleteUser extends Command
public function handle()
{
if ($this->option('force-delete') && posix_geteuid() !== 0) {
error('This command must be run as root. Try: sudo php artisan ' . str($this->signature)->replace(['{', '}'], '')->toString());
error('This command must be run as root. Try: sudo php artisan '.str($this->signature)->replace(['{', '}'], '')->toString());

return Command::FAILURE;
}
Expand All @@ -33,7 +33,7 @@ public function handle()

$users = multiselect(
label: 'Select the user(s) to delete',
options: $userCollection->pluck('name', 'id')->map(fn ($name, $id) => $name . ' (ID: ' . $id . ')')->toArray(),
options: $userCollection->pluck('name', 'id')->map(fn ($name, $id) => $name.' (ID: '.$id.')')->toArray(),
required: true,
);

Expand All @@ -59,7 +59,7 @@ public function handle()
$user->delete();
}

$this->info($this->option('force-delete') ? 'Force deleted' : 'Deleted' . ' user: ' . $user->name);
$this->info($this->option('force-delete') ? 'Force deleted' : 'Deleted'.' user: '.$user->name);
}
}
}
6 changes: 3 additions & 3 deletions src/Console/Commands/ListUsersCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public function handle(): void
return;
}

info('Found ' . $users->count() . ' user(s):');
info('Found '.$users->count().' user(s):');

$this->renderTable($users);

Expand All @@ -46,7 +46,7 @@ public function handle(): void
$userId = search(
label: 'Search for the user that should receive the mail',
options: fn (string $value) => strlen($value) > 0
? User::whereLike('name', "%{$value}%")->pluck('name', 'id')->map(fn ($name, $id) => $name . ' (ID: ' . $id . ')')->toArray()
? User::whereLike('name', "%{$value}%")->pluck('name', 'id')->map(fn ($name, $id) => $name.' (ID: '.$id.')')->toArray()
: []
);

Expand Down Expand Up @@ -169,7 +169,7 @@ protected function renderTable(Collection $users)
$user->email,
$user->hasVerifiedEmail() ? 'Yes' : 'No',
$user->getRoleNames()->implode(', ') ?: 'No roles',
$user->created_at->format('Y-m-d H:i:s') . ' (' . $user->created_at->diffForHumans() . ')',
$user->created_at->format('Y-m-d H:i:s').' ('.$user->created_at->diffForHumans().')',

])->toArray());
}
Expand Down
2 changes: 1 addition & 1 deletion src/Console/Commands/MakeUserCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ public function handle(): int
$this->line("Name: {$user->name}");
$this->line("Email: {$user->email}");
if ($selectedRole) {
$this->line('Role: ' . ($selectedRole instanceof Role ? $selectedRole->name : $selectedRole));
$this->line('Role: '.($selectedRole instanceof Role ? $selectedRole->name : $selectedRole));
}
$this->line("Password: {$password}");

Expand Down
2 changes: 1 addition & 1 deletion src/Domain/Email/Actions/ValidateEmail.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ class ValidateEmail
{
use AsAction;

public function handle(string | array $email): bool | array
public function handle(string|array $email): bool|array
{
if (is_array($email)) {
return $this->validateMultipleEmails($email);
Expand Down
3 changes: 2 additions & 1 deletion src/Eloquent/Observers/UserObserver.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@

namespace Backstage\Laravel\Users\Eloquent\Observers;

use Backstage\Laravel\Users\Eloquent\Models\User;
use Backstage\Laravel\Users\Events\Auth\UserCreated;

class UserObserver
{
/**
* Handle the User "created" event.
*
* @param \Backstage\Laravel\Users\Eloquent\Models\User $user
* @param User $user
* @return void
*/
public function created($user)
Expand Down
2 changes: 1 addition & 1 deletion src/Events/Auth/UserCreated.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ class UserCreated
/**
* The user instance.
*
* @var \Backstage\Laravel\Users\Eloquent\Models\User
* @var User
*/
public function __construct(public User $user) {}
}
50 changes: 50 additions & 0 deletions src/Jobs/RecordUserLogin.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?php

namespace Backstage\Laravel\Users\Jobs;

use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Queue\Queueable;

class RecordUserLogin implements ShouldQueue
{
use Queueable;

/**
* @param array<string, mixed>|null $inputs
*/
public function __construct(
public int $userId,
public string $type,
public ?string $url,
public ?string $referrer,
public ?array $inputs,
public ?string $userAgent,
public ?string $ipAddress,
) {}

public function handle(): void
{
$userModel = config('users.eloquent.user.model');

if (! $userModel || ! class_exists($userModel)) {
return;
}

$user = $userModel::find($this->userId);

if (! $user) {
return;
}

$user->logins()->create([
'user_id' => $this->userId,
'type' => $this->type,
'url' => $this->url,
'referrer' => $this->referrer,
'inputs' => $this->inputs ? json_encode($this->inputs) : null,
'user_agent' => $this->userAgent,
'ip_address' => $this->ipAddress,
'hostname' => $this->ipAddress ? gethostbyaddr($this->ipAddress) : null,
]);
}
}
26 changes: 17 additions & 9 deletions src/LaravelUsersServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,16 @@
namespace Backstage\Laravel\Users;

use Backstage\Laravel\Users\Console\Commands;
use Backstage\Laravel\Users\Eloquent\Models\User;
use Backstage\Laravel\Users\Eloquent\Observers\UserObserver;
use Backstage\Laravel\Users\Events\Auth\UserCreated;
use Backstage\Laravel\Users\Facades\UserManager;
use Backstage\Laravel\Users\Listeners\Auth\HandleUserLogin;
use Backstage\Laravel\Users\Listeners\Auth\HandleUserLogout;
use Backstage\Laravel\Users\Listeners\Auth\SendInvitationMail;
use Illuminate\Auth\Events\Login;
use Illuminate\Auth\Events\Logout;
use Illuminate\Contracts\Http\Kernel;
use Illuminate\Support\Facades\File;
use Spatie\LaravelPackageTools\Package;
use Spatie\LaravelPackageTools\PackageServiceProvider;
Expand All @@ -31,7 +39,7 @@ public function configurePackage(Package $package): void

protected function getMigrations(): array
{
$migrationPath = __DIR__ . '/../database/migrations/';
$migrationPath = __DIR__.'/../database/migrations/';

$files = File::allFiles($migrationPath);

Expand Down Expand Up @@ -61,30 +69,30 @@ public function packageBooted()
/**
* @var Illuminate\Foundation\Http\Kernel $kernel
*/
$kernel = $this->app->make(\Illuminate\Contracts\Http\Kernel::class);
$kernel = $this->app->make(Kernel::class);
});

if (config('users.eloquent.user.observer', \Backstage\Laravel\Users\Eloquent\Observers\UserObserver::class)) {
config('auth.providers.users.model', \Backstage\Laravel\Users\Eloquent\Models\User::class)::observe(config('users.eloquent.user.observer', \Backstage\Laravel\Users\Eloquent\Observers\UserObserver::class));
if (config('users.eloquent.user.observer', UserObserver::class)) {
config('auth.providers.users.model', User::class)::observe(config('users.eloquent.user.observer', UserObserver::class));
}
}

protected function getEvents()
{
$this->app['events']->listen(
\Illuminate\Auth\Events\Login::class,
\Backstage\Laravel\Users\Listeners\Auth\HandleUserLogin::class
Login::class,
HandleUserLogin::class
);

$this->app['events']->listen(
\Illuminate\Auth\Events\Logout::class,
\Backstage\Laravel\Users\Listeners\Auth\HandleUserLogout::class
Logout::class,
HandleUserLogout::class
);

if (config('users.events.auth.user_created.enabled', true)) {
$this->app['events']->listen(
UserCreated::class,
\Backstage\Laravel\Users\Listeners\Auth\SendInvitationMail::class
SendInvitationMail::class
);
}
}
Expand Down
27 changes: 13 additions & 14 deletions src/Listeners/Auth/HandleUserLogin.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,27 @@

namespace Backstage\Laravel\Users\Listeners\Auth;

use Backstage\Laravel\Users\Eloquent\Models\User;
use Backstage\Laravel\Users\Jobs\RecordUserLogin;
use Illuminate\Auth\Events\Login;

class HandleUserLogin
{
public function handle(Login $event)
public function handle(Login $event): void
{
/**
* @var \Backstage\Laravel\Users\Eloquent\Models\User $user
*/
/** @var User $user */
$user = $event->user;

$inputs = request()->except('_method', '_token', 'password');

$user->logins()->create([
'user_id' => $user->id,
'type' => 'login',
'url' => request()->url(),
'referrer' => request()->server('HTTP_REFERER'),
'inputs' => count($inputs) ? json_encode($inputs) : null,
'user_agent' => request()->server('HTTP_USER_AGENT'),
'ip_address' => request()->ip(),
'hostname' => gethostbyaddr(request()->ip()),
]);
RecordUserLogin::dispatch(
userId: $user->id,
type: 'login',
url: request()->url(),
referrer: request()->server('HTTP_REFERER'),
inputs: count($inputs) ? $inputs : null,
userAgent: request()->server('HTTP_USER_AGENT'),
ipAddress: request()->ip(),
);
}
}
31 changes: 17 additions & 14 deletions src/Listeners/Auth/HandleUserLogout.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,31 @@

namespace Backstage\Laravel\Users\Listeners\Auth;

use Backstage\Laravel\Users\Eloquent\Models\User;
use Backstage\Laravel\Users\Jobs\RecordUserLogin;
use Illuminate\Auth\Events\Logout;

class HandleUserLogout
{
public function handle(Logout $event)
public function handle(Logout $event): void
{
/**
* @var \Backstage\Laravel\Users\Eloquent\Models\User $user
*/
/** @var User|null $user */
$user = $event->user;

if (! $user) {
return;
}

$inputs = request()->except('_method', '_token', 'password');

$user->logins()->create([
'user_id' => $user->id,
'type' => 'logout',
'url' => request()->url(),
'referrer' => request()->server('HTTP_REFERER'),
'inputs' => count($inputs) ? json_encode($inputs) : null,
'user_agent' => request()->server('HTTP_USER_AGENT'),
'ip_address' => request()->ip(),
'hostname' => gethostbyaddr(request()->ip()),
]);
RecordUserLogin::dispatch(
userId: $user->id,
type: 'logout',
url: request()->url(),
referrer: request()->server('HTTP_REFERER'),
inputs: count($inputs) ? $inputs : null,
userAgent: request()->server('HTTP_USER_AGENT'),
ipAddress: request()->ip(),
);
}
}
Loading