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
47
from ivle.webapp.admin.offeringservice import OfferingRESTView
48
from ivle.webapp.admin.publishing import (root_to_subject,
49
subject_to_offering, offering_to_projectset, offering_to_project,
50
subject_url, offering_url, projectset_url, project_url)
51
from ivle.webapp.admin.breadcrumbs import (SubjectBreadcrumb,
52
OfferingBreadcrumb, UserBreadcrumb, ProjectBreadcrumb)
53
from ivle.webapp.groups import GroupsView
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):
102
class RoleEnrolmentValidator(formencode.FancyValidator):
103
"""A FormEncode validator that checks permission to enrol users with a
106
The state must have an 'offering' attribute.
108
def _to_python(self, value, state):
109
if ("enrol_" + value) not in state.offering.get_permissions(state.user):
110
raise formencode.Invalid('Not allowed to assign users that role',
82
115
class EnrolSchema(formencode.Schema):
83
116
user = formencode.All(NoEnrolmentValidator(), UserValidator())
117
role = formencode.All(formencode.validators.OneOf(
118
["lecturer", "tutor", "student"]),
119
RoleEnrolmentValidator(),
120
formencode.validators.UnicodeString())
123
class EnrolmentsView(XHTMLView):
124
"""A page which displays all users enrolled in an offering."""
125
template = 'templates/enrolments.html'
128
def populate(self, req, ctx):
129
ctx['offering'] = self.context
86
131
class EnrolView(XHTMLView):
87
132
"""A form to enrol a user in an offering."""
88
template = 'enrol.html'
133
template = 'templates/enrol.html'
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()
104
137
def filter(self, stream, ctx):
105
138
return stream | HTMLFormFiller(data=ctx['data'])
123
156
ctx['data'] = data or {}
124
157
ctx['offering'] = self.context
158
ctx['roles_auth'] = self.context.get_permissions(req.user)
125
159
ctx['errors'] = errors
161
class OfferingProjectsView(XHTMLView):
162
"""View the projects for an offering."""
163
template = 'templates/offering_projects.html'
167
def populate(self, req, ctx):
168
self.plugin_styles[Plugin] = ["project.css"]
169
self.plugin_scripts[Plugin] = ["project.js"]
171
ctx['offering'] = self.context
172
ctx['projectsets'] = []
173
ctx['OfferingRESTView'] = OfferingRESTView
175
#Open the projectset Fragment, and render it for inclusion
176
#into the ProjectSets page
177
#XXX: This could be a lot cleaner
178
loader = genshi.template.TemplateLoader(".", auto_reload=True)
180
set_fragment = os.path.join(os.path.dirname(__file__),
181
"templates/projectset_fragment.html")
182
project_fragment = os.path.join(os.path.dirname(__file__),
183
"templates/project_fragment.html")
185
for projectset in self.context.project_sets:
186
settmpl = loader.load(set_fragment)
189
setCtx['projectset'] = projectset
190
setCtx['projects'] = []
191
setCtx['GroupsView'] = GroupsView
192
setCtx['ProjectSetRESTView'] = ProjectSetRESTView
194
for project in projectset.projects:
195
projecttmpl = loader.load(project_fragment)
196
projectCtx = Context()
197
projectCtx['req'] = req
198
projectCtx['project'] = project
200
setCtx['projects'].append(
201
projecttmpl.generate(projectCtx))
203
ctx['projectsets'].append(settmpl.generate(setCtx))
206
class ProjectView(XHTMLView):
207
"""View the submissions for a ProjectSet"""
208
template = "templates/project.html"
212
def build_subversion_url(self, svnroot, submission):
213
princ = submission.assessed.principal
215
if isinstance(princ, User):
216
path = 'users/%s' % princ.login
218
path = 'groups/%s_%s_%s_%s' % (
219
princ.project_set.offering.subject.short_name,
220
princ.project_set.offering.semester.year,
221
princ.project_set.offering.semester.semester,
224
return urlparse.urljoin(
226
os.path.join(path, submission.path[1:] if
227
submission.path.startswith(os.sep) else
230
def populate(self, req, ctx):
231
self.plugin_styles[Plugin] = ["project.css"]
234
ctx['GroupsView'] = GroupsView
235
ctx['EnrolView'] = EnrolView
236
ctx['format_datetime_short'] = ivle.date.format_datetime_for_paragraph
237
ctx['build_subversion_url'] = self.build_subversion_url
238
ctx['svn_addr'] = req.config['urls']['svn_addr']
239
ctx['project'] = self.context
240
ctx['user'] = req.user
128
242
class Plugin(ViewPlugin, MediaPlugin):
130
('subjects/', SubjectsView),
131
('subjects/:subject/:year/:semester/+enrolments/+new', EnrolView),
243
forward_routes = (root_to_subject, subject_to_offering,
244
offering_to_project, offering_to_projectset)
245
reverse_routes = (subject_url, offering_url, projectset_url, project_url)
247
views = [(ApplicationRoot, ('subjects', '+index'), SubjectsView),
248
(Offering, ('+enrolments', '+index'), EnrolmentsView),
249
(Offering, ('+enrolments', '+new'), EnrolView),
250
(Offering, ('+projects', '+index'), OfferingProjectsView),
251
(Project, '+index', ProjectView),
253
(Offering, ('+projectsets', '+new'), OfferingRESTView, 'api'),
254
(ProjectSet, ('+projects', '+new'), ProjectSetRESTView, 'api'),
257
breadcrumbs = {Subject: SubjectBreadcrumb,
258
Offering: OfferingBreadcrumb,
259
User: UserBreadcrumb,
260
Project: ProjectBreadcrumb,
135
264
('subjects', 'Subjects',