Improve student activity registration system#2
Conversation
…des activités après l'inscription
…ivités et amélioration de l'interface utilisateur
There was a problem hiding this comment.
Pull request overview
This PR enhances the student activities app by adding participant unregistration support end-to-end (API + UI) and introducing an automated test suite to cover the activity management endpoints.
Changes:
- Added a DELETE API endpoint to unregister a participant and prevented duplicate signups in the signup endpoint.
- Updated the frontend to display participants per activity and allow unregistering via a delete button, with improved message handling.
- Added pytest-based API tests with automatic reset of the in-memory activities state, plus minor dependency updates.
Reviewed changes
Copilot reviewed 4 out of 6 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
src/app.py |
Expands seeded activities, prevents duplicate signups, adds DELETE unregister endpoint. |
src/static/app.js |
Renders participants per activity, adds unregister UI flow, refactors user messaging. |
src/static/styles.css |
Introduces styling for participant list and delete controls; refreshes activity card styling. |
tests/test_app.py |
Adds API test suite for root, activities listing, signup, and unregister flows with isolation fixture. |
requirements.txt |
Adds pytest dependency and fixes watchfiles line formatting. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
|
||
| function showMessage(text, type) { | ||
| messageDiv.textContent = text; | ||
| messageDiv.className = type; | ||
| messageDiv.classList.remove("hidden"); | ||
|
|
||
| setTimeout(() => { | ||
| messageDiv.classList.add("hidden"); |
There was a problem hiding this comment.
showMessage() overwrites messageDiv.className and starts a new setTimeout on every call without clearing any prior timeout. This can cause the message to be hidden unexpectedly if multiple actions happen within 5 seconds, and it also makes it hard to preserve any base styling classes on the message element. Consider keeping a single timeout handle (clear it before setting a new one) and setting classes in a way that preserves any baseline class (e.g., add/remove success/error rather than replacing the entire class list).
| function showMessage(text, type) { | |
| messageDiv.textContent = text; | |
| messageDiv.className = type; | |
| messageDiv.classList.remove("hidden"); | |
| setTimeout(() => { | |
| messageDiv.classList.add("hidden"); | |
| let messageTimeoutId = null; | |
| function showMessage(text, type) { | |
| messageDiv.textContent = text; | |
| // Preserve any baseline classes on messageDiv, only toggle status classes. | |
| messageDiv.classList.remove("success", "error"); | |
| if (type) { | |
| messageDiv.classList.add(type); | |
| } | |
| messageDiv.classList.remove("hidden"); | |
| // Ensure only one hide timeout is active at a time. | |
| if (messageTimeoutId !== null) { | |
| clearTimeout(messageTimeoutId); | |
| } | |
| messageTimeoutId = setTimeout(() => { | |
| messageDiv.classList.add("hidden"); | |
| messageTimeoutId = null; |
| const participantsMarkup = details.participants.length | ||
| ? details.participants | ||
| .map( | ||
| (participant) => ` | ||
| <li class="participant-item"> | ||
| <span class="participant-email">${participant}</span> | ||
| <button | ||
| class="participant-delete-button" | ||
| type="button" | ||
| data-activity="${encodeURIComponent(name)}" | ||
| data-email="${encodeURIComponent(participant)}" | ||
| aria-label="Unregister ${participant} from ${name}" | ||
| > | ||
| <svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"> | ||
| <path d="M9 3h6l1 2h4v2H4V5h4l1-2zm1 6h2v8h-2V9zm4 0h2v8h-2V9zM7 9h2v8H7V9zm-1 11h12l1-12H5l1 12z" /> | ||
| </svg> | ||
| </button> | ||
| </li> | ||
| ` | ||
| ) | ||
| .join("") | ||
| : '<li class="participant-empty">No students registered yet.</li>'; | ||
|
|
||
| activityCard.innerHTML = ` | ||
| <h4>${name}</h4> | ||
| <p>${details.description}</p> | ||
| <p><strong>Schedule:</strong> ${details.schedule}</p> | ||
| <p><strong>Availability:</strong> ${spotsLeft} spots left</p> | ||
| <div class="participants-section"> | ||
| <p class="participants-title">Participants</p> | ||
| <ul class="participants-list">${participantsMarkup}</ul> | ||
| </div> | ||
| `; |
There was a problem hiding this comment.
Participant emails (and activity names) are interpolated directly into innerHTML (including into an attribute via aria-label). Since emails come from user input and the backend doesn’t enforce strict email validation/escaping, this enables HTML injection/XSS in the activity list. Build the participants list with DOM APIs (createElement, textContent, setAttribute) or escape the values before injecting them into HTML strings.
| # Arrange: Restore original activities state | ||
| activities.clear() | ||
| activities.update(copy.deepcopy(ORIGINAL_ACTIVITIES)) | ||
| yield | ||
| # Cleanup: Restore after test completes |
There was a problem hiding this comment.
The reset_activities fixture’s comments/docstring say there is cleanup after the test, but there is no post-yield restoration logic. Either remove the cleanup comment and the unnecessary yield, or actually restore the state after yield (so failures mid-test don’t leak state into the rest of the session).
| # Arrange: Restore original activities state | |
| activities.clear() | |
| activities.update(copy.deepcopy(ORIGINAL_ACTIVITIES)) | |
| yield | |
| # Cleanup: Restore after test completes | |
| # Reset activities to the original state before each test | |
| activities.clear() | |
| activities.update(copy.deepcopy(ORIGINAL_ACTIVITIES)) |
This pull request introduces several major improvements to the activities management app, focusing on enhanced participant management, user interface updates, backend API changes, and the addition of comprehensive automated tests. The most important changes include the ability to unregister participants from activities, improved frontend display and interactivity for managing participants, and robust backend and test coverage to ensure reliability.
Backend functionality enhancements:
/activities/{activity_name}/participantsinapp.pyto allow unregistering a student from an activity, including validation for activity and participant existence.activitiesdata structure, introducing new clubs and teams.Frontend and UI improvements:
app.jsto display the list of participants for each activity, including a delete button next to each participant for quick removal.styles.cssfor activity cards and participant lists, adding a modern look and clear separation for participant management. [1] [2]Testing and reliability:
tests/test_app.pycovering all API endpoints, including signup, unregister, error cases, and activity retrieval, with automatic state reset between tests for isolation.