Skip to content

Commit

Permalink
Merge 45cf734 into ec7d0df
Browse files Browse the repository at this point in the history
  • Loading branch information
gannetson committed Sep 9, 2022
2 parents ec7d0df + 45cf734 commit 055d23c
Show file tree
Hide file tree
Showing 27 changed files with 872 additions and 751 deletions.
92 changes: 87 additions & 5 deletions bluebottle/activities/messages.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
from pytz import timezone
from datetime import timedelta

from django.urls import reverse
from django.db.models import Sum, Q
from django.template.defaultfilters import time, date
from django.urls import reverse
from django.utils.timezone import get_current_timezone, now
from django.utils.translation import pgettext_lazy as pgettext
from pytz import timezone

from bluebottle.initiatives.models import InitiativePlatformSettings
from django.utils.timezone import get_current_timezone

from bluebottle.notifications.messages import TransitionMessage
from django.utils.translation import pgettext_lazy as pgettext
from bluebottle.notifications.models import Message
from bluebottle.utils.utils import get_current_host, get_current_language


Expand Down Expand Up @@ -445,3 +447,83 @@ def get_recipients(self):
return [self.obj.team.owner]
else:
return []


class BaseDoGoodHoursReminderNotification(TransitionMessage):

@property
def action_link(self):
from bluebottle.clients.utils import tenant_url
return tenant_url('/initiatives/activities/list')

action_title = pgettext('email', 'Find activities')

send_once = True

def get_context(self, recipient):
from bluebottle.members.models import MemberPlatformSettings
from bluebottle.clients.utils import tenant_url

context = super(BaseDoGoodHoursReminderNotification, self).get_context(recipient)
settings = MemberPlatformSettings.load()
context['do_good_hours'] = settings.do_good_hours
context['opt_out_link'] = tenant_url('/member/profile')
return context

@property
def generic_subject(self):
from bluebottle.members.models import MemberPlatformSettings
settings = MemberPlatformSettings.load()
context = self.get_generic_context()
context['do_good_hours'] = settings.do_good_hours
return str(self.subject.format(**context))

def already_send(self, recipient):
return Message.objects.filter(
template=self.get_template(),
recipient=recipient,
sent__year=now().year
).count() > 0

def get_recipients(self):
"""members with do good hours"""
from bluebottle.members.models import Member
from bluebottle.members.models import MemberPlatformSettings

year = now().year
do_good_hours = timedelta(hours=MemberPlatformSettings.load().do_good_hours)

members = Member.objects.annotate(
hours=Sum(
'contributor__contributions__timecontribution__value',
filter=(
Q(contributor__contributions__start__year=year) &
Q(contributor__contributions__status__in=['new', 'succeeded'])
)
),
).filter(
Q(hours__lt=do_good_hours) | Q(hours__isnull=True),
is_active=True,
receive_reminder_emails=True
).distinct()
return members


class DoGoodHoursReminderQ1Notification(BaseDoGoodHoursReminderNotification):
subject = pgettext('email', "It’s a new year, let's make some impact!")
template = 'messages/do-good-hours/reminder-q1'


class DoGoodHoursReminderQ2Notification(BaseDoGoodHoursReminderNotification):
subject = pgettext('email', "Haven’t joined an activity yet? Let’s get started!")
template = 'messages/do-good-hours/reminder-q2'


class DoGoodHoursReminderQ3Notification(BaseDoGoodHoursReminderNotification):
subject = pgettext('email', "Half way through the year and still plenty of activities to join")
template = 'messages/do-good-hours/reminder-q3'


class DoGoodHoursReminderQ4Notification(BaseDoGoodHoursReminderNotification):
subject = pgettext('email', "Make use of your {do_good_hours} hours of impact!")
template = 'messages/do-good-hours/reminder-q4'
48 changes: 40 additions & 8 deletions bluebottle/activities/tasks.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,18 @@
import logging
from datetime import date

from celery.schedules import crontab
from celery.task import periodic_task

from bluebottle.clients.models import Client
from bluebottle.clients.utils import LocalTenant

from elasticsearch_dsl.query import Nested, Q, FunctionScore, ConstantScore, MatchAll

from bluebottle.initiatives.models import InitiativePlatformSettings
from bluebottle.activities.documents import activity
from bluebottle.activities.messages import MatchingActivitiesNotification, DoGoodHoursReminderQ1Notification, \
DoGoodHoursReminderQ4Notification, DoGoodHoursReminderQ3Notification, DoGoodHoursReminderQ2Notification
from bluebottle.activities.models import Activity
from bluebottle.activities.messages import MatchingActivitiesNotification
from bluebottle.members.models import Member

from bluebottle.clients.models import Client
from bluebottle.clients.utils import LocalTenant
from bluebottle.initiatives.models import InitiativePlatformSettings
from bluebottle.members.models import Member, MemberPlatformSettings

logger = logging.getLogger('bluebottle')

Expand Down Expand Up @@ -123,3 +122,36 @@ def recommend():
)
except Exception as e:
logger.error(e)


@periodic_task(
run_every=(crontab(minute=0, hour=10)),
name="do_good_hours_reminder",
ignore_result=True
)
def do_good_hours_reminder():

for tenant in Client.objects.all():
with LocalTenant(tenant, clear_tenant=True):
settings = MemberPlatformSettings.objects.get()
if settings.do_good_hours:
q1 = date.today().replace(month=1, day=1)
q2 = date.today().replace(month=4, day=1)
q3 = date.today().replace(month=7, day=1)
q4 = date.today().replace(month=10, day=1)
notification = None
today = date.today()
if settings.reminder_q1 and today == q1:
notification = DoGoodHoursReminderQ1Notification(settings)
if settings.reminder_q2 and today == q2:
notification = DoGoodHoursReminderQ2Notification(settings)
if settings.reminder_q3 and today == q3:
notification = DoGoodHoursReminderQ3Notification(settings)
if settings.reminder_q4 and today == q4:
notification = DoGoodHoursReminderQ4Notification(settings)

if notification:
try:
notification.compose_and_send()
except Exception as e:
logger.error(e)
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{% extends "base.mail.html" %}
{% load i18n %}

{% block content %}
<p>
{% blocktrans context 'email' %}Hi {{ recipient_name }},{% endblocktrans %}
</p>
{% block message %}{% endblock %}
{% endblock %}

{% block action %}
<a href="{{ action_link }}" class="action-email">{{ action_title }}</a>
{% endblock %}`

{% block end_message %}
{% blocktrans %}
Go to <a href="{{ opt_out_link }}">your profile</a> to opt-out.
{% endblocktrans %}
{% endblock %}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{% extends "mails/messages/do-good-hours/reminder-base.html" %}
{% load i18n %}

{% block message %}
{% blocktrans context 'email' %}
Can you spend {{ do_good_hours }} hours making an impact this year? Of course you can! There's a wide range of activities to join, all contributing to good causes. Check them out!
{% endblocktrans %}
{% endblock %}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{% extends "mails/messages/do-good-hours/reminder-base.html" %}
{% load i18n %}

{% block message %}
{% blocktrans context 'email' %}
The first step is always the hardest, that's why we have made it as easy as possible to find an activity and make an impact!
{% endblocktrans %}
{% endblock %}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{% extends "mails/messages/do-good-hours/reminder-base.html" %}
{% load i18n %}

{% block message %}
{% blocktrans context 'email' %}
There’s still so much time to reach the target of {{ do_good_hours }} hours making an impact this year.
Check out the activities you can join.
{% endblocktrans %}
{% endblock %}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{% extends "mails/messages/do-good-hours/reminder-base.html" %}
{% load i18n %}

{% block message %}
{% blocktrans context 'email' %}
Get involved with some good causes before the year ends, there are plenty of activities that need your help!
{% endblocktrans %}
{% endblock %}
123 changes: 121 additions & 2 deletions bluebottle/activities/tests/test_notifications.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,25 @@
from datetime import timedelta

from django.utils.timezone import now

from bluebottle.activities.messages import (
ActivityRejectedNotification, ActivityCancelledNotification,
ActivitySucceededNotification, ActivityRestoredNotification,
ActivityExpiredNotification, TeamAddedMessage,
TeamAppliedMessage, TeamCancelledMessage,
TeamCancelledTeamCaptainMessage, TeamWithdrawnActivityOwnerMessage,
TeamWithdrawnMessage, TeamMemberAddedMessage, TeamMemberWithdrewMessage,
TeamMemberRemovedMessage, TeamReappliedMessage, TeamCaptainAcceptedMessage
TeamMemberRemovedMessage, TeamReappliedMessage, TeamCaptainAcceptedMessage, DoGoodHoursReminderQ1Notification,
DoGoodHoursReminderQ3Notification, DoGoodHoursReminderQ2Notification, DoGoodHoursReminderQ4Notification
)
from bluebottle.activities.tests.factories import TeamFactory
from bluebottle.members.models import MemberPlatformSettings, Member
from bluebottle.notifications.models import NotificationPlatformSettings
from bluebottle.test.factory_models.accounts import BlueBottleUserFactory
from bluebottle.test.utils import NotificationTestCase
from bluebottle.time_based.tests.factories import (
DateActivityFactory, PeriodActivityFactory, PeriodParticipantFactory
DateActivityFactory, PeriodActivityFactory, PeriodParticipantFactory, DateActivitySlotFactory,
DateParticipantFactory, SlotParticipantFactory
)


Expand Down Expand Up @@ -260,3 +268,114 @@ def test_team_member_removed_notification(self):

self.assertActionLink(self.obj.activity.get_absolute_url())
self.assertActionTitle('View activity')


class DoGoodHoursReminderNotificationTestCase(NotificationTestCase):

def setUp(self):
self.obj = NotificationPlatformSettings.load()
self.obj = MemberPlatformSettings.load()
self.obj.do_good_hours = 8
self.obj.save()
activity = DateActivityFactory.create(
slots=[],
slot_selection='free',
)

slot1 = DateActivitySlotFactory.create(
start=now() - timedelta(days=2),
duration=timedelta(hours=4),
activity=activity
)
slot2 = DateActivitySlotFactory.create(
start=now() - timedelta(days=1),
duration=timedelta(hours=4),
activity=activity
)
old_slot = DateActivitySlotFactory.create(
start=now().replace(year=2011),
duration=timedelta(hours=8),
activity=activity
)

self.active_user = BlueBottleUserFactory.create(first_name='Active')
part1 = DateParticipantFactory.create(
user=self.active_user,
activity=activity
)
SlotParticipantFactory.create(
participant=part1,
slot=slot1
)
SlotParticipantFactory.create(
participant=part1,
slot=slot2
)
self.moderate_user = BlueBottleUserFactory.create(first_name='Moderate')
part2 = DateParticipantFactory.create(
user=self.moderate_user,
activity=activity
)
SlotParticipantFactory.create(
participant=part2,
slot=slot1
)
SlotParticipantFactory.create(
participant=part2,
slot=old_slot
)
self.passive_user = BlueBottleUserFactory.create(first_name='Passive')
part3 = DateParticipantFactory.create(
user=self.passive_user,
activity=activity
)

SlotParticipantFactory.create(
participant=part3,
slot=old_slot
)

Member.objects.exclude(id__in=[
self.active_user.id,
self.passive_user.id,
self.moderate_user.id,
]).update(receive_reminder_emails=False)

def test_reminder_q1(self):
self.message_class = DoGoodHoursReminderQ1Notification
self.create()
self.assertRecipients([self.moderate_user, self.passive_user])
self.assertSubject("It’s a new year, let's make some impact!")
self.assertBodyContains('Can you spend 8 hours making an impact this year?')
self.assertActionTitle('Find activities')
self.assertActionLink('https://testserver/initiatives/activities/list')
self.assertBodyContains('https://testserver/member/profile')

def test_reminder_q2(self):
self.message_class = DoGoodHoursReminderQ2Notification
self.create()
self.assertRecipients([self.moderate_user, self.passive_user])
self.assertSubject("Haven’t joined an activity yet? Let’s get started!")
self.assertBodyContains('The first step is always the hardest')
self.assertActionTitle('Find activities')

def test_reminder_q3(self):
self.message_class = DoGoodHoursReminderQ3Notification
self.create()
self.assertRecipients([self.moderate_user, self.passive_user])
self.assertSubject("Half way through the year and still plenty of activities to join")
self.assertBodyContains(
'There’s still so much time to reach the target of 8 hours making an impact this year.'
)
self.assertActionTitle('Find activities')

def test_reminder_q4(self):
self.message_class = DoGoodHoursReminderQ4Notification
self.create()
self.assertRecipients([self.moderate_user, self.passive_user])
self.assertSubject("Make use of your 8 hours of impact!")
self.assertBodyContains(
'Get involved with some good causes before the year ends, '
'there are plenty of activities that need your help!'
)
self.assertActionTitle('Find activities')
Loading

0 comments on commit 055d23c

Please sign in to comment.