40
40
from ivle.webapp.base.views import BaseView
41
41
from ivle.webapp.base.xhtml import XHTMLView
42
42
from ivle.webapp.base.plugins import ViewPlugin, MediaPlugin
43
from ivle.webapp.media import MediaFileView
43
from ivle.webapp.media import BaseMediaFileView
44
44
from ivle.webapp.errors import NotFound, Forbidden
45
45
from ivle.webapp.tutorial.rst import rst as rstfunc
46
46
from ivle.webapp.tutorial.service import AttemptsRESTView, \
67
67
'''The view of the index of worksheets for a subject.'''
68
68
template = 'subjectmenu.html'
69
69
appname = 'tutorial' # XXX
71
72
def __init__(self, req, subject):
72
self.subject = req.store.find(Subject, code=subject).one()
73
self.context = req.store.find(Subject, code=subject).one()
74
75
def populate(self, req, ctx):
75
76
self.plugin_styles[Plugin] = ['tutorial.css']
80
81
# Subject names must be valid identifiers
81
if not is_valid_subjname(self.subject.code):
82
if not is_valid_subjname(self.context.code):
84
85
# Parse the subject description file
85
86
# The subject directory must have a file "subject.xml" in it,
86
87
# or it does not exist (404 error).
87
ctx['subject'] = self.subject.code
88
ctx['subject'] = self.context.code
89
90
subjectfile = open(os.path.join(ivle.conf.subjects_base,
90
self.subject.code, "subject.xml")).read()
91
self.context.code, "subject.xml")).read()
101
102
problems_total = 0
102
103
for worksheet in ctx['worksheets']:
103
104
stored_worksheet = ivle.database.Worksheet.get_by_name(req.store,
104
self.subject.code, worksheet.id)
105
self.context.code, worksheet.id)
105
106
# If worksheet is not in database yet, we'll simply not display
106
107
# data about it yet (it should be added as soon as anyone visits
107
108
# the worksheet itself).
157
158
'''The view of a worksheet with exercises.'''
158
159
template = 'worksheet.html'
159
160
appname = 'tutorial' # XXX
161
163
def __init__(self, req, subject, worksheet):
162
self.subject = req.store.find(Subject, code=subject).one()
164
# XXX: Worksheet is actually context, but it's not really there yet.
165
self.context = req.store.find(Subject, code=subject).one()
163
166
self.worksheetname = worksheet
165
168
def populate(self, req, ctx):
166
169
self.plugin_scripts[Plugin] = ['tutorial.js']
167
170
self.plugin_styles[Plugin] = ['tutorial.css']
172
175
# Subject and worksheet names must be valid identifiers
173
if not is_valid_subjname(self.subject.code) or \
176
if not is_valid_subjname(self.context.code) or \
174
177
not is_valid_subjname(self.worksheetname):
177
180
# Read in worksheet data
178
181
worksheetfilename = os.path.join(ivle.conf.subjects_base,
179
self.subject.code, self.worksheetname + ".xml")
182
self.context.code, self.worksheetname + ".xml")
181
184
worksheetfile = open(worksheetfilename)
182
185
worksheetmtime = os.path.getmtime(worksheetfilename)
186
189
worksheetmtime = datetime.fromtimestamp(worksheetmtime)
187
190
worksheetfile = worksheetfile.read()
189
ctx['subject'] = self.subject.code
192
ctx['subject'] = self.context.code
190
193
ctx['worksheet'] = self.worksheetname
191
194
ctx['worksheetstream'] = genshi.Stream(list(genshi.XML(worksheetfile)))
193
196
#TODO: Replace this with a nice way, possibly a match template
194
197
generate_worksheet_data(ctx, req)
196
update_db_worksheet(req.store, self.subject.code, self.worksheetname,
199
update_db_worksheet(req.store, self.context.code, self.worksheetname,
197
200
worksheetmtime, ctx['exerciselist'])
199
202
ctx['worksheetstream'] = add_exercises(ctx['worksheetstream'], ctx, req)
201
class SubjectMediaView(MediaFileView):
204
class SubjectMediaView(BaseMediaFileView):
202
205
'''The view of subject media files.
204
207
URIs pointing here will just be served directly, from the subject's
208
212
def __init__(self, req, subject, path):
209
self.subject = req.store.find(Subject, code=subject).one()
213
self.context = req.store.find(Subject, code=subject).one()
210
214
self.path = os.path.normpath(path)
212
216
def _make_filename(self, req):
213
217
# If the subject doesn't exist, self.subject will be None. Die.
217
221
subjectdir = os.path.join(ivle.conf.subjects_base,
218
self.subject.code, 'media')
222
self.context.code, 'media')
219
223
return os.path.join(subjectdir, self.path)
221
225
def is_valid_subjname(subject):