From f6efa99f6c17cab1cf3bfb4b73eec440f4c12041 Mon Sep 17 00:00:00 2001 From: Rocky Duan Date: Tue, 18 Sep 2012 00:33:16 -0700 Subject: [PATCH] unread count tracking --- .../django_comment_client/forum/views.py | 32 ++++++++++++++++--- lms/djangoapps/django_comment_client/utils.py | 3 +- lms/lib/comment_client/models.py | 4 +-- lms/lib/comment_client/thread.py | 5 +-- lms/lib/comment_client/user.py | 11 +++++++ .../src/discussion/discussion_router.coffee | 2 ++ .../views/discussion_thread_list_view.coffee | 2 ++ lms/static/sass/_discussion.scss | 5 +++ .../discussion/_underscore_templates.html | 2 +- 9 files changed, 55 insertions(+), 11 deletions(-) diff --git a/lms/djangoapps/django_comment_client/forum/views.py b/lms/djangoapps/django_comment_client/forum/views.py index 0abcbf5fbb..7a80de194b 100644 --- a/lms/djangoapps/django_comment_client/forum/views.py +++ b/lms/djangoapps/django_comment_client/forum/views.py @@ -21,6 +21,8 @@ from django_comment_client.utils import merge_dict, extract, strip_none, strip_b import django_comment_client.utils as utils import comment_client as cc import xml.sax.saxutils as saxutils +import datetime +from django.utils.timezone import utc THREADS_PER_PAGE = 20 INLINE_THREADS_PER_PAGE = 20 @@ -43,6 +45,7 @@ def get_threads(request, course_id, discussion_id=None, per_page=THREADS_PER_PAG 'tags': '', 'commentable_id': discussion_id, 'course_id': course_id, + 'user_id': request.user.id, } if not request.GET.get('sort_key'): @@ -166,12 +169,21 @@ def single_thread(request, course_id, discussion_id, thread_id): if request.is_ajax(): course = get_course_with_access(request.user, course_id, 'load') - user_info = cc.User.from_django_user(request.user).to_dict() + cc_user = cc.User.from_django_user(request.user) + user_info = cc_user.to_dict() try: - thread = cc.Thread.find(thread_id).retrieve(recursive=True) + last_read_time = datetime.datetime.utcnow().replace(tzinfo=utc).strftime('%Y-%m-%dT%H:%M:%S%z') + cc_user.update_read_states(course_id, thread_id, last_read_time) + except (cc.utils.CommentClientError, cc.utils.CommentClientUnknownError) as err: + # TODO log error + pass + + try: + thread = cc.Thread.find(thread_id).retrieve(recursive=True, user_id=request.user.id) except (cc.utils.CommentClientError, cc.utils.CommentClientUnknownError) as err: raise Http404 + courseware_context = get_courseware_context(thread, course) annotated_content_info = utils.get_annotated_content_infos(course_id, thread, request.user, user_info=user_info) @@ -190,9 +202,20 @@ def single_thread(request, course_id, discussion_id, thread_id): else: course = get_course_with_access(request.user, course_id, 'load') category_map = utils.get_discussion_category_map(course) + + cc_user = cc.User.from_django_user(request.user) + user_info = cc_user.to_dict() + + try: + last_read_time = datetime.datetime.utcnow().replace(tzinfo=utc).strftime('%Y-%m-%dT%H:%M:%S%z') + cc_user.update_read_states(course_id, thread_id, last_read_time) + except (cc.utils.CommentClientError, cc.utils.CommentClientUnknownError) as err: + # TODO log error + pass + try: threads, query_params = get_threads(request, course_id) - thread = cc.Thread.find(thread_id).retrieve(recursive=True) + thread = cc.Thread.find(thread_id).retrieve(recursive=True, user_id=request.user.id) threads.append(thread.to_dict()) except (cc.utils.CommentClientError, cc.utils.CommentClientUnknownError) as err: raise Http404 @@ -216,8 +239,7 @@ def single_thread(request, course_id, discussion_id, thread_id): # course_id, #) - user_info = cc.User.from_django_user(request.user).to_dict() - + def infogetter(thread): return utils.get_annotated_content_infos(course_id, thread, request.user, user_info) diff --git a/lms/djangoapps/django_comment_client/utils.py b/lms/djangoapps/django_comment_client/utils.py index 476d5b0a6a..76a784a8dc 100644 --- a/lms/djangoapps/django_comment_client/utils.py +++ b/lms/djangoapps/django_comment_client/utils.py @@ -336,7 +336,8 @@ def safe_content(content): 'endorsed', 'parent_id', 'thread_id', 'votes', 'closed', 'created_at', 'updated_at', 'depth', 'type', 'commentable_id', 'comments_count', 'at_position_list', 'children', 'highlighted_title', 'highlighted_body', - 'courseware_title', 'courseware_url', 'tags' + 'courseware_title', 'courseware_url', 'tags', 'unread_comments_count', + 'viewed', ] if (content.get('anonymous') is False) and (content.get('anonymous_to_peers') is False): diff --git a/lms/lib/comment_client/models.py b/lms/lib/comment_client/models.py index 3ce3858d2d..3f1ad35cd7 100644 --- a/lms/lib/comment_client/models.py +++ b/lms/lib/comment_client/models.py @@ -72,8 +72,8 @@ class Model(object): for k, v in kwargs.items(): if k in self.accessible_fields: self.__setattr__(k, v) - else: - raise AttributeError("Field {0} does not exist".format(k)) + #else: + # raise AttributeError("Field {0} does not exist".format(k)) def updatable_attributes(self): return extract(self.attributes, self.updatable_fields) diff --git a/lms/lib/comment_client/thread.py b/lms/lib/comment_client/thread.py index bda032bbdf..2ae72f8fd7 100644 --- a/lms/lib/comment_client/thread.py +++ b/lms/lib/comment_client/thread.py @@ -9,7 +9,8 @@ class Thread(models.Model): 'id', 'title', 'body', 'anonymous', 'anonymous_to_peers', 'course_id', 'closed', 'tags', 'votes', 'commentable_id', 'username', 'user_id', 'created_at', 'updated_at', 'comments_count', 'at_position_list', - 'children', 'type', 'highlighted_title', 'highlighted_body', 'endorsed' + 'children', 'type', 'highlighted_title', 'highlighted_body', 'endorsed', + 'unread_comments_count', 'viewed', ] updatable_fields = [ @@ -61,5 +62,5 @@ class Thread(models.Model): def _retrieve(self, *args, **kwargs): url = self.url(action='get', params=self.attributes) - response = perform_request('get', url, {'recursive': kwargs.get('recursive')}) + response = perform_request('get', url, {'recursive': kwargs.get('recursive'), 'user_id': kwargs.get('user_id')}) self.update_attributes(**response) diff --git a/lms/lib/comment_client/user.py b/lms/lib/comment_client/user.py index 9813e9a199..91b570c10e 100644 --- a/lms/lib/comment_client/user.py +++ b/lms/lib/comment_client/user.py @@ -2,6 +2,7 @@ from utils import * import models import settings +import json class User(models.Model): @@ -73,6 +74,13 @@ class User(models.Model): response = perform_request('get', url, retrieve_params) self.update_attributes(**response) + def update_read_states(self, course_id, thread_id, last_read_time): + url = _url_for_read_states(self.id) + response = perform_request('put', url, { "course_id": course_id, + "thread_id": thread_id, + "last_read_time": last_read_time, + }) + def _url_for_vote_comment(comment_id): return "{prefix}/comments/{comment_id}/votes".format(prefix=settings.PREFIX, comment_id=comment_id) @@ -82,5 +90,8 @@ 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_read_states(user_id): + return "{prefix}/users/{user_id}/read_states".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/discussion_router.coffee b/lms/static/coffee/src/discussion/discussion_router.coffee index a5219a68b9..b02ffbf868 100644 --- a/lms/static/coffee/src/discussion/discussion_router.coffee +++ b/lms/static/coffee/src/discussion/discussion_router.coffee @@ -27,6 +27,8 @@ if Backbone? showThread: (forum_name, thread_id) -> @thread = @discussion.get(thread_id) + @thread.set("unread_comments_count", 0) + @thread.set("viewed", true) @setActiveThread() if(@main) @main.cleanup() diff --git a/lms/static/coffee/src/discussion/views/discussion_thread_list_view.coffee b/lms/static/coffee/src/discussion/views/discussion_thread_list_view.coffee index d998763f50..1028e6a8fb 100644 --- a/lms/static/coffee/src/discussion/views/discussion_thread_list_view.coffee +++ b/lms/static/coffee/src/discussion/views/discussion_thread_list_view.coffee @@ -130,6 +130,8 @@ if Backbone? content.addClass("followed") if thread.get('endorsed') content.addClass("resolved") + if thread.get('viewed') + content.addClass("viewed") @highlight(content) diff --git a/lms/static/sass/_discussion.scss b/lms/static/sass/_discussion.scss index 4c8476f301..42af55dacc 100644 --- a/lms/static/sass/_discussion.scss +++ b/lms/static/sass/_discussion.scss @@ -1018,6 +1018,7 @@ body.discussion { text-shadow: 0 -1px 0 rgba(0, 0, 0, .3); box-shadow: 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 1px rgba(0, 0, 0, .2) inset; } + } } @@ -1134,6 +1135,10 @@ body.discussion { background: url(../images/following-flag.png) no-repeat; } + &.viewed { + @include linear-gradient(top, white, #ddd); + } + &.active { @include linear-gradient(top, #96e0fd, #61c7fc); border-color: #4697c1; diff --git a/lms/templates/discussion/_underscore_templates.html b/lms/templates/discussion/_underscore_templates.html index 86e950d42e..7a9f8a9e9b 100644 --- a/lms/templates/discussion/_underscore_templates.html +++ b/lms/templates/discussion/_underscore_templates.html @@ -128,5 +128,5 @@