}
}
+fn read_elim_list(dir: &Path) -> std::io::Result<HashSet<String>> {
+ match std::fs::File::open(dir.join("eliminated")) {
+ Err(e) if e.kind() == std::io::ErrorKind::NotFound => Ok(HashSet::new()),
+ Err(e) => Err(e),
+ Ok(elimfile) => std::io::BufReader::new(elimfile).lines().collect(),
+ }
+}
+
fn valid_id_char(c: u8) -> bool {
- (b'A'..=b'Z').contains(&c) || (b'a'..=b'z').contains(&c) || (b'0'..=b'9').contains(&c)
+ c.is_ascii_alphanumeric()
}
fn make_random_id() -> [u8; COOKIE_LENGTH] {
<style>
th { font-size: 70%; text-align: left }
input { transform: scale(1.5) }
+ .eliminated { text-decoration: line-through; }
div { animation: 2s infinite linear spin }
@keyframes spin {
from { transform:rotate(0) }
<script>
window.onload = function() {
for (cb of document.getElementsByTagName('input')) {
+ if (cb.parentElement.parentElement.classList.contains('eliminated'))
+ continue;
cb.addEventListener('click', (function(cb) {
return function() {
cb.style.display = 'none'
None
};
let tally = tally_votes(dir).map_err(|_| cgi::text_response(503, "Couldn't tally votes"))?;
+ let elim =
+ read_elim_list(dir).map_err(|_| cgi::text_response(503, "Couldn't read eliminations"))?;
let cfile = std::fs::File::open(dir.join("candidates"))
.map_err(|_| cgi::text_response(503, "No candidates"))?;
let mut response = cgi::html_response(
} else {
""
};
+ let class = if elim.contains(&c) { "eliminated" } else { "" };
format!(
- "<tr>
+ "<tr class=\"{class}\">
<td>{count}</td>
<td><input type=\"checkbox\" autocomplete=\"off\" {checked} disabled></td>
<td>{c}</td>
{
return Err(cgi::text_response(415, "Invalid vote"));
}
+ let elim =
+ read_elim_list(dir).map_err(|_| cgi::text_response(503, "Couldn't read eliminations"))?;
+ if elim.contains(
+ std::str::from_utf8(&body[2..]).map_err(|_| cgi::text_response(415, "Vote not UTF-8"))?,
+ ) {
+ return Err(cgi::text_response(403, "Candidate eliminated"));
+ }
write_vote(dir, get_voter(request)?, body)
.map_err(|_| cgi::text_response(503, "Couldn't record vote"))?;
Ok(cgi::text_response(200, "Vote recorded"))