Repository: bookwyrm-social/bookwyrm

Issue:
Improve Mastodon integration by using the `application/activity+json` type
I'm not sure if this should be a bug, sorry if it's the wrong type!

**Is your feature request related to a problem? Please describe.**
When you follow someone from Mastodon, you don't see previous posts. One of the ways you can see them, however, is by pasting the URL of their status, which allows Mastodon to fetch that activity and associate with a profile. Currently, doing so with BookWyrm doesn't fetch the status.

**Describe the solution you'd like**
I'd like to be able to look for comments and profiles by pasting the URL in Mastodon search bar.

**Describe alternatives you've considered**
I think BookWyrm should use the `content-type` in the api request responses. This would make it so that Mastodon treat the responses as ActivityPub things and parses them correctly.
This however, raises another issues. It seems the serializer used in the views is serializing using `pure=False`, which gives a `Comment`, instead of a `Note`, which is ignored by Mastodon.
Since it probably would be interesting to still return BookWyrm-specific serializations, one way I see for this is to add a user-agent to bookwyrm requests and differentiate them in the views code.


I'd be happy to submit a PR about this if this is the way you think this should go :)


Discussion:
Yeah! I was assuming that the only time mastodon would receive statuses is when they are sent from bookwyrm, and it didn't occur to me that they should be fetch-able from mastodon as well. Bookwyrm instances definitely need the custom activity types (Comment, Review, Quote, etc) to each other, and "pure" versions of those statuses to mastodon, so I think your idea of using a user agent makes a lot of sense. So tl;dr you're right and I think your approach sounds correct. Thank you!

Resolving patch:
diff --git a/bookwyrm/utils/regex.py b/bookwyrm/utils/regex.py
--- a/bookwyrm/utils/regex.py
+++ b/bookwyrm/utils/regex.py
@@ -6,3 +6,5 @@
 username = r'%s(@%s)?' % (localname, domain)
 strict_username = r'%s(@%s)?' % (strict_localname, domain)
 full_username = r'%s@%s' % (localname, domain)
+# should match (BookWyrm/1.0.0; or (BookWyrm/99.1.2;
+bookwyrm_user_agent = r'\(BookWyrm/[0-9]+\.[0-9]+\.[0-9]+;'
diff --git a/bookwyrm/views.py b/bookwyrm/views.py
--- a/bookwyrm/views.py
+++ b/bookwyrm/views.py
@@ -42,6 +42,13 @@ def is_api_request(request):
     return 'json' in request.headers.get('Accept') or \
             request.path[-5:] == '.json'
 
+def is_bookworm_request(request):
+    ''' check if the request is coming from another bookworm instance '''
+    user_agent = request.headers.get('User-Agent')
+    if user_agent is None or re.search(regex.bookwyrm_user_agent, user_agent) is None:
+        return False
+
+    return True
 
 def server_error_page(request):
     ''' 500 errors '''
@@ -505,7 +512,7 @@ def status_page(request, username, status_id):
         return HttpResponseNotFound()
 
     if is_api_request(request):
-        return ActivitypubResponse(status.to_activity())
+        return ActivitypubResponse(status.to_activity(pure=not is_bookworm_request(request)))
 
     data = {
         'title': 'Status by %s' % user.username,


Test patch:
diff --git a/bookwyrm/tests/test_views.py b/bookwyrm/tests/test_views.py
--- a/bookwyrm/tests/test_views.py
+++ b/bookwyrm/tests/test_views.py
@@ -10,7 +10,7 @@
 
 from bookwyrm import models, views
 from bookwyrm.connectors import abstract_connector
-from bookwyrm.settings import DOMAIN
+from bookwyrm.settings import DOMAIN, USER_AGENT
 
 
 # pylint: disable=too-many-public-methods
@@ -539,3 +539,16 @@ def test_shelf_page(self):
                 request, self.local_user.username, shelf.identifier)
         self.assertIsInstance(result, JsonResponse)
         self.assertEqual(result.status_code, 200)
+
+
+    def test_is_bookwyrm_request(self):
+        ''' tests the function that checks if a request came from a bookwyrm instance '''
+        request = self.factory.get('', {'q': 'Test Book'})
+        self.assertFalse(views.is_bookworm_request(request))
+
+        request = self.factory.get('', {'q': 'Test Book'},
+                HTTP_USER_AGENT="http.rb/4.4.1 (Mastodon/3.3.0; +https://mastodon.social/)")
+        self.assertFalse(views.is_bookworm_request(request))
+
+        request = self.factory.get('', {'q': 'Test Book'}, HTTP_USER_AGENT=USER_AGENT)
+        self.assertTrue(views.is_bookworm_request(request))