Files
TimeTracker/app
MacJediWizard 101eb4abf4 fix(uploads,kanban): write all attachment routes to mounted volume; eliminate validator-drift bugs
Two distinct fix sets in one commit, both extending the kanban validator
fix in PR #605 and the project_attachments path-resolution fix already
discussed in this repo's history.

PHASE A — five upload routes joined current_app.root_path + ".." +
"uploads/<X>", which on a deployed instance with the standard
docker-compose layout resolves to /app/uploads/<X>. That path is
outside the mounted app_uploads volume, so every upload returns 500
with PermissionError. Same defect as project_attachments.

  - app/routes/team_chat.py:470 (chat attachments)
  - app/routes/clients.py:1257 (client attachments)
  - app/routes/comments.py:279 (comment attachments)
  - app/routes/quotes.py:1120 (quote attachments)
  - app/routes/client_portal.py:1330,1347 (legacy "uploads/" download
    fallback branches — same join, same bug)

Fix prepends "app/static/" so the resolved path lands inside the
mounted volume at /app/app/static/uploads/<X>. Mirrors the
invoice_images and quote_images patterns elsewhere in the same files.

PHASE B — validator/UI drift bugs, same class as the kanban fix in #605.

  - app/models/kanban_column.py
      * new helper get_columns_with_global_fallback() — returns
        project columns or falls back to globals; mirrors
        get_valid_status_keys behaviour for templates
      * last-ditch hardcoded fallback in get_valid_status_keys now
        includes "on_hold" so the table-not-yet-seeded path matches
        the keys initialize_default_columns seeds
  - app/routes/tasks.py
      * task_counts now initialises from kanban_columns instead of
        the hardcoded 4 keys; tasks in cancelled/on_hold/custom
        columns are counted in the summary cards
      * create-task validator now calls get_valid_status_keys(project_id)
        instead of a hardcoded 5-key tuple; users creating a task in
        on_hold no longer silently get clamped to todo
      * every render_template("tasks/create.html", ...) and
        ("tasks/edit.html", ...) now passes kanban_columns
  - app/templates/tasks/create.html and tasks/edit.html
      * status <option> list now loops over kanban_columns instead of
        hardcoding 5 keys
  - app/routes/invoices.py:832
      * bulk-update validator now accepts "issued", mirroring the
        single-update validator at line 623; the model supports it
  - app/routes/quotes.py:920, 1026, 1320
      * admin-notification queries now use User.is_admin (which
        considers both the legacy role column AND Role rows) instead
        of User.query.filter_by(role="admin", ...). RBAC-only admins
        granted via the Role table are now notified on quote.sent,
        quote.accepted, and quote.approval.requested.

10 files, +60 / -41. No schema change. No data migration.
2026-05-01 16:00:14 -04:00
..