mirror of
https://github.com/jlengrand/getting-started-with-github-copilot.git
synced 2026-03-10 08:21:18 +00:00
Merge pull request #3 from jlengrand/accelerate-with-copilot
Accelerate with copilot
This commit is contained in:
@@ -1,2 +1,5 @@
|
||||
fastapi
|
||||
uvicorn
|
||||
testclient
|
||||
httpx
|
||||
pytest
|
||||
|
||||
57
src/app.py
57
src/app.py
@@ -38,6 +38,45 @@ activities = {
|
||||
"schedule": "Mondays, Wednesdays, Fridays, 2:00 PM - 3:00 PM",
|
||||
"max_participants": 30,
|
||||
"participants": ["john@mergington.edu", "olivia@mergington.edu"]
|
||||
},
|
||||
# Sports related activities
|
||||
"Soccer Team": {
|
||||
"description": "Join the school soccer team and compete in matches",
|
||||
"schedule": "Wednesdays, 4:00 PM - 5:30 PM",
|
||||
"max_participants": 18,
|
||||
"participants": ["lucas@mergington.edu", "mia@mergington.edu"]
|
||||
},
|
||||
"Basketball Club": {
|
||||
"description": "Practice basketball skills and play friendly games",
|
||||
"schedule": "Thursdays, 3:30 PM - 5:00 PM",
|
||||
"max_participants": 15,
|
||||
"participants": ["liam@mergington.edu", "ava@mergington.edu"]
|
||||
},
|
||||
# Artistic activities
|
||||
"Art Workshop": {
|
||||
"description": "Explore painting, drawing, and sculpture techniques",
|
||||
"schedule": "Mondays, 4:00 PM - 5:30 PM",
|
||||
"max_participants": 16,
|
||||
"participants": ["ella@mergington.edu", "noah@mergington.edu"]
|
||||
},
|
||||
"Drama Club": {
|
||||
"description": "Act, direct, and produce school plays and performances",
|
||||
"schedule": "Tuesdays, 3:30 PM - 5:00 PM",
|
||||
"max_participants": 20,
|
||||
"participants": ["isabella@mergington.edu", "jack@mergington.edu"]
|
||||
},
|
||||
# Intellectual activities
|
||||
"Mathletes": {
|
||||
"description": "Compete in math competitions and solve challenging problems",
|
||||
"schedule": "Fridays, 4:00 PM - 5:00 PM",
|
||||
"max_participants": 10,
|
||||
"participants": ["oliver@mergington.edu", "charlotte@mergington.edu"]
|
||||
},
|
||||
"Science Club": {
|
||||
"description": "Conduct experiments and explore scientific concepts",
|
||||
"schedule": "Wednesdays, 3:30 PM - 5:00 PM",
|
||||
"max_participants": 14,
|
||||
"participants": ["henry@mergington.edu", "amelia@mergington.edu"]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,6 +94,12 @@ 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 student is not already signed up
|
||||
for activity in activities.values():
|
||||
if email in activity["participants"]:
|
||||
raise HTTPException(status_code=400, detail="Student already signed up for an activity")
|
||||
|
||||
# Validate activity exists
|
||||
if activity_name not in activities:
|
||||
raise HTTPException(status_code=404, detail="Activity not found")
|
||||
@@ -65,3 +110,15 @@ def signup_for_activity(activity_name: str, email: str):
|
||||
# Add student
|
||||
activity["participants"].append(email)
|
||||
return {"message": f"Signed up {email} for {activity_name}"}
|
||||
|
||||
# Unregister endpoint
|
||||
@app.post("/activities/{activity_name}/unregister")
|
||||
def unregister_from_activity(activity_name: str, email: str):
|
||||
"""Remove a student from an activity"""
|
||||
activity = activities.get(activity_name)
|
||||
if not activity:
|
||||
raise HTTPException(status_code=404, detail="Activity not found")
|
||||
if email not in activity["participants"]:
|
||||
raise HTTPException(status_code=404, detail="Participant not found in activity")
|
||||
activity["participants"].remove(email)
|
||||
return {"message": f"{email} removed from {activity_name}"}
|
||||
|
||||
@@ -20,13 +20,53 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
|
||||
const spotsLeft = details.max_participants - details.participants.length;
|
||||
|
||||
// Participants section
|
||||
let participantsHTML = `
|
||||
<div class="participants-section" style="margin-top: 1em;">
|
||||
<strong style="color: #3949ab; font-size: 1.05em;">Participants:</strong>
|
||||
${
|
||||
details.participants.length > 0
|
||||
? `<ul style="margin: 0.5em 0 0 1em; padding: 0; list-style-type: none;">
|
||||
${details.participants.map(p => `
|
||||
<li style="margin-bottom: 2px; color: #333; display: flex; align-items: center;">
|
||||
<span>${p}</span>
|
||||
<span class="delete-participant" data-activity="${name}" data-participant="${p}" style="cursor:pointer; margin-left:8px; color:#e53935; font-size:1.1em;" title="Remove participant">🗑</span>
|
||||
</li>`).join("")}
|
||||
</ul>`
|
||||
: `<p style="margin: 0.5em 0 0 1em; color: #888; font-style: italic;">No participants yet.</p>`
|
||||
}
|
||||
</div>
|
||||
`;
|
||||
|
||||
activityCard.innerHTML = `
|
||||
<h4>${name}</h4>
|
||||
<p>${details.description}</p>
|
||||
<p><strong>Schedule:</strong> ${details.schedule}</p>
|
||||
<p><strong>Availability:</strong> ${spotsLeft} spots left</p>
|
||||
${participantsHTML}
|
||||
`;
|
||||
|
||||
// Add event listener for delete icons
|
||||
activityCard.querySelectorAll('.delete-participant').forEach(icon => {
|
||||
icon.addEventListener('click', async (e) => {
|
||||
const activityName = icon.getAttribute('data-activity');
|
||||
const participant = icon.getAttribute('data-participant');
|
||||
try {
|
||||
const response = await fetch(`/activities/${encodeURIComponent(activityName)}/unregister?email=${encodeURIComponent(participant)}`, {
|
||||
method: 'POST',
|
||||
});
|
||||
const result = await response.json();
|
||||
if (response.ok) {
|
||||
fetchActivities(); // Refresh list
|
||||
} else {
|
||||
alert(result.detail || 'Failed to remove participant.');
|
||||
}
|
||||
} catch (err) {
|
||||
alert('Error removing participant.');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
activitiesList.appendChild(activityCard);
|
||||
|
||||
// Add option to select dropdown
|
||||
|
||||
@@ -142,3 +142,34 @@ footer {
|
||||
padding: 20px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.participants-section {
|
||||
background: #eef2fa;
|
||||
border-radius: 4px;
|
||||
padding: 10px 12px;
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
.participants-section strong {
|
||||
display: block;
|
||||
margin-bottom: 6px;
|
||||
color: #3949ab;
|
||||
}
|
||||
|
||||
.participants-section ul {
|
||||
margin-left: 1em;
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.participants-section li {
|
||||
color: #333;
|
||||
margin-bottom: 2px;
|
||||
list-style-type: disc;
|
||||
}
|
||||
|
||||
.participants-section p {
|
||||
color: #888;
|
||||
margin-left: 1em;
|
||||
font-style: italic;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
45
tests/test_app.py
Normal file
45
tests/test_app.py
Normal file
@@ -0,0 +1,45 @@
|
||||
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
|
||||
|
||||
def test_signup_for_activity():
|
||||
email = "newstudent@mergington.edu"
|
||||
activity = "Chess Club"
|
||||
response = client.post(f"/activities/{activity}/signup?email={email}")
|
||||
assert response.status_code == 200
|
||||
assert email in response.json()["message"]
|
||||
# Try signing up again (should fail)
|
||||
response2 = client.post(f"/activities/{activity}/signup?email={email}")
|
||||
assert response2.status_code == 400
|
||||
|
||||
def test_unregister_from_activity():
|
||||
email = "newstudent@mergington.edu"
|
||||
activity = "Chess Club"
|
||||
# Unregister
|
||||
response = client.post(f"/activities/{activity}/unregister?email={email}")
|
||||
assert response.status_code == 200
|
||||
assert email in response.json()["message"]
|
||||
# Try unregistering again (should fail)
|
||||
response2 = client.post(f"/activities/{activity}/unregister?email={email}")
|
||||
assert response2.status_code == 404
|
||||
|
||||
def test_signup_invalid_activity():
|
||||
response = client.post("/activities/Nonexistent/signup?email=test@mergington.edu")
|
||||
assert response.status_code == 404
|
||||
|
||||
def test_unregister_invalid_activity():
|
||||
response = client.post("/activities/Nonexistent/unregister?email=test@mergington.edu")
|
||||
assert response.status_code == 404
|
||||
|
||||
def test_unregister_invalid_participant():
|
||||
response = client.post("/activities/Chess Club/unregister?email=notfound@mergington.edu")
|
||||
assert response.status_code == 404
|
||||
Reference in New Issue
Block a user