Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ticket/bb 20531 task for q mails #5218

Merged
merged 6 commits into from
Aug 31, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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)),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would this happen twice since the interval is 10 hours?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought this would run every day at 10:00. Interval would be hours="*/10", not? Crontabs always confuse me...

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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