Cleaning up pep8 violations

This commit is contained in:
Calen Pennington
2012-07-23 14:44:40 -04:00
parent 7ef8b6ac1e
commit 1d1a9173a4
128 changed files with 2200 additions and 2006 deletions

View File

@@ -13,6 +13,7 @@ from django.db import DEFAULT_DB_ALIAS
from . import app_settings
def get_instance(model, instance_or_pk, timeout=None, using=None):
"""
Returns the ``model`` instance with a primary key of ``instance_or_pk``.
@@ -87,6 +88,7 @@ def get_instance(model, instance_or_pk, timeout=None, using=None):
return instance
def delete_instance(model, *instance_or_pk):
"""
Purges the cache keys for the instances of this model.
@@ -94,6 +96,7 @@ def delete_instance(model, *instance_or_pk):
cache.delete_many([instance_key(model, x) for x in instance_or_pk])
def instance_key(model, instance_or_pk):
"""
Returns the cache key for this (model, instance) pair.

View File

@@ -84,6 +84,7 @@ from django.contrib.auth.middleware import AuthenticationMiddleware
from .model import cache_model
class CacheBackedAuthenticationMiddleware(AuthenticationMiddleware):
def __init__(self):
cache_model(User)

View File

@@ -58,6 +58,7 @@ from django.db.models.signals import post_save, post_delete
from .core import get_instance, delete_instance
def cache_model(model, timeout=None):
if hasattr(model, 'get_cached'):
# Already patched

View File

@@ -74,6 +74,7 @@ from django.db.models.signals import post_save, post_delete
from .core import get_instance, delete_instance
def cache_relation(descriptor, timeout=None):
rel = descriptor.related
related_name = '%s_cache' % rel.field.related_query_name()

View File

@@ -5,6 +5,7 @@ from django.template import resolve_variable
register = template.Library()
class CacheNode(Node):
def __init__(self, nodelist, expire_time, key):
self.nodelist = nodelist
@@ -21,6 +22,7 @@ class CacheNode(Node):
cache.set(key, value, expire_time)
return value
@register.tag
def cachedeterministic(parser, token):
"""
@@ -42,6 +44,7 @@ def cachedeterministic(parser, token):
raise TemplateSyntaxError(u"'%r' tag requires 2 arguments." % tokens[0])
return CacheNode(nodelist, tokens[1], tokens[2])
class ShowIfCachedNode(Node):
def __init__(self, key):
self.key = key
@@ -50,6 +53,7 @@ class ShowIfCachedNode(Node):
key = resolve_variable(self.key, context)
return cache.get(key) or ''
@register.tag
def showifcached(parser, token):
"""

View File

@@ -60,6 +60,7 @@ def csrf_response_exempt(view_func):
PendingDeprecationWarning)
return view_func
def csrf_view_exempt(view_func):
"""
Marks a view function as being exempt from CSRF view protection.
@@ -68,6 +69,7 @@ def csrf_view_exempt(view_func):
PendingDeprecationWarning)
return csrf_exempt(view_func)
def csrf_exempt(view_func):
"""
Marks a view function as being exempt from the CSRF view protection.

View File

@@ -6,6 +6,7 @@ from pipeline.conf import settings
from pipeline.packager import Packager
from pipeline.utils import guess_type
def compressed_css(package_name):
package = settings.PIPELINE_CSS.get(package_name, {})
if package:
@@ -20,6 +21,7 @@ def compressed_css(package_name):
paths = packager.compile(package.paths)
return render_individual_css(package, paths)
def render_css(package, path):
template_name = package.template_name or "mako/css.html"
context = package.extra_context
@@ -29,6 +31,7 @@ def render_css(package, path):
})
return render_to_string(template_name, context)
def render_individual_css(package, paths):
tags = [render_css(package, path) for path in paths]
return '\n'.join(tags)
@@ -49,6 +52,7 @@ def compressed_js(package_name):
templates = packager.pack_templates(package)
return render_individual_js(package, paths, templates)
def render_js(package, path):
template_name = package.template_name or "mako/js.html"
context = package.extra_context
@@ -58,6 +62,7 @@ def render_js(package, path):
})
return render_to_string(template_name, context)
def render_inline_js(package, js):
context = package.extra_context
context.update({
@@ -65,6 +70,7 @@ def render_inline_js(package, js):
})
return render_to_string("mako/inline_js.html", context)
def render_individual_js(package, paths, templates=None):
tags = [render_js(package, js) for js in paths]
if templates:

View File

@@ -15,4 +15,3 @@ admin.site.register(CourseEnrollment)
admin.site.register(Registration)
admin.site.register(PendingNameChange)

View File

@@ -25,27 +25,29 @@ import mitxmako.middleware as middleware
middleware.MakoMiddleware()
class Command(BaseCommand):
help = \
'''Exports all users and user profiles.
'''Exports all users and user profiles.
Caveat: Should be looked over before any run
for schema changes.
for schema changes.
Current version grabs user_keys from
Current version grabs user_keys from
django.contrib.auth.models.User and up_keys
from student.userprofile. '''
def handle(self, *args, **options):
users = list(User.objects.all())
user_profiles = list(UserProfile.objects.all())
user_profile_dict = dict([(up.user_id, up) for up in user_profiles])
user_tuples = [(user_profile_dict[u.id], u) for u in users if u.id in user_profile_dict]
user_keys = ['id', 'username', 'email', 'password', 'is_staff',
'is_active', 'is_superuser', 'last_login', 'date_joined',
user_keys = ['id', 'username', 'email', 'password', 'is_staff',
'is_active', 'is_superuser', 'last_login', 'date_joined',
'password']
up_keys = ['language', 'location','meta','name', 'id','user_id']
up_keys = ['language', 'location', 'meta', 'name', 'id', 'user_id']
def extract_dict(keys, object):
d = {}
for key in keys:

View File

@@ -22,6 +22,7 @@ import mitxmako.middleware as middleware
middleware.MakoMiddleware()
def import_user(u):
user_info = u['u']
up_info = u['up']
@@ -30,11 +31,10 @@ def import_user(u):
user_info['last_login'] = dateutil.parser.parse(user_info['last_login'])
user_info['date_joined'] = dateutil.parser.parse(user_info['date_joined'])
user_keys = ['id', 'username', 'email', 'password', 'is_staff',
'is_active', 'is_superuser', 'last_login', 'date_joined',
user_keys = ['id', 'username', 'email', 'password', 'is_staff',
'is_active', 'is_superuser', 'last_login', 'date_joined',
'password']
up_keys = ['language', 'location','meta','name', 'id','user_id']
up_keys = ['language', 'location', 'meta', 'name', 'id', 'user_id']
u = User()
for key in user_keys:
@@ -47,20 +47,22 @@ def import_user(u):
up.__setattr__(key, up_info[key])
up.save()
class Command(BaseCommand):
help = \
'''Exports all users and user profiles.
'''Exports all users and user profiles.
Caveat: Should be looked over before any run
for schema changes.
for schema changes.
Current version grabs user_keys from
Current version grabs user_keys from
django.contrib.auth.models.User and up_keys
from student.userprofile. '''
def handle(self, *args, **options):
extracted = json.load(open('transfer_users.txt'))
n=0
n = 0
for u in extracted:
import_user(u)
if n%100 == 0:
if n % 100 == 0:
print n
n = n+1
n = n + 1

View File

@@ -17,29 +17,32 @@ import json
middleware.MakoMiddleware()
def group_from_value(groups, v):
''' Given group: (('a',0.3),('b',0.4),('c',0.3)) And random value
in [0,1], return the associated group (in the above case, return
'a' if v<0.3, 'b' if 0.3<=v<0.7, and 'c' if v>0.7
'''
sum = 0
for (g,p) in groups:
for (g, p) in groups:
sum = sum + p
if sum > v:
return g
return g # For round-off errors
return g # For round-off errors
class Command(BaseCommand):
help = \
''' Assign users to test groups. Takes a list
of groups:
of groups:
a:0.3,b:0.4,c:0.3 file.txt "Testing something"
Will assign each user to group a, b, or c with
probability 0.3, 0.4, 0.3. Probabilities must
add up to 1.
probability 0.3, 0.4, 0.3. Probabilities must
add up to 1.
Will log what happened to file.txt.
'''
def handle(self, *args, **options):
if len(args) != 3:
print "Invalid number of options"
@@ -47,13 +50,13 @@ Will log what happened to file.txt.
# Extract groups from string
group_strs = [x.split(':') for x in args[0].split(',')]
groups = [(group,float(value)) for group,value in group_strs]
groups = [(group, float(value)) for group, value in group_strs]
print "Groups", groups
## Confirm group probabilities add up to 1
total = sum(zip(*groups)[1])
print "Total:", total
if abs(total-1)>0.01:
if abs(total - 1) > 0.01:
print "Total not 1"
sys.exit(-1)
@@ -65,15 +68,15 @@ Will log what happened to file.txt.
group_objects = {}
f = open(args[1],"a+")
f = open(args[1], "a+")
## Create groups
for group in dict(groups):
utg = UserTestGroup()
utg.name=group
utg.description = json.dumps({"description":args[2]},
{"time":datetime.datetime.utcnow().isoformat()})
group_objects[group]=utg
utg.name = group
utg.description = json.dumps({"description": args[2]},
{"time": datetime.datetime.utcnow().isoformat()})
group_objects[group] = utg
group_objects[group].save()
## Assign groups
@@ -83,11 +86,11 @@ Will log what happened to file.txt.
if count % 1000 == 0:
print count
count = count + 1
v = random.uniform(0,1)
group = group_from_value(groups,v)
v = random.uniform(0, 1)
group = group_from_value(groups, v)
group_objects[group].users.add(user)
f.write("Assigned user {name} ({id}) to {group}\n".format(name=user.username,
id=user.id,
f.write("Assigned user {name} ({id}) to {group}\n".format(name=user.username,
id=user.id,
group=group))
## Save groups

View File

@@ -10,9 +10,11 @@ import mitxmako.middleware as middleware
middleware.MakoMiddleware()
class Command(BaseCommand):
help = \
''' Extract an e-mail list of all active students. '''
def handle(self, *args, **options):
#text = open(args[0]).read()
#subject = open(args[1]).read()

View File

@@ -10,18 +10,20 @@ import mitxmako.middleware as middleware
middleware.MakoMiddleware()
class Command(BaseCommand):
help = \
'''Sends an e-mail to all users. Takes a single
'''Sends an e-mail to all users. Takes a single
parameter -- name of e-mail template -- located
in templates/email. Adds a .txt for the message
body, and an _subject.txt for the subject. '''
def handle(self, *args, **options):
#text = open(args[0]).read()
#subject = open(args[1]).read()
users = User.objects.all()
text = middleware.lookup['main'].get_template('email/'+args[0]+".txt").render()
subject = middleware.lookup['main'].get_template('email/'+args[0]+"_subject.txt").render().strip()
text = middleware.lookup['main'].get_template('email/' + args[0] + ".txt").render()
subject = middleware.lookup['main'].get_template('email/' + args[0] + "_subject.txt").render().strip()
for user in users:
if user.is_active:
user.email_user(subject, text)

View File

@@ -16,16 +16,18 @@ import datetime
middleware.MakoMiddleware()
def chunks(l, n):
""" Yield successive n-sized chunks from l.
"""
for i in xrange(0, len(l), n):
yield l[i:i+n]
yield l[i:i + n]
class Command(BaseCommand):
help = \
'''Sends an e-mail to all users in a text file.
E.g.
'''Sends an e-mail to all users in a text file.
E.g.
manage.py userlist.txt message logfile.txt rate
userlist.txt -- list of all users
message -- prefix for template with message
@@ -35,28 +37,28 @@ rate -- messages per second
log_file = None
def hard_log(self, text):
self.log_file.write(datetime.datetime.utcnow().isoformat()+' -- '+text+'\n')
self.log_file.write(datetime.datetime.utcnow().isoformat() + ' -- ' + text + '\n')
def handle(self, *args, **options):
global log_file
(user_file, message_base, logfilename, ratestr) = args
users = [u.strip() for u in open(user_file).readlines()]
message = middleware.lookup['main'].get_template('emails/'+message_base+"_body.txt").render()
subject = middleware.lookup['main'].get_template('emails/'+message_base+"_subject.txt").render().strip()
message = middleware.lookup['main'].get_template('emails/' + message_base + "_body.txt").render()
subject = middleware.lookup['main'].get_template('emails/' + message_base + "_subject.txt").render().strip()
rate = int(ratestr)
self.log_file = open(logfilename, "a+", buffering = 0)
i=0
self.log_file = open(logfilename, "a+", buffering=0)
i = 0
for users in chunks(users, rate):
emails = [ (subject, message, settings.DEFAULT_FROM_EMAIL, [u]) for u in users ]
emails = [(subject, message, settings.DEFAULT_FROM_EMAIL, [u]) for u in users]
self.hard_log(" ".join(users))
send_mass_mail( emails, fail_silently = False )
send_mass_mail(emails, fail_silently=False)
time.sleep(1)
print datetime.datetime.utcnow().isoformat(), i
i = i+len(users)
i = i + len(users)
# Emergency interruptor
if os.path.exists("/tmp/stopemails.txt"):
self.log_file.close()

View File

@@ -13,26 +13,28 @@ from student.models import UserProfile
middleware.MakoMiddleware()
class Command(BaseCommand):
help = \
''' Extract full user information into a JSON file.
''' Extract full user information into a JSON file.
Pass a single filename.'''
def handle(self, *args, **options):
f = open(args[0],'w')
f = open(args[0], 'w')
#text = open(args[0]).read()
#subject = open(args[1]).read()
users = User.objects.all()
l = []
for user in users:
up = UserProfile.objects.get(user = user)
d = { 'username':user.username,
'email':user.email,
'is_active':user.is_active,
'joined':user.date_joined.isoformat(),
'name':up.name,
'language':up.language,
'location':up.location}
up = UserProfile.objects.get(user=user)
d = {'username': user.username,
'email': user.email,
'is_active': user.is_active,
'joined': user.date_joined.isoformat(),
'name': up.name,
'language': up.language,
'location': up.location}
l.append(d)
json.dump(l,f)
json.dump(l, f)
f.close()

View File

@@ -4,10 +4,11 @@ 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)),
@@ -28,16 +29,14 @@ class Migration(SchemaMigration):
))
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'},

View File

@@ -4,10 +4,11 @@ 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))
@@ -32,9 +33,8 @@ class Migration(SchemaMigration):
# 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'])
@@ -59,7 +59,6 @@ class Migration(SchemaMigration):
# Changing field 'UserProfile.location'
db.alter_column('auth_userprofile', 'location', self.gf('django.db.models.fields.TextField')())
models = {
'auth.group': {
'Meta': {'object_name': 'Group'},

View File

@@ -4,10 +4,11 @@ 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)),
@@ -24,16 +25,14 @@ class Migration(SchemaMigration):
))
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'},

View File

@@ -4,18 +4,17 @@ 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'},

View File

@@ -4,10 +4,11 @@ from south.db import db
from south.v2 import SchemaMigration
from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Adding model 'PendingEmailChange'
db.create_table('student_pendingemailchange', (
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
@@ -29,9 +30,8 @@ class Migration(SchemaMigration):
# Changing field 'UserProfile.user'
db.alter_column('auth_userprofile', 'user_id', self.gf('django.db.models.fields.related.OneToOneField')(unique=True, to=orm['auth.User']))
def backwards(self, orm):
# Deleting model 'PendingEmailChange'
db.delete_table('student_pendingemailchange')
@@ -41,7 +41,6 @@ class Migration(SchemaMigration):
# Changing field 'UserProfile.user'
db.alter_column('auth_userprofile', 'user_id', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'], unique=True))
models = {
'auth.group': {
'Meta': {'object_name': 'Group'},

View File

@@ -4,20 +4,19 @@ 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.meta'
db.alter_column('auth_userprofile', 'meta', self.gf('django.db.models.fields.TextField')())
def backwards(self, orm):
# Changing field 'UserProfile.meta'
db.alter_column('auth_userprofile', 'meta', self.gf('django.db.models.fields.CharField')(max_length=255))
models = {
'auth.group': {
'Meta': {'object_name': 'Group'},

View File

@@ -4,6 +4,7 @@ from south.db import db
from south.v2 import SchemaMigration
from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
@@ -16,12 +17,10 @@ class Migration(SchemaMigration):
ALTER TABLE student_usertestgroup_users CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci;
""")
def backwards(self, orm):
# Although this migration can't be undone, it is okay for it to be run backwards because it doesn't add/remove any fields
pass
models = {
'auth.group': {
'Meta': {'object_name': 'Group'},

View File

@@ -16,12 +16,10 @@ class Migration(SchemaMigration):
))
db.send_create_signal('student', ['CourseRegistration'])
def backwards(self, orm):
# Deleting model 'CourseRegistration'
db.delete_table('student_courseregistration')
models = {
'auth.group': {
'Meta': {'object_name': 'Group'},
@@ -129,4 +127,4 @@ class Migration(SchemaMigration):
}
}
complete_apps = ['student']
complete_apps = ['student']

View File

@@ -19,7 +19,6 @@ class Migration(SchemaMigration):
))
db.send_create_signal('student', ['CourseEnrollment'])
def backwards(self, orm):
# Adding model 'CourseRegistration'
db.create_table('student_courseregistration', (
@@ -32,7 +31,6 @@ class Migration(SchemaMigration):
# Deleting model 'CourseEnrollment'
db.delete_table('student_courseenrollment')
models = {
'auth.group': {
'Meta': {'object_name': 'Group'},
@@ -140,4 +138,4 @@ class Migration(SchemaMigration):
}
}
complete_apps = ['student']
complete_apps = ['student']

View File

@@ -124,4 +124,4 @@ class Migration(SchemaMigration):
}
}
complete_apps = ['student']
complete_apps = ['student']

View File

@@ -13,8 +13,8 @@ class Migration(SchemaMigration):
pass
# # Removing unique constraint on 'CourseEnrollment', fields ['user']
# db.delete_unique('student_courseenrollment', ['user_id'])
#
#
#
#
# # Changing field 'CourseEnrollment.user'
# db.alter_column('student_courseenrollment', 'user_id', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User']))
@@ -25,7 +25,6 @@ class Migration(SchemaMigration):
# # Adding unique constraint on 'CourseEnrollment', fields ['user']
# db.create_unique('student_courseenrollment', ['user_id'])
models = {
'auth.group': {
'Meta': {'object_name': 'Group'},
@@ -133,4 +132,4 @@ class Migration(SchemaMigration):
}
}
complete_apps = ['student']
complete_apps = ['student']

View File

@@ -38,7 +38,6 @@ class Migration(SchemaMigration):
self.gf('django.db.models.fields.CharField')(max_length=255, null=True, blank=True),
keep_default=False)
def backwards(self, orm):
# Deleting field 'UserProfile.gender'
db.delete_column('auth_userprofile', 'gender')
@@ -58,7 +57,6 @@ class Migration(SchemaMigration):
# Deleting field 'UserProfile.occupation'
db.delete_column('auth_userprofile', 'occupation')
models = {
'auth.group': {
'Meta': {'object_name': 'Group'},
@@ -172,4 +170,4 @@ class Migration(SchemaMigration):
}
}
complete_apps = ['student']
complete_apps = ['student']

View File

@@ -130,4 +130,4 @@ class Migration(SchemaMigration):
}
}
complete_apps = ['student']
complete_apps = ['student']

View File

@@ -11,7 +11,6 @@ class Migration(SchemaMigration):
# Deleting model 'CourseEnrollment'
db.delete_table('student_courseenrollment')
def backwards(self, orm):
# Adding model 'CourseEnrollment'
db.create_table('student_courseenrollment', (
@@ -21,7 +20,6 @@ class Migration(SchemaMigration):
))
db.send_create_signal('student', ['CourseEnrollment'])
models = {
'auth.group': {
'Meta': {'object_name': 'Group'},
@@ -129,4 +127,4 @@ class Migration(SchemaMigration):
}
}
complete_apps = ['student']
complete_apps = ['student']

View File

@@ -19,7 +19,6 @@ class Migration(SchemaMigration):
# Adding unique constraint on 'CourseEnrollment', fields ['user', 'course_id']
db.create_unique('student_courseenrollment', ['user_id', 'course_id'])
def backwards(self, orm):
# Removing unique constraint on 'CourseEnrollment', fields ['user', 'course_id']
db.delete_unique('student_courseenrollment', ['user_id', 'course_id'])
@@ -27,7 +26,6 @@ class Migration(SchemaMigration):
# Deleting model 'CourseEnrollment'
db.delete_table('student_courseenrollment')
models = {
'auth.group': {
'Meta': {'object_name': 'Group'},
@@ -141,4 +139,4 @@ class Migration(SchemaMigration):
}
}
complete_apps = ['student']
complete_apps = ['student']

View File

@@ -13,7 +13,6 @@ class Migration(SchemaMigration):
self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True, null=True, blank=True),
keep_default=False)
# Changing field 'UserProfile.country'
db.alter_column('auth_userprofile', 'country', self.gf('django_countries.fields.CountryField')(max_length=2, null=True))
@@ -21,7 +20,6 @@ class Migration(SchemaMigration):
# Deleting field 'CourseEnrollment.date'
db.delete_column('student_courseenrollment', 'date')
# Changing field 'UserProfile.country'
db.alter_column('auth_userprofile', 'country', self.gf('django.db.models.fields.CharField')(max_length=255, null=True))
@@ -139,4 +137,4 @@ class Migration(SchemaMigration):
}
}
complete_apps = ['student']
complete_apps = ['student']

View File

@@ -15,7 +15,6 @@ class Migration(SchemaMigration):
# Rename 'created' field to 'date'
db.rename_column('student_courseenrollment', 'created', 'date')
models = {
'auth.group': {
'Meta': {'object_name': 'Group'},
@@ -130,4 +129,4 @@ class Migration(SchemaMigration):
}
}
complete_apps = ['student']
complete_apps = ['student']

View File

@@ -11,12 +11,10 @@ class Migration(SchemaMigration):
# Adding index on 'CourseEnrollment', fields ['created']
db.create_index('student_courseenrollment', ['created'])
def backwards(self, orm):
# Removing index on 'CourseEnrollment', fields ['created']
db.delete_index('student_courseenrollment', ['created'])
models = {
'auth.group': {
'Meta': {'object_name': 'Group'},
@@ -131,4 +129,4 @@ class Migration(SchemaMigration):
}
}
complete_apps = ['student']
complete_apps = ['student']

View File

@@ -38,7 +38,6 @@ class Migration(SchemaMigration):
# Adding index on 'UserProfile', fields ['gender']
db.create_index('auth_userprofile', ['gender'])
def backwards(self, orm):
# Removing index on 'UserProfile', fields ['gender']
db.delete_index('auth_userprofile', ['gender'])
@@ -72,7 +71,6 @@ class Migration(SchemaMigration):
# Deleting field 'UserProfile.goals'
db.delete_column('auth_userprofile', 'goals')
models = {
'auth.group': {
'Meta': {'object_name': 'Group'},
@@ -186,4 +184,4 @@ class Migration(SchemaMigration):
}
}
complete_apps = ['student']
complete_apps = ['student']

View File

@@ -18,6 +18,7 @@ from django_countries import CountryField
#from cache_toolbox import cache_model, cache_relation
class UserProfile(models.Model):
class Meta:
db_table = "auth_userprofile"
@@ -28,7 +29,7 @@ class UserProfile(models.Model):
user = models.OneToOneField(User, unique=True, db_index=True, related_name='profile')
name = models.CharField(blank=True, max_length=255, db_index=True)
meta = models.TextField(blank=True) # JSON dictionary for future expansion
meta = models.TextField(blank=True) # JSON dictionary for future expansion
courseware = models.CharField(blank=True, max_length=255, default='course.xml')
# Location is no longer used, but is held here for backwards compatibility
@@ -59,7 +60,6 @@ class UserProfile(models.Model):
mailing_address = models.TextField(blank=True, null=True)
goals = models.TextField(blank=True, null=True)
def get_meta(self):
js_str = self.meta
if not js_str:
@@ -69,9 +69,10 @@ class UserProfile(models.Model):
return js_str
def set_meta(self,js):
def set_meta(self, js):
self.meta = json.dumps(js)
## TODO: Should be renamed to generic UserGroup, and possibly
# Given an optional field for type of group
class UserTestGroup(models.Model):
@@ -79,6 +80,7 @@ class UserTestGroup(models.Model):
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
registration profile is created when the user creates an
@@ -92,8 +94,8 @@ class Registration(models.Model):
def register(self, user):
# MINOR TODO: Switch to crypto-secure key
self.activation_key=uuid.uuid4().hex
self.user=user
self.activation_key = uuid.uuid4().hex
self.user = user
self.save()
def activate(self):
@@ -101,22 +103,25 @@ class Registration(models.Model):
self.user.save()
#self.delete()
class PendingNameChange(models.Model):
user = models.OneToOneField(User, unique=True, db_index=True)
new_name = models.CharField(blank=True, max_length=255)
rationale = models.CharField(blank=True, max_length=1024)
class PendingEmailChange(models.Model):
user = models.OneToOneField(User, unique=True, db_index=True)
new_email = models.CharField(blank=True, max_length=255, db_index=True)
activation_key = models.CharField(('activation key'), max_length=32, unique=True, db_index=True)
class CourseEnrollment(models.Model):
user = models.ForeignKey(User)
course_id = models.CharField(max_length=255, db_index=True)
created = models.DateTimeField(auto_now_add=True, null=True, db_index=True)
class Meta:
unique_together = (('user', 'course_id'), )
@@ -124,38 +129,45 @@ class CourseEnrollment(models.Model):
#### Helper methods for use from python manage.py shell.
def get_user(email):
u = User.objects.get(email = email)
up = UserProfile.objects.get(user = u)
return u,up
u = User.objects.get(email=email)
up = UserProfile.objects.get(user=u)
return u, up
def user_info(email):
u,up = get_user(email)
u, up = get_user(email)
print "User id", u.id
print "Username", u.username
print "E-mail", u.email
print "Name", up.name
print "Location", up.location
print "Language", up.language
return u,up
return u, up
def change_email(old_email, new_email):
u = User.objects.get(email = old_email)
u = User.objects.get(email=old_email)
u.email = new_email
u.save()
def change_name(email, new_name):
u,up = get_user(email)
u, up = get_user(email)
up.name = new_name
up.save()
def user_count():
print "All users", User.objects.all().count()
print "Active users", User.objects.filter(is_active = True).count()
print "Active users", User.objects.filter(is_active=True).count()
return User.objects.all().count()
def active_user_count():
return User.objects.filter(is_active = True).count()
return User.objects.filter(is_active=True).count()
def create_group(name, description):
utg = UserTestGroup()
@@ -163,29 +175,31 @@ def create_group(name, description):
utg.description = description
utg.save()
def add_user_to_group(user, group):
utg = UserTestGroup.objects.get(name = group)
utg.users.add(User.objects.get(username = user))
utg = UserTestGroup.objects.get(name=group)
utg.users.add(User.objects.get(username=user))
utg.save()
def remove_user_from_group(user, group):
utg = UserTestGroup.objects.get(name = group)
utg.users.remove(User.objects.get(username = user))
utg = UserTestGroup.objects.get(name=group)
utg.users.remove(User.objects.get(username=user))
utg.save()
default_groups = {'email_future_courses' : 'Receive e-mails about future MITx courses',
'email_helpers' : 'Receive e-mails about how to help with MITx',
'mitx_unenroll' : 'Fully unenrolled -- no further communications',
'6002x_unenroll' : 'Took and dropped 6002x'}
default_groups = {'email_future_courses': 'Receive e-mails about future MITx courses',
'email_helpers': 'Receive e-mails about how to help with MITx',
'mitx_unenroll': 'Fully unenrolled -- no further communications',
'6002x_unenroll': 'Took and dropped 6002x'}
def add_user_to_default_group(user, group):
try:
utg = UserTestGroup.objects.get(name = group)
utg = UserTestGroup.objects.get(name=group)
except UserTestGroup.DoesNotExist:
utg = UserTestGroup()
utg.name = group
utg.description = default_groups[group]
utg.save()
utg.users.add(User.objects.get(username = user))
utg.users.add(User.objects.get(username=user))
utg.save()

View File

@@ -28,7 +28,7 @@ from django.core.cache import cache
from django_future.csrf import ensure_csrf_cookie
from student.models import Registration, UserProfile, PendingNameChange, PendingEmailChange, CourseEnrollment
from util.cache import cache_if_anonymous
from util.cache import cache_if_anonymous
from xmodule.course_module import CourseDescriptor
from xmodule.modulestore.django import modulestore
from xmodule.modulestore.exceptions import ItemNotFoundError
@@ -80,10 +80,12 @@ def index(request):
return render_to_response('index.html', {'universities': universities, 'entries': entries})
def course_from_id(id):
course_loc = CourseDescriptor.id_to_location(id)
return modulestore().get_item(course_loc)
@login_required
@ensure_csrf_cookie
def dashboard(request):
@@ -100,19 +102,18 @@ def dashboard(request):
except ItemNotFoundError:
log.error("User {0} enrolled in non-existant course {1}"
.format(user.username, enrollment.course_id))
message = ""
if not user.is_active:
message = render_to_string('registration/activate_account_notice.html', {'email': user.email})
context = {'courses': courses, 'message' : message}
context = {'courses': courses, 'message': message}
return render_to_response('dashboard.html', context)
def try_change_enrollment(request):
"""
This method calls change_enrollment if the necessary POST
This method calls change_enrollment if the necessary POST
parameters are present, but does not return anything. It
simply logs the result or exception. This is usually
called after a registration or login, as secondary action.
@@ -126,22 +127,23 @@ def try_change_enrollment(request):
log.info("Attempted to automatically enroll after login. Results: {0}".format(enrollment_output))
except Exception, e:
log.exception("Exception automatically enrolling after login: {0}".format(str(e)))
@login_required
def change_enrollment_view(request):
return HttpResponse(json.dumps(change_enrollment(request)))
def change_enrollment(request):
if request.method != "POST":
raise Http404
action = request.POST.get("enrollment_action" , "")
action = request.POST.get("enrollment_action", "")
user = request.user
course_id = request.POST.get("course_id", None)
if course_id == None:
return HttpResponse(json.dumps({'success': False, 'error': 'There was an error receiving the course id.'}))
if action == "enroll":
# Make sure the course exists
# We don't do this check on unenroll, or a bad course id can't be unenrolled from
@@ -151,22 +153,23 @@ def change_enrollment(request):
log.error("User {0} tried to enroll in non-existant course {1}"
.format(user.username, enrollment.course_id))
return {'success': False, 'error': 'The course requested does not exist.'}
enrollment, created = CourseEnrollment.objects.get_or_create(user=user, course_id=course.id)
return {'success': True}
elif action == "unenroll":
try:
enrollment = CourseEnrollment.objects.get(user=user, course_id=course_id)
enrollment = CourseEnrollment.objects.get(user=user, course_id=course_id)
enrollment.delete()
return {'success': True}
except CourseEnrollment.DoesNotExist:
return {'success': False, 'error': 'You are not enrolled for this course.'}
else:
return {'success': False, 'error': 'Invalid enrollment_action.'}
return {'success': False, 'error': 'We weren\'t able to unenroll you. Please try again.'}
# Need different levels of logging
@ensure_csrf_cookie
def login_user(request, error=""):
@@ -195,7 +198,7 @@ def login_user(request, error=""):
try:
login(request, user)
if request.POST.get('remember') == 'true':
request.session.set_expiry(None) # or change to 604800 for 7 days
request.session.set_expiry(None) # or change to 604800 for 7 days
log.debug("Setting user session to never expire")
else:
request.session.set_expiry(0)
@@ -204,38 +207,41 @@ def login_user(request, error=""):
log.exception(e)
log.info("Login success - {0} ({1})".format(username, email))
try_change_enrollment(request)
return HttpResponse(json.dumps({'success':True}))
return HttpResponse(json.dumps({'success': True}))
log.warning("Login failed - Account not active for user {0}".format(username))
return HttpResponse(json.dumps({'success':False,
return HttpResponse(json.dumps({'success': False,
'value': 'This account has not been activated. Please check your e-mail for the activation instructions.'}))
@ensure_csrf_cookie
def logout_user(request):
''' HTTP request to log out the user. Redirects to marketing page'''
logout(request)
return redirect('/')
@login_required
@ensure_csrf_cookie
def change_setting(request):
''' JSON call to change a profile setting: Right now, location
'''
up = UserProfile.objects.get(user=request.user) #request.user.profile_cache
up = UserProfile.objects.get(user=request.user) # request.user.profile_cache
if 'location' in request.POST:
up.location=request.POST['location']
up.location = request.POST['location']
up.save()
return HttpResponse(json.dumps({'success':True,
'location':up.location,}))
return HttpResponse(json.dumps({'success': True,
'location': up.location, }))
@ensure_csrf_cookie
def create_account(request, post_override=None):
''' JSON call to enroll in the course. '''
js={'success':False}
js = {'success': False}
post_vars = post_override if post_override else request.POST
@@ -246,12 +252,11 @@ def create_account(request, post_override=None):
return HttpResponse(json.dumps(js))
if post_vars.get('honor_code', 'false') != u'true':
js['value']="To enroll, you must follow the honor code.".format(field=a)
js['value'] = "To enroll, you must follow the honor code.".format(field=a)
return HttpResponse(json.dumps(js))
if post_vars.get('terms_of_service', 'false') != u'true':
js['value']="You must accept the terms of service.".format(field=a)
js['value'] = "You must accept the terms of service.".format(field=a)
return HttpResponse(json.dumps(js))
# Confirm appropriate fields are there.
@@ -261,25 +266,25 @@ def create_account(request, post_override=None):
# TODO: Check password is sane
for a in ['username', 'email', 'name', 'password', 'terms_of_service', 'honor_code']:
if len(post_vars[a]) < 2:
error_str = {'username' : 'Username of length 2 or greater',
'email' : 'Properly formatted e-mail',
'name' : 'Your legal name ',
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])
js['value'] = "{field} is required.".format(field=error_str[a])
return HttpResponse(json.dumps(js))
try:
validate_email(post_vars['email'])
except ValidationError:
js['value']="Valid e-mail is required.".format(field=a)
js['value'] = "Valid e-mail is required.".format(field=a)
return HttpResponse(json.dumps(js))
try:
validate_slug(post_vars['username'])
except ValidationError:
js['value']="Username should only consist of A-Z and 0-9.".format(field=a)
js['value'] = "Username should only consist of A-Z and 0-9.".format(field=a)
return HttpResponse(json.dumps(js))
u = User(username=post_vars['username'],
@@ -311,17 +316,17 @@ def create_account(request, post_override=None):
up.gender = post_vars.get('gender')
up.mailing_address = post_vars.get('mailing_address')
up.goals = post_vars.get('goals')
try:
up.year_of_birth = int(post_vars['year_of_birth'])
except (ValueError, KeyError):
up.year_of_birth = None # If they give us garbage, just ignore it instead
up.year_of_birth = None # If they give us garbage, just ignore it instead
# of asking them to put an integer.
try:
up.save()
except Exception:
log.exception("UserProfile creation failed for user {0}.".format(u.id))
d = {'name': post_vars['name'],
'key': r.activation_key,
}
@@ -334,7 +339,7 @@ def create_account(request, post_override=None):
try:
if settings.MITX_FEATURES.get('REROUTE_ACTIVATION_EMAIL'):
dest_addr = settings.MITX_FEATURES['REROUTE_ACTIVATION_EMAIL']
message = "Activation for %s (%s): %s\n" % (u,u.email,up.name) + '-' * 80 + '\n\n' + message
message = "Activation for %s (%s): %s\n" % (u, u.email, up.name) + '-' * 80 + '\n\n' + message
send_mail(subject, message, settings.DEFAULT_FROM_EMAIL, [dest_addr], fail_silently=False)
elif not settings.GENERATE_RANDOM_USER_CREDENTIALS:
res = u.email_user(subject, message, settings.DEFAULT_FROM_EMAIL)
@@ -342,57 +347,60 @@ def create_account(request, post_override=None):
log.exception(sys.exc_info())
js['value'] = 'Could not send activation e-mail.'
return HttpResponse(json.dumps(js))
# Immediately after a user creates an account, we log them in. They are only
# logged in until they close the browser. They can't log in again until they click
# the activation link from the email.
login_user = authenticate(username=post_vars['username'], password = post_vars['password'] )
login_user = authenticate(username=post_vars['username'], password=post_vars['password'])
login(request, login_user)
request.session.set_expiry(0)
request.session.set_expiry(0)
try_change_enrollment(request)
js={'success': True}
js = {'success': True}
return HttpResponse(json.dumps(js), mimetype="application/json")
def create_random_account(create_account_function):
def id_generator(size=6, chars=string.ascii_uppercase + string.ascii_lowercase + string.digits):
return ''.join(random.choice(chars) for x in range(size))
def inner_create_random_account(request):
post_override= {'username' : "random_" + id_generator(),
'email' : id_generator(size=10, chars=string.ascii_lowercase) + "_dummy_test@mitx.mit.edu",
'password' : id_generator(),
'location' : id_generator(size=5, chars=string.ascii_uppercase),
'name' : id_generator(size=5, chars=string.ascii_lowercase) + " " + id_generator(size=7, chars=string.ascii_lowercase),
'honor_code' : u'true',
'terms_of_service' : u'true',}
post_override = {'username': "random_" + id_generator(),
'email': id_generator(size=10, chars=string.ascii_lowercase) + "_dummy_test@mitx.mit.edu",
'password': id_generator(),
'location': id_generator(size=5, chars=string.ascii_uppercase),
'name': id_generator(size=5, chars=string.ascii_lowercase) + " " + id_generator(size=7, chars=string.ascii_lowercase),
'honor_code': u'true',
'terms_of_service': u'true', }
return create_account_function(request, post_override = post_override)
return create_account_function(request, post_override=post_override)
return inner_create_random_account
if settings.GENERATE_RANDOM_USER_CREDENTIALS:
create_account = create_random_account(create_account)
@ensure_csrf_cookie
def activate_account(request, key):
''' When link in activation e-mail is clicked
'''
r=Registration.objects.filter(activation_key=key)
if len(r)==1:
r = Registration.objects.filter(activation_key=key)
if len(r) == 1:
user_logged_in = request.user.is_authenticated()
already_active = True
if not r[0].user.is_active:
r[0].activate()
already_active = False
resp = render_to_response("registration/activation_complete.html",{'user_logged_in':user_logged_in, 'already_active' : already_active})
resp = render_to_response("registration/activation_complete.html", {'user_logged_in': user_logged_in, 'already_active': already_active})
return resp
if len(r)==0:
return render_to_response("registration/activation_invalid.html",{'csrf':csrf(request)['csrf_token']})
if len(r) == 0:
return render_to_response("registration/activation_invalid.html", {'csrf': csrf(request)['csrf_token']})
return HttpResponse("Unknown error. Please e-mail us to let us know how it happened.")
@ensure_csrf_cookie
def password_reset(request):
''' Attempts to send a password reset e-mail. '''
@@ -400,43 +408,44 @@ def password_reset(request):
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,
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,
return HttpResponse(json.dumps({'success': False,
'error': 'Invalid e-mail'}))
@ensure_csrf_cookie
def reactivation_email(request):
''' Send an e-mail to reactivate a deactivated account, or to
resend an activation e-mail. Untested. '''
email = request.POST['email']
try:
user = User.objects.get(email = 'email')
user = User.objects.get(email='email')
except User.DoesNotExist:
return HttpResponse(json.dumps({'success':False,
return HttpResponse(json.dumps({'success': False,
'error': 'No inactive user with this e-mail exists'}))
if user.is_active:
return HttpResponse(json.dumps({'success':False,
return HttpResponse(json.dumps({'success': False,
'error': 'User is already active'}))
reg = Registration.objects.get(user = user)
reg = Registration.objects.get(user=user)
reg.register(user)
d={'name':UserProfile.get(user = user).name,
'key':r.activation_key}
d = {'name': UserProfile.get(user=user).name,
'key': r.activation_key}
subject = render_to_string('reactivation_email_subject.txt',d)
subject = render_to_string('reactivation_email_subject.txt', d)
subject = ''.join(subject.splitlines())
message = render_to_string('reactivation_email.txt',d)
message = render_to_string('reactivation_email.txt', d)
res=u.email_user(subject, message, settings.DEFAULT_FROM_EMAIL)
res = u.email_user(subject, message, settings.DEFAULT_FROM_EMAIL)
return HttpResponse(json.dumps({'success':True}))
return HttpResponse(json.dumps({'success': True}))
@ensure_csrf_cookie
@@ -450,26 +459,26 @@ def change_email_request(request):
user = request.user
if not user.check_password(request.POST['password']):
return HttpResponse(json.dumps({'success':False,
'error':'Invalid password'}))
return HttpResponse(json.dumps({'success': False,
'error': 'Invalid password'}))
new_email = request.POST['new_email']
try:
validate_email(new_email)
except ValidationError:
return HttpResponse(json.dumps({'success':False,
'error':'Valid e-mail address required.'}))
return HttpResponse(json.dumps({'success': False,
'error': 'Valid e-mail address required.'}))
if len(User.objects.filter(email = new_email)) != 0:
if len(User.objects.filter(email=new_email)) != 0:
## CRITICAL TODO: Handle case sensitivity for e-mails
return HttpResponse(json.dumps({'success':False,
'error':'An account with this e-mail already exists.'}))
return HttpResponse(json.dumps({'success': False,
'error': 'An account with this e-mail already exists.'}))
pec_list = PendingEmailChange.objects.filter(user = request.user)
pec_list = PendingEmailChange.objects.filter(user=request.user)
if len(pec_list) == 0:
pec = PendingEmailChange()
pec.user = user
else :
else:
pec = pec_list[0]
pec.new_email = request.POST['new_email']
@@ -478,20 +487,21 @@ def change_email_request(request):
if pec.new_email == user.email:
pec.delete()
return HttpResponse(json.dumps({'success':False,
'error':'Old email is the same as the new email.'}))
return HttpResponse(json.dumps({'success': False,
'error': 'Old email is the same as the new email.'}))
d = {'key':pec.activation_key,
'old_email' : user.email,
'new_email' : pec.new_email}
d = {'key': pec.activation_key,
'old_email': user.email,
'new_email': pec.new_email}
subject = render_to_string('emails/email_change_subject.txt',d)
subject = render_to_string('emails/email_change_subject.txt', d)
subject = ''.join(subject.splitlines())
message = render_to_string('emails/email_change.txt',d)
message = render_to_string('emails/email_change.txt', d)
res=send_mail(subject, message, settings.DEFAULT_FROM_EMAIL, [pec.new_email])
res = send_mail(subject, message, settings.DEFAULT_FROM_EMAIL, [pec.new_email])
return HttpResponse(json.dumps({'success': True}))
return HttpResponse(json.dumps({'success':True}))
@ensure_csrf_cookie
def confirm_email_change(request, key):
@@ -499,22 +509,21 @@ def confirm_email_change(request, key):
link is clicked. We confirm with the old e-mail, and update
'''
try:
pec=PendingEmailChange.objects.get(activation_key=key)
pec = PendingEmailChange.objects.get(activation_key=key)
except PendingEmailChange.DoesNotExist:
return render_to_response("invalid_email_key.html", {})
user = pec.user
d = {'old_email' : user.email,
'new_email' : pec.new_email}
d = {'old_email': user.email,
'new_email': pec.new_email}
if len(User.objects.filter(email = pec.new_email)) != 0:
if len(User.objects.filter(email=pec.new_email)) != 0:
return render_to_response("email_exists.html", d)
subject = render_to_string('emails/email_change_subject.txt',d)
subject = render_to_string('emails/email_change_subject.txt', d)
subject = ''.join(subject.splitlines())
message = render_to_string('emails/confirm_email_change.txt',d)
up = UserProfile.objects.get( user = user )
message = render_to_string('emails/confirm_email_change.txt', d)
up = UserProfile.objects.get(user=user)
meta = up.get_meta()
if 'old_emails' not in meta:
meta['old_emails'] = []
@@ -528,6 +537,7 @@ def confirm_email_change(request, key):
return render_to_response("email_change_successful.html", d)
@ensure_csrf_cookie
def change_name_request(request):
''' Log a request for a new name. '''
@@ -535,18 +545,18 @@ def change_name_request(request):
raise Http404
try:
pnc = PendingNameChange.objects.get(user = request.user)
pnc = PendingNameChange.objects.get(user=request.user)
except PendingNameChange.DoesNotExist:
pnc = PendingNameChange()
pnc.user = request.user
pnc.new_name = request.POST['new_name']
pnc.rationale = request.POST['rationale']
if len(pnc.new_name)<2:
return HttpResponse(json.dumps({'success':False,'error':'Name required'}))
if len(pnc.rationale)<2:
return HttpResponse(json.dumps({'success':False,'error':'Rationale required'}))
if len(pnc.new_name) < 2:
return HttpResponse(json.dumps({'success': False, 'error': 'Name required'}))
if len(pnc.rationale) < 2:
return HttpResponse(json.dumps({'success': False, 'error': 'Rationale required'}))
pnc.save()
return HttpResponse(json.dumps({'success':True}))
return HttpResponse(json.dumps({'success': True}))
@ensure_csrf_cookie

View File

@@ -4,6 +4,7 @@ from django.conf import settings
import views
class TrackMiddleware:
def process_request(self, request):
try:
@@ -11,34 +12,34 @@ class TrackMiddleware:
# names/passwords.
if request.META['PATH_INFO'] in ['/event', '/login']:
return
# Removes passwords from the tracking logs
# WARNING: This list needs to be changed whenever we change
# password handling functionality.
# password handling functionality.
#
# As of the time of this comment, only 'password' is used
# The rest are there for future extension.
# The rest are there for future extension.
#
# Passwords should never be sent as GET requests, but
# Passwords should never be sent as GET requests, but
# this can happen due to older browser bugs. We censor
# this too.
#
# this too.
#
# We should manually confirm no passwords make it into log
# files when we change this.
# files when we change this.
censored_strings = ['password', 'newpassword', 'new_password',
censored_strings = ['password', 'newpassword', 'new_password',
'oldpassword', 'old_password']
post_dict = dict(request.POST)
get_dict = dict(request.GET)
for string in censored_strings:
if string in post_dict:
post_dict[string] = '*'*8
if string in get_dict:
get_dict[string] = '*'*8
for string in censored_strings:
if string in post_dict:
post_dict[string] = '*' * 8
if string in get_dict:
get_dict[string] = '*' * 8
event = {'GET': dict(get_dict),
'POST': dict(post_dict)}
event = { 'GET' : dict(get_dict),
'POST' : dict(post_dict)}
# TODO: Confirm no large file uploads
event = json.dumps(event)
event = event[:512]

View File

@@ -10,61 +10,64 @@ from django.conf import settings
log = logging.getLogger("tracking")
def log_event(event):
event_str = json.dumps(event)
log.info(event_str[:settings.TRACK_MAX_EVENT])
def user_track(request):
try: # TODO: Do the same for many of the optional META parameters
try: # TODO: Do the same for many of the optional META parameters
username = request.user.username
except:
except:
username = "anonymous"
try:
scookie = request.META['HTTP_COOKIE'] # Get cookies
scookie = ";".join([c.split('=')[1] for c in scookie.split(";") if "sessionid" in c]).strip() # Extract session ID
except:
try:
scookie = request.META['HTTP_COOKIE'] # Get cookies
scookie = ";".join([c.split('=')[1] for c in scookie.split(";") if "sessionid" in c]).strip() # Extract session ID
except:
scookie = ""
try:
try:
agent = request.META['HTTP_USER_AGENT']
except:
except:
agent = ''
# TODO: Move a bunch of this into log_event
event = {
"username" : username,
"session" : scookie,
"ip" : request.META['REMOTE_ADDR'],
"event_source" : "browser",
"event_type" : request.GET['event_type'],
"event" : request.GET['event'],
"agent" : agent,
"page" : request.GET['page'],
"username": username,
"session": scookie,
"ip": request.META['REMOTE_ADDR'],
"event_source": "browser",
"event_type": request.GET['event_type'],
"event": request.GET['event'],
"agent": agent,
"page": request.GET['page'],
"time": datetime.datetime.utcnow().isoformat(),
}
log_event(event)
return HttpResponse('success')
def server_track(request, event_type, event, page=None):
try:
try:
username = request.user.username
except:
except:
username = "anonymous"
try:
try:
agent = request.META['HTTP_USER_AGENT']
except:
except:
agent = ''
event = {
"username" : username,
"ip" : request.META['REMOTE_ADDR'],
"event_source" : "server",
"event_type" : event_type,
"event" : event,
"agent" : agent,
"page" : page,
"username": username,
"ip": request.META['REMOTE_ADDR'],
"event_source": "server",
"event_type": event_type,
"event": event,
"agent": agent,
"page": page,
"time": datetime.datetime.utcnow().isoformat(),
}
log_event(event)

View File

@@ -2,7 +2,7 @@
This module aims to give a little more fine-tuned control of caching and cache
invalidation. Import these instead of django.core.cache.
Note that 'default' is being preserved for user session caching, which we're
Note that 'default' is being preserved for user session caching, which we're
not migrating so as not to inconvenience users by logging them all out.
"""
from functools import wraps
@@ -16,26 +16,27 @@ try:
except Exception:
cache = cache.cache
def cache_if_anonymous(view_func):
"""
Many of the pages in edX are identical when the user is not logged
in, but should not be cached when the user is logged in (because
of the navigation bar at the top with the username).
in, but should not be cached when the user is logged in (because
of the navigation bar at the top with the username).
The django middleware cache does not handle this correctly, because
we access the session to put the csrf token in the header. This adds
the cookie to the vary header, and so every page is cached seperately
for each user (because each user has a different csrf token).
Note that this decorator should only be used on views that do not
contain the csrftoken within the html. The csrf token can be included
in the header by ordering the decorators as such:
@ensure_csrftoken
@cache_if_anonymous
def myView(request):
"""
@wraps(view_func)
def _decorated(request, *args, **kwargs):
if not request.user.is_authenticated():
@@ -45,12 +46,12 @@ def cache_if_anonymous(view_func):
if not response:
response = view_func(request, *args, **kwargs)
cache.set(cache_key, response, 60 * 3)
return response
else:
#Don't use the cache
return view_func(request, *args, **kwargs)
return _decorated

View File

@@ -2,6 +2,7 @@ from functools import wraps
import copy
import json
def expect_json(view_function):
@wraps(view_function)
def expect_json_with_cloned_request(request, *args, **kwargs):

View File

@@ -6,11 +6,13 @@ from django.utils.encoding import smart_str
import hashlib
import urllib
def fasthash(string):
m = hashlib.new("md4")
m.update(string)
return m.hexdigest()
def safe_key(key, key_prefix, version):
safe_key = urllib.quote_plus(smart_str(key))

View File

@@ -5,12 +5,12 @@ from django.http import HttpResponseServerError
log = logging.getLogger("mitx")
class ExceptionLoggingMiddleware(object):
"""Just here to log unchecked exceptions that go all the way up the Django
"""Just here to log unchecked exceptions that go all the way up the Django
stack"""
if not settings.TEMPLATE_DEBUG:
def process_exception(self, request, exception):
log.exception(exception)
return HttpResponseServerError("Server Error - Please try again later.")

View File

@@ -14,53 +14,57 @@ from mitxmako.shortcuts import render_to_response, render_to_string
import capa.calc
import track.views
def calculate(request):
''' Calculator in footer of every page. '''
equation = request.GET['equation']
try:
try:
result = capa.calc.evaluator({}, {}, equation)
except:
event = {'error':map(str,sys.exc_info()),
'equation':equation}
event = {'error': map(str, sys.exc_info()),
'equation': equation}
track.views.server_track(request, 'error:calc', event, page='calc')
return HttpResponse(json.dumps({'result':'Invalid syntax'}))
return HttpResponse(json.dumps({'result':str(result)}))
return HttpResponse(json.dumps({'result': 'Invalid syntax'}))
return HttpResponse(json.dumps({'result': str(result)}))
def send_feedback(request):
''' Feeback mechanism in footer of every page. '''
try:
try:
username = request.user.username
email = request.user.email
except:
except:
username = "anonymous"
email = "anonymous"
try:
browser = request.META['HTTP_USER_AGENT']
except:
browser = "Unknown"
feedback = render_to_string("feedback_email.txt",
{"subject":request.POST['subject'],
"url": request.POST['url'],
"time": datetime.datetime.now().isoformat(),
"feedback": request.POST['message'],
"email":email,
"browser":browser,
"user":username})
send_mail("MITx Feedback / " +request.POST['subject'],
feedback,
try:
browser = request.META['HTTP_USER_AGENT']
except:
browser = "Unknown"
feedback = render_to_string("feedback_email.txt",
{"subject": request.POST['subject'],
"url": request.POST['url'],
"time": datetime.datetime.now().isoformat(),
"feedback": request.POST['message'],
"email": email,
"browser": browser,
"user": username})
send_mail("MITx Feedback / " + request.POST['subject'],
feedback,
settings.DEFAULT_FROM_EMAIL,
[ settings.DEFAULT_FEEDBACK_EMAIL ],
fail_silently = False
[settings.DEFAULT_FEEDBACK_EMAIL],
fail_silently=False
)
return HttpResponse(json.dumps({'success':True}))
return HttpResponse(json.dumps({'success': True}))
def info(request):
''' Info page (link from main header) '''
return render_to_response("info.html", {})
# From http://djangosnippets.org/snippets/1042/
def parse_accept_header(accept):
"""Parse the Accept header *accept*, returning a list with pairs of
@@ -82,6 +86,7 @@ def parse_accept_header(accept):
result.sort(lambda x, y: -cmp(x[2], y[2]))
return result
def accepts(request, media_type):
"""Return whether this request has an Accept header that matches type"""
accept = parse_accept_header(request.META.get("HTTP_ACCEPT", ""))