1 let express
= require('express');
2 let router
= express
.Router();
3 const createError
= require('http-errors');
4 const sqlite3
= require('sqlite3');//.verbose();
5 const DbPath
= __dirname
.replace("/routes", "/db/vchess.sqlite");
6 const db
= new sqlite3
.Database(DbPath
);
7 const sanitizeHtml
= require('sanitize-html');
8 const MaxNbProblems
= 20;
10 const supportedLang
= ["fr","en"];
11 function selectLanguage(req
, res
)
13 // If preferred language already set:
14 if (!!req
.cookies
["lang"])
15 return req
.cookies
["lang"];
17 // Else: search and set it
18 const langString
= req
.headers
["accept-language"];
19 let langArray
= langString
20 .replace(/;q=[0-9.]+/g, "") //priority
21 .replace(/-[A-Z]+/g, "") //region (skipped for now...)
22 .split(",") //may have some duplicates, but removal is too costly
23 let bestLang
= "en"; //default: English
24 for (let lang
of langArray
)
26 if (supportedLang
.includes(lang
))
32 // Cookie expires in 183 days (expressed in milliseconds)
33 res
.cookie('lang', bestLang
, { maxAge: 183*24*3600*1000 });
38 router
.get('/', function(req
, res
, next
) {
39 db
.serialize(function() {
40 db
.all("SELECT * FROM Variants", (err
,variants
) => {
45 variantArray: variants
,
46 lang: selectLanguage(req
, res
),
47 languages: supportedLang
,
54 router
.get("/:variant([a-zA-Z0-9]+)", (req
,res
,next
) => {
55 const vname
= req
.params
["variant"];
56 db
.serialize(function() {
57 db
.all("SELECT * FROM Variants WHERE name='" + vname
+ "'", (err
,variant
) => {
60 if (!variant
|| variant
.length
==0)
61 return next(createError(404));
62 // Get only N most recent problems
63 const query2
= "SELECT * FROM Problems " +
64 "WHERE variant='" + vname
+ "' " +
65 "ORDER BY added DESC " +
66 "LIMIT " + MaxNbProblems
;
67 db
.all(query2
, (err2
,problems
) => {
70 res
.render('variant', {
71 title: vname
+ ' Variant',
73 problemArray: problems
,
74 lang: selectLanguage(req
, res
),
75 languages: supportedLang
,
82 // Load a rules page (AJAX)
83 router
.get("/rules/:variant([a-zA-Z0-9]+)", (req
,res
) => {
85 return res
.json({errmsg: "Unauthorized access"});
86 const lang
= selectLanguage(req
, res
);
87 res
.render("rules/" + req
.params
["variant"] + "/" + lang
);
90 // Fetch N previous or next problems (AJAX)
91 router
.get("/problems/:variant([a-zA-Z0-9]+)", (req
,res
) => {
93 return res
.json({errmsg: "Unauthorized access"});
94 const vname
= req
.params
["variant"];
95 const directionStr
= (req
.query
.direction
== "forward" ? ">" : "<");
96 const lastDt
= req
.query
.last_dt
;
97 if (!lastDt
.match(/[0-9]+/))
98 return res
.json({errmsg: "Bad timestamp"});
99 db
.serialize(function() {
100 const query
= "SELECT * FROM Problems " +
101 "WHERE variant='" + vname
+ "' " +
102 " AND added " + directionStr
+ " " + lastDt
+ " " +
103 "ORDER BY added " + (directionStr
=="<" ? "DESC " : "") +
104 "LIMIT " + MaxNbProblems
;
105 db
.all(query
, (err
,problems
) => {
107 return res
.json(err
);
108 return res
.json({problems: problems
});
113 // Upload a problem (AJAX)
114 router
.post("/problems/:variant([a-zA-Z0-9]+)", (req
,res
) => {
116 return res
.json({errmsg: "Unauthorized access"});
117 const vname
= req
.params
["variant"];
118 const timestamp
= Date
.now();
120 const fen
= req
.body
["fen"];
121 if (!fen
.match(/^[a-zA-Z0-9, /-]*$/))
122 return res
.json({errmsg: "Bad characters in FEN string"});
123 const instructions
= sanitizeHtml(req
.body
["instructions"]).trim();
124 const solution
= sanitizeHtml(req
.body
["solution"]).trim();
125 if (instructions
.length
== 0)
126 return res
.json({errmsg: "Empty instructions"});
127 if (solution
.length
== 0)
128 return res
.json({errmsg: "Empty solution"});
129 db
.serialize(function() {
130 let stmt
= db
.prepare("INSERT INTO Problems " +
131 "(added,variant,fen,instructions,solution) VALUES (?,?,?,?,?)");
132 stmt
.run(timestamp
, vname
, fen
, instructions
, solution
);
138 module
.exports
= router
;