From 7833cf443ae9d29ee5bae85d47fa63f3f459e164 Mon Sep 17 00:00:00 2001 From: Shane Date: Wed, 14 May 2025 17:22:47 +1000 Subject: [PATCH] add email alert for low rate limit X --- foodie_config.py | 32 ++++++++++++++++++++----------- foodie_utils.py | 49 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+), 11 deletions(-) diff --git a/foodie_config.py b/foodie_config.py index e1f7f8d..6941934 100644 --- a/foodie_config.py +++ b/foodie_config.py @@ -31,7 +31,7 @@ AUTHORS = [ "username": "aishapatel", "password": os.getenv("AISHAPATEL_PASSWORD"), "persona": "Trend Scout", - "bio": "I scout global food trends, obsessed with what’s emerging. My sharp predictions map the industry’s path—always one step ahead.", + "bio": "I scout global food trends, obsessed with what's emerging. My sharp predictions map the industry's path—always one step ahead.", "dob": "1999-03-15" }, { @@ -47,7 +47,7 @@ AUTHORS = [ "username": "keishareid", "password": os.getenv("KEISHAREID_PASSWORD"), "persona": "African-American Soul Food Sage", - "bio": "I bring soul food’s legacy to life, blending history with modern vibes. My stories celebrate flavor and resilience—dishing out culture with every bite.", + "bio": "I bring soul food's legacy to life, blending history with modern vibes. My stories celebrate flavor and resilience—dishing out culture with every bite.", "dob": "1994-06-10" }, { @@ -116,7 +116,7 @@ PERSONA_CONFIGS = { "description": "a commanding food editor with a borderless view", "tone": "a polished and insightful tone, like 'This redefines culinary excellence.'", "article_prompt": ( - "You’re {description}. Summarize this article in {tone}. " + "You're {description}. Summarize this article in {tone}. " "Explore a wide range of food-related topics, skip recipes. Generate exactly {num_paragraphs} paragraphs, 60-80 words each, full thoughts, with a single \n break. " "Write naturally in a refined yet engaging style, with a slight Upworthy/Buzzfeed flair, without mentioning the source name or URL directly in the text. " "Add a bold take and end with a thought-provoking question like Neil Patel would do to boost engagement! Do not include emojis in the summary." @@ -133,7 +133,7 @@ PERSONA_CONFIGS = { "description": "a seasoned foodie reviewer with a sharp eye", "tone": "a professional yet engaging tone, like 'This dish is a revelation.'", "article_prompt": ( - "You’re {description}. Summarize this article in {tone}. " + "You're {description}. Summarize this article in {tone}. " "Explore a wide range of food-related topics, skip recipes. Generate exactly {num_paragraphs} paragraphs, 60-80 words each, full thoughts, with a single \n break. " "Write naturally in a refined yet engaging style, with a slight Upworthy/Buzzfeed flair, without mentioning the source name or URL directly in the text. " "Add a subtle opinion and end with a thought-provoking question like Neil Patel would do to boost engagement! Do not include emojis in the summary." @@ -148,12 +148,12 @@ PERSONA_CONFIGS = { }, "Trend Scout": { "description": "a forward-thinking editor obsessed with trends", - "tone": "an insightful and forward-looking tone, like 'This sets the stage for what’s next.'", + "tone": "an insightful and forward-looking tone, like 'This sets the stage for what's next.'", "article_prompt": ( - "You’re {description}. Summarize this article in {tone}. " + "You're {description}. Summarize this article in {tone}. " "Explore a wide range of food-related topics, skip recipes. Generate exactly {num_paragraphs} paragraphs, 60-80 words each, full thoughts, with a single \n break. " "Write naturally in a refined yet engaging style, with a slight Upworthy/Buzzfeed flair, without mentioning the source name or URL directly in the text. " - "Predict what’s next and end with a thought-provoking question like Neil Patel would do to boost engagement! Do not include emojis in the summary." + "Predict what's next and end with a thought-provoking question like Neil Patel would do to boost engagement! Do not include emojis in the summary." ), "x_prompt": ( "Craft a tweet as {description}. Keep it under 280 characters, using {tone}. " @@ -167,7 +167,7 @@ PERSONA_CONFIGS = { "description": "a cultured food writer who loves storytelling", "tone": "a warm and thoughtful tone, like 'This evokes a sense of tradition.'", "article_prompt": ( - "You’re {description}. Summarize this article in {tone}. " + "You're {description}. Summarize this article in {tone}. " "Explore a wide range of food-related topics, skip recipes. Generate exactly {num_paragraphs} paragraphs, 60-80 words each, full thoughts, with a single \n break. " "Write naturally in a refined yet engaging style, with a slight Upworthy/Buzzfeed flair, without mentioning the source name or URL directly in the text. " "Add a thoughtful observation and end with a thought-provoking question like Neil Patel would do to boost engagement! Do not include emojis in the summary." @@ -184,7 +184,7 @@ PERSONA_CONFIGS = { "description": "a vibrant storyteller rooted in African-American culinary heritage", "tone": "a heartfelt and authentic tone, like 'This captures the essence of heritage.'", "article_prompt": ( - "You’re {description}. Summarize this article in {tone}. " + "You're {description}. Summarize this article in {tone}. " "Explore a wide range of food-related topics, skip recipes. Generate exactly {num_paragraphs} paragraphs, 60-80 words each, full thoughts, with a single \n break. " "Write naturally in a refined yet engaging style, with a slight Upworthy/Buzzfeed flair, without mentioning the source name or URL directly in the text. " "Add a heritage twist and end with a thought-provoking question like Neil Patel would do to boost engagement! Do not include emojis in the summary." @@ -201,7 +201,7 @@ PERSONA_CONFIGS = { "description": "an adventurous explorer of global street food", "tone": "a bold and adventurous tone, like 'This takes you on a global journey.'", "article_prompt": ( - "You’re {description}. Summarize this article in {tone}. " + "You're {description}. Summarize this article in {tone}. " "Explore a wide range of food-related topics, skip recipes. Generate exactly {num_paragraphs} paragraphs, 60-80 words each, full thoughts, with a single \n break. " "Write naturally in a refined yet engaging style, with a slight Upworthy/Buzzfeed flair, without mentioning the source name or URL directly in the text. " "Drop a street-level insight and end with a thought-provoking question like Neil Patel would do to boost engagement! Do not include emojis in the summary." @@ -282,4 +282,14 @@ def get_clean_source_name(source_name): for feed_url, (clean_name, _) in RSS_FEED_NAMES.items(): if feed_url == source_name: return clean_name - return source_name \ No newline at end of file + return source_name + +# Email configuration for alerts +EMAIL_CONFIG = { + 'from_email': 'hi@insiderfoodie.com', # System alerts email + 'to_email': 'hi@insiderfoodie.com', # Same email for receiving alerts + 'smtp_server': 'mail.insiderfoodie.com', # Your SMTP server + 'smtp_port': 587, # STARTTLS port + 'smtp_username': 'hi', # SMTP username + 'smtp_password': os.getenv('INSIDERFOODIE_EMAIL_PASSWORD') # Store password in .env +} \ No newline at end of file diff --git a/foodie_utils.py b/foodie_utils.py index b66e4d9..c4b14bb 100644 --- a/foodie_utils.py +++ b/foodie_utils.py @@ -1435,6 +1435,46 @@ def get_next_author_round_robin(): logger.warning("No authors available due to tweet rate limits.") return None +def send_account_lock_alert(username, error_message): + """Send email alert for account lockout.""" + try: + import smtplib + from email.mime.text import MIMEText + from email.mime.multipart import MIMEMultipart + from foodie_config import EMAIL_CONFIG # Add this to your config file + + msg = MIMEMultipart() + msg['From'] = EMAIL_CONFIG['from_email'] + msg['To'] = EMAIL_CONFIG['to_email'] + msg['Subject'] = f"🚨 X Account Lock Alert: {username}" + + body = f""" + X Account Lock Alert! + + Username: {username} + Time: {datetime.now(timezone.utc).strftime('%Y-%m-%d %H:%M:%S UTC')} + Error: {error_message} + + Action Required: + 1. Visit https://twitter.com + 2. Log in to {username} + 3. Complete verification if prompted + 4. Unlock the account + + This is an automated alert from your foodie_automator system. + """ + + msg.attach(MIMEText(body, 'plain')) + + with smtplib.SMTP(EMAIL_CONFIG['smtp_server'], EMAIL_CONFIG['smtp_port']) as server: + server.starttls() + server.login(EMAIL_CONFIG['smtp_username'], EMAIL_CONFIG['smtp_password']) + server.send_message(msg) + + logger.info(f"Sent account lock alert email for {username}") + except Exception as e: + logger.error(f"Failed to send account lock alert email: {e}") + def get_x_rate_limit_status(author): """ Check the X API Free tier rate limit by posting a test tweet. @@ -1485,6 +1525,15 @@ def get_x_rate_limit_status(author): logger.error(f"User 24-hour limit headers missing for {username}: {headers}") return None, None logger.info(f"Rate limit exceeded for {username}") + elif response.status_code == 403: + error_data = response.json() + error_message = error_data.get('detail', '') + if "account is temporarily locked" in error_message.lower(): + logger.error(f"Account lock detected for {username}: {error_message}") + send_account_lock_alert(username, error_message) + else: + logger.error(f"Unexpected 403 response for {username}: {error_message}") + return None, None else: logger.error(f"Unexpected response for {username}: {response.status_code} - {response.text}") return None, None