Enhanced voting system for groups.

This commit is contained in:
CrowdDiscussesAlternatives 2024-03-31 10:01:14 +03:00
parent 8f8a8e83e4
commit cb867382ca
9 changed files with 521 additions and 1 deletions

104
classes/aliasauth-class.php Normal file
View file

@ -0,0 +1,104 @@
<?php
/*
Crowd Discusses Alternatives is a web application for more organized discussions that help people create alternative solutions, evaluate and rank them.
Copyright 2021-2024 Stavros Kalognomos
This file is part of Crowd Discusses Alternatives.
Crowd Discusses Alternatives is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
Crowd Discusses Alternatives is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License along with Crowd Discusses Alternatives. If not, see <https://www.gnu.org/licenses/>.
*/
class AliasAuth extends Cda
{
protected function getBallotBoxIdOfGroup($groupId)
{
$sql = 'SELECT ballot_box_id
FROM groups_of_p
WHERE id = :groupid;';
$params = array(':groupid' => $groupId);
$stmt = $this->executeStmt($sql, $params);
$result = $stmt->fetch();
return $result;
}
protected function checkIfAliasExists($alias, $ballotBoxId)
{
$sql = 'SELECT id
FROM aliases_of_users
WHERE alias = :alias AND ballot_box_id = :ballotboxid;';
$params = array(':ballotboxid' => $ballotBoxId, ':alias' => $alias);
$stmt = $this->executeStmt($sql, $params);
$result = $stmt->fetch();
if (!($result === false || $result === null || $result['id'] === null)) { //If there is no id, it returns false.
return $result['id'];
} else {
return null;
}
}
protected function setAliasVoteAndHashNumber(int $ballotBoxId, int $userId, $vote, int $groupId, $alias, $hashNumber)
{
$sql = 'INSERT INTO aliases_of_users (id, ballot_box_id, user_id, vote, group_id, alias, hash_number)
VALUES (LAST_INSERT_ID(), :ballotBoxId, :userId, :vote, :groupId, :alias, :hashNumber);';
$params = array(':ballotBoxId' => $ballotBoxId, ':userId' => $userId, ':vote' => $vote, ':groupId' => $groupId, ':alias' => $alias, ':hashNumber' => $hashNumber);
$stmt = $this->executeStmt($sql, $params);
}
protected function getAliasVoteAndHashNumber(int $userId, int $groupId)
{
$sql = 'SELECT id, ballot_box_id, vote, group_id, alias, hash_number
FROM aliases_of_users
WHERE user_id = :userId AND group_id = :groupId;';
$params = array(':userId' => $userId, ':groupId' => $groupId);
$stmt = $this->executeStmt($sql, $params);
$results = $stmt->fetch();
if (!($results === false || $results === null || $results['id'] === null)) { //If there is no id, it returns false.
return $results;
} else {
return null;
}
}
protected function getAllAliasesVotesAndHashNumbersForGroup(int $groupId)
{
$sql = 'SELECT aliases_of_users.id, ballot_box_id, vote, group_id, alias, hash_number, user_name
FROM aliases_of_users
JOIN users_of_cda ON aliases_of_users.user_id = users_of_cda.id
WHERE group_id = ?
ORDER BY alias ASC;';
$params = [$groupId];
$stmt = $this->execStmtWithBindParam($sql, $params);
$results = $stmt->fetchAll();
return $results;
}
/*
protected function getAllUsersThatVotedForGroup(int $groupId)
{
$sql = 'SELECT user_name
FROM aliases_of_users
JOIN users_of_cda ON aliases_of_users.user_id = users_of_cda.id
WHERE group_id = ?;';
$params = [$groupId];
$stmt = $this->execStmtWithBindParam($sql, $params);
$results = $stmt->fetchAll();
return $results;
}
*/
}

View file

@ -0,0 +1,81 @@
<?php
/*
Crowd Discusses Alternatives is a web application for more organized discussions that help people create alternative solutions, evaluate and rank them.
Copyright 2021-2024 Stavros Kalognomos
This file is part of Crowd Discusses Alternatives.
Crowd Discusses Alternatives is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
Crowd Discusses Alternatives is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License along with Crowd Discusses Alternatives. If not, see <https://www.gnu.org/licenses/>.
*/
class AliasAuthContr extends AliasAuth
{
protected function generateAliasAndSecretCode(/*$groupId, */$BallotBoxId)
{
$numberOfCharForAlias = 8;
$numberOfCharForSecretCode = 10;
/*
$ballotBoxId = $this->getBallotBoxIdOfGroup($groupId);
if ($ballotBoxId == false || $ballotBoxId == null) {
exit("--Error: Ballot Box ID does not exist.");
}
*/
for ($i=0; $i < 100; $i++) {
//This only creates characters of [a-f][0-9]. Number of characters = 2 * $bytes.
//$newAlias = bin2hex(random_bytes(4));
$newAlias = bin2hex(openssl_random_pseudo_bytes($numberOfCharForAlias/2));
$aliasId = $this->checkIfAliasExists($newAlias, $BallotBoxId);
if ($aliasId === null) {
break;
}
}
if ($aliasId !== null) {
exit("--Error: There was an error when generating the alias.");
}
$newSecretCode = bin2hex(openssl_random_pseudo_bytes($numberOfCharForSecretCode/2));
return ["alias"=>$newAlias, "secretCode"=>$newSecretCode];
}
Public function createVoteTableInfo($vote, $group)
{
if ($group == 0) {
exit("--Error: Group cannot be found.");
}
$selectedCategory = 'g'; //Implemented only for groups at the moment.
//$group = $this->getSelectedTgpcr($selectedCategory, (int)$group['id']);
$aliasAndSecretCode = $this->generateAliasAndSecretCode(/*(int)$group['id'], */(int)$group['ballot_box_id']);
$hashNumber = hash("sha256", $aliasAndSecretCode['alias'] . $aliasAndSecretCode['secretCode']);
$this->setAliasVoteAndHashNumber($group['ballot_box_id'], $_SESSION["userId"], $vote, $group['id'], $aliasAndSecretCode['alias'], $hashNumber);
$sessionVarName = "voteforg" . $group['id'];
//$_SESSION[$sessionVarName] = ['topicid' => 't' . $group['topic_id'], 'groupname' => $group['group_name'], 'alias' => $aliasAndSecretCode['alias'], 'vote' => $vote, 'secretCode' => $aliasAndSecretCode['secretCode']];
$_SESSION[$sessionVarName] = ['topicid' => 't' . $group['topic_id'], 'groupname' => $group['group_name'], 'alias' => $aliasAndSecretCode['alias'], 'secretCode' => $aliasAndSecretCode['secretCode']];
//return ['t' . $group['topic_id'], $selectedCategory . $group['id'], $group['group_name'], $aliasAndSecretCode['alias'], $vote, $aliasAndSecretCode['secretCode']];
}
Public function checkHashNumber($alias, $secretCode, $providedHashNumber)
{
$alias = trim($alias);
$secretCode = trim($secretCode);
$realHashNumber = hash("sha256", $alias . $secretCode);
if ($realHashNumber == $providedHashNumber) {
$result = "Correct: Hash number is correct.";
} else {
$result = "Error: Hash number is wrong!";
}
return [$alias, $secretCode, $providedHashNumber, $realHashNumber, $result];
}
}

View file

@ -0,0 +1,67 @@
<?php
/*
Crowd Discusses Alternatives is a web application for more organized discussions that help people create alternative solutions, evaluate and rank them.
Copyright 2021-2024 Stavros Kalognomos
This file is part of Crowd Discusses Alternatives.
Crowd Discusses Alternatives is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
Crowd Discusses Alternatives is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License along with Crowd Discusses Alternatives. If not, see <https://www.gnu.org/licenses/>.
*/
class AliasAuthView extends AliasAuth
{
public function showAllAliasesVotesAndHashNumbersForGroup($groupId)
{
$results = $this->getAllAliasesVotesAndHashNumbersForGroup((int)$groupId);
return $results;
}
/*
public function showAllUsersThatVotedForGroup($groupId)
{
$results = $this->getAllUsersThatVotedForGroup((int)$groupId);
return $results;
}
*/
public function suffleResults($results)
{
$i = 0;
foreach ($results as $key => $value) {
$MembersThatVoted[$i] = $value['user_name'];
$i++;
}
shuffle($MembersThatVoted);
/*
$rand = new \Random\Randomizer();
$SuffledResults = $rand->shuffleArray($MembersThatVoted);
return $SuffledResults;
*/
return $MembersThatVoted;
}
Public function checkIfEligibleForTempResults($topicId)
{
$tgpcr = $this->getSelectedTopicWithTimeTableInfo((int)$topicId);
$topicInitiatorName = $tgpcr['user_name'];
if ($topicInitiatorName === null) {
exit("<br><br><b>--Error: Initiator not found, or topic not found.<b>");
} elseif ($topicInitiatorName !== $_SESSION["userUid"]) {
exit("<br><br><b>--Please note that you are not the initiator of the topic in order to perform this action.");
}
if ($tgpcr["groups_state"] > 0) {
exit("<br><br><b>--Temporary results of this voting event will be available when the fourth phase is closed.");
}
}
}

View file

@ -91,6 +91,10 @@ if (isset($_SESSION['userId'], $_SESSION['auth'] ,$_COOKIE['auth']) && $_COOKIE[
$cdaContrObj->vote((int)$tgpcr['ballot_box_id'], $vote, (int)$tgpcr['topic_id'], 2);
$cdaContrObj->updateMembersScore($_POST["selectedcategory"], (int)$_POST["selectedid"], $vote);
//For sending an alias and a secret-code to the user, when he/she is voting for a group. These are used later for validating manually the vote (when the report of the temporary results of the voting event is published).
$aliasAuthContrObj = new AliasAuthContr();
$aliasAuthContrObj->createVoteTableInfo($vote, $tgpcr);
unset($aliasAuthContrObj);
unset($cdaContrObj);
unset($cdaViewObj);
header("Location: ../vote.php?selected=" . $_POST["selectedcategory"] . $_POST["selectedid"] . "&vote=success");

View file

@ -59,6 +59,7 @@
<li><a class="nav_a" href="viewgroups.php?selectedt=t<?php echo $tgpcr['topic_id'] ?>&selectedgid=<?php echo $groupId ?>">View proposals of group</a></li>
<li><a class="nav_a" href="viewcommentsofselected.php?selected=<?php echo $_GET['selected']; ?>">View comments</a></li>
<li><a class="nav_a" href="evaluategroup.php?selected=<?php echo $_GET['selected']; ?>">Evaluate group</a></li>
<li><a class="nav_a" href="votingeventreport.php?selectedgid=<?php echo $groupId; ?>">Print report of results</a></li>
</div>
</ul>
<?php

View file

@ -432,4 +432,79 @@ textarea {
margin-left: 1.5em;
list-style-type: circle solid;
}
/*<<-- For about page. <<--*/
/*<<-- For about page. <<--*/
/*-->> For vote table info. -->>*/
.votetableinfo
{
border: 1px solid;
border-radius: 7px;
margin: 1.5em;
margin-top: 0.5em;
padding: 0.5em;
}
.votetableinfotitle
{
font-size: 0.9em;
margin-bottom: 0.3em;
}
.votetableinfo ul
{
font-size: 0.9em;
margin-left: 0.3em;
list-style-type: none;
}
/*<<-- For vote table info. <<--*/
/*-->> For temporary results. -->>*/
.temporaryresults
{
margin-left: 1.5em;
margin-right: 1.5em;
font-size: 0.9em;
}
.temporaryresults h2
{
margin-top: 0.4em;
font-size: 1.2em;
}
.temporaryresults th, td
{
border: 1px solid;
border-radius: 2px;
font-size: 0.9em;
padding-left: 0.2em;
padding-right: 0.2em;
}
.indexofresults, .aliasofresults
{
width: 6em;
}
.voteofresults
{
width: 4em;
}
.usernameofresults
{
width: 7em;
}
.hashnumberofresults
{
width: 37em;
font-size: 0.8em;
}
.hashnumberofresultstitle
{
width: 32.9em;
font-size: 0.9em;
}
/*<<-- For temporary results. <<--*/

View file

@ -85,6 +85,15 @@
<br>
<p id="p_vote_urlvar"></p>
<?php
//For sending an alias and a secret-code to the user, when he/she is voting for a group. These are used later for validating manually the vote (when the report of the temporary results of the voting event is published).
if ($selectedCateg == 'g' && isset($_GET["vote"]) && $_GET["vote"] == "success") {
require 'votetableinfo.php';
/*?>
<script type="text/javascript" src="./votewithalias.js"></script>
<?php*/
}
?>
<script type="module" src="./vote.js"></script>
<script type="text/javascript" src="./viewtgpcr.js"></script>

43
votetableinfo.php Normal file
View file

@ -0,0 +1,43 @@
<?php
/*
Crowd Discusses Alternatives is a web application for more organized discussions that help people create alternative solutions, evaluate and rank them.
Copyright 2021-2024 Stavros Kalognomos
This file is part of Crowd Discusses Alternatives.
Crowd Discusses Alternatives is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
Crowd Discusses Alternatives is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License along with Crowd Discusses Alternatives. If not, see <https://www.gnu.org/licenses/>.
*/
$groupId = $selectedTgpcrID;
$sessionVarName = "voteforg" . $groupId;
if (!isset($_SESSION[$sessionVarName])) {
exit("--Error: Alias and secret code could not be generated.");
}
$topicId = $_SESSION[$sessionVarName]['topicid'];
$groupName = $_SESSION[$sessionVarName]['groupname'];
$alias = $_SESSION[$sessionVarName]['alias'];
//$vote = $_SESSION[$sessionVarName]['vote'];
$secretCode = $_SESSION[$sessionVarName]['secretCode'];
?>
<br>
<div class="votetableinfo" id="votetableinfo">
<div class="votetableinfotitle" id="votetableinfotitle"><b>-- Information table --</b></div>
<ul>
<li>Topic ID: <?php echo $topicId; ?></li>
<li>Group ID: <?php echo $groupId; ?></li>
<li>Group: <?php echo $groupName; ?></li>
<li>Alias: <?php echo $alias; ?></li>
<li>Secret code: <?php echo $secretCode; ?></li>
<!--<li>Vote: <?php echo $vote; ?></li>-->
<li>Vote: <b>Please fill in this cell with what you have just voted (+1, 0 or -1) after copying/pasting this table.</b></li>
<li>Message: Thank you for voting. Please copy and keep this table somewhere safely in your device, in order to be able to validate your vote later.</li>
</ul>
</div>
<br>
<?php
unset($_SESSION[$sessionVarName]);
?>

136
votingeventreport.php Normal file
View file

@ -0,0 +1,136 @@
<?php
/*
Crowd Discusses Alternatives is a web application for more organized discussions that help people create alternative solutions, evaluate and rank them.
Copyright 2021-2022 Stavros Kalognomos
This file is part of Crowd Discusses Alternatives.
Crowd Discusses Alternatives is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
Crowd Discusses Alternatives is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License along with Crowd Discusses Alternatives. If not, see <https://www.gnu.org/licenses/>.
*/
session_start(); //session_start(); on the top of the code.
require_once 'includes/autoloader-inc.php';
//ini_set('max_execution_time', 300); // in order to avoid Fatal error: Maximum execution time of 30 seconds exceeded.
$cdaContrObj = new CdaContr();
$cdaViewObj = new CdaView();
$aliasAuthViewObj = new AliasAuthView();
$cdaContrObj->checkIfLoggedIn("Location: login.php?error=notloggedin");
require "header.php";
?>
<main>
<?php
if (!isset($_REQUEST['selectedgid'])) {
exit("<br><br><b>-- Error: Group ID is not found!<b>");
}
$groupId = intval($_GET['selectedgid']);
$group = $cdaViewObj->showSelectedTgpcr('g', (int)$groupId);
$aliasAuthViewObj->checkIfEligibleForTempResults((int)$group['topic_id']);
$results = $aliasAuthViewObj->showAllAliasesVotesAndHashNumbersForGroup((int)$groupId);
if ($results == [] || $results == null) {
exit("<br><br><b>-- Please note that no one has voted for this group.<b>");
}
?>
<br>
<div class="temporaryresults">
<h2>Temporary Results of group ID <?php echo $groupId ?></h2>
<br>
<div>
<div>Topic ID: <?php echo $group['topic_id'] ?></div>
<div>Group ID: <?php echo $groupId ?></div>
<div>Group: <?php echo $group['group_name'] ?></div>
</div>
<br>
<caption>First table of temporary results:</caption>
<table>
<tr>
<th class="indexofresults">Index</th>
<th class="aliasofresults">Alias</th>
<th class="voteofresults">Vote</th>
<th class="hashnumberofresultstitle">Hash-Number</th>
</tr>
</table>
<?php
$counter = 0;
$sumOfVotes = 0;
foreach ($results as $key => $value) {
$sumOfVotes = $sumOfVotes + $value['vote'];
$counter++;
?>
<table>
<tr>
<td class="indexofresults"><?php echo $counter ?></td>
<td class="aliasofresults"><?php echo $value['alias'] ?></td>
<td class="voteofresults"><?php echo $value['vote'] ?></td>
<td class="hashnumberofresults"><?php echo $value['hash_number'] ?></td>
</tr>
</table>
<?php
}
//$results = $aliasAuthViewObj->showAllUsersThatVotedForGroup((int)$groupId);
$suffledResults = $aliasAuthViewObj->suffleResults($results);
?>
<table>
<tr>
<th class="indexofresults">Index</th>
<th class="aliasofresults">Alias</th>
<th class="voteofresults">Vote</th>
<th class="hashnumberofresultstitle">Hash-Number</th>
</tr>
</table>
<br>
<caption>Second table of temporary results: Members that have voted in this voting event, <u>in random order</u>.</caption>
<table>
<tr>
<th class="usernameofresults">User-Name</th>
</tr>
</table>
<?php
foreach ($suffledResults as $key => $value) {
?>
<table>
<tr>
<td class="usernameofresults"><?php echo $value ?></td>
</tr>
</table>
<?php
}
?>
<table>
<tr>
<th class="usernameofresults">User-Name</th>
</tr>
</table>
<br>
<div>
<div>Topic ID: <?php echo $group['topic_id'] ?></div>
<div>Group ID: <?php echo $groupId ?></div>
<div>Group: <?php echo $group['group_name'] ?></div>
</div>
<div>Sum of Votes: <?php echo $sumOfVotes ?></div>
</div>
<br>
<br>
<?php
unset($cdaContrObj);
unset($cdaViewObj);
unset($aliasAuthViewObj);
?>
</main>
<?php
require "footer.php";
?>