handler: expand kwargs when initializing InvalidAssignmentSubject.
[pygrader.git] / pygrader / handler / __init__.py
1 # Copyright (C) 2012 W. Trevor King <wking@tremily.us>
2 #
3 # This file is part of pygrader.
4 #
5 # pygrader is free software: you can redistribute it and/or modify it under the
6 # terms of the GNU General Public License as published by the Free Software
7 # Foundation, either version 3 of the License, or (at your option) any later
8 # version.
9 #
10 # pygrader is distributed in the hope that it will be useful, but WITHOUT ANY
11 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
12 # A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
13 #
14 # You should have received a copy of the GNU General Public License along with
15 # pygrader.  If not, see <http://www.gnu.org/licenses/>.
16
17 "Define assorted handlers for use in :py:mod:`~pygrader.mailpipe`."
18
19 import pgp_mime as _pgp_mime
20
21
22 class InvalidMessage (ValueError):
23     def __init__(self, message=None, error=None):
24         super(InvalidMessage, self).__init__(error)
25         self.message = message
26         self.error = error
27
28     def message_id(self):
29         """Return a short string identifying the invalid message.
30         """
31         if self.message is None:
32             return None
33         subject = self.message['Subject']
34         if subject is not None:
35             return repr(subject)
36         message_id = self.message['Message-ID']
37         if message_id is not None:
38             return message_id
39         return None
40
41
42 class PermissionViolationMessage (InvalidMessage):
43     def __init__(self, person=None, allowed_groups=None, **kwargs):
44         if 'error' not in kwargs:
45             kwargs['error'] = 'action not permitted'
46         super(PermissionViolationMessage, self).__init__(**kwargs)
47         self.person = person
48         self.allowed_groups = allowed_groups
49
50
51 class InsecureMessage (InvalidMessage):
52     def __init__(self, **kwargs):
53         if 'error' not in kwargs:
54             kwargs['error'] = 'insecure message'
55         super(InsecureMessage, self).__init__(**kwargs)
56
57
58 class UnsignedMessage (InsecureMessage):
59     def __init__(self, **kwargs):
60         if 'error' not in kwargs:
61             kwargs['error'] = 'unsigned message'
62         super(UnsignedMessage, self).__init__(**kwargs)
63
64
65 class InvalidSubjectMessage (InvalidMessage):
66     def __init__(self, subject=None, **kwargs):
67         if 'error' not in kwargs:
68             kwargs['error'] = 'invalid subject {!r}'.format(subject)
69         super(InvalidSubjectMessage, self).__init__(**kwargs)
70         self.subject = subject
71
72
73 class InvalidStudentSubject (InvalidSubjectMessage):
74     def __init__(self, students=None, **kwargs):
75         if 'error' not in kwargs:
76             if students:
77                 kwargs['error'] = 'Subject matches multiple students'
78             else:
79                 kwargs['error'] = "Subject doesn't match any student"
80         super(InvalidStudentSubject, self).__init__(**kwargs)
81         self.students = students
82
83
84 class InvalidAssignmentSubject (InvalidSubjectMessage):
85     def __init__(self, assignments=None, **kwargs):
86         if 'error' not in kwargs:
87             if assignments:
88                 kwargs['error'] = 'Subject matches multiple assignments'
89             else:
90                 kwargs['error'] = "Subject doesn't match any assignment"
91         super(InvalidAssignmentSubject, self).__init__(**kwargs)
92         self.assignments = assignments
93
94
95 class Response (Exception):
96     """Exception to bubble out email responses.
97
98     Rather than sending email responses themselves, handlers should
99     raise this exception.  The caller can catch it and mail the email
100     (or take other appropriate action).
101     """
102     def __init__(self, message=None, complete=False):
103         super(Response, self).__init__()
104         self.message = message
105         self.complete = complete
106
107
108 def get_subject_student(course, subject):
109     lsubject = subject.lower()
110     students = [p for p in course.find_people()
111                 if p.name.lower() in lsubject]
112     if len(students) == 1:
113         return students[0]
114     raise InvalidStudentSubject(students=students, subject=subject)
115
116 def get_subject_assignment(course, subject):
117     lsubject = subject.lower()
118     assignments = [a for a in course.assignments
119                    if a.name.lower() in lsubject]
120     if len(assignments) == 1:
121         return assignments[0]
122     raise InvalidAssignmentSubject(assignments=assignments, subject=subject)