From c80656abf09459c8b13c9cdb33c9a8d3a8cee502 Mon Sep 17 00:00:00 2001
From: LarsVomMars
Date: Fri, 2 Oct 2020 23:29:06 +0200
Subject: Added basic voting
---
app.js | 2 ++
db.js | 11 ++++++++++
mottos.txt | 10 +++++++++
mottovote/index.js | 21 +++++++++++++++++++
mottovote/public/index.html | 15 ++++++++++++++
mottovote/public/script.js | 49 +++++++++++++++++++++++++++++++++++++++++++++
tables.sql | 21 +++++++++++++------
7 files changed, 123 insertions(+), 6 deletions(-)
create mode 100644 mottos.txt
create mode 100644 mottovote/index.js
create mode 100644 mottovote/public/index.html
create mode 100644 mottovote/public/script.js
diff --git a/app.js b/app.js
index 23e2715..8200713 100644
--- a/app.js
+++ b/app.js
@@ -4,6 +4,7 @@ const session = require("express-session");
const { auth, checkUser } = require("./auth");
const motto = require("./motto");
+const mottovote = require("./mottovote");
const quotes = require("./quotes");
const poll = require("./poll");
@@ -28,6 +29,7 @@ app.use(express.json());
app.use("/", express.static(__dirname + "/overview/public"));
app.use("/motto", checkUser, motto);
+app.use("/mottovote", mottovote);
app.use("/quotes", checkUser, quotes);
app.use("/poll", checkUser, poll);
app.use("/auth", auth);
diff --git a/db.js b/db.js
index 58673bc..26e3d97 100644
--- a/db.js
+++ b/db.js
@@ -50,6 +50,17 @@ class DB {
});
});
+ fs.readFile(__dirname + "/mottos.txt", "utf8", (err, data) => {
+ if (err) throw err;
+
+ const mottos = data.split("\n");
+ mottos.forEach(async (motto) => {
+ const [name, desc] = motto.split(" - ");
+ if (motto)
+ await this.query("INSERT INTO motto_votes (name, description) VALUES (?, ?)", [name, desc]);
+ });
+ });
+
const classes = data.split("--");
const userPasswords = {};
console.log("Generating users");
diff --git a/mottos.txt b/mottos.txt
new file mode 100644
index 0000000..d0519da
--- /dev/null
+++ b/mottos.txt
@@ -0,0 +1,10 @@
+ABIsexuell - Offen für alles
+ABItamin - Der Stoff kam aus dem Lehrerzimmer
+KohlrABI - Wir machen uns vom Acker
+Suit up! It's gonnABI legendary! -
+Westminster ABI - Der Adel geht
+WubbalABIdubdub - { Rick and Morty }
+cannABIs - Mit einer Tüte fing alles an
+kABItalismus - 13 Jahre Klassenkampf
+kABItän blaubär - Immer blau und trotzdem schlau
+kokABIn - Wir haben die Nase voll
diff --git a/mottovote/index.js b/mottovote/index.js
new file mode 100644
index 0000000..4806e55
--- /dev/null
+++ b/mottovote/index.js
@@ -0,0 +1,21 @@
+const express = require("express");
+const db = require("../db");
+const { checkUser } = require("../auth");
+const app = express.Router();
+
+
+app.use("/", express.static(__dirname + "/public/"));
+
+app.get("/api/list", async (req, res) => {
+ const mottos = await db.query("SELECT id, name, description FROM motto_votes ORDER BY name, description");
+ res.json(mottos);
+});
+
+app.put("/api/vote", async (req, res) => {
+ for (const mid in req.body) {
+ await db.query("UPDATE motto_votes SET votes = votes + ? WHERE id = ?", [req.body[mid], mid]);
+ }
+ res.send("ok");
+});
+
+module.exports = app;
\ No newline at end of file
diff --git a/mottovote/public/index.html b/mottovote/public/index.html
new file mode 100644
index 0000000..27ea837
--- /dev/null
+++ b/mottovote/public/index.html
@@ -0,0 +1,15 @@
+
+
+
+
+
+ Motto Vote
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mottovote/public/script.js b/mottovote/public/script.js
new file mode 100644
index 0000000..7216af4
--- /dev/null
+++ b/mottovote/public/script.js
@@ -0,0 +1,49 @@
+get();
+
+async function get() {
+ const resp = await fetch("api/list");
+ const mottos = await resp.json();
+
+ for (const motto of mottos) {
+ const row = document.createElement("div");
+ const id = motto.id;
+
+ const cb = document.createElement("input");
+ cb.type = "checkbox";
+ cb.id = "motto" + id;
+ cb.name = id;
+
+ const label = document.createElement("label");
+ label.for = "motto" + id;
+ label.textContent = `${motto.name} ${motto.description ? "-" : ""} ${motto.description}`
+
+ row.append(cb, label);
+ window.vote.appendChild(row);
+ }
+ addListeners();
+}
+
+function addListeners() {
+ // Only allow 3 votes
+ const boxes = document.querySelectorAll("input[type=checkbox]");
+ boxes.forEach((box) => {
+ box.addEventListener("change", (evt) => {
+ const checkedSiblings = document.querySelectorAll("input[type=checkbox]:checked");
+ if (checkedSiblings.length > 3) evt.target.checked = false;
+ });
+ });
+
+ window.voteButton.addEventListener("click", async () => {
+ const checked = document.querySelectorAll("input[type=checkbox]:checked");
+ if (checked.length !== 3) return;
+ const req = {};
+ for (const box of checked) req[box.name] = 1; // Amount of votes
+ const resp = await fetch("api/vote", {
+ method: "PUT",
+ headers: { "Content-Type": "application/json" },
+ body: JSON.stringify(req),
+ });
+ console.log(await resp.text());
+
+ });
+}
\ No newline at end of file
diff --git a/tables.sql b/tables.sql
index 6161b03..ea86339 100644
--- a/tables.sql
+++ b/tables.sql
@@ -9,12 +9,13 @@ CREATE TABLE IF NOT EXISTS theme(
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- TODO: Remove dropping
-DROP TABLE IF EXISTS quotes;
-DROP TABLE IF EXISTS ranking_questions;
-DROP TABLE IF EXISTS ranking_answers;
-DROP TABLE IF EXISTS users;
-DROP TABLE IF EXISTS types;
-DROP TABLE IF EXISTS class;
+-- DROP TABLE IF EXISTS motto_votes;
+-- DROP TABLE IF EXISTS quotes;
+-- DROP TABLE IF EXISTS ranking_questions;
+-- DROP TABLE IF EXISTS ranking_answers;
+-- DROP TABLE IF EXISTS users;
+-- DROP TABLE IF EXISTS types;
+-- DROP TABLE IF EXISTS class;
CREATE TABLE IF NOT EXISTS types(
id INTEGER PRIMARY KEY AUTO_INCREMENT,
@@ -72,3 +73,11 @@ CREATE TABLE IF NOT EXISTS ranking_answers(
CONSTRAINT `fk_user_answer1` FOREIGN KEY (user_id) REFERENCES users (id),
CONSTRAINT `fk_user_answer2` FOREIGN KEY (answer_id) REFERENCES users (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+
+CREATE TABLE IF NOT EXISTS motto_votes(
+ id INTEGER PRIMARY KEY AUTO_INCREMENT,
+ name VARCHAR(255) NOT NULL,
+ description VARCHAR(255) NOT NULL DEFAULT '',
+ votes INTEGER DEFAULT 0
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
--
cgit v1.2.3
From 467eb283888328b977871b6899bede744cedfdd8 Mon Sep 17 00:00:00 2001
From: LarsVomMars
Date: Sat, 3 Oct 2020 00:41:10 +0200
Subject: Multivote
---
db.js | 2 +-
mottovote/index.js | 23 ++++++++++++++++-------
mottovote/public/script.js | 30 ++++++++++++++++--------------
tables.sql | 17 +++++++++++++++--
4 files changed, 48 insertions(+), 24 deletions(-)
diff --git a/db.js b/db.js
index 26e3d97..193daa8 100644
--- a/db.js
+++ b/db.js
@@ -57,7 +57,7 @@ class DB {
mottos.forEach(async (motto) => {
const [name, desc] = motto.split(" - ");
if (motto)
- await this.query("INSERT INTO motto_votes (name, description) VALUES (?, ?)", [name, desc]);
+ await this.query("INSERT INTO mottos (name, description) VALUES (?, ?)", [name, desc]);
});
});
diff --git a/mottovote/index.js b/mottovote/index.js
index 4806e55..e06f23c 100644
--- a/mottovote/index.js
+++ b/mottovote/index.js
@@ -4,18 +4,27 @@ const { checkUser } = require("../auth");
const app = express.Router();
-app.use("/", express.static(__dirname + "/public/"));
+app.use("/", checkUser, express.static(__dirname + "/public/"));
-app.get("/api/list", async (req, res) => {
- const mottos = await db.query("SELECT id, name, description FROM motto_votes ORDER BY name, description");
+app.get("/api/list", checkUser, async (req, res) => {
+ const mottos = await db.query("SELECT id, name, description FROM mottos ORDER BY name, description");
res.json(mottos);
});
-app.put("/api/vote", async (req, res) => {
- for (const mid in req.body) {
- await db.query("UPDATE motto_votes SET votes = votes + ? WHERE id = ?", [req.body[mid], mid]);
+app.put("/api/vote", checkUser, async (req, res) => {
+ await db.query("DELETE FROM motto_votes WHERE user_id = ?", [req.session.uid]);
+ try {
+ for (const mid in req.body) {
+ await db.query(
+ "INSERT INTO motto_votes (user_id, motto_id, votes) VALUES (?, ?, ?)",
+ [req.session.uid, mid, req.body[mid]]
+ );
+ }
+ res.send("ok");
+ } catch (e) {
+ console.error(e);
+ res.send("error");
}
- res.send("ok");
});
module.exports = app;
\ No newline at end of file
diff --git a/mottovote/public/script.js b/mottovote/public/script.js
index 7216af4..9fada2e 100644
--- a/mottovote/public/script.js
+++ b/mottovote/public/script.js
@@ -1,3 +1,4 @@
+const maxVotes = 3;
get();
async function get() {
@@ -7,17 +8,18 @@ async function get() {
for (const motto of mottos) {
const row = document.createElement("div");
const id = motto.id;
-
- const cb = document.createElement("input");
- cb.type = "checkbox";
- cb.id = "motto" + id;
- cb.name = id;
-
- const label = document.createElement("label");
- label.for = "motto" + id;
- label.textContent = `${motto.name} ${motto.description ? "-" : ""} ${motto.description}`
-
- row.append(cb, label);
+
+ for (let i = 0; i < maxVotes; i++) {
+ const cb = document.createElement("input");
+ cb.type = "checkbox";
+ cb.name = id;
+ row.append(cb);
+ }
+
+ const text = document.createElement("span");
+ text.textContent = `${motto.name} ${motto.description ? "-" : ""} ${motto.description}`
+
+ row.append(text);
window.vote.appendChild(row);
}
addListeners();
@@ -29,15 +31,15 @@ function addListeners() {
boxes.forEach((box) => {
box.addEventListener("change", (evt) => {
const checkedSiblings = document.querySelectorAll("input[type=checkbox]:checked");
- if (checkedSiblings.length > 3) evt.target.checked = false;
+ if (checkedSiblings.length > maxVotes) evt.target.checked = false;
});
});
window.voteButton.addEventListener("click", async () => {
const checked = document.querySelectorAll("input[type=checkbox]:checked");
- if (checked.length !== 3) return;
+ if (checked.length > maxVotes) return; // Shouldn't be necessary
const req = {};
- for (const box of checked) req[box.name] = 1; // Amount of votes
+ for (const box of checked) req[box.name] = box.name in req ? req[box.name] + 1 : 1; // Amount of votes
const resp = await fetch("api/vote", {
method: "PUT",
headers: { "Content-Type": "application/json" },
diff --git a/tables.sql b/tables.sql
index ea86339..e630058 100644
--- a/tables.sql
+++ b/tables.sql
@@ -10,6 +10,7 @@ CREATE TABLE IF NOT EXISTS theme(
-- TODO: Remove dropping
-- DROP TABLE IF EXISTS motto_votes;
+-- DROP TABLE IF EXISTS mottos;
-- DROP TABLE IF EXISTS quotes;
-- DROP TABLE IF EXISTS ranking_questions;
-- DROP TABLE IF EXISTS ranking_answers;
@@ -75,9 +76,21 @@ CREATE TABLE IF NOT EXISTS ranking_answers(
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-CREATE TABLE IF NOT EXISTS motto_votes(
+CREATE TABLE IF NOT EXISTS mottos(
id INTEGER PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(255) NOT NULL,
description VARCHAR(255) NOT NULL DEFAULT '',
- votes INTEGER DEFAULT 0
+
+ UNIQUE KEY main (name, description)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+CREATE TABLE IF NOT EXISTS motto_votes(
+ id INTEGER PRIMARY KEY AUTO_INCREMENT,
+ user_id INTEGER NOT NULL,
+ motto_id INTEGER NOT NULL,
+ votes SMALLINT UNSIGNED NOT NULL DEFAULT 0,
+
+ UNIQUE KEY uk_vote (user_id, motto_id),
+ CONSTRAINT `fk_voted_user` FOREIGN KEY (user_id) REFERENCES users (id),
+ CONSTRAINT `fk_voted_vote` FOREIGN KEY (motto_id) REFERENCES mottos (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
--
cgit v1.2.3
From 7639f176abe404cad1a3c9a3b8e2b4918b86087e Mon Sep 17 00:00:00 2001
From: LarsVomMars
Date: Sat, 3 Oct 2020 11:31:04 +0200
Subject: Store/change selected votes
---
auth/index.js | 2 ++
mottovote/index.js | 8 +++++++-
mottovote/public/script.js | 1 +
3 files changed, 10 insertions(+), 1 deletion(-)
diff --git a/auth/index.js b/auth/index.js
index 0891fc5..0bcbdf5 100644
--- a/auth/index.js
+++ b/auth/index.js
@@ -37,6 +37,8 @@ app.post("/api/login", async (req, res) => {
res.redirect("/auth");
});
+app.use("/api/logout", (req, res) => req.session.destroy() & res.redirect("/"));
+
app.put("/api/password", checkUser, async (req, res) => {
const { pwd, newPwd } = req.body;
if (!(pwd && newPwd)) return res.redirect("/auth");
diff --git a/mottovote/index.js b/mottovote/index.js
index e06f23c..a485a8b 100644
--- a/mottovote/index.js
+++ b/mottovote/index.js
@@ -7,7 +7,13 @@ const app = express.Router();
app.use("/", checkUser, express.static(__dirname + "/public/"));
app.get("/api/list", checkUser, async (req, res) => {
- const mottos = await db.query("SELECT id, name, description FROM mottos ORDER BY name, description");
+ const mottos = await db.query("SELECT id, name, description FROM mottos");
+ const votes = await db.query("SELECT motto_id, votes FROM motto_votes WHERE user_id = ?", [req.session.uid]);
+
+ for (const vote of votes) {
+ const mid = mottos.findIndex((motto) => motto.id === vote.motto_id);
+ if (mid) mottos[mid].votes = vote.votes;
+ }
res.json(mottos);
});
diff --git a/mottovote/public/script.js b/mottovote/public/script.js
index 9fada2e..338b26b 100644
--- a/mottovote/public/script.js
+++ b/mottovote/public/script.js
@@ -13,6 +13,7 @@ async function get() {
const cb = document.createElement("input");
cb.type = "checkbox";
cb.name = id;
+ cb.checked = motto.votes && motto.votes-- > 0
row.append(cb);
}
--
cgit v1.2.3
From 30dd80aa4e7310c3f7958f2db261233583ded909 Mon Sep 17 00:00:00 2001
From: LarsVomMars
Date: Sat, 3 Oct 2020 12:14:33 +0200
Subject: Style
---
mottovote/index.js | 7 ++++++
mottovote/public/index.html | 12 ++++++++--
mottovote/public/script.js | 4 ++--
mottovote/public/style.css | 55 +++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 74 insertions(+), 4 deletions(-)
create mode 100644 mottovote/public/style.css
diff --git a/mottovote/index.js b/mottovote/index.js
index a485a8b..d22ba29 100644
--- a/mottovote/index.js
+++ b/mottovote/index.js
@@ -20,6 +20,7 @@ app.get("/api/list", checkUser, async (req, res) => {
app.put("/api/vote", checkUser, async (req, res) => {
await db.query("DELETE FROM motto_votes WHERE user_id = ?", [req.session.uid]);
try {
+ if (req.body.entries().length > 3) return res.send("error");
for (const mid in req.body) {
await db.query(
"INSERT INTO motto_votes (user_id, motto_id, votes) VALUES (?, ?, ?)",
@@ -33,4 +34,10 @@ app.put("/api/vote", checkUser, async (req, res) => {
}
});
+// Vote result - admin
+app.get("/api/get", checkUser, async (req, res) => {
+ const votes = await db.query("SELECT m.id, m.name, m.description, SUM(votes) votes FROM motto_votes mv RIGHT JOIN mottos m on mv.motto_id = m.id GROUP BY m.id, m.name, m.description ORDER BY SUM(votes) DESC");
+ res.json(votes);
+});
+
module.exports = app;
\ No newline at end of file
diff --git a/mottovote/public/index.html b/mottovote/public/index.html
index 27ea837..4e64cb8 100644
--- a/mottovote/public/index.html
+++ b/mottovote/public/index.html
@@ -1,15 +1,23 @@
+
Motto Vote
+
+
+
-
-
+
+
+
+
+
\ No newline at end of file
diff --git a/mottovote/public/script.js b/mottovote/public/script.js
index 338b26b..c8432c5 100644
--- a/mottovote/public/script.js
+++ b/mottovote/public/script.js
@@ -12,7 +12,7 @@ async function get() {
for (let i = 0; i < maxVotes; i++) {
const cb = document.createElement("input");
cb.type = "checkbox";
- cb.name = id;
+ cb.value = id;
cb.checked = motto.votes && motto.votes-- > 0
row.append(cb);
}
@@ -40,7 +40,7 @@ function addListeners() {
const checked = document.querySelectorAll("input[type=checkbox]:checked");
if (checked.length > maxVotes) return; // Shouldn't be necessary
const req = {};
- for (const box of checked) req[box.name] = box.name in req ? req[box.name] + 1 : 1; // Amount of votes
+ for (const box of checked) req[box.value] = box.value in req ? req[box.value] + 1 : 1; // Amount of votes
const resp = await fetch("api/vote", {
method: "PUT",
headers: { "Content-Type": "application/json" },
diff --git a/mottovote/public/style.css b/mottovote/public/style.css
new file mode 100644
index 0000000..bf4eac7
--- /dev/null
+++ b/mottovote/public/style.css
@@ -0,0 +1,55 @@
+html,
+body {
+ padding: 0;
+ margin: 0;
+ height: 100%;
+ width: 100%;
+ background-color: #eec0c6;
+ background-image: linear-gradient(315deg, #eec0c6 0%, #7ee8fa 74%);
+}
+
+main {
+ display: flex;
+ flex-flow: row wrap;
+ position: absolute;
+ height: 40%;
+ width: 50%;
+ left: 50%;
+ top: 50%;
+ -webkit-transform: translate(-50%, -50%);
+ transform: translate(-50%, -50%);
+ padding: 20px;
+ border-radius: 10px;
+ background: white;
+}
+
+#voteButton {
+ height: 10%;
+}
+
+#vote {
+ margin-bottom: 20px;
+ overflow-y: scroll;
+ width: 100%;
+}
+
+#vote div {
+ padding: 5px;
+ display: flex;
+ align-items: center;
+}
+
+#vote div input {
+ margin-right: 5px;
+}
+
+button,
+select {
+ width: 100%;
+}
+
+@media only screen and (max-width: 600px) {
+ div {
+ width: calc(100% - 50px);
+ }
+}
--
cgit v1.2.3
From e5a757786f632ef15aae7f4010e120d5479b869b Mon Sep 17 00:00:00 2001
From: LarsVomMars
Date: Sat, 3 Oct 2020 12:19:18 +0200
Subject: Fixes
---
mottovote/index.js | 2 +-
mottovote/public/script.js | 5 +++--
2 files changed, 4 insertions(+), 3 deletions(-)
diff --git a/mottovote/index.js b/mottovote/index.js
index d22ba29..df1f6a4 100644
--- a/mottovote/index.js
+++ b/mottovote/index.js
@@ -20,7 +20,7 @@ app.get("/api/list", checkUser, async (req, res) => {
app.put("/api/vote", checkUser, async (req, res) => {
await db.query("DELETE FROM motto_votes WHERE user_id = ?", [req.session.uid]);
try {
- if (req.body.entries().length > 3) return res.send("error");
+ if (Object.keys(req.body).length > 3) return res.send("error");
for (const mid in req.body) {
await db.query(
"INSERT INTO motto_votes (user_id, motto_id, votes) VALUES (?, ?, ?)",
diff --git a/mottovote/public/script.js b/mottovote/public/script.js
index c8432c5..05ca940 100644
--- a/mottovote/public/script.js
+++ b/mottovote/public/script.js
@@ -46,7 +46,8 @@ function addListeners() {
headers: { "Content-Type": "application/json" },
body: JSON.stringify(req),
});
- console.log(await resp.text());
-
+ const res = await resp.text();
+ if (res === "ok") location.reload();
+ else alert(res);
});
}
\ No newline at end of file
--
cgit v1.2.3