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 d40f6ce Change: one database for all elections, rather than
per-election.
d40f6ce is described below
commit d40f6ce383f211391e617a595bbded922dcf8efa
Author: Greg Stein <[email protected]>
AuthorDate: Fri Sep 19 23:39:00 2025 -0500
Change: one database for all elections, rather than per-election.
* schema.sql: update for new design
- METADATA becomes ELECTIONS
- add OWNER_PID and AUTHZ
- add EID to the ISSUES table
* crypto.shuffle() updated for py3.11 change. Needs further work.
* election.py:
- stash the EID for this Election; use as needed
- update some cursors and queries for the schema change
- update .perform() calls to add the EID as needed
- .add_issue() needs an EID parameter
* tweak check_coverage for the schema and API changes
---
v3/schema.sql | 46 ++++++++++++++++++++++++++++++++++++----------
v3/steve/crypto.py | 3 ++-
v3/steve/election.py | 24 ++++++++++++++----------
v3/test/check_coverage.py | 14 +++++++-------
4 files changed, 59 insertions(+), 28 deletions(-)
diff --git a/v3/schema.sql b/v3/schema.sql
index 800af3a..67ddfa5 100644
--- a/v3/schema.sql
+++ b/v3/schema.sql
@@ -17,13 +17,15 @@
* under the License.
*/
-/* ### TBD DOCCO. */
+/* There is a per-install SQLite database containing all election data
+ for the site. This file defines/constructs the schema of that database.
+ */
-/* ### $ sqlite3 testing.db < schema.sql
+/* ### $ sqlite3 steve.db < steve/v3/schema.sql
###
### OR:
### >>> import sqlite3
- ### >>> conn = sqlite3.connect('testing.db')
+ ### >>> conn = sqlite3.connect('steve.db')
### >>> conn.executescript(open('schema.sql').read())
###
### ? maybe: conn.commit() and/or conn.close() ... the DML statements
@@ -34,7 +36,6 @@
/* --------------------------------------------------------------------- */
/* Various metadata about the Election contained in this database.
- Only one row will exist.
An Election has three states:
@@ -49,18 +50,24 @@
3. Closed. The election is closed.
DEFINITION: salt and opened_key are NOT NULL. closed is 1.
*/
-CREATE TABLE METADATA (
+CREATE TABLE ELECTIONS (
- /* The Election ID. This value might be replicated in the
- filesystem holding this database. To remain independent of
- application file choices, the ID is stored here. */
+ /* The Election ID. This is a unique text string. We do not use
+ AUTOINCREMENT, so that URLs for elections cannot be deduced. */
eid TEXT PRIMARY KEY NOT NULL,
/* Title of this election. */
title TEXT NOT NULL,
+ /* Who is the owner/creator of this election? */
+ owner_pid TEXT NOT NULL,
+
+ /* What authz group is allowed to edit this election? If NULL,
+ then only the OWNER_PID can edit. */
+ /* ### contents/format is TBD; think "which PMC" or "Foundation" */
+ authz TEXT,
+
/* ### if we have monitors, they go here. */
- /* ### maybe add an owner? */
/* A salt value to use for hashing this Election. 16 bytes.
This will be NULL until the Election is opened. */
@@ -76,16 +83,32 @@ CREATE TABLE METADATA (
opened). 1 for closed (implies it was opened). */
closed INTEGER
+ /* ### add foreign key for owner_pid */
+
+ /*
+ ,
+ FOREIGN KEY (convo_id) REFERENCES convo(id)
+ ON DELETE RESTRICT
+ ON UPDATE NO ACTION,
+
+ FOREIGN KEY (file_id) REFERENCES files(fname)
+ ON DELETE RESTRICT
+ ON UPDATE NO ACTION
+ */
) STRICT;
/* --------------------------------------------------------------------- */
-/* The set of issues to vote upon in this Election. */
+/* The set of issues to vote upon for a given Election. */
CREATE TABLE ISSUES (
/* The Issue ID, matching [-a-zA-Z0-9]+ */
+ /* ### switch to autoincrement? use TITLE for humans. */
iid TEXT PRIMARY KEY NOT NULL,
+ /* Which election is this issue associated with? */
+ eid TEXT NOT NULL,
+
/* Simple one-line title for this issue. */
title TEXT NOT NULL,
@@ -105,6 +128,8 @@ CREATE TABLE ISSUES (
This will be NULL until the Election is opened. */
salt BLOB
+ /* ### add foreign reference for EID */
+
) STRICT;
/* --------------------------------------------------------------------- */
@@ -155,6 +180,7 @@ CREATE TABLE VOTES (
) STRICT;
+/* ### review queries.yaml to figure out proper indexes */
CREATE INDEX I_BY_PERSON ON VOTES (person_token);
CREATE INDEX I_BY_ISSUE ON VOTES (issue_token);
diff --git a/v3/steve/crypto.py b/v3/steve/crypto.py
index ca969c0..ed8b13c 100644
--- a/v3/steve/crypto.py
+++ b/v3/steve/crypto.py
@@ -78,4 +78,5 @@ def _hash(data: bytes, salt: bytes) -> bytes:
def shuffle(x):
"Ensure we use the strongest RNG available for shuffling."
- return random.shuffle(x, passlib.utils.rng.random)
+ ### second param was removed in 3.11. need to revisit this.
+ return random.shuffle(x) ###, passlib.utils.rng.random)
diff --git a/v3/steve/election.py b/v3/steve/election.py
index 9ce9d2c..5095586 100644
--- a/v3/steve/election.py
+++ b/v3/steve/election.py
@@ -35,8 +35,9 @@ class Election:
S_OPEN = 'open'
S_CLOSED = 'closed'
- def __init__(self, db_fname):
+ def __init__(self, db_fname, eid):
self.db = db.DB(db_fname)
+ self.eid = eid
# Construct cursors for all operations.
self.c_salt_issue = self.db.add_statement(
@@ -44,11 +45,13 @@ class Election:
self.c_salt_person = self.db.add_statement(
'UPDATE PERSON SET salt = ? WHERE _ROWID_ = ?')
self.c_open = self.db.add_statement(
- 'UPDATE METADATA SET salt = ?, opened_key = ?')
+ 'UPDATE ELECTIONS SET salt = ?, opened_key = ?'
+ ' WHERE eid = ?')
self.c_close = self.db.add_statement(
- 'UPDATE METADATA SET closed = 1')
+ 'UPDATE ELECTIONS SET closed = 1'
+ ' WHERE eid = ?')
self.c_add_issue = self.db.add_statement(
- '''INSERT INTO ISSUES VALUES (?, ?, ?, ?, ?, ?)
+ '''INSERT INTO ISSUES VALUES (?, ?, ?, ?, ?, ?, ?)
ON CONFLICT DO UPDATE SET
title=excluded.title,
description=excluded.description,
@@ -74,8 +77,9 @@ class Election:
''')
# Cursors for running queries.
- self.q_metadata = self.db.add_query('metadata',
- 'SELECT * FROM METADATA')
+ ### need to add eid to the ISSUES queries; likely ELECTIONS
+ self.q_metadata = self.db.add_query('elections',
+ 'SELECT * FROM ELECTIONS')
self.q_issues = self.db.add_query('issues',
'SELECT * FROM ISSUES ORDER BY iid')
self.q_person = self.db.add_query('person',
@@ -103,7 +107,7 @@ class Election:
print('SALT:', salt)
print('KEY:', opened_key)
- self.c_open.perform((salt, opened_key))
+ self.c_open.perform((salt, opened_key, self.eid))
def gather_election_data(self):
"Gather a definition of this election for keying and anti-tamper."
@@ -135,7 +139,7 @@ class Election:
assert self.is_open()
# Simple tweak of the metadata to close the Election.
- self.c_close.perform()
+ self.c_close.perform((self.eid,))
def add_salts(self):
"Set the SALT column in the ISSUES and PERSON tables."
@@ -180,14 +184,14 @@ class Election:
return (issue.title, issue.description, issue.type,
self.json2kv(issue.kv))
- def add_issue(self, iid, title, description, vtype, kv):
+ def add_issue(self, iid, eid, title, description, vtype, kv):
"Add or update an issue designated by IID."
assert self.is_editable()
assert vtype in vtypes.TYPES
# If we ADD, then SALT will be NULL. If we UPDATE, then it will not
# be touched (it should be NULL).
- self.c_add_issue.perform((iid, title, description, vtype,
+ self.c_add_issue.perform((iid, eid, title, description, vtype,
self.kv2json(kv), None))
def delete_issue(self, iid):
diff --git a/v3/test/check_coverage.py b/v3/test/check_coverage.py
index 10745b1..75208da 100755
--- a/v3/test/check_coverage.py
+++ b/v3/test/check_coverage.py
@@ -28,7 +28,7 @@ import os.path
import sqlite3
import json
-import coverage
+import coverage # pip3 install coverage
# Ensure that we can import the "steve" package.
THIS_DIR = os.path.realpath(os.path.dirname(__file__))
@@ -54,12 +54,12 @@ def touch_every_line():
pass
conn = sqlite3.connect(TESTING_DB)
conn.executescript(open(SCHEMA_FILE).read())
- conn.execute('INSERT INTO METADATA'
- f' VALUES ("{eid}", "title", NULL, NULL, NULL)')
+ conn.execute('INSERT INTO ELECTIONS VALUES'
+ f' ("{eid}", "title", "alice", NULL, NULL, NULL, NULL)')
conn.commit()
# Ready to load up the Election and exercise it.
- e = steve.election.Election(TESTING_DB)
+ e = steve.election.Election(TESTING_DB, eid)
_ = e.get_metadata() # while EDITABLE
@@ -71,8 +71,8 @@ def touch_every_line():
e.delete_person('david')
_ = e.get_person('alice')
- e.add_issue('a', 'issue A', None, 'yna', None)
- e.add_issue('b', 'issue B', None, 'stv', {
+ e.add_issue('a', eid, 'issue A', None, 'yna', None)
+ e.add_issue('b', eid, 'issue B', None, 'stv', {
'seats': 3,
'labelmap': {
'a': 'Alice',
@@ -83,7 +83,7 @@ def touch_every_line():
},
})
_ = e.list_issues()
- e.add_issue('c', 'issue C', None, 'yna', None)
+ e.add_issue('c', eid, 'issue C', None, 'yna', None)
e.delete_issue('c')
_ = e.get_issue('a')