06edeca117ebfc33efb884166d1d08c2c1d59744
[pygrader.git] / pygrader / handler / __init__.py
1 # Copyright
2
3 "Define assorted handlers for use in :py:mod:`~pygrader.mailpipe`."
4
5 import pgp_mime as _pgp_mime
6
7
8 class InvalidMessage (ValueError):
9     def __init__(self, message=None, error=None):
10         super(InvalidMessage, self).__init__(error)
11         self.message = message
12         self.error = error
13
14     def message_id(self):
15         """Return a short string identifying the invalid message.
16         """
17         if self.message is None:
18             return None
19         subject = self.message['Subject']
20         if subject is not None:
21             return repr(subject)
22         message_id = self.message['Message-ID']
23         if message_id is not None:
24             return message_id
25         return None
26
27
28 class PermissionViolationMessage (InvalidMessage):
29     def __init__(self, person=None, allowed_groups=None, **kwargs):
30         if 'error' not in kwargs:
31             kwargs['error'] = 'action not permitted'
32         super(PermissionViolationMessage, self).__init__(**kwargs)
33         self.person = person
34         self.allowed_groups = allowed_groups
35
36
37 class InsecureMessage (InvalidMessage):
38     def __init__(self, **kwargs):
39         if 'error' not in kwargs:
40             kwargs['error'] = 'insecure message'
41         super(InsecureMessage, self).__init__(**kwargs)
42
43
44 class UnsignedMessage (InsecureMessage):
45     def __init__(self, **kwargs):
46         if 'error' not in kwargs:
47             kwargs['error'] = 'unsigned message'
48         super(UnsignedMessage, self).__init__(**kwargs)
49
50
51 class InvalidSubjectMessage (InvalidMessage):
52     def __init__(self, subject=None, **kwargs):
53         if 'error' not in kwargs:
54             kwargs['error'] = 'invalid subject {!r}'.format(subject)
55         super(InvalidSubjectMessage, self).__init__(**kwargs)
56         self.subject = subject
57
58
59 class InvalidStudentSubject (InvalidSubjectMessage):
60     def __init__(self, students=None, **kwargs):
61         if 'error' not in kwargs:
62             if students:
63                 kwargs['error'] = 'Subject matches multiple students'
64             else:
65                 kwargs['error'] = "Subject doesn't match any student"
66         super(InvalidStudentSubject, self).__init__(**kwargs)
67         self.students = students
68
69
70 class InvalidAssignmentSubject (InvalidSubjectMessage):
71     def __init__(self, assignments=None, **kwargs):
72         if 'error' not in kwargs:
73             if assignments:
74                 kwargs['error'] = 'Subject matches multiple assignments'
75             else:
76                 kwargs['error'] = "Subject doesn't match any assignment"
77         super(InvalidAssignmentSubject, self).__init__(kwargs)
78         self.assignments = assignments
79
80
81 class Response (Exception):
82     """Exception to bubble out email responses.
83
84     Rather than sending email responses themselves, handlers should
85     raise this exception.  The caller can catch it and mail the email
86     (or take other appropriate action).
87     """
88     def __init__(self, message=None, complete=False):
89         super(Response, self).__init__()
90         self.message = message
91         self.complete = complete
92
93
94 def get_subject_student(course, subject):
95     lsubject = subject.lower()
96     students = [p for p in course.find_people()
97                 if p.name.lower() in lsubject]
98     if len(students) == 1:
99         return students[0]
100     raise InvalidStudentSubject(students=students, subject=subject)
101
102 def get_subject_assignment(course, subject):
103     lsubject = subject.lower()
104     assignments = [a for a in course.assignments
105                    if a.name.lower() in lsubject]
106     if len(assignments) == 1:
107         return assignments[0]
108     raise InvalidAssignmentSubject(assignments=assignments, subject=subject)