From a385aa4cb54ad801ed39132e0f69434de73afc1b Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Wed, 13 Jan 2021 13:05:16 -0800 Subject: [PATCH] Following views --- bookwyrm/tests/test_outgoing.py | 60 ---------- bookwyrm/tests/views/test_follow.py | 108 ++++++++++++++++++ .../test_reading.py} | 50 +++----- bookwyrm/urls.py | 9 +- bookwyrm/view_actions.py | 99 ---------------- bookwyrm/views/__init__.py | 2 + bookwyrm/views/reading.py | 3 +- 7 files changed, 133 insertions(+), 198 deletions(-) create mode 100644 bookwyrm/tests/views/test_follow.py rename bookwyrm/tests/{test_view_actions.py => views/test_reading.py} (71%) diff --git a/bookwyrm/tests/test_outgoing.py b/bookwyrm/tests/test_outgoing.py index 78caa93a3..6cd84070c 100644 --- a/bookwyrm/tests/test_outgoing.py +++ b/bookwyrm/tests/test_outgoing.py @@ -112,66 +112,6 @@ class Outgoing(TestCase): self.assertEqual(data['totalItems'], 1) - def test_handle_follow(self): - ''' send a follow request ''' - self.assertEqual(models.UserFollowRequest.objects.count(), 0) - - with patch('bookwyrm.broadcast.broadcast_task.delay'): - outgoing.handle_follow(self.local_user, self.remote_user) - - rel = models.UserFollowRequest.objects.get() - - self.assertEqual(rel.user_subject, self.local_user) - self.assertEqual(rel.user_object, self.remote_user) - self.assertEqual(rel.status, 'follow_request') - - - def test_handle_unfollow(self): - ''' send an unfollow ''' - self.remote_user.followers.add(self.local_user) - self.assertEqual(self.remote_user.followers.count(), 1) - with patch('bookwyrm.broadcast.broadcast_task.delay'): - outgoing.handle_unfollow(self.local_user, self.remote_user) - - self.assertEqual(self.remote_user.followers.count(), 0) - - - def test_handle_accept(self): - ''' accept a follow request ''' - rel = models.UserFollowRequest.objects.create( - user_subject=self.local_user, - user_object=self.remote_user - ) - rel_id = rel.id - - with patch('bookwyrm.broadcast.broadcast_task.delay'): - outgoing.handle_accept(rel) - # request should be deleted - self.assertEqual( - models.UserFollowRequest.objects.filter(id=rel_id).count(), 0 - ) - # follow relationship should exist - self.assertEqual(self.remote_user.followers.first(), self.local_user) - - - def test_handle_reject(self): - ''' reject a follow request ''' - rel = models.UserFollowRequest.objects.create( - user_subject=self.local_user, - user_object=self.remote_user - ) - rel_id = rel.id - - with patch('bookwyrm.broadcast.broadcast_task.delay'): - outgoing.handle_reject(rel) - # request should be deleted - self.assertEqual( - models.UserFollowRequest.objects.filter(id=rel_id).count(), 0 - ) - # follow relationship should not exist - self.assertEqual( - models.UserFollows.objects.filter(id=rel_id).count(), 0 - ) def test_existing_user(self): ''' simple database lookup by username ''' diff --git a/bookwyrm/tests/views/test_follow.py b/bookwyrm/tests/views/test_follow.py new file mode 100644 index 000000000..9bbf67fbb --- /dev/null +++ b/bookwyrm/tests/views/test_follow.py @@ -0,0 +1,108 @@ +''' test for app action functionality ''' +from unittest.mock import patch +from django.contrib.auth.models import Group, Permission +from django.contrib.contenttypes.models import ContentType +from django.test import TestCase +from django.test.client import RequestFactory + +from bookwyrm import models, views + + +class BookViews(TestCase): + ''' books books books ''' + def setUp(self): + ''' we need basic test data and mocks ''' + self.factory = RequestFactory() + self.local_user = models.User.objects.create_user( + 'mouse@local.com', 'mouse@mouse.com', 'mouseword', + local=True, localname='mouse', + remote_id='https://example.com/users/mouse', + ) + with patch('bookwyrm.models.user.set_remote_server'): + self.remote_user = models.User.objects.create_user( + 'rat', 'rat@email.com', 'ratword', + local=False, + remote_id='https://example.com/users/rat', + inbox='https://example.com/users/rat/inbox', + outbox='https://example.com/users/rat/outbox', + ) + self.group = Group.objects.create(name='editor') + self.group.permissions.add( + Permission.objects.create( + name='edit_book', + codename='edit_book', + content_type=ContentType.objects.get_for_model(models.User)).id + ) + self.work = models.Work.objects.create(title='Test Work') + self.book = models.Edition.objects.create( + title='Example Edition', + remote_id='https://example.com/book/1', + parent_work=self.work + ) + + def test_handle_follow(self): + ''' send a follow request ''' + request = self.factory.post('', {'user': self.remote_user.username}) + request.user = self.local_user + self.assertEqual(models.UserFollowRequest.objects.count(), 0) + + with patch('bookwyrm.broadcast.broadcast_task.delay'): + views.follow(request) + + rel = models.UserFollowRequest.objects.get() + + self.assertEqual(rel.user_subject, self.local_user) + self.assertEqual(rel.user_object, self.remote_user) + self.assertEqual(rel.status, 'follow_request') + + + def test_handle_unfollow(self): + ''' send an unfollow ''' + request = self.factory.post('', {'user': self.remote_user.username}) + request.user = self.local_user + self.remote_user.followers.add(self.local_user) + self.assertEqual(self.remote_user.followers.count(), 1) + with patch('bookwyrm.broadcast.broadcast_task.delay'): + views.unfollow(request) + + self.assertEqual(self.remote_user.followers.count(), 0) + + + def test_handle_accept(self): + ''' accept a follow request ''' + request = self.factory.post('', {'user': self.remote_user.username}) + request.user = self.local_user + rel = models.UserFollowRequest.objects.create( + user_subject=self.remote_user, + user_object=self.local_user + ) + + with patch('bookwyrm.broadcast.broadcast_task.delay'): + views.accept_follow_request(request) + # request should be deleted + self.assertEqual( + models.UserFollowRequest.objects.filter(id=rel.id).count(), 0 + ) + # follow relationship should exist + self.assertEqual(self.local_user.followers.first(), self.remote_user) + + + def test_handle_reject(self): + ''' reject a follow request ''' + request = self.factory.post('', {'user': self.remote_user.username}) + request.user = self.local_user + rel = models.UserFollowRequest.objects.create( + user_subject=self.remote_user, + user_object=self.local_user + ) + + with patch('bookwyrm.broadcast.broadcast_task.delay'): + views.delete_follow_request(request) + # request should be deleted + self.assertEqual( + models.UserFollowRequest.objects.filter(id=rel.id).count(), 0 + ) + # follow relationship should not exist + self.assertEqual( + models.UserFollows.objects.filter(id=rel.id).count(), 0 + ) diff --git a/bookwyrm/tests/test_view_actions.py b/bookwyrm/tests/views/test_reading.py similarity index 71% rename from bookwyrm/tests/test_view_actions.py rename to bookwyrm/tests/views/test_reading.py index 11fefae4e..f5e4cd526 100644 --- a/bookwyrm/tests/test_view_actions.py +++ b/bookwyrm/tests/views/test_reading.py @@ -1,32 +1,27 @@ ''' test for app action functionality ''' from unittest.mock import patch - import dateutil -from django.contrib.auth.models import Group, Permission -from django.contrib.contenttypes.models import ContentType from django.test import TestCase from django.test.client import RequestFactory from django.utils import timezone -from bookwyrm import models, view_actions as actions +from bookwyrm import models, views - -#pylint: disable=too-many-public-methods -class ViewActions(TestCase): - ''' a lot here: all handlers for receiving activitypub requests ''' +class ReadingViews(TestCase): + ''' viewing and creating statuses ''' def setUp(self): - ''' we need basic things, like users ''' + ''' we need basic test data and mocks ''' + self.factory = RequestFactory() self.local_user = models.User.objects.create_user( - 'mouse', 'mouse@mouse.com', 'mouseword', - local=True, localname='mouse') - self.local_user.remote_id = 'https://example.com/user/mouse' - self.local_user.save() - self.group = Group.objects.create(name='editor') - self.group.permissions.add( - Permission.objects.create( - name='edit_book', - codename='edit_book', - content_type=ContentType.objects.get_for_model(models.User)).id + 'mouse@local.com', 'mouse@mouse.com', 'mouseword', + local=True, localname='mouse', + remote_id='https://example.com/users/mouse', + ) + self.work = models.Work.objects.create(title='Test Work') + self.book = models.Edition.objects.create( + title='Test Book', + remote_id='https://example.com/book/1', + parent_work=self.work ) with patch('bookwyrm.models.user.set_remote_server.delay'): self.remote_user = models.User.objects.create_user( @@ -36,17 +31,6 @@ class ViewActions(TestCase): inbox='https://example.com/users/rat/inbox', outbox='https://example.com/users/rat/outbox', ) - self.status = models.Status.objects.create( - user=self.local_user, - content='Test status', - remote_id='https://example.com/status/1', - ) - self.work = models.Work.objects.create(title='Test Work') - self.book = models.Edition.objects.create( - title='Test Book', parent_work=self.work) - self.settings = models.SiteSettings.objects.create(id=1) - self.factory = RequestFactory() - def test_edit_readthrough(self): ''' adding dates to an ongoing readthrough ''' @@ -62,7 +46,7 @@ class ViewActions(TestCase): }) request.user = self.local_user - actions.edit_readthrough(request) + views.edit_readthrough(request) readthrough.refresh_from_db() self.assertEqual(readthrough.start_date.year, 2017) self.assertEqual(readthrough.start_date.month, 1) @@ -85,7 +69,7 @@ class ViewActions(TestCase): }) request.user = self.local_user - actions.delete_readthrough(request) + views.delete_readthrough(request) self.assertFalse( models.ReadThrough.objects.filter(id=readthrough.id).exists()) @@ -101,7 +85,7 @@ class ViewActions(TestCase): }) request.user = self.local_user - actions.create_readthrough(request) + views.create_readthrough(request) readthrough = models.ReadThrough.objects.get() self.assertEqual(readthrough.start_date.year, 2017) self.assertEqual(readthrough.start_date.month, 1) diff --git a/bookwyrm/urls.py b/bookwyrm/urls.py index 96fcd2c52..c6ada37f6 100644 --- a/bookwyrm/urls.py +++ b/bookwyrm/urls.py @@ -4,7 +4,6 @@ from django.contrib import admin from django.urls import path, re_path from bookwyrm import incoming, outgoing, settings, views, wellknown -from bookwyrm import view_actions as actions from bookwyrm.utils import regex user_path = r'^user/(?P%s)' % regex.username @@ -128,8 +127,8 @@ urlpatterns = [ re_path(r'^finish-reading/(?P\d+)/?$', views.finish_reading), # following - re_path(r'^follow/?$', actions.follow), - re_path(r'^unfollow/?$', actions.unfollow), - re_path(r'^accept-follow-request/?$', actions.accept_follow_request), - re_path(r'^delete-follow-request/?$', actions.delete_follow_request), + re_path(r'^follow/?$', views.follow), + re_path(r'^unfollow/?$', views.unfollow), + re_path(r'^accept-follow-request/?$', views.accept_follow_request), + re_path(r'^delete-follow-request/?$', views.delete_follow_request), ] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) diff --git a/bookwyrm/view_actions.py b/bookwyrm/view_actions.py index 505062033..e69de29bb 100644 --- a/bookwyrm/view_actions.py +++ b/bookwyrm/view_actions.py @@ -1,99 +0,0 @@ -''' views for actions you can take in the application ''' -from django.contrib.auth.decorators import login_required -from django.http import HttpResponseBadRequest, HttpResponseNotFound -from django.shortcuts import get_object_or_404, redirect -from django.views.decorators.http import require_POST - -from bookwyrm import models, outgoing - -def get_edition(book_id): - ''' look up a book in the db and return an edition ''' - book = models.Book.objects.select_subclasses().get(id=book_id) - if isinstance(book, models.Work): - book = book.get_default_edition() - return book - -def get_user_from_username(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) - except models.User.DoesNotExist: - return models.User.objects.get(username=username) - -@login_required -@require_POST -def follow(request): - ''' follow another user, here or abroad ''' - username = request.POST['user'] - try: - to_follow = get_user_from_username(username) - except models.User.DoesNotExist: - return HttpResponseBadRequest() - - outgoing.handle_follow(request.user, to_follow) - user_slug = to_follow.localname if to_follow.localname \ - else to_follow.username - return redirect('/user/%s' % user_slug) - - -@login_required -@require_POST -def unfollow(request): - ''' unfollow a user ''' - username = request.POST['user'] - try: - to_unfollow = get_user_from_username(username) - except models.User.DoesNotExist: - return HttpResponseBadRequest() - - outgoing.handle_unfollow(request.user, to_unfollow) - user_slug = to_unfollow.localname if to_unfollow.localname \ - else to_unfollow.username - return redirect('/user/%s' % user_slug) - - -@login_required -@require_POST -def accept_follow_request(request): - ''' a user accepts a follow request ''' - username = request.POST['user'] - try: - requester = get_user_from_username(username) - except models.User.DoesNotExist: - return HttpResponseBadRequest() - - try: - follow_request = models.UserFollowRequest.objects.get( - user_subject=requester, - user_object=request.user - ) - except models.UserFollowRequest.DoesNotExist: - # Request already dealt with. - pass - else: - outgoing.handle_accept(follow_request) - - return redirect('/user/%s' % request.user.localname) - - -@login_required -@require_POST -def delete_follow_request(request): - ''' a user rejects a follow request ''' - username = request.POST['user'] - try: - requester = get_user_from_username(username) - except models.User.DoesNotExist: - return HttpResponseBadRequest() - - try: - follow_request = models.UserFollowRequest.objects.get( - user_subject=requester, - user_object=request.user - ) - except models.UserFollowRequest.DoesNotExist: - return HttpResponseBadRequest() - - outgoing.handle_reject(follow_request) - return redirect('/user/%s' % request.user.localname) diff --git a/bookwyrm/views/__init__.py b/bookwyrm/views/__init__.py index 38b03f48d..7c050339a 100644 --- a/bookwyrm/views/__init__.py +++ b/bookwyrm/views/__init__.py @@ -5,6 +5,8 @@ from .books import Book, EditBook, Editions from .books import upload_cover, add_description, switch_edition, resolve_book from .direct_message import DirectMessage from .error import not_found_page, server_error_page +from .follow import follow, unfollow +from .follow import accept_follow_request, delete_follow_request from .import_data import Import, ImportStatus from .interaction import Favorite, Unfavorite, Boost, Unboost from .invite import ManageInvites, Invite diff --git a/bookwyrm/views/reading.py b/bookwyrm/views/reading.py index 51fb2419b..51c3217e4 100644 --- a/bookwyrm/views/reading.py +++ b/bookwyrm/views/reading.py @@ -10,7 +10,8 @@ from django.views.decorators.http import require_POST from bookwyrm import models from bookwyrm.broadcast import broadcast -from .helpers import get_edition, handle_reading_status, handle_unshelve +from .helpers import get_edition, handle_reading_status +from .shelf import handle_unshelve # pylint: disable= no-self-use