fix(mastodon): report failed login

This commit is contained in:
2026-08-20 11:19:07 -06:00
parent 37d2daf8c4
commit 1a16e521fe
2 changed files with 63 additions and 11 deletions
+49 -11
View File
@@ -3,6 +3,7 @@ import os
import sys import sys
import logging import logging
import webbrowser import webbrowser
import shutil
import wx import wx
import requests import requests
import asyncio import asyncio
@@ -12,6 +13,7 @@ import widgetUtils
import config import config
import languageHandler import languageHandler
import application import application
import paths
import sound import sound
import output import output
from pubsub import pub from pubsub import pub
@@ -257,29 +259,33 @@ class Controller(object):
def do_work(self): def do_work(self):
""" Creates the buffer objects for all accounts. This does not starts the buffer streams, only creates the objects.""" """ Creates the buffer objects for all accounts. This does not starts the buffer streams, only creates the objects."""
log.debug("Creating buffers for all sessions...") log.debug("Creating buffers for all sessions...")
for i in sessions.sessions: # Take a copy because a user can choose to remove a session after a
# failed login, which removes it from the global session collection.
for i, session in list(sessions.sessions.items()):
log.debug("Working on session %s" % (i,)) log.debug("Working on session %s" % (i,))
if sessions.sessions[i].is_logged == False: if session.is_logged == False:
if sessions.sessions[i].session_id in config.app["sessions"]["ignored_sessions"]: if session.session_id in config.app["sessions"]["ignored_sessions"]:
self.create_ignored_session_buffer(sessions.sessions[i]) self.create_ignored_session_buffer(session)
continue continue
# Try auto-login for sessions if credentials exist # Try auto-login for sessions if credentials exist
try: try:
sessions.sessions[i].login() session.login()
except Exception: except Exception:
log.exception("Auto-login attempt failed for session %s", i) log.exception("Auto-login attempt failed for session %s", i)
if sessions.sessions[i].is_logged == False: if session.is_logged == False:
self.create_ignored_session_buffer(sessions.sessions[i]) if session.type == "mastodon" and self.handle_failed_mastodon_login(session):
continue
self.create_ignored_session_buffer(session)
continue continue
# Supported session types # Supported session types
valid_session_types = ["mastodon", "blueski"] valid_session_types = ["mastodon", "blueski"]
if sessions.sessions[i].type in valid_session_types: if session.type in valid_session_types:
try: try:
handler = self.get_handler(type=sessions.sessions[i].type) handler = self.get_handler(type=session.type)
if handler is not None: if handler is not None:
handler.create_buffers(sessions.sessions[i], controller=self) handler.create_buffers(session, controller=self)
except Exception: except Exception:
log.exception("Error creating buffers for session %s (%s)", i, sessions.sessions[i].type) log.exception("Error creating buffers for session %s (%s)", i, session.type)
log.debug("Setting updates to buffers every %d seconds..." % (60*config.app["app-settings"]["update_period"],)) log.debug("Setting updates to buffers every %d seconds..." % (60*config.app["app-settings"]["update_period"],))
self.update_buffers_function = RepeatingTimer(60*config.app["app-settings"]["update_period"], self.update_buffers) self.update_buffers_function = RepeatingTimer(60*config.app["app-settings"]["update_period"], self.update_buffers)
self.update_buffers_function.start() self.update_buffers_function.start()
@@ -312,6 +318,38 @@ class Controller(object):
def create_ignored_session_buffer(self, session): def create_ignored_session_buffer(self, session):
pub.sendMessage("core.create_account", name=session.get_name(), session_id=session.session_id) pub.sendMessage("core.create_account", name=session.get_name(), session_id=session.session_id)
def handle_failed_mastodon_login(self, session):
"""Offer to keep or remove a Mastodon session that could not log in.
Returns ``True`` when the session was removed from this application
run, so callers must not create its disconnected account buffer.
"""
instance = session.settings["mastodon"]["instance"]
if commonMessageDialogs.mastodon_login_failed(instance) == wx.ID_YES:
return False
session_path = os.path.join(paths.config_path(), session.session_id)
try:
# A session can have an on-disk cache open, depending on its
# configuration. Close it before deleting the session directory.
if hasattr(session.db, "close"):
session.db.close()
shutil.rmtree(session_path)
except Exception:
log.exception("Unable to remove failed Mastodon session %s", session.session_id)
commonMessageDialogs.common_error(
_("The account configuration could not be removed. It has been kept.")
)
return False
for setting in ("sessions", "ignored_sessions"):
if session.session_id in config.app["sessions"][setting]:
config.app["sessions"][setting].remove(session.session_id)
config.app.write()
sessions.sessions.pop(session.session_id, None)
log.info("Removed Mastodon session %s after failed login", session.session_id)
return True
def login_account(self, session_id): def login_account(self, session_id):
session = None session = None
for i in sessions.sessions: for i in sessions.sessions:
+14
View File
@@ -48,6 +48,20 @@ def cant_update_source() -> wx.MessageDialog:
def invalid_instance(): def invalid_instance():
return wx.MessageDialog(None, _("the provided instance is invalid. Please try again."), _("Invalid instance"), wx.ICON_ERROR).ShowModal() return wx.MessageDialog(None, _("the provided instance is invalid. Please try again."), _("Invalid instance"), wx.ICON_ERROR).ShowModal()
def mastodon_login_failed(instance):
message = _(
"TWBlue could not sign in to the Mastodon instance {instance}. "
"The instance may be temporarily unavailable or your credentials "
"may no longer be valid.\n\nWould you like to keep this account "
"configuration? Choosing No will permanently remove it."
).format(instance=instance)
return wx.MessageDialog(
None,
message,
_("Mastodon login failed"),
wx.YES_NO | wx.YES_DEFAULT | wx.ICON_ERROR,
).ShowModal()
def error_adding_filter(): def error_adding_filter():
return wx.MessageDialog(None, _("TWBlue was unable to add or update the filter with the specified settings. Please try again."), _("Error"), wx.ICON_ERROR).ShowModal() return wx.MessageDialog(None, _("TWBlue was unable to add or update the filter with the specified settings. Please try again."), _("Error"), wx.ICON_ERROR).ShowModal()