Files
termanager2/app/Livewire/Settings/UsersIndex.php
Francesco Picone ac787039c3 ++ amministratori esenti dalla conferma email
Chi ha il ruolo amministratore non deve confermare l'indirizzo
(User::esenteDaConfermaEmail): non riceve l'email di conferma né alla
creazione né al cambio d'indirizzo, in Utenti compare "esente". Se perde
il ruolo torna a valere email_verified_at.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 12:19:29 +02:00

257 lines
8.7 KiB
PHP

<?php
namespace App\Livewire\Settings;
use App\Livewire\Concerns\Avvisa;
use App\Models\Assegnazione;
use App\Models\User;
use Illuminate\Support\Facades\DB;
use Illuminate\Validation\Rule;
use Livewire\Attributes\Locked;
use Livewire\Component;
use Spatie\Activitylog\Models\Activity;
use Spatie\Permission\Models\Role;
class UsersIndex extends Component
{
use Avvisa;
public string $name = '';
public string $email = '';
public string $password = '';
public string $password_confirmation = '';
public string $selectedRole = '';
// Locked: è la lista che le regole di validazione usano per accettare un
// ruolo; modificabile dal client, ammetterebbe qualsiasi nome.
#[Locked]
public array $availableRoles = [];
public ?int $editingUserId = null;
public string $editName = '';
public string $editEmail = '';
public string $editPassword = '';
public string $editPassword_confirmation = '';
public string $editSelectedRole = '';
public function mount(): void
{
$this->availableRoles = Role::query()
->orderBy('name')
->pluck('name')
->all();
if (! empty($this->availableRoles)) {
$this->selectedRole = $this->availableRoles[0];
}
}
protected function rules(): array
{
return [
'name' => ['required', 'string', 'max:255'],
'email' => ['required', 'email', 'max:255', Rule::unique('users', 'email')],
'password' => ['required', 'string', 'min:8', 'confirmed'],
'selectedRole' => ['required', 'string', Rule::in($this->availableRoles)],
];
}
protected function editRules(): array
{
return [
'editName' => ['required', 'string', 'max:255'],
'editEmail' => [
'required',
'email',
'max:255',
Rule::unique('users', 'email')->ignore($this->editingUserId),
],
'editPassword' => ['nullable', 'string', 'min:8', 'confirmed'],
'editSelectedRole' => ['required', 'string', Rule::in($this->availableRoles)],
];
}
public function createUser(): void
{
$validated = $this->validate();
$user = User::create([
'name' => $validated['name'],
'email' => $validated['email'],
'password' => $validated['password'],
]);
$user->syncRoles([$validated['selectedRole']]);
$this->reset(['name', 'email', 'password', 'password_confirmation']);
if (! empty($this->availableRoles)) {
$this->selectedRole = $this->availableRoles[0];
}
// L'account funziona solo dopo la conferma dell'indirizzo, tranne
// per gli amministratori (User::esenteDaConfermaEmail).
if ($user->esenteDaConfermaEmail()) {
$this->avvisa('Utente creato. Gli amministratori non devono confermare l\'email: l\'account funziona subito.');
} elseif ($user->inviaConfermaEmail()) {
$this->avvisa("Utente creato. Gli è stata inviata un'email a {$user->email}: l'account funziona dopo che conferma l'indirizzo.");
} else {
$this->avvisaErrore("Utente creato, ma l'email di conferma non è partita: controlla il server di posta e usa \"Reinvia conferma\".");
}
}
public function reinviaConferma(int $userId): void
{
$user = User::query()->findOrFail($userId);
if ($user->hasVerifiedEmail()) {
$this->avvisa("{$user->email} è già confermato.");
return;
}
if ($user->inviaConfermaEmail()) {
$this->avvisa("Email di conferma inviata a {$user->email}.");
} else {
$this->avvisaErrore('L\'email non è partita: controlla il server di posta.');
}
}
public function startEdit(int $userId): void
{
$user = User::query()->with('roles')->findOrFail($userId);
$this->editingUserId = $user->id;
$this->editName = $user->name;
$this->editEmail = $user->email;
$this->editPassword = '';
$this->editPassword_confirmation = '';
$this->editSelectedRole = $user->roles->first()?->name ?? ($this->availableRoles[0] ?? '');
}
public function cancelEdit(): void
{
$this->reset([
'editingUserId',
'editName',
'editEmail',
'editPassword',
'editPassword_confirmation',
'editSelectedRole',
]);
}
public function updateUser(): void
{
if (! $this->editingUserId) {
return;
}
$validated = $this->validate($this->editRules());
$user = User::query()->findOrFail($this->editingUserId);
// Togliere il ruolo di amministratore a sé stessi, o all'ultimo
// rimasto, lascia l'installazione senza nessuno che possa gestire
// utenti, impostazioni e backup.
if ($user->hasRole('amministratore') && $validated['editSelectedRole'] !== 'amministratore') {
if ($user->id === auth()->id()) {
$this->addError('editSelectedRole', 'Non puoi togliere a te stesso il ruolo di amministratore: chiedilo a un altro amministratore.');
return;
}
if (User::role('amministratore')->count() <= 1) {
$this->addError('editSelectedRole', "È l'ultimo amministratore: assegna prima il ruolo a un altro utente.");
return;
}
}
$user->name = $validated['editName'];
$user->email = $validated['editEmail'];
if (! empty($validated['editPassword'])) {
$user->password = $validated['editPassword'];
}
$emailCambiata = $user->isDirty('email');
$user->save();
$user->syncRoles([$validated['editSelectedRole']]);
$user->load('roles');
$this->cancelEdit();
// Indirizzo nuovo: torna da confermare (User::booted) e gli si manda
// il link, altrimenti il suo account smetterebbe di funzionare senza
// che sappia perché. Gli amministratori sono esenti.
if ($emailCambiata && ! $user->esenteDaConfermaEmail()) {
$inviata = $user->inviaConfermaEmail();
$inviata
? $this->avvisa("Utente aggiornato. Il nuovo indirizzo va confermato: email inviata a {$user->email}.")
: $this->avvisaErrore('Utente aggiornato, ma l\'email di conferma del nuovo indirizzo non è partita: controlla il server di posta.');
return;
}
$this->avvisa('Utente aggiornato con successo.');
}
public function deleteUser(int $userId): void
{
$currentUser = auth()->user();
$user = User::query()->with('roles')->findOrFail($userId);
if (! $currentUser || $currentUser->id === $user->id) {
$this->avvisaErrore('Non puoi cancellare il tuo utente.');
return;
}
if ($user->hasRole('amministratore') && User::role('amministratore')->count() <= 1) {
$this->avvisaErrore('Non puoi cancellare l\'ultimo amministratore.');
return;
}
DB::transaction(function () use ($user, $currentUser) {
$causerName = $user->name;
$causerEmail = $user->email;
$deletedAt = now()->toDateTimeString();
Activity::query()
->where('causer_type', User::class)
->where('causer_id', $user->id)
->chunkById(200, function ($activities) use ($causerName, $causerEmail, $deletedAt) {
foreach ($activities as $activity) {
$properties = $activity->properties?->toArray() ?? [];
$properties['causer_name'] = $causerName;
$properties['causer_email'] = $causerEmail;
$properties['causer_deleted_at'] = $deletedAt;
$activity->properties = $properties;
$activity->save();
}
});
Assegnazione::query()
->where('created_by', $user->id)
->update(['created_by' => $currentUser->id]);
Assegnazione::query()
->where('returned_by', $user->id)
->update(['returned_by' => $currentUser->id]);
$user->syncRoles([]);
$user->delete();
});
if ($this->editingUserId === $userId) {
$this->cancelEdit();
}
$this->avvisa('Utente cancellato. I log sono stati preservati.');
}
public function render()
{
return view('livewire.settings.users-index', [
'users' => User::query()->with('roles')->orderBy('name')->get(),
]);
}
}