diff --git a/courseware/capa/capa_problem.py b/courseware/capa/capa_problem.py
index b7ac8940fe..032b5d41b4 100644
--- a/courseware/capa/capa_problem.py
+++ b/courseware/capa/capa_problem.py
@@ -1,4 +1,5 @@
import copy
+import logging
import math
import numpy
import os
@@ -19,6 +20,8 @@ from responsetypes import numericalresponse, formularesponse, customresponse, sc
import calc
import eia
+log = logging.getLogger("mitx.courseware")
+
response_types = {'numericalresponse':numericalresponse,
'formularesponse':formularesponse,
'customresponse':customresponse,
@@ -80,6 +83,7 @@ class LoncapaProblem(object):
self.seed=struct.unpack('i', os.urandom(4))[0]
## Parse XML file
+ log.debug(u"LoncapaProblem() opening file {0}".format(filename))
file_text = open(filename).read()
# Convert startouttext and endouttext to proper
# TODO: Do with XML operations
diff --git a/courseware/content_parser.py b/courseware/content_parser.py
index af949f1f00..ff61f5cdc0 100644
--- a/courseware/content_parser.py
+++ b/courseware/content_parser.py
@@ -3,10 +3,12 @@ import hashlib
import logging
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 auth.models import UserProfile
+ from student.models import UserProfile
except:
settings = None
@@ -116,10 +118,18 @@ def propogate_downward_tag(element, attribute_name, parent_attribute = None):
#for now and trust that this element will get its turn to propogate
#to its children later.
return
-
+
+template_lookup = TemplateLookup(directories = [settings.DATA_DIR],
+ module_directory = settings.MAKO_MODULE_DIR)
+
def course_file(user):
# TODO: Cache.
- tree = etree.parse(settings.DATA_DIR+UserProfile.objects.get(user=user).courseware)
+ 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))
id_tag(tree)
propogate_downward_tag(tree, "due")
propogate_downward_tag(tree, "graded")
diff --git a/courseware/migrations/0001_initial.py b/courseware/migrations/0001_initial.py
new file mode 100644
index 0000000000..205ed97136
--- /dev/null
+++ b/courseware/migrations/0001_initial.py
@@ -0,0 +1,112 @@
+# 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 'StudentModule'
+ db.create_table('courseware_studentmodule', (
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('module_type', self.gf('django.db.models.fields.CharField')(default='problem', max_length=32)),
+ ('module_id', self.gf('django.db.models.fields.CharField')(max_length=255)),
+ ('student', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'])),
+ ('state', self.gf('django.db.models.fields.TextField')(null=True, blank=True)),
+ ('grade', self.gf('django.db.models.fields.FloatField')(null=True, blank=True)),
+ ('created', self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True, blank=True)),
+ ('modified', self.gf('django.db.models.fields.DateTimeField')(auto_now=True, blank=True)),
+ ))
+ db.send_create_signal('courseware', ['StudentModule'])
+
+ # Adding unique constraint on 'StudentModule', fields ['student', 'module_id', 'module_type']
+ db.create_unique('courseware_studentmodule', ['student_id', 'module_id', 'module_type'])
+
+
+ def backwards(self, orm):
+
+ # Removing unique constraint on 'StudentModule', fields ['student', 'module_id', 'module_type']
+ db.delete_unique('courseware_studentmodule', ['student_id', 'module_id', 'module_type'])
+
+ # Deleting model 'StudentModule'
+ db.delete_table('courseware_studentmodule')
+
+
+ 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', 'module_type'),)", 'object_name': 'StudentModule'},
+ 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'grade': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'modified': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
+ 'module_id': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'module_type': ('django.db.models.fields.CharField', [], {'default': "'problem'", 'max_length': '32'}),
+ 'state': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'student': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ }
+ }
+
+ complete_apps = ['courseware']
diff --git a/courseware/migrations/0002_add_indexes.py b/courseware/migrations/0002_add_indexes.py
new file mode 100644
index 0000000000..02f28c9f78
--- /dev/null
+++ b/courseware/migrations/0002_add_indexes.py
@@ -0,0 +1,120 @@
+# 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 index on 'StudentModule', fields ['created']
+ db.create_index('courseware_studentmodule', ['created'])
+
+ # Adding index on 'StudentModule', fields ['grade']
+ db.create_index('courseware_studentmodule', ['grade'])
+
+ # Adding index on 'StudentModule', fields ['modified']
+ db.create_index('courseware_studentmodule', ['modified'])
+
+ # Adding index on 'StudentModule', fields ['module_type']
+ db.create_index('courseware_studentmodule', ['module_type'])
+
+ # Adding index on 'StudentModule', fields ['module_id']
+ db.create_index('courseware_studentmodule', ['module_id'])
+
+
+ def backwards(self, orm):
+
+ # Removing index on 'StudentModule', fields ['module_id']
+ db.delete_index('courseware_studentmodule', ['module_id'])
+
+ # Removing index on 'StudentModule', fields ['module_type']
+ db.delete_index('courseware_studentmodule', ['module_type'])
+
+ # Removing index on 'StudentModule', fields ['modified']
+ db.delete_index('courseware_studentmodule', ['modified'])
+
+ # Removing index on 'StudentModule', fields ['grade']
+ db.delete_index('courseware_studentmodule', ['grade'])
+
+ # Removing index on 'StudentModule', fields ['created']
+ db.delete_index('courseware_studentmodule', ['created'])
+
+
+ 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', 'module_type'),)", 'object_name': 'StudentModule'},
+ 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'db_index': 'True', 'blank': 'True'}),
+ 'grade': ('django.db.models.fields.FloatField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': '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']
diff --git a/auth/__init__.py b/courseware/migrations/__init__.py
similarity index 100%
rename from auth/__init__.py
rename to courseware/migrations/__init__.py
diff --git a/courseware/models.py b/courseware/models.py
index acba401239..f713da3195 100644
--- a/courseware/models.py
+++ b/courseware/models.py
@@ -1,3 +1,14 @@
+"""
+WE'RE USING MIGRATIONS!
+
+If you make changes to this model, be sure to create an appropriate migration
+file and check it in at the same time as your model changes. To do that,
+
+1. Go to the mitx dir
+2. ./manage.py schemamigration courseware --auto description_of_your_change
+3. Add the migration file created in mitx/courseware/migrations/
+
+"""
from django.db import models
from django.contrib.auth.models import User
@@ -9,9 +20,9 @@ class StudentModule(models.Model):
('html','html'),
)
## These three are the key for the object
- module_type = models.CharField(max_length=32, choices=MODULE_TYPES, default='problem')
- module_id = models.CharField(max_length=255) # Filename for homeworks, etc.
- student = models.ForeignKey(User)
+ module_type = models.CharField(max_length=32, choices=MODULE_TYPES, default='problem', db_index=True)
+ module_id = models.CharField(max_length=255, db_index=True) # Filename for homeworks, etc.
+ student = models.ForeignKey(User, db_index=True)
class Meta:
unique_together = (('student', 'module_id'),)
@@ -19,7 +30,7 @@ class StudentModule(models.Model):
state = models.TextField(null=True, blank=True)
## Grade, and are we done?
- grade = models.FloatField(null=True, blank=True)
+ grade = models.FloatField(null=True, blank=True, db_index=True)
#max_grade = models.FloatField(null=True, blank=True)
# DONE_TYPES = (('done','DONE'), # Finished
@@ -27,8 +38,10 @@ class StudentModule(models.Model):
# ('na','NA')) # Not applicable (e.g. vertical)
# done = models.CharField(max_length=16, choices=DONE_TYPES)
- created = models.DateTimeField(auto_now_add=True)
- modified = models.DateTimeField(auto_now=True)
+ created = models.DateTimeField(auto_now_add=True, db_index=True)
+ modified = models.DateTimeField(auto_now=True, db_index=True)
def __unicode__(self):
return self.module_type+'/'+self.student.username+"/"+self.module_id+'/'+str(self.state)[:20]
+
+
diff --git a/courseware/module_render.py b/courseware/module_render.py
index f001583379..93becb27fa 100644
--- a/courseware/module_render.py
+++ b/courseware/module_render.py
@@ -20,8 +20,8 @@ from django.template import Context
from django.template import Context, loader
from mitxmako.shortcuts import render_to_response, render_to_string
-from auth.models import UserProfile
from models import StudentModule
+from student.models import UserProfile
import track.views
import courseware.content_parser as content_parser
diff --git a/courseware/modules/seq_module.py b/courseware/modules/seq_module.py
index 02c8320ac8..33c4088486 100644
--- a/courseware/modules/seq_module.py
+++ b/courseware/modules/seq_module.py
@@ -9,6 +9,10 @@ from mitxmako.shortcuts import render_to_response, render_to_string
from x_module import XModule
+# HACK: This shouldn't be hard-coded to two types
+# OBSOLETE: This obsoletes 'type'
+class_priority = ['video', 'problem']
+
class SequentialModule(XModule):
''' Layout module which lays out content in a temporal sequence
'''
@@ -55,10 +59,21 @@ class SequentialModule(XModule):
return {'content':content,
"destroy_js":m['destroy_js'],
'init_js':m['init_js'],
- 'type':m['type']}
+ 'type': m['type']}
+
+
+ ## 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]
+
+ 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
js=""
diff --git a/courseware/views.py b/courseware/views.py
index fa705b41eb..e0857d8789 100644
--- a/courseware/views.py
+++ b/courseware/views.py
@@ -17,9 +17,10 @@ from django.db import connection
from lxml import etree
-from auth.models import UserProfile
-from models import StudentModule
from module_render import render_module, modx_dispatch
+from models import StudentModule
+from student.models import UserProfile
+
import courseware.content_parser as content_parser
import courseware.modules.capa_module
diff --git a/fixtures/pm.json b/fixtures/pm.json
index eec6cc6750..5ecb839093 100644
--- a/fixtures/pm.json
+++ b/fixtures/pm.json
@@ -1 +1 @@
-[{"pk": 1, "model": "auth.userprofile", "fields": {"name": "pm", "language": "pm", "courseware": "course.xml", "meta": "", "location": "pm", "user": 1}}, {"pk": 1, "model": "auth.user", "fields": {"status": "w", "last_name": "", "gold": 0, "is_staff": true, "user_permissions": [], "interesting_tags": "", "email_key": null, "date_joined": "2012-01-23 17:03:54", "first_name": "", "email_isvalid": false, "avatar_type": "n", "website": "", "is_superuser": true, "date_of_birth": null, "last_login": "2012-01-23 17:04:16", "location": "", "new_response_count": 0, "email": "pmitros@csail.mit.edu", "username": "pm", "is_active": true, "consecutive_days_visit_count": 0, "email_tag_filter_strategy": 1, "groups": [], "password": "sha1$a3e96$dbabbd114f0da01bce2cc2adcafa2ca651c7ae0a", "silver": 0, "bronze": 0, "questions_per_page": 10, "about": "", "show_country": false, "country": "", "display_tag_filter_strategy": 0, "seen_response_count": 0, "real_name": "", "ignored_tags": "", "reputation": 1, "gravatar": "7a591afd0cc7972fdbe5e12e26af352a", "last_seen": "2012-01-23 17:04:41"}}, {"pk": 1, "model": "auth.userprofile", "fields": {"name": "pm", "language": "pm", "courseware": "course.xml", "meta": "", "location": "pm", "user": 1}}, {"pk": 1, "model": "auth.user", "fields": {"status": "w", "last_name": "", "gold": 0, "is_staff": true, "user_permissions": [], "interesting_tags": "", "email_key": null, "date_joined": "2012-01-23 17:03:54", "first_name": "", "email_isvalid": false, "avatar_type": "n", "website": "", "is_superuser": true, "date_of_birth": null, "last_login": "2012-01-23 17:04:16", "location": "", "new_response_count": 0, "email": "pmitros@csail.mit.edu", "username": "pm", "is_active": true, "consecutive_days_visit_count": 0, "email_tag_filter_strategy": 1, "groups": [], "password": "sha1$a3e96$dbabbd114f0da01bce2cc2adcafa2ca651c7ae0a", "silver": 0, "bronze": 0, "questions_per_page": 10, "about": "", "show_country": false, "country": "", "display_tag_filter_strategy": 0, "seen_response_count": 0, "real_name": "", "ignored_tags": "", "reputation": 1, "gravatar": "7a591afd0cc7972fdbe5e12e26af352a", "last_seen": "2012-01-23 17:04:41"}}]
\ No newline at end of file
+[{"pk": 1, "model": "user.userprofile", "fields": {"name": "pm", "language": "pm", "courseware": "course.xml", "meta": "", "location": "pm", "user": 1}}, {"pk": 1, "model": "auth.user", "fields": {"status": "w", "last_name": "", "gold": 0, "is_staff": true, "user_permissions": [], "interesting_tags": "", "email_key": null, "date_joined": "2012-01-23 17:03:54", "first_name": "", "email_isvalid": false, "avatar_type": "n", "website": "", "is_superuser": true, "date_of_birth": null, "last_login": "2012-01-23 17:04:16", "location": "", "new_response_count": 0, "email": "pmitros@csail.mit.edu", "username": "pm", "is_active": true, "consecutive_days_visit_count": 0, "email_tag_filter_strategy": 1, "groups": [], "password": "sha1$a3e96$dbabbd114f0da01bce2cc2adcafa2ca651c7ae0a", "silver": 0, "bronze": 0, "questions_per_page": 10, "about": "", "show_country": false, "country": "", "display_tag_filter_strategy": 0, "seen_response_count": 0, "real_name": "", "ignored_tags": "", "reputation": 1, "gravatar": "7a591afd0cc7972fdbe5e12e26af352a", "last_seen": "2012-01-23 17:04:41"}}, {"pk": 1, "model": "user.userprofile", "fields": {"name": "pm", "language": "pm", "courseware": "course.xml", "meta": "", "location": "pm", "user": 1}}, {"pk": 1, "model": "auth.user", "fields": {"status": "w", "last_name": "", "gold": 0, "is_staff": true, "user_permissions": [], "interesting_tags": "", "email_key": null, "date_joined": "2012-01-23 17:03:54", "first_name": "", "email_isvalid": false, "avatar_type": "n", "website": "", "is_superuser": true, "date_of_birth": null, "last_login": "2012-01-23 17:04:16", "location": "", "new_response_count": 0, "email": "pmitros@csail.mit.edu", "username": "pm", "is_active": true, "consecutive_days_visit_count": 0, "email_tag_filter_strategy": 1, "groups": [], "password": "sha1$a3e96$dbabbd114f0da01bce2cc2adcafa2ca651c7ae0a", "silver": 0, "bronze": 0, "questions_per_page": 10, "about": "", "show_country": false, "country": "", "display_tag_filter_strategy": 0, "seen_response_count": 0, "real_name": "", "ignored_tags": "", "reputation": 1, "gravatar": "7a591afd0cc7972fdbe5e12e26af352a", "last_seen": "2012-01-23 17:04:41"}}]
\ No newline at end of file
diff --git a/settings_new_askbot.py b/settings_new_askbot.py
index 8ff19cace5..d95c843e09 100644
--- a/settings_new_askbot.py
+++ b/settings_new_askbot.py
@@ -1,12 +1,17 @@
import os
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 = 'http://mitxstatic.s3-website-us-east-1.amazonaws.com/js/'
+LIB_URL = 'https://mitxstatic.s3.amazonaws.com/js/'
BOOK_URL = '/static/book/'
-BOOK_URL = 'http://mitxstatic.s3-website-us-east-1.amazonaws.com/book_images/'
+BOOK_URL = 'https://mitxstatic.s3.amazonaws.com/book_images/'
# Our parent dir (mitx_all) is the BASE_DIR
BASE_DIR = os.path.abspath(os.path.join(__file__, "..", ".."))
@@ -34,6 +39,10 @@ HTTPS = 'on'
MEDIA_URL = ''
MEDIA_ROOT = ''
+# Needed for Askbot
+# Deployed machines: Move to S3
+DEFAULT_FILE_STORAGE = 'django.core.files.storage.FileSystemStorage'
+
DEBUG = True
TEMPLATE_DEBUG = DEBUG
@@ -103,7 +112,7 @@ INSTALLED_APPS = (
'django.contrib.messages',
'django.contrib.staticfiles',
'courseware',
- 'auth',
+ 'student',
'django.contrib.humanize',
'static_template_view',
'staticbook',
@@ -126,10 +135,14 @@ TRACK_MAX_EVENT = 1000
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.
@@ -251,13 +264,15 @@ import site
STATICFILES_DIRS = STATICFILES_DIRS + ( ASKBOT_DIR+'/askbot/skins',)
-# Needed for Askbot
-# Critical TODO: Move to S3
-MEDIA_URL = '/discussion/upfiles/'
-MEDIA_ROOT = ASKBOT_DIR+'/askbot/upfiles'
-
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',)
@@ -281,7 +296,6 @@ FILE_UPLOAD_HANDLERS = (
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__)
@@ -308,6 +322,31 @@ INSTALLED_APPS = INSTALLED_APPS + (
'followit',
)
+# askbot livesettings
+LIVESETTINGS_OPTIONS = {
+ 1: {
+ 'SETTINGS' : {
+ 'MIN_REP' : {
+ 'MIN_REP_TO_VOTE_UP' : 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 = '/'
diff --git a/static_template_view/views.py b/static_template_view/views.py
index 734434b43a..a66a3cd8c5 100644
--- a/static_template_view/views.py
+++ b/static_template_view/views.py
@@ -6,6 +6,7 @@
from mitxmako.shortcuts import render_to_response, render_to_string
from django.shortcuts import redirect
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',
@@ -13,7 +14,15 @@ valid_templates=['mitx_global.html',
'tos.html',
'privacy.html',
'honor.html',
- 'copyright.html']
+ 'copyright.html',
+ '404.html']
+
+print "!!",settings.__dict__
+
+if settings.STATIC_GRAB:
+ valid_templates = valid_templates+['server-down.html',
+ 'server-error.html'
+ 'server-overloaded.html']
def index(request, template):
csrf_token = csrf(request)['csrf_token']
diff --git a/student/__init__.py b/student/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/student/migrations/0001_initial.py b/student/migrations/0001_initial.py
new file mode 100644
index 0000000000..cab5690ea7
--- /dev/null
+++ b/student/migrations/0001_initial.py
@@ -0,0 +1,121 @@
+# 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 'UserProfile'
+ db.create_table('auth_userprofile', (
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('user', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'], unique=True)),
+ ('name', self.gf('django.db.models.fields.TextField')(blank=True)),
+ ('language', self.gf('django.db.models.fields.TextField')(blank=True)),
+ ('location', self.gf('django.db.models.fields.TextField')(blank=True)),
+ ('meta', self.gf('django.db.models.fields.TextField')(blank=True)),
+ ('courseware', self.gf('django.db.models.fields.TextField')(default='course.xml', blank=True)),
+ ))
+ db.send_create_signal('student', ['UserProfile'])
+
+ # Adding model 'Registration'
+ db.create_table('auth_registration', (
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('user', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'], unique=True)),
+ ('activation_key', self.gf('django.db.models.fields.CharField')(unique=True, max_length=32, db_index=True)),
+ ))
+ db.send_create_signal('student', ['Registration'])
+
+
+ def backwards(self, orm):
+
+ # Deleting model 'UserProfile'
+ db.delete_table('auth_userprofile')
+
+ # Deleting model 'Registration'
+ db.delete_table('auth_registration')
+
+
+ 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.TextField', [], {'default': "'course.xml'", 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'language': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'location': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'meta': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'name': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'unique': 'True'})
+ }
+ }
+
+ complete_apps = ['student']
diff --git a/student/migrations/0002_text_to_varchar_and_indexes.py b/student/migrations/0002_text_to_varchar_and_indexes.py
new file mode 100644
index 0000000000..a75f164f3a
--- /dev/null
+++ b/student/migrations/0002_text_to_varchar_and_indexes.py
@@ -0,0 +1,143 @@
+# 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):
+
+ # Changing field 'UserProfile.name'
+ db.alter_column('auth_userprofile', 'name', self.gf('django.db.models.fields.CharField')(max_length=255))
+
+ # Adding index on 'UserProfile', fields ['name']
+ db.create_index('auth_userprofile', ['name'])
+
+ # Changing field 'UserProfile.language'
+ db.alter_column('auth_userprofile', 'language', self.gf('django.db.models.fields.CharField')(max_length=255))
+
+ # Adding index on 'UserProfile', fields ['language']
+ db.create_index('auth_userprofile', ['language'])
+
+ # Changing field 'UserProfile.courseware'
+ db.alter_column('auth_userprofile', 'courseware', self.gf('django.db.models.fields.CharField')(max_length=255))
+
+ # Changing field 'UserProfile.meta'
+ db.alter_column('auth_userprofile', 'meta', self.gf('django.db.models.fields.CharField')(max_length=255))
+
+ # Changing field 'UserProfile.location'
+ db.alter_column('auth_userprofile', 'location', self.gf('django.db.models.fields.CharField')(max_length=255))
+
+ # Adding index on 'UserProfile', fields ['location']
+ db.create_index('auth_userprofile', ['location'])
+
+
+ def backwards(self, orm):
+
+ # Removing index on 'UserProfile', fields ['location']
+ db.delete_index('auth_userprofile', ['location'])
+
+ # Removing index on 'UserProfile', fields ['language']
+ db.delete_index('auth_userprofile', ['language'])
+
+ # Removing index on 'UserProfile', fields ['name']
+ db.delete_index('auth_userprofile', ['name'])
+
+ # Changing field 'UserProfile.name'
+ db.alter_column('auth_userprofile', 'name', self.gf('django.db.models.fields.TextField')())
+
+ # Changing field 'UserProfile.language'
+ db.alter_column('auth_userprofile', 'language', self.gf('django.db.models.fields.TextField')())
+
+ # Changing field 'UserProfile.courseware'
+ db.alter_column('auth_userprofile', 'courseware', self.gf('django.db.models.fields.TextField')())
+
+ # Changing field 'UserProfile.meta'
+ db.alter_column('auth_userprofile', 'meta', self.gf('django.db.models.fields.TextField')())
+
+ # Changing field 'UserProfile.location'
+ db.alter_column('auth_userprofile', 'location', self.gf('django.db.models.fields.TextField')())
+
+
+ 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'})
+ }
+ }
+
+ complete_apps = ['student']
diff --git a/student/migrations/__init__.py b/student/migrations/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/auth/models.py b/student/models.py
similarity index 54%
rename from auth/models.py
rename to student/models.py
index 88cdd2da61..39e0738c72 100644
--- a/auth/models.py
+++ b/student/models.py
@@ -1,24 +1,41 @@
+"""
+WE'RE USING MIGRATIONS!
+
+If you make changes to this model, be sure to create an appropriate migration
+file and check it in at the same time as your model changes. To do that,
+
+1. Go to the mitx dir
+2. ./manage.py schemamigration user --auto description_of_your_change
+3. Add the migration file created in mitx/courseware/migrations/
+"""
import uuid
from django.db import models
from django.contrib.auth.models import User
class UserProfile(models.Model):
+ class Meta:
+ db_table = "auth_userprofile"
+
## CRITICAL TODO/SECURITY
# Sanitize all fields.
# This is not visible to other users, but could introduce holes later
user = models.ForeignKey(User, unique=True, db_index=True)
- name = models.TextField(blank=True)
- language = models.TextField(blank=True)
- location = models.TextField(blank=True)
- meta = models.TextField(blank=True) # JSON dictionary for future expansion
- courseware = models.TextField(blank=True, default='course.xml')
+ name = models.CharField(blank=True, max_length=255, db_index=True)
+ language = models.CharField(blank=True, max_length=255, db_index=True)
+ location = models.CharField(blank=True, max_length=255, db_index=True)
+ 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 Registration(models.Model):
''' Allows us to wait for e-mail before user is registered. A
registration profile is created when the user creates an
account, but that account is inactive. Once the user clicks
on the activation key, it becomes active. '''
+ class Meta:
+ db_table = "auth_registration"
+
user = models.ForeignKey(User, unique=True)
activation_key = models.CharField(('activation key'), max_length=32, unique=True, db_index=True)
diff --git a/auth/tests.py b/student/tests.py
similarity index 100%
rename from auth/tests.py
rename to student/tests.py
diff --git a/auth/views.py b/student/views.py
similarity index 92%
rename from auth/views.py
rename to student/views.py
index f2f945644f..0ccf51dbb5 100644
--- a/auth/views.py
+++ b/student/views.py
@@ -5,17 +5,18 @@ import string
from django.conf import settings
from django.contrib.auth import logout, authenticate, login
-from django.contrib.auth.models import User
+from django.contrib.auth.forms import PasswordResetForm
from django.contrib.auth.models import User
from django.core.context_processors import csrf
from django.core.validators import validate_email, validate_slug
from django.db import connection
-from django.http import HttpResponse
+from django.http import HttpResponse, Http404
from django.shortcuts import redirect
from mitxmako.shortcuts import render_to_response, render_to_string
+
from models import Registration, UserProfile
-log = logging.getLogger("mitx.auth")
+log = logging.getLogger("mitx.user")
def csrf_token(context):
csrf_token = context.get('csrf_token', '')
@@ -230,3 +231,18 @@ def activate_account(request, key):
if len(r)==0:
return render_to_response("activation_invalid.html",{'csrf':csrf(request)['csrf_token']})
return HttpResponse("Unknown error. Please e-mail us to let us know how it happened.")
+
+def password_reset(request):
+ ''' Attempts to send a password reset e-mail. '''
+ if request.method != "POST":
+ raise Http404
+ form = PasswordResetForm(request.POST)
+ if form.is_valid():
+ form.save( use_https = request.is_secure(),
+ from_email = settings.DEFAULT_FROM_EMAIL,
+ request = request )
+ return HttpResponse(json.dumps({'success':True,
+ 'value': render_to_string('registration/password_reset_done.html', {})}))
+ else:
+ return HttpResponse(json.dumps({'success':False,
+ 'error': 'Invalid e-mail'}))
diff --git a/urls.py b/urls.py
index 5ebda7bd4e..e40c0a13d7 100644
--- a/urls.py
+++ b/urls.py
@@ -10,15 +10,16 @@ import django.contrib.auth.views
urlpatterns = ('',
url(r'^event$', 'track.views.user_track'),
url(r'^t/(?P[^/]*)$', 'static_template_view.views.index'),
- url(r'^logout$', 'auth.views.logout_user'),
+ url(r'^logout$', 'student.views.logout_user'),
url(r'^info$', 'util.views.info'),
- url(r'^login$', 'auth.views.login_user'),
- url(r'^login/(?P[^/]*)$', 'auth.views.login_user'),
- url(r'^create_account$', 'auth.views.create_account'),
- url(r'^activate/(?P[^/]*)$', 'auth.views.activate_account'),
- url(r'^$', 'auth.views.index'),
- url(r'^password_reset/$', 'django.contrib.auth.views.password_reset',
- dict(from_email='registration@mitx.mit.edu'),name='auth_password_reset'),
+ url(r'^login$', 'student.views.login_user'),
+ url(r'^login/(?P[^/]*)$', 'student.views.login_user'),
+ url(r'^create_account$', 'student.views.create_account'),
+ url(r'^activate/(?P[^/]*)$', 'student.views.activate_account'),
+ url(r'^$', 'student.views.index'),
+# url(r'^password_reset/$', 'django.contrib.auth.views.password_reset',
+# dict(from_email='registration@mitx.mit.edu'),name='auth_password_reset'),
+ url(r'^password_reset/$', 'student.views.password_reset'),
url(r'^password_change/$',django.contrib.auth.views.password_change,name='auth_password_change'),
url(r'^password_change_done/$',django.contrib.auth.views.password_change_done,name='auth_password_change_done'),
url(r'^password_reset_confirm/(?P[0-9A-Za-z]+)-(?P.+)/$',django.contrib.auth.views.password_reset_confirm,
@@ -41,12 +42,12 @@ url(r'^wiki/', include('simplewiki.urls')),
url(r'^courseware/(?P[^/]*)/$', 'courseware.views.index'),
url(r'^modx/(?P[^/]*)/(?P[^/]*)/(?P[^/]*)$', 'courseware.views.modx_dispatch'), #reset_problem'),
url(r'^profile$', 'courseware.views.profile'),
- url(r'^change_setting$', 'auth.views.change_setting'),
+ url(r'^change_setting$', 'student.views.change_setting'),
url(r'^s/(?P[^/]*)$', 'static_template_view.views.auth_index'),
url(r'^book/(?P[^/]*)$', 'staticbook.views.index'),
url(r'^book-shifted/(?P[^/]*)$', 'staticbook.views.index_shifted'),
url(r'^book*$', 'staticbook.views.index'),
-# url(r'^course_info/$', 'auth.views.courseinfo'),
+# url(r'^course_info/$', 'student.views.courseinfo'),
# url(r'^show_circuit/(?P[^/]*)$', 'circuit.views.show_circuit'),
url(r'^edit_circuit/(?P[^/]*)$', 'circuit.views.edit_circuit'),
url(r'^save_circuit/(?P[^/]*)$', 'circuit.views.save_circuit'),