diff --git a/ietf/doc/mails.py b/ietf/doc/mails.py index 28a26ead8..3948d775c 100644 --- a/ietf/doc/mails.py +++ b/ietf/doc/mails.py @@ -635,3 +635,12 @@ def email_charter_internal_review(request, charter): cc=addrs.cc, extra={'Reply-To': ["irsg@irtf.org" if charter.group.type_id == 'rg' else "iesg@ietf.org", ]}, ) + +def email_lc_to_yang_doctors(request, doc): + addrs = gather_address_lists('last_call_of_doc_with_yang_issued') + send_mail(request, addrs.to, settings.DEFAULT_FROM_EMAIL, + 'Attn YangDoctors: IETF LC issued for %s' % doc.name , + 'doc/mail/lc_to_yang_doctors.txt', + dict(doc=doc, url=settings.IDTRACKER_BASE_URL + doc.get_absolute_url() ), + cc = addrs.cc, + ) \ No newline at end of file diff --git a/ietf/doc/tests.py b/ietf/doc/tests.py index 247e43d31..288fac75f 100644 --- a/ietf/doc/tests.py +++ b/ietf/doc/tests.py @@ -1220,6 +1220,7 @@ class EmailAliasesTests(TestCase): def setUp(self): WgDraftFactory(name='draft-ietf-mars-test',group__acronym='mars') WgDraftFactory(name='draft-ietf-ames-test',group__acronym='ames') + RoleFactory(group__type_id='review', group__acronym='yangdoctors', name_id='secr') self.doc_alias_file = NamedTemporaryFile(delete=False, mode='w+') self.doc_alias_file.write("""# Generated by hand at 2015-02-12_16:26:45 virtual.ietf.org anything diff --git a/ietf/doc/tests_ballot.py b/ietf/doc/tests_ballot.py index 3c1f670e3..d72441b4a 100644 --- a/ietf/doc/tests_ballot.py +++ b/ietf/doc/tests_ballot.py @@ -16,7 +16,7 @@ from ietf.doc.models import ( Document, State, DocEvent, from ietf.doc.factories import DocumentFactory, IndividualDraftFactory, IndividualRfcFactory, WgDraftFactory from ietf.doc.utils import create_ballot_if_not_open from ietf.group.models import Group, Role -from ietf.group.factories import GroupFactory, RoleFactory +from ietf.group.factories import GroupFactory, RoleFactory, ReviewTeamFactory from ietf.ipr.factories import HolderIprDisclosureFactory from ietf.name.models import BallotPositionName from ietf.iesg.models import TelechatDate @@ -804,6 +804,42 @@ class MakeLastCallTests(TestCase): self.assertTrue("Last Call" in draft.message_set.order_by("-time")[0].subject) + def test_make_last_call_yang_document(self): + yd = ReviewTeamFactory(acronym='yangdoctors') + secr_email = RoleFactory(group=yd,name_id='secr').person.email().address + draft = WgDraftFactory() + submission = draft.submission_set.create( + state_id = 'posted', + name = draft.name, + group = draft.group, + rev = draft.rev, + authors = '[]', + ) + submission.checks.create( + checker = 'yang validation', + passed = True, + ) + + + url = urlreverse('ietf.doc.views_ballot.make_last_call', kwargs=dict(name=draft.name)) + login_testing_unauthorized(self, 'secretary', url) + + mailbox_before = len(outbox) + + last_call_sent_date = datetime.date.today() + expire_date = last_call_sent_date+datetime.timedelta(days=14) + + r = self.client.post(url, + dict(last_call_sent_date=last_call_sent_date, + last_call_expiration_date=expire_date + )) + self.assertEqual(r.status_code, 302) + self.assertEqual(len(outbox), mailbox_before + 3) + self.assertIn("ietf-announce@", outbox[-3]['To']) + self.assertIn("drafts-lastcall@icann.org", outbox[-2]['To']) + self.assertIn(secr_email, outbox[-1]['To']) + + class DeferUndeferTestCase(TestCase): def helper_test_defer(self,name): diff --git a/ietf/doc/views_ballot.py b/ietf/doc/views_ballot.py index 2ba13ed66..f8a992e14 100644 --- a/ietf/doc/views_ballot.py +++ b/ietf/doc/views_ballot.py @@ -26,7 +26,8 @@ from ietf.doc.utils import ( add_state_change_event, close_ballot, close_open_ba from ietf.doc.mails import ( email_ballot_deferred, email_ballot_undeferred, extra_automation_headers, generate_last_call_announcement, generate_issue_ballot_mail, generate_ballot_writeup, generate_ballot_rfceditornote, - generate_approval_mail, email_irsg_ballot_closed, email_irsg_ballot_issued ) + generate_approval_mail, email_irsg_ballot_closed, email_irsg_ballot_issued, + email_lc_to_yang_doctors ) from ietf.doc.lastcall import request_last_call from ietf.doc.templatetags.ietf_filters import can_ballot from ietf.iesg.models import TelechatDate @@ -1046,6 +1047,10 @@ def make_last_call(request, name): doc.save_with_history(events) + sub = doc.submission() + if sub and sub.has_yang(): + email_lc_to_yang_doctors(request, doc) + return HttpResponseRedirect(doc.get_absolute_url()) else: initial = {} diff --git a/ietf/mailtrigger/migrations/0017_lc_to_yang_doctors.py b/ietf/mailtrigger/migrations/0017_lc_to_yang_doctors.py new file mode 100644 index 000000000..6685d857f --- /dev/null +++ b/ietf/mailtrigger/migrations/0017_lc_to_yang_doctors.py @@ -0,0 +1,38 @@ +# Copyright The IETF Trust 2019-2020, All Rights Reserved + +from django.db import migrations + +def forward(apps, schema_editor): + MailTrigger = apps.get_model('mailtrigger', 'MailTrigger') + Recipient = apps.get_model('mailtrigger', 'Recipient') + + Recipient.objects.create( + slug = 'yang_doctors_secretaries', + desc = 'Yang Doctors Secretaries', + template = '' + ) + + lc_to_yang_doctors = MailTrigger.objects.create( + slug='last_call_of_doc_with_yang_issued', + desc='Recipients when IETF LC is issued on a document with yang checks', + ) + + lc_to_yang_doctors.to.set(Recipient.objects.filter(slug='yang_doctors_secretaries')) + +def reverse(apps, schema_editor): + MailTrigger = apps.get_model('mailtrigger', 'MailTrigger') + Recipient = apps.get_model('mailtrigger', 'Recipient') + + MailTrigger.objects.filter(slug='last_call_of_doc_with_yang_issued').delete() + Recipient.objects.filter(slug='yang_doctors_secretaries').delete() + + +class Migration(migrations.Migration): + + dependencies = [ + ('mailtrigger', '0016_add_irsg_ballot_issued'), + ] + + operations = [ + migrations.RunPython(forward, reverse), + ] diff --git a/ietf/mailtrigger/models.py b/ietf/mailtrigger/models.py index c1b1dedb3..3df49bf45 100644 --- a/ietf/mailtrigger/models.py +++ b/ietf/mailtrigger/models.py @@ -7,6 +7,7 @@ from django.template import Template, Context from email.utils import parseaddr from ietf.utils.mail import formataddr, get_email_addresses_from_text +from ietf.group.models import Group from ietf.person.models import Email, Alias from ietf.review.models import ReviewTeamSettings @@ -367,3 +368,6 @@ class Recipient(models.Model): for role in review_req.team.parent.role_set.filter(name='ad'): addrs.append(role.email.address) return addrs + + def gather_yang_doctors_secretaries(self, **kwargs): + return self.gather_group_secretaries(group=Group.objects.get(acronym='yangdoctors')) diff --git a/ietf/name/fixtures/names.json b/ietf/name/fixtures/names.json index d9f2ef3de..21253571c 100644 --- a/ietf/name/fixtures/names.json +++ b/ietf/name/fixtures/names.json @@ -3940,6 +3940,17 @@ "model": "mailtrigger.mailtrigger", "pk": "last_call_issued_iana" }, + { + "fields": { + "cc": [], + "desc": "Recipients when IETF LC is issued on a document with yang checks", + "to": [ + "yang_doctors_secretaries" + ] + }, + "model": "mailtrigger.mailtrigger", + "pk": "last_call_of_doc_with_yang_issued" + }, { "fields": { "cc": [ @@ -5543,6 +5554,14 @@ "model": "mailtrigger.recipient", "pk": "submission_submitter" }, + { + "fields": { + "desc": "Yang Doctors Secretaries", + "template": "" + }, + "model": "mailtrigger.recipient", + "pk": "yang_doctors_secretaries" + }, { "fields": { "name": "Area meetings cannot conflict with anything else in their area", @@ -14886,7 +14905,7 @@ "fields": { "command": "xym", "switch": "--version", - "time": "2020-08-04T00:13:15.604", + "time": "2020-08-12T00:12:54.984", "used": true, "version": "xym 0.4.8" }, @@ -14897,7 +14916,7 @@ "fields": { "command": "pyang", "switch": "--version", - "time": "2020-08-04T00:13:16.892", + "time": "2020-08-12T00:12:56.359", "used": true, "version": "pyang 2.3.2" }, @@ -14908,7 +14927,7 @@ "fields": { "command": "yanglint", "switch": "--version", - "time": "2020-08-04T00:13:17.151", + "time": "2020-08-12T00:12:56.632", "used": true, "version": "yanglint SO 1.6.7" }, @@ -14919,7 +14938,7 @@ "fields": { "command": "xml2rfc", "switch": "--version", - "time": "2020-08-04T00:13:18.980", + "time": "2020-08-12T00:12:58.366", "used": true, "version": "xml2rfc 2.47.0" }, diff --git a/ietf/submit/models.py b/ietf/submit/models.py index ae21aec92..2a71e3416 100644 --- a/ietf/submit/models.py +++ b/ietf/submit/models.py @@ -73,6 +73,9 @@ class Submission(models.Model): def latest_checks(self): checks = [ self.checks.filter(checker=c).latest('time') for c in self.checks.values_list('checker', flat=True).distinct() ] return checks + + def has_yang(self): + return any ( [ c.checker=='yang validation' and c.passed is not None for c in self.latest_checks()] ) class SubmissionCheck(models.Model): time = models.DateTimeField(default=datetime.datetime.now) diff --git a/ietf/templates/doc/mail/lc_to_yang_doctors.txt b/ietf/templates/doc/mail/lc_to_yang_doctors.txt new file mode 100644 index 000000000..80b82c909 --- /dev/null +++ b/ietf/templates/doc/mail/lc_to_yang_doctors.txt @@ -0,0 +1,4 @@ +{% load ietf_filters %}{% autoescape off %}{% filter wordwrap:78 %} +IETF Last Call has been issued for a document with yang checks. + +The document is available at {{ url }}{% endfilter %}{% endautoescape %} \ No newline at end of file