Files
TimeTracker/migrations/versions/005_add_missing_columns.py
Dries Peeters 7486037307 feat: local SQLite test env, UI fixes, and DB migrations
- UI/UX: Refine layouts and responsive styles; fix task and timer views; update
  shared components and dashboard templates
  - Updates across `app/templates/**`, `templates/**`, `app/static/base.css`,
    and `app/static/mobile.css`
- Backend: Route cleanups and minor fixes for admin, auth, invoices, and timer
  - Touches `app/routes/admin.py`, `app/routes/auth.py`, `app/routes/api.py`,
    `app/routes/invoices.py`, `app/routes/timer.py`
- DevOps: Improve Docker setup and add local testing workflow
  - Update `Dockerfile`, `docker/start-fixed.py`
  - Add `docker-compose.local-test.yml`, `.env.local-test`, start scripts
- Docs: Update `README.md` and add `docs/LOCAL_TESTING_WITH_SQLITE.md`
- Utilities: Adjust CLI and PDF generator behavior

Database (Alembic) migrations:
- 005_add_missing_columns.py
- 006_add_logo_and_task_timestamps.py
- 007_add_invoice_and_more_settings_columns.py
- 008_align_invoices_and_settings_more.py
- 009_add_invoice_created_by.py
- 010_enforce_single_active_timer.py

BREAKING CHANGE: Only one active timer per user is now enforced.

Note: Apply database migrations after deploy (e.g., `alembic upgrade head`).
2025-09-10 11:49:49 +02:00

57 lines
1.8 KiB
Python

"""add missing columns for settings and time_entries
Revision ID: 005
Revises: 004
Create Date: 2025-09-08 16:30:00
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = '005'
down_revision = '004'
branch_labels = None
depends_on = None
def upgrade() -> None:
bind = op.get_bind()
inspector = sa.inspect(bind)
# Existing columns per table
settings_cols = {c['name'] for c in inspector.get_columns('settings')}
time_entries_cols = {c['name'] for c in inspector.get_columns('time_entries')}
# Add columns to settings if missing
to_add_settings = []
if 'backup_retention_days' not in settings_cols:
to_add_settings.append(sa.Column('backup_retention_days', sa.Integer(), nullable=False, server_default='30'))
if 'backup_time' not in settings_cols:
to_add_settings.append(sa.Column('backup_time', sa.String(length=5), nullable=False, server_default='02:00'))
if 'export_delimiter' not in settings_cols:
to_add_settings.append(sa.Column('export_delimiter', sa.String(length=1), nullable=False, server_default=','))
if to_add_settings:
with op.batch_alter_table('settings') as batch_op:
for col in to_add_settings:
batch_op.add_column(col)
# Add column to time_entries if missing
if 'duration_seconds' not in time_entries_cols:
with op.batch_alter_table('time_entries') as batch_op:
batch_op.add_column(sa.Column('duration_seconds', sa.Integer(), nullable=True))
def downgrade() -> None:
with op.batch_alter_table('time_entries') as batch_op:
batch_op.drop_column('duration_seconds')
with op.batch_alter_table('settings') as batch_op:
batch_op.drop_column('export_delimiter')
batch_op.drop_column('backup_time')
batch_op.drop_column('backup_retention_days')