++ 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>
This commit is contained in:
@@ -121,6 +121,12 @@ Richieste dell'utente, con le sue scelte:
|
|||||||
e — per l'amministratore — il server di posta.
|
e — per l'amministratore — il server di posta.
|
||||||
Emergenza: `php artisan utenti:conferma-email <email>`. Il primo admin
|
Emergenza: `php artisan utenti:conferma-email <email>`. Il primo admin
|
||||||
creato da riga di comando nasce confermato.
|
creato da riga di comando nasce confermato.
|
||||||
|
**Aggiornamento 19 ottobre 2026 — amministratori esenti** (scelta
|
||||||
|
dell'utente, preferita a un parametro segreto nell'URL): chi ha il ruolo
|
||||||
|
`amministratore` non deve confermare l'email (`User::esenteDaConfermaEmail`,
|
||||||
|
che fa rispondere `hasVerifiedEmail()` true). Non riceve l'email di conferma
|
||||||
|
né alla creazione né al cambio d'indirizzo; in Utenti compare "esente". Se
|
||||||
|
perde il ruolo torna a contare `email_verified_at`.
|
||||||
- Nei test gli utenti nascono confermati (`tests/TestCase.php`,
|
- Nei test gli utenti nascono confermati (`tests/TestCase.php`,
|
||||||
`$confermaUtentiCreati`).
|
`$confermaUtentiCreati`).
|
||||||
|
|
||||||
|
|||||||
@@ -41,7 +41,8 @@ class Profile extends Component
|
|||||||
|
|
||||||
// L'indirizzo nuovo va confermato (User::booted lo segna da
|
// L'indirizzo nuovo va confermato (User::booted lo segna da
|
||||||
// confermare): finché non apre il link, l'account resta bloccato.
|
// confermare): finché non apre il link, l'account resta bloccato.
|
||||||
if ($emailCambiata) {
|
// Gli amministratori sono esenti (User::esenteDaConfermaEmail).
|
||||||
|
if ($emailCambiata && ! $user->esenteDaConfermaEmail()) {
|
||||||
$user->inviaConfermaEmail()
|
$user->inviaConfermaEmail()
|
||||||
? session()->flash('success', "Profilo aggiornato. Conferma il nuovo indirizzo: ti abbiamo mandato un'email a {$user->email}.")
|
? session()->flash('success', "Profilo aggiornato. Conferma il nuovo indirizzo: ti abbiamo mandato un'email a {$user->email}.")
|
||||||
: session()->flash('error', 'Profilo aggiornato, ma l\'email di conferma non è partita: richiedila qui sotto.');
|
: session()->flash('error', 'Profilo aggiornato, ma l\'email di conferma non è partita: richiedila qui sotto.');
|
||||||
|
|||||||
@@ -86,8 +86,11 @@ class UsersIndex extends Component
|
|||||||
$this->selectedRole = $this->availableRoles[0];
|
$this->selectedRole = $this->availableRoles[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
// L'account funziona solo dopo la conferma dell'indirizzo.
|
// L'account funziona solo dopo la conferma dell'indirizzo, tranne
|
||||||
if ($user->inviaConfermaEmail()) {
|
// 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.");
|
$this->avvisa("Utente creato. Gli è stata inviata un'email a {$user->email}: l'account funziona dopo che conferma l'indirizzo.");
|
||||||
} else {
|
} else {
|
||||||
$this->avvisaErrore("Utente creato, ma l'email di conferma non è partita: controlla il server di posta e usa \"Reinvia conferma\".");
|
$this->avvisaErrore("Utente creato, ma l'email di conferma non è partita: controlla il server di posta e usa \"Reinvia conferma\".");
|
||||||
@@ -171,13 +174,14 @@ class UsersIndex extends Component
|
|||||||
$emailCambiata = $user->isDirty('email');
|
$emailCambiata = $user->isDirty('email');
|
||||||
$user->save();
|
$user->save();
|
||||||
$user->syncRoles([$validated['editSelectedRole']]);
|
$user->syncRoles([$validated['editSelectedRole']]);
|
||||||
|
$user->load('roles');
|
||||||
|
|
||||||
$this->cancelEdit();
|
$this->cancelEdit();
|
||||||
|
|
||||||
// Indirizzo nuovo: torna da confermare (User::booted) e gli si manda
|
// Indirizzo nuovo: torna da confermare (User::booted) e gli si manda
|
||||||
// il link, altrimenti il suo account smetterebbe di funzionare senza
|
// il link, altrimenti il suo account smetterebbe di funzionare senza
|
||||||
// che sappia perché.
|
// che sappia perché. Gli amministratori sono esenti.
|
||||||
if ($emailCambiata) {
|
if ($emailCambiata && ! $user->esenteDaConfermaEmail()) {
|
||||||
$inviata = $user->inviaConfermaEmail();
|
$inviata = $user->inviaConfermaEmail();
|
||||||
$inviata
|
$inviata
|
||||||
? $this->avvisa("Utente aggiornato. Il nuovo indirizzo va confermato: email inviata a {$user->email}.")
|
? $this->avvisa("Utente aggiornato. Il nuovo indirizzo va confermato: email inviata a {$user->email}.")
|
||||||
|
|||||||
@@ -58,13 +58,36 @@ class User extends Authenticatable implements MustVerifyEmail
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gli amministratori sono esenti dalla conferma dell'email: scelta
|
||||||
|
* esplicita, perché l'amministratore deve poter entrare anche quando la
|
||||||
|
* posta non funziona (è lui che la configura). Vale finché ha il ruolo:
|
||||||
|
* se lo perde, torna a contare `email_verified_at`.
|
||||||
|
*/
|
||||||
|
public function esenteDaConfermaEmail(): bool
|
||||||
|
{
|
||||||
|
return $this->hasRole('amministratore');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Usato dal middleware `verified`: un esente è sempre "confermato".
|
||||||
|
*/
|
||||||
|
public function hasVerifiedEmail(): bool
|
||||||
|
{
|
||||||
|
return $this->esenteDaConfermaEmail() || ! is_null($this->email_verified_at);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Manda l'email di conferma; false se il server di posta non risponde o
|
* Manda l'email di conferma; false se il server di posta non risponde o
|
||||||
* rifiuta. Chi chiama decide cosa dire: l'utente è comunque salvato, e
|
* rifiuta. Chi chiama decide cosa dire: l'utente è comunque salvato, e
|
||||||
* l'email si può richiedere di nuovo.
|
* l'email si può richiedere di nuovo. Agli esenti non si manda nulla.
|
||||||
*/
|
*/
|
||||||
public function inviaConfermaEmail(): bool
|
public function inviaConfermaEmail(): bool
|
||||||
{
|
{
|
||||||
|
if ($this->esenteDaConfermaEmail()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$this->sendEmailVerificationNotification();
|
$this->sendEmailVerificationNotification();
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
|
|||||||
@@ -112,7 +112,10 @@
|
|||||||
<td data-label="Nome" class="px-4 py-2 text-gray-900">{{ $user->name }}</td>
|
<td data-label="Nome" class="px-4 py-2 text-gray-900">{{ $user->name }}</td>
|
||||||
<td data-label="Email" class="px-4 py-2 text-gray-700">
|
<td data-label="Email" class="px-4 py-2 text-gray-700">
|
||||||
{{ $user->email }}
|
{{ $user->email }}
|
||||||
@if($user->hasVerifiedEmail())
|
@if($user->esenteDaConfermaEmail())
|
||||||
|
<span class="ml-1 inline-flex items-center rounded-full bg-gray-100 px-2 py-0.5 text-xs font-medium text-gray-700"
|
||||||
|
title="Gli amministratori non devono confermare l'email">esente</span>
|
||||||
|
@elseif($user->hasVerifiedEmail())
|
||||||
<span class="ml-1 inline-flex items-center rounded-full bg-green-50 px-2 py-0.5 text-xs font-medium text-green-700">confermata</span>
|
<span class="ml-1 inline-flex items-center rounded-full bg-green-50 px-2 py-0.5 text-xs font-medium text-green-700">confermata</span>
|
||||||
@else
|
@else
|
||||||
<span class="ml-1 inline-flex items-center rounded-full bg-amber-50 px-2 py-0.5 text-xs font-medium text-amber-800"
|
<span class="ml-1 inline-flex items-center rounded-full bg-amber-50 px-2 py-0.5 text-xs font-medium text-amber-800"
|
||||||
|
|||||||
@@ -65,14 +65,59 @@ class ConfermaEmailTest extends TestCase
|
|||||||
$this->actingAs($utente)->get(route('profile'))->assertOk();
|
$this->actingAs($utente)->get(route('profile'))->assertOk();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function test_un_amministratore_non_confermato_puo_configurare_la_posta(): void
|
public function test_un_amministratore_e_esente_dalla_conferma(): void
|
||||||
{
|
{
|
||||||
$admin = $this->utente('amministratore');
|
$admin = $this->utente('amministratore');
|
||||||
|
|
||||||
$this->actingAs($admin)->get(route('settings.edit'))->assertRedirect(route('verification.notice'));
|
$this->assertNull($admin->email_verified_at);
|
||||||
|
$this->assertTrue($admin->hasVerifiedEmail());
|
||||||
|
$this->actingAs($admin)->get(route('settings.edit'))->assertOk();
|
||||||
$this->actingAs($admin)->get(route('posta.edit'))->assertOk()->assertSee('Server di posta');
|
$this->actingAs($admin)->get(route('posta.edit'))->assertOk()->assertSee('Server di posta');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function test_chi_perde_il_ruolo_di_amministratore_torna_a_dover_confermare(): void
|
||||||
|
{
|
||||||
|
$utente = $this->utente('amministratore');
|
||||||
|
$utente->syncRoles(['operatore']);
|
||||||
|
|
||||||
|
$this->assertFalse($utente->fresh()->hasVerifiedEmail());
|
||||||
|
$this->actingAs($utente->fresh())->get(route('dashboard'))->assertRedirect(route('verification.notice'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_all_amministratore_creato_non_parte_la_conferma(): void
|
||||||
|
{
|
||||||
|
Notification::fake();
|
||||||
|
$admin = $this->utente('amministratore');
|
||||||
|
|
||||||
|
Livewire::actingAs($admin)->test(UsersIndex::class)
|
||||||
|
->set('name', 'Luca Neri')
|
||||||
|
->set('email', 'luca@example.test')
|
||||||
|
->set('password', 'password-di-prova')
|
||||||
|
->set('password_confirmation', 'password-di-prova')
|
||||||
|
->set('selectedRole', 'amministratore')
|
||||||
|
->call('createUser')
|
||||||
|
->assertHasNoErrors();
|
||||||
|
|
||||||
|
$nuovo = User::where('email', 'luca@example.test')->sole();
|
||||||
|
$this->assertTrue($nuovo->hasVerifiedEmail());
|
||||||
|
Notification::assertNothingSentTo($nuovo);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_l_amministratore_che_cambia_email_resta_dentro(): void
|
||||||
|
{
|
||||||
|
Notification::fake();
|
||||||
|
$admin = $this->utente('amministratore');
|
||||||
|
|
||||||
|
Livewire::actingAs($admin)->test(Profile::class)
|
||||||
|
->set('name', 'Mario Rossi')
|
||||||
|
->set('email', 'nuovo-admin@example.test')
|
||||||
|
->call('updateProfile')
|
||||||
|
->assertRedirect(route('profile'));
|
||||||
|
|
||||||
|
$this->assertTrue($admin->fresh()->hasVerifiedEmail());
|
||||||
|
Notification::assertNothingSentTo($admin->fresh());
|
||||||
|
}
|
||||||
|
|
||||||
public function test_il_link_conferma_anche_senza_essere_entrati(): void
|
public function test_il_link_conferma_anche_senza_essere_entrati(): void
|
||||||
{
|
{
|
||||||
$utente = $this->utente();
|
$utente = $this->utente();
|
||||||
|
|||||||
Reference in New Issue
Block a user