streamline profile url
This commit is contained in:
parent
d45d1b3946
commit
df0908b6bd
24 changed files with 141 additions and 92 deletions
|
@ -58,7 +58,7 @@
|
|||
{% if comment.rating_grade %}{{ comment.rating_grade|rating_star }}{% endif %}
|
||||
<a href="{{ comment.owner.url }}"
|
||||
class="nickname"
|
||||
title="@{{ comment.owner.handler }}">{{ comment.owner.display_name }}</a>
|
||||
title="@{{ comment.owner.handle }}">{{ comment.owner.display_name }}</a>
|
||||
</span>
|
||||
<span class="action inline">
|
||||
<span class="timestamp">
|
||||
|
|
|
@ -62,7 +62,7 @@
|
|||
{% if comment.rating_grade %}{{ comment.rating_grade|rating_star }}{% endif %}
|
||||
<a href="{{ comment.owner.url }}"
|
||||
class="nickname"
|
||||
title="@{{ comment.owner.handler }}">{{ comment.owner.display_name }}</a>
|
||||
title="@{{ comment.owner.handle }}">{{ comment.owner.display_name }}</a>
|
||||
</span>
|
||||
<span class="action inline">
|
||||
<span class="timestamp">
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
{% if review.rating_grade %}{{ review.rating_grade|rating_star }}{% endif %}
|
||||
<a href="{{ review.owner.url }}"
|
||||
class="nickname"
|
||||
title="@{{ review.owner.handler }}">{{ review.owner.display_name }}</a>
|
||||
title="@{{ review.owner.handle }}">{{ review.owner.display_name }}</a>
|
||||
</span>
|
||||
<span class="action inline">
|
||||
<span class="timestamp">{{ review.created_time|date }}</span>
|
||||
|
|
|
@ -43,7 +43,7 @@
|
|||
<span class="timestamp">{{ mark.created_time|date }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<a href="{{ mark.owner.url }}" title="@{{ mark.owner.handler }}">{{ mark.owner.display_name }}</a>
|
||||
<a href="{{ mark.owner.url }}" title="@{{ mark.owner.handle }}">{{ mark.owner.display_name }}</a>
|
||||
<span>{{ mark.action_label }}</span>
|
||||
{% if mark.rating_grade %}{{ mark.rating_grade|rating_star }}{% endif %}
|
||||
{% if mark.comment.item != item %}<a href="{{ mark.comment.item_url }}">{{ mark.comment.item.title }}</a>{% endif %}
|
||||
|
|
|
@ -45,7 +45,7 @@
|
|||
<span>
|
||||
<a href="{{ review.owner.url }}"
|
||||
class="nickname"
|
||||
title="@{{ review.owner.handler }}">{{ review.owner.display_name }}</a>
|
||||
title="@{{ review.owner.handle }}">{{ review.owner.display_name }}</a>
|
||||
</span>
|
||||
</div>
|
||||
<div>{{ review.plain_content | truncate:200 }}</div>
|
||||
|
|
|
@ -196,7 +196,7 @@
|
|||
<div class="tag-list">
|
||||
{% for t in top_tags %}
|
||||
<span>
|
||||
<a href="{% url 'journal:user_tag_member_list' identity.handler t %}">{{ t }}</a>
|
||||
<a href="{% url 'journal:user_tag_member_list' identity.user.handler t %}">{{ t }}</a>
|
||||
</span>
|
||||
{% empty %}
|
||||
<div class="empty">暂无可见标签</div>
|
||||
|
@ -204,7 +204,7 @@
|
|||
</div>
|
||||
<small>
|
||||
{% if top_tags %}
|
||||
<a href="{% url 'journal:user_tag_list' identity.handler %}">...{% trans '全部' %}</a>
|
||||
<a href="{% url 'journal:user_tag_list' identity.user.handler %}">...{% trans '全部' %}</a>
|
||||
{% endif %}
|
||||
</small>
|
||||
</details>
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
import functools
|
||||
import re
|
||||
import uuid
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from django.db.models import query
|
||||
from django.http import Http404, HttpRequest, HttpResponseRedirect, QueryDict
|
||||
from django.utils import timezone
|
||||
from django.utils.baseconv import base62
|
||||
|
@ -55,7 +53,38 @@ def target_identity_required(func):
|
|||
from users.views import render_user_blocked, render_user_not_found
|
||||
|
||||
try:
|
||||
target = APIdentity.get_by_handler(user_name)
|
||||
target = APIdentity.get_by_handle(user_name)
|
||||
except APIdentity.DoesNotExist:
|
||||
return render_user_not_found(request)
|
||||
target_user = target.user
|
||||
viewer = None
|
||||
if target_user and not target_user.is_active:
|
||||
return render_user_not_found(request)
|
||||
if request.user.is_authenticated:
|
||||
try:
|
||||
viewer = APIdentity.objects.get(user=request.user)
|
||||
except APIdentity.DoesNotExist:
|
||||
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)
|
||||
else:
|
||||
viewer = None
|
||||
request.target_identity = target
|
||||
request.identity = viewer
|
||||
return func(request, user_name, *args, **kwargs)
|
||||
|
||||
return wrapper
|
||||
|
||||
|
||||
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)
|
||||
target_user = target.user
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
{% csrf_token %}
|
||||
{% if not application.is_official %}
|
||||
<p>
|
||||
<b>{{ application.name }}</b> 是由 <a href="{{ application.user.identity.url }}">@{{ application.user.identity.handler }}</a> 创建和维护的应用程序。
|
||||
<b>{{ application.name }}</b> 是由 <a href="{{ application.user.identity.url }}">@{{ application.user.identity.handle }}</a> 创建和维护的应用程序。
|
||||
{{ site_name }}无法保证其安全性和有效性,请自行验证确认后再授权。
|
||||
</p>
|
||||
{% endif %}
|
||||
|
|
|
@ -49,7 +49,7 @@
|
|||
<span class="timestamp">{{ mark.created_time|date }}</span>
|
||||
</div>
|
||||
<div>
|
||||
{% comment %} <a href="{{mark.owner.url }}" title="@{{ mark.owner.handler }}">{{ mark.owner.display_name }}</a> {% endcomment %}
|
||||
{% comment %} <a href="{{mark.owner.url }}" title="@{{ mark.owner.handle }}">{{ mark.owner.display_name }}</a> {% endcomment %}
|
||||
<span>{{ mark.action_label }}</span>
|
||||
{% if mark.rating_grade %}{{ mark.rating_grade|rating_star }}{% endif %}
|
||||
</div>
|
||||
|
|
|
@ -62,7 +62,7 @@
|
|||
<div class="info">
|
||||
<p>
|
||||
<a href="{{ collection.owner.url }}">{{ collection.owner.mastodon_account.display_name }}</a>
|
||||
<span class="handler">@{{ collection.owner.handler }}</span>
|
||||
<span class="handler">@{{ collection.owner.handle }}</span>
|
||||
</p>
|
||||
<p>
|
||||
{% for cat, count in collection.get_summary.items %}
|
||||
|
|
|
@ -10,21 +10,21 @@
|
|||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
{% if identity.user == request.user %}
|
||||
{% if me %}
|
||||
<title>{{ site_name }} - {% trans '我的个人主页' %}</title>
|
||||
{% else %}
|
||||
<title>{{ site_name }} - {{ identity.display_name }}</title>
|
||||
{% endif %}
|
||||
<meta property="og:title"
|
||||
content="{{ identity.handler }} - {{ site_name }}">
|
||||
<meta property="og:url" content="{{ request.build_absolute_uri }}">
|
||||
content="{{ site_name }} - @{{ identity.handle }}">
|
||||
<meta property="og:url" content="{{ identity.url }}">
|
||||
<meta property="og:image" content="{{ identity.avatar }}">
|
||||
<meta property="og:site_name" content="{{ site_name }}">
|
||||
{% if not identity.anonymous_viewable %}<meta name="robots" content="noindex">{% endif %}
|
||||
<link rel="alternate"
|
||||
type="application/rss+xml"
|
||||
title="{{ site_name }} - {{ identity.handler }}的评论"
|
||||
href="{{ request.build_absolute_uri }}feed/reviews/">
|
||||
title="{{ site_name }} - @{{ identity.handle }}的评论"
|
||||
href="{{ identity.url }}/feed/reviews/">
|
||||
{% include "common_libs.html" %}
|
||||
<script src="{% static 'js/calendar_yearview_blocks.js' %}" defer></script>
|
||||
<link href="{% static 'css/calendar_yearview_blocks.css' %}"
|
||||
|
@ -68,7 +68,7 @@
|
|||
</p>
|
||||
</div>
|
||||
<span class="calendar_data"
|
||||
hx-get="{% url 'journal:user_calendar_data' identity.handler %}"
|
||||
hx-get="{% url 'journal:user_calendar_data' identity.handle %}"
|
||||
hx-trigger="load"
|
||||
hx-swap="innerHTML"
|
||||
style="display:none"></span>
|
||||
|
@ -94,7 +94,7 @@
|
|||
<h5>
|
||||
{{ shelf.title }}
|
||||
<small>
|
||||
<a href="{% if shelf_type == 'reviewed' %}{% url 'journal:user_review_list' identity.handler category %}{% else %}{% url 'journal:user_mark_list' identity.handler shelf_type category %}{% endif %}">{{ shelf.count }}</a>
|
||||
<a href="{% if shelf_type == 'reviewed' %}{% url 'journal:user_review_list' identity.handle category %}{% else %}{% url 'journal:user_mark_list' identity.handle shelf_type category %}{% endif %}">{{ shelf.count }}</a>
|
||||
</small>
|
||||
</h5>
|
||||
<ul class="cards">
|
||||
|
@ -133,7 +133,7 @@
|
|||
<h5>
|
||||
{% trans '创建的收藏单' %}
|
||||
<small>
|
||||
<a href="{% url 'journal:user_collection_list' identity.handler %}">{{ collections_count }}</a>
|
||||
<a href="{% url 'journal:user_collection_list' identity.handle %}">{{ collections_count }}</a>
|
||||
{% if identity.user == request.user %}
|
||||
<a href="{% url 'journal:collection_create' %}">
|
||||
<i class="fa-regular fa-square-plus"></i>
|
||||
|
@ -173,7 +173,7 @@
|
|||
<h5>
|
||||
{% trans '喜欢的收藏单' %}
|
||||
<small>
|
||||
<a href="{% url 'journal:user_liked_collection_list' identity.handler %}">{{ liked_collections_count }}</a>
|
||||
<a href="{% url 'journal:user_liked_collection_list' identity.handle %}">{{ liked_collections_count }}</a>
|
||||
</small>
|
||||
</h5>
|
||||
<ul class="cards">
|
||||
|
|
|
@ -50,7 +50,7 @@
|
|||
</div>
|
||||
<div class="info">
|
||||
<a href="{{ review.owner.url }}">{{ review.owner.display_name }}</a>
|
||||
<span class="handler">@{{ review.owner.handler }}</span>
|
||||
<span class="handler">@{{ review.owner.handle }}</span>
|
||||
<br>
|
||||
评论
|
||||
<a href="{{ review.item.url }}">{{ review.item.title }}</a>
|
||||
|
|
|
@ -40,7 +40,7 @@
|
|||
{% if liked %}
|
||||
-
|
||||
<a href="{{ collection.owner.url }}"
|
||||
title="@{{ collection.owner.handler }}">{{ collection.owner.display_name }}</a>
|
||||
title="@{{ collection.owner.handle }}">{{ collection.owner.display_name }}</a>
|
||||
{% endif %}
|
||||
</p>
|
||||
{% empty %}
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
{% for v in tags %}
|
||||
<span style="margin-right:2em; white-space: nowrap;">
|
||||
<span>
|
||||
<a href="{% url 'journal:user_tag_member_list' identity.handler v.title %}">{{ v.title }}</a>
|
||||
<a href="{% url 'journal:user_tag_member_list' identity.handle v.title %}">{{ v.title }}</a>
|
||||
</span>
|
||||
<span>({{ v.total }})</span>
|
||||
</span>
|
||||
|
|
|
@ -13,6 +13,7 @@ from common.utils import (
|
|||
AuthedHttpRequest,
|
||||
PageLinksGenerator,
|
||||
get_uuid_or_404,
|
||||
profile_identity_required,
|
||||
target_identity_required,
|
||||
)
|
||||
|
||||
|
|
|
@ -1,32 +1,42 @@
|
|||
import datetime
|
||||
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.core.exceptions import BadRequest, ObjectDoesNotExist, PermissionDenied
|
||||
from django.http import Http404, HttpResponse, HttpResponseRedirect
|
||||
from django.shortcuts import get_object_or_404, redirect, render
|
||||
from django.shortcuts import render
|
||||
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 common.utils import AuthedHttpRequest
|
||||
from users.models import APIdentity, User
|
||||
from users.views import render_user_blocked, render_user_not_found
|
||||
|
||||
from ..forms import *
|
||||
from ..models import *
|
||||
from .common import render_list, target_identity_required
|
||||
from .common import profile_identity_required, target_identity_required
|
||||
|
||||
|
||||
@require_http_methods(["GET"])
|
||||
@target_identity_required
|
||||
@profile_identity_required
|
||||
def profile(request: AuthedHttpRequest, user_name):
|
||||
target = request.target_identity
|
||||
# if user.mastodon_acct != user_name and user.username != user_name:
|
||||
# return redirect(user.url)
|
||||
if not request.user.is_authenticated and not target.anonymous_viewable:
|
||||
return render(request, "users/home_anonymous.html", {"user": target.user})
|
||||
me = target.user == request.user
|
||||
|
||||
if not request.user.is_authenticated and (
|
||||
not target.local or not target.anonymous_viewable
|
||||
):
|
||||
return render(
|
||||
request,
|
||||
"users/home_anonymous.html",
|
||||
{"identity": target, "redir": f"/account/login?next={target.url}"},
|
||||
)
|
||||
|
||||
if (target.local and user_name != target.handle) or (
|
||||
not target.local and user_name != f"@{target.handle}"
|
||||
):
|
||||
return render(
|
||||
request,
|
||||
"users/home_anonymous.html",
|
||||
{"identity": target, "redir": target.url},
|
||||
)
|
||||
|
||||
me = target.local and target.user == request.user
|
||||
|
||||
qv = q_owned_piece_visible_to_user(request.user, target)
|
||||
shelf_list = {}
|
||||
|
@ -91,6 +101,7 @@ def profile(request: AuthedHttpRequest, user_name):
|
|||
{
|
||||
"user": target.user,
|
||||
"identity": target,
|
||||
"me": me,
|
||||
"top_tags": top_tags,
|
||||
"shelf_list": shelf_list,
|
||||
"collections": collections[:10],
|
||||
|
|
|
@ -3,8 +3,8 @@ import mimetypes
|
|||
from django.conf import settings
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.contrib.syndication.views import Feed
|
||||
from django.core.exceptions import BadRequest, ObjectDoesNotExist, PermissionDenied
|
||||
from django.http import Http404, HttpResponse, HttpResponseRedirect
|
||||
from django.core.exceptions import BadRequest, PermissionDenied
|
||||
from django.http import Http404
|
||||
from django.shortcuts import get_object_or_404, redirect, render
|
||||
from django.urls import reverse
|
||||
from django.utils import timezone
|
||||
|
@ -106,7 +106,7 @@ MAX_ITEM_PER_TYPE = 10
|
|||
|
||||
class ReviewFeed(Feed):
|
||||
def get_object(self, request, *args, **kwargs):
|
||||
return APIdentity.get_by_handler(kwargs["username"])
|
||||
return APIdentity.get_by_handle(kwargs["username"])
|
||||
|
||||
def title(self, owner):
|
||||
return "%s的评论" % owner.display_name if owner else "无效链接"
|
||||
|
|
|
@ -90,7 +90,7 @@ class APIdentity(models.Model):
|
|||
|
||||
@property
|
||||
def url(self):
|
||||
return f"/users/{self.handler}/"
|
||||
return f"/users/{self.handle}/" if self.local else f"/users/@{self.handle}/"
|
||||
|
||||
@property
|
||||
def preference(self):
|
||||
|
@ -101,11 +101,11 @@ class APIdentity(models.Model):
|
|||
return f"{self.username}@{self.domain_name}"
|
||||
|
||||
@property
|
||||
def handler(self):
|
||||
def handle(self):
|
||||
if self.local:
|
||||
return self.username
|
||||
else:
|
||||
return f"@{self.username}@{self.domain_name}"
|
||||
return f"{self.username}@{self.domain_name}"
|
||||
|
||||
@property
|
||||
def following(self):
|
||||
|
@ -214,11 +214,25 @@ class APIdentity(models.Model):
|
|||
return Takahe.get_is_follow_requesting(target.pk, self.pk)
|
||||
|
||||
@classmethod
|
||||
def get_by_handler(cls, handler: str) -> "APIdentity":
|
||||
def get_remote(cls, username, domain):
|
||||
i = cls.objects.filter(
|
||||
username__iexact=username, domain_name__iexact=domain, deleted__isnull=True
|
||||
).first()
|
||||
if i:
|
||||
return i
|
||||
if domain != settings.SITE_INFO["site_domain"].lower():
|
||||
identity = Takahe.get_identity_by_handler(username, domain)
|
||||
if identity:
|
||||
return Takahe.get_or_create_remote_apidentity(identity)
|
||||
|
||||
@classmethod
|
||||
def get_by_handle(cls, handler: str, match_linked=False) -> "APIdentity":
|
||||
"""
|
||||
Handler format
|
||||
'id' - local identity with username 'id'
|
||||
'id@site' - local identity with linked mastodon id == 'id@site'
|
||||
'id@site'
|
||||
match_linked = True - local identity with linked mastodon id == 'id@site' (for backward compatibility)
|
||||
match_linked = False - remote activitypub identity 'id@site'
|
||||
'@id' - local identity with username 'id'
|
||||
'@id@site' - remote activitypub identity 'id@site'
|
||||
"""
|
||||
|
@ -231,22 +245,22 @@ class APIdentity(models.Model):
|
|||
deleted__isnull=True,
|
||||
)
|
||||
elif l == 2:
|
||||
return cls.objects.get(
|
||||
user__mastodon_username__iexact=s[0],
|
||||
user__mastodon_site__iexact=s[1],
|
||||
deleted__isnull=True,
|
||||
)
|
||||
if match_linked:
|
||||
return cls.objects.get(
|
||||
user__mastodon_username__iexact=s[0],
|
||||
user__mastodon_site__iexact=s[1],
|
||||
deleted__isnull=True,
|
||||
)
|
||||
else:
|
||||
i = cls.get_remote(s[0], s[1])
|
||||
if i:
|
||||
return i
|
||||
raise cls.DoesNotExist(f"Identity not found @{handler}")
|
||||
elif l == 3 and s[0] == "":
|
||||
i = cls.objects.filter(
|
||||
username__iexact=s[1], domain_name__iexact=s[2], deleted__isnull=True
|
||||
).first()
|
||||
i = cls.get_remote(s[1], s[2])
|
||||
if i:
|
||||
return i
|
||||
if s[2].lower() != settings.SITE_INFO["site_domain"].lower():
|
||||
identity = Takahe.get_identity_by_handler(s[1], s[2])
|
||||
if identity:
|
||||
return Takahe.get_or_create_remote_apidentity(identity)
|
||||
raise cls.DoesNotExist(f"Identity not exist {handler}")
|
||||
raise cls.DoesNotExist(f"Identity not found {handler}")
|
||||
else:
|
||||
raise cls.DoesNotExist(f"Identity handler invalid {handler}")
|
||||
|
||||
|
|
|
@ -4,21 +4,16 @@
|
|||
<html lang="zh">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="refresh"
|
||||
content="0;URL={% url 'users:login' %}?next={{ request.path }}" />
|
||||
<title>{{ site_name }} - {{ identity.handler }}</title>
|
||||
<link rel="alternate"
|
||||
type="application/rss+xml"
|
||||
title="{{ site_name }} - {{ identity.handler }}的评论"
|
||||
href="{{ request.build_absolute_uri }}feed/reviews/">
|
||||
<meta http-equiv="refresh" content="0;URL={{ redir }}" />
|
||||
<title>{{ site_name }} - {{ identity.handle }}</title>
|
||||
<meta property="og:title"
|
||||
content="{{ site_name }} - {{ identity.handler }}的主页">
|
||||
content="{{ site_name }} - {{ identity.handle }}的主页">
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:url" content="{{ request.build_absolute_uri }}">
|
||||
<meta property="og:url" content="{{ identity.url }}">
|
||||
<meta property="og:image" content="{{ identity.avatar }}">
|
||||
</head>
|
||||
<body>
|
||||
{% if identity.user.mastodon_account.url %}
|
||||
{% if identity.local and identity.user.mastodon_account.url %}
|
||||
<a href="{{ identity.user.mastodon_account.url }}"
|
||||
rel="me"
|
||||
style="display:none">Mastodon verification</a>
|
||||
|
|
|
@ -47,7 +47,7 @@
|
|||
</header>
|
||||
<div>
|
||||
{% if request.user.is_authenticated %}
|
||||
<a href="{% url 'common:home' %}" class="button">{% trans '前往首页' %}</a>
|
||||
<a href="{{ request.session.next_url | default:'/' }}" class="button">{% trans '前往首页' %}</a>
|
||||
{% else %}
|
||||
<form action="{% url 'users:connect' %}" method="post">
|
||||
{% csrf_token %}
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<span class="tag-list">
|
||||
<span><a title="点击可取消屏蔽"
|
||||
hx-confirm="确定要取消对该用户的屏蔽吗?"
|
||||
hx-post="{% url 'users:unblock' identity.handler %}"
|
||||
hx-post="{% url 'users:unblock' identity.handle %}"
|
||||
hx-target="closest .action"
|
||||
hx-swap="innerHTML">已屏蔽</a></span>
|
||||
</span>
|
||||
|
@ -46,7 +46,7 @@
|
|||
<span>
|
||||
<a title="接受关注请求"
|
||||
class="activated"
|
||||
hx-post="{% url 'users:accept_follow_request' identity.handler %}"
|
||||
hx-post="{% url 'users:accept_follow_request' identity.handle %}"
|
||||
hx-target="closest .action"
|
||||
hx-swap="innerHTML">
|
||||
<i class="fa-solid fa-check"></i>
|
||||
|
@ -55,7 +55,7 @@
|
|||
<span>
|
||||
<a title="拒绝关注请求"
|
||||
class="activated"
|
||||
hx-post="{% url 'users:reject_follow_request' identity.handler %}"
|
||||
hx-post="{% url 'users:reject_follow_request' identity.handle %}"
|
||||
hx-target="closest .action"
|
||||
hx-swap="innerHTML">
|
||||
<i class="fa-solid fa-xmark"></i>
|
||||
|
@ -66,7 +66,7 @@
|
|||
<span>
|
||||
<a title="已关注,点击可取消关注"
|
||||
class="activated"
|
||||
hx-post="{% url 'users:unfollow' identity.handler %}"
|
||||
hx-post="{% url 'users:unfollow' identity.handle %}"
|
||||
hx-target="closest .action"
|
||||
hx-swap="innerHTML">
|
||||
<i class="fa-solid fa-user-check"></i>
|
||||
|
@ -76,7 +76,7 @@
|
|||
<span>
|
||||
<a title="已发送关注请求,点击可取消"
|
||||
class="activated"
|
||||
hx-post="{% url 'users:unfollow' identity.handler %}"
|
||||
hx-post="{% url 'users:unfollow' identity.handle %}"
|
||||
hx-target="closest .action"
|
||||
hx-swap="innerHTML">
|
||||
<i class="fa-solid fa-user-clock"></i>
|
||||
|
@ -85,7 +85,7 @@
|
|||
{% else %}
|
||||
<span>
|
||||
<a title="点击可关注该用户"
|
||||
hx-post="{% url 'users:follow' identity.handler %}"
|
||||
hx-post="{% url 'users:follow' identity.handle %}"
|
||||
hx-target="closest .action"
|
||||
hx-swap="innerHTML">
|
||||
<i class="fa-solid fa-user-plus"></i>
|
||||
|
@ -95,7 +95,7 @@
|
|||
{% if not relationship.muting %}
|
||||
<span>
|
||||
<a title="点击可隐藏该用户"
|
||||
hx-post="{% url 'users:mute' identity.handler %}"
|
||||
hx-post="{% url 'users:mute' identity.handle %}"
|
||||
hx-target="closest .action"
|
||||
hx-swap="innerHTML">
|
||||
<i class="fa-solid fa-eye"></i>
|
||||
|
@ -105,7 +105,7 @@
|
|||
<span>
|
||||
<a title="已隐藏,点击可取消隐藏"
|
||||
class="activated"
|
||||
hx-post="{% url 'users:unmute' identity.handler %}"
|
||||
hx-post="{% url 'users:unmute' identity.handle %}"
|
||||
hx-target="closest .action"
|
||||
hx-swap="innerHTML">
|
||||
<i class="fa-solid fa-eye-slash"></i>
|
||||
|
@ -115,11 +115,10 @@
|
|||
<span>
|
||||
<a title="点击可屏蔽该用户"
|
||||
hx-confirm="确定要屏蔽该用户吗?"
|
||||
hx-post="{% url 'users:block' identity.handler %}"
|
||||
hx-post="{% url 'users:block' identity.handle %}"
|
||||
hx-target="closest .action"
|
||||
hx-swap="innerHTML">
|
||||
<i class="fa-solid fa-user-slash"></i>
|
||||
</a>
|
||||
</span>
|
||||
{% comment %} <span><a href="{% url 'users:report' %}?user_id={{ identity.id }}">{% trans '投诉用户' %}</a></span> {% endcomment %}
|
||||
{% endif %}
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<code class="{{ id }}_handler"
|
||||
style="cursor:pointer"
|
||||
onmouseleave="$(this).removeAttr('data-tooltip')"
|
||||
onclick="navigator.clipboard.writeText(this.innerText);$(this).data('tooltip','copied');">{{ identity.handler }}</code>
|
||||
onclick="navigator.clipboard.writeText(this.innerText);$(this).data('tooltip','copied');">@{{ identity.handle }}</code>
|
||||
</p>
|
||||
{% empty %}
|
||||
<p class="empty">无数据</p>
|
||||
|
|
|
@ -19,17 +19,17 @@ class UserTest(TestCase):
|
|||
self.domain = settings.SITE_INFO.get("site_domain")
|
||||
|
||||
def test_handle(self):
|
||||
self.assertEqual(APIdentity.get_by_handler("Alice"), self.alice)
|
||||
self.assertEqual(APIdentity.get_by_handler("@alice"), self.alice)
|
||||
self.assertEqual(APIdentity.get_by_handler("Alice@MySpace"), self.alice)
|
||||
self.assertEqual(APIdentity.get_by_handler("alice@myspace"), self.alice)
|
||||
self.assertEqual(APIdentity.get_by_handler("@alice@" + self.domain), self.alice)
|
||||
self.assertEqual(APIdentity.get_by_handler("@Alice@" + self.domain), self.alice)
|
||||
self.assertEqual(APIdentity.get_by_handle("Alice"), self.alice)
|
||||
self.assertEqual(APIdentity.get_by_handle("@alice"), self.alice)
|
||||
self.assertEqual(APIdentity.get_by_handle("Alice@MySpace", True), self.alice)
|
||||
self.assertEqual(APIdentity.get_by_handle("alice@myspace", True), self.alice)
|
||||
self.assertEqual(APIdentity.get_by_handle("@alice@" + self.domain), self.alice)
|
||||
self.assertEqual(APIdentity.get_by_handle("@Alice@" + self.domain), self.alice)
|
||||
self.assertRaises(
|
||||
APIdentity.DoesNotExist, APIdentity.get_by_handler, "@Alice@MySpace"
|
||||
APIdentity.DoesNotExist, APIdentity.get_by_handle, "@Alice@MySpace"
|
||||
)
|
||||
self.assertRaises(
|
||||
APIdentity.DoesNotExist, APIdentity.get_by_handler, "@alice@KKCity"
|
||||
APIdentity.DoesNotExist, APIdentity.get_by_handle, "@alice@KKCity"
|
||||
)
|
||||
|
||||
def test_fetch(self):
|
||||
|
|
|
@ -62,7 +62,7 @@ def render_user_noanonymous(request):
|
|||
|
||||
def query_identity(request, handle):
|
||||
try:
|
||||
i = APIdentity.get_by_handler(handle)
|
||||
i = APIdentity.get_by_handle(handle)
|
||||
return redirect(i.url)
|
||||
except APIdentity.DoesNotExist:
|
||||
if len(handle.split("@")) == 3:
|
||||
|
@ -77,7 +77,7 @@ def query_identity(request, handle):
|
|||
def fetch_refresh(request):
|
||||
handle = request.GET.get("handle", "")
|
||||
try:
|
||||
i = APIdentity.get_by_handler(handle)
|
||||
i = APIdentity.get_by_handle(handle)
|
||||
return HTTPResponseHXRedirect(i.url)
|
||||
except:
|
||||
retry = int(request.GET.get("retry", 0)) + 1
|
||||
|
@ -161,7 +161,7 @@ def unblock(request: AuthedHttpRequest, user_name):
|
|||
if request.method != "POST":
|
||||
raise BadRequest()
|
||||
try:
|
||||
target = APIdentity.get_by_handler(user_name)
|
||||
target = APIdentity.get_by_handle(user_name)
|
||||
except APIdentity.DoesNotExist:
|
||||
return render_user_not_found(request)
|
||||
target_user = target.user
|
||||
|
|
Loading…
Add table
Reference in a new issue