Merge branch 'main' into create-book
This commit is contained in:
@@ -7,19 +7,18 @@ from bookwyrm import models
|
||||
class Author(TestCase):
|
||||
def setUp(self):
|
||||
self.book = models.Edition.objects.create(
|
||||
title='Example Edition',
|
||||
remote_id='https://example.com/book/1',
|
||||
title="Example Edition",
|
||||
remote_id="https://example.com/book/1",
|
||||
)
|
||||
self.author = models.Author.objects.create(
|
||||
name='Author fullname',
|
||||
aliases=['One', 'Two'],
|
||||
bio='bio bio bio',
|
||||
name="Author fullname",
|
||||
aliases=["One", "Two"],
|
||||
bio="bio bio bio",
|
||||
)
|
||||
|
||||
|
||||
def test_serialize_model(self):
|
||||
activity = self.author.to_activity()
|
||||
self.assertEqual(activity['id'], self.author.remote_id)
|
||||
self.assertIsInstance(activity['aliases'], list)
|
||||
self.assertEqual(activity['aliases'], ['One', 'Two'])
|
||||
self.assertEqual(activity['name'], 'Author fullname')
|
||||
self.assertEqual(activity["id"], self.author.remote_id)
|
||||
self.assertIsInstance(activity["aliases"], list)
|
||||
self.assertEqual(activity["aliases"], ["One", "Two"])
|
||||
self.assertEqual(activity["name"], "Author fullname")
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
''' tests the base functionality for activitypub dataclasses '''
|
||||
""" tests the base functionality for activitypub dataclasses """
|
||||
from io import BytesIO
|
||||
import json
|
||||
import pathlib
|
||||
@@ -10,231 +10,229 @@ from PIL import Image
|
||||
import responses
|
||||
|
||||
from bookwyrm import activitypub
|
||||
from bookwyrm.activitypub.base_activity import ActivityObject, \
|
||||
resolve_remote_id, set_related_field
|
||||
from bookwyrm.activitypub.base_activity import (
|
||||
ActivityObject,
|
||||
resolve_remote_id,
|
||||
set_related_field,
|
||||
)
|
||||
from bookwyrm.activitypub import ActivitySerializerError
|
||||
from bookwyrm import models
|
||||
|
||||
|
||||
class BaseActivity(TestCase):
|
||||
''' the super class for model-linked activitypub dataclasses '''
|
||||
""" the super class for model-linked activitypub dataclasses """
|
||||
|
||||
def setUp(self):
|
||||
''' we're probably going to re-use this so why copy/paste '''
|
||||
""" we're probably going to re-use this so why copy/paste """
|
||||
self.user = models.User.objects.create_user(
|
||||
'mouse', 'mouse@mouse.mouse', 'mouseword',
|
||||
local=True, localname='mouse')
|
||||
self.user.remote_id = 'http://example.com/a/b'
|
||||
"mouse", "mouse@mouse.mouse", "mouseword", local=True, localname="mouse"
|
||||
)
|
||||
self.user.remote_id = "http://example.com/a/b"
|
||||
self.user.save(broadcast=False)
|
||||
|
||||
datafile = pathlib.Path(__file__).parent.joinpath(
|
||||
'../data/ap_user.json'
|
||||
)
|
||||
datafile = pathlib.Path(__file__).parent.joinpath("../data/ap_user.json")
|
||||
self.userdata = json.loads(datafile.read_bytes())
|
||||
# don't try to load the user icon
|
||||
del self.userdata['icon']
|
||||
del self.userdata["icon"]
|
||||
|
||||
image_file = pathlib.Path(__file__).parent.joinpath(
|
||||
'../../static/images/default_avi.jpg')
|
||||
"../../static/images/default_avi.jpg"
|
||||
)
|
||||
image = Image.open(image_file)
|
||||
output = BytesIO()
|
||||
image.save(output, format=image.format)
|
||||
self.image_data = output.getvalue()
|
||||
|
||||
def test_init(self):
|
||||
''' simple successfuly init '''
|
||||
instance = ActivityObject(id='a', type='b')
|
||||
self.assertTrue(hasattr(instance, 'id'))
|
||||
self.assertTrue(hasattr(instance, 'type'))
|
||||
""" simple successfuly init """
|
||||
instance = ActivityObject(id="a", type="b")
|
||||
self.assertTrue(hasattr(instance, "id"))
|
||||
self.assertTrue(hasattr(instance, "type"))
|
||||
|
||||
def test_init_missing(self):
|
||||
''' init with missing required params '''
|
||||
""" init with missing required params """
|
||||
with self.assertRaises(ActivitySerializerError):
|
||||
ActivityObject()
|
||||
|
||||
def test_init_extra_fields(self):
|
||||
''' init ignoring additional fields '''
|
||||
instance = ActivityObject(id='a', type='b', fish='c')
|
||||
self.assertTrue(hasattr(instance, 'id'))
|
||||
self.assertTrue(hasattr(instance, 'type'))
|
||||
""" init ignoring additional fields """
|
||||
instance = ActivityObject(id="a", type="b", fish="c")
|
||||
self.assertTrue(hasattr(instance, "id"))
|
||||
self.assertTrue(hasattr(instance, "type"))
|
||||
|
||||
def test_init_default_field(self):
|
||||
''' replace an existing required field with a default field '''
|
||||
""" replace an existing required field with a default field """
|
||||
|
||||
@dataclass(init=False)
|
||||
class TestClass(ActivityObject):
|
||||
''' test class with default field '''
|
||||
type: str = 'TestObject'
|
||||
""" test class with default field """
|
||||
|
||||
instance = TestClass(id='a')
|
||||
self.assertEqual(instance.id, 'a')
|
||||
self.assertEqual(instance.type, 'TestObject')
|
||||
type: str = "TestObject"
|
||||
|
||||
instance = TestClass(id="a")
|
||||
self.assertEqual(instance.id, "a")
|
||||
self.assertEqual(instance.type, "TestObject")
|
||||
|
||||
def test_serialize(self):
|
||||
''' simple function for converting dataclass to dict '''
|
||||
instance = ActivityObject(id='a', type='b')
|
||||
""" simple function for converting dataclass to dict """
|
||||
instance = ActivityObject(id="a", type="b")
|
||||
serialized = instance.serialize()
|
||||
self.assertIsInstance(serialized, dict)
|
||||
self.assertEqual(serialized['id'], 'a')
|
||||
self.assertEqual(serialized['type'], 'b')
|
||||
self.assertEqual(serialized["id"], "a")
|
||||
self.assertEqual(serialized["type"], "b")
|
||||
|
||||
@responses.activate
|
||||
def test_resolve_remote_id(self):
|
||||
''' look up or load remote data '''
|
||||
""" look up or load remote data """
|
||||
# existing item
|
||||
result = resolve_remote_id('http://example.com/a/b', model=models.User)
|
||||
result = resolve_remote_id("http://example.com/a/b", model=models.User)
|
||||
self.assertEqual(result, self.user)
|
||||
|
||||
# remote item
|
||||
responses.add(
|
||||
responses.GET,
|
||||
'https://example.com/user/mouse',
|
||||
"https://example.com/user/mouse",
|
||||
json=self.userdata,
|
||||
status=200)
|
||||
status=200,
|
||||
)
|
||||
|
||||
with patch('bookwyrm.models.user.set_remote_server.delay'):
|
||||
with patch("bookwyrm.models.user.set_remote_server.delay"):
|
||||
result = resolve_remote_id(
|
||||
'https://example.com/user/mouse', model=models.User)
|
||||
"https://example.com/user/mouse", model=models.User
|
||||
)
|
||||
self.assertIsInstance(result, models.User)
|
||||
self.assertEqual(result.remote_id, 'https://example.com/user/mouse')
|
||||
self.assertEqual(result.name, 'MOUSE?? MOUSE!!')
|
||||
self.assertEqual(result.remote_id, "https://example.com/user/mouse")
|
||||
self.assertEqual(result.name, "MOUSE?? MOUSE!!")
|
||||
|
||||
def test_to_model_invalid_model(self):
|
||||
''' catch mismatch between activity type and model type '''
|
||||
instance = ActivityObject(id='a', type='b')
|
||||
""" catch mismatch between activity type and model type """
|
||||
instance = ActivityObject(id="a", type="b")
|
||||
with self.assertRaises(ActivitySerializerError):
|
||||
instance.to_model(model=models.User)
|
||||
|
||||
|
||||
@responses.activate
|
||||
def test_to_model_image(self):
|
||||
''' update an image field '''
|
||||
""" update an image field """
|
||||
activity = activitypub.Person(
|
||||
id=self.user.remote_id,
|
||||
name='New Name',
|
||||
preferredUsername='mouse',
|
||||
inbox='http://www.com/',
|
||||
outbox='http://www.com/',
|
||||
followers='',
|
||||
summary='',
|
||||
publicKey={
|
||||
'id': 'hi',
|
||||
'owner': self.user.remote_id,
|
||||
'publicKeyPem': 'hi'},
|
||||
name="New Name",
|
||||
preferredUsername="mouse",
|
||||
inbox="http://www.com/",
|
||||
outbox="http://www.com/",
|
||||
followers="",
|
||||
summary="",
|
||||
publicKey={"id": "hi", "owner": self.user.remote_id, "publicKeyPem": "hi"},
|
||||
endpoints={},
|
||||
icon={
|
||||
'type': 'Image',
|
||||
'url': 'http://www.example.com/image.jpg'
|
||||
}
|
||||
icon={"type": "Image", "url": "http://www.example.com/image.jpg"},
|
||||
)
|
||||
|
||||
responses.add(
|
||||
responses.GET,
|
||||
'http://www.example.com/image.jpg',
|
||||
"http://www.example.com/image.jpg",
|
||||
body=self.image_data,
|
||||
status=200)
|
||||
status=200,
|
||||
)
|
||||
|
||||
self.assertIsNone(self.user.avatar.name)
|
||||
with self.assertRaises(ValueError):
|
||||
self.user.avatar.file #pylint: disable=pointless-statement
|
||||
self.user.avatar.file # pylint: disable=pointless-statement
|
||||
|
||||
# this would trigger a broadcast because it's a local user
|
||||
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
|
||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
|
||||
activity.to_model(model=models.User, instance=self.user)
|
||||
self.assertIsNotNone(self.user.avatar.file)
|
||||
self.assertEqual(self.user.name, 'New Name')
|
||||
self.assertEqual(self.user.key_pair.public_key, 'hi')
|
||||
self.assertEqual(self.user.name, "New Name")
|
||||
self.assertEqual(self.user.key_pair.public_key, "hi")
|
||||
|
||||
def test_to_model_many_to_many(self):
|
||||
''' annoying that these all need special handling '''
|
||||
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
|
||||
""" annoying that these all need special handling """
|
||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
|
||||
status = models.Status.objects.create(
|
||||
content='test status',
|
||||
content="test status",
|
||||
user=self.user,
|
||||
)
|
||||
book = models.Edition.objects.create(
|
||||
title='Test Edition', remote_id='http://book.com/book')
|
||||
title="Test Edition", remote_id="http://book.com/book"
|
||||
)
|
||||
update_data = activitypub.Note(
|
||||
id=status.remote_id,
|
||||
content=status.content,
|
||||
attributedTo=self.user.remote_id,
|
||||
published='hi',
|
||||
published="hi",
|
||||
to=[],
|
||||
cc=[],
|
||||
tag=[
|
||||
{"type": "Mention", "name": "gerald", "href": "http://example.com/a/b"},
|
||||
{
|
||||
'type': 'Mention',
|
||||
'name': 'gerald',
|
||||
'href': 'http://example.com/a/b'
|
||||
"type": "Edition",
|
||||
"name": "gerald j. books",
|
||||
"href": "http://book.com/book",
|
||||
},
|
||||
{
|
||||
'type': 'Edition',
|
||||
'name': 'gerald j. books',
|
||||
'href': 'http://book.com/book'
|
||||
},
|
||||
]
|
||||
],
|
||||
)
|
||||
update_data.to_model(model=models.Status, instance=status)
|
||||
self.assertEqual(status.mention_users.first(), self.user)
|
||||
self.assertEqual(status.mention_books.first(), book)
|
||||
|
||||
|
||||
@responses.activate
|
||||
def test_to_model_one_to_many(self):
|
||||
''' these are reversed relationships, where the secondary object
|
||||
keys the primary object but not vice versa '''
|
||||
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
|
||||
"""these are reversed relationships, where the secondary object
|
||||
keys the primary object but not vice versa"""
|
||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
|
||||
status = models.Status.objects.create(
|
||||
content='test status',
|
||||
content="test status",
|
||||
user=self.user,
|
||||
)
|
||||
update_data = activitypub.Note(
|
||||
id=status.remote_id,
|
||||
content=status.content,
|
||||
attributedTo=self.user.remote_id,
|
||||
published='hi',
|
||||
published="hi",
|
||||
to=[],
|
||||
cc=[],
|
||||
attachment=[{
|
||||
'url': 'http://www.example.com/image.jpg',
|
||||
'name': 'alt text',
|
||||
'type': 'Image',
|
||||
}],
|
||||
attachment=[
|
||||
{
|
||||
"url": "http://www.example.com/image.jpg",
|
||||
"name": "alt text",
|
||||
"type": "Image",
|
||||
}
|
||||
],
|
||||
)
|
||||
|
||||
responses.add(
|
||||
responses.GET,
|
||||
'http://www.example.com/image.jpg',
|
||||
"http://www.example.com/image.jpg",
|
||||
body=self.image_data,
|
||||
status=200)
|
||||
status=200,
|
||||
)
|
||||
|
||||
# sets the celery task call to the function call
|
||||
with patch(
|
||||
'bookwyrm.activitypub.base_activity.set_related_field.delay'):
|
||||
with patch('bookwyrm.models.status.Status.ignore_activity') \
|
||||
as discarder:
|
||||
with patch("bookwyrm.activitypub.base_activity.set_related_field.delay"):
|
||||
with patch("bookwyrm.models.status.Status.ignore_activity") as discarder:
|
||||
discarder.return_value = False
|
||||
update_data.to_model(model=models.Status, instance=status)
|
||||
self.assertIsNone(status.attachments.first())
|
||||
|
||||
|
||||
@responses.activate
|
||||
def test_set_related_field(self):
|
||||
''' celery task to add back-references to created objects '''
|
||||
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
|
||||
""" celery task to add back-references to created objects """
|
||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
|
||||
status = models.Status.objects.create(
|
||||
content='test status',
|
||||
content="test status",
|
||||
user=self.user,
|
||||
)
|
||||
data = {
|
||||
'url': 'http://www.example.com/image.jpg',
|
||||
'name': 'alt text',
|
||||
'type': 'Image',
|
||||
"url": "http://www.example.com/image.jpg",
|
||||
"name": "alt text",
|
||||
"type": "Image",
|
||||
}
|
||||
responses.add(
|
||||
responses.GET,
|
||||
'http://www.example.com/image.jpg',
|
||||
"http://www.example.com/image.jpg",
|
||||
body=self.image_data,
|
||||
status=200)
|
||||
set_related_field(
|
||||
'Image', 'Status', 'status', status.remote_id, data)
|
||||
status=200,
|
||||
)
|
||||
set_related_field("Image", "Status", "status", status.remote_id, data)
|
||||
|
||||
self.assertIsInstance(status.attachments.first(), models.Image)
|
||||
self.assertIsNotNone(status.attachments.first().image)
|
||||
|
||||
@@ -9,23 +9,19 @@ from bookwyrm import activitypub, models
|
||||
|
||||
class Person(TestCase):
|
||||
def setUp(self):
|
||||
datafile = pathlib.Path(__file__).parent.joinpath(
|
||||
'../data/ap_user.json'
|
||||
)
|
||||
datafile = pathlib.Path(__file__).parent.joinpath("../data/ap_user.json")
|
||||
self.user_data = json.loads(datafile.read_bytes())
|
||||
|
||||
|
||||
def test_load_user_data(self):
|
||||
activity = activitypub.Person(**self.user_data)
|
||||
self.assertEqual(activity.id, 'https://example.com/user/mouse')
|
||||
self.assertEqual(activity.preferredUsername, 'mouse')
|
||||
self.assertEqual(activity.type, 'Person')
|
||||
|
||||
self.assertEqual(activity.id, "https://example.com/user/mouse")
|
||||
self.assertEqual(activity.preferredUsername, "mouse")
|
||||
self.assertEqual(activity.type, "Person")
|
||||
|
||||
def test_user_to_model(self):
|
||||
activity = activitypub.Person(**self.user_data)
|
||||
with patch('bookwyrm.models.user.set_remote_server.delay'):
|
||||
with patch("bookwyrm.models.user.set_remote_server.delay"):
|
||||
user = activity.to_model(model=models.User)
|
||||
self.assertEqual(user.username, 'mouse@example.com')
|
||||
self.assertEqual(user.remote_id, 'https://example.com/user/mouse')
|
||||
self.assertEqual(user.username, "mouse@example.com")
|
||||
self.assertEqual(user.remote_id, "https://example.com/user/mouse")
|
||||
self.assertFalse(user.local)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
''' quotation activty object serializer class '''
|
||||
""" quotation activty object serializer class """
|
||||
import json
|
||||
import pathlib
|
||||
from unittest.mock import patch
|
||||
@@ -8,43 +8,40 @@ from bookwyrm import activitypub, models
|
||||
|
||||
|
||||
class Quotation(TestCase):
|
||||
''' we have hecka ways to create statuses '''
|
||||
""" we have hecka ways to create statuses """
|
||||
|
||||
def setUp(self):
|
||||
''' model objects we'll need '''
|
||||
with patch('bookwyrm.models.user.set_remote_server.delay'):
|
||||
""" model objects we'll need """
|
||||
with patch("bookwyrm.models.user.set_remote_server.delay"):
|
||||
self.user = models.User.objects.create_user(
|
||||
'mouse', 'mouse@mouse.mouse', 'mouseword',
|
||||
"mouse",
|
||||
"mouse@mouse.mouse",
|
||||
"mouseword",
|
||||
local=False,
|
||||
inbox='https://example.com/user/mouse/inbox',
|
||||
outbox='https://example.com/user/mouse/outbox',
|
||||
remote_id='https://example.com/user/mouse',
|
||||
inbox="https://example.com/user/mouse/inbox",
|
||||
outbox="https://example.com/user/mouse/outbox",
|
||||
remote_id="https://example.com/user/mouse",
|
||||
)
|
||||
self.book = models.Edition.objects.create(
|
||||
title='Example Edition',
|
||||
remote_id='https://example.com/book/1',
|
||||
)
|
||||
datafile = pathlib.Path(__file__).parent.joinpath(
|
||||
'../data/ap_quotation.json'
|
||||
title="Example Edition",
|
||||
remote_id="https://example.com/book/1",
|
||||
)
|
||||
datafile = pathlib.Path(__file__).parent.joinpath("../data/ap_quotation.json")
|
||||
self.status_data = json.loads(datafile.read_bytes())
|
||||
|
||||
|
||||
def test_quotation_activity(self):
|
||||
''' create a Quoteation ap object from json '''
|
||||
""" create a Quoteation ap object from json """
|
||||
quotation = activitypub.Quotation(**self.status_data)
|
||||
|
||||
self.assertEqual(quotation.type, 'Quotation')
|
||||
self.assertEqual(
|
||||
quotation.id, 'https://example.com/user/mouse/quotation/13')
|
||||
self.assertEqual(quotation.content, 'commentary')
|
||||
self.assertEqual(quotation.quote, 'quote body')
|
||||
self.assertEqual(quotation.inReplyToBook, 'https://example.com/book/1')
|
||||
self.assertEqual(
|
||||
quotation.published, '2020-05-10T02:38:31.150343+00:00')
|
||||
|
||||
self.assertEqual(quotation.type, "Quotation")
|
||||
self.assertEqual(quotation.id, "https://example.com/user/mouse/quotation/13")
|
||||
self.assertEqual(quotation.content, "commentary")
|
||||
self.assertEqual(quotation.quote, "quote body")
|
||||
self.assertEqual(quotation.inReplyToBook, "https://example.com/book/1")
|
||||
self.assertEqual(quotation.published, "2020-05-10T02:38:31.150343+00:00")
|
||||
|
||||
def test_activity_to_model(self):
|
||||
''' create a model instance from an activity object '''
|
||||
""" create a model instance from an activity object """
|
||||
activity = activitypub.Quotation(**self.status_data)
|
||||
quotation = activity.to_model(model=models.Quotation)
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
''' testing book data connectors '''
|
||||
""" testing book data connectors """
|
||||
from unittest.mock import patch
|
||||
from django.test import TestCase
|
||||
import responses
|
||||
@@ -10,109 +10,115 @@ from bookwyrm.settings import DOMAIN
|
||||
|
||||
|
||||
class AbstractConnector(TestCase):
|
||||
''' generic code for connecting to outside data sources '''
|
||||
""" generic code for connecting to outside data sources """
|
||||
|
||||
def setUp(self):
|
||||
''' we need an example connector '''
|
||||
""" we need an example connector """
|
||||
self.connector_info = models.Connector.objects.create(
|
||||
identifier='example.com',
|
||||
connector_file='openlibrary',
|
||||
base_url='https://example.com',
|
||||
books_url='https://example.com/books',
|
||||
covers_url='https://example.com/covers',
|
||||
search_url='https://example.com/search?q=',
|
||||
identifier="example.com",
|
||||
connector_file="openlibrary",
|
||||
base_url="https://example.com",
|
||||
books_url="https://example.com/books",
|
||||
covers_url="https://example.com/covers",
|
||||
search_url="https://example.com/search?q=",
|
||||
)
|
||||
work_data = {
|
||||
'id': 'abc1',
|
||||
'title': 'Test work',
|
||||
'type': 'work',
|
||||
'openlibraryKey': 'OL1234W',
|
||||
"id": "abc1",
|
||||
"title": "Test work",
|
||||
"type": "work",
|
||||
"openlibraryKey": "OL1234W",
|
||||
}
|
||||
self.work_data = work_data
|
||||
edition_data = {
|
||||
'id': 'abc2',
|
||||
'title': 'Test edition',
|
||||
'type': 'edition',
|
||||
'openlibraryKey': 'OL1234M',
|
||||
"id": "abc2",
|
||||
"title": "Test edition",
|
||||
"type": "edition",
|
||||
"openlibraryKey": "OL1234M",
|
||||
}
|
||||
self.edition_data = edition_data
|
||||
|
||||
class TestConnector(abstract_connector.AbstractConnector):
|
||||
''' nothing added here '''
|
||||
""" nothing added here """
|
||||
|
||||
def format_search_result(self, search_result):
|
||||
return search_result
|
||||
|
||||
def parse_search_data(self, data):
|
||||
return data
|
||||
|
||||
def format_isbn_search_result(self, search_result):
|
||||
return search_result
|
||||
|
||||
def parse_isbn_search_data(self, data):
|
||||
return data
|
||||
|
||||
def is_work_data(self, data):
|
||||
return data['type'] == 'work'
|
||||
return data["type"] == "work"
|
||||
|
||||
def get_edition_from_work_data(self, data):
|
||||
return edition_data
|
||||
|
||||
def get_work_from_edition_data(self, data):
|
||||
return work_data
|
||||
|
||||
def get_authors_from_data(self, data):
|
||||
return []
|
||||
|
||||
def expand_book_data(self, book):
|
||||
pass
|
||||
self.connector = TestConnector('example.com')
|
||||
|
||||
self.connector = TestConnector("example.com")
|
||||
self.connector.book_mappings = [
|
||||
Mapping('id'),
|
||||
Mapping('title'),
|
||||
Mapping('openlibraryKey'),
|
||||
Mapping("id"),
|
||||
Mapping("title"),
|
||||
Mapping("openlibraryKey"),
|
||||
]
|
||||
|
||||
self.book = models.Edition.objects.create(
|
||||
title='Test Book', remote_id='https://example.com/book/1234',
|
||||
openlibrary_key='OL1234M')
|
||||
|
||||
title="Test Book",
|
||||
remote_id="https://example.com/book/1234",
|
||||
openlibrary_key="OL1234M",
|
||||
)
|
||||
|
||||
def test_abstract_connector_init(self):
|
||||
''' barebones connector for search with defaults '''
|
||||
""" barebones connector for search with defaults """
|
||||
self.assertIsInstance(self.connector.book_mappings, list)
|
||||
|
||||
|
||||
def test_is_available(self):
|
||||
''' this isn't used.... '''
|
||||
""" this isn't used.... """
|
||||
self.assertTrue(self.connector.is_available())
|
||||
self.connector.max_query_count = 1
|
||||
self.connector.connector.query_count = 2
|
||||
self.assertFalse(self.connector.is_available())
|
||||
|
||||
|
||||
def test_get_or_create_book_existing(self):
|
||||
''' find an existing book by remote/origin id '''
|
||||
""" find an existing book by remote/origin id """
|
||||
self.assertEqual(models.Book.objects.count(), 1)
|
||||
self.assertEqual(
|
||||
self.book.remote_id, 'https://%s/book/%d' % (DOMAIN, self.book.id))
|
||||
self.assertEqual(
|
||||
self.book.origin_id, 'https://example.com/book/1234')
|
||||
self.book.remote_id, "https://%s/book/%d" % (DOMAIN, self.book.id)
|
||||
)
|
||||
self.assertEqual(self.book.origin_id, "https://example.com/book/1234")
|
||||
|
||||
# dedupe by origin id
|
||||
result = self.connector.get_or_create_book(
|
||||
'https://example.com/book/1234')
|
||||
result = self.connector.get_or_create_book("https://example.com/book/1234")
|
||||
self.assertEqual(models.Book.objects.count(), 1)
|
||||
self.assertEqual(result, self.book)
|
||||
|
||||
# dedupe by remote id
|
||||
result = self.connector.get_or_create_book(
|
||||
'https://%s/book/%d' % (DOMAIN, self.book.id))
|
||||
"https://%s/book/%d" % (DOMAIN, self.book.id)
|
||||
)
|
||||
self.assertEqual(models.Book.objects.count(), 1)
|
||||
self.assertEqual(result, self.book)
|
||||
|
||||
@responses.activate
|
||||
def test_get_or_create_book_deduped(self):
|
||||
''' load remote data and deduplicate '''
|
||||
""" load remote data and deduplicate """
|
||||
responses.add(
|
||||
responses.GET,
|
||||
'https://example.com/book/abcd',
|
||||
json=self.edition_data
|
||||
responses.GET, "https://example.com/book/abcd", json=self.edition_data
|
||||
)
|
||||
with patch(
|
||||
'bookwyrm.connectors.abstract_connector.load_more_data.delay'):
|
||||
result = self.connector.get_or_create_book(
|
||||
'https://example.com/book/abcd')
|
||||
with patch("bookwyrm.connectors.abstract_connector.load_more_data.delay"):
|
||||
result = self.connector.get_or_create_book("https://example.com/book/abcd")
|
||||
self.assertEqual(result, self.book)
|
||||
self.assertEqual(models.Edition.objects.count(), 1)
|
||||
self.assertEqual(models.Edition.objects.count(), 1)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
''' testing book data connectors '''
|
||||
""" testing book data connectors """
|
||||
from django.test import TestCase
|
||||
import responses
|
||||
|
||||
@@ -8,99 +8,101 @@ from bookwyrm.connectors.abstract_connector import Mapping, SearchResult
|
||||
|
||||
|
||||
class AbstractConnector(TestCase):
|
||||
''' generic code for connecting to outside data sources '''
|
||||
""" generic code for connecting to outside data sources """
|
||||
|
||||
def setUp(self):
|
||||
''' we need an example connector '''
|
||||
""" we need an example connector """
|
||||
self.connector_info = models.Connector.objects.create(
|
||||
identifier='example.com',
|
||||
connector_file='openlibrary',
|
||||
base_url='https://example.com',
|
||||
books_url='https://example.com/books',
|
||||
covers_url='https://example.com/covers',
|
||||
search_url='https://example.com/search?q=',
|
||||
isbn_search_url='https://example.com/isbn',
|
||||
identifier="example.com",
|
||||
connector_file="openlibrary",
|
||||
base_url="https://example.com",
|
||||
books_url="https://example.com/books",
|
||||
covers_url="https://example.com/covers",
|
||||
search_url="https://example.com/search?q=",
|
||||
isbn_search_url="https://example.com/isbn",
|
||||
)
|
||||
|
||||
class TestConnector(abstract_connector.AbstractMinimalConnector):
|
||||
''' nothing added here '''
|
||||
""" nothing added here """
|
||||
|
||||
def format_search_result(self, search_result):
|
||||
return search_result
|
||||
|
||||
def get_or_create_book(self, remote_id):
|
||||
pass
|
||||
|
||||
def parse_search_data(self, data):
|
||||
return data
|
||||
|
||||
def format_isbn_search_result(self, search_result):
|
||||
return search_result
|
||||
|
||||
def parse_isbn_search_data(self, data):
|
||||
return data
|
||||
self.test_connector = TestConnector('example.com')
|
||||
|
||||
self.test_connector = TestConnector("example.com")
|
||||
|
||||
def test_abstract_minimal_connector_init(self):
|
||||
''' barebones connector for search with defaults '''
|
||||
""" barebones connector for search with defaults """
|
||||
connector = self.test_connector
|
||||
self.assertEqual(connector.connector, self.connector_info)
|
||||
self.assertEqual(connector.base_url, 'https://example.com')
|
||||
self.assertEqual(connector.books_url, 'https://example.com/books')
|
||||
self.assertEqual(connector.covers_url, 'https://example.com/covers')
|
||||
self.assertEqual(connector.search_url, 'https://example.com/search?q=')
|
||||
self.assertEqual(connector.isbn_search_url, 'https://example.com/isbn')
|
||||
self.assertEqual(connector.base_url, "https://example.com")
|
||||
self.assertEqual(connector.books_url, "https://example.com/books")
|
||||
self.assertEqual(connector.covers_url, "https://example.com/covers")
|
||||
self.assertEqual(connector.search_url, "https://example.com/search?q=")
|
||||
self.assertEqual(connector.isbn_search_url, "https://example.com/isbn")
|
||||
self.assertIsNone(connector.name)
|
||||
self.assertEqual(connector.identifier, 'example.com')
|
||||
self.assertEqual(connector.identifier, "example.com")
|
||||
self.assertIsNone(connector.max_query_count)
|
||||
self.assertFalse(connector.local)
|
||||
|
||||
|
||||
@responses.activate
|
||||
def test_search(self):
|
||||
''' makes an http request to the outside service '''
|
||||
""" makes an http request to the outside service """
|
||||
responses.add(
|
||||
responses.GET,
|
||||
'https://example.com/search?q=a%20book%20title',
|
||||
json=['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l'],
|
||||
status=200)
|
||||
results = self.test_connector.search('a book title')
|
||||
"https://example.com/search?q=a%20book%20title",
|
||||
json=["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l"],
|
||||
status=200,
|
||||
)
|
||||
results = self.test_connector.search("a book title")
|
||||
self.assertEqual(len(results), 10)
|
||||
self.assertEqual(results[0], 'a')
|
||||
self.assertEqual(results[1], 'b')
|
||||
self.assertEqual(results[2], 'c')
|
||||
|
||||
self.assertEqual(results[0], "a")
|
||||
self.assertEqual(results[1], "b")
|
||||
self.assertEqual(results[2], "c")
|
||||
|
||||
def test_search_result(self):
|
||||
''' a class that stores info about a search result '''
|
||||
""" a class that stores info about a search result """
|
||||
result = SearchResult(
|
||||
title='Title',
|
||||
key='https://example.com/book/1',
|
||||
author='Author Name',
|
||||
year='1850',
|
||||
title="Title",
|
||||
key="https://example.com/book/1",
|
||||
author="Author Name",
|
||||
year="1850",
|
||||
connector=self.test_connector,
|
||||
)
|
||||
# there's really not much to test here, it's just a dataclass
|
||||
self.assertEqual(result.confidence, 1)
|
||||
self.assertEqual(result.title, 'Title')
|
||||
|
||||
self.assertEqual(result.title, "Title")
|
||||
|
||||
def test_create_mapping(self):
|
||||
''' maps remote fields for book data to bookwyrm activitypub fields '''
|
||||
mapping = Mapping('isbn')
|
||||
self.assertEqual(mapping.local_field, 'isbn')
|
||||
self.assertEqual(mapping.remote_field, 'isbn')
|
||||
self.assertEqual(mapping.formatter('bb'), 'bb')
|
||||
|
||||
""" maps remote fields for book data to bookwyrm activitypub fields """
|
||||
mapping = Mapping("isbn")
|
||||
self.assertEqual(mapping.local_field, "isbn")
|
||||
self.assertEqual(mapping.remote_field, "isbn")
|
||||
self.assertEqual(mapping.formatter("bb"), "bb")
|
||||
|
||||
def test_create_mapping_with_remote(self):
|
||||
''' the remote field is different than the local field '''
|
||||
mapping = Mapping('isbn', remote_field='isbn13')
|
||||
self.assertEqual(mapping.local_field, 'isbn')
|
||||
self.assertEqual(mapping.remote_field, 'isbn13')
|
||||
self.assertEqual(mapping.formatter('bb'), 'bb')
|
||||
|
||||
""" the remote field is different than the local field """
|
||||
mapping = Mapping("isbn", remote_field="isbn13")
|
||||
self.assertEqual(mapping.local_field, "isbn")
|
||||
self.assertEqual(mapping.remote_field, "isbn13")
|
||||
self.assertEqual(mapping.formatter("bb"), "bb")
|
||||
|
||||
def test_create_mapping_with_formatter(self):
|
||||
''' a function is provided to modify the data '''
|
||||
formatter = lambda x: 'aa' + x
|
||||
mapping = Mapping('isbn', formatter=formatter)
|
||||
self.assertEqual(mapping.local_field, 'isbn')
|
||||
self.assertEqual(mapping.remote_field, 'isbn')
|
||||
""" a function is provided to modify the data """
|
||||
formatter = lambda x: "aa" + x
|
||||
mapping = Mapping("isbn", formatter=formatter)
|
||||
self.assertEqual(mapping.local_field, "isbn")
|
||||
self.assertEqual(mapping.remote_field, "isbn")
|
||||
self.assertEqual(mapping.formatter, formatter)
|
||||
self.assertEqual(mapping.formatter('bb'), 'aabb')
|
||||
self.assertEqual(mapping.formatter("bb"), "aabb")
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
''' testing book data connectors '''
|
||||
""" testing book data connectors """
|
||||
import json
|
||||
import pathlib
|
||||
from django.test import TestCase
|
||||
@@ -9,39 +9,36 @@ from bookwyrm.connectors.abstract_connector import SearchResult
|
||||
|
||||
|
||||
class BookWyrmConnector(TestCase):
|
||||
''' this connector doesn't do much, just search '''
|
||||
def setUp(self):
|
||||
''' create the connector '''
|
||||
models.Connector.objects.create(
|
||||
identifier='example.com',
|
||||
connector_file='bookwyrm_connector',
|
||||
base_url='https://example.com',
|
||||
books_url='https://example.com',
|
||||
covers_url='https://example.com/images/covers',
|
||||
search_url='https://example.com/search?q=',
|
||||
)
|
||||
self.connector = Connector('example.com')
|
||||
""" this connector doesn't do much, just search """
|
||||
|
||||
work_file = pathlib.Path(__file__).parent.joinpath(
|
||||
'../data/bw_work.json')
|
||||
edition_file = pathlib.Path(__file__).parent.joinpath(
|
||||
'../data/bw_edition.json')
|
||||
def setUp(self):
|
||||
""" create the connector """
|
||||
models.Connector.objects.create(
|
||||
identifier="example.com",
|
||||
connector_file="bookwyrm_connector",
|
||||
base_url="https://example.com",
|
||||
books_url="https://example.com",
|
||||
covers_url="https://example.com/images/covers",
|
||||
search_url="https://example.com/search?q=",
|
||||
)
|
||||
self.connector = Connector("example.com")
|
||||
|
||||
work_file = pathlib.Path(__file__).parent.joinpath("../data/bw_work.json")
|
||||
edition_file = pathlib.Path(__file__).parent.joinpath("../data/bw_edition.json")
|
||||
self.work_data = json.loads(work_file.read_bytes())
|
||||
self.edition_data = json.loads(edition_file.read_bytes())
|
||||
|
||||
|
||||
def test_format_search_result(self):
|
||||
''' create a SearchResult object from search response json '''
|
||||
datafile = pathlib.Path(__file__).parent.joinpath(
|
||||
'../data/bw_search.json')
|
||||
""" create a SearchResult object from search response json """
|
||||
datafile = pathlib.Path(__file__).parent.joinpath("../data/bw_search.json")
|
||||
search_data = json.loads(datafile.read_bytes())
|
||||
results = self.connector.parse_search_data(search_data)
|
||||
self.assertIsInstance(results, list)
|
||||
|
||||
result = self.connector.format_search_result(results[0])
|
||||
self.assertIsInstance(result, SearchResult)
|
||||
self.assertEqual(result.title, 'Jonathan Strange and Mr Norrell')
|
||||
self.assertEqual(result.key, 'https://example.com/book/122')
|
||||
self.assertEqual(result.author, 'Susanna Clarke')
|
||||
self.assertEqual(result.title, "Jonathan Strange and Mr Norrell")
|
||||
self.assertEqual(result.key, "https://example.com/book/122")
|
||||
self.assertEqual(result.author, "Susanna Clarke")
|
||||
self.assertEqual(result.year, 2017)
|
||||
self.assertEqual(result.connector, self.connector)
|
||||
|
||||
@@ -1,54 +1,49 @@
|
||||
''' interface between the app and various connectors '''
|
||||
""" interface between the app and various connectors """
|
||||
from django.test import TestCase
|
||||
|
||||
from bookwyrm import models
|
||||
from bookwyrm.connectors import connector_manager
|
||||
from bookwyrm.connectors.bookwyrm_connector \
|
||||
import Connector as BookWyrmConnector
|
||||
from bookwyrm.connectors.self_connector \
|
||||
import Connector as SelfConnector
|
||||
from bookwyrm.connectors.bookwyrm_connector import Connector as BookWyrmConnector
|
||||
from bookwyrm.connectors.self_connector import Connector as SelfConnector
|
||||
|
||||
|
||||
class ConnectorManager(TestCase):
|
||||
''' interface between the app and various connectors '''
|
||||
""" interface between the app and various connectors """
|
||||
|
||||
def setUp(self):
|
||||
''' we'll need some books and a connector info entry '''
|
||||
self.work = models.Work.objects.create(
|
||||
title='Example Work'
|
||||
)
|
||||
""" we'll need some books and a connector info entry """
|
||||
self.work = models.Work.objects.create(title="Example Work")
|
||||
|
||||
self.edition = models.Edition.objects.create(
|
||||
title='Example Edition',
|
||||
parent_work=self.work
|
||||
title="Example Edition", parent_work=self.work
|
||||
)
|
||||
self.work.default_edition = self.edition
|
||||
self.work.save()
|
||||
|
||||
self.connector = models.Connector.objects.create(
|
||||
identifier='test_connector',
|
||||
identifier="test_connector",
|
||||
priority=1,
|
||||
local=True,
|
||||
connector_file='self_connector',
|
||||
base_url='http://test.com/',
|
||||
books_url='http://test.com/',
|
||||
covers_url='http://test.com/',
|
||||
connector_file="self_connector",
|
||||
base_url="http://test.com/",
|
||||
books_url="http://test.com/",
|
||||
covers_url="http://test.com/",
|
||||
)
|
||||
|
||||
|
||||
def test_get_or_create_connector(self):
|
||||
''' loads a connector if the data source is known or creates one '''
|
||||
remote_id = 'https://example.com/object/1'
|
||||
""" loads a connector if the data source is known or creates one """
|
||||
remote_id = "https://example.com/object/1"
|
||||
connector = connector_manager.get_or_create_connector(remote_id)
|
||||
self.assertIsInstance(connector, BookWyrmConnector)
|
||||
self.assertEqual(connector.identifier, 'example.com')
|
||||
self.assertEqual(connector.base_url, 'https://example.com')
|
||||
self.assertEqual(connector.identifier, "example.com")
|
||||
self.assertEqual(connector.base_url, "https://example.com")
|
||||
|
||||
same_connector = connector_manager.get_or_create_connector(remote_id)
|
||||
self.assertEqual(connector.identifier, same_connector.identifier)
|
||||
|
||||
def test_get_connectors(self):
|
||||
''' load all connectors '''
|
||||
remote_id = 'https://example.com/object/1'
|
||||
""" load all connectors """
|
||||
remote_id = "https://example.com/object/1"
|
||||
connector_manager.get_or_create_connector(remote_id)
|
||||
connectors = list(connector_manager.get_connectors())
|
||||
self.assertEqual(len(connectors), 2)
|
||||
@@ -56,28 +51,28 @@ class ConnectorManager(TestCase):
|
||||
self.assertIsInstance(connectors[1], BookWyrmConnector)
|
||||
|
||||
def test_search(self):
|
||||
''' search all connectors '''
|
||||
results = connector_manager.search('Example')
|
||||
""" search all connectors """
|
||||
results = connector_manager.search("Example")
|
||||
self.assertEqual(len(results), 1)
|
||||
self.assertIsInstance(results[0]['connector'], SelfConnector)
|
||||
self.assertEqual(len(results[0]['results']), 1)
|
||||
self.assertEqual(results[0]['results'][0].title, 'Example Edition')
|
||||
self.assertIsInstance(results[0]["connector"], SelfConnector)
|
||||
self.assertEqual(len(results[0]["results"]), 1)
|
||||
self.assertEqual(results[0]["results"][0].title, "Example Edition")
|
||||
|
||||
def test_local_search(self):
|
||||
''' search only the local database '''
|
||||
results = connector_manager.local_search('Example')
|
||||
""" search only the local database """
|
||||
results = connector_manager.local_search("Example")
|
||||
self.assertEqual(len(results), 1)
|
||||
self.assertEqual(results[0].title, 'Example Edition')
|
||||
self.assertEqual(results[0].title, "Example Edition")
|
||||
|
||||
def test_first_search_result(self):
|
||||
''' only get one search result '''
|
||||
result = connector_manager.first_search_result('Example')
|
||||
self.assertEqual(result.title, 'Example Edition')
|
||||
no_result = connector_manager.first_search_result('dkjfhg')
|
||||
""" only get one search result """
|
||||
result = connector_manager.first_search_result("Example")
|
||||
self.assertEqual(result.title, "Example Edition")
|
||||
no_result = connector_manager.first_search_result("dkjfhg")
|
||||
self.assertIsNone(no_result)
|
||||
|
||||
def test_load_connector(self):
|
||||
''' load a connector object from the database entry '''
|
||||
""" load a connector object from the database entry """
|
||||
connector = connector_manager.load_connector(self.connector)
|
||||
self.assertIsInstance(connector, SelfConnector)
|
||||
self.assertEqual(connector.identifier, 'test_connector')
|
||||
self.assertEqual(connector.identifier, "test_connector")
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
''' testing book data connectors '''
|
||||
""" testing book data connectors """
|
||||
import json
|
||||
import pathlib
|
||||
from unittest.mock import patch
|
||||
@@ -9,253 +9,231 @@ import responses
|
||||
from bookwyrm import models
|
||||
from bookwyrm.connectors.openlibrary import Connector
|
||||
from bookwyrm.connectors.openlibrary import get_languages, get_description
|
||||
from bookwyrm.connectors.openlibrary import pick_default_edition, \
|
||||
get_openlibrary_key
|
||||
from bookwyrm.connectors.openlibrary import pick_default_edition, get_openlibrary_key
|
||||
from bookwyrm.connectors.abstract_connector import SearchResult
|
||||
from bookwyrm.connectors.connector_manager import ConnectorException
|
||||
|
||||
|
||||
class Openlibrary(TestCase):
|
||||
''' test loading data from openlibrary.org '''
|
||||
def setUp(self):
|
||||
''' creates the connector we'll use '''
|
||||
models.Connector.objects.create(
|
||||
identifier='openlibrary.org',
|
||||
name='OpenLibrary',
|
||||
connector_file='openlibrary',
|
||||
base_url='https://openlibrary.org',
|
||||
books_url='https://openlibrary.org',
|
||||
covers_url='https://covers.openlibrary.org',
|
||||
search_url='https://openlibrary.org/search?q=',
|
||||
isbn_search_url='https://openlibrary.org/isbn',
|
||||
)
|
||||
self.connector = Connector('openlibrary.org')
|
||||
""" test loading data from openlibrary.org """
|
||||
|
||||
work_file = pathlib.Path(__file__).parent.joinpath(
|
||||
'../data/ol_work.json')
|
||||
edition_file = pathlib.Path(__file__).parent.joinpath(
|
||||
'../data/ol_edition.json')
|
||||
def setUp(self):
|
||||
""" creates the connector we'll use """
|
||||
models.Connector.objects.create(
|
||||
identifier="openlibrary.org",
|
||||
name="OpenLibrary",
|
||||
connector_file="openlibrary",
|
||||
base_url="https://openlibrary.org",
|
||||
books_url="https://openlibrary.org",
|
||||
covers_url="https://covers.openlibrary.org",
|
||||
search_url="https://openlibrary.org/search?q=",
|
||||
isbn_search_url="https://openlibrary.org/isbn",
|
||||
)
|
||||
self.connector = Connector("openlibrary.org")
|
||||
|
||||
work_file = pathlib.Path(__file__).parent.joinpath("../data/ol_work.json")
|
||||
edition_file = pathlib.Path(__file__).parent.joinpath("../data/ol_edition.json")
|
||||
edition_list_file = pathlib.Path(__file__).parent.joinpath(
|
||||
'../data/ol_edition_list.json')
|
||||
"../data/ol_edition_list.json"
|
||||
)
|
||||
self.work_data = json.loads(work_file.read_bytes())
|
||||
self.edition_data = json.loads(edition_file.read_bytes())
|
||||
self.edition_list_data = json.loads(edition_list_file.read_bytes())
|
||||
|
||||
|
||||
def test_get_remote_id_from_data(self):
|
||||
''' format the remote id from the data '''
|
||||
data = {'key': '/work/OL1234W'}
|
||||
""" format the remote id from the data """
|
||||
data = {"key": "/work/OL1234W"}
|
||||
result = self.connector.get_remote_id_from_data(data)
|
||||
self.assertEqual(result, 'https://openlibrary.org/work/OL1234W')
|
||||
self.assertEqual(result, "https://openlibrary.org/work/OL1234W")
|
||||
# error handlding
|
||||
with self.assertRaises(ConnectorException):
|
||||
self.connector.get_remote_id_from_data({})
|
||||
|
||||
|
||||
def test_is_work_data(self):
|
||||
''' detect if the loaded json is a work '''
|
||||
""" detect if the loaded json is a work """
|
||||
self.assertEqual(self.connector.is_work_data(self.work_data), True)
|
||||
self.assertEqual(self.connector.is_work_data(self.edition_data), False)
|
||||
|
||||
|
||||
@responses.activate
|
||||
def test_get_edition_from_work_data(self):
|
||||
''' loads a list of editions '''
|
||||
data = {'key': '/work/OL1234W'}
|
||||
""" loads a list of editions """
|
||||
data = {"key": "/work/OL1234W"}
|
||||
responses.add(
|
||||
responses.GET,
|
||||
'https://openlibrary.org/work/OL1234W/editions',
|
||||
json={'entries': []},
|
||||
status=200)
|
||||
with patch('bookwyrm.connectors.openlibrary.pick_default_edition') \
|
||||
as pick_edition:
|
||||
pick_edition.return_value = 'hi'
|
||||
"https://openlibrary.org/work/OL1234W/editions",
|
||||
json={"entries": []},
|
||||
status=200,
|
||||
)
|
||||
with patch(
|
||||
"bookwyrm.connectors.openlibrary.pick_default_edition"
|
||||
) as pick_edition:
|
||||
pick_edition.return_value = "hi"
|
||||
result = self.connector.get_edition_from_work_data(data)
|
||||
self.assertEqual(result, 'hi')
|
||||
|
||||
self.assertEqual(result, "hi")
|
||||
|
||||
@responses.activate
|
||||
def test_get_work_from_edition_data(self):
|
||||
''' loads a list of editions '''
|
||||
data = {'works': [{'key': '/work/OL1234W'}]}
|
||||
""" loads a list of editions """
|
||||
data = {"works": [{"key": "/work/OL1234W"}]}
|
||||
responses.add(
|
||||
responses.GET,
|
||||
'https://openlibrary.org/work/OL1234W',
|
||||
json={'hi': 'there'},
|
||||
status=200)
|
||||
"https://openlibrary.org/work/OL1234W",
|
||||
json={"hi": "there"},
|
||||
status=200,
|
||||
)
|
||||
result = self.connector.get_work_from_edition_data(data)
|
||||
self.assertEqual(result, {'hi': 'there'})
|
||||
|
||||
self.assertEqual(result, {"hi": "there"})
|
||||
|
||||
@responses.activate
|
||||
def test_get_authors_from_data(self):
|
||||
''' find authors in data '''
|
||||
""" find authors in data """
|
||||
responses.add(
|
||||
responses.GET,
|
||||
'https://openlibrary.org/authors/OL382982A',
|
||||
"https://openlibrary.org/authors/OL382982A",
|
||||
json={
|
||||
"name": "George Elliott",
|
||||
"personal_name": "George Elliott",
|
||||
"last_modified": {
|
||||
"type": "/type/datetime",
|
||||
"value": "2008-08-31 10:09:33.413686"
|
||||
},
|
||||
"value": "2008-08-31 10:09:33.413686",
|
||||
},
|
||||
"key": "/authors/OL453734A",
|
||||
"type": {
|
||||
"key": "/type/author"
|
||||
},
|
||||
"type": {"key": "/type/author"},
|
||||
"id": 1259965,
|
||||
"revision": 2
|
||||
"revision": 2,
|
||||
},
|
||||
status=200)
|
||||
status=200,
|
||||
)
|
||||
results = self.connector.get_authors_from_data(self.work_data)
|
||||
result = list(results)[0]
|
||||
self.assertIsInstance(result, models.Author)
|
||||
self.assertEqual(result.name, 'George Elliott')
|
||||
self.assertEqual(result.openlibrary_key, 'OL453734A')
|
||||
|
||||
self.assertEqual(result.name, "George Elliott")
|
||||
self.assertEqual(result.openlibrary_key, "OL453734A")
|
||||
|
||||
def test_get_cover_url(self):
|
||||
''' formats a url that should contain the cover image '''
|
||||
blob = ['image']
|
||||
""" formats a url that should contain the cover image """
|
||||
blob = ["image"]
|
||||
result = self.connector.get_cover_url(blob)
|
||||
self.assertEqual(
|
||||
result, 'https://covers.openlibrary.org/b/id/image-L.jpg')
|
||||
self.assertEqual(result, "https://covers.openlibrary.org/b/id/image-L.jpg")
|
||||
|
||||
def test_parse_search_result(self):
|
||||
''' extract the results from the search json response '''
|
||||
datafile = pathlib.Path(__file__).parent.joinpath(
|
||||
'../data/ol_search.json')
|
||||
""" extract the results from the search json response """
|
||||
datafile = pathlib.Path(__file__).parent.joinpath("../data/ol_search.json")
|
||||
search_data = json.loads(datafile.read_bytes())
|
||||
result = self.connector.parse_search_data(search_data)
|
||||
self.assertIsInstance(result, list)
|
||||
self.assertEqual(len(result), 2)
|
||||
|
||||
|
||||
def test_format_search_result(self):
|
||||
''' translate json from openlibrary into SearchResult '''
|
||||
datafile = pathlib.Path(__file__).parent.joinpath(
|
||||
'../data/ol_search.json')
|
||||
""" translate json from openlibrary into SearchResult """
|
||||
datafile = pathlib.Path(__file__).parent.joinpath("../data/ol_search.json")
|
||||
search_data = json.loads(datafile.read_bytes())
|
||||
results = self.connector.parse_search_data(search_data)
|
||||
self.assertIsInstance(results, list)
|
||||
|
||||
result = self.connector.format_search_result(results[0])
|
||||
self.assertIsInstance(result, SearchResult)
|
||||
self.assertEqual(result.title, 'This Is How You Lose the Time War')
|
||||
self.assertEqual(
|
||||
result.key, 'https://openlibrary.org/works/OL20639540W')
|
||||
self.assertEqual(result.author, 'Amal El-Mohtar, Max Gladstone')
|
||||
self.assertEqual(result.title, "This Is How You Lose the Time War")
|
||||
self.assertEqual(result.key, "https://openlibrary.org/works/OL20639540W")
|
||||
self.assertEqual(result.author, "Amal El-Mohtar, Max Gladstone")
|
||||
self.assertEqual(result.year, 2019)
|
||||
self.assertEqual(result.connector, self.connector)
|
||||
|
||||
|
||||
def test_parse_isbn_search_result(self):
|
||||
''' extract the results from the search json response '''
|
||||
datafile = pathlib.Path(__file__).parent.joinpath(
|
||||
'../data/ol_isbn_search.json')
|
||||
""" extract the results from the search json response """
|
||||
datafile = pathlib.Path(__file__).parent.joinpath("../data/ol_isbn_search.json")
|
||||
search_data = json.loads(datafile.read_bytes())
|
||||
result = self.connector.parse_isbn_search_data(search_data)
|
||||
self.assertIsInstance(result, list)
|
||||
self.assertEqual(len(result), 1)
|
||||
|
||||
|
||||
def test_format_isbn_search_result(self):
|
||||
''' translate json from openlibrary into SearchResult '''
|
||||
datafile = pathlib.Path(__file__).parent.joinpath(
|
||||
'../data/ol_isbn_search.json')
|
||||
""" translate json from openlibrary into SearchResult """
|
||||
datafile = pathlib.Path(__file__).parent.joinpath("../data/ol_isbn_search.json")
|
||||
search_data = json.loads(datafile.read_bytes())
|
||||
results = self.connector.parse_isbn_search_data(search_data)
|
||||
self.assertIsInstance(results, list)
|
||||
|
||||
result = self.connector.format_isbn_search_result(results[0])
|
||||
self.assertIsInstance(result, SearchResult)
|
||||
self.assertEqual(result.title, 'Les ombres errantes')
|
||||
self.assertEqual(
|
||||
result.key, 'https://openlibrary.org/books/OL16262504M')
|
||||
self.assertEqual(result.author, 'Pascal Quignard')
|
||||
self.assertEqual(result.year, '2002')
|
||||
self.assertEqual(result.title, "Les ombres errantes")
|
||||
self.assertEqual(result.key, "https://openlibrary.org/books/OL16262504M")
|
||||
self.assertEqual(result.author, "Pascal Quignard")
|
||||
self.assertEqual(result.year, "2002")
|
||||
self.assertEqual(result.connector, self.connector)
|
||||
|
||||
|
||||
@responses.activate
|
||||
def test_load_edition_data(self):
|
||||
''' format url from key and make request '''
|
||||
key = 'OL1234W'
|
||||
""" format url from key and make request """
|
||||
key = "OL1234W"
|
||||
responses.add(
|
||||
responses.GET,
|
||||
'https://openlibrary.org/works/OL1234W/editions',
|
||||
json={'hi': 'there'}
|
||||
"https://openlibrary.org/works/OL1234W/editions",
|
||||
json={"hi": "there"},
|
||||
)
|
||||
result = self.connector.load_edition_data(key)
|
||||
self.assertEqual(result, {'hi': 'there'})
|
||||
|
||||
self.assertEqual(result, {"hi": "there"})
|
||||
|
||||
@responses.activate
|
||||
def test_expand_book_data(self):
|
||||
''' given a book, get more editions '''
|
||||
work = models.Work.objects.create(
|
||||
title='Test Work', openlibrary_key='OL1234W')
|
||||
edition = models.Edition.objects.create(
|
||||
title='Test Edition', parent_work=work)
|
||||
""" given a book, get more editions """
|
||||
work = models.Work.objects.create(title="Test Work", openlibrary_key="OL1234W")
|
||||
edition = models.Edition.objects.create(title="Test Edition", parent_work=work)
|
||||
|
||||
responses.add(
|
||||
responses.GET,
|
||||
'https://openlibrary.org/works/OL1234W/editions',
|
||||
json={'entries': []},
|
||||
"https://openlibrary.org/works/OL1234W/editions",
|
||||
json={"entries": []},
|
||||
)
|
||||
with patch(
|
||||
'bookwyrm.connectors.abstract_connector.AbstractConnector.' \
|
||||
'create_edition_from_data'):
|
||||
"bookwyrm.connectors.abstract_connector.AbstractConnector."
|
||||
"create_edition_from_data"
|
||||
):
|
||||
self.connector.expand_book_data(edition)
|
||||
self.connector.expand_book_data(work)
|
||||
|
||||
|
||||
def test_get_description(self):
|
||||
''' should do some cleanup on the description data '''
|
||||
description = get_description(self.work_data['description'])
|
||||
expected = 'First in the Old Kingdom/Abhorsen series.'
|
||||
""" should do some cleanup on the description data """
|
||||
description = get_description(self.work_data["description"])
|
||||
expected = "First in the Old Kingdom/Abhorsen series."
|
||||
self.assertEqual(description, expected)
|
||||
|
||||
|
||||
def test_get_openlibrary_key(self):
|
||||
''' extracts the uuid '''
|
||||
key = get_openlibrary_key('/books/OL27320736M')
|
||||
self.assertEqual(key, 'OL27320736M')
|
||||
|
||||
""" extracts the uuid """
|
||||
key = get_openlibrary_key("/books/OL27320736M")
|
||||
self.assertEqual(key, "OL27320736M")
|
||||
|
||||
def test_get_languages(self):
|
||||
''' looks up languages from a list '''
|
||||
languages = get_languages(self.edition_data['languages'])
|
||||
self.assertEqual(languages, ['English'])
|
||||
|
||||
""" looks up languages from a list """
|
||||
languages = get_languages(self.edition_data["languages"])
|
||||
self.assertEqual(languages, ["English"])
|
||||
|
||||
def test_pick_default_edition(self):
|
||||
''' detect if the loaded json is an edition '''
|
||||
edition = pick_default_edition(self.edition_list_data['entries'])
|
||||
self.assertEqual(edition['key'], '/books/OL9788823M')
|
||||
|
||||
""" detect if the loaded json is an edition """
|
||||
edition = pick_default_edition(self.edition_list_data["entries"])
|
||||
self.assertEqual(edition["key"], "/books/OL9788823M")
|
||||
|
||||
@responses.activate
|
||||
def test_create_edition_from_data(self):
|
||||
''' okay but can it actually create an edition with proper metadata '''
|
||||
work = models.Work.objects.create(title='Hello')
|
||||
""" okay but can it actually create an edition with proper metadata """
|
||||
work = models.Work.objects.create(title="Hello")
|
||||
responses.add(
|
||||
responses.GET,
|
||||
'https://openlibrary.org/authors/OL382982A',
|
||||
json={'hi': 'there'},
|
||||
status=200)
|
||||
with patch('bookwyrm.connectors.openlibrary.Connector.' \
|
||||
'get_authors_from_data') as mock:
|
||||
"https://openlibrary.org/authors/OL382982A",
|
||||
json={"hi": "there"},
|
||||
status=200,
|
||||
)
|
||||
with patch(
|
||||
"bookwyrm.connectors.openlibrary.Connector." "get_authors_from_data"
|
||||
) as mock:
|
||||
mock.return_value = []
|
||||
result = self.connector.create_edition_from_data(
|
||||
work, self.edition_data)
|
||||
result = self.connector.create_edition_from_data(work, self.edition_data)
|
||||
self.assertEqual(result.parent_work, work)
|
||||
self.assertEqual(result.title, 'Sabriel')
|
||||
self.assertEqual(result.isbn_10, '0060273224')
|
||||
self.assertEqual(result.title, "Sabriel")
|
||||
self.assertEqual(result.isbn_10, "0060273224")
|
||||
self.assertIsNotNone(result.description)
|
||||
self.assertEqual(result.languages[0], 'English')
|
||||
self.assertEqual(result.publishers[0], 'Harper Trophy')
|
||||
self.assertEqual(result.languages[0], "English")
|
||||
self.assertEqual(result.publishers[0], "Harper Trophy")
|
||||
self.assertEqual(result.pages, 491)
|
||||
self.assertEqual(result.subjects[0], 'Fantasy.')
|
||||
self.assertEqual(result.physical_format, 'Hardcover')
|
||||
self.assertEqual(result.subjects[0], "Fantasy.")
|
||||
self.assertEqual(result.physical_format, "Hardcover")
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
''' testing book data connectors '''
|
||||
""" testing book data connectors """
|
||||
import datetime
|
||||
from django.test import TestCase
|
||||
from django.utils import timezone
|
||||
@@ -9,100 +9,98 @@ from bookwyrm.settings import DOMAIN
|
||||
|
||||
|
||||
class SelfConnector(TestCase):
|
||||
''' just uses local data '''
|
||||
""" just uses local data """
|
||||
|
||||
def setUp(self):
|
||||
''' creating the connector '''
|
||||
""" creating the connector """
|
||||
models.Connector.objects.create(
|
||||
identifier=DOMAIN,
|
||||
name='Local',
|
||||
name="Local",
|
||||
local=True,
|
||||
connector_file='self_connector',
|
||||
base_url='https://%s' % DOMAIN,
|
||||
books_url='https://%s/book' % DOMAIN,
|
||||
covers_url='https://%s/images/covers' % DOMAIN,
|
||||
search_url='https://%s/search?q=' % DOMAIN,
|
||||
connector_file="self_connector",
|
||||
base_url="https://%s" % DOMAIN,
|
||||
books_url="https://%s/book" % DOMAIN,
|
||||
covers_url="https://%s/images/covers" % DOMAIN,
|
||||
search_url="https://%s/search?q=" % DOMAIN,
|
||||
priority=1,
|
||||
)
|
||||
self.connector = Connector(DOMAIN)
|
||||
|
||||
|
||||
def test_format_search_result(self):
|
||||
''' create a SearchResult '''
|
||||
author = models.Author.objects.create(name='Anonymous')
|
||||
""" create a SearchResult """
|
||||
author = models.Author.objects.create(name="Anonymous")
|
||||
edition = models.Edition.objects.create(
|
||||
title='Edition of Example Work',
|
||||
title="Edition of Example Work",
|
||||
published_date=datetime.datetime(1980, 5, 10, tzinfo=timezone.utc),
|
||||
)
|
||||
edition.authors.add(author)
|
||||
result = self.connector.search('Edition of Example')[0]
|
||||
self.assertEqual(result.title, 'Edition of Example Work')
|
||||
result = self.connector.search("Edition of Example")[0]
|
||||
self.assertEqual(result.title, "Edition of Example Work")
|
||||
self.assertEqual(result.key, edition.remote_id)
|
||||
self.assertEqual(result.author, 'Anonymous')
|
||||
self.assertEqual(result.author, "Anonymous")
|
||||
self.assertEqual(result.year, 1980)
|
||||
self.assertEqual(result.connector, self.connector)
|
||||
|
||||
|
||||
def test_search_rank(self):
|
||||
''' prioritize certain results '''
|
||||
author = models.Author.objects.create(name='Anonymous')
|
||||
""" prioritize certain results """
|
||||
author = models.Author.objects.create(name="Anonymous")
|
||||
edition = models.Edition.objects.create(
|
||||
title='Edition of Example Work',
|
||||
title="Edition of Example Work",
|
||||
published_date=datetime.datetime(1980, 5, 10, tzinfo=timezone.utc),
|
||||
parent_work=models.Work.objects.create(title='')
|
||||
parent_work=models.Work.objects.create(title=""),
|
||||
)
|
||||
# author text is rank C
|
||||
edition.authors.add(author)
|
||||
|
||||
# series is rank D
|
||||
models.Edition.objects.create(
|
||||
title='Another Edition',
|
||||
series='Anonymous',
|
||||
parent_work=models.Work.objects.create(title='')
|
||||
title="Another Edition",
|
||||
series="Anonymous",
|
||||
parent_work=models.Work.objects.create(title=""),
|
||||
)
|
||||
# subtitle is rank B
|
||||
models.Edition.objects.create(
|
||||
title='More Editions',
|
||||
subtitle='The Anonymous Edition',
|
||||
parent_work=models.Work.objects.create(title='')
|
||||
title="More Editions",
|
||||
subtitle="The Anonymous Edition",
|
||||
parent_work=models.Work.objects.create(title=""),
|
||||
)
|
||||
# title is rank A
|
||||
models.Edition.objects.create(title='Anonymous')
|
||||
models.Edition.objects.create(title="Anonymous")
|
||||
# doesn't rank in this search
|
||||
edition = models.Edition.objects.create(
|
||||
title='An Edition',
|
||||
parent_work=models.Work.objects.create(title='')
|
||||
title="An Edition", parent_work=models.Work.objects.create(title="")
|
||||
)
|
||||
|
||||
results = self.connector.search('Anonymous')
|
||||
results = self.connector.search("Anonymous")
|
||||
self.assertEqual(len(results), 3)
|
||||
self.assertEqual(results[0].title, 'Anonymous')
|
||||
self.assertEqual(results[1].title, 'More Editions')
|
||||
self.assertEqual(results[2].title, 'Edition of Example Work')
|
||||
|
||||
self.assertEqual(results[0].title, "Anonymous")
|
||||
self.assertEqual(results[1].title, "More Editions")
|
||||
self.assertEqual(results[2].title, "Edition of Example Work")
|
||||
|
||||
def test_search_multiple_editions(self):
|
||||
''' it should get rid of duplicate editions for the same work '''
|
||||
work = models.Work.objects.create(title='Work Title')
|
||||
""" it should get rid of duplicate editions for the same work """
|
||||
work = models.Work.objects.create(title="Work Title")
|
||||
edition_1 = models.Edition.objects.create(
|
||||
title='Edition 1 Title', parent_work=work)
|
||||
title="Edition 1 Title", parent_work=work
|
||||
)
|
||||
edition_2 = models.Edition.objects.create(
|
||||
title='Edition 2 Title', parent_work=work)
|
||||
edition_3 = models.Edition.objects.create(
|
||||
title='Fish', parent_work=work)
|
||||
title="Edition 2 Title", parent_work=work
|
||||
)
|
||||
edition_3 = models.Edition.objects.create(title="Fish", parent_work=work)
|
||||
work.default_edition = edition_2
|
||||
work.save()
|
||||
|
||||
# pick the best edition
|
||||
results = self.connector.search('Edition 1 Title')
|
||||
results = self.connector.search("Edition 1 Title")
|
||||
self.assertEqual(len(results), 1)
|
||||
self.assertEqual(results[0].key, edition_1.remote_id)
|
||||
|
||||
# pick the default edition when no match is best
|
||||
results = self.connector.search('Edition Title')
|
||||
results = self.connector.search("Edition Title")
|
||||
self.assertEqual(len(results), 1)
|
||||
self.assertEqual(results[0].key, edition_2.remote_id)
|
||||
|
||||
# only matches one edition, so no deduplication takes place
|
||||
results = self.connector.search('Fish')
|
||||
results = self.connector.search("Fish")
|
||||
self.assertEqual(len(results), 1)
|
||||
self.assertEqual(results[0].key, edition_3.remote_id)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
''' testing model activitypub utilities '''
|
||||
""" testing model activitypub utilities """
|
||||
from unittest.mock import patch
|
||||
from collections import namedtuple
|
||||
from dataclasses import dataclass
|
||||
@@ -12,238 +12,249 @@ from bookwyrm.models import base_model
|
||||
from bookwyrm.models.activitypub_mixin import ActivitypubMixin
|
||||
from bookwyrm.models.activitypub_mixin import ActivityMixin, ObjectMixin
|
||||
|
||||
|
||||
class ActivitypubMixins(TestCase):
|
||||
''' functionality shared across models '''
|
||||
""" functionality shared across models """
|
||||
|
||||
def setUp(self):
|
||||
''' shared data '''
|
||||
""" shared data """
|
||||
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'
|
||||
"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)
|
||||
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(
|
||||
'rat', 'rat@rat.com', 'ratword',
|
||||
"rat",
|
||||
"rat@rat.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',
|
||||
remote_id="https://example.com/users/rat",
|
||||
inbox="https://example.com/users/rat/inbox",
|
||||
outbox="https://example.com/users/rat/outbox",
|
||||
)
|
||||
|
||||
self.object_mock = {
|
||||
'to': 'to field', 'cc': 'cc field',
|
||||
'content': 'hi', 'id': 'bip', 'type': 'Test',
|
||||
'published': '2020-12-04T17:52:22.623807+00:00',
|
||||
"to": "to field",
|
||||
"cc": "cc field",
|
||||
"content": "hi",
|
||||
"id": "bip",
|
||||
"type": "Test",
|
||||
"published": "2020-12-04T17:52:22.623807+00:00",
|
||||
}
|
||||
|
||||
|
||||
# ActivitypubMixin
|
||||
def test_to_activity(self):
|
||||
''' model to ActivityPub json '''
|
||||
""" model to ActivityPub json """
|
||||
|
||||
@dataclass(init=False)
|
||||
class TestActivity(ActivityObject):
|
||||
''' real simple mock '''
|
||||
type: str = 'Test'
|
||||
""" real simple mock """
|
||||
|
||||
type: str = "Test"
|
||||
|
||||
class TestModel(ActivitypubMixin, base_model.BookWyrmModel):
|
||||
''' real simple mock model because BookWyrmModel is abstract '''
|
||||
""" real simple mock model because BookWyrmModel is abstract """
|
||||
|
||||
instance = TestModel()
|
||||
instance.remote_id = 'https://www.example.com/test'
|
||||
instance.remote_id = "https://www.example.com/test"
|
||||
instance.activity_serializer = TestActivity
|
||||
|
||||
activity = instance.to_activity()
|
||||
self.assertIsInstance(activity, dict)
|
||||
self.assertEqual(activity['id'], 'https://www.example.com/test')
|
||||
self.assertEqual(activity['type'], 'Test')
|
||||
|
||||
self.assertEqual(activity["id"], "https://www.example.com/test")
|
||||
self.assertEqual(activity["type"], "Test")
|
||||
|
||||
def test_find_existing_by_remote_id(self):
|
||||
''' attempt to match a remote id to an object in the db '''
|
||||
""" attempt to match a remote id to an object in the db """
|
||||
# uses a different remote id scheme
|
||||
# this isn't really part of this test directly but it's helpful to state
|
||||
book = models.Edition.objects.create(
|
||||
title='Test Edition', remote_id='http://book.com/book')
|
||||
title="Test Edition", remote_id="http://book.com/book"
|
||||
)
|
||||
|
||||
self.assertEqual(book.origin_id, 'http://book.com/book')
|
||||
self.assertNotEqual(book.remote_id, 'http://book.com/book')
|
||||
self.assertEqual(book.origin_id, "http://book.com/book")
|
||||
self.assertNotEqual(book.remote_id, "http://book.com/book")
|
||||
|
||||
# uses subclasses
|
||||
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
|
||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
|
||||
models.Comment.objects.create(
|
||||
user=self.local_user, content='test status', book=book, \
|
||||
remote_id='https://comment.net')
|
||||
user=self.local_user,
|
||||
content="test status",
|
||||
book=book,
|
||||
remote_id="https://comment.net",
|
||||
)
|
||||
|
||||
result = models.User.find_existing_by_remote_id('hi')
|
||||
result = models.User.find_existing_by_remote_id("hi")
|
||||
self.assertIsNone(result)
|
||||
|
||||
result = models.User.find_existing_by_remote_id(
|
||||
'http://example.com/a/b')
|
||||
result = models.User.find_existing_by_remote_id("http://example.com/a/b")
|
||||
self.assertEqual(result, self.local_user)
|
||||
|
||||
# test using origin id
|
||||
result = models.Edition.find_existing_by_remote_id(
|
||||
'http://book.com/book')
|
||||
result = models.Edition.find_existing_by_remote_id("http://book.com/book")
|
||||
self.assertEqual(result, book)
|
||||
|
||||
# test subclass match
|
||||
result = models.Status.find_existing_by_remote_id(
|
||||
'https://comment.net')
|
||||
|
||||
result = models.Status.find_existing_by_remote_id("https://comment.net")
|
||||
|
||||
def test_find_existing(self):
|
||||
''' match a blob of data to a model '''
|
||||
""" match a blob of data to a model """
|
||||
book = models.Edition.objects.create(
|
||||
title='Test edition',
|
||||
openlibrary_key='OL1234',
|
||||
title="Test edition",
|
||||
openlibrary_key="OL1234",
|
||||
)
|
||||
|
||||
result = models.Edition.find_existing(
|
||||
{'openlibraryKey': 'OL1234'})
|
||||
result = models.Edition.find_existing({"openlibraryKey": "OL1234"})
|
||||
self.assertEqual(result, book)
|
||||
|
||||
|
||||
def test_get_recipients_public_object(self):
|
||||
''' determines the recipients for an object's broadcast '''
|
||||
MockSelf = namedtuple('Self', ('privacy'))
|
||||
mock_self = MockSelf('public')
|
||||
""" determines the recipients for an object's broadcast """
|
||||
MockSelf = namedtuple("Self", ("privacy"))
|
||||
mock_self = MockSelf("public")
|
||||
recipients = ActivitypubMixin.get_recipients(mock_self)
|
||||
self.assertEqual(len(recipients), 1)
|
||||
self.assertEqual(recipients[0], self.remote_user.inbox)
|
||||
|
||||
|
||||
def test_get_recipients_public_user_object_no_followers(self):
|
||||
''' determines the recipients for a user's object broadcast '''
|
||||
MockSelf = namedtuple('Self', ('privacy', 'user'))
|
||||
mock_self = MockSelf('public', self.local_user)
|
||||
""" determines the recipients for a user's object broadcast """
|
||||
MockSelf = namedtuple("Self", ("privacy", "user"))
|
||||
mock_self = MockSelf("public", self.local_user)
|
||||
|
||||
recipients = ActivitypubMixin.get_recipients(mock_self)
|
||||
self.assertEqual(len(recipients), 0)
|
||||
|
||||
|
||||
def test_get_recipients_public_user_object(self):
|
||||
''' determines the recipients for a user's object broadcast '''
|
||||
MockSelf = namedtuple('Self', ('privacy', 'user'))
|
||||
mock_self = MockSelf('public', self.local_user)
|
||||
""" determines the recipients for a user's object broadcast """
|
||||
MockSelf = namedtuple("Self", ("privacy", "user"))
|
||||
mock_self = MockSelf("public", self.local_user)
|
||||
self.local_user.followers.add(self.remote_user)
|
||||
|
||||
recipients = ActivitypubMixin.get_recipients(mock_self)
|
||||
self.assertEqual(len(recipients), 1)
|
||||
self.assertEqual(recipients[0], self.remote_user.inbox)
|
||||
|
||||
|
||||
def test_get_recipients_public_user_object_with_mention(self):
|
||||
''' determines the recipients for a user's object broadcast '''
|
||||
MockSelf = namedtuple('Self', ('privacy', 'user'))
|
||||
mock_self = MockSelf('public', self.local_user)
|
||||
""" determines the recipients for a user's object broadcast """
|
||||
MockSelf = namedtuple("Self", ("privacy", "user"))
|
||||
mock_self = MockSelf("public", self.local_user)
|
||||
self.local_user.followers.add(self.remote_user)
|
||||
with patch('bookwyrm.models.user.set_remote_server.delay'):
|
||||
with patch("bookwyrm.models.user.set_remote_server.delay"):
|
||||
another_remote_user = models.User.objects.create_user(
|
||||
'nutria', 'nutria@nutria.com', 'nutriaword',
|
||||
"nutria",
|
||||
"nutria@nutria.com",
|
||||
"nutriaword",
|
||||
local=False,
|
||||
remote_id='https://example.com/users/nutria',
|
||||
inbox='https://example.com/users/nutria/inbox',
|
||||
outbox='https://example.com/users/nutria/outbox',
|
||||
remote_id="https://example.com/users/nutria",
|
||||
inbox="https://example.com/users/nutria/inbox",
|
||||
outbox="https://example.com/users/nutria/outbox",
|
||||
)
|
||||
MockSelf = namedtuple('Self', ('privacy', 'user', 'recipients'))
|
||||
mock_self = MockSelf('public', self.local_user, [another_remote_user])
|
||||
MockSelf = namedtuple("Self", ("privacy", "user", "recipients"))
|
||||
mock_self = MockSelf("public", self.local_user, [another_remote_user])
|
||||
|
||||
recipients = ActivitypubMixin.get_recipients(mock_self)
|
||||
self.assertEqual(len(recipients), 2)
|
||||
self.assertEqual(recipients[0], another_remote_user.inbox)
|
||||
self.assertEqual(recipients[1], self.remote_user.inbox)
|
||||
|
||||
|
||||
def test_get_recipients_direct(self):
|
||||
''' determines the recipients for a user's object broadcast '''
|
||||
MockSelf = namedtuple('Self', ('privacy', 'user'))
|
||||
mock_self = MockSelf('public', self.local_user)
|
||||
""" determines the recipients for a user's object broadcast """
|
||||
MockSelf = namedtuple("Self", ("privacy", "user"))
|
||||
mock_self = MockSelf("public", self.local_user)
|
||||
self.local_user.followers.add(self.remote_user)
|
||||
with patch('bookwyrm.models.user.set_remote_server.delay'):
|
||||
with patch("bookwyrm.models.user.set_remote_server.delay"):
|
||||
another_remote_user = models.User.objects.create_user(
|
||||
'nutria', 'nutria@nutria.com', 'nutriaword',
|
||||
"nutria",
|
||||
"nutria@nutria.com",
|
||||
"nutriaword",
|
||||
local=False,
|
||||
remote_id='https://example.com/users/nutria',
|
||||
inbox='https://example.com/users/nutria/inbox',
|
||||
outbox='https://example.com/users/nutria/outbox',
|
||||
remote_id="https://example.com/users/nutria",
|
||||
inbox="https://example.com/users/nutria/inbox",
|
||||
outbox="https://example.com/users/nutria/outbox",
|
||||
)
|
||||
MockSelf = namedtuple('Self', ('privacy', 'user', 'recipients'))
|
||||
mock_self = MockSelf('direct', self.local_user, [another_remote_user])
|
||||
MockSelf = namedtuple("Self", ("privacy", "user", "recipients"))
|
||||
mock_self = MockSelf("direct", self.local_user, [another_remote_user])
|
||||
|
||||
recipients = ActivitypubMixin.get_recipients(mock_self)
|
||||
self.assertEqual(len(recipients), 1)
|
||||
self.assertEqual(recipients[0], another_remote_user.inbox)
|
||||
|
||||
|
||||
def test_get_recipients_combine_inboxes(self):
|
||||
''' should combine users with the same shared_inbox '''
|
||||
self.remote_user.shared_inbox = 'http://example.com/inbox'
|
||||
""" should combine users with the same shared_inbox """
|
||||
self.remote_user.shared_inbox = "http://example.com/inbox"
|
||||
self.remote_user.save(broadcast=False)
|
||||
with patch('bookwyrm.models.user.set_remote_server.delay'):
|
||||
with patch("bookwyrm.models.user.set_remote_server.delay"):
|
||||
another_remote_user = models.User.objects.create_user(
|
||||
'nutria', 'nutria@nutria.com', 'nutriaword',
|
||||
"nutria",
|
||||
"nutria@nutria.com",
|
||||
"nutriaword",
|
||||
local=False,
|
||||
remote_id='https://example.com/users/nutria',
|
||||
inbox='https://example.com/users/nutria/inbox',
|
||||
shared_inbox='http://example.com/inbox',
|
||||
outbox='https://example.com/users/nutria/outbox',
|
||||
remote_id="https://example.com/users/nutria",
|
||||
inbox="https://example.com/users/nutria/inbox",
|
||||
shared_inbox="http://example.com/inbox",
|
||||
outbox="https://example.com/users/nutria/outbox",
|
||||
)
|
||||
MockSelf = namedtuple('Self', ('privacy', 'user'))
|
||||
mock_self = MockSelf('public', self.local_user)
|
||||
MockSelf = namedtuple("Self", ("privacy", "user"))
|
||||
mock_self = MockSelf("public", self.local_user)
|
||||
self.local_user.followers.add(self.remote_user)
|
||||
self.local_user.followers.add(another_remote_user)
|
||||
|
||||
recipients = ActivitypubMixin.get_recipients(mock_self)
|
||||
self.assertEqual(len(recipients), 1)
|
||||
self.assertEqual(recipients[0], 'http://example.com/inbox')
|
||||
|
||||
self.assertEqual(recipients[0], "http://example.com/inbox")
|
||||
|
||||
def test_get_recipients_software(self):
|
||||
''' should differentiate between bookwyrm and other remote users '''
|
||||
with patch('bookwyrm.models.user.set_remote_server.delay'):
|
||||
""" should differentiate between bookwyrm and other remote users """
|
||||
with patch("bookwyrm.models.user.set_remote_server.delay"):
|
||||
another_remote_user = models.User.objects.create_user(
|
||||
'nutria', 'nutria@nutria.com', 'nutriaword',
|
||||
"nutria",
|
||||
"nutria@nutria.com",
|
||||
"nutriaword",
|
||||
local=False,
|
||||
remote_id='https://example.com/users/nutria',
|
||||
inbox='https://example.com/users/nutria/inbox',
|
||||
outbox='https://example.com/users/nutria/outbox',
|
||||
remote_id="https://example.com/users/nutria",
|
||||
inbox="https://example.com/users/nutria/inbox",
|
||||
outbox="https://example.com/users/nutria/outbox",
|
||||
bookwyrm_user=False,
|
||||
)
|
||||
MockSelf = namedtuple('Self', ('privacy', 'user'))
|
||||
mock_self = MockSelf('public', self.local_user)
|
||||
MockSelf = namedtuple("Self", ("privacy", "user"))
|
||||
mock_self = MockSelf("public", self.local_user)
|
||||
self.local_user.followers.add(self.remote_user)
|
||||
self.local_user.followers.add(another_remote_user)
|
||||
|
||||
recipients = ActivitypubMixin.get_recipients(mock_self)
|
||||
self.assertEqual(len(recipients), 2)
|
||||
|
||||
recipients = ActivitypubMixin.get_recipients(
|
||||
mock_self, software='bookwyrm')
|
||||
recipients = ActivitypubMixin.get_recipients(mock_self, software="bookwyrm")
|
||||
self.assertEqual(len(recipients), 1)
|
||||
self.assertEqual(recipients[0], self.remote_user.inbox)
|
||||
|
||||
recipients = ActivitypubMixin.get_recipients(
|
||||
mock_self, software='other')
|
||||
recipients = ActivitypubMixin.get_recipients(mock_self, software="other")
|
||||
self.assertEqual(len(recipients), 1)
|
||||
self.assertEqual(recipients[0], another_remote_user.inbox)
|
||||
|
||||
|
||||
# ObjectMixin
|
||||
def test_object_save_create(self):
|
||||
''' should save uneventufully when broadcast is disabled '''
|
||||
""" should save uneventufully when broadcast is disabled """
|
||||
|
||||
class Success(Exception):
|
||||
''' this means we got to the right method '''
|
||||
""" this means we got to the right method """
|
||||
|
||||
class ObjectModel(ObjectMixin, base_model.BookWyrmModel):
|
||||
''' real simple mock model because BookWyrmModel is abstract '''
|
||||
user = models.fields.ForeignKey('User', on_delete=db.models.CASCADE)
|
||||
""" real simple mock model because BookWyrmModel is abstract """
|
||||
|
||||
user = models.fields.ForeignKey("User", on_delete=db.models.CASCADE)
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
with patch('django.db.models.Model.save'):
|
||||
with patch("django.db.models.Model.save"):
|
||||
super().save(*args, **kwargs)
|
||||
def broadcast(self, activity, sender, **kwargs):#pylint: disable=arguments-differ
|
||||
''' do something '''
|
||||
|
||||
def broadcast(
|
||||
self, activity, sender, **kwargs
|
||||
): # pylint: disable=arguments-differ
|
||||
""" do something """
|
||||
raise Success()
|
||||
def to_create_activity(self, user):#pylint: disable=arguments-differ
|
||||
|
||||
def to_create_activity(self, user): # pylint: disable=arguments-differ
|
||||
return {}
|
||||
|
||||
with self.assertRaises(Success):
|
||||
@@ -253,20 +264,24 @@ class ActivitypubMixins(TestCase):
|
||||
ObjectModel(user=self.local_user).save(broadcast=False)
|
||||
ObjectModel(user=None).save()
|
||||
|
||||
|
||||
def test_object_save_update(self):
|
||||
''' should save uneventufully when broadcast is disabled '''
|
||||
""" should save uneventufully when broadcast is disabled """
|
||||
|
||||
class Success(Exception):
|
||||
''' this means we got to the right method '''
|
||||
""" this means we got to the right method """
|
||||
|
||||
class UpdateObjectModel(ObjectMixin, base_model.BookWyrmModel):
|
||||
''' real simple mock model because BookWyrmModel is abstract '''
|
||||
user = models.fields.ForeignKey('User', on_delete=db.models.CASCADE)
|
||||
""" real simple mock model because BookWyrmModel is abstract """
|
||||
|
||||
user = models.fields.ForeignKey("User", on_delete=db.models.CASCADE)
|
||||
last_edited_by = models.fields.ForeignKey(
|
||||
'User', on_delete=db.models.CASCADE)
|
||||
"User", on_delete=db.models.CASCADE
|
||||
)
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
with patch('django.db.models.Model.save'):
|
||||
with patch("django.db.models.Model.save"):
|
||||
super().save(*args, **kwargs)
|
||||
|
||||
def to_update_activity(self, user):
|
||||
raise Success()
|
||||
|
||||
@@ -275,87 +290,71 @@ class ActivitypubMixins(TestCase):
|
||||
with self.assertRaises(Success):
|
||||
UpdateObjectModel(id=1, last_edited_by=self.local_user).save()
|
||||
|
||||
|
||||
def test_object_save_delete(self):
|
||||
''' should create delete activities when objects are deleted by flag '''
|
||||
""" should create delete activities when objects are deleted by flag """
|
||||
|
||||
class ActivitySuccess(Exception):
|
||||
''' this means we got to the right method '''
|
||||
""" this means we got to the right method """
|
||||
|
||||
class DeletableObjectModel(ObjectMixin, base_model.BookWyrmModel):
|
||||
''' real simple mock model because BookWyrmModel is abstract '''
|
||||
user = models.fields.ForeignKey('User', on_delete=db.models.CASCADE)
|
||||
""" real simple mock model because BookWyrmModel is abstract """
|
||||
|
||||
user = models.fields.ForeignKey("User", on_delete=db.models.CASCADE)
|
||||
deleted = models.fields.BooleanField()
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
with patch('django.db.models.Model.save'):
|
||||
with patch("django.db.models.Model.save"):
|
||||
super().save(*args, **kwargs)
|
||||
|
||||
def to_delete_activity(self, user):
|
||||
raise ActivitySuccess()
|
||||
|
||||
with self.assertRaises(ActivitySuccess):
|
||||
DeletableObjectModel(
|
||||
id=1, user=self.local_user, deleted=True).save()
|
||||
|
||||
DeletableObjectModel(id=1, user=self.local_user, deleted=True).save()
|
||||
|
||||
def test_to_delete_activity(self):
|
||||
''' wrapper for Delete activity '''
|
||||
MockSelf = namedtuple('Self', ('remote_id', 'to_activity'))
|
||||
""" wrapper for Delete activity """
|
||||
MockSelf = namedtuple("Self", ("remote_id", "to_activity"))
|
||||
mock_self = MockSelf(
|
||||
'https://example.com/status/1',
|
||||
lambda *args: self.object_mock
|
||||
"https://example.com/status/1", lambda *args: self.object_mock
|
||||
)
|
||||
activity = ObjectMixin.to_delete_activity(
|
||||
mock_self, self.local_user)
|
||||
activity = ObjectMixin.to_delete_activity(mock_self, self.local_user)
|
||||
self.assertEqual(activity["id"], "https://example.com/status/1/activity")
|
||||
self.assertEqual(activity["actor"], self.local_user.remote_id)
|
||||
self.assertEqual(activity["type"], "Delete")
|
||||
self.assertEqual(activity["to"], ["%s/followers" % self.local_user.remote_id])
|
||||
self.assertEqual(
|
||||
activity['id'],
|
||||
'https://example.com/status/1/activity'
|
||||
activity["cc"], ["https://www.w3.org/ns/activitystreams#Public"]
|
||||
)
|
||||
self.assertEqual(activity['actor'], self.local_user.remote_id)
|
||||
self.assertEqual(activity['type'], 'Delete')
|
||||
self.assertEqual(
|
||||
activity['to'],
|
||||
['%s/followers' % self.local_user.remote_id])
|
||||
self.assertEqual(
|
||||
activity['cc'],
|
||||
['https://www.w3.org/ns/activitystreams#Public'])
|
||||
|
||||
|
||||
def test_to_update_activity(self):
|
||||
''' ditto above but for Update '''
|
||||
MockSelf = namedtuple('Self', ('remote_id', 'to_activity'))
|
||||
""" ditto above but for Update """
|
||||
MockSelf = namedtuple("Self", ("remote_id", "to_activity"))
|
||||
mock_self = MockSelf(
|
||||
'https://example.com/status/1',
|
||||
lambda *args: self.object_mock
|
||||
"https://example.com/status/1", lambda *args: self.object_mock
|
||||
)
|
||||
activity = ObjectMixin.to_update_activity(
|
||||
mock_self, self.local_user)
|
||||
activity = ObjectMixin.to_update_activity(mock_self, self.local_user)
|
||||
self.assertIsNotNone(
|
||||
re.match(
|
||||
r'^https:\/\/example\.com\/status\/1#update\/.*',
|
||||
activity['id']
|
||||
)
|
||||
re.match(r"^https:\/\/example\.com\/status\/1#update\/.*", activity["id"])
|
||||
)
|
||||
self.assertEqual(activity['actor'], self.local_user.remote_id)
|
||||
self.assertEqual(activity['type'], 'Update')
|
||||
self.assertEqual(activity["actor"], self.local_user.remote_id)
|
||||
self.assertEqual(activity["type"], "Update")
|
||||
self.assertEqual(
|
||||
activity['to'],
|
||||
['https://www.w3.org/ns/activitystreams#Public'])
|
||||
self.assertIsInstance(activity['object'], dict)
|
||||
|
||||
activity["to"], ["https://www.w3.org/ns/activitystreams#Public"]
|
||||
)
|
||||
self.assertIsInstance(activity["object"], dict)
|
||||
|
||||
# Activity mixin
|
||||
def test_to_undo_activity(self):
|
||||
''' and again, for Undo '''
|
||||
MockSelf = namedtuple('Self', ('remote_id', 'to_activity', 'user'))
|
||||
""" and again, for Undo """
|
||||
MockSelf = namedtuple("Self", ("remote_id", "to_activity", "user"))
|
||||
mock_self = MockSelf(
|
||||
'https://example.com/status/1',
|
||||
"https://example.com/status/1",
|
||||
lambda *args: self.object_mock,
|
||||
self.local_user,
|
||||
)
|
||||
activity = ActivityMixin.to_undo_activity(mock_self)
|
||||
self.assertEqual(
|
||||
activity['id'],
|
||||
'https://example.com/status/1#undo'
|
||||
)
|
||||
self.assertEqual(activity['actor'], self.local_user.remote_id)
|
||||
self.assertEqual(activity['type'], 'Undo')
|
||||
self.assertIsInstance(activity['object'], dict)
|
||||
self.assertEqual(activity["id"], "https://example.com/status/1#undo")
|
||||
self.assertEqual(activity["actor"], self.local_user.remote_id)
|
||||
self.assertEqual(activity["type"], "Undo")
|
||||
self.assertIsInstance(activity["object"], dict)
|
||||
|
||||
@@ -1,42 +1,41 @@
|
||||
''' testing models '''
|
||||
""" testing models """
|
||||
from django.test import TestCase
|
||||
|
||||
from bookwyrm import models
|
||||
from bookwyrm.models import base_model
|
||||
from bookwyrm.settings import DOMAIN
|
||||
|
||||
|
||||
class BaseModel(TestCase):
|
||||
''' functionality shared across models '''
|
||||
""" functionality shared across models """
|
||||
|
||||
def test_remote_id(self):
|
||||
''' these should be generated '''
|
||||
""" these should be generated """
|
||||
instance = base_model.BookWyrmModel()
|
||||
instance.id = 1
|
||||
expected = instance.get_remote_id()
|
||||
self.assertEqual(expected, 'https://%s/bookwyrmmodel/1' % DOMAIN)
|
||||
self.assertEqual(expected, "https://%s/bookwyrmmodel/1" % DOMAIN)
|
||||
|
||||
def test_remote_id_with_user(self):
|
||||
''' format of remote id when there's a user object '''
|
||||
""" format of remote id when there's a user object """
|
||||
user = models.User.objects.create_user(
|
||||
'mouse', 'mouse@mouse.com', 'mouseword',
|
||||
local=True, localname='mouse')
|
||||
"mouse", "mouse@mouse.com", "mouseword", local=True, localname="mouse"
|
||||
)
|
||||
instance = base_model.BookWyrmModel()
|
||||
instance.user = user
|
||||
instance.id = 1
|
||||
expected = instance.get_remote_id()
|
||||
self.assertEqual(
|
||||
expected,
|
||||
'https://%s/user/mouse/bookwyrmmodel/1' % DOMAIN)
|
||||
self.assertEqual(expected, "https://%s/user/mouse/bookwyrmmodel/1" % DOMAIN)
|
||||
|
||||
def test_execute_after_save(self):
|
||||
''' this function sets remote ids after creation '''
|
||||
""" this function sets remote ids after creation """
|
||||
# using Work because it BookWrymModel is abstract and this requires save
|
||||
# Work is a relatively not-fancy model.
|
||||
instance = models.Work.objects.create(title='work title')
|
||||
instance = models.Work.objects.create(title="work title")
|
||||
instance.remote_id = None
|
||||
base_model.execute_after_save(None, instance, True)
|
||||
self.assertEqual(
|
||||
instance.remote_id,
|
||||
'https://%s/book/%d' % (DOMAIN, instance.id)
|
||||
instance.remote_id, "https://%s/book/%d" % (DOMAIN, instance.id)
|
||||
)
|
||||
|
||||
# shouldn't set remote_id if it's not created
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
''' testing models '''
|
||||
""" testing models """
|
||||
from dateutil.parser import parse
|
||||
from django.test import TestCase
|
||||
from django.utils import timezone
|
||||
@@ -8,88 +8,80 @@ from bookwyrm.models.book import isbn_10_to_13, isbn_13_to_10
|
||||
|
||||
|
||||
class Book(TestCase):
|
||||
''' not too much going on in the books model but here we are '''
|
||||
""" not too much going on in the books model but here we are """
|
||||
|
||||
def setUp(self):
|
||||
''' we'll need some books '''
|
||||
""" we'll need some books """
|
||||
self.work = models.Work.objects.create(
|
||||
title='Example Work',
|
||||
remote_id='https://example.com/book/1'
|
||||
title="Example Work", remote_id="https://example.com/book/1"
|
||||
)
|
||||
self.first_edition = models.Edition.objects.create(
|
||||
title='Example Edition',
|
||||
title="Example Edition",
|
||||
parent_work=self.work,
|
||||
)
|
||||
self.second_edition = models.Edition.objects.create(
|
||||
title='Another Example Edition',
|
||||
title="Another Example Edition",
|
||||
parent_work=self.work,
|
||||
)
|
||||
|
||||
def test_remote_id(self):
|
||||
''' fanciness with remote/origin ids '''
|
||||
remote_id = 'https://%s/book/%d' % (settings.DOMAIN, self.work.id)
|
||||
""" fanciness with remote/origin ids """
|
||||
remote_id = "https://%s/book/%d" % (settings.DOMAIN, self.work.id)
|
||||
self.assertEqual(self.work.get_remote_id(), remote_id)
|
||||
self.assertEqual(self.work.remote_id, remote_id)
|
||||
|
||||
def test_create_book(self):
|
||||
''' you shouldn't be able to create Books (only editions and works) '''
|
||||
self.assertRaises(
|
||||
ValueError,
|
||||
models.Book.objects.create,
|
||||
title='Invalid Book'
|
||||
)
|
||||
""" you shouldn't be able to create Books (only editions and works) """
|
||||
self.assertRaises(ValueError, models.Book.objects.create, title="Invalid Book")
|
||||
|
||||
def test_isbn_10_to_13(self):
|
||||
''' checksums and so on '''
|
||||
isbn_10 = '178816167X'
|
||||
""" checksums and so on """
|
||||
isbn_10 = "178816167X"
|
||||
isbn_13 = isbn_10_to_13(isbn_10)
|
||||
self.assertEqual(isbn_13, '9781788161671')
|
||||
self.assertEqual(isbn_13, "9781788161671")
|
||||
|
||||
isbn_10 = '1-788-16167-X'
|
||||
isbn_10 = "1-788-16167-X"
|
||||
isbn_13 = isbn_10_to_13(isbn_10)
|
||||
self.assertEqual(isbn_13, '9781788161671')
|
||||
|
||||
self.assertEqual(isbn_13, "9781788161671")
|
||||
|
||||
def test_isbn_13_to_10(self):
|
||||
''' checksums and so on '''
|
||||
isbn_13 = '9781788161671'
|
||||
""" checksums and so on """
|
||||
isbn_13 = "9781788161671"
|
||||
isbn_10 = isbn_13_to_10(isbn_13)
|
||||
self.assertEqual(isbn_10, '178816167X')
|
||||
self.assertEqual(isbn_10, "178816167X")
|
||||
|
||||
isbn_13 = '978-1788-16167-1'
|
||||
isbn_13 = "978-1788-16167-1"
|
||||
isbn_10 = isbn_13_to_10(isbn_13)
|
||||
self.assertEqual(isbn_10, '178816167X')
|
||||
|
||||
self.assertEqual(isbn_10, "178816167X")
|
||||
|
||||
def test_get_edition_info(self):
|
||||
''' text slug about an edition '''
|
||||
book = models.Edition.objects.create(title='Test Edition')
|
||||
self.assertEqual(book.edition_info, '')
|
||||
""" text slug about an edition """
|
||||
book = models.Edition.objects.create(title="Test Edition")
|
||||
self.assertEqual(book.edition_info, "")
|
||||
|
||||
book.physical_format = 'worm'
|
||||
book.physical_format = "worm"
|
||||
book.save()
|
||||
self.assertEqual(book.edition_info, 'worm')
|
||||
self.assertEqual(book.edition_info, "worm")
|
||||
|
||||
book.languages = ['English']
|
||||
book.languages = ["English"]
|
||||
book.save()
|
||||
self.assertEqual(book.edition_info, 'worm')
|
||||
self.assertEqual(book.edition_info, "worm")
|
||||
|
||||
book.languages = ['Glorbish', 'English']
|
||||
book.languages = ["Glorbish", "English"]
|
||||
book.save()
|
||||
self.assertEqual(book.edition_info, 'worm, Glorbish language')
|
||||
self.assertEqual(book.edition_info, "worm, Glorbish language")
|
||||
|
||||
book.published_date = timezone.make_aware(parse('2020'))
|
||||
book.published_date = timezone.make_aware(parse("2020"))
|
||||
book.save()
|
||||
self.assertEqual(book.edition_info, 'worm, Glorbish language, 2020')
|
||||
self.assertEqual(
|
||||
book.alt_text, 'Test Edition (worm, Glorbish language, 2020)')
|
||||
|
||||
self.assertEqual(book.edition_info, "worm, Glorbish language, 2020")
|
||||
self.assertEqual(book.alt_text, "Test Edition (worm, Glorbish language, 2020)")
|
||||
|
||||
def test_get_rank(self):
|
||||
''' sets the data quality index for the book '''
|
||||
""" sets the data quality index for the book """
|
||||
# basic rank
|
||||
self.assertEqual(self.first_edition.edition_rank, 0)
|
||||
|
||||
self.first_edition.description = 'hi'
|
||||
self.first_edition.description = "hi"
|
||||
self.first_edition.save()
|
||||
self.assertEqual(self.first_edition.edition_rank, 1)
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
''' testing models '''
|
||||
""" testing models """
|
||||
from io import BytesIO
|
||||
from collections import namedtuple
|
||||
from dataclasses import dataclass
|
||||
@@ -23,408 +23,388 @@ from bookwyrm.models import fields, User, Status
|
||||
from bookwyrm.models.base_model import BookWyrmModel
|
||||
from bookwyrm.models.activitypub_mixin import ActivitypubMixin
|
||||
|
||||
#pylint: disable=too-many-public-methods
|
||||
# pylint: disable=too-many-public-methods
|
||||
class ActivitypubFields(TestCase):
|
||||
''' overwrites standard model feilds to work with activitypub '''
|
||||
""" overwrites standard model feilds to work with activitypub """
|
||||
|
||||
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'))
|
||||
self.assertIsNone(fields.validate_remote_id('http://exle.com/dlg-23/x'))
|
||||
""" 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"))
|
||||
self.assertIsNone(fields.validate_remote_id("http://exle.com/dlg-23/x"))
|
||||
self.assertRaises(
|
||||
ValidationError, fields.validate_remote_id,
|
||||
'http:/example.com/dlfjg-23/x')
|
||||
ValidationError, fields.validate_remote_id, "http:/example.com/dlfjg-23/x"
|
||||
)
|
||||
self.assertRaises(
|
||||
ValidationError, fields.validate_remote_id,
|
||||
'www.example.com/dlfjg-23/x')
|
||||
ValidationError, fields.validate_remote_id, "www.example.com/dlfjg-23/x"
|
||||
)
|
||||
self.assertRaises(
|
||||
ValidationError, fields.validate_remote_id,
|
||||
'http://www.example.com/dlfjg 23/x')
|
||||
ValidationError,
|
||||
fields.validate_remote_id,
|
||||
"http://www.example.com/dlfjg 23/x",
|
||||
)
|
||||
|
||||
def test_activitypub_field_mixin(self):
|
||||
''' generic mixin with super basic to and from functionality '''
|
||||
""" generic mixin with super basic to and from functionality """
|
||||
instance = fields.ActivitypubFieldMixin()
|
||||
self.assertEqual(instance.field_to_activity('fish'), 'fish')
|
||||
self.assertEqual(instance.field_from_activity('fish'), 'fish')
|
||||
self.assertEqual(instance.field_to_activity("fish"), "fish")
|
||||
self.assertEqual(instance.field_from_activity("fish"), "fish")
|
||||
self.assertFalse(instance.deduplication_field)
|
||||
|
||||
instance = fields.ActivitypubFieldMixin(
|
||||
activitypub_wrapper='endpoints', activitypub_field='outbox'
|
||||
activitypub_wrapper="endpoints", activitypub_field="outbox"
|
||||
)
|
||||
self.assertEqual(
|
||||
instance.field_to_activity('fish'),
|
||||
{'outbox': 'fish'}
|
||||
)
|
||||
self.assertEqual(
|
||||
instance.field_from_activity({'outbox': 'fish'}),
|
||||
'fish'
|
||||
)
|
||||
self.assertEqual(instance.get_activitypub_field(), 'endpoints')
|
||||
self.assertEqual(instance.field_to_activity("fish"), {"outbox": "fish"})
|
||||
self.assertEqual(instance.field_from_activity({"outbox": "fish"}), "fish")
|
||||
self.assertEqual(instance.get_activitypub_field(), "endpoints")
|
||||
|
||||
instance = fields.ActivitypubFieldMixin()
|
||||
instance.name = 'snake_case_name'
|
||||
self.assertEqual(instance.get_activitypub_field(), 'snakeCaseName')
|
||||
instance.name = "snake_case_name"
|
||||
self.assertEqual(instance.get_activitypub_field(), "snakeCaseName")
|
||||
|
||||
def test_set_field_from_activity(self):
|
||||
''' setter from entire json blob '''
|
||||
""" setter from entire json blob """
|
||||
|
||||
@dataclass
|
||||
class TestModel:
|
||||
''' real simple mock '''
|
||||
""" real simple mock """
|
||||
|
||||
field_name: str
|
||||
|
||||
mock_model = TestModel(field_name='bip')
|
||||
TestActivity = namedtuple('test', ('fieldName', 'unrelated'))
|
||||
data = TestActivity(fieldName='hi', unrelated='bfkjh')
|
||||
mock_model = TestModel(field_name="bip")
|
||||
TestActivity = namedtuple("test", ("fieldName", "unrelated"))
|
||||
data = TestActivity(fieldName="hi", unrelated="bfkjh")
|
||||
|
||||
instance = fields.ActivitypubFieldMixin()
|
||||
instance.name = 'field_name'
|
||||
instance.name = "field_name"
|
||||
|
||||
instance.set_field_from_activity(mock_model, data)
|
||||
self.assertEqual(mock_model.field_name, 'hi')
|
||||
self.assertEqual(mock_model.field_name, "hi")
|
||||
|
||||
def test_set_activity_from_field(self):
|
||||
''' set json field given entire model '''
|
||||
""" set json field given entire model """
|
||||
|
||||
@dataclass
|
||||
class TestModel:
|
||||
''' real simple mock '''
|
||||
""" real simple mock """
|
||||
|
||||
field_name: str
|
||||
unrelated: str
|
||||
mock_model = TestModel(field_name='bip', unrelated='field')
|
||||
|
||||
mock_model = TestModel(field_name="bip", unrelated="field")
|
||||
instance = fields.ActivitypubFieldMixin()
|
||||
instance.name = 'field_name'
|
||||
instance.name = "field_name"
|
||||
|
||||
data = {}
|
||||
instance.set_activity_from_field(data, mock_model)
|
||||
self.assertEqual(data['fieldName'], 'bip')
|
||||
self.assertEqual(data["fieldName"], "bip")
|
||||
|
||||
def test_remote_id_field(self):
|
||||
''' just sets some defaults on charfield '''
|
||||
""" just sets some defaults on charfield """
|
||||
instance = fields.RemoteIdField()
|
||||
self.assertEqual(instance.max_length, 255)
|
||||
self.assertTrue(instance.deduplication_field)
|
||||
|
||||
with self.assertRaises(ValidationError):
|
||||
instance.run_validators('http://www.example.com/dlfjg 23/x')
|
||||
instance.run_validators("http://www.example.com/dlfjg 23/x")
|
||||
|
||||
def test_username_field(self):
|
||||
''' again, just setting defaults on username field '''
|
||||
""" again, just setting defaults on username field """
|
||||
instance = fields.UsernameField()
|
||||
self.assertEqual(instance.activitypub_field, 'preferredUsername')
|
||||
self.assertEqual(instance.activitypub_field, "preferredUsername")
|
||||
self.assertEqual(instance.max_length, 150)
|
||||
self.assertEqual(instance.unique, True)
|
||||
with self.assertRaises(ValidationError):
|
||||
instance.run_validators('mouse')
|
||||
instance.run_validators('mouseexample.com')
|
||||
instance.run_validators('mouse@example.c')
|
||||
instance.run_validators('@example.com')
|
||||
instance.run_validators('mouse@examplecom')
|
||||
instance.run_validators('one two@fish.aaaa')
|
||||
instance.run_validators('a*&@exampke.com')
|
||||
instance.run_validators('trailingwhite@example.com ')
|
||||
self.assertIsNone(instance.run_validators('mouse@example.com'))
|
||||
self.assertIsNone(instance.run_validators('mo-2use@ex3ample.com'))
|
||||
self.assertIsNone(instance.run_validators('aksdhf@sdkjf-df.cm'))
|
||||
|
||||
self.assertEqual(instance.field_to_activity('test@example.com'), 'test')
|
||||
instance.run_validators("mouse")
|
||||
instance.run_validators("mouseexample.com")
|
||||
instance.run_validators("mouse@example.c")
|
||||
instance.run_validators("@example.com")
|
||||
instance.run_validators("mouse@examplecom")
|
||||
instance.run_validators("one two@fish.aaaa")
|
||||
instance.run_validators("a*&@exampke.com")
|
||||
instance.run_validators("trailingwhite@example.com ")
|
||||
self.assertIsNone(instance.run_validators("mouse@example.com"))
|
||||
self.assertIsNone(instance.run_validators("mo-2use@ex3ample.com"))
|
||||
self.assertIsNone(instance.run_validators("aksdhf@sdkjf-df.cm"))
|
||||
|
||||
self.assertEqual(instance.field_to_activity("test@example.com"), "test")
|
||||
|
||||
def test_privacy_field_defaults(self):
|
||||
''' post privacy field's many default values '''
|
||||
""" post privacy field's many default values """
|
||||
instance = fields.PrivacyField()
|
||||
self.assertEqual(instance.max_length, 255)
|
||||
self.assertEqual(
|
||||
[c[0] for c in instance.choices],
|
||||
['public', 'unlisted', 'followers', 'direct'])
|
||||
self.assertEqual(instance.default, 'public')
|
||||
["public", "unlisted", "followers", "direct"],
|
||||
)
|
||||
self.assertEqual(instance.default, "public")
|
||||
self.assertEqual(
|
||||
instance.public, 'https://www.w3.org/ns/activitystreams#Public')
|
||||
instance.public, "https://www.w3.org/ns/activitystreams#Public"
|
||||
)
|
||||
|
||||
def test_privacy_field_set_field_from_activity(self):
|
||||
''' translate between to/cc fields and privacy '''
|
||||
""" translate between to/cc fields and privacy """
|
||||
|
||||
@dataclass(init=False)
|
||||
class TestActivity(ActivityObject):
|
||||
''' real simple mock '''
|
||||
""" real simple mock """
|
||||
|
||||
to: List[str]
|
||||
cc: List[str]
|
||||
id: str = 'http://hi.com'
|
||||
type: str = 'Test'
|
||||
id: str = "http://hi.com"
|
||||
type: str = "Test"
|
||||
|
||||
class TestPrivacyModel(ActivitypubMixin, BookWyrmModel):
|
||||
''' real simple mock model because BookWyrmModel is abstract '''
|
||||
""" real simple mock model because BookWyrmModel is abstract """
|
||||
|
||||
privacy_field = fields.PrivacyField()
|
||||
mention_users = fields.TagField(User)
|
||||
user = fields.ForeignKey(User, on_delete=models.CASCADE)
|
||||
|
||||
public = 'https://www.w3.org/ns/activitystreams#Public'
|
||||
public = "https://www.w3.org/ns/activitystreams#Public"
|
||||
data = TestActivity(
|
||||
to=[public],
|
||||
cc=['bleh'],
|
||||
cc=["bleh"],
|
||||
)
|
||||
model_instance = TestPrivacyModel(privacy_field='direct')
|
||||
self.assertEqual(model_instance.privacy_field, 'direct')
|
||||
model_instance = TestPrivacyModel(privacy_field="direct")
|
||||
self.assertEqual(model_instance.privacy_field, "direct")
|
||||
|
||||
instance = fields.PrivacyField()
|
||||
instance.name = 'privacy_field'
|
||||
instance.name = "privacy_field"
|
||||
instance.set_field_from_activity(model_instance, data)
|
||||
self.assertEqual(model_instance.privacy_field, 'public')
|
||||
self.assertEqual(model_instance.privacy_field, "public")
|
||||
|
||||
data.to = ['bleh']
|
||||
data.to = ["bleh"]
|
||||
data.cc = []
|
||||
instance.set_field_from_activity(model_instance, data)
|
||||
self.assertEqual(model_instance.privacy_field, 'direct')
|
||||
self.assertEqual(model_instance.privacy_field, "direct")
|
||||
|
||||
data.to = ['bleh']
|
||||
data.cc = [public, 'waah']
|
||||
data.to = ["bleh"]
|
||||
data.cc = [public, "waah"]
|
||||
instance.set_field_from_activity(model_instance, data)
|
||||
self.assertEqual(model_instance.privacy_field, 'unlisted')
|
||||
self.assertEqual(model_instance.privacy_field, "unlisted")
|
||||
|
||||
|
||||
@patch('bookwyrm.models.activitypub_mixin.ObjectMixin.broadcast')
|
||||
@patch("bookwyrm.models.activitypub_mixin.ObjectMixin.broadcast")
|
||||
def test_privacy_field_set_activity_from_field(self, _):
|
||||
''' translate between to/cc fields and privacy '''
|
||||
""" translate between to/cc fields and privacy """
|
||||
user = User.objects.create_user(
|
||||
'rat', 'rat@rat.rat', 'ratword',
|
||||
local=True, localname='rat')
|
||||
public = 'https://www.w3.org/ns/activitystreams#Public'
|
||||
followers = '%s/followers' % user.remote_id
|
||||
"rat", "rat@rat.rat", "ratword", local=True, localname="rat"
|
||||
)
|
||||
public = "https://www.w3.org/ns/activitystreams#Public"
|
||||
followers = "%s/followers" % user.remote_id
|
||||
|
||||
instance = fields.PrivacyField()
|
||||
instance.name = 'privacy_field'
|
||||
instance.name = "privacy_field"
|
||||
|
||||
model_instance = Status.objects.create(user=user, content='hi')
|
||||
model_instance = Status.objects.create(user=user, content="hi")
|
||||
activity = {}
|
||||
instance.set_activity_from_field(activity, model_instance)
|
||||
self.assertEqual(activity['to'], [public])
|
||||
self.assertEqual(activity['cc'], [followers])
|
||||
self.assertEqual(activity["to"], [public])
|
||||
self.assertEqual(activity["cc"], [followers])
|
||||
|
||||
model_instance = Status.objects.create(
|
||||
user=user, content='hi', privacy='unlisted')
|
||||
user=user, content="hi", privacy="unlisted"
|
||||
)
|
||||
activity = {}
|
||||
instance.set_activity_from_field(activity, model_instance)
|
||||
self.assertEqual(activity['to'], [followers])
|
||||
self.assertEqual(activity['cc'], [public])
|
||||
self.assertEqual(activity["to"], [followers])
|
||||
self.assertEqual(activity["cc"], [public])
|
||||
|
||||
model_instance = Status.objects.create(
|
||||
user=user, content='hi', privacy='followers')
|
||||
user=user, content="hi", privacy="followers"
|
||||
)
|
||||
activity = {}
|
||||
instance.set_activity_from_field(activity, model_instance)
|
||||
self.assertEqual(activity['to'], [followers])
|
||||
self.assertEqual(activity['cc'], [])
|
||||
self.assertEqual(activity["to"], [followers])
|
||||
self.assertEqual(activity["cc"], [])
|
||||
|
||||
model_instance = Status.objects.create(
|
||||
user=user,
|
||||
content='hi',
|
||||
privacy='direct',
|
||||
content="hi",
|
||||
privacy="direct",
|
||||
)
|
||||
model_instance.mention_users.set([user])
|
||||
activity = {}
|
||||
instance.set_activity_from_field(activity, model_instance)
|
||||
self.assertEqual(activity['to'], [user.remote_id])
|
||||
self.assertEqual(activity['cc'], [])
|
||||
|
||||
self.assertEqual(activity["to"], [user.remote_id])
|
||||
self.assertEqual(activity["cc"], [])
|
||||
|
||||
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'))
|
||||
item = Serializable(lambda: {'a': 'b'}, 'https://e.b/c')
|
||||
""" should be able to format a related model """
|
||||
instance = fields.ForeignKey("User", on_delete=models.CASCADE)
|
||||
Serializable = namedtuple("Serializable", ("to_activity", "remote_id"))
|
||||
item = Serializable(lambda: {"a": "b"}, "https://e.b/c")
|
||||
# returns the remote_id field of the related object
|
||||
self.assertEqual(instance.field_to_activity(item), 'https://e.b/c')
|
||||
|
||||
self.assertEqual(instance.field_to_activity(item), "https://e.b/c")
|
||||
|
||||
@responses.activate
|
||||
def test_foreign_key_from_activity_str(self):
|
||||
''' create a new object from a foreign key '''
|
||||
""" 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')
|
||||
datafile = pathlib.Path(__file__).parent.joinpath("../data/ap_user.json")
|
||||
userdata = json.loads(datafile.read_bytes())
|
||||
# don't try to load the user icon
|
||||
del userdata['icon']
|
||||
del userdata["icon"]
|
||||
|
||||
# it shouldn't match with this unrelated user:
|
||||
unrelated_user = User.objects.create_user(
|
||||
'rat', 'rat@rat.rat', 'ratword',
|
||||
local=True, localname='rat')
|
||||
"rat", "rat@rat.rat", "ratword", local=True, localname="rat"
|
||||
)
|
||||
|
||||
# test receiving an unknown remote id and loading data
|
||||
responses.add(
|
||||
responses.GET,
|
||||
'https://example.com/user/mouse',
|
||||
json=userdata,
|
||||
status=200)
|
||||
with patch('bookwyrm.models.user.set_remote_server.delay'):
|
||||
value = instance.field_from_activity(
|
||||
'https://example.com/user/mouse')
|
||||
responses.GET, "https://example.com/user/mouse", json=userdata, status=200
|
||||
)
|
||||
with patch("bookwyrm.models.user.set_remote_server.delay"):
|
||||
value = instance.field_from_activity("https://example.com/user/mouse")
|
||||
self.assertIsInstance(value, User)
|
||||
self.assertNotEqual(value, unrelated_user)
|
||||
self.assertEqual(value.remote_id, 'https://example.com/user/mouse')
|
||||
self.assertEqual(value.name, 'MOUSE?? MOUSE!!')
|
||||
|
||||
self.assertEqual(value.remote_id, "https://example.com/user/mouse")
|
||||
self.assertEqual(value.name, "MOUSE?? MOUSE!!")
|
||||
|
||||
def test_foreign_key_from_activity_dict(self):
|
||||
''' test recieving activity json '''
|
||||
""" test recieving activity json """
|
||||
instance = fields.ForeignKey(User, on_delete=models.CASCADE)
|
||||
datafile = pathlib.Path(__file__).parent.joinpath(
|
||||
'../data/ap_user.json')
|
||||
datafile = pathlib.Path(__file__).parent.joinpath("../data/ap_user.json")
|
||||
userdata = json.loads(datafile.read_bytes())
|
||||
# don't try to load the user icon
|
||||
del userdata['icon']
|
||||
del userdata["icon"]
|
||||
|
||||
# it shouldn't match with this unrelated user:
|
||||
unrelated_user = User.objects.create_user(
|
||||
'rat', 'rat@rat.rat', 'ratword',
|
||||
local=True, localname='rat')
|
||||
with patch('bookwyrm.models.user.set_remote_server.delay'):
|
||||
"rat", "rat@rat.rat", "ratword", local=True, localname="rat"
|
||||
)
|
||||
with patch("bookwyrm.models.user.set_remote_server.delay"):
|
||||
value = instance.field_from_activity(activitypub.Person(**userdata))
|
||||
self.assertIsInstance(value, User)
|
||||
self.assertNotEqual(value, unrelated_user)
|
||||
self.assertEqual(value.remote_id, 'https://example.com/user/mouse')
|
||||
self.assertEqual(value.name, 'MOUSE?? MOUSE!!')
|
||||
self.assertEqual(value.remote_id, "https://example.com/user/mouse")
|
||||
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):
|
||||
''' test receiving a dict of an existing object in the db '''
|
||||
""" 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'
|
||||
)
|
||||
datafile = pathlib.Path(__file__).parent.joinpath("../data/ap_user.json")
|
||||
userdata = json.loads(datafile.read_bytes())
|
||||
user = User.objects.create_user(
|
||||
'mouse', 'mouse@mouse.mouse', 'mouseword',
|
||||
local=True, localname='mouse')
|
||||
user.remote_id = 'https://example.com/user/mouse'
|
||||
"mouse", "mouse@mouse.mouse", "mouseword", local=True, localname="mouse"
|
||||
)
|
||||
user.remote_id = "https://example.com/user/mouse"
|
||||
user.save(broadcast=False)
|
||||
User.objects.create_user(
|
||||
'rat', 'rat@rat.rat', 'ratword',
|
||||
local=True, localname='rat')
|
||||
"rat", "rat@rat.rat", "ratword", local=True, localname="rat"
|
||||
)
|
||||
|
||||
with patch('bookwyrm.models.activitypub_mixin.ObjectMixin.broadcast'):
|
||||
with patch("bookwyrm.models.activitypub_mixin.ObjectMixin.broadcast"):
|
||||
value = instance.field_from_activity(activitypub.Person(**userdata))
|
||||
self.assertEqual(value, user)
|
||||
|
||||
|
||||
def test_foreign_key_from_activity_str_existing(self):
|
||||
''' test receiving a remote id of an existing object in the db '''
|
||||
""" 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(
|
||||
'mouse', 'mouse@mouse.mouse', 'mouseword',
|
||||
local=True, localname='mouse')
|
||||
"mouse", "mouse@mouse.mouse", "mouseword", local=True, localname="mouse"
|
||||
)
|
||||
User.objects.create_user(
|
||||
'rat', 'rat@rat.rat', 'ratword',
|
||||
local=True, localname='rat')
|
||||
"rat", "rat@rat.rat", "ratword", local=True, localname="rat"
|
||||
)
|
||||
|
||||
value = instance.field_from_activity(user.remote_id)
|
||||
self.assertEqual(value, user)
|
||||
|
||||
|
||||
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'})
|
||||
""" 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):
|
||||
''' lists! '''
|
||||
instance = fields.ManyToManyField('User')
|
||||
""" lists! """
|
||||
instance = fields.ManyToManyField("User")
|
||||
|
||||
Serializable = namedtuple('Serializable', ('to_activity', 'remote_id'))
|
||||
Queryset = namedtuple('Queryset', ('all', 'instance'))
|
||||
item = Serializable(lambda: {'a': 'b'}, 'https://e.b/c')
|
||||
another_item = Serializable(lambda: {}, 'example.com')
|
||||
Serializable = namedtuple("Serializable", ("to_activity", "remote_id"))
|
||||
Queryset = namedtuple("Queryset", ("all", "instance"))
|
||||
item = Serializable(lambda: {"a": "b"}, "https://e.b/c")
|
||||
another_item = Serializable(lambda: {}, "example.com")
|
||||
|
||||
items = Queryset(lambda: [item], another_item)
|
||||
|
||||
self.assertEqual(instance.field_to_activity(items), ['https://e.b/c'])
|
||||
self.assertEqual(instance.field_to_activity(items), ["https://e.b/c"])
|
||||
|
||||
instance = fields.ManyToManyField('User', link_only=True)
|
||||
instance.name = 'snake_case'
|
||||
self.assertEqual(
|
||||
instance.field_to_activity(items),
|
||||
'example.com/snake_case'
|
||||
)
|
||||
instance = fields.ManyToManyField("User", link_only=True)
|
||||
instance.name = "snake_case"
|
||||
self.assertEqual(instance.field_to_activity(items), "example.com/snake_case")
|
||||
|
||||
@responses.activate
|
||||
def test_many_to_many_field_from_activity(self):
|
||||
''' resolve related fields for a list, takes a list of remote ids '''
|
||||
""" 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'
|
||||
)
|
||||
datafile = pathlib.Path(__file__).parent.joinpath("../data/ap_user.json")
|
||||
userdata = json.loads(datafile.read_bytes())
|
||||
# don't try to load the user icon
|
||||
del userdata['icon']
|
||||
del userdata["icon"]
|
||||
|
||||
# test receiving an unknown remote id and loading data
|
||||
responses.add(
|
||||
responses.GET,
|
||||
'https://example.com/user/mouse',
|
||||
json=userdata,
|
||||
status=200)
|
||||
with patch('bookwyrm.models.user.set_remote_server.delay'):
|
||||
responses.GET, "https://example.com/user/mouse", json=userdata, status=200
|
||||
)
|
||||
with patch("bookwyrm.models.user.set_remote_server.delay"):
|
||||
value = instance.field_from_activity(
|
||||
['https://example.com/user/mouse', 'bleh']
|
||||
["https://example.com/user/mouse", "bleh"]
|
||||
)
|
||||
self.assertIsInstance(value, list)
|
||||
self.assertEqual(len(value), 1)
|
||||
self.assertIsInstance(value[0], User)
|
||||
|
||||
def test_tag_field(self):
|
||||
''' a special type of many to many field '''
|
||||
instance = fields.TagField('User')
|
||||
""" a special type of many to many field """
|
||||
instance = fields.TagField("User")
|
||||
|
||||
Serializable = namedtuple(
|
||||
'Serializable',
|
||||
('to_activity', 'remote_id', 'name_field', 'name')
|
||||
"Serializable", ("to_activity", "remote_id", "name_field", "name")
|
||||
)
|
||||
Queryset = namedtuple('Queryset', ('all', 'instance'))
|
||||
item = Serializable(
|
||||
lambda: {'a': 'b'}, 'https://e.b/c', 'name', 'Name')
|
||||
another_item = Serializable(
|
||||
lambda: {}, 'example.com', '', '')
|
||||
Queryset = namedtuple("Queryset", ("all", "instance"))
|
||||
item = Serializable(lambda: {"a": "b"}, "https://e.b/c", "name", "Name")
|
||||
another_item = Serializable(lambda: {}, "example.com", "", "")
|
||||
items = Queryset(lambda: [item], another_item)
|
||||
|
||||
result = instance.field_to_activity(items)
|
||||
self.assertIsInstance(result, list)
|
||||
self.assertEqual(len(result), 1)
|
||||
self.assertEqual(result[0].href, 'https://e.b/c')
|
||||
self.assertEqual(result[0].name, 'Name')
|
||||
self.assertEqual(result[0].type, 'Serializable')
|
||||
|
||||
self.assertEqual(result[0].href, "https://e.b/c")
|
||||
self.assertEqual(result[0].name, "Name")
|
||||
self.assertEqual(result[0].type, "Serializable")
|
||||
|
||||
def test_tag_field_from_activity(self):
|
||||
''' loadin' a list of items from Links '''
|
||||
""" loadin' a list of items from Links """
|
||||
# TODO
|
||||
|
||||
|
||||
@responses.activate
|
||||
@patch('bookwyrm.models.activitypub_mixin.ObjectMixin.broadcast')
|
||||
@patch("bookwyrm.models.activitypub_mixin.ObjectMixin.broadcast")
|
||||
def test_image_field(self, _):
|
||||
''' storing images '''
|
||||
""" storing images """
|
||||
user = User.objects.create_user(
|
||||
'mouse', 'mouse@mouse.mouse', 'mouseword',
|
||||
local=True, localname='mouse')
|
||||
"mouse", "mouse@mouse.mouse", "mouseword", local=True, localname="mouse"
|
||||
)
|
||||
image_file = pathlib.Path(__file__).parent.joinpath(
|
||||
'../../static/images/default_avi.jpg')
|
||||
"../../static/images/default_avi.jpg"
|
||||
)
|
||||
image = Image.open(image_file)
|
||||
output = BytesIO()
|
||||
image.save(output, format=image.format)
|
||||
user.avatar.save(
|
||||
'test.jpg',
|
||||
ContentFile(output.getvalue())
|
||||
)
|
||||
user.avatar.save("test.jpg", ContentFile(output.getvalue()))
|
||||
|
||||
output = fields.image_serializer(user.avatar, alt='alt text')
|
||||
output = fields.image_serializer(user.avatar, alt="alt text")
|
||||
self.assertIsNotNone(
|
||||
re.match(
|
||||
r'.*\.jpg',
|
||||
r".*\.jpg",
|
||||
output.url,
|
||||
)
|
||||
)
|
||||
self.assertEqual(output.name, 'alt text')
|
||||
self.assertEqual(output.type, 'Image')
|
||||
self.assertEqual(output.name, "alt text")
|
||||
self.assertEqual(output.type, "Image")
|
||||
|
||||
instance = fields.ImageField()
|
||||
|
||||
@@ -433,36 +413,30 @@ class ActivitypubFields(TestCase):
|
||||
|
||||
responses.add(
|
||||
responses.GET,
|
||||
'http://www.example.com/image.jpg',
|
||||
"http://www.example.com/image.jpg",
|
||||
body=user.avatar.file.read(),
|
||||
status=200)
|
||||
loaded_image = instance.field_from_activity(
|
||||
'http://www.example.com/image.jpg')
|
||||
status=200,
|
||||
)
|
||||
loaded_image = instance.field_from_activity("http://www.example.com/image.jpg")
|
||||
self.assertIsInstance(loaded_image, list)
|
||||
self.assertIsInstance(loaded_image[1], ContentFile)
|
||||
|
||||
|
||||
def test_datetime_field(self):
|
||||
''' this one is pretty simple, it just has to use isoformat '''
|
||||
""" this one is pretty simple, it just has to use isoformat """
|
||||
instance = fields.DateTimeField()
|
||||
now = timezone.now()
|
||||
self.assertEqual(instance.field_to_activity(now), now.isoformat())
|
||||
self.assertEqual(
|
||||
instance.field_from_activity(now.isoformat()), now
|
||||
)
|
||||
self.assertEqual(instance.field_from_activity('bip'), None)
|
||||
|
||||
self.assertEqual(instance.field_from_activity(now.isoformat()), now)
|
||||
self.assertEqual(instance.field_from_activity("bip"), None)
|
||||
|
||||
def test_array_field(self):
|
||||
''' idk why it makes them strings but probably for a good reason '''
|
||||
""" 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'])
|
||||
|
||||
self.assertEqual(instance.field_to_activity([0, 1]), ["0", "1"])
|
||||
|
||||
def test_html_field(self):
|
||||
''' sanitizes html, the sanitizer has its own tests '''
|
||||
""" sanitizes html, the sanitizer has its own tests """
|
||||
instance = fields.HtmlField()
|
||||
self.assertEqual(
|
||||
instance.field_from_activity('<marquee><p>hi</p></marquee>'),
|
||||
'<p>hi</p>'
|
||||
instance.field_from_activity("<marquee><p>hi</p></marquee>"), "<p>hi</p>"
|
||||
)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
''' testing models '''
|
||||
""" testing models """
|
||||
import datetime
|
||||
import json
|
||||
import pathlib
|
||||
@@ -14,165 +14,166 @@ from bookwyrm.connectors.abstract_connector import SearchResult
|
||||
|
||||
|
||||
class ImportJob(TestCase):
|
||||
''' this is a fancy one!!! '''
|
||||
""" this is a fancy one!!! """
|
||||
|
||||
def setUp(self):
|
||||
''' data is from a goodreads export of The Raven Tower '''
|
||||
""" data is from a goodreads export of The Raven Tower """
|
||||
read_data = {
|
||||
'Book Id': 39395857,
|
||||
'Title': 'The Raven Tower',
|
||||
'Author': 'Ann Leckie',
|
||||
'Author l-f': 'Leckie, Ann',
|
||||
'Additional Authors': '',
|
||||
'ISBN': '="0356506991"',
|
||||
'ISBN13': '="9780356506999"',
|
||||
'My Rating': 0,
|
||||
'Average Rating': 4.06,
|
||||
'Publisher': 'Orbit',
|
||||
'Binding': 'Hardcover',
|
||||
'Number of Pages': 416,
|
||||
'Year Published': 2019,
|
||||
'Original Publication Year': 2019,
|
||||
'Date Read': '2019/04/12',
|
||||
'Date Added': '2019/04/09',
|
||||
'Bookshelves': '',
|
||||
'Bookshelves with positions': '',
|
||||
'Exclusive Shelf': 'read',
|
||||
'My Review': '',
|
||||
'Spoiler': '',
|
||||
'Private Notes': '',
|
||||
'Read Count': 1,
|
||||
'Recommended For': '',
|
||||
'Recommended By': '',
|
||||
'Owned Copies': 0,
|
||||
'Original Purchase Date': '',
|
||||
'Original Purchase Location': '',
|
||||
'Condition': '',
|
||||
'Condition Description': '',
|
||||
'BCID': ''
|
||||
"Book Id": 39395857,
|
||||
"Title": "The Raven Tower",
|
||||
"Author": "Ann Leckie",
|
||||
"Author l-f": "Leckie, Ann",
|
||||
"Additional Authors": "",
|
||||
"ISBN": '="0356506991"',
|
||||
"ISBN13": '="9780356506999"',
|
||||
"My Rating": 0,
|
||||
"Average Rating": 4.06,
|
||||
"Publisher": "Orbit",
|
||||
"Binding": "Hardcover",
|
||||
"Number of Pages": 416,
|
||||
"Year Published": 2019,
|
||||
"Original Publication Year": 2019,
|
||||
"Date Read": "2019/04/12",
|
||||
"Date Added": "2019/04/09",
|
||||
"Bookshelves": "",
|
||||
"Bookshelves with positions": "",
|
||||
"Exclusive Shelf": "read",
|
||||
"My Review": "",
|
||||
"Spoiler": "",
|
||||
"Private Notes": "",
|
||||
"Read Count": 1,
|
||||
"Recommended For": "",
|
||||
"Recommended By": "",
|
||||
"Owned Copies": 0,
|
||||
"Original Purchase Date": "",
|
||||
"Original Purchase Location": "",
|
||||
"Condition": "",
|
||||
"Condition Description": "",
|
||||
"BCID": "",
|
||||
}
|
||||
currently_reading_data = read_data.copy()
|
||||
currently_reading_data['Exclusive Shelf'] = 'currently-reading'
|
||||
currently_reading_data['Date Read'] = ''
|
||||
currently_reading_data["Exclusive Shelf"] = "currently-reading"
|
||||
currently_reading_data["Date Read"] = ""
|
||||
|
||||
unknown_read_data = currently_reading_data.copy()
|
||||
unknown_read_data['Exclusive Shelf'] = 'read'
|
||||
unknown_read_data['Date Read'] = ''
|
||||
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')
|
||||
"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)
|
||||
self.item_2 = models.ImportItem.objects.create(
|
||||
job=job, index=2, data=read_data)
|
||||
job=job, index=1, data=currently_reading_data
|
||||
)
|
||||
self.item_2 = models.ImportItem.objects.create(job=job, index=2, data=read_data)
|
||||
self.item_3 = models.ImportItem.objects.create(
|
||||
job=job, index=3, data=unknown_read_data)
|
||||
|
||||
job=job, index=3, data=unknown_read_data
|
||||
)
|
||||
|
||||
def test_isbn(self):
|
||||
''' it unquotes the isbn13 field from data '''
|
||||
expected = '9780356506999'
|
||||
""" it unquotes the isbn13 field from data """
|
||||
expected = "9780356506999"
|
||||
item = models.ImportItem.objects.get(index=1)
|
||||
self.assertEqual(item.isbn, expected)
|
||||
|
||||
|
||||
def test_shelf(self):
|
||||
''' converts to the local shelf typology '''
|
||||
expected = 'reading'
|
||||
""" converts to the local shelf typology """
|
||||
expected = "reading"
|
||||
self.assertEqual(self.item_1.shelf, expected)
|
||||
|
||||
|
||||
def test_date_added(self):
|
||||
''' converts to the local shelf typology '''
|
||||
""" converts to the local shelf typology """
|
||||
expected = datetime.datetime(2019, 4, 9, 0, 0, tzinfo=timezone.utc)
|
||||
item = models.ImportItem.objects.get(index=1)
|
||||
self.assertEqual(item.date_added, expected)
|
||||
|
||||
|
||||
def test_date_read(self):
|
||||
''' converts to the local shelf typology '''
|
||||
""" converts to the local shelf typology """
|
||||
expected = datetime.datetime(2019, 4, 12, 0, 0, tzinfo=timezone.utc)
|
||||
item = models.ImportItem.objects.get(index=2)
|
||||
self.assertEqual(item.date_read, expected)
|
||||
|
||||
|
||||
def test_currently_reading_reads(self):
|
||||
''' infer currently reading dates where available '''
|
||||
expected = [models.ReadThrough(
|
||||
start_date=datetime.datetime(2019, 4, 9, 0, 0, tzinfo=timezone.utc)
|
||||
)]
|
||||
""" infer currently reading dates where available """
|
||||
expected = [
|
||||
models.ReadThrough(
|
||||
start_date=datetime.datetime(2019, 4, 9, 0, 0, tzinfo=timezone.utc)
|
||||
)
|
||||
]
|
||||
actual = models.ImportItem.objects.get(index=1)
|
||||
self.assertEqual(actual.reads[0].start_date, expected[0].start_date)
|
||||
self.assertEqual(actual.reads[0].finish_date, expected[0].finish_date)
|
||||
|
||||
def test_read_reads(self):
|
||||
''' infer read dates where available '''
|
||||
""" infer read dates where available """
|
||||
actual = self.item_2
|
||||
self.assertEqual(
|
||||
actual.reads[0].start_date,
|
||||
datetime.datetime(2019, 4, 9, 0, 0, tzinfo=timezone.utc))
|
||||
datetime.datetime(2019, 4, 9, 0, 0, tzinfo=timezone.utc),
|
||||
)
|
||||
self.assertEqual(
|
||||
actual.reads[0].finish_date,
|
||||
datetime.datetime(2019, 4, 12, 0, 0, tzinfo=timezone.utc))
|
||||
datetime.datetime(2019, 4, 12, 0, 0, tzinfo=timezone.utc),
|
||||
)
|
||||
|
||||
def test_unread_reads(self):
|
||||
''' handle books with no read dates '''
|
||||
""" handle books with no read dates """
|
||||
expected = []
|
||||
actual = models.ImportItem.objects.get(index=3)
|
||||
self.assertEqual(actual.reads, expected)
|
||||
|
||||
|
||||
@responses.activate
|
||||
def test_get_book_from_isbn(self):
|
||||
''' search and load books by isbn (9780356506999) '''
|
||||
""" search and load books by isbn (9780356506999) """
|
||||
connector_info = models.Connector.objects.create(
|
||||
identifier='openlibrary.org',
|
||||
name='OpenLibrary',
|
||||
connector_file='openlibrary',
|
||||
base_url='https://openlibrary.org',
|
||||
books_url='https://openlibrary.org',
|
||||
covers_url='https://covers.openlibrary.org',
|
||||
search_url='https://openlibrary.org/search?q=',
|
||||
identifier="openlibrary.org",
|
||||
name="OpenLibrary",
|
||||
connector_file="openlibrary",
|
||||
base_url="https://openlibrary.org",
|
||||
books_url="https://openlibrary.org",
|
||||
covers_url="https://covers.openlibrary.org",
|
||||
search_url="https://openlibrary.org/search?q=",
|
||||
priority=3,
|
||||
)
|
||||
connector = connector_manager.load_connector(connector_info)
|
||||
result = SearchResult(
|
||||
title='Test Result',
|
||||
key='https://openlibrary.org/works/OL1234W',
|
||||
author='An Author',
|
||||
year='1980',
|
||||
title="Test Result",
|
||||
key="https://openlibrary.org/works/OL1234W",
|
||||
author="An Author",
|
||||
year="1980",
|
||||
connector=connector,
|
||||
)
|
||||
|
||||
|
||||
datafile = pathlib.Path(__file__).parent.joinpath(
|
||||
'../data/ol_edition.json')
|
||||
datafile = pathlib.Path(__file__).parent.joinpath("../data/ol_edition.json")
|
||||
bookdata = json.loads(datafile.read_bytes())
|
||||
responses.add(
|
||||
responses.GET,
|
||||
'https://openlibrary.org/works/OL1234W',
|
||||
"https://openlibrary.org/works/OL1234W",
|
||||
json=bookdata,
|
||||
status=200)
|
||||
status=200,
|
||||
)
|
||||
responses.add(
|
||||
responses.GET,
|
||||
'https://openlibrary.org/works/OL15832982W',
|
||||
"https://openlibrary.org/works/OL15832982W",
|
||||
json=bookdata,
|
||||
status=200)
|
||||
status=200,
|
||||
)
|
||||
responses.add(
|
||||
responses.GET,
|
||||
'https://openlibrary.org/authors/OL382982A',
|
||||
json={'name': 'test author'},
|
||||
status=200)
|
||||
"https://openlibrary.org/authors/OL382982A",
|
||||
json={"name": "test author"},
|
||||
status=200,
|
||||
)
|
||||
|
||||
with patch(
|
||||
'bookwyrm.connectors.abstract_connector.load_more_data.delay'):
|
||||
with patch("bookwyrm.connectors.abstract_connector.load_more_data.delay"):
|
||||
with patch(
|
||||
'bookwyrm.connectors.connector_manager.first_search_result'
|
||||
) as search:
|
||||
"bookwyrm.connectors.connector_manager.first_search_result"
|
||||
) as search:
|
||||
search.return_value = result
|
||||
with patch('bookwyrm.connectors.openlibrary.Connector.' \
|
||||
'get_authors_from_data'):
|
||||
with patch(
|
||||
"bookwyrm.connectors.openlibrary.Connector." "get_authors_from_data"
|
||||
):
|
||||
book = self.item_1.get_book_from_isbn()
|
||||
|
||||
self.assertEqual(book.title, 'Sabriel')
|
||||
self.assertEqual(book.title, "Sabriel")
|
||||
|
||||
@@ -1,43 +1,41 @@
|
||||
''' testing models '''
|
||||
""" 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')
|
||||
@patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay")
|
||||
class List(TestCase):
|
||||
''' some activitypub oddness ahead '''
|
||||
""" some activitypub oddness ahead """
|
||||
|
||||
def setUp(self):
|
||||
''' look, a list '''
|
||||
""" look, a list """
|
||||
self.user = models.User.objects.create_user(
|
||||
'mouse', 'mouse@mouse.mouse', 'mouseword',
|
||||
local=True, localname='mouse')
|
||||
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
|
||||
self.list = models.List.objects.create(
|
||||
name='Test List', user=self.user)
|
||||
"mouse", "mouse@mouse.mouse", "mouseword", local=True, localname="mouse"
|
||||
)
|
||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
|
||||
self.list = models.List.objects.create(name="Test List", user=self.user)
|
||||
|
||||
def test_remote_id(self, _):
|
||||
''' shelves use custom remote ids '''
|
||||
expected_id = 'https://%s/list/%d' % \
|
||||
(settings.DOMAIN, self.list.id)
|
||||
""" shelves use custom remote ids """
|
||||
expected_id = "https://%s/list/%d" % (settings.DOMAIN, self.list.id)
|
||||
self.assertEqual(self.list.get_remote_id(), expected_id)
|
||||
|
||||
|
||||
def test_to_activity(self, _):
|
||||
''' jsonify it '''
|
||||
""" jsonify it """
|
||||
activity_json = self.list.to_activity()
|
||||
self.assertIsInstance(activity_json, dict)
|
||||
self.assertEqual(activity_json['id'], self.list.remote_id)
|
||||
self.assertEqual(activity_json['totalItems'], 0)
|
||||
self.assertEqual(activity_json['type'], 'BookList')
|
||||
self.assertEqual(activity_json['name'], 'Test List')
|
||||
self.assertEqual(activity_json['owner'], self.user.remote_id)
|
||||
self.assertEqual(activity_json["id"], self.list.remote_id)
|
||||
self.assertEqual(activity_json["totalItems"], 0)
|
||||
self.assertEqual(activity_json["type"], "BookList")
|
||||
self.assertEqual(activity_json["name"], "Test List")
|
||||
self.assertEqual(activity_json["owner"], self.user.remote_id)
|
||||
|
||||
def test_list_item(self, _):
|
||||
''' a list entry '''
|
||||
work = models.Work.objects.create(title='hello')
|
||||
book = models.Edition.objects.create(title='hi', parent_work=work)
|
||||
""" a list entry """
|
||||
work = models.Work.objects.create(title="hello")
|
||||
book = models.Edition.objects.create(title="hi", parent_work=work)
|
||||
item = models.ListItem.objects.create(
|
||||
book_list=self.list,
|
||||
book=book,
|
||||
@@ -47,11 +45,11 @@ class List(TestCase):
|
||||
self.assertTrue(item.approved)
|
||||
|
||||
add_activity = item.to_add_activity()
|
||||
self.assertEqual(add_activity['actor'], self.user.remote_id)
|
||||
self.assertEqual(add_activity['object']['id'], book.remote_id)
|
||||
self.assertEqual(add_activity['target'], self.list.remote_id)
|
||||
self.assertEqual(add_activity["actor"], self.user.remote_id)
|
||||
self.assertEqual(add_activity["object"]["id"], book.remote_id)
|
||||
self.assertEqual(add_activity["target"], self.list.remote_id)
|
||||
|
||||
remove_activity = item.to_remove_activity()
|
||||
self.assertEqual(remove_activity['actor'], self.user.remote_id)
|
||||
self.assertEqual(remove_activity['object']['id'], book.remote_id)
|
||||
self.assertEqual(remove_activity['target'], self.list.remote_id)
|
||||
self.assertEqual(remove_activity["actor"], self.user.remote_id)
|
||||
self.assertEqual(remove_activity["object"]["id"], book.remote_id)
|
||||
self.assertEqual(remove_activity["target"], self.list.remote_id)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
''' testing models '''
|
||||
""" testing models """
|
||||
from django.test import TestCase
|
||||
from django.core.exceptions import ValidationError
|
||||
|
||||
@@ -6,39 +6,36 @@ from bookwyrm import models, settings
|
||||
|
||||
|
||||
class ReadThrough(TestCase):
|
||||
''' some activitypub oddness ahead '''
|
||||
def setUp(self):
|
||||
''' look, a shelf '''
|
||||
self.user = models.User.objects.create_user(
|
||||
'mouse', 'mouse@mouse.mouse', 'mouseword',
|
||||
local=True, localname='mouse')
|
||||
""" some activitypub oddness ahead """
|
||||
|
||||
self.work = models.Work.objects.create(
|
||||
title='Example Work'
|
||||
def setUp(self):
|
||||
""" look, a shelf """
|
||||
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
|
||||
title="Example Edition", parent_work=self.work
|
||||
)
|
||||
self.work.default_edition = self.edition
|
||||
self.work.save()
|
||||
|
||||
self.readthrough = models.ReadThrough.objects.create(
|
||||
user=self.user,
|
||||
book=self.edition)
|
||||
user=self.user, book=self.edition
|
||||
)
|
||||
|
||||
def test_progress_update(self):
|
||||
''' Test progress updates '''
|
||||
self.readthrough.create_update() # No-op, no progress yet
|
||||
""" 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()
|
||||
|
||||
updates = self.readthrough.progressupdate_set \
|
||||
.order_by('created_date').all()
|
||||
updates = self.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)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
''' testing models '''
|
||||
""" testing models """
|
||||
from unittest.mock import patch
|
||||
from django.test import TestCase
|
||||
|
||||
@@ -6,87 +6,79 @@ from bookwyrm import models
|
||||
|
||||
|
||||
class Relationship(TestCase):
|
||||
''' following, blocking, stuff like that '''
|
||||
""" following, blocking, stuff like that """
|
||||
|
||||
def setUp(self):
|
||||
''' we need some users for this '''
|
||||
with patch('bookwyrm.models.user.set_remote_server.delay'):
|
||||
""" we need some users for this """
|
||||
with patch("bookwyrm.models.user.set_remote_server.delay"):
|
||||
self.remote_user = models.User.objects.create_user(
|
||||
'rat', 'rat@rat.com', 'ratword',
|
||||
"rat",
|
||||
"rat@rat.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',
|
||||
remote_id="https://example.com/users/rat",
|
||||
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')
|
||||
self.local_user.remote_id = 'http://local.com/user/mouse'
|
||||
"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)
|
||||
|
||||
|
||||
def test_user_follows_from_request(self):
|
||||
''' convert a follow request into a follow '''
|
||||
""" convert a follow request into a follow """
|
||||
real_broadcast = models.UserFollowRequest.broadcast
|
||||
|
||||
def mock_broadcast(_, activity, user):
|
||||
''' introspect what's being sent out '''
|
||||
""" introspect what's being sent out """
|
||||
self.assertEqual(user.remote_id, self.local_user.remote_id)
|
||||
self.assertEqual(activity['type'], 'Follow')
|
||||
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
|
||||
user_subject=self.local_user, user_object=self.remote_user
|
||||
)
|
||||
self.assertEqual(
|
||||
request.remote_id,
|
||||
'http://local.com/user/mouse#follows/%d' % request.id
|
||||
request.remote_id, "http://local.com/user/mouse#follows/%d" % request.id
|
||||
)
|
||||
self.assertEqual(request.status, 'follow_request')
|
||||
self.assertEqual(request.status, "follow_request")
|
||||
|
||||
rel = models.UserFollows.from_request(request)
|
||||
self.assertEqual(
|
||||
rel.remote_id,
|
||||
'http://local.com/user/mouse#follows/%d' % request.id
|
||||
rel.remote_id, "http://local.com/user/mouse#follows/%d" % request.id
|
||||
)
|
||||
self.assertEqual(rel.status, 'follows')
|
||||
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):
|
||||
''' store a specific remote id for a relationship provided by remote '''
|
||||
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
|
||||
""" 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(
|
||||
user_subject=self.local_user,
|
||||
user_object=self.remote_user,
|
||||
remote_id='http://antoher.server/sdkfhskdjf/23'
|
||||
remote_id="http://antoher.server/sdkfhskdjf/23",
|
||||
)
|
||||
self.assertEqual(
|
||||
request.remote_id,
|
||||
'http://antoher.server/sdkfhskdjf/23'
|
||||
)
|
||||
self.assertEqual(request.status, 'follow_request')
|
||||
self.assertEqual(request.remote_id, "http://antoher.server/sdkfhskdjf/23")
|
||||
self.assertEqual(request.status, "follow_request")
|
||||
|
||||
rel = models.UserFollows.from_request(request)
|
||||
self.assertEqual(
|
||||
rel.remote_id,
|
||||
'http://antoher.server/sdkfhskdjf/23'
|
||||
)
|
||||
self.assertEqual(rel.status, 'follows')
|
||||
self.assertEqual(rel.remote_id, "http://antoher.server/sdkfhskdjf/23")
|
||||
self.assertEqual(rel.status, "follows")
|
||||
self.assertEqual(rel.user_subject, self.local_user)
|
||||
self.assertEqual(rel.user_object, self.remote_user)
|
||||
|
||||
|
||||
def test_follow_request_activity(self):
|
||||
''' accept a request and make it a relationship '''
|
||||
""" 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')
|
||||
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(
|
||||
@@ -95,15 +87,15 @@ class Relationship(TestCase):
|
||||
)
|
||||
models.UserFollowRequest.broadcast = real_broadcast
|
||||
|
||||
|
||||
def test_follow_request_accept(self):
|
||||
''' accept a request and make it a relationship '''
|
||||
""" 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.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)
|
||||
@@ -111,7 +103,7 @@ class Relationship(TestCase):
|
||||
request = models.UserFollowRequest.objects.create(
|
||||
user_subject=self.remote_user,
|
||||
user_object=self.local_user,
|
||||
remote_id='https://www.hi.com/'
|
||||
remote_id="https://www.hi.com/",
|
||||
)
|
||||
request.accept()
|
||||
|
||||
@@ -122,16 +114,15 @@ class Relationship(TestCase):
|
||||
self.assertEqual(rel.user_object, self.local_user)
|
||||
models.UserFollowRequest.broadcast = real_broadcast
|
||||
|
||||
|
||||
def test_follow_request_reject(self):
|
||||
''' accept a request and make it a relationship '''
|
||||
""" 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)
|
||||
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
|
||||
|
||||
@@ -1,116 +1,120 @@
|
||||
''' testing models '''
|
||||
""" testing models """
|
||||
from django.test import TestCase
|
||||
|
||||
from bookwyrm import models, settings
|
||||
|
||||
|
||||
#pylint: disable=unused-argument
|
||||
# pylint: disable=unused-argument
|
||||
class Shelf(TestCase):
|
||||
''' some activitypub oddness ahead '''
|
||||
""" some activitypub oddness ahead """
|
||||
|
||||
def setUp(self):
|
||||
''' look, a shelf '''
|
||||
""" look, a shelf """
|
||||
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)
|
||||
"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):
|
||||
''' shelves use custom remote ids '''
|
||||
""" shelves use custom remote ids """
|
||||
real_broadcast = models.Shelf.broadcast
|
||||
|
||||
def broadcast_mock(_, activity, user, **kwargs):
|
||||
''' nah '''
|
||||
""" nah """
|
||||
|
||||
models.Shelf.broadcast = broadcast_mock
|
||||
shelf = models.Shelf.objects.create(
|
||||
name='Test Shelf', identifier='test-shelf',
|
||||
user=self.local_user)
|
||||
expected_id = 'https://%s/user/mouse/shelf/test-shelf' % settings.DOMAIN
|
||||
name="Test Shelf", identifier="test-shelf", user=self.local_user
|
||||
)
|
||||
expected_id = "https://%s/user/mouse/shelf/test-shelf" % settings.DOMAIN
|
||||
self.assertEqual(shelf.get_remote_id(), expected_id)
|
||||
models.Shelf.broadcast = real_broadcast
|
||||
|
||||
|
||||
def test_to_activity(self):
|
||||
''' jsonify it '''
|
||||
""" jsonify it """
|
||||
real_broadcast = models.Shelf.broadcast
|
||||
|
||||
def empty_mock(_, activity, user, **kwargs):
|
||||
''' nah '''
|
||||
""" nah """
|
||||
|
||||
models.Shelf.broadcast = empty_mock
|
||||
shelf = models.Shelf.objects.create(
|
||||
name='Test Shelf', identifier='test-shelf',
|
||||
user=self.local_user)
|
||||
name="Test Shelf", identifier="test-shelf", user=self.local_user
|
||||
)
|
||||
activity_json = shelf.to_activity()
|
||||
self.assertIsInstance(activity_json, dict)
|
||||
self.assertEqual(activity_json['id'], shelf.remote_id)
|
||||
self.assertEqual(activity_json['totalItems'], 0)
|
||||
self.assertEqual(activity_json['type'], 'Shelf')
|
||||
self.assertEqual(activity_json['name'], 'Test Shelf')
|
||||
self.assertEqual(activity_json['owner'], self.local_user.remote_id)
|
||||
self.assertEqual(activity_json["id"], shelf.remote_id)
|
||||
self.assertEqual(activity_json["totalItems"], 0)
|
||||
self.assertEqual(activity_json["type"], "Shelf")
|
||||
self.assertEqual(activity_json["name"], "Test Shelf")
|
||||
self.assertEqual(activity_json["owner"], self.local_user.remote_id)
|
||||
models.Shelf.broadcast = real_broadcast
|
||||
|
||||
|
||||
def test_create_update_shelf(self):
|
||||
''' create and broadcast shelf creation '''
|
||||
""" create and broadcast shelf creation """
|
||||
real_broadcast = models.Shelf.broadcast
|
||||
|
||||
def create_mock(_, activity, user, **kwargs):
|
||||
''' ok '''
|
||||
""" ok """
|
||||
self.assertEqual(user.remote_id, self.local_user.remote_id)
|
||||
self.assertEqual(activity['type'], 'Create')
|
||||
self.assertEqual(activity['actor'], self.local_user.remote_id)
|
||||
self.assertEqual(activity['object']['name'], 'Test Shelf')
|
||||
self.assertEqual(activity["type"], "Create")
|
||||
self.assertEqual(activity["actor"], self.local_user.remote_id)
|
||||
self.assertEqual(activity["object"]["name"], "Test Shelf")
|
||||
|
||||
models.Shelf.broadcast = create_mock
|
||||
|
||||
shelf = models.Shelf.objects.create(
|
||||
name='Test Shelf', identifier='test-shelf', user=self.local_user)
|
||||
name="Test Shelf", identifier="test-shelf", user=self.local_user
|
||||
)
|
||||
|
||||
def update_mock(_, activity, user, **kwargs):
|
||||
''' ok '''
|
||||
""" ok """
|
||||
self.assertEqual(user.remote_id, self.local_user.remote_id)
|
||||
self.assertEqual(activity['type'], 'Update')
|
||||
self.assertEqual(activity['actor'], self.local_user.remote_id)
|
||||
self.assertEqual(activity['object']['name'], 'arthur russel')
|
||||
self.assertEqual(activity["type"], "Update")
|
||||
self.assertEqual(activity["actor"], self.local_user.remote_id)
|
||||
self.assertEqual(activity["object"]["name"], "arthur russel")
|
||||
|
||||
models.Shelf.broadcast = update_mock
|
||||
|
||||
shelf.name = 'arthur russel'
|
||||
shelf.name = "arthur russel"
|
||||
shelf.save()
|
||||
self.assertEqual(shelf.name, 'arthur russel')
|
||||
self.assertEqual(shelf.name, "arthur russel")
|
||||
models.Shelf.broadcast = real_broadcast
|
||||
|
||||
|
||||
def test_shelve(self):
|
||||
''' create and broadcast shelf creation '''
|
||||
""" create and broadcast shelf creation """
|
||||
real_broadcast = models.Shelf.broadcast
|
||||
real_shelfbook_broadcast = models.ShelfBook.broadcast
|
||||
|
||||
def add_mock(_, activity, user, **kwargs):
|
||||
''' ok '''
|
||||
""" ok """
|
||||
self.assertEqual(user.remote_id, self.local_user.remote_id)
|
||||
self.assertEqual(activity['type'], 'Add')
|
||||
self.assertEqual(activity['actor'], self.local_user.remote_id)
|
||||
self.assertEqual(activity['object']['id'], self.book.remote_id)
|
||||
self.assertEqual(activity['target'], shelf.remote_id)
|
||||
self.assertEqual(activity["type"], "Add")
|
||||
self.assertEqual(activity["actor"], self.local_user.remote_id)
|
||||
self.assertEqual(activity["object"]["id"], self.book.remote_id)
|
||||
self.assertEqual(activity["target"], shelf.remote_id)
|
||||
|
||||
def remove_mock(_, activity, user, **kwargs):
|
||||
''' ok '''
|
||||
""" ok """
|
||||
self.assertEqual(user.remote_id, self.local_user.remote_id)
|
||||
self.assertEqual(activity['type'], 'Remove')
|
||||
self.assertEqual(activity['actor'], self.local_user.remote_id)
|
||||
self.assertEqual(activity['object']['id'], self.book.remote_id)
|
||||
self.assertEqual(activity['target'], shelf.remote_id)
|
||||
self.assertEqual(activity["type"], "Remove")
|
||||
self.assertEqual(activity["actor"], self.local_user.remote_id)
|
||||
self.assertEqual(activity["object"]["id"], self.book.remote_id)
|
||||
self.assertEqual(activity["target"], shelf.remote_id)
|
||||
|
||||
def empty_mock(_, activity, user, **kwargs):
|
||||
''' nah '''
|
||||
""" nah """
|
||||
|
||||
models.Shelf.broadcast = empty_mock
|
||||
shelf = models.Shelf.objects.create(
|
||||
name='Test Shelf', identifier='test-shelf', user=self.local_user)
|
||||
name="Test Shelf", identifier="test-shelf", user=self.local_user
|
||||
)
|
||||
|
||||
models.ShelfBook.broadcast = add_mock
|
||||
shelf_book = models.ShelfBook.objects.create(
|
||||
shelf=shelf,
|
||||
user=self.local_user,
|
||||
book=self.book)
|
||||
shelf=shelf, user=self.local_user, book=self.book
|
||||
)
|
||||
self.assertEqual(shelf.books.first(), self.book)
|
||||
|
||||
models.ShelfBook.broadcast = remove_mock
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
''' testing models '''
|
||||
""" testing models """
|
||||
from unittest.mock import patch
|
||||
from io import BytesIO
|
||||
import pathlib
|
||||
@@ -12,44 +12,45 @@ from django.utils import timezone
|
||||
from bookwyrm import models, settings
|
||||
|
||||
|
||||
@patch('bookwyrm.models.Status.broadcast')
|
||||
@patch("bookwyrm.models.Status.broadcast")
|
||||
class Status(TestCase):
|
||||
''' lotta types of statuses '''
|
||||
""" lotta types of statuses """
|
||||
|
||||
def setUp(self):
|
||||
''' useful things for creating a status '''
|
||||
""" useful things for creating a status """
|
||||
self.user = models.User.objects.create_user(
|
||||
'mouse', 'mouse@mouse.mouse', 'mouseword',
|
||||
local=True, localname='mouse')
|
||||
self.book = models.Edition.objects.create(title='Test Edition')
|
||||
"mouse", "mouse@mouse.mouse", "mouseword", local=True, localname="mouse"
|
||||
)
|
||||
self.book = models.Edition.objects.create(title="Test Edition")
|
||||
|
||||
image_file = pathlib.Path(__file__).parent.joinpath(
|
||||
'../../static/images/default_avi.jpg')
|
||||
"../../static/images/default_avi.jpg"
|
||||
)
|
||||
image = Image.open(image_file)
|
||||
output = BytesIO()
|
||||
with patch('bookwyrm.models.Status.broadcast'):
|
||||
with patch("bookwyrm.models.Status.broadcast"):
|
||||
image.save(output, format=image.format)
|
||||
self.book.cover.save(
|
||||
'test.jpg',
|
||||
ContentFile(output.getvalue())
|
||||
)
|
||||
self.book.cover.save("test.jpg", ContentFile(output.getvalue()))
|
||||
|
||||
def test_status_generated_fields(self, _):
|
||||
''' setting remote id '''
|
||||
status = models.Status.objects.create(content='bleh', user=self.user)
|
||||
expected_id = 'https://%s/user/mouse/status/%d' % \
|
||||
(settings.DOMAIN, status.id)
|
||||
""" setting remote id """
|
||||
status = models.Status.objects.create(content="bleh", user=self.user)
|
||||
expected_id = "https://%s/user/mouse/status/%d" % (settings.DOMAIN, status.id)
|
||||
self.assertEqual(status.remote_id, expected_id)
|
||||
self.assertEqual(status.privacy, 'public')
|
||||
self.assertEqual(status.privacy, "public")
|
||||
|
||||
def test_replies(self, _):
|
||||
''' get a list of replies '''
|
||||
parent = models.Status.objects.create(content='hi', user=self.user)
|
||||
""" get a list of replies """
|
||||
parent = models.Status.objects.create(content="hi", user=self.user)
|
||||
child = models.Status.objects.create(
|
||||
content='hello', reply_parent=parent, user=self.user)
|
||||
content="hello", reply_parent=parent, user=self.user
|
||||
)
|
||||
models.Review.objects.create(
|
||||
content='hey', reply_parent=parent, user=self.user, book=self.book)
|
||||
content="hey", reply_parent=parent, user=self.user, book=self.book
|
||||
)
|
||||
models.Status.objects.create(
|
||||
content='hi hello', reply_parent=child, user=self.user)
|
||||
content="hi hello", reply_parent=child, user=self.user
|
||||
)
|
||||
|
||||
replies = models.Status.replies(parent)
|
||||
self.assertEqual(replies.count(), 2)
|
||||
@@ -58,199 +59,228 @@ class Status(TestCase):
|
||||
self.assertIsInstance(replies.last(), models.Review)
|
||||
|
||||
def test_status_type(self, _):
|
||||
''' class name '''
|
||||
self.assertEqual(models.Status().status_type, 'Note')
|
||||
self.assertEqual(models.Review().status_type, 'Review')
|
||||
self.assertEqual(models.Quotation().status_type, 'Quotation')
|
||||
self.assertEqual(models.Comment().status_type, 'Comment')
|
||||
self.assertEqual(models.Boost().status_type, 'Announce')
|
||||
""" class name """
|
||||
self.assertEqual(models.Status().status_type, "Note")
|
||||
self.assertEqual(models.Review().status_type, "Review")
|
||||
self.assertEqual(models.Quotation().status_type, "Quotation")
|
||||
self.assertEqual(models.Comment().status_type, "Comment")
|
||||
self.assertEqual(models.Boost().status_type, "Announce")
|
||||
|
||||
def test_boostable(self, _):
|
||||
''' can a status be boosted, based on privacy '''
|
||||
self.assertTrue(models.Status(privacy='public').boostable)
|
||||
self.assertTrue(models.Status(privacy='unlisted').boostable)
|
||||
self.assertFalse(models.Status(privacy='followers').boostable)
|
||||
self.assertFalse(models.Status(privacy='direct').boostable)
|
||||
""" can a status be boosted, based on privacy """
|
||||
self.assertTrue(models.Status(privacy="public").boostable)
|
||||
self.assertTrue(models.Status(privacy="unlisted").boostable)
|
||||
self.assertFalse(models.Status(privacy="followers").boostable)
|
||||
self.assertFalse(models.Status(privacy="direct").boostable)
|
||||
|
||||
def test_to_replies(self, _):
|
||||
''' activitypub replies collection '''
|
||||
parent = models.Status.objects.create(content='hi', user=self.user)
|
||||
""" activitypub replies collection """
|
||||
parent = models.Status.objects.create(content="hi", user=self.user)
|
||||
child = models.Status.objects.create(
|
||||
content='hello', reply_parent=parent, user=self.user)
|
||||
content="hello", reply_parent=parent, user=self.user
|
||||
)
|
||||
models.Review.objects.create(
|
||||
content='hey', reply_parent=parent, user=self.user, book=self.book)
|
||||
content="hey", reply_parent=parent, user=self.user, book=self.book
|
||||
)
|
||||
models.Status.objects.create(
|
||||
content='hi hello', reply_parent=child, user=self.user)
|
||||
content="hi hello", reply_parent=child, user=self.user
|
||||
)
|
||||
|
||||
replies = parent.to_replies()
|
||||
self.assertEqual(replies['id'], '%s/replies' % parent.remote_id)
|
||||
self.assertEqual(replies['totalItems'], 2)
|
||||
self.assertEqual(replies["id"], "%s/replies" % parent.remote_id)
|
||||
self.assertEqual(replies["totalItems"], 2)
|
||||
|
||||
def test_status_to_activity(self, _):
|
||||
''' subclass of the base model version with a "pure" serializer '''
|
||||
status = models.Status.objects.create(
|
||||
content='test content', user=self.user)
|
||||
""" subclass of the base model version with a "pure" serializer """
|
||||
status = models.Status.objects.create(content="test content", user=self.user)
|
||||
activity = status.to_activity()
|
||||
self.assertEqual(activity['id'], status.remote_id)
|
||||
self.assertEqual(activity['type'], 'Note')
|
||||
self.assertEqual(activity['content'], 'test content')
|
||||
self.assertEqual(activity['sensitive'], False)
|
||||
self.assertEqual(activity["id"], status.remote_id)
|
||||
self.assertEqual(activity["type"], "Note")
|
||||
self.assertEqual(activity["content"], "test content")
|
||||
self.assertEqual(activity["sensitive"], False)
|
||||
|
||||
def test_status_to_activity_tombstone(self, _):
|
||||
''' subclass of the base model version with a "pure" serializer '''
|
||||
""" subclass of the base model version with a "pure" serializer """
|
||||
status = models.Status.objects.create(
|
||||
content='test content', user=self.user,
|
||||
deleted=True, deleted_date=timezone.now())
|
||||
content="test content",
|
||||
user=self.user,
|
||||
deleted=True,
|
||||
deleted_date=timezone.now(),
|
||||
)
|
||||
activity = status.to_activity()
|
||||
self.assertEqual(activity['id'], status.remote_id)
|
||||
self.assertEqual(activity['type'], 'Tombstone')
|
||||
self.assertFalse(hasattr(activity, 'content'))
|
||||
self.assertEqual(activity["id"], status.remote_id)
|
||||
self.assertEqual(activity["type"], "Tombstone")
|
||||
self.assertFalse(hasattr(activity, "content"))
|
||||
|
||||
def test_status_to_pure_activity(self, _):
|
||||
''' subclass of the base model version with a "pure" serializer '''
|
||||
status = models.Status.objects.create(
|
||||
content='test content', user=self.user)
|
||||
""" subclass of the base model version with a "pure" serializer """
|
||||
status = models.Status.objects.create(content="test content", user=self.user)
|
||||
activity = status.to_activity(pure=True)
|
||||
self.assertEqual(activity['id'], status.remote_id)
|
||||
self.assertEqual(activity['type'], 'Note')
|
||||
self.assertEqual(activity['content'], 'test content')
|
||||
self.assertEqual(activity['sensitive'], False)
|
||||
self.assertEqual(activity['attachment'], [])
|
||||
self.assertEqual(activity["id"], status.remote_id)
|
||||
self.assertEqual(activity["type"], "Note")
|
||||
self.assertEqual(activity["content"], "test content")
|
||||
self.assertEqual(activity["sensitive"], False)
|
||||
self.assertEqual(activity["attachment"], [])
|
||||
|
||||
def test_generated_note_to_activity(self, _):
|
||||
''' subclass of the base model version with a "pure" serializer '''
|
||||
""" subclass of the base model version with a "pure" serializer """
|
||||
status = models.GeneratedNote.objects.create(
|
||||
content='test content', user=self.user)
|
||||
content="test content", user=self.user
|
||||
)
|
||||
status.mention_books.set([self.book])
|
||||
status.mention_users.set([self.user])
|
||||
activity = status.to_activity()
|
||||
self.assertEqual(activity['id'], status.remote_id)
|
||||
self.assertEqual(activity['type'], 'GeneratedNote')
|
||||
self.assertEqual(activity['content'], 'test content')
|
||||
self.assertEqual(activity['sensitive'], False)
|
||||
self.assertEqual(len(activity['tag']), 2)
|
||||
self.assertEqual(activity["id"], status.remote_id)
|
||||
self.assertEqual(activity["type"], "GeneratedNote")
|
||||
self.assertEqual(activity["content"], "test content")
|
||||
self.assertEqual(activity["sensitive"], False)
|
||||
self.assertEqual(len(activity["tag"]), 2)
|
||||
|
||||
def test_generated_note_to_pure_activity(self, _):
|
||||
''' subclass of the base model version with a "pure" serializer '''
|
||||
""" subclass of the base model version with a "pure" serializer """
|
||||
status = models.GeneratedNote.objects.create(
|
||||
content='test content', user=self.user)
|
||||
content="test content", user=self.user
|
||||
)
|
||||
status.mention_books.set([self.book])
|
||||
status.mention_users.set([self.user])
|
||||
activity = status.to_activity(pure=True)
|
||||
self.assertEqual(activity['id'], status.remote_id)
|
||||
self.assertEqual(activity["id"], status.remote_id)
|
||||
self.assertEqual(
|
||||
activity['content'],
|
||||
'mouse test content <a href="%s">"Test Edition"</a>' % \
|
||||
self.book.remote_id)
|
||||
self.assertEqual(len(activity['tag']), 2)
|
||||
self.assertEqual(activity['type'], 'Note')
|
||||
self.assertEqual(activity['sensitive'], False)
|
||||
self.assertIsInstance(activity['attachment'], list)
|
||||
self.assertEqual(activity['attachment'][0].type, 'Image')
|
||||
self.assertEqual(activity['attachment'][0].url, 'https://%s%s' % \
|
||||
(settings.DOMAIN, self.book.cover.url))
|
||||
activity["content"],
|
||||
'mouse test content <a href="%s">"Test Edition"</a>' % self.book.remote_id,
|
||||
)
|
||||
self.assertEqual(len(activity["tag"]), 2)
|
||||
self.assertEqual(activity["type"], "Note")
|
||||
self.assertEqual(activity["sensitive"], False)
|
||||
self.assertIsInstance(activity["attachment"], list)
|
||||
self.assertEqual(activity["attachment"][0].type, "Image")
|
||||
self.assertEqual(
|
||||
activity['attachment'][0].name, 'Test Edition')
|
||||
activity["attachment"][0].url,
|
||||
"https://%s%s" % (settings.DOMAIN, self.book.cover.url),
|
||||
)
|
||||
self.assertEqual(activity["attachment"][0].name, "Test Edition")
|
||||
|
||||
def test_comment_to_activity(self, _):
|
||||
''' subclass of the base model version with a "pure" serializer '''
|
||||
""" subclass of the base model version with a "pure" serializer """
|
||||
status = models.Comment.objects.create(
|
||||
content='test content', user=self.user, book=self.book)
|
||||
content="test content", user=self.user, book=self.book
|
||||
)
|
||||
activity = status.to_activity()
|
||||
self.assertEqual(activity['id'], status.remote_id)
|
||||
self.assertEqual(activity['type'], 'Comment')
|
||||
self.assertEqual(activity['content'], 'test content')
|
||||
self.assertEqual(activity['inReplyToBook'], self.book.remote_id)
|
||||
self.assertEqual(activity["id"], status.remote_id)
|
||||
self.assertEqual(activity["type"], "Comment")
|
||||
self.assertEqual(activity["content"], "test content")
|
||||
self.assertEqual(activity["inReplyToBook"], self.book.remote_id)
|
||||
|
||||
def test_comment_to_pure_activity(self, _):
|
||||
''' subclass of the base model version with a "pure" serializer '''
|
||||
""" subclass of the base model version with a "pure" serializer """
|
||||
status = models.Comment.objects.create(
|
||||
content='test content', user=self.user, book=self.book)
|
||||
content="test content", user=self.user, book=self.book
|
||||
)
|
||||
activity = status.to_activity(pure=True)
|
||||
self.assertEqual(activity['id'], status.remote_id)
|
||||
self.assertEqual(activity['type'], 'Note')
|
||||
self.assertEqual(activity["id"], status.remote_id)
|
||||
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)
|
||||
self.assertEqual(activity['attachment'][0].type, 'Image')
|
||||
self.assertEqual(activity['attachment'][0].url, 'https://%s%s' % \
|
||||
(settings.DOMAIN, self.book.cover.url))
|
||||
activity["content"],
|
||||
'test content<p>(comment on <a href="%s">"Test Edition"</a>)</p>'
|
||||
% self.book.remote_id,
|
||||
)
|
||||
self.assertEqual(activity["attachment"][0].type, "Image")
|
||||
self.assertEqual(
|
||||
activity['attachment'][0].name, 'Test Edition')
|
||||
activity["attachment"][0].url,
|
||||
"https://%s%s" % (settings.DOMAIN, self.book.cover.url),
|
||||
)
|
||||
self.assertEqual(activity["attachment"][0].name, "Test Edition")
|
||||
|
||||
def test_quotation_to_activity(self, _):
|
||||
''' subclass of the base model version with a "pure" serializer '''
|
||||
""" subclass of the base model version with a "pure" serializer """
|
||||
status = models.Quotation.objects.create(
|
||||
quote='a sickening sense', content='test content',
|
||||
user=self.user, book=self.book)
|
||||
quote="a sickening sense",
|
||||
content="test content",
|
||||
user=self.user,
|
||||
book=self.book,
|
||||
)
|
||||
activity = status.to_activity()
|
||||
self.assertEqual(activity['id'], status.remote_id)
|
||||
self.assertEqual(activity['type'], 'Quotation')
|
||||
self.assertEqual(activity['quote'], 'a sickening sense')
|
||||
self.assertEqual(activity['content'], 'test content')
|
||||
self.assertEqual(activity['inReplyToBook'], self.book.remote_id)
|
||||
self.assertEqual(activity["id"], status.remote_id)
|
||||
self.assertEqual(activity["type"], "Quotation")
|
||||
self.assertEqual(activity["quote"], "a sickening sense")
|
||||
self.assertEqual(activity["content"], "test content")
|
||||
self.assertEqual(activity["inReplyToBook"], self.book.remote_id)
|
||||
|
||||
def test_quotation_to_pure_activity(self, _):
|
||||
''' subclass of the base model version with a "pure" serializer '''
|
||||
""" subclass of the base model version with a "pure" serializer """
|
||||
status = models.Quotation.objects.create(
|
||||
quote='a sickening sense', content='test content',
|
||||
user=self.user, book=self.book)
|
||||
quote="a sickening sense",
|
||||
content="test content",
|
||||
user=self.user,
|
||||
book=self.book,
|
||||
)
|
||||
activity = status.to_activity(pure=True)
|
||||
self.assertEqual(activity['id'], status.remote_id)
|
||||
self.assertEqual(activity['type'], 'Note')
|
||||
self.assertEqual(activity["id"], status.remote_id)
|
||||
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)
|
||||
self.assertEqual(activity['attachment'][0].type, 'Image')
|
||||
self.assertEqual(activity['attachment'][0].url, 'https://%s%s' % \
|
||||
(settings.DOMAIN, self.book.cover.url))
|
||||
activity["content"],
|
||||
'a sickening sense <p>-- <a href="%s">"Test Edition"</a></p>'
|
||||
"test content" % self.book.remote_id,
|
||||
)
|
||||
self.assertEqual(activity["attachment"][0].type, "Image")
|
||||
self.assertEqual(
|
||||
activity['attachment'][0].name, 'Test Edition')
|
||||
activity["attachment"][0].url,
|
||||
"https://%s%s" % (settings.DOMAIN, self.book.cover.url),
|
||||
)
|
||||
self.assertEqual(activity["attachment"][0].name, "Test Edition")
|
||||
|
||||
def test_review_to_activity(self, _):
|
||||
''' subclass of the base model version with a "pure" serializer '''
|
||||
""" subclass of the base model version with a "pure" serializer """
|
||||
status = models.Review.objects.create(
|
||||
name='Review name', content='test content', rating=3,
|
||||
user=self.user, book=self.book)
|
||||
name="Review name",
|
||||
content="test content",
|
||||
rating=3,
|
||||
user=self.user,
|
||||
book=self.book,
|
||||
)
|
||||
activity = status.to_activity()
|
||||
self.assertEqual(activity['id'], status.remote_id)
|
||||
self.assertEqual(activity['type'], 'Review')
|
||||
self.assertEqual(activity['rating'], 3)
|
||||
self.assertEqual(activity['name'], 'Review name')
|
||||
self.assertEqual(activity['content'], 'test content')
|
||||
self.assertEqual(activity['inReplyToBook'], self.book.remote_id)
|
||||
self.assertEqual(activity["id"], status.remote_id)
|
||||
self.assertEqual(activity["type"], "Review")
|
||||
self.assertEqual(activity["rating"], 3)
|
||||
self.assertEqual(activity["name"], "Review name")
|
||||
self.assertEqual(activity["content"], "test content")
|
||||
self.assertEqual(activity["inReplyToBook"], self.book.remote_id)
|
||||
|
||||
def test_review_to_pure_activity(self, _):
|
||||
''' subclass of the base model version with a "pure" serializer '''
|
||||
""" subclass of the base model version with a "pure" serializer """
|
||||
status = models.Review.objects.create(
|
||||
name='Review name', content='test content', rating=3,
|
||||
user=self.user, book=self.book)
|
||||
name="Review name",
|
||||
content="test content",
|
||||
rating=3,
|
||||
user=self.user,
|
||||
book=self.book,
|
||||
)
|
||||
activity = status.to_activity(pure=True)
|
||||
self.assertEqual(activity['id'], status.remote_id)
|
||||
self.assertEqual(activity['type'], 'Article')
|
||||
self.assertEqual(activity["id"], status.remote_id)
|
||||
self.assertEqual(activity["type"], "Article")
|
||||
self.assertEqual(
|
||||
activity['name'], 'Review of "%s" (3 stars): Review name' \
|
||||
% self.book.title)
|
||||
self.assertEqual(activity['content'], 'test content')
|
||||
self.assertEqual(activity['attachment'][0].type, 'Image')
|
||||
self.assertEqual(activity['attachment'][0].url, 'https://%s%s' % \
|
||||
(settings.DOMAIN, self.book.cover.url))
|
||||
activity["name"], 'Review of "%s" (3 stars): Review name' % self.book.title
|
||||
)
|
||||
self.assertEqual(activity["content"], "test content")
|
||||
self.assertEqual(activity["attachment"][0].type, "Image")
|
||||
self.assertEqual(
|
||||
activity['attachment'][0].name, 'Test Edition')
|
||||
activity["attachment"][0].url,
|
||||
"https://%s%s" % (settings.DOMAIN, self.book.cover.url),
|
||||
)
|
||||
self.assertEqual(activity["attachment"][0].name, "Test Edition")
|
||||
|
||||
def test_favorite(self, _):
|
||||
''' fav a status '''
|
||||
""" fav a status """
|
||||
real_broadcast = models.Favorite.broadcast
|
||||
|
||||
def fav_broadcast_mock(_, activity, user):
|
||||
''' ok '''
|
||||
""" ok """
|
||||
self.assertEqual(user.remote_id, self.user.remote_id)
|
||||
self.assertEqual(activity['type'], 'Like')
|
||||
self.assertEqual(activity["type"], "Like")
|
||||
|
||||
models.Favorite.broadcast = fav_broadcast_mock
|
||||
|
||||
status = models.Status.objects.create(
|
||||
content='test content', user=self.user)
|
||||
status = models.Status.objects.create(content="test content", user=self.user)
|
||||
fav = models.Favorite.objects.create(status=status, user=self.user)
|
||||
|
||||
# can't fav a status twice
|
||||
@@ -258,50 +288,47 @@ class Status(TestCase):
|
||||
models.Favorite.objects.create(status=status, user=self.user)
|
||||
|
||||
activity = fav.to_activity()
|
||||
self.assertEqual(activity['type'], 'Like')
|
||||
self.assertEqual(activity['actor'], self.user.remote_id)
|
||||
self.assertEqual(activity['object'], status.remote_id)
|
||||
self.assertEqual(activity["type"], "Like")
|
||||
self.assertEqual(activity["actor"], self.user.remote_id)
|
||||
self.assertEqual(activity["object"], status.remote_id)
|
||||
models.Favorite.broadcast = real_broadcast
|
||||
|
||||
def test_boost(self, _):
|
||||
''' boosting, this one's a bit fussy '''
|
||||
status = models.Status.objects.create(
|
||||
content='test content', user=self.user)
|
||||
boost = models.Boost.objects.create(
|
||||
boosted_status=status, user=self.user)
|
||||
""" boosting, this one's a bit fussy """
|
||||
status = models.Status.objects.create(content="test content", user=self.user)
|
||||
boost = models.Boost.objects.create(boosted_status=status, user=self.user)
|
||||
activity = boost.to_activity()
|
||||
self.assertEqual(activity['actor'], self.user.remote_id)
|
||||
self.assertEqual(activity['object'], status.remote_id)
|
||||
self.assertEqual(activity['type'], 'Announce')
|
||||
self.assertEqual(activity["actor"], self.user.remote_id)
|
||||
self.assertEqual(activity["object"], status.remote_id)
|
||||
self.assertEqual(activity["type"], "Announce")
|
||||
self.assertEqual(activity, boost.to_activity(pure=True))
|
||||
|
||||
def test_notification(self, _):
|
||||
''' a simple model '''
|
||||
""" a simple model """
|
||||
notification = models.Notification.objects.create(
|
||||
user=self.user, notification_type='FAVORITE')
|
||||
user=self.user, notification_type="FAVORITE"
|
||||
)
|
||||
self.assertFalse(notification.read)
|
||||
|
||||
with self.assertRaises(IntegrityError):
|
||||
models.Notification.objects.create(
|
||||
user=self.user, notification_type='GLORB')
|
||||
|
||||
user=self.user, notification_type="GLORB"
|
||||
)
|
||||
|
||||
def test_create_broadcast(self, broadcast_mock):
|
||||
''' should send out two verions of a status on create '''
|
||||
models.Comment.objects.create(
|
||||
content='hi', user=self.user, book=self.book)
|
||||
""" should send out two verions of a status on create """
|
||||
models.Comment.objects.create(content="hi", user=self.user, book=self.book)
|
||||
self.assertEqual(broadcast_mock.call_count, 2)
|
||||
pure_call = broadcast_mock.call_args_list[0]
|
||||
bw_call = broadcast_mock.call_args_list[1]
|
||||
|
||||
self.assertEqual(pure_call[1]['software'], 'other')
|
||||
self.assertEqual(pure_call[1]["software"], "other")
|
||||
args = pure_call[0][0]
|
||||
self.assertEqual(args['type'], 'Create')
|
||||
self.assertEqual(args['object']['type'], 'Note')
|
||||
self.assertTrue('content' in args['object'])
|
||||
self.assertEqual(args["type"], "Create")
|
||||
self.assertEqual(args["object"]["type"], "Note")
|
||||
self.assertTrue("content" in args["object"])
|
||||
|
||||
|
||||
self.assertEqual(bw_call[1]['software'], 'bookwyrm')
|
||||
self.assertEqual(bw_call[1]["software"], "bookwyrm")
|
||||
args = bw_call[0][0]
|
||||
self.assertEqual(args['type'], 'Create')
|
||||
self.assertEqual(args['object']['type'], 'Comment')
|
||||
self.assertEqual(args["type"], "Create")
|
||||
self.assertEqual(args["object"]["type"], "Comment")
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
''' testing models '''
|
||||
""" testing models """
|
||||
from unittest.mock import patch
|
||||
from django.test import TestCase
|
||||
import responses
|
||||
@@ -11,75 +11,84 @@ from bookwyrm.settings import DOMAIN
|
||||
class User(TestCase):
|
||||
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)
|
||||
"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
|
||||
""" username instead of id here """
|
||||
expected_id = "https://%s/user/mouse" % DOMAIN
|
||||
self.assertEqual(self.user.remote_id, expected_id)
|
||||
self.assertEqual(self.user.username, 'mouse@%s' % 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.username, "mouse@%s" % 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.assertIsNotNone(self.user.key_pair.private_key)
|
||||
self.assertIsNotNone(self.user.key_pair.public_key)
|
||||
|
||||
def test_remote_user(self):
|
||||
with patch('bookwyrm.models.user.set_remote_server.delay'):
|
||||
with patch("bookwyrm.models.user.set_remote_server.delay"):
|
||||
user = models.User.objects.create_user(
|
||||
'rat', 'rat@rat.rat', 'ratword', local=False,
|
||||
remote_id='https://example.com/dfjkg', bookwyrm_user=False)
|
||||
self.assertEqual(user.username, 'rat@example.com')
|
||||
|
||||
"rat",
|
||||
"rat@rat.rat",
|
||||
"ratword",
|
||||
local=False,
|
||||
remote_id="https://example.com/dfjkg",
|
||||
bookwyrm_user=False,
|
||||
)
|
||||
self.assertEqual(user.username, "rat@example.com")
|
||||
|
||||
def test_user_shelves(self):
|
||||
shelves = models.Shelf.objects.filter(user=self.user).all()
|
||||
self.assertEqual(len(shelves), 3)
|
||||
names = [s.name for s in shelves]
|
||||
self.assertTrue('To Read' in names)
|
||||
self.assertTrue('Currently Reading' in names)
|
||||
self.assertTrue('Read' in names)
|
||||
self.assertTrue("To Read" in names)
|
||||
self.assertTrue("Currently Reading" in names)
|
||||
self.assertTrue("Read" in names)
|
||||
ids = [s.identifier for s in shelves]
|
||||
self.assertTrue('to-read' in ids)
|
||||
self.assertTrue('reading' in ids)
|
||||
self.assertTrue('read' in ids)
|
||||
|
||||
self.assertTrue("to-read" in ids)
|
||||
self.assertTrue("reading" in ids)
|
||||
self.assertTrue("read" in ids)
|
||||
|
||||
def test_activitypub_serialize(self):
|
||||
activity = self.user.to_activity()
|
||||
self.assertEqual(activity['id'], self.user.remote_id)
|
||||
self.assertEqual(activity['@context'], [
|
||||
'https://www.w3.org/ns/activitystreams',
|
||||
'https://w3id.org/security/v1',
|
||||
{
|
||||
'manuallyApprovesFollowers': 'as:manuallyApprovesFollowers',
|
||||
'schema': 'http://schema.org#',
|
||||
'PropertyValue': 'schema:PropertyValue',
|
||||
'value': 'schema:value',
|
||||
}
|
||||
])
|
||||
self.assertEqual(activity['preferredUsername'], self.user.localname)
|
||||
self.assertEqual(activity['name'], self.user.name)
|
||||
self.assertEqual(activity['inbox'], self.user.inbox)
|
||||
self.assertEqual(activity['outbox'], self.user.outbox)
|
||||
self.assertEqual(activity['bookwyrmUser'], False)
|
||||
self.assertEqual(activity['discoverable'], True)
|
||||
self.assertEqual(activity['type'], 'Person')
|
||||
self.assertEqual(activity["id"], self.user.remote_id)
|
||||
self.assertEqual(
|
||||
activity["@context"],
|
||||
[
|
||||
"https://www.w3.org/ns/activitystreams",
|
||||
"https://w3id.org/security/v1",
|
||||
{
|
||||
"manuallyApprovesFollowers": "as:manuallyApprovesFollowers",
|
||||
"schema": "http://schema.org#",
|
||||
"PropertyValue": "schema:PropertyValue",
|
||||
"value": "schema:value",
|
||||
},
|
||||
],
|
||||
)
|
||||
self.assertEqual(activity["preferredUsername"], self.user.localname)
|
||||
self.assertEqual(activity["name"], self.user.name)
|
||||
self.assertEqual(activity["inbox"], self.user.inbox)
|
||||
self.assertEqual(activity["outbox"], self.user.outbox)
|
||||
self.assertEqual(activity["bookwyrmUser"], False)
|
||||
self.assertEqual(activity["discoverable"], True)
|
||||
self.assertEqual(activity["type"], "Person")
|
||||
|
||||
def test_activitypub_outbox(self):
|
||||
activity = self.user.to_outbox()
|
||||
self.assertEqual(activity['type'], 'OrderedCollection')
|
||||
self.assertEqual(activity['id'], self.user.outbox)
|
||||
self.assertEqual(activity['totalItems'], 0)
|
||||
|
||||
self.assertEqual(activity["type"], "OrderedCollection")
|
||||
self.assertEqual(activity["id"], self.user.outbox)
|
||||
self.assertEqual(activity["totalItems"], 0)
|
||||
|
||||
def test_set_remote_server(self):
|
||||
server = models.FederatedServer.objects.create(
|
||||
server_name=DOMAIN,
|
||||
application_type='test type',
|
||||
application_version=3
|
||||
server_name=DOMAIN, application_type="test type", application_version=3
|
||||
)
|
||||
|
||||
models.user.set_remote_server(self.user.id)
|
||||
@@ -91,26 +100,24 @@ class User(TestCase):
|
||||
def test_get_or_create_remote_server(self):
|
||||
responses.add(
|
||||
responses.GET,
|
||||
'https://%s/.well-known/nodeinfo' % DOMAIN,
|
||||
json={'links': [{'href': 'http://www.example.com'}, {}]}
|
||||
"https://%s/.well-known/nodeinfo" % DOMAIN,
|
||||
json={"links": [{"href": "http://www.example.com"}, {}]},
|
||||
)
|
||||
responses.add(
|
||||
responses.GET,
|
||||
'http://www.example.com',
|
||||
json={'software': {'name': 'hi', 'version': '2'}},
|
||||
"http://www.example.com",
|
||||
json={"software": {"name": "hi", "version": "2"}},
|
||||
)
|
||||
|
||||
server = models.user.get_or_create_remote_server(DOMAIN)
|
||||
self.assertEqual(server.server_name, DOMAIN)
|
||||
self.assertEqual(server.application_type, 'hi')
|
||||
self.assertEqual(server.application_version, '2')
|
||||
self.assertEqual(server.application_type, "hi")
|
||||
self.assertEqual(server.application_version, "2")
|
||||
|
||||
@responses.activate
|
||||
def test_get_or_create_remote_server_no_wellknown(self):
|
||||
responses.add(
|
||||
responses.GET,
|
||||
'https://%s/.well-known/nodeinfo' % DOMAIN,
|
||||
status=404
|
||||
responses.GET, "https://%s/.well-known/nodeinfo" % DOMAIN, status=404
|
||||
)
|
||||
|
||||
server = models.user.get_or_create_remote_server(DOMAIN)
|
||||
@@ -122,14 +129,10 @@ class User(TestCase):
|
||||
def test_get_or_create_remote_server_no_links(self):
|
||||
responses.add(
|
||||
responses.GET,
|
||||
'https://%s/.well-known/nodeinfo' % DOMAIN,
|
||||
json={'links': [{'href': 'http://www.example.com'}, {}]}
|
||||
)
|
||||
responses.add(
|
||||
responses.GET,
|
||||
'http://www.example.com',
|
||||
status=404
|
||||
"https://%s/.well-known/nodeinfo" % DOMAIN,
|
||||
json={"links": [{"href": "http://www.example.com"}, {}]},
|
||||
)
|
||||
responses.add(responses.GET, "http://www.example.com", status=404)
|
||||
|
||||
server = models.user.get_or_create_remote_server(DOMAIN)
|
||||
self.assertEqual(server.server_name, DOMAIN)
|
||||
@@ -140,14 +143,10 @@ class User(TestCase):
|
||||
def test_get_or_create_remote_server_unknown_format(self):
|
||||
responses.add(
|
||||
responses.GET,
|
||||
'https://%s/.well-known/nodeinfo' % DOMAIN,
|
||||
json={'links': [{'href': 'http://www.example.com'}, {}]}
|
||||
)
|
||||
responses.add(
|
||||
responses.GET,
|
||||
'http://www.example.com',
|
||||
json={'fish': 'salmon'}
|
||||
"https://%s/.well-known/nodeinfo" % DOMAIN,
|
||||
json={"links": [{"href": "http://www.example.com"}, {}]},
|
||||
)
|
||||
responses.add(responses.GET, "http://www.example.com", json={"fish": "salmon"})
|
||||
|
||||
server = models.user.get_or_create_remote_server(DOMAIN)
|
||||
self.assertEqual(server.server_name, DOMAIN)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
''' testing import '''
|
||||
""" testing import """
|
||||
from collections import namedtuple
|
||||
import csv
|
||||
import pathlib
|
||||
@@ -12,125 +12,117 @@ from bookwyrm.goodreads_import import GoodreadsImporter
|
||||
from bookwyrm import importer
|
||||
from bookwyrm.settings import DOMAIN
|
||||
|
||||
|
||||
class GoodreadsImport(TestCase):
|
||||
''' importing from goodreads csv '''
|
||||
""" importing from goodreads csv """
|
||||
|
||||
def setUp(self):
|
||||
self.importer = GoodreadsImporter()
|
||||
''' use a test csv '''
|
||||
datafile = pathlib.Path(__file__).parent.joinpath(
|
||||
'data/goodreads.csv')
|
||||
self.csv = open(datafile, 'r', encoding=self.importer.encoding)
|
||||
""" use a test csv """
|
||||
datafile = pathlib.Path(__file__).parent.joinpath("data/goodreads.csv")
|
||||
self.csv = open(datafile, "r", encoding=self.importer.encoding)
|
||||
self.user = models.User.objects.create_user(
|
||||
'mouse', 'mouse@mouse.mouse', 'password', local=True)
|
||||
"mouse", "mouse@mouse.mouse", "password", local=True
|
||||
)
|
||||
|
||||
models.Connector.objects.create(
|
||||
identifier=DOMAIN,
|
||||
name='Local',
|
||||
name="Local",
|
||||
local=True,
|
||||
connector_file='self_connector',
|
||||
base_url='https://%s' % DOMAIN,
|
||||
books_url='https://%s/book' % DOMAIN,
|
||||
covers_url='https://%s/images/covers' % DOMAIN,
|
||||
search_url='https://%s/search?q=' % DOMAIN,
|
||||
connector_file="self_connector",
|
||||
base_url="https://%s" % DOMAIN,
|
||||
books_url="https://%s/book" % DOMAIN,
|
||||
covers_url="https://%s/images/covers" % DOMAIN,
|
||||
search_url="https://%s/search?q=" % DOMAIN,
|
||||
priority=1,
|
||||
)
|
||||
work = models.Work.objects.create(title='Test Work')
|
||||
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
|
||||
title="Example Edition",
|
||||
remote_id="https://example.com/book/1",
|
||||
parent_work=work,
|
||||
)
|
||||
|
||||
|
||||
def test_create_job(self):
|
||||
''' creates the import job entry and checks csv '''
|
||||
import_job = self.importer.create_job(
|
||||
self.user, self.csv, False, 'public')
|
||||
""" creates the import job entry and checks csv """
|
||||
import_job = self.importer.create_job(self.user, self.csv, False, "public")
|
||||
self.assertEqual(import_job.user, self.user)
|
||||
self.assertEqual(import_job.include_reviews, False)
|
||||
self.assertEqual(import_job.privacy, 'public')
|
||||
self.assertEqual(import_job.privacy, "public")
|
||||
|
||||
import_items = models.ImportItem.objects.filter(job=import_job).all()
|
||||
self.assertEqual(len(import_items), 3)
|
||||
self.assertEqual(import_items[0].index, 0)
|
||||
self.assertEqual(import_items[0].data['Book Id'], '42036538')
|
||||
self.assertEqual(import_items[0].data["Book Id"], "42036538")
|
||||
self.assertEqual(import_items[1].index, 1)
|
||||
self.assertEqual(import_items[1].data['Book Id'], '52691223')
|
||||
self.assertEqual(import_items[1].data["Book Id"], "52691223")
|
||||
self.assertEqual(import_items[2].index, 2)
|
||||
self.assertEqual(import_items[2].data['Book Id'], '28694510')
|
||||
|
||||
self.assertEqual(import_items[2].data["Book Id"], "28694510")
|
||||
|
||||
def test_create_retry_job(self):
|
||||
''' trying again with items that didn't import '''
|
||||
import_job = self.importer.create_job(
|
||||
self.user, self.csv, False, 'unlisted')
|
||||
import_items = models.ImportItem.objects.filter(
|
||||
job=import_job
|
||||
).all()[:2]
|
||||
""" trying again with items that didn't import """
|
||||
import_job = self.importer.create_job(self.user, self.csv, False, "unlisted")
|
||||
import_items = models.ImportItem.objects.filter(job=import_job).all()[:2]
|
||||
|
||||
retry = self.importer.create_retry_job(
|
||||
self.user, import_job, import_items)
|
||||
retry = self.importer.create_retry_job(self.user, import_job, import_items)
|
||||
self.assertNotEqual(import_job, retry)
|
||||
self.assertEqual(retry.user, self.user)
|
||||
self.assertEqual(retry.include_reviews, False)
|
||||
self.assertEqual(retry.privacy, 'unlisted')
|
||||
self.assertEqual(retry.privacy, "unlisted")
|
||||
|
||||
retry_items = models.ImportItem.objects.filter(job=retry).all()
|
||||
self.assertEqual(len(retry_items), 2)
|
||||
self.assertEqual(retry_items[0].index, 0)
|
||||
self.assertEqual(retry_items[0].data['Book Id'], '42036538')
|
||||
self.assertEqual(retry_items[0].data["Book Id"], "42036538")
|
||||
self.assertEqual(retry_items[1].index, 1)
|
||||
self.assertEqual(retry_items[1].data['Book Id'], '52691223')
|
||||
|
||||
self.assertEqual(retry_items[1].data["Book Id"], "52691223")
|
||||
|
||||
def test_start_import(self):
|
||||
''' begin loading books '''
|
||||
import_job = self.importer.create_job(
|
||||
self.user, self.csv, False, 'unlisted')
|
||||
MockTask = namedtuple('Task', ('id'))
|
||||
""" begin loading books """
|
||||
import_job = self.importer.create_job(self.user, self.csv, False, "unlisted")
|
||||
MockTask = namedtuple("Task", ("id"))
|
||||
mock_task = MockTask(7)
|
||||
with patch('bookwyrm.importer.import_data.delay') as start:
|
||||
with patch("bookwyrm.importer.import_data.delay") as start:
|
||||
start.return_value = mock_task
|
||||
self.importer.start_import(import_job)
|
||||
import_job.refresh_from_db()
|
||||
self.assertEqual(import_job.task_id, '7')
|
||||
|
||||
self.assertEqual(import_job.task_id, "7")
|
||||
|
||||
@responses.activate
|
||||
def test_import_data(self):
|
||||
''' resolve entry '''
|
||||
import_job = self.importer.create_job(
|
||||
self.user, self.csv, False, 'unlisted')
|
||||
book = models.Edition.objects.create(title='Test Book')
|
||||
""" resolve entry """
|
||||
import_job = self.importer.create_job(self.user, self.csv, False, "unlisted")
|
||||
book = models.Edition.objects.create(title="Test Book")
|
||||
|
||||
with patch(
|
||||
'bookwyrm.models.import_job.ImportItem.get_book_from_isbn'
|
||||
) as resolve:
|
||||
"bookwyrm.models.import_job.ImportItem.get_book_from_isbn"
|
||||
) as resolve:
|
||||
resolve.return_value = book
|
||||
with patch('bookwyrm.importer.handle_imported_book'):
|
||||
with patch("bookwyrm.importer.handle_imported_book"):
|
||||
importer.import_data(self.importer.service, import_job.id)
|
||||
|
||||
import_item = models.ImportItem.objects.get(job=import_job, index=0)
|
||||
self.assertEqual(import_item.book.id, book.id)
|
||||
|
||||
|
||||
def test_handle_imported_book(self):
|
||||
''' goodreads import added a book, this adds related connections '''
|
||||
shelf = self.user.shelf_set.filter(identifier='read').first()
|
||||
""" goodreads import added a book, this adds related connections """
|
||||
shelf = self.user.shelf_set.filter(identifier="read").first()
|
||||
self.assertIsNone(shelf.books.first())
|
||||
|
||||
import_job = models.ImportJob.objects.create(user=self.user)
|
||||
datafile = pathlib.Path(__file__).parent.joinpath('data/goodreads.csv')
|
||||
csv_file = open(datafile, 'r')
|
||||
datafile = pathlib.Path(__file__).parent.joinpath("data/goodreads.csv")
|
||||
csv_file = open(datafile, "r")
|
||||
for index, entry in enumerate(list(csv.DictReader(csv_file))):
|
||||
entry = self.importer.parse_fields(entry)
|
||||
import_item = models.ImportItem.objects.create(
|
||||
job_id=import_job.id, index=index, data=entry, book=self.book)
|
||||
job_id=import_job.id, index=index, data=entry, book=self.book
|
||||
)
|
||||
break
|
||||
|
||||
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
|
||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
|
||||
importer.handle_imported_book(
|
||||
self.importer.service, self.user, import_item, False, 'public')
|
||||
self.importer.service, self.user, import_item, False, "public"
|
||||
)
|
||||
|
||||
shelf.refresh_from_db()
|
||||
self.assertEqual(shelf.books.first(), self.book)
|
||||
@@ -145,31 +137,30 @@ class GoodreadsImport(TestCase):
|
||||
self.assertEqual(readthrough.finish_date.month, 10)
|
||||
self.assertEqual(readthrough.finish_date.day, 25)
|
||||
|
||||
|
||||
def test_handle_imported_book_already_shelved(self):
|
||||
''' goodreads import added a book, this adds related connections '''
|
||||
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
|
||||
shelf = self.user.shelf_set.filter(identifier='to-read').first()
|
||||
models.ShelfBook.objects.create(
|
||||
shelf=shelf, user=self.user, book=self.book)
|
||||
""" goodreads import added a book, this adds related connections """
|
||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
|
||||
shelf = self.user.shelf_set.filter(identifier="to-read").first()
|
||||
models.ShelfBook.objects.create(shelf=shelf, user=self.user, book=self.book)
|
||||
|
||||
import_job = models.ImportJob.objects.create(user=self.user)
|
||||
datafile = pathlib.Path(__file__).parent.joinpath('data/goodreads.csv')
|
||||
csv_file = open(datafile, 'r')
|
||||
datafile = pathlib.Path(__file__).parent.joinpath("data/goodreads.csv")
|
||||
csv_file = open(datafile, "r")
|
||||
for index, entry in enumerate(list(csv.DictReader(csv_file))):
|
||||
entry = self.importer.parse_fields(entry)
|
||||
import_item = models.ImportItem.objects.create(
|
||||
job_id=import_job.id, index=index, data=entry, book=self.book)
|
||||
job_id=import_job.id, index=index, data=entry, book=self.book
|
||||
)
|
||||
break
|
||||
|
||||
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
|
||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
|
||||
importer.handle_imported_book(
|
||||
self.importer.service, self.user, import_item, False, 'public')
|
||||
self.importer.service, self.user, import_item, False, "public"
|
||||
)
|
||||
|
||||
shelf.refresh_from_db()
|
||||
self.assertEqual(shelf.books.first(), self.book)
|
||||
self.assertIsNone(
|
||||
self.user.shelf_set.get(identifier='read').books.first())
|
||||
self.assertIsNone(self.user.shelf_set.get(identifier="read").books.first())
|
||||
readthrough = models.ReadThrough.objects.get(user=self.user)
|
||||
self.assertEqual(readthrough.book, self.book)
|
||||
self.assertEqual(readthrough.start_date.year, 2020)
|
||||
@@ -179,24 +170,26 @@ class GoodreadsImport(TestCase):
|
||||
self.assertEqual(readthrough.finish_date.month, 10)
|
||||
self.assertEqual(readthrough.finish_date.day, 25)
|
||||
|
||||
|
||||
def test_handle_import_twice(self):
|
||||
''' re-importing books '''
|
||||
shelf = self.user.shelf_set.filter(identifier='read').first()
|
||||
""" re-importing books """
|
||||
shelf = self.user.shelf_set.filter(identifier="read").first()
|
||||
import_job = models.ImportJob.objects.create(user=self.user)
|
||||
datafile = pathlib.Path(__file__).parent.joinpath('data/goodreads.csv')
|
||||
csv_file = open(datafile, 'r')
|
||||
datafile = pathlib.Path(__file__).parent.joinpath("data/goodreads.csv")
|
||||
csv_file = open(datafile, "r")
|
||||
for index, entry in enumerate(list(csv.DictReader(csv_file))):
|
||||
entry = self.importer.parse_fields(entry)
|
||||
import_item = models.ImportItem.objects.create(
|
||||
job_id=import_job.id, index=index, data=entry, book=self.book)
|
||||
job_id=import_job.id, index=index, data=entry, book=self.book
|
||||
)
|
||||
break
|
||||
|
||||
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
|
||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
|
||||
importer.handle_imported_book(
|
||||
self.importer.service, self.user, import_item, False, 'public')
|
||||
self.importer.service, self.user, import_item, False, "public"
|
||||
)
|
||||
importer.handle_imported_book(
|
||||
self.importer.service, self.user, import_item, False, 'public')
|
||||
self.importer.service, self.user, import_item, False, "public"
|
||||
)
|
||||
|
||||
shelf.refresh_from_db()
|
||||
self.assertEqual(shelf.books.first(), self.book)
|
||||
@@ -211,42 +204,44 @@ class GoodreadsImport(TestCase):
|
||||
self.assertEqual(readthrough.finish_date.month, 10)
|
||||
self.assertEqual(readthrough.finish_date.day, 25)
|
||||
|
||||
|
||||
def test_handle_imported_book_review(self):
|
||||
''' goodreads review import '''
|
||||
""" goodreads review import """
|
||||
import_job = models.ImportJob.objects.create(user=self.user)
|
||||
datafile = pathlib.Path(__file__).parent.joinpath('data/goodreads.csv')
|
||||
csv_file = open(datafile, 'r')
|
||||
datafile = pathlib.Path(__file__).parent.joinpath("data/goodreads.csv")
|
||||
csv_file = open(datafile, "r")
|
||||
entry = list(csv.DictReader(csv_file))[2]
|
||||
entry = self.importer.parse_fields(entry)
|
||||
import_item = models.ImportItem.objects.create(
|
||||
job_id=import_job.id, index=0, data=entry, book=self.book)
|
||||
job_id=import_job.id, index=0, data=entry, book=self.book
|
||||
)
|
||||
|
||||
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
|
||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
|
||||
importer.handle_imported_book(
|
||||
self.importer.service, self.user, import_item, True, 'unlisted')
|
||||
self.importer.service, self.user, import_item, True, "unlisted"
|
||||
)
|
||||
review = models.Review.objects.get(book=self.book, user=self.user)
|
||||
self.assertEqual(review.content, 'mixed feelings')
|
||||
self.assertEqual(review.content, "mixed feelings")
|
||||
self.assertEqual(review.rating, 2)
|
||||
self.assertEqual(review.published_date.year, 2019)
|
||||
self.assertEqual(review.published_date.month, 7)
|
||||
self.assertEqual(review.published_date.day, 8)
|
||||
self.assertEqual(review.privacy, 'unlisted')
|
||||
|
||||
self.assertEqual(review.privacy, "unlisted")
|
||||
|
||||
def test_handle_imported_book_reviews_disabled(self):
|
||||
''' goodreads review import '''
|
||||
""" goodreads review import """
|
||||
import_job = models.ImportJob.objects.create(user=self.user)
|
||||
datafile = pathlib.Path(__file__).parent.joinpath('data/goodreads.csv')
|
||||
csv_file = open(datafile, 'r')
|
||||
datafile = pathlib.Path(__file__).parent.joinpath("data/goodreads.csv")
|
||||
csv_file = open(datafile, "r")
|
||||
entry = list(csv.DictReader(csv_file))[2]
|
||||
entry = self.importer.parse_fields(entry)
|
||||
import_item = models.ImportItem.objects.create(
|
||||
job_id=import_job.id, index=0, data=entry, book=self.book)
|
||||
job_id=import_job.id, index=0, data=entry, book=self.book
|
||||
)
|
||||
|
||||
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
|
||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
|
||||
importer.handle_imported_book(
|
||||
self.importer.service, self.user, import_item, False, 'unlisted')
|
||||
self.assertFalse(models.Review.objects.filter(
|
||||
book=self.book, user=self.user
|
||||
).exists())
|
||||
self.importer.service, self.user, import_item, False, "unlisted"
|
||||
)
|
||||
self.assertFalse(
|
||||
models.Review.objects.filter(book=self.book, user=self.user).exists()
|
||||
)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
''' testing import '''
|
||||
""" testing import """
|
||||
from collections import namedtuple
|
||||
import csv
|
||||
import pathlib
|
||||
@@ -11,114 +11,110 @@ from bookwyrm import models, importer
|
||||
from bookwyrm.librarything_import import LibrarythingImporter
|
||||
from bookwyrm.settings import DOMAIN
|
||||
|
||||
|
||||
class LibrarythingImport(TestCase):
|
||||
''' importing from librarything tsv '''
|
||||
""" importing from librarything tsv """
|
||||
|
||||
def setUp(self):
|
||||
self.importer = LibrarythingImporter()
|
||||
''' use a test tsv '''
|
||||
datafile = pathlib.Path(__file__).parent.joinpath(
|
||||
'data/librarything.tsv')
|
||||
""" use a test tsv """
|
||||
datafile = pathlib.Path(__file__).parent.joinpath("data/librarything.tsv")
|
||||
|
||||
# Librarything generates latin encoded exports...
|
||||
self.csv = open(datafile, 'r', encoding=self.importer.encoding)
|
||||
self.csv = open(datafile, "r", encoding=self.importer.encoding)
|
||||
self.user = models.User.objects.create_user(
|
||||
'mmai', 'mmai@mmai.mmai', 'password', local=True)
|
||||
"mmai", "mmai@mmai.mmai", "password", local=True
|
||||
)
|
||||
|
||||
models.Connector.objects.create(
|
||||
identifier=DOMAIN,
|
||||
name='Local',
|
||||
name="Local",
|
||||
local=True,
|
||||
connector_file='self_connector',
|
||||
base_url='https://%s' % DOMAIN,
|
||||
books_url='https://%s/book' % DOMAIN,
|
||||
covers_url='https://%s/images/covers' % DOMAIN,
|
||||
search_url='https://%s/search?q=' % DOMAIN,
|
||||
connector_file="self_connector",
|
||||
base_url="https://%s" % DOMAIN,
|
||||
books_url="https://%s/book" % DOMAIN,
|
||||
covers_url="https://%s/images/covers" % DOMAIN,
|
||||
search_url="https://%s/search?q=" % DOMAIN,
|
||||
priority=1,
|
||||
)
|
||||
work = models.Work.objects.create(title='Test Work')
|
||||
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
|
||||
title="Example Edition",
|
||||
remote_id="https://example.com/book/1",
|
||||
parent_work=work,
|
||||
)
|
||||
|
||||
|
||||
def test_create_job(self):
|
||||
''' creates the import job entry and checks csv '''
|
||||
import_job = self.importer.create_job(
|
||||
self.user, self.csv, False, 'public')
|
||||
""" creates the import job entry and checks csv """
|
||||
import_job = self.importer.create_job(self.user, self.csv, False, "public")
|
||||
self.assertEqual(import_job.user, self.user)
|
||||
self.assertEqual(import_job.include_reviews, False)
|
||||
self.assertEqual(import_job.privacy, 'public')
|
||||
self.assertEqual(import_job.privacy, "public")
|
||||
|
||||
import_items = models.ImportItem.objects.filter(job=import_job).all()
|
||||
self.assertEqual(len(import_items), 3)
|
||||
self.assertEqual(import_items[0].index, 0)
|
||||
self.assertEqual(import_items[0].data['Book Id'], '5498194')
|
||||
self.assertEqual(import_items[0].data["Book Id"], "5498194")
|
||||
self.assertEqual(import_items[1].index, 1)
|
||||
self.assertEqual(import_items[1].data['Book Id'], '5015319')
|
||||
self.assertEqual(import_items[1].data["Book Id"], "5015319")
|
||||
self.assertEqual(import_items[2].index, 2)
|
||||
self.assertEqual(import_items[2].data['Book Id'], '5015399')
|
||||
|
||||
self.assertEqual(import_items[2].data["Book Id"], "5015399")
|
||||
|
||||
def test_create_retry_job(self):
|
||||
''' trying again with items that didn't import '''
|
||||
import_job = self.importer.create_job(
|
||||
self.user, self.csv, False, 'unlisted')
|
||||
import_items = models.ImportItem.objects.filter(
|
||||
job=import_job
|
||||
).all()[:2]
|
||||
""" trying again with items that didn't import """
|
||||
import_job = self.importer.create_job(self.user, self.csv, False, "unlisted")
|
||||
import_items = models.ImportItem.objects.filter(job=import_job).all()[:2]
|
||||
|
||||
retry = self.importer.create_retry_job(
|
||||
self.user, import_job, import_items)
|
||||
retry = self.importer.create_retry_job(self.user, import_job, import_items)
|
||||
self.assertNotEqual(import_job, retry)
|
||||
self.assertEqual(retry.user, self.user)
|
||||
self.assertEqual(retry.include_reviews, False)
|
||||
self.assertEqual(retry.privacy, 'unlisted')
|
||||
self.assertEqual(retry.privacy, "unlisted")
|
||||
|
||||
retry_items = models.ImportItem.objects.filter(job=retry).all()
|
||||
self.assertEqual(len(retry_items), 2)
|
||||
self.assertEqual(retry_items[0].index, 0)
|
||||
self.assertEqual(import_items[0].data['Book Id'], '5498194')
|
||||
self.assertEqual(import_items[0].data["Book Id"], "5498194")
|
||||
self.assertEqual(retry_items[1].index, 1)
|
||||
self.assertEqual(retry_items[1].data['Book Id'], '5015319')
|
||||
|
||||
self.assertEqual(retry_items[1].data["Book Id"], "5015319")
|
||||
|
||||
@responses.activate
|
||||
def test_import_data(self):
|
||||
''' resolve entry '''
|
||||
import_job = self.importer.create_job(
|
||||
self.user, self.csv, False, 'unlisted')
|
||||
book = models.Edition.objects.create(title='Test Book')
|
||||
""" resolve entry """
|
||||
import_job = self.importer.create_job(self.user, self.csv, False, "unlisted")
|
||||
book = models.Edition.objects.create(title="Test Book")
|
||||
|
||||
with patch(
|
||||
'bookwyrm.models.import_job.ImportItem.get_book_from_isbn'
|
||||
) as resolve:
|
||||
"bookwyrm.models.import_job.ImportItem.get_book_from_isbn"
|
||||
) as resolve:
|
||||
resolve.return_value = book
|
||||
with patch('bookwyrm.importer.handle_imported_book'):
|
||||
with patch("bookwyrm.importer.handle_imported_book"):
|
||||
importer.import_data(self.importer.service, import_job.id)
|
||||
|
||||
import_item = models.ImportItem.objects.get(job=import_job, index=0)
|
||||
self.assertEqual(import_item.book.id, book.id)
|
||||
|
||||
|
||||
def test_handle_imported_book(self):
|
||||
''' librarything import added a book, this adds related connections '''
|
||||
shelf = self.user.shelf_set.filter(identifier='read').first()
|
||||
""" librarything import added a book, this adds related connections """
|
||||
shelf = self.user.shelf_set.filter(identifier="read").first()
|
||||
self.assertIsNone(shelf.books.first())
|
||||
|
||||
import_job = models.ImportJob.objects.create(user=self.user)
|
||||
datafile = pathlib.Path(__file__).parent.joinpath('data/librarything.tsv')
|
||||
csv_file = open(datafile, 'r', encoding=self.importer.encoding)
|
||||
for index, entry in enumerate(list(csv.DictReader(csv_file, delimiter=self.importer.delimiter))):
|
||||
datafile = pathlib.Path(__file__).parent.joinpath("data/librarything.tsv")
|
||||
csv_file = open(datafile, "r", encoding=self.importer.encoding)
|
||||
for index, entry in enumerate(
|
||||
list(csv.DictReader(csv_file, delimiter=self.importer.delimiter))
|
||||
):
|
||||
entry = self.importer.parse_fields(entry)
|
||||
import_item = models.ImportItem.objects.create(
|
||||
job_id=import_job.id, index=index, data=entry, book=self.book)
|
||||
job_id=import_job.id, index=index, data=entry, book=self.book
|
||||
)
|
||||
break
|
||||
|
||||
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
|
||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
|
||||
importer.handle_imported_book(
|
||||
self.importer.service, self.user, import_item, False, 'public')
|
||||
self.importer.service, self.user, import_item, False, "public"
|
||||
)
|
||||
|
||||
shelf.refresh_from_db()
|
||||
self.assertEqual(shelf.books.first(), self.book)
|
||||
@@ -133,31 +129,32 @@ class LibrarythingImport(TestCase):
|
||||
self.assertEqual(readthrough.finish_date.month, 5)
|
||||
self.assertEqual(readthrough.finish_date.day, 8)
|
||||
|
||||
|
||||
def test_handle_imported_book_already_shelved(self):
|
||||
''' librarything import added a book, this adds related connections '''
|
||||
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
|
||||
shelf = self.user.shelf_set.filter(identifier='to-read').first()
|
||||
models.ShelfBook.objects.create(
|
||||
shelf=shelf, user=self.user, book=self.book)
|
||||
""" librarything import added a book, this adds related connections """
|
||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
|
||||
shelf = self.user.shelf_set.filter(identifier="to-read").first()
|
||||
models.ShelfBook.objects.create(shelf=shelf, user=self.user, book=self.book)
|
||||
|
||||
import_job = models.ImportJob.objects.create(user=self.user)
|
||||
datafile = pathlib.Path(__file__).parent.joinpath('data/librarything.tsv')
|
||||
csv_file = open(datafile, 'r', encoding=self.importer.encoding)
|
||||
for index, entry in enumerate(list(csv.DictReader(csv_file, delimiter=self.importer.delimiter))):
|
||||
datafile = pathlib.Path(__file__).parent.joinpath("data/librarything.tsv")
|
||||
csv_file = open(datafile, "r", encoding=self.importer.encoding)
|
||||
for index, entry in enumerate(
|
||||
list(csv.DictReader(csv_file, delimiter=self.importer.delimiter))
|
||||
):
|
||||
entry = self.importer.parse_fields(entry)
|
||||
import_item = models.ImportItem.objects.create(
|
||||
job_id=import_job.id, index=index, data=entry, book=self.book)
|
||||
job_id=import_job.id, index=index, data=entry, book=self.book
|
||||
)
|
||||
break
|
||||
|
||||
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
|
||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
|
||||
importer.handle_imported_book(
|
||||
self.importer.service, self.user, import_item, False, 'public')
|
||||
self.importer.service, self.user, import_item, False, "public"
|
||||
)
|
||||
|
||||
shelf.refresh_from_db()
|
||||
self.assertEqual(shelf.books.first(), self.book)
|
||||
self.assertIsNone(
|
||||
self.user.shelf_set.get(identifier='read').books.first())
|
||||
self.assertIsNone(self.user.shelf_set.get(identifier="read").books.first())
|
||||
readthrough = models.ReadThrough.objects.get(user=self.user)
|
||||
self.assertEqual(readthrough.book, self.book)
|
||||
self.assertEqual(readthrough.start_date.year, 2007)
|
||||
@@ -167,24 +164,28 @@ class LibrarythingImport(TestCase):
|
||||
self.assertEqual(readthrough.finish_date.month, 5)
|
||||
self.assertEqual(readthrough.finish_date.day, 8)
|
||||
|
||||
|
||||
def test_handle_import_twice(self):
|
||||
''' re-importing books '''
|
||||
shelf = self.user.shelf_set.filter(identifier='read').first()
|
||||
""" re-importing books """
|
||||
shelf = self.user.shelf_set.filter(identifier="read").first()
|
||||
import_job = models.ImportJob.objects.create(user=self.user)
|
||||
datafile = pathlib.Path(__file__).parent.joinpath('data/librarything.tsv')
|
||||
csv_file = open(datafile, 'r', encoding=self.importer.encoding)
|
||||
for index, entry in enumerate(list(csv.DictReader(csv_file, delimiter=self.importer.delimiter))):
|
||||
datafile = pathlib.Path(__file__).parent.joinpath("data/librarything.tsv")
|
||||
csv_file = open(datafile, "r", encoding=self.importer.encoding)
|
||||
for index, entry in enumerate(
|
||||
list(csv.DictReader(csv_file, delimiter=self.importer.delimiter))
|
||||
):
|
||||
entry = self.importer.parse_fields(entry)
|
||||
import_item = models.ImportItem.objects.create(
|
||||
job_id=import_job.id, index=index, data=entry, book=self.book)
|
||||
job_id=import_job.id, index=index, data=entry, book=self.book
|
||||
)
|
||||
break
|
||||
|
||||
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
|
||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
|
||||
importer.handle_imported_book(
|
||||
self.importer.service, self.user, import_item, False, 'public')
|
||||
self.importer.service, self.user, import_item, False, "public"
|
||||
)
|
||||
importer.handle_imported_book(
|
||||
self.importer.service, self.user, import_item, False, 'public')
|
||||
self.importer.service, self.user, import_item, False, "public"
|
||||
)
|
||||
|
||||
shelf.refresh_from_db()
|
||||
self.assertEqual(shelf.books.first(), self.book)
|
||||
@@ -199,42 +200,44 @@ class LibrarythingImport(TestCase):
|
||||
self.assertEqual(readthrough.finish_date.month, 5)
|
||||
self.assertEqual(readthrough.finish_date.day, 8)
|
||||
|
||||
|
||||
def test_handle_imported_book_review(self):
|
||||
''' librarything review import '''
|
||||
""" librarything review import """
|
||||
import_job = models.ImportJob.objects.create(user=self.user)
|
||||
datafile = pathlib.Path(__file__).parent.joinpath('data/librarything.tsv')
|
||||
csv_file = open(datafile, 'r', encoding=self.importer.encoding)
|
||||
datafile = pathlib.Path(__file__).parent.joinpath("data/librarything.tsv")
|
||||
csv_file = open(datafile, "r", encoding=self.importer.encoding)
|
||||
entry = list(csv.DictReader(csv_file, delimiter=self.importer.delimiter))[0]
|
||||
entry = self.importer.parse_fields(entry)
|
||||
import_item = models.ImportItem.objects.create(
|
||||
job_id=import_job.id, index=0, data=entry, book=self.book)
|
||||
job_id=import_job.id, index=0, data=entry, book=self.book
|
||||
)
|
||||
|
||||
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
|
||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
|
||||
importer.handle_imported_book(
|
||||
self.importer.service, self.user, import_item, True, 'unlisted')
|
||||
self.importer.service, self.user, import_item, True, "unlisted"
|
||||
)
|
||||
review = models.Review.objects.get(book=self.book, user=self.user)
|
||||
self.assertEqual(review.content, 'chef d\'oeuvre')
|
||||
self.assertEqual(review.content, "chef d'oeuvre")
|
||||
self.assertEqual(review.rating, 5)
|
||||
self.assertEqual(review.published_date.year, 2007)
|
||||
self.assertEqual(review.published_date.month, 5)
|
||||
self.assertEqual(review.published_date.day, 8)
|
||||
self.assertEqual(review.privacy, 'unlisted')
|
||||
|
||||
self.assertEqual(review.privacy, "unlisted")
|
||||
|
||||
def test_handle_imported_book_reviews_disabled(self):
|
||||
''' librarything review import '''
|
||||
""" librarything review import """
|
||||
import_job = models.ImportJob.objects.create(user=self.user)
|
||||
datafile = pathlib.Path(__file__).parent.joinpath('data/librarything.tsv')
|
||||
csv_file = open(datafile, 'r', encoding=self.importer.encoding)
|
||||
datafile = pathlib.Path(__file__).parent.joinpath("data/librarything.tsv")
|
||||
csv_file = open(datafile, "r", encoding=self.importer.encoding)
|
||||
entry = list(csv.DictReader(csv_file, delimiter=self.importer.delimiter))[2]
|
||||
entry = self.importer.parse_fields(entry)
|
||||
import_item = models.ImportItem.objects.create(
|
||||
job_id=import_job.id, index=0, data=entry, book=self.book)
|
||||
job_id=import_job.id, index=0, data=entry, book=self.book
|
||||
)
|
||||
|
||||
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
|
||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
|
||||
importer.handle_imported_book(
|
||||
self.importer.service, self.user, import_item, False, 'unlisted')
|
||||
self.assertFalse(models.Review.objects.filter(
|
||||
book=self.book, user=self.user
|
||||
).exists())
|
||||
self.importer.service, self.user, import_item, False, "unlisted"
|
||||
)
|
||||
self.assertFalse(
|
||||
models.Review.objects.filter(book=self.book, user=self.user).exists()
|
||||
)
|
||||
|
||||
@@ -1,28 +1,30 @@
|
||||
''' make sure only valid html gets to the app '''
|
||||
""" make sure only valid html gets to the app """
|
||||
from django.test import TestCase
|
||||
|
||||
from bookwyrm.sanitize_html import InputHtmlParser
|
||||
|
||||
|
||||
class Sanitizer(TestCase):
|
||||
''' sanitizer tests '''
|
||||
""" sanitizer tests """
|
||||
|
||||
def test_no_html(self):
|
||||
''' just text '''
|
||||
input_text = 'no html '
|
||||
""" just text """
|
||||
input_text = "no html "
|
||||
parser = InputHtmlParser()
|
||||
parser.feed(input_text)
|
||||
output = parser.get_output()
|
||||
self.assertEqual(input_text, output)
|
||||
|
||||
def test_valid_html(self):
|
||||
''' leave the html untouched '''
|
||||
input_text = '<b>yes </b> <i>html</i>'
|
||||
""" leave the html untouched """
|
||||
input_text = "<b>yes </b> <i>html</i>"
|
||||
parser = InputHtmlParser()
|
||||
parser.feed(input_text)
|
||||
output = parser.get_output()
|
||||
self.assertEqual(input_text, output)
|
||||
|
||||
def test_valid_html_attrs(self):
|
||||
''' and don't remove attributes '''
|
||||
""" and don't remove attributes """
|
||||
input_text = '<a href="fish.com">yes </a> <i>html</i>'
|
||||
parser = InputHtmlParser()
|
||||
parser.feed(input_text)
|
||||
@@ -30,23 +32,23 @@ class Sanitizer(TestCase):
|
||||
self.assertEqual(input_text, output)
|
||||
|
||||
def test_invalid_html(self):
|
||||
''' remove all html when the html is malformed '''
|
||||
input_text = '<b>yes <i>html</i>'
|
||||
""" remove all html when the html is malformed """
|
||||
input_text = "<b>yes <i>html</i>"
|
||||
parser = InputHtmlParser()
|
||||
parser.feed(input_text)
|
||||
output = parser.get_output()
|
||||
self.assertEqual('yes html', output)
|
||||
self.assertEqual("yes html", output)
|
||||
|
||||
input_text = 'yes <i></b>html </i>'
|
||||
input_text = "yes <i></b>html </i>"
|
||||
parser = InputHtmlParser()
|
||||
parser.feed(input_text)
|
||||
output = parser.get_output()
|
||||
self.assertEqual('yes html ', output)
|
||||
self.assertEqual("yes html ", output)
|
||||
|
||||
def test_disallowed_html(self):
|
||||
''' remove disallowed html but keep allowed html '''
|
||||
input_text = '<div> yes <i>html</i></div>'
|
||||
""" remove disallowed html but keep allowed html """
|
||||
input_text = "<div> yes <i>html</i></div>"
|
||||
parser = InputHtmlParser()
|
||||
parser.feed(input_text)
|
||||
output = parser.get_output()
|
||||
self.assertEqual(' yes <i>html</i>', output)
|
||||
self.assertEqual(" yes <i>html</i>", output)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
''' getting and verifying signatures '''
|
||||
""" getting and verifying signatures """
|
||||
import time
|
||||
from collections import namedtuple
|
||||
from urllib.parse import urlsplit
|
||||
@@ -18,141 +18,125 @@ from bookwyrm.activitypub import Follow
|
||||
from bookwyrm.settings import DOMAIN
|
||||
from bookwyrm.signatures import create_key_pair, make_signature, make_digest
|
||||
|
||||
|
||||
def get_follow_activity(follower, followee):
|
||||
''' generates a test activity '''
|
||||
""" generates a test activity """
|
||||
return Follow(
|
||||
id='https://test.com/user/follow/id',
|
||||
id="https://test.com/user/follow/id",
|
||||
actor=follower.remote_id,
|
||||
object=followee.remote_id,
|
||||
).serialize()
|
||||
|
||||
KeyPair = namedtuple('KeyPair', ('private_key', 'public_key'))
|
||||
Sender = namedtuple('Sender', ('remote_id', 'key_pair'))
|
||||
|
||||
KeyPair = namedtuple("KeyPair", ("private_key", "public_key"))
|
||||
Sender = namedtuple("Sender", ("remote_id", "key_pair"))
|
||||
|
||||
|
||||
class Signature(TestCase):
|
||||
''' signature test '''
|
||||
""" signature test """
|
||||
|
||||
def setUp(self):
|
||||
''' create users and test data '''
|
||||
""" create users and test data """
|
||||
self.mouse = models.User.objects.create_user(
|
||||
'mouse@%s' % DOMAIN, 'mouse@example.com', '',
|
||||
local=True, localname='mouse')
|
||||
"mouse@%s" % DOMAIN, "mouse@example.com", "", local=True, localname="mouse"
|
||||
)
|
||||
self.rat = models.User.objects.create_user(
|
||||
'rat@%s' % DOMAIN, 'rat@example.com', '',
|
||||
local=True, localname='rat')
|
||||
"rat@%s" % DOMAIN, "rat@example.com", "", local=True, localname="rat"
|
||||
)
|
||||
self.cat = models.User.objects.create_user(
|
||||
'cat@%s' % DOMAIN, 'cat@example.com', '',
|
||||
local=True, localname='cat')
|
||||
"cat@%s" % DOMAIN, "cat@example.com", "", local=True, localname="cat"
|
||||
)
|
||||
|
||||
private_key, public_key = create_key_pair()
|
||||
|
||||
self.fake_remote = Sender(
|
||||
'http://localhost/user/remote',
|
||||
KeyPair(private_key, public_key)
|
||||
"http://localhost/user/remote", KeyPair(private_key, public_key)
|
||||
)
|
||||
|
||||
models.SiteSettings.objects.create()
|
||||
|
||||
def send(self, signature, now, data, digest):
|
||||
''' test request '''
|
||||
""" test request """
|
||||
c = Client()
|
||||
return c.post(
|
||||
urlsplit(self.rat.inbox).path,
|
||||
data=data,
|
||||
content_type='application/json',
|
||||
content_type="application/json",
|
||||
**{
|
||||
'HTTP_DATE': now,
|
||||
'HTTP_SIGNATURE': signature,
|
||||
'HTTP_DIGEST': digest,
|
||||
'HTTP_CONTENT_TYPE': 'application/activity+json; charset=utf-8',
|
||||
'HTTP_HOST': DOMAIN,
|
||||
"HTTP_DATE": now,
|
||||
"HTTP_SIGNATURE": signature,
|
||||
"HTTP_DIGEST": digest,
|
||||
"HTTP_CONTENT_TYPE": "application/activity+json; charset=utf-8",
|
||||
"HTTP_HOST": DOMAIN,
|
||||
}
|
||||
)
|
||||
|
||||
def send_test_request(#pylint: disable=too-many-arguments
|
||||
self,
|
||||
sender,
|
||||
signer=None,
|
||||
send_data=None,
|
||||
digest=None,
|
||||
date=None):
|
||||
''' sends a follow request to the "rat" user '''
|
||||
def send_test_request( # pylint: disable=too-many-arguments
|
||||
self, sender, signer=None, send_data=None, digest=None, date=None
|
||||
):
|
||||
""" sends a follow request to the "rat" user """
|
||||
now = date or http_date()
|
||||
data = json.dumps(get_follow_activity(sender, self.rat))
|
||||
digest = digest or make_digest(data)
|
||||
signature = make_signature(
|
||||
signer or sender, self.rat.inbox, now, digest)
|
||||
with patch('bookwyrm.views.inbox.activity_task.delay'):
|
||||
with patch('bookwyrm.models.user.set_remote_server.delay'):
|
||||
signature = make_signature(signer or sender, self.rat.inbox, now, digest)
|
||||
with patch("bookwyrm.views.inbox.activity_task.delay"):
|
||||
with patch("bookwyrm.models.user.set_remote_server.delay"):
|
||||
return self.send(signature, now, send_data or data, digest)
|
||||
|
||||
def test_correct_signature(self):
|
||||
''' this one should just work '''
|
||||
""" this one should just work """
|
||||
response = self.send_test_request(sender=self.mouse)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
def test_wrong_signature(self):
|
||||
''' Messages must be signed by the right actor.
|
||||
(cat cannot sign messages on behalf of mouse) '''
|
||||
"""Messages must be signed by the right actor.
|
||||
(cat cannot sign messages on behalf of mouse)"""
|
||||
response = self.send_test_request(sender=self.mouse, signer=self.cat)
|
||||
self.assertEqual(response.status_code, 401)
|
||||
|
||||
@responses.activate
|
||||
def test_remote_signer(self):
|
||||
''' signtures for remote users '''
|
||||
datafile = pathlib.Path(__file__).parent.joinpath('data/ap_user.json')
|
||||
""" signtures for remote users """
|
||||
datafile = pathlib.Path(__file__).parent.joinpath("data/ap_user.json")
|
||||
data = json.loads(datafile.read_bytes())
|
||||
data['id'] = self.fake_remote.remote_id
|
||||
data['publicKey']['publicKeyPem'] = self.fake_remote.key_pair.public_key
|
||||
del data['icon'] # Avoid having to return an avatar.
|
||||
data["id"] = self.fake_remote.remote_id
|
||||
data["publicKey"]["publicKeyPem"] = self.fake_remote.key_pair.public_key
|
||||
del data["icon"] # Avoid having to return an avatar.
|
||||
responses.add(responses.GET, self.fake_remote.remote_id, json=data, status=200)
|
||||
responses.add(
|
||||
responses.GET, "https://localhost/.well-known/nodeinfo", status=404
|
||||
)
|
||||
responses.add(
|
||||
responses.GET,
|
||||
self.fake_remote.remote_id,
|
||||
json=data,
|
||||
status=200)
|
||||
responses.add(
|
||||
responses.GET,
|
||||
'https://localhost/.well-known/nodeinfo',
|
||||
status=404)
|
||||
responses.add(
|
||||
responses.GET,
|
||||
'https://example.com/user/mouse/outbox?page=true',
|
||||
json={'orderedItems': []},
|
||||
status=200
|
||||
"https://example.com/user/mouse/outbox?page=true",
|
||||
json={"orderedItems": []},
|
||||
status=200,
|
||||
)
|
||||
|
||||
with patch('bookwyrm.models.user.get_remote_reviews.delay'):
|
||||
with patch("bookwyrm.models.user.get_remote_reviews.delay"):
|
||||
response = self.send_test_request(sender=self.fake_remote)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
@responses.activate
|
||||
def test_key_needs_refresh(self):
|
||||
''' an out of date key should be updated and the new key work '''
|
||||
datafile = pathlib.Path(__file__).parent.joinpath('data/ap_user.json')
|
||||
""" an out of date key should be updated and the new key work """
|
||||
datafile = pathlib.Path(__file__).parent.joinpath("data/ap_user.json")
|
||||
data = json.loads(datafile.read_bytes())
|
||||
data['id'] = self.fake_remote.remote_id
|
||||
data['publicKey']['publicKeyPem'] = self.fake_remote.key_pair.public_key
|
||||
del data['icon'] # Avoid having to return an avatar.
|
||||
data["id"] = self.fake_remote.remote_id
|
||||
data["publicKey"]["publicKeyPem"] = self.fake_remote.key_pair.public_key
|
||||
del data["icon"] # Avoid having to return an avatar.
|
||||
responses.add(responses.GET, self.fake_remote.remote_id, json=data, status=200)
|
||||
responses.add(
|
||||
responses.GET,
|
||||
self.fake_remote.remote_id,
|
||||
json=data,
|
||||
status=200)
|
||||
responses.add(
|
||||
responses.GET,
|
||||
'https://localhost/.well-known/nodeinfo',
|
||||
status=404)
|
||||
responses.GET, "https://localhost/.well-known/nodeinfo", status=404
|
||||
)
|
||||
|
||||
# Second and subsequent fetches get a different key:
|
||||
key_pair = KeyPair(*create_key_pair())
|
||||
new_sender = Sender(self.fake_remote.remote_id, key_pair)
|
||||
data['publicKey']['publicKeyPem'] = key_pair.public_key
|
||||
responses.add(
|
||||
responses.GET,
|
||||
self.fake_remote.remote_id,
|
||||
json=data,
|
||||
status=200)
|
||||
data["publicKey"]["publicKeyPem"] = key_pair.public_key
|
||||
responses.add(responses.GET, self.fake_remote.remote_id, json=data, status=200)
|
||||
|
||||
with patch('bookwyrm.models.user.get_remote_reviews.delay'):
|
||||
with patch("bookwyrm.models.user.get_remote_reviews.delay"):
|
||||
# Key correct:
|
||||
response = self.send_test_request(sender=self.fake_remote)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
@@ -169,43 +153,42 @@ class Signature(TestCase):
|
||||
response = self.send_test_request(sender=self.fake_remote)
|
||||
self.assertEqual(response.status_code, 401)
|
||||
|
||||
|
||||
@responses.activate
|
||||
def test_nonexistent_signer(self):
|
||||
''' fail when unable to look up signer '''
|
||||
""" fail when unable to look up signer """
|
||||
responses.add(
|
||||
responses.GET,
|
||||
self.fake_remote.remote_id,
|
||||
json={'error': 'not found'},
|
||||
status=404)
|
||||
json={"error": "not found"},
|
||||
status=404,
|
||||
)
|
||||
|
||||
response = self.send_test_request(sender=self.fake_remote)
|
||||
self.assertEqual(response.status_code, 401)
|
||||
|
||||
@pytest.mark.integration
|
||||
def test_changed_data(self):
|
||||
'''Message data must match the digest header.'''
|
||||
with patch('bookwyrm.activitypub.resolve_remote_id'):
|
||||
"""Message data must match the digest header."""
|
||||
with patch("bookwyrm.activitypub.resolve_remote_id"):
|
||||
response = self.send_test_request(
|
||||
self.mouse,
|
||||
send_data=get_follow_activity(self.mouse, self.cat))
|
||||
self.mouse, send_data=get_follow_activity(self.mouse, self.cat)
|
||||
)
|
||||
self.assertEqual(response.status_code, 401)
|
||||
|
||||
@pytest.mark.integration
|
||||
def test_invalid_digest(self):
|
||||
''' signature digest must be valid '''
|
||||
with patch('bookwyrm.activitypub.resolve_remote_id'):
|
||||
""" signature digest must be valid """
|
||||
with patch("bookwyrm.activitypub.resolve_remote_id"):
|
||||
response = self.send_test_request(
|
||||
self.mouse,
|
||||
digest='SHA-256=AAAAAAAAAAAAAAAAAA')
|
||||
self.mouse, digest="SHA-256=AAAAAAAAAAAAAAAAAA"
|
||||
)
|
||||
self.assertEqual(response.status_code, 401)
|
||||
|
||||
@pytest.mark.integration
|
||||
def test_old_message(self):
|
||||
'''Old messages should be rejected to prevent replay attacks.'''
|
||||
with patch('bookwyrm.activitypub.resolve_remote_id'):
|
||||
"""Old messages should be rejected to prevent replay attacks."""
|
||||
with patch("bookwyrm.activitypub.resolve_remote_id"):
|
||||
response = self.send_test_request(
|
||||
self.mouse,
|
||||
date=http_date(time.time() - 301)
|
||||
self.mouse, date=http_date(time.time() - 301)
|
||||
)
|
||||
self.assertEqual(response.status_code, 401)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
''' style fixes and lookups for templates '''
|
||||
""" style fixes and lookups for templates """
|
||||
import re
|
||||
from unittest.mock import patch
|
||||
|
||||
@@ -11,82 +11,85 @@ from bookwyrm.templatetags import bookwyrm_tags
|
||||
|
||||
|
||||
class TemplateTags(TestCase):
|
||||
''' lotta different things here '''
|
||||
def setUp(self):
|
||||
''' create some filler objects '''
|
||||
self.user = models.User.objects.create_user(
|
||||
'mouse@example.com', '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', 'rat@rat.rat', 'ratword',
|
||||
remote_id='http://example.com/rat', local=False)
|
||||
self.book = models.Edition.objects.create(title='Test Book')
|
||||
""" lotta different things here """
|
||||
|
||||
def setUp(self):
|
||||
""" create some filler objects """
|
||||
self.user = models.User.objects.create_user(
|
||||
"mouse@example.com",
|
||||
"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",
|
||||
"rat@rat.rat",
|
||||
"ratword",
|
||||
remote_id="http://example.com/rat",
|
||||
local=False,
|
||||
)
|
||||
self.book = models.Edition.objects.create(title="Test Book")
|
||||
|
||||
def test_dict_key(self):
|
||||
''' just getting a value out of a dict '''
|
||||
test_dict = {'a': 1, 'b': 3}
|
||||
self.assertEqual(
|
||||
bookwyrm_tags.dict_key(test_dict, 'a'), 1)
|
||||
self.assertEqual(
|
||||
bookwyrm_tags.dict_key(test_dict, 'c'), 0)
|
||||
|
||||
""" just getting a value out of a dict """
|
||||
test_dict = {"a": 1, "b": 3}
|
||||
self.assertEqual(bookwyrm_tags.dict_key(test_dict, "a"), 1)
|
||||
self.assertEqual(bookwyrm_tags.dict_key(test_dict, "c"), 0)
|
||||
|
||||
def test_get_user_rating(self):
|
||||
''' get a user's most recent rating of a book '''
|
||||
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
|
||||
models.Review.objects.create(
|
||||
user=self.user, book=self.book, rating=3)
|
||||
self.assertEqual(
|
||||
bookwyrm_tags.get_user_rating(self.book, self.user), 3)
|
||||
|
||||
""" get a user's most recent rating of a book """
|
||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
|
||||
models.Review.objects.create(user=self.user, book=self.book, rating=3)
|
||||
self.assertEqual(bookwyrm_tags.get_user_rating(self.book, self.user), 3)
|
||||
|
||||
def test_get_user_rating_doesnt_exist(self):
|
||||
''' there is no rating available '''
|
||||
self.assertEqual(
|
||||
bookwyrm_tags.get_user_rating(self.book, self.user), 0)
|
||||
|
||||
""" there is no rating available """
|
||||
self.assertEqual(bookwyrm_tags.get_user_rating(self.book, self.user), 0)
|
||||
|
||||
def test_get_user_identifer_local(self):
|
||||
''' fall back to the simplest uid available '''
|
||||
""" fall back to the simplest uid available """
|
||||
self.assertNotEqual(self.user.username, self.user.localname)
|
||||
self.assertEqual(
|
||||
bookwyrm_tags.get_user_identifier(self.user), 'mouse')
|
||||
self.assertEqual(bookwyrm_tags.get_user_identifier(self.user), "mouse")
|
||||
|
||||
def test_get_user_identifer_remote(self):
|
||||
''' for a remote user, should be their full username '''
|
||||
""" for a remote user, should be their full username """
|
||||
self.assertEqual(
|
||||
bookwyrm_tags.get_user_identifier(self.remote_user),
|
||||
'rat@example.com')
|
||||
bookwyrm_tags.get_user_identifier(self.remote_user), "rat@example.com"
|
||||
)
|
||||
|
||||
def test_get_notification_count(self):
|
||||
''' just countin' '''
|
||||
""" just countin' """
|
||||
self.assertEqual(bookwyrm_tags.get_notification_count(self.user), 0)
|
||||
|
||||
models.Notification.objects.create(
|
||||
user=self.user, notification_type='FAVORITE')
|
||||
models.Notification.objects.create(
|
||||
user=self.user, notification_type='MENTION')
|
||||
models.Notification.objects.create(user=self.user, notification_type="FAVORITE")
|
||||
models.Notification.objects.create(user=self.user, notification_type="MENTION")
|
||||
|
||||
models.Notification.objects.create(
|
||||
user=self.remote_user, notification_type='FOLLOW')
|
||||
user=self.remote_user, notification_type="FOLLOW"
|
||||
)
|
||||
|
||||
self.assertEqual(bookwyrm_tags.get_notification_count(self.user), 2)
|
||||
|
||||
|
||||
def test_get_replies(self):
|
||||
''' direct replies to a status '''
|
||||
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
|
||||
""" direct replies to a status """
|
||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
|
||||
parent = models.Review.objects.create(
|
||||
user=self.user, book=self.book, content='hi')
|
||||
user=self.user, book=self.book, content="hi"
|
||||
)
|
||||
first_child = models.Status.objects.create(
|
||||
reply_parent=parent, user=self.user, content='hi')
|
||||
reply_parent=parent, user=self.user, content="hi"
|
||||
)
|
||||
second_child = models.Status.objects.create(
|
||||
reply_parent=parent, user=self.user, content='hi')
|
||||
reply_parent=parent, user=self.user, content="hi"
|
||||
)
|
||||
third_child = models.Status.objects.create(
|
||||
reply_parent=parent, user=self.user,
|
||||
deleted=True, deleted_date=timezone.now())
|
||||
reply_parent=parent,
|
||||
user=self.user,
|
||||
deleted=True,
|
||||
deleted_date=timezone.now(),
|
||||
)
|
||||
|
||||
replies = bookwyrm_tags.get_replies(parent)
|
||||
self.assertEqual(len(replies), 2)
|
||||
@@ -94,181 +97,162 @@ class TemplateTags(TestCase):
|
||||
self.assertTrue(second_child in replies)
|
||||
self.assertFalse(third_child in replies)
|
||||
|
||||
|
||||
def test_get_parent(self):
|
||||
''' get the reply parent of a status '''
|
||||
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
|
||||
""" get the reply parent of a status """
|
||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
|
||||
parent = models.Review.objects.create(
|
||||
user=self.user, book=self.book, content='hi')
|
||||
user=self.user, book=self.book, content="hi"
|
||||
)
|
||||
child = models.Status.objects.create(
|
||||
reply_parent=parent, user=self.user, content='hi')
|
||||
reply_parent=parent, user=self.user, content="hi"
|
||||
)
|
||||
|
||||
result = bookwyrm_tags.get_parent(child)
|
||||
self.assertEqual(result, parent)
|
||||
self.assertIsInstance(result, models.Review)
|
||||
|
||||
|
||||
def test_get_user_liked(self):
|
||||
''' did a user like a status '''
|
||||
status = models.Review.objects.create(
|
||||
user=self.remote_user, book=self.book)
|
||||
""" did a user like a status """
|
||||
status = models.Review.objects.create(user=self.remote_user, book=self.book)
|
||||
|
||||
self.assertFalse(bookwyrm_tags.get_user_liked(self.user, status))
|
||||
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
|
||||
models.Favorite.objects.create(
|
||||
user=self.user,
|
||||
status=status
|
||||
)
|
||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
|
||||
models.Favorite.objects.create(user=self.user, status=status)
|
||||
self.assertTrue(bookwyrm_tags.get_user_liked(self.user, status))
|
||||
|
||||
|
||||
def test_get_user_boosted(self):
|
||||
''' did a user boost a status '''
|
||||
status = models.Review.objects.create(
|
||||
user=self.remote_user, book=self.book)
|
||||
""" did a user boost a status """
|
||||
status = models.Review.objects.create(user=self.remote_user, book=self.book)
|
||||
|
||||
self.assertFalse(bookwyrm_tags.get_user_boosted(self.user, status))
|
||||
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
|
||||
models.Boost.objects.create(
|
||||
user=self.user,
|
||||
boosted_status=status
|
||||
)
|
||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
|
||||
models.Boost.objects.create(user=self.user, boosted_status=status)
|
||||
self.assertTrue(bookwyrm_tags.get_user_boosted(self.user, status))
|
||||
|
||||
|
||||
def test_follow_request_exists(self):
|
||||
''' does a user want to follow '''
|
||||
""" does a user want to follow """
|
||||
self.assertFalse(
|
||||
bookwyrm_tags.follow_request_exists(self.user, self.remote_user))
|
||||
bookwyrm_tags.follow_request_exists(self.user, self.remote_user)
|
||||
)
|
||||
|
||||
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
|
||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
|
||||
models.UserFollowRequest.objects.create(
|
||||
user_subject=self.user,
|
||||
user_object=self.remote_user)
|
||||
user_subject=self.user, user_object=self.remote_user
|
||||
)
|
||||
|
||||
self.assertFalse(
|
||||
bookwyrm_tags.follow_request_exists(self.user, self.remote_user))
|
||||
bookwyrm_tags.follow_request_exists(self.user, self.remote_user)
|
||||
)
|
||||
self.assertTrue(
|
||||
bookwyrm_tags.follow_request_exists(self.remote_user, self.user))
|
||||
|
||||
bookwyrm_tags.follow_request_exists(self.remote_user, self.user)
|
||||
)
|
||||
|
||||
def test_get_boosted(self):
|
||||
''' load a boosted status '''
|
||||
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
|
||||
status = models.Review.objects.create(
|
||||
user=self.remote_user, book=self.book)
|
||||
boost = models.Boost.objects.create(
|
||||
user=self.user,
|
||||
boosted_status=status
|
||||
)
|
||||
""" load a boosted status """
|
||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
|
||||
status = models.Review.objects.create(user=self.remote_user, book=self.book)
|
||||
boost = models.Boost.objects.create(user=self.user, boosted_status=status)
|
||||
boosted = bookwyrm_tags.get_boosted(boost)
|
||||
self.assertIsInstance(boosted, models.Review)
|
||||
self.assertEqual(boosted, status)
|
||||
|
||||
|
||||
def test_get_book_description(self):
|
||||
''' grab it from the edition or the parent '''
|
||||
work = models.Work.objects.create(title='Test Work')
|
||||
""" grab it from the edition or the parent """
|
||||
work = models.Work.objects.create(title="Test Work")
|
||||
self.book.parent_work = work
|
||||
self.book.save()
|
||||
|
||||
self.assertIsNone(bookwyrm_tags.get_book_description(self.book))
|
||||
|
||||
work.description = 'hi'
|
||||
work.description = "hi"
|
||||
work.save()
|
||||
self.assertEqual(bookwyrm_tags.get_book_description(self.book), 'hi')
|
||||
self.assertEqual(bookwyrm_tags.get_book_description(self.book), "hi")
|
||||
|
||||
self.book.description = 'hello'
|
||||
self.book.description = "hello"
|
||||
self.book.save()
|
||||
self.assertEqual(bookwyrm_tags.get_book_description(self.book), 'hello')
|
||||
|
||||
self.assertEqual(bookwyrm_tags.get_book_description(self.book), "hello")
|
||||
|
||||
def test_get_uuid(self):
|
||||
''' uuid functionality '''
|
||||
uuid = bookwyrm_tags.get_uuid('hi')
|
||||
self.assertTrue(re.match(r'hi[A-Za-z0-9\-]', uuid))
|
||||
|
||||
""" uuid functionality """
|
||||
uuid = bookwyrm_tags.get_uuid("hi")
|
||||
self.assertTrue(re.match(r"hi[A-Za-z0-9\-]", uuid))
|
||||
|
||||
def test_time_since(self):
|
||||
''' ultraconcise timestamps '''
|
||||
self.assertEqual(bookwyrm_tags.time_since('bleh'), '')
|
||||
""" ultraconcise timestamps """
|
||||
self.assertEqual(bookwyrm_tags.time_since("bleh"), "")
|
||||
|
||||
now = timezone.now()
|
||||
self.assertEqual(bookwyrm_tags.time_since(now), '0s')
|
||||
self.assertEqual(bookwyrm_tags.time_since(now), "0s")
|
||||
|
||||
seconds_ago = now - relativedelta(seconds=4)
|
||||
self.assertEqual(bookwyrm_tags.time_since(seconds_ago), '4s')
|
||||
self.assertEqual(bookwyrm_tags.time_since(seconds_ago), "4s")
|
||||
|
||||
minutes_ago = now - relativedelta(minutes=8)
|
||||
self.assertEqual(bookwyrm_tags.time_since(minutes_ago), '8m')
|
||||
self.assertEqual(bookwyrm_tags.time_since(minutes_ago), "8m")
|
||||
|
||||
hours_ago = now - relativedelta(hours=9)
|
||||
self.assertEqual(bookwyrm_tags.time_since(hours_ago), '9h')
|
||||
self.assertEqual(bookwyrm_tags.time_since(hours_ago), "9h")
|
||||
|
||||
days_ago = now - relativedelta(days=3)
|
||||
self.assertEqual(bookwyrm_tags.time_since(days_ago), '3d')
|
||||
self.assertEqual(bookwyrm_tags.time_since(days_ago), "3d")
|
||||
|
||||
# I am not going to figure out how to mock dates tonight.
|
||||
months_ago = now - relativedelta(months=5)
|
||||
self.assertTrue(re.match(
|
||||
r'[A-Z][a-z]{2} \d?\d',
|
||||
bookwyrm_tags.time_since(months_ago)
|
||||
))
|
||||
self.assertTrue(
|
||||
re.match(r"[A-Z][a-z]{2} \d?\d", bookwyrm_tags.time_since(months_ago))
|
||||
)
|
||||
|
||||
years_ago = now - relativedelta(years=10)
|
||||
self.assertTrue(re.match(
|
||||
r'[A-Z][a-z]{2} \d?\d \d{4}',
|
||||
bookwyrm_tags.time_since(years_ago)
|
||||
))
|
||||
|
||||
self.assertTrue(
|
||||
re.match(r"[A-Z][a-z]{2} \d?\d \d{4}", bookwyrm_tags.time_since(years_ago))
|
||||
)
|
||||
|
||||
def test_get_markdown(self):
|
||||
''' mardown format data '''
|
||||
result = bookwyrm_tags.get_markdown('_hi_')
|
||||
self.assertEqual(result, '<p><em>hi</em></p>')
|
||||
|
||||
result = bookwyrm_tags.get_markdown('<marquee>_hi_</marquee>')
|
||||
self.assertEqual(result, '<p><em>hi</em></p>')
|
||||
""" mardown format data """
|
||||
result = bookwyrm_tags.get_markdown("_hi_")
|
||||
self.assertEqual(result, "<p><em>hi</em></p>")
|
||||
|
||||
result = bookwyrm_tags.get_markdown("<marquee>_hi_</marquee>")
|
||||
self.assertEqual(result, "<p><em>hi</em></p>")
|
||||
|
||||
def test_get_mentions(self):
|
||||
''' list of people mentioned '''
|
||||
status = models.Status.objects.create(
|
||||
content='hi', user=self.remote_user)
|
||||
""" list of people mentioned """
|
||||
status = models.Status.objects.create(content="hi", user=self.remote_user)
|
||||
result = bookwyrm_tags.get_mentions(status, self.user)
|
||||
self.assertEqual(result, '@rat@example.com ')
|
||||
|
||||
self.assertEqual(result, "@rat@example.com ")
|
||||
|
||||
def test_get_status_preview_name(self):
|
||||
''' status context string '''
|
||||
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
|
||||
status = models.Status.objects.create(content='hi', user=self.user)
|
||||
""" status context string """
|
||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
|
||||
status = models.Status.objects.create(content="hi", user=self.user)
|
||||
result = bookwyrm_tags.get_status_preview_name(status)
|
||||
self.assertEqual(result, 'status')
|
||||
self.assertEqual(result, "status")
|
||||
|
||||
status = models.Review.objects.create(
|
||||
content='hi', user=self.user, book=self.book)
|
||||
content="hi", user=self.user, book=self.book
|
||||
)
|
||||
result = bookwyrm_tags.get_status_preview_name(status)
|
||||
self.assertEqual(result, 'review of <em>Test Book</em>')
|
||||
self.assertEqual(result, "review of <em>Test Book</em>")
|
||||
|
||||
status = models.Comment.objects.create(
|
||||
content='hi', user=self.user, book=self.book)
|
||||
content="hi", user=self.user, book=self.book
|
||||
)
|
||||
result = bookwyrm_tags.get_status_preview_name(status)
|
||||
self.assertEqual(result, 'comment on <em>Test Book</em>')
|
||||
self.assertEqual(result, "comment on <em>Test Book</em>")
|
||||
|
||||
status = models.Quotation.objects.create(
|
||||
content='hi', user=self.user, book=self.book)
|
||||
content="hi", user=self.user, book=self.book
|
||||
)
|
||||
result = bookwyrm_tags.get_status_preview_name(status)
|
||||
self.assertEqual(result, 'quotation from <em>Test Book</em>')
|
||||
|
||||
self.assertEqual(result, "quotation from <em>Test Book</em>")
|
||||
|
||||
def test_related_status(self):
|
||||
''' gets the subclass model for a notification status '''
|
||||
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
|
||||
status = models.Status.objects.create(content='hi', user=self.user)
|
||||
""" gets the subclass model for a notification status """
|
||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
|
||||
status = models.Status.objects.create(content="hi", user=self.user)
|
||||
notification = models.Notification.objects.create(
|
||||
user=self.user, notification_type='MENTION',
|
||||
related_status=status)
|
||||
user=self.user, notification_type="MENTION", related_status=status
|
||||
)
|
||||
|
||||
result = bookwyrm_tags.related_status(notification)
|
||||
self.assertIsInstance(result, models.Status)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
''' test for app action functionality '''
|
||||
""" test for app action functionality """
|
||||
from unittest.mock import patch
|
||||
|
||||
from django.contrib.auth.models import AnonymousUser
|
||||
@@ -14,21 +14,26 @@ from bookwyrm.settings import DOMAIN
|
||||
|
||||
# pylint: disable=too-many-public-methods
|
||||
class AuthenticationViews(TestCase):
|
||||
''' login and password management '''
|
||||
""" login and password management """
|
||||
|
||||
def setUp(self):
|
||||
''' we need basic test data and mocks '''
|
||||
""" we need basic test data and mocks """
|
||||
self.factory = RequestFactory()
|
||||
self.local_user = models.User.objects.create_user(
|
||||
'mouse@local.com', 'mouse@mouse.com', 'password',
|
||||
local=True, localname='mouse')
|
||||
"mouse@local.com",
|
||||
"mouse@mouse.com",
|
||||
"password",
|
||||
local=True,
|
||||
localname="mouse",
|
||||
)
|
||||
self.anonymous_user = AnonymousUser
|
||||
self.anonymous_user.is_authenticated = False
|
||||
self.settings = models.SiteSettings.objects.create(id=1)
|
||||
|
||||
def test_login_get(self):
|
||||
''' there are so many views, this just makes sure it LOADS '''
|
||||
""" there are so many views, this just makes sure it LOADS """
|
||||
login = views.Login.as_view()
|
||||
request = self.factory.get('')
|
||||
request = self.factory.get("")
|
||||
request.user = self.anonymous_user
|
||||
|
||||
result = login(request)
|
||||
@@ -38,135 +43,117 @@ class AuthenticationViews(TestCase):
|
||||
|
||||
request.user = self.local_user
|
||||
result = login(request)
|
||||
self.assertEqual(result.url, '/')
|
||||
self.assertEqual(result.url, "/")
|
||||
self.assertEqual(result.status_code, 302)
|
||||
|
||||
|
||||
def test_register(self):
|
||||
''' create a user '''
|
||||
""" create a user """
|
||||
view = views.Register.as_view()
|
||||
self.assertEqual(models.User.objects.count(), 1)
|
||||
request = self.factory.post(
|
||||
'register/',
|
||||
"register/",
|
||||
{
|
||||
'localname': 'nutria-user.user_nutria',
|
||||
'password': 'mouseword',
|
||||
'email': 'aa@bb.cccc'
|
||||
})
|
||||
with patch('bookwyrm.views.authentication.login'):
|
||||
"localname": "nutria-user.user_nutria",
|
||||
"password": "mouseword",
|
||||
"email": "aa@bb.cccc",
|
||||
},
|
||||
)
|
||||
with patch("bookwyrm.views.authentication.login"):
|
||||
response = view(request)
|
||||
self.assertEqual(models.User.objects.count(), 2)
|
||||
self.assertEqual(response.status_code, 302)
|
||||
nutria = models.User.objects.last()
|
||||
self.assertEqual(nutria.username, 'nutria-user.user_nutria@%s' % DOMAIN)
|
||||
self.assertEqual(nutria.localname, 'nutria-user.user_nutria')
|
||||
self.assertEqual(nutria.username, "nutria-user.user_nutria@%s" % DOMAIN)
|
||||
self.assertEqual(nutria.localname, "nutria-user.user_nutria")
|
||||
self.assertEqual(nutria.local, True)
|
||||
|
||||
def test_register_trailing_space(self):
|
||||
''' django handles this so weirdly '''
|
||||
""" django handles this so weirdly """
|
||||
view = views.Register.as_view()
|
||||
request = self.factory.post(
|
||||
'register/',
|
||||
{
|
||||
'localname': 'nutria ',
|
||||
'password': 'mouseword',
|
||||
'email': 'aa@bb.ccc'
|
||||
})
|
||||
with patch('bookwyrm.views.authentication.login'):
|
||||
"register/",
|
||||
{"localname": "nutria ", "password": "mouseword", "email": "aa@bb.ccc"},
|
||||
)
|
||||
with patch("bookwyrm.views.authentication.login"):
|
||||
response = view(request)
|
||||
self.assertEqual(models.User.objects.count(), 2)
|
||||
self.assertEqual(response.status_code, 302)
|
||||
nutria = models.User.objects.last()
|
||||
self.assertEqual(nutria.username, 'nutria@%s' % DOMAIN)
|
||||
self.assertEqual(nutria.localname, 'nutria')
|
||||
self.assertEqual(nutria.username, "nutria@%s" % DOMAIN)
|
||||
self.assertEqual(nutria.localname, "nutria")
|
||||
self.assertEqual(nutria.local, True)
|
||||
|
||||
def test_register_invalid_email(self):
|
||||
''' gotta have an email '''
|
||||
""" gotta have an email """
|
||||
view = views.Register.as_view()
|
||||
self.assertEqual(models.User.objects.count(), 1)
|
||||
request = self.factory.post(
|
||||
'register/',
|
||||
{
|
||||
'localname': 'nutria',
|
||||
'password': 'mouseword',
|
||||
'email': 'aa'
|
||||
})
|
||||
"register/", {"localname": "nutria", "password": "mouseword", "email": "aa"}
|
||||
)
|
||||
response = view(request)
|
||||
self.assertEqual(models.User.objects.count(), 1)
|
||||
response.render()
|
||||
|
||||
def test_register_invalid_username(self):
|
||||
''' gotta have an email '''
|
||||
""" gotta have an email """
|
||||
view = views.Register.as_view()
|
||||
self.assertEqual(models.User.objects.count(), 1)
|
||||
request = self.factory.post(
|
||||
'register/',
|
||||
{
|
||||
'localname': 'nut@ria',
|
||||
'password': 'mouseword',
|
||||
'email': 'aa@bb.ccc'
|
||||
})
|
||||
"register/",
|
||||
{"localname": "nut@ria", "password": "mouseword", "email": "aa@bb.ccc"},
|
||||
)
|
||||
response = view(request)
|
||||
self.assertEqual(models.User.objects.count(), 1)
|
||||
response.render()
|
||||
|
||||
request = self.factory.post(
|
||||
'register/',
|
||||
{
|
||||
'localname': 'nutr ia',
|
||||
'password': 'mouseword',
|
||||
'email': 'aa@bb.ccc'
|
||||
})
|
||||
"register/",
|
||||
{"localname": "nutr ia", "password": "mouseword", "email": "aa@bb.ccc"},
|
||||
)
|
||||
response = view(request)
|
||||
self.assertEqual(models.User.objects.count(), 1)
|
||||
response.render()
|
||||
|
||||
request = self.factory.post(
|
||||
'register/',
|
||||
{
|
||||
'localname': 'nut@ria',
|
||||
'password': 'mouseword',
|
||||
'email': 'aa@bb.ccc'
|
||||
})
|
||||
"register/",
|
||||
{"localname": "nut@ria", "password": "mouseword", "email": "aa@bb.ccc"},
|
||||
)
|
||||
response = view(request)
|
||||
self.assertEqual(models.User.objects.count(), 1)
|
||||
response.render()
|
||||
|
||||
|
||||
def test_register_closed_instance(self):
|
||||
''' you can't just register '''
|
||||
""" you can't just register """
|
||||
view = views.Register.as_view()
|
||||
self.settings.allow_registration = False
|
||||
self.settings.save()
|
||||
request = self.factory.post(
|
||||
'register/',
|
||||
{
|
||||
'localname': 'nutria ',
|
||||
'password': 'mouseword',
|
||||
'email': 'aa@bb.ccc'
|
||||
})
|
||||
"register/",
|
||||
{"localname": "nutria ", "password": "mouseword", "email": "aa@bb.ccc"},
|
||||
)
|
||||
with self.assertRaises(PermissionDenied):
|
||||
view(request)
|
||||
|
||||
def test_register_invite(self):
|
||||
''' you can't just register '''
|
||||
""" you can't just register """
|
||||
view = views.Register.as_view()
|
||||
self.settings.allow_registration = False
|
||||
self.settings.save()
|
||||
models.SiteInvite.objects.create(
|
||||
code='testcode', user=self.local_user, use_limit=1)
|
||||
code="testcode", user=self.local_user, use_limit=1
|
||||
)
|
||||
self.assertEqual(models.SiteInvite.objects.get().times_used, 0)
|
||||
|
||||
request = self.factory.post(
|
||||
'register/',
|
||||
"register/",
|
||||
{
|
||||
'localname': 'nutria',
|
||||
'password': 'mouseword',
|
||||
'email': 'aa@bb.ccc',
|
||||
'invite_code': 'testcode'
|
||||
})
|
||||
with patch('bookwyrm.views.authentication.login'):
|
||||
"localname": "nutria",
|
||||
"password": "mouseword",
|
||||
"email": "aa@bb.ccc",
|
||||
"invite_code": "testcode",
|
||||
},
|
||||
)
|
||||
with patch("bookwyrm.views.authentication.login"):
|
||||
response = view(request)
|
||||
self.assertEqual(models.User.objects.count(), 2)
|
||||
self.assertEqual(response.status_code, 302)
|
||||
@@ -174,26 +161,28 @@ class AuthenticationViews(TestCase):
|
||||
|
||||
# invite already used to max capacity
|
||||
request = self.factory.post(
|
||||
'register/',
|
||||
"register/",
|
||||
{
|
||||
'localname': 'nutria2',
|
||||
'password': 'mouseword',
|
||||
'email': 'aa@bb.ccc',
|
||||
'invite_code': 'testcode'
|
||||
})
|
||||
"localname": "nutria2",
|
||||
"password": "mouseword",
|
||||
"email": "aa@bb.ccc",
|
||||
"invite_code": "testcode",
|
||||
},
|
||||
)
|
||||
with self.assertRaises(PermissionDenied):
|
||||
response = view(request)
|
||||
self.assertEqual(models.User.objects.count(), 2)
|
||||
|
||||
# bad invite code
|
||||
request = self.factory.post(
|
||||
'register/',
|
||||
"register/",
|
||||
{
|
||||
'localname': 'nutria3',
|
||||
'password': 'mouseword',
|
||||
'email': 'aa@bb.ccc',
|
||||
'invite_code': 'dkfkdjgdfkjgkdfj'
|
||||
})
|
||||
"localname": "nutria3",
|
||||
"password": "mouseword",
|
||||
"email": "aa@bb.ccc",
|
||||
"invite_code": "dkfkdjgdfkjgkdfj",
|
||||
},
|
||||
)
|
||||
with self.assertRaises(Http404):
|
||||
response = view(request)
|
||||
self.assertEqual(models.User.objects.count(), 2)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
''' test for app action functionality '''
|
||||
""" 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
|
||||
@@ -12,37 +12,41 @@ from bookwyrm.activitypub import ActivitypubResponse
|
||||
|
||||
|
||||
class AuthorViews(TestCase):
|
||||
''' author views'''
|
||||
""" author views"""
|
||||
|
||||
def setUp(self):
|
||||
''' we need basic test data and mocks '''
|
||||
""" 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',
|
||||
"mouse@local.com",
|
||||
"mouse@mouse.com",
|
||||
"mouseword",
|
||||
local=True,
|
||||
localname="mouse",
|
||||
remote_id="https://example.com/users/mouse",
|
||||
)
|
||||
self.group = Group.objects.create(name='editor')
|
||||
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
|
||||
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.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
|
||||
title="Example Edition",
|
||||
remote_id="https://example.com/book/1",
|
||||
parent_work=self.work,
|
||||
)
|
||||
models.SiteSettings.objects.create()
|
||||
|
||||
|
||||
def test_author_page(self):
|
||||
''' there are so many views, this just makes sure it LOADS '''
|
||||
""" there are so many views, this just makes sure it LOADS """
|
||||
view = views.Author.as_view()
|
||||
author = models.Author.objects.create(name='Jessica')
|
||||
request = self.factory.get('')
|
||||
with patch('bookwyrm.views.author.is_api_request') as is_api:
|
||||
author = models.Author.objects.create(name="Jessica")
|
||||
request = self.factory.get("")
|
||||
with patch("bookwyrm.views.author.is_api_request") as is_api:
|
||||
is_api.return_value = False
|
||||
result = view(request, author.id)
|
||||
self.assertIsInstance(result, TemplateResponse)
|
||||
@@ -50,19 +54,18 @@ class AuthorViews(TestCase):
|
||||
self.assertEqual(result.status_code, 200)
|
||||
self.assertEqual(result.status_code, 200)
|
||||
|
||||
request = self.factory.get('')
|
||||
with patch('bookwyrm.views.author.is_api_request') as is_api:
|
||||
request = self.factory.get("")
|
||||
with patch("bookwyrm.views.author.is_api_request") as is_api:
|
||||
is_api.return_value = True
|
||||
result = view(request, author.id)
|
||||
self.assertIsInstance(result, ActivitypubResponse)
|
||||
self.assertEqual(result.status_code, 200)
|
||||
|
||||
|
||||
def test_edit_author_page(self):
|
||||
''' there are so many views, this just makes sure it LOADS '''
|
||||
""" there are so many views, this just makes sure it LOADS """
|
||||
view = views.EditAuthor.as_view()
|
||||
author = models.Author.objects.create(name='Test Author')
|
||||
request = self.factory.get('')
|
||||
author = models.Author.objects.create(name="Test Author")
|
||||
request = self.factory.get("")
|
||||
request.user = self.local_user
|
||||
request.user.is_superuser = True
|
||||
|
||||
@@ -72,52 +75,51 @@ class AuthorViews(TestCase):
|
||||
self.assertEqual(result.status_code, 200)
|
||||
self.assertEqual(result.status_code, 200)
|
||||
|
||||
|
||||
def test_edit_author(self):
|
||||
''' edit an author '''
|
||||
""" edit an author """
|
||||
view = views.EditAuthor.as_view()
|
||||
author = models.Author.objects.create(name='Test Author')
|
||||
author = models.Author.objects.create(name="Test Author")
|
||||
self.local_user.groups.add(self.group)
|
||||
form = forms.AuthorForm(instance=author)
|
||||
form.data['name'] = 'New Name'
|
||||
form.data['last_edited_by'] = self.local_user.id
|
||||
request = self.factory.post('', form.data)
|
||||
form.data["name"] = "New Name"
|
||||
form.data["last_edited_by"] = self.local_user.id
|
||||
request = self.factory.post("", form.data)
|
||||
request.user = self.local_user
|
||||
|
||||
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
|
||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
|
||||
view(request, author.id)
|
||||
author.refresh_from_db()
|
||||
self.assertEqual(author.name, 'New Name')
|
||||
self.assertEqual(author.name, "New Name")
|
||||
self.assertEqual(author.last_edited_by, self.local_user)
|
||||
|
||||
def test_edit_author_non_editor(self):
|
||||
''' edit an author with invalid post data'''
|
||||
""" edit an author with invalid post data"""
|
||||
view = views.EditAuthor.as_view()
|
||||
author = models.Author.objects.create(name='Test Author')
|
||||
author = models.Author.objects.create(name="Test Author")
|
||||
form = forms.AuthorForm(instance=author)
|
||||
form.data['name'] = 'New Name'
|
||||
form.data['last_edited_by'] = self.local_user.id
|
||||
request = self.factory.post('', form.data)
|
||||
form.data["name"] = "New Name"
|
||||
form.data["last_edited_by"] = self.local_user.id
|
||||
request = self.factory.post("", form.data)
|
||||
request.user = self.local_user
|
||||
|
||||
with self.assertRaises(PermissionDenied):
|
||||
view(request, author.id)
|
||||
author.refresh_from_db()
|
||||
self.assertEqual(author.name, 'Test Author')
|
||||
self.assertEqual(author.name, "Test Author")
|
||||
|
||||
def test_edit_author_invalid_form(self):
|
||||
''' edit an author with invalid post data'''
|
||||
""" edit an author with invalid post data"""
|
||||
view = views.EditAuthor.as_view()
|
||||
author = models.Author.objects.create(name='Test Author')
|
||||
author = models.Author.objects.create(name="Test Author")
|
||||
self.local_user.groups.add(self.group)
|
||||
form = forms.AuthorForm(instance=author)
|
||||
form.data['name'] = ''
|
||||
form.data['last_edited_by'] = self.local_user.id
|
||||
request = self.factory.post('', form.data)
|
||||
form.data["name"] = ""
|
||||
form.data["last_edited_by"] = self.local_user.id
|
||||
request = self.factory.post("", form.data)
|
||||
request.user = self.local_user
|
||||
|
||||
resp = view(request, author.id)
|
||||
author.refresh_from_db()
|
||||
self.assertEqual(author.name, 'Test Author')
|
||||
self.assertEqual(author.name, "Test Author")
|
||||
resp.render()
|
||||
self.assertEqual(resp.status_code, 200)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
''' test for app action functionality '''
|
||||
""" test for app action functionality """
|
||||
from unittest.mock import patch
|
||||
from django.template.response import TemplateResponse
|
||||
from django.test import TestCase
|
||||
@@ -8,28 +8,34 @@ from bookwyrm import models, views
|
||||
|
||||
|
||||
class BlockViews(TestCase):
|
||||
''' view user and edit profile '''
|
||||
""" view user and edit profile """
|
||||
|
||||
def setUp(self):
|
||||
''' we need basic test data and mocks '''
|
||||
""" we need basic test data and mocks """
|
||||
self.factory = RequestFactory()
|
||||
self.local_user = models.User.objects.create_user(
|
||||
'mouse@local.com', 'mouse@mouse.mouse', 'password',
|
||||
local=True, localname='mouse')
|
||||
with patch('bookwyrm.models.user.set_remote_server.delay'):
|
||||
"mouse@local.com",
|
||||
"mouse@mouse.mouse",
|
||||
"password",
|
||||
local=True,
|
||||
localname="mouse",
|
||||
)
|
||||
with patch("bookwyrm.models.user.set_remote_server.delay"):
|
||||
self.remote_user = models.User.objects.create_user(
|
||||
'rat', 'rat@rat.com', 'ratword',
|
||||
"rat",
|
||||
"rat@rat.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',
|
||||
remote_id="https://example.com/users/rat",
|
||||
inbox="https://example.com/users/rat/inbox",
|
||||
outbox="https://example.com/users/rat/outbox",
|
||||
)
|
||||
models.SiteSettings.objects.create()
|
||||
|
||||
|
||||
def test_block_get(self):
|
||||
''' there are so many views, this just makes sure it LOADS '''
|
||||
""" there are so many views, this just makes sure it LOADS """
|
||||
view = views.Block.as_view()
|
||||
request = self.factory.get('')
|
||||
request = self.factory.get("")
|
||||
request.user = self.local_user
|
||||
result = view(request)
|
||||
self.assertIsInstance(result, TemplateResponse)
|
||||
@@ -37,19 +43,19 @@ class BlockViews(TestCase):
|
||||
self.assertEqual(result.status_code, 200)
|
||||
|
||||
def test_block_post(self):
|
||||
''' create a "block" database entry from an activity '''
|
||||
""" create a "block" database entry from an activity """
|
||||
view = views.Block.as_view()
|
||||
self.local_user.followers.add(self.remote_user)
|
||||
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
|
||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
|
||||
models.UserFollowRequest.objects.create(
|
||||
user_subject=self.local_user,
|
||||
user_object=self.remote_user)
|
||||
user_subject=self.local_user, user_object=self.remote_user
|
||||
)
|
||||
self.assertTrue(models.UserFollows.objects.exists())
|
||||
self.assertTrue(models.UserFollowRequest.objects.exists())
|
||||
|
||||
request = self.factory.post('')
|
||||
request = self.factory.post("")
|
||||
request.user = self.local_user
|
||||
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
|
||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
|
||||
view(request, self.remote_user.id)
|
||||
block = models.UserBlocks.objects.get()
|
||||
self.assertEqual(block.user_subject, self.local_user)
|
||||
@@ -59,12 +65,12 @@ class BlockViews(TestCase):
|
||||
self.assertFalse(models.UserFollowRequest.objects.exists())
|
||||
|
||||
def test_unblock(self):
|
||||
''' undo a block '''
|
||||
""" undo a block """
|
||||
self.local_user.blocks.add(self.remote_user)
|
||||
request = self.factory.post('')
|
||||
request = self.factory.post("")
|
||||
request.user = self.local_user
|
||||
|
||||
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
|
||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
|
||||
views.block.unblock(request, self.remote_user.id)
|
||||
|
||||
self.assertFalse(models.UserBlocks.objects.exists())
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
''' test for app action functionality '''
|
||||
""" 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
|
||||
@@ -11,55 +11,58 @@ from bookwyrm.activitypub import ActivitypubResponse
|
||||
|
||||
|
||||
class BookViews(TestCase):
|
||||
''' books books books '''
|
||||
""" books books books """
|
||||
|
||||
def setUp(self):
|
||||
''' we need basic test data and mocks '''
|
||||
""" 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',
|
||||
"mouse@local.com",
|
||||
"mouse@mouse.com",
|
||||
"mouseword",
|
||||
local=True,
|
||||
localname="mouse",
|
||||
remote_id="https://example.com/users/mouse",
|
||||
)
|
||||
self.group = Group.objects.create(name='editor')
|
||||
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
|
||||
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.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
|
||||
title="Example Edition",
|
||||
remote_id="https://example.com/book/1",
|
||||
parent_work=self.work,
|
||||
)
|
||||
models.SiteSettings.objects.create()
|
||||
|
||||
|
||||
def test_book_page(self):
|
||||
''' there are so many views, this just makes sure it LOADS '''
|
||||
""" there are so many views, this just makes sure it LOADS """
|
||||
view = views.Book.as_view()
|
||||
request = self.factory.get('')
|
||||
request = self.factory.get("")
|
||||
request.user = self.local_user
|
||||
with patch('bookwyrm.views.books.is_api_request') as is_api:
|
||||
with patch("bookwyrm.views.books.is_api_request") as is_api:
|
||||
is_api.return_value = False
|
||||
result = view(request, self.book.id)
|
||||
self.assertIsInstance(result, TemplateResponse)
|
||||
result.render()
|
||||
self.assertEqual(result.status_code, 200)
|
||||
|
||||
request = self.factory.get('')
|
||||
with patch('bookwyrm.views.books.is_api_request') as is_api:
|
||||
request = self.factory.get("")
|
||||
with patch("bookwyrm.views.books.is_api_request") as is_api:
|
||||
is_api.return_value = True
|
||||
result = view(request, self.book.id)
|
||||
self.assertIsInstance(result, ActivitypubResponse)
|
||||
self.assertEqual(result.status_code, 200)
|
||||
|
||||
|
||||
def test_edit_book_page(self):
|
||||
''' there are so many views, this just makes sure it LOADS '''
|
||||
""" there are so many views, this just makes sure it LOADS """
|
||||
view = views.EditBook.as_view()
|
||||
request = self.factory.get('')
|
||||
request = self.factory.get("")
|
||||
request.user = self.local_user
|
||||
request.user.is_superuser = True
|
||||
result = view(request, self.book.id)
|
||||
@@ -67,21 +70,19 @@ class BookViews(TestCase):
|
||||
result.render()
|
||||
self.assertEqual(result.status_code, 200)
|
||||
|
||||
|
||||
def test_edit_book(self):
|
||||
''' lets a user edit a book '''
|
||||
""" lets a user edit a book """
|
||||
view = views.EditBook.as_view()
|
||||
self.local_user.groups.add(self.group)
|
||||
form = forms.EditionForm(instance=self.book)
|
||||
form.data['title'] = 'New Title'
|
||||
form.data['last_edited_by'] = self.local_user.id
|
||||
request = self.factory.post('', form.data)
|
||||
form.data["title"] = "New Title"
|
||||
form.data["last_edited_by"] = self.local_user.id
|
||||
request = self.factory.post("", form.data)
|
||||
request.user = self.local_user
|
||||
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
|
||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
|
||||
view(request, self.book.id)
|
||||
self.book.refresh_from_db()
|
||||
self.assertEqual(self.book.title, 'New Title')
|
||||
|
||||
self.assertEqual(self.book.title, "New Title")
|
||||
|
||||
def test_edit_book_add_author(self):
|
||||
''' lets a user edit a book with new authors '''
|
||||
@@ -141,49 +142,42 @@ class BookViews(TestCase):
|
||||
|
||||
|
||||
def test_switch_edition(self):
|
||||
''' updates user's relationships to a book '''
|
||||
work = models.Work.objects.create(title='test work')
|
||||
edition1 = models.Edition.objects.create(
|
||||
title='first ed', parent_work=work)
|
||||
edition2 = models.Edition.objects.create(
|
||||
title='second ed', parent_work=work)
|
||||
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
|
||||
shelf = models.Shelf.objects.create(
|
||||
name='Test Shelf', user=self.local_user)
|
||||
""" updates user's relationships to a book """
|
||||
work = models.Work.objects.create(title="test work")
|
||||
edition1 = models.Edition.objects.create(title="first ed", parent_work=work)
|
||||
edition2 = models.Edition.objects.create(title="second ed", parent_work=work)
|
||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
|
||||
shelf = models.Shelf.objects.create(name="Test Shelf", user=self.local_user)
|
||||
models.ShelfBook.objects.create(
|
||||
book=edition1,
|
||||
user=self.local_user,
|
||||
shelf=shelf,
|
||||
)
|
||||
models.ReadThrough.objects.create(
|
||||
user=self.local_user, book=edition1)
|
||||
models.ReadThrough.objects.create(user=self.local_user, book=edition1)
|
||||
|
||||
self.assertEqual(models.ShelfBook.objects.get().book, edition1)
|
||||
self.assertEqual(models.ReadThrough.objects.get().book, edition1)
|
||||
request = self.factory.post('', {
|
||||
'edition': edition2.id
|
||||
})
|
||||
request = self.factory.post("", {"edition": edition2.id})
|
||||
request.user = self.local_user
|
||||
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
|
||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
|
||||
views.switch_edition(request)
|
||||
|
||||
self.assertEqual(models.ShelfBook.objects.get().book, edition2)
|
||||
self.assertEqual(models.ReadThrough.objects.get().book, edition2)
|
||||
|
||||
|
||||
def test_editions_page(self):
|
||||
''' there are so many views, this just makes sure it LOADS '''
|
||||
""" there are so many views, this just makes sure it LOADS """
|
||||
view = views.Editions.as_view()
|
||||
request = self.factory.get('')
|
||||
with patch('bookwyrm.views.books.is_api_request') as is_api:
|
||||
request = self.factory.get("")
|
||||
with patch("bookwyrm.views.books.is_api_request") as is_api:
|
||||
is_api.return_value = False
|
||||
result = view(request, self.work.id)
|
||||
self.assertIsInstance(result, TemplateResponse)
|
||||
result.render()
|
||||
self.assertEqual(result.status_code, 200)
|
||||
|
||||
request = self.factory.get('')
|
||||
with patch('bookwyrm.views.books.is_api_request') as is_api:
|
||||
request = self.factory.get("")
|
||||
with patch("bookwyrm.views.books.is_api_request") as is_api:
|
||||
is_api.return_value = True
|
||||
result = view(request, self.work.id)
|
||||
self.assertIsInstance(result, ActivitypubResponse)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
''' test for app action functionality '''
|
||||
""" test for app action functionality """
|
||||
from django.template.response import TemplateResponse
|
||||
from django.test import TestCase
|
||||
from django.test.client import RequestFactory
|
||||
@@ -8,20 +8,24 @@ from bookwyrm import views
|
||||
|
||||
|
||||
class FederationViews(TestCase):
|
||||
''' every response to a get request, html or json '''
|
||||
""" every response to a get request, html or json """
|
||||
|
||||
def setUp(self):
|
||||
''' we need basic test data and mocks '''
|
||||
""" we need basic test data and mocks """
|
||||
self.factory = RequestFactory()
|
||||
self.local_user = models.User.objects.create_user(
|
||||
'mouse@local.com', 'mouse@mouse.mouse', 'password',
|
||||
local=True, localname='mouse')
|
||||
"mouse@local.com",
|
||||
"mouse@mouse.mouse",
|
||||
"password",
|
||||
local=True,
|
||||
localname="mouse",
|
||||
)
|
||||
models.SiteSettings.objects.create()
|
||||
|
||||
|
||||
def test_federation_page(self):
|
||||
''' there are so many views, this just makes sure it LOADS '''
|
||||
""" there are so many views, this just makes sure it LOADS """
|
||||
view = views.Federation.as_view()
|
||||
request = self.factory.get('')
|
||||
request = self.factory.get("")
|
||||
request.user = self.local_user
|
||||
request.user.is_superuser = True
|
||||
result = view(request)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
''' test for app action functionality '''
|
||||
""" test for app action functionality """
|
||||
from unittest.mock import patch
|
||||
from django.template.response import TemplateResponse
|
||||
from django.test import TestCase
|
||||
@@ -10,95 +10,93 @@ from bookwyrm.activitypub import ActivitypubResponse
|
||||
|
||||
|
||||
class FeedMessageViews(TestCase):
|
||||
''' dms '''
|
||||
""" dms """
|
||||
|
||||
def setUp(self):
|
||||
''' we need basic test data and mocks '''
|
||||
""" we need basic test data and mocks """
|
||||
self.factory = RequestFactory()
|
||||
self.local_user = models.User.objects.create_user(
|
||||
'mouse@local.com', 'mouse@mouse.mouse', 'password',
|
||||
local=True, localname='mouse')
|
||||
"mouse@local.com",
|
||||
"mouse@mouse.mouse",
|
||||
"password",
|
||||
local=True,
|
||||
localname="mouse",
|
||||
)
|
||||
self.book = models.Edition.objects.create(
|
||||
parent_work=models.Work.objects.create(title='hi'),
|
||||
title='Example Edition',
|
||||
remote_id='https://example.com/book/1',
|
||||
parent_work=models.Work.objects.create(title="hi"),
|
||||
title="Example Edition",
|
||||
remote_id="https://example.com/book/1",
|
||||
)
|
||||
models.SiteSettings.objects.create()
|
||||
|
||||
|
||||
def test_feed(self):
|
||||
''' there are so many views, this just makes sure it LOADS '''
|
||||
""" there are so many views, this just makes sure it LOADS """
|
||||
view = views.Feed.as_view()
|
||||
request = self.factory.get('')
|
||||
request = self.factory.get("")
|
||||
request.user = self.local_user
|
||||
result = view(request, 'local')
|
||||
result = view(request, "local")
|
||||
self.assertIsInstance(result, TemplateResponse)
|
||||
result.render()
|
||||
self.assertEqual(result.status_code, 200)
|
||||
|
||||
|
||||
def test_status_page(self):
|
||||
''' there are so many views, this just makes sure it LOADS '''
|
||||
""" there are so many views, this just makes sure it LOADS """
|
||||
view = views.Status.as_view()
|
||||
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
|
||||
status = models.Status.objects.create(
|
||||
content='hi', user=self.local_user)
|
||||
request = self.factory.get('')
|
||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
|
||||
status = models.Status.objects.create(content="hi", user=self.local_user)
|
||||
request = self.factory.get("")
|
||||
request.user = self.local_user
|
||||
with patch('bookwyrm.views.feed.is_api_request') as is_api:
|
||||
with patch("bookwyrm.views.feed.is_api_request") as is_api:
|
||||
is_api.return_value = False
|
||||
result = view(request, 'mouse', status.id)
|
||||
result = view(request, "mouse", status.id)
|
||||
self.assertIsInstance(result, TemplateResponse)
|
||||
result.render()
|
||||
self.assertEqual(result.status_code, 200)
|
||||
|
||||
with patch('bookwyrm.views.feed.is_api_request') as is_api:
|
||||
with patch("bookwyrm.views.feed.is_api_request") as is_api:
|
||||
is_api.return_value = True
|
||||
result = view(request, 'mouse', status.id)
|
||||
result = view(request, "mouse", status.id)
|
||||
self.assertIsInstance(result, ActivitypubResponse)
|
||||
self.assertEqual(result.status_code, 200)
|
||||
|
||||
|
||||
def test_replies_page(self):
|
||||
''' there are so many views, this just makes sure it LOADS '''
|
||||
""" there are so many views, this just makes sure it LOADS """
|
||||
view = views.Replies.as_view()
|
||||
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
|
||||
status = models.Status.objects.create(
|
||||
content='hi', user=self.local_user)
|
||||
request = self.factory.get('')
|
||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
|
||||
status = models.Status.objects.create(content="hi", user=self.local_user)
|
||||
request = self.factory.get("")
|
||||
request.user = self.local_user
|
||||
with patch('bookwyrm.views.feed.is_api_request') as is_api:
|
||||
with patch("bookwyrm.views.feed.is_api_request") as is_api:
|
||||
is_api.return_value = False
|
||||
result = view(request, 'mouse', status.id)
|
||||
result = view(request, "mouse", status.id)
|
||||
self.assertIsInstance(result, TemplateResponse)
|
||||
result.render()
|
||||
self.assertEqual(result.status_code, 200)
|
||||
|
||||
with patch('bookwyrm.views.feed.is_api_request') as is_api:
|
||||
with patch("bookwyrm.views.feed.is_api_request") as is_api:
|
||||
is_api.return_value = True
|
||||
result = view(request, 'mouse', status.id)
|
||||
result = view(request, "mouse", status.id)
|
||||
self.assertIsInstance(result, ActivitypubResponse)
|
||||
self.assertEqual(result.status_code, 200)
|
||||
|
||||
|
||||
def test_direct_messages_page(self):
|
||||
''' there are so many views, this just makes sure it LOADS '''
|
||||
""" there are so many views, this just makes sure it LOADS """
|
||||
view = views.DirectMessage.as_view()
|
||||
request = self.factory.get('')
|
||||
request = self.factory.get("")
|
||||
request.user = self.local_user
|
||||
result = view(request)
|
||||
self.assertIsInstance(result, TemplateResponse)
|
||||
result.render()
|
||||
self.assertEqual(result.status_code, 200)
|
||||
|
||||
|
||||
def test_get_suggested_book(self):
|
||||
''' gets books the ~*~ algorithm ~*~ thinks you want to post about '''
|
||||
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
|
||||
""" gets books the ~*~ algorithm ~*~ thinks you want to post about """
|
||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
|
||||
models.ShelfBook.objects.create(
|
||||
book=self.book,
|
||||
user=self.local_user,
|
||||
shelf=self.local_user.shelf_set.get(identifier='reading')
|
||||
shelf=self.local_user.shelf_set.get(identifier="reading"),
|
||||
)
|
||||
suggestions = views.feed.get_suggested_books(self.local_user)
|
||||
self.assertEqual(suggestions[0]['name'], 'Currently Reading')
|
||||
self.assertEqual(suggestions[0]['books'][0], self.book)
|
||||
self.assertEqual(suggestions[0]["name"], "Currently Reading")
|
||||
self.assertEqual(suggestions[0]["books"][0], self.book)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
''' test for app action functionality '''
|
||||
""" 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
|
||||
@@ -9,148 +9,147 @@ from bookwyrm import models, views
|
||||
|
||||
|
||||
class BookViews(TestCase):
|
||||
''' books books books '''
|
||||
""" books books books """
|
||||
|
||||
def setUp(self):
|
||||
''' we need basic test data and mocks '''
|
||||
""" 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',
|
||||
"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'):
|
||||
with patch("bookwyrm.models.user.set_remote_server"):
|
||||
self.remote_user = models.User.objects.create_user(
|
||||
'rat', 'rat@email.com', 'ratword',
|
||||
"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',
|
||||
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 = 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
|
||||
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.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
|
||||
title="Example Edition",
|
||||
remote_id="https://example.com/book/1",
|
||||
parent_work=self.work,
|
||||
)
|
||||
|
||||
def test_handle_follow_remote(self):
|
||||
''' send a follow request '''
|
||||
request = self.factory.post('', {'user': self.remote_user.username})
|
||||
""" 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.models.activitypub_mixin.broadcast_task.delay'):
|
||||
with patch("bookwyrm.models.activitypub_mixin.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')
|
||||
|
||||
self.assertEqual(rel.status, "follow_request")
|
||||
|
||||
def test_handle_follow_local_manually_approves(self):
|
||||
''' send a follow request '''
|
||||
""" send a follow request """
|
||||
rat = models.User.objects.create_user(
|
||||
'rat@local.com', 'rat@rat.com', 'ratword',
|
||||
local=True, localname='rat',
|
||||
remote_id='https://example.com/users/rat',
|
||||
"rat@local.com",
|
||||
"rat@rat.com",
|
||||
"ratword",
|
||||
local=True,
|
||||
localname="rat",
|
||||
remote_id="https://example.com/users/rat",
|
||||
manually_approves_followers=True,
|
||||
)
|
||||
request = self.factory.post('', {'user': rat})
|
||||
request = self.factory.post("", {"user": rat})
|
||||
request.user = self.local_user
|
||||
self.assertEqual(models.UserFollowRequest.objects.count(), 0)
|
||||
|
||||
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
|
||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
|
||||
views.follow(request)
|
||||
rel = models.UserFollowRequest.objects.get()
|
||||
|
||||
self.assertEqual(rel.user_subject, self.local_user)
|
||||
self.assertEqual(rel.user_object, rat)
|
||||
self.assertEqual(rel.status, 'follow_request')
|
||||
|
||||
self.assertEqual(rel.status, "follow_request")
|
||||
|
||||
def test_handle_follow_local(self):
|
||||
''' send a follow request '''
|
||||
""" send a follow request """
|
||||
rat = models.User.objects.create_user(
|
||||
'rat@local.com', 'rat@rat.com', 'ratword',
|
||||
local=True, localname='rat',
|
||||
remote_id='https://example.com/users/rat',
|
||||
"rat@local.com",
|
||||
"rat@rat.com",
|
||||
"ratword",
|
||||
local=True,
|
||||
localname="rat",
|
||||
remote_id="https://example.com/users/rat",
|
||||
)
|
||||
request = self.factory.post('', {'user': rat})
|
||||
request = self.factory.post("", {"user": rat})
|
||||
request.user = self.local_user
|
||||
self.assertEqual(models.UserFollowRequest.objects.count(), 0)
|
||||
|
||||
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
|
||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
|
||||
views.follow(request)
|
||||
|
||||
rel = models.UserFollows.objects.get()
|
||||
|
||||
self.assertEqual(rel.user_subject, self.local_user)
|
||||
self.assertEqual(rel.user_object, rat)
|
||||
self.assertEqual(rel.status, 'follows')
|
||||
|
||||
self.assertEqual(rel.status, "follows")
|
||||
|
||||
def test_handle_unfollow(self):
|
||||
''' send an unfollow '''
|
||||
request = self.factory.post('', {'user': self.remote_user.username})
|
||||
""" 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.models.activitypub_mixin.broadcast_task.delay') \
|
||||
as mock:
|
||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay") as mock:
|
||||
views.unfollow(request)
|
||||
self.assertEqual(mock.call_count, 1)
|
||||
|
||||
self.assertEqual(self.remote_user.followers.count(), 0)
|
||||
|
||||
|
||||
def test_handle_accept(self):
|
||||
''' accept a follow request '''
|
||||
""" accept a follow request """
|
||||
self.local_user.manually_approves_followers = True
|
||||
self.local_user.save(broadcast=False)
|
||||
request = self.factory.post('', {'user': self.remote_user.username})
|
||||
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
|
||||
user_subject=self.remote_user, user_object=self.local_user
|
||||
)
|
||||
|
||||
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
|
||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
|
||||
views.accept_follow_request(request)
|
||||
# request should be deleted
|
||||
self.assertEqual(
|
||||
models.UserFollowRequest.objects.filter(id=rel.id).count(), 0
|
||||
)
|
||||
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 '''
|
||||
""" reject a follow request """
|
||||
self.local_user.manually_approves_followers = True
|
||||
self.local_user.save(broadcast=False)
|
||||
request = self.factory.post('', {'user': self.remote_user.username})
|
||||
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
|
||||
user_subject=self.remote_user, user_object=self.local_user
|
||||
)
|
||||
|
||||
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
|
||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
|
||||
views.delete_follow_request(request)
|
||||
# request should be deleted
|
||||
self.assertEqual(
|
||||
models.UserFollowRequest.objects.filter(id=rel.id).count(), 0
|
||||
)
|
||||
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
|
||||
)
|
||||
self.assertEqual(models.UserFollows.objects.filter(id=rel.id).count(), 0)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
''' test for app action functionality '''
|
||||
""" test for app action functionality """
|
||||
from unittest.mock import patch
|
||||
from django.utils import timezone
|
||||
|
||||
@@ -11,60 +11,65 @@ from bookwyrm import models, views
|
||||
|
||||
|
||||
class GoalViews(TestCase):
|
||||
''' viewing and creating statuses '''
|
||||
""" viewing and creating statuses """
|
||||
|
||||
def setUp(self):
|
||||
''' we need basic test data and mocks '''
|
||||
""" 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',
|
||||
"mouse@local.com",
|
||||
"mouse@mouse.com",
|
||||
"mouseword",
|
||||
local=True,
|
||||
localname="mouse",
|
||||
remote_id="https://example.com/users/mouse",
|
||||
)
|
||||
self.rat = models.User.objects.create_user(
|
||||
'rat@local.com', 'rat@rat.com', 'ratword',
|
||||
local=True, localname='rat',
|
||||
remote_id='https://example.com/users/rat',
|
||||
"rat@local.com",
|
||||
"rat@rat.com",
|
||||
"ratword",
|
||||
local=True,
|
||||
localname="rat",
|
||||
remote_id="https://example.com/users/rat",
|
||||
)
|
||||
self.book = models.Edition.objects.create(
|
||||
title='Example Edition',
|
||||
remote_id='https://example.com/book/1',
|
||||
title="Example Edition",
|
||||
remote_id="https://example.com/book/1",
|
||||
)
|
||||
self.anonymous_user = AnonymousUser
|
||||
self.anonymous_user.is_authenticated = False
|
||||
models.SiteSettings.objects.create()
|
||||
|
||||
|
||||
def test_goal_page_no_goal(self):
|
||||
''' view a reading goal page for another's unset goal '''
|
||||
""" view a reading goal page for another's unset goal """
|
||||
view = views.Goal.as_view()
|
||||
request = self.factory.get('')
|
||||
request = self.factory.get("")
|
||||
request.user = self.rat
|
||||
|
||||
result = view(request, self.local_user.localname, 2020)
|
||||
self.assertEqual(result.status_code, 404)
|
||||
|
||||
def test_goal_page_no_goal_self(self):
|
||||
''' view a reading goal page for your own unset goal '''
|
||||
""" view a reading goal page for your own unset goal """
|
||||
view = views.Goal.as_view()
|
||||
request = self.factory.get('')
|
||||
request = self.factory.get("")
|
||||
request.user = self.local_user
|
||||
|
||||
result = view(request, self.local_user.localname, 2020)
|
||||
result.render()
|
||||
self.assertIsInstance(result, TemplateResponse)
|
||||
|
||||
|
||||
def test_goal_page_anonymous(self):
|
||||
''' can't view it without login '''
|
||||
""" can't view it without login """
|
||||
view = views.Goal.as_view()
|
||||
request = self.factory.get('')
|
||||
request = self.factory.get("")
|
||||
request.user = self.anonymous_user
|
||||
|
||||
result = view(request, self.local_user.localname, 2020)
|
||||
self.assertEqual(result.status_code, 302)
|
||||
|
||||
def test_goal_page_public(self):
|
||||
''' view a user's public goal '''
|
||||
""" view a user's public goal """
|
||||
models.ReadThrough.objects.create(
|
||||
finish_date=timezone.now(),
|
||||
user=self.local_user,
|
||||
@@ -75,9 +80,10 @@ class GoalViews(TestCase):
|
||||
user=self.local_user,
|
||||
year=timezone.now().year,
|
||||
goal=128937123,
|
||||
privacy='public')
|
||||
privacy="public",
|
||||
)
|
||||
view = views.Goal.as_view()
|
||||
request = self.factory.get('')
|
||||
request = self.factory.get("")
|
||||
request.user = self.rat
|
||||
|
||||
result = view(request, self.local_user.localname, timezone.now().year)
|
||||
@@ -85,40 +91,40 @@ class GoalViews(TestCase):
|
||||
self.assertIsInstance(result, TemplateResponse)
|
||||
|
||||
def test_goal_page_private(self):
|
||||
''' view a user's private goal '''
|
||||
""" view a user's private goal """
|
||||
models.AnnualGoal.objects.create(
|
||||
user=self.local_user,
|
||||
year=2020,
|
||||
goal=15,
|
||||
privacy='followers')
|
||||
user=self.local_user, year=2020, goal=15, privacy="followers"
|
||||
)
|
||||
view = views.Goal.as_view()
|
||||
request = self.factory.get('')
|
||||
request = self.factory.get("")
|
||||
request.user = self.rat
|
||||
|
||||
result = view(request, self.local_user.localname, 2020)
|
||||
self.assertEqual(result.status_code, 404)
|
||||
|
||||
|
||||
def test_create_goal(self):
|
||||
''' create a new goal '''
|
||||
""" create a new goal """
|
||||
view = views.Goal.as_view()
|
||||
request = self.factory.post('', {
|
||||
'user': self.local_user.id,
|
||||
'goal': 10,
|
||||
'year': 2020,
|
||||
'privacy': 'unlisted',
|
||||
'post-status': True
|
||||
})
|
||||
request = self.factory.post(
|
||||
"",
|
||||
{
|
||||
"user": self.local_user.id,
|
||||
"goal": 10,
|
||||
"year": 2020,
|
||||
"privacy": "unlisted",
|
||||
"post-status": True,
|
||||
},
|
||||
)
|
||||
request.user = self.local_user
|
||||
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
|
||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
|
||||
view(request, self.local_user.localname, 2020)
|
||||
|
||||
goal = models.AnnualGoal.objects.get()
|
||||
self.assertEqual(goal.user, self.local_user)
|
||||
self.assertEqual(goal.goal, 10)
|
||||
self.assertEqual(goal.year, 2020)
|
||||
self.assertEqual(goal.privacy, 'unlisted')
|
||||
self.assertEqual(goal.privacy, "unlisted")
|
||||
|
||||
status = models.GeneratedNote.objects.get()
|
||||
self.assertEqual(status.user, self.local_user)
|
||||
self.assertEqual(status.privacy, 'unlisted')
|
||||
self.assertEqual(status.privacy, "unlisted")
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
''' test for app action functionality '''
|
||||
""" test for app action functionality """
|
||||
import json
|
||||
from unittest.mock import patch
|
||||
import pathlib
|
||||
@@ -9,127 +9,129 @@ import responses
|
||||
from bookwyrm import models, views
|
||||
from bookwyrm.settings import USER_AGENT
|
||||
|
||||
|
||||
class ViewsHelpers(TestCase):
|
||||
''' viewing and creating statuses '''
|
||||
""" viewing and creating statuses """
|
||||
|
||||
def setUp(self):
|
||||
''' we need basic test data and mocks '''
|
||||
""" 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',
|
||||
"mouse@local.com",
|
||||
"mouse@mouse.com",
|
||||
"mouseword",
|
||||
local=True,
|
||||
localname="mouse",
|
||||
remote_id="https://example.com/users/mouse",
|
||||
)
|
||||
self.work = models.Work.objects.create(title='Test Work')
|
||||
self.work = models.Work.objects.create(title="Test Work")
|
||||
self.book = models.Edition.objects.create(
|
||||
title='Test Book',
|
||||
remote_id='https://example.com/book/1',
|
||||
parent_work=self.work
|
||||
title="Test Book",
|
||||
remote_id="https://example.com/book/1",
|
||||
parent_work=self.work,
|
||||
)
|
||||
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(
|
||||
'rat', 'rat@rat.com', 'ratword',
|
||||
"rat",
|
||||
"rat@rat.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',
|
||||
remote_id="https://example.com/users/rat",
|
||||
inbox="https://example.com/users/rat/inbox",
|
||||
outbox="https://example.com/users/rat/outbox",
|
||||
)
|
||||
datafile = pathlib.Path(__file__).parent.joinpath(
|
||||
'../data/ap_user.json'
|
||||
)
|
||||
datafile = pathlib.Path(__file__).parent.joinpath("../data/ap_user.json")
|
||||
self.userdata = json.loads(datafile.read_bytes())
|
||||
del self.userdata['icon']
|
||||
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
|
||||
del self.userdata["icon"]
|
||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
|
||||
self.shelf = models.Shelf.objects.create(
|
||||
name='Test Shelf',
|
||||
identifier='test-shelf',
|
||||
user=self.local_user
|
||||
name="Test Shelf", identifier="test-shelf", user=self.local_user
|
||||
)
|
||||
|
||||
|
||||
def test_get_edition(self):
|
||||
''' given an edition or a work, returns an edition '''
|
||||
self.assertEqual(
|
||||
views.helpers.get_edition(self.book.id), self.book)
|
||||
self.assertEqual(
|
||||
views.helpers.get_edition(self.work.id), self.book)
|
||||
""" given an edition or a work, returns an edition """
|
||||
self.assertEqual(views.helpers.get_edition(self.book.id), self.book)
|
||||
self.assertEqual(views.helpers.get_edition(self.work.id), self.book)
|
||||
|
||||
def test_get_user_from_username(self):
|
||||
''' works for either localname or username '''
|
||||
""" works for either localname or username """
|
||||
self.assertEqual(
|
||||
views.helpers.get_user_from_username(
|
||||
self.local_user, 'mouse'), self.local_user)
|
||||
views.helpers.get_user_from_username(self.local_user, "mouse"),
|
||||
self.local_user,
|
||||
)
|
||||
self.assertEqual(
|
||||
views.helpers.get_user_from_username(
|
||||
self.local_user, 'mouse@local.com'), self.local_user)
|
||||
views.helpers.get_user_from_username(self.local_user, "mouse@local.com"),
|
||||
self.local_user,
|
||||
)
|
||||
with self.assertRaises(models.User.DoesNotExist):
|
||||
views.helpers.get_user_from_username(
|
||||
self.local_user, 'mojfse@example.com')
|
||||
|
||||
views.helpers.get_user_from_username(self.local_user, "mojfse@example.com")
|
||||
|
||||
def test_is_api_request(self):
|
||||
''' should it return html or json '''
|
||||
request = self.factory.get('/path')
|
||||
request.headers = {'Accept': 'application/json'}
|
||||
""" should it return html or json """
|
||||
request = self.factory.get("/path")
|
||||
request.headers = {"Accept": "application/json"}
|
||||
self.assertTrue(views.helpers.is_api_request(request))
|
||||
|
||||
request = self.factory.get('/path.json')
|
||||
request.headers = {'Accept': 'Praise'}
|
||||
request = self.factory.get("/path.json")
|
||||
request.headers = {"Accept": "Praise"}
|
||||
self.assertTrue(views.helpers.is_api_request(request))
|
||||
|
||||
request = self.factory.get('/path')
|
||||
request.headers = {'Accept': 'Praise'}
|
||||
request = self.factory.get("/path")
|
||||
request.headers = {"Accept": "Praise"}
|
||||
self.assertFalse(views.helpers.is_api_request(request))
|
||||
|
||||
|
||||
def test_get_activity_feed(self):
|
||||
''' loads statuses '''
|
||||
""" loads statuses """
|
||||
rat = models.User.objects.create_user(
|
||||
'rat', 'rat@rat.rat', 'password', local=True)
|
||||
"rat", "rat@rat.rat", "password", local=True
|
||||
)
|
||||
|
||||
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
|
||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
|
||||
public_status = models.Comment.objects.create(
|
||||
content='public status', book=self.book, user=self.local_user)
|
||||
content="public status", book=self.book, user=self.local_user
|
||||
)
|
||||
direct_status = models.Status.objects.create(
|
||||
content='direct', user=self.local_user, privacy='direct')
|
||||
content="direct", user=self.local_user, privacy="direct"
|
||||
)
|
||||
|
||||
rat_public = models.Status.objects.create(
|
||||
content='blah blah', user=rat)
|
||||
rat_public = models.Status.objects.create(content="blah blah", user=rat)
|
||||
rat_unlisted = models.Status.objects.create(
|
||||
content='blah blah', user=rat, privacy='unlisted')
|
||||
content="blah blah", user=rat, privacy="unlisted"
|
||||
)
|
||||
remote_status = models.Status.objects.create(
|
||||
content='blah blah', user=self.remote_user)
|
||||
content="blah blah", user=self.remote_user
|
||||
)
|
||||
followers_status = models.Status.objects.create(
|
||||
content='blah', user=rat, privacy='followers')
|
||||
content="blah", user=rat, privacy="followers"
|
||||
)
|
||||
rat_mention = models.Status.objects.create(
|
||||
content='blah blah blah', user=rat, privacy='followers')
|
||||
content="blah blah blah", user=rat, privacy="followers"
|
||||
)
|
||||
rat_mention.mention_users.set([self.local_user])
|
||||
|
||||
statuses = views.helpers.get_activity_feed(
|
||||
self.local_user,
|
||||
privacy=['public', 'unlisted', 'followers'],
|
||||
privacy=["public", "unlisted", "followers"],
|
||||
following_only=True,
|
||||
queryset=models.Comment.objects
|
||||
queryset=models.Comment.objects,
|
||||
)
|
||||
self.assertEqual(len(statuses), 1)
|
||||
self.assertEqual(statuses[0], public_status)
|
||||
|
||||
statuses = views.helpers.get_activity_feed(
|
||||
self.local_user,
|
||||
privacy=['public', 'followers'],
|
||||
local_only=True
|
||||
self.local_user, privacy=["public", "followers"], local_only=True
|
||||
)
|
||||
self.assertEqual(len(statuses), 2)
|
||||
self.assertEqual(statuses[1], public_status)
|
||||
self.assertEqual(statuses[0], rat_public)
|
||||
|
||||
statuses = views.helpers.get_activity_feed(
|
||||
self.local_user, privacy=['direct'])
|
||||
statuses = views.helpers.get_activity_feed(self.local_user, privacy=["direct"])
|
||||
self.assertEqual(len(statuses), 1)
|
||||
self.assertEqual(statuses[0], direct_status)
|
||||
|
||||
statuses = views.helpers.get_activity_feed(
|
||||
self.local_user,
|
||||
privacy=['public', 'followers'],
|
||||
privacy=["public", "followers"],
|
||||
)
|
||||
self.assertEqual(len(statuses), 3)
|
||||
self.assertEqual(statuses[2], public_status)
|
||||
@@ -138,8 +140,8 @@ class ViewsHelpers(TestCase):
|
||||
|
||||
statuses = views.helpers.get_activity_feed(
|
||||
self.local_user,
|
||||
privacy=['public', 'unlisted', 'followers'],
|
||||
following_only=True
|
||||
privacy=["public", "unlisted", "followers"],
|
||||
following_only=True,
|
||||
)
|
||||
self.assertEqual(len(statuses), 2)
|
||||
self.assertEqual(statuses[1], public_status)
|
||||
@@ -148,8 +150,8 @@ class ViewsHelpers(TestCase):
|
||||
rat.followers.add(self.local_user)
|
||||
statuses = views.helpers.get_activity_feed(
|
||||
self.local_user,
|
||||
privacy=['public', 'unlisted', 'followers'],
|
||||
following_only=True
|
||||
privacy=["public", "unlisted", "followers"],
|
||||
following_only=True,
|
||||
)
|
||||
self.assertEqual(len(statuses), 5)
|
||||
self.assertEqual(statuses[4], public_status)
|
||||
@@ -158,187 +160,187 @@ class ViewsHelpers(TestCase):
|
||||
self.assertEqual(statuses[1], followers_status)
|
||||
self.assertEqual(statuses[0], rat_mention)
|
||||
|
||||
|
||||
def test_get_activity_feed_blocks(self):
|
||||
''' feed generation with blocked users '''
|
||||
""" feed generation with blocked users """
|
||||
rat = models.User.objects.create_user(
|
||||
'rat', 'rat@rat.rat', 'password', local=True)
|
||||
"rat", "rat@rat.rat", "password", local=True
|
||||
)
|
||||
|
||||
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
|
||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
|
||||
public_status = models.Comment.objects.create(
|
||||
content='public status', book=self.book, user=self.local_user)
|
||||
rat_public = models.Status.objects.create(
|
||||
content='blah blah', user=rat)
|
||||
content="public status", book=self.book, user=self.local_user
|
||||
)
|
||||
rat_public = models.Status.objects.create(content="blah blah", user=rat)
|
||||
|
||||
statuses = views.helpers.get_activity_feed(
|
||||
self.local_user, privacy=['public'])
|
||||
self.local_user, privacy=["public"]
|
||||
)
|
||||
self.assertEqual(len(statuses), 2)
|
||||
|
||||
# block relationship
|
||||
rat.blocks.add(self.local_user)
|
||||
statuses = views.helpers.get_activity_feed(
|
||||
self.local_user, privacy=['public'])
|
||||
statuses = views.helpers.get_activity_feed(self.local_user, privacy=["public"])
|
||||
self.assertEqual(len(statuses), 1)
|
||||
self.assertEqual(statuses[0], public_status)
|
||||
|
||||
statuses = views.helpers.get_activity_feed(
|
||||
rat, privacy=['public'])
|
||||
statuses = views.helpers.get_activity_feed(rat, privacy=["public"])
|
||||
self.assertEqual(len(statuses), 1)
|
||||
self.assertEqual(statuses[0], rat_public)
|
||||
|
||||
|
||||
|
||||
def test_is_bookwyrm_request(self):
|
||||
''' checks if a request came from a bookwyrm instance '''
|
||||
request = self.factory.get('', {'q': 'Test Book'})
|
||||
""" checks if a request came from a bookwyrm instance """
|
||||
request = self.factory.get("", {"q": "Test Book"})
|
||||
self.assertFalse(views.helpers.is_bookwyrm_request(request))
|
||||
|
||||
request = self.factory.get(
|
||||
'', {'q': 'Test Book'},
|
||||
HTTP_USER_AGENT=\
|
||||
"http.rb/4.4.1 (Mastodon/3.3.0; +https://mastodon.social/)"
|
||||
"",
|
||||
{"q": "Test Book"},
|
||||
HTTP_USER_AGENT="http.rb/4.4.1 (Mastodon/3.3.0; +https://mastodon.social/)",
|
||||
)
|
||||
self.assertFalse(views.helpers.is_bookwyrm_request(request))
|
||||
|
||||
request = self.factory.get(
|
||||
'', {'q': 'Test Book'}, HTTP_USER_AGENT=USER_AGENT)
|
||||
request = self.factory.get("", {"q": "Test Book"}, HTTP_USER_AGENT=USER_AGENT)
|
||||
self.assertTrue(views.helpers.is_bookwyrm_request(request))
|
||||
|
||||
|
||||
def test_existing_user(self):
|
||||
''' simple database lookup by username '''
|
||||
result = views.helpers.handle_remote_webfinger('@mouse@local.com')
|
||||
""" simple database lookup by username """
|
||||
result = views.helpers.handle_remote_webfinger("@mouse@local.com")
|
||||
self.assertEqual(result, self.local_user)
|
||||
|
||||
result = views.helpers.handle_remote_webfinger('mouse@local.com')
|
||||
result = views.helpers.handle_remote_webfinger("mouse@local.com")
|
||||
self.assertEqual(result, self.local_user)
|
||||
|
||||
|
||||
@responses.activate
|
||||
def test_load_user(self):
|
||||
''' find a remote user using webfinger '''
|
||||
username = 'mouse@example.com'
|
||||
""" find a remote user using webfinger """
|
||||
username = "mouse@example.com"
|
||||
wellknown = {
|
||||
"subject": "acct:mouse@example.com",
|
||||
"links": [{
|
||||
"rel": "self",
|
||||
"type": "application/activity+json",
|
||||
"href": "https://example.com/user/mouse"
|
||||
}]
|
||||
"links": [
|
||||
{
|
||||
"rel": "self",
|
||||
"type": "application/activity+json",
|
||||
"href": "https://example.com/user/mouse",
|
||||
}
|
||||
],
|
||||
}
|
||||
responses.add(
|
||||
responses.GET,
|
||||
'https://example.com/.well-known/webfinger?resource=acct:%s' \
|
||||
% username,
|
||||
"https://example.com/.well-known/webfinger?resource=acct:%s" % username,
|
||||
json=wellknown,
|
||||
status=200)
|
||||
status=200,
|
||||
)
|
||||
responses.add(
|
||||
responses.GET,
|
||||
'https://example.com/user/mouse',
|
||||
"https://example.com/user/mouse",
|
||||
json=self.userdata,
|
||||
status=200)
|
||||
with patch('bookwyrm.models.user.set_remote_server.delay'):
|
||||
result = views.helpers.handle_remote_webfinger('@mouse@example.com')
|
||||
status=200,
|
||||
)
|
||||
with patch("bookwyrm.models.user.set_remote_server.delay"):
|
||||
result = views.helpers.handle_remote_webfinger("@mouse@example.com")
|
||||
self.assertIsInstance(result, models.User)
|
||||
self.assertEqual(result.username, 'mouse@example.com')
|
||||
|
||||
self.assertEqual(result.username, "mouse@example.com")
|
||||
|
||||
def test_handle_reading_status_to_read(self):
|
||||
''' posts shelve activities '''
|
||||
shelf = self.local_user.shelf_set.get(identifier='to-read')
|
||||
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
|
||||
""" posts shelve activities """
|
||||
shelf = self.local_user.shelf_set.get(identifier="to-read")
|
||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
|
||||
views.helpers.handle_reading_status(
|
||||
self.local_user, shelf, self.book, 'public')
|
||||
self.local_user, shelf, self.book, "public"
|
||||
)
|
||||
status = models.GeneratedNote.objects.get()
|
||||
self.assertEqual(status.user, self.local_user)
|
||||
self.assertEqual(status.mention_books.first(), self.book)
|
||||
self.assertEqual(status.content, 'wants to read')
|
||||
self.assertEqual(status.content, "wants to read")
|
||||
|
||||
def test_handle_reading_status_reading(self):
|
||||
''' posts shelve activities '''
|
||||
shelf = self.local_user.shelf_set.get(identifier='reading')
|
||||
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
|
||||
""" posts shelve activities """
|
||||
shelf = self.local_user.shelf_set.get(identifier="reading")
|
||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
|
||||
views.helpers.handle_reading_status(
|
||||
self.local_user, shelf, self.book, 'public')
|
||||
self.local_user, shelf, self.book, "public"
|
||||
)
|
||||
status = models.GeneratedNote.objects.get()
|
||||
self.assertEqual(status.user, self.local_user)
|
||||
self.assertEqual(status.mention_books.first(), self.book)
|
||||
self.assertEqual(status.content, 'started reading')
|
||||
self.assertEqual(status.content, "started reading")
|
||||
|
||||
def test_handle_reading_status_read(self):
|
||||
''' posts shelve activities '''
|
||||
shelf = self.local_user.shelf_set.get(identifier='read')
|
||||
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
|
||||
""" posts shelve activities """
|
||||
shelf = self.local_user.shelf_set.get(identifier="read")
|
||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
|
||||
views.helpers.handle_reading_status(
|
||||
self.local_user, shelf, self.book, 'public')
|
||||
self.local_user, shelf, self.book, "public"
|
||||
)
|
||||
status = models.GeneratedNote.objects.get()
|
||||
self.assertEqual(status.user, self.local_user)
|
||||
self.assertEqual(status.mention_books.first(), self.book)
|
||||
self.assertEqual(status.content, 'finished reading')
|
||||
self.assertEqual(status.content, "finished reading")
|
||||
|
||||
def test_handle_reading_status_other(self):
|
||||
''' posts shelve activities '''
|
||||
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
|
||||
""" posts shelve activities """
|
||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
|
||||
views.helpers.handle_reading_status(
|
||||
self.local_user, self.shelf, self.book, 'public')
|
||||
self.local_user, self.shelf, self.book, "public"
|
||||
)
|
||||
self.assertFalse(models.GeneratedNote.objects.exists())
|
||||
|
||||
def test_object_visible_to_user(self):
|
||||
''' does a user have permission to view an object '''
|
||||
""" does a user have permission to view an object """
|
||||
obj = models.Status.objects.create(
|
||||
content='hi', user=self.remote_user, privacy='public')
|
||||
self.assertTrue(
|
||||
views.helpers.object_visible_to_user(self.local_user, obj))
|
||||
content="hi", user=self.remote_user, privacy="public"
|
||||
)
|
||||
self.assertTrue(views.helpers.object_visible_to_user(self.local_user, obj))
|
||||
|
||||
obj = models.Shelf.objects.create(
|
||||
name='test', user=self.remote_user, privacy='unlisted')
|
||||
self.assertTrue(
|
||||
views.helpers.object_visible_to_user(self.local_user, obj))
|
||||
name="test", user=self.remote_user, privacy="unlisted"
|
||||
)
|
||||
self.assertTrue(views.helpers.object_visible_to_user(self.local_user, obj))
|
||||
|
||||
obj = models.Status.objects.create(
|
||||
content='hi', user=self.remote_user, privacy='followers')
|
||||
self.assertFalse(
|
||||
views.helpers.object_visible_to_user(self.local_user, obj))
|
||||
content="hi", user=self.remote_user, privacy="followers"
|
||||
)
|
||||
self.assertFalse(views.helpers.object_visible_to_user(self.local_user, obj))
|
||||
|
||||
obj = models.Status.objects.create(
|
||||
content='hi', user=self.remote_user, privacy='direct')
|
||||
self.assertFalse(
|
||||
views.helpers.object_visible_to_user(self.local_user, obj))
|
||||
content="hi", user=self.remote_user, privacy="direct"
|
||||
)
|
||||
self.assertFalse(views.helpers.object_visible_to_user(self.local_user, obj))
|
||||
|
||||
obj = models.Status.objects.create(
|
||||
content='hi', user=self.remote_user, privacy='direct')
|
||||
content="hi", user=self.remote_user, privacy="direct"
|
||||
)
|
||||
obj.mention_users.add(self.local_user)
|
||||
self.assertTrue(
|
||||
views.helpers.object_visible_to_user(self.local_user, obj))
|
||||
self.assertTrue(views.helpers.object_visible_to_user(self.local_user, obj))
|
||||
|
||||
def test_object_visible_to_user_follower(self):
|
||||
''' what you can see if you follow a user '''
|
||||
""" 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(
|
||||
views.helpers.object_visible_to_user(self.local_user, obj))
|
||||
content="hi", user=self.remote_user, privacy="followers"
|
||||
)
|
||||
self.assertTrue(views.helpers.object_visible_to_user(self.local_user, obj))
|
||||
|
||||
obj = models.Status.objects.create(
|
||||
content='hi', user=self.remote_user, privacy='direct')
|
||||
self.assertFalse(
|
||||
views.helpers.object_visible_to_user(self.local_user, obj))
|
||||
content="hi", user=self.remote_user, privacy="direct"
|
||||
)
|
||||
self.assertFalse(views.helpers.object_visible_to_user(self.local_user, obj))
|
||||
|
||||
obj = models.Status.objects.create(
|
||||
content='hi', user=self.remote_user, privacy='direct')
|
||||
content="hi", user=self.remote_user, privacy="direct"
|
||||
)
|
||||
obj.mention_users.add(self.local_user)
|
||||
self.assertTrue(
|
||||
views.helpers.object_visible_to_user(self.local_user, obj))
|
||||
self.assertTrue(views.helpers.object_visible_to_user(self.local_user, obj))
|
||||
|
||||
def test_object_visible_to_user_blocked(self):
|
||||
''' you can't see it if they block you '''
|
||||
""" 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(
|
||||
views.helpers.object_visible_to_user(self.local_user, obj))
|
||||
content="hi", user=self.remote_user, privacy="public"
|
||||
)
|
||||
self.assertFalse(views.helpers.object_visible_to_user(self.local_user, obj))
|
||||
|
||||
obj = models.Shelf.objects.create(
|
||||
name='test', user=self.remote_user, privacy='unlisted')
|
||||
self.assertFalse(
|
||||
views.helpers.object_visible_to_user(self.local_user, obj))
|
||||
name="test", user=self.remote_user, privacy="unlisted"
|
||||
)
|
||||
self.assertFalse(views.helpers.object_visible_to_user(self.local_user, obj))
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
''' test for app action functionality '''
|
||||
""" test for app action functionality """
|
||||
from unittest.mock import patch
|
||||
from django.template.response import TemplateResponse
|
||||
from django.test import TestCase
|
||||
@@ -9,34 +9,37 @@ from bookwyrm import views
|
||||
|
||||
|
||||
class ImportViews(TestCase):
|
||||
''' goodreads import views '''
|
||||
""" goodreads import views """
|
||||
|
||||
def setUp(self):
|
||||
''' we need basic test data and mocks '''
|
||||
""" we need basic test data and mocks """
|
||||
self.factory = RequestFactory()
|
||||
self.local_user = models.User.objects.create_user(
|
||||
'mouse@local.com', 'mouse@mouse.mouse', 'password',
|
||||
local=True, localname='mouse')
|
||||
"mouse@local.com",
|
||||
"mouse@mouse.mouse",
|
||||
"password",
|
||||
local=True,
|
||||
localname="mouse",
|
||||
)
|
||||
models.SiteSettings.objects.create()
|
||||
|
||||
|
||||
def test_import_page(self):
|
||||
''' there are so many views, this just makes sure it LOADS '''
|
||||
""" there are so many views, this just makes sure it LOADS """
|
||||
view = views.Import.as_view()
|
||||
request = self.factory.get('')
|
||||
request = self.factory.get("")
|
||||
request.user = self.local_user
|
||||
result = view(request)
|
||||
self.assertIsInstance(result, TemplateResponse)
|
||||
result.render()
|
||||
self.assertEqual(result.status_code, 200)
|
||||
|
||||
|
||||
def test_import_status(self):
|
||||
''' there are so many views, this just makes sure it LOADS '''
|
||||
""" there are so many views, this just makes sure it LOADS """
|
||||
view = views.ImportStatus.as_view()
|
||||
import_job = models.ImportJob.objects.create(user=self.local_user)
|
||||
request = self.factory.get('')
|
||||
request = self.factory.get("")
|
||||
request.user = self.local_user
|
||||
with patch('bookwyrm.tasks.app.AsyncResult') as async_result:
|
||||
with patch("bookwyrm.tasks.app.AsyncResult") as async_result:
|
||||
async_result.return_value = []
|
||||
result = view(request, import_job.id)
|
||||
self.assertIsInstance(result, TemplateResponse)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,4 @@
|
||||
''' test for app action functionality '''
|
||||
""" test for app action functionality """
|
||||
from unittest.mock import patch
|
||||
from django.test import TestCase
|
||||
from django.test.client import RequestFactory
|
||||
@@ -7,40 +7,44 @@ from bookwyrm import models, views
|
||||
|
||||
|
||||
class InteractionViews(TestCase):
|
||||
''' viewing and creating statuses '''
|
||||
""" viewing and creating statuses """
|
||||
|
||||
def setUp(self):
|
||||
''' we need basic test data and mocks '''
|
||||
""" 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',
|
||||
"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'):
|
||||
with patch("bookwyrm.models.user.set_remote_server"):
|
||||
self.remote_user = models.User.objects.create_user(
|
||||
'rat', 'rat@email.com', 'ratword',
|
||||
"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',
|
||||
remote_id="https://example.com/users/rat",
|
||||
inbox="https://example.com/users/rat/inbox",
|
||||
outbox="https://example.com/users/rat/outbox",
|
||||
)
|
||||
|
||||
work = models.Work.objects.create(title='Test Work')
|
||||
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
|
||||
title="Example Edition",
|
||||
remote_id="https://example.com/book/1",
|
||||
parent_work=work,
|
||||
)
|
||||
|
||||
|
||||
def test_handle_favorite(self):
|
||||
''' create and broadcast faving a status '''
|
||||
""" create and broadcast faving a status """
|
||||
view = views.Favorite.as_view()
|
||||
request = self.factory.post('')
|
||||
request = self.factory.post("")
|
||||
request.user = self.remote_user
|
||||
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
|
||||
status = models.Status.objects.create(
|
||||
user=self.local_user, content='hi')
|
||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
|
||||
status = models.Status.objects.create(user=self.local_user, content="hi")
|
||||
|
||||
view(request, status.id)
|
||||
fav = models.Favorite.objects.get()
|
||||
@@ -48,106 +52,100 @@ class InteractionViews(TestCase):
|
||||
self.assertEqual(fav.user, self.remote_user)
|
||||
|
||||
notification = models.Notification.objects.get()
|
||||
self.assertEqual(notification.notification_type, 'FAVORITE')
|
||||
self.assertEqual(notification.notification_type, "FAVORITE")
|
||||
self.assertEqual(notification.user, self.local_user)
|
||||
self.assertEqual(notification.related_user, self.remote_user)
|
||||
|
||||
|
||||
def test_handle_unfavorite(self):
|
||||
''' unfav a status '''
|
||||
""" unfav a status """
|
||||
view = views.Unfavorite.as_view()
|
||||
request = self.factory.post('')
|
||||
request = self.factory.post("")
|
||||
request.user = self.remote_user
|
||||
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
|
||||
status = models.Status.objects.create(
|
||||
user=self.local_user, content='hi')
|
||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
|
||||
status = models.Status.objects.create(user=self.local_user, content="hi")
|
||||
views.Favorite.as_view()(request, status.id)
|
||||
|
||||
self.assertEqual(models.Favorite.objects.count(), 1)
|
||||
self.assertEqual(models.Notification.objects.count(), 1)
|
||||
|
||||
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
|
||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
|
||||
view(request, status.id)
|
||||
self.assertEqual(models.Favorite.objects.count(), 0)
|
||||
self.assertEqual(models.Notification.objects.count(), 0)
|
||||
|
||||
|
||||
def test_handle_boost(self):
|
||||
''' boost a status '''
|
||||
""" boost a status """
|
||||
view = views.Boost.as_view()
|
||||
request = self.factory.post('')
|
||||
request = self.factory.post("")
|
||||
request.user = self.remote_user
|
||||
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
|
||||
status = models.Status.objects.create(
|
||||
user=self.local_user, content='hi')
|
||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
|
||||
status = models.Status.objects.create(user=self.local_user, content="hi")
|
||||
|
||||
view(request, status.id)
|
||||
|
||||
boost = models.Boost.objects.get()
|
||||
self.assertEqual(boost.boosted_status, status)
|
||||
self.assertEqual(boost.user, self.remote_user)
|
||||
self.assertEqual(boost.privacy, 'public')
|
||||
self.assertEqual(boost.privacy, "public")
|
||||
|
||||
notification = models.Notification.objects.get()
|
||||
self.assertEqual(notification.notification_type, 'BOOST')
|
||||
self.assertEqual(notification.notification_type, "BOOST")
|
||||
self.assertEqual(notification.user, self.local_user)
|
||||
self.assertEqual(notification.related_user, self.remote_user)
|
||||
self.assertEqual(notification.related_status, status)
|
||||
|
||||
def test_handle_boost_unlisted(self):
|
||||
''' boost a status '''
|
||||
""" boost a status """
|
||||
view = views.Boost.as_view()
|
||||
request = self.factory.post('')
|
||||
request = self.factory.post("")
|
||||
request.user = self.local_user
|
||||
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
|
||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
|
||||
status = models.Status.objects.create(
|
||||
user=self.local_user, content='hi', privacy='unlisted')
|
||||
user=self.local_user, content="hi", privacy="unlisted"
|
||||
)
|
||||
|
||||
view(request, status.id)
|
||||
|
||||
boost = models.Boost.objects.get()
|
||||
self.assertEqual(boost.privacy, 'unlisted')
|
||||
self.assertEqual(boost.privacy, "unlisted")
|
||||
|
||||
def test_handle_boost_private(self):
|
||||
''' boost a status '''
|
||||
""" boost a status """
|
||||
view = views.Boost.as_view()
|
||||
request = self.factory.post('')
|
||||
request = self.factory.post("")
|
||||
request.user = self.local_user
|
||||
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
|
||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
|
||||
status = models.Status.objects.create(
|
||||
user=self.local_user, content='hi', privacy='followers')
|
||||
user=self.local_user, content="hi", privacy="followers"
|
||||
)
|
||||
|
||||
view(request, status.id)
|
||||
self.assertFalse(models.Boost.objects.exists())
|
||||
|
||||
def test_handle_boost_twice(self):
|
||||
''' boost a status '''
|
||||
""" boost a status """
|
||||
view = views.Boost.as_view()
|
||||
request = self.factory.post('')
|
||||
request = self.factory.post("")
|
||||
request.user = self.local_user
|
||||
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
|
||||
status = models.Status.objects.create(
|
||||
user=self.local_user, content='hi')
|
||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
|
||||
status = models.Status.objects.create(user=self.local_user, content="hi")
|
||||
|
||||
view(request, status.id)
|
||||
view(request, status.id)
|
||||
self.assertEqual(models.Boost.objects.count(), 1)
|
||||
|
||||
|
||||
def test_handle_unboost(self):
|
||||
''' undo a boost '''
|
||||
""" undo a boost """
|
||||
view = views.Unboost.as_view()
|
||||
request = self.factory.post('')
|
||||
request = self.factory.post("")
|
||||
request.user = self.local_user
|
||||
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
|
||||
status = models.Status.objects.create(
|
||||
user=self.local_user, content='hi')
|
||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
|
||||
status = models.Status.objects.create(user=self.local_user, content="hi")
|
||||
views.Boost.as_view()(request, status.id)
|
||||
|
||||
self.assertEqual(models.Boost.objects.count(), 1)
|
||||
self.assertEqual(models.Notification.objects.count(), 1)
|
||||
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay') \
|
||||
as mock:
|
||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay") as mock:
|
||||
view(request, status.id)
|
||||
self.assertEqual(mock.call_count, 1)
|
||||
self.assertEqual(models.Boost.objects.count(), 0)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
''' test for app action functionality '''
|
||||
""" test for app action functionality """
|
||||
from unittest.mock import patch
|
||||
|
||||
from django.contrib.auth.models import AnonymousUser
|
||||
@@ -11,36 +11,39 @@ from bookwyrm import views
|
||||
|
||||
|
||||
class InviteViews(TestCase):
|
||||
''' every response to a get request, html or json '''
|
||||
""" every response to a get request, html or json """
|
||||
|
||||
def setUp(self):
|
||||
''' we need basic test data and mocks '''
|
||||
""" we need basic test data and mocks """
|
||||
self.factory = RequestFactory()
|
||||
self.local_user = models.User.objects.create_user(
|
||||
'mouse@local.com', 'mouse@mouse.mouse', 'password',
|
||||
local=True, localname='mouse')
|
||||
"mouse@local.com",
|
||||
"mouse@mouse.mouse",
|
||||
"password",
|
||||
local=True,
|
||||
localname="mouse",
|
||||
)
|
||||
models.SiteSettings.objects.create()
|
||||
|
||||
|
||||
def test_invite_page(self):
|
||||
''' there are so many views, this just makes sure it LOADS '''
|
||||
""" there are so many views, this just makes sure it LOADS """
|
||||
view = views.Invite.as_view()
|
||||
models.SiteInvite.objects.create(code='hi', user=self.local_user)
|
||||
request = self.factory.get('')
|
||||
models.SiteInvite.objects.create(code="hi", user=self.local_user)
|
||||
request = self.factory.get("")
|
||||
request.user = AnonymousUser
|
||||
# why?? this is annoying.
|
||||
request.user.is_authenticated = False
|
||||
with patch('bookwyrm.models.site.SiteInvite.valid') as invite:
|
||||
with patch("bookwyrm.models.site.SiteInvite.valid") as invite:
|
||||
invite.return_value = True
|
||||
result = view(request, 'hi')
|
||||
result = view(request, "hi")
|
||||
self.assertIsInstance(result, TemplateResponse)
|
||||
result.render()
|
||||
self.assertEqual(result.status_code, 200)
|
||||
|
||||
|
||||
def test_manage_invites(self):
|
||||
''' there are so many views, this just makes sure it LOADS '''
|
||||
""" there are so many views, this just makes sure it LOADS """
|
||||
view = views.ManageInvites.as_view()
|
||||
request = self.factory.get('')
|
||||
request = self.factory.get("")
|
||||
request.user = self.local_user
|
||||
request.user.is_superuser = True
|
||||
result = view(request)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
''' test for app action functionality '''
|
||||
""" test for app action functionality """
|
||||
import json
|
||||
from unittest.mock import patch
|
||||
|
||||
@@ -13,42 +13,41 @@ from bookwyrm.settings import DOMAIN
|
||||
|
||||
|
||||
class IsbnViews(TestCase):
|
||||
''' tag views'''
|
||||
""" tag views"""
|
||||
|
||||
def setUp(self):
|
||||
''' we need basic test data and mocks '''
|
||||
""" 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',
|
||||
"mouse@local.com",
|
||||
"mouse@mouse.com",
|
||||
"mouseword",
|
||||
local=True,
|
||||
localname="mouse",
|
||||
remote_id="https://example.com/users/mouse",
|
||||
)
|
||||
self.work = models.Work.objects.create(title='Test Work')
|
||||
self.work = models.Work.objects.create(title="Test Work")
|
||||
self.book = models.Edition.objects.create(
|
||||
title='Test Book',
|
||||
isbn_13='1234567890123',
|
||||
remote_id='https://example.com/book/1',
|
||||
parent_work=self.work
|
||||
title="Test Book",
|
||||
isbn_13="1234567890123",
|
||||
remote_id="https://example.com/book/1",
|
||||
parent_work=self.work,
|
||||
)
|
||||
models.Connector.objects.create(
|
||||
identifier='self',
|
||||
connector_file='self_connector',
|
||||
local=True
|
||||
identifier="self", connector_file="self_connector", local=True
|
||||
)
|
||||
models.SiteSettings.objects.create()
|
||||
|
||||
|
||||
def test_isbn_json_response(self):
|
||||
''' searches local data only and returns book data in json format '''
|
||||
""" searches local data only and returns book data in json format """
|
||||
view = views.Isbn.as_view()
|
||||
request = self.factory.get('')
|
||||
with patch('bookwyrm.views.isbn.is_api_request') as is_api:
|
||||
request = self.factory.get("")
|
||||
with patch("bookwyrm.views.isbn.is_api_request") as is_api:
|
||||
is_api.return_value = True
|
||||
response = view(request, isbn='1234567890123')
|
||||
response = view(request, isbn="1234567890123")
|
||||
self.assertIsInstance(response, JsonResponse)
|
||||
|
||||
data = json.loads(response.content)
|
||||
self.assertEqual(len(data), 1)
|
||||
self.assertEqual(data[0]['title'], 'Test Book')
|
||||
self.assertEqual(
|
||||
data[0]['key'], 'https://%s/book/%d' % (DOMAIN, self.book.id))
|
||||
|
||||
self.assertEqual(data[0]["title"], "Test Book")
|
||||
self.assertEqual(data[0]["key"], "https://%s/book/%d" % (DOMAIN, self.book.id))
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
''' test for app action functionality '''
|
||||
""" test for app action functionality """
|
||||
from django.contrib.auth.models import AnonymousUser
|
||||
from django.template.response import TemplateResponse
|
||||
from django.test import TestCase
|
||||
@@ -9,22 +9,26 @@ from bookwyrm import views
|
||||
|
||||
|
||||
class LandingViews(TestCase):
|
||||
''' pages you land on without really trying '''
|
||||
""" pages you land on without really trying """
|
||||
|
||||
def setUp(self):
|
||||
''' we need basic test data and mocks '''
|
||||
""" we need basic test data and mocks """
|
||||
self.factory = RequestFactory()
|
||||
self.local_user = models.User.objects.create_user(
|
||||
'mouse@local.com', 'mouse@mouse.mouse', 'password',
|
||||
local=True, localname='mouse')
|
||||
"mouse@local.com",
|
||||
"mouse@mouse.mouse",
|
||||
"password",
|
||||
local=True,
|
||||
localname="mouse",
|
||||
)
|
||||
self.anonymous_user = AnonymousUser
|
||||
self.anonymous_user.is_authenticated = False
|
||||
models.SiteSettings.objects.create()
|
||||
|
||||
|
||||
def test_home_page(self):
|
||||
''' there are so many views, this just makes sure it LOADS '''
|
||||
""" there are so many views, this just makes sure it LOADS """
|
||||
view = views.Home.as_view()
|
||||
request = self.factory.get('')
|
||||
request = self.factory.get("")
|
||||
request.user = self.local_user
|
||||
result = view(request)
|
||||
self.assertEqual(result.status_code, 200)
|
||||
@@ -36,21 +40,19 @@ class LandingViews(TestCase):
|
||||
self.assertEqual(result.status_code, 200)
|
||||
result.render()
|
||||
|
||||
|
||||
def test_about_page(self):
|
||||
''' there are so many views, this just makes sure it LOADS '''
|
||||
""" there are so many views, this just makes sure it LOADS """
|
||||
view = views.About.as_view()
|
||||
request = self.factory.get('')
|
||||
request = self.factory.get("")
|
||||
request.user = self.local_user
|
||||
result = view(request)
|
||||
self.assertIsInstance(result, TemplateResponse)
|
||||
result.render()
|
||||
self.assertEqual(result.status_code, 200)
|
||||
|
||||
|
||||
def test_discover(self):
|
||||
''' there are so many views, this just makes sure it LOADS '''
|
||||
""" there are so many views, this just makes sure it LOADS """
|
||||
view = views.Discover.as_view()
|
||||
request = self.factory.get('')
|
||||
request = self.factory.get("")
|
||||
result = view(request)
|
||||
self.assertIsInstance(result, TemplateResponse)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
''' test for app action functionality '''
|
||||
""" test for app action functionality """
|
||||
from unittest.mock import patch
|
||||
|
||||
from django.contrib.auth.models import AnonymousUser
|
||||
@@ -9,44 +9,52 @@ from django.test.client import RequestFactory
|
||||
from bookwyrm import models, views
|
||||
from bookwyrm.activitypub import ActivitypubResponse
|
||||
|
||||
#pylint: disable=unused-argument
|
||||
# pylint: disable=unused-argument
|
||||
class ListViews(TestCase):
|
||||
''' tag views'''
|
||||
""" tag views"""
|
||||
|
||||
def setUp(self):
|
||||
''' we need basic test data and mocks '''
|
||||
""" 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',
|
||||
"mouse@local.com",
|
||||
"mouse@mouse.com",
|
||||
"mouseword",
|
||||
local=True,
|
||||
localname="mouse",
|
||||
remote_id="https://example.com/users/mouse",
|
||||
)
|
||||
self.rat = models.User.objects.create_user(
|
||||
'rat@local.com', 'rat@rat.com', 'ratword',
|
||||
local=True, localname='rat',
|
||||
remote_id='https://example.com/users/rat',
|
||||
"rat@local.com",
|
||||
"rat@rat.com",
|
||||
"ratword",
|
||||
local=True,
|
||||
localname="rat",
|
||||
remote_id="https://example.com/users/rat",
|
||||
)
|
||||
work = models.Work.objects.create(title='Work')
|
||||
work = models.Work.objects.create(title="Work")
|
||||
self.book = models.Edition.objects.create(
|
||||
title='Example Edition',
|
||||
remote_id='https://example.com/book/1',
|
||||
title="Example Edition",
|
||||
remote_id="https://example.com/book/1",
|
||||
parent_work=work,
|
||||
)
|
||||
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
|
||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
|
||||
self.list = models.List.objects.create(
|
||||
name='Test List', user=self.local_user)
|
||||
name="Test List", user=self.local_user
|
||||
)
|
||||
self.anonymous_user = AnonymousUser
|
||||
self.anonymous_user.is_authenticated = False
|
||||
models.SiteSettings.objects.create()
|
||||
|
||||
|
||||
def test_lists_page(self):
|
||||
''' there are so many views, this just makes sure it LOADS '''
|
||||
""" there are so many views, this just makes sure it LOADS """
|
||||
view = views.Lists.as_view()
|
||||
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
|
||||
models.List.objects.create(name='Public list', user=self.local_user)
|
||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
|
||||
models.List.objects.create(name="Public list", user=self.local_user)
|
||||
models.List.objects.create(
|
||||
name='Private list', privacy='direct', user=self.local_user)
|
||||
request = self.factory.get('')
|
||||
name="Private list", privacy="direct", user=self.local_user
|
||||
)
|
||||
request = self.factory.get("")
|
||||
request.user = self.local_user
|
||||
|
||||
result = view(request)
|
||||
@@ -61,42 +69,45 @@ class ListViews(TestCase):
|
||||
result.render()
|
||||
self.assertEqual(result.status_code, 200)
|
||||
|
||||
|
||||
def test_lists_create(self):
|
||||
''' create list view '''
|
||||
""" create list view """
|
||||
real_broadcast = models.List.broadcast
|
||||
|
||||
def mock_broadcast(_, activity, user, **kwargs):
|
||||
''' ok '''
|
||||
""" ok """
|
||||
self.assertEqual(user.remote_id, self.local_user.remote_id)
|
||||
self.assertEqual(activity['type'], 'Create')
|
||||
self.assertEqual(activity['actor'], self.local_user.remote_id)
|
||||
self.assertEqual(activity["type"], "Create")
|
||||
self.assertEqual(activity["actor"], self.local_user.remote_id)
|
||||
|
||||
models.List.broadcast = mock_broadcast
|
||||
|
||||
view = views.Lists.as_view()
|
||||
request = self.factory.post('', {
|
||||
'name': 'A list',
|
||||
'description': 'wow',
|
||||
'privacy': 'unlisted',
|
||||
'curation': 'open',
|
||||
'user': self.local_user.id,
|
||||
})
|
||||
request = self.factory.post(
|
||||
"",
|
||||
{
|
||||
"name": "A list",
|
||||
"description": "wow",
|
||||
"privacy": "unlisted",
|
||||
"curation": "open",
|
||||
"user": self.local_user.id,
|
||||
},
|
||||
)
|
||||
request.user = self.local_user
|
||||
result = view(request)
|
||||
self.assertEqual(result.status_code, 302)
|
||||
new_list = models.List.objects.filter(name='A list').get()
|
||||
self.assertEqual(new_list.description, 'wow')
|
||||
self.assertEqual(new_list.privacy, 'unlisted')
|
||||
self.assertEqual(new_list.curation, 'open')
|
||||
new_list = models.List.objects.filter(name="A list").get()
|
||||
self.assertEqual(new_list.description, "wow")
|
||||
self.assertEqual(new_list.privacy, "unlisted")
|
||||
self.assertEqual(new_list.curation, "open")
|
||||
models.List.broadcast = real_broadcast
|
||||
|
||||
|
||||
def test_list_page(self):
|
||||
''' there are so many views, this just makes sure it LOADS '''
|
||||
""" there are so many views, this just makes sure it LOADS """
|
||||
view = views.List.as_view()
|
||||
request = self.factory.get('')
|
||||
request = self.factory.get("")
|
||||
request.user = self.local_user
|
||||
|
||||
with patch('bookwyrm.views.list.is_api_request') as is_api:
|
||||
with patch("bookwyrm.views.list.is_api_request") as is_api:
|
||||
is_api.return_value = False
|
||||
result = view(request, self.list.id)
|
||||
self.assertIsInstance(result, TemplateResponse)
|
||||
@@ -104,68 +115,72 @@ class ListViews(TestCase):
|
||||
self.assertEqual(result.status_code, 200)
|
||||
|
||||
request.user = self.anonymous_user
|
||||
with patch('bookwyrm.views.list.is_api_request') as is_api:
|
||||
with patch("bookwyrm.views.list.is_api_request") as is_api:
|
||||
is_api.return_value = False
|
||||
result = view(request, self.list.id)
|
||||
self.assertIsInstance(result, TemplateResponse)
|
||||
result.render()
|
||||
self.assertEqual(result.status_code, 200)
|
||||
|
||||
with patch('bookwyrm.views.list.is_api_request') as is_api:
|
||||
with patch("bookwyrm.views.list.is_api_request") as is_api:
|
||||
is_api.return_value = True
|
||||
result = view(request, self.list.id)
|
||||
self.assertIsInstance(result, ActivitypubResponse)
|
||||
self.assertEqual(result.status_code, 200)
|
||||
|
||||
request = self.factory.get('/?page=1')
|
||||
request = self.factory.get("/?page=1")
|
||||
request.user = self.local_user
|
||||
with patch('bookwyrm.views.list.is_api_request') as is_api:
|
||||
with patch("bookwyrm.views.list.is_api_request") as is_api:
|
||||
is_api.return_value = True
|
||||
result = view(request, self.list.id)
|
||||
self.assertIsInstance(result, ActivitypubResponse)
|
||||
self.assertEqual(result.status_code, 200)
|
||||
|
||||
|
||||
def test_list_edit(self):
|
||||
''' edit a list '''
|
||||
""" edit a list """
|
||||
real_broadcast = models.List.broadcast
|
||||
|
||||
def mock_broadcast(_, activity, user, **kwargs):
|
||||
''' ok '''
|
||||
""" ok """
|
||||
self.assertEqual(user.remote_id, self.local_user.remote_id)
|
||||
self.assertEqual(activity['type'], 'Update')
|
||||
self.assertEqual(activity['actor'], self.local_user.remote_id)
|
||||
self.assertEqual(activity['object']['id'], self.list.remote_id)
|
||||
self.assertEqual(activity["type"], "Update")
|
||||
self.assertEqual(activity["actor"], self.local_user.remote_id)
|
||||
self.assertEqual(activity["object"]["id"], self.list.remote_id)
|
||||
|
||||
models.List.broadcast = mock_broadcast
|
||||
|
||||
view = views.List.as_view()
|
||||
request = self.factory.post('', {
|
||||
'name': 'New Name',
|
||||
'description': 'wow',
|
||||
'privacy': 'direct',
|
||||
'curation': 'curated',
|
||||
'user': self.local_user.id,
|
||||
})
|
||||
request = self.factory.post(
|
||||
"",
|
||||
{
|
||||
"name": "New Name",
|
||||
"description": "wow",
|
||||
"privacy": "direct",
|
||||
"curation": "curated",
|
||||
"user": self.local_user.id,
|
||||
},
|
||||
)
|
||||
request.user = self.local_user
|
||||
|
||||
result = view(request, self.list.id)
|
||||
self.assertEqual(result.status_code, 302)
|
||||
|
||||
self.list.refresh_from_db()
|
||||
self.assertEqual(self.list.name, 'New Name')
|
||||
self.assertEqual(self.list.description, 'wow')
|
||||
self.assertEqual(self.list.privacy, 'direct')
|
||||
self.assertEqual(self.list.curation, 'curated')
|
||||
self.assertEqual(self.list.name, "New Name")
|
||||
self.assertEqual(self.list.description, "wow")
|
||||
self.assertEqual(self.list.privacy, "direct")
|
||||
self.assertEqual(self.list.curation, "curated")
|
||||
models.List.broadcast = real_broadcast
|
||||
|
||||
|
||||
def test_curate_page(self):
|
||||
''' there are so many views, this just makes sure it LOADS '''
|
||||
""" there are so many views, this just makes sure it LOADS """
|
||||
view = views.Curate.as_view()
|
||||
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
|
||||
models.List.objects.create(name='Public list', user=self.local_user)
|
||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
|
||||
models.List.objects.create(name="Public list", user=self.local_user)
|
||||
models.List.objects.create(
|
||||
name='Private list', privacy='direct', user=self.local_user)
|
||||
request = self.factory.get('')
|
||||
name="Private list", privacy="direct", user=self.local_user
|
||||
)
|
||||
request = self.factory.get("")
|
||||
request.user = self.local_user
|
||||
|
||||
result = view(request, self.list.id)
|
||||
@@ -177,31 +192,35 @@ class ListViews(TestCase):
|
||||
result = view(request, self.list.id)
|
||||
self.assertEqual(result.status_code, 302)
|
||||
|
||||
|
||||
def test_curate_approve(self):
|
||||
''' approve a pending item '''
|
||||
""" approve a pending item """
|
||||
real_broadcast = models.List.broadcast
|
||||
|
||||
def mock_broadcast(_, activity, user, **kwargs):
|
||||
''' ok '''
|
||||
""" ok """
|
||||
self.assertEqual(user.remote_id, self.local_user.remote_id)
|
||||
self.assertEqual(activity['type'], 'Add')
|
||||
self.assertEqual(activity['actor'], self.local_user.remote_id)
|
||||
self.assertEqual(activity['target'], self.list.remote_id)
|
||||
self.assertEqual(activity["type"], "Add")
|
||||
self.assertEqual(activity["actor"], self.local_user.remote_id)
|
||||
self.assertEqual(activity["target"], self.list.remote_id)
|
||||
|
||||
models.ListItem.broadcast = mock_broadcast
|
||||
|
||||
view = views.Curate.as_view()
|
||||
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
|
||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
|
||||
pending = models.ListItem.objects.create(
|
||||
book_list=self.list,
|
||||
user=self.local_user,
|
||||
book=self.book,
|
||||
approved=False
|
||||
approved=False,
|
||||
)
|
||||
|
||||
request = self.factory.post('', {
|
||||
'item': pending.id,
|
||||
'approved': 'true',
|
||||
})
|
||||
request = self.factory.post(
|
||||
"",
|
||||
{
|
||||
"item": pending.id,
|
||||
"approved": "true",
|
||||
},
|
||||
)
|
||||
request.user = self.local_user
|
||||
|
||||
view(request, self.list.id)
|
||||
@@ -211,43 +230,49 @@ class ListViews(TestCase):
|
||||
self.assertTrue(pending.approved)
|
||||
models.ListItem.broadcast = real_broadcast
|
||||
|
||||
|
||||
def test_curate_reject(self):
|
||||
''' approve a pending item '''
|
||||
""" approve a pending item """
|
||||
view = views.Curate.as_view()
|
||||
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
|
||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
|
||||
pending = models.ListItem.objects.create(
|
||||
book_list=self.list,
|
||||
user=self.local_user,
|
||||
book=self.book,
|
||||
approved=False
|
||||
approved=False,
|
||||
)
|
||||
|
||||
request = self.factory.post('', {
|
||||
'item': pending.id,
|
||||
'approved': 'false',
|
||||
})
|
||||
request = self.factory.post(
|
||||
"",
|
||||
{
|
||||
"item": pending.id,
|
||||
"approved": "false",
|
||||
},
|
||||
)
|
||||
request.user = self.local_user
|
||||
|
||||
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
|
||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
|
||||
view(request, self.list.id)
|
||||
self.assertFalse(self.list.books.exists())
|
||||
self.assertFalse(models.ListItem.objects.exists())
|
||||
|
||||
|
||||
def test_add_book(self):
|
||||
''' put a book on a list '''
|
||||
""" put a book on a list """
|
||||
real_broadcast = models.List.broadcast
|
||||
|
||||
def mock_broadcast(_, activity, user):
|
||||
''' ok '''
|
||||
""" ok """
|
||||
self.assertEqual(user.remote_id, self.local_user.remote_id)
|
||||
self.assertEqual(activity['type'], 'Add')
|
||||
self.assertEqual(activity['actor'], self.local_user.remote_id)
|
||||
self.assertEqual(activity['target'], self.list.remote_id)
|
||||
self.assertEqual(activity["type"], "Add")
|
||||
self.assertEqual(activity["actor"], self.local_user.remote_id)
|
||||
self.assertEqual(activity["target"], self.list.remote_id)
|
||||
|
||||
models.ListItem.broadcast = mock_broadcast
|
||||
request = self.factory.post('', {
|
||||
'book': self.book.id,
|
||||
})
|
||||
request = self.factory.post(
|
||||
"",
|
||||
{
|
||||
"book": self.book.id,
|
||||
},
|
||||
)
|
||||
request.user = self.local_user
|
||||
|
||||
views.list.add_book(request, self.list.id)
|
||||
@@ -257,22 +282,26 @@ class ListViews(TestCase):
|
||||
self.assertTrue(item.approved)
|
||||
models.ListItem.broadcast = real_broadcast
|
||||
|
||||
|
||||
def test_add_book_outsider(self):
|
||||
''' put a book on a list '''
|
||||
""" put a book on a list """
|
||||
real_broadcast = models.List.broadcast
|
||||
|
||||
def mock_broadcast(_, activity, user):
|
||||
''' ok '''
|
||||
""" ok """
|
||||
self.assertEqual(user.remote_id, self.rat.remote_id)
|
||||
self.assertEqual(activity['type'], 'Add')
|
||||
self.assertEqual(activity['actor'], self.rat.remote_id)
|
||||
self.assertEqual(activity['target'], self.list.remote_id)
|
||||
self.assertEqual(activity["type"], "Add")
|
||||
self.assertEqual(activity["actor"], self.rat.remote_id)
|
||||
self.assertEqual(activity["target"], self.list.remote_id)
|
||||
|
||||
models.ListItem.broadcast = mock_broadcast
|
||||
self.list.curation = 'open'
|
||||
self.list.curation = "open"
|
||||
self.list.save(broadcast=False)
|
||||
request = self.factory.post('', {
|
||||
'book': self.book.id,
|
||||
})
|
||||
request = self.factory.post(
|
||||
"",
|
||||
{
|
||||
"book": self.book.id,
|
||||
},
|
||||
)
|
||||
request.user = self.rat
|
||||
|
||||
views.list.add_book(request, self.list.id)
|
||||
@@ -282,23 +311,27 @@ class ListViews(TestCase):
|
||||
self.assertTrue(item.approved)
|
||||
models.ListItem.broadcast = real_broadcast
|
||||
|
||||
|
||||
def test_add_book_pending(self):
|
||||
''' put a book on a list awaiting approval '''
|
||||
""" put a book on a list awaiting approval """
|
||||
real_broadcast = models.List.broadcast
|
||||
|
||||
def mock_broadcast(_, activity, user):
|
||||
''' ok '''
|
||||
""" ok """
|
||||
self.assertEqual(user.remote_id, self.rat.remote_id)
|
||||
self.assertEqual(activity['type'], 'Add')
|
||||
self.assertEqual(activity['actor'], self.rat.remote_id)
|
||||
self.assertEqual(activity['target'], self.list.remote_id)
|
||||
self.assertEqual(activity['object']['id'], self.book.remote_id)
|
||||
self.assertEqual(activity["type"], "Add")
|
||||
self.assertEqual(activity["actor"], self.rat.remote_id)
|
||||
self.assertEqual(activity["target"], self.list.remote_id)
|
||||
self.assertEqual(activity["object"]["id"], self.book.remote_id)
|
||||
|
||||
models.ListItem.broadcast = mock_broadcast
|
||||
self.list.curation = 'curated'
|
||||
self.list.curation = "curated"
|
||||
self.list.save(broadcast=False)
|
||||
request = self.factory.post('', {
|
||||
'book': self.book.id,
|
||||
})
|
||||
request = self.factory.post(
|
||||
"",
|
||||
{
|
||||
"book": self.book.id,
|
||||
},
|
||||
)
|
||||
request.user = self.rat
|
||||
|
||||
views.list.add_book(request, self.list.id)
|
||||
@@ -308,23 +341,27 @@ class ListViews(TestCase):
|
||||
self.assertFalse(item.approved)
|
||||
models.ListItem.broadcast = real_broadcast
|
||||
|
||||
|
||||
def test_add_book_self_curated(self):
|
||||
''' put a book on a list automatically approved '''
|
||||
""" put a book on a list automatically approved """
|
||||
real_broadcast = models.ListItem.broadcast
|
||||
|
||||
def mock_broadcast(_, activity, user):
|
||||
''' ok '''
|
||||
""" ok """
|
||||
self.assertEqual(user.remote_id, self.local_user.remote_id)
|
||||
self.assertEqual(activity['type'], 'Add')
|
||||
self.assertEqual(activity['actor'], self.local_user.remote_id)
|
||||
self.assertEqual(activity['target'], self.list.remote_id)
|
||||
self.assertEqual(activity["type"], "Add")
|
||||
self.assertEqual(activity["actor"], self.local_user.remote_id)
|
||||
self.assertEqual(activity["target"], self.list.remote_id)
|
||||
|
||||
models.ListItem.broadcast = mock_broadcast
|
||||
|
||||
self.list.curation = 'curated'
|
||||
self.list.curation = "curated"
|
||||
self.list.save(broadcast=False)
|
||||
request = self.factory.post('', {
|
||||
'book': self.book.id,
|
||||
})
|
||||
request = self.factory.post(
|
||||
"",
|
||||
{
|
||||
"book": self.book.id,
|
||||
},
|
||||
)
|
||||
request.user = self.local_user
|
||||
|
||||
views.list.add_book(request, self.list.id)
|
||||
@@ -334,12 +371,11 @@ class ListViews(TestCase):
|
||||
self.assertTrue(item.approved)
|
||||
models.ListItem.broadcast = real_broadcast
|
||||
|
||||
|
||||
def test_remove_book(self):
|
||||
''' take an item off a list '''
|
||||
""" take an item off a list """
|
||||
real_broadcast = models.ListItem.broadcast
|
||||
|
||||
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
|
||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
|
||||
item = models.ListItem.objects.create(
|
||||
book_list=self.list,
|
||||
user=self.local_user,
|
||||
@@ -348,15 +384,19 @@ class ListViews(TestCase):
|
||||
self.assertTrue(self.list.listitem_set.exists())
|
||||
|
||||
def mock_broadcast(_, activity, user):
|
||||
''' ok '''
|
||||
""" ok """
|
||||
self.assertEqual(user.remote_id, self.local_user.remote_id)
|
||||
self.assertEqual(activity['type'], 'Remove')
|
||||
self.assertEqual(activity['actor'], self.local_user.remote_id)
|
||||
self.assertEqual(activity['target'], self.list.remote_id)
|
||||
self.assertEqual(activity["type"], "Remove")
|
||||
self.assertEqual(activity["actor"], self.local_user.remote_id)
|
||||
self.assertEqual(activity["target"], self.list.remote_id)
|
||||
|
||||
models.ListItem.broadcast = mock_broadcast
|
||||
request = self.factory.post('', {
|
||||
'item': item.id,
|
||||
})
|
||||
request = self.factory.post(
|
||||
"",
|
||||
{
|
||||
"item": item.id,
|
||||
},
|
||||
)
|
||||
request.user = self.local_user
|
||||
|
||||
views.list.remove_book(request, self.list.id)
|
||||
@@ -364,19 +404,21 @@ class ListViews(TestCase):
|
||||
self.assertFalse(self.list.listitem_set.exists())
|
||||
models.ListItem.broadcast = real_broadcast
|
||||
|
||||
|
||||
def test_remove_book_unauthorized(self):
|
||||
''' take an item off a list '''
|
||||
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
|
||||
""" take an item off a list """
|
||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
|
||||
item = models.ListItem.objects.create(
|
||||
book_list=self.list,
|
||||
user=self.local_user,
|
||||
book=self.book,
|
||||
)
|
||||
self.assertTrue(self.list.listitem_set.exists())
|
||||
request = self.factory.post('', {
|
||||
'item': item.id,
|
||||
})
|
||||
request = self.factory.post(
|
||||
"",
|
||||
{
|
||||
"item": item.id,
|
||||
},
|
||||
)
|
||||
request.user = self.rat
|
||||
|
||||
views.list.remove_book(request, self.list.id)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
''' test for app action functionality '''
|
||||
""" test for app action functionality """
|
||||
from django.template.response import TemplateResponse
|
||||
from django.test import TestCase
|
||||
from django.test.client import RequestFactory
|
||||
@@ -8,19 +8,24 @@ from bookwyrm import views
|
||||
|
||||
|
||||
class NotificationViews(TestCase):
|
||||
''' notifications '''
|
||||
""" notifications """
|
||||
|
||||
def setUp(self):
|
||||
''' we need basic test data and mocks '''
|
||||
""" we need basic test data and mocks """
|
||||
self.factory = RequestFactory()
|
||||
self.local_user = models.User.objects.create_user(
|
||||
'mouse@local.com', 'mouse@mouse.mouse', 'password',
|
||||
local=True, localname='mouse')
|
||||
"mouse@local.com",
|
||||
"mouse@mouse.mouse",
|
||||
"password",
|
||||
local=True,
|
||||
localname="mouse",
|
||||
)
|
||||
models.SiteSettings.objects.create()
|
||||
|
||||
def test_notifications_page(self):
|
||||
''' there are so many views, this just makes sure it LOADS '''
|
||||
""" there are so many views, this just makes sure it LOADS """
|
||||
view = views.Notifications.as_view()
|
||||
request = self.factory.get('')
|
||||
request = self.factory.get("")
|
||||
request.user = self.local_user
|
||||
result = view(request)
|
||||
self.assertIsInstance(result, TemplateResponse)
|
||||
@@ -28,14 +33,16 @@ class NotificationViews(TestCase):
|
||||
self.assertEqual(result.status_code, 200)
|
||||
|
||||
def test_clear_notifications(self):
|
||||
''' erase notifications '''
|
||||
""" erase notifications """
|
||||
models.Notification.objects.create(
|
||||
user=self.local_user, notification_type='FAVORITE')
|
||||
user=self.local_user, notification_type="FAVORITE"
|
||||
)
|
||||
models.Notification.objects.create(
|
||||
user=self.local_user, notification_type='MENTION', read=True)
|
||||
user=self.local_user, notification_type="MENTION", read=True
|
||||
)
|
||||
self.assertEqual(models.Notification.objects.count(), 2)
|
||||
view = views.Notifications.as_view()
|
||||
request = self.factory.post('')
|
||||
request = self.factory.post("")
|
||||
request.user = self.local_user
|
||||
result = view(request)
|
||||
self.assertEqual(result.status_code, 302)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
''' sending out activities '''
|
||||
""" sending out activities """
|
||||
from unittest.mock import patch
|
||||
import json
|
||||
|
||||
@@ -12,118 +12,127 @@ from bookwyrm.settings import USER_AGENT
|
||||
|
||||
# pylint: disable=too-many-public-methods
|
||||
class OutboxView(TestCase):
|
||||
''' sends out activities '''
|
||||
""" sends out activities """
|
||||
|
||||
def setUp(self):
|
||||
''' we'll need some data '''
|
||||
""" we'll need some data """
|
||||
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',
|
||||
"mouse@local.com",
|
||||
"mouse@mouse.com",
|
||||
"mouseword",
|
||||
local=True,
|
||||
localname="mouse",
|
||||
remote_id="https://example.com/users/mouse",
|
||||
)
|
||||
work = models.Work.objects.create(title='Test Work')
|
||||
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
|
||||
title="Example Edition",
|
||||
remote_id="https://example.com/book/1",
|
||||
parent_work=work,
|
||||
)
|
||||
|
||||
|
||||
def test_outbox(self):
|
||||
''' returns user's statuses '''
|
||||
request = self.factory.get('')
|
||||
result = views.Outbox.as_view()(request, 'mouse')
|
||||
""" returns user's statuses """
|
||||
request = self.factory.get("")
|
||||
result = views.Outbox.as_view()(request, "mouse")
|
||||
self.assertIsInstance(result, JsonResponse)
|
||||
|
||||
def test_outbox_bad_method(self):
|
||||
''' can't POST to outbox '''
|
||||
request = self.factory.post('')
|
||||
result = views.Outbox.as_view()(request, 'mouse')
|
||||
""" can't POST to outbox """
|
||||
request = self.factory.post("")
|
||||
result = views.Outbox.as_view()(request, "mouse")
|
||||
self.assertEqual(result.status_code, 405)
|
||||
|
||||
def test_outbox_unknown_user(self):
|
||||
''' should 404 for unknown and remote users '''
|
||||
request = self.factory.post('')
|
||||
result = views.Outbox.as_view()(request, 'beepboop')
|
||||
""" should 404 for unknown and remote users """
|
||||
request = self.factory.post("")
|
||||
result = views.Outbox.as_view()(request, "beepboop")
|
||||
self.assertEqual(result.status_code, 405)
|
||||
result = views.Outbox.as_view()(request, 'rat')
|
||||
result = views.Outbox.as_view()(request, "rat")
|
||||
self.assertEqual(result.status_code, 405)
|
||||
|
||||
def test_outbox_privacy(self):
|
||||
''' don't show dms et cetera in outbox '''
|
||||
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
|
||||
""" don't show dms et cetera in outbox """
|
||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
|
||||
models.Status.objects.create(
|
||||
content='PRIVATE!!', user=self.local_user, privacy='direct')
|
||||
content="PRIVATE!!", user=self.local_user, privacy="direct"
|
||||
)
|
||||
models.Status.objects.create(
|
||||
content='bffs ONLY', user=self.local_user, privacy='followers')
|
||||
content="bffs ONLY", user=self.local_user, privacy="followers"
|
||||
)
|
||||
models.Status.objects.create(
|
||||
content='unlisted status', user=self.local_user,
|
||||
privacy='unlisted')
|
||||
content="unlisted status", user=self.local_user, privacy="unlisted"
|
||||
)
|
||||
models.Status.objects.create(
|
||||
content='look at this', user=self.local_user, privacy='public')
|
||||
content="look at this", user=self.local_user, privacy="public"
|
||||
)
|
||||
|
||||
request = self.factory.get('')
|
||||
result = views.Outbox.as_view()(request, 'mouse')
|
||||
request = self.factory.get("")
|
||||
result = views.Outbox.as_view()(request, "mouse")
|
||||
self.assertIsInstance(result, JsonResponse)
|
||||
data = json.loads(result.content)
|
||||
self.assertEqual(data['type'], 'OrderedCollection')
|
||||
self.assertEqual(data['totalItems'], 2)
|
||||
self.assertEqual(data["type"], "OrderedCollection")
|
||||
self.assertEqual(data["totalItems"], 2)
|
||||
|
||||
def test_outbox_filter(self):
|
||||
''' if we only care about reviews, only get reviews '''
|
||||
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
|
||||
""" if we only care about reviews, only get reviews """
|
||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
|
||||
models.Review.objects.create(
|
||||
content='look at this', name='hi', rating=1,
|
||||
book=self.book, user=self.local_user)
|
||||
models.Status.objects.create(
|
||||
content='look at this', user=self.local_user)
|
||||
content="look at this",
|
||||
name="hi",
|
||||
rating=1,
|
||||
book=self.book,
|
||||
user=self.local_user,
|
||||
)
|
||||
models.Status.objects.create(content="look at this", user=self.local_user)
|
||||
|
||||
request = self.factory.get('', {'type': 'bleh'})
|
||||
result = views.Outbox.as_view()(request, 'mouse')
|
||||
request = self.factory.get("", {"type": "bleh"})
|
||||
result = views.Outbox.as_view()(request, "mouse")
|
||||
self.assertIsInstance(result, JsonResponse)
|
||||
data = json.loads(result.content)
|
||||
self.assertEqual(data['type'], 'OrderedCollection')
|
||||
self.assertEqual(data['totalItems'], 2)
|
||||
self.assertEqual(data["type"], "OrderedCollection")
|
||||
self.assertEqual(data["totalItems"], 2)
|
||||
|
||||
request = self.factory.get('', {'type': 'Review'})
|
||||
result = views.Outbox.as_view()(request, 'mouse')
|
||||
request = self.factory.get("", {"type": "Review"})
|
||||
result = views.Outbox.as_view()(request, "mouse")
|
||||
self.assertIsInstance(result, JsonResponse)
|
||||
data = json.loads(result.content)
|
||||
self.assertEqual(data['type'], 'OrderedCollection')
|
||||
self.assertEqual(data['totalItems'], 1)
|
||||
self.assertEqual(data["type"], "OrderedCollection")
|
||||
self.assertEqual(data["totalItems"], 1)
|
||||
|
||||
def test_outbox_bookwyrm_request_true(self):
|
||||
''' should differentiate between bookwyrm and outside requests '''
|
||||
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
|
||||
""" should differentiate between bookwyrm and outside requests """
|
||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
|
||||
models.Review.objects.create(
|
||||
name='hi',
|
||||
content='look at this',
|
||||
name="hi",
|
||||
content="look at this",
|
||||
user=self.local_user,
|
||||
book=self.book,
|
||||
privacy='public',
|
||||
privacy="public",
|
||||
)
|
||||
|
||||
request = self.factory.get('', {'page': 1}, HTTP_USER_AGENT=USER_AGENT)
|
||||
result = views.Outbox.as_view()(request, 'mouse')
|
||||
request = self.factory.get("", {"page": 1}, HTTP_USER_AGENT=USER_AGENT)
|
||||
result = views.Outbox.as_view()(request, "mouse")
|
||||
|
||||
data = json.loads(result.content)
|
||||
self.assertEqual(len(data['orderedItems']), 1)
|
||||
self.assertEqual(data['orderedItems'][0]['type'], 'Review')
|
||||
self.assertEqual(len(data["orderedItems"]), 1)
|
||||
self.assertEqual(data["orderedItems"][0]["type"], "Review")
|
||||
|
||||
def test_outbox_bookwyrm_request_false(self):
|
||||
''' should differentiate between bookwyrm and outside requests '''
|
||||
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
|
||||
""" should differentiate between bookwyrm and outside requests """
|
||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
|
||||
models.Review.objects.create(
|
||||
name='hi',
|
||||
content='look at this',
|
||||
name="hi",
|
||||
content="look at this",
|
||||
user=self.local_user,
|
||||
book=self.book,
|
||||
privacy='public',
|
||||
privacy="public",
|
||||
)
|
||||
|
||||
request = self.factory.get('', {'page': 1})
|
||||
result = views.Outbox.as_view()(request, 'mouse')
|
||||
request = self.factory.get("", {"page": 1})
|
||||
result = views.Outbox.as_view()(request, "mouse")
|
||||
|
||||
data = json.loads(result.content)
|
||||
self.assertEqual(len(data['orderedItems']), 1)
|
||||
self.assertEqual(data['orderedItems'][0]['type'], 'Article')
|
||||
self.assertEqual(len(data["orderedItems"]), 1)
|
||||
self.assertEqual(data["orderedItems"][0]["type"], "Article")
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
''' test for app action functionality '''
|
||||
""" test for app action functionality """
|
||||
from unittest.mock import patch
|
||||
|
||||
from django.contrib.auth.models import AnonymousUser
|
||||
@@ -10,22 +10,26 @@ from bookwyrm import models, views
|
||||
|
||||
|
||||
class PasswordViews(TestCase):
|
||||
''' view user and edit profile '''
|
||||
""" view user and edit profile """
|
||||
|
||||
def setUp(self):
|
||||
''' we need basic test data and mocks '''
|
||||
""" we need basic test data and mocks """
|
||||
self.factory = RequestFactory()
|
||||
self.local_user = models.User.objects.create_user(
|
||||
'mouse@local.com', 'mouse@mouse.com', 'password',
|
||||
local=True, localname='mouse')
|
||||
"mouse@local.com",
|
||||
"mouse@mouse.com",
|
||||
"password",
|
||||
local=True,
|
||||
localname="mouse",
|
||||
)
|
||||
self.anonymous_user = AnonymousUser
|
||||
self.anonymous_user.is_authenticated = False
|
||||
models.SiteSettings.objects.create(id=1)
|
||||
|
||||
|
||||
def test_password_reset_request(self):
|
||||
''' there are so many views, this just makes sure it LOADS '''
|
||||
""" there are so many views, this just makes sure it LOADS """
|
||||
view = views.PasswordResetRequest.as_view()
|
||||
request = self.factory.get('')
|
||||
request = self.factory.get("")
|
||||
request.user = self.local_user
|
||||
|
||||
result = view(request)
|
||||
@@ -33,76 +37,63 @@ class PasswordViews(TestCase):
|
||||
result.render()
|
||||
self.assertEqual(result.status_code, 200)
|
||||
|
||||
|
||||
def test_password_reset_request_post(self):
|
||||
''' send 'em an email '''
|
||||
request = self.factory.post('', {'email': 'aa@bb.ccc'})
|
||||
""" send 'em an email """
|
||||
request = self.factory.post("", {"email": "aa@bb.ccc"})
|
||||
view = views.PasswordResetRequest.as_view()
|
||||
resp = view(request)
|
||||
self.assertEqual(resp.status_code, 302)
|
||||
|
||||
request = self.factory.post('', {'email': 'mouse@mouse.com'})
|
||||
with patch('bookwyrm.emailing.send_email.delay'):
|
||||
request = self.factory.post("", {"email": "mouse@mouse.com"})
|
||||
with patch("bookwyrm.emailing.send_email.delay"):
|
||||
resp = view(request)
|
||||
resp.render()
|
||||
|
||||
self.assertEqual(
|
||||
models.PasswordReset.objects.get().user, self.local_user)
|
||||
self.assertEqual(models.PasswordReset.objects.get().user, self.local_user)
|
||||
|
||||
def test_password_reset(self):
|
||||
''' there are so many views, this just makes sure it LOADS '''
|
||||
""" there are so many views, this just makes sure it LOADS """
|
||||
view = views.PasswordReset.as_view()
|
||||
code = models.PasswordReset.objects.create(user=self.local_user)
|
||||
request = self.factory.get('')
|
||||
request = self.factory.get("")
|
||||
request.user = self.anonymous_user
|
||||
result = view(request, code.code)
|
||||
self.assertIsInstance(result, TemplateResponse)
|
||||
result.render()
|
||||
self.assertEqual(result.status_code, 200)
|
||||
|
||||
|
||||
def test_password_reset_post(self):
|
||||
''' reset from code '''
|
||||
""" reset from code """
|
||||
view = views.PasswordReset.as_view()
|
||||
code = models.PasswordReset.objects.create(user=self.local_user)
|
||||
request = self.factory.post('', {
|
||||
'password': 'hi',
|
||||
'confirm-password': 'hi'
|
||||
})
|
||||
with patch('bookwyrm.views.password.login'):
|
||||
request = self.factory.post("", {"password": "hi", "confirm-password": "hi"})
|
||||
with patch("bookwyrm.views.password.login"):
|
||||
resp = view(request, code.code)
|
||||
self.assertEqual(resp.status_code, 302)
|
||||
self.assertFalse(models.PasswordReset.objects.exists())
|
||||
|
||||
def test_password_reset_wrong_code(self):
|
||||
''' reset from code '''
|
||||
""" reset from code """
|
||||
view = views.PasswordReset.as_view()
|
||||
models.PasswordReset.objects.create(user=self.local_user)
|
||||
request = self.factory.post('', {
|
||||
'password': 'hi',
|
||||
'confirm-password': 'hi'
|
||||
})
|
||||
resp = view(request, 'jhgdkfjgdf')
|
||||
request = self.factory.post("", {"password": "hi", "confirm-password": "hi"})
|
||||
resp = view(request, "jhgdkfjgdf")
|
||||
resp.render()
|
||||
self.assertTrue(models.PasswordReset.objects.exists())
|
||||
|
||||
def test_password_reset_mismatch(self):
|
||||
''' reset from code '''
|
||||
""" reset from code """
|
||||
view = views.PasswordReset.as_view()
|
||||
code = models.PasswordReset.objects.create(user=self.local_user)
|
||||
request = self.factory.post('', {
|
||||
'password': 'hi',
|
||||
'confirm-password': 'hihi'
|
||||
})
|
||||
request = self.factory.post("", {"password": "hi", "confirm-password": "hihi"})
|
||||
resp = view(request, code.code)
|
||||
resp.render()
|
||||
self.assertTrue(models.PasswordReset.objects.exists())
|
||||
|
||||
|
||||
def test_password_change_get(self):
|
||||
''' there are so many views, this just makes sure it LOADS '''
|
||||
""" there are so many views, this just makes sure it LOADS """
|
||||
view = views.ChangePassword.as_view()
|
||||
request = self.factory.get('')
|
||||
request = self.factory.get("")
|
||||
request.user = self.local_user
|
||||
|
||||
result = view(request)
|
||||
@@ -110,28 +101,21 @@ class PasswordViews(TestCase):
|
||||
result.render()
|
||||
self.assertEqual(result.status_code, 200)
|
||||
|
||||
|
||||
def test_password_change(self):
|
||||
''' change password '''
|
||||
""" change password """
|
||||
view = views.ChangePassword.as_view()
|
||||
password_hash = self.local_user.password
|
||||
request = self.factory.post('', {
|
||||
'password': 'hi',
|
||||
'confirm-password': 'hi'
|
||||
})
|
||||
request = self.factory.post("", {"password": "hi", "confirm-password": "hi"})
|
||||
request.user = self.local_user
|
||||
with patch('bookwyrm.views.password.login'):
|
||||
with patch("bookwyrm.views.password.login"):
|
||||
view(request)
|
||||
self.assertNotEqual(self.local_user.password, password_hash)
|
||||
|
||||
def test_password_change_mismatch(self):
|
||||
''' change password '''
|
||||
""" change password """
|
||||
view = views.ChangePassword.as_view()
|
||||
password_hash = self.local_user.password
|
||||
request = self.factory.post('', {
|
||||
'password': 'hi',
|
||||
'confirm-password': 'hihi'
|
||||
})
|
||||
request = self.factory.post("", {"password": "hi", "confirm-password": "hihi"})
|
||||
request.user = self.local_user
|
||||
view(request)
|
||||
self.assertEqual(self.local_user.password, password_hash)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
''' test for app action functionality '''
|
||||
""" test for app action functionality """
|
||||
from unittest.mock import patch
|
||||
import dateutil
|
||||
from django.test import TestCase
|
||||
@@ -7,45 +7,54 @@ from django.utils import timezone
|
||||
|
||||
from bookwyrm import models, views
|
||||
|
||||
|
||||
class ReadingViews(TestCase):
|
||||
''' viewing and creating statuses '''
|
||||
""" viewing and creating statuses """
|
||||
|
||||
def setUp(self):
|
||||
''' we need basic test data and mocks '''
|
||||
""" 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',
|
||||
"mouse@local.com",
|
||||
"mouse@mouse.com",
|
||||
"mouseword",
|
||||
local=True,
|
||||
localname="mouse",
|
||||
remote_id="https://example.com/users/mouse",
|
||||
)
|
||||
self.work = models.Work.objects.create(title='Test Work')
|
||||
self.work = models.Work.objects.create(title="Test Work")
|
||||
self.book = models.Edition.objects.create(
|
||||
title='Test Book',
|
||||
remote_id='https://example.com/book/1',
|
||||
parent_work=self.work
|
||||
title="Test Book",
|
||||
remote_id="https://example.com/book/1",
|
||||
parent_work=self.work,
|
||||
)
|
||||
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(
|
||||
'rat', 'rat@rat.com', 'ratword',
|
||||
"rat",
|
||||
"rat@rat.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',
|
||||
remote_id="https://example.com/users/rat",
|
||||
inbox="https://example.com/users/rat/inbox",
|
||||
outbox="https://example.com/users/rat/outbox",
|
||||
)
|
||||
|
||||
|
||||
def test_start_reading(self):
|
||||
''' begin a book '''
|
||||
shelf = self.local_user.shelf_set.get(identifier='reading')
|
||||
""" begin a book """
|
||||
shelf = self.local_user.shelf_set.get(identifier="reading")
|
||||
self.assertFalse(shelf.books.exists())
|
||||
self.assertFalse(models.Status.objects.exists())
|
||||
|
||||
request = self.factory.post('', {
|
||||
'post-status': True,
|
||||
'privacy': 'followers',
|
||||
'start_date': '2020-01-05',
|
||||
})
|
||||
request = self.factory.post(
|
||||
"",
|
||||
{
|
||||
"post-status": True,
|
||||
"privacy": "followers",
|
||||
"start_date": "2020-01-05",
|
||||
},
|
||||
)
|
||||
request.user = self.local_user
|
||||
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
|
||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
|
||||
views.start_reading(request, self.book.id)
|
||||
|
||||
self.assertEqual(shelf.books.get(), self.book)
|
||||
@@ -53,7 +62,7 @@ class ReadingViews(TestCase):
|
||||
status = models.GeneratedNote.objects.get()
|
||||
self.assertEqual(status.user, self.local_user)
|
||||
self.assertEqual(status.mention_books.get(), self.book)
|
||||
self.assertEqual(status.privacy, 'followers')
|
||||
self.assertEqual(status.privacy, "followers")
|
||||
|
||||
readthrough = models.ReadThrough.objects.get()
|
||||
self.assertIsNotNone(readthrough.start_date)
|
||||
@@ -61,45 +70,47 @@ class ReadingViews(TestCase):
|
||||
self.assertEqual(readthrough.user, self.local_user)
|
||||
self.assertEqual(readthrough.book, self.book)
|
||||
|
||||
|
||||
def test_start_reading_reshelf(self):
|
||||
''' begin a book '''
|
||||
to_read_shelf = self.local_user.shelf_set.get(identifier='to-read')
|
||||
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
|
||||
""" begin a book """
|
||||
to_read_shelf = self.local_user.shelf_set.get(identifier="to-read")
|
||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
|
||||
models.ShelfBook.objects.create(
|
||||
shelf=to_read_shelf, book=self.book, user=self.local_user)
|
||||
shelf = self.local_user.shelf_set.get(identifier='reading')
|
||||
shelf=to_read_shelf, book=self.book, user=self.local_user
|
||||
)
|
||||
shelf = self.local_user.shelf_set.get(identifier="reading")
|
||||
self.assertEqual(to_read_shelf.books.get(), self.book)
|
||||
self.assertFalse(shelf.books.exists())
|
||||
self.assertFalse(models.Status.objects.exists())
|
||||
|
||||
request = self.factory.post('')
|
||||
request = self.factory.post("")
|
||||
request.user = self.local_user
|
||||
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
|
||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
|
||||
views.start_reading(request, self.book.id)
|
||||
|
||||
self.assertFalse(to_read_shelf.books.exists())
|
||||
self.assertEqual(shelf.books.get(), self.book)
|
||||
|
||||
def test_finish_reading(self):
|
||||
''' begin a book '''
|
||||
shelf = self.local_user.shelf_set.get(identifier='read')
|
||||
""" begin a book """
|
||||
shelf = self.local_user.shelf_set.get(identifier="read")
|
||||
self.assertFalse(shelf.books.exists())
|
||||
self.assertFalse(models.Status.objects.exists())
|
||||
readthrough = models.ReadThrough.objects.create(
|
||||
user=self.local_user,
|
||||
start_date=timezone.now(),
|
||||
book=self.book)
|
||||
user=self.local_user, start_date=timezone.now(), book=self.book
|
||||
)
|
||||
|
||||
request = self.factory.post('', {
|
||||
'post-status': True,
|
||||
'privacy': 'followers',
|
||||
'finish_date': '2020-01-07',
|
||||
'id': readthrough.id,
|
||||
})
|
||||
request = self.factory.post(
|
||||
"",
|
||||
{
|
||||
"post-status": True,
|
||||
"privacy": "followers",
|
||||
"finish_date": "2020-01-07",
|
||||
"id": readthrough.id,
|
||||
},
|
||||
)
|
||||
request.user = self.local_user
|
||||
|
||||
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
|
||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
|
||||
views.finish_reading(request, self.book.id)
|
||||
|
||||
self.assertEqual(shelf.books.get(), self.book)
|
||||
@@ -107,7 +118,7 @@ class ReadingViews(TestCase):
|
||||
status = models.GeneratedNote.objects.get()
|
||||
self.assertEqual(status.user, self.local_user)
|
||||
self.assertEqual(status.mention_books.get(), self.book)
|
||||
self.assertEqual(status.privacy, 'followers')
|
||||
self.assertEqual(status.privacy, "followers")
|
||||
|
||||
readthrough = models.ReadThrough.objects.get()
|
||||
self.assertIsNotNone(readthrough.start_date)
|
||||
@@ -115,19 +126,21 @@ class ReadingViews(TestCase):
|
||||
self.assertEqual(readthrough.user, self.local_user)
|
||||
self.assertEqual(readthrough.book, self.book)
|
||||
|
||||
|
||||
def test_edit_readthrough(self):
|
||||
''' adding dates to an ongoing readthrough '''
|
||||
start = timezone.make_aware(dateutil.parser.parse('2021-01-03'))
|
||||
""" adding dates to an ongoing readthrough """
|
||||
start = timezone.make_aware(dateutil.parser.parse("2021-01-03"))
|
||||
readthrough = models.ReadThrough.objects.create(
|
||||
book=self.book, user=self.local_user, start_date=start)
|
||||
book=self.book, user=self.local_user, start_date=start
|
||||
)
|
||||
request = self.factory.post(
|
||||
'', {
|
||||
'start_date': '2017-01-01',
|
||||
'finish_date': '2018-03-07',
|
||||
'book': '',
|
||||
'id': readthrough.id,
|
||||
})
|
||||
"",
|
||||
{
|
||||
"start_date": "2017-01-01",
|
||||
"finish_date": "2018-03-07",
|
||||
"book": "",
|
||||
"id": readthrough.id,
|
||||
},
|
||||
)
|
||||
request.user = self.local_user
|
||||
|
||||
views.edit_readthrough(request)
|
||||
@@ -140,33 +153,34 @@ class ReadingViews(TestCase):
|
||||
self.assertEqual(readthrough.finish_date.day, 7)
|
||||
self.assertEqual(readthrough.book, self.book)
|
||||
|
||||
|
||||
def test_delete_readthrough(self):
|
||||
''' remove a readthrough '''
|
||||
""" remove a readthrough """
|
||||
readthrough = models.ReadThrough.objects.create(
|
||||
book=self.book, user=self.local_user)
|
||||
models.ReadThrough.objects.create(
|
||||
book=self.book, user=self.local_user)
|
||||
book=self.book, user=self.local_user
|
||||
)
|
||||
models.ReadThrough.objects.create(book=self.book, user=self.local_user)
|
||||
request = self.factory.post(
|
||||
'', {
|
||||
'id': readthrough.id,
|
||||
})
|
||||
"",
|
||||
{
|
||||
"id": readthrough.id,
|
||||
},
|
||||
)
|
||||
request.user = self.local_user
|
||||
|
||||
views.delete_readthrough(request)
|
||||
self.assertFalse(
|
||||
models.ReadThrough.objects.filter(id=readthrough.id).exists())
|
||||
|
||||
self.assertFalse(models.ReadThrough.objects.filter(id=readthrough.id).exists())
|
||||
|
||||
def test_create_readthrough(self):
|
||||
''' adding new read dates '''
|
||||
""" adding new read dates """
|
||||
request = self.factory.post(
|
||||
'', {
|
||||
'start_date': '2017-01-01',
|
||||
'finish_date': '2018-03-07',
|
||||
'book': self.book.id,
|
||||
'id': '',
|
||||
})
|
||||
"",
|
||||
{
|
||||
"start_date": "2017-01-01",
|
||||
"finish_date": "2018-03-07",
|
||||
"book": self.book.id,
|
||||
"id": "",
|
||||
},
|
||||
)
|
||||
request.user = self.local_user
|
||||
|
||||
views.create_readthrough(request)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
''' tests updating reading progress '''
|
||||
""" tests updating reading progress """
|
||||
from datetime import datetime
|
||||
from unittest.mock import patch
|
||||
from django.test import TestCase, Client
|
||||
@@ -6,63 +6,68 @@ from django.utils import timezone
|
||||
|
||||
from bookwyrm import models
|
||||
|
||||
@patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay')
|
||||
|
||||
@patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay")
|
||||
class ReadThrough(TestCase):
|
||||
''' readthrough tests '''
|
||||
""" readthrough tests """
|
||||
|
||||
def setUp(self):
|
||||
''' basic user and book data '''
|
||||
""" basic user and book data """
|
||||
self.client = Client()
|
||||
|
||||
self.work = models.Work.objects.create(
|
||||
title='Example Work'
|
||||
)
|
||||
self.work = models.Work.objects.create(title="Example Work")
|
||||
|
||||
self.edition = models.Edition.objects.create(
|
||||
title='Example Edition',
|
||||
parent_work=self.work
|
||||
title="Example Edition", parent_work=self.work
|
||||
)
|
||||
self.work.default_edition = self.edition
|
||||
self.work.save()
|
||||
|
||||
self.user = models.User.objects.create_user(
|
||||
'cinco', 'cinco@example.com', 'seissiete',
|
||||
local=True, localname='cinco')
|
||||
"cinco", "cinco@example.com", "seissiete", local=True, localname="cinco"
|
||||
)
|
||||
|
||||
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
|
||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
|
||||
self.client.force_login(self.user)
|
||||
|
||||
def test_create_basic_readthrough(self, delay_mock):
|
||||
"""A basic readthrough doesn't create a progress update"""
|
||||
self.assertEqual(self.edition.readthrough_set.count(), 0)
|
||||
|
||||
self.client.post('/start-reading/{}'.format(self.edition.id), {
|
||||
'start_date': '2020-11-27',
|
||||
})
|
||||
self.client.post(
|
||||
"/start-reading/{}".format(self.edition.id),
|
||||
{
|
||||
"start_date": "2020-11-27",
|
||||
},
|
||||
)
|
||||
|
||||
readthroughs = self.edition.readthrough_set.all()
|
||||
self.assertEqual(len(readthroughs), 1)
|
||||
self.assertEqual(readthroughs[0].progressupdate_set.count(), 0)
|
||||
self.assertEqual(
|
||||
readthroughs[0].start_date,
|
||||
datetime(2020, 11, 27, tzinfo=timezone.utc))
|
||||
readthroughs[0].start_date, datetime(2020, 11, 27, tzinfo=timezone.utc)
|
||||
)
|
||||
self.assertEqual(readthroughs[0].progress, None)
|
||||
self.assertEqual(readthroughs[0].finish_date, None)
|
||||
self.assertEqual(delay_mock.call_count, 1)
|
||||
|
||||
def test_create_progress_readthrough(self, delay_mock):
|
||||
''' a readthrough with progress '''
|
||||
""" a readthrough with progress """
|
||||
self.assertEqual(self.edition.readthrough_set.count(), 0)
|
||||
|
||||
self.client.post('/start-reading/{}'.format(self.edition.id), {
|
||||
'start_date': '2020-11-27',
|
||||
'progress': 50,
|
||||
})
|
||||
self.client.post(
|
||||
"/start-reading/{}".format(self.edition.id),
|
||||
{
|
||||
"start_date": "2020-11-27",
|
||||
"progress": 50,
|
||||
},
|
||||
)
|
||||
|
||||
readthroughs = self.edition.readthrough_set.all()
|
||||
self.assertEqual(len(readthroughs), 1)
|
||||
self.assertEqual(
|
||||
readthroughs[0].start_date,
|
||||
datetime(2020, 11, 27, tzinfo=timezone.utc))
|
||||
readthroughs[0].start_date, datetime(2020, 11, 27, tzinfo=timezone.utc)
|
||||
)
|
||||
self.assertEqual(readthroughs[0].progress, 50)
|
||||
self.assertEqual(readthroughs[0].finish_date, None)
|
||||
|
||||
@@ -73,13 +78,17 @@ class ReadThrough(TestCase):
|
||||
self.assertEqual(delay_mock.call_count, 1)
|
||||
|
||||
# Update progress
|
||||
self.client.post('/edit-readthrough', {
|
||||
'id': readthroughs[0].id,
|
||||
'progress': 100,
|
||||
})
|
||||
self.client.post(
|
||||
"/edit-readthrough",
|
||||
{
|
||||
"id": readthroughs[0].id,
|
||||
"progress": 100,
|
||||
},
|
||||
)
|
||||
|
||||
progress_updates = readthroughs[0].progressupdate_set\
|
||||
.order_by('updated_date').all()
|
||||
progress_updates = (
|
||||
readthroughs[0].progressupdate_set.order_by("updated_date").all()
|
||||
)
|
||||
self.assertEqual(len(progress_updates), 2)
|
||||
self.assertEqual(progress_updates[1].mode, models.ProgressMode.PAGE)
|
||||
self.assertEqual(progress_updates[1].progress, 100)
|
||||
@@ -87,9 +96,12 @@ class ReadThrough(TestCase):
|
||||
# Edit doesn't publish anything
|
||||
self.assertEqual(delay_mock.call_count, 1)
|
||||
|
||||
self.client.post('/delete-readthrough', {
|
||||
'id': readthroughs[0].id,
|
||||
})
|
||||
self.client.post(
|
||||
"/delete-readthrough",
|
||||
{
|
||||
"id": readthroughs[0].id,
|
||||
},
|
||||
)
|
||||
|
||||
readthroughs = self.edition.readthrough_set.all()
|
||||
updates = self.user.progressupdate_set.all()
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
''' testing import '''
|
||||
""" testing import """
|
||||
|
||||
from unittest.mock import patch
|
||||
from django.test import RequestFactory, TestCase
|
||||
@@ -6,41 +6,51 @@ from django.test import RequestFactory, TestCase
|
||||
from bookwyrm import models
|
||||
from bookwyrm.views import rss_feed
|
||||
|
||||
|
||||
class RssFeedView(TestCase):
|
||||
''' rss feed behaves as expected '''
|
||||
""" rss feed behaves as expected """
|
||||
|
||||
def setUp(self):
|
||||
''' test data '''
|
||||
""" test data """
|
||||
self.site = models.SiteSettings.objects.create()
|
||||
|
||||
self.user = models.User.objects.create_user(
|
||||
'rss_user', 'rss@test.rss', 'password', local=True)
|
||||
|
||||
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
|
||||
"rss_user", "rss@test.rss", "password", local=True
|
||||
)
|
||||
|
||||
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
|
||||
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,
|
||||
)
|
||||
|
||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
|
||||
self.review = models.Review.objects.create(
|
||||
name='Review name', content='test content', rating=3,
|
||||
user=self.user, book=self.book)
|
||||
name="Review name",
|
||||
content="test content",
|
||||
rating=3,
|
||||
user=self.user,
|
||||
book=self.book,
|
||||
)
|
||||
|
||||
self.quote = models.Quotation.objects.create(
|
||||
quote='a sickening sense', content='test content',
|
||||
user=self.user, book=self.book)
|
||||
quote="a sickening sense",
|
||||
content="test content",
|
||||
user=self.user,
|
||||
book=self.book,
|
||||
)
|
||||
|
||||
self.generatednote = models.GeneratedNote.objects.create(
|
||||
content='test content', user=self.user)
|
||||
content="test content", user=self.user
|
||||
)
|
||||
|
||||
self.factory = RequestFactory()
|
||||
|
||||
|
||||
def test_rss_feed(self):
|
||||
''' load an rss feed '''
|
||||
""" load an rss feed """
|
||||
view = rss_feed.RssFeed()
|
||||
request = self.factory.get('/user/rss_user/rss')
|
||||
request = self.factory.get("/user/rss_user/rss")
|
||||
request.user = self.user
|
||||
with patch("bookwyrm.models.SiteSettings.objects.get") as site:
|
||||
site.return_value = self.site
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
''' test for app action functionality '''
|
||||
""" test for app action functionality """
|
||||
import json
|
||||
from unittest.mock import patch
|
||||
|
||||
@@ -13,103 +13,107 @@ from bookwyrm.settings import DOMAIN
|
||||
|
||||
|
||||
class ShelfViews(TestCase):
|
||||
''' tag views'''
|
||||
""" tag views"""
|
||||
|
||||
def setUp(self):
|
||||
''' we need basic test data and mocks '''
|
||||
""" 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',
|
||||
"mouse@local.com",
|
||||
"mouse@mouse.com",
|
||||
"mouseword",
|
||||
local=True,
|
||||
localname="mouse",
|
||||
remote_id="https://example.com/users/mouse",
|
||||
)
|
||||
self.work = models.Work.objects.create(title='Test Work')
|
||||
self.work = models.Work.objects.create(title="Test Work")
|
||||
self.book = models.Edition.objects.create(
|
||||
title='Test Book',
|
||||
remote_id='https://example.com/book/1',
|
||||
parent_work=self.work
|
||||
title="Test Book",
|
||||
remote_id="https://example.com/book/1",
|
||||
parent_work=self.work,
|
||||
)
|
||||
models.Connector.objects.create(
|
||||
identifier='self',
|
||||
connector_file='self_connector',
|
||||
local=True
|
||||
identifier="self", connector_file="self_connector", local=True
|
||||
)
|
||||
models.SiteSettings.objects.create()
|
||||
|
||||
|
||||
def test_search_json_response(self):
|
||||
''' searches local data only and returns book data in json format '''
|
||||
""" searches local data only and returns book data in json format """
|
||||
view = views.Search.as_view()
|
||||
# we need a connector for this, sorry
|
||||
request = self.factory.get('', {'q': 'Test Book'})
|
||||
with patch('bookwyrm.views.search.is_api_request') as is_api:
|
||||
request = self.factory.get("", {"q": "Test Book"})
|
||||
with patch("bookwyrm.views.search.is_api_request") as is_api:
|
||||
is_api.return_value = True
|
||||
response = view(request)
|
||||
self.assertIsInstance(response, JsonResponse)
|
||||
|
||||
data = json.loads(response.content)
|
||||
self.assertEqual(len(data), 1)
|
||||
self.assertEqual(data[0]['title'], 'Test Book')
|
||||
self.assertEqual(
|
||||
data[0]['key'], 'https://%s/book/%d' % (DOMAIN, self.book.id))
|
||||
|
||||
self.assertEqual(data[0]["title"], "Test Book")
|
||||
self.assertEqual(data[0]["key"], "https://%s/book/%d" % (DOMAIN, self.book.id))
|
||||
|
||||
def test_search_html_response(self):
|
||||
''' searches remote connectors '''
|
||||
""" searches remote connectors """
|
||||
view = views.Search.as_view()
|
||||
|
||||
class TestConnector(abstract_connector.AbstractMinimalConnector):
|
||||
''' nothing added here '''
|
||||
""" nothing added here """
|
||||
|
||||
def format_search_result(self, search_result):
|
||||
pass
|
||||
|
||||
def get_or_create_book(self, remote_id):
|
||||
pass
|
||||
|
||||
def parse_search_data(self, data):
|
||||
pass
|
||||
|
||||
def format_isbn_search_result(self, search_result):
|
||||
return search_result
|
||||
|
||||
def parse_isbn_search_data(self, data):
|
||||
return data
|
||||
|
||||
models.Connector.objects.create(
|
||||
identifier='example.com',
|
||||
connector_file='openlibrary',
|
||||
base_url='https://example.com',
|
||||
books_url='https://example.com/books',
|
||||
covers_url='https://example.com/covers',
|
||||
search_url='https://example.com/search?q=',
|
||||
identifier="example.com",
|
||||
connector_file="openlibrary",
|
||||
base_url="https://example.com",
|
||||
books_url="https://example.com/books",
|
||||
covers_url="https://example.com/covers",
|
||||
search_url="https://example.com/search?q=",
|
||||
)
|
||||
connector = TestConnector('example.com')
|
||||
connector = TestConnector("example.com")
|
||||
|
||||
search_result = abstract_connector.SearchResult(
|
||||
key='http://www.example.com/book/1',
|
||||
title='Gideon the Ninth',
|
||||
author='Tamsyn Muir',
|
||||
year='2019',
|
||||
connector=connector
|
||||
key="http://www.example.com/book/1",
|
||||
title="Gideon the Ninth",
|
||||
author="Tamsyn Muir",
|
||||
year="2019",
|
||||
connector=connector,
|
||||
)
|
||||
|
||||
request = self.factory.get('', {'q': 'Test Book'})
|
||||
request = self.factory.get("", {"q": "Test Book"})
|
||||
request.user = self.local_user
|
||||
with patch('bookwyrm.views.search.is_api_request') as is_api:
|
||||
with patch("bookwyrm.views.search.is_api_request") as is_api:
|
||||
is_api.return_value = False
|
||||
with patch(
|
||||
'bookwyrm.connectors.connector_manager.search') as manager:
|
||||
with patch("bookwyrm.connectors.connector_manager.search") as manager:
|
||||
manager.return_value = [search_result]
|
||||
response = view(request)
|
||||
self.assertIsInstance(response, TemplateResponse)
|
||||
response.render()
|
||||
self.assertEqual(
|
||||
response.context_data['book_results'][0].title, 'Gideon the Ninth')
|
||||
|
||||
response.context_data["book_results"][0].title, "Gideon the Ninth"
|
||||
)
|
||||
|
||||
def test_search_html_response_users(self):
|
||||
''' searches remote connectors '''
|
||||
""" searches remote connectors """
|
||||
view = views.Search.as_view()
|
||||
request = self.factory.get('', {'q': 'mouse'})
|
||||
request = self.factory.get("", {"q": "mouse"})
|
||||
request.user = self.local_user
|
||||
with patch('bookwyrm.views.search.is_api_request') as is_api:
|
||||
with patch("bookwyrm.views.search.is_api_request") as is_api:
|
||||
is_api.return_value = False
|
||||
with patch('bookwyrm.connectors.connector_manager.search'):
|
||||
with patch("bookwyrm.connectors.connector_manager.search"):
|
||||
response = view(request)
|
||||
self.assertIsInstance(response, TemplateResponse)
|
||||
response.render()
|
||||
self.assertEqual(
|
||||
response.context_data['user_results'][0], self.local_user)
|
||||
self.assertEqual(response.context_data["user_results"][0], self.local_user)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
''' test for app action functionality '''
|
||||
""" test for app action functionality """
|
||||
from unittest.mock import patch
|
||||
from django.template.response import TemplateResponse
|
||||
from django.test import TestCase
|
||||
@@ -8,195 +8,172 @@ from bookwyrm import models, views
|
||||
from bookwyrm.activitypub import ActivitypubResponse
|
||||
|
||||
|
||||
@patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay')
|
||||
@patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay")
|
||||
class ShelfViews(TestCase):
|
||||
''' tag views'''
|
||||
""" tag views"""
|
||||
|
||||
def setUp(self):
|
||||
''' we need basic test data and mocks '''
|
||||
""" 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',
|
||||
"mouse@local.com",
|
||||
"mouse@mouse.com",
|
||||
"mouseword",
|
||||
local=True,
|
||||
localname="mouse",
|
||||
remote_id="https://example.com/users/mouse",
|
||||
)
|
||||
self.work = models.Work.objects.create(title='Test Work')
|
||||
self.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
|
||||
title="Example Edition",
|
||||
remote_id="https://example.com/book/1",
|
||||
parent_work=self.work,
|
||||
)
|
||||
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
|
||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
|
||||
self.shelf = models.Shelf.objects.create(
|
||||
name='Test Shelf',
|
||||
identifier='test-shelf',
|
||||
user=self.local_user
|
||||
name="Test Shelf", identifier="test-shelf", user=self.local_user
|
||||
)
|
||||
models.SiteSettings.objects.create()
|
||||
|
||||
|
||||
def test_shelf_page(self, _):
|
||||
''' there are so many views, this just makes sure it LOADS '''
|
||||
""" there are so many views, this just makes sure it LOADS """
|
||||
view = views.Shelf.as_view()
|
||||
shelf = self.local_user.shelf_set.first()
|
||||
request = self.factory.get('')
|
||||
request = self.factory.get("")
|
||||
request.user = self.local_user
|
||||
with patch('bookwyrm.views.shelf.is_api_request') as is_api:
|
||||
with patch("bookwyrm.views.shelf.is_api_request") as is_api:
|
||||
is_api.return_value = False
|
||||
result = view(request, self.local_user.username, shelf.identifier)
|
||||
self.assertIsInstance(result, TemplateResponse)
|
||||
result.render()
|
||||
self.assertEqual(result.status_code, 200)
|
||||
|
||||
with patch('bookwyrm.views.shelf.is_api_request') as is_api:
|
||||
with patch("bookwyrm.views.shelf.is_api_request") as is_api:
|
||||
is_api.return_value = True
|
||||
result = view(
|
||||
request, self.local_user.username, shelf.identifier)
|
||||
result = view(request, self.local_user.username, shelf.identifier)
|
||||
self.assertIsInstance(result, ActivitypubResponse)
|
||||
self.assertEqual(result.status_code, 200)
|
||||
|
||||
request = self.factory.get('/?page=1')
|
||||
request = self.factory.get("/?page=1")
|
||||
request.user = self.local_user
|
||||
with patch('bookwyrm.views.shelf.is_api_request') as is_api:
|
||||
with patch("bookwyrm.views.shelf.is_api_request") as is_api:
|
||||
is_api.return_value = True
|
||||
result = view(
|
||||
request, self.local_user.username, shelf.identifier)
|
||||
result = view(request, self.local_user.username, shelf.identifier)
|
||||
self.assertIsInstance(result, ActivitypubResponse)
|
||||
self.assertEqual(result.status_code, 200)
|
||||
|
||||
|
||||
def test_edit_shelf_privacy(self, _):
|
||||
''' set name or privacy on shelf '''
|
||||
""" set name or privacy on shelf """
|
||||
view = views.Shelf.as_view()
|
||||
shelf = self.local_user.shelf_set.get(identifier='to-read')
|
||||
self.assertEqual(shelf.privacy, 'public')
|
||||
shelf = self.local_user.shelf_set.get(identifier="to-read")
|
||||
self.assertEqual(shelf.privacy, "public")
|
||||
|
||||
request = self.factory.post(
|
||||
'', {
|
||||
'privacy': 'unlisted',
|
||||
'user': self.local_user.id,
|
||||
'name': 'To Read',
|
||||
})
|
||||
"",
|
||||
{
|
||||
"privacy": "unlisted",
|
||||
"user": self.local_user.id,
|
||||
"name": "To Read",
|
||||
},
|
||||
)
|
||||
request.user = self.local_user
|
||||
view(request, self.local_user.username, shelf.identifier)
|
||||
shelf.refresh_from_db()
|
||||
|
||||
self.assertEqual(shelf.privacy, 'unlisted')
|
||||
|
||||
self.assertEqual(shelf.privacy, "unlisted")
|
||||
|
||||
def test_edit_shelf_name(self, _):
|
||||
''' change the name of an editable shelf '''
|
||||
""" change the name of an editable shelf """
|
||||
view = views.Shelf.as_view()
|
||||
shelf = models.Shelf.objects.create(
|
||||
name='Test Shelf', user=self.local_user)
|
||||
self.assertEqual(shelf.privacy, 'public')
|
||||
shelf = models.Shelf.objects.create(name="Test Shelf", user=self.local_user)
|
||||
self.assertEqual(shelf.privacy, "public")
|
||||
|
||||
request = self.factory.post(
|
||||
'', {
|
||||
'privacy': 'public',
|
||||
'user': self.local_user.id,
|
||||
'name': 'cool name'
|
||||
})
|
||||
"", {"privacy": "public", "user": self.local_user.id, "name": "cool name"}
|
||||
)
|
||||
request.user = self.local_user
|
||||
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
|
||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
|
||||
view(request, request.user.username, shelf.identifier)
|
||||
shelf.refresh_from_db()
|
||||
|
||||
self.assertEqual(shelf.name, 'cool name')
|
||||
self.assertEqual(shelf.identifier, 'testshelf-%d' % shelf.id)
|
||||
|
||||
self.assertEqual(shelf.name, "cool name")
|
||||
self.assertEqual(shelf.identifier, "testshelf-%d" % shelf.id)
|
||||
|
||||
def test_edit_shelf_name_not_editable(self, _):
|
||||
''' can't change the name of an non-editable shelf '''
|
||||
""" can't change the name of an non-editable shelf """
|
||||
view = views.Shelf.as_view()
|
||||
shelf = self.local_user.shelf_set.get(identifier='to-read')
|
||||
self.assertEqual(shelf.privacy, 'public')
|
||||
shelf = self.local_user.shelf_set.get(identifier="to-read")
|
||||
self.assertEqual(shelf.privacy, "public")
|
||||
|
||||
request = self.factory.post(
|
||||
'', {
|
||||
'privacy': 'public',
|
||||
'user': self.local_user.id,
|
||||
'name': 'cool name'
|
||||
})
|
||||
"", {"privacy": "public", "user": self.local_user.id, "name": "cool name"}
|
||||
)
|
||||
request.user = self.local_user
|
||||
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
|
||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
|
||||
view(request, request.user.username, shelf.identifier)
|
||||
|
||||
self.assertEqual(shelf.name, 'To Read')
|
||||
|
||||
self.assertEqual(shelf.name, "To Read")
|
||||
|
||||
def test_handle_shelve(self, _):
|
||||
''' shelve a book '''
|
||||
request = self.factory.post('', {
|
||||
'book': self.book.id,
|
||||
'shelf': self.shelf.identifier
|
||||
})
|
||||
""" shelve a book """
|
||||
request = self.factory.post(
|
||||
"", {"book": self.book.id, "shelf": self.shelf.identifier}
|
||||
)
|
||||
request.user = self.local_user
|
||||
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
|
||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
|
||||
views.shelve(request)
|
||||
# make sure the book is on the shelf
|
||||
self.assertEqual(self.shelf.books.get(), self.book)
|
||||
|
||||
|
||||
def test_handle_shelve_to_read(self, _):
|
||||
''' special behavior for the to-read shelf '''
|
||||
shelf = models.Shelf.objects.get(identifier='to-read')
|
||||
request = self.factory.post('', {
|
||||
'book': self.book.id,
|
||||
'shelf': shelf.identifier
|
||||
})
|
||||
""" special behavior for the to-read shelf """
|
||||
shelf = models.Shelf.objects.get(identifier="to-read")
|
||||
request = self.factory.post(
|
||||
"", {"book": self.book.id, "shelf": shelf.identifier}
|
||||
)
|
||||
request.user = self.local_user
|
||||
|
||||
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
|
||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
|
||||
views.shelve(request)
|
||||
# make sure the book is on the shelf
|
||||
self.assertEqual(shelf.books.get(), self.book)
|
||||
|
||||
|
||||
def test_handle_shelve_reading(self, _):
|
||||
''' special behavior for the reading shelf '''
|
||||
shelf = models.Shelf.objects.get(identifier='reading')
|
||||
request = self.factory.post('', {
|
||||
'book': self.book.id,
|
||||
'shelf': shelf.identifier
|
||||
})
|
||||
""" special behavior for the reading shelf """
|
||||
shelf = models.Shelf.objects.get(identifier="reading")
|
||||
request = self.factory.post(
|
||||
"", {"book": self.book.id, "shelf": shelf.identifier}
|
||||
)
|
||||
request.user = self.local_user
|
||||
|
||||
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
|
||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
|
||||
views.shelve(request)
|
||||
# make sure the book is on the shelf
|
||||
self.assertEqual(shelf.books.get(), self.book)
|
||||
|
||||
|
||||
def test_handle_shelve_read(self, _):
|
||||
''' special behavior for the read shelf '''
|
||||
shelf = models.Shelf.objects.get(identifier='read')
|
||||
request = self.factory.post('', {
|
||||
'book': self.book.id,
|
||||
'shelf': shelf.identifier
|
||||
})
|
||||
""" special behavior for the read shelf """
|
||||
shelf = models.Shelf.objects.get(identifier="read")
|
||||
request = self.factory.post(
|
||||
"", {"book": self.book.id, "shelf": shelf.identifier}
|
||||
)
|
||||
request.user = self.local_user
|
||||
|
||||
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
|
||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
|
||||
views.shelve(request)
|
||||
# make sure the book is on the shelf
|
||||
self.assertEqual(shelf.books.get(), self.book)
|
||||
|
||||
|
||||
def test_handle_unshelve(self, _):
|
||||
''' remove a book from a shelf '''
|
||||
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
|
||||
""" remove a book from a shelf """
|
||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
|
||||
models.ShelfBook.objects.create(
|
||||
book=self.book,
|
||||
user=self.local_user,
|
||||
shelf=self.shelf
|
||||
book=self.book, user=self.local_user, shelf=self.shelf
|
||||
)
|
||||
self.shelf.save()
|
||||
self.assertEqual(self.shelf.books.count(), 1)
|
||||
request = self.factory.post('', {
|
||||
'book': self.book.id,
|
||||
'shelf': self.shelf.id
|
||||
})
|
||||
request = self.factory.post("", {"book": self.book.id, "shelf": self.shelf.id})
|
||||
request.user = self.local_user
|
||||
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
|
||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
|
||||
views.unshelve(request)
|
||||
self.assertEqual(self.shelf.books.count(), 0)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
''' test for app action functionality '''
|
||||
""" test for app action functionality """
|
||||
import json
|
||||
from unittest.mock import patch
|
||||
from django.test import TestCase
|
||||
@@ -9,239 +9,247 @@ from bookwyrm.settings import DOMAIN
|
||||
|
||||
|
||||
class StatusViews(TestCase):
|
||||
''' viewing and creating statuses '''
|
||||
""" viewing and creating statuses """
|
||||
|
||||
def setUp(self):
|
||||
''' we need basic test data and mocks '''
|
||||
""" 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',
|
||||
"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'):
|
||||
with patch("bookwyrm.models.user.set_remote_server"):
|
||||
self.remote_user = models.User.objects.create_user(
|
||||
'rat', 'rat@email.com', 'ratword',
|
||||
"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',
|
||||
remote_id="https://example.com/users/rat",
|
||||
inbox="https://example.com/users/rat/inbox",
|
||||
outbox="https://example.com/users/rat/outbox",
|
||||
)
|
||||
|
||||
work = models.Work.objects.create(title='Test Work')
|
||||
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
|
||||
title="Example Edition",
|
||||
remote_id="https://example.com/book/1",
|
||||
parent_work=work,
|
||||
)
|
||||
|
||||
|
||||
def test_handle_status(self):
|
||||
''' create a status '''
|
||||
""" create a status """
|
||||
view = views.CreateStatus.as_view()
|
||||
form = forms.CommentForm({
|
||||
'content': 'hi',
|
||||
'user': self.local_user.id,
|
||||
'book': self.book.id,
|
||||
'privacy': 'public',
|
||||
})
|
||||
request = self.factory.post('', form.data)
|
||||
form = forms.CommentForm(
|
||||
{
|
||||
"content": "hi",
|
||||
"user": self.local_user.id,
|
||||
"book": self.book.id,
|
||||
"privacy": "public",
|
||||
}
|
||||
)
|
||||
request = self.factory.post("", form.data)
|
||||
request.user = self.local_user
|
||||
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
|
||||
view(request, 'comment')
|
||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
|
||||
view(request, "comment")
|
||||
status = models.Comment.objects.get()
|
||||
self.assertEqual(status.content, '<p>hi</p>')
|
||||
self.assertEqual(status.content, "<p>hi</p>")
|
||||
self.assertEqual(status.user, self.local_user)
|
||||
self.assertEqual(status.book, self.book)
|
||||
|
||||
def test_handle_status_reply(self):
|
||||
''' create a status in reply to an existing status '''
|
||||
""" create a status in reply to an existing status """
|
||||
view = views.CreateStatus.as_view()
|
||||
user = models.User.objects.create_user(
|
||||
'rat', 'rat@rat.com', 'password', local=True)
|
||||
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
|
||||
"rat", "rat@rat.com", "password", local=True
|
||||
)
|
||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
|
||||
parent = models.Status.objects.create(
|
||||
content='parent status', user=self.local_user)
|
||||
form = forms.ReplyForm({
|
||||
'content': 'hi',
|
||||
'user': user.id,
|
||||
'reply_parent': parent.id,
|
||||
'privacy': 'public',
|
||||
})
|
||||
request = self.factory.post('', form.data)
|
||||
content="parent status", user=self.local_user
|
||||
)
|
||||
form = forms.ReplyForm(
|
||||
{
|
||||
"content": "hi",
|
||||
"user": user.id,
|
||||
"reply_parent": parent.id,
|
||||
"privacy": "public",
|
||||
}
|
||||
)
|
||||
request = self.factory.post("", form.data)
|
||||
request.user = user
|
||||
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
|
||||
view(request, 'reply')
|
||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
|
||||
view(request, "reply")
|
||||
status = models.Status.objects.get(user=user)
|
||||
self.assertEqual(status.content, '<p>hi</p>')
|
||||
self.assertEqual(status.content, "<p>hi</p>")
|
||||
self.assertEqual(status.user, user)
|
||||
self.assertEqual(
|
||||
models.Notification.objects.get().user, self.local_user)
|
||||
self.assertEqual(models.Notification.objects.get().user, self.local_user)
|
||||
|
||||
def test_handle_status_mentions(self):
|
||||
''' @mention a user in a post '''
|
||||
""" @mention a user in a post """
|
||||
view = views.CreateStatus.as_view()
|
||||
user = models.User.objects.create_user(
|
||||
'rat@%s' % DOMAIN, 'rat@rat.com', 'password',
|
||||
local=True, localname='rat')
|
||||
form = forms.CommentForm({
|
||||
'content': 'hi @rat',
|
||||
'user': self.local_user.id,
|
||||
'book': self.book.id,
|
||||
'privacy': 'public',
|
||||
})
|
||||
request = self.factory.post('', form.data)
|
||||
"rat@%s" % DOMAIN, "rat@rat.com", "password", local=True, localname="rat"
|
||||
)
|
||||
form = forms.CommentForm(
|
||||
{
|
||||
"content": "hi @rat",
|
||||
"user": self.local_user.id,
|
||||
"book": self.book.id,
|
||||
"privacy": "public",
|
||||
}
|
||||
)
|
||||
request = self.factory.post("", form.data)
|
||||
request.user = self.local_user
|
||||
|
||||
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
|
||||
view(request, 'comment')
|
||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
|
||||
view(request, "comment")
|
||||
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,
|
||||
'<p>hi <a href="%s">@rat</a></p>' % user.remote_id)
|
||||
status.content, '<p>hi <a href="%s">@rat</a></p>' % user.remote_id
|
||||
)
|
||||
|
||||
def test_handle_status_reply_with_mentions(self):
|
||||
''' reply to a post with an @mention'ed user '''
|
||||
""" reply to a post with an @mention'ed user """
|
||||
view = views.CreateStatus.as_view()
|
||||
user = models.User.objects.create_user(
|
||||
'rat', 'rat@rat.com', 'password',
|
||||
local=True, localname='rat')
|
||||
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)
|
||||
"rat", "rat@rat.com", "password", local=True, localname="rat"
|
||||
)
|
||||
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)
|
||||
request.user = self.local_user
|
||||
|
||||
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
|
||||
view(request, 'comment')
|
||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
|
||||
view(request, "comment")
|
||||
status = models.Status.objects.get()
|
||||
|
||||
form = forms.ReplyForm({
|
||||
'content': 'right',
|
||||
'user': user.id,
|
||||
'privacy': 'public',
|
||||
'reply_parent': status.id
|
||||
})
|
||||
request = self.factory.post('', form.data)
|
||||
form = forms.ReplyForm(
|
||||
{
|
||||
"content": "right",
|
||||
"user": user.id,
|
||||
"privacy": "public",
|
||||
"reply_parent": status.id,
|
||||
}
|
||||
)
|
||||
request = self.factory.post("", form.data)
|
||||
request.user = user
|
||||
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
|
||||
view(request, 'reply')
|
||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
|
||||
view(request, "reply")
|
||||
|
||||
reply = models.Status.replies(status).first()
|
||||
self.assertEqual(reply.content, '<p>right</p>')
|
||||
self.assertEqual(reply.content, "<p>right</p>")
|
||||
self.assertEqual(reply.user, user)
|
||||
# the mentioned user in the parent post is only included if @'ed
|
||||
self.assertFalse(self.remote_user in reply.mention_users.all())
|
||||
self.assertTrue(self.local_user in reply.mention_users.all())
|
||||
|
||||
def test_find_mentions(self):
|
||||
''' detect and look up @ mentions of users '''
|
||||
""" detect and look up @ mentions of users """
|
||||
user = models.User.objects.create_user(
|
||||
'nutria@%s' % DOMAIN, 'nutria@nutria.com', 'password',
|
||||
local=True, localname='nutria')
|
||||
self.assertEqual(user.username, 'nutria@%s' % DOMAIN)
|
||||
"nutria@%s" % DOMAIN,
|
||||
"nutria@nutria.com",
|
||||
"password",
|
||||
local=True,
|
||||
localname="nutria",
|
||||
)
|
||||
self.assertEqual(user.username, "nutria@%s" % DOMAIN)
|
||||
|
||||
self.assertEqual(
|
||||
list(views.status.find_mentions('@nutria'))[0],
|
||||
('@nutria', user)
|
||||
list(views.status.find_mentions("@nutria"))[0], ("@nutria", user)
|
||||
)
|
||||
self.assertEqual(
|
||||
list(views.status.find_mentions('leading text @nutria'))[0],
|
||||
('@nutria', user)
|
||||
list(views.status.find_mentions("leading text @nutria"))[0],
|
||||
("@nutria", user),
|
||||
)
|
||||
self.assertEqual(
|
||||
list(views.status.find_mentions(
|
||||
'leading @nutria trailing text'))[0],
|
||||
('@nutria', user)
|
||||
list(views.status.find_mentions("leading @nutria trailing text"))[0],
|
||||
("@nutria", user),
|
||||
)
|
||||
self.assertEqual(
|
||||
list(views.status.find_mentions(
|
||||
'@rat@example.com'))[0],
|
||||
('@rat@example.com', self.remote_user)
|
||||
list(views.status.find_mentions("@rat@example.com"))[0],
|
||||
("@rat@example.com", self.remote_user),
|
||||
)
|
||||
|
||||
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))
|
||||
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))
|
||||
|
||||
with patch('bookwyrm.views.status.handle_remote_webfinger') as rw:
|
||||
with patch("bookwyrm.views.status.handle_remote_webfinger") as rw:
|
||||
rw.return_value = self.local_user
|
||||
self.assertEqual(
|
||||
list(views.status.find_mentions('@beep@beep.com'))[0],
|
||||
('@beep@beep.com', self.local_user)
|
||||
list(views.status.find_mentions("@beep@beep.com"))[0],
|
||||
("@beep@beep.com", self.local_user),
|
||||
)
|
||||
with patch('bookwyrm.views.status.handle_remote_webfinger') as rw:
|
||||
with patch("bookwyrm.views.status.handle_remote_webfinger") as rw:
|
||||
rw.return_value = None
|
||||
self.assertEqual(list(views.status.find_mentions(
|
||||
'@beep@beep.com')), [])
|
||||
self.assertEqual(list(views.status.find_mentions("@beep@beep.com")), [])
|
||||
|
||||
self.assertEqual(
|
||||
list(views.status.find_mentions('@nutria@%s' % DOMAIN))[0],
|
||||
('@nutria@%s' % DOMAIN, user)
|
||||
list(views.status.find_mentions("@nutria@%s" % DOMAIN))[0],
|
||||
("@nutria@%s" % DOMAIN, user),
|
||||
)
|
||||
|
||||
def test_format_links(self):
|
||||
''' find and format urls into a tags '''
|
||||
url = 'http://www.fish.com/'
|
||||
""" find and format urls into a tags """
|
||||
url = "http://www.fish.com/"
|
||||
self.assertEqual(
|
||||
views.status.format_links(url), '<a href="%s">www.fish.com/</a>' % url
|
||||
)
|
||||
self.assertEqual(
|
||||
views.status.format_links("(%s)" % url),
|
||||
'(<a href="%s">www.fish.com/</a>)' % url,
|
||||
)
|
||||
url = "https://archive.org/details/dli.granth.72113/page/n25/mode/2up"
|
||||
self.assertEqual(
|
||||
views.status.format_links(url),
|
||||
'<a href="%s">www.fish.com/</a>' % url)
|
||||
self.assertEqual(
|
||||
views.status.format_links('(%s)' % url),
|
||||
'(<a href="%s">www.fish.com/</a>)' % url)
|
||||
url = 'https://archive.org/details/dli.granth.72113/page/n25/mode/2up'
|
||||
'<a href="%s">'
|
||||
"archive.org/details/dli.granth.72113/page/n25/mode/2up</a>" % url,
|
||||
)
|
||||
url = "https://openlibrary.org/search" "?q=arkady+strugatsky&mode=everything"
|
||||
self.assertEqual(
|
||||
views.status.format_links(url),
|
||||
'<a href="%s">' \
|
||||
'archive.org/details/dli.granth.72113/page/n25/mode/2up</a>' \
|
||||
% url)
|
||||
url = 'https://openlibrary.org/search' \
|
||||
'?q=arkady+strugatsky&mode=everything'
|
||||
self.assertEqual(
|
||||
views.status.format_links(url),
|
||||
'<a href="%s">openlibrary.org/search' \
|
||||
'?q=arkady+strugatsky&mode=everything</a>' % url)
|
||||
|
||||
'<a href="%s">openlibrary.org/search'
|
||||
"?q=arkady+strugatsky&mode=everything</a>" % url,
|
||||
)
|
||||
|
||||
def test_to_markdown(self):
|
||||
''' this is mostly handled in other places, but nonetheless '''
|
||||
text = '_hi_ and http://fish.com is <marquee>rad</marquee>'
|
||||
""" this is mostly handled in other places, but nonetheless """
|
||||
text = "_hi_ and http://fish.com is <marquee>rad</marquee>"
|
||||
result = views.status.to_markdown(text)
|
||||
self.assertEqual(
|
||||
result,
|
||||
'<p><em>hi</em> and <a href="http://fish.com">fish.com</a> ' \
|
||||
'is rad</p>')
|
||||
|
||||
'<p><em>hi</em> and <a href="http://fish.com">fish.com</a> ' "is rad</p>",
|
||||
)
|
||||
|
||||
def test_to_markdown_link(self):
|
||||
''' this is mostly handled in other places, but nonetheless '''
|
||||
text = '[hi](http://fish.com) is <marquee>rad</marquee>'
|
||||
""" this is mostly handled in other places, but nonetheless """
|
||||
text = "[hi](http://fish.com) is <marquee>rad</marquee>"
|
||||
result = views.status.to_markdown(text)
|
||||
self.assertEqual(
|
||||
result,
|
||||
'<p><a href="http://fish.com">hi</a> ' \
|
||||
'is rad</p>')
|
||||
|
||||
self.assertEqual(result, '<p><a href="http://fish.com">hi</a> ' "is rad</p>")
|
||||
|
||||
def test_handle_delete_status(self):
|
||||
''' marks a status as deleted '''
|
||||
""" marks a status as deleted """
|
||||
view = views.DeleteStatus.as_view()
|
||||
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
|
||||
status = models.Status.objects.create(
|
||||
user=self.local_user, content='hi')
|
||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
|
||||
status = models.Status.objects.create(user=self.local_user, content="hi")
|
||||
self.assertFalse(status.deleted)
|
||||
request = self.factory.post('')
|
||||
request = self.factory.post("")
|
||||
request.user = self.local_user
|
||||
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay') \
|
||||
as mock:
|
||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay") as mock:
|
||||
view(request, status.id)
|
||||
activity = json.loads(mock.call_args_list[0][0][1])
|
||||
self.assertEqual(activity['type'], 'Delete')
|
||||
self.assertEqual(activity['object']['type'], 'Tombstone')
|
||||
self.assertEqual(activity["type"], "Delete")
|
||||
self.assertEqual(activity["object"]["type"], "Tombstone")
|
||||
status.refresh_from_db()
|
||||
self.assertTrue(status.deleted)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
''' test for app action functionality '''
|
||||
""" 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
|
||||
@@ -11,107 +11,109 @@ from bookwyrm.activitypub import ActivitypubResponse
|
||||
|
||||
|
||||
class TagViews(TestCase):
|
||||
''' tag views'''
|
||||
""" tag views"""
|
||||
|
||||
def setUp(self):
|
||||
''' we need basic test data and mocks '''
|
||||
""" 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',
|
||||
"mouse@local.com",
|
||||
"mouse@mouse.com",
|
||||
"mouseword",
|
||||
local=True,
|
||||
localname="mouse",
|
||||
remote_id="https://example.com/users/mouse",
|
||||
)
|
||||
self.group = Group.objects.create(name='editor')
|
||||
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
|
||||
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.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
|
||||
title="Example Edition",
|
||||
remote_id="https://example.com/book/1",
|
||||
parent_work=self.work,
|
||||
)
|
||||
models.SiteSettings.objects.create()
|
||||
|
||||
|
||||
def test_tag_page(self):
|
||||
''' there are so many views, this just makes sure it LOADS '''
|
||||
""" there are so many views, this just makes sure it LOADS """
|
||||
view = views.Tag.as_view()
|
||||
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
|
||||
tag = models.Tag.objects.create(name='hi there')
|
||||
models.UserTag.objects.create(
|
||||
tag=tag, user=self.local_user, book=self.book)
|
||||
request = self.factory.get('')
|
||||
with patch('bookwyrm.views.tag.is_api_request') as is_api:
|
||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
|
||||
tag = models.Tag.objects.create(name="hi there")
|
||||
models.UserTag.objects.create(tag=tag, user=self.local_user, book=self.book)
|
||||
request = self.factory.get("")
|
||||
with patch("bookwyrm.views.tag.is_api_request") as is_api:
|
||||
is_api.return_value = False
|
||||
result = view(request, tag.identifier)
|
||||
self.assertIsInstance(result, TemplateResponse)
|
||||
result.render()
|
||||
self.assertEqual(result.status_code, 200)
|
||||
|
||||
request = self.factory.get('')
|
||||
with patch('bookwyrm.views.tag.is_api_request') as is_api:
|
||||
request = self.factory.get("")
|
||||
with patch("bookwyrm.views.tag.is_api_request") as is_api:
|
||||
is_api.return_value = True
|
||||
result = view(request, tag.identifier)
|
||||
self.assertIsInstance(result, ActivitypubResponse)
|
||||
self.assertEqual(result.status_code, 200)
|
||||
|
||||
|
||||
def test_tag_page_activitypub_page(self):
|
||||
''' there are so many views, this just makes sure it LOADS '''
|
||||
""" there are so many views, this just makes sure it LOADS """
|
||||
view = views.Tag.as_view()
|
||||
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
|
||||
tag = models.Tag.objects.create(name='hi there')
|
||||
models.UserTag.objects.create(
|
||||
tag=tag, user=self.local_user, book=self.book)
|
||||
request = self.factory.get('', {'page': 1})
|
||||
with patch('bookwyrm.views.tag.is_api_request') as is_api:
|
||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
|
||||
tag = models.Tag.objects.create(name="hi there")
|
||||
models.UserTag.objects.create(tag=tag, user=self.local_user, book=self.book)
|
||||
request = self.factory.get("", {"page": 1})
|
||||
with patch("bookwyrm.views.tag.is_api_request") as is_api:
|
||||
is_api.return_value = True
|
||||
result = view(request, tag.identifier)
|
||||
self.assertIsInstance(result, ActivitypubResponse)
|
||||
self.assertEqual(result.status_code, 200)
|
||||
|
||||
|
||||
def test_tag(self):
|
||||
''' add a tag to a book '''
|
||||
""" add a tag to a book """
|
||||
view = views.AddTag.as_view()
|
||||
request = self.factory.post(
|
||||
'', {
|
||||
'name': 'A Tag!?',
|
||||
'book': self.book.id,
|
||||
})
|
||||
"",
|
||||
{
|
||||
"name": "A Tag!?",
|
||||
"book": self.book.id,
|
||||
},
|
||||
)
|
||||
request.user = self.local_user
|
||||
|
||||
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
|
||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
|
||||
view(request)
|
||||
|
||||
tag = models.Tag.objects.get()
|
||||
user_tag = models.UserTag.objects.get()
|
||||
self.assertEqual(tag.name, 'A Tag!?')
|
||||
self.assertEqual(tag.identifier, 'A+Tag%21%3F')
|
||||
self.assertEqual(tag.name, "A Tag!?")
|
||||
self.assertEqual(tag.identifier, "A+Tag%21%3F")
|
||||
self.assertEqual(user_tag.user, self.local_user)
|
||||
self.assertEqual(user_tag.book, self.book)
|
||||
|
||||
|
||||
def test_untag(self):
|
||||
''' remove a tag from a book '''
|
||||
""" remove a tag from a book """
|
||||
view = views.RemoveTag.as_view()
|
||||
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
|
||||
tag = models.Tag.objects.create(name='A Tag!?')
|
||||
models.UserTag.objects.create(
|
||||
user=self.local_user, book=self.book, tag=tag)
|
||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
|
||||
tag = models.Tag.objects.create(name="A Tag!?")
|
||||
models.UserTag.objects.create(user=self.local_user, book=self.book, tag=tag)
|
||||
request = self.factory.post(
|
||||
'', {
|
||||
'user': self.local_user.id,
|
||||
'book': self.book.id,
|
||||
'name': tag.name,
|
||||
})
|
||||
"",
|
||||
{
|
||||
"user": self.local_user.id,
|
||||
"book": self.book.id,
|
||||
"name": tag.name,
|
||||
},
|
||||
)
|
||||
request.user = self.local_user
|
||||
|
||||
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
|
||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
|
||||
view(request)
|
||||
|
||||
self.assertTrue(models.Tag.objects.filter(name='A Tag!?').exists())
|
||||
self.assertTrue(models.Tag.objects.filter(name="A Tag!?").exists())
|
||||
self.assertFalse(models.UserTag.objects.exists())
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
''' test for app action functionality '''
|
||||
""" test for app action functionality """
|
||||
import pathlib
|
||||
from unittest.mock import patch
|
||||
from PIL import Image
|
||||
@@ -15,180 +15,177 @@ from bookwyrm.activitypub import ActivitypubResponse
|
||||
|
||||
|
||||
class UserViews(TestCase):
|
||||
''' view user and edit profile '''
|
||||
""" view user and edit profile """
|
||||
|
||||
def setUp(self):
|
||||
''' we need basic test data and mocks '''
|
||||
""" we need basic test data and mocks """
|
||||
self.factory = RequestFactory()
|
||||
self.local_user = models.User.objects.create_user(
|
||||
'mouse@local.com', 'mouse@mouse.mouse', 'password',
|
||||
local=True, localname='mouse')
|
||||
"mouse@local.com",
|
||||
"mouse@mouse.mouse",
|
||||
"password",
|
||||
local=True,
|
||||
localname="mouse",
|
||||
)
|
||||
self.rat = models.User.objects.create_user(
|
||||
'rat@local.com', 'rat@rat.rat', 'password',
|
||||
local=True, localname='rat')
|
||||
"rat@local.com", "rat@rat.rat", "password", local=True, localname="rat"
|
||||
)
|
||||
models.SiteSettings.objects.create()
|
||||
self.anonymous_user = AnonymousUser
|
||||
self.anonymous_user.is_authenticated = False
|
||||
|
||||
|
||||
def test_user_page(self):
|
||||
''' there are so many views, this just makes sure it LOADS '''
|
||||
""" there are so many views, this just makes sure it LOADS """
|
||||
view = views.User.as_view()
|
||||
request = self.factory.get('')
|
||||
request = self.factory.get("")
|
||||
request.user = self.local_user
|
||||
with patch('bookwyrm.views.user.is_api_request') as is_api:
|
||||
with patch("bookwyrm.views.user.is_api_request") as is_api:
|
||||
is_api.return_value = False
|
||||
result = view(request, 'mouse')
|
||||
result = view(request, "mouse")
|
||||
self.assertIsInstance(result, TemplateResponse)
|
||||
result.render()
|
||||
self.assertEqual(result.status_code, 200)
|
||||
|
||||
request.user = self.anonymous_user
|
||||
with patch('bookwyrm.views.user.is_api_request') as is_api:
|
||||
with patch("bookwyrm.views.user.is_api_request") as is_api:
|
||||
is_api.return_value = False
|
||||
result = view(request, 'mouse')
|
||||
result = view(request, "mouse")
|
||||
self.assertIsInstance(result, TemplateResponse)
|
||||
result.render()
|
||||
self.assertEqual(result.status_code, 200)
|
||||
|
||||
with patch('bookwyrm.views.user.is_api_request') as is_api:
|
||||
with patch("bookwyrm.views.user.is_api_request") as is_api:
|
||||
is_api.return_value = True
|
||||
result = view(request, 'mouse')
|
||||
result = view(request, "mouse")
|
||||
self.assertIsInstance(result, ActivitypubResponse)
|
||||
self.assertEqual(result.status_code, 200)
|
||||
|
||||
|
||||
def test_user_page_blocked(self):
|
||||
''' there are so many views, this just makes sure it LOADS '''
|
||||
""" there are so many views, this just makes sure it LOADS """
|
||||
view = views.User.as_view()
|
||||
request = self.factory.get('')
|
||||
request = self.factory.get("")
|
||||
request.user = self.local_user
|
||||
self.rat.blocks.add(self.local_user)
|
||||
with patch('bookwyrm.views.user.is_api_request') as is_api:
|
||||
with patch("bookwyrm.views.user.is_api_request") as is_api:
|
||||
is_api.return_value = False
|
||||
result = view(request, 'rat')
|
||||
result = view(request, "rat")
|
||||
self.assertEqual(result.status_code, 404)
|
||||
|
||||
|
||||
def test_followers_page(self):
|
||||
''' there are so many views, this just makes sure it LOADS '''
|
||||
""" there are so many views, this just makes sure it LOADS """
|
||||
view = views.Followers.as_view()
|
||||
request = self.factory.get('')
|
||||
request = self.factory.get("")
|
||||
request.user = self.local_user
|
||||
with patch('bookwyrm.views.user.is_api_request') as is_api:
|
||||
with patch("bookwyrm.views.user.is_api_request") as is_api:
|
||||
is_api.return_value = False
|
||||
result = view(request, 'mouse')
|
||||
result = view(request, "mouse")
|
||||
self.assertIsInstance(result, TemplateResponse)
|
||||
result.render()
|
||||
self.assertEqual(result.status_code, 200)
|
||||
|
||||
with patch('bookwyrm.views.user.is_api_request') as is_api:
|
||||
with patch("bookwyrm.views.user.is_api_request") as is_api:
|
||||
is_api.return_value = True
|
||||
result = view(request, 'mouse')
|
||||
result = view(request, "mouse")
|
||||
self.assertIsInstance(result, ActivitypubResponse)
|
||||
self.assertEqual(result.status_code, 200)
|
||||
|
||||
|
||||
def test_followers_page_blocked(self):
|
||||
''' there are so many views, this just makes sure it LOADS '''
|
||||
""" there are so many views, this just makes sure it LOADS """
|
||||
view = views.Followers.as_view()
|
||||
request = self.factory.get('')
|
||||
request = self.factory.get("")
|
||||
request.user = self.local_user
|
||||
self.rat.blocks.add(self.local_user)
|
||||
with patch('bookwyrm.views.user.is_api_request') as is_api:
|
||||
with patch("bookwyrm.views.user.is_api_request") as is_api:
|
||||
is_api.return_value = False
|
||||
result = view(request, 'rat')
|
||||
result = view(request, "rat")
|
||||
self.assertEqual(result.status_code, 404)
|
||||
|
||||
|
||||
def test_following_page(self):
|
||||
''' there are so many views, this just makes sure it LOADS '''
|
||||
""" there are so many views, this just makes sure it LOADS """
|
||||
view = views.Following.as_view()
|
||||
request = self.factory.get('')
|
||||
request = self.factory.get("")
|
||||
request.user = self.local_user
|
||||
with patch('bookwyrm.views.user.is_api_request') as is_api:
|
||||
with patch("bookwyrm.views.user.is_api_request") as is_api:
|
||||
is_api.return_value = False
|
||||
result = view(request, 'mouse')
|
||||
result = view(request, "mouse")
|
||||
self.assertIsInstance(result, TemplateResponse)
|
||||
result.render()
|
||||
self.assertEqual(result.status_code, 200)
|
||||
|
||||
with patch('bookwyrm.views.user.is_api_request') as is_api:
|
||||
with patch("bookwyrm.views.user.is_api_request") as is_api:
|
||||
is_api.return_value = True
|
||||
result = view(request, 'mouse')
|
||||
result = view(request, "mouse")
|
||||
self.assertIsInstance(result, ActivitypubResponse)
|
||||
self.assertEqual(result.status_code, 200)
|
||||
|
||||
|
||||
def test_following_page_blocked(self):
|
||||
''' there are so many views, this just makes sure it LOADS '''
|
||||
""" there are so many views, this just makes sure it LOADS """
|
||||
view = views.Following.as_view()
|
||||
request = self.factory.get('')
|
||||
request = self.factory.get("")
|
||||
request.user = self.local_user
|
||||
self.rat.blocks.add(self.local_user)
|
||||
with patch('bookwyrm.views.user.is_api_request') as is_api:
|
||||
with patch("bookwyrm.views.user.is_api_request") as is_api:
|
||||
is_api.return_value = False
|
||||
result = view(request, 'rat')
|
||||
result = view(request, "rat")
|
||||
self.assertEqual(result.status_code, 404)
|
||||
|
||||
|
||||
def test_edit_user_page(self):
|
||||
''' there are so many views, this just makes sure it LOADS '''
|
||||
""" there are so many views, this just makes sure it LOADS """
|
||||
view = views.EditUser.as_view()
|
||||
request = self.factory.get('')
|
||||
request = self.factory.get("")
|
||||
request.user = self.local_user
|
||||
result = view(request)
|
||||
self.assertIsInstance(result, TemplateResponse)
|
||||
result.render()
|
||||
self.assertEqual(result.status_code, 200)
|
||||
|
||||
|
||||
def test_edit_user(self):
|
||||
''' use a form to update a user '''
|
||||
""" use a form to update a user """
|
||||
view = views.EditUser.as_view()
|
||||
form = forms.EditUserForm(instance=self.local_user)
|
||||
form.data['name'] = 'New Name'
|
||||
form.data['email'] = 'wow@email.com'
|
||||
request = self.factory.post('', form.data)
|
||||
form.data["name"] = "New Name"
|
||||
form.data["email"] = "wow@email.com"
|
||||
request = self.factory.post("", form.data)
|
||||
request.user = self.local_user
|
||||
|
||||
self.assertIsNone(self.local_user.name)
|
||||
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay') \
|
||||
as delay_mock:
|
||||
with patch(
|
||||
"bookwyrm.models.activitypub_mixin.broadcast_task.delay"
|
||||
) as delay_mock:
|
||||
view(request)
|
||||
self.assertEqual(delay_mock.call_count, 1)
|
||||
self.assertEqual(self.local_user.name, 'New Name')
|
||||
self.assertEqual(self.local_user.email, 'wow@email.com')
|
||||
self.assertEqual(self.local_user.name, "New Name")
|
||||
self.assertEqual(self.local_user.email, "wow@email.com")
|
||||
|
||||
# idk how to mock the upload form, got tired of triyng to make it work
|
||||
# def test_edit_user_avatar(self):
|
||||
# ''' use a form to update a user '''
|
||||
# view = views.EditUser.as_view()
|
||||
# form = forms.EditUserForm(instance=self.local_user)
|
||||
# form.data['name'] = 'New Name'
|
||||
# form.data['email'] = 'wow@email.com'
|
||||
# image_file = pathlib.Path(__file__).parent.joinpath(
|
||||
# '../../static/images/no_cover.jpg')
|
||||
# image = Image.open(image_file)
|
||||
# form.files['avatar'] = SimpleUploadedFile(
|
||||
# image_file, open(image_file), content_type='image/jpeg')
|
||||
# request = self.factory.post('', form.data, form.files)
|
||||
# request.user = self.local_user
|
||||
|
||||
# idk how to mock the upload form, got tired of triyng to make it work
|
||||
# def test_edit_user_avatar(self):
|
||||
# ''' use a form to update a user '''
|
||||
# view = views.EditUser.as_view()
|
||||
# form = forms.EditUserForm(instance=self.local_user)
|
||||
# form.data['name'] = 'New Name'
|
||||
# form.data['email'] = 'wow@email.com'
|
||||
# image_file = pathlib.Path(__file__).parent.joinpath(
|
||||
# '../../static/images/no_cover.jpg')
|
||||
# image = Image.open(image_file)
|
||||
# form.files['avatar'] = SimpleUploadedFile(
|
||||
# image_file, open(image_file), content_type='image/jpeg')
|
||||
# request = self.factory.post('', form.data, form.files)
|
||||
# request.user = self.local_user
|
||||
|
||||
# with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay') \
|
||||
# as delay_mock:
|
||||
# view(request)
|
||||
# self.assertEqual(delay_mock.call_count, 1)
|
||||
# self.assertEqual(self.local_user.name, 'New Name')
|
||||
# self.assertEqual(self.local_user.email, 'wow@email.com')
|
||||
# self.assertIsNotNone(self.local_user.avatar)
|
||||
# self.assertEqual(self.local_user.avatar.size, (120, 120))
|
||||
|
||||
# with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay') \
|
||||
# as delay_mock:
|
||||
# view(request)
|
||||
# self.assertEqual(delay_mock.call_count, 1)
|
||||
# self.assertEqual(self.local_user.name, 'New Name')
|
||||
# self.assertEqual(self.local_user.email, 'wow@email.com')
|
||||
# self.assertIsNotNone(self.local_user.avatar)
|
||||
# self.assertEqual(self.local_user.avatar.size, (120, 120))
|
||||
|
||||
def test_crop_avatar(self):
|
||||
''' reduce that image size '''
|
||||
""" reduce that image size """
|
||||
image_file = pathlib.Path(__file__).parent.joinpath(
|
||||
'../../static/images/no_cover.jpg')
|
||||
"../../static/images/no_cover.jpg"
|
||||
)
|
||||
image = Image.open(image_file)
|
||||
|
||||
result = views.user.crop_avatar(image)
|
||||
|
||||
Reference in New Issue
Block a user