Commit 2c5bd99f by Bridger Maxwell

Caught up to default branch

--HG--
branch : bridger-dev
parents 216e9969 ccacc90c
...@@ -58,6 +58,11 @@ def get_instance(model, instance_or_pk, timeout=None, using=None): ...@@ -58,6 +58,11 @@ def get_instance(model, instance_or_pk, timeout=None, using=None):
cache.delete(key) cache.delete(key)
# Use the default manager so we are never filtered by a .get_query_set() # 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) instance = model._default_manager.using(using).get(pk=pk)
data = {} data = {}
......
...@@ -92,6 +92,10 @@ def cache_relation(descriptor, timeout=None): ...@@ -92,6 +92,10 @@ def cache_relation(descriptor, timeout=None):
except AttributeError: except AttributeError:
pass 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) instance = get_instance(rel.model, self.pk, timeout)
setattr(self, '_%s_cache' % related_name, instance) setattr(self, '_%s_cache' % related_name, instance)
......
...@@ -146,11 +146,11 @@ def propogate_downward_tag(element, attribute_name, parent_attribute = None): ...@@ -146,11 +146,11 @@ def propogate_downward_tag(element, attribute_name, parent_attribute = None):
def user_groups(user): def user_groups(user):
# TODO: Rewrite in Django # TODO: Rewrite in Django
key = 'user_group_names_{user.id}'.format(user=user) key = 'user_group_names_{user.id}'.format(user=user)
cache_expiration = 60 * 60 * 4 # four hours cache_expiration = 60 * 60 # one hour
group_names = cache.get(key) group_names = cache.get(fasthash(key))
if group_names is None: if group_names is None:
group_names = [u.name for u in UserTestGroup.objects.filter(users=user)] 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 return group_names
...@@ -169,19 +169,23 @@ def course_xml_process(tree): ...@@ -169,19 +169,23 @@ def course_xml_process(tree):
def course_file(user): def course_file(user):
''' Given a user, return course.xml''' ''' 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) groups = user_groups(user)
options = {'dev_content':settings.DEV_CONTENT, options = {'dev_content':settings.DEV_CONTENT,
'groups' : groups} 'groups' : groups}
cache_key = filename + "_processed?dev_content:" + str(options['dev_content']) + "&groups:" + str(sorted(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: if not tree_string:
tree = course_xml_process(etree.XML(render_to_string(filename, options, namespace = 'course'))) tree = course_xml_process(etree.XML(render_to_string(filename, options, namespace = 'course')))
tree_string = etree.tostring(tree) tree_string = etree.tostring(tree)
cache.set(cache_key, tree_string, 60) cache.set(fasthash(cache_key), tree_string, 60)
else: else:
tree = etree.XML(tree_string) tree = etree.XML(tree_string)
......
...@@ -14,12 +14,12 @@ ASSUMPTIONS: modules have unique IDs, even across different module_types ...@@ -14,12 +14,12 @@ ASSUMPTIONS: modules have unique IDs, even across different module_types
""" """
from django.db import models from django.db import models
from django.db.models.signals import post_save, post_delete 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 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): class StudentModule(models.Model):
# For a homework problem, contains a JSON # For a homework problem, contains a JSON
...@@ -58,35 +58,35 @@ class StudentModule(models.Model): ...@@ -58,35 +58,35 @@ class StudentModule(models.Model):
def __unicode__(self): def __unicode__(self):
return self.module_type+'/'+self.student.username+"/"+self.module_id+'/'+str(self.state)[:20] return self.module_type+'/'+self.student.username+"/"+self.module_id+'/'+str(self.state)[:20]
@classmethod # @classmethod
def get_with_caching(cls, student, module_id): # def get_with_caching(cls, student, module_id):
k = cls.key_for(student, module_id) # k = cls.key_for(student, module_id)
student_module = cache.get(k) # student_module = cache.get(k)
if student_module is None: # if student_module is None:
student_module = StudentModule.objects.filter(student=student, # student_module = StudentModule.objects.filter(student=student,
module_id=module_id)[0] # module_id=module_id)[0]
# It's possible it really doesn't exist... # # It's possible it really doesn't exist...
if student_module is not None: # if student_module is not None:
cache.set(k, student_module, CACHE_TIMEOUT) # cache.set(k, student_module, CACHE_TIMEOUT)
return student_module # return student_module
@classmethod @classmethod
def key_for(cls, student, module_id): def key_for(cls, student, module_id):
return "StudentModule-student_id:{0};module_id:{1}".format(student.id, 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): # def clear_cache_by_student_and_module_id(sender, instance, *args, **kwargs):
k = sender.key_for(instance.student, instance.module_id) # k = sender.key_for(instance.student, instance.module_id)
cache.delete(k) # cache.delete(k)
def update_cache_by_student_and_module_id(sender, instance, *args, **kwargs): # def update_cache_by_student_and_module_id(sender, instance, *args, **kwargs):
k = sender.key_for(instance.student, instance.module_id) # k = sender.key_for(instance.student, instance.module_id)
cache.set(k, instance, CACHE_TIMEOUT) # cache.set(k, instance, CACHE_TIMEOUT)
post_save.connect(update_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) #post_delete.connect(clear_cache_by_student_and_module_id, sender=StudentModule, weak=False)
cache_model(StudentModule) #cache_model(StudentModule)
...@@ -47,13 +47,17 @@ def make_track_function(request): ...@@ -47,13 +47,17 @@ def make_track_function(request):
def modx_dispatch(request, module=None, dispatch=None, id=None): def modx_dispatch(request, module=None, dispatch=None, id=None):
''' Generic view for extensions. ''' ''' Generic view for extensions. '''
if not request.user.is_authenticated():
return redirect('/')
# Grab the student information for the module from the database # Grab the student information for the module from the database
#s = StudentModule.objects.filter(student=request.user, s = StudentModule.objects.filter(student=request.user,
# module_id=id) module_id=id)
s = StudentModule.get_with_caching(request.user, id) #s = StudentModule.get_with_caching(request.user, id)
if s is None: if len(s) == 0 or s is None:
log.debug("Couldnt find module for user and id " + str(module) + " " + str(request.user) + " "+ str(id)) log.debug("Couldnt find module for user and id " + str(module) + " " + str(request.user) + " "+ str(id))
raise Http404 raise Http404
s = s[0]
oldgrade = s.grade oldgrade = s.grade
oldstate = s.state oldstate = s.state
......
...@@ -254,7 +254,7 @@ def profile(request): ...@@ -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, context={'name':user_info.name,
'username':request.user.username, 'username':request.user.username,
'location':user_info.location, 'location':user_info.location,
...@@ -345,6 +345,10 @@ def index(request, course="6.002 Spring 2012", chapter="Using the System", secti ...@@ -345,6 +345,10 @@ def index(request, course="6.002 Spring 2012", chapter="Using the System", secti
if course!="6.002 Spring 2012": if course!="6.002 Spring 2012":
return redirect('/') return redirect('/')
#import logging
#log = logging.getLogger("mitx")
#log.info( "DEBUG: "+str(user) )
dom = content_parser.course_file(user) dom = content_parser.course_file(user)
dom_module = dom.xpath("//course[@name=$course]/chapter[@name=$chapter]//section[@name=$section]/*[1]", dom_module = dom.xpath("//course[@name=$course]/chapter[@name=$chapter]//section[@name=$section]/*[1]",
course=course, chapter=chapter, section=section) course=course, chapter=chapter, section=section)
......
...@@ -174,7 +174,7 @@ execfile(os.path.join(BASE_DIR, "settings.py")) ...@@ -174,7 +174,7 @@ execfile(os.path.join(BASE_DIR, "settings.py"))
pid = os.getpid() pid = os.getpid()
hostname = platform.node().split(".")[0] hostname = platform.node().split(".")[0]
SYSLOG_ADDRESS = ('syslog.m.i4x.org', 514) SYSLOG_ADDRESS = ('syslog.m.i4x.org', 514)
LOGGING_FILENAME = 'trackinglog-' + str(pid) TRACKING_LOG_FILE = LOG_DIR + "/tracking_{0}.log".format(pid)
handlers = ['console'] handlers = ['console']
if not DEBUG: if not DEBUG:
...@@ -214,10 +214,11 @@ LOGGING = { ...@@ -214,10 +214,11 @@ LOGGING = {
'address' : SYSLOG_ADDRESS, 'address' : SYSLOG_ADDRESS,
'formatter' : 'syslog_format', 'formatter' : 'syslog_format',
}, },
'filelogger' : { 'tracking' : {
'level' : 'INFO', 'level' : 'DEBUG',
'class' : 'logging.FileHandler', 'class' : 'logging.handlers.WatchedFileHandler',
'filename' : LOGGING_FILENAME, 'filename' : TRACKING_LOG_FILE,
'formatter' : 'raw',
}, },
'mail_admins' : { 'mail_admins' : {
'level': 'ERROR', 'level': 'ERROR',
...@@ -231,7 +232,7 @@ LOGGING = { ...@@ -231,7 +232,7 @@ LOGGING = {
'level' : 'INFO' 'level' : 'INFO'
}, },
'tracking' : { 'tracking' : {
'handlers' : [] if DEBUG else ['filelogger'], # handlers, 'handlers' : ['tracking'],
'level' : 'DEBUG', 'level' : 'DEBUG',
'propagate' : False, 'propagate' : False,
}, },
...@@ -248,6 +249,8 @@ LOGGING = { ...@@ -248,6 +249,8 @@ LOGGING = {
} }
} }
if PERFSTATS : if PERFSTATS :
MIDDLEWARE_CLASSES = ( 'perfstats.middleware.ProfileMiddleware',) + MIDDLEWARE_CLASSES MIDDLEWARE_CLASSES = ( 'perfstats.middleware.ProfileMiddleware',) + MIDDLEWARE_CLASSES
...@@ -443,7 +446,7 @@ LIVESETTINGS_OPTIONS = { ...@@ -443,7 +446,7 @@ LIVESETTINGS_OPTIONS = {
'MIN_ANSWER_BODY_LENGTH' : 1, 'MIN_ANSWER_BODY_LENGTH' : 1,
'WIKI_ON' : True, 'WIKI_ON' : True,
'ALLOW_ASK_ANONYMOUSLY' : True, 'ALLOW_ASK_ANONYMOUSLY' : True,
'ALLOW_POSTING_BEFORE_LOGGING_IN' : True, 'ALLOW_POSTING_BEFORE_LOGGING_IN' : False,
'ALLOW_SWAPPING_QUESTION_WITH_ANSWER' : False, 'ALLOW_SWAPPING_QUESTION_WITH_ANSWER' : False,
'MAX_TAG_LENGTH' : 20, 'MAX_TAG_LENGTH' : 20,
'MIN_TITLE_LENGTH' : 1, 'MIN_TITLE_LENGTH' : 1,
...@@ -628,7 +631,7 @@ LIVESETTINGS_OPTIONS = { ...@@ -628,7 +631,7 @@ LIVESETTINGS_OPTIONS = {
'VOTE_RULES' : { 'VOTE_RULES' : {
'MAX_VOTES_PER_USER_PER_DAY' : 30, 'MAX_VOTES_PER_USER_PER_DAY' : 30,
'MAX_FLAGS_PER_USER_PER_DAY' : 5, '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_DAYS_TO_ANSWER_OWN_QUESTION' : 0,
'MIN_FLAGS_TO_DELETE_POST' : 5, 'MIN_FLAGS_TO_DELETE_POST' : 5,
'MIN_FLAGS_TO_HIDE_POST' : 3, 'MIN_FLAGS_TO_HIDE_POST' : 3,
...@@ -647,7 +650,7 @@ ot = MAKO_TEMPLATES ...@@ -647,7 +650,7 @@ ot = MAKO_TEMPLATES
MAKO_TEMPLATES['course'] = [DATA_DIR] MAKO_TEMPLATES['course'] = [DATA_DIR]
MAKO_TEMPLATES['sections'] = [DATA_DIR+'/sections'] MAKO_TEMPLATES['sections'] = [DATA_DIR+'/sections']
MAKO_TEMPLATES['custom_tags'] = [DATA_DIR+'/custom_tags'] 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) MAKO_TEMPLATES.update(ot)
......
...@@ -39,7 +39,7 @@ def view(request, wiki_url): ...@@ -39,7 +39,7 @@ def view(request, wiki_url):
'wiki_write': article.can_write_l(request.user), 'wiki_write': article.can_write_l(request.user),
'wiki_attachments_write': article.can_attach(request.user), 'wiki_attachments_write': article.can_attach(request.user),
'wiki_current_revision_deleted' : not (article.current_revision.deleted == 0), '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)) d.update(csrf(request))
return render_to_response('simplewiki_view.html', d) return render_to_response('simplewiki_view.html', d)
......
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?"
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
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)
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()
...@@ -13,7 +13,7 @@ import uuid ...@@ -13,7 +13,7 @@ import uuid
from django.db import models from django.db import models
from django.contrib.auth.models import User 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 UserProfile(models.Model):
class Meta: class Meta:
...@@ -56,4 +56,4 @@ class Registration(models.Model): ...@@ -56,4 +56,4 @@ class Registration(models.Model):
self.user.save() self.user.save()
#self.delete() #self.delete()
cache_relation(User.profile) #cache_relation(User.profile)
...@@ -86,7 +86,7 @@ def logout_user(request): ...@@ -86,7 +86,7 @@ def logout_user(request):
def change_setting(request): def change_setting(request):
if not request.user.is_authenticated(): if not request.user.is_authenticated():
return redirect('/') 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: if 'location' in request.POST:
# print "loc" # print "loc"
up.location=request.POST['location'] up.location=request.POST['location']
......
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