ChristmasTreeGameSetup.cs
- Neues Enum GameEndCondition mit AllFivesGone (Standard) und TreeCleared
- Property EndCondition zum Setup hinzugefügt
ChristmasTreeGameModel.cs
- Property EndCondition hinzugefügt
ChristmasTreeGameLogicService.cs
- Neue Methode CheckGameEndCondition() prüft je nach Einstellung
- Neue Methode CheckAnyTreeCleared() prüft ob ein Team alle Zahlen gestrichen hat
- Alle 3 Stellen wo Spielende geprüft wird nutzen jetzt die flexible Methode
ChristmasTreeSetup.razor
- Neues Dropdown "Spielende" mit zwei Optionen:
- "Alle 5er gestrichen" (Standard)
- "Ein Baum komplett leer"
- Hilfstexte erklären die jeweilige Bedingung
Der Fix teilt die Operation in zwei Schritte:
1. Alle IsDefault auf false → SaveChanges
2. Neuen Default auf true → SaveChanges
Das verhindert, dass EF Core temporär zwei IsDefault = true Einträge hat, was den Filtered Unique Index verletzen würde.
1. ClubService.cs:134 - MonthlyMembershipFee in UpdateAsync hinzugefügt
2. Settings.razor:358-364 - Laden der Kassenbuch-Einstellungen beim Init
3. Settings.razor:665-689 - SaveCashBookSettings() Methode implementiert
Der Kassenbuch-Tab in den Vereins-Einstellungen funktioniert jetzt:
- Zeigt aktuellen Kontostand
- Erlaubt Ändern des monatlichen Mitgliedsbeitrags
- Speichert Änderungen via Fluxor-Action
- Quick-Links zu Kassenbuch, Kategorien, Berichten
- ICashBookService.CreatePenaltyEntriesForDayAsync
- Groups PersonExpenses by person, sums amounts
- Marks PersonExpenses as Done
- DayService calls after SaveChanges
1. Neue Methode CreateAbsentMemberExpensesAsync() (Zeile 322-421)
- Prüft Club.ExpenseCalculation (None → skip)
- Berechnet Average/Maximum aller Tages-Expenses
- Findet Absent-Expense via ExpenseTriggerType.Absent
- Erstellt PersonExpense für alle abwesenden Members
2. Aufruf in AdvanceStatusAsync() (Zeile 312-316)
- Wird aufgerufen wenn Status → Closed wechselt
- Vor SaveChangesAsync() → eine Transaktion
1. IMediaStorageService (src/Koogle.Domain/Interfaces/):
- Neue Methoden GetMediaBasePath() und GetFilePath() hinzugefügt
2. MediaStorageService (src/Koogle.Infrastructure/Services/):
- Erkennt Production+Linux → verwendet /home/data/club-media
- Development → verwendet wwwroot/club-media
3. Program.cs (src/Koogle.Web/):
- StaticFileOptions für /club-media aus /home/data/club-media in Production
4. DemoSeeder (src/Koogle.Infrastructure/Data/):
- Alle Methoden nutzen jetzt IMediaStorageService statt hardkodierte Pfade
5. ClubGifService (src/Koogle.Application/Services/):
- Alle Path.Combine("wwwroot", ...) durch _mediaStorage.GetFilePath() ersetzt
Das Verhalten:
- Windows/Development: weiterhin wwwroot/club-media
- Linux/Production (Azure): /home/data/club-media (persistent und beschreibbar)
UI (Submit.razor)
- Toggle zwischen "Datei" und "URL" Modus
- URL-Eingabefeld mit Validierung (nur HTTP/HTTPS)
- Beide Modi teilen Submit-Button und Erfolgsanzeige
Service (IClubGifService, ClubGifService)
- Neue Methode SubmitAnonymousFromUrlAsync(token, url, name)
- Nutzt bestehende SaveGifFromUrlAsync von MediaStorageService
Serverseitige Validierung (bereits in MediaStorageService vorhanden):
- Content-Type Prüfung: nur image/gif, video/mp4, video/webm
- Dateigröße max. 20MB
- Datei wird nach Download nochmals auf Größe geprüft
- Ungültige Content-Types werden mit Exception abgelehnt
Summary of Changes:
Phase 1-3 (Domain/Infrastructure/Application):
- ThrowEventType enum with Strike, Circle, Bell, Gutter flags
- ClubGif, ClubGifRating, GifSubmissionToken entities
- EF configurations with proper indexes
- ClubGifRepository with weighted random selection
- MediaStorageService for file storage (wwwroot/club-media/{LoginName}/gifs/)
- ClubGifService with rating system and auto-disable at -5 threshold
Phase 4-5 (Admin UI & Playback):
- Admin page at /club/{ClubId}/admin/gifs with Upload, Import, Edit, Token management
- QR code generation for submission tokens
- GifPlayer component with overlay, rating buttons, and dismiss
- Fluxor state management (GifState, actions, reducers, effects)
Phase 6 (Anonymous Submission):
- Public page at /gif/submit/{Token} with EmptyLayout
- Token validation and file upload
Phase 7 (Game Integration + Migration):
- Database migration AddClubGifFeature applied
- GameEffects.TriggerGifForEventsAsync triggers GIFs on special throws
- SignalR broadcast via BroadcastGifTriggeredAsync to all clients
- DayDetails.razor includes GifPlayer and handles SignalR GIF events
Key Features:
- GIFs play on Strike (alle 9), Circle (Kranz), Bell (Glocke), Gutter (Rinne)
- Weighted random selection based on ratings
- Real-time sync across all connected clients via SignalR
- Thumbs up/down rating with auto-disable at -5
- Max file size: 20MB, Video duration: 15s
- Supports GIF, MP4, WebM formats