Skip to content

Sprint 4 follow-up — implement ICS format for /solutions/{id}/export - #251

Closed
tomqwu wants to merge 1 commit into
mainfrom
claude/sweet-hamilton-uo6hb7
Closed

tomqwu wants to merge 1 commit into
mainfrom
claude/sweet-hamilton-uo6hb7

Conversation

@tomqwu

@tomqwu tomqwu commented Aug 20, 2026

Copy link
Copy Markdown
Owner

Summary

POST /api/v1/solutions/{id}/export returned 501 Not Implemented for
format: "ics" with a stale TODO: ICS export has StringIO bug – needs fixing.
The generate_ics_from_events helper in api/utils/calendar_utils already
produces well-formed VCALENDAR output for the calendar router, so this PR
wires it into the export branch and closes the gap. Admins can now download
solution_<id>.ics alongside the existing JSON / CSV / PDF formats.

Changes

  • api/routers/solutions.py — replace the 501 branch with an
    event-per-VEVENT build via generate_ics_from_events. The per-person
    scope: "person:{id}" filter that was already applied to the working
    assignments list carries over (a person scope trims the event list and
    strips other people's names from assignment descriptions). Response is
    text/calendar; charset=utf-8 with a solution_<id>.ics
    Content-Disposition.
  • tests/api/test_solution_export_ics.py — new test module:
    • org-scope happy path (two VEVENTs, right SUMMARY values, headers)
    • person-scope filter (only that person's events)
    • empty-solution guard (still 400 before format branching)
    • unknown-solution 404

Validation

  • poetry run pytest tests/api/ — 336 passed
  • poetry run pytest tests/unit/ — 350 passed, 21 skipped
  • poetry run pytest tests/contract/ — snapshot still matches (endpoint
    shape is unchanged — FastAPI already declared the response as
    application/json with an empty schema; the dynamic media type isn't
    reflected in the OpenAPI doc so no snapshot refresh is needed)
  • poetry run black api tests and poetry run ruff check api tests clean
  • poetry run mypy api/utils api/core api/schemas — strict, clean

Follow-ups

  • POST /solutions/{id}/export still has no Depends(get_current_user) /
    admin gate — a separate auth-hardening task (parallel to PR 4.5b/c/d for
    calendar).

🤖 Generated with Claude Code

https://claude.ai/code/session_018bCm1FtKXgqSdDdev7ZXHW


Generated by Claude Code

Summary:
The /api/v1/solutions/{id}/export endpoint returned 501 Not Implemented
for format=ics with a stale 'StringIO bug' TODO. The
generate_ics_from_events helper in api/utils/calendar_utils already
produces well-formed VCALENDAR output; wire it into the export branch
so admins get a proper ICS download (matching the CSV path). The
per-person scope filter that already existed on the endpoint carries
over — a person: scope trims the event list before ICS assembly.

Changed files:
- api/routers/solutions.py: replace the 501 branch with an
  event-per-VEVENT build via generate_ics_from_events, honouring the
  existing scope filter and returning text/calendar with a
  solution_<id>.ics Content-Disposition.
- tests/api/test_solution_export_ics.py: new test module — org-scope
  happy path (two VEVENTs, right summaries, proper headers),
  person-scope filter (only that person's events), empty-solution
  guard, and unknown-solution 404.

Validation:
- poetry run pytest tests/api/ (336 passed)
- poetry run pytest tests/unit/ (350 passed, 21 skipped)
- poetry run pytest tests/contract/ (snapshot still matches — endpoint
  shape unchanged)
- poetry run black api tests / poetry run ruff check api tests clean
- poetry run mypy api/utils api/core api/schemas (strict, clean)

Follow-ups:
- The endpoint still has no Depends(get_current_user) / admin gate;
  that's a separate auth-hardening task (parallel to PR 4.5b/c/d for
  calendar) and out of scope here.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018bCm1FtKXgqSdDdev7ZXHW
@tomqwu

tomqwu commented Sep 15, 2026

Copy link
Copy Markdown
Owner Author

Superseded by #333, now merged to main as 626bf4a031ec573f9bfb452d126c3facb424f3e5.

The replacement implementation is based on current main, keeps the existing admin gate, filters assignments/events/people/resources before ICS serialization, and adds real-JWT org/person/team authorization and cross-tenant privacy coverage. Exact-head local evidence: 1,985 passed, 21 skipped, zero failures; Flutter 65 passed; generated client 692 passed; deterministic codegen and documentation validation passed.

Closing this stale draft without deleting its source branch.

@tomqwu tomqwu closed this Sep 15, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants