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
The following commit(s) were added to refs/heads/trunk by this push:
new 91d3a48 Continued page development (voter/admin). Add vote-on.
91d3a48 is described below
commit 91d3a48aa845cc922f209a39e53bd8de69bf8923
Author: Greg Stein <[email protected]>
AuthorDate: Mon Oct 6 01:52:43 2025 -0500
Continued page development (voter/admin). Add vote-on.
* admin.ezt: provide cards for each election, lifted from voter.ezt
* voter.ezt: new link target for voting on an election
* vote-on.ezt: new page to vote on an election
* e_bad_eid.ezt: unknown or invalid election for the user
* pages.py:
- add TEMPLATES global, and use throughout
- T_BAD_EID is a 404 page
- voter_page(): use the signed-in uid rather than dev/test gstein.
Only pass election data, not owned/admin data. Provide lengths for
both of those.
- vote_on_page(): new page to display a page for a Person to vote on
an Election. may use the new T_BAD_EID.
- admin_page(): fetch elections for this user, and the owned
elections. pass into template, along with lengths.
- raise_404(): new func to raise a 404 with custom content.
---
v3/server/pages.py | 85 +++++++++++++++++-------
v3/server/templates/admin.ezt | 58 +++++++++++++++-
v3/server/templates/{admin.ezt => e_bad_eid.ezt} | 3 +-
v3/server/templates/{admin.ezt => vote-on.ezt} | 5 +-
v3/server/templates/voter.ezt | 2 +-
5 files changed, 126 insertions(+), 27 deletions(-)
diff --git a/v3/server/pages.py b/v3/server/pages.py
index 3ab5340..eecf61a 100644
--- a/v3/server/pages.py
+++ b/v3/server/pages.py
@@ -37,6 +37,7 @@ APP = asfquart.APP
THIS_DIR = pathlib.Path(__file__).resolve().parent
DB_FNAME = THIS_DIR / APP.cfg.db
+TEMPLATES = THIS_DIR / 'templates'
sys.path.insert(0, str(THIS_DIR.parent))
import steve.election
@@ -48,6 +49,8 @@ FMT_DATE_FULL = '%Y-%m-%d %H:%M'
SOON_1HOUR = 60 * 60
SOON_CUTOFF = 48 * SOON_1HOUR # 48 hours, in seconds
+T_BAD_EID = APP.load_template(TEMPLATES / 'e_bad_eid.ezt')
+
async def signin_info():
"Return EZT template data for the Sign-In, in the upper right."
@@ -60,7 +63,7 @@ async def signin_info():
@APP.get('/')
[email protected]_template('templates/home.ezt')
[email protected]_template(TEMPLATES / 'home.ezt')
async def home_page():
result = await signin_info()
result.title = 'Home'
@@ -70,49 +73,80 @@ async def home_page():
@APP.get('/voter')
@asfquart.auth.require({R.committer}) ### need general solution
[email protected]_template('templates/voter.ezt')
[email protected]_template(TEMPLATES / 'voter.ezt')
async def voter_page():
- pid = 'gstein' ### get from session
+ result = await signin_info()
+ result.title = 'Voting'
with asfpy.stopwatch.Stopwatch():
# These are lists of EasyDict instances for each Election.
- election = steve.election.Election.open_to_pid(DB_FNAME, pid)
- owned = steve.election.Election.owned_elections(DB_FNAME, pid)
+ election = steve.election.Election.open_to_pid(DB_FNAME, result.uid)
+ owned = steve.election.Election.owned_elections(DB_FNAME, result.uid)
- ### should change q_owned to return owner_pid even though it is
- ### known from the query param. (ie. solve in sql, not python)
- for e in owned:
- e.owner_pid = pid
+ result.election = [ postprocess_election(e) for e in election ]
+
+ result.len_election = len(election)
+ result.len_owned = len(owned)
+ return result
+
+
[email protected]('/vote-on/<eid>')
[email protected]({R.committer}) ### need general solution
[email protected]_template(TEMPLATES / 'vote-on.ezt')
+async def vote_on_page(eid):
result = await signin_info()
- result.title = 'Voting'
+ result.title = 'Vote On Election'
- result.election = [ postprocess_election(e) for e in election ]
- result.owned = [ postprocess_election(e) for e in owned ]
+ e = steve.election.Election(DB_FNAME, eid)
- result.len_elections = len(result.election)
- result.len_owned = len(result.owned)
+ try:
+ md = e.get_metadata()
+ except AttributeError:
+ # If the EID is wrong, the fetch fails trying to access metadata.
+ ### YES, very poor way to signal a bad EID. fix this.
+ result.title = 'Unknown Election'
+ result.eid = eid
+ # Note: result.uid (and friends) are needed for the navbar.
+ raise_404(T_BAD_EID, result)
+ # NOTREACHED
+
+ ### check authz
+
+ ### rando for now. fetch the issues, and put in a count.
+ result.issue_count = 7
return result
-### NOTE: this is for ASF committers only. Obviously, this is not a
-### general purpose solution. Something for the future, to figure out
-### how we'd like to do configuration authorization for various install
-### scenarios and authn systems.
@APP.get('/admin')
@asfquart.auth.require({R.committer}) ### need general solution
[email protected]_template('templates/admin.ezt')
[email protected]_template(TEMPLATES / 'admin.ezt')
async def admin_page():
result = await signin_info()
result.title = 'Administration'
+ with asfpy.stopwatch.Stopwatch():
+ # These are lists of EasyDict instances for each Election.
+ election = steve.election.Election.open_to_pid(DB_FNAME, result.uid)
+ owned = steve.election.Election.owned_elections(DB_FNAME, result.uid)
+
+ ### for now. future: adjust query
+ for e in owned:
+ e.issue_count = 5
+ e.owner_pid = result.uid
+
+ result.owned = [ postprocess_election(e) for e in owned ]
+
+ result.len_election = len(election)
+ result.len_owned = len(owned)
+
return result
@APP.get('/profile')
@asfquart.auth.require # Bare decorator means just require a valid session
[email protected]_template('templates/profile.ezt')
[email protected]_template(TEMPLATES / 'profile.ezt')
async def profile_page():
result = await signin_info()
result.title = 'Profile'
@@ -122,7 +156,7 @@ async def profile_page():
@APP.get('/settings')
@asfquart.auth.require # Bare decorator means just require a valid session
[email protected]_template('templates/settings.ezt')
[email protected]_template(TEMPLATES / 'settings.ezt')
async def settings_page():
result = await signin_info()
result.title = 'Settings'
@@ -131,7 +165,7 @@ async def settings_page():
@APP.get('/privacy')
[email protected]_template('templates/privacy.ezt')
[email protected]_template(TEMPLATES / 'privacy.ezt')
async def privacy_page():
result = await signin_info()
result.title = 'Privacy'
@@ -140,7 +174,7 @@ async def privacy_page():
@APP.get('/about')
[email protected]_template('templates/about.ezt')
[email protected]_template(TEMPLATES / 'about.ezt')
async def about_page():
result = await signin_info()
result.title = 'About'
@@ -190,3 +224,8 @@ def postprocess_election(e):
e.fmt_close_at_full = dt_close and dt_close.strftime(FMT_DATE_FULL)
return e
+
+
+def raise_404(template, data):
+ content = asfquart.utils.render(template, data)
+ quart.abort(quart.Response(content, status=404, mimetype='text/html'))
diff --git a/v3/server/templates/admin.ezt b/v3/server/templates/admin.ezt
index 4d95432..a4dada5 100644
--- a/v3/server/templates/admin.ezt
+++ b/v3/server/templates/admin.ezt
@@ -1,8 +1,64 @@
[include "header.ezt"]
<div class="container">
<h1>[title]</h1>
+
+
+ [for owned]
+ <div class="col-md-5 mb-4">
+ <a href="/vote-on/[owned.eid]" class="text-decoration-none">
+ <div class="card h-100">
+ <div class="card-body">
+ <h5 class="card-title">[owned.title][#
+ ][if-any owned.closed] (closed)[else][#
+ ][if-any owned.is_opened] (open)[end][end]</h5>
+ <p class="card-text">
+ This election currently has
[owned.issue_count] issues.
+ <br/>
+ eid: [owned.eid]
+ <br/>
+ created by: [owned.owner_pid]
+ <br/>
+ authz: [owned.authz]
+ <br/>
+ closed: [owned.closed]
+ </p>
+ </div>
+ <div class="card-footer text-muted">
+ [if-any owned.closed]
+ Closed
+ <span title="[owned.fmt_close_at_full]"
+ style="border-bottom: 1px dotted
#007bff;"
+ >[owned.fmt_close_at]</span>
+ [else]
+ [if-any owned.open_at]
+ <div>
+ [if-any owned.is_opened]
+ Opened
+ [else]
+ Opening
+ [end]
+ <span title="[owned.fmt_open_at_full]"
+ style="border-bottom: 1px dotted
#007bff;"
+ >[owned.fmt_open_at]</span>
+ </div>
+ [end]
+ [if-any owned.close_at]
+ <div>
+ Closing
+ <span title="[owned.fmt_close_at_full]"
+ style="border-bottom: 1px dotted
#007bff;"
+ >[owned.fmt_close_at]</span>
+ </div>
+ [end]
+ [end]
+ </div>
+ </div>
+ </a>
+ </div>
+ [end]
+
<p>
- TBD
+ You have [len_election] election(s) <a href="/voter">to vote
upon</a>.
</p>
</div>
[include "footer.ezt"]
diff --git a/v3/server/templates/admin.ezt b/v3/server/templates/e_bad_eid.ezt
similarity index 54%
copy from v3/server/templates/admin.ezt
copy to v3/server/templates/e_bad_eid.ezt
index 4d95432..5beb3b8 100644
--- a/v3/server/templates/admin.ezt
+++ b/v3/server/templates/e_bad_eid.ezt
@@ -2,7 +2,8 @@
<div class="container">
<h1>[title]</h1>
<p>
- TBD
+ The Election ID ([eid]) does not exist,
+ or you have no issues to vote in that Election.
</p>
</div>
[include "footer.ezt"]
diff --git a/v3/server/templates/admin.ezt b/v3/server/templates/vote-on.ezt
similarity index 52%
copy from v3/server/templates/admin.ezt
copy to v3/server/templates/vote-on.ezt
index 4d95432..f027df9 100644
--- a/v3/server/templates/admin.ezt
+++ b/v3/server/templates/vote-on.ezt
@@ -2,7 +2,10 @@
<div class="container">
<h1>[title]</h1>
<p>
- TBD
+ You have [issue_count] issues to vote upon, in this election.
+ </p>
+ <p>
+ TBD: list
</p>
</div>
[include "footer.ezt"]
diff --git a/v3/server/templates/voter.ezt b/v3/server/templates/voter.ezt
index 544d7fe..a19db62 100644
--- a/v3/server/templates/voter.ezt
+++ b/v3/server/templates/voter.ezt
@@ -4,7 +4,7 @@
[for election]
<div class="col-md-5 mb-4">
- <a href="#" class="text-decoration-none">
+ <a href="/vote-on/[election.eid]" class="text-decoration-none">
<div class="card h-100">
<div class="card-body">
<h5 class="card-title">[election.title][#