ferrero-opentext/Python-Version/scripts/a4_webhook_monitor.py
DJP 0d69c2b37f Update A4 webhook monitor to process all campaigns at once
- Changed from single-campaign mode to process all A4 campaigns in one run
- Added summary statistics (total found, webhooks sent, already processed, failed)
- Since webhooks are lightweight operations, processing all at once is efficient
- Duplicate prevention still works via database tracking

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-05 17:34:24 -05:00

251 lines
8.3 KiB
Python
Executable file

#!/usr/bin/env python3
"""
A4 Webhook Monitor
Monitors campaigns with status A4 and sends webhook notification
A4 status indicates campaign is not going live
Sends webhook with "Live Campaign": "NO"
Compatible with Python 3.6+
"""
import sys
import os
import time
import logging
import argparse
# Add shared library to path
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))
from shared.config_loader import load_config
from shared.dam_client import DAMClient
from shared.database import Database
from shared.notifier import Notifier
# Setup logging with rotation
from logging.handlers import RotatingFileHandler
# Create logs directory if it doesn't exist
os.makedirs('logs', exist_ok=True)
os.makedirs('logs/backup', exist_ok=True)
# Configure logging with rotation
log_handler = RotatingFileHandler(
'logs/a4_webhook.log',
maxBytes=10*1024*1024, # 10MB per file
backupCount=28 # Keep 28 rotated files (approximately 1 month)
)
log_handler.setLevel(logging.INFO)
log_handler.setFormatter(logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s'))
console_handler = logging.StreamHandler()
console_handler.setLevel(logging.INFO)
console_handler.setFormatter(logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s'))
logging.basicConfig(
level=logging.INFO,
handlers=[log_handler, console_handler]
)
logger = logging.getLogger('A4Webhook')
def process_campaign(campaign, dam, db, notifier, config):
"""
Process A4 campaign - send webhook notification
Returns:
dict with success boolean
"""
campaign_id = campaign['asset_id']
campaign_name = campaign['campaign_name']
campaign_number = campaign.get('campaign_id') or 'UNKNOWN'
logger.info("=" * 60)
logger.info("Processing A4 campaign: {} ({})".format(campaign_name, campaign_number))
logger.info("=" * 60)
try:
# Check if campaign already processed
campaign_check = db.check_campaign_processed(campaign_id)
if campaign_check['exists'] and campaign_check['webhook_sent']:
logger.info("Campaign already processed - webhook already sent")
logger.info(" Sent at: {}".format(campaign_check['webhook_sent_at']))
logger.info(" Status: {}".format(campaign_check['status']))
logger.info(" Live Campaign: {}".format(campaign_check['live_campaign']))
logger.info("Skipping to avoid duplicate webhook")
return {'success': True, 'webhook_sent': False, 'already_processed': True}
# Check if webhook is enabled
if not config['webhooks']['campaign_status_update']['enabled']:
logger.info("Webhook disabled in config - skipping")
return {'success': True, 'webhook_sent': False}
webhook_url = config['webhooks']['campaign_status_update']['url']
# Build webhook payload
payload = {
'campaign_id': campaign_id,
'campaign_number': campaign_number,
'campaign_name': campaign_name,
'status': 'A4',
'live_campaign': 'NO', # A4 = Not going live
'timestamp': int(time.time()),
'message': 'Campaign marked A4 - Not going live'
}
logger.info("Sending webhook for A4 campaign...")
logger.info(" Campaign: {} ({})".format(campaign_name, campaign_number))
logger.info(" Status: A4")
logger.info(" Live Campaign: NO")
logger.info(" Webhook URL: {}".format(webhook_url))
# Send webhook
webhook_result = notifier.send_webhook(
url=webhook_url,
payload=payload
)
if webhook_result:
logger.info("✓ Webhook sent successfully")
# Record campaign status in database (prevents duplicate webhooks)
logger.info("Recording campaign status in database...")
db.record_campaign_status(
campaign_id=campaign_id,
campaign_number=campaign_number,
campaign_name=campaign_name,
live_campaign='NO', # A4 campaigns are NOT going live
status='A4',
webhook_sent=True
)
# Send email notification
notifier.send_email(
template_name='a4_webhook_sent',
recipients=config['notifications']['recipients']['success'],
data={
'campaign_name': campaign_name,
'campaign_id': campaign_id,
'campaign_number': campaign_number,
'webhook_url': webhook_url
}
)
return {'success': True, 'webhook_sent': True}
else:
logger.error("✗ Webhook send failed")
return {'success': False, 'webhook_sent': False}
except Exception as e:
logger.error("Campaign processing failed: {}".format(str(e)))
return {'success': False, 'webhook_sent': False}
def main():
"""Main polling loop"""
# Parse command-line arguments
parser = argparse.ArgumentParser(description='Ferrero A4 Webhook Monitor')
parser.add_argument('--auth-pfx', action='store_true',
help='Use mTLS certificate authentication instead of OAuth2')
args = parser.parse_args()
logger.info("=" * 60)
logger.info("Ferrero A4 Webhook Monitor Starting")
if args.auth_pfx:
logger.info("Authentication: mTLS Certificate (--auth-pfx)")
else:
logger.info("Authentication: OAuth2 (default)")
logger.info("=" * 60)
# Load configuration
config = load_config('config/config.yaml')
# Initialize clients
dam = DAMClient(config, use_mtls=args.auth_pfx)
db = Database(config)
notifier = Notifier(config)
# Test connections
logger.info("Testing connections...")
if not dam.test_connection():
logger.error("DAM connection failed - exiting")
sys.exit(1)
if not db.test_connection():
logger.error("Database connection failed - exiting")
sys.exit(1)
logger.info("All connections OK")
logger.info("")
# Process ALL A4 campaigns in a single run
# Since webhooks are lightweight, we can process all campaigns at once
try:
logger.info("Searching for A4 campaigns...")
# Search for campaigns with status A4
campaigns = dam.search_campaigns(status='A4')
if not campaigns:
logger.info("No A4 campaigns found - exiting")
db.close()
sys.exit(0)
# Process ALL campaigns
logger.info("Found {} A4 campaign(s) - processing all".format(len(campaigns)))
logger.info("")
processed_count = 0
webhook_sent_count = 0
already_processed_count = 0
failed_count = 0
for campaign in campaigns:
result = process_campaign(campaign, dam, db, notifier, config)
if result['success']:
processed_count += 1
if result.get('webhook_sent'):
webhook_sent_count += 1
if result.get('already_processed'):
already_processed_count += 1
else:
failed_count += 1
# Summary
logger.info("")
logger.info("=" * 60)
logger.info("A4 Webhook Monitor Summary")
logger.info("=" * 60)
logger.info("Total campaigns found: {}".format(len(campaigns)))
logger.info("Webhooks sent: {}".format(webhook_sent_count))
logger.info("Already processed: {}".format(already_processed_count))
logger.info("Failed: {}".format(failed_count))
logger.info("=" * 60)
db.close()
# Exit with success if at least some succeeded
if failed_count == 0:
sys.exit(0)
elif processed_count > 0:
sys.exit(0) # Partial success
else:
sys.exit(1) # All failed
except Exception as e:
logger.critical("Script error: {}".format(str(e)))
# Send critical error notification
notifier.send_email(
template_name='upload_failed',
recipients=config['notifications']['recipients']['critical'],
data={
'filename': 'A4 Webhook Script',
'tracking_id': 'N/A',
'error': str(e)
}
)
db.close()
sys.exit(1)
if __name__ == '__main__':
main()