35
35
import ivle.database
36
36
from ivle.database import Subject, Offering, Semester, Exercise, \
37
ExerciseSave, WorksheetExercise
37
ExerciseSave, WorksheetExercise, ExerciseAttempt
38
38
from ivle.database import Worksheet as DBWorksheet
39
39
import ivle.worksheet.utils
40
from ivle.webapp import ApplicationRoot
40
41
from ivle.webapp.base.views import BaseView
41
42
from ivle.webapp.base.xhtml import XHTMLView
42
43
from ivle.webapp.base.plugins import ViewPlugin, MediaPlugin
43
from ivle.webapp.media import BaseMediaFileView, media_url
44
from ivle.webapp.errors import NotFound, Forbidden
44
from ivle.webapp.media import media_url
45
from ivle.webapp.errors import NotFound
45
46
from ivle.worksheet.rst import rst as rstfunc
46
from ivle.webapp.tutorial.service import AttemptsRESTView, AttemptRESTView, \
47
WorksheetExerciseRESTView, WorksheetRESTView, WorksheetsRESTView
48
from ivle.webapp.tutorial.service import (AttemptsRESTView, AttemptRESTView,
49
WorksheetExerciseRESTView, WorksheetRESTView, WorksheetsRESTView)
49
50
from ivle.webapp.tutorial.exercise_service import ExercisesRESTView, \
52
from ivle.webapp.tutorial.publishing import (root_to_exercise, exercise_url,
53
offering_to_worksheet, worksheet_url,
54
worksheet_to_worksheetexercise, worksheetexercise_url,
55
ExerciseAttempts, worksheetexercise_to_exerciseattempts,
56
exerciseattempts_url, exerciseattempts_to_attempt,
58
from ivle.webapp.tutorial.breadcrumbs import (ExerciseBreadcrumb,
60
from ivle.webapp.tutorial.media import (SubjectMediaFile, SubjectMediaView,
53
64
"""This class represents a worksheet and a particular students progress
147
146
permission = 'view'
149
def __init__(self, req, subject, year, semester, worksheet):
150
self.context = req.store.find(DBWorksheet,
151
DBWorksheet.offering_id == Offering.id,
152
Offering.subject_id == Subject.id,
153
Subject.short_name == subject,
154
Offering.semester_id == Semester.id,
155
Semester.year == year,
156
Semester.semester == semester,
157
DBWorksheet.identifier == worksheet).one()
159
if self.context is None:
160
raise NotFound(str(worksheet) + " was not found.")
163
self.semester = semester
165
148
def populate(self, req, ctx):
166
149
self.plugin_scripts[Plugin] = ['tutorial.js']
167
150
self.plugin_styles[Plugin] = ['tutorial.css', 'worksheet.css']
182
165
ctx['worksheetstream'] = add_exercises(ctx['worksheetstream'], ctx, req)
184
class SubjectMediaView(BaseMediaFileView):
185
'''The view of subject media files.
187
URIs pointing here will just be served directly, from the subject's
192
def __init__(self, req, subject, path):
193
self.context = req.store.find(Subject, short_name=subject).one()
194
self.path = os.path.normpath(path)
196
def _make_filename(self, req):
197
# If the subject doesn't exist, self.subject will be None. Die.
201
subjectdir = os.path.join(req.config['paths']['data'],
203
self.context.short_name, 'media')
204
return os.path.join(subjectdir, self.path)
206
167
def get_worksheets(subjectfile):
207
168
'''Given a subject stream, get all the worksheets and put them in ctx'''
385
346
template = "templates/worksheet_edit.html"
388
def __init__(self, req, **kwargs):
390
subject = kwargs['subject']
391
year = kwargs['year']
392
semester = kwargs['semester']
393
worksheet = kwargs['worksheet']
394
self.context = req.store.find(DBWorksheet,
395
DBWorksheet.identifier == worksheet,
396
DBWorksheet.offering_id == Offering.id,
397
Offering.semester_id == Semester.id,
398
Semester.year == year,
399
Semester.semester == semester,
400
Offering.subject_id == Subject.id,
401
Subject.short_name == subject
404
if self.context is None:
407
self.subject = subject
409
self.semester = semester
410
self.worksheet = worksheet
413
349
def populate(self, req, ctx):
414
350
self.plugin_styles[Plugin] = ["tutorial_admin.css"]
415
351
self.plugin_scripts[Plugin] = ['tutorial_admin.js']
417
353
ctx['worksheet'] = self.context
418
ctx['worksheetname'] = self.worksheet
354
ctx['worksheetname'] = self.context.identifier
419
355
ctx['subject'] = self.context.offering.subject
420
ctx['year'] = self.year
421
ctx['semester'] = self.semester
356
ctx['year'] = self.context.offering.semester.year
357
ctx['semester'] = self.context.offering.semester.semester
422
358
#XXX: Get the list of formats from somewhere else
423
359
ctx['formats'] = ['xml', 'rst']
428
364
permission = "edit"
429
365
template = "templates/worksheet_add.html"
431
def __init__(self, req, subject, year, semester):
432
self.context = req.store.find(Offering,
433
Offering.semester_id == Semester.id,
434
Semester.year == year,
435
Semester.semester == semester,
436
Offering.subject_id == Subject.id,
437
Subject.short_name == subject
440
self.subject = subject
442
self.semester = semester
444
if self.context is None:
447
367
def populate(self, req, ctx):
448
368
self.plugin_styles[Plugin] = ["tutorial_admin.css"]
449
369
self.plugin_scripts[Plugin] = ['tutorial_admin.js']
451
371
ctx['subject'] = self.context.subject
452
ctx['year'] = self.year
453
ctx['semester'] = self.semester
372
ctx['year'] = self.context.semester.year
373
ctx['semester'] = self.context.semester.semester
455
375
#XXX: Get the list of formats from somewhere else
456
376
ctx['formats'] = ['xml', 'rst']
461
381
permission = 'edit'
462
382
template = 'templates/worksheets_edit.html'
464
def __init__(self, req, subject, year, semester):
465
self.context = req.store.find(Offering,
466
Offering.semester_id == Semester.id,
467
Semester.year == year,
468
Semester.semester == semester,
469
Offering.subject_id == Subject.id,
470
Subject.short_name == subject
473
self.subject = subject
475
self.semester = semester
477
if self.context is None:
480
384
def populate(self, req, ctx):
481
385
self.plugin_styles[Plugin] = ['tutorial_admin.css']
482
386
self.plugin_scripts[Plugin] = ['tutorial_admin.js']
484
388
ctx['subject'] = self.context.subject
485
ctx['year'] = self.year
486
ctx['semester'] = self.semester
389
ctx['year'] = self.context.semester.year
390
ctx['semester'] = self.context.semester.semester
488
392
ctx['worksheets'] = self.context.worksheets
587
477
ctx['exercises'] = req.store.find(Exercise).order_by(Exercise.id)
588
478
ctx['mediapath'] = media_url(req, Plugin, 'images/')
590
481
class Plugin(ViewPlugin, MediaPlugin):
592
# Worksheet View Urls
593
('subjects/:subject/+worksheets/+media/*(path)', SubjectMediaView),
594
('subjects/:subject/:year/:semester/+worksheets', OfferingView),
595
('subjects/:subject/:year/:semester/+worksheets/+new', WorksheetAddView),
596
('subjects/:subject/:year/:semester/+worksheets/+edit', WorksheetsEditView),
597
('subjects/:subject/:year/:semester/+worksheets/:worksheet', WorksheetView),
598
('subjects/:subject/:year/:semester/+worksheets/:worksheet/+edit', WorksheetEditView),
601
('api/subjects/:subject/:year/:semester/+worksheets', WorksheetsRESTView),
602
('api/subjects/:subject/:year/:semester/+worksheets/:worksheet/*exercise/'
603
'+attempts/:username', AttemptsRESTView),
604
('api/subjects/:subject/:year/:semester/+worksheets/:worksheet/*exercise/'
605
'+attempts/:username/:date', AttemptRESTView),
606
('api/subjects/:subject/:year/:semester/+worksheets/:worksheet', WorksheetRESTView),
607
('api/subjects/:subject/:year/:semester/+worksheets/:worksheet/*exercise', WorksheetExerciseRESTView),
610
('+exercises', ExercisesView),
611
('+exercises/+add', ExerciseAddView),
612
('+exercises/:exercise/+edit', ExerciseEditView),
613
('+exercises/:exercise/+delete', ExerciseDeleteView),
616
('api/+exercises', ExercisesRESTView),
617
('api/+exercises/*exercise', ExerciseRESTView),
482
forward_routes = (root_to_exercise, offering_to_worksheet,
483
worksheet_to_worksheetexercise, worksheetexercise_to_exerciseattempts,
484
exerciseattempts_to_attempt, subject_to_media)
486
reverse_routes = (exercise_url, worksheet_url, worksheetexercise_url,
487
exerciseattempts_url, exerciseattempt_url)
489
breadcrumbs = {Exercise: ExerciseBreadcrumb,
490
DBWorksheet: WorksheetBreadcrumb
493
views = [(Offering, ('+worksheets', '+index'), OfferingView),
494
(Offering, ('+worksheets', '+new'), WorksheetAddView),
495
(Offering, ('+worksheets', '+edit'), WorksheetsEditView),
496
(DBWorksheet, '+index', WorksheetView),
497
(DBWorksheet, '+edit', WorksheetEditView),
498
(ApplicationRoot, ('+exercises', '+index'), ExercisesView),
499
(ApplicationRoot, ('+exercises', '+add'), ExerciseAddView),
500
(Exercise, '+edit', ExerciseEditView),
501
(Exercise, '+delete', ExerciseDeleteView),
502
(SubjectMediaFile, '+index', SubjectMediaView),
504
(Offering, ('+worksheets', '+index'), WorksheetsRESTView, 'api'),
505
(DBWorksheet, '+index', WorksheetRESTView, 'api'),
506
(WorksheetExercise, '+index', WorksheetExerciseRESTView, 'api'),
507
(ExerciseAttempts, '+index', AttemptsRESTView, 'api'),
508
(ExerciseAttempt, '+index', AttemptRESTView, 'api'),
509
(ApplicationRoot, ('+exercises', '+index'), ExercisesRESTView,
511
(Exercise, '+index', ExerciseRESTView, 'api'),
621
515
help = {'Tutorial': 'help.html'}