"""tools plugin baseline: the secure send table. Creates the one table this plugin owns. Tech Tools was schemaless until secure send arrived: a link that expires and dies on first read has to keep the ciphertext somewhere until it is claimed. Not an asset extension: a shared credential is a short-lived event rather than a thing the site inventories, so there is no assetid and no asset type. Explicit Alembic ops rather than the create_plugin_tables helper, matching the backups baseline: the helper builds a per-plugin MetaData filtered to this plugin's tables, so the foreign key to the core users table cannot resolve at CreateTable-compile time. """ from alembic import op import sqlalchemy as sa # revision identifiers, used by Alembic. revision = 'tools0001securesend' down_revision = None branch_labels = None depends_on = None def upgrade(): op.create_table( 'securesendsecrets', sa.Column('secretid', sa.Integer(), nullable=False), # 128 bits of randomness as hex. With no login on the read side this is # the credential, so it must never be a sequence. sa.Column('token', sa.String(length=64), nullable=False), sa.Column('ciphertext', sa.Text(), nullable=False), sa.Column('iv', sa.String(length=64), nullable=False), sa.Column('expiresat', sa.DateTime(), nullable=False), sa.Column('viewsremaining', sa.Integer(), nullable=False, server_default='1'), sa.Column('createdbyuserid', sa.Integer(), nullable=True), sa.Column('lastviewedat', sa.DateTime(), nullable=True), sa.Column('viewcount', sa.Integer(), nullable=False, server_default='0'), sa.Column('createddate', sa.DateTime(), nullable=False), sa.Column('modifieddate', sa.DateTime(), nullable=False), sa.Column('isactive', sa.Boolean(), nullable=False, server_default=sa.true()), sa.ForeignKeyConstraint(['createdbyuserid'], ['users.userid'], ondelete='SET NULL'), sa.PrimaryKeyConstraint('secretid'), ) # Unique, because the token is looked up on every read and two rows sharing # one would make a link ambiguous. op.create_index('ixsecuresendsecretstoken', 'securesendsecrets', ['token'], unique=True) # Expiry sweeps scan on this. op.create_index('ixsecuresendsecretsexpiresat', 'securesendsecrets', ['expiresat']) op.create_index('ixsecuresendsecretscreatedby', 'securesendsecrets', ['createdbyuserid']) def downgrade(): op.drop_index('ixsecuresendsecretscreatedby', table_name='securesendsecrets') op.drop_index('ixsecuresendsecretsexpiresat', table_name='securesendsecrets') op.drop_index('ixsecuresendsecretstoken', table_name='securesendsecrets') op.drop_table('securesendsecrets')