diff --git a/.gitignore b/.gitignore
index adda588..34d79e9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,3 +4,5 @@ node_modules
scripts/*
tmp
config.yaml
+sessions
+sessions-journal
diff --git a/app.js b/app.js
index af39593..a4c080f 100644
--- a/app.js
+++ b/app.js
@@ -5,6 +5,7 @@ const createError = require('http-errors'),
logger = require('morgan'),
compileSass = require('express-compile-sass'),
session = require('express-session'),
+ SQLiteStore = require('connect-sqlite3')(session),
fsx = require('fs-extra'),
yaml = require('js-yaml'),
graphqlHTTP = require('express-graphql'),
@@ -39,6 +40,7 @@ app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(session({
+ store: new SQLiteStore,
secret: settings.sessions.secret,
resave: false,
saveUninitialized: true,
diff --git a/package-lock.json b/package-lock.json
index e1f03ba..2621680 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -474,6 +474,11 @@
"upath": "^1.1.1"
}
},
+ "chownr": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.1.tgz",
+ "integrity": "sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g=="
+ },
"class-utils": {
"version": "0.3.6",
"resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz",
@@ -567,6 +572,14 @@
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
},
+ "connect-sqlite3": {
+ "version": "0.9.11",
+ "resolved": "https://registry.npmjs.org/connect-sqlite3/-/connect-sqlite3-0.9.11.tgz",
+ "integrity": "sha1-TlQVXcLq3ypZmDhbLzXoPdkkCy0=",
+ "requires": {
+ "sqlite3": "^4.0.0"
+ }
+ },
"console-control-strings": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
@@ -675,6 +688,11 @@
"resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz",
"integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU="
},
+ "deep-extend": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
+ "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA=="
+ },
"define-property": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz",
@@ -737,6 +755,11 @@
"resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
"integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA="
},
+ "detect-libc": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
+ "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups="
+ },
"doctypes": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/doctypes/-/doctypes-1.1.0.tgz",
@@ -1131,6 +1154,14 @@
"universalify": "^0.1.0"
}
},
+ "fs-minipass": {
+ "version": "1.2.5",
+ "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.5.tgz",
+ "integrity": "sha512-JhBl0skXjUPCFH7x6x61gQxrKyXsxB5gcgePLZCwfyCGGsTISMoIeObbrvVeP6Xmyaudw4TT43qV2Gz+iyd2oQ==",
+ "requires": {
+ "minipass": "^2.2.1"
+ }
+ },
"fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
@@ -1832,6 +1863,14 @@
"safer-buffer": ">= 2.1.2 < 3"
}
},
+ "ignore-walk": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.1.tgz",
+ "integrity": "sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ==",
+ "requires": {
+ "minimatch": "^3.0.4"
+ }
+ },
"in-publish": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/in-publish/-/in-publish-2.0.0.tgz",
@@ -1859,6 +1898,11 @@
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
},
+ "ini": {
+ "version": "1.3.5",
+ "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz",
+ "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw=="
+ },
"inline-source-map-comment": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/inline-source-map-comment/-/inline-source-map-comment-1.0.5.tgz",
@@ -2341,6 +2385,30 @@
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ="
},
+ "minipass": {
+ "version": "2.3.5",
+ "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.3.5.tgz",
+ "integrity": "sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA==",
+ "requires": {
+ "safe-buffer": "^5.1.2",
+ "yallist": "^3.0.0"
+ },
+ "dependencies": {
+ "yallist": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz",
+ "integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A=="
+ }
+ }
+ },
+ "minizlib": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.2.1.tgz",
+ "integrity": "sha512-7+4oTUOWKg7AuL3vloEWekXY2/D20cevzsrNT2kGWm+39J9hGTCBv8VI5Pm5lXZ/o3/mdR4f8rflAPhnQb8mPA==",
+ "requires": {
+ "minipass": "^2.2.1"
+ }
+ },
"mixin-deep": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.1.tgz",
@@ -2422,6 +2490,31 @@
}
}
},
+ "needle": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/needle/-/needle-2.3.1.tgz",
+ "integrity": "sha512-CaLXV3W8Vnbps8ZANqDGz7j4x7Yj1LW4TWF/TQuDfj7Cfx4nAPTvw98qgTevtto1oHDrh3pQkaODbqupXlsWTg==",
+ "requires": {
+ "debug": "^4.1.0",
+ "iconv-lite": "^0.4.4",
+ "sax": "^1.2.4"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
+ "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
+ "requires": {
+ "ms": "^2.1.1"
+ }
+ },
+ "ms": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
+ "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg=="
+ }
+ }
+ },
"negotiator": {
"version": "0.6.2",
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz",
@@ -2453,6 +2546,53 @@
}
}
},
+ "node-pre-gyp": {
+ "version": "0.11.0",
+ "resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.11.0.tgz",
+ "integrity": "sha512-TwWAOZb0j7e9eGaf9esRx3ZcLaE5tQ2lvYy1pb5IAaG1a2e2Kv5Lms1Y4hpj+ciXJRofIxxlt5haeQ/2ANeE0Q==",
+ "requires": {
+ "detect-libc": "^1.0.2",
+ "mkdirp": "^0.5.1",
+ "needle": "^2.2.1",
+ "nopt": "^4.0.1",
+ "npm-packlist": "^1.1.6",
+ "npmlog": "^4.0.2",
+ "rc": "^1.2.7",
+ "rimraf": "^2.6.1",
+ "semver": "^5.3.0",
+ "tar": "^4"
+ },
+ "dependencies": {
+ "nopt": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz",
+ "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=",
+ "requires": {
+ "abbrev": "1",
+ "osenv": "^0.1.4"
+ }
+ },
+ "tar": {
+ "version": "4.4.8",
+ "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.8.tgz",
+ "integrity": "sha512-LzHF64s5chPQQS0IYBn9IN5h3i98c12bo4NCO7e0sGM2llXQ3p2FGC5sdENN4cTW48O915Sh+x+EXx7XW96xYQ==",
+ "requires": {
+ "chownr": "^1.1.1",
+ "fs-minipass": "^1.2.5",
+ "minipass": "^2.3.4",
+ "minizlib": "^1.1.1",
+ "mkdirp": "^0.5.0",
+ "safe-buffer": "^5.1.2",
+ "yallist": "^3.0.2"
+ }
+ },
+ "yallist": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz",
+ "integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A=="
+ }
+ }
+ },
"node-sass": {
"version": "4.12.0",
"resolved": "https://registry.npmjs.org/node-sass/-/node-sass-4.12.0.tgz",
@@ -2525,6 +2665,20 @@
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
"integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA=="
},
+ "npm-bundled": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.0.6.tgz",
+ "integrity": "sha512-8/JCaftHwbd//k6y2rEWp6k1wxVfpFzB6t1p825+cUb7Ym2XQfhwIC5KwhrvzZRJu+LtDE585zVaS32+CGtf0g=="
+ },
+ "npm-packlist": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.4.1.tgz",
+ "integrity": "sha512-+TcdO7HJJ8peiiYhvPxsEDhF3PJFGUGRcFsGve3vxvxdcpO2Z4Z7rkosRM0kWj6LfbK/P0gu3dzk5RU1ffvFcw==",
+ "requires": {
+ "ignore-walk": "^3.0.1",
+ "npm-bundled": "^1.0.1"
+ }
+ },
"npmlog": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz",
@@ -2896,6 +3050,17 @@
"unpipe": "1.0.0"
}
},
+ "rc": {
+ "version": "1.2.8",
+ "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
+ "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==",
+ "requires": {
+ "deep-extend": "^0.6.0",
+ "ini": "~1.3.0",
+ "minimist": "^1.2.0",
+ "strip-json-comments": "~2.0.1"
+ }
+ },
"read-pkg": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz",
@@ -3127,6 +3292,11 @@
}
}
},
+ "sax": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
+ "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw=="
+ },
"scss-tokenizer": {
"version": "0.2.3",
"resolved": "https://registry.npmjs.org/scss-tokenizer/-/scss-tokenizer-0.2.3.tgz",
@@ -3371,6 +3541,16 @@
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
"integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw="
},
+ "sqlite3": {
+ "version": "4.0.8",
+ "resolved": "https://registry.npmjs.org/sqlite3/-/sqlite3-4.0.8.tgz",
+ "integrity": "sha512-kgwHu4j10KhpCHtx//dejd/tVQot7jc3sw+Sn0vMuKOw0X00Ckyg9VceKgzPyGmmz+zEoYue9tOLriWTvYy0ww==",
+ "requires": {
+ "nan": "^2.12.1",
+ "node-pre-gyp": "^0.11.0",
+ "request": "^2.87.0"
+ }
+ },
"sshpk": {
"version": "1.16.1",
"resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz",
@@ -3461,6 +3641,11 @@
"get-stdin": "^4.0.1"
}
},
+ "strip-json-comments": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
+ "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo="
+ },
"sum-up": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/sum-up/-/sum-up-1.0.3.tgz",
diff --git a/package.json b/package.json
index a17f1e6..176f489 100644
--- a/package.json
+++ b/package.json
@@ -6,6 +6,7 @@
"start": "node ./bin/www"
},
"dependencies": {
+ "connect-sqlite3": "^0.9.11",
"cookie-parser": "~1.4.4",
"debug": "~2.6.9",
"express": "~4.16.1",
diff --git a/public/javascripts/bingo-web.js b/public/javascripts/bingo-web.js
index c89e5ac..59179f4 100644
--- a/public/javascripts/bingo-web.js
+++ b/public/javascripts/bingo-web.js
@@ -76,8 +76,9 @@ async function createFollowup() {
*/
async function submitUsername() {
let unameInput = document.querySelector('#username-input');
- let username = unameInput.value;
- let response = await postGraphqlQuery(`
+ let username = unameInput.value.replace(/^\s+|\s+$/g, '');
+ if (username.length > 1 && username !== 'anonymous') {
+ let response = await postGraphqlQuery(`
mutation($username:String!) {
bingo {
setUsername(input: {username: $username}) {
@@ -86,16 +87,19 @@ async function submitUsername() {
}
}
}`, {
- username: username
- },`/graphql?game=${getGameParam()}`);
- if (response.status === 200) {
- unameInput.value = '';
- unameInput.placeholder = response.data.username;
- document.querySelector('#username-form').remove();
- document.querySelector('.greyover').remove();
+ username: username
+ },`/graphql?game=${getGameParam()}`);
+ if (response.status === 200) {
+ unameInput.value = '';
+ unameInput.placeholder = response.data.username;
+ document.querySelector('#username-form').remove();
+ document.querySelector('.greyover').remove();
+ } else {
+ showError(`Failed to submit username. HTTP Error: ${response.status}`);
+ console.error(response);
+ }
} else {
- showError(`Failed to submit username. HTTP Error: ${response.status}`);
- console.error(response);
+ showError('You need to provide a username (minimum 2 characters)!');
}
}
@@ -306,12 +310,10 @@ function addChatMessage(messageObject) {
if (messageObject.type === "USER") {
msgSpan.innerHTML = `
${messageObject.username}:
- ${messageObject.htmlContent}
- `;
+ ${messageObject.htmlContent}`;
} else {
msgSpan.innerHTML = `
- ${messageObject.htmlContent}
- `;
+ ${messageObject.htmlContent}`;
}
let chatContent = document.querySelector('#chat-content');
chatContent.appendChild(msgSpan);
@@ -334,6 +336,8 @@ window.addEventListener("unhandledrejection", function(promiseRejectionEvent) {
});
window.onload = () => {
+ if (document.querySelector('#chat-container'))
+ refresh();
if (window && !document.querySelector('#bingoform')) {
refrInterval = setInterval(refresh, 1000); // global variable to clear
}
diff --git a/public/stylesheets/sass/bingo/style.sass b/public/stylesheets/sass/bingo/style.sass
index ab28468..c5b0c92 100644
--- a/public/stylesheets/sass/bingo/style.sass
+++ b/public/stylesheets/sass/bingo/style.sass
@@ -23,14 +23,17 @@ textarea
grid-template-columns: 0 100% !important
grid-template-rows: 10% 80% 10% !important
- #players-container div
- display: none
+ #players-container #chat-container
+ display: none !important
padding: 0
+
#username-form
width: calc(100% - 2rem) !important
left: 0 !important
+
#hide-player-container-button
display: none
+
.popup
width: calc(100% - 2rem) !important
left: 0 !important
@@ -173,6 +176,7 @@ textarea
height: 100%
border: 1px solid $inactive
margin: 0 0.5rem
+ word-break: break-word
#chat-content
height: calc(100% - 3.5rem)
diff --git a/routes/bingo.js b/routes/bingo.js
index 3daa8b1..b14b677 100644
--- a/routes/bingo.js
+++ b/routes/bingo.js
@@ -33,6 +33,9 @@ class BingoSession {
addUser(user) {
let id = user.id;
this.users[id] = user;
+ if (user.username !== 'anonymous') {
+ this.chatMessages.push(new BingoChatMessage(`**${user.username}** joined.`, "INFO"));
+ }
}
/**
@@ -57,7 +60,7 @@ class BingoSession {
this.followup = followup.id;
bingoSessions[followup.id] = followup;
followup.chatMessages = this.chatMessages;
- followup.chatMessages.push(new BingoChatMessage('--- Rematch ---', "INFO"));
+ followup.chatMessages.push(new BingoChatMessage('**Rematch**', "INFO"));
return followup;
}
@@ -84,7 +87,7 @@ class BingoSession {
*/
sendToggleInfo(base64Word, bingoUser) {
let word = Buffer.from(base64Word, 'base64').toString();
- let toggleMessage = new BingoChatMessage(`${bingoUser.username} toggled phrase "${word}"`, "INFO");
+ let toggleMessage = new BingoChatMessage(`**${bingoUser.username}** toggled phrase "${word}".`, "INFO");
this.chatMessages.push(toggleMessage);
}
}
@@ -343,6 +346,7 @@ router.graphqlResolver = (req, res) => {
});
let size = input.size;
if (words.length > 0 && size < 10 && size > 0) {
+ words = words.slice(0, 10000); // only allow up to 10000 words in the bingo
let game = new BingoSession(words, size);
bingoSessions[game.id] = game;
@@ -404,7 +408,7 @@ router.graphqlResolver = (req, res) => {
}
},
sendChatMessage: ({input}) => {
- input.message = replaceTagSigns(input.message);
+ input.message = replaceTagSigns(input.message).substring(0, 250);
if (bingoSession && input.message) {
let userMessage = new BingoChatMessage(input.message, 'USER', bingoUser.username);
bingoSession.chatMessages.push(userMessage);
diff --git a/views/bingo/bingo-game.pug b/views/bingo/bingo-game.pug
index 78654b6..1f9974a 100644
--- a/views/bingo/bingo-game.pug
+++ b/views/bingo/bingo-game.pug
@@ -4,7 +4,7 @@ block content
if username === 'anonymous'
div(class='greyover')
div(id='username-form', onkeypress='submitOnEnter(event, submitUsername)')
- input(type='text', id='username-input', placeholder=username)
+ input(type='text', id='username-input', placeholder=username, maxlength="30")
span Maximum is 30 characters.
button(onclick='submitUsername()') Set Username
div(id='content-container')
@@ -15,7 +15,7 @@ block content
span(class='player-name-span')= player.username
div(id='chat-container')
div(id='chat-content')
- input(id='chat-input' type='text', placeholder='chat', onkeypress='submitOnEnter(event, sendChatMessage)')
+ input(id='chat-input' type='text', placeholder='chat', onkeypress='submitOnEnter(event, sendChatMessage)' maxlength="250")
div(id='words-container')
each val in grid
div(class='bingo-word-row')
diff --git a/views/bingo/bingo-submit.pug b/views/bingo/bingo-submit.pug
index e351819..db8c533 100644
--- a/views/bingo/bingo-submit.pug
+++ b/views/bingo/bingo-submit.pug
@@ -10,4 +10,4 @@ block content
div(class='stretchDiv')
button(onclick='submitBingoWords()') Submit
span(id='word-count') Please provide at least 9 phrases:
- textarea(id='bingo-textarea', placeholder='Bingo Words')
+ textarea(id='bingo-textarea', placeholder='Bingo Words (max 10,000)', maxlength=1000000)