-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
3 changed files
with
437 additions
and
165 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,165 +0,0 @@ | ||
# encoding: utf8 | ||
import os | ||
import textwrap | ||
|
||
from emailtunnel import SMTPForwarder, Message, InvalidRecipient | ||
|
||
import django | ||
|
||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mftutor.settings") | ||
django.setup() | ||
|
||
import mftutor.settings | ||
|
||
from mftutor.aliases.models import resolve_alias | ||
from mftutor.tutor.models import Tutor, TutorGroup, RusClass, Rus | ||
|
||
|
||
class TutorForwarder(SMTPForwarder): | ||
ERROR_TEMPLATE = """ | ||
Nedenstående email blev ikke leveret til nogen. | ||
{reason} | ||
{message} | ||
""" | ||
|
||
def __init__(self, *args, **kwargs): | ||
self.gf_year = mftutor.settings.YEAR | ||
self.tutor_year = mftutor.settings.TUTORMAIL_YEAR | ||
self.rus_year = mftutor.settings.RUSMAIL_YEAR | ||
self.gf_groups = mftutor.settings.GF_GROUPS | ||
self.rusclass_base = mftutor.settings.RUSCLASS_BASE | ||
|
||
def handle_envelope(self, envelope, peer): | ||
try: | ||
return super(TutorForwarder).handle_envelope(envelope, peer) | ||
except ForwardToAdmin as e: | ||
self.forward_to_admin(envelope, e.args[0]) | ||
|
||
def translate_recipient(self, rcptto): | ||
name, domain = rcptto.split('@') | ||
groups = self.get_groups(name) | ||
if groups: | ||
emails = self.get_group_emails(name, groups) | ||
if not emails: | ||
raise ForwardToAdmin('Grupper er tomme: %r' % (groups,)) | ||
return emails | ||
|
||
tutors_only, rusclasses = self.get_rusclasses(name) | ||
if rusclasses is not None: | ||
emails = self.get_rusclass_emails(tutors_only, rusclasses) | ||
if not emails: | ||
raise ForwardToAdmin('Ingen tutor/rus-modtagere: %r' % | ||
(groups,)) | ||
return emails | ||
|
||
raise InvalidRecipient(name) | ||
|
||
def forward_to_admin(self, envelope, reason): | ||
admin_emails = ['[email protected]'] | ||
sender = recipient = '[email protected]' | ||
|
||
subject = '[TutorForwarder] %s' % (reason[:50],) | ||
body = textwrap.dedent(self.ERROR_TEMPLATE).format( | ||
reason=reason, message=envelope.message) | ||
admin_message = Message.compose( | ||
sender, recipient, subject, body) | ||
admin_message.add_header('Auto-Submitted', 'auto-replied') | ||
self.deliver(admin_message, admin_emails, sender) | ||
|
||
def get_groups(self, recipient): | ||
"""Get all TutorGroups that an alias refers to.""" | ||
group_names = resolve_alias(recipient) | ||
groups = [] | ||
for name in group_names: | ||
group_and_year = self.get_group(name) | ||
if group_and_year is not None: | ||
groups.append(group_and_year) | ||
return groups | ||
|
||
def get_group(self, group_name): | ||
"""Resolves a concrete group name to a (group, year)-tuple. | ||
Returns None if the group name is invalid, | ||
or a tuple (group, year) where group is a TutorGroup | ||
and year is the year to find the tutors in. | ||
""" | ||
|
||
# Find the year | ||
if group_name in self.gf_groups: | ||
year = self.gf_year | ||
elif group_name.startswith('g') and group_name[1:] in self.gf_groups: | ||
year = self.gf_year - 1 | ||
group_name = group_name[1:] | ||
else: | ||
year = self.tutor_year | ||
|
||
# Is name a tutorgroup? | ||
try: | ||
group = TutorGroup.objects.get(handle=group_name) | ||
except TutorGroup.DoesNotExist: | ||
return None | ||
|
||
# Disallow 'alle' | ||
if group.handle == 'alle': | ||
return None | ||
|
||
return (group, year) | ||
|
||
def get_group_emails(self, name, groups): | ||
emails = [] | ||
for group, year in groups: | ||
group_tutors = Tutor.objects.filter( | ||
groups=group, year=year, | ||
early_termination__isnull=True) | ||
group_emails = [tutor.profile.email for tutor in group_tutors] | ||
emails += [email for email in group_emails | ||
if email is not None] | ||
|
||
# Remove duplicate email addresses | ||
return sorted(set(emails)) | ||
|
||
def get_rusclasses(self, recipient): | ||
"""(tutors_only, list of RusClass)""" | ||
year = self.rus_year | ||
|
||
tutors_only_prefix = 'tutor+' | ||
if recipient.startswith(tutors_only_prefix): | ||
recipient = recipient[len(tutors_only_prefix):] | ||
tutors_only = True | ||
else: | ||
tutors_only = False | ||
|
||
rusclasses = None | ||
|
||
for official, handle, internal in self.rusclass_base: | ||
if recipient == handle: | ||
rusclasses = list(RusClass.objects.filter( | ||
year=year, | ||
handle__startswith=recipient)) | ||
|
||
if rusclasses is None: | ||
try: | ||
rusclasses = [RusClass.objects.get(year=year, handle=recipient)] | ||
except RusClass.DoesNotExist: | ||
pass | ||
|
||
return (tutors_only, rusclasses) | ||
|
||
def get_rusclass_emails(self, tutors_only, rusclasses): | ||
tutor_emails = [ | ||
tutor.profile.email | ||
for tutor in Tutor.objects.filter(rusclass__in=rusclasses) | ||
] | ||
if tutors_only: | ||
rus_emails = [] | ||
else: | ||
rus_emails = [ | ||
rus.profile.email | ||
for rus in Rus.objects.filter(rusclass__in=rusclasses) | ||
] | ||
|
||
emails = tutor_emails + rus_emails | ||
|
||
return sorted(set(email for email in emails if email)) | ||
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,188 @@ | ||
# encoding: utf8 | ||
import os | ||
import logging | ||
import textwrap | ||
|
||
from emailtunnel import SMTPForwarder, Message, InvalidRecipient | ||
|
||
import django | ||
|
||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mftutor.settings") | ||
django.setup() | ||
|
||
import mftutor.settings | ||
|
||
from mftutor.aliases.models import resolve_alias | ||
from mftutor.tutor.models import Tutor, TutorGroup, RusClass, Rus | ||
|
||
|
||
class ForwardToAdmin(Exception): | ||
pass | ||
|
||
|
||
class TutorForwarder(SMTPForwarder): | ||
ERROR_TEMPLATE = """ | ||
Nedenstående email blev ikke leveret til nogen. | ||
{reason} | ||
{message} | ||
""" | ||
|
||
def __init__(self, *args, **kwargs): | ||
self.gf_year = kwargs.pop('gf_year', None) | ||
self.tutor_year = kwargs.pop('tutor_year', None) | ||
self.rus_year = kwargs.pop('rus_year', None) | ||
|
||
years = (self.gf_year, self.tutor_year, self.rus_year) | ||
if all(years): | ||
logging.info("Year from kwargs: (%s, %s, %s)" % | ||
(self.gf_year, self.tutor_year, self.rus_year)) | ||
else: | ||
if any(years): | ||
logging.error("must specify all of gf_year, tutor_year, " + | ||
"rus_year or none of them") | ||
self.gf_year = mftutor.settings.YEAR | ||
self.tutor_year = mftutor.settings.TUTORMAIL_YEAR | ||
self.rus_year = mftutor.settings.RUSMAIL_YEAR | ||
logging.info("Year from mftutor.settings: (%s, %s, %s)" % | ||
(self.gf_year, self.tutor_year, self.rus_year)) | ||
|
||
self.gf_groups = kwargs.pop( | ||
'gf_groups', mftutor.settings.GF_GROUPS) | ||
self.rusclass_base = kwargs.pop( | ||
'rusclass_base', mftutor.settings.RUSCLASS_BASE) | ||
super(TutorForwarder, self).__init__(*args, **kwargs) | ||
|
||
def handle_envelope(self, envelope, peer): | ||
try: | ||
return super(TutorForwarder, self).handle_envelope(envelope, peer) | ||
except ForwardToAdmin as e: | ||
self.forward_to_admin(envelope, e.args[0]) | ||
|
||
def translate_recipient(self, rcptto): | ||
name, domain = rcptto.split('@') | ||
groups = self.get_groups(name) | ||
if groups: | ||
emails = self.get_group_emails(name, groups) | ||
if not emails: | ||
raise ForwardToAdmin('Grupper er tomme: %r' % (groups,)) | ||
return emails | ||
|
||
tutors_only, rusclasses = self.get_rusclasses(name) | ||
if rusclasses is not None: | ||
emails = self.get_rusclass_emails(tutors_only, rusclasses) | ||
if not emails: | ||
raise ForwardToAdmin('Ingen tutor/rus-modtagere: %r' % | ||
(groups,)) | ||
return emails | ||
|
||
raise InvalidRecipient(name) | ||
|
||
def forward_to_admin(self, envelope, reason): | ||
admin_emails = ['[email protected]'] | ||
sender = recipient = '[email protected]' | ||
|
||
subject = '[TutorForwarder] %s' % (reason[:50],) | ||
body = textwrap.dedent(self.ERROR_TEMPLATE).format( | ||
reason=reason, message=envelope.message) | ||
admin_message = Message.compose( | ||
sender, recipient, subject, body) | ||
admin_message.add_header('Auto-Submitted', 'auto-replied') | ||
self.deliver(admin_message, admin_emails, sender) | ||
|
||
def get_groups(self, recipient): | ||
"""Get all TutorGroups that an alias refers to.""" | ||
group_names = resolve_alias(recipient) | ||
groups = [] | ||
for name in group_names: | ||
group_and_year = self.get_group(name) | ||
if group_and_year is not None: | ||
groups.append(group_and_year) | ||
return groups | ||
|
||
def get_group(self, group_name): | ||
"""Resolves a concrete group name to a (group, year)-tuple. | ||
Returns None if the group name is invalid, | ||
or a tuple (group, year) where group is a TutorGroup | ||
and year is the year to find the tutors in. | ||
""" | ||
|
||
# Find the year | ||
if group_name in self.gf_groups: | ||
year = self.gf_year | ||
elif group_name.startswith('g') and group_name[1:] in self.gf_groups: | ||
year = self.gf_year - 1 | ||
group_name = group_name[1:] | ||
else: | ||
year = self.tutor_year | ||
|
||
# Is name a tutorgroup? | ||
try: | ||
group = TutorGroup.objects.get(handle=group_name) | ||
except TutorGroup.DoesNotExist: | ||
return None | ||
|
||
# Disallow 'alle' | ||
if group.handle == 'alle': | ||
return None | ||
|
||
return (group, year) | ||
|
||
def get_group_emails(self, name, groups): | ||
emails = [] | ||
for group, year in groups: | ||
group_tutors = Tutor.objects.filter( | ||
groups=group, year=year, | ||
early_termination__isnull=True) | ||
group_emails = [tutor.profile.email for tutor in group_tutors] | ||
emails += [email for email in group_emails | ||
if email is not None] | ||
|
||
# Remove duplicate email addresses | ||
return sorted(set(emails)) | ||
|
||
def get_rusclasses(self, recipient): | ||
"""(tutors_only, list of RusClass)""" | ||
year = self.rus_year | ||
|
||
tutors_only_prefix = 'tutor+' | ||
if recipient.startswith(tutors_only_prefix): | ||
recipient = recipient[len(tutors_only_prefix):] | ||
tutors_only = True | ||
else: | ||
tutors_only = False | ||
|
||
rusclasses = None | ||
|
||
for official, handle, internal in self.rusclass_base: | ||
if recipient == handle: | ||
rusclasses = list(RusClass.objects.filter( | ||
year=year, | ||
handle__startswith=recipient)) | ||
|
||
if rusclasses is None: | ||
try: | ||
rusclasses = [RusClass.objects.get(year=year, handle=recipient)] | ||
except RusClass.DoesNotExist: | ||
pass | ||
|
||
return (tutors_only, rusclasses) | ||
|
||
def get_rusclass_emails(self, tutors_only, rusclasses): | ||
tutor_emails = [ | ||
tutor.profile.email | ||
for tutor in Tutor.objects.filter(rusclass__in=rusclasses) | ||
] | ||
if tutors_only: | ||
rus_emails = [] | ||
else: | ||
rus_emails = [ | ||
rus.profile.email | ||
for rus in Rus.objects.filter(rusclass__in=rusclasses) | ||
] | ||
|
||
emails = tutor_emails + rus_emails | ||
|
||
return sorted(set(email for email in emails if email)) |
Oops, something went wrong.