88 lines
3.8 KiB
Python
88 lines
3.8 KiB
Python
"""add users table RBAC
|
|
|
|
Revision ID: add_users_table
|
|
Revises:
|
|
Create Date: 2026-02-22
|
|
|
|
"""
|
|
from alembic import op
|
|
import sqlalchemy as sa
|
|
from sqlalchemy.dialects.postgresql import UUID, ENUM
|
|
import uuid
|
|
|
|
# revision identifiers, used by Alembic.
|
|
revision = 'add_users_table'
|
|
down_revision = '380f4e61b41c' # Changed from None to 380f4e61b41c
|
|
branch_labels = None
|
|
depends_on = None
|
|
|
|
|
|
def upgrade():
|
|
bind = op.get_bind()
|
|
is_sqlite = bind.dialect.name == 'sqlite'
|
|
role_column_type = sa.String(50)
|
|
status_column_type = sa.String(50)
|
|
|
|
# Create enums (only for Postgres)
|
|
if not is_sqlite:
|
|
user_role_enum = ENUM('BOSS', 'ADMIN', 'AI', 'FE', 'BE', name='userrole', create_type=True)
|
|
user_status_enum = ENUM('active', 'away', 'offline', name='userstatus', create_type=True)
|
|
role_column_type = ENUM('BOSS', 'ADMIN', 'AI', 'FE', 'BE', name='userrole', create_type=False)
|
|
status_column_type = ENUM('active', 'away', 'offline', name='userstatus', create_type=False)
|
|
|
|
user_role_enum.create(bind, checkfirst=True)
|
|
user_status_enum.create(bind, checkfirst=True)
|
|
|
|
# Create users table
|
|
op.create_table(
|
|
'users',
|
|
sa.Column('id', sa.Integer(), primary_key=True, autoincrement=True) if is_sqlite else sa.Column('id', UUID(as_uuid=True), primary_key=True, default=uuid.uuid4),
|
|
sa.Column('username', sa.String(50), unique=True, nullable=False, index=True),
|
|
sa.Column('password_hash', sa.String(255), nullable=False),
|
|
sa.Column('name', sa.String(100), nullable=False),
|
|
sa.Column('email', sa.String(255), unique=True, nullable=True),
|
|
sa.Column('role', role_column_type, nullable=False, server_default='FE'),
|
|
sa.Column('assigned_domains', sa.JSON(), nullable=True, server_default='[]'),
|
|
sa.Column('workload', sa.Integer(), nullable=False, server_default='0'),
|
|
sa.Column('status', status_column_type, nullable=False, server_default='active'),
|
|
sa.Column('created_at', sa.DateTime(), nullable=False, server_default=sa.func.now()),
|
|
sa.Column('updated_at', sa.DateTime(), nullable=False, server_default=sa.func.now()),
|
|
)
|
|
|
|
# Create initial users (with simple password hashes for demo)
|
|
# In production, these should be created with proper password hashing
|
|
from passlib.context import CryptContext
|
|
pwd_context = CryptContext(schemes=['bcrypt'], deprecated='auto')
|
|
|
|
admin_hash = pwd_context.hash('admin123')
|
|
user_hash = pwd_context.hash('user123')
|
|
|
|
if is_sqlite:
|
|
op.execute(f"""
|
|
INSERT INTO users (username, password_hash, name, email, role, assigned_domains, workload, status, created_at, updated_at)
|
|
VALUES
|
|
('admin', '{admin_hash}', 'System Administrator', 'admin@neural-sync.ai', 'BOSS', '[]', 0, 'active', datetime('now'), datetime('now')),
|
|
('user', '{user_hash}', 'Test User', 'user@neural-sync.ai', 'FE', '[]', 0, 'active', datetime('now'), datetime('now'))
|
|
""")
|
|
else:
|
|
op.execute(f"""
|
|
INSERT INTO users (id, username, password_hash, name, email, role, assigned_domains, workload, status, created_at, updated_at)
|
|
VALUES
|
|
('{uuid.uuid4()}', 'admin', '{admin_hash}', 'System Administrator', 'admin@neural-sync.ai', 'BOSS', '[]', 0, 'active', NOW(), NOW()),
|
|
('{uuid.uuid4()}', 'user', '{user_hash}', 'Test User', 'user@neural-sync.ai', 'FE', '[]', 0, 'active', NOW(), NOW())
|
|
""")
|
|
|
|
|
|
def downgrade():
|
|
op.drop_table('users')
|
|
|
|
bind = op.get_bind()
|
|
is_sqlite = bind.dialect.name == 'sqlite'
|
|
|
|
# Drop enums (only for Postgres)
|
|
if not is_sqlite:
|
|
user_role_enum = sa.dialects.postgresql.ENUM(name='userrole')
|
|
user_status_enum = sa.dialects.postgresql.ENUM(name='userstatus')
|
|
user_role_enum.drop(bind, checkfirst=True)
|
|
user_status_enum.drop(bind, checkfirst=True)
|