Caught up to default branch
--HG-- branch : bridger-dev
This commit is contained in:
@@ -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 = {}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
21
settings.py
21
settings.py
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
0
student/management/__init__.py
Normal file
0
student/management/__init__.py
Normal file
0
student/management/commands/__init__.py
Normal file
0
student/management/commands/__init__.py
Normal file
99
student/management/commands/assigngroups.py
Normal file
99
student/management/commands/assigngroups.py
Normal 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?"
|
||||
23
student/management/commands/emaillist.py
Normal file
23
student/management/commands/emaillist.py
Normal 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
|
||||
27
student/management/commands/massemail.py
Normal file
27
student/management/commands/massemail.py
Normal 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)
|
||||
64
student/management/commands/massemailtxt.py
Normal file
64
student/management/commands/massemailtxt.py
Normal 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()
|
||||
@@ -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)
|
||||
|
||||
@@ -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']
|
||||
|
||||
Reference in New Issue
Block a user