From 7c6a9240d7d2838f076d8d1d9fe6f69d1cb5f16f Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Mon, 18 Mar 2019 21:43:48 -0600 Subject: [PATCH] Support basic presentation of a stickerpack --- package-lock.json | 154 +++++++++++++++++++++++++++++++++ package.json | 2 + src/web/webserver.ts | 40 ++++++--- views/404.handlebars | 9 ++ views/assets/404.svg | 1 + views/layouts/error.handlebars | 39 +++++++++ views/layouts/main.handlebars | 62 +++++++++++++ views/stickerpack.handlebars | 51 +++++++++++ 8 files changed, 348 insertions(+), 10 deletions(-) create mode 100644 views/404.handlebars create mode 100644 views/assets/404.svg create mode 100644 views/layouts/error.handlebars create mode 100644 views/layouts/main.handlebars create mode 100644 views/stickerpack.handlebars diff --git a/package-lock.json b/package-lock.json index 465dc92..184f84c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -60,6 +60,11 @@ "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=" }, + "asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=" + }, "asn1": { "version": "0.2.4", "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", @@ -73,6 +78,14 @@ "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" }, + "async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.2.tgz", + "integrity": "sha512-H1qVYh1MYhEEFLsP97cVKqCGo7KfCyTt6uEWqsTBr9SO84oK9Uwbyd/yCW+6rKJLHksBNUVWZDAjfS+Ccx0Bbg==", + "requires": { + "lodash": "^4.17.11" + } + }, "asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -279,6 +292,14 @@ "ms": "2.0.0" } }, + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "requires": { + "object-keys": "^1.0.12" + } + }, "delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -416,6 +437,33 @@ "vary": "~1.1.2" } }, + "express-handlebars": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/express-handlebars/-/express-handlebars-3.0.2.tgz", + "integrity": "sha512-rPaSqR8xPnSqfvWvI8Mhtn7nifaMmySq6yhWkjH07Ks/nuDaRngJyf7eDN2I7PBkNVdZHf0Bz+1rY1yrZFdx8g==", + "requires": { + "glob": "^7.1.3", + "graceful-fs": "^4.1.2", + "handlebars": "^4.0.13", + "object.assign": "^4.1.0", + "promise": "^8.0.2" + }, + "dependencies": { + "glob": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", + "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + } + } + }, "extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", @@ -450,6 +498,11 @@ "unpipe": "~1.0.0" } }, + "foreachasync": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/foreachasync/-/foreachasync-3.0.0.tgz", + "integrity": "sha1-VQKYfchxS+M5IJfzLgBxyd7gfPY=" + }, "forever-agent": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", @@ -480,6 +533,11 @@ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, "getpass": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", @@ -506,6 +564,17 @@ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz", "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==" }, + "handlebars": { + "version": "4.0.13", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.0.13.tgz", + "integrity": "sha512-uydY0jy4Z3wy/iGXsi64UtLD4t1fFJe16c/NFxsYE4WdQis8ZCzOXUZaPQNG0e5bgtLQV41QTfqBindhEjnpyQ==", + "requires": { + "async": "^2.5.0", + "optimist": "^0.6.1", + "source-map": "^0.6.1", + "uglify-js": "^3.1.4" + } + }, "har-schema": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", @@ -533,6 +602,11 @@ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" }, + "has-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz", + "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=" + }, "hash.js": { "version": "1.1.7", "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", @@ -542,6 +616,15 @@ "minimalistic-assert": "^1.0.1" } }, + "hbs": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/hbs/-/hbs-4.0.3.tgz", + "integrity": "sha512-u8AAbtYUWqNATGEruLdlyAbN+lOtKED+mn38t/13ZkeaKy5BObknFuL1Gtmj0QwXgcSizQ68FHOP1ZST/HP+dg==", + "requires": { + "handlebars": "4.0.13", + "walk": "2.3.9" + } + }, "htmlparser2": { "version": "3.10.1", "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz", @@ -836,6 +919,22 @@ "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" }, + "object-keys": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.0.tgz", + "integrity": "sha512-6OO5X1+2tYkNyNEx6TsCxEqFfRWaqx6EtMiSbGrw8Ob8v9Ne+Hl8rBAgLBZn5wjEz3s/s6U1WXFUFOcxxAwUpg==" + }, + "object.assign": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", + "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", + "requires": { + "define-properties": "^1.1.2", + "function-bind": "^1.1.1", + "has-symbols": "^1.0.0", + "object-keys": "^1.0.11" + } + }, "on-finished": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", @@ -857,6 +956,22 @@ "wrappy": "1" } }, + "optimist": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", + "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", + "requires": { + "minimist": "~0.0.1", + "wordwrap": "~0.0.2" + }, + "dependencies": { + "minimist": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", + "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=" + } + } + }, "parseurl": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz", @@ -927,6 +1042,14 @@ } } }, + "promise": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/promise/-/promise-8.0.2.tgz", + "integrity": "sha512-EIyzM39FpVOMbqgzEHhxdrEhtOSDOtjMZQ0M6iVfCE+kWNgCkAyOdnuCWqfmflylftfadU6FkiMgHZA2kUzwRw==", + "requires": { + "asap": "~2.0.6" + } + }, "proxy-addr": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.4.tgz", @@ -1274,6 +1397,24 @@ "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.3.3333.tgz", "integrity": "sha512-JjSKsAfuHBE/fB2oZ8NxtRTk5iGcg6hkYXMnZ3Wc+b2RSqejEqTaem11mHASMnFilHrax3sLK0GDzcJrekZYLw==" }, + "uglify-js": { + "version": "3.4.10", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.10.tgz", + "integrity": "sha512-Y2VsbPVs0FIshJztycsO2SfPk7/KAF/T72qzv9u5EpQ4kB2hQoHlhNQTsNyy6ul7lQtqJN/AoWeS23OzEiEFxw==", + "optional": true, + "requires": { + "commander": "~2.19.0", + "source-map": "~0.6.1" + }, + "dependencies": { + "commander": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.19.0.tgz", + "integrity": "sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg==", + "optional": true + } + } + }, "unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", @@ -1317,6 +1458,19 @@ "extsprintf": "^1.2.0" } }, + "walk": { + "version": "2.3.9", + "resolved": "https://registry.npmjs.org/walk/-/walk-2.3.9.tgz", + "integrity": "sha1-MbTbZnjyrgHDnqn7hyWpAx5Vins=", + "requires": { + "foreachasync": "^3.0.0" + } + }, + "wordwrap": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", + "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=" + }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", diff --git a/package.json b/package.json index 847215e..029a9fc 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,8 @@ "dependencies": { "@types/node": "^10.14.1", "config": "^3.0.1", + "express-handlebars": "^3.0.2", + "hbs": "^4.0.3", "js-yaml": "^3.12.2", "matrix-bot-sdk": "^0.3.4", "random-string": "^0.2.0", diff --git a/src/web/webserver.ts b/src/web/webserver.ts index 7f20e11..44db5b8 100644 --- a/src/web/webserver.ts +++ b/src/web/webserver.ts @@ -1,5 +1,9 @@ import { Appservice, LogService } from "matrix-bot-sdk"; import { StickerStore } from "../db/StickerStore"; +import * as path from "path"; +import * as exphbs from "express-handlebars"; +import * as express from "express"; +import config from "../config"; export default class Webserver { @@ -10,9 +14,14 @@ export default class Webserver { constructor(private appservice: Appservice, private store: StickerStore) { this.app = (appservice).app; // HACK: Private variable access - this.app.get('/pack/:userId/:packId', this.getStickerpack.bind(this)); + this.app.engine('handlebars', exphbs({defaultLayout: 'main'})); + this.app.set('view engine', 'handlebars'); + //this.app.set('views', path.join(__dirname, 'views')); - // TODO: Serve a home page of some kind. Stickerpack browser? + this.app.get('/pack/:userId/:packId', this.getStickerpack.bind(this)); + this.app.get('/', this.getIndex.bind(this)); + + this.app.use(express.static(path.join(__dirname, '..', '..', 'views', 'assets'))) } public static begin(appservice: Appservice, store: StickerStore) { @@ -20,6 +29,10 @@ export default class Webserver { Webserver.instance = new Webserver(appservice, store); } + private async getIndex(req, res) { + res.status(200).send({"TODO": "This page"}); + } + private async getStickerpack(req, res) { const accept = (req.headers['accept'] || ""); const params = (req.params || {}); @@ -31,16 +44,20 @@ export default class Webserver { const pack = await this.store.getStickerpack(packId); if (!pack) { - // TODO: A real 404 page - res.status(404); - res.send({"TODO": "A real 404 page"}); + if (replyJson) { + res.status(404).send({error: "Pack not found", errcode: "M_NOT_FOUND"}); + } else { + res.status(404).render('404', {layout: 'error'}); + } return; } if (pack.creatorId !== userId) { - // TODO: A real 400 page - res.status(400); - res.send({"TODO": "A real 400 page"}); + if (replyJson) { + res.status(400).send({error: "Creator != requested user ID", errcode: "M_BAD_REQUEST"}); + } else { + res.status(400).render('404', {layout: 'error'}); + } return; } @@ -77,7 +94,10 @@ export default class Webserver { return; } - // TODO: A real preview page - res.send({"TODO": "A real preview page"}); + const renderVars = JSON.parse(JSON.stringify(pack)); + renderVars.stickers = renderVars.stickers.map(s => Object.assign({ + contentUrl: `${config.appservice.homeserverUrl}/_matrix/media/r0/download/${s.contentUri.substring("mxc://".length)}`, + }, s)); + res.render('stickerpack', {pack: renderVars}); } } \ No newline at end of file diff --git a/views/404.handlebars b/views/404.handlebars new file mode 100644 index 0000000..d9576b6 --- /dev/null +++ b/views/404.handlebars @@ -0,0 +1,9 @@ + + + +

Sticker pack not found

+

Please double check the link or ask the sender to re-send it to you.

diff --git a/views/assets/404.svg b/views/assets/404.svg new file mode 100644 index 0000000..074b3b3 --- /dev/null +++ b/views/assets/404.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/views/layouts/error.handlebars b/views/layouts/error.handlebars new file mode 100644 index 0000000..f31df0a --- /dev/null +++ b/views/layouts/error.handlebars @@ -0,0 +1,39 @@ + + + + + Matrix Sticker Manager + + + + + + +
+ {{{body}}} +
+ + + \ No newline at end of file diff --git a/views/layouts/main.handlebars b/views/layouts/main.handlebars new file mode 100644 index 0000000..a1ea6b9 --- /dev/null +++ b/views/layouts/main.handlebars @@ -0,0 +1,62 @@ + + + + + Matrix Sticker Manager + + + + + + +
+
+ {{#if pack}} + Matrix Stickerpack: {{pack.name}} + Created by {{pack.creatorId}} + {{else}} + Matrix Stickerpacks + {{/if}} +
+
+ +
+ {{{body}}} +
+ + + \ No newline at end of file diff --git a/views/stickerpack.handlebars b/views/stickerpack.handlebars new file mode 100644 index 0000000..a2686ea --- /dev/null +++ b/views/stickerpack.handlebars @@ -0,0 +1,51 @@ + + +
+ {{#each pack.stickers}} +
+ + {{this.description}} +
+ {{/each}} +
\ No newline at end of file