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

« back to all changes in this revision

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

  • Committer: mattgiuca
  • Date: 2008-01-24 23:31:45 UTC
  • Revision ID: svn-v3-trunk0:2b9c9e99-6f39-0410-b283-7f802c844ae2:trunk:291
tutorial: Added code to handle top-level menu and subject menu (reads dir
    listing, XML files, and presents a list of links).
    Added code to handle a worksheet page. Presents the page as HTML,
    observing <problem> elements and reading in their XML files.
    Currently does not handle problems; just prints out their source files.
Added media/tutorial/tutorial.css (very minimal currently).

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
 
                                             ProjectRESTView
48
 
from ivle.webapp.admin.offeringservice import OfferingRESTView
49
 
from ivle.webapp.admin.publishing import (root_to_subject,
50
 
            subject_to_offering, offering_to_projectset, offering_to_project,
51
 
            subject_url, offering_url, projectset_url, project_url)
52
 
from ivle.webapp.admin.breadcrumbs import (SubjectBreadcrumb,
53
 
            OfferingBreadcrumb, UserBreadcrumb, ProjectBreadcrumb)
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
 
            enrolments = semester.enrolments.find(user=req.user)
69
 
            if enrolments.count():
70
 
                ctx['semesters'].append((semester, enrolments))
71
 
 
72
 
 
73
 
class UserValidator(formencode.FancyValidator):
74
 
    """A FormEncode validator that turns a username into a user.
75
 
 
76
 
    The state must have a 'store' attribute, which is the Storm store
77
 
    to use."""
78
 
    def _to_python(self, value, state):
79
 
        user = User.get_by_login(state.store, value)
80
 
        if user:
81
 
            return user
82
 
        else:
83
 
            raise formencode.Invalid('User does not exist', value, state)
84
 
 
85
 
 
86
 
class NoEnrolmentValidator(formencode.FancyValidator):
87
 
    """A FormEncode validator that ensures absence of an enrolment.
88
 
 
89
 
    The state must have an 'offering' attribute.
90
 
    """
91
 
    def _to_python(self, value, state):
92
 
        if state.offering.get_enrolment(value):
93
 
            raise formencode.Invalid('User already enrolled', value, state)
94
 
        return value
95
 
 
96
 
 
97
 
class EnrolSchema(formencode.Schema):
98
 
    user = formencode.All(NoEnrolmentValidator(), UserValidator())
99
 
 
100
 
 
101
 
class EnrolView(XHTMLView):
102
 
    """A form to enrol a user in an offering."""
103
 
    template = 'templates/enrol.html'
104
 
    tab = 'subjects'
105
 
    permission = 'edit'
106
 
 
107
 
    def filter(self, stream, ctx):
108
 
        return stream | HTMLFormFiller(data=ctx['data'])
109
 
 
110
 
    def populate(self, req, ctx):
111
 
        if req.method == 'POST':
112
 
            data = dict(req.get_fieldstorage())
113
 
            try:
114
 
                validator = EnrolSchema()
115
 
                req.offering = self.context # XXX: Getting into state.
116
 
                data = validator.to_python(data, state=req)
117
 
                self.context.enrol(data['user'])
118
 
                req.store.commit()
119
 
                req.throw_redirect(req.uri)
120
 
            except formencode.Invalid, e:
121
 
                errors = e.unpack_errors()
122
 
        else:
123
 
            data = {}
124
 
            errors = {}
125
 
 
126
 
        ctx['data'] = data or {}
127
 
        ctx['offering'] = self.context
128
 
        ctx['errors'] = errors
129
 
 
130
 
class OfferingProjectsView(XHTMLView):
131
 
    """View the projects for an offering."""
132
 
    template = 'templates/offering_projects.html'
133
 
    permission = 'edit'
134
 
    tab = 'subjects'
135
 
 
136
 
    def project_url(self, projectset, project):
137
 
        return "/subjects/%s/%s/%s/+projects/%s" % (
138
 
                    self.context.subject.short_name,
139
 
                    self.context.semester.year,
140
 
                    self.context.semester.semester,
141
 
                    project.short_name
142
 
                    )
143
 
 
144
 
    def new_project_url(self, projectset):
145
 
        return "/api/subjects/" + self.context.subject.short_name + "/" +\
146
 
                self.context.semester.year + "/" + \
147
 
                self.context.semester.semester + "/+projectsets/" +\
148
 
                str(projectset.id) + "/+projects/+new"
149
 
    
150
 
    def populate(self, req, ctx):
151
 
        self.plugin_styles[Plugin] = ["project.css"]
152
 
        self.plugin_scripts[Plugin] = ["project.js"]
153
 
        ctx['offering'] = self.context
154
 
        ctx['projectsets'] = []
155
 
 
156
 
        #Open the projectset Fragment, and render it for inclusion
157
 
        #into the ProjectSets page
158
 
        #XXX: This could be a lot cleaner
159
 
        loader = genshi.template.TemplateLoader(".", auto_reload=True)
160
 
 
161
 
        set_fragment = os.path.join(os.path.dirname(__file__),
162
 
                "templates/projectset_fragment.html")
163
 
        project_fragment = os.path.join(os.path.dirname(__file__),
164
 
                "templates/project_fragment.html")
165
 
 
166
 
        for projectset in self.context.project_sets:
167
 
            settmpl = loader.load(set_fragment)
168
 
            setCtx = Context()
169
 
            setCtx['projectset'] = projectset
170
 
            setCtx['new_project_url'] = self.new_project_url(projectset)
171
 
            setCtx['projects'] = []
172
 
 
173
 
            for project in projectset.projects:
174
 
                projecttmpl = loader.load(project_fragment)
175
 
                projectCtx = Context()
176
 
                projectCtx['project'] = project
177
 
                projectCtx['project_url'] = self.project_url(projectset, project)
178
 
 
179
 
                setCtx['projects'].append(
180
 
                        projecttmpl.generate(projectCtx))
181
 
 
182
 
            ctx['projectsets'].append(settmpl.generate(setCtx))
183
 
 
184
 
 
185
 
class ProjectView(XHTMLView):
186
 
    """View the submissions for a ProjectSet"""
187
 
    template = "templates/project.html"
188
 
    permission = "edit"
189
 
    tab = 'subjects'
190
 
 
191
 
    def build_subversion_url(self, svnroot, submission):
192
 
        princ = submission.assessed.principal
193
 
 
194
 
        if isinstance(princ, User):
195
 
            path = 'users/%s' % princ.login
196
 
        else:
197
 
            path = 'groups/%s_%s_%s_%s' % (
198
 
                    princ.project_set.offering.subject.short_name,
199
 
                    princ.project_set.offering.semester.year,
200
 
                    princ.project_set.offering.semester.semester,
201
 
                    princ.name
202
 
                    )
203
 
        return urlparse.urljoin(
204
 
                    svnroot,
205
 
                    os.path.join(path, submission.path[1:] if
206
 
                                       submission.path.startswith(os.sep) else
207
 
                                       submission.path))
208
 
 
209
 
    def populate(self, req, ctx):
210
 
        self.plugin_styles[Plugin] = ["project.css"]
211
 
 
212
 
        ctx['format_datetime_short'] = ivle.date.format_datetime_for_paragraph
213
 
        ctx['build_subversion_url'] = self.build_subversion_url
214
 
        ctx['svn_addr'] = req.config['urls']['svn_addr']
215
 
        ctx['project'] = self.context
216
 
        ctx['user'] = req.user
217
 
 
218
 
class OfferingEnrolmentSet(object):
219
 
    def __init__(self, offering):
220
 
        self.offering = offering
221
 
 
222
 
class Plugin(ViewPlugin, MediaPlugin):
223
 
    forward_routes = (root_to_subject, subject_to_offering,
224
 
                      offering_to_project, offering_to_projectset)
225
 
    reverse_routes = (subject_url, offering_url, projectset_url, project_url)
226
 
 
227
 
    views = [(ApplicationRoot, ('subjects', '+index'), SubjectsView),
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
 
             (Project, '+index', ProjectRESTView, 'api'),
235
 
             ]
236
 
 
237
 
    breadcrumbs = {Subject: SubjectBreadcrumb,
238
 
                   Offering: OfferingBreadcrumb,
239
 
                   User: UserBreadcrumb,
240
 
                   Project: ProjectBreadcrumb,
241
 
                   }
242
 
 
243
 
    tabs = [
244
 
        ('subjects', 'Subjects',
245
 
         'View subject content and complete worksheets',
246
 
         'subjects.png', 'subjects', 5)
247
 
    ]
248
 
 
249
 
    media = 'subject-media'