Bladeren bron

Added docker & sqlite support

docker
Tyler Dence 1 jaar geleden
bovenliggende
commit
ce5e7ab865
Getekend door: Tyler Dence <tyzoid.d@gmail.com> GPG sleutel-ID: 3B08EFC6BA974CFC
12 gewijzigde bestanden met toevoegingen van 326 en 87 verwijderingen
  1. 13
    0
      Dockerfile
  2. 4
    2
      web/admin/checkin.php
  3. 7
    4
      web/admin/paper.php
  4. 40
    29
      web/admin/voting.php
  5. 71
    32
      web/configure.php
  6. 168
    12
      web/inc/db.php
  7. 6
    2
      web/inc/inc.php
  8. 8
    0
      web/inc/misc.php
  9. 2
    1
      web/inc/user.php
  10. 3
    1
      web/index.php
  11. 2
    2
      web/styles/style.css
  12. 2
    2
      web/vote.php

+ 13
- 0
Dockerfile Bestand weergeven

@@ -0,0 +1,13 @@
FROM docker.io/bravecheng/php-nginx-sqlite:latest

USER nobody
RUN mkdir -p /var/www/html/inc/config
RUN chown nobody:nobody /var/www/html/inc/config
VOLUME /var/www/html/inc/config

USER root
WORKDIR /var/www
COPY cli cli
COPY web html

USER nobody

+ 4
- 2
web/admin/checkin.php Bestand weergeven

@@ -39,15 +39,17 @@ select
MIN(username) as `username`,
group_concat(proxy.voting_id) as `proxies`,
MIN(upstream_proxy.delegate_id) as `delegate`,
md5(coalesce(MIN(email), "")) as `gravatar_hash`
coalesce(MIN(email), "") as `gravatar_email`
from members
left join proxy on (members.voting_id=proxy.delegate_id)
left join proxy as upstream_proxy on (upstream_proxy.voting_id=members.voting_id)
where members.voting_id is not null
group by members.voting_id
UNION
select skymanager_id, voting_id, name, username, NULL as `proxies`, NULL as `delegate`, md5(coalesce(email, "")) as `gravatar_hash`
select skymanager_id, voting_id, name, username, NULL as `proxies`, NULL as `delegate`, coalesce(email, "") as `gravatar_email`
from members where members.voting_id is null');

get_gravatar_assoc($voters);
?>
<script type="text/javascript">
var voters = <?= json_encode($voters); ?>;

+ 7
- 4
web/admin/paper.php Bestand weergeven

@@ -28,7 +28,7 @@ if (!empty($_POST['ballot']) && !empty($_POST['candidate'])) {

if (empty($error)) {
$result = $db->query("INSERT INTO votes (candidate_id, position, member_id, vote_type, submitter_id) SELECT $candidate_selected, \"$ballot\", $voter_selected, 'IN PERSON', $voter_selected UNION SELECT $candidate_selected, \"$ballot\", voting_id, 'PROXY IN PERSON', delegate_id from proxy where delegate_id=$voter_selected");
$candidate = $db->fetchRow('select skymanager_id, name, username, md5(coalesce(email, "")) as `gravatar_hash` from members where skymanager_id=' . $candidate_selected);
$candidate = $db->fetchRow('select skymanager_id, name, username, coalesce(email, "") as `gravatar_email` from members where skymanager_id=' . $candidate_selected);

if ($result) {
$proxy_votes = $db->fetchAssoc("SELECT member_id, submitter_id from votes where submitter_id=$voter_selected and position=\"$ballot\"");
@@ -57,8 +57,11 @@ $header->setAttribute('title', 'Michigan Flyers');
$header->setAttribute('tagline', 'Election Poll Worker Tools');
$header->output();

$candidates = $db->fetchAssoc('select skymanager_id, name, username, md5(coalesce(email, "")) as `gravatar_hash` from members where voting_id is not null');
$voters = $db->fetchAssoc('select MIN(skymanager_id) as `skymanager_id`, MIN(members.voting_id) as `voting_id`, MIN(name) as `name`, MIN(username) as `username`, group_concat(proxy.voting_id) as `proxies`, MIN(upstream_proxy.delegate_id) as `delegate`, md5(coalesce(MIN(email), "")) as `gravatar_hash` from members left join proxy on (members.voting_id=proxy.delegate_id) left join proxy as upstream_proxy on (upstream_proxy.voting_id=members.voting_id) where members.voting_id is not null group by members.voting_id UNION select skymanager_id, voting_id, name, username, NULL as `proxies`, NULL as `delegate`, md5(coalesce(email, "")) as `gravatar_hash` from members where members.voting_id is null');
$candidates = $db->fetchAssoc('select skymanager_id, name, username, coalesce(email, "") as `gravatar_email` from members where voting_id is not null');
$voters = $db->fetchAssoc('select MIN(skymanager_id) as `skymanager_id`, MIN(members.voting_id) as `voting_id`, MIN(name) as `name`, MIN(username) as `username`, group_concat(proxy.voting_id) as `proxies`, MIN(upstream_proxy.delegate_id) as `delegate`, coalesce(MIN(email), "") as `gravatar_email` from members left join proxy on (members.voting_id=proxy.delegate_id) left join proxy as upstream_proxy on (upstream_proxy.voting_id=members.voting_id) where members.voting_id is not null group by members.voting_id UNION select skymanager_id, voting_id, name, username, NULL as `proxies`, NULL as `delegate`, coalesce(email, "") as `gravatar_email` from members where members.voting_id is null');

get_gravatar_assoc($candidates);
get_gravatar_assoc($voters);
?>
<script type="text/javascript">
var voters = <?= json_encode($voters); ?>;
@@ -134,7 +137,7 @@ var candidates = <?= json_encode($candidates); ?>;
<h4 class="section-heading">Candidate</h4>
<div id="vote-profile" class="candidate">
<div class="profile-icon">
<img src="https://www.gravatar.com/avatar/<?= $candidate['gravatar_hash']; ?>.png?d=mp&s=64" />
<img src="https://www.gravatar.com/avatar/<?= md5($candidate['gravatar_email']); ?>.png?d=mp&s=64" />
</div>
<div class="profile">
<h2 class="profile-name"><?= $candidate['name']; ?></h2>

+ 40
- 29
web/admin/voting.php Bestand weergeven

@@ -25,7 +25,7 @@ function loadPositions() {
function loadVoters() {
global $db;

return $db->fetchAssoc('
$voters = $db->fetchAssoc('
select
MIN(skymanager_id) as `skymanager_id`,
MIN(members.voting_id) as `voting_id`,
@@ -33,15 +33,18 @@ function loadVoters() {
MIN(username) as `username`,
group_concat(proxy.voting_id) as `proxies`,
MIN(upstream_proxy.delegate_id) as `delegate`,
md5(coalesce(MIN(email), "")) as `gravatar_hash`
coalesce(MIN(email), "") as `gravatar_email`
from members
left join proxy on (members.voting_id=proxy.delegate_id)
left join proxy as upstream_proxy on (upstream_proxy.voting_id=members.voting_id)
where members.voting_id is not null
group by members.voting_id
UNION
select skymanager_id, voting_id, name, username, NULL as `proxies`, NULL as `delegate`, md5(coalesce(email, "")) as `gravatar_hash`
select skymanager_id, voting_id, name, username, NULL as `proxies`, NULL as `delegate`, coalesce(email, "") as `gravatar_email`
from members where members.voting_id is null');

get_gravatar_assoc($voters);
return $voters;
}

$result = null;
@@ -60,34 +63,42 @@ if (!empty($_POST['create'])) {
$error = "Created position " . htmlspecialchars($desc);
}
} else if (!empty($_POST['setActive']) || !empty($_POST['deactivate'])) {
$positions = loadPositions();

$position = $_POST['ballot'];
if (!array_key_exists($position, $positions)) $error = "That position does not exist";
if (!empty($_POST['deactivate']))
$position='';

if (empty($error)) {
$result = $db->query('UPDATE positions set active=(position="' . $db->sanitize($position) . '")');
if ($result === false)
$error = "Failed to set active position";
else if (empty($position))
$error = "Deactivated voting form";
else
$error = "Set " . htmlspecialchars($positions[$_POST['ballot']]['label']) . " as active.";
if (!array_key_exists('ballot', $_POST)) {
$error = "No position selected";
} else {
$positions = loadPositions();

$position = $_POST['ballot'];
if (!array_key_exists($position, $positions)) $error = "That position does not exist";
if (!empty($_POST['deactivate']))
$position='';


if (empty($error)) {
$result = $db->query('UPDATE positions set active=(position="' . $db->sanitize($position) . '")');
if ($result === false)
$error = "Failed to set active position";
else if (empty($position))
$error = "Deactivated voting form";
else
$error = "Set " . htmlspecialchars($positions[$_POST['ballot']]['label']) . " as active.";
}
}
} else if (!empty($_POST['remove'])) {
$positions = loadPositions();

if (!array_key_exists($_POST['ballot'], $positions)) $error = "That position does not exist";

if (empty($error)) {
$result = $db->query('DELETE FROM positions WHERE position="' . $db->sanitize($_POST['ballot']) . '"');
if ($result === false)
$error = "Failed to remove position";
else
$error = "Removed " . htmlspecialchars($positions[$_POST['ballot']]['label']) . " and discarded cast ballots.";
if (!array_key_exists('ballot', $_POST)) {
$error = "No position selected";
} else {
$positions = loadPositions();

if (!array_key_exists($_POST['ballot'], $positions)) $error = "That position does not exist";

if (empty($error)) {
$result = $db->query('DELETE FROM positions WHERE position="' . $db->sanitize($_POST['ballot']) . '"');
if ($result === false)
$error = "Failed to remove position";
else
$error = "Removed " . htmlspecialchars($positions[$_POST['ballot']]['label']) . " and discarded cast ballots.";
}
}
} else if (!empty($_POST['force'])) {
$voters = loadVoters();

+ 71
- 32
web/configure.php Bestand weergeven

@@ -11,24 +11,41 @@ if (!empty($config)) {
require_once(BASE . '/inc/db.php');
require_once(BASE . '/inc/user.php');

$required = ['db-host', 'db-username', 'db-password', 'db-database', 'flyers-user', 'flyers-password'];
$fieldNames = ['db-type', 'db-host', 'db-username', 'db-password', 'db-database', 'flyers-user', 'flyers-password'];

function test_config($params) {
global $required, $db, $user;
global $fieldNames, $db, $user;

if (!empty($params) && count($params) != count($required))
return "All fields are required";

mysqli_report(MYSQLI_REPORT_OFF);
$mysql = mysqli_connect($params['db-host'], $params['db-username'], $params['db-password']);
if (!$mysql)
return "Unable to connect to the database.";
$config = [
"type" => $params['db-type']
];

mysqli_select_db($mysql, $params['db-database']);
if (mysqli_error($mysql))
return "Unable to access database '" . htmlspecialchars($params['db-database']) . "': " . mysqli_error($mysql);
if (empty($params['flyers-user']) || empty($params['flyers-password']))
return "All fields are required";

mysqli_multi_query($mysql, "
switch ($params['db-type']) {
case "mysql":
if (!empty($params) && count($params) != count($fieldNames))
return "All fields are required";
$config += [
'host' => $params['db-host'],
'user' => $params['db-username'],
'pass' => $params['db-password'],
'db' => $params['db-database']
];

$db = MysqlDb::Connect($config->host, $config->user, $config->pass, $config->db);
break;
case "sqlite":
$db = SqliteDb::Connect();
break;
default:
return "Invalid Database Type";
}

$success = $db->exec_multi("
CREATE TABLE IF NOT EXISTS `members` (
`skymanager_id` integer NOT NULL PRIMARY KEY,
`name` varchar(128) NOT NULL,
@@ -53,43 +70,36 @@ CREATE TABLE IF NOT EXISTS `votes` (
`candidate_id` integer NOT NULL,
`position` varchar(64) NOT NULL,
`member_id` integer NOT NULL,
`vote_type` enum('IN PERSON','ONLINE','PROXY IN PERSON','PROXY ONLINE','UNANIMOUS') NOT NULL DEFAULT 'ONLINE',
-- `vote_type` enum('IN PERSON','ONLINE','PROXY IN PERSON','PROXY ONLINE','UNANIMOUS') NOT NULL DEFAULT 'ONLINE',
`vote_type` varchar(24) NOT NULL DEFAULT 'ONLINE',
`submitted_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`submitter_id` integer NOT NULL,
PRIMARY KEY (`position`,`member_id`),
FOREIGN KEY (`position`) REFERENCES `positions` (`position`) ON DELETE CASCADE)
");
if (!$success)
return "Failed to set up database schema: " . $db->getError();

do {
if (mysqli_error($mysql))
return "Unable to set up tables: " . mysqli_error($mysql);
} while (mysqli_next_result($mysql) || mysqli_error($mysql));

$db = DBHandler::wrap($mysql);
$success = $user->login($params['flyers-user'], $params['flyers-password']);
if (!$success)
return "Login Failed";

$db->query("UPDATE members SET `pollworker`=TRUE where skymanager_id=" . ((int) $user->getUserId()));
if ($db->getError())
return "Failed to update user permissions";
if ($err = $db->getError())
return "Failed to update user permissions: $err";

$conf = json_encode([
'host' => $params['db-host'],
'user' => $params['db-username'],
'pass' => $params['db-password'],
'db' => $params['db-database']
], JSON_PRETTY_PRINT);
$conf = "";
$conf = json_encode($config, JSON_PRETTY_PRINT);

if (file_put_contents(BASE . "/inc/config.json", $conf) === false)
if (file_put_contents(BASE . "/inc/config/config.json", $conf) === false)
return "Failed to write configuration.";

return false;
}

$params = [];
foreach ($required as $field) {
foreach ($fieldNames as $field) {
if (array_key_exists($field, $_POST) && !empty($_POST[$field]))
$params[$field] = $_POST[$field];
}
@@ -110,6 +120,19 @@ if ($error === false) {
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" />
<link rel="stylesheet" type="text/css" href="https://fonts.googleapis.com/css2?family=Fira+Sans:wght@400;600;800&display=swap" />
<link rel="stylesheet" type="text/css" href="/styles/style.css" />
<style type="text/css">
form input#db-sqlite:checked~.form-row label[for="db-sqlite"] .radio-button-label,
form input#db-mysql:checked~.form-row label[for="db-mysql"] .radio-button-label {
background-color: #000;
color: #fff;
border: 2px solid #fff;
box-shadow: 0px 0px 0px 2px #000;
}

form .form-row.conditional { display: none; }
form input#db-mysql:checked~.form-row.mysql { display: block; }

</style>
</head>
<body>
<div id="container">
@@ -122,20 +145,36 @@ if ($error === false) {
<?php if(!empty($error)) echo "<span class=\"errormessage\">$error</span>"; ?>
<form action="configure.php" method="POST">
<div class="form-section">
<input type="radio" id="db-sqlite" name="db-type" value="sqlite" checked />
<input type="radio" id="db-mysql" name="db-type" value="mysql" />
<h3>Database Setup</h3>
<div class="form-row">
<div class="selector">
<label class="radio" for="db-sqlite">
<span class="radio-button-label">SQLite</span>
</label>
<label class="radio" for="db-mysql">
<span class="radio-button-label">MySQL</span>
</label>
</div>
</div>
<div class="form-row conditional mysql">
<label for="db-host">Host</label>
<input type="text" id="db-host" name="db-host" value="localhost" />
</div>
<div class="form-row">
<div class="form-row conditional mysql">
<label for="db-host">Host</label>
<input type="text" id="db-host" name="db-host" value="localhost" />
</div>
<div class="form-row conditional mysql">
<label for="db-database">Database Name</label>
<input type="text" id="db-database" name="db-database" />
</div>
<div class="form-row">
<div class="form-row conditional mysql">
<label for="db-username">Username</label>
<input type="text" id="db-username" name="db-username" />
</div>
<div class="form-row">
<div class="form-row conditional mysql">
<label for="db-password">Password</label>
<input type="password" id="db-password" name="db-password" />
</div>

+ 168
- 12
web/inc/db.php Bestand weergeven

@@ -1,22 +1,20 @@
<?php
class DBHandler{
class MysqlDb {
private $mysql;

private function __construct() {}

public static function Connect($hostname, $username, $password, $database){
$handler = new DBHandler();
$handler = new MysqlDb();

mysqli_report(MYSQLI_REPORT_OFF);
$handler->mysql = mysqli_connect($hostname, $username, $password);
if(!$handler->mysql) die("MySql error: " . mysql_error());
if(!$handler->mysql) return false;

mysqli_select_db($handler->mysql, $database);
return $handler;
}
if (mysqli_error($handler->mysql))
return false;

public static function Wrap($mysql) {
$handler = new DBHandler();
$handler->mysql = $mysql;
return $handler;
}

@@ -32,6 +30,45 @@ class DBHandler{
}
}

public function insert($table, $fields, $values_assoc, $ignore = false) {
$field_list = implode(",", $fields);
$values_arr = [];
foreach ($values_assoc as $value) {
$value_arr = [];
foreach ($value as $v) {
if ($this->verifyInteger($v))
$value_arr[] = $v;
else if ($v === "NULL")
$value_arr[] = "NULL";
else
$value_arr[] = "\"{$this->sanitize($v)}\"";
}

$values_arr[] = "(" . implode(',', $value_arr) . ")";
}
$values_list = implode(',', $values_arr);

$ignore_str = '';
if ($ignore)
$ignore_str = 'IGNORE';

return $this->query("INSERT $ignore_str INTO $table ($field_list) VALUES $values_list");
}

public function exec_multi($query){
try {
$res = mysqli_multi_query($this->mysql, $query);
do {
if ($err = $this->getError())
return false;
} while (mysqli_next_result($this->mysqli) || $this->getError());
return true;
} catch (Throwable $err) {
return false;
}
}

public function fetchRow($query){
$result = $this->query($query);
if($result === false || $result === true) die(mysqli_error($this->mysql));//return $result;
@@ -55,14 +92,133 @@ class DBHandler{
return mysqli_error($this->mysql);
}

public function lastInsertId(){
return mysqli_insert_id($this->mysql);
//public function lastInsertId(){
// return mysqli_insert_id($this->mysql);
//}

//public function getAffectedRows() {
// return mysqli_affected_rows($this->mysql);
//}

public function verifyInteger($input, $minimum = 1){
/*
* Pretty hacky solution.
*
* First checks if the integer cast of the input is equal to itself.
* This filters out decimals, alternate bases, and exponents.
* Then checks if the input is numeric, which filters out other strings that slip by the first check.
* This guarantees that it's in a numeric format, which combined with the first filter, should guarantee that it is an integer
*/
return (((int) $input == $input) && is_numeric($input) && (($minimum === false) || (int) $input >= $minimum));
}

// Always returns a key of length 40. TODO: Add arbitrary length
public function randomKey(){
//Cryptographically Secure Key
if(function_exists('openssl_random_pseudo_bytes')) return base64_encode(openssl_random_pseudo_bytes(30));


//Fallback (Not cryptographically secure)
$str = "";
for($i=0; $i<30; $i++){
$str .= chr(mt_rand(0,255));
}

return base64_encode($str);
}
}

class SqliteDb {
private $sqlite;

private function __construct() {}

public static function Connect(){
$handler = new SqliteDb();
$handler->sqlite = new Sqlite3(BASE . "/inc/config/sqlite3.db");
$handler->sqlite->exec('PRAGMA foreign_keys = ON');

return $handler;
}

public function sanitize($text){
return SQLite3::escapeString($text);
}

public function query($query){
try {
return $this->sqlite->query($query);
} catch (Throwable $err) {
return false;
}
}

public function insert($table, $fields, $values_assoc, $ignore = false) {
$field_list = implode(",", $fields);
$values_arr = [];
foreach ($values_assoc as $value) {
$value_arr = [];
foreach ($value as $v) {
if ($this->verifyInteger($v))
$value_arr[] = $v;
else if ($v === "NULL")
$value_arr[] = "NULL";
else
$value_arr[] = "\"{$this->sanitize($v)}\"";
}

$values_arr[] = "(" . implode(',', $value_arr) . ")";
}
$values_list = implode(',', $values_arr);

$ignore_str = '';
if ($ignore)
$ignore_str = 'OR IGNORE';

return $this->query("INSERT $ignore_str INTO $table ($field_list) VALUES $values_list");
}

public function exec_multi($query){
try {
return $this->sqlite->exec($query);
} catch (Throwable $err) {
return false;
}
}

public function fetchRow($query){
$result = $this->query($query);
if ($result === false || $result === true)
return $result;

return $result->fetchArray();
}

public function fetchAssoc($query){
$result = $this->query($query);
if($result === false || $result === true) die($this->getError());//return $result;

$data = array();
while($row = $result->fetchArray()){
$data[] = $row;
}

return $data;
}

public function getAffectedRows() {
return mysqli_affected_rows($this->mysql);
public function getError() {
return $this->sqlite->lastErrorCode() === 0 ? "" : $this->sqlite->lastErrorMsg();
}

//public function lastInsertId(){
// return mysqli_insert_id($this->mysql);
//}

//public function getAffectedRows() {
// return mysqli_affected_rows($this->mysql);
//}

public function verifyInteger($input, $minimum = 1){
/*
* Pretty hacky solution.

+ 6
- 2
web/inc/inc.php Bestand weergeven

@@ -3,7 +3,7 @@
define('BASE', dirname(__DIR__));
define('BASEURL', $_SERVER['SERVER_NAME']);

$config = json_decode(file_get_contents(BASE . "/inc/config.json"));
$config = json_decode(file_get_contents(BASE . "/inc/config/config.json"));
if (empty($config)) {
header('Location: /configure.php');
die();
@@ -15,9 +15,13 @@ session_start();
// Database and Authentication
require_once(BASE . '/inc/db.php');

$db = DBHandler::Connect($config->host, $config->user, $config->pass, $config->db);
if ($config->type == "mysql")
$db = MysqlDb::Connect($config->host, $config->user, $config->pass, $config->db);
else
$db = SqliteDb::Connect();

require_once(BASE . '/inc/user.php');
require_once(BASE . '/inc/misc.php');

// Templates
require_once(BASE . '/templates/header.php');

+ 8
- 0
web/inc/misc.php Bestand weergeven

@@ -0,0 +1,8 @@
<?php
function get_gravatar_assoc(&$results) {
foreach ($results as &$result) {
$result['gravatar_hash'] = md5($result['gravatar_email']);
unset($result['gravatar_email']);
}
}


+ 2
- 1
web/inc/user.php Bestand weergeven

@@ -59,7 +59,8 @@ class User{
$this->loggedin = true;

// Create user automatically on login
$_ = $db->query('insert ignore into members (skymanager_id, name, username, email) VALUES (' . ((int) $this->uid) . ', "' . $db->sanitize($this->name) . '", "' . $db->sanitize($this->username) . '", ' . (empty($this->email) ? 'NULL' : '"' . $db->sanitize($this->email) . '"') . ')');
//$_ = $db->query('insert into members (skymanager_id, name, username, email) VALUES (' . ((int) $this->uid) . ', "' . $db->sanitize($this->name) . '", "' . $db->sanitize($this->username) . '", ' . (empty($this->email) ? 'NULL' : '"' . $db->sanitize($this->email) . '"') . ') ON DUPLICATE KEY UPDATE skymanager_id=skymanager_id');
$_ = $db->insert('members', ['skymanager_id', 'name', 'username', 'email'], [[((int) $this->uid), $this->name, $this->username, (empty($this->email) ? 'NULL' : $this->email)]], true);

// Get voter ID
$result = $db->fetchRow('select members.voting_id from members left join proxy on (members.voting_id=proxy.voting_id) where proxy.delegate_id is null and skymanager_id=' . ((int) $this->uid));

+ 3
- 1
web/index.php Bestand weergeven

@@ -19,10 +19,12 @@ $header->setAttribute('title', 'Michigan Flyers');
$header->setAttribute('tagline', 'Online Ballot');
$header->output();

$candidates = $db->fetchAssoc('select skymanager_id, name, username, md5(coalesce(email, "")) as `gravatar_hash` from members where voting_id is not null');
$candidates = $db->fetchAssoc('select skymanager_id, name, username, coalesce(email, "") as `gravatar_email` from members where voting_id is not null');
$votes = $db->fetchAssoc("select position from votes where member_id={$user->voterId()}");
$position = $db->fetchRow("select position as code, description as label from positions where active<>0 limit 1");

get_gravatar_assoc($candidates);

foreach ($votes as &$vote) {
$vote = $vote['position'];
}

+ 2
- 2
web/styles/style.css Bestand weergeven

@@ -193,7 +193,7 @@ form div.selector label {
flex-grow: 1;
}

form label.radio input {
form label.radio input, form input[type=radio] {
display: none;
}

@@ -207,7 +207,7 @@ form label.radio .radio-button-label {
border-radius: 10px;
}

form label.radio input:checked+.radio-button-label {
form label.radio input:checked+.radio-button-label, form input:checked+label.radio .radio-button-label {
background-color: #000;
color: #fff;
border: 2px solid #fff;

+ 2
- 2
web/vote.php Bestand weergeven

@@ -24,7 +24,7 @@ if (!$error) {
try {
$result = $db->query("INSERT INTO votes (candidate_id, position, member_id, vote_type, submitter_id) SELECT $candidate_selected, \"$ballot\", {$user->voterId()}, 'ONLINE', {$user->voterId()} UNION SELECT $candidate_selected, \"$ballot\", voting_id, 'PROXY ONLINE', delegate_id from proxy where delegate_id={$user->voterId()}");
} catch (Throwable $ignore) {}
$candidate = $db->fetchRow('select skymanager_id, name, username, md5(coalesce(email, "")) as `gravatar_hash` from members where skymanager_id=' . $candidate_selected);
$candidate = $db->fetchRow('select skymanager_id, name, username, coalesce(email, "") as `gravatar_email` from members where skymanager_id=' . $candidate_selected);
if ($result) {
$to = 'mf2022elec@gmail.com';
$from = 'noreply@tyzoid.com';
@@ -83,7 +83,7 @@ $header->output();
<h4 class="section-heading">Candidate</h4>
<div id="vote-profile" class="candidate">
<div class="profile-icon">
<img src="https://www.gravatar.com/avatar/<?= $candidate['gravatar_hash']; ?>.png?d=mp&s=64" />
<img src="https://www.gravatar.com/avatar/<?= md5($candidate['gravatar_email']); ?>.png?d=mp&s=64" />
</div>
<div class="profile">
<h2 class="profile-name"><?= $candidate['name']; ?></h2>

Laden…
Annuleren
Opslaan