Hugh Rundle
8dc69f2a9e
Blog announcements were using the string "None" as the author, now they should not. Updated tests accordingly. Fixed email test being captured by bot trap.
239 lines
8.4 KiB
Python
239 lines
8.4 KiB
Python
"""send the weekly email"""
|
|
|
|
from datetime import timedelta
|
|
import logging
|
|
import random
|
|
|
|
from django.conf import settings
|
|
from django.utils import timezone
|
|
from django.core.management.base import BaseCommand
|
|
|
|
from blogs import models
|
|
from blogs.utilities import send_email
|
|
from blogs.models.utils import GroupType
|
|
|
|
|
|
class Command(BaseCommand):
|
|
"""the announce command"""
|
|
|
|
# we could add arguments but we don't really need any
|
|
|
|
def handle(self, *args, **options):
|
|
"""find subscribers and send an update"""
|
|
|
|
subscribers = models.Subscriber.objects.filter(confirmed=True)
|
|
|
|
logging.info(
|
|
f"Sending weekly emails to {len(subscribers)} subscribers at {timezone.now()}"
|
|
)
|
|
|
|
cutoff = timezone.now() - timedelta(days=7)
|
|
blogs = models.Blog.objects.filter(
|
|
approved=True, active=True, added__gte=cutoff
|
|
)
|
|
articles = models.Article.objects.filter(pubdate__gte=cutoff)
|
|
events = models.Event.objects.filter(approved=True, pubdate__gte=cutoff)
|
|
cfps = models.CallForPapers.objects.filter(
|
|
event__approved=True, closing_date__gte=timezone.now().date()
|
|
)
|
|
newsletters = models.Newsletter.objects.filter(
|
|
approved=True, pubdate__gte=cutoff
|
|
)
|
|
editions = models.Edition.objects.filter(pubdate__gte=cutoff)
|
|
groups = models.Group.objects.filter(approved=True, pubdate__gte=cutoff)
|
|
|
|
new_blogs = ""
|
|
for blog in blogs:
|
|
title_string = f"<h4><a href='{blog.url}'>{blog.title}</a></h4>"
|
|
author_string = (
|
|
f"<p><em>{blog.author_name}</em></p>" if blog.author_name else ""
|
|
)
|
|
description_string = (
|
|
f"<p style='margin-bottom:24px;'>{blog.description}</p>"
|
|
)
|
|
|
|
string_list = [title_string, author_string, description_string]
|
|
string = "".join(string_list)
|
|
|
|
new_blogs = new_blogs + string
|
|
|
|
if new_blogs != "":
|
|
new_blogs = (
|
|
"<h3 style='margin-top:20px;'>New Blogs</h3>" + new_blogs + "<hr/>"
|
|
)
|
|
|
|
new_articles = ""
|
|
for post in articles:
|
|
title_string = f"<h4><a href='{post.url}'>{post.title}</a></h4>"
|
|
author_string = (
|
|
f"<p><em>{post.author_name}</em></p>" if post.author_name else ""
|
|
)
|
|
description_string = (
|
|
f"<p style='margin-bottom:24px;'>{post.description}</p>"
|
|
)
|
|
|
|
string_list = [title_string, author_string, description_string]
|
|
string = "".join(string_list)
|
|
|
|
new_articles = new_articles + string
|
|
|
|
if new_articles != "":
|
|
new_articles = (
|
|
"<h3 style='margin-top:20px;'>New Blog Posts</h3>"
|
|
+ new_articles
|
|
+ "<hr/>"
|
|
)
|
|
|
|
new_editions = ""
|
|
for edition in editions:
|
|
title_string = f"<h4><a href='{edition.url}'>{edition.title}</a></h4>"
|
|
author_string = (
|
|
f"<p><em>{edition.author_name}</em></p>" if edition.author_name else ""
|
|
)
|
|
description_string = (
|
|
f"<p style='margin-bottom:24px;'>{edition.description}</p>"
|
|
)
|
|
|
|
string_list = [title_string, author_string, description_string]
|
|
string = "".join(string_list)
|
|
|
|
new_editions = new_editions + string
|
|
|
|
if new_editions != "":
|
|
new_editions = (
|
|
"<h3 style='margin-top:20px;'>New Newsletter Editions</h3>"
|
|
+ new_editions
|
|
+ "<hr/>"
|
|
)
|
|
|
|
coming_events = ""
|
|
for event in events:
|
|
s_date = event.start_date
|
|
title_string = f"<h4><a href='{event.url}'>{event.name}</a></h4>"
|
|
date_string = (
|
|
f"<p><em>{s_date:%a} {s_date.day} {s_date:%B} {s_date:%Y}</em></p>"
|
|
)
|
|
description_string = (
|
|
f"<p style='margin-bottom:24px;'>{event.description}</p>"
|
|
)
|
|
|
|
string_list = [title_string, date_string, description_string]
|
|
string = "".join(string_list)
|
|
|
|
coming_events = coming_events + string
|
|
|
|
if coming_events != "":
|
|
coming_events = (
|
|
"<h3 style='margin-top:20px;'>Upcoming Events</h3>"
|
|
+ coming_events
|
|
+ "<hr/>"
|
|
)
|
|
|
|
open_cfps = ""
|
|
for instance in cfps:
|
|
c_date = instance.closing_date
|
|
title_string = f"<h4><a href='{instance.event.url}'>{instance.event.name} - {instance.name}</a></h4>"
|
|
dates_string = f"<p><strong>Closes:</strong><em>{c_date:%a} {c_date.day} {c_date:%B}</em></p>"
|
|
description_string = f"<p>{instance.details}</p><p style='margin-bottom:24px;'>{instance.event.description}</p>"
|
|
|
|
string_list = [title_string, dates_string, description_string]
|
|
string = "".join(string_list)
|
|
|
|
open_cfps = open_cfps + string
|
|
|
|
if open_cfps != "":
|
|
open_cfps = (
|
|
"<h3 style='margin-top:20px;'>Open Calls</h3>" + open_cfps + "<hr/>"
|
|
)
|
|
|
|
new_newsletters = ""
|
|
for instance in newsletters:
|
|
title_string = f"<h4><a href='{instance.url}'>{instance.name}</a></h4>"
|
|
author_string = (
|
|
f"<p><em>{instance.author}</em></p>" if instance.author else ""
|
|
)
|
|
description_string = (
|
|
f"<p style='margin-bottom:24px;'>{instance.description}</p>"
|
|
)
|
|
string_list = [title_string, author_string, description_string]
|
|
string = "".join(string_list)
|
|
|
|
new_newsletters = new_newsletters + string
|
|
|
|
if new_newsletters != "":
|
|
new_newsletters = (
|
|
"<h3 style='margin-top:20px;'>New Newsletters</h3>"
|
|
+ new_newsletters
|
|
+ "<hr/>"
|
|
)
|
|
|
|
new_groups = ""
|
|
for instance in groups:
|
|
group_type = GroupType(instance.type).label
|
|
title_string = f"<h4><a href='{instance.url}'>{instance.name}</a></h4>"
|
|
register_string = f"<p><em><a href='{instance.registration_url}'>Register</a> to join this {group_type}</em></p>"
|
|
description_string = (
|
|
f"<p style='margin-bottom:24px;'>{instance.description}</p>"
|
|
)
|
|
string_list = [title_string, register_string, description_string]
|
|
string = "".join(string_list)
|
|
|
|
new_groups = new_groups + string
|
|
|
|
if new_groups != "":
|
|
new_groups = (
|
|
"<h3 style='margin-top:20px;'>New Groups</h3>" + new_groups + "<hr/>"
|
|
)
|
|
|
|
# Now let's put it all together...
|
|
dt = timezone.now()
|
|
choices = [
|
|
"🍓",
|
|
"🍒",
|
|
"🍎",
|
|
"🍊",
|
|
"🍍",
|
|
"🍋",
|
|
"🍉",
|
|
"🥝",
|
|
"🥦",
|
|
"🥒",
|
|
"🥕",
|
|
"🍏",
|
|
"🍅",
|
|
"🥬",
|
|
"🫐",
|
|
"🍐",
|
|
"🥗",
|
|
"☕️",
|
|
"🚚",
|
|
"📬",
|
|
"🍣",
|
|
]
|
|
emoji = random.choice(choices)
|
|
subject = f"{emoji} Fresh Aus GLAMR updates for the week of {dt.day} {dt:%B} {dt.year}"
|
|
sections = [
|
|
new_articles,
|
|
new_editions,
|
|
new_blogs,
|
|
new_newsletters,
|
|
new_groups,
|
|
open_cfps,
|
|
coming_events,
|
|
]
|
|
body = "".join(sections)
|
|
if body == "":
|
|
body = "<p>No new updates this week.</p><p>Why not spend some time publishing your own blog post instead?</p>"
|
|
|
|
for subscriber in subscribers:
|
|
opt_out = f"https://{settings.DOMAIN}/unsubscribe-email/{subscriber.token}/{subscriber.id}"
|
|
start = "<html><body>"
|
|
footer = f"<div style='padding: 20px; width: 100vw; background-color:#eee; margin-top: 100px;text-align:center;'><em><p>This email was sent to <strong>{subscriber.email}</strong> because you subscribed to email updates from <a href='https://{settings.DOMAIN}'>Aus GLAMR</a>.</p><p>You can <a href='{opt_out}'>unsubscribe</a> at any time.</p></em></div>"
|
|
end = "</body></html>"
|
|
parts = [start, body, footer, end]
|
|
message = "".join(parts)
|
|
|
|
send_email(subject, message, subscriber.email)
|
|
|
|
logging.info(f"Weekly emails completed {timezone.now()}")
|