summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--public/common/play.js836
-rw-r--r--public/sort.js101
-rw-r--r--server.js1938
-rw-r--r--views/chat.pug62
-rw-r--r--views/forum_post.pug6
-rw-r--r--views/join.pug10
-rw-r--r--views/message_outbox.pug4
-rw-r--r--views/message_read.pug6
8 files changed, 1499 insertions, 1464 deletions
diff --git a/public/common/play.js b/public/common/play.js
index 80ead70..1df4708 100644
--- a/public/common/play.js
+++ b/public/common/play.js
@@ -1,18 +1,18 @@
-"use strict";
+"use strict"
// TODO: Remove when CSS Images Module Level 4 is widely supported,
-(function () {
- let avif = new Image();
- avif.src = "data:image/avif;base64,AAAAIGZ0eXBhdmlmAAAAAGF2aWZtaWYxbWlhZk1BMUEAAADybWV0YQAAAAAAAAAoaGRscgAAAAAAAAAAcGljdAAAAAAAAAAAAAAAAGxpYmF2aWYAAAAADnBpdG0AAAAAAAEAAAAeaWxvYwAAAABEAAABAAEAAAABAAABGgAAABkAAAAoaWluZgAAAAAAAQAAABppbmZlAgAAAAABAABhdjAxQ29sb3IAAAAAamlwcnAAAABLaXBjbwAAABRpc3BlAAAAAAAAAAEAAAABAAAAEHBpeGkAAAAAAwgICAAAAAxhdjFDgSAAAAAAABNjb2xybmNseAABAA0ABoAAAAAXaXBtYQAAAAAAAAABAAEEAQKDBAAAACFtZGF0EgAKBzgABhAQ0GkyDBZABhhhhAAAeUzRyg==";
- avif.onload = () => document.documentElement.className = "avif";
- avif.onerror = () => document.documentElement.className = "jpeg";
-})();
+;(function () {
+ let avif = new Image()
+ avif.src = "data:image/avif;base64,AAAAIGZ0eXBhdmlmAAAAAGF2aWZtaWYxbWlhZk1BMUEAAADybWV0YQAAAAAAAAAoaGRscgAAAAAAAAAAcGljdAAAAAAAAAAAAAAAAGxpYmF2aWYAAAAADnBpdG0AAAAAAAEAAAAeaWxvYwAAAABEAAABAAEAAAABAAABGgAAABkAAAAoaWluZgAAAAAAAQAAABppbmZlAgAAAAABAABhdjAxQ29sb3IAAAAAamlwcnAAAABLaXBjbwAAABRpc3BlAAAAAAAAAAEAAAABAAAAEHBpeGkAAAAAAwgICAAAAAxhdjFDgSAAAAAAABNjb2xybmNseAABAA0ABoAAAAAXaXBtYQAAAAAAAAABAAEEAQKDBAAAACFtZGF0EgAKBzgABhAQ0GkyDBZABhhhhAAAeUzRyg=="
+ avif.onload = () => document.documentElement.className = "avif"
+ avif.onerror = () => document.documentElement.className = "jpeg"
+})()
/* URL: /$title_id/(re)play:$game_id:$role */
if (!/\/[\w-]+\/(re)?play:\d+(:[\w-]+)?/.test(window.location.pathname)) {
- document.getElementById("prompt").textContent = "Invalid game ID.";
- throw Error("Invalid game ID.");
+ document.getElementById("prompt").textContent = "Invalid game ID."
+ throw Error("Invalid game ID.")
}
let params = {
@@ -22,129 +22,129 @@ let params = {
role: decodeURIComponent(window.location.pathname.split("/")[2]).split(":")[2] || "Observer",
}
-let roles = Array.from(document.querySelectorAll(".role")).map(x=>({id:x.id,role:x.id.replace(/^role_/,"").replace(/_/g," ")}));
+let roles = Array.from(document.querySelectorAll(".role")).map(x=>({id:x.id,role:x.id.replace(/^role_/,"").replace(/_/g," ")}))
-let view = null;
-let player = "Observer";
-let socket = null;
-let chat = null;
+let view = null
+let player = "Observer"
+let socket = null
+let chat = null
function scroll_with_middle_mouse(panel_sel, multiplier) {
- let panel = document.querySelector(panel_sel);
- let down_x, down_y, scroll_x, scroll_y;
+ let panel = document.querySelector(panel_sel)
+ let down_x, down_y, scroll_x, scroll_y
if (!multiplier)
- multiplier = 1;
+ multiplier = 1
function md(e) {
if (e.button === 1) {
- down_x = e.clientX;
- down_y = e.clientY;
- scroll_x = panel.scrollLeft;
- scroll_y = panel.scrollTop;
- window.addEventListener("mousemove", mm);
- window.addEventListener("mouseup", mu);
- e.preventDefault();
+ down_x = e.clientX
+ down_y = e.clientY
+ scroll_x = panel.scrollLeft
+ scroll_y = panel.scrollTop
+ window.addEventListener("mousemove", mm)
+ window.addEventListener("mouseup", mu)
+ e.preventDefault()
}
}
function mm(e) {
- let dx = down_x - e.clientX;
- let dy = down_y - e.clientY;
- panel.scrollLeft = scroll_x + dx * multiplier;
- panel.scrollTop = scroll_y + dy * multiplier;
- e.preventDefault();
+ let dx = down_x - e.clientX
+ let dy = down_y - e.clientY
+ panel.scrollLeft = scroll_x + dx * multiplier
+ panel.scrollTop = scroll_y + dy * multiplier
+ e.preventDefault()
}
function mu(e) {
if (e.button === 1) {
- window.removeEventListener("mousemove", mm);
- window.removeEventListener("mouseup", mu);
- e.preventDefault();
+ window.removeEventListener("mousemove", mm)
+ window.removeEventListener("mouseup", mu)
+ e.preventDefault()
}
}
- panel.addEventListener("mousedown", md);
+ panel.addEventListener("mousedown", md)
}
function drag_element_with_mouse(element_sel, grabber_sel) {
- let element = document.querySelector(element_sel);
- let grabber = document.querySelector(grabber_sel) || element;
- let save_x, save_y;
+ let element = document.querySelector(element_sel)
+ let grabber = document.querySelector(grabber_sel) || element
+ let save_x, save_y
function md(e) {
if (e.button === 0) {
- save_x = e.clientX;
- save_y = e.clientY;
- window.addEventListener("mousemove", mm);
- window.addEventListener("mouseup", mu);
- e.preventDefault();
+ save_x = e.clientX
+ save_y = e.clientY
+ window.addEventListener("mousemove", mm)
+ window.addEventListener("mouseup", mu)
+ e.preventDefault()
}
}
function mm(e) {
- let dx = save_x - e.clientX;
- let dy = save_y - e.clientY;
- save_x = e.clientX;
- save_y = e.clientY;
- element.style.left = (element.offsetLeft - dx) + "px";
- element.style.top = (element.offsetTop - dy) + "px";
- e.preventDefault();
+ let dx = save_x - e.clientX
+ let dy = save_y - e.clientY
+ save_x = e.clientX
+ save_y = e.clientY
+ element.style.left = (element.offsetLeft - dx) + "px"
+ element.style.top = (element.offsetTop - dy) + "px"
+ e.preventDefault()
}
function mu(e) {
if (e.button === 0) {
- window.removeEventListener("mousemove", mm);
- window.removeEventListener("mouseup", mu);
- e.preventDefault();
+ window.removeEventListener("mousemove", mm)
+ window.removeEventListener("mouseup", mu)
+ e.preventDefault()
}
}
- grabber.addEventListener("mousedown", md);
+ grabber.addEventListener("mousedown", md)
}
/* TITLE BLINKER */
-let blink_title = document.title;
-let blink_timer = 0;
+let blink_title = document.title
+let blink_timer = 0
function start_blinker(message) {
- let tick = false;
+ let tick = false
if (blink_timer)
- stop_blinker();
+ stop_blinker()
if (!document.hasFocus()) {
- document.title = message;
+ document.title = message
blink_timer = setInterval(function () {
- document.title = tick ? message : blink_title;
- tick = !tick;
- }, 1000);
+ document.title = tick ? message : blink_title
+ tick = !tick
+ }, 1000)
}
}
function stop_blinker() {
- document.title = blink_title;
- clearInterval(blink_timer);
- blink_timer = 0;
+ document.title = blink_title
+ clearInterval(blink_timer)
+ blink_timer = 0
}
-window.addEventListener("focus", stop_blinker);
+window.addEventListener("focus", stop_blinker)
/* CHAT */
function init_chat() {
// only fetch new messages when we reconnect!
if (chat !== null) {
- send_message("getchat", chat.log);
- return;
+ send_message("getchat", chat.log)
+ return
}
- let chat_window = document.createElement("div");
- chat_window.id = "chat_window";
+ let chat_window = document.createElement("div")
+ chat_window.id = "chat_window"
chat_window.innerHTML = `
<div id="chat_x" onclick="toggle_chat()">\u274c</div>
<div id="chat_header">Chat</div>
<div id="chat_text"></div>
<form id="chat_form" action=""><input id="chat_input" autocomplete="off"></form>
- `;
- document.querySelector("body").appendChild(chat_window);
+ `
+ document.querySelector("body").appendChild(chat_window)
- let chat_button = document.createElement("div");
- chat_button.id = "chat_button";
- chat_button.className = "icon_button";
- chat_button.innerHTML = '<img src="/images/chat-bubble.svg">';
- chat_button.addEventListener("click", toggle_chat);
- document.querySelector("#toolbar").appendChild(chat_button);
+ let chat_button = document.createElement("div")
+ chat_button.id = "chat_button"
+ chat_button.className = "icon_button"
+ chat_button.innerHTML = '<img src="/images/chat-bubble.svg">'
+ chat_button.addEventListener("click", toggle_chat)
+ document.querySelector("#toolbar").appendChild(chat_button)
chat = {
is_visible: false,
@@ -154,737 +154,737 @@ function init_chat() {
log: 0
}
- chat.seen = window.localStorage.getItem(chat.key) | 0;
+ chat.seen = window.localStorage.getItem(chat.key) | 0
- drag_element_with_mouse("#chat_window", "#chat_header");
+ drag_element_with_mouse("#chat_window", "#chat_header")
document.getElementById("chat_form").addEventListener("submit", e => {
- let input = document.getElementById("chat_input");
- e.preventDefault();
+ let input = document.getElementById("chat_input")
+ e.preventDefault()
if (input.value) {
- send_message("chat", input.value);
- input.value = "";
+ send_message("chat", input.value)
+ input.value = ""
} else {
- hide_chat();
+ hide_chat()
}
- });
+ })
document.querySelector("body").addEventListener("keydown", e => {
if (e.key === "Escape") {
if (chat.is_visible) {
- e.preventDefault();
- hide_chat();
+ e.preventDefault()
+ hide_chat()
}
}
if (e.key === "Enter") {
- let input = document.getElementById("chat_input");
+ let input = document.getElementById("chat_input")
if (document.activeElement !== input) {
- e.preventDefault();
- show_chat();
+ e.preventDefault()
+ show_chat()
}
}
- });
+ })
- send_message("getchat", 0);
+ send_message("getchat", 0)
}
function save_chat() {
- window.localStorage.setItem(chat.key, chat.log);
+ window.localStorage.setItem(chat.key, chat.log)
}
function update_chat(chat_id, utc_date, user, message) {
function format_time(date) {
- let mm = date.getMinutes();
- let hh = date.getHours();
- if (mm < 10) mm = "0" + mm;
- if (hh < 10) hh = "0" + hh;
- return hh + ":" + mm;
+ let mm = date.getMinutes()
+ let hh = date.getHours()
+ if (mm < 10) mm = "0" + mm
+ if (hh < 10) hh = "0" + hh
+ return hh + ":" + mm
}
function add_date_line(date) {
- let line = document.createElement("div");
- line.className = "date";
- line.textContent = "~ " + date + " ~";
- chat.text_element.appendChild(line);
+ let line = document.createElement("div")
+ line.className = "date"
+ line.textContent = "~ " + date + " ~"
+ chat.text_element.appendChild(line)
}
function add_chat_line(time, user, message) {
- let line = document.createElement("div");
- line.textContent = "[" + time + "] " + user + " \xbb " + message;
- chat.text_element.appendChild(line);
- chat.text_element.scrollTop = chat.text_element.scrollHeight;
+ let line = document.createElement("div")
+ line.textContent = "[" + time + "] " + user + " \xbb " + message
+ chat.text_element.appendChild(line)
+ chat.text_element.scrollTop = chat.text_element.scrollHeight
}
if (chat_id > chat.log) {
- chat.log = chat_id;
- let date = new Date(utc_date + "Z");
- let day = date.toDateString();
+ chat.log = chat_id
+ let date = new Date(utc_date + "Z")
+ let day = date.toDateString()
if (day !== chat.last_day) {
- add_date_line(day);
- chat.last_day = day;
+ add_date_line(day)
+ chat.last_day = day
}
- add_chat_line(format_time(date), user, message);
+ add_chat_line(format_time(date), user, message)
}
if (chat_id > chat.seen) {
- let button = document.getElementById("chat_button");
- start_blinker("NEW MESSAGE");
+ let button = document.getElementById("chat_button")
+ start_blinker("NEW MESSAGE")
if (!chat.is_visible)
- button.classList.add("new");
+ button.classList.add("new")
else
- save_chat();
+ save_chat()
}
}
function show_chat() {
if (!chat.is_visible) {
- document.getElementById("chat_button").classList.remove("new");
- document.getElementById("chat_window").classList.add("show");
- document.getElementById("chat_input").focus();
- chat.is_visible = true;
- save_chat();
+ document.getElementById("chat_button").classList.remove("new")
+ document.getElementById("chat_window").classList.add("show")
+ document.getElementById("chat_input").focus()
+ chat.is_visible = true
+ save_chat()
}
}
function hide_chat() {
if (chat.is_visible) {
- document.getElementById("chat_window").classList.remove("show");
- document.getElementById("chat_input").blur();
- chat.is_visible = false;
+ document.getElementById("chat_window").classList.remove("show")
+ document.getElementById("chat_input").blur()
+ chat.is_visible = false
}
}
function toggle_chat() {
if (chat.is_visible)
- hide_chat();
+ hide_chat()
else
- show_chat();
+ show_chat()
}
/* REMATCH BUTTON */
function remove_resign_menu() {
- document.querySelectorAll(".resign").forEach(x => x.remove());
+ document.querySelectorAll(".resign").forEach(x => x.remove())
}
function goto_rematch() {
- window.location = "/rematch/" + params.game_id + "/" + params.role;
+ window.location = "/rematch/" + params.game_id + "/" + params.role
}
function goto_replay() {
- window.location = "/" + params.title_id + "/replay:" + params.game_id;
+ window.location = "/" + params.title_id + "/replay:" + params.game_id
}
function on_game_over() {
function icon_button(id, img, title, fn) {
if (!document.getElementById(id)) {
- let button = document.createElement("div");
- button.id = id;
- button.title = title;
- button.className = "icon_button";
- button.innerHTML = '<img src="/images/' + img + '.svg">';
- button.addEventListener("click", fn);
- document.querySelector("header").appendChild(button);
+ let button = document.createElement("div")
+ button.id = id
+ button.title = title
+ button.className = "icon_button"
+ button.innerHTML = '<img src="/images/' + img + '.svg">'
+ button.addEventListener("click", fn)
+ document.querySelector("header").appendChild(button)
}
}
- icon_button("replay_button", "sherlock-holmes-mirror", "Watch replay", goto_replay);
+ icon_button("replay_button", "sherlock-holmes-mirror", "Watch replay", goto_replay)
if (player !== "Observer")
- icon_button("rematch_button", "cycle", "Propose a rematch!", goto_rematch);
- remove_resign_menu();
+ icon_button("rematch_button", "cycle", "Propose a rematch!", goto_rematch)
+ remove_resign_menu()
}
/* CONNECT TO GAME SERVER */
function init_player_names(players) {
for (let i = 0; i < roles.length; ++i) {
- let sel = "#" + roles[i].id + " .role_user";
- let p = players.find(p => p.role === roles[i].role);
- document.querySelector(sel).textContent = p ? p.name : "NONE";
+ let sel = "#" + roles[i].id + " .role_user"
+ let p = players.find(p => p.role === roles[i].role)
+ document.querySelector(sel).textContent = p ? p.name : "NONE"
}
}
function send_message(cmd, arg) {
- let data = JSON.stringify([cmd, arg]);
- console.log("SEND %s %s", cmd, arg);
- socket.send(data);
+ let data = JSON.stringify([cmd, arg])
+ console.log("SEND %s %s", cmd, arg)
+ socket.send(data)
}
-let reconnect_count = 0;
-let reconnect_max = 10;
+let reconnect_count = 0
+let reconnect_max = 10
function connect_play() {
if (reconnect_count >= reconnect_max) {
- document.title = "DISCONNECTED";
- document.getElementById("prompt").textContent = "Disconnected.";
- return;
+ document.title = "DISCONNECTED"
+ document.getElementById("prompt").textContent = "Disconnected."
+ return
}
- let protocol = (window.location.protocol === "http:") ? "ws" : "wss";
- let seen = document.getElementById("log").children.length;
- let url = `${protocol}://${window.location.host}/play-socket?title=${params.title_id}&game=${params.game_id}&role=${params.role}&seen=${seen}`;
+ let protocol = (window.location.protocol === "http:") ? "ws" : "wss"
+ let seen = document.getElementById("log").children.length
+ let url = `${protocol}://${window.location.host}/play-socket?title=${params.title_id}&game=${params.game_id}&role=${params.role}&seen=${seen}`
- console.log("CONNECTING", url);
- document.getElementById("prompt").textContent = "Connecting... ";
+ console.log("CONNECTING", url)
+ document.getElementById("prompt").textContent = "Connecting... "
- socket = new WebSocket(url);
+ socket = new WebSocket(url)
window.addEventListener('beforeunload', function () {
- socket.close(1000);
- });
+ socket.close(1000)
+ })
socket.onopen = function (evt) {
- console.log("OPEN");
- document.querySelector("header").classList.remove("disconnected");
- reconnect_count = 0;
+ console.log("OPEN")
+ document.querySelector("header").classList.remove("disconnected")
+ reconnect_count = 0
}
socket.onclose = function (evt) {
- console.log("CLOSE %d", evt.code);
+ console.log("CLOSE %d", evt.code)
if (evt.code === 1000 && evt.reason !== "") {
- document.getElementById("prompt").textContent = "Disconnected: " + evt.reason;
- document.title = "DISCONNECTED";
+ document.getElementById("prompt").textContent = "Disconnected: " + evt.reason
+ document.title = "DISCONNECTED"
}
if (evt.code !== 1000) {
- document.querySelector("header").classList.add("disconnected");
- document.getElementById("prompt").textContent = `Reconnecting soon... (${reconnect_count+1}/${reconnect_max})`;
- let wait = 1000 * (Math.random() + 0.5) * Math.pow(2, reconnect_count++);
- console.log("WAITING %.1f TO RECONNECT", wait/1000);
- setTimeout(connect_play, wait);
+ document.querySelector("header").classList.add("disconnected")
+ document.getElementById("prompt").textContent = `Reconnecting soon... (${reconnect_count+1}/${reconnect_max})`
+ let wait = 1000 * (Math.random() + 0.5) * Math.pow(2, reconnect_count++)
+ console.log("WAITING %.1f TO RECONNECT", wait/1000)
+ setTimeout(connect_play, wait)
}
}
socket.onmessage = function (evt) {
- let [ cmd, arg ] = JSON.parse(evt.data);
- console.log("MESSAGE %s", cmd);
+ let [ cmd, arg ] = JSON.parse(evt.data)
+ console.log("MESSAGE %s", cmd)
switch (cmd) {
case 'error':
- document.getElementById("prompt").textContent = arg;
- break;
+ document.getElementById("prompt").textContent = arg
+ break
case 'chat':
- update_chat(arg[0], arg[1], arg[2], arg[3]);
- break;
+ update_chat(arg[0], arg[1], arg[2], arg[3])
+ break
case 'players':
- player = arg[0];
- document.querySelector("body").classList.add(player.replace(/ /g, "_"));
+ player = arg[0]
+ document.querySelector("body").classList.add(player.replace(/ /g, "_"))
if (player !== "Observer")
- init_chat();
+ init_chat()
else
- remove_resign_menu();
- init_player_names(arg[1]);
- break;
+ remove_resign_menu()
+ init_player_names(arg[1])
+ break
case 'presence':
for (let i = 0; i < roles.length; ++i) {
- let elt = document.getElementById(roles[i].id);
+ let elt = document.getElementById(roles[i].id)
if (roles[i].role in arg)
- elt.classList.add("present");
+ elt.classList.add("present")
else
- elt.classList.remove("present");
+ elt.classList.remove("present")
}
- break;
+ break
case 'state':
- view = arg;
- on_update_header();
+ view = arg
+ on_update_header()
if (typeof on_update === 'function')
- on_update();
- on_update_log();
+ on_update()
+ on_update_log()
if (view.game_over)
- on_game_over();
- break;
+ on_game_over()
+ break
case 'reply':
if (typeof on_reply === 'function')
- on_reply(arg[0], arg[1]);
- break;
+ on_reply(arg[0], arg[1])
+ break
case 'save':
- window.localStorage[params.title_id + "/save"] = arg;
- break;
+ window.localStorage[params.title_id + "/save"] = arg
+ break
}
}
}
/* HEADER */
-let is_your_turn = false;
-let old_active = null;
+let is_your_turn = false
+let old_active = null
function on_update_header() {
- document.getElementById("prompt").textContent = view.prompt;
+ document.getElementById("prompt").textContent = view.prompt
if (params.mode === "replay")
- return;
+ return
if (view.actions) {
- document.querySelector("header").classList.add("your_turn");
+ document.querySelector("header").classList.add("your_turn")
if (!is_your_turn || old_active !== view.active)
- start_blinker("YOUR TURN");
- is_your_turn = true;
+ start_blinker("YOUR TURN")
+ is_your_turn = true
} else {
- document.querySelector("header").classList.remove("your_turn");
- is_your_turn = false;
+ document.querySelector("header").classList.remove("your_turn")
+ is_your_turn = false
}
- old_active = view.active;
+ old_active = view.active
}
/* LOG */
function on_update_log() {
- let div = document.getElementById("log");
- let to_delete = div.children.length - view.log_start;
+ let div = document.getElementById("log")
+ let to_delete = div.children.length - view.log_start
while (to_delete-- > 0)
- div.removeChild(div.lastChild);
+ div.removeChild(div.lastChild)
for (let text of view.log) {
if (typeof on_log === 'function') {
- div.appendChild(on_log(text));
+ div.appendChild(on_log(text))
} else {
- let entry = document.createElement("div");
- entry.textContent = text;
- div.appendChild(entry);
+ let entry = document.createElement("div")
+ entry.textContent = text
+ div.appendChild(entry)
}
}
- scroll_log_to_end();
+ scroll_log_to_end()
}
function scroll_log_to_end() {
- let div = document.getElementById("log");
- div.scrollTop = div.scrollHeight;
+ let div = document.getElementById("log")
+ div.scrollTop = div.scrollHeight
}
try {
- new ResizeObserver(scroll_log_to_end).observe(document.getElementById("log"));
+ new ResizeObserver(scroll_log_to_end).observe(document.getElementById("log"))
} catch (err) {
- window.addEventListener("resize", scroll_log_to_end);
+ window.addEventListener("resize", scroll_log_to_end)
}
/* MAP ZOOM */
function toggle_log() {
- document.querySelector("aside").classList.toggle("hide");
- zoom_map();
+ document.querySelector("aside").classList.toggle("hide")
+ zoom_map()
}
function toggle_zoom() {
- let mapwrap = document.getElementById("mapwrap");
+ let mapwrap = document.getElementById("mapwrap")
if (mapwrap) {
- mapwrap.classList.toggle("fit");
- zoom_map();
+ mapwrap.classList.toggle("fit")
+ zoom_map()
}
}
function zoom_map() {
- let mapwrap = document.getElementById("mapwrap");
+ let mapwrap = document.getElementById("mapwrap")
if (mapwrap) {
- let main = document.querySelector("main");
- let map = document.getElementById("map");
- map.style.transform = null;
- mapwrap.style.width = null;
- mapwrap.style.height = null;
+ let main = document.querySelector("main")
+ let map = document.getElementById("map")
+ map.style.transform = null
+ mapwrap.style.width = null
+ mapwrap.style.height = null
if (mapwrap.classList.contains("fit")) {
- let { width: gw, height: gh } = main.getBoundingClientRect();
- let { width: ww, height: wh } = mapwrap.getBoundingClientRect();
- let { width: cw, height: ch } = map.getBoundingClientRect();
- let scale = Math.min(ww / cw, gh / ch);
+ let { width: gw, height: gh } = main.getBoundingClientRect()
+ let { width: ww, height: wh } = mapwrap.getBoundingClientRect()
+ let { width: cw, height: ch } = map.getBoundingClientRect()
+ let scale = Math.min(ww / cw, gh / ch)
if (scale < 1) {
- map.style.transform = "scale(" + scale + ")";
- mapwrap.style.width = (cw * scale) + "px";
- mapwrap.style.height = (ch * scale) + "px";
+ map.style.transform = "scale(" + scale + ")"
+ mapwrap.style.width = (cw * scale) + "px"
+ mapwrap.style.height = (ch * scale) + "px"
}
}
}
}
-window.addEventListener("resize", zoom_map);
+window.addEventListener("resize", zoom_map)
window.addEventListener("keydown", (evt) => {
if (evt.key === "Shift")
- document.querySelector("body").classList.add("shift");
-});
+ document.querySelector("body").classList.add("shift")
+})
window.addEventListener("keyup", (evt) => {
if (evt.key === "Shift")
- document.querySelector("body").classList.remove("shift");
-});
+ document.querySelector("body").classList.remove("shift")
+})
/* ACTIONS */
function action_button_imp(action, label, callback) {
if (params.mode === "replay")
- return;
- let id = action + "_button";
- let button = document.getElementById(id);
+ return
+ let id = action + "_button"
+ let button = document.getElementById(id)
if (!button) {
- button = document.createElement("button");
- button.id = id;
- button.textContent = label;
- button.addEventListener("click", callback);
- document.getElementById("actions").appendChild(button);
+ button = document.createElement("button")
+ button.id = id
+ button.textContent = label
+ button.addEventListener("click", callback)
+ document.getElementById("actions").appendChild(button)
}
if (view.actions && action in view.actions) {
- button.classList.remove("hide");
+ button.classList.remove("hide")
if (view.actions[action]) {
if (label === undefined)
- button.textContent = view.actions[action];
- button.disabled = false;
+ button.textContent = view.actions[action]
+ button.disabled = false
} else {
- button.disabled = true;
+ button.disabled = true
}
} else {
- button.classList.add("hide");
+ button.classList.add("hide")
}
}
function action_button(action, label) {
- action_button_imp(action, label, evt => send_action(action));
+ action_button_imp(action, label, evt => send_action(action))
}
function confirm_action_button(action, label, message) {
- action_button_imp(action, label, evt => confirm_action(message, action));
+ action_button_imp(action, label, evt => confirm_action(message, action))
}
function send_action(verb, noun) {
if (params.mode === "replay")
- return;
+ return
// Reset action list here so we don't send more than one action per server prompt!
if (noun !== undefined) {
- let realnoun = Array.isArray(noun) ? noun[0] : noun;
+ let realnoun = Array.isArray(noun) ? noun[0] : noun
if (view.actions && view.actions[verb] && view.actions[verb].includes(realnoun)) {
- view.actions = null;
- send_message("action", [verb, noun]);
- return true;
+ view.actions = null
+ send_message("action", [verb, noun])
+ return true
}
} else {
if (view.actions && view.actions[verb]) {
- view.actions = null;
- send_message("action", [verb]);
- return true;
+ view.actions = null
+ send_message("action", [verb])
+ return true
}
}
- return false;
+ return false
}
function confirm_action(message, verb, noun) {
if (window.confirm(message))
- send_action(verb, noun);
+ send_action(verb, noun)
}
-let replay_query = null;
+let replay_query = null
function send_query(q, param) {
- if (param !== undefined)
+ if (param !== undefined) {
if (replay_query)
- replay_query(q, param);
+ replay_query(q, param)
else
- send_message("query", [q, param]);
- else
+ send_message("query", [q, param])
+ } else {
if (replay_query)
- replay_query(q, undefined);
+ replay_query(q, undefined)
else
- send_message("query", q);
+ send_message("query", q)
+ }
}
function confirm_resign() {
if (window.confirm("Are you sure that you want to resign?"))
- send_message("resign");
+ send_message("resign")
}
/* MOBILE PHONE LAYOUT */
-let mobile_scroll_header = document.querySelector("header");
-let mobile_scroll_last_y = 0;
+let mobile_scroll_header = document.querySelector("header")
+let mobile_scroll_last_y = 0
window.addEventListener("scroll", function scroll_mobile_fix (evt) {
if (mobile_scroll_header.clientWidth <= 640) {
if (window.scrollY > 40) {
if (mobile_scroll_last_y <= 40)
- mobile_scroll_header.classList.add("mobilefix");
+ mobile_scroll_header.classList.add("mobilefix")
} else {
if (mobile_scroll_last_y > 40)
- mobile_scroll_header.classList.remove("mobilefix");
+ mobile_scroll_header.classList.remove("mobilefix")
}
- mobile_scroll_last_y = window.scrollY;
+ mobile_scroll_last_y = window.scrollY
}
-});
+})
/* DEBUGGING */
function send_save() {
- send_message("save");
+ send_message("save")
}
function send_restore() {
- send_message("restore", window.localStorage[params.title_id + "/save"]);
+ send_message("restore", window.localStorage[params.title_id + "/save"])
}
function send_restart(scenario) {
- send_message("restart", scenario);
+ send_message("restart", scenario)
}
/* REPLAY */
function adler32(data) {
- let a = 1, b = 0;
+ let a = 1, b = 0
for (let i = 0, n = data.length; i < n; ++i) {
- a = (a + data.charCodeAt(i)) % 65521;
- b = (b + a) % 65521;
+ a = (a + data.charCodeAt(i)) % 65521
+ b = (b + a) % 65521
}
- return (b << 16) | a;
+ return (b << 16) | a
}
async function require(path) {
- let cache = {};
+ let cache = {}
if (!path.endsWith(".js"))
- path = path + ".js";
+ path = path + ".js"
if (path.startsWith("./"))
- path = path.substring(2);
+ path = path.substring(2)
- console.log("REQUIRE", path);
+ console.log("REQUIRE", path)
- let response = await fetch(path);
- let source = await response.text();
+ let response = await fetch(path)
+ let source = await response.text()
for (let [_, subpath] of source.matchAll(/require\(['"]([^)]*)['"]\)/g))
if (cache[subpath] === undefined)
- cache[subpath] = await require(subpath);
+ cache[subpath] = await require(subpath)
- let module = { exports: {} };
- Function("module", "exports", "require", source)
- (module, module.exports, path => cache[path]);
- return module.exports;
+ let module = { exports: {} }
+ Function("module", "exports", "require", source)(module, module.exports, path => cache[path])
+ return module.exports
}
-let replay = null;
+let replay = null
async function init_replay() {
- remove_resign_menu();
+ remove_resign_menu()
- document.getElementById("prompt").textContent = "Loading replay...";
+ document.getElementById("prompt").textContent = "Loading replay..."
- console.log("LOADING RULES");
- let rules = await require("rules.js");
+ console.log("LOADING RULES")
+ let rules = await require("rules.js")
- console.log("LOADING REPLAY");
- let response = await fetch("/replay/" + params.game_id);
- let body = await response.json();
- replay = body.replay;
+ console.log("LOADING REPLAY")
+ let response = await fetch("/replay/" + params.game_id)
+ let body = await response.json()
+ replay = body.replay
- init_player_names(body.players);
+ init_player_names(body.players)
- let viewpoint = "Observer";
- let log_length = 0;
- let p = 0;
- let s = {};
+ let viewpoint = "Observer"
+ let log_length = 0
+ let p = 0
+ let s = {}
function eval_action(item) {
switch (item.action) {
case "setup":
- s = rules.setup(item.arguments[0], item.arguments[1], item.arguments[2]);
- break;
+ s = rules.setup(item.arguments[0], item.arguments[1], item.arguments[2])
+ break
case "resign":
- s = rules.resign(s, item.role);
- break;
+ s = rules.resign(s, item.role)
+ break
default:
- s = rules.action(s, item.role, item.action, item.arguments);
- break;
+ s = rules.action(s, item.role, item.action, item.arguments)
+ break
}
}
replay_query = function (query, params) {
- let reply = rules.query(s, player, query, params);
- on_reply(query, reply);
+ let reply = rules.query(s, player, query, params)
+ on_reply(query, reply)
}
- let ss;
+ let ss
for (p = 0; p < replay.length; ++p) {
- replay[p].arguments = JSON.parse(replay[p].arguments);
+ replay[p].arguments = JSON.parse(replay[p].arguments)
if (rules.is_checkpoint) {
- replay[p].is_checkpoint = (p > 0 && rules.is_checkpoint(ss, s));
- ss = Object.assign({}, s);
+ replay[p].is_checkpoint = (p > 0 && rules.is_checkpoint(ss, s))
+ ss = Object.assign({}, s)
}
try {
- eval_action(replay[p]);
+ eval_action(replay[p])
} catch (err) {
- console.log("ERROR IN REPLAY %d %s %s/%s/%s", p, s.state, replay[p].role, replay[p].action, replay[p].arguments);
- console.log(err);
- replay.length = 0;
- break;
+ console.log("ERROR IN REPLAY %d %s %s/%s/%s", p, s.state, replay[p].role, replay[p].action, replay[p].arguments)
+ console.log(err)
+ replay.length = 0
+ break
}
- replay[p].digest = adler32(JSON.stringify(s));
+ replay[p].digest = adler32(JSON.stringify(s))
for (let k = p-1; k > 0; --k) {
if (replay[k].digest === replay[p].digest && !replay[k].is_undone) {
for (let a = k+1; a <= p; ++a)
if (!replay[a].is_undone)
- replay[a].is_undone = true;
- break;
+ replay[a].is_undone = true
+ break
}
}
}
- replay = replay.filter(x => !x.is_undone);
+ replay = replay.filter(x => !x.is_undone)
function set_hash(n) {
- history.replaceState(null, "", window.location.pathname + "#" + n);
+ history.replaceState(null, "", window.location.pathname + "#" + n)
}
- let timer = 0;
+ let timer = 0
function play_pause_replay(evt) {
if (timer === 0) {
- evt.target.textContent = "Stop";
+ evt.target.textContent = "Stop"
timer = setInterval(() => {
if (p < replay.length)
- goto_replay(p+1);
+ goto_replay(p+1)
else
- play_pause_replay(evt);
- }, 1000);
+ play_pause_replay(evt)
+ }, 1000)
} else {
- evt.target.textContent = "Run";
- clearInterval(timer);
- timer = 0;
+ evt.target.textContent = "Run"
+ clearInterval(timer)
+ timer = 0
}
}
function prev() {
for (let i = p - 1; i > 1; --i)
if (replay[i].is_checkpoint)
- return i;
- return 1;
+ return i
+ return 1
}
function next() {
for (let i = p + 1; i < replay.length; ++i)
if (replay[i].is_checkpoint)
- return i;
- return replay.length;
+ return i
+ return replay.length
}
function on_hash_change() {
- goto_replay(parseInt(window.location.hash.slice(1)) || 1);
+ goto_replay(parseInt(window.location.hash.slice(1)) || 1)
}
function goto_replay(np) {
if (np < 1)
- np = 1;
+ np = 1
if (np > replay.length)
- np = replay.length;
- set_hash(np);
+ np = replay.length
+ set_hash(np)
if (p > np)
- p = 0, s = {};
+ p = 0, s = {}
while (p < np)
- eval_action(replay[p++]);
- update_replay_view();
+ eval_action(replay[p++])
+ update_replay_view()
}
function update_replay_view() {
- player = viewpoint;
+ player = viewpoint
if (viewpoint === "Active") {
- player = s.active;
+ player = s.active
if (player === "All" || player === "Both" || player === "None" || !player)
- player = "Observer";
+ player = "Observer"
}
- let body = document.querySelector("body");
- body.classList.remove("Observer");
+ let body = document.querySelector("body")
+ body.classList.remove("Observer")
for (let i = 0; i < roles.length; ++i)
- body.classList.remove(roles[i].role.replace(/ /g, "_"));
- body.classList.add(player.replace(/ /g, "_"));
+ body.classList.remove(roles[i].role.replace(/ /g, "_"))
+ body.classList.add(player.replace(/ /g, "_"))
- view = rules.view(s, player);
- view.actions = null;
+ view = rules.view(s, player)
+ view.actions = null
if (viewpoint === "Observer")
- view.game_over = 1;
+ view.game_over = 1
if (s.state === "game_over")
- view.game_over = 1;
+ view.game_over = 1
if (replay.length > 0) {
if (document.querySelector("body").classList.contains("shift")) {
- view.prompt = `[${p}/${replay.length}] ${s.active} / ${s.state}`;
+ view.prompt = `[${p}/${replay.length}] ${s.active} / ${s.state}`
if (p < replay.length)
- view.prompt += ` / ${replay[p].action} ${replay[p].arguments}`;
+ view.prompt += ` / ${replay[p].action} ${replay[p].arguments}`
} else {
- view.prompt = "[" + p + "/" + replay.length + "] " + view.prompt;
+ view.prompt = "[" + p + "/" + replay.length + "] " + view.prompt
}
}
if (log_length < view.log.length)
- view.log_start = log_length;
+ view.log_start = log_length
else
- view.log_start = view.log.length;
- log_length = view.log.length;
- view.log = view.log.slice(view.log_start);
+ view.log_start = view.log.length
+ log_length = view.log.length
+ view.log = view.log.slice(view.log_start)
- on_update_header();
- on_update();
- on_update_log();
+ on_update_header()
+ on_update()
+ on_update_log()
}
function text_button(div, txt, fn) {
- let button = document.createElement("button");
- button.addEventListener("click", fn);
- button.textContent = txt;
- div.appendChild(button);
- return button;
+ let button = document.createElement("button")
+ button.addEventListener("click", fn)
+ button.textContent = txt
+ div.appendChild(button)
+ return button
}
function set_viewpoint(vp) {
- viewpoint = vp;
- update_replay_view();
+ viewpoint = vp
+ update_replay_view()
}
- let div = document.createElement("div");
- div.className = "replay";
+ let div = document.createElement("div")
+ div.className = "replay"
if (replay.length > 0)
- text_button(div, "Active", () => set_viewpoint("Active"));
+ text_button(div, "Active", () => set_viewpoint("Active"))
for (let r of roles)
- text_button(div, r.role, () => set_viewpoint(r.role));
- text_button(div, "Observer", () => set_viewpoint("Observer"));
- document.querySelector("header").appendChild(div);
+ text_button(div, r.role, () => set_viewpoint(r.role))
+ text_button(div, "Observer", () => set_viewpoint("Observer"))
+ document.querySelector("header").appendChild(div)
if (replay.length > 0) {
- console.log("REPLAY READY");
-
- div = document.createElement("div");
- div.className = "replay";
- text_button(div, "<<<", () => goto_replay(1));
- text_button(div, "<<", () => goto_replay(prev()));
- text_button(div, "<\xa0", () => goto_replay(p-1));
- text_button(div, "\xa0>", () => goto_replay(p+1));
- text_button(div, ">>", () => goto_replay(next()));
- text_button(div, "Run", play_pause_replay).style.width = "65px";
- document.querySelector("header").appendChild(div);
+ console.log("REPLAY READY")
+
+ div = document.createElement("div")
+ div.className = "replay"
+ text_button(div, "<<<", () => goto_replay(1))
+ text_button(div, "<<", () => goto_replay(prev()))
+ text_button(div, "<\xa0", () => goto_replay(p-1))
+ text_button(div, "\xa0>", () => goto_replay(p+1))
+ text_button(div, ">>", () => goto_replay(next()))
+ text_button(div, "Run", play_pause_replay).style.width = "65px"
+ document.querySelector("header").appendChild(div)
if (window.location.hash === "")
- set_hash(replay.length);
+ set_hash(replay.length)
- on_hash_change();
+ on_hash_change()
- window.addEventListener("hashchange", on_hash_change);
+ window.addEventListener("hashchange", on_hash_change)
} else {
- console.log("REPLAY NOT AVAILABLE");
- s = JSON.parse(body.state);
- update_replay_view();
+ console.log("REPLAY NOT AVAILABLE")
+ s = JSON.parse(body.state)
+ update_replay_view()
}
}
window.addEventListener("load", function () {
- zoom_map();
+ zoom_map()
if (params.mode === "replay")
- init_replay();
+ init_replay()
if (params.mode === "play")
- connect_play();
-});
+ connect_play()
+})
function init_home_menu(link, text) {
- let popup = document.querySelector(".menu_popup");
- let sep = document.createElement("div");
- sep.className = "menu_separator";
- popup.insertBefore(sep, popup.firstChild);
- let item = document.createElement("div");
- item.className = "menu_item";
- item.onclick = () => window.open(link, "_self");
- item.textContent = text;
- popup.insertBefore(item, popup.firstChild);
-}
-
-init_home_menu("/games/active", "Go Home");
+ let popup = document.querySelector(".menu_popup")
+ let sep = document.createElement("div")
+ sep.className = "menu_separator"
+ popup.insertBefore(sep, popup.firstChild)
+ let item = document.createElement("div")
+ item.className = "menu_item"
+ item.onclick = () => window.open(link, "_self")
+ item.textContent = text
+ popup.insertBefore(item, popup.firstChild)
+}
+
+init_home_menu("/games/active", "Go Home")
diff --git a/public/sort.js b/public/sort.js
index b98334d..ed243c2 100644
--- a/public/sort.js
+++ b/public/sort.js
@@ -1,67 +1,82 @@
-"use strict";
+"use strict"
function sort_table_column(table, column) {
- const minute = 60000;
- const hour = 60 * minute;
- const day = 24 * hour;
- const week = 7 * day;
+ const minute = 60000
+ const hour = 60 * minute
+ const day = 24 * hour
+ const week = 7 * day
function is_date(s) {
if (s.match(/^\d{4}-\d{2}-\d{2}$/))
- return true;
+ return true
if (s.match(/^\d+ (minutes?|hours?|days|weeks) ago$/))
- return true;
+ return true
if (s.match(/^(Yesterday|now)$/))
- return true;
- return false;
+ return true
+ return false
}
function parse_date(s) {
- if (s.match(/^\d{4}-\d{2}-\d{2}$/)) return new Date(s).valueOf();
- if (s === 'now') return Date.now();
- if (s === 'Yesterday') return Date.now() - day;
- let [ _, value, unit ] = s.match(/^(\d+) (minutes?|hours?|days|weeks) ago$/);
+ if (s.match(/^\d{4}-\d{2}-\d{2}$/))
+ return new Date(s).valueOf()
+ if (s === "now")
+ return Date.now()
+ if (s === "Yesterday")
+ return Date.now() - day
+ let [ _, value, unit ] = s.match(/^(\d+) (minutes?|hours?|days|weeks) ago$/)
switch (unit) {
- default: unit = 0; break;
- case 'minute': case 'minutes': unit = minute; break;
- case 'hours': case 'hours': unit = hour; break;
- case 'days': unit = day; break;
- case 'weeks': unit = week; break;
+ default:
+ unit = 0
+ break
+ case "minute":
+ case "minutes":
+ unit = minute
+ break
+ case "hours":
+ case "hours":
+ unit = hour
+ break
+ case "days":
+ unit = day
+ break
+ case "weeks":
+ unit = week
+ break
}
- return Date.now() - Number(value) * unit;
+ return Date.now() - Number(value) * unit
}
- let tbody = table.querySelector("tbody");
- let rows = Array.from(tbody.querySelectorAll("tr"));
+ let tbody = table.querySelector("tbody")
+ let rows = Array.from(tbody.querySelectorAll("tr"))
rows.sort((row_a, row_b) => {
- let cell_a = row_a.querySelectorAll("td")[column].textContent;
- let cell_b = row_b.querySelectorAll("td")[column].textContent;
+ let cell_a = row_a.querySelectorAll("td")[column].textContent
+ let cell_b = row_b.querySelectorAll("td")[column].textContent
if (is_date(cell_a) && is_date(cell_b)) {
- let age_a = parse_date(cell_a);
- let age_b = parse_date(cell_b);
- if (age_a > age_b) return -1;
- if (age_a < age_b) return 1;
- return 0;
+ let age_a = parse_date(cell_a)
+ let age_b = parse_date(cell_b)
+ if (age_a > age_b) return -1
+ if (age_a < age_b) return 1
+ return 0
} else if (cell_a.match(/^\d+$/) && cell_b.match(/^\d+$/)) {
- cell_a = Number(cell_a);
- cell_b = Number(cell_b);
- if (cell_a > cell_b) return -1;
- if (cell_a < cell_b) return 1;
- return 0;
+ cell_a = Number(cell_a)
+ cell_b = Number(cell_b)
+ if (cell_a > cell_b) return -1
+ if (cell_a < cell_b) return 1
+ return 0
} else {
- if (cell_a > cell_b) return 1;
- if (cell_a < cell_b) return -1;
- return 0;
+ if (cell_a > cell_b) return 1
+ if (cell_a < cell_b) return -1
+ return 0
}
- });
- rows.forEach(row => tbody.appendChild(row));
+ })
+ rows.forEach((row) => tbody.appendChild(row))
}
-document.querySelectorAll("table.sort").forEach(table => {
+document.querySelectorAll("table.sort").forEach((table) => {
table.querySelectorAll("th").forEach((th, column) => {
if (th.textContent !== "") {
- th.addEventListener("click", evt => sort_table_column(table, column));
- th.style.cursor = "pointer";
+ th.addEventListener("click", (evt) => sort_table_column(table, column))
+ th.style.cursor = "pointer"
}
- });
-});
+ })
+})
diff --git a/server.js b/server.js
index dbb11d1..15e2a53 100644
--- a/server.js
+++ b/server.js
@@ -1,62 +1,62 @@
-"use strict";
+"use strict"
-const fs = require('fs');
-const crypto = require('crypto');
-const http = require('http');
-const https = require('https');
-const { WebSocketServer } = require('ws');
-const express = require('express');
-const url = require('url');
-const compression = require('compression');
-const sqlite3 = require('better-sqlite3');
+const fs = require('fs')
+const crypto = require('crypto')
+const http = require('http')
+const https = require('https')
+const { WebSocketServer } = require('ws')
+const express = require('express')
+const url = require('url')
+const compression = require('compression')
+const sqlite3 = require('better-sqlite3')
-require('dotenv').config();
+require('dotenv').config()
-let DEBUG = process.env.DEBUG || 0;
+let DEBUG = process.env.DEBUG || 0
-let HTTP_PORT = process.env.HTTP_PORT || 8080;
-let HTTPS_PORT = process.env.HTTPS_PORT;
+let HTTP_PORT = process.env.HTTP_PORT || 8080
+let HTTPS_PORT = process.env.HTTPS_PORT
-let SITE_HOST = process.env.SITE_HOST || "localhost";
-let SITE_NAME = process.env.SITE_NAME || "Untitled";
-let SITE_URL = process.env.SITE_URL;
+let SITE_HOST = process.env.SITE_HOST || "localhost"
+let SITE_NAME = process.env.SITE_NAME || "Untitled"
+let SITE_URL = process.env.SITE_URL
if (!SITE_URL) {
if (HTTPS_PORT)
- SITE_URL = "https://" + SITE_HOST + ":" + HTTPS_PORT;
+ SITE_URL = "https://" + SITE_HOST + ":" + HTTPS_PORT
else
- SITE_URL = "http://" + SITE_HOST + ":" + HTTP_PORT;
+ SITE_URL = "http://" + SITE_HOST + ":" + HTTP_PORT
}
/*
* Main database.
*/
-let db = new sqlite3(process.env.DATABASE || "./db");
-db.pragma("journal_mode = WAL");
-db.pragma("synchronous = NORMAL");
-db.pragma("foreign_keys = ON");
+let db = new sqlite3(process.env.DATABASE || "./db")
+db.pragma("journal_mode = WAL")
+db.pragma("synchronous = NORMAL")
+db.pragma("foreign_keys = ON")
function SQL(s) {
- return db.prepare(s);
+ return db.prepare(s)
}
/*
* Notification mail setup.
*/
-let mailer = null;
+let mailer = null
if (process.env.MAIL_HOST && process.env.MAIL_PORT && process.env.MAIL_FROM) {
mailer = require("nodemailer").createTransport({
host: process.env.MAIL_HOST,
port: process.env.MAIL_PORT,
ignoreTLS: true
- });
- console.log("Mail notifications enabled: ", mailer.options);
+ })
+ console.log("Mail notifications enabled: ", mailer.options)
} else {
- console.log("Mail notifications disabled.");
+ console.log("Mail notifications disabled.")
mailer = {
sendMail(obj, callback) {
- callback("DID NOT SEND: " + JSON.stringify(obj,0,4));
+ callback("DID NOT SEND: " + JSON.stringify(obj,0,4))
}
}
}
@@ -65,90 +65,90 @@ if (process.env.MAIL_HOST && process.env.MAIL_PORT && process.env.MAIL_FROM) {
* Login session management.
*/
-const COOKIE = (process.env.COOKIE || "login") + "=";
+const COOKIE = (process.env.COOKIE || "login") + "="
-db.exec("delete from logins where expires < julianday()");
-const login_sql_select = SQL("select user_id from logins where sid = ? and expires > julianday()").pluck();
-const login_sql_insert = SQL("insert into logins values (abs(random()) % (1<<48), ?, julianday() + 28) returning sid").pluck();
-const login_sql_delete = SQL("delete from logins where sid = ?");
-const login_sql_touch = SQL("update logins set expires = julianday() + 28 where sid = ? and expires < julianday() + 27");
+db.exec("delete from logins where expires < julianday()")
+const login_sql_select = SQL("select user_id from logins where sid = ? and expires > julianday()").pluck()
+const login_sql_insert = SQL("insert into logins values (abs(random()) % (1<<48), ?, julianday() + 28) returning sid").pluck()
+const login_sql_delete = SQL("delete from logins where sid = ?")
+const login_sql_touch = SQL("update logins set expires = julianday() + 28 where sid = ? and expires < julianday() + 27")
function make_cookie(sid, age) {
if (SITE_HOST !== "localhost")
- return `${COOKIE}${sid}; Path=/; Domain=${SITE_HOST}; Max-Age=${age}; HttpOnly`;
- return `${COOKIE}${sid}; Path=/; Max-Age=${age}; HttpOnly`;
+ return `${COOKIE}${sid}; Path=/; Domain=${SITE_HOST}; Max-Age=${age}; HttpOnly`
+ return `${COOKIE}${sid}; Path=/; Max-Age=${age}; HttpOnly`
}
function login_cookie(req) {
- let c = req.headers.cookie;
+ let c = req.headers.cookie
if (c) {
- let i = c.indexOf(COOKIE);
+ let i = c.indexOf(COOKIE)
if (i >= 0)
- return parseInt(c.substring(i+COOKIE.length));
+ return parseInt(c.substring(i+COOKIE.length))
}
- return 0;
+ return 0
}
function login_insert(res, user_id) {
- let sid = login_sql_insert.get(user_id);
- res.setHeader("Set-Cookie", make_cookie(sid, 2419200));
+ let sid = login_sql_insert.get(user_id)
+ res.setHeader("Set-Cookie", make_cookie(sid, 2419200))
}
function login_touch(res, sid) {
if (login_sql_touch.run(sid).changes === 1)
- res.setHeader("Set-Cookie", make_cookie(sid, 2419200));
+ res.setHeader("Set-Cookie", make_cookie(sid, 2419200))
}
function login_delete(res, sid) {
- login_sql_delete.run(sid);
- res.setHeader("Set-Cookie", make_cookie("", 0));
+ login_sql_delete.run(sid)
+ res.setHeader("Set-Cookie", make_cookie("", 0))
}
/*
* Web server setup.
*/
-express.static.mime.define({ "image/avif": ["avif"] });
+express.static.mime.define({ "image/avif": ["avif"] })
function set_static_headers(res, path) {
if (path.match(/\.(jpg|png|svg|avif|webp|ico|woff2)$/))
- res.setHeader("Cache-Control", "max-age=86400");
+ res.setHeader("Cache-Control", "max-age=86400")
else
- res.setHeader("Cache-Control", "max-age=60");
+ res.setHeader("Cache-Control", "max-age=60")
}
-let app = express();
-app.locals.SITE_NAME = SITE_NAME;
-app.locals.SITE_URL = SITE_URL;
-app.set('x-powered-by', false);
-app.set('etag', false);
-app.set('view engine', 'pug');
+let app = express()
+app.locals.SITE_NAME = SITE_NAME
+app.locals.SITE_URL = SITE_URL
+app.set('x-powered-by', false)
+app.set('etag', false)
+app.set('view engine', 'pug')
-app.use(compression());
-app.use(express.static('public', { redirect: false, etag: false, cacheControl: false, setHeaders: set_static_headers }));
-app.use(express.urlencoded({extended:false}));
+app.use(compression())
+app.use(express.static('public', { redirect: false, etag: false, cacheControl: false, setHeaders: set_static_headers }))
+app.use(express.urlencoded({extended:false}))
-let wss;
+let wss
if (HTTPS_PORT) {
let https_server = https.createServer({
key: fs.readFileSync(process.env.SSL_KEY || "key.pem"),
cert: fs.readFileSync(process.env.SSL_CERT || "cert.pem")
- }, app);
- wss = new WebSocketServer({server: https_server});
- https_server.listen(HTTPS_PORT, "0.0.0.0", () => console.log("Listening to HTTPS on *:" + HTTPS_PORT));
- https_server.keepAliveTimeout = 0;
+ }, app)
+ wss = new WebSocketServer({server: https_server})
+ https_server.listen(HTTPS_PORT, "0.0.0.0", () => console.log("Listening to HTTPS on *:" + HTTPS_PORT))
+ https_server.keepAliveTimeout = 0
// Force HTTPS by redirecting HTTP.
- let redirect_app = express();
- redirect_app.all("*", (req, res) => res.redirect(308, SITE_URL + req.url));
- let redirect_server = http.createServer(redirect_app);
- redirect_server.listen(HTTP_PORT, "0.0.0.0", () => console.log("Redirecting from HTTP on *:" + HTTP_PORT));
+ let redirect_app = express()
+ redirect_app.all("*", (req, res) => res.redirect(308, SITE_URL + req.url))
+ let redirect_server = http.createServer(redirect_app)
+ redirect_server.listen(HTTP_PORT, "0.0.0.0", () => console.log("Redirecting from HTTP on *:" + HTTP_PORT))
} else {
- let http_server = http.createServer(app);
- wss = new WebSocketServer({server: http_server});
- http_server.keepAliveTimeout = 0;
- http_server.listen(HTTP_PORT, "0.0.0.0", () => console.log("Listening to HTTP on *:" + HTTP_PORT));
+ let http_server = http.createServer(app)
+ wss = new WebSocketServer({server: http_server})
+ http_server.keepAliveTimeout = 0
+ http_server.listen(HTTP_PORT, "0.0.0.0", () => console.log("Listening to HTTP on *:" + HTTP_PORT))
}
/*
@@ -156,89 +156,89 @@ if (HTTPS_PORT) {
*/
function random_seed() {
- return crypto.randomInt(1, 0x7ffffffe);
+ return crypto.randomInt(1, 0x7ffffffe)
}
function SLOG(socket, ...msg) {
- let time = new Date().toISOString().substring(11,19);
- let name = (socket.user ? socket.user.name : "guest").padEnd(20);
- let ip = String(socket.ip).padEnd(15);
- let ws = "----------";
+ let time = new Date().toISOString().substring(11,19)
+ let name = (socket.user ? socket.user.name : "guest").padEnd(20)
+ let ip = String(socket.ip).padEnd(15)
+ let ws = "----------"
console.log(time, ip, ws, name, "WS",
socket.title_id,
socket.game_id,
socket.role,
- ...msg);
+ ...msg)
}
function human_date(time) {
- var date = time ? new Date(time + " UTC") : new Date(0);
- var seconds = (Date.now() - date.getTime()) / 1000;
- var days = Math.floor(seconds / 86400);
+ var date = time ? new Date(time + " UTC") : new Date(0)
+ var seconds = (Date.now() - date.getTime()) / 1000
+ var days = Math.floor(seconds / 86400)
if (days === 0) {
- if (seconds < 60) return "Now";
- if (seconds < 120) return "1 minute ago";
- if (seconds < 3600) return Math.floor(seconds / 60) + " minutes ago";
- if (seconds < 7200) return "1 hour ago";
- if (seconds < 86400) return Math.floor(seconds / 3600) + " hours ago";
+ if (seconds < 60) return "Now"
+ if (seconds < 120) return "1 minute ago"
+ if (seconds < 3600) return Math.floor(seconds / 60) + " minutes ago"
+ if (seconds < 7200) return "1 hour ago"
+ if (seconds < 86400) return Math.floor(seconds / 3600) + " hours ago"
}
- if (days === 1) return "Yesterday";
- if (days < 14) return days + " days ago";
- if (days < 31) return Math.floor(days / 7) + " weeks ago";
- return date.toISOString().substring(0,10);
+ if (days === 1) return "Yesterday"
+ if (days < 14) return days + " days ago"
+ if (days < 31) return Math.floor(days / 7) + " weeks ago"
+ return date.toISOString().substring(0,10)
}
function is_email(email) {
- return email.match(/^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/);
+ return email.match(/^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/)
}
function clean_user_name(name) {
- name = name.replace(/^ */,'').replace(/ *$/,'').replace(/ */g,' ');
+ name = name.replace(/^ */,'').replace(/ *$/,'').replace(/ */g,' ')
if (name.length > 50)
- name = name.substring(0, 50);
- return name;
+ name = name.substring(0, 50)
+ return name
}
-const USER_NAME_RE = /^[\p{Alpha}\p{Number}'_-]+( [\p{Alpha}\p{Number}'_-]+)*$/u;
+const USER_NAME_RE = /^[\p{Alpha}\p{Number}'_-]+( [\p{Alpha}\p{Number}'_-]+)*$/u
function is_valid_user_name(name) {
if (name.length < 2)
- return false;
+ return false
if (name.length > 50)
- return false;
- return USER_NAME_RE.test(name);
+ return false
+ return USER_NAME_RE.test(name)
}
function hash_password(password, salt) {
- let hash = crypto.createHash('sha256');
- hash.update(password);
- hash.update(salt);
- return hash.digest('hex');
+ let hash = crypto.createHash('sha256')
+ hash.update(password)
+ hash.update(salt)
+ return hash.digest('hex')
}
function get_avatar(mail) {
if (!mail)
- mail = "foo@example.com";
- let digest = crypto.createHash('md5').update(mail.trim().toLowerCase()).digest('hex');
- return '//www.gravatar.com/avatar/' + digest + '?d=mp';
+ mail = "foo@example.com"
+ let digest = crypto.createHash('md5').update(mail.trim().toLowerCase()).digest('hex')
+ return '//www.gravatar.com/avatar/' + digest + '?d=mp'
}
/*
* USER AUTHENTICATION
*/
-const SQL_BLACKLIST_MAIL = SQL("SELECT EXISTS ( SELECT 1 FROM blacklist_mail WHERE ? LIKE mail )").pluck();
+const SQL_BLACKLIST_MAIL = SQL("SELECT EXISTS ( SELECT 1 FROM blacklist_mail WHERE ? LIKE mail )").pluck()
-const SQL_EXISTS_USER_NAME = SQL("SELECT EXISTS ( SELECT 1 FROM users WHERE name=? )").pluck();
-const SQL_EXISTS_USER_MAIL = SQL("SELECT EXISTS ( SELECT 1 FROM users WHERE mail=? )").pluck();
+const SQL_EXISTS_USER_NAME = SQL("SELECT EXISTS ( SELECT 1 FROM users WHERE name=? )").pluck()
+const SQL_EXISTS_USER_MAIL = SQL("SELECT EXISTS ( SELECT 1 FROM users WHERE mail=? )").pluck()
-const SQL_INSERT_USER = SQL("INSERT INTO users (name,mail,password,salt) VALUES (?,?,?,?) RETURNING user_id,name,mail,notify");
+const SQL_INSERT_USER = SQL("INSERT INTO users (name,mail,password,salt) VALUES (?,?,?,?) RETURNING user_id,name,mail,notify")
-const SQL_SELECT_USER_BY_NAME = SQL("SELECT * FROM user_view WHERE name=?");
-const SQL_SELECT_LOGIN_BY_MAIL = SQL("SELECT * FROM user_login_view WHERE mail=?");
-const SQL_SELECT_LOGIN_BY_NAME = SQL("SELECT * FROM user_login_view WHERE name=?");
-const SQL_SELECT_USER_PROFILE = SQL("SELECT * FROM user_profile_view WHERE name=?");
-const SQL_SELECT_USER_NAME = SQL("SELECT name FROM users WHERE user_id=?").pluck();
+const SQL_SELECT_USER_BY_NAME = SQL("SELECT * FROM user_view WHERE name=?")
+const SQL_SELECT_LOGIN_BY_MAIL = SQL("SELECT * FROM user_login_view WHERE mail=?")
+const SQL_SELECT_LOGIN_BY_NAME = SQL("SELECT * FROM user_login_view WHERE name=?")
+const SQL_SELECT_USER_PROFILE = SQL("SELECT * FROM user_profile_view WHERE name=?")
+const SQL_SELECT_USER_NAME = SQL("SELECT name FROM users WHERE user_id=?").pluck()
const SQL_SELECT_USER_INFO = SQL(`
select
user_id,
@@ -269,329 +269,329 @@ const SQL_SELECT_USER_INFO = SQL(`
from
users
where user_id = ?
- `);
+ `)
-const SQL_OFFLINE_USER = SQL("SELECT * FROM user_view NATURAL JOIN user_last_seen WHERE user_id=? AND datetime('now') > datetime(atime,?)");
+const SQL_OFFLINE_USER = SQL("SELECT * FROM user_view NATURAL JOIN user_last_seen WHERE user_id=? AND datetime('now') > datetime(atime,?)")
-const SQL_SELECT_USER_NOTIFY = SQL("SELECT notify FROM users WHERE user_id=?").pluck();
-const SQL_UPDATE_USER_NOTIFY = SQL("UPDATE users SET notify=? WHERE user_id=?");
-const SQL_UPDATE_USER_NAME = SQL("UPDATE users SET name=? WHERE user_id=?");
-const SQL_UPDATE_USER_MAIL = SQL("UPDATE users SET mail=? WHERE user_id=?");
-const SQL_UPDATE_USER_ABOUT = SQL("UPDATE users SET about=? WHERE user_id=?");
-const SQL_UPDATE_USER_PASSWORD = SQL("UPDATE users SET password=?, salt=? WHERE user_id=?");
-const SQL_UPDATE_USER_LAST_SEEN = SQL("INSERT OR REPLACE INTO user_last_seen (user_id,atime) VALUES (?,datetime('now'))");
+const SQL_SELECT_USER_NOTIFY = SQL("SELECT notify FROM users WHERE user_id=?").pluck()
+const SQL_UPDATE_USER_NOTIFY = SQL("UPDATE users SET notify=? WHERE user_id=?")
+const SQL_UPDATE_USER_NAME = SQL("UPDATE users SET name=? WHERE user_id=?")
+const SQL_UPDATE_USER_MAIL = SQL("UPDATE users SET mail=? WHERE user_id=?")
+const SQL_UPDATE_USER_ABOUT = SQL("UPDATE users SET about=? WHERE user_id=?")
+const SQL_UPDATE_USER_PASSWORD = SQL("UPDATE users SET password=?, salt=? WHERE user_id=?")
+const SQL_UPDATE_USER_LAST_SEEN = SQL("INSERT OR REPLACE INTO user_last_seen (user_id,atime) VALUES (?,datetime('now'))")
-const SQL_FIND_TOKEN = SQL("SELECT token FROM tokens WHERE user_id=? AND datetime('now') < datetime(time, '+5 minutes')").pluck();
-const SQL_CREATE_TOKEN = SQL("INSERT OR REPLACE INTO tokens (user_id,token,time) VALUES (?, lower(hex(randomblob(16))), datetime('now')) RETURNING token").pluck();
-const SQL_VERIFY_TOKEN = SQL("SELECT EXISTS ( SELECT 1 FROM tokens WHERE user_id=? AND datetime('now') < datetime(time, '+20 minutes') AND token=? )").pluck();
+const SQL_FIND_TOKEN = SQL("SELECT token FROM tokens WHERE user_id=? AND datetime('now') < datetime(time, '+5 minutes')").pluck()
+const SQL_CREATE_TOKEN = SQL("INSERT OR REPLACE INTO tokens (user_id,token,time) VALUES (?, lower(hex(randomblob(16))), datetime('now')) RETURNING token").pluck()
+const SQL_VERIFY_TOKEN = SQL("SELECT EXISTS ( SELECT 1 FROM tokens WHERE user_id=? AND datetime('now') < datetime(time, '+20 minutes') AND token=? )").pluck()
function is_blacklisted(mail) {
if (SQL_BLACKLIST_MAIL.get(mail) === 1)
- return true;
- return false;
+ return true
+ return false
}
function parse_user_agent(req) {
- let user_agent = req.headers["user-agent"];
+ let user_agent = req.headers["user-agent"]
if (!user_agent)
- return "Browser";
- let agent = user_agent;
+ return "Browser"
+ let agent = user_agent
if (user_agent.indexOf("Firefox/") >= 0)
- agent = "Firefox";
+ agent = "Firefox"
else if (user_agent.indexOf("Chrome/") >= 0)
- agent = "Chrome";
+ agent = "Chrome"
else if (user_agent.indexOf("Safari/") >= 0)
- agent = "Safari";
+ agent = "Safari"
else if (user_agent.indexOf("Edg/") >= 0)
- agent = "Edge";
+ agent = "Edge"
else if (user_agent.indexOf("OPR/") >= 0)
- agent = "Opera";
+ agent = "Opera"
else if (user_agent.indexOf("Opera") >= 0)
- agent = "Opera";
+ agent = "Opera"
else if (user_agent.indexOf("Googlebot") >= 0)
- agent = "Googlebot";
+ agent = "Googlebot"
else if (user_agent.indexOf("bingbot") >= 0)
- agent = "Bingbot";
+ agent = "Bingbot"
else if (user_agent.indexOf("; MSIE") >= 0)
- agent = "MSIE";
+ agent = "MSIE"
else if (user_agent.indexOf("Trident/") >= 0)
- agent = "MSIE";
+ agent = "MSIE"
else if (user_agent.indexOf("AppleWebKit/") >= 0)
- agent = "AppleWebKit";
+ agent = "AppleWebKit"
if (user_agent.indexOf("Mobile") >= 0)
- return agent + "/M";
- return agent;
+ return agent + "/M"
+ return agent
}
app.use(function (req, res, next) {
- req.user_agent = parse_user_agent(req);
+ req.user_agent = parse_user_agent(req)
if (req.user_agent === "MSIE")
- return res.redirect("/msie.html");
- let ip = req.ip || req.connection.remoteAddress || "0.0.0.0";
- res.setHeader('Cache-Control', 'no-store');
- let sid = login_cookie(req);
+ return res.redirect("/msie.html")
+ let ip = req.ip || req.connection.remoteAddress || "0.0.0.0"
+ res.setHeader('Cache-Control', 'no-store')
+ let sid = login_cookie(req)
if (sid) {
- let user_id = login_sql_select.get(sid);
+ let user_id = login_sql_select.get(sid)
if (user_id) {
- login_touch(res, sid);
- req.user = SQL_SELECT_USER_INFO.get(user_id);
- SQL_UPDATE_USER_LAST_SEEN.run(user_id);
+ login_touch(res, sid)
+ req.user = SQL_SELECT_USER_INFO.get(user_id)
+ SQL_UPDATE_USER_LAST_SEEN.run(user_id)
}
}
// Log non-static accesses.
- let time = new Date().toISOString().substring(11,19);
- let name = (req.user ? req.user.name : "guest").padEnd(20);
- let ua = req.user_agent.padEnd(10);
- ip = String(ip).padEnd(15);
- console.log(time, ip, ua, name, req.method, req.url);
+ let time = new Date().toISOString().substring(11,19)
+ let name = (req.user ? req.user.name : "guest").padEnd(20)
+ let ua = req.user_agent.padEnd(10)
+ ip = String(ip).padEnd(15)
+ console.log(time, ip, ua, name, req.method, req.url)
- return next();
-});
+ return next()
+})
function must_be_logged_in(req, res, next) {
if (!req.user)
- return res.redirect('/login?redirect=' + encodeURIComponent(req.originalUrl));
- return next();
+ return res.redirect('/login?redirect=' + encodeURIComponent(req.originalUrl))
+ return next()
}
app.get('/', function (req, res) {
- res.render('index.pug', { user: req.user, titles: TITLES });
-});
+ res.render('index.pug', { user: req.user, titles: TITLES })
+})
app.get('/about', function (req, res) {
- res.render('about.pug', { user: req.user });
-});
+ res.render('about.pug', { user: req.user })
+})
app.get('/logout', function (req, res) {
- let sid = login_cookie(req);
+ let sid = login_cookie(req)
if (sid)
- login_delete(res, sid);
- res.redirect('/login');
-});
+ login_delete(res, sid)
+ res.redirect('/login')
+})
app.get('/login', function (req, res) {
if (req.user)
- return res.redirect('/');
- res.render('login.pug', { redirect: req.query.redirect || '/profile' });
-});
+ return res.redirect('/')
+ res.render('login.pug', { redirect: req.query.redirect || '/profile' })
+})
app.post('/login', function (req, res) {
- let name_or_mail = req.body.username;
- let password = req.body.password;
- let redirect = req.body.redirect;
+ let name_or_mail = req.body.username
+ let password = req.body.password
+ let redirect = req.body.redirect
if (!is_email(name_or_mail))
- name_or_mail = clean_user_name(name_or_mail);
- let user = SQL_SELECT_LOGIN_BY_NAME.get(name_or_mail);
+ name_or_mail = clean_user_name(name_or_mail)
+ let user = SQL_SELECT_LOGIN_BY_NAME.get(name_or_mail)
if (!user)
- user = SQL_SELECT_LOGIN_BY_MAIL.get(name_or_mail);
+ user = SQL_SELECT_LOGIN_BY_MAIL.get(name_or_mail)
if (!user || is_blacklisted(user.mail) || hash_password(password, user.salt) != user.password)
- return setTimeout(() => res.render('login.pug', { flash: "Invalid login." }), 1000);
- login_insert(res, user.user_id);
- res.redirect(redirect);
-});
+ return setTimeout(() => res.render('login.pug', { flash: "Invalid login." }), 1000)
+ login_insert(res, user.user_id)
+ res.redirect(redirect)
+})
app.get('/signup', function (req, res) {
if (req.user)
- return res.redirect('/');
- res.render('signup.pug');
-});
+ return res.redirect('/')
+ res.render('signup.pug')
+})
app.post('/signup', function (req, res) {
function err(msg) {
- res.render('signup.pug', { flash: msg });
+ res.render('signup.pug', { flash: msg })
}
- let name = req.body.username;
- let mail = req.body.mail;
- let password = req.body.password;
- name = clean_user_name(name);
+ let name = req.body.username
+ let mail = req.body.mail
+ let password = req.body.password
+ name = clean_user_name(name)
if (!is_valid_user_name(name))
- return err("Invalid user name!");
+ return err("Invalid user name!")
if (SQL_EXISTS_USER_NAME.get(name))
- return err("That name is already taken.");
+ return err("That name is already taken.")
if (!is_email(mail) || is_blacklisted(mail))
- return err("Invalid mail address!");
+ return err("Invalid mail address!")
if (SQL_EXISTS_USER_MAIL.get(mail))
- return err("That mail is already taken.");
+ return err("That mail is already taken.")
if (password.length < 4)
- return err("Password is too short!");
+ return err("Password is too short!")
if (password.length > 100)
- return err("Password is too long!");
- let salt = crypto.randomBytes(32).toString('hex');
- let hash = hash_password(password, salt);
- let user = SQL_INSERT_USER.get(name, mail, hash, salt);
- login_insert(res, user.user_id);
- res.redirect('/profile');
-});
+ return err("Password is too long!")
+ let salt = crypto.randomBytes(32).toString('hex')
+ let hash = hash_password(password, salt)
+ let user = SQL_INSERT_USER.get(name, mail, hash, salt)
+ login_insert(res, user.user_id)
+ res.redirect('/profile')
+})
app.get('/forgot-password', function (req, res) {
if (req.user)
- return res.redirect('/');
- res.render('forgot_password.pug');
-});
+ return res.redirect('/')
+ res.render('forgot_password.pug')
+})
app.post('/forgot-password', function (req, res) {
- let mail = req.body.mail;
- let user = SQL_SELECT_LOGIN_BY_MAIL.get(mail);
+ let mail = req.body.mail
+ let user = SQL_SELECT_LOGIN_BY_MAIL.get(mail)
if (user) {
- let token = SQL_FIND_TOKEN.get(user.user_id);
+ let token = SQL_FIND_TOKEN.get(user.user_id)
if (!token) {
- token = SQL_CREATE_TOKEN.get(user.user_id);
- mail_password_reset_token(user, token);
+ token = SQL_CREATE_TOKEN.get(user.user_id)
+ mail_password_reset_token(user, token)
}
- return res.redirect('/reset-password/' + mail);
+ return res.redirect('/reset-password/' + mail)
}
- res.render('forgot_password.pug', { flash: "User not found." });
-});
+ res.render('forgot_password.pug', { flash: "User not found." })
+})
app.get('/reset-password', function (req, res) {
if (req.user)
- return res.redirect('/');
- res.render('reset_password.pug', { mail: "", token: "" });
-});
+ return res.redirect('/')
+ res.render('reset_password.pug', { mail: "", token: "" })
+})
app.get('/reset-password/:mail', function (req, res) {
if (req.user)
- return res.redirect('/');
- let mail = req.params.mail;
- res.render('reset_password.pug', { mail: mail, token: "" });
-});
+ return res.redirect('/')
+ let mail = req.params.mail
+ res.render('reset_password.pug', { mail: mail, token: "" })
+})
app.get('/reset-password/:mail/:token', function (req, res) {
if (req.user)
- return res.redirect('/');
- let mail = req.params.mail;
- let token = req.params.token;
- res.render('reset_password.pug', { mail: mail, token: token });
-});
+ return res.redirect('/')
+ let mail = req.params.mail
+ let token = req.params.token
+ res.render('reset_password.pug', { mail: mail, token: token })
+})
app.post('/reset-password', function (req, res) {
- let mail = req.body.mail;
- let token = req.body.token;
- let password = req.body.password;
+ let mail = req.body.mail
+ let token = req.body.token
+ let password = req.body.password
function err(msg) {
- res.render('reset_password.pug', { mail: mail, token: token });
+ res.render('reset_password.pug', { mail: mail, token: token })
}
- let user = SQL_SELECT_LOGIN_BY_MAIL.get(mail);
+ let user = SQL_SELECT_LOGIN_BY_MAIL.get(mail)
if (!user)
- return err("User not found.");
+ return err("User not found.")
if (password.length < 4)
- return err("Password is too short!");
+ return err("Password is too short!")
if (password.length > 100)
- return err("Password is too long!");
+ return err("Password is too long!")
if (!SQL_VERIFY_TOKEN.get(user.user_id, token))
- return err("Invalid or expired token!");
- let salt = crypto.randomBytes(32).toString('hex');
- let hash = hash_password(password, salt);
- SQL_UPDATE_USER_PASSWORD.run(hash, salt, user.user_id);
- login_insert(res, user.user_id);
- return res.redirect('/profile');
-});
+ return err("Invalid or expired token!")
+ let salt = crypto.randomBytes(32).toString('hex')
+ let hash = hash_password(password, salt)
+ SQL_UPDATE_USER_PASSWORD.run(hash, salt, user.user_id)
+ login_insert(res, user.user_id)
+ return res.redirect('/profile')
+})
app.get('/change-password', must_be_logged_in, function (req, res) {
- res.render('change_password.pug', { user: req.user });
-});
+ res.render('change_password.pug', { user: req.user })
+})
app.post('/change-password', must_be_logged_in, function (req, res) {
- let oldpass = req.body.password;
- let newpass = req.body.newpass;
+ let oldpass = req.body.password
+ let newpass = req.body.newpass
// Get full user record including password and salt
- let user = SQL_SELECT_LOGIN_BY_MAIL.get(req.user.mail);
+ let user = SQL_SELECT_LOGIN_BY_MAIL.get(req.user.mail)
if (newpass.length < 4)
- return res.render('change_password.pug', { user: req.user, flash: "Password is too short!" });
+ return res.render('change_password.pug', { user: req.user, flash: "Password is too short!" })
if (newpass.length > 100)
- return res.render('change_password.pug', { user: req.user, flash: "Password is too long!" });
- let oldhash = hash_password(oldpass, user.salt);
+ return res.render('change_password.pug', { user: req.user, flash: "Password is too long!" })
+ let oldhash = hash_password(oldpass, user.salt)
if (oldhash !== user.password)
- return res.render('change_password.pug', { user: req.user, flash: "Wrong password!" });
- let salt = crypto.randomBytes(32).toString('hex');
- let hash = hash_password(newpass, salt);
- return res.redirect('/profile');
-});
+ return res.render('change_password.pug', { user: req.user, flash: "Wrong password!" })
+ let salt = crypto.randomBytes(32).toString('hex')
+ let hash = hash_password(newpass, salt)
+ return res.redirect('/profile')
+})
/*
* USER PROFILE
*/
app.get('/subscribe', must_be_logged_in, function (req, res) {
- SQL_UPDATE_USER_NOTIFY.run(1, req.user.user_id);
- res.redirect('/profile');
-});
+ SQL_UPDATE_USER_NOTIFY.run(1, req.user.user_id)
+ res.redirect('/profile')
+})
app.get('/unsubscribe', must_be_logged_in, function (req, res) {
- SQL_UPDATE_USER_NOTIFY.run(0, req.user.user_id);
- res.redirect('/profile');
-});
+ SQL_UPDATE_USER_NOTIFY.run(0, req.user.user_id)
+ res.redirect('/profile')
+})
app.get('/change-name', must_be_logged_in, function (req, res) {
- res.render('change_name.pug', { user: req.user });
-});
+ res.render('change_name.pug', { user: req.user })
+})
app.post('/change-name', must_be_logged_in, function (req, res) {
- let newname = clean_user_name(req.body.newname);
+ let newname = clean_user_name(req.body.newname)
if (!is_valid_user_name(newname))
- return res.render('change_name.pug', { user: req.user, flash: "Invalid user name!" });
+ return res.render('change_name.pug', { user: req.user, flash: "Invalid user name!" })
if (SQL_EXISTS_USER_NAME.get(newname))
- return res.render('change_name.pug', { user: req.user, flash: "That name is already taken!" });
- SQL_UPDATE_USER_NAME.run(newname, req.user.user_id);
- return res.redirect('/profile');
-});
+ return res.render('change_name.pug', { user: req.user, flash: "That name is already taken!" })
+ SQL_UPDATE_USER_NAME.run(newname, req.user.user_id)
+ return res.redirect('/profile')
+})
app.get('/change-mail', must_be_logged_in, function (req, res) {
- res.render('change_mail.pug', { user: req.user });
-});
+ res.render('change_mail.pug', { user: req.user })
+})
app.post('/change-mail', must_be_logged_in, function (req, res) {
- let newmail = req.body.newmail;
+ let newmail = req.body.newmail
if (!is_email(newmail))
- res.render('change_mail.pug', { user: req.user, flash: "Invalid mail address!" });
+ res.render('change_mail.pug', { user: req.user, flash: "Invalid mail address!" })
if (SQL_EXISTS_USER_MAIL.get(newmail))
- res.render('change_mail.pug', { user: req.user, flash: "That mail address is already taken!" });
- SQL_UPDATE_USER_MAIL.run(newmail, req.user.user_id);
- return res.redirect('/profile');
-});
+ res.render('change_mail.pug', { user: req.user, flash: "That mail address is already taken!" })
+ SQL_UPDATE_USER_MAIL.run(newmail, req.user.user_id)
+ return res.redirect('/profile')
+})
app.get('/change-about', must_be_logged_in, function (req, res) {
- let about = SQL_SELECT_USER_PROFILE.get(req.user.name).about;
- res.render('change_about.pug', { user: req.user, about: about || "" });
-});
+ let about = SQL_SELECT_USER_PROFILE.get(req.user.name).about
+ res.render('change_about.pug', { user: req.user, about: about || "" })
+})
app.post('/change-about', must_be_logged_in, function (req, res) {
- SQL_UPDATE_USER_ABOUT.run(req.body.about, req.user.user_id);
- return res.redirect('/profile');
-});
+ SQL_UPDATE_USER_ABOUT.run(req.body.about, req.user.user_id)
+ return res.redirect('/profile')
+})
app.get('/user/:who_name', function (req, res) {
- let who = SQL_SELECT_USER_PROFILE.get(req.params.who_name);
+ let who = SQL_SELECT_USER_PROFILE.get(req.params.who_name)
if (who) {
- who.avatar = get_avatar(who.mail);
- who.ctime = human_date(who.ctime);
- who.atime = human_date(who.atime);
- res.render('user.pug', { user: req.user, who: who });
+ who.avatar = get_avatar(who.mail)
+ who.ctime = human_date(who.ctime)
+ who.atime = human_date(who.atime)
+ res.render('user.pug', { user: req.user, who: who })
} else {
- return res.status(404).send("Invalid user name.");
+ return res.status(404).send("Invalid user name.")
}
-});
+})
app.get('/users', function (req, res) {
- let rows = SQL("SELECT * FROM user_profile_view ORDER BY atime DESC").all();
+ let rows = SQL("SELECT * FROM user_profile_view ORDER BY atime DESC").all()
rows.forEach(row => {
- row.avatar = get_avatar(row.mail);
- row.ctime = human_date(row.ctime);
- row.atime = human_date(row.atime);
- });
- res.render('user_list.pug', { user: req.user, user_list: rows });
-});
+ row.avatar = get_avatar(row.mail)
+ row.ctime = human_date(row.ctime)
+ row.atime = human_date(row.atime)
+ })
+ res.render('user_list.pug', { user: req.user, user_list: rows })
+})
app.get('/chat', must_be_logged_in, function (req, res) {
- let chat = SQL_SELECT_USER_CHAT_N.all(req.user.user_id, 12*20);
- res.render('chat.pug', { user: req.user, chat: chat, page_size: 12 });
-});
+ let chat = SQL_SELECT_USER_CHAT_N.all(req.user.user_id, 12*20)
+ res.render('chat.pug', { user: req.user, chat: chat, page_size: 12 })
+})
app.get('/chat/all', must_be_logged_in, function (req, res) {
- let chat = SQL_SELECT_USER_CHAT.all(req.user.user_id);
- res.render('chat.pug', { user: req.user, chat: chat, page_size: 0 });
-});
+ let chat = SQL_SELECT_USER_CHAT.all(req.user.user_id)
+ res.render('chat.pug', { user: req.user, chat: chat, page_size: 0 })
+})
/*
* MESSAGES
@@ -601,57 +601,57 @@ const MESSAGE_LIST_INBOX = SQL(`
SELECT message_id, from_name, subject, time, is_read
FROM message_view
WHERE to_id=? AND is_deleted_from_inbox=0
- ORDER BY message_id DESC`);
+ ORDER BY message_id DESC`)
const MESSAGE_LIST_OUTBOX = SQL(`
SELECT message_id, to_name, subject, time, 1 as is_read
FROM message_view
WHERE from_id=? AND is_deleted_from_outbox=0
- ORDER BY message_id DESC`);
+ ORDER BY message_id DESC`)
-const MESSAGE_FETCH = SQL("SELECT * FROM message_view WHERE message_id=? AND ( from_id=? OR to_id=? )");
-const MESSAGE_SEND = SQL("INSERT INTO messages (from_id,to_id,subject,body) VALUES (?,?,?,?)");
-const MESSAGE_MARK_READ = SQL("UPDATE messages SET is_read=1 WHERE message_id=? AND is_read = 0");
-const MESSAGE_DELETE_INBOX = SQL("UPDATE messages SET is_deleted_from_inbox=1 WHERE message_id=? AND to_id=?");
-const MESSAGE_DELETE_OUTBOX = SQL("UPDATE messages SET is_deleted_from_outbox=1 WHERE message_id=? AND from_id=?");
-const MESSAGE_DELETE_ALL_OUTBOX = SQL("UPDATE messages SET is_deleted_from_outbox=1 WHERE from_id=?");
+const MESSAGE_FETCH = SQL("SELECT * FROM message_view WHERE message_id=? AND ( from_id=? OR to_id=? )")
+const MESSAGE_SEND = SQL("INSERT INTO messages (from_id,to_id,subject,body) VALUES (?,?,?,?)")
+const MESSAGE_MARK_READ = SQL("UPDATE messages SET is_read=1 WHERE message_id=? AND is_read = 0")
+const MESSAGE_DELETE_INBOX = SQL("UPDATE messages SET is_deleted_from_inbox=1 WHERE message_id=? AND to_id=?")
+const MESSAGE_DELETE_OUTBOX = SQL("UPDATE messages SET is_deleted_from_outbox=1 WHERE message_id=? AND from_id=?")
+const MESSAGE_DELETE_ALL_OUTBOX = SQL("UPDATE messages SET is_deleted_from_outbox=1 WHERE from_id=?")
app.get('/inbox', must_be_logged_in, function (req, res) {
- let messages = MESSAGE_LIST_INBOX.all(req.user.user_id);
+ let messages = MESSAGE_LIST_INBOX.all(req.user.user_id)
for (let i = 0; i < messages.length; ++i)
- messages[i].time = human_date(messages[i].time);
+ messages[i].time = human_date(messages[i].time)
res.render('message_inbox.pug', {
user: req.user,
messages: messages,
- });
-});
+ })
+})
app.get('/outbox', must_be_logged_in, function (req, res) {
- let messages = MESSAGE_LIST_OUTBOX.all(req.user.user_id);
+ let messages = MESSAGE_LIST_OUTBOX.all(req.user.user_id)
for (let i = 0; i < messages.length; ++i)
- messages[i].time = human_date(messages[i].time);
+ messages[i].time = human_date(messages[i].time)
res.render('message_outbox.pug', {
user: req.user,
messages: messages,
- });
-});
+ })
+})
app.get('/message/read/:message_id', must_be_logged_in, function (req, res) {
- let message_id = req.params.message_id | 0;
- let message = MESSAGE_FETCH.get(message_id, req.user.user_id, req.user.user_id);
+ let message_id = req.params.message_id | 0
+ let message = MESSAGE_FETCH.get(message_id, req.user.user_id, req.user.user_id)
if (!message)
- return res.status(404).send("Invalid message ID.");
+ return res.status(404).send("Invalid message ID.")
if (message.to_id === req.user.user_id && message.is_read === 0) {
- MESSAGE_MARK_READ.run(message_id);
- req.user.unread --;
+ MESSAGE_MARK_READ.run(message_id)
+ req.user.unread --
}
- message.time = human_date(message.time);
- message.body = linkify_post(message.body);
+ message.time = human_date(message.time)
+ message.body = linkify_post(message.body)
res.render('message_read.pug', {
user: req.user,
message: message,
- });
-});
+ })
+})
app.get('/message/send', must_be_logged_in, function (req, res) {
res.render('message_send.pug', {
@@ -659,24 +659,24 @@ app.get('/message/send', must_be_logged_in, function (req, res) {
to_name: "",
subject: "",
body: "",
- });
-});
+ })
+})
app.get('/message/send/:to_name', must_be_logged_in, function (req, res) {
- let to_name = req.params.to_name;
+ let to_name = req.params.to_name
res.render('message_send.pug', {
user: req.user,
to_name: to_name,
subject: "",
body: "",
- });
-});
+ })
+})
app.post('/message/send', must_be_logged_in, function (req, res) {
- let to_name = req.body.to.trim();
- let subject = req.body.subject.trim();
- let body = req.body.body.trim();
- let to_user = SQL_SELECT_USER_BY_NAME.get(to_name);
+ let to_name = req.body.to.trim()
+ let subject = req.body.subject.trim()
+ let body = req.body.body.trim()
+ let to_user = SQL_SELECT_USER_BY_NAME.get(to_name)
if (!to_user) {
return res.render('message_send.pug', {
user: req.user,
@@ -685,274 +685,274 @@ app.post('/message/send', must_be_logged_in, function (req, res) {
subject: subject,
body: body,
flash: "Cannot find that user."
- });
+ })
}
- let info = MESSAGE_SEND.run(req.user.user_id, to_user.user_id, subject, body);
+ let info = MESSAGE_SEND.run(req.user.user_id, to_user.user_id, subject, body)
if (to_user.notify)
- mail_new_message(to_user, info.lastInsertRowid, req.user.name);
- res.redirect('/inbox');
-});
+ mail_new_message(to_user, info.lastInsertRowid, req.user.name)
+ res.redirect('/inbox')
+})
function quote_body(message) {
- let when = new Date(message.time).toDateString();
- let who = message.from_name;
- let what = message.body.split("\n").join("\n> ");
- return "\n\n" + "On " + when + " " + who + " wrote:\n> " + what + "\n";
+ let when = new Date(message.time).toDateString()
+ let who = message.from_name
+ let what = message.body.split("\n").join("\n> ")
+ return "\n\n" + "On " + when + " " + who + " wrote:\n> " + what + "\n"
}
app.get('/message/reply/:message_id', must_be_logged_in, function (req, res) {
- let message_id = req.params.message_id | 0;
- let message = MESSAGE_FETCH.get(message_id, req.user.user_id, req.user.user_id);
+ let message_id = req.params.message_id | 0
+ let message = MESSAGE_FETCH.get(message_id, req.user.user_id, req.user.user_id)
if (!message)
- return res.status(404).send("Invalid message ID.");
+ return res.status(404).send("Invalid message ID.")
return res.render('message_send.pug', {
user: req.user,
to_id: message.from_id,
to_name: message.from_name,
subject: message.subject.startsWith("Re: ") ? message.subject : "Re: " + message.subject,
body: quote_body(message),
- });
-});
+ })
+})
app.get('/message/delete/:message_id', must_be_logged_in, function (req, res) {
- let message_id = req.params.message_id | 0;
- MESSAGE_DELETE_INBOX.run(message_id, req.user.user_id);
- MESSAGE_DELETE_OUTBOX.run(message_id, req.user.user_id);
- res.redirect('/inbox');
-});
+ let message_id = req.params.message_id | 0
+ MESSAGE_DELETE_INBOX.run(message_id, req.user.user_id)
+ MESSAGE_DELETE_OUTBOX.run(message_id, req.user.user_id)
+ res.redirect('/inbox')
+})
app.get('/outbox/delete', must_be_logged_in, function (req, res) {
- MESSAGE_DELETE_ALL_OUTBOX.run(req.user.user_id);
- res.redirect('/outbox');
-});
+ MESSAGE_DELETE_ALL_OUTBOX.run(req.user.user_id)
+ res.redirect('/outbox')
+})
/*
* FORUM
*/
-const FORUM_PAGE_SIZE = 15;
+const FORUM_PAGE_SIZE = 15
-const FORUM_COUNT_THREADS = SQL("SELECT COUNT(*) FROM threads").pluck();
-const FORUM_LIST_THREADS = SQL("SELECT * FROM thread_view ORDER BY mtime DESC LIMIT ? OFFSET ?");
-const FORUM_GET_THREAD = SQL("SELECT * FROM thread_view WHERE thread_id=?");
-const FORUM_LIST_POSTS = SQL("SELECT * FROM post_view WHERE thread_id=?");
-const FORUM_GET_POST = SQL("SELECT * FROM post_view WHERE post_id=?");
-const FORUM_NEW_THREAD = SQL("INSERT INTO threads (author_id,subject) VALUES (?,?)");
-const FORUM_NEW_POST = SQL("INSERT INTO posts (thread_id,author_id,body) VALUES (?,?,?)");
-const FORUM_EDIT_POST = SQL("UPDATE posts SET body=?, mtime=datetime('now') WHERE post_id=? AND author_id=? RETURNING thread_id").pluck();
+const FORUM_COUNT_THREADS = SQL("SELECT COUNT(*) FROM threads").pluck()
+const FORUM_LIST_THREADS = SQL("SELECT * FROM thread_view ORDER BY mtime DESC LIMIT ? OFFSET ?")
+const FORUM_GET_THREAD = SQL("SELECT * FROM thread_view WHERE thread_id=?")
+const FORUM_LIST_POSTS = SQL("SELECT * FROM post_view WHERE thread_id=?")
+const FORUM_GET_POST = SQL("SELECT * FROM post_view WHERE post_id=?")
+const FORUM_NEW_THREAD = SQL("INSERT INTO threads (author_id,subject) VALUES (?,?)")
+const FORUM_NEW_POST = SQL("INSERT INTO posts (thread_id,author_id,body) VALUES (?,?,?)")
+const FORUM_EDIT_POST = SQL("UPDATE posts SET body=?, mtime=datetime('now') WHERE post_id=? AND author_id=? RETURNING thread_id").pluck()
function show_forum_page(req, res, page) {
- let thread_count = FORUM_COUNT_THREADS.get();
- let page_count = Math.ceil(thread_count / FORUM_PAGE_SIZE);
- let threads = FORUM_LIST_THREADS.all(FORUM_PAGE_SIZE, FORUM_PAGE_SIZE * (page - 1));
+ let thread_count = FORUM_COUNT_THREADS.get()
+ let page_count = Math.ceil(thread_count / FORUM_PAGE_SIZE)
+ let threads = FORUM_LIST_THREADS.all(FORUM_PAGE_SIZE, FORUM_PAGE_SIZE * (page - 1))
for (let thread of threads) {
- thread.ctime = human_date(thread.ctime);
- thread.mtime = human_date(thread.mtime);
+ thread.ctime = human_date(thread.ctime)
+ thread.mtime = human_date(thread.mtime)
}
res.render('forum_view.pug', {
user: req.user,
threads: threads,
current_page: page,
page_count: page_count,
- });
+ })
}
function linkify_post(text) {
- text = text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
+ text = text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;")
text = text.replace(/https?:\/\/\S+/g, (match) => {
if (match.endsWith(".jpg") || match.endsWith(".png") || match.endsWith(".svg"))
- return `<a href="${match}"><img src="${match}"></a>`;
- return `<a href="${match}">${match}</a>`;
- });
- return text;
+ return `<a href="${match}"><img src="${match}"></a>`
+ return `<a href="${match}">${match}</a>`
+ })
+ return text
}
app.get('/forum', function (req, res) {
- show_forum_page(req, res, 1);
-});
+ show_forum_page(req, res, 1)
+})
app.get('/forum/page/:page', function (req, res) {
- show_forum_page(req, res, req.params.page | 0);
-});
+ show_forum_page(req, res, req.params.page | 0)
+})
app.get('/forum/thread/:thread_id', function (req, res) {
- let thread_id = req.params.thread_id | 0;
- let thread = FORUM_GET_THREAD.get(thread_id);
- let posts = FORUM_LIST_POSTS.all(thread_id);
+ let thread_id = req.params.thread_id | 0
+ let thread = FORUM_GET_THREAD.get(thread_id)
+ let posts = FORUM_LIST_POSTS.all(thread_id)
if (!thread)
- return res.status(404).send("Invalid thread ID.");
+ return res.status(404).send("Invalid thread ID.")
for (let i = 0; i < posts.length; ++i) {
- posts[i].body = linkify_post(posts[i].body);
- posts[i].edited = posts[i].mtime !== posts[i].ctime;
- posts[i].ctime = human_date(posts[i].ctime);
- posts[i].mtime = human_date(posts[i].mtime);
+ posts[i].body = linkify_post(posts[i].body)
+ posts[i].edited = posts[i].mtime !== posts[i].ctime
+ posts[i].ctime = human_date(posts[i].ctime)
+ posts[i].mtime = human_date(posts[i].mtime)
}
res.render('forum_thread.pug', {
user: req.user,
thread: thread,
posts: posts,
- });
-});
+ })
+})
app.get('/forum/post', must_be_logged_in, function (req, res) {
res.render('forum_post.pug', {
user: req.user,
- });
-});
+ })
+})
app.post('/forum/post', must_be_logged_in, function (req, res) {
- let user_id = req.user.user_id;
- let subject = req.body.subject.trim();
- let body = req.body.body;
+ let user_id = req.user.user_id
+ let subject = req.body.subject.trim()
+ let body = req.body.body
if (subject.length === 0)
- subject = "Untitled";
- let thread_id = FORUM_NEW_THREAD.run(user_id, subject).lastInsertRowid;
- FORUM_NEW_POST.run(thread_id, user_id, body);
- res.redirect('/forum/thread/'+thread_id);
-});
+ subject = "Untitled"
+ let thread_id = FORUM_NEW_THREAD.run(user_id, subject).lastInsertRowid
+ FORUM_NEW_POST.run(thread_id, user_id, body)
+ res.redirect('/forum/thread/'+thread_id)
+})
app.get('/forum/edit/:post_id', must_be_logged_in, function (req, res) {
// TODO: edit subject if editing first post
- let post_id = req.params.post_id | 0;
- let post = FORUM_GET_POST.get(post_id);
+ let post_id = req.params.post_id | 0
+ let post = FORUM_GET_POST.get(post_id)
if (!post || post.author_id != req.user.user_id)
- return res.status(404).send("Invalid post ID.");
- post.ctime = human_date(post.ctime);
- post.mtime = human_date(post.mtime);
+ return res.status(404).send("Invalid post ID.")
+ post.ctime = human_date(post.ctime)
+ post.mtime = human_date(post.mtime)
res.render('forum_edit.pug', {
user: req.user,
post: post,
- });
-});
+ })
+})
app.post('/forum/edit/:post_id', must_be_logged_in, function (req, res) {
- let user_id = req.user.user_id;
- let post_id = req.params.post_id | 0;
- let body = req.body.body;
- let thread_id = FORUM_EDIT_POST.get(body, post_id, user_id);
- res.redirect('/forum/thread/'+thread_id);
-});
+ let user_id = req.user.user_id
+ let post_id = req.params.post_id | 0
+ let body = req.body.body
+ let thread_id = FORUM_EDIT_POST.get(body, post_id, user_id)
+ res.redirect('/forum/thread/'+thread_id)
+})
app.get('/forum/reply/:post_id', must_be_logged_in, function (req, res) {
- let post_id = req.params.post_id | 0;
- let post = FORUM_GET_POST.get(post_id);
+ let post_id = req.params.post_id | 0
+ let post = FORUM_GET_POST.get(post_id)
if (!post)
- return res.status(404).send("Invalid post ID.");
- let thread = FORUM_GET_THREAD.get(post.thread_id);
- post.body = linkify_post(post.body);
- post.edited = post.mtime !== post.ctime;
- post.ctime = human_date(post.ctime);
- post.mtime = human_date(post.mtime);
+ return res.status(404).send("Invalid post ID.")
+ let thread = FORUM_GET_THREAD.get(post.thread_id)
+ post.body = linkify_post(post.body)
+ post.edited = post.mtime !== post.ctime
+ post.ctime = human_date(post.ctime)
+ post.mtime = human_date(post.mtime)
res.render('forum_reply.pug', {
user: req.user,
thread: thread,
post: post,
- });
-});
+ })
+})
app.post('/forum/reply/:thread_id', must_be_logged_in, function (req, res) {
- let thread_id = req.params.thread_id | 0;
- let user_id = req.user.user_id;
- let body = req.body.body;
- FORUM_NEW_POST.run(thread_id, user_id, body);
- res.redirect('/forum/thread/'+thread_id);
-});
+ let thread_id = req.params.thread_id | 0
+ let user_id = req.user.user_id
+ let body = req.body.body
+ FORUM_NEW_POST.run(thread_id, user_id, body)
+ res.redirect('/forum/thread/'+thread_id)
+})
/*
* GAME LOBBY
*/
-let TITLES = {};
-let RULES = {};
-let HTML_ABOUT = {};
-let HTML_CREATE = {};
+let TITLES = {}
+let RULES = {}
+let HTML_ABOUT = {}
+let HTML_CREATE = {}
function is_open_game(game) {
- return game.status === 0 && !game.is_ready;
+ return game.status === 0 && !game.is_ready
}
function is_ready_game(game) {
- return game.status === 0 && game.is_ready;
+ return game.status === 0 && game.is_ready
}
function is_replacement_game(game) {
- return game.status === 1 && !game.is_ready;
+ return game.status === 1 && !game.is_ready
}
function is_active_game(game) {
- return game.status === 1 && game.is_ready;
+ return game.status === 1 && game.is_ready
}
function is_finished_game(game) {
- return game.status === 2;
+ return game.status === 2
}
function load_rules() {
- const SQL_SELECT_TITLES = SQL("SELECT * FROM titles");
+ const SQL_SELECT_TITLES = SQL("SELECT * FROM titles")
for (let title of SQL_SELECT_TITLES.all()) {
- let title_id = title.title_id;
+ let title_id = title.title_id
if (fs.existsSync(__dirname + "/public/" + title_id + "/rules.js")) {
- console.log("Loading rules for " + title_id);
+ console.log("Loading rules for " + title_id)
try {
- TITLES[title_id] = title;
- RULES[title_id] = require("./public/" + title_id + "/rules.js");
- HTML_ABOUT[title_id] = fs.readFileSync("./public/" + title_id + "/about.html");
- HTML_CREATE[title_id] = fs.readFileSync("./public/" + title_id + "/create.html");
+ TITLES[title_id] = title
+ RULES[title_id] = require("./public/" + title_id + "/rules.js")
+ HTML_ABOUT[title_id] = fs.readFileSync("./public/" + title_id + "/about.html")
+ HTML_CREATE[title_id] = fs.readFileSync("./public/" + title_id + "/create.html")
} catch (err) {
- console.log(err);
+ console.log(err)
}
} else {
- console.log("Cannot find rules for " + title_id);
+ console.log("Cannot find rules for " + title_id)
}
}
}
function get_game_roles(title_id, scenario, options) {
- let roles = RULES[title_id].roles;
+ let roles = RULES[title_id].roles
if (typeof roles === 'function')
- return roles(scenario, options);
- return roles;
+ return roles(scenario, options)
+ return roles
}
-load_rules();
+load_rules()
-const SQL_INSERT_GAME = SQL("INSERT INTO games (owner_id,title_id,scenario,options,is_private,is_random,description) VALUES (?,?,?,?,?,?,?)");
-const SQL_DELETE_GAME = SQL("DELETE FROM games WHERE game_id=? AND owner_id=?");
+const SQL_INSERT_GAME = SQL("INSERT INTO games (owner_id,title_id,scenario,options,is_private,is_random,description) VALUES (?,?,?,?,?,?,?)")
+const SQL_DELETE_GAME = SQL("DELETE FROM games WHERE game_id=? AND owner_id=?")
-const SQL_SELECT_USER_CHAT = SQL("SELECT game_id,time,name,message FROM game_chat_view WHERE game_id IN ( SELECT DISTINCT game_id FROM players WHERE user_id=? ) ORDER BY chat_id DESC").raw();
-const SQL_SELECT_USER_CHAT_N = SQL("SELECT game_id,time,name,message FROM game_chat_view WHERE game_id IN ( SELECT DISTINCT game_id FROM players WHERE user_id=? ) ORDER BY chat_id DESC LIMIT ?").raw();
+const SQL_SELECT_USER_CHAT = SQL("SELECT game_id,time,name,message FROM game_chat_view WHERE game_id IN ( SELECT DISTINCT game_id FROM players WHERE user_id=? ) ORDER BY chat_id DESC").raw()
+const SQL_SELECT_USER_CHAT_N = SQL("SELECT game_id,time,name,message FROM game_chat_view WHERE game_id IN ( SELECT DISTINCT game_id FROM players WHERE user_id=? ) ORDER BY chat_id DESC LIMIT ?").raw()
-const SQL_SELECT_GAME_CHAT = SQL("SELECT chat_id,time,name,message FROM game_chat_view WHERE game_id=? AND chat_id>?").raw();
-const SQL_INSERT_GAME_CHAT = SQL("INSERT INTO game_chat (game_id,user_id,message) VALUES (?,?,?) RETURNING chat_id,time,'',message").raw();
+const SQL_SELECT_GAME_CHAT = SQL("SELECT chat_id,time,name,message FROM game_chat_view WHERE game_id=? AND chat_id>?").raw()
+const SQL_INSERT_GAME_CHAT = SQL("INSERT INTO game_chat (game_id,user_id,message) VALUES (?,?,?) RETURNING chat_id,time,'',message").raw()
-const SQL_SELECT_GAME_STATE = SQL("SELECT state FROM game_state WHERE game_id=?").pluck();
-const SQL_UPDATE_GAME_STATE = SQL("INSERT OR REPLACE INTO game_state (game_id,state,active,mtime) VALUES (?,?,?,datetime('now'))");
-const SQL_UPDATE_GAME_RESULT = SQL("UPDATE games SET status=?, result=? WHERE game_id=?");
-const SQL_UPDATE_GAME_PRIVATE = SQL("UPDATE games SET is_private=1 WHERE game_id=?");
-const SQL_INSERT_REPLAY = SQL("INSERT INTO game_replay (game_id,role,action,arguments) VALUES (?,?,?,?)");
-const SQL_SELECT_REPLAY = SQL("SELECT role,action,arguments FROM game_replay WHERE game_id=?");
+const SQL_SELECT_GAME_STATE = SQL("SELECT state FROM game_state WHERE game_id=?").pluck()
+const SQL_UPDATE_GAME_STATE = SQL("INSERT OR REPLACE INTO game_state (game_id,state,active,mtime) VALUES (?,?,?,datetime('now'))")
+const SQL_UPDATE_GAME_RESULT = SQL("UPDATE games SET status=?, result=? WHERE game_id=?")
+const SQL_UPDATE_GAME_PRIVATE = SQL("UPDATE games SET is_private=1 WHERE game_id=?")
+const SQL_INSERT_REPLAY = SQL("INSERT INTO game_replay (game_id,role,action,arguments) VALUES (?,?,?,?)")
+const SQL_SELECT_REPLAY = SQL("SELECT role,action,arguments FROM game_replay WHERE game_id=?")
-const SQL_SELECT_GAME = SQL("SELECT * FROM games WHERE game_id=?");
-const SQL_SELECT_GAME_VIEW = SQL("SELECT * FROM game_view WHERE game_id=?");
-const SQL_SELECT_GAME_FULL_VIEW = SQL("SELECT * FROM game_full_view WHERE game_id=?");
-const SQL_SELECT_GAME_TITLE = SQL("SELECT title_id FROM games WHERE game_id=?").pluck();
-const SQL_SELECT_GAME_RANDOM = SQL("SELECT is_random FROM games WHERE game_id=?").pluck();
+const SQL_SELECT_GAME = SQL("SELECT * FROM games WHERE game_id=?")
+const SQL_SELECT_GAME_VIEW = SQL("SELECT * FROM game_view WHERE game_id=?")
+const SQL_SELECT_GAME_FULL_VIEW = SQL("SELECT * FROM game_full_view WHERE game_id=?")
+const SQL_SELECT_GAME_TITLE = SQL("SELECT title_id FROM games WHERE game_id=?").pluck()
+const SQL_SELECT_GAME_RANDOM = SQL("SELECT is_random FROM games WHERE game_id=?").pluck()
-const SQL_SELECT_GAME_HAS_TITLE_AND_STATUS = SQL("SELECT 1 FROM games WHERE game_id=? AND title_id=? AND status=?");
+const SQL_SELECT_GAME_HAS_TITLE_AND_STATUS = SQL("SELECT 1 FROM games WHERE game_id=? AND title_id=? AND status=?")
-const SQL_SELECT_PLAYERS = SQL("SELECT * FROM players NATURAL JOIN user_view WHERE game_id=?");
-const SQL_SELECT_PLAYERS_JOIN = SQL("SELECT role, user_id, name FROM players NATURAL JOIN users WHERE game_id=?");
-const SQL_SELECT_PLAYER_ROLE = SQL("SELECT role FROM players WHERE game_id=? AND user_id=?").pluck();
-const SQL_INSERT_PLAYER_ROLE = SQL("INSERT OR IGNORE INTO players (game_id,role,user_id) VALUES (?,?,?)");
-const SQL_DELETE_PLAYER_ROLE = SQL("DELETE FROM players WHERE game_id=? AND role=?");
-const SQL_UPDATE_PLAYER_ROLE = SQL("UPDATE players SET role=? WHERE game_id=? AND role=? AND user_id=?");
+const SQL_SELECT_PLAYERS = SQL("SELECT * FROM players NATURAL JOIN user_view WHERE game_id=?")
+const SQL_SELECT_PLAYERS_JOIN = SQL("SELECT role, user_id, name FROM players NATURAL JOIN users WHERE game_id=?")
+const SQL_SELECT_PLAYER_ROLE = SQL("SELECT role FROM players WHERE game_id=? AND user_id=?").pluck()
+const SQL_INSERT_PLAYER_ROLE = SQL("INSERT OR IGNORE INTO players (game_id,role,user_id) VALUES (?,?,?)")
+const SQL_DELETE_PLAYER_ROLE = SQL("DELETE FROM players WHERE game_id=? AND role=?")
+const SQL_UPDATE_PLAYER_ROLE = SQL("UPDATE players SET role=? WHERE game_id=? AND role=? AND user_id=?")
-const SQL_AUTHORIZE_GAME_ROLE = SQL("SELECT 1 FROM players NATURAL JOIN games WHERE title_id=? AND game_id=? AND role=? AND user_id=?").pluck();
+const SQL_AUTHORIZE_GAME_ROLE = SQL("SELECT 1 FROM players NATURAL JOIN games WHERE title_id=? AND game_id=? AND role=? AND user_id=?").pluck()
-const SQL_SELECT_OPEN_GAMES = SQL("SELECT * FROM games WHERE status=0");
-const SQL_COUNT_OPEN_GAMES = SQL("SELECT COUNT(*) FROM games WHERE owner_id=? AND status=0").pluck();
+const SQL_SELECT_OPEN_GAMES = SQL("SELECT * FROM games WHERE status=0")
+const SQL_COUNT_OPEN_GAMES = SQL("SELECT COUNT(*) FROM games WHERE owner_id=? AND status=0").pluck()
-const SQL_SELECT_REMATCH = SQL("SELECT game_id FROM games WHERE status < 3 AND description=?").pluck();
+const SQL_SELECT_REMATCH = SQL("SELECT game_id FROM games WHERE status < 3 AND description=?").pluck()
const SQL_INSERT_REMATCH = SQL(`
INSERT INTO games
(owner_id, title_id, scenario, options, is_private, is_random, description)
@@ -962,14 +962,14 @@ const SQL_INSERT_REMATCH = SQL(`
WHERE game_id = $game_id AND NOT EXISTS (
SELECT * FROM games WHERE description=$magic
)
-`);
+`)
const QUERY_LIST_PUBLIC_GAMES = SQL(`
SELECT * FROM game_view
WHERE is_private=0 AND status < 2
AND EXISTS ( SELECT 1 FROM players WHERE players.game_id = game_view.game_id )
ORDER BY mtime DESC
- `);
+ `)
const QUERY_LIST_GAMES_OF_TITLE = SQL(`
SELECT * FROM game_view
@@ -977,7 +977,7 @@ const QUERY_LIST_GAMES_OF_TITLE = SQL(`
AND EXISTS ( SELECT 1 FROM players WHERE players.game_id = game_view.game_id )
ORDER BY mtime DESC
LIMIT ?
- `);
+ `)
const QUERY_LIST_ACTIVE_GAMES_OF_USER = SQL(`
select * from game_view
@@ -986,7 +986,7 @@ const QUERY_LIST_ACTIVE_GAMES_OF_USER = SQL(`
and
( status < 2 or mtime > datetime('now', '-7 days') )
order by status asc, mtime desc
- `);
+ `)
const QUERY_LIST_FINISHED_GAMES_OF_USER = SQL(`
select * from game_view
@@ -995,26 +995,26 @@ const QUERY_LIST_FINISHED_GAMES_OF_USER = SQL(`
and
status = 2
order by status asc, mtime desc
- `);
+ `)
function is_active(game, players, user_id) {
if (game.status !== 1 || user_id === 0)
- return false;
- let active = game.active;
+ return false
+ let active = game.active
for (let i = 0; i < players.length; ++i) {
- let p = players[i];
+ let p = players[i]
if ((p.user_id === user_id) && (active === 'All' || active === 'Both' || active === p.role))
- return true;
+ return true
}
- return false;
+ return false
}
function is_shared(game, players, user_id) {
- let n = 0;
+ let n = 0
for (let i = 0; i < players.length; ++i)
if (players[i].user_id === user_id)
- ++n;
- return n > 1;
+ ++n
+ return n > 1
}
function is_solo(players) {
@@ -1023,14 +1023,14 @@ function is_solo(players) {
function format_options(options) {
function to_english(k) {
- if (k === true || k === 1) return 'yes';
- if (k === false) return 'no';
- return k.replace(/_/g, " ").replace(/^\w/, c => c.toUpperCase());
+ if (k === true || k === 1) return 'yes'
+ if (k === false) return 'no'
+ return k.replace(/_/g, " ").replace(/^\w/, c => c.toUpperCase())
}
if (!options || options === '{}')
- return "None";
- options = JSON.parse(options);
- return Object.entries(options||{}).map(([k,v]) => (v === true || v === 1) ? to_english(k) : `${to_english(k)}=${to_english(v)}`).join(", ");
+ return "None"
+ options = JSON.parse(options)
+ return Object.entries(options||{}).map(([k,v]) => (v === true || v === 1) ? to_english(k) : `${to_english(k)}=${to_english(v)}`).join(", ")
}
function annotate_game(game, user_id) {
@@ -1088,21 +1088,21 @@ function annotate_games(games, user_id) {
}
app.get('/profile', must_be_logged_in, function (req, res) {
- req.user.notify = SQL_SELECT_USER_NOTIFY.get(req.user.user_id);
- let avatar = get_avatar(req.user.mail);
+ req.user.notify = SQL_SELECT_USER_NOTIFY.get(req.user.user_id)
+ let avatar = get_avatar(req.user.mail)
res.render('profile.pug', {
user: req.user,
avatar: avatar,
- });
-});
+ })
+})
app.get('/games', function (req, res) {
- res.redirect('/games/public');
-});
+ res.redirect('/games/public')
+})
app.get('/games/active', must_be_logged_in, function (req, res) {
- let games = QUERY_LIST_ACTIVE_GAMES_OF_USER.all({user_id: req.user.user_id});
- annotate_games(games, req.user.user_id);
+ let games = QUERY_LIST_ACTIVE_GAMES_OF_USER.all({user_id: req.user.user_id})
+ annotate_games(games, req.user.user_id)
res.render('games_active.pug', {
user: req.user,
open_games: games.filter(is_open_game),
@@ -1110,24 +1110,24 @@ app.get('/games/active', must_be_logged_in, function (req, res) {
ready_games: games.filter(is_ready_game),
active_games: games.filter(is_active_game),
finished_games: games.filter(is_finished_game),
- });
-});
+ })
+})
app.get('/games/finished', must_be_logged_in, function (req, res) {
- let games = QUERY_LIST_FINISHED_GAMES_OF_USER.all({user_id: req.user.user_id});
- annotate_games(games, req.user.user_id);
+ let games = QUERY_LIST_FINISHED_GAMES_OF_USER.all({user_id: req.user.user_id})
+ annotate_games(games, req.user.user_id)
res.render('games_finished.pug', {
user: req.user,
finished_games: games,
- });
-});
+ })
+})
app.get('/games/public', function (req, res) {
let games = QUERY_LIST_PUBLIC_GAMES.all()
if (req.user)
- annotate_games(games, req.user.user_id);
+ annotate_games(games, req.user.user_id)
else
- annotate_games(games, 0);
+ annotate_games(games, 0)
res.render('games_public.pug', {
user: req.user,
open_games: games.filter(is_open_game),
@@ -1135,21 +1135,21 @@ app.get('/games/public', function (req, res) {
ready_games: games.filter(is_ready_game),
active_games: games.filter(is_active_game),
finished_games: games.filter(is_finished_game),
- });
-});
+ })
+})
app.get('/info/:title_id', function (req, res) {
- return res.redirect('/' + req.params.title_id);
-});
+ return res.redirect('/' + req.params.title_id)
+})
function get_title_page(req, res, title_id) {
- let title = TITLES[title_id];
+ let title = TITLES[title_id]
if (!title)
- return res.status(404).send("Invalid title.");
- let active_games = QUERY_LIST_GAMES_OF_TITLE.all(title_id, 0, 1, 1000);
- let finished_games = QUERY_LIST_GAMES_OF_TITLE.all(title_id, 2, 2, 50);
- annotate_games(active_games, req.user ? req.user.user_id : 0);
- annotate_games(finished_games, req.user ? req.user.user_id : 0);
+ return res.status(404).send("Invalid title.")
+ let active_games = QUERY_LIST_GAMES_OF_TITLE.all(title_id, 0, 1, 1000)
+ let finished_games = QUERY_LIST_GAMES_OF_TITLE.all(title_id, 2, 2, 50)
+ annotate_games(active_games, req.user ? req.user.user_id : 0)
+ annotate_games(finished_games, req.user ? req.user.user_id : 0)
res.render('info.pug', {
user: req.user,
title: title,
@@ -1159,464 +1159,464 @@ function get_title_page(req, res, title_id) {
ready_games: active_games.filter(is_ready_game),
active_games: active_games.filter(is_active_game),
finished_games: finished_games,
- });
+ })
}
for (let title_id in TITLES)
- app.get('/' + title_id, (req, res) => get_title_page(req, res, title_id));
+ app.get('/' + title_id, (req, res) => get_title_page(req, res, title_id))
app.get('/create/:title_id', must_be_logged_in, function (req, res) {
- let title_id = req.params.title_id;
- let title = TITLES[title_id];
+ let title_id = req.params.title_id
+ let title = TITLES[title_id]
if (!title)
- return res.status(404).send("Invalid title.");
+ return res.status(404).send("Invalid title.")
res.render('create.pug', {
user: req.user,
title: title,
scenarios: RULES[title_id].scenarios,
create_html: HTML_CREATE[title_id],
- });
-});
+ })
+})
function options_json_replacer(key, value) {
- if (key === 'scenario') return undefined;
- if (key === 'description') return undefined;
- if (key === 'is_random') return undefined;
- if (key === 'is_private') return undefined;
- if (value === 'true') return true;
- if (value === 'false') return false;
- if (value === '') return undefined;
- return value;
+ if (key === 'scenario') return undefined
+ if (key === 'description') return undefined
+ if (key === 'is_random') return undefined
+ if (key === 'is_private') return undefined
+ if (value === 'true') return true
+ if (value === 'false') return false
+ if (value === '') return undefined
+ return value
}
app.post('/create/:title_id', must_be_logged_in, function (req, res) {
- let title_id = req.params.title_id;
- let descr = req.body.description;
- let priv = req.body.is_private === 'true';
- let rand = req.body.is_random === 'true';
- let user_id = req.user.user_id;
- let scenario = req.body.scenario;
- let options = JSON.stringify(req.body, options_json_replacer);
- let count = SQL_COUNT_OPEN_GAMES.get(user_id);
+ let title_id = req.params.title_id
+ let descr = req.body.description
+ let priv = req.body.is_private === 'true'
+ let rand = req.body.is_random === 'true'
+ let user_id = req.user.user_id
+ let scenario = req.body.scenario
+ let options = JSON.stringify(req.body, options_json_replacer)
+ let count = SQL_COUNT_OPEN_GAMES.get(user_id)
if (count >= 5)
- return res.send("You have too many open games!");
+ return res.send("You have too many open games!")
if (!(title_id in RULES))
- return res.send("Invalid title.");
+ return res.send("Invalid title.")
if (!RULES[title_id].scenarios.includes(scenario))
- return res.send("Invalid scenario.");
- let info = SQL_INSERT_GAME.run(user_id, title_id, scenario, options, priv ? 1 : 0, rand ? 1 : 0, descr);
- res.redirect('/join/'+info.lastInsertRowid);
-});
+ return res.send("Invalid scenario.")
+ let info = SQL_INSERT_GAME.run(user_id, title_id, scenario, options, priv ? 1 : 0, rand ? 1 : 0, descr)
+ res.redirect('/join/'+info.lastInsertRowid)
+})
app.get('/delete/:game_id', must_be_logged_in, function (req, res) {
- let game_id = req.params.game_id;
- let title_id = SQL_SELECT_GAME_TITLE.get(game_id);
- let info = SQL_DELETE_GAME.run(game_id, req.user.user_id);
+ let game_id = req.params.game_id
+ let title_id = SQL_SELECT_GAME_TITLE.get(game_id)
+ let info = SQL_DELETE_GAME.run(game_id, req.user.user_id)
if (info.changes === 0)
- return res.send("Not authorized to delete that game ID.");
+ return res.send("Not authorized to delete that game ID.")
if (info.changes === 1)
- update_join_clients_deleted(game_id);
- res.redirect('/'+title_id);
-});
+ update_join_clients_deleted(game_id)
+ res.redirect('/'+title_id)
+})
function join_rematch(req, res, game_id, role) {
try {
- let is_random = SQL_SELECT_GAME_RANDOM.get(game_id);
+ let is_random = SQL_SELECT_GAME_RANDOM.get(game_id)
if (is_random) {
- let role = SQL_SELECT_PLAYER_ROLE.get(game_id, req.user.user_id);
+ let role = SQL_SELECT_PLAYER_ROLE.get(game_id, req.user.user_id)
if (!role) {
for (let i = 1; i <= 6; ++i) {
- let info = SQL_INSERT_PLAYER_ROLE.run(game_id, 'Random ' + i, req.user.user_id);
+ let info = SQL_INSERT_PLAYER_ROLE.run(game_id, 'Random ' + i, req.user.user_id)
if (info.changes === 1) {
- update_join_clients_players(game_id);
- break;
+ update_join_clients_players(game_id)
+ break
}
}
}
} else {
- let info = SQL_INSERT_PLAYER_ROLE.run(game_id, role, req.user.user_id);
+ let info = SQL_INSERT_PLAYER_ROLE.run(game_id, role, req.user.user_id)
if (info.changes === 1)
- update_join_clients_players(game_id);
+ update_join_clients_players(game_id)
}
} catch (err) {
- console.log(err);
+ console.log(err)
}
- return res.redirect('/join/'+game_id);
+ return res.redirect('/join/'+game_id)
}
app.get('/rematch/:old_game_id/:role', must_be_logged_in, function (req, res) {
- let old_game_id = req.params.old_game_id | 0;
- let role = req.params.role;
- let magic = "\u{1F503} " + old_game_id;
- let new_game_id = 0;
- let info = SQL_INSERT_REMATCH.run({user_id: req.user.user_id, game_id: old_game_id, magic: magic});
+ let old_game_id = req.params.old_game_id | 0
+ let role = req.params.role
+ let magic = "\u{1F503} " + old_game_id
+ let new_game_id = 0
+ let info = SQL_INSERT_REMATCH.run({user_id: req.user.user_id, game_id: old_game_id, magic: magic})
if (info.changes === 1)
- new_game_id = info.lastInsertRowid;
+ new_game_id = info.lastInsertRowid
else
- new_game_id = SQL_SELECT_REMATCH.get(magic);
+ new_game_id = SQL_SELECT_REMATCH.get(magic)
if (new_game_id)
- return join_rematch(req, res, new_game_id, role);
- return res.status(404).send("Can't create or find rematch game!");
-});
+ return join_rematch(req, res, new_game_id, role)
+ return res.status(404).send("Can't create or find rematch game!")
+})
-let join_clients = {};
+let join_clients = {}
function update_join_clients_deleted(game_id) {
- let list = join_clients[game_id];
+ let list = join_clients[game_id]
if (list && list.length > 0) {
for (let {res} of list) {
- res.write("retry: 15000\n");
- res.write("event: deleted\n");
- res.write("data: The game doesn't exist.\n\n");
- res.flush();
+ res.write("retry: 15000\n")
+ res.write("event: deleted\n")
+ res.write("data: The game doesn't exist.\n\n")
+ res.flush()
}
}
}
function update_join_clients_game(game_id) {
- let list = join_clients[game_id];
+ let list = join_clients[game_id]
if (list && list.length > 0) {
- let game = SQL_SELECT_GAME_VIEW.get(game_id);
+ let game = SQL_SELECT_GAME_VIEW.get(game_id)
for (let {res} of list) {
- res.write("retry: 15000\n");
- res.write("event: game\n");
- res.write("data: " + JSON.stringify(game) + "\n\n");
- res.flush();
+ res.write("retry: 15000\n")
+ res.write("event: game\n")
+ res.write("data: " + JSON.stringify(game) + "\n\n")
+ res.flush()
}
}
}
function update_join_clients_players(game_id) {
- let list = join_clients[game_id];
+ let list = join_clients[game_id]
if (list && list.length > 0) {
- let players = SQL_SELECT_PLAYERS_JOIN.all(game_id);
- let ready = RULES[list.title_id].ready(list.scenario, list.options, players);
+ let players = SQL_SELECT_PLAYERS_JOIN.all(game_id)
+ let ready = RULES[list.title_id].ready(list.scenario, list.options, players)
for (let {res} of list) {
- res.write("retry: 15000\n");
- res.write("event: players\n");
- res.write("data: " + JSON.stringify(players) + "\n\n");
- res.write("event: ready\n");
- res.write("data: " + ready + "\n\n");
- res.flush();
+ res.write("retry: 15000\n")
+ res.write("event: players\n")
+ res.write("data: " + JSON.stringify(players) + "\n\n")
+ res.write("event: ready\n")
+ res.write("data: " + ready + "\n\n")
+ res.flush()
}
}
}
app.get('/join/:game_id', must_be_logged_in, function (req, res) {
- let game_id = req.params.game_id | 0;
- let game = SQL_SELECT_GAME_VIEW.get(game_id);
+ let game_id = req.params.game_id | 0
+ let game = SQL_SELECT_GAME_VIEW.get(game_id)
if (!game)
- return res.status(404).send("Invalid game ID.");
- annotate_game(game, req.user.user_id);
- let roles = get_game_roles(game.title_id, game.scenario, game.options);
- let players = SQL_SELECT_PLAYERS_JOIN.all(game_id);
- let ready = (game.status === 0) && RULES[game.title_id].ready(game.scenario, game.options, players);
+ return res.status(404).send("Invalid game ID.")
+ annotate_game(game, req.user.user_id)
+ let roles = get_game_roles(game.title_id, game.scenario, game.options)
+ let players = SQL_SELECT_PLAYERS_JOIN.all(game_id)
+ let ready = (game.status === 0) && RULES[game.title_id].ready(game.scenario, game.options, players)
res.render('join.pug', {
user: req.user,
game: game,
roles: roles,
players: players,
ready: ready,
- });
-});
+ })
+})
app.get('/join-events/:game_id', must_be_logged_in, function (req, res) {
- let game_id = req.params.game_id | 0;
- let game = SQL_SELECT_GAME_VIEW.get(game_id);
- let players = SQL_SELECT_PLAYERS_JOIN.all(game_id);
+ let game_id = req.params.game_id | 0
+ let game = SQL_SELECT_GAME_VIEW.get(game_id)
+ let players = SQL_SELECT_PLAYERS_JOIN.all(game_id)
- res.setHeader("Content-Type", "text/event-stream");
- res.setHeader("Connection", "keep-alive");
+ res.setHeader("Content-Type", "text/event-stream")
+ res.setHeader("Connection", "keep-alive")
if (!game) {
- return res.send("event: deleted\ndata: The game doesn't exist.\n\n");
+ return res.send("event: deleted\ndata: The game doesn't exist.\n\n")
}
if (!(game_id in join_clients)) {
- join_clients[game_id] = [];
- join_clients[game_id].title_id = game.title_id;
- join_clients[game_id].scenario = game.scenario;
- join_clients[game_id].options = JSON.parse(game.options);
+ join_clients[game_id] = []
+ join_clients[game_id].title_id = game.title_id
+ join_clients[game_id].scenario = game.scenario
+ join_clients[game_id].options = JSON.parse(game.options)
}
- join_clients[game_id].push({ res: res, user_id: req.user.user_id});
+ join_clients[game_id].push({ res: res, user_id: req.user.user_id})
res.on('close', () => {
- let list = join_clients[game_id];
- let i = list.findIndex(item => item.res === res);
+ let list = join_clients[game_id]
+ let i = list.findIndex(item => item.res === res)
if (i >= 0)
- list.splice(i, 1);
- });
+ list.splice(i, 1)
+ })
- res.write("retry: 15000\n\n");
- res.write("event: game\n");
- res.write("data: " + JSON.stringify(game) + "\n\n");
- res.write("event: players\n");
- res.write("data: " + JSON.stringify(players) + "\n\n");
- res.flush();
-});
+ res.write("retry: 15000\n\n")
+ res.write("event: game\n")
+ res.write("data: " + JSON.stringify(game) + "\n\n")
+ res.write("event: players\n")
+ res.write("data: " + JSON.stringify(players) + "\n\n")
+ res.flush()
+})
app.post('/join/:game_id/:role', must_be_logged_in, function (req, res) {
- let game_id = req.params.game_id | 0;
- let role = req.params.role;
- let game = SQL_SELECT_GAME.get(game_id);
- let roles = get_game_roles(game.title_id, game.scenario, game.options);
+ let game_id = req.params.game_id | 0
+ let role = req.params.role
+ let game = SQL_SELECT_GAME.get(game_id)
+ let roles = get_game_roles(game.title_id, game.scenario, game.options)
if (game.is_random && game.status === 0) {
- let m = role.match(/^Random (\d+)$/);
+ let m = role.match(/^Random (\d+)$/)
if (!m || Number(m[1]) < 1 || Number(m[1]) > roles.length)
- return res.status(404).send("Invalid role.");
+ return res.status(404).send("Invalid role.")
} else {
if (!roles.includes(role))
- return res.status(404).send("Invalid role.");
+ return res.status(404).send("Invalid role.")
}
- let info = SQL_INSERT_PLAYER_ROLE.run(game_id, role, req.user.user_id);
+ let info = SQL_INSERT_PLAYER_ROLE.run(game_id, role, req.user.user_id)
if (info.changes === 1) {
- update_join_clients_players(game_id);
- res.send("SUCCESS");
+ update_join_clients_players(game_id)
+ res.send("SUCCESS")
} else {
- res.send("Could not join game.");
+ res.send("Could not join game.")
}
-});
+})
app.post('/part/:game_id/:role', must_be_logged_in, function (req, res) {
- let game_id = req.params.game_id | 0;
- let role = req.params.role;
- SQL_DELETE_PLAYER_ROLE.run(game_id, role);
- update_join_clients_players(game_id);
- res.send("SUCCESS");
-});
+ let game_id = req.params.game_id | 0
+ let role = req.params.role
+ SQL_DELETE_PLAYER_ROLE.run(game_id, role)
+ update_join_clients_players(game_id)
+ res.send("SUCCESS")
+})
function assign_random_roles(game, players) {
function pick_random_item(list) {
- let k = crypto.randomInt(list.length);
- let r = list[k];
- list.splice(k, 1);
- return r;
+ let k = crypto.randomInt(list.length)
+ let r = list[k]
+ list.splice(k, 1)
+ return r
}
- let roles = get_game_roles(game.title_id, game.scenario, game.options).slice();
+ let roles = get_game_roles(game.title_id, game.scenario, game.options).slice()
for (let p of players) {
- let old_role = p.role;
- p.role = pick_random_item(roles);
- console.log("ASSIGN ROLE", "(" + p.name + ")", old_role, "->", p.role);
- SQL_UPDATE_PLAYER_ROLE.run(p.role, game.game_id, old_role, p.user_id);
+ let old_role = p.role
+ p.role = pick_random_item(roles)
+ console.log("ASSIGN ROLE", "(" + p.name + ")", old_role, "->", p.role)
+ SQL_UPDATE_PLAYER_ROLE.run(p.role, game.game_id, old_role, p.user_id)
}
}
function start_game(game_id, game) {
- let players = SQL_SELECT_PLAYERS.all(game_id);
+ let players = SQL_SELECT_PLAYERS.all(game_id)
if (!RULES[game.title_id].ready(game.scenario, game.options, players))
- return res.send("Invalid scenario/options/player configuration!");
+ return res.send("Invalid scenario/options/player configuration!")
if (game.is_random) {
- assign_random_roles(game, players);
- players = SQL_SELECT_PLAYERS.all(game_id);
- update_join_clients_players(game_id);
+ assign_random_roles(game, players)
+ players = SQL_SELECT_PLAYERS.all(game_id)
+ update_join_clients_players(game_id)
}
- let options = game.options ? JSON.parse(game.options) : {};
- let seed = random_seed();
- let state = RULES[game.title_id].setup(seed, game.scenario, options, players);
- put_replay(game_id, null, 'setup', [seed, game.scenario, options, players]);
- SQL_UPDATE_GAME_RESULT.run(1, null, game_id);
- SQL_UPDATE_GAME_STATE.run(game_id, JSON.stringify(state), state.active);
+ let options = game.options ? JSON.parse(game.options) : {}
+ let seed = random_seed()
+ let state = RULES[game.title_id].setup(seed, game.scenario, options, players)
+ put_replay(game_id, null, 'setup', [seed, game.scenario, options, players])
+ SQL_UPDATE_GAME_RESULT.run(1, null, game_id)
+ SQL_UPDATE_GAME_STATE.run(game_id, JSON.stringify(state), state.active)
if (is_solo(players))
- SQL_UPDATE_GAME_PRIVATE.run(game_id);
- update_join_clients_game(game_id);
- mail_game_started_notification_to_offline_users(game_id, game.owner_id);
- mail_your_turn_notification_to_offline_users(game_id, null, state.active);
+ SQL_UPDATE_GAME_PRIVATE.run(game_id)
+ update_join_clients_game(game_id)
+ mail_game_started_notification_to_offline_users(game_id, game.owner_id)
+ mail_your_turn_notification_to_offline_users(game_id, null, state.active)
}
app.post('/start/:game_id', must_be_logged_in, function (req, res) {
- let game_id = req.params.game_id | 0;
- let game = SQL_SELECT_GAME.get(game_id);
+ let game_id = req.params.game_id | 0
+ let game = SQL_SELECT_GAME.get(game_id)
if (game.owner_id !== req.user.user_id)
- return res.send("Not authorized to start that game ID.");
+ return res.send("Not authorized to start that game ID.")
if (game.status !== 0)
- return res.send("The game is already started.");
- start_game(game_id, game);
- res.send("SUCCESS");
-});
+ return res.send("The game is already started.")
+ start_game(game_id, game)
+ res.send("SUCCESS")
+})
app.get('/play/:game_id/:role', function (req, res) {
- let game_id = req.params.game_id | 0;
- let role = req.params.role;
- let title = SQL_SELECT_GAME_TITLE.get(game_id);
+ let game_id = req.params.game_id | 0
+ let role = req.params.role
+ let title = SQL_SELECT_GAME_TITLE.get(game_id)
if (!title)
- return res.status(404).send("Invalid game ID.");
- res.redirect('/'+title+'/play:'+game_id+':'+role);
-});
+ return res.status(404).send("Invalid game ID.")
+ res.redirect('/'+title+'/play:'+game_id+':'+role)
+})
app.get('/play/:game_id', function (req, res) {
- let game_id = req.params.game_id | 0;
- let user_id = req.user ? req.user.user_id : 0;
- let title = SQL_SELECT_GAME_TITLE.get(game_id);
+ let game_id = req.params.game_id | 0
+ let user_id = req.user ? req.user.user_id : 0
+ let title = SQL_SELECT_GAME_TITLE.get(game_id)
if (!title)
- return res.status(404).send("Invalid game ID.");
- let role = SQL_SELECT_PLAYER_ROLE.get(game_id, user_id);
+ return res.status(404).send("Invalid game ID.")
+ let role = SQL_SELECT_PLAYER_ROLE.get(game_id, user_id)
if (role)
- res.redirect('/'+title+'/play:'+game_id+':'+role);
+ res.redirect('/'+title+'/play:'+game_id+':'+role)
else
- res.redirect('/'+title+'/play:'+game_id);
-});
+ res.redirect('/'+title+'/play:'+game_id)
+})
app.get('/:title_id/play\::game_id\::role', must_be_logged_in, function (req, res) {
- let user_id = req.user ? req.user.user_id : 0;
- let title_id = req.params.title_id;
- let game_id = req.params.game_id;
- let role = req.params.role;
+ let user_id = req.user ? req.user.user_id : 0
+ let title_id = req.params.title_id
+ let game_id = req.params.game_id
+ let role = req.params.role
if (!SQL_AUTHORIZE_GAME_ROLE.get(title_id, game_id, role, user_id))
- return res.status(404).send("Invalid game ID.");
- return res.sendFile(__dirname + '/public/' + title_id + '/play.html');
-});
+ return res.status(404).send("Invalid game ID.")
+ return res.sendFile(__dirname + '/public/' + title_id + '/play.html')
+})
app.get('/:title_id/play\::game_id', function (req, res) {
- let title_id = req.params.title_id;
- let game_id = req.params.game_id;
- let a_title = SQL_SELECT_GAME_TITLE.get(game_id);
+ let title_id = req.params.title_id
+ let game_id = req.params.game_id
+ let a_title = SQL_SELECT_GAME_TITLE.get(game_id)
if (a_title !== title_id)
- return res.status(404).send("Invalid game ID.");
- return res.sendFile(__dirname + '/public/' + title_id + '/play.html');
-});
+ return res.status(404).send("Invalid game ID.")
+ return res.sendFile(__dirname + '/public/' + title_id + '/play.html')
+})
app.get('/:title_id/replay\::game_id', function (req, res) {
- let title_id = req.params.title_id;
- let game_id = req.params.game_id;
- let game = SQL_SELECT_GAME.get(game_id);
+ let title_id = req.params.title_id
+ let game_id = req.params.game_id
+ let game = SQL_SELECT_GAME.get(game_id)
if (!game)
- return res.status(404).send("Invalid game ID.");
+ return res.status(404).send("Invalid game ID.")
if (game.title_id !== title_id)
- return res.status(404).send("Invalid game ID.");
+ return res.status(404).send("Invalid game ID.")
if (game.status < 2)
- return res.status(404).send("Invalid game ID.");
- return res.sendFile(__dirname + '/public/' + title_id + '/play.html');
-});
+ return res.status(404).send("Invalid game ID.")
+ return res.sendFile(__dirname + '/public/' + title_id + '/play.html')
+})
app.get('/replay/:game_id', function (req, res) {
- let game_id = req.params.game_id;
- let game = SQL_SELECT_GAME.get(game_id);
+ let game_id = req.params.game_id
+ let game = SQL_SELECT_GAME.get(game_id)
if (game.status < 2)
- return res.status(404).send("Invalid game ID.");
- let players = SQL_SELECT_PLAYERS_JOIN.all(game_id);
- let state = SQL_SELECT_GAME_STATE.get(game_id);
- let replay = SQL_SELECT_REPLAY.all(game_id);
- return res.json({players, state, replay});
-});
+ return res.status(404).send("Invalid game ID.")
+ let players = SQL_SELECT_PLAYERS_JOIN.all(game_id)
+ let state = SQL_SELECT_GAME_STATE.get(game_id)
+ let replay = SQL_SELECT_REPLAY.all(game_id)
+ return res.json({players, state, replay})
+})
/*
* MAIL NOTIFICATIONS
*/
-const MAIL_FROM = process.env.MAIL_FROM || "user@localhost";
-const MAIL_FOOTER = "\n--\nYou can unsubscribe from notifications on your profile page:\n" + SITE_URL + "/profile\n";
+const MAIL_FROM = process.env.MAIL_FROM || "user@localhost"
+const MAIL_FOOTER = "\n--\nYou can unsubscribe from notifications on your profile page:\n" + SITE_URL + "/profile\n"
-const SQL_SELECT_NOTIFIED = SQL("SELECT datetime('now') < datetime(time,?) FROM last_notified WHERE game_id=? AND user_id=?").pluck();
-const SQL_INSERT_NOTIFIED = SQL("INSERT OR REPLACE INTO last_notified (game_id,user_id,time) VALUES (?,?,datetime('now'))");
-const SQL_DELETE_NOTIFIED = SQL("DELETE FROM last_notified WHERE game_id=? AND user_id=?");
+const SQL_SELECT_NOTIFIED = SQL("SELECT datetime('now') < datetime(time,?) FROM last_notified WHERE game_id=? AND user_id=?").pluck()
+const SQL_INSERT_NOTIFIED = SQL("INSERT OR REPLACE INTO last_notified (game_id,user_id,time) VALUES (?,?,datetime('now'))")
+const SQL_DELETE_NOTIFIED = SQL("DELETE FROM last_notified WHERE game_id=? AND user_id=?")
-const QUERY_LIST_YOUR_TURN = SQL("SELECT * FROM your_turn_reminder");
+const QUERY_LIST_YOUR_TURN = SQL("SELECT * FROM your_turn_reminder")
function mail_callback(err, info) {
if (err)
- console.log("MAIL ERROR", err);
+ console.log("MAIL ERROR", err)
}
function mail_addr(user) {
- return user.name + " <" + user.mail + ">";
+ return user.name + " <" + user.mail + ">"
}
function mail_game_info(game) {
- let desc = `Game: ${game.title_name}\n`;
- desc += `Scenario: ${game.scenario}\n`;
- desc += `Players: ${game.player_names}\n`;
+ let desc = `Game: ${game.title_name}\n`
+ desc += `Scenario: ${game.scenario}\n`
+ desc += `Players: ${game.player_names}\n`
if (game.description.length > 0)
- desc += `Description: ${game.description}\n`;
- return desc + "\n";
+ desc += `Description: ${game.description}\n`
+ return desc + "\n"
}
function mail_game_link(game_id, user) {
- return SITE_URL + "/play/" + game_id + "/" + encodeURI(user.role) + "\n";
+ return SITE_URL + "/play/" + game_id + "/" + encodeURI(user.role) + "\n"
}
function mail_password_reset_token(user, token) {
if (mailer) {
- let subject = "Password reset request";
+ let subject = "Password reset request"
let body =
"Your password reset token is: " + token + "\n\n" +
SITE_URL + "/reset-password/" + user.mail + "/" + token + "\n\n" +
- "If you did not request a password reset you can ignore this mail.\n";
- console.log("SENT MAIL:", mail_addr(user), subject);
- mailer.sendMail({ from: MAIL_FROM, to: mail_addr(user), subject: subject, text: body }, mail_callback);
+ "If you did not request a password reset you can ignore this mail.\n"
+ console.log("SENT MAIL:", mail_addr(user), subject)
+ mailer.sendMail({ from: MAIL_FROM, to: mail_addr(user), subject: subject, text: body }, mail_callback)
}
}
function mail_new_message(user, msg_id, msg_from) {
if (mailer) {
- let subject = "You have a new message from " + msg_from + ".";
+ let subject = "You have a new message from " + msg_from + "."
let body =
"Read the message here:\n" +
SITE_URL + "/message/read/" + msg_id + "\n" +
- MAIL_FOOTER;
- console.log("SENT MAIL:", mail_addr(user), subject);
- mailer.sendMail({ from: MAIL_FROM, to: mail_addr(user), subject: subject, text: body }, mail_callback);
+ MAIL_FOOTER
+ console.log("SENT MAIL:", mail_addr(user), subject)
+ mailer.sendMail({ from: MAIL_FROM, to: mail_addr(user), subject: subject, text: body }, mail_callback)
}
}
function mail_game_started_notification(user, game_id) {
if (mailer) {
- let game = SQL_SELECT_GAME_FULL_VIEW.get(game_id);
- let subject = `${game.title_name} #${game_id} (${user.role}) - Started!`;
+ let game = SQL_SELECT_GAME_FULL_VIEW.get(game_id)
+ let subject = `${game.title_name} #${game_id} (${user.role}) - Started!`
let body = mail_game_info(game) +
"The game has started!\n\n" +
mail_game_link(game_id, user) +
- MAIL_FOOTER;
- console.log("SENT MAIL:", mail_addr(user), subject);
- mailer.sendMail({ from: MAIL_FROM, to: mail_addr(user), subject: subject, text: body }, mail_callback);
+ MAIL_FOOTER
+ console.log("SENT MAIL:", mail_addr(user), subject)
+ mailer.sendMail({ from: MAIL_FROM, to: mail_addr(user), subject: subject, text: body }, mail_callback)
}
}
function mail_game_over_notification(user, game_id, result, victory) {
if (mailer) {
- let game = SQL_SELECT_GAME_FULL_VIEW.get(game_id);
- let subject = `${game.title_name} #${game_id} (${user.role}) - Finished!`;
+ let game = SQL_SELECT_GAME_FULL_VIEW.get(game_id)
+ let subject = `${game.title_name} #${game_id} (${user.role}) - Finished!`
let body = mail_game_info(game) +
victory + "\n\n" +
mail_game_link(game_id, user) +
- MAIL_FOOTER;
- console.log("SENT MAIL:", mail_addr(user), subject);
- mailer.sendMail({ from: MAIL_FROM, to: mail_addr(user), subject: subject, text: body }, mail_callback);
+ MAIL_FOOTER
+ console.log("SENT MAIL:", mail_addr(user), subject)
+ mailer.sendMail({ from: MAIL_FROM, to: mail_addr(user), subject: subject, text: body }, mail_callback)
}
}
function mail_your_turn_notification(user, game_id, interval) {
if (mailer) {
- let too_soon = SQL_SELECT_NOTIFIED.get(interval, game_id, user.user_id);
+ let too_soon = SQL_SELECT_NOTIFIED.get(interval, game_id, user.user_id)
if (!too_soon) {
- SQL_INSERT_NOTIFIED.run(game_id, user.user_id);
- let game = SQL_SELECT_GAME_FULL_VIEW.get(game_id);
- let subject = `${game.title_name} #${game_id} (${user.role}) - Your turn!`;
+ SQL_INSERT_NOTIFIED.run(game_id, user.user_id)
+ let game = SQL_SELECT_GAME_FULL_VIEW.get(game_id)
+ let subject = `${game.title_name} #${game_id} (${user.role}) - Your turn!`
let body = mail_game_info(game) +
"It's your turn.\n\n" +
mail_game_link(game_id, user) +
- MAIL_FOOTER;
- console.log("SENT MAIL:", mail_addr(user), subject);
- mailer.sendMail({ from: MAIL_FROM, to: mail_addr(user), subject: subject, text: body }, mail_callback);
+ MAIL_FOOTER
+ console.log("SENT MAIL:", mail_addr(user), subject)
+ mailer.sendMail({ from: MAIL_FROM, to: mail_addr(user), subject: subject, text: body }, mail_callback)
}
}
}
function reset_your_turn_notification(user, game_id) {
- SQL_DELETE_NOTIFIED.run(game_id, user.user_id);
+ SQL_DELETE_NOTIFIED.run(game_id, user.user_id)
}
function mail_ready_to_start_notification(user, game_id, interval) {
if (mailer) {
- let too_soon = SQL_SELECT_NOTIFIED.get(interval, game_id, user.user_id);
+ let too_soon = SQL_SELECT_NOTIFIED.get(interval, game_id, user.user_id)
if (!too_soon) {
- SQL_INSERT_NOTIFIED.run(game_id, user.user_id);
- let game = SQL_SELECT_GAME_FULL_VIEW.get(game_id);
- let subject = `${game.title_name} #${game_id} - Ready to start!`;
+ SQL_INSERT_NOTIFIED.run(game_id, user.user_id)
+ let game = SQL_SELECT_GAME_FULL_VIEW.get(game_id)
+ let subject = `${game.title_name} #${game_id} - Ready to start!`
let body = mail_game_info(game) +
"Your game is ready to start.\n\n" +
SITE_URL + "/join/" + game_id + "\n" +
- MAIL_FOOTER;
- console.log("SENT MAIL:", mail_addr(user), subject);
- mailer.sendMail({ from: MAIL_FROM, to: mail_addr(user), subject: subject, text: body }, mail_callback);
+ MAIL_FOOTER
+ console.log("SENT MAIL:", mail_addr(user), subject)
+ mailer.sendMail({ from: MAIL_FROM, to: mail_addr(user), subject: subject, text: body }, mail_callback)
}
}
}
@@ -1624,390 +1624,410 @@ function mail_ready_to_start_notification(user, game_id, interval) {
function mail_your_turn_notification_to_offline_users(game_id, old_active, active) {
// Only send notifications when the active player changes.
if (old_active === active)
- return;
+ return
- let players = SQL_SELECT_PLAYERS.all(game_id);
+ let players = SQL_SELECT_PLAYERS.all(game_id)
for (let p of players) {
if (p.notify) {
- let p_was_active = (old_active === p.role || old_active === 'Both' || old_active === 'All');
- let p_is_active = (active === p.role || active === 'Both' || active === 'All');
+ let p_was_active = (old_active === p.role || old_active === 'Both' || old_active === 'All')
+ let p_is_active = (active === p.role || active === 'Both' || active === 'All')
if (!p_was_active && p_is_active) {
if (is_online(game_id, p.user_id)) {
- reset_your_turn_notification(p, game_id);
+ reset_your_turn_notification(p, game_id)
} else {
- mail_your_turn_notification(p, game_id, '+15 minutes');
+ mail_your_turn_notification(p, game_id, '+15 minutes')
}
} else {
- reset_your_turn_notification(p, game_id);
+ reset_your_turn_notification(p, game_id)
}
}
}
}
function mail_game_started_notification_to_offline_users(game_id, owner_id) {
- let players = SQL_SELECT_PLAYERS.all(game_id);
+ let players = SQL_SELECT_PLAYERS.all(game_id)
for (let p of players)
if (p.notify && !is_online(game_id, p.user_id))
- mail_game_started_notification(p, game_id);
+ mail_game_started_notification(p, game_id)
}
function mail_game_over_notification_to_offline_users(game_id, result, victory) {
- let players = SQL_SELECT_PLAYERS.all(game_id);
+ let players = SQL_SELECT_PLAYERS.all(game_id)
for (let p of players)
if (p.notify && !is_online(game_id, p.user_id))
- mail_game_over_notification(p, game_id, result, victory);
+ mail_game_over_notification(p, game_id, result, victory)
}
function notify_your_turn_reminder() {
for (let item of QUERY_LIST_YOUR_TURN.all()) {
- mail_your_turn_notification(item, item.game_id, '+25 hours');
+ mail_your_turn_notification(item, item.game_id, '+25 hours')
}
}
function notify_ready_to_start_reminder() {
for (let game of SQL_SELECT_OPEN_GAMES.all()) {
- let players = SQL_SELECT_PLAYERS.all(game.game_id);
- let rules = RULES[game.title_id];
+ let players = SQL_SELECT_PLAYERS.all(game.game_id)
+ let rules = RULES[game.title_id]
if (rules && rules.ready(game.scenario, game.options, players)) {
- let owner = SQL_OFFLINE_USER.get(game.owner_id, '+3 minutes');
+ let owner = SQL_OFFLINE_USER.get(game.owner_id, '+3 minutes')
if (owner) {
if (owner.notify)
- mail_ready_to_start_notification(owner, game.game_id, '+25 hours');
+ mail_ready_to_start_notification(owner, game.game_id, '+25 hours')
}
}
}
}
// Check and send daily 'your turn' reminders every 15 minutes.
-setInterval(notify_your_turn_reminder, 15 * 60 * 1000);
+setInterval(notify_your_turn_reminder, 15 * 60 * 1000)
// Check and send ready to start notifications every 5 minutes.
-setInterval(notify_ready_to_start_reminder, 5 * 60 * 1000);
+setInterval(notify_ready_to_start_reminder, 5 * 60 * 1000)
/*
* GAME SERVER
*/
-let clients = {};
+let clients = {}
function is_online(game_id, user_id) {
if (clients[game_id])
for (let other of clients[game_id])
if (other.user && other.user.user_id === user_id)
- return true;
+ return true
if (join_clients[game_id])
for (let other of join_clients[game_id])
if (other.user_id === user_id)
- return true;
- return false;
+ return true
+ return false
}
function send_message(socket, cmd, arg) {
- socket.send(JSON.stringify([cmd, arg]));
+ socket.send(JSON.stringify([cmd, arg]))
}
function send_state(socket, state) {
try {
- let view = socket.rules.view(state, socket.role);
+ let view = socket.rules.view(state, socket.role)
if (socket.seen < view.log.length)
- view.log_start = socket.seen;
+ view.log_start = socket.seen
else
- view.log_start = view.log.length;
- socket.seen = view.log.length;
- view.log = view.log.slice(view.log_start);
+ view.log_start = view.log.length
+ socket.seen = view.log.length
+ view.log = view.log.slice(view.log_start)
if (state.state === 'game_over')
- view.game_over = 1;
- view = JSON.stringify(['state', view]);
+ view.game_over = 1
+ view = JSON.stringify(['state', view])
if (socket.last_view !== view) {
- socket.send(view);
- socket.last_view = view;
+ socket.send(view)
+ socket.last_view = view
}
} catch (err) {
- console.log(err);
- return send_message(socket, 'error', err.toString());
+ console.log(err)
+ return send_message(socket, 'error', err.toString())
}
}
function get_game_state(game_id) {
- let game_state = SQL_SELECT_GAME_STATE.get(game_id);
+ let game_state = SQL_SELECT_GAME_STATE.get(game_id)
if (!game_state)
- throw new Error("No game with that ID");
- return JSON.parse(game_state);
+ throw new Error("No game with that ID")
+ return JSON.parse(game_state)
}
function put_game_state(game_id, state, old_active) {
if (state.state === 'game_over') {
- SQL_UPDATE_GAME_RESULT.run(2, state.result, game_id);
- mail_game_over_notification_to_offline_users(game_id, state.result, state.victory);
+ SQL_UPDATE_GAME_RESULT.run(2, state.result, game_id)
+ mail_game_over_notification_to_offline_users(game_id, state.result, state.victory)
}
- SQL_UPDATE_GAME_STATE.run(game_id, JSON.stringify(state), state.active);
+ SQL_UPDATE_GAME_STATE.run(game_id, JSON.stringify(state), state.active)
for (let other of clients[game_id])
- send_state(other, state);
- update_join_clients_game(game_id);
- mail_your_turn_notification_to_offline_users(game_id, old_active, state.active);
+ send_state(other, state)
+ update_join_clients_game(game_id)
+ mail_your_turn_notification_to_offline_users(game_id, old_active, state.active)
}
function put_replay(game_id, role, action, args) {
if (args !== undefined && args !== null)
- args = JSON.stringify(args);
- SQL_INSERT_REPLAY.run(game_id, role, action, args);
+ args = JSON.stringify(args)
+ SQL_INSERT_REPLAY.run(game_id, role, action, args)
}
function on_action(socket, action, arg) {
if (arg !== undefined)
- SLOG(socket, "ACTION", action, JSON.stringify(arg));
+ SLOG(socket, "ACTION", action, JSON.stringify(arg))
else
- SLOG(socket, "ACTION", action);
+ SLOG(socket, "ACTION", action)
try {
- let state = get_game_state(socket.game_id);
- let old_active = state.active;
- state = socket.rules.action(state, socket.role, action, arg);
- put_game_state(socket.game_id, state, old_active);
- put_replay(socket.game_id, socket.role, action, arg);
+ let state = get_game_state(socket.game_id)
+ let old_active = state.active
+ state = socket.rules.action(state, socket.role, action, arg)
+ put_game_state(socket.game_id, state, old_active)
+ put_replay(socket.game_id, socket.role, action, arg)
} catch (err) {
- console.log(err);
- return send_message(socket, 'error', err.toString());
+ console.log(err)
+ return send_message(socket, 'error', err.toString())
}
}
function on_query(socket, q) {
- let params = undefined;
+ let params = undefined
if (Array.isArray(q)) {
- params = q[1];
- q = q[0];
+ params = q[1]
+ q = q[0]
}
if (params !== undefined)
- SLOG(socket, "QUERY", q, JSON.stringify(params));
+ SLOG(socket, "QUERY", q, JSON.stringify(params))
else
- SLOG(socket, "QUERY", q);
+ SLOG(socket, "QUERY", q)
try {
if (socket.rules.query) {
- let state = get_game_state(socket.game_id);
- let reply = socket.rules.query(state, socket.role, q, params);
- send_message(socket, 'reply', [q, reply]);
+ let state = get_game_state(socket.game_id)
+ let reply = socket.rules.query(state, socket.role, q, params)
+ send_message(socket, 'reply', [q, reply])
}
} catch (err) {
- console.log(err);
- return send_message(socket, 'error', err.toString());
+ console.log(err)
+ return send_message(socket, 'error', err.toString())
}
}
function on_resign(socket) {
- SLOG(socket, "RESIGN");
+ SLOG(socket, "RESIGN")
try {
- let state = get_game_state(socket.game_id);
- let old_active = state.active;
+ let state = get_game_state(socket.game_id)
+ let old_active = state.active
// TODO: shared "resign" function
- state = socket.rules.resign(state, socket.role);
- put_game_state(socket.game_id, state, old_active);
- put_replay(socket.game_id, socket.role, 'resign', null);
+ state = socket.rules.resign(state, socket.role)
+ put_game_state(socket.game_id, state, old_active)
+ put_replay(socket.game_id, socket.role, 'resign', null)
} catch (err) {
- console.log(err);
- return send_message(socket, 'error', err.toString());
+ console.log(err)
+ return send_message(socket, 'error', err.toString())
}
}
function on_getchat(socket, seen) {
try {
- let chat = SQL_SELECT_GAME_CHAT.all(socket.game_id, seen);
+ let chat = SQL_SELECT_GAME_CHAT.all(socket.game_id, seen)
if (chat.length > 0)
- SLOG(socket, "GETCHAT", seen, chat.length);
+ SLOG(socket, "GETCHAT", seen, chat.length)
for (let i = 0; i < chat.length; ++i)
- send_message(socket, 'chat', chat[i]);
+ send_message(socket, 'chat', chat[i])
} catch (err) {
- console.log(err);
- return send_message(socket, 'error', err.toString());
+ console.log(err)
+ return send_message(socket, 'error', err.toString())
}
}
function on_chat(socket, message) {
- message = message.substring(0,4000);
+ message = message.substring(0,4000)
try {
- let chat = SQL_INSERT_GAME_CHAT.get(socket.game_id, socket.user.user_id, message);
- chat[2] = socket.user.name;
- SLOG(socket, "CHAT");
+ let chat = SQL_INSERT_GAME_CHAT.get(socket.game_id, socket.user.user_id, message)
+ chat[2] = socket.user.name
+ SLOG(socket, "CHAT")
for (let other of clients[socket.game_id])
if (other.role !== "Observer")
- send_message(other, 'chat', chat);
+ send_message(other, 'chat', chat)
} catch (err) {
- console.log(err);
- return send_message(socket, 'error', err.toString());
+ console.log(err)
+ return send_message(socket, 'error', err.toString())
}
}
function on_debug(socket) {
if (!DEBUG)
- send_message(socket, 'error', "Debugging is not enabled on this server.");
- SLOG(socket, "DEBUG");
+ send_message(socket, 'error', "Debugging is not enabled on this server.")
+ SLOG(socket, "DEBUG")
try {
- let game_state = SQL_SELECT_GAME_STATE.get(socket.game_id);
+ let game_state = SQL_SELECT_GAME_STATE.get(socket.game_id)
if (!game_state)
- return send_message(socket, 'error', "No game with that ID.");
- send_message(socket, 'debug', game_state);
+ return send_message(socket, 'error', "No game with that ID.")
+ send_message(socket, 'debug', game_state)
} catch (err) {
- console.log(err);
- return send_message(socket, 'error', err.toString());
+ console.log(err)
+ return send_message(socket, 'error', err.toString())
}
}
function on_save(socket) {
if (!DEBUG)
- send_message(socket, 'error', "Debugging is not enabled on this server.");
- SLOG(socket, "SAVE");
+ send_message(socket, 'error', "Debugging is not enabled on this server.")
+ SLOG(socket, "SAVE")
try {
- let game_state = SQL_SELECT_GAME_STATE.get(socket.game_id);
+ let game_state = SQL_SELECT_GAME_STATE.get(socket.game_id)
if (!game_state)
- return send_message(socket, 'error', "No game with that ID.");
- send_message(socket, 'save', game_state);
+ return send_message(socket, 'error', "No game with that ID.")
+ send_message(socket, 'save', game_state)
} catch (err) {
- console.log(err);
- return send_message(socket, 'error', err.toString());
+ console.log(err)
+ return send_message(socket, 'error', err.toString())
}
}
function on_restore(socket, state_text) {
if (!DEBUG)
- send_message(socket, 'error', "Debugging is not enabled on this server.");
- SLOG(socket, "RESTORE");
+ send_message(socket, 'error', "Debugging is not enabled on this server.")
+ SLOG(socket, "RESTORE")
try {
- let state = JSON.parse(state_text);
- state.seed = random_seed(); // reseed!
- state_text = JSON.stringify(state);
- SQL_UPDATE_GAME_RESULT.run(1, null, socket.game_id);
- SQL_UPDATE_GAME_STATE.run(socket.game_id, state_text, state.active);
- put_replay(socket.game_id, null, 'restore', state_text);
+ let state = JSON.parse(state_text)
+ state.seed = random_seed() // reseed!
+ state_text = JSON.stringify(state)
+ SQL_UPDATE_GAME_RESULT.run(1, null, socket.game_id)
+ SQL_UPDATE_GAME_STATE.run(socket.game_id, state_text, state.active)
+ put_replay(socket.game_id, null, 'restore', state_text)
for (let other of clients[socket.game_id])
- send_state(other, state);
+ send_state(other, state)
} catch (err) {
- console.log(err);
- return send_message(socket, 'error', err.toString());
+ console.log(err)
+ return send_message(socket, 'error', err.toString())
}
}
function broadcast_presence(game_id) {
- let presence = {};
+ let presence = {}
for (let socket of clients[game_id])
- presence[socket.role] = true;
+ presence[socket.role] = true
for (let socket of clients[game_id])
- send_message(socket, 'presence', presence);
+ send_message(socket, 'presence', presence)
}
function on_restart(socket, scenario) {
if (!DEBUG)
- send_message(socket, 'error', "Debugging is not enabled on this server.");
+ send_message(socket, 'error', "Debugging is not enabled on this server.")
try {
- let seed = random_seed();
- let options = JSON.parse(SQL_SELECT_GAME.get(socket.game_id).options);
- let state = socket.rules.setup(seed, scenario, options, socket.players);
- put_replay(socket.game_id, null, 'setup', [seed, scenario, options, socket.players]);
+ let seed = random_seed()
+ let options = JSON.parse(SQL_SELECT_GAME.get(socket.game_id).options)
+ let state = socket.rules.setup(seed, scenario, options, socket.players)
+ put_replay(socket.game_id, null, 'setup', [seed, scenario, options, socket.players])
for (let other of clients[socket.game_id]) {
- other.seen = 0;
- send_state(other, state);
+ other.seen = 0
+ send_state(other, state)
}
- let state_text = JSON.stringify(state);
- SQL_UPDATE_GAME_RESULT.run(1, null, socket.game_id);
- SQL_UPDATE_GAME_STATE.run(socket.game_id, state_text, state.active);
+ let state_text = JSON.stringify(state)
+ SQL_UPDATE_GAME_RESULT.run(1, null, socket.game_id)
+ SQL_UPDATE_GAME_STATE.run(socket.game_id, state_text, state.active)
} catch (err) {
- console.log(err);
- return send_message(socket, 'error', err.toString());
+ console.log(err)
+ return send_message(socket, 'error', err.toString())
}
}
function handle_player_message(socket, cmd, arg) {
switch (cmd) {
- case 'action': on_action(socket, arg[0], arg[1]); break;
- case 'query': on_query(socket, arg); break;
- case 'resign': on_resign(socket); break;
- case 'getchat': on_getchat(socket, arg); break;
- case 'chat': on_chat(socket, arg); break;
- case 'debug': on_debug(socket); break;
- case 'save': on_save(socket); break;
- case 'restore': on_restore(socket, arg); break;
- case 'restart': on_restart(socket, arg); break;
+ case "action":
+ on_action(socket, arg[0], arg[1])
+ break
+ case "query":
+ on_query(socket, arg)
+ break
+ case "resign":
+ on_resign(socket)
+ break
+ case "getchat":
+ on_getchat(socket, arg)
+ break
+ case "chat":
+ on_chat(socket, arg)
+ break
+ case "debug":
+ on_debug(socket)
+ break
+ case "save":
+ on_save(socket)
+ break
+ case "restore":
+ on_restore(socket, arg)
+ break
+ case "restart":
+ on_restart(socket, arg)
+ break
}
}
function handle_observer_message(socket, cmd, arg) {
switch (cmd) {
- case 'query': on_query(socket, arg); break;
+ case 'query':
+ on_query(socket, arg)
+ break
}
}
wss.on('connection', (socket, req, client) => {
- let u = url.parse(req.url, true);
+ let u = url.parse(req.url, true)
if (u.pathname !== '/play-socket')
- return setTimeout(() => socket.close(1000, "Invalid request."), 30000);
- req.query = u.query;
+ return setTimeout(() => socket.close(1000, "Invalid request."), 30000)
+ req.query = u.query
- let user_id = 0;
- let sid = login_cookie(req);
+ let user_id = 0
+ let sid = login_cookie(req)
if (sid)
- user_id = login_sql_select.get(sid);
+ user_id = login_sql_select.get(sid)
if (user_id)
- socket.user = SQL_SELECT_USER_INFO.get(user_id);
+ socket.user = SQL_SELECT_USER_INFO.get(user_id)
- socket.ip = req.ip || req.connection.remoteAddress || "0.0.0.0";
- socket.title_id = req.query.title || "unknown";
- socket.game_id = req.query.game | 0;
- socket.role = req.query.role;
- socket.seen = req.query.seen | 0;
- socket.rules = RULES[socket.title_id];
+ socket.ip = req.ip || req.connection.remoteAddress || "0.0.0.0"
+ socket.title_id = req.query.title || "unknown"
+ socket.game_id = req.query.game | 0
+ socket.role = req.query.role
+ socket.seen = req.query.seen | 0
+ socket.rules = RULES[socket.title_id]
- SLOG(socket, "OPEN " + socket.seen);
+ SLOG(socket, "OPEN " + socket.seen)
try {
- let title_id = SQL_SELECT_GAME_TITLE.get(socket.game_id);
+ let title_id = SQL_SELECT_GAME_TITLE.get(socket.game_id)
if (title_id !== socket.title_id)
- return socket.close(1000, "Invalid game ID.");
+ return socket.close(1000, "Invalid game ID.")
- let players = socket.players = SQL_SELECT_PLAYERS_JOIN.all(socket.game_id);
+ let players = socket.players = SQL_SELECT_PLAYERS_JOIN.all(socket.game_id)
if (socket.role !== "Observer") {
if (!socket.user)
- return socket.close(1000, "You are not logged in!");
+ return socket.close(1000, "You are not logged in!")
if (socket.role && socket.role !== 'undefined' && socket.role !== 'null') {
- let me = players.find(p => p.user_id === socket.user.user_id && p.role === socket.role);
+ let me = players.find(p => p.user_id === socket.user.user_id && p.role === socket.role)
if (!me)
- return socket.close(1000, "You aren't assigned that role!");
+ return socket.close(1000, "You aren't assigned that role!")
} else {
- let me = players.find(p => p.user_id === socket.user.user_id);
- socket.role = me ? me.role : "Observer";
+ let me = players.find(p => p.user_id === socket.user.user_id)
+ socket.role = me ? me.role : "Observer"
}
}
if (socket.seen === 0)
- send_message(socket, 'players', [socket.role, players]);
+ send_message(socket, 'players', [socket.role, players])
if (clients[socket.game_id])
- clients[socket.game_id].push(socket);
+ clients[socket.game_id].push(socket)
else
- clients[socket.game_id] = [ socket ];
+ clients[socket.game_id] = [ socket ]
socket.on('close', (code, reason) => {
- SLOG(socket, "CLOSE " + code);
- clients[socket.game_id].splice(clients[socket.game_id].indexOf(socket), 1);
- broadcast_presence(socket.game_id);
- });
+ SLOG(socket, "CLOSE " + code)
+ clients[socket.game_id].splice(clients[socket.game_id].indexOf(socket), 1)
+ broadcast_presence(socket.game_id)
+ })
socket.on('message', (data) => {
try {
- let [ cmd, arg ] = JSON.parse(data);
+ let [ cmd, arg ] = JSON.parse(data)
if (socket.role !== "Observer")
- handle_player_message(socket, cmd, arg);
+ handle_player_message(socket, cmd, arg)
else
- handle_observer_message(socket, cmd, arg);
+ handle_observer_message(socket, cmd, arg)
} catch (err) {
- send_message(socket, 'error', err);
+ send_message(socket, 'error', err)
}
- });
+ })
- broadcast_presence(socket.game_id);
- send_state(socket, get_game_state(socket.game_id));
+ broadcast_presence(socket.game_id)
+ send_state(socket, get_game_state(socket.game_id))
} catch (err) {
- console.log(err);
- socket.close(1000, err.message);
+ console.log(err)
+ socket.close(1000, err.message)
}
-});
+})
/*
* HIDDEN EXTRAS
@@ -2040,21 +2060,21 @@ const SQL_GAME_STATS = SQL(`
title_id, scenario, options
having
total > 12
- `);
+ `)
app.get('/stats', function (req, res) {
- let stats = SQL_GAME_STATS.all();
+ let stats = SQL_GAME_STATS.all()
stats.forEach(row => {
- row.title_name = TITLES[row.title_id].title_name;
- row.options = format_options(row.options);
- row.result_role = row.result_role.split(",");
- row.result_count = row.result_count.split(",").map(Number);
- });
+ row.title_name = TITLES[row.title_id].title_name
+ row.options = format_options(row.options)
+ row.result_role = row.result_role.split(",")
+ row.result_count = row.result_count.split(",").map(Number)
+ })
res.render('stats.pug', {
user: req.user,
stats: stats,
- });
-});
+ })
+})
const SQL_USER_STATS = SQL(`
select
@@ -2075,14 +2095,14 @@ const SQL_USER_STATS = SQL(`
title_name,
scenario,
role
- `);
+ `)
app.get('/user-stats/:who_name', function (req, res) {
- let who = SQL_SELECT_USER_BY_NAME.get(req.params.who_name);
+ let who = SQL_SELECT_USER_BY_NAME.get(req.params.who_name)
if (who) {
- let stats = SQL_USER_STATS.all(who.user_id);
- res.render('user_stats.pug', { user: req.user, who: who, stats: stats });
+ let stats = SQL_USER_STATS.all(who.user_id)
+ res.render('user_stats.pug', { user: req.user, who: who, stats: stats })
} else {
- return res.status(404).send("Invalid user name.");
+ return res.status(404).send("Invalid user name.")
}
-});
+})
diff --git a/views/chat.pug b/views/chat.pug
index 15d99df..3fb9b35 100644
--- a/views/chat.pug
+++ b/views/chat.pug
@@ -38,56 +38,56 @@ html
p: a(href="/chat/all") All messages
script.
- let chat_data = !{ JSON.stringify(chat).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;") };
- let page_size = !{ page_size };
- let me = !{ JSON.stringify(user.name) };
- let table = document.querySelector("tbody");
- let foot = document.querySelector("#foot");
- let chat_lines = [];
+ let chat_data = !{ JSON.stringify(chat).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;") }
+ let page_size = !{ page_size }
+ let me = !{ JSON.stringify(user.name) }
+ let table = document.querySelector("tbody")
+ let foot = document.querySelector("#foot")
+ let chat_lines = []
function add(tr,text,link) {
- let td = document.createElement("td");
+ let td = document.createElement("td")
if (link) {
- let a = document.createElement("a");
- a.href = link;
- a.textContent = text;
- td.appendChild(a);
+ let a = document.createElement("a")
+ a.href = link
+ a.textContent = text
+ td.appendChild(a)
} else {
- td.textContent = text;
+ td.textContent = text
}
- tr.appendChild(td);
+ tr.appendChild(td)
}
function format_date(date) {
- let t = date.toISOString();
- return t.substring(0,10) + " " + t.substring(11,19);
+ let t = date.toISOString()
+ return t.substring(0,10) + " " + t.substring(11,19)
}
for (let [game_id,time,user,message] of chat_data) {
- let tr = document.createElement("tr");
- if (user === me) tr.className = "me";
- add(tr,game_id,"/join/"+game_id);
- add(tr,format_date(new Date(time+"Z")));
- add(tr,user,"/user/"+user);
- add(tr,message);
- chat_lines.push(tr);
+ let tr = document.createElement("tr")
+ if (user === me) tr.className = "me"
+ add(tr,game_id,"/join/"+game_id)
+ add(tr,format_date(new Date(time+"Z")))
+ add(tr,user,"/user/"+user)
+ add(tr,message)
+ chat_lines.push(tr)
}
function next() { if (page > 0) --page; update(); }
function back() { if (page < page_count-1) ++page; update(); }
function newest() { page=0; update(); }
function oldest() { page=page_count-1; update(); }
- let chat_size = chat_lines.length;
- let page_count = Math.ceil(chat_size / page_size);
- let page = 0;
+ let chat_size = chat_lines.length
+ let page_count = Math.ceil(chat_size / page_size)
+ let page = 0
function update() {
- table.innerHTML = "";
+ table.innerHTML = ""
for (let i = 0; i < page_size; ++i) {
- let k = page * page_size + ( page_size - i - 1);
+ let k = page * page_size + ( page_size - i - 1)
if (k >= 0 && k < chat_size)
- table.appendChild(chat_lines[k]);
- foot.textContent = `${page_count-page} / ${page_count}`;
+ table.appendChild(chat_lines[k])
+ foot.textContent = `${page_count-page} / ${page_count}`
}
}
if (page_size > 0) {
- newest();
+ newest()
} else {
for (let i = chat_size-1; i >= 0; --i)
- table.appendChild(chat_lines[i]);
+ table.appendChild(chat_lines[i])
}
diff --git a/views/forum_post.pug b/views/forum_post.pug
index d3c0e80..a0ff207 100644
--- a/views/forum_post.pug
+++ b/views/forum_post.pug
@@ -9,10 +9,10 @@ html
script.
function next(event,sel) {
if (event.keyCode === 13) {
- document.querySelector(sel).focus();
- return false;
+ document.querySelector(sel).focus()
+ return false
}
- return true;
+ return true
}
body
include header
diff --git a/views/join.pug b/views/join.pug
index bc1567a..8a19a09 100644
--- a/views/join.pug
+++ b/views/join.pug
@@ -14,11 +14,11 @@ html
td a { text-decoration: underline; color: blue; }
.hide { display: none; }
script.
- let game = !{ JSON.stringify(game) };
- let roles = !{ JSON.stringify(roles) };
- let players = !{ JSON.stringify(players) };
- let user_id = !{ user.user_id };
- let ready = !{ ready };
+ let game = !{ JSON.stringify(game) }
+ let roles = !{ JSON.stringify(roles) }
+ let players = !{ JSON.stringify(players) }
+ let user_id = !{ user.user_id }
+ let ready = !{ ready }
script(src="/join.js")
body
include header
diff --git a/views/message_outbox.pug b/views/message_outbox.pug
index 57d6d60..5da84c6 100644
--- a/views/message_outbox.pug
+++ b/views/message_outbox.pug
@@ -8,9 +8,9 @@ html
td a { display: block }
script.
function delete_all() {
- let warning = "Are you sure you want to delete ALL the messages?";
+ let warning = "Are you sure you want to delete ALL the messages?"
if (window.confirm(warning))
- window.location.href = "/outbox/delete";
+ window.location.href = "/outbox/delete"
}
body
include header
diff --git a/views/message_read.pug b/views/message_read.pug
index db43423..f02c2f7 100644
--- a/views/message_read.pug
+++ b/views/message_read.pug
@@ -8,12 +8,12 @@ html
.head {white-space:pre-wrap}
script.
function delete_message(id) {
- let warning = "Are you sure you want to DELETE this message?";
+ let warning = "Are you sure you want to DELETE this message?"
if (window.confirm(warning))
- window.location.href = "/message/delete/" + id;
+ window.location.href = "/message/delete/" + id
}
function reply_message(id) {
- window.location.href = "/message/reply/" + id;
+ window.location.href = "/message/reply/" + id
}
body
include header