added password

This commit is contained in:
silas 2021-04-01 13:06:29 +02:00
parent c5161fb1df
commit e3e60bfcf6
7 changed files with 188 additions and 123 deletions

8
dist/bundle.js vendored

File diff suppressed because one or more lines are too long

View File

@ -1 +1,4 @@
CREATE TABLE presents (id int(11) NOT NULL PRIMARY KEY, version int(11) NOT NULL, isBought tinyint(1) NOT NULL)
CREATE TABLE presents (id int(11) NOT NULL PRIMARY KEY, version int(11) NOT NULL, isBought tinyint(1) NOT NULL)
---
ALTER TABLE presents ADD COLUMN password varchar(127) NOT NULL DEFAULT '';

View File

@ -8,9 +8,9 @@
ihr euch unten in der Liste etwas ausgesucht habt, dann setzt dort gerne einen Haken. Wenn ihr auf ein Bild
klickt, öffnet sich direkt der passende Link dazu.
</p>
<p>
Diese Liste wird sich in den nächsten Wochen noch füllen. Schaut gerne noch mal vorbei!
</p>
<!-- <p>-->
<!-- Diese Liste wird sich in den nächsten Wochen noch füllen. Schaut gerne noch mal vorbei!-->
<!-- </p>-->
<div id="present-container">
<a id="present-template" class="flex-container present" target="_blank">
<div class="present-checkbox">

View File

@ -1,11 +1,13 @@
<div class="site-content grid-container">
<h1>Herzlich Willkommen</h1>
<p>Wir heiraten! Und das möchten wir mit euch gemeinsam am 8.Mai 2021 in Aachen feiern.
Bitte sagt uns doch bis zum 15.März, ob ihr dabei sein könnt! Schreibt uns dazu bitte eine Mail an <a href = 'mailto:hochzeit-js@gmx.net'>hochzeit-js@gmx.net</a>.</p>
<p>Wir heiraten! Und das möchten wir mit euch gemeinsam in Aachen feiern.
Leider müssen wir jedoch wegen der Corona Pandemie unsere kirchliche
Hochzeit um ein Jahr verschieben. Standesamtlich heiraten wir natürlich
trotzdem am 24.April in Betzdorf (Sieg) und sind glücklich darüber bald
gemeinsam in die Ehe zu starten. Wir freuen uns schon sehr darauf, nächstes Jahr
unseren Hochzeitsgottesdienst und eine große Party mit euch zu feiern
und melden uns, sobald der neue Hochzeitstermin feststeht.
</p>
<p>Natürlich können wir unsere Einladung für nächstes Jahr nicht aussprechen, ohne ein paar Worte zu der aktuellen
Corona Pandemie zu verlieren. Wir hoffen sehr, dass sich die Lage bis Mai soweit beruhigt hat, dass wir unsere
Hochzeit mit euch allen feiern können. Leider ist das aber momentan sehr ungewiss. Soweit es geht, planen wir
damit, dass wir am 8. Mai gemeinsam feiern, falls sich daran etwas ändert, melden wir uns bei euch. Sagt uns
gerne trotzdem bis zum 15.März zu, damit wir besser planen können!</p>
</div>
<p>Falls ihr Fragen habt, meldet euch gerne unter <a href = 'mailto:hochzeit-js@gmx.net'>hochzeit-js@gmx.net</a></p>
</div>

View File

@ -7,32 +7,33 @@ export class PresentsHandler {
image: string,
name: string,
description: string
link: string
link: string,
isMine?: boolean,
}
} = {};
password: string;
// @ts-ignore
private readonly basePath = __BASE_PATH__;
async loadPresents() {
const presents = require("./presents").default;
presents.forEach(p => this.presents[p.id] = p);
this.password = localStorage.getItem("pw") || "";
await this.updateStates();
}
async updateStates() {
const presentData: any[] = await fetch(this.basePath + "/presents", {
"credentials": "same-origin",
"method": "GET",
}).then(function (res) {
return res.json();
});
const presentData: any[] = await this.send(this.basePath + "/presents", {password: this.password});
presentData.forEach(data => {
const present = this.presents[data.id];
if (present){
if (present) {
present.isBought = data.isBought === 1;
present.version = data.version;
present.isMine = data.isMine === true
}
})
}
@ -60,6 +61,19 @@ export class PresentsHandler {
checkboxElement.addEventListener("click", async e => {
e.preventDefault();
if (!this.password || (present.isBought && !present.isMine)){
const pw = prompt("Bitte gib ein Passwort ein. Das brauchst du, wenn du das Geschenk wieder bearbeitest:")
if (pw){
this.password = pw;
localStorage.setItem("pw", pw);
}
else {
alert("Du brauchst ein Passwort.");
return;
}
}
await this.setPresentIsBought(present, !present.isBought);
if (present.isBought) {
checkboxElement.classList.add("checked");
@ -72,28 +86,46 @@ export class PresentsHandler {
})
}
private async setPresentIsBought(present: { id: number, isBought: boolean; version: number, image: string; name: string; description: string; link: string }, isBought: boolean) {
const url = this.basePath + "/presents"
private async setPresentIsBought(present: {
id: number,
isBought: boolean;
version: number,
image: string;
name: string;
description: string;
link: string,
isMine?: boolean
}, isBought: boolean) {
const url = this.basePath + "/setPresent"
const params = {
id: present.id,
version: present.version,
isBought: isBought
isBought: isBought,
password: this.password
}
const res = await this.send(url, params);
console.log("result", res);
if (res.present && res.present.id === present.id) {
present.version = res.present.version;
present.isBought = res.present.isBought === 1
if (present.isBought){
present.isMine = true;
}
}
if (res.success === false) {
if (res.error === "wrong-version") {
alert("Jemand hat schon vor dir das Geschenk bearbeitet. Bitte versuche es erneut.")
}
else if (res.error === "wrong-password"){
alert("Das Passwort, was du angegeben hast, stimmt nicht.")
present.isMine = false;
}
else if (res.error === "no-password"){
alert("Bitte gib ein Passwort an.")
}
}
}
@ -124,4 +156,4 @@ export class PresentsHandler {
}
});
}
}
}

View File

@ -47,61 +47,56 @@ export default [{
description: "Wir freuen uns immer über ein neues, spannendes Brettspiel. Falls ihr sichergehen wollt, welche Spiele wir schon haben, fragt doch unsere Trauzeugen Sinah oder Miriam.",
link: "",
version: 0,
}, {
id: 7,
isBought: false,
image: require("../img/geschenke/Zahnbürste.png").default,
name: "Elektrische Pärchenzahn-bürste",
description: "Nachhaltige elektrische Zahnbürste von happy brush, SCHALL VIBE 3 Partner Bundle",
link: "https://www.happybrush.de/starterkit-vibe-3-schall-zahnbuerste-bundle-mix/",
version: 0,
}, {
id: 8,
isBought: false,
image: require("../img/geschenke/Kappsäge.png").default,
name: "Kappsäge",
description: "Einhell Kapp-/Gehrungssäge TC-MS 2112 (1600 W, Sägeblatt Ø 210 mm, Schnittbreite 120 mm, schwenkbarer Sägekopf)",
link: "https://www.amazon.de/dp/B00DEXXFMK",
version: 0,
}, {
id: 9,
isBought: false,
image: require("../img/geschenke/Akkuschrauber.png").default,
name: "Akku-schrauber",
description: "LUX Akku-Bohrschrauber-Set inkl. Akku (wie im Link oder ähnlich)",
link: "https://www.obi.de/akkuschrauber/lux-akku-bohrschrauber-set-1-powersystem-a-bs-20/p/9543208",
version: 0,
}, {
id: 10,
isBought: false,
image: require("../img/geschenke/BodumBrotbox.jpg").default,
name: "Bodum Brotbox",
description: "Bodum bistroBrotkasten mit Bambus-Schneidebrett, 23.81 x 37.15 x 14.29 cm; 1.11 Kilogramm",
link: "https://www.amazon.de/Bodum-bistroBrotkasten-Bambus-Schneidebrett-BPA-freier-Kunststoff/dp/B00MAPNVCW/",
version: 0,
}, {
id: 11,
isBought: false,
image: require("../img/geschenke/großer_Topf.png").default,
name: "Großer Kochtopf",
description: "Tefal A70546 Duetto, ein großer Kochtopf, der circa 5l fasst (wie im Link oder ähnlich)",
link: "https://www.amazon.de/dp/B00V6GF7UU/",
version: 0,
},
{
id: 7,
isBought: false,
image: require("../img/geschenke/Zahnbürste.png").default,
name: "Elektrische Pärchenzahn-bürste",
description: "Nachhaltige elektrische Zahnbürste von happy brush, SCHALL VIBE 3 Partner Bundle",
link: "https://www.happybrush.de/starterkit-vibe-3-schall-zahnbuerste-bundle-mix/",
version: 0,
},
{
id: 8,
isBought: false,
image: require("../img/geschenke/Kappsäge.png").default,
name: "Kappsäge",
description: "Einhell Kapp-/Gehrungssäge TC-MS 2112 (1600 W, Sägeblatt Ø 210 mm, Schnittbreite 120 mm, schwenkbarer Sägekopf)",
link: "https://www.amazon.de/dp/B00DEXXFMK",
version: 0,
},
{
id: 9,
isBought: false,
image: require("../img/geschenke/Akkuschrauber.png").default,
name: "Akku-schrauber",
description: "LUX Akku-Bohrschrauber-Set inkl. Akku (wie im Link oder ähnlich)",
link: "https://www.obi.de/akkuschrauber/lux-akku-bohrschrauber-set-1-powersystem-a-bs-20/p/9543208",
version: 0,
},
{
id: 10,
isBought: false,
image: require("../img/geschenke/BodumBrotbox.jpg").default,
name: "Bodum Brotbox",
description: "Bodum bistroBrotkasten mit Bambus-Schneidebrett, 23.81 x 37.15 x 14.29 cm; 1.11 Kilogramm",
link: "https://www.amazon.de/Bodum-bistroBrotkasten-Bambus-Schneidebrett-BPA-freier-Kunststoff/dp/B00MAPNVCW/",
version: 0,
},
{
id: 11,
isBought: false,
image: require("../img/geschenke/großer_Topf.png").default,
name: "Großer Kochtopf",
description: "Tefal A70546 Duetto, ein großer Kochtopf, der circa 5l fasst (wie im Link oder ähnlich)",
link: "https://www.amazon.de/dp/B00V6GF7UU/",
version: 0,
},
// {
// id: 12,
// isBought: false,
// image: require("../img/geschenke/Ligretto.png").default,
// name: "Ligretto in rot",
// description: "Ligretto in rot, um mit acht Leuten spielen zu können",
// link: "https://www.thalia.de/shop/home/artikeldetails/ID5130805.html",
// version: 0,
// },
// {
// id: 12,
// isBought: false,
// image: require("../img/geschenke/Ligretto.png").default,
// name: "Ligretto in rot",
// description: "Ligretto in rot, um mit acht Leuten spielen zu können",
// link: "https://www.thalia.de/shop/home/artikeldetails/ID5130805.html",
// version: 0,
// },
{
id: 13,
isBought: false,
@ -110,8 +105,7 @@ export default [{
description: "MacArthur Studienbibel mit Schlachter 2000 Übersetzung",
link: "https://www.scm-shop.de/macarthur-studienbibel-schlachter-2000-7485697.html",
version: 0,
},
{
}, {
id: 14,
isBought: false,
image: require("../img/geschenke/nudelholz.png").default,
@ -119,8 +113,7 @@ export default [{
description: "Eine Teigrolle aus Holz (wie im Link oder ähnlich)",
link: "https://shop.oetker.at/dr-oetker-teigroller-holz",
version: 0,
},
{
}, {
id: 15,
isBought: false,
image: require("../img/geschenke/suppenkelle.png").default,
@ -128,8 +121,7 @@ export default [{
description: "Eine Suppenkelle/ Schöpflöffel mit Ausguss",
link: "https://www.fackelmann.de/fackelmann-ovalgriff-schoepfloeffel-29cm",
version: 0,
},
{
}, {
id: 16,
isBought: false,
image: require("../img/geschenke/pizzaschneider.png").default,
@ -137,8 +129,7 @@ export default [{
description: "Ein Fahrrad Pizzaschneider",
link: "https://www.amazon.de/s?k=Fahrrad+Pizzaschneider&i=kitchen&__mk_de_DE=%C3%85M%C3%85%C5%BD%C3%95%C3%91",
version: 0,
},
{
}, {
id: 17,
isBought: false,
image: require("../img/geschenke/teekasten.png").default,
@ -146,8 +137,7 @@ export default [{
description: "Eine Teebox mit genügend Platz für viele Teebeutel (wie im Link oder ähnlich)",
link: "https://www.amazon.de/dp/B002P9JK4Q?tag=teebox-best-21",
version: 0,
},
{
}, {
id: 18,
isBought: false,
image: require("../img/geschenke/backblech.png").default,
@ -155,8 +145,7 @@ export default [{
description: "Ein Backblech mit passender Kuchenhaube (wie im Link oder ähnlich)",
link: "https://www.real.de/product/309417147/",
version: 0,
},
{
}, {
id: 19,
isBought: false,
image: require("../img/geschenke/zimmerpflanze.png").default,

View File

@ -34,31 +34,32 @@ export class Server {
// this.handleSocketConnection();
}
private async query(sql): Promise<any[]> {
private async query(sql, params?): Promise<any[]> {
return new Promise((resolve, reject) => {
try {
params = params || [];
console.log("[LOG:DO_QUERY]", sql, params);
if (!this.mysqlConnection || (this.mysqlConnection.state !== "connected" && this.mysqlConnection.state !== "authenticated")) {
console.log("reopening connection...");
this.mysqlConnection = mysql.createConnection({
host: process.env.MYSQL_HOST || "localhost",
user: process.env.MYSQL_USER || "root",
password: process.env.MYSQL_PASSWORD || "",
database: process.env.MYSQL_DATABASE || "hochzeit"
});
if (!this.mysqlConnection || this.mysqlConnection.state === "disconnected"){
console.log("reopening connection...");
this.mysqlConnection = mysql.createConnection({
host: process.env.MYSQL_HOST || "localhost",
user: process.env.MYSQL_USER || "root",
password: process.env.MYSQL_PASSWORD || "",
database: process.env.MYSQL_DATABASE || "hochzeit"
});
// setTimeout(() => {
// this.mysqlConnection.destroy();
// }, 5000);
}
}catch(e){
// setTimeout(() => {
// this.mysqlConnection.destroy();
// }, 5000);
}
} catch (e) {
console.error(e);
reject(e);
}
this.mysqlConnection.query(sql, (error, results) => {
this.mysqlConnection.query(sql, params, (error, results) => {
if (error) {
console.error(error);
console.error("Error for query", '"' + sql + '"\n', error);
reject(error)
} else {
resolve(results);
@ -67,6 +68,16 @@ export class Server {
})
}
private static preparePresent(present, password?) {
if (present.password) {
if (password && password === present.password) {
present.isMine = true;
}
delete present.password;
}
return present;
}
private configureApp(): void {
this.app.use(express.json({limit: "1mb"}));
this.app.use(express.static(path.join(__dirname, "../../dist")));
@ -76,28 +87,56 @@ export class Server {
this.app.get("/", (req, res) => {
res.sendFile("index.html");
});
this.app.get("/presents", async (req, res) => {
res.json(await this.query("SELECT * FROM presents"));
})
this.app.post("/presents", async (req, res) => {
res.json((await this.query("SELECT * FROM presents")).map(p => Server.preparePresent(p, req.body.password)));
})
this.app.post("/setPresent", async (req, res) => {
const id = parseInt(req.body.id);
const isBought = (req.body.isBought === true)?1:0;
const isBought = (req.body.isBought === true) ? 1 : 0;
const version = parseInt(req.body.version) || 0;
const newVersion = version + 1;
const password = req.body.password;
const presents = await this.query("SELECT * FROM presents WHERE id = '" + id + "'");
const presents = await this.query("SELECT * FROM presents WHERE id = ?", [id]);
if (presents.length === 0) {
await this.query("INSERT INTO presents (id, isBought, version) VALUES (" + id + ", " + isBought + ", " + newVersion + ");");
if (password) {
await this.query("INSERT INTO presents (id, isBought, version, password) VALUES (?, ?, ?, ?);", [id, isBought, newVersion, password]);
} else {
return res.json({
"success": false,
"error": "no-password",
});
}
} else {
const present = presents[0];
if (present.version === version) {
await this.query("UPDATE presents SET version = " + newVersion + ", isBought = " + isBought + " WHERE ID = " + id);
if (present.isBought === 1) {
if (present.password !== "" && present.password !== password) {
return res.json({
"success": false,
"error": "wrong-password",
present: Server.preparePresent(present, password)
});
}
}
const newPassword = (isBought === 1 ? password : "");
if (isBought && !password) {
return res.json({
"success": false,
"error": "no-password",
});
}
await this.query("UPDATE presents SET version = ?, isBought = ?, password = ? WHERE ID = ?", [newVersion, isBought, newPassword, id]);
} else {
return res.json({"success": false, "error": "wrong-version", present: present});
return res.json({
"success": false,
"error": "wrong-version",
present: Server.preparePresent(present, password)
});
}
}
return res.json({"success": true, present: {id: id, isBought: isBought, version: newVersion}})
})
return res.json({"success": true, present: {id: id, isBought: isBought, version: newVersion, isMine: true}})
});
}
public listen(callback: (port: number) => void): void {