5ab6ae90f67b61936c02fe57a058786b18d8b9f2
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');
7 const MaxNbProblems
= 20;
9 const supportedLang
= ["fr","en"];
10 function selectLanguage(req
, res
)
12 // If preferred language already set:
13 if (!!req
.cookies
["lang"])
14 return req
.cookies
["lang"];
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
)
25 if (supportedLang
.includes(lang
))
31 // Cookie expires in 183 days (expressed in milliseconds)
32 res
.cookie('lang', bestLang
, { maxAge: 183*24*3600*1000 });
37 router
.get('/', function(req
, res
, next
) {
38 db
.serialize(function() {
39 db
.all("SELECT * FROM Variants", (err
,variants
) => {
44 variantArray: variants
,
45 lang: selectLanguage(req
, res
),
46 languages: supportedLang
,
53 router
.get("/:variant([a-zA-Z0-9]+)", (req
,res
,next
) => {
54 const vname
= req
.params
["variant"];
55 db
.serialize(function() {
56 db
.all("SELECT * FROM Variants WHERE name='" + vname
+ "'", (err
,variant
) => {
59 if (!variant
|| variant
.length
==0)
60 return next(createError(404));
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
) => {
69 res
.render('variant', {
70 title: vname
+ ' Variant',
72 problemArray: problems
,
73 lang: selectLanguage(req
, res
),
74 languages: supportedLang
,
81 // Load a rules page (AJAX)
82 router
.get("/rules/:variant([a-zA-Z0-9]+)", (req
,res
) => {
84 return res
.json({errmsg: "Unauthorized access"});
85 const lang
= selectLanguage(req
, res
);
86 res
.render("rules/" + req
.params
["variant"] + "/" + lang
);
89 // Fetch N previous or next problems (AJAX)
90 router
.get("/problems/:variant([a-zA-Z0-9]+)", (req
,res
) => {
92 return res
.json({errmsg: "Unauthorized access"});
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"});
98 db
.serialize(function() {
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
) => {
106 return res
.json(err
);
107 return res
.json({problems: problems
});
112 // Upload a problem (AJAX)
113 router
.post("/problems/:variant([a-zA-Z0-9]+)", (req
,res
) => {
115 return res
.json({errmsg: "Unauthorized access"});
116 const vname
= req
.params
["variant"];
117 const timestamp
= Date
.now();
119 const fen
= req
.body
["fen"];
120 if (!fen
.match(/^[a-zA-Z0-9, /-]*$/))
121 return res
.json({errmsg: "Bad characters in FEN string"});
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"});
128 db
.serialize(function() {
129 let stmt
= db
.prepare("INSERT INTO Problems " +
130 "(added,variant,fen,instructions,solution) VALUES (?,?,?,?,?)");
131 stmt
.run(timestamp
, vname
, fen
, instructions
, solution
);
137 module
.exports
= router
;