2
# Copyright (C) 2007-2009 The University of Melbourne
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.
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.
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
20
"""Project submissions user interface."""
25
from storm.locals import Store
27
from ivle.database import (User, ProjectGroup, Offering, Subject, Semester,
28
ProjectSet, Project, Enrolment)
29
from ivle.webapp.errors import NotFound, BadRequest
30
from ivle.webapp.base.xhtml import XHTMLView
31
from ivle.webapp.base.plugins import ViewPlugin
36
class SubmitView(XHTMLView):
37
"""A view to submit a Subversion repository path for a project."""
38
template = 'submit.html'
40
permission = 'submit_project'
42
def __init__(self, req, name, path):
43
# We need to work out which entity owns the repository, so we look
44
# at the first two path segments. The first tells us the type.
45
self.context = self.get_repository_owner(req.store, name)
46
self.path = os.path.normpath(path)
48
if self.context is None:
51
self.offering = self.get_offering()
53
def get_repository_owner(self, store, name):
54
"""Return the owner of the repository given the name and a Store."""
55
raise NotImplementedError()
57
def get_offering(self):
58
"""Return the offering that this path can be submitted to."""
59
raise NotImplementedError()
61
def populate(self, req, ctx):
62
if req.method == 'POST':
63
data = dict(req.get_fieldstorage())
64
if 'revision' not in data:
65
raise BadRequest('No revision selected.')
68
revision = int(data['revision'])
70
raise BadRequest('Revision must be an integer.')
72
if 'project' not in data:
73
raise BadRequest('No project selected.')
76
projectid = int(data['project'])
78
raise BadRequest('Project must be an integer.')
80
project = req.store.find(Project, Project.id == projectid).one()
82
# This view's offering will be the sole offering for which the
83
# path is permissible. We need to check that.
84
if project.project_set.offering is not self.offering:
85
raise BadRequest('Path is not permissible for this offering')
88
raise BadRequest('Specified project does not exist')
90
project.submit(self.context, self.path, revision, req.user)
92
self.template = 'submitted.html'
93
ctx['project'] = project
96
ctx['principal'] = self.context
97
ctx['offering'] = self.offering
98
ctx['path'] = self.path
99
ctx['now'] = datetime.datetime.now()
100
ctx['format_datetime'] = ivle.date.format_datetime_for_paragraph
103
class UserSubmitView(SubmitView):
104
def get_repository_owner(self, store, name):
105
'''Resolve the user name into a user.'''
106
return User.get_by_login(store, name)
108
def get_offering(self):
109
return Store.of(self.context).find(Offering,
110
Offering.id == Enrolment.offering_id,
111
Enrolment.user_id == self.context.id,
112
Offering.semester_id == Semester.id,
113
Semester.state == u'current',
114
Offering.subject_id == Subject.id,
115
Subject.short_name == self.path.split('/')[0],
119
class GroupSubmitView(SubmitView):
120
def get_repository_owner(self, store, name):
121
'''Resolve the subject_year_semester_group name into a group.'''
122
namebits = name.split('_', 3)
123
if len(namebits) != 4:
126
# Find the project group with the given name in any project set in the
127
# offering of the given subject in the semester with the given year
129
return store.find(ProjectGroup,
130
ProjectGroup.name == namebits[3],
131
ProjectGroup.project_set_id == ProjectSet.id,
132
ProjectSet.offering_id == Offering.id,
133
Offering.subject_id == Subject.id,
134
Subject.short_name == namebits[0],
135
Offering.semester_id == Semester.id,
136
Semester.year == namebits[1],
137
Semester.semester == namebits[2]).one()
139
def get_offering(self):
140
return self.context.project_set.offering
143
class Plugin(ViewPlugin):
145
('+submit/users/:name/*path', UserSubmitView),
146
('+submit/groups/:name/*path', GroupSubmitView),