From 2fdb47cc1b0045505e0cc1ea24ef6b20624a817f Mon Sep 17 00:00:00 2001 From: Chris Fulljames Date: Sat, 12 Apr 2025 13:08:24 -0400 Subject: [PATCH] Implement event update/delete --- src/littlesongplace/jams.py | 44 ++++++-- src/littlesongplace/templates/jam-event.html | 4 +- test/test_jams.py | 103 +++++++++++++++++-- 3 files changed, 133 insertions(+), 18 deletions(-) diff --git a/src/littlesongplace/jams.py b/src/littlesongplace/jams.py index ebc17e2..96dd6d5 100644 --- a/src/littlesongplace/jams.py +++ b/src/littlesongplace/jams.py @@ -55,7 +55,7 @@ def create(): @bp.get("/") def jam(jamid): - jam = get_jam_by_id(jamid) + jam = _get_jam_by_id(jamid) # Show the main jam page return render_template("jam.html", jam=jam) @@ -114,7 +114,7 @@ def events_create(jamid): @bp.get("//events/") def events_view(jamid, eventid): # Show the event page - jam = get_jam_by_id(jamid) + jam = _get_jam_by_id(jamid) try: event = next(e for e in jam.events if e.eventid == eventid) except StopIteration: @@ -128,7 +128,23 @@ def events_view(jamid, eventid): @jam_owner_only def events_update(jamid, eventid): # Update an event with the new form data - ... + title = request.form["title"] + description = request.form["description"] + startdate = request.form["startdate"] + enddate = request.form["enddate"] + _validate_timestamp(startdate) + _validate_timestamp(enddate) + db.query( + """ + UPDATE jam_events + SET title = ?, description = ?, startdate = ?, enddate = ? + WHERE eventid = ? AND jamid = ? + RETURNING * + """, + [title, description, startdate, enddate, eventid, jamid], + expect_one=True) + db.commit() + return redirect(url_for("jams.events_view", jamid=jamid, eventid=eventid)) @bp.get("//events//delete") @@ -136,9 +152,16 @@ def events_update(jamid, eventid): @jam_owner_only def events_delete(jamid, eventid): # Delete an event, redirect to list of all events - ... + db.query( + """ + DELETE FROM jam_events + WHERE eventid = ? AND jamid = ? + RETURNING * + """, [eventid, jamid], expect_one=True) + return redirect(url_for("jams.jam", jamid=jamid)) + -def get_jam_by_id(jamid): +def _get_jam_by_id(jamid): row = db.query( """ SELECT * FROM jams @@ -147,6 +170,13 @@ def get_jam_by_id(jamid): """, [jamid], expect_one=True) return Jam.from_row(row) + +def _validate_timestamp(timestamp): + try: + datetime.fromisoformat(timestamp) + except ValueError: + abort(400) + @dataclass class Jam: jamid: int @@ -215,8 +245,8 @@ class JamEvent: threadid=row["threadid"], created=datetime.fromisoformat(row["created"]), title=row["title"], - startdate=datetime.fromisoformat(row["startdate"]) if "startdate" in row else None, - enddate=datetime.fromisoformat(row["enddate"]) if "enddate" in row else None, + startdate=datetime.fromisoformat(row["startdate"]) if row["startdate"] else None, + enddate=datetime.fromisoformat(row["enddate"]) if row["enddate"] else None, description=sanitize_user_text(row["description"] or ""), jam_title=row["jam_title"], jam_ownername=row["jam_ownername"], diff --git a/src/littlesongplace/templates/jam-event.html b/src/littlesongplace/templates/jam-event.html index 8dad7a7..d67660e 100644 --- a/src/littlesongplace/templates/jam-event.html +++ b/src/littlesongplace/templates/jam-event.html @@ -12,12 +12,12 @@
{% if event.startdate %} Start Date: - {{ event.startdate.aslocaltime().strftime("%Y-%m-%d @ %H:%M") }} + {{ event.startdate.astimezone().strftime("%Y-%m-%d @ %I:%M%p") }}
{% endif %} {% if event.enddate %} End Date: - {{ event.enddate.aslocaltime().strftime("%Y-%m-%d @ %H:%M") }} + {{ event.enddate.astimezone().strftime("%Y-%m-%d @ %I:%M%p") }} {% endif %} diff --git a/test/test_jams.py b/test/test_jams.py index 58a51da..46daefa 100644 --- a/test/test_jams.py +++ b/test/test_jams.py @@ -1,3 +1,5 @@ +from datetime import datetime, timezone + import pytest from .utils import create_user @@ -8,10 +10,15 @@ def user(client): yield "user" @pytest.fixture -def jam(client): +def jam(client, user): client.get("/jams/create") return 1 +@pytest.fixture +def event(client, jam): + client.get(f"/jams/{jam}/events/create") + return 1 + # Jams ######################################################################### def test_view_invalid_jam(client): @@ -107,13 +114,91 @@ def test_create_event_on_other_users_jam(client, user, jam): response = client.get(f"/jams/{jam}/events/create", follow_redirects=True) assert response.status_code == 403 -# Update event -# Update event invalid event -# Update event not logged in -# Update event other users jam +def _to_utc(timestamp): + return (datetime + .fromisoformat(timestamp) + .astimezone(timezone.utc) + .isoformat()) + +def _get_event_data(**kwargs): + event_data = { + "title": "Event Title", + "description": "description of the event", + "startdate": _to_utc("2040-01-01T00:00:00"), + "enddate": _to_utc("2040-01-02T00:00:00"), + } + for k, v in kwargs.items(): + event_data[k] = v + return event_data + +def test_update_event(client, user, jam, event): + response = client.post( + f"/jams/{jam}/events/{event}/update", + data=_get_event_data(), follow_redirects=True) + assert response.request.path == f"/jams/{jam}/events/{event}" + assert b"Event Title" in response.data + assert b"description of the event" in response.data + assert b"2040-01-01" in response.data + assert b"2040-01-02" in response.data + +def test_update_event_invalid_eventid(client, user, jam): + response = client.post(f"/jams/{jam}/events/1/update", data=_get_event_data()) + assert response.status_code == 404 + +def test_update_event_invalid_jamid(client, user, event): + response = client.post(f"/jams/2/events/{event}/update", data=_get_event_data()) + assert response.status_code == 404 + +def test_update_event_not_logged_in(client, user, jam, event): + response = client.get("/logout") + response = client.post( + f"/jams/{jam}/events/{event}/update", + data=_get_event_data(), + follow_redirects=True) + assert response.request.path == "/login" + +def test_update_event_other_users_jam(client, user, jam, event): + create_user(client, "otheruser", login=True) + response = client.post( + f"/jams/{jam}/events/{event}/update", + data=_get_event_data(), + follow_redirects=True) + assert response.status_code == 403 + +def test_update_event_invalid_startdate(client, user, jam, event): + response = client.post( + f"/jams/{jam}/events/{event}/update", + data=_get_event_data(startdate="notadate"), + follow_redirects=True) + assert response.status_code == 400 + +def test_update_event_invalid_enddate(client, user, jam, event): + response = client.post( + f"/jams/{jam}/events/{event}/update", + data=_get_event_data(enddate="notadate"), + follow_redirects=True) + assert response.status_code == 400 + +def test_delete_event(client, user, jam, event): + response = client.get(f"/jams/{jam}/events/{event}/delete", follow_redirects=True) + assert response.request.path == f"/jams/{jam}" + assert b"Event Title" not in response.data -# Delete event -# Delete event not logged in -# Delete event invalid event -# Delete event other users jam +def test_delete_event_not_logged_in(client, user, jam, event): + client.get("/logout") + response = client.get(f"/jams/{jam}/events/{event}/delete", follow_redirects=True) + assert response.request.path == "/login" + +def test_delete_event_invalid_jamid(client, user, jam, event): + response = client.get(f"/jams/2/events/{event}/delete", follow_redirects=True) + assert response.status_code == 404 + +def test_delete_event_invalid_eventid(client, user, jam, event): + response = client.get(f"/jams/{jam}/events/2/delete", follow_redirects=True) + assert response.status_code == 404 + +def test_delete_event_other_users_jam(client, user, jam, event): + create_user(client, "otheruser", login=True) + response = client.get(f"/jams/{jam}/events/{event}/delete", follow_redirects=True) + assert response.status_code == 403 -- 2.39.5