43
43
from ivle import util
46
from ivle.webapp.admin.projectservice import ProjectSetRESTView,\
46
from ivle.webapp.admin.projectservice import ProjectSetRESTView
48
47
from ivle.webapp.admin.offeringservice import OfferingRESTView
49
from ivle.webapp.admin.traversal import (root_to_subject,
48
from ivle.webapp.admin.publishing import (root_to_subject,
50
49
subject_to_offering, offering_to_projectset, offering_to_project,
51
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
53
55
class SubjectsView(XHTMLView):
54
56
'''The view of the list of subjects.'''
63
65
ctx['semesters'] = []
64
66
for semester in req.store.find(Semester).order_by(Desc(Semester.year),
65
67
Desc(Semester.semester)):
66
enrolments = semester.enrolments.find(user=req.user)
67
if enrolments.count():
68
ctx['semesters'].append((semester, enrolments))
69
# For admins, show all subjects in the system
70
offerings = list(semester.offerings.find())
72
offerings = [enrolment.offering for enrolment in
73
semester.enrolments.find(user=req.user)]
75
ctx['semesters'].append((semester, offerings))
71
78
class UserValidator(formencode.FancyValidator):
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',
95
115
class EnrolSchema(formencode.Schema):
96
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
99
131
class EnrolView(XHTMLView):
100
132
"""A form to enrol a user in an offering."""
101
133
template = 'templates/enrol.html'
105
137
def filter(self, stream, ctx):
106
138
return stream | HTMLFormFiller(data=ctx['data'])
112
144
validator = EnrolSchema()
113
145
req.offering = self.context # XXX: Getting into state.
114
146
data = validator.to_python(data, state=req)
115
self.context.enrol(data['user'])
147
self.context.enrol(data['user'], data['role'])
116
148
req.store.commit()
117
149
req.throw_redirect(req.uri)
118
150
except formencode.Invalid, e:
131
164
permission = 'edit'
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
167
def populate(self, req, ctx):
149
168
self.plugin_styles[Plugin] = ["project.css"]
150
169
self.plugin_scripts[Plugin] = ["project.js"]
151
171
ctx['offering'] = self.context
152
172
ctx['projectsets'] = []
173
ctx['OfferingRESTView'] = OfferingRESTView
154
175
#Open the projectset Fragment, and render it for inclusion
155
176
#into the ProjectSets page
164
185
for projectset in self.context.project_sets:
165
186
settmpl = loader.load(set_fragment)
166
187
setCtx = Context()
167
189
setCtx['projectset'] = projectset
168
setCtx['new_project_url'] = self.new_project_url(projectset)
169
190
setCtx['projects'] = []
191
setCtx['GroupsView'] = GroupsView
192
setCtx['ProjectSetRESTView'] = ProjectSetRESTView
171
194
for project in projectset.projects:
172
195
projecttmpl = loader.load(project_fragment)
173
196
projectCtx = Context()
197
projectCtx['req'] = req
174
198
projectCtx['project'] = project
175
projectCtx['project_url'] = self.project_url(projectset, project)
177
200
setCtx['projects'].append(
178
201
projecttmpl.generate(projectCtx))
207
230
def populate(self, req, ctx):
208
231
self.plugin_styles[Plugin] = ["project.css"]
234
ctx['GroupsView'] = GroupsView
235
ctx['EnrolView'] = EnrolView
210
236
ctx['format_datetime_short'] = ivle.date.format_datetime_for_paragraph
211
237
ctx['build_subversion_url'] = self.build_subversion_url
212
238
ctx['svn_addr'] = req.config['urls']['svn_addr']
213
239
ctx['project'] = self.context
214
240
ctx['user'] = req.user
216
class OfferingEnrolmentSet(object):
217
def __init__(self, offering):
218
self.offering = offering
220
242
class Plugin(ViewPlugin, MediaPlugin):
221
243
forward_routes = (root_to_subject, subject_to_offering,
222
244
offering_to_project, offering_to_projectset)
223
245
reverse_routes = (subject_url, offering_url, projectset_url, project_url)
225
247
views = [(ApplicationRoot, ('subjects', '+index'), SubjectsView),
248
(Offering, ('+enrolments', '+index'), EnrolmentsView),
226
249
(Offering, ('+enrolments', '+new'), EnrolView),
227
250
(Offering, ('+projects', '+index'), OfferingProjectsView),
228
251
(Project, '+index', ProjectView),
230
253
(Offering, ('+projectsets', '+new'), OfferingRESTView, 'api'),
231
254
(ProjectSet, ('+projects', '+new'), ProjectSetRESTView, 'api'),
232
(Project, '+index', ProjectRESTView, 'api'),
257
breadcrumbs = {Subject: SubjectBreadcrumb,
258
Offering: OfferingBreadcrumb,
259
User: UserBreadcrumb,
260
Project: ProjectBreadcrumb,
236
264
('subjects', 'Subjects',
237
265
'View subject content and complete worksheets',