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 e805ed5db52eac09b80fe9f144cb6798013cbcc5 Author: Greg Stein <[email protected]> AuthorDate: Fri Feb 20 02:00:19 2026 -0600 feat: add upcoming elections section to voter page Co-authored-by: aider (openrouter/x-ai/grok-code-fast-1) <[email protected]> --- v3/TODO.md | 9 ++------- v3/server/pages.py | 3 ++- v3/server/templates/voter.ezt | 46 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 50 insertions(+), 8 deletions(-) diff --git a/v3/TODO.md b/v3/TODO.md index d062c76..ddbd3ee 100644 --- a/v3/TODO.md +++ b/v3/TODO.md @@ -7,15 +7,10 @@ Based on a review of `v3/server/pages.py` (and related templates like `voter.ezt - **Impact**: Users won't be able to save dates via the UI, breaking the intended workflow. - **Resolution**: Added the two endpoints with a refactored helper function `_set_election_date` to handle common logic (auth, JSON parsing, validation, setting dates, logging, and response). Endpoints now require authentication, validate dates, and log actions. CSRF handling remains a TODO (placeholder token in use). Test for proper date-setting and error handling. Added supporting methods `set_open_at` and `set_close_at` to the Election class in `election.py`, and corresponding cursors [...] -## 2. Upcoming Elections Not Populated in `voter_page()` +## 2. Upcoming Elections Not Populated in `voter_page()` - RESOLVED - **Issue**: The `voter.ezt` template checks for `[if-any upcoming]` and loops over `upcoming` elections, but `voter_page()` only sets `result.election` (for open elections). `result.upcoming` is never defined, so the "Upcoming Elections" section will always be empty. - **Impact**: Upcoming elections (e.g., those in 'editable' state with a future open date) won't display, confusing users. -- **Suggested Fix**: Modify `voter_page()` to separate elections into `upcoming` and `election` (open ones). Assuming `steve.election.Election.open_to_pid()` returns all relevant elections, filter them: - - `upcoming`: Elections where `state == 'editable'` and `open_at` is in the future (within `SOON_CUTOFF`). - - `election`: The rest (open or closed, but template seems to handle closed via `(closed)` text). - - Add: `result.upcoming = [postprocess_election(e) for e in election if e.state == steve.election.Election.S_EDITABLE and (e.open_at and e.open_at > datetime.datetime.now().timestamp())]` - - Then, `result.election = [postprocess_election(e) for e in election if e not in result.upcoming]` - - Update `result.len_election` accordingly. +- **Resolution**: Added a new Election class method `upcoming_to_pid` to return editable elections for a given PID with voting eligibility. Added corresponding query `q_upcoming_to_me` in `queries.yaml`. Updated `voter_page()` to fetch and post-process upcoming elections into `result.upcoming`. Updated `voter.ezt` to include a dedicated "Upcoming Elections" section with similar card layout, a "Preview Ballot" link, and subtle visual distinction (lighter background, "Upcoming" badge). No [...] ## 3. Hardcoded `vtype` in `do_add_issue_endpoint()` - **Issue**: `vtype` is hardcoded to `'yna'`, and `kv = None`. The comment mentions handling SEATS for STV, but it's not implemented. If users try to add STV issues, it will fail or behave incorrectly. diff --git a/v3/server/pages.py b/v3/server/pages.py index 8c9daf9..945fb95 100644 --- a/v3/server/pages.py +++ b/v3/server/pages.py @@ -11,7 +11,7 @@ # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the +# KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. @@ -154,6 +154,7 @@ async def voter_page(): owned = steve.election.Election.owned_elections(DB_FNAME, result.uid) result.election = [postprocess_election(e) for e in election] + result.upcoming = [postprocess_election(e) for e in steve.election.Election.upcoming_to_pid(DB_FNAME, result.uid)] result.len_election = len(election) result.len_owned = len(owned) diff --git a/v3/server/templates/voter.ezt b/v3/server/templates/voter.ezt index 8def7c2..d4a6dc5 100644 --- a/v3/server/templates/voter.ezt +++ b/v3/server/templates/voter.ezt @@ -57,6 +57,52 @@ </div> [end] + <h2>Upcoming Elections</h2> + [if-any upcoming] + [for upcoming] + <div class="w-auto mb-4"> + <a href="/vote-on/[upcoming.eid]" class="text-decoration-none"> + <div class="card h-100 bg-light"> + <div class="card-body"> + <h5 class="card-title">[upcoming.title] <span class="badge badge-secondary">Upcoming</span></h5> + <p class="card-text"> + You have [upcoming.issue_count] issues to vote upon. + <br/> + eid: [upcoming.eid] + + [if-any upcoming.open_at] + <div> + Opening + <span title="[upcoming.fmt_open_at_full]" + style="border-bottom: 1px dotted #007bff;" + >[upcoming.fmt_open_at]</span> + </div> + [end] + [if-any upcoming.close_at] + <div> + Closing + <span title="[upcoming.fmt_close_at_full]" + style="border-bottom: 1px dotted #007bff;" + >[upcoming.fmt_close_at]</span> + </div> + [end] + + </p> + </div> + <div class="card-footer text-muted small"> + Created by [upcoming.owner_name] ([upcoming.owner_pid]) + [if-any upcoming.authz] + (authz: [upcoming.authz]) + [end] + </div> + </div> + </a> + </div> + [end] + [else] + <p>No upcoming elections.</p> + [end] + <p> You have [len_owned] <a href="/admin">elections to manage</a>. </p>
