Commit 5fe68e3a by Piotr Mitros

Merge to default for next developments

--HG--
branch : pmitros-mod-template
parents 8174e496 ffba3c59
...@@ -4,6 +4,7 @@ import math ...@@ -4,6 +4,7 @@ import math
import operator import operator
import numpy import numpy
import scipy.constants
from pyparsing import Word, alphas, nums, oneOf, Literal from pyparsing import Word, alphas, nums, oneOf, Literal
from pyparsing import ZeroOrMore, OneOrMore, StringStart from pyparsing import ZeroOrMore, OneOrMore, StringStart
...@@ -24,18 +25,26 @@ default_functions = {'sin' : numpy.sin, ...@@ -24,18 +25,26 @@ default_functions = {'sin' : numpy.sin,
'abs':numpy.abs 'abs':numpy.abs
} }
default_variables = {'j':numpy.complex(0,1), 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") log = logging.getLogger("mitx.courseware.capa")
def evaluator(variables, functions, string): def evaluator(variables, functions, string):
''' Evaluate an expression. Variables are passed as a dictionary ''' Evaluate an expression. Variables are passed as a dictionary
from string to value. Unary functions 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.
log.debug(u"Evaluating: {0} with vars: {1}, funcs: {2}"
.format(string, variables, functions)) 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 = copy.copy(default_variables)
all_variables.update(variables) all_variables.update(variables)
...@@ -125,7 +134,10 @@ def evaluator(variables, functions, string): ...@@ -125,7 +134,10 @@ def evaluator(variables, functions, string):
# Handle variables passed in. E.g. if we have {'R':0.5}, we make the substitution. # 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 # Special case for no variables because of how we understand PyParsing is put together
if len(all_variables)>0: 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: CaselessLiteral(x), all_variables_keys))
varnames.setParseAction(lambda x:map(lambda y:all_variables[y], x)) varnames.setParseAction(lambda x:map(lambda y:all_variables[y], x))
else: else:
varnames=NoMatch() varnames=NoMatch()
...@@ -153,7 +165,9 @@ if __name__=='__main__': ...@@ -153,7 +165,9 @@ if __name__=='__main__':
print "X",evaluator(variables, functions, "10000||sin(7+5)-6k") print "X",evaluator(variables, functions, "10000||sin(7+5)-6k")
print "X",evaluator(variables, functions, "13") print "X",evaluator(variables, functions, "13")
print evaluator({'R1': 2.0, 'R3':4.0}, {}, "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({'a': 2.2997471478310274, 'k': 9, 'm': 8, 'x': 0.66009498411213041}, {}, "5")
print evaluator({},{}, "-1") print evaluator({},{}, "-1")
print evaluator({},{}, "-(7+5)") print evaluator({},{}, "-(7+5)")
......
...@@ -19,24 +19,36 @@ global_context={'random':random, ...@@ -19,24 +19,36 @@ global_context={'random':random,
'calc':calc, 'calc':calc,
'eia':eia} '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): class numericalresponse(object):
def __init__(self, xml, context): def __init__(self, xml, context):
self.xml = xml self.xml = xml
self.correct_answer = contextualize_text(xml.get('answer'), context) self.correct_answer = contextualize_text(xml.get('answer'), context)
self.correct_answer = float(self.correct_answer) 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] id=xml.get('id'))[0]
self.tolerance = contextualize_text(self.tolerance, context) self.tolerance = contextualize_text(self.tolerance_xml, context)
self.tolerance = evaluator(dict(),dict(),self.tolerance)
self.answer_id = xml.xpath('//*[@id=$id]//textline/@id', self.answer_id = xml.xpath('//*[@id=$id]//textline/@id',
id=xml.get('id'))[0] id=xml.get('id'))[0]
def grade(self, student_answers): def grade(self, student_answers):
''' Display HTML for a numeric response ''' ''' Display HTML for a numeric response '''
student_answer = student_answers[self.answer_id] student_answer = student_answers[self.answer_id]
error = abs(evaluator(dict(),dict(),student_answer) - self.correct_answer) correct = compare_with_tolerance (evaluator(dict(),dict(),student_answer), self.correct_answer, self.tolerance)
allowed_error = abs(self.correct_answer*self.tolerance)
if error <= allowed_error: if correct:
return {self.answer_id:'correct'} return {self.answer_id:'correct'}
else: else:
return {self.answer_id:'incorrect'} return {self.answer_id:'incorrect'}
...@@ -77,10 +89,9 @@ class formularesponse(object): ...@@ -77,10 +89,9 @@ class formularesponse(object):
self.xml = xml self.xml = xml
self.correct_answer = contextualize_text(xml.get('answer'), context) self.correct_answer = contextualize_text(xml.get('answer'), context)
self.samples = contextualize_text(xml.get('samples'), 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] id=xml.get('id'))[0]
self.tolerance = contextualize_text(self.tolerance, context) self.tolerance = contextualize_text(self.tolerance_xml, context)
self.tolerance = evaluator(dict(),dict(),self.tolerance)
self.answer_id = xml.xpath('//*[@id=$id]//textline/@id', self.answer_id = xml.xpath('//*[@id=$id]//textline/@id',
id=xml.get('id'))[0] id=xml.get('id'))[0]
self.context = context self.context = context
...@@ -105,7 +116,7 @@ class formularesponse(object): ...@@ -105,7 +116,7 @@ class formularesponse(object):
student_result = evaluator(student_variables,dict(),student_answers[self.answer_id]) student_result = evaluator(student_variables,dict(),student_answers[self.answer_id])
if math.isnan(student_result) or math.isinf(student_result): if math.isnan(student_result) or math.isinf(student_result):
return {self.answer_id:"incorrect"} 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:"incorrect"}
return {self.answer_id:"correct"} return {self.answer_id:"correct"}
......
...@@ -11,6 +11,7 @@ from mako.lookup import TemplateLookup ...@@ -11,6 +11,7 @@ from mako.lookup import TemplateLookup
try: # This lets us do __name__ == ='__main__' try: # This lets us do __name__ == ='__main__'
from django.conf import settings from django.conf import settings
from student.models import UserProfile from student.models import UserProfile
from student.models import UserTestGroup
except: except:
settings = None settings = None
...@@ -149,7 +150,11 @@ def course_file(user): ...@@ -149,7 +150,11 @@ def course_file(user):
filename = UserProfile.objects.get(user=user).courseware filename = UserProfile.objects.get(user=user).courseware
data_template = template_lookup.get_template(filename) data_template = template_lookup.get_template(filename)
options = {'dev_content':settings.DEV_CONTENT} # TODO: Rewrite in Django
groups = [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])]
options = {'dev_content':settings.DEV_CONTENT,
'groups' : groups}
tree = etree.XML(data_template.render(**options)) tree = etree.XML(data_template.render(**options))
id_tag(tree) id_tag(tree)
......
...@@ -8,6 +8,7 @@ from django.contrib.auth.models import User ...@@ -8,6 +8,7 @@ from django.contrib.auth.models import User
from mitx.courseware.content_parser import course_file from mitx.courseware.content_parser import course_file
import mitx.courseware.module_render import mitx.courseware.module_render
import mitx.courseware.modules
class Command(BaseCommand): class Command(BaseCommand):
help = "Does basic validity tests on course.xml." help = "Does basic validity tests on course.xml."
...@@ -24,7 +25,7 @@ class Command(BaseCommand): ...@@ -24,7 +25,7 @@ class Command(BaseCommand):
check = False check = False
print "Confirming all modules render. Nothing should print during this step. " print "Confirming all modules render. Nothing should print during this step. "
for module in course.xpath('//problem|//html|//video|//vertical|//sequential|/tab'): 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 # TODO: Abstract this out in render_module.py
try: try:
instance=module_class(etree.tostring(module), instance=module_class(etree.tostring(module),
......
...@@ -60,8 +60,6 @@ def modx_dispatch(request, module=None, dispatch=None, id=None): ...@@ -60,8 +60,6 @@ def modx_dispatch(request, module=None, dispatch=None, id=None):
ajax_url = '/modx/'+module+'/'+id+'/' ajax_url = '/modx/'+module+'/'+id+'/'
# id_tag=courseware.modules.get_module_class(module)
# Grab the XML corresponding to the request from course.xml # Grab the XML corresponding to the request from course.xml
xml = content_parser.module_xml(content_parser.course_file(request.user), module, 'id', id) xml = content_parser.module_xml(content_parser.course_file(request.user), module, 'id', id)
...@@ -118,7 +116,10 @@ def render_x_module(user, request, xml_module, module_object_preload): ...@@ -118,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) smod.save() # This may be optional (at least in the case of no instance in the dB)
module_object_preload.append(smod) module_object_preload.append(smod)
# Grab content # 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(), "destroy_js":instance.get_destroy_js(),
'init_js':instance.get_init_js(), 'init_js':instance.get_init_js(),
'type':module_type} 'type':module_type}
......
...@@ -253,7 +253,7 @@ class Module(XModule): ...@@ -253,7 +253,7 @@ class Module(XModule):
for key in get: for key in get:
answers['_'.join(key.split('_')[1:])]=get[key] answers['_'.join(key.split('_')[1:])]=get[key]
print "XXX", answers, get # print "XXX", answers, get
event_info['answers']=answers event_info['answers']=answers
......
...@@ -27,6 +27,9 @@ class ModelsTest(unittest.TestCase): ...@@ -27,6 +27,9 @@ class ModelsTest(unittest.TestCase):
self.assertEqual(calc.evaluator({},{}, "-1"), -1) self.assertEqual(calc.evaluator({},{}, "-1"), -1)
self.assertEqual(calc.evaluator({},{}, "-0.33"), -.33) self.assertEqual(calc.evaluator({},{}, "-0.33"), -.33)
self.assertEqual(calc.evaluator({},{}, "-.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 exception_happened = False
try: try:
evaluator({},{}, "5+7 QWSEKO") evaluator({},{}, "5+7 QWSEKO")
......
import json import json
import logging import logging
import os import os
import random
import sys import sys
import StringIO import StringIO
import urllib import urllib
...@@ -41,9 +42,8 @@ def profile(request): ...@@ -41,9 +42,8 @@ def profile(request):
return redirect('/') return redirect('/')
dom=content_parser.course_file(request.user) dom=content_parser.course_file(request.user)
hw=[]
course = dom.xpath('//course/@name')[0] 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) responses=StudentModule.objects.filter(student=request.user)
response_by_id = {} response_by_id = {}
...@@ -52,8 +52,9 @@ def profile(request): ...@@ -52,8 +52,9 @@ def profile(request):
total_scores = {} total_scores = {}
chapters=[]
for c in chapters: for c in xmlChapters:
sections = []
chname=c.get('name') chname=c.get('name')
for s in dom.xpath('//course[@name=$course]/chapter[@name=$chname]/section', for s in dom.xpath('//course[@name=$course]/chapter[@name=$chname]/section',
course=course, chname=chname): course=course, chname=chname):
...@@ -71,7 +72,7 @@ def profile(request): ...@@ -71,7 +72,7 @@ def profile(request):
if response.grade!=None: if response.grade!=None:
correct=response.grade 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? 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?
scores.append((int(correct),total, graded )) scores.append((int(correct),total, graded ))
...@@ -89,9 +90,7 @@ def profile(request): ...@@ -89,9 +90,7 @@ def profile(request):
format_scores.append( graded_total ) format_scores.append( graded_total )
total_scores[ format ] = format_scores total_scores[ format ] = format_scores
score={'course':course, score={'section':s.get("name"),
'section':s.get("name"),
'chapter':c.get("name"),
'scores':scores, 'scores':scores,
'section_total' : section_total, 'section_total' : section_total,
'format' : format, 'format' : format,
...@@ -99,7 +98,12 @@ def profile(request): ...@@ -99,7 +98,12 @@ def profile(request):
'due' : s.get("due") or "", 'due' : s.get("due") or "",
'graded' : graded, 'graded' : graded,
} }
hw.append(score) sections.append(score)
chapters.append({'course':course,
'chapter' : c.get("name"),
'sections' : sections,})
def totalWithDrops(scores, drop_count): def totalWithDrops(scores, drop_count):
#Note that this key will sort the list descending #Note that this key will sort the list descending
...@@ -125,9 +129,17 @@ def profile(request): ...@@ -125,9 +129,17 @@ def profile(request):
else: else:
percentage = 0 percentage = 0
summary = "0% (?/?)" summary = "0% (?/?)"
if settings.GENERATE_PROFILE_SCORES:
points_possible = random.randrange(10, 50)
points_earned = random.randrange(5, points_possible)
percentage = points_earned / float(points_possible)
summary = "{0:.0%} ({1}/{2})".format( percentage, points_earned, points_possible )
summary = "Homework {0} - {1}".format(i + 1, summary) summary = "Homework {0} - {1}".format(i + 1, summary)
label = "HW {0:02d}".format(i + 1)
homework_percentages.append( {'percentage': percentage, 'summary': summary} ) homework_percentages.append( {'percentage': percentage, 'summary': summary, 'label' : label} )
homework_total, homework_dropped_indices = totalWithDrops(homework_percentages, 2) homework_total, homework_dropped_indices = totalWithDrops(homework_percentages, 2)
#Figure the lab scores #Figure the lab scores
...@@ -140,8 +152,17 @@ def profile(request): ...@@ -140,8 +152,17 @@ def profile(request):
else: else:
percentage = 0 percentage = 0
summary = "0% (?/?)" summary = "0% (?/?)"
if settings.GENERATE_PROFILE_SCORES:
points_possible = random.randrange(10, 50)
points_earned = random.randrange(5, points_possible)
percentage = points_earned / float(points_possible)
summary = "{0:.0%} ({1}/{2})".format( percentage, points_earned, points_possible )
summary = "Lab {0} - {1}".format(i + 1, summary) summary = "Lab {0} - {1}".format(i + 1, summary)
lab_percentages.append( {'percentage': percentage, 'summary': summary} ) label = "Lab {0:02d}".format(i + 1)
lab_percentages.append( {'percentage': percentage, 'summary': summary, 'label' : label} )
lab_total, lab_dropped_indices = totalWithDrops(lab_percentages, 2) lab_total, lab_dropped_indices = totalWithDrops(lab_percentages, 2)
...@@ -152,12 +173,21 @@ def profile(request): ...@@ -152,12 +173,21 @@ def profile(request):
final_score = ('?', '?') final_score = ('?', '?')
final_percentage = 0 final_percentage = 0
if settings.GENERATE_PROFILE_SCORES:
midterm_score = (random.randrange(50, 150), 150)
midterm_percentage = midterm_score[0] / float(midterm_score[1])
final_score = (random.randrange(100, 300), 300)
final_percentage = final_score[0] / float(final_score[1])
grade_summary = [ grade_summary = [
{ {
'category': 'Homework', 'category': 'Homework',
'subscores' : homework_percentages, 'subscores' : homework_percentages,
'dropped_indices' : homework_dropped_indices, 'dropped_indices' : homework_dropped_indices,
'totalscore' : {'score' : homework_total, 'summary' : "Homework Average - {0:.0%}".format(homework_total)}, 'totalscore' : {'score' : homework_total, 'summary' : "Homework Average - {0:.0%}".format(homework_total)},
'totallabel' : 'HW Avg',
'weight' : 0.15, 'weight' : 0.15,
}, },
{ {
...@@ -165,16 +195,19 @@ def profile(request): ...@@ -165,16 +195,19 @@ def profile(request):
'subscores' : lab_percentages, 'subscores' : lab_percentages,
'dropped_indices' : lab_dropped_indices, 'dropped_indices' : lab_dropped_indices,
'totalscore' : {'score' : lab_total, 'summary' : "Lab Average - {0:.0%}".format(lab_total)}, 'totalscore' : {'score' : lab_total, 'summary' : "Lab Average - {0:.0%}".format(lab_total)},
'totallabel' : 'Lab Avg',
'weight' : 0.15, 'weight' : 0.15,
}, },
{ {
'category': 'Midterm', 'category': 'Midterm',
'totalscore' : {'score' : midterm_percentage, 'summary' : "Midterm - {0:.0%} ({1}/{2})".format(midterm_percentage, midterm_score[0], midterm_score[1])}, 'totalscore' : {'score' : midterm_percentage, 'summary' : "Midterm - {0:.0%} ({1}/{2})".format(midterm_percentage, midterm_score[0], midterm_score[1])},
'totallabel' : 'Midterm',
'weight' : 0.30, 'weight' : 0.30,
}, },
{ {
'category': 'Final', 'category': 'Final',
'totalscore' : {'score' : final_percentage, 'summary' : "Final - {0:.0%} ({1}/{2})".format(final_percentage, final_score[0], final_score[1])}, 'totalscore' : {'score' : final_percentage, 'summary' : "Final - {0:.0%} ({1}/{2})".format(final_percentage, final_score[0], final_score[1])},
'totallabel' : 'Final',
'weight' : 0.40, 'weight' : 0.40,
} }
] ]
...@@ -186,7 +219,7 @@ def profile(request): ...@@ -186,7 +219,7 @@ def profile(request):
'location':user_info.location, 'location':user_info.location,
'language':user_info.language, 'language':user_info.language,
'email':request.user.email, 'email':request.user.email,
'homeworks':hw, 'chapters':chapters,
'format_url_params' : format_url_params, 'format_url_params' : format_url_params,
'grade_summary' : grade_summary, 'grade_summary' : grade_summary,
'csrf':csrf(request)['csrf_token'] 'csrf':csrf(request)['csrf_token']
......
...@@ -14,6 +14,9 @@ LIB_URL = 'https://mitxstatic.s3.amazonaws.com/js/' ...@@ -14,6 +14,9 @@ LIB_URL = 'https://mitxstatic.s3.amazonaws.com/js/'
BOOK_URL = '/static/book/' BOOK_URL = '/static/book/'
BOOK_URL = 'https://mitxstatic.s3.amazonaws.com/book_images/' 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 # Our parent dir (mitx_all) is the BASE_DIR
BASE_DIR = os.path.abspath(os.path.join(__file__, "..", "..")) BASE_DIR = os.path.abspath(os.path.join(__file__, "..", ".."))
......
...@@ -14,7 +14,8 @@ valid_templates=['index.html', ...@@ -14,7 +14,8 @@ valid_templates=['index.html',
'privacy.html', 'privacy.html',
'honor.html', 'honor.html',
'copyright.html', 'copyright.html',
'404.html'] '404.html',
'mitx_help.html']
if settings.STATIC_GRAB: if settings.STATIC_GRAB:
valid_templates = valid_templates+['server-down.html', valid_templates = valid_templates+['server-down.html',
......
# 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']
...@@ -27,6 +27,10 @@ class UserProfile(models.Model): ...@@ -27,6 +27,10 @@ class UserProfile(models.Model):
meta = models.CharField(blank=True, max_length=255) # JSON dictionary for future expansion meta = models.CharField(blank=True, max_length=255) # JSON dictionary for future expansion
courseware = models.CharField(blank=True, max_length=255, default='course.xml') 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): class Registration(models.Model):
''' Allows us to wait for e-mail before user is registered. A ''' Allows us to wait for e-mail before user is registered. A
......
...@@ -32,23 +32,14 @@ def index(request): ...@@ -32,23 +32,14 @@ def index(request):
else: else:
csrf_token = csrf(request)['csrf_token'] csrf_token = csrf(request)['csrf_token']
# TODO: Clean up how 'error' is done. # TODO: Clean up how 'error' is done.
return render_to_response('index.html', {'error' : '', return render_to_response('index.html', {'csrf': csrf_token })
'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 # Need different levels of logging
@ensure_csrf_cookie @ensure_csrf_cookie
def login_user(request, error=""): def login_user(request, error=""):
if 'email' not in request.POST or 'password' not in request.POST: 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'] email = request.POST['email']
password = request.POST['password'] password = request.POST['password']
...@@ -136,9 +127,15 @@ def create_account(request, post_override=None): ...@@ -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 # TODO: Confirm e-mail is not from a generic domain (mailinator, etc.)? Not sure if
# this is a good idea # this is a good idea
# TODO: Check password is sane # 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: 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)) return HttpResponse(json.dumps(js))
try: try:
......
import logging import logging
from django.conf import settings from django.conf import settings
from django.http import HttpResponse from django.http import HttpResponseServerError
log = logging.getLogger("mitx") log = logging.getLogger("mitx")
...@@ -12,4 +12,4 @@ class ExceptionLoggingMiddleware(object): ...@@ -12,4 +12,4 @@ class ExceptionLoggingMiddleware(object):
if not settings.TEMPLATE_DEBUG: if not settings.TEMPLATE_DEBUG:
def process_exception(self, request, exception): def process_exception(self, request, exception):
log.exception(exception) log.exception(exception)
return HttpResponse("Server Error - Please try again later.") return HttpResponseServerError("Server Error - Please try again later.")
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment