23
23
# A sample / testing application for IVLE.
29
from storm.locals import Desc
31
from storm.locals import Desc, Store
30
33
from genshi.filters import HTMLFormFiller
34
from genshi.template import Context, TemplateLoader
33
37
from ivle.webapp.base.xhtml import XHTMLView
34
38
from ivle.webapp.base.plugins import ViewPlugin, MediaPlugin
35
from ivle.webapp.errors import NotFound
36
from ivle.database import Subject, Semester, Offering, Enrolment, User
39
from ivle.webapp import ApplicationRoot
41
from ivle.database import Subject, Semester, Offering, Enrolment, User,\
42
ProjectSet, Project, ProjectSubmission
37
43
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.publishing import (root_to_subject,
50
subject_to_offering, offering_to_projectset, offering_to_project,
51
subject_url, offering_url, projectset_url, project_url)
52
from ivle.webapp.admin.breadcrumbs import (SubjectBreadcrumb,
53
OfferingBreadcrumb, UserBreadcrumb, ProjectBreadcrumb)
40
55
class SubjectsView(XHTMLView):
41
56
'''The view of the list of subjects.'''
42
template = 'subjects.html'
57
template = 'templates/subjects.html'
45
60
def authorize(self, req):
124
127
ctx['offering'] = self.context
125
128
ctx['errors'] = errors
130
class OfferingProjectsView(XHTMLView):
131
"""View the projects for an offering."""
132
template = 'templates/offering_projects.html'
136
def project_url(self, projectset, project):
137
return "/subjects/%s/%s/%s/+projects/%s" % (
138
self.context.subject.short_name,
139
self.context.semester.year,
140
self.context.semester.semester,
144
def new_project_url(self, projectset):
145
return "/api/subjects/" + self.context.subject.short_name + "/" +\
146
self.context.semester.year + "/" + \
147
self.context.semester.semester + "/+projectsets/" +\
148
str(projectset.id) + "/+projects/+new"
150
def populate(self, req, ctx):
151
self.plugin_styles[Plugin] = ["project.css"]
152
self.plugin_scripts[Plugin] = ["project.js"]
153
ctx['offering'] = self.context
154
ctx['projectsets'] = []
156
#Open the projectset Fragment, and render it for inclusion
157
#into the ProjectSets page
158
#XXX: This could be a lot cleaner
159
loader = genshi.template.TemplateLoader(".", auto_reload=True)
161
set_fragment = os.path.join(os.path.dirname(__file__),
162
"templates/projectset_fragment.html")
163
project_fragment = os.path.join(os.path.dirname(__file__),
164
"templates/project_fragment.html")
166
for projectset in self.context.project_sets:
167
settmpl = loader.load(set_fragment)
169
setCtx['projectset'] = projectset
170
setCtx['new_project_url'] = self.new_project_url(projectset)
171
setCtx['projects'] = []
173
for project in projectset.projects:
174
projecttmpl = loader.load(project_fragment)
175
projectCtx = Context()
176
projectCtx['project'] = project
177
projectCtx['project_url'] = self.project_url(projectset, project)
179
setCtx['projects'].append(
180
projecttmpl.generate(projectCtx))
182
ctx['projectsets'].append(settmpl.generate(setCtx))
185
class ProjectView(XHTMLView):
186
"""View the submissions for a ProjectSet"""
187
template = "templates/project.html"
191
def build_subversion_url(self, svnroot, submission):
192
princ = submission.assessed.principal
194
if isinstance(princ, User):
195
path = 'users/%s' % princ.login
197
path = 'groups/%s_%s_%s_%s' % (
198
princ.project_set.offering.subject.short_name,
199
princ.project_set.offering.semester.year,
200
princ.project_set.offering.semester.semester,
203
return urlparse.urljoin(
205
os.path.join(path, submission.path[1:] if
206
submission.path.startswith(os.sep) else
209
def populate(self, req, ctx):
210
self.plugin_styles[Plugin] = ["project.css"]
212
ctx['format_datetime_short'] = ivle.date.format_datetime_for_paragraph
213
ctx['build_subversion_url'] = self.build_subversion_url
214
ctx['svn_addr'] = req.config['urls']['svn_addr']
215
ctx['project'] = self.context
216
ctx['user'] = req.user
218
class OfferingEnrolmentSet(object):
219
def __init__(self, offering):
220
self.offering = offering
128
222
class Plugin(ViewPlugin, MediaPlugin):
130
('subjects/', SubjectsView),
131
('subjects/:subject/:year/:semester/+enrolments/+new', EnrolView),
223
forward_routes = (root_to_subject, subject_to_offering,
224
offering_to_project, offering_to_projectset)
225
reverse_routes = (subject_url, offering_url, projectset_url, project_url)
227
views = [(ApplicationRoot, ('subjects', '+index'), SubjectsView),
228
(Offering, ('+enrolments', '+new'), EnrolView),
229
(Offering, ('+projects', '+index'), OfferingProjectsView),
230
(Project, '+index', ProjectView),
232
(Offering, ('+projectsets', '+new'), OfferingRESTView, 'api'),
233
(ProjectSet, ('+projects', '+new'), ProjectSetRESTView, 'api'),
234
(Project, '+index', ProjectRESTView, 'api'),
237
breadcrumbs = {Subject: SubjectBreadcrumb,
238
Offering: OfferingBreadcrumb,
239
User: UserBreadcrumb,
240
Project: ProjectBreadcrumb,
135
244
('subjects', 'Subjects',