from importlib import import_module from courseware.models import StudentModuleCache from courseware.module_render import get_module from xmodule.modulestore import Location from xmodule.modulestore.django import modulestore from django.http import HttpResponse from django.utils import simplejson from django.db import connection from django.conf import settings from django_comment_client.permissions import check_permissions_by_view from mitxmako import middleware import logging import operator import itertools import pystache_custom as pystache _FULLMODULES = None _DISCUSSIONINFO = None def extract(dic, keys): return {k: dic.get(k) for k in keys} def strip_none(dic): return dict([(k, v) for k, v in dic.iteritems() if v is not None]) def strip_blank(dic): def _is_blank(v): return isinstance(v, str) and len(v.strip()) == 0 return dict([(k, v) for k, v in dic.iteritems() if not _is_blank(v)]) def merge_dict(dic1, dic2): return dict(dic1.items() + dic2.items()) def get_full_modules(): global _FULLMODULES if not _FULLMODULES: class_path = settings.MODULESTORE['default']['ENGINE'] module_path, _, class_name = class_path.rpartition('.') class_ = getattr(import_module(module_path), class_name) modulestore = class_(**dict(settings.MODULESTORE['default']['OPTIONS'].items() + [('eager', True)])) _FULLMODULES = modulestore.modules return _FULLMODULES def get_categorized_discussion_info(request, course): """ return a dict of the form {category: modules} """ global _DISCUSSIONINFO if not _DISCUSSIONINFO: initialize_discussion_info(request, course) return _DISCUSSIONINFO['categorized'] def get_discussion_title(request, course, discussion_id): global _DISCUSSIONINFO if not _DISCUSSIONINFO: initialize_discussion_info(request, course) title = _DISCUSSIONINFO['by_id'].get(discussion_id, {}).get('title', '(no title)') return title def initialize_discussion_info(request, course): global _DISCUSSIONINFO if _DISCUSSIONINFO: return course_id = course.id _, course_name, _ = course_id.split('/') user = request.user url_course_id = course_id.replace('/', '_').replace('.', '_') _is_course_discussion = lambda x: x[0].dict()['category'] == 'discussion' \ and x[0].dict()['course'] == course_name _get_module_descriptor = operator.itemgetter(1) def _get_module(module_descriptor): print module_descriptor module = get_module(user, request, module_descriptor.location, student_module_cache) return module def _extract_info(module): return { 'title': module.title, 'discussion_id': module.discussion_id, 'category': module.discussion_category, } def _pack_with_id(info): return (info['discussion_id'], info) discussion_module_descriptors = map(_get_module_descriptor, filter(_is_course_discussion, get_full_modules().items())) student_module_cache = StudentModuleCache.cache_for_descriptor_descendents(user, course) discussion_info = map(_extract_info, map(_get_module, discussion_module_descriptors)) _DISCUSSIONINFO = {} _DISCUSSIONINFO['by_id'] = dict(map(_pack_with_id, discussion_info)) _DISCUSSIONINFO['categorized'] = dict((category, list(l)) \ for category, l in itertools.groupby(discussion_info, operator.itemgetter('category'))) _DISCUSSIONINFO['categorized']['General'] = [{ 'title': 'General discussion', 'discussion_id': url_course_id, 'category': 'General', }] class JsonResponse(HttpResponse): def __init__(self, data=None): content = simplejson.dumps(data) super(JsonResponse, self).__init__(content, mimetype='application/json; charset=utf8') class JsonError(HttpResponse): def __init__(self, error_messages=[]): if isinstance(error_messages, str): error_messages = [error_messages] content = simplejson.dumps({'errors': error_messages}, indent=2, ensure_ascii=False) super(JsonError, self).__init__(content, mimetype='application/json; charset=utf8', status=400) class HtmlResponse(HttpResponse): def __init__(self, html=''): super(HtmlResponse, self).__init__(html, content_type='text/plain') class ViewNameMiddleware(object): def process_view(self, request, view_func, view_args, view_kwargs): 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): return { 'editable': check_permissions_by_view(user, course_id, content, "update_thread" if content['type'] == 'thread' else "update_comment"), 'can_reply': check_permissions_by_view(user, course_id, content, "create_comment" if content['type'] == 'thread' else "create_sub_comment"), 'can_endorse': check_permissions_by_view(user, course_id, content, "endorse_comment") if content['type'] == 'comment' else False, 'can_delete': check_permissions_by_view(user, course_id, content, "delete_thread" if content['type'] == 'thread' else "delete_comment"), 'can_openclose': check_permissions_by_view(user, course_id, content, "openclose_thread") if content['type'] == 'thread' else False, 'can_vote': check_permissions_by_view(user, course_id, content, "vote_for_thread" if content['type'] == 'thread' else "vote_for_comment"), } def get_annotated_content_infos(course_id, thread, user): infos = {} def _annotate(content): infos[str(content['id'])] = get_annotated_content_info(course_id, content, user) for child in content.get('children', []): _annotate(child) _annotate(thread) return infos def render_mustache(template_name, dictionary, *args, **kwargs): template = middleware.lookup['main'].get_template(template_name).source return pystache.render(template, dictionary)