diff --git a/ietf/nomcom/management/commands/send_reminders.py b/ietf/nomcom/management/commands/send_reminders.py index 7d1350bc5..b49d81b02 100644 --- a/ietf/nomcom/management/commands/send_reminders.py +++ b/ietf/nomcom/management/commands/send_reminders.py @@ -20,16 +20,12 @@ class Command(BaseCommand): def handle(self, *args, **options): for nomcom in NomCom.objects.filter(group__state__slug='active'): - for state in ('pending','accepted'): - for nominee_position in NomineePosition.objects.filter(nominee__nomcom=nomcom, - state=state, - nominee__duplicated__isnull=True): - if is_time_to_send(nomcom, datetime.date.today(), nominee_position.time.date()): - if state=='pending': - send_accept_reminder_to_nominee(nominee_position) - log('Sent accept reminder to %s' % nominee_position.nominee.email.address) - elif state=='accepted': - send_questionnaire_reminder_to_nominee(nominee_position) - log('Sent questionnaire reminder to %s' % nominee_position.nominee.email.address) - else: - pass + nps = NomineePosition.objects.filter(nominee__nomcom=nomcom,nominee__duplicated__isnull=True) + for nominee_position in nps.pending(): + if is_time_to_send(nomcom, datetime.date.today(), nominee_position.time.date()): + send_accept_reminder_to_nominee(nominee_position) + log('Sent accept reminder to %s' % nominee_position.nominee.email.address) + for nominee_position in nps.accepted().without_questionnaire_response(): + if is_time_to_send(nomcom, datetime.date.today(), nominee_position.time.date()): + send_questionnaire_reminder_to_nominee(nominee_position) + log('Sent questionnaire reminder to %s' % nominee_position.nominee.email.address) diff --git a/ietf/nomcom/managers.py b/ietf/nomcom/managers.py index 302229c38..c6b719c3f 100644 --- a/ietf/nomcom/managers.py +++ b/ietf/nomcom/managers.py @@ -33,6 +33,13 @@ class NomineePositionQuerySet(QuerySet): def not_duplicated(self): return self.filter(nominee__duplicated__isnull=True) + def with_questionnaire_response(self): + return self.filter(nominee__feedback__type='questio',nominee__feedback__positions=models.F('position')).distinct() + + def without_questionnaire_response(self): + with_ids = self.with_questionnaire_response().values_list('id', flat=True) + return self.exclude(id__in=with_ids) + class NomineePositionManager(models.Manager, MixinManager): def get_query_set(self): diff --git a/ietf/nomcom/tests.py b/ietf/nomcom/tests.py index 3a10ad102..73061570e 100644 --- a/ietf/nomcom/tests.py +++ b/ietf/nomcom/tests.py @@ -14,6 +14,7 @@ from ietf.utils.mail import outbox from ietf.person.models import Email, Person +from django.contrib.auth.models import User from ietf.nomcom.test_data import nomcom_test_data, generate_cert, check_comments, \ COMMUNITY_USER, CHAIR_USER, \ @@ -657,12 +658,15 @@ class FeedbackTest(TestCase): os.unlink(self.privatekey_file.name) os.unlink(self.cert_file.name) -class ReminderCommandTest(TestCase): +class ReminderTest(TestCase): perma_fixtures = ['names', 'nomcom_templates'] def setUp(self): nomcom_test_data() self.nomcom = get_nomcom_by_year(NOMCOM_YEAR) + self.cert_file, self.privatekey_file = generate_cert() + self.nomcom.public_key.storage.location = tempfile.gettempdir() + self.nomcom.public_key.save('cert', File(open(self.cert_file.name, 'r'))) gen = Position.objects.get(nomcom=self.nomcom,name='GEN') rai = Position.objects.get(nomcom=self.nomcom,name='RAI') @@ -684,6 +688,17 @@ class ReminderCommandTest(TestCase): np = n.nomineeposition_set.get(position=rai) np.time = t_minus_4 np.save() + n = get_or_create_nominee(self.nomcom,"Nominee 2","nominee2@example.org",gen,None) + np = n.nomineeposition_set.get(position=gen) + np.state = NomineePositionState.objects.get(slug='accepted') + np.time = t_minus_4 + np.save() + feedback = Feedback.objects.create(nomcom=self.nomcom, + comments='some non-empty comments', + type=FeedbackType.objects.get(slug='questio'), + user=User.objects.get(username=CHAIR_USER)) + feedback.positions.add(gen) + feedback.nominees.add(n) def test_is_time_to_send(self): self.nomcom.reminder_interval = 4 @@ -714,5 +729,22 @@ class ReminderCommandTest(TestCase): self.assertEqual(len(outbox), messages_before + 1) self.assertTrue('nominee2@example.org' in outbox[-1]['To']) self.assertTrue('please accept' in outbox[-1]['Subject']) - + def test_remind_accept_view(self): + url = reverse('nomcom_send_reminder_mail', kwargs={'year': NOMCOM_YEAR,'type':'accept'}) + login_testing_unauthorized(self, CHAIR_USER, url) + messages_before=len(outbox) + test_data = {'selected': [x.id for x in Nominee.objects.filter(nomcom=self.nomcom)]} + response = self.client.post(url, test_data) + self.assertEqual(response.status_code, 200) + self.assertEqual(len(outbox), messages_before + 2) + + def test_remind_questionnaire_view(self): + url = reverse('nomcom_send_reminder_mail', kwargs={'year': NOMCOM_YEAR,'type':'questionnaire'}) + login_testing_unauthorized(self, CHAIR_USER, url) + messages_before=len(outbox) + test_data = {'selected': [x.id for x in Nominee.objects.filter(nomcom=self.nomcom)]} + response = self.client.post(url, test_data) + self.assertEqual(response.status_code, 200) + self.assertEqual(len(outbox), messages_before + 1) + diff --git a/ietf/nomcom/utils.py b/ietf/nomcom/utils.py index 4361cacd6..cb9249837 100644 --- a/ietf/nomcom/utils.py +++ b/ietf/nomcom/utils.py @@ -263,7 +263,7 @@ def send_reminder_to_nominees(nominees,type): addrs.append(nominee_position.nominee.email.address) elif type=='questionnaire': for nominee in nominees: - for nominee_position in nominee.nomineeposition_set.accepted(): + for nominee_position in nominee.nomineeposition_set.accepted().without_questionnaire_response(): send_questionnaire_reminder_to_nominee(nominee_position) addrs.append(nominee_position.nominee.email.address) return addrs diff --git a/ietf/nomcom/views.py b/ietf/nomcom/views.py index 0c01d1b95..05381d07d 100644 --- a/ietf/nomcom/views.py +++ b/ietf/nomcom/views.py @@ -173,18 +173,26 @@ def send_reminder_mail(request, year, type): mail_path = nomcom_template_path + NOMINEE_ACCEPT_REMINDER_TEMPLATE reminder_description = 'accept (or decline) a nomination' selected_tab = 'send_accept_reminder' + state_description = NomineePositionState.objects.get(slug=interesting_state).name elif type=='questionnaire': interesting_state = 'accepted' mail_path = nomcom_template_path + NOMINEE_QUESTIONNAIRE_REMINDER_TEMPLATE reminder_description = 'complete the questionnaire for a nominated position' selected_tab = 'send_questionnaire_reminder' + state_description = NomineePositionState.objects.get(slug=interesting_state).name+' but no questionnaire has been received' else: raise Http404 nominees = Nominee.objects.get_by_nomcom(nomcom).not_duplicated().filter(nomineeposition__state=interesting_state).distinct() - annotated_nominees = list(nominees) - for nominee in annotated_nominees: - nominee.interesting_positions = [x.position.name for x in nominee.nomineeposition_set.all() if x.state.slug==interesting_state] + annotated_nominees = [] + for nominee in nominees: + if type=='accept': + nominee.interesting_positions = [x.position.name for x in nominee.nomineeposition_set.pending()] + else: + nominee.interesting_positions = [x.position.name for x in nominee.nomineeposition_set.accepted().without_questionnaire_response()] + if nominee.interesting_positions: + annotated_nominees.append(nominee) + mail_template = DBTemplate.objects.filter(group=nomcom.group, path=mail_path) mail_template = mail_template and mail_template[0] or None message = None @@ -197,7 +205,7 @@ def send_reminder_mail(request, year, type): if addrs: message = ('success', 'A copy of "%s" has been sent to %s'%(mail_template.title,", ".join(addrs))) else: - message = {'warning', 'No messages were sent.'} + message = ('warning', 'No messages were sent.') else: message = ('warning', "Please, select at least one nominee") return render_to_response('nomcom/send_reminder_mail.html', @@ -207,7 +215,7 @@ def send_reminder_mail(request, year, type): 'mail_template': mail_template, 'selected': selected_tab, 'reminder_description': reminder_description, - 'state_description': NomineePositionState.objects.get(slug=interesting_state).name, + 'state_description': state_description, 'message': message}, RequestContext(request))