This is an automated email from the ASF dual-hosted git repository. gstein pushed a commit to branch trunk in repository https://gitbox.apache.org/repos/asf/steve.git
commit 1caa49b1ea136209a5b9a74cf6da3a3a2f64ff67 Author: Greg Stein <[email protected]> AuthorDate: Fri Feb 20 05:49:34 2026 -0600 refactor: update voting to use form-based submission with submitFormWithLoading Co-authored-by: aider (openrouter/x-ai/grok-code-fast-1) <[email protected]> --- v3/TODO.md | 12 +++++++++++- v3/server/pages.py | 15 +++++++++++---- v3/server/templates/vote-on.ezt | 29 ++++++++--------------------- 3 files changed, 30 insertions(+), 26 deletions(-) diff --git a/v3/TODO.md b/v3/TODO.md index ddbd3ee..dcc1129 100644 --- a/v3/TODO.md +++ b/v3/TODO.md @@ -39,4 +39,14 @@ Based on a review of `v3/server/pages.py` (and related templates like `voter.ezt - **Imports/Constants**: All seem correct and follow conventions. - **No Obvious Syntax/Logic Errors**: The code parses and runs logically, but the above are functional gaps. -If you'd like to implement any of these fixes (e.g., add the date endpoints or fix upcoming elections), provide confirmation and details. Let me know if you have more context or want me to check specific sections! +If you'd like to implement any of these fixes (e.g., add the date endpoints or fix upcoming elections), provide confirmation and details. Let me know if you have more context or want to check specific sections! + +## 8. CSRF Checking +- **Issue**: CSRF tokens are placeholders and not validated in POST endpoints. +- **Impact**: Vulnerable to CSRF attacks. +- **Suggested Fix**: Implement a decorator to check CSRF tokens on POST endpoints (e.g., compare form/session token). Generate real tokens per session. + +## 9. Error Handling in `submitFormWithLoading` +- **Issue**: If the server returns an error during form submission via `submitFormWithLoading`, the page doesn't reload, and the button stays disabled, potentially confusing users. +- **Impact**: Poor UX on submission failures. +- **Suggested Fix**: Investigate and add client-side error handling (e.g., re-enable button on failure, show error message). diff --git a/v3/server/pages.py b/v3/server/pages.py index 83a4e31..7b160bf 100644 --- a/v3/server/pages.py +++ b/v3/server/pages.py @@ -375,18 +375,25 @@ async def do_vote_endpoint(election): ### check authz - # Parse the JSON payload - data = await quart.request.get_json() - if not data: + # Parse the form data + form = edict(await quart.request.form) + if not form: await flash_danger('No vote data provided.') return quart.redirect(f'/vote-on/{election.eid}', code=303) + # Extract votes from form (keys like 'vote-<iid>') + votes = {} + for key, value in form.items(): + if key.startswith('vote-'): + iid = key.split('-', 1)[1] + votes[iid] = value + # Get the list of issues for this election issues = election.list_issues() issue_dict = {i.iid: i for i in issues} # Process each vote - for iid, votestring in data.items(): + for iid, votestring in votes.items(): if iid not in issue_dict: await flash_danger(f'Invalid issue ID: {iid}') return quart.redirect(f'/vote-on/{election.eid}', code=303) diff --git a/v3/server/templates/vote-on.ezt b/v3/server/templates/vote-on.ezt index f46cab0..9c1e4fd 100644 --- a/v3/server/templates/vote-on.ezt +++ b/v3/server/templates/vote-on.ezt @@ -21,6 +21,10 @@ </button> </div> + <form id="voteForm" method="POST" action="/do-vote/[eid]"> + <!-- CSRF token for form submission --> + <input type="hidden" name="csrf_token" value="[csrf_token]"> + <div id="issues-list" class="list-group"> [for issues] <div class="list-group-item issue-item"> @@ -51,8 +55,9 @@ <!-- Submit Button --> <div class="mt-4"> - <button type="button" class="btn btn-primary" onclick="submitVotes()">Submit Votes</button> + <button type="button" class="btn btn-primary" id="submitVoteBtn" onclick="submitVotes()">Submit Votes</button> </div> + </form> </div> </div> @@ -105,7 +110,7 @@ // Submit votes function submitVotes() { const votes = {}; - [# careful! be wary of open-brackets within ezt ] + // careful! be wary of open-brackets within ezt document.querySelectorAll('.vote-radio input[[]type="radio"]:checked').forEach(radio => { const issueId = radio.name.split('-')[[]1]; votes[[]issueId] = radio.value; @@ -116,24 +121,6 @@ return; } - fetch('/do-vote/[eid]', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify(votes), - }) - .then(response => { - if (!response.ok) throw new Error('Network response was not ok'); - return response.json(); - }) - .then(data => { - alert('Votes submitted successfully!'); - console.log('Server response:', data); - }) - .catch(error => { - alert('Error submitting votes: ' + error.message); - console.error('Error:', error); - }); + submitFormWithLoading('voteForm', 'submitVoteBtn', 'Submitting Votes...'); } </script>
