Merge branch 'main' into 2571

This commit is contained in:
Hugh Rundle 2023-04-16 18:11:39 +10:00 committed by GitHub
commit 74f08323d1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
20 changed files with 95 additions and 76 deletions

View file

@ -241,7 +241,7 @@ class ActivityObject:
return data
@app.task(queue=MEDIUM, ignore_result=True)
@app.task(queue=MEDIUM)
@transaction.atomic
def set_related_field(
model_name, origin_model_name, related_field_name, related_remote_id, data
@ -384,7 +384,8 @@ def get_activitypub_data(url):
resp = requests.get(
url,
headers={
"Accept": "application/json; charset=utf-8",
# pylint: disable=line-too-long
"Accept": 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"',
"Date": now,
"Signature": make_signature("get", sender, url, now),
},

View file

@ -497,7 +497,7 @@ def remove_statuses_on_unshelve(sender, instance, *args, **kwargs):
# ---- TASKS
@app.task(queue=LOW, ignore_result=True)
@app.task(queue=LOW)
def add_book_statuses_task(user_id, book_id):
"""add statuses related to a book on shelve"""
user = models.User.objects.get(id=user_id)
@ -505,7 +505,7 @@ def add_book_statuses_task(user_id, book_id):
BooksStream().add_book_statuses(user, book)
@app.task(queue=LOW, ignore_result=True)
@app.task(queue=LOW)
def remove_book_statuses_task(user_id, book_id):
"""remove statuses about a book from a user's books feed"""
user = models.User.objects.get(id=user_id)
@ -513,7 +513,7 @@ def remove_book_statuses_task(user_id, book_id):
BooksStream().remove_book_statuses(user, book)
@app.task(queue=MEDIUM, ignore_result=True)
@app.task(queue=MEDIUM)
def populate_stream_task(stream, user_id):
"""background task for populating an empty activitystream"""
user = models.User.objects.get(id=user_id)
@ -521,7 +521,7 @@ def populate_stream_task(stream, user_id):
stream.populate_streams(user)
@app.task(queue=MEDIUM, ignore_result=True)
@app.task(queue=MEDIUM)
def remove_status_task(status_ids):
"""remove a status from any stream it might be in"""
# this can take an id or a list of ids
@ -536,7 +536,7 @@ def remove_status_task(status_ids):
)
@app.task(queue=HIGH, ignore_result=True)
@app.task(queue=HIGH)
def add_status_task(status_id, increment_unread=False):
"""add a status to any stream it should be in"""
status = models.Status.objects.select_subclasses().get(id=status_id)
@ -548,7 +548,7 @@ def add_status_task(status_id, increment_unread=False):
stream.add_status(status, increment_unread=increment_unread)
@app.task(queue=MEDIUM, ignore_result=True)
@app.task(queue=MEDIUM)
def remove_user_statuses_task(viewer_id, user_id, stream_list=None):
"""remove all statuses by a user from a viewer's stream"""
stream_list = [streams[s] for s in stream_list] if stream_list else streams.values()
@ -558,7 +558,7 @@ def remove_user_statuses_task(viewer_id, user_id, stream_list=None):
stream.remove_user_statuses(viewer, user)
@app.task(queue=MEDIUM, ignore_result=True)
@app.task(queue=MEDIUM)
def add_user_statuses_task(viewer_id, user_id, stream_list=None):
"""add all statuses by a user to a viewer's stream"""
stream_list = [streams[s] for s in stream_list] if stream_list else streams.values()
@ -568,7 +568,7 @@ def add_user_statuses_task(viewer_id, user_id, stream_list=None):
stream.add_user_statuses(viewer, user)
@app.task(queue=MEDIUM, ignore_result=True)
@app.task(queue=MEDIUM)
def handle_boost_task(boost_id):
"""remove the original post and other, earlier boosts"""
instance = models.Status.objects.get(id=boost_id)

View file

@ -143,7 +143,7 @@ def get_or_create_connector(remote_id):
return load_connector(connector_info)
@app.task(queue=LOW, ignore_result=True)
@app.task(queue=LOW)
def load_more_data(connector_id, book_id):
"""background the work of getting all 10,000 editions of LoTR"""
connector_info = models.Connector.objects.get(id=connector_id)
@ -152,7 +152,7 @@ def load_more_data(connector_id, book_id):
connector.expand_book_data(book)
@app.task(queue=LOW, ignore_result=True)
@app.task(queue=LOW)
def create_edition_task(connector_id, work_id, data):
"""separate task for each of the 10,000 editions of LoTR"""
connector_info = models.Connector.objects.get(id=connector_id)

View file

@ -75,7 +75,7 @@ def format_email(email_name, data):
return (subject, html_content, text_content)
@app.task(queue=HIGH, ignore_result=True)
@app.task(queue=HIGH)
def send_email(recipient, subject, html_content, text_content):
"""use a task to send the email"""
email = EmailMultiAlternatives(

View file

@ -217,14 +217,14 @@ def add_list_on_account_create_command(user_id):
# ---- TASKS
@app.task(queue=MEDIUM, ignore_result=True)
@app.task(queue=MEDIUM)
def populate_lists_task(user_id):
"""background task for populating an empty list stream"""
user = models.User.objects.get(id=user_id)
ListsStream().populate_lists(user)
@app.task(queue=MEDIUM, ignore_result=True)
@app.task(queue=MEDIUM)
def remove_list_task(list_id, re_add=False):
"""remove a list from any stream it might be in"""
stores = models.User.objects.filter(local=True, is_active=True).values_list(
@ -239,14 +239,14 @@ def remove_list_task(list_id, re_add=False):
add_list_task.delay(list_id)
@app.task(queue=HIGH, ignore_result=True)
@app.task(queue=HIGH)
def add_list_task(list_id):
"""add a list to any stream it should be in"""
book_list = models.List.objects.get(id=list_id)
ListsStream().add_list(book_list)
@app.task(queue=MEDIUM, ignore_result=True)
@app.task(queue=MEDIUM)
def remove_user_lists_task(viewer_id, user_id, exclude_privacy=None):
"""remove all lists by a user from a viewer's stream"""
viewer = models.User.objects.get(id=viewer_id)
@ -254,7 +254,7 @@ def remove_user_lists_task(viewer_id, user_id, exclude_privacy=None):
ListsStream().remove_user_lists(viewer, user, exclude_privacy=exclude_privacy)
@app.task(queue=MEDIUM, ignore_result=True)
@app.task(queue=MEDIUM)
def add_user_lists_task(viewer_id, user_id):
"""add all lists by a user to a viewer's stream"""
viewer = models.User.objects.get(id=viewer_id)

View file

@ -506,7 +506,7 @@ def unfurl_related_field(related_field, sort_field=None):
return related_field.remote_id
@app.task(queue=BROADCAST, ignore_result=True)
@app.task(queue=BROADCAST)
def broadcast_task(sender_id: int, activity: str, recipients: List[str]):
"""the celery task for broadcast"""
user_model = apps.get_model("bookwyrm.User", require_ready=True)

View file

@ -65,7 +65,7 @@ class AutoMod(AdminModel):
created_by = models.ForeignKey("User", on_delete=models.PROTECT)
@app.task(queue=LOW, ignore_result=True)
@app.task(queue=LOW)
def automod_task():
"""Create reports"""
if not AutoMod.objects.exists():

View file

@ -327,7 +327,7 @@ class ImportItem(models.Model):
)
@app.task(queue=IMPORTS, ignore_result=True)
@app.task(queue=IMPORTS)
def start_import_task(job_id):
"""trigger the child tasks for each row"""
job = ImportJob.objects.get(id=job_id)
@ -346,7 +346,7 @@ def start_import_task(job_id):
job.save()
@app.task(queue=IMPORTS, ignore_result=True)
@app.task(queue=IMPORTS)
def import_item_task(item_id):
"""resolve a row into a book"""
item = ImportItem.objects.get(id=item_id)

View file

@ -469,7 +469,7 @@ class KeyPair(ActivitypubMixin, BookWyrmModel):
return super().save(*args, **kwargs)
@app.task(queue=LOW, ignore_result=True)
@app.task(queue=LOW)
def set_remote_server(user_id):
"""figure out the user's remote server in the background"""
user = User.objects.get(id=user_id)
@ -513,7 +513,7 @@ def get_or_create_remote_server(domain, refresh=False):
return server
@app.task(queue=LOW, ignore_result=True)
@app.task(queue=LOW)
def get_remote_reviews(outbox):
"""ingest reviews by a new remote bookwyrm user"""
outbox_page = outbox + "?page=true&type=Review"

View file

@ -420,7 +420,7 @@ def save_and_cleanup(image, instance=None):
# pylint: disable=invalid-name
@app.task(queue=LOW, ignore_result=True)
@app.task(queue=LOW)
def generate_site_preview_image_task():
"""generate preview_image for the website"""
if not settings.ENABLE_PREVIEW_IMAGES:
@ -445,7 +445,7 @@ def generate_site_preview_image_task():
# pylint: disable=invalid-name
@app.task(queue=LOW, ignore_result=True)
@app.task(queue=LOW)
def generate_edition_preview_image_task(book_id):
"""generate preview_image for a book"""
if not settings.ENABLE_PREVIEW_IMAGES:
@ -470,7 +470,7 @@ def generate_edition_preview_image_task(book_id):
save_and_cleanup(image, instance=book)
@app.task(queue=LOW, ignore_result=True)
@app.task(queue=LOW)
def generate_user_preview_image_task(user_id):
"""generate preview_image for a user"""
if not settings.ENABLE_PREVIEW_IMAGES:
@ -496,7 +496,7 @@ def generate_user_preview_image_task(user_id):
save_and_cleanup(image, instance=user)
@app.task(queue=LOW, ignore_result=True)
@app.task(queue=LOW)
def remove_user_preview_image_task(user_id):
"""remove preview_image for a user"""
if not settings.ENABLE_PREVIEW_IMAGES:

View file

@ -244,20 +244,20 @@ def domain_level_update(sender, instance, created, update_fields=None, **kwargs)
# ------------------- TASKS
@app.task(queue=LOW, ignore_result=True)
@app.task(queue=LOW)
def rerank_suggestions_task(user_id):
"""do the hard work in celery"""
suggested_users.rerank_user_suggestions(user_id)
@app.task(queue=LOW, ignore_result=True)
@app.task(queue=LOW)
def rerank_user_task(user_id, update_only=False):
"""do the hard work in celery"""
user = models.User.objects.get(id=user_id)
suggested_users.rerank_obj(user, update_only=update_only)
@app.task(queue=LOW, ignore_result=True)
@app.task(queue=LOW)
def remove_user_task(user_id):
"""do the hard work in celery"""
user = models.User.objects.get(id=user_id)
@ -266,14 +266,14 @@ def remove_user_task(user_id):
)
@app.task(queue=MEDIUM, ignore_result=True)
@app.task(queue=MEDIUM)
def remove_suggestion_task(user_id, suggested_user_id):
"""remove a specific user from a specific user's suggestions"""
suggested_user = models.User.objects.get(id=suggested_user_id)
suggested_users.remove_suggestion(user_id, suggested_user)
@app.task(queue=LOW, ignore_result=True)
@app.task(queue=LOW)
def bulk_remove_instance_task(instance_id):
"""remove a bunch of users from recs"""
for user in models.User.objects.filter(federated_server__id=instance_id):
@ -282,7 +282,7 @@ def bulk_remove_instance_task(instance_id):
)
@app.task(queue=LOW, ignore_result=True)
@app.task(queue=LOW)
def bulk_add_instance_task(instance_id):
"""remove a bunch of users from recs"""
for user in models.User.objects.filter(federated_server__id=instance_id):

View file

@ -4,6 +4,7 @@
{% load humanize %}
{% load utilities %}
{% load static %}
{% load shelf_tags %}
{% block title %}{{ book|book_title }}{% endblock %}
@ -46,7 +47,13 @@
<meta itemprop="isPartOf" content="{{ book.series | escape }}">
<meta itemprop="volumeNumber" content="{{ book.series_number }}">
(<a href="{% url 'book-series-by' book.authors.first.id %}?series_name={{ book.series }}">{{ book.series }}{% if book.series_number %} #{{ book.series_number }}{% endif %}</a>)
{% if book.authors.exists %}
<a href="{% url 'book-series-by' book.authors.first.id %}?series_name={{ book.series }}">
{% endif %}
{{ book.series }}{% if book.series_number %} #{{ book.series_number }}{% endif %}
{% if book.authors.exists %}
</a>
{% endif %}
{% endif %}
</p>
{% endif %}
@ -239,7 +246,7 @@
<ul>
{% for shelf in user_shelfbooks %}
<li class="box">
<a href="{{ shelf.shelf.local_path }}">{{ shelf.shelf.name }}</a>
<a href="{{ shelf.shelf.local_path }}">{{ shelf.shelf|translate_shelf_name }}</a>
<div class="is-pulled-right">
{% include 'snippets/shelf_selector.html' with shelf=shelf.shelf class="is-small" readthrough=readthrough %}
</div>

View file

@ -30,7 +30,7 @@
<fieldset name="books" class="columns is-mobile">
{% if book_results %}
<div class="column is-narrow">
<p class="help mb-0">Search results</p>
<p class="help mb-0">{% trans "Search results" %}</p>
<div class="columns is-mobile">
{% for book in book_results %}

View file

@ -5,7 +5,7 @@
<div class="block">
<h2 class="title is-4">{% trans "Who to follow" %}</h2>
<p class="subtitle is-6">You can follow users on other BookWyrm instances and federated services like Mastodon.</p>
<p class="subtitle is-6">{% trans "You can follow users on other BookWyrm instances and federated services like Mastodon." %}</p>
<form class="field has-addons" method="get" action="{% url 'get-started-users' %}">
<div class="control">
<input type="text" name="query" value="{{ request.GET.query }}" class="input" placeholder="{% trans 'Search for a user' %}" aria-label="{% trans 'Search for a user' %}">

View file

@ -3,7 +3,7 @@
{% if list.curation == 'group' %}
{% blocktrans with username=list.user.display_name userpath=list.user.local_path groupname=list.group.name grouppath=list.group.local_path %}Created by <a href="{{ userpath }}">{{ username }}</a> and managed by <a href="{{ grouppath }}">{{ groupname }}</a>{% endblocktrans %}
{% elif list.curation != 'open' %}
{% elif list.curation == 'curated' %}
{% blocktrans with username=list.user.display_name path=list.user.local_path %}Created and curated by <a href="{{ path }}">{{ username }}</a>{% endblocktrans %}
{% else %}
{% blocktrans with username=list.user.display_name path=list.user.local_path %}Created by <a href="{{ path }}">{{ username }}</a>{% endblocktrans %}

View file

@ -29,7 +29,7 @@
</div>
<div class="control">
<button type="submit" class="button is-primary">
<span>Search</span>
<span>{% trans "Search" %}</span>
<span class="icon icon-search" aria-hidden="true"></span>
</button>
</div>

View file

@ -9,6 +9,15 @@ from bookwyrm.utils import cache
register = template.Library()
SHELF_NAMES = {
"all": _("All books"),
"to-read": _("To Read"),
"reading": _("Currently Reading"),
"read": _("Read"),
"stopped-reading": _("Stopped Reading"),
}
@register.filter(name="is_book_on_shelf")
def get_is_book_on_shelf(book, shelf):
"""is a book on a shelf"""
@ -42,14 +51,10 @@ def get_translated_shelf_name(shelf):
return ""
# support obj or dict
identifier = shelf["identifier"] if isinstance(shelf, dict) else shelf.identifier
if identifier == "all":
return _("All books")
if identifier == "to-read":
return _("To Read")
if identifier == "reading":
return _("Currently Reading")
if identifier == "read":
return _("Read")
try:
return SHELF_NAMES[identifier]
except KeyError:
return shelf["name"] if isinstance(shelf, dict) else shelf.name

View file

@ -115,7 +115,7 @@ def sometimes_async_activity_task(activity_json, queue=MEDIUM):
activity_task.apply_async(args=(activity_json,), queue=queue)
@app.task(queue=MEDIUM, ignore_result=True)
@app.task(queue=MEDIUM)
def activity_task(activity_json):
"""do something with this json we think is legit"""
# lets see if the activitypub module can make sense of this json

View file

@ -8,7 +8,7 @@ from django.db import transaction
from django.db.models import Avg, DecimalField, Q, Max
from django.db.models.functions import Coalesce
from django.http import HttpResponseBadRequest, HttpResponse
from django.shortcuts import get_object_or_404
from django.shortcuts import get_object_or_404, redirect
from django.template.response import TemplateResponse
from django.urls import reverse
from django.utils.decorators import method_decorator
@ -183,7 +183,7 @@ def delete_list(request, list_id):
book_list.raise_not_deletable(request.user)
book_list.delete()
return redirect_to_referer(request, "lists")
return redirect("/list")
@require_POST

54
bw-dev
View file

@ -23,21 +23,27 @@ trap showerr EXIT
source .env
trap - EXIT
if docker compose &> /dev/null ; then
DOCKER_COMPOSE="docker compose"
else
DOCKER_COMPOSE="docker-compose"
fi
function clean {
docker-compose stop
docker-compose rm -f
$DOCKER_COMPOSE stop
$DOCKER_COMPOSE rm -f
}
function runweb {
docker-compose run --rm web "$@"
$DOCKER_COMPOSE run --rm web "$@"
}
function execdb {
docker-compose exec db $@
$DOCKER_COMPOSE exec db $@
}
function execweb {
docker-compose exec web "$@"
$DOCKER_COMPOSE exec web "$@"
}
function initdb {
@ -75,23 +81,23 @@ set -x
case "$CMD" in
up)
docker-compose up --build "$@"
$DOCKER_COMPOSE up --build "$@"
;;
down)
docker-compose down
$DOCKER_COMPOSE down
;;
service_ports_web)
prod_error
docker-compose run --rm --service-ports web
$DOCKER_COMPOSE run --rm --service-ports web
;;
initdb)
initdb "@"
;;
resetdb)
prod_error
docker-compose rm -svf
$DOCKER_COMPOSE rm -svf
docker volume rm -f bookwyrm_media_volume bookwyrm_pgdata bookwyrm_redis_activity_data bookwyrm_redis_broker_data bookwyrm_static_volume
docker-compose build
$DOCKER_COMPOSE build
migrate
migrate django_celery_beat
initdb
@ -116,7 +122,7 @@ case "$CMD" in
execdb psql -U ${POSTGRES_USER} ${POSTGRES_DB}
;;
restart_celery)
docker-compose restart celery_worker
$DOCKER_COMPOSE restart celery_worker
;;
pytest)
prod_error
@ -164,7 +170,7 @@ case "$CMD" in
runweb django-admin compilemessages --ignore venv
;;
build)
docker-compose build
$DOCKER_COMPOSE build
;;
clean)
prod_error
@ -172,7 +178,7 @@ case "$CMD" in
;;
black)
prod_error
docker-compose run --rm dev-tools black celerywyrm bookwyrm
$DOCKER_COMPOSE run --rm dev-tools black celerywyrm bookwyrm
;;
pylint)
prod_error
@ -181,25 +187,25 @@ case "$CMD" in
;;
prettier)
prod_error
docker-compose run --rm dev-tools npx prettier --write bookwyrm/static/js/*.js
$DOCKER_COMPOSE run --rm dev-tools npx prettier --write bookwyrm/static/js/*.js
;;
eslint)
prod_error
docker-compose run --rm dev-tools npx eslint bookwyrm/static --ext .js
$DOCKER_COMPOSE run --rm dev-tools npx eslint bookwyrm/static --ext .js
;;
stylelint)
prod_error
docker-compose run --rm dev-tools npx stylelint \
$DOCKER_COMPOSE run --rm dev-tools npx stylelint \
bookwyrm/static/css/bookwyrm.scss bookwyrm/static/css/bookwyrm/**/*.scss --fix \
--config dev-tools/.stylelintrc.js
;;
formatters)
prod_error
runweb pylint bookwyrm/
docker-compose run --rm dev-tools black celerywyrm bookwyrm
docker-compose run --rm dev-tools npx prettier --write bookwyrm/static/js/*.js
docker-compose run --rm dev-tools npx eslint bookwyrm/static --ext .js
docker-compose run --rm dev-tools npx stylelint \
$DOCKER_COMPOSE run --rm dev-tools black celerywyrm bookwyrm
$DOCKER_COMPOSE run --rm dev-tools npx prettier --write bookwyrm/static/js/*.js
$DOCKER_COMPOSE run --rm dev-tools npx eslint bookwyrm/static --ext .js
$DOCKER_COMPOSE run --rm dev-tools npx stylelint \
bookwyrm/static/css/bookwyrm.scss bookwyrm/static/css/bookwyrm/**/*.scss --fix \
--config dev-tools/.stylelintrc.js
;;
@ -209,14 +215,14 @@ case "$CMD" in
;;
update)
git pull
docker-compose build
$DOCKER_COMPOSE build
# ./update.sh
runweb python manage.py migrate
runweb python manage.py compile_themes
runweb python manage.py collectstatic --no-input
docker-compose up -d
docker-compose restart web
docker-compose restart celery_worker
$DOCKER_COMPOSE up -d
$DOCKER_COMPOSE restart web
$DOCKER_COMPOSE restart celery_worker
;;
populate_streams)
runweb python manage.py populate_streams "$@"