diff --git a/lms/djangoapps/django_comment_client/base/views.py b/lms/djangoapps/django_comment_client/base/views.py index 038a6071d8..72f051c945 100644 --- a/lms/djangoapps/django_comment_client/base/views.py +++ b/lms/djangoapps/django_comment_client/base/views.py @@ -65,9 +65,9 @@ def create_thread(request, course_id, commentable_id): } html = render_to_string('discussion/ajax_create_thread.html', context) annotated_content_info = utils.get_annotated_content_info(course_id, - thread.to_dict(), - request.user, - 'thread') + thread.to_dict(), + request.user, + 'thread') return JsonResponse({ 'html': html, 'content': thread.to_dict(), diff --git a/lms/djangoapps/django_comment_client/forum/views.py b/lms/djangoapps/django_comment_client/forum/views.py index 6217de63e2..79f6aa3931 100644 --- a/lms/djangoapps/django_comment_client/forum/views.py +++ b/lms/djangoapps/django_comment_client/forum/views.py @@ -41,24 +41,35 @@ def render_accordion(request, course, discussion_id): return render_to_string('discussion/_accordion.html', context) -def render_discussion(request, course_id, threads, discussion_id=None, \ - discussion_type='inline', query_params={}): +def render_discussion(request, course_id, threads, *args, **kwargs): + + discussion_id = kwargs.get('discussion_id') + user_id = kwargs.get('user_id') + discussion_type = kwargs.get('discussion_type', 'inline') + query_params = kwargs.get('query_params', {}) template = { 'inline': 'discussion/_inline.html', 'forum': 'discussion/_forum.html', + 'user': 'discussion/_user_active_threads.html', }[discussion_type] base_url = { 'inline': (lambda: reverse('django_comment_client.forum.views.inline_discussion', args=[course_id, discussion_id])), 'forum': (lambda: reverse('django_comment_client.forum.views.forum_form_discussion', args=[course_id, discussion_id])), + 'user': (lambda: reverse('django_comment_client.forum.views.user_profile', args=[course_id, user_id])), }[discussion_type]() - annotated_content_info = {thread['id']: utils.get_annotated_content_info(course_id, thread, request.user, type='thread') for thread in threads} + print "start annotating" + annotated_content_infos = map(lambda x: utils.get_annotated_content_infos(course_id, x, request.user, type='thread'), threads) + print "start merging annotations" + annotated_content_info = reduce(utils.merge_dict, annotated_content_infos, {}) + print "finished annotating" context = { 'threads': threads, 'discussion_id': discussion_id, + 'user_id': user_id, 'user_info': json.dumps(cc.User.from_django_user(request.user).to_dict()), 'course_id': course_id, 'request': request, @@ -78,6 +89,9 @@ def render_inline_discussion(*args, **kwargs): def render_forum_discussion(*args, **kwargs): return render_discussion(discussion_type='forum', *args, **kwargs) +def render_user_discussion(*args, **kwargs): + return render_discussion(discussion_type='user', *args, **kwargs) + def get_threads(request, course_id, discussion_id): query_params = { 'page': request.GET.get('page', 1), @@ -150,7 +164,7 @@ def render_single_thread(request, discussion_id, course_id, thread_id): thread = cc.Thread.find(thread_id).retrieve(recursive=True) annotated_content_info = utils.get_annotated_content_infos(course_id, thread=thread.to_dict(), \ - user=request.user, type='thread') + user=request.user, type='thread') context = { 'discussion_id': discussion_id, @@ -194,14 +208,29 @@ def single_thread(request, course_id, discussion_id, thread_id): def user_profile(request, course_id, user_id): course = check_course(request.user, course_id) - discussion_user = cc.User(id=user_id, course_id=course_id) - context = { - 'course': course, - 'user': request.user, - 'django_user': User.objects.get(id=user_id), - 'discussion_user': discussion_user.to_dict(), + query_params = { + 'page': request.GET.get('page', 1), + 'per_page': THREADS_PER_PAGE, # more than threads_per_page to show more activities } - return render_to_response('discussion/user_profile.html', context) + threads, page, num_pages = discussion_user.active_threads(query_params) + + query_params['page'] = page + query_params['num_pages'] = num_pages + + content = render_user_discussion(request, course_id, threads, user_id=user_id, query_params=query_params) + + if request.is_ajax(): + return utils.HtmlResponse(content) + else: + context = { + 'course': course, + 'user': request.user, + 'django_user': User.objects.get(id=user_id), + 'discussion_user': discussion_user.to_dict(), + 'content': content, + } + + return render_to_response('discussion/user_profile.html', context) diff --git a/lms/djangoapps/django_comment_client/permissions.py b/lms/djangoapps/django_comment_client/permissions.py index ea8d4e9f24..9ca2b46af0 100644 --- a/lms/djangoapps/django_comment_client/permissions.py +++ b/lms/djangoapps/django_comment_client/permissions.py @@ -96,7 +96,6 @@ VIEW_PERMISSIONS = { def check_permissions_by_view(user, course_id, content, name): - # import pdb; pdb.set_trace() try: p = VIEW_PERMISSIONS[name] except KeyError: diff --git a/lms/djangoapps/django_comment_client/utils.py b/lms/djangoapps/django_comment_client/utils.py index 30c9042155..aac409435a 100644 --- a/lms/djangoapps/django_comment_client/utils.py +++ b/lms/djangoapps/django_comment_client/utils.py @@ -16,13 +16,16 @@ _FULLMODULES = None _DISCUSSIONINFO = None def extract(dic, keys): - return {k: dic[k] for k in keys} + return {k: dic.get(k) for k in keys} def strip_none(dic): def _is_none(v): return v is None or (isinstance(v, str) and len(v.strip()) == 0) return dict([(k, v) for k, v in dic.iteritems() if not _is_none(v)]) +def merge_dict(dic1, dic2): + return dict(dic1.items() + dic2.items()) + def get_full_modules(): global _FULLMODULES if not _FULLMODULES: diff --git a/lms/lib/comment_client/user.py b/lms/lib/comment_client/user.py index a73bdf6a6f..ae4abf91b7 100644 --- a/lms/lib/comment_client/user.py +++ b/lms/lib/comment_client/user.py @@ -55,6 +55,15 @@ class User(models.Model): request = perform_request('delete', url, params) voteable.update_attributes(request) + def active_threads(self, query_params={}): + if not self.course_id: + raise CommentClientError("Must provide course_id when retrieving active threads for the user") + url = _url_for_user_active_threads(self.id) + params = {'course_id': self.course_id} + params = merge_dict(params, query_params) + response = perform_request('get', url, params) + return response.get('collection', []), response.get('page', 1), response.get('num_pages', 1) + def _retrieve(self, *args, **kwargs): url = self.url(action='get', params=self.attributes) retrieve_params = self.default_retrieve_params @@ -71,3 +80,6 @@ def _url_for_vote_thread(thread_id): def _url_for_subscription(user_id): return "{prefix}/users/{user_id}/subscriptions".format(prefix=settings.PREFIX, user_id=user_id) + +def _url_for_user_active_threads(user_id): + return "{prefix}/users/{user_id}/active_threads".format(prefix=settings.PREFIX, user_id=user_id) diff --git a/lms/static/coffee/src/discussion/content.coffee b/lms/static/coffee/src/discussion/content.coffee index 2c01420007..448b092045 100644 --- a/lms/static/coffee/src/discussion/content.coffee +++ b/lms/static/coffee/src/discussion/content.coffee @@ -252,12 +252,14 @@ initializeFollowThread = (thread) -> handleHideSingleThread = (elem) -> $threadTitle = $local(".thread-title") - $showComments = $local(".discussion-show-comments") + $hideComments = $local(".discussion-hide-comments") + $hideComments.removeClass("discussion-hide-comments") + .addClass("discussion-show-comments") $content.children(".comments").hide() $threadTitle.unbind('click').click handleShowSingleThread - $showComments.unbind('click').click handleShowSingleThread - prevHtml = $showComments.html() - $showComments.html prevHtml.replace "Hide", "Show" + $hideComments.unbind('click').click handleShowSingleThread + prevHtml = $hideComments.html() + $hideComments.html prevHtml.replace "Hide", "Show" handleShowSingleThread = -> $threadTitle = $local(".thread-title") @@ -269,9 +271,12 @@ initializeFollowThread = (thread) -> rebindHideEvents = -> $threadTitle.unbind('click').click handleHideSingleThread $showComments.unbind('click').click handleHideSingleThread + $showComments.removeClass("discussion-show-comments") + .addClass("discussion-hide-comments") prevHtml = $showComments.html() $showComments.html prevHtml.replace "Show", "Hide" + if $content.children(".comments").length $content.children(".comments").show() rebindHideEvents() @@ -299,6 +304,9 @@ initializeFollowThread = (thread) -> "click .discussion-show-comments": -> handleShowSingleThread(this) + "click .discussion-hide-comments": -> + handleHideSingleThread(this) + "click .discussion-reply-thread": -> handleShowSingleThread($local(".thread-title")) handleReply(this) @@ -374,11 +382,12 @@ initializeFollowThread = (thread) -> MathJax.Hub.Queue ["Typeset", MathJax.Hub, $contentBody.attr("id")] id = $content.attr("_id") - discussion_id = $content.parents(".discussion").attr("_id") if $content.hasClass("thread") + discussion_id = $content.attr("_discussion_id") permalink = Discussion.urlFor("permanent_link_thread", discussion_id, id) else thread_id = $content.parents(".thread").attr("_id") + discussion_id = $content.parents(".thread").attr("_discussion_id") permalink = Discussion.urlFor("permanent_link_comment", discussion_id, thread_id, id) $local(".discussion-permanent-link").attr "href", permalink diff --git a/lms/static/coffee/src/discussion/discussion.coffee b/lms/static/coffee/src/discussion/discussion.coffee index 3d948286c2..b25ab35bf7 100644 --- a/lms/static/coffee/src/discussion/discussion.coffee +++ b/lms/static/coffee/src/discussion/discussion.coffee @@ -55,7 +55,7 @@ initializeFollowDiscussion = (discussion) -> handleCancelNewPost = (elem) -> if $discussion.hasClass("inline-discussion") $local(".new-post-form").addClass("collapsed") - else + else if $discussion.hasClass("forum-discussion") $local(".new-post-form").hide() handleSimilarPost = (elem) -> @@ -106,7 +106,7 @@ initializeFollowDiscussion = (discussion) -> if $discussion.hasClass("inline-discussion") $input.bind 'focus', (e) -> $local(".new-post-form").removeClass('collapsed') - else + else if $discussion.hasClass("forum-discussion") $local(".new-post-form").removeClass('collapsed') $local(".new-post-tags").tagsInput Discussion.tagsInputOptions() @@ -135,8 +135,9 @@ initializeFollowDiscussion = (discussion) -> dataType: 'html' success: (data, textStatus) -> $data = $(data) + $parent = $discussion.parent() $discussion.replaceWith($data) - $discussion = $(".discussion[_id='#{id}']") + $discussion = $parent.children(".discussion") Discussion.initializeDiscussion($discussion) Discussion.bindDiscussionEvents($discussion) @@ -158,12 +159,13 @@ initializeFollowDiscussion = (discussion) -> if $discussion.hasClass("inline-discussion") initializeNewPost() - $discussionSidebar = $(".discussion-sidebar") - if $discussionSidebar.length - $sidebarLocal = Discussion.generateLocal($discussionSidebar) - Discussion.bindLocalEvents $sidebarLocal, - "click .sidebar-new-post-button": (event) -> - initializeNewPost() + if $discussion.hasClass("forum-discussion") + $discussionSidebar = $(".discussion-sidebar") + if $discussionSidebar.length + $sidebarLocal = Discussion.generateLocal($discussionSidebar) + Discussion.bindLocalEvents $sidebarLocal, + "click .sidebar-new-post-button": (event) -> + initializeNewPost() Discussion.bindLocalEvents $local, diff --git a/lms/static/coffee/src/discussion/user_profile.coffee b/lms/static/coffee/src/discussion/user_profile.coffee index a431688f96..0cff708ae6 100644 --- a/lms/static/coffee/src/discussion/user_profile.coffee +++ b/lms/static/coffee/src/discussion/user_profile.coffee @@ -30,3 +30,5 @@ Discussion = @Discussion handleUpdateModeratorStatus(this, false) "click .sidebar-promote-moderator-button": (event) -> handleUpdateModeratorStatus(this, true) + + initializeUserActiveDiscussion: ($discussion) -> diff --git a/lms/static/sass/_discussion.scss b/lms/static/sass/_discussion.scss index 59609fd4ca..12ec834663 100644 --- a/lms/static/sass/_discussion.scss +++ b/lms/static/sass/_discussion.scss @@ -844,7 +844,7 @@ $tag-text-color: #5b614f; } } - &.inline-discussion, .forum-discussion { + &.inline-discussion, .forum-discussion, .user-discussion { .new-post-form { margin: 24px 60px; diff --git a/lms/templates/discussion/_thread.html b/lms/templates/discussion/_thread.html index 5326b10a02..a9a354225f 100644 --- a/lms/templates/discussion/_thread.html +++ b/lms/templates/discussion/_thread.html @@ -4,9 +4,16 @@ <%! from django_comment_client.utils import pluralize %> <%! import urllib %> +<%! + def user_id_with_anonymity(content): + if content.get('anonymous', False): + return '' + else: + return content['user_id'] +%> <%def name="render_thread(course_id, thread, show_comments=False)"> -
+
${render_content(thread, "thread", show_comments=show_comments)} % if show_comments: ${render_comments(thread.get('children', []))} @@ -16,9 +23,9 @@ <%def name="render_comment(comment)"> % if comment['endorsed']: -
+
% else: -
+
% endif ${render_content(comment, "comment")}
@@ -60,7 +67,7 @@ ${render_title(content, type, **kwargs)}
- + % if content.get('highlighted_body', None):
${content['highlighted_body'] | h}
% else: @@ -103,20 +110,16 @@ <%def name="render_bottom_bar(content, type, **kwargs)">
- ${render_info(content)} + ${render_info(content, type, **kwargs)}
  • ${render_link("discussion-link discussion-reply discussion-reply-" + type, "Reply")}
  • ${render_link("discussion-link discussion-permanent-link", "Permanent Link")}
- - - -
-<%def name="render_info(content)"> +<%def name="render_info(content, type, **kwargs)"> <% def url_for_user(user_id): return reverse('django_comment_client.forum.views.user_profile', args=[course_id, user_id]) @@ -131,7 +134,11 @@
diff --git a/lms/templates/discussion/_user_active_threads.html b/lms/templates/discussion/_user_active_threads.html new file mode 100644 index 0000000000..6a4de78fdc --- /dev/null +++ b/lms/templates/discussion/_user_active_threads.html @@ -0,0 +1,24 @@ +<%namespace name="renderer" file="_thread.html"/> +<%! from django.template.defaultfilters import escapejs %> + +
+ +
+ +
+ % for thread in threads: + ${renderer.render_thread(course_id, thread, show_comments=True)} + % endfor +
+ + <%include file="_paginator.html" /> +
+ + diff --git a/lms/templates/discussion/user_profile.html b/lms/templates/discussion/user_profile.html index 87b802e66a..3825879c3b 100644 --- a/lms/templates/discussion/user_profile.html +++ b/lms/templates/discussion/user_profile.html @@ -1,4 +1,5 @@ <%! from django.template.defaultfilters import escapejs %> +<%namespace name="renderer" file="_thread.html"/> <%inherit file="../main.html" /> <%namespace name='static' file='../static_content.html'/> @@ -28,7 +29,7 @@
- + ${content}