Merge in default
--HG-- branch : bridger-dev
This commit is contained in:
@@ -1,14 +1,17 @@
|
||||
import copy
|
||||
import logging
|
||||
import math
|
||||
import operator
|
||||
import re
|
||||
|
||||
import numpy
|
||||
import scipy.constants
|
||||
|
||||
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
|
||||
from pyparsing import NoMatch, stringEnd, alphanums
|
||||
|
||||
default_functions = {'sin' : numpy.sin,
|
||||
'cos' : numpy.cos,
|
||||
@@ -23,19 +26,75 @@ default_functions = {'sin' : numpy.sin,
|
||||
'abs':numpy.abs
|
||||
}
|
||||
default_variables = {'j':numpy.complex(0,1),
|
||||
'e':numpy.complex(numpy.e)
|
||||
'e':numpy.e,
|
||||
'pi':numpy.pi,
|
||||
'k':scipy.constants.k,
|
||||
'c':scipy.constants.c,
|
||||
'T':298.15,
|
||||
'q':scipy.constants.e
|
||||
}
|
||||
|
||||
log = logging.getLogger("mitx.courseware.capa")
|
||||
|
||||
def evaluator(variables, functions, string):
|
||||
class UndefinedVariable(Exception):
|
||||
def raiseself(self):
|
||||
''' Helper so we can use inside of a lambda '''
|
||||
raise self
|
||||
|
||||
|
||||
general_whitespace = re.compile('[^\w]+')
|
||||
def check_variables(string, variables):
|
||||
''' Confirm the only variables in string are defined.
|
||||
|
||||
Pyparsing uses a left-to-right parser, which makes the more
|
||||
elegant approach pretty hopeless.
|
||||
|
||||
achar = reduce(lambda a,b:a|b ,map(Literal,alphas)) # Any alphabetic character
|
||||
undefined_variable = achar + Word(alphanums)
|
||||
undefined_variable.setParseAction(lambda x:UndefinedVariable("".join(x)).raiseself())
|
||||
varnames = varnames | undefined_variable'''
|
||||
possible_variables = re.split(general_whitespace, string) # List of all alnums in string
|
||||
bad_variables = list()
|
||||
for v in possible_variables:
|
||||
if len(v) == 0:
|
||||
continue
|
||||
if v[0] <= '9' and '0' <= 'v': # Skip things that begin with numbers
|
||||
continue
|
||||
if v not in variables:
|
||||
bad_variables.append(v)
|
||||
if len(bad_variables)>0:
|
||||
raise UndefinedVariable(' '.join(bad_variables))
|
||||
|
||||
def evaluator(variables, functions, string, cs=False):
|
||||
''' Evaluate an expression. Variables are passed as a dictionary
|
||||
from string to value. Unary functions are passed as a dictionary
|
||||
from string to function '''
|
||||
from string to function. Variables must be floats.
|
||||
cs: Case sensitive
|
||||
|
||||
TODO: Fix it so we can pass integers and complex numbers in variables dict
|
||||
'''
|
||||
# log.debug("variables: {0}".format(variables))
|
||||
# log.debug("functions: {0}".format(functions))
|
||||
# log.debug("string: {0}".format(string))
|
||||
|
||||
all_variables = copy.copy(default_variables)
|
||||
all_variables.update(variables)
|
||||
all_functions = copy.copy(default_functions)
|
||||
all_functions.update(functions)
|
||||
|
||||
if not cs:
|
||||
string_cs = string.lower()
|
||||
for v in all_variables.keys():
|
||||
all_variables[v.lower()]=all_variables[v]
|
||||
for f in all_functions.keys():
|
||||
all_functions[f.lower()]=all_functions[f]
|
||||
CasedLiteral = CaselessLiteral
|
||||
else:
|
||||
string_cs = string
|
||||
CasedLiteral = Literal
|
||||
|
||||
check_variables(string_cs, set(all_variables.keys()+all_functions.keys()))
|
||||
|
||||
if string.strip() == "":
|
||||
return float('nan')
|
||||
ops = { "^" : operator.pow,
|
||||
@@ -119,19 +178,22 @@ def evaluator(variables, functions, string):
|
||||
# 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(all_variables)>0:
|
||||
varnames = sreduce(lambda x,y:x|y, map(lambda x: CaselessLiteral(x), all_variables.keys()))
|
||||
# We sort the list so that var names (like "e2") match before
|
||||
# mathematical constants (like "e"). This is kind of a hack.
|
||||
all_variables_keys = sorted(all_variables.keys(), key=len, reverse=True)
|
||||
varnames = sreduce(lambda x,y:x|y, map(lambda x: CasedLiteral(x), all_variables_keys))
|
||||
varnames.setParseAction(lambda x:map(lambda y:all_variables[y], x))
|
||||
else:
|
||||
varnames=NoMatch()
|
||||
# Same thing for functions.
|
||||
if len(all_functions)>0:
|
||||
funcnames = sreduce(lambda x,y:x|y, map(lambda x: CaselessLiteral(x), all_functions.keys()))
|
||||
funcnames = sreduce(lambda x,y:x|y, map(lambda x: CasedLiteral(x), all_functions.keys()))
|
||||
function = funcnames+lpar.suppress()+expr+rpar.suppress()
|
||||
function.setParseAction(func_parse_action)
|
||||
else:
|
||||
function = NoMatch()
|
||||
|
||||
atom = number | varnames | lpar+expr+rpar | function
|
||||
atom = number | function | varnames | lpar+expr+rpar
|
||||
factor << (atom + ZeroOrMore(exp+atom)).setParseAction(exp_parse_action) # 7^6
|
||||
paritem = factor + ZeroOrMore(Literal('||')+factor) # 5k || 4k
|
||||
paritem=paritem.setParseAction(parallel)
|
||||
@@ -147,7 +209,9 @@ if __name__=='__main__':
|
||||
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({'e1':1,'e2':1.0,'R3':7,'V0':5,'R5':15,'I1':1,'R4':6}, {},"e2")
|
||||
|
||||
print evaluator({'a': 2.2997471478310274, 'k': 9, 'm': 8, 'x': 0.66009498411213041}, {}, "5")
|
||||
print evaluator({},{}, "-1")
|
||||
print evaluator({},{}, "-(7+5)")
|
||||
|
||||
@@ -15,7 +15,7 @@ from mako.template import Template
|
||||
|
||||
from util import contextualize_text
|
||||
from inputtypes import textline, schematic
|
||||
from responsetypes import numericalresponse, formularesponse, customresponse, schematicresponse
|
||||
from responsetypes import numericalresponse, formularesponse, customresponse, schematicresponse, StudentInputError
|
||||
|
||||
import calc
|
||||
import eia
|
||||
@@ -53,7 +53,7 @@ html_special_response = {"textline":textline.render,
|
||||
"schematic":schematic.render}
|
||||
|
||||
class LoncapaProblem(object):
|
||||
def __init__(self, filename, id=None, state=None):
|
||||
def __init__(self, filename, id=None, state=None, seed=None):
|
||||
## Initialize class variables from state
|
||||
self.seed = None
|
||||
self.student_answers = dict()
|
||||
@@ -61,6 +61,9 @@ class LoncapaProblem(object):
|
||||
self.done = False
|
||||
self.filename = filename
|
||||
|
||||
if seed != None:
|
||||
self.seed = seed
|
||||
|
||||
if id:
|
||||
self.problem_id = id
|
||||
else:
|
||||
@@ -78,10 +81,14 @@ class LoncapaProblem(object):
|
||||
if 'done' in state:
|
||||
self.done = state['done']
|
||||
|
||||
# print self.seed
|
||||
|
||||
# TODO: Does this deplete the Linux entropy pool? Is this fast enough?
|
||||
if not self.seed:
|
||||
self.seed=struct.unpack('i', os.urandom(4))[0]
|
||||
|
||||
# print filename, self.seed, seed
|
||||
|
||||
## Parse XML file
|
||||
#log.debug(u"LoncapaProblem() opening file {0}".format(filename))
|
||||
file_text = open(filename).read()
|
||||
|
||||
@@ -3,8 +3,9 @@ import math
|
||||
import numpy
|
||||
import random
|
||||
import scipy
|
||||
import traceback
|
||||
|
||||
from calc import evaluator
|
||||
from calc import evaluator, UndefinedVariable
|
||||
from django.conf import settings
|
||||
from util import contextualize_text
|
||||
|
||||
@@ -19,24 +20,36 @@ global_context={'random':random,
|
||||
'calc':calc,
|
||||
'eia':eia}
|
||||
|
||||
|
||||
def compare_with_tolerance(v1, v2, tol):
|
||||
''' Compare v1 to v2 with maximum tolerance tol
|
||||
tol is relative if it ends in %; otherwise, it is absolute
|
||||
'''
|
||||
relative = "%" in tol
|
||||
if relative:
|
||||
tolerance_rel = evaluator(dict(),dict(),tol[:-1]) * 0.01
|
||||
tolerance = tolerance_rel * max(abs(v1), abs(v2))
|
||||
else:
|
||||
tolerance = evaluator(dict(),dict(),tol)
|
||||
return abs(v1-v2) <= tolerance
|
||||
|
||||
class numericalresponse(object):
|
||||
def __init__(self, xml, context):
|
||||
self.xml = xml
|
||||
self.correct_answer = contextualize_text(xml.get('answer'), context)
|
||||
self.correct_answer = float(self.correct_answer)
|
||||
self.tolerance = xml.xpath('//*[@id=$id]//responseparam[@type="tolerance"]/@default',
|
||||
self.tolerance_xml = xml.xpath('//*[@id=$id]//responseparam[@type="tolerance"]/@default',
|
||||
id=xml.get('id'))[0]
|
||||
self.tolerance = contextualize_text(self.tolerance, context)
|
||||
self.tolerance = evaluator(dict(),dict(),self.tolerance)
|
||||
self.tolerance = contextualize_text(self.tolerance_xml, context)
|
||||
self.answer_id = xml.xpath('//*[@id=$id]//textline/@id',
|
||||
id=xml.get('id'))[0]
|
||||
|
||||
def grade(self, student_answers):
|
||||
''' Display HTML for a numeric response '''
|
||||
student_answer = student_answers[self.answer_id]
|
||||
error = abs(evaluator(dict(),dict(),student_answer) - self.correct_answer)
|
||||
allowed_error = abs(self.correct_answer*self.tolerance)
|
||||
if error <= allowed_error:
|
||||
correct = compare_with_tolerance (evaluator(dict(),dict(),student_answer), self.correct_answer, self.tolerance)
|
||||
|
||||
if correct:
|
||||
return {self.answer_id:'correct'}
|
||||
else:
|
||||
return {self.answer_id:'incorrect'}
|
||||
@@ -72,18 +85,31 @@ class customresponse(object):
|
||||
# be handled by capa_problem
|
||||
return {}
|
||||
|
||||
class StudentInputError(Exception):
|
||||
pass
|
||||
|
||||
class formularesponse(object):
|
||||
def __init__(self, xml, context):
|
||||
self.xml = xml
|
||||
self.correct_answer = contextualize_text(xml.get('answer'), context)
|
||||
self.samples = contextualize_text(xml.get('samples'), context)
|
||||
self.tolerance = xml.xpath('//*[@id=$id]//responseparam[@type="tolerance"]/@default',
|
||||
self.tolerance_xml = xml.xpath('//*[@id=$id]//responseparam[@type="tolerance"]/@default',
|
||||
id=xml.get('id'))[0]
|
||||
self.tolerance = contextualize_text(self.tolerance, context)
|
||||
self.tolerance = evaluator(dict(),dict(),self.tolerance)
|
||||
self.tolerance = contextualize_text(self.tolerance_xml, context)
|
||||
self.answer_id = xml.xpath('//*[@id=$id]//textline/@id',
|
||||
id=xml.get('id'))[0]
|
||||
self.context = context
|
||||
ts = xml.get('type')
|
||||
if ts == None:
|
||||
typeslist = []
|
||||
else:
|
||||
typeslist = ts.split(',')
|
||||
if 'ci' in typeslist: # Case insensitive
|
||||
self.case_sensitive = False
|
||||
elif 'cs' in typeslist: # Case sensitive
|
||||
self.case_sensitive = True
|
||||
else: # Default
|
||||
self.case_sensitive = False
|
||||
|
||||
|
||||
def grade(self, student_answers):
|
||||
@@ -102,10 +128,19 @@ class formularesponse(object):
|
||||
instructor_variables[str(var)] = value
|
||||
student_variables[str(var)] = value
|
||||
instructor_result = evaluator(instructor_variables,dict(),self.correct_answer)
|
||||
student_result = evaluator(student_variables,dict(),student_answers[self.answer_id])
|
||||
try:
|
||||
#print student_variables,dict(),student_answers[self.answer_id]
|
||||
student_result = evaluator(student_variables,dict(),
|
||||
student_answers[self.answer_id],
|
||||
cs = self.case_sensitive)
|
||||
except UndefinedVariable as uv:
|
||||
raise StudentInputError('Undefined: '+uv.message)
|
||||
except:
|
||||
#traceback.print_exc()
|
||||
raise StudentInputError("Syntax Error")
|
||||
if math.isnan(student_result) or math.isinf(student_result):
|
||||
return {self.answer_id:"incorrect"}
|
||||
if abs( student_result - instructor_result ) > self.tolerance:
|
||||
if not compare_with_tolerance(student_result, instructor_result, self.tolerance):
|
||||
return {self.answer_id:"incorrect"}
|
||||
|
||||
return {self.answer_id:"correct"}
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
import hashlib
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
|
||||
from datetime import timedelta
|
||||
from lxml import etree
|
||||
from mako.template import Template
|
||||
from mako.lookup import TemplateLookup
|
||||
|
||||
try: # This lets us do __name__ == ='__main__'
|
||||
from django.conf import settings
|
||||
from student.models import UserProfile
|
||||
from student.models import UserTestGroup
|
||||
from mitxmako.shortcuts import render_to_response, render_to_string
|
||||
except:
|
||||
settings = None
|
||||
|
||||
@@ -49,7 +50,7 @@ def xpath(xml, query_string, **args):
|
||||
We should remove this with the move to lxml.
|
||||
We should also use lxml argument passing. '''
|
||||
doc = etree.fromstring(xml)
|
||||
print type(doc)
|
||||
#print type(doc)
|
||||
def escape(x):
|
||||
# TODO: This should escape the string. For now, we just assume it's made of valid characters.
|
||||
# Couldn't figure out how to escape for lxml in a few quick Googles
|
||||
@@ -60,7 +61,7 @@ def xpath(xml, query_string, **args):
|
||||
return x
|
||||
|
||||
args=dict( ((k, escape(args[k])) for k in args) )
|
||||
print args
|
||||
#print args
|
||||
results = doc.xpath(query_string.format(**args))
|
||||
return results
|
||||
|
||||
@@ -86,14 +87,20 @@ def item(l, default="", process=lambda x:x):
|
||||
|
||||
def id_tag(course):
|
||||
''' Tag all course elements with unique IDs '''
|
||||
default_ids = {'video':'youtube',
|
||||
old_ids = {'video':'youtube',
|
||||
'problem':'filename',
|
||||
'sequential':'id',
|
||||
'html':'filename',
|
||||
'vertical':'id',
|
||||
'tab':'id',
|
||||
'schematic':'id'}
|
||||
|
||||
'schematic':'id',
|
||||
'book' : 'id'}
|
||||
import courseware.modules
|
||||
default_ids = courseware.modules.get_default_ids()
|
||||
|
||||
#print default_ids, old_ids
|
||||
#print default_ids == old_ids
|
||||
|
||||
# Tag elements with unique IDs
|
||||
elements = course.xpath("|".join(['//'+c for c in default_ids]))
|
||||
for elem in elements:
|
||||
@@ -135,23 +142,51 @@ def propogate_downward_tag(element, attribute_name, parent_attribute = None):
|
||||
#to its children later.
|
||||
return
|
||||
|
||||
template_lookup = TemplateLookup(directories = [settings.DATA_DIR],
|
||||
module_directory = settings.MAKO_MODULE_DIR)
|
||||
def user_groups(user):
|
||||
# TODO: Rewrite in Django
|
||||
return [u.name for u in UserTestGroup.objects.raw("select * from auth_user, student_usertestgroup, student_usertestgroup_users where auth_user.id = student_usertestgroup_users.user_id and student_usertestgroup_users.usertestgroup_id = student_usertestgroup.id and auth_user.id = %s", [user.id])]
|
||||
|
||||
def course_file(user):
|
||||
# TODO: Cache.
|
||||
filename = UserProfile.objects.get(user=user).courseware
|
||||
data_template = template_lookup.get_template(filename)
|
||||
|
||||
options = {'dev_content':True}
|
||||
|
||||
tree = etree.XML(data_template.render(**options))
|
||||
def course_xml_process(tree):
|
||||
''' Do basic pre-processing of an XML tree. Assign IDs to all
|
||||
items without. Propagate due dates, grace periods, etc. to child
|
||||
items.
|
||||
'''
|
||||
id_tag(tree)
|
||||
propogate_downward_tag(tree, "due")
|
||||
propogate_downward_tag(tree, "graded")
|
||||
propogate_downward_tag(tree, "graceperiod")
|
||||
return tree
|
||||
|
||||
def course_file(user):
|
||||
''' Given a user, return course.xml
|
||||
'''
|
||||
# TODO: Cache.
|
||||
filename = UserProfile.objects.get(user=user).courseware
|
||||
|
||||
groups = user_groups(user)
|
||||
|
||||
options = {'dev_content':settings.DEV_CONTENT,
|
||||
'groups' : groups}
|
||||
|
||||
tree = course_xml_process(etree.XML(render_to_string(filename, options, namespace = 'course')))
|
||||
return tree
|
||||
|
||||
def section_file(user, section):
|
||||
''' Given a user and the name of a section, return that section
|
||||
'''
|
||||
filename = section+".xml"
|
||||
|
||||
if filename not in os.listdir(settings.DATA_DIR + '/sections/'):
|
||||
print filename+" not in "+str(os.listdir(settings.DATA_DIR + '/sections/'))
|
||||
return None
|
||||
|
||||
options = {'dev_content':settings.DEV_CONTENT,
|
||||
'groups' : user_groups(user)}
|
||||
|
||||
tree = course_xml_process(etree.XML(render_to_string(filename, options, namespace = 'sections')))
|
||||
return tree
|
||||
|
||||
|
||||
def module_xml(coursefile, module, id_tag, module_id):
|
||||
''' Get XML for a module based on module and module_id. Assumes
|
||||
module occurs once in courseware XML file.. '''
|
||||
|
||||
@@ -8,6 +8,7 @@ from django.contrib.auth.models import User
|
||||
|
||||
from mitx.courseware.content_parser import course_file
|
||||
import mitx.courseware.module_render
|
||||
import mitx.courseware.modules
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = "Does basic validity tests on course.xml."
|
||||
@@ -24,7 +25,7 @@ class Command(BaseCommand):
|
||||
check = False
|
||||
print "Confirming all modules render. Nothing should print during this step. "
|
||||
for module in course.xpath('//problem|//html|//video|//vertical|//sequential|/tab'):
|
||||
module_class=mitx.courseware.module_render.modx_modules[module.tag]
|
||||
module_class=mitx.courseware.modules.modx_modules[module.tag]
|
||||
# TODO: Abstract this out in render_module.py
|
||||
try:
|
||||
instance=module_class(etree.tostring(module),
|
||||
@@ -41,6 +42,7 @@ class Command(BaseCommand):
|
||||
if os.path.exists(sections_dir):
|
||||
print "Checking all section includes are valid XML"
|
||||
for f in os.listdir(sections_dir):
|
||||
print f
|
||||
etree.parse(sections_dir+'/'+f)
|
||||
else:
|
||||
print "Skipping check of include files -- no section includes dir ("+sections_dir+")"
|
||||
|
||||
116
courseware/migrations/0003_done_grade_cache.py
Normal file
116
courseware/migrations/0003_done_grade_cache.py
Normal file
@@ -0,0 +1,116 @@
|
||||
# encoding: utf-8
|
||||
import datetime
|
||||
from south.db import db
|
||||
from south.v2 import SchemaMigration
|
||||
from django.db import models
|
||||
|
||||
class Migration(SchemaMigration):
|
||||
|
||||
def forwards(self, orm):
|
||||
|
||||
# Removing unique constraint on 'StudentModule', fields ['module_id', 'module_type', 'student']
|
||||
db.delete_unique('courseware_studentmodule', ['module_id', 'module_type', 'student_id'])
|
||||
|
||||
# Adding field 'StudentModule.max_grade'
|
||||
db.add_column('courseware_studentmodule', 'max_grade', self.gf('django.db.models.fields.FloatField')(null=True, blank=True), keep_default=False)
|
||||
|
||||
# Adding field 'StudentModule.done'
|
||||
db.add_column('courseware_studentmodule', 'done', self.gf('django.db.models.fields.CharField')(default='na', max_length=8, db_index=True), keep_default=False)
|
||||
|
||||
# Adding unique constraint on 'StudentModule', fields ['module_id', 'student']
|
||||
db.create_unique('courseware_studentmodule', ['module_id', 'student_id'])
|
||||
|
||||
|
||||
def backwards(self, orm):
|
||||
|
||||
# Removing unique constraint on 'StudentModule', fields ['module_id', 'student']
|
||||
db.delete_unique('courseware_studentmodule', ['module_id', 'student_id'])
|
||||
|
||||
# Deleting field 'StudentModule.max_grade'
|
||||
db.delete_column('courseware_studentmodule', 'max_grade')
|
||||
|
||||
# Deleting field 'StudentModule.done'
|
||||
db.delete_column('courseware_studentmodule', 'done')
|
||||
|
||||
# Adding unique constraint on 'StudentModule', fields ['module_id', 'module_type', 'student']
|
||||
db.create_unique('courseware_studentmodule', ['module_id', 'module_type', 'student_id'])
|
||||
|
||||
|
||||
models = {
|
||||
'auth.group': {
|
||||
'Meta': {'object_name': 'Group'},
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
|
||||
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
|
||||
},
|
||||
'auth.permission': {
|
||||
'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
|
||||
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
|
||||
},
|
||||
'auth.user': {
|
||||
'Meta': {'object_name': 'User'},
|
||||
'about': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'avatar_type': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '1'}),
|
||||
'bronze': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
|
||||
'consecutive_days_visit_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'country': ('django_countries.fields.CountryField', [], {'max_length': '2', 'blank': 'True'}),
|
||||
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'date_of_birth': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'display_tag_filter_strategy': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
|
||||
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
|
||||
'email_isvalid': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'email_key': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),
|
||||
'email_tag_filter_strategy': ('django.db.models.fields.SmallIntegerField', [], {'default': '1'}),
|
||||
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'gold': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
|
||||
'gravatar': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
|
||||
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'ignored_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'interesting_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'last_seen': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'location': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
|
||||
'new_response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
|
||||
'questions_per_page': ('django.db.models.fields.SmallIntegerField', [], {'default': '10'}),
|
||||
'real_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
|
||||
'reputation': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}),
|
||||
'seen_response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'show_country': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'silver': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
|
||||
'status': ('django.db.models.fields.CharField', [], {'default': "'w'", 'max_length': '2'}),
|
||||
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}),
|
||||
'website': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'})
|
||||
},
|
||||
'contenttypes.contenttype': {
|
||||
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
|
||||
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
|
||||
},
|
||||
'courseware.studentmodule': {
|
||||
'Meta': {'unique_together': "(('student', 'module_id'),)", 'object_name': 'StudentModule'},
|
||||
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'db_index': 'True', 'blank': 'True'}),
|
||||
'done': ('django.db.models.fields.CharField', [], {'default': "'na'", 'max_length': '8', 'db_index': 'True'}),
|
||||
'grade': ('django.db.models.fields.FloatField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'max_grade': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'modified': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'db_index': 'True', 'blank': 'True'}),
|
||||
'module_id': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
|
||||
'module_type': ('django.db.models.fields.CharField', [], {'default': "'problem'", 'max_length': '32', 'db_index': 'True'}),
|
||||
'state': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'student': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['courseware']
|
||||
@@ -31,8 +31,13 @@ class StudentModule(models.Model):
|
||||
|
||||
## Grade, and are we done?
|
||||
grade = models.FloatField(null=True, blank=True, db_index=True)
|
||||
#max_grade = models.FloatField(null=True, blank=True)
|
||||
|
||||
max_grade = models.FloatField(null=True, blank=True)
|
||||
DONE_TYPES = (('na','NOT_APPLICABLE'),
|
||||
('f','FINISHED'),
|
||||
('i','INCOMPLETE'),
|
||||
)
|
||||
done = models.CharField(max_length=8, choices=DONE_TYPES, default='na', db_index=True)
|
||||
|
||||
# DONE_TYPES = (('done','DONE'), # Finished
|
||||
# ('incomplete','NOTDONE'), # Not finished
|
||||
# ('na','NA')) # Not applicable (e.g. vertical)
|
||||
|
||||
@@ -26,24 +26,10 @@ import track.views
|
||||
|
||||
import courseware.content_parser as content_parser
|
||||
|
||||
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
|
||||
import courseware.modules
|
||||
|
||||
log = logging.getLogger("mitx.courseware")
|
||||
|
||||
## TODO: Add registration mechanism
|
||||
modx_modules={'problem':courseware.modules.capa_module.LoncapaModule,
|
||||
'video':courseware.modules.video_module.VideoModule,
|
||||
'html':courseware.modules.html_module.HtmlModule,
|
||||
'vertical':courseware.modules.vertical_module.VerticalModule,
|
||||
'sequential':courseware.modules.seq_module.SequentialModule,
|
||||
'tab':courseware.modules.seq_module.SequentialModule,
|
||||
'schematic':courseware.modules.schematic_module.SchematicModule}
|
||||
|
||||
def object_cache(cache, user, module_type, module_id):
|
||||
# We don't look up on user -- all queries include user
|
||||
# Additional lookup would require a DB hit the way Django
|
||||
@@ -74,18 +60,16 @@ def modx_dispatch(request, module=None, dispatch=None, id=None):
|
||||
|
||||
ajax_url = '/modx/'+module+'/'+id+'/'
|
||||
|
||||
id_tag=modx_modules[module].id_attribute
|
||||
|
||||
# Grab the XML corresponding to the request from course.xml
|
||||
xml = content_parser.module_xml(content_parser.course_file(request.user), module, id_tag, id)
|
||||
xml = content_parser.module_xml(content_parser.course_file(request.user), module, 'id', id)
|
||||
|
||||
# Create the module
|
||||
instance=modx_modules[module](xml,
|
||||
s.module_id,
|
||||
ajax_url=ajax_url,
|
||||
state=s.state,
|
||||
track_function = make_track_function(request),
|
||||
render_function = None)
|
||||
instance=courseware.modules.get_module_class(module)(xml,
|
||||
s.module_id,
|
||||
ajax_url=ajax_url,
|
||||
state=s.state,
|
||||
track_function = make_track_function(request),
|
||||
render_function = None)
|
||||
# Let the module handle the AJAX
|
||||
ajax_return=instance.handle_ajax(dispatch, request.POST)
|
||||
# Save the state back to the database
|
||||
@@ -100,7 +84,7 @@ def render_x_module(user, request, xml_module, module_object_preload):
|
||||
''' Generic module for extensions. This renders to HTML. '''
|
||||
# Check if problem has an instance in DB
|
||||
module_type=xml_module.tag
|
||||
module_class=modx_modules[module_type]
|
||||
module_class=courseware.modules.get_module_class(module_type)
|
||||
module_id=xml_module.get('id') #module_class.id_attribute) or ""
|
||||
|
||||
# Grab state from database
|
||||
@@ -132,7 +116,10 @@ def render_x_module(user, request, xml_module, module_object_preload):
|
||||
smod.save() # This may be optional (at least in the case of no instance in the dB)
|
||||
module_object_preload.append(smod)
|
||||
# Grab content
|
||||
content = {'content':instance.get_html(),
|
||||
content = instance.get_html()
|
||||
if user.is_staff:
|
||||
content=content+render_to_string("staff_problem_info.html", {'xml':etree.tostring(xml_module)})
|
||||
content = {'content':content,
|
||||
"destroy_js":instance.get_destroy_js(),
|
||||
'init_js':instance.get_init_js(),
|
||||
'type':module_type}
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
import os
|
||||
import os.path
|
||||
|
||||
from django.conf import settings
|
||||
|
||||
import capa_module
|
||||
import html_module
|
||||
import schematic_module
|
||||
import seq_module
|
||||
import template_module
|
||||
import vertical_module
|
||||
import video_module
|
||||
|
||||
from courseware import content_parser
|
||||
|
||||
# Import all files in modules directory, excluding backups (# and . in name)
|
||||
# and __init__
|
||||
#
|
||||
# Stick them in a list
|
||||
# modx_module_list = []
|
||||
|
||||
# for f in os.listdir(os.path.dirname(__file__)):
|
||||
# if f!='__init__.py' and \
|
||||
# f[-3:] == ".py" and \
|
||||
# "." not in f[:-3] \
|
||||
# and '#' not in f:
|
||||
# mod_path = 'courseware.modules.'+f[:-3]
|
||||
# mod = __import__(mod_path, fromlist = "courseware.modules")
|
||||
# if 'Module' in mod.__dict__:
|
||||
# modx_module_list.append(mod)
|
||||
|
||||
#print modx_module_list
|
||||
modx_module_list = [capa_module, html_module, schematic_module, seq_module, template_module, vertical_module, video_module]
|
||||
#print modx_module_list
|
||||
|
||||
modx_modules = {}
|
||||
|
||||
# Convert list to a dictionary for lookup by tag
|
||||
def update_modules():
|
||||
global modx_modules
|
||||
modx_modules = dict()
|
||||
for module in modx_module_list:
|
||||
for tag in module.Module.get_xml_tags():
|
||||
modx_modules[tag] = module.Module
|
||||
|
||||
update_modules()
|
||||
|
||||
def get_module_class(tag):
|
||||
''' Given an XML tag (e.g. 'video'), return
|
||||
the associated module (e.g. video_module.Module).
|
||||
'''
|
||||
if tag not in modx_modules:
|
||||
update_modules()
|
||||
return modx_modules[tag]
|
||||
|
||||
def get_module_id(tag):
|
||||
''' Given an XML tag (e.g. 'video'), return
|
||||
the default ID for that module (e.g. 'youtube_id')
|
||||
'''
|
||||
return modx_modules[tag].id_attribute
|
||||
|
||||
def get_valid_tags():
|
||||
return modx_modules.keys()
|
||||
|
||||
def get_default_ids():
|
||||
tags = get_valid_tags()
|
||||
ids = map(get_module_id, tags)
|
||||
return dict(zip(tags, ids))
|
||||
|
||||
|
||||
@@ -21,20 +21,23 @@ 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
|
||||
from courseware.capa.capa_problem import LoncapaProblem, StudentInputError
|
||||
import courseware.content_parser as content_parser
|
||||
|
||||
log = logging.getLogger("mitx.courseware")
|
||||
|
||||
class LoncapaModule(XModule):
|
||||
class Module(XModule):
|
||||
''' Interface between capa_problem and x_module. Originally a hack
|
||||
meant to be refactored out, but it seems to be serving a useful
|
||||
prupose now. We can e.g .destroy and create the capa_problem on a
|
||||
reset.
|
||||
'''
|
||||
xml_tags = ["problem"]
|
||||
|
||||
id_attribute = "filename"
|
||||
|
||||
@classmethod
|
||||
def get_xml_tags(c):
|
||||
return ["problem"]
|
||||
|
||||
def get_state(self):
|
||||
state = self.lcp.get_state()
|
||||
@@ -78,7 +81,7 @@ class LoncapaModule(XModule):
|
||||
|
||||
# User submitted a problem, and hasn't reset. We don't want
|
||||
# more submissions.
|
||||
if self.lcp.done and self.rerandomize:
|
||||
if self.lcp.done and self.rerandomize == "always":
|
||||
#print "!"
|
||||
check_button = False
|
||||
save_button = False
|
||||
@@ -91,6 +94,10 @@ class LoncapaModule(XModule):
|
||||
if self.max_attempts != None:
|
||||
attempts_str = " ({a}/{m})".format(a=self.attempts, m=self.max_attempts)
|
||||
|
||||
# We don't need a "save" button if infinite number of attempts and non-randomized
|
||||
if self.max_attempts == None and self.rerandomize != "always":
|
||||
save_button = False
|
||||
|
||||
# Check if explanation is available, and if so, give a link
|
||||
explain=""
|
||||
if self.lcp.done and self.explain_available=='attempted':
|
||||
@@ -157,12 +164,12 @@ class LoncapaModule(XModule):
|
||||
self.show_answer="closed"
|
||||
|
||||
self.rerandomize=content_parser.item(dom2.xpath('/problem/@rerandomize'))
|
||||
if self.rerandomize=="":
|
||||
self.rerandomize=True
|
||||
elif self.rerandomize=="false":
|
||||
self.rerandomize=False
|
||||
elif self.rerandomize=="true":
|
||||
self.rerandomize=True
|
||||
if self.rerandomize=="" or self.rerandomize=="always" or self.rerandomize=="true":
|
||||
self.rerandomize="always"
|
||||
elif self.rerandomize=="false" or self.rerandomize=="per_student":
|
||||
self.rerandomize="per_student"
|
||||
elif self.rerandomize=="never":
|
||||
self.rerandomize="never"
|
||||
else:
|
||||
raise Exception("Invalid rerandomize attribute "+self.rerandomize)
|
||||
|
||||
@@ -172,9 +179,13 @@ class LoncapaModule(XModule):
|
||||
self.attempts=state['attempts']
|
||||
|
||||
self.filename=content_parser.item(dom2.xpath('/problem/@filename'))
|
||||
filename=settings.DATA_DIR+"problems/"+self.filename+".xml"
|
||||
filename=settings.DATA_DIR+"/problems/"+self.filename+".xml"
|
||||
self.name=content_parser.item(dom2.xpath('/problem/@name'))
|
||||
self.lcp=LoncapaProblem(filename, self.item_id, state)
|
||||
if self.rerandomize == 'never':
|
||||
seed = 1
|
||||
else:
|
||||
seed = None
|
||||
self.lcp=LoncapaProblem(filename, self.item_id, state, seed = seed)
|
||||
|
||||
def handle_ajax(self, dispatch, get):
|
||||
if dispatch=='problem_get':
|
||||
@@ -250,7 +261,7 @@ class LoncapaModule(XModule):
|
||||
for key in get:
|
||||
answers['_'.join(key.split('_')[1:])]=get[key]
|
||||
|
||||
print "XXX", answers, get
|
||||
# print "XXX", answers, get
|
||||
|
||||
event_info['answers']=answers
|
||||
|
||||
@@ -263,7 +274,7 @@ class LoncapaModule(XModule):
|
||||
|
||||
# Problem submitted. Student should reset before checking
|
||||
# again.
|
||||
if self.lcp.done and self.rerandomize:
|
||||
if self.lcp.done and self.rerandomize == "always":
|
||||
event_info['failure']='unreset'
|
||||
self.tracker('save_problem_check_fail', event_info)
|
||||
print "cpdr"
|
||||
@@ -274,22 +285,27 @@ class LoncapaModule(XModule):
|
||||
lcp_id = self.lcp.problem_id
|
||||
filename = self.lcp.filename
|
||||
correct_map = self.lcp.grade_answers(answers)
|
||||
except StudentInputError as inst:
|
||||
self.lcp = LoncapaProblem(filename, id=lcp_id, state=old_state)
|
||||
traceback.print_exc()
|
||||
# print {'error':sys.exc_info(),
|
||||
# 'answers':answers,
|
||||
# 'seed':self.lcp.seed,
|
||||
# 'filename':self.lcp.filename}
|
||||
return json.dumps({'success':inst.message})
|
||||
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,
|
||||
'filename':self.lcp.filename}
|
||||
return json.dumps({'success':'syntax'})
|
||||
return json.dumps({'success':'Unknown Error'})
|
||||
|
||||
|
||||
self.attempts = self.attempts + 1
|
||||
self.lcp.done=True
|
||||
|
||||
success = 'finished'
|
||||
success = 'correct'
|
||||
for i in correct_map:
|
||||
if correct_map[i]!='correct':
|
||||
success = 'errors'
|
||||
success = 'incorrect'
|
||||
|
||||
js=json.dumps({'correct_map' : correct_map,
|
||||
'success' : success})
|
||||
@@ -319,7 +335,7 @@ class LoncapaModule(XModule):
|
||||
|
||||
# Problem submitted. Student should reset before saving
|
||||
# again.
|
||||
if self.lcp.done and self.rerandomize:
|
||||
if self.lcp.done and self.rerandomize == "always":
|
||||
event_info['failure']='done'
|
||||
self.tracker('save_problem_fail', event_info)
|
||||
return "Problem needs to be reset prior to save."
|
||||
@@ -352,7 +368,7 @@ class LoncapaModule(XModule):
|
||||
self.lcp.student_answers = dict()
|
||||
|
||||
|
||||
if self.rerandomize:
|
||||
if self.rerandomize == "always":
|
||||
self.lcp.context=dict()
|
||||
self.lcp.questions=dict() # Detailed info about questions in problem instance. TODO: Should be by id and not lid.
|
||||
self.lcp.seed=None
|
||||
|
||||
@@ -7,14 +7,15 @@ from mitxmako.shortcuts import render_to_response, render_to_string
|
||||
from x_module import XModule
|
||||
from lxml import etree
|
||||
|
||||
class HtmlModule(XModule):
|
||||
class Module(XModule):
|
||||
id_attribute = 'filename'
|
||||
|
||||
def get_state(self):
|
||||
return json.dumps({ })
|
||||
|
||||
def get_xml_tags():
|
||||
return "html"
|
||||
@classmethod
|
||||
def get_xml_tags(c):
|
||||
return ["html"]
|
||||
|
||||
def get_html(self):
|
||||
if self.filename==None:
|
||||
@@ -23,7 +24,7 @@ class HtmlModule(XModule):
|
||||
textlist=[i for i in textlist if type(i)==str]
|
||||
return "".join(textlist)
|
||||
try:
|
||||
filename=settings.DATA_DIR+"html/"+self.filename+".xml"
|
||||
filename=settings.DATA_DIR+"html/"+self.filename
|
||||
return open(filename).read()
|
||||
except: # For backwards compatibility. TODO: Remove
|
||||
return render_to_string(self.filename, {'id': self.item_id})
|
||||
|
||||
@@ -6,14 +6,15 @@ from mitxmako.shortcuts import render_to_response, render_to_string
|
||||
|
||||
from x_module import XModule
|
||||
|
||||
class SchematicModule(XModule):
|
||||
class Module(XModule):
|
||||
id_attribute = 'id'
|
||||
|
||||
def get_state(self):
|
||||
return json.dumps({ })
|
||||
|
||||
def get_xml_tags():
|
||||
return "schematic"
|
||||
@classmethod
|
||||
def get_xml_tags(c):
|
||||
return ["schematic"]
|
||||
|
||||
def get_html(self):
|
||||
return '<input type="hidden" class="schematic" name="{item_id}" height="480" width="640">'.format(item_id=self.item_id)
|
||||
|
||||
@@ -13,7 +13,7 @@ from x_module import XModule
|
||||
# OBSOLETE: This obsoletes 'type'
|
||||
class_priority = ['video', 'problem']
|
||||
|
||||
class SequentialModule(XModule):
|
||||
class Module(XModule):
|
||||
''' Layout module which lays out content in a temporal sequence
|
||||
'''
|
||||
id_attribute = 'id'
|
||||
@@ -21,7 +21,8 @@ class SequentialModule(XModule):
|
||||
def get_state(self):
|
||||
return json.dumps({ 'position':self.position })
|
||||
|
||||
def get_xml_tags():
|
||||
@classmethod
|
||||
def get_xml_tags(c):
|
||||
return ["sequential", 'tab']
|
||||
|
||||
def get_html(self):
|
||||
@@ -65,28 +66,34 @@ class SequentialModule(XModule):
|
||||
## Returns a set of all types of all sub-children
|
||||
child_classes = [set([i.tag for i in e.iter()]) for e in self.xmltree]
|
||||
|
||||
self.contents=[(e.get("name"),j(self.render_function(e))) \
|
||||
for e in self.xmltree]
|
||||
self.titles = json.dumps(["\n".join([i.get("name").strip() for i in e.iter() if i.get("name") != None]) \
|
||||
for e in self.xmltree])
|
||||
|
||||
self.contents = [j(self.render_function(e)) \
|
||||
for e in self.xmltree]
|
||||
|
||||
print self.titles
|
||||
|
||||
for (content, element_class) in zip(self.contents, child_classes):
|
||||
new_class = 'other'
|
||||
for c in class_priority:
|
||||
if c in element_class:
|
||||
new_class = c
|
||||
content[1]['type'] = new_class
|
||||
content['type'] = new_class
|
||||
|
||||
js=""
|
||||
|
||||
params={'items':self.contents,
|
||||
'id':self.item_id,
|
||||
'position': self.position}
|
||||
'position': self.position,
|
||||
'titles':self.titles}
|
||||
|
||||
# TODO/BUG: Destroy JavaScript should only be called for the active view
|
||||
# This calls it for all the views
|
||||
#
|
||||
# To fix this, we'd probably want to have some way of assigning unique
|
||||
# IDs to sequences.
|
||||
destroy_js="".join([e[1]['destroy_js'] for e in self.contents if 'destroy_js' in e[1]])
|
||||
destroy_js="".join([e['destroy_js'] for e in self.contents if 'destroy_js' in e])
|
||||
|
||||
if self.xmltree.tag == 'sequential':
|
||||
self.init_js=js+render_to_string('seq_module.js',params)
|
||||
|
||||
29
courseware/modules/template_module.py
Normal file
29
courseware/modules/template_module.py
Normal file
@@ -0,0 +1,29 @@
|
||||
import json
|
||||
import os
|
||||
|
||||
## TODO: Abstract out from Django
|
||||
from django.conf import settings
|
||||
from mitxmako.shortcuts import render_to_response, render_to_string
|
||||
|
||||
from x_module import XModule
|
||||
from lxml import etree
|
||||
|
||||
class Module(XModule):
|
||||
def get_state(self):
|
||||
return json.dumps({ })
|
||||
|
||||
@classmethod
|
||||
def get_xml_tags(c):
|
||||
tags = os.listdir(settings.DATA_DIR+'/custom_tags')
|
||||
return tags
|
||||
|
||||
def get_html(self):
|
||||
return self.html
|
||||
|
||||
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)
|
||||
xmltree = etree.fromstring(xml)
|
||||
filename = xmltree.tag
|
||||
params = dict(xmltree.items())
|
||||
# print params
|
||||
self.html = render_to_string(filename, params, namespace = 'custom_tags')
|
||||
@@ -7,14 +7,15 @@ from mitxmako.shortcuts import render_to_response, render_to_string
|
||||
from x_module import XModule
|
||||
from lxml import etree
|
||||
|
||||
class VerticalModule(XModule):
|
||||
class Module(XModule):
|
||||
id_attribute = 'id'
|
||||
|
||||
def get_state(self):
|
||||
return json.dumps({ })
|
||||
|
||||
def get_xml_tags():
|
||||
return "vertical"
|
||||
@classmethod
|
||||
def get_xml_tags(c):
|
||||
return ["vertical"]
|
||||
|
||||
def get_html(self):
|
||||
return render_to_string('vert_module.html',{'items':self.contents})
|
||||
|
||||
@@ -11,8 +11,8 @@ from x_module import XModule
|
||||
|
||||
log = logging.getLogger("mitx.courseware.modules")
|
||||
|
||||
class VideoModule(XModule):
|
||||
#id_attribute = 'youtube'
|
||||
class Module(XModule):
|
||||
id_attribute = 'youtube'
|
||||
video_time = 0
|
||||
|
||||
def handle_ajax(self, dispatch, get):
|
||||
@@ -28,9 +28,10 @@ class VideoModule(XModule):
|
||||
log.debug(u"STATE POSITION {0}".format(self.position))
|
||||
return json.dumps({ 'position':self.position })
|
||||
|
||||
def get_xml_tags():
|
||||
@classmethod
|
||||
def get_xml_tags(c):
|
||||
'''Tags in the courseware file guaranteed to correspond to the module'''
|
||||
return "video"
|
||||
return ["video"]
|
||||
|
||||
def video_list(self):
|
||||
l = self.youtube.split(',')
|
||||
|
||||
@@ -8,9 +8,10 @@ class XModule(object):
|
||||
Initialized on access with __init__, first time with state=None, and
|
||||
then with state
|
||||
'''
|
||||
id_attribute='name' # An attribute guaranteed to be unique
|
||||
id_attribute='id' # An attribute guaranteed to be unique
|
||||
|
||||
def get_xml_tags():
|
||||
@classmethod
|
||||
def get_xml_tags(c):
|
||||
''' Tags in the courseware file guaranteed to correspond to the module '''
|
||||
return []
|
||||
|
||||
|
||||
@@ -1,16 +1,53 @@
|
||||
"""
|
||||
This file demonstrates writing tests using the unittest module. These will pass
|
||||
when you run "manage.py test".
|
||||
import unittest
|
||||
|
||||
Replace this with more appropriate tests for your application.
|
||||
"""
|
||||
import numpy
|
||||
|
||||
from django.test import TestCase
|
||||
import courseware.modules
|
||||
import courseware.capa.calc as calc
|
||||
|
||||
class ModelsTest(unittest.TestCase):
|
||||
def setUp(self):
|
||||
pass
|
||||
|
||||
def test_get_module_class(self):
|
||||
vc = courseware.modules.get_module_class('video')
|
||||
vc_str = "<class 'courseware.modules.video_module.Module'>"
|
||||
self.assertEqual(str(vc), vc_str)
|
||||
video_id = courseware.modules.get_default_ids()['video']
|
||||
self.assertEqual(video_id, 'youtube')
|
||||
|
||||
def test_calc(self):
|
||||
variables={'R1':2.0, 'R3':4.0}
|
||||
functions={'sin':numpy.sin, 'cos':numpy.cos}
|
||||
|
||||
self.assertEqual(calc.evaluator(variables, functions, "10000||sin(7+5)-6k"), 4000.0)
|
||||
self.assertEqual(calc.evaluator({'R1': 2.0, 'R3':4.0}, {}, "13"), 13)
|
||||
self.assertEqual(calc.evaluator(variables, functions, "13"), 13)
|
||||
self.assertEqual(calc.evaluator({'a': 2.2997471478310274, 'k': 9, 'm': 8, 'x': 0.66009498411213041}, {}, "5"), 5)
|
||||
self.assertEqual(calc.evaluator({},{}, "-1"), -1)
|
||||
self.assertEqual(calc.evaluator({},{}, "-0.33"), -.33)
|
||||
self.assertEqual(calc.evaluator({},{}, "-.33"), -.33)
|
||||
self.assertEqual(calc.evaluator(variables, functions, "R1*R3"), 8.0)
|
||||
self.assertTrue(abs(calc.evaluator(variables, functions, "sin(e)-0.41"))<0.01)
|
||||
self.assertTrue(abs(calc.evaluator(variables, functions, "k*T/q-0.025"))<0.001)
|
||||
exception_happened = False
|
||||
try:
|
||||
calc.evaluator({},{}, "5+7 QWSEKO")
|
||||
except:
|
||||
exception_happened = True
|
||||
self.assertTrue(exception_happened)
|
||||
|
||||
try:
|
||||
calc.evaluator({'r1':5},{}, "r1+r2")
|
||||
except calc.UndefinedVariable:
|
||||
pass
|
||||
|
||||
self.assertEqual(calc.evaluator(variables, functions, "r1*r3"), 8.0)
|
||||
|
||||
exception_happened = False
|
||||
try:
|
||||
calc.evaluator(variables, functions, "r1*r3", cs=True)
|
||||
except:
|
||||
exception_happened = True
|
||||
self.assertTrue(exception_happened)
|
||||
|
||||
class SimpleTest(TestCase):
|
||||
def test_basic_addition(self):
|
||||
"""
|
||||
Tests that 1 + 1 always equals 2.
|
||||
"""
|
||||
self.assertEqual(1 + 1, 2)
|
||||
|
||||
@@ -34,6 +34,38 @@ etree.set_default_parser(etree.XMLParser(dtd_validation=False, load_dtd=False,
|
||||
|
||||
template_imports={'urllib':urllib}
|
||||
|
||||
def get_grade(request, problem, cache):
|
||||
## HACK: assumes max score is fixed per problem
|
||||
id = problem.get('id')
|
||||
correct = 0
|
||||
|
||||
# If the ID is not in the cache, add the item
|
||||
if id not in cache:
|
||||
module = StudentModule(module_type = 'problem', # TODO: Move into StudentModule.__init__?
|
||||
module_id = id,
|
||||
student = request.user,
|
||||
state = None,
|
||||
grade = 0,
|
||||
max_grade = None,
|
||||
done = 'i')
|
||||
cache[id] = module
|
||||
|
||||
# Grab the # correct from cache
|
||||
if id in cache:
|
||||
response = cache[id]
|
||||
if response.grade!=None:
|
||||
correct=response.grade
|
||||
|
||||
# Grab max grade from cache, or if it doesn't exist, compute and save to DB
|
||||
if id in cache and response.max_grade != None:
|
||||
total = response.max_grade
|
||||
else:
|
||||
total=courseware.modules.capa_module.Module(etree.tostring(problem), "id").max_score()
|
||||
response.max_grade = total
|
||||
response.save()
|
||||
|
||||
return (correct, total)
|
||||
|
||||
@cache_control(no_cache=True, no_store=True, must_revalidate=True)
|
||||
def profile(request):
|
||||
''' User profile. Show username, location, etc, as well as grades .
|
||||
@@ -42,46 +74,48 @@ def profile(request):
|
||||
return redirect('/')
|
||||
|
||||
dom=content_parser.course_file(request.user)
|
||||
hw=[]
|
||||
course = dom.xpath('//course/@name')[0]
|
||||
chapters = dom.xpath('//course[@name=$course]/chapter', course=course)
|
||||
xmlChapters = dom.xpath('//course[@name=$course]/chapter', course=course)
|
||||
|
||||
responses=StudentModule.objects.filter(student=request.user)
|
||||
response_by_id = {}
|
||||
for response in responses:
|
||||
response_by_id[response.module_id] = response
|
||||
|
||||
|
||||
|
||||
|
||||
total_scores = {}
|
||||
|
||||
for c in chapters:
|
||||
chapters=[]
|
||||
for c in xmlChapters:
|
||||
sections = []
|
||||
chname=c.get('name')
|
||||
for s in dom.xpath('//course[@name=$course]/chapter[@name=$chname]/section',
|
||||
course=course, chname=chname):
|
||||
problems=dom.xpath('//course[@name=$course]/chapter[@name=$chname]/section[@name=$section]//problem',
|
||||
course=course, chname=chname, section=s.get('name'))
|
||||
|
||||
|
||||
graded = True if s.get('graded') == "true" else False
|
||||
scores=[]
|
||||
if len(problems)>0:
|
||||
for p in problems:
|
||||
id = p.get('id')
|
||||
correct = 0
|
||||
if id in response_by_id:
|
||||
response = response_by_id[id]
|
||||
if response.grade!=None:
|
||||
correct=response.grade
|
||||
|
||||
total=courseware.modules.capa_module.LoncapaModule(etree.tostring(p), "id").max_score() # TODO: Add state. Not useful now, but maybe someday problems will have randomized max scores?
|
||||
(correct,total) = get_grade(request, p, response_by_id)
|
||||
# id = p.get('id')
|
||||
# correct = 0
|
||||
# if id in response_by_id:
|
||||
# response = response_by_id[id]
|
||||
# if response.grade!=None:
|
||||
# correct=response.grade
|
||||
|
||||
# total=courseware.modules.capa_module.Module(etree.tostring(p), "id").max_score() # TODO: Add state. Not useful now, but maybe someday problems will have randomized max scores?
|
||||
# print correct, total
|
||||
scores.append((int(correct),total, graded ))
|
||||
|
||||
|
||||
|
||||
|
||||
section_total = (sum([score[0] for score in scores]),
|
||||
sum([score[1] for score in scores]))
|
||||
|
||||
|
||||
graded_total = (sum([score[0] for score in scores if score[2]]),
|
||||
sum([score[1] for score in scores if score[2]]))
|
||||
|
||||
|
||||
#Add the graded total to total_scores
|
||||
format = s.get('format') if s.get('format') else ""
|
||||
subtitle = s.get('subtitle') if s.get('subtitle') else format
|
||||
@@ -89,10 +123,8 @@ def profile(request):
|
||||
format_scores = total_scores[ format ] if format in total_scores else []
|
||||
format_scores.append( graded_total )
|
||||
total_scores[ format ] = format_scores
|
||||
|
||||
score={'course':course,
|
||||
'section':s.get("name"),
|
||||
'chapter':c.get("name"),
|
||||
|
||||
score={'section':s.get("name"),
|
||||
'scores':scores,
|
||||
'section_total' : section_total,
|
||||
'format' : format,
|
||||
@@ -100,7 +132,12 @@ def profile(request):
|
||||
'due' : s.get("due") or "",
|
||||
'graded' : graded,
|
||||
}
|
||||
hw.append(score)
|
||||
sections.append(score)
|
||||
|
||||
chapters.append({'course':course,
|
||||
'chapter' : c.get("name"),
|
||||
'sections' : sections,})
|
||||
|
||||
|
||||
def totalWithDrops(scores, drop_count):
|
||||
#Note that this key will sort the list descending
|
||||
@@ -216,11 +253,12 @@ def profile(request):
|
||||
'location':user_info.location,
|
||||
'language':user_info.language,
|
||||
'email':request.user.email,
|
||||
'homeworks':hw,
|
||||
'chapters':chapters,
|
||||
'format_url_params' : format_url_params,
|
||||
'grade_summary' : grade_summary,
|
||||
'csrf':csrf(request)['csrf_token']
|
||||
}
|
||||
|
||||
return render_to_response('profile.html', context)
|
||||
|
||||
def format_url_params(params):
|
||||
@@ -244,6 +282,40 @@ def render_accordion(request,course,chapter,section):
|
||||
return {'init_js':render_to_string('accordion_init.js',context),
|
||||
'content':render_to_string('accordion.html',context)}
|
||||
|
||||
@cache_control(no_cache=True, no_store=True, must_revalidate=True)
|
||||
def render_section(request, section):
|
||||
''' TODO: Consolidate with index
|
||||
'''
|
||||
user = request.user
|
||||
if not settings.COURSEWARE_ENABLED or not user.is_authenticated():
|
||||
return redirect('/')
|
||||
|
||||
# try:
|
||||
dom = content_parser.section_file(user, section)
|
||||
#except:
|
||||
# raise Http404
|
||||
|
||||
accordion=render_accordion(request, '', '', '')
|
||||
|
||||
module_ids = dom.xpath("//@id")
|
||||
|
||||
module_object_preload = list(StudentModule.objects.filter(student=user,
|
||||
module_id__in=module_ids))
|
||||
|
||||
module=render_module(user, request, dom, module_object_preload)
|
||||
|
||||
if 'init_js' not in module:
|
||||
module['init_js']=''
|
||||
|
||||
context={'init':accordion['init_js']+module['init_js'],
|
||||
'accordion':accordion['content'],
|
||||
'content':module['content'],
|
||||
'csrf':csrf(request)['csrf_token']}
|
||||
|
||||
result = render_to_response('courseware.html', context)
|
||||
return result
|
||||
|
||||
|
||||
@cache_control(no_cache=True, no_store=True, must_revalidate=True)
|
||||
def index(request, course="6.002 Spring 2012", chapter="Using the System", section="Hints"):
|
||||
''' Displays courseware accordion, and any associated content.
|
||||
|
||||
@@ -17,33 +17,31 @@ import tempfile
|
||||
from django.template import RequestContext
|
||||
|
||||
requestcontext = None
|
||||
lookup = None
|
||||
lookup = {}
|
||||
|
||||
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)
|
||||
|
||||
template_locations = settings.MAKO_TEMPLATES
|
||||
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,
|
||||
for location in template_locations:
|
||||
lookup[location] = TemplateLookup(directories=template_locations[location],
|
||||
module_directory=module_directory,
|
||||
output_encoding=output_encoding,
|
||||
encoding_errors=encoding_errors,
|
||||
output_encoding='utf-8',
|
||||
input_encoding='utf-8',
|
||||
encoding_errors='replace',
|
||||
)
|
||||
|
||||
import mitxmako
|
||||
mitxmako.lookup = lookup
|
||||
|
||||
def process_request (self, request):
|
||||
global requestcontext
|
||||
requestcontext = RequestContext(request)
|
||||
# print requestcontext
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ from django.conf import settings
|
||||
|
||||
from mitxmako.middleware import requestcontext
|
||||
|
||||
def render_to_string(template_name, dictionary, context_instance=None):
|
||||
def render_to_string(template_name, dictionary, context_instance=None, namespace='main'):
|
||||
context_instance = context_instance or Context(dictionary)
|
||||
# add dictionary to context_instance
|
||||
context_instance.update(dictionary or {})
|
||||
@@ -31,12 +31,12 @@ def render_to_string(template_name, dictionary, context_instance=None):
|
||||
for d in context_instance:
|
||||
context_dictionary.update(d)
|
||||
# fetch and render template
|
||||
template = middleware.lookup.get_template(template_name)
|
||||
template = middleware.lookup[namespace].get_template(template_name)
|
||||
return template.render(**context_dictionary)
|
||||
|
||||
def render_to_response(template_name, dictionary, context_instance=None, **kwargs):
|
||||
def render_to_response(template_name, dictionary, context_instance=None, namespace='main', **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)
|
||||
return HttpResponse(render_to_string(template_name, dictionary, context_instance, namespace), **kwargs)
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
settings_new_askbot.py
|
||||
645
settings.py
Normal file
645
settings.py
Normal file
@@ -0,0 +1,645 @@
|
||||
import os
|
||||
import platform
|
||||
import sys
|
||||
import tempfile
|
||||
|
||||
import djcelery
|
||||
|
||||
# from settings2.askbotsettings import LIVESETTINGS_OPTIONS
|
||||
|
||||
# Configuration option for when we want to grab server error pages
|
||||
STATIC_GRAB = False
|
||||
DEV_CONTENT = True
|
||||
|
||||
LIB_URL = '/static/lib/'
|
||||
LIB_URL = 'https://mitxstatic.s3.amazonaws.com/js/'
|
||||
BOOK_URL = '/static/book/'
|
||||
BOOK_URL = 'https://mitxstatic.s3.amazonaws.com/book_images/'
|
||||
|
||||
# Feature Flags. These should be set to false until they are ready to deploy, and then eventually flag mechanisms removed
|
||||
GENERATE_PROFILE_SCORES = False # If this is true, random scores will be generated for the purpose of debugging the profile graphs
|
||||
|
||||
# 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
|
||||
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
|
||||
SITE_NAME = "localhost:8000"
|
||||
|
||||
DEFAULT_FROM_EMAIL = 'registration@mitx.mit.edu'
|
||||
DEFAULT_FEEDBACK_EMAIL = 'feedback@mitx.mit.edu'
|
||||
|
||||
GENERATE_RANDOM_USER_CREDENTIALS = False
|
||||
|
||||
WIKI_REQUIRE_LOGIN_EDIT = True
|
||||
WIKI_REQUIRE_LOGIN_VIEW = True
|
||||
|
||||
PERFSTATS = False
|
||||
|
||||
HTTPS = 'on'
|
||||
|
||||
MEDIA_URL = ''
|
||||
MEDIA_ROOT = ''
|
||||
|
||||
# S3BotoStorage insists on a timeout for uploaded assets. We should make it
|
||||
# permanent instead, but rather than trying to figure out exactly where that
|
||||
# setting is, I'm just bumping the expiration time to something absurd (100
|
||||
# years). This is only used if DEFAULT_FILE_STORAGE is overriden to use S3
|
||||
# in the global settings.py
|
||||
AWS_QUERYSTRING_EXPIRE = 10 * 365 * 24 * 60 * 60 # 10 years
|
||||
|
||||
# Needed for Askbot
|
||||
# Deployed machines: Move to S3
|
||||
DEFAULT_FILE_STORAGE = 'django.core.files.storage.FileSystemStorage'
|
||||
|
||||
DEBUG = True
|
||||
TEMPLATE_DEBUG = DEBUG
|
||||
|
||||
ADMINS = (
|
||||
('MITx Admins', 'admin@mitx.mit.edu'),
|
||||
)
|
||||
|
||||
MANAGERS = ADMINS
|
||||
|
||||
# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name
|
||||
TIME_ZONE = 'America/New_York'
|
||||
|
||||
# Language code for this installation. All choices can be found here:
|
||||
# http://www.i18nguy.com/unicode/language-identifiers.html
|
||||
LANGUAGE_CODE = 'en'
|
||||
|
||||
SITE_ID = 1
|
||||
|
||||
# If you set this to False, Django will make some optimizations so as not
|
||||
# to load the internationalization machinery.
|
||||
USE_I18N = True
|
||||
|
||||
# If you set this to False, Django will not format dates, numbers and
|
||||
# calendars according to the current locale
|
||||
USE_L10N = True
|
||||
|
||||
STATIC_URL = '/static/'
|
||||
|
||||
# URL prefix for admin static files -- CSS, JavaScript and images.
|
||||
# Make sure to use a trailing slash.
|
||||
# Examples: "http://foo.com/static/admin/", "/static/admin/".
|
||||
ADMIN_MEDIA_PREFIX = '/static/admin/'
|
||||
|
||||
# List of finder classes that know how to find static files in
|
||||
# various locations.
|
||||
STATICFILES_FINDERS = (
|
||||
'django.contrib.staticfiles.finders.FileSystemFinder',
|
||||
'django.contrib.staticfiles.finders.AppDirectoriesFinder',
|
||||
# 'django.contrib.staticfiles.finders.DefaultStorageFinder',
|
||||
)
|
||||
|
||||
# List of callables that know how to import templates from various sources.
|
||||
TEMPLATE_LOADERS = (
|
||||
'django.template.loaders.filesystem.Loader',
|
||||
'django.template.loaders.app_directories.Loader',
|
||||
# 'django.template.loaders.eggs.Loader',
|
||||
)
|
||||
|
||||
MIDDLEWARE_CLASSES = (
|
||||
'django.middleware.common.CommonMiddleware',
|
||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||
'django.middleware.csrf.CsrfViewMiddleware',
|
||||
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
||||
'django.contrib.messages.middleware.MessageMiddleware',
|
||||
'track.middleware.TrackMiddleware',
|
||||
'mitxmako.middleware.MakoMiddleware',
|
||||
#'debug_toolbar.middleware.DebugToolbarMiddleware',
|
||||
)
|
||||
|
||||
ROOT_URLCONF = 'mitx.urls'
|
||||
|
||||
INSTALLED_APPS = (
|
||||
'django.contrib.auth',
|
||||
'django.contrib.contenttypes',
|
||||
'django.contrib.sessions',
|
||||
'django.contrib.sites',
|
||||
'django.contrib.messages',
|
||||
'django.contrib.staticfiles',
|
||||
'courseware',
|
||||
'student',
|
||||
'django.contrib.humanize',
|
||||
'static_template_view',
|
||||
'staticbook',
|
||||
'simplewiki',
|
||||
'track',
|
||||
'circuit',
|
||||
'perfstats',
|
||||
'util',
|
||||
# Uncomment the next line to enable the admin:
|
||||
# 'django.contrib.admin',
|
||||
# Uncomment the next line to enable admin documentation:
|
||||
# 'django.contrib.admindocs',
|
||||
)
|
||||
|
||||
#TRACK_DIR = None
|
||||
DEBUG_TRACK_LOG = False
|
||||
# Maximum length of a tracking string. We don't want e.g. a file upload in our log
|
||||
TRACK_MAX_EVENT = 10000
|
||||
# Maximum length of log file before starting a new one.
|
||||
MAXLOG = 500
|
||||
|
||||
LOG_DIR = "/tmp/"
|
||||
MAKO_MODULE_DIR = None
|
||||
|
||||
MAKO_TEMPLATES = {}
|
||||
|
||||
# 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.
|
||||
|
||||
pid = os.getpid()
|
||||
hostname = platform.node().split(".")[0]
|
||||
SYSLOG_ADDRESS = ('syslog.m.i4x.org', 514)
|
||||
|
||||
handlers = ['console']
|
||||
if not DEBUG:
|
||||
handlers.append('syslogger')
|
||||
|
||||
LOGGING = {
|
||||
'version': 1,
|
||||
'disable_existing_loggers': True,
|
||||
'formatters' : {
|
||||
'standard' : {
|
||||
'format' : '%(asctime)s %(levelname)s %(process)d [%(name)s] %(filename)s:%(lineno)d - %(message)s',
|
||||
},
|
||||
'syslog_format' : {
|
||||
'format' : '[%(name)s] %(levelname)s [' + hostname + ' %(process)d] [%(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,
|
||||
},
|
||||
'syslogger' : {
|
||||
'level' : 'INFO',
|
||||
'class' : 'logging.handlers.SysLogHandler',
|
||||
'address' : SYSLOG_ADDRESS,
|
||||
'formatter' : 'syslog_format',
|
||||
},
|
||||
'mail_admins' : {
|
||||
'level': 'ERROR',
|
||||
'class': 'django.utils.log.AdminEmailHandler',
|
||||
},
|
||||
},
|
||||
'loggers' : {
|
||||
'django' : {
|
||||
'handlers' : handlers + ['mail_admins'],
|
||||
'propagate' : True,
|
||||
'level' : 'INFO'
|
||||
},
|
||||
'tracking' : {
|
||||
'handlers' : [] if DEBUG else ['syslogger'], # handlers,
|
||||
'level' : 'DEBUG',
|
||||
'propagate' : False,
|
||||
},
|
||||
'root' : {
|
||||
'handlers' : handlers,
|
||||
'level' : 'DEBUG',
|
||||
'propagate' : False
|
||||
},
|
||||
'mitx' : {
|
||||
'handlers' : handlers,
|
||||
'level' : 'DEBUG',
|
||||
'propagate' : False
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
if PERFSTATS :
|
||||
MIDDLEWARE_CLASSES = ( 'perfstats.middleware.ProfileMiddleware',) + MIDDLEWARE_CLASSES
|
||||
|
||||
if 'TRACK_DIR' not in locals():
|
||||
TRACK_DIR = BASE_DIR+'/track_dir/'
|
||||
if 'STATIC_ROOT' not in locals():
|
||||
STATIC_ROOT = BASE_DIR+'/staticroot/'
|
||||
if 'DATA_DIR' not in locals():
|
||||
DATA_DIR = BASE_DIR+'/data/'
|
||||
if 'TEXTBOOK_DIR' not in locals():
|
||||
TEXTBOOK_DIR = BASE_DIR+'/textbook/'
|
||||
|
||||
if 'TEMPLATE_DIRS' not in locals():
|
||||
TEMPLATE_DIRS = (
|
||||
BASE_DIR+'/templates/',
|
||||
DATA_DIR+'/templates',
|
||||
TEXTBOOK_DIR,
|
||||
)
|
||||
|
||||
if 'STATICFILES_DIRS' not in locals():
|
||||
STATICFILES_DIRS = (
|
||||
BASE_DIR+'/3rdParty/static',
|
||||
BASE_DIR+'/static',
|
||||
)
|
||||
|
||||
|
||||
if 'ASKBOT_EXTRA_SKINS_DIR' not in locals():
|
||||
ASKBOT_EXTRA_SKINS_DIR = BASE_DIR+'/askbot-devel/askbot/skins'
|
||||
if 'ASKBOT_DIR' not in locals():
|
||||
ASKBOT_DIR = BASE_DIR+'/askbot-devel'
|
||||
|
||||
sys.path.append(ASKBOT_DIR)
|
||||
import askbot
|
||||
import site
|
||||
|
||||
STATICFILES_DIRS = STATICFILES_DIRS + ( ASKBOT_DIR+'/askbot/skins',)
|
||||
|
||||
ASKBOT_ROOT = os.path.dirname(askbot.__file__)
|
||||
|
||||
# Needed for Askbot
|
||||
# Deployed machines: Move to S3
|
||||
if MEDIA_ROOT == '':
|
||||
MEDIA_ROOT = ASKBOT_DIR+'/askbot/upfiles'
|
||||
if MEDIA_URL == '':
|
||||
MEDIA_URL = '/discussion/upfiles/'
|
||||
|
||||
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',
|
||||
'django.middleware.transaction.TransactionMiddleware',
|
||||
#'debug_toolbar.middleware.DebugToolbarMiddleware',
|
||||
'askbot.middleware.view_log.ViewLogMiddleware',
|
||||
'askbot.middleware.spaceless.SpacelessMiddleware',
|
||||
# 'askbot.middleware.pagesize.QuestionsPageSizeMiddleware',
|
||||
)
|
||||
|
||||
FILE_UPLOAD_TEMP_DIR = os.path.join(os.path.dirname(__file__), 'tmp').replace('\\','/')
|
||||
FILE_UPLOAD_HANDLERS = (
|
||||
'django.core.files.uploadhandler.MemoryFileUploadHandler',
|
||||
'django.core.files.uploadhandler.TemporaryFileUploadHandler',
|
||||
)
|
||||
ASKBOT_ALLOWED_UPLOAD_FILE_TYPES = ('.jpg', '.jpeg', '.gif', '.bmp', '.png', '.tiff')
|
||||
ASKBOT_MAX_UPLOAD_FILE_SIZE = 1024 * 1024 #result in bytes
|
||||
# ASKBOT_FILE_UPLOAD_DIR = os.path.join(os.path.dirname(__file__), 'askbot', 'upfiles')
|
||||
|
||||
PROJECT_ROOT = os.path.dirname(__file__)
|
||||
|
||||
TEMPLATE_CONTEXT_PROCESSORS = (
|
||||
'django.core.context_processors.request',
|
||||
'askbot.context.application_settings',
|
||||
#'django.core.context_processors.i18n',
|
||||
'askbot.user_messages.context_processors.user_messages',#must be before auth
|
||||
'django.core.context_processors.auth', #this is required for admin
|
||||
'django.core.context_processors.csrf', #necessary for csrf protection
|
||||
)
|
||||
|
||||
INSTALLED_APPS = INSTALLED_APPS + (
|
||||
'django.contrib.sitemaps',
|
||||
'django.contrib.admin',
|
||||
'south',
|
||||
'askbot.deps.livesettings',
|
||||
'askbot',
|
||||
'keyedcache', # TODO: Main askbot tree has this installed, but we get intermittent errors if we include it.
|
||||
'robots',
|
||||
'django_countries',
|
||||
'djcelery',
|
||||
'djkombu',
|
||||
'followit',
|
||||
)
|
||||
|
||||
CACHE_MIDDLEWARE_ANONYMOUS_ONLY = True
|
||||
ASKBOT_URL = 'discussion/'
|
||||
LOGIN_REDIRECT_URL = '/'
|
||||
LOGIN_URL = '/'
|
||||
|
||||
# ASKBOT_UPLOADED_FILES_URL = '%s%s' % (ASKBOT_URL, 'upfiles/')
|
||||
ALLOW_UNICODE_SLUGS = False
|
||||
ASKBOT_USE_STACKEXCHANGE_URLS = False #mimic url scheme of stackexchange
|
||||
ASKBOT_CSS_DEVEL = True
|
||||
|
||||
LIVESETTINGS_OPTIONS = {
|
||||
1: {
|
||||
'DB' : False,
|
||||
'SETTINGS' : {
|
||||
'ACCESS_CONTROL' : {
|
||||
'ASKBOT_CLOSED_FORUM_MODE' : True,
|
||||
},
|
||||
'BADGES' : {
|
||||
'DISCIPLINED_BADGE_MIN_UPVOTES' : 3,
|
||||
'PEER_PRESSURE_BADGE_MIN_DOWNVOTES' : 3,
|
||||
'TEACHER_BADGE_MIN_UPVOTES' : 1,
|
||||
'NICE_ANSWER_BADGE_MIN_UPVOTES' : 2,
|
||||
'GOOD_ANSWER_BADGE_MIN_UPVOTES' : 3,
|
||||
'GREAT_ANSWER_BADGE_MIN_UPVOTES' : 5,
|
||||
'NICE_QUESTION_BADGE_MIN_UPVOTES' : 2,
|
||||
'GOOD_QUESTION_BADGE_MIN_UPVOTES' : 3,
|
||||
'GREAT_QUESTION_BADGE_MIN_UPVOTES' : 5,
|
||||
'POPULAR_QUESTION_BADGE_MIN_VIEWS' : 150,
|
||||
'NOTABLE_QUESTION_BADGE_MIN_VIEWS' : 250,
|
||||
'FAMOUS_QUESTION_BADGE_MIN_VIEWS' : 500,
|
||||
'SELF_LEARNER_BADGE_MIN_UPVOTES' : 1,
|
||||
'CIVIC_DUTY_BADGE_MIN_VOTES' : 100,
|
||||
'ENLIGHTENED_BADGE_MIN_UPVOTES' : 3,
|
||||
'ASSOCIATE_EDITOR_BADGE_MIN_EDITS' : 20,
|
||||
'COMMENTATOR_BADGE_MIN_COMMENTS' : 10,
|
||||
'ENTHUSIAST_BADGE_MIN_DAYS' : 30,
|
||||
'FAVORITE_QUESTION_BADGE_MIN_STARS' : 3,
|
||||
'GURU_BADGE_MIN_UPVOTES' : 5,
|
||||
'NECROMANCER_BADGE_MIN_DELAY' : 30,
|
||||
'NECROMANCER_BADGE_MIN_UPVOTES' : 1,
|
||||
'STELLAR_QUESTION_BADGE_MIN_STARS' : 5,
|
||||
'TAXONOMIST_BADGE_MIN_USE_COUNT' : 10,
|
||||
},
|
||||
'EMAIL' : {
|
||||
'EMAIL_SUBJECT_PREFIX' : u'[Django] ',
|
||||
'EMAIL_UNIQUE' : True,
|
||||
'EMAIL_VALIDATION' : False,
|
||||
'DEFAULT_NOTIFICATION_DELIVERY_SCHEDULE_M_AND_C' : u'w',
|
||||
'DEFAULT_NOTIFICATION_DELIVERY_SCHEDULE_Q_ALL' : u'w',
|
||||
'DEFAULT_NOTIFICATION_DELIVERY_SCHEDULE_Q_ANS' : u'w',
|
||||
'DEFAULT_NOTIFICATION_DELIVERY_SCHEDULE_Q_ASK' : u'w',
|
||||
'DEFAULT_NOTIFICATION_DELIVERY_SCHEDULE_Q_SEL' : u'w',
|
||||
'ENABLE_UNANSWERED_REMINDERS' : False,
|
||||
'DAYS_BEFORE_SENDING_UNANSWERED_REMINDER' : 1,
|
||||
'UNANSWERED_REMINDER_FREQUENCY' : 1,
|
||||
'MAX_UNANSWERED_REMINDERS' : 5,
|
||||
'ENABLE_ACCEPT_ANSWER_REMINDERS' : False,
|
||||
'DAYS_BEFORE_SENDING_ACCEPT_ANSWER_REMINDER' : 3,
|
||||
'ACCEPT_ANSWER_REMINDER_FREQUENCY' : 3,
|
||||
'MAX_ACCEPT_ANSWER_REMINDERS' : 5,
|
||||
'ANONYMOUS_USER_EMAIL' : u'anonymous@askbot.org',
|
||||
'ALLOW_ASKING_BY_EMAIL' : False,
|
||||
'REPLACE_SPACE_WITH_DASH_IN_EMAILED_TAGS' : True,
|
||||
'MAX_ALERTS_PER_EMAIL' : 7,
|
||||
},
|
||||
'EMBEDDABLE_WIDGETS' : {
|
||||
'QUESTIONS_WIDGET_CSS' : u"\nbody {\n overflow: hidden;\n}\n#container {\n width: 200px;\n height: 350px;\n}\nul {\n list-style: none;\n padding: 5px;\n margin: 5px;\n}\nli {\n border-bottom: #CCC 1px solid;\n padding-bottom: 5px;\n padding-top: 5px;\n}\nli:last-child {\n border: none;\n}\na {\n text-decoration: none;\n color: #464646;\n font-family: 'Yanone Kaffeesatz', sans-serif;\n font-size: 15px;\n}\n",
|
||||
'QUESTIONS_WIDGET_FOOTER' : u"\n<link \n href='http://fonts.googleapis.com/css?family=Yanone+Kaffeesatz:300,400,700'\n rel='stylesheet'\n type='text/css'\n>\n",
|
||||
'QUESTIONS_WIDGET_HEADER' : u'',
|
||||
'QUESTIONS_WIDGET_MAX_QUESTIONS' : 7,
|
||||
},
|
||||
'EXTERNAL_KEYS' : {
|
||||
'RECAPTCHA_KEY' : u'',
|
||||
'RECAPTCHA_SECRET' : u'',
|
||||
'FACEBOOK_KEY' : u'',
|
||||
'FACEBOOK_SECRET' : u'',
|
||||
'HOW_TO_CHANGE_LDAP_PASSWORD' : u'',
|
||||
'IDENTICA_KEY' : u'',
|
||||
'IDENTICA_SECRET' : u'',
|
||||
'GOOGLE_ANALYTICS_KEY' : u'',
|
||||
'GOOGLE_SITEMAP_CODE' : u'',
|
||||
'LDAP_PROVIDER_NAME' : u'',
|
||||
'LDAP_URL' : u'',
|
||||
'LINKEDIN_KEY' : u'',
|
||||
'LINKEDIN_SECRET' : u'',
|
||||
'TWITTER_KEY' : u'',
|
||||
'TWITTER_SECRET' : u'',
|
||||
'USE_LDAP_FOR_PASSWORD_LOGIN' : False,
|
||||
'USE_RECAPTCHA' : False,
|
||||
},
|
||||
'FLATPAGES' : {
|
||||
'FORUM_ABOUT' : u'',
|
||||
'FORUM_FAQ' : u'',
|
||||
'FORUM_PRIVACY' : u'',
|
||||
},
|
||||
'FORUM_DATA_RULES' : {
|
||||
'MIN_TITLE_LENGTH' : 1,
|
||||
'MIN_QUESTION_BODY_LENGTH' : 1,
|
||||
'MIN_ANSWER_BODY_LENGTH' : 1,
|
||||
'WIKI_ON' : True,
|
||||
'ALLOW_ASK_ANONYMOUSLY' : True,
|
||||
'ALLOW_POSTING_BEFORE_LOGGING_IN' : True,
|
||||
'ALLOW_SWAPPING_QUESTION_WITH_ANSWER' : False,
|
||||
'MAX_TAG_LENGTH' : 20,
|
||||
'MIN_TITLE_LENGTH' : 1,
|
||||
'MIN_QUESTION_BODY_LENGTH' : 1,
|
||||
'MIN_ANSWER_BODY_LENGTH' : 1,
|
||||
'MANDATORY_TAGS' : u'',
|
||||
'FORCE_LOWERCASE_TAGS' : False,
|
||||
'TAG_LIST_FORMAT' : u'list',
|
||||
'USE_WILDCARD_TAGS' : False,
|
||||
'MAX_COMMENTS_TO_SHOW' : 5,
|
||||
'MAX_COMMENT_LENGTH' : 300,
|
||||
'USE_TIME_LIMIT_TO_EDIT_COMMENT' : True,
|
||||
'MINUTES_TO_EDIT_COMMENT' : 10,
|
||||
'SAVE_COMMENT_ON_ENTER' : True,
|
||||
'MIN_SEARCH_WORD_LENGTH' : 4,
|
||||
'DECOUPLE_TEXT_QUERY_FROM_SEARCH_STATE' : False,
|
||||
'MAX_TAGS_PER_POST' : 5,
|
||||
'DEFAULT_QUESTIONS_PAGE_SIZE' : u'30',
|
||||
'UNANSWERED_QUESTION_MEANING' : u'NO_ACCEPTED_ANSWERS',
|
||||
|
||||
# Enabling video requires forked version of markdown
|
||||
# pip uninstall markdown2
|
||||
# pip install -e git+git://github.com/andryuha/python-markdown2.git#egg=markdown2
|
||||
'ENABLE_VIDEO_EMBEDDING' : False,
|
||||
},
|
||||
'GENERAL_SKIN_SETTINGS' : {
|
||||
'CUSTOM_CSS' : u'',
|
||||
'CUSTOM_FOOTER' : u'',
|
||||
'CUSTOM_HEADER' : u'',
|
||||
'CUSTOM_HTML_HEAD' : u'',
|
||||
'CUSTOM_JS' : u'',
|
||||
'SITE_FAVICON' : u'/images/favicon.gif',
|
||||
'SITE_LOGO_URL' : u'/images/logo.gif',
|
||||
'SHOW_LOGO' : False,
|
||||
'LOCAL_LOGIN_ICON' : u'/images/pw-login.gif',
|
||||
'ALWAYS_SHOW_ALL_UI_FUNCTIONS' : False,
|
||||
'ASKBOT_DEFAULT_SKIN' : u'default',
|
||||
'USE_CUSTOM_HTML_HEAD' : False,
|
||||
'FOOTER_MODE' : u'default',
|
||||
'USE_CUSTOM_CSS' : False,
|
||||
'USE_CUSTOM_JS' : False,
|
||||
},
|
||||
'LEADING_SIDEBAR' : {
|
||||
'ENABLE_LEADING_SIDEBAR' : False,
|
||||
'LEADING_SIDEBAR' : u'',
|
||||
},
|
||||
'LOGIN_PROVIDERS' : {
|
||||
'PASSWORD_REGISTER_SHOW_PROVIDER_BUTTONS' : True,
|
||||
'SIGNIN_ALWAYS_SHOW_LOCAL_LOGIN' : True,
|
||||
'SIGNIN_AOL_ENABLED' : True,
|
||||
'SIGNIN_BLOGGER_ENABLED' : True,
|
||||
'SIGNIN_CLAIMID_ENABLED' : True,
|
||||
'SIGNIN_FACEBOOK_ENABLED' : True,
|
||||
'SIGNIN_FLICKR_ENABLED' : True,
|
||||
'SIGNIN_GOOGLE_ENABLED' : True,
|
||||
'SIGNIN_IDENTI.CA_ENABLED' : True,
|
||||
'SIGNIN_LINKEDIN_ENABLED' : True,
|
||||
'SIGNIN_LIVEJOURNAL_ENABLED' : True,
|
||||
'SIGNIN_LOCAL_ENABLED' : True,
|
||||
'SIGNIN_OPENID_ENABLED' : True,
|
||||
'SIGNIN_TECHNORATI_ENABLED' : True,
|
||||
'SIGNIN_TWITTER_ENABLED' : True,
|
||||
'SIGNIN_VERISIGN_ENABLED' : True,
|
||||
'SIGNIN_VIDOOP_ENABLED' : True,
|
||||
'SIGNIN_WORDPRESS_ENABLED' : True,
|
||||
'SIGNIN_WORDPRESS_SITE_ENABLED' : False,
|
||||
'SIGNIN_YAHOO_ENABLED' : True,
|
||||
'WORDPRESS_SITE_ICON' : u'/images/logo.gif',
|
||||
'WORDPRESS_SITE_URL' : '',
|
||||
},
|
||||
'LICENSE_SETTINGS' : {
|
||||
'LICENSE_ACRONYM' : u'cc-by-sa',
|
||||
'LICENSE_LOGO_URL' : u'/images/cc-by-sa.png',
|
||||
'LICENSE_TITLE' : u'Creative Commons Attribution Share Alike 3.0',
|
||||
'LICENSE_URL' : 'http://creativecommons.org/licenses/by-sa/3.0/legalcode',
|
||||
'LICENSE_USE_LOGO' : True,
|
||||
'LICENSE_USE_URL' : True,
|
||||
'USE_LICENSE' : True,
|
||||
},
|
||||
'MARKUP' : {
|
||||
'MARKUP_CODE_FRIENDLY' : False,
|
||||
'ENABLE_MATHJAX' : False, # FIXME: Test with this enabled
|
||||
'MATHJAX_BASE_URL' : u'',
|
||||
'ENABLE_AUTO_LINKING' : False,
|
||||
'AUTO_LINK_PATTERNS' : u'',
|
||||
'AUTO_LINK_URLS' : u'',
|
||||
},
|
||||
'MIN_REP' : {
|
||||
'MIN_REP_TO_ACCEPT_OWN_ANSWER' : 1,
|
||||
'MIN_REP_TO_ANSWER_OWN_QUESTION' : 1,
|
||||
'MIN_REP_TO_CLOSE_OTHERS_QUESTIONS' : 100,
|
||||
'MIN_REP_TO_CLOSE_OWN_QUESTIONS' : 1,
|
||||
'MIN_REP_TO_DELETE_OTHERS_COMMENTS' : 2000,
|
||||
'MIN_REP_TO_DELETE_OTHERS_POSTS' : 5000,
|
||||
'MIN_REP_TO_EDIT_OTHERS_POSTS' : 2000,
|
||||
'MIN_REP_TO_EDIT_WIKI' : 1,
|
||||
'MIN_REP_TO_FLAG_OFFENSIVE' : 1,
|
||||
'MIN_REP_TO_HAVE_STRONG_URL' : 250,
|
||||
'MIN_REP_TO_LEAVE_COMMENTS' : 1,
|
||||
'MIN_REP_TO_LOCK_POSTS' : 4000,
|
||||
'MIN_REP_TO_REOPEN_OWN_QUESTIONS' : 1,
|
||||
'MIN_REP_TO_RETAG_OTHERS_QUESTIONS' : 1,
|
||||
'MIN_REP_TO_UPLOAD_FILES' : 1,
|
||||
'MIN_REP_TO_VIEW_OFFENSIVE_FLAGS' : 2000,
|
||||
'MIN_REP_TO_VOTE_DOWN' : 1,
|
||||
'MIN_REP_TO_VOTE_UP' : 1,
|
||||
},
|
||||
'QA_SITE_SETTINGS' : {
|
||||
'APP_COPYRIGHT' : u'Copyright Askbot, 2010-2011.',
|
||||
'APP_DESCRIPTION' : u'Open source question and answer forum written in Python and Django',
|
||||
'APP_KEYWORDS' : u'Askbot,CNPROG,forum,community',
|
||||
'APP_SHORT_NAME' : u'Askbot',
|
||||
'APP_TITLE' : u'Askbot: Open Source Q&A Forum',
|
||||
'APP_URL' : u'http://askbot.org',
|
||||
'FEEDBACK_SITE_URL' : u'',
|
||||
'ENABLE_GREETING_FOR_ANON_USER' : True,
|
||||
'GREETING_FOR_ANONYMOUS_USER' : u'First time here? Check out the FAQ!',
|
||||
},
|
||||
'REP_CHANGES' : {
|
||||
'MAX_REP_GAIN_PER_USER_PER_DAY' : 200,
|
||||
'REP_GAIN_FOR_ACCEPTING_ANSWER' : 2,
|
||||
'REP_GAIN_FOR_CANCELING_DOWNVOTE' : 1,
|
||||
'REP_GAIN_FOR_RECEIVING_ANSWER_ACCEPTANCE' : 15,
|
||||
'REP_GAIN_FOR_RECEIVING_DOWNVOTE_CANCELATION' : 2,
|
||||
'REP_GAIN_FOR_RECEIVING_UPVOTE' : 10,
|
||||
'REP_LOSS_FOR_CANCELING_ANSWER_ACCEPTANCE' : -2,
|
||||
'REP_LOSS_FOR_DOWNVOTING' : -2,
|
||||
'REP_LOSS_FOR_RECEIVING_CANCELATION_OF_ANSWER_ACCEPTANCE' : -5,
|
||||
'REP_LOSS_FOR_RECEIVING_DOWNVOTE' : -1,
|
||||
'REP_LOSS_FOR_RECEIVING_FIVE_FLAGS_PER_REVISION' : -100,
|
||||
'REP_LOSS_FOR_RECEIVING_FLAG' : -2,
|
||||
'REP_LOSS_FOR_RECEIVING_THREE_FLAGS_PER_REVISION' : -30,
|
||||
'REP_LOSS_FOR_RECEIVING_UPVOTE_CANCELATION' : -10,
|
||||
},
|
||||
'SOCIAL_SHARING' : {
|
||||
'ENABLE_SHARING_TWITTER' : False,
|
||||
'ENABLE_SHARING_FACEBOOK' : False,
|
||||
'ENABLE_SHARING_LINKEDIN' : False,
|
||||
'ENABLE_SHARING_IDENTICA' : False,
|
||||
'ENABLE_SHARING_GOOGLE' : False,
|
||||
},
|
||||
'SIDEBAR_MAIN' : {
|
||||
'SIDEBAR_MAIN_AVATAR_LIMIT' : 16,
|
||||
'SIDEBAR_MAIN_FOOTER' : u'',
|
||||
'SIDEBAR_MAIN_HEADER' : u'',
|
||||
'SIDEBAR_MAIN_SHOW_AVATARS' : True,
|
||||
'SIDEBAR_MAIN_SHOW_TAGS' : True,
|
||||
'SIDEBAR_MAIN_SHOW_TAG_SELECTOR' : True,
|
||||
},
|
||||
'SIDEBAR_PROFILE' : {
|
||||
'SIDEBAR_PROFILE_FOOTER' : u'',
|
||||
'SIDEBAR_PROFILE_HEADER' : u'',
|
||||
},
|
||||
'SIDEBAR_QUESTION' : {
|
||||
'SIDEBAR_QUESTION_FOOTER' : u'',
|
||||
'SIDEBAR_QUESTION_HEADER' : u'',
|
||||
'SIDEBAR_QUESTION_SHOW_META' : True,
|
||||
'SIDEBAR_QUESTION_SHOW_RELATED' : True,
|
||||
'SIDEBAR_QUESTION_SHOW_TAGS' : True,
|
||||
},
|
||||
'SITE_MODES' : {
|
||||
'ACTIVATE_BOOTSTRAP_MODE' : False,
|
||||
},
|
||||
'SKIN_COUNTER_SETTINGS' : {
|
||||
|
||||
},
|
||||
'SPAM_AND_MODERATION' : {
|
||||
'AKISMET_API_KEY' : u'',
|
||||
'USE_AKISMET' : False,
|
||||
},
|
||||
'USER_SETTINGS' : {
|
||||
'EDITABLE_SCREEN_NAME' : False,
|
||||
'EDITABLE_EMAIL' : False,
|
||||
'ALLOW_ADD_REMOVE_LOGIN_METHODS' : False,
|
||||
'ENABLE_GRAVATAR' : False,
|
||||
'GRAVATAR_TYPE' : u'identicon',
|
||||
'NAME_OF_ANONYMOUS_USER' : u'',
|
||||
'DEFAULT_AVATAR_URL' : u'/images/nophoto.png',
|
||||
'MIN_USERNAME_LENGTH' : 1,
|
||||
'ALLOW_ACCOUNT_RECOVERY_BY_EMAIL' : True,
|
||||
},
|
||||
'VOTE_RULES' : {
|
||||
'MAX_VOTES_PER_USER_PER_DAY' : 30,
|
||||
'MAX_FLAGS_PER_USER_PER_DAY' : 5,
|
||||
'MIN_DAYS_FOR_STAFF_TO_ACCEPT_ANSWER' : 7,
|
||||
'MIN_DAYS_TO_ANSWER_OWN_QUESTION' : 0,
|
||||
'MIN_FLAGS_TO_DELETE_POST' : 5,
|
||||
'MIN_FLAGS_TO_HIDE_POST' : 3,
|
||||
'MAX_DAYS_TO_CANCEL_VOTE' : 1,
|
||||
'VOTES_LEFT_WARNING_THRESHOLD' : 5,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
# Celery Settings
|
||||
BROKER_TRANSPORT = "djkombu.transport.DatabaseTransport"
|
||||
CELERY_ALWAYS_EAGER = True
|
||||
|
||||
ot = MAKO_TEMPLATES
|
||||
MAKO_TEMPLATES['course'] = [DATA_DIR]
|
||||
MAKO_TEMPLATES['sections'] = [DATA_DIR+'/sections']
|
||||
MAKO_TEMPLATES['custom_tags'] = [DATA_DIR+'/custom_tags']
|
||||
MAKO_TEMPLATES['main'] = [BASE_DIR+'/templates/']
|
||||
|
||||
|
||||
MAKO_TEMPLATES.update(ot)
|
||||
|
||||
if MAKO_MODULE_DIR == None:
|
||||
MAKO_MODULE_DIR = tempfile.mkdtemp('mako')
|
||||
|
||||
djcelery.setup_loader()
|
||||
|
||||
4
settings2/README.txt
Normal file
4
settings2/README.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
Transitional for moving to new settings scheme.
|
||||
|
||||
To use:
|
||||
django-admin runserver --settings=settings2.dev --pythonpath="."
|
||||
0
settings2/__init__.py
Normal file
0
settings2/__init__.py
Normal file
287
settings2/askbotsettings.py
Normal file
287
settings2/askbotsettings.py
Normal file
@@ -0,0 +1,287 @@
|
||||
# askbot livesettings
|
||||
LIVESETTINGS_OPTIONS = {
|
||||
1: {
|
||||
'DB' : False,
|
||||
'SETTINGS' : {
|
||||
'ACCESS_CONTROL' : {
|
||||
'ASKBOT_CLOSED_FORUM_MODE' : True,
|
||||
},
|
||||
'BADGES' : {
|
||||
'DISCIPLINED_BADGE_MIN_UPVOTES' : 3,
|
||||
'PEER_PRESSURE_BADGE_MIN_DOWNVOTES' : 3,
|
||||
'TEACHER_BADGE_MIN_UPVOTES' : 1,
|
||||
'NICE_ANSWER_BADGE_MIN_UPVOTES' : 2,
|
||||
'GOOD_ANSWER_BADGE_MIN_UPVOTES' : 3,
|
||||
'GREAT_ANSWER_BADGE_MIN_UPVOTES' : 5,
|
||||
'NICE_QUESTION_BADGE_MIN_UPVOTES' : 2,
|
||||
'GOOD_QUESTION_BADGE_MIN_UPVOTES' : 3,
|
||||
'GREAT_QUESTION_BADGE_MIN_UPVOTES' : 5,
|
||||
'POPULAR_QUESTION_BADGE_MIN_VIEWS' : 150,
|
||||
'NOTABLE_QUESTION_BADGE_MIN_VIEWS' : 250,
|
||||
'FAMOUS_QUESTION_BADGE_MIN_VIEWS' : 500,
|
||||
'SELF_LEARNER_BADGE_MIN_UPVOTES' : 1,
|
||||
'CIVIC_DUTY_BADGE_MIN_VOTES' : 100,
|
||||
'ENLIGHTENED_BADGE_MIN_UPVOTES' : 3,
|
||||
'ASSOCIATE_EDITOR_BADGE_MIN_EDITS' : 20,
|
||||
'COMMENTATOR_BADGE_MIN_COMMENTS' : 10,
|
||||
'ENTHUSIAST_BADGE_MIN_DAYS' : 30,
|
||||
'FAVORITE_QUESTION_BADGE_MIN_STARS' : 3,
|
||||
'GURU_BADGE_MIN_UPVOTES' : 5,
|
||||
'NECROMANCER_BADGE_MIN_DELAY' : 30,
|
||||
'NECROMANCER_BADGE_MIN_UPVOTES' : 1,
|
||||
'STELLAR_QUESTION_BADGE_MIN_STARS' : 5,
|
||||
'TAXONOMIST_BADGE_MIN_USE_COUNT' : 10,
|
||||
},
|
||||
'EMAIL' : {
|
||||
'EMAIL_SUBJECT_PREFIX' : u'[Django] ',
|
||||
'EMAIL_UNIQUE' : True,
|
||||
'EMAIL_VALIDATION' : False,
|
||||
'DEFAULT_NOTIFICATION_DELIVERY_SCHEDULE_M_AND_C' : u'w',
|
||||
'DEFAULT_NOTIFICATION_DELIVERY_SCHEDULE_Q_ALL' : u'w',
|
||||
'DEFAULT_NOTIFICATION_DELIVERY_SCHEDULE_Q_ANS' : u'w',
|
||||
'DEFAULT_NOTIFICATION_DELIVERY_SCHEDULE_Q_ASK' : u'w',
|
||||
'DEFAULT_NOTIFICATION_DELIVERY_SCHEDULE_Q_SEL' : u'w',
|
||||
'ENABLE_UNANSWERED_REMINDERS' : False,
|
||||
'DAYS_BEFORE_SENDING_UNANSWERED_REMINDER' : 1,
|
||||
'UNANSWERED_REMINDER_FREQUENCY' : 1,
|
||||
'MAX_UNANSWERED_REMINDERS' : 5,
|
||||
'ENABLE_ACCEPT_ANSWER_REMINDERS' : False,
|
||||
'DAYS_BEFORE_SENDING_ACCEPT_ANSWER_REMINDER' : 3,
|
||||
'ACCEPT_ANSWER_REMINDER_FREQUENCY' : 3,
|
||||
'MAX_ACCEPT_ANSWER_REMINDERS' : 5,
|
||||
'ANONYMOUS_USER_EMAIL' : u'anonymous@askbot.org',
|
||||
'ALLOW_ASKING_BY_EMAIL' : False,
|
||||
'REPLACE_SPACE_WITH_DASH_IN_EMAILED_TAGS' : True,
|
||||
'MAX_ALERTS_PER_EMAIL' : 7,
|
||||
},
|
||||
'EMBEDDABLE_WIDGETS' : {
|
||||
'QUESTIONS_WIDGET_CSS' : u"\nbody {\n overflow: hidden;\n}\n#container {\n width: 200px;\n height: 350px;\n}\nul {\n list-style: none;\n padding: 5px;\n margin: 5px;\n}\nli {\n border-bottom: #CCC 1px solid;\n padding-bottom: 5px;\n padding-top: 5px;\n}\nli:last-child {\n border: none;\n}\na {\n text-decoration: none;\n color: #464646;\n font-family: 'Yanone Kaffeesatz', sans-serif;\n font-size: 15px;\n}\n",
|
||||
'QUESTIONS_WIDGET_FOOTER' : u"\n<link \n href='http://fonts.googleapis.com/css?family=Yanone+Kaffeesatz:300,400,700'\n rel='stylesheet'\n type='text/css'\n>\n",
|
||||
'QUESTIONS_WIDGET_HEADER' : u'',
|
||||
'QUESTIONS_WIDGET_MAX_QUESTIONS' : 7,
|
||||
},
|
||||
'EXTERNAL_KEYS' : {
|
||||
'RECAPTCHA_KEY' : u'',
|
||||
'RECAPTCHA_SECRET' : u'',
|
||||
'FACEBOOK_KEY' : u'',
|
||||
'FACEBOOK_SECRET' : u'',
|
||||
'HOW_TO_CHANGE_LDAP_PASSWORD' : u'',
|
||||
'IDENTICA_KEY' : u'',
|
||||
'IDENTICA_SECRET' : u'',
|
||||
'GOOGLE_ANALYTICS_KEY' : u'',
|
||||
'GOOGLE_SITEMAP_CODE' : u'',
|
||||
'LDAP_PROVIDER_NAME' : u'',
|
||||
'LDAP_URL' : u'',
|
||||
'LINKEDIN_KEY' : u'',
|
||||
'LINKEDIN_SECRET' : u'',
|
||||
'TWITTER_KEY' : u'',
|
||||
'TWITTER_SECRET' : u'',
|
||||
'USE_LDAP_FOR_PASSWORD_LOGIN' : False,
|
||||
'USE_RECAPTCHA' : False,
|
||||
},
|
||||
'FLATPAGES' : {
|
||||
'FORUM_ABOUT' : u'',
|
||||
'FORUM_FAQ' : u'',
|
||||
'FORUM_PRIVACY' : u'',
|
||||
},
|
||||
'FORUM_DATA_RULES' : {
|
||||
'MIN_TITLE_LENGTH' : 1,
|
||||
'MIN_QUESTION_BODY_LENGTH' : 1,
|
||||
'MIN_ANSWER_BODY_LENGTH' : 1,
|
||||
'WIKI_ON' : True,
|
||||
'ALLOW_ASK_ANONYMOUSLY' : True,
|
||||
'ALLOW_POSTING_BEFORE_LOGGING_IN' : True,
|
||||
'ALLOW_SWAPPING_QUESTION_WITH_ANSWER' : False,
|
||||
'MAX_TAG_LENGTH' : 20,
|
||||
'MIN_TITLE_LENGTH' : 1,
|
||||
'MIN_QUESTION_BODY_LENGTH' : 1,
|
||||
'MIN_ANSWER_BODY_LENGTH' : 1,
|
||||
'MANDATORY_TAGS' : u'',
|
||||
'FORCE_LOWERCASE_TAGS' : False,
|
||||
'TAG_LIST_FORMAT' : u'list',
|
||||
'USE_WILDCARD_TAGS' : False,
|
||||
'MAX_COMMENTS_TO_SHOW' : 5,
|
||||
'MAX_COMMENT_LENGTH' : 300,
|
||||
'USE_TIME_LIMIT_TO_EDIT_COMMENT' : True,
|
||||
'MINUTES_TO_EDIT_COMMENT' : 10,
|
||||
'SAVE_COMMENT_ON_ENTER' : True,
|
||||
'MIN_SEARCH_WORD_LENGTH' : 4,
|
||||
'DECOUPLE_TEXT_QUERY_FROM_SEARCH_STATE' : False,
|
||||
'MAX_TAGS_PER_POST' : 5,
|
||||
'DEFAULT_QUESTIONS_PAGE_SIZE' : u'30',
|
||||
'UNANSWERED_QUESTION_MEANING' : u'NO_ACCEPTED_ANSWERS',
|
||||
|
||||
# Enabling video requires forked version of markdown
|
||||
# pip uninstall markdown2
|
||||
# pip install -e git+git://github.com/andryuha/python-markdown2.git#egg=markdown2
|
||||
'ENABLE_VIDEO_EMBEDDING' : False,
|
||||
},
|
||||
'GENERAL_SKIN_SETTINGS' : {
|
||||
'CUSTOM_CSS' : u'',
|
||||
'CUSTOM_FOOTER' : u'',
|
||||
'CUSTOM_HEADER' : u'',
|
||||
'CUSTOM_HTML_HEAD' : u'',
|
||||
'CUSTOM_JS' : u'',
|
||||
'SITE_FAVICON' : u'/images/favicon.gif',
|
||||
'SITE_LOGO_URL' : u'/images/logo.gif',
|
||||
'SHOW_LOGO' : False,
|
||||
'LOCAL_LOGIN_ICON' : u'/images/pw-login.gif',
|
||||
'ALWAYS_SHOW_ALL_UI_FUNCTIONS' : False,
|
||||
'ASKBOT_DEFAULT_SKIN' : u'default',
|
||||
'USE_CUSTOM_HTML_HEAD' : False,
|
||||
'FOOTER_MODE' : u'default',
|
||||
'USE_CUSTOM_CSS' : False,
|
||||
'USE_CUSTOM_JS' : False,
|
||||
},
|
||||
'LEADING_SIDEBAR' : {
|
||||
'ENABLE_LEADING_SIDEBAR' : False,
|
||||
'LEADING_SIDEBAR' : u'',
|
||||
},
|
||||
'LOGIN_PROVIDERS' : {
|
||||
'PASSWORD_REGISTER_SHOW_PROVIDER_BUTTONS' : True,
|
||||
'SIGNIN_ALWAYS_SHOW_LOCAL_LOGIN' : True,
|
||||
'SIGNIN_AOL_ENABLED' : True,
|
||||
'SIGNIN_BLOGGER_ENABLED' : True,
|
||||
'SIGNIN_CLAIMID_ENABLED' : True,
|
||||
'SIGNIN_FACEBOOK_ENABLED' : True,
|
||||
'SIGNIN_FLICKR_ENABLED' : True,
|
||||
'SIGNIN_GOOGLE_ENABLED' : True,
|
||||
'SIGNIN_IDENTI.CA_ENABLED' : True,
|
||||
'SIGNIN_LINKEDIN_ENABLED' : True,
|
||||
'SIGNIN_LIVEJOURNAL_ENABLED' : True,
|
||||
'SIGNIN_LOCAL_ENABLED' : True,
|
||||
'SIGNIN_OPENID_ENABLED' : True,
|
||||
'SIGNIN_TECHNORATI_ENABLED' : True,
|
||||
'SIGNIN_TWITTER_ENABLED' : True,
|
||||
'SIGNIN_VERISIGN_ENABLED' : True,
|
||||
'SIGNIN_VIDOOP_ENABLED' : True,
|
||||
'SIGNIN_WORDPRESS_ENABLED' : True,
|
||||
'SIGNIN_WORDPRESS_SITE_ENABLED' : False,
|
||||
'SIGNIN_YAHOO_ENABLED' : True,
|
||||
'WORDPRESS_SITE_ICON' : u'/images/logo.gif',
|
||||
'WORDPRESS_SITE_URL' : '',
|
||||
},
|
||||
'LICENSE_SETTINGS' : {
|
||||
'LICENSE_ACRONYM' : u'cc-by-sa',
|
||||
'LICENSE_LOGO_URL' : u'/images/cc-by-sa.png',
|
||||
'LICENSE_TITLE' : u'Creative Commons Attribution Share Alike 3.0',
|
||||
'LICENSE_URL' : 'http://creativecommons.org/licenses/by-sa/3.0/legalcode',
|
||||
'LICENSE_USE_LOGO' : True,
|
||||
'LICENSE_USE_URL' : True,
|
||||
'USE_LICENSE' : True,
|
||||
},
|
||||
'MARKUP' : {
|
||||
'MARKUP_CODE_FRIENDLY' : False,
|
||||
'ENABLE_MATHJAX' : False, # FIXME: Test with this enabled
|
||||
'MATHJAX_BASE_URL' : u'',
|
||||
'ENABLE_AUTO_LINKING' : False,
|
||||
'AUTO_LINK_PATTERNS' : u'',
|
||||
'AUTO_LINK_URLS' : u'',
|
||||
},
|
||||
'MIN_REP' : {
|
||||
'MIN_REP_TO_ACCEPT_OWN_ANSWER' : 1,
|
||||
'MIN_REP_TO_ANSWER_OWN_QUESTION' : 1,
|
||||
'MIN_REP_TO_CLOSE_OTHERS_QUESTIONS' : 100,
|
||||
'MIN_REP_TO_CLOSE_OWN_QUESTIONS' : 1,
|
||||
'MIN_REP_TO_DELETE_OTHERS_COMMENTS' : 2000,
|
||||
'MIN_REP_TO_DELETE_OTHERS_POSTS' : 5000,
|
||||
'MIN_REP_TO_EDIT_OTHERS_POSTS' : 2000,
|
||||
'MIN_REP_TO_EDIT_WIKI' : 1,
|
||||
'MIN_REP_TO_FLAG_OFFENSIVE' : 1,
|
||||
'MIN_REP_TO_HAVE_STRONG_URL' : 250,
|
||||
'MIN_REP_TO_LEAVE_COMMENTS' : 1,
|
||||
'MIN_REP_TO_LOCK_POSTS' : 4000,
|
||||
'MIN_REP_TO_REOPEN_OWN_QUESTIONS' : 1,
|
||||
'MIN_REP_TO_RETAG_OTHERS_QUESTIONS' : 1,
|
||||
'MIN_REP_TO_UPLOAD_FILES' : 1,
|
||||
'MIN_REP_TO_VIEW_OFFENSIVE_FLAGS' : 2000,
|
||||
'MIN_REP_TO_VOTE_DOWN' : 1,
|
||||
'MIN_REP_TO_VOTE_UP' : 1,
|
||||
},
|
||||
'QA_SITE_SETTINGS' : {
|
||||
'APP_COPYRIGHT' : u'Copyright Askbot, 2010-2011.',
|
||||
'APP_DESCRIPTION' : u'Open source question and answer forum written in Python and Django',
|
||||
'APP_KEYWORDS' : u'Askbot,CNPROG,forum,community',
|
||||
'APP_SHORT_NAME' : u'Askbot',
|
||||
'APP_TITLE' : u'Askbot: Open Source Q&A Forum',
|
||||
'APP_URL' : u'http://askbot.org',
|
||||
'FEEDBACK_SITE_URL' : u'',
|
||||
'ENABLE_GREETING_FOR_ANON_USER' : True,
|
||||
'GREETING_FOR_ANONYMOUS_USER' : u'First time here? Check out the FAQ!',
|
||||
},
|
||||
'REP_CHANGES' : {
|
||||
'MAX_REP_GAIN_PER_USER_PER_DAY' : 200,
|
||||
'REP_GAIN_FOR_ACCEPTING_ANSWER' : 2,
|
||||
'REP_GAIN_FOR_CANCELING_DOWNVOTE' : 1,
|
||||
'REP_GAIN_FOR_RECEIVING_ANSWER_ACCEPTANCE' : 15,
|
||||
'REP_GAIN_FOR_RECEIVING_DOWNVOTE_CANCELATION' : 2,
|
||||
'REP_GAIN_FOR_RECEIVING_UPVOTE' : 10,
|
||||
'REP_LOSS_FOR_CANCELING_ANSWER_ACCEPTANCE' : -2,
|
||||
'REP_LOSS_FOR_DOWNVOTING' : -2,
|
||||
'REP_LOSS_FOR_RECEIVING_CANCELATION_OF_ANSWER_ACCEPTANCE' : -5,
|
||||
'REP_LOSS_FOR_RECEIVING_DOWNVOTE' : -1,
|
||||
'REP_LOSS_FOR_RECEIVING_FIVE_FLAGS_PER_REVISION' : -100,
|
||||
'REP_LOSS_FOR_RECEIVING_FLAG' : -2,
|
||||
'REP_LOSS_FOR_RECEIVING_THREE_FLAGS_PER_REVISION' : -30,
|
||||
'REP_LOSS_FOR_RECEIVING_UPVOTE_CANCELATION' : -10,
|
||||
},
|
||||
'SOCIAL_SHARING' : {
|
||||
'ENABLE_SHARING_TWITTER' : False,
|
||||
'ENABLE_SHARING_FACEBOOK' : False,
|
||||
'ENABLE_SHARING_LINKEDIN' : False,
|
||||
'ENABLE_SHARING_IDENTICA' : False,
|
||||
'ENABLE_SHARING_GOOGLE' : False,
|
||||
},
|
||||
'SIDEBAR_MAIN' : {
|
||||
'SIDEBAR_MAIN_AVATAR_LIMIT' : 16,
|
||||
'SIDEBAR_MAIN_FOOTER' : u'',
|
||||
'SIDEBAR_MAIN_HEADER' : u'',
|
||||
'SIDEBAR_MAIN_SHOW_AVATARS' : True,
|
||||
'SIDEBAR_MAIN_SHOW_TAGS' : True,
|
||||
'SIDEBAR_MAIN_SHOW_TAG_SELECTOR' : True,
|
||||
},
|
||||
'SIDEBAR_PROFILE' : {
|
||||
'SIDEBAR_PROFILE_FOOTER' : u'',
|
||||
'SIDEBAR_PROFILE_HEADER' : u'',
|
||||
},
|
||||
'SIDEBAR_QUESTION' : {
|
||||
'SIDEBAR_QUESTION_FOOTER' : u'',
|
||||
'SIDEBAR_QUESTION_HEADER' : u'',
|
||||
'SIDEBAR_QUESTION_SHOW_META' : True,
|
||||
'SIDEBAR_QUESTION_SHOW_RELATED' : True,
|
||||
'SIDEBAR_QUESTION_SHOW_TAGS' : True,
|
||||
},
|
||||
'SITE_MODES' : {
|
||||
'ACTIVATE_BOOTSTRAP_MODE' : False,
|
||||
},
|
||||
'SKIN_COUNTER_SETTINGS' : {
|
||||
|
||||
},
|
||||
'SPAM_AND_MODERATION' : {
|
||||
'AKISMET_API_KEY' : u'',
|
||||
'USE_AKISMET' : False,
|
||||
},
|
||||
'USER_SETTINGS' : {
|
||||
'EDITABLE_SCREEN_NAME' : False,
|
||||
'EDITABLE_EMAIL' : False,
|
||||
'ALLOW_ADD_REMOVE_LOGIN_METHODS' : False,
|
||||
'ENABLE_GRAVATAR' : False,
|
||||
'GRAVATAR_TYPE' : u'identicon',
|
||||
'NAME_OF_ANONYMOUS_USER' : u'',
|
||||
'DEFAULT_AVATAR_URL' : u'/images/nophoto.png',
|
||||
'MIN_USERNAME_LENGTH' : 1,
|
||||
'ALLOW_ACCOUNT_RECOVERY_BY_EMAIL' : True,
|
||||
},
|
||||
'VOTE_RULES' : {
|
||||
'MAX_VOTES_PER_USER_PER_DAY' : 30,
|
||||
'MAX_FLAGS_PER_USER_PER_DAY' : 5,
|
||||
'MIN_DAYS_FOR_STAFF_TO_ACCEPT_ANSWER' : 7,
|
||||
'MIN_DAYS_TO_ANSWER_OWN_QUESTION' : 0,
|
||||
'MIN_FLAGS_TO_DELETE_POST' : 5,
|
||||
'MIN_FLAGS_TO_HIDE_POST' : 3,
|
||||
'MAX_DAYS_TO_CANCEL_VOTE' : 1,
|
||||
'VOTES_LEFT_WARNING_THRESHOLD' : 5,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
18
settings2/aws.py
Normal file
18
settings2/aws.py
Normal file
@@ -0,0 +1,18 @@
|
||||
from common import *
|
||||
|
||||
EMAIL_BACKEND = 'django_ses.SESBackend'
|
||||
SESSION_ENGINE = 'django.contrib.sessions.backends.cache'
|
||||
DEFAULT_FILE_STORAGE = 'storages.backends.s3boto.S3BotoStorage'
|
||||
|
||||
CSRF_COOKIE_DOMAIN = '.mitx.mit.edu'
|
||||
LIB_URL = 'https://mitxstatic.s3.amazonaws.com/js/'
|
||||
BOOK_URL = 'https://mitxstatic.s3.amazonaws.com/book_images/'
|
||||
|
||||
CACHES = {
|
||||
'default': {
|
||||
'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG = False
|
||||
TEMPLATE_DEBUG = False
|
||||
348
settings2/common.py
Normal file
348
settings2/common.py
Normal file
@@ -0,0 +1,348 @@
|
||||
"""
|
||||
This is the common settings file, intended to set sane defaults. If you have a
|
||||
piece of configuration that's dependent on a set of feature flags being set,
|
||||
then create a function that returns the calculated value based on the value of
|
||||
MITX_FEATURES[...]. That classes that extend this one can change the feature
|
||||
configuration in an environment specific config file and re-calculate those
|
||||
values.
|
||||
|
||||
We should make a method that calls all these config methods so that you just
|
||||
make one call at the end of your site-specific dev file and it reset all the
|
||||
dependent variables (like INSTALLED_APPS) for you.
|
||||
|
||||
TODO:
|
||||
1. Right now our treatment of static content in general and in particular
|
||||
course-specific static content is haphazard.
|
||||
2. We should have a more disciplined approach to feature flagging, even if it
|
||||
just means that we stick them in a dict called MITX_FEATURES.
|
||||
3. We need to handle configuration for multiple courses. This could be as
|
||||
multiple sites, but we do need a way to map their data assets.
|
||||
"""
|
||||
import os
|
||||
import platform
|
||||
import sys
|
||||
import tempfile
|
||||
|
||||
import djcelery
|
||||
from path import path
|
||||
|
||||
from askbotsettings import LIVESETTINGS_OPTIONS
|
||||
|
||||
################################### FEATURES ###################################
|
||||
COURSEWARE_ENABLED = True
|
||||
ASKBOT_ENABLED = True
|
||||
GENERATE_RANDOM_USER_CREDENTIALS = False
|
||||
PERFSTATS = False
|
||||
|
||||
# Features
|
||||
MITX_FEATURES = {
|
||||
'SAMPLE' : False
|
||||
}
|
||||
|
||||
############################# SET PATH INFORMATION #############################
|
||||
PROJECT_ROOT = path(__file__).abspath().dirname().dirname() # /mitxweb
|
||||
ENV_ROOT = PROJECT_ROOT.dirname() # virtualenv dir /mitxweb is in
|
||||
#ASKBOT_ROOT = ENV_ROOT / "3rdparty" / "askbot-devel"
|
||||
ASKBOT_ROOT = ENV_ROOT / "askbot-devel"
|
||||
#COURSES_ROOT = ENV_ROOT / "courses"
|
||||
COURSES_ROOT = ENV_ROOT / "data"
|
||||
|
||||
# FIXME: code shouldn't expect trailing "/"
|
||||
# FIXME: To support multiple courses, we should walk the courses dir at startup
|
||||
#DATA_DIR = COURSES_ROOT / "6002x" / ""
|
||||
DATA_DIR = COURSES_ROOT
|
||||
|
||||
#print DATA_DIR, COURSES_ROOT, ASKBOT_ROOT, ENV_ROOT, PROJECT_ROOT
|
||||
|
||||
sys.path.append(ENV_ROOT)
|
||||
sys.path.append(ASKBOT_ROOT)
|
||||
sys.path.append(ASKBOT_ROOT / "askbot" / "deps")
|
||||
sys.path.append(PROJECT_ROOT / 'djangoapps')
|
||||
sys.path.append(PROJECT_ROOT / 'lib')
|
||||
|
||||
################################## MITXWEB #####################################
|
||||
# This is where we stick our compiled template files
|
||||
MAKO_MODULE_DIR = tempfile.mkdtemp('mako')
|
||||
MAKO_TEMPLATES = {}
|
||||
MAKO_TEMPLATES['course'] = [DATA_DIR]
|
||||
MAKO_TEMPLATES['sections'] = [DATA_DIR+'/sections']
|
||||
MAKO_TEMPLATES['custom_tags'] = [DATA_DIR+'/custom_tags']
|
||||
MAKO_TEMPLATES['main'] = [ENV_ROOT+'/templates/']
|
||||
|
||||
TEXTBOOK_DIR = ENV_ROOT / "books" / "circuits_agarwal_lang"
|
||||
|
||||
# FIXME ???????? --
|
||||
# We should have separate S3 staged URLs in case we need to make changes to
|
||||
# these assets and test them.
|
||||
LIB_URL = '/static/lib/'
|
||||
# LIB_URL = 'https://mitxstatic.s3.amazonaws.com/js/' # For AWS deploys
|
||||
|
||||
# Dev machines shouldn't need the book
|
||||
# BOOK_URL = '/static/book/'
|
||||
BOOK_URL = 'https://mitxstatic.s3.amazonaws.com/book_images/' # For AWS deploys
|
||||
|
||||
# FIXME ??????? What are these exactly?
|
||||
# Configuration option for when we want to grab server error pages
|
||||
STATIC_GRAB = False
|
||||
DEV_CONTENT = True
|
||||
|
||||
# FIXME: Should we be doing this truncation?
|
||||
TRACK_MAX_EVENT = 1000
|
||||
|
||||
GENERATE_PROFILE_SCORES = False
|
||||
|
||||
############################### DJANGO BUILT-INS ###############################
|
||||
# Change DEBUG/TEMPLATE_DEBUG in your environment settings files, not here
|
||||
DEBUG = False
|
||||
TEMPLATE_DEBUG = False
|
||||
|
||||
# Site info
|
||||
SITE_ID = 1
|
||||
SITE_NAME = "localhost:8000"
|
||||
CSRF_COOKIE_DOMAIN = '127.0.0.1'
|
||||
HTTPS = 'on'
|
||||
#ROOT_URLCONF = 'mitxweb.urls'
|
||||
ROOT_URLCONF = 'mitx.urls'
|
||||
|
||||
# Email
|
||||
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
|
||||
DEFAULT_FROM_EMAIL = 'registration@mitx.mit.edu'
|
||||
DEFAULT_FEEDBACK_EMAIL = 'feedback@mitx.mit.edu'
|
||||
ADMINS = (
|
||||
('MITx Admins', 'admin@mitx.mit.edu'),
|
||||
)
|
||||
MANAGERS = ADMINS
|
||||
|
||||
# Static content
|
||||
STATIC_URL = '/static/'
|
||||
ADMIN_MEDIA_PREFIX = '/static/admin/'
|
||||
STATIC_ROOT = ENV_ROOT / "staticfiles" # FIXME: Should this and uploads be moved out of the repo?
|
||||
|
||||
# FIXME: We should iterate through the courses we have, adding the static
|
||||
# contents for each of them.
|
||||
STATICFILES_DIRS = (
|
||||
# FIXME: Need to add entries for book, data/images, etc.
|
||||
# PROJECT_ROOT / "static",
|
||||
ENV_ROOT / "static",
|
||||
ASKBOT_ROOT / "askbot" / "skins",
|
||||
# ("circuits", DATA_DIR / "images"),
|
||||
# ("handouts", DATA_DIR / "handouts"),
|
||||
# ("subs", DATA_DIR / "subs"),
|
||||
# ("book", TEXTBOOK_DIR)
|
||||
)
|
||||
|
||||
print STATICFILES_DIRS
|
||||
|
||||
# Templates
|
||||
TEMPLATE_DIRS = (
|
||||
ENV_ROOT / "templates",
|
||||
# PROJECT_ROOT / "templates",
|
||||
# DATA_DIR / "problems",
|
||||
)
|
||||
|
||||
TEMPLATE_CONTEXT_PROCESSORS = (
|
||||
'django.core.context_processors.request',
|
||||
'askbot.context.application_settings',
|
||||
#'django.core.context_processors.i18n',
|
||||
'askbot.user_messages.context_processors.user_messages',#must be before auth
|
||||
'django.core.context_processors.auth', #this is required for admin
|
||||
'django.core.context_processors.csrf', #necessary for csrf protection
|
||||
)
|
||||
|
||||
# Storage
|
||||
DEFAULT_FILE_STORAGE = 'django.core.files.storage.FileSystemStorage'
|
||||
MEDIA_ROOT = ENV_ROOT / "uploads"
|
||||
MEDIA_URL = "/discussion/upfiles/"
|
||||
FILE_UPLOAD_TEMP_DIR = os.path.join(os.path.dirname(__file__), 'tmp').replace('\\','/')
|
||||
FILE_UPLOAD_HANDLERS = (
|
||||
'django.core.files.uploadhandler.MemoryFileUploadHandler',
|
||||
'django.core.files.uploadhandler.TemporaryFileUploadHandler',
|
||||
)
|
||||
|
||||
# Locale/Internationalization
|
||||
TIME_ZONE = 'America/New_York' # http://en.wikipedia.org/wiki/List_of_tz_zones_by_name
|
||||
LANGUAGE_CODE = 'en' # http://www.i18nguy.com/unicode/language-identifiers.html
|
||||
USE_I18N = True
|
||||
USE_L10N = True
|
||||
|
||||
################################### LOGGING ####################################
|
||||
# Might want to rewrite this to use logger code and push more things to the root
|
||||
# logger.
|
||||
pid = os.getpid() # So we can log which process is creating the log
|
||||
hostname = platform.node().split(".")[0]
|
||||
SYSLOG_ADDRESS = ('syslog.m.i4x.org', 514)
|
||||
|
||||
handlers = ['console']
|
||||
# FIXME: re-enable syslogger later
|
||||
# if not DEBUG:
|
||||
# handlers.append('syslogger')
|
||||
|
||||
LOGGING = {
|
||||
'version': 1,
|
||||
'disable_existing_loggers': True,
|
||||
'formatters' : {
|
||||
'standard' : {
|
||||
'format' : '%(asctime)s %(levelname)s %(process)d [%(name)s] %(filename)s:%(lineno)d - %(message)s',
|
||||
},
|
||||
'syslog_format' : {
|
||||
'format' : '[%(name)s] %(levelname)s [' + hostname + ' %(process)d] [%(filename)s:%(lineno)d] - %(message)s',
|
||||
},
|
||||
'raw' : {
|
||||
'format' : '%(message)s',
|
||||
}
|
||||
},
|
||||
'handlers' : {
|
||||
'console' : {
|
||||
'level' : 'DEBUG',
|
||||
'class' : 'logging.StreamHandler',
|
||||
'formatter' : 'standard',
|
||||
'stream' : sys.stdout,
|
||||
},
|
||||
'console_err' : {
|
||||
'level' : 'ERROR',
|
||||
'class' : 'logging.StreamHandler',
|
||||
'formatter' : 'standard',
|
||||
'stream' : sys.stderr,
|
||||
},
|
||||
'syslogger' : {
|
||||
'level' : 'INFO',
|
||||
'class' : 'logging.handlers.SysLogHandler',
|
||||
'address' : SYSLOG_ADDRESS,
|
||||
'formatter' : 'syslog_format',
|
||||
},
|
||||
'mail_admins' : {
|
||||
'level': 'ERROR',
|
||||
'class': 'django.utils.log.AdminEmailHandler',
|
||||
},
|
||||
},
|
||||
'loggers' : {
|
||||
'django' : {
|
||||
'handlers' : handlers + ['mail_admins'],
|
||||
'propagate' : True,
|
||||
'level' : 'INFO'
|
||||
},
|
||||
'tracking' : {
|
||||
'handlers' : [] if DEBUG else ['syslogger'], # handlers,
|
||||
'level' : 'DEBUG',
|
||||
'propagate' : False,
|
||||
},
|
||||
'root' : {
|
||||
'handlers' : handlers,
|
||||
'level' : 'DEBUG',
|
||||
'propagate' : False
|
||||
},
|
||||
'mitx' : {
|
||||
'handlers' : handlers,
|
||||
'level' : 'DEBUG',
|
||||
'propagate' : False
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
#################################### AWS #######################################
|
||||
# S3BotoStorage insists on a timeout for uploaded assets. We should make it
|
||||
# permanent instead, but rather than trying to figure out exactly where that
|
||||
# setting is, I'm just bumping the expiration time to something absurd (100
|
||||
# years). This is only used if DEFAULT_FILE_STORAGE is overriden to use S3
|
||||
# in the global settings.py
|
||||
AWS_QUERYSTRING_EXPIRE = 10 * 365 * 24 * 60 * 60 # 10 years
|
||||
|
||||
################################### ASKBOT #####################################
|
||||
ASKBOT_EXTRA_SKINS_DIR = ASKBOT_ROOT / "askbot" / "skins"
|
||||
ASKBOT_ALLOWED_UPLOAD_FILE_TYPES = ('.jpg', '.jpeg', '.gif', '.bmp', '.png', '.tiff')
|
||||
ASKBOT_MAX_UPLOAD_FILE_SIZE = 1024 * 1024 # result in bytes
|
||||
|
||||
CACHE_MIDDLEWARE_ANONYMOUS_ONLY = True
|
||||
ASKBOT_URL = 'discussion/'
|
||||
LOGIN_REDIRECT_URL = '/'
|
||||
LOGIN_URL = '/'
|
||||
|
||||
ALLOW_UNICODE_SLUGS = False
|
||||
ASKBOT_USE_STACKEXCHANGE_URLS = False # mimic url scheme of stackexchange
|
||||
ASKBOT_CSS_DEVEL = True
|
||||
|
||||
# Celery Settings
|
||||
BROKER_TRANSPORT = "djkombu.transport.DatabaseTransport"
|
||||
CELERY_ALWAYS_EAGER = True
|
||||
djcelery.setup_loader()
|
||||
|
||||
################################# SIMPLEWIKI ###################################
|
||||
WIKI_REQUIRE_LOGIN_EDIT = True
|
||||
WIKI_REQUIRE_LOGIN_VIEW = True
|
||||
|
||||
################################# Middleware ###################################
|
||||
# List of finder classes that know how to find static files in
|
||||
# various locations.
|
||||
STATICFILES_FINDERS = (
|
||||
'django.contrib.staticfiles.finders.FileSystemFinder',
|
||||
'django.contrib.staticfiles.finders.AppDirectoriesFinder',
|
||||
)
|
||||
|
||||
# List of callables that know how to import templates from various sources.
|
||||
TEMPLATE_LOADERS = (
|
||||
'django.template.loaders.filesystem.Loader',
|
||||
'django.template.loaders.app_directories.Loader',
|
||||
'askbot.skins.loaders.filesystem_load_template_source',
|
||||
# 'django.template.loaders.eggs.Loader',
|
||||
)
|
||||
|
||||
MIDDLEWARE_CLASSES = (
|
||||
'util.middleware.ExceptionLoggingMiddleware',
|
||||
'django.middleware.common.CommonMiddleware',
|
||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||
'django.middleware.csrf.CsrfViewMiddleware',
|
||||
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
||||
'django.contrib.messages.middleware.MessageMiddleware',
|
||||
'track.middleware.TrackMiddleware',
|
||||
'mitxmako.middleware.MakoMiddleware',
|
||||
# 'debug_toolbar.middleware.DebugToolbarMiddleware',
|
||||
'askbot.middleware.anon_user.ConnectToSessionMessagesMiddleware',
|
||||
'askbot.middleware.forum_mode.ForumModeMiddleware',
|
||||
'askbot.middleware.cancel.CancelActionMiddleware',
|
||||
'django.middleware.transaction.TransactionMiddleware',
|
||||
'askbot.middleware.view_log.ViewLogMiddleware',
|
||||
'askbot.middleware.spaceless.SpacelessMiddleware',
|
||||
# 'askbot.middleware.pagesize.QuestionsPageSizeMiddleware',
|
||||
)
|
||||
|
||||
################################### APPS #######################################
|
||||
def installed_apps():
|
||||
"""If you want to get a different set of INSTALLED_APPS out of this, you'll
|
||||
have to set ASKBOT_ENABLED and COURSEWARE_ENABLED to True/False and call
|
||||
this method. We can't just take these as params because other pieces of the
|
||||
code check fo the value of these constants.
|
||||
"""
|
||||
# We always install these
|
||||
STANDARD_APPS = ['django.contrib.auth',
|
||||
'django.contrib.contenttypes',
|
||||
'django.contrib.humanize',
|
||||
'django.contrib.sessions',
|
||||
'django.contrib.sites',
|
||||
'django.contrib.messages',
|
||||
'django.contrib.staticfiles',
|
||||
'track',
|
||||
'util']
|
||||
COURSEWARE_APPS = ['circuit',
|
||||
'courseware',
|
||||
'student',
|
||||
'static_template_view',
|
||||
'staticbook',
|
||||
'simplewiki',
|
||||
'perfstats']
|
||||
ASKBOT_APPS = ['django.contrib.sitemaps',
|
||||
'django.contrib.admin',
|
||||
'south',
|
||||
'askbot.deps.livesettings',
|
||||
'askbot',
|
||||
'keyedcache',
|
||||
'robots',
|
||||
'django_countries',
|
||||
'djcelery',
|
||||
'djkombu',
|
||||
'followit']
|
||||
|
||||
return tuple(STANDARD_APPS +
|
||||
(COURSEWARE_APPS if COURSEWARE_ENABLED else []) +
|
||||
(ASKBOT_APPS if ASKBOT_ENABLED else []))
|
||||
|
||||
INSTALLED_APPS = installed_apps()
|
||||
28
settings2/dev.py
Normal file
28
settings2/dev.py
Normal file
@@ -0,0 +1,28 @@
|
||||
"""
|
||||
This config file runs the simplest dev environment using sqlite, and db-based
|
||||
sessions.
|
||||
"""
|
||||
from common import *
|
||||
|
||||
CSRF_COOKIE_DOMAIN = 'localhost'
|
||||
|
||||
DATABASES = {
|
||||
'default': {
|
||||
'ENGINE': 'django.db.backends.sqlite3',
|
||||
'NAME': ENV_ROOT / "db" / "mitx.db",
|
||||
}
|
||||
}
|
||||
|
||||
# Make this unique, and don't share it with anybody.
|
||||
SECRET_KEY = '85920908f28904ed733fe576320db18cabd7b6cd'
|
||||
|
||||
DEBUG = True
|
||||
TEMPLATE_DEBUG = False
|
||||
|
||||
# This is disabling ASKBOT, but not properly overwriting INSTALLED_APPS. ???
|
||||
# It's because our ASKBOT_ENABLED here is actually shadowing the real one.
|
||||
#
|
||||
# ASKBOT_ENABLED = True
|
||||
# MITX_FEATURES['SAMPLE'] = True # Switch to this system so we get around the shadowing
|
||||
#
|
||||
# INSTALLED_APPS = installed_apps()
|
||||
35
settings2/devplus.py
Normal file
35
settings2/devplus.py
Normal file
@@ -0,0 +1,35 @@
|
||||
"""
|
||||
This config file tries to mimic the production environment more closely than the
|
||||
normal dev.py. It assumes you're running a local instance of MySQL 5.1 and that
|
||||
you're running memcached.
|
||||
"""
|
||||
from common import *
|
||||
|
||||
CSRF_COOKIE_DOMAIN = 'localhost'
|
||||
|
||||
DATABASES = {
|
||||
'default': {
|
||||
'ENGINE': 'django.db.backends.mysql', # Add 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'.
|
||||
'NAME': 'wwc', # Or path to database file if using sqlite3.
|
||||
'USER': 'root', # Not used with sqlite3.
|
||||
'PASSWORD': '', # Not used with sqlite3.
|
||||
'HOST': '127.0.0.1', # Set to empty string for localhost. Not used with sqlite3.
|
||||
'PORT': '3306', # Set to empty string for default. Not used with sqlite3.
|
||||
}
|
||||
}
|
||||
|
||||
# Make this unique, and don't share it with anybody.
|
||||
SECRET_KEY = '85920908f28904ed733fe576320db18cabd7b6cd'
|
||||
|
||||
CACHES = {
|
||||
'default': {
|
||||
'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
|
||||
'LOCATION': '127.0.0.1:11211',
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
SESSION_ENGINE = 'django.contrib.sessions.backends.cache'
|
||||
|
||||
DEBUG = True
|
||||
TEMPLATE_DEBUG = True
|
||||
3
settings2/loadtest.py
Normal file
3
settings2/loadtest.py
Normal file
@@ -0,0 +1,3 @@
|
||||
from common import *
|
||||
|
||||
GENERATE_RANDOM_USER_CREDENTIALS = True
|
||||
13
settings2/staging.py
Normal file
13
settings2/staging.py
Normal file
@@ -0,0 +1,13 @@
|
||||
from aws import *
|
||||
|
||||
# Staging specific overrides
|
||||
SITE_NAME = "staging.mitx.mit.edu"
|
||||
AWS_STORAGE_BUCKET_NAME = 'mitx_askbot_stage'
|
||||
CACHES['default']['LOCATION'] = ['***REMOVED***',
|
||||
'***REMOVED***']
|
||||
|
||||
### Secure Data Below Here ###
|
||||
SECRET_KEY = ""
|
||||
AWS_ACCESS_KEY_ID = ""
|
||||
AWS_SECRET_ACCESS_KEY = ""
|
||||
|
||||
@@ -1,392 +0,0 @@
|
||||
import os
|
||||
import platform
|
||||
import sys
|
||||
import tempfile
|
||||
|
||||
import djcelery
|
||||
|
||||
# Configuration option for when we want to grab server error pages
|
||||
STATIC_GRAB = False
|
||||
DEV_CONTENT = True
|
||||
|
||||
LIB_URL = '/static/lib/'
|
||||
LIB_URL = 'https://mitxstatic.s3.amazonaws.com/js/'
|
||||
BOOK_URL = '/static/book/'
|
||||
BOOK_URL = 'https://mitxstatic.s3.amazonaws.com/book_images/'
|
||||
|
||||
# Feature Flags. These should be set to false until they are ready to deploy, and then eventually flag mechanisms removed
|
||||
GENERATE_PROFILE_SCORES = False # If this is true, random scores will be generated for the purpose of debugging the profile graphs
|
||||
|
||||
# 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
|
||||
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
|
||||
SITE_NAME = "localhost:8000"
|
||||
|
||||
DEFAULT_FROM_EMAIL = 'registration@mitx.mit.edu'
|
||||
DEFAULT_FEEDBACK_EMAIL = 'feedback@mitx.mit.edu'
|
||||
|
||||
GENERATE_RANDOM_USER_CREDENTIALS = False
|
||||
|
||||
WIKI_REQUIRE_LOGIN_EDIT = True
|
||||
WIKI_REQUIRE_LOGIN_VIEW = True
|
||||
|
||||
PERFSTATS = False
|
||||
|
||||
HTTPS = 'on'
|
||||
|
||||
MEDIA_URL = ''
|
||||
MEDIA_ROOT = ''
|
||||
|
||||
# S3BotoStorage insists on a timeout for uploaded assets. We should make it
|
||||
# permanent instead, but rather than trying to figure out exactly where that
|
||||
# setting is, I'm just bumping the expiration time to something absurd (100
|
||||
# years). This is only used if DEFAULT_FILE_STORAGE is overriden to use S3
|
||||
# in the global settings.py
|
||||
AWS_QUERYSTRING_EXPIRE = 10 * 365 * 24 * 60 * 60 # 10 years
|
||||
|
||||
# Needed for Askbot
|
||||
# Deployed machines: Move to S3
|
||||
DEFAULT_FILE_STORAGE = 'django.core.files.storage.FileSystemStorage'
|
||||
|
||||
DEBUG = True
|
||||
TEMPLATE_DEBUG = DEBUG
|
||||
|
||||
ADMINS = (
|
||||
('Piotr Mitros', 'staff@csail.mit.edu'),
|
||||
)
|
||||
|
||||
MANAGERS = ADMINS
|
||||
|
||||
# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name
|
||||
TIME_ZONE = 'America/New_York'
|
||||
|
||||
# Language code for this installation. All choices can be found here:
|
||||
# http://www.i18nguy.com/unicode/language-identifiers.html
|
||||
LANGUAGE_CODE = 'en'
|
||||
|
||||
SITE_ID = 1
|
||||
|
||||
# If you set this to False, Django will make some optimizations so as not
|
||||
# to load the internationalization machinery.
|
||||
USE_I18N = True
|
||||
|
||||
# If you set this to False, Django will not format dates, numbers and
|
||||
# calendars according to the current locale
|
||||
USE_L10N = True
|
||||
|
||||
STATIC_URL = '/static/'
|
||||
|
||||
# URL prefix for admin static files -- CSS, JavaScript and images.
|
||||
# Make sure to use a trailing slash.
|
||||
# Examples: "http://foo.com/static/admin/", "/static/admin/".
|
||||
ADMIN_MEDIA_PREFIX = '/static/admin/'
|
||||
|
||||
# List of finder classes that know how to find static files in
|
||||
# various locations.
|
||||
STATICFILES_FINDERS = (
|
||||
'django.contrib.staticfiles.finders.FileSystemFinder',
|
||||
'django.contrib.staticfiles.finders.AppDirectoriesFinder',
|
||||
# 'django.contrib.staticfiles.finders.DefaultStorageFinder',
|
||||
)
|
||||
|
||||
# List of callables that know how to import templates from various sources.
|
||||
TEMPLATE_LOADERS = (
|
||||
'django.template.loaders.filesystem.Loader',
|
||||
'django.template.loaders.app_directories.Loader',
|
||||
# 'django.template.loaders.eggs.Loader',
|
||||
)
|
||||
|
||||
MIDDLEWARE_CLASSES = (
|
||||
'django.middleware.common.CommonMiddleware',
|
||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||
'django.middleware.csrf.CsrfViewMiddleware',
|
||||
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
||||
'django.contrib.messages.middleware.MessageMiddleware',
|
||||
'track.middleware.TrackMiddleware',
|
||||
'mitxmako.middleware.MakoMiddleware',
|
||||
#'debug_toolbar.middleware.DebugToolbarMiddleware',
|
||||
)
|
||||
|
||||
ROOT_URLCONF = 'mitx.urls'
|
||||
|
||||
INSTALLED_APPS = (
|
||||
'django.contrib.auth',
|
||||
'django.contrib.contenttypes',
|
||||
'django.contrib.sessions',
|
||||
'django.contrib.sites',
|
||||
'django.contrib.messages',
|
||||
'django.contrib.staticfiles',
|
||||
'courseware',
|
||||
'student',
|
||||
'django.contrib.humanize',
|
||||
'static_template_view',
|
||||
'staticbook',
|
||||
'simplewiki',
|
||||
'track',
|
||||
'circuit',
|
||||
'perfstats',
|
||||
'util',
|
||||
# Uncomment the next line to enable the admin:
|
||||
# 'django.contrib.admin',
|
||||
# Uncomment the next line to enable admin documentation:
|
||||
# 'django.contrib.admindocs',
|
||||
)
|
||||
|
||||
#TRACK_DIR = None
|
||||
DEBUG_TRACK_LOG = False
|
||||
# Maximum length of a tracking string. We don't want e.g. a file upload in our log
|
||||
TRACK_MAX_EVENT = 1000
|
||||
# Maximum length of log file before starting a new one.
|
||||
MAXLOG = 500
|
||||
|
||||
LOG_DIR = "/tmp/"
|
||||
MAKO_MODULE_DIR = None
|
||||
|
||||
# Make sure we execute correctly regardless of where we're called from
|
||||
execfile(os.path.join(BASE_DIR, "settings.py"))
|
||||
|
||||
if MAKO_MODULE_DIR == None:
|
||||
MAKO_MODULE_DIR = tempfile.mkdtemp('mako')
|
||||
|
||||
# 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.
|
||||
|
||||
pid = os.getpid()
|
||||
hostname = platform.node().split(".")[0]
|
||||
SYSLOG_ADDRESS = ('syslog.m.i4x.org', 514)
|
||||
|
||||
handlers = ['console']
|
||||
if not DEBUG:
|
||||
handlers.append('syslogger')
|
||||
|
||||
LOGGING = {
|
||||
'version': 1,
|
||||
'disable_existing_loggers': True,
|
||||
'formatters' : {
|
||||
'standard' : {
|
||||
'format' : '%(asctime)s %(levelname)s %(process)d [%(name)s] %(filename)s:%(lineno)d - %(message)s',
|
||||
},
|
||||
'syslog_format' : {
|
||||
'format' : '[%(name)s] %(levelname)s [' + hostname + ' %(process)d] [%(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,
|
||||
},
|
||||
'syslogger' : {
|
||||
'level' : 'INFO',
|
||||
'class' : 'logging.handlers.SysLogHandler',
|
||||
'address' : SYSLOG_ADDRESS,
|
||||
'formatter' : 'syslog_format',
|
||||
},
|
||||
'mail_admins' : {
|
||||
'level': 'ERROR',
|
||||
'class': 'django.utils.log.AdminEmailHandler',
|
||||
},
|
||||
},
|
||||
'loggers' : {
|
||||
'django' : {
|
||||
'handlers' : handlers + ['mail_admins'],
|
||||
'propagate' : True,
|
||||
'level' : 'INFO'
|
||||
},
|
||||
'tracking' : {
|
||||
'handlers' : [] if DEBUG else ['syslogger'], # handlers,
|
||||
'level' : 'DEBUG',
|
||||
'propagate' : False,
|
||||
},
|
||||
'root' : {
|
||||
'handlers' : handlers,
|
||||
'level' : 'DEBUG',
|
||||
'propagate' : False
|
||||
},
|
||||
'mitx' : {
|
||||
'handlers' : handlers,
|
||||
'level' : 'DEBUG',
|
||||
'propagate' : False
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
if PERFSTATS :
|
||||
MIDDLEWARE_CLASSES = ( 'perfstats.middleware.ProfileMiddleware',) + MIDDLEWARE_CLASSES
|
||||
|
||||
if 'TRACK_DIR' not in locals():
|
||||
TRACK_DIR = BASE_DIR+'/track_dir/'
|
||||
if 'STATIC_ROOT' not in locals():
|
||||
STATIC_ROOT = BASE_DIR+'/staticroot/'
|
||||
if 'DATA_DIR' not in locals():
|
||||
DATA_DIR = BASE_DIR+'/data/'
|
||||
if 'TEXTBOOK_DIR' not in locals():
|
||||
TEXTBOOK_DIR = BASE_DIR+'/textbook/'
|
||||
|
||||
if 'TEMPLATE_DIRS' not in locals():
|
||||
TEMPLATE_DIRS = (
|
||||
BASE_DIR+'/templates/',
|
||||
DATA_DIR+'/templates',
|
||||
TEXTBOOK_DIR,
|
||||
)
|
||||
|
||||
if 'STATICFILES_DIRS' not in locals():
|
||||
STATICFILES_DIRS = (
|
||||
BASE_DIR+'/3rdParty/static',
|
||||
BASE_DIR+'/static',
|
||||
)
|
||||
|
||||
|
||||
if 'ASKBOT_EXTRA_SKINS_DIR' not in locals():
|
||||
ASKBOT_EXTRA_SKINS_DIR = BASE_DIR+'/askbot-devel/askbot/skins'
|
||||
if 'ASKBOT_DIR' not in locals():
|
||||
ASKBOT_DIR = BASE_DIR+'/askbot-devel'
|
||||
|
||||
sys.path.append(ASKBOT_DIR)
|
||||
import askbot
|
||||
import site
|
||||
|
||||
STATICFILES_DIRS = STATICFILES_DIRS + ( ASKBOT_DIR+'/askbot/skins',)
|
||||
|
||||
ASKBOT_ROOT = os.path.dirname(askbot.__file__)
|
||||
|
||||
# Needed for Askbot
|
||||
# Deployed machines: Move to S3
|
||||
if MEDIA_ROOT == '':
|
||||
MEDIA_ROOT = ASKBOT_DIR+'/askbot/upfiles'
|
||||
if MEDIA_URL == '':
|
||||
MEDIA_URL = '/discussion/upfiles/'
|
||||
|
||||
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',
|
||||
'django.middleware.transaction.TransactionMiddleware',
|
||||
#'debug_toolbar.middleware.DebugToolbarMiddleware',
|
||||
'askbot.middleware.view_log.ViewLogMiddleware',
|
||||
'askbot.middleware.spaceless.SpacelessMiddleware',
|
||||
# 'askbot.middleware.pagesize.QuestionsPageSizeMiddleware',
|
||||
)
|
||||
|
||||
FILE_UPLOAD_TEMP_DIR = os.path.join(os.path.dirname(__file__), 'tmp').replace('\\','/')
|
||||
FILE_UPLOAD_HANDLERS = (
|
||||
'django.core.files.uploadhandler.MemoryFileUploadHandler',
|
||||
'django.core.files.uploadhandler.TemporaryFileUploadHandler',
|
||||
)
|
||||
ASKBOT_ALLOWED_UPLOAD_FILE_TYPES = ('.jpg', '.jpeg', '.gif', '.bmp', '.png', '.tiff')
|
||||
ASKBOT_MAX_UPLOAD_FILE_SIZE = 1024 * 1024 #result in bytes
|
||||
# ASKBOT_FILE_UPLOAD_DIR = os.path.join(os.path.dirname(__file__), 'askbot', 'upfiles')
|
||||
|
||||
PROJECT_ROOT = os.path.dirname(__file__)
|
||||
|
||||
TEMPLATE_CONTEXT_PROCESSORS = (
|
||||
'django.core.context_processors.request',
|
||||
'askbot.context.application_settings',
|
||||
#'django.core.context_processors.i18n',
|
||||
'askbot.user_messages.context_processors.user_messages',#must be before auth
|
||||
'django.core.context_processors.auth', #this is required for admin
|
||||
'django.core.context_processors.csrf', #necessary for csrf protection
|
||||
)
|
||||
|
||||
INSTALLED_APPS = INSTALLED_APPS + (
|
||||
'django.contrib.sitemaps',
|
||||
'django.contrib.admin',
|
||||
'south',
|
||||
'askbot.deps.livesettings',
|
||||
'askbot',
|
||||
#'keyedcache', # TODO: Main askbot tree has this installed, but we get intermittent errors if we include it.
|
||||
'robots',
|
||||
'django_countries',
|
||||
'djcelery',
|
||||
'djkombu',
|
||||
'followit',
|
||||
)
|
||||
|
||||
# askbot livesettings
|
||||
LIVESETTINGS_OPTIONS = {
|
||||
1: {
|
||||
'SETTINGS' : {
|
||||
'FORUM_DATA_RULES' : {
|
||||
'MIN_TITLE_LENGTH' : 1,
|
||||
'MIN_QUESTION_BODY_LENGTH' : 1,
|
||||
'MIN_ANSWER_BODY_LENGTH' : 1,
|
||||
|
||||
# 'ENABLE_VIDEO_EMBEDDING' : True,
|
||||
#
|
||||
# Enabling video requires forked version of markdown
|
||||
# pip uninstall markdown2
|
||||
# pip install -e git+git://github.com/andryuha/python-markdown2.git#egg=markdown2
|
||||
},
|
||||
'MIN_REP' : {
|
||||
'MIN_REP_TO_VOTE_UP' : 1,
|
||||
'MIN_REP_TO_VOTE_DOWN' : 1,
|
||||
'MIN_REP_TO_ANSWER_OWN_QUESTION' : 1,
|
||||
'MIN_REP_TO_ACCEPT_OWN_ANSWER' : 1,
|
||||
'MIN_REP_TO_FLAG_OFFENSIVE' : 1,
|
||||
'MIN_REP_TO_LEAVE_COMMENTS' : 1,
|
||||
'MIN_REP_TO_CLOSE_OWN_QUESTIONS' : 1,
|
||||
'MIN_REP_TO_RETAG_OTHERS_QUESTIONS' : 1,
|
||||
'MIN_REP_TO_REOPEN_OWN_QUESTIONS' : 1,
|
||||
'MIN_REP_TO_EDIT_WIKI' : 1,
|
||||
'MIN_REP_TO_CLOSE_OTHERS_QUESTIONS' : 100,
|
||||
'MIN_REP_TO_UPLOAD_FILES' : 1,
|
||||
},
|
||||
'SOCIAL_SHARING' : {
|
||||
'ENABLE_SHARING_TWITTER' : False,
|
||||
'ENABLE_SHARING_FACEBOOK' : False,
|
||||
'ENABLE_SHARING_LINKEDIN' : False,
|
||||
'ENABLE_SHARING_IDENTICA' : False,
|
||||
'ENABLE_SHARING_GOOGLE' : False,
|
||||
},
|
||||
'USER_SETTINGS' : {
|
||||
'EDITABLE_SCREEN_NAME' : False,
|
||||
'EDITABLE_EMAIL' : False,
|
||||
'ALLOW_ADD_REMOVE_LOGIN_METHODS' : False,
|
||||
'ENABLE_GRAVATAR' : False,
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
CACHE_MIDDLEWARE_ANONYMOUS_ONLY = True
|
||||
ASKBOT_URL = 'discussion/'
|
||||
LOGIN_REDIRECT_URL = '/'
|
||||
LOGIN_URL = '/'
|
||||
|
||||
# ASKBOT_UPLOADED_FILES_URL = '%s%s' % (ASKBOT_URL, 'upfiles/')
|
||||
ALLOW_UNICODE_SLUGS = False
|
||||
ASKBOT_USE_STACKEXCHANGE_URLS = False #mimic url scheme of stackexchange
|
||||
ASKBOT_CSS_DEVEL = True
|
||||
|
||||
# Celery Settings
|
||||
BROKER_TRANSPORT = "djkombu.transport.DatabaseTransport"
|
||||
CELERY_ALWAYS_EAGER = True
|
||||
|
||||
djcelery.setup_loader()
|
||||
|
||||
@@ -1,245 +0,0 @@
|
||||
if 'COURSEWARE_ENABLED' not in locals():
|
||||
COURSEWARE_ENABLED = True
|
||||
if 'ASKBOT_ENABLED' not in locals():
|
||||
ASKBOT_ENABLED = True
|
||||
if not COURSEWARE_ENABLED:
|
||||
ASKBOT_ENABLED = False
|
||||
|
||||
# Defaults to be overridden
|
||||
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
|
||||
SITE_NAME = "localhost:8000"
|
||||
|
||||
DEFAULT_FROM_EMAIL = 'registration@mitx.mit.edu'
|
||||
DEFAULT_FEEDBACK_EMAIL = 'feedback@mitx.mit.edu'
|
||||
|
||||
# For testing the login system
|
||||
GENERATE_RANDOM_USER_CREDENTIALS = False
|
||||
|
||||
WIKI_REQUIRE_LOGIN_EDIT = True
|
||||
WIKI_REQUIRE_LOGIN_VIEW = True
|
||||
|
||||
PERFSTATS = False
|
||||
|
||||
HTTPS = 'on'
|
||||
|
||||
DEBUG = True
|
||||
TEMPLATE_DEBUG = DEBUG
|
||||
|
||||
ADMINS = (
|
||||
('Piotr Mitros', 'staff@csail.mit.edu'),
|
||||
)
|
||||
|
||||
MANAGERS = ADMINS
|
||||
|
||||
# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name
|
||||
TIME_ZONE = 'America/Chicago'
|
||||
|
||||
# Language code for this installation. All choices can be found here:
|
||||
# http://www.i18nguy.com/unicode/language-identifiers.html
|
||||
LANGUAGE_CODE = 'en'
|
||||
|
||||
SITE_ID = 1
|
||||
|
||||
# If you set this to False, Django will make some optimizations so as not
|
||||
# to load the internationalization machinery.
|
||||
USE_I18N = True
|
||||
|
||||
# If you set this to False, Django will not format dates, numbers and
|
||||
# calendars according to the current locale
|
||||
USE_L10N = True
|
||||
|
||||
#MEDIA_ROOT = ''
|
||||
#MEDIA_URL = ''
|
||||
|
||||
STATIC_URL = '/static/'
|
||||
|
||||
# URL prefix for admin static files -- CSS, JavaScript and images.
|
||||
# Make sure to use a trailing slash.
|
||||
# Examples: "http://foo.com/static/admin/", "/static/admin/".
|
||||
ADMIN_MEDIA_PREFIX = '/static/admin/'
|
||||
|
||||
|
||||
# List of finder classes that know how to find static files in
|
||||
# various locations.
|
||||
STATICFILES_FINDERS = (
|
||||
'django.contrib.staticfiles.finders.FileSystemFinder',
|
||||
'django.contrib.staticfiles.finders.AppDirectoriesFinder',
|
||||
# 'django.contrib.staticfiles.finders.DefaultStorageFinder',
|
||||
)
|
||||
|
||||
# List of callables that know how to import templates from various sources.
|
||||
TEMPLATE_LOADERS = (
|
||||
'django.template.loaders.filesystem.Loader',
|
||||
'django.template.loaders.app_directories.Loader',
|
||||
# 'django.template.loaders.eggs.Loader',
|
||||
)
|
||||
|
||||
MIDDLEWARE_CLASSES = (
|
||||
'django.middleware.common.CommonMiddleware',
|
||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||
'django.middleware.csrf.CsrfViewMiddleware',
|
||||
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
||||
'django.contrib.messages.middleware.MessageMiddleware',
|
||||
'track.middleware.TrackMiddleware',
|
||||
'mitxmako.middleware.MakoMiddleware',
|
||||
#'debug_toolbar.middleware.DebugToolbarMiddleware',
|
||||
)
|
||||
|
||||
ROOT_URLCONF = 'mitx.urls'
|
||||
|
||||
INSTALLED_APPS = (
|
||||
'django.contrib.auth',
|
||||
'django.contrib.contenttypes',
|
||||
'django.contrib.sessions',
|
||||
'django.contrib.sites',
|
||||
'django.contrib.messages',
|
||||
'django.contrib.staticfiles',
|
||||
'courseware',
|
||||
'auth',
|
||||
'django.contrib.humanize',
|
||||
'static_template_view',
|
||||
'staticbook',
|
||||
'simplewiki',
|
||||
'track',
|
||||
'circuit',
|
||||
'perfstats',
|
||||
# Uncomment the next line to enable the admin:
|
||||
# 'django.contrib.admin',
|
||||
# Uncomment the next line to enable admin documentation:
|
||||
# 'django.contrib.admindocs',
|
||||
)
|
||||
|
||||
# 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': False,
|
||||
'handlers': {
|
||||
'mail_admins': {
|
||||
'level': 'ERROR',
|
||||
'class': 'django.utils.log.AdminEmailHandler'
|
||||
}
|
||||
},
|
||||
'loggers': {
|
||||
'django.request': {
|
||||
'handlers': ['mail_admins'],
|
||||
'level': 'ERROR',
|
||||
'propagate': True,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
#TRACK_DIR = None
|
||||
DEBUG_TRACK_LOG = False
|
||||
# Maximum length of a tracking string. We don't want e.g. a file upload in our log
|
||||
TRACK_MAX_EVENT = 1000
|
||||
# Maximum length of log file before starting a new one.
|
||||
MAXLOG = 500
|
||||
|
||||
execfile("../settings.py")
|
||||
|
||||
if PERFSTATS :
|
||||
MIDDLEWARE_CLASSES = ( 'perfstats.middleware.ProfileMiddleware',) + MIDDLEWARE_CLASSES
|
||||
|
||||
if 'TRACK_DIR' not in locals():
|
||||
TRACK_DIR = BASE_DIR+'/track_dir/'
|
||||
if 'ASKBOT_EXTRA_SKINS_DIR' not in locals():
|
||||
ASKBOT_EXTRA_SKINS_DIR = BASE_DIR+'/askbot/skins'
|
||||
if 'ASKBOT_DIR' not in locals():
|
||||
ASKBOT_DIR = BASE_DIR
|
||||
if 'STATIC_ROOT' not in locals():
|
||||
STATIC_ROOT = BASE_DIR+'/staticroot/'
|
||||
if 'DATA_DIR' not in locals():
|
||||
DATA_DIR = BASE_DIR+'/data/'
|
||||
if 'TEXTBOOK_DIR' not in locals():
|
||||
TEXTBOOK_DIR = BASE_DIR+'/textbook/'
|
||||
|
||||
if 'TEMPLATE_DIRS' not in locals():
|
||||
TEMPLATE_DIRS = (
|
||||
BASE_DIR+'/templates/',
|
||||
DATA_DIR+'/templates',
|
||||
TEXTBOOK_DIR,
|
||||
)
|
||||
|
||||
if 'STATICFILES_DIRS' not in locals():
|
||||
STATICFILES_DIRS = (
|
||||
BASE_DIR+'/3rdParty/static',
|
||||
BASE_DIR+'/static'
|
||||
)
|
||||
|
||||
if ASKBOT_ENABLED:
|
||||
import sys
|
||||
sys.path.append(ASKBOT_DIR)
|
||||
import os
|
||||
import askbot
|
||||
import site
|
||||
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 + (
|
||||
'askbot.middleware.anon_user.ConnectToSessionMessagesMiddleware',
|
||||
'askbot.middleware.pagesize.QuestionsPageSizeMiddleware',
|
||||
'askbot.middleware.cancel.CancelActionMiddleware',
|
||||
'django.middleware.transaction.TransactionMiddleware',
|
||||
'askbot.middleware.view_log.ViewLogMiddleware',
|
||||
'askbot.middleware.spaceless.SpacelessMiddleware',
|
||||
'askbot.middleware.forum_mode.ForumModeMiddleware',
|
||||
)
|
||||
|
||||
FILE_UPLOAD_TEMP_DIR = os.path.join(
|
||||
os.path.dirname(__file__),
|
||||
'tmp'
|
||||
).replace('\\','/')
|
||||
FILE_UPLOAD_HANDLERS = (
|
||||
'django.core.files.uploadhandler.MemoryFileUploadHandler',
|
||||
'django.core.files.uploadhandler.TemporaryFileUploadHandler',
|
||||
)
|
||||
ASKBOT_ALLOWED_UPLOAD_FILE_TYPES = ('.jpg', '.jpeg', '.gif', '.bmp', '.png', '.tiff')
|
||||
ASKBOT_MAX_UPLOAD_FILE_SIZE = 1024 * 1024 #result in bytes
|
||||
ASKBOT_FILE_UPLOAD_DIR = os.path.join(os.path.dirname(__file__), 'askbot', 'upfiles')
|
||||
DEFAULT_FILE_STORAGE = 'django.core.files.storage.FileSystemStorage'
|
||||
|
||||
PROJECT_ROOT = os.path.dirname(__file__)
|
||||
|
||||
TEMPLATE_CONTEXT_PROCESSORS = (
|
||||
'django.core.context_processors.request',
|
||||
'askbot.context.application_settings',
|
||||
#'django.core.context_processors.i18n',
|
||||
'askbot.user_messages.context_processors.user_messages',#must be before auth
|
||||
'django.core.context_processors.auth', #this is required for admin
|
||||
'django.core.context_processors.csrf', #necessary for csrf protection
|
||||
)
|
||||
|
||||
INSTALLED_APPS = INSTALLED_APPS + (
|
||||
'django.contrib.sitemaps',
|
||||
'django.contrib.admin',
|
||||
'south',
|
||||
'askbot.deps.livesettings',
|
||||
'askbot',
|
||||
#'keyedcache', # TODO: Main askbot tree has this installed, but we get intermittent errors if we include it.
|
||||
'robots',
|
||||
'django_countries',
|
||||
'djcelery',
|
||||
'djkombu',
|
||||
'followit',
|
||||
)
|
||||
|
||||
CACHE_MIDDLEWARE_ANONYMOUS_ONLY = True
|
||||
ASKBOT_URL = 'discussion/'
|
||||
LOGIN_REDIRECT_URL = '/'
|
||||
LOGIN_URL = '/'
|
||||
|
||||
ASKBOT_UPLOADED_FILES_URL = '%s%s' % (ASKBOT_URL, 'upfiles/')
|
||||
ALLOW_UNICODE_SLUGS = False
|
||||
ASKBOT_USE_STACKEXCHANGE_URLS = False #mimic url scheme of stackexchange
|
||||
ASKBOT_CSS_DEVEL = True
|
||||
|
||||
#Celery Settings
|
||||
BROKER_TRANSPORT = "djkombu.transport.DatabaseTransport"
|
||||
CELERY_ALWAYS_EAGER = True
|
||||
|
||||
import djcelery
|
||||
djcelery.setup_loader()
|
||||
@@ -9,20 +9,23 @@ from django.core.context_processors import csrf
|
||||
from django.conf import settings
|
||||
|
||||
#valid_templates=['index.html', 'staff.html', 'info.html', 'credits.html']
|
||||
valid_templates=['mitx_global.html',
|
||||
'index.html',
|
||||
valid_templates=['index.html',
|
||||
'tos.html',
|
||||
'privacy.html',
|
||||
'honor.html',
|
||||
'copyright.html',
|
||||
'404.html']
|
||||
|
||||
print "!!",settings.__dict__
|
||||
'404.html',
|
||||
'mitx_help.html']
|
||||
|
||||
if settings.STATIC_GRAB:
|
||||
valid_templates = valid_templates+['server-down.html',
|
||||
'server-error.html'
|
||||
'server-overloaded.html']
|
||||
'server-overloaded.html',
|
||||
'mitx_global.html',
|
||||
'mitx-overview.html',
|
||||
'6002x-faq.html',
|
||||
'6002x-press-release.html'
|
||||
]
|
||||
|
||||
def index(request, template):
|
||||
csrf_token = csrf(request)['csrf_token']
|
||||
|
||||
124
student/migrations/0003_auto__add_usertestgroup.py
Normal file
124
student/migrations/0003_auto__add_usertestgroup.py
Normal file
@@ -0,0 +1,124 @@
|
||||
# encoding: utf-8
|
||||
import datetime
|
||||
from south.db import db
|
||||
from south.v2 import SchemaMigration
|
||||
from django.db import models
|
||||
|
||||
class Migration(SchemaMigration):
|
||||
|
||||
def forwards(self, orm):
|
||||
|
||||
# Adding model 'UserTestGroup'
|
||||
db.create_table('student_usertestgroup', (
|
||||
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
|
||||
('name', self.gf('django.db.models.fields.CharField')(max_length=32, db_index=True)),
|
||||
('description', self.gf('django.db.models.fields.TextField')(blank=True)),
|
||||
))
|
||||
db.send_create_signal('student', ['UserTestGroup'])
|
||||
|
||||
# Adding M2M table for field users on 'UserTestGroup'
|
||||
db.create_table('student_usertestgroup_users', (
|
||||
('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
|
||||
('usertestgroup', models.ForeignKey(orm['student.usertestgroup'], null=False)),
|
||||
('user', models.ForeignKey(orm['auth.user'], null=False))
|
||||
))
|
||||
db.create_unique('student_usertestgroup_users', ['usertestgroup_id', 'user_id'])
|
||||
|
||||
|
||||
def backwards(self, orm):
|
||||
|
||||
# Deleting model 'UserTestGroup'
|
||||
db.delete_table('student_usertestgroup')
|
||||
|
||||
# Removing M2M table for field users on 'UserTestGroup'
|
||||
db.delete_table('student_usertestgroup_users')
|
||||
|
||||
|
||||
models = {
|
||||
'auth.group': {
|
||||
'Meta': {'object_name': 'Group'},
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
|
||||
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
|
||||
},
|
||||
'auth.permission': {
|
||||
'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
|
||||
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
|
||||
},
|
||||
'auth.user': {
|
||||
'Meta': {'object_name': 'User'},
|
||||
'about': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'avatar_type': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '1'}),
|
||||
'bronze': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
|
||||
'consecutive_days_visit_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'country': ('django_countries.fields.CountryField', [], {'max_length': '2', 'blank': 'True'}),
|
||||
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'date_of_birth': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'display_tag_filter_strategy': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
|
||||
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
|
||||
'email_isvalid': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'email_key': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),
|
||||
'email_tag_filter_strategy': ('django.db.models.fields.SmallIntegerField', [], {'default': '1'}),
|
||||
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'gold': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
|
||||
'gravatar': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
|
||||
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'ignored_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'interesting_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'last_seen': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'location': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
|
||||
'new_response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
|
||||
'questions_per_page': ('django.db.models.fields.SmallIntegerField', [], {'default': '10'}),
|
||||
'real_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
|
||||
'reputation': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}),
|
||||
'seen_response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'show_country': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'silver': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
|
||||
'status': ('django.db.models.fields.CharField', [], {'default': "'w'", 'max_length': '2'}),
|
||||
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}),
|
||||
'website': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'})
|
||||
},
|
||||
'contenttypes.contenttype': {
|
||||
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
|
||||
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
|
||||
},
|
||||
'student.registration': {
|
||||
'Meta': {'object_name': 'Registration', 'db_table': "'auth_registration'"},
|
||||
'activation_key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '32', 'db_index': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'unique': 'True'})
|
||||
},
|
||||
'student.userprofile': {
|
||||
'Meta': {'object_name': 'UserProfile', 'db_table': "'auth_userprofile'"},
|
||||
'courseware': ('django.db.models.fields.CharField', [], {'default': "'course.xml'", 'max_length': '255', 'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'language': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '255', 'blank': 'True'}),
|
||||
'location': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '255', 'blank': 'True'}),
|
||||
'meta': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '255', 'blank': 'True'}),
|
||||
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'unique': 'True'})
|
||||
},
|
||||
'student.usertestgroup': {
|
||||
'Meta': {'object_name': 'UserTestGroup'},
|
||||
'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '32', 'db_index': 'True'}),
|
||||
'users': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.User']", 'db_index': 'True', 'symmetrical': 'False'})
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['student']
|
||||
106
student/migrations/0004_add_email_index.py
Normal file
106
student/migrations/0004_add_email_index.py
Normal file
@@ -0,0 +1,106 @@
|
||||
# encoding: utf-8
|
||||
import datetime
|
||||
from south.db import db
|
||||
from south.v2 import SchemaMigration
|
||||
from django.db import models
|
||||
|
||||
class Migration(SchemaMigration):
|
||||
|
||||
def forwards(self, orm):
|
||||
db.execute("create unique index email on auth_user (email)")
|
||||
pass
|
||||
|
||||
|
||||
def backwards(self, orm):
|
||||
db.execute("drop index email on auth_user")
|
||||
pass
|
||||
|
||||
|
||||
models = {
|
||||
'auth.group': {
|
||||
'Meta': {'object_name': 'Group'},
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
|
||||
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
|
||||
},
|
||||
'auth.permission': {
|
||||
'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
|
||||
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
|
||||
},
|
||||
'auth.user': {
|
||||
'Meta': {'object_name': 'User'},
|
||||
'about': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'avatar_type': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '1'}),
|
||||
'bronze': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
|
||||
'consecutive_days_visit_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'country': ('django_countries.fields.CountryField', [], {'max_length': '2', 'blank': 'True'}),
|
||||
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'date_of_birth': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'display_tag_filter_strategy': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
|
||||
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
|
||||
'email_isvalid': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'email_key': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),
|
||||
'email_tag_filter_strategy': ('django.db.models.fields.SmallIntegerField', [], {'default': '1'}),
|
||||
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'gold': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
|
||||
'gravatar': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
|
||||
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'ignored_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'interesting_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'last_seen': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'location': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
|
||||
'new_response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
|
||||
'questions_per_page': ('django.db.models.fields.SmallIntegerField', [], {'default': '10'}),
|
||||
'real_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
|
||||
'reputation': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}),
|
||||
'seen_response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'show_country': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'silver': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
|
||||
'status': ('django.db.models.fields.CharField', [], {'default': "'w'", 'max_length': '2'}),
|
||||
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}),
|
||||
'website': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'})
|
||||
},
|
||||
'contenttypes.contenttype': {
|
||||
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
|
||||
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
|
||||
},
|
||||
'student.registration': {
|
||||
'Meta': {'object_name': 'Registration', 'db_table': "'auth_registration'"},
|
||||
'activation_key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '32', 'db_index': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'unique': 'True'})
|
||||
},
|
||||
'student.userprofile': {
|
||||
'Meta': {'object_name': 'UserProfile', 'db_table': "'auth_userprofile'"},
|
||||
'courseware': ('django.db.models.fields.CharField', [], {'default': "'course.xml'", 'max_length': '255', 'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'language': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '255', 'blank': 'True'}),
|
||||
'location': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '255', 'blank': 'True'}),
|
||||
'meta': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '255', 'blank': 'True'}),
|
||||
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'unique': 'True'})
|
||||
},
|
||||
'student.usertestgroup': {
|
||||
'Meta': {'object_name': 'UserTestGroup'},
|
||||
'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '32', 'db_index': 'True'}),
|
||||
'users': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.User']", 'db_index': 'True', 'symmetrical': 'False'})
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['student']
|
||||
@@ -27,6 +27,10 @@ class UserProfile(models.Model):
|
||||
meta = models.CharField(blank=True, max_length=255) # JSON dictionary for future expansion
|
||||
courseware = models.CharField(blank=True, max_length=255, default='course.xml')
|
||||
|
||||
class UserTestGroup(models.Model):
|
||||
users = models.ManyToManyField(User, db_index=True)
|
||||
name = models.CharField(blank=False, max_length=32, db_index=True)
|
||||
description = models.TextField(blank=True)
|
||||
|
||||
class Registration(models.Model):
|
||||
''' Allows us to wait for e-mail before user is registered. A
|
||||
|
||||
@@ -28,27 +28,18 @@ def csrf_token(context):
|
||||
@ensure_csrf_cookie
|
||||
def index(request):
|
||||
if settings.COURSEWARE_ENABLED and request.user.is_authenticated():
|
||||
return redirect('/courseware')
|
||||
return redirect('/info')
|
||||
else:
|
||||
csrf_token = csrf(request)['csrf_token']
|
||||
# TODO: Clean up how 'error' is done.
|
||||
return render_to_response('index.html', {'error' : '',
|
||||
'csrf': csrf_token })
|
||||
return render_to_response('index.html', {'csrf': csrf_token })
|
||||
|
||||
# def courseinfo(request):
|
||||
# if request.user.is_authenticated():
|
||||
# return redirect('/courseware')
|
||||
# else:
|
||||
# csrf_token = csrf(request)['csrf_token']
|
||||
# # TODO: Clean up how 'error' is done.
|
||||
# return render_to_response('courseinfo.html', {'error' : '',
|
||||
# 'csrf': csrf_token })
|
||||
|
||||
# Need different levels of logging
|
||||
@ensure_csrf_cookie
|
||||
def login_user(request, error=""):
|
||||
if 'email' not in request.POST or 'password' not in request.POST:
|
||||
return render_to_response('login.html', {'error':error.replace('+',' ')})
|
||||
return HttpResponse(json.dumps({'success':False,
|
||||
'error': 'Invalid login'})) # TODO: User error message
|
||||
|
||||
email = request.POST['email']
|
||||
password = request.POST['password']
|
||||
@@ -136,9 +127,15 @@ def create_account(request, post_override=None):
|
||||
# TODO: Confirm e-mail is not from a generic domain (mailinator, etc.)? Not sure if
|
||||
# this is a good idea
|
||||
# TODO: Check password is sane
|
||||
for a in ['username', 'email', 'password', 'terms_of_service', 'honor_code']:
|
||||
for a in ['username', 'email', 'name', 'password', 'terms_of_service', 'honor_code']:
|
||||
if len(post_vars[a])<2:
|
||||
js['value']="{field} is required.".format(field=a)
|
||||
error_str = {'username' : 'Username of length 2 or greater',
|
||||
'email' : 'Properly formatted e-mail',
|
||||
'name' : 'Your legal name ',
|
||||
'password': 'Valid password ',
|
||||
'terms_of_service': 'Accepting Terms of Service',
|
||||
'honor_code': 'Agreeing to the Honor Code'}
|
||||
js['value']="{field} is required.".format(field=error_str[a])
|
||||
return HttpResponse(json.dumps(js))
|
||||
|
||||
try:
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import datetime
|
||||
|
||||
# Create your views here.
|
||||
from django.http import HttpResponse
|
||||
@@ -39,6 +40,7 @@ def user_track(request):
|
||||
"event" : request.GET['event'],
|
||||
"agent" : agent,
|
||||
"page" : request.GET['page'],
|
||||
"time": datetime.datetime.utcnow().isoformat(),
|
||||
}
|
||||
log_event(event)
|
||||
return HttpResponse('success')
|
||||
@@ -62,5 +64,6 @@ def server_track(request, event_type, event, page=None):
|
||||
"event" : event,
|
||||
"agent" : agent,
|
||||
"page" : page,
|
||||
"time": datetime.datetime.utcnow().isoformat(),
|
||||
}
|
||||
log_event(event)
|
||||
|
||||
2
urls.py
2
urls.py
@@ -40,6 +40,7 @@ if settings.COURSEWARE_ENABLED:
|
||||
url(r'^courseware/(?P<course>[^/]*)/(?P<chapter>[^/]*)/(?P<section>[^/]*)/$', 'courseware.views.index', name="courseware_section"),
|
||||
url(r'^courseware/(?P<course>[^/]*)/(?P<chapter>[^/]*)/$', 'courseware.views.index', name="courseware_chapter"),
|
||||
url(r'^courseware/(?P<course>[^/]*)/$', 'courseware.views.index', name="courseware_course"),
|
||||
url(r'^section/(?P<section>[^/]*)/$', 'courseware.views.render_section'),
|
||||
url(r'^modx/(?P<module>[^/]*)/(?P<id>[^/]*)/(?P<dispatch>[^/]*)$', 'courseware.views.modx_dispatch'), #reset_problem'),
|
||||
url(r'^profile$', 'courseware.views.profile'),
|
||||
url(r'^change_setting$', 'student.views.change_setting'),
|
||||
@@ -63,3 +64,4 @@ if settings.ASKBOT_ENABLED:
|
||||
)
|
||||
|
||||
urlpatterns = patterns(*urlpatterns)
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import logging
|
||||
|
||||
from django.conf import settings
|
||||
from django.http import HttpResponse
|
||||
from django.http import HttpResponseServerError
|
||||
|
||||
log = logging.getLogger("mitx")
|
||||
|
||||
@@ -12,4 +12,4 @@ class ExceptionLoggingMiddleware(object):
|
||||
if not settings.TEMPLATE_DEBUG:
|
||||
def process_exception(self, request, exception):
|
||||
log.exception(exception)
|
||||
return HttpResponse("Server Error - Please try again later.")
|
||||
return HttpResponseServerError("Server Error - Please try again later.")
|
||||
|
||||
@@ -51,4 +51,7 @@ def send_feedback(request):
|
||||
|
||||
def info(request):
|
||||
''' Info page (link from main header) '''
|
||||
if not request.user.is_authenticated():
|
||||
return redirect('/')
|
||||
|
||||
return render_to_response("info.html", {})
|
||||
|
||||
Reference in New Issue
Block a user