def test_calls_activitypub_retrieve_and_parse_content(self, mock_import): mock_retrieve = Mock() mock_import.return_value = mock_retrieve retrieve_remote_content("https://example.com/foobar") mock_retrieve.retrieve_and_parse_content.assert_called_once_with( id="https://example.com/foobar", guid=None, handle=None, entity_type=None, sender_key_fetcher=None, )
def test_calls_diaspora_retrieve_and_parse_content(self, mock_import): mock_retrieve = Mock() mock_import.return_value = mock_retrieve retrieve_remote_content("1234", handle="*****@*****.**", entity_type="post", sender_key_fetcher=sum) mock_retrieve.retrieve_and_parse_content.assert_called_once_with( id="1234", guid="1234", handle="*****@*****.**", entity_type="post", sender_key_fetcher=sum, )
def test_calls_diaspora_retrieve_and_parse_content(self, mock_import): mock_retrieve = Mock() mock_import.return_value = mock_retrieve retrieve_remote_content( "diaspora://[email protected]/status_message/1234", sender_key_fetcher=sum) mock_retrieve.retrieve_and_parse_content.assert_called_once_with( "diaspora://[email protected]/status_message/1234", sender_key_fetcher=sum, )
def process_entity_share(entity, profile): """Process an entity of type Share.""" if not entity.entity_type == "Post": # TODO: enable shares of replies too logger.warning("Ignoring share entity type that is not of type Post") return try: target_content = Content.objects.fed(entity.target_id, share_of__isnull=True).get() except Content.DoesNotExist: # Try fetching. If found, process and then try again remote_target = retrieve_remote_content( entity.target_id, guid=entity.target_guid, handle=entity.target_handle, entity_type=entity.entity_type, sender_key_fetcher=sender_key_fetcher, ) if remote_target: process_entities([remote_target]) try: target_content = Content.objects.fed( entity.target_id, share_of__isnull=True).get() except Content.DoesNotExist: logger.warning( "Share target was fetched from remote, but it is still missing locally! Share: %s", entity) return else: logger.warning( "No target found for share even after fetching from remote: %s", entity) return values = { "text": safe_text_for_markdown(entity.raw_content), "author": profile, # TODO: ensure visibility constraints depending on shared content? "visibility": Visibility.PUBLIC if entity.public else Visibility.LIMITED, "remote_created": safe_make_aware(entity.created_at, "UTC"), "service_label": safe_text(entity.provider_display_name) or "", } values["text"] = _embed_entity_images_to_post(entity._children, values["text"]) fid = safe_text(entity.id) if getattr(entity, "guid", None): values["guid"] = safe_text(entity.guid) content, created = Content.objects.fed_update_or_create( fid, values, extra_lookups={'share_of': target_content}) _process_mentions(content, entity) if created: logger.info("Saved share: %s", content) else: logger.info("Updated share: %s", content) # TODO: send participation to the share from the author, if local # We probably want that to happen even though our shares are not separate in the stream? if target_content.local: # We should relay this share entity to participants we know of from socialhome.federate.tasks import forward_entity django_rq.enqueue(forward_entity, entity, target_content.id)
def process_entity_share(entity, profile): """Process an entity of type Share.""" if not entity.entity_type == "Post": # TODO: enable shares of replies too logger.warning("Ignoring share entity type that is not of type Post") return try: target_content = Content.objects.fed(entity.target_id, share_of__isnull=True).get() except Content.DoesNotExist: # Try fetching. If found, process and then try again remote_target = retrieve_remote_content( entity.target_id, guid=entity.target_guid, handle=entity.target_handle, entity_type=entity.entity_type, sender_key_fetcher=sender_key_fetcher, ) if remote_target: process_entities([remote_target]) try: target_content = Content.objects.fed(entity.target_id, share_of__isnull=True).get() except Content.DoesNotExist: logger.warning("Share target was fetched from remote, but it is still missing locally! Share: %s", entity) return else: logger.warning("No target found for share even after fetching from remote: %s", entity) return values = { "text": safe_text_for_markdown(entity.raw_content), "author": profile, # TODO: ensure visibility constraints depending on shared content? "visibility": Visibility.PUBLIC if entity.public else Visibility.LIMITED, "remote_created": safe_make_aware(entity.created_at, "UTC"), "service_label": safe_text(entity.provider_display_name) or "", } values["text"] = _embed_entity_images_to_post(entity._children, values["text"]) fid = safe_text(entity.id) if getattr(entity, "guid", None): values["guid"] = safe_text(entity.guid) content, created = Content.objects.fed_update_or_create(fid, values, extra_lookups={'share_of': target_content}) _process_mentions(content, entity) if created: logger.info("Saved share: %s", content) else: logger.info("Updated share: %s", content) # TODO: send participation to the share from the author, if local # We probably want that to happen even though our shares are not separate in the stream? if target_content.local: # We should relay this share entity to participants we know of from socialhome.federate.tasks import forward_entity django_rq.enqueue(forward_entity, entity, target_content.id)
def process_entity_share(entity, profile): """Process an entity of type Share.""" if not entity.entity_type == "Post": # TODO: enable shares of replies too logger.warning("Ignoring share entity type that is not of type Post") return try: target_content = Content.objects.get(guid=entity.target_guid, share_of__isnull=True) except Content.DoesNotExist: # Try fetching. If found, process and then try again remote_target = retrieve_remote_content( entity.target_id, sender_key_fetcher=sender_key_fetcher) if remote_target: process_entities([remote_target]) try: target_content = Content.objects.get(guid=entity.target_guid, share_of__isnull=True) except Content.DoesNotExist: logger.warning( "Share target was fetched from remote, but it is still missing locally! Share: %s", entity) return else: logger.warning( "No target found for share even after fetching from remote: %s", entity) return if not target_content.author.handle == entity.target_handle: logger.warning( "Share target handle is different from the author of locally known shared content!" ) return values = { "text": safe_text_for_markdown(entity.raw_content), "author": profile, # TODO: ensure visibility constraints depending on shared content? "visibility": Visibility.PUBLIC if entity.public else Visibility.LIMITED, "remote_created": safe_make_aware(entity.created_at, "UTC"), "service_label": safe_text(entity.provider_display_name) or "", } values["text"] = _embed_entity_images_to_post(entity._children, values["text"]) guid = safe_text(entity.guid) content, created = Content.objects.update_or_create( guid=guid, share_of=target_content, defaults=values) if created: logger.info("Saved share: %s", content) else: logger.info("Updated share: %s", content)
def get(self, request, *args, **kwargs): """See if we have a direct match. If so redirect, if not, search. Try fetching a remote profile if the search term is a handle or fid. """ q = safe_text(request.GET.get("q")) if q: q = q.strip().lower().strip("@") self.q = q # Check if direct tag matches if q.startswith('#'): try: tag = Tag.objects.filter( name=q[1:] ).annotate( content_count=Count('contents') ).filter( content_count__gt=0 ).get() except Tag.DoesNotExist: pass else: return redirect(tag.get_absolute_url()) # Check if profile matches profile = None try: profile = Profile.objects.visible_for_user(request.user).fed(q).get() except Profile.DoesNotExist: # Try a remote search if is_url(q) or validate_handle(q): try: remote_profile = retrieve_remote_profile(q) except (AttributeError, ValueError, xml.parsers.expat.ExpatError): # Catch various errors parsing the remote profile return super().get(request, *args, **kwargs) if remote_profile and isinstance(remote_profile, base.Profile): profile = Profile.from_remote_profile(remote_profile) if profile: return redirect(reverse("users:profile-detail", kwargs={"uuid": profile.uuid})) # Check if content matches content = None try: content = Content.objects.visible_for_user(request.user).fed(q).get() except Content.DoesNotExist: # Try a remote search if is_url(q): try: remote_content = retrieve_remote_content(q) except (AttributeError, ValueError): # Catch various errors parsing the remote content return super().get(request, *args, **kwargs) if remote_content: process_entities([remote_content]) # Try again try: content = Content.objects.visible_for_user(request.user).fed(remote_content.id).get() except Content.DoesNotExist: return super().get(request, *args, **kwargs) if content: return redirect(reverse("content:view", kwargs={"pk": content.id})) try: return super().get(request, *args, **kwargs) except QueryError: # Re-render the form messages.warning(self.request, _("Search string is invalid, please try another one.")) return HttpResponseRedirect(self.get_success_url())