major-domo-database/.claude/sqlite-to-postgres/player-to-sbaplayer-matching/post_new_sbaplayers.py
Cal Corum 7130a1fd43 Postgres Migration
Migration documentation and scripts
2025-08-25 07:18:31 -05:00

192 lines
6.8 KiB
Python

#!/usr/bin/env python3
"""
Post new SbaPlayer records to production API
"""
import csv
import json
import requests
import logging
import os
import argparse
from typing import Dict, List, Optional
# Set up logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
handlers=[
logging.FileHandler('matching.log'),
logging.StreamHandler()
]
)
logger = logging.getLogger(f'{__name__}.post_new_sbaplayers')
# Production API configuration
API_BASE_URL = "https://api.sba.manticorum.com"
SBAPLAYERS_ENDPOINT = f"{API_BASE_URL}/sbaplayers"
def get_api_token(token_arg=None):
"""Get API token from argument, environment, or prompt user"""
if token_arg:
return token_arg
api_token = os.getenv('API_TOKEN')
if not api_token:
print("API_TOKEN environment variable not found.")
api_token = input("Please enter your API token: ").strip()
return api_token
def load_new_sbaplayers():
"""Load new SbaPlayer records from CSV file"""
new_players = []
logger.info("Loading new SbaPlayers from new_sbaplayers_to_insert.csv...")
with open('./new_sbaplayers_to_insert.csv', 'r') as f:
reader = csv.DictReader(f)
for row in reader:
# Convert CSV row to API format
player = {
"first_name": row['first_name'],
"last_name": row['last_name'],
"key_bbref": row['key_bbref'] if row['key_bbref'] else None,
"key_fangraphs": None, # We don't have fangraphs IDs
"key_mlbam": None, # We don't have MLBAM IDs
"key_retro": None # We don't have retro IDs
}
new_players.append(player)
logger.info(f"Loaded {len(new_players)} new SbaPlayer records")
return new_players
def post_sbaplayers_bulk(players: List[Dict], api_token: str) -> bool:
"""Post multiple SbaPlayers via bulk endpoint"""
payload = {
"players": players
}
headers = {
"Authorization": f"Bearer {api_token}",
"Content-Type": "application/json"
}
logger.info(f"Posting {len(players)} new SbaPlayers to {SBAPLAYERS_ENDPOINT}...")
try:
response = requests.post(SBAPLAYERS_ENDPOINT, json=payload, headers=headers, timeout=30)
if response.status_code == 200:
logger.info(f"✅ SUCCESS: {response.text}")
return True
else:
logger.error(f"❌ API Error {response.status_code}: {response.text}")
return False
except requests.exceptions.RequestException as e:
logger.error(f"❌ Request failed: {e}")
return False
def verify_posted_players(players: List[Dict], api_token: str):
"""Verify that the posted players exist in the database"""
headers = {
"Authorization": f"Bearer {api_token}",
"Content-Type": "application/json"
}
logger.info("Verifying posted players...")
for player in players:
full_name = f"{player['first_name']} {player['last_name']}"
# Search by full name
params = {"full_name": [full_name]}
try:
response = requests.get(SBAPLAYERS_ENDPOINT, params=params, headers=headers, timeout=10)
if response.status_code == 200:
data = response.json()
if data['count'] > 0:
sba_player = data['players'][0]
logger.info(f"✅ Verified: {full_name} -> SbaPlayer ID {sba_player['id']}")
else:
logger.warning(f"⚠️ Not found: {full_name}")
else:
logger.error(f"❌ Verification failed for {full_name}: {response.status_code}")
except requests.exceptions.RequestException as e:
logger.error(f"❌ Verification request failed for {full_name}: {e}")
def main():
"""Main execution function"""
parser = argparse.ArgumentParser(description='Post new SbaPlayer records to production API')
parser.add_argument('--token', help='API token for authentication')
parser.add_argument('--confirm', action='store_true', help='Skip confirmation prompt')
parser.add_argument('--dry-run', action='store_true', help='Show what would be posted without actually posting')
args = parser.parse_args()
logger.info("Starting SbaPlayer creation process...")
try:
# Load new players
new_players = load_new_sbaplayers()
if not new_players:
logger.warning("No new players to post. Exiting.")
return
# Show preview
print(f"\n📋 PREVIEW: About to create {len(new_players)} new SbaPlayer records:")
for i, player in enumerate(new_players, 1):
bbref_info = f" (bbref: {player['key_bbref']})" if player['key_bbref'] else ""
print(f" {i:2d}. {player['first_name']} {player['last_name']}{bbref_info}")
if args.dry_run:
print(f"\n🧪 DRY RUN: Would create {len(new_players)} new SbaPlayer records")
print("JSON payload preview:")
print(json.dumps({"players": new_players[:3]}, indent=2))
if len(new_players) > 3:
print(f"... and {len(new_players) - 3} more players")
return
# Get API token (only needed for actual posting)
api_token = get_api_token(args.token)
if not api_token:
logger.error("No API token provided. Exiting.")
return
# Confirm with user (unless --confirm flag is used)
if not args.confirm:
print(f"\n🚨 WARNING: This will create {len(new_players)} new records in the PRODUCTION database!")
confirm = input("Are you sure you want to proceed? (yes/no): ").strip().lower()
if confirm not in ['yes', 'y']:
logger.info("User cancelled. No records created.")
return
# Bulk insert
logger.info("Posting via bulk endpoint...")
success = post_sbaplayers_bulk(new_players, api_token)
if success:
logger.info("✅ Bulk insert completed successfully!")
# Verify the results
print(f"\n🔍 Verifying created players...")
verify_posted_players(new_players, api_token)
else:
logger.error("❌ Bulk insert failed. Check the error messages above.")
logger.info("✅ SbaPlayer creation process completed!")
print(f"\n🎉 Process completed! Check the logs above for results.")
except Exception as e:
logger.error(f"Unexpected error: {e}")
raise
if __name__ == "__main__":
main()