module_render.py 5.06 KB
Newer Older
1
import logging
2

3 4 5
from lxml import etree

from django.http import Http404
6 7
from django.http import HttpResponse
from django.shortcuts import redirect
8
from django.template import Context
9
from django.template import Context, loader
Lyla Fischer committed
10 11 12

from fs.osfs import OSFS

13
from django.conf import settings
Calen Pennington committed
14
from mitxmako.shortcuts import render_to_string
15

Lyla Fischer committed
16

17
from models import StudentModule
18

19
import courseware.modules
20 21 22

log = logging.getLogger("mitx.courseware")

Lyla Fischer committed
23 24 25 26
class I4xSystem(object):
    def __init__(self, ajax_url, track_function, render_function, filestore=None):
        self.ajax_url = ajax_url
        self.track_function = track_function
27 28
        if not filestore: 
            self.filestore = OSFS(settings.DATA_DIR)
Lyla Fischer committed
29 30 31
        self.render_function = render_function
        self.exception404 = Http404

32 33 34 35 36 37 38 39 40 41
def object_cache(cache, user, module_type, module_id):
    # We don't look up on user -- all queries include user
    # Additional lookup would require a DB hit the way Django 
    # is broken. 
    for o in cache: 
        if o.module_type == module_type and \
                o.module_id == module_id:
            return o
    return None

42
def make_track_function(request):
Piotr Mitros committed
43 44 45 46 47 48
    ''' We want the capa problem (and other modules) to be able to
    track/log what happens inside them without adding dependencies on
    Django or the rest of the codebase. We do this by passing a
    tracking function to them. This generates a closure for each request 
    that gives a clean interface on both sides. 
    '''
49 50
    import track.views

51 52 53
    def f(event_type, event):
        return track.views.server_track(request, event_type, event, page='x_module')
    return f
Piotr Mitros committed
54
def grade_histogram(module_id):
Piotr Mitros committed
55 56 57
    ''' Print out a histogram of grades on a given problem. 
        Part of staff member debug info. 
    '''
58
    from django.db import connection
Piotr Mitros committed
59 60 61 62 63 64
    cursor = connection.cursor()

    cursor.execute("select courseware_studentmodule.grade,COUNT(courseware_studentmodule.student_id) from courseware_studentmodule where courseware_studentmodule.module_id=%s group by courseware_studentmodule.grade", [module_id])

    grades = list(cursor.fetchall())
    grades.sort(key=lambda x:x[0]) # Probably not necessary
65 66
    if (len(grades) == 1 and grades[0][0] == None):
        return []
Piotr Mitros committed
67 68
    return grades

69
def render_x_module(user, request, xml_module, module_object_preload):
70 71
    ''' Generic module for extensions. This renders to HTML. '''
    # Check if problem has an instance in DB
72
    module_type=xml_module.tag
73
    module_class=courseware.modules.get_module_class(module_type)
74
    module_id=xml_module.get('id') #module_class.id_attribute) or "" 
75 76

    # Grab state from database
77 78 79 80
    smod = object_cache(module_object_preload, 
                        user, 
                        module_type, 
                        module_id)
81

82
    if not smod: # If nothing in the database...
83 84 85 86 87
        state=None
    else:
        state = smod.state

    # Create a new instance
88
    ajax_url = settings.MITX_ROOT_URL + '/modx/'+module_type+'/'+module_id+'/'
Lyla Fischer committed
89 90 91 92 93 94 95
    system = I4xSystem(track_function = make_track_function(request), 
                       render_function = lambda x: render_module(user, request, x, module_object_preload), 
                       ajax_url = ajax_url,
                       filestore = None
                       )
    instance=module_class(system, 
                          etree.tostring(xml_module), 
96
                          module_id, 
Lyla Fischer committed
97
                          state=state)
98
    
99 100 101
    # If instance wasn't already in the database, and this
    # isn't a guest user, create it
    if not smod and user.is_authenticated():
102
        smod=StudentModule(student=user, 
103 104
                           module_type = module_type,
                           module_id=module_id, 
105
                           state=instance.get_state())
106
        smod.save()
107
        module_object_preload.append(smod)
108
    # Grab content
Piotr Mitros committed
109
    content = instance.get_html()
110 111
    init_js = instance.get_init_js()
    destory_js = instance.get_destroy_js()
112 113

    # special extra information about each problem, only for users who are staff 
Piotr Mitros committed
114
    if user.is_staff:
115 116
        histogram = grade_histogram(module_id)
        render_histogram = len(histogram) > 0
Piotr Mitros committed
117
        content=content+render_to_string("staff_problem_info.html", {'xml':etree.tostring(xml_module), 
118 119 120 121 122
                                                                     'module_id' : module_id,
                                                                     'render_histogram' : render_histogram})
        if render_histogram:
            init_js = init_js+render_to_string("staff_problem_histogram.js", {'histogram' : histogram,
                                                                              'module_id' : module_id})
123
        
Piotr Mitros committed
124
    content = {'content':content, 
125 126
               "destroy_js":destory_js,
               'init_js':init_js, 
127
               'type':module_type}
128 129 130

    return content

131
def render_module(user, request, module, module_object_preload):
132
    ''' Generic dispatch for internal modules. '''
133
    if module==None :
134
        return {"content":""}
135
    return render_x_module(user, request, module, module_object_preload)