-
+
User Activity
{% for activity in activities %}
- {% include 'snippets/status.html' with status=activity %}
+ {% include 'snippets/status/status.html' with status=activity %}
{% endfor %}
{% if not activities %}
diff --git a/bookwyrm/templates/user/user_layout.html b/bookwyrm/templates/user/user_layout.html
index 979ee0b0b..9abc469aa 100644
--- a/bookwyrm/templates/user/user_layout.html
+++ b/bookwyrm/templates/user/user_layout.html
@@ -43,14 +43,7 @@
{% if not is_self and request.user.is_authenticated %}
-
-
- {% include 'snippets/follow_button.html' with user=user %}
-
-
- {% include 'snippets/user_options.html' with user=user class="is-small" %}
-
-
+ {% include 'snippets/follow_button.html' with user=user %}
{% endif %}
{% if is_self and user.follower_requests.all %}
diff --git a/bookwyrm/tests/models/test_user_model.py b/bookwyrm/tests/models/test_user_model.py
index a10c89b85..ed3ad41a5 100644
--- a/bookwyrm/tests/models/test_user_model.py
+++ b/bookwyrm/tests/models/test_user_model.py
@@ -1,16 +1,18 @@
''' testing models '''
from unittest.mock import patch
from django.test import TestCase
+import responses
from bookwyrm import models
from bookwyrm.settings import DOMAIN
-
+# pylint: disable=missing-class-docstring
+# pylint: disable=missing-function-docstring
class User(TestCase):
def setUp(self):
self.user = models.User.objects.create_user(
'mouse@%s' % DOMAIN, 'mouse@mouse.mouse', 'mouseword',
- local=True, localname='mouse', name='hi')
+ local=True, localname='mouse', name='hi', bookwyrm_user=False)
def test_computed_fields(self):
''' username instead of id here '''
@@ -28,7 +30,7 @@ class User(TestCase):
with patch('bookwyrm.models.user.set_remote_server.delay'):
user = models.User.objects.create_user(
'rat', 'rat@rat.rat', 'ratword', local=False,
- remote_id='https://example.com/dfjkg')
+ remote_id='https://example.com/dfjkg', bookwyrm_user=False)
self.assertEqual(user.username, 'rat@example.com')
@@ -62,7 +64,7 @@ class User(TestCase):
self.assertEqual(activity['name'], self.user.name)
self.assertEqual(activity['inbox'], self.user.inbox)
self.assertEqual(activity['outbox'], self.user.outbox)
- self.assertEqual(activity['bookwyrmUser'], True)
+ self.assertEqual(activity['bookwyrmUser'], False)
self.assertEqual(activity['discoverable'], True)
self.assertEqual(activity['type'], 'Person')
@@ -71,3 +73,83 @@ class User(TestCase):
self.assertEqual(activity['type'], 'OrderedCollection')
self.assertEqual(activity['id'], self.user.outbox)
self.assertEqual(activity['totalItems'], 0)
+
+
+ def test_set_remote_server(self):
+ server = models.FederatedServer.objects.create(
+ server_name=DOMAIN,
+ application_type='test type',
+ application_version=3
+ )
+
+ models.user.set_remote_server(self.user.id)
+ self.user.refresh_from_db()
+
+ self.assertEqual(self.user.federated_server, server)
+
+ @responses.activate
+ def test_get_or_create_remote_server(self):
+ responses.add(
+ responses.GET,
+ 'https://%s/.well-known/nodeinfo' % DOMAIN,
+ json={'links': [{'href': 'http://www.example.com'}, {}]}
+ )
+ responses.add(
+ responses.GET,
+ 'http://www.example.com',
+ json={'software': {'name': 'hi', 'version': '2'}},
+ )
+
+ server = models.user.get_or_create_remote_server(DOMAIN)
+ self.assertEqual(server.server_name, DOMAIN)
+ self.assertEqual(server.application_type, 'hi')
+ self.assertEqual(server.application_version, '2')
+
+ @responses.activate
+ def test_get_or_create_remote_server_no_wellknown(self):
+ responses.add(
+ responses.GET,
+ 'https://%s/.well-known/nodeinfo' % DOMAIN,
+ status=404
+ )
+
+ server = models.user.get_or_create_remote_server(DOMAIN)
+ self.assertEqual(server.server_name, DOMAIN)
+ self.assertIsNone(server.application_type)
+ self.assertIsNone(server.application_version)
+
+ @responses.activate
+ def test_get_or_create_remote_server_no_links(self):
+ responses.add(
+ responses.GET,
+ 'https://%s/.well-known/nodeinfo' % DOMAIN,
+ json={'links': [{'href': 'http://www.example.com'}, {}]}
+ )
+ responses.add(
+ responses.GET,
+ 'http://www.example.com',
+ status=404
+ )
+
+ server = models.user.get_or_create_remote_server(DOMAIN)
+ self.assertEqual(server.server_name, DOMAIN)
+ self.assertIsNone(server.application_type)
+ self.assertIsNone(server.application_version)
+
+ @responses.activate
+ def test_get_or_create_remote_server_unknown_format(self):
+ responses.add(
+ responses.GET,
+ 'https://%s/.well-known/nodeinfo' % DOMAIN,
+ json={'links': [{'href': 'http://www.example.com'}, {}]}
+ )
+ responses.add(
+ responses.GET,
+ 'http://www.example.com',
+ json={'fish': 'salmon'}
+ )
+
+ server = models.user.get_or_create_remote_server(DOMAIN)
+ self.assertEqual(server.server_name, DOMAIN)
+ self.assertIsNone(server.application_type)
+ self.assertIsNone(server.application_version)
diff --git a/bookwyrm/tests/views/test_helpers.py b/bookwyrm/tests/views/test_helpers.py
index b75d61d55..10221933c 100644
--- a/bookwyrm/tests/views/test_helpers.py
+++ b/bookwyrm/tests/views/test_helpers.py
@@ -56,12 +56,14 @@ class ViewsHelpers(TestCase):
def test_get_user_from_username(self):
''' works for either localname or username '''
self.assertEqual(
- views.helpers.get_user_from_username('mouse'), self.local_user)
+ views.helpers.get_user_from_username(
+ self.local_user, 'mouse'), self.local_user)
self.assertEqual(
views.helpers.get_user_from_username(
- 'mouse@local.com'), self.local_user)
+ self.local_user, 'mouse@local.com'), self.local_user)
with self.assertRaises(models.User.DoesNotExist):
- views.helpers.get_user_from_username('mojfse@example.com')
+ views.helpers.get_user_from_username(
+ self.local_user, 'mojfse@example.com')
def test_is_api_request(self):
@@ -188,18 +190,18 @@ class ViewsHelpers(TestCase):
def test_is_bookwyrm_request(self):
''' checks if a request came from a bookwyrm instance '''
request = self.factory.get('', {'q': 'Test Book'})
- self.assertFalse(views.helpers.is_bookworm_request(request))
+ self.assertFalse(views.helpers.is_bookwyrm_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.helpers.is_bookworm_request(request))
+ self.assertFalse(views.helpers.is_bookwyrm_request(request))
request = self.factory.get(
'', {'q': 'Test Book'}, HTTP_USER_AGENT=USER_AGENT)
- self.assertTrue(views.helpers.is_bookworm_request(request))
+ self.assertTrue(views.helpers.is_bookwyrm_request(request))
def test_existing_user(self):
diff --git a/bookwyrm/tests/views/test_outbox.py b/bookwyrm/tests/views/test_outbox.py
index d59f028c5..7986dea61 100644
--- a/bookwyrm/tests/views/test_outbox.py
+++ b/bookwyrm/tests/views/test_outbox.py
@@ -7,6 +7,7 @@ from django.test import TestCase
from django.test.client import RequestFactory
from bookwyrm import models, views
+from bookwyrm.settings import USER_AGENT
# pylint: disable=too-many-public-methods
@@ -90,3 +91,39 @@ class OutboxView(TestCase):
data = json.loads(result.content)
self.assertEqual(data['type'], 'OrderedCollection')
self.assertEqual(data['totalItems'], 1)
+
+ def test_outbox_bookwyrm_request_true(self):
+ ''' should differentiate between bookwyrm and outside requests '''
+ with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
+ models.Review.objects.create(
+ name='hi',
+ content='look at this',
+ user=self.local_user,
+ book=self.book,
+ privacy='public',
+ )
+
+ request = self.factory.get('', {'page': 1}, HTTP_USER_AGENT=USER_AGENT)
+ result = views.Outbox.as_view()(request, 'mouse')
+
+ data = json.loads(result.content)
+ self.assertEqual(len(data['orderedItems']), 1)
+ self.assertEqual(data['orderedItems'][0]['type'], 'Review')
+
+ def test_outbox_bookwyrm_request_false(self):
+ ''' should differentiate between bookwyrm and outside requests '''
+ with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
+ models.Review.objects.create(
+ name='hi',
+ content='look at this',
+ user=self.local_user,
+ book=self.book,
+ privacy='public',
+ )
+
+ request = self.factory.get('', {'page': 1})
+ result = views.Outbox.as_view()(request, 'mouse')
+
+ data = json.loads(result.content)
+ self.assertEqual(len(data['orderedItems']), 1)
+ self.assertEqual(data['orderedItems'][0]['type'], 'Article')
diff --git a/bookwyrm/tests/views/test_rss_feed.py b/bookwyrm/tests/views/test_rss_feed.py
index 2b5e415e7..3d5bec49a 100644
--- a/bookwyrm/tests/views/test_rss_feed.py
+++ b/bookwyrm/tests/views/test_rss_feed.py
@@ -41,6 +41,7 @@ class RssFeedView(TestCase):
''' load an rss feed '''
view = rss_feed.RssFeed()
request = self.factory.get('/user/rss_user/rss')
+ request.user = self.user
with patch("bookwyrm.models.SiteSettings.objects.get") as site:
site.return_value = self.site
result = view(request, username=self.user.username)
diff --git a/bookwyrm/views/feed.py b/bookwyrm/views/feed.py
index 0e550f0c8..c229b7c9e 100644
--- a/bookwyrm/views/feed.py
+++ b/bookwyrm/views/feed.py
@@ -13,7 +13,7 @@ from bookwyrm.activitypub import ActivitypubResponse
from bookwyrm.settings import PAGE_LENGTH
from .helpers import get_activity_feed
from .helpers import get_user_from_username
-from .helpers import is_api_request, is_bookworm_request, object_visible_to_user
+from .helpers import is_api_request, is_bookwyrm_request, object_visible_to_user
# pylint: disable= no-self-use
@@ -65,7 +65,7 @@ class DirectMessage(View):
user = None
if username:
try:
- user = get_user_from_username(username)
+ user = get_user_from_username(request.user, username)
except models.User.DoesNotExist:
pass
if user:
@@ -91,7 +91,7 @@ class Status(View):
def get(self, request, username, status_id):
''' display a particular status (and replies, etc) '''
try:
- user = get_user_from_username(username)
+ user = get_user_from_username(request.user, username)
status = models.Status.objects.select_subclasses().get(
id=status_id, deleted=False)
except ValueError:
@@ -107,7 +107,7 @@ class Status(View):
if is_api_request(request):
return ActivitypubResponse(
- status.to_activity(pure=not is_bookworm_request(request)))
+ status.to_activity(pure=not is_bookwyrm_request(request)))
data = {**feed_page_data(request.user), **{
'title': 'Status by %s' % user.username,
diff --git a/bookwyrm/views/follow.py b/bookwyrm/views/follow.py
index c59f2e6d2..e1b1a0bbd 100644
--- a/bookwyrm/views/follow.py
+++ b/bookwyrm/views/follow.py
@@ -13,7 +13,7 @@ def follow(request):
''' follow another user, here or abroad '''
username = request.POST['user']
try:
- to_follow = get_user_from_username(username)
+ to_follow = get_user_from_username(request.user, username)
except models.User.DoesNotExist:
return HttpResponseBadRequest()
@@ -33,7 +33,7 @@ def unfollow(request):
''' unfollow a user '''
username = request.POST['user']
try:
- to_unfollow = get_user_from_username(username)
+ to_unfollow = get_user_from_username(request.user, username)
except models.User.DoesNotExist:
return HttpResponseBadRequest()
@@ -52,7 +52,7 @@ def accept_follow_request(request):
''' a user accepts a follow request '''
username = request.POST['user']
try:
- requester = get_user_from_username(username)
+ requester = get_user_from_username(request.user, username)
except models.User.DoesNotExist:
return HttpResponseBadRequest()
@@ -75,7 +75,7 @@ def delete_follow_request(request):
''' a user rejects a follow request '''
username = request.POST['user']
try:
- requester = get_user_from_username(username)
+ requester = get_user_from_username(request.user, username)
except models.User.DoesNotExist:
return HttpResponseBadRequest()
diff --git a/bookwyrm/views/goal.py b/bookwyrm/views/goal.py
index 4f2d1b6f4..97f139136 100644
--- a/bookwyrm/views/goal.py
+++ b/bookwyrm/views/goal.py
@@ -18,7 +18,7 @@ class Goal(View):
''' track books for the year '''
def get(self, request, username, year):
''' reading goal page '''
- user = get_user_from_username(username)
+ user = get_user_from_username(request.user, username)
year = int(year)
goal = models.AnnualGoal.objects.filter(
year=year, user=user
@@ -42,7 +42,7 @@ class Goal(View):
def post(self, request, username, year):
''' update or create an annual goal '''
- user = get_user_from_username(username)
+ user = get_user_from_username(request.user, username)
if user != request.user:
return HttpResponseNotFound()
diff --git a/bookwyrm/views/helpers.py b/bookwyrm/views/helpers.py
index 842b8d1c4..fac3ab0c6 100644
--- a/bookwyrm/views/helpers.py
+++ b/bookwyrm/views/helpers.py
@@ -9,13 +9,13 @@ from bookwyrm.status import create_generated_note
from bookwyrm.utils import regex
-def get_user_from_username(username):
+def get_user_from_username(viewer, username):
''' helper function to resolve a localname or a username to a user '''
# raises DoesNotExist if user is now found
try:
- return models.User.objects.get(localname=username)
+ return models.User.viewer_aware_objects(viewer).get(localname=username)
except models.User.DoesNotExist:
- return models.User.objects.get(username=username)
+ return models.User.viewer_aware_objects(viewer).get(username=username)
def is_api_request(request):
@@ -24,8 +24,8 @@ def is_api_request(request):
request.path[-5:] == '.json'
-def is_bookworm_request(request):
- ''' check if the request is coming from another bookworm instance '''
+def is_bookwyrm_request(request):
+ ''' check if the request is coming from another bookwyrm instance '''
user_agent = request.headers.get('User-Agent')
if user_agent is None or \
re.search(regex.bookwyrm_user_agent, user_agent) is None:
diff --git a/bookwyrm/views/invite.py b/bookwyrm/views/invite.py
index bd0715a0b..6b3611fc1 100644
--- a/bookwyrm/views/invite.py
+++ b/bookwyrm/views/invite.py
@@ -1,5 +1,6 @@
''' invites when registration is closed '''
from django.contrib.auth.decorators import login_required, permission_required
+from django.core.paginator import Paginator
from django.http import HttpResponseBadRequest
from django.shortcuts import get_object_or_404, redirect
from django.template.response import TemplateResponse
@@ -7,6 +8,7 @@ from django.utils.decorators import method_decorator
from django.views import View
from bookwyrm import forms, models
+from bookwyrm.settings import PAGE_LENGTH
# pylint: disable= no-self-use
@@ -18,10 +20,18 @@ class ManageInvites(View):
''' create invites '''
def get(self, request):
''' invite management page '''
+ try:
+ page = int(request.GET.get('page', 1))
+ except ValueError:
+ page = 1
+
+ paginated = Paginator(models.SiteInvite.objects.filter(
+ user=request.user
+ ).order_by('-created_date'), PAGE_LENGTH)
+
data = {
'title': 'Invitations',
- 'invites': models.SiteInvite.objects.filter(
- user=request.user).order_by('-created_date'),
+ 'invites': paginated.page(page),
'form': forms.CreateInviteForm(),
}
return TemplateResponse(request, 'settings/manage_invites.html', data)
@@ -36,7 +46,15 @@ class ManageInvites(View):
invite.user = request.user
invite.save()
- return redirect('/settings/invites')
+ paginated = Paginator(models.SiteInvite.objects.filter(
+ user=request.user
+ ).order_by('-created_date'), PAGE_LENGTH)
+ data = {
+ 'title': 'Invitations',
+ 'invites': paginated.page(1),
+ 'form': form
+ }
+ return TemplateResponse(request, 'settings/manage_invites.html', data)
class Invite(View):
diff --git a/bookwyrm/views/landing.py b/bookwyrm/views/landing.py
index 0d841ef04..3be3eb312 100644
--- a/bookwyrm/views/landing.py
+++ b/bookwyrm/views/landing.py
@@ -16,7 +16,7 @@ class About(View):
data = {
'title': 'About',
}
- return TemplateResponse(request, 'about.html', data)
+ return TemplateResponse(request, 'discover/about.html', data)
class Home(View):
''' discover page or home feed depending on auth '''
@@ -56,4 +56,4 @@ class Discover(View):
'books': list(set(books)),
'ratings': ratings
}
- return TemplateResponse(request, 'discover.html', data)
+ return TemplateResponse(request, 'discover/discover.html', data)
diff --git a/bookwyrm/views/list.py b/bookwyrm/views/list.py
index cfdf6d769..7286bfb4f 100644
--- a/bookwyrm/views/list.py
+++ b/bookwyrm/views/list.py
@@ -65,7 +65,7 @@ class UserLists(View):
page = int(request.GET.get('page', 1))
except ValueError:
page = 1
- user = get_user_from_username(username)
+ user = get_user_from_username(request.user, username)
lists = models.List.objects.filter(user=user).all()
lists = privacy_filter(
request.user, lists, ['public', 'followers', 'unlisted'])
diff --git a/bookwyrm/views/outbox.py b/bookwyrm/views/outbox.py
index 8bfc3b3d4..5df9d1999 100644
--- a/bookwyrm/views/outbox.py
+++ b/bookwyrm/views/outbox.py
@@ -4,6 +4,7 @@ from django.shortcuts import get_object_or_404
from django.views import View
from bookwyrm import activitypub, models
+from .helpers import is_bookwyrm_request
# pylint: disable= no-self-use
@@ -17,6 +18,10 @@ class Outbox(View):
filter_type = None
return JsonResponse(
- user.to_outbox(**request.GET, filter_type=filter_type),
+ user.to_outbox(
+ **request.GET,
+ filter_type=filter_type,
+ pure=not is_bookwyrm_request(request)
+ ),
encoder=activitypub.ActivityEncoder
)
diff --git a/bookwyrm/views/rss_feed.py b/bookwyrm/views/rss_feed.py
index 496689ff1..aad227bff 100644
--- a/bookwyrm/views/rss_feed.py
+++ b/bookwyrm/views/rss_feed.py
@@ -11,7 +11,7 @@ class RssFeed(Feed):
def get_object(self, request, username):
''' the user who's posts get serialized '''
- return get_user_from_username(username)
+ return get_user_from_username(request.user, username)
def link(self, obj):
diff --git a/bookwyrm/views/search.py b/bookwyrm/views/search.py
index a4cd73374..98be166f4 100644
--- a/bookwyrm/views/search.py
+++ b/bookwyrm/views/search.py
@@ -33,7 +33,7 @@ class Search(View):
handle_remote_webfinger(query)
# do a user search
- user_results = models.User.objects.annotate(
+ user_results = models.User.viewer_aware_objects(request.user).annotate(
similarity=Greatest(
TrigramSimilarity('username', query),
TrigramSimilarity('localname', query),
diff --git a/bookwyrm/views/shelf.py b/bookwyrm/views/shelf.py
index 02502ff64..70d3d1dea 100644
--- a/bookwyrm/views/shelf.py
+++ b/bookwyrm/views/shelf.py
@@ -19,7 +19,7 @@ class Shelf(View):
def get(self, request, username, shelf_identifier):
''' display a shelf '''
try:
- user = get_user_from_username(username)
+ user = get_user_from_username(request.user, username)
except models.User.DoesNotExist:
return HttpResponseNotFound()
diff --git a/bookwyrm/views/user.py b/bookwyrm/views/user.py
index 4da0fdac1..7a238ce7c 100644
--- a/bookwyrm/views/user.py
+++ b/bookwyrm/views/user.py
@@ -26,7 +26,7 @@ class User(View):
def get(self, request, username):
''' profile page for a user '''
try:
- user = get_user_from_username(username)
+ user = get_user_from_username(request.user, username)
except models.User.DoesNotExist:
return HttpResponseNotFound()
@@ -96,7 +96,7 @@ class Followers(View):
def get(self, request, username):
''' list of followers '''
try:
- user = get_user_from_username(username)
+ user = get_user_from_username(request.user, username)
except models.User.DoesNotExist:
return HttpResponseNotFound()
@@ -121,7 +121,7 @@ class Following(View):
def get(self, request, username):
''' list of followers '''
try:
- user = get_user_from_username(username)
+ user = get_user_from_username(request.user, username)
except models.User.DoesNotExist:
return HttpResponseNotFound()