# Copyright The IETF Trust 2015-2020, All Rights Reserved # -*- coding: utf-8 -*- from django.db import models 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 import debug # pyflakes:ignore def clean_duplicates(addrlist): address_info = {} for a in addrlist: (name,addr) = parseaddr(a) # This collapses duplicate addresses to one, using (arbitrarily) the # name from the last one: address_info[addr] = (name, a) addresses = [] for addr, info in address_info.items(): name, a = info if (name,addr)==('',''): addresses.append(a) elif name: addresses.append(formataddr((name,addr))) else: addresses.append(addr) return addresses class MailTrigger(models.Model): slug = models.CharField(max_length=64, primary_key=True) desc = models.TextField(blank=True) to = models.ManyToManyField('Recipient', blank=True, related_name='used_in_to') cc = models.ManyToManyField('Recipient', blank=True, related_name='used_in_cc') class Meta: ordering = ["slug"] def __str__(self): return self.slug class Recipient(models.Model): slug = models.CharField(max_length=32, primary_key=True) desc = models.TextField(blank=True) template = models.TextField(null=True, blank=True) class Meta: ordering = ["slug"] def __str__(self): return self.slug def gather(self, **kwargs): retval = [] if hasattr(self,'gather_%s'%self.slug): retval.extend(eval('self.gather_%s(**kwargs)'%self.slug)) if self.template: rendering = Template('{%% autoescape off %%}%s{%% endautoescape %%}'%self.template).render(Context(kwargs)) if rendering: retval.extend( get_email_addresses_from_text(rendering) ) return clean_duplicates(retval) def gather_doc_group_chairs(self, **kwargs): addrs = [] if 'doc' in kwargs: doc=kwargs['doc'] if doc.group and doc.group.features.acts_like_wg: addrs.append('%s-chairs@ietf.org'%doc.group.acronym) return addrs def gather_doc_group_delegates(self, **kwargs): addrs = [] if 'doc' in kwargs: doc=kwargs['doc'] if doc.group and doc.group.features.acts_like_wg: addrs.extend(doc.group.role_set.filter(name='delegate').values_list('email__address',flat=True)) return addrs def gather_doc_group_mail_list(self, **kwargs): addrs = [] if 'doc' in kwargs: doc=kwargs['doc'] if doc.group and doc.group.features.acts_like_wg: if doc.group.list_email: addrs.append(doc.group.list_email) return addrs def gather_doc_affecteddoc_authors(self, **kwargs): addrs = [] if 'doc' in kwargs: for reldoc in kwargs['doc'].related_that_doc(('conflrev','tohist','tois','tops')): addrs.extend(Recipient.objects.get(slug='doc_authors').gather(**{'doc':reldoc.document})) return addrs def gather_doc_affecteddoc_group_chairs(self, **kwargs): addrs = [] if 'doc' in kwargs: for reldoc in kwargs['doc'].related_that_doc(('conflrev','tohist','tois','tops')): addrs.extend(Recipient.objects.get(slug='doc_group_chairs').gather(**{'doc':reldoc.document})) return addrs def gather_doc_affecteddoc_notify(self, **kwargs): addrs = [] if 'doc' in kwargs: for reldoc in kwargs['doc'].related_that_doc(('conflrev','tohist','tois','tops')): addrs.extend(Recipient.objects.get(slug='doc_notify').gather(**{'doc':reldoc.document})) return addrs def gather_conflict_review_stream_manager(self, **kwargs): addrs = [] if 'doc' in kwargs: for reldoc in kwargs['doc'].related_that_doc(('conflrev',)): addrs.extend(Recipient.objects.get(slug='doc_stream_manager').gather(**{'doc':reldoc.document})) return addrs def gather_conflict_review_steering_group(self,**kwargs): addrs = [] if 'doc' in kwargs: for reldoc in kwargs['doc'].related_that_doc(('conflrev',)): if reldoc.document.stream_id=='irtf': addrs.append('"Internet Research Steering Group" ') return addrs def gather_group_steering_group(self,**kwargs): addrs = [] sg_map = dict( wg='"The IESG" ', rg='"Internet Research Steering Group" ' ) if 'group' in kwargs and kwargs['group'].type_id in sg_map: addrs.append(sg_map[kwargs['group'].type_id]) return addrs def gather_stream_managers(self, **kwargs): addrs = [] manager_map = dict(ise = '', irtf = '', ietf = '', iab = '') if 'streams' in kwargs: for stream in kwargs['streams']: if stream in manager_map: addrs.append(manager_map[stream]) return addrs def gather_doc_stream_manager(self, **kwargs): addrs = [] if 'doc' in kwargs: addrs.extend(Recipient.objects.get(slug='stream_managers').gather(**{'streams':[kwargs['doc'].stream_id]})) return addrs def gather_doc_non_ietf_stream_manager(self, **kwargs): addrs = [] if 'doc' in kwargs: doc = kwargs['doc'] if doc.stream_id and doc.stream_id != 'ietf': addrs.extend(Recipient.objects.get(slug='stream_managers').gather(**{'streams':[doc.stream_id,]})) return addrs def gather_group_responsible_directors(self, **kwargs): addrs = [] if 'group' in kwargs: group = kwargs['group'] if not group.acronym=='none': addrs.extend(group.role_set.filter(name='ad').values_list('email__address',flat=True)) if group.type_id=='rg': addrs.extend(Recipient.objects.get(slug='stream_managers').gather(**{'streams':['irtf']})) elif group.type_id=='program': addrs.extend(Recipient.objects.get(slug='iab').gather(**{})) return addrs def gather_group_secretaries(self, **kwargs): addrs = [] if 'group' in kwargs: group = kwargs['group'] if not group.acronym=='none': rts = ReviewTeamSettings.objects.filter(group=group).first() if rts and rts.secr_mail_alias and len(rts.secr_mail_alias) > 1: addrs = get_email_addresses_from_text(rts.secr_mail_alias) else: for role in group.role_set.filter(name='secr'): addrs.append(role.email.address) return addrs def gather_review_req_reviewers(self, **kwargs): addrs = [] if 'review_request' in kwargs: review_request = kwargs['review_request'] for assignment in review_request.reviewassignment_set.all(): addrs.append(assignment.reviewer.formatted_email()) return addrs def gather_review_secretaries(self, **kwargs): if not kwargs.get('skip_secretary'): return self.gather_group_secretaries(**kwargs) return [] def gather_doc_group_responsible_directors(self, **kwargs): addrs = [] if 'doc' in kwargs: group = kwargs['doc'].group if group and not group.acronym=='none': addrs.extend(Recipient.objects.get(slug='group_responsible_directors').gather(**{'group':group})) return addrs def gather_submission_authors(self, **kwargs): """ Returns a list of name and email, e.g.: [ 'Ano Nymous ' ] Is intended for display use, not in email context. """ addrs = [] if 'submission' in kwargs: submission = kwargs['submission'] addrs.extend(["%s <%s>" % (author["name"], author["email"]) for author in submission.authors if author.get("email")]) return addrs def gather_submission_submitter(self, **kwargs): """ Returns a list of name and email, e.g.: [ 'Ano Nymous ' ] """ addrs = [] if 'submission' in kwargs: submission = kwargs['submission'] if '@' in submission.submitter: addrs.extend( get_email_addresses_from_text(submission.submitter) ) else: try: submitter = Alias.objects.get(name=submission.submitter).person if submitter and submitter.email(): addrs.extend(["%s <%s>" % (submitter.name, submitter.email().address)]) except (Alias.DoesNotExist, Alias.MultipleObjectsReturned): pass return addrs def gather_submission_group_chairs(self, **kwargs): addrs = [] if 'submission' in kwargs: submission = kwargs['submission'] if submission.group: addrs.extend(Recipient.objects.get(slug='group_chairs').gather(**{'group':submission.group})) return addrs def gather_submission_confirmers(self, **kwargs): """If a submitted document is revising an existing document, the confirmers are the authors of that existing document, and the chairs if the document is a working group document and the author list has changed. Otherwise, the confirmers are the authors and submitter of the submitted document.""" addrs=[] if 'submission' in kwargs: submission = kwargs['submission'] doc=submission.existing_document() if doc: old_authors = [ author for author in doc.documentauthor_set.all() if author.email ] addrs.extend([ author.formatted_email() for author in old_authors]) old_author_email_set = set(author.email.address for author in old_authors) new_author_email_set = set(author["email"] for author in submission.authors if author.get("email")) if doc.group and old_author_email_set != new_author_email_set: if doc.group.features.acts_like_wg: addrs.extend(Recipient.objects.get(slug='group_chairs').gather(**{'group':doc.group})) elif doc.group.type_id in ['area']: addrs.extend(Recipient.objects.get(slug='group_responsible_directors').gather(**{'group':doc.group})) else: pass if doc.stream_id and doc.stream_id not in ['ietf']: addrs.extend(Recipient.objects.get(slug='stream_managers').gather(**{'streams':[doc.stream_id]})) else: # This is a bit roundabout, but we do it to get consistent and unicode-compliant # email names for known persons, without relying on the name parsed from the # draft (which might be ascii, also for persons with non-ascii names) emails = [ Email.objects.filter(address=author['email']).first() or author for author in submission.authors if author.get('email') ] addrs.extend([ e.formatted_email() if isinstance(e, Email) else formataddr((e["name"], e["email"])) for e in emails ] ) submitter_email = submission.submitter_parsed()["email"] if submitter_email and not submitter_email in [ parseaddr(a)[1] for a in addrs ]: addrs.append(submission.submitter) return addrs def gather_submission_group_mail_list(self, **kwargs): addrs=[] if 'submission' in kwargs: submission = kwargs['submission'] if submission.group: addrs.extend(Recipient.objects.get(slug='group_mail_list').gather(**{'group':submission.group})) return addrs def gather_rfc_editor_if_doc_in_queue(self, **kwargs): addrs=[] if 'doc' in kwargs: doc = kwargs['doc'] if doc.get_state_slug("draft-rfceditor") is not None: addrs.extend(Recipient.objects.get(slug='rfc_editor').gather(**{})) return addrs def gather_doc_discussing_ads(self, **kwargs): addrs=[] if 'doc' in kwargs: doc = kwargs['doc'] active_ballot = doc.active_ballot() if active_ballot: for balloter, pos in active_ballot.active_balloter_positions().items(): if pos and pos.pos_id == "discuss": addrs.append(balloter.role_email("ad").address) return addrs def gather_ipr_updatedipr_contacts(self, **kwargs): addrs=[] if 'ipr' in kwargs: ipr = kwargs['ipr'] for rel in ipr.updates: if rel.target.submitter_email: addrs.append(rel.target.submitter_email) elif hasattr(rel.target,'ietfer_email') and rel.target.ietfer_email: addrs.append(rel.target.ietfer_email) return addrs def gather_ipr_updatedipr_holders(self, **kwargs): addrs=[] if 'ipr' in kwargs: ipr = kwargs['ipr'] for disc in ipr.recursively_updates(): if hasattr(ipr,'holder_contact_email') and ipr.holder_contact_email: addrs.append(ipr.holder_contact_email) return addrs def gather_doc_ipr_group_or_ad(self, **kwargs): """A document's group email list if the document is a group document, otherwise, the document's AD if the document is active, otherwise nobody (in the past, the default was the IETF chair)""" addrs=[] if 'doc' in kwargs: doc=kwargs['doc'] if doc.group and doc.group.acronym == 'none': if doc.ad and doc.get_state_slug('draft')=='active': addrs.extend(Recipient.objects.get(slug='doc_ad').gather(**kwargs)) else: pass else: addrs.extend(Recipient.objects.get(slug='doc_group_mail_list').gather(**kwargs)) return addrs def gather_liaison_manager(self, **kwargs): addrs=[] if 'group' in kwargs: group=kwargs['group'] addrs.extend(group.role_set.filter(name='liaiman').values_list('email__address',flat=True)) return addrs def gather_session_requester(self, **kwargs): addrs=[] if 'session' in kwargs: session = kwargs['session'] from ietf.meeting.models import SchedulingEvent first_event = SchedulingEvent.objects.filter(session=session).select_related('by').order_by('time', 'id').first() if first_event and first_event.status_id in ['appw', 'schedw']: addrs.append(first_event.by.role_email('chair').address) return addrs def gather_review_team_ads(self, **kwargs): addrs=[] if 'review_req' in kwargs: review_req = kwargs['review_req'] if review_req.team.parent: 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'))