Merge with default branch
--HG-- branch : profiledev
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import uuid
|
||||
|
||||
from django.db import models
|
||||
from django.contrib.auth.models import User
|
||||
import uuid
|
||||
|
||||
class UserProfile(models.Model):
|
||||
## CRITICAL TODO/SECURITY
|
||||
|
||||
@@ -1,16 +1,21 @@
|
||||
from djangomako.shortcuts import render_to_response, render_to_string
|
||||
from django.contrib.auth.models import User
|
||||
from django.shortcuts import redirect
|
||||
import json
|
||||
import logging
|
||||
import random
|
||||
import string
|
||||
|
||||
from django.conf import settings
|
||||
from django.contrib.auth import logout, authenticate, login
|
||||
from django.contrib.auth.models import User
|
||||
from django.http import HttpResponse
|
||||
import json
|
||||
from models import Registration, UserProfile
|
||||
from django.conf import settings
|
||||
from django.contrib.auth.models import User
|
||||
from django.core.context_processors import csrf
|
||||
from django.core.validators import validate_email, validate_slug
|
||||
import random, string
|
||||
from django.db import connection
|
||||
from django.http import HttpResponse
|
||||
from django.shortcuts import redirect
|
||||
from mitxmako.shortcuts import render_to_response, render_to_string
|
||||
from models import Registration, UserProfile
|
||||
|
||||
log = logging.getLogger("mitx.auth")
|
||||
|
||||
def csrf_token(context):
|
||||
csrf_token = context.get('csrf_token', '')
|
||||
@@ -37,37 +42,43 @@ def index(request):
|
||||
# return render_to_response('courseinfo.html', {'error' : '',
|
||||
# 'csrf': csrf_token })
|
||||
|
||||
# Need different levels of logging
|
||||
def login_user(request, error=""):
|
||||
# print request.POST
|
||||
if 'email' not in request.POST or 'password' not in request.POST:
|
||||
# print "X"
|
||||
return render_to_response('login.html', {'error':error.replace('+',' ')})
|
||||
|
||||
email = request.POST['email']
|
||||
password = request.POST['password']
|
||||
try:
|
||||
user=User.objects.get(email=email)
|
||||
user = User.objects.get(email=email)
|
||||
except User.DoesNotExist:
|
||||
log.warning("Login failed - Unknown user email: {0}".format(email))
|
||||
return HttpResponse(json.dumps({'success':False,
|
||||
'error': 'Invalid login'})) # TODO: User error message
|
||||
|
||||
username=user.username
|
||||
user=authenticate(username=username, password=password)
|
||||
username = user.username
|
||||
user = authenticate(username=username, password=password)
|
||||
if user is None:
|
||||
log.warning("Login failed - password for {0} is invalid".format(email))
|
||||
return HttpResponse(json.dumps({'success':False,
|
||||
'error': 'Invalid login'}))
|
||||
|
||||
if user is not None and user.is_active:
|
||||
login(request, user)
|
||||
if request.POST['remember'] == 'true':
|
||||
request.session.set_expiry(None) # or change to 604800 for 7 days
|
||||
# print "recall"
|
||||
else:
|
||||
request.session.set_expiry(0)
|
||||
#print "close"
|
||||
# print len(connection.queries), connection.queries
|
||||
try:
|
||||
login(request, user)
|
||||
if request.POST['remember'] == 'true':
|
||||
request.session.set_expiry(None) # or change to 604800 for 7 days
|
||||
log.debug("Setting user session to never expire")
|
||||
else:
|
||||
request.session.set_expiry(0)
|
||||
except Exception as e:
|
||||
log.critical("Login failed - Could not create session. Is memcached running?")
|
||||
log.exception(e)
|
||||
|
||||
log.info("Login success - {0} ({1})".format(username, email))
|
||||
return HttpResponse(json.dumps({'success':True}))
|
||||
|
||||
# print len(connection.queries), connection.queries
|
||||
|
||||
log.warning("Login failed - Account not active for user {0}".format(username))
|
||||
return HttpResponse(json.dumps({'success':False,
|
||||
'error': 'Account not active. Check your e-mail.'}))
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import uuid
|
||||
|
||||
from django.db import models
|
||||
from django.contrib.auth.models import User
|
||||
import uuid
|
||||
|
||||
class ServerCircuit(models.Model):
|
||||
# Later, add owner, who can edit, part of what app, etc.
|
||||
|
||||
@@ -1,24 +1,26 @@
|
||||
from djangomako.shortcuts import render_to_response, render_to_string
|
||||
from django.shortcuts import redirect
|
||||
import json
|
||||
import os
|
||||
|
||||
import xml.etree.ElementTree
|
||||
|
||||
from django.conf import settings
|
||||
from django.http import Http404
|
||||
from models import ServerCircuit
|
||||
import json
|
||||
import xml.etree.ElementTree
|
||||
from django.http import HttpResponse
|
||||
from django.shortcuts import redirect
|
||||
from mitxmako.shortcuts import render_to_response, render_to_string
|
||||
|
||||
from models import ServerCircuit
|
||||
|
||||
def circuit_line(circuit):
|
||||
''' Returns string for an appropriate input element for a circuit.
|
||||
TODO: Rename. '''
|
||||
if not circuit.isalnum():
|
||||
raise Http404()
|
||||
try:
|
||||
sc = ServerCircuit.objects.get(name=circuit)
|
||||
schematic = sc.schematic
|
||||
print "Got"
|
||||
except:
|
||||
schematic = ''
|
||||
print "not got"
|
||||
print "X", schematic
|
||||
|
||||
circuit_line = xml.etree.ElementTree.Element('input')
|
||||
circuit_line.set('type', 'hidden')
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import math
|
||||
import operator
|
||||
|
||||
from pyparsing import Word, alphas, nums, oneOf, Literal
|
||||
from pyparsing import ZeroOrMore, OneOrMore, StringStart
|
||||
from pyparsing import StringEnd, Optional, Forward
|
||||
|
||||
@@ -1,18 +1,24 @@
|
||||
import random, numpy, math, scipy
|
||||
import struct, os
|
||||
import copy
|
||||
import math
|
||||
import numpy
|
||||
import os
|
||||
import random
|
||||
import re
|
||||
import scipy
|
||||
import struct
|
||||
|
||||
from lxml import etree
|
||||
from lxml.etree import Element
|
||||
import copy
|
||||
|
||||
from mako.template import Template
|
||||
from courseware.content_parser import xpath_remove
|
||||
import calc, eia
|
||||
|
||||
from util import contextualize_text
|
||||
|
||||
from inputtypes import textline, schematic
|
||||
from responsetypes import numericalresponse, formularesponse, customresponse, schematicresponse
|
||||
|
||||
import calc
|
||||
import eia
|
||||
|
||||
response_types = {'numericalresponse':numericalresponse,
|
||||
'formularesponse':formularesponse,
|
||||
'customresponse':customresponse,
|
||||
@@ -52,12 +58,14 @@ class LoncapaProblem(object):
|
||||
self.done = False
|
||||
self.filename = filename
|
||||
|
||||
if id!=None:
|
||||
if id:
|
||||
self.problem_id = id
|
||||
else:
|
||||
self.problem_id = filename
|
||||
print "NO ID"
|
||||
raise Exception("This should never happen (183)")
|
||||
#self.problem_id = filename
|
||||
|
||||
if state!=None:
|
||||
if state:
|
||||
if 'seed' in state:
|
||||
self.seed = state['seed']
|
||||
if 'student_answers' in state:
|
||||
@@ -68,7 +76,7 @@ class LoncapaProblem(object):
|
||||
self.done = state['done']
|
||||
|
||||
# TODO: Does this deplete the Linux entropy pool? Is this fast enough?
|
||||
if self.seed == None:
|
||||
if not self.seed:
|
||||
self.seed=struct.unpack('i', os.urandom(4))[0]
|
||||
|
||||
## Parse XML file
|
||||
@@ -102,7 +110,7 @@ class LoncapaProblem(object):
|
||||
for key in self.correct_map:
|
||||
if self.correct_map[key] == u'correct':
|
||||
correct += 1
|
||||
if self.student_answers == None or len(self.student_answers)==0:
|
||||
if (not self.student_answers) or len(self.student_answers)==0:
|
||||
return {'score':0,
|
||||
'total':self.get_max_score()}
|
||||
else:
|
||||
@@ -132,8 +140,8 @@ class LoncapaProblem(object):
|
||||
|
||||
for entry in problems_simple.xpath("//"+"|//".join(response_properties+entry_types)):
|
||||
answer = entry.get('correct_answer')
|
||||
if answer != None:
|
||||
answer_map[entry.get('id')] = contextualize_text(answer, self.context())
|
||||
if answer:
|
||||
answer_map[entry.get('id')] = contextualize_text(answer, self.context)
|
||||
|
||||
return answer_map
|
||||
|
||||
@@ -162,7 +170,7 @@ class LoncapaProblem(object):
|
||||
status = self.correct_map[problemtree.get('id')]
|
||||
|
||||
value = ""
|
||||
if self.student_answers != None and problemtree.get('id') in self.student_answers:
|
||||
if self.student_answers and problemtree.get('id') in self.student_answers:
|
||||
value = self.student_answers[problemtree.get('id')]
|
||||
|
||||
return html_special_response[problemtree.tag](problemtree, value, status) #TODO
|
||||
@@ -170,7 +178,7 @@ class LoncapaProblem(object):
|
||||
tree=Element(problemtree.tag)
|
||||
for item in problemtree:
|
||||
subitems = self.extract_html(item)
|
||||
if subitems != None:
|
||||
if subitems:
|
||||
for subitem in subitems:
|
||||
tree.append(subitem)
|
||||
for (key,value) in problemtree.items():
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
from djangomako.shortcuts import render_to_response, render_to_string
|
||||
|
||||
from lxml.etree import Element
|
||||
from lxml import etree
|
||||
|
||||
from mitxmako.shortcuts import render_to_response, render_to_string
|
||||
|
||||
class textline(object):
|
||||
@staticmethod
|
||||
def render(element, value, state):
|
||||
|
||||
@@ -1,14 +1,23 @@
|
||||
import random, numpy, math, scipy, json
|
||||
from util import contextualize_text
|
||||
import json
|
||||
import math
|
||||
import numpy
|
||||
import random
|
||||
import scipy
|
||||
|
||||
from calc import evaluator
|
||||
import random, math
|
||||
from django.conf import settings
|
||||
from util import contextualize_text
|
||||
|
||||
import calc
|
||||
import eia
|
||||
|
||||
# TODO: Should be the same object as in capa_problem
|
||||
global_context={'random':random,
|
||||
'numpy':numpy,
|
||||
'math':math,
|
||||
'scipy':scipy}
|
||||
'scipy':scipy,
|
||||
'calc':calc,
|
||||
'eia':eia}
|
||||
|
||||
class numericalresponse(object):
|
||||
def __init__(self, xml, context):
|
||||
|
||||
132
courseware/capa/unit.py
Normal file
132
courseware/capa/unit.py
Normal file
@@ -0,0 +1,132 @@
|
||||
import math
|
||||
import operator
|
||||
|
||||
from numpy import eye, array
|
||||
|
||||
from pyparsing import Word, alphas, nums, oneOf, Literal
|
||||
from pyparsing import ZeroOrMore, OneOrMore, StringStart
|
||||
from pyparsing import StringEnd, Optional, Forward
|
||||
from pyparsing import CaselessLiteral, Group, StringEnd
|
||||
from pyparsing import NoMatch, stringEnd
|
||||
|
||||
base_units = ['meter', 'gram', 'second', 'ampere', 'kelvin', 'mole', 'cd']
|
||||
unit_vectors = dict([(base_units[i], eye(len(base_units))[:,i]) for i in range(len(base_units))])
|
||||
|
||||
|
||||
def unit_evaluator(unit_string, units=unit_map):
|
||||
''' Evaluate an expression. Variables are passed as a dictionary
|
||||
from string to value. Unary functions are passed as a dictionary
|
||||
from string to function '''
|
||||
if string.strip() == "":
|
||||
return float('nan')
|
||||
ops = { "^" : operator.pow,
|
||||
"*" : operator.mul,
|
||||
"/" : operator.truediv,
|
||||
}
|
||||
prefixes={'%':0.01,'k':1e3,'M':1e6,'G':1e9,
|
||||
'T':1e12,#'P':1e15,'E':1e18,'Z':1e21,'Y':1e24,
|
||||
'c':1e-2,'m':1e-3,'u':1e-6,
|
||||
'n':1e-9,'p':1e-12}#,'f':1e-15,'a':1e-18,'z':1e-21,'y':1e-24}
|
||||
|
||||
def super_float(text):
|
||||
''' Like float, but with si extensions. 1k goes to 1000'''
|
||||
if text[-1] in suffixes:
|
||||
return float(text[:-1])*suffixes[text[-1]]
|
||||
else:
|
||||
return float(text)
|
||||
|
||||
def number_parse_action(x): # [ '7' ] -> [ 7 ]
|
||||
return [super_float("".join(x))]
|
||||
def exp_parse_action(x): # [ 2 ^ 3 ^ 2 ] -> 512
|
||||
x = [e for e in x if type(e) == float] # Ignore ^
|
||||
x.reverse()
|
||||
x=reduce(lambda a,b:b**a, x)
|
||||
return x
|
||||
def parallel(x): # Parallel resistors [ 1 2 ] => 2/3
|
||||
if len(x) == 1:
|
||||
return x[0]
|
||||
if 0 in x:
|
||||
return float('nan')
|
||||
x = [1./e for e in x if type(e) == float] # Ignore ^
|
||||
return 1./sum(x)
|
||||
def sum_parse_action(x): # [ 1 + 2 - 3 ] -> 0
|
||||
total = 0.0
|
||||
op = ops['+']
|
||||
for e in x:
|
||||
if e in set('+-'):
|
||||
op = ops[e]
|
||||
else:
|
||||
total=op(total, e)
|
||||
return total
|
||||
def prod_parse_action(x): # [ 1 * 2 / 3 ] => 0.66
|
||||
prod = 1.0
|
||||
op = ops['*']
|
||||
for e in x:
|
||||
if e in set('*/'):
|
||||
op = ops[e]
|
||||
else:
|
||||
prod=op(prod, e)
|
||||
return prod
|
||||
def func_parse_action(x):
|
||||
return [functions[x[0]](x[1])]
|
||||
|
||||
number_suffix=reduce(lambda a,b:a|b, map(Literal,suffixes.keys()), NoMatch()) # SI suffixes and percent
|
||||
(dot,minus,plus,times,div,lpar,rpar,exp)=map(Literal,".-+*/()^")
|
||||
|
||||
number_part=Word(nums)
|
||||
inner_number = ( number_part+Optional("."+number_part) ) | ("."+number_part) # 0.33 or 7 or .34
|
||||
number=Optional(minus | plus)+ inner_number + \
|
||||
Optional(CaselessLiteral("E")+Optional("-")+number_part)+ \
|
||||
Optional(number_suffix) # 0.33k or -17
|
||||
number=number.setParseAction( number_parse_action ) # Convert to number
|
||||
|
||||
# Predefine recursive variables
|
||||
expr = Forward()
|
||||
factor = Forward()
|
||||
|
||||
def sreduce(f, l):
|
||||
''' Same as reduce, but handle len 1 and len 0 lists sensibly '''
|
||||
if len(l)==0:
|
||||
return NoMatch()
|
||||
if len(l)==1:
|
||||
return l[0]
|
||||
return reduce(f, l)
|
||||
|
||||
# Handle variables passed in. E.g. if we have {'R':0.5}, we make the substitution.
|
||||
# Special case for no variables because of how we understand PyParsing is put together
|
||||
if len(variables)>0:
|
||||
varnames = sreduce(lambda x,y:x|y, map(lambda x: CaselessLiteral(x), variables.keys()))
|
||||
varnames.setParseAction(lambda x:map(lambda y:variables[y], x))
|
||||
else:
|
||||
varnames=NoMatch()
|
||||
# Same thing for functions.
|
||||
if len(functions)>0:
|
||||
funcnames = sreduce(lambda x,y:x|y, map(lambda x: CaselessLiteral(x), functions.keys()))
|
||||
function = funcnames+lpar.suppress()+expr+rpar.suppress()
|
||||
function.setParseAction(func_parse_action)
|
||||
else:
|
||||
function = NoMatch()
|
||||
|
||||
atom = number | varnames | lpar+expr+rpar | function
|
||||
factor << (atom + ZeroOrMore(exp+atom)).setParseAction(exp_parse_action) # 7^6
|
||||
paritem = factor + ZeroOrMore(Literal('||')+factor) # 5k || 4k
|
||||
paritem=paritem.setParseAction(parallel)
|
||||
term = paritem + ZeroOrMore((times|div)+paritem) # 7 * 5 / 4 - 3
|
||||
term = term.setParseAction(prod_parse_action)
|
||||
expr << Optional((plus|minus)) + term + ZeroOrMore((plus|minus)+term) # -5 + 4 - 3
|
||||
expr=expr.setParseAction(sum_parse_action)
|
||||
return (expr+stringEnd).parseString(string)[0]
|
||||
|
||||
if __name__=='__main__':
|
||||
variables={'R1':2.0, 'R3':4.0}
|
||||
functions={'sin':math.sin, 'cos':math.cos}
|
||||
print "X",evaluator(variables, functions, "10000||sin(7+5)-6k")
|
||||
print "X",evaluator(variables, functions, "13")
|
||||
print evaluator({'R1': 2.0, 'R3':4.0}, {}, "13")
|
||||
#
|
||||
print evaluator({'a': 2.2997471478310274, 'k': 9, 'm': 8, 'x': 0.66009498411213041}, {}, "5")
|
||||
print evaluator({},{}, "-1")
|
||||
print evaluator({},{}, "-(7+5)")
|
||||
print evaluator({},{}, "-0.33")
|
||||
print evaluator({},{}, "-.33")
|
||||
print evaluator({},{}, "5+7 QWSEKO")
|
||||
@@ -1,15 +1,15 @@
|
||||
try:
|
||||
import json
|
||||
import hashlib
|
||||
import logging
|
||||
|
||||
from lxml import etree
|
||||
|
||||
try: # This lets us do __name__ == ='__main__'
|
||||
from django.conf import settings
|
||||
from auth.models import UserProfile
|
||||
except:
|
||||
settings = None
|
||||
|
||||
from lxml import etree
|
||||
|
||||
import json
|
||||
import hashlib
|
||||
import logging
|
||||
|
||||
''' This file will eventually form an abstraction layer between the
|
||||
course XML file and the rest of the system.
|
||||
|
||||
|
||||
@@ -1,43 +1,6 @@
|
||||
from django.db import models
|
||||
from django.contrib.auth.models import User
|
||||
|
||||
# class Organization(models.Model):
|
||||
# # Tree structure implemented such that child node has left ID
|
||||
# # greater than all parents, and right ID less than all parents
|
||||
# left_tree_id = models.IntegerField(unique=True, db_index=True)
|
||||
# right_tree_id = models.IntegerField(unique=True, db_index=True)
|
||||
# # This is a duplicate, but we keep this to enforce unique name
|
||||
# # constraint
|
||||
# parent = models.ForeignKey('self', null=True, blank=True)
|
||||
# name = models.CharField(max_length=200)
|
||||
# ORG_TYPES= (('course','course'),
|
||||
# ('chapter','chapter'),
|
||||
# ('section','section'),)
|
||||
# org_type = models.CharField(max_length=32, choices=ORG_TYPES)
|
||||
# available = models.DateField(null=True, blank=True)
|
||||
# due = models.DateField(null=True, blank=True)
|
||||
# # JSON dictionary of metadata:
|
||||
# # Time for a video, format of a section, etc.
|
||||
# metadata = models.TextField(null=True, blank=True)
|
||||
|
||||
# class Modules(models.Model):
|
||||
# MOD_TYPES = (('hw','homework'),
|
||||
# ('vid','video_clip'),
|
||||
# ('lay','layout'),
|
||||
# (),)
|
||||
# module_type = models.CharField(max_length=100)
|
||||
# left_tree_id = models.IntegerField(unique=True, db_index=True)
|
||||
# right_tree_id = models.IntegerField(unique=True, db_index=True)
|
||||
|
||||
# LAYOUT_TYPES = (('leaf','leaf'),
|
||||
# ('tab','tab'),
|
||||
# ('seq','sequential'),
|
||||
# ('sim','simultaneous'),)
|
||||
# layout_type = models.CharField(max_length=32, choices=LAYOUT_TYPES)
|
||||
# data = models.TextField(null=True, blank=True)
|
||||
|
||||
#class HomeworkProblems(models.Model):
|
||||
|
||||
class StudentModule(models.Model):
|
||||
# For a homework problem, contains a JSON
|
||||
# object consisting of state
|
||||
|
||||
@@ -1,43 +1,36 @@
|
||||
from django.http import HttpResponse
|
||||
from django.template import Context, loader
|
||||
from djangomako.shortcuts import render_to_response, render_to_string
|
||||
import json, os, sys
|
||||
from django.core.context_processors import csrf
|
||||
|
||||
from django.db import connection
|
||||
from django.template import Context
|
||||
from django.contrib.auth.models import User
|
||||
from auth.models import UserProfile
|
||||
from django.shortcuts import redirect
|
||||
|
||||
import StringIO
|
||||
import track.views
|
||||
|
||||
from django.http import Http404
|
||||
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
import sys
|
||||
import urllib
|
||||
import uuid
|
||||
|
||||
import courseware.modules.capa_module
|
||||
import courseware.modules.video_module
|
||||
import courseware.modules.vertical_module
|
||||
import courseware.modules.html_module
|
||||
import courseware.modules.schematic_module
|
||||
import courseware.modules.seq_module
|
||||
|
||||
from models import StudentModule
|
||||
|
||||
import urllib
|
||||
from lxml import etree
|
||||
|
||||
from django.conf import settings
|
||||
from django.contrib.auth.models import User
|
||||
from django.core.context_processors import csrf
|
||||
from django.db import connection
|
||||
from django.http import Http404
|
||||
from django.http import HttpResponse
|
||||
from django.shortcuts import redirect
|
||||
from django.template import Context
|
||||
from django.template import Context, loader
|
||||
from mitxmako.shortcuts import render_to_response, render_to_string
|
||||
|
||||
from auth.models import UserProfile
|
||||
from models import StudentModule
|
||||
import track.views
|
||||
|
||||
import courseware.content_parser as content_parser
|
||||
|
||||
import sys
|
||||
import logging
|
||||
|
||||
from lxml import etree
|
||||
import uuid
|
||||
|
||||
import courseware.modules.capa_module
|
||||
import courseware.modules.html_module
|
||||
import courseware.modules.schematic_module
|
||||
import courseware.modules.seq_module
|
||||
import courseware.modules.vertical_module
|
||||
import courseware.modules.video_module
|
||||
|
||||
log = logging.getLogger("mitx.courseware")
|
||||
|
||||
@@ -96,7 +89,7 @@ def modx_dispatch(request, module=None, dispatch=None, id=None):
|
||||
ajax_return=instance.handle_ajax(dispatch, request.POST)
|
||||
# Save the state back to the database
|
||||
s.state=instance.get_state()
|
||||
if instance.get_score() != None:
|
||||
if not instance.get_score():
|
||||
s.grade=instance.get_score()['score']
|
||||
s.save()
|
||||
# Return whatever the module wanted to return to the client/caller
|
||||
@@ -110,22 +103,14 @@ def render_x_module(user, request, xml_module, module_object_preload):
|
||||
module_id=xml_module.get('id') #module_class.id_attribute) or ""
|
||||
|
||||
# Grab state from database
|
||||
s = object_cache(module_object_preload,
|
||||
user,
|
||||
module_type,
|
||||
module_id)
|
||||
# s = StudentModule.objects.filter(student=request.user,
|
||||
# module_id=module_id,
|
||||
# module_type = module_type)
|
||||
# if len(s) == 0:
|
||||
# s=None
|
||||
# else:
|
||||
# s=s[0]
|
||||
smod = object_cache(module_object_preload,
|
||||
user,
|
||||
module_type,
|
||||
module_id)
|
||||
|
||||
if s == None: # If nothing in the database...
|
||||
if not smod: # If nothing in the database...
|
||||
state=None
|
||||
else:
|
||||
smod = s
|
||||
state = smod.state
|
||||
|
||||
# Create a new instance
|
||||
@@ -135,10 +120,10 @@ def render_x_module(user, request, xml_module, module_object_preload):
|
||||
ajax_url=ajax_url,
|
||||
state=state,
|
||||
track_function = make_track_function(request),
|
||||
render_function = lambda x: render_module(user, request, x, module_object_preload))
|
||||
render_function = lambda x: render_module(user, request, x, module_object_preload))
|
||||
|
||||
# If instance wasn't already in the database, create it
|
||||
if s == None:
|
||||
if not smod:
|
||||
smod=StudentModule(student=user,
|
||||
module_type = module_type,
|
||||
module_id=module_id,
|
||||
|
||||
@@ -1,21 +1,27 @@
|
||||
import random, numpy, math, scipy, sys, StringIO, os, struct, json
|
||||
from x_module import XModule
|
||||
import sys
|
||||
|
||||
from courseware.capa.capa_problem import LoncapaProblem
|
||||
from django.http import Http404
|
||||
|
||||
import StringIO
|
||||
import datetime
|
||||
import dateutil
|
||||
import dateutil.parser
|
||||
import datetime
|
||||
|
||||
import courseware.content_parser as content_parser
|
||||
import json
|
||||
import math
|
||||
import numpy
|
||||
import os
|
||||
import random
|
||||
import scipy
|
||||
import struct
|
||||
import sys
|
||||
import traceback
|
||||
|
||||
from lxml import etree
|
||||
|
||||
## TODO: Abstract out from Django
|
||||
from django.conf import settings
|
||||
from djangomako.shortcuts import render_to_response, render_to_string
|
||||
from mitxmako.shortcuts import render_to_response, render_to_string
|
||||
from django.http import Http404
|
||||
|
||||
from x_module import XModule
|
||||
from courseware.capa.capa_problem import LoncapaProblem
|
||||
import courseware.content_parser as content_parser
|
||||
|
||||
class LoncapaModule(XModule):
|
||||
''' Interface between capa_problem and x_module. Originally a hack
|
||||
@@ -231,6 +237,8 @@ class LoncapaModule(XModule):
|
||||
for key in get:
|
||||
answers['_'.join(key.split('_')[1:])]=get[key]
|
||||
|
||||
print "XXX", answers, get
|
||||
|
||||
event_info['answers']=answers
|
||||
|
||||
# Too late. Cannot submit
|
||||
@@ -255,6 +263,7 @@ class LoncapaModule(XModule):
|
||||
correct_map = self.lcp.grade_answers(answers)
|
||||
except:
|
||||
self.lcp = LoncapaProblem(filename, id=lcp_id, state=old_state)
|
||||
traceback.print_exc()
|
||||
print {'error':sys.exc_info(),
|
||||
'answers':answers,
|
||||
'seed':self.lcp.seed,
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
from x_module import XModule
|
||||
from lxml import etree
|
||||
|
||||
import json
|
||||
|
||||
## TODO: Abstract out from Django
|
||||
from django.conf import settings
|
||||
from djangomako.shortcuts import render_to_response, render_to_string
|
||||
from mitxmako.shortcuts import render_to_response, render_to_string
|
||||
|
||||
from x_module import XModule
|
||||
from lxml import etree
|
||||
|
||||
class HtmlModule(XModule):
|
||||
id_attribute = 'filename'
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
from x_module import XModule
|
||||
|
||||
import json
|
||||
|
||||
## TODO: Abstract out from Django
|
||||
from django.conf import settings
|
||||
from djangomako.shortcuts import render_to_response, render_to_string
|
||||
from mitxmako.shortcuts import render_to_response, render_to_string
|
||||
|
||||
from x_module import XModule
|
||||
|
||||
class SchematicModule(XModule):
|
||||
id_attribute = 'id'
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
from x_module import XModule
|
||||
from lxml import etree
|
||||
from django.http import Http404
|
||||
|
||||
import json
|
||||
|
||||
from lxml import etree
|
||||
|
||||
## TODO: Abstract out from Django
|
||||
from django.http import Http404
|
||||
from django.conf import settings
|
||||
from djangomako.shortcuts import render_to_response, render_to_string
|
||||
from mitxmako.shortcuts import render_to_response, render_to_string
|
||||
|
||||
from x_module import XModule
|
||||
|
||||
class SequentialModule(XModule):
|
||||
''' Layout module which lays out content in a temporal sequence
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
from x_module import XModule
|
||||
from lxml import etree
|
||||
|
||||
import json
|
||||
|
||||
## TODO: Abstract out from Django
|
||||
from django.conf import settings
|
||||
from djangomako.shortcuts import render_to_response, render_to_string
|
||||
from mitxmako.shortcuts import render_to_response, render_to_string
|
||||
|
||||
from x_module import XModule
|
||||
from lxml import etree
|
||||
|
||||
class VerticalModule(XModule):
|
||||
id_attribute = 'id'
|
||||
|
||||
@@ -1,36 +1,40 @@
|
||||
from x_module import XModule
|
||||
from lxml import etree
|
||||
|
||||
import json
|
||||
import logging
|
||||
|
||||
from lxml import etree
|
||||
|
||||
## TODO: Abstract out from Django
|
||||
from django.conf import settings
|
||||
from djangomako.shortcuts import render_to_response, render_to_string
|
||||
from mitxmako.shortcuts import render_to_response, render_to_string
|
||||
|
||||
from x_module import XModule
|
||||
|
||||
log = logging.getLogger("mitx.courseware.modules")
|
||||
|
||||
class VideoModule(XModule):
|
||||
#id_attribute = 'youtube'
|
||||
video_time = 0
|
||||
|
||||
def handle_ajax(self, dispatch, get):
|
||||
print "GET", get
|
||||
print "DISPATCH", dispatch
|
||||
if dispatch=='goto_position':
|
||||
log.debug(u"GET {0}".format(get))
|
||||
log.debug(u"DISPATCH {0}".format(dispatch))
|
||||
if dispatch == 'goto_position':
|
||||
self.position = int(float(get['position']))
|
||||
print "NEW POSITION", self.position
|
||||
log.debug(u"NEW POSITION {0}".format(self.position))
|
||||
return json.dumps({'success':True})
|
||||
raise Http404()
|
||||
|
||||
def get_state(self):
|
||||
print "STATE POSITION", self.position
|
||||
log.debug(u"STATE POSITION {0}".format(self.position))
|
||||
return json.dumps({ 'position':self.position })
|
||||
|
||||
def get_xml_tags():
|
||||
''' Tags in the courseware file guaranteed to correspond to the module '''
|
||||
'''Tags in the courseware file guaranteed to correspond to the module'''
|
||||
return "video"
|
||||
|
||||
def video_list(self):
|
||||
l=self.youtube.split(',')
|
||||
l=[i.split(":") for i in l]
|
||||
l = self.youtube.split(',')
|
||||
l = [i.split(":") for i in l]
|
||||
return json.dumps(dict(l))
|
||||
|
||||
def get_html(self):
|
||||
@@ -39,24 +43,25 @@ class VideoModule(XModule):
|
||||
'position':self.position})
|
||||
|
||||
def get_init_js(self):
|
||||
''' JavaScript code to be run when problem is shown. Be aware
|
||||
'''JavaScript code to be run when problem is shown. Be aware
|
||||
that this may happen several times on the same page
|
||||
(e.g. student switching tabs). Common functions should be put
|
||||
in the main course .js files for now. '''
|
||||
print "INIT POSITION", self.position
|
||||
log.debug(u"INIT POSITION {0}".format(self.position))
|
||||
return render_to_string('video_init.js',{'streams':self.video_list(),
|
||||
'id':self.item_id,
|
||||
'position':self.position})
|
||||
|
||||
def get_destroy_js(self):
|
||||
return "videoDestroy(\""+self.item_id+"\");"
|
||||
return "videoDestroy(\"{0}\");".format(self.item_id)
|
||||
|
||||
def __init__(self, xml, item_id, ajax_url=None, track_url=None, state=None, track_function=None, render_function = None):
|
||||
XModule.__init__(self, xml, item_id, ajax_url, track_url, state, track_function, render_function)
|
||||
self.youtube = etree.XML(xml).get('youtube')
|
||||
self.position = 0
|
||||
if state!=None:
|
||||
if state != None:
|
||||
state = json.loads(state)
|
||||
if 'position' in state: self.position = int(float(state['position']))
|
||||
print "POOSITION IN STATE"
|
||||
print "LOAD POSITION", self.position
|
||||
if 'position' in state:
|
||||
self.position = int(float(state['position']))
|
||||
log.debug("POSITION IN STATE")
|
||||
log.debug(u"LOAD POSITION {0}".format(self.position))
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import courseware.progress
|
||||
|
||||
def dummy_track(event_type, event):
|
||||
pass
|
||||
|
||||
@@ -12,6 +14,9 @@ class XModule(object):
|
||||
''' Tags in the courseware file guaranteed to correspond to the module '''
|
||||
return []
|
||||
|
||||
def get_completion(self):
|
||||
return courseware.progress.completion()
|
||||
|
||||
def get_state(self):
|
||||
return ""
|
||||
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
class completion(object):
|
||||
def __init__(self, d=None):
|
||||
self.dict = dict()
|
||||
def __init__(self, **d):
|
||||
self.dict = dict({'duration_total':0,
|
||||
'duration_watched':0,
|
||||
'done':True,
|
||||
'questions_correct':0,
|
||||
'questions_incorrect':0,
|
||||
'questions_total':0})
|
||||
if d:
|
||||
self.dict.update(d)
|
||||
|
||||
@@ -11,9 +16,23 @@ class completion(object):
|
||||
self.dict[key] = value
|
||||
|
||||
def __add__(self, other):
|
||||
result = dict()
|
||||
dict.update(self.dict)
|
||||
dict.update(other.dict)
|
||||
result = dict(self.dict)
|
||||
for item in ['duration_total',
|
||||
'duration_watched',
|
||||
'done',
|
||||
'questions_correct',
|
||||
'questions_incorrect',
|
||||
'questions_total']:
|
||||
result[item] = result[item]+other.dict[item]
|
||||
return completion(**result)
|
||||
|
||||
def __contains__(self, key):
|
||||
pass
|
||||
return key in dict
|
||||
|
||||
def __repr__(self):
|
||||
return repr(self.dict)
|
||||
|
||||
if __name__ == '__main__':
|
||||
dict1=completion(duration_total=5)
|
||||
dict2=completion(duration_total=7)
|
||||
print dict1+dict2
|
||||
|
||||
@@ -12,16 +12,16 @@ from django.contrib.auth.models import User
|
||||
from django.http import HttpResponse, Http404
|
||||
from django.shortcuts import redirect
|
||||
from django.template import Context, loader
|
||||
from djangomako.shortcuts import render_to_response, render_to_string
|
||||
from mitxmako.shortcuts import render_to_response, render_to_string
|
||||
from django.db import connection
|
||||
|
||||
from lxml import etree
|
||||
|
||||
from auth.models import UserProfile
|
||||
from models import StudentModule
|
||||
from module_render import * # TODO: Clean up
|
||||
from module_render import modx_dispatch
|
||||
from module_render import render_module, modx_dispatch
|
||||
import courseware.content_parser as content_parser
|
||||
import courseware.modules.capa_module
|
||||
|
||||
log = logging.getLogger("mitx.courseware")
|
||||
|
||||
@@ -36,10 +36,6 @@ def profile(request):
|
||||
if not request.user.is_authenticated():
|
||||
return redirect('/')
|
||||
|
||||
log.info("Profile called")
|
||||
logging.info("Now the root")
|
||||
logging.getLogger("tracking").info("this should be unformatted")
|
||||
|
||||
dom=content_parser.course_file(request.user)
|
||||
hw=[]
|
||||
course = dom.xpath('//course/@name')[0]
|
||||
@@ -145,6 +141,7 @@ def index(request, course="6.002 Spring 2012", chapter="Using the System", secti
|
||||
|
||||
module_object_preload = list(StudentModule.objects.filter(student=user,
|
||||
module_id__in=module_ids))
|
||||
|
||||
|
||||
module=render_module(user, request, module, module_object_preload)
|
||||
|
||||
|
||||
15
mitxmako/README
Normal file
15
mitxmako/README
Normal file
@@ -0,0 +1,15 @@
|
||||
================================================================================
|
||||
django-mako
|
||||
================================================================================
|
||||
This module provides a drop in replacement of Django templates for Mako
|
||||
Templates.
|
||||
|
||||
Django: http://www.djangoproject.com/
|
||||
Mako: http://www.makotemplates.org/
|
||||
|
||||
================================================================================
|
||||
How to install?
|
||||
================================================================================
|
||||
|
||||
$ sudo python setup.py install
|
||||
|
||||
16
mitxmako/__init__.py
Normal file
16
mitxmako/__init__.py
Normal file
@@ -0,0 +1,16 @@
|
||||
# Copyright (c) 2008 Mikeal Rogers
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
lookup = None
|
||||
|
||||
49
mitxmako/middleware.py
Normal file
49
mitxmako/middleware.py
Normal file
@@ -0,0 +1,49 @@
|
||||
# Copyright (c) 2008 Mikeal Rogers
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from mako.lookup import TemplateLookup
|
||||
import tempfile
|
||||
from django.template import RequestContext
|
||||
|
||||
requestcontext = None
|
||||
lookup = None
|
||||
|
||||
class MakoMiddleware(object):
|
||||
def __init__(self):
|
||||
"""Setup mako variables and lookup object"""
|
||||
from django.conf import settings
|
||||
# Set all mako variables based on django settings
|
||||
global template_dirs, output_encoding, module_directory, encoding_errors
|
||||
directories = getattr(settings, 'MAKO_TEMPLATE_DIRS', settings.TEMPLATE_DIRS)
|
||||
|
||||
module_directory = getattr(settings, 'MAKO_MODULE_DIR', None)
|
||||
if module_directory is None:
|
||||
module_directory = tempfile.mkdtemp()
|
||||
|
||||
output_encoding = getattr(settings, 'MAKO_OUTPUT_ENCODING', 'utf-8')
|
||||
encoding_errors = getattr(settings, 'MAKO_ENCODING_ERRORS', 'replace')
|
||||
|
||||
global lookup
|
||||
lookup = TemplateLookup(directories=directories,
|
||||
module_directory=module_directory,
|
||||
output_encoding=output_encoding,
|
||||
encoding_errors=encoding_errors,
|
||||
)
|
||||
import mitxmako
|
||||
mitxmako.lookup = lookup
|
||||
|
||||
def process_request (self, request):
|
||||
global requestcontext
|
||||
requestcontext = RequestContext(request)
|
||||
# print requestcontext
|
||||
42
mitxmako/shortcuts.py
Normal file
42
mitxmako/shortcuts.py
Normal file
@@ -0,0 +1,42 @@
|
||||
# Copyright (c) 2008 Mikeal Rogers
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from django.template import Context
|
||||
from django.http import HttpResponse
|
||||
|
||||
import mitxmako.middleware as middleware
|
||||
from django.conf import settings
|
||||
|
||||
from mitxmako.middleware import requestcontext
|
||||
|
||||
def render_to_string(template_name, dictionary, context_instance=None):
|
||||
context_instance = context_instance or Context(dictionary)
|
||||
# add dictionary to context_instance
|
||||
context_instance.update(dictionary or {})
|
||||
# collapse context_instance to a single dictionary for mako
|
||||
context_dictionary = {}
|
||||
context_instance['settings'] = settings
|
||||
context_instance['request_context'] = requestcontext
|
||||
for d in context_instance:
|
||||
context_dictionary.update(d)
|
||||
# fetch and render template
|
||||
template = middleware.lookup.get_template(template_name)
|
||||
return template.render(**context_dictionary)
|
||||
|
||||
def render_to_response(template_name, dictionary, context_instance=None, **kwargs):
|
||||
"""
|
||||
Returns a HttpResponse whose content is filled with the result of calling
|
||||
lookup.get_template(args[0]).render with the passed arguments.
|
||||
"""
|
||||
return HttpResponse(render_to_string(template_name, dictionary, context_instance), **kwargs)
|
||||
28
mitxmako/template.py
Normal file
28
mitxmako/template.py
Normal file
@@ -0,0 +1,28 @@
|
||||
# Copyright (c) 2008 Mikeal Rogers
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from mako.template import Template as MakoTemplate
|
||||
|
||||
import middleware
|
||||
|
||||
django_variables = ['lookup', 'template_dirs', 'output_encoding',
|
||||
'module_directory', 'encoding_errors',]
|
||||
|
||||
class Template(MakoTemplate):
|
||||
def __init__(self, *args, **kwargs):
|
||||
"""Overrides base __init__ to provide django variable overrides"""
|
||||
if not kwargs.get('no_django', False):
|
||||
overrides = dict([(k, getattr(middleware, k, None),) for k in django_variables])
|
||||
kwargs.update(overrides)
|
||||
super(Template, self).__init__(*args, **kwargs)
|
||||
@@ -1,7 +1,11 @@
|
||||
import views, json, tempfile, time
|
||||
import json
|
||||
import tempfile
|
||||
import time
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import connection
|
||||
|
||||
import views
|
||||
|
||||
class ProfileMiddleware:
|
||||
def process_request (self, request):
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
# Create your views here.
|
||||
import middleware
|
||||
|
||||
from django.http import HttpResponse
|
||||
|
||||
def end_profile(request):
|
||||
|
||||
@@ -3,12 +3,16 @@ import sys
|
||||
|
||||
import djcelery
|
||||
|
||||
LIB_URL = '/static/lib/'
|
||||
LIB_URL = 'http://mitxstatic.s3-website-us-east-1.amazonaws.com/js/'
|
||||
BOOK_URL = '/static/book/'
|
||||
BOOK_URL = 'http://mitxstatic.s3-website-us-east-1.amazonaws.com/book_images/'
|
||||
|
||||
# Our parent dir (mitx_all) is the BASE_DIR
|
||||
BASE_DIR = os.path.abspath(os.path.join(__file__, "..", ".."))
|
||||
|
||||
COURSEWARE_ENABLED = True
|
||||
ASKBOT_ENABLED = True
|
||||
|
||||
CSRF_COOKIE_DOMAIN = '127.0.0.1'
|
||||
|
||||
# Defaults to be overridden
|
||||
@@ -34,7 +38,7 @@ DEBUG = True
|
||||
TEMPLATE_DEBUG = DEBUG
|
||||
|
||||
ADMINS = (
|
||||
('Piotr Mitros', 'pmitros@csail.mit.edu'),
|
||||
('Piotr Mitros', 'staff@csail.mit.edu'),
|
||||
)
|
||||
|
||||
MANAGERS = ADMINS
|
||||
@@ -56,87 +60,6 @@ USE_I18N = True
|
||||
# calendars according to the current locale
|
||||
USE_L10N = True
|
||||
|
||||
# A sample logging configuration. The only tangible logging
|
||||
# performed by this configuration is to send an email to
|
||||
# the site admins on every HTTP 500 error.
|
||||
# See http://docs.djangoproject.com/en/dev/topics/logging for
|
||||
# more details on how to customize your logging configuration.
|
||||
LOGGING = {
|
||||
'version': 1,
|
||||
'disable_existing_loggers': True,
|
||||
'formatters' : {
|
||||
'standard' : {
|
||||
'format' : '%(levelname)s %(asctime)s PID:%(process)d %(name)s %(filename)s:%(lineno)d %(message)s',
|
||||
},
|
||||
'raw' : {
|
||||
'format' : '%(message)s',
|
||||
}
|
||||
},
|
||||
'handlers' : {
|
||||
'console' : {
|
||||
'level' : 'DEBUG' if DEBUG else 'INFO',
|
||||
'class' : 'logging.StreamHandler',
|
||||
'formatter' : 'standard',
|
||||
'stream' : sys.stdout,
|
||||
},
|
||||
'console_err' : {
|
||||
'level' : 'ERROR',
|
||||
'class' : 'logging.StreamHandler',
|
||||
'formatter' : 'standard',
|
||||
'stream' : sys.stderr,
|
||||
},
|
||||
# 'app' : {
|
||||
# 'level' : 'INFO',
|
||||
# 'class' : 'logging.handlers.TimedRotatingFileHandler',
|
||||
# 'formatter' : 'standard',
|
||||
# 'filename' : '/tmp/mitx.log', # temporary location for proof of concept
|
||||
# 'when' : 'midnight',
|
||||
# 'utc' : True,
|
||||
# 'encoding' : 'utf-8',
|
||||
# },
|
||||
|
||||
# We should actually use this for tracking:
|
||||
# http://pypi.python.org/pypi/ConcurrentLogHandler/0.8.2
|
||||
'tracking' : {
|
||||
'level' : 'INFO',
|
||||
'class' : 'logging.handlers.TimedRotatingFileHandler',
|
||||
'formatter' : 'raw',
|
||||
'filename' : BASE_DIR + '/track_dir/tracking.log',
|
||||
'when' : 'midnight',
|
||||
'utc' : True,
|
||||
'encoding' : 'utf-8',
|
||||
},
|
||||
'mail_admins' : {
|
||||
'level': 'ERROR',
|
||||
'class': 'django.utils.log.AdminEmailHandler',
|
||||
},
|
||||
},
|
||||
'loggers' : {
|
||||
'django.request': {
|
||||
'handlers': ['mail_admins', 'console', 'console_err'],
|
||||
'level': 'INFO',
|
||||
'propagate': True,
|
||||
},
|
||||
'tracking' : {
|
||||
'handlers' : ['tracking'],
|
||||
'level' : 'DEBUG',
|
||||
'propagate' : False,
|
||||
},
|
||||
'root' : {
|
||||
'handlers' : ['console', 'console_err'],
|
||||
'level' : 'DEBUG',
|
||||
'propagate' : False
|
||||
},
|
||||
'mitx' : {
|
||||
'handlers' : ['console', 'console_err'],
|
||||
'level' : 'DEBUG',
|
||||
'propagate' : False
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC_URL = '/static/'
|
||||
|
||||
# URL prefix for admin static files -- CSS, JavaScript and images.
|
||||
@@ -166,7 +89,7 @@ MIDDLEWARE_CLASSES = (
|
||||
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
||||
'django.contrib.messages.middleware.MessageMiddleware',
|
||||
'track.middleware.TrackMiddleware',
|
||||
'djangomako.middleware.MakoMiddleware',
|
||||
'mitxmako.middleware.MakoMiddleware',
|
||||
#'debug_toolbar.middleware.DebugToolbarMiddleware',
|
||||
)
|
||||
|
||||
@@ -188,6 +111,7 @@ INSTALLED_APPS = (
|
||||
'track',
|
||||
'circuit',
|
||||
'perfstats',
|
||||
'util',
|
||||
# Uncomment the next line to enable the admin:
|
||||
# 'django.contrib.admin',
|
||||
# Uncomment the next line to enable admin documentation:
|
||||
@@ -201,9 +125,94 @@ TRACK_MAX_EVENT = 1000
|
||||
# Maximum length of log file before starting a new one.
|
||||
MAXLOG = 500
|
||||
|
||||
LOG_DIR = "/tmp/"
|
||||
|
||||
# Make sure we execute correctly regardless of where we're called from
|
||||
execfile(os.path.join(BASE_DIR, "settings.py"))
|
||||
|
||||
# A sample logging configuration. The only tangible logging
|
||||
# performed by this configuration is to send an email to
|
||||
# the site admins on every HTTP 500 error.
|
||||
# See http://docs.djangoproject.com/en/dev/topics/logging for
|
||||
# more details on how to customize your logging configuration.
|
||||
LOGGING = {
|
||||
'version': 1,
|
||||
'disable_existing_loggers': True,
|
||||
'formatters' : {
|
||||
'standard' : {
|
||||
'format' : '%(asctime)s %(levelname)s %(process)d [%(name)s] %(filename)s:%(lineno)d - %(message)s',
|
||||
},
|
||||
'raw' : {
|
||||
'format' : '%(message)s',
|
||||
}
|
||||
},
|
||||
'handlers' : {
|
||||
'console' : {
|
||||
'level' : 'DEBUG' if DEBUG else 'INFO',
|
||||
'class' : 'logging.StreamHandler',
|
||||
'formatter' : 'standard',
|
||||
'stream' : sys.stdout,
|
||||
},
|
||||
'console_err' : {
|
||||
'level' : 'ERROR',
|
||||
'class' : 'logging.StreamHandler',
|
||||
'formatter' : 'standard',
|
||||
'stream' : sys.stderr,
|
||||
},
|
||||
'app' : {
|
||||
'level' : 'DEBUG' if DEBUG else 'INFO',
|
||||
'class' : 'logging.handlers.WatchedFileHandler',
|
||||
'formatter' : 'standard',
|
||||
'filename' : LOG_DIR + '/mitx.log', # temporary location for proof of concept
|
||||
'encoding' : 'utf-8',
|
||||
},
|
||||
'app_err' : {
|
||||
'level' : 'WARNING',
|
||||
'class' : 'logging.handlers.WatchedFileHandler',
|
||||
'formatter' : 'standard',
|
||||
'filename' : LOG_DIR + '/mitx.err.log', # temporary location for proof of concept
|
||||
'encoding' : 'utf-8',
|
||||
},
|
||||
# We should actually use this for tracking:
|
||||
# http://pypi.python.org/pypi/ConcurrentLogHandler/0.8.2
|
||||
'tracking' : {
|
||||
'level' : 'INFO',
|
||||
'class' : 'logging.handlers.WatchedFileHandler',
|
||||
'formatter' : 'raw',
|
||||
'filename' : LOG_DIR + '/tracking.log',
|
||||
'encoding' : 'utf-8',
|
||||
},
|
||||
'mail_admins' : {
|
||||
'level': 'ERROR',
|
||||
'class': 'django.utils.log.AdminEmailHandler',
|
||||
},
|
||||
},
|
||||
'loggers' : {
|
||||
'django' : {
|
||||
'handlers' : ['console', 'mail_admins', 'app_err'],
|
||||
'propagate' : True,
|
||||
'level' : 'INFO'
|
||||
},
|
||||
'tracking' : {
|
||||
'handlers' : ['console', 'tracking'],
|
||||
'level' : 'DEBUG',
|
||||
'propagate' : False,
|
||||
},
|
||||
'root' : {
|
||||
'handlers' : ['console', 'app', 'app_err'],
|
||||
'level' : 'DEBUG',
|
||||
'propagate' : False
|
||||
},
|
||||
'mitx' : {
|
||||
'handlers' : ['console', 'app', 'app_err'],
|
||||
'level' : 'DEBUG',
|
||||
'propagate' : False
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
if PERFSTATS :
|
||||
MIDDLEWARE_CLASSES = ( 'perfstats.middleware.ProfileMiddleware',) + MIDDLEWARE_CLASSES
|
||||
|
||||
@@ -252,6 +261,7 @@ site.addsitedir(os.path.join(os.path.dirname(askbot.__file__), 'deps'))
|
||||
TEMPLATE_LOADERS = TEMPLATE_LOADERS + ('askbot.skins.loaders.filesystem_load_template_source',)
|
||||
|
||||
MIDDLEWARE_CLASSES = MIDDLEWARE_CLASSES + (
|
||||
'util.middleware.ExceptionLoggingMiddleware',
|
||||
'askbot.middleware.anon_user.ConnectToSessionMessagesMiddleware',
|
||||
'askbot.middleware.forum_mode.ForumModeMiddleware',
|
||||
'askbot.middleware.cancel.CancelActionMiddleware',
|
||||
@@ -312,3 +322,4 @@ BROKER_TRANSPORT = "djkombu.transport.DatabaseTransport"
|
||||
CELERY_ALWAYS_EAGER = True
|
||||
|
||||
djcelery.setup_loader()
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ DEBUG = True
|
||||
TEMPLATE_DEBUG = DEBUG
|
||||
|
||||
ADMINS = (
|
||||
('Piotr Mitros', 'pmitros@csail.mit.edu'),
|
||||
('Piotr Mitros', 'staff@csail.mit.edu'),
|
||||
)
|
||||
|
||||
MANAGERS = ADMINS
|
||||
@@ -81,7 +81,7 @@ MIDDLEWARE_CLASSES = (
|
||||
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
||||
'django.contrib.messages.middleware.MessageMiddleware',
|
||||
'track.middleware.TrackMiddleware',
|
||||
'djangomako.middleware.MakoMiddleware',
|
||||
'mitxmako.middleware.MakoMiddleware',
|
||||
#'debug_toolbar.middleware.DebugToolbarMiddleware',
|
||||
)
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# Source: django-simplewiki. GPL license.
|
||||
|
||||
import sys, os
|
||||
import os
|
||||
import sys
|
||||
|
||||
# allow mdx_* parsers to be just dropped in the simplewiki folder
|
||||
module_path = os.path.abspath(os.path.dirname(__file__))
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
# Source: django-simplewiki. GPL license.
|
||||
|
||||
from django.contrib import admin
|
||||
from django import forms
|
||||
from django.contrib import admin
|
||||
from django.utils.translation import ugettext as _
|
||||
|
||||
from models import Article, Revision, Permission, ArticleAttachment
|
||||
|
||||
class RevisionInline(admin.TabularInline):
|
||||
|
||||
@@ -8,7 +8,7 @@ circuit:name becomes the circuit.
|
||||
|
||||
import simplewiki.settings as settings
|
||||
|
||||
from djangomako.shortcuts import render_to_response, render_to_string
|
||||
from mitxmako.shortcuts import render_to_response, render_to_string
|
||||
|
||||
import markdown
|
||||
try:
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.db import models
|
||||
from django.db.models import signals
|
||||
from django.contrib.auth.models import User
|
||||
from markdown import markdown
|
||||
from django import forms
|
||||
from django.core.urlresolvers import reverse
|
||||
import difflib
|
||||
import os
|
||||
|
||||
from django import forms
|
||||
from django.contrib.auth.models import User
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.db import models
|
||||
from django.db.models import signals
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from markdown import markdown
|
||||
|
||||
from settings import *
|
||||
|
||||
class ShouldHaveExactlyOneRootSlug(Exception):
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
from django import template
|
||||
from django.template.defaultfilters import stringfilter
|
||||
from simplewiki.settings import *
|
||||
from django.conf import settings
|
||||
from django.template.defaultfilters import stringfilter
|
||||
from django.utils.http import urlquote as django_urlquote
|
||||
|
||||
from simplewiki.settings import *
|
||||
|
||||
register = template.Library()
|
||||
|
||||
@register.filter()
|
||||
@@ -14,4 +15,4 @@ def prepend_media_url(value):
|
||||
@register.filter()
|
||||
def urlquote(value):
|
||||
"""Prepend user defined media root to url"""
|
||||
return django_urlquote(value)
|
||||
return django_urlquote(value)
|
||||
|
||||
@@ -3,6 +3,7 @@ from django.conf.urls.defaults import *
|
||||
urlpatterns = patterns('',
|
||||
url(r'^$', 'simplewiki.views.root_redirect', name='wiki_root'),
|
||||
url(r'^view(/[a-zA-Z\d/_-]*)/?$', 'simplewiki.views.view', name='wiki_view'),
|
||||
url(r'^view_revision/([0-9]*)(/[a-zA-Z\d/_-]*)/?$', 'simplewiki.views.view_revision', name='wiki_view_revision'),
|
||||
url(r'^edit(/[a-zA-Z\d/_-]*)/?$', 'simplewiki.views.edit', name='wiki_edit'),
|
||||
url(r'^create(/[a-zA-Z\d/_-]*)/?$', 'simplewiki.views.create', name='wiki_create'),
|
||||
url(r'^history(/[a-zA-Z\d/_-]*)/([0-9]*)/?$', 'simplewiki.views.history', name='wiki_history'),
|
||||
|
||||
@@ -1,27 +1,26 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import types
|
||||
from django.core.urlresolvers import get_callable
|
||||
from django.http import Http404, HttpResponse, HttpResponseRedirect, HttpResponseServerError, HttpResponseForbidden, HttpResponseNotAllowed
|
||||
from django.utils import simplejson
|
||||
from djangomako.shortcuts import render_to_response, render_to_string
|
||||
from django.shortcuts import get_object_or_404
|
||||
from django.template import RequestContext, Context, loader
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.db.models import Q
|
||||
|
||||
from django.conf import settings
|
||||
from django.shortcuts import redirect
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.core.context_processors import csrf
|
||||
|
||||
from django.template import Context
|
||||
from django.core.urlresolvers import get_callable
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.db.models import Q
|
||||
from django.http import Http404, HttpResponse, HttpResponseRedirect, HttpResponseServerError, HttpResponseForbidden, HttpResponseNotAllowed
|
||||
from django.http import HttpResponse
|
||||
|
||||
import djangomako.middleware
|
||||
from mako.template import Template
|
||||
from django.shortcuts import get_object_or_404
|
||||
from django.shortcuts import redirect
|
||||
from django.template import Context
|
||||
from django.template import RequestContext, Context, loader
|
||||
from django.utils import simplejson
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from mitxmako.shortcuts import render_to_response, render_to_string
|
||||
from mako.lookup import TemplateLookup
|
||||
from mako.template import Template
|
||||
import mitxmako.middleware
|
||||
|
||||
from models import *
|
||||
from models import * # TODO: Clean up
|
||||
from settings import *
|
||||
|
||||
def view(request, wiki_url):
|
||||
@@ -36,12 +35,44 @@ def view(request, wiki_url):
|
||||
if perm_err:
|
||||
return perm_err
|
||||
d = {'wiki_article': article,
|
||||
'wiki_article_revision':article.current_revision,
|
||||
'wiki_write': article.can_write_l(request.user),
|
||||
'wiki_attachments_write': article.can_attach(request.user),
|
||||
'wiki_current_revision_deleted' : not (article.current_revision.deleted == 0),
|
||||
}
|
||||
d.update(csrf(request))
|
||||
return render_to_response('simplewiki_view.html', d)
|
||||
|
||||
def view_revision(request, revision_number, wiki_url, revision=None):
|
||||
if not request.user.is_authenticated():
|
||||
return redirect('/')
|
||||
|
||||
(article, path, err) = fetch_from_url(request, wiki_url)
|
||||
if err:
|
||||
return err
|
||||
|
||||
try:
|
||||
revision = Revision.objects.get(counter=int(revision_number), article=article)
|
||||
except:
|
||||
d = {'wiki_article': article,
|
||||
'wiki_err_norevision': revision_number,}
|
||||
d.update(csrf(request))
|
||||
return render_to_response('simplewiki_error.html', d)
|
||||
|
||||
|
||||
perm_err = check_permissions(request, article, check_read=True, check_deleted=True, revision=revision)
|
||||
if perm_err:
|
||||
return perm_err
|
||||
|
||||
d = {'wiki_article': article,
|
||||
'wiki_article_revision':revision,
|
||||
'wiki_write': article.can_write_l(request.user),
|
||||
'wiki_attachments_write': article.can_attach(request.user),
|
||||
'wiki_current_revision_deleted' : not (revision.deleted == 0),
|
||||
}
|
||||
d.update(csrf(request))
|
||||
return render_to_response('simplewiki_view.html', d)
|
||||
|
||||
|
||||
def root_redirect(request):
|
||||
if not request.user.is_authenticated():
|
||||
@@ -206,12 +237,18 @@ def history(request, wiki_url, page=1):
|
||||
perm_err = check_permissions(request, article, check_write=True, check_locked=True)
|
||||
if perm_err:
|
||||
return perm_err
|
||||
|
||||
redirectURL = reverse('wiki_view', args=(article.get_url(),))
|
||||
try:
|
||||
r = int(request.POST['revision'])
|
||||
revision = Revision.objects.get(id=r)
|
||||
if request.POST.__contains__('change'):
|
||||
article.current_revision = revision
|
||||
article.save()
|
||||
elif request.POST.__contains__('view'):
|
||||
redirectURL = reverse('wiki_view_revision', args=(revision.counter, article.get_url(),))
|
||||
|
||||
#The rese of these are admin functions
|
||||
elif request.POST.__contains__('delete') and request.user.is_superuser:
|
||||
if (revision.deleted == 0):
|
||||
revision.adminSetDeleted(2)
|
||||
@@ -228,7 +265,7 @@ def history(request, wiki_url, page=1):
|
||||
except:
|
||||
pass
|
||||
finally:
|
||||
return HttpResponseRedirect(reverse('wiki_view', args=(article.get_url(),)))
|
||||
return HttpResponseRedirect(redirectURL)
|
||||
#
|
||||
#
|
||||
# <input type="submit" name="delete" value="Delete revision"/>
|
||||
@@ -433,14 +470,16 @@ def fetch_from_url(request, url):
|
||||
return (article, path, err)
|
||||
|
||||
|
||||
def check_permissions(request, article, check_read=False, check_write=False, check_locked=False, check_deleted=False):
|
||||
def check_permissions(request, article, check_read=False, check_write=False, check_locked=False, check_deleted=False, revision = None):
|
||||
read_err = check_read and not article.can_read(request.user)
|
||||
|
||||
write_err = check_write and not article.can_write(request.user)
|
||||
|
||||
locked_err = check_locked and article.locked
|
||||
|
||||
deleted_err = check_deleted and not (article.current_revision.deleted == 0)
|
||||
if revision == None:
|
||||
revision = article.current_revision
|
||||
deleted_err = check_deleted and not (revision.deleted == 0)
|
||||
if (request.user.is_superuser):
|
||||
deleted_err = False
|
||||
locked_err = False
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
import os
|
||||
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.core.servers.basehttp import FileWrapper
|
||||
from django.db.models.fields.files import FieldFile
|
||||
from django.http import HttpResponse, HttpResponseRedirect, HttpResponseForbidden, Http404
|
||||
from django.template import loader, Context
|
||||
from django.db.models.fields.files import FieldFile
|
||||
from django.core.servers.basehttp import FileWrapper
|
||||
from django.contrib.auth.decorators import login_required
|
||||
|
||||
from settings import *
|
||||
from settings import * # TODO: Clean up
|
||||
from models import Article, ArticleAttachment, get_attachment_filepath
|
||||
from views import not_found, check_permissions, get_url_path, fetch_from_url
|
||||
|
||||
import os
|
||||
from simplewiki.settings import WIKI_ALLOW_ANON_ATTACHMENTS
|
||||
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
# List of valid templates is explicitly managed for (short-term)
|
||||
# security reasons.
|
||||
|
||||
from djangomako.shortcuts import render_to_response, render_to_string
|
||||
from mitxmako.shortcuts import render_to_response, render_to_string
|
||||
from django.shortcuts import redirect
|
||||
from django.core.context_processors import csrf
|
||||
|
||||
|
||||
@@ -1,11 +1,15 @@
|
||||
# Create your views here.
|
||||
from djangomako.shortcuts import render_to_response, render_to_string
|
||||
from django.shortcuts import redirect
|
||||
import os
|
||||
|
||||
from django.conf import settings
|
||||
from django.http import Http404
|
||||
from django.shortcuts import redirect
|
||||
from mitxmako.shortcuts import render_to_response, render_to_string
|
||||
|
||||
def index(request, page=1):
|
||||
def index(request, page=0):
|
||||
if not request.user.is_authenticated():
|
||||
return redirect('/')
|
||||
return render_to_response('staticbook.html',{'page':int(page)})
|
||||
|
||||
def index_shifted(request, page):
|
||||
return index(request, int(page)+24)
|
||||
|
||||
@@ -1,10 +1,15 @@
|
||||
import views, json
|
||||
import json
|
||||
|
||||
from django.conf import settings
|
||||
|
||||
import views
|
||||
|
||||
class TrackMiddleware:
|
||||
def process_request (self, request):
|
||||
def process_request(self, request):
|
||||
try:
|
||||
# We're already logging events
|
||||
if request.META['PATH_INFO'] == '/event':
|
||||
# We're already logging events, and we don't want to capture user
|
||||
# names/passwords.
|
||||
if request.META['PATH_INFO'] in ['/event', '/login']:
|
||||
return
|
||||
|
||||
event = { 'GET' : dict(request.GET),
|
||||
|
||||
@@ -1,47 +1,17 @@
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
|
||||
# Create your views here.
|
||||
from django.http import HttpResponse
|
||||
from django.http import Http404
|
||||
from django.conf import settings
|
||||
import json, os, stat
|
||||
|
||||
import tempfile
|
||||
|
||||
if settings.TRACK_DIR != None:
|
||||
directory = tempfile.mkdtemp(prefix = settings.TRACK_DIR)
|
||||
else:
|
||||
directory = None
|
||||
|
||||
logfile = None
|
||||
file_index = 0
|
||||
log_index = 0
|
||||
filename = None
|
||||
|
||||
def make_file():
|
||||
global logfile, log_index, file_index, filename
|
||||
if logfile != None:
|
||||
logfile.close()
|
||||
os.chmod(filename, stat.S_IRUSR | stat.S_IWUSR | \
|
||||
stat.S_IRGRP | stat.S_IWGRP | \
|
||||
stat.S_IROTH )
|
||||
filename = directory+"/%05i"%(file_index)+".trklog"
|
||||
logfile = open(filename, "w")
|
||||
file_index = file_index + 1
|
||||
log_index = 0
|
||||
log = logging.getLogger("tracking")
|
||||
|
||||
def log_event(event):
|
||||
global logfile, log_index
|
||||
event_str = json.dumps(event)
|
||||
if settings.TRACK_DIR == None:
|
||||
# print event
|
||||
return
|
||||
|
||||
if logfile == None or log_index >= settings.MAXLOG:
|
||||
make_file()
|
||||
|
||||
logfile.write(event_str[:settings.TRACK_MAX_EVENT]+'\n')
|
||||
if settings.DEBUG_TRACK_LOG:
|
||||
print event_str
|
||||
log_index = log_index + 1
|
||||
log.info(event_str[:settings.TRACK_MAX_EVENT])
|
||||
|
||||
def user_track(request):
|
||||
try: # TODO: Do the same for many of the optional META parameters
|
||||
@@ -49,15 +19,25 @@ def user_track(request):
|
||||
except:
|
||||
username = "anonymous"
|
||||
|
||||
try:
|
||||
scookie = request.META['HTTP_COOKIE']
|
||||
except:
|
||||
scookie = ""
|
||||
|
||||
try:
|
||||
agent = request.META['HTTP_USER_AGENT']
|
||||
except:
|
||||
agent = ''
|
||||
|
||||
# TODO: Move a bunch of this into log_event
|
||||
event = {
|
||||
"username" : username,
|
||||
"session" : request.META['HTTP_COOKIE'],
|
||||
"session" : scookie,
|
||||
"ip" : request.META['REMOTE_ADDR'],
|
||||
"event_source" : "browser",
|
||||
"event_type" : request.GET['event_type'],
|
||||
"event" : request.GET['event'],
|
||||
"agent" : request.META['HTTP_USER_AGENT'],
|
||||
"agent" : agent,
|
||||
"page" : request.GET['page'],
|
||||
}
|
||||
log_event(event)
|
||||
@@ -69,13 +49,18 @@ def server_track(request, event_type, event, page=None):
|
||||
except:
|
||||
username = "anonymous"
|
||||
|
||||
try:
|
||||
agent = request.META['HTTP_USER_AGENT']
|
||||
except:
|
||||
agent = ''
|
||||
|
||||
event = {
|
||||
"username" : username,
|
||||
"ip" : request.META['REMOTE_ADDR'],
|
||||
"event_source" : "server",
|
||||
"event_type" : event_type,
|
||||
"event" : event,
|
||||
"agent" : request.META['HTTP_USER_AGENT'],
|
||||
"agent" : agent,
|
||||
"page" : page,
|
||||
}
|
||||
log_event(event)
|
||||
|
||||
12
urls.py
12
urls.py
@@ -1,8 +1,7 @@
|
||||
from django.conf.urls.defaults import patterns, include, url
|
||||
import django.contrib.auth.views
|
||||
from django.conf import settings
|
||||
from django.conf.urls.defaults import patterns, include, url
|
||||
from django.contrib import admin
|
||||
import perfstats
|
||||
import django.contrib.auth.views
|
||||
|
||||
# Uncomment the next two lines to enable the admin:
|
||||
# from django.contrib import admin
|
||||
@@ -19,7 +18,7 @@ urlpatterns = ('',
|
||||
url(r'^activate/(?P<key>[^/]*)$', 'auth.views.activate_account'),
|
||||
url(r'^$', 'auth.views.index'),
|
||||
url(r'^password_reset/$', 'django.contrib.auth.views.password_reset',
|
||||
dict(from_email='6002-admin@mit.edu'),name='auth_password_reset'),
|
||||
dict(from_email='registration@mitx.mit.edu'),name='auth_password_reset'),
|
||||
url(r'^password_change/$',django.contrib.auth.views.password_change,name='auth_password_change'),
|
||||
url(r'^password_change_done/$',django.contrib.auth.views.password_change_done,name='auth_password_change_done'),
|
||||
url(r'^password_reset_confirm/(?P<uidb36>[0-9A-Za-z]+)-(?P<token>.+)/$',django.contrib.auth.views.password_reset_confirm,
|
||||
@@ -29,14 +28,14 @@ urlpatterns = ('',
|
||||
url(r'^password_reset_done/$',django.contrib.auth.views.password_reset_done,
|
||||
name='auth_password_reset_done'),
|
||||
url(r'^send_feedback$', 'util.views.send_feedback'),
|
||||
url(r'^courseware/$', 'courseware.views.index'),
|
||||
)
|
||||
|
||||
if settings.PERFSTATS:
|
||||
urlpatterns=urlpatterns + (url(r'^reprofile$','perfstats.views.end_profile'),)
|
||||
|
||||
if settings.COURSEWARE_ENABLED:
|
||||
urlpatterns=urlpatterns + (url(r'^wiki/', include('simplewiki.urls')),
|
||||
urlpatterns=urlpatterns + ( url(r'^courseware/$', 'courseware.views.index'),
|
||||
url(r'^wiki/', include('simplewiki.urls')),
|
||||
url(r'^courseware/(?P<course>[^/]*)/(?P<chapter>[^/]*)/(?P<section>[^/]*)/$', 'courseware.views.index'),
|
||||
url(r'^courseware/(?P<course>[^/]*)/(?P<chapter>[^/]*)/$', 'courseware.views.index'),
|
||||
url(r'^courseware/(?P<course>[^/]*)/$', 'courseware.views.index'),
|
||||
@@ -45,6 +44,7 @@ if settings.COURSEWARE_ENABLED:
|
||||
url(r'^change_setting$', 'auth.views.change_setting'),
|
||||
url(r'^s/(?P<template>[^/]*)$', 'static_template_view.views.auth_index'),
|
||||
url(r'^book/(?P<page>[^/]*)$', 'staticbook.views.index'),
|
||||
url(r'^book-shifted/(?P<page>[^/]*)$', 'staticbook.views.index_shifted'),
|
||||
url(r'^book*$', 'staticbook.views.index'),
|
||||
# url(r'^course_info/$', 'auth.views.courseinfo'),
|
||||
# url(r'^show_circuit/(?P<circuit>[^/]*)$', 'circuit.views.show_circuit'),
|
||||
|
||||
13
util/middleware.py
Normal file
13
util/middleware.py
Normal file
@@ -0,0 +1,13 @@
|
||||
import logging
|
||||
|
||||
from django.http import HttpResponse
|
||||
|
||||
log = logging.getLogger("mitx")
|
||||
|
||||
class ExceptionLoggingMiddleware(object):
|
||||
"""Just here to log unchecked exceptions that go all the way up the Django
|
||||
stack"""
|
||||
|
||||
def process_exception(self, request, exception):
|
||||
log.exception(exception)
|
||||
return HttpResponse("Server Error - Please try again later.")
|
||||
@@ -1,21 +1,22 @@
|
||||
from djangomako.shortcuts import render_to_response, render_to_string
|
||||
from django.shortcuts import redirect
|
||||
from django.contrib.auth.models import User
|
||||
from django.http import HttpResponse
|
||||
import json
|
||||
from django.conf import settings
|
||||
from django.core.context_processors import csrf
|
||||
from django.http import Http404
|
||||
import courseware.capa.calc
|
||||
from django.core.mail import send_mail
|
||||
from django.conf import settings
|
||||
import datetime
|
||||
import json
|
||||
import sys
|
||||
|
||||
from django.conf import settings
|
||||
from django.conf import settings
|
||||
from django.contrib.auth.models import User
|
||||
from django.core.context_processors import csrf
|
||||
from django.core.mail import send_mail
|
||||
from django.http import Http404
|
||||
from django.http import HttpResponse
|
||||
from django.shortcuts import redirect
|
||||
from mitxmako.shortcuts import render_to_response, render_to_string
|
||||
|
||||
import courseware.capa.calc
|
||||
import track.views
|
||||
|
||||
def calculate(request):
|
||||
# if not request.user.is_authenticated():
|
||||
# raise Http404
|
||||
''' Calculator in footer of every page. '''
|
||||
equation = request.GET['equation']
|
||||
try:
|
||||
result = courseware.capa.calc.evaluator({}, {}, equation)
|
||||
@@ -27,8 +28,7 @@ def calculate(request):
|
||||
return HttpResponse(json.dumps({'result':result}))
|
||||
|
||||
def send_feedback(request):
|
||||
# if not request.user.is_authenticated():
|
||||
# raise Http404
|
||||
''' Feeback mechanism in footer of every page. '''
|
||||
try:
|
||||
username = request.user.username
|
||||
except:
|
||||
@@ -50,4 +50,5 @@ def send_feedback(request):
|
||||
return HttpResponse(json.dumps({'success':True}))
|
||||
|
||||
def info(request):
|
||||
''' Info page (link from main header) '''
|
||||
return render_to_response("info.html", {})
|
||||
|
||||
Reference in New Issue
Block a user