printeditemfiles lands as the plugin's first incremental migration (0002 on the plugin chain - the ADR-008 payoff). Revisions are append-only per item: upload assigns the next number, records the uploader from the JWT, enforces an extension allowlist and a 100 MB cap; download serves the original filename; a permission-gated delete covers wrong-file mistakes. The detail page gains the revision table with a current badge. Unique storedfilename is sized 191 so the index fits MySQL's 767-byte prefix - the per-plugin chain does not apply the core env's ROW_FORMAT hook. Alert recipients gain roles: Role joins the 0.13.0 surface, a role picker on the settings page, and every active member of the selected roles is folded into the deduped recipient list.
44 lines
1.7 KiB
Python
44 lines
1.7 KiB
Python
"""Add printeditemfiles: append-only print-file revisions per item.
|
|
|
|
The plugin's first incremental migration on top of its 0001 baseline -
|
|
the ADR-008 payoff: the plugin evolves its own schema without touching
|
|
the core chain. Applied by `flask plugin upgrade-all`.
|
|
"""
|
|
from alembic import op
|
|
import sqlalchemy as sa
|
|
|
|
|
|
# revision identifiers, used by Alembic.
|
|
revision = 'printedparts0002files'
|
|
down_revision = 'printedparts0001baseline'
|
|
branch_labels = None
|
|
depends_on = None
|
|
|
|
|
|
def upgrade():
|
|
op.create_table(
|
|
'printeditemfiles',
|
|
sa.Column('fileid', sa.Integer(), nullable=False),
|
|
sa.Column('printeditemid', sa.Integer(), nullable=False),
|
|
sa.Column('revision', sa.Integer(), nullable=False),
|
|
sa.Column('filename', sa.String(length=255), nullable=False),
|
|
sa.Column('storedfilename', sa.String(length=191), nullable=False),
|
|
sa.Column('filesize', sa.Integer(), nullable=False),
|
|
sa.Column('uploadnote', sa.String(length=255), nullable=True),
|
|
sa.Column('uploadedby', sa.String(length=80), nullable=False),
|
|
sa.Column('createddate', sa.DateTime(), nullable=False),
|
|
sa.Column('modifieddate', sa.DateTime(), nullable=False),
|
|
sa.Column('isactive', sa.Boolean(), nullable=False),
|
|
sa.ForeignKeyConstraint(['printeditemid'],
|
|
['printeditems.printeditemid'],
|
|
ondelete='CASCADE'),
|
|
sa.PrimaryKeyConstraint('fileid'),
|
|
sa.UniqueConstraint('storedfilename'),
|
|
)
|
|
op.create_index('ix_printeditemfiles_printeditemid',
|
|
'printeditemfiles', ['printeditemid'])
|
|
|
|
|
|
def downgrade():
|
|
op.drop_table('printeditemfiles')
|