update
This commit is contained in:
@@ -162,6 +162,7 @@ def get_latest_articles(max_articles=10, hours=24):
|
||||
'link': doc.get('link', ''),
|
||||
'summary': cluster.get('neutral_summary', doc.get('summary', '')),
|
||||
'source': doc.get('source', ''),
|
||||
'category': doc.get('category', 'general'),
|
||||
'published_at': doc.get('published_at', ''),
|
||||
'is_clustered': True,
|
||||
'sources': sources,
|
||||
@@ -177,6 +178,7 @@ def get_latest_articles(max_articles=10, hours=24):
|
||||
'link': doc.get('link', ''),
|
||||
'summary': doc.get('summary', ''),
|
||||
'source': doc.get('source', ''),
|
||||
'category': doc.get('category', 'general'),
|
||||
'published_at': doc.get('published_at', ''),
|
||||
'is_clustered': False
|
||||
})
|
||||
@@ -190,6 +192,7 @@ def get_latest_articles(max_articles=10, hours=24):
|
||||
'link': doc.get('link', ''),
|
||||
'summary': doc.get('summary', ''),
|
||||
'source': doc.get('source', ''),
|
||||
'category': doc.get('category', 'general'),
|
||||
'published_at': doc.get('published_at', ''),
|
||||
'is_clustered': False
|
||||
})
|
||||
@@ -206,22 +209,29 @@ def get_latest_articles(max_articles=10, hours=24):
|
||||
|
||||
def get_active_subscribers():
|
||||
"""
|
||||
Get all active subscribers from database
|
||||
Get all active subscribers from database with their category preferences
|
||||
|
||||
Returns:
|
||||
list: Email addresses of active subscribers
|
||||
list: Subscriber dictionaries with email and categories
|
||||
"""
|
||||
cursor = subscribers_collection.find({'status': 'active'})
|
||||
return [doc['email'] for doc in cursor]
|
||||
subscribers = []
|
||||
for doc in cursor:
|
||||
subscribers.append({
|
||||
'email': doc['email'],
|
||||
'categories': doc.get('categories', None) # None means all categories
|
||||
})
|
||||
return subscribers
|
||||
|
||||
|
||||
def render_newsletter_html(articles, tracking_enabled=False, pixel_tracking_id=None,
|
||||
link_tracking_map=None, api_url=None):
|
||||
def render_newsletter_html(articles, subscriber_categories=None, tracking_enabled=False,
|
||||
pixel_tracking_id=None, link_tracking_map=None, api_url=None):
|
||||
"""
|
||||
Render newsletter HTML from template with optional tracking integration
|
||||
|
||||
Args:
|
||||
articles: List of article dictionaries
|
||||
subscriber_categories: List of categories the subscriber wants (None = all)
|
||||
tracking_enabled: Whether to inject tracking pixel and replace links
|
||||
pixel_tracking_id: Tracking ID for the email open pixel
|
||||
link_tracking_map: Dictionary mapping original URLs to tracking IDs
|
||||
@@ -237,10 +247,39 @@ def render_newsletter_html(articles, tracking_enabled=False, pixel_tracking_id=N
|
||||
|
||||
template = Template(template_content)
|
||||
|
||||
# Split articles into sections
|
||||
# Top 3 are "trending", rest are "other articles"
|
||||
trending_articles = articles[:3] if len(articles) >= 3 else articles
|
||||
other_articles = articles[3:] if len(articles) > 3 else []
|
||||
# Filter articles by subscriber's category preferences
|
||||
if subscriber_categories:
|
||||
filtered_articles = [a for a in articles if a.get('category', 'general') in subscriber_categories]
|
||||
else:
|
||||
filtered_articles = articles
|
||||
|
||||
# Group articles by category (max 3 per category)
|
||||
from collections import defaultdict
|
||||
articles_by_category = defaultdict(list)
|
||||
|
||||
for article in filtered_articles:
|
||||
category = article.get('category', 'general')
|
||||
if len(articles_by_category[category]) < 3:
|
||||
articles_by_category[category].append(article)
|
||||
|
||||
# Convert to list of category sections
|
||||
category_sections = []
|
||||
category_names = {
|
||||
'general': {'name': 'Top Trending', 'icon': '🔥'},
|
||||
'local': {'name': 'Local Events', 'icon': '🏛️'},
|
||||
'sports': {'name': 'Sports', 'icon': '⚽'},
|
||||
'science': {'name': 'Science & Tech', 'icon': '🔬'}
|
||||
}
|
||||
|
||||
for category, category_articles in sorted(articles_by_category.items()):
|
||||
if category_articles:
|
||||
cat_info = category_names.get(category, {'name': category.title(), 'icon': '📄'})
|
||||
category_sections.append({
|
||||
'id': category,
|
||||
'name': cat_info['name'],
|
||||
'icon': cat_info['icon'],
|
||||
'articles': category_articles
|
||||
})
|
||||
|
||||
# Get weather data
|
||||
from weather_service import get_munich_weather
|
||||
@@ -248,13 +287,14 @@ def render_newsletter_html(articles, tracking_enabled=False, pixel_tracking_id=N
|
||||
|
||||
# Prepare template data
|
||||
now = datetime.now()
|
||||
total_articles = sum(len(section['articles']) for section in category_sections)
|
||||
template_data = {
|
||||
'date': now.strftime('%A, %B %d, %Y'),
|
||||
'year': now.year,
|
||||
'article_count': len(articles),
|
||||
'trending_articles': trending_articles,
|
||||
'other_articles': other_articles,
|
||||
'article_count': total_articles,
|
||||
'category_sections': category_sections,
|
||||
'unsubscribe_link': f'{Config.WEBSITE_URL}/unsubscribe',
|
||||
'preferences_link': f'{Config.WEBSITE_URL}/preferences.html',
|
||||
'website_link': Config.WEBSITE_URL,
|
||||
'tracking_enabled': tracking_enabled,
|
||||
'weather': weather
|
||||
@@ -358,7 +398,8 @@ def send_newsletter(max_articles=None, test_email=None):
|
||||
|
||||
# Get subscribers
|
||||
if test_email:
|
||||
subscribers = [test_email]
|
||||
# For test mode, send with all categories
|
||||
subscribers = [{'email': test_email, 'categories': None}]
|
||||
print(f"\n🧪 Test mode: Sending to {test_email} only")
|
||||
else:
|
||||
print("\nFetching active subscribers...")
|
||||
@@ -386,7 +427,10 @@ def send_newsletter(max_articles=None, test_email=None):
|
||||
failed_count = 0
|
||||
errors = []
|
||||
|
||||
for i, email in enumerate(subscribers, 1):
|
||||
for i, subscriber in enumerate(subscribers, 1):
|
||||
email = subscriber['email']
|
||||
categories = subscriber['categories']
|
||||
|
||||
print(f"[{i}/{len(subscribers)}] Sending to {email}...", end=' ')
|
||||
|
||||
# Generate tracking data for this subscriber if tracking is enabled
|
||||
@@ -399,9 +443,10 @@ def send_newsletter(max_articles=None, test_email=None):
|
||||
tracking_service=tracking_service
|
||||
)
|
||||
|
||||
# Render newsletter with tracking
|
||||
# Render newsletter with tracking and subscriber's category preferences
|
||||
html_content = render_newsletter_html(
|
||||
articles=articles,
|
||||
subscriber_categories=categories,
|
||||
tracking_enabled=True,
|
||||
pixel_tracking_id=tracking_data['pixel_tracking_id'],
|
||||
link_tracking_map=tracking_data['link_tracking_map'],
|
||||
@@ -410,10 +455,10 @@ def send_newsletter(max_articles=None, test_email=None):
|
||||
except Exception as e:
|
||||
print(f"⚠ Tracking error: {e}, sending without tracking...", end=' ')
|
||||
# Fallback: send without tracking
|
||||
html_content = render_newsletter_html(articles)
|
||||
html_content = render_newsletter_html(articles, subscriber_categories=categories)
|
||||
else:
|
||||
# Render newsletter without tracking
|
||||
html_content = render_newsletter_html(articles)
|
||||
# Render newsletter without tracking but with subscriber's preferences
|
||||
html_content = render_newsletter_html(articles, subscriber_categories=categories)
|
||||
|
||||
# Send email
|
||||
success, error = send_email(email, subject, html_content)
|
||||
|
||||
Reference in New Issue
Block a user