Cleanup code and prepare for AI usage

This commit is contained in:
2026-07-27 21:24:35 +02:00
parent b0110e1bc8
commit 04dca24513
33 changed files with 579 additions and 468 deletions
+39
View File
@@ -0,0 +1,39 @@
# apifootball — API-Football Integration
Fetches, caches, and serves match data from [API-Football](https://www.api-football.com/). Raw JSON is cached in S3 to avoid repeated API calls.
## Classes
### APIFootballUpdater
HTTP client that fetches raw JSON from API-Football and writes to S3.
- `updateAllFixtures(season)` — fetches all leagues' fixtures
- `updateAllRounds(season)` — fetches all leagues' round metadata
- `getRawData(requestPath, season, league)` — calls API-Football with rate-limit retry
- `getLeagues()` — reads league IDs from `Ligen_v3.json` resource
Handles the Tippliga↔API-Football season offset: for most leagues, Tippliga season N corresponds to API-Football season N-1 (except World Cup `league=1` and Euro `league=4`).
### APIFootballConnector
Singleton that reads cached S3 JSON and resolves API data into `APIFootballMatch` objects.
- `getMatchDataByLeagueAndMatchday(league, matchday)` — all matches for a matchday
- `getMatchDataByLeagueAndMatchID(league, id)` — single match by API fixture ID
- `getMatchdays(leagueId)` — round metadata from S3
- `getTeamsForLeague(season, league)` — live team list from API
### APIFootballMatch
Extends `BaseMatch`. Parses a raw API-Football JSON fixture object.
Parses: fixture ID, league ID, team IDs + names, round string, datetime, status, fulltime/extratime/penalty scores.
Key method: `getMatchdayFromRoundString(season, round, leagueId)` — converts API round names (e.g. `"Regular Season - 1"`) to Tippliga matchday numbers. Falls back to the rounds JSON for non-regular-season formats.
### APIFootballMatchesProvider
High-level resolver that reads matchday config (from the JSON config file) and returns flat `APIFootballMatch` lists.
Supports two config entry types:
- `AllMatchesOfMatchday` — fetch all matches for a given API league+matchday
- `SingleMatch` — fetch a specific match by API league+fixture ID
Honors `showTable` and `ko` flags from config.
+29
View File
@@ -0,0 +1,29 @@
# googlecalendar — Google Calendar Integration
Manages matchday deadline events in Google Calendar. Each matchday can have up to 3 delivery deadlines (1st, 2nd, 3rd chance).
## Classes
### GoogleCalendarConnector
Sets up the Google Calendar API service using a service account.
- Reads service account credentials from `tippliga-4e0def9ef447.json` (classpath resource)
- Uses `CalendarScopes.CALENDAR` scope
- Returns authenticated `com.google.api.services.calendar.Calendar` service
### CalendarConfigProvider
Reads calendar ID and URL from `Google_Calendar_Config.json` resource. Currently hardcoded to league 1.
### TippligaGoogleEventManager
CRUD operations for matchday deadline events.
- `createOrUpdateEventsForMatchday(matchday)` — creates/updates up to 3 events per matchday
- `createNewEvent()` / `updateEvent()` / `deleteEvent()` — individual event operations
- `deleteAllEvents(season)` — wipe all events for a season
- `updateAllMatchdays(matchdays)` — batch update; automatically deletes events for removed delivery dates
Event details:
- **Summary**: `"Tippliga Spieltag N tippen!"` (or custom matchday name)
- **Description**: season, league, matchday, delivery deadline number
- **Location**: `https://tippliga-wuerzburg.de/app.php/football/bet`
- **Time**: delivery deadline datetime, Europe/Berlin timezone
+25
View File
@@ -0,0 +1,25 @@
# teamidmatcher — Team ID Mapping
Maintains a bi-directional mapping between Tippliga (phpBB) team IDs and API-Football team IDs. Uses a Guava `HashBiMap` loaded from `Team_ID_Matcher_Config.json`.
## Classes
### TeamIDMatcher
Singleton `HashBiMap<Integer, Integer>` mapping Tippliga IDs ↔ API-Football IDs.
- `getApiFootballIdFromTippligaId(id)` — Tippliga → API-Football
- `getTippligaIdFromApiFootballId(match, homeguest)` — API-Football → Tippliga, for a given match and team side
- `getTeamNameFromTippligaId(id)` — human-readable team name
Sets `StatusHolder.setError()` if a lookup fails. Used by `TLWMatch`, `TLWMatchesUpdaterFootball`, `TLWMatchesResultsUpdater`.
Config format (`Team_ID_Matcher_Config.json`):
```json
[
{ "tippligaID": 1, "teamname": "Team Name", "apiFootballID": 12345 },
...
]
```
### TeamIDMatcherTemplateCreator
Utility that fetches teams from API-Football for a given league and generates a JSON config template. Useful when setting up new seasons — outputs skeleton entries with `apiFootballID` pre-filled, `tippligaID` left blank.
+99
View File
@@ -0,0 +1,99 @@
# tippliga — Domain Models & Operations
Core domain package with match, matchday, team, and league models plus operations for creating, updating, and managing the prediction league schedule. All extend `TLWMatchesManagerBase` or `TLWMatchesCreatorBase`.
## Base Classes
### BaseMatch (`de.jeyp91.BaseMatch`)
Abstract class with shared match state: team IDs, goals (home/guest/overtime/penalty), datetime, status, KO flag, show-table flag, and a `COMPARISON` enum (`IDENTICAL`, `DIFFERENT`, `DIFFERENT_DATETIME`, `DIFFERENT_RESULT`).
Status constants:
- `STATUS_NOTSTARTED = 0`
- `STATUS_STARTED = 1`
- `STATUS_PROVISIONAL_RESULT_AVAILABLE = 2`
- `STATUS_FINISHED = 3`
- `STATUS_NOT_EVALUATED = 4`
### TLWMatchesCreatorBase
Abstract creator with `TLWMatches` list, `getSQLInsertString()` generating `REPLACE INTO` queries, `getMatchesForMatchday()`, and `getNumberOfMatchdays()`.
### TLWMatchesManagerBase
Shared helpers used by updaters:
- Date parsing from TLW (`yyyy-MM-dd HH:mm:ss`) and API-Football (`yyyy-MM-dd'T'HH:mm:ss`) formats
- `getFirstMatchtimeTLW()` / `getFirstMatchtimeAPIFootball()` — earliest match in a list
- `getDaysDifference()` — calendar day diff
- `getMatchesStartingFromSecondDay()` / `getMatchesStartingFromSecondWeek()` — filter helpers for delivery date computation
- `getMatchingMatch()` — matches an API match to a TLW match by home/guest team IDs
## Domain Models
### TLWMatch (extends BaseMatch)
Full match model mapped from `phpbb_footb_matches` table. Multiple constructors:
- From `ResultSet` (DB query)
- From `APIFootballMatch` + `TeamIDMatcher` (API sync)
- Manual constructors for creators
- Copy constructor
Key methods:
- `getSQLQueryInsert()` / `getSQLQueryReplace()` — generates SQL values
- `updateMatch(APIFootballMatch)` — updates teams, goals, datetime from API data
- `isSameMatchPlaceholder()` — matches placeholder config entries to existing matches
### TLWMatchday
Mapped from `phpbb_footb_matchdays`. Fields: season, league, matchday, status, 3 delivery dates, matchday name, match count.
### TLWTeam
Mapped from `phpbb_footb_teams`. Fields: season, league, team ID, name, short name, symbol, group ID, matchday.
### TLWLeague
Mapped from `phpbb_footb_leagues`. Fields: season, league ID, league name, short name.
## Operations
### TLWMatchesCreatorFootball
Builds match schedule from API-Football data and JSON config. For each matchday config entry:
1. Resolves API matches via `APIFootballMatchesProvider`
2. Creates `TLWMatch` objects with team IDs matched via `TeamIDMatcher`
3. Fills remaining slots with placeholder matches (empty teams)
Handles `deliveryDateMode`: in `"single"` mode, matches beyond the first day get `status = -1` to prevent early betting on later matches.
### TLWMatchesCreatorTipperLeague
Creates matches for tipper-vs-tipper leagues (where tippers are "teams"). Reads pairing config from `Tipper_Match_Pair_Config.json` and tipper-team mapping from `Tipper_Team_Config.json`.
### TLWMatchesCreatorTipperPokal
Creates single-matchday knockout tournament matches from a tipper list config. Each pair of tippers is one match with `koMatch = 1` and `showTable = false`.
### TLWMatchesUpdaterFootball
Compares current DB matches with latest API data and generates SQL UPDATE statements. Only operates on matchdays where the first match is still in the future. Updates:
- Team IDs (via `TeamIDMatcher`)
- Match datetimes
- Status flags (0 = current matchday, -1 = next-day match, -2 = later)
- `show_table` / `ko_match` flags
Also handles:
- `addMissingMatches()` — inserts API matches not yet in DB (finds placeholder slots by datetime/formula)
- `addPlaceholderMatches()` — adds config-defined placeholders for TBD matchups
### TLWMatchesResultsUpdater
For finished matches, compares DB goals with API goals and pushes updates to the website via `TippligaWebsiteConnector`. Detects changes to:
- Full-time goals
- Overtime goals (for KO matches with `betKOType = 2`)
- Penalty → overtime mapping (for `betKOType = 1` or `3`)
- Status transitions from provisional to confirmed
### TLWMatchdaysCreator
Computes delivery dates (betting deadlines) from match times. Supports two modes:
- **"single"**: one deadline = first match time
- **"multiple"** (default): 3 deadlines — first match, first match of second day, first match of second week
Also handles `additionalDeliveryDate` config flags for special matchday events.
### TLWMatchdaysUpdater
Compares original DB matchdays with recomputed deadlines and generates SQL UPDATEs and Google Calendar syncs. Only updates future matchdays (deadline in the past is skipped).
### TLWTeamsCreator
Extracts unique team IDs from a list of matches and generates `REPLACE INTO phpbb_footb_teams` SQL, preserving group and matchday info from match data.
### TLWTeamsUpdater
Detects teams referenced in matches but not yet present in the league's team table. Generates INSERT SQL to add them (copies team metadata from existing entries in other seasons/leagues).
+48
View File
@@ -0,0 +1,48 @@
# tippligaforum — MySQL & phpBB Integration
Database connector, config loader, website HTTP client, and forum post management.
## Classes
### TippligaSQLConnector
Singleton JDBC connector to the phpBB MySQL database (`d0144ddb`). Connects to production via credentials from environment variables, with a fallback to localhost.
All major queries in one class:
- `getTeams()`, `getMatches()`, `getMatchdays()`, `getLeague()` — read domain objects
- `getUpdatedMatchdaysBasedOnMatches()` — complex SQL that computes delivery deadlines from match times (uses `DATEDIFF` to split deadlines across days/weeks)
- `getNextWhatsAppReminders(hours)` — multi-table query finding users with missing bets on upcoming matchdays, joins with reminder tracking to avoid duplicates
- `updatePost()` / `getPost()` / `getChecksumOfPost()` — phpBB post CRUD
- `executeQuery()` / `executeUpdate()` — raw SQL access
- `markWhatsAppReminderAsSent()` — logs sent reminders
Post updates use the phpBB checksum mechanism: `post_checksum` = MD5 of XML-escaped post text.
### TippligaConfigProvider
Reads JSON configuration from phpBB forum posts. Configs are stored as topics under the `Admin → Tippliga-Config → <season>` forum hierarchy.
- `getTippligaConfig(config)` — fetches post, strips `[code]` BBCode wrapper, parses JSON
- `getChecksumOfConfigPost(configFile)` — reads post checksum for integrity verification
### TippligaWebsiteConnector
HTTP client that logs into the phpBB frontend + admin panel and submits match results. Used by `TLWMatchesResultsUpdater`.
Login flow:
1. GET login page → extract `creation_time`, `form_token`, `sid` from hidden fields
2. POST credentials → capture session cookies
3. GET admin panel → extract admin credential token
4. POST admin login with `password_<credential>` parameter
Result submission:
1. GET results management page → extract CSRF tokens
2. POST form with season, league, matchday, match scores (home, guest, overtime)
### MatchesListCreator
Generates a JSON match list config from raw API-Football fixture data (read from S3). Creates `SingleMatch` config entries with matchday, matchtime, team names, and fixture IDs. Used by `MatchesListForumUpdater` to create fixture list forum posts.
### MatchesListForumUpdater
For each league:
1. Creates `MatchesListCreator` from S3 fixture data
2. Formats as pretty-printed JSON
3. Wraps in `[code]` BBCode
4. Finds the correct forum post (under `Admin → Tippliga-Config → <season> → Ligen → <country> <league>`)
5. Updates the post text via `TippligaSQLConnector`
+40
View File
@@ -0,0 +1,40 @@
# whatsapp — WhatsApp Reminder System
Sends personalized WhatsApp reminders to users who haven't submitted their bets before the deadline. Uses OpenAI GPT-3.5 to generate natural-language reminder messages.
## Classes
### WhatsAppNotifier
Orchestrates the reminder workflow:
1. Queries DB for upcoming reminders at 2 checkpoints: **24 hours** and **2 hours** before deadline
2. For each reminder, generates a message via `OpenAIConnector`
3. Sends via WhatsApp API (HTTP POST to configurable host:port)
4. Marks sent reminders in DB to avoid duplicates
Requires env vars: `TLW_WHATSAPP_HOST`, `TLW_WHATSAPP_PORT`, `TLW_WHATSAPP_API_KEY`.
### OpenAIConnector
Caches and generates reminder text via OpenAI Chat Completions API (model `gpt-3.5-turbo-0125`).
Prompt structure:
- **System prompt** (German): "Generate a message reminding someone to submit missing tips. Must sound like a friend. Use correct singular/plural."
- **User input**: JSON with league name, matchday name, delivery day, time
- **Output template** has 2 variants — 24h deadline uses a friendly intro, 2h deadline emphasizes urgency
Message format:
```
Hey <username>,
<AI-generated intro>
Bitte gib die fehlenden Tipps bis <today/morgen> um <HH:MM> ab.
Du kannst deine Tipps wie immer unter https://tippliga-wuerzburg.de/app.php/football/bet abgeben.
Viele Grüße
Die Tippliga Admins
```
Messages are cached per (league + matchday + delivery) key to avoid repeated API calls.
### WhatsAppReminder
Java `record` with fields: season, league, leagueName, matchday, matchdayName, deliveryDate, todayTomorrow, time, remainingHours, userId, username, phoneNumber, missingBets.
Maps directly to the SQL query result from `TippligaSQLConnector.getNextWhatsAppReminders()`.