-
-
Notifications
You must be signed in to change notification settings - Fork 500
Make config multiuser #999
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 36 commits
Commits
Show all changes
37 commits
Select commit
Hold shift + click to select a range
93a054a
make config table multiuser and adjust token behaviour
deep1401 b615bc2
changes to mlx trainer to avoid deprecation
deep1401 684d2ca
remove path import
deep1401 3e83339
Merge branch 'main' into fix/config-multiuser
deep1401 429bc0e
fix config test
deep1401 4d0433e
Merge branch 'fix/config-multiuser' of https://github.com/transformer…
deep1401 2ca4b26
fix config methods
deep1401 888cd3a
fix
deep1401 36182c2
fix null condition for sql
deep1401 b96d94d
remove unused import
deep1401 3815571
add batch function to downgrade
deep1401 ed4fe88
Merge branch 'main' into fix/config-multiuser
deep1401 9f2b815
batch script ruff
deep1401 8297c61
Merge branch 'fix/config-multiuser' of https://github.com/transformer…
deep1401 0ea7be4
Merge branch 'main' into fix/config-multiuser
deep1401 9cb7a0a
Merge branch 'main' into fix/config-multiuser
deep1401 65aa9af
adjust up and down revisions
deep1401 6f7ef27
simplify
deep1401 b7893a9
Merge branch 'main' into fix/config-multiuser
deep1401 1f86d8f
Merge branch 'main' into fix/config-multiuser
deep1401 0af8e26
Merge branch 'main' into fix/config-multiuser
deep1401 23ddd65
Merge branch 'main' into fix/config-multiuser
deep1401 30a9b4a
ruff
deep1401 64df92d
fix down revision
deep1401 8aa580d
Merge branch 'main' into fix/config-multiuser
dadmobile 201dcda
Merge branch 'main' into fix/config-multiuser
deep1401 5f781bd
remove mention of global config
deep1401 e9a2f60
Merge branch 'fix/config-multiuser' of https://github.com/transformer…
deep1401 15bbefe
get rid of team_wide param
deep1401 036202b
Fix issues with batch alter table on sqlite
deep1401 dfe1571
fix downgrade too
deep1401 42abe0f
version
deep1401 70b1d7c
fix missing _TFL_USER_ID setup
deep1401 5cd389c
fix bug of user id not being set for user specific ones
deep1401 e1bfe73
format
deep1401 cc1c1f3
Merge branch 'main' into fix/config-multiuser
deep1401 022fb51
Merge branch 'main' into fix/config-multiuser
dadmobile File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
161 changes: 161 additions & 0 deletions
161
api/alembic/versions/c78d76a6d65c_add_team_id_to_config_table.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,161 @@ | ||
| """add_team_id_to_config_table | ||
|
|
||
| Revision ID: c78d76a6d65c | ||
| Revises: 1f7cb465d15a | ||
| Create Date: 2025-12-04 11:23:22.165544 | ||
|
|
||
| """ | ||
|
|
||
| from typing import Sequence, Union | ||
|
|
||
| from alembic import op | ||
| import sqlalchemy as sa | ||
|
|
||
|
|
||
| # revision identifiers, used by Alembic. | ||
| revision: str = "c78d76a6d65c" | ||
| down_revision: Union[str, Sequence[str], None] = "1f7cb465d15a" | ||
| branch_labels: Union[str, Sequence[str], None] = None | ||
| depends_on: Union[str, Sequence[str], None] = None | ||
|
|
||
|
|
||
| def upgrade() -> None: | ||
| """Upgrade schema.""" | ||
| connection = op.get_bind() | ||
|
|
||
| # Check existing columns | ||
| column_result = connection.execute(sa.text("PRAGMA table_info(config)")) | ||
| existing_columns = [row[1] for row in column_result.fetchall()] | ||
|
|
||
| # Get existing indexes by querying SQLite directly | ||
| # SQLite stores unique constraints as unique indexes | ||
| index_result = connection.execute( | ||
| sa.text("SELECT name FROM sqlite_master WHERE type='index' AND tbl_name='config'") | ||
| ) | ||
| existing_index_names = [row[0] for row in index_result.fetchall()] | ||
|
|
||
| # Add columns first (outside batch mode to avoid circular dependency) | ||
| # Only add if they don't already exist | ||
| if "user_id" not in existing_columns: | ||
| op.add_column("config", sa.Column("user_id", sa.String(), nullable=True)) | ||
| if "team_id" not in existing_columns: | ||
| op.add_column("config", sa.Column("team_id", sa.String(), nullable=True)) | ||
|
|
||
| # Handle indexes outside of batch mode to avoid type inference issues | ||
| # Drop existing unique index on key if it exists (to recreate as non-unique) | ||
| if "ix_config_key" in existing_index_names: | ||
| # Check if it's unique by querying the index definition | ||
| index_info = connection.execute( | ||
| sa.text("SELECT sql FROM sqlite_master WHERE type='index' AND name='ix_config_key'") | ||
| ).fetchone() | ||
| if index_info and index_info[0] and "UNIQUE" in index_info[0].upper(): | ||
| # Drop the unique index using raw SQL to avoid batch mode issues | ||
| connection.execute(sa.text("DROP INDEX IF EXISTS ix_config_key")) | ||
| existing_index_names.remove("ix_config_key") # Update our list | ||
|
|
||
| # Create new indexes (non-unique) - these can be done outside batch mode | ||
| if "ix_config_key" not in existing_index_names: | ||
| op.create_index("ix_config_key", "config", ["key"], unique=False) | ||
| if "ix_config_user_id" not in existing_index_names: | ||
| op.create_index("ix_config_user_id", "config", ["user_id"], unique=False) | ||
| if "ix_config_team_id" not in existing_index_names: | ||
| op.create_index("ix_config_team_id", "config", ["team_id"], unique=False) | ||
|
|
||
| # For SQLite, unique constraints are stored as unique indexes | ||
| # Create the unique constraint as a unique index using raw SQL to avoid batch mode issues | ||
| if "uq_config_user_team_key" not in existing_index_names: | ||
| connection.execute( | ||
| sa.text("CREATE UNIQUE INDEX IF NOT EXISTS uq_config_user_team_key ON config(user_id, team_id, key)") | ||
| ) | ||
|
|
||
| # Migrate existing configs to admin user's first team | ||
| # Note: Don't call connection.commit() - Alembic manages transactions | ||
| connection = op.get_bind() | ||
| # Find admin user's first team | ||
| admin_team_result = connection.execute( | ||
| sa.text(""" | ||
| SELECT ut.team_id | ||
| FROM users_teams ut | ||
| JOIN user u ON ut.user_id = u.id | ||
| WHERE u.email = 'admin@example.com' | ||
| LIMIT 1 | ||
| """) | ||
| ) | ||
| admin_team_row = admin_team_result.fetchone() | ||
|
|
||
| if admin_team_row: | ||
| admin_team_id = admin_team_row[0] | ||
| # Update all existing configs (where team_id is NULL) to use admin team | ||
| connection.execute( | ||
| sa.text("UPDATE config SET team_id = :team_id WHERE team_id IS NULL"), {"team_id": admin_team_id} | ||
| ) | ||
| print(f"✅ Migrated existing configs to team {admin_team_id}") | ||
| else: | ||
| # If no admin team found, try to get any user's first team | ||
| any_team_result = connection.execute(sa.text("SELECT team_id FROM users_teams LIMIT 1")) | ||
| any_team_row = any_team_result.fetchone() | ||
| if any_team_row: | ||
| any_team_id = any_team_row[0] | ||
| connection.execute( | ||
| sa.text("UPDATE config SET team_id = :team_id WHERE team_id IS NULL"), {"team_id": any_team_id} | ||
| ) | ||
| print(f"✅ Migrated existing configs to team {any_team_id}") | ||
| else: | ||
| # No teams found, delete existing configs | ||
| deleted_count = connection.execute(sa.text("DELETE FROM config WHERE team_id IS NULL")).rowcount | ||
| print(f"⚠️ No teams found, deleted {deleted_count} config entries") | ||
| # ### end Alembic commands ### | ||
|
|
||
|
|
||
| def downgrade() -> None: | ||
| """Downgrade schema.""" | ||
| connection = op.get_bind() | ||
|
|
||
| # Check existing indexes | ||
| index_result = connection.execute( | ||
| sa.text("SELECT name FROM sqlite_master WHERE type='index' AND tbl_name='config'") | ||
| ) | ||
| existing_index_names = [row[0] for row in index_result.fetchall()] | ||
|
|
||
| # Check existing columns | ||
| column_result = connection.execute(sa.text("PRAGMA table_info(config)")) | ||
| existing_columns = [row[1] for row in column_result.fetchall()] | ||
|
|
||
| # Drop indexes and constraints outside of batch mode to avoid type inference issues | ||
| # Drop unique constraint (stored as unique index in SQLite) | ||
| if "uq_config_user_team_key" in existing_index_names: | ||
| connection.execute(sa.text("DROP INDEX IF EXISTS uq_config_user_team_key")) | ||
|
|
||
| # Drop indexes | ||
| if "ix_config_team_id" in existing_index_names: | ||
| op.drop_index("ix_config_team_id", table_name="config") | ||
| if "ix_config_user_id" in existing_index_names: | ||
| op.drop_index("ix_config_user_id", table_name="config") | ||
| if "ix_config_key" in existing_index_names: | ||
| op.drop_index("ix_config_key", table_name="config") | ||
|
|
||
| # Drop columns using raw SQL to avoid batch mode type inference issues | ||
| # SQLite doesn't support DROP COLUMN directly, so we recreate the table | ||
| if "team_id" in existing_columns or "user_id" in existing_columns: | ||
| # Create new table without user_id and team_id columns | ||
| connection.execute( | ||
| sa.text(""" | ||
| CREATE TABLE config_new ( | ||
| id INTEGER NOT NULL PRIMARY KEY, | ||
| key VARCHAR NOT NULL, | ||
| value VARCHAR | ||
| ) | ||
| """) | ||
| ) | ||
| # Copy data from old table to new table (only id, key, value columns) | ||
| connection.execute(sa.text("INSERT INTO config_new (id, key, value) SELECT id, key, value FROM config")) | ||
| # Drop old table (this also drops all indexes) | ||
| connection.execute(sa.text("DROP TABLE config")) | ||
| # Rename new table to original name | ||
| connection.execute(sa.text("ALTER TABLE config_new RENAME TO config")) | ||
| # Recreate the original unique index on key (it was dropped with the old table) | ||
| op.create_index("ix_config_key", "config", ["key"], unique=True) | ||
| else: | ||
| # If we're not dropping columns, just recreate the unique index on key | ||
| op.create_index("ix_config_key", "config", ["key"], unique=True) | ||
| # ### end Alembic commands ### |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| # TransformerLab plugin SDK package | ||
| # This allows imports like: from transformerlab.sdk.v1.train import ... |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.