-# Copyright
+# Copyright (C) 2012 W. Trevor King <wking@tremily.us>
+#
+# This file is part of pygrader.
+#
+# pygrader is free software: you can redistribute it and/or modify it under the
+# terms of the GNU General Public License as published by the Free Software
+# Foundation, either version 3 of the License, or (at your option) any later
+# version.
+#
+# pygrader is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+# A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# pygrader. If not, see <http://www.gnu.org/licenses/>.
"""Handle information requests
from .. import LOG as _LOG
from ..email import construct_text_email as _construct_text_email
from ..email import construct_email as _construct_email
+from ..extract_mime import message_time as _message_time
from ..storage import assignment_path as _assignment_path
from ..tabulate import tabulate as _tabulate
from ..template import _student_email as _student_email
-from . import InvalidMessage as _InvalidMessage
-from . import InvalidSubjectMessage as _InvalidSubjectMessage
+from . import get_subject_assignment as _get_subject_assignment
+from . import get_subject_student as _get_subject_student
+from . import InvalidStudentSubject as _InvalidStudentSubject
+from . import InvalidAssignmentSubject as _InvalidAssignmentSubject
from . import Response as _Response
from . import UnsignedMessage as _UnsignedMessage
-class InvalidStudent (_InvalidSubjectMessage):
- def __init__(self, students=None, **kwargs):
- if 'error' not in kwargs:
- kwargs['error'] = 'Subject matches multiple students'
- super(InvalidStudent, self).__init__(kwargs)
- self.students = students
-
-
def run(basedir, course, message, person, subject,
trust_email_infrastructure=False, dry_run=False, **kwargs):
"""
... person=person, subject='[get]', max_late=0)
... # doctest: +ELLIPSIS, +REPORT_UDIFF
respond with:
- Content-Type: multipart/signed; protocol="application/pgp-signature"; micalg="pgp-sha1"; boundary="===============...=="
+ Content-Type: multipart/signed; ...protocol="application/pgp-signature"; ...boundary="===============...=="
MIME-Version: 1.0
Content-Disposition: inline
Date: ...
... person=person, subject='[get]', max_late=0)
... # doctest: +ELLIPSIS, +REPORT_UDIFF
respond with:
- Content-Type: multipart/signed; protocol="application/pgp-signature"; micalg="pgp-sha1"; boundary="===============...=="
+ Content-Type: multipart/signed; ...protocol="application/pgp-signature"; ...boundary="===============...=="
MIME-Version: 1.0
Content-Disposition: inline
Date: ...
... max_late=0)
... # doctest: +ELLIPSIS, +REPORT_UDIFF
respond with:
- Content-Type: multipart/signed; protocol="application/pgp-signature"; micalg="pgp-sha1"; boundary="===============...=="
+ Content-Type: multipart/signed; ...protocol="application/pgp-signature"; ...boundary="===============...=="
MIME-Version: 1.0
Content-Disposition: inline
Date: ...
... max_late=0)
... # doctest: +ELLIPSIS, +REPORT_UDIFF
respond with:
- Content-Type: multipart/signed; protocol="application/pgp-signature"; micalg="pgp-sha1"; boundary="===============...=="
+ Content-Type: multipart/signed; ...protocol="application/pgp-signature"; ...boundary="===============...=="
MIME-Version: 1.0
Content-Disposition: inline
Date: ...
hasattr(message, 'authenticated') and message.authenticated)
if not authenticated:
raise _UnsignedMessage()
- if 'assistants' in person.groups or 'professors' in person.groups:
+ if person.is_admin():
email = _get_admin_email(
basedir=basedir, course=course, person=person, subject=subject)
elif 'students' in person.groups:
else:
raise NotImplementedError(
'strange groups {} for {}'.format(person.groups, person))
- raise _Response(message=email)
+ raise _Response(message=email, complete=True)
def _get_student_email(basedir, course, person, student=None):
if student is None:
).format(student.name)
message = _pgp_mime.encodedMIMEText(text)
message['Subject'] = 'No grades for {}'.format(student.alias())
- raise _Response(message=message)
+ raise _Response(message=message, complete=True)
elif len(emails) > 1:
raise NotImplementedError(emails)
email,callback = emails[0]
for assignment in assignments:
grade = course.grade(student=student, assignment=assignment)
if grade is not None:
- message.attach(_pgp_mime.encodedMIMEText(
- '{} grade: {}\n\n{}\n'.format(
- assignment.name, grade.points, grade.comment)))
+ text = '{} grade: {}\n'.format(assignment.name, grade.points)
+ if grade.comment:
+ text += '\n{}\n'.format(grade.comment)
+ message.attach(_pgp_mime.encodedMIMEText(text))
assignment_path = _assignment_path(basedir, assignment, student)
mpath = _os_path.join(assignment_path, 'mail')
try:
except _mailbox.NoSuchMailboxError as e:
pass
else:
- for msg in mbox:
+ messages = []
+ for key,msg in mbox.items():
+ subpath = mbox._lookup(key)
+ if subpath.endswith('.gitignore'):
+ _LOG.debug('skipping non-message {}'.format(subpath))
+ continue
+ messages.append(msg)
+ messages.sort(key=_message_time)
+ for msg in messages:
message.attach(_MIMEMessage(msg))
return _construct_email(
author=course.robot, targets=[person], subject=subject,
message=message)
def _get_admin_email(basedir, course, person, subject):
- lsubject = subject.lower()
- students = [p for p in course.find_people()
- if p.name.lower() in lsubject]
- if len(students) == 0:
+ try:
+ student = _get_subject_student(course, subject)
+ except _InvalidStudentSubject as error:
+ if error.students: # several students
+ raise
+ # no students
_LOG.debug('construct course grades email for {}'.format(person))
stream = _io.StringIO()
_tabulate(
author=course.robot, targets=[person],
subject='All grades for {}'.format(course.name),
text=text)
- elif len(students) == 1:
- student = students[0]
- assignments = [a for a in course.assignments
- if a.name.lower() in lsubject]
- if len(assignments) == 0:
- email = _get_student_email(
- basedir=basedir, course=course, person=person, student=student)
- else:
+ else: # a single student
+ try:
+ assignment = _get_subject_assignment(course, subject)
+ except _InvalidAssignmentSubject as error:
+ if error.assignments: # several assignments
+ email = _get_student_submission_email(
+ basedir=basedir, course=course, person=person,
+ student=student, assignments=error.assignments)
+ else: # no assignments
+ email = _get_student_email(
+ basedir=basedir, course=course, person=person,
+ student=student)
+ else: # a single assignment
email = _get_student_submission_email(
basedir=basedir, course=course, person=person, student=student,
- assignments=assignments)
- else:
- raise InvalidStudent(students=students)
+ assignments=[assignment])
return email