Merge pull request #2544 from joachimesque/redirect-after-shelving-book

Redirect back to the original page after shelving book
This commit is contained in:
Mouse Reeve 2023-01-09 20:05:13 -08:00 committed by GitHub
commit 9480318c5d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 64 additions and 13 deletions

View file

@ -13,7 +13,7 @@ Finish "<em>{{ book_title }}</em>"
{% csrf_token %} {% csrf_token %}
<input type="hidden" name="id" value="{{ readthrough.id }}"> <input type="hidden" name="id" value="{{ readthrough.id }}">
<input type="hidden" name="reading_status" value="read"> <input type="hidden" name="reading_status" value="read">
<input type="hidden" name="shelf" value="{{ move_from }}"> <input type="hidden" name="shelf" value="{{ move_from }}">
{% endblock %} {% endblock %}
{% block reading-dates %} {% block reading-dates %}

View file

@ -10,9 +10,9 @@ Start "<em>{{ book_title }}</em>"
{% block modal-form-open %} {% block modal-form-open %}
<form name="start-reading-{{ uuid }}" action="{% url 'reading-status' 'start' book.id %}" method="post" {% if not refresh %}class="submit-status"{% endif %}> <form name="start-reading-{{ uuid }}" action="{% url 'reading-status' 'start' book.id %}" method="post" {% if not refresh %}class="submit-status"{% endif %}>
{% csrf_token %}
<input type="hidden" name="reading_status" value="reading"> <input type="hidden" name="reading_status" value="reading">
<input type="hidden" name="shelf" value="{{ move_from }}"> <input type="hidden" name="shelf" value="{{ move_from }}">
{% csrf_token %}
{% endblock %} {% endblock %}
{% block reading-dates %} {% block reading-dates %}

View file

@ -10,9 +10,9 @@ Want to Read "<em>{{ book_title }}</em>"
{% block modal-form-open %} {% block modal-form-open %}
<form name="want-to-read-{{ uuid }}" action="{% url 'reading-status' 'want' book.id %}" method="post" {% if not refresh %}class="submit-status"{% endif %}> <form name="want-to-read-{{ uuid }}" action="{% url 'reading-status' 'want' book.id %}" method="post" {% if not refresh %}class="submit-status"{% endif %}>
{% csrf_token %}
<input type="hidden" name="reading_status" value="to-read"> <input type="hidden" name="reading_status" value="to-read">
<input type="hidden" name="shelf" value="{{ move_from }}"> <input type="hidden" name="shelf" value="{{ move_from }}">
{% csrf_token %}
{% endblock %} {% endblock %}
{% block form %} {% block form %}

View file

@ -22,7 +22,6 @@
<input type="hidden" name="book" value="{{ book.id }}"> <input type="hidden" name="book" value="{{ book.id }}">
<input type="hidden" name="change-shelf-from" value="{{ current.identifier }}"> <input type="hidden" name="change-shelf-from" value="{{ current.identifier }}">
<input type="hidden" name="shelf" value="{{ shelf.identifier }}"> <input type="hidden" name="shelf" value="{{ shelf.identifier }}">
<button class="button is-fullwidth is-small shelf-option is-radiusless has-background-body" type="submit" {% if shelf.identifier == current.identifier %}disabled{% endif %}> <button class="button is-fullwidth is-small shelf-option is-radiusless has-background-body" type="submit" {% if shelf.identifier == current.identifier %}disabled{% endif %}>
<span> <span>
{% include "snippets/translated_shelf_name.html" with shelf=shelf %} {% include "snippets/translated_shelf_name.html" with shelf=shelf %}

View file

@ -3,6 +3,7 @@ import re
from django.test import TestCase from django.test import TestCase
from bookwyrm.utils import regex from bookwyrm.utils import regex
from bookwyrm.utils.validate import validate_url_domain
class TestUtils(TestCase): class TestUtils(TestCase):
@ -11,3 +12,20 @@ class TestUtils(TestCase):
def test_regex(self): def test_regex(self):
"""Regexes used throughout the app""" """Regexes used throughout the app"""
self.assertTrue(re.match(regex.DOMAIN, "xn--69aa8bzb.xn--y9a3aq")) self.assertTrue(re.match(regex.DOMAIN, "xn--69aa8bzb.xn--y9a3aq"))
def test_valid_url_domain(self):
"""Check with a valid URL"""
self.assertEqual(
validate_url_domain("https://your.domain.here/legit-book-url/"),
"https://your.domain.here/legit-book-url/",
)
def test_invalid_url_domain(self):
"""Check with an invalid URL"""
self.assertEqual(
validate_url_domain("https://up-to-no-good.tld/bad-actor.exe"), "/"
)
def test_default_url_domain(self):
"""Check with a default URL"""
self.assertEqual(validate_url_domain("/"), "/")

View file

@ -0,0 +1,19 @@
"""Validations"""
from bookwyrm.settings import DOMAIN, USE_HTTPS
def validate_url_domain(url, default="/"):
"""Basic check that the URL starts with the instance domain name"""
if not url:
return default
if url in ("/", default):
return url
protocol = "https://" if USE_HTTPS else "http://"
origin = f"{protocol}{DOMAIN}"
if url.startswith(origin):
return url
return default

View file

@ -12,6 +12,7 @@ from django.views.decorators.http import require_POST
from bookwyrm import forms, models from bookwyrm import forms, models
from bookwyrm.views.shelf.shelf_actions import unshelve from bookwyrm.views.shelf.shelf_actions import unshelve
from bookwyrm.utils.validate import validate_url_domain
from .status import CreateStatus from .status import CreateStatus
from .helpers import get_edition, handle_reading_status, is_api_request from .helpers import get_edition, handle_reading_status, is_api_request
from .helpers import load_date_in_user_tz_as_utc from .helpers import load_date_in_user_tz_as_utc
@ -42,6 +43,8 @@ class ReadingStatus(View):
@transaction.atomic @transaction.atomic
def post(self, request, status, book_id): def post(self, request, status, book_id):
"""Change the state of a book by shelving it and adding reading dates""" """Change the state of a book by shelving it and adding reading dates"""
next_step = request.META.get("HTTP_REFERER")
next_step = validate_url_domain(next_step, "/")
identifier = { identifier = {
"want": models.Shelf.TO_READ, "want": models.Shelf.TO_READ,
"start": models.Shelf.READING, "start": models.Shelf.READING,
@ -83,7 +86,7 @@ class ReadingStatus(View):
if current_status_shelfbook.shelf.identifier != desired_shelf.identifier: if current_status_shelfbook.shelf.identifier != desired_shelf.identifier:
current_status_shelfbook.delete() current_status_shelfbook.delete()
else: # It already was on the shelf else: # It already was on the shelf
return redirect("/") return redirect(next_step)
models.ShelfBook.objects.create( models.ShelfBook.objects.create(
book=book, shelf=desired_shelf, user=request.user book=book, shelf=desired_shelf, user=request.user
@ -121,7 +124,7 @@ class ReadingStatus(View):
if is_api_request(request): if is_api_request(request):
return HttpResponse() return HttpResponse()
return redirect("/") return redirect(next_step)
@method_decorator(login_required, name="dispatch") @method_decorator(login_required, name="dispatch")

View file

@ -3,6 +3,7 @@ from django.db import IntegrityError, transaction
from django.contrib.auth.decorators import login_required from django.contrib.auth.decorators import login_required
from django.shortcuts import get_object_or_404, redirect from django.shortcuts import get_object_or_404, redirect
from django.views.decorators.http import require_POST from django.views.decorators.http import require_POST
from bookwyrm.utils.validate import validate_url_domain
from bookwyrm import forms, models from bookwyrm import forms, models
@ -35,6 +36,8 @@ def delete_shelf(request, shelf_id):
@transaction.atomic @transaction.atomic
def shelve(request): def shelve(request):
"""put a book on a user's shelf""" """put a book on a user's shelf"""
next_step = request.META.get("HTTP_REFERER")
next_step = validate_url_domain(next_step, "/")
book = get_object_or_404(models.Edition, id=request.POST.get("book")) book = get_object_or_404(models.Edition, id=request.POST.get("book"))
desired_shelf = get_object_or_404( desired_shelf = get_object_or_404(
request.user.shelf_set, identifier=request.POST.get("shelf") request.user.shelf_set, identifier=request.POST.get("shelf")
@ -64,13 +67,14 @@ def shelve(request):
.first() .first()
) )
if current_read_status_shelfbook is not None: if current_read_status_shelfbook is not None:
# If it is not already on the shelf
if ( if (
current_read_status_shelfbook.shelf.identifier current_read_status_shelfbook.shelf.identifier
!= desired_shelf.identifier != desired_shelf.identifier
): ):
current_read_status_shelfbook.delete() current_read_status_shelfbook.delete()
else: # It is already on the shelf else:
return redirect("/") return redirect(next_step)
# create the new shelf-book entry # create the new shelf-book entry
models.ShelfBook.objects.create( models.ShelfBook.objects.create(
@ -86,13 +90,16 @@ def shelve(request):
# Might be good to alert, or reject the action? # Might be good to alert, or reject the action?
except IntegrityError: except IntegrityError:
pass pass
return redirect("/")
return redirect(next_step)
@login_required @login_required
@require_POST @require_POST
def unshelve(request, book_id=False): def unshelve(request, book_id=False):
"""remove a book from a user's shelf""" """remove a book from a user's shelf"""
next_step = request.META.get("HTTP_REFERER")
next_step = validate_url_domain(next_step, "/")
identity = book_id if book_id else request.POST.get("book") identity = book_id if book_id else request.POST.get("book")
book = get_object_or_404(models.Edition, id=identity) book = get_object_or_404(models.Edition, id=identity)
shelf_book = get_object_or_404( shelf_book = get_object_or_404(
@ -100,4 +107,4 @@ def unshelve(request, book_id=False):
) )
shelf_book.raise_not_deletable(request.user) shelf_book.raise_not_deletable(request.user)
shelf_book.delete() shelf_book.delete()
return redirect("/") return redirect(next_step)

View file

@ -18,6 +18,7 @@ from django.views.decorators.http import require_POST
from markdown import markdown from markdown import markdown
from bookwyrm import forms, models from bookwyrm import forms, models
from bookwyrm.utils import regex, sanitizer from bookwyrm.utils import regex, sanitizer
from bookwyrm.utils.validate import validate_url_domain
from .helpers import handle_remote_webfinger, is_api_request from .helpers import handle_remote_webfinger, is_api_request
from .helpers import load_date_in_user_tz_as_utc from .helpers import load_date_in_user_tz_as_utc
@ -58,6 +59,8 @@ class CreateStatus(View):
# pylint: disable=too-many-branches # pylint: disable=too-many-branches
def post(self, request, status_type, existing_status_id=None): def post(self, request, status_type, existing_status_id=None):
"""create status of whatever type""" """create status of whatever type"""
next_step = request.META.get("HTTP_REFERER")
next_step = validate_url_domain(next_step, "/")
created = not existing_status_id created = not existing_status_id
existing_status = None existing_status = None
if existing_status_id: if existing_status_id:
@ -80,7 +83,7 @@ class CreateStatus(View):
if is_api_request(request): if is_api_request(request):
logger.exception(form.errors) logger.exception(form.errors)
return HttpResponseBadRequest() return HttpResponseBadRequest()
return redirect("/") return redirect(next_step)
status = form.save(request, commit=False) status = form.save(request, commit=False)
status.ready = False status.ready = False
@ -134,7 +137,7 @@ class CreateStatus(View):
if is_api_request(request): if is_api_request(request):
return HttpResponse() return HttpResponse()
return redirect("/") return redirect(next_step)
@method_decorator(login_required, name="dispatch") @method_decorator(login_required, name="dispatch")
@ -167,6 +170,8 @@ def update_progress(request, book_id): # pylint: disable=unused-argument
def edit_readthrough(request): def edit_readthrough(request):
"""can't use the form because the dates are too finnicky""" """can't use the form because the dates are too finnicky"""
# TODO: remove this, it duplicates the code in the ReadThrough view # TODO: remove this, it duplicates the code in the ReadThrough view
next_step = request.META.get("HTTP_REFERER")
next_step = validate_url_domain(next_step, "/")
readthrough = get_object_or_404(models.ReadThrough, id=request.POST.get("id")) readthrough = get_object_or_404(models.ReadThrough, id=request.POST.get("id"))
readthrough.start_date = load_date_in_user_tz_as_utc( readthrough.start_date = load_date_in_user_tz_as_utc(
@ -198,7 +203,7 @@ def edit_readthrough(request):
if is_api_request(request): if is_api_request(request):
return HttpResponse() return HttpResponse()
return redirect("/") return redirect(next_step)
def find_mentions(user, content): def find_mentions(user, content):