++ gruppi: il gruppo sciolto si elimina; il sorvegliante entra con un nome utente dal nome del gruppo
- Sciolto, il gruppo non resta nello storico: si elimina (via sciolto_at;
la migrazione elimina anche quelli gia' sciolti). I territori solo nel
pacchetto tornano in reparto; quelli gia' dati restano ai membri, e
l'assegnazione conserva il nome del gruppo (assegnazioni.gruppo_nome).
- Creando il gruppo non si chiede l'email: users.username dal nome del
gruppo ("Gruppo Zisa" -> gruppo.zisa), users.email facoltativa. Login con
"Email o nome utente". Nome del gruppo unico.
- Sciolto il gruppo il nome utente si libera (l'utenza disattivata prende
ex.sorvegliante.<id>). XML: nome utente e gruppo_nome.
- Profilo, testata, cambio password e Utenti mostrano il nome utente dove
manca l'email. Informativa privacy, README, HANDOFF e test aggiornati.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -68,12 +68,12 @@ class GruppiServizioTest extends TestCase
|
||||
$rossi = $this->proclamatore('Rossi', 'Mario');
|
||||
$verdi = $this->proclamatore('Verdi', 'Anna');
|
||||
$bianchi = $this->proclamatore('Bianchi', 'Luca');
|
||||
[$gruppo, $password] = app(GruppiServizio::class)->crea('Zisa', $rossi, 'mario@example.test', [$verdi->id, $bianchi->id]);
|
||||
[$gruppo, $password] = app(GruppiServizio::class)->crea('Zisa', $rossi, [$verdi->id, $bianchi->id]);
|
||||
$territori = collect(['12', '14', '35'])->map(fn ($n) => $this->territorio($n));
|
||||
app(GruppiServizio::class)->aggiungiAlPacchetto($gruppo, $territori->pluck('id')->all());
|
||||
$territori = $territori->map->fresh();
|
||||
|
||||
$sorvegliante = User::where('email', 'mario@example.test')->sole();
|
||||
$sorvegliante = User::where('username', 'zisa')->sole();
|
||||
// Il cambio password al primo accesso ha i suoi test: qui si lavora.
|
||||
// E l'email non confermata, come nella realtà (TestCase le conferma).
|
||||
$sorvegliante->forceFill(['password_change_required' => false, 'email_verified_at' => null])->save();
|
||||
@@ -87,16 +87,20 @@ class GruppiServizioTest extends TestCase
|
||||
{
|
||||
$rossi = $this->proclamatore('Rossi', 'Mario');
|
||||
|
||||
// Niente email: il nome utente viene dal nome del gruppo.
|
||||
$pagina = Livewire::test(GruppiIndex::class)
|
||||
->assertDontSee('Email per l')
|
||||
->set('nome', 'Zisa')
|
||||
->set('sorveglianteId', $rossi->id)
|
||||
->set('email', 'mario@example.test')
|
||||
->call('crea')
|
||||
->assertHasNoErrors();
|
||||
->assertHasNoErrors()
|
||||
->assertSee('Nome utente')
|
||||
->assertSee('zisa');
|
||||
|
||||
$gruppo = GruppoServizio::sole();
|
||||
$utente = User::where('email', 'mario@example.test')->sole();
|
||||
$utente = User::where('username', 'zisa')->sole();
|
||||
|
||||
$this->assertNull($utente->email);
|
||||
$this->assertSame($rossi->id, $gruppo->sorvegliante_id);
|
||||
$this->assertSame($gruppo->id, $rossi->fresh()->gruppo_servizio_id, 'Il sorvegliante è anche membro');
|
||||
$this->assertSame($rossi->id, $utente->proclamatore_id);
|
||||
@@ -114,10 +118,27 @@ class GruppiServizioTest extends TestCase
|
||||
$this->assertTrue(\Illuminate\Support\Facades\Hash::check($password, $utente->password));
|
||||
}
|
||||
|
||||
public function test_il_nome_utente_viene_dal_nome_del_gruppo(): void
|
||||
{
|
||||
$servizio = app(GruppiServizio::class);
|
||||
|
||||
$servizio->crea('Gruppo Noce Città', $this->proclamatore('Neri'));
|
||||
$this->assertSame('gruppo.noce.citta', User::whereNotNull('username')->sole()->username);
|
||||
|
||||
// Già preso (per esempio da un'utenza riattivata): un numero in coda.
|
||||
User::create(['name' => 'Altro', 'username' => 'zisa', 'password' => 'password-di-prova']);
|
||||
$servizio->crea('Zisa', $this->proclamatore('Gialli'));
|
||||
$this->assertTrue(User::where('username', 'zisa2')->exists());
|
||||
|
||||
// Due gruppi con lo stesso nome no.
|
||||
$this->expectException(InvalidArgumentException::class);
|
||||
$servizio->crea('Zisa', $this->proclamatore('Blu'));
|
||||
}
|
||||
|
||||
public function test_un_proclamatore_sta_in_un_solo_gruppo(): void
|
||||
{
|
||||
['gruppo' => $zisa, 'verdi' => $verdi] = $this->gruppo();
|
||||
[$noce] = app(GruppiServizio::class)->crea('Noce', $this->proclamatore('Neri'), 'neri@example.test');
|
||||
[$noce] = app(GruppiServizio::class)->crea('Noce', $this->proclamatore('Neri'));
|
||||
|
||||
$this->expectException(InvalidArgumentException::class);
|
||||
app(GruppiServizio::class)->aggiungiMembri($noce, [$verdi->id]);
|
||||
@@ -199,16 +220,25 @@ class GruppiServizioTest extends TestCase
|
||||
$this->get(route('dashboard'))->assertOk()->assertDontSee('Il mio gruppo')->assertSee('Gruppi di servizio');
|
||||
}
|
||||
|
||||
public function test_il_sorvegliante_entra_senza_conferma_dell_email_e_va_al_suo_gruppo(): void
|
||||
public function test_il_sorvegliante_entra_con_il_nome_utente_e_va_al_suo_gruppo(): void
|
||||
{
|
||||
$this->gruppo();
|
||||
$this->flushSession();
|
||||
auth()->logout();
|
||||
$password = 'una-password-nuova-1';
|
||||
User::where('email', 'mario@example.test')->sole()->forceFill(['password' => $password])->save();
|
||||
User::where('username', 'zisa')->sole()->forceFill(['password' => $password])->save();
|
||||
|
||||
$this->post(route('login.store'), ['email' => 'mario@example.test', 'password' => $password])
|
||||
$this->get(route('login'))->assertSee('Email o nome utente');
|
||||
|
||||
// Senza badare alle maiuscole (la tastiera del telefono le mette da sé).
|
||||
$this->post(route('login.store'), ['email' => 'Zisa', 'password' => $password])
|
||||
->assertRedirect(route('mio-gruppo'));
|
||||
|
||||
// Gli altri continuano a entrare con l'email.
|
||||
auth()->logout();
|
||||
$this->flushSession();
|
||||
$this->post(route('login.store'), ['email' => 'admin@example.test', 'password' => 'password-di-prova'])
|
||||
->assertRedirect(route('dashboard'));
|
||||
}
|
||||
|
||||
// ─── Il sorvegliante al lavoro ──────────────────────────────
|
||||
@@ -322,19 +352,29 @@ class GruppiServizioTest extends TestCase
|
||||
['gruppo' => $gruppo, 'sorvegliante' => $s, 'verdi' => $verdi, 'territori' => $territori] = $this->gruppo();
|
||||
$data = app(GruppiServizio::class)->assegna($gruppo, $territori[0], $verdi, now());
|
||||
|
||||
Livewire::test(GruppoShow::class, ['gruppo' => $gruppo])->call('sciogli');
|
||||
Livewire::test(GruppoShow::class, ['gruppo' => $gruppo])
|
||||
->call('sciogli')
|
||||
->assertRedirect(route('gruppi.index'));
|
||||
|
||||
$gruppo->refresh();
|
||||
$this->assertNotNull($gruppo->sciolto_at);
|
||||
// I non dati tornano in reparto; quello dato resta a Verdi, assegnazione normale.
|
||||
// Il gruppo non resta nello storico: non esiste più.
|
||||
$this->assertNull(GruppoServizio::find($gruppo->id));
|
||||
$this->get(route('gruppi.index'))->assertOk()->assertSee('Nessun gruppo di servizio');
|
||||
// I non dati tornano in reparto; quello dato resta a Verdi, assegnazione
|
||||
// normale, che del gruppo conserva solo il nome.
|
||||
$this->assertNull($territori[1]->fresh()->gruppo_servizio_id);
|
||||
$this->assertNull($territori[2]->fresh()->gruppo_servizio_id);
|
||||
$this->assertSame('in_reparto', $territori[2]->fresh()->stato);
|
||||
$this->assertNull($data->fresh()->returned_at);
|
||||
$this->assertSame($gruppo->id, $data->fresh()->gruppo_servizio_id, 'Lo storico continua a dirlo');
|
||||
// Membri liberi, utenza disattivata e senza ruolo.
|
||||
$this->assertSame(0, Proclamatore::where('gruppo_servizio_id', $gruppo->id)->count());
|
||||
$this->assertSame('assegnato', $territori[0]->fresh()->stato);
|
||||
$this->assertNull($data->fresh()->gruppo_servizio_id);
|
||||
$this->assertSame('Zisa', $data->fresh()->gruppo_nome);
|
||||
$this->get(route('territori.show', $territori[0]))->assertOk()->assertSee('via gruppo Zisa');
|
||||
// Membri liberi; utenza disattivata, senza ruolo, e il nome utente del
|
||||
// gruppo è libero.
|
||||
$this->assertSame(0, Proclamatore::whereNotNull('gruppo_servizio_id')->count());
|
||||
$this->assertTrue($s->fresh()->isDisattivato());
|
||||
$this->assertFalse($s->fresh()->hasRole('sorvegliante'));
|
||||
$this->assertSame("ex.sorvegliante.{$s->id}", $s->fresh()->username);
|
||||
$this->assertFalse(User::where('username', 'zisa')->exists());
|
||||
|
||||
// Per ripartire serve un gruppo nuovo.
|
||||
$this->expectException(InvalidArgumentException::class);
|
||||
@@ -350,7 +390,7 @@ class GruppiServizioTest extends TestCase
|
||||
$this->flushSession();
|
||||
auth()->logout();
|
||||
|
||||
$this->post(route('login.store'), ['email' => 'mario@example.test', 'password' => $password])
|
||||
$this->post(route('login.store'), ['email' => 'zisa', 'password' => $password])
|
||||
->assertSessionHasErrors('email');
|
||||
$this->assertGuest();
|
||||
|
||||
@@ -365,13 +405,14 @@ class GruppiServizioTest extends TestCase
|
||||
$pagina = Livewire::test(GruppiIndex::class);
|
||||
$this->assertContains((string) $rossi->id, collect($pagina->viewData('opzioniSorveglianti'))->pluck('valore')->all(), 'Torna tra i candidati');
|
||||
|
||||
[$nuovo, $password] = app(GruppiServizio::class)->crea('Zisa 2', $rossi->fresh(), 'mario.nuovo@example.test');
|
||||
// Sciolto, il nome non è più occupato: si può rifare "Zisa".
|
||||
[$nuovo, $password] = app(GruppiServizio::class)->crea('Zisa', $rossi->fresh());
|
||||
|
||||
$utente = $s->fresh();
|
||||
$this->assertSame(1, User::where('proclamatore_id', $rossi->id)->count(), 'Un proclamatore, un\'utenza');
|
||||
$this->assertFalse($utente->isDisattivato());
|
||||
$this->assertTrue($utente->hasRole('sorvegliante'));
|
||||
$this->assertSame('mario.nuovo@example.test', $utente->email);
|
||||
$this->assertSame('zisa', $utente->username);
|
||||
$this->assertTrue($utente->password_change_required);
|
||||
$this->assertTrue(\Illuminate\Support\Facades\Hash::check($password, $utente->password));
|
||||
$this->assertSame($nuovo->id, $utente->gruppoSorvegliato()?->id);
|
||||
@@ -382,7 +423,8 @@ class GruppiServizioTest extends TestCase
|
||||
/** Il gruppo è sciolto come da "Togli il ruolo": tutto tranne l'assegnazione già fatta. */
|
||||
private function assertSciolto(array $g, Assegnazione $data): void
|
||||
{
|
||||
$this->assertNotNull($g['gruppo']->fresh()->sciolto_at, 'Gruppo sciolto');
|
||||
$this->assertNull(GruppoServizio::find($g['gruppo']->id), 'Gruppo sciolto ed eliminato');
|
||||
$this->assertSame('Zisa', $data->fresh()->gruppo_nome);
|
||||
$this->assertNull($g['territori'][1]->fresh()->gruppo_servizio_id, 'I non dati tornano in reparto');
|
||||
$this->assertSame('in_reparto', $g['territori'][2]->fresh()->stato);
|
||||
$this->assertNull($data->fresh()->returned_at, 'Quello già dato resta al membro');
|
||||
@@ -406,7 +448,7 @@ class GruppiServizioTest extends TestCase
|
||||
|
||||
// Riattivarlo non ricostruisce il gruppo: se ne crea uno nuovo.
|
||||
Livewire::test(\App\Livewire\Proclamatori\ProclamatoreIndex::class)->call('toggleActive', $g['rossi']->id);
|
||||
$this->assertNotNull($g['gruppo']->fresh()->sciolto_at);
|
||||
$this->assertSame(0, GruppoServizio::count());
|
||||
$this->assertNull($g['rossi']->fresh()->gruppoSorvegliato());
|
||||
}
|
||||
|
||||
@@ -445,7 +487,7 @@ class GruppiServizioTest extends TestCase
|
||||
->call('toggleActive', $verdi->id)
|
||||
->call('deleteProclamatore', $bianchi->id);
|
||||
|
||||
$this->assertNull($gruppo->fresh()->sciolto_at);
|
||||
$this->assertNotNull(GruppoServizio::find($gruppo->id));
|
||||
$this->assertSame($gruppo->id, $verdi->fresh()->gruppo_servizio_id, 'Non attivo resta membro, ma non riceve territori');
|
||||
$this->assertNull($bianchi->fresh()->gruppo_servizio_id, 'Nel cestino lascia il gruppo');
|
||||
}
|
||||
@@ -459,17 +501,18 @@ class GruppiServizioTest extends TestCase
|
||||
|
||||
$this->get(route('proclamatori.show', $g['rossi']))->assertOk()
|
||||
->assertSeeInOrder(['Gruppo di servizio', 'Sorvegliante', 'Zisa', 'Membri', '3', 'Nel pacchetto', '3', 'Da dare', '2', 'Assegnazioni dal gruppo', '1'])
|
||||
->assertSee('mario@example.test')
|
||||
->assertSee('<code>zisa</code>', false)
|
||||
->assertSee('non è ancora entrato');
|
||||
|
||||
$this->get(route('proclamatori.show', $g['verdi']))->assertOk()
|
||||
->assertSee('Membro del gruppo')
|
||||
->assertSee('sorvegliante Rossi Mario');
|
||||
|
||||
// Sciolto il gruppo, nella scheda non ne resta traccia.
|
||||
app(GruppiServizio::class)->sciogli($g['gruppo']);
|
||||
$this->get(route('proclamatori.show', $g['rossi']))->assertOk()
|
||||
->assertSee('In passato sorvegliante di:')
|
||||
->assertDontSee('Assegnazioni dal gruppo');
|
||||
->assertDontSee('Assegnazioni dal gruppo')
|
||||
->assertDontSee('In passato');
|
||||
}
|
||||
|
||||
public function test_chi_fa_parte_di_un_gruppo_e_segnalato_in_elenco_scheda_e_scelta(): void
|
||||
@@ -529,7 +572,8 @@ class GruppiServizioTest extends TestCase
|
||||
|
||||
$utente = $s->fresh();
|
||||
$this->assertSame('Anonimo', $utente->name);
|
||||
$this->assertStringEndsWith('@anonimo.invalid', $utente->email);
|
||||
$this->assertNull($utente->email);
|
||||
$this->assertSame("anonimo.{$utente->id}", $utente->username);
|
||||
$this->assertTrue($utente->isDisattivato());
|
||||
$this->assertCount(0, $utente->roles);
|
||||
}
|
||||
@@ -579,6 +623,25 @@ class GruppiServizioTest extends TestCase
|
||||
$this->assertEqualsCanonicalizing(['Rossi Mario', 'Verdi Anna', 'Bianchi Luca'], $g->membri->map->nome_completo->all());
|
||||
$this->assertEqualsCanonicalizing(['12', '14', '35'], $g->territori->pluck('numero')->all());
|
||||
$this->assertSame($g->id, Assegnazione::sole()->gruppo_servizio_id);
|
||||
$this->assertSame($g->sorvegliante_id, User::where('email', 'mario@example.test')->sole()->proclamatore_id);
|
||||
$this->assertSame('Zisa', Assegnazione::sole()->gruppo_nome);
|
||||
$utenza = User::where('username', 'zisa')->sole();
|
||||
$this->assertNull($utenza->email);
|
||||
$this->assertSame($g->sorvegliante_id, $utenza->proclamatore_id);
|
||||
}
|
||||
|
||||
public function test_l_xml_conserva_il_nome_del_gruppo_sulle_assegnazioni_dopo_lo_scioglimento(): void
|
||||
{
|
||||
['gruppo' => $gruppo, 'verdi' => $verdi, 'territori' => $territori] = $this->gruppo();
|
||||
app(GruppiServizio::class)->assegna($gruppo, $territori[0], $verdi, now());
|
||||
app(GruppiServizio::class)->sciogli($gruppo);
|
||||
|
||||
$xml = (new XmlExchange())->currentXmlBackup();
|
||||
$this->assertArrayNotHasKey('error', (new XmlExchange())->importXmlFromContent($xml));
|
||||
|
||||
$this->assertSame(0, GruppoServizio::count());
|
||||
$this->assertNull(Assegnazione::sole()->gruppo_servizio_id);
|
||||
$this->assertSame('Zisa', Assegnazione::sole()->gruppo_nome);
|
||||
// L'utenza disattivata, autrice dell'assegnazione, sopravvive al giro.
|
||||
$this->assertTrue(User::where('username', 'like', 'ex.sorvegliante.%')->sole()->isDisattivato());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user