Merge branch 'main' into main
This commit is contained in:
@ -1,7 +1,9 @@
|
||||
""" functionality outline for a book data connector """
|
||||
from abc import ABC, abstractmethod
|
||||
import imghdr
|
||||
import logging
|
||||
|
||||
from django.core.files.base import ContentFile
|
||||
from django.db import transaction
|
||||
import requests
|
||||
from requests.exceptions import RequestException
|
||||
@ -290,10 +292,18 @@ def get_image(url, timeout=10):
|
||||
)
|
||||
except RequestException as err:
|
||||
logger.exception(err)
|
||||
return None
|
||||
return None, None
|
||||
|
||||
if not resp.ok:
|
||||
return None
|
||||
return resp
|
||||
return None, None
|
||||
|
||||
image_content = ContentFile(resp.content)
|
||||
extension = imghdr.what(None, image_content.read())
|
||||
if not extension:
|
||||
logger.exception("File requested was not an image: %s", url)
|
||||
return None, None
|
||||
|
||||
return image_content, extension
|
||||
|
||||
|
||||
class Mapping:
|
||||
|
37
bookwyrm/migrations/0132_alter_user_preferred_language.py
Normal file
37
bookwyrm/migrations/0132_alter_user_preferred_language.py
Normal file
@ -0,0 +1,37 @@
|
||||
# Generated by Django 3.2.10 on 2022-02-02 20:42
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("bookwyrm", "0131_merge_20220125_1644"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name="user",
|
||||
name="preferred_language",
|
||||
field=models.CharField(
|
||||
blank=True,
|
||||
choices=[
|
||||
("en-us", "English"),
|
||||
("de-de", "Deutsch (German)"),
|
||||
("es-es", "Español (Spanish)"),
|
||||
("gl-es", "Galego (Galician)"),
|
||||
("it-it", "Italiano (Italian)"),
|
||||
("fr-fr", "Français (French)"),
|
||||
("lt-lt", "Lietuvių (Lithuanian)"),
|
||||
("no-no", "Norsk (Norwegian)"),
|
||||
("pt-br", "Português do Brasil (Brazilian Portuguese)"),
|
||||
("pt-pt", "Português Europeu (European Portuguese)"),
|
||||
("sv-se", "Svenska (Swedish)"),
|
||||
("zh-hans", "简体中文 (Simplified Chinese)"),
|
||||
("zh-hant", "繁體中文 (Traditional Chinese)"),
|
||||
],
|
||||
max_length=255,
|
||||
null=True,
|
||||
),
|
||||
),
|
||||
]
|
@ -1,6 +1,5 @@
|
||||
""" activitypub-aware django model fields """
|
||||
from dataclasses import MISSING
|
||||
import imghdr
|
||||
import re
|
||||
from uuid import uuid4
|
||||
from urllib.parse import urljoin
|
||||
@ -9,7 +8,6 @@ import dateutil.parser
|
||||
from dateutil.parser import ParserError
|
||||
from django.contrib.postgres.fields import ArrayField as DjangoArrayField
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.core.files.base import ContentFile
|
||||
from django.db import models
|
||||
from django.forms import ClearableFileInput, ImageField as DjangoImageField
|
||||
from django.utils import timezone
|
||||
@ -443,12 +441,10 @@ class ImageField(ActivitypubFieldMixin, models.ImageField):
|
||||
except ValidationError:
|
||||
return None
|
||||
|
||||
response = get_image(url)
|
||||
if not response:
|
||||
image_content, extension = get_image(url)
|
||||
if not image_content:
|
||||
return None
|
||||
|
||||
image_content = ContentFile(response.content)
|
||||
extension = imghdr.what(None, image_content.read()) or ""
|
||||
image_name = f"{uuid4()}.{extension}"
|
||||
return [image_name, image_content]
|
||||
|
||||
|
@ -9,7 +9,7 @@ from django.utils.translation import gettext_lazy as _
|
||||
env = Env()
|
||||
env.read_env()
|
||||
DOMAIN = env("DOMAIN")
|
||||
VERSION = "0.2.0"
|
||||
VERSION = "0.2.1"
|
||||
|
||||
PAGE_LENGTH = env("PAGE_LENGTH", 15)
|
||||
DEFAULT_LANGUAGE = env("DEFAULT_LANGUAGE", "English")
|
||||
@ -255,7 +255,7 @@ LANGUAGES = [
|
||||
("no-no", _("Norsk (Norwegian)")),
|
||||
("pt-br", _("Português do Brasil (Brazilian Portuguese)")),
|
||||
("pt-pt", _("Português Europeu (European Portuguese)")),
|
||||
("sv-se", _("Swedish (Svenska)")),
|
||||
("sv-se", _("Svenska (Swedish)")),
|
||||
("zh-hans", _("简体中文 (Simplified Chinese)")),
|
||||
("zh-hant", _("繁體中文 (Traditional Chinese)")),
|
||||
]
|
||||
|
@ -356,10 +356,11 @@
|
||||
<form name="list-add" method="post" action="{% url 'list-add-book' %}">
|
||||
{% csrf_token %}
|
||||
<input type="hidden" name="book" value="{{ book.id }}">
|
||||
<input type="hidden" name="user" value="{{ request.user.id }}">
|
||||
<label class="label" for="id_list">{% trans "Add to list" %}</label>
|
||||
<div class="field has-addons">
|
||||
<div class="select control is-clipped">
|
||||
<select name="list" id="id_list">
|
||||
<select name="book_list" id="id_list">
|
||||
{% for list in user.list_set.all %}
|
||||
<option value="{{ list.id }}">{{ list.name }}</option>
|
||||
{% endfor %}
|
||||
|
@ -97,7 +97,7 @@
|
||||
<span class="details-close icon icon-pencil" aria-hidden></span>
|
||||
</span>
|
||||
</summary>
|
||||
{% include "lists/edit_item_form.html" %}
|
||||
{% include "lists/edit_item_form.html" with book=item.book %}
|
||||
</details>
|
||||
</div>
|
||||
{% endif %}
|
||||
@ -112,7 +112,7 @@
|
||||
<span class="details-close icon icon-plus" aria-hidden></span>
|
||||
</span>
|
||||
</summary>
|
||||
{% include "lists/edit_item_form.html" %}
|
||||
{% include "lists/edit_item_form.html" with book=item.book %}
|
||||
</details>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
@ -45,7 +45,7 @@
|
||||
href="{{ shelf_tab.local_path }}"
|
||||
{% if shelf_tab.identifier == shelf.identifier %} aria-current="page"{% endif %}
|
||||
>
|
||||
{% include 'user/books_header.html' with shelf=shelf_tab %}
|
||||
{% include "snippets/translated_shelf_name.html" with shelf=shelf_tab %}
|
||||
</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
|
@ -443,18 +443,17 @@ class ModelFields(TestCase):
|
||||
image_file = pathlib.Path(__file__).parent.joinpath(
|
||||
"../../static/images/default_avi.jpg"
|
||||
)
|
||||
image = Image.open(image_file)
|
||||
output = BytesIO()
|
||||
image.save(output, format=image.format)
|
||||
|
||||
instance = fields.ImageField()
|
||||
|
||||
responses.add(
|
||||
responses.GET,
|
||||
"http://www.example.com/image.jpg",
|
||||
body=image.tobytes(),
|
||||
status=200,
|
||||
)
|
||||
with open(image_file, "rb") as image_data:
|
||||
responses.add(
|
||||
responses.GET,
|
||||
"http://www.example.com/image.jpg",
|
||||
body=image_data.read(),
|
||||
status=200,
|
||||
content_type="image/jpeg",
|
||||
stream=True,
|
||||
)
|
||||
loaded_image = instance.field_from_activity("http://www.example.com/image.jpg")
|
||||
self.assertIsInstance(loaded_image, list)
|
||||
self.assertIsInstance(loaded_image[1], ContentFile)
|
||||
@ -465,18 +464,18 @@ class ModelFields(TestCase):
|
||||
image_file = pathlib.Path(__file__).parent.joinpath(
|
||||
"../../static/images/default_avi.jpg"
|
||||
)
|
||||
image = Image.open(image_file)
|
||||
output = BytesIO()
|
||||
image.save(output, format=image.format)
|
||||
|
||||
instance = fields.ImageField(activitypub_field="cover", name="cover")
|
||||
|
||||
responses.add(
|
||||
responses.GET,
|
||||
"http://www.example.com/image.jpg",
|
||||
body=image.tobytes(),
|
||||
status=200,
|
||||
)
|
||||
with open(image_file, "rb") as image_data:
|
||||
responses.add(
|
||||
responses.GET,
|
||||
"http://www.example.com/image.jpg",
|
||||
body=image_data.read(),
|
||||
content_type="image/jpeg",
|
||||
status=200,
|
||||
stream=True,
|
||||
)
|
||||
book = Edition.objects.create(title="hello")
|
||||
|
||||
MockActivity = namedtuple("MockActivity", ("cover"))
|
||||
@ -491,18 +490,18 @@ class ModelFields(TestCase):
|
||||
image_file = pathlib.Path(__file__).parent.joinpath(
|
||||
"../../static/images/default_avi.jpg"
|
||||
)
|
||||
image = Image.open(image_file)
|
||||
output = BytesIO()
|
||||
image.save(output, format=image.format)
|
||||
|
||||
instance = fields.ImageField(activitypub_field="cover", name="cover")
|
||||
|
||||
responses.add(
|
||||
responses.GET,
|
||||
"http://www.example.com/image.jpg",
|
||||
body=image.tobytes(),
|
||||
status=200,
|
||||
)
|
||||
with open(image_file, "rb") as image_data:
|
||||
responses.add(
|
||||
responses.GET,
|
||||
"http://www.example.com/image.jpg",
|
||||
body=image_data.read(),
|
||||
status=200,
|
||||
content_type="image/jpeg",
|
||||
stream=True,
|
||||
)
|
||||
book = Edition.objects.create(title="hello")
|
||||
|
||||
MockActivity = namedtuple("MockActivity", ("cover"))
|
||||
@ -565,18 +564,18 @@ class ModelFields(TestCase):
|
||||
another_image_file = pathlib.Path(__file__).parent.joinpath(
|
||||
"../../static/images/logo.png"
|
||||
)
|
||||
another_image = Image.open(another_image_file)
|
||||
another_output = BytesIO()
|
||||
another_image.save(another_output, format=another_image.format)
|
||||
|
||||
instance = fields.ImageField(activitypub_field="cover", name="cover")
|
||||
|
||||
responses.add(
|
||||
responses.GET,
|
||||
"http://www.example.com/image.jpg",
|
||||
body=another_image.tobytes(),
|
||||
status=200,
|
||||
)
|
||||
with open(another_image_file, "rb") as another_image:
|
||||
responses.add(
|
||||
responses.GET,
|
||||
"http://www.example.com/image.jpg",
|
||||
body=another_image.read(),
|
||||
status=200,
|
||||
content_type="image/jpeg",
|
||||
stream=True,
|
||||
)
|
||||
|
||||
MockActivity = namedtuple("MockActivity", ("cover"))
|
||||
mock_activity = MockActivity("http://www.example.com/image.jpg")
|
||||
|
@ -2,7 +2,6 @@
|
||||
from uuid import uuid4
|
||||
|
||||
from django.contrib.auth.decorators import login_required, permission_required
|
||||
from django.core.files.base import ContentFile
|
||||
from django.core.paginator import Paginator
|
||||
from django.db.models import Avg, Q
|
||||
from django.http import Http404
|
||||
@ -144,13 +143,12 @@ def upload_cover(request, book_id):
|
||||
def set_cover_from_url(url):
|
||||
"""load it from a url"""
|
||||
try:
|
||||
image_file = get_image(url)
|
||||
image_content, extension = get_image(url)
|
||||
except: # pylint: disable=bare-except
|
||||
return None
|
||||
if not image_file:
|
||||
if not image_content:
|
||||
return None
|
||||
image_name = str(uuid4()) + "." + url.split(".")[-1]
|
||||
image_content = ContentFile(image_file.content)
|
||||
image_name = str(uuid4()) + "." + extension
|
||||
return [image_name, image_content]
|
||||
|
||||
|
||||
|
@ -19,4 +19,6 @@ class ListItem(View):
|
||||
form = forms.ListItemForm(request.POST, instance=list_item)
|
||||
if form.is_valid():
|
||||
form.save()
|
||||
else:
|
||||
raise Exception(form.errors)
|
||||
return redirect("list", list_item.book_list.id)
|
||||
|
Reference in New Issue
Block a user