Merge branch 'main' into image-absolute-url-getter
This commit is contained in:
@ -20,18 +20,21 @@ from bookwyrm.settings import PAGE_LENGTH
|
||||
|
||||
|
||||
# pylint: disable=invalid-name
|
||||
@patch("bookwyrm.activitystreams.ActivityStream.add_status")
|
||||
@patch("bookwyrm.activitystreams.add_status_task.delay")
|
||||
@patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay")
|
||||
class ActivitypubMixins(TestCase):
|
||||
"""functionality shared across models"""
|
||||
|
||||
def setUp(self):
|
||||
"""shared data"""
|
||||
self.local_user = models.User.objects.create_user(
|
||||
"mouse", "mouse@mouse.com", "mouseword", local=True, localname="mouse"
|
||||
)
|
||||
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
|
||||
"bookwyrm.activitystreams.populate_stream_task.delay"
|
||||
):
|
||||
self.local_user = models.User.objects.create_user(
|
||||
"mouse", "mouse@mouse.com", "mouseword", local=True, localname="mouse"
|
||||
)
|
||||
self.local_user.remote_id = "http://example.com/a/b"
|
||||
self.local_user.save(broadcast=False)
|
||||
self.local_user.save(broadcast=False, update_fields=["remote_id"])
|
||||
with patch("bookwyrm.models.user.set_remote_server.delay"):
|
||||
self.remote_user = models.User.objects.create_user(
|
||||
"rat",
|
||||
@ -189,7 +192,7 @@ class ActivitypubMixins(TestCase):
|
||||
def test_get_recipients_combine_inboxes(self, *_):
|
||||
"""should combine users with the same shared_inbox"""
|
||||
self.remote_user.shared_inbox = "http://example.com/inbox"
|
||||
self.remote_user.save(broadcast=False)
|
||||
self.remote_user.save(broadcast=False, update_fields=["shared_inbox"])
|
||||
with patch("bookwyrm.models.user.set_remote_server.delay"):
|
||||
another_remote_user = models.User.objects.create_user(
|
||||
"nutria",
|
||||
|
@ -1,5 +1,6 @@
|
||||
""" testing models """
|
||||
from unittest.mock import patch
|
||||
from django.http import Http404
|
||||
from django.test import TestCase
|
||||
|
||||
from bookwyrm import models
|
||||
@ -13,9 +14,12 @@ class BaseModel(TestCase):
|
||||
|
||||
def setUp(self):
|
||||
"""shared data"""
|
||||
self.local_user = models.User.objects.create_user(
|
||||
"mouse", "mouse@mouse.com", "mouseword", local=True, localname="mouse"
|
||||
)
|
||||
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
|
||||
"bookwyrm.activitystreams.populate_stream_task.delay"
|
||||
):
|
||||
self.local_user = models.User.objects.create_user(
|
||||
"mouse", "mouse@mouse.com", "mouseword", local=True, localname="mouse"
|
||||
)
|
||||
with patch("bookwyrm.models.user.set_remote_server.delay"):
|
||||
self.remote_user = models.User.objects.create_user(
|
||||
"rat",
|
||||
@ -36,14 +40,14 @@ class BaseModel(TestCase):
|
||||
"""these should be generated"""
|
||||
self.test_model.id = 1
|
||||
expected = self.test_model.get_remote_id()
|
||||
self.assertEqual(expected, "https://%s/bookwyrmtestmodel/1" % DOMAIN)
|
||||
self.assertEqual(expected, f"https://{DOMAIN}/bookwyrmtestmodel/1")
|
||||
|
||||
def test_remote_id_with_user(self):
|
||||
"""format of remote id when there's a user object"""
|
||||
self.test_model.user = self.local_user
|
||||
self.test_model.id = 1
|
||||
expected = self.test_model.get_remote_id()
|
||||
self.assertEqual(expected, "https://%s/user/mouse/bookwyrmtestmodel/1" % DOMAIN)
|
||||
self.assertEqual(expected, f"https://{DOMAIN}/user/mouse/bookwyrmtestmodel/1")
|
||||
|
||||
def test_set_remote_id(self):
|
||||
"""this function sets remote ids after creation"""
|
||||
@ -52,74 +56,77 @@ class BaseModel(TestCase):
|
||||
instance = models.Work.objects.create(title="work title")
|
||||
instance.remote_id = None
|
||||
base_model.set_remote_id(None, instance, True)
|
||||
self.assertEqual(
|
||||
instance.remote_id, "https://%s/book/%d" % (DOMAIN, instance.id)
|
||||
)
|
||||
self.assertEqual(instance.remote_id, f"https://{DOMAIN}/book/{instance.id}")
|
||||
|
||||
# shouldn't set remote_id if it's not created
|
||||
instance.remote_id = None
|
||||
base_model.set_remote_id(None, instance, False)
|
||||
self.assertIsNone(instance.remote_id)
|
||||
|
||||
@patch("bookwyrm.activitystreams.ActivityStream.add_status")
|
||||
@patch("bookwyrm.activitystreams.add_status_task.delay")
|
||||
def test_object_visible_to_user(self, _):
|
||||
"""does a user have permission to view an object"""
|
||||
obj = models.Status.objects.create(
|
||||
content="hi", user=self.remote_user, privacy="public"
|
||||
)
|
||||
self.assertTrue(obj.visible_to_user(self.local_user))
|
||||
self.assertIsNone(obj.raise_visible_to_user(self.local_user))
|
||||
|
||||
obj = models.Shelf.objects.create(
|
||||
name="test", user=self.remote_user, privacy="unlisted"
|
||||
)
|
||||
self.assertTrue(obj.visible_to_user(self.local_user))
|
||||
self.assertIsNone(obj.raise_visible_to_user(self.local_user))
|
||||
|
||||
obj = models.Status.objects.create(
|
||||
content="hi", user=self.remote_user, privacy="followers"
|
||||
)
|
||||
self.assertFalse(obj.visible_to_user(self.local_user))
|
||||
with self.assertRaises(Http404):
|
||||
obj.raise_visible_to_user(self.local_user)
|
||||
|
||||
obj = models.Status.objects.create(
|
||||
content="hi", user=self.remote_user, privacy="direct"
|
||||
)
|
||||
self.assertFalse(obj.visible_to_user(self.local_user))
|
||||
with self.assertRaises(Http404):
|
||||
obj.raise_visible_to_user(self.local_user)
|
||||
|
||||
obj = models.Status.objects.create(
|
||||
content="hi", user=self.remote_user, privacy="direct"
|
||||
)
|
||||
obj.mention_users.add(self.local_user)
|
||||
self.assertTrue(obj.visible_to_user(self.local_user))
|
||||
self.assertIsNone(obj.raise_visible_to_user(self.local_user))
|
||||
|
||||
@patch("bookwyrm.activitystreams.ActivityStream.add_status")
|
||||
@patch("bookwyrm.activitystreams.add_status_task.delay")
|
||||
def test_object_visible_to_user_follower(self, _):
|
||||
"""what you can see if you follow a user"""
|
||||
self.remote_user.followers.add(self.local_user)
|
||||
obj = models.Status.objects.create(
|
||||
content="hi", user=self.remote_user, privacy="followers"
|
||||
)
|
||||
self.assertTrue(obj.visible_to_user(self.local_user))
|
||||
self.assertIsNone(obj.raise_visible_to_user(self.local_user))
|
||||
|
||||
obj = models.Status.objects.create(
|
||||
content="hi", user=self.remote_user, privacy="direct"
|
||||
)
|
||||
self.assertFalse(obj.visible_to_user(self.local_user))
|
||||
with self.assertRaises(Http404):
|
||||
obj.raise_visible_to_user(self.local_user)
|
||||
|
||||
obj = models.Status.objects.create(
|
||||
content="hi", user=self.remote_user, privacy="direct"
|
||||
)
|
||||
obj.mention_users.add(self.local_user)
|
||||
self.assertTrue(obj.visible_to_user(self.local_user))
|
||||
self.assertIsNone(obj.raise_visible_to_user(self.local_user))
|
||||
|
||||
@patch("bookwyrm.activitystreams.ActivityStream.add_status")
|
||||
@patch("bookwyrm.activitystreams.add_status_task.delay")
|
||||
def test_object_visible_to_user_blocked(self, _):
|
||||
"""you can't see it if they block you"""
|
||||
self.remote_user.blocks.add(self.local_user)
|
||||
obj = models.Status.objects.create(
|
||||
content="hi", user=self.remote_user, privacy="public"
|
||||
)
|
||||
self.assertFalse(obj.visible_to_user(self.local_user))
|
||||
with self.assertRaises(Http404):
|
||||
obj.raise_visible_to_user(self.local_user)
|
||||
|
||||
obj = models.Shelf.objects.create(
|
||||
name="test", user=self.remote_user, privacy="unlisted"
|
||||
)
|
||||
self.assertFalse(obj.visible_to_user(self.local_user))
|
||||
with self.assertRaises(Http404):
|
||||
obj.raise_visible_to_user(self.local_user)
|
||||
|
@ -25,10 +25,12 @@ from bookwyrm.models.activitypub_mixin import ActivitypubMixin
|
||||
from bookwyrm.settings import DOMAIN
|
||||
|
||||
# pylint: disable=too-many-public-methods
|
||||
class ActivitypubFields(TestCase):
|
||||
@patch("bookwyrm.suggested_users.rerank_suggestions_task.delay")
|
||||
@patch("bookwyrm.activitystreams.populate_stream_task.delay")
|
||||
class ModelFields(TestCase):
|
||||
"""overwrites standard model feilds to work with activitypub"""
|
||||
|
||||
def test_validate_remote_id(self):
|
||||
def test_validate_remote_id(self, *_):
|
||||
"""should look like a url"""
|
||||
self.assertIsNone(fields.validate_remote_id("http://www.example.com"))
|
||||
self.assertIsNone(fields.validate_remote_id("https://www.example.com"))
|
||||
@ -45,7 +47,7 @@ class ActivitypubFields(TestCase):
|
||||
"http://www.example.com/dlfjg 23/x",
|
||||
)
|
||||
|
||||
def test_activitypub_field_mixin(self):
|
||||
def test_activitypub_field_mixin(self, *_):
|
||||
"""generic mixin with super basic to and from functionality"""
|
||||
instance = fields.ActivitypubFieldMixin()
|
||||
self.assertEqual(instance.field_to_activity("fish"), "fish")
|
||||
@ -63,7 +65,7 @@ class ActivitypubFields(TestCase):
|
||||
instance.name = "snake_case_name"
|
||||
self.assertEqual(instance.get_activitypub_field(), "snakeCaseName")
|
||||
|
||||
def test_set_field_from_activity(self):
|
||||
def test_set_field_from_activity(self, *_):
|
||||
"""setter from entire json blob"""
|
||||
|
||||
@dataclass
|
||||
@ -82,7 +84,7 @@ class ActivitypubFields(TestCase):
|
||||
instance.set_field_from_activity(mock_model, data)
|
||||
self.assertEqual(mock_model.field_name, "hi")
|
||||
|
||||
def test_set_activity_from_field(self):
|
||||
def test_set_activity_from_field(self, *_):
|
||||
"""set json field given entire model"""
|
||||
|
||||
@dataclass
|
||||
@ -100,7 +102,7 @@ class ActivitypubFields(TestCase):
|
||||
instance.set_activity_from_field(data, mock_model)
|
||||
self.assertEqual(data["fieldName"], "bip")
|
||||
|
||||
def test_remote_id_field(self):
|
||||
def test_remote_id_field(self, *_):
|
||||
"""just sets some defaults on charfield"""
|
||||
instance = fields.RemoteIdField()
|
||||
self.assertEqual(instance.max_length, 255)
|
||||
@ -109,7 +111,7 @@ class ActivitypubFields(TestCase):
|
||||
with self.assertRaises(ValidationError):
|
||||
instance.run_validators("http://www.example.com/dlfjg 23/x")
|
||||
|
||||
def test_username_field(self):
|
||||
def test_username_field(self, *_):
|
||||
"""again, just setting defaults on username field"""
|
||||
instance = fields.UsernameField()
|
||||
self.assertEqual(instance.activitypub_field, "preferredUsername")
|
||||
@ -130,7 +132,7 @@ class ActivitypubFields(TestCase):
|
||||
|
||||
self.assertEqual(instance.field_to_activity("test@example.com"), "test")
|
||||
|
||||
def test_privacy_field_defaults(self):
|
||||
def test_privacy_field_defaults(self, *_):
|
||||
"""post privacy field's many default values"""
|
||||
instance = fields.PrivacyField()
|
||||
self.assertEqual(instance.max_length, 255)
|
||||
@ -143,9 +145,18 @@ class ActivitypubFields(TestCase):
|
||||
instance.public, "https://www.w3.org/ns/activitystreams#Public"
|
||||
)
|
||||
|
||||
def test_privacy_field_set_field_from_activity(self):
|
||||
def test_privacy_field_set_field_from_activity(self, *_):
|
||||
"""translate between to/cc fields and privacy"""
|
||||
|
||||
with patch("bookwyrm.models.user.set_remote_server.delay"):
|
||||
test_user = User.objects.create_user(
|
||||
username="test_user@example.com",
|
||||
local=False,
|
||||
remote_id="https://example.com/test_user",
|
||||
inbox="https://example.com/users/test_user/inbox",
|
||||
followers_url="https://example.com/users/test_user/followers",
|
||||
)
|
||||
|
||||
@dataclass(init=False)
|
||||
class TestActivity(ActivityObject):
|
||||
"""real simple mock"""
|
||||
@ -154,6 +165,7 @@ class ActivitypubFields(TestCase):
|
||||
cc: List[str]
|
||||
id: str = "http://hi.com"
|
||||
type: str = "Test"
|
||||
attributedTo: str = test_user.remote_id
|
||||
|
||||
class TestPrivacyModel(ActivitypubMixin, BookWyrmModel):
|
||||
"""real simple mock model because BookWyrmModel is abstract"""
|
||||
@ -185,8 +197,18 @@ class ActivitypubFields(TestCase):
|
||||
instance.set_field_from_activity(model_instance, data)
|
||||
self.assertEqual(model_instance.privacy_field, "unlisted")
|
||||
|
||||
data.to = [test_user.followers_url]
|
||||
data.cc = []
|
||||
instance.set_field_from_activity(model_instance, data)
|
||||
self.assertEqual(model_instance.privacy_field, "followers")
|
||||
|
||||
data.to = ["http://user_remote/followers"]
|
||||
data.cc = ["http://mentioned_user/remote_id"]
|
||||
instance.set_field_from_activity(model_instance, data)
|
||||
self.assertEqual(model_instance.privacy_field, "followers")
|
||||
|
||||
@patch("bookwyrm.models.activitypub_mixin.ObjectMixin.broadcast")
|
||||
@patch("bookwyrm.activitystreams.ActivityStream.add_status")
|
||||
@patch("bookwyrm.activitystreams.add_status_task.delay")
|
||||
def test_privacy_field_set_activity_from_field(self, *_):
|
||||
"""translate between to/cc fields and privacy"""
|
||||
user = User.objects.create_user(
|
||||
@ -231,7 +253,7 @@ class ActivitypubFields(TestCase):
|
||||
self.assertEqual(activity["to"], [user.remote_id])
|
||||
self.assertEqual(activity["cc"], [])
|
||||
|
||||
def test_foreign_key(self):
|
||||
def test_foreign_key(self, *_):
|
||||
"""should be able to format a related model"""
|
||||
instance = fields.ForeignKey("User", on_delete=models.CASCADE)
|
||||
Serializable = namedtuple("Serializable", ("to_activity", "remote_id"))
|
||||
@ -240,7 +262,7 @@ class ActivitypubFields(TestCase):
|
||||
self.assertEqual(instance.field_to_activity(item), "https://e.b/c")
|
||||
|
||||
@responses.activate
|
||||
def test_foreign_key_from_activity_str(self):
|
||||
def test_foreign_key_from_activity_str(self, *_):
|
||||
"""create a new object from a foreign key"""
|
||||
instance = fields.ForeignKey(User, on_delete=models.CASCADE)
|
||||
datafile = pathlib.Path(__file__).parent.joinpath("../data/ap_user.json")
|
||||
@ -267,7 +289,7 @@ class ActivitypubFields(TestCase):
|
||||
self.assertEqual(value.remote_id, "https://example.com/user/mouse")
|
||||
self.assertEqual(value.name, "MOUSE?? MOUSE!!")
|
||||
|
||||
def test_foreign_key_from_activity_dict(self):
|
||||
def test_foreign_key_from_activity_dict(self, *_):
|
||||
"""test recieving activity json"""
|
||||
instance = fields.ForeignKey(User, on_delete=models.CASCADE)
|
||||
datafile = pathlib.Path(__file__).parent.joinpath("../data/ap_user.json")
|
||||
@ -287,7 +309,7 @@ class ActivitypubFields(TestCase):
|
||||
self.assertEqual(value.name, "MOUSE?? MOUSE!!")
|
||||
# et cetera but we're not testing serializing user json
|
||||
|
||||
def test_foreign_key_from_activity_dict_existing(self):
|
||||
def test_foreign_key_from_activity_dict_existing(self, *_):
|
||||
"""test receiving a dict of an existing object in the db"""
|
||||
instance = fields.ForeignKey(User, on_delete=models.CASCADE)
|
||||
datafile = pathlib.Path(__file__).parent.joinpath("../data/ap_user.json")
|
||||
@ -296,7 +318,7 @@ class ActivitypubFields(TestCase):
|
||||
"mouse", "mouse@mouse.mouse", "mouseword", local=True, localname="mouse"
|
||||
)
|
||||
user.remote_id = "https://example.com/user/mouse"
|
||||
user.save(broadcast=False)
|
||||
user.save(broadcast=False, update_fields=["remote_id"])
|
||||
|
||||
User.objects.create_user(
|
||||
"rat", "rat@rat.rat", "ratword", local=True, localname="rat"
|
||||
@ -306,7 +328,7 @@ class ActivitypubFields(TestCase):
|
||||
value = instance.field_from_activity(activitypub.Person(**userdata))
|
||||
self.assertEqual(value, user)
|
||||
|
||||
def test_foreign_key_from_activity_str_existing(self):
|
||||
def test_foreign_key_from_activity_str_existing(self, *_):
|
||||
"""test receiving a remote id of an existing object in the db"""
|
||||
instance = fields.ForeignKey(User, on_delete=models.CASCADE)
|
||||
user = User.objects.create_user(
|
||||
@ -319,14 +341,14 @@ class ActivitypubFields(TestCase):
|
||||
value = instance.field_from_activity(user.remote_id)
|
||||
self.assertEqual(value, user)
|
||||
|
||||
def test_one_to_one_field(self):
|
||||
def test_one_to_one_field(self, *_):
|
||||
"""a gussied up foreign key"""
|
||||
instance = fields.OneToOneField("User", on_delete=models.CASCADE)
|
||||
Serializable = namedtuple("Serializable", ("to_activity", "remote_id"))
|
||||
item = Serializable(lambda: {"a": "b"}, "https://e.b/c")
|
||||
self.assertEqual(instance.field_to_activity(item), {"a": "b"})
|
||||
|
||||
def test_many_to_many_field(self):
|
||||
def test_many_to_many_field(self, *_):
|
||||
"""lists!"""
|
||||
instance = fields.ManyToManyField("User")
|
||||
|
||||
@ -344,7 +366,7 @@ class ActivitypubFields(TestCase):
|
||||
self.assertEqual(instance.field_to_activity(items), "example.com/snake_case")
|
||||
|
||||
@responses.activate
|
||||
def test_many_to_many_field_from_activity(self):
|
||||
def test_many_to_many_field_from_activity(self, *_):
|
||||
"""resolve related fields for a list, takes a list of remote ids"""
|
||||
instance = fields.ManyToManyField(User)
|
||||
datafile = pathlib.Path(__file__).parent.joinpath("../data/ap_user.json")
|
||||
@ -364,7 +386,7 @@ class ActivitypubFields(TestCase):
|
||||
self.assertEqual(len(value), 1)
|
||||
self.assertIsInstance(value[0], User)
|
||||
|
||||
def test_tag_field(self):
|
||||
def test_tag_field(self, *_):
|
||||
"""a special type of many to many field"""
|
||||
instance = fields.TagField("User")
|
||||
|
||||
@ -383,13 +405,14 @@ class ActivitypubFields(TestCase):
|
||||
self.assertEqual(result[0].name, "Name")
|
||||
self.assertEqual(result[0].type, "Serializable")
|
||||
|
||||
def test_tag_field_from_activity(self):
|
||||
def test_tag_field_from_activity(self, *_):
|
||||
"""loadin' a list of items from Links"""
|
||||
# TODO
|
||||
|
||||
@responses.activate
|
||||
@patch("bookwyrm.models.activitypub_mixin.ObjectMixin.broadcast")
|
||||
def test_image_field(self, _):
|
||||
@patch("bookwyrm.suggested_users.remove_user_task.delay")
|
||||
def test_image_field(self, *_):
|
||||
"""storing images"""
|
||||
user = User.objects.create_user(
|
||||
"mouse", "mouse@mouse.mouse", "mouseword", local=True, localname="mouse"
|
||||
@ -424,7 +447,7 @@ class ActivitypubFields(TestCase):
|
||||
self.assertIsInstance(loaded_image, list)
|
||||
self.assertIsInstance(loaded_image[1], ContentFile)
|
||||
|
||||
def test_image_serialize(self):
|
||||
def test_image_serialize(self, *_):
|
||||
"""make sure we're creating sensible image paths"""
|
||||
ValueMock = namedtuple("ValueMock", ("url"))
|
||||
value_mock = ValueMock("https://your.domain.here/images/fish.jpg")
|
||||
@ -433,7 +456,7 @@ class ActivitypubFields(TestCase):
|
||||
self.assertEqual(result.url, "https://your.domain.here/images/fish.jpg")
|
||||
self.assertEqual(result.name, "hello")
|
||||
|
||||
def test_datetime_field(self):
|
||||
def test_datetime_field(self, *_):
|
||||
"""this one is pretty simple, it just has to use isoformat"""
|
||||
instance = fields.DateTimeField()
|
||||
now = timezone.now()
|
||||
@ -441,12 +464,12 @@ class ActivitypubFields(TestCase):
|
||||
self.assertEqual(instance.field_from_activity(now.isoformat()), now)
|
||||
self.assertEqual(instance.field_from_activity("bip"), None)
|
||||
|
||||
def test_array_field(self):
|
||||
def test_array_field(self, *_):
|
||||
"""idk why it makes them strings but probably for a good reason"""
|
||||
instance = fields.ArrayField(fields.IntegerField)
|
||||
self.assertEqual(instance.field_to_activity([0, 1]), ["0", "1"])
|
||||
|
||||
def test_html_field(self):
|
||||
def test_html_field(self, *_):
|
||||
"""sanitizes html, the sanitizer has its own tests"""
|
||||
instance = fields.HtmlField()
|
||||
self.assertEqual(
|
||||
|
135
bookwyrm/tests/models/test_group.py
Normal file
135
bookwyrm/tests/models/test_group.py
Normal file
@ -0,0 +1,135 @@
|
||||
""" testing models """
|
||||
from unittest.mock import patch
|
||||
from django.test import TestCase
|
||||
|
||||
from bookwyrm import models, settings
|
||||
|
||||
|
||||
@patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay")
|
||||
class Group(TestCase):
|
||||
"""some activitypub oddness ahead"""
|
||||
|
||||
def setUp(self):
|
||||
"""Set up for tests"""
|
||||
|
||||
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
|
||||
"bookwyrm.activitystreams.populate_stream_task.delay"
|
||||
):
|
||||
self.owner_user = models.User.objects.create_user(
|
||||
"mouse", "mouse@mouse.mouse", "mouseword", local=True, localname="mouse"
|
||||
)
|
||||
|
||||
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
|
||||
"bookwyrm.activitystreams.populate_stream_task.delay"
|
||||
):
|
||||
self.rat = models.User.objects.create_user(
|
||||
"rat", "rat@rat.rat", "ratword", local=True, localname="rat"
|
||||
)
|
||||
|
||||
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
|
||||
"bookwyrm.activitystreams.populate_stream_task.delay"
|
||||
):
|
||||
self.badger = models.User.objects.create_user(
|
||||
"badger",
|
||||
"badger@badger.badger",
|
||||
"badgerword",
|
||||
local=True,
|
||||
localname="badger",
|
||||
)
|
||||
|
||||
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
|
||||
"bookwyrm.activitystreams.populate_stream_task.delay"
|
||||
):
|
||||
self.capybara = models.User.objects.create_user(
|
||||
"capybara",
|
||||
"capybara@capybara.capybara",
|
||||
"capybaraword",
|
||||
local=True,
|
||||
localname="capybara",
|
||||
)
|
||||
|
||||
self.public_group = models.Group.objects.create(
|
||||
name="Public Group",
|
||||
description="Initial description",
|
||||
user=self.owner_user,
|
||||
privacy="public",
|
||||
)
|
||||
|
||||
self.private_group = models.Group.objects.create(
|
||||
name="Private Group",
|
||||
description="Top secret",
|
||||
user=self.owner_user,
|
||||
privacy="direct",
|
||||
)
|
||||
|
||||
self.followers_only_group = models.Group.objects.create(
|
||||
name="Followers Group",
|
||||
description="No strangers",
|
||||
user=self.owner_user,
|
||||
privacy="followers",
|
||||
)
|
||||
|
||||
models.GroupMember.objects.create(group=self.private_group, user=self.badger)
|
||||
models.GroupMember.objects.create(
|
||||
group=self.followers_only_group, user=self.badger
|
||||
)
|
||||
models.GroupMember.objects.create(group=self.public_group, user=self.capybara)
|
||||
|
||||
def test_group_members_can_see_followers_only_groups(self, _):
|
||||
"""follower-only group should not be excluded from group listings for group members viewing"""
|
||||
|
||||
rat_groups = models.Group.privacy_filter(self.rat).all()
|
||||
badger_groups = models.Group.privacy_filter(self.badger).all()
|
||||
|
||||
self.assertFalse(self.followers_only_group in rat_groups)
|
||||
self.assertTrue(self.followers_only_group in badger_groups)
|
||||
|
||||
def test_group_members_can_see_private_groups(self, _):
|
||||
"""direct privacy group should not be excluded from group listings for group members viewing"""
|
||||
|
||||
rat_groups = models.Group.privacy_filter(self.rat).all()
|
||||
badger_groups = models.Group.privacy_filter(self.badger).all()
|
||||
|
||||
self.assertFalse(self.private_group in rat_groups)
|
||||
self.assertTrue(self.private_group in badger_groups)
|
||||
|
||||
def test_group_members_can_see_followers_only_lists(self, _):
|
||||
"""follower-only group booklists should not be excluded from group booklist listing for group members who do not follower list owner"""
|
||||
|
||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
|
||||
followers_list = models.List.objects.create(
|
||||
name="Followers List",
|
||||
curation="group",
|
||||
privacy="followers",
|
||||
group=self.public_group,
|
||||
user=self.owner_user,
|
||||
)
|
||||
|
||||
rat_lists = models.List.privacy_filter(self.rat).all()
|
||||
badger_lists = models.List.privacy_filter(self.badger).all()
|
||||
capybara_lists = models.List.privacy_filter(self.capybara).all()
|
||||
|
||||
self.assertFalse(followers_list in rat_lists)
|
||||
self.assertFalse(followers_list in badger_lists)
|
||||
self.assertTrue(followers_list in capybara_lists)
|
||||
|
||||
def test_group_members_can_see_private_lists(self, _):
|
||||
"""private group booklists should not be excluded from group booklist listing for group members"""
|
||||
|
||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
|
||||
|
||||
private_list = models.List.objects.create(
|
||||
name="Private List",
|
||||
privacy="direct",
|
||||
curation="group",
|
||||
group=self.public_group,
|
||||
user=self.owner_user,
|
||||
)
|
||||
|
||||
rat_lists = models.List.privacy_filter(self.rat).all()
|
||||
badger_lists = models.List.privacy_filter(self.badger).all()
|
||||
capybara_lists = models.List.privacy_filter(self.capybara).all()
|
||||
|
||||
self.assertFalse(private_list in rat_lists)
|
||||
self.assertFalse(private_list in badger_lists)
|
||||
self.assertTrue(private_list in capybara_lists)
|
@ -9,8 +9,8 @@ from django.test import TestCase
|
||||
import responses
|
||||
|
||||
from bookwyrm import models
|
||||
from bookwyrm.book_search import SearchResult
|
||||
from bookwyrm.connectors import connector_manager
|
||||
from bookwyrm.connectors.abstract_connector import SearchResult
|
||||
|
||||
|
||||
class ImportJob(TestCase):
|
||||
@ -59,9 +59,12 @@ class ImportJob(TestCase):
|
||||
unknown_read_data["Exclusive Shelf"] = "read"
|
||||
unknown_read_data["Date Read"] = ""
|
||||
|
||||
user = models.User.objects.create_user(
|
||||
"mouse", "mouse@mouse.mouse", "mouseword", local=True, localname="mouse"
|
||||
)
|
||||
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
|
||||
"bookwyrm.activitystreams.populate_stream_task.delay"
|
||||
):
|
||||
user = models.User.objects.create_user(
|
||||
"mouse", "mouse@mouse.mouse", "mouseword", local=True, localname="mouse"
|
||||
)
|
||||
job = models.ImportJob.objects.create(user=user)
|
||||
self.item_1 = models.ImportItem.objects.create(
|
||||
job=job, index=1, data=currently_reading_data
|
||||
|
@ -11,9 +11,12 @@ class List(TestCase):
|
||||
|
||||
def setUp(self):
|
||||
"""look, a list"""
|
||||
self.local_user = models.User.objects.create_user(
|
||||
"mouse", "mouse@mouse.mouse", "mouseword", local=True, localname="mouse"
|
||||
)
|
||||
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
|
||||
"bookwyrm.activitystreams.populate_stream_task.delay"
|
||||
):
|
||||
self.local_user = models.User.objects.create_user(
|
||||
"mouse", "mouse@mouse.mouse", "mouseword", local=True, localname="mouse"
|
||||
)
|
||||
work = models.Work.objects.create(title="hello")
|
||||
self.book = models.Edition.objects.create(title="hi", parent_work=work)
|
||||
|
||||
|
@ -1,6 +1,9 @@
|
||||
""" testing models """
|
||||
import datetime
|
||||
from unittest.mock import patch
|
||||
from django.test import TestCase
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.utils import timezone
|
||||
|
||||
from bookwyrm import models
|
||||
|
||||
@ -10,36 +13,91 @@ class ReadThrough(TestCase):
|
||||
|
||||
def setUp(self):
|
||||
"""look, a shelf"""
|
||||
self.user = models.User.objects.create_user(
|
||||
"mouse", "mouse@mouse.mouse", "mouseword", local=True, localname="mouse"
|
||||
)
|
||||
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
|
||||
"bookwyrm.activitystreams.populate_stream_task.delay"
|
||||
):
|
||||
self.user = models.User.objects.create_user(
|
||||
"mouse", "mouse@mouse.mouse", "mouseword", local=True, localname="mouse"
|
||||
)
|
||||
|
||||
self.work = models.Work.objects.create(title="Example Work")
|
||||
self.edition = models.Edition.objects.create(
|
||||
title="Example Edition", parent_work=self.work
|
||||
)
|
||||
|
||||
self.readthrough = models.ReadThrough.objects.create(
|
||||
user=self.user, book=self.edition
|
||||
def test_valid_date(self):
|
||||
"""can't finish a book before you start it"""
|
||||
start = timezone.now()
|
||||
finish = start + datetime.timedelta(days=1)
|
||||
# just make sure there's no errors
|
||||
models.ReadThrough.objects.create(
|
||||
user=self.user,
|
||||
book=self.edition,
|
||||
start_date=start,
|
||||
finish_date=finish,
|
||||
)
|
||||
|
||||
def test_valid_date_null_start(self):
|
||||
"""can't finish a book before you start it"""
|
||||
start = timezone.now()
|
||||
finish = start + datetime.timedelta(days=1)
|
||||
# just make sure there's no errors
|
||||
models.ReadThrough.objects.create(
|
||||
user=self.user,
|
||||
book=self.edition,
|
||||
finish_date=finish,
|
||||
)
|
||||
|
||||
def test_valid_date_null_finish(self):
|
||||
"""can't finish a book before you start it"""
|
||||
start = timezone.now()
|
||||
# just make sure there's no errors
|
||||
models.ReadThrough.objects.create(
|
||||
user=self.user,
|
||||
book=self.edition,
|
||||
start_date=start,
|
||||
)
|
||||
|
||||
def test_valid_date_null(self):
|
||||
"""can't finish a book before you start it"""
|
||||
# just make sure there's no errors
|
||||
models.ReadThrough.objects.create(
|
||||
user=self.user,
|
||||
book=self.edition,
|
||||
)
|
||||
|
||||
def test_valid_date_same(self):
|
||||
"""can't finish a book before you start it"""
|
||||
start = timezone.now()
|
||||
# just make sure there's no errors
|
||||
models.ReadThrough.objects.create(
|
||||
user=self.user,
|
||||
book=self.edition,
|
||||
start_date=start,
|
||||
finish_date=start,
|
||||
)
|
||||
|
||||
def test_progress_update(self):
|
||||
"""Test progress updates"""
|
||||
self.readthrough.create_update() # No-op, no progress yet
|
||||
self.readthrough.progress = 10
|
||||
self.readthrough.create_update()
|
||||
self.readthrough.progress = 20
|
||||
self.readthrough.progress_mode = models.ProgressMode.PERCENT
|
||||
self.readthrough.create_update()
|
||||
readthrough = models.ReadThrough.objects.create(
|
||||
user=self.user, book=self.edition
|
||||
)
|
||||
|
||||
updates = self.readthrough.progressupdate_set.order_by("created_date").all()
|
||||
readthrough.create_update() # No-op, no progress yet
|
||||
readthrough.progress = 10
|
||||
readthrough.create_update()
|
||||
readthrough.progress = 20
|
||||
readthrough.progress_mode = models.ProgressMode.PERCENT
|
||||
readthrough.create_update()
|
||||
|
||||
updates = readthrough.progressupdate_set.order_by("created_date").all()
|
||||
self.assertEqual(len(updates), 2)
|
||||
self.assertEqual(updates[0].progress, 10)
|
||||
self.assertEqual(updates[0].mode, models.ProgressMode.PAGE)
|
||||
self.assertEqual(updates[1].progress, 20)
|
||||
self.assertEqual(updates[1].mode, models.ProgressMode.PERCENT)
|
||||
|
||||
self.readthrough.progress = -10
|
||||
self.assertRaises(ValidationError, self.readthrough.clean_fields)
|
||||
update = self.readthrough.create_update()
|
||||
readthrough.progress = -10
|
||||
self.assertRaises(ValidationError, readthrough.clean_fields)
|
||||
update = readthrough.create_update()
|
||||
self.assertRaises(ValidationError, update.clean_fields)
|
||||
|
@ -1,10 +1,12 @@
|
||||
""" testing models """
|
||||
import json
|
||||
from unittest.mock import patch
|
||||
from django.test import TestCase
|
||||
|
||||
from bookwyrm import models
|
||||
|
||||
|
||||
@patch("bookwyrm.activitystreams.add_user_statuses_task.delay")
|
||||
class Relationship(TestCase):
|
||||
"""following, blocking, stuff like that"""
|
||||
|
||||
@ -20,25 +22,23 @@ class Relationship(TestCase):
|
||||
inbox="https://example.com/users/rat/inbox",
|
||||
outbox="https://example.com/users/rat/outbox",
|
||||
)
|
||||
self.local_user = models.User.objects.create_user(
|
||||
"mouse", "mouse@mouse.com", "mouseword", local=True, localname="mouse"
|
||||
)
|
||||
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
|
||||
"bookwyrm.activitystreams.populate_stream_task.delay"
|
||||
):
|
||||
self.local_user = models.User.objects.create_user(
|
||||
"mouse", "mouse@mouse.com", "mouseword", local=True, localname="mouse"
|
||||
)
|
||||
self.local_user.remote_id = "http://local.com/user/mouse"
|
||||
self.local_user.save(broadcast=False)
|
||||
self.local_user.save(broadcast=False, update_fields=["remote_id"])
|
||||
|
||||
def test_user_follows_from_request(self):
|
||||
def test_user_follows_from_request(self, _):
|
||||
"""convert a follow request into a follow"""
|
||||
real_broadcast = models.UserFollowRequest.broadcast
|
||||
|
||||
def mock_broadcast(_, activity, user):
|
||||
"""introspect what's being sent out"""
|
||||
self.assertEqual(user.remote_id, self.local_user.remote_id)
|
||||
self.assertEqual(activity["type"], "Follow")
|
||||
|
||||
models.UserFollowRequest.broadcast = mock_broadcast
|
||||
request = models.UserFollowRequest.objects.create(
|
||||
user_subject=self.local_user, user_object=self.remote_user
|
||||
)
|
||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay") as mock:
|
||||
request = models.UserFollowRequest.objects.create(
|
||||
user_subject=self.local_user, user_object=self.remote_user
|
||||
)
|
||||
activity = json.loads(mock.call_args[0][1])
|
||||
self.assertEqual(activity["type"], "Follow")
|
||||
self.assertEqual(
|
||||
request.remote_id, "http://local.com/user/mouse#follows/%d" % request.id
|
||||
)
|
||||
@ -51,9 +51,8 @@ class Relationship(TestCase):
|
||||
self.assertEqual(rel.status, "follows")
|
||||
self.assertEqual(rel.user_subject, self.local_user)
|
||||
self.assertEqual(rel.user_object, self.remote_user)
|
||||
models.UserFollowRequest.broadcast = real_broadcast
|
||||
|
||||
def test_user_follows_from_request_custom_remote_id(self):
|
||||
def test_user_follows_from_request_custom_remote_id(self, _):
|
||||
"""store a specific remote id for a relationship provided by remote"""
|
||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
|
||||
request = models.UserFollowRequest.objects.create(
|
||||
@ -70,36 +69,26 @@ class Relationship(TestCase):
|
||||
self.assertEqual(rel.user_subject, self.local_user)
|
||||
self.assertEqual(rel.user_object, self.remote_user)
|
||||
|
||||
def test_follow_request_activity(self):
|
||||
@patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay")
|
||||
def test_follow_request_activity(self, broadcast_mock, _):
|
||||
"""accept a request and make it a relationship"""
|
||||
real_broadcast = models.UserFollowRequest.broadcast
|
||||
|
||||
def mock_broadcast(_, activity, user):
|
||||
self.assertEqual(user.remote_id, self.local_user.remote_id)
|
||||
self.assertEqual(activity["actor"], self.local_user.remote_id)
|
||||
self.assertEqual(activity["object"], self.remote_user.remote_id)
|
||||
self.assertEqual(activity["type"], "Follow")
|
||||
|
||||
models.UserFollowRequest.broadcast = mock_broadcast
|
||||
models.UserFollowRequest.objects.create(
|
||||
user_subject=self.local_user,
|
||||
user_object=self.remote_user,
|
||||
)
|
||||
models.UserFollowRequest.broadcast = real_broadcast
|
||||
activity = json.loads(broadcast_mock.call_args[0][1])
|
||||
self.assertEqual(activity["actor"], self.local_user.remote_id)
|
||||
self.assertEqual(activity["object"], self.remote_user.remote_id)
|
||||
self.assertEqual(activity["type"], "Follow")
|
||||
|
||||
def test_follow_request_accept(self):
|
||||
@patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay")
|
||||
def test_follow_request_accept(self, broadcast_mock, _):
|
||||
"""accept a request and make it a relationship"""
|
||||
real_broadcast = models.UserFollowRequest.broadcast
|
||||
|
||||
def mock_broadcast(_, activity, user):
|
||||
self.assertEqual(user.remote_id, self.local_user.remote_id)
|
||||
self.assertEqual(activity["type"], "Accept")
|
||||
self.assertEqual(activity["actor"], self.local_user.remote_id)
|
||||
self.assertEqual(activity["object"]["id"], "https://www.hi.com/")
|
||||
|
||||
self.local_user.manually_approves_followers = True
|
||||
self.local_user.save(broadcast=False)
|
||||
models.UserFollowRequest.broadcast = mock_broadcast
|
||||
self.local_user.save(
|
||||
broadcast=False, update_fields=["manually_approves_followers"]
|
||||
)
|
||||
|
||||
request = models.UserFollowRequest.objects.create(
|
||||
user_subject=self.remote_user,
|
||||
user_object=self.local_user,
|
||||
@ -107,32 +96,34 @@ class Relationship(TestCase):
|
||||
)
|
||||
request.accept()
|
||||
|
||||
activity = json.loads(broadcast_mock.call_args[0][1])
|
||||
self.assertEqual(activity["type"], "Accept")
|
||||
self.assertEqual(activity["actor"], self.local_user.remote_id)
|
||||
self.assertEqual(activity["object"]["id"], "https://www.hi.com/")
|
||||
|
||||
self.assertFalse(models.UserFollowRequest.objects.exists())
|
||||
self.assertTrue(models.UserFollows.objects.exists())
|
||||
rel = models.UserFollows.objects.get()
|
||||
self.assertEqual(rel.user_subject, self.remote_user)
|
||||
self.assertEqual(rel.user_object, self.local_user)
|
||||
models.UserFollowRequest.broadcast = real_broadcast
|
||||
|
||||
def test_follow_request_reject(self):
|
||||
@patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay")
|
||||
def test_follow_request_reject(self, broadcast_mock, _):
|
||||
"""accept a request and make it a relationship"""
|
||||
real_broadcast = models.UserFollowRequest.broadcast
|
||||
|
||||
def mock_reject(_, activity, user):
|
||||
self.assertEqual(user.remote_id, self.local_user.remote_id)
|
||||
self.assertEqual(activity["type"], "Reject")
|
||||
self.assertEqual(activity["actor"], self.local_user.remote_id)
|
||||
self.assertEqual(activity["object"]["id"], request.remote_id)
|
||||
|
||||
models.UserFollowRequest.broadcast = mock_reject
|
||||
self.local_user.manually_approves_followers = True
|
||||
self.local_user.save(broadcast=False)
|
||||
self.local_user.save(
|
||||
broadcast=False, update_fields=["manually_approves_followers"]
|
||||
)
|
||||
request = models.UserFollowRequest.objects.create(
|
||||
user_subject=self.remote_user,
|
||||
user_object=self.local_user,
|
||||
)
|
||||
request.reject()
|
||||
|
||||
activity = json.loads(broadcast_mock.call_args[0][1])
|
||||
self.assertEqual(activity["type"], "Reject")
|
||||
self.assertEqual(activity["actor"], self.local_user.remote_id)
|
||||
self.assertEqual(activity["object"]["id"], request.remote_id)
|
||||
|
||||
self.assertFalse(models.UserFollowRequest.objects.exists())
|
||||
self.assertFalse(models.UserFollows.objects.exists())
|
||||
models.UserFollowRequest.broadcast = real_broadcast
|
||||
|
@ -7,18 +7,25 @@ from bookwyrm import models, settings
|
||||
|
||||
|
||||
# pylint: disable=unused-argument
|
||||
@patch("bookwyrm.suggested_users.rerank_suggestions_task.delay")
|
||||
@patch("bookwyrm.activitystreams.populate_stream_task.delay")
|
||||
@patch("bookwyrm.activitystreams.add_book_statuses_task.delay")
|
||||
@patch("bookwyrm.activitystreams.remove_book_statuses_task.delay")
|
||||
class Shelf(TestCase):
|
||||
"""some activitypub oddness ahead"""
|
||||
|
||||
def setUp(self):
|
||||
"""look, a shelf"""
|
||||
self.local_user = models.User.objects.create_user(
|
||||
"mouse", "mouse@mouse.mouse", "mouseword", local=True, localname="mouse"
|
||||
)
|
||||
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
|
||||
"bookwyrm.activitystreams.populate_stream_task.delay"
|
||||
):
|
||||
self.local_user = models.User.objects.create_user(
|
||||
"mouse", "mouse@mouse.mouse", "mouseword", local=True, localname="mouse"
|
||||
)
|
||||
work = models.Work.objects.create(title="Test Work")
|
||||
self.book = models.Edition.objects.create(title="test book", parent_work=work)
|
||||
|
||||
def test_remote_id(self):
|
||||
def test_remote_id(self, *_):
|
||||
"""shelves use custom remote ids"""
|
||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
|
||||
shelf = models.Shelf.objects.create(
|
||||
@ -27,7 +34,7 @@ class Shelf(TestCase):
|
||||
expected_id = "https://%s/user/mouse/books/test-shelf" % settings.DOMAIN
|
||||
self.assertEqual(shelf.get_remote_id(), expected_id)
|
||||
|
||||
def test_to_activity(self):
|
||||
def test_to_activity(self, *_):
|
||||
"""jsonify it"""
|
||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
|
||||
shelf = models.Shelf.objects.create(
|
||||
@ -41,7 +48,7 @@ class Shelf(TestCase):
|
||||
self.assertEqual(activity_json["name"], "Test Shelf")
|
||||
self.assertEqual(activity_json["owner"], self.local_user.remote_id)
|
||||
|
||||
def test_create_update_shelf(self):
|
||||
def test_create_update_shelf(self, *_):
|
||||
"""create and broadcast shelf creation"""
|
||||
|
||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay") as mock:
|
||||
@ -62,7 +69,7 @@ class Shelf(TestCase):
|
||||
self.assertEqual(activity["object"]["name"], "arthur russel")
|
||||
self.assertEqual(shelf.name, "arthur russel")
|
||||
|
||||
def test_shelve(self):
|
||||
def test_shelve(self, *_):
|
||||
"""create and broadcast shelf creation"""
|
||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
|
||||
shelf = models.Shelf.objects.create(
|
||||
|
95
bookwyrm/tests/models/test_site.py
Normal file
95
bookwyrm/tests/models/test_site.py
Normal file
@ -0,0 +1,95 @@
|
||||
""" testing models """
|
||||
from datetime import timedelta
|
||||
from unittest.mock import patch
|
||||
|
||||
from django.db import IntegrityError
|
||||
from django.test import TestCase
|
||||
from django.utils import timezone
|
||||
|
||||
from bookwyrm import models, settings
|
||||
|
||||
|
||||
class SiteModels(TestCase):
|
||||
"""tests for site models"""
|
||||
|
||||
def setUp(self):
|
||||
"""we need basic test data and mocks"""
|
||||
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
|
||||
"bookwyrm.activitystreams.populate_stream_task.delay"
|
||||
):
|
||||
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",
|
||||
)
|
||||
|
||||
def test_site_settings_absent(self):
|
||||
"""create and load site settings"""
|
||||
self.assertFalse(models.SiteSettings.objects.exists())
|
||||
result = models.SiteSettings.get()
|
||||
self.assertTrue(models.SiteSettings.objects.exists())
|
||||
self.assertEqual(result.id, 1)
|
||||
self.assertEqual(result.name, "BookWyrm")
|
||||
|
||||
def test_site_settings_present(self):
|
||||
"""load site settings"""
|
||||
models.SiteSettings.objects.create(id=1, name="Fish Town")
|
||||
result = models.SiteSettings.get()
|
||||
self.assertEqual(result.id, 1)
|
||||
self.assertEqual(result.name, "Fish Town")
|
||||
self.assertEqual(models.SiteSettings.objects.all().count(), 1)
|
||||
|
||||
def test_site_invite(self):
|
||||
"""default invite"""
|
||||
invite = models.SiteInvite.objects.create(
|
||||
user=self.local_user,
|
||||
)
|
||||
self.assertTrue(invite.valid())
|
||||
|
||||
def test_site_invite_with_limit(self):
|
||||
"""with use limit"""
|
||||
# valid
|
||||
invite = models.SiteInvite.objects.create(user=self.local_user, use_limit=1)
|
||||
self.assertTrue(invite.valid())
|
||||
|
||||
# invalid
|
||||
invite = models.SiteInvite.objects.create(user=self.local_user, use_limit=0)
|
||||
self.assertFalse(invite.valid())
|
||||
invite = models.SiteInvite.objects.create(
|
||||
user=self.local_user, use_limit=1, times_used=1
|
||||
)
|
||||
self.assertFalse(invite.valid())
|
||||
|
||||
def test_site_invite_with_expiry(self):
|
||||
"""with expiration date"""
|
||||
date = timezone.now() + timedelta(days=1)
|
||||
invite = models.SiteInvite.objects.create(user=self.local_user, expiry=date)
|
||||
self.assertTrue(invite.valid())
|
||||
|
||||
date = timezone.now() - timedelta(days=1)
|
||||
invite = models.SiteInvite.objects.create(user=self.local_user, expiry=date)
|
||||
self.assertFalse(invite.valid())
|
||||
|
||||
def test_site_invite_link(self):
|
||||
"""invite link generator"""
|
||||
invite = models.SiteInvite.objects.create(user=self.local_user, code="hello")
|
||||
self.assertEqual(invite.link, f"https://{settings.DOMAIN}/invite/hello")
|
||||
|
||||
def test_invite_request(self):
|
||||
"""someone wants an invite"""
|
||||
# normal and good
|
||||
request = models.InviteRequest.objects.create(email="mouse.reeve@gmail.com")
|
||||
self.assertIsNone(request.invite)
|
||||
|
||||
# already in use
|
||||
with self.assertRaises(IntegrityError):
|
||||
request = models.InviteRequest.objects.create(email="mouse@mouse.com")
|
||||
|
||||
def test_password_reset(self):
|
||||
"""password reset token"""
|
||||
token = models.PasswordReset.objects.create(user=self.local_user, code="hello")
|
||||
self.assertTrue(token.valid())
|
||||
self.assertEqual(token.link, f"https://{settings.DOMAIN}/password-reset/hello")
|
@ -3,28 +3,34 @@ from unittest.mock import patch
|
||||
from io import BytesIO
|
||||
import pathlib
|
||||
|
||||
from PIL import Image
|
||||
from django.http import Http404
|
||||
from django.core.files.base import ContentFile
|
||||
from django.db import IntegrityError
|
||||
from django.contrib.auth.models import AnonymousUser
|
||||
from django.test import TestCase
|
||||
from django.utils import timezone
|
||||
from PIL import Image
|
||||
import responses
|
||||
|
||||
from bookwyrm import activitypub, models, settings
|
||||
|
||||
|
||||
# pylint: disable=too-many-public-methods
|
||||
# pylint: disable=line-too-long
|
||||
@patch("bookwyrm.models.Status.broadcast")
|
||||
@patch("bookwyrm.activitystreams.ActivityStream.add_status")
|
||||
@patch("bookwyrm.activitystreams.ActivityStream.remove_object_from_related_stores")
|
||||
@patch("bookwyrm.activitystreams.add_status_task.delay")
|
||||
@patch("bookwyrm.activitystreams.remove_status_task.delay")
|
||||
class Status(TestCase):
|
||||
"""lotta types of statuses"""
|
||||
|
||||
def setUp(self):
|
||||
"""useful things for creating a status"""
|
||||
self.local_user = models.User.objects.create_user(
|
||||
"mouse", "mouse@mouse.mouse", "mouseword", local=True, localname="mouse"
|
||||
)
|
||||
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
|
||||
"bookwyrm.activitystreams.populate_stream_task.delay"
|
||||
):
|
||||
self.local_user = models.User.objects.create_user(
|
||||
"mouse", "mouse@mouse.mouse", "mouseword", local=True, localname="mouse"
|
||||
)
|
||||
with patch("bookwyrm.models.user.set_remote_server.delay"):
|
||||
self.remote_user = models.User.objects.create_user(
|
||||
"rat",
|
||||
@ -46,25 +52,32 @@ class Status(TestCase):
|
||||
image.save(output, format=image.format)
|
||||
self.book.cover.save("test.jpg", ContentFile(output.getvalue()))
|
||||
|
||||
self.anonymous_user = AnonymousUser
|
||||
self.anonymous_user.is_authenticated = False
|
||||
|
||||
def test_status_generated_fields(self, *_):
|
||||
"""setting remote id"""
|
||||
status = models.Status.objects.create(content="bleh", user=self.local_user)
|
||||
expected_id = "https://%s/user/mouse/status/%d" % (settings.DOMAIN, status.id)
|
||||
expected_id = f"https://{settings.DOMAIN}/user/mouse/status/{status.id}"
|
||||
self.assertEqual(status.remote_id, expected_id)
|
||||
self.assertEqual(status.privacy, "public")
|
||||
|
||||
def test_replies(self, *_):
|
||||
"""get a list of replies"""
|
||||
parent = models.Status.objects.create(content="hi", user=self.local_user)
|
||||
child = models.Status.objects.create(
|
||||
parent = models.Status(content="hi", user=self.local_user)
|
||||
parent.save(broadcast=False)
|
||||
child = models.Status(
|
||||
content="hello", reply_parent=parent, user=self.local_user
|
||||
)
|
||||
models.Review.objects.create(
|
||||
child.save(broadcast=False)
|
||||
sibling = models.Review(
|
||||
content="hey", reply_parent=parent, user=self.local_user, book=self.book
|
||||
)
|
||||
models.Status.objects.create(
|
||||
sibling.save(broadcast=False)
|
||||
grandchild = models.Status(
|
||||
content="hi hello", reply_parent=child, user=self.local_user
|
||||
)
|
||||
grandchild.save(broadcast=False)
|
||||
|
||||
replies = models.Status.replies(parent)
|
||||
self.assertEqual(replies.count(), 2)
|
||||
@ -72,6 +85,11 @@ class Status(TestCase):
|
||||
# should select subclasses
|
||||
self.assertIsInstance(replies.last(), models.Review)
|
||||
|
||||
self.assertEqual(parent.thread_id, parent.id)
|
||||
self.assertEqual(child.thread_id, parent.id)
|
||||
self.assertEqual(sibling.thread_id, parent.id)
|
||||
self.assertEqual(grandchild.thread_id, parent.id)
|
||||
|
||||
def test_status_type(self, *_):
|
||||
"""class name"""
|
||||
self.assertEqual(models.Status().status_type, "Note")
|
||||
@ -101,7 +119,7 @@ class Status(TestCase):
|
||||
)
|
||||
|
||||
replies = parent.to_replies()
|
||||
self.assertEqual(replies["id"], "%s/replies" % parent.remote_id)
|
||||
self.assertEqual(replies["id"], f"{parent.remote_id}/replies")
|
||||
self.assertEqual(replies["totalItems"], 2)
|
||||
|
||||
def test_status_to_activity(self, *_):
|
||||
@ -117,15 +135,12 @@ class Status(TestCase):
|
||||
|
||||
def test_status_to_activity_tombstone(self, *_):
|
||||
"""subclass of the base model version with a "pure" serializer"""
|
||||
with patch(
|
||||
"bookwyrm.activitystreams.ActivityStream.remove_object_from_related_stores"
|
||||
):
|
||||
status = models.Status.objects.create(
|
||||
content="test content",
|
||||
user=self.local_user,
|
||||
deleted=True,
|
||||
deleted_date=timezone.now(),
|
||||
)
|
||||
status = models.Status.objects.create(
|
||||
content="test content",
|
||||
user=self.local_user,
|
||||
deleted=True,
|
||||
deleted_date=timezone.now(),
|
||||
)
|
||||
activity = status.to_activity()
|
||||
self.assertEqual(activity["id"], status.remote_id)
|
||||
self.assertEqual(activity["type"], "Tombstone")
|
||||
@ -168,7 +183,7 @@ class Status(TestCase):
|
||||
self.assertEqual(activity["id"], status.remote_id)
|
||||
self.assertEqual(
|
||||
activity["content"],
|
||||
'mouse test content <a href="%s">"Test Edition"</a>' % self.book.remote_id,
|
||||
f'mouse test content <a href="{self.book.remote_id}">"Test Edition"</a>',
|
||||
)
|
||||
self.assertEqual(len(activity["tag"]), 2)
|
||||
self.assertEqual(activity["type"], "Note")
|
||||
@ -177,7 +192,7 @@ class Status(TestCase):
|
||||
self.assertEqual(activity["attachment"][0].type, "Document")
|
||||
self.assertEqual(
|
||||
activity["attachment"][0].url,
|
||||
"https://%s%s" % (settings.MEDIA_FULL_URL, self.book.cover.url),
|
||||
f"https://{settings.MEDIA_FULL_URL}{self.book.cover.url}",
|
||||
)
|
||||
self.assertEqual(activity["attachment"][0].name, "Test Edition")
|
||||
|
||||
@ -202,13 +217,12 @@ class Status(TestCase):
|
||||
self.assertEqual(activity["type"], "Note")
|
||||
self.assertEqual(
|
||||
activity["content"],
|
||||
'test content<p>(comment on <a href="%s">"Test Edition"</a>)</p>'
|
||||
% self.book.remote_id,
|
||||
f'test content<p>(comment on <a href="{self.book.remote_id}">"Test Edition"</a>)</p>',
|
||||
)
|
||||
self.assertEqual(activity["attachment"][0].type, "Document")
|
||||
self.assertEqual(
|
||||
activity["attachment"][0].url,
|
||||
"https://%s%s" % (settings.MEDIA_FULL_URL, self.book.cover.url),
|
||||
f"https://{settings.MEDIA_FULL_URL}{self.book.cover.url}",
|
||||
)
|
||||
self.assertEqual(activity["attachment"][0].name, "Test Edition")
|
||||
|
||||
@ -240,13 +254,12 @@ class Status(TestCase):
|
||||
self.assertEqual(activity["type"], "Note")
|
||||
self.assertEqual(
|
||||
activity["content"],
|
||||
'a sickening sense <p>-- <a href="%s">"Test Edition"</a></p>'
|
||||
"test content" % self.book.remote_id,
|
||||
f'a sickening sense <p>-- <a href="{self.book.remote_id}">"Test Edition"</a></p>test content',
|
||||
)
|
||||
self.assertEqual(activity["attachment"][0].type, "Document")
|
||||
self.assertEqual(
|
||||
activity["attachment"][0].url,
|
||||
"https://%s%s" % (settings.MEDIA_FULL_URL, self.book.cover.url),
|
||||
"https://{settings.MEDIA_FULL_URL}{self.book.cover.url}",
|
||||
)
|
||||
self.assertEqual(activity["attachment"][0].name, "Test Edition")
|
||||
|
||||
@ -281,13 +294,13 @@ class Status(TestCase):
|
||||
self.assertEqual(activity["type"], "Article")
|
||||
self.assertEqual(
|
||||
activity["name"],
|
||||
'Review of "%s" (3 stars): Review\'s name' % self.book.title,
|
||||
f'Review of "{self.book.title}" (3 stars): Review\'s name',
|
||||
)
|
||||
self.assertEqual(activity["content"], "test content")
|
||||
self.assertEqual(activity["attachment"][0].type, "Document")
|
||||
self.assertEqual(
|
||||
activity["attachment"][0].url,
|
||||
"https://%s%s" % (settings.MEDIA_FULL_URL, self.book.cover.url),
|
||||
f"https://{settings.MEDIA_FULL_URL}{self.book.cover.url}",
|
||||
)
|
||||
self.assertEqual(activity["attachment"][0].name, "Test Edition")
|
||||
|
||||
@ -303,13 +316,13 @@ class Status(TestCase):
|
||||
self.assertEqual(activity["id"], status.remote_id)
|
||||
self.assertEqual(activity["type"], "Article")
|
||||
self.assertEqual(
|
||||
activity["name"], 'Review of "%s": Review name' % self.book.title
|
||||
activity["name"], f'Review of "{self.book.title}": Review name'
|
||||
)
|
||||
self.assertEqual(activity["content"], "test content")
|
||||
self.assertEqual(activity["attachment"][0].type, "Document")
|
||||
self.assertEqual(
|
||||
activity["attachment"][0].url,
|
||||
"https://%s%s" % (settings.MEDIA_FULL_URL, self.book.cover.url),
|
||||
f"https://{settings.MEDIA_FULL_URL}{self.book.cover.url}",
|
||||
)
|
||||
self.assertEqual(activity["attachment"][0].name, "Test Edition")
|
||||
|
||||
@ -325,13 +338,12 @@ class Status(TestCase):
|
||||
self.assertEqual(activity["type"], "Note")
|
||||
self.assertEqual(
|
||||
activity["content"],
|
||||
'Rated <em><a href="%s">%s</a></em>: 3 stars'
|
||||
% (self.book.remote_id, self.book.title),
|
||||
f'rated <em><a href="{self.book.remote_id}">{self.book.title}</a></em>: 3 stars',
|
||||
)
|
||||
self.assertEqual(activity["attachment"][0].type, "Document")
|
||||
self.assertEqual(
|
||||
activity["attachment"][0].url,
|
||||
"https://%s%s" % (settings.MEDIA_FULL_URL, self.book.cover.url),
|
||||
f"https://{settings.MEDIA_FULL_URL}{self.book.cover.url}",
|
||||
)
|
||||
self.assertEqual(activity["attachment"][0].name, "Test Edition")
|
||||
|
||||
@ -453,3 +465,60 @@ class Status(TestCase):
|
||||
responses.add(responses.GET, "http://fish.com/nothing", status=404)
|
||||
|
||||
self.assertTrue(models.Status.ignore_activity(activity))
|
||||
|
||||
def test_raise_visible_to_user_public(self, *_):
|
||||
"""privacy settings"""
|
||||
status = models.Status.objects.create(
|
||||
content="bleh", user=self.local_user, privacy="public"
|
||||
)
|
||||
self.assertIsNone(status.raise_visible_to_user(self.remote_user))
|
||||
self.assertIsNone(status.raise_visible_to_user(self.local_user))
|
||||
self.assertIsNone(status.raise_visible_to_user(self.anonymous_user))
|
||||
|
||||
def test_raise_visible_to_user_unlisted(self, *_):
|
||||
"""privacy settings"""
|
||||
status = models.Status.objects.create(
|
||||
content="bleh", user=self.local_user, privacy="unlisted"
|
||||
)
|
||||
self.assertIsNone(status.raise_visible_to_user(self.remote_user))
|
||||
self.assertIsNone(status.raise_visible_to_user(self.local_user))
|
||||
self.assertIsNone(status.raise_visible_to_user(self.anonymous_user))
|
||||
|
||||
@patch("bookwyrm.suggested_users.rerank_suggestions_task.delay")
|
||||
def test_raise_visible_to_user_followers(self, *_):
|
||||
"""privacy settings"""
|
||||
status = models.Status.objects.create(
|
||||
content="bleh", user=self.local_user, privacy="followers"
|
||||
)
|
||||
status.raise_visible_to_user(self.local_user)
|
||||
with self.assertRaises(Http404):
|
||||
status.raise_visible_to_user(self.remote_user)
|
||||
with self.assertRaises(Http404):
|
||||
status.raise_visible_to_user(self.anonymous_user)
|
||||
|
||||
self.local_user.followers.add(self.remote_user)
|
||||
self.assertIsNone(status.raise_visible_to_user(self.remote_user))
|
||||
|
||||
def test_raise_visible_to_user_followers_mentioned(self, *_):
|
||||
"""privacy settings"""
|
||||
status = models.Status.objects.create(
|
||||
content="bleh", user=self.local_user, privacy="followers"
|
||||
)
|
||||
status.mention_users.set([self.remote_user])
|
||||
self.assertIsNone(status.raise_visible_to_user(self.remote_user))
|
||||
|
||||
@patch("bookwyrm.suggested_users.rerank_suggestions_task.delay")
|
||||
def test_raise_visible_to_user_direct(self, *_):
|
||||
"""privacy settings"""
|
||||
status = models.Status.objects.create(
|
||||
content="bleh", user=self.local_user, privacy="direct"
|
||||
)
|
||||
status.raise_visible_to_user(self.local_user)
|
||||
with self.assertRaises(Http404):
|
||||
status.raise_visible_to_user(self.remote_user)
|
||||
with self.assertRaises(Http404):
|
||||
status.raise_visible_to_user(self.anonymous_user)
|
||||
|
||||
# mentioned user
|
||||
status.mention_users.set([self.remote_user])
|
||||
self.assertIsNone(status.raise_visible_to_user(self.remote_user))
|
||||
|
@ -5,31 +5,37 @@ from django.test import TestCase
|
||||
import responses
|
||||
|
||||
from bookwyrm import models
|
||||
from bookwyrm.settings import DOMAIN
|
||||
from bookwyrm.settings import USE_HTTPS, DOMAIN
|
||||
|
||||
# pylint: disable=missing-class-docstring
|
||||
# pylint: disable=missing-function-docstring
|
||||
class User(TestCase):
|
||||
protocol = "https://" if USE_HTTPS else "http://"
|
||||
|
||||
def setUp(self):
|
||||
self.user = models.User.objects.create_user(
|
||||
"mouse@%s" % DOMAIN,
|
||||
"mouse@mouse.mouse",
|
||||
"mouseword",
|
||||
local=True,
|
||||
localname="mouse",
|
||||
name="hi",
|
||||
bookwyrm_user=False,
|
||||
)
|
||||
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
|
||||
"bookwyrm.activitystreams.populate_stream_task.delay"
|
||||
):
|
||||
self.user = models.User.objects.create_user(
|
||||
"mouse@%s" % DOMAIN,
|
||||
"mouse@mouse.mouse",
|
||||
"mouseword",
|
||||
local=True,
|
||||
localname="mouse",
|
||||
name="hi",
|
||||
bookwyrm_user=False,
|
||||
)
|
||||
|
||||
def test_computed_fields(self):
|
||||
"""username instead of id here"""
|
||||
expected_id = "https://%s/user/mouse" % DOMAIN
|
||||
expected_id = f"{self.protocol}{DOMAIN}/user/mouse"
|
||||
self.assertEqual(self.user.remote_id, expected_id)
|
||||
self.assertEqual(self.user.username, "mouse@%s" % DOMAIN)
|
||||
self.assertEqual(self.user.username, f"mouse@{DOMAIN}")
|
||||
self.assertEqual(self.user.localname, "mouse")
|
||||
self.assertEqual(self.user.shared_inbox, "https://%s/inbox" % DOMAIN)
|
||||
self.assertEqual(self.user.inbox, "%s/inbox" % expected_id)
|
||||
self.assertEqual(self.user.outbox, "%s/outbox" % expected_id)
|
||||
self.assertEqual(self.user.shared_inbox, f"{self.protocol}{DOMAIN}/inbox")
|
||||
self.assertEqual(self.user.inbox, f"{expected_id}/inbox")
|
||||
self.assertEqual(self.user.outbox, f"{expected_id}/outbox")
|
||||
self.assertEqual(self.user.followers_url, f"{expected_id}/followers")
|
||||
self.assertIsNotNone(self.user.key_pair.private_key)
|
||||
self.assertIsNotNone(self.user.key_pair.public_key)
|
||||
|
||||
@ -154,7 +160,8 @@ class User(TestCase):
|
||||
self.assertIsNone(server.application_type)
|
||||
self.assertIsNone(server.application_version)
|
||||
|
||||
def test_delete_user(self):
|
||||
@patch("bookwyrm.suggested_users.remove_user_task.delay")
|
||||
def test_delete_user(self, _):
|
||||
"""deactivate a user"""
|
||||
self.assertTrue(self.user.is_active)
|
||||
with patch(
|
||||
|
Reference in New Issue
Block a user