Display interim results

This commit is contained in:
Peter J. Holzer 2022-11-07 23:06:51 +01:00
parent 41d545d191
commit 6edca66f7e
10 changed files with 163 additions and 9 deletions

106
app.py
View File

@ -150,7 +150,20 @@ def vote_date():
""",
(session["user"]["id"], meet_id,))
dates = csr.fetchall()
return render_template("date_vote_fragment.html", dates=dates)
result = instantrunoff_forward(meet_id, "date")
log.debug("result = %s", result)
return render_template("date_vote_fragment.html", dates=dates, result=result)
@app.get("/result/<int:meet_id>/date")
def result_date(meet_id):
result = instantrunoff_forward(meet_id, "date")
log.debug("result = %s", result)
return render_template("date_result_fragment.html", result=result)
@app.post("/vote/time")
def vote_time():
@ -186,7 +199,18 @@ def vote_time():
""",
(session["user"]["id"], meet_id,))
times = csr.fetchall()
return render_template("time_vote_fragment.html", times=times)
result = instantrunoff_forward(meet_id, "time")
log.debug("result = %s", result)
return render_template("time_vote_fragment.html", times=times, result=result)
@app.get("/result/<int:meet_id>/time")
def result_time(meet_id):
result = instantrunoff_forward(meet_id, "time")
log.debug("result = %s", result)
return render_template("time_result_fragment.html", result=result)
@app.post("/vote/place")
def vote_place():
@ -222,7 +246,19 @@ def vote_place():
""",
(session["user"]["id"], meet_id,))
places = csr.fetchall()
return render_template("place_vote_fragment.html", places=places)
result = instantrunoff_forward(meet_id, "place")
log.debug("result = %s", result)
return render_template("place_vote_fragment.html", places=places, result=result)
@app.get("/result/<int:meet_id>/place")
def result_place(meet_id):
result = instantrunoff_forward(meet_id, "place")
log.debug("result = %s", result)
return render_template("place_result_fragment.html", result=result)
def send_mail(email_address, confirmation_url):
@ -235,6 +271,70 @@ def send_mail(email_address, confirmation_url):
mta = smtplib.SMTP(host="localhost")
mta.send_message(msg)
def get_ballots(meet_id, kind):
csr = get_cursor()
q = f"""
select {kind}.*, bod, position
from {kind} join {kind}_vote on {kind}.id = {kind}_vote.{kind}
where meet = %s
order by bod, position
"""
csr.execute(q, (meet_id,))
last_bod = None
ballots = []
for r in csr:
if r.bod != last_bod:
ballot = []
ballots.append(ballot)
last_bod = r.bod
ballot.append(r)
return ballots
def dump_ballots(ballots):
for ballot in ballots:
log.debug ("---")
for r in ballot:
log.debug(r)
def runoff(ballots):
count = {}
candidates = {}
for ballot in ballots:
for r in ballot:
count[r.id] = 0
candidates[r.id] = r
for ballot in ballots:
# The votes are sorted by position, so the first entry is the favourite
count[ballot[0].id] += 1
result = sorted(count.keys(), key=lambda i: count[i])
log.debug("result of this round:")
for r in result:
log.debug(r, count[r])
log.debug("striking %d", result[0])
loser = candidates[result[0]]
new_ballots = [
[
r for r in ballot if r.id != loser.id
] for ballot in ballots
]
return loser, new_ballots
def instantrunoff_forward(meet_id, kind):
ballots = get_ballots(meet_id, kind)
result = []
while max(len(b) for b in ballots):
dump_ballots(ballots)
loser, ballots = runoff(ballots)
result.append(loser)
result = list(reversed(result))
log.debug("final result")
for r in result:
log.debug(r)
return result
def get_cursor():
db = get_db()
csr = db.cursor(row_factory=psycopg.rows.namedtuple_row)

View File

@ -10,19 +10,31 @@ body {
padding: 1em;
border: #CCC 1px solid;
border-radius: 0.2em;
cursor: grab;
}
.blue-background-class {
background: #CDF;
cursor: grabbing;
}
body {
display: grid;
grid-template-columns: 1fr 1fr;
grid-column-gap: 2em;
}
#hello {
grid-column: 1 / 3;
}
#h-day, #h-time, #h-place {
h1, h2 {
grid-column: 1 / 3;
}
.result-item {
padding: 1em;
border: #CCC 1px solid;
border-radius: 0.2em;
color: #888;
}

View File

@ -0,0 +1,7 @@
<div id="r-day" hx-swap-oob="true">
{% for r in result %}
<div class="result-item">
{{ r.display or r.date }}
</div>
{% endfor %}
</div>

View File

@ -4,3 +4,10 @@
<input type="hidden" name="date" value="{{d.id}}">
</div>
{% endfor %}
<div id="r-day" hx-swap-oob="true">
{% for r in result %}
<div class="result-item">
{{ r.display or r.date }}
</div>
{% endfor %}
</div>

View File

@ -0,0 +1,7 @@
<div id="r-place" hx-swap-oob="true">
{% for r in result %}
<div class="result-item">
{{ r.name }}
</div>
{% endfor %}
</div>

View File

@ -4,3 +4,10 @@
<input type="hidden" name="place" value="{{d.id}}">
</div>
{% endfor %}
<div id="r-place" hx-swap-oob="true">
{% for r in result %}
<div class="result-item">
{{ r.name }}
</div>
{% endfor %}
</div>

View File

@ -7,8 +7,8 @@
<body>
<p>Registriere dich:</p>
<form method="POST">
<input type="email" name="email">
<input name="target" value="{{request.args.target}}">
<input type="email" name="email" placeholder="Mail-Adresse">
<input type="hidden" name="target" value="{{request.args.target}}">
<input type="submit">
</form>
</body>

View File

@ -0,0 +1,7 @@
<div id="r-time" hx-swap-oob="true">
{% for r in result %}
<div class="result-item">
{{ r.display or r.time }}
</div>
{% endfor %}
</div>

View File

@ -4,3 +4,10 @@
<input type="hidden" name="time" value="{{d.id}}">
</div>
{% endfor %}
<div id="r-time" hx-swap-oob="true">
{% for r in result %}
<div class="result-item">
{{ r.display or r.time }}
</div>
{% endfor %}
</div>

View File

@ -23,7 +23,7 @@
</div>
{% endfor %}
</form>
<div id="r-day">
<div id="r-day" hx-get="/result/{{meet.id}}/date" hx-trigger="load">
</div>
<h2 id="h-time">
Zu welcher Zeit?
@ -36,7 +36,7 @@
</div>
{% endfor %}
</form>
<div id="r-time">
<div id="r-time" hx-get="/result/{{meet.id}}/time" hx-trigger="load">
</div>
<h2 id="h-place">
An welchem Ort?
@ -49,7 +49,7 @@
</div>
{% endfor %}
</form>
<div id="r-place">
<div id="r-place" hx-get="/result/{{meet.id}}/place" hx-trigger="load">
</div>
</body>
<script>