diff --git a/doc/configure_instance.rst b/doc/configure_instance.rst index 5c52e5de3a93b962833a256dfa30efabc0b404c5..1fbcba1aa2c71791313536b23d99fc8eb599b0fd 100644 --- a/doc/configure_instance.rst +++ b/doc/configure_instance.rst @@ -358,6 +358,12 @@ Reviewers can express their conflicts of interest Reviewers can indicate that they have conflict of interest when reviewing a candidate. They can also indicate that they don't want to review a candidate. To do se the application have to be configured so they see the candidate list in https://strass-master.dev.pasteur.cloud/setup/#review-settings . +Reminding reviewers to indicate their profiles +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Reviewers should have already indicated which profile they accepte to review. +If some have forgotten it, you can use the :ref:`Mass Mailing` to automatically select this subset of reviewers and remind them to do it. + Assign reviewers ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Link: https://strass-master.dev.pasteur.cloud/setup/review/overview/ diff --git a/doc/mass_mailing.rst b/doc/mass_mailing.rst index ea7a1a5579e5cedc70e4e9b0e4b78b00b512f8d6..782da9a450fcf3b9ea9363ad8667f262f74586f7 100644 --- a/doc/mass_mailing.rst +++ b/doc/mass_mailing.rst @@ -44,6 +44,9 @@ There are multiple recipients group, some such as ``Reviewers`` are explicit eno **Reviewers with editable reviews not completed**: The reviewers that are associated to a review that is both empty and in a review stage that still allows to provide a review. +**Reviewers that haven't indicated reviewable profiles**: +The reviewers that haven't specified the candidate's profiles they are willing to review. + **Pending reviewer**: Users that have accepted to be reviewer, but have not been yet confirmed as reviewer, or refused. diff --git a/src/strass/strass_app/forms.py b/src/strass/strass_app/forms.py index b0817194768c570e5a7a1f7811f413fdb1f59df1..1a0436e4fcecf79728c27e751ceea28687fb4a81 100644 --- a/src/strass/strass_app/forms.py +++ b/src/strass/strass_app/forms.py @@ -1631,6 +1631,7 @@ class MassMailingForm(forms.Form): for key, text in [ ('reviewers', _("Reviewers (%i)")), ('reviewers_with_review_todo', _("Reviewers with editable reviews not completed (%i)")), + ('reviewers_without_profile', _("Reviewers with no associated profile (%i)")), ('pending_reviewers', _("Pending reviewers (%i)")), ('jurors', _("Jurors (%i)")), ('pending_jurors', _("Pending jurors (%i)")), @@ -1671,6 +1672,10 @@ class MassMailingForm(forms.Form): .filter(is_open_for_edition=True, is_completed=False) .values_list('reviewer__pk', flat=True) ) + if recipients == "reviewers_without_profile": + return business_logic.get_reviewers().exclude( + pk__in=business_logic.get_reviewers().filter(user_preferences__profiles__pk__isnull=False) + ) if recipients == "jurors": return business_logic.get_jurors() if recipients == "pending_jurors": diff --git a/src/strass/strass_app/locale/en/LC_MESSAGES/django.po b/src/strass/strass_app/locale/en/LC_MESSAGES/django.po index 6798b5673e49554ab2091271009e76468c52063f..63b137f638cf881adfc16a3bf71ebd674b0d0a26 100644 --- a/src/strass/strass_app/locale/en/LC_MESSAGES/django.po +++ b/src/strass/strass_app/locale/en/LC_MESSAGES/django.po @@ -10,7 +10,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2025-02-12 18:54+0100\n" +"POT-Creation-Date: 2025-02-28 09:44+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Language-Team: LANGUAGE <LL@li.org>\n" @@ -744,6 +744,10 @@ msgstr "" msgid "Reviewers with editable reviews not completed (%i)" msgstr "" +#, python-format +msgid "Reviewers with no associated profile (%i)" +msgstr "Reviewers that haven't indicated reviewable profiles (%i)" + #, python-format msgid "Pending reviewers (%i)" msgstr "" diff --git a/src/strass/strass_app/locale/fr/LC_MESSAGES/django.po b/src/strass/strass_app/locale/fr/LC_MESSAGES/django.po index f88d736dd13f6f0c62ff6411f54934ba8634f163..5828bdc68c767dd50cacbe72a569474e98ba8b4c 100644 --- a/src/strass/strass_app/locale/fr/LC_MESSAGES/django.po +++ b/src/strass/strass_app/locale/fr/LC_MESSAGES/django.po @@ -10,7 +10,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2025-02-12 18:54+0100\n" +"POT-Creation-Date: 2025-02-28 09:47+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Language-Team: LANGUAGE <LL@li.org>\n" @@ -796,6 +796,10 @@ msgstr "Reviewers (%i)" msgid "Reviewers with editable reviews not completed (%i)" msgstr "Reviewers avec des reviews éditables et pas encore finalisées (%i)" +#, python-format +msgid "Reviewers with no associated profile (%i)" +msgstr "Reviewers qui n'ont pas indiqués leur profiles (%i)" + #, python-format msgid "Pending reviewers (%i)" msgstr "Reviewers potentiels (%i)" diff --git a/src/strass/strass_app/tests/test_mass_mailing.py b/src/strass/strass_app/tests/test_mass_mailing.py index f3261cb0039eb17cf5ce88e728d113b2d13685ed..9d0ffe995f4509929d753b8f739238f08d360d73 100644 --- a/src/strass/strass_app/tests/test_mass_mailing.py +++ b/src/strass/strass_app/tests/test_mass_mailing.py @@ -532,6 +532,74 @@ class TestViews2(BaseTestCase): self.assertIn(f'http://testserver{reverse("strass:review-detail", args=[pk])}', m.body) +@override_settings( + MEDIA_ROOT=os.path.join( + settings.BASE_DIR, + 'persistent_volume', + f'{MEDIA_DIR}_3', + ), + STORAGE_ROOT=os.path.join( + settings.BASE_DIR, + 'persistent_volume', + '.storage_for_test_3', + ), +) +class TestViews3(BaseTestCase): + def test_reviewers_without_profils(self): + steps = list() + live_settings.show_email_as_message = False + mail_count = len(mail.outbox) + self.client.force_login(self.jury_manager) + business_logic.get_reviewers().first().profiles.clear() + business_logic.get_reviewers().last().profiles.clear() + self.assertTrue(models.Profile.objects.first().myuserpreferences_set.all().exists()) + self.assertFalse(business_logic.get_reviewers().first().profiles.exists()) + + ####################################################################### + # Use user group, also send a test email + ####################################################################### + url = reverse('strass:mass-mailing') + response_home = self.client.get(url, follow=True) + target = response_home.redirect_chain[0][0] + step_name = target.split("/")[-2] + form_data = { + step_name + "-sender": self.jury_manager.pk, + step_name + "-recipients": "reviewers_without_profile", + step_name + "-subject": "mail subject", + step_name + "-body": "hi [first_name] x [last_name] !", + "mass_mailing_wizard-current_step": step_name, + } + response = self.client.post(target, form_data, follow=True) + self.assertEqual(response.status_code, 200) + steps.append(WizardStep(target=target, response=response, form_data=form_data, step_name=step_name)) + self.write_in_tmp_file(response) + del target, response, form_data, step_name + + target = steps[-1].response.redirect_chain[0][0] + step_name = target.split("/")[-2] + form_data = { + step_name + "-agree": 'on', + "mass_mailing_wizard-current_step": step_name, + } + response = self.client.post(target, form_data, follow=True) + self.assertEqual(response.status_code, 200) + steps.append(WizardStep(target=target, response=response, form_data=form_data, step_name=step_name)) + del target, response, form_data, step_name + + recipients = set() + for m in mail.outbox[mail_count:]: + recipients |= set(m.recipients()) + + self.assertEqual( + recipients, + { + business_logic.get_reviewers().get(pk=1).email, + business_logic.get_reviewers().first().email, + business_logic.get_reviewers().last().email, + }, + ) + + class _TestViews(BaseTestCase): def _test_with_reviewers(self): steps = list()