|
19 | 19 |
|
20 | 20 | from django.conf import settings |
21 | 21 | from django.contrib import messages |
| 22 | +from django.db.models import OuterRef |
22 | 23 | from django.forms import ValidationError |
23 | 24 | from django.http import Http404 |
24 | 25 | from django.template.loader import render_to_string |
|
39 | 40 | from ietf.name.models import DocReminderTypeName, DocRelationshipName |
40 | 41 | from ietf.group.models import Role, Group, GroupFeatures |
41 | 42 | from ietf.ietfauth.utils import has_role, is_authorized_in_doc_stream, is_individual_draft_author, is_bofreq_editor |
42 | | -from ietf.person.models import Person |
| 43 | +from ietf.person.models import Email, Person |
43 | 44 | from ietf.review.models import ReviewWish |
44 | 45 | from ietf.utils import draft, log |
45 | 46 | from ietf.utils.mail import parseaddr, send_mail |
@@ -1301,9 +1302,13 @@ def get_draft_shepherd_email(self, doc): |
1301 | 1302 | def get_draft_authors_emails(self, doc): |
1302 | 1303 | """Get list of authors for the given draft.""" |
1303 | 1304 | author_emails = set() |
1304 | | - for author in doc.documentauthor_set.all(): |
1305 | | - if author.email and author.email.email_address(): |
1306 | | - author_emails.add(author.email.email_address()) |
| 1305 | + for email in Email.objects.filter(documentauthor__document=doc): |
| 1306 | + if email.active: |
| 1307 | + author_emails.add(email.address) |
| 1308 | + elif email.person: |
| 1309 | + person_email = email.person.email_address() |
| 1310 | + if person_email: |
| 1311 | + author_emails.add(person_email) |
1307 | 1312 | return author_emails |
1308 | 1313 |
|
1309 | 1314 | def get_draft_notify_emails(self, doc): |
@@ -1336,59 +1341,82 @@ def get_draft_notify_emails(self, doc): |
1336 | 1341 | notify_emails.add(email) |
1337 | 1342 | return notify_emails |
1338 | 1343 |
|
| 1344 | + def _yield_aliases_for_draft(self, doc)-> Iterator[tuple[str, list[str]]]: |
| 1345 | + alias = doc.name |
| 1346 | + all = set() |
| 1347 | + |
| 1348 | + # no suffix and .authors are the same list |
| 1349 | + emails = self.get_draft_authors_emails(doc) |
| 1350 | + all.update(emails) |
| 1351 | + if emails: |
| 1352 | + yield alias, list(emails) |
| 1353 | + yield alias + ".authors", list(emails) |
| 1354 | + |
| 1355 | + # .chairs = group chairs |
| 1356 | + emails = self.get_draft_chair_emails(doc) |
| 1357 | + if emails: |
| 1358 | + all.update(emails) |
| 1359 | + yield alias + ".chairs", list(emails) |
| 1360 | + |
| 1361 | + # .ad = sponsoring AD / WG AD (WG document) |
| 1362 | + emails = self.get_draft_ad_emails(doc) |
| 1363 | + if emails: |
| 1364 | + all.update(emails) |
| 1365 | + yield alias + ".ad", list(emails) |
| 1366 | + |
| 1367 | + # .notify = notify email list from the Document |
| 1368 | + emails = self.get_draft_notify_emails(doc) |
| 1369 | + if emails: |
| 1370 | + all.update(emails) |
| 1371 | + yield alias + ".notify", list(emails) |
| 1372 | + |
| 1373 | + # .shepherd = shepherd email from the Document |
| 1374 | + emails = self.get_draft_shepherd_email(doc) |
| 1375 | + if emails: |
| 1376 | + all.update(emails) |
| 1377 | + yield alias + ".shepherd", list(emails) |
| 1378 | + |
| 1379 | + # .all = everything from above |
| 1380 | + if all: |
| 1381 | + yield alias + ".all", list(all) |
| 1382 | + |
1339 | 1383 | def __iter__(self) -> Iterator[tuple[str, list[str]]]: |
1340 | 1384 | # Internet-Drafts with active status or expired within self.days |
1341 | 1385 | show_since = timezone.now() - datetime.timedelta(days=self.days) |
1342 | 1386 | drafts = self.draft_queryset |
1343 | | - active_drafts = drafts.filter(states__slug='active') |
1344 | | - inactive_recent_drafts = drafts.exclude(states__slug='active').filter(expires__gte=show_since) |
1345 | | - interesting_drafts = active_drafts | inactive_recent_drafts |
1346 | 1387 |
|
1347 | | - for this_draft in interesting_drafts.distinct().iterator(): |
| 1388 | + # Look up the draft-active state properly. Doing this with |
| 1389 | + # states__type_id, states__slug directly in the `filter()` |
| 1390 | + # works, but it does not work as expected in `exclude()`. |
| 1391 | + active_state = State.objects.get(type_id="draft", slug="active") |
| 1392 | + active_drafts = drafts.filter(states=active_state) |
| 1393 | + for this_draft in active_drafts: |
| 1394 | + for alias, addresses in self._yield_aliases_for_draft(this_draft): |
| 1395 | + yield alias, addresses |
| 1396 | + |
| 1397 | + # Annotate with the draft state slug so we can check for drafts that |
| 1398 | + # have become RFCs |
| 1399 | + inactive_recent_drafts = ( |
| 1400 | + drafts.exclude(states=active_state) |
| 1401 | + .filter(expires__gte=show_since) |
| 1402 | + .annotate( |
| 1403 | + # Why _default_manager instead of objects? See: |
| 1404 | + # https://docs.djangoproject.com/en/4.2/topics/db/managers/#django.db.models.Model._default_manager |
| 1405 | + draft_state_slug=Document.states.through._default_manager.filter( |
| 1406 | + document__pk=OuterRef("pk"), |
| 1407 | + state__type_id="draft" |
| 1408 | + ).values("state__slug"), |
| 1409 | + ) |
| 1410 | + ) |
| 1411 | + for this_draft in inactive_recent_drafts: |
1348 | 1412 | # Omit drafts that became RFCs, unless they were published in the last DEFAULT_YEARS |
1349 | | - if this_draft.get_state_slug() == "rfc": |
| 1413 | + if this_draft.draft_state_slug == "rfc": |
1350 | 1414 | rfc = this_draft.became_rfc() |
1351 | 1415 | log.assertion("rfc is not None") |
1352 | 1416 | if rfc.latest_event(type='published_rfc').time < show_since: |
1353 | 1417 | continue |
1354 | | - |
1355 | | - alias = this_draft.name |
1356 | | - all = set() |
1357 | | - |
1358 | | - # no suffix and .authors are the same list |
1359 | | - emails = self.get_draft_authors_emails(this_draft) |
1360 | | - all.update(emails) |
1361 | | - if emails: |
1362 | | - yield alias, list(emails) |
1363 | | - yield alias + ".authors", list(emails) |
1364 | | - |
1365 | | - # .chairs = group chairs |
1366 | | - emails = self.get_draft_chair_emails(this_draft) |
1367 | | - if emails: |
1368 | | - all.update(emails) |
1369 | | - yield alias + ".chairs", list(emails) |
1370 | | - |
1371 | | - # .ad = sponsoring AD / WG AD (WG document) |
1372 | | - emails = self.get_draft_ad_emails(this_draft) |
1373 | | - if emails: |
1374 | | - all.update(emails) |
1375 | | - yield alias + ".ad", list(emails) |
1376 | | - |
1377 | | - # .notify = notify email list from the Document |
1378 | | - emails = self.get_draft_notify_emails(this_draft) |
1379 | | - if emails: |
1380 | | - all.update(emails) |
1381 | | - yield alias + ".notify", list(emails) |
1382 | | - |
1383 | | - # .shepherd = shepherd email from the Document |
1384 | | - emails = self.get_draft_shepherd_email(this_draft) |
1385 | | - if emails: |
1386 | | - all.update(emails) |
1387 | | - yield alias + ".shepherd", list(emails) |
1388 | | - |
1389 | | - # .all = everything from above |
1390 | | - if all: |
1391 | | - yield alias + ".all", list(all) |
| 1418 | + for alias, addresses in self._yield_aliases_for_draft(this_draft): |
| 1419 | + yield alias, addresses |
1392 | 1420 |
|
1393 | 1421 |
|
1394 | 1422 | def get_doc_email_aliases(name: Optional[str] = None): |
|
0 commit comments