diff --git a/catalog/search/views.py b/catalog/search/views.py
index f9f12e45..0f5e234f 100644
--- a/catalog/search/views.py
+++ b/catalog/search/views.py
@@ -1,4 +1,3 @@
-import logging
import re
import django_rq
@@ -8,11 +7,11 @@ from django.core.cache import cache
from django.core.exceptions import BadRequest
from django.shortcuts import redirect, render
from django.utils.translation import gettext_lazy as _
+from django.views.decorators.http import require_http_methods
from rq.job import Job
from catalog.common.models import ItemCategory, SiteName
from catalog.common.sites import AbstractSite, SiteManager
-from common.config import PAGE_LINK_NUMBER
from common.utils import (
HTTPResponseHXRedirect,
PageLinksGenerator,
@@ -52,7 +51,7 @@ def fetch(request, url, is_refetch: bool = False, site: AbstractSite | None = No
if not site:
site = SiteManager.get_site_by_url(url)
if not site:
- raise BadRequest()
+ raise BadRequest(_("Invalid URL"))
item = site.get_item()
if item and not is_refetch:
return redirect(item.url)
@@ -172,10 +171,9 @@ def external_search(request):
@login_required
+@require_http_methods(["POST"])
def refetch(request):
- if request.method != "POST":
- raise BadRequest()
url = request.POST.get("url")
if not url:
- raise BadRequest()
+ raise BadRequest(_("Invalid URL"))
return fetch(request, url, True)
diff --git a/catalog/views.py b/catalog/views.py
index 1eccf246..b808cd35 100644
--- a/catalog/views.py
+++ b/catalog/views.py
@@ -50,11 +50,11 @@ def retrieve_redirect(request, item_path, item_uuid):
def embed(request, item_path, item_uuid):
item = Item.get_by_url(item_uuid)
if item is None:
- raise Http404()
+ raise Http404(_("Item not found"))
if item.merged_to_item:
return redirect(item.merged_to_item.url)
if item.is_deleted:
- raise Http404()
+ raise Http404(_("Item no longer exists"))
focus_item = None
if request.GET.get("focus"):
focus_item = get_object_or_404(
@@ -73,7 +73,7 @@ def retrieve(request, item_path, item_uuid):
# item = get_object_or_404(Item, uid=get_uuid_or_404(item_uuid))
item = Item.get_by_url(item_uuid)
if item is None:
- raise Http404()
+ raise Http404(_("Item not found"))
item_url = f"/{item_path}/{item_uuid}"
if item.url != item_url:
return redirect(item.url)
@@ -81,7 +81,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:
- raise Http404()
+ raise Http404(_("Item no longer exists"))
if request.headers.get("Accept", "").endswith("json"):
return redirect(item.api_url)
focus_item = None
@@ -146,8 +146,6 @@ def episode_data(request, item_uuid):
@login_required
def mark_list(request, item_path, item_uuid, following_only=False):
item = get_object_or_404(Item, uid=get_uuid_or_404(item_uuid))
- if not item:
- raise Http404()
queryset = ShelfMember.objects.filter(item=item).order_by("-created_time")
if following_only:
queryset = queryset.filter(q_piece_in_home_feed_of_user(request.user))
@@ -171,8 +169,6 @@ 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=get_uuid_or_404(item_uuid))
- if not item:
- raise Http404()
queryset = Review.objects.filter(item=item).order_by("-created_time")
queryset = queryset.filter(q_piece_visible_to_user(request.user))
paginator = Paginator(queryset, NUM_REVIEWS_ON_LIST_PAGE)
@@ -192,8 +188,6 @@ def review_list(request, item_path, item_uuid):
def comments(request, item_path, item_uuid):
item = get_object_or_404(Item, uid=get_uuid_or_404(item_uuid))
- if not item:
- raise Http404()
ids = item.child_item_ids + [item.id] + item.sibling_item_ids
queryset = Comment.objects.filter(item_id__in=ids).order_by("-created_time")
queryset = queryset.filter(q_piece_visible_to_user(request.user))
@@ -212,8 +206,6 @@ def comments(request, item_path, item_uuid):
def comments_by_episode(request, item_path, item_uuid):
item = get_object_or_404(Item, uid=get_uuid_or_404(item_uuid))
- if not item:
- raise Http404()
episode_uuid = request.GET.get("episode_uuid")
if episode_uuid:
episode = TVEpisode.get_by_url(episode_uuid)
@@ -238,8 +230,6 @@ def comments_by_episode(request, item_path, item_uuid):
def reviews(request, item_path, item_uuid):
item = get_object_or_404(Item, uid=get_uuid_or_404(item_uuid))
- if not item:
- raise Http404()
ids = item.child_item_ids + [item.id] + item.sibling_item_ids
queryset = Review.objects.filter(item_id__in=ids).order_by("-created_time")
queryset = queryset.filter(q_piece_visible_to_user(request.user))
diff --git a/catalog/views_edit.py b/catalog/views_edit.py
index 01986030..fc99ba90 100644
--- a/catalog/views_edit.py
+++ b/catalog/views_edit.py
@@ -97,7 +97,7 @@ def edit(request, item_path, item_uuid):
form.fields["primary_lookup_id_type"].disabled = True
form.fields["primary_lookup_id_value"].disabled = True
return render(request, "catalog_edit.html", {"form": form, "item": item})
- elif request.method == "POST":
+ else:
item = get_object_or_404(Item, uid=get_uuid_or_404(item_uuid))
form_cls = CatalogForms[item.__class__.__name__]
form = form_cls(request.POST, request.FILES, instance=item)
@@ -115,8 +115,6 @@ def edit(request, item_path, item_uuid):
return redirect(form.instance.url)
else:
raise BadRequest(_add_error_map_detail(form.errors))
- else:
- raise BadRequest()
@require_http_methods(["POST"])
@@ -124,7 +122,7 @@ def edit(request, item_path, item_uuid):
def delete(request, item_path, item_uuid):
item = get_object_or_404(Item, uid=get_uuid_or_404(item_uuid))
if not request.user.is_staff and item.journal_exists():
- raise PermissionDenied()
+ raise PermissionDenied(_("Insufficient permission"))
if request.POST.get("sure", 0) != "1":
return render(request, "catalog_delete.html", {"item": item})
else:
@@ -147,7 +145,7 @@ def delete(request, item_path, item_uuid):
def undelete(request, item_path, item_uuid):
item = get_object_or_404(Item, uid=get_uuid_or_404(item_uuid))
if not request.user.is_staff:
- raise PermissionDenied()
+ raise PermissionDenied(_("Insufficient permission"))
item.is_deleted = False
item.save()
return redirect(item.url)
@@ -199,10 +197,10 @@ def recast(request, item_path, item_uuid):
@login_required
def unlink(request):
if not request.user.is_staff:
- raise PermissionDenied()
+ raise PermissionDenied(_("Insufficient permission"))
res_id = request.POST.get("id")
if not res_id:
- raise BadRequest()
+ raise BadRequest(_("Invalid parameter"))
resource = get_object_or_404(ExternalResource, id=res_id)
resource.unlink_from_item()
return HttpResponseRedirect(request.META.get("HTTP_REFERER"))
@@ -251,7 +249,7 @@ def remove_unused_seasons(request, item_path, item_uuid):
def fetch_tvepisodes(request, item_path, item_uuid):
item = get_object_or_404(Item, uid=get_uuid_or_404(item_uuid))
if item.class_name != "tvseason" or not item.imdb or item.season_number is None:
- raise BadRequest()
+ raise BadRequest(_("Must be a TV Season with IMDB id and season id"))
item.log_action({"!fetch_tvepisodes": ["", ""]})
django_rq.get_queue("crawl").enqueue(
fetch_episodes_for_season_task, item.uuid, request.user
@@ -275,7 +273,7 @@ def fetch_episodes_for_season_task(item_uuid, user):
def merge(request, item_path, item_uuid):
item = get_object_or_404(Item, uid=get_uuid_or_404(item_uuid))
if not request.user.is_staff and item.journal_exists():
- raise PermissionDenied()
+ raise PermissionDenied(_("Insufficient permission"))
if request.POST.get("sure", 0) != "1":
new_item = Item.get_by_url(request.POST.get("target_item_url"))
return render(
@@ -352,7 +350,7 @@ def link_edition(request, item_path, item_uuid):
def unlink_works(request, item_path, item_uuid):
item = get_object_or_404(Item, uid=get_uuid_or_404(item_uuid))
if not request.user.is_staff and item.journal_exists():
- raise PermissionDenied()
+ raise PermissionDenied(_("Insufficient permission"))
item.unlink_from_all_works()
discord_send(
"audit",
diff --git a/common/templates/400.html b/common/templates/400.html
index cb3d9bf2..553ac962 100644
--- a/common/templates/400.html
+++ b/common/templates/400.html
@@ -8,7 +8,7 @@
- {{ site_name }} - {% trans '无效请求' %}
+ {{ site_name }} - 400
{% include "common_libs.html" %}
@@ -17,11 +17,12 @@
- 🤷🏻 无效的请求
+ 🤷🏻 {{ exception }}
- 您可能提交了无效的数据,或者相关内容已被作者删除。如果您确信这是我们的错误,请通过页面底部的链接联系我们。
+ {% blocktrans %}You may have submitted invalid data, or the content may have been deleted by the author.{% endblocktrans %}
+
+ {% blocktrans %}If you believe this is our mistake, please contact us through the link at the bottom of the page.{% endblocktrans %}
- {{ exception }}
{% if exception.additonal_detail %}
{% for e in exception.additonal_detail %}{{ e }}
{% endfor %}
{% endif %}
diff --git a/common/templates/403.html b/common/templates/403.html
index 20bb116f..fadf9ca1 100644
--- a/common/templates/403.html
+++ b/common/templates/403.html
@@ -4,11 +4,11 @@
{% load mastodon %}
{% load thumb %}
-
+
- {{ site_name }} - {% trans '权限不符' %}
+ {{ site_name }} - 403
{% include "common_libs.html" %}
@@ -17,10 +17,11 @@
- 🙅🏻 权限不符
+ 🙅🏻 {{ exception|default:"" }}
- {{ exception }}
- 您可能访问了错误的网址,或者相关内容已被作者删除。如果您确信这是我们的错误,请通过页面底部的链接联系我们。
+ {% blocktrans %}Author may require you to log in before accessing this content, or you do not have permission to view it.{% endblocktrans %}
+
+ {% blocktrans %}If you believe this is our mistake, please contact us through the link at the bottom of the page.{% endblocktrans %}
{% include "_footer.html" %}
diff --git a/common/templates/404.html b/common/templates/404.html
index 49fb9ce8..18ce0d40 100644
--- a/common/templates/404.html
+++ b/common/templates/404.html
@@ -4,11 +4,11 @@
{% load mastodon %}
{% load thumb %}
-
+
- {{ site_name }} - {% trans '未找到' %}
+ {{ site_name }} - 404
{% include "common_libs.html" %}
@@ -17,9 +17,11 @@
- 🤷🏻 条目未找到
+ 🤷🏻 {{ exception|default:"" }}
- 您可能输入了一个无效的网址,或者相关内容已被作者删除。如果您确信这是我们的错误,请通过页面底部的链接联系我们。
+ {% blocktrans %}You may have visited an incorrect URL, or the content you are looking for has been deleted by the author.{% endblocktrans %}
+
+ {% blocktrans %}If you believe this is our mistake, please contact us through the link at the bottom of the page.{% endblocktrans %}
{% include "_footer.html" %}
diff --git a/common/templates/500.html b/common/templates/500.html
index 5ba080d7..66e25c8c 100644
--- a/common/templates/500.html
+++ b/common/templates/500.html
@@ -4,11 +4,11 @@
{% load mastodon %}
{% load thumb %}
-
+
- {{ site_name }} - {% trans '系统错误' %}
+ {{ site_name }} - 500
{% include "common_libs.html" %}
@@ -17,9 +17,11 @@
- 发生了一个内部错误,如果这个错误多次出现,后台会记录并会由人工处理。如果您有紧急情况或任何疑问,请通过页面底部的链接联系我们。
+ {% blocktrans %}An internal error occurred. If this error occurs repeatedly, it will be recorded and handled by a human.{% endblocktrans %}
+
+ {% blocktrans %}If you have an urgent situation or any questions, please contact us through the link at the bottom of the page.{% endblocktrans %}
{% include "_footer.html" %}
diff --git a/common/utils.py b/common/utils.py
index 3e1485d9..1b25963e 100644
--- a/common/utils.py
+++ b/common/utils.py
@@ -4,9 +4,11 @@ from typing import TYPE_CHECKING
from discord import SyncWebhook
from django.conf import settings
+from django.core.exceptions import PermissionDenied
from django.http import Http404, HttpRequest, HttpResponseRedirect, QueryDict
from django.utils import timezone
from django.utils.baseconv import base62
+from django.utils.translation import gettext_lazy as _
from .config import PAGE_LINK_NUMBER
@@ -52,16 +54,15 @@ def target_identity_required(func):
@functools.wraps(func)
def wrapper(request, user_name, *args, **kwargs):
from users.models import APIdentity
- from users.views import render_user_blocked, render_user_not_found
try:
target = APIdentity.get_by_handle(user_name)
except APIdentity.DoesNotExist:
- return render_user_not_found(request)
+ raise Http404(_("User not found"))
target_user = target.user
viewer = None
if target_user and not target_user.is_active:
- return render_user_not_found(request)
+ raise Http404(_("User no longer exists"))
if request.user.is_authenticated:
try:
viewer = APIdentity.objects.get(user=request.user)
@@ -69,7 +70,7 @@ def target_identity_required(func):
return HttpResponseRedirect("/account/register")
if request.user != target_user:
if target.is_blocking(viewer) or target.is_blocked_by(viewer):
- return render_user_blocked(request)
+ raise PermissionDenied(_("Access denied"))
else:
viewer = None
request.target_identity = target
@@ -83,16 +84,15 @@ def profile_identity_required(func):
@functools.wraps(func)
def wrapper(request, user_name, *args, **kwargs):
from users.models import APIdentity
- from users.views import render_user_blocked, render_user_not_found
try:
target = APIdentity.get_by_handle(user_name, match_linked=True)
except APIdentity.DoesNotExist:
- return render_user_not_found(request)
+ raise Http404(_("User not found"))
target_user = target.user
viewer = None
if target_user and not target_user.is_active:
- return render_user_not_found(request)
+ raise Http404(_("User no longer exists"))
if request.user.is_authenticated:
try:
viewer = APIdentity.objects.get(user=request.user)
@@ -100,7 +100,7 @@ def profile_identity_required(func):
return HttpResponseRedirect("/account/register")
if request.user != target_user:
if target.is_blocking(viewer) or target.is_blocked_by(viewer):
- return render_user_blocked(request)
+ raise PermissionDenied(_("Access denied"))
else:
viewer = None
request.target_identity = target
diff --git a/common/views.py b/common/views.py
index da21b41e..60af379b 100644
--- a/common/views.py
+++ b/common/views.py
@@ -69,21 +69,16 @@ def nodeinfo2(request):
def error_400(request, exception=None):
- return render(
- request,
- "400.html",
- {"exception": exception},
- status=400,
- )
+ return render(request, "400.html", status=400, context={"exception": exception})
def error_403(request, exception=None):
- return render(request, "403.html", status=403)
+ return render(request, "403.html", status=403, context={"exception": exception})
def error_404(request, exception=None):
- return render(request, "404.html", status=404)
+ return render(request, "404.html", status=404, context={"exception": exception})
def error_500(request, exception=None):
- return render(request, "500.html", status=500)
+ return render(request, "500.html", status=500, context={"exception": exception})
diff --git a/journal/views/collection.py b/journal/views/collection.py
index 3f6ebdf5..d0e5261b 100644
--- a/journal/views/collection.py
+++ b/journal/views/collection.py
@@ -6,17 +6,11 @@ from django.shortcuts import get_object_or_404, redirect, render
from django.urls import reverse
from django.utils import timezone
from django.utils.translation import gettext_lazy as _
+from django.views.decorators.http import require_http_methods
from catalog.models import Item
from common.utils import AuthedHttpRequest, get_uuid_or_404
from mastodon.api import boost_toot_later, share_collection
-from users.models import User
-from users.models.apidentity import APIdentity
-from users.views import (
- render_user_blocked,
- render_user_noanonymous,
- render_user_not_found,
-)
from ..forms import *
from ..models import *
@@ -55,7 +49,7 @@ def collection_retrieve_redirect(request: AuthedHttpRequest, collection_uuid):
def collection_retrieve(request: AuthedHttpRequest, collection_uuid):
collection = get_object_or_404(Collection, uid=get_uuid_or_404(collection_uuid))
if not collection.is_visible_to(request.user):
- raise PermissionDenied()
+ raise PermissionDenied(_("Insufficient permission"))
follower_count = collection.likes.all().count()
following = (
Like.user_liked_piece(request.user.identity, collection)
@@ -101,12 +95,11 @@ def collection_retrieve(request: AuthedHttpRequest, collection_uuid):
@login_required
+@require_http_methods(["POST"])
def collection_add_featured(request: AuthedHttpRequest, collection_uuid):
- if request.method != "POST":
- raise BadRequest()
collection = get_object_or_404(Collection, uid=get_uuid_or_404(collection_uuid))
if not collection.is_visible_to(request.user):
- raise PermissionDenied()
+ raise PermissionDenied(_("Insufficient permission"))
FeaturedCollection.objects.update_or_create(
owner=request.user.identity, target=collection
)
@@ -114,12 +107,11 @@ def collection_add_featured(request: AuthedHttpRequest, collection_uuid):
@login_required
+@require_http_methods(["POST"])
def collection_remove_featured(request: AuthedHttpRequest, collection_uuid):
- if request.method != "POST":
- raise BadRequest()
collection = get_object_or_404(Collection, uid=get_uuid_or_404(collection_uuid))
if not collection.is_visible_to(request.user):
- raise PermissionDenied()
+ raise PermissionDenied(_("Insufficient permission"))
fc = FeaturedCollection.objects.filter(
owner=request.user.identity, target=collection
).first()
@@ -129,15 +121,16 @@ def collection_remove_featured(request: AuthedHttpRequest, collection_uuid):
@login_required
+@require_http_methods(["POST", "GET"])
def collection_share(request: AuthedHttpRequest, collection_uuid):
collection = get_object_or_404(
Collection, uid=get_uuid_or_404(collection_uuid) if collection_uuid else None
)
if collection and not collection.is_visible_to(request.user):
- raise PermissionDenied()
+ raise PermissionDenied(_("Insufficient permission"))
if request.method == "GET":
return render(request, "collection_share.html", {"collection": collection})
- elif request.method == "POST":
+ else:
comment = request.POST.get("comment")
# boost if possible, otherwise quote
if (
@@ -158,8 +151,6 @@ def collection_share(request: AuthedHttpRequest, collection_uuid):
):
return render_relogin(request)
return HttpResponseRedirect(request.META.get("HTTP_REFERER", "/"))
- else:
- raise BadRequest()
def collection_retrieve_items(
@@ -167,7 +158,7 @@ def collection_retrieve_items(
):
collection = get_object_or_404(Collection, uid=get_uuid_or_404(collection_uuid))
if not collection.is_visible_to(request.user):
- raise PermissionDenied()
+ raise PermissionDenied(_("Insufficient permission"))
form = CollectionForm(instance=collection)
return render(
request,
@@ -182,12 +173,11 @@ def collection_retrieve_items(
@login_required
+@require_http_methods(["POST"])
def collection_append_item(request: AuthedHttpRequest, collection_uuid):
- if request.method != "POST":
- raise BadRequest()
collection = get_object_or_404(Collection, uid=get_uuid_or_404(collection_uuid))
if not collection.is_editable_by(request.user):
- raise PermissionDenied()
+ raise PermissionDenied(_("Insufficient permission"))
url = request.POST.get("url")
note = request.POST.get("note")
@@ -202,26 +192,24 @@ def collection_append_item(request: AuthedHttpRequest, collection_uuid):
@login_required
+@require_http_methods(["POST"])
def collection_remove_item(request: AuthedHttpRequest, collection_uuid, item_uuid):
- if request.method != "POST":
- raise BadRequest()
collection = get_object_or_404(Collection, uid=get_uuid_or_404(collection_uuid))
item = get_object_or_404(Item, uid=get_uuid_or_404(item_uuid))
if not collection.is_editable_by(request.user):
- raise PermissionDenied()
+ raise PermissionDenied(_("Insufficient permission"))
collection.remove_item(item)
return collection_retrieve_items(request, collection_uuid, True)
@login_required
+@require_http_methods(["POST"])
def collection_move_item(
request: AuthedHttpRequest, direction, collection_uuid, item_uuid
):
- if request.method != "POST":
- raise BadRequest()
collection = get_object_or_404(Collection, uid=get_uuid_or_404(collection_uuid))
if not collection.is_editable_by(request.user):
- raise PermissionDenied()
+ raise PermissionDenied(_("Insufficient permission"))
item = get_object_or_404(Item, uid=get_uuid_or_404(item_uuid))
if direction == "up":
collection.move_up_item(item)
@@ -231,45 +219,44 @@ def collection_move_item(
@login_required
+@require_http_methods(["POST"])
def collection_update_member_order(request: AuthedHttpRequest, collection_uuid):
- if request.method != "POST":
- raise BadRequest()
collection = get_object_or_404(Collection, uid=get_uuid_or_404(collection_uuid))
if not collection.is_editable_by(request.user):
- raise PermissionDenied()
+ raise PermissionDenied(_("Insufficient permission"))
ids = request.POST.get("member_ids", "").strip()
if not ids:
- raise BadRequest()
+ raise BadRequest(_("Invalid parameter"))
ordered_member_ids = [int(i) for i in ids.split(",")]
collection.update_member_order(ordered_member_ids)
return collection_retrieve_items(request, collection_uuid, True)
@login_required
+@require_http_methods(["GET", "POST"])
def collection_update_item_note(request: AuthedHttpRequest, collection_uuid, item_uuid):
collection = get_object_or_404(Collection, uid=get_uuid_or_404(collection_uuid))
if not collection.is_editable_by(request.user):
- raise PermissionDenied()
+ raise PermissionDenied(_("Insufficient permission"))
item = get_object_or_404(Item, uid=get_uuid_or_404(item_uuid))
if not collection.is_editable_by(request.user):
- raise PermissionDenied()
+ raise PermissionDenied(_("Insufficient permission"))
if request.method == "POST":
collection.update_item_metadata(
item, {"note": request.POST.get("note", default="")}
)
return collection_retrieve_items(request, collection_uuid, True)
- elif request.method == "GET":
+ else:
member = collection.get_member_for_item(item)
return render(
request,
"collection_update_item_note.html",
{"collection": collection, "item": item, "note": member.note},
)
- else:
- raise BadRequest()
@login_required
+@require_http_methods(["GET", "POST"])
def collection_edit(request: AuthedHttpRequest, collection_uuid=None):
collection = (
get_object_or_404(Collection, uid=get_uuid_or_404(collection_uuid))
@@ -277,7 +264,7 @@ def collection_edit(request: AuthedHttpRequest, collection_uuid=None):
else None
)
if collection and not collection.is_editable_by(request.user):
- raise PermissionDenied()
+ raise PermissionDenied(_("Insufficient permission"))
if request.method == "GET":
form = CollectionForm(instance=collection) if collection else CollectionForm()
if request.GET.get("title"):
@@ -292,7 +279,7 @@ def collection_edit(request: AuthedHttpRequest, collection_uuid=None):
"identity": collection.owner if collection else request.user.identity,
},
)
- elif request.method == "POST":
+ else:
form = (
CollectionForm(request.POST, request.FILES, instance=collection)
if collection
@@ -306,16 +293,14 @@ def collection_edit(request: AuthedHttpRequest, collection_uuid=None):
reverse("journal:collection_retrieve", args=[form.instance.uuid])
)
else:
- raise BadRequest()
- else:
- raise BadRequest()
+ raise BadRequest(_("Invalid parameter"))
@target_identity_required
def user_collection_list(request: AuthedHttpRequest, user_name):
target = request.target_identity
if not request.user.is_authenticated and not target.anonymous_viewable:
- return render_user_noanonymous(request)
+ raise PermissionDenied(_("Login required"))
collections = (
Collection.objects.filter(owner=target)
.filter(q_owned_piece_visible_to_user(request.user, target))
@@ -336,7 +321,7 @@ def user_collection_list(request: AuthedHttpRequest, user_name):
def user_liked_collection_list(request: AuthedHttpRequest, user_name):
target = request.target_identity
if not request.user.is_authenticated and not target.anonymous_viewable:
- return render_user_noanonymous(request)
+ raise PermissionDenied(_("Login required"))
collections = Collection.objects.filter(
interactions__identity=target,
interactions__interaction_type="like",
diff --git a/journal/views/common.py b/journal/views/common.py
index 9b24ffc2..639adcef 100644
--- a/journal/views/common.py
+++ b/journal/views/common.py
@@ -7,6 +7,7 @@ from django.db.models import F, Min, OuterRef, Subquery
from django.shortcuts import get_object_or_404, redirect, render
from django.urls import reverse
from django.utils.translation import gettext_lazy as _
+from django.views.decorators.http import require_http_methods
from catalog.models import *
from common.utils import (
@@ -77,7 +78,7 @@ def render_list(
elif type == "review" and item_category:
queryset = Review.objects.filter(q_item_in_category(item_category))
else:
- raise BadRequest()
+ raise BadRequest(_("Invalid parameter"))
if sort == "rating":
rating = Rating.objects.filter(
owner_id=OuterRef("owner_id"), item_id=OuterRef("item_id")
@@ -125,17 +126,16 @@ def render_list(
@login_required
+@require_http_methods(["GET", "POST"])
def piece_delete(request, piece_uuid):
piece = get_object_or_404(Piece, uid=get_uuid_or_404(piece_uuid))
return_url = request.GET.get("return_url", None) or "/"
if not piece.is_editable_by(request.user):
- raise PermissionDenied()
+ raise PermissionDenied(_("Insufficient permission"))
if request.method == "GET":
return render(
request, "piece_delete.html", {"piece": piece, "return_url": return_url}
)
- elif request.method == "POST":
+ else:
piece.delete()
return redirect(return_url)
- else:
- raise BadRequest()
diff --git a/journal/views/mark.py b/journal/views/mark.py
index ade62155..30f8169b 100644
--- a/journal/views/mark.py
+++ b/journal/views/mark.py
@@ -9,6 +9,7 @@ from django.shortcuts import get_object_or_404, redirect, render
from django.utils import timezone
from django.utils.dateparse import parse_datetime
from django.utils.translation import gettext_lazy as _
+from django.views.decorators.http import require_http_methods
from catalog.models import *
from common.utils import AuthedHttpRequest, get_uuid_or_404
@@ -25,12 +26,9 @@ _checkmark = "✔️".encode("utf-8")
@login_required
+@require_http_methods(["POST"])
def wish(request: AuthedHttpRequest, item_uuid):
- if request.method != "POST":
- raise BadRequest()
item = get_object_or_404(Item, uid=get_uuid_or_404(item_uuid))
- if not item:
- raise Http404()
mark = Mark(request.user.identity, item)
if not mark.shelf_type:
mark.update(ShelfType.WISHLIST)
@@ -40,6 +38,7 @@ def wish(request: AuthedHttpRequest, item_uuid):
@login_required
+@require_http_methods(["GET", "POST"])
def mark(request: AuthedHttpRequest, item_uuid):
item = get_object_or_404(Item, uid=get_uuid_or_404(item_uuid))
mark = Mark(request.user.identity, item)
@@ -59,7 +58,7 @@ def mark(request: AuthedHttpRequest, item_uuid):
"date_today": timezone.localdate().isoformat(),
},
)
- elif request.method == "POST":
+ else:
if request.POST.get("delete", default=False):
mark.delete()
return HttpResponseRedirect(request.META.get("HTTP_REFERER", "/"))
@@ -120,27 +119,28 @@ def mark(request: AuthedHttpRequest, item_uuid):
},
)
return HttpResponseRedirect(request.META.get("HTTP_REFERER", "/"))
- raise BadRequest()
@login_required
+@require_http_methods(["POST"])
def mark_log(request: AuthedHttpRequest, item_uuid, log_id):
"""
Delete log of one item by log id.
"""
item = get_object_or_404(Item, uid=get_uuid_or_404(item_uuid))
mark = Mark(request.user.identity, item)
- if request.method == "POST":
- if request.GET.get("delete", default=False):
- if log_id:
- mark.delete_log(log_id)
- else:
- mark.delete_all_logs()
- return render(request, "_item_user_mark_history.html", {"mark": mark})
- raise BadRequest()
+ if request.GET.get("delete", default=False):
+ if log_id:
+ mark.delete_log(log_id)
+ else:
+ mark.delete_all_logs()
+ return render(request, "_item_user_mark_history.html", {"mark": mark})
+ else:
+ raise BadRequest(_("Invalid parameter"))
@login_required
+@require_http_methods(["GET", "POST"])
def comment(request: AuthedHttpRequest, item_uuid):
item = get_object_or_404(Item, uid=get_uuid_or_404(item_uuid))
if item.class_name not in ["podcastepisode", "tvepisode"]:
@@ -155,10 +155,10 @@ def comment(request: AuthedHttpRequest, item_uuid):
"comment": comment,
},
)
- elif request.method == "POST":
+ else:
if request.POST.get("delete", default=False):
if not comment:
- raise Http404()
+ raise Http404(_("Content not found"))
comment.delete()
return HttpResponseRedirect(request.META.get("HTTP_REFERER", "/"))
visibility = int(request.POST.get("visibility", default=0))
@@ -176,9 +176,9 @@ def comment(request: AuthedHttpRequest, item_uuid):
d = {"text": text, "visibility": visibility}
if position:
d["metadata"] = {"position": position}
- comment, _ = Comment.objects.update_or_create(
+ comment = Comment.objects.update_or_create(
owner=request.user.identity, item=item, defaults=d
- )
+ )[0]
post = Takahe.post_comment(comment, False)
share_to_mastodon = bool(request.POST.get("share_to_mastodon", default=False))
if post and share_to_mastodon:
@@ -187,7 +187,6 @@ def comment(request: AuthedHttpRequest, item_uuid):
else:
boost_toot_later(request.user, post.url)
return HttpResponseRedirect(request.META.get("HTTP_REFERER", "/"))
- raise BadRequest()
def user_mark_list(request: AuthedHttpRequest, user_name, shelf_type, item_category):
diff --git a/journal/views/post.py b/journal/views/post.py
index f6959b90..2cf1faa1 100644
--- a/journal/views/post.py
+++ b/journal/views/post.py
@@ -17,7 +17,7 @@ from ..models import *
def piece_replies(request: AuthedHttpRequest, piece_uuid: str):
piece = get_object_or_404(Piece, uid=get_uuid_or_404(piece_uuid))
if not piece.is_visible_to(request.user):
- raise PermissionDenied()
+ raise PermissionDenied(_("Insufficient permission"))
replies = piece.get_replies(request.user.identity)
return render(
request, "replies.html", {"post": piece.latest_post, "replies": replies}
@@ -38,7 +38,7 @@ def post_reply(request: AuthedHttpRequest, post_id: int):
content = request.POST.get("content", "").strip()
visibility = Takahe.Visibilities(int(request.POST.get("visibility", -1)))
if not content:
- raise BadRequest()
+ raise BadRequest(_("Invalid parameter"))
Takahe.reply_post(post_id, request.user.identity.pk, content, visibility)
replies = Takahe.get_replies_for_posts([post_id], request.user.identity.pk)
return render(
@@ -52,7 +52,7 @@ def post_boost(request: AuthedHttpRequest, post_id: int):
# classic_repost = request.user.preference.mastodon_repost_mode == 1
post = Takahe.get_post(post_id)
if not post:
- raise BadRequest()
+ raise BadRequest(_("Invalid parameter"))
if request.user.mastodon_site:
boost_toot_later(request.user, post.object_uri)
else:
@@ -70,7 +70,5 @@ def post_like(request: AuthedHttpRequest, post_id: int):
@require_http_methods(["POST"])
@login_required
def post_unlike(request: AuthedHttpRequest, post_id: int):
- if request.method != "POST":
- raise BadRequest()
Takahe.unlike_post(post_id, request.user.identity.pk)
return render(request, "action_like_post.html", {"post": Takahe.get_post(post_id)})
diff --git a/journal/views/review.py b/journal/views/review.py
index f04dc797..62820e6d 100644
--- a/journal/views/review.py
+++ b/journal/views/review.py
@@ -27,13 +27,14 @@ def review_retrieve(request, review_uuid):
# piece = get_object_or_404(Review, uid=get_uuid_or_404(review_uuid))
piece = Review.get_by_url(review_uuid)
if piece is None:
- raise Http404()
+ raise Http404(_("Content not found"))
if not piece.is_visible_to(request.user):
- raise PermissionDenied()
+ raise PermissionDenied(_("Insufficient permission"))
return render(request, "review.html", {"review": piece})
@login_required
+@require_http_methods(["GET", "POST"])
def review_edit(request: AuthedHttpRequest, item_uuid, review_uuid=None):
item = get_object_or_404(Item, uid=get_uuid_or_404(item_uuid))
review = (
@@ -42,7 +43,7 @@ def review_edit(request: AuthedHttpRequest, item_uuid, review_uuid=None):
else None
)
if review and not review.is_editable_by(request.user):
- raise PermissionDenied()
+ raise PermissionDenied(_("Insufficient permission"))
if request.method == "GET":
form = (
ReviewForm(instance=review)
@@ -63,7 +64,7 @@ def review_edit(request: AuthedHttpRequest, item_uuid, review_uuid=None):
"date_today": timezone.localdate().isoformat(),
},
)
- elif request.method == "POST":
+ else:
form = (
ReviewForm(request.POST, instance=review)
if review
@@ -89,12 +90,10 @@ def review_edit(request: AuthedHttpRequest, item_uuid, review_uuid=None):
form.cleaned_data["share_to_mastodon"],
)
if not review:
- raise BadRequest()
+ raise BadRequest(_("Invalid parameter"))
return redirect(reverse("journal:review_retrieve", args=[review.uuid]))
else:
- raise BadRequest()
- else:
- raise BadRequest()
+ raise BadRequest(_("Invalid parameter"))
def user_review_list(request, user_name, item_category):
@@ -112,7 +111,7 @@ class ReviewFeed(Feed):
return (
_("Reviews by {0}").format(owner.display_name)
if owner
- else _("link unavailable")
+ else _("Link invalid")
)
def link(self, owner):
@@ -120,9 +119,9 @@ class ReviewFeed(Feed):
def description(self, owner):
if not owner:
- return _("link unavailable")
+ return _("Link invalid")
elif not owner.anonymous_viewable:
- return _("anonymous access disabled by owner")
+ return _("Login required")
else:
return _("Reviews by {0}").format(owner.display_name)
diff --git a/journal/views/tag.py b/journal/views/tag.py
index bfee5828..df660679 100644
--- a/journal/views/tag.py
+++ b/journal/views/tag.py
@@ -1,15 +1,13 @@
from django.contrib.auth.decorators import login_required
-from django.core.exceptions import BadRequest, ObjectDoesNotExist, PermissionDenied
from django.db.models import Count
from django.http import Http404, HttpResponse, HttpResponseRedirect
from django.shortcuts import get_object_or_404, redirect, render
from django.urls import reverse
from django.utils.translation import gettext_lazy as _
+from django.views.decorators.http import require_http_methods
from user_messages import api as msg
from catalog.models import *
-from users.models import User
-from users.views import render_user_blocked, render_user_not_found
from ..forms import *
from ..models import *
@@ -38,16 +36,17 @@ def user_tag_list(request, user_name):
@login_required
+@require_http_methods(["GET", "POST"])
def user_tag_edit(request):
if request.method == "GET":
tag_title = Tag.cleanup_title(request.GET.get("tag", ""), replace=False)
if not tag_title:
- raise Http404()
+ raise Http404(_("Invalid tag"))
tag = Tag.objects.filter(owner=request.user.identity, title=tag_title).first()
if not tag:
- raise Http404()
+ raise Http404(_("Tag not found"))
return render(request, "tag_edit.html", {"tag": tag})
- elif request.method == "POST":
+ else:
tag_title = Tag.cleanup_title(request.POST.get("title", ""), replace=False)
tag_id = request.POST.get("id")
tag = (
@@ -56,7 +55,7 @@ def user_tag_edit(request):
else None
)
if not tag or not tag_title:
- msg.error(request.user, _("Invalid tag."))
+ msg.error(request.user, _("Invalid tag"))
return HttpResponseRedirect(request.META.get("HTTP_REFERER"))
if request.POST.get("delete"):
tag.delete()
@@ -83,7 +82,6 @@ def user_tag_edit(request):
args=[request.user.username, tag.title],
)
)
- raise BadRequest()
def user_tag_member_list(request, user_name, tag_title):
diff --git a/locale/zh_Hans/LC_MESSAGES/django.po b/locale/zh_Hans/LC_MESSAGES/django.po
index df97422b..aa7d10f1 100644
--- a/locale/zh_Hans/LC_MESSAGES/django.po
+++ b/locale/zh_Hans/LC_MESSAGES/django.po
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2024-04-20 12:47-0400\n"
+"POT-Creation-Date: 2024-04-24 01:50-0400\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME \n"
"Language-Team: LANGUAGE \n"
@@ -578,6 +578,10 @@ msgstr "结束日期"
msgid "host"
msgstr "主播"
+#: catalog/search/views.py:54 catalog/search/views.py:178
+msgid "Invalid URL"
+msgstr "无效网址"
+
#: catalog/templates/_item_card_metadata_edition.html:17
#: catalog/templates/edition.html:54
msgid "年"
@@ -1129,59 +1133,113 @@ msgstr ""
msgid "season number"
msgstr ""
-#: catalog/views_edit.py:259
+#: catalog/views.py:53 catalog/views.py:76
+msgid "Item not found"
+msgstr ""
+
+#: catalog/views.py:57 catalog/views.py:84
+msgid "Item no longer exists"
+msgstr ""
+
+#: catalog/views_edit.py:125 catalog/views_edit.py:148
+#: catalog/views_edit.py:200 catalog/views_edit.py:276
+#: catalog/views_edit.py:353 journal/views/collection.py:52
+#: journal/views/collection.py:102 journal/views/collection.py:114
+#: journal/views/collection.py:130 journal/views/collection.py:161
+#: journal/views/collection.py:180 journal/views/collection.py:200
+#: journal/views/collection.py:212 journal/views/collection.py:226
+#: journal/views/collection.py:240 journal/views/collection.py:243
+#: journal/views/collection.py:267 journal/views/common.py:134
+#: journal/views/post.py:20 journal/views/review.py:32
+#: journal/views/review.py:46
+msgid "Insufficient permission"
+msgstr ""
+
+#: catalog/views_edit.py:203 journal/views/collection.py:229
+#: journal/views/collection.py:296 journal/views/common.py:81
+#: journal/views/mark.py:139 journal/views/post.py:41 journal/views/post.py:55
+#: journal/views/review.py:93 journal/views/review.py:96 users/views.py:169
+msgid "Invalid parameter"
+msgstr "无效参数"
+
+#: catalog/views_edit.py:252
+msgid "Must be a TV Season with IMDB id and season id"
+msgstr ""
+
+#: catalog/views_edit.py:257
msgid "Updating episodes"
msgstr ""
-#: catalog/views_edit.py:289
+#: catalog/views_edit.py:287
msgid "Cannot be merged to an item already deleted or merged"
msgstr ""
-#: catalog/views_edit.py:292
+#: catalog/views_edit.py:290
msgid "Cannot merge items in different categories"
msgstr ""
-#: catalog/views_edit.py:329
+#: catalog/views_edit.py:327
msgid "Cannot be linked to an item already deleted or merged"
msgstr ""
-#: catalog/views_edit.py:331
+#: catalog/views_edit.py:329
msgid "Cannot link items other than editions"
msgstr ""
-#: common/templates/400.html:11
-msgid "无效请求"
-msgstr ""
+#: common/templates/400.html:22
+msgid ""
+"You may have submitted invalid data, or the content may have been deleted by "
+"the author."
+msgstr "您可能提交了无效的数据,或者相关内容已被作者删除。"
-#: common/templates/403.html:11
-msgid "权限不符"
-msgstr ""
+#: common/templates/400.html:24 common/templates/403.html:24
+#: common/templates/404.html:24
+msgid ""
+"If you believe this is our mistake, please contact us through the link at "
+"the bottom of the page."
+msgstr "如果您确信这是我们的错误,请通过页面底部的链接联系我们。"
-#: common/templates/404.html:11
-msgid "未找到"
-msgstr ""
+#: common/templates/403.html:22
+msgid ""
+"Author may require you to log in before accessing this content, or you do "
+"not have permission to view it."
+msgstr "作者可能希望您登录后访问,或者您没有权限查看此内容。"
-#: common/templates/500.html:11
-msgid "系统错误"
-msgstr ""
+#: common/templates/404.html:22
+msgid ""
+"You may have visited an incorrect URL, or the content you are looking for "
+"has been deleted by the author."
+msgstr "您可能访问了错误的网址,或者相关内容已被作者删除。"
-#: common/templates/_footer.html:11
+#: common/templates/500.html:22
+msgid ""
+"An internal error occurred. If this error occurs repeatedly, it will be "
+"recorded and handled by a human."
+msgstr "发生了一个内部错误,如果这个错误多次出现,后台会记录并会由人工处理。"
+
+#: common/templates/500.html:24
+msgid ""
+"If you have an urgent situation or any questions, please contact us through "
+"the link at the bottom of the page."
+msgstr "如果您有紧急情况或任何疑问,请通过页面底部的链接联系我们。"
+
+#: common/templates/_footer.html:6
msgid "Rules"
msgstr "站点规则"
-#: common/templates/_footer.html:12
+#: common/templates/_footer.html:7
msgid "Terms"
msgstr "服务协议"
-#: common/templates/_footer.html:13
+#: common/templates/_footer.html:8
msgid "Announcements"
msgstr "公告栏"
-#: common/templates/_footer.html:14
+#: common/templates/_footer.html:9
msgid "Developer"
msgstr "开发者"
-#: common/templates/_footer.html:19
+#: common/templates/_footer.html:13
msgid "Source Code"
msgstr "源代码"
@@ -1294,71 +1352,83 @@ msgstr "关注了你"
msgid "just now"
msgstr "刚刚"
+#: common/utils.py:61 common/utils.py:91 users/views.py:35 users/views.py:121
+msgid "User not found"
+msgstr "用户不存在"
+
+#: common/utils.py:65 common/utils.py:95 users/views.py:124
+msgid "User no longer exists"
+msgstr "用户不存在了"
+
+#: common/utils.py:73 common/utils.py:103
+msgid "Access denied"
+msgstr "访问被拒绝"
+
#: developer/models.py:18
msgid "minimum two characters, words and -_. only, no special characters"
-msgstr ""
+msgstr "两字符以上,无特殊字符"
#: developer/models.py:29
msgid "Allowed URIs list, space separated, at least one URI is required"
-msgstr ""
+msgstr "至少一个网址,空格分隔"
#: developer/templates/console.html:37
#: developer/templates/oauth2_provider/application_list.html:5
msgid "Your applications"
-msgstr ""
+msgstr "你的应用程序"
#: developer/templates/oauth2_provider/application_detail.html:9
msgid "Client ID"
-msgstr ""
+msgstr "Client ID"
#: developer/templates/oauth2_provider/application_detail.html:18
msgid "URL"
-msgstr ""
+msgstr "网址"
#: developer/templates/oauth2_provider/application_detail.html:24
msgid "Description"
-msgstr ""
+msgstr "描述"
#: developer/templates/oauth2_provider/application_detail.html:30
msgid "Redirect Uris"
-msgstr ""
+msgstr "重定向网址"
#: developer/templates/oauth2_provider/application_detail.html:38
#: developer/templates/oauth2_provider/application_form.html:33
msgid "Go Back"
-msgstr ""
+msgstr "返回"
#: developer/templates/oauth2_provider/application_detail.html:40
msgid "Edit"
-msgstr ""
+msgstr "编辑"
#: developer/templates/oauth2_provider/application_detail.html:42
msgid "Delete"
-msgstr ""
+msgstr "删除"
#: developer/templates/oauth2_provider/application_form.html:8
msgid "Edit application"
-msgstr ""
+msgstr "编辑应用程序"
#: developer/templates/oauth2_provider/application_form.html:35
msgid "Save"
-msgstr ""
+msgstr "保存"
#: developer/templates/oauth2_provider/application_list.html:20
msgid "New Application"
-msgstr ""
+msgstr "新建应用程序"
#: developer/templates/oauth2_provider/application_list.html:23
msgid "No applications defined"
-msgstr ""
+msgstr "尚无应用程序"
#: developer/templates/oauth2_provider/application_list.html:23
msgid "Click here"
-msgstr ""
+msgstr "点此"
#: developer/templates/oauth2_provider/application_list.html:23
msgid "if you want to register a new one"
-msgstr ""
+msgstr "如果你希望新注册一个"
#: journal/forms.py:18 journal/forms.py:41
msgid "Title"
@@ -1790,7 +1860,7 @@ msgstr ""
msgid "喜欢的收藏单"
msgstr ""
-#: journal/templates/replies.html:39 social/templates/events.html:46
+#: journal/templates/replies.html:46 social/templates/events.html:46
msgid "nothing so far."
msgstr "暂无内容。"
@@ -1824,83 +1894,92 @@ msgstr ""
msgid "分享"
msgstr ""
-#: journal/views/collection.py:44
+#: journal/views/collection.py:38
#, python-brace-format
msgid "Collection by {0}"
msgstr "{0} 的收藏单"
-#: journal/views/collection.py:200
+#: journal/views/collection.py:190
msgid "Unable to find the item, please use item url from this site."
msgstr ""
-#: journal/views/common.py:32 journal/views/mark.py:118
+#: journal/views/collection.py:303 journal/views/collection.py:324
+#: journal/views/review.py:124
+msgid "Login required"
+msgstr "登录后访问"
+
+#: journal/views/common.py:33 journal/views/mark.py:117
msgid "Data saved but unable to repost to Fediverse."
-msgstr ""
+msgstr "数据已保存但未能转发到联邦宇宙。"
-#: journal/views/common.py:34
+#: journal/views/common.py:35
msgid "Redirecting to your Mastodon instance now to re-authenticate."
-msgstr ""
+msgstr "正在重定向到你的Mastodon实例以重新认证。"
-#: journal/views/common.py:41
+#: journal/views/common.py:42
msgid "List not found."
-msgstr ""
+msgstr "列表未找到"
-#: journal/views/mark.py:110
+#: journal/views/mark.py:109
msgid "Content too long for your Mastodon instance."
-msgstr ""
+msgstr "内容过长,超出了你的Mastodon实例的限制。"
-#: journal/views/review.py:113 journal/views/review.py:127
+#: journal/views/mark.py:161 journal/views/review.py:30
+msgid "Content not found"
+msgstr "内容未找到"
+
+#: journal/views/review.py:112 journal/views/review.py:126
#, python-brace-format
msgid "Reviews by {0}"
-msgstr ""
+msgstr "{0} 的评论"
-#: journal/views/review.py:115 journal/views/review.py:123
-msgid "link unavailable"
-msgstr ""
+#: journal/views/review.py:114 journal/views/review.py:122
+msgid "Link invalid"
+msgstr "链接无效"
-#: journal/views/review.py:125
-msgid "anonymous access disabled by owner"
-msgstr ""
-
-#: journal/views/review.py:136
+#: journal/views/review.py:135
#, python-brace-format
msgid "{review_title} - a review of {item_title}"
-msgstr ""
+msgstr "{review_title} - 关于 {item_title} 的评论"
-#: journal/views/tag.py:59
-msgid "Invalid tag."
-msgstr ""
+#: journal/views/tag.py:43 journal/views/tag.py:57
+msgid "Invalid tag"
+msgstr "无效标签"
-#: journal/views/tag.py:63
+#: journal/views/tag.py:46
+msgid "Tag not found"
+msgstr "标签不存在"
+
+#: journal/views/tag.py:61
msgid "Tag deleted."
-msgstr ""
+msgstr "标签已删除"
-#: journal/views/tag.py:73
+#: journal/views/tag.py:71
msgid "Duplicated tag."
-msgstr ""
+msgstr "重复标签"
-#: journal/views/tag.py:79
+#: journal/views/tag.py:77
msgid "Tag updated."
-msgstr ""
+msgstr "标签已更新"
#: journal/views/wrapped.py:141
msgid "Summary posted to timeline."
-msgstr ""
+msgstr "总结已发布到时间轴"
#: mastodon/api.py:489 takahe/utils.py:514
#, python-brace-format
msgid "regarding {item_title}, may contain spoiler or triggering content"
msgstr "关于 {item_title},可能包含剧透或敏感内容"
-#: mastodon/api.py:639
+#: mastodon/api.py:646
msgid "collection"
msgstr "收藏单"
-#: mastodon/api.py:644
+#: mastodon/api.py:651
msgid "shared my collection"
msgstr "分享我的收藏单"
-#: mastodon/api.py:647
+#: mastodon/api.py:654
#, python-brace-format
msgid "shared {username}'s collection"
msgstr "分享 {username} 的收藏单"
@@ -2007,14 +2086,18 @@ msgstr "转播了你的帖文"
msgid ""
"\n"
"boosted your collection %(piece_title)s\n"
-msgstr "\n转播了你的收藏单 %(piece_title)s\n"
+msgstr ""
+"\n"
+"转播了你的收藏单 %(piece_title)s\n"
#: social/templates/event/boosted_comment.html:3
#, python-format
msgid ""
"\n"
"boosted your comment on %(item_title)s\n"
-msgstr "\n转播了你对 %(item_title)s 的短评\n"
+msgstr ""
+"\n"
+"转播了你对 %(item_title)s 的短评\n"
#: social/templates/event/boosted_review.html:2
#, python-format
@@ -2023,7 +2106,8 @@ msgid ""
"boosted your review %(piece_title)s on %(item_title)s\n"
msgstr ""
-"\n转播了你对 %(item_title)s 的评论 %(item_title)s 的评论 %(piece_title)s\n"
#: social/templates/event/boosted_shelfmember.html:3
@@ -2031,7 +2115,9 @@ msgstr ""
msgid ""
"\n"
"boosted your mark on %(item_title)s\n"
-msgstr "\n转播了你对 %(item_title)s 的标记\n"
+msgstr ""
+"\n"
+"转播了你对 %(item_title)s 的标记\n"
#: social/templates/event/follow_requested.html:3
msgid "requested to follow you"
@@ -2050,14 +2136,18 @@ msgstr "赞了你的帖文"
msgid ""
"\n"
"liked your collection %(piece_title)s\n"
-msgstr "\n赞了你的收藏单 %(piece_title)s\n"
+msgstr ""
+"\n"
+"赞了你的收藏单 %(piece_title)s\n"
#: social/templates/event/liked_comment.html:3
#, python-format
msgid ""
"\n"
"liked your comment on %(item_title)s\n"
-msgstr "\n赞了你对 %(item_title)s 的短评\n"
+msgstr ""
+"\n"
+"赞了你对 %(item_title)s 的短评\n"
#: social/templates/event/liked_review.html:2
#, python-format
@@ -2066,7 +2156,8 @@ msgid ""
"liked your review %(piece_title)s on %(item_title)s\n"
msgstr ""
-"\n赞了你对 %(item_title)s 的评论 %(item_title)s 的评论 %(piece_title)s\n"
#: social/templates/event/liked_shelfmember.html:3
@@ -2074,7 +2165,9 @@ msgstr ""
msgid ""
"\n"
"liked your mark on %(item_title)s\n"
-msgstr "\n赞了你对 %(item_title)s 的标记\n"
+msgstr ""
+"\n"
+"赞了你对 %(item_title)s 的标记\n"
#: social/templates/event/mentioned.html:3
msgid "mentioned you"
@@ -2085,14 +2178,18 @@ msgstr "提到了你"
msgid ""
"\n"
"replied to your collection %(piece_title)s\n"
-msgstr "\n回应了你的收藏单 %(piece_title)s\n"
+msgstr ""
+"\n"
+"回应了你的收藏单 %(piece_title)s\n"
#: social/templates/event/mentioned_comment.html:3
#, python-format
msgid ""
"\n"
"replied to your comment on %(item_title)s\n"
-msgstr "\n回应了你对 %(item_title)s 的短评\n"
+msgstr ""
+"\n"
+"回应了你对 %(item_title)s 的短评\n"
#: social/templates/event/mentioned_review.html:2
#, python-format
@@ -2101,7 +2198,8 @@ msgid ""
"replied to your review %(piece_title)s on %(item_title)s\n"
msgstr ""
-"\n回应了你对 %(item_title)s 的评论 %(item_title)s 的评论 %(piece_title)s\n"
#: social/templates/event/mentioned_shelfmember.html:3
@@ -2109,7 +2207,9 @@ msgstr ""
msgid ""
"\n"
"replied to your mark on %(item_title)s\n"
-msgstr "\n回应了你对 %(item_title)s 的标记\n"
+msgstr ""
+"\n"
+"回应了你对 %(item_title)s 的标记\n"
#: social/templates/events.html:44
msgid "nothing more."
@@ -2167,114 +2267,118 @@ msgstr ""
msgid "created collection"
msgstr ""
-#: users/account.py:87
+#: users/account.py:86
msgid "无效的电子邮件地址"
msgstr ""
-#: users/account.py:105
+#: users/account.py:104
msgid "验证邮件已发送"
msgstr ""
-#: users/account.py:106
+#: users/account.py:105
msgid "请查阅收件箱"
msgstr ""
-#: users/account.py:156 users/account.py:163 users/account.py:173
+#: users/account.py:155 users/account.py:162 users/account.py:172
msgid "认证失败😫"
msgstr ""
-#: users/account.py:156
+#: users/account.py:155
msgid "Mastodon服务未能返回有效认证信息"
msgstr ""
-#: users/account.py:163
+#: users/account.py:162
msgid "无效会话信息"
msgstr ""
-#: users/account.py:173
+#: users/account.py:167
+msgid "Invalid instance domain"
+msgstr ""
+
+#: users/account.py:172
msgid "Mastodon服务未能返回有效认证令牌"
msgstr ""
-#: users/account.py:190
+#: users/account.py:189
msgid "联邦宇宙访问失败😫"
msgstr ""
-#: users/account.py:212
+#: users/account.py:211
msgid "注册失败😫"
msgstr ""
-#: users/account.py:213
+#: users/account.py:212
msgid "本站仅限邀请注册"
msgstr ""
-#: users/account.py:279
+#: users/account.py:273
msgid "This username is already in use."
msgstr ""
-#: users/account.py:290
+#: users/account.py:284
msgid "This email address is already in use."
msgstr ""
-#: users/account.py:342 users/account.py:351
+#: users/account.py:336 users/account.py:345
msgid "无效的验证码"
msgstr ""
-#: users/account.py:370
+#: users/account.py:364
msgid "链接无效或已过期"
msgstr ""
-#: users/account.py:387 users/account.py:393
+#: users/account.py:381 users/account.py:387
msgid "电子邮件地址不匹配"
msgstr ""
-#: users/account.py:397
+#: users/account.py:391
msgid "此电子邮件地址已被注册"
msgstr ""
-#: users/account.py:402
+#: users/account.py:396
msgid "无法完成验证"
msgstr ""
-#: users/account.py:434
+#: users/account.py:428
msgid "用户名已被使用"
msgstr ""
-#: users/account.py:449
+#: users/account.py:443
msgid "电子邮件地址已被使用"
msgstr ""
-#: users/account.py:467
+#: users/account.py:461
msgid "已发送验证邮件,请查收。"
msgstr ""
-#: users/account.py:471
+#: users/account.py:465
msgid "用户名已设置。"
msgstr ""
-#: users/account.py:473
+#: users/account.py:467
msgid "电子邮件地址已取消关联。"
msgstr ""
-#: users/account.py:491
+#: users/account.py:485
#, python-brace-format
msgid "该身份 {username}@{site} 与当前账号相同。"
msgstr ""
-#: users/account.py:499
+#: users/account.py:493
#, python-brace-format
msgid "该身份 {username}@{site} 已被用于其它账号。"
msgstr ""
-#: users/account.py:523
+#: users/account.py:517
#, python-brace-format
msgid "账号身份已更新为 {username}@{site}。"
msgstr ""
-#: users/account.py:526
+#: users/account.py:520
msgid "连接联邦宇宙获取身份信息失败。"
msgstr ""
-#: users/account.py:575
+#: users/account.py:569
msgid "验证信息不符。"
msgstr ""
@@ -2534,18 +2638,5 @@ msgstr ""
msgid "验证电子邮件"
msgstr ""
-#: users/views.py:25
-msgid "😖哎呀,这位用户好像还没有加入本站,快去联邦宇宙呼唤TA来注册吧!"
-msgstr ""
-
-#: users/views.py:26
-msgid "未找到用户"
-msgstr ""
-
-#: users/views.py:38
-msgid "没有访问该用户主页的权限"
-msgstr ""
-
-#: users/views.py:49
-msgid "作者已设置仅限登录用户查看"
-msgstr ""
+#~ msgid "Invalid tag."
+#~ msgstr "无效标签"
diff --git a/pyproject.toml b/pyproject.toml
index 36407d92..2925f380 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -4,7 +4,7 @@ reportIncompatibleVariableOverride = false
reportUnusedImport = false
[tool.djlint]
-ignore="T002,T003,H006,H019,H020,H021,H023,H030,H031,D018"
+ignore="T002,T003,H005,H006,H019,H020,H021,H023,H030,H031,D018"
indent=2
[tool.isort]
diff --git a/users/account.py b/users/account.py
index 2c226081..6f175a36 100644
--- a/users/account.py
+++ b/users/account.py
@@ -32,46 +32,45 @@ from takahe.utils import Takahe
from .models import Preference, User
from .tasks import *
-
# the 'login' page that user can see
-def login(request):
- if request.method == "GET":
- selected_site = request.GET.get("site", default="")
+require_http_methods(["GET"])
- cache_key = "login_sites"
- sites = cache.get(cache_key, [])
- if not sites:
- sites = list(
- User.objects.filter(is_active=True)
- .values("mastodon_site")
- .annotate(total=Count("mastodon_site"))
- .order_by("-total")
- .values_list("mastodon_site", flat=True)
- )
- cache.set(cache_key, sites, timeout=3600 * 8)
- # store redirect url in the cookie
- if request.GET.get("next"):
- request.session["next_url"] = request.GET.get("next")
- invite_status = -1 if settings.INVITE_ONLY else 0
- if settings.INVITE_ONLY and request.GET.get("invite"):
- if Takahe.verify_invite(request.GET.get("invite")):
- invite_status = 1
- request.session["invite"] = request.GET.get("invite")
- else:
- invite_status = -2
- return render(
- request,
- "users/login.html",
- {
- "sites": sites,
- "scope": quote(settings.MASTODON_CLIENT_SCOPE),
- "selected_site": selected_site,
- "allow_any_site": settings.MASTODON_ALLOW_ANY_SITE,
- "invite_status": invite_status,
- },
+
+def login(request):
+ selected_site = request.GET.get("site", default="")
+
+ cache_key = "login_sites"
+ sites = cache.get(cache_key, [])
+ if not sites:
+ sites = list(
+ User.objects.filter(is_active=True)
+ .values("mastodon_site")
+ .annotate(total=Count("mastodon_site"))
+ .order_by("-total")
+ .values_list("mastodon_site", flat=True)
)
- else:
- raise BadRequest()
+ cache.set(cache_key, sites, timeout=3600 * 8)
+ # store redirect url in the cookie
+ if request.GET.get("next"):
+ request.session["next_url"] = request.GET.get("next")
+ invite_status = -1 if settings.INVITE_ONLY else 0
+ if settings.INVITE_ONLY and request.GET.get("invite"):
+ if Takahe.verify_invite(request.GET.get("invite")):
+ invite_status = 1
+ request.session["invite"] = request.GET.get("invite")
+ else:
+ invite_status = -2
+ return render(
+ request,
+ "users/login.html",
+ {
+ "sites": sites,
+ "scope": quote(settings.MASTODON_CLIENT_SCOPE),
+ "selected_site": selected_site,
+ "allow_any_site": settings.MASTODON_ALLOW_ANY_SITE,
+ "invite_status": invite_status,
+ },
+ )
# connect will send verification email or redirect to mastodon server
@@ -165,7 +164,7 @@ def connect_redirect_back(request):
try:
token, refresh_token = obtain_token(site, request, code)
except ObjectDoesNotExist:
- raise BadRequest()
+ raise BadRequest(_("Invalid instance domain"))
if not token:
return render(
request,
@@ -239,24 +238,19 @@ def login_existing_user(request, existing_user):
@mastodon_request_included
@login_required
def logout(request):
- if request.method == "GET":
- # revoke_token(request.user.mastodon_site, request.user.mastodon_token)
- return auth_logout(request)
- else:
- raise BadRequest()
+ # revoke_token(request.user.mastodon_site, request.user.mastodon_token)
+ return auth_logout(request)
@mastodon_request_included
@login_required
+@require_http_methods(["POST"])
def reconnect(request):
if request.META.get("HTTP_AUTHORIZATION"):
raise BadRequest("Only for web login")
- if request.method == "POST":
- request.session["swap_login"] = True
- request.session["swap_domain"] = request.POST["domain"]
- return connect(request)
- else:
- raise BadRequest()
+ request.session["swap_login"] = True
+ request.session["swap_domain"] = request.POST["domain"]
+ return connect(request)
class RegistrationForm(forms.ModelForm):
diff --git a/users/views.py b/users/views.py
index be495afa..2588d825 100644
--- a/users/views.py
+++ b/users/views.py
@@ -2,7 +2,7 @@ import json
from django.contrib.auth.decorators import login_required
from django.core.exceptions import BadRequest
-from django.http import HttpResponseRedirect
+from django.http import Http404, HttpResponseRedirect
from django.shortcuts import redirect, render
from django.urls import reverse
from django.utils.translation import gettext_lazy as _
@@ -21,41 +21,6 @@ from .data import *
from .models import APIdentity
-def render_user_not_found(request, user_name=""):
- sec_msg = _("😖哎呀,这位用户好像还没有加入本站,快去联邦宇宙呼唤TA来注册吧!")
- msg = _("未找到用户") + user_name
- return render(
- request,
- "common/error.html",
- {
- "msg": msg,
- "secondary_msg": sec_msg,
- },
- )
-
-
-def render_user_blocked(request):
- msg = _("没有访问该用户主页的权限")
- return render(
- request,
- "common/error.html",
- {
- "msg": msg,
- },
- )
-
-
-def render_user_noanonymous(request):
- msg = _("作者已设置仅限登录用户查看")
- return render(
- request,
- "common/error.html",
- {
- "msg": msg,
- },
- )
-
-
def query_identity(request, handle):
try:
i = APIdentity.get_by_handle(handle)
@@ -67,7 +32,7 @@ def query_identity(request, handle):
request, "users/fetch_identity_pending.html", {"handle": handle}
)
else:
- return render_user_not_found(request, handle)
+ raise Http404(_("User not found"))
def fetch_refresh(request):
@@ -153,10 +118,10 @@ def unblock(request: AuthedHttpRequest, user_name):
try:
target = APIdentity.get_by_handle(user_name)
except APIdentity.DoesNotExist:
- return render_user_not_found(request)
+ raise Http404(_("User not found"))
target_user = target.user
if target_user and not target_user.is_active:
- return render_user_not_found(request)
+ raise Http404(_("User no longer exists"))
request.user.identity.unblock(target)
return render(
request,
@@ -201,7 +166,7 @@ def set_layout(request: AuthedHttpRequest):
request.user.preference.discover_layout = layout
request.user.preference.save(update_fields=["discover_layout"])
return redirect(reverse("catalog:discover"))
- raise BadRequest()
+ raise BadRequest(_("Invalid parameter"))
@login_required