diff --git a/boofilsic/settings.py b/boofilsic/settings.py
index bb66dcfa..6e7cc88d 100644
--- a/boofilsic/settings.py
+++ b/boofilsic/settings.py
@@ -104,7 +104,8 @@ env = environ.FileAwareEnv(
SLACK_API_TOKEN=(str, ""),
THREADS_APP_ID=(str, ""),
THREADS_APP_SECRET=(str, ""),
- BLUESKY_LOGIN_ENABLED=(bool, False),
+ NEODB_ENABLE_LOGIN_BLUESKY=(bool, False),
+ NEODB_ENABLE_LOGIN_THREADS=(bool, False),
# SSL only, better be True for production security
SSL_ONLY=(bool, False),
NEODB_SENTRY_DSN=(str, ""),
@@ -181,7 +182,8 @@ else:
THREADS_APP_ID = env("THREADS_APP_ID")
THREADS_APP_SECRET = env("THREADS_APP_SECRET")
-BLUESKY_LOGIN_ENABLED = env("BLUESKY_LOGIN_ENABLED")
+ENABLE_LOGIN_BLUESKY = env("NEODB_ENABLE_LOGIN_BLUESKY")
+ENABLE_LOGIN_THREADS = env("NEODB_ENABLE_LOGIN_THREADS")
SITE_DOMAIN = env("NEODB_SITE_DOMAIN").lower()
SITE_INFO = {
diff --git a/common/templates/_sidebar.html b/common/templates/_sidebar.html
index 07046028..3c87aba8 100644
--- a/common/templates/_sidebar.html
+++ b/common/templates/_sidebar.html
@@ -54,26 +54,7 @@
{% endif %}
- {% if identity.user.mastodon %}
-
-
-
-
-
- {% endif %}
- {% if identity.user.threads %}
-
-
-
-
-
- {% endif %}
+ {% include "users/_profile_social_icons.html" %}
{% elif request.user.is_authenticated %}
{% include 'users/profile_actions.html' %}
{% endif %}
diff --git a/common/views.py b/common/views.py
index d01e8e67..6f4d3cfb 100644
--- a/common/views.py
+++ b/common/views.py
@@ -1,7 +1,7 @@
from django.conf import settings
from django.contrib.auth.decorators import login_required
from django.core.cache import cache
-from django.http import JsonResponse
+from django.http import HttpRequest, JsonResponse
from django.shortcuts import redirect, render
from django.urls import reverse
@@ -11,7 +11,7 @@ from takahe.utils import Takahe
from .api import api
-def render_error(request, title, message=""):
+def render_error(request: HttpRequest, title, message=""):
return render(
request, "common/error.html", {"msg": title, "secondary_msg": message}
)
diff --git a/compose.yml b/compose.yml
index f8b10751..21752232 100644
--- a/compose.yml
+++ b/compose.yml
@@ -43,6 +43,8 @@ x-shared:
NEODB_EMAIL_URL:
NEODB_EMAIL_FROM: no-reply@${NEODB_SITE_DOMAIN}
NEODB_ENABLE_LOCAL_ONLY:
+ NEODB_ENABLE_LOGIN_BLUESKY:
+ NEODB_ENABLE_LOGIN_THREADS:
NEODB_EXTRA_APPS:
NEODB_FANOUT_LIMIT_DAYS:
TAKAHE_FANOUT_LIMIT_DAYS:
@@ -69,7 +71,6 @@ x-shared:
TAKAHE_VENV: /takahe-venv
THREADS_APP_ID:
THREADS_APP_SECRET:
- BLUESKY_LOGIN_ENABLED:
SPOTIFY_API_KEY:
TMDB_API_V3_KEY:
GOOGLE_API_KEY:
diff --git a/journal/models/common.py b/journal/models/common.py
index 71ebf50f..76e4a7ac 100644
--- a/journal/models/common.py
+++ b/journal/models/common.py
@@ -9,7 +9,7 @@ import django_rq
# from deepmerge import always_merger
from django.conf import settings
-from django.core.exceptions import PermissionDenied
+from django.core.exceptions import PermissionDenied, RequestAborted
from django.core.signing import b62_decode, b62_encode
from django.db import models
from django.db.models import CharField, Q
@@ -309,7 +309,7 @@ class Piece(PolymorphicModel, UserOwnedObjectMixin):
return
try:
r = threads.post(**params)
- except Exception:
+ except RequestAborted:
logger.warning(f"{self} post to {threads} failed")
messages.error(threads.user, _("A recent post was not posted to Threads."))
return False
@@ -338,9 +338,8 @@ class Piece(PolymorphicModel, UserOwnedObjectMixin):
mastodon = self.owner.user.mastodon
if not mastodon:
return False
- r = mastodon.post(**params)
try:
- pass
+ r = mastodon.post(**params)
except PermissionDenied:
messages.error(
mastodon.user,
@@ -348,7 +347,7 @@ class Piece(PolymorphicModel, UserOwnedObjectMixin):
meta={"url": mastodon.get_reauthorize_url()},
)
return False
- except Exception:
+ except RequestAborted:
logger.warning(f"{self} post to {mastodon} failed")
messages.error(
mastodon.user, _("A recent post was not posted to Mastodon.")
diff --git a/locale/zh_Hans/LC_MESSAGES/django.po b/locale/zh_Hans/LC_MESSAGES/django.po
index 33c56d3a..3461246d 100644
--- a/locale/zh_Hans/LC_MESSAGES/django.po
+++ b/locale/zh_Hans/LC_MESSAGES/django.po
@@ -6,7 +6,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2024-07-03 16:40-0400\n"
+"POT-Creation-Date: 2024-07-04 00:13-0400\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME \n"
"Language-Team: LANGUAGE \n"
@@ -15,15 +15,15 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-#: boofilsic/settings.py:406
+#: boofilsic/settings.py:408
msgid "English"
msgstr "英语"
-#: boofilsic/settings.py:407
+#: boofilsic/settings.py:409
msgid "Simplified Chinese"
msgstr "简体中文"
-#: boofilsic/settings.py:408
+#: boofilsic/settings.py:410
msgid "Traditional Chinese"
msgstr "繁体中文"
@@ -1108,8 +1108,7 @@ msgstr "热门标签"
#: catalog/templates/discover.html:177 catalog/templates/item_base.html:236
#: catalog/templates/item_mark_list.html:54
-#: catalog/templates/item_review_list.html:50
-#: common/templates/_sidebar.html:109
+#: catalog/templates/item_review_list.html:50 common/templates/_sidebar.html:90
#: common/templates/_sidebar_anonymous.html:43
#: common/templates/_sidebar_anonymous.html:58
#: journal/templates/collection_items.html:8 journal/templates/posts.html:49
@@ -1472,7 +1471,7 @@ msgstr "开发者"
msgid "Source Code"
msgstr "源代码"
-#: common/templates/_footer.html:16 users/templates/users/login.html:173
+#: common/templates/_footer.html:16 users/templates/users/login.html:191
#, python-format
msgid "You are visiting an alternative domain for %(site_name)s, please always use original version if possible."
msgstr "这是%(site_name)s的临时镜像,请尽可能使用原始站点。"
@@ -1545,50 +1544,50 @@ msgstr "打开"
msgid "approving followers manually"
msgstr "已开启关注审核"
-#: common/templates/_sidebar.html:94
+#: common/templates/_sidebar.html:75
msgid "Current Targets"
msgstr "当前目标"
-#: common/templates/_sidebar.html:107
+#: common/templates/_sidebar.html:88
msgid "Set a collection as target, its progress will show up here."
msgstr "将自己或他人的收藏单设为目标,这里就会显示进度"
-#: common/templates/_sidebar.html:120
+#: common/templates/_sidebar.html:101
msgid "Recent podcast episodes"
msgstr "近期播客节目"
-#: common/templates/_sidebar.html:155
+#: common/templates/_sidebar.html:136
msgid "Currently reading"
msgstr "正在阅读"
-#: common/templates/_sidebar.html:178
+#: common/templates/_sidebar.html:159
msgid "Currently watching"
msgstr "正在追看"
-#: common/templates/_sidebar.html:201 journal/templates/user_tag_list.html:12
+#: common/templates/_sidebar.html:182 journal/templates/user_tag_list.html:12
#: journal/templates/user_tagmember_list.html:4
msgid "Tags"
msgstr "标签"
-#: common/templates/_sidebar.html:207 journal/templates/user_tag_list.html:26
+#: common/templates/_sidebar.html:188 journal/templates/user_tag_list.html:26
#: journal/templates/user_tagmember_list.html:10
msgid "featured tag"
msgstr "置顶标签"
-#: common/templates/_sidebar.html:210 journal/templates/user_tag_list.html:29
+#: common/templates/_sidebar.html:191 journal/templates/user_tag_list.html:29
#: journal/templates/user_tagmember_list.html:15
msgid "personal tag"
msgstr "个人标签"
-#: common/templates/_sidebar.html:217 journal/templates/user_tag_list.html:37
+#: common/templates/_sidebar.html:198 journal/templates/user_tag_list.html:37
msgid "no tags so far."
msgstr "暂无标签。"
-#: common/templates/_sidebar.html:221
+#: common/templates/_sidebar.html:202
msgid "show all"
msgstr "显示全部"
-#: common/templates/_sidebar.html:231
+#: common/templates/_sidebar.html:212
msgid "Recent Posts"
msgstr "近期帖文"
@@ -1746,11 +1745,11 @@ msgstr "自己和提到的人"
msgid "A recent post was not posted to Threads."
msgstr "帖文未能发布到Threads。"
-#: journal/models/common.py:347
+#: journal/models/common.py:346
msgid "A recent post was not posted to Mastodon, please re-authorize."
msgstr "帖文未能发布到联邦实例,请重新验证登录。"
-#: journal/models/common.py:354
+#: journal/models/common.py:353
msgid "A recent post was not posted to Mastodon."
msgstr "帖文未能发布到联邦实例。"
@@ -2781,7 +2780,7 @@ msgstr "Mastodon"
msgid "Threads"
msgstr "Threads"
-#: mastodon/models/common.py:14 users/templates/users/login.html:83
+#: mastodon/models/common.py:14
msgid "Bluesky"
msgstr "Bluesky"
@@ -2879,47 +2878,63 @@ msgstr "转播"
msgid "New Post"
msgstr "新帖文"
+#: mastodon/views/bluesky.py:22 mastodon/views/bluesky.py:28
#: mastodon/views/common.py:29 mastodon/views/mastodon.py:37
#: mastodon/views/mastodon.py:44 mastodon/views/mastodon.py:54
-#: mastodon/views/mastodon.py:61 mastodon/views/threads.py:40
-#: mastodon/views/threads.py:45 users/views/account.py:104
+#: mastodon/views/mastodon.py:61 mastodon/views/threads.py:41
+#: mastodon/views/threads.py:47 users/views/account.py:104
msgid "Authentication failed"
msgstr "认证失败"
-#: mastodon/views/common.py:29 mastodon/views/common.py:79
+#: mastodon/views/bluesky.py:23
+msgid "Username and app password is required."
+msgstr "请输入用户名和密码。"
+
+#: mastodon/views/bluesky.py:28
+msgid "Invalid account data from Bluesky."
+msgstr "Bluesky返回了无效的账号数据。"
+
+#: mastodon/views/common.py:29 mastodon/views/common.py:94
msgid "Invalid user."
msgstr "无效用户。"
-#: mastodon/views/common.py:44
+#: mastodon/views/common.py:45
msgid "Registration failed"
msgstr "注册失败"
-#: mastodon/views/common.py:44
+#: mastodon/views/common.py:45
msgid "User already logged in."
msgstr "用户已经登录了。"
-#: mastodon/views/common.py:52
-msgid "Unable to update login information: identical identity."
-msgstr "无法更新登录信息:该身份与当前账号相同。"
+#: mastodon/views/common.py:57
+#, python-brace-format
+msgid "Continue login as {handle}."
+msgstr "继续以 {handle} 登录。"
-#: mastodon/views/common.py:56
-msgid "Unable to update login information: identity in use."
-msgstr "无法更新登录信息:该身份已被其它账号使用。"
+#: mastodon/views/common.py:63
+msgid "Unable to update login information"
+msgstr "无法更新登录信息"
-#: mastodon/views/common.py:70
-msgid "Login information updated."
-msgstr "登录信息已更新"
+#: mastodon/views/common.py:64
+#, python-brace-format
+msgid "Identity {handle} in use by a different user."
+msgstr "身份 {handle} 已被其它账号使用。"
-#: mastodon/views/common.py:77 mastodon/views/common.py:79
-#: mastodon/views/common.py:83
+#: mastodon/views/common.py:80
+#, python-brace-format
+msgid "Login information updated as {handle}."
+msgstr "登录信息已更新为{handle}。"
+
+#: mastodon/views/common.py:90 mastodon/views/common.py:94
+#: mastodon/views/common.py:100
msgid "Disconnect identity failed"
msgstr "未能取消身份关联"
-#: mastodon/views/common.py:77
+#: mastodon/views/common.py:90
msgid "Identity not found."
msgstr "身份未找到"
-#: mastodon/views/common.py:84
+#: mastodon/views/common.py:101
msgid "You cannot disconnect last login identity."
msgstr "无法取消唯一的登录用身份。"
@@ -2967,7 +2982,7 @@ msgstr "联邦实例返回了无效的认证令牌。"
msgid "Invalid account data from Fediverse instance."
msgstr "联邦实例返回了无效的账号数据。"
-#: mastodon/views/threads.py:45
+#: mastodon/views/threads.py:47
msgid "Invalid account data from Threads."
msgstr "Threads返回了无效的账号数据。"
@@ -3305,7 +3320,8 @@ msgid "Verified Identity"
msgstr "已验证的身份"
#: users/templates/users/account.html:86 users/templates/users/account.html:147
-#: users/templates/users/account.html:209
+#: users/templates/users/account.html:183
+#: users/templates/users/account.html:263
msgid "Last updated"
msgstr "最近更新"
@@ -3335,6 +3351,7 @@ msgstr "关联联邦宇宙身份后可发现更多用户,并使用本站完整
#: users/templates/users/account.html:123
#: users/templates/users/account.html:159
+#: users/templates/users/account.html:213
msgid "Once disconnected, you will no longer be able login with this identity. Are you sure to continue?"
msgstr "取消关联后将无法使用这个身份登录本站,确认继续吗?"
@@ -3362,75 +3379,107 @@ msgstr "关联一个threads.net账号"
msgid "Disconnect with Threads"
msgstr "取消关联"
-#: users/templates/users/account.html:171
+#: users/templates/users/account.html:170 users/templates/users/login.html:83
+msgid "Bluesky (ATProto)"
+msgstr "Bluesky (ATProto)"
+
+#: users/templates/users/account.html:176
+msgid "Verified ATProto identity"
+msgstr "已验证的ATProto身份"
+
+#: users/templates/users/account.html:192 users/templates/users/login.html:151
+msgid "Bluesky Login ID"
+msgstr "Bluesky 登录名"
+
+#: users/templates/users/account.html:200 users/templates/users/login.html:159
+msgid "Bluesky app password"
+msgstr "Bluesky 应用密码"
+
+#: users/templates/users/account.html:206
+msgid "Link with a different ATProto identity"
+msgstr "关联另一个ATProto身份"
+
+#: users/templates/users/account.html:206
+msgid "Link with an ATProto identity"
+msgstr "关联ATProto身份"
+
+#: users/templates/users/account.html:207 users/templates/users/login.html:164
+msgid "App password can be created on bsky.app."
+msgstr "应用密码可在 bsky.app 创建管理。"
+
+#: users/templates/users/account.html:216
+msgid "Disconnect with ATProto identity"
+msgstr "取消关联"
+
+#: users/templates/users/account.html:225
msgid "Sync and import social account"
msgstr "同步第三方社交网络上的个人信息和社交数据"
-#: users/templates/users/account.html:181
+#: users/templates/users/account.html:235
msgid "Sync display name, bio and avatar"
msgstr "自动同步用户昵称等基本信息"
-#: users/templates/users/account.html:189
+#: users/templates/users/account.html:243
msgid "Sync follow, mute and block"
msgstr "自动导入新增的关注、屏蔽和隐藏列表"
-#: users/templates/users/account.html:193
+#: users/templates/users/account.html:247
msgid "Save sync settings"
msgstr "保存同步设置"
-#: users/templates/users/account.html:196
+#: users/templates/users/account.html:250
msgid "New follow, mute and blocks in the associated identity may be automatically imported; removal has to be done manually."
msgstr "本站会按照以上设置每天自动导入你在联邦宇宙实例等社交网络中新增的关注、屏蔽和隐藏列表;如果你在联邦宇宙实例中关注的用户加入了本站,你会自动关注她;如果你在联邦宇宙实例中取消了关注、屏蔽或隐藏,本站不会自动取消,但你可以手动移除。"
-#: users/templates/users/account.html:203
+#: users/templates/users/account.html:257
msgid "Click button below to start sync now."
msgstr "如果希望立即开始同步,可以点击下方按钮。"
-#: users/templates/users/account.html:205
+#: users/templates/users/account.html:259
msgid "Sync now"
msgstr "立即同步"
-#: users/templates/users/account.html:217
+#: users/templates/users/account.html:271
msgid "Users you are following"
msgstr "正在关注的用户"
-#: users/templates/users/account.html:223
+#: users/templates/users/account.html:277
msgid "Users who follow you"
msgstr "关注了你的用户"
-#: users/templates/users/account.html:229
+#: users/templates/users/account.html:283
msgid "Users who request to follow you"
msgstr "请求关注你的用户"
-#: users/templates/users/account.html:235
+#: users/templates/users/account.html:289
msgid "Users you are muting"
msgstr "已隐藏的用户"
-#: users/templates/users/account.html:241
+#: users/templates/users/account.html:295
msgid "Users you are blocking"
msgstr "已屏蔽的用户"
-#: users/templates/users/account.html:248
+#: users/templates/users/account.html:302
msgid "Delete Account"
msgstr "删除账号"
-#: users/templates/users/account.html:251
+#: users/templates/users/account.html:305
msgid "Once deleted, account data cannot be recovered. Sure to proceed?"
msgstr "账号数据一旦删除后将无法恢复,确定继续吗?"
-#: users/templates/users/account.html:254
+#: users/templates/users/account.html:308
msgid "Enter full username@instance.social or email@domain.com to confirm deletion."
msgstr "输入完整的登录用 用户名@实例名 或 电子邮件地址 以确认删除"
-#: users/templates/users/account.html:264
+#: users/templates/users/account.html:318
msgid "Once deleted, account data cannot be recovered."
msgstr "账号数据一旦删除后将无法恢复"
-#: users/templates/users/account.html:266
+#: users/templates/users/account.html:320
msgid "Importing in progress, can't delete now."
msgstr "暂时无法删除,因为有导入任务正在进行"
-#: users/templates/users/account.html:269
+#: users/templates/users/account.html:323
msgid "Permanently Delete"
msgstr "永久删除"
@@ -3586,7 +3635,7 @@ msgstr "实例域名(不含@和@之前的部分),如mastodon.social"
msgid "Please enter domain of your instance; e.g. if your id is @neodb@mastodon.social, only enter mastodon.social."
msgstr "请输入你的实例域名(不含@和@之前的部分);如果你的联邦账号是@neodb@mastodon.social,只需要在此输入mastodon.social。"
-#: users/templates/users/login.html:125 users/templates/users/login.html:156
+#: users/templates/users/login.html:125 users/templates/users/login.html:174
msgid "Authorize via Fediverse instance"
msgstr "去联邦实例授权注册或登录"
@@ -3602,35 +3651,35 @@ msgstr "去Threads授权注册或登录"
msgid "If you have already account here registered via a different way, you may login through there and link with your Threads account in account settings."
msgstr "如果你已通过其它方式注册过本站帐号,请用该方式登录后再关联Threads。"
-#: users/templates/users/login.html:147
-msgid "Authorize via Bluesky"
-msgstr "去Bluesky授权注册或登录"
+#: users/templates/users/login.html:165
+msgid "Authorize via bsky.app"
+msgstr "使用Bluesky账号信息注册或登录"
-#: users/templates/users/login.html:148
+#: users/templates/users/login.html:166
msgid "If you have already account here registered via a different way, you may login through there and link with your Bluesky account in account settings."
msgstr "如果你已通过其它方式注册过本站帐号,请用该方式登录后再关联Bluesky。"
-#: users/templates/users/login.html:163
+#: users/templates/users/login.html:181
msgid "Valid invitation code, please login or register."
msgstr "邀请链接有效,可注册新用户"
-#: users/templates/users/login.html:165
+#: users/templates/users/login.html:183
msgid "Please use invitation link to register a new account; existing user may login."
msgstr "本站目前为邀请注册,已有账户可直接登入,新用户请使用有效邀请链接注册"
-#: users/templates/users/login.html:167
+#: users/templates/users/login.html:185
msgid "Invitation code invalid or expired."
msgstr "邀请链接无效,已有账户可直接登入,新用户请使用有效邀请链接注册"
-#: users/templates/users/login.html:175
+#: users/templates/users/login.html:193
msgid "Loading timed out, please check your network (VPN) settings."
msgstr "部分模块加载超时,请检查网络(翻墙)设置。"
-#: users/templates/users/login.html:181
+#: users/templates/users/login.html:199
msgid "Continue using this site implies consent to our rules and terms, including using cookies to provide necessary functionality."
msgstr "继续访问或注册视为同意站规与协议,及使用cookie提供必要功能"
-#: users/templates/users/login.html:187
+#: users/templates/users/login.html:205
msgid "Domain of your instance (excl. @)"
msgstr "实例域名(不含@和@之前的部分)"
@@ -3786,59 +3835,59 @@ msgstr "用户资料"
msgid "original home"
msgstr "原始主页"
-#: users/templates/users/profile_actions.html:82
+#: users/templates/users/profile_actions.html:63
msgid "accept follow request"
msgstr "接受关注请求"
-#: users/templates/users/profile_actions.html:84
+#: users/templates/users/profile_actions.html:65
msgid "sure to accept follow request?"
msgstr "确定接受关注请求吗?"
-#: users/templates/users/profile_actions.html:92
+#: users/templates/users/profile_actions.html:73
msgid "reject follow request"
msgstr "拒绝关注请求"
-#: users/templates/users/profile_actions.html:94
+#: users/templates/users/profile_actions.html:75
msgid "sure to reject follow request?"
msgstr "确定拒绝关注请求吗?"
-#: users/templates/users/profile_actions.html:104
+#: users/templates/users/profile_actions.html:85
msgid "click to unfollow"
msgstr "点击可取消关注"
-#: users/templates/users/profile_actions.html:106
+#: users/templates/users/profile_actions.html:87
msgid "sure to unfollow?"
msgstr "确定取消关注该用户吗?"
-#: users/templates/users/profile_actions.html:115
+#: users/templates/users/profile_actions.html:96
msgid "click to cancel follow request"
msgstr "点击可取消关注请求"
-#: users/templates/users/profile_actions.html:117
+#: users/templates/users/profile_actions.html:98
msgid "sure to cancel follow request?"
msgstr "确定取消关注请求吗?"
-#: users/templates/users/profile_actions.html:126
+#: users/templates/users/profile_actions.html:107
msgid "click to follow"
msgstr "点击可关注"
-#: users/templates/users/profile_actions.html:127
+#: users/templates/users/profile_actions.html:108
msgid "sure to follow?"
msgstr "确定关注该用户吗?"
-#: users/templates/users/profile_actions.html:137
+#: users/templates/users/profile_actions.html:118
msgid "click to mute"
msgstr "点击可静音"
-#: users/templates/users/profile_actions.html:146
+#: users/templates/users/profile_actions.html:127
msgid "click to unmute"
msgstr "点击可取消静音"
-#: users/templates/users/profile_actions.html:156
+#: users/templates/users/profile_actions.html:137
msgid "click to block"
msgstr "点击可屏蔽"
-#: users/templates/users/profile_actions.html:157
+#: users/templates/users/profile_actions.html:138
msgid "sure to block?"
msgstr "确定屏蔽该用户吗?"
diff --git a/locale/zh_Hant/LC_MESSAGES/django.po b/locale/zh_Hant/LC_MESSAGES/django.po
index 1ea334c2..50d46d84 100644
--- a/locale/zh_Hant/LC_MESSAGES/django.po
+++ b/locale/zh_Hant/LC_MESSAGES/django.po
@@ -6,7 +6,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2024-07-03 16:40-0400\n"
+"POT-Creation-Date: 2024-07-04 00:13-0400\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME \n"
"Language-Team: LANGUAGE \n"
@@ -15,15 +15,15 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-#: boofilsic/settings.py:406
+#: boofilsic/settings.py:408
msgid "English"
msgstr "英語"
-#: boofilsic/settings.py:407
+#: boofilsic/settings.py:409
msgid "Simplified Chinese"
msgstr "簡體中文"
-#: boofilsic/settings.py:408
+#: boofilsic/settings.py:410
msgid "Traditional Chinese"
msgstr "繁體中文"
@@ -1108,8 +1108,7 @@ msgstr "熱門標籤"
#: catalog/templates/discover.html:177 catalog/templates/item_base.html:236
#: catalog/templates/item_mark_list.html:54
-#: catalog/templates/item_review_list.html:50
-#: common/templates/_sidebar.html:109
+#: catalog/templates/item_review_list.html:50 common/templates/_sidebar.html:90
#: common/templates/_sidebar_anonymous.html:43
#: common/templates/_sidebar_anonymous.html:58
#: journal/templates/collection_items.html:8 journal/templates/posts.html:49
@@ -1472,7 +1471,7 @@ msgstr "開發者"
msgid "Source Code"
msgstr "源代碼"
-#: common/templates/_footer.html:16 users/templates/users/login.html:173
+#: common/templates/_footer.html:16 users/templates/users/login.html:191
#, python-format
msgid "You are visiting an alternative domain for %(site_name)s, please always use original version if possible."
msgstr "這是%(site_name)s的臨時鏡像,請儘可能使用原始站點。"
@@ -1545,50 +1544,50 @@ msgstr "打開"
msgid "approving followers manually"
msgstr "已開啓關注審覈"
-#: common/templates/_sidebar.html:94
+#: common/templates/_sidebar.html:75
msgid "Current Targets"
msgstr "當前目標"
-#: common/templates/_sidebar.html:107
+#: common/templates/_sidebar.html:88
msgid "Set a collection as target, its progress will show up here."
msgstr "將自己或他人的收藏單設爲目標,這裏就會顯示進度"
-#: common/templates/_sidebar.html:120
+#: common/templates/_sidebar.html:101
msgid "Recent podcast episodes"
msgstr "近期播客節目"
-#: common/templates/_sidebar.html:155
+#: common/templates/_sidebar.html:136
msgid "Currently reading"
msgstr "正在閱讀"
-#: common/templates/_sidebar.html:178
+#: common/templates/_sidebar.html:159
msgid "Currently watching"
msgstr "正在追看"
-#: common/templates/_sidebar.html:201 journal/templates/user_tag_list.html:12
+#: common/templates/_sidebar.html:182 journal/templates/user_tag_list.html:12
#: journal/templates/user_tagmember_list.html:4
msgid "Tags"
msgstr "標籤"
-#: common/templates/_sidebar.html:207 journal/templates/user_tag_list.html:26
+#: common/templates/_sidebar.html:188 journal/templates/user_tag_list.html:26
#: journal/templates/user_tagmember_list.html:10
msgid "featured tag"
msgstr "置頂標籤"
-#: common/templates/_sidebar.html:210 journal/templates/user_tag_list.html:29
+#: common/templates/_sidebar.html:191 journal/templates/user_tag_list.html:29
#: journal/templates/user_tagmember_list.html:15
msgid "personal tag"
msgstr "個人標籤"
-#: common/templates/_sidebar.html:217 journal/templates/user_tag_list.html:37
+#: common/templates/_sidebar.html:198 journal/templates/user_tag_list.html:37
msgid "no tags so far."
msgstr "暫無標籤。"
-#: common/templates/_sidebar.html:221
+#: common/templates/_sidebar.html:202
msgid "show all"
msgstr "顯示全部"
-#: common/templates/_sidebar.html:231
+#: common/templates/_sidebar.html:212
msgid "Recent Posts"
msgstr "近期帖文"
@@ -1746,11 +1745,11 @@ msgstr "自己和提到的人"
msgid "A recent post was not posted to Threads."
msgstr "帖文未能發佈到Threads。"
-#: journal/models/common.py:347
+#: journal/models/common.py:346
msgid "A recent post was not posted to Mastodon, please re-authorize."
msgstr "帖文未能發佈到聯邦實例,請重新驗證登錄。"
-#: journal/models/common.py:354
+#: journal/models/common.py:353
msgid "A recent post was not posted to Mastodon."
msgstr "帖文未能發佈到聯邦實例。"
@@ -2781,7 +2780,7 @@ msgstr "Mastodon"
msgid "Threads"
msgstr "Threads"
-#: mastodon/models/common.py:14 users/templates/users/login.html:83
+#: mastodon/models/common.py:14
msgid "Bluesky"
msgstr "Bluesky"
@@ -2879,47 +2878,63 @@ msgstr "轉播"
msgid "New Post"
msgstr "新帖文"
+#: mastodon/views/bluesky.py:22 mastodon/views/bluesky.py:28
#: mastodon/views/common.py:29 mastodon/views/mastodon.py:37
#: mastodon/views/mastodon.py:44 mastodon/views/mastodon.py:54
-#: mastodon/views/mastodon.py:61 mastodon/views/threads.py:40
-#: mastodon/views/threads.py:45 users/views/account.py:104
+#: mastodon/views/mastodon.py:61 mastodon/views/threads.py:41
+#: mastodon/views/threads.py:47 users/views/account.py:104
msgid "Authentication failed"
msgstr "認證失敗"
-#: mastodon/views/common.py:29 mastodon/views/common.py:79
+#: mastodon/views/bluesky.py:23
+msgid "Username and app password is required."
+msgstr "請輸入用戶名和密碼。"
+
+#: mastodon/views/bluesky.py:28
+msgid "Invalid account data from Bluesky."
+msgstr "Bluesky返回了無效的賬號數據。"
+
+#: mastodon/views/common.py:29 mastodon/views/common.py:94
msgid "Invalid user."
msgstr "無效用戶。"
-#: mastodon/views/common.py:44
+#: mastodon/views/common.py:45
msgid "Registration failed"
msgstr "註冊失敗"
-#: mastodon/views/common.py:44
+#: mastodon/views/common.py:45
msgid "User already logged in."
msgstr "用戶已經登錄了。"
-#: mastodon/views/common.py:52
-msgid "Unable to update login information: identical identity."
-msgstr "無法更新登錄信息:該身份與當前賬號相同。"
+#: mastodon/views/common.py:57
+#, python-brace-format
+msgid "Continue login as {handle}."
+msgstr "繼續以 {handle} 登錄。"
-#: mastodon/views/common.py:56
-msgid "Unable to update login information: identity in use."
-msgstr "無法更新登錄信息:該身份已被其它賬號使用。"
+#: mastodon/views/common.py:63
+msgid "Unable to update login information"
+msgstr "無法更新登錄信息"
-#: mastodon/views/common.py:70
-msgid "Login information updated."
-msgstr "登錄信息已更新"
+#: mastodon/views/common.py:64
+#, python-brace-format
+msgid "Identity {handle} in use by a different user."
+msgstr "身份 {handle} 已被其它賬號使用。"
-#: mastodon/views/common.py:77 mastodon/views/common.py:79
-#: mastodon/views/common.py:83
+#: mastodon/views/common.py:80
+#, python-brace-format
+msgid "Login information updated as {handle}."
+msgstr "登錄信息已更新爲{handle}。"
+
+#: mastodon/views/common.py:90 mastodon/views/common.py:94
+#: mastodon/views/common.py:100
msgid "Disconnect identity failed"
msgstr "未能取消身份關聯"
-#: mastodon/views/common.py:77
+#: mastodon/views/common.py:90
msgid "Identity not found."
msgstr "身份未找到"
-#: mastodon/views/common.py:84
+#: mastodon/views/common.py:101
msgid "You cannot disconnect last login identity."
msgstr "無法取消唯一的登錄用身份。"
@@ -2967,7 +2982,7 @@ msgstr "聯邦實例返回了無效的認證令牌。"
msgid "Invalid account data from Fediverse instance."
msgstr "聯邦實例返回了無效的賬號數據。"
-#: mastodon/views/threads.py:45
+#: mastodon/views/threads.py:47
msgid "Invalid account data from Threads."
msgstr "Threads返回了無效的賬號數據。"
@@ -3305,7 +3320,8 @@ msgid "Verified Identity"
msgstr "已驗證的身份"
#: users/templates/users/account.html:86 users/templates/users/account.html:147
-#: users/templates/users/account.html:209
+#: users/templates/users/account.html:183
+#: users/templates/users/account.html:263
msgid "Last updated"
msgstr "最近更新"
@@ -3335,6 +3351,7 @@ msgstr "關聯聯邦宇宙身份後可發現更多用戶,並使用本站完整
#: users/templates/users/account.html:123
#: users/templates/users/account.html:159
+#: users/templates/users/account.html:213
msgid "Once disconnected, you will no longer be able login with this identity. Are you sure to continue?"
msgstr "取消關聯後將無法使用這個身份登錄本站,確認繼續嗎?"
@@ -3362,75 +3379,107 @@ msgstr "關聯一個threads.net賬號"
msgid "Disconnect with Threads"
msgstr "取消關聯"
-#: users/templates/users/account.html:171
+#: users/templates/users/account.html:170 users/templates/users/login.html:83
+msgid "Bluesky (ATProto)"
+msgstr "Bluesky (ATProto)"
+
+#: users/templates/users/account.html:176
+msgid "Verified ATProto identity"
+msgstr "已驗證的ATProto身份"
+
+#: users/templates/users/account.html:192 users/templates/users/login.html:151
+msgid "Bluesky Login ID"
+msgstr "Bluesky 登錄名"
+
+#: users/templates/users/account.html:200 users/templates/users/login.html:159
+msgid "Bluesky app password"
+msgstr "Bluesky 應用密碼"
+
+#: users/templates/users/account.html:206
+msgid "Link with a different ATProto identity"
+msgstr "關聯另一個ATProto身份"
+
+#: users/templates/users/account.html:206
+msgid "Link with an ATProto identity"
+msgstr "關聯ATProto身份"
+
+#: users/templates/users/account.html:207 users/templates/users/login.html:164
+msgid "App password can be created on bsky.app."
+msgstr "應用密碼可在 bsky.app 創建管理。"
+
+#: users/templates/users/account.html:216
+msgid "Disconnect with ATProto identity"
+msgstr "取消關聯"
+
+#: users/templates/users/account.html:225
msgid "Sync and import social account"
msgstr "同步第三方社交網絡上的個人信息和社交數據"
-#: users/templates/users/account.html:181
+#: users/templates/users/account.html:235
msgid "Sync display name, bio and avatar"
msgstr "自動同步用戶暱稱等基本信息"
-#: users/templates/users/account.html:189
+#: users/templates/users/account.html:243
msgid "Sync follow, mute and block"
msgstr "自動導入新增的關注、屏蔽和隱藏列表"
-#: users/templates/users/account.html:193
+#: users/templates/users/account.html:247
msgid "Save sync settings"
msgstr "保存同步設置"
-#: users/templates/users/account.html:196
+#: users/templates/users/account.html:250
msgid "New follow, mute and blocks in the associated identity may be automatically imported; removal has to be done manually."
msgstr "本站會按照以上設置每天自動導入你在聯邦宇宙實例等社交網絡中新增的關注、屏蔽和隱藏列表;如果你在聯邦宇宙實例中關注的用戶加入了本站,你會自動關注她;如果你在聯邦宇宙實例中取消了關注、屏蔽或隱藏,本站不會自動取消,但你可以手動移除。"
-#: users/templates/users/account.html:203
+#: users/templates/users/account.html:257
msgid "Click button below to start sync now."
msgstr "如果希望立即開始同步,可以點擊下方按鈕。"
-#: users/templates/users/account.html:205
+#: users/templates/users/account.html:259
msgid "Sync now"
msgstr "立即同步"
-#: users/templates/users/account.html:217
+#: users/templates/users/account.html:271
msgid "Users you are following"
msgstr "正在關注的用戶"
-#: users/templates/users/account.html:223
+#: users/templates/users/account.html:277
msgid "Users who follow you"
msgstr "關注了你的用戶"
-#: users/templates/users/account.html:229
+#: users/templates/users/account.html:283
msgid "Users who request to follow you"
msgstr "請求關注你的用戶"
-#: users/templates/users/account.html:235
+#: users/templates/users/account.html:289
msgid "Users you are muting"
msgstr "已隱藏的用戶"
-#: users/templates/users/account.html:241
+#: users/templates/users/account.html:295
msgid "Users you are blocking"
msgstr "已屏蔽的用戶"
-#: users/templates/users/account.html:248
+#: users/templates/users/account.html:302
msgid "Delete Account"
msgstr "刪除賬號"
-#: users/templates/users/account.html:251
+#: users/templates/users/account.html:305
msgid "Once deleted, account data cannot be recovered. Sure to proceed?"
msgstr "賬號數據一旦刪除後將無法恢復,確定繼續嗎?"
-#: users/templates/users/account.html:254
+#: users/templates/users/account.html:308
msgid "Enter full username@instance.social or email@domain.com to confirm deletion."
msgstr "輸入完整的登錄用 用戶名@實例名 或 電子郵件地址 以確認刪除"
-#: users/templates/users/account.html:264
+#: users/templates/users/account.html:318
msgid "Once deleted, account data cannot be recovered."
msgstr "賬號數據一旦刪除後將無法恢復"
-#: users/templates/users/account.html:266
+#: users/templates/users/account.html:320
msgid "Importing in progress, can't delete now."
msgstr "暫時無法刪除,因爲有導入任務正在進行"
-#: users/templates/users/account.html:269
+#: users/templates/users/account.html:323
msgid "Permanently Delete"
msgstr "永久刪除"
@@ -3586,7 +3635,7 @@ msgstr "實例域名(不含@和@之前的部分),如mastodon.social"
msgid "Please enter domain of your instance; e.g. if your id is @neodb@mastodon.social, only enter mastodon.social."
msgstr "請輸入你的實例域名(不含@和@之前的部分);如果你的聯邦賬號是@neodb@mastodon.social,只需要在此輸入mastodon.social。"
-#: users/templates/users/login.html:125 users/templates/users/login.html:156
+#: users/templates/users/login.html:125 users/templates/users/login.html:174
msgid "Authorize via Fediverse instance"
msgstr "去聯邦實例授權註冊或登錄"
@@ -3602,35 +3651,35 @@ msgstr "去Threads授權註冊或登錄"
msgid "If you have already account here registered via a different way, you may login through there and link with your Threads account in account settings."
msgstr "如果你已通過其它方式註冊過本站帳號,請用該方式登錄後再關聯Threads。"
-#: users/templates/users/login.html:147
-msgid "Authorize via Bluesky"
-msgstr "去Bluesky授權註冊或登錄"
+#: users/templates/users/login.html:165
+msgid "Authorize via bsky.app"
+msgstr "使用Bluesky賬號信息註冊或登錄"
-#: users/templates/users/login.html:148
+#: users/templates/users/login.html:166
msgid "If you have already account here registered via a different way, you may login through there and link with your Bluesky account in account settings."
msgstr "如果你已通過其它方式註冊過本站帳號,請用該方式登錄後再關聯Bluesky。"
-#: users/templates/users/login.html:163
+#: users/templates/users/login.html:181
msgid "Valid invitation code, please login or register."
msgstr "邀請鏈接有效,可註冊新用戶"
-#: users/templates/users/login.html:165
+#: users/templates/users/login.html:183
msgid "Please use invitation link to register a new account; existing user may login."
msgstr "本站目前爲邀請註冊,已有賬戶可直接登入,新用戶請使用有效邀請鏈接註冊"
-#: users/templates/users/login.html:167
+#: users/templates/users/login.html:185
msgid "Invitation code invalid or expired."
msgstr "邀請鏈接無效,已有賬戶可直接登入,新用戶請使用有效邀請鏈接註冊"
-#: users/templates/users/login.html:175
+#: users/templates/users/login.html:193
msgid "Loading timed out, please check your network (VPN) settings."
msgstr "部分模塊加載超時,請檢查網絡(翻牆)設置。"
-#: users/templates/users/login.html:181
+#: users/templates/users/login.html:199
msgid "Continue using this site implies consent to our rules and terms, including using cookies to provide necessary functionality."
msgstr "繼續訪問或註冊視爲同意站規與協議,及使用cookie提供必要功能"
-#: users/templates/users/login.html:187
+#: users/templates/users/login.html:205
msgid "Domain of your instance (excl. @)"
msgstr "實例域名(不含@和@之前的部分)"
@@ -3786,59 +3835,59 @@ msgstr "用戶資料"
msgid "original home"
msgstr "原始主頁"
-#: users/templates/users/profile_actions.html:82
+#: users/templates/users/profile_actions.html:63
msgid "accept follow request"
msgstr "接受關注請求"
-#: users/templates/users/profile_actions.html:84
+#: users/templates/users/profile_actions.html:65
msgid "sure to accept follow request?"
msgstr "確定接受關注請求嗎?"
-#: users/templates/users/profile_actions.html:92
+#: users/templates/users/profile_actions.html:73
msgid "reject follow request"
msgstr "拒絕關注請求"
-#: users/templates/users/profile_actions.html:94
+#: users/templates/users/profile_actions.html:75
msgid "sure to reject follow request?"
msgstr "確定拒絕關注請求嗎?"
-#: users/templates/users/profile_actions.html:104
+#: users/templates/users/profile_actions.html:85
msgid "click to unfollow"
msgstr "點擊可取消關注"
-#: users/templates/users/profile_actions.html:106
+#: users/templates/users/profile_actions.html:87
msgid "sure to unfollow?"
msgstr "確定取消關注該用戶嗎?"
-#: users/templates/users/profile_actions.html:115
+#: users/templates/users/profile_actions.html:96
msgid "click to cancel follow request"
msgstr "點擊可取消關注請求"
-#: users/templates/users/profile_actions.html:117
+#: users/templates/users/profile_actions.html:98
msgid "sure to cancel follow request?"
msgstr "確定取消關注請求嗎?"
-#: users/templates/users/profile_actions.html:126
+#: users/templates/users/profile_actions.html:107
msgid "click to follow"
msgstr "點擊可關注"
-#: users/templates/users/profile_actions.html:127
+#: users/templates/users/profile_actions.html:108
msgid "sure to follow?"
msgstr "確定關注該用戶嗎?"
-#: users/templates/users/profile_actions.html:137
+#: users/templates/users/profile_actions.html:118
msgid "click to mute"
msgstr "點擊可靜音"
-#: users/templates/users/profile_actions.html:146
+#: users/templates/users/profile_actions.html:127
msgid "click to unmute"
msgstr "點擊可取消靜音"
-#: users/templates/users/profile_actions.html:156
+#: users/templates/users/profile_actions.html:137
msgid "click to block"
msgstr "點擊可屏蔽"
-#: users/templates/users/profile_actions.html:157
+#: users/templates/users/profile_actions.html:138
msgid "sure to block?"
msgstr "確定屏蔽該用戶嗎?"
diff --git a/mastodon/models/bluesky.py b/mastodon/models/bluesky.py
index e9f28fe2..da9f08c4 100644
--- a/mastodon/models/bluesky.py
+++ b/mastodon/models/bluesky.py
@@ -1,15 +1,91 @@
+from functools import cached_property
+
+from atproto import Client, SessionEvent, client_utils
+from django.utils import timezone
+from loguru import logger
+
from catalog.common import jsondata
from .common import SocialAccount
class Bluesky:
- pass
+ BASE_DOMAIN = "bsky.app" # TODO support alternative servers
+
+ @staticmethod
+ def authenticate(username: str, password: str) -> "BlueskyAccount | None":
+ try:
+ client = Client()
+ profile = client.login(username, password)
+ session_string = client.export_session_string()
+ except Exception as e:
+ logger.debug(f"Bluesky login {username} exception {e}")
+ return None
+ existing_account = BlueskyAccount.objects.filter(
+ uid=profile.did, domain=Bluesky.BASE_DOMAIN
+ ).first()
+ if existing_account:
+ existing_account.session_string = session_string
+ existing_account.save(update_fields=["access_data"])
+ existing_account.refresh(save=True, profile=profile)
+ return existing_account
+ account = BlueskyAccount(uid=profile.did, domain=Bluesky.BASE_DOMAIN)
+ account.session_string = session_string
+ account.refresh(save=False, profile=profile)
+ return account
class BlueskyAccount(SocialAccount):
- app_username = jsondata.CharField(json_field_name="access_data", default="")
- app_password = jsondata.EncryptedTextField(
+ # app_username = jsondata.CharField(json_field_name="access_data", default="")
+ # app_password = jsondata.EncryptedTextField(
+ # json_field_name="access_data", default=""
+ # )
+ session_string = jsondata.EncryptedTextField(
json_field_name="access_data", default=""
)
- pass
+
+ def on_session_change(self, event, session) -> None:
+ logger.debug("Bluesky session changed:", event, repr(session))
+ if event in (SessionEvent.CREATE, SessionEvent.REFRESH):
+ session_string = session.export()
+ if session_string != self.session_string:
+ self.session_string = session_string
+ if self.pk:
+ self.save(update_fields=["access_data"])
+
+ @cached_property
+ def _client(self):
+ client = Client()
+ client.on_session_change(self.on_session_change)
+ self._profile = client.login(session_string=self.session_string)
+ return client
+
+ @property
+ def url(self):
+ return f"https://bsky.app/profile/{self.handle}"
+
+ def refresh(self, save=True, profile=None):
+ if not profile:
+ _ = self._client
+ profile = self._profile
+ self.handle = profile.handle
+ self.account_data = {
+ k: v for k, v in profile.__dict__.items() if isinstance(v, (int, str))
+ }
+ self.last_refresh = timezone.now()
+ self.last_reachable = self.last_refresh
+ if save:
+ self.save(
+ update_fields=[
+ "account_data",
+ "handle",
+ "last_refresh",
+ "last_reachable",
+ ]
+ )
+
+ def post(self, content):
+ text = client_utils.TextBuilder().text(content)
+ # .link("Python SDK", "https://atproto.blue")
+ post = self._client.send_post(text)
+ return {"id": post.cid, "url": post.uri}
diff --git a/mastodon/models/common.py b/mastodon/models/common.py
index dbbcb4dd..42a7fae5 100644
--- a/mastodon/models/common.py
+++ b/mastodon/models/common.py
@@ -83,6 +83,8 @@ class SocialAccount(TypedModel):
if k
not in [
"_state",
+ "_client",
+ "_profile",
"api_domain",
"created",
"modified",
diff --git a/mastodon/models/mastodon.py b/mastodon/models/mastodon.py
index 1e8238e7..3de96b82 100644
--- a/mastodon/models/mastodon.py
+++ b/mastodon/models/mastodon.py
@@ -851,7 +851,7 @@ class MastodonAccount(SocialAccount):
spoiler_text,
attachments,
)
- if response:
+ if response is not None:
if response.status_code in [200, 201]:
j = response.json()
return {"id": j["id"], "url": j["url"]}
@@ -864,4 +864,4 @@ class MastodonAccount(SocialAccount):
# TODO
def get_reauthorize_url(self):
- return reverse("mastodon:connect") + "?domain=" + self.domain
+ return reverse("mastodon:login") + "?domain=" + self.domain
diff --git a/mastodon/urls.py b/mastodon/urls.py
index 9291c296..2d00eeb9 100644
--- a/mastodon/urls.py
+++ b/mastodon/urls.py
@@ -20,4 +20,7 @@ urlpatterns = [
path("threads/uninstall", threads_uninstall, name="threads_uninstall"),
path("threads/delete", threads_delete, name="threads_delete"),
# Bluesky
+ path("bluesky/login", bluesky_login, name="bluesky_login"),
+ path("bluesky/reconnect", bluesky_reconnect, name="bluesky_reconnect"),
+ path("bluesky/disconnect", bluesky_disconnect, name="bluesky_disconnect"),
]
diff --git a/mastodon/views/__init__.py b/mastodon/views/__init__.py
index 032dd573..febebbdf 100644
--- a/mastodon/views/__init__.py
+++ b/mastodon/views/__init__.py
@@ -1,3 +1,4 @@
+from .bluesky import *
from .email import *
from .mastodon import *
from .threads import *
diff --git a/mastodon/views/bluesky.py b/mastodon/views/bluesky.py
new file mode 100644
index 00000000..6e565c1a
--- /dev/null
+++ b/mastodon/views/bluesky.py
@@ -0,0 +1,44 @@
+from django.contrib.auth.decorators import login_required
+from django.http import HttpRequest
+from django.shortcuts import redirect
+from django.urls import reverse
+from django.utils.translation import gettext as _
+from django.views.decorators.http import require_http_methods
+
+from common.views import render_error
+from mastodon.models import bluesky
+
+from ..models import Bluesky
+from .common import disconnect_identity, process_verified_account
+
+
+@require_http_methods(["POST"])
+def bluesky_login(request: HttpRequest):
+ username = request.POST.get("username", "").strip()
+ password = request.POST.get("password", "").strip()
+ if not username or not password:
+ return render_error(
+ request,
+ _("Authentication failed"),
+ _("Username and app password is required."),
+ )
+ account = Bluesky.authenticate(username, password)
+ if not account:
+ return render_error(
+ request, _("Authentication failed"), _("Invalid account data from Bluesky.")
+ )
+ return process_verified_account(request, account)
+
+
+@require_http_methods(["POST"])
+@login_required
+def bluesky_reconnect(request: HttpRequest):
+ """link another bluesky to an existing logged-in user"""
+ return bluesky_login(request)
+
+
+@require_http_methods(["POST"])
+@login_required
+def bluesky_disconnect(request):
+ """unlink bluesky from an existing logged-in user"""
+ return disconnect_identity(request, request.user.bluesky)
diff --git a/mastodon/views/common.py b/mastodon/views/common.py
index 94671c6d..7a13920e 100644
--- a/mastodon/views/common.py
+++ b/mastodon/views/common.py
@@ -26,7 +26,7 @@ def process_verified_account(request: HttpRequest, account: SocialAccount):
def login_existing_user(request: HttpRequest, account: SocialAccount):
user = authenticate(request, social_account=account)
if not user:
- return render_error(_("Authentication failed"), _("Invalid user."))
+ return render_error(request, _("Authentication failed"), _("Invalid user."))
existing_user = account.user
auth_login(request, existing_user)
account.sync_later()
@@ -41,19 +41,29 @@ def login_existing_user(request: HttpRequest, account: SocialAccount):
def register_new_user(request: HttpRequest, account: SocialAccount):
if request.user.is_authenticated:
- return render_error(_("Registration failed"), _("User already logged in."))
+ return render_error(
+ request, _("Registration failed"), _("User already logged in.")
+ )
request.session["verified_account"] = account.to_dict()
return redirect(reverse("users:register"))
def reconnect_account(request, account: SocialAccount):
if account.user == request.user:
- return render_error(
- request, _("Unable to update login information: identical identity.")
+ account.sync_later()
+ messages.add_message(
+ request,
+ messages.INFO,
+ _("Continue login as {handle}.").format(handle=account.handle),
)
+ return redirect(reverse("users:info"))
elif account.user:
return render_error(
- request, _("Unable to update login information: identity in use.")
+ request,
+ _("Unable to update login information"),
+ _("Identity {handle} in use by a different user.").format(
+ handle=account.handle
+ ),
)
else:
# TODO add confirmation screen
@@ -67,19 +77,26 @@ def reconnect_account(request, account: SocialAccount):
messages.add_message(
request,
messages.INFO,
- _("Login information updated.") + account.handle,
+ _("Login information updated as {handle}.").format(
+ handle=account.handle
+ ),
)
return redirect(reverse("users:info"))
def disconnect_identity(request, account):
if not account:
- return render_error(_("Disconnect identity failed"), _("Identity not found."))
+ return render_error(
+ request, _("Disconnect identity failed"), _("Identity not found.")
+ )
if request.user != account.user:
- return render_error(_("Disconnect identity failed"), _("Invalid user."))
+ return render_error(
+ request, _("Disconnect identity failed"), _("Invalid user.")
+ )
with transaction.atomic():
if request.user.social_accounts.all().count() <= 1:
return render_error(
+ request,
_("Disconnect identity failed"),
_("You cannot disconnect last login identity."),
)
diff --git a/mastodon/views/threads.py b/mastodon/views/threads.py
index b8d33353..10e4c79d 100644
--- a/mastodon/views/threads.py
+++ b/mastodon/views/threads.py
@@ -37,12 +37,14 @@ def threads_oauth(request: HttpRequest):
code = request.GET.get("code")
if not code:
return render_error(
- _("Authentication failed"), request.GET.get("error_description", "")
+ request,
+ _("Authentication failed"),
+ request.GET.get("error_description", ""),
)
account = Threads.authenticate(request, code)
if not account:
return render_error(
- _("Authentication failed"), _("Invalid account data from Threads.")
+ request, _("Authentication failed"), _("Invalid account data from Threads.")
)
return process_verified_account(request, account)
diff --git a/users/templates/users/_profile_social_icons.html b/users/templates/users/_profile_social_icons.html
new file mode 100644
index 00000000..c94b748f
--- /dev/null
+++ b/users/templates/users/_profile_social_icons.html
@@ -0,0 +1,30 @@
+{% if identity.user.mastodon %}
+
+
+
+
+
+{% endif %}
+{% if identity.user.threads %}
+
+
+
+
+
+{% endif %}
+{% if identity.user.bluesky %}
+
+
+
+
+
+{% endif %}
diff --git a/users/templates/users/account.html b/users/templates/users/account.html
index ac922efa..7f43bfca 100644
--- a/users/templates/users/account.html
+++ b/users/templates/users/account.html
@@ -154,7 +154,7 @@
{% if request.user.threads %}
-
{% csrf_token %}
-
+
+
+ {% blocktrans %}App password can be created on bsky.app.{% endblocktrans %}
+
{% trans "If you have already account here registered via a different way, you may login through there and link with your Bluesky account in account settings." %}