From d4a3c33816bfe090372c25cba96e3811386a2786 Mon Sep 17 00:00:00 2001 From: Colourfulzi <6041568+Colourfulzi@users.noreply.github.com> Date: Wed, 1 Apr 2026 16:38:21 +0800 Subject: [PATCH 1/2] fix(webchat): migrate webchat data when dashboard username changes When dashboard account username is updated, existing webchat records still reference the old username in UMO-like identifiers, causing chat history to appear empty after re-login. This change: - adds a database migration contract for username-based webchat data updates - implements SQLite migration for related user-scoped records - triggers migration in account edit flow before saving config - injects database dependency into AuthRoute for migration execution Closes #7242 --- astrbot/core/db/__init__.py | 9 ++++++- astrbot/core/db/sqlite.py | 41 ++++++++++++++++++++++++++++++++ astrbot/dashboard/routes/auth.py | 10 +++++++- astrbot/dashboard/server.py | 2 +- 4 files changed, 59 insertions(+), 3 deletions(-) diff --git a/astrbot/core/db/__init__.py b/astrbot/core/db/__init__.py index 087aa625bd..abf957edf3 100644 --- a/astrbot/core/db/__init__.py +++ b/astrbot/core/db/__init__.py @@ -722,9 +722,16 @@ async def delete_platform_session(self, session_id: str) -> None: """Delete a Platform session by its ID.""" ... + @abc.abstractmethod + async def migrate_user_webchat_data( + self, old_username: str, new_username: str + ) -> None: + """Migrate all webchat user data when username is changed.""" + ... + # ==== # ChatUI Project Management - # ==== + # ====" @abc.abstractmethod async def create_chatui_project( diff --git a/astrbot/core/db/sqlite.py b/astrbot/core/db/sqlite.py index fd6668c0c7..e745b9579e 100644 --- a/astrbot/core/db/sqlite.py +++ b/astrbot/core/db/sqlite.py @@ -1616,6 +1616,47 @@ async def delete_platform_session(self, session_id: str) -> None: ), ) + async def migrate_user_webchat_data( + self, old_username: str, new_username: str + ) -> None: + """Migrate all webchat user data when username is changed.""" + old_fragment = f"!{old_username}!" + new_fragment = f"!{new_username}!" + async with self.get_db() as session: + session: AsyncSession + async with session.begin(): + await session.execute( + update(PlatformSession) + .where(col(PlatformSession.creator) == old_username) + .values(creator=new_username) + ) + await session.execute( + update(ChatUIProject) + .where(col(ChatUIProject.creator) == old_username) + .values(creator=new_username) + ) + await session.execute( + update(ConversationV2) + .where(col(ConversationV2.user_id).like("webchat%")) + .values( + user_id=func.replace( + ConversationV2.user_id, old_fragment, new_fragment + ) + ) + ) + await session.execute( + update(Preference) + .where( + col(Preference.scope) == "umo", + col(Preference.scope_id).like("webchat%"), + ) + .values( + scope_id=func.replace( + Preference.scope_id, old_fragment, new_fragment + ) + ) + ) + # ==== # ChatUI Project Management # ==== diff --git a/astrbot/dashboard/routes/auth.py b/astrbot/dashboard/routes/auth.py index eac5f65b0b..ef7d559492 100644 --- a/astrbot/dashboard/routes/auth.py +++ b/astrbot/dashboard/routes/auth.py @@ -6,13 +6,15 @@ from astrbot import logger from astrbot.core import DEMO_MODE +from astrbot.core.db import BaseDatabase from .route import Response, Route, RouteContext class AuthRoute(Route): - def __init__(self, context: RouteContext) -> None: + def __init__(self, context: RouteContext, db: BaseDatabase) -> None: super().__init__(context) + self.db = db self.routes = { "/auth/login": ("POST", self.login), "/auth/account/edit": ("POST", self.edit_account), @@ -72,9 +74,15 @@ async def edit_account(self): if confirm_pwd != new_pwd: return Response().error("两次输入的新密码不一致").__dict__ self.config["dashboard"]["password"] = new_pwd + + old_username = self.config["dashboard"]["username"] if new_username: self.config["dashboard"]["username"] = new_username + # Migrate webchat user data before saving config to keep them in sync. + if new_username and new_username != old_username: + await self.db.migrate_user_webchat_data(old_username, new_username) + self.config.save_config() return Response().ok(None, "修改成功").__dict__ diff --git a/astrbot/dashboard/server.py b/astrbot/dashboard/server.py index cbb7296bd0..2a3f90f479 100644 --- a/astrbot/dashboard/server.py +++ b/astrbot/dashboard/server.py @@ -112,7 +112,7 @@ def __init__( self.cr = ConfigRoute(self.context, core_lifecycle) self.lr = LogRoute(self.context, core_lifecycle.log_broker) self.sfr = StaticFileRoute(self.context) - self.ar = AuthRoute(self.context) + self.ar = AuthRoute(self.context, db) self.api_key_route = ApiKeyRoute(self.context, db) self.chat_route = ChatRoute(self.context, db, core_lifecycle) self.open_api_route = OpenApiRoute( From 9cf43978d12d0e9af7fc36936191940ddc4f5781 Mon Sep 17 00:00:00 2001 From: Colourfulzi <6041568+Colourfulzi@users.noreply.github.com> Date: Wed, 1 Apr 2026 17:41:15 +0800 Subject: [PATCH 2/2] fix: remove trailing double quote in ChatUI project section comment --- astrbot/core/db/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/astrbot/core/db/__init__.py b/astrbot/core/db/__init__.py index abf957edf3..4c4f8ab58d 100644 --- a/astrbot/core/db/__init__.py +++ b/astrbot/core/db/__init__.py @@ -731,7 +731,7 @@ async def migrate_user_webchat_data( # ==== # ChatUI Project Management - # ====" + # ==== @abc.abstractmethod async def create_chatui_project(