mirror of
https://github.com/bookwyrm-social/bookwyrm.git
synced 2024-12-16 13:16:33 +00:00
Following views
This commit is contained in:
parent
7555d76c3f
commit
a385aa4cb5
7 changed files with 133 additions and 198 deletions
|
@ -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 '''
|
||||||
|
|
108
bookwyrm/tests/views/test_follow.py
Normal file
108
bookwyrm/tests/views/test_follow.py
Normal 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
|
||||||
|
)
|
|
@ -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)
|
|
@ -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)
|
||||||
|
|
|
@ -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)
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue