-
Notifications
You must be signed in to change notification settings - Fork 0
Accelerate with copilot #2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
e2a8186
8b30a06
b93df53
43d8aa3
c0aae0c
7ec80ae
6859f13
e45d7f0
64f5317
a8c3b5c
ce4844f
5ea4b0f
96fd9f5
95ff5b7
26a9418
157cd33
b3e03d4
450fba0
1c31d8a
f886c59
c5e5fc4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,2 +1,5 @@ | ||
| pytest | ||
| httpx | ||
| pytest-cov | ||
| fastapi | ||
| uvicorn |
| Original file line number | Diff line number | Diff line change | ||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,3 +1,6 @@ | ||||||||||||||||
| from fastapi import FastAPI, HTTPException, Request | ||||||||||||||||
| from fastapi.responses import JSONResponse | ||||||||||||||||
| # ...existing code... | ||||||||||||||||
|
Comment on lines
+1
to
+3
|
||||||||||||||||
| """ | ||||||||||||||||
| High School Management System API | ||||||||||||||||
|
|
||||||||||||||||
|
|
@@ -16,11 +19,46 @@ | |||||||||||||||
|
|
||||||||||||||||
| # Mount the static files directory | ||||||||||||||||
| current_dir = Path(__file__).parent | ||||||||||||||||
| app.mount("/static", StaticFiles(directory=os.path.join(Path(__file__).parent, | ||||||||||||||||
| "static")), name="static") | ||||||||||||||||
| app.mount("/static", StaticFiles(directory=os.path.join(Path(__file__).parent, "static")), name="static") | ||||||||||||||||
|
|
||||||||||||||||
| # In-memory activity database | ||||||||||||||||
| activities = { | ||||||||||||||||
| "Basketball Team": { | ||||||||||||||||
| "description": "Join the school basketball team for training and competitions", | ||||||||||||||||
| "schedule": "Tuesdays and Thursdays, 4:00 PM - 6:00 PM", | ||||||||||||||||
| "max_participants": 15, | ||||||||||||||||
| "participants": [] | ||||||||||||||||
| }, | ||||||||||||||||
| "Soccer Club": { | ||||||||||||||||
| "description": "Practice soccer skills and play friendly matches", | ||||||||||||||||
| "schedule": "Wednesdays, 3:30 PM - 5:30 PM", | ||||||||||||||||
| "max_participants": 18, | ||||||||||||||||
| "participants": [] | ||||||||||||||||
| }, | ||||||||||||||||
| "Drama Club": { | ||||||||||||||||
| "description": "Participate in acting, stage production, and school plays", | ||||||||||||||||
| "schedule": "Mondays, 4:00 PM - 5:30 PM", | ||||||||||||||||
| "max_participants": 25, | ||||||||||||||||
| "participants": [] | ||||||||||||||||
| }, | ||||||||||||||||
| "Art Workshop": { | ||||||||||||||||
| "description": "Explore painting, drawing, and other visual arts", | ||||||||||||||||
| "schedule": "Fridays, 2:30 PM - 4:00 PM", | ||||||||||||||||
| "max_participants": 20, | ||||||||||||||||
| "participants": [] | ||||||||||||||||
| }, | ||||||||||||||||
| "Math Olympiad": { | ||||||||||||||||
| "description": "Prepare for math competitions and solve challenging problems", | ||||||||||||||||
| "schedule": "Thursdays, 3:30 PM - 5:00 PM", | ||||||||||||||||
| "max_participants": 10, | ||||||||||||||||
| "participants": [] | ||||||||||||||||
| }, | ||||||||||||||||
| "Science Club": { | ||||||||||||||||
| "description": "Conduct experiments and explore scientific concepts", | ||||||||||||||||
| "schedule": "Wednesdays, 4:00 PM - 5:00 PM", | ||||||||||||||||
| "max_participants": 15, | ||||||||||||||||
| "participants": [] | ||||||||||||||||
| }, | ||||||||||||||||
| "Chess Club": { | ||||||||||||||||
| "description": "Learn strategies and compete in chess tournaments", | ||||||||||||||||
| "schedule": "Fridays, 3:30 PM - 5:00 PM", | ||||||||||||||||
|
|
@@ -55,13 +93,38 @@ def get_activities(): | |||||||||||||||
| @app.post("/activities/{activity_name}/signup") | ||||||||||||||||
| def signup_for_activity(activity_name: str, email: str): | ||||||||||||||||
| """Sign up a student for an activity""" | ||||||||||||||||
| # Validate email is not empty or whitespace-only | ||||||||||||||||
| if not email.strip(): | ||||||||||||||||
| raise HTTPException(status_code=400, detail="Email cannot be empty or whitespace-only") | ||||||||||||||||
|
|
||||||||||||||||
| # 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] | ||||||||||||||||
|
|
||||||||||||||||
| # Validate student is not already signed up | ||||||||||||||||
| if email in activity["participants"]: | ||||||||||||||||
|
pmca31 marked this conversation as resolved.
|
||||||||||||||||
| raise HTTPException(status_code=400, detail="Student already signed up for this activity") | ||||||||||||||||
|
Comment on lines
+107
to
+109
|
||||||||||||||||
|
|
||||||||||||||||
|
|
||||||||||||||||
|
Comment on lines
+110
to
+111
|
||||||||||||||||
| # Validate activity is not at max capacity (if a limit is defined) | |
| if "max_participants" in activity and activity["max_participants"] is not None: | |
| if len(activity["participants"]) >= activity["max_participants"]: | |
| raise HTTPException(status_code=400, detail="Activity is full") |
Copilot
AI
Feb 10, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unnecessary blank line at line 116. This creates inconsistent spacing in the function and should be removed for cleaner code formatting.
Copilot
AI
Feb 10, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
signup_for_activity no longer enforces max_participants capacity before appending to participants. This makes it possible to overfill an activity and will break the expected 400 "Activity is full" behavior (see tests). Add a check comparing len(activity["participants"]) against activity["max_participants"] and raise HTTPException(400, "Activity is full") before appending.
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -20,13 +20,102 @@ document.addEventListener("DOMContentLoaded", () => { | |||||||||||||||||||||
|
|
||||||||||||||||||||||
| const spotsLeft = details.max_participants - details.participants.length; | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| activityCard.innerHTML = ` | ||||||||||||||||||||||
| <h4>${name}</h4> | ||||||||||||||||||||||
| <p>${details.description}</p> | ||||||||||||||||||||||
| <p><strong>Schedule:</strong> ${details.schedule}</p> | ||||||||||||||||||||||
| <p><strong>Availability:</strong> ${spotsLeft} spots left</p> | ||||||||||||||||||||||
| `; | ||||||||||||||||||||||
| // Create title | ||||||||||||||||||||||
| const title = document.createElement("h4"); | ||||||||||||||||||||||
| title.textContent = name; | ||||||||||||||||||||||
| activityCard.appendChild(title); | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| // Create description | ||||||||||||||||||||||
| const description = document.createElement("p"); | ||||||||||||||||||||||
| description.textContent = details.description; | ||||||||||||||||||||||
| activityCard.appendChild(description); | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| // Create schedule | ||||||||||||||||||||||
| const schedule = document.createElement("p"); | ||||||||||||||||||||||
| const scheduleLabel = document.createElement("strong"); | ||||||||||||||||||||||
| scheduleLabel.textContent = "Schedule: "; | ||||||||||||||||||||||
| schedule.appendChild(scheduleLabel); | ||||||||||||||||||||||
| schedule.appendChild(document.createTextNode(details.schedule)); | ||||||||||||||||||||||
| activityCard.appendChild(schedule); | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| // Create availability | ||||||||||||||||||||||
| const availability = document.createElement("p"); | ||||||||||||||||||||||
| const availabilityLabel = document.createElement("strong"); | ||||||||||||||||||||||
| availabilityLabel.textContent = "Availability: "; | ||||||||||||||||||||||
| availability.appendChild(availabilityLabel); | ||||||||||||||||||||||
| availability.appendChild(document.createTextNode(`${spotsLeft} spots left`)); | ||||||||||||||||||||||
| activityCard.appendChild(availability); | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| // Create participants section | ||||||||||||||||||||||
| const participantsSection = document.createElement("div"); | ||||||||||||||||||||||
| participantsSection.className = "participants-section"; | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| const participantsLabel = document.createElement("strong"); | ||||||||||||||||||||||
| participantsLabel.textContent = "Participants:"; | ||||||||||||||||||||||
| participantsSection.appendChild(participantsLabel); | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| if (details.participants.length > 0) { | ||||||||||||||||||||||
| const participantsList = document.createElement("div"); | ||||||||||||||||||||||
| participantsList.className = "participants-list"; | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| details.participants.forEach((email) => { | ||||||||||||||||||||||
| const participantItem = document.createElement("div"); | ||||||||||||||||||||||
|
Comment on lines
+58
to
+62
|
||||||||||||||||||||||
| const participantsList = document.createElement("div"); | |
| participantsList.className = "participants-list"; | |
| details.participants.forEach((email) => { | |
| const participantItem = document.createElement("div"); | |
| const participantsList = document.createElement("ul"); | |
| participantsList.className = "participants-list"; | |
| details.participants.forEach((email) => { | |
| const participantItem = document.createElement("li"); |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -142,3 +142,35 @@ footer { | |||||||||||||||||||||||||||||||||||
| padding: 20px; | ||||||||||||||||||||||||||||||||||||
| color: #666; | ||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| .participants-section { | ||||||||||||||||||||||||||||||||||||
| margin-top: 12px; | ||||||||||||||||||||||||||||||||||||
| padding: 10px; | ||||||||||||||||||||||||||||||||||||
| background-color: #e3f2fd; | ||||||||||||||||||||||||||||||||||||
| border-radius: 4px; | ||||||||||||||||||||||||||||||||||||
| border: 1px solid #bbdefb; | ||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| .participants-section strong { | ||||||||||||||||||||||||||||||||||||
| color: #1976d2; | ||||||||||||||||||||||||||||||||||||
| font-size: 15px; | ||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| .participants-list { | ||||||||||||||||||||||||||||||||||||
| margin-top: 6px; | ||||||||||||||||||||||||||||||||||||
| margin-left: 18px; | ||||||||||||||||||||||||||||||||||||
| list-style-type: disc; | ||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||
| list-style-type: disc; |
Copilot
AI
Feb 10, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The delete icon (trash can emoji) added in the JavaScript is missing CSS styling to make it visually distinct and interactive. Consider adding styles for .delete-icon to include cursor pointer, color, hover effects, and proper spacing to improve usability.
| } | |
| } | |
| .delete-icon { | |
| cursor: pointer; | |
| margin-left: 8px; | |
| color: #9e9e9e; | |
| font-size: 0.9em; | |
| vertical-align: middle; | |
| transition: color 0.2s ease, transform 0.2s ease; | |
| } | |
| .delete-icon:hover, | |
| .delete-icon:focus { | |
| color: #d32f2f; | |
| transform: scale(1.1); | |
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,95 @@ | ||
| 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 | ||
| assert isinstance(response.json(), dict) | ||
|
|
||
| def test_signup_and_unregister(): | ||
| activity = "Basketball Team" | ||
| email = "testuser@example.com" | ||
| # Signup | ||
| signup_resp = client.post(f"/activities/{activity}/signup?email={email}") | ||
| assert signup_resp.status_code == 200 or signup_resp.status_code == 400 | ||
| # Unregister | ||
| unregister_resp = client.post(f"/activities/{activity}/unregister?email={email}") | ||
| assert unregister_resp.status_code == 200 or unregister_resp.status_code == 400 | ||
|
Comment on lines
+15
to
+19
|
||
|
|
||
| def test_signup_nonexistent_activity(): | ||
| email = "ghost@example.com" | ||
| resp = client.post("/activities/Nonexistent Activity/signup?email=" + email) | ||
| assert resp.status_code == 404 | ||
| assert resp.json()["detail"] == "Activity not found" | ||
|
|
||
|
|
||
| def test_unregister_non_participant(): | ||
| activity = "Drama Club" | ||
| email = "not_signed_up@example.com" | ||
| resp = client.post(f"/activities/{activity}/unregister?email={email}") | ||
| assert resp.status_code == 400 | ||
| assert resp.json()["detail"] == "Participant not found" | ||
|
|
||
|
|
||
| def test_max_participants_limit(): | ||
| activity = "Art Workshop" | ||
| emails = [f"user{i}@example.com" for i in range(1, 22)] | ||
| # Fill up the activity | ||
| for email in emails[:20]: | ||
| resp = client.post(f"/activities/{activity}/signup?email={email}") | ||
| assert resp.status_code == 200 or resp.status_code == 400 | ||
| # Try to add one more | ||
| resp = client.post(f"/activities/{activity}/signup?email={emails[20]}") | ||
| assert resp.status_code == 400 | ||
| assert resp.json()["detail"] == "Activity is full" | ||
|
|
||
|
|
||
| def test_static_index(): | ||
| resp = client.get("/static/index.html") | ||
| assert resp.status_code == 200 | ||
|
|
||
|
|
||
| def test_signup_twice(): | ||
| activity = "Soccer Club" | ||
| email = "twiceuser@example.com" | ||
| # First signup | ||
| resp1 = client.post(f"/activities/{activity}/signup?email={email}") | ||
| assert resp1.status_code == 200 | ||
| # Second signup should fail | ||
| resp2 = client.post(f"/activities/{activity}/signup?email={email}") | ||
| assert resp2.status_code == 400 | ||
| assert resp2.json()["detail"] == "Student already signed up for this activity" | ||
|
pmca31 marked this conversation as resolved.
|
||
|
|
||
|
|
||
| def test_signup_empty_email(): | ||
| activity = "Basketball Team" | ||
| # Test with empty email | ||
| resp = client.post(f"/activities/{activity}/signup?email=") | ||
| assert resp.status_code == 400 | ||
| assert resp.json()["detail"] == "Email cannot be empty or whitespace-only" | ||
|
|
||
|
|
||
| def test_signup_whitespace_email(): | ||
| activity = "Basketball Team" | ||
| # Test with whitespace-only email | ||
| resp = client.post(f"/activities/{activity}/signup?email= ") | ||
| assert resp.status_code == 400 | ||
| assert resp.json()["detail"] == "Email cannot be empty or whitespace-only" | ||
|
|
||
|
|
||
| def test_unregister_empty_email(): | ||
| activity = "Drama Club" | ||
| # Test with empty email | ||
| resp = client.post(f"/activities/{activity}/unregister?email=") | ||
| assert resp.status_code == 400 | ||
| assert resp.json()["detail"] == "Email cannot be empty or whitespace-only" | ||
|
|
||
|
|
||
| def test_unregister_whitespace_email(): | ||
| activity = "Drama Club" | ||
| # Test with whitespace-only email | ||
| resp = client.post(f"/activities/{activity}/unregister?email= ") | ||
| assert resp.status_code == 400 | ||
| assert resp.json()["detail"] == "Email cannot be empty or whitespace-only" | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The comment "...existing code..." on line 3 appears to be a placeholder or merge artifact that should be removed. This comment doesn't provide any meaningful information and clutters the code.