diff --git a/data/admin/user.py b/data/admin/user.py index e0d098f74..2a148584d 100644 --- a/data/admin/user.py +++ b/data/admin/user.py @@ -75,6 +75,7 @@ class MaCanteenUserAdmin(UserAdmin): _("Emails automatiques"), { "fields": ( + "opt_out_reminder_emails", "email_no_canteen_first_reminder", "email_no_canteen_second_reminder", ), diff --git a/data/migrations/0084_user_opt_out_reminder_emails.py b/data/migrations/0084_user_opt_out_reminder_emails.py new file mode 100644 index 000000000..957a94d99 --- /dev/null +++ b/data/migrations/0084_user_opt_out_reminder_emails.py @@ -0,0 +1,18 @@ +# Generated by Django 4.0.6 on 2022-07-26 16:18 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('data', '0083_diagnostic_diagnostic_type'), + ] + + operations = [ + migrations.AddField( + model_name='user', + name='opt_out_reminder_emails', + field=models.BooleanField(default='False', verbose_name='Désactiver les emails de rappel'), + ), + ] diff --git a/data/models/user.py b/data/models/user.py index 084a7773e..9a643e9e5 100644 --- a/data/models/user.py +++ b/data/models/user.py @@ -58,6 +58,8 @@ class Sources(models.TextChoices): email = models.EmailField(_("email address"), unique=True) email_confirmed = models.BooleanField(default="False", verbose_name="adresse email confirmée") + opt_out_reminder_emails = models.BooleanField(default="False", verbose_name="Désactiver les emails de rappel") + law_awareness = ChoiceArrayField( base_field=models.CharField(max_length=255, choices=LawAwareness.choices), blank=True, diff --git a/macantine/tasks.py b/macantine/tasks.py index 2fad2f853..0b1e19752 100644 --- a/macantine/tasks.py +++ b/macantine/tasks.py @@ -35,6 +35,7 @@ def no_canteen_first_reminder(): canteens=None, date_joined__lte=threshold, email_no_canteen_first_reminder__isnull=True, + opt_out_reminder_emails=False, ).all() if not users: logger.info("no_canteen_first_reminder: No users to notify.") @@ -69,6 +70,7 @@ def no_canteen_second_reminder(): date_joined__lte=threshold, email_no_canteen_first_reminder__lte=first_reminder_threshold, email_no_canteen_second_reminder__isnull=True, + opt_out_reminder_emails=False, ).all() if not users: logger.info("no_canteen_second_reminder: No users to notify.") @@ -109,7 +111,7 @@ def no_diagnostic_first_reminder(): logger.info(f"no_diagnostic_first_reminder: {len(canteens)} canteens to notify.") for canteen in canteens: - for manager in canteen.managers.all(): + for manager in canteen.managers.filter(opt_out_reminder_emails=False): try: parameters = {"PRENOM": manager.first_name, "NOM_CANTINE": canteen.name} diff --git a/macantine/tests/test_automatic_emails.py b/macantine/tests/test_automatic_emails.py index eff336291..e8718189f 100644 --- a/macantine/tests/test_automatic_emails.py +++ b/macantine/tests/test_automatic_emails.py @@ -310,3 +310,96 @@ def test_no_diagnostic_first_reminder(self, _): # DB objects are updated canteen_no_diagnostics.refresh_from_db() self.assertIsNotNone(canteen_no_diagnostics.email_no_diagnostic_first_reminder) + + @mock.patch("macantine.tasks._send_sib_template") + @override_settings(TEMPLATE_ID_NO_CANTEEN_FIRST=1) + @override_settings(ANYMAIL={"SENDINBLUE_API_KEY": "fake-api-key"}) + def test_email_opt_out_first_reminder(self, _): + """ + The email should not be sent to users that have opted-out of the + reminder emails. + """ + today = timezone.now() + + jean = UserFactory.create( + date_joined=(today - timedelta(weeks=1)), + email_no_canteen_first_reminder=None, + first_name="Jean", + last_name="Sérien", + email="jean.serien@example.com", + opt_out_reminder_emails=True, + ) + tasks.no_canteen_first_reminder() + + tasks._send_sib_template.assert_not_called() + + self.assertIsNone(jean.email_no_canteen_first_reminder) + + @mock.patch("macantine.tasks._send_sib_template") + @override_settings(TEMPLATE_ID_NO_CANTEEN_SECOND=2) + @override_settings(ANYMAIL={"SENDINBLUE_API_KEY": "fake-api-key"}) + def test_opt_out_second_reminder(self, _): + """ + The email should not be sent to users that have opted-out of the + reminder emails. + """ + today = timezone.now() + + marie = UserFactory.create( + date_joined=(today - timedelta(weeks=2)), + email_no_canteen_first_reminder=(today - timedelta(weeks=1)), + email_no_canteen_second_reminder=None, + first_name="Marie", + last_name="Olait", + email="marie.olait@example.com", + opt_out_reminder_emails=True, + ) + tasks.no_canteen_second_reminder() + + tasks._send_sib_template.assert_not_called() + + marie.refresh_from_db() + + self.assertIsNone(marie.email_no_canteen_second_reminder) + + @mock.patch("macantine.tasks._send_sib_template") + @override_settings(TEMPLATE_ID_NO_DIAGNOSTIC_FIRST=1) + @override_settings(ANYMAIL={"SENDINBLUE_API_KEY": "fake-api-key"}) + def test_opt_out_no_diagnostic_first_reminder(self, _): + """ + The email should not be sent to users that have opted-out of the + reminder emails. + """ + today = timezone.now() + + # Only Anna should receive the email since Jean has opted out + jean = UserFactory.create( + first_name="Jean", + last_name="Sérien", + email="jean.serien@example.com", + opt_out_reminder_emails=True, + ) + anna = UserFactory.create( + first_name="Anna", + last_name="Logue", + email="anna.logue@example.com", + ) + canteen_no_diagnostics = CanteenFactory.create( + managers=[ + anna, + jean, + ] + ) + Canteen.objects.filter(pk=canteen_no_diagnostics.id).update(creation_date=(today - timedelta(weeks=2))) + + tasks.no_diagnostic_first_reminder() + + # Email is only sent once to Anna + tasks._send_sib_template.assert_called + self.assertEqual(tasks._send_sib_template.call_count, 1) + call_args_list = tasks._send_sib_template.call_args_list + self.assertEqual(call_args_list[0][0][2], "anna.logue@example.com") + + # DB objects are updated + canteen_no_diagnostics.refresh_from_db() + self.assertIsNotNone(canteen_no_diagnostics.email_no_diagnostic_first_reminder)