glastree_on_gitea
This commit is contained in:
@@ -0,0 +1,83 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
|
||||
class ActivityLog extends Model
|
||||
{
|
||||
public $timestamps = false;
|
||||
|
||||
protected $fillable = [
|
||||
'user_id',
|
||||
'action',
|
||||
'module',
|
||||
'description',
|
||||
'details',
|
||||
'ip_address',
|
||||
'created_at',
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
'details' => 'array',
|
||||
'created_at' => 'datetime',
|
||||
];
|
||||
|
||||
public function user(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(User::class);
|
||||
}
|
||||
|
||||
public static function log(
|
||||
string $action,
|
||||
string $module,
|
||||
?string $description = null,
|
||||
?array $details = null
|
||||
): self {
|
||||
return static::create([
|
||||
'user_id' => auth()->id(),
|
||||
'action' => $action,
|
||||
'module' => $module,
|
||||
'description' => $description,
|
||||
'details' => $details,
|
||||
'ip_address' => request()->ip(),
|
||||
'created_at' => now(),
|
||||
]);
|
||||
}
|
||||
|
||||
public static function logCreate(Model $model, ?string $description = null): self
|
||||
{
|
||||
return static::log(
|
||||
'create',
|
||||
$model::class,
|
||||
$description ?? 'Creato ' . class_basename($model),
|
||||
['new' => $model->toArray()]
|
||||
);
|
||||
}
|
||||
|
||||
public static function logUpdate(Model $model, array $old, ?string $description = null): self
|
||||
{
|
||||
return static::log(
|
||||
'update',
|
||||
$model::class,
|
||||
$description ?? 'Modificato ' . class_basename($model),
|
||||
['old' => $old, 'new' => $model->toArray()]
|
||||
);
|
||||
}
|
||||
|
||||
public static function logDelete(Model $model, ?string $description = null): self
|
||||
{
|
||||
return static::log(
|
||||
'delete',
|
||||
$model::class,
|
||||
$description ?? 'Eliminato ' . class_basename($model),
|
||||
['deleted' => $model->toArray()]
|
||||
);
|
||||
}
|
||||
|
||||
public static function logLogin(): self
|
||||
{
|
||||
return static::log('login', 'auth', 'Login effettuato');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class AppSetting extends Model
|
||||
{
|
||||
protected $table = 'app_settings';
|
||||
|
||||
protected $fillable = [
|
||||
'logo',
|
||||
'logo_small',
|
||||
'logo_path',
|
||||
'logo_small_path',
|
||||
'nome_applicazione',
|
||||
'nome_organizzazione',
|
||||
'footer_text',
|
||||
'app_version',
|
||||
'dashboard_welcome',
|
||||
'show_version',
|
||||
];
|
||||
|
||||
public static function getSetting(string $key, $default = null)
|
||||
{
|
||||
$setting = self::first();
|
||||
return $setting?->{$key} ?? $default;
|
||||
}
|
||||
|
||||
public static function getLogo(): ?string
|
||||
{
|
||||
return self::getSetting('logo');
|
||||
}
|
||||
|
||||
public static function getLogoSmall(): ?string
|
||||
{
|
||||
return self::getSetting('logo_small');
|
||||
}
|
||||
|
||||
public static function getAppName(): string
|
||||
{
|
||||
return self::getSetting('nome_applicazione', 'Glastree');
|
||||
}
|
||||
|
||||
public static function getOrgName(): string
|
||||
{
|
||||
return self::getSetting('nome_organizzazione', 'Parrocchia');
|
||||
}
|
||||
|
||||
public static function getFooterText(): string
|
||||
{
|
||||
$footer = self::getSetting('footer_text');
|
||||
if ($footer) {
|
||||
return $footer;
|
||||
}
|
||||
$appName = self::getAppName();
|
||||
$year = date('Y');
|
||||
return "© {$year} {$appName}";
|
||||
}
|
||||
|
||||
public static function getAppVersion(): ?string
|
||||
{
|
||||
return self::getSetting('app_version');
|
||||
}
|
||||
|
||||
public static function getDashboardWelcome(): ?string
|
||||
{
|
||||
return self::getSetting('dashboard_welcome');
|
||||
}
|
||||
|
||||
public static function shouldShowVersion(): bool
|
||||
{
|
||||
return (bool) self::getSetting('show_version', false);
|
||||
}
|
||||
|
||||
public function getLogoUrlInstance(): ?string
|
||||
{
|
||||
if ($this->logo && file_exists(public_path('storage/' . $this->logo))) {
|
||||
return asset('storage/' . $this->logo);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public function getLogoSmallUrlInstance(): ?string
|
||||
{
|
||||
if ($this->logo_small && file_exists(public_path('storage/' . $this->logo_small))) {
|
||||
return asset('storage/' . $this->logo_small);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public function getLogoPath(): ?string
|
||||
{
|
||||
if ($this->logo_path && file_exists(public_path('storage/' . $this->logo_path))) {
|
||||
return asset('storage/' . $this->logo_path);
|
||||
}
|
||||
if ($this->logo && file_exists(public_path('storage/' . $this->logo))) {
|
||||
return asset('storage/' . $this->logo);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public function getLogoSmallPath(): ?string
|
||||
{
|
||||
if ($this->logo_small_path && file_exists(public_path('storage/' . $this->logo_small_path))) {
|
||||
return asset('storage/' . $this->logo_small_path);
|
||||
}
|
||||
if ($this->logo_small && file_exists(public_path('storage/' . $this->logo_small))) {
|
||||
return asset('storage/' . $this->logo_small);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static function getLogoUrl(): ?string
|
||||
{
|
||||
$setting = self::first();
|
||||
return $setting?->getLogoPath();
|
||||
}
|
||||
|
||||
public static function getLogoSmallUrl(): ?string
|
||||
{
|
||||
$setting = self::first();
|
||||
return $setting?->getLogoSmallPath();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class Comune extends Model
|
||||
{
|
||||
protected $table = 'comuni';
|
||||
protected $fillable = ['nome', 'codice_istat', 'cap', 'sigla_provincia', 'regione', 'latitudine', 'longitudine'];
|
||||
|
||||
public static function search(string $query)
|
||||
{
|
||||
return static::where('nome', 'like', "%{$query}%")
|
||||
->orderBy('nome')
|
||||
->limit(20)
|
||||
->get();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
|
||||
class Contatto extends Model
|
||||
{
|
||||
protected $table = 'contatti';
|
||||
protected $fillable = ['individuo_id', 'tipo', 'valore', 'etichetta', 'is_primary'];
|
||||
|
||||
protected $casts = [
|
||||
'is_primary' => 'boolean',
|
||||
];
|
||||
|
||||
public function individuo(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Individuo::class);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
|
||||
class Diocesi extends Model
|
||||
{
|
||||
protected $table = 'diocesi';
|
||||
protected $fillable = ['nome', 'regione'];
|
||||
|
||||
public function gruppi(): HasMany
|
||||
{
|
||||
return $this->hasMany(Gruppo::class);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\MorphTo;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
|
||||
class Documento extends Model
|
||||
{
|
||||
protected $table = 'documenti';
|
||||
protected $fillable = [
|
||||
'tenant_id', 'user_id', 'nome_file', 'file_path', 'tipo', 'tipologia',
|
||||
'visibilita', 'visibilita_target_id', 'visibilita_target_type',
|
||||
'mime_type', 'dimensione', 'note'
|
||||
];
|
||||
|
||||
public function tenant(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Tenant::class);
|
||||
}
|
||||
|
||||
public function user(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(User::class);
|
||||
}
|
||||
|
||||
public function target(): MorphTo
|
||||
{
|
||||
return $this->morphTo('target', 'visibilita_target_type', 'visibilita_target_id');
|
||||
}
|
||||
|
||||
public function eventi(): BelongsToMany
|
||||
{
|
||||
return $this->belongsToMany(Evento::class, 'eventi_documenti')->withTimestamps();
|
||||
}
|
||||
|
||||
public function gruppi(): BelongsToMany
|
||||
{
|
||||
return $this->belongsToMany(Gruppo::class, 'gruppi_documenti')->withTimestamps();
|
||||
}
|
||||
|
||||
public function individui(): BelongsToMany
|
||||
{
|
||||
return $this->belongsToMany(Individuo::class, 'individui_documenti')->withTimestamps();
|
||||
}
|
||||
|
||||
public function isVisibilePerIndividuo(Individuo $individuo): bool
|
||||
{
|
||||
if ($this->visibilita === 'pubblico') return true;
|
||||
|
||||
if ($this->visibilita === 'individuo' && $this->visibilita_target_id === $individuo->id) return true;
|
||||
|
||||
if ($this->visibilita === 'gruppo' && $this->visibilita_target_type === Gruppo::class) {
|
||||
return $individuo->gruppi()->where('gruppi.id', $this->visibilita_target_id)->exists();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
|
||||
class EmailAttachment extends Model
|
||||
{
|
||||
protected $table = 'email_attachments';
|
||||
|
||||
protected $fillable = [
|
||||
'email_message_id', 'filename', 'mime_type', 'size', 'file_path',
|
||||
'is_saved_to_documenti', 'documenti_id'
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
'is_saved_to_documenti' => 'boolean',
|
||||
];
|
||||
|
||||
public function message(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(EmailMessage::class, 'email_message_id');
|
||||
}
|
||||
|
||||
public function documento(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Documento::class, 'documenti_id');
|
||||
}
|
||||
|
||||
public function getUrlAttribute(): string
|
||||
{
|
||||
return route('email.attachment.download', $this->id);
|
||||
}
|
||||
|
||||
public function saveToDocumenti(): ?Documento
|
||||
{
|
||||
if ($this->is_saved_to_documenti || !$this->documenti_id) {
|
||||
return $this->documento;
|
||||
}
|
||||
|
||||
$documento = Documento::create([
|
||||
'nome_file' => $this->filename,
|
||||
'file_path' => $this->file_path,
|
||||
'tipo' => 'upload',
|
||||
'tipologia' => 'email_attachment',
|
||||
'mime_type' => $this->mime_type,
|
||||
'dimensione' => $this->size,
|
||||
'note' => 'Allegato email: ' . ($this->message->subject ?? ''),
|
||||
]);
|
||||
|
||||
$this->update(['is_saved_to_documenti' => true, 'documenti_id' => $documento->id]);
|
||||
|
||||
return $documento;
|
||||
}
|
||||
|
||||
public function getIconAttribute(): string
|
||||
{
|
||||
if (str_starts_with($this->mime_type, 'image/')) {
|
||||
return 'fa-image';
|
||||
}
|
||||
if (str_starts_with($this->mime_type, 'video/')) {
|
||||
return 'fa-video';
|
||||
}
|
||||
if (str_starts_with($this->mime_type, 'audio/')) {
|
||||
return 'fa-music';
|
||||
}
|
||||
if (str_contains($this->mime_type, 'pdf')) {
|
||||
return 'fa-file-pdf';
|
||||
}
|
||||
if (str_contains($this->mime_type, 'word')) {
|
||||
return 'fa-file-word';
|
||||
}
|
||||
if (str_contains($this->mime_type, 'excel') || str_contains($this->mime_type, 'spreadsheet')) {
|
||||
return 'fa-file-excel';
|
||||
}
|
||||
return 'fa-file';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
|
||||
class EmailFolder extends Model
|
||||
{
|
||||
protected $table = 'email_folders';
|
||||
|
||||
protected $fillable = ['name', 'imap_folder_name', 'type', 'icon', 'color', 'sort_order', 'is_system'];
|
||||
|
||||
protected $casts = [
|
||||
'is_system' => 'boolean',
|
||||
];
|
||||
|
||||
public function messages(): HasMany
|
||||
{
|
||||
return $this->hasMany(EmailMessage::class, 'email_folder_id')->orderBy('received_at', 'desc');
|
||||
}
|
||||
|
||||
public function unreadCount(): int
|
||||
{
|
||||
return $this->messages()->where('is_read', false)->count();
|
||||
}
|
||||
|
||||
public static function getSystemFolders(): array
|
||||
{
|
||||
return [
|
||||
['name' => 'Inbox', 'imap_folder_name' => 'INBOX', 'type' => 'inbox', 'icon' => 'fa-inbox', 'color' => 'primary', 'sort_order' => 0, 'is_system' => true],
|
||||
['name' => 'Invio', 'imap_folder_name' => 'Sent', 'type' => 'sent', 'icon' => 'fa-paper-plane', 'color' => 'success', 'sort_order' => 1, 'is_system' => true],
|
||||
['name' => 'Bozze', 'imap_folder_name' => 'Drafts', 'type' => 'drafts', 'icon' => 'fa-edit', 'color' => 'warning', 'sort_order' => 2, 'is_system' => true],
|
||||
['name' => 'Cestino', 'imap_folder_name' => 'Trash', 'type' => 'trash', 'icon' => 'fa-trash', 'color' => 'danger', 'sort_order' => 3, 'is_system' => true],
|
||||
['name' => 'Archivio', 'imap_folder_name' => 'Archive', 'type' => 'archive', 'icon' => 'fa-archive', 'color' => 'secondary', 'sort_order' => 4, 'is_system' => true],
|
||||
['name' => 'Importanti', 'imap_folder_name' => 'Starred', 'type' => 'starred', 'icon' => 'fa-star', 'color' => 'warning', 'sort_order' => 5, 'is_system' => true],
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
|
||||
class EmailMessage extends Model
|
||||
{
|
||||
protected $table = 'email_messages';
|
||||
|
||||
protected $fillable = [
|
||||
'email_folder_id', 'message_id', 'subject', 'from_name', 'from_email',
|
||||
'to_name', 'to_email', 'cc', 'bcc', 'body_text', 'body_html',
|
||||
'is_read', 'is_starred', 'is_important', 'is_sent', 'is_draft', 'is_trash',
|
||||
'received_at', 'sent_at', 'imap_uid'
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
'is_read' => 'boolean',
|
||||
'is_starred' => 'boolean',
|
||||
'is_important' => 'boolean',
|
||||
'is_sent' => 'boolean',
|
||||
'is_draft' => 'boolean',
|
||||
'is_trash' => 'boolean',
|
||||
'received_at' => 'datetime',
|
||||
'sent_at' => 'datetime',
|
||||
];
|
||||
|
||||
public function folder(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(EmailFolder::class, 'email_folder_id');
|
||||
}
|
||||
|
||||
public function attachments(): HasMany
|
||||
{
|
||||
return $this->hasMany(EmailAttachment::class, 'email_message_id');
|
||||
}
|
||||
|
||||
public function getExcerptAttribute(): string
|
||||
{
|
||||
$body = strip_tags($this->body_text ?? $this->body_html ?? '');
|
||||
return mb_strimwidth($body, 0, 100, '...');
|
||||
}
|
||||
|
||||
public function getBodyForDisplayAttribute(): string
|
||||
{
|
||||
if ($this->body_html) {
|
||||
return $this->body_html;
|
||||
}
|
||||
return nl2br(e($this->body_text ?? ''));
|
||||
}
|
||||
|
||||
public function scopeUnread($query)
|
||||
{
|
||||
return $query->where('is_read', false);
|
||||
}
|
||||
|
||||
public function scopeInbox($query)
|
||||
{
|
||||
return $query->whereHas('folder', fn($q) => $q->where('type', 'inbox'));
|
||||
}
|
||||
|
||||
public function scopeSent($query)
|
||||
{
|
||||
return $query->where('is_sent', true);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Illuminate\Support\Facades\Crypt;
|
||||
|
||||
class EmailSetting extends Model
|
||||
{
|
||||
protected $table = 'email_settings';
|
||||
|
||||
protected $fillable = [
|
||||
'imap_host', 'imap_port', 'imap_encryption', 'imap_username', 'imap_password',
|
||||
'smtp_host', 'smtp_port', 'smtp_encryption', 'smtp_username', 'smtp_password',
|
||||
'email_address', 'email_name', 'reply_to', 'sync_interval_minutes',
|
||||
'last_sync_at', 'is_active', 'signature', 'signature_enabled'
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
'is_active' => 'boolean',
|
||||
'signature_enabled' => 'boolean',
|
||||
'last_sync_at' => 'datetime',
|
||||
];
|
||||
|
||||
public function folders(): HasMany
|
||||
{
|
||||
return $this->hasMany(EmailFolder::class)->orderBy('sort_order');
|
||||
}
|
||||
|
||||
public function getImapConfig(): array
|
||||
{
|
||||
return [
|
||||
'host' => $this->imap_host,
|
||||
'port' => $this->imap_port,
|
||||
'encryption' => $this->imap_encryption,
|
||||
'username' => $this->imap_username,
|
||||
'password' => $this->imap_password,
|
||||
];
|
||||
}
|
||||
|
||||
public function getDecryptedPassword(): string
|
||||
{
|
||||
if (empty($this->imap_password)) {
|
||||
return '';
|
||||
}
|
||||
try {
|
||||
return Crypt::decryptString($this->imap_password);
|
||||
} catch (\Exception $e) {
|
||||
return $this->imap_password;
|
||||
}
|
||||
}
|
||||
|
||||
public function getDecryptedSmtpPassword(): string
|
||||
{
|
||||
if (empty($this->smtp_password)) {
|
||||
return $this->getDecryptedPassword();
|
||||
}
|
||||
try {
|
||||
return Crypt::decryptString($this->smtp_password);
|
||||
} catch (\Exception $e) {
|
||||
return $this->smtp_password;
|
||||
}
|
||||
}
|
||||
|
||||
public function getSmtpConfig(): array
|
||||
{
|
||||
return [
|
||||
'host' => $this->smtp_host ?? $this->imap_host,
|
||||
'port' => $this->smtp_port ?? 587,
|
||||
'encryption' => $this->smtp_encryption ?? 'tls',
|
||||
'username' => $this->smtp_username ?? $this->imap_username,
|
||||
'password' => $this->smtp_password ?? $this->imap_password,
|
||||
];
|
||||
}
|
||||
|
||||
public function getImapClient(): ?\DirectoryTree\ImapEngine\Mailbox
|
||||
{
|
||||
if (!$this->imap_host || !$this->imap_username) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
$encryption = match ($this->imap_encryption) {
|
||||
'ssl' => 'ssl',
|
||||
'tls' => 'tls',
|
||||
default => 'none',
|
||||
};
|
||||
|
||||
return new \DirectoryTree\ImapEngine\Mailbox([
|
||||
'host' => $this->imap_host,
|
||||
'port' => $this->imap_port ?? 993,
|
||||
'encryption' => $encryption,
|
||||
'validate_cert' => false,
|
||||
'username' => $this->imap_username,
|
||||
'password' => $this->getDecryptedPassword(),
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public function testConnection(): array
|
||||
{
|
||||
try {
|
||||
$mailbox = $this->getImapClient();
|
||||
|
||||
if (!$mailbox) {
|
||||
return ['success' => false, 'message' => 'Configurazione IMAP non valida'];
|
||||
}
|
||||
|
||||
$mailbox->connect();
|
||||
$mailbox->disconnect();
|
||||
|
||||
return [
|
||||
'success' => true,
|
||||
'message' => 'Connessione IMAP riuscita! Server: ' . $this->imap_host
|
||||
];
|
||||
} catch (\Exception $e) {
|
||||
$message = $e->getMessage();
|
||||
if (strpos($message, 'Undefined property') !== false) {
|
||||
return ['success' => true, 'message' => 'Connessione IMAP riuscita! (Server: ' . $this->imap_host . ')'];
|
||||
}
|
||||
return ['success' => false, 'message' => $message];
|
||||
}
|
||||
}
|
||||
|
||||
public static function getActive()
|
||||
{
|
||||
return self::where('is_active', true)->first();
|
||||
}
|
||||
|
||||
public function getSignature(): ?string
|
||||
{
|
||||
return $this->signature;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,267 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
|
||||
class Evento extends Model
|
||||
{
|
||||
protected $table = 'eventi';
|
||||
|
||||
protected $fillable = [
|
||||
'tenant_id',
|
||||
'nome_evento',
|
||||
'descrizione_evento',
|
||||
'tipo_evento',
|
||||
'tipo_recorrenza',
|
||||
'giorno_settimana',
|
||||
'giorno_mese',
|
||||
'occorrenza_mese',
|
||||
'mesi_recorrenza',
|
||||
'mese_annuale',
|
||||
'ora_inizio',
|
||||
'data_specifica',
|
||||
'durata_minuti',
|
||||
'descrizione',
|
||||
'note',
|
||||
'is_incontro_gruppo',
|
||||
'luogo_indirizzo',
|
||||
'luogo_url_maps',
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
'data_specifica' => 'date',
|
||||
'ora_inizio' => 'datetime:H:i',
|
||||
'is_incontro_gruppo' => 'boolean',
|
||||
];
|
||||
|
||||
public function tenant(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Tenant::class);
|
||||
}
|
||||
|
||||
public function gruppi(): BelongsToMany
|
||||
{
|
||||
return $this->belongsToMany(Gruppo::class, 'eventi_gruppi')->withTimestamps();
|
||||
}
|
||||
|
||||
public function responsabili(): BelongsToMany
|
||||
{
|
||||
return $this->belongsToMany(Individuo::class, 'eventi_responsabili')->withTimestamps();
|
||||
}
|
||||
|
||||
public function documenti(): BelongsToMany
|
||||
{
|
||||
return $this->belongsToMany(Documento::class, 'eventi_documenti')->withTimestamps();
|
||||
}
|
||||
|
||||
public function isRicorrente(): bool
|
||||
{
|
||||
return $this->tipo_recorrenza !== null && $this->tipo_recorrenza !== 'singolo';
|
||||
}
|
||||
|
||||
public function isSingolo(): bool
|
||||
{
|
||||
return $this->tipo_recorrenza === 'singolo' || $this->tipo_recorrenza === null;
|
||||
}
|
||||
|
||||
public function isGlobale(): bool
|
||||
{
|
||||
return $this->gruppi()->count() === 0;
|
||||
}
|
||||
|
||||
public function isEventoRicorrenteSettimanale(): bool
|
||||
{
|
||||
return $this->tipo_recorrenza === 'settimanale';
|
||||
}
|
||||
|
||||
public function isEventoRicorrenteMensile(): bool
|
||||
{
|
||||
return $this->tipo_recorrenza === 'mensile';
|
||||
}
|
||||
|
||||
public function isEventoRicorrenteAnnuale(): bool
|
||||
{
|
||||
return $this->tipo_recorrenza === 'annuale';
|
||||
}
|
||||
|
||||
public function isEventoAltro(): bool
|
||||
{
|
||||
return $this->tipo_recorrenza === 'altro';
|
||||
}
|
||||
|
||||
public function isIncroGruppo(): bool
|
||||
{
|
||||
return $this->is_incontro_gruppo === true;
|
||||
}
|
||||
|
||||
public function getGiornoSettimanaLabelAttribute(): string
|
||||
{
|
||||
$giorni = [
|
||||
0 => 'Domenica',
|
||||
1 => 'Lunedì',
|
||||
2 => 'Martedì',
|
||||
3 => 'Mercoledì',
|
||||
4 => 'Giovedì',
|
||||
5 => 'Venerdì',
|
||||
6 => 'Sabato',
|
||||
];
|
||||
return $giorni[$this->giorno_settimana] ?? '-';
|
||||
}
|
||||
|
||||
public function getGiornoSettimanaList(): array
|
||||
{
|
||||
return [
|
||||
0 => ['value' => 0, 'label' => 'Domenica'],
|
||||
1 => ['value' => 1, 'label' => 'Lunedì'],
|
||||
2 => ['value' => 2, 'label' => 'Martedì'],
|
||||
3 => ['value' => 3, 'label' => 'Mercoledì'],
|
||||
4 => ['value' => 4, 'label' => 'Giovedì'],
|
||||
5 => ['value' => 5, 'label' => 'Venerdì'],
|
||||
6 => ['value' => 6, 'label' => 'Sabato'],
|
||||
];
|
||||
}
|
||||
|
||||
public function getOccorrenzeMensiliList(): array
|
||||
{
|
||||
$giorni = ['Lunedì', 'Martedì', 'Mercoledì', 'Giovedì', 'Venerdì', 'Sabato', 'Domenica'];
|
||||
$list = [];
|
||||
for ($occ = 1; $occ <= 4; $occ++) {
|
||||
foreach ($giorni as $idx => $giorno) {
|
||||
$value = $occ . ',' . $idx;
|
||||
$label = $occ . '° ' . $giorno;
|
||||
$list[] = ['value' => $value, 'label' => $label];
|
||||
}
|
||||
}
|
||||
return $list;
|
||||
}
|
||||
|
||||
public function getOccorrenzaMensileLabelAttribute(): string
|
||||
{
|
||||
if (!$this->occorrenza_mese) {
|
||||
return '-';
|
||||
}
|
||||
|
||||
$parts = explode(',', $this->occorrenza_mese);
|
||||
if (count($parts) !== 2) {
|
||||
return '-';
|
||||
}
|
||||
|
||||
$occorrenza = (int) $parts[0];
|
||||
$giorno = (int) $parts[1];
|
||||
|
||||
$giorni = ['Lunedì', 'Martedì', 'Mercoledì', 'Giovedì', 'Venerdì', 'Sabato', 'Domenica'];
|
||||
|
||||
return $occorrenza . '° ' . ($giorni[$giorno] ?? '-');
|
||||
}
|
||||
|
||||
public function getMesiList(): array
|
||||
{
|
||||
return [
|
||||
1 => ['value' => 1, 'label' => 'Gennaio'],
|
||||
2 => ['value' => 2, 'label' => 'Febbraio'],
|
||||
3 => ['value' => 3, 'label' => 'Marzo'],
|
||||
4 => ['value' => 4, 'label' => 'Aprile'],
|
||||
5 => ['value' => 5, 'label' => 'Maggio'],
|
||||
6 => ['value' => 6, 'label' => 'Giugno'],
|
||||
7 => ['value' => 7, 'label' => 'Luglio'],
|
||||
8 => ['value' => 8, 'label' => 'Agosto'],
|
||||
9 => ['value' => 9, 'label' => 'Settembre'],
|
||||
10 => ['value' => 10, 'label' => 'Ottobre'],
|
||||
11 => ['value' => 11, 'label' => 'Novembre'],
|
||||
12 => ['value' => 12, 'label' => 'Dicembre'],
|
||||
];
|
||||
}
|
||||
|
||||
public function getMesiRecorrenzaLabelAttribute(): string
|
||||
{
|
||||
if (!$this->mesi_recorrenza) {
|
||||
return '-';
|
||||
}
|
||||
|
||||
$mesiSelezionati = explode(',', $this->mesi_recorrenza);
|
||||
$mesiLabels = $this->getMesiList();
|
||||
|
||||
$labels = array_map(function ($mese) use ($mesiLabels) {
|
||||
return $mesiLabels[$mese]['label'] ?? $mese;
|
||||
}, $mesiSelezionati);
|
||||
|
||||
return implode(', ', $labels);
|
||||
}
|
||||
|
||||
public function getMeseAnnualeLabelAttribute(): string
|
||||
{
|
||||
if (!$this->mese_annuale) {
|
||||
return '-';
|
||||
}
|
||||
|
||||
$mesiLabels = $this->getMesiList();
|
||||
return $mesiLabels[$this->mese_annuale]['label'] ?? '-';
|
||||
}
|
||||
|
||||
public function getPeriodicitaLabelAttribute(): string
|
||||
{
|
||||
$labels = [
|
||||
'settimanale' => 'Settimanale',
|
||||
'mensile' => 'Mensile',
|
||||
'annuale' => 'Annuale',
|
||||
'altro' => 'Altro',
|
||||
'singolo' => 'Singolo',
|
||||
];
|
||||
return $labels[$this->tipo_recorrenza] ?? '-';
|
||||
}
|
||||
|
||||
public function getInfoRicorrenzaAttribute(): string
|
||||
{
|
||||
if ($this->tipo_recorrenza === 'settimanale') {
|
||||
return 'Ogni ' . $this->giorno_settimana_label;
|
||||
}
|
||||
|
||||
if ($this->tipo_recorrenza === 'mensile') {
|
||||
$info = [];
|
||||
if ($this->occorrenza_mese) {
|
||||
$info[] = $this->occorrenza_mensile_label;
|
||||
}
|
||||
if ($this->mesi_recorrenza) {
|
||||
$info[] = '(' . $this->mesi_recorrenza_label . ')';
|
||||
}
|
||||
return implode(' ', $info) ?: '-';
|
||||
}
|
||||
|
||||
if ($this->tipo_recorrenza === 'annuale') {
|
||||
if ($this->mese_annuale) {
|
||||
return $this->mese_annuale_label;
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->tipo_recorrenza === 'altro') {
|
||||
return $this->giorno_settimana_label ?? '-';
|
||||
}
|
||||
|
||||
return '-';
|
||||
}
|
||||
|
||||
public function getInfoIncroAttribute(): ?string
|
||||
{
|
||||
if (!$this->is_incontro_gruppo) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$info = [];
|
||||
|
||||
if ($this->isRicorrente()) {
|
||||
$info[] = $this->info_ricorrenza;
|
||||
} else {
|
||||
$info[] = $this->data_specifica?->format('d/m/Y') ?? '-';
|
||||
}
|
||||
|
||||
if ($this->ora_inizio) {
|
||||
$info[] = 'ore ' . $this->ora_inizio->format('H:i');
|
||||
}
|
||||
|
||||
return implode(' ', $info);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
|
||||
class Gruppo extends Model
|
||||
{
|
||||
protected $table = 'gruppi';
|
||||
protected $fillable = [
|
||||
'tenant_id', 'parent_id', 'diocesi_id', 'responsabile_ids',
|
||||
'nome', 'descrizione', 'indirizzo_incontro', 'cap_incontro',
|
||||
'città_incontro', 'sigla_provincia_incontro', 'mappa_posizione', 'metadata'
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
'metadata' => 'array',
|
||||
'responsabile_ids' => 'array',
|
||||
];
|
||||
|
||||
public function tenant(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Tenant::class);
|
||||
}
|
||||
|
||||
public function parent(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Gruppo::class, 'parent_id');
|
||||
}
|
||||
|
||||
public function children(): HasMany
|
||||
{
|
||||
return $this->hasMany(Gruppo::class, 'parent_id');
|
||||
}
|
||||
|
||||
public function diocesi(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Diocesi::class);
|
||||
}
|
||||
|
||||
public function individui(): BelongsToMany
|
||||
{
|
||||
return $this->belongsToMany(Individuo::class, 'gruppo_individuo')
|
||||
->withPivot('ruolo_ids', 'ruolo_nel_gruppo', 'data_adesione')
|
||||
->withTimestamps();
|
||||
}
|
||||
|
||||
public function getResponsabiliIds(): array
|
||||
{
|
||||
if (empty($this->responsabile_ids)) {
|
||||
return [];
|
||||
}
|
||||
if (is_array($this->responsabile_ids)) {
|
||||
return $this->responsabile_ids;
|
||||
}
|
||||
return json_decode($this->responsabile_ids, true) ?? [];
|
||||
}
|
||||
|
||||
public function getResponsabili(): \Illuminate\Database\Eloquent\Collection
|
||||
{
|
||||
$ids = $this->getResponsabiliIds();
|
||||
if (empty($ids)) {
|
||||
return new \Illuminate\Database\Eloquent\Collection();
|
||||
}
|
||||
return Individuo::whereIn('id', $ids)->get();
|
||||
}
|
||||
|
||||
public function eventi(): BelongsToMany
|
||||
{
|
||||
return $this->belongsToMany(Evento::class, 'eventi_gruppi')->withTimestamps();
|
||||
}
|
||||
|
||||
public function documenti(): HasMany
|
||||
{
|
||||
return $this->hasMany(Documento::class, 'visibilita_target_id')
|
||||
->where('visibilita_target_type', self::class);
|
||||
}
|
||||
|
||||
public function getAncestors(): array
|
||||
{
|
||||
$ancestors = [];
|
||||
$current = $this->parent;
|
||||
while ($current) {
|
||||
$ancestors[] = $current;
|
||||
$current = $current->parent;
|
||||
}
|
||||
return $ancestors;
|
||||
}
|
||||
|
||||
public function getDescendants(): array
|
||||
{
|
||||
$descendants = [];
|
||||
foreach ($this->children as $child) {
|
||||
$descendants[] = $child;
|
||||
$descendants = array_merge($descendants, $child->getDescendants());
|
||||
}
|
||||
return $descendants;
|
||||
}
|
||||
|
||||
public function getFullPathAttribute(): string
|
||||
{
|
||||
$path = [$this->nome];
|
||||
foreach (array_reverse($this->getAncestors()) as $ancestor) {
|
||||
$path[] = $ancestor->nome;
|
||||
}
|
||||
return implode(' > ', array_reverse($path));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
use Illuminate\Database\Eloquent\Relations\HasOne;
|
||||
|
||||
class Individuo extends Model
|
||||
{
|
||||
protected $table = 'individui';
|
||||
protected $fillable = [
|
||||
'tenant_id', 'codice_id', 'cognome', 'nome', 'data_nascita',
|
||||
'indirizzo', 'cap', 'città', 'sigla_provincia', 'genere',
|
||||
'tipo_documento', 'numero_documento', 'scadenza_documento', 'note', 'avatar_path'
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
'data_nascita' => 'date',
|
||||
'scadenza_documento' => 'date',
|
||||
];
|
||||
|
||||
public function hasDocumentoScaduto(): bool
|
||||
{
|
||||
return $this->scadenza_documento && $this->scadenza_documento->isPast();
|
||||
}
|
||||
|
||||
public function hasDocumentoScadeEntroGiorni(int $giorni): bool
|
||||
{
|
||||
if (!$this->scadenza_documento || $this->scadenza_documento->isPast()) {
|
||||
return false;
|
||||
}
|
||||
return $this->scadenza_documento->diffInDays(null, true) <= $giorni;
|
||||
}
|
||||
|
||||
public function getGiorniScadenzaDocumentoAttribute(): ?int
|
||||
{
|
||||
if (!$this->scadenza_documento) {
|
||||
return null;
|
||||
}
|
||||
return (int) round($this->scadenza_documento->diffInDays(null, true));
|
||||
}
|
||||
|
||||
public static function boot(): void
|
||||
{
|
||||
parent::boot();
|
||||
|
||||
static::creating(function ($individuo) {
|
||||
if (empty($individuo->codice_id)) {
|
||||
$individuo->codice_id = static::generaCodiceId();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static function generaCodiceId(): string
|
||||
{
|
||||
do {
|
||||
$codice = str_pad(random_int(1, 99999), 5, '0', STR_PAD_LEFT);
|
||||
} while (static::where('codice_id', $codice)->exists());
|
||||
|
||||
return $codice;
|
||||
}
|
||||
|
||||
public function tenant(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Tenant::class);
|
||||
}
|
||||
|
||||
public function contatti(): HasMany
|
||||
{
|
||||
return $this->hasMany(Contatto::class)->orderBy('is_primary', 'desc');
|
||||
}
|
||||
|
||||
public function gruppi(): BelongsToMany
|
||||
{
|
||||
return $this->belongsToMany(Gruppo::class, 'gruppo_individuo')
|
||||
->withPivot('ruolo_ids', 'ruolo_nel_gruppo', 'data_adesione')
|
||||
->withTimestamps();
|
||||
}
|
||||
|
||||
public function getRuoloIdsForGruppo($gruppoId): array
|
||||
{
|
||||
$pivot = $this->gruppi()->wherePivot('gruppo_id', $gruppoId)->first()?->pivot;
|
||||
if ($pivot && $pivot->ruolo_ids) {
|
||||
return json_decode($pivot->ruolo_ids, true) ?? [];
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
public function getRuoliForGruppo($gruppoId): \Illuminate\Database\Eloquent\Collection
|
||||
{
|
||||
$ids = $this->getRuoloIdsForGruppo($gruppoId);
|
||||
return Ruolo::findByIds($ids);
|
||||
}
|
||||
|
||||
public function getRuoliNamesForGruppo($gruppoId): string
|
||||
{
|
||||
return Ruolo::namesByIds($this->getRuoloIdsForGruppo($gruppoId));
|
||||
}
|
||||
|
||||
public function mailingContacts(): HasMany
|
||||
{
|
||||
return $this->hasMany(MailingContact::class);
|
||||
}
|
||||
|
||||
public function eventiResponsabili(): BelongsToMany
|
||||
{
|
||||
return $this->belongsToMany(Evento::class, 'eventi_responsabili');
|
||||
}
|
||||
|
||||
public function avatar(): HasOne
|
||||
{
|
||||
return $this->hasOne(Documento::class, 'visibilita_target_id')
|
||||
->where('tipologia', 'avatar')
|
||||
->where('visibilita_target_type', self::class);
|
||||
}
|
||||
|
||||
public function getNomeCompletoAttribute(): string
|
||||
{
|
||||
return $this->cognome . ' ' . $this->nome;
|
||||
}
|
||||
|
||||
public function getEmailPrimariaAttribute(): ?string
|
||||
{
|
||||
return $this->contatti()->where('tipo', 'email')->where('is_primary', true)->first()?->valore
|
||||
?? $this->contatti()->where('tipo', 'email')->first()?->valore;
|
||||
}
|
||||
|
||||
public function getTelefonoPrimarioAttribute(): ?string
|
||||
{
|
||||
return $this->contatti()->whereIn('tipo', ['telefono', 'cellulare'])->where('is_primary', true)->first()?->valore
|
||||
?? $this->contatti()->whereIn('tipo', ['telefono', 'cellulare'])->first()?->valore;
|
||||
}
|
||||
|
||||
public function documenti(): HasMany
|
||||
{
|
||||
return $this->hasMany(Documento::class, 'visibilita_target_id')
|
||||
->where('visibilita_target_type', self::class);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
|
||||
class MailingContact extends Model
|
||||
{
|
||||
protected $table = 'mailing_contacts';
|
||||
protected $fillable = ['mailing_list_id', 'individuo_id', 'opt_in', 'opt_in_data', 'opt_out_data'];
|
||||
|
||||
protected $casts = [
|
||||
'opt_in' => 'boolean',
|
||||
'opt_in_data' => 'datetime',
|
||||
'opt_out_data' => 'datetime',
|
||||
];
|
||||
|
||||
public function mailingList(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(MailingList::class);
|
||||
}
|
||||
|
||||
public function individuo(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Individuo::class);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
|
||||
class MailingList extends Model
|
||||
{
|
||||
protected $table = 'mailing_lists';
|
||||
protected $fillable = ['tenant_id', 'user_id', 'nome', 'descrizione', 'attiva'];
|
||||
|
||||
protected $casts = ['attiva' => 'boolean'];
|
||||
|
||||
public function tenant(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Tenant::class);
|
||||
}
|
||||
|
||||
public function user(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(User::class);
|
||||
}
|
||||
|
||||
public function contatti(): HasMany
|
||||
{
|
||||
return $this->hasMany(MailingContact::class);
|
||||
}
|
||||
|
||||
public function messaggi(): HasMany
|
||||
{
|
||||
return $this->hasMany(MailingMessaggio::class);
|
||||
}
|
||||
|
||||
public function getIndividui()
|
||||
{
|
||||
return Individuo::whereHas('mailingContacts', function ($q) {
|
||||
$q->where('mailing_list_id', $this->id)->where('opt_in', true);
|
||||
})->get();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
|
||||
class MailingMessaggio extends Model
|
||||
{
|
||||
protected $table = 'mailing_messaggi';
|
||||
protected $fillable = [
|
||||
'tenant_id', 'mailing_list_id', 'user_id', 'oggetto', 'corpo',
|
||||
'canale', 'stato', 'inviato_al', 'totale_destinatari', 'invii_ok', 'invii_falliti'
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
'inviato_al' => 'datetime',
|
||||
];
|
||||
|
||||
public function tenant(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Tenant::class);
|
||||
}
|
||||
|
||||
public function mailingList(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(MailingList::class);
|
||||
}
|
||||
|
||||
public function user(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(User::class);
|
||||
}
|
||||
|
||||
public function isInviato(): bool
|
||||
{
|
||||
return $this->stato === 'inviato';
|
||||
}
|
||||
|
||||
public function canBeSent(): bool
|
||||
{
|
||||
return in_array($this->stato, ['bozza', 'fallito']);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
|
||||
class Notifica extends Model
|
||||
{
|
||||
protected $table = 'notifiche';
|
||||
protected $fillable = ['user_id', 'tipo', 'titolo', 'messaggio', 'link', 'is_read', 'read_at'];
|
||||
|
||||
protected $casts = [
|
||||
'is_read' => 'boolean',
|
||||
'read_at' => 'datetime',
|
||||
];
|
||||
|
||||
public function user(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(User::class);
|
||||
}
|
||||
|
||||
public function markAsRead(): void
|
||||
{
|
||||
$this->update(['is_read' => true, 'read_at' => now()]);
|
||||
}
|
||||
|
||||
public function scopeUnread($query)
|
||||
{
|
||||
return $query->where('is_read', false);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
|
||||
class ReportCustom extends Model
|
||||
{
|
||||
protected $table = 'report_custom';
|
||||
|
||||
protected $fillable = [
|
||||
'user_id',
|
||||
'nome',
|
||||
'descrizione',
|
||||
'tipo_report',
|
||||
'config',
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
'config' => 'array',
|
||||
];
|
||||
|
||||
public function user(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(User::class);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
|
||||
class RolePreset extends Model
|
||||
{
|
||||
protected $fillable = ['name', 'description', 'permissions'];
|
||||
|
||||
protected $casts = [
|
||||
'permissions' => 'array',
|
||||
];
|
||||
|
||||
public function users(): HasMany
|
||||
{
|
||||
return $this->hasMany(User::class, 'role_preset_id');
|
||||
}
|
||||
|
||||
public static function defaultPermissions(): array
|
||||
{
|
||||
return [
|
||||
'individui' => 1,
|
||||
'gruppi' => 1,
|
||||
'eventi' => 1,
|
||||
'documenti' => 1,
|
||||
'mailing' => 1,
|
||||
'viste' => 1,
|
||||
];
|
||||
}
|
||||
|
||||
public static function adminPreset(): array
|
||||
{
|
||||
return [
|
||||
'individui' => 2,
|
||||
'gruppi' => 2,
|
||||
'eventi' => 2,
|
||||
'documenti' => 2,
|
||||
'mailing' => 2,
|
||||
'viste' => 2,
|
||||
];
|
||||
}
|
||||
|
||||
public static function operatorePreset(): array
|
||||
{
|
||||
return [
|
||||
'individui' => 2,
|
||||
'gruppi' => 2,
|
||||
'eventi' => 2,
|
||||
'documenti' => 1,
|
||||
'mailing' => 1,
|
||||
'viste' => 1,
|
||||
];
|
||||
}
|
||||
|
||||
public static function letturaPreset(): array
|
||||
{
|
||||
return [
|
||||
'individui' => 1,
|
||||
'gruppi' => 1,
|
||||
'eventi' => 1,
|
||||
'documenti' => 1,
|
||||
'mailing' => 1,
|
||||
'viste' => 1,
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class Ruolo extends Model
|
||||
{
|
||||
protected $table = 'ruoli';
|
||||
|
||||
protected $fillable = ['nome', 'descrizione', 'ordine', 'attiva'];
|
||||
|
||||
protected $casts = [
|
||||
'attiva' => 'boolean',
|
||||
'ordine' => 'integer',
|
||||
];
|
||||
|
||||
public static function attive(): \Illuminate\Database\Eloquent\Collection
|
||||
{
|
||||
return static::where('attiva', true)->orderBy('ordine')->get();
|
||||
}
|
||||
|
||||
public static function opzioni(): array
|
||||
{
|
||||
return static::attive()->pluck('nome', 'id')->toArray();
|
||||
}
|
||||
|
||||
public static function findByIds(?array $ids): \Illuminate\Database\Eloquent\Collection
|
||||
{
|
||||
if (empty($ids)) {
|
||||
return new \Illuminate\Database\Eloquent\Collection();
|
||||
}
|
||||
return static::whereIn('id', $ids)->get();
|
||||
}
|
||||
|
||||
public static function namesByIds(?array $ids): string
|
||||
{
|
||||
if (empty($ids)) {
|
||||
return '';
|
||||
}
|
||||
return static::whereIn('id', $ids)
|
||||
->orderBy('ordine')
|
||||
->pluck('nome')
|
||||
->implode(', ');
|
||||
}
|
||||
|
||||
public function getMembriCount(): int
|
||||
{
|
||||
return DB::table('gruppo_individuo')
|
||||
->whereNotNull('ruolo_ids')
|
||||
->whereRaw("JSON_CONTAINS(ruolo_ids, ?)", [json_encode($this->id)])
|
||||
->count();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
|
||||
class Tenant extends Model
|
||||
{
|
||||
protected $table = 'tenants';
|
||||
protected $fillable = ['nome', 'slug', 'email', 'telefono', 'note', 'attivo'];
|
||||
|
||||
public function individui(): HasMany
|
||||
{
|
||||
return $this->hasMany(Individuo::class);
|
||||
}
|
||||
|
||||
public function gruppi(): HasMany
|
||||
{
|
||||
return $this->hasMany(Gruppo::class);
|
||||
}
|
||||
|
||||
public function documenti(): HasMany
|
||||
{
|
||||
return $this->hasMany(Documento::class);
|
||||
}
|
||||
|
||||
public function mailingLists(): HasMany
|
||||
{
|
||||
return $this->hasMany(MailingList::class);
|
||||
}
|
||||
|
||||
public function eventi(): HasMany
|
||||
{
|
||||
return $this->hasMany(Evento::class);
|
||||
}
|
||||
|
||||
public function users(): HasMany
|
||||
{
|
||||
return $this->hasMany(User::class);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
|
||||
class TipologiaDocumento extends Model
|
||||
{
|
||||
protected $table = 'tipologie_documenti';
|
||||
|
||||
protected $fillable = ['nome', 'descrizione', 'ordine', 'attiva'];
|
||||
|
||||
protected $casts = [
|
||||
'attiva' => 'boolean',
|
||||
'ordine' => 'integer',
|
||||
];
|
||||
|
||||
public function documenti(): HasMany
|
||||
{
|
||||
return $this->hasMany(Documento::class, 'tipologia', 'nome');
|
||||
}
|
||||
|
||||
public static function attive(): \Illuminate\Database\Eloquent\Collection
|
||||
{
|
||||
return static::where('attiva', true)->orderBy('ordine')->get();
|
||||
}
|
||||
|
||||
public static function opzioni(): array
|
||||
{
|
||||
return static::attive()->pluck('nome')->toArray();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,159 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Attributes\Fillable;
|
||||
use Illuminate\Database\Eloquent\Attributes\Hidden;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Illuminate\Foundation\Auth\User as Authenticatable;
|
||||
use Illuminate\Notifications\Notifiable;
|
||||
|
||||
#[Fillable(['name', 'email', 'password', 'tenant_id', 'is_admin', 'permissions', 'role_preset_id', 'status'])]
|
||||
#[Hidden(['password', 'remember_token'])]
|
||||
class User extends Authenticatable
|
||||
{
|
||||
use HasFactory, Notifiable;
|
||||
|
||||
protected $fillable = ['name', 'email', 'password', 'tenant_id', 'is_admin', 'permissions', 'role_preset_id', 'status'];
|
||||
|
||||
protected function casts(): array
|
||||
{
|
||||
return [
|
||||
'email_verified_at' => 'datetime',
|
||||
'password' => 'hashed',
|
||||
'is_admin' => 'boolean',
|
||||
'permissions' => 'array',
|
||||
'status' => 'string',
|
||||
];
|
||||
}
|
||||
|
||||
public const STATUS_ACTIVE = 'active';
|
||||
public const STATUS_SUSPENDED = 'suspended';
|
||||
public const STATUS_PENDING = 'pending';
|
||||
|
||||
public const MODULES = ['individui', 'gruppi', 'eventi', 'documenti', 'mailing', 'viste', 'report'];
|
||||
public const LEVEL_NONE = 0;
|
||||
public const LEVEL_READ = 1;
|
||||
public const LEVEL_FULL = 2;
|
||||
|
||||
public function tenant(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Tenant::class);
|
||||
}
|
||||
|
||||
public function rolePreset(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(RolePreset::class);
|
||||
}
|
||||
|
||||
public function notifiche(): HasMany
|
||||
{
|
||||
return $this->hasMany(Notifica::class)->orderBy('created_at', 'desc');
|
||||
}
|
||||
|
||||
public function unreadNotifiche(): HasMany
|
||||
{
|
||||
return $this->hasMany(Notifica::class)->where('is_read', false)->orderBy('created_at', 'desc');
|
||||
}
|
||||
|
||||
public function unreadNotificheCount(): int
|
||||
{
|
||||
return $this->notifiche()->unread()->count();
|
||||
}
|
||||
|
||||
public function activityLogs(): HasMany
|
||||
{
|
||||
return $this->hasMany(ActivityLog::class)->orderBy('created_at', 'desc');
|
||||
}
|
||||
|
||||
public function isSuperAdmin(): bool
|
||||
{
|
||||
return $this->is_admin === true;
|
||||
}
|
||||
|
||||
public static function firstUserIsAdmin(): bool
|
||||
{
|
||||
return self::count() === 1;
|
||||
}
|
||||
|
||||
public function isActive(): bool
|
||||
{
|
||||
return $this->status !== self::STATUS_SUSPENDED;
|
||||
}
|
||||
|
||||
public function getPermission(string $module): int
|
||||
{
|
||||
if ($this->isSuperAdmin()) {
|
||||
return self::LEVEL_FULL;
|
||||
}
|
||||
|
||||
return $this->permissions[$module] ?? self::LEVEL_NONE;
|
||||
}
|
||||
|
||||
public function hasPermission(string $module, int $level = self::LEVEL_READ): bool
|
||||
{
|
||||
return $this->getPermission($module) >= $level;
|
||||
}
|
||||
|
||||
public function canAccess(string $module): bool
|
||||
{
|
||||
return $this->getPermission($module) >= self::LEVEL_READ;
|
||||
}
|
||||
|
||||
public function canManage(string $module): bool
|
||||
{
|
||||
return $this->getPermission($module) >= self::LEVEL_FULL;
|
||||
}
|
||||
|
||||
public function canRead(string $module): bool
|
||||
{
|
||||
return $this->getPermission($module) >= self::LEVEL_READ;
|
||||
}
|
||||
|
||||
public function canWrite(string $module): bool
|
||||
{
|
||||
return $this->getPermission($module) >= self::LEVEL_FULL;
|
||||
}
|
||||
|
||||
public function canDelete(string $module): bool
|
||||
{
|
||||
return $this->getPermission($module) >= self::LEVEL_FULL;
|
||||
}
|
||||
|
||||
public function setPermission(string $module, int $level): self
|
||||
{
|
||||
$permissions = $this->permissions ?? [];
|
||||
$permissions[$module] = $level;
|
||||
$this->permissions = $permissions;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setPermissions(array $permissions): self
|
||||
{
|
||||
$this->permissions = $permissions;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getPermissionsSummary(): array
|
||||
{
|
||||
$result = [];
|
||||
foreach (self::MODULES as $module) {
|
||||
$level = $this->getPermission($module);
|
||||
$result[$module] = match ($level) {
|
||||
self::LEVEL_NONE => 'Nessuno',
|
||||
self::LEVEL_READ => 'Lettura',
|
||||
self::LEVEL_FULL => 'Completo',
|
||||
};
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function applyRolePreset(RolePreset $preset): self
|
||||
{
|
||||
$this->role_preset_id = $preset->id;
|
||||
$this->permissions = $preset->permissions;
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
|
||||
class VistaReport extends Model
|
||||
{
|
||||
protected $table = 'viste_report';
|
||||
protected $fillable = [
|
||||
'user_id', 'nome', 'tipo', 'colonne_visibili',
|
||||
'colonne_ordinamento', 'filtri', 'ricerca'
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
'colonne_visibili' => 'array',
|
||||
'colonne_ordinamento' => 'array',
|
||||
'filtri' => 'array',
|
||||
];
|
||||
|
||||
public function user(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(User::class);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user