diff --git a/bookwyrm/views/block.py b/bookwyrm/views/block.py index 0b80c327..90b3be90 100644 --- a/bookwyrm/views/block.py +++ b/bookwyrm/views/block.py @@ -1,6 +1,5 @@ """ views for actions you can take in the application """ from django.contrib.auth.decorators import login_required -from django.http import HttpResponseNotFound from django.shortcuts import get_object_or_404, redirect from django.template.response import TemplateResponse from django.utils.decorators import method_decorator @@ -32,12 +31,10 @@ class Block(View): def unblock(request, user_id): """undo a block""" to_unblock = get_object_or_404(models.User, id=user_id) - try: - block = models.UserBlocks.objects.get( - user_subject=request.user, - user_object=to_unblock, - ) - except models.UserBlocks.DoesNotExist: - return HttpResponseNotFound() + block = get_object_or_404( + models.UserBlocks, + user_subject=request.user, + user_object=to_unblock, + ) block.delete() return redirect("prefs-block") diff --git a/bookwyrm/views/feed.py b/bookwyrm/views/feed.py index 09d45065..ea3bb8f8 100644 --- a/bookwyrm/views/feed.py +++ b/bookwyrm/views/feed.py @@ -3,6 +3,7 @@ from django.contrib.auth.decorators import login_required from django.core.paginator import Paginator from django.db.models import Q from django.http import HttpResponseNotFound, Http404 +from django.shortcuts import get_object_or_404 from django.template.response import TemplateResponse from django.utils import timezone from django.utils.decorators import method_decorator @@ -93,17 +94,12 @@ class Status(View): def get(self, request, username, status_id): """display a particular status (and replies, etc)""" - try: - user = get_user_from_username(request.user, username) - status = models.Status.objects.select_subclasses().get( - user=user, id=status_id, deleted=False - ) - except (ValueError, models.Status.DoesNotExist): - return HttpResponseNotFound() - + user = get_user_from_username(request.user, username) + status = get_object_or_404(models.Status.objects.select_subclasses(), + user=user, id=status_id, deleted=False + ) # make sure the user is authorized to see the status - if not status.visible_to_user(request.user): - return HttpResponseNotFound() + status.raise_visible_to_user(request.user) if is_api_request(request): return ActivitypubResponse( @@ -133,6 +129,7 @@ class Replies(View): status = models.Status.objects.get(id=status_id) if status.user.localname != username: return HttpResponseNotFound() + status.raise_visible_to_user(request.user) return ActivitypubResponse(status.to_replies(**request.GET)) diff --git a/bookwyrm/views/follow.py b/bookwyrm/views/follow.py index 0710a70c..8cbb1d25 100644 --- a/bookwyrm/views/follow.py +++ b/bookwyrm/views/follow.py @@ -1,8 +1,7 @@ """ views for actions you can take in the application """ from django.contrib.auth.decorators import login_required from django.db import IntegrityError -from django.http import HttpResponseBadRequest -from django.shortcuts import redirect +from django.shortcuts import get_object_or_404, redirect from django.views.decorators.http import require_POST from bookwyrm import models @@ -78,12 +77,10 @@ def delete_follow_request(request): username = request.POST["user"] requester = get_user_from_username(request.user, username) - try: - follow_request = models.UserFollowRequest.objects.get( - user_subject=requester, user_object=request.user - ) - except models.UserFollowRequest.DoesNotExist: - return HttpResponseBadRequest() + follow_request = get_object_or_404(models.UserFollowRequest, + user_subject=requester, user_object=request.user + ) + follow_request.raise_not_deletable(request.user) follow_request.delete() return redirect(f"/user/{request.user.localname}") diff --git a/bookwyrm/views/get_started.py b/bookwyrm/views/get_started.py index 3de88e10..4a6b55c5 100644 --- a/bookwyrm/views/get_started.py +++ b/bookwyrm/views/get_started.py @@ -5,7 +5,6 @@ from django.contrib.auth.decorators import login_required from django.contrib.postgres.search import TrigramSimilarity from django.db.models.functions import Greatest from django.db.models import Count, Q -from django.http import HttpResponseNotFound from django.shortcuts import get_object_or_404, redirect from django.template.response import TemplateResponse from django.utils.decorators import method_decorator @@ -91,9 +90,8 @@ class GetStartedBooks(View): for (book_id, shelf_id) in shelve_actions: book = get_object_or_404(models.Edition, id=book_id) shelf = get_object_or_404(models.Shelf, id=shelf_id) - if shelf.user != request.user: - # hmmmmm - return HttpResponseNotFound() + shelf.raise_not_editable(request.user) + models.ShelfBook.objects.create(book=book, shelf=shelf, user=request.user) return redirect(self.next_view) diff --git a/bookwyrm/views/goal.py b/bookwyrm/views/goal.py index 12224517..1a0a99bf 100644 --- a/bookwyrm/views/goal.py +++ b/bookwyrm/views/goal.py @@ -31,8 +31,7 @@ class Goal(View): if not goal and year != timezone.now().year: return redirect("user-goal", username, current_year) - if goal and not goal.visible_to_user(request.user): - return HttpResponseNotFound() + goal.raise_visible_to_user(request.user) data = { "goal_form": forms.GoalForm(instance=goal), @@ -45,12 +44,12 @@ class Goal(View): def post(self, request, username, year): """update or create an annual goal""" - user = get_user_from_username(request.user, username) - if user != request.user: - return HttpResponseNotFound() - year = int(year) - goal = models.AnnualGoal.objects.filter(year=year, user=request.user).first() + user = get_user_from_username(request.user, username) + goal = models.AnnualGoal.objects.filter(year=year, user=user).first() + if goal: + goal.raise_not_editable(request.user) + form = forms.GoalForm(request.POST, instance=goal) if not form.is_valid(): data = { @@ -62,11 +61,11 @@ class Goal(View): goal = form.save() if request.POST.get("post-status"): - # create status, if appropraite + # create status, if appropriate template = get_template("snippets/generated_status/goal.html") create_generated_note( request.user, - template.render({"goal": goal, "user": request.user}).strip(), + template.render({"goal": goal, "user": user}).strip(), privacy=goal.privacy, ) @@ -78,5 +77,5 @@ class Goal(View): def hide_goal(request): """don't keep bugging people to set a goal""" request.user.show_goal = False - request.user.save(broadcast=False) + request.user.save(broadcast=False, update_fields=["show_goal"]) return redirect(request.headers.get("Referer", "/")) diff --git a/bookwyrm/views/list.py b/bookwyrm/views/list.py index c043e483..99fee3f8 100644 --- a/bookwyrm/views/list.py +++ b/bookwyrm/views/list.py @@ -7,7 +7,7 @@ from django.core.paginator import Paginator from django.db import IntegrityError, transaction from django.db.models import Avg, Count, DecimalField, Q, Max from django.db.models.functions import Coalesce -from django.http import HttpResponseNotFound, HttpResponseBadRequest, HttpResponse +from django.http import HttpResponseBadRequest, HttpResponse from django.shortcuts import get_object_or_404, redirect from django.template.response import TemplateResponse from django.urls import reverse @@ -110,8 +110,7 @@ class List(View): def get(self, request, list_id): """display a book list""" book_list = get_object_or_404(models.List, id=list_id) - if not book_list.visible_to_user(request.user): - return HttpResponseNotFound() + book_list.raise_visible_to_user(request.user) if is_api_request(request): return ActivitypubResponse(book_list.to_activity(**request.GET)) @@ -192,6 +191,8 @@ class List(View): def post(self, request, list_id): """edit a list""" book_list = get_object_or_404(models.List, id=list_id) + book_list.raise_not_editable(request.user) + form = forms.ListForm(request.POST, instance=book_list) if not form.is_valid(): return redirect("list", book_list.id) @@ -206,9 +207,7 @@ class Curate(View): def get(self, request, list_id): """display a pending list""" book_list = get_object_or_404(models.List, id=list_id) - if not book_list.user == request.user: - # only the creater can curate the list - return HttpResponseNotFound() + book_list.raise_not_editable(request.user) data = { "list": book_list, @@ -222,6 +221,8 @@ class Curate(View): def post(self, request, list_id): """edit a book_list""" book_list = get_object_or_404(models.List, id=list_id) + book_list.raise_not_editable(request.user) + suggestion = get_object_or_404(models.ListItem, id=request.POST.get("item")) approved = request.POST.get("approved") == "true" if approved: @@ -269,7 +270,7 @@ def delete_list(request, list_id): book_list = get_object_or_404(models.List, id=list_id) # only the owner or a moderator can delete a list - book_list.raise_not_editable(request.user) + book_list.raise_not_deletable(request.user) book_list.delete() return redirect("lists") @@ -280,8 +281,7 @@ def delete_list(request, list_id): def add_book(request): """put a book on a list""" book_list = get_object_or_404(models.List, id=request.POST.get("list")) - if not book_list.visible_to_user(request.user): - return HttpResponseNotFound() + book_list.raise_visible_to_user(request.user) book = get_object_or_404(models.Edition, id=request.POST.get("book")) # do you have permission to add to the list? diff --git a/bookwyrm/views/reading.py b/bookwyrm/views/reading.py index 09b4b2bf..8d0020c2 100644 --- a/bookwyrm/views/reading.py +++ b/bookwyrm/views/reading.py @@ -45,9 +45,9 @@ class ReadingStatus(View): if not identifier: return HttpResponseBadRequest() - desired_shelf = models.Shelf.objects.filter( + desired_shelf = get_object_or_404(models.Shelf, identifier=identifier, user=request.user - ).first() + ) book = ( models.Edition.viewer_aware_objects(request.user) @@ -138,10 +138,7 @@ def update_readthrough_on_shelve( def edit_readthrough(request): """can't use the form because the dates are too finnicky""" readthrough = get_object_or_404(models.ReadThrough, id=request.POST.get("id")) - - # don't let people edit other people's data - if request.user != readthrough.user: - return HttpResponseBadRequest() + readthrough.raise_not_editable(request.user) readthrough.start_date = load_date_in_user_tz_as_utc( request.POST.get("start_date"), request.user @@ -178,10 +175,7 @@ def edit_readthrough(request): def delete_readthrough(request): """remove a readthrough""" readthrough = get_object_or_404(models.ReadThrough, id=request.POST.get("id")) - - # don't let people edit other people's data - if request.user != readthrough.user: - return HttpResponseBadRequest() + readthrough.raise_not_deletable(request.user) readthrough.delete() return redirect(request.headers.get("Referer", "/")) @@ -225,10 +219,7 @@ def load_date_in_user_tz_as_utc(date_str: str, user: models.User) -> datetime: def delete_progressupdate(request): """remove a progress update""" update = get_object_or_404(models.ProgressUpdate, id=request.POST.get("id")) - - # don't let people edit other people's data - if request.user != update.user: - return HttpResponseBadRequest() + update.raise_not_deletable(request.user) update.delete() return redirect(request.headers.get("Referer", "/")) diff --git a/bookwyrm/views/user.py b/bookwyrm/views/user.py index ca6eb0a5..fb553228 100644 --- a/bookwyrm/views/user.py +++ b/bookwyrm/views/user.py @@ -1,6 +1,7 @@ """ non-interactive pages """ from django.contrib.auth.decorators import login_required from django.core.paginator import Paginator +from django.http import Http404 from django.shortcuts import redirect from django.template.response import TemplateResponse from django.utils import timezone @@ -77,8 +78,12 @@ class User(View): goal = models.AnnualGoal.objects.filter( user=user, year=timezone.now().year ).first() - if goal and not goal.visible_to_user(request.user): - goal = None + if goal: + try: + goal.raise_visible_to_user(request.user) + except Http404: + goal = None + data = { "user": user, "is_self": is_self, diff --git a/bookwyrm/views/wellknown.py b/bookwyrm/views/wellknown.py index 660a4524..3350ae31 100644 --- a/bookwyrm/views/wellknown.py +++ b/bookwyrm/views/wellknown.py @@ -3,6 +3,7 @@ from dateutil.relativedelta import relativedelta from django.http import HttpResponseNotFound from django.http import JsonResponse +from django.shortcuts import get_object_or_404 from django.template.response import TemplateResponse from django.utils import timezone from django.views.decorators.http import require_GET @@ -19,10 +20,7 @@ def webfinger(request): return HttpResponseNotFound() username = resource.replace("acct:", "") - try: - user = models.User.objects.get(username__iexact=username) - except models.User.DoesNotExist: - return HttpResponseNotFound("No account found") + user = get_object_or_404(models.User, username__iexact=username) return JsonResponse( {