Commit | Line | Data |
---|---|---|
da06a6eb BA |
1 | let express = require('express'); |
2 | let router = express.Router(); | |
3 | const createError = require('http-errors'); | |
4 | const sqlite3 = require('sqlite3');//.verbose(); | |
5 | const db = new sqlite3.Database('db/vchess.sqlite'); | |
6 | const sanitizeHtml = require('sanitize-html'); | |
a5d56686 | 7 | const MaxNbProblems = 2; |
1d184b4c | 8 | |
9a3c9f79 BA |
9 | const supportedLang = ["fr","en"]; |
10 | function selectLanguage(req, res) | |
11 | { | |
12 | // If preferred language already set: | |
13 | if (!!req.cookies["lang"]) | |
14 | return req.cookies["lang"]; | |
15 | ||
16 | // Else: search and set it | |
17 | const langString = req.headers["accept-language"]; | |
18 | let langArray = langString | |
19 | .replace(/;q=[0-9.]+/g, "") //priority | |
20 | .replace(/-[A-Z]+/g, "") //region (skipped for now...) | |
21 | .split(",") //may have some duplicates, but removal is too costly | |
22 | let bestLang = "en"; //default: English | |
23 | for (let lang of langArray) | |
24 | { | |
25 | if (supportedLang.includes(lang)) | |
26 | { | |
27 | bestLang = lang; | |
28 | break; | |
29 | } | |
30 | } | |
31 | // Cookie expires in 183 days (expressed in milliseconds) | |
32 | res.cookie('lang', bestLang, { maxAge: 183*24*3600*1000 }); | |
33 | return bestLang; | |
34 | } | |
35 | ||
1d184b4c BA |
36 | // Home |
37 | router.get('/', function(req, res, next) { | |
da06a6eb BA |
38 | db.serialize(function() { |
39 | db.all("SELECT * FROM Variants", (err,variants) => { | |
40 | if (!!err) | |
41 | return next(err); | |
42 | res.render('index', { | |
43 | title: 'club', | |
9a3c9f79 BA |
44 | variantArray: variants, |
45 | lang: selectLanguage(req, res), | |
46 | languages: supportedLang, | |
da06a6eb BA |
47 | }); |
48 | }); | |
1d184b4c BA |
49 | }); |
50 | }); | |
51 | ||
52 | // Variant | |
a5d56686 BA |
53 | router.get("/:variant([a-zA-Z0-9]+)", (req,res,next) => { |
54 | const vname = req.params["variant"]; | |
da06a6eb BA |
55 | db.serialize(function() { |
56 | db.all("SELECT * FROM Variants WHERE name='" + vname + "'", (err,variant) => { | |
57 | if (!!err) | |
58 | return next(err); | |
59 | if (!variant || variant.length==0) | |
60 | return next(createError(404)); | |
a5d56686 BA |
61 | // Get only N most recent problems |
62 | const query2 = "SELECT * FROM Problems " + | |
63 | "WHERE variant='" + vname + "' " + | |
64 | "ORDER BY added DESC " + | |
65 | "LIMIT " + MaxNbProblems; | |
66 | db.all(query2, (err2,problems) => { | |
67 | if (!!err2) | |
68 | return next(err2); | |
69 | res.render('variant', { | |
70 | title: vname + ' Variant', | |
71 | variant: vname, | |
72 | problemArray: problems, | |
73 | lang: selectLanguage(req, res), | |
74 | languages: supportedLang, | |
75 | }); | |
76 | }); | |
da06a6eb | 77 | }); |
1d184b4c BA |
78 | }); |
79 | }); | |
80 | ||
81 | // Load a rules page (AJAX) | |
82 | router.get("/rules/:variant([a-zA-Z0-9]+)", (req,res) => { | |
da06a6eb BA |
83 | if (!req.xhr) |
84 | return res.json({errmsg: "Unauthorized access"}); | |
9a3c9f79 BA |
85 | const lang = selectLanguage(req, res); |
86 | res.render("rules/" + req.params["variant"] + "/" + lang); | |
da06a6eb BA |
87 | }); |
88 | ||
a5d56686 | 89 | // Fetch N previous or next problems (AJAX) |
da06a6eb BA |
90 | router.get("/problems/:variant([a-zA-Z0-9]+)", (req,res) => { |
91 | if (!req.xhr) | |
92 | return res.json({errmsg: "Unauthorized access"}); | |
a5d56686 BA |
93 | const vname = req.params["variant"]; |
94 | const directionStr = (req.query.direction == "forward" ? ">" : "<"); | |
95 | const lastDt = req.query.last_dt; | |
96 | if (!lastDt.match(/[0-9]+/)) | |
97 | return res.json({errmsg: "Bad timestamp"}); | |
7931e479 | 98 | db.serialize(function() { |
a5d56686 BA |
99 | const query = "SELECT * FROM Problems " + |
100 | "WHERE variant='" + vname + "' " + | |
101 | " AND added " + directionStr + " " + lastDt + " " + | |
102 | "ORDER BY added " + (directionStr=="<" ? "DESC " : "") + | |
103 | "LIMIT " + MaxNbProblems; | |
104 | db.all(query, (err,problems) => { | |
105 | if (!!err) | |
106 | return res.json(err); | |
107 | return res.json({problems: problems}); | |
108 | }); | |
7931e479 | 109 | }); |
1d184b4c BA |
110 | }); |
111 | ||
da06a6eb BA |
112 | // Upload a problem (AJAX) |
113 | router.post("/problems/:variant([a-zA-Z0-9]+)", (req,res) => { | |
114 | if (!req.xhr) | |
115 | return res.json({errmsg: "Unauthorized access"}); | |
116 | const vname = req.params["variant"]; | |
7931e479 BA |
117 | const timestamp = Date.now(); |
118 | // Sanitize them | |
119 | const fen = req.body["fen"]; | |
b5fb8e69 | 120 | if (!fen.match(/^[a-zA-Z0-9, /-]*$/)) |
7931e479 | 121 | return res.json({errmsg: "Bad characters in FEN string"}); |
a5d56686 BA |
122 | const instructions = sanitizeHtml(req.body["instructions"]).trim(); |
123 | const solution = sanitizeHtml(req.body["solution"]).trim(); | |
124 | if (instructions.length == 0) | |
125 | return res.json({errmsg: "Empty instructions"}); | |
126 | if (solution.length == 0) | |
127 | return res.json({errmsg: "Empty solution"}); | |
da06a6eb | 128 | db.serialize(function() { |
3a609580 BA |
129 | let stmt = db.prepare("INSERT INTO Problems " + |
130 | "(added,variant,fen,instructions,solution) VALUES (?,?,?,?,?)"); | |
da06a6eb BA |
131 | stmt.run(timestamp, vname, fen, instructions, solution); |
132 | stmt.finalize(); | |
133 | }); | |
134 | res.json({}); | |
135 | }); | |
136 | ||
1d184b4c | 137 | module.exports = router; |