Following views

This commit is contained in:
Mouse Reeve 2021-01-13 13:05:16 -08:00
parent 7555d76c3f
commit a385aa4cb5
7 changed files with 133 additions and 198 deletions

View file

@ -112,66 +112,6 @@ class Outgoing(TestCase):
self.assertEqual(data['totalItems'], 1) 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): def test_existing_user(self):
''' simple database lookup by username ''' ''' simple database lookup by username '''

View file

@ -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
)

View file

@ -1,32 +1,27 @@
''' test for app action functionality ''' ''' test for app action functionality '''
from unittest.mock import patch from unittest.mock import patch
import dateutil 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 import TestCase
from django.test.client import RequestFactory from django.test.client import RequestFactory
from django.utils import timezone from django.utils import timezone
from bookwyrm import models, view_actions as actions from bookwyrm import models, views
class ReadingViews(TestCase):
#pylint: disable=too-many-public-methods ''' viewing and creating statuses '''
class ViewActions(TestCase):
''' a lot here: all handlers for receiving activitypub requests '''
def setUp(self): 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( self.local_user = models.User.objects.create_user(
'mouse', 'mouse@mouse.com', 'mouseword', 'mouse@local.com', 'mouse@mouse.com', 'mouseword',
local=True, localname='mouse') local=True, localname='mouse',
self.local_user.remote_id = 'https://example.com/user/mouse' remote_id='https://example.com/users/mouse',
self.local_user.save() )
self.group = Group.objects.create(name='editor') self.work = models.Work.objects.create(title='Test Work')
self.group.permissions.add( self.book = models.Edition.objects.create(
Permission.objects.create( title='Test Book',
name='edit_book', remote_id='https://example.com/book/1',
codename='edit_book', parent_work=self.work
content_type=ContentType.objects.get_for_model(models.User)).id
) )
with patch('bookwyrm.models.user.set_remote_server.delay'): with patch('bookwyrm.models.user.set_remote_server.delay'):
self.remote_user = models.User.objects.create_user( self.remote_user = models.User.objects.create_user(
@ -36,17 +31,6 @@ class ViewActions(TestCase):
inbox='https://example.com/users/rat/inbox', inbox='https://example.com/users/rat/inbox',
outbox='https://example.com/users/rat/outbox', 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): def test_edit_readthrough(self):
''' adding dates to an ongoing readthrough ''' ''' adding dates to an ongoing readthrough '''
@ -62,7 +46,7 @@ class ViewActions(TestCase):
}) })
request.user = self.local_user request.user = self.local_user
actions.edit_readthrough(request) views.edit_readthrough(request)
readthrough.refresh_from_db() readthrough.refresh_from_db()
self.assertEqual(readthrough.start_date.year, 2017) self.assertEqual(readthrough.start_date.year, 2017)
self.assertEqual(readthrough.start_date.month, 1) self.assertEqual(readthrough.start_date.month, 1)
@ -85,7 +69,7 @@ class ViewActions(TestCase):
}) })
request.user = self.local_user request.user = self.local_user
actions.delete_readthrough(request) views.delete_readthrough(request)
self.assertFalse( self.assertFalse(
models.ReadThrough.objects.filter(id=readthrough.id).exists()) models.ReadThrough.objects.filter(id=readthrough.id).exists())
@ -101,7 +85,7 @@ class ViewActions(TestCase):
}) })
request.user = self.local_user request.user = self.local_user
actions.create_readthrough(request) views.create_readthrough(request)
readthrough = models.ReadThrough.objects.get() readthrough = models.ReadThrough.objects.get()
self.assertEqual(readthrough.start_date.year, 2017) self.assertEqual(readthrough.start_date.year, 2017)
self.assertEqual(readthrough.start_date.month, 1) self.assertEqual(readthrough.start_date.month, 1)

View file

@ -4,7 +4,6 @@ from django.contrib import admin
from django.urls import path, re_path from django.urls import path, re_path
from bookwyrm import incoming, outgoing, settings, views, wellknown from bookwyrm import incoming, outgoing, settings, views, wellknown
from bookwyrm import view_actions as actions
from bookwyrm.utils import regex from bookwyrm.utils import regex
user_path = r'^user/(?P<username>%s)' % regex.username user_path = r'^user/(?P<username>%s)' % regex.username
@ -128,8 +127,8 @@ urlpatterns = [
re_path(r'^finish-reading/(?P<book_id>\d+)/?$', views.finish_reading), re_path(r'^finish-reading/(?P<book_id>\d+)/?$', views.finish_reading),
# following # following
re_path(r'^follow/?$', actions.follow), re_path(r'^follow/?$', views.follow),
re_path(r'^unfollow/?$', actions.unfollow), re_path(r'^unfollow/?$', views.unfollow),
re_path(r'^accept-follow-request/?$', actions.accept_follow_request), re_path(r'^accept-follow-request/?$', views.accept_follow_request),
re_path(r'^delete-follow-request/?$', actions.delete_follow_request), re_path(r'^delete-follow-request/?$', views.delete_follow_request),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) ] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

View file

@ -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)

View file

@ -5,6 +5,8 @@ from .books import Book, EditBook, Editions
from .books import upload_cover, add_description, switch_edition, resolve_book from .books import upload_cover, add_description, switch_edition, resolve_book
from .direct_message import DirectMessage from .direct_message import DirectMessage
from .error import not_found_page, server_error_page 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 .import_data import Import, ImportStatus
from .interaction import Favorite, Unfavorite, Boost, Unboost from .interaction import Favorite, Unfavorite, Boost, Unboost
from .invite import ManageInvites, Invite from .invite import ManageInvites, Invite

View file

@ -10,7 +10,8 @@ from django.views.decorators.http import require_POST
from bookwyrm import models from bookwyrm import models
from bookwyrm.broadcast import broadcast 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 # pylint: disable= no-self-use