Merge branch 'bheesham-feature/35-email-reminders'
This commit is contained in:
commit
a5822d4088
12 changed files with 208 additions and 12 deletions
24
events/migrations/0024_auto_20180404_0504.py
Normal file
24
events/migrations/0024_auto_20180404_0504.py
Normal file
|
@ -0,0 +1,24 @@
|
|||
# Generated by Django 2.0 on 2018-04-04 05:04
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.utils.timezone
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('events', '0023_add_searchable_timezone'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='attendee',
|
||||
name='last_reminded',
|
||||
field=models.DateTimeField(blank=True, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='team',
|
||||
name='created_date',
|
||||
field=models.DateField(blank=True, default=django.utils.timezone.now, null=True, verbose_name='Date Created'),
|
||||
),
|
||||
]
|
|
@ -208,6 +208,7 @@ class Attendee(models.Model):
|
|||
role = models.SmallIntegerField(_("Role"), choices=ROLES, default=NORMAL, db_index=True)
|
||||
status = models.SmallIntegerField(_("Attending?"), choices=STATUSES, default=YES, db_index=True)
|
||||
joined_date = models.DateTimeField(default=timezone.now)
|
||||
last_reminded = models.DateTimeField(null=True, blank=True)
|
||||
|
||||
@property
|
||||
def role_name(self):
|
||||
|
|
|
@ -13,4 +13,3 @@ class BaseTest(TestCase):
|
|||
|
||||
def test_harness(self):
|
||||
return
|
||||
|
||||
|
|
61
get_together/management/commands/send_event_reminder.py
Normal file
61
get_together/management/commands/send_event_reminder.py
Normal file
|
@ -0,0 +1,61 @@
|
|||
from django.core.management.base import BaseCommand, CommandError
|
||||
from django.urls import reverse
|
||||
from django.core.mail import send_mail
|
||||
from django.template.loader import get_template, render_to_string
|
||||
from django.conf import settings
|
||||
from django.contrib.sites.models import Site
|
||||
from django.utils import timezone
|
||||
from django.db.models import Q
|
||||
|
||||
from accounts.models import Account, EmailConfirmation
|
||||
from events.models import Event, Attendee
|
||||
|
||||
import time
|
||||
import urllib
|
||||
import datetime
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = "Sends upcomming event notifications to attendees."
|
||||
|
||||
def handle(self, *args, **options):
|
||||
site = Site.objects.get(id=1)
|
||||
|
||||
# Events that start within a day.
|
||||
query = Q(status=Attendee.YES,
|
||||
event__start_time__gt=timezone.now(),
|
||||
event__start_time__lt=timezone.now()+datetime.timedelta(days=1))
|
||||
|
||||
attendees = Attendee.objects.filter(query)
|
||||
|
||||
for attendee in attendees:
|
||||
|
||||
# Skip people who don't want notificiations or have no email address.
|
||||
if not attendee.user.send_notifications or not attendee.user.user.email:
|
||||
continue
|
||||
|
||||
# Skip people who have been reminded in the last day.
|
||||
if attendee.last_reminded and timezone.now() - datetime.timedelta(days=1) < attendee.last_reminded:
|
||||
continue
|
||||
|
||||
context = {
|
||||
'event': attendee.event,
|
||||
}
|
||||
|
||||
email_subject = '[GetTogether] Upcoming event reminder'
|
||||
email_body_text = render_to_string('get_together/emails/reminder.txt', context)
|
||||
email_body_html = render_to_string('get_together/emails/reminder.html', context)
|
||||
email_recipients = [attendee.user.user.email]
|
||||
email_from = getattr(settings, 'DEFAULT_FROM_EMAIL', 'noreply@gettogether.community')
|
||||
|
||||
send_mail(
|
||||
from_email=email_from,
|
||||
html_message=email_body_html,
|
||||
message=email_body_text,
|
||||
recipient_list=email_recipients,
|
||||
subject=email_subject,
|
||||
)
|
||||
|
||||
attendee.last_reminded = timezone.now()
|
||||
attendee.save()
|
||||
|
||||
time.sleep(0.1)
|
|
@ -35,7 +35,10 @@ form {
|
|||
<main role="main" class="container">
|
||||
|
||||
{% block content %}{% endblock %}
|
||||
|
||||
<hr>
|
||||
<p>This is an automated email sent by <a href="https://gettogether.community">https://gettogether.community</a></p>
|
||||
<p>
|
||||
Learn more at <a href="https://github.com/GetTogetherComm/GetTogether/">https://github.com/GetTogetherComm/GetTogether/</a></p>
|
||||
</main>
|
||||
|
||||
|
||||
</html>
|
||||
|
|
3
get_together/templates/get_together/emails/base.txt
Normal file
3
get_together/templates/get_together/emails/base.txt
Normal file
|
@ -0,0 +1,3 @@
|
|||
--
|
||||
This is an automated email sent by https://gettogether.community
|
||||
Learn more at https://github.com/GetTogetherComm/GetTogether/
|
|
@ -6,8 +6,4 @@
|
|||
<p>Please confirm this email address with GetTogether.Community by clicking on the link below:</p>
|
||||
|
||||
<p><a href="{{confirmation_url}}" class="btn btn-success">Confirm email</a></p>
|
||||
|
||||
<hr/>
|
||||
<p>This is an automated email sent by <a href="https://gettogether.community">https://gettogether.community</a></p>
|
||||
<p>Learn more at <a href="https://github.com/GetTogetherComm/GetTogether/">https://github.com/GetTogetherComm/GetTogether/</a></p>
|
||||
{% endblock %}
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
{% extends 'get_together/emails/base.txt' %}
|
||||
{% block content %}
|
||||
== Request Email Confirmation ==
|
||||
|
||||
Please confirm this email address with GetTogether.Community by clicking on the link below:
|
||||
|
||||
Confirm email: {{confirmation_url}}
|
||||
|
||||
--
|
||||
This is an automated email sent by https://gettogether.community
|
||||
Learn more at https://github.com/GetTogetherComm/GetTogether/
|
||||
{% endblock %}
|
||||
|
|
15
get_together/templates/get_together/emails/reminder.html
Normal file
15
get_together/templates/get_together/emails/reminder.html
Normal file
|
@ -0,0 +1,15 @@
|
|||
{% extends "get_together/emails/base.html" %}
|
||||
|
||||
{% block content %}
|
||||
<h3>Event Reminder Notification</h3>
|
||||
|
||||
<p>You have an event coming up!</p>
|
||||
|
||||
<p>
|
||||
<strong>Name</strong>: {{ event.name|striptags }}<br>
|
||||
<strong>Time</strong>: {{event.local_start_time}}<br>
|
||||
<strong>Location</strong>: {{ event.location|striptags }}<br>
|
||||
<br>
|
||||
<a href="{{event.get_full_url}}" title="{{ event.name|striptags }} page.">Go to the event page.</a>
|
||||
</p>
|
||||
{% endblock %}
|
11
get_together/templates/get_together/emails/reminder.txt
Normal file
11
get_together/templates/get_together/emails/reminder.txt
Normal file
|
@ -0,0 +1,11 @@
|
|||
{% block content %}
|
||||
== Event Reminder Notification ==
|
||||
|
||||
You have an event coming up!
|
||||
|
||||
Name: {{ event.name|striptags }}
|
||||
Time: {{event.local_start_time}}
|
||||
Location: {{ event.location|striptags }}
|
||||
|
||||
Event page: {{event.get_full_url}}
|
||||
{% endblock %}
|
|
@ -1,4 +1,4 @@
|
|||
from django.test import TestCase
|
||||
|
||||
from .events import *
|
||||
|
||||
from .event_reminder import *
|
||||
|
|
84
get_together/tests/event_reminder.py
Normal file
84
get_together/tests/event_reminder.py
Normal file
|
@ -0,0 +1,84 @@
|
|||
from django.test import TestCase
|
||||
from django.core.management import call_command
|
||||
from django.core import mail
|
||||
from django.utils import timezone
|
||||
from model_mommy import mommy
|
||||
from model_mommy.recipe import Recipe
|
||||
import datetime
|
||||
|
||||
from django.contrib.auth.models import User
|
||||
|
||||
from events.models.events import Event, Attendee
|
||||
from events.models.profiles import UserProfile
|
||||
|
||||
class UpcommingEventReminderTest(TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
|
||||
user = mommy.make(User, email='test@gettogether.community')
|
||||
|
||||
self.userProfile = mommy.make(UserProfile, user=user, send_notifications=True)
|
||||
self.event = mommy.make(Event, start_time=timezone.now() + datetime.timedelta(hours=1))
|
||||
|
||||
|
||||
def tearDown(self):
|
||||
super().tearDown()
|
||||
|
||||
|
||||
def test_reminder(self):
|
||||
attendee = mommy.make(Attendee, event=self.event, user=self.userProfile, status=Attendee.YES)
|
||||
|
||||
call_command('send_event_reminder')
|
||||
|
||||
self.assertEquals(len(mail.outbox), 1)
|
||||
|
||||
|
||||
def test_reminder_updated_last_reminded(self):
|
||||
attendee = mommy.make(Attendee, event=self.event, user=self.userProfile, status=Attendee.YES)
|
||||
last_reminded = attendee.last_reminded
|
||||
|
||||
call_command('send_event_reminder')
|
||||
|
||||
attendee.refresh_from_db()
|
||||
|
||||
self.assertNotEqual(attendee.last_reminded, last_reminded)
|
||||
|
||||
|
||||
def test_quick_successive_reminders(self):
|
||||
attendee = mommy.make(Attendee, event=self.event, user=self.userProfile, status=Attendee.YES)
|
||||
|
||||
call_command('send_event_reminder')
|
||||
call_command('send_event_reminder')
|
||||
|
||||
self.assertEquals(len(mail.outbox), 1)
|
||||
|
||||
def test_successive_reminders_after_a_day(self):
|
||||
attendee = mommy.make(Attendee, event=self.event, user=self.userProfile, status=Attendee.YES)
|
||||
attendee_id = attendee.id
|
||||
|
||||
call_command('send_event_reminder')
|
||||
self.assertEquals(len(mail.outbox), 1)
|
||||
|
||||
attendee.last_reminded = timezone.now() - datetime.timedelta(days=2)
|
||||
attendee.save()
|
||||
# This should send another email, because the last one was more than a day ago
|
||||
call_command('send_event_reminder')
|
||||
|
||||
self.assertEquals(len(mail.outbox), 2)
|
||||
|
||||
def test_reminders_only_for_the_upcoming_day(self):
|
||||
attendee = mommy.make(Attendee, event=self.event, user=self.userProfile, status=Attendee.YES)
|
||||
self.event.start_time = timezone.now() + datetime.timedelta(days=2)
|
||||
self.event.save()
|
||||
|
||||
call_command('send_event_reminder')
|
||||
self.assertEquals(len(mail.outbox), 0)
|
||||
|
||||
self.event.start_time = timezone.now() + datetime.timedelta(hours=23)
|
||||
self.event.save()
|
||||
|
||||
call_command('send_event_reminder')
|
||||
self.assertEquals(len(mail.outbox), 1)
|
||||
|
||||
|
Loading…
Reference in a new issue