Commit 4b6681b3 by Bridger Maxwell

Merged in default

--HG--
branch : bridger-dev
parents 13a7d2cb 8c3c33b7
Copyright © 2010, 2011 UUMC Ltd. <tech@playfire.com>
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the <organization> nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
django-cache-toolbox
============================
Documentation: http://code.playfire.com/django-cache-toolbox/
"""
:mod:`cache_toolbox` --- Non-magical object caching tools for Django
====================================================================
Introduction
------------
``cache_toolbox`` is intended to be a lightweight series of independent tools
to leverage caching within Django projects.
The tools are deliberately `non-magical`. That is to say, instances are never
retrieved from caches behind your back and regular Django ``.filter()`` /
``.get()`` queries continue to work exactly as before.
Because of this, you can introduce ``cache_toolbox`` into your project slowly
when needed rather than "switching" to it with invasive changes.
Links
-----
View/download code
https://github.com/playfire/django-cache-toolbox
File a bug
https://github.com/playfire/django-cache-toolbox/issues
"""
from .model import cache_model
from .relation import cache_relation
from django.conf import settings
# Default cache timeout
CACHE_TOOLBOX_DEFAULT_TIMEOUT = getattr(
settings,
'CACHE_TOOLBOX_DEFAULT_TIMEOUT',
60 * 60 * 24 * 3,
)
"""
Core methods
------------
.. autofunction:: cache_toolbox.core.get_instance
.. autofunction:: cache_toolbox.core.delete_instance
.. autofunction:: cache_toolbox.core.instance_key
"""
from django.core.cache import cache
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``.
If the data is cached it will be returned from there, otherwise the regular
Django ORM is queried for this instance and the data stored in the cache.
If omitted, the timeout value defaults to
``settings.CACHE_TOOLBOX_DEFAULT_TIMEOUT`` instead of 0 (zero).
Example::
>>> get_instance(User, 1) # Cache miss
<User: lamby>
>>> get_instance(User, 1) # Cache hit
<User: lamby>
>>> User.objects.get(pk=1) == get_instance(User, 1)
True
"""
pk = getattr(instance_or_pk, 'pk', instance_or_pk)
key = instance_key(model, instance_or_pk)
data = cache.get(key)
if data is not None:
try:
# Try and construct instance from dictionary
instance = model(pk=pk, **data)
# Ensure instance knows that it already exists in the database,
# otherwise we will fail any uniqueness checks when saving the
# instance.
instance._state.adding = False
# Specify database so that instance is setup correctly. We don't
# namespace cached objects by their origin database, however.
instance._state.db = using or DEFAULT_DB_ALIAS
return instance
except:
# Error when deserialising - remove from the cache; we will
# fallback and return the underlying instance
cache.delete(key)
# Use the default manager so we are never filtered by a .get_query_set()
instance = model._default_manager.using(using).get(pk=pk)
data = {}
for field in instance._meta.fields:
# Harmless to save, but saves space in the dictionary - we already know
# the primary key when we lookup
if field.primary_key:
continue
if field.get_internal_type() == 'FileField':
# Avoid problems with serializing FileFields
# by only serializing the file name
file = getattr(instance, field.attname)
data[field.attname] = file.name
else:
data[field.attname] = getattr(instance, field.attname)
if timeout is None:
timeout = app_settings.CACHE_TOOLBOX_DEFAULT_TIMEOUT
cache.set(key, data, timeout)
return instance
def delete_instance(model, *instance_or_pk):
"""
Purges the cache keys for the instances of this model.
"""
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.
"""
return '%s.%s:%d' % (
model._meta.app_label,
model._meta.module_name,
getattr(instance_or_pk, 'pk', instance_or_pk),
)
"""
Cache-backed ``AuthenticationMiddleware``
-----------------------------------------
``CacheBackedAuthenticationMiddleware`` is an
``django.contrib.auth.middleware.AuthenticationMiddleware`` replacement to
avoid querying the database for a ``User`` instance in each request.
Whilst the built-in ``AuthenticationMiddleware`` mechanism will only obtain the
``User`` instance when it is required, the vast majority of sites will do so on
every page to render "Logged in as 'X'" text as well to evaluate the result of
``user.is_authenticated()`` and ``user.is_superuser`` to provide conditional
functionality.
This middleware eliminates the cost of retrieving this ``User`` instance by
caching it using the ``cache_toolbox`` instance caching mechanisms.
Depending on your average number of queries per page, saving one query per
request can---in aggregate---reduce load on your database. In addition,
avoiding the database entirely for pages can avoid incurring any connection
latency in your environment, resulting in faster page loads for your users.
Saving this data in the cache can also be used as a way of authenticating users
in systems outside of Django that should not access your database. For
example, a "maintenance mode" page would be able to render a personalised
message without touching the database at all but rather authenticating via the
cache.
``CacheBackedAuthenticationMiddleware`` is ``AUTHENTICATION_BACKENDS`` agnostic.
Implementation
~~~~~~~~~~~~~~
The cache and session backends are still accessed on each request - we are
simply assuming that they are cheaper (or otherwise more preferable) to access
than your database. (In the future, signed cookies may allow us to avoid this
lookup altogether -- whilst we could not safely save ``User.password`` in a
cookie, we could use delayed loading to pull it out when needed.)
Another alternative solution would be to store the attributes in the user's
session instead of in the cache. This would save the cache hit on every request
as all the relevant data would be pulled in one go from the session backend.
However, this has two main disadvantages:
* Session keys are not deterministic -- after making changes to an
``auth_user`` row in the database, you cannot determine the user's session
key to flush the now out-of-sync data (and doing so would log them out
anyway).
* Stores data per-session rather than per-user -- if a user logs in from
multiple computers the data is duplicated in each session. This problem is
compounded by most projects wishing to avoid expiring session data as long
as possible (in addition to storing sessions in persistent stores).
Usage
~~~~~
To use, find ``MIDDLEWARE_CLASSES`` in your ``settings.py`` and replace::
MIDDLEWARE_CLASSES = [
...
'django.contrib.auth.middleware.AuthenticationMiddleware',
...
]
with::
MIDDLEWARE_CLASSES = [
...
'cache_toolbox.middleware.CacheBackedAuthenticationMiddleware',
...
]
You should confirm you are using a ``SESSION_ENGINE`` that doesn't query the
database for each request. The built-in ``cached_db`` engine is the safest
choice for most environments but you may be happy with the trade-offs of the
``memcached`` backend - see the Django documentation for more details.
"""
from django.contrib.auth import SESSION_KEY
from django.contrib.auth.models import User
from django.contrib.auth.middleware import AuthenticationMiddleware
from .model import cache_model
class CacheBackedAuthenticationMiddleware(AuthenticationMiddleware):
def __init__(self):
cache_model(User)
def process_request(self, request):
try:
# Try and construct a User instance from data stored in the cache
request.user = User.get_cached(request.session[SESSION_KEY])
except:
# Fallback to constructing the User from the database.
super(CacheBackedAuthenticationMiddleware, self).process_request(request)
"""
Caching model instances
-----------------------
``cache_model`` adds utility methods to a model to obtain ``ForeignKey``
instances via the cache.
Usage
~~~~~
::
from django.db import models
from django.contrib.auth.models import User
class Foo(models.Model):
name = models.CharField(length=20)
cache_model(Foo)
::
>>> a = Foo.objects.create(name='a')
>>> a
<Foo: >
>>> Foo.get_cached(a.pk) # Cache miss
<Foo: >
>>> a = Foo.get_cached(a.pk) # Cache hit
>>> a.name
u'a'
Instances returned from ``get_cached`` are real model instances::
>>> a = Foo.get_cached(a.pk) # Cache hit
>>> type(a)
<class '__main__.models.A'>
>>> a.pk
1L
Invalidation
~~~~~~~~~~~~
Invalidation is performed automatically upon saving or deleting a ``Foo``
instance::
>>> a = Foo.objects.create(name='a')
>>> a.name = 'b'
>>> a.save()
>>> a = Foo.get_cached(a.pk)
>>> a.name
u'b'
>>> a.delete()
>>> a = Foo.get_cached(a.pk)
... Foo.DoesNotExist
"""
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
return
def clear_cache(sender, instance, *args, **kwargs):
delete_instance(sender, instance)
post_save.connect(clear_cache, sender=model, weak=False)
post_delete.connect(clear_cache, sender=model, weak=False)
@classmethod
def get(cls, pk, using=None):
if pk is None:
return None
return get_instance(cls, pk, timeout, using)
model.get_cached = get
"""
Caching instances via ``related_name``
--------------------------------------
``cache_relation`` adds utility methods to a model to obtain ``related_name``
instances via the cache.
Usage
~~~~~
::
from django.db import models
from django.contrib.auth.models import User
class Foo(models.Model):
user = models.OneToOneField(
User,
primary_key=True,
related_name='foo',
)
name = models.CharField(max_length=20)
cache_relation(User.foo)
::
>>> user = User.objects.get(pk=1)
>>> user.foo_cache # Cache miss - hits the database
<Foo: >
>>> user = User.objects.get(pk=1)
>>> user.foo_cache # Cache hit - no database access
<Foo: >
>>> user = User.objects.get(pk=2)
>>> user.foo # Regular lookup - hits the database
<Foo: >
>>> user.foo_cache # Special-case: Will not hit cache or database.
<Foo: >
Accessing ``user_instance.foo_cache`` (note the "_cache" suffix) will now
obtain the related ``Foo`` instance via the cache. Accessing the original
``user_instance.foo`` attribute will perform the lookup as normal.
Invalidation
~~~~~~~~~~~~
Upon saving (or deleting) the instance, the cache is cleared. For example::
>>> user = User.objects.get(pk=1)
>>> foo = user.foo_cache # (Assume cache hit from previous session)
>>> foo.name = "New name"
>>> foo.save() # Cache is cleared on save
>>> user = User.objects.get(pk=1)
>>> user.foo_cache # Cache miss.
<Foo: >
Manual invalidation may also be performed using the following methods::
>>> user_instance.foo_cache_clear()
>>> User.foo_cache_clear_fk(user_instance_pk)
Manual invalidation is required if you use ``.update()`` methods which the
``post_save`` and ``post_delete`` hooks cannot intercept.
Support
~~~~~~~
``cache_relation`` currently only works with ``OneToOneField`` fields. Support
for regular ``ForeignKey`` fields is planned.
"""
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()
@property
def get(self):
# Always use the cached "real" instance if available
try:
return getattr(self, descriptor.cache_name)
except AttributeError:
pass
# Lookup cached instance
try:
return getattr(self, '_%s_cache' % related_name)
except AttributeError:
pass
instance = get_instance(rel.model, self.pk, timeout)
setattr(self, '_%s_cache' % related_name, instance)
return instance
setattr(rel.parent_model, related_name, get)
# Clearing cache
def clear(self):
delete_instance(rel.model, self)
@classmethod
def clear_pk(cls, *instances_or_pk):
delete_instance(rel.model, *instances_or_pk)
def clear_cache(sender, instance, *args, **kwargs):
delete_instance(rel.model, instance)
setattr(rel.parent_model, '%s_clear' % related_name, clear)
setattr(rel.parent_model, '%s_clear_pk' % related_name, clear_pk)
post_save.connect(clear_cache, sender=rel.model, weak=False)
post_delete.connect(clear_cache, sender=rel.model, weak=False)
from django import template
from django.core.cache import cache
from django.template import Node, TemplateSyntaxError, Variable
from django.template import resolve_variable
register = template.Library()
class CacheNode(Node):
def __init__(self, nodelist, expire_time, key):
self.nodelist = nodelist
self.expire_time = Variable(expire_time)
self.key = key
def render(self, context):
key = resolve_variable(self.key, context)
expire_time = int(self.expire_time.resolve(context))
value = cache.get(key)
if value is None:
value = self.nodelist.render(context)
cache.set(key, value, expire_time)
return value
@register.tag
def cachedeterministic(parser, token):
"""
This will cache the contents of a template fragment for a given amount of
time, just like {% cache .. %} except that the key is deterministic and not
mangled or run through MD5.
Usage::
{% cachedeterministic [expire_time] [key] %}
.. some expensive processing ..
{% endcachedeterministic %}
"""
nodelist = parser.parse(('endcachedeterministic',))
parser.delete_first_token()
tokens = token.contents.split()
if len(tokens) != 3:
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
def render(self, context):
key = resolve_variable(self.key, context)
return cache.get(key) or ''
@register.tag
def showifcached(parser, token):
"""
Show content if it exists in the cache, otherwise display nothing.
The key is entirely deterministic and not mangled or run through MD5 (cf.
{% cache %})
Usage::
{% showifcached [key] %}
"""
tokens = token.contents.split()
if len(tokens) != 2:
raise TemplateSyntaxError(u"'%r' tag requires 1 argument." % tokens[0])
return ShowIfCachedNode(tokens[1])
......@@ -127,7 +127,7 @@ class formularesponse(object):
value = random.uniform(*ranges[var])
instructor_variables[str(var)] = value
student_variables[str(var)] = value
instructor_result = evaluator(instructor_variables,dict(),self.correct_answer)
instructor_result = evaluator(instructor_variables,dict(),self.correct_answer, cs = self.case_sensitive)
try:
#print student_variables,dict(),student_answers[self.answer_id]
student_result = evaluator(student_variables,dict(),
......
......@@ -9,6 +9,7 @@ from lxml import etree
try: # This lets us do __name__ == ='__main__'
from django.conf import settings
from django.core.cache import cache
from student.models import UserProfile
from student.models import UserTestGroup
from mitxmako.shortcuts import render_to_response, render_to_string
......@@ -144,7 +145,16 @@ def propogate_downward_tag(element, attribute_name, parent_attribute = None):
def user_groups(user):
# TODO: Rewrite in Django
return [u.name for u in UserTestGroup.objects.raw("select * from auth_user, student_usertestgroup, student_usertestgroup_users where auth_user.id = student_usertestgroup_users.user_id and student_usertestgroup_users.usertestgroup_id = student_usertestgroup.id and auth_user.id = %s", [user.id])]
key = 'user_group_names_{user.id}'.format(user=user)
cache_expiration = 60 * 60 * 4 # four hours
group_names = cache.get(key)
if group_names is None:
group_names = [u.name for u in UserTestGroup.objects.filter(users=user)]
cache.set(key, group_names, cache_expiration)
return group_names
# return [u.name for u in UserTestGroup.objects.raw("select * from auth_user, student_usertestgroup, student_usertestgroup_users where auth_user.id = student_usertestgroup_users.user_id and student_usertestgroup_users.usertestgroup_id = student_usertestgroup.id and auth_user.id = %s", [user.id])]
def course_xml_process(tree):
''' Do basic pre-processing of an XML tree. Assign IDs to all
......@@ -158,17 +168,23 @@ def course_xml_process(tree):
return tree
def course_file(user):
''' Given a user, return course.xml
'''
# TODO: Cache.
filename = UserProfile.objects.get(user=user).courseware
''' Given a user, return course.xml'''
filename = user.profile_cache.courseware # UserProfile.objects.get(user=user).courseware
groups = user_groups(user)
options = {'dev_content':settings.DEV_CONTENT,
'groups' : groups}
tree = course_xml_process(etree.XML(render_to_string(filename, options, namespace = 'course')))
cache_key = filename + "_processed?dev_content:" + str(options['dev_content']) + "&groups:" + str(sorted(groups))
tree_string = cache.get(cache_key)
if not tree_string:
tree = course_xml_process(etree.XML(render_to_string(filename, options, namespace = 'course')))
tree_string = etree.tostring(tree)
cache.set(cache_key, tree_string, 60)
else:
tree = etree.XML(tree_string)
return tree
def section_file(user, section):
......
......@@ -8,10 +8,19 @@ file and check it in at the same time as your model changes. To do that,
2. ./manage.py schemamigration courseware --auto description_of_your_change
3. Add the migration file created in mitx/courseware/migrations/
ASSUMPTIONS: modules have unique IDs, even across different module_types
"""
from django.db import models
from django.db.models.signals import post_save, post_delete
from django.core.cache import cache
from django.contrib.auth.models import User
from cache_toolbox import cache_model, cache_relation
CACHE_TIMEOUT = 60 * 60 * 4 # Set the cache timeout to be four hours
class StudentModule(models.Model):
# For a homework problem, contains a JSON
# object consisting of state
......@@ -49,4 +58,35 @@ class StudentModule(models.Model):
def __unicode__(self):
return self.module_type+'/'+self.student.username+"/"+self.module_id+'/'+str(self.state)[:20]
@classmethod
def get_with_caching(cls, student, module_id):
k = cls.key_for(student, module_id)
student_module = cache.get(k)
if student_module is None:
student_module = StudentModule.objects.filter(student=student,
module_id=module_id)[0]
# It's possible it really doesn't exist...
if student_module is not None:
cache.set(k, student_module, CACHE_TIMEOUT)
return student_module
@classmethod
def key_for(cls, student, module_id):
return "StudentModule-student_id:{0};module_id:{1}".format(student.id, module_id)
def clear_cache_by_student_and_module_id(sender, instance, *args, **kwargs):
k = sender.key_for(instance.student, instance.module_id)
cache.delete(k)
def update_cache_by_student_and_module_id(sender, instance, *args, **kwargs):
k = sender.key_for(instance.student, instance.module_id)
cache.set(k, instance, CACHE_TIMEOUT)
post_save.connect(update_cache_by_student_and_module_id, sender=StudentModule, weak=False)
post_delete.connect(clear_cache_by_student_and_module_id, sender=StudentModule, weak=False)
cache_model(StudentModule)
......@@ -48,13 +48,15 @@ def make_track_function(request):
def modx_dispatch(request, module=None, dispatch=None, id=None):
''' Generic view for extensions. '''
# Grab the student information for the module from the database
s = StudentModule.objects.filter(student=request.user,
module_id=id)
if len(s) == 0:
#s = StudentModule.objects.filter(student=request.user,
# module_id=id)
s = StudentModule.get_with_caching(request.user, id)
if s is None:
log.debug("Couldnt find module for user and id " + str(module) + " " + str(request.user) + " "+ str(id))
raise Http404
s=s[0]
oldgrade = s.grade
oldstate = s.state
dispatch=dispatch.split('?')[0]
......@@ -65,9 +67,9 @@ def modx_dispatch(request, module=None, dispatch=None, id=None):
# Create the module
instance=courseware.modules.get_module_class(module)(xml,
s.module_id,
id,
ajax_url=ajax_url,
state=s.state,
state=oldstate,
track_function = make_track_function(request),
render_function = None)
# Let the module handle the AJAX
......@@ -76,7 +78,8 @@ def modx_dispatch(request, module=None, dispatch=None, id=None):
s.state=instance.get_state()
if instance.get_score():
s.grade=instance.get_score()['score']
s.save()
if s.grade != oldgrade or s.state != oldstate:
s.save()
# Return whatever the module wanted to return to the client/caller
return HttpResponse(ajax_return)
......@@ -113,7 +116,7 @@ def render_x_module(user, request, xml_module, module_object_preload):
module_type = module_type,
module_id=module_id,
state=instance.get_state())
smod.save() # This may be optional (at least in the case of no instance in the dB)
smod.save()
module_object_preload.append(smod)
# Grab content
content = instance.get_html()
......
......@@ -107,6 +107,12 @@ def profile(request):
# total=courseware.modules.capa_module.Module(etree.tostring(p), "id").max_score() # TODO: Add state. Not useful now, but maybe someday problems will have randomized max scores?
# print correct, total
if settings.GENERATE_PROFILE_SCORES:
if total > 1:
correct = random.randrange( max(total-2, 1) , total + 1 )
else:
correct = total
scores.append((int(correct),total, graded ))
......@@ -159,16 +165,16 @@ def profile(request):
for i in range(12):
if i < len(homework_scores):
percentage = homework_scores[i][0] / float(homework_scores[i][1])
summary = "{0:.0%} ({1}/{2})".format( percentage, homework_scores[i][0], homework_scores[i][1] )
summary = "{0:.0%} ({1:g}/{2:g})".format( percentage, homework_scores[i][0], homework_scores[i][1] )
else:
percentage = 0
summary = "0% (?/?)"
if settings.GENERATE_PROFILE_SCORES:
points_possible = random.randrange(10, 50)
points_earned = random.randrange(5, points_possible)
percentage = points_earned / float(points_possible)
summary = "{0:.0%} ({1}/{2})".format( percentage, points_earned, points_possible )
if settings.GENERATE_PROFILE_SCORES:
points_possible = random.randrange(10, 50)
points_earned = random.randrange(5, points_possible)
percentage = points_earned / float(points_possible)
summary = "{0:.0%} ({1:g}/{2:g})".format( percentage, points_earned, points_possible )
summary = "Homework {0} - {1}".format(i + 1, summary)
label = "HW {0:02d}".format(i + 1)
......@@ -179,19 +185,20 @@ def profile(request):
#Figure the lab scores
lab_scores = total_scores['Lab'] if 'Lab' in total_scores else []
lab_percentages = []
log.debug("lab_scores: {0}".format(lab_scores))
for i in range(12):
if i < len(lab_scores):
percentage = lab_scores[i][0] / float(lab_scores[i][1])
summary = "{0:.0%} ({1}/{2})".format( percentage, lab_scores[i][0], lab_scores[i][1] )
summary = "{0:.0%} ({1:g}/{2:g})".format( percentage, lab_scores[i][0], lab_scores[i][1] )
else:
percentage = 0
summary = "0% (?/?)"
if settings.GENERATE_PROFILE_SCORES:
points_possible = random.randrange(10, 50)
points_earned = random.randrange(5, points_possible)
percentage = points_earned / float(points_possible)
summary = "{0:.0%} ({1}/{2})".format( percentage, points_earned, points_possible )
if settings.GENERATE_PROFILE_SCORES:
points_possible = random.randrange(10, 50)
points_earned = random.randrange(5, points_possible)
percentage = points_earned / float(points_possible)
summary = "{0:.0%} ({1:g}/{2:g})".format( percentage, points_earned, points_possible )
summary = "Lab {0} - {1}".format(i + 1, summary)
label = "Lab {0:02d}".format(i + 1)
......@@ -247,7 +254,7 @@ def profile(request):
]
user_info=UserProfile.objects.get(user=request.user)
user_info = request.user.profile_cache # UserProfile.objects.get(user=request.user)
context={'name':user_info.name,
'username':request.user.username,
'location':user_info.location,
......@@ -267,7 +274,9 @@ def format_url_params(params):
def render_accordion(request,course,chapter,section):
''' Draws navigation bar. Takes current position in accordion as
parameter. Returns (initialization_javascript, content)'''
if not course:
course = "6.002 Spring 2012"
toc=content_parser.toc_from_xml(content_parser.course_file(request.user), chapter, section)
active_chapter=1
for i in range(len(toc)):
......
......@@ -105,14 +105,22 @@ TEMPLATE_LOADERS = (
)
MIDDLEWARE_CLASSES = (
'util.middleware.ExceptionLoggingMiddleware',
'django.middleware.cache.UpdateCacheMiddleware',
'django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
#'django.contrib.auth.middleware.AuthenticationMiddleware',
'cache_toolbox.middleware.CacheBackedAuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'track.middleware.TrackMiddleware',
'mitxmako.middleware.MakoMiddleware',
#'debug_toolbar.middleware.DebugToolbarMiddleware',
# Uncommenting the following will prevent csrf token from being re-set if you
# delete it on the browser. I don't know why.
#'django.middleware.cache.FetchFromCacheMiddleware',
)
ROOT_URLCONF = 'mitx.urls'
......@@ -152,6 +160,8 @@ MAKO_MODULE_DIR = None
MAKO_TEMPLATES = {}
LOGGING_ENV = "dev" # override this in different environments
# Make sure we execute correctly regardless of where we're called from
execfile(os.path.join(BASE_DIR, "settings.py"))
......@@ -177,7 +187,8 @@ LOGGING = {
'format' : '%(asctime)s %(levelname)s %(process)d [%(name)s] %(filename)s:%(lineno)d - %(message)s',
},
'syslog_format' : {
'format' : '[%(name)s] %(levelname)s [' + hostname + ' %(process)d] [%(filename)s:%(lineno)d] - %(message)s',
'format' : '[%(name)s][env:' + LOGGING_ENV + '] %(levelname)s [' + \
hostname + ' %(process)d] [%(filename)s:%(lineno)d] - %(message)s',
},
'raw' : {
'format' : '%(message)s',
......@@ -283,7 +294,6 @@ site.addsitedir(os.path.join(os.path.dirname(askbot.__file__), 'deps'))
TEMPLATE_LOADERS = TEMPLATE_LOADERS + ('askbot.skins.loaders.filesystem_load_template_source',)
MIDDLEWARE_CLASSES = MIDDLEWARE_CLASSES + (
'util.middleware.ExceptionLoggingMiddleware',
'askbot.middleware.anon_user.ConnectToSessionMessagesMiddleware',
'askbot.middleware.forum_mode.ForumModeMiddleware',
'askbot.middleware.cancel.CancelActionMiddleware',
......@@ -291,7 +301,7 @@ MIDDLEWARE_CLASSES = MIDDLEWARE_CLASSES + (
#'debug_toolbar.middleware.DebugToolbarMiddleware',
'askbot.middleware.view_log.ViewLogMiddleware',
'askbot.middleware.spaceless.SpacelessMiddleware',
# 'askbot.middleware.pagesize.QuestionsPageSizeMiddleware',
#'askbot.middleware.pagesize.QuestionsPageSizeMiddleware',
)
FILE_UPLOAD_TEMP_DIR = os.path.join(os.path.dirname(__file__), 'tmp').replace('\\','/')
......@@ -520,21 +530,21 @@ LIVESETTINGS_OPTIONS = {
'MIN_REP' : {
'MIN_REP_TO_ACCEPT_OWN_ANSWER' : 1,
'MIN_REP_TO_ANSWER_OWN_QUESTION' : 1,
'MIN_REP_TO_CLOSE_OTHERS_QUESTIONS' : 100,
'MIN_REP_TO_CLOSE_OTHERS_QUESTIONS' : 250,
'MIN_REP_TO_CLOSE_OWN_QUESTIONS' : 1,
'MIN_REP_TO_DELETE_OTHERS_COMMENTS' : 2000,
'MIN_REP_TO_DELETE_OTHERS_POSTS' : 5000,
'MIN_REP_TO_EDIT_OTHERS_POSTS' : 2000,
'MIN_REP_TO_EDIT_WIKI' : 1,
'MIN_REP_TO_EDIT_WIKI' : 50,
'MIN_REP_TO_FLAG_OFFENSIVE' : 1,
'MIN_REP_TO_HAVE_STRONG_URL' : 250,
'MIN_REP_TO_LEAVE_COMMENTS' : 1,
'MIN_REP_TO_LOCK_POSTS' : 4000,
'MIN_REP_TO_REOPEN_OWN_QUESTIONS' : 1,
'MIN_REP_TO_RETAG_OTHERS_QUESTIONS' : 1,
'MIN_REP_TO_RETAG_OTHERS_QUESTIONS' : 100,
'MIN_REP_TO_UPLOAD_FILES' : 1,
'MIN_REP_TO_VIEW_OFFENSIVE_FLAGS' : 2000,
'MIN_REP_TO_VOTE_DOWN' : 1,
'MIN_REP_TO_VOTE_DOWN' : 15,
'MIN_REP_TO_VOTE_UP' : 1,
},
'QA_SITE_SETTINGS' : {
......
......@@ -13,6 +13,8 @@ import uuid
from django.db import models
from django.contrib.auth.models import User
from cache_toolbox import cache_model, cache_relation
class UserProfile(models.Model):
class Meta:
db_table = "auth_userprofile"
......@@ -20,7 +22,7 @@ class UserProfile(models.Model):
## 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)
user = models.OneToOneField(User, unique=True, db_index=True, related_name='profile')
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)
......@@ -54,3 +56,4 @@ class Registration(models.Model):
self.user.save()
#self.delete()
cache_relation(User.profile)
......@@ -86,7 +86,7 @@ def logout_user(request):
def change_setting(request):
if not request.user.is_authenticated():
return redirect('/')
up=UserProfile.objects.get(user=request.user)
up = request.user.profile_cache # UserProfile.objects.get(user=request.user)
if 'location' in request.POST:
# print "loc"
up.location=request.POST['location']
......@@ -171,7 +171,7 @@ def create_account(request, post_override=None):
u.save()
r.register(u)
up=UserProfile(user=u)
up = UserProfile(user=u)
up.name=post_vars['name']
up.language=post_vars['language']
up.location=post_vars['location']
......
......@@ -21,7 +21,8 @@ def user_track(request):
username = "anonymous"
try:
scookie = request.META['HTTP_COOKIE']
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 = ""
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment