#!/bin/bash source "$(dirname "$0")/entrypoint.sh" 2>/dev/null || true # Master orchestration script for LWVWV member subscription automation # This script coordinates the entire workflow: # 1. Download roster from LWVWV portal (if download-roster.js is available) # 2. Convert roster to CSV format, filtered by League ID per list # 3. Subscribe members to Mailman list(s) via connector API # 4. Cleanup temporary files # # Environment Variables (loaded from /app/env via entrypoint.sh): # CONNECTOR_URL - URL of mailman-connector # CONNECTOR_PASSWORD - Secret password for connector API # MAILMAN_LIST_ID - Target mailing list ID(s). Format: "list_id:league_id, list_id:league_id" # If :league_id is omitted, defaults to "ALL" (all members) # EMAIL_TO - Email for failure notifications # SMTP_HOST - SMTP server for notifications # # Examples: # Single list, all members: "members.lists.lwvwv.org" # Single list, WV000 only: "members.lists.lwvwv.org:WV000" # Multiple lists: "members.lists.lwvwv.org:WV000, morgantown.lists.lwvwv.org:WV103" set -e # Exit on error # Configuration from environment WORK_DIR="${WORK_DIR:-/tmp/rosters}" TIMESTAMP=$(date +%Y%m%d_%H%M%S) ROSTER_FILE="$WORK_DIR/roster_$TIMESTAMP.csv" log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" } error_exit() { echo "[ERROR] $1" >&2 # Send alert email if configured if [ -n "$EMAIL_TO" ] && [ -n "$SMTP_HOST" ]; then echo "$1" | s-nail -s "LWVWV Subscription Failed" "$EMAIL_TO" 2>/dev/null || true fi exit 1 } # Create work directory mkdir -p "$WORK_DIR" # Determine CSV input source or download if [ -n "$1" ]; then # CSV file provided as argument ROSTER_FILE="$1" log "Using provided roster file: $ROSTER_FILE" if [ ! -f "$ROSTER_FILE" ]; then error_exit "Roster file not found: $ROSTER_FILE" fi else # No CSV provided - try to download from portal if [ ! -f "./download-roster.js" ]; then error_exit "No CSV file provided and download-roster.js not found" fi # Step 1: Download roster log "Downloading roster from LWVWV portal..." if ! node download-roster.js; then error_exit "Failed to download roster" fi # Find the downloaded file ROSTER_FILE=$(ls -t league_membership_state_view_*.csv 2>/dev/null | head -1) if [ -z "$ROSTER_FILE" ]; then error_exit "No roster file found after download" fi log "Downloaded roster: $ROSTER_FILE" fi # Validate required environment variables if [ -z "$CONNECTOR_URL" ]; then error_exit "CONNECTOR_URL not set. Ensure /app/env is mounted and contains \$CONNECTOR_URL" fi if [ -z "$CONNECTOR_PASSWORD" ]; then error_exit "CONNECTOR_PASSWORD not set. Ensure /app/env is mounted and contains \$CONNECTOR_PASSWORD" fi if [ -z "$MAILMAN_LIST_ID" ]; then error_exit "MAILMAN_LIST_ID not set. Ensure /app/env is mounted and contains \$MAILMAN_LIST_ID" fi if [ ! -f "./google-civic-api.pl" ]; then error_exit "google-civic-api.pl not found for roster conversion" fi if [ ! -f "./subscribe-members.sh" ]; then error_exit "subscribe-members.sh not found" fi # Parse multiple list configurations (comma-separated) # Format: list_id:league_id or just list_id (defaults to ALL) IFS=',' read -ra LIST_CONFIGS <<< "$MAILMAN_LIST_ID" log "==========================================" log "Starting batch subscription" log "==========================================" log "Roster File: $ROSTER_FILE" log "Connector URL: $CONNECTOR_URL" log "Total Lists: ${#LIST_CONFIGS[@]}" log "==========================================" # Track success/failure per list SUCCESS_COUNT=0 FAILED_LISTS=() # Helper function to increment counter (avoids set -e issues with arithmetic) increment_count() { SUCCESS_COUNT=$((SUCCESS_COUNT + 1)) } # Loop through each list configuration for CONFIG in "${LIST_CONFIGS[@]}"; do # Trim whitespace CONFIG=$(echo "$CONFIG" | xargs) # Parse list_id and league_id (format: list_id:league_id or just list_id) if [[ "$CONFIG" =~ ^([^:]+):(.*)$ ]]; then LIST_ID="${BASH_REMATCH[1]}" LEAGUE_ID="${BASH_REMATCH[2]}" else LIST_ID="$CONFIG" LEAGUE_ID="ALL" fi log "" log "----------------------------------------" log "Processing List: $LIST_ID" log "League Filter: $LEAGUE_ID" log "----------------------------------------" # Generate filtered CSV for this list FILTERED_CSV="$WORK_DIR/members_${LEAGUE_ID}_${TIMESTAMP}.csv" log "Filtering roster for League ID: $LEAGUE_ID..." if ! ./google-civic-api.pl "$LEAGUE_ID" "$ROSTER_FILE" email-csv > "$FILTERED_CSV" 2>/dev/null; then log "✗ Failed to filter roster for $LEAGUE_ID" FAILED_LISTS+=("$LIST_ID") rm -f "$FILTERED_CSV" continue fi # Check if any members were found MEMBER_COUNT=$(wc -l < "$FILTERED_CSV" | tr -d ' ') log "Found $MEMBER_COUNT members for $LEAGUE_ID" if [ "$MEMBER_COUNT" -eq 0 ]; then log "⚠ No members found for League ID $LEAGUE_ID, skipping $LIST_ID" rm -f "$FILTERED_CSV" continue fi # Subscribe members to this list log "Subscribing $MEMBER_COUNT members to $LIST_ID..." if ./subscribe-members.sh "$FILTERED_CSV" "$CONNECTOR_PASSWORD" "$LIST_ID" "$CONNECTOR_URL"; then log "✓ Successfully subscribed to $LIST_ID" increment_count # Clean up filtered CSV on success rm -f "$FILTERED_CSV" else log "✗ Failed to subscribe to $LIST_ID" FAILED_LISTS+=("$LIST_ID") # Keep filtered CSV for debugging on failure log " Filtered CSV retained: $FILTERED_CSV" fi done # Summary log "" log "==========================================" log "Subscription Summary" log "==========================================" log "Total Lists: ${#LIST_CONFIGS[@]}" log "Successful: $SUCCESS_COUNT" log "Failed: ${#FAILED_LISTS[@]}" log "==========================================" # Cleanup original roster if we downloaded it if [ -z "$1" ] && [ -f "$ROSTER_FILE" ]; then log "Cleaning up roster file..." rm -f "$ROSTER_FILE" fi # If any lists failed, report error if [ ${#FAILED_LISTS[@]} -gt 0 ]; then error_exit "Failed to subscribe to the following list(s): ${FAILED_LISTS[*]}" fi log "Subscription process completed successfully" exit 0