Fix database migrations; add cat/field/tag editing

Progress toward #4, #5, and #26
This commit is contained in:
digimint 2025-11-28 13:09:21 -06:00
parent ce18ed2fd4
commit 875c5f7f06
Signed by: digimint
GPG key ID: 8DF1C6FD85ABF748
27 changed files with 1343 additions and 46 deletions

View file

@ -9,9 +9,11 @@ from alembic import context
# access to the values within the .ini file in use.
config = context.config
# Interpret the config file for Python logging.
# This line sets up loggers basically.
fileConfig(config.config_file_name)
# for some reason, flask-migrate decided it was a good idea to override our
# logging config whenever we call any of their functions >:(
#
# this line has been commented out in order to remove this "feature"
# fileConfig(config.config_file_name)
logger = logging.getLogger('alembic.env')

View file

@ -0,0 +1,57 @@
"""Fix tag/field/category links
Revision ID: 067ee615c967
Revises: f34868d85e32
Create Date: 2025-11-28 12:03:26.164002
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = '067ee615c967'
down_revision = 'f34868d85e32'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.create_table('cat_to_task',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('cat', sa.Integer(), nullable=False),
sa.Column('task', sa.Integer(), nullable=False),
sa.ForeignKeyConstraint(['cat'], ['category.id'], name='fk_c2t_cat', ondelete='CASCADE'),
sa.ForeignKeyConstraint(['task'], ['task.id'], name='fk_c2t_task', ondelete='CASCADE'),
sa.PrimaryKeyConstraint('id')
)
op.create_table('field_to_task',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('field', sa.Integer(), nullable=False),
sa.Column('task', sa.Integer(), nullable=False),
sa.Column('raw_val', sa.String(length=1024), nullable=False),
sa.ForeignKeyConstraint(['field'], ['field.id'], name='fk_f2t_field', ondelete='CASCADE'),
sa.ForeignKeyConstraint(['task'], ['task.id'], name='fk_f2t_task', ondelete='CASCADE'),
sa.PrimaryKeyConstraint('id')
)
with op.batch_alter_table('field', schema=None) as batch_op:
batch_op.drop_column('raw_val')
with op.batch_alter_table('task', schema=None) as batch_op:
batch_op.add_column(sa.Column('soft_due', sa.DateTime(), nullable=True))
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table('task', schema=None) as batch_op:
batch_op.drop_column('soft_due')
with op.batch_alter_table('field', schema=None) as batch_op:
batch_op.add_column(sa.Column('raw_val', sa.VARCHAR(length=1024), nullable=False))
op.drop_table('field_to_task')
op.drop_table('cat_to_task')
# ### end Alembic commands ###

View file

@ -0,0 +1,151 @@
"""base
Revision ID: 6db9f9b83a8d
Revises:
Create Date: 2025-11-28 11:36:25.704433
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = '6db9f9b83a8d'
down_revision = None
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.create_table('namespace',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('name', sa.String(length=64), nullable=False),
sa.Column('description', sa.String(), nullable=False),
sa.Column('created', sa.DateTime(), nullable=False),
sa.PrimaryKeyConstraint('id')
)
op.create_table('pwned_password',
sa.Column('hash', sa.String(), nullable=False),
sa.Column('count', sa.Integer(), nullable=False),
sa.PrimaryKeyConstraint('hash')
)
op.create_table('user',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('username', sa.String(length=32), nullable=False),
sa.Column('display_name', sa.String(length=256), nullable=False),
sa.Column('created', sa.DateTime(), nullable=False),
sa.Column('enabled', sa.Boolean(), nullable=False),
sa.Column('administrator', sa.Boolean(), nullable=False),
sa.Column('pr_sub', sa.String(), nullable=False),
sa.Column('pr_obj', sa.String(), nullable=False),
sa.Column('pr_dep', sa.String(), nullable=False),
sa.Column('pr_ind', sa.String(), nullable=False),
sa.Column('pr_ref', sa.String(), nullable=False),
sa.Column('pr_plr', sa.Boolean(), nullable=False),
sa.Column('password', sa.String(length=256), nullable=False),
sa.Column('salt', sa.String(length=256), nullable=False),
sa.Column('hash_params', sa.String(length=256), nullable=False),
sa.PrimaryKeyConstraint('id'),
sa.UniqueConstraint('username')
)
op.create_table('namespace_role',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('name', sa.String(length=32), nullable=False),
sa.Column('permissions', sa.Integer(), nullable=False),
sa.Column('perms_deny', sa.Integer(), nullable=False),
sa.Column('priority', sa.Integer(), nullable=False),
sa.Column('created', sa.DateTime(), nullable=False),
sa.Column('namespace', sa.Integer(), nullable=False),
sa.ForeignKeyConstraint(['namespace'], ['namespace.id'], ),
sa.PrimaryKeyConstraint('id')
)
op.create_table('sign_up_code',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('code', sa.String(length=32), nullable=False),
sa.Column('created', sa.DateTime(), nullable=False),
sa.Column('expires', sa.DateTime(), nullable=False),
sa.Column('grants_admin', sa.Boolean(), nullable=False),
sa.Column('created_by', sa.Integer(), nullable=True),
sa.ForeignKeyConstraint(['created_by'], ['user.id'], ondelete='CASCADE'),
sa.PrimaryKeyConstraint('id'),
sa.UniqueConstraint('code')
)
op.create_table('task',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('name', sa.String(length=64), nullable=False),
sa.Column('description', sa.String(), nullable=False),
sa.Column('due', sa.DateTime(), nullable=False),
sa.Column('created', sa.DateTime(), nullable=False),
sa.Column('complete', sa.Boolean(), nullable=False),
sa.Column('namespace', sa.Integer(), nullable=False),
sa.Column('owner', sa.Integer(), nullable=False),
sa.ForeignKeyConstraint(['namespace'], ['namespace.id'], ondelete='CASCADE'),
sa.ForeignKeyConstraint(['owner'], ['user.id'], ondelete='CASCADE'),
sa.PrimaryKeyConstraint('id')
)
op.create_table('user_role',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('is_self', sa.Boolean(), nullable=False),
sa.Column('name', sa.String(length=32), nullable=False),
sa.Column('permissions', sa.Integer(), nullable=False),
sa.Column('perms_deny', sa.Integer(), nullable=False),
sa.Column('priority', sa.Integer(), nullable=False),
sa.Column('created', sa.DateTime(), nullable=False),
sa.Column('user', sa.Integer(), nullable=False),
sa.ForeignKeyConstraint(['user'], ['user.id'], ondelete='CASCADE'),
sa.PrimaryKeyConstraint('id')
)
op.create_table('namespace_invite_code',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('code', sa.String(length=32), nullable=False),
sa.Column('created', sa.DateTime(), nullable=False),
sa.Column('expires', sa.DateTime(), nullable=False),
sa.Column('created_by', sa.Integer(), nullable=False),
sa.Column('for_role', sa.Integer(), nullable=False),
sa.ForeignKeyConstraint(['created_by'], ['user.id'], ondelete='CASCADE'),
sa.ForeignKeyConstraint(['for_role'], ['namespace_role.id'], ondelete='CASCADE'),
sa.PrimaryKeyConstraint('id'),
sa.UniqueConstraint('code')
)
op.create_table('task_to_namespace',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('namespace', sa.Integer(), nullable=False),
sa.Column('task', sa.Integer(), nullable=False),
sa.ForeignKeyConstraint(['namespace'], ['namespace.id'], ondelete='CASCADE'),
sa.ForeignKeyConstraint(['task'], ['task.id'], ondelete='CASCADE'),
sa.PrimaryKeyConstraint('id')
)
op.create_table('user_to_namespace_role',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('user', sa.Integer(), nullable=False),
sa.Column('role', sa.Integer(), nullable=False),
sa.ForeignKeyConstraint(['role'], ['namespace_role.id'], ondelete='CASCADE'),
sa.ForeignKeyConstraint(['user'], ['user.id'], ondelete='CASCADE'),
sa.PrimaryKeyConstraint('id')
)
op.create_table('user_to_user_role',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('user', sa.Integer(), nullable=False),
sa.Column('role', sa.Integer(), nullable=False),
sa.ForeignKeyConstraint(['role'], ['user_role.id'], ondelete='CASCADE'),
sa.ForeignKeyConstraint(['user'], ['user.id'], ondelete='CASCADE'),
sa.PrimaryKeyConstraint('id')
)
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_table('user_to_user_role')
op.drop_table('user_to_namespace_role')
op.drop_table('task_to_namespace')
op.drop_table('namespace_invite_code')
op.drop_table('user_role')
op.drop_table('task')
op.drop_table('sign_up_code')
op.drop_table('namespace_role')
op.drop_table('user')
op.drop_table('pwned_password')
op.drop_table('namespace')
# ### end Alembic commands ###

View file

@ -11,7 +11,7 @@ import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = '945140c35257'
down_revision = None
down_revision = '6db9f9b83a8d'
branch_labels = None
depends_on = None