Browse Source

flusso primo accesso

FabioFratini 7 months ago
parent
commit
a9ab518f1b

+ 222 - 0
app/Http/Controllers/FirstLoginController.php

@@ -0,0 +1,222 @@
+<?php
+
+namespace App\Http\Controllers;
+
+use Illuminate\Http\Request;
+use Illuminate\Support\Facades\Auth;
+use Illuminate\Support\Facades\Hash;
+use Illuminate\Support\Facades\DB;
+use Illuminate\Support\Facades\Log;
+use Illuminate\Support\Facades\Mail;
+use App\Http\Middleware\TenantMiddleware;
+
+class FirstLoginController extends Controller
+{
+    public function __construct()
+    {
+        $this->middleware('auth');
+        app(TenantMiddleware::class)->setupTenantConnection();
+    }
+
+    public function show()
+    {
+        $user = Auth::user();
+
+        // If already completed first login, redirect to dashboard
+        if ($user->first_login_completed) {
+            return redirect('/dashboard');
+        }
+
+        return view('first-login');
+    }
+
+    public function complete(Request $request)
+    {
+        // Validate only password
+        $request->validate([
+            'password' => 'required|min:6|confirmed',
+        ], [
+            'password.required' => 'La password è obbligatoria',
+            'password.min' => 'La password deve essere di almeno 6 caratteri',
+            'password.confirmed' => 'Le password non coincidono',
+        ]);
+
+        $currentUser = Auth::user();
+
+        Log::info('Starting first login completion', [
+            'user_id' => $currentUser->id,
+            'email' => $currentUser->email
+        ]);
+
+        try {
+            $this->updateTenantDatabase($currentUser, $request->password);
+
+            $this->updateMasterDatabaseSafely($currentUser, $request->password);
+
+            $this->sendAccountActivationEmailSafely($currentUser);
+
+            return redirect('/dashboard')->with('success', 'Password impostata con successo! Benvenuto in Leezard.cloud.');
+
+        } catch (\Exception $e) {
+            Log::error('First login completion failed', [
+                'user_id' => $currentUser->id,
+                'error' => $e->getMessage(),
+                'trace' => $e->getTraceAsString()
+            ]);
+
+            return back()
+                ->withErrors(['error' => 'Errore durante l\'impostazione della password. Riprova.']);
+        }
+    }
+
+    private function updateTenantDatabase($currentUser, $password)
+    {
+        try {
+            Log::info('Updating tenant database', ['user_id' => $currentUser->id]);
+
+            $user = \App\Models\User::findOrFail($currentUser->id);
+            $user->password = Hash::make($password);
+            $user->first_login_completed = true;
+            $user->email_verified_at = now();
+            $user->save();
+
+            Log::info('Tenant database updated successfully', ['user_id' => $currentUser->id]);
+
+        } catch (\Exception $e) {
+            Log::error('Failed to update tenant database', [
+                'user_id' => $currentUser->id,
+                'error' => $e->getMessage()
+            ]);
+            throw new \Exception('Errore durante l\'aggiornamento del database locale: ' . $e->getMessage());
+        }
+    }
+
+    private function updateMasterDatabaseSafely($currentUser, $password)
+    {
+        try {
+            Log::info('Attempting to update master database', ['user_id' => $currentUser->id]);
+
+            if (!env('DB_DATABASE')) {
+                Log::warning('No master database configured, skipping master update');
+                return;
+            }
+
+            $this->updateMasterDatabaseWithTimeout($currentUser, $password);
+
+        } catch (\Exception $e) {
+            Log::error('Master database update failed (non-critical)', [
+                'user_id' => $currentUser->id,
+                'error' => $e->getMessage()
+            ]);
+        }
+    }
+
+    private function updateMasterDatabaseWithTimeout($currentUser, $password)
+    {
+        $originalTimeout = ini_get('max_execution_time');
+        set_time_limit(10);
+        try {
+            $masterConfig = [
+                'driver' => 'mysql',
+                'host' => env('DB_HOST', '127.0.0.1'),
+                'port' => env('DB_PORT', '3306'),
+                'database' => env('DB_DATABASE'),
+                'username' => env('DB_USERNAME'),
+                'password' => env('DB_PASSWORD'),
+                'charset' => 'utf8mb4',
+                'collation' => 'utf8mb4_unicode_ci',
+                'prefix' => '',
+                'strict' => true,
+                'engine' => null,
+                'options' => [
+                    \PDO::ATTR_TIMEOUT => 5,
+                ],
+            ];
+
+            config(['database.connections.master_temp' => $masterConfig]);
+
+            $connection = DB::connection('master_temp');
+            $connection->getPdo();
+
+            Log::info('Master database connection established');
+
+            $updateData = [
+                'password' => Hash::make($password),
+                'first_login_completed' => true,
+                'email_verified_at' => now(),
+                'updated_at' => now()
+            ];
+
+            $updated = $connection->table('users')
+                ->where('email', $currentUser->email)
+                ->update($updateData);
+
+            if ($updated) {
+                Log::info('Master database updated successfully', [
+                    'email' => $currentUser->email,
+                    'rows_updated' => $updated
+                ]);
+            } else {
+                Log::warning('No rows updated in master database', [
+                    'email' => $currentUser->email
+                ]);
+            }
+
+            DB::purge('master_temp');
+
+        } catch (\Exception $e) {
+            Log::error('Master database update timeout or error', [
+                'error' => $e->getMessage(),
+                'user_email' => $currentUser->email
+            ]);
+
+            try {
+                DB::purge('master_temp');
+            } catch (\Exception $cleanupError) {
+                // Ignore cleanup errors
+            }
+
+            throw $e;
+        } finally {
+            set_time_limit($originalTimeout);
+        }
+    }
+
+    private function sendAccountActivationEmailSafely($user)
+    {
+        try {
+            Log::info('Attempting to send activation email', ['user_id' => $user->id]);
+
+            $emailData = [
+                'name' => $user->name,
+                'email' => $user->email,
+                'login_url' => url('/'),
+                'activation_time' => now()->format('d/m/Y H:i'),
+                'platform_name' => 'Leezard.cloud'
+            ];
+
+            $originalTimeout = ini_get('max_execution_time');
+            set_time_limit(15);
+
+            Mail::send('emails.account-activated', $emailData, function ($message) use ($user) {
+                $message->to($user->email, $user->name)
+                        ->subject('Il tuo account è attivo – Benvenuto in Leezard.cloud')
+                        ->from(config('mail.from.address'), config('mail.from.name'));
+            });
+
+            set_time_limit($originalTimeout);
+
+            Log::info('Activation email sent successfully', [
+                'user_id' => $user->id,
+                'email' => $user->email
+            ]);
+
+        } catch (\Exception $e) {
+            Log::error('Failed to send activation email (non-critical)', [
+                'user_id' => $user->id,
+                'email' => $user->email,
+                'error' => $e->getMessage()
+            ]);
+        }
+    }
+}

+ 1 - 0
app/Http/Kernel.php

@@ -64,5 +64,6 @@ class Kernel extends HttpKernel
         'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
         'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
         'tenant' => \App\Http\Middleware\TenantMiddleware::class,
+        'first.login.completed' => \App\Http\Middleware\CheckFirstLoginCompleted::class,
     ];
 }

+ 189 - 0
app/Http/Livewire/FirstLogin.php

@@ -0,0 +1,189 @@
+<?php
+
+namespace App\Http\Livewire;
+
+use Illuminate\Support\Facades\Auth;
+use Illuminate\Support\Facades\Hash;
+use Illuminate\Support\Facades\DB;
+use Illuminate\Support\Facades\Log;
+use Livewire\Component;
+use App\Http\Middleware\TenantMiddleware;
+use Illuminate\Support\Facades\Mail;
+
+class FirstLogin extends Component
+{
+    // Component properties
+    public $name;
+    public $cognome;
+    public $email;
+    public $telefono;
+    public $cellulare;
+    public $password;
+    public $password_confirmation;
+    public $isLoading = false; // Make sure this is defined
+
+    protected $rules = [
+        'password' => 'required|min:6|confirmed',
+        'password_confirmation' => 'required|min:6',
+    ];
+
+    protected $messages = [
+        'password.required' => 'La password è obbligatoria',
+        'password.min' => 'La password deve essere di almeno 6 caratteri',
+        'password.confirmed' => 'Le password non coincidono',
+        'password_confirmation.required' => 'Conferma la password',
+    ];
+
+    public function boot()
+    {
+        app(TenantMiddleware::class)->setupTenantConnection();
+    }
+
+    public function mount()
+    {
+        $currentUser = Auth::user();
+
+        if ($currentUser->first_login_completed) {
+            return redirect('/dashboard');
+        }
+
+        $user = \App\Models\User::findOrFail($currentUser->id);
+
+        $this->name = $user->name ?? '';
+        $this->cognome = $user->cognome ?? '';
+        $this->email = $user->email ?? '';
+        $this->telefono = $user->telefono ?? '';
+        $this->cellulare = $user->cellulare ?? '';
+    }
+
+    public function completeProfile()
+    {
+        $this->isLoading = true;
+
+        $this->validate();
+
+        $currentUser = Auth::user();
+
+        try {
+            DB::beginTransaction();
+
+            $user = \App\Models\User::findOrFail($currentUser->id);
+            $oldEmail = $user->email;
+
+            $user->password = Hash::make($this->password);
+            $user->first_login_completed = true;
+            $user->email_verified_at = now();
+            $user->save();
+
+            $this->updateMasterDatabase($currentUser, $oldEmail);
+
+            DB::commit();
+
+            $this->sendAccountActivationEmail($user);
+
+            session()->flash('success', 'Profilo completato con successo! Benvenuto in Leezard.cloud.');
+
+            $this->isLoading = false;
+
+            return redirect('/dashboard');
+
+        } catch (\Exception $e) {
+            DB::rollback();
+
+            Log::error('First login profile completion failed', [
+                'user_id' => $currentUser->id,
+                'error' => $e->getMessage(),
+                'trace' => $e->getTraceAsString()
+            ]);
+
+            $this->isLoading = false;
+            session()->flash('error', 'Errore durante il completamento del profilo: ' . $e->getMessage());
+        }
+    }
+
+    private function updateMasterDatabase($currentUser, $oldEmail)
+    {
+        try {
+            $masterConfig = [
+                'driver' => 'mysql',
+                'host' => env('DB_HOST', '127.0.0.1'),
+                'port' => env('DB_PORT', '3306'),
+                'database' => env('DB_DATABASE'),
+                'username' => env('DB_USERNAME'),
+                'password' => env('DB_PASSWORD'),
+                'charset' => 'utf8mb4',
+                'collation' => 'utf8mb4_unicode_ci',
+                'prefix' => '',
+                'strict' => true,
+                'engine' => null,
+            ];
+
+            config(['database.connections.master_temp' => $masterConfig]);
+
+            $updateData = [
+                'password' => Hash::make($this->password),
+                'first_login_completed' => true,
+                'email_verified_at' => now(),
+                'updated_at' => now()
+            ];
+
+            $updated = DB::connection('master_temp')
+                ->table('users')
+                ->where('email', $oldEmail)
+                ->update($updateData);
+
+            if ($updated) {
+                Log::info('Successfully updated user in master database during first login', [
+                    'old_email' => $oldEmail,
+                    'new_email' => $this->email
+                ]);
+            }
+
+            DB::purge('master_temp');
+        } catch (\Exception $e) {
+            Log::error('Failed to update master database during first login', [
+                'error' => $e->getMessage(),
+                'user_id' => $currentUser->id,
+                'old_email' => $oldEmail,
+                'new_email' => $this->email
+            ]);
+            throw $e;
+        }
+    }
+
+    private function sendAccountActivationEmail($user)
+    {
+        try {
+            $emailData = [
+                'name' => $user->name,
+                'email' => $user->email,
+                'login_url' => url('/'),
+                'activation_time' => now()->format('d/m/Y H:i'),
+                'platform_name' => 'Leezard.cloud'
+            ];
+
+            Mail::send('emails.account-activated', $emailData, function ($message) use ($user) {
+                $message->to($user->email, $user->name)
+                        ->subject('Il tuo account è attivo – Benvenuto in Leezard.cloud')
+                        ->from(config('mail.from.address'), config('mail.from.name'));
+            });
+
+            Log::info('Account activation email sent after first login completion', [
+                'user_id' => $user->id,
+                'email' => $user->email
+            ]);
+
+        } catch (\Exception $e) {
+            Log::error('Failed to send account activation email', [
+                'user_id' => $user->id,
+                'email' => $user->email,
+                'error' => $e->getMessage()
+            ]);
+        }
+    }
+
+    public function render()
+    {
+        return view('livewire.first-login');
+    }
+}

+ 28 - 0
app/Http/Middleware/CheckFirstLoginCompleted.php

@@ -0,0 +1,28 @@
+<?php
+
+namespace App\Http\Middleware;
+
+use Closure;
+use Illuminate\Http\Request;
+use Illuminate\Support\Facades\Auth;
+
+class CheckFirstLoginCompleted
+{
+    public function handle(Request $request, Closure $next)
+    {
+        $user = Auth::user();
+
+        if (!$user) {
+            return $next($request);
+        }
+
+        if (!$user->first_login_completed) {
+            if (!$request->routeIs(['first-login', 'logout', 'login'])) {
+                return redirect('/first-login')
+                    ->with('warning', 'Devi completare il tuo profilo prima di accedere alla piattaforma.');
+            }
+        }
+
+        return $next($request);
+    }
+}

+ 7 - 3
app/Models/User.php

@@ -25,7 +25,9 @@ class User extends Authenticatable
         'email',
         'password',
         'level',
-        'enabled'
+        'enabled',
+        'first_login_completed',
+        'first_login_at',
     ];
 
     /**
@@ -44,6 +46,8 @@ class User extends Authenticatable
      * @var array<string, string>
      */
     protected $casts = [
-        'email_verified_at' => 'datetime',
-    ];
+    'email_verified_at' => 'datetime',
+    'first_login_at' => 'datetime',
+    'first_login_completed' => 'boolean',
+    'enabled' => 'boolean',];
 }

+ 24 - 0
database/migrations/2025_06_20_122026_add_first_login_to_users_table_master.php

@@ -0,0 +1,24 @@
+<?php
+
+use App\Database\Migrations\MasterMigration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+return new class extends MasterMigration
+{
+    public function up()
+    {
+        Schema::table('users', function (Blueprint $table) {
+            $table->boolean('first_login_completed')->default(false);
+            $table->timestamp('first_login_at')->nullable()->after('first_login_completed');
+        });
+    }
+
+    public function down()
+    {
+        Schema::table('users', function (Blueprint $table) {
+            $table->dropColumn(['first_login_completed', 'first_login_at']);
+        });
+    }
+};
+

+ 23 - 0
database/migrations/2025_06_20_122038_add_first_login_to_users_table_master_tenant.php

@@ -0,0 +1,23 @@
+<?php
+
+use App\Database\Migrations\TenantMigration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+return new class extends TenantMigration
+{
+    public function up()
+    {
+        Schema::table('users', function (Blueprint $table) {
+            $table->boolean('first_login_completed')->default(false);
+            $table->timestamp('first_login_at')->nullable()->after('first_login_completed');
+        });
+    }
+
+    public function down()
+    {
+        Schema::table('users', function (Blueprint $table) {
+            $table->dropColumn(['first_login_completed', 'first_login_at']);
+        });
+    }
+};

+ 94 - 0
resources/views/emails/account-activated.blade.php

@@ -0,0 +1,94 @@
+<!DOCTYPE html>
+<html lang="it">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>Il tuo account è attivo</title>
+    <style>
+        body {
+            font-family: Arial, sans-serif;
+            line-height: 1.6;
+            color: #333;
+            max-width: 600px;
+            margin: 0 auto;
+            padding: 20px;
+        }
+        .header {
+            background-color: #28a745;
+            color: white;
+            padding: 20px;
+            text-align: center;
+            border-radius: 8px 8px 0 0;
+        }
+        .content {
+            background-color: #f8f9fa;
+            padding: 30px;
+            border-radius: 0 0 8px 8px;
+        }
+        .login-button {
+            display: inline-block;
+            background-color: #0C6197;
+            color: white;
+            padding: 12px 30px;
+            text-decoration: none;
+            border-radius: 5px;
+            margin: 20px 0;
+            font-weight: bold;
+        }
+        .brand {
+            color: #0C6197;
+            font-weight: bold;
+        }
+        .footer {
+            margin-top: 30px;
+            padding-top: 20px;
+            border-top: 1px solid #dee2e6;
+            font-size: 14px;
+            color: #6c757d;
+        }
+        .login-url {
+            background-color: white;
+            border: 2px solid #0C6197;
+            border-radius: 8px;
+            padding: 15px;
+            margin: 20px 0;
+            word-break: break-all;
+            font-family: monospace;
+            font-size: 14px;
+        }
+    </style>
+</head>
+<body>
+    <div class="header">
+        <h1>🎉 Account Attivato!</h1>
+    </div>
+
+    <div class="content">
+        <p>Ciao <strong>{{ $name }}</strong>,</p>
+
+        <p>la tua registrazione su <span class="brand">Leezard.cloud</span> è andata a buon fine e il tuo account è stato attivato con successo.</p>
+
+        <p>Ora puoi accedere alla piattaforma utilizzando le tue credenziali.</p>
+
+        <div style="text-align: center;">
+            <a href="{{ $login_url }}" class="login-button" style="color: #FFF!important">🚀 Accedi alla piattaforma</a>
+        </div>
+
+        <p>Oppure copia e incolla questo link nel tuo browser:</p>
+
+        <div class="login-url">
+            {{ $login_url }}
+        </div>
+
+        <p>Per qualsiasi dubbio o supporto, non esitare a contattarci.</p>
+
+        <p>A presto!</p>
+
+        <div class="footer">
+            <p>Il team di <span class="brand">Leezard.cloud</span></p>
+            <p>Data attivazione: {{ date('d/m/Y H:i') }} ({{ date('T') }})</p>
+            <p>Questa email è stata generata automaticamente. Per favore, non rispondere a questo indirizzo.</p>
+        </div>
+    </div>
+</body>
+</html>

+ 1 - 1
resources/views/emails/password-changed.blade.php

@@ -72,7 +72,7 @@
         <div class="footer">
             <p>Grazie,<br>
             Il team di <span class="brand">Leezard.cloud</span></p>
-            <p>Data modifica: {{ date('d/m/Y H:i') }}</p>
+            <p>Data modifica: {{ date('d/m/Y H:i') }} ({{ date('T') }})</p>
             <p>Questa email è stata generata automaticamente. Per favore, non rispondere a questo indirizzo.</p>
         </div>
     </div>

+ 36 - 61
resources/views/emails/welcome-user.blade.php

@@ -3,7 +3,7 @@
 <head>
     <meta charset="UTF-8">
     <meta name="viewport" content="width=device-width, initial-scale=1.0">
-    <title>Benvenuto - Account Creato</title>
+    <title>Benvenuto su Leezard.cloud – Attiva il tuo account</title>
     <style>
         body {
             font-family: Arial, sans-serif;
@@ -25,37 +25,36 @@
             padding: 30px;
             border-radius: 0 0 8px 8px;
         }
-        .credentials-box {
+        .activation-box {
             background-color: white;
             border: 2px solid #0C6197;
             border-radius: 8px;
             padding: 20px;
             margin: 20px 0;
+            text-align: center;
         }
-        .credential-item {
-            margin: 10px 0;
-            font-size: 16px;
-        }
-        .credential-label {
-            font-weight: bold;
-            color: #007bff;
-        }
-        .credential-value {
-            background-color: #e9ecef;
-            padding: 5px 10px;
-            border-radius: 4px;
-            font-family: monospace;
-            margin-left: 10px;
-        }
-        .login-button {
+        .activation-button {
             display: inline-block;
             background-color: #0C6197;
             color: white;
-            padding: 12px 30px;
+            padding: 15px 40px;
             text-decoration: none;
             border-radius: 5px;
             margin: 20px 0;
             font-weight: bold;
+            font-size: 16px;
+        }
+        .activation-button:hover {
+            background-color: #094c73;
+        }
+        .link-box {
+            background-color: #e9ecef;
+            padding: 15px;
+            border-radius: 4px;
+            font-family: monospace;
+            margin: 20px 0;
+            word-break: break-all;
+            font-size: 14px;
         }
         .footer {
             margin-top: 30px;
@@ -72,66 +71,42 @@
             border-radius: 5px;
             margin: 20px 0;
         }
+        .platform-name {
+            font-weight: bold;
+            color: #0C6197;
+        }
     </style>
 </head>
 <body>
     <div class="header">
-        <h1>🎉 Benvenuto in {{ $company }}!</h1>
+        <h1>🎉 Benvenuto su Leezard.cloud</h1>
     </div>
 
     <div class="content">
-        <h2>Ciao {{ $name }} {{ $cognome }},</h2>
-
-        <p>Il tuo account è stato creato con successo da <strong>{{ $created_by }}</strong>. Ora puoi accedere alla piattaforma con le credenziali fornite di seguito.</p>
+        <h2>Ciao <strong>{{ $name }}</strong>,</h2>
 
-        <div class="credentials-box">
-            <h3>🔐 Le tue credenziali di accesso:</h3>
+        <p>è stato creato per te un account su <span class="platform-name">{{ $platform_name }}</span>.</p>
 
-            <div class="credential-item">
-                <span class="credential-label">Email:</span>
-                <span class="credential-value">{{ $email }}</span>
-            </div>
-
-            <div class="credential-item">
-                <span class="credential-label">Password:</span>
-                <span class="credential-value">{{ $password }}</span>
-            </div>
-
-            <div class="credential-item">
-                <span class="credential-label">Livello Account:</span>
-                <span class="credential-value">
-                    @if($level == 0)
-                        Amministratore
-                    @elseif($level == 1)
-                        Worker
-                    @else
-                        Istruttore
-                    @endif
-                </span>
-            </div>
-        </div>
+        <p>Per completare l'attivazione, conferma il tuo indirizzo email e imposta la tua password cliccando sul pulsante qui sotto:</p>
 
-        <div class="warning">
-            <strong>⚠️ Importante:</strong> Per motivi di sicurezza, ti consigliamo di cambiare la password al primo accesso. Vai alla sezione "Profilo" dopo aver effettuato il login.
+        <div class="activation-box">
+            <h3>🔐 Attiva il tuo account</h3>
+            <a href="{{ $activation_link }}" class="activation-button" style="color: #FFF!important">🚀 Attiva il tuo account</a>
         </div>
 
-        <div style="text-align: center;">
-            <a href="{{ $login_url }}" class="login-button" style="color: #FFF!important">🚀 Accedi Ora</a>
+        <p><strong>Oppure</strong> copia e incolla questo link nel tuo browser:</p>
+        <div class="link-box">
+            {{ $activation_link }}
         </div>
 
-        <h3>📋 Cosa puoi fare ora:</h3>
-        <ul>
-            <li>Accedi alla piattaforma usando le credenziali sopra</li>
-            <li>Completa il tuo profilo nella sezione "Profilo"</li>
-            <li>Cambia la password per maggiore sicurezza</li>
-        </ul>
 
-        <p>Se hai domande o problemi nell'accesso, contatta l'amministratore del sistema.</p>
+        <p>Grazie e benvenuto!</p>
+        <p><strong>Il team di Leezard.cloud</strong></p>
 
         <div class="footer">
-            <p><strong>{{ $company }}</strong></p>
+            <p><strong>Leezard.cloud</strong></p>
             <p>Questa email è stata generata automaticamente. Per favore, non rispondere a questo indirizzo.</p>
-            <p>Data creazione account: {{ date('d/m/Y H:i') }} ({{ date('T') }})</p>
+            <p>Data invio: {{ date('d/m/Y H:i') }} ({{ date('T') }})</p>
         </div>
     </div>
 </body>

+ 231 - 0
resources/views/first-login.blade.php

@@ -0,0 +1,231 @@
+<!DOCTYPE html>
+<html lang="it">
+<head>
+    <meta charset="utf-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1">
+    <title>Primo Accesso - Leezard.cloud</title>
+
+    <!-- Bootstrap CSS -->
+    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
+    <!-- Font Awesome -->
+    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
+
+    <style>
+        body {
+            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
+            min-height: 100vh;
+            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
+        }
+
+        .first-login-container {
+            padding: 2rem 0;
+            min-height: 100vh;
+            display: flex;
+            align-items: center;
+        }
+
+        .card {
+            box-shadow: 0 15px 35px rgba(0,0,0,0.1);
+            border: none;
+            border-radius: 15px;
+            overflow: hidden;
+        }
+
+        .card-header {
+            background: linear-gradient(135deg, #0C6197 0%, #094a79 100%);
+            color: white;
+            border: none;
+            padding: 2rem;
+            text-align: center;
+        }
+
+        .card-header h3 {
+            margin: 0;
+            font-weight: 300;
+        }
+
+        .text-primary {
+            color: #0C6197 !important;
+        }
+
+        .btn-primary {
+            background-color: #0C6197;
+            border-color: #0C6197;
+            padding: 12px 30px;
+            font-weight: 600;
+        }
+
+        .btn-primary:hover {
+            background-color: #094a79;
+            border-color: #094a79;
+        }
+
+        .form-control:focus {
+            border-color: #0C6197;
+            box-shadow: 0 0 0 0.2rem rgba(12, 97, 151, 0.25);
+        }
+
+        .alert-warning {
+            background-color: rgba(255, 193, 7, 0.1);
+            border-color: #ffc107;
+            color: #856404;
+        }
+
+        .section-header {
+            border-bottom: 2px solid #f8f9fa;
+            padding-bottom: 0.5rem;
+            margin-bottom: 1.5rem;
+        }
+
+        .logout-link {
+            position: absolute;
+            top: 20px;
+            right: 20px;
+            color: white;
+            text-decoration: none;
+            background: rgba(255,255,255,0.2);
+            padding: 8px 15px;
+            border-radius: 5px;
+            transition: background 0.3s;
+        }
+
+        .logout-link:hover {
+            background: rgba(255,255,255,0.3);
+            color: white;
+            text-decoration: none;
+        }
+    </style>
+</head>
+<body>
+    <a href="/logout" class="logout-link">
+        <i class="fas fa-sign-out-alt"></i> Esci
+    </a>
+
+    <div class="first-login-container">
+        <div class="container">
+            <div class="row justify-content-center">
+                <div class="col-md-8 col-lg-6">
+
+                    <div class="card">
+                        <div class="card-header">
+                            <h3><i class="fas fa-user-cog"></i> Completa il tuo Profilo</h3>
+                            <p class="mb-0">Primo accesso - Configurazione obbligatoria</p>
+                        </div>
+
+                        <div class="card-body p-4">
+
+                            {{-- Welcome Message --}}
+                            <div class="alert alert-warning mb-4">
+                                <h6><i class="fas fa-exclamation-triangle"></i> <strong>Primo Accesso</strong></h6>
+                                <p class="mb-2">Per motivi di sicurezza, devi <strong>impostare una nuova password</strong> prima di accedere alla piattaforma.</p>
+                                <p class="mb-0">I tuoi dati sono già stati configurati dall'amministratore.</p>
+                            </div>
+
+                            {{-- Success/Error Messages --}}
+                            @if (session('success'))
+                                <div class="alert alert-success alert-dismissible fade show" role="alert">
+                                    <i class="fas fa-check-circle"></i> {{ session('success') }}
+                                    <button type="button" class="btn-close" data-bs-dismiss="alert"></button>
+                                </div>
+                            @endif
+
+                            <form method="POST" action="{{ route('first-login.complete') }}">
+                                @csrf
+
+                                <div class="section-header">
+                                    <h6 class="text-primary mb-0">
+                                        <i class="fas fa-lock"></i> Imposta la Tua Password
+                                    </h6>
+                                </div>
+
+                                <div class="alert alert-info mb-3">
+                                    <i class="fas fa-info-circle"></i>
+                                    <strong>Cambia Password:</strong> Sostituisci la password temporanea con una tua password sicura.
+                                </div>
+
+                                <div class="row mb-4">
+                                    <div class="col-md-6">
+                                        <label for="password" class="form-label">Nuova Password <span class="text-danger">*</span></label>
+                                        <input type="password"
+                                               class="form-control @error('password') is-invalid @enderror"
+                                               id="password"
+                                               name="password"
+                                               placeholder="Inserisci una password sicura"
+                                               required>
+                                        <small class="form-text text-muted">
+                                            <i class="fas fa-key"></i> Minimo 6 caratteri
+                                        </small>
+                                        @error('password')
+                                            <div class="invalid-feedback">{{ $message }}</div>
+                                        @enderror
+                                    </div>
+
+                                    <div class="col-md-6">
+                                        <label for="password_confirmation" class="form-label">Conferma Password <span class="text-danger">*</span></label>
+                                        <input type="password"
+                                               class="form-control @error('password_confirmation') is-invalid @enderror"
+                                               id="password_confirmation"
+                                               name="password_confirmation"
+                                               placeholder="Ripeti la password"
+                                               required>
+                                        @error('password_confirmation')
+                                            <div class="invalid-feedback">{{ $message }}</div>
+                                        @enderror
+                                    </div>
+                                </div>
+
+                                {{-- Action Buttons --}}
+                                <div class="d-grid gap-2 d-md-block text-center">
+                                    <button type="submit" class="btn btn-primary btn-lg">
+                                        <i class="fas fa-key"></i> Imposta Password e Accedi
+                                    </button>
+                                </div>
+
+                                <div class="text-center mt-3">
+                                    <small class="text-muted">
+                                        <i class="fas fa-shield-alt"></i>
+                                        Dopo aver impostato la password, riceverai un'email di conferma dell'attivazione.
+                                    </small>
+                                </div>
+
+                            </form>
+                        </div>
+                    </div>
+
+                </div>
+            </div>
+        </div>
+    </div>
+
+    <!-- Bootstrap JS -->
+    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
+
+    <script>
+        // Password strength indicator
+        document.getElementById('password').addEventListener('input', function() {
+            const password = this.value;
+            const strength = document.getElementById('password-strength');
+
+            if (password.length >= 8) {
+                this.classList.remove('is-invalid');
+                this.classList.add('is-valid');
+            } else {
+                this.classList.remove('is-valid');
+            }
+        });
+
+        // Password confirmation check
+        document.getElementById('password_confirmation').addEventListener('input', function() {
+            const password = document.getElementById('password').value;
+            const confirmation = this.value;
+
+            if (password === confirmation && confirmation.length >= 8) {
+                this.classList.remove('is-invalid');
+                this.classList.add('is-valid');
+            } else {
+                this.classList.remove('is-valid');
+            }
+        });
+    </script>
+</body>
+</html>

+ 39 - 20
routes/web.php

@@ -24,44 +24,63 @@ use App\Http\Controllers\PasswordResetController;
 
 Route::get('/', function () {
     return view('login');
-    // return Redirect::to('/dashboard');
 })->name('login');
 
-Route::get('/login', function () {
-    return Redirect::to('/');
-    // return Redirect::to('/dashboard');
-});
+Route::post('/login', function () {
+    $email = request('email');
+    $password = request('password');
+
+    if (Auth::attempt(['email' => $email, 'password' => $password])) {
+        $user = Auth::user();
+
+        if (!$user->first_login_completed) {
+            $user->first_login_at = now();
+            $user->save();
+
+            return redirect('/first-login');
+        }
+
+        return redirect('/dashboard');
+    } else {
+        return redirect('/?error=1');
+    }
+})->name('login.submit');
+
 Route::get('/password-reset-request', [PasswordResetController::class, 'showResetRequestForm'])->name('password.request');
 Route::post('/password-reset-request', [PasswordResetController::class, 'sendResetEmail'])->name('password.email');
 Route::get('/password-reset/{token}', [PasswordResetController::class, 'showResetForm'])->name('password.reset');
 Route::post('/password-reset', [PasswordResetController::class, 'resetPassword'])->name('password.update');
 
 
-Route::post('/login', function () {
-    $email = request('email');
-    $password = request('password');
 
-    $user = MultiTenantAuthService::authenticate($email, $password);
+Route::get('/first-login', [App\Http\Controllers\FirstLoginController::class, 'show'])
+    ->middleware('auth')
+    ->name('first-login');
 
-    if ($user) {
-        $authUser = \App\Models\User::where('email', $email)->first();
+Route::post('/first-login/complete', [App\Http\Controllers\FirstLoginController::class, 'complete'])
+    ->middleware('auth')
+    ->name('first-login.complete');
 
-        if ($authUser) {
-            Auth::login($authUser);
-            return redirect('/dashboard');
-        }
-    }
+Route::get('/profile', function () {
+    return view('profile.index');
+})->middleware(['auth', 'first.login.completed'])->name('profile');
 
-    return redirect('/?error=1');
-})->name('login');
+Route::middleware(['auth', 'first.login.completed'])->group(function () {
+    Route::get('/dashboard', function () {
+        return view('dashboard');
+    })->name('dashboard');
+
+    Route::get('/users', function () {
+        return view('users.index');
+    })->name('users');
 
+});
 
 Route::get('/logout', function () {
     session()->forget('currentClient');
-
     Auth::logout();
     return redirect('/');
-});
+})->name('logout');
 
 
 //Route::group(['middleware' => 'auth'], function () {