Support basic presentation of a stickerpack

This commit is contained in:
Travis Ralston 2019-03-18 21:43:48 -06:00
parent a287828946
commit 7c6a9240d7
8 changed files with 348 additions and 10 deletions

154
package-lock.json generated
View file

@ -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",

View file

@ -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",

View file

@ -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 = (<any>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});
}
}

9
views/404.handlebars Normal file
View file

@ -0,0 +1,9 @@
<style type="text/css">
* {
text-align: center;
}
</style>
<img src="/404.svg" width="175" />
<h2>Sticker pack not found</h2>
<p>Please double check the link or ask the sender to re-send it to you.</p>

1
views/assets/404.svg Normal file
View file

@ -0,0 +1 @@
<?xml version="1.0" ?><svg id="Layer_1" style="enable-background:new 0 0 60 60;" version="1.1" viewBox="0 0 60 60" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M50.7,32c0.9-1.7,1.3-3.6,1.3-5.5c0-6.6-5.4-12-12-12c-2.7,0-5.3,0.9-7.4,2.5c-1.5-2.2-4-3.5-6.6-3.5 c-3.4,0-6.3,2.1-7.5,5.1c-0.5-0.1-1-0.1-1.5-0.1c-4.4,0-8,3.6-8,8c0,1.7,0.6,3.4,1.6,4.8C7.8,32.6,6,35.4,6,38.5c0,4.4,3.6,8,8,8h32 c4.4,0,8-3.6,8-8C54,35.9,52.7,33.5,50.7,32z M46,44.5H14c-3.3,0-6-2.7-6-6c0-2.8,1.9-5.2,4.6-5.8l1.8-0.5L13,31 c-1.3-1.1-2-2.8-2-4.5c0-3.3,2.7-6,6-6c0.6,0,1.3,0.1,1.9,0.3l1,0.3l0.3-1.1c0.7-2.7,3-4.6,5.8-4.6c2.3,0,4.5,1.4,5.5,3.5l0.6,1.3 l1-1c1.9-1.8,4.3-2.8,6.9-2.8c5.5,0,10,4.5,10,10c0,1.9-0.5,3.7-1.5,5.3l-0.6,0.9l0.9,0.5c1.9,1,3.2,3.1,3.2,5.3 C52,41.8,49.3,44.5,46,44.5z"/><path d="M22,34.5h-3.6l2.6-7.7l-1.9-0.6l-3,9c-0.1,0.3-0.1,0.6,0.1,0.9s0.5,0.4,0.8,0.4h5v4h2v-9h-2V34.5z"/><path d="M42,34.5h-3.6l2.6-7.7l-1.9-0.6l-3,9c-0.1,0.3-0.1,0.6,0.1,0.9s0.5,0.4,0.8,0.4h5v4h2v-9h-2V34.5z"/><path d="M26,40.5h8v-14h-8V40.5z M28,28.5h4v10h-4V28.5z"/></svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View file

@ -0,0 +1,39 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Matrix Sticker Manager</title>
<link href="https://fonts.googleapis.com/css?family=Mukta" rel="stylesheet">
<style type="text/css">
* {
font-family: 'Mukta', sans-serif;
}
body, html {
width: 100%;
padding: 0;
margin: 0;
background-color: #EBEBEB;
color: #000;
}
.wrapper {
display: inline-block;
margin: 30px auto auto;
padding: 40px;
border: 1px solid #F03A47;
border-radius: 5px;
box-shadow: #F03A47 5px 5px;
background-color: #fff;
}
</style>
</head>
<body>
<div class="wrapper">
{{{body}}}
</div>
</body>
</html>

View file

@ -0,0 +1,62 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Matrix Sticker Manager</title>
<link href="https://fonts.googleapis.com/css?family=Mukta" rel="stylesheet">
<style type="text/css">
* {
font-family: 'Mukta', sans-serif;
}
body, html {
width: 100%;
padding: 0;
margin: 0;
background-color: #EBEBEB;
color: #000;
}
header {
padding-bottom: 5px;
background: linear-gradient(90deg, rgba(185, 54, 201, 0.7), rgba(79, 174, 255, 0.7));
}
header div {
font-size: 25px;
padding: 10px 10px 10px 25px;
background-color: #fff;
}
header small {
display: block;
font-size: 12px;
}
.wrapper {
display: inline-block;
margin: 30px auto auto;
padding: 40px;
}
</style>
</head>
<body>
<header>
<div>
{{#if pack}}
Matrix Stickerpack: {{pack.name}}
<small>Created by {{pack.creatorId}}</small>
{{else}}
Matrix Stickerpacks
{{/if}}
</div>
</header>
<div class="wrapper">
{{{body}}}
</div>
</body>
</html>

View file

@ -0,0 +1,51 @@
<style type="text/css">
.stickers {
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: center;
align-content: center;
width: 100%;
}
.wrapper {
width: 100%;
padding: 0;
}
.sticker {
background: #fff;
border: 1px solid #4062BB33;
border-radius: 5px;
box-shadow: #4062BB33 5px 5px;
transition: all ease 300ms;
padding: 25px 5px 5px;
width: 200px;
height: 200px;
text-align: center;
margin: 20px;
}
.sticker:hover {
border: 1px solid #52489C;
box-shadow: #52489C 5px 5px;
}
.sticker img {
display: inline-block;
}
.sticker .description {
display: block;
text-overflow: ellipsis;
}
</style>
<div class="stickers">
{{#each pack.stickers}}
<div class="sticker">
<img src="{{this.contentUrl}}" width="150" height="150" />
<span class="description">{{this.description}}</span>
</div>
{{/each}}
</div>