Commit c6d2ea6a by Bridger Maxwell

Merge with default branch

--HG--
branch : profiledev
parents c3a6ad2f 3a6a43c0
import uuid
from django.db import models from django.db import models
from django.contrib.auth.models import User from django.contrib.auth.models import User
import uuid
class UserProfile(models.Model): class UserProfile(models.Model):
## CRITICAL TODO/SECURITY ## CRITICAL TODO/SECURITY
......
from djangomako.shortcuts import render_to_response, render_to_string
from django.contrib.auth.models import User
from django.shortcuts import redirect
from django.contrib.auth import logout, authenticate, login
from django.contrib.auth.models import User
from django.http import HttpResponse
import json import json
from models import Registration, UserProfile import logging
import random
import string
from django.conf import settings from django.conf import settings
from django.contrib.auth import logout, authenticate, login
from django.contrib.auth.models import User
from django.contrib.auth.models import User
from django.core.context_processors import csrf from django.core.context_processors import csrf
from django.core.validators import validate_email, validate_slug from django.core.validators import validate_email, validate_slug
import random, string
from django.db import connection 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): def csrf_token(context):
csrf_token = context.get('csrf_token', '') csrf_token = context.get('csrf_token', '')
...@@ -37,37 +42,43 @@ def index(request): ...@@ -37,37 +42,43 @@ def index(request):
# return render_to_response('courseinfo.html', {'error' : '', # return render_to_response('courseinfo.html', {'error' : '',
# 'csrf': csrf_token }) # 'csrf': csrf_token })
# Need different levels of logging
def login_user(request, error=""): def login_user(request, error=""):
# print request.POST
if 'email' not in request.POST or 'password' not in 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('+',' ')}) return render_to_response('login.html', {'error':error.replace('+',' ')})
email = request.POST['email'] email = request.POST['email']
password = request.POST['password'] password = request.POST['password']
try: try:
user=User.objects.get(email=email) user = User.objects.get(email=email)
except User.DoesNotExist: except User.DoesNotExist:
log.warning("Login failed - Unknown user email: {0}".format(email))
return HttpResponse(json.dumps({'success':False, return HttpResponse(json.dumps({'success':False,
'error': 'Invalid login'})) # TODO: User error message 'error': 'Invalid login'})) # TODO: User error message
username=user.username username = user.username
user=authenticate(username=username, password=password) user = authenticate(username=username, password=password)
if user is None: if user is None:
log.warning("Login failed - password for {0} is invalid".format(email))
return HttpResponse(json.dumps({'success':False, return HttpResponse(json.dumps({'success':False,
'error': 'Invalid login'})) 'error': 'Invalid login'}))
if user is not None and user.is_active: if user is not None and user.is_active:
try:
login(request, user) login(request, user)
if request.POST['remember'] == 'true': if request.POST['remember'] == 'true':
request.session.set_expiry(None) # or change to 604800 for 7 days request.session.set_expiry(None) # or change to 604800 for 7 days
# print "recall" log.debug("Setting user session to never expire")
else: else:
request.session.set_expiry(0) request.session.set_expiry(0)
#print "close" except Exception as e:
# print len(connection.queries), connection.queries log.critical("Login failed - Could not create session. Is memcached running?")
return HttpResponse(json.dumps({'success':True})) log.exception(e)
# print len(connection.queries), connection.queries log.info("Login success - {0} ({1})".format(username, email))
return HttpResponse(json.dumps({'success':True}))
log.warning("Login failed - Account not active for user {0}".format(username))
return HttpResponse(json.dumps({'success':False, return HttpResponse(json.dumps({'success':False,
'error': 'Account not active. Check your e-mail.'})) 'error': 'Account not active. Check your e-mail.'}))
......
import uuid
from django.db import models from django.db import models
from django.contrib.auth.models import User from django.contrib.auth.models import User
import uuid
class ServerCircuit(models.Model): class ServerCircuit(models.Model):
# Later, add owner, who can edit, part of what app, etc. # Later, add owner, who can edit, part of what app, etc.
......
from djangomako.shortcuts import render_to_response, render_to_string import json
from django.shortcuts import redirect
import os import os
import xml.etree.ElementTree
from django.conf import settings from django.conf import settings
from django.http import Http404 from django.http import Http404
from models import ServerCircuit
import json
import xml.etree.ElementTree
from django.http import HttpResponse 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): def circuit_line(circuit):
''' Returns string for an appropriate input element for a circuit.
TODO: Rename. '''
if not circuit.isalnum(): if not circuit.isalnum():
raise Http404() raise Http404()
try: try:
sc = ServerCircuit.objects.get(name=circuit) sc = ServerCircuit.objects.get(name=circuit)
schematic = sc.schematic schematic = sc.schematic
print "Got"
except: except:
schematic = '' schematic = ''
print "not got"
print "X", schematic
circuit_line = xml.etree.ElementTree.Element('input') circuit_line = xml.etree.ElementTree.Element('input')
circuit_line.set('type', 'hidden') circuit_line.set('type', 'hidden')
......
import math import math
import operator import operator
from pyparsing import Word, alphas, nums, oneOf, Literal from pyparsing import Word, alphas, nums, oneOf, Literal
from pyparsing import ZeroOrMore, OneOrMore, StringStart from pyparsing import ZeroOrMore, OneOrMore, StringStart
from pyparsing import StringEnd, Optional, Forward from pyparsing import StringEnd, Optional, Forward
......
import random, numpy, math, scipy import copy
import struct, os import math
import numpy
import os
import random
import re import re
import scipy
import struct
from lxml import etree from lxml import etree
from lxml.etree import Element from lxml.etree import Element
import copy
from mako.template import Template from mako.template import Template
from courseware.content_parser import xpath_remove
import calc, eia
from util import contextualize_text from util import contextualize_text
from inputtypes import textline, schematic from inputtypes import textline, schematic
from responsetypes import numericalresponse, formularesponse, customresponse, schematicresponse from responsetypes import numericalresponse, formularesponse, customresponse, schematicresponse
import calc
import eia
response_types = {'numericalresponse':numericalresponse, response_types = {'numericalresponse':numericalresponse,
'formularesponse':formularesponse, 'formularesponse':formularesponse,
'customresponse':customresponse, 'customresponse':customresponse,
...@@ -52,12 +58,14 @@ class LoncapaProblem(object): ...@@ -52,12 +58,14 @@ class LoncapaProblem(object):
self.done = False self.done = False
self.filename = filename self.filename = filename
if id!=None: if id:
self.problem_id = id self.problem_id = id
else: 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: if 'seed' in state:
self.seed = state['seed'] self.seed = state['seed']
if 'student_answers' in state: if 'student_answers' in state:
...@@ -68,7 +76,7 @@ class LoncapaProblem(object): ...@@ -68,7 +76,7 @@ class LoncapaProblem(object):
self.done = state['done'] self.done = state['done']
# TODO: Does this deplete the Linux entropy pool? Is this fast enough? # 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] self.seed=struct.unpack('i', os.urandom(4))[0]
## Parse XML file ## Parse XML file
...@@ -102,7 +110,7 @@ class LoncapaProblem(object): ...@@ -102,7 +110,7 @@ class LoncapaProblem(object):
for key in self.correct_map: for key in self.correct_map:
if self.correct_map[key] == u'correct': if self.correct_map[key] == u'correct':
correct += 1 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, return {'score':0,
'total':self.get_max_score()} 'total':self.get_max_score()}
else: else:
...@@ -132,8 +140,8 @@ class LoncapaProblem(object): ...@@ -132,8 +140,8 @@ class LoncapaProblem(object):
for entry in problems_simple.xpath("//"+"|//".join(response_properties+entry_types)): for entry in problems_simple.xpath("//"+"|//".join(response_properties+entry_types)):
answer = entry.get('correct_answer') answer = entry.get('correct_answer')
if answer != None: if answer:
answer_map[entry.get('id')] = contextualize_text(answer, self.context()) answer_map[entry.get('id')] = contextualize_text(answer, self.context)
return answer_map return answer_map
...@@ -162,7 +170,7 @@ class LoncapaProblem(object): ...@@ -162,7 +170,7 @@ class LoncapaProblem(object):
status = self.correct_map[problemtree.get('id')] status = self.correct_map[problemtree.get('id')]
value = "" 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')] value = self.student_answers[problemtree.get('id')]
return html_special_response[problemtree.tag](problemtree, value, status) #TODO return html_special_response[problemtree.tag](problemtree, value, status) #TODO
...@@ -170,7 +178,7 @@ class LoncapaProblem(object): ...@@ -170,7 +178,7 @@ class LoncapaProblem(object):
tree=Element(problemtree.tag) tree=Element(problemtree.tag)
for item in problemtree: for item in problemtree:
subitems = self.extract_html(item) subitems = self.extract_html(item)
if subitems != None: if subitems:
for subitem in subitems: for subitem in subitems:
tree.append(subitem) tree.append(subitem)
for (key,value) in problemtree.items(): for (key,value) in problemtree.items():
......
from djangomako.shortcuts import render_to_response, render_to_string
from lxml.etree import Element from lxml.etree import Element
from lxml import etree from lxml import etree
from mitxmako.shortcuts import render_to_response, render_to_string
class textline(object): class textline(object):
@staticmethod @staticmethod
def render(element, value, state): def render(element, value, state):
......
import random, numpy, math, scipy, json import json
from util import contextualize_text import math
import numpy
import random
import scipy
from calc import evaluator from calc import evaluator
import random, math
from django.conf import settings from django.conf import settings
from util import contextualize_text
import calc
import eia
# TODO: Should be the same object as in capa_problem # TODO: Should be the same object as in capa_problem
global_context={'random':random, global_context={'random':random,
'numpy':numpy, 'numpy':numpy,
'math':math, 'math':math,
'scipy':scipy} 'scipy':scipy,
'calc':calc,
'eia':eia}
class numericalresponse(object): class numericalresponse(object):
def __init__(self, xml, context): def __init__(self, xml, context):
......
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")
try: import json
import hashlib
import logging
from lxml import etree
try: # This lets us do __name__ == ='__main__'
from django.conf import settings from django.conf import settings
from auth.models import UserProfile from auth.models import UserProfile
except: except:
settings = None settings = None
from lxml import etree
import json
import hashlib
import logging
''' This file will eventually form an abstraction layer between the ''' This file will eventually form an abstraction layer between the
course XML file and the rest of the system. course XML file and the rest of the system.
......
from django.db import models from django.db import models
from django.contrib.auth.models import User 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): class StudentModule(models.Model):
# For a homework problem, contains a JSON # For a homework problem, contains a JSON
# object consisting of state # object consisting of state
......
from django.http import HttpResponse import StringIO
from django.template import Context, loader import json
from djangomako.shortcuts import render_to_response, render_to_string import os
import json, os, sys import sys
from django.core.context_processors import csrf import sys
import urllib
import uuid
from django.db import connection from lxml import etree
from django.template import Context
from django.conf import settings
from django.contrib.auth.models import User from django.contrib.auth.models import User
from auth.models import UserProfile 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.shortcuts import redirect
from django.template import Context
from django.template import Context, loader
from mitxmako.shortcuts import render_to_response, render_to_string
import StringIO from auth.models import UserProfile
from models import StudentModule
import track.views import track.views
from django.http import Http404 import courseware.content_parser as content_parser
import urllib
import courseware.modules.capa_module import courseware.modules.capa_module
import courseware.modules.video_module
import courseware.modules.vertical_module
import courseware.modules.html_module import courseware.modules.html_module
import courseware.modules.schematic_module import courseware.modules.schematic_module
import courseware.modules.seq_module import courseware.modules.seq_module
import courseware.modules.vertical_module
from models import StudentModule import courseware.modules.video_module
import urllib
from django.conf import settings
import courseware.content_parser as content_parser
import sys
import logging
from lxml import etree
import uuid
log = logging.getLogger("mitx.courseware") log = logging.getLogger("mitx.courseware")
...@@ -96,7 +89,7 @@ def modx_dispatch(request, module=None, dispatch=None, id=None): ...@@ -96,7 +89,7 @@ def modx_dispatch(request, module=None, dispatch=None, id=None):
ajax_return=instance.handle_ajax(dispatch, request.POST) ajax_return=instance.handle_ajax(dispatch, request.POST)
# Save the state back to the database # Save the state back to the database
s.state=instance.get_state() s.state=instance.get_state()
if instance.get_score() != None: if not instance.get_score():
s.grade=instance.get_score()['score'] s.grade=instance.get_score()['score']
s.save() s.save()
# Return whatever the module wanted to return to the client/caller # 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): ...@@ -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 "" module_id=xml_module.get('id') #module_class.id_attribute) or ""
# Grab state from database # Grab state from database
s = object_cache(module_object_preload, smod = object_cache(module_object_preload,
user, user,
module_type, module_type,
module_id) module_id)
# s = StudentModule.objects.filter(student=request.user,
# module_id=module_id, if not smod: # If nothing in the database...
# module_type = module_type)
# if len(s) == 0:
# s=None
# else:
# s=s[0]
if s == None: # If nothing in the database...
state=None state=None
else: else:
smod = s
state = smod.state state = smod.state
# Create a new instance # Create a new instance
...@@ -138,7 +123,7 @@ def render_x_module(user, request, xml_module, module_object_preload): ...@@ -138,7 +123,7 @@ def render_x_module(user, request, xml_module, module_object_preload):
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 instance wasn't already in the database, create it
if s == None: if not smod:
smod=StudentModule(student=user, smod=StudentModule(student=user,
module_type = module_type, module_type = module_type,
module_id=module_id, module_id=module_id,
......
import random, numpy, math, scipy, sys, StringIO, os, struct, json import StringIO
from x_module import XModule import datetime
import sys
from courseware.capa.capa_problem import LoncapaProblem
from django.http import Http404
import dateutil import dateutil
import dateutil.parser import dateutil.parser
import datetime import json
import math
import courseware.content_parser as content_parser import numpy
import os
import random
import scipy
import struct
import sys
import traceback
from lxml import etree from lxml import etree
## TODO: Abstract out from Django ## TODO: Abstract out from Django
from django.conf import settings 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): class LoncapaModule(XModule):
''' Interface between capa_problem and x_module. Originally a hack ''' Interface between capa_problem and x_module. Originally a hack
...@@ -231,6 +237,8 @@ class LoncapaModule(XModule): ...@@ -231,6 +237,8 @@ class LoncapaModule(XModule):
for key in get: for key in get:
answers['_'.join(key.split('_')[1:])]=get[key] answers['_'.join(key.split('_')[1:])]=get[key]
print "XXX", answers, get
event_info['answers']=answers event_info['answers']=answers
# Too late. Cannot submit # Too late. Cannot submit
...@@ -255,6 +263,7 @@ class LoncapaModule(XModule): ...@@ -255,6 +263,7 @@ class LoncapaModule(XModule):
correct_map = self.lcp.grade_answers(answers) correct_map = self.lcp.grade_answers(answers)
except: except:
self.lcp = LoncapaProblem(filename, id=lcp_id, state=old_state) self.lcp = LoncapaProblem(filename, id=lcp_id, state=old_state)
traceback.print_exc()
print {'error':sys.exc_info(), print {'error':sys.exc_info(),
'answers':answers, 'answers':answers,
'seed':self.lcp.seed, 'seed':self.lcp.seed,
......
from x_module import XModule
from lxml import etree
import json import json
## TODO: Abstract out from Django ## TODO: Abstract out from Django
from django.conf import settings 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): class HtmlModule(XModule):
id_attribute = 'filename' id_attribute = 'filename'
......
from x_module import XModule
import json import json
## TODO: Abstract out from Django ## TODO: Abstract out from Django
from django.conf import settings 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): class SchematicModule(XModule):
id_attribute = 'id' id_attribute = 'id'
......
from x_module import XModule
from lxml import etree
from django.http import Http404
import json import json
from lxml import etree
## TODO: Abstract out from Django ## TODO: Abstract out from Django
from django.http import Http404
from django.conf import settings 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): class SequentialModule(XModule):
''' Layout module which lays out content in a temporal sequence ''' Layout module which lays out content in a temporal sequence
......
from x_module import XModule
from lxml import etree
import json import json
## TODO: Abstract out from Django ## TODO: Abstract out from Django
from django.conf import settings 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): class VerticalModule(XModule):
id_attribute = 'id' id_attribute = 'id'
......
from x_module import XModule
from lxml import etree
import json import json
import logging
from lxml import etree
## TODO: Abstract out from Django ## TODO: Abstract out from Django
from django.conf import settings 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): class VideoModule(XModule):
#id_attribute = 'youtube' #id_attribute = 'youtube'
video_time = 0 video_time = 0
def handle_ajax(self, dispatch, get): def handle_ajax(self, dispatch, get):
print "GET", get log.debug(u"GET {0}".format(get))
print "DISPATCH", dispatch log.debug(u"DISPATCH {0}".format(dispatch))
if dispatch=='goto_position': if dispatch == 'goto_position':
self.position = int(float(get['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}) return json.dumps({'success':True})
raise Http404() raise Http404()
def get_state(self): def get_state(self):
print "STATE POSITION", self.position log.debug(u"STATE POSITION {0}".format(self.position))
return json.dumps({ 'position':self.position }) return json.dumps({ 'position':self.position })
def get_xml_tags(): 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" return "video"
def video_list(self): def video_list(self):
l=self.youtube.split(',') l = self.youtube.split(',')
l=[i.split(":") for i in l] l = [i.split(":") for i in l]
return json.dumps(dict(l)) return json.dumps(dict(l))
def get_html(self): def get_html(self):
...@@ -39,24 +43,25 @@ class VideoModule(XModule): ...@@ -39,24 +43,25 @@ class VideoModule(XModule):
'position':self.position}) 'position':self.position})
def get_init_js(self): 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 that this may happen several times on the same page
(e.g. student switching tabs). Common functions should be put (e.g. student switching tabs). Common functions should be put
in the main course .js files for now. ''' 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(), return render_to_string('video_init.js',{'streams':self.video_list(),
'id':self.item_id, 'id':self.item_id,
'position':self.position}) 'position':self.position})
def get_destroy_js(self): 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): 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) XModule.__init__(self, xml, item_id, ajax_url, track_url, state, track_function, render_function)
self.youtube = etree.XML(xml).get('youtube') self.youtube = etree.XML(xml).get('youtube')
self.position = 0 self.position = 0
if state!=None: if state != None:
state = json.loads(state) state = json.loads(state)
if 'position' in state: self.position = int(float(state['position'])) if 'position' in state:
print "POOSITION IN STATE" self.position = int(float(state['position']))
print "LOAD POSITION", self.position log.debug("POSITION IN STATE")
log.debug(u"LOAD POSITION {0}".format(self.position))
import courseware.progress
def dummy_track(event_type, event): def dummy_track(event_type, event):
pass pass
...@@ -12,6 +14,9 @@ class XModule(object): ...@@ -12,6 +14,9 @@ class XModule(object):
''' Tags in the courseware file guaranteed to correspond to the module ''' ''' Tags in the courseware file guaranteed to correspond to the module '''
return [] return []
def get_completion(self):
return courseware.progress.completion()
def get_state(self): def get_state(self):
return "" return ""
......
class completion(object): class completion(object):
def __init__(self, d=None): def __init__(self, **d):
self.dict = dict() self.dict = dict({'duration_total':0,
'duration_watched':0,
'done':True,
'questions_correct':0,
'questions_incorrect':0,
'questions_total':0})
if d: if d:
self.dict.update(d) self.dict.update(d)
...@@ -11,9 +16,23 @@ class completion(object): ...@@ -11,9 +16,23 @@ class completion(object):
self.dict[key] = value self.dict[key] = value
def __add__(self, other): def __add__(self, other):
result = dict() result = dict(self.dict)
dict.update(self.dict) for item in ['duration_total',
dict.update(other.dict) 'duration_watched',
'done',
'questions_correct',
'questions_incorrect',
'questions_total']:
result[item] = result[item]+other.dict[item]
return completion(**result)
def __contains__(self, key): 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 ...@@ -12,16 +12,16 @@ from django.contrib.auth.models import User
from django.http import HttpResponse, Http404 from django.http import HttpResponse, Http404
from django.shortcuts import redirect from django.shortcuts import redirect
from django.template import Context, loader 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 django.db import connection
from lxml import etree from lxml import etree
from auth.models import UserProfile from auth.models import UserProfile
from models import StudentModule from models import StudentModule
from module_render import * # TODO: Clean up from module_render import render_module, modx_dispatch
from module_render import modx_dispatch
import courseware.content_parser as content_parser import courseware.content_parser as content_parser
import courseware.modules.capa_module
log = logging.getLogger("mitx.courseware") log = logging.getLogger("mitx.courseware")
...@@ -36,10 +36,6 @@ def profile(request): ...@@ -36,10 +36,6 @@ def profile(request):
if not request.user.is_authenticated(): if not request.user.is_authenticated():
return redirect('/') 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) dom=content_parser.course_file(request.user)
hw=[] hw=[]
course = dom.xpath('//course/@name')[0] course = dom.xpath('//course/@name')[0]
...@@ -146,6 +142,7 @@ def index(request, course="6.002 Spring 2012", chapter="Using the System", secti ...@@ -146,6 +142,7 @@ def index(request, course="6.002 Spring 2012", chapter="Using the System", secti
module_object_preload = list(StudentModule.objects.filter(student=user, module_object_preload = list(StudentModule.objects.filter(student=user,
module_id__in=module_ids)) module_id__in=module_ids))
module=render_module(user, request, module, module_object_preload) module=render_module(user, request, module, module_object_preload)
if 'init_js' not in module: if 'init_js' not in module:
......
================================================================================
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
# 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
# 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
# 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)
# 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)
import views, json, tempfile, time import json
import tempfile
import time
from django.conf import settings from django.conf import settings
from django.db import connection from django.db import connection
import views
class ProfileMiddleware: class ProfileMiddleware:
def process_request (self, request): def process_request (self, request):
......
# Create your views here. # Create your views here.
import middleware import middleware
from django.http import HttpResponse from django.http import HttpResponse
def end_profile(request): def end_profile(request):
......
...@@ -3,12 +3,16 @@ import sys ...@@ -3,12 +3,16 @@ import sys
import djcelery 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 # Our parent dir (mitx_all) is the BASE_DIR
BASE_DIR = os.path.abspath(os.path.join(__file__, "..", "..")) BASE_DIR = os.path.abspath(os.path.join(__file__, "..", ".."))
COURSEWARE_ENABLED = True COURSEWARE_ENABLED = True
ASKBOT_ENABLED = True ASKBOT_ENABLED = True
CSRF_COOKIE_DOMAIN = '127.0.0.1' CSRF_COOKIE_DOMAIN = '127.0.0.1'
# Defaults to be overridden # Defaults to be overridden
...@@ -34,7 +38,7 @@ DEBUG = True ...@@ -34,7 +38,7 @@ DEBUG = True
TEMPLATE_DEBUG = DEBUG TEMPLATE_DEBUG = DEBUG
ADMINS = ( ADMINS = (
('Piotr Mitros', 'pmitros@csail.mit.edu'), ('Piotr Mitros', 'staff@csail.mit.edu'),
) )
MANAGERS = ADMINS MANAGERS = ADMINS
...@@ -56,87 +60,6 @@ USE_I18N = True ...@@ -56,87 +60,6 @@ USE_I18N = True
# calendars according to the current locale # calendars according to the current locale
USE_L10N = True 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/' STATIC_URL = '/static/'
# URL prefix for admin static files -- CSS, JavaScript and images. # URL prefix for admin static files -- CSS, JavaScript and images.
...@@ -166,7 +89,7 @@ MIDDLEWARE_CLASSES = ( ...@@ -166,7 +89,7 @@ MIDDLEWARE_CLASSES = (
'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware', 'django.contrib.messages.middleware.MessageMiddleware',
'track.middleware.TrackMiddleware', 'track.middleware.TrackMiddleware',
'djangomako.middleware.MakoMiddleware', 'mitxmako.middleware.MakoMiddleware',
#'debug_toolbar.middleware.DebugToolbarMiddleware', #'debug_toolbar.middleware.DebugToolbarMiddleware',
) )
...@@ -188,6 +111,7 @@ INSTALLED_APPS = ( ...@@ -188,6 +111,7 @@ INSTALLED_APPS = (
'track', 'track',
'circuit', 'circuit',
'perfstats', 'perfstats',
'util',
# Uncomment the next line to enable the admin: # Uncomment the next line to enable the admin:
# 'django.contrib.admin', # 'django.contrib.admin',
# Uncomment the next line to enable admin documentation: # Uncomment the next line to enable admin documentation:
...@@ -201,9 +125,94 @@ TRACK_MAX_EVENT = 1000 ...@@ -201,9 +125,94 @@ TRACK_MAX_EVENT = 1000
# Maximum length of log file before starting a new one. # Maximum length of log file before starting a new one.
MAXLOG = 500 MAXLOG = 500
LOG_DIR = "/tmp/"
# Make sure we execute correctly regardless of where we're called from # Make sure we execute correctly regardless of where we're called from
execfile(os.path.join(BASE_DIR, "settings.py")) 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 : if PERFSTATS :
MIDDLEWARE_CLASSES = ( 'perfstats.middleware.ProfileMiddleware',) + MIDDLEWARE_CLASSES MIDDLEWARE_CLASSES = ( 'perfstats.middleware.ProfileMiddleware',) + MIDDLEWARE_CLASSES
...@@ -252,6 +261,7 @@ site.addsitedir(os.path.join(os.path.dirname(askbot.__file__), 'deps')) ...@@ -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',) TEMPLATE_LOADERS = TEMPLATE_LOADERS + ('askbot.skins.loaders.filesystem_load_template_source',)
MIDDLEWARE_CLASSES = MIDDLEWARE_CLASSES + ( MIDDLEWARE_CLASSES = MIDDLEWARE_CLASSES + (
'util.middleware.ExceptionLoggingMiddleware',
'askbot.middleware.anon_user.ConnectToSessionMessagesMiddleware', 'askbot.middleware.anon_user.ConnectToSessionMessagesMiddleware',
'askbot.middleware.forum_mode.ForumModeMiddleware', 'askbot.middleware.forum_mode.ForumModeMiddleware',
'askbot.middleware.cancel.CancelActionMiddleware', 'askbot.middleware.cancel.CancelActionMiddleware',
...@@ -312,3 +322,4 @@ BROKER_TRANSPORT = "djkombu.transport.DatabaseTransport" ...@@ -312,3 +322,4 @@ BROKER_TRANSPORT = "djkombu.transport.DatabaseTransport"
CELERY_ALWAYS_EAGER = True CELERY_ALWAYS_EAGER = True
djcelery.setup_loader() djcelery.setup_loader()
...@@ -26,7 +26,7 @@ DEBUG = True ...@@ -26,7 +26,7 @@ DEBUG = True
TEMPLATE_DEBUG = DEBUG TEMPLATE_DEBUG = DEBUG
ADMINS = ( ADMINS = (
('Piotr Mitros', 'pmitros@csail.mit.edu'), ('Piotr Mitros', 'staff@csail.mit.edu'),
) )
MANAGERS = ADMINS MANAGERS = ADMINS
...@@ -81,7 +81,7 @@ MIDDLEWARE_CLASSES = ( ...@@ -81,7 +81,7 @@ MIDDLEWARE_CLASSES = (
'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware', 'django.contrib.messages.middleware.MessageMiddleware',
'track.middleware.TrackMiddleware', 'track.middleware.TrackMiddleware',
'djangomako.middleware.MakoMiddleware', 'mitxmako.middleware.MakoMiddleware',
#'debug_toolbar.middleware.DebugToolbarMiddleware', #'debug_toolbar.middleware.DebugToolbarMiddleware',
) )
......
# Source: django-simplewiki. GPL license. # Source: django-simplewiki. GPL license.
import sys, os import os
import sys
# allow mdx_* parsers to be just dropped in the simplewiki folder # allow mdx_* parsers to be just dropped in the simplewiki folder
module_path = os.path.abspath(os.path.dirname(__file__)) module_path = os.path.abspath(os.path.dirname(__file__))
......
# Source: django-simplewiki. GPL license. # Source: django-simplewiki. GPL license.
from django.contrib import admin
from django import forms from django import forms
from django.contrib import admin
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
from models import Article, Revision, Permission, ArticleAttachment from models import Article, Revision, Permission, ArticleAttachment
class RevisionInline(admin.TabularInline): class RevisionInline(admin.TabularInline):
......
...@@ -8,7 +8,7 @@ circuit:name becomes the circuit. ...@@ -8,7 +8,7 @@ circuit:name becomes the circuit.
import simplewiki.settings as settings 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 import markdown
try: try:
......
from django.utils.translation import ugettext_lazy as _ 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 import models
from django.db.models import signals from django.db.models import signals
from django.contrib.auth.models import User from django.utils.translation import ugettext_lazy as _
from markdown import markdown from markdown import markdown
from django import forms
from django.core.urlresolvers import reverse
import difflib
import os
from settings import * from settings import *
class ShouldHaveExactlyOneRootSlug(Exception): class ShouldHaveExactlyOneRootSlug(Exception):
......
from django import template from django import template
from django.template.defaultfilters import stringfilter
from simplewiki.settings import *
from django.conf import settings from django.conf import settings
from django.template.defaultfilters import stringfilter
from django.utils.http import urlquote as django_urlquote from django.utils.http import urlquote as django_urlquote
from simplewiki.settings import *
register = template.Library() register = template.Library()
@register.filter() @register.filter()
......
...@@ -3,6 +3,7 @@ from django.conf.urls.defaults import * ...@@ -3,6 +3,7 @@ from django.conf.urls.defaults import *
urlpatterns = patterns('', urlpatterns = patterns('',
url(r'^$', 'simplewiki.views.root_redirect', name='wiki_root'), 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(/[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'^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'^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'), url(r'^history(/[a-zA-Z\d/_-]*)/([0-9]*)/?$', 'simplewiki.views.history', name='wiki_history'),
......
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import types import types
from django.conf import settings
from django.contrib.auth.decorators import login_required
from django.core.context_processors import csrf
from django.core.urlresolvers import get_callable 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.core.urlresolvers import reverse
from django.contrib.auth.decorators import login_required
from django.db.models import Q from django.db.models import Q
from django.conf import settings from django.http import Http404, HttpResponse, HttpResponseRedirect, HttpResponseServerError, HttpResponseForbidden, HttpResponseNotAllowed
from django.http import HttpResponse
from django.shortcuts import get_object_or_404
from django.shortcuts import redirect from django.shortcuts import redirect
from django.core.context_processors import csrf
from django.template import Context from django.template import Context
from django.http import HttpResponse from django.template import RequestContext, Context, loader
from django.utils import simplejson
import djangomako.middleware from django.utils.translation import ugettext_lazy as _
from mako.template import Template from mitxmako.shortcuts import render_to_response, render_to_string
from mako.lookup import TemplateLookup 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 * from settings import *
def view(request, wiki_url): def view(request, wiki_url):
...@@ -36,6 +35,7 @@ def view(request, wiki_url): ...@@ -36,6 +35,7 @@ def view(request, wiki_url):
if perm_err: if perm_err:
return perm_err return perm_err
d = {'wiki_article': article, d = {'wiki_article': article,
'wiki_article_revision':article.current_revision,
'wiki_write': article.can_write_l(request.user), 'wiki_write': article.can_write_l(request.user),
'wiki_attachments_write': article.can_attach(request.user), 'wiki_attachments_write': article.can_attach(request.user),
'wiki_current_revision_deleted' : not (article.current_revision.deleted == 0), 'wiki_current_revision_deleted' : not (article.current_revision.deleted == 0),
...@@ -43,6 +43,37 @@ def view(request, wiki_url): ...@@ -43,6 +43,37 @@ def view(request, wiki_url):
d.update(csrf(request)) d.update(csrf(request))
return render_to_response('simplewiki_view.html', d) 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): def root_redirect(request):
if not request.user.is_authenticated(): if not request.user.is_authenticated():
return redirect('/') return redirect('/')
...@@ -206,12 +237,18 @@ def history(request, wiki_url, page=1): ...@@ -206,12 +237,18 @@ def history(request, wiki_url, page=1):
perm_err = check_permissions(request, article, check_write=True, check_locked=True) perm_err = check_permissions(request, article, check_write=True, check_locked=True)
if perm_err: if perm_err:
return perm_err return perm_err
redirectURL = reverse('wiki_view', args=(article.get_url(),))
try: try:
r = int(request.POST['revision']) r = int(request.POST['revision'])
revision = Revision.objects.get(id=r) revision = Revision.objects.get(id=r)
if request.POST.__contains__('change'): if request.POST.__contains__('change'):
article.current_revision = revision article.current_revision = revision
article.save() 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: elif request.POST.__contains__('delete') and request.user.is_superuser:
if (revision.deleted == 0): if (revision.deleted == 0):
revision.adminSetDeleted(2) revision.adminSetDeleted(2)
...@@ -228,7 +265,7 @@ def history(request, wiki_url, page=1): ...@@ -228,7 +265,7 @@ def history(request, wiki_url, page=1):
except: except:
pass pass
finally: finally:
return HttpResponseRedirect(reverse('wiki_view', args=(article.get_url(),))) return HttpResponseRedirect(redirectURL)
# #
# #
# <input type="submit" name="delete" value="Delete revision"/> # <input type="submit" name="delete" value="Delete revision"/>
...@@ -433,14 +470,16 @@ def fetch_from_url(request, url): ...@@ -433,14 +470,16 @@ def fetch_from_url(request, url):
return (article, path, err) 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) read_err = check_read and not article.can_read(request.user)
write_err = check_write and not article.can_write(request.user) write_err = check_write and not article.can_write(request.user)
locked_err = check_locked and article.locked 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): if (request.user.is_superuser):
deleted_err = False deleted_err = False
locked_err = False locked_err = False
......
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.http import HttpResponse, HttpResponseRedirect, HttpResponseForbidden, Http404
from django.template import loader, Context 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 models import Article, ArticleAttachment, get_attachment_filepath
from views import not_found, check_permissions, get_url_path, fetch_from_url from views import not_found, check_permissions, get_url_path, fetch_from_url
import os
from simplewiki.settings import WIKI_ALLOW_ANON_ATTACHMENTS from simplewiki.settings import WIKI_ALLOW_ANON_ATTACHMENTS
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
# List of valid templates is explicitly managed for (short-term) # List of valid templates is explicitly managed for (short-term)
# security reasons. # 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.shortcuts import redirect
from django.core.context_processors import csrf from django.core.context_processors import csrf
......
# Create your views here. # Create your views here.
from djangomako.shortcuts import render_to_response, render_to_string
from django.shortcuts import redirect
import os import os
from django.conf import settings from django.conf import settings
from django.http import Http404 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(): if not request.user.is_authenticated():
return redirect('/') return redirect('/')
return render_to_response('staticbook.html',{'page':int(page)}) return render_to_response('staticbook.html',{'page':int(page)})
def index_shifted(request, page):
return index(request, int(page)+24)
import views, json import json
from django.conf import settings
import views
class TrackMiddleware: class TrackMiddleware:
def process_request (self, request): def process_request(self, request):
try: try:
# We're already logging events # We're already logging events, and we don't want to capture user
if request.META['PATH_INFO'] == '/event': # names/passwords.
if request.META['PATH_INFO'] in ['/event', '/login']:
return return
event = { 'GET' : dict(request.GET), event = { 'GET' : dict(request.GET),
......
import json
import logging
import os
# Create your views here. # Create your views here.
from django.http import HttpResponse from django.http import HttpResponse
from django.http import Http404 from django.http import Http404
from django.conf import settings 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(): log = logging.getLogger("tracking")
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
def log_event(event): def log_event(event):
global logfile, log_index
event_str = json.dumps(event) event_str = json.dumps(event)
if settings.TRACK_DIR == None: log.info(event_str[:settings.TRACK_MAX_EVENT])
# 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
def user_track(request): def user_track(request):
try: # TODO: Do the same for many of the optional META parameters try: # TODO: Do the same for many of the optional META parameters
...@@ -49,15 +19,25 @@ def user_track(request): ...@@ -49,15 +19,25 @@ def user_track(request):
except: except:
username = "anonymous" 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 # TODO: Move a bunch of this into log_event
event = { event = {
"username" : username, "username" : username,
"session" : request.META['HTTP_COOKIE'], "session" : scookie,
"ip" : request.META['REMOTE_ADDR'], "ip" : request.META['REMOTE_ADDR'],
"event_source" : "browser", "event_source" : "browser",
"event_type" : request.GET['event_type'], "event_type" : request.GET['event_type'],
"event" : request.GET['event'], "event" : request.GET['event'],
"agent" : request.META['HTTP_USER_AGENT'], "agent" : agent,
"page" : request.GET['page'], "page" : request.GET['page'],
} }
log_event(event) log_event(event)
...@@ -69,13 +49,18 @@ def server_track(request, event_type, event, page=None): ...@@ -69,13 +49,18 @@ def server_track(request, event_type, event, page=None):
except: except:
username = "anonymous" username = "anonymous"
try:
agent = request.META['HTTP_USER_AGENT']
except:
agent = ''
event = { event = {
"username" : username, "username" : username,
"ip" : request.META['REMOTE_ADDR'], "ip" : request.META['REMOTE_ADDR'],
"event_source" : "server", "event_source" : "server",
"event_type" : event_type, "event_type" : event_type,
"event" : event, "event" : event,
"agent" : request.META['HTTP_USER_AGENT'], "agent" : agent,
"page" : page, "page" : page,
} }
log_event(event) log_event(event)
from django.conf.urls.defaults import patterns, include, url
import django.contrib.auth.views
from django.conf import settings from django.conf import settings
from django.conf.urls.defaults import patterns, include, url
from django.contrib import admin from django.contrib import admin
import perfstats import django.contrib.auth.views
# Uncomment the next two lines to enable the admin: # Uncomment the next two lines to enable the admin:
# from django.contrib import admin # from django.contrib import admin
...@@ -19,7 +18,7 @@ urlpatterns = ('', ...@@ -19,7 +18,7 @@ urlpatterns = ('',
url(r'^activate/(?P<key>[^/]*)$', 'auth.views.activate_account'), url(r'^activate/(?P<key>[^/]*)$', 'auth.views.activate_account'),
url(r'^$', 'auth.views.index'), url(r'^$', 'auth.views.index'),
url(r'^password_reset/$', 'django.contrib.auth.views.password_reset', 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/$',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_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, 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 = ('', ...@@ -29,14 +28,14 @@ urlpatterns = ('',
url(r'^password_reset_done/$',django.contrib.auth.views.password_reset_done, url(r'^password_reset_done/$',django.contrib.auth.views.password_reset_done,
name='auth_password_reset_done'), name='auth_password_reset_done'),
url(r'^send_feedback$', 'util.views.send_feedback'), url(r'^send_feedback$', 'util.views.send_feedback'),
url(r'^courseware/$', 'courseware.views.index'),
) )
if settings.PERFSTATS: if settings.PERFSTATS:
urlpatterns=urlpatterns + (url(r'^reprofile$','perfstats.views.end_profile'),) urlpatterns=urlpatterns + (url(r'^reprofile$','perfstats.views.end_profile'),)
if settings.COURSEWARE_ENABLED: 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>[^/]*)/(?P<section>[^/]*)/$', 'courseware.views.index'),
url(r'^courseware/(?P<course>[^/]*)/(?P<chapter>[^/]*)/$', 'courseware.views.index'), url(r'^courseware/(?P<course>[^/]*)/(?P<chapter>[^/]*)/$', 'courseware.views.index'),
url(r'^courseware/(?P<course>[^/]*)/$', 'courseware.views.index'), url(r'^courseware/(?P<course>[^/]*)/$', 'courseware.views.index'),
...@@ -45,6 +44,7 @@ if settings.COURSEWARE_ENABLED: ...@@ -45,6 +44,7 @@ if settings.COURSEWARE_ENABLED:
url(r'^change_setting$', 'auth.views.change_setting'), url(r'^change_setting$', 'auth.views.change_setting'),
url(r'^s/(?P<template>[^/]*)$', 'static_template_view.views.auth_index'), url(r'^s/(?P<template>[^/]*)$', 'static_template_view.views.auth_index'),
url(r'^book/(?P<page>[^/]*)$', 'staticbook.views.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'^book*$', 'staticbook.views.index'),
# url(r'^course_info/$', 'auth.views.courseinfo'), # url(r'^course_info/$', 'auth.views.courseinfo'),
# url(r'^show_circuit/(?P<circuit>[^/]*)$', 'circuit.views.show_circuit'), # url(r'^show_circuit/(?P<circuit>[^/]*)$', 'circuit.views.show_circuit'),
......
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.")
from djangomako.shortcuts import render_to_response, render_to_string import datetime
from django.shortcuts import redirect
from django.contrib.auth.models import User
from django.http import HttpResponse
import json import json
import sys
from django.conf import settings 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.context_processors import csrf
from django.core.mail import send_mail
from django.http import Http404 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 courseware.capa.calc
from django.core.mail import send_mail
from django.conf import settings
import datetime
import sys
import track.views import track.views
def calculate(request): def calculate(request):
# if not request.user.is_authenticated(): ''' Calculator in footer of every page. '''
# raise Http404
equation = request.GET['equation'] equation = request.GET['equation']
try: try:
result = courseware.capa.calc.evaluator({}, {}, equation) result = courseware.capa.calc.evaluator({}, {}, equation)
...@@ -27,8 +28,7 @@ def calculate(request): ...@@ -27,8 +28,7 @@ def calculate(request):
return HttpResponse(json.dumps({'result':result})) return HttpResponse(json.dumps({'result':result}))
def send_feedback(request): def send_feedback(request):
# if not request.user.is_authenticated(): ''' Feeback mechanism in footer of every page. '''
# raise Http404
try: try:
username = request.user.username username = request.user.username
except: except:
...@@ -50,4 +50,5 @@ def send_feedback(request): ...@@ -50,4 +50,5 @@ def send_feedback(request):
return HttpResponse(json.dumps({'success':True})) return HttpResponse(json.dumps({'success':True}))
def info(request): def info(request):
''' Info page (link from main header) '''
return render_to_response("info.html", {}) return render_to_response("info.html", {})
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment