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

« back to all changes in this revision

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

  • Committer: David Coles
  • Date: 2009-12-10 01:18:36 UTC
  • Revision ID: coles.david@gmail.com-20091210011836-6kk2omcmr9hvphj0
Correct documentation's system diagram (console communication goes via Application Slaves)

Show diffs side-by-side

added added

removed removed

Lines of Context:
23
23
# A sample / testing application for IVLE.
24
24
 
25
25
import os
 
26
import os.path
26
27
import urllib
 
28
import urlparse
27
29
import cgi
28
30
 
29
 
from storm.locals import Desc
 
31
from storm.locals import Desc, Store
 
32
import genshi
30
33
from genshi.filters import HTMLFormFiller
 
34
from genshi.template import Context, TemplateLoader
31
35
import formencode
32
36
 
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
 
40
 
 
41
from ivle.database import Subject, Semester, Offering, Enrolment, User,\
 
42
                          ProjectSet, Project, ProjectSubmission
37
43
from ivle import util
 
44
import ivle.date
38
45
 
 
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
39
54
 
40
55
class SubjectsView(XHTMLView):
41
56
    '''The view of the list of subjects.'''
42
 
    template = 'subjects.html'
 
57
    template = 'templates/subjects.html'
43
58
    tab = 'subjects'
44
59
 
45
60
    def authorize(self, req):
50
65
        ctx['semesters'] = []
51
66
        for semester in req.store.find(Semester).order_by(Desc(Semester.year),
52
67
                                                     Desc(Semester.semester)):
53
 
            enrolments = semester.enrolments.find(user=req.user)
54
 
            if enrolments.count():
55
 
                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))
56
76
 
57
77
 
58
78
class UserValidator(formencode.FancyValidator):
79
99
        return value
80
100
 
81
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
 
82
115
class EnrolSchema(formencode.Schema):
83
116
    user = formencode.All(NoEnrolmentValidator(), UserValidator())
84
 
 
 
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
85
130
 
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'
89
134
    tab = 'subjects'
90
 
    permission = 'edit'
91
 
 
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()
100
 
 
101
 
        if not self.context:
102
 
            raise NotFound()
 
135
    permission = 'enrol'
103
136
 
104
137
    def filter(self, stream, ctx):
105
138
        return stream | HTMLFormFiller(data=ctx['data'])
111
144
                validator = EnrolSchema()
112
145
                req.offering = self.context # XXX: Getting into state.
113
146
                data = validator.to_python(data, state=req)
114
 
                self.context.enrol(data['user'])
 
147
                self.context.enrol(data['user'], data['role'])
115
148
                req.store.commit()
116
149
                req.throw_redirect(req.uri)
117
150
            except formencode.Invalid, e:
122
155
 
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
126
160
 
 
161
class OfferingProjectsView(XHTMLView):
 
162
    """View the projects for an offering."""
 
163
    template = 'templates/offering_projects.html'
 
164
    permission = 'edit'
 
165
    tab = 'subjects'
 
166
 
 
167
    def populate(self, req, ctx):
 
168
        self.plugin_styles[Plugin] = ["project.css"]
 
169
        self.plugin_scripts[Plugin] = ["project.js"]
 
170
        ctx['req'] = req
 
171
        ctx['offering'] = self.context
 
172
        ctx['projectsets'] = []
 
173
        ctx['OfferingRESTView'] = OfferingRESTView
 
174
 
 
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)
 
179
 
 
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")
 
184
 
 
185
        for projectset in self.context.project_sets:
 
186
            settmpl = loader.load(set_fragment)
 
187
            setCtx = Context()
 
188
            setCtx['req'] = req
 
189
            setCtx['projectset'] = projectset
 
190
            setCtx['projects'] = []
 
191
            setCtx['GroupsView'] = GroupsView
 
192
            setCtx['ProjectSetRESTView'] = ProjectSetRESTView
 
193
 
 
194
            for project in projectset.projects:
 
195
                projecttmpl = loader.load(project_fragment)
 
196
                projectCtx = Context()
 
197
                projectCtx['req'] = req
 
198
                projectCtx['project'] = project
 
199
 
 
200
                setCtx['projects'].append(
 
201
                        projecttmpl.generate(projectCtx))
 
202
 
 
203
            ctx['projectsets'].append(settmpl.generate(setCtx))
 
204
 
 
205
 
 
206
class ProjectView(XHTMLView):
 
207
    """View the submissions for a ProjectSet"""
 
208
    template = "templates/project.html"
 
209
    permission = "edit"
 
210
    tab = 'subjects'
 
211
 
 
212
    def build_subversion_url(self, svnroot, submission):
 
213
        princ = submission.assessed.principal
 
214
 
 
215
        if isinstance(princ, User):
 
216
            path = 'users/%s' % princ.login
 
217
        else:
 
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,
 
222
                    princ.name
 
223
                    )
 
224
        return urlparse.urljoin(
 
225
                    svnroot,
 
226
                    os.path.join(path, submission.path[1:] if
 
227
                                       submission.path.startswith(os.sep) else
 
228
                                       submission.path))
 
229
 
 
230
    def populate(self, req, ctx):
 
231
        self.plugin_styles[Plugin] = ["project.css"]
 
232
 
 
233
        ctx['req'] = req
 
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
127
241
 
128
242
class Plugin(ViewPlugin, MediaPlugin):
129
 
    urls = [
130
 
        ('subjects/', SubjectsView),
131
 
        ('subjects/:subject/:year/:semester/+enrolments/+new', EnrolView),
132
 
    ]
 
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
                   }
133
262
 
134
263
    tabs = [
135
264
        ('subjects', 'Subjects',