23
23
# A sample / testing application for IVLE.
31
from storm.locals import Desc, Store
29
from storm.locals import Desc
33
30
from genshi.filters import HTMLFormFiller
34
from genshi.template import Context, TemplateLoader
37
33
from ivle.webapp.base.xhtml import XHTMLView
38
34
from ivle.webapp.base.plugins import ViewPlugin, MediaPlugin
39
from ivle.webapp import ApplicationRoot
41
from ivle.database import Subject, Semester, Offering, Enrolment, User,\
42
ProjectSet, Project, ProjectSubmission
35
from ivle.webapp.errors import NotFound
36
from ivle.database import Subject, Semester, Offering, Enrolment, User
43
37
from ivle import util
46
from ivle.webapp.admin.projectservice import ProjectSetRESTView,\
48
from ivle.webapp.admin.offeringservice import OfferingRESTView
49
from ivle.webapp.admin.traversal import (root_to_subject,
50
subject_to_offering, offering_to_projectset, offering_to_project,
51
subject_url, offering_url, projectset_url, project_url)
53
40
class SubjectsView(XHTMLView):
54
41
'''The view of the list of subjects.'''
55
template = 'templates/subjects.html'
42
template = 'subjects.html'
58
45
def authorize(self, req):
99
86
class EnrolView(XHTMLView):
100
87
"""A form to enrol a user in an offering."""
101
template = 'templates/enrol.html'
88
template = 'enrol.html'
103
90
permission = 'edit'
92
def __init__(self, req, subject, year, semester):
93
"""Find the given offering by subject, year and semester."""
94
self.context = req.store.find(Offering,
95
Offering.subject_id == Subject.id,
96
Subject.short_name == subject,
97
Offering.semester_id == Semester.id,
98
Semester.year == year,
99
Semester.semester == semester).one()
105
104
def filter(self, stream, ctx):
106
105
return stream | HTMLFormFiller(data=ctx['data'])
125
124
ctx['offering'] = self.context
126
125
ctx['errors'] = errors
128
class OfferingProjectsView(XHTMLView):
129
"""View the projects for an offering."""
130
template = 'templates/offering_projects.html'
134
def project_url(self, projectset, project):
135
return "/subjects/%s/%s/%s/+projects/%s" % (
136
self.context.subject.short_name,
137
self.context.semester.year,
138
self.context.semester.semester,
142
def new_project_url(self, projectset):
143
return "/api/subjects/" + self.context.subject.short_name + "/" +\
144
self.context.semester.year + "/" + \
145
self.context.semester.semester + "/+projectsets/" +\
146
str(projectset.id) + "/+projects/+new"
148
def populate(self, req, ctx):
149
self.plugin_styles[Plugin] = ["project.css"]
150
self.plugin_scripts[Plugin] = ["project.js"]
151
ctx['offering'] = self.context
152
ctx['projectsets'] = []
154
#Open the projectset Fragment, and render it for inclusion
155
#into the ProjectSets page
156
#XXX: This could be a lot cleaner
157
loader = genshi.template.TemplateLoader(".", auto_reload=True)
159
set_fragment = os.path.join(os.path.dirname(__file__),
160
"templates/projectset_fragment.html")
161
project_fragment = os.path.join(os.path.dirname(__file__),
162
"templates/project_fragment.html")
164
for projectset in self.context.project_sets:
165
settmpl = loader.load(set_fragment)
167
setCtx['projectset'] = projectset
168
setCtx['new_project_url'] = self.new_project_url(projectset)
169
setCtx['projects'] = []
171
for project in projectset.projects:
172
projecttmpl = loader.load(project_fragment)
173
projectCtx = Context()
174
projectCtx['project'] = project
175
projectCtx['project_url'] = self.project_url(projectset, project)
177
setCtx['projects'].append(
178
projecttmpl.generate(projectCtx))
180
ctx['projectsets'].append(settmpl.generate(setCtx))
183
class ProjectView(XHTMLView):
184
"""View the submissions for a ProjectSet"""
185
template = "templates/project.html"
189
def build_subversion_url(self, svnroot, submission):
190
princ = submission.assessed.principal
192
if isinstance(princ, User):
193
path = 'users/%s' % princ.login
195
path = 'groups/%s_%s_%s_%s' % (
196
princ.project_set.offering.subject.short_name,
197
princ.project_set.offering.semester.year,
198
princ.project_set.offering.semester.semester,
201
return urlparse.urljoin(
203
os.path.join(path, submission.path[1:] if
204
submission.path.startswith(os.sep) else
207
def populate(self, req, ctx):
208
self.plugin_styles[Plugin] = ["project.css"]
210
ctx['format_datetime_short'] = ivle.date.format_datetime_for_paragraph
211
ctx['build_subversion_url'] = self.build_subversion_url
212
ctx['svn_addr'] = req.config['urls']['svn_addr']
213
ctx['project'] = self.context
214
ctx['user'] = req.user
216
class OfferingEnrolmentSet(object):
217
def __init__(self, offering):
218
self.offering = offering
220
128
class Plugin(ViewPlugin, MediaPlugin):
221
forward_routes = (root_to_subject, subject_to_offering,
222
offering_to_project, offering_to_projectset)
223
reverse_routes = (subject_url, offering_url, projectset_url, project_url)
225
views = [(ApplicationRoot, ('subjects', '+index'), SubjectsView),
226
(Offering, ('+enrolments', '+new'), EnrolView),
227
(Offering, ('+projects', '+index'), OfferingProjectsView),
228
(Project, '+index', ProjectView),
230
(Offering, ('+projectsets', '+new'), OfferingRESTView, 'api'),
231
(ProjectSet, ('+projects', '+new'), ProjectSetRESTView, 'api'),
232
(Project, '+index', ProjectRESTView, 'api'),
130
('subjects/', SubjectsView),
131
('subjects/:subject/:year/:semester/+enrolments/+new', EnrolView),
236
135
('subjects', 'Subjects',