'datetime', 'password' => 'hashed', 'password_change_required' => 'boolean', 'proclamatore_id' => 'integer', ]; } /** Il proclamatore di cui è l'utenza (sorvegliante di gruppo). */ public function proclamatore() { return $this->belongsTo(Proclamatore::class, 'proclamatore_id')->withTrashed(); } /** * Sorvegliante di gruppo: vede solo il proprio gruppo e il proprio * profilo (middleware LimitaSorvegliante). */ public function isSorvegliante(): bool { return $this->hasRole('sorvegliante'); } /** Il gruppo di cui è sorvegliante (sciolto il gruppo, l'utenza non esiste più). */ public function gruppoSorvegliato(): ?GruppoServizio { return $this->proclamatore_id ? GruppoServizio::where('sorvegliante_id', $this->proclamatore_id)->first() : null; } /** * Elimina l'utenza senza perdere lo storico: le assegnazioni che ha fatto * o fatto rientrare passano a $subentra (la colonna non può restare * vuota), e nel registro delle attività le sue voci si tengono, con * scritto chi era ($nome, $email) al posto del collegamento all'utenza. */ public function eliminaConservandoStorico(self $subentra, string $nome, ?string $email): void { DB::transaction(function () use ($subentra, $nome, $email) { $eliminatoIl = now()->toDateTimeString(); Activity::query() ->where('causer_type', self::class) ->where('causer_id', $this->id) ->chunkById(200, function ($attivita) use ($nome, $email, $eliminatoIl) { foreach ($attivita as $voce) { $proprieta = $voce->properties?->toArray() ?? []; $proprieta['causer_name'] = $nome; $proprieta['causer_email'] = $email; $proprieta['causer_deleted_at'] = $eliminatoIl; $voce->properties = $proprieta; $voce->save(); } }); Assegnazione::query()->where('created_by', $this->id)->update(['created_by' => $subentra->id]); Assegnazione::query()->where('returned_by', $this->id)->update(['returned_by' => $subentra->id]); $this->syncRoles([]); $this->delete(); }); } /** * Il sorvegliante non conferma l'email (scelta dell'utente, 19 ottobre * 2026): l'utenza la crea l'amministratore con una password temporanea. * Per tutti gli altri resta obbligatoria. */ public function hasVerifiedEmail(): bool { return ! is_null($this->email_verified_at) || $this->isSorvegliante(); } public function getActivitylogOptions(): LogOptions { return LogOptions::defaults() ->logOnly(['name', 'email']) ->logOnlyDirty() ->dontSubmitEmptyLogs(); } /** * L'utenza di un sorvegliante porta nome (ed email, spesso) di un * proclamatore: nel registro delle attività i proclamatori compaiono solo * con l'identificativo, quindi anche qui. */ public function tapActivity(\Spatie\Activitylog\Contracts\Activity $activity, string $eventName): void { $proclamatoreId = $this->proclamatore_id ?? $this->getOriginal('proclamatore_id'); if (! $proclamatoreId) { return; } $activity->properties = collect($activity->properties)->map(function ($valori) use ($proclamatoreId) { if (! is_array($valori)) { return $valori; } foreach (['name', 'email'] as $campo) { if (array_key_exists($campo, $valori)) { $valori[$campo] = "proclamatore #{$proclamatoreId}"; } } return $valori; }); } protected static function booted(): void { // Un indirizzo nuovo va confermato di nuovo, chiunque lo cambi. static::updating(function (self $utente) { if ($utente->isDirty('email') && ! $utente->isDirty('email_verified_at')) { $utente->email_verified_at = null; } }); } /** * 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 * l'email si può richiedere di nuovo. */ public function inviaConfermaEmail(): bool { if ($this->isSorvegliante()) { return true; } try { $this->sendEmailVerificationNotification(); } catch (\Throwable $e) { report($e); return false; } return true; } }