from app.models import Role from tests.factories import make_volunteer def _url(edition, volunteer, suffix=""): return f"/editions/{edition.id}/volunteers/{volunteer.id}/availability{suffix}" def test_put_then_get_returns_windows_sorted(client, edition, session): v = make_volunteer(session, edition, email="v@e.fr") resp = client.put( _url(edition, v), json={ "windows": [ {"date": "2026-07-11", "start_time": "14:00", "end_time": "19:00"}, {"date": "2026-07-10", "start_time": "08:00", "end_time": "13:00"}, {"date": "2026-07-10", "start_time": "19:00", "end_time": "02:00"}, ] }, ) assert resp.status_code == 200 got = [(w["date"], w["start_time"], w["end_time"]) for w in resp.json()] assert got == [ ("2026-07-10", "08:00:00", "13:00:00"), ("2026-07-10", "19:00:00", "02:00:00"), ("2026-07-11", "14:00:00", "19:00:00"), ] assert client.get(_url(edition, v)).json() == resp.json() def test_put_replaces_the_whole_set_and_dedupes(client, edition, session): v = make_volunteer(session, edition, email="v@e.fr") client.put( _url(edition, v), json={ "windows": [ {"date": "2026-07-10", "start_time": "08:00", "end_time": "12:00"} ] }, ) resp = client.put( _url(edition, v), json={ "windows": [ {"date": "2026-07-11", "start_time": "09:00", "end_time": "17:00"}, {"date": "2026-07-11", "start_time": "09:00", "end_time": "17:00"}, ] }, ) body = resp.json() assert len(body) == 1 assert body[0]["date"] == "2026-07-11" def test_put_rejects_date_outside_edition(client, edition, session): v = make_volunteer(session, edition, email="v@e.fr") resp = client.put( _url(edition, v), json={ "windows": [ {"date": "2026-08-01", "start_time": "08:00", "end_time": "12:00"} ] }, ) assert resp.status_code == 422 assert resp.json()["detail"]["code"] == "availability.date_outside_edition" def test_put_rejects_empty_window(client, edition, session): v = make_volunteer(session, edition, email="v@e.fr") resp = client.put( _url(edition, v), json={ "windows": [ {"date": "2026-07-10", "start_time": "09:00", "end_time": "09:00"} ] }, ) assert resp.status_code == 422 assert resp.json()["detail"]["code"] == "availability.empty_window" def test_edition_wide_listing(client, edition, session): v1 = make_volunteer(session, edition, first_name="A", email="a@e.fr") v2 = make_volunteer(session, edition, first_name="B", email="b@e.fr") for v in (v1, v2): client.put( _url(edition, v), json={ "windows": [ {"date": "2026-07-10", "start_time": "08:00", "end_time": "13:00"} ] }, ) body = client.get(f"/editions/{edition.id}/availability").json() assert {w["volunteer_id"] for w in body} == {str(v1.id), str(v2.id)} def test_lead_can_read_but_not_write(edition, session, make_account, as_account): v = make_volunteer(session, edition, email="v@e.fr") lead = make_account(Role.LEAD, email="lead@e.fr") api = as_account(lead) assert api.get(_url(edition, v)).status_code == 200 resp = api.put(_url(edition, v), json={"windows": []}) assert resp.status_code == 403 def test_volunteer_reads_only_their_own(edition, session, make_account, as_account): me = make_volunteer(session, edition, email="me@e.fr") other = make_volunteer(session, edition, email="other@e.fr") account = make_account(Role.VOLUNTEER, volunteer_id=me.id, email="acc@e.fr") api = as_account(account) assert api.get(_url(edition, me)).status_code == 200 assert api.get(_url(edition, other)).status_code == 403