Add clickable link field to weather embed as fallback for Discord
caching issues. Users can click the link to view the stadium image
in their browser if the embedded image fails to render.
Changes:
- Added "Stadium Image" field with direct link to team.stadium
- Bump version to 2.29.7
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Fix /injury roll and /injury clear commands crashing when player.team is None
- Add team fetching logic after search_players() for all injury commands
- The search_players() API endpoint returns team as ID only (not nested object)
- Added null checks and explicit team fetching using team_service.get_team()
- Add Gitea Actions workflow for automated Docker builds
- Implements semantic version validation on PRs
- Builds and pushes to Docker Hub on main branch merges
- Sends Discord notifications on success/failure
- Generates 3 image tags: latest, v{VERSION}, v{VERSION}-{COMMIT}
Fixes AttributeError: 'NoneType' object has no attribute 'roster_type'
Fixes AttributeError: 'NoneType' object has no attribute 'thumbnail'
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
The search_players() API endpoint returns team as an ID only (not nested object),
causing player.team to be None. Added null check before accessing team.thumbnail.
Fixes AttributeError: 'NoneType' object has no attribute 'thumbnail'
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Prevents double emoji display by clearing the "✅ Confirmed!" content
when showing the delete result embed.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Changed from command.creator_id (database ID) to command.creator.discord_id
to properly compare against the deleter's Discord user ID.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The setup_profile_commands() function was returning None instead of the
expected (successful, failed, failed_modules) tuple, causing bot startup
to log "Failed to load profile package: cannot unpack non-iterable NoneType".
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Root cause: league_service.update_current_state() was calling self.patch()
without use_query_params=True. The API expected query params but received
JSON body, so database updates for week/freeze silently failed.
Changes:
- Add use_query_params=True to league_service.py:99
- Fix service layer violation in transaction_freeze.py - now uses
player_service.update_player_team() instead of direct API client
- Bump version to 2.25.8
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add sWAR cap validation to TransactionBuilder.validate_transaction()
- Use team-specific salary_cap from Team.salary_cap field
- Fall back to config.swar_cap_limit (32.0) if team has no custom cap
- Add major_league_swar_cap field to RosterValidationResult
- Update major_league_swar_status to show ✅/❌ with cap limit
- Add 4 new tests for sWAR cap validation
This fixes a bug where IL moves could put a team over their sWAR cap
because the validation only checked roster counts, not sWAR limits.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Changed /injury roll, /injury set-new, and /injury clear to use
search_players() instead of get_players_by_name(). The /players?name=
API endpoint fails to find some players (e.g., Gunnar Henderson) while
the /players/search?q= endpoint works correctly.
This fixes the "Player Not Found" error when users try to clear
injuries for players that exist in the database.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Release includes:
- Add pending transaction validation for /dropadd command
- Players already in a pending transaction cannot be added to another
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Security fix: Remove user_id from ConfirmationView so only the player's
team GM(s) can click "Log Injury" button. Anyone can still run /injury roll
to see the result, but only authorized GMs can record it.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Features:
- Post injury announcements to #sba-network-news when injuries are logged
- Update #injury-log channel with two embeds:
- All injuries grouped by Major League team with return dates
- All injuries grouped by return week, sorted ascending
- Auto-purge old messages before posting updated injury log
Bug Fixes:
- Fix BaseView interaction_check logic that incorrectly rejected command users
- Old: Rejected if (not user_id match) OR (not in responders)
- New: Allow if (user_id match) OR (in responders)
- Filter None values from responders list (handles missing gmid2)
Changes:
- services/injury_service.py: Add get_all_active_injuries_raw() method
- utils/injury_log.py: New utility for injury channel posting
- views/modals.py: Call injury posting after successful injury logging
- views/base.py: Fix interaction authorization logic
- config.py: Update to Season 13 Players role
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
IL moves (/ilmove) are intra-team transactions that should always be
visible immediately. Only scheduled transactions (/dropadd) need to
remain hidden during the freeze period.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Bug: Transactions were being posted to #transaction-log even when Current.freeze=True.
Transactions should only be posted when Current.freeze=False.
Fix: Added freeze state checks before calling post_transaction_to_log() in both
scheduled (/dropadd) and immediate (/ilmove) submission handlers.
When frozen:
- Transactions are still saved to DB with frozen=True
- NOT posted to #transaction-log (hidden until Saturday processing)
- User sees "Transaction saved during freeze period" message
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
During the draft, teams draft 32 players and then drop to 26. The cap
calculation must account for remaining draft picks:
- max_zeroes = 32 - projected_roster_size (remaining draft picks)
- players_counted = 26 - max_zeroes (how many current players count)
This allows teams to draft expensive players mid-draft knowing they'll
drop cheap ones later. Previously the code was using min(roster_size, 26)
which didn't account for future picks, causing false cap violations.
Example: WAI with 18 players drafting 19th:
- Old (broken): players_counted = 19, sum all players
- New (fixed): max_zeroes = 13, players_counted = 13, only cheapest 13 count
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
The get_recent_picks service method was subtracting 1 from overall_end,
but callers were already passing currentpick - 1. This caused the "Last 5
picks" list on the OnTheClock embed to skip the most recently completed
pick (showing picks 2-6 before current instead of 1-5).
Removed the extra subtraction in the service method since callers already
handle the exclusivity of the overall_end parameter.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
The manual /draft command was only posting draft cards to the ping_channel,
but not to the result_channel. The auto-draft task correctly posted to both
channels. This fix ensures manual draft picks also post player cards to the
configured result channel for consistent draft result tracking.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
When users select from autocomplete dropdown, Discord sometimes sends
the display text (e.g., "Mason Miller (RP) - 2.50 sWAR") instead of
the value ("Mason Miller"). Added _parse_player_name() to strip the
position and sWAR info from the input.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Previously, only the draft monitor task posted on-clock announcements
when auto-drafting. Now the /draft command also posts an on-clock
announcement with team role ping after each pick advances.
Changes:
- Added _post_on_clock_announcement method to DraftPicksCog
- Called after advance_pick() in _process_draft_pick
- Posts embed with team info, sWAR, recent picks, and role ping
- Imports roster_service and get_team_salary_cap for sWAR calculation
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Bug: The _post_on_clock_announcement method referenced 'guild' without
defining it, causing the role ping to silently fail when posting
on-clock announcements after auto-draft picks.
Fix: Added guild lookup from bot.get_guild(config.guild_id) at the
start of the method.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Changed write_picks_batch() from 105 individual API calls to 1 batch call
- Builds 2D array covering full pick range and writes in single update_values()
- Eliminates Google Sheets 429 rate limiting during resync operations
- Reduces resync time from ~2 minutes to seconds
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Features:
- Skipped pick support: Teams can make up missed picks
- Google Sheets integration: Auto-sync picks to shared sheet
- Draft pause/resume: Admins can pause/resume draft with timer control
- Auto-draft improvements: Auto-start monitor, post picks to result channel
- Sheet links in draft embeds: Quick access to draft board
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Fix DraftPickService to send full model body on PATCH (API requirement)
- Fix DraftListService to use client-side sorting (API doesn't support sort param)
- Fix parameter names: round_start/end -> pick_round_start/end
- Add 53 tests covering DraftService, DraftPickService, DraftListService
- Add draft model tests for DraftData, DraftPick, DraftList
- Add OpenAPI spec URL to CLAUDE.md for API reference
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add multi-team trade acceptance system requiring all GMs to approve
- TradeBuilder tracks accepted_teams with accept_trade/reject_trade methods
- TradeAcceptanceView with Accept/Reject buttons validates GM permissions
- Create transactions when all teams accept (frozen=false for immediate effect)
- Add post_trade_to_log() for rich trade embeds in #transaction-log
- Trade embeds show grouped player moves by receiving team with sWAR
- Add 10 comprehensive tests for acceptance tracking methods
- All 36 trade builder tests pass
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Remove redundant sba_current_season and pd_current_season config values.
All code now uses sba_season and pd_season, which properly read from
environment variables. Fixes /team command defaulting to Season 12.
- Remove duplicate *_current_season constants from config.py
- Update 100+ references across commands, services, and utils
- sba_season defaults to 13, pd_season defaults to 10
- Environment variables SBA_SEASON/PD_SEASON now work correctly
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Implemented comprehensive team branding management system allowing team owners
to update colors and logos for major league, minor league, and dice rolls.
Features:
- Modal-based interactive form input with validation
- Hex color validation with normalization (6 chars, optional # prefix)
- Image URL accessibility testing with aiohttp (5 second timeout)
- Preview + confirmation workflow with ConfirmationView
- Support for both major league and minor league affiliate updates
- Dice color customization for game rolls
- Discord role color sync (non-blocking with graceful fallback)
- Comprehensive error handling and user feedback
Technical Implementation:
- BrandingModal class with 5 optional fields
- Concurrent URL validation using asyncio.gather
- Fixed team_service.update_team() to use PATCH with query parameters
- Enhanced TeamService documentation with correct method signatures
- 33 comprehensive tests (100% passing)
Bug Fixes:
- Fixed modal send timing (immediate response vs deferred)
- Fixed interaction handling for cancel button
- Fixed database API communication (PATCH query params vs PUT JSON)
Files:
- commands/teams/branding.py (NEW - ~500 lines)
- commands/teams/__init__.py (added BrandingCommands registration)
- commands/teams/CLAUDE.md (added comprehensive documentation)
- tests/test_commands_teams_branding.py (NEW - 33 tests)
- services/team_service.py (fixed update_team to use query params)
- VERSION (2.19.2 → 2.20.0)
Docker: manticorum67/major-domo-discord-app-v2:2.20.0
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Corrected API endpoint paths from 'custom_command_creators' to 'custom_commands/creators' to match the database API routing structure.
**Issue**: Users unable to create custom commands due to 404 errors
**Root Cause**: Bot calling /api/v3/custom_command_creators instead of /api/v3/custom_commands/creators
**Solution**: Updated 5 endpoint references in custom_commands_service.py
Fixes:
- Line 547: create_item_in_table() call
- Lines 732, 748: client.put() calls for creator updates
- Lines 762, 768: get_items_from_table_with_params() calls for creator queries
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Initial version: 2.19.1
This file tracks the current version for Docker builds. When building
and pushing new versions, this file will be updated and the commit
will be tagged with the version number.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>