Merge branch 'main' into production

This commit is contained in:
Mouse Reeve 2022-02-04 15:45:20 -08:00
commit 771435168b
12 changed files with 141 additions and 42 deletions

View file

@ -1,7 +1,9 @@
""" functionality outline for a book data connector """
from abc import ABC, abstractmethod
import imghdr
import ipaddress
import logging
from urllib.parse import urlparse
from django.core.files.base import ContentFile
from django.db import transaction
@ -250,6 +252,8 @@ def dict_from_mappings(data, mappings):
def get_data(url, params=None, timeout=10):
"""wrapper for request.get"""
# check if the url is blocked
raise_not_valid_url(url)
if models.FederatedServer.is_blocked(url):
raise ConnectorException(f"Attempting to load data from blocked url: {url}")
@ -282,6 +286,7 @@ def get_data(url, params=None, timeout=10):
def get_image(url, timeout=10):
"""wrapper for requesting an image"""
raise_not_valid_url(url)
try:
resp = requests.get(
url,
@ -306,6 +311,20 @@ def get_image(url, timeout=10):
return image_content, extension
def raise_not_valid_url(url):
"""do some basic reality checks on the url"""
parsed = urlparse(url)
if not parsed.scheme in ["http", "https"]:
raise ConnectorException("Invalid scheme: ", url)
try:
ipaddress.ip_address(parsed.netloc)
raise ConnectorException("Provided url is an IP address: ", url)
except ValueError:
# it's not an IP address, which is good
pass
class Mapping:
"""associate a local database field with a field in an external dataset"""

View file

@ -1,6 +1,7 @@
""" using django model forms """
import datetime
from collections import defaultdict
from urllib.parse import urlparse
from django import forms
from django.forms import ModelForm, PasswordInput, widgets, ChoiceField
@ -227,6 +228,34 @@ class FileLinkForm(CustomForm):
model = models.FileLink
fields = ["url", "filetype", "availability", "book", "added_by"]
def clean(self):
"""make sure the domain isn't blocked or pending"""
cleaned_data = super().clean()
url = cleaned_data.get("url")
filetype = cleaned_data.get("filetype")
book = cleaned_data.get("book")
domain = urlparse(url).netloc
if models.LinkDomain.objects.filter(domain=domain).exists():
status = models.LinkDomain.objects.get(domain=domain).status
if status == "blocked":
# pylint: disable=line-too-long
self.add_error(
"url",
_(
"This domain is blocked. Please contact your administrator if you think this is an error."
),
)
elif models.FileLink.objects.filter(
url=url, book=book, filetype=filetype
).exists():
# pylint: disable=line-too-long
self.add_error(
"url",
_(
"This link with file type has already been added for this book. If it is not visible, the domain is still pending."
),
)
class EditionForm(CustomForm):
class Meta:

View file

@ -0,0 +1,21 @@
# Generated by Django 3.2.11 on 2022-02-04 20:06
import bookwyrm.models.fields
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
("bookwyrm", "0132_alter_user_preferred_language"),
]
operations = [
migrations.AlterField(
model_name="listitem",
name="notes",
field=bookwyrm.models.fields.HtmlField(
blank=True, max_length=300, null=True
),
),
]

View file

@ -142,7 +142,7 @@ class ListItem(CollectionItemMixin, BookWyrmModel):
user = fields.ForeignKey(
"User", on_delete=models.PROTECT, activitypub_field="actor"
)
notes = fields.TextField(blank=True, null=True, max_length=300)
notes = fields.HtmlField(blank=True, null=True, max_length=300)
approved = models.BooleanField(default=True)
order = fields.IntegerField()
endorsement = models.ManyToManyField("User", related_name="endorsers")

View file

@ -79,14 +79,12 @@
<div class="media-content">
<div class="content">
<header>
{% url 'user-feed' user|username as user_path %}
{% url 'user-feed' item.user|username as user_path %}
{% blocktrans trimmed with username=user.display_name %}
<a href="{{ user_path }}">{{ username }}</a> says:
{% endblocktrans %}
</header>
<p>
{{ item.notes|to_markdown|safe }}
</p>
{{ item.notes|to_markdown|safe }}
</div>
{% if item.user == request.user %}
<div>

View file

@ -4,8 +4,8 @@ from django.test import TestCase
import responses
from bookwyrm import models
from bookwyrm.connectors import abstract_connector
from bookwyrm.connectors.abstract_connector import Mapping
from bookwyrm.connectors import abstract_connector, ConnectorException
from bookwyrm.connectors.abstract_connector import Mapping, get_data
from bookwyrm.settings import DOMAIN
@ -163,3 +163,11 @@ class AbstractConnector(TestCase):
author.refresh_from_db()
self.assertEqual(author.name, "Test")
self.assertEqual(author.isni, "hi")
def test_get_data_invalid_url(self):
"""load json data from an arbitrary url"""
with self.assertRaises(ConnectorException):
get_data("file://hello.com/image/jpg")
with self.assertRaises(ConnectorException):
get_data("http://127.0.0.1/image/jpg")

View file

@ -85,6 +85,7 @@ class ListViews(TestCase):
user=self.local_user,
book=self.book,
approved=True,
notes="hello",
order=1,
)
@ -178,6 +179,7 @@ class ListViews(TestCase):
book_list=self.list,
user=self.local_user,
book=self.book,
notes="hi hello",
approved=True,
order=1,
)

View file

@ -67,4 +67,4 @@ class ListItemViews(TestCase):
self.assertEqual(mock.call_count, 1)
item.refresh_from_db()
self.assertEqual(item.notes, "beep boop")
self.assertEqual(item.notes, "<p>beep boop</p>")

View file

@ -5,6 +5,7 @@ from django.utils.decorators import method_decorator
from django.views import View
from bookwyrm import forms, models
from bookwyrm.views.status import to_markdown
# pylint: disable=no-self-use
@ -18,7 +19,9 @@ class ListItem(View):
list_item.raise_not_editable(request.user)
form = forms.ListItemForm(request.POST, instance=list_item)
if form.is_valid():
form.save()
item = form.save(commit=False)
item.notes = to_markdown(item.notes)
item.save()
else:
raise Exception(form.errors)
return redirect("list", list_item.book_list.id)

View file

@ -33,9 +33,13 @@ class User(View):
# only show shelves that should be visible
is_self = request.user.id == user.id
if not is_self:
shelves = models.Shelf.privacy_filter(
request.user, privacy_levels=["public", "followers"]
).filter(user=user, books__isnull=False)
shelves = (
models.Shelf.privacy_filter(
request.user, privacy_levels=["public", "followers"]
)
.filter(user=user, books__isnull=False)
.distinct()
)
else:
shelves = user.shelf_set.filter(books__isnull=False).distinct()

View file

@ -17,62 +17,70 @@ msgstr ""
"X-Crowdin-File: /[bookwyrm-social.bookwyrm] main/locale/en_US/LC_MESSAGES/django.po\n"
"X-Crowdin-File-ID: 1553\n"
#: bookwyrm/forms.py:365
#: bookwyrm/forms.py:239
msgid "Domain is blocked. Don't try this url again."
msgstr "Die Domäne ist blockiert. Versuchen Sie diese Url nicht mehr."
#: bookwyrm/forms.py:241
msgid "Domain already pending. Please try later."
msgstr "Die Domain ist bereits in Bearbeitung. Bitte versuchen Sie es später."
#: bookwyrm/forms.py:378
msgid "A user with this email already exists."
msgstr "Es existiert bereits ein Benutzer*inkonto mit dieser E-Mail-Adresse."
#: bookwyrm/forms.py:379
#: bookwyrm/forms.py:392
msgid "One Day"
msgstr "Ein Tag"
#: bookwyrm/forms.py:380
#: bookwyrm/forms.py:393
msgid "One Week"
msgstr "Eine Woche"
#: bookwyrm/forms.py:381
#: bookwyrm/forms.py:394
msgid "One Month"
msgstr "Ein Monat"
#: bookwyrm/forms.py:382
#: bookwyrm/forms.py:395
msgid "Does Not Expire"
msgstr "Läuft nicht ab"
#: bookwyrm/forms.py:386
#: bookwyrm/forms.py:399
#, python-brace-format
msgid "{i} uses"
msgstr "{i}-mal verwendbar"
#: bookwyrm/forms.py:387
#: bookwyrm/forms.py:400
msgid "Unlimited"
msgstr "Unbegrenzt"
#: bookwyrm/forms.py:489
#: bookwyrm/forms.py:502
msgid "List Order"
msgstr "Reihenfolge der Liste"
#: bookwyrm/forms.py:490
#: bookwyrm/forms.py:503
msgid "Book Title"
msgstr "Buchtitel"
#: bookwyrm/forms.py:491 bookwyrm/templates/shelf/shelf.html:155
#: bookwyrm/forms.py:504 bookwyrm/templates/shelf/shelf.html:155
#: bookwyrm/templates/shelf/shelf.html:187
#: bookwyrm/templates/snippets/create_status/review.html:32
msgid "Rating"
msgstr "Bewertung"
#: bookwyrm/forms.py:493 bookwyrm/templates/lists/list.html:177
#: bookwyrm/forms.py:506 bookwyrm/templates/lists/list.html:177
msgid "Sort By"
msgstr "Sortieren nach"
#: bookwyrm/forms.py:497
#: bookwyrm/forms.py:510
msgid "Ascending"
msgstr "Aufsteigend"
#: bookwyrm/forms.py:498
#: bookwyrm/forms.py:511
msgid "Descending"
msgstr "Absteigend"
#: bookwyrm/forms.py:511
#: bookwyrm/forms.py:524
msgid "Reading finish date cannot be before start date."
msgstr "Enddatum darf nicht vor dem Startdatum liegen."
@ -284,7 +292,7 @@ msgstr "Português Europeu (Portugiesisch)"
#: bookwyrm/settings.py:258
msgid "Swedish (Svenska)"
msgstr ""
msgstr "Swedish (Schwedisch)"
#: bookwyrm/settings.py:259
msgid "简体中文 (Simplified Chinese)"
@ -4677,4 +4685,3 @@ msgid "Load %(count)d unread status"
msgid_plural "Load %(count)d unread statuses"
msgstr[0] "Lade %(count)d ungelesene Statusmeldung"
msgstr[1] "Lade %(count)d ungelesene Statusmeldungen"

View file

@ -18,62 +18,70 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: bookwyrm/forms.py:365
#: bookwyrm/forms.py:239
msgid "Domain is blocked. Don't try this url again."
msgstr ""
#: bookwyrm/forms.py:241
msgid "Domain already pending. Please try later."
msgstr ""
#: bookwyrm/forms.py:378
msgid "A user with this email already exists."
msgstr ""
#: bookwyrm/forms.py:379
#: bookwyrm/forms.py:392
msgid "One Day"
msgstr ""
#: bookwyrm/forms.py:380
#: bookwyrm/forms.py:393
msgid "One Week"
msgstr ""
#: bookwyrm/forms.py:381
#: bookwyrm/forms.py:394
msgid "One Month"
msgstr ""
#: bookwyrm/forms.py:382
#: bookwyrm/forms.py:395
msgid "Does Not Expire"
msgstr ""
#: bookwyrm/forms.py:386
#: bookwyrm/forms.py:399
#, python-brace-format
msgid "{i} uses"
msgstr ""
#: bookwyrm/forms.py:387
#: bookwyrm/forms.py:400
msgid "Unlimited"
msgstr ""
#: bookwyrm/forms.py:489
#: bookwyrm/forms.py:502
msgid "List Order"
msgstr ""
#: bookwyrm/forms.py:490
#: bookwyrm/forms.py:503
msgid "Book Title"
msgstr ""
#: bookwyrm/forms.py:491 bookwyrm/templates/shelf/shelf.html:155
#: bookwyrm/forms.py:504 bookwyrm/templates/shelf/shelf.html:155
#: bookwyrm/templates/shelf/shelf.html:187
#: bookwyrm/templates/snippets/create_status/review.html:32
msgid "Rating"
msgstr ""
#: bookwyrm/forms.py:493 bookwyrm/templates/lists/list.html:177
#: bookwyrm/forms.py:506 bookwyrm/templates/lists/list.html:177
msgid "Sort By"
msgstr ""
#: bookwyrm/forms.py:497
#: bookwyrm/forms.py:510
msgid "Ascending"
msgstr ""
#: bookwyrm/forms.py:498
#: bookwyrm/forms.py:511
msgid "Descending"
msgstr ""
#: bookwyrm/forms.py:511
#: bookwyrm/forms.py:524
msgid "Reading finish date cannot be before start date."
msgstr ""