From a58ab5eb743751a0e1d16b8daaae8fb7f7971432 Mon Sep 17 00:00:00 2001 From: Your Name Date: Sat, 4 Feb 2023 00:45:17 -0500 Subject: [PATCH] add 4xx 5xx pages --- boofilsic/urls.py | 5 +++ catalog/search/views.py | 17 +++++----- catalog/views.py | 42 +++++++++++-------------- common/templates/400.html | 39 +++++++++++++++++++++++ common/templates/403.html | 39 +++++++++++++++++++++++ common/templates/404.html | 39 +++++++++++++++++++++++ common/templates/500.html | 39 +++++++++++++++++++++++ common/views.py | 18 ++++++++++- journal/views.py | 66 ++++++++++++++++++--------------------- users/account.py | 16 ++++------ users/views.py | 13 ++++---- 11 files changed, 246 insertions(+), 87 deletions(-) create mode 100644 common/templates/400.html create mode 100644 common/templates/403.html create mode 100644 common/templates/404.html create mode 100644 common/templates/500.html diff --git a/boofilsic/urls.py b/boofilsic/urls.py index 32364a9c..4add5367 100644 --- a/boofilsic/urls.py +++ b/boofilsic/urls.py @@ -39,3 +39,8 @@ if settings.DEBUG: from django.conf.urls.static import static urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) + +handler400 = "common.views.error_400" +handler403 = "common.views.error_403" +handler404 = "common.views.error_404" +handler500 = "common.views.error_500" diff --git a/catalog/search/views.py b/catalog/search/views.py index 273ce7bb..2b841b9a 100644 --- a/catalog/search/views.py +++ b/catalog/search/views.py @@ -1,13 +1,10 @@ import uuid import logging -from django.shortcuts import render, get_object_or_404, redirect -from django.contrib.auth.decorators import login_required, permission_required +from django.core.exceptions import BadRequest +from django.shortcuts import render, redirect +from django.contrib.auth.decorators import login_required from django.utils.translation import gettext_lazy as _ -from django.http import ( - HttpResponseBadRequest, - HttpResponseRedirect, -) -from django.contrib.auth.decorators import login_required, permission_required +from django.http import HttpResponseRedirect from catalog.common.models import SiteName from catalog.common.sites import AbstractSite, SiteManager from ..models import * @@ -59,7 +56,7 @@ def fetch(request, url, is_refetch: bool = False, site: AbstractSite = None): if not site: site = SiteManager.get_site_by_url(url) if not site: - return HttpResponseBadRequest() + raise BadRequest() item = site.get_item() if item and not is_refetch: return redirect(item.url) @@ -169,10 +166,10 @@ def external_search(request): @login_required def refetch(request): if request.method != "POST": - return HttpResponseBadRequest() + raise BadRequest() url = request.POST.get("url") if not url: - return HttpResponseBadRequest() + raise BadRequest() return fetch(request, url, True) diff --git a/catalog/views.py b/catalog/views.py index 0a7914ad..996281c0 100644 --- a/catalog/views.py +++ b/catalog/views.py @@ -2,12 +2,8 @@ import logging from django.shortcuts import render, get_object_or_404, redirect from django.contrib.auth.decorators import login_required, permission_required from django.utils.translation import gettext_lazy as _ -from django.http import ( - HttpResponseBadRequest, - HttpResponseRedirect, - HttpResponseNotFound, -) -from django.core.exceptions import ObjectDoesNotExist, PermissionDenied +from django.http import HttpResponseRedirect +from django.core.exceptions import BadRequest, PermissionDenied from django.db.models import Count from django.utils import timezone from django.core.paginator import Paginator @@ -25,7 +21,7 @@ from common.config import PAGE_LINK_NUMBER from journal.models import ShelfTypeNames from .forms import * from .search.views import * -from pprint import pprint +from django.http import Http404 _logger = logging.getLogger(__name__) @@ -44,7 +40,7 @@ def retrieve(request, item_path, item_uuid): # item = get_object_or_404(Item, uid=base62.decode(item_uuid)) item = Item.get_by_url(item_uuid) if item is None: - return HttpResponseNotFound() + raise Http404() item_url = f"/{item_path}/{item_uuid}" if item.url != item_url: return redirect(item.url) @@ -52,7 +48,7 @@ def retrieve(request, item_path, item_uuid): if not skipcheck and item.merged_to_item: return redirect(item.merged_to_item.url) if not skipcheck and item.is_deleted: - return HttpResponseNotFound("item not found") + raise Http404() focus_item = None if request.GET.get("focus"): focus_item = get_object_or_404( @@ -105,7 +101,7 @@ def retrieve(request, item_path, item_uuid): }, ) else: - return HttpResponseBadRequest() + raise BadRequest() @login_required @@ -129,9 +125,9 @@ def create(request, item_model): form.instance.save() return redirect(form.instance.url) else: - return HttpResponseBadRequest(form.errors) + raise BadRequest() else: - return HttpResponseBadRequest() + raise BadRequest() @login_required @@ -157,15 +153,15 @@ def edit(request, item_path, item_uuid): form.instance.save() return redirect(form.instance.url) else: - return HttpResponseBadRequest(form.errors) + raise BadRequest() else: - return HttpResponseBadRequest() + raise BadRequest() @login_required def delete(request, item_path, item_uuid): if request.method != "POST": - return HttpResponseBadRequest() + raise BadRequest() if not request.user.is_staff: raise PermissionDenied() item = get_object_or_404(Item, uid=base62.decode(item_uuid)) @@ -181,12 +177,12 @@ def delete(request, item_path, item_uuid): @login_required def recast(request, item_path, item_uuid): if request.method != "POST": - return HttpResponseBadRequest() + raise BadRequest() item = get_object_or_404(Item, uid=base62.decode(item_uuid)) cls = request.POST.get("class") model = TVShow if cls == "tvshow" else (Movie if cls == "movie" else None) if not model: - return HttpResponseBadRequest("invalid class") + raise BadRequest() new_item = item.recast_to(model) return redirect(new_item.url) @@ -194,12 +190,12 @@ def recast(request, item_path, item_uuid): @login_required def unlink(request): if request.method != "POST": - return HttpResponseBadRequest() + raise BadRequest() if not request.user.is_staff: raise PermissionDenied() res_id = request.POST.get("id") if not res_id: - return HttpResponseBadRequest() + raise BadRequest() resource = get_object_or_404(ExternalResource, id=res_id) resource.item = None resource.save() @@ -209,13 +205,13 @@ def unlink(request): @login_required def merge(request, item_path, item_uuid): if request.method != "POST": - return HttpResponseBadRequest() + raise BadRequest() if not request.user.is_staff: raise PermissionDenied() item = get_object_or_404(Item, uid=base62.decode(item_uuid)) new_item = Item.get_by_url(request.POST.get("new_item_url")) if not new_item or new_item.is_deleted or new_item.merged_to_item_id: - return HttpResponseBadRequest(b"invalid new item") + raise BadRequest() _logger.warn(f"{request.user} merges {item} to {new_item}") item.merge_to(new_item) update_journal_for_merged_item(item_uuid) @@ -236,7 +232,7 @@ def episode_data(request, item_uuid): def mark_list(request, item_path, item_uuid, following_only=False): item = get_object_or_404(Item, uid=base62.decode(item_uuid)) if not item: - return HttpResponseNotFound(b"item not found") + raise Http404() queryset = ShelfMember.objects.filter(item=item).order_by("-created_time") if following_only: queryset = queryset.filter(query_following(request.user)) @@ -261,7 +257,7 @@ def mark_list(request, item_path, item_uuid, following_only=False): def review_list(request, item_path, item_uuid): item = get_object_or_404(Item, uid=base62.decode(item_uuid)) if not item: - return HttpResponseNotFound(b"item not found") + raise Http404() queryset = Review.objects.filter(item=item).order_by("-created_time") queryset = queryset.filter(query_visible(request.user)) paginator = Paginator(queryset, NUM_REVIEWS_ON_LIST_PAGE) diff --git a/common/templates/400.html b/common/templates/400.html new file mode 100644 index 00000000..f4913675 --- /dev/null +++ b/common/templates/400.html @@ -0,0 +1,39 @@ +{% load static %} +{% load i18n %} +{% load l10n %} +{% load admin_url %} +{% load mastodon %} +{% load oauth_token %} +{% load truncate %} +{% load thumb %} + + + + + + + {{ site_name }} - {% trans '无效请求' %} + {% include "common_libs.html" with jquery=0 %} + + + + +
+
+ {% include "partial/_navbar.html" %} +
+ + + +
+ 无效的请求 +
+
+ 您可能提交了无效的数据,或者相关内容已被作者删除。如果您确信这是我们的错误,欢迎通过页面底部的链接联系。 +
+
+
+ {% include "partial/_footer.html" %} +
+ + diff --git a/common/templates/403.html b/common/templates/403.html new file mode 100644 index 00000000..7a18a32b --- /dev/null +++ b/common/templates/403.html @@ -0,0 +1,39 @@ +{% load static %} +{% load i18n %} +{% load l10n %} +{% load admin_url %} +{% load mastodon %} +{% load oauth_token %} +{% load truncate %} +{% load thumb %} + + + + + + + {{ site_name }} - {% trans '权限不符' %} + {% include "common_libs.html" with jquery=0 %} + + + + +
+
+ {% include "partial/_navbar.html" %} +
+ + + +
+ 权限不符 +
+
+ 您可能访问了错误的网址,或者相关内容已被作者隐藏。如果您确信这是我们的错误,欢迎通过页面底部的链接联系。 +
+
+
+ {% include "partial/_footer.html" %} +
+ + diff --git a/common/templates/404.html b/common/templates/404.html new file mode 100644 index 00000000..46d3ea92 --- /dev/null +++ b/common/templates/404.html @@ -0,0 +1,39 @@ +{% load static %} +{% load i18n %} +{% load l10n %} +{% load admin_url %} +{% load mastodon %} +{% load oauth_token %} +{% load truncate %} +{% load thumb %} + + + + + + + {{ site_name }} - {% trans '未找到' %} + {% include "common_libs.html" with jquery=0 %} + + + + +
+
+ {% include "partial/_navbar.html" %} +
+ + + +
+ 请求条目未找到 +
+
+ 您可能输入了一个无效的网址,或者相关内容已被作者删除。如果您确信这是我们的错误,欢迎通过页面底部的链接联系。 +
+
+
+ {% include "partial/_footer.html" %} +
+ + diff --git a/common/templates/500.html b/common/templates/500.html new file mode 100644 index 00000000..7213d7de --- /dev/null +++ b/common/templates/500.html @@ -0,0 +1,39 @@ +{% load static %} +{% load i18n %} +{% load l10n %} +{% load admin_url %} +{% load mastodon %} +{% load oauth_token %} +{% load truncate %} +{% load thumb %} + + + + + + + {{ site_name }} - {% trans '系统错误' %} + {% include "common_libs.html" with jquery=0 %} + + + + +
+
+ {% include "partial/_navbar.html" %} +
+ + + +
+ 系统内部错误 +
+
+ 发生了一个内部错误,如果这个错误多次出现,后台会记录并会由人工处理。如果您有紧急情况或疑问,欢迎通过页面底部的链接联系。 +
+
+
+ {% include "partial/_footer.html" %} +
+ + diff --git a/common/views.py b/common/views.py index 41e92de3..d0ce83b4 100644 --- a/common/views.py +++ b/common/views.py @@ -1,4 +1,4 @@ -from django.shortcuts import redirect +from django.shortcuts import redirect, render from django.urls import reverse from django.contrib.auth.decorators import login_required @@ -11,3 +11,19 @@ def home(request): ) else: return redirect(reverse("social:feed")) + + +def error_400(request, exception=None): + return render(request, "400.html", status=400) + + +def error_403(request, exception=None): + return render(request, "403.html", status=403) + + +def error_404(request, exception=None): + return render(request, "404.html", status=404) + + +def error_500(request, exception=None): + return render(request, "500.html", status=500) diff --git a/journal/views.py b/journal/views.py index b65917b2..78a19b74 100644 --- a/journal/views.py +++ b/journal/views.py @@ -1,14 +1,9 @@ import logging -from os import stat from django.shortcuts import render, get_object_or_404, redirect from django.urls import reverse -from django.contrib.auth.decorators import login_required, permission_required +from django.contrib.auth.decorators import login_required from django.utils.translation import gettext_lazy as _ -from django.http import ( - HttpResponse, - HttpResponseBadRequest, - HttpResponseNotFound, -) +from django.http import Http404, HttpResponse from django.core.exceptions import BadRequest, ObjectDoesNotExist, PermissionDenied from django.db.models import Count from django.utils import timezone @@ -17,7 +12,6 @@ from django.core.paginator import Paginator from .models import * from django.conf import settings from django.http import HttpResponseRedirect -from django.db.models import Q from management.models import Announcement from django.utils.baseconv import base62 from .forms import * @@ -44,10 +38,10 @@ _checkmark = "✔️".encode("utf-8") @login_required def wish(request, item_uuid): if request.method != "POST": - return HttpResponseBadRequest(b"invalid request") + raise BadRequest() item = get_object_or_404(Item, uid=base62.decode(item_uuid)) if not item: - return HttpResponseNotFound(b"item not found") + raise Http404() request.user.shelf_manager.move_item(item, ShelfType.WISHLIST) if request.GET.get("back"): return HttpResponseRedirect(request.META.get("HTTP_REFERER")) @@ -57,10 +51,10 @@ def wish(request, item_uuid): @login_required def like(request, piece_uuid): if request.method != "POST": - return HttpResponseBadRequest(b"invalid request") + raise BadRequest() piece = get_object_or_404(Collection, uid=base62.decode(piece_uuid)) if not piece: - return HttpResponseNotFound(b"piece not found") + raise Http404() Like.user_like_piece(request.user, piece) if request.GET.get("back"): return HttpResponseRedirect(request.META.get("HTTP_REFERER")) @@ -70,10 +64,10 @@ def like(request, piece_uuid): @login_required def unlike(request, piece_uuid): if request.method != "POST": - return HttpResponseBadRequest(b"invalid request") + raise BadRequest() piece = get_object_or_404(Collection, uid=base62.decode(piece_uuid)) if not piece: - return HttpResponseNotFound(b"piece not found") + raise Http404() Like.user_unlike_piece(request.user, piece) if request.GET.get("back"): return HttpResponseRedirect(request.META.get("HTTP_REFERER")) @@ -176,7 +170,7 @@ def mark(request, item_uuid): _logger.warn(f"post to mastodon error {e}") return render_relogin(request) return HttpResponseRedirect(request.META.get("HTTP_REFERER")) - return HttpResponseBadRequest() + raise BadRequest() @login_required @@ -184,7 +178,7 @@ def comment(request, item_uuid, focus_item_uuid): item = get_object_or_404(Item, uid=base62.decode(item_uuid)) focus_item = get_object_or_404(Item, uid=base62.decode(focus_item_uuid)) if focus_item.parent_item != item: - return HttpResponseNotFound() + raise Http404() comment = Comment.objects.filter( owner=request.user, item=item, focus_item=focus_item ).first() @@ -201,7 +195,7 @@ def comment(request, item_uuid, focus_item_uuid): elif request.method == "POST": if request.POST.get("delete", default=False): if not comment: - return HttpResponseNotFound() + raise Http404() comment.delete() return HttpResponseRedirect(request.META.get("HTTP_REFERER")) visibility = int(request.POST.get("visibility", default=0)) @@ -264,7 +258,7 @@ def comment(request, item_uuid, focus_item_uuid): if post_error: return render_relogin(request) return HttpResponseRedirect(request.META.get("HTTP_REFERER")) - return HttpResponseBadRequest() + raise BadRequest() def collection_retrieve(request, collection_uuid): @@ -314,7 +308,7 @@ def collection_retrieve(request, collection_uuid): def collection_add_featured(request, collection_uuid): if request.method != "POST": - return HttpResponseBadRequest() + raise BadRequest() collection = get_object_or_404(Collection, uid=base62.decode(collection_uuid)) if not collection.is_visible_to(request.user): raise PermissionDenied() @@ -324,7 +318,7 @@ def collection_add_featured(request, collection_uuid): def collection_remove_featured(request, collection_uuid): if request.method != "POST": - return HttpResponseBadRequest() + raise BadRequest() collection = get_object_or_404(Collection, uid=base62.decode(collection_uuid)) if not collection.is_visible_to(request.user): raise PermissionDenied() @@ -354,7 +348,7 @@ def collection_share(request, collection_uuid): else: return render_relogin(request) else: - return HttpResponseBadRequest() + raise BadRequest() def collection_retrieve_items(request, collection_uuid, edit=False, msg=None): @@ -377,7 +371,7 @@ def collection_retrieve_items(request, collection_uuid, edit=False, msg=None): @login_required def collection_append_item(request, collection_uuid): if request.method != "POST": - return HttpResponseBadRequest() + raise BadRequest() collection = get_object_or_404(Collection, uid=base62.decode(collection_uuid)) if not collection.is_editable_by(request.user): raise PermissionDenied() @@ -397,7 +391,7 @@ def collection_append_item(request, collection_uuid): @login_required def collection_remove_item(request, collection_uuid, item_uuid): if request.method != "POST": - return HttpResponseBadRequest() + raise BadRequest() collection = get_object_or_404(Collection, uid=base62.decode(collection_uuid)) item = get_object_or_404(Item, uid=base62.decode(item_uuid)) if not collection.is_editable_by(request.user): @@ -409,7 +403,7 @@ def collection_remove_item(request, collection_uuid, item_uuid): @login_required def collection_move_item(request, direction, collection_uuid, item_uuid): if request.method != "POST": - return HttpResponseBadRequest() + raise BadRequest() collection = get_object_or_404(Collection, uid=base62.decode(collection_uuid)) if not collection.is_editable_by(request.user): raise PermissionDenied() @@ -442,7 +436,7 @@ def collection_update_item_note(request, collection_uuid, item_uuid): {"collection": collection, "item": item, "note": member.note}, ) else: - return HttpResponseBadRequest() + raise BadRequest() @login_required @@ -474,16 +468,16 @@ def collection_edit(request, collection_uuid=None): reverse("journal:collection_retrieve", args=[form.instance.uuid]) ) else: - return HttpResponseBadRequest(form.errors) + raise BadRequest() else: - return HttpResponseBadRequest() + raise BadRequest() def review_retrieve(request, review_uuid): # piece = get_object_or_404(Review, uid=base62.decode(review_uuid)) piece = Review.get_by_url(review_uuid) if piece is None: - return HttpResponseNotFound() + raise Http404() if not piece.is_visible_to(request.user): raise PermissionDenied() return render(request, "review.html", {"review": piece}) @@ -550,9 +544,9 @@ def review_edit(request, item_uuid, review_uuid=None): reverse("journal:review_retrieve", args=[form.instance.uuid]) ) else: - return HttpResponseBadRequest(form.errors) + raise BadRequest() else: - return HttpResponseBadRequest() + raise BadRequest() @login_required @@ -569,7 +563,7 @@ def piece_delete(request, piece_uuid): piece.delete() return redirect(return_url) else: - return HttpResponseBadRequest() + raise BadRequest() def render_list_not_fount(request): @@ -607,7 +601,7 @@ def _render_list( queryset = Review.objects.filter(owner=user) queryset = queryset.filter(query_item_category(item_category)) else: - return HttpResponseBadRequest() + raise BadRequest() queryset = queryset.filter(q_visible_to(request.user, user)).order_by( "-created_time" ) @@ -639,10 +633,10 @@ def user_tag_edit(request): if request.method == "GET": tag_title = Tag.cleanup_title(request.GET.get("tag", "")) if not tag_title: - return HttpResponseNotFound() + raise Http404() tag = Tag.objects.filter(owner=request.user, title=tag_title).first() if not tag: - return HttpResponseNotFound() + raise Http404() return render(request, "tag_edit.html", {"tag": tag}) elif request.method == "POST": tag_title = Tag.cleanup_title(request.POST.get("title", "")) @@ -678,7 +672,7 @@ def user_tag_edit(request): args=[request.user.mastodon_username, tag.title], ) ) - return HttpResponseBadRequest() + raise BadRequest() @login_required @@ -776,7 +770,7 @@ def profile_anonymous(request, id): def profile(request, user_name): if request.method != "GET": - return HttpResponseBadRequest() + raise BadRequest() user = User.get(user_name) if user is None: return render_user_not_found(request) diff --git a/users/account.py b/users/account.py index 81f93b38..a53b5a3c 100644 --- a/users/account.py +++ b/users/account.py @@ -1,19 +1,16 @@ from django.shortcuts import reverse, redirect, render, get_object_or_404 -from django.http import HttpResponseBadRequest, HttpResponse from django.contrib.auth.decorators import login_required from django.contrib import auth from django.contrib.auth import authenticate from django.core.paginator import Paginator from django.utils.translation import gettext_lazy as _ -from django.core.exceptions import ObjectDoesNotExist +from django.core.exceptions import ObjectDoesNotExist, BadRequest from django.db.models import Count from .models import User, Report, Preference from .forms import ReportForm from mastodon.api import * from mastodon import mastodon_request_included from common.config import * -from common.utils import PageLinksGenerator -from management.models import Announcement from mastodon.models import MastodonApplication from mastodon.api import verify_account from django.conf import settings @@ -23,7 +20,6 @@ from .account import * from .tasks import * from datetime import timedelta from django.utils import timezone -import json from django.contrib import messages from journal.models import remove_data_by_user @@ -50,7 +46,7 @@ def login(request): }, ) else: - return HttpResponseBadRequest() + raise BadRequest() # connect will redirect to mastodon server @@ -94,7 +90,7 @@ def connect(request): @mastodon_request_included def OAuth2_login(request): if request.method != "GET": - return HttpResponseBadRequest() + raise BadRequest() code = request.GET.get("code") if not code: @@ -113,7 +109,7 @@ def OAuth2_login(request): try: token, refresh_token = obtain_token(site, request, code) except ObjectDoesNotExist: - return HttpResponseBadRequest("Mastodon site not registered") + raise BadRequest() if not token: return render( request, @@ -165,7 +161,7 @@ def logout(request): auth_logout(request) return redirect(reverse("users:login")) else: - return HttpResponseBadRequest() + raise BadRequest() @mastodon_request_included @@ -176,7 +172,7 @@ def reconnect(request): request.session["swap_domain"] = request.POST["domain"] return connect(request) else: - return HttpResponseBadRequest() + raise BadRequest() @mastodon_request_included diff --git a/users/views.py b/users/views.py index ab6d8c3c..b0374f75 100644 --- a/users/views.py +++ b/users/views.py @@ -1,16 +1,15 @@ from django.shortcuts import redirect, render, get_object_or_404 from django.urls import reverse -from django.http import HttpResponseBadRequest from django.contrib.auth.decorators import login_required from django.utils.translation import gettext_lazy as _ from .models import User, Report, Preference from .forms import ReportForm from mastodon.api import * -from mastodon import mastodon_request_included from common.config import * from .account import * from .data import * import json +from django.core.exceptions import BadRequest def render_user_not_found(request): @@ -52,7 +51,7 @@ def followers(request, id): }, ) else: - return HttpResponseBadRequest() + raise BadRequest() @login_required @@ -70,7 +69,7 @@ def following(request, id): }, ) else: - return HttpResponseBadRequest() + raise BadRequest() @login_required @@ -83,7 +82,7 @@ def set_layout(request): reverse("journal:user_profile", args=[request.user.mastodon_username]) ) else: - return HttpResponseBadRequest() + raise BadRequest() @login_required @@ -123,7 +122,7 @@ def report(request): }, ) else: - return HttpResponseBadRequest() + raise BadRequest() @login_required @@ -141,4 +140,4 @@ def manage_report(request): }, ) else: - return HttpResponseBadRequest() + raise BadRequest()