~azzar1/unity/add-show-desktop-key

« back to all changes in this revision

Viewing changes to ivle/webapp/admin/subject.py

  • Committer: William Grant
  • Date: 2009-12-09 09:24:45 UTC
  • mto: This revision was merged to the branch mainline in revision 1396.
  • Revision ID: grantw@unimelb.edu.au-20091209092445-3351kawijoxhnbd1
Add note about the _check_code string->function eval hack.

Show diffs side-by-side

added added

removed removed

Lines of Context:
28
28
import urlparse
29
29
import cgi
30
30
 
31
 
from storm.locals import Desc
 
31
from storm.locals import Desc, Store
32
32
import genshi
33
33
from genshi.filters import HTMLFormFiller
34
34
from genshi.template import Context, TemplateLoader
36
36
 
37
37
from ivle.webapp.base.xhtml import XHTMLView
38
38
from ivle.webapp.base.plugins import ViewPlugin, MediaPlugin
39
 
from ivle.webapp.errors import NotFound
 
39
from ivle.webapp import ApplicationRoot
40
40
 
41
41
from ivle.database import Subject, Semester, Offering, Enrolment, User,\
42
42
                          ProjectSet, Project, ProjectSubmission
43
43
from ivle import util
44
44
import ivle.date
45
45
 
46
 
from ivle.webapp.admin.projectservice import ProjectSetRESTView,\
47
 
                                             ProjectRESTView
 
46
from ivle.webapp.admin.projectservice import ProjectSetRESTView
48
47
from ivle.webapp.admin.offeringservice import OfferingRESTView
49
 
 
 
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
50
54
 
51
55
class SubjectsView(XHTMLView):
52
56
    '''The view of the list of subjects.'''
61
65
        ctx['semesters'] = []
62
66
        for semester in req.store.find(Semester).order_by(Desc(Semester.year),
63
67
                                                     Desc(Semester.semester)):
64
 
            enrolments = semester.enrolments.find(user=req.user)
65
 
            if enrolments.count():
66
 
                ctx['semesters'].append((semester, enrolments))
 
68
            if req.user.admin:
 
69
                # For admins, show all subjects in the system
 
70
                offerings = list(semester.offerings.find())
 
71
            else:
 
72
                offerings = [enrolment.offering for enrolment in
 
73
                                    semester.enrolments.find(user=req.user)]
 
74
            if len(offerings):
 
75
                ctx['semesters'].append((semester, offerings))
67
76
 
68
77
 
69
78
class UserValidator(formencode.FancyValidator):
90
99
        return value
91
100
 
92
101
 
 
102
class RoleEnrolmentValidator(formencode.FancyValidator):
 
103
    """A FormEncode validator that checks permission to enrol users with a
 
104
    particular role.
 
105
 
 
106
    The state must have an 'offering' attribute.
 
107
    """
 
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',
 
111
                                     value, state)
 
112
        return value
 
113
 
 
114
 
93
115
class EnrolSchema(formencode.Schema):
94
116
    user = formencode.All(NoEnrolmentValidator(), UserValidator())
95
 
 
 
117
    role = formencode.All(formencode.validators.OneOf(
 
118
                                ["lecturer", "tutor", "student"]),
 
119
                          RoleEnrolmentValidator(),
 
120
                          formencode.validators.UnicodeString())
 
121
 
 
122
 
 
123
class EnrolmentsView(XHTMLView):
 
124
    """A page which displays all users enrolled in an offering."""
 
125
    template = 'templates/enrolments.html'
 
126
    permission = 'edit'
 
127
 
 
128
    def populate(self, req, ctx):
 
129
        ctx['offering'] = self.context
96
130
 
97
131
class EnrolView(XHTMLView):
98
132
    """A form to enrol a user in an offering."""
99
133
    template = 'templates/enrol.html'
100
134
    tab = 'subjects'
101
 
    permission = 'edit'
102
 
 
103
 
    def __init__(self, req, subject, year, semester):
104
 
        """Find the given offering by subject, year and semester."""
105
 
        self.context = req.store.find(Offering,
106
 
            Offering.subject_id == Subject.id,
107
 
            Subject.short_name == subject,
108
 
            Offering.semester_id == Semester.id,
109
 
            Semester.year == year,
110
 
            Semester.semester == semester).one()
111
 
 
112
 
        if not self.context:
113
 
            raise NotFound()
 
135
    permission = 'enrol'
114
136
 
115
137
    def filter(self, stream, ctx):
116
138
        return stream | HTMLFormFiller(data=ctx['data'])
122
144
                validator = EnrolSchema()
123
145
                req.offering = self.context # XXX: Getting into state.
124
146
                data = validator.to_python(data, state=req)
125
 
                self.context.enrol(data['user'])
 
147
                self.context.enrol(data['user'], data['role'])
126
148
                req.store.commit()
127
149
                req.throw_redirect(req.uri)
128
150
            except formencode.Invalid, e:
133
155
 
134
156
        ctx['data'] = data or {}
135
157
        ctx['offering'] = self.context
 
158
        ctx['roles_auth'] = self.context.get_permissions(req.user)
136
159
        ctx['errors'] = errors
137
160
 
138
161
class OfferingProjectsView(XHTMLView):
140
163
    template = 'templates/offering_projects.html'
141
164
    permission = 'edit'
142
165
    tab = 'subjects'
143
 
    
144
 
    def __init__(self, req, subject, year, semester):
145
 
        self.context = req.store.find(Offering,
146
 
            Offering.subject_id == Subject.id,
147
 
            Subject.short_name == subject,
148
 
            Offering.semester_id == Semester.id,
149
 
            Semester.year == year,
150
 
            Semester.semester == semester).one()
151
 
 
152
 
        if not self.context:
153
 
            raise NotFound()
154
 
 
155
 
    def project_url(self, projectset, project):
156
 
        return "/subjects/%s/%s/%s/+projects/%s" % (
157
 
                    self.context.subject.short_name,
158
 
                    self.context.semester.year,
159
 
                    self.context.semester.semester,
160
 
                    project.short_name
161
 
                    )
162
 
 
163
 
    def new_project_url(self, projectset):
164
 
        return "/api/subjects/" + self.context.subject.short_name + "/" +\
165
 
                self.context.semester.year + "/" + \
166
 
                self.context.semester.semester + "/+projectsets/" +\
167
 
                str(projectset.id) + "/+projects/+new"
168
 
    
 
166
 
169
167
    def populate(self, req, ctx):
170
168
        self.plugin_styles[Plugin] = ["project.css"]
171
169
        self.plugin_scripts[Plugin] = ["project.js"]
 
170
        ctx['req'] = req
172
171
        ctx['offering'] = self.context
173
172
        ctx['projectsets'] = []
 
173
        ctx['OfferingRESTView'] = OfferingRESTView
174
174
 
175
175
        #Open the projectset Fragment, and render it for inclusion
176
176
        #into the ProjectSets page
185
185
        for projectset in self.context.project_sets:
186
186
            settmpl = loader.load(set_fragment)
187
187
            setCtx = Context()
 
188
            setCtx['req'] = req
188
189
            setCtx['projectset'] = projectset
189
 
            setCtx['new_project_url'] = self.new_project_url(projectset)
190
190
            setCtx['projects'] = []
 
191
            setCtx['GroupsView'] = GroupsView
 
192
            setCtx['ProjectSetRESTView'] = ProjectSetRESTView
191
193
 
192
194
            for project in projectset.projects:
193
195
                projecttmpl = loader.load(project_fragment)
194
196
                projectCtx = Context()
 
197
                projectCtx['req'] = req
195
198
                projectCtx['project'] = project
196
 
                projectCtx['project_url'] = self.project_url(projectset, project)
197
199
 
198
200
                setCtx['projects'].append(
199
201
                        projecttmpl.generate(projectCtx))
207
209
    permission = "edit"
208
210
    tab = 'subjects'
209
211
 
210
 
    def __init__(self, req, subject, year, semester, project):
211
 
        self.context = req.store.find(Project,
212
 
                Project.short_name == project,
213
 
                Project.project_set_id == ProjectSet.id,
214
 
                ProjectSet.offering_id == Offering.id,
215
 
                Offering.semester_id == Semester.id,
216
 
                Semester.year == year,
217
 
                Semester.semester == semester,
218
 
                Offering.subject_id == Subject.id,
219
 
                Subject.short_name == subject).one()
220
 
        if self.context is None:
221
 
            raise NotFound()
222
 
 
223
212
    def build_subversion_url(self, svnroot, submission):
224
213
        princ = submission.assessed.principal
225
214
 
241
230
    def populate(self, req, ctx):
242
231
        self.plugin_styles[Plugin] = ["project.css"]
243
232
 
 
233
        ctx['req'] = req
 
234
        ctx['GroupsView'] = GroupsView
 
235
        ctx['EnrolView'] = EnrolView
244
236
        ctx['format_datetime_short'] = ivle.date.format_datetime_for_paragraph
245
237
        ctx['build_subversion_url'] = self.build_subversion_url
246
238
        ctx['svn_addr'] = req.config['urls']['svn_addr']
248
240
        ctx['user'] = req.user
249
241
 
250
242
class Plugin(ViewPlugin, MediaPlugin):
251
 
    urls = [
252
 
        ('subjects/', SubjectsView),
253
 
        ('subjects/:subject/:year/:semester/+enrolments/+new', EnrolView),
254
 
        ('subjects/:subject/:year/:semester/+projects', OfferingProjectsView),
255
 
        ('subjects/:subject/:year/:semester/+projects/:project', ProjectView),
256
 
        #API Views
257
 
        ('api/subjects/:subject/:year/:semester/+projectsets/+new',
258
 
            OfferingRESTView),
259
 
        ('api/subjects/:subject/:year/:semester/+projectsets/:projectset/+projects/+new',
260
 
            ProjectSetRESTView),
261
 
        ('api/subjects/:subject/:year/:semester/+projects/:project', 
262
 
            ProjectRESTView),
263
 
 
264
 
    ]
 
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)
 
246
 
 
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),
 
252
 
 
253
             (Offering, ('+projectsets', '+new'), OfferingRESTView, 'api'),
 
254
             (ProjectSet, ('+projects', '+new'), ProjectSetRESTView, 'api'),
 
255
             ]
 
256
 
 
257
    breadcrumbs = {Subject: SubjectBreadcrumb,
 
258
                   Offering: OfferingBreadcrumb,
 
259
                   User: UserBreadcrumb,
 
260
                   Project: ProjectBreadcrumb,
 
261
                   }
265
262
 
266
263
    tabs = [
267
264
        ('subjects', 'Subjects',