From 9080cf1a6df4948fe26e4c06efb7cae5e194d36f Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Wed, 20 Oct 2021 10:22:15 -0700 Subject: [PATCH 01/17] Updates German locale --- locale/de_DE/LC_MESSAGES/django.mo | Bin 44764 -> 57128 bytes locale/de_DE/LC_MESSAGES/django.po | 467 +++++++++++++---------------- 2 files changed, 216 insertions(+), 251 deletions(-) diff --git a/locale/de_DE/LC_MESSAGES/django.mo b/locale/de_DE/LC_MESSAGES/django.mo index 0907655a21ebb14477d0e72251c2130be347e7b2..cff3c02e0f08cfd668de4985bdba3f4c87608ffb 100644 GIT binary patch literal 57128 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 S=94M>zcK~?z_C=C9Q{Aby!7Y* delta 15809 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 I^y3--59h\n" "Language-Team: German\n" "Language: de\n" @@ -90,11 +90,11 @@ msgstr "Selbstlöschung" #: bookwyrm/models/base_model.py:19 msgid "Moderator suspension" -msgstr "Moderator suspendieren" +msgstr "Moderator*in suspendieren" #: bookwyrm/models/base_model.py:20 msgid "Moderator deletion" -msgstr "Moderatoren löschen" +msgstr "Moderator*in löschen" #: bookwyrm/models/base_model.py:21 msgid "Domain block" @@ -187,7 +187,7 @@ msgstr "Français (Französisch)" #: bookwyrm/settings.py:169 msgid "Português - Brasil (Brazilian Portuguese)" -msgstr "" +msgstr "Português (Portugiesisch)" #: bookwyrm/settings.py:170 msgid "简体中文 (Simplified Chinese)" @@ -296,7 +296,7 @@ msgstr "Name:" #: bookwyrm/templates/book/edit/edit_book_form.html:79 #: bookwyrm/templates/book/edit/edit_book_form.html:124 msgid "Separate multiple values with commas." -msgstr "Geben Sie mehrere Werte durch Kommas getrennt ein." +msgstr "Mehrere Werte durch Kommas getrennt eingeben." #: bookwyrm/templates/author/edit_author.html:50 msgid "Bio:" @@ -320,20 +320,20 @@ msgstr "Autor*innenidentifikatoren" #: bookwyrm/templates/author/edit_author.html:81 msgid "Openlibrary key:" -msgstr "Openlibrary Schlüssel:" +msgstr "Openlibrary-Schlüssel:" #: bookwyrm/templates/author/edit_author.html:89 #: bookwyrm/templates/book/edit/edit_book_form.html:224 msgid "Inventaire ID:" -msgstr "Inventaire ID:" +msgstr "Inventaire-ID:" #: bookwyrm/templates/author/edit_author.html:97 msgid "Librarything key:" -msgstr "Librarything Schlüssel:" +msgstr "Librarything-Schlüssel:" #: bookwyrm/templates/author/edit_author.html:105 msgid "Goodreads key:" -msgstr "Goodreads Schlüssel:" +msgstr "Goodreads-Schlüssel:" #: bookwyrm/templates/author/edit_author.html:116 #: bookwyrm/templates/book/book.html:140 @@ -382,7 +382,7 @@ msgstr "Cover hinzufügen" #: bookwyrm/templates/book/book.html:77 msgid "Failed to load cover" -msgstr "Fehler beim Laden des Covers" +msgstr "Fehler beim Laden des Titelbilds" #: bookwyrm/templates/book/book.html:117 #, python-format @@ -434,11 +434,11 @@ msgstr "Du hast keine Leseaktivität für dieses Buch." #: bookwyrm/templates/book/book.html:218 msgid "Reviews" -msgstr "Rezensionen" +msgstr "Besprechungen" #: bookwyrm/templates/book/book.html:223 msgid "Your reviews" -msgstr "Deine Rezensionen" +msgstr "Deine Besprechungen" #: bookwyrm/templates/book/book.html:229 msgid "Your comments" @@ -523,7 +523,7 @@ msgstr "Existiert \"%(name)s\" bereits als Autor:in?" #: bookwyrm/templates/book/edit/edit_book.html:64 #, python-format msgid "Author of %(book_title)s" -msgstr "Autor von %(book_title)s" +msgstr "Autor*in von %(book_title)s" #: bookwyrm/templates/book/edit/edit_book.html:68 msgid "This is a new author" @@ -591,7 +591,7 @@ msgstr "Veröffentlichungsdatum:" #: bookwyrm/templates/book/edit/edit_book_form.html:104 msgid "Authors" -msgstr "Autoren" +msgstr "Autor*innen" #: bookwyrm/templates/book/edit/edit_book_form.html:112 #, python-format @@ -601,11 +601,11 @@ msgstr "%(name)s entfernen" #: bookwyrm/templates/book/edit/edit_book_form.html:115 #, python-format msgid "Author page for %(name)s" -msgstr "Autorenseite für %(name)s" +msgstr "Autor*innenseite für %(name)s" #: bookwyrm/templates/book/edit/edit_book_form.html:122 msgid "Add Authors:" -msgstr "Autoren hinzufügen:" +msgstr "Autor*innen hinzufügen:" #: bookwyrm/templates/book/edit/edit_book_form.html:123 msgid "John Doe, Jane Smith" @@ -614,7 +614,7 @@ msgstr "Max Mustermann, Maria Musterfrau" #: bookwyrm/templates/book/edit/edit_book_form.html:132 #: bookwyrm/templates/shelf/shelf.html:127 msgid "Cover" -msgstr "Einband" +msgstr "Titelbild" #: bookwyrm/templates/book/edit/edit_book_form.html:161 msgid "Physical Properties" @@ -647,7 +647,7 @@ msgstr "ISBN 10:" #: bookwyrm/templates/book/edit/edit_book_form.html:216 msgid "Openlibrary ID:" -msgstr "OpenLibrary ID:" +msgstr "OpenLibrary-ID:" #: bookwyrm/templates/book/editions/editions.html:4 #, python-format @@ -686,7 +686,7 @@ msgstr "%(pages)s Seiten" #: bookwyrm/templates/book/publisher_info.html:38 #, python-format msgid "%(languages)s language" -msgstr "%(languages)s Sprache" +msgstr "%(languages)s-sprachig" #: bookwyrm/templates/book/publisher_info.html:65 #, python-format @@ -696,7 +696,7 @@ msgstr "Am %(date)s von %(publisher)s veröffentlicht." #: bookwyrm/templates/book/publisher_info.html:67 #, python-format msgid "Published %(date)s" -msgstr "Erscheinungsdatum %(date)s" +msgstr "Erschienen am %(date)s" #: bookwyrm/templates/book/publisher_info.html:69 #, python-format @@ -752,10 +752,8 @@ msgid "Help" msgstr "Hilfe" #: bookwyrm/templates/compose.html:5 bookwyrm/templates/compose.html:8 -#, fuzzy -#| msgid "View status" msgid "Edit status" -msgstr "Status ansehen" +msgstr "Status bearbeiten" #: bookwyrm/templates/confirm_email/confirm_email.html:4 msgid "Confirm email" @@ -763,7 +761,7 @@ msgstr "E-Mail bestätigen" #: bookwyrm/templates/confirm_email/confirm_email.html:7 msgid "Confirm your email address" -msgstr "Bestätigen Sie Ihre E-Mail-Adresse" +msgstr "Bestätige deine E-Mail-Adresse" #: bookwyrm/templates/confirm_email/confirm_email.html:13 msgid "A confirmation code has been sent to the email address you used to register your account." @@ -855,13 +853,13 @@ msgstr "Empfohlen" #: bookwyrm/templates/user/user_preview.html:16 #: bookwyrm/templates/user/user_preview.html:17 msgid "Locked account" -msgstr "Gesperrter Account" +msgstr "Gesperrtes Benutzer*inkonto" #: bookwyrm/templates/directory/user_card.html:40 msgid "follower you follow" msgid_plural "followers you follow" -msgstr[0] "gegenseitiger Follower" -msgstr[1] "gegenseitige Followers" +msgstr[0] "gegenseitige Follower*innen" +msgstr[1] "gegenseitige Follower*innen" #: bookwyrm/templates/directory/user_card.html:47 msgid "book on your shelves" @@ -879,7 +877,7 @@ msgstr "zuletzt aktiv" #: bookwyrm/templates/directory/user_type_filter.html:5 msgid "User type" -msgstr "Art der Benutzer*innen" +msgstr "Benutzer*in-Typ" #: bookwyrm/templates/directory/user_type_filter.html:8 msgid "BookWyrm users" @@ -890,28 +888,24 @@ msgid "All known users" msgstr "Alle bekannten Nutzer*innen" #: bookwyrm/templates/discover/card-header.html:9 -#, fuzzy, python-format -#| msgid "replied to your review of %(book_title)s" +#, python-format msgid "%(username)s rated %(book_title)s" -msgstr "hat auf deine Bewertung von %(book_title)s geantwortet " +msgstr "%(username)s hat %(book_title)s bewertet" #: bookwyrm/templates/discover/card-header.html:13 -#, fuzzy, python-format -#| msgid "replied to your review of %(book_title)s" +#, python-format msgid "%(username)s reviewed %(book_title)s" -msgstr "hat auf deine Bewertung von %(book_title)s geantwortet " +msgstr "%(username)s hat %(book_title)s besprochen" #: bookwyrm/templates/discover/card-header.html:17 -#, fuzzy, python-format -#| msgid "replied to your review of %(book_title)s" +#, python-format msgid "%(username)s commented on %(book_title)s" -msgstr "hat auf deine Bewertung von %(book_title)s geantwortet " +msgstr "%(username)s hat %(book_title)s kommentiert" #: bookwyrm/templates/discover/card-header.html:21 -#, fuzzy, python-format -#| msgid "replied to your review of %(book_title)s" +#, python-format msgid "%(username)s quoted %(book_title)s" -msgstr "hat auf deine Bewertung von %(book_title)s geantwortet " +msgstr "%(username)s hat %(book_title)s zitiert" #: bookwyrm/templates/discover/discover.html:4 #: bookwyrm/templates/discover/discover.html:10 @@ -937,7 +931,7 @@ msgstr "Als letzten Schritt bevor du %(site_name)s beitrittst - bestätige bitte #: bookwyrm/templates/email/confirm/html_content.html:11 msgid "Confirm Email" -msgstr "E-Mail bestätigen" +msgstr "E-Mail-Adresse bestätigen" #: bookwyrm/templates/email/confirm/html_content.html:15 #, python-format @@ -971,17 +965,16 @@ msgstr "E-Mail Einstellungen" #: bookwyrm/templates/email/invite/subject.html:2 #, python-format msgid "You're invited to join %(site_name)s!" -msgstr "Du bist eingeladen %(site_name)s beizutreten!" +msgstr "Du bist eingeladen, %(site_name)s beizutreten!" #: bookwyrm/templates/email/invite/html_content.html:9 msgid "Join Now" msgstr "Tritt jetzt bei" #: bookwyrm/templates/email/invite/html_content.html:15 -#, fuzzy, python-format -#| msgid "Learn more about this instance." +#, python-format msgid "Learn more about %(site_name)s." -msgstr "Erfahre mehr über diese Instanz." +msgstr "Erfahre mehr über %(site_name)s." #: bookwyrm/templates/email/invite/text_content.html:4 #, python-format @@ -989,10 +982,9 @@ msgid "You're invited to join %(site_name)s! Click the link below to create an a msgstr "Du bist eingeladen, %(site_name)s beizutreten! Klicke auf den Link unten um einen Account zu erstellen." #: bookwyrm/templates/email/invite/text_content.html:8 -#, fuzzy, python-format -#| msgid "Learn more about this instance:" +#, python-format msgid "Learn more about %(site_name)s:" -msgstr "Lerne mehr über diese Instanz:" +msgstr "Erfahre mehr über %(site_name)s:" #: bookwyrm/templates/email/password_reset/html_content.html:6 #: bookwyrm/templates/email/password_reset/text_content.html:4 @@ -1078,7 +1070,7 @@ msgstr "Zu lesen" #: bookwyrm/templates/feed/layout.html:26 #: bookwyrm/templates/shelf/shelf.html:40 msgid "Currently Reading" -msgstr "Gegenwärtiger Lesestoff" +msgstr "Lese ich gerade" #: bookwyrm/templates/feed/layout.html:27 #: bookwyrm/templates/shelf/shelf.html:42 @@ -1142,7 +1134,7 @@ msgstr "Empfohlene Bücher" #: bookwyrm/templates/get_started/books.html:46 #, python-format msgid "Popular on %(site_name)s" -msgstr "Beliebt auf %(site_name)s" +msgstr "Auf %(site_name)s beliebt" #: bookwyrm/templates/get_started/books.html:58 #: bookwyrm/templates/lists/list.html:154 @@ -1187,7 +1179,7 @@ msgstr "Schritt überspringen" #: bookwyrm/templates/get_started/layout.html:49 msgid "Finish" -msgstr "Fertig stellen" +msgstr "Fertigstellen" #: bookwyrm/templates/get_started/profile.html:15 #: bookwyrm/templates/preferences/edit_user.html:42 @@ -1224,7 +1216,7 @@ msgstr "Dein Account wird im Verzeichnis gezeigt und möglicherweise anderen Use #: bookwyrm/templates/get_started/users.html:11 msgid "Search for a user" -msgstr "Nach Benutzer*in suchen" +msgstr "Benutzer*in suchen" #: bookwyrm/templates/get_started/users.html:13 #, python-format @@ -1273,7 +1265,7 @@ msgstr "Importstatus" #: bookwyrm/templates/import/import_status.html:11 msgid "Back to imports" -msgstr "" +msgstr "Zurück zu Importen" #: bookwyrm/templates/import/import_status.html:15 msgid "Import started:" @@ -1307,7 +1299,7 @@ msgstr "Zum Ende der Liste springen, um die %(failed_count)s Einträge, deren Im #: bookwyrm/templates/import/import_status.html:62 #, python-format msgid "Line %(index)s: %(title)s by %(author)s" -msgstr "" +msgstr "Zeile %(index)s: %(title)s von %(author)s" #: bookwyrm/templates/import/import_status.html:82 msgid "Select all" @@ -1323,7 +1315,7 @@ msgstr "Erfolgreich importiert" #: bookwyrm/templates/import/import_status.html:114 msgid "Import Progress" -msgstr "" +msgstr "Import-Fortschritt" #: bookwyrm/templates/import/import_status.html:119 msgid "Book" @@ -1346,10 +1338,8 @@ msgid "Imported" msgstr "Importiert" #: bookwyrm/templates/import/tooltip.html:6 -#, fuzzy -#| msgid "You can download your GoodReads data from the Import/Export page of your GoodReads account." msgid "You can download your Goodreads data from the Import/Export page of your Goodreads account." -msgstr "Du kannst dir deine GoodReads Daten von Import/Export page in deinem GoodReads Account runterladen." +msgstr "Du kannst deine Goodreads-Daten von der Import/Export-Seite deines Goodreads-Kontos downloaden." #: bookwyrm/templates/invite.html:4 bookwyrm/templates/invite.html:8 #: bookwyrm/templates/login.html:49 @@ -1393,7 +1383,7 @@ msgstr "Freundlich" #: bookwyrm/templates/landing/layout.html:29 msgid "Anti-Corporate" -msgstr "Unkommerziell" +msgstr "Nichtkommerziell" #: bookwyrm/templates/landing/layout.html:45 #, python-format @@ -1407,7 +1397,7 @@ msgstr "Einladung beantragen" #: bookwyrm/templates/landing/layout.html:49 #, python-format msgid "%(name)s registration is closed" -msgstr "%(name)s Registrierung ist geschlossen" +msgstr "%(name)s erlaubt keine Selbtregistrierung" #: bookwyrm/templates/landing/layout.html:60 msgid "Thank you! Your request has been received." @@ -1420,11 +1410,11 @@ msgstr "Dein Account" #: bookwyrm/templates/layout.html:13 #, python-format msgid "%(site_name)s search" -msgstr "%(site_name)s Suche" +msgstr "%(site_name)s-Suche" #: bookwyrm/templates/layout.html:43 msgid "Search for a book, user, or list" -msgstr "Nach einem Buch, einem Benutzer oder einer Liste suchen" +msgstr "Nach einem Buch, einem*r Benutzer*in oder einer Liste suchen" #: bookwyrm/templates/layout.html:61 bookwyrm/templates/layout.html:62 msgid "Main navigation menu" @@ -1452,7 +1442,7 @@ msgstr "Einladungen" #: bookwyrm/templates/layout.html:132 msgid "Admin" -msgstr "Administrator" +msgstr "Administration" #: bookwyrm/templates/layout.html:139 msgid "Log out" @@ -1468,7 +1458,7 @@ msgstr "Benachrichtigungen" #: bookwyrm/templates/login.html:21 #: bookwyrm/templates/snippets/register_form.html:4 msgid "Username:" -msgstr "Benutzername:" +msgstr "Benutzer*inname:" #: bookwyrm/templates/layout.html:175 msgid "password" @@ -1489,7 +1479,7 @@ msgstr "Beitreten" #: bookwyrm/templates/layout.html:221 msgid "Successfully posted status" -msgstr "Status erfolgreich veröffentlicht" +msgstr "Status veröffentlicht" #: bookwyrm/templates/layout.html:222 msgid "Error posting status" @@ -1715,7 +1705,7 @@ msgstr "%(book_title)s zu deiner Liste \" #: bookwyrm/templates/notifications/items/add.html:31 #, python-format msgid "suggested adding %(book_title)s to your list \"%(list_name)s\"" -msgstr "%(book_title)s zu deiner Liste \"%(list_name)s\" vorgeschlagen" +msgstr "hat vorgeschlagen, %(book_title)s zu deiner Liste „%(list_name)s“ hinzuzufügen" #: bookwyrm/templates/notifications/items/boost.html:19 #, python-format @@ -1738,26 +1728,22 @@ msgid "boosted your status" msgstr "hat deinen Status geteilt" #: bookwyrm/templates/notifications/items/fav.html:19 -#, fuzzy, python-format -#| msgid "favorited your review of %(book_title)s" +#, python-format msgid "liked your review of %(book_title)s" -msgstr "hat deine Bewertung von %(book_title)s favorisiert" +msgstr "hat deine Besprechung von %(book_title)s favorisiert" #: bookwyrm/templates/notifications/items/fav.html:25 -#, fuzzy, python-format -#| msgid "favorited your comment on%(book_title)s" +#, python-format msgid "liked your comment on%(book_title)s" -msgstr "favorisierte deinen Kommentar zu%(book_title)s" +msgstr "hat deinen Kommentar zu %(book_title)s favorisiert" #: bookwyrm/templates/notifications/items/fav.html:31 -#, fuzzy, python-format -#| msgid "favorited your quote from %(book_title)s" +#, python-format msgid "liked your quote from %(book_title)s" -msgstr " hat dein Zitat aus %(book_title)s favorisiert" +msgstr "hat dein Zitat aus %(book_title)s favorisiert" #: bookwyrm/templates/notifications/items/fav.html:37 -#, fuzzy, python-format -#| msgid "favorited your status" +#, python-format msgid "liked your status" msgstr "hat deinen Status favorisiert" @@ -1825,7 +1811,7 @@ msgstr "Benachrichtigungen löschen" #: bookwyrm/templates/notifications/notifications_page.html:29 msgid "All" -msgstr "Alle" +msgstr "Alle(s)" #: bookwyrm/templates/notifications/notifications_page.html:33 msgid "Mentions" @@ -1876,7 +1862,7 @@ msgstr "Neues Passwort:" #: bookwyrm/templates/preferences/layout.html:24 #: bookwyrm/templates/settings/users/delete_user_form.html:23 msgid "Delete Account" -msgstr "Account löschen" +msgstr "Benutzer*inkonto löschen" #: bookwyrm/templates/preferences/delete_user.html:12 msgid "Permanently delete account" @@ -1910,7 +1896,7 @@ msgstr "Privatsphäre" #: bookwyrm/templates/preferences/edit_user.html:72 msgid "Show reading goal prompt in feed:" -msgstr "Zeige Lesezielabfrage im Feed:" +msgstr "Zeige Leseziel-Abfrage im Feed:" #: bookwyrm/templates/preferences/edit_user.html:76 msgid "Show suggested users:" @@ -1931,7 +1917,7 @@ msgstr "Voreinstellung für Beitragssichtbarkeit:" #: bookwyrm/templates/preferences/layout.html:11 msgid "Account" -msgstr "Account" +msgstr "Benutzer*inkonto" #: bookwyrm/templates/preferences/layout.html:27 msgid "Relationships" @@ -1950,7 +1936,7 @@ msgstr "\"%(book_title)s\" beginnen" #: bookwyrm/templates/reading_progress/want.html:5 #, python-format msgid "Want to Read \"%(book_title)s\"" -msgstr "" +msgstr "\"%(book_title)s\" auf Leseliste setzen" #: bookwyrm/templates/search/book.html:47 #: bookwyrm/templates/settings/reports/reports.html:25 @@ -1964,7 +1950,7 @@ msgstr "Buch importieren" #: bookwyrm/templates/search/book.html:107 msgid "Load results from other catalogues" -msgstr "" +msgstr "Ergebnisse aus anderen Katalogen laden" #: bookwyrm/templates/search/book.html:111 msgid "Manually add book" @@ -1980,7 +1966,7 @@ msgstr "Suchanfrage" #: bookwyrm/templates/search/layout.html:19 msgid "Search type" -msgstr "" +msgstr "Suchart" #: bookwyrm/templates/search/layout.html:23 #: bookwyrm/templates/search/layout.html:46 @@ -1995,7 +1981,7 @@ msgstr "Benutzer*innen" #: bookwyrm/templates/search/layout.html:58 #, python-format msgid "No results found for \"%(query)s\"" -msgstr "Für \"%(query)s\" wurden keine Ergebnisse gefunden" +msgstr "Keine Ergebnisse für „%(query)s“ gefunden" #: bookwyrm/templates/settings/announcements/announcement.html:3 #: bookwyrm/templates/settings/announcements/announcement.html:6 @@ -2028,18 +2014,18 @@ msgstr "Nein" #: bookwyrm/templates/settings/announcements/announcement_form.html:40 #: bookwyrm/templates/settings/dashboard/dashboard.html:71 msgid "Start date:" -msgstr "" +msgstr "Startdatum:" #: bookwyrm/templates/settings/announcements/announcement.html:54 #: bookwyrm/templates/settings/announcements/announcement_form.html:49 #: bookwyrm/templates/settings/dashboard/dashboard.html:77 msgid "End date:" -msgstr "" +msgstr "Enddatum:" #: bookwyrm/templates/settings/announcements/announcement.html:60 #: bookwyrm/templates/settings/announcements/announcement_form.html:58 msgid "Active:" -msgstr "" +msgstr "Aktiv:" #: bookwyrm/templates/settings/announcements/announcement_form.html:8 #: bookwyrm/templates/settings/announcements/announcements.html:8 @@ -2056,7 +2042,7 @@ msgstr "Inhalt:" #: bookwyrm/templates/settings/announcements/announcement_form.html:30 msgid "Event date:" -msgstr "" +msgstr "Ereignisdatum:" #: bookwyrm/templates/settings/announcements/announcements.html:3 #: bookwyrm/templates/settings/announcements/announcements.html:5 @@ -2075,11 +2061,11 @@ msgstr "Vorschau" #: bookwyrm/templates/settings/announcements/announcements.html:30 msgid "Start date" -msgstr "" +msgstr "Startdatum" #: bookwyrm/templates/settings/announcements/announcements.html:34 msgid "End date" -msgstr "" +msgstr "Enddatum" #: bookwyrm/templates/settings/announcements/announcements.html:38 #: bookwyrm/templates/settings/federation/instance_list.html:46 @@ -2092,11 +2078,11 @@ msgstr "Status" #: bookwyrm/templates/settings/announcements/announcements.html:48 msgid "active" -msgstr "" +msgstr "aktiv" #: bookwyrm/templates/settings/announcements/announcements.html:48 msgid "inactive" -msgstr "" +msgstr "inaktiv" #: bookwyrm/templates/settings/announcements/announcements.html:52 msgid "No announcements found" @@ -2111,7 +2097,7 @@ msgstr "Übersicht" #: bookwyrm/templates/settings/dashboard/dashboard.html:15 #: bookwyrm/templates/settings/dashboard/dashboard.html:100 msgid "Total users" -msgstr "" +msgstr "Benutzer*innen insgesamt" #: bookwyrm/templates/settings/dashboard/dashboard.html:21 #: bookwyrm/templates/settings/dashboard/user_chart.html:16 @@ -2120,12 +2106,12 @@ msgstr "Diesen Monat aktiv" #: bookwyrm/templates/settings/dashboard/dashboard.html:27 msgid "Statuses" -msgstr "Statusse" +msgstr "Statusmeldungen" #: bookwyrm/templates/settings/dashboard/dashboard.html:33 #: bookwyrm/templates/settings/dashboard/works_chart.html:11 msgid "Works" -msgstr "" +msgstr "Werke" #: bookwyrm/templates/settings/dashboard/dashboard.html:43 #, python-format @@ -2159,11 +2145,11 @@ msgstr "Wochen" #: bookwyrm/templates/settings/dashboard/dashboard.html:106 msgid "User signup activity" -msgstr "" +msgstr "Neuanmeldungen" #: bookwyrm/templates/settings/dashboard/dashboard.html:112 msgid "Status activity" -msgstr "" +msgstr "Statusaktivitäten" #: bookwyrm/templates/settings/dashboard/dashboard.html:118 msgid "Works created" @@ -2171,15 +2157,15 @@ msgstr "Erstellte Werke" #: bookwyrm/templates/settings/dashboard/registration_chart.html:10 msgid "Registrations" -msgstr "Anmeldungen" +msgstr "Registrierungen" #: bookwyrm/templates/settings/dashboard/status_chart.html:11 msgid "Statuses posted" -msgstr "Statusse veröffentlicht" +msgstr "Statusmeldungen veröffentlicht" #: bookwyrm/templates/settings/dashboard/user_chart.html:11 msgid "Total" -msgstr "" +msgstr "Gesamt" #: bookwyrm/templates/settings/email_blocklist/domain_form.html:5 #: bookwyrm/templates/settings/email_blocklist/email_blocklist.html:10 @@ -2188,13 +2174,13 @@ msgstr "Domain hinzufügen" #: bookwyrm/templates/settings/email_blocklist/domain_form.html:11 msgid "Domain:" -msgstr "" +msgstr "Domain:" #: bookwyrm/templates/settings/email_blocklist/email_blocklist.html:5 #: bookwyrm/templates/settings/email_blocklist/email_blocklist.html:7 #: bookwyrm/templates/settings/layout.html:59 msgid "Email Blocklist" -msgstr "E-Mail-Blockliste" +msgstr "E-Mail-Sperrliste" #: bookwyrm/templates/settings/email_blocklist/email_blocklist.html:18 msgid "When someone tries to register with an email from this domain, no account will be created. The registration process will appear to have worked." @@ -2202,12 +2188,12 @@ msgstr "Wenn sich jemand mit einer E-Mail-Adresse von dieser Domain zu registrie #: bookwyrm/templates/settings/email_blocklist/email_blocklist.html:25 msgid "Domain" -msgstr "" +msgstr "Domain" #: bookwyrm/templates/settings/email_blocklist/email_blocklist.html:29 #: bookwyrm/templates/settings/ip_blocklist/ip_blocklist.html:27 msgid "Options" -msgstr "" +msgstr "Optionen" #: bookwyrm/templates/settings/email_blocklist/email_blocklist.html:38 #, python-format @@ -2218,7 +2204,7 @@ msgstr[1] "%(display_count)s Benutzer*innen" #: bookwyrm/templates/settings/email_blocklist/email_blocklist.html:59 msgid "No email domains currently blocked" -msgstr "" +msgstr "Derzeit sind keine E-Mail-Domains gesperrt" #: bookwyrm/templates/settings/federation/edit_instance.html:3 #: bookwyrm/templates/settings/federation/edit_instance.html:6 @@ -2233,12 +2219,12 @@ msgstr "Instanz hinzufügen" #: bookwyrm/templates/settings/federation/edit_instance.html:7 #: bookwyrm/templates/settings/federation/instance_blocklist.html:7 msgid "Back to instance list" -msgstr "Zurück zur Instanzliste" +msgstr "Zurück zur Instanzenliste" #: bookwyrm/templates/settings/federation/edit_instance.html:16 #: bookwyrm/templates/settings/federation/instance_blocklist.html:16 msgid "Import block list" -msgstr "Blockliste importieren" +msgstr "Sperrliste importieren" #: bookwyrm/templates/settings/federation/edit_instance.html:30 msgid "Instance:" @@ -2264,7 +2250,7 @@ msgstr "Version:" #: bookwyrm/templates/settings/federation/edit_instance.html:70 msgid "Notes:" -msgstr "Hinweise:" +msgstr "Anmerkungen:" #: bookwyrm/templates/settings/federation/instance.html:19 msgid "Details" @@ -2277,7 +2263,7 @@ msgstr "Aktivität" #: bookwyrm/templates/settings/federation/instance.html:38 msgid "Users:" -msgstr "Benutzer:" +msgstr "Benutzer*innen:" #: bookwyrm/templates/settings/federation/instance.html:41 #: bookwyrm/templates/settings/federation/instance.html:47 @@ -2291,20 +2277,20 @@ msgstr "Meldungen:" #: bookwyrm/templates/settings/federation/instance.html:50 msgid "Followed by us:" -msgstr "" +msgstr "Folgen wir:" #: bookwyrm/templates/settings/federation/instance.html:55 msgid "Followed by them:" -msgstr "" +msgstr "Folgen:" #: bookwyrm/templates/settings/federation/instance.html:60 msgid "Blocked by us:" -msgstr "" +msgstr "Von uns gesperrt:" #: bookwyrm/templates/settings/federation/instance.html:72 #: bookwyrm/templates/settings/users/user_info.html:110 msgid "Notes" -msgstr "Hinweise" +msgstr "Anmerkungen" #: bookwyrm/templates/settings/federation/instance.html:75 #: bookwyrm/templates/snippets/status/status_options.html:24 @@ -2313,34 +2299,34 @@ msgstr "Ändern" #: bookwyrm/templates/settings/federation/instance.html:79 msgid "No notes" -msgstr "" +msgstr "Keine Anmerkungen" #: bookwyrm/templates/settings/federation/instance.html:94 #: bookwyrm/templates/settings/users/user_moderation_actions.html:8 msgid "Actions" -msgstr "" +msgstr "Aktionen" #: bookwyrm/templates/settings/federation/instance.html:98 #: bookwyrm/templates/snippets/block_button.html:5 msgid "Block" -msgstr "Blockieren" +msgstr "Sperren" #: bookwyrm/templates/settings/federation/instance.html:99 msgid "All users from this instance will be deactivated." -msgstr "Alle Benutzer dieser Instanz werden deaktiviert." +msgstr "Alle Benutzer*innen dieser Instanz werden deaktiviert." #: bookwyrm/templates/settings/federation/instance.html:104 #: bookwyrm/templates/snippets/block_button.html:10 msgid "Un-block" -msgstr "Entblocken" +msgstr "Entsperren" #: bookwyrm/templates/settings/federation/instance.html:105 msgid "All users from this instance will be re-activated." -msgstr "Alle Benutzer dieser Instanz werden wieder aktiviert." +msgstr "Alle Benutzer*innen dieser Instanz werden wieder aktiviert." #: bookwyrm/templates/settings/federation/instance_blocklist.html:6 msgid "Import Blocklist" -msgstr "Blockliste importieren" +msgstr "Sperrliste importieren" #: bookwyrm/templates/settings/federation/instance_blocklist.html:26 #: bookwyrm/templates/snippets/goal_progress.html:7 @@ -2349,7 +2335,7 @@ msgstr "Erfolg!" #: bookwyrm/templates/settings/federation/instance_blocklist.html:30 msgid "Successfully blocked:" -msgstr "Erfolgreich blockiert:" +msgstr "Erfolgreich gesperrt:" #: bookwyrm/templates/settings/federation/instance_blocklist.html:32 msgid "Failed:" @@ -2391,7 +2377,7 @@ msgstr "Datum der Anfrage" #: bookwyrm/templates/settings/invites/manage_invite_requests.html:39 msgid "Date accepted" -msgstr "Datum der Annahme" +msgstr "Datum der Bestätigung" #: bookwyrm/templates/settings/invites/manage_invite_requests.html:42 msgid "Email" @@ -2408,7 +2394,7 @@ msgstr "Keine Anfragen" #: bookwyrm/templates/settings/invites/manage_invite_requests.html:59 #: bookwyrm/templates/settings/invites/status_filter.html:16 msgid "Accepted" -msgstr "Akzeptiert" +msgstr "Bestätigt" #: bookwyrm/templates/settings/invites/manage_invite_requests.html:61 #: bookwyrm/templates/settings/invites/status_filter.html:12 @@ -2438,7 +2424,7 @@ msgstr "Un-ignorieren" #: bookwyrm/templates/settings/invites/manage_invite_requests.html:108 msgid "Back to pending requests" -msgstr "Keine ausstehenden Anfragen" +msgstr "Zurück zu ausstehenden Anfragen" #: bookwyrm/templates/settings/invites/manage_invite_requests.html:110 msgid "View ignored requests" @@ -2487,7 +2473,7 @@ msgstr "IP-Adresse hinzufügen" #: bookwyrm/templates/settings/ip_blocklist/ip_address_form.html:11 msgid "Use IP address blocks with caution, and consider using blocks only temporarily, as IP addresses are often shared or change hands. If you block your own IP, you will not be able to access this page." -msgstr "" +msgstr "Lass bei der Sperrung von IP-Adressen Vorsicht walten. Erwäge, IP-Adressen nur vorübergehend zu sperren, da sie oft geteilt werden oder neu zugeordnet werden. Wenn du deine eigene IP blockierst, kannst du nicht mehr auf diese Seite zugreifen." #: bookwyrm/templates/settings/ip_blocklist/ip_address_form.html:18 msgid "IP Address:" @@ -2497,27 +2483,27 @@ msgstr "IP-Adresse:" #: bookwyrm/templates/settings/ip_blocklist/ip_blocklist.html:7 #: bookwyrm/templates/settings/layout.html:63 msgid "IP Address Blocklist" -msgstr "" +msgstr "IP-Addressen-Sperrliste" #: bookwyrm/templates/settings/ip_blocklist/ip_blocklist.html:18 msgid "Any traffic from this IP address will get a 404 response when trying to access any part of the application." -msgstr "" +msgstr "Jeder Datenverkehr von dieser IP-Adresse erhält eine 404-Antwort, wenn versucht wird, auf einen beliebigen Teil der Anwendung zuzugreifen." #: bookwyrm/templates/settings/ip_blocklist/ip_blocklist.html:24 msgid "Address" -msgstr "" +msgstr "Adresse" #: bookwyrm/templates/settings/ip_blocklist/ip_blocklist.html:46 msgid "No IP addresses currently blocked" -msgstr "" +msgstr "Derzeit sind keine IP-Adressen gesperrt" #: bookwyrm/templates/settings/ip_blocklist/ip_tooltip.html:6 msgid "You can block IP ranges using CIDR syntax." -msgstr "" +msgstr "Du kannst IP-Bereiche mittels CIDR-Syntax blockieren." #: bookwyrm/templates/settings/layout.html:4 msgid "Administration" -msgstr "" +msgstr "Administration" #: bookwyrm/templates/settings/layout.html:29 msgid "Manage Users" @@ -2525,7 +2511,7 @@ msgstr "Nutzer*innen verwalten" #: bookwyrm/templates/settings/layout.html:51 msgid "Moderation" -msgstr "" +msgstr "Moderation" #: bookwyrm/templates/settings/layout.html:55 #: bookwyrm/templates/settings/reports/reports.html:8 @@ -2565,7 +2551,7 @@ msgstr "Kommentieren" #: bookwyrm/templates/settings/reports/report.html:46 msgid "Reported statuses" -msgstr "" +msgstr "Gemeldete Statusmeldungen" #: bookwyrm/templates/settings/reports/report.html:48 msgid "No statuses reported" @@ -2573,7 +2559,7 @@ msgstr "Keine Beiträge gemeldet" #: bookwyrm/templates/settings/reports/report.html:54 msgid "Status has been deleted" -msgstr "" +msgstr "Statusmeldung gelöscht" #: bookwyrm/templates/settings/reports/report_preview.html:13 msgid "No notes provided" @@ -2604,11 +2590,11 @@ msgstr "Meldungen: %(instance_name)s" #: bookwyrm/templates/settings/reports/reports.html:28 msgid "Resolved" -msgstr "" +msgstr "Behoben" #: bookwyrm/templates/settings/reports/reports.html:37 msgid "No reports found." -msgstr "" +msgstr "Keine Meldungen gefunden." #: bookwyrm/templates/settings/site.html:10 #: bookwyrm/templates/settings/site.html:21 @@ -2636,7 +2622,7 @@ msgstr "Instanzname" #: bookwyrm/templates/settings/site.html:28 msgid "Tagline:" -msgstr "" +msgstr "Motto:" #: bookwyrm/templates/settings/site.html:32 msgid "Instance description:" @@ -2644,15 +2630,15 @@ msgstr "Instanzbeschreibung" #: bookwyrm/templates/settings/site.html:36 msgid "Short description:" -msgstr "" +msgstr "Kurzbeschreibung:" #: bookwyrm/templates/settings/site.html:37 msgid "Used when the instance is previewed on joinbookwyrm.com. Does not support HTML or Markdown." -msgstr "" +msgstr "Wird verwendet, wenn die Instanz auf joinbookwyrm.com in der Vorschau angezeigt wird. Unterstützt weder HTML noch Markdown." #: bookwyrm/templates/settings/site.html:41 msgid "Code of conduct:" -msgstr "" +msgstr "Verhaltenskodex:" #: bookwyrm/templates/settings/site.html:45 msgid "Privacy Policy:" @@ -2680,7 +2666,7 @@ msgstr "Unterstützungstitel" #: bookwyrm/templates/settings/site.html:85 msgid "Admin email:" -msgstr "" +msgstr "E-Mail-Adresse des*r Administrator*in:" #: bookwyrm/templates/settings/site.html:89 msgid "Additional info:" @@ -2688,11 +2674,11 @@ msgstr "Zusätzliche Info:" #: bookwyrm/templates/settings/site.html:103 msgid "Allow registration" -msgstr "" +msgstr "Selbstregistrierung zulassen" #: bookwyrm/templates/settings/site.html:109 msgid "Allow invite requests" -msgstr "" +msgstr "Einladungsanfragen zulassen" #: bookwyrm/templates/settings/site.html:115 msgid "Require users to confirm email address" @@ -2708,7 +2694,7 @@ msgstr "Registrierungen geschlossen text" #: bookwyrm/templates/settings/site.html:124 msgid "Invite request text:" -msgstr "" +msgstr "Hinweis für Einladungsanfragen:" #: bookwyrm/templates/settings/users/delete_user_form.html:5 #: bookwyrm/templates/settings/users/user_moderation_actions.html:31 @@ -2726,21 +2712,21 @@ msgstr "Dein Passwort:" #: bookwyrm/templates/settings/users/user.html:7 msgid "Back to users" -msgstr "" +msgstr "Zurück zu Benutzer*innen" #: bookwyrm/templates/settings/users/user_admin.html:7 #, python-format msgid "Users: %(instance_name)s" -msgstr "" +msgstr "Benutzer*innen: %(instance_name)s" #: bookwyrm/templates/settings/users/user_admin.html:22 #: bookwyrm/templates/settings/users/username_filter.html:5 msgid "Username" -msgstr "Benutzername" +msgstr "Benutzer*inname" #: bookwyrm/templates/settings/users/user_admin.html:26 msgid "Date Added" -msgstr "" +msgstr "Hinzugefügt am" #: bookwyrm/templates/settings/users/user_admin.html:30 msgid "Last Active" @@ -2748,12 +2734,12 @@ msgstr "Zuletzt aktiv" #: bookwyrm/templates/settings/users/user_admin.html:38 msgid "Remote instance" -msgstr "" +msgstr "Entfernte Instanz" #: bookwyrm/templates/settings/users/user_admin.html:47 #: bookwyrm/templates/settings/users/user_info.html:24 msgid "Active" -msgstr "" +msgstr "Aktiv" #: bookwyrm/templates/settings/users/user_admin.html:47 #: bookwyrm/templates/settings/users/user_info.html:28 @@ -2767,7 +2753,7 @@ msgstr "Nicht gesetzt" #: bookwyrm/templates/settings/users/user_info.html:16 msgid "View user profile" -msgstr "" +msgstr "Benutzer*inprofil anzeigen" #: bookwyrm/templates/settings/users/user_info.html:36 msgid "Local" @@ -2775,11 +2761,11 @@ msgstr "Lokal" #: bookwyrm/templates/settings/users/user_info.html:38 msgid "Remote" -msgstr "" +msgstr "Entfernt" #: bookwyrm/templates/settings/users/user_info.html:47 msgid "User details" -msgstr "Benutzerdetails" +msgstr "Benutzer*indetails" #: bookwyrm/templates/settings/users/user_info.html:51 msgid "Email:" @@ -2787,19 +2773,19 @@ msgstr "E-Mail:" #: bookwyrm/templates/settings/users/user_info.html:61 msgid "(View reports)" -msgstr "" +msgstr "(Meldungen anzeigen)" #: bookwyrm/templates/settings/users/user_info.html:67 msgid "Blocked by count:" -msgstr "" +msgstr "Gesperrt durch (Anzahl):" #: bookwyrm/templates/settings/users/user_info.html:70 msgid "Last active date:" -msgstr "" +msgstr "Zuletzt aktiv:" #: bookwyrm/templates/settings/users/user_info.html:73 msgid "Manually approved followers:" -msgstr "" +msgstr "Manuell zugelassene Follower*innen:" #: bookwyrm/templates/settings/users/user_info.html:76 msgid "Discoverable:" @@ -2807,11 +2793,11 @@ msgstr "Entdeckbar:" #: bookwyrm/templates/settings/users/user_info.html:80 msgid "Deactivation reason:" -msgstr "" +msgstr "Grund der Deaktivierung:" #: bookwyrm/templates/settings/users/user_info.html:95 msgid "Instance details" -msgstr "" +msgstr "Instanzdetails" #: bookwyrm/templates/settings/users/user_info.html:117 msgid "View instance" @@ -2829,15 +2815,15 @@ msgstr "Direktnachricht senden" #: bookwyrm/templates/settings/users/user_moderation_actions.html:20 msgid "Suspend user" -msgstr "" +msgstr "Benutzer*in vorläufig sperren" #: bookwyrm/templates/settings/users/user_moderation_actions.html:25 msgid "Un-suspend user" -msgstr "" +msgstr "Vorläufige Sperre für Benutzer*in aufheben" #: bookwyrm/templates/settings/users/user_moderation_actions.html:47 msgid "Access level:" -msgstr "" +msgstr "Zugriffsstufe:" #: bookwyrm/templates/shelf/create_shelf_form.html:5 msgid "Create Shelf" @@ -2897,14 +2883,14 @@ msgstr "Dieses Regal ist leer." #: bookwyrm/templates/snippets/announcement.html:31 #, python-format msgid "Posted by %(username)s" -msgstr "" +msgstr "Von %(username)s veröffentlicht" #: bookwyrm/templates/snippets/authors.html:22 #, python-format msgid "and %(remainder_count_display)s other" msgid_plural "and %(remainder_count_display)s others" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "und %(remainder_count_display)s Andere*r" +msgstr[1] "und %(remainder_count_display)s Andere" #: bookwyrm/templates/snippets/book_cover.html:61 msgid "No cover" @@ -2913,17 +2899,17 @@ msgstr "Kein Titelbild" #: bookwyrm/templates/snippets/book_titleby.html:6 #, python-format msgid "%(title)s by" -msgstr "" +msgstr "%(title)s von" #: bookwyrm/templates/snippets/boost_button.html:20 #: bookwyrm/templates/snippets/boost_button.html:21 msgid "Boost" -msgstr "" +msgstr "Teilen" #: bookwyrm/templates/snippets/boost_button.html:33 #: bookwyrm/templates/snippets/boost_button.html:34 msgid "Un-boost" -msgstr "" +msgstr "Teilen zurücknehmen" #: bookwyrm/templates/snippets/create_status.html:17 msgid "Review" @@ -2966,11 +2952,11 @@ msgstr "Antwort" #: bookwyrm/templates/snippets/create_status/content_field.html:17 msgid "Content" -msgstr "" +msgstr "Inhalt" #: bookwyrm/templates/snippets/create_status/content_warning_field.html:10 msgid "Content warning:" -msgstr "" +msgstr "Inhaltswarnung:" #: bookwyrm/templates/snippets/create_status/content_warning_field.html:18 msgid "Spoilers ahead!" @@ -3003,11 +2989,11 @@ msgstr "Zitat:" #: bookwyrm/templates/snippets/create_status/quotation.html:25 #, python-format msgid "An excerpt from '%(book_title)s'" -msgstr "" +msgstr "Ein Auszug aus „%(book_title)s“" #: bookwyrm/templates/snippets/create_status/quotation.html:32 msgid "Position:" -msgstr "" +msgstr "Position:" #: bookwyrm/templates/snippets/create_status/quotation.html:45 msgid "On page:" @@ -3015,16 +3001,16 @@ msgstr "Auf Seite:" #: bookwyrm/templates/snippets/create_status/quotation.html:51 msgid "At percent:" -msgstr "" +msgstr "Bei Prozentsatz:" #: bookwyrm/templates/snippets/create_status/review.html:25 #, python-format msgid "Your review of '%(book_title)s'" -msgstr "Deine Rezension von '%(book_title)s'" +msgstr "Deine Besprechung von „%(book_title)s“" #: bookwyrm/templates/snippets/create_status/review.html:40 msgid "Review:" -msgstr "" +msgstr "Besprechung:" #: bookwyrm/templates/snippets/delete_readthrough_modal.html:4 msgid "Delete these read dates?" @@ -3043,7 +3029,7 @@ msgstr "Favorisieren" #: bookwyrm/templates/snippets/fav_button.html:30 #: bookwyrm/templates/snippets/fav_button.html:31 msgid "Un-like" -msgstr "" +msgstr "Favorisierung zurücknehmen" #: bookwyrm/templates/snippets/filters_panel/filters_panel.html:7 msgid "Show filters" @@ -3059,12 +3045,12 @@ msgstr "Filter anwenden" #: bookwyrm/templates/snippets/filters_panel/filters_panel.html:26 msgid "Clear filters" -msgstr "" +msgstr "Filter zurücksetzen" #: bookwyrm/templates/snippets/follow_button.html:14 #, python-format msgid "Follow @%(username)s" -msgstr "" +msgstr "@%(username)s folgen" #: bookwyrm/templates/snippets/follow_button.html:16 msgid "Follow" @@ -3072,12 +3058,12 @@ msgstr "Folgen" #: bookwyrm/templates/snippets/follow_button.html:25 msgid "Undo follow request" -msgstr "" +msgstr "Folgeanfrage zurücknehmen" #: bookwyrm/templates/snippets/follow_button.html:30 #, python-format msgid "Unfollow @%(username)s" -msgstr "" +msgstr "@%(username)s entfolgen" #: bookwyrm/templates/snippets/follow_button.html:32 msgid "Unfollow" @@ -3096,16 +3082,16 @@ msgstr "Kein Rating" #, python-format msgid "%(half_rating)s star" msgid_plural "%(half_rating)s stars" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "%(half_rating)s Stern" +msgstr[1] "%(half_rating)s Sterne" #: bookwyrm/templates/snippets/form_rate_stars.html:64 #: bookwyrm/templates/snippets/stars.html:7 #, python-format msgid "%(rating)s star" msgid_plural "%(rating)s stars" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "%(rating)s Stern" +msgstr[1] "%(rating)s Sterne" #: bookwyrm/templates/snippets/generated_status/goal.html:2 #, python-format @@ -3118,15 +3104,15 @@ msgstr[1] "Setze das Ziel, %(year)s %(counter)s Bücher zu lesen" #, python-format msgid "rated %(title)s: %(display_rating)s star" msgid_plural "rated %(title)s: %(display_rating)s stars" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "hat %(title)s mit %(display_rating)s Stern bewertet" +msgstr[1] "hat %(title)s mit %(display_rating)s Sternen bewertet" #: bookwyrm/templates/snippets/generated_status/review_pure_name.html:4 #, python-format msgid "Review of \"%(book_title)s\" (%(display_rating)s star): %(review_title)s" msgid_plural "Review of \"%(book_title)s\" (%(display_rating)s stars): %(review_title)s" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "Besprechung von „%(book_title)s“ (%(display_rating)s Stern): %(review_title)s" +msgstr[1] "Besprechung von „%(book_title)s“ (%(display_rating)s Sterne): %(review_title)s" #: bookwyrm/templates/snippets/generated_status/review_pure_name.html:8 #, python-format @@ -3177,12 +3163,12 @@ msgstr "%(username)s hat %(read_count)s von %(goal_count)s #: bookwyrm/templates/snippets/page_text.html:8 #, python-format msgid "page %(page)s of %(total_pages)s" -msgstr "" +msgstr "Seite %(page)s von %(total_pages)s" #: bookwyrm/templates/snippets/page_text.html:14 #, python-format msgid "page %(page)s" -msgstr "" +msgstr "Seite %(page)s" #: bookwyrm/templates/snippets/pagination.html:12 msgid "Previous" @@ -3224,7 +3210,7 @@ msgstr "Raten" #: bookwyrm/templates/snippets/rate_action.html:19 msgid "Rate" -msgstr "" +msgstr "Bewerten" #: bookwyrm/templates/snippets/reading_modals/finish_reading_modal.html:6 #, python-format @@ -3244,12 +3230,12 @@ msgstr "Zu Ende gelesen" #: bookwyrm/templates/snippets/reading_modals/form.html:9 msgid "(Optional)" -msgstr "" +msgstr "(Optional)" #: bookwyrm/templates/snippets/reading_modals/progress_update_modal.html:5 #: bookwyrm/templates/snippets/shelve_button/shelve_button_dropdown_options.html:50 msgid "Update progress" -msgstr "" +msgstr "Update-Fortschritt" #: bookwyrm/templates/snippets/reading_modals/start_reading_modal.html:6 #, python-format @@ -3271,12 +3257,12 @@ msgstr "Registrieren" #: bookwyrm/templates/snippets/report_button.html:6 msgid "Report" -msgstr "" +msgstr "Melden" #: bookwyrm/templates/snippets/report_modal.html:6 #, python-format msgid "Report @%(username)s" -msgstr "" +msgstr "@%(username)s melden" #: bookwyrm/templates/snippets/report_modal.html:23 #, python-format @@ -3285,11 +3271,11 @@ msgstr "Diese Meldung wird an die Moderator:innen von %(site_name)s weitergeleti #: bookwyrm/templates/snippets/report_modal.html:24 msgid "More info about this report:" -msgstr "" +msgstr "Weitere Angeben zu dieser Meldung:" #: bookwyrm/templates/snippets/shelf_selector.html:4 msgid "Move book" -msgstr "" +msgstr "Buch verschieben" #: bookwyrm/templates/snippets/shelve_button/shelve_button_dropdown.html:5 msgid "More shelves" @@ -3308,7 +3294,7 @@ msgstr "Auf Leseliste setzen" #: bookwyrm/templates/snippets/shelve_button/shelve_button_dropdown_options.html:62 #, python-format msgid "Remove from %(name)s" -msgstr "" +msgstr "Aus %(name)s entfernen" #: bookwyrm/templates/snippets/shelve_button/shelve_button_options.html:30 msgid "Finish reading" @@ -3316,21 +3302,21 @@ msgstr "Lesen abschließen" #: bookwyrm/templates/snippets/status/content_status.html:72 msgid "Content warning" -msgstr "" +msgstr "Inhaltswarnung" #: bookwyrm/templates/snippets/status/content_status.html:79 msgid "Show status" -msgstr "" +msgstr "Status anzeigen" #: bookwyrm/templates/snippets/status/content_status.html:101 #, python-format msgid "(Page %(page)s)" -msgstr "" +msgstr "(Seite %(page)s)" #: bookwyrm/templates/snippets/status/content_status.html:103 #, python-format msgid "(%(percent)s%%)" -msgstr "" +msgstr "(%(percent)s%%)" #: bookwyrm/templates/snippets/status/content_status.html:125 msgid "Open image in new window" @@ -3338,53 +3324,52 @@ msgstr "Bild in neuem Fenster öffnen" #: bookwyrm/templates/snippets/status/content_status.html:144 msgid "Hide status" -msgstr "" +msgstr "Status ausblenden" #: bookwyrm/templates/snippets/status/header.html:45 -#, fuzzy, python-format -#| msgid "Joined %(date)s" +#, python-format msgid "edited %(date)s" -msgstr "Beigetreten %(date)s" +msgstr "%(date)s bearbeitet" #: bookwyrm/templates/snippets/status/headers/comment.html:2 #, python-format msgid "commented on %(book)s" -msgstr "" +msgstr "hat %(book)s kommentiert" #: bookwyrm/templates/snippets/status/headers/note.html:15 #, python-format msgid "replied to %(username)s's status" -msgstr "" +msgstr "hat auf die Statusmeldung von %(username)s geantwortet" #: bookwyrm/templates/snippets/status/headers/quotation.html:2 #, python-format msgid "quoted %(book)s" -msgstr "" +msgstr "hat %(book)s zitiert" #: bookwyrm/templates/snippets/status/headers/rating.html:3 #, python-format msgid "rated %(book)s:" -msgstr "" +msgstr "hat %(book)s bewertet:" #: bookwyrm/templates/snippets/status/headers/read.html:7 #, python-format msgid "finished reading %(book)s" -msgstr "" +msgstr "hat %(book)s ausgelesen" #: bookwyrm/templates/snippets/status/headers/reading.html:7 #, python-format msgid "started reading %(book)s" -msgstr "" +msgstr "hat angefangen, %(book)s zu lesen" #: bookwyrm/templates/snippets/status/headers/review.html:3 #, python-format msgid "reviewed %(book)s" -msgstr "" +msgstr "hat %(book)s besprochen" #: bookwyrm/templates/snippets/status/headers/to_read.html:7 #, python-format msgid "%(username)s wants to read %(book)s" -msgstr "" +msgstr "%(username)s hat %(book)s auf die Leseliste gesetzt" #: bookwyrm/templates/snippets/status/layout.html:24 #: bookwyrm/templates/snippets/status/status_options.html:17 @@ -3414,20 +3399,20 @@ msgstr "Mehr Optionen" #, python-format msgid "%(mutuals)s follower you follow" msgid_plural "%(mutuals)s followers you follow" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "%(mutuals)s Follower*in, der*die du folgst" +msgstr[1] "%(mutuals)s Follower*innen, denen du folgst" #: bookwyrm/templates/snippets/suggested_users.html:23 #, python-format msgid "%(shared_books)s book on your shelves" msgid_plural "%(shared_books)s books on your shelves" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "%(shared_books)s Buch in deinen Regalen" +msgstr[1] "%(shared_books)s Bücher in deinen Regalen" #: bookwyrm/templates/snippets/suggested_users.html:31 #: bookwyrm/templates/user/user_preview.html:36 msgid "Follows you" -msgstr "" +msgstr "Folgt dir" #: bookwyrm/templates/snippets/switch_edition_button.html:5 msgid "Switch to this edition" @@ -3435,11 +3420,11 @@ msgstr "Zu dieser Edition wechseln" #: bookwyrm/templates/snippets/table-sort-header.html:6 msgid "Sorted ascending" -msgstr "" +msgstr "Aufsteigend sortiert" #: bookwyrm/templates/snippets/table-sort-header.html:10 msgid "Sorted descending" -msgstr "" +msgstr "Absteigend sortiert" #: bookwyrm/templates/snippets/trimmed_text.html:17 msgid "Show more" @@ -3452,7 +3437,7 @@ msgstr "Weniger anzeigen" #: bookwyrm/templates/user/books_header.html:5 #, python-format msgid "%(username)s's books" -msgstr "" +msgstr "Bücher von %(username)s" #: bookwyrm/templates/user/goal.html:8 #, python-format @@ -3521,7 +3506,7 @@ msgstr "Profil bearbeiten" #: bookwyrm/templates/user/user.html:33 #, python-format msgid "View all %(size)s" -msgstr "" +msgstr "Alle %(size)s anzeigen" #: bookwyrm/templates/user/user.html:46 msgid "View all books" @@ -3533,7 +3518,7 @@ msgstr "Nutzer*innenaktivität" #: bookwyrm/templates/user/user.html:63 msgid "RSS feed" -msgstr "" +msgstr "RSS-Feed" #: bookwyrm/templates/user/user.html:74 msgid "No activities yet!" @@ -3560,21 +3545,21 @@ msgstr "Folgt %(counter)s" #, python-format msgid "%(mutuals_display)s follower you follow" msgid_plural "%(mutuals_display)s followers you follow" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "%(mutuals_display)s Follower*in, der*die du folgst" +msgstr[1] "%(mutuals_display)s Follower*in, der*die du folgst" #: bookwyrm/templates/user/user_preview.html:38 msgid "No followers you follow" -msgstr "" +msgstr "Keine Follower*innen, denen du folgst" #: bookwyrm/templates/widgets/clearable_file_input_with_warning.html:28 msgid "File exceeds maximum size: 10MB" -msgstr "" +msgstr "Datei überschreitet die maximale Größe von 10MB" #: bookwyrm/templatetags/utilities.py:31 #, python-format msgid "%(title)s: %(subtitle)s" -msgstr "" +msgstr "%(title)s: %(subtitle)s" #: bookwyrm/views/import_data.py:67 msgid "Not a valid csv file" @@ -3586,7 +3571,7 @@ msgstr "Username oder Passwort sind falsch" #: bookwyrm/views/password.py:32 msgid "No user with that email address was found." -msgstr "" +msgstr "Es wurde kein*e Benutzer*in mit dieser E-Mail-Adresse gefunden." #: bookwyrm/views/password.py:41 #, python-brace-format @@ -3598,23 +3583,3 @@ msgstr "Ein Passwortwiederherstellungslinl wurde zu {email} gesendet" msgid "Status updates from {obj.display_name}" msgstr "Status updates von {obj.display_name}" -#~ msgid "Compose status" -#~ msgstr "Status verfassen" - -#~ msgid "%(format)s" -#~ msgstr "Formate: %(format)s" - -#~ msgid "rated" -#~ msgstr "bewertet" - -#~ msgid "reviewed" -#~ msgstr "bewertete" - -#~ msgid "commented on" -#~ msgstr "kommentierte" - -#~ msgid "quoted" -#~ msgstr "zitierte" - -#~ msgid "About this instance" -#~ msgstr "Über diese Instanz" From baba2e2057a4e675a178cc21cc32882c1a12bbbb Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Wed, 20 Oct 2021 13:08:33 -0700 Subject: [PATCH 02/17] Move shelf views into directory --- bookwyrm/views/__init__.py | 8 +++++--- bookwyrm/views/shelf/__init__.py | 0 bookwyrm/views/{ => shelf}/shelf.py | 0 3 files changed, 5 insertions(+), 3 deletions(-) create mode 100644 bookwyrm/views/shelf/__init__.py rename bookwyrm/views/{ => shelf}/shelf.py (100%) diff --git a/bookwyrm/views/__init__.py b/bookwyrm/views/__init__.py index b502bd8d5..ba83b5320 100644 --- a/bookwyrm/views/__init__.py +++ b/bookwyrm/views/__init__.py @@ -38,6 +38,11 @@ from .landing.login import Login, Logout from .landing.register import Register, ConfirmEmail, ConfirmEmailCode, resend_link from .landing.password import PasswordResetRequest, PasswordReset +# shelves +from .shelf.shelf import Shelf +from .shelf.shelf import create_shelf, delete_shelf +from .shelf.shelf import shelve, unshelve + # misc views from .author import Author, EditAuthor from .directory import Directory @@ -69,9 +74,6 @@ from .reading import create_readthrough, delete_readthrough, delete_progressupda from .reading import ReadingStatus from .rss_feed import RssFeed from .search import Search -from .shelf import Shelf -from .shelf import create_shelf, delete_shelf -from .shelf import shelve, unshelve from .status import CreateStatus, EditStatus, DeleteStatus, update_progress from .status import edit_readthrough from .updates import get_notification_count, get_unread_status_count diff --git a/bookwyrm/views/shelf/__init__.py b/bookwyrm/views/shelf/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/bookwyrm/views/shelf.py b/bookwyrm/views/shelf/shelf.py similarity index 100% rename from bookwyrm/views/shelf.py rename to bookwyrm/views/shelf/shelf.py From 6a2f962f8db0314849e8b9b3908d8347e24116a3 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Wed, 20 Oct 2021 13:15:43 -0700 Subject: [PATCH 03/17] Split shelf view into multiple files --- bookwyrm/views/__init__.py | 4 +- bookwyrm/views/shelf/shelf.py | 100 +------------------------ bookwyrm/views/shelf/shelf_actions.py | 103 ++++++++++++++++++++++++++ 3 files changed, 106 insertions(+), 101 deletions(-) create mode 100644 bookwyrm/views/shelf/shelf_actions.py diff --git a/bookwyrm/views/__init__.py b/bookwyrm/views/__init__.py index ba83b5320..e1dd83557 100644 --- a/bookwyrm/views/__init__.py +++ b/bookwyrm/views/__init__.py @@ -40,8 +40,8 @@ from .landing.password import PasswordResetRequest, PasswordReset # shelves from .shelf.shelf import Shelf -from .shelf.shelf import create_shelf, delete_shelf -from .shelf.shelf import shelve, unshelve +from .shelf.shelf_actions import create_shelf, delete_shelf +from .shelf.shelf_actions import shelve, unshelve # misc views from .author import Author, EditAuthor diff --git a/bookwyrm/views/shelf/shelf.py b/bookwyrm/views/shelf/shelf.py index 0b830d906..f8cffe93f 100644 --- a/bookwyrm/views/shelf/shelf.py +++ b/bookwyrm/views/shelf/shelf.py @@ -1,7 +1,6 @@ """ shelf views """ from collections import namedtuple -from django.db import IntegrityError, transaction from django.db.models import OuterRef, Subquery, F from django.contrib.auth.decorators import login_required from django.core.paginator import Paginator @@ -11,12 +10,11 @@ from django.template.response import TemplateResponse from django.utils.decorators import method_decorator from django.utils.translation import gettext_lazy as _ from django.views import View -from django.views.decorators.http import require_POST from bookwyrm import forms, models from bookwyrm.activitypub import ActivitypubResponse from bookwyrm.settings import PAGE_LENGTH -from .helpers import is_api_request, get_user_from_username +from bookwyrm.views.helpers import is_api_request, get_user_from_username # pylint: disable=no-self-use @@ -128,102 +126,6 @@ class Shelf(View): return redirect(shelf.local_path) -@login_required -@require_POST -def create_shelf(request): - """user generated shelves""" - form = forms.ShelfForm(request.POST) - if not form.is_valid(): - return redirect(request.headers.get("Referer", "/")) - - shelf = form.save() - return redirect(shelf.local_path) - - -@login_required -@require_POST -def delete_shelf(request, shelf_id): - """user generated shelves""" - shelf = get_object_or_404(models.Shelf, id=shelf_id) - shelf.raise_not_deletable(request.user) - - shelf.delete() - return redirect("user-shelves", request.user.localname) - - -@login_required -@require_POST -@transaction.atomic -def shelve(request): - """put a book on a user's shelf""" - book = get_object_or_404(models.Edition, id=request.POST.get("book")) - desired_shelf = get_object_or_404( - request.user.shelf_set, identifier=request.POST.get("shelf") - ) - - # first we need to remove from the specified shelf - change_from_current_identifier = request.POST.get("change-shelf-from") - if change_from_current_identifier: - # find the shelfbook obj and delete it - get_object_or_404( - models.ShelfBook, - book=book, - user=request.user, - shelf__identifier=change_from_current_identifier, - ).delete() - - # A book can be on multiple shelves, but only on one read status shelf at a time - if desired_shelf.identifier in models.Shelf.READ_STATUS_IDENTIFIERS: - # figure out where state shelf it's currently on (if any) - current_read_status_shelfbook = ( - models.ShelfBook.objects.select_related("shelf") - .filter( - shelf__identifier__in=models.Shelf.READ_STATUS_IDENTIFIERS, - user=request.user, - book=book, - ) - .first() - ) - if current_read_status_shelfbook is not None: - if ( - current_read_status_shelfbook.shelf.identifier - != desired_shelf.identifier - ): - current_read_status_shelfbook.delete() - else: # It is already on the shelf - return redirect(request.headers.get("Referer", "/")) - - # create the new shelf-book entry - models.ShelfBook.objects.create( - book=book, shelf=desired_shelf, user=request.user - ) - else: - # we're putting it on a custom shelf - try: - models.ShelfBook.objects.create( - book=book, shelf=desired_shelf, user=request.user - ) - # The book is already on this shelf. - # Might be good to alert, or reject the action? - except IntegrityError: - pass - return redirect(request.headers.get("Referer", "/")) - - -@login_required -@require_POST -def unshelve(request): - """put a on a user's shelf""" - book = get_object_or_404(models.Edition, id=request.POST.get("book")) - shelf_book = get_object_or_404( - models.ShelfBook, book=book, shelf__id=request.POST["shelf"] - ) - shelf_book.raise_not_deletable(request.user) - - shelf_book.delete() - return redirect(request.headers.get("Referer", "/")) - - def sort_books(books, sort): """Books in shelf sorting""" sort_fields = [ diff --git a/bookwyrm/views/shelf/shelf_actions.py b/bookwyrm/views/shelf/shelf_actions.py new file mode 100644 index 000000000..470b2d3d3 --- /dev/null +++ b/bookwyrm/views/shelf/shelf_actions.py @@ -0,0 +1,103 @@ +""" shelf views """ +from django.db import IntegrityError, transaction +from django.contrib.auth.decorators import login_required +from django.shortcuts import get_object_or_404, redirect +from django.views.decorators.http import require_POST + +from bookwyrm import forms, models + + +@login_required +@require_POST +def create_shelf(request): + """user generated shelves""" + form = forms.ShelfForm(request.POST) + if not form.is_valid(): + return redirect(request.headers.get("Referer", "/")) + + shelf = form.save() + return redirect(shelf.local_path) + + +@login_required +@require_POST +def delete_shelf(request, shelf_id): + """user generated shelves""" + shelf = get_object_or_404(models.Shelf, id=shelf_id) + shelf.raise_not_deletable(request.user) + + shelf.delete() + return redirect("user-shelves", request.user.localname) + + +@login_required +@require_POST +@transaction.atomic +def shelve(request): + """put a book on a user's shelf""" + book = get_object_or_404(models.Edition, id=request.POST.get("book")) + desired_shelf = get_object_or_404( + request.user.shelf_set, identifier=request.POST.get("shelf") + ) + + # first we need to remove from the specified shelf + change_from_current_identifier = request.POST.get("change-shelf-from") + if change_from_current_identifier: + # find the shelfbook obj and delete it + get_object_or_404( + models.ShelfBook, + book=book, + user=request.user, + shelf__identifier=change_from_current_identifier, + ).delete() + + # A book can be on multiple shelves, but only on one read status shelf at a time + if desired_shelf.identifier in models.Shelf.READ_STATUS_IDENTIFIERS: + # figure out where state shelf it's currently on (if any) + current_read_status_shelfbook = ( + models.ShelfBook.objects.select_related("shelf") + .filter( + shelf__identifier__in=models.Shelf.READ_STATUS_IDENTIFIERS, + user=request.user, + book=book, + ) + .first() + ) + if current_read_status_shelfbook is not None: + if ( + current_read_status_shelfbook.shelf.identifier + != desired_shelf.identifier + ): + current_read_status_shelfbook.delete() + else: # It is already on the shelf + return redirect(request.headers.get("Referer", "/")) + + # create the new shelf-book entry + models.ShelfBook.objects.create( + book=book, shelf=desired_shelf, user=request.user + ) + else: + # we're putting it on a custom shelf + try: + models.ShelfBook.objects.create( + book=book, shelf=desired_shelf, user=request.user + ) + # The book is already on this shelf. + # Might be good to alert, or reject the action? + except IntegrityError: + pass + return redirect(request.headers.get("Referer", "/")) + + +@login_required +@require_POST +def unshelve(request): + """put a on a user's shelf""" + book = get_object_or_404(models.Edition, id=request.POST.get("book")) + shelf_book = get_object_or_404( + models.ShelfBook, book=book, shelf__id=request.POST["shelf"] + ) + shelf_book.raise_not_deletable(request.user) + + shelf_book.delete() + return redirect(request.headers.get("Referer", "/")) From d86ffc47a71763f63c4f3de0f2278c4dcbb521bc Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Wed, 20 Oct 2021 13:16:29 -0700 Subject: [PATCH 04/17] Fixes incorrect method comment --- bookwyrm/views/shelf/shelf_actions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bookwyrm/views/shelf/shelf_actions.py b/bookwyrm/views/shelf/shelf_actions.py index 470b2d3d3..702b72c13 100644 --- a/bookwyrm/views/shelf/shelf_actions.py +++ b/bookwyrm/views/shelf/shelf_actions.py @@ -92,7 +92,7 @@ def shelve(request): @login_required @require_POST def unshelve(request): - """put a on a user's shelf""" + """remove a book from a user's shelf""" book = get_object_or_404(models.Edition, id=request.POST.get("book")) shelf_book = get_object_or_404( models.ShelfBook, book=book, shelf__id=request.POST["shelf"] From 87deac17f9f23fef0a95c1417530d9d29dfe9bd2 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Wed, 20 Oct 2021 13:31:18 -0700 Subject: [PATCH 05/17] Make import link a link not a button --- bookwyrm/templates/shelf/shelf.html | 67 +++++++++++++++++------------ 1 file changed, 40 insertions(+), 27 deletions(-) diff --git a/bookwyrm/templates/shelf/shelf.html b/bookwyrm/templates/shelf/shelf.html index fa1e91f98..662d75073 100644 --- a/bookwyrm/templates/shelf/shelf.html +++ b/bookwyrm/templates/shelf/shelf.html @@ -19,45 +19,58 @@ -
- +
{% include 'shelf/create_shelf_form.html' with controls_text='create_shelf_form' %} From b64a616ff94859ae9c5f2071fb4de068c639bb35 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Wed, 20 Oct 2021 13:56:55 -0700 Subject: [PATCH 06/17] Fixes mock in test --- bookwyrm/tests/views/test_shelf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bookwyrm/tests/views/test_shelf.py b/bookwyrm/tests/views/test_shelf.py index b78e241cc..35cc63f21 100644 --- a/bookwyrm/tests/views/test_shelf.py +++ b/bookwyrm/tests/views/test_shelf.py @@ -52,7 +52,7 @@ class ShelfViews(TestCase): shelf = self.local_user.shelf_set.first() 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.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) From 1bb23a8edf1d916a7f315cf127f8566678df8bd9 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Wed, 20 Oct 2021 14:15:05 -0700 Subject: [PATCH 07/17] Adds more tests of shelf views --- bookwyrm/tests/views/test_shelf.py | 45 ++++++++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/bookwyrm/tests/views/test_shelf.py b/bookwyrm/tests/views/test_shelf.py index 35cc63f21..914f73973 100644 --- a/bookwyrm/tests/views/test_shelf.py +++ b/bookwyrm/tests/views/test_shelf.py @@ -2,6 +2,7 @@ import json from unittest.mock import patch +from django.contrib.auth.models import AnonymousUser from django.core.exceptions import PermissionDenied from django.template.response import TemplateResponse from django.test import TestCase @@ -46,6 +47,46 @@ class ShelfViews(TestCase): ) models.SiteSettings.objects.create() + self.anonymous_user = AnonymousUser + self.anonymous_user.is_authenticated = False + + def test_shelf_page_all_books(self, *_): + """there are so many views, this just makes sure it LOADS""" + view = views.Shelf.as_view() + request = self.factory.get("") + request.user = self.local_user + with patch("bookwyrm.views.shelf.shelf.is_api_request") as is_api: + is_api.return_value = False + result = view(request, self.local_user.username) + self.assertIsInstance(result, TemplateResponse) + validate_html(result.render()) + self.assertEqual(result.status_code, 200) + + def test_shelf_page_all_books_anonymous(self, *_): + """there are so many views, this just makes sure it LOADS""" + view = views.Shelf.as_view() + request = self.factory.get("") + request.user = self.anonymous_user + with patch("bookwyrm.views.shelf.shelf.is_api_request") as is_api: + is_api.return_value = False + result = view(request, self.local_user.username) + self.assertIsInstance(result, TemplateResponse) + validate_html(result.render()) + self.assertEqual(result.status_code, 200) + + def test_shelf_page_sorted(self, *_): + """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("", {"sort": "author"}) + request.user = self.local_user + with patch("bookwyrm.views.shelf.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) + validate_html(result.render()) + self.assertEqual(result.status_code, 200) + def test_shelf_page(self, *_): """there are so many views, this just makes sure it LOADS""" view = views.Shelf.as_view() @@ -59,7 +100,7 @@ class ShelfViews(TestCase): validate_html(result.render()) self.assertEqual(result.status_code, 200) - with patch("bookwyrm.views.shelf.is_api_request") as is_api: + with patch("bookwyrm.views.shelf.shelf.is_api_request") as is_api: is_api.return_value = True result = view(request, self.local_user.username, shelf.identifier) self.assertIsInstance(result, ActivitypubResponse) @@ -67,7 +108,7 @@ class ShelfViews(TestCase): 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.shelf.is_api_request") as is_api: is_api.return_value = True result = view(request, self.local_user.username, shelf.identifier) self.assertIsInstance(result, ActivitypubResponse) From 3d92afdf280231a4d07a57bf6770f7c532ca929d Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Wed, 20 Oct 2021 14:16:13 -0700 Subject: [PATCH 08/17] Moves shelf tests into subdirectory --- bookwyrm/tests/views/shelf/__init__.py | 1 + bookwyrm/tests/views/{ => shelf}/test_shelf.py | 0 2 files changed, 1 insertion(+) create mode 100644 bookwyrm/tests/views/shelf/__init__.py rename bookwyrm/tests/views/{ => shelf}/test_shelf.py (100%) diff --git a/bookwyrm/tests/views/shelf/__init__.py b/bookwyrm/tests/views/shelf/__init__.py new file mode 100644 index 000000000..b6e690fd5 --- /dev/null +++ b/bookwyrm/tests/views/shelf/__init__.py @@ -0,0 +1 @@ +from . import * diff --git a/bookwyrm/tests/views/test_shelf.py b/bookwyrm/tests/views/shelf/test_shelf.py similarity index 100% rename from bookwyrm/tests/views/test_shelf.py rename to bookwyrm/tests/views/shelf/test_shelf.py From 5c2d6e651029ca597f4b3a5de9fc3801b9cf46b5 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Wed, 20 Oct 2021 14:30:11 -0700 Subject: [PATCH 09/17] Separate out test files and add more tests --- bookwyrm/tests/views/shelf/test_shelf.py | 153 +------------ .../tests/views/shelf/test_shelf_actions.py | 216 ++++++++++++++++++ 2 files changed, 217 insertions(+), 152 deletions(-) create mode 100644 bookwyrm/tests/views/shelf/test_shelf_actions.py diff --git a/bookwyrm/tests/views/shelf/test_shelf.py b/bookwyrm/tests/views/shelf/test_shelf.py index 914f73973..71df3631f 100644 --- a/bookwyrm/tests/views/shelf/test_shelf.py +++ b/bookwyrm/tests/views/shelf/test_shelf.py @@ -1,14 +1,12 @@ """ test for app action functionality """ -import json from unittest.mock import patch from django.contrib.auth.models import AnonymousUser -from django.core.exceptions import PermissionDenied from django.template.response import TemplateResponse from django.test import TestCase from django.test.client import RequestFactory -from bookwyrm import forms, models, views +from bookwyrm import models, views from bookwyrm.activitypub import ActivitypubResponse from bookwyrm.tests.validate_html import validate_html @@ -165,152 +163,3 @@ class ShelfViews(TestCase): view(request, request.user.username, shelf.identifier) self.assertEqual(shelf.name, "To Read") - - def test_shelve(self, *_): - """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") as mock: - views.shelve(request) - - self.assertEqual(mock.call_count, 1) - activity = json.loads(mock.call_args[0][1]) - self.assertEqual(activity["type"], "Add") - - item = models.ShelfBook.objects.get() - self.assertEqual(activity["object"]["id"], item.remote_id) - # make sure the book is on the shelf - self.assertEqual(self.shelf.books.get(), self.book) - - def test_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} - ) - request.user = self.local_user - - 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_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} - ) - request.user = self.local_user - - 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_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} - ) - request.user = self.local_user - - 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_unshelve(self, *_): - """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 - ) - item = models.ShelfBook.objects.get() - - self.shelf.save() - self.assertEqual(self.shelf.books.count(), 1) - 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") as mock: - views.unshelve(request) - activity = json.loads(mock.call_args[0][1]) - self.assertEqual(activity["type"], "Remove") - self.assertEqual(activity["object"]["id"], item.remote_id) - self.assertEqual(self.shelf.books.count(), 0) - - def test_create_shelf(self, *_): - """a brand new custom shelf""" - form = forms.ShelfForm() - form.data["user"] = self.local_user.id - form.data["name"] = "new shelf name" - form.data["description"] = "desc" - form.data["privacy"] = "unlisted" - request = self.factory.post("", form.data) - request.user = self.local_user - - views.create_shelf(request) - - shelf = models.Shelf.objects.get(name="new shelf name") - self.assertEqual(shelf.privacy, "unlisted") - self.assertEqual(shelf.description, "desc") - self.assertEqual(shelf.user, self.local_user) - - def test_delete_shelf(self, *_): - """delete a brand new custom shelf""" - request = self.factory.post("") - request.user = self.local_user - shelf_id = self.shelf.id - - views.delete_shelf(request, shelf_id) - - self.assertFalse(models.Shelf.objects.filter(id=shelf_id).exists()) - - def test_delete_shelf_unauthorized(self, *_): - """delete a brand new custom shelf""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ): - rat = models.User.objects.create_user( - "rat@local.com", - "rat@mouse.mouse", - "password", - local=True, - localname="rat", - ) - request = self.factory.post("") - request.user = rat - - with self.assertRaises(PermissionDenied): - views.delete_shelf(request, self.shelf.id) - - self.assertTrue(models.Shelf.objects.filter(id=self.shelf.id).exists()) - - def test_delete_shelf_has_book(self, *_): - """delete a brand new custom shelf""" - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): - models.ShelfBook.objects.create( - book=self.book, user=self.local_user, shelf=self.shelf - ) - request = self.factory.post("") - request.user = self.local_user - - with self.assertRaises(PermissionDenied): - views.delete_shelf(request, self.shelf.id) - - self.assertTrue(models.Shelf.objects.filter(id=self.shelf.id).exists()) - - def test_delete_shelf_not_editable(self, *_): - """delete a brand new custom shelf""" - shelf = self.local_user.shelf_set.first() - self.assertFalse(shelf.editable) - request = self.factory.post("") - request.user = self.local_user - - with self.assertRaises(PermissionDenied): - views.delete_shelf(request, shelf.id) - - self.assertTrue(models.Shelf.objects.filter(id=shelf.id).exists()) diff --git a/bookwyrm/tests/views/shelf/test_shelf_actions.py b/bookwyrm/tests/views/shelf/test_shelf_actions.py new file mode 100644 index 000000000..50b319d0e --- /dev/null +++ b/bookwyrm/tests/views/shelf/test_shelf_actions.py @@ -0,0 +1,216 @@ +""" test for app action functionality """ +import json +from unittest.mock import patch + +from django.core.exceptions import PermissionDenied +from django.test import TestCase +from django.test.client import RequestFactory + +from bookwyrm import forms, models, views + + +@patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay") +@patch("bookwyrm.suggested_users.rerank_suggestions_task.delay") +@patch("bookwyrm.activitystreams.populate_stream_task.delay") +@patch("bookwyrm.activitystreams.add_book_statuses_task.delay") +@patch("bookwyrm.activitystreams.remove_book_statuses_task.delay") +class ShelfActionViews(TestCase): + """tag views""" + + def setUp(self): + """we need basic test data and mocks""" + self.factory = RequestFactory() + with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( + "bookwyrm.activitystreams.populate_stream_task.delay" + ): + self.local_user = models.User.objects.create_user( + "mouse@local.com", + "mouse@mouse.com", + "mouseword", + local=True, + localname="mouse", + remote_id="https://example.com/users/mouse", + ) + 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, + ) + 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 + ) + models.SiteSettings.objects.create() + + def test_shelve(self, *_): + """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") as mock: + views.shelve(request) + + self.assertEqual(mock.call_count, 1) + activity = json.loads(mock.call_args[0][1]) + self.assertEqual(activity["type"], "Add") + + item = models.ShelfBook.objects.get() + self.assertEqual(activity["object"]["id"], item.remote_id) + # make sure the book is on the shelf + self.assertEqual(self.shelf.books.get(), self.book) + + def test_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} + ) + request.user = self.local_user + + 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_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} + ) + request.user = self.local_user + + 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_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} + ) + request.user = self.local_user + + 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_shelve_read_with_change_shelf(self, *_): + """special behavior for the read shelf""" + previous_shelf = models.Shelf.objects.get(identifier="reading") + models.ShelfBook.objects.create( + shelf=previous_shelf, user=self.local_user, book=self.book + ) + shelf = models.Shelf.objects.get(identifier="read") + + request = self.factory.post( + "", { + "book": self.book.id, + "shelf": shelf.identifier, + "change-shelf-from": previous_shelf.identifier, + } + ) + request.user = self.local_user + + 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) + self.assertEqual(list(previous_shelf.books.all()), []) + + def test_unshelve(self, *_): + """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 + ) + item = models.ShelfBook.objects.get() + + self.shelf.save() + self.assertEqual(self.shelf.books.count(), 1) + 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") as mock: + views.unshelve(request) + activity = json.loads(mock.call_args[0][1]) + self.assertEqual(activity["type"], "Remove") + self.assertEqual(activity["object"]["id"], item.remote_id) + self.assertEqual(self.shelf.books.count(), 0) + + def test_create_shelf(self, *_): + """a brand new custom shelf""" + form = forms.ShelfForm() + form.data["user"] = self.local_user.id + form.data["name"] = "new shelf name" + form.data["description"] = "desc" + form.data["privacy"] = "unlisted" + request = self.factory.post("", form.data) + request.user = self.local_user + + views.create_shelf(request) + + shelf = models.Shelf.objects.get(name="new shelf name") + self.assertEqual(shelf.privacy, "unlisted") + self.assertEqual(shelf.description, "desc") + self.assertEqual(shelf.user, self.local_user) + + def test_delete_shelf(self, *_): + """delete a brand new custom shelf""" + request = self.factory.post("") + request.user = self.local_user + shelf_id = self.shelf.id + + views.delete_shelf(request, shelf_id) + + self.assertFalse(models.Shelf.objects.filter(id=shelf_id).exists()) + + def test_delete_shelf_unauthorized(self, *_): + """delete a brand new custom shelf""" + with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( + "bookwyrm.activitystreams.populate_stream_task.delay" + ): + rat = models.User.objects.create_user( + "rat@local.com", + "rat@mouse.mouse", + "password", + local=True, + localname="rat", + ) + request = self.factory.post("") + request.user = rat + + with self.assertRaises(PermissionDenied): + views.delete_shelf(request, self.shelf.id) + + self.assertTrue(models.Shelf.objects.filter(id=self.shelf.id).exists()) + + def test_delete_shelf_has_book(self, *_): + """delete a brand new custom shelf""" + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): + models.ShelfBook.objects.create( + book=self.book, user=self.local_user, shelf=self.shelf + ) + request = self.factory.post("") + request.user = self.local_user + + with self.assertRaises(PermissionDenied): + views.delete_shelf(request, self.shelf.id) + + self.assertTrue(models.Shelf.objects.filter(id=self.shelf.id).exists()) + + def test_delete_shelf_not_editable(self, *_): + """delete a brand new custom shelf""" + shelf = self.local_user.shelf_set.first() + self.assertFalse(shelf.editable) + request = self.factory.post("") + request.user = self.local_user + + with self.assertRaises(PermissionDenied): + views.delete_shelf(request, shelf.id) + + self.assertTrue(models.Shelf.objects.filter(id=shelf.id).exists()) From f65a54eb4abe8b5f0b089f1801fb598faa96e2ed Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Wed, 20 Oct 2021 14:34:42 -0700 Subject: [PATCH 10/17] Python formatting --- bookwyrm/tests/views/shelf/test_shelf_actions.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/bookwyrm/tests/views/shelf/test_shelf_actions.py b/bookwyrm/tests/views/shelf/test_shelf_actions.py index 50b319d0e..3efae0f45 100644 --- a/bookwyrm/tests/views/shelf/test_shelf_actions.py +++ b/bookwyrm/tests/views/shelf/test_shelf_actions.py @@ -109,11 +109,12 @@ class ShelfActionViews(TestCase): shelf = models.Shelf.objects.get(identifier="read") request = self.factory.post( - "", { + "", + { "book": self.book.id, "shelf": shelf.identifier, "change-shelf-from": previous_shelf.identifier, - } + }, ) request.user = self.local_user From 89a385da0a96eece560aa569f4cb95c98b6e8dfe Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Wed, 20 Oct 2021 17:36:52 -0700 Subject: [PATCH 11/17] Paginate books on author page --- bookwyrm/views/author.py | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/bookwyrm/views/author.py b/bookwyrm/views/author.py index e1e9247de..1265ad689 100644 --- a/bookwyrm/views/author.py +++ b/bookwyrm/views/author.py @@ -1,6 +1,7 @@ """ the good people stuff! the authors! """ from django.contrib.auth.decorators import login_required, permission_required -from django.db.models import Q +from django.core.paginator import Paginator +from django.db.models import OuterRef, Subquery, F, Q from django.shortcuts import get_object_or_404, redirect from django.template.response import TemplateResponse from django.utils.decorators import method_decorator @@ -8,7 +9,8 @@ from django.views import View from bookwyrm import forms, models from bookwyrm.activitypub import ActivitypubResponse -from .helpers import is_api_request +from bookwyrm.settings import PAGE_LENGTH +from bookwyrm.views.helpers import is_api_request # pylint: disable= no-self-use @@ -22,12 +24,26 @@ class Author(View): if is_api_request(request): return ActivitypubResponse(author.to_activity()) - books = models.Work.objects.filter( - Q(authors=author) | Q(editions__authors=author) - ).distinct() + default_editions = models.Edition.objects.filter( + parent_work=OuterRef("parent_work") + ).order_by("-edition_rank") + + books = ( + models.Edition.objects.filter( + Q(authors=author) | Q(parent_work__authors=author) + ) + .annotate(default_id=Subquery(default_editions.values("id")[:1])) + .filter(default_id=F("id")) + ) + + paginated = Paginator(books, PAGE_LENGTH) + page = paginated.get_page(request.GET.get("page")) data = { "author": author, - "books": [b.default_edition for b in books], + "books": page, + "page_range": paginated.get_elided_page_range( + page.number, on_each_side=2, on_ends=1 + ), } return TemplateResponse(request, "author/author.html", data) From 3eb3225d2c629abe72ca82f2ac09fa7413c9d6e5 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Wed, 20 Oct 2021 17:42:19 -0700 Subject: [PATCH 12/17] Adds pagination to the template --- bookwyrm/templates/author/author.html | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/bookwyrm/templates/author/author.html b/bookwyrm/templates/author/author.html index 8a15cd0f0..5310f0df8 100644 --- a/bookwyrm/templates/author/author.html +++ b/bookwyrm/templates/author/author.html @@ -114,4 +114,9 @@ {% endfor %}
+ +
+ {% include 'snippets/pagination.html' with page=books %} +
+ {% endblock %} From de93beca84e5f2dcee9922486d99b6cc662a4525 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Wed, 20 Oct 2021 17:51:42 -0700 Subject: [PATCH 13/17] Adds shelve buttons to books on author page --- bookwyrm/templates/author/author.html | 1 + bookwyrm/views/author.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/bookwyrm/templates/author/author.html b/bookwyrm/templates/author/author.html index 5310f0df8..6a67b50b3 100644 --- a/bookwyrm/templates/author/author.html +++ b/bookwyrm/templates/author/author.html @@ -110,6 +110,7 @@ {% for book in books %}
{% include 'landing/small-book.html' with book=book %} + {% include 'snippets/shelve_button/shelve_button.html' with book=book %}
{% endfor %} diff --git a/bookwyrm/views/author.py b/bookwyrm/views/author.py index 1265ad689..9a3d582d6 100644 --- a/bookwyrm/views/author.py +++ b/bookwyrm/views/author.py @@ -29,7 +29,7 @@ class Author(View): ).order_by("-edition_rank") books = ( - models.Edition.objects.filter( + models.Edition.viewer_aware_objects(request.user).filter( Q(authors=author) | Q(parent_work__authors=author) ) .annotate(default_id=Subquery(default_editions.values("id")[:1])) From 14682ed8c687590b3ebb5be299a9399419fec0db Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Wed, 20 Oct 2021 18:04:29 -0700 Subject: [PATCH 14/17] Prefect related data in author view --- bookwyrm/views/author.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bookwyrm/views/author.py b/bookwyrm/views/author.py index 9a3d582d6..4f29e2af6 100644 --- a/bookwyrm/views/author.py +++ b/bookwyrm/views/author.py @@ -34,7 +34,7 @@ class Author(View): ) .annotate(default_id=Subquery(default_editions.values("id")[:1])) .filter(default_id=F("id")) - ) + ).prefetch_related("authors") paginated = Paginator(books, PAGE_LENGTH) page = paginated.get_page(request.GET.get("page")) From d706b26ac98b3fbb0b2e82d1d2423defbe3168e4 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Wed, 20 Oct 2021 18:11:31 -0700 Subject: [PATCH 15/17] Python formatting --- bookwyrm/views/author.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/bookwyrm/views/author.py b/bookwyrm/views/author.py index 4f29e2af6..4cb7ac2b5 100644 --- a/bookwyrm/views/author.py +++ b/bookwyrm/views/author.py @@ -29,9 +29,8 @@ class Author(View): ).order_by("-edition_rank") books = ( - models.Edition.viewer_aware_objects(request.user).filter( - Q(authors=author) | Q(parent_work__authors=author) - ) + models.Edition.viewer_aware_objects(request.user) + .filter(Q(authors=author) | Q(parent_work__authors=author)) .annotate(default_id=Subquery(default_editions.values("id")[:1])) .filter(default_id=F("id")) ).prefetch_related("authors") From 72dc21e82ab7c076eda0b984ea9f9ad57c687a4b Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Wed, 20 Oct 2021 18:27:19 -0700 Subject: [PATCH 16/17] Adds tests and fixes unset ordering warnings --- bookwyrm/tests/views/test_author.py | 27 +++++++++++++++++++++++++-- bookwyrm/views/author.py | 4 +++- 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/bookwyrm/tests/views/test_author.py b/bookwyrm/tests/views/test_author.py index 03c027fae..75c7433fe 100644 --- a/bookwyrm/tests/views/test_author.py +++ b/bookwyrm/tests/views/test_author.py @@ -1,6 +1,7 @@ """ test for app action functionality """ from unittest.mock import patch -from django.contrib.auth.models import Group, Permission + +from django.contrib.auth.models import AnonymousUser, Group, Permission from django.contrib.contenttypes.models import ContentType from django.core.exceptions import PermissionDenied from django.template.response import TemplateResponse @@ -44,6 +45,8 @@ class AuthorViews(TestCase): parent_work=self.work, ) + self.anonymous_user = AnonymousUser + self.anonymous_user.is_authenticated = False models.SiteSettings.objects.create() def test_author_page(self): @@ -51,6 +54,7 @@ class AuthorViews(TestCase): view = views.Author.as_view() author = models.Author.objects.create(name="Jessica") request = self.factory.get("") + request.user = self.local_user with patch("bookwyrm.views.author.is_api_request") as is_api: is_api.return_value = False result = view(request, author.id) @@ -59,7 +63,26 @@ class AuthorViews(TestCase): self.assertEqual(result.status_code, 200) self.assertEqual(result.status_code, 200) + def test_author_page_logged_out(self): + """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("") + request.user = self.anonymous_user + 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) + validate_html(result.render()) + self.assertEqual(result.status_code, 200) + self.assertEqual(result.status_code, 200) + + def test_author_page_api_response(self): + """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("") + request.user = self.local_user with patch("bookwyrm.views.author.is_api_request") as is_api: is_api.return_value = True result = view(request, author.id) @@ -126,5 +149,5 @@ class AuthorViews(TestCase): resp = view(request, author.id) author.refresh_from_db() self.assertEqual(author.name, "Test Author") - resp.render() + validate_html(resp.render()) self.assertEqual(resp.status_code, 200) diff --git a/bookwyrm/views/author.py b/bookwyrm/views/author.py index 4cb7ac2b5..6c3ee36ff 100644 --- a/bookwyrm/views/author.py +++ b/bookwyrm/views/author.py @@ -33,7 +33,9 @@ class Author(View): .filter(Q(authors=author) | Q(parent_work__authors=author)) .annotate(default_id=Subquery(default_editions.values("id")[:1])) .filter(default_id=F("id")) - ).prefetch_related("authors") + .order_by("-first_published_date", "-published_date", "-created_date") + .prefetch_related("authors") + ) paginated = Paginator(books, PAGE_LENGTH) page = paginated.get_page(request.GET.get("page")) From 278a9de673b54638342a31ea94f0fa5b0a08ae87 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Wed, 20 Oct 2021 18:29:00 -0700 Subject: [PATCH 17/17] Removes duplicate assertions in author view test --- bookwyrm/tests/views/test_author.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/bookwyrm/tests/views/test_author.py b/bookwyrm/tests/views/test_author.py index 75c7433fe..ccbfe5493 100644 --- a/bookwyrm/tests/views/test_author.py +++ b/bookwyrm/tests/views/test_author.py @@ -61,7 +61,6 @@ class AuthorViews(TestCase): self.assertIsInstance(result, TemplateResponse) validate_html(result.render()) self.assertEqual(result.status_code, 200) - self.assertEqual(result.status_code, 200) def test_author_page_logged_out(self): """there are so many views, this just makes sure it LOADS""" @@ -75,7 +74,6 @@ class AuthorViews(TestCase): self.assertIsInstance(result, TemplateResponse) validate_html(result.render()) self.assertEqual(result.status_code, 200) - self.assertEqual(result.status_code, 200) def test_author_page_api_response(self): """there are so many views, this just makes sure it LOADS""" @@ -101,7 +99,6 @@ class AuthorViews(TestCase): self.assertIsInstance(result, TemplateResponse) validate_html(result.render()) self.assertEqual(result.status_code, 200) - self.assertEqual(result.status_code, 200) def test_edit_author(self): """edit an author"""