Merge branch 'main' into suggestions-redis

This commit is contained in:
Mouse Reeve
2021-05-20 20:25:15 -07:00
committed by GitHub
200 changed files with 11270 additions and 6135 deletions

View File

@ -84,13 +84,6 @@ class AbstractConnector(TestCase):
"""barebones connector for search with defaults"""
self.assertIsInstance(self.connector.book_mappings, list)
def test_is_available(self):
"""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"""
self.assertEqual(models.Book.objects.count(), 1)

View File

@ -53,7 +53,6 @@ class AbstractConnector(TestCase):
self.assertEqual(connector.isbn_search_url, "https://example.com/isbn?q=")
self.assertIsNone(connector.name)
self.assertEqual(connector.identifier, "example.com")
self.assertIsNone(connector.max_query_count)
self.assertFalse(connector.local)
@responses.activate

View File

@ -1,5 +1,6 @@
""" interface between the app and various connectors """
from django.test import TestCase
import responses
from bookwyrm import models
from bookwyrm.connectors import connector_manager
@ -17,8 +18,9 @@ class ConnectorManager(TestCase):
self.edition = models.Edition.objects.create(
title="Example Edition", parent_work=self.work, isbn_10="0000000000"
)
self.work.default_edition = self.edition
self.work.save()
self.edition = models.Edition.objects.create(
title="Another Edition", parent_work=self.work, isbn_10="1111111111"
)
self.connector = models.Connector.objects.create(
identifier="test_connector",
@ -31,6 +33,18 @@ class ConnectorManager(TestCase):
isbn_search_url="http://test.com/isbn/",
)
self.remote_connector = models.Connector.objects.create(
identifier="test_connector_remote",
priority=1,
local=False,
connector_file="bookwyrm_connector",
base_url="http://fake.ciom/",
books_url="http://fake.ciom/",
search_url="http://fake.ciom/search/",
covers_url="http://covers.fake.ciom/",
isbn_search_url="http://fake.ciom/isbn/",
)
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"
@ -44,23 +58,38 @@ class ConnectorManager(TestCase):
def test_get_connectors(self):
"""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)
self.assertIsInstance(connectors[0], SelfConnector)
self.assertIsInstance(connectors[1], BookWyrmConnector)
@responses.activate
def test_search(self):
"""search all connectors"""
responses.add(
responses.GET,
"http://fake.ciom/search/Example?min_confidence=0.1",
json={},
)
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")
def test_search_empty_query(self):
"""don't panic on empty queries"""
results = connector_manager.search("")
self.assertEqual(results, [])
@responses.activate
def test_search_isbn(self):
"""special handling if a query resembles an isbn"""
responses.add(
responses.GET,
"http://fake.ciom/isbn/0000000000",
json={},
)
results = connector_manager.search("0000000000")
self.assertEqual(len(results), 1)
self.assertIsInstance(results[0]["connector"], SelfConnector)
@ -77,8 +106,22 @@ class ConnectorManager(TestCase):
"""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_first_search_result_empty_query(self):
"""only get one search result"""
result = connector_manager.first_search_result("")
self.assertIsNone(result)
@responses.activate
def test_first_search_result_no_results(self):
"""only get one search result"""
responses.add(
responses.GET,
"http://fake.ciom/search/dkjfhg?min_confidence=0.1",
json={},
)
result = connector_manager.first_search_result("dkjfhg")
self.assertIsNone(result)
def test_load_connector(self):
"""load a connector object from the database entry"""

View File

@ -0,0 +1,173 @@
""" testing book data connectors """
import json
import pathlib
from django.test import TestCase
import responses
from bookwyrm import models
from bookwyrm.connectors.inventaire import Connector, get_language_code
class Inventaire(TestCase):
"""test loading data from inventaire.io"""
def setUp(self):
"""creates the connector we'll use"""
models.Connector.objects.create(
identifier="inventaire.io",
name="Inventaire",
connector_file="inventaire",
base_url="https://inventaire.io",
books_url="https://inventaire.io",
covers_url="https://covers.inventaire.io",
search_url="https://inventaire.io/search?q=",
isbn_search_url="https://inventaire.io/isbn",
)
self.connector = Connector("inventaire.io")
@responses.activate
def test_get_book_data(self):
"""flattens the default structure to make it easier to parse"""
responses.add(
responses.GET,
"https://test.url/ok",
json={
"entities": {
"isbn:9780375757853": {
"claims": {
"wdt:P31": ["wd:Q3331189"],
},
"uri": "isbn:9780375757853",
}
},
"redirects": {},
},
)
result = self.connector.get_book_data("https://test.url/ok")
self.assertEqual(result["wdt:P31"], ["wd:Q3331189"])
self.assertEqual(result["uri"], "isbn:9780375757853")
def test_format_search_result(self):
"""json to search result objs"""
search_file = pathlib.Path(__file__).parent.joinpath(
"../data/inventaire_search.json"
)
search_results = json.loads(search_file.read_bytes())
results = self.connector.parse_search_data(search_results)
formatted = self.connector.format_search_result(results[0])
self.assertEqual(formatted.title, "The Stories of Vladimir Nabokov")
self.assertEqual(
formatted.key, "https://inventaire.io?action=by-uris&uris=wd:Q7766679"
)
self.assertEqual(
formatted.cover,
"https://covers.inventaire.io/img/entities/ddb32",
)
def test_get_cover_url(self):
"""figure out where the cover image is"""
cover_blob = {"url": "/img/entities/d46a8"}
result = self.connector.get_cover_url(cover_blob)
self.assertEqual(result, "https://covers.inventaire.io/img/entities/d46a8")
cover_blob = {
"url": "https://commons.wikimedia.org/wiki/d.jpg?width=1000",
"file": "The Moonstone 1st ed.jpg",
"credits": {
"text": "Wikimedia Commons",
"url": "https://commons.wikimedia.org/wiki/File:The Moonstone.jpg",
},
}
result = self.connector.get_cover_url(cover_blob)
self.assertEqual(
result,
"https://commons.wikimedia.org/wiki/d.jpg?width=1000",
)
@responses.activate
def test_resolve_keys(self):
"""makes an http request"""
responses.add(
responses.GET,
"https://inventaire.io?action=by-uris&uris=wd:Q465821",
json={
"entities": {
"wd:Q465821": {
"type": "genre",
"labels": {
"nl": "briefroman",
"en": "epistolary novel",
"de-ch": "Briefroman",
"en-ca": "Epistolary novel",
"nb": "brev- og dagbokroman",
},
"descriptions": {
"en": "novel written as a series of documents",
"es": "novela escrita como una serie de documentos",
"eo": "romano en la formo de serio de leteroj",
},
},
"redirects": {},
}
},
)
responses.add(
responses.GET,
"https://inventaire.io?action=by-uris&uris=wd:Q208505",
json={
"entities": {
"wd:Q208505": {
"type": "genre",
"labels": {
"en": "crime novel",
},
},
}
},
)
keys = [
"wd:Q465821",
"wd:Q208505",
]
result = self.connector.resolve_keys(keys)
self.assertEqual(result, ["epistolary novel", "crime novel"])
def test_isbn_search(self):
"""another search type"""
search_file = pathlib.Path(__file__).parent.joinpath(
"../data/inventaire_isbn_search.json"
)
search_results = json.loads(search_file.read_bytes())
results = self.connector.parse_isbn_search_data(search_results)
formatted = self.connector.format_isbn_search_result(results[0])
self.assertEqual(formatted.title, "L'homme aux cercles bleus")
self.assertEqual(
formatted.key,
"https://inventaire.io?action=by-uris&uris=isbn:9782290349229",
)
self.assertEqual(
formatted.cover,
"https://covers.inventaire.io/img/entities/12345",
)
def test_get_language_code(self):
"""get english or whatever is in reach"""
options = {
"de": "bip",
"en": "hi",
"fr": "there",
}
self.assertEqual(get_language_code(options), "hi")
options = {
"fr": "there",
}
self.assertEqual(get_language_code(options), "there")
self.assertIsNone(get_language_code({}))

View File

@ -84,11 +84,11 @@ class SelfConnector(TestCase):
title="Edition 1 Title", parent_work=work
)
edition_2 = models.Edition.objects.create(
title="Edition 2 Title", parent_work=work
title="Edition 2 Title",
parent_work=work,
edition_rank=20, # that's default babey
)
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")

View File

@ -0,0 +1,5 @@
Book Id,Title,Author,Author l-f,Additional Authors,ISBN,ISBN13,My Rating,Average Rating,Publisher,Binding,Number of Pages,Year Published,Original Publication Year,Date Read,Date Added,Bookshelves,Bookshelves with positions,Exclusive Shelf,My Review,Spoiler,Private Notes,Read Count,Recommended For,Recommended By,Owned Copies,Original Purchase Date,Original Purchase Location,Condition,Condition Description,BCID
42036538,Gideon the Ninth (The Locked Tomb #1),Tamsyn Muir,"Muir, Tamsyn",,"=""1250313198""","=""9781250313195""",0,4.20,Tor,Hardcover,448,2019,2019,2020/10/25,2020/10/21,,,read,,,,1,,,0,,,,,
52691223,Subcutanean,Aaron A. Reed,"Reed, Aaron A.",,"=""""","=""""",0,4.45,,Paperback,232,2020,,2020/03/06,2020/03/05,,,read,,,,1,,,0,,,,,
28694510,Patisserie at Home,Mélanie Dupuis,"Dupuis, Mélanie",Anne Cazor,"=""0062445316""","=""9780062445315""",2,4.60,Harper Design,Hardcover,288,2016,,,2019/07/08,,,read,,,,2,,,0,,,,,
1 Book Id Title Author Author l-f Additional Authors ISBN ISBN13 My Rating Average Rating Publisher Binding Number of Pages Year Published Original Publication Year Date Read Date Added Bookshelves Bookshelves with positions Exclusive Shelf My Review Spoiler Private Notes Read Count Recommended For Recommended By Owned Copies Original Purchase Date Original Purchase Location Condition Condition Description BCID
2 42036538 Gideon the Ninth (The Locked Tomb #1) Tamsyn Muir Muir, Tamsyn ="1250313198" ="9781250313195" 0 4.20 Tor Hardcover 448 2019 2019 2020/10/25 2020/10/21 read 1 0
3 52691223 Subcutanean Aaron A. Reed Reed, Aaron A. ="" ="" 0 4.45 Paperback 232 2020 2020/03/06 2020/03/05 read 1 0
4 28694510 Patisserie at Home Mélanie Dupuis Dupuis, Mélanie Anne Cazor ="0062445316" ="9780062445315" 2 4.60 Harper Design Hardcover 288 2016 2019/07/08 read 2 0

View File

@ -0,0 +1,45 @@
{
"entities": {
"isbn:9780375757853": {
"_id": "7beee121a8d9ac345cdf4e9128577723",
"_rev": "2-ac318b04b953ca3894deb77fee28211c",
"type": "edition",
"labels": {},
"claims": {
"wdt:P31": [
"wd:Q3331189"
],
"wdt:P212": [
"978-0-375-75785-3"
],
"wdt:P957": [
"0-375-75785-6"
],
"wdt:P407": [
"wd:Q1860"
],
"wdt:P1476": [
"The Moonstone"
],
"wdt:P577": [
"2001"
],
"wdt:P629": [
"wd:Q2362563"
],
"invp:P2": [
"d46a8eac7555afa479b8bbb5149f35858e8e19c4"
]
},
"created": 1495452670475,
"updated": 1541032981834,
"version": 3,
"uri": "isbn:9780375757853",
"originalLang": "en",
"image": {
"url": "/img/entities/d46a8eac7555afa479b8bbb5149f35858e8e19c4"
}
}
},
"redirects": {}
}

View File

@ -0,0 +1,48 @@
{
"entities": {
"isbn:9782290349229": {
"_id": "d59e3e64f92c6340fbb10c5dcf7c0abf",
"_rev": "3-079ed51158a001dc74caafb21cff1c22",
"type": "edition",
"labels": {},
"claims": {
"wdt:P31": [
"wd:Q3331189"
],
"wdt:P212": [
"978-2-290-34922-9"
],
"wdt:P957": [
"2-290-34922-4"
],
"wdt:P407": [
"wd:Q150"
],
"wdt:P1476": [
"L'homme aux cercles bleus"
],
"wdt:P629": [
"wd:Q3203603"
],
"wdt:P123": [
"wd:Q3156592"
],
"invp:P2": [
"57883743aa7c6ad25885a63e6e94349ec4f71562"
],
"wdt:P577": [
"2005-05-01"
]
},
"created": 1485023383338,
"updated": 1609171008418,
"version": 5,
"uri": "isbn:9782290349229",
"originalLang": "fr",
"image": {
"url": "/img/entities/12345"
}
}
},
"redirects": {}
}

View File

@ -0,0 +1,111 @@
{
"results": [
{
"id": "Q7766679",
"type": "works",
"uri": "wd:Q7766679",
"label": "The Stories of Vladimir Nabokov",
"description": "book by Vladimir Nabokov",
"image": [
"ddb32"
],
"_score": 25.180836,
"_popularity": 4
},
{
"id": "Q47407212",
"type": "works",
"uri": "wd:Q47407212",
"label": "Conversations with Vladimir Nabokov",
"description": "book edited by Robert Golla",
"image": [],
"_score": 24.41498,
"_popularity": 2
},
{
"id": "Q6956987",
"type": "works",
"uri": "wd:Q6956987",
"label": "Nabokov's Congeries",
"description": "book by Vladimir Nabokov",
"image": [],
"_score": 22.343866,
"_popularity": 2
},
{
"id": "Q6956986",
"type": "works",
"uri": "wd:Q6956986",
"label": "Nabokov's Butterflies",
"description": "book by Brian Boyd",
"image": [],
"_score": 22.343866,
"_popularity": 2
},
{
"id": "Q47472170",
"type": "works",
"uri": "wd:Q47472170",
"label": "A Reader's Guide to Nabokov's \"Lolita\"",
"description": "book by Julian W. Connolly",
"image": [],
"_score": 19.482553,
"_popularity": 2
},
{
"id": "Q7936323",
"type": "works",
"uri": "wd:Q7936323",
"label": "Visiting Mrs Nabokov: And Other Excursions",
"description": "book by Martin Amis",
"image": [],
"_score": 18.684965,
"_popularity": 2
},
{
"id": "1732d81bf7376e04da27568a778561a4",
"type": "works",
"uri": "inv:1732d81bf7376e04da27568a778561a4",
"label": "Nabokov's Dark Cinema",
"image": [
"7512805a53da569b11bf29cc3fb272c969619749"
],
"_score": 16.56681,
"_popularity": 1
},
{
"id": "00f118336b02219e1bddc8fa93c56050",
"type": "works",
"uri": "inv:00f118336b02219e1bddc8fa93c56050",
"label": "The Cambridge Companion to Nabokov",
"image": [
"0683a059fb95430cfa73334f9eff2ef377f3ae3d"
],
"_score": 15.502292,
"_popularity": 1
},
{
"id": "6e59f968a1cd00dbedeb1964dec47507",
"type": "works",
"uri": "inv:6e59f968a1cd00dbedeb1964dec47507",
"label": "Vladimir Nabokov : selected letters, 1940-1977",
"image": [
"e3ce8c0ee89d576adf2651a6e5ce55fc6d9f8cb3"
],
"_score": 15.019735,
"_popularity": 1
},
{
"id": "Q127149",
"type": "works",
"uri": "wd:Q127149",
"label": "Lolita",
"description": "novel by Vladimir Nabokov",
"image": [
"51cbfdbf7257b1a6bb3ea3fbb167dbce1fb44a0e"
],
"_score": 13.458428,
"_popularity": 32
}
]
}

View File

@ -0,0 +1,155 @@
{
"entities": {
"wd:Q2362563": {
"type": "work",
"labels": {
"zh-hans": "月亮宝石",
"zh-hant": "月亮寶石",
"zh-hk": "月光石",
"zh-tw": "月光石",
"cy": "The Moonstone",
"ml": "ദ മൂൺസ്റ്റോൺ",
"ja": "月長石",
"te": "ది మూన్ స్టోన్",
"ru": "Лунный камень",
"fr": "La Pierre de lune",
"en": "The Moonstone",
"es": "La piedra lunar",
"it": "La Pietra di Luna",
"zh": "月亮宝石",
"pl": "Kamień Księżycowy",
"sr": "2 Јн",
"ta": "moon stone",
"ar": "حجر القمر",
"fa": "ماه‌الماس",
"uk": "Місячний камінь",
"nl": "The Moonstone",
"de": "Der Monddiamant",
"sl": "Diamant",
"sv": "Månstenen",
"he": "אבן הירח",
"eu": "Ilargi-harriak",
"bg": "Лунният камък",
"ka": "მთვარის ქვა",
"eo": "La Lunŝtono",
"hy": "Լուսնաքար",
"ro": "Piatra Lunii",
"ca": "The Moonstone",
"is": "The Moonstone"
},
"descriptions": {
"it": "romanzo scritto da Wilkie Collins",
"en": "novel by Wilkie Collins",
"de": "Buch von Wilkie Collins",
"nl": "boek van Wilkie Collins",
"ru": "роман Уилки Коллинза",
"he": "רומן מאת וילקי קולינס",
"ar": "رواية من تأليف ويلكي كولينز",
"fr": "livre de Wilkie Collins",
"es": "libro de Wilkie Collins",
"bg": "роман на Уилки Колинс",
"ka": "უილკი კოლინსის რომანი",
"eo": "angalingva romano far Wilkie Collins",
"ro": "roman de Wilkie Collins"
},
"aliases": {
"zh": [
"月光石"
],
"ml": [
"The Moonstone"
],
"fr": [
"The Moonstone"
],
"it": [
"Il diamante indiano",
"La pietra della luna",
"La maledizione del diamante indiano"
],
"ro": [
"The Moonstone"
]
},
"claims": {
"wdt:P18": [
"The Moonstone 1st ed.jpg"
],
"wdt:P31": [
"wd:Q7725634"
],
"wdt:P50": [
"wd:Q210740"
],
"wdt:P123": [
"wd:Q4457856"
],
"wdt:P136": [
"wd:Q465821",
"wd:Q208505",
"wd:Q10992055"
],
"wdt:P156": [
"wd:Q7228798"
],
"wdt:P268": [
"12496407z"
],
"wdt:P407": [
"wd:Q7979"
],
"wdt:P577": [
"1868"
],
"wdt:P1433": [
"wd:Q21"
],
"wdt:P1476": [
"The Moonstone"
],
"wdt:P1680": [
"A Romance"
],
"wdt:P2034": [
"155"
]
},
"sitelinks": {
"arwiki": "حجر القمر (رواية)",
"bgwiki": "Лунният камък (роман)",
"cywiki": "The Moonstone",
"dewiki": "Der Monddiamant",
"enwiki": "The Moonstone",
"enwikisource": "The Moonstone",
"eswiki": "La piedra lunar",
"euwiki": "Ilargi-harria",
"fawiki": "ماه‌الماس",
"frwiki": "La Pierre de lune (roman de Wilkie Collins)",
"hewiki": "אבן הירח",
"hywiki": "Լուսնաքար",
"iswiki": "The Moonstone",
"itwiki": "La pietra di Luna",
"jawiki": "月長石 (小説)",
"mlwiki": "ദ മൂൺസ്റ്റോൺ",
"plwiki": "Kamień Księżycowy (powieść)",
"ruwiki": "Лунный камень (роман)",
"slwiki": "Diamant (roman)",
"srwikisource": "Нови завјет (Караџић) / 2. Јованова",
"svwiki": "Månstenen",
"tewiki": "ది మూన్‌స్టోన్",
"ukwiki": "Місячний камінь (роман)",
"zhwiki": "月亮宝石"
},
"uri": "wd:Q2362563",
"image": {
"url": "https://commons.wikimedia.org/wiki/Special:FilePath/The%20Moonstone%201st%20ed.jpg?width=1000",
"file": "The Moonstone 1st ed.jpg",
"credits": {
"text": "Wikimedia Commons",
"url": "https://commons.wikimedia.org/wiki/File:The Moonstone 1st ed.jpg"
}
}
}
},
"redirects": {}
}

View File

@ -228,6 +228,32 @@ class GoodreadsImport(TestCase):
self.assertEqual(review.published_date.day, 8)
self.assertEqual(review.privacy, "unlisted")
@patch("bookwyrm.activitystreams.ActivityStream.add_status")
def test_handle_imported_book_rating(self, _):
"""goodreads rating import"""
import_job = models.ImportJob.objects.create(user=self.user)
datafile = pathlib.Path(__file__).parent.joinpath(
"../data/goodreads-rating.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
)
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
handle_imported_book(
self.importer.service, self.user, import_item, True, "unlisted"
)
review = models.ReviewRating.objects.get(book=self.book, user=self.user)
self.assertIsInstance(review, models.ReviewRating)
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")
def test_handle_imported_book_reviews_disabled(self):
"""goodreads review import"""
import_job = models.ImportJob.objects.create(user=self.user)

View File

@ -26,20 +26,23 @@ class BaseModel(TestCase):
outbox="https://example.com/users/rat/outbox",
)
class BookWyrmTestModel(base_model.BookWyrmModel):
"""just making it not abstract"""
self.test_model = BookWyrmTestModel()
def test_remote_id(self):
"""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.test_model.id = 1
expected = self.test_model.get_remote_id()
self.assertEqual(expected, "https://%s/bookwyrmtestmodel/1" % DOMAIN)
def test_remote_id_with_user(self):
"""format of remote id when there's a user object"""
instance = base_model.BookWyrmModel()
instance.user = self.local_user
instance.id = 1
expected = instance.get_remote_id()
self.assertEqual(expected, "https://%s/user/mouse/bookwyrmmodel/1" % DOMAIN)
self.test_model.user = self.local_user
self.test_model.id = 1
expected = self.test_model.get_remote_id()
self.assertEqual(expected, "https://%s/user/mouse/bookwyrmtestmodel/1" % DOMAIN)
def test_set_remote_id(self):
"""this function sets remote ids after creation"""

View File

@ -84,9 +84,3 @@ class Book(TestCase):
self.first_edition.description = "hi"
self.first_edition.save()
self.assertEqual(self.first_edition.edition_rank, 1)
# default edition
self.work.default_edition = self.first_edition
self.work.save()
self.first_edition.refresh_from_db()
self.assertEqual(self.first_edition.edition_rank, 20)

View File

@ -2,7 +2,7 @@
from django.test import TestCase
from django.core.exceptions import ValidationError
from bookwyrm import models, settings
from bookwyrm import models
class ReadThrough(TestCase):
@ -19,8 +19,6 @@ class ReadThrough(TestCase):
self.edition = models.Edition.objects.create(
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

View File

@ -2,12 +2,17 @@
import re
from unittest.mock import patch
from dateutil.relativedelta import relativedelta
from django.test import TestCase
from django.utils import timezone
from bookwyrm import models
from bookwyrm.templatetags import bookwyrm_tags
from bookwyrm.templatetags import (
bookwyrm_tags,
interaction,
markdown,
status_display,
utilities,
)
@patch("bookwyrm.activitystreams.ActivityStream.add_status")
@ -33,12 +38,6 @@ class TemplateTags(TestCase):
)
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)
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"):
@ -52,27 +51,14 @@ class TemplateTags(TestCase):
def test_get_user_identifer_local(self, _):
"""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(utilities.get_user_identifier(self.user), "mouse")
def test_get_user_identifer_remote(self, _):
"""for a remote user, should be their full username"""
self.assertEqual(
bookwyrm_tags.get_user_identifier(self.remote_user), "rat@example.com"
utilities.get_user_identifier(self.remote_user), "rat@example.com"
)
def test_get_notification_count(self, _):
"""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.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"):
@ -95,7 +81,7 @@ class TemplateTags(TestCase):
deleted_date=timezone.now(),
)
replies = bookwyrm_tags.get_replies(parent)
replies = status_display.get_replies(parent)
self.assertEqual(len(replies), 2)
self.assertTrue(first_child in replies)
self.assertTrue(second_child in replies)
@ -111,7 +97,7 @@ class TemplateTags(TestCase):
reply_parent=parent, user=self.user, content="hi"
)
result = bookwyrm_tags.get_parent(child)
result = status_display.get_parent(child)
self.assertEqual(result, parent)
self.assertIsInstance(result, models.Review)
@ -119,44 +105,26 @@ class TemplateTags(TestCase):
"""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))
self.assertFalse(interaction.get_user_liked(self.user, 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))
self.assertTrue(interaction.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)
self.assertFalse(bookwyrm_tags.get_user_boosted(self.user, status))
self.assertFalse(interaction.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)
self.assertTrue(bookwyrm_tags.get_user_boosted(self.user, status))
def test_follow_request_exists(self, _):
"""does a user want to follow"""
self.assertFalse(
bookwyrm_tags.follow_request_exists(self.user, self.remote_user)
)
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
models.UserFollowRequest.objects.create(
user_subject=self.user, user_object=self.remote_user
)
self.assertFalse(
bookwyrm_tags.follow_request_exists(self.user, self.remote_user)
)
self.assertTrue(
bookwyrm_tags.follow_request_exists(self.remote_user, self.user)
)
self.assertTrue(interaction.get_user_boosted(self.user, status))
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)
boosted = bookwyrm_tags.get_boosted(boost)
boosted = status_display.get_boosted(boost)
self.assertIsInstance(boosted, models.Review)
self.assertEqual(boosted, status)
@ -178,48 +146,23 @@ class TemplateTags(TestCase):
def test_get_uuid(self, _):
"""uuid functionality"""
uuid = bookwyrm_tags.get_uuid("hi")
uuid = utilities.get_uuid("hi")
self.assertTrue(re.match(r"hi[A-Za-z0-9\-]", uuid))
def test_get_markdown(self, _):
"""mardown format data"""
result = bookwyrm_tags.get_markdown("_hi_")
result = markdown.get_markdown("_hi_")
self.assertEqual(result, "<p><em>hi</em></p>")
result = bookwyrm_tags.get_markdown("<marquee>_hi_</marquee>")
result = markdown.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)
result = bookwyrm_tags.get_mentions(status, self.user)
result = status_display.get_mentions(status, self.user)
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)
result = bookwyrm_tags.get_status_preview_name(status)
self.assertEqual(result, "status")
status = models.Review.objects.create(
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>")
status = models.Comment.objects.create(
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>")
status = models.Quotation.objects.create(
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>")
def test_related_status(self, _):
"""gets the subclass model for a notification status"""
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):

View File

@ -35,29 +35,49 @@ class InboxAdd(TestCase):
work = models.Work.objects.create(title="work title")
self.book = models.Edition.objects.create(
title="Test",
remote_id="https://bookwyrm.social/book/37292",
remote_id="https://example.com/book/37292",
parent_work=work,
)
models.SiteSettings.objects.create()
@responses.activate
def test_handle_add_book_to_shelf(self):
"""shelving a book"""
shelf = models.Shelf.objects.create(user=self.remote_user, name="Test Shelf")
shelf.remote_id = "https://bookwyrm.social/user/mouse/shelf/to-read"
shelf.remote_id = "https://example.com/user/rat/shelf/to-read"
shelf.save()
responses.add(
responses.GET,
"https://example.com/user/rat/shelf/to-read",
json={
"id": shelf.remote_id,
"type": "Shelf",
"totalItems": 1,
"first": "https://example.com/shelf/22?page=1",
"last": "https://example.com/shelf/22?page=1",
"name": "Test Shelf",
"owner": self.remote_user.remote_id,
"to": ["https://www.w3.org/ns/activitystreams#Public"],
"cc": ["https://example.com/user/rat/followers"],
"summary": "summary text",
"curation": "curated",
"@context": "https://www.w3.org/ns/activitystreams",
},
)
activity = {
"id": "https://bookwyrm.social/shelfbook/6189#add",
"id": "https://example.com/shelfbook/6189#add",
"type": "Add",
"actor": "https://example.com/users/rat",
"object": {
"actor": self.remote_user.remote_id,
"type": "ShelfItem",
"book": self.book.remote_id,
"id": "https://bookwyrm.social/shelfbook/6189",
"id": "https://example.com/shelfbook/6189",
},
"target": "https://bookwyrm.social/user/mouse/shelf/to-read",
"target": "https://example.com/user/rat/shelf/to-read",
"@context": "https://www.w3.org/ns/activitystreams",
}
views.inbox.activity_task(activity)
@ -68,7 +88,7 @@ class InboxAdd(TestCase):
"""listing a book"""
responses.add(
responses.GET,
"https://bookwyrm.social/user/mouse/list/to-read",
"https://example.com/user/mouse/list/to-read",
json={
"id": "https://example.com/list/22",
"type": "BookList",
@ -86,17 +106,17 @@ class InboxAdd(TestCase):
)
activity = {
"id": "https://bookwyrm.social/listbook/6189#add",
"id": "https://example.com/listbook/6189#add",
"type": "Add",
"actor": "https://example.com/users/rat",
"object": {
"actor": self.remote_user.remote_id,
"type": "ListItem",
"book": self.book.remote_id,
"id": "https://bookwyrm.social/listbook/6189",
"id": "https://example.com/listbook/6189",
"order": 1,
},
"target": "https://bookwyrm.social/user/mouse/list/to-read",
"target": "https://example.com/user/mouse/list/to-read",
"@context": "https://www.w3.org/ns/activitystreams",
}
views.inbox.activity_task(activity)
@ -105,4 +125,4 @@ class InboxAdd(TestCase):
listitem = models.ListItem.objects.get()
self.assertEqual(booklist.name, "Test List")
self.assertEqual(booklist.books.first(), self.book)
self.assertEqual(listitem.remote_id, "https://bookwyrm.social/listbook/6189")
self.assertEqual(listitem.remote_id, "https://example.com/listbook/6189")

View File

@ -127,6 +127,43 @@ class InboxCreate(TestCase):
self.assertTrue(models.Notification.objects.filter(user=self.local_user))
self.assertEqual(models.Notification.objects.get().notification_type, "REPLY")
def test_create_rating(self):
"""a remote rating activity"""
book = models.Edition.objects.create(
title="Test Book", remote_id="https://example.com/book/1"
)
activity = self.create_json
activity["object"] = {
"id": "https://example.com/user/mouse/reviewrating/12",
"type": "Rating",
"published": "2021-04-29T21:27:30.014235+00:00",
"attributedTo": "https://example.com/user/mouse",
"to": ["https://www.w3.org/ns/activitystreams#Public"],
"cc": ["https://example.com/user/mouse/followers"],
"replies": {
"id": "https://example.com/user/mouse/reviewrating/12/replies",
"type": "OrderedCollection",
"totalItems": 0,
"first": "https://example.com/user/mouse/reviewrating/12/replies?page=1",
"last": "https://example.com/user/mouse/reviewrating/12/replies?page=1",
"@context": "https://www.w3.org/ns/activitystreams",
},
"inReplyTo": "",
"summary": "",
"tag": [],
"attachment": [],
"sensitive": False,
"inReplyToBook": "https://example.com/book/1",
"rating": 3,
"@context": "https://www.w3.org/ns/activitystreams",
}
with patch("bookwyrm.activitystreams.ActivityStream.add_status") as redis_mock:
views.inbox.activity_task(activity)
self.assertTrue(redis_mock.called)
rating = models.ReviewRating.objects.first()
self.assertEqual(rating.book, book)
self.assertEqual(rating.rating, 3.0)
def test_create_list(self):
"""a new list"""
activity = self.create_json

View File

@ -0,0 +1,137 @@
""" test for app action functionality """
from django.template.response import TemplateResponse
from django.test import TestCase
from django.test.client import RequestFactory
from bookwyrm import forms, models, views
class AnnouncementViews(TestCase):
"""every response to a get request, html or json"""
def setUp(self):
"""we need basic test data and mocks"""
self.factory = RequestFactory()
self.local_user = models.User.objects.create_user(
"mouse@local.com",
"mouse@mouse.mouse",
"password",
local=True,
localname="mouse",
)
models.SiteSettings.objects.create()
def test_announcements_page(self):
"""there are so many views, this just makes sure it LOADS"""
models.Announcement.objects.create(preview="hi", user=self.local_user)
view = views.Announcements.as_view()
request = self.factory.get("")
request.user = self.local_user
request.user.is_superuser = True
result = view(request)
self.assertIsInstance(result, TemplateResponse)
result.render()
self.assertEqual(result.status_code, 200)
def test_announcements_page_empty(self):
"""there are so many views, this just makes sure it LOADS"""
view = views.Announcements.as_view()
request = self.factory.get("")
request.user = self.local_user
request.user.is_superuser = True
result = view(request)
self.assertIsInstance(result, TemplateResponse)
result.render()
self.assertEqual(result.status_code, 200)
def test_announcement_page(self):
"""there are so many views, this just makes sure it LOADS"""
announcement = models.Announcement.objects.create(
preview="hi", user=self.local_user
)
view = views.Announcement.as_view()
request = self.factory.get("")
request.user = self.local_user
request.user.is_superuser = True
result = view(request, announcement.id)
self.assertIsInstance(result, TemplateResponse)
result.render()
self.assertEqual(result.status_code, 200)
def test_create_announcement(self):
"""create a new announcement"""
view = views.Announcements.as_view()
form = forms.AnnouncementForm()
form.data["preview"] = "hi hi"
form.data["start_date"] = "2021-05-20"
form.data["user"] = self.local_user.id
request = self.factory.post("", form.data)
request.user = self.local_user
request.user.is_superuser = True
view(request)
announcement = models.Announcement.objects.get()
self.assertEqual(announcement.preview, "hi hi")
self.assertEqual(announcement.start_date.year, 2021)
self.assertEqual(announcement.start_date.month, 5)
self.assertEqual(announcement.start_date.day, 20)
def test_edit_announcement(self):
"""edit an announcement"""
announcement = models.Announcement.objects.create(
preview="hi", user=self.local_user
)
view = views.Announcement.as_view()
form = forms.AnnouncementForm(instance=announcement)
form.data["preview"] = "hi hi"
form.data["start_date"] = "2021-05-20"
form.data["user"] = self.local_user.id
request = self.factory.post("", form.data)
request.user = self.local_user
request.user.is_superuser = True
view(request, announcement.id)
announcement.refresh_from_db()
self.assertEqual(announcement.preview, "hi hi")
self.assertEqual(announcement.start_date.year, 2021)
self.assertEqual(announcement.start_date.month, 5)
self.assertEqual(announcement.start_date.day, 20)
def test_delete_announcement(self):
"""delete an announcement"""
announcement = models.Announcement.objects.create(
preview="hi", user=self.local_user
)
view = views.delete_announcement
request = self.factory.post("")
request.user = self.local_user
request.user.is_superuser = True
view(request, announcement.id)
self.assertFalse(models.Announcement.objects.exists())
def test_view_announcement(self):
"""display announcement on other pages"""
view = views.User.as_view()
request = self.factory.get("")
request.user = self.local_user
result = view(request, self.local_user.localname)
self.assertIsInstance(result, TemplateResponse)
result.render()
self.assertEqual(result.status_code, 200)

View File

@ -47,39 +47,6 @@ class BookViews(TestCase):
)
models.SiteSettings.objects.create()
def test_date_regression(self):
"""ensure that creating a new book actually saves the published date fields
this was initially a regression due to using a custom date picker tag
"""
first_published_date = "2021-04-20"
published_date = "2022-04-20"
self.local_user.groups.add(self.group)
view = views.EditBook.as_view()
form = forms.EditionForm(
{
"title": "New Title",
"last_edited_by": self.local_user.id,
"first_published_date": first_published_date,
"published_date": published_date,
}
)
request = self.factory.post("", form.data)
request.user = self.local_user
with patch("bookwyrm.connectors.connector_manager.local_search"):
result = view(request)
result.render()
self.assertContains(
result,
f'<input type="date" name="first_published_date" class="input" id="id_first_published_date" value="{first_published_date}">',
)
self.assertContains(
result,
f'<input type="date" name="published_date" class="input" id="id_published_date" value="{published_date}">',
)
def test_book_page(self):
"""there are so many views, this just makes sure it LOADS"""
view = views.Book.as_view()
@ -92,7 +59,6 @@ class BookViews(TestCase):
result.render()
self.assertEqual(result.status_code, 200)
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)

View File

@ -60,7 +60,12 @@ class FederationViews(TestCase):
def test_server_page_block(self):
"""block a server"""
server = models.FederatedServer.objects.create(server_name="hi.there.com")
server = models.FederatedServer.objects.create(
server_name="hi.there.com", application_type="bookwyrm"
)
connector = models.Connector.objects.get(
identifier="hi.there.com",
)
self.remote_user.federated_server = server
self.remote_user.save()
@ -72,17 +77,32 @@ class FederationViews(TestCase):
request.user.is_superuser = True
view(request, server.id)
server.refresh_from_db()
self.remote_user.refresh_from_db()
self.assertEqual(server.status, "blocked")
# and the user was deactivated
self.assertFalse(self.remote_user.is_active)
self.assertEqual(self.remote_user.deactivation_reason, "domain_block")
# and the connector was disabled
connector.refresh_from_db()
self.assertFalse(connector.active)
self.assertEqual(connector.deactivation_reason, "domain_block")
def test_server_page_unblock(self):
"""unblock a server"""
server = models.FederatedServer.objects.create(
server_name="hi.there.com", status="blocked"
server_name="hi.there.com", status="blocked", application_type="bookwyrm"
)
connector = models.Connector.objects.get(
identifier="hi.there.com",
)
connector.active = False
connector.deactivation_reason = "domain_block"
connector.save()
self.remote_user.federated_server = server
self.remote_user.is_active = False
self.remote_user.deactivation_reason = "domain_block"
@ -96,8 +116,15 @@ class FederationViews(TestCase):
server.refresh_from_db()
self.remote_user.refresh_from_db()
self.assertEqual(server.status, "federated")
# and the user was re-activated
self.assertTrue(self.remote_user.is_active)
self.assertIsNone(self.remote_user.deactivation_reason)
# and the connector was re-enabled
connector.refresh_from_db()
self.assertTrue(connector.active)
self.assertIsNone(connector.deactivation_reason)
def test_add_view_get(self):
"""there are so many views, this just makes sure it LOADS"""

View File

@ -3,6 +3,7 @@ import json
from unittest.mock import patch
import pathlib
from django.db.models import Q
from django.http import Http404
from django.test import TestCase
from django.test.client import RequestFactory
import responses
@ -67,7 +68,7 @@ class ViewsHelpers(TestCase):
views.helpers.get_user_from_username(self.local_user, "mouse@local.com"),
self.local_user,
)
with self.assertRaises(models.User.DoesNotExist):
with self.assertRaises(Http404):
views.helpers.get_user_from_username(self.local_user, "mojfse@example.com")
def test_is_api_request(self, _):
@ -219,7 +220,7 @@ class ViewsHelpers(TestCase):
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
# 1 shared follow
self.local_user.following.add(user_2)
user_1.following.add(user_2)
user_1.followers.add(user_2)
# 1 shared book
models.ShelfBook.objects.create(
@ -264,7 +265,7 @@ class ViewsHelpers(TestCase):
local=True,
localname=i,
)
user.followers.add(user_1)
user.following.add(user_1)
user.followers.add(self.local_user)
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):

View File

@ -122,6 +122,14 @@ class ListViews(TestCase):
view = views.List.as_view()
request = self.factory.get("")
request.user = self.local_user
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
models.ListItem.objects.create(
book_list=self.list,
user=self.local_user,
book=self.book,
approved=True,
order=1,
)
with patch("bookwyrm.views.list.is_api_request") as is_api:
is_api.return_value = False
@ -130,6 +138,81 @@ class ListViews(TestCase):
result.render()
self.assertEqual(result.status_code, 200)
def test_list_page_sorted(self):
"""there are so many views, this just makes sure it LOADS"""
view = views.List.as_view()
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
for (i, book) in enumerate([self.book, self.book_two, self.book_three]):
models.ListItem.objects.create(
book_list=self.list,
user=self.local_user,
book=book,
approved=True,
order=i + 1,
)
request = self.factory.get("/?sort_by=order")
request.user = self.local_user
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)
request = self.factory.get("/?sort_by=title")
request.user = self.local_user
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)
request = self.factory.get("/?sort_by=rating")
request.user = self.local_user
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)
request = self.factory.get("/?sort_by=sdkfh")
request.user = self.local_user
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)
def test_list_page_empty(self):
"""there are so many views, this just makes sure it LOADS"""
view = views.List.as_view()
request = self.factory.get("")
request.user = self.local_user
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)
def test_list_page_logged_out(self):
"""there are so many views, this just makes sure it LOADS"""
view = views.List.as_view()
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
models.ListItem.objects.create(
book_list=self.list,
user=self.local_user,
book=self.book,
approved=True,
order=1,
)
request = self.factory.get("")
request.user = self.anonymous_user
with patch("bookwyrm.views.list.is_api_request") as is_api:
is_api.return_value = False
@ -138,12 +221,32 @@ class ListViews(TestCase):
result.render()
self.assertEqual(result.status_code, 200)
def test_list_page_json_view(self):
"""there are so many views, this just makes sure it LOADS"""
view = views.List.as_view()
request = self.factory.get("")
request.user = self.local_user
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
models.ListItem.objects.create(
book_list=self.list,
user=self.local_user,
book=self.book,
approved=True,
order=1,
)
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_page_json_view_page(self):
"""there are so many views, this just makes sure it LOADS"""
view = views.List.as_view()
request = self.factory.get("")
request.user = self.local_user
request = self.factory.get("/?page=1")
request.user = self.local_user
with patch("bookwyrm.views.list.is_api_request") as is_api:
@ -204,466 +307,34 @@ class ListViews(TestCase):
result = view(request, self.list.id)
self.assertEqual(result.status_code, 302)
def test_curate_approve(self):
"""approve a pending item"""
view = views.Curate.as_view()
def test_user_lists_page(self):
"""there are so many views, this just makes sure it LOADS"""
view = views.UserLists.as_view()
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,
order=1,
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.post(
"",
{
"item": pending.id,
"approved": "true",
},
)
request = self.factory.get("")
request.user = self.local_user
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay") as mock:
view(request, self.list.id)
result = view(request, self.local_user.localname)
self.assertIsInstance(result, TemplateResponse)
result.render()
self.assertEqual(result.status_code, 200)
self.assertEqual(mock.call_count, 2)
activity = json.loads(mock.call_args[0][1])
self.assertEqual(activity["type"], "Add")
self.assertEqual(activity["actor"], self.local_user.remote_id)
self.assertEqual(activity["target"], self.list.remote_id)
pending.refresh_from_db()
self.assertEqual(self.list.books.count(), 1)
self.assertEqual(self.list.listitem_set.first(), pending)
self.assertTrue(pending.approved)
def test_curate_reject(self):
"""approve a pending item"""
view = views.Curate.as_view()
def test_user_lists_page_logged_out(self):
"""there are so many views, this just makes sure it LOADS"""
view = views.UserLists.as_view()
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,
order=1,
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("")
request.user = self.anonymous_user
request = self.factory.post(
"",
{
"item": pending.id,
"approved": "false",
},
)
request.user = self.local_user
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"""
request = self.factory.post(
"",
{
"book": self.book.id,
"list": self.list.id,
},
)
request.user = self.local_user
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay") as mock:
views.list.add_book(request)
self.assertEqual(mock.call_count, 1)
activity = json.loads(mock.call_args[0][1])
self.assertEqual(activity["type"], "Add")
self.assertEqual(activity["actor"], self.local_user.remote_id)
self.assertEqual(activity["target"], self.list.remote_id)
item = self.list.listitem_set.get()
self.assertEqual(item.book, self.book)
self.assertEqual(item.user, self.local_user)
self.assertTrue(item.approved)
def test_add_two_books(self):
"""
Putting two books on the list. The first should have an order value of
1 and the second should have an order value of 2.
"""
request_one = self.factory.post(
"",
{
"book": self.book.id,
"list": self.list.id,
},
)
request_one.user = self.local_user
request_two = self.factory.post(
"",
{
"book": self.book_two.id,
"list": self.list.id,
},
)
request_two.user = self.local_user
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
views.list.add_book(request_one)
views.list.add_book(request_two)
items = self.list.listitem_set.order_by("order").all()
self.assertEqual(items[0].book, self.book)
self.assertEqual(items[1].book, self.book_two)
self.assertEqual(items[0].order, 1)
self.assertEqual(items[1].order, 2)
def test_add_three_books_and_remove_second(self):
"""
Put three books on a list and then remove the one in the middle. The
ordering of the list should adjust to not have a gap.
"""
request_one = self.factory.post(
"",
{
"book": self.book.id,
"list": self.list.id,
},
)
request_one.user = self.local_user
request_two = self.factory.post(
"",
{
"book": self.book_two.id,
"list": self.list.id,
},
)
request_two.user = self.local_user
request_three = self.factory.post(
"",
{
"book": self.book_three.id,
"list": self.list.id,
},
)
request_three.user = self.local_user
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
views.list.add_book(request_one)
views.list.add_book(request_two)
views.list.add_book(request_three)
items = self.list.listitem_set.order_by("order").all()
self.assertEqual(items[0].book, self.book)
self.assertEqual(items[1].book, self.book_two)
self.assertEqual(items[2].book, self.book_three)
self.assertEqual(items[0].order, 1)
self.assertEqual(items[1].order, 2)
self.assertEqual(items[2].order, 3)
remove_request = self.factory.post("", {"item": items[1].id})
remove_request.user = self.local_user
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
views.list.remove_book(remove_request, self.list.id)
items = self.list.listitem_set.order_by("order").all()
self.assertEqual(items[0].book, self.book)
self.assertEqual(items[1].book, self.book_three)
self.assertEqual(items[0].order, 1)
self.assertEqual(items[1].order, 2)
def test_adding_book_with_a_pending_book(self):
"""
When a list contains any pending books, the pending books should have
be at the end of the list by order. If a book is added while a book is
pending, its order should precede the pending books.
"""
request = self.factory.post(
"",
{
"book": self.book_three.id,
"list": self.list.id,
},
)
request.user = self.local_user
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
models.ListItem.objects.create(
book_list=self.list,
user=self.local_user,
book=self.book,
approved=True,
order=1,
)
models.ListItem.objects.create(
book_list=self.list,
user=self.rat,
book=self.book_two,
approved=False,
order=2,
)
views.list.add_book(request)
items = self.list.listitem_set.order_by("order").all()
self.assertEqual(items[0].book, self.book)
self.assertEqual(items[0].order, 1)
self.assertTrue(items[0].approved)
self.assertEqual(items[1].book, self.book_three)
self.assertEqual(items[1].order, 2)
self.assertTrue(items[1].approved)
self.assertEqual(items[2].book, self.book_two)
self.assertEqual(items[2].order, 3)
self.assertFalse(items[2].approved)
def test_approving_one_pending_book_from_multiple(self):
"""
When a list contains any pending books, the pending books should have
be at the end of the list by order. If a pending book is approved, then
its order should be at the end of the approved books and before the
remaining pending books.
"""
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
models.ListItem.objects.create(
book_list=self.list,
user=self.local_user,
book=self.book,
approved=True,
order=1,
)
models.ListItem.objects.create(
book_list=self.list,
user=self.local_user,
book=self.book_two,
approved=True,
order=2,
)
models.ListItem.objects.create(
book_list=self.list,
user=self.rat,
book=self.book_three,
approved=False,
order=3,
)
to_be_approved = models.ListItem.objects.create(
book_list=self.list,
user=self.rat,
book=self.book_four,
approved=False,
order=4,
)
view = views.Curate.as_view()
request = self.factory.post(
"",
{
"item": to_be_approved.id,
"approved": "true",
},
)
request.user = self.local_user
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
view(request, self.list.id)
items = self.list.listitem_set.order_by("order").all()
self.assertEqual(items[0].book, self.book)
self.assertEqual(items[0].order, 1)
self.assertTrue(items[0].approved)
self.assertEqual(items[1].book, self.book_two)
self.assertEqual(items[1].order, 2)
self.assertTrue(items[1].approved)
self.assertEqual(items[2].book, self.book_four)
self.assertEqual(items[2].order, 3)
self.assertTrue(items[2].approved)
self.assertEqual(items[3].book, self.book_three)
self.assertEqual(items[3].order, 4)
self.assertFalse(items[3].approved)
def test_add_three_books_and_move_last_to_first(self):
"""
Put three books on the list and move the last book to the first
position.
"""
request_one = self.factory.post(
"",
{
"book": self.book.id,
"list": self.list.id,
},
)
request_one.user = self.local_user
request_two = self.factory.post(
"",
{
"book": self.book_two.id,
"list": self.list.id,
},
)
request_two.user = self.local_user
request_three = self.factory.post(
"",
{
"book": self.book_three.id,
"list": self.list.id,
},
)
request_three.user = self.local_user
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
views.list.add_book(request_one)
views.list.add_book(request_two)
views.list.add_book(request_three)
items = self.list.listitem_set.order_by("order").all()
self.assertEqual(items[0].book, self.book)
self.assertEqual(items[1].book, self.book_two)
self.assertEqual(items[2].book, self.book_three)
self.assertEqual(items[0].order, 1)
self.assertEqual(items[1].order, 2)
self.assertEqual(items[2].order, 3)
set_position_request = self.factory.post("", {"position": 1})
set_position_request.user = self.local_user
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
views.list.set_book_position(set_position_request, items[2].id)
items = self.list.listitem_set.order_by("order").all()
self.assertEqual(items[0].book, self.book_three)
self.assertEqual(items[1].book, self.book)
self.assertEqual(items[2].book, self.book_two)
self.assertEqual(items[0].order, 1)
self.assertEqual(items[1].order, 2)
self.assertEqual(items[2].order, 3)
def test_add_book_outsider(self):
"""put a book on a list"""
self.list.curation = "open"
self.list.save(broadcast=False)
request = self.factory.post(
"",
{
"book": self.book.id,
"list": self.list.id,
},
)
request.user = self.rat
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay") as mock:
views.list.add_book(request)
self.assertEqual(mock.call_count, 1)
activity = json.loads(mock.call_args[0][1])
self.assertEqual(activity["type"], "Add")
self.assertEqual(activity["actor"], self.rat.remote_id)
self.assertEqual(activity["target"], self.list.remote_id)
item = self.list.listitem_set.get()
self.assertEqual(item.book, self.book)
self.assertEqual(item.user, self.rat)
self.assertTrue(item.approved)
def test_add_book_pending(self):
"""put a book on a list awaiting approval"""
self.list.curation = "curated"
self.list.save(broadcast=False)
request = self.factory.post(
"",
{
"book": self.book.id,
"list": self.list.id,
},
)
request.user = self.rat
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay") as mock:
views.list.add_book(request)
self.assertEqual(mock.call_count, 1)
activity = json.loads(mock.call_args[0][1])
self.assertEqual(activity["type"], "Add")
self.assertEqual(activity["actor"], self.rat.remote_id)
self.assertEqual(activity["target"], self.list.remote_id)
item = self.list.listitem_set.get()
self.assertEqual(activity["object"]["id"], item.remote_id)
self.assertEqual(item.book, self.book)
self.assertEqual(item.user, self.rat)
self.assertFalse(item.approved)
def test_add_book_self_curated(self):
"""put a book on a list automatically approved"""
self.list.curation = "curated"
self.list.save(broadcast=False)
request = self.factory.post(
"",
{
"book": self.book.id,
"list": self.list.id,
},
)
request.user = self.local_user
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay") as mock:
views.list.add_book(request)
self.assertEqual(mock.call_count, 1)
activity = json.loads(mock.call_args[0][1])
self.assertEqual(activity["type"], "Add")
self.assertEqual(activity["actor"], self.local_user.remote_id)
self.assertEqual(activity["target"], self.list.remote_id)
item = self.list.listitem_set.get()
self.assertEqual(item.book, self.book)
self.assertEqual(item.user, self.local_user)
self.assertTrue(item.approved)
def test_remove_book(self):
"""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,
order=1,
)
self.assertTrue(self.list.listitem_set.exists())
request = self.factory.post(
"",
{
"item": item.id,
},
)
request.user = self.local_user
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
views.list.remove_book(request, self.list.id)
self.assertFalse(self.list.listitem_set.exists())
def test_remove_book_unauthorized(self):
"""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, order=1
)
self.assertTrue(self.list.listitem_set.exists())
request = self.factory.post(
"",
{
"item": item.id,
},
)
request.user = self.rat
views.list.remove_book(request, self.list.id)
self.assertTrue(self.list.listitem_set.exists())
result = view(request, self.local_user.username)
self.assertIsInstance(result, TemplateResponse)
result.render()
self.assertEqual(result.status_code, 200)

View File

@ -0,0 +1,529 @@
""" test for app action functionality """
import json
from unittest.mock import patch
from django.contrib.auth.models import AnonymousUser
from django.test import TestCase
from django.test.client import RequestFactory
from bookwyrm import models, views
# pylint: disable=unused-argument
class ListActionViews(TestCase):
"""tag views"""
def setUp(self):
"""we need basic test data and mocks"""
self.factory = RequestFactory()
self.local_user = models.User.objects.create_user(
"mouse@local.com",
"mouse@mouse.com",
"mouseword",
local=True,
localname="mouse",
remote_id="https://example.com/users/mouse",
)
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",
)
work = models.Work.objects.create(title="Work")
self.book = models.Edition.objects.create(
title="Example Edition",
remote_id="https://example.com/book/1",
parent_work=work,
)
work_two = models.Work.objects.create(title="Labori")
self.book_two = models.Edition.objects.create(
title="Example Edition 2",
remote_id="https://example.com/book/2",
parent_work=work_two,
)
work_three = models.Work.objects.create(title="Trabajar")
self.book_three = models.Edition.objects.create(
title="Example Edition 3",
remote_id="https://example.com/book/3",
parent_work=work_three,
)
work_four = models.Work.objects.create(title="Travailler")
self.book_four = models.Edition.objects.create(
title="Example Edition 4",
remote_id="https://example.com/book/4",
parent_work=work_four,
)
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
self.list = models.List.objects.create(
name="Test List", user=self.local_user
)
self.anonymous_user = AnonymousUser
self.anonymous_user.is_authenticated = False
models.SiteSettings.objects.create()
def test_curate_approve(self):
"""approve a pending item"""
view = views.Curate.as_view()
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,
order=1,
)
request = self.factory.post(
"",
{
"item": pending.id,
"approved": "true",
},
)
request.user = self.local_user
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay") as mock:
view(request, self.list.id)
self.assertEqual(mock.call_count, 2)
activity = json.loads(mock.call_args[0][1])
self.assertEqual(activity["type"], "Add")
self.assertEqual(activity["actor"], self.local_user.remote_id)
self.assertEqual(activity["target"], self.list.remote_id)
pending.refresh_from_db()
self.assertEqual(self.list.books.count(), 1)
self.assertEqual(self.list.listitem_set.first(), pending)
self.assertTrue(pending.approved)
def test_curate_reject(self):
"""approve a pending item"""
view = views.Curate.as_view()
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,
order=1,
)
request = self.factory.post(
"",
{
"item": pending.id,
"approved": "false",
},
)
request.user = self.local_user
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"""
request = self.factory.post(
"",
{
"book": self.book.id,
"list": self.list.id,
},
)
request.user = self.local_user
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay") as mock:
views.list.add_book(request)
self.assertEqual(mock.call_count, 1)
activity = json.loads(mock.call_args[0][1])
self.assertEqual(activity["type"], "Add")
self.assertEqual(activity["actor"], self.local_user.remote_id)
self.assertEqual(activity["target"], self.list.remote_id)
item = self.list.listitem_set.get()
self.assertEqual(item.book, self.book)
self.assertEqual(item.user, self.local_user)
self.assertTrue(item.approved)
def test_add_two_books(self):
"""
Putting two books on the list. The first should have an order value of
1 and the second should have an order value of 2.
"""
request_one = self.factory.post(
"",
{
"book": self.book.id,
"list": self.list.id,
},
)
request_one.user = self.local_user
request_two = self.factory.post(
"",
{
"book": self.book_two.id,
"list": self.list.id,
},
)
request_two.user = self.local_user
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
views.list.add_book(request_one)
views.list.add_book(request_two)
items = self.list.listitem_set.order_by("order").all()
self.assertEqual(items[0].book, self.book)
self.assertEqual(items[1].book, self.book_two)
self.assertEqual(items[0].order, 1)
self.assertEqual(items[1].order, 2)
def test_add_three_books_and_remove_second(self):
"""
Put three books on a list and then remove the one in the middle. The
ordering of the list should adjust to not have a gap.
"""
request_one = self.factory.post(
"",
{
"book": self.book.id,
"list": self.list.id,
},
)
request_one.user = self.local_user
request_two = self.factory.post(
"",
{
"book": self.book_two.id,
"list": self.list.id,
},
)
request_two.user = self.local_user
request_three = self.factory.post(
"",
{
"book": self.book_three.id,
"list": self.list.id,
},
)
request_three.user = self.local_user
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
views.list.add_book(request_one)
views.list.add_book(request_two)
views.list.add_book(request_three)
items = self.list.listitem_set.order_by("order").all()
self.assertEqual(items[0].book, self.book)
self.assertEqual(items[1].book, self.book_two)
self.assertEqual(items[2].book, self.book_three)
self.assertEqual(items[0].order, 1)
self.assertEqual(items[1].order, 2)
self.assertEqual(items[2].order, 3)
remove_request = self.factory.post("", {"item": items[1].id})
remove_request.user = self.local_user
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
views.list.remove_book(remove_request, self.list.id)
items = self.list.listitem_set.order_by("order").all()
self.assertEqual(items[0].book, self.book)
self.assertEqual(items[1].book, self.book_three)
self.assertEqual(items[0].order, 1)
self.assertEqual(items[1].order, 2)
def test_adding_book_with_a_pending_book(self):
"""
When a list contains any pending books, the pending books should have
be at the end of the list by order. If a book is added while a book is
pending, its order should precede the pending books.
"""
request = self.factory.post(
"",
{
"book": self.book_three.id,
"list": self.list.id,
},
)
request.user = self.local_user
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
models.ListItem.objects.create(
book_list=self.list,
user=self.local_user,
book=self.book,
approved=True,
order=1,
)
models.ListItem.objects.create(
book_list=self.list,
user=self.rat,
book=self.book_two,
approved=False,
order=2,
)
views.list.add_book(request)
items = self.list.listitem_set.order_by("order").all()
self.assertEqual(items[0].book, self.book)
self.assertEqual(items[0].order, 1)
self.assertTrue(items[0].approved)
self.assertEqual(items[1].book, self.book_three)
self.assertEqual(items[1].order, 2)
self.assertTrue(items[1].approved)
self.assertEqual(items[2].book, self.book_two)
self.assertEqual(items[2].order, 3)
self.assertFalse(items[2].approved)
def test_approving_one_pending_book_from_multiple(self):
"""
When a list contains any pending books, the pending books should have
be at the end of the list by order. If a pending book is approved, then
its order should be at the end of the approved books and before the
remaining pending books.
"""
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
models.ListItem.objects.create(
book_list=self.list,
user=self.local_user,
book=self.book,
approved=True,
order=1,
)
models.ListItem.objects.create(
book_list=self.list,
user=self.local_user,
book=self.book_two,
approved=True,
order=2,
)
models.ListItem.objects.create(
book_list=self.list,
user=self.rat,
book=self.book_three,
approved=False,
order=3,
)
to_be_approved = models.ListItem.objects.create(
book_list=self.list,
user=self.rat,
book=self.book_four,
approved=False,
order=4,
)
view = views.Curate.as_view()
request = self.factory.post(
"",
{
"item": to_be_approved.id,
"approved": "true",
},
)
request.user = self.local_user
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
view(request, self.list.id)
items = self.list.listitem_set.order_by("order").all()
self.assertEqual(items[0].book, self.book)
self.assertEqual(items[0].order, 1)
self.assertTrue(items[0].approved)
self.assertEqual(items[1].book, self.book_two)
self.assertEqual(items[1].order, 2)
self.assertTrue(items[1].approved)
self.assertEqual(items[2].book, self.book_four)
self.assertEqual(items[2].order, 3)
self.assertTrue(items[2].approved)
self.assertEqual(items[3].book, self.book_three)
self.assertEqual(items[3].order, 4)
self.assertFalse(items[3].approved)
def test_add_three_books_and_move_last_to_first(self):
"""
Put three books on the list and move the last book to the first
position.
"""
request_one = self.factory.post(
"",
{
"book": self.book.id,
"list": self.list.id,
},
)
request_one.user = self.local_user
request_two = self.factory.post(
"",
{
"book": self.book_two.id,
"list": self.list.id,
},
)
request_two.user = self.local_user
request_three = self.factory.post(
"",
{
"book": self.book_three.id,
"list": self.list.id,
},
)
request_three.user = self.local_user
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
views.list.add_book(request_one)
views.list.add_book(request_two)
views.list.add_book(request_three)
items = self.list.listitem_set.order_by("order").all()
self.assertEqual(items[0].book, self.book)
self.assertEqual(items[1].book, self.book_two)
self.assertEqual(items[2].book, self.book_three)
self.assertEqual(items[0].order, 1)
self.assertEqual(items[1].order, 2)
self.assertEqual(items[2].order, 3)
set_position_request = self.factory.post("", {"position": 1})
set_position_request.user = self.local_user
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
views.list.set_book_position(set_position_request, items[2].id)
items = self.list.listitem_set.order_by("order").all()
self.assertEqual(items[0].book, self.book_three)
self.assertEqual(items[1].book, self.book)
self.assertEqual(items[2].book, self.book_two)
self.assertEqual(items[0].order, 1)
self.assertEqual(items[1].order, 2)
self.assertEqual(items[2].order, 3)
def test_add_book_outsider(self):
"""put a book on a list"""
self.list.curation = "open"
self.list.save(broadcast=False)
request = self.factory.post(
"",
{
"book": self.book.id,
"list": self.list.id,
},
)
request.user = self.rat
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay") as mock:
views.list.add_book(request)
self.assertEqual(mock.call_count, 1)
activity = json.loads(mock.call_args[0][1])
self.assertEqual(activity["type"], "Add")
self.assertEqual(activity["actor"], self.rat.remote_id)
self.assertEqual(activity["target"], self.list.remote_id)
item = self.list.listitem_set.get()
self.assertEqual(item.book, self.book)
self.assertEqual(item.user, self.rat)
self.assertTrue(item.approved)
def test_add_book_pending(self):
"""put a book on a list awaiting approval"""
self.list.curation = "curated"
self.list.save(broadcast=False)
request = self.factory.post(
"",
{
"book": self.book.id,
"list": self.list.id,
},
)
request.user = self.rat
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay") as mock:
views.list.add_book(request)
self.assertEqual(mock.call_count, 1)
activity = json.loads(mock.call_args[0][1])
self.assertEqual(activity["type"], "Add")
self.assertEqual(activity["actor"], self.rat.remote_id)
self.assertEqual(activity["target"], self.list.remote_id)
item = self.list.listitem_set.get()
self.assertEqual(activity["object"]["id"], item.remote_id)
self.assertEqual(item.book, self.book)
self.assertEqual(item.user, self.rat)
self.assertFalse(item.approved)
def test_add_book_self_curated(self):
"""put a book on a list automatically approved"""
self.list.curation = "curated"
self.list.save(broadcast=False)
request = self.factory.post(
"",
{
"book": self.book.id,
"list": self.list.id,
},
)
request.user = self.local_user
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay") as mock:
views.list.add_book(request)
self.assertEqual(mock.call_count, 1)
activity = json.loads(mock.call_args[0][1])
self.assertEqual(activity["type"], "Add")
self.assertEqual(activity["actor"], self.local_user.remote_id)
self.assertEqual(activity["target"], self.list.remote_id)
item = self.list.listitem_set.get()
self.assertEqual(item.book, self.book)
self.assertEqual(item.user, self.local_user)
self.assertTrue(item.approved)
def test_remove_book(self):
"""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,
order=1,
)
self.assertTrue(self.list.listitem_set.exists())
request = self.factory.post(
"",
{
"item": item.id,
},
)
request.user = self.local_user
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
views.list.remove_book(request, self.list.id)
self.assertFalse(self.list.listitem_set.exists())
def test_remove_book_unauthorized(self):
"""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, order=1
)
self.assertTrue(self.list.listitem_set.exists())
request = self.factory.post(
"",
{
"item": item.id,
},
)
request.user = self.rat
views.list.remove_book(request, self.list.id)
self.assertTrue(self.list.listitem_set.exists())

View File

@ -20,8 +20,6 @@ class ReadThrough(TestCase):
self.edition = models.Edition.objects.create(
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"

View File

@ -2,6 +2,7 @@
import json
from unittest.mock import patch
from django.contrib.auth.models import AnonymousUser
from django.http import JsonResponse
from django.template.response import TemplateResponse
from django.test import TestCase
@ -12,7 +13,7 @@ from bookwyrm.connectors import abstract_connector
from bookwyrm.settings import DOMAIN
class ShelfViews(TestCase):
class Views(TestCase):
"""tag views"""
def setUp(self):
@ -52,7 +53,18 @@ class ShelfViews(TestCase):
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):
def test_search_no_query(self):
"""just the search page"""
view = views.Search.as_view()
# we need a connector for this, sorry
request = self.factory.get("")
with patch("bookwyrm.views.search.is_api_request") as is_api:
is_api.return_value = False
response = view(request)
self.assertIsInstance(response, TemplateResponse)
response.render()
def test_search_books(self):
"""searches remote connectors"""
view = views.Search.as_view()
@ -92,7 +104,7 @@ class ShelfViews(TestCase):
connector=connector,
)
request = self.factory.get("", {"q": "Test Book"})
request = self.factory.get("", {"q": "Test Book", "remote": True})
request.user = self.local_user
with patch("bookwyrm.views.search.is_api_request") as is_api:
is_api.return_value = False
@ -101,19 +113,44 @@ class ShelfViews(TestCase):
response = view(request)
self.assertIsInstance(response, TemplateResponse)
response.render()
self.assertEqual(
response.context_data["book_results"][0].title, "Gideon the Ninth"
)
self.assertEqual(response.context_data["results"][0].title, "Gideon the Ninth")
def test_search_html_response_users(self):
def test_search_users(self):
"""searches remote connectors"""
view = views.Search.as_view()
request = self.factory.get("", {"q": "mouse"})
request = self.factory.get("", {"q": "mouse", "type": "user"})
request.user = self.local_user
with patch("bookwyrm.views.search.is_api_request") as is_api:
is_api.return_value = False
with patch("bookwyrm.connectors.connector_manager.search"):
response = view(request)
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["results"][0], self.local_user)
def test_search_users_logged_out(self):
"""searches remote connectors"""
view = views.Search.as_view()
request = self.factory.get("", {"q": "mouse", "type": "user"})
anonymous_user = AnonymousUser
anonymous_user.is_authenticated = False
request.user = anonymous_user
response = view(request)
response.render()
self.assertFalse("results" in response.context_data)
def test_search_lists(self):
"""searches remote connectors"""
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
booklist = models.List.objects.create(
user=self.local_user, name="test list"
)
view = views.Search.as_view()
request = self.factory.get("", {"q": "test", "type": "list"})
request.user = self.local_user
response = view(request)
self.assertIsInstance(response, TemplateResponse)
response.render()
self.assertEqual(response.context_data["results"][0], booklist)

View File

@ -6,6 +6,7 @@ from PIL import Image
from django.contrib.auth.models import AnonymousUser
from django.core.files.base import ContentFile
from django.core.files.uploadedfile import SimpleUploadedFile
from django.http.response import Http404
from django.template.response import TemplateResponse
from django.test import TestCase
from django.test.client import RequestFactory
@ -76,8 +77,8 @@ class UserViews(TestCase):
self.rat.blocks.add(self.local_user)
with patch("bookwyrm.views.user.is_api_request") as is_api:
is_api.return_value = False
result = view(request, "rat")
self.assertEqual(result.status_code, 404)
with self.assertRaises(Http404):
view(request, "rat")
def test_followers_page(self):
"""there are so many views, this just makes sure it LOADS"""
@ -105,8 +106,8 @@ class UserViews(TestCase):
self.rat.blocks.add(self.local_user)
with patch("bookwyrm.views.user.is_api_request") as is_api:
is_api.return_value = False
result = view(request, "rat")
self.assertEqual(result.status_code, 404)
with self.assertRaises(Http404):
view(request, "rat")
def test_following_page(self):
"""there are so many views, this just makes sure it LOADS"""
@ -134,8 +135,8 @@ class UserViews(TestCase):
self.rat.blocks.add(self.local_user)
with patch("bookwyrm.views.user.is_api_request") as is_api:
is_api.return_value = False
result = view(request, "rat")
self.assertEqual(result.status_code, 404)
with self.assertRaises(Http404):
view(request, "rat")
def test_edit_user_page(self):
"""there are so many views, this just makes sure it LOADS"""
@ -166,7 +167,6 @@ class UserViews(TestCase):
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()