'datetime', 'is_active' => 'boolean', 'name' => 'array', 'description' => 'array', 'photobooth_enabled' => 'boolean', 'photobooth_expires_at' => 'datetime', 'photobooth_metadata' => 'array', ]; protected $hidden = [ 'photobooth_password_encrypted', ]; protected static function booted(): void { static::created(function (self $event): void { if ($event->joinTokens()->exists()) { return; } app(EventJoinTokenService::class)->createToken($event, [ 'label' => 'Standard-Link', 'metadata' => [ 'auto_generated' => true, ], ]); }); } public function storageAssignments(): HasMany { return $this->hasMany(EventStorageAssignment::class); } public function mediaAssets(): HasMany { return $this->hasMany(EventMediaAsset::class); } public function currentStorageTarget(?string $role = 'hot'): ?MediaStorageTarget { $assignment = $this->storageAssignments() ->where('role', $role) ->where('status', 'active') ->latest('assigned_at') ->first(); return $assignment?->storageTarget; } public function tenant(): BelongsTo { return $this->belongsTo(Tenant::class); } public function eventType(): BelongsTo { return $this->belongsTo(EventType::class); } public function photos(): HasMany { return $this->hasMany(Photo::class); } public function taskCollections(): BelongsToMany { return $this->belongsToMany( TaskCollection::class, 'event_task_collection', 'event_id', 'task_collection_id' ); } public function tasks(): BelongsToMany { return $this->belongsToMany(Task::class, 'event_task', 'event_id', 'task_id') ->withTimestamps(); } public function eventPackage(): BelongsTo { return $this->belongsTo(EventPackage::class); } public function eventPackages(): HasMany { return $this->hasMany(EventPackage::class); } public function joinTokens(): HasMany { return $this->hasMany(EventJoinToken::class); } public function members(): HasMany { return $this->hasMany(EventMember::class); } public function hasActivePackage(): bool { return $this->eventPackage && $this->eventPackage->isActive(); } public function getPackageLimits(): array { if (! $this->hasActivePackage()) { return []; } return $this->eventPackage->package->limits; } public function canUploadPhoto(): bool { if (! $this->hasActivePackage()) { return false; } return $this->eventPackage->canUploadPhoto(); } public function getSettingsAttribute($value): array { if (is_array($value)) { return $value; } if (is_string($value) && $value !== '') { $decoded = json_decode($value, true); return is_array($decoded) ? $decoded : []; } return []; } public function setSettingsAttribute($value): void { if (is_string($value)) { $decoded = json_decode($value, true); $value = is_array($decoded) ? $decoded : []; } $this->attributes['settings'] = json_encode($value ?? []); } public function getPhotoboothPasswordAttribute(): ?string { $encrypted = $this->attributes['photobooth_password_encrypted'] ?? null; if (! $encrypted) { return null; } try { return Crypt::decryptString($encrypted); } catch (DecryptException) { return null; } } public function setPhotoboothPasswordAttribute(?string $value): void { $this->attributes['photobooth_password_encrypted'] = $value ? Crypt::encryptString($value) : null; } }