Commit 71089853 by Arjun Singh

Adding context to posts in the forum view.

parent a27ba692
...@@ -13,7 +13,7 @@ from courseware.access import has_access ...@@ -13,7 +13,7 @@ from courseware.access import has_access
from urllib import urlencode from urllib import urlencode
from operator import methodcaller from operator import methodcaller
from django_comment_client.permissions import check_permissions_by_view from django_comment_client.permissions import check_permissions_by_view
from django_comment_client.utils import merge_dict, extract, strip_none, strip_blank from django_comment_client.utils import merge_dict, extract, strip_none, strip_blank, get_courseware_context
import json import json
import django_comment_client.utils as utils import django_comment_client.utils as utils
...@@ -99,6 +99,8 @@ def render_user_discussion(*args, **kwargs): ...@@ -99,6 +99,8 @@ def render_user_discussion(*args, **kwargs):
def get_threads(request, course_id, discussion_id=None): def get_threads(request, course_id, discussion_id=None):
course = get_course_with_access(request.user, course_id, 'load')
default_query_params = { default_query_params = {
'page': 1, 'page': 1,
'per_page': THREADS_PER_PAGE, 'per_page': THREADS_PER_PAGE,
...@@ -115,6 +117,13 @@ def get_threads(request, course_id, discussion_id=None): ...@@ -115,6 +117,13 @@ def get_threads(request, course_id, discussion_id=None):
threads, page, num_pages = cc.Thread.search(query_params) threads, page, num_pages = cc.Thread.search(query_params)
for thread in threads:
courseware_context = get_courseware_context(thread, course)
if courseware_context:
thread['courseware_location'] = courseware_context['courseware_location']
thread['courseware_title'] = courseware_context['courseware_title']
query_params['page'] = page query_params['page'] = page
query_params['num_pages'] = num_pages query_params['num_pages'] = num_pages
......
from collections import defaultdict
from importlib import import_module from importlib import import_module
from courseware.models import StudentModuleCache from courseware.models import StudentModuleCache
from courseware.module_render import get_module from courseware.module_render import get_module
...@@ -40,80 +41,92 @@ def merge_dict(dic1, dic2): ...@@ -40,80 +41,92 @@ def merge_dict(dic1, dic2):
def get_full_modules(): def get_full_modules():
global _FULLMODULES global _FULLMODULES
if not _FULLMODULES: if not _FULLMODULES:
class_path = settings.MODULESTORE['default']['ENGINE'] _FULLMODULES = modulestore().modules
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 return _FULLMODULES
def get_categorized_discussion_info(request, course): def get_discussion_id_map(course):
""" """
return a dict of the form {category: modules} return a dict of the form {category: modules}
""" """
global _DISCUSSIONINFO global _DISCUSSIONINFO
if not _DISCUSSIONINFO: if not _DISCUSSIONINFO:
initialize_discussion_info(request, course) initialize_discussion_info(course)
return _DISCUSSIONINFO['categorized'] return _DISCUSSIONINFO['id_map']
def get_discussion_title(request, course, discussion_id): def get_discussion_title(request, course, discussion_id):
global _DISCUSSIONINFO global _DISCUSSIONINFO
if not _DISCUSSIONINFO: if not _DISCUSSIONINFO:
initialize_discussion_info(request, course) initialize_discussion_info(course)
title = _DISCUSSIONINFO['by_id'].get(discussion_id, {}).get('title', '(no title)') title = _DISCUSSIONINFO['id_map'].get(discussion_id, {}).get('title', '(no title)')
return title return title
def initialize_discussion_info(request, course): def get_discussion_category_map(course):
global _DISCUSSIONINFO
if not _DISCUSSIONINFO:
initialize_discussion_info(course)
return _DISCUSSIONINFO['category_map']
def initialize_discussion_info(course):
global _DISCUSSIONINFO global _DISCUSSIONINFO
if _DISCUSSIONINFO: if _DISCUSSIONINFO:
return return
course_id = course.id course_id = course.id
_, course_name, _ = course_id.split('/')
user = request.user
url_course_id = course_id.replace('/', '_').replace('.', '_') url_course_id = course_id.replace('/', '_').replace('.', '_')
_is_course_discussion = lambda x: x[0].dict()['category'] == 'discussion' \ all_modules = get_full_modules()[course_id]
and x[0].dict()['course'] == course_name
discussion_id_map = {}
_get_module_descriptor = operator.itemgetter(1) unexpanded_category_map = defaultdict(list)
for location, module in all_modules.items():
def _get_module(module_descriptor): if location.category == 'discussion':
print module_descriptor id = module.metadata['id']
module = get_module(user, request, module_descriptor.location, student_module_cache) category = module.metadata['discussion_category']
return module title = module.metadata['for']
sort_key = module.metadata.get('sort_key', title)
def _extract_info(module): discussion_id_map[id] = {"location": location, "title": title}
return { category = " / ".join([x.strip() for x in category.split("/")])
'title': module.title, unexpanded_category_map[category].append({"title": title, "id": id,
'discussion_id': module.discussion_id, "sort_key": sort_key})
'category': module.discussion_category,
} category_map = {"entries": defaultdict(dict), "subcategories": defaultdict(dict)}
for category_path, entries in unexpanded_category_map.items():
def _pack_with_id(info): node = category_map["subcategories"]
return (info['discussion_id'], info) path = [x.strip() for x in category_path.split("/")]
for level in path[:-1]:
discussion_module_descriptors = map(_get_module_descriptor, if level not in node:
filter(_is_course_discussion, node[level] = {"subcategories": defaultdict(dict),
get_full_modules().items())) "entries": defaultdict(dict),
"sort_key": level}
student_module_cache = StudentModuleCache.cache_for_descriptor_descendents(user, course) node = node[level]["subcategories"]
discussion_info = map(_extract_info, map(_get_module, discussion_module_descriptors)) level = path[-1]
if level not in node:
node[level] = {"subcategories": defaultdict(dict),
"entries": defaultdict(dict),
"sort_key": level}
for entry in entries:
node[level]["entries"][entry["title"]] = {"id": entry["id"],
"sort_key": entry["sort_key"]}
def sort_map_entries(map):
things = []
for title, entry in map["entries"].items():
things.append((title, entry))
for title, category in map["subcategories"].items():
things.append((title, category))
sort_map_entries(map["subcategories"][title])
map["children"] = [x[0] for x in sorted(things, key=lambda x: x[1]["sort_key"])]
sort_map_entries(category_map)
_DISCUSSIONINFO = {} _DISCUSSIONINFO = {}
_DISCUSSIONINFO['by_id'] = dict(map(_pack_with_id, discussion_info)) _DISCUSSIONINFO['id_map'] = discussion_id_map
_DISCUSSIONINFO['categorized'] = dict((category, list(l)) \
for category, l in itertools.groupby(discussion_info, operator.itemgetter('category')))
_DISCUSSIONINFO['categorized']['General'] = [{ _DISCUSSIONINFO['category_map'] = category_map
'title': 'General discussion',
'discussion_id': url_course_id,
'category': 'General',
}]
class JsonResponse(HttpResponse): class JsonResponse(HttpResponse):
def __init__(self, data=None): def __init__(self, data=None):
...@@ -220,6 +233,17 @@ def extend_content(content): ...@@ -220,6 +233,17 @@ def extend_content(content):
} }
return merge_dict(content, content_info) return merge_dict(content, content_info)
def get_courseware_context(content, course):
id_map = get_discussion_id_map(course)
id = content['commentable_id']
content_info = None
if id in id_map:
location = id_map[id]["location"].url()
title = id_map[id]["title"]
content_info = { "courseware_location": location, "courseware_title": title}
return content_info
def safe_content(content): def safe_content(content):
fields = [ fields = [
'id', 'title', 'body', 'course_id', 'anonymous', 'endorsed', 'id', 'title', 'body', 'course_id', 'anonymous', 'endorsed',
......
...@@ -342,6 +342,11 @@ $tag-text-color: #5b614f; ...@@ -342,6 +342,11 @@ $tag-text-color: #5b614f;
display: inline-block; display: inline-block;
} }
.context{
margin-top: 1em;
font-size: $comment-font-size;
}
.info { .info {
@include discussion-font; @include discussion-font;
color: gray; color: gray;
......
...@@ -27,6 +27,11 @@ ...@@ -27,6 +27,11 @@
{{/content.tags}} {{/content.tags}}
</div> </div>
{{/thread}} {{/thread}}
<div class="context">
{{#content.courseware_location}}
(this post is about <a href="../../jump_to/{{content.courseware_location}}">{{content.courseware_title}}</a>)
{{/content.courseware_location}}
</div>
<div class="info"> <div class="info">
<div class="comment-time"> <div class="comment-time">
<span class="timeago" title="{{content.updated_at}}">sometime</span> by <span class="timeago" title="{{content.updated_at}}">sometime</span> by
......
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