use gavatar for email only user; fix a few edge cases
This commit is contained in:
parent
fbb4bbc437
commit
94016315ef
15 changed files with 105 additions and 52 deletions
3
common/static/img/avatar.svg
Normal file
3
common/static/img/avatar.svg
Normal file
|
@ -0,0 +1,3 @@
|
|||
<svg height="100%" stroke-miterlimit="10" version="1.1" viewBox="0 0 12800 12306.1" width="100%" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<path d="M6665.58 702.124C6684.58 704.116 6749.59 711.092 6810.59 717.068C7510.61 783.8 8240.72 1069.52 8810.89 1499.3C9043.95 1674.21 9345.07 1964.1 9518.15 2180.03C10227.5 3063.76 10534.9 4173.64 10376.3 5279.7C10240.7 6225.75 9773.03 7096.93 9068.27 7718.2C8927.32 7842.26 8728.38 7993.33 8590.41 8083.39L8497.44 8143.42L8550.44 8155.4C8692.45 8188.35 9022.49 8280.22 9178.51 8331.16C10845.7 8868.52 12075.1 9861.05 12564.6 11062.9C12714.7 11431.8 12799.9 11850.8 12800 12223.8C12800 12328.8 0.0415832 12334.7 0.00285795 12233.7C-0.118302 11917.7 59.7467 11565.7 166.627 11253.6C602.138 9977.45 1831.74 8926.98 3563.51 8352.31C3755.49 8288.24 4124.45 8182.1 4228.44 8162.06C4247.44 8158.05 4269.44 8152.04 4276.44 8148.04C4283.44 8144.04 4235.42 8105.06 4146.4 8044.09C3770.3 7790.23 3455.18 7490.36 3186.05 7132.46C3089 7003.5 3000.95 6870.53 2944.91 6771.55C2920.89 6728.56 2878.86 6654.58 2852.85 6607.59C2784.8 6489.61 2690.72 6279.65 2623.65 6100.67C2381.4 5445.77 2316.12 4726.79 2436.85 4022.75C2510.69 3591.72 2678.51 3122.65 2897.36 2733.57C2981.3 2585.54 3146.21 2342.47 3262.16 2197.43C3400.09 2024.38 3702.97 1721.26 3875.92 1583.19C4015.88 1471.14 4261.81 1304.05 4400.78 1224.99C4777.7 1011.85 5189.64 856.69 5610.61 771.528C5860.59 720.432 6020.58 705.371 6335.58 701.25C6497.58 699.188 6646.58 700.131 6665.58 702.124Z" fill="#646b79" fill-rule="nonzero" opacity="1" stroke="none"/>
|
||||
</svg>
|
After Width: | Height: | Size: 1.6 KiB |
|
@ -59,19 +59,19 @@
|
|||
<summary aria-haspopup="listbox">
|
||||
<span class="avatar">
|
||||
<img alt=""
|
||||
src="{% if request.user.is_authenticated %}{{ request.user.mastodon_account.avatar }}{% else %}data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw=={% endif %}" />
|
||||
src="{% if request.user.is_authenticated %}{{ request.user.avatar }}{% else %}{% static 'img/avatar.svg' %}{% endif %}" />
|
||||
</span>
|
||||
</summary>
|
||||
<ul role="listbox" style="min-width:-webkit-max-content;" dir="rtl">
|
||||
{% if request.user.is_authenticated %}
|
||||
<li>
|
||||
<a href="{% url 'users:data' %}">数据管理</a>
|
||||
<a href="{% url 'users:data' %}">数据</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{% url 'users:preferences' %}">使用设置</a>
|
||||
<a href="{% url 'users:preferences' %}">设置</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{% url 'users:info' %}">账号信息</a>
|
||||
<a href="{% url 'users:info' %}">账号</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{% url 'users:logout' %}">登出</a>
|
||||
|
@ -92,14 +92,19 @@
|
|||
</ul>
|
||||
</nav>
|
||||
</header>
|
||||
{% comment %}
|
||||
{% if request.user.is_authenticated and not request.user.username %}
|
||||
<ul class="messages" style="text-align:center">
|
||||
<li class="error">
|
||||
请<a href="{% url 'users:info' %}">设置用户名</a>
|
||||
</li>
|
||||
</ul>
|
||||
{% endif %}
|
||||
{% endcomment %}
|
||||
{% if messages %}
|
||||
<div class="main-section-wrapper"
|
||||
style="margin-bottom: 10px;
|
||||
text-align:center">
|
||||
<ul class="messages">
|
||||
{% for message in messages %}
|
||||
<li {% if message.tags %}class="{{ message.tags }}"{% endif %}>{{ message }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
<ul class="messages" style="text-align:center">
|
||||
{% for message in messages %}
|
||||
<li {% if message.tags %}class="{{ message.tags }}"{% endif %}>{{ message }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
|
|
|
@ -40,7 +40,7 @@
|
|||
<div class="avatar">
|
||||
<a href="{{ user.url }}" onclick="window.location = this.href">
|
||||
{% comment %} onclick to workaround webkit issue with <a /> in <summary /> {% endcomment %}
|
||||
<img src="{{ user.mastodon_account.avatar }}" alt="">
|
||||
<img src="{{ user.avatar }}" alt="">
|
||||
</a>
|
||||
</div>
|
||||
<div>
|
||||
|
|
|
@ -55,7 +55,7 @@
|
|||
<div class="owner-info">
|
||||
<div class="owner">
|
||||
<span class="avatar">
|
||||
<img src="{{ collection.owner.mastodon_account.avatar }}"
|
||||
<img src="{{ collection.owner.avatar }}"
|
||||
alt="{{ collection.owner.display_name }}">
|
||||
</span>
|
||||
</div>
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
{% endif %}
|
||||
<meta property="og:title" content="{{ site_name }}用户 - @{{ user.handler }}">
|
||||
<meta property="og:url" content="{{ request.build_absolute_uri }}">
|
||||
<meta property="og:image" content="{{ user.mastodon_account.avatar }}">
|
||||
<meta property="og:image" content="{{ user.avatar }}">
|
||||
<meta property="og:site_name" content="{{ site_name }}">
|
||||
{% if user.preference.no_anonymous_view %}<meta name="robots" content="noindex">{% endif %}
|
||||
<link rel="alternate"
|
||||
|
|
|
@ -51,8 +51,7 @@
|
|||
<div class="owner-info">
|
||||
<div class="owner">
|
||||
<span class="avatar">
|
||||
<img src="{{ review.owner.mastodon_account.avatar }}"
|
||||
alt="{{ review.owner.display_name }}">
|
||||
<img src="{{ review.owner.avatar }}" alt="{{ review.owner.display_name }}">
|
||||
</span>
|
||||
</div>
|
||||
<div class="info">
|
||||
|
|
|
@ -82,7 +82,7 @@ urlpatterns = [
|
|||
name="collection_remove_featured",
|
||||
),
|
||||
re_path(
|
||||
r"^users/(?P<user_name>[A-Za-z0-9_\-.@]+)/(?P<shelf_type>"
|
||||
r"^users/(?P<user_name>[~A-Za-z0-9_\-.@]+)/(?P<shelf_type>"
|
||||
+ _get_all_shelf_types()
|
||||
+ ")/(?P<item_category>"
|
||||
+ _get_all_categories()
|
||||
|
@ -91,14 +91,14 @@ urlpatterns = [
|
|||
name="user_mark_list",
|
||||
),
|
||||
re_path(
|
||||
r"^users/(?P<user_name>[A-Za-z0-9_\-.@]+)/reviews/(?P<item_category>"
|
||||
r"^users/(?P<user_name>[~A-Za-z0-9_\-.@]+)/reviews/(?P<item_category>"
|
||||
+ _get_all_categories()
|
||||
+ ")/$",
|
||||
user_review_list,
|
||||
name="user_review_list",
|
||||
),
|
||||
re_path(
|
||||
r"^users/(?P<user_name>[A-Za-z0-9_\-.@]+)/tags/(?P<tag_title>.+)/$",
|
||||
r"^users/(?P<user_name>[~A-Za-z0-9_\-.@]+)/tags/(?P<tag_title>.+)/$",
|
||||
user_tag_member_list,
|
||||
name="user_tag_member_list",
|
||||
),
|
||||
|
@ -108,23 +108,25 @@ urlpatterns = [
|
|||
name="user_tag_edit",
|
||||
),
|
||||
re_path(
|
||||
r"^users/(?P<user_name>[A-Za-z0-9_\-.@]+)/collections/$",
|
||||
r"^users/(?P<user_name>[~A-Za-z0-9_\-.@]+)/collections/$",
|
||||
user_collection_list,
|
||||
name="user_collection_list",
|
||||
),
|
||||
re_path(
|
||||
r"^users/(?P<user_name>[A-Za-z0-9_\-.@]+)/like/collections/$",
|
||||
r"^users/(?P<user_name>[~A-Za-z0-9_\-.@]+)/like/collections/$",
|
||||
user_liked_collection_list,
|
||||
name="user_liked_collection_list",
|
||||
),
|
||||
re_path(
|
||||
r"^users/(?P<user_name>[A-Za-z0-9_\-.@]+)/tags/$",
|
||||
r"^users/(?P<user_name>[~A-Za-z0-9_\-.@]+)/tags/$",
|
||||
user_tag_list,
|
||||
name="user_tag_list",
|
||||
),
|
||||
re_path(r"^users/(?P<user_name>[A-Za-z0-9_\-.@]+)/$", profile, name="user_profile"),
|
||||
re_path(
|
||||
r"^users/(?P<user_name>[A-Za-z0-9_\-.@]+)/calendar_data$",
|
||||
r"^users/(?P<user_name>[~A-Za-z0-9_\-.@]+)/$", profile, name="user_profile"
|
||||
),
|
||||
re_path(
|
||||
r"^users/(?P<user_name>[~A-Za-z0-9_\-.@]+)/calendar_data$",
|
||||
user_calendar_data,
|
||||
name="user_calendar_data",
|
||||
),
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
{% for activity in activities %}
|
||||
<section class="activity">
|
||||
<div class="avatar">
|
||||
<img src="{{ activity.owner.mastodon_account.avatar }}" alt="cover">
|
||||
<img src="{{ activity.owner.avatar }}" alt="cover">
|
||||
</div>
|
||||
<div>
|
||||
<div>
|
||||
|
|
|
@ -180,7 +180,9 @@ def OAuth2_login(request):
|
|||
return render(request, "common/error.html", {"msg": _("联邦宇宙访问失败😫")})
|
||||
return register_new_user(
|
||||
request,
|
||||
username=None,
|
||||
username=None
|
||||
if settings.MASTODON_ALLOW_ANY_SITE
|
||||
else user_data["username"],
|
||||
mastodon_username=user_data["username"],
|
||||
mastodon_id=user_data["id"],
|
||||
mastodon_site=site,
|
||||
|
@ -251,7 +253,6 @@ class RegistrationForm(forms.ModelForm):
|
|||
def send_verification_link(user_id, action, email):
|
||||
s = {"i": user_id, "e": email, "a": action}
|
||||
v = TimestampSigner().sign_object(s) # type: ignore
|
||||
site = settings.SITE_INFO["site_name"]
|
||||
if action == "verify":
|
||||
subject = f'{settings.SITE_INFO["site_name"]} - {_("验证电子邮件地址")}'
|
||||
url = settings.SITE_INFO["site_url"] + "/account/verify_email?c=" + v
|
||||
|
@ -263,15 +264,16 @@ def send_verification_link(user_id, action, email):
|
|||
elif action == "register":
|
||||
subject = f'{settings.SITE_INFO["site_name"]} - {_("注册新账号")}'
|
||||
url = settings.SITE_INFO["site_url"] + "/account/register_email?c=" + v
|
||||
msg = f"你好,\n{site}还没有与{email}关联的账号。你希望注册一个新账号吗?\n"
|
||||
msg += f"如果你已经注册过{site}或联邦宇宙(长毛象),不必重新注册,只要用联邦宇宙身份登录{site},再关联这个电子邮件地址,未来就可以通过邮件登录。\n"
|
||||
msg = f"你好,\n本站没有与{email}关联的账号。你希望注册一个新账号吗?\n"
|
||||
msg += f"如果你已经注册过本站或联邦宇宙(长毛象),不必重新注册,只要用联邦宇宙身份登录本站,再关联这个电子邮件地址,未来就可以通过邮件登录。\n"
|
||||
msg += f"\n如果你还没有联邦宇宙身份,可以访问这里选择实例并创建一个: https://joinmastodon.org/zh/servers\n"
|
||||
if settings.ALLOW_EMAIL_ONLY_ACCOUNT:
|
||||
msg += f"\n如果你不便使用联邦宇宙身份,可以点击以下链接注册新的{site}账号,以后再关联到联邦宇宙。\n{url}\n"
|
||||
msg += f"\n如果你不便使用联邦宇宙身份,可以点击以下链接注册新的本站账号,以后再关联到联邦宇宙。\n{url}\n"
|
||||
msg += f"\n如果你没有打算用此电子邮件地址注册或登录本站,请忽略此邮件。"
|
||||
else:
|
||||
raise ValueError("Invalid action")
|
||||
try:
|
||||
logger.info(f"Sending email to {email} with subject {subject}")
|
||||
send_mail(
|
||||
subject=subject,
|
||||
message=msg,
|
||||
|
@ -287,6 +289,13 @@ def verify_email(request):
|
|||
error = ""
|
||||
try:
|
||||
s = TimestampSigner().unsign_object(request.GET.get("c"), max_age=60 * 15) # type: ignore
|
||||
except Exception as e:
|
||||
logger.error(e)
|
||||
error = _("链接无效或已过期")
|
||||
return render(
|
||||
request, "users/verify_email.html", {"success": False, "error": error}
|
||||
)
|
||||
try:
|
||||
email = s["e"]
|
||||
action = s["a"]
|
||||
if action == "verify":
|
||||
|
@ -314,7 +323,8 @@ def verify_email(request):
|
|||
else:
|
||||
return register_new_user(request, username=None, email=email)
|
||||
except Exception as e:
|
||||
error = _("链接已失效")
|
||||
logger.error(e)
|
||||
error = _("无法完成验证")
|
||||
return render(
|
||||
request, "users/verify_email.html", {"success": False, "error": error}
|
||||
)
|
||||
|
@ -426,7 +436,7 @@ def swap_login(request, token, site, refresh_token):
|
|||
]
|
||||
)
|
||||
django_rq.get_queue("mastodon").enqueue(
|
||||
refresh_mastodon_data_task, current_user, token
|
||||
refresh_mastodon_data_task, current_user.pk, token
|
||||
)
|
||||
messages.add_message(
|
||||
request, messages.INFO, _(f"账号身份已更新为 {username}@{site}。")
|
||||
|
@ -443,7 +453,7 @@ def auth_login(request, user):
|
|||
user.mastodon_last_refresh < timezone.now() - timedelta(hours=1)
|
||||
or user.mastodon_account == {}
|
||||
):
|
||||
django_rq.get_queue("mastodon").enqueue(refresh_mastodon_data_task, user)
|
||||
django_rq.get_queue("mastodon").enqueue(refresh_mastodon_data_task, user.pk)
|
||||
|
||||
|
||||
def auth_logout(request):
|
||||
|
@ -465,7 +475,8 @@ def clear_data(request):
|
|||
if request.META.get("HTTP_AUTHORIZATION"):
|
||||
raise BadRequest("Only for web login")
|
||||
if request.method == "POST":
|
||||
if request.POST.get("verification") == request.user.mastodon_acct:
|
||||
v = request.POST.get("verification")
|
||||
if v and (v == request.user.mastodon_acct or v == request.user.email):
|
||||
django_rq.get_queue("mastodon").enqueue(clear_data_task, request.user.id)
|
||||
auth_logout(request)
|
||||
return redirect(reverse("users:login"))
|
||||
|
|
|
@ -118,9 +118,9 @@ def export_marks(request):
|
|||
|
||||
@login_required
|
||||
def sync_mastodon(request):
|
||||
if request.method == "POST":
|
||||
if request.method == "POST" and request.user.mastodon_username:
|
||||
django_rq.get_queue("mastodon").enqueue(
|
||||
refresh_mastodon_data_task, request.user
|
||||
refresh_mastodon_data_task, request.user.pk
|
||||
)
|
||||
messages.add_message(request, messages.INFO, _("同步已开始。"))
|
||||
return redirect(reverse("users:data"))
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
import django.contrib.auth.validators
|
||||
from django.db import migrations, models
|
||||
import users.models
|
||||
from django.conf import settings
|
||||
|
||||
|
||||
def move_username(apps, schema_editor):
|
||||
|
@ -16,7 +17,7 @@ def move_username(apps, schema_editor):
|
|||
def clear_username(apps, schema_editor):
|
||||
User = apps.get_model("users", "User")
|
||||
for u in User.objects.all():
|
||||
u.username = None
|
||||
u.username = None if settings.ALLOW_ANY_SITE else u.mastodon_username
|
||||
u.save()
|
||||
|
||||
|
||||
|
|
|
@ -13,6 +13,8 @@ from management.models import Announcement
|
|||
from mastodon.api import *
|
||||
from django.urls import reverse
|
||||
from django.db.models import Q
|
||||
from django.templatetags.static import static
|
||||
import hashlib
|
||||
|
||||
|
||||
RESERVED_USERNAMES = [
|
||||
|
@ -122,6 +124,19 @@ class User(AbstractUser):
|
|||
else (self.username or self.mastodon_acct or "")
|
||||
)
|
||||
|
||||
@property
|
||||
def avatar(self):
|
||||
if self.mastodon_account:
|
||||
return self.mastodon_account.get("avatar") or static(
|
||||
"static/img/avatar.svg"
|
||||
)
|
||||
if self.email:
|
||||
return (
|
||||
"https://www.gravatar.com/avatar/"
|
||||
+ hashlib.md5(self.email.lower().encode()).hexdigest()
|
||||
)
|
||||
return static("static/img/avatar.svg")
|
||||
|
||||
@property
|
||||
def handler(self):
|
||||
return self.mastodon_acct or self.username or f"~{self.pk}"
|
||||
|
@ -142,13 +157,13 @@ class User(AbstractUser):
|
|||
def clear(self):
|
||||
if self.mastodon_site == "removed" and not self.is_active:
|
||||
return
|
||||
self.first_name = self.mastodon_username
|
||||
self.last_name = self.mastodon_site
|
||||
self.first_name = self.mastodon_acct or ""
|
||||
self.last_name = self.email or ""
|
||||
self.is_active = False
|
||||
self.email = None
|
||||
# self.username = "~removed~" + str(self.pk)
|
||||
# to get ready for federation, username has to be reserved
|
||||
self.mastodon_username = "~removed~" + str(self.pk)
|
||||
self.mastodon_username = None
|
||||
self.mastodon_id = None
|
||||
self.mastodon_site = "removed"
|
||||
self.mastodon_token = ""
|
||||
|
@ -275,14 +290,19 @@ class User(AbstractUser):
|
|||
def get(cls, name):
|
||||
if isinstance(name, str):
|
||||
sp = name.split("@")
|
||||
if len(sp) == 1:
|
||||
if name.startswith("~"):
|
||||
try:
|
||||
query_kwargs = {"pk": int(name[1:])}
|
||||
except:
|
||||
return None
|
||||
elif len(sp) == 1:
|
||||
query_kwargs = {"username": name}
|
||||
elif len(sp) == 2:
|
||||
query_kwargs = {"mastodon_username": sp[0], "mastodon_site": sp[1]}
|
||||
else:
|
||||
return None
|
||||
elif isinstance(id, int):
|
||||
query_kwargs = {"pk": id}
|
||||
elif isinstance(name, int):
|
||||
query_kwargs = {"pk": name}
|
||||
else:
|
||||
return None
|
||||
return User.objects.filter(**query_kwargs).first()
|
||||
|
|
|
@ -1,11 +1,17 @@
|
|||
from django.conf import settings
|
||||
from .models import User
|
||||
from loguru import logger
|
||||
|
||||
|
||||
def refresh_mastodon_data_task(user, token=None):
|
||||
def refresh_mastodon_data_task(user_id, token=None):
|
||||
user = User.objects.get(pk=user_id)
|
||||
if not user.mastodon_username:
|
||||
logger.info(f"{user} mastodon data refresh skipped")
|
||||
return
|
||||
if token:
|
||||
user.mastodon_token = token
|
||||
if user.refresh_mastodon_data():
|
||||
user.save()
|
||||
print(f"{user} mastodon data refreshed")
|
||||
logger.info(f"{user} mastodon data refreshed")
|
||||
else:
|
||||
print(f"{user} mastodon data refresh failed")
|
||||
logger.error(f"{user} mastodon data refresh failed")
|
||||
|
|
|
@ -82,8 +82,12 @@
|
|||
method="post"
|
||||
enctype="multipart/form-data">
|
||||
{% csrf_token %}
|
||||
<input type="submit" value="{% trans '同步' %}" id="uploadBtn" />
|
||||
上次更新时间 {{ user.mastodon_last_refresh }}
|
||||
<input type="submit"
|
||||
value="{% trans '同步' %}"
|
||||
{% if not request.user.mastodon_username %}disabled{% endif %} />
|
||||
<small>
|
||||
{% if user.mastodon_last_refresh %}上次更新时间 {{ user.mastodon_last_refresh }}{% endif %}
|
||||
</small>
|
||||
<div>
|
||||
为了正确高效的展示短评和评论,{{ site_name }}会缓存你在联邦宇宙的关注、屏蔽和静音列表。如果你刚刚更新过帐户的上锁状态、增减过关注、静音或屏蔽,希望立即生效,可以点击这里立刻更新;这类信息也会每天自动同步。
|
||||
</div>
|
||||
|
@ -98,11 +102,12 @@
|
|||
onsubmit="return confirm('账号数据一旦删除后将无法恢复。确认删除吗?');">
|
||||
{% csrf_token %}
|
||||
<div>
|
||||
输入完整的 <code>用户名@实例名</code> 以确认删除
|
||||
<input type="input"
|
||||
输入完整的 <code>用户名@实例名</code> 或 <code>电子邮件地址</code> 以确认删除
|
||||
<input type="email"
|
||||
name="verification"
|
||||
_="on input remove [@disabled] from #delete end"
|
||||
value=""
|
||||
autocomplete="off"
|
||||
required
|
||||
aria-invalid="true"
|
||||
aria-describedby="invalid-helper"
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
</p>
|
||||
{% else %}
|
||||
<p>
|
||||
{{ error }}
|
||||
链接无效或已过期,<a href="{% url 'users:login' %}">点击这里重新登录</a>。
|
||||
</p>
|
||||
{% endif %}
|
||||
|
|
Loading…
Add table
Reference in a new issue