Files
Hotel-Booking/Backend/alembic/versions/add_enterprise_features.py
Iliyan Angelov 1a103a769f updates
2025-12-01 01:08:39 +02:00

219 lines
14 KiB
Python

"""
Add enterprise features: approval workflows, GDPR requests, sessions, webhooks, API keys.
"""
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import mysql
revision = 'add_enterprise_features'
down_revision = 'add_sections_blog' # Depends on latest migration
branch_labels = None
depends_on = None
def upgrade() -> None:
# Approval workflow table
op.create_table(
'approval_requests',
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
sa.Column('approval_type', sa.Enum('invoice_update', 'payment_refund', 'invoice_mark_paid', 'financial_adjustment', 'user_role_change', 'large_transaction', name='approvaltype'), nullable=False),
sa.Column('status', sa.Enum('pending', 'approved', 'rejected', 'cancelled', name='approvalstatus'), nullable=False),
sa.Column('requested_by', sa.Integer(), nullable=False),
sa.Column('requested_at', sa.DateTime(), nullable=False),
sa.Column('approved_by', sa.Integer(), nullable=True),
sa.Column('approved_at', sa.DateTime(), nullable=True),
sa.Column('rejection_reason', sa.Text(), nullable=True),
sa.Column('resource_type', sa.String(length=50), nullable=False),
sa.Column('resource_id', sa.Integer(), nullable=False),
sa.Column('request_data', sa.JSON(), nullable=True),
sa.Column('current_data', sa.JSON(), nullable=True),
sa.Column('priority', sa.String(length=20), nullable=True),
sa.Column('notes', sa.Text(), nullable=True),
sa.Column('extra_metadata', sa.JSON(), nullable=True),
sa.Column('created_at', sa.DateTime(), nullable=False),
sa.Column('updated_at', sa.DateTime(), nullable=False),
sa.ForeignKeyConstraint(['approved_by'], ['users.id'], ),
sa.ForeignKeyConstraint(['requested_by'], ['users.id'], ),
sa.PrimaryKeyConstraint('id')
)
op.create_index(op.f('ix_approval_requests_id'), 'approval_requests', ['id'], unique=False)
op.create_index(op.f('ix_approval_requests_approval_type'), 'approval_requests', ['approval_type'], unique=False)
op.create_index(op.f('ix_approval_requests_status'), 'approval_requests', ['status'], unique=False)
op.create_index(op.f('ix_approval_requests_requested_by'), 'approval_requests', ['requested_by'], unique=False)
op.create_index(op.f('ix_approval_requests_approved_by'), 'approval_requests', ['approved_by'], unique=False)
op.create_index(op.f('ix_approval_requests_resource_type'), 'approval_requests', ['resource_type'], unique=False)
op.create_index(op.f('ix_approval_requests_resource_id'), 'approval_requests', ['resource_id'], unique=False)
# GDPR requests table
op.create_table(
'gdpr_requests',
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
sa.Column('request_type', sa.Enum('data_export', 'data_deletion', 'data_rectification', 'consent_withdrawal', name='gdprrequesttype'), nullable=False),
sa.Column('status', sa.Enum('pending', 'processing', 'completed', 'rejected', 'cancelled', name='gdprrequeststatus'), nullable=False),
sa.Column('user_id', sa.Integer(), nullable=False),
sa.Column('user_email', sa.String(length=255), nullable=False),
sa.Column('request_data', sa.JSON(), nullable=True),
sa.Column('verification_token', sa.String(length=255), nullable=True),
sa.Column('verified_at', sa.DateTime(), nullable=True),
sa.Column('processed_by', sa.Integer(), nullable=True),
sa.Column('processed_at', sa.DateTime(), nullable=True),
sa.Column('processing_notes', sa.Text(), nullable=True),
sa.Column('export_file_path', sa.String(length=500), nullable=True),
sa.Column('deletion_log', sa.JSON(), nullable=True),
sa.Column('ip_address', sa.String(length=45), nullable=True),
sa.Column('user_agent', sa.String(length=255), nullable=True),
sa.Column('created_at', sa.DateTime(), nullable=False),
sa.Column('updated_at', sa.DateTime(), nullable=False),
sa.Column('expires_at', sa.DateTime(), nullable=True),
sa.ForeignKeyConstraint(['processed_by'], ['users.id'], ),
sa.ForeignKeyConstraint(['user_id'], ['users.id'], ),
sa.PrimaryKeyConstraint('id')
)
op.create_index(op.f('ix_gdpr_requests_id'), 'gdpr_requests', ['id'], unique=False)
op.create_index(op.f('ix_gdpr_requests_request_type'), 'gdpr_requests', ['request_type'], unique=False)
op.create_index(op.f('ix_gdpr_requests_status'), 'gdpr_requests', ['status'], unique=False)
op.create_index(op.f('ix_gdpr_requests_user_id'), 'gdpr_requests', ['user_id'], unique=False)
op.create_index(op.f('ix_gdpr_requests_verification_token'), 'gdpr_requests', ['verification_token'], unique=True)
# User sessions table
op.create_table(
'user_sessions',
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
sa.Column('user_id', sa.Integer(), nullable=False),
sa.Column('session_token', sa.String(length=255), nullable=False),
sa.Column('refresh_token', sa.String(length=255), nullable=True),
sa.Column('ip_address', sa.String(length=45), nullable=True),
sa.Column('user_agent', sa.String(length=500), nullable=True),
sa.Column('device_info', sa.Text(), nullable=True),
sa.Column('is_active', sa.Boolean(), nullable=False),
sa.Column('last_activity', sa.DateTime(), nullable=False),
sa.Column('expires_at', sa.DateTime(), nullable=False),
sa.Column('created_at', sa.DateTime(), nullable=False),
sa.ForeignKeyConstraint(['user_id'], ['users.id'], ),
sa.PrimaryKeyConstraint('id')
)
op.create_index(op.f('ix_user_sessions_id'), 'user_sessions', ['id'], unique=False)
op.create_index(op.f('ix_user_sessions_user_id'), 'user_sessions', ['user_id'], unique=False)
op.create_index(op.f('ix_user_sessions_session_token'), 'user_sessions', ['session_token'], unique=True)
op.create_index(op.f('ix_user_sessions_refresh_token'), 'user_sessions', ['refresh_token'], unique=True)
op.create_index(op.f('ix_user_sessions_is_active'), 'user_sessions', ['is_active'], unique=False)
op.create_index(op.f('ix_user_sessions_last_activity'), 'user_sessions', ['last_activity'], unique=False)
op.create_index(op.f('ix_user_sessions_expires_at'), 'user_sessions', ['expires_at'], unique=False)
# Webhooks table
op.create_table(
'webhooks',
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
sa.Column('name', sa.String(length=255), nullable=False),
sa.Column('url', sa.String(length=500), nullable=False),
sa.Column('secret', sa.String(length=255), nullable=False),
sa.Column('events', sa.JSON(), nullable=False),
sa.Column('status', sa.Enum('active', 'inactive', 'paused', name='webhookstatus'), nullable=False),
sa.Column('retry_count', sa.Integer(), nullable=False),
sa.Column('timeout_seconds', sa.Integer(), nullable=False),
sa.Column('description', sa.Text(), nullable=True),
sa.Column('created_by', sa.Integer(), nullable=True),
sa.Column('created_at', sa.DateTime(), nullable=False),
sa.Column('updated_at', sa.DateTime(), nullable=False),
sa.ForeignKeyConstraint(['created_by'], ['users.id'], ),
sa.PrimaryKeyConstraint('id')
)
op.create_index(op.f('ix_webhooks_id'), 'webhooks', ['id'], unique=False)
op.create_index(op.f('ix_webhooks_status'), 'webhooks', ['status'], unique=False)
# Webhook deliveries table
op.create_table(
'webhook_deliveries',
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
sa.Column('webhook_id', sa.Integer(), nullable=False),
sa.Column('event_type', sa.String(length=100), nullable=False),
sa.Column('event_id', sa.String(length=255), nullable=False),
sa.Column('status', sa.Enum('pending', 'success', 'failed', 'retrying', name='webhookdeliverystatus'), nullable=False),
sa.Column('payload', sa.JSON(), nullable=False),
sa.Column('response_status', sa.Integer(), nullable=True),
sa.Column('response_body', sa.Text(), nullable=True),
sa.Column('error_message', sa.Text(), nullable=True),
sa.Column('attempt_count', sa.Integer(), nullable=False),
sa.Column('next_retry_at', sa.DateTime(), nullable=True),
sa.Column('delivered_at', sa.DateTime(), nullable=True),
sa.Column('created_at', sa.DateTime(), nullable=False),
sa.ForeignKeyConstraint(['webhook_id'], ['webhooks.id'], ),
sa.PrimaryKeyConstraint('id')
)
op.create_index(op.f('ix_webhook_deliveries_id'), 'webhook_deliveries', ['id'], unique=False)
op.create_index(op.f('ix_webhook_deliveries_webhook_id'), 'webhook_deliveries', ['webhook_id'], unique=False)
op.create_index(op.f('ix_webhook_deliveries_event_type'), 'webhook_deliveries', ['event_type'], unique=False)
op.create_index(op.f('ix_webhook_deliveries_event_id'), 'webhook_deliveries', ['event_id'], unique=False)
op.create_index(op.f('ix_webhook_deliveries_status'), 'webhook_deliveries', ['status'], unique=False)
op.create_index(op.f('ix_webhook_deliveries_created_at'), 'webhook_deliveries', ['created_at'], unique=False)
# API keys table
op.create_table(
'api_keys',
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
sa.Column('name', sa.String(length=255), nullable=False),
sa.Column('key_hash', sa.String(length=255), nullable=False),
sa.Column('key_prefix', sa.String(length=20), nullable=False),
sa.Column('scopes', sa.JSON(), nullable=False),
sa.Column('rate_limit', sa.Integer(), nullable=False),
sa.Column('is_active', sa.Boolean(), nullable=False),
sa.Column('expires_at', sa.DateTime(), nullable=True),
sa.Column('description', sa.Text(), nullable=True),
sa.Column('last_used_at', sa.DateTime(), nullable=True),
sa.Column('created_by', sa.Integer(), nullable=True),
sa.Column('created_at', sa.DateTime(), nullable=False),
sa.Column('updated_at', sa.DateTime(), nullable=False),
sa.ForeignKeyConstraint(['created_by'], ['users.id'], ),
sa.PrimaryKeyConstraint('id')
)
op.create_index(op.f('ix_api_keys_id'), 'api_keys', ['id'], unique=False)
op.create_index(op.f('ix_api_keys_key_hash'), 'api_keys', ['key_hash'], unique=True)
op.create_index(op.f('ix_api_keys_key_prefix'), 'api_keys', ['key_prefix'], unique=False)
op.create_index(op.f('ix_api_keys_is_active'), 'api_keys', ['is_active'], unique=False)
op.create_index(op.f('ix_api_keys_expires_at'), 'api_keys', ['expires_at'], unique=False)
def downgrade() -> None:
op.drop_index(op.f('ix_api_keys_expires_at'), table_name='api_keys')
op.drop_index(op.f('ix_api_keys_is_active'), table_name='api_keys')
op.drop_index(op.f('ix_api_keys_key_prefix'), table_name='api_keys')
op.drop_index(op.f('ix_api_keys_key_hash'), table_name='api_keys')
op.drop_index(op.f('ix_api_keys_id'), table_name='api_keys')
op.drop_table('api_keys')
op.drop_index(op.f('ix_webhook_deliveries_created_at'), table_name='webhook_deliveries')
op.drop_index(op.f('ix_webhook_deliveries_status'), table_name='webhook_deliveries')
op.drop_index(op.f('ix_webhook_deliveries_event_id'), table_name='webhook_deliveries')
op.drop_index(op.f('ix_webhook_deliveries_event_type'), table_name='webhook_deliveries')
op.drop_index(op.f('ix_webhook_deliveries_webhook_id'), table_name='webhook_deliveries')
op.drop_index(op.f('ix_webhook_deliveries_id'), table_name='webhook_deliveries')
op.drop_table('webhook_deliveries')
op.drop_index(op.f('ix_webhooks_status'), table_name='webhooks')
op.drop_index(op.f('ix_webhooks_id'), table_name='webhooks')
op.drop_table('webhooks')
op.drop_index(op.f('ix_user_sessions_expires_at'), table_name='user_sessions')
op.drop_index(op.f('ix_user_sessions_last_activity'), table_name='user_sessions')
op.drop_index(op.f('ix_user_sessions_is_active'), table_name='user_sessions')
op.drop_index(op.f('ix_user_sessions_refresh_token'), table_name='user_sessions')
op.drop_index(op.f('ix_user_sessions_session_token'), table_name='user_sessions')
op.drop_index(op.f('ix_user_sessions_user_id'), table_name='user_sessions')
op.drop_index(op.f('ix_user_sessions_id'), table_name='user_sessions')
op.drop_table('user_sessions')
op.drop_index(op.f('ix_gdpr_requests_verification_token'), table_name='gdpr_requests')
op.drop_index(op.f('ix_gdpr_requests_user_id'), table_name='gdpr_requests')
op.drop_index(op.f('ix_gdpr_requests_status'), table_name='gdpr_requests')
op.drop_index(op.f('ix_gdpr_requests_request_type'), table_name='gdpr_requests')
op.drop_index(op.f('ix_gdpr_requests_id'), table_name='gdpr_requests')
op.drop_table('gdpr_requests')
op.drop_index(op.f('ix_approval_requests_resource_id'), table_name='approval_requests')
op.drop_index(op.f('ix_approval_requests_resource_type'), table_name='approval_requests')
op.drop_index(op.f('ix_approval_requests_approved_by'), table_name='approval_requests')
op.drop_index(op.f('ix_approval_requests_requested_by'), table_name='approval_requests')
op.drop_index(op.f('ix_approval_requests_status'), table_name='approval_requests')
op.drop_index(op.f('ix_approval_requests_approval_type'), table_name='approval_requests')
op.drop_index(op.f('ix_approval_requests_id'), table_name='approval_requests')
op.drop_table('approval_requests')