POTE/scripts/fetch_congress_members.py
ilia 0d8d85adc1 Add complete automation, reporting, and CI/CD system
Features Added:
==============

📧 EMAIL REPORTING SYSTEM:
- EmailReporter: Send reports via SMTP (Gmail, SendGrid, custom)
- ReportGenerator: Generate daily/weekly summaries with HTML/text formatting
- Configurable via .env (SMTP_HOST, SMTP_PORT, etc.)
- Scripts: send_daily_report.py, send_weekly_report.py

🤖 AUTOMATED RUNS:
- automated_daily_run.sh: Full daily ETL pipeline + reporting
- automated_weekly_run.sh: Weekly pattern analysis + reports
- setup_cron.sh: Interactive cron job setup (5-minute setup)
- Logs saved to ~/logs/ with automatic cleanup

🔍 HEALTH CHECKS:
- health_check.py: System health monitoring
- Checks: DB connection, data freshness, counts, recent alerts
- JSON output for programmatic use
- Exit codes for monitoring integration

🚀 CI/CD PIPELINE:
- .github/workflows/ci.yml: Full CI/CD pipeline
- GitHub Actions / Gitea Actions compatible
- Jobs: lint & test, security scan, dependency scan, Docker build
- PostgreSQL service for integration tests
- 93 tests passing in CI

📚 COMPREHENSIVE DOCUMENTATION:
- AUTOMATION_QUICKSTART.md: 5-minute email setup guide
- docs/12_automation_and_reporting.md: Full automation guide
- Updated README.md with automation links
- Deployment → Production workflow guide

🛠️ IMPROVEMENTS:
- All shell scripts made executable
- Environment variable examples in .env.example
- Report logs saved with timestamps
- 30-day log retention with auto-cleanup
- Health checks can be scheduled via cron

WHAT THIS ENABLES:
==================
After deployment, users can:
1. Set up automated daily/weekly email reports (5 min)
2. Receive HTML+text emails with:
   - New trades, market alerts, suspicious timing
   - Weekly patterns, rankings, repeat offenders
3. Monitor system health automatically
4. Run full CI/CD pipeline on every commit
5. Deploy with confidence (tests + security scans)

USAGE:
======
# One-time setup (on deployed server)
./scripts/setup_cron.sh

# Or manually send reports
python scripts/send_daily_report.py --to user@example.com
python scripts/send_weekly_report.py --to user@example.com

# Check system health
python scripts/health_check.py

See AUTOMATION_QUICKSTART.md for full instructions.

93 tests passing | Full CI/CD | Email reports ready
2025-12-15 15:34:31 -05:00

181 lines
7.9 KiB
Python
Executable File

#!/usr/bin/env python
"""
Fetch current members of Congress.
Creates a watchlist of active members.
"""
import json
import requests
from pathlib import Path
# Congress.gov API (no key required for basic info)
# or ProPublica Congress API (requires free key)
def fetch_from_propublica():
"""
Fetch from ProPublica Congress API.
Free API key: https://www.propublica.org/datastore/api/propublica-congress-api
"""
API_KEY = "YOUR_API_KEY" # Get free key from ProPublica
headers = {"X-API-Key": API_KEY}
# Get current Congress (118th = 2023-2025, 119th = 2025-2027)
members = []
# Senate
senate_url = "https://api.propublica.org/congress/v1/118/senate/members.json"
response = requests.get(senate_url, headers=headers)
if response.ok:
data = response.json()
for member in data['results'][0]['members']:
members.append({
'name': f"{member['first_name']} {member['last_name']}",
'chamber': 'Senate',
'party': member['party'],
'state': member['state'],
})
# House
house_url = "https://api.propublica.org/congress/v1/118/house/members.json"
response = requests.get(house_url, headers=headers)
if response.ok:
data = response.json()
for member in data['results'][0]['members']:
members.append({
'name': f"{member['first_name']} {member['last_name']}",
'chamber': 'House',
'party': member['party'],
'state': member['state'],
})
return members
def get_known_active_traders():
"""
Manually curated list of Congress members known for active trading.
Based on public reporting and analysis.
"""
return [
# === SENATE ===
{"name": "Tommy Tuberville", "chamber": "Senate", "party": "Republican", "state": "AL"},
{"name": "Rand Paul", "chamber": "Senate", "party": "Republican", "state": "KY"},
{"name": "Sheldon Whitehouse", "chamber": "Senate", "party": "Democrat", "state": "RI"},
{"name": "John Hickenlooper", "chamber": "Senate", "party": "Democrat", "state": "CO"},
{"name": "Steve Daines", "chamber": "Senate", "party": "Republican", "state": "MT"},
{"name": "Gary Peters", "chamber": "Senate", "party": "Democrat", "state": "MI"},
{"name": "Rick Scott", "chamber": "Senate", "party": "Republican", "state": "FL"},
{"name": "Mark Warner", "chamber": "Senate", "party": "Democrat", "state": "VA"},
{"name": "Dianne Feinstein", "chamber": "Senate", "party": "Democrat", "state": "CA"}, # Note: deceased
# === HOUSE ===
{"name": "Nancy Pelosi", "chamber": "House", "party": "Democrat", "state": "CA"},
{"name": "Brian Higgins", "chamber": "House", "party": "Democrat", "state": "NY"},
{"name": "Michael McCaul", "chamber": "House", "party": "Republican", "state": "TX"},
{"name": "Dan Crenshaw", "chamber": "House", "party": "Republican", "state": "TX"},
{"name": "Marjorie Taylor Greene", "chamber": "House", "party": "Republican", "state": "GA"},
{"name": "Josh Gottheimer", "chamber": "House", "party": "Democrat", "state": "NJ"},
{"name": "Ro Khanna", "chamber": "House", "party": "Democrat", "state": "CA"},
{"name": "Dean Phillips", "chamber": "House", "party": "Democrat", "state": "MN"},
{"name": "Virginia Foxx", "chamber": "House", "party": "Republican", "state": "NC"},
{"name": "Debbie Wasserman Schultz", "chamber": "House", "party": "Democrat", "state": "FL"},
{"name": "Pat Fallon", "chamber": "House", "party": "Republican", "state": "TX"},
{"name": "Kevin Hern", "chamber": "House", "party": "Republican", "state": "OK"},
{"name": "Mark Green", "chamber": "House", "party": "Republican", "state": "TN"},
{"name": "French Hill", "chamber": "House", "party": "Republican", "state": "AR"},
{"name": "John Curtis", "chamber": "House", "party": "Republican", "state": "UT"},
# === HIGH VOLUME TRADERS (Based on 2023-2024 reporting) ===
{"name": "Austin Scott", "chamber": "House", "party": "Republican", "state": "GA"},
{"name": "Nicole Malliotakis", "chamber": "House", "party": "Republican", "state": "NY"},
{"name": "Lois Frankel", "chamber": "House", "party": "Democrat", "state": "FL"},
{"name": "Earl Blumenauer", "chamber": "House", "party": "Democrat", "state": "OR"},
{"name": "Pete Sessions", "chamber": "House", "party": "Republican", "state": "TX"},
]
def save_watchlist(members, filename="watchlist.json"):
"""Save watchlist to file."""
output_path = Path(__file__).parent.parent / "config" / filename
output_path.parent.mkdir(exist_ok=True)
with open(output_path, 'w') as f:
json.dump(members, f, indent=2)
print(f"✅ Saved {len(members)} members to {output_path}")
return output_path
def load_watchlist(filename="watchlist.json"):
"""Load watchlist from file."""
config_path = Path(__file__).parent.parent / "config" / filename
if not config_path.exists():
print(f"⚠️ Watchlist not found at {config_path}")
print(" Creating default watchlist...")
members = get_known_active_traders()
save_watchlist(members, filename)
return members
with open(config_path) as f:
return json.load(f)
if __name__ == "__main__":
import argparse
parser = argparse.ArgumentParser(description="Manage Congress member watchlist")
parser.add_argument("--create", action="store_true", help="Create default watchlist")
parser.add_argument("--list", action="store_true", help="List current watchlist")
parser.add_argument("--propublica", action="store_true", help="Fetch from ProPublica API")
args = parser.parse_args()
if args.propublica:
print("Fetching from ProPublica API...")
print("⚠️ You need to set API_KEY in the script first")
print(" Get free key: https://www.propublica.org/datastore/api/propublica-congress-api")
# members = fetch_from_propublica()
# save_watchlist(members)
elif args.create:
members = get_known_active_traders()
save_watchlist(members, "watchlist.json")
print(f"\n✅ Created watchlist with {len(members)} active traders")
elif args.list:
members = load_watchlist()
print(f"\n📋 Watchlist ({len(members)} members):\n")
# Group by chamber
senate = [m for m in members if m['chamber'] == 'Senate']
house = [m for m in members if m['chamber'] == 'House']
print("SENATE:")
for m in sorted(senate, key=lambda x: x['name']):
print(f"{m['name']:30s} ({m['party']:1s}-{m['state']})")
print("\nHOUSE:")
for m in sorted(house, key=lambda x: x['name']):
print(f"{m['name']:30s} ({m['party']:1s}-{m['state']})")
else:
# Default: show known active traders
members = get_known_active_traders()
print(f"\n📋 Known Active Traders ({len(members)} members):\n")
print("These are Congress members with historically high trading activity.\n")
senate = [m for m in members if m['chamber'] == 'Senate']
house = [m for m in members if m['chamber'] == 'House']
print("SENATE:")
for m in sorted(senate, key=lambda x: x['name']):
print(f"{m['name']:30s} ({m['party']:1s}-{m['state']})")
print("\nHOUSE:")
for m in sorted(house, key=lambda x: x['name']):
print(f"{m['name']:30s} ({m['party']:1s}-{m['state']})")
print("\n💡 To create watchlist file: python scripts/fetch_congress_members.py --create")
print("💡 To view saved watchlist: python scripts/fetch_congress_members.py --list")