Massive changes but I have to go to sleep now

This commit is contained in:
2020-12-05 06:05:56 +01:00
parent 525074af15
commit a642ea9890
17 changed files with 1104 additions and 1147 deletions

View File

@@ -1,13 +1,12 @@
package com.github.cato447.AbizeitungVotingSystem.controller;
import com.github.cato447.AbizeitungVotingSystem.entities.AuthCode;
import com.github.cato447.AbizeitungVotingSystem.entities.Category;
import com.github.cato447.AbizeitungVotingSystem.entities.PossibleCandidate;
import com.github.cato447.AbizeitungVotingSystem.entities.Voter;
import com.github.cato447.AbizeitungVotingSystem.helper.PossibleCandidateWrapper;
import com.github.cato447.AbizeitungVotingSystem.repositories.CandidateRepository;
import com.github.cato447.AbizeitungVotingSystem.repositories.CategoryRepository;
import com.github.cato447.AbizeitungVotingSystem.repositories.PossibleCandidateRepository;
import com.github.cato447.AbizeitungVotingSystem.repositories.VoterRepository;
import com.github.cato447.AbizeitungVotingSystem.helper.RandomNumber;
import com.github.cato447.AbizeitungVotingSystem.repositories.*;
import com.github.cato447.AbizeitungVotingSystem.table.TableAction;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mail.SimpleMailMessage;
@@ -20,24 +19,17 @@ import org.springframework.web.bind.annotation.RequestParam;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
@Controller
public class VotingController {
private Boolean candidatesAdded = false;
private Boolean candidatesAdded = true;
private static final Logger LOGGER = LogManager.getLogger(VotingController.class);
private TableAction tableAction = new TableAction();
List<String> ipAddresses = new ArrayList<String>();
@Autowired
VoterRepository voterRepository;
@@ -50,6 +42,9 @@ public class VotingController {
@Autowired
PossibleCandidateRepository possibleCandidateRepository;
@Autowired
AuthCodesRepository authCodesRepository;
@Autowired
JavaMailSender emailSender;
@@ -75,14 +70,6 @@ public class VotingController {
@RequestMapping("/")
public String WelcomeSite() {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes())
.getRequest();
String currentIpAddress = request.getRemoteAddr();
if (!this.ipAddresses.contains(currentIpAddress)) {
LOGGER.info("User IP: " + request.getRemoteAddr());
ipAddresses.add(currentIpAddress);
}
return "start.html";
}
@@ -95,77 +82,90 @@ public class VotingController {
emailSender.send(message);
}
@RequestMapping("/vote")
@RequestMapping("/checkStatus")
public String VerifyName(@RequestParam String name, Model model) {
if (name.strip().toLowerCase().matches("[a-z]+\\.[a-z]+@adolfinum+\\.de$")) {
try {
Voter voter = voterRepository.findByEmail(name.toLowerCase().strip());
LOGGER.warn(voter.getEmail());
if (voter.getVote_status()) {
LOGGER.warn(name + " has already voted");
return "errors/alreadyVoted.html";
} else if (voter.getCandidatesubmit_status()) {
} else if (voter.getCandidatesubmit_status() && candidatesAdded == false) {
LOGGER.warn(name + " has already submitted its candidates");
return "errors/alreadysubmittedcandidates.html";
} else {
if(candidatesAdded) {
List<Category> categories = categoryRepository.findAll();
model.addAttribute("categories", categories);
model.addAttribute("name", name);
//sendSimpleMessage(name,"test", "test");
LOGGER.info(name + " is voting now");
return "voting.html";
} else {
PossibleCandidateWrapper possibleCandidates = new PossibleCandidateWrapper();
List<Category> categories = categoryRepository.findAll();
for (int i = 0; i < categories.size(); i++){
possibleCandidates.addPossibleCandidate(new PossibleCandidate());
}
model.addAttribute("categories", categories);
model.addAttribute("form", possibleCandidates);
LOGGER.info(name + " is submitting candidates");
return "addingCandidates.html";
}
AuthCode authCode = tableAction.generateToken(name, RandomNumber.getRandomNumberString(), authCodesRepository);
sendSimpleMessage(name,"Code zur Authentifizierung", "Dein Code lautet: " + authCode.getCode());
model.addAttribute("name", name);
return "authenticate.html";
}
} catch (Exception e) {
LOGGER.error(name + " is not allowed to vote");
return "errors/notRegistered.html";
}
} else {
return "errors/falseInput";
return "errors/falseInput.html";
}
}
@RequestMapping("/vote")
public String voting_adding(@RequestParam String name, Model model){
if(candidatesAdded) {
List<Category> categories = categoryRepository.findAll();
model.addAttribute("categories", categories);
model.addAttribute("name", name);
return "voting.html";
} else {
PossibleCandidateWrapper possibleCandidates = new PossibleCandidateWrapper();
List<Category> categories = categoryRepository.findAll();
for (int i = 0; i < categories.size(); i++){
possibleCandidates.addPossibleCandidate(new PossibleCandidate());
}
model.addAttribute("categories", categories);
model.addAttribute("form", possibleCandidates);
model.addAttribute("name", name);
return "addingCandidates.html";
}
}
@RequestMapping("/saveCandidates")
public String candidateSaving(@ModelAttribute PossibleCandidateWrapper possibleCandidates){
LinkedList<PossibleCandidate> posCandidates = possibleCandidates.getPossibleCandidates();
long index = 1;
for (PossibleCandidate posCandidate : posCandidates){
if (posCandidate.getName() != "") {
if (possibleCandidateRepository.findByNameAndCategory(posCandidate.getName(), categoryRepository.findById(index).get()) != null) {
PossibleCandidate p = possibleCandidateRepository.findByNameAndCategory(posCandidate.getName(), categoryRepository.findById(index).get());
LOGGER.warn(p.getVotes());
p.setVotes(p.getVotes() + 1);
possibleCandidateRepository.save(p);
} else {
PossibleCandidate possibleCandidate = new PossibleCandidate(posCandidate.getName(), categoryRepository.findById(index).get());
possibleCandidateRepository.save(possibleCandidate);
public String candidateSaving(@ModelAttribute PossibleCandidateWrapper possibleCandidates, @RequestParam String name){
if (voterRepository.findByEmail(name).getVote_status()){
return "errors/alreadyVoted.html";
} else {
LinkedList<PossibleCandidate> posCandidates = possibleCandidates.getPossibleCandidates();
long index = 1;
for (PossibleCandidate posCandidate : posCandidates){
if (posCandidate.getName() != "") {
if (possibleCandidateRepository.findByNameAndCategory(posCandidate.getName(), categoryRepository.findById(index).get()) != null) {
PossibleCandidate p = possibleCandidateRepository.findByNameAndCategory(posCandidate.getName(), categoryRepository.findById(index).get());
p.setVotes(p.getVotes() + 1);
possibleCandidateRepository.save(p);
} else {
PossibleCandidate possibleCandidate = new PossibleCandidate(posCandidate.getName(), categoryRepository.findById(index).get());
possibleCandidateRepository.save(possibleCandidate);
}
}
index++;
}
index++;
//tableAction.updateCandidatesubmit_status(voterEmail, voterRepository);
return "candidateAddingSuccessful.html";
}
return "candidateAddingSuccessful.html";
}
@RequestMapping("/processVote")
public String ProcessVote(@RequestParam String voteValues, @RequestParam String voterEmail) {
String[] partVoteValues = voteValues.split(",");
for (String s: partVoteValues) {
tableAction.voteFor(s, candidateRepository);
public String ProcessVote(@RequestParam String name, @RequestParam String voteValues) {
if (voterRepository.findByEmail(name).getCandidatesubmit_status()){
return "errors/alreadySubmitted.html";
} else {
String[] partVoteValues = voteValues.split(",");
for (String s : partVoteValues) {
tableAction.voteFor(s, candidateRepository);
}
//tableAction.updateVotingStatus(voterEmail, voterRepository);
LOGGER.info(name + " has voted!");
return "voteSuccessful.html";
}
tableAction.updateVotingStatus(voterEmail,voterRepository);
LOGGER.info(voterEmail + " has voted!");
return "voteSuccessful.html";
}
@RequestMapping("/dashboard")

View File

@@ -0,0 +1,39 @@
package com.github.cato447.AbizeitungVotingSystem.entities;
import javax.persistence.*;
@Entity
@Table(name="auth_codes")
public class AuthCode {
public AuthCode(){
super();
}
public AuthCode(String name, String code) {
this.name = name;
this.code = code;
}
@Id
@GeneratedValue(strategy= GenerationType.IDENTITY)
private Long id;
private String name;
private String code;
private long time = System.currentTimeMillis();
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getName() {
return name;
}
public long getTime() {
return time;
}
}

View File

@@ -42,4 +42,8 @@ public class Voter {
public void vote(){
vote_status = true;
}
public void submitCandidates() {
candidatesubmit_status = true;
}
}

View File

@@ -0,0 +1,15 @@
package com.github.cato447.AbizeitungVotingSystem.helper;
import java.util.Random;
public class RandomNumber {
public static String getRandomNumberString() {
// It will generate 6 digit random Number.
// from 0 to 999999
Random rnd = new Random();
int number = rnd.nextInt(999999);
// this will convert any number sequence into 6 character.
return String.format("%06d", number);
}
}

View File

@@ -0,0 +1,10 @@
package com.github.cato447.AbizeitungVotingSystem.repositories;
import com.github.cato447.AbizeitungVotingSystem.entities.AuthCode;
import org.springframework.data.jpa.repository.JpaRepository;
public interface AuthCodesRepository extends JpaRepository<AuthCode, Integer> {
public AuthCode findByName(String name);
}

View File

@@ -1,14 +1,9 @@
package com.github.cato447.AbizeitungVotingSystem.table;
import com.github.cato447.AbizeitungVotingSystem.controller.VotingController;
import com.github.cato447.AbizeitungVotingSystem.entities.Candidate;
import com.github.cato447.AbizeitungVotingSystem.entities.Category;
import com.github.cato447.AbizeitungVotingSystem.entities.PossibleCandidate;
import com.github.cato447.AbizeitungVotingSystem.entities.Voter;
import com.github.cato447.AbizeitungVotingSystem.repositories.CandidateRepository;
import com.github.cato447.AbizeitungVotingSystem.repositories.CategoryRepository;
import com.github.cato447.AbizeitungVotingSystem.repositories.PossibleCandidateRepository;
import com.github.cato447.AbizeitungVotingSystem.repositories.VoterRepository;
import com.github.cato447.AbizeitungVotingSystem.entities.*;
import com.github.cato447.AbizeitungVotingSystem.repositories.*;
import org.aspectj.weaver.loadtime.definition.LightXMLParser;
import java.io.File;
import java.io.FileNotFoundException;
@@ -36,6 +31,40 @@ public class TableAction {
voterRepository.save(voter);
}
public void updateCandidatesubmit_status(String email, VoterRepository voterRepository){
Voter voter = voterRepository.findByEmail(email);
voter.submitCandidates();
voterRepository.save(voter);
}
public AuthCode generateToken(String name, String code, AuthCodesRepository authCodesRepository) {
AuthCode authCode = new AuthCode(name, code);
if (authCodesRepository.findByName(authCode.getName()) != null) {
authCodesRepository.findByName(authCode.getName()).setCode(authCode.getCode());
return authCode;
} else {
authCodesRepository.save(authCode);
return authCode;
}
}
public String checkToken(String name, String code, AuthCodesRepository authCodesRepository){
AuthCode authCode = authCodesRepository.findByName(name);
if (authCode.getCode().equals(code) && !fiveMinutesPassed(authCode.getTime())){
authCodesRepository.delete(authCode);
return "matched";
} else if(fiveMinutesPassed(authCode.getTime())) {
authCodesRepository.delete(authCode);
return "expired";
} else {
return "wrong";
}
}
private boolean fiveMinutesPassed(Long time){
return System.currentTimeMillis() >= (time + 300*1000);
}
public void voteFor(String id, CandidateRepository candidateRepository){
long candidateID = Long.valueOf(id);
Candidate candidate = candidateRepository.findById(candidateID).get();

View File

@@ -35,12 +35,11 @@ input {
color: #FFF;
font-size: .875rem;
font-weight: normal;
text-transform: uppercase;
text-align: left;
transition: opacity .25s .5s;
}
#submitButton {
.submitButton {
margin-top: 5%;
margin-bottom: 5%;
border: 0;
@@ -59,6 +58,6 @@ html,
body {
width: 100%;
height: 100%;
background-image: linear-gradient(to bottom right, #111E25 0%, #111 100%) fixed;
background-image: linear-gradient(to bottom right, #111E25 0%, #111 100%);
font-family: 'Lato', sans-serif;
}

View File

@@ -0,0 +1,62 @@
body {
background-color: rgb(44, 49, 54);
font-family: Arial, Helvetica, sans-serif;
}
.center-screen {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
text-align: center;
}
.centered {
background: transparent;
margin: 0 auto;
padding: 20px;
width: 100%;
overflow: auto;
}
h1 {
margin-top: 5%;
color: #FFF;
margin-bottom: 5%;
}
h2.categoryHeader {
color: #FFF;
}
input {
background-color: transparent;
border: transparent;
border-bottom: 2px solid red;
color: #FFF;
font-size: xx-large;
width: 1ch;
}
.submitButton {
margin-top: 5%;
margin-bottom: 5%;
border: 0;
outline: 0;
background: #bb1515;
color: rgba(255, 255, 255, 0.85);
font-size: 2rem;
width: 500px;
letter-spacing: .0625rem;
border-radius: 12px;
box-shadow: 0 3px 5px 1px rgba(0, 0, 0, 0.25);
text-shadow: 0 -2px 0 rgba(0, 0, 0, 0.25), 0 1px 0 rgba(255, 255, 255, 0.2);
}
html,
body {
width: 100%;
height: 100%;
background-image: linear-gradient(to bottom right, #111E25 0%, #111 100%);
font-family: 'Lato', sans-serif;
}

View File

@@ -2,6 +2,8 @@ td.voted {
background-color: #f05048;
}
td.submitted {}
td.notVoted {
background-color: #76ed6b;
}

View File

@@ -39,7 +39,7 @@ button {
transition: opacity .25s .5s;
}
#submitButton {
.submitButton {
margin-top: 5%;
padding: .25em 0;
border: 0;

View File

@@ -5,17 +5,49 @@
<meta charset="UTF-8">
<title>Title</title>
<link th:href="@{/styles/addingCandidates.css}" rel="stylesheet" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
</head>
<body class="center-screen">
<script>
var q = 1,
qMax = 0;
$(function() {
qMax = $('#inputForm div.group').length;
$('#inputForm div.group').hide();
$('#inputForm div.group:nth-child(1)').show();
$('#btnNext').on('click', function(event) {
event.preventDefault();
handleClick();
});
});
function handleClick() {
if (q < qMax) {
$('#inputForm div.group:nth-child(' + q + ')').hide();
$('#inputForm div.group:nth-child(' + (q + 1) + ')').show();
if (q == (qMax - 1)) {
$('#btnNext').html('Submit Answers');
}
q++;
} else {
document.getElementById("inputForm").submit();
}
}
</script>
<div class="centered">
<h1>Schlage für jede Kategorie eine/n Kandiadt/en vor:</h1>
<form action="#" th:action="@{/saveCandidates}" th:object="${form}" method="post">
<div th:each="category, itemStat : ${categories}">
<h2 class="categoryHeader" th:text="${category.name}"></h2>
<input th:field="*{possibleCandidates[__${itemStat.index}__].name}" />
<form id="inputForm" action="#" th:action="@{/saveCandidates}" th:object="${form}" method="post">
<div id="candidateAdding">
<div class="group" th:each="category, itemStat : ${categories}">
<h2 class="categoryHeader" th:text="${category.name}"></h2>
<input th:field="*{possibleCandidates[__${itemStat.index}__].name}" />
</div>
</div>
<input type="submit" id="submitButton" th:value="Confirm"></button>
<button class="submitButton" id="btnNext" type="submit">Nächste Frage</button>
<input id="voterName" type="hidden" name="name" th:value="${name}" />
</form>
</div>
</body>

View File

@@ -0,0 +1,56 @@
<!DOCTYPE html>
<html lang="en" xmlns:th="https://www.thymeleaf.org/">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<link th:href="@{/styles/authenticate.css}" rel="stylesheet" />
</head>
<body class="center-screen">
<script>
const $inp = $(".passInput");
$inp.on({
paste(ev) { // Handle Pasting
const clip = ev.originalEvent.clipboardData.getData('text').trim();
// Allow numbers only
if (!/\d{6}/.test(clip)) return ev.preventDefault(); // Invalid. Exit here
// Split string to Array or characters
const s = [...clip];
// Populate inputs. Focus last input.
$inp.val(i => s[i]).eq(5).focus();
},
input(ev) { // Handle typing
const i = $inp.index(this);
if (this.value) $inp.eq(i + 1).focus();
},
keydown(ev) { // Handle Deleting
const i = $inp.index(this);
if (!this.value && ev.key === "Backspace" && i) $inp.eq(i - 1).focus();
}
});
</script>
<h1 th:text="|Dir wurde eine Email an ${name} gesendet!|"></h1>
<h2>Gebe den enthaltenen Authentifizierungscode ein</h2>
<form action="#" id="passForm" th:action="@{/vote}" method="post">
<input id="voterName" type="hidden" name="name" th:value="${name}" />
<input type="text" placeholder="•" class="passInput" name="pass[]" maxlength="1" autocomplete="off" required pattern="\d{1}" autofocus>
<input type="text" placeholder="•" class="passInput" name="pass[]" maxlength="1" autocomplete="off" required pattern="\d{1}">
<input type="text" placeholder="•" class="passInput" name="pass[]" maxlength="1" autocomplete="off" required pattern="\d{1}">
<input type="text" placeholder="•" class="passInput" name="pass[]" maxlength="1" autocomplete="off" required pattern="\d{1}">
<input type="text" placeholder="•" class="passInput" name="pass[]" maxlength="1" autocomplete="off" required pattern="\d{1}">
<input type="text" placeholder="•" class="passInput" name="pass[]" maxlength="1" autocomplete="off" required pattern="\d{1}">
<button type="submit" id="signup_button">Abstimmen</button>
</form>
</body>
</html>

View File

@@ -18,22 +18,28 @@
<tr>
<th>Id</th>
<th>E-Mail</th>
<th>Vote status</th>
<th>Status</th>
</tr>
<tr th:each="voter : ${voters}">
<div th:if="${voter.candidatesubmit_status}">
<td class="submitted" th:text="${voter.id}"></td>
<td class="submitted" th:text="${voter.email}"></td>
<td class="submitted" th:text="Candidates submitted"></td>
</div>
<!-- If voter has voted -->
<div th:if="${voter.vote_status}">
<td class="voted" th:text="${voter.id}"></td>
<td class="voted" th:text="${voter.email}"></td>
<td class="voted" th:text="${voter.vote_status}"></td>
<td class="voted" th:text="Voted"></td>
</div>
<!-- ELSE -->
<div th:unless="${voter.vote_status}">
<td class="notVoted" th:text="${voter.id}"></td>
<td class="notVoted" th:text="${voter.email}"></td>
<td class="notVoted" th:text="${voter.vote_status}"></td>
<td class="notVoted" th:text="$Not voted"></td>
</tr>
</table>
</div>

View File

@@ -26,7 +26,7 @@
</script>
<div class="userLogin">
<form action="#" th:action="@{/vote}" method="post">
<form action="#" th:action="@{/checkStatus}" method="post">
<label for="email_input">
<span class="label-text">Adolfinum E-Mail</span>
</label>

View File

@@ -5,14 +5,14 @@
<meta charset="UTF-8">
<title>Title</title>
<link th:href="@{/styles/voting.css}" rel="stylesheet" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
</head>
<body class="center-screen">
<script>
function setColor(button) {
groupButtons = document.querySelectorAll('[id^= ' + button.id.split("_")[0] + ']');
groupButtons = document.querySelectorAll('[id^=' + button.id.split("_")[0] + ']');
groupButtons.forEach(button => {
button.style.background = 'transparent';
button.style.fontWeight = 'normal';
@@ -43,19 +43,48 @@
input = document.getElementById("voteValues");
input.value = voteIds;
}
var q = 1,
qMax = 0;
$(function() {
qMax = $('#votingButtons div.voteDiv').length;
$('#votingButtons div.voteDiv').hide();
$('#votingButtons div.voteDiv:nth-child(1)').show();
$('#btnNext').on('click', function(event) {
event.preventDefault();
handleClick();
});
});
function handleClick() {
if (q < qMax) {
$('#votingButtons div.voteDiv:nth-child(' + q + ')').hide();
$('#votingButtons div.voteDiv:nth-child(' + (q + 1) + ')').show();
if (q == (qMax - 1)) {
$('#btnNext').html('Submit Answers');
}
q++;
} else {
getVotes();
document.getElementById("myForm").submit();
}
}
</script>
<div class="centered">
<h1>Wähle deine Kandidaten:</h1>
<div th:each="category,iter : ${categories}">
<h2 class="categoryHeader" th:text="${category.name}"></h2>
<div th:each="candidate : ${category.candidateList}" class="voteDiv">
<button class="inputButton" th:id="|category${category.id}_candidate${candidate.id}|" th:text="${candidate.name}" th:onclick="|setColor(category${category.id}_candidate${candidate.id})|"></button>
<div id="votingButtons">
<div th:each="category,iter : ${categories}" class="voteDiv">
<h2 class="categoryHeader" th:text="${category.name}"></h2>
<div th:each="candidate : ${category.candidateList}">
<button class="inputButton" th:id="|category${category.id}_candidate${candidate.id}|" th:text="${candidate.name}" th:onclick="|setColor(category${category.id}_candidate${candidate.id})|"></button>
</div>
</div>
</div>
<form action="#" th:action="@{/processVote}" method="post">
<button class="submitButton" id="btnNext" type="submit">Nächste Frage</button>
<form action="#" th:action="@{/processVote}" method="post" id="myForm">
<input id="voteValues" type="hidden" name="voteValues" value="" />
<input id="voterName" type="hidden" name="voterEmail" th:value="${name}" />
<button type="submit" id="submitButton" onclick="getVotes()">Auswahl bestätigen</button>
<input id="voterName" type="hidden" name="name" th:value="${name}" />
</form>
</div>
</body>