1
0
Fork 0

Merge from main into 'user-export'

Conflicts:
	bookwyrm/models/bookwyrm_export_job.py
	requirements.txt
This commit is contained in:
Adeodato Simó 2024-03-18 14:36:07 -03:00
commit 518da3b9cf
70 changed files with 8108 additions and 430 deletions

View file

@ -5,6 +5,7 @@ from .admin.announcements import EditAnnouncement, delete_announcement
from .admin.automod import AutoMod, automod_delete, run_automod
from .admin.automod import schedule_automod_task, unschedule_automod_task
from .admin.celery_status import CeleryStatus, celery_ping
from .admin.schedule import ScheduledTasks
from .admin.dashboard import Dashboard
from .admin.federation import Federation, FederatedServer
from .admin.federation import AddFederatedServer, ImportServerBlocklist

View file

@ -6,7 +6,7 @@ from django.template.response import TemplateResponse
from django.utils.decorators import method_decorator
from django.views import View
from django.views.decorators.http import require_POST
from django_celery_beat.models import PeriodicTask
from django_celery_beat.models import PeriodicTask, IntervalSchedule
from bookwyrm import forms, models
@ -54,7 +54,7 @@ def schedule_automod_task(request):
return TemplateResponse(request, "settings/automod/rules.html", data)
with transaction.atomic():
schedule = form.save(request)
schedule, _ = IntervalSchedule.objects.get_or_create(**form.cleaned_data)
PeriodicTask.objects.get_or_create(
interval=schedule,
name="automod-task",

View file

@ -6,16 +6,18 @@ from dateutil.parser import parse
from packaging import version
from django.contrib.auth.decorators import login_required, permission_required
from django.db import transaction
from django.db.models import Q
from django.shortcuts import redirect
from django.template.response import TemplateResponse
from django.utils import timezone
from django.utils.decorators import method_decorator
from django.views import View
from django_celery_beat.models import PeriodicTask, IntervalSchedule
from csp.decorators import csp_update
from bookwyrm import models, settings
from bookwyrm.connectors.abstract_connector import get_data
from bookwyrm import forms, models, settings
from bookwyrm.utils import regex
@ -59,21 +61,36 @@ class Dashboard(View):
== site._meta.get_field("privacy_policy").get_default()
)
# check version
if site.available_version and version.parse(
site.available_version
) > version.parse(settings.VERSION):
data["current_version"] = settings.VERSION
data["available_version"] = site.available_version
try:
release = get_data(settings.RELEASE_API, timeout=3)
available_version = release.get("tag_name", None)
if available_version and version.parse(available_version) > version.parse(
settings.VERSION
):
data["current_version"] = settings.VERSION
data["available_version"] = available_version
except: # pylint: disable= bare-except
pass
if not PeriodicTask.objects.filter(name="check-for-updates").exists():
data["schedule_form"] = forms.IntervalScheduleForm(
{"every": 1, "period": "days"}
)
return TemplateResponse(request, "settings/dashboard/dashboard.html", data)
def post(self, request):
"""Create a schedule task to check for updates"""
schedule_form = forms.IntervalScheduleForm(request.POST)
if not schedule_form.is_valid():
raise schedule_form.ValidationError(schedule_form.errors)
with transaction.atomic():
schedule, _ = IntervalSchedule.objects.get_or_create(
**schedule_form.cleaned_data
)
PeriodicTask.objects.get_or_create(
interval=schedule,
name="check-for-updates",
task="bookwyrm.models.site.check_for_updates_task",
)
return redirect("settings-dashboard")
def get_charts_and_stats(request):
"""Defines the dashboard charts"""

View file

@ -0,0 +1,31 @@
""" Scheduled celery tasks """
from django.contrib.auth.decorators import login_required, permission_required
from django.shortcuts import redirect
from django.template.response import TemplateResponse
from django.utils.decorators import method_decorator
from django.views import View
from django_celery_beat.models import PeriodicTask, IntervalSchedule
@method_decorator(login_required, name="dispatch")
@method_decorator(
permission_required("bookwyrm.edit_instance_settings", raise_exception=True),
name="dispatch",
)
# pylint: disable=no-self-use
class ScheduledTasks(View):
"""Manage automated flagging"""
def get(self, request):
"""view schedules"""
data = {}
data["tasks"] = PeriodicTask.objects.all()
data["schedules"] = IntervalSchedule.objects.all()
return TemplateResponse(request, "settings/schedules.html", data)
# pylint: disable=unused-argument
def post(self, request, task_id):
"""un-schedule a task"""
task = PeriodicTask.objects.get(id=task_id)
task.delete()
return redirect("settings-schedules")

View file

@ -93,6 +93,7 @@ def switch_edition(request):
user=shelfbook.user,
shelf=shelfbook.shelf,
book=new_edition,
shelved_date=shelfbook.shelved_date,
)
shelfbook.delete()
@ -103,4 +104,13 @@ def switch_edition(request):
readthrough.book = new_edition
readthrough.save()
reviews = models.Review.objects.filter(
book__parent_work=new_edition.parent_work, user=request.user
)
for review in reviews.all():
# because ratings are a subclass of reviews,
# this will pick up both ratings and reviews
review.book = new_edition
review.save()
return redirect(f"/book/{new_edition.id}")

View file

@ -1,4 +1,5 @@
""" non-interactive pages """
from datetime import date
from django.contrib.auth.decorators import login_required
from django.core.paginator import Paginator
from django.db.models import Q
@ -52,6 +53,19 @@ class Feed(View):
suggestions = suggested_users.get_suggestions(request.user)
cutoff = (
date(get_annual_summary_year(), 12, 31)
if get_annual_summary_year()
else None
)
readthroughs = (
models.ReadThrough.objects.filter(
user=request.user, finish_date__lte=cutoff
)
if get_annual_summary_year()
else []
)
data = {
**feed_page_data(request.user),
**{
@ -66,6 +80,7 @@ class Feed(View):
"path": f"/{tab['key']}",
"annual_summary_year": get_annual_summary_year(),
"has_tour": True,
"has_summary_read_throughs": len(readthroughs),
},
}
return TemplateResponse(request, "feed/feed.html", data)
@ -185,19 +200,15 @@ class Status(View):
params=[status.id, visible_thread, visible_thread],
)
preview = None
if hasattr(status, "book"):
preview = status.book.preview_image
elif status.mention_books.exists():
preview = status.mention_books.first().preview_image
data = {
**feed_page_data(request.user),
**{
"status": status,
"children": children,
"ancestors": ancestors,
"preview": preview,
"title": status.page_title,
"description": status.page_description,
"page_image": status.page_image,
},
}
return TemplateResponse(request, "feed/status.html", data)

View file

@ -1,4 +1,5 @@
""" search views"""
import re
from django.contrib.postgres.search import TrigramSimilarity
@ -39,6 +40,7 @@ class Search(View):
endpoints = {
"book": book_search,
"author": author_search,
"user": user_search,
"list": list_search,
}
@ -90,6 +92,31 @@ def book_search(request):
return TemplateResponse(request, "search/book.html", data)
def author_search(request):
"""search for an author"""
query = request.GET.get("q")
query = query.strip()
data = {"type": "author", "query": query}
results = (
models.Author.objects.annotate(
similarity=TrigramSimilarity("name", query),
)
.filter(
similarity__gt=0.1,
)
.order_by("-similarity")
)
paginated = Paginator(results, PAGE_LENGTH)
page = paginated.get_page(request.GET.get("page"))
data["results"] = page
data["page_range"] = paginated.get_elided_page_range(
page.number, on_each_side=2, on_ends=1
)
return TemplateResponse(request, "search/author.html", data)
def user_search(request):
"""user search: search for a user"""
viewer = request.user