"""mobile settings, enrollment codes, devices, refresh tokens; policy use_mobile Revision ID: 014 Revises: 013 """ from typing import Sequence, Union import sqlalchemy as sa from alembic import op revision: str = "014" down_revision: Union[str, None] = "013" branch_labels: Union[str, Sequence[str], None] = None depends_on: Union[str, Sequence[str], None] = None MOBILE_SETTINGS_ROW_ID = 1 def upgrade() -> None: op.add_column( "notification_policy", sa.Column("use_mobile", sa.Boolean(), nullable=False, server_default=sa.text("false")), ) op.create_table( "mobile_settings", sa.Column("id", sa.Integer(), nullable=False), sa.Column("devices_allowed", sa.Boolean(), nullable=False, server_default=sa.text("false")), sa.Column("max_devices_per_user", sa.Integer(), nullable=False, server_default="3"), sa.Column("min_app_version", sa.String(length=32), nullable=True), sa.PrimaryKeyConstraint("id"), ) op.execute( sa.text( "INSERT INTO mobile_settings (id, devices_allowed, max_devices_per_user) " f"VALUES ({MOBILE_SETTINGS_ROW_ID}, false, 3)" ) ) op.create_table( "mobile_enrollment_codes", sa.Column("id", sa.Integer(), autoincrement=True, nullable=False), sa.Column("label", sa.String(length=128), nullable=False, server_default=""), sa.Column("code_hash", sa.String(length=64), nullable=False), sa.Column("code_prefix", sa.String(length=16), nullable=False), sa.Column("created_by_user_id", sa.Integer(), nullable=True), sa.Column("target_user_id", sa.Integer(), nullable=True), sa.Column("login_mode", sa.String(length=16), nullable=False, server_default="password"), sa.Column("max_uses", sa.Integer(), nullable=False, server_default="1"), sa.Column("use_count", sa.Integer(), nullable=False, server_default="0"), sa.Column("expires_at", sa.DateTime(timezone=True), nullable=False), sa.Column("revoked_at", sa.DateTime(timezone=True), nullable=True), sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.text("now()"), nullable=False), sa.ForeignKeyConstraint(["created_by_user_id"], ["sac_users.id"], ondelete="SET NULL"), sa.ForeignKeyConstraint(["target_user_id"], ["sac_users.id"], ondelete="SET NULL"), sa.PrimaryKeyConstraint("id"), ) op.create_index("ix_mobile_enrollment_codes_code_hash", "mobile_enrollment_codes", ["code_hash"], unique=True) op.create_table( "mobile_devices", sa.Column("id", sa.Integer(), autoincrement=True, nullable=False), sa.Column("user_id", sa.Integer(), nullable=False), sa.Column("device_uuid", sa.String(length=64), nullable=False), sa.Column("display_name", sa.String(length=128), nullable=False, server_default=""), sa.Column("platform", sa.String(length=32), nullable=False, server_default="android"), sa.Column("app_version", sa.String(length=32), nullable=True), sa.Column("fcm_token", sa.String(length=512), nullable=True), sa.Column("fcm_token_updated_at", sa.DateTime(timezone=True), nullable=True), sa.Column("enrollment_code_id", sa.Integer(), nullable=True), sa.Column("enrolled_at", sa.DateTime(timezone=True), server_default=sa.text("now()"), nullable=False), sa.Column("last_seen_at", sa.DateTime(timezone=True), nullable=True), sa.Column("revoked_at", sa.DateTime(timezone=True), nullable=True), sa.ForeignKeyConstraint(["user_id"], ["sac_users.id"], ondelete="CASCADE"), sa.ForeignKeyConstraint(["enrollment_code_id"], ["mobile_enrollment_codes.id"], ondelete="SET NULL"), sa.PrimaryKeyConstraint("id"), ) op.create_index("ix_mobile_devices_device_uuid", "mobile_devices", ["device_uuid"], unique=True) op.create_index("ix_mobile_devices_user_id", "mobile_devices", ["user_id"]) op.create_table( "mobile_refresh_tokens", sa.Column("id", sa.Integer(), autoincrement=True, nullable=False), sa.Column("device_id", sa.Integer(), nullable=False), sa.Column("token_hash", sa.String(length=64), nullable=False), sa.Column("expires_at", sa.DateTime(timezone=True), nullable=False), sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.text("now()"), nullable=False), sa.Column("revoked_at", sa.DateTime(timezone=True), nullable=True), sa.ForeignKeyConstraint(["device_id"], ["mobile_devices.id"], ondelete="CASCADE"), sa.PrimaryKeyConstraint("id"), ) op.create_index("ix_mobile_refresh_tokens_token_hash", "mobile_refresh_tokens", ["token_hash"], unique=True) def downgrade() -> None: op.drop_index("ix_mobile_refresh_tokens_token_hash", table_name="mobile_refresh_tokens") op.drop_table("mobile_refresh_tokens") op.drop_index("ix_mobile_devices_user_id", table_name="mobile_devices") op.drop_index("ix_mobile_devices_device_uuid", table_name="mobile_devices") op.drop_table("mobile_devices") op.drop_index("ix_mobile_enrollment_codes_code_hash", table_name="mobile_enrollment_codes") op.drop_table("mobile_enrollment_codes") op.drop_table("mobile_settings") op.drop_column("notification_policy", "use_mobile")