From 63cb53c9193dff216f68bc3f3bc1126a075ed2c7 Mon Sep 17 00:00:00 2001 From: David Ormsbee Date: Wed, 25 Jan 2012 16:30:32 -0500 Subject: [PATCH 01/25] Move logging config, add tracking info to console, remove logging tests. --- courseware/views.py | 4 - settings_new_askbot.py | 172 ++++++++++++++++++++++------------------- 2 files changed, 91 insertions(+), 85 deletions(-) diff --git a/courseware/views.py b/courseware/views.py index cd6857b635..9236bbe870 100644 --- a/courseware/views.py +++ b/courseware/views.py @@ -35,10 +35,6 @@ def profile(request): if not request.user.is_authenticated(): return redirect('/') - log.info("Profile called") - logging.info("Now the root") - logging.getLogger("tracking").info("this should be unformatted") - dom=content_parser.course_file(request.user) hw=[] course = dom.xpath('//course/@name')[0] diff --git a/settings_new_askbot.py b/settings_new_askbot.py index d54af20813..2ef4b5f893 100644 --- a/settings_new_askbot.py +++ b/settings_new_askbot.py @@ -56,87 +56,6 @@ USE_I18N = True # calendars according to the current locale USE_L10N = True -# A sample logging configuration. The only tangible logging -# performed by this configuration is to send an email to -# the site admins on every HTTP 500 error. -# See http://docs.djangoproject.com/en/dev/topics/logging for -# more details on how to customize your logging configuration. -LOGGING = { - 'version': 1, - 'disable_existing_loggers': True, - 'formatters' : { - 'standard' : { - 'format' : '%(levelname)s %(asctime)s PID:%(process)d %(name)s %(filename)s:%(lineno)d %(message)s', - }, - 'raw' : { - 'format' : '%(message)s', - } - }, - 'handlers' : { - 'console' : { - 'level' : 'DEBUG' if DEBUG else 'INFO', - 'class' : 'logging.StreamHandler', - 'formatter' : 'standard', - 'stream' : sys.stdout, - }, - 'console_err' : { - 'level' : 'ERROR', - 'class' : 'logging.StreamHandler', - 'formatter' : 'standard', - 'stream' : sys.stderr, - }, - # 'app' : { - # 'level' : 'INFO', - # 'class' : 'logging.handlers.TimedRotatingFileHandler', - # 'formatter' : 'standard', - # 'filename' : '/tmp/mitx.log', # temporary location for proof of concept - # 'when' : 'midnight', - # 'utc' : True, - # 'encoding' : 'utf-8', - # }, - - # We should actually use this for tracking: - # http://pypi.python.org/pypi/ConcurrentLogHandler/0.8.2 - 'tracking' : { - 'level' : 'INFO', - 'class' : 'logging.handlers.TimedRotatingFileHandler', - 'formatter' : 'raw', - 'filename' : BASE_DIR + '/track_dir/tracking.log', - 'when' : 'midnight', - 'utc' : True, - 'encoding' : 'utf-8', - }, - 'mail_admins' : { - 'level': 'ERROR', - 'class': 'django.utils.log.AdminEmailHandler', - }, - }, - 'loggers' : { - 'django.request': { - 'handlers': ['mail_admins', 'console', 'console_err'], - 'level': 'INFO', - 'propagate': True, - }, - 'tracking' : { - 'handlers' : ['tracking'], - 'level' : 'DEBUG', - 'propagate' : False, - }, - 'root' : { - 'handlers' : ['console', 'console_err'], - 'level' : 'DEBUG', - 'propagate' : False - }, - 'mitx' : { - 'handlers' : ['console', 'console_err'], - 'level' : 'DEBUG', - 'propagate' : False - }, - } -} - - - STATIC_URL = '/static/' # URL prefix for admin static files -- CSS, JavaScript and images. @@ -201,9 +120,100 @@ TRACK_MAX_EVENT = 1000 # Maximum length of log file before starting a new one. MAXLOG = 500 +LOG_DIR = "/tmp/" + # Make sure we execute correctly regardless of where we're called from execfile(os.path.join(BASE_DIR, "settings.py")) +# A sample logging configuration. The only tangible logging +# performed by this configuration is to send an email to +# the site admins on every HTTP 500 error. +# See http://docs.djangoproject.com/en/dev/topics/logging for +# more details on how to customize your logging configuration. +LOGGING = { + 'version': 1, + 'disable_existing_loggers': True, + 'formatters' : { + 'standard' : { + 'format' : '%(asctime)s %(levelname)s %(process)d [%(name)s] %(filename)s:%(lineno)d - %(message)s', + }, + 'raw' : { + 'format' : '%(message)s', + } + }, + 'handlers' : { + 'console' : { + 'level' : 'DEBUG' if DEBUG else 'INFO', + 'class' : 'logging.StreamHandler', + 'formatter' : 'standard', + 'stream' : sys.stdout, + }, + 'console_err' : { + 'level' : 'ERROR', + 'class' : 'logging.StreamHandler', + 'formatter' : 'standard', + 'stream' : sys.stderr, + }, + 'app' : { + 'level' : 'INFO', + 'class' : 'logging.handlers.TimedRotatingFileHandler', + 'formatter' : 'standard', + 'filename' : LOG_DIR + '/mitx.log', # temporary location for proof of concept + 'when' : 'midnight', + 'utc' : True, + 'encoding' : 'utf-8', + }, + 'app_err' : { + 'level' : 'ERROR', + 'class' : 'logging.handlers.TimedRotatingFileHandler', + 'formatter' : 'standard', + 'filename' : LOG_DIR + '/mitx.err.log', # temporary location for proof of concept + 'when' : 'midnight', + 'utc' : True, + 'encoding' : 'utf-8', + }, + # We should actually use this for tracking: + # http://pypi.python.org/pypi/ConcurrentLogHandler/0.8.2 + 'tracking' : { + 'level' : 'INFO', + 'class' : 'logging.handlers.TimedRotatingFileHandler', + 'formatter' : 'raw', + 'filename' : LOG_DIR + '/tracking.log', + 'when' : 'midnight', + 'utc' : True, + 'encoding' : 'utf-8', + }, + 'mail_admins' : { + 'level': 'ERROR', + 'class': 'django.utils.log.AdminEmailHandler', + }, + }, + 'loggers' : { + 'django' : { + 'handlers' : ['console', 'mail_admins'], + 'propagate' : True, + 'level' : 'INFO' + }, + 'tracking' : { + 'handlers' : ['console', 'tracking'], + 'level' : 'DEBUG', + 'propagate' : False, + }, + 'root' : { + 'handlers' : ['console', 'app', 'app_err'], + 'level' : 'DEBUG', + 'propagate' : False + }, + 'mitx' : { + 'handlers' : ['console', 'app', 'app_err'], + 'level' : 'DEBUG', + 'propagate' : False + }, + } +} + + + if PERFSTATS : MIDDLEWARE_CLASSES = ( 'perfstats.middleware.ProfileMiddleware',) + MIDDLEWARE_CLASSES From fd79da9a7ace36439ea33926cd36045481ed97cf Mon Sep 17 00:00:00 2001 From: David Ormsbee Date: Thu, 26 Jan 2012 13:50:21 -0500 Subject: [PATCH 02/25] added some sample logging to login process --- auth/views.py | 40 ++++++++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/auth/views.py b/auth/views.py index 61419e507b..7675578a57 100644 --- a/auth/views.py +++ b/auth/views.py @@ -1,3 +1,5 @@ +import logging + from djangomako.shortcuts import render_to_response, render_to_string from django.contrib.auth.models import User from django.shortcuts import redirect @@ -12,6 +14,8 @@ from django.core.validators import validate_email, validate_slug import random, string from django.db import connection +log = logging.getLogger("mitx.auth") + def csrf_token(context): csrf_token = context.get('csrf_token', '') if csrf_token == 'NOTPROVIDED': @@ -37,36 +41,40 @@ def index(request): # return render_to_response('courseinfo.html', {'error' : '', # 'csrf': csrf_token }) +# Need different levels of logging def login_user(request, error=""): -# print request.POST if 'email' not in request.POST or 'password' not in request.POST: -# print "X" return render_to_response('login.html', {'error':error.replace('+',' ')}) + email = request.POST['email'] password = request.POST['password'] try: - user=User.objects.get(email=email) + user = User.objects.get(email=email) except User.DoesNotExist: + log.warning("Login failed - Unknown user email: {0}".format(email)) return HttpResponse(json.dumps({'success':False, 'error': 'Invalid login'})) # TODO: User error message - username=user.username - user=authenticate(username=username, password=password) + username = user.username + user = authenticate(username=username, password=password) if user is None: + log.warning("Login failed - Unknown password for {0} is invalid".format(email)) return HttpResponse(json.dumps({'success':False, 'error': 'Invalid login'})) - if user is not None and user.is_active: - login(request, user) - if request.POST['remember'] == 'true': - request.session.set_expiry(None) # or change to 604800 for 7 days -# print "recall" - else: - request.session.set_expiry(0) - #print "close" -# print len(connection.queries), connection.queries - return HttpResponse(json.dumps({'success':True})) -# print len(connection.queries), connection.queries + if user is not None and user.is_active: + try: + login(request, user) + if request.POST['remember'] == 'true': + 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) + except Exception as e: + log.critical("Login failed - Could not create session. Is memcached running?") + log.exception(e) + + return HttpResponse(json.dumps({'success':True})) return HttpResponse(json.dumps({'success':False, 'error': 'Account not active. Check your e-mail.'})) From fd8b1e50c2f1aec99de311fb0d75fbd793d1a1f2 Mon Sep 17 00:00:00 2001 From: Piotr Mitros Date: Thu, 26 Jan 2012 14:26:44 -0500 Subject: [PATCH 03/25] Staging new Askbot, some work on completion framework --- courseware/module_render.py | 9 +-------- courseware/modules/x_module.py | 5 +++++ courseware/progress.py | 31 +++++++++++++++++++++++++------ courseware/views.py | 1 + settings.py | 2 +- 5 files changed, 33 insertions(+), 15 deletions(-) diff --git a/courseware/module_render.py b/courseware/module_render.py index 4c969447a1..4bfbccf8b3 100644 --- a/courseware/module_render.py +++ b/courseware/module_render.py @@ -111,13 +111,6 @@ def render_x_module(user, request, xml_module, module_object_preload): user, module_type, module_id) - # s = StudentModule.objects.filter(student=request.user, - # module_id=module_id, - # module_type = module_type) - # if len(s) == 0: - # s=None - # else: - # s=s[0] if s == None: # If nothing in the database... state=None @@ -132,7 +125,7 @@ def render_x_module(user, request, xml_module, module_object_preload): ajax_url=ajax_url, state=state, track_function = make_track_function(request), - render_function = lambda x: render_module(user, request, x, module_object_preload)) + render_function = lambda x: render_module(user, request, x, module_object_preload)) # If instance wasn't already in the database, create it if s == None: diff --git a/courseware/modules/x_module.py b/courseware/modules/x_module.py index efad4417e8..4b45c4c7fc 100644 --- a/courseware/modules/x_module.py +++ b/courseware/modules/x_module.py @@ -1,3 +1,5 @@ +import courseware.progress + def dummy_track(event_type, event): pass @@ -12,6 +14,9 @@ class XModule(object): ''' Tags in the courseware file guaranteed to correspond to the module ''' return [] + def get_completion(self): + return courseware.progress.completion() + def get_state(self): return "" diff --git a/courseware/progress.py b/courseware/progress.py index 6fe7cf3f2a..ad2cb725b4 100644 --- a/courseware/progress.py +++ b/courseware/progress.py @@ -1,6 +1,11 @@ class completion(object): - def __init__(self, d=None): - self.dict = dict() + def __init__(self, **d): + self.dict = dict({'duration_total':0, + 'duration_watched':0, + 'done':True, + 'questions_correct':0, + 'questions_incorrect':0, + 'questions_total':0}) if d: self.dict.update(d) @@ -11,9 +16,23 @@ class completion(object): self.dict[key] = value def __add__(self, other): - result = dict() - dict.update(self.dict) - dict.update(other.dict) + result = dict(self.dict) + for item in ['duration_total', + 'duration_watched', + 'done', + 'questions_correct', + 'questions_incorrect', + 'questions_total']: + result[item] = result[item]+other.dict[item] + return completion(**result) def __contains__(self, key): - pass + return key in dict + + def __repr__(self): + return repr(self.dict) + +if __name__ == '__main__': + dict1=completion(duration_total=5) + dict2=completion(duration_total=7) + print dict1+dict2 diff --git a/courseware/views.py b/courseware/views.py index 864e5d0223..4345084ec0 100644 --- a/courseware/views.py +++ b/courseware/views.py @@ -134,6 +134,7 @@ def index(request, course="6.002 Spring 2012", chapter="Using the System", secti module_object_preload = list(StudentModule.objects.filter(student=user, module_id__in=module_ids)) + module=render_module(user, request, module, module_object_preload) diff --git a/settings.py b/settings.py index 57b3227b1f..f42725e7f1 120000 --- a/settings.py +++ b/settings.py @@ -1 +1 @@ -settings_old_askbot.py \ No newline at end of file +settings_new_askbot.py \ No newline at end of file From cf210ea171bcd533478d4481a08d796b38fa3eb5 Mon Sep 17 00:00:00 2001 From: David Ormsbee Date: Thu, 26 Jan 2012 15:03:19 -0500 Subject: [PATCH 04/25] switch tracking to use logger --- track/middleware.py | 6 +++++- track/views.py | 42 ++++++------------------------------------ 2 files changed, 11 insertions(+), 37 deletions(-) diff --git a/track/middleware.py b/track/middleware.py index 866accbeb5..407f64b992 100644 --- a/track/middleware.py +++ b/track/middleware.py @@ -1,4 +1,8 @@ -import views, json +import json + +from django.conf import settings + +import views class TrackMiddleware: def process_request (self, request): diff --git a/track/views.py b/track/views.py index 2a368b3188..a95cc1ca62 100644 --- a/track/views.py +++ b/track/views.py @@ -1,47 +1,17 @@ +import json +import logging +import os + # Create your views here. from django.http import HttpResponse from django.http import Http404 from django.conf import settings -import json, os, stat -import tempfile - -if settings.TRACK_DIR != None: - directory = tempfile.mkdtemp(prefix = settings.TRACK_DIR) -else: - directory = None - -logfile = None -file_index = 0 -log_index = 0 -filename = None - -def make_file(): - global logfile, log_index, file_index, filename - if logfile != None: - logfile.close() - os.chmod(filename, stat.S_IRUSR | stat.S_IWUSR | \ - stat.S_IRGRP | stat.S_IWGRP | \ - stat.S_IROTH ) - filename = directory+"/%05i"%(file_index)+".trklog" - logfile = open(filename, "w") - file_index = file_index + 1 - log_index = 0 +log = logging.getLogger("tracking") def log_event(event): - global logfile, log_index event_str = json.dumps(event) - if settings.TRACK_DIR == None: -# print event - return - - if logfile == None or log_index >= settings.MAXLOG: - make_file() - - logfile.write(event_str[:settings.TRACK_MAX_EVENT]+'\n') - if settings.DEBUG_TRACK_LOG: - print event_str - log_index = log_index + 1 + log.info(event_str[:settings.TRACK_MAX_EVENT]) def user_track(request): try: # TODO: Do the same for many of the optional META parameters From 79c1cf19a065b99d896b81b292b588762bedc6db Mon Sep 17 00:00:00 2001 From: David Ormsbee Date: Thu, 26 Jan 2012 16:35:04 -0500 Subject: [PATCH 05/25] typo in login error --- auth/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/auth/views.py b/auth/views.py index 7675578a57..1b6069b593 100644 --- a/auth/views.py +++ b/auth/views.py @@ -58,7 +58,7 @@ def login_user(request, error=""): username = user.username user = authenticate(username=username, password=password) if user is None: - log.warning("Login failed - Unknown password for {0} is invalid".format(email)) + log.warning("Login failed - password for {0} is invalid".format(email)) return HttpResponse(json.dumps({'success':False, 'error': 'Invalid login'})) From e5ca9618ea5ae9f2fc11ea5a8c9f479b1430d84c Mon Sep 17 00:00:00 2001 From: David Ormsbee Date: Thu, 26 Jan 2012 19:05:52 -0500 Subject: [PATCH 06/25] remove /login from tracking logs so we don't capture passwords --- auth/views.py | 2 ++ track/middleware.py | 7 ++++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/auth/views.py b/auth/views.py index 1b6069b593..fa8c56933f 100644 --- a/auth/views.py +++ b/auth/views.py @@ -74,8 +74,10 @@ def login_user(request, error=""): log.critical("Login failed - Could not create session. Is memcached running?") log.exception(e) + log.info("Login success - {0} ({1})".format(username, email)) return HttpResponse(json.dumps({'success':True})) + log.warning("Login failed - Account not active for user {0}".format(username)) return HttpResponse(json.dumps({'success':False, 'error': 'Account not active. Check your e-mail.'})) diff --git a/track/middleware.py b/track/middleware.py index 407f64b992..6905ae86f3 100644 --- a/track/middleware.py +++ b/track/middleware.py @@ -5,10 +5,11 @@ from django.conf import settings import views class TrackMiddleware: - def process_request (self, request): + def process_request(self, request): try: - # We're already logging events - if request.META['PATH_INFO'] == '/event': + # We're already logging events, and we don't want to capture user + # names/passwords. + if request.META['PATH_INFO'] in ['/event', '/login']: return event = { 'GET' : dict(request.GET), From efdaa04742bb01ce6c04d494b46b45c309069e21 Mon Sep 17 00:00:00 2001 From: David Ormsbee Date: Fri, 27 Jan 2012 10:57:36 -0500 Subject: [PATCH 07/25] convert more prints to logging --- courseware/modules/video_module.py | 40 ++++++++++++++++-------------- settings_new_askbot.py | 2 +- 2 files changed, 23 insertions(+), 19 deletions(-) diff --git a/courseware/modules/video_module.py b/courseware/modules/video_module.py index 354d988a2e..93650cb6d3 100644 --- a/courseware/modules/video_module.py +++ b/courseware/modules/video_module.py @@ -1,36 +1,39 @@ -from x_module import XModule -from lxml import etree - +import logging import json ## TODO: Abstract out from Django from django.conf import settings from djangomako.shortcuts import render_to_response, render_to_string +from lxml import etree + +from x_module import XModule + +log = logging.getLogger("mitx.courseware.modules") class VideoModule(XModule): #id_attribute = 'youtube' video_time = 0 def handle_ajax(self, dispatch, get): - print "GET", get - print "DISPATCH", dispatch - if dispatch=='goto_position': + log.debug(u"GET {0}".format(get)) + log.debug(u"DISPATCH {0}".format(dispatch)) + if dispatch == 'goto_position': self.position = int(float(get['position'])) - print "NEW POSITION", self.position + log.debug(u"NEW POSITION {0}".format(self.position)) return json.dumps({'success':True}) raise Http404() def get_state(self): - print "STATE POSITION", self.position + log.debug(u"STATE POSITION {0}".format(self.position)) return json.dumps({ 'position':self.position }) def get_xml_tags(): - ''' Tags in the courseware file guaranteed to correspond to the module ''' + '''Tags in the courseware file guaranteed to correspond to the module''' return "video" def video_list(self): - l=self.youtube.split(',') - l=[i.split(":") for i in l] + l = self.youtube.split(',') + l = [i.split(":") for i in l] return json.dumps(dict(l)) def get_html(self): @@ -39,24 +42,25 @@ class VideoModule(XModule): 'position':self.position}) def get_init_js(self): - ''' JavaScript code to be run when problem is shown. Be aware + '''JavaScript code to be run when problem is shown. Be aware that this may happen several times on the same page (e.g. student switching tabs). Common functions should be put in the main course .js files for now. ''' - print "INIT POSITION", self.position + log.debug(u"INIT POSITION {0}".format(self.position)) return render_to_string('video_init.js',{'streams':self.video_list(), 'id':self.item_id, 'position':self.position}) def get_destroy_js(self): - return "videoDestroy(\""+self.item_id+"\");" + return "videoDestroy(\"{0}\");".format(self.item_id) def __init__(self, xml, item_id, ajax_url=None, track_url=None, state=None, track_function=None, render_function = None): XModule.__init__(self, xml, item_id, ajax_url, track_url, state, track_function, render_function) self.youtube = etree.XML(xml).get('youtube') self.position = 0 - if state!=None: + if state != None: state = json.loads(state) - if 'position' in state: self.position = int(float(state['position'])) - print "POOSITION IN STATE" - print "LOAD POSITION", self.position + if 'position' in state: + self.position = int(float(state['position'])) + log.debug("POSITION IN STATE") + log.debug(u"LOAD POSITION {0}".format(self.position)) diff --git a/settings_new_askbot.py b/settings_new_askbot.py index 2ef4b5f893..39c9602eac 100644 --- a/settings_new_askbot.py +++ b/settings_new_askbot.py @@ -155,7 +155,7 @@ LOGGING = { 'stream' : sys.stderr, }, 'app' : { - 'level' : 'INFO', + 'level' : 'DEBUG' if DEBUG else 'INFO', 'class' : 'logging.handlers.TimedRotatingFileHandler', 'formatter' : 'standard', 'filename' : LOG_DIR + '/mitx.log', # temporary location for proof of concept From ca44cf07b266a228d832005df93289b94009d957 Mon Sep 17 00:00:00 2001 From: Bridger Maxwell Date: Fri, 27 Jan 2012 17:24:07 -0500 Subject: [PATCH 08/25] Added 'view revision' on wiki history --- simplewiki/urls.py | 1 + simplewiki/views.py | 46 ++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 44 insertions(+), 3 deletions(-) diff --git a/simplewiki/urls.py b/simplewiki/urls.py index 05a631f0be..0a95fc305a 100644 --- a/simplewiki/urls.py +++ b/simplewiki/urls.py @@ -3,6 +3,7 @@ from django.conf.urls.defaults import * urlpatterns = patterns('', url(r'^$', 'simplewiki.views.root_redirect', name='wiki_root'), url(r'^view(/[a-zA-Z\d/_-]*)/?$', 'simplewiki.views.view', name='wiki_view'), + url(r'^view_revision/([0-9]*)(/[a-zA-Z\d/_-]*)/?$', 'simplewiki.views.view_revision', name='wiki_view_revision'), url(r'^edit(/[a-zA-Z\d/_-]*)/?$', 'simplewiki.views.edit', name='wiki_edit'), url(r'^create(/[a-zA-Z\d/_-]*)/?$', 'simplewiki.views.create', name='wiki_create'), url(r'^history(/[a-zA-Z\d/_-]*)/([0-9]*)/?$', 'simplewiki.views.history', name='wiki_history'), diff --git a/simplewiki/views.py b/simplewiki/views.py index a49d135aee..ea7e04e419 100644 --- a/simplewiki/views.py +++ b/simplewiki/views.py @@ -36,12 +36,44 @@ def view(request, wiki_url): if perm_err: return perm_err d = {'wiki_article': article, + 'wiki_article_revision':article.current_revision, '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), } d.update(csrf(request)) return render_to_response('simplewiki_view.html', d) + +def view_revision(request, revision_number, wiki_url, revision=None): + if not request.user.is_authenticated(): + return redirect('/') + + (article, path, err) = fetch_from_url(request, wiki_url) + if err: + return err + + try: + revision = Revision.objects.get(counter=int(revision_number), article=article) + except: + d = {'wiki_article': article, + 'wiki_err_norevision': revision_number,} + d.update(csrf(request)) + return render_to_response('simplewiki_error.html', d) + + + perm_err = check_permissions(request, article, check_read=True, check_deleted=True, revision=revision) + if perm_err: + return perm_err + + d = {'wiki_article': article, + 'wiki_article_revision':revision, + 'wiki_write': article.can_write_l(request.user), + 'wiki_attachments_write': article.can_attach(request.user), + 'wiki_current_revision_deleted' : not (revision.deleted == 0), + } + d.update(csrf(request)) + return render_to_response('simplewiki_view.html', d) + def root_redirect(request): if not request.user.is_authenticated(): @@ -206,12 +238,18 @@ def history(request, wiki_url, page=1): perm_err = check_permissions(request, article, check_write=True, check_locked=True) if perm_err: return perm_err + + redirectURL = reverse('wiki_view', args=(article.get_url(),)) try: r = int(request.POST['revision']) revision = Revision.objects.get(id=r) if request.POST.__contains__('change'): article.current_revision = revision article.save() + elif request.POST.__contains__('view'): + redirectURL = reverse('wiki_view_revision', args=(revision.counter, article.get_url(),)) + + #The rese of these are admin functions elif request.POST.__contains__('delete') and request.user.is_superuser: if (revision.deleted == 0): revision.adminSetDeleted(2) @@ -228,7 +266,7 @@ def history(request, wiki_url, page=1): except: pass finally: - return HttpResponseRedirect(reverse('wiki_view', args=(article.get_url(),))) + return HttpResponseRedirect(redirectURL) # # # @@ -433,14 +471,16 @@ def fetch_from_url(request, url): return (article, path, err) -def check_permissions(request, article, check_read=False, check_write=False, check_locked=False, check_deleted=False): +def check_permissions(request, article, check_read=False, check_write=False, check_locked=False, check_deleted=False, revision = None): read_err = check_read and not article.can_read(request.user) write_err = check_write and not article.can_write(request.user) locked_err = check_locked and article.locked - deleted_err = check_deleted and not (article.current_revision.deleted == 0) + if revision == None: + revision = article.current_revision + deleted_err = check_deleted and not (revision.deleted == 0) if (request.user.is_superuser): deleted_err = False locked_err = False From 84794a230da7039e030936d522efc917a4198407 Mon Sep 17 00:00:00 2001 From: David Ormsbee Date: Fri, 27 Jan 2012 19:07:46 -0500 Subject: [PATCH 09/25] make sure exceptions that go all the way up the django stack are logged in our error logs when DEBUG=False --- settings_new_askbot.py | 1 + util/middleware.py | 13 +++++++++++++ 2 files changed, 14 insertions(+) create mode 100644 util/middleware.py diff --git a/settings_new_askbot.py b/settings_new_askbot.py index 39c9602eac..14ede01c85 100644 --- a/settings_new_askbot.py +++ b/settings_new_askbot.py @@ -262,6 +262,7 @@ 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', diff --git a/util/middleware.py b/util/middleware.py new file mode 100644 index 0000000000..3bda2c7873 --- /dev/null +++ b/util/middleware.py @@ -0,0 +1,13 @@ +import logging + +from django.http import HttpResponse + +log = logging.getLogger("mitx") + +class ExceptionLoggingMiddleware(object): + """Just here to log unchecked exceptions that go all the way up the Django + stack""" + + def process_exception(self, request, exception): + log.exception(exception) + return HttpResponse("Server Error - Please try again later.") From 6c1a7ce66e86ed3d2e12e864b0159fde3d02b7b4 Mon Sep 17 00:00:00 2001 From: fischerl Date: Fri, 27 Jan 2012 19:16:24 -0500 Subject: [PATCH 10/25] default to cover of textbook --- staticbook/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/staticbook/views.py b/staticbook/views.py index dbfab3852c..ad1314a71c 100644 --- a/staticbook/views.py +++ b/staticbook/views.py @@ -5,7 +5,7 @@ import os from django.conf import settings from django.http import Http404 -def index(request, page=1): +def index(request, page=0): if not request.user.is_authenticated(): return redirect('/') return render_to_response('staticbook.html',{'page':int(page)}) From 1268530f7af4e0a95c78f3d115d7c375e12c216c Mon Sep 17 00:00:00 2001 From: Piotr Mitros Date: Fri, 27 Jan 2012 22:09:47 -0500 Subject: [PATCH 11/25] Preparing for stage --- courseware/capa/unit.py | 130 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 130 insertions(+) create mode 100644 courseware/capa/unit.py diff --git a/courseware/capa/unit.py b/courseware/capa/unit.py new file mode 100644 index 0000000000..c6a4d4591a --- /dev/null +++ b/courseware/capa/unit.py @@ -0,0 +1,130 @@ +import math +from numpy import eye, array +import operator +from pyparsing import Word, alphas, nums, oneOf, Literal +from pyparsing import ZeroOrMore, OneOrMore, StringStart +from pyparsing import StringEnd, Optional, Forward +from pyparsing import CaselessLiteral, Group, StringEnd +from pyparsing import NoMatch, stringEnd + +base_units = ['meter', 'gram', 'second', 'ampere', 'kelvin', 'mole', 'cd'] +unit_vectors = dict([(base_units[i], eye(len(base_units))[:,i]) for i in range(len(base_units))]) + + +def unit_evaluator(unit_string, units=unit_map): + ''' Evaluate an expression. Variables are passed as a dictionary + from string to value. Unary functions are passed as a dictionary + from string to function ''' + if string.strip() == "": + return float('nan') + ops = { "^" : operator.pow, + "*" : operator.mul, + "/" : operator.truediv, + } + prefixes={'%':0.01,'k':1e3,'M':1e6,'G':1e9, + 'T':1e12,#'P':1e15,'E':1e18,'Z':1e21,'Y':1e24, + 'c':1e-2,'m':1e-3,'u':1e-6, + 'n':1e-9,'p':1e-12}#,'f':1e-15,'a':1e-18,'z':1e-21,'y':1e-24} + + def super_float(text): + ''' Like float, but with si extensions. 1k goes to 1000''' + if text[-1] in suffixes: + return float(text[:-1])*suffixes[text[-1]] + else: + return float(text) + + def number_parse_action(x): # [ '7' ] -> [ 7 ] + return [super_float("".join(x))] + def exp_parse_action(x): # [ 2 ^ 3 ^ 2 ] -> 512 + x = [e for e in x if type(e) == float] # Ignore ^ + x.reverse() + x=reduce(lambda a,b:b**a, x) + return x + def parallel(x): # Parallel resistors [ 1 2 ] => 2/3 + if len(x) == 1: + return x[0] + if 0 in x: + return float('nan') + x = [1./e for e in x if type(e) == float] # Ignore ^ + return 1./sum(x) + def sum_parse_action(x): # [ 1 + 2 - 3 ] -> 0 + total = 0.0 + op = ops['+'] + for e in x: + if e in set('+-'): + op = ops[e] + else: + total=op(total, e) + return total + def prod_parse_action(x): # [ 1 * 2 / 3 ] => 0.66 + prod = 1.0 + op = ops['*'] + for e in x: + if e in set('*/'): + op = ops[e] + else: + prod=op(prod, e) + return prod + def func_parse_action(x): + return [functions[x[0]](x[1])] + + number_suffix=reduce(lambda a,b:a|b, map(Literal,suffixes.keys()), NoMatch()) # SI suffixes and percent + (dot,minus,plus,times,div,lpar,rpar,exp)=map(Literal,".-+*/()^") + + number_part=Word(nums) + inner_number = ( number_part+Optional("."+number_part) ) | ("."+number_part) # 0.33 or 7 or .34 + number=Optional(minus | plus)+ inner_number + \ + Optional(CaselessLiteral("E")+Optional("-")+number_part)+ \ + Optional(number_suffix) # 0.33k or -17 + number=number.setParseAction( number_parse_action ) # Convert to number + + # Predefine recursive variables + expr = Forward() + factor = Forward() + + def sreduce(f, l): + ''' Same as reduce, but handle len 1 and len 0 lists sensibly ''' + if len(l)==0: + return NoMatch() + if len(l)==1: + return l[0] + return reduce(f, l) + + # Handle variables passed in. E.g. if we have {'R':0.5}, we make the substitution. + # Special case for no variables because of how we understand PyParsing is put together + if len(variables)>0: + varnames = sreduce(lambda x,y:x|y, map(lambda x: CaselessLiteral(x), variables.keys())) + varnames.setParseAction(lambda x:map(lambda y:variables[y], x)) + else: + varnames=NoMatch() + # Same thing for functions. + if len(functions)>0: + funcnames = sreduce(lambda x,y:x|y, map(lambda x: CaselessLiteral(x), functions.keys())) + function = funcnames+lpar.suppress()+expr+rpar.suppress() + function.setParseAction(func_parse_action) + else: + function = NoMatch() + + atom = number | varnames | lpar+expr+rpar | function + factor << (atom + ZeroOrMore(exp+atom)).setParseAction(exp_parse_action) # 7^6 + paritem = factor + ZeroOrMore(Literal('||')+factor) # 5k || 4k + paritem=paritem.setParseAction(parallel) + term = paritem + ZeroOrMore((times|div)+paritem) # 7 * 5 / 4 - 3 + term = term.setParseAction(prod_parse_action) + expr << Optional((plus|minus)) + term + ZeroOrMore((plus|minus)+term) # -5 + 4 - 3 + expr=expr.setParseAction(sum_parse_action) + return (expr+stringEnd).parseString(string)[0] + +if __name__=='__main__': + variables={'R1':2.0, 'R3':4.0} + functions={'sin':math.sin, 'cos':math.cos} + print "X",evaluator(variables, functions, "10000||sin(7+5)-6k") + print "X",evaluator(variables, functions, "13") + print evaluator({'R1': 2.0, 'R3':4.0}, {}, "13") + # + print evaluator({'a': 2.2997471478310274, 'k': 9, 'm': 8, 'x': 0.66009498411213041}, {}, "5") + print evaluator({},{}, "-1") + print evaluator({},{}, "-(7+5)") + print evaluator({},{}, "-0.33") + print evaluator({},{}, "-.33") + print evaluator({},{}, "5+7 QWSEKO") From 04a7be0ae7a1a4ad2512a89399f0f3d058f2e34b Mon Sep 17 00:00:00 2001 From: Piotr Mitros Date: Fri, 27 Jan 2012 22:37:34 -0500 Subject: [PATCH 12/25] Fixed e-mail in URLs.py, fixed 2 gjs bugs --- courseware/capa/capa_problem.py | 2 +- courseware/capa/responsetypes.py | 4 +++- urls.py | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/courseware/capa/capa_problem.py b/courseware/capa/capa_problem.py index 46ad5e861d..a6021af3bc 100644 --- a/courseware/capa/capa_problem.py +++ b/courseware/capa/capa_problem.py @@ -133,7 +133,7 @@ class LoncapaProblem(object): for entry in problems_simple.xpath("//"+"|//".join(response_properties+entry_types)): answer = entry.get('correct_answer') if answer != None: - answer_map[entry.get('id')] = contextualize_text(answer, self.context()) + answer_map[entry.get('id')] = contextualize_text(answer, self.context) return answer_map diff --git a/courseware/capa/responsetypes.py b/courseware/capa/responsetypes.py index 3e3cefd8ab..2fbc16ed47 100644 --- a/courseware/capa/responsetypes.py +++ b/courseware/capa/responsetypes.py @@ -8,7 +8,9 @@ from django.conf import settings global_context={'random':random, 'numpy':numpy, 'math':math, - 'scipy':scipy} + 'scipy':scipy, + 'calc':calc, + 'eia':eia} class numericalresponse(object): def __init__(self, xml, context): diff --git a/urls.py b/urls.py index 6d5cfeb561..f24b2088f2 100644 --- a/urls.py +++ b/urls.py @@ -19,7 +19,7 @@ urlpatterns = ('', url(r'^activate/(?P[^/]*)$', 'auth.views.activate_account'), url(r'^$', 'auth.views.index'), url(r'^password_reset/$', 'django.contrib.auth.views.password_reset', - dict(from_email='6002-admin@mit.edu'),name='auth_password_reset'), + dict(from_email='registration@mitx.mit.edu'),name='auth_password_reset'), url(r'^password_change/$',django.contrib.auth.views.password_change,name='auth_password_change'), url(r'^password_change_done/$',django.contrib.auth.views.password_change_done,name='auth_password_change_done'), url(r'^password_reset_confirm/(?P[0-9A-Za-z]+)-(?P.+)/$',django.contrib.auth.views.password_reset_confirm, From cbd8a96431d04a6c72c5e6c7131699c78a905169 Mon Sep 17 00:00:00 2001 From: Piotr Mitros Date: Fri, 27 Jan 2012 22:39:56 -0500 Subject: [PATCH 13/25] Bug in last commit --- courseware/capa/responsetypes.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/courseware/capa/responsetypes.py b/courseware/capa/responsetypes.py index 2fbc16ed47..d925f31b35 100644 --- a/courseware/capa/responsetypes.py +++ b/courseware/capa/responsetypes.py @@ -3,6 +3,8 @@ from util import contextualize_text from calc import evaluator import random, math from django.conf import settings +import eia +import calc # TODO: Should be the same object as in capa_problem global_context={'random':random, From 8125180edc261a06383244a74eecf1e0e7e9a36b Mon Sep 17 00:00:00 2001 From: Piotr Mitros Date: Sat, 28 Jan 2012 12:10:56 -0500 Subject: [PATCH 14/25] Major number of minor cleanups. Fixed from e-mail, import order, ==None, etc. --- auth/models.py | 3 +- auth/views.py | 17 ++--- circuit/models.py | 3 +- circuit/views.py | 18 +++--- courseware/capa/calc.py | 1 + courseware/capa/capa_problem.py | 36 ++++++----- courseware/capa/inputtypes.py | 4 +- courseware/capa/responsetypes.py | 13 ++-- courseware/capa/unit.py | 4 +- courseware/content_parser.py | 10 +-- courseware/models.py | 37 ----------- courseware/module_render.py | 70 ++++++++++----------- courseware/modules/capa_module.py | 29 ++++++--- courseware/modules/html_module.py | 6 +- courseware/modules/schematic_module.py | 4 +- courseware/modules/seq_module.py | 9 +-- courseware/modules/vertical_module.py | 6 +- courseware/modules/video_module.py | 5 +- courseware/views.py | 3 +- perfstats/middleware.py | 6 +- perfstats/views.py | 1 + settings_new_askbot.py | 2 +- settings_old_askbot.py | 2 +- simplewiki/__init__.py | 3 +- simplewiki/admin.py | 3 +- simplewiki/models.py | 16 ++--- simplewiki/templatetags/simplewiki_utils.py | 7 ++- simplewiki/views.py | 33 +++++----- simplewiki/views_attachments.py | 11 ++-- staticbook/views.py | 5 +- urls.py | 5 +- util/views.py | 31 ++++----- 32 files changed, 203 insertions(+), 200 deletions(-) diff --git a/auth/models.py b/auth/models.py index 1a7bf6c221..88cdd2da61 100644 --- a/auth/models.py +++ b/auth/models.py @@ -1,6 +1,7 @@ +import uuid + from django.db import models from django.contrib.auth.models import User -import uuid class UserProfile(models.Model): ## CRITICAL TODO/SECURITY diff --git a/auth/views.py b/auth/views.py index fa8c56933f..56c9cd81de 100644 --- a/auth/views.py +++ b/auth/views.py @@ -1,18 +1,19 @@ +import json import logging +import random +import string -from djangomako.shortcuts import render_to_response, render_to_string -from django.contrib.auth.models import User -from django.shortcuts import redirect +from django.conf import settings from django.contrib.auth import logout, authenticate, login from django.contrib.auth.models import User -from django.http import HttpResponse -import json -from models import Registration, UserProfile -from django.conf import settings +from django.contrib.auth.models import User from django.core.context_processors import csrf from django.core.validators import validate_email, validate_slug -import random, string from django.db import connection +from django.http import HttpResponse +from django.shortcuts import redirect +from djangomako.shortcuts import render_to_response, render_to_string +from models import Registration, UserProfile log = logging.getLogger("mitx.auth") diff --git a/circuit/models.py b/circuit/models.py index ada1a5f295..cc103e1af8 100644 --- a/circuit/models.py +++ b/circuit/models.py @@ -1,6 +1,7 @@ +import uuid + from django.db import models from django.contrib.auth.models import User -import uuid class ServerCircuit(models.Model): # Later, add owner, who can edit, part of what app, etc. diff --git a/circuit/views.py b/circuit/views.py index 235c25b69f..c8840484a8 100644 --- a/circuit/views.py +++ b/circuit/views.py @@ -1,24 +1,26 @@ -from djangomako.shortcuts import render_to_response, render_to_string -from django.shortcuts import redirect +import json import os + +import xml.etree.ElementTree + from django.conf import settings from django.http import Http404 -from models import ServerCircuit -import json -import xml.etree.ElementTree from django.http import HttpResponse +from django.shortcuts import redirect +from djangomako.shortcuts import render_to_response, render_to_string + +from models import ServerCircuit def circuit_line(circuit): + ''' Returns string for an appropriate input element for a circuit. + TODO: Rename. ''' if not circuit.isalnum(): raise Http404() try: sc = ServerCircuit.objects.get(name=circuit) schematic = sc.schematic - print "Got" except: schematic = '' - print "not got" - print "X", schematic circuit_line = xml.etree.ElementTree.Element('input') circuit_line.set('type', 'hidden') diff --git a/courseware/capa/calc.py b/courseware/capa/calc.py index ef34e186e2..bd4136d393 100644 --- a/courseware/capa/calc.py +++ b/courseware/capa/calc.py @@ -1,5 +1,6 @@ import math import operator + from pyparsing import Word, alphas, nums, oneOf, Literal from pyparsing import ZeroOrMore, OneOrMore, StringStart from pyparsing import StringEnd, Optional, Forward diff --git a/courseware/capa/capa_problem.py b/courseware/capa/capa_problem.py index a6021af3bc..b7ac8940fe 100644 --- a/courseware/capa/capa_problem.py +++ b/courseware/capa/capa_problem.py @@ -1,18 +1,24 @@ -import random, numpy, math, scipy -import struct, os +import copy +import math +import numpy +import os +import random import re +import scipy +import struct + from lxml import etree from lxml.etree import Element -import copy + from mako.template import Template -from courseware.content_parser import xpath_remove -import calc, eia from util import contextualize_text - from inputtypes import textline, schematic from responsetypes import numericalresponse, formularesponse, customresponse, schematicresponse +import calc +import eia + response_types = {'numericalresponse':numericalresponse, 'formularesponse':formularesponse, 'customresponse':customresponse, @@ -52,12 +58,14 @@ class LoncapaProblem(object): self.done = False self.filename = filename - if id!=None: + if id: self.problem_id = id else: - self.problem_id = filename + print "NO ID" + raise Exception("This should never happen (183)") + #self.problem_id = filename - if state!=None: + if state: if 'seed' in state: self.seed = state['seed'] if 'student_answers' in state: @@ -68,7 +76,7 @@ class LoncapaProblem(object): self.done = state['done'] # TODO: Does this deplete the Linux entropy pool? Is this fast enough? - if self.seed == None: + if not self.seed: self.seed=struct.unpack('i', os.urandom(4))[0] ## Parse XML file @@ -102,7 +110,7 @@ class LoncapaProblem(object): for key in self.correct_map: if self.correct_map[key] == u'correct': correct += 1 - if self.student_answers == None or len(self.student_answers)==0: + if (not self.student_answers) or len(self.student_answers)==0: return {'score':0, 'total':self.get_max_score()} else: @@ -132,7 +140,7 @@ class LoncapaProblem(object): for entry in problems_simple.xpath("//"+"|//".join(response_properties+entry_types)): answer = entry.get('correct_answer') - if answer != None: + if answer: answer_map[entry.get('id')] = contextualize_text(answer, self.context) return answer_map @@ -162,7 +170,7 @@ class LoncapaProblem(object): status = self.correct_map[problemtree.get('id')] value = "" - if self.student_answers != None and problemtree.get('id') in self.student_answers: + if self.student_answers and problemtree.get('id') in self.student_answers: value = self.student_answers[problemtree.get('id')] return html_special_response[problemtree.tag](problemtree, value, status) #TODO @@ -170,7 +178,7 @@ class LoncapaProblem(object): tree=Element(problemtree.tag) for item in problemtree: subitems = self.extract_html(item) - if subitems != None: + if subitems: for subitem in subitems: tree.append(subitem) for (key,value) in problemtree.items(): diff --git a/courseware/capa/inputtypes.py b/courseware/capa/inputtypes.py index db98363872..c3b59a4537 100644 --- a/courseware/capa/inputtypes.py +++ b/courseware/capa/inputtypes.py @@ -1,8 +1,8 @@ -from djangomako.shortcuts import render_to_response, render_to_string - from lxml.etree import Element from lxml import etree +from djangomako.shortcuts import render_to_response, render_to_string + class textline(object): @staticmethod def render(element, value, state): diff --git a/courseware/capa/responsetypes.py b/courseware/capa/responsetypes.py index d925f31b35..93ebac85f9 100644 --- a/courseware/capa/responsetypes.py +++ b/courseware/capa/responsetypes.py @@ -1,10 +1,15 @@ -import random, numpy, math, scipy, json -from util import contextualize_text +import json +import math +import numpy +import random +import scipy + from calc import evaluator -import random, math from django.conf import settings -import eia +from util import contextualize_text + import calc +import eia # TODO: Should be the same object as in capa_problem global_context={'random':random, diff --git a/courseware/capa/unit.py b/courseware/capa/unit.py index c6a4d4591a..2cbe4f93f0 100644 --- a/courseware/capa/unit.py +++ b/courseware/capa/unit.py @@ -1,6 +1,8 @@ import math -from numpy import eye, array import operator + +from numpy import eye, array + from pyparsing import Word, alphas, nums, oneOf, Literal from pyparsing import ZeroOrMore, OneOrMore, StringStart from pyparsing import StringEnd, Optional, Forward diff --git a/courseware/content_parser.py b/courseware/content_parser.py index c5c0600f9d..fd6fbb2d58 100644 --- a/courseware/content_parser.py +++ b/courseware/content_parser.py @@ -1,13 +1,15 @@ -try: +import json +import hashlib + +from lxml import etree + +try: # This lets us do __name__ == ='__main__' from django.conf import settings from auth.models import UserProfile except: settings = None -from lxml import etree -import json -import hashlib ''' This file will eventually form an abstraction layer between the course XML file and the rest of the system. diff --git a/courseware/models.py b/courseware/models.py index cee61f336b..5c706f10a8 100644 --- a/courseware/models.py +++ b/courseware/models.py @@ -1,43 +1,6 @@ from django.db import models from django.contrib.auth.models import User -# class Organization(models.Model): -# # Tree structure implemented such that child node has left ID -# # greater than all parents, and right ID less than all parents -# left_tree_id = models.IntegerField(unique=True, db_index=True) -# right_tree_id = models.IntegerField(unique=True, db_index=True) -# # This is a duplicate, but we keep this to enforce unique name -# # constraint -# parent = models.ForeignKey('self', null=True, blank=True) -# name = models.CharField(max_length=200) -# ORG_TYPES= (('course','course'), -# ('chapter','chapter'), -# ('section','section'),) -# org_type = models.CharField(max_length=32, choices=ORG_TYPES) -# available = models.DateField(null=True, blank=True) -# due = models.DateField(null=True, blank=True) -# # JSON dictionary of metadata: -# # Time for a video, format of a section, etc. -# metadata = models.TextField(null=True, blank=True) - -# class Modules(models.Model): -# MOD_TYPES = (('hw','homework'), -# ('vid','video_clip'), -# ('lay','layout'), -# (),) -# module_type = models.CharField(max_length=100) -# left_tree_id = models.IntegerField(unique=True, db_index=True) -# right_tree_id = models.IntegerField(unique=True, db_index=True) - -# LAYOUT_TYPES = (('leaf','leaf'), -# ('tab','tab'), -# ('seq','sequential'), -# ('sim','simultaneous'),) -# layout_type = models.CharField(max_length=32, choices=LAYOUT_TYPES) -# data = models.TextField(null=True, blank=True) - -#class HomeworkProblems(models.Model): - class StudentModule(models.Model): # For a homework problem, contains a JSON # object consisting of state diff --git a/courseware/module_render.py b/courseware/module_render.py index 4bfbccf8b3..96833cc32d 100644 --- a/courseware/module_render.py +++ b/courseware/module_render.py @@ -1,41 +1,36 @@ -from django.http import HttpResponse -from django.template import Context, loader -from djangomako.shortcuts import render_to_response, render_to_string -import json, os, sys -from django.core.context_processors import csrf - -from django.db import connection -from django.template import Context -from django.contrib.auth.models import User -from auth.models import UserProfile -from django.shortcuts import redirect - import StringIO -import track.views - -from django.http import Http404 - +import json +import os +import sys +import sys import urllib +import uuid -import courseware.modules.capa_module -import courseware.modules.video_module -import courseware.modules.vertical_module -import courseware.modules.html_module -import courseware.modules.schematic_module -import courseware.modules.seq_module - -from models import StudentModule - -import urllib +from lxml import etree from django.conf import settings +from django.contrib.auth.models import User +from django.core.context_processors import csrf +from django.db import connection +from django.http import Http404 +from django.http import HttpResponse +from django.shortcuts import redirect +from django.template import Context +from django.template import Context, loader +from djangomako.shortcuts import render_to_response, render_to_string + +from auth.models import UserProfile +from models import StudentModule +import track.views import courseware.content_parser as content_parser -import sys - -from lxml import etree -import uuid +import courseware.modules.capa_module +import courseware.modules.html_module +import courseware.modules.schematic_module +import courseware.modules.seq_module +import courseware.modules.vertical_module +import courseware.modules.video_module ## TODO: Add registration mechanism modx_modules={'problem':courseware.modules.capa_module.LoncapaModule, @@ -93,7 +88,7 @@ def modx_dispatch(request, module=None, dispatch=None, id=None): ajax_return=instance.handle_ajax(dispatch, request.POST) # Save the state back to the database s.state=instance.get_state() - if instance.get_score() != None: + if not instance.get_score(): s.grade=instance.get_score()['score'] s.save() # Return whatever the module wanted to return to the client/caller @@ -107,15 +102,14 @@ def render_x_module(user, request, xml_module, module_object_preload): module_id=xml_module.get('id') #module_class.id_attribute) or "" # Grab state from database - s = object_cache(module_object_preload, - user, - module_type, - module_id) + smod = object_cache(module_object_preload, + user, + module_type, + module_id) - if s == None: # If nothing in the database... + if not smod: # If nothing in the database... state=None else: - smod = s state = smod.state # Create a new instance @@ -128,7 +122,7 @@ def render_x_module(user, request, xml_module, module_object_preload): render_function = lambda x: render_module(user, request, x, module_object_preload)) # If instance wasn't already in the database, create it - if s == None: + if not smod: smod=StudentModule(student=user, module_type = module_type, module_id=module_id, diff --git a/courseware/modules/capa_module.py b/courseware/modules/capa_module.py index 591f9c7516..8eeeec1f3c 100644 --- a/courseware/modules/capa_module.py +++ b/courseware/modules/capa_module.py @@ -1,21 +1,27 @@ -import random, numpy, math, scipy, sys, StringIO, os, struct, json -from x_module import XModule -import sys - -from courseware.capa.capa_problem import LoncapaProblem -from django.http import Http404 - +import StringIO +import datetime import dateutil import dateutil.parser -import datetime - -import courseware.content_parser as content_parser +import json +import math +import numpy +import os +import random +import scipy +import struct +import sys +import traceback from lxml import etree ## TODO: Abstract out from Django from django.conf import settings from djangomako.shortcuts import render_to_response, render_to_string +from django.http import Http404 + +from x_module import XModule +from courseware.capa.capa_problem import LoncapaProblem +import courseware.content_parser as content_parser class LoncapaModule(XModule): ''' Interface between capa_problem and x_module. Originally a hack @@ -231,6 +237,8 @@ class LoncapaModule(XModule): for key in get: answers['_'.join(key.split('_')[1:])]=get[key] + print "XXX", answers, get + event_info['answers']=answers # Too late. Cannot submit @@ -255,6 +263,7 @@ class LoncapaModule(XModule): correct_map = self.lcp.grade_answers(answers) except: self.lcp = LoncapaProblem(filename, id=lcp_id, state=old_state) + traceback.print_exc() print {'error':sys.exc_info(), 'answers':answers, 'seed':self.lcp.seed, diff --git a/courseware/modules/html_module.py b/courseware/modules/html_module.py index 0c5a0edae2..61c903d41c 100644 --- a/courseware/modules/html_module.py +++ b/courseware/modules/html_module.py @@ -1,12 +1,12 @@ -from x_module import XModule -from lxml import etree - import json ## TODO: Abstract out from Django from django.conf import settings from djangomako.shortcuts import render_to_response, render_to_string +from x_module import XModule +from lxml import etree + class HtmlModule(XModule): id_attribute = 'filename' diff --git a/courseware/modules/schematic_module.py b/courseware/modules/schematic_module.py index a32de9b275..9c7d291b92 100644 --- a/courseware/modules/schematic_module.py +++ b/courseware/modules/schematic_module.py @@ -1,11 +1,11 @@ -from x_module import XModule - import json ## TODO: Abstract out from Django from django.conf import settings from djangomako.shortcuts import render_to_response, render_to_string +from x_module import XModule + class SchematicModule(XModule): id_attribute = 'id' diff --git a/courseware/modules/seq_module.py b/courseware/modules/seq_module.py index 737f9ac2e9..2a91b0caa0 100644 --- a/courseware/modules/seq_module.py +++ b/courseware/modules/seq_module.py @@ -1,13 +1,14 @@ -from x_module import XModule -from lxml import etree -from django.http import Http404 - import json +from lxml import etree + ## TODO: Abstract out from Django +from django.http import Http404 from django.conf import settings from djangomako.shortcuts import render_to_response, render_to_string +from x_module import XModule + class SequentialModule(XModule): ''' Layout module which lays out content in a temporal sequence ''' diff --git a/courseware/modules/vertical_module.py b/courseware/modules/vertical_module.py index 73a7a6c521..5530e22415 100644 --- a/courseware/modules/vertical_module.py +++ b/courseware/modules/vertical_module.py @@ -1,12 +1,12 @@ -from x_module import XModule -from lxml import etree - import json ## TODO: Abstract out from Django from django.conf import settings from djangomako.shortcuts import render_to_response, render_to_string +from x_module import XModule +from lxml import etree + class VerticalModule(XModule): id_attribute = 'id' diff --git a/courseware/modules/video_module.py b/courseware/modules/video_module.py index 93650cb6d3..69a0837403 100644 --- a/courseware/modules/video_module.py +++ b/courseware/modules/video_module.py @@ -1,10 +1,11 @@ -import logging import json +import logging + +from lxml import etree ## TODO: Abstract out from Django from django.conf import settings from djangomako.shortcuts import render_to_response, render_to_string -from lxml import etree from x_module import XModule diff --git a/courseware/views.py b/courseware/views.py index 4345084ec0..9254da1e1e 100644 --- a/courseware/views.py +++ b/courseware/views.py @@ -19,8 +19,9 @@ from lxml import etree from auth.models import UserProfile from models import StudentModule -from module_render import * # TODO: Clean up +from module_render import render_module, modx_dispatch import courseware.content_parser as content_parser +import courseware.modules.capa_module log = logging.getLogger("mitx.courseware") diff --git a/perfstats/middleware.py b/perfstats/middleware.py index ebb8e8142c..1308dd650a 100644 --- a/perfstats/middleware.py +++ b/perfstats/middleware.py @@ -1,7 +1,11 @@ -import views, json, tempfile, time +import json +import tempfile +import time + from django.conf import settings from django.db import connection +import views class ProfileMiddleware: def process_request (self, request): diff --git a/perfstats/views.py b/perfstats/views.py index fef5100a4b..7d0695b9fe 100644 --- a/perfstats/views.py +++ b/perfstats/views.py @@ -1,5 +1,6 @@ # Create your views here. import middleware + from django.http import HttpResponse def end_profile(request): diff --git a/settings_new_askbot.py b/settings_new_askbot.py index 14ede01c85..aa79e08ea8 100644 --- a/settings_new_askbot.py +++ b/settings_new_askbot.py @@ -34,7 +34,7 @@ DEBUG = True TEMPLATE_DEBUG = DEBUG ADMINS = ( - ('Piotr Mitros', 'pmitros@csail.mit.edu'), + ('Piotr Mitros', 'staff@csail.mit.edu'), ) MANAGERS = ADMINS diff --git a/settings_old_askbot.py b/settings_old_askbot.py index 8ab2a98df8..d7783c05db 100644 --- a/settings_old_askbot.py +++ b/settings_old_askbot.py @@ -26,7 +26,7 @@ DEBUG = True TEMPLATE_DEBUG = DEBUG ADMINS = ( - ('Piotr Mitros', 'pmitros@csail.mit.edu'), + ('Piotr Mitros', 'staff@csail.mit.edu'), ) MANAGERS = ADMINS diff --git a/simplewiki/__init__.py b/simplewiki/__init__.py index 071ec2c38f..8c4ebf2d51 100644 --- a/simplewiki/__init__.py +++ b/simplewiki/__init__.py @@ -1,6 +1,7 @@ # Source: django-simplewiki. GPL license. -import sys, os +import os +import sys # allow mdx_* parsers to be just dropped in the simplewiki folder module_path = os.path.abspath(os.path.dirname(__file__)) diff --git a/simplewiki/admin.py b/simplewiki/admin.py index 31e0856b75..b53ace1a7a 100644 --- a/simplewiki/admin.py +++ b/simplewiki/admin.py @@ -1,8 +1,9 @@ # Source: django-simplewiki. GPL license. -from django.contrib import admin from django import forms +from django.contrib import admin from django.utils.translation import ugettext as _ + from models import Article, Revision, Permission, ArticleAttachment class RevisionInline(admin.TabularInline): diff --git a/simplewiki/models.py b/simplewiki/models.py index 71add3c0fc..ed6366e801 100644 --- a/simplewiki/models.py +++ b/simplewiki/models.py @@ -1,12 +1,14 @@ -from django.utils.translation import ugettext_lazy as _ -from django.db import models -from django.db.models import signals -from django.contrib.auth.models import User -from markdown import markdown -from django import forms -from django.core.urlresolvers import reverse import difflib import os + +from django import forms +from django.contrib.auth.models import User +from django.core.urlresolvers import reverse +from django.db import models +from django.db.models import signals +from django.utils.translation import ugettext_lazy as _ +from markdown import markdown + from settings import * class ShouldHaveExactlyOneRootSlug(Exception): diff --git a/simplewiki/templatetags/simplewiki_utils.py b/simplewiki/templatetags/simplewiki_utils.py index 5b8eccf910..1534a7b401 100644 --- a/simplewiki/templatetags/simplewiki_utils.py +++ b/simplewiki/templatetags/simplewiki_utils.py @@ -1,9 +1,10 @@ from django import template -from django.template.defaultfilters import stringfilter -from simplewiki.settings import * from django.conf import settings +from django.template.defaultfilters import stringfilter from django.utils.http import urlquote as django_urlquote +from simplewiki.settings import * + register = template.Library() @register.filter() @@ -14,4 +15,4 @@ def prepend_media_url(value): @register.filter() def urlquote(value): """Prepend user defined media root to url""" - return django_urlquote(value) \ No newline at end of file + return django_urlquote(value) diff --git a/simplewiki/views.py b/simplewiki/views.py index ea7e04e419..16bfc11c44 100644 --- a/simplewiki/views.py +++ b/simplewiki/views.py @@ -1,27 +1,26 @@ # -*- coding: utf-8 -*- import types -from django.core.urlresolvers import get_callable -from django.http import Http404, HttpResponse, HttpResponseRedirect, HttpResponseServerError, HttpResponseForbidden, HttpResponseNotAllowed -from django.utils import simplejson -from djangomako.shortcuts import render_to_response, render_to_string -from django.shortcuts import get_object_or_404 -from django.template import RequestContext, Context, loader -from django.utils.translation import ugettext_lazy as _ -from django.core.urlresolvers import reverse -from django.contrib.auth.decorators import login_required -from django.db.models import Q + from django.conf import settings -from django.shortcuts import redirect +from django.contrib.auth.decorators import login_required from django.core.context_processors import csrf - -from django.template import Context +from django.core.urlresolvers import get_callable +from django.core.urlresolvers import reverse +from django.db.models import Q +from django.http import Http404, HttpResponse, HttpResponseRedirect, HttpResponseServerError, HttpResponseForbidden, HttpResponseNotAllowed from django.http import HttpResponse - -import djangomako.middleware -from mako.template import Template +from django.shortcuts import get_object_or_404 +from django.shortcuts import redirect +from django.template import Context +from django.template import RequestContext, Context, loader +from django.utils import simplejson +from django.utils.translation import ugettext_lazy as _ +from djangomako.shortcuts import render_to_response, render_to_string from mako.lookup import TemplateLookup +from mako.template import Template +import djangomako.middleware -from models import * +from models import * # TODO: Clean up from settings import * def view(request, wiki_url): diff --git a/simplewiki/views_attachments.py b/simplewiki/views_attachments.py index 47eb09a0b2..205f836ab9 100644 --- a/simplewiki/views_attachments.py +++ b/simplewiki/views_attachments.py @@ -1,14 +1,15 @@ +import os + +from django.contrib.auth.decorators import login_required +from django.core.servers.basehttp import FileWrapper +from django.db.models.fields.files import FieldFile from django.http import HttpResponse, HttpResponseRedirect, HttpResponseForbidden, Http404 from django.template import loader, Context -from django.db.models.fields.files import FieldFile -from django.core.servers.basehttp import FileWrapper -from django.contrib.auth.decorators import login_required -from settings import * +from settings import * # TODO: Clean up from models import Article, ArticleAttachment, get_attachment_filepath from views import not_found, check_permissions, get_url_path, fetch_from_url -import os from simplewiki.settings import WIKI_ALLOW_ANON_ATTACHMENTS diff --git a/staticbook/views.py b/staticbook/views.py index ad1314a71c..bb6e2ada19 100644 --- a/staticbook/views.py +++ b/staticbook/views.py @@ -1,9 +1,10 @@ # Create your views here. -from djangomako.shortcuts import render_to_response, render_to_string -from django.shortcuts import redirect import os + from django.conf import settings from django.http import Http404 +from django.shortcuts import redirect +from djangomako.shortcuts import render_to_response, render_to_string def index(request, page=0): if not request.user.is_authenticated(): diff --git a/urls.py b/urls.py index f24b2088f2..54c910dccf 100644 --- a/urls.py +++ b/urls.py @@ -1,8 +1,7 @@ -from django.conf.urls.defaults import patterns, include, url -import django.contrib.auth.views from django.conf import settings +from django.conf.urls.defaults import patterns, include, url from django.contrib import admin -import perfstats +import django.contrib.auth.views # Uncomment the next two lines to enable the admin: # from django.contrib import admin diff --git a/util/views.py b/util/views.py index 738bd93de7..139906e24a 100644 --- a/util/views.py +++ b/util/views.py @@ -1,21 +1,22 @@ -from djangomako.shortcuts import render_to_response, render_to_string -from django.shortcuts import redirect -from django.contrib.auth.models import User -from django.http import HttpResponse -import json -from django.conf import settings -from django.core.context_processors import csrf -from django.http import Http404 -import courseware.capa.calc -from django.core.mail import send_mail -from django.conf import settings import datetime +import json import sys + +from django.conf import settings +from django.conf import settings +from django.contrib.auth.models import User +from django.core.context_processors import csrf +from django.core.mail import send_mail +from django.http import Http404 +from django.http import HttpResponse +from django.shortcuts import redirect +from djangomako.shortcuts import render_to_response, render_to_string + +import courseware.capa.calc import track.views def calculate(request): -# if not request.user.is_authenticated(): -# raise Http404 + ''' Calculator in footer of every page. ''' equation = request.GET['equation'] try: result = courseware.capa.calc.evaluator({}, {}, equation) @@ -27,8 +28,7 @@ def calculate(request): return HttpResponse(json.dumps({'result':result})) def send_feedback(request): -# if not request.user.is_authenticated(): -# raise Http404 + ''' Feeback mechanism in footer of every page. ''' try: username = request.user.username except: @@ -50,4 +50,5 @@ def send_feedback(request): return HttpResponse(json.dumps({'success':True})) def info(request): + ''' Info page (link from main header) ''' return render_to_response("info.html", {}) From abef62a23a112b4afdb02cfeaacb67e6e09a8c21 Mon Sep 17 00:00:00 2001 From: Piotr Mitros Date: Sat, 28 Jan 2012 21:27:54 -0500 Subject: [PATCH 15/25] Syncing between machines --- settings_new_askbot.py | 1 + 1 file changed, 1 insertion(+) diff --git a/settings_new_askbot.py b/settings_new_askbot.py index aa79e08ea8..b7d918bcfc 100644 --- a/settings_new_askbot.py +++ b/settings_new_askbot.py @@ -107,6 +107,7 @@ INSTALLED_APPS = ( 'track', 'circuit', 'perfstats', + 'util', # Uncomment the next line to enable the admin: # 'django.contrib.admin', # Uncomment the next line to enable admin documentation: From b86ba908da84367a6a599827bd5f522b88f440e6 Mon Sep 17 00:00:00 2001 From: Piotr Mitros Date: Sun, 29 Jan 2012 07:46:41 -0500 Subject: [PATCH 16/25] Forked django middleware and moved it into the project. We'd like better django integration --- auth/views.py | 2 +- circuit/views.py | 2 +- courseware/capa/inputtypes.py | 2 +- courseware/module_render.py | 2 +- courseware/modules/capa_module.py | 2 +- courseware/modules/html_module.py | 2 +- courseware/modules/schematic_module.py | 2 +- courseware/modules/seq_module.py | 2 +- courseware/modules/vertical_module.py | 2 +- courseware/modules/video_module.py | 2 +- courseware/views.py | 2 +- settings_new_askbot.py | 5 ++++- settings_old_askbot.py | 2 +- simplewiki/mdx_circuit.py | 2 +- simplewiki/views.py | 4 ++-- static_template_view/views.py | 2 +- staticbook/views.py | 2 +- util/views.py | 2 +- 18 files changed, 22 insertions(+), 19 deletions(-) diff --git a/auth/views.py b/auth/views.py index 56c9cd81de..f2f945644f 100644 --- a/auth/views.py +++ b/auth/views.py @@ -12,7 +12,7 @@ from django.core.validators import validate_email, validate_slug from django.db import connection from django.http import HttpResponse from django.shortcuts import redirect -from djangomako.shortcuts import render_to_response, render_to_string +from mitxmako.shortcuts import render_to_response, render_to_string from models import Registration, UserProfile log = logging.getLogger("mitx.auth") diff --git a/circuit/views.py b/circuit/views.py index c8840484a8..96fcc83115 100644 --- a/circuit/views.py +++ b/circuit/views.py @@ -7,7 +7,7 @@ from django.conf import settings from django.http import Http404 from django.http import HttpResponse from django.shortcuts import redirect -from djangomako.shortcuts import render_to_response, render_to_string +from mitxmako.shortcuts import render_to_response, render_to_string from models import ServerCircuit diff --git a/courseware/capa/inputtypes.py b/courseware/capa/inputtypes.py index c3b59a4537..c7732014da 100644 --- a/courseware/capa/inputtypes.py +++ b/courseware/capa/inputtypes.py @@ -1,7 +1,7 @@ from lxml.etree import Element from lxml import etree -from djangomako.shortcuts import render_to_response, render_to_string +from mitxmako.shortcuts import render_to_response, render_to_string class textline(object): @staticmethod diff --git a/courseware/module_render.py b/courseware/module_render.py index 96833cc32d..6aa407bf80 100644 --- a/courseware/module_render.py +++ b/courseware/module_render.py @@ -17,7 +17,7 @@ from django.http import HttpResponse from django.shortcuts import redirect from django.template import Context from django.template import Context, loader -from djangomako.shortcuts import render_to_response, render_to_string +from mitxmako.shortcuts import render_to_response, render_to_string from auth.models import UserProfile from models import StudentModule diff --git a/courseware/modules/capa_module.py b/courseware/modules/capa_module.py index 8eeeec1f3c..b6c7f1748c 100644 --- a/courseware/modules/capa_module.py +++ b/courseware/modules/capa_module.py @@ -16,7 +16,7 @@ from lxml import etree ## TODO: Abstract out from Django from django.conf import settings -from djangomako.shortcuts import render_to_response, render_to_string +from mitxmako.shortcuts import render_to_response, render_to_string from django.http import Http404 from x_module import XModule diff --git a/courseware/modules/html_module.py b/courseware/modules/html_module.py index 61c903d41c..e72fea9dfd 100644 --- a/courseware/modules/html_module.py +++ b/courseware/modules/html_module.py @@ -2,7 +2,7 @@ import json ## TODO: Abstract out from Django from django.conf import settings -from djangomako.shortcuts import render_to_response, render_to_string +from mitxmako.shortcuts import render_to_response, render_to_string from x_module import XModule from lxml import etree diff --git a/courseware/modules/schematic_module.py b/courseware/modules/schematic_module.py index 9c7d291b92..0312321b4d 100644 --- a/courseware/modules/schematic_module.py +++ b/courseware/modules/schematic_module.py @@ -2,7 +2,7 @@ import json ## TODO: Abstract out from Django from django.conf import settings -from djangomako.shortcuts import render_to_response, render_to_string +from mitxmako.shortcuts import render_to_response, render_to_string from x_module import XModule diff --git a/courseware/modules/seq_module.py b/courseware/modules/seq_module.py index 2a91b0caa0..02c8320ac8 100644 --- a/courseware/modules/seq_module.py +++ b/courseware/modules/seq_module.py @@ -5,7 +5,7 @@ from lxml import etree ## TODO: Abstract out from Django from django.http import Http404 from django.conf import settings -from djangomako.shortcuts import render_to_response, render_to_string +from mitxmako.shortcuts import render_to_response, render_to_string from x_module import XModule diff --git a/courseware/modules/vertical_module.py b/courseware/modules/vertical_module.py index 5530e22415..6939c75cc9 100644 --- a/courseware/modules/vertical_module.py +++ b/courseware/modules/vertical_module.py @@ -2,7 +2,7 @@ import json ## TODO: Abstract out from Django from django.conf import settings -from djangomako.shortcuts import render_to_response, render_to_string +from mitxmako.shortcuts import render_to_response, render_to_string from x_module import XModule from lxml import etree diff --git a/courseware/modules/video_module.py b/courseware/modules/video_module.py index 69a0837403..4225f36880 100644 --- a/courseware/modules/video_module.py +++ b/courseware/modules/video_module.py @@ -5,7 +5,7 @@ from lxml import etree ## TODO: Abstract out from Django from django.conf import settings -from djangomako.shortcuts import render_to_response, render_to_string +from mitxmako.shortcuts import render_to_response, render_to_string from x_module import XModule diff --git a/courseware/views.py b/courseware/views.py index 9254da1e1e..f7035975df 100644 --- a/courseware/views.py +++ b/courseware/views.py @@ -12,7 +12,7 @@ from django.contrib.auth.models import User from django.http import HttpResponse, Http404 from django.shortcuts import redirect from django.template import Context, loader -from djangomako.shortcuts import render_to_response, render_to_string +from mitxmako.shortcuts import render_to_response, render_to_string from django.db import connection from lxml import etree diff --git a/settings_new_askbot.py b/settings_new_askbot.py index aa79e08ea8..eb168dabd2 100644 --- a/settings_new_askbot.py +++ b/settings_new_askbot.py @@ -3,6 +3,9 @@ import sys import djcelery +LIB_URL = '/static/lib/' +BOOK_URL = '/static/book/' + # Our parent dir (mitx_all) is the BASE_DIR BASE_DIR = os.path.abspath(os.path.join(__file__, "..", "..")) @@ -85,7 +88,7 @@ MIDDLEWARE_CLASSES = ( 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'track.middleware.TrackMiddleware', - 'djangomako.middleware.MakoMiddleware', + 'mitxmako.middleware.MakoMiddleware', #'debug_toolbar.middleware.DebugToolbarMiddleware', ) diff --git a/settings_old_askbot.py b/settings_old_askbot.py index d7783c05db..b711440d65 100644 --- a/settings_old_askbot.py +++ b/settings_old_askbot.py @@ -81,7 +81,7 @@ MIDDLEWARE_CLASSES = ( 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'track.middleware.TrackMiddleware', - 'djangomako.middleware.MakoMiddleware', + 'mitxmako.middleware.MakoMiddleware', #'debug_toolbar.middleware.DebugToolbarMiddleware', ) diff --git a/simplewiki/mdx_circuit.py b/simplewiki/mdx_circuit.py index efac721b7c..465e7d9a3a 100755 --- a/simplewiki/mdx_circuit.py +++ b/simplewiki/mdx_circuit.py @@ -8,7 +8,7 @@ circuit:name becomes the circuit. import simplewiki.settings as settings -from djangomako.shortcuts import render_to_response, render_to_string +from mitxmako.shortcuts import render_to_response, render_to_string import markdown try: diff --git a/simplewiki/views.py b/simplewiki/views.py index 16bfc11c44..856a45d1c0 100644 --- a/simplewiki/views.py +++ b/simplewiki/views.py @@ -15,10 +15,10 @@ from django.template import Context from django.template import RequestContext, Context, loader from django.utils import simplejson from django.utils.translation import ugettext_lazy as _ -from djangomako.shortcuts import render_to_response, render_to_string +from mitxmako.shortcuts import render_to_response, render_to_string from mako.lookup import TemplateLookup from mako.template import Template -import djangomako.middleware +import mitxmako.middleware from models import * # TODO: Clean up from settings import * diff --git a/static_template_view/views.py b/static_template_view/views.py index 5579e20c86..734434b43a 100644 --- a/static_template_view/views.py +++ b/static_template_view/views.py @@ -3,7 +3,7 @@ # List of valid templates is explicitly managed for (short-term) # security reasons. -from djangomako.shortcuts import render_to_response, render_to_string +from mitxmako.shortcuts import render_to_response, render_to_string from django.shortcuts import redirect from django.core.context_processors import csrf diff --git a/staticbook/views.py b/staticbook/views.py index bb6e2ada19..2e5712fc67 100644 --- a/staticbook/views.py +++ b/staticbook/views.py @@ -4,7 +4,7 @@ import os from django.conf import settings from django.http import Http404 from django.shortcuts import redirect -from djangomako.shortcuts import render_to_response, render_to_string +from mitxmako.shortcuts import render_to_response, render_to_string def index(request, page=0): if not request.user.is_authenticated(): diff --git a/util/views.py b/util/views.py index 139906e24a..5f0400d143 100644 --- a/util/views.py +++ b/util/views.py @@ -10,7 +10,7 @@ from django.core.mail import send_mail from django.http import Http404 from django.http import HttpResponse from django.shortcuts import redirect -from djangomako.shortcuts import render_to_response, render_to_string +from mitxmako.shortcuts import render_to_response, render_to_string import courseware.capa.calc import track.views From c99bc566ba02bf7e68229046e0d7499f60da4dc2 Mon Sep 17 00:00:00 2001 From: Piotr Mitros Date: Sun, 29 Jan 2012 13:40:52 -0500 Subject: [PATCH 17/25] Forked django-mako into our project. --- mitxmako/README | 15 +++++++++++++++ mitxmako/__init__.py | 16 ++++++++++++++++ mitxmako/middleware.py | 41 +++++++++++++++++++++++++++++++++++++++++ mitxmako/shortcuts.py | 37 +++++++++++++++++++++++++++++++++++++ mitxmako/template.py | 28 ++++++++++++++++++++++++++++ 5 files changed, 137 insertions(+) create mode 100644 mitxmako/README create mode 100644 mitxmako/__init__.py create mode 100644 mitxmako/middleware.py create mode 100644 mitxmako/shortcuts.py create mode 100644 mitxmako/template.py diff --git a/mitxmako/README b/mitxmako/README new file mode 100644 index 0000000000..ab04df2cf7 --- /dev/null +++ b/mitxmako/README @@ -0,0 +1,15 @@ +================================================================================ +django-mako +================================================================================ +This module provides a drop in replacement of Django templates for Mako +Templates. + +Django: http://www.djangoproject.com/ +Mako: http://www.makotemplates.org/ + +================================================================================ +How to install? +================================================================================ + + $ sudo python setup.py install + diff --git a/mitxmako/__init__.py b/mitxmako/__init__.py new file mode 100644 index 0000000000..aa8a48bfe7 --- /dev/null +++ b/mitxmako/__init__.py @@ -0,0 +1,16 @@ +# Copyright (c) 2008 Mikeal Rogers +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +lookup = None + diff --git a/mitxmako/middleware.py b/mitxmako/middleware.py new file mode 100644 index 0000000000..01990fa93a --- /dev/null +++ b/mitxmako/middleware.py @@ -0,0 +1,41 @@ +# Copyright (c) 2008 Mikeal Rogers +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from mako.lookup import TemplateLookup +import tempfile + +class MakoMiddleware(object): + def __init__(self): + """Setup mako variables and lookup object""" + from django.conf import settings + # Set all mako variables based on django settings + global template_dirs, output_encoding, module_directory, encoding_errors + directories = getattr(settings, 'MAKO_TEMPLATE_DIRS', settings.TEMPLATE_DIRS) + + module_directory = getattr(settings, 'MAKO_MODULE_DIR', None) + if module_directory is None: + module_directory = tempfile.mkdtemp() + + output_encoding = getattr(settings, 'MAKO_OUTPUT_ENCODING', 'utf-8') + encoding_errors = getattr(settings, 'MAKO_ENCODING_ERRORS', 'replace') + + global lookup + lookup = TemplateLookup(directories=directories, + module_directory=module_directory, + output_encoding=output_encoding, + encoding_errors=encoding_errors, + ) + import mitxmako + mitxmako.lookup = lookup + diff --git a/mitxmako/shortcuts.py b/mitxmako/shortcuts.py new file mode 100644 index 0000000000..946832cfaf --- /dev/null +++ b/mitxmako/shortcuts.py @@ -0,0 +1,37 @@ +# Copyright (c) 2008 Mikeal Rogers +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from django.template import Context +from django.http import HttpResponse + +import middleware + +def render_to_string(template_name, dictionary, context_instance=None): + context_instance = context_instance or Context(dictionary) + # add dictionary to context_instance + context_instance.update(dictionary or {}) + # collapse context_instance to a single dictionary for mako + context_dictionary = {} + for d in context_instance: + context_dictionary.update(d) + # fetch and render template + template = middleware.lookup.get_template(template_name) + return template.render(**context_dictionary) + +def render_to_response(template_name, dictionary, context_instance=None, **kwargs): + """ + Returns a HttpResponse whose content is filled with the result of calling + lookup.get_template(args[0]).render with the passed arguments. + """ + return HttpResponse(render_to_string(template_name, dictionary, context_instance), **kwargs) diff --git a/mitxmako/template.py b/mitxmako/template.py new file mode 100644 index 0000000000..9e5897ef25 --- /dev/null +++ b/mitxmako/template.py @@ -0,0 +1,28 @@ +# Copyright (c) 2008 Mikeal Rogers +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from mako.template import Template as MakoTemplate + +import middleware + +django_variables = ['lookup', 'template_dirs', 'output_encoding', + 'module_directory', 'encoding_errors',] + +class Template(MakoTemplate): + def __init__(self, *args, **kwargs): + """Overrides base __init__ to provide django variable overrides""" + if not kwargs.get('no_django', False): + overrides = dict([(k, getattr(middleware, k, None),) for k in django_variables]) + kwargs.update(overrides) + super(Template, self).__init__(*args, **kwargs) From 859afccd276162055117eb1f6d186181ed37c36e Mon Sep 17 00:00:00 2001 From: fischerl Date: Sun, 29 Jan 2012 17:14:43 -0500 Subject: [PATCH 18/25] added handi book indexing url and view --- settings_new_askbot.py | 5 ++++- staticbook/views.py | 3 +++ urls.py | 1 + 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/settings_new_askbot.py b/settings_new_askbot.py index aa79e08ea8..b81832f037 100644 --- a/settings_new_askbot.py +++ b/settings_new_askbot.py @@ -8,7 +8,9 @@ BASE_DIR = os.path.abspath(os.path.join(__file__, "..", "..")) COURSEWARE_ENABLED = True ASKBOT_ENABLED = True - +ASKBOT_FILE_UPLOAD_DIR = "" +ASKBOT_FILE_UPLOAD_DIR = "" +ASKBOT_UPLOADED_FILES_URL = "" CSRF_COOKIE_DOMAIN = '127.0.0.1' # Defaults to be overridden @@ -86,6 +88,7 @@ MIDDLEWARE_CLASSES = ( 'django.contrib.messages.middleware.MessageMiddleware', 'track.middleware.TrackMiddleware', 'djangomako.middleware.MakoMiddleware', + 'askbot.middleware.pagesize.QuestionsPageSizeMiddleware', #'debug_toolbar.middleware.DebugToolbarMiddleware', ) diff --git a/staticbook/views.py b/staticbook/views.py index bb6e2ada19..23ca0756c3 100644 --- a/staticbook/views.py +++ b/staticbook/views.py @@ -10,3 +10,6 @@ def index(request, page=0): if not request.user.is_authenticated(): return redirect('/') return render_to_response('staticbook.html',{'page':int(page)}) + +def index_shifted(request, page): + return index(request, int(page)+24) diff --git a/urls.py b/urls.py index 54c910dccf..68d789b5ff 100644 --- a/urls.py +++ b/urls.py @@ -44,6 +44,7 @@ if settings.COURSEWARE_ENABLED: url(r'^change_setting$', 'auth.views.change_setting'), url(r'^s/(?P