mirror of
https://github.com/bookwyrm-social/bookwyrm.git
synced 2024-10-31 22:19:00 +00:00
Merge branch 'main' into production
This commit is contained in:
commit
f6366e1c4a
13 changed files with 145 additions and 17 deletions
|
@ -6,7 +6,8 @@ from .base_activity import ActivityEncoder, Signature, naive_parse
|
|||
from .base_activity import Link, Mention
|
||||
from .base_activity import ActivitySerializerError, resolve_remote_id
|
||||
from .image import Image
|
||||
from .note import Note, GeneratedNote, Article, Comment, Review, Quotation
|
||||
from .note import Note, GeneratedNote, Article, Comment, Quotation
|
||||
from .note import Review, Rating
|
||||
from .note import Tombstone
|
||||
from .ordered_collection import OrderedCollection, OrderedCollectionPage
|
||||
from .ordered_collection import BookList, Shelf
|
||||
|
|
|
@ -13,7 +13,7 @@ class Tombstone(ActivityObject):
|
|||
|
||||
type: str = "Tombstone"
|
||||
|
||||
def to_model(self, *args, **kwargs):
|
||||
def to_model(self, *args, **kwargs): # pylint: disable=unused-argument
|
||||
""" this should never really get serialized, just searched for """
|
||||
model = apps.get_model("bookwyrm.Status")
|
||||
return model.find_existing_by_remote_id(self.id)
|
||||
|
@ -60,6 +60,14 @@ class Comment(Note):
|
|||
type: str = "Comment"
|
||||
|
||||
|
||||
@dataclass(init=False)
|
||||
class Quotation(Comment):
|
||||
""" a quote and commentary on a book """
|
||||
|
||||
quote: str
|
||||
type: str = "Quotation"
|
||||
|
||||
|
||||
@dataclass(init=False)
|
||||
class Review(Comment):
|
||||
""" a full book review """
|
||||
|
@ -70,8 +78,9 @@ class Review(Comment):
|
|||
|
||||
|
||||
@dataclass(init=False)
|
||||
class Quotation(Comment):
|
||||
""" a quote and commentary on a book """
|
||||
class Rating(Comment):
|
||||
""" just a star rating """
|
||||
|
||||
quote: str
|
||||
type: str = "Quotation"
|
||||
rating: int
|
||||
content: str = None
|
||||
type: str = "Rating"
|
||||
|
|
|
@ -54,8 +54,8 @@ class RegisterForm(CustomForm):
|
|||
|
||||
class RatingForm(CustomForm):
|
||||
class Meta:
|
||||
model = models.Review
|
||||
fields = ["user", "book", "content", "rating", "privacy"]
|
||||
model = models.ReviewRating
|
||||
fields = ["user", "book", "rating", "privacy"]
|
||||
|
||||
|
||||
class ReviewForm(CustomForm):
|
||||
|
|
66
bookwyrm/migrations/0046_reviewrating.py
Normal file
66
bookwyrm/migrations/0046_reviewrating.py
Normal file
|
@ -0,0 +1,66 @@
|
|||
# Generated by Django 3.0.7 on 2021-02-25 18:36
|
||||
|
||||
from django.db import migrations, models
|
||||
from django.db import connection
|
||||
from django.db.models import Q
|
||||
import django.db.models.deletion
|
||||
from psycopg2.extras import execute_values
|
||||
|
||||
|
||||
def convert_review_rating(app_registry, schema_editor):
|
||||
""" take rating type Reviews and convert them to ReviewRatings """
|
||||
db_alias = schema_editor.connection.alias
|
||||
|
||||
reviews = (
|
||||
app_registry.get_model("bookwyrm", "Review")
|
||||
.objects.using(db_alias)
|
||||
.filter(Q(content__isnull=True) | Q(content=""))
|
||||
)
|
||||
|
||||
with connection.cursor() as cursor:
|
||||
values = [(r.id,) for r in reviews]
|
||||
execute_values(
|
||||
cursor,
|
||||
"""
|
||||
INSERT INTO bookwyrm_reviewrating(review_ptr_id)
|
||||
VALUES %s""",
|
||||
values,
|
||||
)
|
||||
|
||||
|
||||
def unconvert_review_rating(app_registry, schema_editor):
|
||||
""" undo the conversion from ratings back to reviews"""
|
||||
# All we need to do to revert this is drop the table, which Django will do
|
||||
# on its own, as long as we have a valid reverse function. So, this is a
|
||||
# no-op function so Django will do its thing
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("bookwyrm", "0045_auto_20210210_2114"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name="ReviewRating",
|
||||
fields=[
|
||||
(
|
||||
"review_ptr",
|
||||
models.OneToOneField(
|
||||
auto_created=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
parent_link=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
to="bookwyrm.Review",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"abstract": False,
|
||||
},
|
||||
bases=("bookwyrm.review",),
|
||||
),
|
||||
migrations.RunPython(convert_review_rating, unconvert_review_rating),
|
||||
]
|
13
bookwyrm/migrations/0047_merge_20210228_1839.py
Normal file
13
bookwyrm/migrations/0047_merge_20210228_1839.py
Normal file
|
@ -0,0 +1,13 @@
|
|||
# Generated by Django 3.0.7 on 2021-02-28 18:39
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("bookwyrm", "0046_reviewrating"),
|
||||
("bookwyrm", "0046_sitesettings_privacy_policy"),
|
||||
]
|
||||
|
||||
operations = []
|
13
bookwyrm/migrations/0048_merge_20210308_1754.py
Normal file
13
bookwyrm/migrations/0048_merge_20210308_1754.py
Normal file
|
@ -0,0 +1,13 @@
|
|||
# Generated by Django 3.0.7 on 2021-03-08 17:54
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("bookwyrm", "0047_connector_isbn_search_url"),
|
||||
("bookwyrm", "0047_merge_20210228_1839"),
|
||||
]
|
||||
|
||||
operations = []
|
|
@ -9,7 +9,8 @@ from .connector import Connector
|
|||
from .shelf import Shelf, ShelfBook
|
||||
from .list import List, ListItem
|
||||
|
||||
from .status import Status, GeneratedNote, Review, Comment, Quotation
|
||||
from .status import Status, GeneratedNote, Comment, Quotation
|
||||
from .status import Review, ReviewRating
|
||||
from .status import Boost
|
||||
from .attachment import Image
|
||||
from .favorite import Favorite
|
||||
|
|
|
@ -278,13 +278,12 @@ class Review(Status):
|
|||
def pure_name(self):
|
||||
""" clarify review names for mastodon serialization """
|
||||
if self.rating:
|
||||
# pylint: disable=bad-string-format-type
|
||||
return 'Review of "%s" (%d stars): %s' % (
|
||||
return 'Review of "{}" ({:d} stars): {}'.format(
|
||||
self.book.title,
|
||||
self.rating,
|
||||
self.name,
|
||||
)
|
||||
return 'Review of "%s": %s' % (self.book.title, self.name)
|
||||
return 'Review of "{}": {}'.format(self.book.title, self.name)
|
||||
|
||||
@property
|
||||
def pure_content(self):
|
||||
|
@ -295,6 +294,22 @@ class Review(Status):
|
|||
pure_type = "Article"
|
||||
|
||||
|
||||
class ReviewRating(Review):
|
||||
""" a subtype of review that only contains a rating """
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
if not self.rating:
|
||||
raise ValueError("ReviewRating object must include a numerical rating")
|
||||
return super().save(*args, **kwargs)
|
||||
|
||||
@property
|
||||
def pure_content(self):
|
||||
return 'Rated "{}": {:d} stars'.format(self.book.title, self.rating)
|
||||
|
||||
activity_serializer = activitypub.Rating
|
||||
pure_type = "Note"
|
||||
|
||||
|
||||
class Boost(ActivityMixin, Status):
|
||||
""" boost'ing a post """
|
||||
|
||||
|
|
|
@ -104,7 +104,7 @@
|
|||
{% for error in form.openlibrary_key.errors %}
|
||||
<p class="help is-danger">{{ error | escape }}</p>
|
||||
{% endfor %}
|
||||
<p class="fields is-grouped"><label class="label" for="id_librarything_key">{% trans "OCLC Number:" %}</label> {{ form.oclc_number }} </p>
|
||||
<p class="fields is-grouped"><label class="label" for="id_oclc_number">{% trans "OCLC Number:" %}</label> {{ form.oclc_number }} </p>
|
||||
{% for error in form.oclc_number.errors %}
|
||||
<p class="help is-danger">{{ error | escape }}</p>
|
||||
{% endfor %}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{% load bookwyrm_tags %}
|
||||
{% load i18n %}
|
||||
<div class="block">
|
||||
{% if status.status_type == 'Review' %}
|
||||
{% if status.status_type == 'Review' or status.status_type == 'Rating' %}
|
||||
<div>
|
||||
{% if status.name %}
|
||||
<h3 class="title is-5 has-subtitle" dir="auto">
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
{% if status.status_type == 'GeneratedNote' %}
|
||||
{{ status.content | safe }}
|
||||
{% elif status.status_type == 'Review' and not status.name and not status.content%}
|
||||
{% elif status.status_type == 'Rating' %}
|
||||
{% trans "rated" %}
|
||||
{% elif status.status_type == 'Review' %}
|
||||
{% trans "reviewed" %}
|
||||
|
|
|
@ -10,7 +10,15 @@ from bookwyrm.utils import regex
|
|||
user_path = r"^user/(?P<username>%s)" % regex.username
|
||||
local_user_path = r"^user/(?P<username>%s)" % regex.localname
|
||||
|
||||
status_types = ["status", "review", "comment", "quotation", "boost", "generatednote"]
|
||||
status_types = [
|
||||
"status",
|
||||
"review",
|
||||
"reviewrating",
|
||||
"comment",
|
||||
"quotation",
|
||||
"boost",
|
||||
"generatednote",
|
||||
]
|
||||
status_path = r"%s/(%s)/(?P<status_id>\d+)" % (user_path, "|".join(status_types))
|
||||
|
||||
book_path = r"^book/(?P<book_id>\d+)"
|
||||
|
|
|
@ -57,7 +57,7 @@ class CreateStatus(View):
|
|||
status.mention_users.set(set(status.mention_users.all()))
|
||||
|
||||
# don't apply formatting to generated notes
|
||||
if not isinstance(status, models.GeneratedNote):
|
||||
if not isinstance(status, models.GeneratedNote) and content:
|
||||
status.content = to_markdown(content)
|
||||
# do apply formatting to quotes
|
||||
if hasattr(status, "quote"):
|
||||
|
@ -85,6 +85,8 @@ class DeleteStatus(View):
|
|||
|
||||
def find_mentions(content):
|
||||
""" detect @mentions in raw status content """
|
||||
if not content:
|
||||
return
|
||||
for match in re.finditer(regex.strict_username, content):
|
||||
username = match.group().strip().split("@")[1:]
|
||||
if len(username) == 1:
|
||||
|
|
Loading…
Reference in a new issue