moviewyrm/bookwyrm/tests/views/test_status.py

401 lines
15 KiB
Python
Raw Normal View History

2021-03-08 16:49:10 +00:00
""" test for app action functionality """
2021-02-24 18:07:03 +00:00
import json
2021-01-12 22:02:38 +00:00
from unittest.mock import patch
from django.test import TestCase
from django.test.client import RequestFactory
from bookwyrm import forms, models, views
from bookwyrm.settings import DOMAIN
2021-07-07 16:47:07 +00:00
# pylint: disable=invalid-name
2021-08-03 17:25:53 +00:00
@patch("bookwyrm.suggested_users.rerank_suggestions_task.delay")
2021-09-06 21:50:33 +00:00
@patch("bookwyrm.activitystreams.populate_stream_task.delay")
2021-09-06 23:59:58 +00:00
@patch("bookwyrm.activitystreams.remove_status_task.delay")
2021-08-03 23:21:29 +00:00
@patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay")
2021-01-12 22:02:38 +00:00
class StatusViews(TestCase):
2021-04-26 16:15:42 +00:00
"""viewing and creating statuses"""
2021-03-08 16:49:10 +00:00
2021-01-12 22:02:38 +00:00
def setUp(self):
2021-04-26 16:15:42 +00:00
"""we need basic test data and mocks"""
2021-01-12 22:02:38 +00:00
self.factory = RequestFactory()
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
"bookwyrm.activitystreams.populate_stream_task.delay"
):
2021-08-03 17:25:53 +00:00
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",
)
2021-08-02 23:05:40 +00:00
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",
2021-05-26 21:57:29 +00:00
)
2021-01-12 22:43:59 +00:00
2021-08-02 23:05:40 +00:00
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=work,
)
models.SiteSettings.objects.create()
2021-01-12 22:02:38 +00:00
2021-08-03 17:25:53 +00:00
def test_handle_status(self, *_):
2021-04-26 16:15:42 +00:00
"""create a status"""
2021-01-12 22:02:38 +00:00
view = views.CreateStatus.as_view()
2021-03-08 16:49:10 +00:00
form = forms.CommentForm(
{
"content": "hi",
"user": self.local_user.id,
"book": self.book.id,
"privacy": "public",
}
)
request = self.factory.post("", form.data)
2021-01-12 22:02:38 +00:00
request.user = self.local_user
2021-09-07 01:39:14 +00:00
view(request, "comment")
2021-03-23 15:13:57 +00:00
2021-01-12 22:02:38 +00:00
status = models.Comment.objects.get()
2021-03-08 16:49:10 +00:00
self.assertEqual(status.content, "<p>hi</p>")
2021-01-12 22:02:38 +00:00
self.assertEqual(status.user, self.local_user)
self.assertEqual(status.book, self.book)
2021-08-03 17:25:53 +00:00
def test_handle_status_reply(self, *_):
2021-04-26 16:15:42 +00:00
"""create a status in reply to an existing status"""
2021-01-12 22:02:38 +00:00
view = views.CreateStatus.as_view()
2021-08-02 23:05:40 +00:00
user = models.User.objects.create_user(
"rat", "rat@rat.com", "password", local=True
)
2021-09-07 01:39:14 +00:00
parent = models.Status.objects.create(
content="parent status", user=self.local_user
)
2021-03-08 16:49:10 +00:00
form = forms.ReplyForm(
{
"content": "hi",
"user": user.id,
"reply_parent": parent.id,
"privacy": "public",
}
)
request = self.factory.post("", form.data)
2021-01-12 22:43:59 +00:00
request.user = user
2021-09-07 01:39:14 +00:00
view(request, "reply")
2021-03-23 15:13:57 +00:00
2021-01-12 22:02:38 +00:00
status = models.Status.objects.get(user=user)
2021-03-08 16:49:10 +00:00
self.assertEqual(status.content, "<p>hi</p>")
2021-01-12 22:02:38 +00:00
self.assertEqual(status.user, user)
2021-03-08 16:49:10 +00:00
self.assertEqual(models.Notification.objects.get().user, self.local_user)
2021-01-12 22:02:38 +00:00
2021-08-03 17:25:53 +00:00
def test_handle_status_mentions(self, *_):
2021-04-26 16:15:42 +00:00
"""@mention a user in a post"""
2021-01-12 22:02:38 +00:00
view = views.CreateStatus.as_view()
2021-08-02 23:05:40 +00:00
user = models.User.objects.create_user(
f"rat@{DOMAIN}",
2021-08-02 23:05:40 +00:00
"rat@rat.com",
"password",
local=True,
localname="rat",
)
2021-03-08 16:49:10 +00:00
form = forms.CommentForm(
{
"content": "hi @rat",
"user": self.local_user.id,
"book": self.book.id,
"privacy": "public",
}
)
request = self.factory.post("", form.data)
2021-01-12 22:02:38 +00:00
request.user = self.local_user
2021-09-07 01:39:14 +00:00
view(request, "comment")
2021-03-23 15:13:57 +00:00
2021-01-12 22:02:38 +00:00
status = models.Status.objects.get()
self.assertEqual(list(status.mention_users.all()), [user])
self.assertEqual(models.Notification.objects.get().user, user)
self.assertEqual(
status.content, f'<p>hi <a href="{user.remote_id}">@rat</a></p>'
2021-03-08 16:49:10 +00:00
)
2021-01-12 22:02:38 +00:00
2021-08-03 17:25:53 +00:00
def test_handle_status_reply_with_mentions(self, *_):
2021-04-26 16:15:42 +00:00
"""reply to a post with an @mention'ed user"""
2021-01-12 22:02:38 +00:00
view = views.CreateStatus.as_view()
2021-08-02 23:05:40 +00:00
user = models.User.objects.create_user(
"rat", "rat@rat.com", "password", local=True, localname="rat"
)
2021-03-08 16:49:10 +00:00
form = forms.CommentForm(
{
"content": "hi @rat@example.com",
"user": self.local_user.id,
"book": self.book.id,
"privacy": "public",
}
)
request = self.factory.post("", form.data)
2021-01-12 22:02:38 +00:00
request.user = self.local_user
2021-09-07 01:39:14 +00:00
view(request, "comment")
2021-01-12 22:02:38 +00:00
status = models.Status.objects.get()
2021-03-08 16:49:10 +00:00
form = forms.ReplyForm(
{
"content": "right",
"user": user.id,
"privacy": "public",
"reply_parent": status.id,
}
)
request = self.factory.post("", form.data)
2021-01-12 22:43:59 +00:00
request.user = user
2021-09-07 01:39:14 +00:00
view(request, "reply")
2021-03-23 15:13:57 +00:00
2021-01-12 22:02:38 +00:00
reply = models.Status.replies(status).first()
2021-03-08 16:49:10 +00:00
self.assertEqual(reply.content, "<p>right</p>")
2021-01-12 22:02:38 +00:00
self.assertEqual(reply.user, user)
2021-01-27 17:31:01 +00:00
# the mentioned user in the parent post is only included if @'ed
self.assertFalse(self.remote_user in reply.mention_users.all())
2021-01-12 22:02:38 +00:00
self.assertTrue(self.local_user in reply.mention_users.all())
2021-08-03 17:25:53 +00:00
def test_delete_and_redraft(self, *_):
2021-04-26 16:15:42 +00:00
"""delete and re-draft a status"""
2021-04-04 16:45:25 +00:00
view = views.DeleteAndRedraft.as_view()
request = self.factory.post("")
request.user = self.local_user
2021-09-07 01:39:14 +00:00
status = models.Comment.objects.create(
content="hi", book=self.book, user=self.local_user
)
2021-04-04 16:45:25 +00:00
2021-09-07 01:39:14 +00:00
with patch("bookwyrm.activitystreams.remove_status_task.delay") as mock:
2021-04-04 16:45:25 +00:00
result = view(request, status.id)
self.assertTrue(mock.called)
result.render()
# make sure it was deleted
status.refresh_from_db()
self.assertTrue(status.deleted)
2021-08-03 17:25:53 +00:00
def test_delete_and_redraft_invalid_status_type_rating(self, *_):
2021-04-26 16:15:42 +00:00
"""you can't redraft generated statuses"""
2021-04-04 16:45:25 +00:00
view = views.DeleteAndRedraft.as_view()
request = self.factory.post("")
request.user = self.local_user
2021-09-06 20:53:49 +00:00
with patch("bookwyrm.activitystreams.add_status_task.delay"):
2021-08-02 23:05:40 +00:00
status = models.ReviewRating.objects.create(
book=self.book, rating=2.0, user=self.local_user
)
2021-04-04 16:45:25 +00:00
2021-09-07 01:39:14 +00:00
with patch("bookwyrm.activitystreams.remove_status_task.delay") as mock:
2021-04-04 16:45:25 +00:00
result = view(request, status.id)
self.assertFalse(mock.called)
self.assertEqual(result.status_code, 400)
status.refresh_from_db()
self.assertFalse(status.deleted)
2021-08-03 17:25:53 +00:00
def test_delete_and_redraft_invalid_status_type_generated_note(self, *_):
2021-04-26 16:15:42 +00:00
"""you can't redraft generated statuses"""
2021-04-04 16:45:25 +00:00
view = views.DeleteAndRedraft.as_view()
request = self.factory.post("")
request.user = self.local_user
2021-09-06 20:53:49 +00:00
with patch("bookwyrm.activitystreams.add_status_task.delay"):
2021-04-04 16:45:25 +00:00
status = models.GeneratedNote.objects.create(
content="hi", user=self.local_user
)
2021-09-07 01:39:14 +00:00
with patch("bookwyrm.activitystreams.remove_status_task.delay") as mock:
2021-04-04 16:45:25 +00:00
result = view(request, status.id)
self.assertFalse(mock.called)
self.assertEqual(result.status_code, 400)
status.refresh_from_db()
self.assertFalse(status.deleted)
2021-08-03 17:25:53 +00:00
def test_find_mentions(self, *_):
2021-04-26 16:15:42 +00:00
"""detect and look up @ mentions of users"""
2021-08-02 23:05:40 +00:00
user = models.User.objects.create_user(
f"nutria@{DOMAIN}",
2021-08-02 23:05:40 +00:00
"nutria@nutria.com",
"password",
local=True,
localname="nutria",
)
self.assertEqual(user.username, f"nutria@{DOMAIN}")
2021-01-12 22:02:38 +00:00
self.assertEqual(
2021-03-08 16:49:10 +00:00
list(views.status.find_mentions("@nutria"))[0], ("@nutria", user)
2021-01-12 22:02:38 +00:00
)
self.assertEqual(
2021-03-08 16:49:10 +00:00
list(views.status.find_mentions("leading text @nutria"))[0],
("@nutria", user),
2021-01-12 22:02:38 +00:00
)
self.assertEqual(
2021-03-08 16:49:10 +00:00
list(views.status.find_mentions("leading @nutria trailing text"))[0],
("@nutria", user),
2021-01-12 22:02:38 +00:00
)
self.assertEqual(
2021-03-08 16:49:10 +00:00
list(views.status.find_mentions("@rat@example.com"))[0],
("@rat@example.com", self.remote_user),
2021-01-12 22:02:38 +00:00
)
2021-03-08 16:49:10 +00:00
multiple = list(views.status.find_mentions("@nutria and @rat@example.com"))
self.assertEqual(multiple[0], ("@nutria", user))
self.assertEqual(multiple[1], ("@rat@example.com", self.remote_user))
2021-01-12 22:02:38 +00:00
2021-03-08 16:49:10 +00:00
with patch("bookwyrm.views.status.handle_remote_webfinger") as rw:
2021-01-12 22:02:38 +00:00
rw.return_value = self.local_user
self.assertEqual(
2021-03-08 16:49:10 +00:00
list(views.status.find_mentions("@beep@beep.com"))[0],
("@beep@beep.com", self.local_user),
2021-01-12 22:02:38 +00:00
)
2021-03-08 16:49:10 +00:00
with patch("bookwyrm.views.status.handle_remote_webfinger") as rw:
2021-01-12 22:02:38 +00:00
rw.return_value = None
2021-03-08 16:49:10 +00:00
self.assertEqual(list(views.status.find_mentions("@beep@beep.com")), [])
2021-01-12 22:02:38 +00:00
self.assertEqual(
list(views.status.find_mentions(f"@nutria@{DOMAIN}"))[0],
(f"@nutria@{DOMAIN}", user),
2021-01-12 22:02:38 +00:00
)
def test_format_links_simple_url(self, *_):
2021-04-26 16:15:42 +00:00
"""find and format urls into a tags"""
2021-03-08 16:49:10 +00:00
url = "http://www.fish.com/"
2021-01-12 22:02:38 +00:00
self.assertEqual(
views.status.format_links(url), f'<a href="{url}">www.fish.com/</a>'
2021-03-08 16:49:10 +00:00
)
2021-01-12 22:02:38 +00:00
self.assertEqual(
views.status.format_links(f"({url})"),
f'(<a href="{url}">www.fish.com/</a>)',
2021-03-08 16:49:10 +00:00
)
def test_format_links_paragraph_break(self, *_):
"""find and format urls into a tags"""
url = """okay
http://www.fish.com/"""
self.assertEqual(
views.status.format_links(url),
'okay\n\n<a href="http://www.fish.com/">www.fish.com/</a>',
)
def test_format_links_parens(self, *_):
"""find and format urls into a tags"""
url = "http://www.fish.com/"
self.assertEqual(
views.status.format_links(f"({url})"),
f'(<a href="{url}">www.fish.com/</a>)',
)
def test_format_links_special_chars(self, *_):
"""find and format urls into a tags"""
2021-03-08 16:49:10 +00:00
url = "https://archive.org/details/dli.granth.72113/page/n25/mode/2up"
2021-01-12 22:02:38 +00:00
self.assertEqual(
views.status.format_links(url),
f'<a href="{url}">'
"archive.org/details/dli.granth.72113/page/n25/mode/2up</a>",
2021-03-08 16:49:10 +00:00
)
url = "https://openlibrary.org/search?q=arkady+strugatsky&mode=everything"
2021-01-12 22:02:38 +00:00
self.assertEqual(
views.status.format_links(url),
f'<a href="{url}">openlibrary.org/search'
"?q=arkady+strugatsky&mode=everything</a>",
2021-03-08 16:49:10 +00:00
)
url = "https://tech.lgbt/@bookwyrm"
self.assertEqual(
views.status.format_links(url), f'<a href="{url}">tech.lgbt/@bookwyrm</a>'
)
url = "https://users.speakeasy.net/~lion/nb/book.pdf"
self.assertEqual(
views.status.format_links(url),
f'<a href="{url}">users.speakeasy.net/~lion/nb/book.pdf</a>',
)
url = "https://pkm.one/#/page/The%20Book%20launched%20a%201000%20Note%20apps"
self.assertEqual(
views.status.format_links(url), f'<a href="{url}">{url[8:]}</a>'
)
2021-01-12 22:02:38 +00:00
2021-08-03 17:25:53 +00:00
def test_to_markdown(self, *_):
2021-04-26 16:15:42 +00:00
"""this is mostly handled in other places, but nonetheless"""
2021-03-08 16:49:10 +00:00
text = "_hi_ and http://fish.com is <marquee>rad</marquee>"
2021-01-12 22:02:38 +00:00
result = views.status.to_markdown(text)
self.assertEqual(
result,
2021-03-08 16:49:10 +00:00
'<p><em>hi</em> and <a href="http://fish.com">fish.com</a> ' "is rad</p>",
)
2021-08-03 17:25:53 +00:00
def test_to_markdown_detect_url(self, *_):
2021-07-07 16:47:07 +00:00
"""this is mostly handled in other places, but nonetheless"""
text = "http://fish.com/@hello#okay"
result = views.status.to_markdown(text)
self.assertEqual(
result,
'<p><a href="http://fish.com/@hello#okay">fish.com/@hello#okay</a></p>',
)
2021-08-03 17:25:53 +00:00
def test_to_markdown_link(self, *_):
2021-04-26 16:15:42 +00:00
"""this is mostly handled in other places, but nonetheless"""
2021-03-08 16:49:10 +00:00
text = "[hi](http://fish.com) is <marquee>rad</marquee>"
2021-02-10 20:07:50 +00:00
result = views.status.to_markdown(text)
2021-03-08 16:49:10 +00:00
self.assertEqual(result, '<p><a href="http://fish.com">hi</a> ' "is rad</p>")
2021-02-10 20:07:50 +00:00
2021-08-03 23:21:29 +00:00
def test_handle_delete_status(self, mock, *_):
2021-04-26 16:15:42 +00:00
"""marks a status as deleted"""
view = views.DeleteStatus.as_view()
2021-09-06 20:53:49 +00:00
with patch("bookwyrm.activitystreams.add_status_task.delay"):
2021-03-23 15:13:57 +00:00
status = models.Status.objects.create(user=self.local_user, content="hi")
self.assertFalse(status.deleted)
2021-03-08 16:49:10 +00:00
request = self.factory.post("")
request.user = self.local_user
2021-09-07 01:39:14 +00:00
with patch("bookwyrm.activitystreams.remove_status_task.delay") as redis_mock:
2021-03-23 15:13:57 +00:00
view(request, status.id)
self.assertTrue(redis_mock.called)
activity = json.loads(mock.call_args_list[1][0][1])
self.assertEqual(activity["type"], "Delete")
self.assertEqual(activity["object"]["type"], "Tombstone")
status.refresh_from_db()
self.assertTrue(status.deleted)
2021-08-03 17:25:53 +00:00
def test_handle_delete_status_permission_denied(self, *_):
2021-04-26 16:15:42 +00:00
"""marks a status as deleted"""
view = views.DeleteStatus.as_view()
2021-09-06 20:53:49 +00:00
with patch("bookwyrm.activitystreams.add_status_task.delay"):
2021-03-23 15:13:57 +00:00
status = models.Status.objects.create(user=self.local_user, content="hi")
self.assertFalse(status.deleted)
request = self.factory.post("")
request.user = self.remote_user
view(request, status.id)
status.refresh_from_db()
self.assertFalse(status.deleted)
2021-09-06 22:09:04 +00:00
def test_handle_delete_status_moderator(self, mock, *_):
2021-04-26 16:15:42 +00:00
"""marks a status as deleted"""
view = views.DeleteStatus.as_view()
2021-09-06 20:53:49 +00:00
with patch("bookwyrm.activitystreams.add_status_task.delay"):
2021-03-23 15:13:57 +00:00
status = models.Status.objects.create(user=self.local_user, content="hi")
self.assertFalse(status.deleted)
request = self.factory.post("")
request.user = self.remote_user
request.user.is_superuser = True
2021-09-07 01:39:14 +00:00
with patch("bookwyrm.activitystreams.remove_status_task.delay") as redis_mock:
2021-03-23 15:13:57 +00:00
view(request, status.id)
self.assertTrue(redis_mock.called)
activity = json.loads(mock.call_args_list[1][0][1])
self.assertEqual(activity["type"], "Delete")
self.assertEqual(activity["object"]["type"], "Tombstone")
status.refresh_from_db()
self.assertTrue(status.deleted)