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 %} @@ -165,6 +165,60 @@ {% endif %} +
+
+ {% trans "Bluesky (ATProto)" %} + + {% csrf_token %} +
+ {% if request.user.bluesky %} + + {% endif %} + + + + {% blocktrans %}App password can be created on bsky.app.{% endblocktrans %} +
+ + {% if request.user.bluesky %} +
+ {% csrf_token %} + +
+ {% endif %} +
+
{% endif %}
diff --git a/users/templates/users/login.html b/users/templates/users/login.html index 7f11b8d6..f1d72a22 100644 --- a/users/templates/users/login.html +++ b/users/templates/users/login.html @@ -80,7 +80,7 @@ {% if enable_bluesky %} {% endif %} @@ -139,12 +139,30 @@ {% else %} diff --git a/users/templates/users/profile_actions.html b/users/templates/users/profile_actions.html index 4d111775..892df3b7 100644 --- a/users/templates/users/profile_actions.html +++ b/users/templates/users/profile_actions.html @@ -55,26 +55,7 @@ {% endif %} {% if not identity.locked or request.user.is_superuser or relationship.requested or relationship.status %} - {% if identity.user.mastodon %} - - - - - - {% endif %} - {% if identity.user.threads %} - - - - - - {% endif %} + {% include "users/_profile_social_icons.html" %} {% endif %} {% endif %} {% if relationship.requested %} diff --git a/users/views/account.py b/users/views/account.py index 827b9f8a..41441174 100644 --- a/users/views/account.py +++ b/users/views/account.py @@ -46,8 +46,8 @@ def login(request): "selected_domain": selected_domain, "allow_any_site": settings.MASTODON_ALLOW_ANY_SITE, "enable_email": settings.ENABLE_LOGIN_EMAIL, - "enable_threads": bool(settings.THREADS_APP_ID), - "enable_bluesky": settings.BLUESKY_LOGIN_ENABLED, + "enable_threads": settings.ENABLE_LOGIN_THREADS, + "enable_bluesky": settings.ENABLE_LOGIN_BLUESKY, "invite_status": invite_status, }, )