diff --git a/users/account.py b/users/account.py
index 1984eba9..58b1728d 100644
--- a/users/account.py
+++ b/users/account.py
@@ -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"))
diff --git a/users/data.py b/users/data.py
index 8fbec52c..c4ad7b53 100644
--- a/users/data.py
+++ b/users/data.py
@@ -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"))
diff --git a/users/migrations/0005_add_dedicated_username.py b/users/migrations/0005_add_dedicated_username.py
index 5b2a6644..5b23f2d9 100644
--- a/users/migrations/0005_add_dedicated_username.py
+++ b/users/migrations/0005_add_dedicated_username.py
@@ -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()
diff --git a/users/models.py b/users/models.py
index 54805247..7638b011 100644
--- a/users/models.py
+++ b/users/models.py
@@ -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()
diff --git a/users/tasks.py b/users/tasks.py
index 93f2df4c..c3f4abfc 100644
--- a/users/tasks.py
+++ b/users/tasks.py
@@ -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")
diff --git a/users/templates/users/account.html b/users/templates/users/account.html
index 87deabd7..e29ae127 100644
--- a/users/templates/users/account.html
+++ b/users/templates/users/account.html
@@ -82,8 +82,12 @@
method="post"
enctype="multipart/form-data">
{% csrf_token %}
-
- 上次更新时间 {{ user.mastodon_last_refresh }}
+
+
+ {% if user.mastodon_last_refresh %}上次更新时间 {{ user.mastodon_last_refresh }}{% endif %}
+
为了正确高效的展示短评和评论,{{ site_name }}会缓存你在联邦宇宙的关注、屏蔽和静音列表。如果你刚刚更新过帐户的上锁状态、增减过关注、静音或屏蔽,希望立即生效,可以点击这里立刻更新;这类信息也会每天自动同步。
@@ -98,11 +102,12 @@
onsubmit="return confirm('账号数据一旦删除后将无法恢复。确认删除吗?');">
{% csrf_token %}
- 输入完整的
用户名@实例名
以确认删除
-
用户名@实例名 或
电子邮件地址
以确认删除
+
{% else %}
+ {{ error }}
链接无效或已过期,点击这里重新登录。
{% endif %}