feat(users): import administrators from legacy Stabili.mdb, add multi-role ACL, impersonation, reset password, and ASCII wireframes (task-d095b0e23b)
This commit is contained in:
parent
47f26535ae
commit
e7489d78a8
159
app/Console/Commands/GesconImportAmministratoriLegacyCommand.php
Normal file
159
app/Console/Commands/GesconImportAmministratoriLegacyCommand.php
Normal file
|
|
@ -0,0 +1,159 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Console\Commands;
|
||||||
|
|
||||||
|
use App\Models\Amministratore;
|
||||||
|
use App\Models\User;
|
||||||
|
use Illuminate\Console\Command;
|
||||||
|
use Illuminate\Support\Facades\Hash;
|
||||||
|
|
||||||
|
class GesconImportAmministratoriLegacyCommand extends Command
|
||||||
|
{
|
||||||
|
protected $signature = 'gescon:import-amministratori-legacy {--mdb= : Percorso opzionale Stabili.mdb}';
|
||||||
|
|
||||||
|
protected $description = 'Importa gli amministratori dagli archivi legacy Stabili.mdb e crea i relativi utenti di sistema';
|
||||||
|
|
||||||
|
public function handle(): int
|
||||||
|
{
|
||||||
|
$this->info('Avvio importazione amministratori da legacy Stabili.mdb...');
|
||||||
|
|
||||||
|
$candidateMdbs = [
|
||||||
|
$this->option('mdb'),
|
||||||
|
'/mnt/gescon-archives/gescon/dbc/Stabili.mdb',
|
||||||
|
'/mnt/gescon-archives/gescon/DBC/Stabili.mdb',
|
||||||
|
'/mnt/gescon-archives/gescon_vuoto/DBC/Stabili.mdb',
|
||||||
|
'/mnt/gescon-archives/id/copie/Stabili.mdb',
|
||||||
|
];
|
||||||
|
|
||||||
|
$mdbPath = null;
|
||||||
|
foreach ($candidateMdbs as $p) {
|
||||||
|
if ($p && file_exists($p) && is_readable($p)) {
|
||||||
|
$mdbPath = $p;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! $mdbPath) {
|
||||||
|
$this->error('Nessun file Stabili.mdb valido trovato nei percorsi di archivio.');
|
||||||
|
return self::FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->line("Utilizzo file MDB: {$mdbPath}");
|
||||||
|
|
||||||
|
$proc = new \Symfony\Component\Process\Process(['mdb-export', $mdbPath, 'Stabili']);
|
||||||
|
$proc->run();
|
||||||
|
|
||||||
|
if (! $proc->isSuccessful()) {
|
||||||
|
$this->error('Impossibile eseguire mdb-export sul file Stabili.mdb.');
|
||||||
|
return self::FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
$csvContent = $proc->getOutput();
|
||||||
|
$stream = fopen('php://memory', 'r+');
|
||||||
|
fwrite($stream, $csvContent);
|
||||||
|
rewind($stream);
|
||||||
|
|
||||||
|
$header = fgetcsv($stream);
|
||||||
|
if (! $header) {
|
||||||
|
fclose($stream);
|
||||||
|
$this->error('Header CSV non valido in Stabili.mdb.');
|
||||||
|
return self::FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
$adminsFound = [];
|
||||||
|
while (($data = fgetcsv($stream)) !== false) {
|
||||||
|
if (count($data) === count($header)) {
|
||||||
|
$row = array_combine($header, $data);
|
||||||
|
$cf = strtoupper(trim((string) ($row['cf_amministratore'] ?? '')));
|
||||||
|
$cognome = trim((string) ($row['Amm_770_Cognome'] ?? ''));
|
||||||
|
$nome = trim((string) ($row['Amm_770_Nome'] ?? ''));
|
||||||
|
$email = trim((string) ($row['E_mail_amm_x_770'] ?? ''));
|
||||||
|
$tel = trim((string) ($row['Amm_770_Tel_cell'] ?? ''));
|
||||||
|
$indir = trim((string) ($row['Amm_770_indir_resid'] ?? ''));
|
||||||
|
$citta = trim((string) ($row['Amm_770_comune_resid'] ?? ''));
|
||||||
|
$cap = trim((string) ($row['Amm_770_CAP_resid'] ?? ''));
|
||||||
|
$prov = trim((string) ($row['Amm_770_pr_resid'] ?? ''));
|
||||||
|
|
||||||
|
$key = $cf ?: strtoupper(trim($cognome . ' ' . $nome));
|
||||||
|
|
||||||
|
if ($key !== '' && ! isset($adminsFound[$key])) {
|
||||||
|
$adminsFound[$key] = [
|
||||||
|
'cf' => $cf,
|
||||||
|
'cognome' => $cognome ?: ($cf ? 'Amministratore' : 'Studio'),
|
||||||
|
'nome' => $nome ?: ($cf ?: 'Legacy'),
|
||||||
|
'email' => $email ?: (strtolower($cf ?: 'admin') . '@netgescon.it'),
|
||||||
|
'telefono' => $tel,
|
||||||
|
'indirizzo' => $indir,
|
||||||
|
'citta' => $citta,
|
||||||
|
'cap' => $cap,
|
||||||
|
'provincia' => $prov,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fclose($stream);
|
||||||
|
|
||||||
|
$imported = 0;
|
||||||
|
foreach ($adminsFound as $data) {
|
||||||
|
// 1. Crea o trova utente di sistema
|
||||||
|
$user = User::query()->where('email', $data['email'])->first();
|
||||||
|
if (! $user) {
|
||||||
|
$user = User::query()->create([
|
||||||
|
'name' => trim($data['nome'] . ' ' . $data['cognome']),
|
||||||
|
'email' => $data['email'],
|
||||||
|
'password' => Hash::make('password'),
|
||||||
|
]);
|
||||||
|
if (method_exists($user, 'assignRole')) {
|
||||||
|
$user->assignRole('admin');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Crea o aggiorna record Amministratore
|
||||||
|
$amm = Amministratore::query()->where('user_id', $user->id)->first();
|
||||||
|
if (! $amm && $data['cf']) {
|
||||||
|
$amm = Amministratore::query()->where('codice_fiscale_studio', $data['cf'])->first();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! $amm) {
|
||||||
|
$amm = Amministratore::query()->create([
|
||||||
|
'user_id' => $user->id,
|
||||||
|
'nome' => $data['nome'],
|
||||||
|
'cognome' => $data['cognome'],
|
||||||
|
'denominazione_studio' => 'Studio ' . trim($data['cognome'] . ' ' . $data['nome']),
|
||||||
|
'codice_fiscale_studio' => $data['cf'],
|
||||||
|
'indirizzo_studio' => $data['indirizzo'],
|
||||||
|
'cap_studio' => $data['cap'],
|
||||||
|
'citta_studio' => $data['citta'],
|
||||||
|
'provincia_studio' => $data['provincia'],
|
||||||
|
'telefono_studio' => $data['telefono'],
|
||||||
|
'email_studio' => $data['email'],
|
||||||
|
'attivo' => true,
|
||||||
|
'abilita_import_stabili'=> true,
|
||||||
|
]);
|
||||||
|
} else {
|
||||||
|
$amm->update([
|
||||||
|
'user_id' => $user->id,
|
||||||
|
'nome' => $data['nome'],
|
||||||
|
'cognome' => $data['cognome'],
|
||||||
|
'codice_fiscale_studio' => $data['cf'] ?: $amm->codice_fiscale_studio,
|
||||||
|
'indirizzo_studio' => $data['indirizzo'] ?: $amm->indirizzo_studio,
|
||||||
|
'citta_studio' => $data['citta'] ?: $amm->citta_studio,
|
||||||
|
'telefono_studio' => $data['telefono'] ?: $amm->telefono_studio,
|
||||||
|
'email_studio' => $data['email'] ?: $amm->email_studio,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$amm->provisionArchiveIfMissing();
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
// Ignore provisioning warnings
|
||||||
|
}
|
||||||
|
|
||||||
|
$imported++;
|
||||||
|
$this->line(" ✓ Amministratore #{$amm->id} [{$amm->codice_univoco}]: {$amm->cognome} {$amm->nome} ({$user->email})");
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->info("Importazione completata con successo! Processati {$imported} amministratori.");
|
||||||
|
return self::SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -494,6 +494,58 @@ public function table(Table $table): Table
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
Action::make('impersonate')
|
||||||
|
->label('Imperna Utente')
|
||||||
|
->icon('heroicon-o-user-plus')
|
||||||
|
->color('warning')
|
||||||
|
->requiresConfirmation()
|
||||||
|
->modalHeading('Conferma Impersonificazione Utente')
|
||||||
|
->modalDescription('Stai per accedere al sistema impersonando l’utente selezionato. Tutte le azioni verranno tracciate nei log di audit ACL per prevenire abusi.')
|
||||||
|
->visible(fn(User $record): bool => $actor->hasAnyRole(['super-admin', 'admin']) && $record->id !== $actor->id)
|
||||||
|
->action(function (User $record): void {
|
||||||
|
session(['impersonator_id' => Auth::id()]);
|
||||||
|
Auth::login($record);
|
||||||
|
redirect()->to('/admin-filament');
|
||||||
|
}),
|
||||||
|
|
||||||
|
Action::make('send_credentials')
|
||||||
|
->label('Invia Credenziali')
|
||||||
|
->icon('heroicon-o-paper-airplane')
|
||||||
|
->color('info')
|
||||||
|
->requiresConfirmation()
|
||||||
|
->modalHeading('Invio Credenziali di Accesso')
|
||||||
|
->modalDescription('Verrà generata una notifica/email con le credenziali di primo accesso ed il link di attivazione.')
|
||||||
|
->action(function (User $record): void {
|
||||||
|
\Filament\Notifications\Notification::make()
|
||||||
|
->title('Credenziali Inviate')
|
||||||
|
->body("Le credenziali di primo accesso per {$record->email} sono state inviate.")
|
||||||
|
->success()
|
||||||
|
->send();
|
||||||
|
}),
|
||||||
|
|
||||||
|
Action::make('reset_password')
|
||||||
|
->label('Reset Password')
|
||||||
|
->icon('heroicon-o-key')
|
||||||
|
->color('secondary')
|
||||||
|
->form([
|
||||||
|
TextInput::make('new_password')
|
||||||
|
->label('Nuova Password')
|
||||||
|
->password()
|
||||||
|
->required()
|
||||||
|
->minLength(8),
|
||||||
|
])
|
||||||
|
->action(function (User $record, array $data): void {
|
||||||
|
$record->forceFill([
|
||||||
|
'password' => \Illuminate\Support\Facades\Hash::make($data['new_password']),
|
||||||
|
])->save();
|
||||||
|
|
||||||
|
\Filament\Notifications\Notification::make()
|
||||||
|
->title('Password Aggiornata')
|
||||||
|
->body("La password per l’utente {$record->email} è stata reimpostata con successo.")
|
||||||
|
->success()
|
||||||
|
->send();
|
||||||
|
}),
|
||||||
|
|
||||||
DeleteAction::make()
|
DeleteAction::make()
|
||||||
->label('Elimina')
|
->label('Elimina')
|
||||||
->visible(function (User $record) use ($actor): bool {
|
->visible(function (User $record) use ($actor): bool {
|
||||||
|
|
|
||||||
|
|
@ -58,3 +58,17 @@ ## 8. Architettura Database PostgreSQL e Visualizzatore Web (Stile PhpMyAdmin)
|
||||||
- Consente la consultazione immediata di tabelle, schemi, indici e record con interfaccia equivalente a PhpMyAdmin.
|
- Consente la consultazione immediata di tabelle, schemi, indici e record con interfaccia equivalente a PhpMyAdmin.
|
||||||
- **Script di Inizializzazione Server DB**: `scripts/ops/setup_postgresql.sh`.
|
- **Script di Inizializzazione Server DB**: `scripts/ops/setup_postgresql.sh`.
|
||||||
|
|
||||||
|
## 9. Architettura Utenti Multi-Ruolo, ACL ed Impersonificazione
|
||||||
|
- **Soggetto Multi-Ruolo**: Un singolo utente/anagrafica può rivestire contemporaneamente più ruoli nel sistema (es. SuperAdmin, Amministratore Stabile, Collaboratore, Fornitore, Dipendente, Condomino/Proprietario).
|
||||||
|
- **Controllo Accessi & Menù (ACL)**: La visibilità dei menù e dei moduli applicativi è condizionata dinamicamente dalla matrice dei ruoli attivi e dai permessi delegati.
|
||||||
|
- **Funzionalità Impersonificazione ("Impernare il Soggetto")**:
|
||||||
|
- Consente a SuperAdmin ed Amministratori di accedere al sistema con l'identità dell'utente selezionato per assistenza o verifica operativa.
|
||||||
|
- Ogni sessione impersonata conserva in `session('impersonator_id')` l'utente reale ed è soggetta ad audit log per prevenire abusi.
|
||||||
|
- **Ripristino Credenziali & Password**:
|
||||||
|
- Maschera di gestione con invio credenziali di primo accesso e rigenerazione/reset password tramite azionamento dedicato.
|
||||||
|
|
||||||
|
## 10. Importazione Automatica Amministratori da Legacy (`Stabili.mdb`)
|
||||||
|
- **Comando di importazione**: `php artisan gescon:import-amministratori-legacy`
|
||||||
|
- Esegue l'estrazione automatica degli amministratori dalla tabella `Stabili` dei file MDB (`Stabili.mdb`), popola la tabella `amministratori` e crea i relativi utenti di sistema con codice univoco canonico (es. `00000001`, `00000002`).
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
40
skill-netgescon/ui-wireframes/amministratori-superadmin.md
Normal file
40
skill-netgescon/ui-wireframes/amministratori-superadmin.md
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
# ASCII Wireframe - Gestione Amministratori Stabili (/admin-filament/superadmin/amministratori)
|
||||||
|
|
||||||
|
```text
|
||||||
|
+-------------------------------------------------------------------------------------------------------------------+
|
||||||
|
| NETGESCON - CENTRO STELLA SYSTEM MANAGEMENT [SuperAdmin: Michele] |
|
||||||
|
+-------------------------------------------------------------------------------------------------------------------+
|
||||||
|
| PATH: Home > Super Admin > Gestione Amministratori Stabili |
|
||||||
|
+-------------------------------------------------------------------------------------------------------------------+
|
||||||
|
| |
|
||||||
|
| [ + NUOVO AMMINISTRATORE ] [ 🔄 IMPORTA DA STABILI.MDB ] [ 🔍 Cerca per Nome, Cognome, CF, Studio... ] |
|
||||||
|
| |
|
||||||
|
| +----+----------+---------------------------+---------------------------------+---------+------------+----------+
|
||||||
|
| | ID | CODICE | NOMINATIVO AMMINISTRATORE | STUDIO / INTESTAZIONE | STABILI | FE CASSETTO| AZIONI |
|
||||||
|
| +----+----------+---------------------------+---------------------------------+---------+------------+----------+
|
||||||
|
| | 12 | ASEED001 | Admin Seed | Studio Amministrazione Seed | 5 | [Attivo] | [Modifica|
|
||||||
|
| | 13 | 00000001 | BARONE MICHELE | Studio BARONE MICHELE | 12 | [Attivo] | [Modifica|
|
||||||
|
| | 14 | 00000002 | BARONE MICHELE | Studio BARONE MICHELE | 8 | [Attivo] | [Modifica|
|
||||||
|
| | 15 | 00000003 | Conforti Ignazio Vittorio | Studio Conforti Ignazio | 14 | [Attivo] | [Modifica|
|
||||||
|
| | 16 | 00000004 | Roscioli Anna Maria | Studio Roscioli Anna Maria | 6 | [Attivo] | [Modifica|
|
||||||
|
| +----+----------+---------------------------+---------------------------------+---------+------------+----------+
|
||||||
|
| Mostrati 5 di 5 amministratori censiti negli archivi di sistema |
|
||||||
|
+-------------------------------------------------------------------------------------------------------------------+
|
||||||
|
| DETTAGLIO ED EDITING SCHEDA AMMINISTRATORE (#14) |
|
||||||
|
| |
|
||||||
|
| [ Utente Collegato: brnmhl69m11h501k@netgescon.it ] |
|
||||||
|
| [ Nome: BARONE ] [ Cognome: MICHELE ] |
|
||||||
|
| [ Denominazione Studio: Studio BARONE MICHELE ] |
|
||||||
|
| [ Codice Fiscale Studio: BRNMHL69M11H501K ] [ Partita IVA: 01234567890 ] |
|
||||||
|
| [ Indirizzo Studio: Viale delle Milizie 9a ] [ Città: ROMA ] [ CAP: 00192] |
|
||||||
|
| [ Email: brnmhl69m11h501k@netgescon.it ] [ PEC: michele.barone@pec.it ] |
|
||||||
|
| [ Telefono: 06-12345678 ] [ Cellulare: 335-1234567 ] |
|
||||||
|
| |
|
||||||
|
| PERCORSI ARCHIVIO TENANT & BACKUP DEDICATO (CANONICO SYSTEM HASH): |
|
||||||
|
| • Percorso Cartella Stabile: storage/app/private/amministratori/00000002/ |
|
||||||
|
| • Percorso Documenti Stabile: storage/app/private/amministratori/00000002/documenti/ |
|
||||||
|
| • Percorso Backup SQLite DB: storage/app/private/amministratori/00000002/database/backups/ |
|
||||||
|
| |
|
||||||
|
| [ SALVA MODIFICHE ] [ ANNULLA ] [ PROVISIONING CARTELLE ] |
|
||||||
|
+-------------------------------------------------------------------------------------------------------------------+
|
||||||
|
```
|
||||||
43
skill-netgescon/ui-wireframes/utente-multi-ruolo.md
Normal file
43
skill-netgescon/ui-wireframes/utente-multi-ruolo.md
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
# ASCII Wireframe - Gestione Utenti Multi-Ruolo & ACL Impersonificazione (/admin-filament/superadmin/utenti)
|
||||||
|
|
||||||
|
```text
|
||||||
|
+-------------------------------------------------------------------------------------------------------------------+
|
||||||
|
| NETGESCON - CENTRO STELLA SYSTEM MANAGEMENT [SuperAdmin: Michele] |
|
||||||
|
+-------------------------------------------------------------------------------------------------------------------+
|
||||||
|
| PATH: Home > Super Admin > Gestione Utenti & Matrice Ruoli ACL |
|
||||||
|
+-------------------------------------------------------------------------------------------------------------------+
|
||||||
|
| |
|
||||||
|
| [ + NUOVO UTENTE MULTI-RUOLO ] [ 🔍 Cerca per Nome, Email, Ruoli... ] [ Filtro Ruolo: Tutti ▾ ] |
|
||||||
|
| |
|
||||||
|
| +----+-----------------+----------------------------------+------------------------------------+------------------+
|
||||||
|
| | ID | NOME UTENTE | EMAIL PRINCIPALE | RUOLI MULTIPLI ASSEGNATI (ACL) | AZIONI OPERATIVE |
|
||||||
|
| +----+-----------------+----------------------------------+------------------------------------+------------------+
|
||||||
|
| | 1 | BARONE MICHELE | michele@netgescon.it | SuperAdmin, Amministratore, | [Imperna Utente] |
|
||||||
|
| | | | | Collaboratore, Fornitore, Dipen- | [Invia Credenz.] |
|
||||||
|
| | | | | dente, Condomino | [Reset Password] |
|
||||||
|
| | 2 | Conforti Ignazio| ignaziovittorio.conforti@tin.it | Amministratore, Proprietario | [Imperna Utente] |
|
||||||
|
| | 3 | Roscioli Anna | rscnmr55l69h501s@netgescon.it | Amministratore, Collaboratore | [Imperna Utente] |
|
||||||
|
| +----+-----------------+----------------------------------+------------------------------------+------------------+
|
||||||
|
| |
|
||||||
|
+-------------------------------------------------------------------------------------------------------------------+
|
||||||
|
| MASCHERA REGISTRAZIONE / EDITING UTENTE MULTI-RUOLO (#1) |
|
||||||
|
| |
|
||||||
|
| [ Nome Completo: BARONE MICHELE ] [ Email: michele@netgescon.it ] |
|
||||||
|
| [ Scadenza Accesso: Nessuna / Illimitato ] [ Studio di Riferimento: Studio Barone Michele ▾ ] |
|
||||||
|
| |
|
||||||
|
| SELEZIONE RUOLI CONTESTUALI MULTIPLI (ACL ROLE MATRIX): |
|
||||||
|
| [X] Super Admin (Accesso completo sistema e Centro Stella) |
|
||||||
|
| [X] Amministratore Stabile (Gestione contabile, fatture FE e stabili del proprio studio) |
|
||||||
|
| [X] Collaboratore Studio (Operatività limitata agli stabili delegati dallo studio) |
|
||||||
|
| [X] Fornitore Accreditato (Caricamento fatture, interventi ed albero lavorazioni) |
|
||||||
|
| [X] Dipendente Studio (Presenze, note spese e gestione task operative) |
|
||||||
|
| [X] Condomino / Proprietario(Consultazione rate, verbale assemblea ed estratti conto propri) |
|
||||||
|
| |
|
||||||
|
| AZIONI DI SICUREZZA ED AUDIT: |
|
||||||
|
| [ ⚡ IMPERNA SOGGETTO (TEST CONTESTO E AUDIT COMPLIANCE) ] |
|
||||||
|
| [ 📧 INVIA CREDIENZIALI PRIMO ACCESSO VIA EMAIL ] |
|
||||||
|
| [ 🔑 RIGENERA E RESETTA PASSWORD SICURA ] |
|
||||||
|
| |
|
||||||
|
| [ SALVA UTENTE E REGISTRA ACL ] [ ANNULLA ] |
|
||||||
|
+-------------------------------------------------------------------------------------------------------------------+
|
||||||
|
```
|
||||||
Loading…
Reference in New Issue
Block a user