~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-08 23:45:39 UTC
  • mto: This revision was merged to the branch mainline in revision 1384.
  • Revision ID: grantw@unimelb.edu.au-20091208234539-rtge6krc4uab0ccc
Remove ProjectRESTView, which did nothing and was unused.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# IVLE
 
2
# Copyright (C) 2007-2008 The University of Melbourne
 
3
#
 
4
# This program is free software; you can redistribute it and/or modify
 
5
# it under the terms of the GNU General Public License as published by
 
6
# the Free Software Foundation; either version 2 of the License, or
 
7
# (at your option) any later version.
 
8
#
 
9
# This program is distributed in the hope that it will be useful,
 
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
12
# GNU General Public License for more details.
 
13
#
 
14
# You should have received a copy of the GNU General Public License
 
15
# along with this program; if not, write to the Free Software
 
16
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
17
 
 
18
# App: subjects
 
19
# Author: Matt Giuca
 
20
# Date: 29/2/2008
 
21
 
 
22
# This is an IVLE application.
 
23
# A sample / testing application for IVLE.
 
24
 
 
25
import os
 
26
import os.path
 
27
import urllib
 
28
import urlparse
 
29
import cgi
 
30
 
 
31
from storm.locals import Desc, Store
 
32
import genshi
 
33
from genshi.filters import HTMLFormFiller
 
34
from genshi.template import Context, TemplateLoader
 
35
import formencode
 
36
 
 
37
from ivle.webapp.base.xhtml import XHTMLView
 
38
from ivle.webapp.base.plugins import ViewPlugin, MediaPlugin
 
39
from ivle.webapp import ApplicationRoot
 
40
 
 
41
from ivle.database import Subject, Semester, Offering, Enrolment, User,\
 
42
                          ProjectSet, Project, ProjectSubmission
 
43
from ivle import util
 
44
import ivle.date
 
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
 
54
 
 
55
class SubjectsView(XHTMLView):
 
56
    '''The view of the list of subjects.'''
 
57
    template = 'templates/subjects.html'
 
58
    tab = 'subjects'
 
59
 
 
60
    def authorize(self, req):
 
61
        return req.user is not None
 
62
 
 
63
    def populate(self, req, ctx):
 
64
        ctx['user'] = req.user
 
65
        ctx['semesters'] = []
 
66
        for semester in req.store.find(Semester).order_by(Desc(Semester.year),
 
67
                                                     Desc(Semester.semester)):
 
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))
 
76
 
 
77
 
 
78
class UserValidator(formencode.FancyValidator):
 
79
    """A FormEncode validator that turns a username into a user.
 
80
 
 
81
    The state must have a 'store' attribute, which is the Storm store
 
82
    to use."""
 
83
    def _to_python(self, value, state):
 
84
        user = User.get_by_login(state.store, value)
 
85
        if user:
 
86
            return user
 
87
        else:
 
88
            raise formencode.Invalid('User does not exist', value, state)
 
89
 
 
90
 
 
91
class NoEnrolmentValidator(formencode.FancyValidator):
 
92
    """A FormEncode validator that ensures absence of an enrolment.
 
93
 
 
94
    The state must have an 'offering' attribute.
 
95
    """
 
96
    def _to_python(self, value, state):
 
97
        if state.offering.get_enrolment(value):
 
98
            raise formencode.Invalid('User already enrolled', value, state)
 
99
        return value
 
100
 
 
101
 
 
102
class EnrolSchema(formencode.Schema):
 
103
    user = formencode.All(NoEnrolmentValidator(), UserValidator())
 
104
 
 
105
 
 
106
class EnrolmentsView(XHTMLView):
 
107
    """A page which displays all users enrolled in an offering."""
 
108
    template = 'templates/enrolments.html'
 
109
    permission = 'edit'
 
110
 
 
111
    def populate(self, req, ctx):
 
112
        ctx['offering'] = self.context
 
113
 
 
114
class EnrolView(XHTMLView):
 
115
    """A form to enrol a user in an offering."""
 
116
    template = 'templates/enrol.html'
 
117
    tab = 'subjects'
 
118
    permission = 'edit'
 
119
 
 
120
    def filter(self, stream, ctx):
 
121
        return stream | HTMLFormFiller(data=ctx['data'])
 
122
 
 
123
    def populate(self, req, ctx):
 
124
        if req.method == 'POST':
 
125
            data = dict(req.get_fieldstorage())
 
126
            try:
 
127
                validator = EnrolSchema()
 
128
                req.offering = self.context # XXX: Getting into state.
 
129
                data = validator.to_python(data, state=req)
 
130
                self.context.enrol(data['user'])
 
131
                req.store.commit()
 
132
                req.throw_redirect(req.uri)
 
133
            except formencode.Invalid, e:
 
134
                errors = e.unpack_errors()
 
135
        else:
 
136
            data = {}
 
137
            errors = {}
 
138
 
 
139
        ctx['data'] = data or {}
 
140
        ctx['offering'] = self.context
 
141
        ctx['errors'] = errors
 
142
 
 
143
class OfferingProjectsView(XHTMLView):
 
144
    """View the projects for an offering."""
 
145
    template = 'templates/offering_projects.html'
 
146
    permission = 'edit'
 
147
    tab = 'subjects'
 
148
 
 
149
    def populate(self, req, ctx):
 
150
        self.plugin_styles[Plugin] = ["project.css"]
 
151
        self.plugin_scripts[Plugin] = ["project.js"]
 
152
        ctx['req'] = req
 
153
        ctx['offering'] = self.context
 
154
        ctx['projectsets'] = []
 
155
        ctx['OfferingRESTView'] = OfferingRESTView
 
156
 
 
157
        #Open the projectset Fragment, and render it for inclusion
 
158
        #into the ProjectSets page
 
159
        #XXX: This could be a lot cleaner
 
160
        loader = genshi.template.TemplateLoader(".", auto_reload=True)
 
161
 
 
162
        set_fragment = os.path.join(os.path.dirname(__file__),
 
163
                "templates/projectset_fragment.html")
 
164
        project_fragment = os.path.join(os.path.dirname(__file__),
 
165
                "templates/project_fragment.html")
 
166
 
 
167
        for projectset in self.context.project_sets:
 
168
            settmpl = loader.load(set_fragment)
 
169
            setCtx = Context()
 
170
            setCtx['req'] = req
 
171
            setCtx['projectset'] = projectset
 
172
            setCtx['projects'] = []
 
173
            setCtx['GroupsView'] = GroupsView
 
174
            setCtx['ProjectSetRESTView'] = ProjectSetRESTView
 
175
 
 
176
            for project in projectset.projects:
 
177
                projecttmpl = loader.load(project_fragment)
 
178
                projectCtx = Context()
 
179
                projectCtx['req'] = req
 
180
                projectCtx['project'] = project
 
181
 
 
182
                setCtx['projects'].append(
 
183
                        projecttmpl.generate(projectCtx))
 
184
 
 
185
            ctx['projectsets'].append(settmpl.generate(setCtx))
 
186
 
 
187
 
 
188
class ProjectView(XHTMLView):
 
189
    """View the submissions for a ProjectSet"""
 
190
    template = "templates/project.html"
 
191
    permission = "edit"
 
192
    tab = 'subjects'
 
193
 
 
194
    def build_subversion_url(self, svnroot, submission):
 
195
        princ = submission.assessed.principal
 
196
 
 
197
        if isinstance(princ, User):
 
198
            path = 'users/%s' % princ.login
 
199
        else:
 
200
            path = 'groups/%s_%s_%s_%s' % (
 
201
                    princ.project_set.offering.subject.short_name,
 
202
                    princ.project_set.offering.semester.year,
 
203
                    princ.project_set.offering.semester.semester,
 
204
                    princ.name
 
205
                    )
 
206
        return urlparse.urljoin(
 
207
                    svnroot,
 
208
                    os.path.join(path, submission.path[1:] if
 
209
                                       submission.path.startswith(os.sep) else
 
210
                                       submission.path))
 
211
 
 
212
    def populate(self, req, ctx):
 
213
        self.plugin_styles[Plugin] = ["project.css"]
 
214
 
 
215
        ctx['format_datetime_short'] = ivle.date.format_datetime_for_paragraph
 
216
        ctx['build_subversion_url'] = self.build_subversion_url
 
217
        ctx['svn_addr'] = req.config['urls']['svn_addr']
 
218
        ctx['project'] = self.context
 
219
        ctx['user'] = req.user
 
220
 
 
221
class Plugin(ViewPlugin, MediaPlugin):
 
222
    forward_routes = (root_to_subject, subject_to_offering,
 
223
                      offering_to_project, offering_to_projectset)
 
224
    reverse_routes = (subject_url, offering_url, projectset_url, project_url)
 
225
 
 
226
    views = [(ApplicationRoot, ('subjects', '+index'), SubjectsView),
 
227
             (Offering, ('+enrolments', '+index'), EnrolmentsView),
 
228
             (Offering, ('+enrolments', '+new'), EnrolView),
 
229
             (Offering, ('+projects', '+index'), OfferingProjectsView),
 
230
             (Project, '+index', ProjectView),
 
231
 
 
232
             (Offering, ('+projectsets', '+new'), OfferingRESTView, 'api'),
 
233
             (ProjectSet, ('+projects', '+new'), ProjectSetRESTView, 'api'),
 
234
             ]
 
235
 
 
236
    breadcrumbs = {Subject: SubjectBreadcrumb,
 
237
                   Offering: OfferingBreadcrumb,
 
238
                   User: UserBreadcrumb,
 
239
                   Project: ProjectBreadcrumb,
 
240
                   }
 
241
 
 
242
    tabs = [
 
243
        ('subjects', 'Subjects',
 
244
         'View subject content and complete worksheets',
 
245
         'subjects.png', 'subjects', 5)
 
246
    ]
 
247
 
 
248
    media = 'subject-media'