1165.1.8
by William Grant
Start a submission UI in ivle.webapp.submit. |
1 |
# IVLE
|
2 |
# Copyright (C) 2007-2009 The University of Melbourne
|
|
3 |
#
|
|
4 |
# This program is free software; you can redistribute it and/or modify
|
|
5 |
# it under the terms of the GNU General Public License as published by
|
|
6 |
# the Free Software Foundation; either version 2 of the License, or
|
|
7 |
# (at your option) any later version.
|
|
8 |
#
|
|
9 |
# This program is distributed in the hope that it will be useful,
|
|
10 |
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
12 |
# GNU General Public License for more details.
|
|
13 |
#
|
|
14 |
# You should have received a copy of the GNU General Public License
|
|
15 |
# along with this program; if not, write to the Free Software
|
|
16 |
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
17 |
||
18 |
# Author: Will Grant
|
|
19 |
||
20 |
"""Project submissions user interface."""
|
|
21 |
||
1165.1.13
by William Grant
Add an initial project selection UI to SubmitView. |
22 |
import os.path |
1165.1.17
by William Grant
Disable project radio buttons if they are closed. |
23 |
import datetime |
1165.1.13
by William Grant
Add an initial project selection UI to SubmitView. |
24 |
|
1165.1.22
by William Grant
Detect the permitted offering for the given submission URL and restrict to that. |
25 |
from storm.locals import Store |
26 |
||
1513
by Matt Giuca
submit: Now produces a graceful user error if submitting a project after the deadline (forbidden by HTML, but still possible and not due to malice). Previously resulted in an internal server error. |
27 |
from ivle import database |
1165.1.8
by William Grant
Start a submission UI in ivle.webapp.submit. |
28 |
from ivle.database import (User, ProjectGroup, Offering, Subject, Semester, |
1165.1.22
by William Grant
Detect the permitted offering for the given submission URL and restrict to that. |
29 |
ProjectSet, Project, Enrolment) |
1165.1.20
by William Grant
Add a POST handler to SubmitView, which does the actual submission. |
30 |
from ivle.webapp.errors import NotFound, BadRequest |
1165.1.8
by William Grant
Start a submission UI in ivle.webapp.submit. |
31 |
from ivle.webapp.base.xhtml import XHTMLView |
32 |
from ivle.webapp.base.plugins import ViewPlugin |
|
1294.4.13
by David Coles
Ported Submit to object publisher framework |
33 |
from ivle.webapp import ApplicationRoot |
1165.1.8
by William Grant
Start a submission UI in ivle.webapp.submit. |
34 |
|
1165.1.16
by William Grant
Show the deadline for each project when submitting. |
35 |
import ivle.date |
1165.5.8
by William Grant
Rebuild SVN authz files on submission. |
36 |
import ivle.chat |
1515
by Matt Giuca
Submit view: The projects list is now identical (except for radio buttons) to the view on the subjects page. It is much clearer and contains more info. The code is somewhat different, because it's a table, not a list, so I didn't abstract it. Moved a function out of subject.py to ivle.util, as it is shared by both views. |
37 |
from ivle import util |
1165.1.8
by William Grant
Start a submission UI in ivle.webapp.submit. |
38 |
|
39 |
class SubmitView(XHTMLView): |
|
40 |
"""A view to submit a Subversion repository path for a project."""
|
|
41 |
template = 'submit.html' |
|
42 |
tab = 'files' |
|
43 |
permission = 'submit_project' |
|
1294.4.13
by David Coles
Ported Submit to object publisher framework |
44 |
subpath_allowed = True |
45 |
||
46 |
def __init__(self, req, context, subpath): |
|
47 |
super(SubmitView, self).__init__(req, context, subpath) |
|
48 |
||
49 |
if len(subpath) < 1: |
|
50 |
raise NotFound() |
|
51 |
name = subpath[0] |
|
1165.1.8
by William Grant
Start a submission UI in ivle.webapp.submit. |
52 |
# We need to work out which entity owns the repository, so we look
|
53 |
# at the first two path segments. The first tells us the type.
|
|
1165.1.9
by William Grant
Split SubmitView.__init__ into new subclasses, {User,Group}SubmitView. |
54 |
self.context = self.get_repository_owner(req.store, name) |
1244
by William Grant
Ensure that the path is absolute when submitting a project. |
55 |
|
1165.1.8
by William Grant
Start a submission UI in ivle.webapp.submit. |
56 |
if self.context is None: |
57 |
raise NotFound() |
|
58 |
||
1165.1.28
by William Grant
Don't crash when the principal cannot be determined. |
59 |
self.offering = self.get_offering() |
60 |
||
1165.1.9
by William Grant
Split SubmitView.__init__ into new subclasses, {User,Group}SubmitView. |
61 |
def get_repository_owner(self, store, name): |
62 |
"""Return the owner of the repository given the name and a Store."""
|
|
63 |
raise NotImplementedError() |
|
64 |
||
1165.1.22
by William Grant
Detect the permitted offering for the given submission URL and restrict to that. |
65 |
def get_offering(self): |
66 |
"""Return the offering that this path can be submitted to."""
|
|
67 |
raise NotImplementedError() |
|
68 |
||
1165.1.8
by William Grant
Start a submission UI in ivle.webapp.submit. |
69 |
def populate(self, req, ctx): |
1165.1.20
by William Grant
Add a POST handler to SubmitView, which does the actual submission. |
70 |
if req.method == 'POST': |
71 |
data = dict(req.get_fieldstorage()) |
|
1165.1.25
by William Grant
Take the revision to submit from the query string. |
72 |
if 'revision' not in data: |
1165.1.41
by William Grant
Give more human-readable 400 messages for submission. |
73 |
raise BadRequest('No revision selected.') |
1165.1.25
by William Grant
Take the revision to submit from the query string. |
74 |
|
75 |
try: |
|
76 |
revision = int(data['revision']) |
|
77 |
except ValueError: |
|
1165.1.41
by William Grant
Give more human-readable 400 messages for submission. |
78 |
raise BadRequest('Revision must be an integer.') |
1165.1.25
by William Grant
Take the revision to submit from the query string. |
79 |
|
1165.1.20
by William Grant
Add a POST handler to SubmitView, which does the actual submission. |
80 |
if 'project' not in data: |
1165.1.41
by William Grant
Give more human-readable 400 messages for submission. |
81 |
raise BadRequest('No project selected.') |
1165.1.20
by William Grant
Add a POST handler to SubmitView, which does the actual submission. |
82 |
|
83 |
try: |
|
84 |
projectid = int(data['project']) |
|
85 |
except ValueError: |
|
1165.1.41
by William Grant
Give more human-readable 400 messages for submission. |
86 |
raise BadRequest('Project must be an integer.') |
1165.1.20
by William Grant
Add a POST handler to SubmitView, which does the actual submission. |
87 |
|
88 |
project = req.store.find(Project, Project.id == projectid).one() |
|
89 |
||
1165.1.24
by William Grant
400 if a non-matching project is POSTed. |
90 |
# This view's offering will be the sole offering for which the
|
91 |
# path is permissible. We need to check that.
|
|
92 |
if project.project_set.offering is not self.offering: |
|
1512
by Matt Giuca
ivle/webapp/submit: Full stops in errors for consistency. |
93 |
raise BadRequest('Path is not permissible for this offering.') |
1165.1.24
by William Grant
400 if a non-matching project is POSTed. |
94 |
|
1165.1.20
by William Grant
Add a POST handler to SubmitView, which does the actual submission. |
95 |
if project is None: |
1512
by Matt Giuca
ivle/webapp/submit: Full stops in errors for consistency. |
96 |
raise BadRequest('Specified project does not exist.') |
1165.1.20
by William Grant
Add a POST handler to SubmitView, which does the actual submission. |
97 |
|
1513
by Matt Giuca
submit: Now produces a graceful user error if submitting a project after the deadline (forbidden by HTML, but still possible and not due to malice). Previously resulted in an internal server error. |
98 |
try: |
1526
by Matt Giuca
Made the submitted page friendlier. It explains the submission process, how to re-submit, how to verify, and provides links to verify and the subject page. |
99 |
ctx['submission'] = project.submit(self.context, |
100 |
unicode(self.path), revision, req.user) |
|
1513
by Matt Giuca
submit: Now produces a graceful user error if submitting a project after the deadline (forbidden by HTML, but still possible and not due to malice). Previously resulted in an internal server error. |
101 |
except database.DeadlinePassed, e: |
102 |
raise BadRequest(str(e) + ".") |
|
1165.1.20
by William Grant
Add a POST handler to SubmitView, which does the actual submission. |
103 |
|
1165.5.8
by William Grant
Rebuild SVN authz files on submission. |
104 |
# The Subversion configuration needs to be updated, to grant
|
105 |
# tutors and lecturers access to this submission. We have to
|
|
106 |
# commit early so usrmgt-server can see the new submission.
|
|
107 |
req.store.commit() |
|
108 |
||
109 |
# Instruct usrmgt-server to rebuild the SVN group authz file.
|
|
110 |
msg = {'rebuild_svn_group_config': {}} |
|
111 |
usrmgt = ivle.chat.chat(req.config['usrmgt']['host'], |
|
112 |
req.config['usrmgt']['port'], |
|
113 |
msg, |
|
114 |
req.config['usrmgt']['magic'], |
|
115 |
)
|
|
116 |
||
117 |
if usrmgt.get('response') in (None, 'failure'): |
|
118 |
raise Exception("Failure creating repository: " + str(usrmgt)) |
|
119 |
||
120 |
# Instruct usrmgt-server to rebuild the SVN user authz file.
|
|
121 |
msg = {'rebuild_svn_config': {}} |
|
122 |
usrmgt = ivle.chat.chat(req.config['usrmgt']['host'], |
|
123 |
req.config['usrmgt']['port'], |
|
124 |
msg, |
|
125 |
req.config['usrmgt']['magic'], |
|
126 |
)
|
|
127 |
||
128 |
if usrmgt.get('response') in (None, 'failure'): |
|
129 |
raise Exception("Failure creating repository: " + str(usrmgt)) |
|
130 |
||
1165.1.43
by William Grant
Display an informative view on submission success. |
131 |
self.template = 'submitted.html' |
132 |
ctx['project'] = project |
|
133 |
||
1165.1.27
by William Grant
Make the submit view significantly more readable. |
134 |
ctx['req'] = req |
1165.1.13
by William Grant
Add an initial project selection UI to SubmitView. |
135 |
ctx['principal'] = self.context |
1165.1.24
by William Grant
400 if a non-matching project is POSTed. |
136 |
ctx['offering'] = self.offering |
1165.1.13
by William Grant
Add an initial project selection UI to SubmitView. |
137 |
ctx['path'] = self.path |
1165.1.17
by William Grant
Disable project radio buttons if they are closed. |
138 |
ctx['now'] = datetime.datetime.now() |
1515
by Matt Giuca
Submit view: The projects list is now identical (except for radio buttons) to the view on the subjects page. It is much clearer and contains more info. The code is somewhat different, because it's a table, not a list, so I didn't abstract it. Moved a function out of subject.py to ivle.util, as it is shared by both views. |
139 |
ctx['format_submission_principal'] = util.format_submission_principal |
1179
by Matt Giuca
submit: Added tooltip for the due date (which displays the whole date, while |
140 |
ctx['format_datetime'] = ivle.date.make_date_nice |
141 |
ctx['format_datetime_short'] = ivle.date.format_datetime_for_paragraph |
|
1294.4.13
by David Coles
Ported Submit to object publisher framework |
142 |
|
143 |
@property
|
|
144 |
def path(self): |
|
145 |
return os.path.join('/', *self.subpath[1:]) if self.subpath else '/' |
|
1165.1.8
by William Grant
Start a submission UI in ivle.webapp.submit. |
146 |
|
1165.1.9
by William Grant
Split SubmitView.__init__ into new subclasses, {User,Group}SubmitView. |
147 |
|
148 |
class UserSubmitView(SubmitView): |
|
149 |
def get_repository_owner(self, store, name): |
|
150 |
'''Resolve the user name into a user.'''
|
|
151 |
return User.get_by_login(store, name) |
|
152 |
||
1165.1.22
by William Grant
Detect the permitted offering for the given submission URL and restrict to that. |
153 |
def get_offering(self): |
154 |
return Store.of(self.context).find(Offering, |
|
155 |
Offering.id == Enrolment.offering_id, |
|
156 |
Enrolment.user_id == self.context.id, |
|
157 |
Offering.semester_id == Semester.id, |
|
158 |
Semester.state == u'current', |
|
159 |
Offering.subject_id == Subject.id, |
|
1244
by William Grant
Ensure that the path is absolute when submitting a project. |
160 |
Subject.short_name == self.path.split('/')[1], |
1165.1.22
by William Grant
Detect the permitted offering for the given submission URL and restrict to that. |
161 |
).one() |
162 |
||
1165.1.9
by William Grant
Split SubmitView.__init__ into new subclasses, {User,Group}SubmitView. |
163 |
|
164 |
class GroupSubmitView(SubmitView): |
|
165 |
def get_repository_owner(self, store, name): |
|
166 |
'''Resolve the subject_year_semester_group name into a group.'''
|
|
167 |
namebits = name.split('_', 3) |
|
168 |
if len(namebits) != 4: |
|
169 |
return None |
|
170 |
||
171 |
# Find the project group with the given name in any project set in the
|
|
172 |
# offering of the given subject in the semester with the given year
|
|
173 |
# and semester.
|
|
174 |
return store.find(ProjectGroup, |
|
175 |
ProjectGroup.name == namebits[3], |
|
176 |
ProjectGroup.project_set_id == ProjectSet.id, |
|
177 |
ProjectSet.offering_id == Offering.id, |
|
178 |
Offering.subject_id == Subject.id, |
|
179 |
Subject.short_name == namebits[0], |
|
180 |
Offering.semester_id == Semester.id, |
|
181 |
Semester.year == namebits[1], |
|
182 |
Semester.semester == namebits[2]).one() |
|
183 |
||
1165.1.22
by William Grant
Detect the permitted offering for the given submission URL and restrict to that. |
184 |
def get_offering(self): |
185 |
return self.context.project_set.offering |
|
186 |
||
1165.1.9
by William Grant
Split SubmitView.__init__ into new subclasses, {User,Group}SubmitView. |
187 |
|
1165.1.8
by William Grant
Start a submission UI in ivle.webapp.submit. |
188 |
class Plugin(ViewPlugin): |
1294.4.13
by David Coles
Ported Submit to object publisher framework |
189 |
views = [(ApplicationRoot, ('+submit', 'users'), UserSubmitView), |
190 |
(ApplicationRoot, ('+submit', 'groups'), GroupSubmitView)] |
|
191 |