From bd8378f643dd8a56366ad9d1843b7d40f67cf1f9 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Mon, 10 Aug 2026 23:22:08 -0600 Subject: [PATCH] refac --- ...bf1f23_repair_double_encoded_user_oauth.py | 63 +++++++++++++++++++ .../b10670c03dd5_update_user_table.py | 6 +- 2 files changed, 65 insertions(+), 4 deletions(-) create mode 100644 backend/open_webui/migrations/versions/6d09d1bf1f23_repair_double_encoded_user_oauth.py diff --git a/backend/open_webui/migrations/versions/6d09d1bf1f23_repair_double_encoded_user_oauth.py b/backend/open_webui/migrations/versions/6d09d1bf1f23_repair_double_encoded_user_oauth.py new file mode 100644 index 0000000000..995fe263ae --- /dev/null +++ b/backend/open_webui/migrations/versions/6d09d1bf1f23_repair_double_encoded_user_oauth.py @@ -0,0 +1,63 @@ +"""repair double encoded user oauth + +Revision ID: 6d09d1bf1f23 +Revises: 1ce6ade7d93b +Create Date: 2026-08-10 23:20:20.374826 + +""" +import json +from typing import Sequence, Union + +from alembic import op +import sqlalchemy as sa +import open_webui.internal.db + + +# revision identifiers, used by Alembic. +revision: str = '6d09d1bf1f23' +down_revision: Union[str, None] = '1ce6ade7d93b' +branch_labels: Union[str, Sequence[str], None] = None +depends_on: Union[str, Sequence[str], None] = None + + +_user = sa.table( + 'user', + sa.column('id', sa.Text), + sa.column('oauth', sa.JSON), +) + + +def _decode_json_object(value: str) -> dict | None: + try: + decoded = json.loads(value) + except Exception: + return None + return decoded if isinstance(decoded, dict) else None + + +def upgrade() -> None: + conn = op.get_bind() + inspector = sa.inspect(conn) + + if 'user' not in inspector.get_table_names(): + return + + user_columns = {c['name'] for c in inspector.get_columns('user')} + if 'oauth' not in user_columns: + return + + rows = conn.execute(sa.select(_user.c.id, _user.c.oauth).where(_user.c.oauth.is_not(None))).fetchall() + + for uid, oauth in rows: + if not isinstance(oauth, str): + continue + + decoded = _decode_json_object(oauth) + if decoded is None: + continue + + conn.execute(sa.update(_user).where(_user.c.id == uid).values(oauth=decoded)) + + +def downgrade() -> None: + pass diff --git a/backend/open_webui/migrations/versions/b10670c03dd5_update_user_table.py b/backend/open_webui/migrations/versions/b10670c03dd5_update_user_table.py index c3965dbd7c..1de7af315f 100644 --- a/backend/open_webui/migrations/versions/b10670c03dd5_update_user_table.py +++ b/backend/open_webui/migrations/versions/b10670c03dd5_update_user_table.py @@ -185,9 +185,7 @@ def upgrade() -> None: for uid, oauth_sub in rows: if oauth_sub: provider, sub = oauth_sub.split('@', 1) if '@' in oauth_sub else ('oidc', oauth_sub) - conn.execute( - sa.update(_user).where(_user.c.id == uid).values(oauth=json.dumps({provider: {'sub': sub}})) - ) + conn.execute(sa.update(_user).where(_user.c.id == uid).values(oauth={provider: {'sub': sub}})) # ── Migrate api_key column → api_key table (only if old column still exists) if 'api_key' in user_columns: @@ -226,7 +224,7 @@ def downgrade() -> None: for uid, oauth in rows: try: - data = json.loads(oauth) + data = oauth if isinstance(oauth, dict) else json.loads(oauth) provider = list(data.keys())[0] sub = data[provider].get('sub') oauth_sub = f'{provider}@{sub}'