Caught up to default branch

--HG--
branch : bridger-dev
This commit is contained in:
Bridger Maxwell
2012-03-06 12:35:48 -05:00
16 changed files with 284 additions and 47 deletions

View File

@@ -58,6 +58,11 @@ def get_instance(model, instance_or_pk, timeout=None, using=None):
cache.delete(key)
# Use the default manager so we are never filtered by a .get_query_set()
# import logging
# log = logging.getLogger("tracking")
# log.info( str(pk) )
instance = model._default_manager.using(using).get(pk=pk)
data = {}

View File

@@ -92,6 +92,10 @@ def cache_relation(descriptor, timeout=None):
except AttributeError:
pass
# import logging
# log = logging.getLogger("tracking")
# log.info( "DEBUG: "+str(str(rel.model)+"/"+str(self.pk) ))
instance = get_instance(rel.model, self.pk, timeout)
setattr(self, '_%s_cache' % related_name, instance)

View File

@@ -146,11 +146,11 @@ def propogate_downward_tag(element, attribute_name, parent_attribute = None):
def user_groups(user):
# TODO: Rewrite in Django
key = 'user_group_names_{user.id}'.format(user=user)
cache_expiration = 60 * 60 * 4 # four hours
group_names = cache.get(key)
cache_expiration = 60 * 60 # one hour
group_names = cache.get(fasthash(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)
cache.set(fasthash(key), group_names, cache_expiration)
return group_names
@@ -169,19 +169,23 @@ def course_xml_process(tree):
def course_file(user):
''' Given a user, return course.xml'''
filename = user.profile_cache.courseware # UserProfile.objects.get(user=user).courseware
#import logging
#log = logging.getLogger("tracking")
#log.info( "DEBUG: cf:"+str(user) )
filename = UserProfile.objects.get(user=user).courseware # user.profile_cache.courseware
groups = user_groups(user)
options = {'dev_content':settings.DEV_CONTENT,
'groups' : groups}
cache_key = filename + "_processed?dev_content:" + str(options['dev_content']) + "&groups:" + str(sorted(groups))
tree_string = cache.get(cache_key)
tree_string = cache.get(fasthash(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)
cache.set(fasthash(cache_key), tree_string, 60)
else:
tree = etree.XML(tree_string)

View File

@@ -14,12 +14,12 @@ 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.core.cache import cache
from django.contrib.auth.models import User
from cache_toolbox import cache_model, cache_relation
#from cache_toolbox import cache_model, cache_relation
CACHE_TIMEOUT = 60 * 60 * 4 # Set the cache timeout to be four hours
#CACHE_TIMEOUT = 60 * 60 * 4 # Set the cache timeout to be four hours
class StudentModule(models.Model):
# For a homework problem, contains a JSON
@@ -58,35 +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)
# @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
# 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 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)
# 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)
#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)
#cache_model(StudentModule)

View File

@@ -47,13 +47,17 @@ def make_track_function(request):
def modx_dispatch(request, module=None, dispatch=None, id=None):
''' Generic view for extensions. '''
if not request.user.is_authenticated():
return redirect('/')
# Grab the student information for the module from the database
#s = StudentModule.objects.filter(student=request.user,
# module_id=id)
s = StudentModule.get_with_caching(request.user, id)
if s is None:
s = StudentModule.objects.filter(student=request.user,
module_id=id)
#s = StudentModule.get_with_caching(request.user, id)
if len(s) == 0 or 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

View File

@@ -254,7 +254,7 @@ def profile(request):
]
user_info = request.user.profile_cache # UserProfile.objects.get(user=request.user)
user_info = UserProfile.objects.get(user=request.user) # request.user.profile_cache #
context={'name':user_info.name,
'username':request.user.username,
'location':user_info.location,
@@ -345,6 +345,10 @@ def index(request, course="6.002 Spring 2012", chapter="Using the System", secti
if course!="6.002 Spring 2012":
return redirect('/')
#import logging
#log = logging.getLogger("mitx")
#log.info( "DEBUG: "+str(user) )
dom = content_parser.course_file(user)
dom_module = dom.xpath("//course[@name=$course]/chapter[@name=$chapter]//section[@name=$section]/*[1]",
course=course, chapter=chapter, section=section)

View File

@@ -174,7 +174,7 @@ execfile(os.path.join(BASE_DIR, "settings.py"))
pid = os.getpid()
hostname = platform.node().split(".")[0]
SYSLOG_ADDRESS = ('syslog.m.i4x.org', 514)
LOGGING_FILENAME = 'trackinglog-' + str(pid)
TRACKING_LOG_FILE = LOG_DIR + "/tracking_{0}.log".format(pid)
handlers = ['console']
if not DEBUG:
@@ -214,10 +214,11 @@ LOGGING = {
'address' : SYSLOG_ADDRESS,
'formatter' : 'syslog_format',
},
'filelogger' : {
'level' : 'INFO',
'class' : 'logging.FileHandler',
'filename' : LOGGING_FILENAME,
'tracking' : {
'level' : 'DEBUG',
'class' : 'logging.handlers.WatchedFileHandler',
'filename' : TRACKING_LOG_FILE,
'formatter' : 'raw',
},
'mail_admins' : {
'level': 'ERROR',
@@ -231,7 +232,7 @@ LOGGING = {
'level' : 'INFO'
},
'tracking' : {
'handlers' : [] if DEBUG else ['filelogger'], # handlers,
'handlers' : ['tracking'],
'level' : 'DEBUG',
'propagate' : False,
},
@@ -248,6 +249,8 @@ LOGGING = {
}
}
if PERFSTATS :
MIDDLEWARE_CLASSES = ( 'perfstats.middleware.ProfileMiddleware',) + MIDDLEWARE_CLASSES
@@ -443,7 +446,7 @@ LIVESETTINGS_OPTIONS = {
'MIN_ANSWER_BODY_LENGTH' : 1,
'WIKI_ON' : True,
'ALLOW_ASK_ANONYMOUSLY' : True,
'ALLOW_POSTING_BEFORE_LOGGING_IN' : True,
'ALLOW_POSTING_BEFORE_LOGGING_IN' : False,
'ALLOW_SWAPPING_QUESTION_WITH_ANSWER' : False,
'MAX_TAG_LENGTH' : 20,
'MIN_TITLE_LENGTH' : 1,
@@ -628,7 +631,7 @@ LIVESETTINGS_OPTIONS = {
'VOTE_RULES' : {
'MAX_VOTES_PER_USER_PER_DAY' : 30,
'MAX_FLAGS_PER_USER_PER_DAY' : 5,
'MIN_DAYS_FOR_STAFF_TO_ACCEPT_ANSWER' : 7,
'MIN_DAYS_FOR_STAFF_TO_ACCEPT_ANSWER' : 0,
'MIN_DAYS_TO_ANSWER_OWN_QUESTION' : 0,
'MIN_FLAGS_TO_DELETE_POST' : 5,
'MIN_FLAGS_TO_HIDE_POST' : 3,
@@ -647,7 +650,7 @@ ot = MAKO_TEMPLATES
MAKO_TEMPLATES['course'] = [DATA_DIR]
MAKO_TEMPLATES['sections'] = [DATA_DIR+'/sections']
MAKO_TEMPLATES['custom_tags'] = [DATA_DIR+'/custom_tags']
MAKO_TEMPLATES['main'] = [BASE_DIR+'/templates/']
MAKO_TEMPLATES['main'] = [BASE_DIR+'/templates/', DATA_DIR+'/info']
MAKO_TEMPLATES.update(ot)

View File

@@ -39,7 +39,7 @@ def view(request, wiki_url):
'wiki_write': article.can_write_l(request.user),
'wiki_attachments_write': article.can_attach(request.user),
'wiki_current_revision_deleted' : not (article.current_revision.deleted == 0),
'wiki_title' : article.title + " - MITX 6.002 Wiki"
'wiki_title' : article.title + " - MITX 6.002x Wiki"
}
d.update(csrf(request))
return render_to_response('simplewiki_view.html', d)

View File

View File

View File

@@ -0,0 +1,99 @@
import os.path
from lxml import etree
from django.core.management.base import BaseCommand
from django.conf import settings
from django.contrib.auth.models import User
import mitxmako.middleware as middleware
from student.models import UserTestGroup
import random
import sys
import datetime
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:
sum = sum + p
if sum > v:
return g
return g # For round-off errors
class Command(BaseCommand):
help = \
''' Assign users to test groups. Takes a list
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.
Will log what happened to file.txt.
'''
def handle(self, *args, **options):
if len(args) != 3:
print "Invalid number of options"
sys.exit(-1)
# Extract groups from string
group_strs = [x.split(':') for x in args[0].split(',')]
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:
print "Total not 1"
sys.exit(-1)
## Confirm groups don't already exist
for group in dict(groups):
if UserTestGroup.objects.filter(name=group).count() != 0:
print group, "already exists!"
sys.exit(-1)
group_objects = {}
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
group_objects[group].save()
## Assign groups
users = list(User.objects.all())
count = 0
for user in users:
if count % 1000 == 0:
print count
count = count + 1
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,
group=group))
## Save groups
for group in group_objects:
group_objects[group].save()
f.close()
# python manage.py assigngroups summary_test:0.3,skip_summary_test:0.7 log.txt "Do previews of future materials help?"
# python manage.py assigngroups skip_capacitor:0.3,capacitor:0.7 log.txt "Do we show capacitor in linearity tutorial?"

View File

@@ -0,0 +1,23 @@
import os.path
from lxml import etree
from django.core.management.base import BaseCommand
from django.conf import settings
from django.contrib.auth.models import User
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()
users = User.objects.all()
for user in users:
if user.is_active:
print user.email

View File

@@ -0,0 +1,27 @@
import os.path
from lxml import etree
from django.core.management.base import BaseCommand
from django.conf import settings
from django.contrib.auth.models import User
import mitxmako.middleware as middleware
middleware.MakoMiddleware()
class Command(BaseCommand):
help = \
'''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()
for user in users:
if user.is_active:
user.email_user(subject, text)

View File

@@ -0,0 +1,64 @@
import os.path
import time
from lxml import etree
from django.core.management.base import BaseCommand
from django.conf import settings
from django.contrib.auth.models import User
import mitxmako.middleware as middleware
from django.core.mail import send_mass_mail
import sys
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]
class Command(BaseCommand):
help = \
'''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
logfile.txt -- where to log progress
rate -- messages per second
'''
log_file = None
def hard_log(self, text):
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()
rate = int(ratestr)
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 ]
self.hard_log(" ".join(users))
send_mass_mail( emails, fail_silently = False )
time.sleep(1)
print datetime.datetime.utcnow().isoformat(), i
i = i+len(users)
# Emergency interruptor
if os.path.exists("/tmp/stopemails.txt"):
self.log_file.close()
sys.exit(-1)
self.log_file.close()

View File

@@ -13,7 +13,7 @@ import uuid
from django.db import models
from django.contrib.auth.models import User
from cache_toolbox import cache_model, cache_relation
#from cache_toolbox import cache_model, cache_relation
class UserProfile(models.Model):
class Meta:
@@ -56,4 +56,4 @@ class Registration(models.Model):
self.user.save()
#self.delete()
cache_relation(User.profile)
#cache_relation(User.profile)

View File

@@ -86,7 +86,7 @@ def logout_user(request):
def change_setting(request):
if not request.user.is_authenticated():
return redirect('/')
up = request.user.profile_cache # UserProfile.objects.get(user=request.user)
up = UserProfile.objects.get(user=request.user) #request.user.profile_cache
if 'location' in request.POST:
# print "loc"
up.location=request.POST['location']