feat: Add more advanced voting
All checks were successful
Build Docker / Build Image (push) Successful in 22s

This commit is contained in:
Nathan Woodburn 2024-02-25 21:39:04 +11:00
parent eaf0a23923
commit e960d6d0ef
Signed by: nathanwoodburn
GPG Key ID: 203B000478AD0EF1
5 changed files with 114 additions and 11 deletions

2
dist/bundle.js vendored

File diff suppressed because one or more lines are too long

12
main.py
View File

@ -15,6 +15,8 @@ app = Flask(__name__)
dotenv.load_dotenv() dotenv.load_dotenv()
CURRENT_VOTE = os.getenv('CURRENT_VOTE') CURRENT_VOTE = os.getenv('CURRENT_VOTE')
OPTIONS = os.getenv('OPTIONS')
OPTIONS = json.loads(OPTIONS)
DISCORD_WEBHOOK = os.getenv('DISCORD_WEBHOOK') DISCORD_WEBHOOK = os.getenv('DISCORD_WEBHOOK')
# If votes file doesn't exist, create it # If votes file doesn't exist, create it
@ -52,7 +54,9 @@ def faviconPNG():
def index(): def index():
year = datetime.datetime.now().year year = datetime.datetime.now().year
votes = render.votes() votes = render.votes()
return render_template('index.html',year=year,votes=votes, current_vote=CURRENT_VOTE) options = render.options(OPTIONS)
return render_template('index.html',year=year,votes=votes, current_vote=CURRENT_VOTE, options=options)
@app.route('/<path:path>') @app.route('/<path:path>')
def catch_all(path): def catch_all(path):
@ -167,10 +171,8 @@ def send_discord_message(data):
} }
# Send the message as a POST request to the webhook URL # Send the message as a POST request to the webhook URL
response = requests.post(DISCORD_WEBHOOK, data=json.dumps(message), headers={'Content-Type': 'application/json'}) if DISCORD_WEBHOOK is not None:
requests.post(DISCORD_WEBHOOK, data=json.dumps(message), headers={'Content-Type': 'application/json'})
# Print the response from the webhook (for debugging purposes)
print(response.text)

View File

@ -6,9 +6,20 @@ def votes():
with open('data/votes.json') as file: with open('data/votes.json') as file:
votes = json.load(file) votes = json.load(file)
print(votes)
options = {} options = {}
for vote in votes: for vote in votes:
# Check if message is json
if vote["message"].startswith("{"):
message = json.loads(vote["message"])
for key in message:
if key in options:
options[key] += (int(message[key]) * int(vote["votes"]))
else:
options[key] = (int(message[key]) * int(vote["votes"]))
continue
if vote["message"] in options: if vote["message"] in options:
options[vote["message"]] += vote["votes"] options[vote["message"]] += vote["votes"]
else: else:
@ -45,3 +56,71 @@ def votes():
html += f'<canvas data-bss-chart=\'{json.dumps(chart_data)}\' class="chartjs-render-monitor"></canvas>' html += f'<canvas data-bss-chart=\'{json.dumps(chart_data)}\' class="chartjs-render-monitor"></canvas>'
return html return html
def options(options):
html = '<select id="vote" class="form-select" name="vote" onchange="showHideDiv()">'
for option in options:
html += f'<option value="{option}">{option}</option>'
html += '<option value="Advanced">Advanced</option>'
html += '</select>'
html += f'''
<script>function showHideDiv() {{
var selectedValue = document.getElementById("vote").value;
var divToToggle = document.getElementById("advancedOptions");
if (selectedValue === "Advanced") {{
divToToggle.style.display = "block";
}} else {{
divToToggle.style.display = "none";
// Set value of all inputs to 0
var inputs = document.querySelectorAll('#advancedOptions input[type="number"]');
inputs.forEach(function(input) {{
input.value = 0;
}});
// Set value of matching select to 100
var select = document.querySelector('#advancedOptions input[name="' + selectedValue + '"]');
select.value = 100;
}}
}}
</script>
'''
html += '<div id="advancedOptions" style="display: none;margin-top: 25px;text-align: left;">'
lastOption = options[-1]
for option in options:
html += '<div class="form-group" style="margin-bottom: 10px;">'
html += f'<label for="{option}" style="display: inline;margin-right:10px;">{option}</label>'
value = 0
if option == options[0]:
value = 100
if not lastOption == option:
html += f'<input id="{option}" type="number" name="{option}" value="{value}" class="form-control" style="width: auto; display: inline;margin-right:10px;" min="0" max="100" onchange="updateLastInput()">'
html += '% of vote share<br>'
else:
html += f'<input id="{option}" type="number" name="{option}" value="0" class="form-control" style="width: auto; display: inline;margin-right:10px;" min="0" max="100" readonly>'
html += '% of vote share (automatically calculated)<br>'
html += '</div>'
html += '</div>'
html += f'''
<script>
function updateLastInput() {{
var inputs = document.querySelectorAll('#advancedOptions input[type="number"]:not([readonly])');
var sum = 0;
inputs.forEach(function(input) {{
sum += parseInt(input.value);
}});
var lastInput = document.getElementById('{lastOption}');
lastInput.value = 100 - sum;
}}
</script>
'''
return html

View File

@ -97,13 +97,35 @@ document.addEventListener('DOMContentLoaded', async function() {
document.getElementById('signMessageForm').addEventListener('submit', async function(event) { document.getElementById('signMessageForm').addEventListener('submit', async function(event) {
event.preventDefault(); event.preventDefault();
const vote = document.getElementById('vote').value.trim(); // Get the value of the vote input field // Get all inputs in #advancedOptions
const inputs = document.querySelectorAll('#advancedOptions input');
// Ensure the vote is not empty // Store values in json with matching names
if (!vote) { const options = {};
alert('Please enter your vote.'); inputs.forEach(input => {
options[input.name] = input.value;
}
);
console.log(options);
// Make sure the votes total 100
let total = 0;
for (const key in options) {
if (options.hasOwnProperty(key)) {
const element = options[key];
total += parseInt(element);
// If value less than 0 or greater than 100, alert and return
if (element < 0 || element > 100) {
alert('Votes must be between 0 and 100');
return;
}
}
}
if (total !== 100) {
alert('Votes must total 100');
return; return;
} }
const vote = JSON.stringify(options);
// Encode the message as a buffer-like object // Encode the message as a buffer-like object
const messageUint8Array = new TextEncoder().encode(vote); const messageUint8Array = new TextEncoder().encode(vote);

View File

@ -49,7 +49,7 @@
<h4><span id="percent">0</span>% of the voting power.</h4> <h4><span id="percent">0</span>% of the voting power.</h4>
<p class="fs-5 text-muted mb-5">Vote here</p> <p class="fs-5 text-muted mb-5">Vote here</p>
<form class="d-flex justify-content-center flex-wrap" id="signMessageForm" data-bs-theme="light"> <form class="d-flex justify-content-center flex-wrap" id="signMessageForm" data-bs-theme="light">
<div class="shadow-lg mb-3"><input class="form-control" type="text" id="vote" name="vote" value="{{vote}}" placeholder="Your Vote"></div> <div class="shadow-lg mb-3">{{options|safe}}</div>
<div class="shadow-lg mb-3"><button class="btn btn-primary" type="submit">Vote</button></div> <div class="shadow-lg mb-3"><button class="btn btn-primary" type="submit">Vote</button></div>
</form> </form>
</div>{{votes|safe}} </div>{{votes|safe}}