i18n for 4xx 5xx pages

This commit is contained in:
Your Name 2024-04-23 23:57:49 -04:00 committed by Henri Dickson
parent c74e3c5332
commit a776dcfbb5
19 changed files with 390 additions and 374 deletions

View file

@ -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)

View file

@ -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))

View file

@ -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",

View file

@ -8,7 +8,7 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ site_name }} - {% trans '无效请求' %}</title>
<title>{{ site_name }} - 400</title>
<meta name="robots" content="noindex">
{% include "common_libs.html" %}
</head>
@ -17,11 +17,12 @@
<main class="container">
<article class="error">
<header>
<h3>🤷🏻 无效的请求</h3>
<h3>🤷🏻 {{ exception }}</h3>
</header>
您可能提交了无效的数据,或者相关内容已被作者删除。如果您确信这是我们的错误,请通过页面底部的链接联系我们。
{% blocktrans %}You may have submitted invalid data, or the content may have been deleted by the author.{% endblocktrans %}
<br>
{% blocktrans %}If you believe this is our mistake, please contact us through the link at the bottom of the page.{% endblocktrans %}
<section>
{{ exception }}
{% if exception.additonal_detail %}
{% for e in exception.additonal_detail %}<p>{{ e }}</p>{% endfor %}
{% endif %}

View file

@ -4,11 +4,11 @@
{% load mastodon %}
{% load thumb %}
<!DOCTYPE html>
<html lang="zh">
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ site_name }} - {% trans '权限不符' %}</title>
<title>{{ site_name }} - 403</title>
<meta name="robots" content="noindex">
{% include "common_libs.html" %}
</head>
@ -17,10 +17,11 @@
<main class="container">
<article class="error">
<header>
<h3>🙅🏻 权限不符</h3>
<h3>🙅🏻 {{ exception|default:"" }}</h3>
</header>
{{ exception }}
您可能访问了错误的网址,或者相关内容已被作者删除。如果您确信这是我们的错误,请通过页面底部的链接联系我们。
{% blocktrans %}Author may require you to log in before accessing this content, or you do not have permission to view it.{% endblocktrans %}
<br>
{% blocktrans %}If you believe this is our mistake, please contact us through the link at the bottom of the page.{% endblocktrans %}
</article>
</main>
{% include "_footer.html" %}

View file

@ -4,11 +4,11 @@
{% load mastodon %}
{% load thumb %}
<!DOCTYPE html>
<html lang="zh">
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ site_name }} - {% trans '未找到' %}</title>
<title>{{ site_name }} - 404</title>
<meta name="robots" content="noindex">
{% include "common_libs.html" %}
</head>
@ -17,9 +17,11 @@
<main class="container">
<article class="error">
<header>
<h3>🤷🏻 条目未找到</h3>
<h3>🤷🏻 {{ exception|default:"" }}</h3>
</header>
您可能输入了一个无效的网址,或者相关内容已被作者删除。如果您确信这是我们的错误,请通过页面底部的链接联系我们。
{% blocktrans %}You may have visited an incorrect URL, or the content you are looking for has been deleted by the author.{% endblocktrans %}
<br>
{% blocktrans %}If you believe this is our mistake, please contact us through the link at the bottom of the page.{% endblocktrans %}
</article>
</main>
{% include "_footer.html" %}

View file

@ -4,11 +4,11 @@
{% load mastodon %}
{% load thumb %}
<!DOCTYPE html>
<html lang="zh">
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ site_name }} - {% trans '系统错误' %}</title>
<title>{{ site_name }} - 500</title>
<meta name="robots" content="noindex">
{% include "common_libs.html" %}
</head>
@ -17,9 +17,11 @@
<main class="container">
<article class="error">
<header>
<h3>🤦🏻 系统内部错误</h3>
<h3>🤦🏻 My Bad</h3>
</header>
发生了一个内部错误,如果这个错误多次出现,后台会记录并会由人工处理。如果您有紧急情况或任何疑问,请通过页面底部的链接联系我们。
{% blocktrans %}An internal error occurred. If this error occurs repeatedly, it will be recorded and handled by a human.{% endblocktrans %}
<br>
{% blocktrans %}If you have an urgent situation or any questions, please contact us through the link at the bottom of the page.{% endblocktrans %}
</article>
</main>
{% include "_footer.html" %}

View file

@ -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

View file

@ -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})

View file

@ -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",

View file

@ -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()

View file

@ -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):

View file

@ -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)})

View file

@ -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)

View file

@ -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):

View file

@ -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 <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\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 <a href=\"%(piece_url)s\">%(piece_title)s</a>\n"
msgstr "\n转播了你的收藏单 <a href=\"%(piece_url)s\">%(piece_title)s</a>\n"
msgstr ""
"\n"
"转播了你的收藏单 <a href=\"%(piece_url)s\">%(piece_title)s</a>\n"
#: social/templates/event/boosted_comment.html:3
#, python-format
msgid ""
"\n"
"boosted your comment on <a href=\"%(item_url)s\">%(item_title)s</a>\n"
msgstr "\n转播了你对 <a href=\"%(item_url)s\">%(item_title)s</a> 的短评\n"
msgstr ""
"\n"
"转播了你对 <a href=\"%(item_url)s\">%(item_title)s</a> 的短评\n"
#: social/templates/event/boosted_review.html:2
#, python-format
@ -2023,7 +2106,8 @@ msgid ""
"boosted your review <a href=\"%(piece_url)s\">%(piece_title)s</a> on <a "
"href=\"%(item_url)s\">%(item_title)s</a>\n"
msgstr ""
"\n转播了你对 <a href=\"%(item_url)s\">%(item_title)s</a> 的评论 <a "
"\n"
"转播了你对 <a href=\"%(item_url)s\">%(item_title)s</a> 的评论 <a "
"href=\"%(piece_url)s\">%(piece_title)s</a>\n"
#: social/templates/event/boosted_shelfmember.html:3
@ -2031,7 +2115,9 @@ msgstr ""
msgid ""
"\n"
"boosted your mark on <a href=\"%(item_url)s\">%(item_title)s</a>\n"
msgstr "\n转播了你对 <a href=\"%(item_url)s\">%(item_title)s</a> 的标记\n"
msgstr ""
"\n"
"转播了你对 <a href=\"%(item_url)s\">%(item_title)s</a> 的标记\n"
#: social/templates/event/follow_requested.html:3
msgid "requested to follow you"
@ -2050,14 +2136,18 @@ msgstr "赞了你的帖文"
msgid ""
"\n"
"liked your collection <a href=\"%(piece_url)s\">%(piece_title)s</a>\n"
msgstr "\n赞了你的收藏单 <a href=\"%(piece_url)s\">%(piece_title)s</a>\n"
msgstr ""
"\n"
"赞了你的收藏单 <a href=\"%(piece_url)s\">%(piece_title)s</a>\n"
#: social/templates/event/liked_comment.html:3
#, python-format
msgid ""
"\n"
"liked your comment on <a href=\"%(item_url)s\">%(item_title)s</a>\n"
msgstr "\n赞了你对 <a href=\"%(item_url)s\">%(item_title)s</a> 的短评\n"
msgstr ""
"\n"
"赞了你对 <a href=\"%(item_url)s\">%(item_title)s</a> 的短评\n"
#: social/templates/event/liked_review.html:2
#, python-format
@ -2066,7 +2156,8 @@ msgid ""
"liked your review <a href=\"%(piece_url)s\">%(piece_title)s</a> on <a "
"href=\"%(item_url)s\">%(item_title)s</a>\n"
msgstr ""
"\n赞了你对 <a href=\"%(item_url)s\">%(item_title)s</a> 的评论 <a "
"\n"
"赞了你对 <a href=\"%(item_url)s\">%(item_title)s</a> 的评论 <a "
"href=\"%(piece_url)s\">%(piece_title)s</a>\n"
#: social/templates/event/liked_shelfmember.html:3
@ -2074,7 +2165,9 @@ msgstr ""
msgid ""
"\n"
"liked your mark on <a href=\"%(item_url)s\">%(item_title)s</a>\n"
msgstr "\n赞了你对 <a href=\"%(item_url)s\">%(item_title)s</a> 的标记\n"
msgstr ""
"\n"
"赞了你对 <a href=\"%(item_url)s\">%(item_title)s</a> 的标记\n"
#: social/templates/event/mentioned.html:3
msgid "mentioned you"
@ -2085,14 +2178,18 @@ msgstr "提到了你"
msgid ""
"\n"
"replied to your collection <a href=\"%(piece_url)s\">%(piece_title)s</a>\n"
msgstr "\n回应了你的收藏单 <a href=\"%(piece_url)s\">%(piece_title)s</a>\n"
msgstr ""
"\n"
"回应了你的收藏单 <a href=\"%(piece_url)s\">%(piece_title)s</a>\n"
#: social/templates/event/mentioned_comment.html:3
#, python-format
msgid ""
"\n"
"replied to your comment on <a href=\"%(item_url)s\">%(item_title)s</a>\n"
msgstr "\n回应了你对 <a href=\"%(item_url)s\">%(item_title)s</a> 的短评\n"
msgstr ""
"\n"
"回应了你对 <a href=\"%(item_url)s\">%(item_title)s</a> 的短评\n"
#: social/templates/event/mentioned_review.html:2
#, python-format
@ -2101,7 +2198,8 @@ msgid ""
"replied to your review <a href=\"%(piece_url)s\">%(piece_title)s</a> on <a "
"href=\"%(item_url)s\">%(item_title)s</a>\n"
msgstr ""
"\n回应了你对 <a href=\"%(item_url)s\">%(item_title)s</a> 的评论 <a "
"\n"
"回应了你对 <a href=\"%(item_url)s\">%(item_title)s</a> 的评论 <a "
"href=\"%(piece_url)s\">%(piece_title)s</a>\n"
#: social/templates/event/mentioned_shelfmember.html:3
@ -2109,7 +2207,9 @@ msgstr ""
msgid ""
"\n"
"replied to your mark on <a href=\"%(item_url)s\">%(item_title)s</a>\n"
msgstr "\n回应了你对 <a href=\"%(item_url)s\">%(item_title)s</a> 的标记\n"
msgstr ""
"\n"
"回应了你对 <a href=\"%(item_url)s\">%(item_title)s</a> 的标记\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 "无效标签"

View file

@ -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]

View file

@ -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):

View file

@ -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