Commit 051afcca by Rocky Duan

Merge branch 'ccp0101/performance' of github.com:dementrock/mitx

parents 1a92cc5c d56ac9a7
...@@ -14,6 +14,7 @@ from datehelper import time_ago_in_words ...@@ -14,6 +14,7 @@ from datehelper import time_ago_in_words
import django_comment_client.utils as utils import django_comment_client.utils as utils
from urllib import urlencode from urllib import urlencode
from django_comment_client.permissions import check_permissions_by_view
import json import json
import comment_client as cc import comment_client as cc
...@@ -159,6 +160,26 @@ def forum_form_discussion(request, course_id): ...@@ -159,6 +160,26 @@ def forum_form_discussion(request, course_id):
} }
return render_to_response('discussion/index.html', context) return render_to_response('discussion/index.html', context)
def get_annotated_content_info(course_id, content, user, is_thread):
permissions = {
'editable': check_permissions_by_view(user, course_id, content, "update_thread" if is_thread else "update_comment"),
'can_reply': check_permissions_by_view(user, course_id, content, "create_comment" if is_thread else "create_sub_comment"),
'can_endorse': check_permissions_by_view(user, course_id, content, "endorse_comment") if not is_thread else False,
'can_delete': check_permissions_by_view(user, course_id, content, "delete_thread" if is_thread else "delete_comment"),
'can_openclose': check_permissions_by_view(user, course_id, content, "openclose_thread") if is_thread else False,
'can_vote': check_permissions_by_view(user, course_id, content, "vote_for_thread" if is_thread else "vote_for_comment"),
}
return permissions
def get_annotated_content_infos(course_id, thread, user, is_thread=True):
infos = {}
def _annotate(content, is_thread=is_thread):
infos[str(content['id'])] = get_annotated_content_info(course_id, content, user, is_thread)
for child in content.get('children', []):
_annotate(child, is_thread=False)
_annotate(thread)
return infos
def render_single_thread(request, discussion_id, course_id, thread_id): def render_single_thread(request, discussion_id, course_id, thread_id):
thread = cc.Thread.find(thread_id).retrieve(recursive=True) thread = cc.Thread.find(thread_id).retrieve(recursive=True)
......
...@@ -5,6 +5,7 @@ from django.dispatch import receiver ...@@ -5,6 +5,7 @@ from django.dispatch import receiver
from student.models import CourseEnrollment from student.models import CourseEnrollment
import logging import logging
from util.cache import cache
@receiver(post_save, sender=CourseEnrollment) @receiver(post_save, sender=CourseEnrollment)
...@@ -17,9 +18,20 @@ def assign_default_role(sender, instance, **kwargs): ...@@ -17,9 +18,20 @@ def assign_default_role(sender, instance, **kwargs):
logging.info("assign_default_role: adding %s as %s" % (instance.user, role)) logging.info("assign_default_role: adding %s as %s" % (instance.user, role))
instance.user.roles.add(role) instance.user.roles.add(role)
def cached_has_permission(user, permission, course_id=None):
"""
Call has_permission if it's not cached. A change in a user's role or
a role's permissions will only become effective after CACHE_LIFESPAN seconds.
"""
CACHE_LIFESPAN = 60
key = "permission_%d_%s_%s" % (user.id, str(course_id), permission)
val = cache.get(key, None)
if val not in [True, False]:
val = has_permission(user, permission, course_id=course_id)
cache.set(key, val, CACHE_LIFESPAN)
return val
def has_permission(user, permission, course_id=None): def has_permission(user, permission, course_id=None):
# if user.permissions.filter(name=permission).exists():
# return True
for role in user.roles.filter(course_id=course_id): for role in user.roles.filter(course_id=course_id):
if role.has_permission(permission): if role.has_permission(permission):
return True return True
...@@ -60,7 +72,7 @@ def check_conditions_permissions(user, permissions, course_id, **kwargs): ...@@ -60,7 +72,7 @@ def check_conditions_permissions(user, permissions, course_id, **kwargs):
if isinstance(per, basestring): if isinstance(per, basestring):
if per in CONDITIONS: if per in CONDITIONS:
return check_condition(user, per, course_id, kwargs) return check_condition(user, per, course_id, kwargs)
return has_permission(user, per, course_id=course_id) return cached_has_permission(user, per, course_id=course_id)
elif isinstance(per, list) and operator in ["and", "or"]: elif isinstance(per, list) and operator in ["and", "or"]:
results = [test(user, x, operator="and") for x in per] results = [test(user, x, operator="and") for x in per]
if operator == "or": if operator == "or":
......
...@@ -5,7 +5,8 @@ from xmodule.modulestore import Location ...@@ -5,7 +5,8 @@ from xmodule.modulestore import Location
from xmodule.modulestore.django import modulestore from xmodule.modulestore.django import modulestore
from django.http import HttpResponse from django.http import HttpResponse
from django.utils import simplejson from django.utils import simplejson
from django.db import connection
import logging
from django.conf import settings from django.conf import settings
import operator import operator
import itertools import itertools
...@@ -128,6 +129,31 @@ class ViewNameMiddleware(object): ...@@ -128,6 +129,31 @@ class ViewNameMiddleware(object):
def process_view(self, request, view_func, view_args, view_kwargs): def process_view(self, request, view_func, view_args, view_kwargs):
request.view_name = view_func.__name__ request.view_name = view_func.__name__
class QueryCountDebugMiddleware(object):
"""
This middleware will log the number of queries run
and the total time taken for each request (with a
status code of 200). It does not currently support
multi-db setups.
"""
def process_response(self, request, response):
if response.status_code == 200:
total_time = 0
for query in connection.queries:
query_time = query.get('time')
if query_time is None:
# django-debug-toolbar monkeypatches the connection
# cursor wrapper and adds extra information in each
# item in connection.queries. The query time is stored
# under the key "duration" rather than "time" and is
# in milliseconds, not seconds.
query_time = query.get('duration', 0) / 1000
total_time += float(query_time)
logging.info('%s queries run, total %s seconds' % (len(connection.queries), total_time))
return response
def get_annotated_content_info(course_id, content, user, type): def get_annotated_content_info(course_id, content, user, type):
return { return {
'editable': check_permissions_by_view(user, course_id, content, "update_thread" if type == 'thread' else "update_comment"), 'editable': check_permissions_by_view(user, course_id, content, "update_thread" if type == 'thread' else "update_comment"),
......
...@@ -329,6 +329,7 @@ MIDDLEWARE_CLASSES = ( ...@@ -329,6 +329,7 @@ MIDDLEWARE_CLASSES = (
# 'debug_toolbar.middleware.DebugToolbarMiddleware', # 'debug_toolbar.middleware.DebugToolbarMiddleware',
'django_comment_client.utils.ViewNameMiddleware', 'django_comment_client.utils.ViewNameMiddleware',
'django_comment_client.utils.QueryCountDebugMiddleware',
) )
############################### Pipeline ####################################### ############################### Pipeline #######################################
......
...@@ -402,3 +402,5 @@ initializeFollowThread = (thread) -> ...@@ -402,3 +402,5 @@ initializeFollowThread = (thread) ->
$local(".admin-delete").remove() $local(".admin-delete").remove()
if not Discussion.getContentInfo id, 'can_openclose' if not Discussion.getContentInfo id, 'can_openclose'
$local(".discussion-openclose").remove() $local(".discussion-openclose").remove()
if not Discussion.getContentInfo id, 'can_vote'
$local(".discussion-vote").css "visibility", "hidden"
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment