def test_create_comment_content_does_not_exceed_max_length_complex(self, node, user, auth): Comment.create( auth=auth, user=user, node=node, target=node.guids.all()[0], content=''.join(['c' for c in range(settings.COMMENT_MAXLENGTH - 12)]) + '[@George Ant](http://localhost:5000/' + user._id + '/)' )
def test_create_comment_content_cannot_exceed_max_length_simple(self, node, user, auth): with pytest.raises(ValidationError): Comment.create( auth=auth, user=user, node=node, target=node.guids.all()[0], content=''.join(['c' for c in range(settings.COMMENT_MAXLENGTH + 3)]) )
def test_create_comment_content_cannot_exceed_max_length_simple(self, node, user, auth): with pytest.raises(ValidationError): Comment.create( auth=auth, user=user, node=node, target=node.guids.all()[0], content=''.join(['c' for c in range(settings.COMMENT_MAXLENGTH + 3)]) )
def test_create_comment_content_cannot_exceed_max_length_complex(self, node, user, auth): with pytest.raises(ValidationError): Comment.create( auth=auth, user=user, node=node, target=node.guids.all()[0], content=''.join(['c' for c in range(settings.COMMENT_MAXLENGTH - 8)]) + '[@George Ant](http://localhost:5000/' + user._id + '/)' )
def test_create_comment_content_cannot_be_whitespace(self, node, user, auth): with pytest.raises(ValidationError) as error: Comment.create( auth=auth, user=user, node=node, target=node.guids.all()[0], content=' ' ) assert error.value.messages[0] == 'Value must not be empty.'
def test_create_sends_mention_added_signal_if_mentions(self, node, user, auth): with capture_signals() as mock_signals: Comment.create( auth=auth, user=user, node=node, target=node.guids.all()[0], content='This is a comment with a bad mention [@Unconfirmed User](http://localhost:5000/' + user._id + '/).' ) assert mock_signals.signals_sent() == ({comment_added, mention_added})
def test_create_sends_comment_added_signal(self, node, user, auth): with capture_signals() as mock_signals: Comment.create( auth=auth, user=user, node=node, target=node.guids.all()[0], content='This is a comment.' ) assert mock_signals.signals_sent() == ({comment_added})
def test_create_comment_content_cannot_be_whitespace(self, node, user, auth): with pytest.raises(ValidationError) as error: Comment.create( auth=auth, user=user, node=node, target=node.guids.all()[0], content=' ' ) assert error.value.messages[0] == 'Value must not be empty.'
def test_create_sends_comment_added_signal(self, node, user, auth): with capture_signals() as mock_signals: Comment.create( auth=auth, user=user, node=node, target=node.guids.all()[0], content='This is a comment.' ) assert mock_signals.signals_sent() == ({comment_added})
def test_create_sends_mention_added_signal_if_mentions(self, node, user, auth): with capture_signals() as mock_signals: Comment.create( auth=auth, user=user, node=node, target=node.guids.all()[0], content='This is a comment with a bad mention [@Unconfirmed User](http://localhost:5000/' + user._id + '/).' ) assert mock_signals.signals_sent() == ({comment_added, mention_added})
def test_create_comment_content_cannot_be_empty(self, node, user, auth): with pytest.raises(ValidationError) as error: Comment.create( auth=auth, user=user, node=node, target=node.guids.all()[0], content='' ) assert error.value.messages[0] == 'This field cannot be blank.'
def test_create_comment_content_cannot_be_empty(self, node, user, auth): with pytest.raises(ValidationError) as error: Comment.create( auth=auth, user=user, node=node, target=node.guids.all()[0], content='' ) assert error.value.messages[0] == 'This field cannot be blank.'
def setUp(self): super(TestSpamListView, self).setUp() Comment.remove() self.project = ProjectFactory(is_public=True) self.user_1 = AuthUserFactory() self.user_2 = AuthUserFactory() self.project.add_contributor(self.user_1) self.project.add_contributor(self.user_2) self.project.save() self.user_1.save() self.user_2.save() date = timezone.now() self.comment_1 = CommentFactory(node=self.project, user=self.user_1) self.comment_2 = CommentFactory(node=self.project, user=self.user_1) self.comment_3 = CommentFactory(node=self.project, user=self.user_1) self.comment_4 = CommentFactory(node=self.project, user=self.user_1) self.comment_5 = CommentFactory(node=self.project, user=self.user_2) self.comment_6 = CommentFactory(node=self.project, user=self.user_2) self.comment_1.report_abuse( user=self.user_2, save=True, category='spam', date=date - timedelta(seconds=5) ) self.comment_2.report_abuse( user=self.user_2, save=True, category='spam', date=date - timedelta(seconds=4) ) self.comment_3.report_abuse( user=self.user_2, save=True, category='spam', date=date - timedelta(seconds=3) ) self.comment_4.report_abuse( user=self.user_2, save=True, category='spam', date=date - timedelta(seconds=2) ) self.comment_5.report_abuse( user=self.user_1, save=True, category='spam', date=date - timedelta(seconds=1) ) self.comment_6.report_abuse(user=self.user_1, save=True, category='spam') self.request = RequestFactory().get('/fake_path') self.view = SpamList() self.view = setup_view(self.view, self.request, user_id=self.user_1._id)
def test_create_does_not_send_mention_added_signal_if_nonuser_mentioned(self, node, user, auth): with pytest.raises(ValidationError) as error: with capture_signals() as mock_signals: Comment.create( auth=auth, user=user, node=node, target=node.guids.all()[0], content='This is a comment with a bad mention [@Not a User](http://localhost:5000/qwert/).' ) assert mock_signals.signals_sent() == set([]) assert error.value.message == 'User does not exist or is not active.'
def test_create_does_not_send_mention_added_signal_if_nonuser_mentioned(self, node, user, auth): with pytest.raises(ValidationError) as error: with capture_signals() as mock_signals: Comment.create( auth=auth, user=user, node=node, target=node.guids.all()[0], content='This is a comment with a bad mention [@Not a User](http://localhost:5000/qwert/).' ) assert mock_signals.signals_sent() == set([]) assert error.value.message == 'User does not exist or is not active.'
def test_create_does_not_send_mention_added_signal_if_noncontributor_mentioned(self, node, user, auth): with pytest.raises(ValidationError) as error: with capture_signals() as mock_signals: user = UserFactory() Comment.create( auth=auth, user=user, node=node, target=node.guids.all()[0], content='This is a comment with a bad mention [@Non-contributor User](http://localhost:5000/' + user._id + '/).' ) assert mock_signals.signals_sent() == set([]) assert error.value.message == 'Mentioned user is not a contributor.'
def test_create_does_not_send_mention_added_signal_if_noncontributor_mentioned(self, node, user, auth): with pytest.raises(ValidationError) as error: with capture_signals() as mock_signals: user = UserFactory() Comment.create( auth=auth, user=user, node=node, target=node.guids.all()[0], content='This is a comment with a bad mention [@Non-contributor User](http://localhost:5000/' + user._id + '/).' ) assert mock_signals.signals_sent() == set([]) assert error.value.message == 'Mentioned user is not a contributor.'
def test_create_sends_mention_added_signal_if_group_member_mentions(self, node, user, auth): manager = AuthUserFactory() group = OSFGroupFactory(creator=manager) node.add_osf_group(group) assert node.is_contributor_or_group_member(manager) is True with capture_signals() as mock_signals: Comment.create( auth=auth, user=user, node=node, target=node.guids.all()[0], content='This is a comment with a group member mention [@Group Member](http://localhost:5000/' + manager._id + '/).' ) assert mock_signals.signals_sent() == ({comment_added, mention_added})
def get_paginated_response(self, data): """Add number of unread comments to links.meta when viewing list of comments filtered by a target node, file or wiki page.""" response = super(CommentPagination, self).get_paginated_response(data) response_dict = response.data kwargs = self.request.parser_context['kwargs'].copy() if self.request.query_params.get('related_counts', False): target_id = self.request.query_params.get('filter[target]', None) node_id = kwargs.get('node_id', None) node = AbstractNode.load(node_id) user = self.request.user if target_id and not user.is_anonymous and node.is_contributor_or_group_member(user): root_target = Guid.load(target_id) if root_target: page = getattr(root_target.referent, 'root_target_page', None) if page: if not len(data): unread = 0 else: unread = Comment.find_n_unread(user=user, node=node, page=page, root_id=target_id) if self.request.version < '2.1': response_dict['links']['meta']['unread'] = unread else: response_dict['meta']['unread'] = unread return Response(response_dict)
def test_comments_move_when_file_moved_to_osfstorage(self, project, user): osfstorage = project.get_addon('osfstorage') root_node = osfstorage.get_root() osf_file = root_node.append_file('file.txt') osf_file.create_version(user, { 'object': '06d80e', 'service': 'cloud', osfstorage_settings.WATERBUTLER_RESOURCE: 'osf', }, { 'size': 1337, 'contentType': 'img/png', 'etag': 'abcdefghijklmnop' }).save() source = { 'path': '/file.txt', 'node': project, 'provider': self.provider } destination = { 'path': osf_file.path, 'node': project, 'provider': 'osfstorage' } self._create_file_with_comment(node=source['node'], path=source['path'], user=user) payload = self._create_payload('move', user, source, destination, self.file._id, destination_file_id=destination['path'].strip('/')) update_file_guid_referent(self=None, node=destination['node'], event_type='addon_file_moved', payload=payload) self.guid.reload() file_node = BaseFileNode.resolve_class('osfstorage', BaseFileNode.FILE).get_or_create(destination['node'], destination['path']) assert self.guid._id == file_node.get_guid()._id file_comments = Comment.find(Q('root_target', 'eq', self.guid.pk)) assert file_comments.count() == 1
def test_comments_move_when_folder_moved_to_different_provider(self, destination_provider, destination_path, project, user): if self.provider == destination_provider: return True project.add_addon(destination_provider, auth=Auth(user)) project.save() self.addon_settings = project.get_addon(destination_provider) self.addon_settings.folder = '/AddonFolder' self.addon_settings.save() source = { 'path': '/', 'node': project, 'provider': self.provider } destination = { 'path': '/subfolder/', 'node': project, 'provider': destination_provider, 'children': [{ 'path': '/subfolder/file.txt', 'node': project, 'provider': destination_provider }] } file_name = 'file.txt' self._create_file_with_comment(node=source['node'], path='{}{}'.format(source['path'], file_name), user=user) payload = self._create_payload('move', user, source, destination, self.file._id) update_file_guid_referent(self=None, node=destination['node'], event_type='addon_file_moved', payload=payload) self.guid.reload() file_node = BaseFileNode.resolve_class(destination_provider, BaseFileNode.FILE).get_or_create(destination['node'], destination_path) assert self.guid._id == file_node.get_guid()._id file_comments = Comment.find(Q('root_target', 'eq', self.guid.pk)) assert file_comments.count() == 1
def test_create_does_not_send_mention_added_signal_if_unconfirmed_contributor_mentioned(self, node, user, auth): with pytest.raises(ValidationError) as error: with capture_signals() as mock_signals: user = UnregUserFactory() user.save() node.add_unregistered_contributor(user.fullname, user.email, Auth(node.creator), permissions=[permissions.READ], save=True) Comment.create( auth=auth, user=user, node=node, target=node.guids.all()[0], content='This is a comment with a bad mention [@Unconfirmed User](http://localhost:5000/' + user._id + '/).' ) assert mock_signals.signals_sent() == ({contributor_added}) assert error.value.message == 'User does not exist or is not active.'
def update_file_guid_referent(self, node, event_type, payload, user=None): if event_type not in ('addon_file_moved', 'addon_file_renamed'): return # Nothing to do source, destination = payload['source'], payload['destination'] source_node, destination_node = Node.load(source['node']['_id']), Node.load(destination['node']['_id']) if source['provider'] in settings.ADDONS_BASED_ON_IDS: if event_type == 'addon_file_renamed': return # Node has not changed and provider has not changed # Must be a move if source['provider'] == destination['provider'] and source_node == destination_node: return # Node has not changed and provider has not changed file_guids = BaseFileNode.resolve_class(source['provider'], BaseFileNode.ANY).get_file_guids( materialized_path=source['materialized'] if source['provider'] != 'osfstorage' else source['path'], provider=source['provider'], node=source_node ) for guid in file_guids: obj = Guid.load(guid) if source_node != destination_node and Comment.find(Q('root_target._id', 'eq', guid)).count() != 0: update_comment_node(guid, source_node, destination_node) if source['provider'] != destination['provider'] or source['provider'] != 'osfstorage': old_file = BaseFileNode.load(obj.referent._id) obj.referent = create_new_file(obj, source, destination, destination_node) obj.save() if old_file and not TrashedFileNode.load(old_file._id): old_file.delete()
def get_unread_comments_count(self, obj): user = get_user_auth(self.context['request']).user node_comments = Comment.find_n_unread(user=user, node=obj, page='node') return { 'node': node_comments }
def test_find_unread_new_comments(self): project = ProjectFactory() user = UserFactory() project.add_contributor(user, save=True) CommentFactory(node=project, user=project.creator) n_unread = Comment.find_n_unread(user=user, node=project, page='node') assert n_unread == 1
def get_paginated_response(self, data): """Add number of unread comments to links.meta when viewing list of comments filtered by a target node, file or wiki page.""" response = super(CommentPagination, self).get_paginated_response(data) response_dict = response.data kwargs = self.request.parser_context['kwargs'].copy() if self.request.query_params.get('related_counts', False): target_id = self.request.query_params.get('filter[target]', None) node_id = kwargs.get('node_id', None) node = Node.load(node_id) user = self.request.user if target_id and not user.is_anonymous and node.is_contributor(user): root_target = Guid.load(target_id) if root_target: page = getattr(root_target.referent, 'root_target_page', None) if page: if not len(data): unread = 0 else: unread = Comment.find_n_unread(user=user, node=node, page=page, root_id=target_id) if self.request.version < '2.1': response_dict['links']['meta']['unread'] = unread else: response_dict['meta']['unread'] = unread return Response(response_dict)
def test_find_unread_new_comments(self): project = ProjectFactory() user = UserFactory() project.add_contributor(user, save=True) CommentFactory(node=project, user=project.creator) n_unread = Comment.find_n_unread(user=user, node=project, page='node') assert n_unread == 1
def setUp(self): super(TestSpamListView, self).setUp() Comment.remove() self.project = ProjectFactory(is_public=True) self.user_1 = AuthUserFactory() self.user_2 = AuthUserFactory() self.project.add_contributor(self.user_1) self.project.add_contributor(self.user_2) self.project.save() self.user_1.save() self.user_2.save() date = timezone.now() self.comment_1 = CommentFactory(node=self.project, user=self.user_1) self.comment_2 = CommentFactory(node=self.project, user=self.user_1) self.comment_3 = CommentFactory(node=self.project, user=self.user_1) self.comment_4 = CommentFactory(node=self.project, user=self.user_1) self.comment_5 = CommentFactory(node=self.project, user=self.user_2) self.comment_6 = CommentFactory(node=self.project, user=self.user_2) self.comment_1.report_abuse(user=self.user_2, save=True, category='spam', date=date - timedelta(seconds=5)) self.comment_2.report_abuse(user=self.user_2, save=True, category='spam', date=date - timedelta(seconds=4)) self.comment_3.report_abuse(user=self.user_2, save=True, category='spam', date=date - timedelta(seconds=3)) self.comment_4.report_abuse(user=self.user_2, save=True, category='spam', date=date - timedelta(seconds=2)) self.comment_5.report_abuse(user=self.user_1, save=True, category='spam', date=date - timedelta(seconds=1)) self.comment_6.report_abuse(user=self.user_1, save=True, category='spam') self.request = RequestFactory().get('/fake_path') self.view = SpamList() self.view = setup_view(self.view, self.request, user_id=self.user_1._id)
def get_unread_comments_count(self, obj): user = self.context['request'].user if user.is_anonymous: return 0 return Comment.find_n_unread(user=user, node=obj.target, page='files', root_id=obj.get_guid()._id)
def test_find_unread_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_unread = Comment.find_n_unread(user=user, node=project, page='node') assert n_unread == 1
def test_find_unread_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_unread = Comment.find_n_unread(user=user, node=project, page='node') assert n_unread == 0
def test_find_unread_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_unread = Comment.find_n_unread(user=user, node=project, page='node') assert n_unread == 0
def test_find_unread_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_unread = Comment.find_n_unread(user=user, node=project, page='node') assert n_unread == 1
def test_create_does_not_send_mention_added_signal_if_unconfirmed_contributor_mentioned(self, node, user, auth): with pytest.raises(ValidationError) as error: with capture_signals() as mock_signals: user = UserFactory() user.is_registered = False user.is_claimed = False user.save() node.add_contributor(user, visible=False, permissions=[permissions.READ], save=True) Comment.create( auth=auth, user=user, node=node, target=node.guids.all()[0], content='This is a comment with a bad mention [@Unconfirmed User](http://localhost:5000/' + user._id + '/).' ) assert mock_signals.signals_sent() == ({contributor_added}) assert error.value.message == 'User does not exist or is not active.'
def test_create_comment(self, request, user, project, comment_content, expected_signals, expected_error_msg): if hasattr(comment_content, '_pytestfixturefunction'): comment_content = request.getfixturevalue(comment_content.__name__) auth = Auth(user) error_msg = None with capture_signals() as mock_signals: try: Comment.create( auth=auth, user=user, node=project, target=project.guids.all()[0], content=comment_content ) except Exception as e: error_msg = str(e) assert expected_signals == mock_signals.signals_sent() assert error_msg == expected_error_msg
def test_create(self): first_comment = CommentFactory() auth = Auth(user=first_comment.user) comment = Comment.create( auth=auth, user=first_comment.user, node=first_comment.node, target=first_comment.target, root_target=first_comment.root_target, page='node', content='This is a comment, and ya cant teach that.' ) assert comment.user == first_comment.user assert comment.node == first_comment.node assert comment.target == first_comment.target assert comment.node.logs.count() == 2 assert comment.node.logs.latest().action == NodeLog.COMMENT_ADDED assert not first_comment.ever_mentioned.exists()
def test_create(self): first_comment = CommentFactory() auth = Auth(user=first_comment.user) comment = Comment.create( auth=auth, user=first_comment.user, node=first_comment.node, target=first_comment.target, root_target=first_comment.root_target, page='node', content='This is a comment, and ya cant teach that.' ) assert comment.user == first_comment.user assert comment.node == first_comment.node assert comment.target == first_comment.target assert comment.node.logs.count() == 2 assert comment.node.logs.latest().action == NodeLog.COMMENT_ADDED assert not first_comment.ever_mentioned.exists()
def test_comments_move_on_file_rename(self, project, user): source = { 'path': '/file.txt', 'node': project, 'provider': self.provider } destination = { 'path': '/file_renamed.txt', 'node': project, 'provider': self.provider } self._create_file_with_comment(node=source['node'], path=source['path'], user=user) payload = self._create_payload('move', user, source, destination, self.file._id) update_file_guid_referent(self=None, node=destination['node'], event_type='addon_file_renamed', payload=payload) self.guid.reload() file_node = BaseFileNode.resolve_class(self.provider, BaseFileNode.FILE).get_or_create(destination['node'], self._format_path(destination['path'], file_id=self.file._id)) assert self.guid._id == file_node.get_guid()._id file_comments = Comment.find(Q('root_target', 'eq', self.guid.pk)) assert file_comments.count() == 1
def get_comment(self, check_permissions=True): pk = self.kwargs[self.comment_lookup_url_kwarg] try: comment = Comment.find_one( Q('guids___id', 'eq', pk) & Q('root_target', 'ne', None)) except NoResultsFound: raise NotFound # Deleted root targets still appear as tuples in the database and are included in # the above query, requiring an additional check if comment.root_target.referent.is_deleted: comment.root_target = None comment.save() if comment.root_target is None: raise NotFound if check_permissions: # May raise a permission denied self.check_object_permissions(self.request, comment) return comment
def create(self, validated_data): user = validated_data['user'] auth = Auth(user) node = validated_data['node'] target_id = self.context['request'].data.get('id') try: target = self.get_target(node._id, target_id) except ValueError: raise InvalidModelValueError( source={'pointer': '/data/relationships/target/data/id'}, detail='Invalid comment target \'{}\'.'.format(target_id) ) validated_data['target'] = target validated_data['content'] = validated_data.pop('get_content') try: comment = Comment.create(auth=auth, **validated_data) except PermissionsError: raise PermissionDenied('Not authorized to comment on this project.') except ModelValidationError as err: raise ValidationError(err.messages[0]) return comment
def create(self, validated_data): user = validated_data['user'] auth = Auth(user) node = validated_data['node'] target_id = self.context['request'].data.get('id') try: target = self.get_target(node._id, target_id) except ValueError: raise InvalidModelValueError( source={'pointer': '/data/relationships/target/data/id'}, detail='Invalid comment target \'{}\'.'.format(target_id)) validated_data['target'] = target validated_data['content'] = validated_data.pop('get_content') try: comment = Comment.create(auth=auth, **validated_data) except PermissionsError: raise PermissionDenied( 'Not authorized to comment on this project.') except ModelValidationError as err: raise ValidationError(err.messages[0]) return comment
def test_comments_move_when_folder_moved_from_component_to_project(self, project, component, user): source = { 'path': '/subfolder/', 'node': component, 'provider': self.provider } destination = { 'path': '/subfolder/', 'node': project, 'provider': self.provider } file_name = 'file.txt' self._create_file_with_comment(node=source['node'], path='{}{}'.format(source['path'], file_name), user=user) self.file.move_under(destination['node'].get_addon(self.provider).get_root()) payload = self._create_payload('move', user, source, destination, self.file._id) update_file_guid_referent(self=None, node=destination['node'], event_type='addon_file_moved', payload=payload) self.guid.reload() file_node = BaseFileNode.resolve_class(self.provider, BaseFileNode.FILE).get_or_create(destination['node'], self._format_path('{}{}'.format(destination['path'], file_name), file_id=self.file._id)) assert self.guid._id == file_node.get_guid()._id file_comments = Comment.find(Q('root_target', 'eq', self.guid.pk)) assert file_comments.count() == 1
def _view_project(node, auth, primary=False, embed_contributors=False, embed_descendants=False, embed_registrations=False, embed_forks=False): """Build a JSON object containing everything needed to render project.view.mako. """ node = Node.objects.filter(pk=node.pk).include('contributor__user__guids').get() user = auth.user parent = node.find_readable_antecedent(auth) if user: bookmark_collection = find_bookmark_collection(user) bookmark_collection_id = bookmark_collection._id in_bookmark_collection = bookmark_collection.linked_nodes.filter(pk=node.pk).exists() else: in_bookmark_collection = False bookmark_collection_id = '' view_only_link = auth.private_key or request.args.get('view_only', '').strip('/') anonymous = has_anonymous_link(node, auth) widgets, configs, js, css = _render_addon(node) redirect_url = node.url + '?view_only=None' disapproval_link = '' if (node.is_pending_registration and node.has_permission(user, ADMIN)): disapproval_link = node.root.registration_approval.stashed_urls.get(user._id, {}).get('reject', '') if (node.is_pending_embargo and node.has_permission(user, ADMIN)): disapproval_link = node.root.embargo.stashed_urls.get(user._id, {}).get('reject', '') # Before page load callback; skip if not primary call if primary: for addon in node.get_addons(): messages = addon.before_page_load(node, user) or [] for message in messages: status.push_status_message(message, kind='info', dismissible=False, trust=True) data = { 'node': { 'disapproval_link': disapproval_link, 'id': node._primary_key, 'title': node.title, 'category': node.category_display, 'category_short': node.category, 'node_type': node.project_or_component, 'description': node.description or '', 'license': serialize_node_license_record(node.license), 'url': node.url, 'api_url': node.api_url, 'absolute_url': node.absolute_url, 'redirect_url': redirect_url, 'display_absolute_url': node.display_absolute_url, 'update_url': node.api_url_for('update_node'), 'in_dashboard': in_bookmark_collection, 'is_public': node.is_public, 'is_archiving': node.archiving, 'date_created': iso8601format(node.date_created), 'date_modified': iso8601format(node.logs.latest().date) if node.logs.exists() else '', 'tags': list(node.tags.filter(system=False).values_list('name', flat=True)), 'children': bool(node.nodes_active), 'is_registration': node.is_registration, 'is_pending_registration': node.is_pending_registration, 'is_retracted': node.is_retracted, 'is_pending_retraction': node.is_pending_retraction, 'retracted_justification': getattr(node.retraction, 'justification', None), 'date_retracted': iso8601format(getattr(node.retraction, 'date_retracted', None)), 'embargo_end_date': node.embargo_end_date.strftime('%A, %b. %d, %Y') if node.embargo_end_date else False, 'is_pending_embargo': node.is_pending_embargo, 'is_embargoed': node.is_embargoed, 'is_pending_embargo_termination': node.is_embargoed and ( node.embargo_termination_approval and node.embargo_termination_approval.is_pending_approval ), 'registered_from_url': node.registered_from.url if node.is_registration else '', 'registered_date': iso8601format(node.registered_date) if node.is_registration else '', 'root_id': node.root._id if node.root else None, 'registered_meta': node.registered_meta, 'registered_schemas': serialize_meta_schemas(list(node.registered_schema.all())), 'registration_count': node.registrations_all.count(), 'is_fork': node.is_fork, 'forked_from_id': node.forked_from._primary_key if node.is_fork else '', 'forked_from_display_absolute_url': node.forked_from.display_absolute_url if node.is_fork else '', 'forked_date': iso8601format(node.forked_date) if node.is_fork else '', 'fork_count': node.forks.filter(is_deleted=False).count(), 'templated_count': node.templated_list.count(), 'private_links': [x.to_json() for x in node.private_links_active], 'link': view_only_link, 'anonymous': anonymous, 'points': len(node.get_points(deleted=False, folders=False)), 'comment_level': node.comment_level, 'has_comments': bool(Comment.find(Q('node', 'eq', node))), 'has_children': bool(Comment.find(Q('node', 'eq', node))), 'identifiers': { 'doi': node.get_identifier_value('doi'), 'ark': node.get_identifier_value('ark'), }, 'institutions': get_affiliated_institutions(node) if node else [], 'alternative_citations': [citation.to_json() for citation in node.alternative_citations.all()], 'has_draft_registrations': node.has_active_draft_registrations, 'contributors': list(node.contributors.values_list('guids___id', flat=True)), 'is_preprint': node.is_preprint, 'is_preprint_orphan': node.is_preprint_orphan, 'has_published_preprint': node.preprints.filter(is_published=True).exists() if node else False, 'preprint_file_id': node.preprint_file._id if node.preprint_file else None, 'preprint_url': node.preprint_url }, 'parent_node': { 'exists': parent is not None, 'id': parent._primary_key if parent else '', 'title': parent.title if parent else '', 'category': parent.category_display if parent else '', 'url': parent.url if parent else '', 'api_url': parent.api_url if parent else '', 'absolute_url': parent.absolute_url if parent else '', 'registrations_url': parent.web_url_for('node_registrations') if parent else '', 'is_public': parent.is_public if parent else '', 'is_contributor': parent.is_contributor(user) if parent else '', 'can_view': parent.can_view(auth) if parent else False }, 'user': { 'is_contributor': node.is_contributor(user), 'is_admin': node.has_permission(user, ADMIN), 'is_admin_parent': parent.is_admin_parent(user) if parent else False, 'can_edit': (node.can_edit(auth) and not node.is_registration), 'has_read_permissions': node.has_permission(user, READ), 'permissions': node.get_permissions(user) if user else [], 'id': user._id if user else None, 'username': user.username if user else None, 'fullname': user.fullname if user else '', 'can_comment': node.can_comment(auth), 'show_wiki_widget': _should_show_wiki_widget(node, user), 'dashboard_id': bookmark_collection_id, 'institutions': get_affiliated_institutions(user) if user else [], }, 'badges': _get_badge(user), # TODO: Namespace with nested dicts 'addons_enabled': node.get_addon_names(), 'addons': configs, 'addon_widgets': widgets, 'addon_widget_js': js, 'addon_widget_css': css, 'node_categories': [ {'value': key, 'display_name': value} for key, value in settings.NODE_CATEGORY_MAP.iteritems() ] } if embed_contributors and not anonymous: data['node']['contributors'] = utils.serialize_visible_contributors(node) if embed_descendants: descendants, all_readable = _get_readable_descendants(auth=auth, node=node) data['user']['can_sort'] = all_readable data['node']['descendants'] = [ serialize_node_summary(node=each, auth=auth, primary=not node.has_node_link_to(each), show_path=False) for each in descendants ] if embed_registrations: data['node']['registrations'] = [ serialize_node_summary(node=each, auth=auth, show_path=False) for each in node.registrations_all.order_by('-registered_date').exclude(is_deleted=True).annotate(nlogs=Count('logs')) ] if embed_forks: data['node']['forks'] = [ serialize_node_summary(node=each, auth=auth, show_path=False) for each in node.forks.exclude(type='osf.registration').exclude(is_deleted=True).order_by('-forked_date').annotate(nlogs=Count('logs')) ] return data
def test_find_unread_is_zero_when_no_comments(self): n_unread = Comment.find_n_unread(user=UserFactory(), node=ProjectFactory(), page='node') assert n_unread == 0
def get_unread_comments_count(self, obj): user = self.context['request'].user if user.is_anonymous: return 0 return Comment.find_n_unread(user=user, node=obj.node, page='files', root_id=obj.get_guid()._id)
def get_unread_comments_count(self, obj): user = get_user_auth(self.context['request']).user node_comments = Comment.find_n_unread(user=user, node=obj, page='node') return {'node': node_comments}
def get_has_children(self, obj): return Comment.find(Q('target', 'eq', Guid.load(obj._id))).count() > 0
def test_comments_are_queryable_by_root_target(): root_target = ProjectFactory() comment = CommentFactory(node=root_target) assert Comment.find(Q('root_target', 'eq', root_target.guids.first()))[0] == comment
def test_find_unread_is_zero_when_no_comments(self): n_unread = Comment.find_n_unread(user=UserFactory(), node=ProjectFactory(), page='node') assert n_unread == 0