diff --git a/api/files/serializers.py b/api/files/serializers.py index e68845c4cd1..5bc43209ac6 100644 --- a/api/files/serializers.py +++ b/api/files/serializers.py @@ -244,7 +244,7 @@ class BaseFileSerializer(JSONAPISerializer): FileRelationshipField( related_view='nodes:node-comments', related_view_kwargs={'node_id': ''}, - related_meta={'unread': 'get_unread_comments_count'}, + related_meta={'unread': 'get_unread_comments_count', 'comment_count': 'get_comments_count'}, filter={'target': 'get_file_guid'}, ), ) @@ -337,6 +337,9 @@ def get_unread_comments_count(self, obj): return 0 return Comment.find_n_unread(user=user, node=obj.target, page='files', root_id=obj.get_guid()._id) + def get_comments_count(self, obj): + return Comment.find_count(node=obj.target, page='files', root_id=obj.get_guid()._id) + def user_id(self, obj): # NOTE: obj is the user here, the meta field for # Hyperlinks is weird diff --git a/api/nodes/serializers.py b/api/nodes/serializers.py index 473b439ffd5..778e6d81577 100644 --- a/api/nodes/serializers.py +++ b/api/nodes/serializers.py @@ -327,7 +327,7 @@ class NodeSerializer(TaxonomizableSerializerMixin, JSONAPISerializer): comments = RelationshipField( related_view='nodes:node-comments', related_view_kwargs={'node_id': '<_id>'}, - related_meta={'unread': 'get_unread_comments_count'}, + related_meta={'unread': 'get_unread_comments_count', 'comment_count': 'get_comments_count'}, filter={'target': '<_id>'}, ) @@ -724,6 +724,13 @@ def get_unread_comments_count(self, obj): 'node': node_comments, } + def get_comments_count(self, obj): + node_comment_count = Comment.find_count(node=obj, page='node') + + return { + 'node_comment_count': node_comment_count, + } + def get_region_id(self, obj): try: # use the annotated value if possible diff --git a/api/registrations/serializers.py b/api/registrations/serializers.py index 33ffb1bda18..a08f54f8cbd 100644 --- a/api/registrations/serializers.py +++ b/api/registrations/serializers.py @@ -223,6 +223,7 @@ class RegistrationSerializer(NodeSerializer): related_meta={ 'unread': 'get_unread_comments_count', 'count': 'get_total_comments_count', + 'comment_count': 'get_comments_count', }, filter={'target': '<_id>'}, ), @@ -948,7 +949,7 @@ class RegistrationFileSerializer(OsfStorageFileSerializer): comments = FileRelationshipField( related_view='registrations:registration-comments', related_view_kwargs={'node_id': ''}, - related_meta={'unread': 'get_unread_comments_count'}, + related_meta={'unread': 'get_unread_comments_count', 'comment_count': 'get_comments_count'}, filter={'target': 'get_file_guid'}, ) diff --git a/api/wikis/serializers.py b/api/wikis/serializers.py index 45533e982db..aca5b73ea39 100644 --- a/api/wikis/serializers.py +++ b/api/wikis/serializers.py @@ -102,7 +102,7 @@ class NodeWikiSerializer(WikiSerializer): comments = RelationshipField( related_view='nodes:node-comments', related_view_kwargs={'node_id': ''}, - related_meta={'unread': 'get_unread_comments_count'}, + related_meta={'unread': 'get_unread_comments_count', 'comment_count': 'get_comments_count'}, filter={'target': '<_id>'}, ) @@ -158,7 +158,7 @@ class RegistrationWikiSerializer(WikiSerializer): comments = RelationshipField( related_view='registrations:registration-comments', related_view_kwargs={'node_id': ''}, - related_meta={'unread': 'get_unread_comments_count'}, + related_meta={'unread': 'get_unread_comments_count', 'comment_count': 'get_comments_count'}, filter={'target': '<_id>'}, ) diff --git a/osf/models/comment.py b/osf/models/comment.py index 586763956ee..85e5cc1d994 100644 --- a/osf/models/comment.py +++ b/osf/models/comment.py @@ -134,6 +134,21 @@ def find_n_unread(cls, user, node, page, root_id=None): return 0 + @classmethod + def find_count(cls, node, page, root_id=None): + if page == Comment.OVERVIEW: + root_target = Guid.load(node._id) + elif page == Comment.FILES or page == Comment.WIKI: + root_target = Guid.load(root_id) + else: + raise ValueError('Invalid page') + + return cls.objects.filter( + Q(node=node) & + Q(is_deleted=False) & + Q(root_target=root_target) + ).count() + @classmethod def create(cls, auth, **kwargs): comment = cls(**kwargs) diff --git a/osf_tests/test_comment.py b/osf_tests/test_comment.py index 878b12962d9..ff982deb1ce 100644 --- a/osf_tests/test_comment.py +++ b/osf_tests/test_comment.py @@ -457,6 +457,37 @@ def test_find_unread_does_not_include_deleted_comments(self): n_unread = Comment.find_n_unread(user=user, node=project, page='node') assert n_unread == 0 + #Comment count tests + def test_find_count_is_zero_when_no_comments(self): + n_count = Comment.find_count(node=ProjectFactory(), page='node') + assert n_count == 0 + + def test_find_count_new_comments(self): + project = ProjectFactory() + user = UserFactory() + project.add_contributor(user, save=True) + CommentFactory(node=project, user=project.creator) + n_count = Comment.find_count(node=project, page='node') + assert n_count == 1 + + def test_find_count_includes_comment_replies(self): + project = ProjectFactory() + user = UserFactory() + project.add_contributor(user, save=True) + comment = CommentFactory(node=project, user=user) + CommentFactory(node=project, target=Guid.load(comment._id), user=project.creator) + n_count = Comment.find_count(node=project, page='node') + assert n_count == 1 + + def test_find_count_does_not_include_deleted_comments(self): + project = ProjectFactory() + user = AuthUserFactory() + project.add_contributor(user) + project.save() + CommentFactory(node=project, user=project.creator, is_deleted=True) + n_count = Comment.find_count(node=project, page='node') + assert n_count == 0 + # copied from tests/test_comments.py class FileCommentMoveRenameTestMixin: diff --git a/website/static/css/commentpane.css b/website/static/css/commentpane.css index 9f0a2fa109f..c3a5a20f7f1 100644 --- a/website/static/css/commentpane.css +++ b/website/static/css/commentpane.css @@ -54,11 +54,15 @@ .comment-handle-icon { padding-top: 2px; - color: #428bca; + color: #333333; cursor: pointer; position: relative; } +.comment-handle-icon.has-comments { + color: #428bca; +} + .cp-bar { width: 1px; /* Note: Should be the same as .cp-sidebar:margin-left */ top: 88px; diff --git a/website/static/js/comment.js b/website/static/js/comment.js index fed0eea6da5..e24dc7b613f 100644 --- a/website/static/js/comment.js +++ b/website/static/js/comment.js @@ -291,6 +291,9 @@ BaseComment.prototype.fetchNext = function(url, comments, setUnread) { self.$root.unreadComments(response.links.meta.unread); setUnread = false; } + if (response.links.meta.comment_count) { + self.$root.totalComments(response.links.meta.comment_count); + } comments.forEach(function(comment) { self.comments.push( new CommentModel(comment, self, self.$root) @@ -780,6 +783,15 @@ var CommentListModel = function(options) { } }); + self.totalComments = ko.observable(0); + self.hasComments = ko.pureComputed(function() { + if (self.totalComments() !== 0) { + return true; + } else { + return false; + } + }); + /* Removes number of unread comments from tab when comments pane is opened */ self.removeCount = function() { self.unreadComments(0); diff --git a/website/templates/include/comment_pane_template.mako b/website/templates/include/comment_pane_template.mako index 653b7b3b511..486342da4b5 100644 --- a/website/templates/include/comment_pane_template.mako +++ b/website/templates/include/comment_pane_template.mako @@ -4,7 +4,8 @@ - +