|
|
|
|
@@ -0,0 +1,174 @@
|
|
|
|
|
"""v0.1.7 calendar baseline
|
|
|
|
|
|
|
|
|
|
Revision ID: 9e0f1a2b3c4d
|
|
|
|
|
Revises: None
|
|
|
|
|
Create Date: 2026-07-11 00:00:00.000000
|
|
|
|
|
"""
|
|
|
|
|
from __future__ import annotations
|
|
|
|
|
|
|
|
|
|
from alembic import op
|
|
|
|
|
import sqlalchemy as sa
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
revision = '9e0f1a2b3c4d'
|
|
|
|
|
down_revision = None
|
|
|
|
|
branch_labels = None
|
|
|
|
|
depends_on = '4f2a9c8e7b6d'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def upgrade() -> None:
|
|
|
|
|
op.create_table('calendar_collections',
|
|
|
|
|
sa.Column('id', sa.String(length=36), nullable=False),
|
|
|
|
|
sa.Column('tenant_id', sa.String(length=36), nullable=False),
|
|
|
|
|
sa.Column('slug', sa.String(length=100), nullable=False),
|
|
|
|
|
sa.Column('name', sa.String(length=255), nullable=False),
|
|
|
|
|
sa.Column('description', sa.Text(), nullable=True),
|
|
|
|
|
sa.Column('timezone', sa.String(length=100), nullable=False),
|
|
|
|
|
sa.Column('color', sa.String(length=20), nullable=True),
|
|
|
|
|
sa.Column('owner_type', sa.String(length=20), nullable=False),
|
|
|
|
|
sa.Column('owner_id', sa.String(length=36), nullable=True),
|
|
|
|
|
sa.Column('visibility', sa.String(length=20), nullable=False),
|
|
|
|
|
sa.Column('is_default', sa.Boolean(), nullable=False),
|
|
|
|
|
sa.Column('created_by_user_id', sa.String(length=36), nullable=True),
|
|
|
|
|
sa.Column('deleted_at', sa.DateTime(timezone=True), nullable=True),
|
|
|
|
|
sa.Column('metadata', sa.JSON(), nullable=True),
|
|
|
|
|
sa.Column('created_at', sa.DateTime(timezone=True), nullable=False),
|
|
|
|
|
sa.Column('updated_at', sa.DateTime(timezone=True), nullable=False),
|
|
|
|
|
sa.ForeignKeyConstraint(['created_by_user_id'], ['access_users.id'], name=op.f('fk_calendar_collections_created_by_user_id_access_users'), ondelete='SET NULL'),
|
|
|
|
|
sa.ForeignKeyConstraint(['tenant_id'], ['core_scopes.id'], name=op.f('fk_calendar_collections_tenant_id_scopes'), ondelete='CASCADE'),
|
|
|
|
|
sa.PrimaryKeyConstraint('id', name=op.f('pk_calendar_collections'))
|
|
|
|
|
)
|
|
|
|
|
op.create_index(op.f('ix_calendar_collections_created_by_user_id'), 'calendar_collections', ['created_by_user_id'], unique=False)
|
|
|
|
|
op.create_index(op.f('ix_calendar_collections_deleted_at'), 'calendar_collections', ['deleted_at'], unique=False)
|
|
|
|
|
op.create_index(op.f('ix_calendar_collections_is_default'), 'calendar_collections', ['is_default'], unique=False)
|
|
|
|
|
op.create_index('ix_calendar_collections_owner', 'calendar_collections', ['tenant_id', 'owner_type', 'owner_id'], unique=False)
|
|
|
|
|
op.create_index(op.f('ix_calendar_collections_owner_id'), 'calendar_collections', ['owner_id'], unique=False)
|
|
|
|
|
op.create_index(op.f('ix_calendar_collections_owner_type'), 'calendar_collections', ['owner_type'], unique=False)
|
|
|
|
|
op.create_index(op.f('ix_calendar_collections_tenant_id'), 'calendar_collections', ['tenant_id'], unique=False)
|
|
|
|
|
op.create_index(op.f('ix_calendar_collections_visibility'), 'calendar_collections', ['visibility'], unique=False)
|
|
|
|
|
op.create_index('uq_calendar_collections_active_slug', 'calendar_collections', ['tenant_id', 'slug'], unique=True, sqlite_where=sa.text('deleted_at IS NULL'), postgresql_where=sa.text('deleted_at IS NULL'))
|
|
|
|
|
op.create_table('calendar_sync_credentials',
|
|
|
|
|
sa.Column('id', sa.String(length=36), nullable=False),
|
|
|
|
|
sa.Column('tenant_id', sa.String(length=36), nullable=False),
|
|
|
|
|
sa.Column('credential_kind', sa.String(length=30), nullable=False),
|
|
|
|
|
sa.Column('label', sa.String(length=255), nullable=True),
|
|
|
|
|
sa.Column('secret_encrypted', sa.Text(), nullable=True),
|
|
|
|
|
sa.Column('created_by_user_id', sa.String(length=36), nullable=True),
|
|
|
|
|
sa.Column('deleted_at', sa.DateTime(timezone=True), nullable=True),
|
|
|
|
|
sa.Column('metadata', sa.JSON(), nullable=True),
|
|
|
|
|
sa.Column('created_at', sa.DateTime(timezone=True), nullable=False),
|
|
|
|
|
sa.Column('updated_at', sa.DateTime(timezone=True), nullable=False),
|
|
|
|
|
sa.ForeignKeyConstraint(['created_by_user_id'], ['access_users.id'], name=op.f('fk_calendar_sync_credentials_created_by_user_id_access_users'), ondelete='SET NULL'),
|
|
|
|
|
sa.ForeignKeyConstraint(['tenant_id'], ['core_scopes.id'], name=op.f('fk_calendar_sync_credentials_tenant_id_scopes'), ondelete='CASCADE'),
|
|
|
|
|
sa.PrimaryKeyConstraint('id', name=op.f('pk_calendar_sync_credentials'))
|
|
|
|
|
)
|
|
|
|
|
op.create_index(op.f('ix_calendar_sync_credentials_created_by_user_id'), 'calendar_sync_credentials', ['created_by_user_id'], unique=False)
|
|
|
|
|
op.create_index(op.f('ix_calendar_sync_credentials_credential_kind'), 'calendar_sync_credentials', ['credential_kind'], unique=False)
|
|
|
|
|
op.create_index(op.f('ix_calendar_sync_credentials_deleted_at'), 'calendar_sync_credentials', ['deleted_at'], unique=False)
|
|
|
|
|
op.create_index(op.f('ix_calendar_sync_credentials_tenant_id'), 'calendar_sync_credentials', ['tenant_id'], unique=False)
|
|
|
|
|
op.create_index('ix_calendar_sync_credentials_tenant_kind', 'calendar_sync_credentials', ['tenant_id', 'credential_kind'], unique=False)
|
|
|
|
|
op.create_table('calendar_events',
|
|
|
|
|
sa.Column('id', sa.String(length=36), nullable=False),
|
|
|
|
|
sa.Column('tenant_id', sa.String(length=36), nullable=False),
|
|
|
|
|
sa.Column('calendar_id', sa.String(length=36), nullable=False),
|
|
|
|
|
sa.Column('uid', sa.String(length=255), nullable=False),
|
|
|
|
|
sa.Column('recurrence_id', sa.String(length=255), nullable=True),
|
|
|
|
|
sa.Column('sequence', sa.Integer(), nullable=False),
|
|
|
|
|
sa.Column('summary', sa.String(length=500), nullable=False),
|
|
|
|
|
sa.Column('description', sa.Text(), nullable=True),
|
|
|
|
|
sa.Column('location', sa.String(length=500), nullable=True),
|
|
|
|
|
sa.Column('status', sa.String(length=40), nullable=False),
|
|
|
|
|
sa.Column('transparency', sa.String(length=20), nullable=False),
|
|
|
|
|
sa.Column('classification', sa.String(length=20), nullable=False),
|
|
|
|
|
sa.Column('start_at', sa.DateTime(timezone=True), nullable=False),
|
|
|
|
|
sa.Column('end_at', sa.DateTime(timezone=True), nullable=True),
|
|
|
|
|
sa.Column('duration_seconds', sa.Integer(), nullable=True),
|
|
|
|
|
sa.Column('all_day', sa.Boolean(), nullable=False),
|
|
|
|
|
sa.Column('timezone', sa.String(length=100), nullable=True),
|
|
|
|
|
sa.Column('organizer', sa.JSON(), nullable=True),
|
|
|
|
|
sa.Column('attendees', sa.JSON(), nullable=False),
|
|
|
|
|
sa.Column('categories', sa.JSON(), nullable=False),
|
|
|
|
|
sa.Column('rrule', sa.JSON(), nullable=True),
|
|
|
|
|
sa.Column('rdate', sa.JSON(), nullable=False),
|
|
|
|
|
sa.Column('exdate', sa.JSON(), nullable=False),
|
|
|
|
|
sa.Column('reminders', sa.JSON(), nullable=False),
|
|
|
|
|
sa.Column('attachments', sa.JSON(), nullable=False),
|
|
|
|
|
sa.Column('related_to', sa.JSON(), nullable=False),
|
|
|
|
|
sa.Column('source_kind', sa.String(length=30), nullable=False),
|
|
|
|
|
sa.Column('source_href', sa.String(length=1000), nullable=True),
|
|
|
|
|
sa.Column('etag', sa.String(length=255), nullable=True),
|
|
|
|
|
sa.Column('icalendar', sa.JSON(), nullable=False),
|
|
|
|
|
sa.Column('raw_ics', sa.Text(), nullable=True),
|
|
|
|
|
sa.Column('created_by_user_id', sa.String(length=36), nullable=True),
|
|
|
|
|
sa.Column('updated_by_user_id', sa.String(length=36), nullable=True),
|
|
|
|
|
sa.Column('deleted_at', sa.DateTime(timezone=True), nullable=True),
|
|
|
|
|
sa.Column('metadata', sa.JSON(), nullable=True),
|
|
|
|
|
sa.Column('created_at', sa.DateTime(timezone=True), nullable=False),
|
|
|
|
|
sa.Column('updated_at', sa.DateTime(timezone=True), nullable=False),
|
|
|
|
|
sa.ForeignKeyConstraint(['calendar_id'], ['calendar_collections.id'], name=op.f('fk_calendar_events_calendar_id_calendar_collections'), ondelete='CASCADE'),
|
|
|
|
|
sa.ForeignKeyConstraint(['created_by_user_id'], ['access_users.id'], name=op.f('fk_calendar_events_created_by_user_id_access_users'), ondelete='SET NULL'),
|
|
|
|
|
sa.ForeignKeyConstraint(['tenant_id'], ['core_scopes.id'], name=op.f('fk_calendar_events_tenant_id_scopes'), ondelete='CASCADE'),
|
|
|
|
|
sa.ForeignKeyConstraint(['updated_by_user_id'], ['access_users.id'], name=op.f('fk_calendar_events_updated_by_user_id_access_users'), ondelete='SET NULL'),
|
|
|
|
|
sa.PrimaryKeyConstraint('id', name=op.f('pk_calendar_events')),
|
|
|
|
|
sa.UniqueConstraint('calendar_id', 'uid', 'recurrence_id', name='uq_calendar_events_calendar_uid_recurrence')
|
|
|
|
|
)
|
|
|
|
|
op.create_index(op.f('ix_calendar_events_all_day'), 'calendar_events', ['all_day'], unique=False)
|
|
|
|
|
op.create_index(op.f('ix_calendar_events_calendar_id'), 'calendar_events', ['calendar_id'], unique=False)
|
|
|
|
|
op.create_index(op.f('ix_calendar_events_created_by_user_id'), 'calendar_events', ['created_by_user_id'], unique=False)
|
|
|
|
|
op.create_index(op.f('ix_calendar_events_deleted_at'), 'calendar_events', ['deleted_at'], unique=False)
|
|
|
|
|
op.create_index(op.f('ix_calendar_events_end_at'), 'calendar_events', ['end_at'], unique=False)
|
|
|
|
|
op.create_index(op.f('ix_calendar_events_etag'), 'calendar_events', ['etag'], unique=False)
|
|
|
|
|
op.create_index('ix_calendar_events_range', 'calendar_events', ['tenant_id', 'calendar_id', 'start_at', 'end_at'], unique=False)
|
|
|
|
|
op.create_index(op.f('ix_calendar_events_recurrence_id'), 'calendar_events', ['recurrence_id'], unique=False)
|
|
|
|
|
op.create_index(op.f('ix_calendar_events_source_kind'), 'calendar_events', ['source_kind'], unique=False)
|
|
|
|
|
op.create_index(op.f('ix_calendar_events_start_at'), 'calendar_events', ['start_at'], unique=False)
|
|
|
|
|
op.create_index(op.f('ix_calendar_events_status'), 'calendar_events', ['status'], unique=False)
|
|
|
|
|
op.create_index(op.f('ix_calendar_events_tenant_id'), 'calendar_events', ['tenant_id'], unique=False)
|
|
|
|
|
op.create_index('ix_calendar_events_tenant_status', 'calendar_events', ['tenant_id', 'status'], unique=False)
|
|
|
|
|
op.create_index('ix_calendar_events_tenant_uid', 'calendar_events', ['tenant_id', 'uid'], unique=False)
|
|
|
|
|
op.create_index(op.f('ix_calendar_events_uid'), 'calendar_events', ['uid'], unique=False)
|
|
|
|
|
op.create_index(op.f('ix_calendar_events_updated_by_user_id'), 'calendar_events', ['updated_by_user_id'], unique=False)
|
|
|
|
|
op.create_table('calendar_sync_sources',
|
|
|
|
|
sa.Column('id', sa.String(length=36), nullable=False),
|
|
|
|
|
sa.Column('tenant_id', sa.String(length=36), nullable=False),
|
|
|
|
|
sa.Column('calendar_id', sa.String(length=36), nullable=False),
|
|
|
|
|
sa.Column('source_kind', sa.String(length=30), nullable=False),
|
|
|
|
|
sa.Column('collection_url', sa.String(length=1000), nullable=False),
|
|
|
|
|
sa.Column('display_name', sa.String(length=255), nullable=True),
|
|
|
|
|
sa.Column('auth_type', sa.String(length=30), nullable=False),
|
|
|
|
|
sa.Column('username', sa.String(length=255), nullable=True),
|
|
|
|
|
sa.Column('credential_ref', sa.String(length=255), nullable=True),
|
|
|
|
|
sa.Column('sync_enabled', sa.Boolean(), nullable=False),
|
|
|
|
|
sa.Column('sync_interval_seconds', sa.Integer(), nullable=False),
|
|
|
|
|
sa.Column('sync_direction', sa.String(length=30), nullable=False),
|
|
|
|
|
sa.Column('conflict_policy', sa.String(length=30), nullable=False),
|
|
|
|
|
sa.Column('sync_token', sa.Text(), nullable=True),
|
|
|
|
|
sa.Column('ctag', sa.String(length=255), nullable=True),
|
|
|
|
|
sa.Column('last_attempt_at', sa.DateTime(timezone=True), nullable=True),
|
|
|
|
|
sa.Column('last_synced_at', sa.DateTime(timezone=True), nullable=True),
|
|
|
|
|
sa.Column('next_sync_at', sa.DateTime(timezone=True), nullable=True),
|
|
|
|
|
sa.Column('last_status', sa.String(length=30), nullable=True),
|
|
|
|
|
sa.Column('last_error', sa.Text(), nullable=True),
|
|
|
|
|
sa.Column('deleted_at', sa.DateTime(timezone=True), nullable=True),
|
|
|
|
|
sa.Column('metadata', sa.JSON(), nullable=True),
|
|
|
|
|
sa.Column('created_at', sa.DateTime(timezone=True), nullable=False),
|
|
|
|
|
sa.Column('updated_at', sa.DateTime(timezone=True), nullable=False),
|
|
|
|
|
sa.ForeignKeyConstraint(['calendar_id'], ['calendar_collections.id'], name=op.f('fk_calendar_sync_sources_calendar_id_calendar_collections'), ondelete='CASCADE'),
|
|
|
|
|
sa.ForeignKeyConstraint(['tenant_id'], ['core_scopes.id'], name=op.f('fk_calendar_sync_sources_tenant_id_scopes'), ondelete='CASCADE'),
|
|
|
|
|
sa.PrimaryKeyConstraint('id', name=op.f('pk_calendar_sync_sources'))
|
|
|
|
|
)
|
|
|
|
|
op.create_index('ix_calendar_sync_sources_calendar', 'calendar_sync_sources', ['tenant_id', 'calendar_id', 'source_kind'], unique=False)
|
|
|
|
|
op.create_index(op.f('ix_calendar_sync_sources_calendar_id'), 'calendar_sync_sources', ['calendar_id'], unique=False)
|
|
|
|
|
op.create_index(op.f('ix_calendar_sync_sources_deleted_at'), 'calendar_sync_sources', ['deleted_at'], unique=False)
|
|
|
|
|
op.create_index(op.f('ix_calendar_sync_sources_next_sync_at'), 'calendar_sync_sources', ['next_sync_at'], unique=False)
|
|
|
|
|
op.create_index(op.f('ix_calendar_sync_sources_source_kind'), 'calendar_sync_sources', ['source_kind'], unique=False)
|
|
|
|
|
op.create_index(op.f('ix_calendar_sync_sources_sync_enabled'), 'calendar_sync_sources', ['sync_enabled'], unique=False)
|
|
|
|
|
op.create_index(op.f('ix_calendar_sync_sources_tenant_id'), 'calendar_sync_sources', ['tenant_id'], unique=False)
|
|
|
|
|
op.create_index('uq_calendar_sync_sources_active_url', 'calendar_sync_sources', ['tenant_id', 'source_kind', 'collection_url'], unique=True, sqlite_where=sa.text('deleted_at IS NULL'), postgresql_where=sa.text('deleted_at IS NULL'))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def downgrade() -> None:
|
|
|
|
|
op.drop_table('calendar_sync_sources')
|
|
|
|
|
op.drop_table('calendar_events')
|
|
|
|
|
op.drop_table('calendar_sync_credentials')
|
|
|
|
|
op.drop_table('calendar_collections')
|