Skip to content

Commit 780bb9b

Browse files
committed
wip
1 parent fa128fa commit 780bb9b

File tree

8 files changed

+223
-10
lines changed

8 files changed

+223
-10
lines changed

.DS_Store

0 Bytes
Binary file not shown.

composer.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,9 @@
8080
"providers": [
8181
"Backstage\\Laravel\\Users\\LaravelUsersServiceProvider"
8282
],
83-
"aliases": {}
83+
"aliases": {
84+
"LaravelUsers": "Backstage\\Laravel\\Users\\Facades\\LaravelUsers"
85+
}
8486
}
8587
},
8688
"minimum-stability": "dev",

src/Commands/ListUsersCommand.php

Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
<?php
2+
3+
namespace Backstage\Laravel\Users\Commands;
4+
5+
use function Termwind\ask;
6+
use Illuminate\Console\Command;
7+
use function Laravel\Prompts\info;
8+
9+
use function Laravel\Prompts\text;
10+
use Illuminate\Support\Collection;
11+
use Spatie\Permission\Models\Role;
12+
use function Laravel\Prompts\error;
13+
use function Laravel\Prompts\table;
14+
use function Laravel\Prompts\search;
15+
use function Laravel\Prompts\select;
16+
use Spatie\Permission\Traits\HasRoles;
17+
use function Laravel\Prompts\multisearch;
18+
use Spatie\Permission\Traits\HasPermissions;
19+
use Backstage\Laravel\Users\Eloquent\Models\User;
20+
21+
class ListUsersCommand extends Command
22+
{
23+
protected $signature = 'users:list {--edit}';
24+
25+
protected $description = 'List all users in the system.';
26+
27+
public function handle(): void
28+
{
29+
$users = User::all();
30+
31+
if ($users->isEmpty()) {
32+
error('No users found.');
33+
return;
34+
}
35+
36+
info('Found ' . $users->count() . ' user(s):');
37+
38+
$this->renderTable($users);
39+
40+
if (!$this->option('edit')) {
41+
$editingUsers = $this->confirm('Do you want to edit any user?', false);
42+
43+
if (!$editingUsers) {
44+
return;
45+
}
46+
}
47+
48+
$userId = search(
49+
label: 'Search for the user that should receive the mail',
50+
options: fn(string $value) => strlen($value) > 0
51+
? User::whereLike('name', "%{$value}%")->pluck('name', 'id')->map(fn($name, $id) => $name . ' (ID: ' . $id . ')')->toArray()
52+
: []
53+
);
54+
55+
/**
56+
* @var HasRoles $user
57+
*/
58+
$user = User::find($userId);
59+
60+
if (!$user) {
61+
error('User not found!');
62+
return;
63+
}
64+
65+
info('User selected:');
66+
$this->renderTable(collect([$user]));
67+
68+
$changableFields = ['name', 'email', 'roles'];
69+
70+
$fieldToChange = $this->choice('Which field do you want to change?', $changableFields);
71+
72+
switch ($fieldToChange) {
73+
case 'name':
74+
$newName = text('Enter the new name:', required: true);
75+
$user->name = $newName;
76+
break;
77+
78+
case 'email':
79+
$newEmail = text('Enter the new email:', required: true);
80+
$user->email = $newEmail;
81+
break;
82+
83+
case 'roles':
84+
$attachingRoles = $this->confirm('Do you want to attach roles to the user?', false);
85+
86+
if (!$attachingRoles) {
87+
$detachingRoles = $this->confirm('Do you want to detach roles from the user?', false);
88+
89+
$contaningRoles = $user->getRoleNames();
90+
91+
if ($contaningRoles->isEmpty()) {
92+
error('User has no roles to detach.');
93+
return;
94+
}
95+
96+
$selectedRoles = multisearch(
97+
label: 'Select the roles to detach from the user',
98+
options: fn(string $value) => strlen($value) > 0
99+
? $contaningRoles->values()->all()
100+
: [],
101+
required: true,
102+
);
103+
104+
$collectedSeletedRoles = collect($selectedRoles);
105+
106+
if ($collectedSeletedRoles->isEmpty()) {
107+
error('No roles selected.');
108+
return;
109+
}
110+
111+
foreach ($collectedSeletedRoles->toArray() as $role) {
112+
$user->removeRole($role);
113+
}
114+
115+
info('Roles detached from the user.');
116+
117+
return;
118+
}
119+
120+
$roleClass = config('permission.models.role', Role::class);
121+
$allRoles = $roleClass::pluck('name');
122+
$currentUserRoles = $user->getRoleNames();
123+
124+
$diffedRoles = $allRoles->diff($currentUserRoles);
125+
126+
if ($diffedRoles->isEmpty()) {
127+
error('No roles available to assign to the user.');
128+
return;
129+
}
130+
131+
$selectedRoles = multisearch(
132+
label: 'Select the roles to assign to the user',
133+
options: fn(string $value) => strlen($value) > 0
134+
? $diffedRoles->values()->all()
135+
: [],
136+
required: true,
137+
);
138+
139+
$collectedSeletedRoles = collect($selectedRoles);
140+
141+
if ($collectedSeletedRoles->isEmpty()) {
142+
error('No roles selected.');
143+
return;
144+
}
145+
146+
$user->syncRoles($collectedSeletedRoles->toArray());
147+
}
148+
149+
$user->save();
150+
}
151+
152+
protected function renderTable(Collection $users)
153+
{
154+
table([
155+
'ID',
156+
'Name',
157+
'Email',
158+
'Verified',
159+
'Role(s)',
160+
'Created At'
161+
], $users->map(fn(User $user) => [
162+
$user->id,
163+
$user->name,
164+
$user->email,
165+
$user->hasVerifiedEmail() ? 'Yes' : 'No',
166+
$user->getRoleNames()->implode(', ') ?: 'No roles',
167+
$user->created_at->format('Y-m-d H:i:s') . ' (' . $user->created_at->diffForHumans() . ')',
168+
])->toArray());
169+
}
170+
}

src/Commands/MakeUserCommand.php

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ public function handle(): int
3232
$name = $this->option('name') ?: text('Name', placeholder: 'John Doe', required: true);
3333
$email = $this->validateColumn($this->option('email') ?: text('Email', placeholder: 'john@doe.nl', required: true), 'email');
3434
$password = $this->option('password') ?: password('Password', placeholder: 'secret', required: true);
35+
$verified = $this->confirm('Is the user verified?', true);
3536

3637
$roleClass = config('permission.models.role', Role::class);
3738
$userClass = config('users.eloquent.user.model', User::class);
@@ -75,6 +76,11 @@ public function handle(): int
7576
$user->name = $name;
7677
$user->email = $email;
7778
$user->password = Hash::make($password);
79+
80+
if ($verified) {
81+
$user->email_verified_at = now();
82+
}
83+
7884
$user->save();
7985

8086
if ($selectedRole instanceof Role) {
@@ -100,7 +106,7 @@ public function handle(): int
100106
$this->line("Name: {$user->name}");
101107
$this->line("Email: {$user->email}");
102108
if ($selectedRole) {
103-
$this->line('Role: '.($selectedRole instanceof Role ? $selectedRole->name : $selectedRole));
109+
$this->line('Role: ' . ($selectedRole instanceof Role ? $selectedRole->name : $selectedRole));
104110
}
105111
$this->line("Password: {$password}");
106112

src/Facades/UserManager.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php
2+
3+
namespace Backstage\Laravel\Users\Facades;
4+
5+
use Illuminate\Support\Facades\Facade;
6+
7+
/**
8+
* @see \Backstage\Laravel\Users\UserManager
9+
*/
10+
class UserManager extends Facade
11+
{
12+
protected static function getFacadeAccessor()
13+
{
14+
return 'user-manager';
15+
}
16+
}

src/LaravelUsersServiceProvider.php

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,16 @@
22

33
namespace Backstage\Laravel\Users;
44

5-
use Backstage\Laravel\Users\Commands\MakeUserCommand;
6-
use Backstage\Laravel\Users\Events\Auth\UserCreated;
7-
use Backstage\Laravel\Users\Events\Request\WebTrafficDetected;
8-
use Backstage\Laravel\Users\Http\Middleware\DetectUserTraffic;
5+
use SplFileInfo;
96
use Illuminate\Support\Facades\File;
107
use Spatie\LaravelPackageTools\Package;
8+
use Backstage\Laravel\Users\Facades\UserManager;
9+
use Backstage\Laravel\Users\Events\Auth\UserCreated;
10+
use Backstage\Laravel\Users\Commands\MakeUserCommand;
11+
use Backstage\Laravel\Users\Commands\ListUsersCommand;
1112
use Spatie\LaravelPackageTools\PackageServiceProvider;
12-
use SplFileInfo;
13+
use Backstage\Laravel\Users\Events\Request\WebTrafficDetected;
14+
use Backstage\Laravel\Users\Http\Middleware\DetectUserTraffic;
1315

1416
class LaravelUsersServiceProvider extends PackageServiceProvider
1517
{
@@ -21,24 +23,34 @@ public function configurePackage(Package $package): void
2123
->hasMigrations($this->getMigrations())
2224
->hasCommands([
2325
MakeUserCommand::class,
26+
ListUsersCommand::class
2427
]);
2528
}
2629

2730
protected function getMigrations(): array
2831
{
29-
$migrationPath = __DIR__.'/../database/migrations/';
32+
$migrationPath = __DIR__ . '/../database/migrations/';
3033

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

3336
$migrations = collect($files)
34-
->map(fn (SplFileInfo $splFile) => str($splFile->getBasename())->before('.')->toString())
37+
->map(fn(SplFileInfo $splFile) => str($splFile->getBasename())->before('.')->toString())
3538
->toArray();
3639

3740
return [
3841
...$migrations,
3942
];
4043
}
4144

45+
public function packageRegistered()
46+
{
47+
$this->app->singleton('user-manager', function ($app) {
48+
return new UserManager($app);
49+
});
50+
51+
$this->app->alias('user-manager', UserManager::class);
52+
}
53+
4254
public function packageBooted()
4355
{
4456
$this->getEvents();

src/Listeners/Auth/SendInvitationMail.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ class SendInvitationMail
99
{
1010
public function handle(UserCreated $event)
1111
{
12-
$event->user->notify(new Invitation);
12+
$invitationClass = config('users.events.auth.user_created.invitation_notification', Invitation::class);
13+
14+
$event->user->notify(new $invitationClass);
1315
}
1416
}

src/UserManager.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<?php
2+
3+
namespace Backstage\Laravel\Users;
4+
5+
class UserManager {}

0 commit comments

Comments
 (0)