feat: allow admins to bypass approval flow when joining networks
This commit is contained in:
@@ -0,0 +1,691 @@
|
||||
"""Merge user_network_approvals and device_network_memberships into network_access_requests.
|
||||
|
||||
Revision ID: c0a1b2c3d4e5
|
||||
Revises: a1b2c3d4e5f6
|
||||
Create Date: 2026-05-02 00:00:00.000000
|
||||
"""
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = 'c0a1b2c3d4e5'
|
||||
down_revision = 'a1b2c3d4e5f6'
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# UPGRADE
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def upgrade():
|
||||
# ------------------------------------------------------------------
|
||||
# Step 1: Create the new network_access_requests table
|
||||
# ------------------------------------------------------------------
|
||||
op.create_table(
|
||||
'network_access_requests',
|
||||
sa.Column('id', sa.String(length=36), nullable=False),
|
||||
sa.Column('organization_id', sa.String(length=36), nullable=False),
|
||||
sa.Column('user_id', sa.String(length=36), nullable=False),
|
||||
sa.Column('device_id', sa.String(length=36), nullable=False),
|
||||
sa.Column('portal_network_id', sa.String(length=36), nullable=False),
|
||||
sa.Column('granted_by_user_id', sa.String(length=36), nullable=True),
|
||||
sa.Column(
|
||||
'grant_type',
|
||||
sa.Enum('requested', 'assigned', name='approval_grant_type', create_type=False),
|
||||
nullable=False,
|
||||
),
|
||||
sa.Column(
|
||||
'status',
|
||||
sa.Enum(
|
||||
'pending', 'approved', 'rejected', 'revoked', 'suspended',
|
||||
name='approval_state', create_type=False,
|
||||
),
|
||||
nullable=False,
|
||||
),
|
||||
sa.Column('active', sa.Boolean(), nullable=False, server_default='false'),
|
||||
sa.Column('justification', sa.Text(), nullable=True),
|
||||
sa.Column('join_seen', sa.Boolean(), nullable=False, server_default='false'),
|
||||
sa.Column('created_at', sa.DateTime(), nullable=False),
|
||||
sa.Column('updated_at', sa.DateTime(), nullable=False),
|
||||
sa.Column('deleted_at', sa.DateTime(), nullable=True),
|
||||
sa.ForeignKeyConstraint(
|
||||
['device_id'], ['devices.id'],
|
||||
name='fk_network_access_requests_device',
|
||||
),
|
||||
sa.ForeignKeyConstraint(
|
||||
['granted_by_user_id'], ['users.id'],
|
||||
name='fk_network_access_requests_granted_by_user',
|
||||
),
|
||||
sa.ForeignKeyConstraint(
|
||||
['organization_id'], ['organizations.id'],
|
||||
name='fk_network_access_requests_organization',
|
||||
),
|
||||
sa.ForeignKeyConstraint(
|
||||
['portal_network_id'], ['portal_networks.id'],
|
||||
name='fk_network_access_requests_portal_network',
|
||||
),
|
||||
sa.ForeignKeyConstraint(
|
||||
['user_id'], ['users.id'],
|
||||
name='fk_network_access_requests_user',
|
||||
),
|
||||
sa.PrimaryKeyConstraint('id', name='pk_network_access_requests'),
|
||||
sa.UniqueConstraint(
|
||||
'user_id', 'device_id', 'portal_network_id', 'deleted_at',
|
||||
name='uix_user_device_network',
|
||||
),
|
||||
)
|
||||
|
||||
# Indexes on network_access_requests
|
||||
op.create_index(
|
||||
'ix_network_access_requests_device_id',
|
||||
'network_access_requests',
|
||||
['device_id'],
|
||||
unique=False,
|
||||
)
|
||||
op.create_index(
|
||||
'ix_network_access_requests_organization_id',
|
||||
'network_access_requests',
|
||||
['organization_id'],
|
||||
unique=False,
|
||||
)
|
||||
op.create_index(
|
||||
'ix_network_access_requests_portal_network_id',
|
||||
'network_access_requests',
|
||||
['portal_network_id'],
|
||||
unique=False,
|
||||
)
|
||||
op.create_index(
|
||||
'ix_network_access_requests_status',
|
||||
'network_access_requests',
|
||||
['status'],
|
||||
unique=False,
|
||||
)
|
||||
op.create_index(
|
||||
'ix_network_access_requests_user_id',
|
||||
'network_access_requests',
|
||||
['user_id'],
|
||||
unique=False,
|
||||
)
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Step 2: Migrate data from old tables into the new table
|
||||
# ------------------------------------------------------------------
|
||||
op.execute(
|
||||
"""
|
||||
INSERT INTO network_access_requests (
|
||||
id, organization_id, user_id, device_id, portal_network_id,
|
||||
granted_by_user_id, grant_type, status, active, justification,
|
||||
join_seen, created_at, updated_at, deleted_at
|
||||
)
|
||||
SELECT
|
||||
dnm.id,
|
||||
dnm.organization_id,
|
||||
dnm.user_id,
|
||||
dnm.device_id,
|
||||
dnm.portal_network_id,
|
||||
COALESCE(una.granted_by_user_id, NULL),
|
||||
COALESCE(una.grant_type, 'requested'),
|
||||
COALESCE(una.state, 'pending'),
|
||||
CASE
|
||||
WHEN dnm.currently_authorized = true AND una.state = 'approved'
|
||||
THEN true
|
||||
ELSE false
|
||||
END,
|
||||
una.justification,
|
||||
dnm.join_seen,
|
||||
COALESCE(dnm.created_at, una.created_at),
|
||||
COALESCE(dnm.updated_at, una.updated_at),
|
||||
dnm.deleted_at
|
||||
FROM device_network_memberships dnm
|
||||
LEFT JOIN user_network_approvals una
|
||||
ON una.id = dnm.user_network_approval_id;
|
||||
"""
|
||||
)
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Step 3: Update activation_sessions FK
|
||||
# ------------------------------------------------------------------
|
||||
# 3a. Add the new nullable column
|
||||
op.add_column(
|
||||
'activation_sessions',
|
||||
sa.Column('network_access_request_id', sa.String(length=36), nullable=True),
|
||||
)
|
||||
|
||||
# 3b. Populate the new column from the old column
|
||||
op.execute(
|
||||
"""
|
||||
UPDATE activation_sessions
|
||||
SET network_access_request_id = device_network_membership_id;
|
||||
"""
|
||||
)
|
||||
|
||||
# 3c. Drop the old foreign-key constraint
|
||||
op.drop_constraint(
|
||||
'activation_sessions_device_network_membership_id_fkey',
|
||||
'activation_sessions',
|
||||
type_='foreignkey',
|
||||
)
|
||||
|
||||
# 3d. Drop the old column
|
||||
op.drop_column('activation_sessions', 'device_network_membership_id')
|
||||
|
||||
# 3d-alt. Enforce NOT NULL on the new column before FK creation
|
||||
op.alter_column('activation_sessions', 'network_access_request_id', nullable=False)
|
||||
|
||||
# 3e. Create the new foreign-key constraint
|
||||
op.create_foreign_key(
|
||||
'fk_activation_sessions_network_access_request',
|
||||
'activation_sessions',
|
||||
'network_access_requests',
|
||||
['network_access_request_id'],
|
||||
['id'],
|
||||
)
|
||||
|
||||
# 3f. Create the new index
|
||||
op.create_index(
|
||||
'ix_activation_sessions_network_access_request_id',
|
||||
'activation_sessions',
|
||||
['network_access_request_id'],
|
||||
unique=False,
|
||||
)
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Step 4: Update zerotier_memberships FK
|
||||
# ------------------------------------------------------------------
|
||||
# 4a. Add the new nullable column
|
||||
op.add_column(
|
||||
'zerotier_memberships',
|
||||
sa.Column('network_access_request_id', sa.String(length=36), nullable=True),
|
||||
)
|
||||
|
||||
# 4b. Populate the new column from the old column
|
||||
op.execute(
|
||||
"""
|
||||
UPDATE zerotier_memberships
|
||||
SET network_access_request_id = device_network_membership_id;
|
||||
"""
|
||||
)
|
||||
|
||||
# 4c. Drop the old foreign-key constraint
|
||||
op.drop_constraint(
|
||||
'zerotier_memberships_device_network_membership_id_fkey',
|
||||
'zerotier_memberships',
|
||||
type_='foreignkey',
|
||||
)
|
||||
|
||||
# 4d. Drop the old column
|
||||
op.drop_column('zerotier_memberships', 'device_network_membership_id')
|
||||
|
||||
# 4e. Create the new foreign-key constraint
|
||||
op.create_foreign_key(
|
||||
'fk_zerotier_memberships_network_access_request',
|
||||
'zerotier_memberships',
|
||||
'network_access_requests',
|
||||
['network_access_request_id'],
|
||||
['id'],
|
||||
)
|
||||
|
||||
# 4f. Create the new index
|
||||
op.create_index(
|
||||
'ix_zerotier_memberships_network_access_request_id',
|
||||
'zerotier_memberships',
|
||||
['network_access_request_id'],
|
||||
unique=False,
|
||||
)
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Step 5: Drop old tables and the membership_state enum
|
||||
# ------------------------------------------------------------------
|
||||
# 5a. Drop device_network_memberships and all its indexes
|
||||
op.drop_index(
|
||||
'ix_device_network_memberships_user_network_approval_id',
|
||||
table_name='device_network_memberships',
|
||||
)
|
||||
op.drop_index(
|
||||
'ix_device_network_memberships_user_id',
|
||||
table_name='device_network_memberships',
|
||||
)
|
||||
op.drop_index(
|
||||
'ix_device_network_memberships_state',
|
||||
table_name='device_network_memberships',
|
||||
)
|
||||
op.drop_index(
|
||||
'ix_device_network_memberships_portal_network_id',
|
||||
table_name='device_network_memberships',
|
||||
)
|
||||
op.drop_index(
|
||||
'ix_device_network_memberships_organization_id',
|
||||
table_name='device_network_memberships',
|
||||
)
|
||||
op.drop_index(
|
||||
'ix_device_network_memberships_device_id',
|
||||
table_name='device_network_memberships',
|
||||
)
|
||||
op.drop_table('device_network_memberships')
|
||||
|
||||
# 5b. Drop user_network_approvals and all its indexes
|
||||
op.drop_index(
|
||||
'ix_user_network_approvals_user_id',
|
||||
table_name='user_network_approvals',
|
||||
)
|
||||
op.drop_index(
|
||||
'ix_user_network_approvals_state',
|
||||
table_name='user_network_approvals',
|
||||
)
|
||||
op.drop_index(
|
||||
'ix_user_network_approvals_portal_network_id',
|
||||
table_name='user_network_approvals',
|
||||
)
|
||||
op.drop_index(
|
||||
'ix_user_network_approvals_organization_id',
|
||||
table_name='user_network_approvals',
|
||||
)
|
||||
op.drop_table('user_network_approvals')
|
||||
|
||||
# 5c. Drop the membership_state enum type if it exists
|
||||
op.execute(
|
||||
"""
|
||||
DO $$
|
||||
BEGIN
|
||||
IF EXISTS (
|
||||
SELECT 1 FROM pg_type WHERE typname = 'membership_state'
|
||||
) THEN
|
||||
DROP TYPE membership_state;
|
||||
END IF;
|
||||
END$$;
|
||||
"""
|
||||
)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# DOWNGRADE
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def downgrade():
|
||||
# ------------------------------------------------------------------
|
||||
# Step 1: Recreate the membership_state enum (used by old tables)
|
||||
# ------------------------------------------------------------------
|
||||
membership_state = sa.Enum(
|
||||
'pending_device_registration',
|
||||
'pending_request',
|
||||
'pending_manager_approval',
|
||||
'approved_inactive',
|
||||
'joined_deauthorized',
|
||||
'active_authorized',
|
||||
'activation_expired',
|
||||
'suspended',
|
||||
'revoked',
|
||||
'rejected',
|
||||
name='membership_state',
|
||||
)
|
||||
membership_state.create(op.get_bind(), checkfirst=True)
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Step 2: Recreate user_network_approvals table
|
||||
# ------------------------------------------------------------------
|
||||
op.create_table(
|
||||
'user_network_approvals',
|
||||
sa.Column('organization_id', sa.String(length=36), nullable=False),
|
||||
sa.Column('user_id', sa.String(length=36), nullable=False),
|
||||
sa.Column('portal_network_id', sa.String(length=36), nullable=False),
|
||||
sa.Column('granted_by_user_id', sa.String(length=36), nullable=True),
|
||||
sa.Column(
|
||||
'grant_type',
|
||||
sa.Enum('requested', 'assigned', name='approval_grant_type', create_type=False),
|
||||
nullable=False,
|
||||
),
|
||||
sa.Column(
|
||||
'state',
|
||||
sa.Enum(
|
||||
'pending', 'approved', 'rejected', 'revoked', 'suspended',
|
||||
name='approval_state', create_type=False,
|
||||
),
|
||||
nullable=False,
|
||||
),
|
||||
sa.Column('justification', sa.Text(), nullable=True),
|
||||
sa.Column('id', sa.String(length=36), nullable=False),
|
||||
sa.Column('created_at', sa.DateTime(), nullable=False),
|
||||
sa.Column('updated_at', sa.DateTime(), nullable=False),
|
||||
sa.Column('deleted_at', sa.DateTime(), nullable=True),
|
||||
sa.ForeignKeyConstraint(
|
||||
['granted_by_user_id'], ['users.id'],
|
||||
),
|
||||
sa.ForeignKeyConstraint(
|
||||
['organization_id'], ['organizations.id'],
|
||||
),
|
||||
sa.ForeignKeyConstraint(
|
||||
['portal_network_id'], ['portal_networks.id'],
|
||||
),
|
||||
sa.ForeignKeyConstraint(
|
||||
['user_id'], ['users.id'],
|
||||
),
|
||||
sa.PrimaryKeyConstraint('id'),
|
||||
sa.UniqueConstraint(
|
||||
'user_id', 'portal_network_id', 'deleted_at',
|
||||
name='uix_user_network_approval',
|
||||
),
|
||||
)
|
||||
|
||||
# Recreate indexes on user_network_approvals
|
||||
op.create_index(
|
||||
'ix_user_network_approvals_organization_id',
|
||||
'user_network_approvals',
|
||||
['organization_id'],
|
||||
unique=False,
|
||||
)
|
||||
op.create_index(
|
||||
'ix_user_network_approvals_portal_network_id',
|
||||
'user_network_approvals',
|
||||
['portal_network_id'],
|
||||
unique=False,
|
||||
)
|
||||
op.create_index(
|
||||
'ix_user_network_approvals_state',
|
||||
'user_network_approvals',
|
||||
['state'],
|
||||
unique=False,
|
||||
)
|
||||
op.create_index(
|
||||
'ix_user_network_approvals_user_id',
|
||||
'user_network_approvals',
|
||||
['user_id'],
|
||||
unique=False,
|
||||
)
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Step 3: Migrate data back into user_network_approvals
|
||||
# ------------------------------------------------------------------
|
||||
# Derive one approval row per (user_id, portal_network_id, deleted_at).
|
||||
# We use gen_random_uuid() to generate new approval IDs because the
|
||||
# original approval IDs were lost during the upgrade.
|
||||
op.execute(
|
||||
"""
|
||||
INSERT INTO user_network_approvals (
|
||||
id, organization_id, user_id, portal_network_id,
|
||||
granted_by_user_id, grant_type, state, justification,
|
||||
created_at, updated_at, deleted_at
|
||||
)
|
||||
SELECT
|
||||
gen_random_uuid()::text,
|
||||
(array_agg(organization_id ORDER BY created_at))[1],
|
||||
user_id,
|
||||
portal_network_id,
|
||||
(array_agg(granted_by_user_id ORDER BY created_at))[1],
|
||||
(array_agg(grant_type ORDER BY created_at))[1],
|
||||
(array_agg(status ORDER BY created_at))[1],
|
||||
(array_agg(justification ORDER BY created_at))[1],
|
||||
MIN(created_at),
|
||||
MAX(updated_at),
|
||||
deleted_at
|
||||
FROM network_access_requests
|
||||
GROUP BY user_id, portal_network_id, deleted_at;
|
||||
"""
|
||||
)
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Step 4: Recreate device_network_memberships table
|
||||
# ------------------------------------------------------------------
|
||||
op.create_table(
|
||||
'device_network_memberships',
|
||||
sa.Column('organization_id', sa.String(length=36), nullable=False),
|
||||
sa.Column('user_id', sa.String(length=36), nullable=False),
|
||||
sa.Column('device_id', sa.String(length=36), nullable=False),
|
||||
sa.Column('portal_network_id', sa.String(length=36), nullable=False),
|
||||
sa.Column('user_network_approval_id', sa.String(length=36), nullable=True),
|
||||
sa.Column(
|
||||
'state',
|
||||
sa.Enum(
|
||||
'pending_device_registration',
|
||||
'pending_request',
|
||||
'pending_manager_approval',
|
||||
'approved_inactive',
|
||||
'joined_deauthorized',
|
||||
'active_authorized',
|
||||
'activation_expired',
|
||||
'suspended',
|
||||
'revoked',
|
||||
'rejected',
|
||||
name='membership_state', create_type=False,
|
||||
),
|
||||
nullable=False,
|
||||
),
|
||||
sa.Column('join_seen', sa.Boolean(), nullable=False),
|
||||
sa.Column('currently_authorized', sa.Boolean(), nullable=False),
|
||||
sa.Column('approved_for_activation', sa.Boolean(), nullable=False),
|
||||
sa.Column('id', sa.String(length=36), nullable=False),
|
||||
sa.Column('created_at', sa.DateTime(), nullable=False),
|
||||
sa.Column('updated_at', sa.DateTime(), nullable=False),
|
||||
sa.Column('deleted_at', sa.DateTime(), nullable=True),
|
||||
sa.ForeignKeyConstraint(
|
||||
['device_id'], ['devices.id'],
|
||||
),
|
||||
sa.ForeignKeyConstraint(
|
||||
['organization_id'], ['organizations.id'],
|
||||
),
|
||||
sa.ForeignKeyConstraint(
|
||||
['portal_network_id'], ['portal_networks.id'],
|
||||
),
|
||||
sa.ForeignKeyConstraint(
|
||||
['user_id'], ['users.id'],
|
||||
),
|
||||
sa.ForeignKeyConstraint(
|
||||
['user_network_approval_id'], ['user_network_approvals.id'],
|
||||
),
|
||||
sa.PrimaryKeyConstraint('id'),
|
||||
sa.UniqueConstraint(
|
||||
'device_id', 'portal_network_id', 'deleted_at',
|
||||
name='uix_device_network',
|
||||
),
|
||||
)
|
||||
|
||||
# Recreate indexes on device_network_memberships
|
||||
op.create_index(
|
||||
'ix_device_network_memberships_device_id',
|
||||
'device_network_memberships',
|
||||
['device_id'],
|
||||
unique=False,
|
||||
)
|
||||
op.create_index(
|
||||
'ix_device_network_memberships_organization_id',
|
||||
'device_network_memberships',
|
||||
['organization_id'],
|
||||
unique=False,
|
||||
)
|
||||
op.create_index(
|
||||
'ix_device_network_memberships_portal_network_id',
|
||||
'device_network_memberships',
|
||||
['portal_network_id'],
|
||||
unique=False,
|
||||
)
|
||||
op.create_index(
|
||||
'ix_device_network_memberships_state',
|
||||
'device_network_memberships',
|
||||
['state'],
|
||||
unique=False,
|
||||
)
|
||||
op.create_index(
|
||||
'ix_device_network_memberships_user_id',
|
||||
'device_network_memberships',
|
||||
['user_id'],
|
||||
unique=False,
|
||||
)
|
||||
op.create_index(
|
||||
'ix_device_network_memberships_user_network_approval_id',
|
||||
'device_network_memberships',
|
||||
['user_network_approval_id'],
|
||||
unique=False,
|
||||
)
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Step 5: Migrate data back into device_network_memberships
|
||||
# ------------------------------------------------------------------
|
||||
# Map network_access_requests rows back to device_network_memberships.
|
||||
# Reverse the status/active mapping using a best-effort approach.
|
||||
op.execute(
|
||||
"""
|
||||
INSERT INTO device_network_memberships (
|
||||
id, organization_id, user_id, device_id, portal_network_id,
|
||||
user_network_approval_id, state, join_seen, currently_authorized,
|
||||
approved_for_activation, created_at, updated_at, deleted_at
|
||||
)
|
||||
SELECT
|
||||
nar.id,
|
||||
nar.organization_id,
|
||||
nar.user_id,
|
||||
nar.device_id,
|
||||
nar.portal_network_id,
|
||||
una.id AS user_network_approval_id,
|
||||
CASE nar.status
|
||||
WHEN 'approved' THEN
|
||||
CASE WHEN nar.active = true
|
||||
THEN 'active_authorized'
|
||||
ELSE 'approved_inactive'
|
||||
END
|
||||
WHEN 'pending' THEN 'pending_request'
|
||||
ELSE nar.status
|
||||
END AS state,
|
||||
nar.join_seen,
|
||||
nar.active AS currently_authorized,
|
||||
CASE
|
||||
WHEN nar.status = 'approved' THEN true
|
||||
ELSE false
|
||||
END AS approved_for_activation,
|
||||
nar.created_at,
|
||||
nar.updated_at,
|
||||
nar.deleted_at
|
||||
FROM network_access_requests nar
|
||||
JOIN user_network_approvals una
|
||||
ON una.user_id = nar.user_id
|
||||
AND una.portal_network_id = nar.portal_network_id
|
||||
AND (una.deleted_at IS NOT DISTINCT FROM nar.deleted_at);
|
||||
"""
|
||||
)
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Step 6: Restore activation_sessions FK
|
||||
# ------------------------------------------------------------------
|
||||
# 6a. Add the old column (nullable first so we can populate)
|
||||
op.add_column(
|
||||
'activation_sessions',
|
||||
sa.Column('device_network_membership_id', sa.String(length=36), nullable=True),
|
||||
)
|
||||
|
||||
# 6b. Populate the old column from the new column before it disappears
|
||||
op.execute(
|
||||
"""
|
||||
UPDATE activation_sessions
|
||||
SET device_network_membership_id = network_access_request_id
|
||||
WHERE network_access_request_id IS NOT NULL;
|
||||
"""
|
||||
)
|
||||
|
||||
# 6c. Drop the new column, FK, and index
|
||||
op.drop_constraint(
|
||||
'fk_activation_sessions_network_access_request',
|
||||
'activation_sessions',
|
||||
type_='foreignkey',
|
||||
)
|
||||
op.drop_index(
|
||||
'ix_activation_sessions_network_access_request_id',
|
||||
table_name='activation_sessions',
|
||||
)
|
||||
op.drop_column('activation_sessions', 'network_access_request_id')
|
||||
|
||||
# 6d. Alter the old column to NOT NULL
|
||||
op.alter_column(
|
||||
'activation_sessions',
|
||||
'device_network_membership_id',
|
||||
nullable=False,
|
||||
)
|
||||
|
||||
# 6d. Recreate the old foreign key
|
||||
op.create_foreign_key(
|
||||
None,
|
||||
'activation_sessions',
|
||||
'device_network_memberships',
|
||||
['device_network_membership_id'],
|
||||
['id'],
|
||||
)
|
||||
|
||||
# 6e. Recreate the old index
|
||||
op.create_index(
|
||||
'ix_activation_sessions_device_network_membership_id',
|
||||
'activation_sessions',
|
||||
['device_network_membership_id'],
|
||||
unique=False,
|
||||
)
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Step 7: Restore zerotier_memberships FK
|
||||
# ------------------------------------------------------------------
|
||||
# 7a. Add the old column (nullable first so we can populate)
|
||||
op.add_column(
|
||||
'zerotier_memberships',
|
||||
sa.Column('device_network_membership_id', sa.String(length=36), nullable=True),
|
||||
)
|
||||
|
||||
# 7b. Populate the old column from the new column before it disappears
|
||||
op.execute(
|
||||
"""
|
||||
UPDATE zerotier_memberships
|
||||
SET device_network_membership_id = network_access_request_id
|
||||
WHERE network_access_request_id IS NOT NULL;
|
||||
"""
|
||||
)
|
||||
|
||||
# 7c. Drop the new column, FK, and index
|
||||
op.drop_constraint(
|
||||
'fk_zerotier_memberships_network_access_request',
|
||||
'zerotier_memberships',
|
||||
type_='foreignkey',
|
||||
)
|
||||
op.drop_index(
|
||||
'ix_zerotier_memberships_network_access_request_id',
|
||||
table_name='zerotier_memberships',
|
||||
)
|
||||
op.drop_column('zerotier_memberships', 'network_access_request_id')
|
||||
|
||||
# 7d. Recreate the old foreign key
|
||||
op.create_foreign_key(
|
||||
None,
|
||||
'zerotier_memberships',
|
||||
'device_network_memberships',
|
||||
['device_network_membership_id'],
|
||||
['id'],
|
||||
)
|
||||
|
||||
# 7e. Recreate the old index
|
||||
op.create_index(
|
||||
'ix_zerotier_memberships_device_network_membership_id',
|
||||
'zerotier_memberships',
|
||||
['device_network_membership_id'],
|
||||
unique=False,
|
||||
)
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Step 8: Drop the new network_access_requests table and indexes
|
||||
# ------------------------------------------------------------------
|
||||
op.drop_index(
|
||||
'ix_network_access_requests_user_id',
|
||||
table_name='network_access_requests',
|
||||
)
|
||||
op.drop_index(
|
||||
'ix_network_access_requests_status',
|
||||
table_name='network_access_requests',
|
||||
)
|
||||
op.drop_index(
|
||||
'ix_network_access_requests_portal_network_id',
|
||||
table_name='network_access_requests',
|
||||
)
|
||||
op.drop_index(
|
||||
'ix_network_access_requests_organization_id',
|
||||
table_name='network_access_requests',
|
||||
)
|
||||
op.drop_index(
|
||||
'ix_network_access_requests_device_id',
|
||||
table_name='network_access_requests',
|
||||
)
|
||||
op.drop_table('network_access_requests')
|
||||
Reference in New Issue
Block a user