From 1814952dbf015d2d1781b196c9518b1890807e4e Mon Sep 17 00:00:00 2001
From: Katsuhiko Takahashi <207565286+kt-devoss@users.noreply.github.com>
Date: Mon, 12 Jan 2026 01:33:05 +0000
Subject: [PATCH 1/6] =?UTF-8?q?=E6=B4=BB=E5=8B=95=E3=83=87=E3=83=BC?=
=?UTF-8?q?=E3=82=BF=E3=83=99=E3=83=BC=E3=82=B9=E3=81=AB=E6=96=B0=E3=81=97?=
=?UTF-8?q?=E3=81=84=E8=AA=B2=E5=A4=96=E6=B4=BB=E5=8B=95=E3=82=92=E8=BF=BD?=
=?UTF-8?q?=E5=8A=A0=E3=81=97=E3=80=81=E3=82=B5=E3=82=A4=E3=83=B3=E3=82=A2?=
=?UTF-8?q?=E3=83=83=E3=83=97=E6=99=82=E3=81=AB=E9=87=8D=E8=A4=87=E3=82=92?=
=?UTF-8?q?=E3=83=81=20=E3=82=A7=E3=83=83=E3=82=AF=E3=81=99=E3=82=8B?=
=?UTF-8?q?=E6=A9=9F=E8=83=BD=E3=82=92=E5=AE=9F=E8=A3=85?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/app.py | 46 ++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 46 insertions(+)
diff --git a/src/app.py b/src/app.py
index 4ebb1d9..efd075c 100644
--- a/src/app.py
+++ b/src/app.py
@@ -38,6 +38,48 @@
"schedule": "Mondays, Wednesdays, Fridays, 2:00 PM - 3:00 PM",
"max_participants": 30,
"participants": ["john@mergington.edu", "olivia@mergington.edu"]
+ },
+
+ # Sports-related (2 more)
+ "Soccer Team": {
+ "description": "Competitive soccer team for students of all skill levels",
+ "schedule": "Mondays and Thursdays, 4:00 PM - 6:00 PM",
+ "max_participants": 25,
+ "participants": ["liam@mergington.edu", "noah@mergington.edu"]
+ },
+ "Basketball Club": {
+ "description": "Pickup games and skills training for basketball enthusiasts",
+ "schedule": "Wednesdays, 5:00 PM - 7:00 PM",
+ "max_participants": 18,
+ "participants": ["lucas@mergington.edu", "mason@mergington.edu"]
+ },
+
+ # Artistic (2 more)
+ "Art Club": {
+ "description": "Explore drawing, painting, and mixed media projects",
+ "schedule": "Tuesdays, 3:30 PM - 5:00 PM",
+ "max_participants": 20,
+ "participants": ["ava@mergington.edu"]
+ },
+ "Drama Club": {
+ "description": "Acting, play production, and stagecraft",
+ "schedule": "Thursdays, 4:00 PM - 6:00 PM",
+ "max_participants": 25,
+ "participants": ["isabella@mergington.edu"]
+ },
+
+ # Intellectual (2 more)
+ "Math Club": {
+ "description": "Problem solving, competitions, and math enrichment",
+ "schedule": "Wednesdays, 3:30 PM - 4:30 PM",
+ "max_participants": 20,
+ "participants": ["ethan@mergington.edu"]
+ },
+ "Science Olympiad": {
+ "description": "Prepare for science competitions and run experiments",
+ "schedule": "Fridays, 3:30 PM - 5:00 PM",
+ "max_participants": 22,
+ "participants": ["mia@mergington.edu"]
}
}
@@ -63,5 +105,9 @@ def signup_for_activity(activity_name: str, email: str):
activity = activities[activity_name]
# Add student
+ # Check if already signed up
+ if email in activity["participants"]:
+ raise HTTPException(status_code=400, detail="Student already signed up for this activity")
+
activity["participants"].append(email)
return {"message": f"Signed up {email} for {activity_name}"}
From 2635ac9b08ca838d1fa0c7956a95154ca8eca7d0 Mon Sep 17 00:00:00 2001
From: Katsuhiko Takahashi <207565286+kt-devoss@users.noreply.github.com>
Date: Mon, 12 Jan 2026 01:53:23 +0000
Subject: [PATCH 2/6] =?UTF-8?q?=E6=B4=BB=E5=8B=95=E3=82=AB=E3=83=BC?=
=?UTF-8?q?=E3=83=89=E3=81=AB=E5=8F=82=E5=8A=A0=E8=80=85=E3=83=AA=E3=82=B9?=
=?UTF-8?q?=E3=83=88=E3=82=92=E8=BF=BD=E5=8A=A0=E3=81=97=E3=80=81=E3=82=B9?=
=?UTF-8?q?=E3=82=BF=E3=82=A4=E3=83=AB=E3=82=92=E8=AA=BF=E6=95=B4?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/static/app.js | 4 ++++
src/static/styles.css | 11 +++++++++++
2 files changed, 15 insertions(+)
diff --git a/src/static/app.js b/src/static/app.js
index dcc1e38..f1b29c5 100644
--- a/src/static/app.js
+++ b/src/static/app.js
@@ -25,6 +25,10 @@ document.addEventListener("DOMContentLoaded", () => {
${details.description}
Schedule: ${details.schedule}
Availability: ${spotsLeft} spots left
+ Participants:
+
+ ${details.participants.map(participant => `- ${participant}
`).join('')}
+
`;
activitiesList.appendChild(activityCard);
diff --git a/src/static/styles.css b/src/static/styles.css
index a533b32..523bc97 100644
--- a/src/static/styles.css
+++ b/src/static/styles.css
@@ -74,6 +74,17 @@ section h3 {
margin-bottom: 8px;
}
+.activity-card ul {
+ list-style-type: disc;
+ padding-left: 20px;
+ margin-top: 10px;
+ color: #555;
+}
+
+.activity-card li {
+ margin-bottom: 5px;
+}
+
.form-group {
margin-bottom: 15px;
}
From 63dd3f5d78cbc3dc87ee0f8046b6ae9a4446356a Mon Sep 17 00:00:00 2001
From: Katsuhiko Takahashi <207565286+kt-devoss@users.noreply.github.com>
Date: Mon, 12 Jan 2026 03:03:47 +0000
Subject: [PATCH 3/6] =?UTF-8?q?=E6=B4=BB=E5=8B=95=E3=81=8B=E3=82=89?=
=?UTF-8?q?=E3=81=AE=E5=8F=82=E5=8A=A0=E8=80=85=E3=81=AE=E7=99=BB=E9=8C=B2?=
=?UTF-8?q?=E8=A7=A3=E9=99=A4=E6=A9=9F=E8=83=BD=E3=82=92=E8=BF=BD=E5=8A=A0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/app.py | 18 ++++++++++++++++++
src/static/app.js | 36 ++++++++++++++++++++++++++++++++++--
2 files changed, 52 insertions(+), 2 deletions(-)
diff --git a/src/app.py b/src/app.py
index efd075c..25b0cee 100644
--- a/src/app.py
+++ b/src/app.py
@@ -111,3 +111,21 @@ def signup_for_activity(activity_name: str, email: str):
activity["participants"].append(email)
return {"message": f"Signed up {email} for {activity_name}"}
+
+
+@app.delete("/activities/{activity_name}/participants/{email}")
+def unregister_from_activity(activity_name: str, email: str):
+ """Unregister a student from an activity"""
+ # Validate activity exists
+ if activity_name not in activities:
+ raise HTTPException(status_code=404, detail="Activity not found")
+
+ # Get the specific activity
+ activity = activities[activity_name]
+
+ # Check if student is signed up
+ if email not in activity["participants"]:
+ raise HTTPException(status_code=400, detail="Student not signed up for this activity")
+
+ activity["participants"].remove(email)
+ return {"message": f"Unregistered {email} from {activity_name}"}
diff --git a/src/static/app.js b/src/static/app.js
index f1b29c5..d97c49d 100644
--- a/src/static/app.js
+++ b/src/static/app.js
@@ -26,8 +26,8 @@ document.addEventListener("DOMContentLoaded", () => {
Schedule: ${details.schedule}
Availability: ${spotsLeft} spots left
Participants:
-
- ${details.participants.map(participant => `- ${participant}
`).join('')}
+
+ ${details.participants.map(participant => `- ${participant}
`).join('')}
`;
@@ -45,6 +45,36 @@ document.addEventListener("DOMContentLoaded", () => {
}
}
+ // Event listener for delete buttons
+ activitiesList.addEventListener('click', async (event) => {
+ if (event.target.classList.contains('delete-btn')) {
+ const activity = event.target.dataset.activity;
+ const email = event.target.dataset.email;
+
+ try {
+ const response = await fetch(`/activities/${encodeURIComponent(activity)}/participants/${encodeURIComponent(email)}`, {
+ method: 'DELETE'
+ });
+
+ if (response.ok) {
+ // Refresh the activities
+ fetchActivities();
+ } else {
+ const result = await response.json();
+ messageDiv.textContent = result.detail || "Failed to unregister";
+ messageDiv.className = "error";
+ messageDiv.classList.remove("hidden");
+ setTimeout(() => messageDiv.classList.add("hidden"), 5000);
+ }
+ } catch (error) {
+ messageDiv.textContent = "Failed to unregister. Please try again.";
+ messageDiv.className = "error";
+ messageDiv.classList.remove("hidden");
+ console.error("Error unregistering:", error);
+ }
+ }
+ });
+
// Handle form submission
signupForm.addEventListener("submit", async (event) => {
event.preventDefault();
@@ -66,6 +96,8 @@ document.addEventListener("DOMContentLoaded", () => {
messageDiv.textContent = result.message;
messageDiv.className = "success";
signupForm.reset();
+ // Refresh the activities list
+ fetchActivities();
} else {
messageDiv.textContent = result.detail || "An error occurred";
messageDiv.className = "error";
From 4cbfb596e3e5773d4f3a9b7a16b839c66e4ac61b Mon Sep 17 00:00:00 2001
From: Katsuhiko Takahashi <207565286+kt-devoss@users.noreply.github.com>
Date: Mon, 12 Jan 2026 03:07:40 +0000
Subject: [PATCH 4/6] =?UTF-8?q?requirements.txt=E3=81=ABpytest=E3=81=A8htt?=
=?UTF-8?q?px=E3=82=92=E8=BF=BD=E5=8A=A0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
requirements.txt | 2 ++
1 file changed, 2 insertions(+)
diff --git a/requirements.txt b/requirements.txt
index 97dc7cd..2522ad0 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,2 +1,4 @@
fastapi
uvicorn
+pytest
+httpx
From ded6460401e276993c26f0d21aa1d7745eacf6b7 Mon Sep 17 00:00:00 2001
From: Katsuhiko Takahashi <207565286+kt-devoss@users.noreply.github.com>
Date: Mon, 12 Jan 2026 03:08:52 +0000
Subject: [PATCH 5/6] =?UTF-8?q?=E3=83=86=E3=82=B9=E3=83=88=E3=82=B1?=
=?UTF-8?q?=E3=83=BC=E3=82=B9=E3=82=92=E8=BF=BD=E5=8A=A0=E3=81=97=E3=81=A6?=
=?UTF-8?q?=E3=80=81=E6=B4=BB=E5=8B=95=E3=81=AE=E5=8F=96=E5=BE=97=E3=80=81?=
=?UTF-8?q?=E3=82=B5=E3=82=A4=E3=83=B3=E3=82=A2=E3=83=83=E3=83=97=E3=80=81?=
=?UTF-8?q?=E7=99=BB=E9=8C=B2=E8=A7=A3=E9=99=A4=E3=81=AE=E6=A9=9F=E8=83=BD?=
=?UTF-8?q?=E3=82=92=E6=A4=9C=E8=A8=BC?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
tests/test_api.py | 66 +++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 66 insertions(+)
create mode 100644 tests/test_api.py
diff --git a/tests/test_api.py b/tests/test_api.py
new file mode 100644
index 0000000..ee5a7f0
--- /dev/null
+++ b/tests/test_api.py
@@ -0,0 +1,66 @@
+import pytest
+from fastapi.testclient import TestClient
+from src.app import app
+
+client = TestClient(app)
+
+def test_get_activities():
+ response = client.get("/activities")
+ assert response.status_code == 200
+ data = response.json()
+ assert isinstance(data, dict)
+ assert "Chess Club" in data
+ assert "participants" in data["Chess Club"]
+
+def test_signup_success():
+ # Test signing up for an activity
+ response = client.post("/activities/Chess%20Club/signup?email=test@example.com")
+ assert response.status_code == 200
+ data = response.json()
+ assert "Signed up" in data["message"]
+
+ # Check if added
+ response = client.get("/activities")
+ data = response.json()
+ assert "test@example.com" in data["Chess Club"]["participants"]
+
+def test_signup_already_signed_up():
+ # First signup
+ client.post("/activities/Chess%20Club/signup?email=duplicate@example.com")
+ # Second signup should fail
+ response = client.post("/activities/Chess%20Club/signup?email=duplicate@example.com")
+ assert response.status_code == 400
+ data = response.json()
+ assert "already signed up" in data["detail"]
+
+def test_signup_activity_not_found():
+ response = client.post("/activities/Nonexistent/signup?email=test@example.com")
+ assert response.status_code == 404
+ data = response.json()
+ assert "Activity not found" in data["detail"]
+
+def test_unregister_success():
+ # First signup
+ client.post("/activities/Programming%20Class/signup?email=unregister@example.com")
+ # Then unregister
+ response = client.delete("/activities/Programming%20Class/participants/unregister@example.com")
+ assert response.status_code == 200
+ data = response.json()
+ assert "Unregistered" in data["message"]
+
+ # Check if removed
+ response = client.get("/activities")
+ data = response.json()
+ assert "unregister@example.com" not in data["Programming Class"]["participants"]
+
+def test_unregister_not_signed_up():
+ response = client.delete("/activities/Chess%20Club/participants/notsigned@example.com")
+ assert response.status_code == 400
+ data = response.json()
+ assert "not signed up" in data["detail"]
+
+def test_unregister_activity_not_found():
+ response = client.delete("/activities/Nonexistent/participants/test@example.com")
+ assert response.status_code == 404
+ data = response.json()
+ assert "Activity not found" in data["detail"]
\ No newline at end of file
From 4db6d7922ccc131a9183cb5cf0e72002d4352204 Mon Sep 17 00:00:00 2001
From: Katsuhiko Takahashi <207565286+kt-devoss@users.noreply.github.com>
Date: Mon, 12 Jan 2026 03:10:28 +0000
Subject: [PATCH 6/6] =?UTF-8?q?=E3=83=86=E3=82=B9=E3=83=88=E3=82=B1?=
=?UTF-8?q?=E3=83=BC=E3=82=B9=E3=81=AB=E8=AA=AC=E6=98=8E=E6=96=87=E3=82=92?=
=?UTF-8?q?=E8=BF=BD=E5=8A=A0=E3=81=97=E3=81=A6=E3=80=81=E5=90=84=E3=83=86?=
=?UTF-8?q?=E3=82=B9=E3=83=88=E3=81=AE=E7=9B=AE=E7=9A=84=E3=82=92=E6=98=8E?=
=?UTF-8?q?=E7=A2=BA=E5=8C=96?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
tests/test_api.py | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/tests/test_api.py b/tests/test_api.py
index ee5a7f0..2748eb3 100644
--- a/tests/test_api.py
+++ b/tests/test_api.py
@@ -5,6 +5,7 @@
client = TestClient(app)
def test_get_activities():
+ """アクティビティの一覧を取得できることを確認するテスト"""
response = client.get("/activities")
assert response.status_code == 200
data = response.json()
@@ -13,6 +14,7 @@ def test_get_activities():
assert "participants" in data["Chess Club"]
def test_signup_success():
+ """新しい参加者がアクティビティに正常にサインアップできることを確認するテスト"""
# Test signing up for an activity
response = client.post("/activities/Chess%20Club/signup?email=test@example.com")
assert response.status_code == 200
@@ -25,6 +27,7 @@ def test_signup_success():
assert "test@example.com" in data["Chess Club"]["participants"]
def test_signup_already_signed_up():
+ """既にサインアップ済みの参加者が再度サインアップしようとするとエラーになることを確認するテスト"""
# First signup
client.post("/activities/Chess%20Club/signup?email=duplicate@example.com")
# Second signup should fail
@@ -34,12 +37,14 @@ def test_signup_already_signed_up():
assert "already signed up" in data["detail"]
def test_signup_activity_not_found():
+ """存在しないアクティビティにサインアップしようとするとエラーになることを確認するテスト"""
response = client.post("/activities/Nonexistent/signup?email=test@example.com")
assert response.status_code == 404
data = response.json()
assert "Activity not found" in data["detail"]
def test_unregister_success():
+ """サインアップ済みの参加者がアクティビティから正常にアンサインアップできることを確認するテスト"""
# First signup
client.post("/activities/Programming%20Class/signup?email=unregister@example.com")
# Then unregister
@@ -54,12 +59,14 @@ def test_unregister_success():
assert "unregister@example.com" not in data["Programming Class"]["participants"]
def test_unregister_not_signed_up():
+ """サインアップしていない参加者をアンサインアップしようとするとエラーになることを確認するテスト"""
response = client.delete("/activities/Chess%20Club/participants/notsigned@example.com")
assert response.status_code == 400
data = response.json()
assert "not signed up" in data["detail"]
def test_unregister_activity_not_found():
+ """存在しないアクティビティからアンサインアップしようとするとエラーになることを確認するテスト"""
response = client.delete("/activities/Nonexistent/participants/test@example.com")
assert response.status_code == 404
data = response.json()