Skip to content

Commit

Permalink
Merge pull request #5218 from onepercentclub/ticket/BB-20531-task-for…
Browse files Browse the repository at this point in the history
…-q-mails

Ticket/bb 20531 task for q mails
  • Loading branch information
gannetson committed Aug 31, 2022
2 parents 5878d6b + c9d389b commit ad18e57
Show file tree
Hide file tree
Showing 5 changed files with 281 additions and 704 deletions.
15 changes: 14 additions & 1 deletion bluebottle/activities/messages.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

from bluebottle.initiatives.models import InitiativePlatformSettings
from bluebottle.notifications.messages import TransitionMessage
from bluebottle.notifications.models import Message
from bluebottle.utils.utils import get_current_host, get_current_language


Expand Down Expand Up @@ -456,6 +457,15 @@ def action_link(self):

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

send_once = True

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
Expand All @@ -467,7 +477,10 @@ def get_recipients(self):
members = Member.objects.annotate(
hours=Sum(
'contributor__contributions__timecontribution__value',
filter=Q(contributor__contributions__start__year=year)
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),
Expand Down
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)
227 changes: 227 additions & 0 deletions bluebottle/activities/tests/test_periodic_tasks.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,227 @@
from datetime import date, datetime, timedelta
from unittest import mock

from django.core import mail
from django.utils import timezone
from django.utils.timezone import now

from bluebottle.activities.tasks import do_good_hours_reminder
from bluebottle.members.models import MemberPlatformSettings, Member
from bluebottle.test.factory_models.accounts import BlueBottleUserFactory

from bluebottle.test.utils import BluebottleTestCase
from bluebottle.time_based.tests.factories import (
DateActivityFactory, DateActivitySlotFactory, DateParticipantFactory,
SlotParticipantFactory
)


class DoGoodHoursReminderPeriodicTasksTest(BluebottleTestCase):

def setUp(self):
super().setUp()
settings = MemberPlatformSettings.load()
settings.do_good_hours = 8
settings.reminder_q1 = True
settings.reminder_q2 = True
settings.reminder_q3 = False
settings.reminder_q4 = True
settings.save()

activity = DateActivityFactory.create(
slots=[],
slot_selection='free',
)

self.slot1 = DateActivitySlotFactory.create(
start=self.after_q1,
duration=timedelta(hours=4),
activity=activity
)
self.slot2 = DateActivitySlotFactory.create(
start=self.after_q1,
duration=timedelta(hours=4),
activity=activity
)
self.slot3 = DateActivitySlotFactory.create(
start=self.after_q2,
duration=timedelta(hours=8),
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')
self.part1 = DateParticipantFactory.create(
user=self.active_user,
activity=activity
)
SlotParticipantFactory.create(
participant=self.part1,
slot=self.slot1
)
SlotParticipantFactory.create(
participant=self.part1,
slot=self.slot2
)
self.moderate_user = BlueBottleUserFactory.create(first_name='Moderate')
self.part2 = DateParticipantFactory.create(
user=self.moderate_user,
activity=activity
)
SlotParticipantFactory.create(
participant=self.part2,
slot=self.slot1
)
SlotParticipantFactory.create(
participant=self.part2,
slot=old_slot
)

self.tempted_user = BlueBottleUserFactory.create(first_name='Tempted')
self.part3 = DateParticipantFactory.create(
user=self.tempted_user,
activity=activity
)
SlotParticipantFactory.create(
participant=self.part3,
slot=old_slot
)

self.passive_user = BlueBottleUserFactory.create(first_name='Passive')

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

mail.outbox = []

def run_task(self, when):
with mock.patch('bluebottle.activities.messages.now', return_value=when):
with mock.patch('bluebottle.activities.tasks.date') as mock_date:
mock_date.today.return_value = when.date()
mock_date.side_effect = lambda *args, **kwargs: date(*args, **kwargs)
do_good_hours_reminder()

@property
def next_year(self):
return timezone.get_current_timezone().localize(
datetime(now().year + 1, 1, 1)
)

@property
def q1(self):
return timezone.get_current_timezone().localize(
datetime(now().year, 1, 1)
)

@property
def after_q1(self):
return timezone.get_current_timezone().localize(
datetime(now().year, 1, 12)
)

@property
def after_q2(self):
return timezone.get_current_timezone().localize(
datetime(now().year, 4, 15)
)

@property
def q2(self):
return timezone.get_current_timezone().localize(
datetime(now().year, 4, 1)
)

@property
def q3(self):
return timezone.get_current_timezone().localize(
datetime(now().year, 7, 1)
)

@property
def q4(self):
return timezone.get_current_timezone().localize(
datetime(now().year, 10, 1)
)

def test_reminder_q1(self):
self.run_task(self.q1)
self.assertEqual(len(mail.outbox), 3)
self.assertEqual(
mail.outbox[0].subject,
'Are you ready to do good? Q1'
)
recipients = [m.to[0] for m in mail.outbox]
self.assertTrue(self.moderate_user.email in recipients, "Moderate user should receive email")
self.assertTrue(self.passive_user.email in recipients, "Passive user should receive email")
self.assertTrue(self.tempted_user.email in recipients, "Tempted user should receive email")

mail.outbox = []
self.run_task(self.q1)
self.assertEqual(len(mail.outbox), 0, "Reminder mail should not be send again.")

def test_reminder_after_q1(self):
self.run_task(self.after_q1)
self.assertEqual(len(mail.outbox), 0)

def test_reminder_q2(self):
SlotParticipantFactory.create(
participant=self.part3,
slot=self.slot3
)
self.run_task(self.q2)
self.assertEqual(len(mail.outbox), 2)
self.assertEqual(
mail.outbox[0].subject,
'Are you ready to do good? Q2'
)
recipients = [m.to[0] for m in mail.outbox]
self.assertTrue(self.moderate_user.email in recipients, "Moderate user should receive email")
self.assertTrue(self.passive_user.email in recipients, "Passive user should receive email")
self.assertFalse(self.tempted_user.email in recipients, "Tempted user should not receive email")

def test_reminder_q3(self):
SlotParticipantFactory.create(
participant=self.part3,
slot=self.slot3
)
self.run_task(self.q3)
self.assertEqual(len(mail.outbox), 0, 'Q3 mails should be disabled')

def test_reminder_q4(self):
SlotParticipantFactory.create(
participant=self.part3,
slot=self.slot3
)
self.part3.states.withdraw(save=True)
mail.outbox = []
self.run_task(self.q4)
self.assertEqual(len(mail.outbox), 3)
self.assertEqual(
mail.outbox[0].subject,
'Are you ready to do good? Q4'
)
recipients = [m.to[0] for m in mail.outbox]
self.assertTrue(self.moderate_user.email in recipients, "Moderate user should receive email")
self.assertTrue(self.passive_user.email in recipients, "Passive user should receive email")
self.assertTrue(self.tempted_user.email in recipients, "Tempted user should receive email, because withdrawn")

def test_reminder_q1_next_year(self):
self.run_task(self.next_year)
self.assertEqual(len(mail.outbox), 4)
self.assertEqual(
mail.outbox[0].subject,
'Are you ready to do good? Q1'
)
recipients = [m.to[0] for m in mail.outbox]
self.assertTrue(self.active_user.email in recipients, "Active user should receive email")
self.assertTrue(self.moderate_user.email in recipients, "Moderate user should receive email")
self.assertTrue(self.passive_user.email in recipients, "Passive user should receive email")
self.assertTrue(self.tempted_user.email in recipients, "Tempted user should receive email")
Loading

0 comments on commit ad18e57

Please sign in to comment.