From e83766309aca671fff6901bb16fda695b493aabe Mon Sep 17 00:00:00 2001 From: Wolvan Date: Wed, 29 Dec 2021 18:21:22 +0100 Subject: [PATCH] First steps towards functional frontend Polls and their results can now be accessed as long as they are found on the backend. --- frontend/html/poll.html | 13 ++++ frontend/html/result.html | 13 ++++ package-lock.json | 152 ++++++++++++++++++++++++++++++++++++++ package.json | 2 + src/Poll.ts | 34 +++++++++ src/backend.ts | 14 +--- src/frontend.ts | 33 ++++++++- 7 files changed, 246 insertions(+), 15 deletions(-) create mode 100644 frontend/html/poll.html create mode 100644 frontend/html/result.html create mode 100644 src/Poll.ts diff --git a/frontend/html/poll.html b/frontend/html/poll.html new file mode 100644 index 0000000..13b5dfa --- /dev/null +++ b/frontend/html/poll.html @@ -0,0 +1,13 @@ + + + + + + {{ TITLE }} + + + +

Welcome to poll.horse!

+

{{ POLL_TITLE }}

+ + \ No newline at end of file diff --git a/frontend/html/result.html b/frontend/html/result.html new file mode 100644 index 0000000..326adec --- /dev/null +++ b/frontend/html/result.html @@ -0,0 +1,13 @@ + + + + + + {{ TITLE }} + + + +

Welcome to poll.horse!

+

{{ POLL_TITLE }} - Result

+ + \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 384041e..0e89ea7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,6 +13,7 @@ "compression": "^1.7.4", "cookie-parser": "^1.4.6", "express": "^4.17.2", + "node-fetch": "^2.6.6", "node-persist": "^3.1.0" }, "devDependencies": { @@ -24,6 +25,7 @@ "@types/fs-extra": "^9.0.13", "@types/mocha": "^9.0.0", "@types/node": "^16.11.10", + "@types/node-fetch": "^2.5.12", "@types/node-persist": "^3.1.2", "@typescript-eslint/eslint-plugin": "^5.4.0", "@typescript-eslint/parser": "^5.4.0", @@ -268,6 +270,16 @@ "integrity": "sha512-3aRnHa1KlOEEhJ6+CvyHKK5vE9BcLGjtUpwvqYLRvYNQKMfabu3BwfJaA/SLW8dxe28LsNDjtHwePTuzn3gmOA==", "dev": true }, + "node_modules/@types/node-fetch": { + "version": "2.5.12", + "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.5.12.tgz", + "integrity": "sha512-MKgC4dlq4kKNa/mYrwpKfzQMB5X3ee5U6fSprkKpToBqBmX4nFZL9cW5jl6sWn+xpRJ7ypWh2yyqqr8UUCstSw==", + "dev": true, + "dependencies": { + "@types/node": "*", + "form-data": "^3.0.0" + } + }, "node_modules/@types/node-persist": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/@types/node-persist/-/node-persist-3.1.2.tgz", @@ -632,6 +644,12 @@ "node": "*" } }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "dev": true + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -853,6 +871,18 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/commander": { "version": "8.3.0", "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", @@ -1032,6 +1062,15 @@ "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/depd": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", @@ -1537,6 +1576,20 @@ "integrity": "sha512-8/sOawo8tJ4QOBX8YlQBMxL8+RLZfxMQOif9o0KUKTNTjMYElWPE0r/m5VNFxTRd0NSw8qSy8dajrwX4RYI1Hw==", "dev": true }, + "node_modules/form-data": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", + "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", + "dev": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -2198,6 +2251,17 @@ "node": ">= 0.6" } }, + "node_modules/node-fetch": { + "version": "2.6.6", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.6.tgz", + "integrity": "sha512-Z8/6vRlTUChSdIgMa51jxQ4lrw/Jy5SOW10ObaA47/RElsAN2c5Pn8bTgFGWn/ibwzXTE8qwr1Yzx28vsecXEA==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + } + }, "node_modules/node-persist": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/node-persist/-/node-persist-3.1.0.tgz", @@ -2791,6 +2855,11 @@ "node": ">=0.6" } }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=" + }, "node_modules/ts-node": { "version": "10.4.0", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.4.0.tgz", @@ -2968,6 +3037,20 @@ "node": ">= 0.8" } }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -3308,6 +3391,16 @@ "integrity": "sha512-3aRnHa1KlOEEhJ6+CvyHKK5vE9BcLGjtUpwvqYLRvYNQKMfabu3BwfJaA/SLW8dxe28LsNDjtHwePTuzn3gmOA==", "dev": true }, + "@types/node-fetch": { + "version": "2.5.12", + "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.5.12.tgz", + "integrity": "sha512-MKgC4dlq4kKNa/mYrwpKfzQMB5X3ee5U6fSprkKpToBqBmX4nFZL9cW5jl6sWn+xpRJ7ypWh2yyqqr8UUCstSw==", + "dev": true, + "requires": { + "@types/node": "*", + "form-data": "^3.0.0" + } + }, "@types/node-persist": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/@types/node-persist/-/node-persist-3.1.2.tgz", @@ -3554,6 +3647,12 @@ "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", "dev": true }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "dev": true + }, "balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -3732,6 +3831,15 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "requires": { + "delayed-stream": "~1.0.0" + } + }, "commander": { "version": "8.3.0", "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", @@ -3869,6 +3977,12 @@ "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "dev": true + }, "depd": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", @@ -4269,6 +4383,17 @@ "integrity": "sha512-8/sOawo8tJ4QOBX8YlQBMxL8+RLZfxMQOif9o0KUKTNTjMYElWPE0r/m5VNFxTRd0NSw8qSy8dajrwX4RYI1Hw==", "dev": true }, + "form-data": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", + "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", + "dev": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + } + }, "forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -4749,6 +4874,14 @@ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" }, + "node-fetch": { + "version": "2.6.6", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.6.tgz", + "integrity": "sha512-Z8/6vRlTUChSdIgMa51jxQ4lrw/Jy5SOW10ObaA47/RElsAN2c5Pn8bTgFGWn/ibwzXTE8qwr1Yzx28vsecXEA==", + "requires": { + "whatwg-url": "^5.0.0" + } + }, "node-persist": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/node-persist/-/node-persist-3.1.0.tgz", @@ -5156,6 +5289,11 @@ "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==" }, + "tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=" + }, "ts-node": { "version": "10.4.0", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.4.0.tgz", @@ -5271,6 +5409,20 @@ "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" }, + "webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=" + }, + "whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", + "requires": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", diff --git a/package.json b/package.json index f858101..f294bc4 100644 --- a/package.json +++ b/package.json @@ -40,6 +40,7 @@ "@types/fs-extra": "^9.0.13", "@types/mocha": "^9.0.0", "@types/node": "^16.11.10", + "@types/node-fetch": "^2.5.12", "@types/node-persist": "^3.1.2", "@typescript-eslint/eslint-plugin": "^5.4.0", "@typescript-eslint/parser": "^5.4.0", @@ -60,6 +61,7 @@ "compression": "^1.7.4", "cookie-parser": "^1.4.6", "express": "^4.17.2", + "node-fetch": "^2.6.6", "node-persist": "^3.1.0" } } diff --git a/src/Poll.ts b/src/Poll.ts new file mode 100644 index 0000000..33ab9bb --- /dev/null +++ b/src/Poll.ts @@ -0,0 +1,34 @@ +"use strict"; + +type BasePoll = { + id: string, + title: string, + dupeCheckMode: "none" | "ip" | "cookie", + multiSelect: boolean, + captcha: boolean, + creationTime: Date, +}; +type FrontendPoll = BasePoll & { + options: string[], + error?: string, +}; +type BackendPoll = BasePoll & { + options: { + [option: string]: number + }, + dupeData: null | string[] | string +}; +type PollResult = { + title: string, + votes: { + [option: string]: number + }, + error?: string +}; + + +export { + FrontendPoll, + BackendPoll, + PollResult +}; diff --git a/src/backend.ts b/src/backend.ts index 7a8677f..d131f83 100644 --- a/src/backend.ts +++ b/src/backend.ts @@ -4,19 +4,7 @@ import { Router } from "express"; import persist from "node-persist"; import { program } from "commander"; import { resolve } from "path"; - -type Poll = { - id: string, - title: string, - options: { - [option: string]: number - }, - dupeCheckMode: "none" | "ip" | "cookie", - dupeData: null | string[] | string, - multiSelect: boolean, - captcha: boolean, - creationTime: Date, -}; +import { BackendPoll as Poll } from "./Poll"; function randomString(length = 10, charset = "abcdefghjkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789") { let result = ""; diff --git a/src/frontend.ts b/src/frontend.ts index 33a32c6..71575f7 100644 --- a/src/frontend.ts +++ b/src/frontend.ts @@ -3,6 +3,9 @@ import fs from "fs-extra"; import { resolve } from "path"; import { Transform as TransformStream, Stream } from "stream"; import { Router, Request, Response } from "express"; +import fetch from 'node-fetch'; +import { program } from "commander"; +import { FrontendPoll as Poll, PollResult } from "./Poll"; const RenderBuffer = new WeakMap(); const RenderReplacements = new WeakMap(); @@ -91,11 +94,37 @@ async function displayPage(req: Request, res: Response, htmlFilename: string, re export default function init(router: Router): void { router.get("/:id/r", async (req, res) => { const id = req.params.id; - res.redirect(`/`); + try { + const poll: PollResult = await fetch( + (program.opts().backendBaseUrl || "http://localhost:" + program.opts().port) + "/_backend/poll-result/" + id + ).then(r => r.json()) as PollResult; + if (!poll || poll.error) return res.redirect("/"); + await displayPage(req, res, "result.html", { + "POLL_ID": id, + "POLL_TITLE": poll.title, + + }); + } catch (error) { + console.log(error); + res.redirect(`/`); + } }); router.get("/:id", async (req, res) => { const id = req.params.id; - res.redirect(`/`); + try { + const poll: Poll = await fetch( + (program.opts().backendBaseUrl || "http://localhost:" + program.opts().port) + "/_backend/poll/" + id + ).then(r => r.json()) as Poll; + if (!poll || poll.error) return res.redirect("/"); + await displayPage(req, res, "poll.html", { + "POLL_ID": id, + "POLL_TITLE": poll.title, + + }); + } catch (error) { + console.log(error); + res.redirect(`/`); + } }); router.get("/", (req, res) => displayPage(req, res, "index.html")); } \ No newline at end of file