Drop problems from server + draft DB cleaning functions
authorBenjamin Auder <benjamin.auder@somewhere>
Wed, 15 Jan 2020 13:45:26 +0000 (14:45 +0100)
committerBenjamin Auder <benjamin.auder@somewhere>
Wed, 15 Jan 2020 13:45:26 +0000 (14:45 +0100)
server/TODO
server/bin/www
server/db/create.sql
server/models/Challenge.js
server/models/Game.js
server/models/Problem.js [deleted file]
server/models/User.js
server/routes/all.js
server/routes/problems.js [deleted file]

index bcffc7b..bd5d730 100644 (file)
@@ -2,8 +2,3 @@ Later: use http2
 https://webapplog.com/http2-node/
 https://www.npmjs.com/package/spdy
 Express 5?
-
-Finish :
- - models
- - routes
- - sockets
index e287d50..94f39e1 100755 (executable)
@@ -21,6 +21,21 @@ app.set('port', port);
 
 var server = http.createServer(app);
 
+/*
+ * CRON tasks
+ */
+
+var cron = require('node-cron');
+var UserModel = require("../models/User");
+var ChallengeModel = require("../models/Challenge");
+var GameModel = require("../models/Game");
+cron.schedule('0 0 0 * * *', function() {
+       // Remove some old users, challenges and games every 24h
+       UserModel.cleanUsersDb(); //TODO: write this
+       ChallengeModel.removeOld(); //TODO: this too
+       GameModel.cleanGamesDb();
+});
+
 /**
  * Listen on provided port, on all network interfaces.
  */
index 11c3574..a8c8d68 100644 (file)
@@ -16,18 +16,6 @@ create table Users (
   notify boolean
 );
 
-create table Problems (
-  id integer primary key,
-  added datetime,
-  uid integer,
-  vid integer,
-  fen varchar,
-  instructions text,
-  solution text,
-  foreign key (uid) references Users(id),
-  foreign key (vid) references Variants(id)
-);
-
 -- All the following tables are for correspondance play only
 -- (Live games are stored in browser)
 
@@ -51,6 +39,7 @@ create table Games (
   fen varchar, --current state
   score varchar,
   timeControl varchar,
+  created datetime, --used only for DB cleaning
   foreign key (vid) references Variants(id)
 );
 
index f82f9e8..ba805aa 100644 (file)
@@ -94,4 +94,22 @@ const ChallengeModel =
   },
 }
 
+// TODO: adapt
+// Remove challenges older than 1 month, and 1to1 older than 36h
+//exports.removeOld = function()
+//{
+//     var tsNow = new Date().getTime();
+//     // 86400000 = 24 hours in milliseconds
+//     var day = 86400000;
+//     db.challenges.find({}, (err,challengeArray) => {
+//             challengeArray.forEach( c => {
+//                     if (c._id.getTimestamp() + 30*day < tsNow //automatch
+//                             || (!!c.to && c._id.getTimestamp() + 1.5*day < tsNow)) //1 to 1
+//                     {
+//                             db.challenges.remove({"_id": c._id});
+//                     }
+//             });
+//     });
+//}
+
 module.exports = ChallengeModel;
index 0949fc9..3d2184b 100644 (file)
@@ -28,8 +28,9 @@ const GameModel =
        {
                db.serialize(function() {
                        let query =
-                               "INSERT INTO Games (vid, fenStart, fen, score, timeControl) VALUES " +
-        "(" + vid + ",'" + fen + "','" + fen + "','*','" + timeControl + "')";
+                               "INSERT INTO Games (vid, fenStart, fen, score, timeControl, created)"
+        + " VALUES (" + vid + ",'" + fen + "','" + fen + "','*','"
+        + timeControl + "'," + Date.now() + ")";
       db.run(query, function(err) {
         if (!!err)
           return cb(err);
@@ -174,6 +175,36 @@ const GameModel =
                        db.run(query);
                });
        },
+
+  cleanGamesDb: function()
+  {
+    const tsNow = Date.now();
+    // 86400000 = 24 hours in milliseconds
+    const day = 86400000;
+    db.serialize(function() {
+      let query =
+        "SELECT id,score " +
+        "FROM Games ";
+      db.all(query, (err,games) => {
+        games.forEach(g => {
+          query =
+            "SELECT max(played) AS lastMaj " +
+            "FROM Moves " +
+            "WHERE gid = " + g.id;
+          db.get(query, (err2,updated) {
+            if (!updated && tsNow - g.created > 7*day)
+              return GameModel.remove(g.id);
+            const lastMaj = updated.lastMaj;
+            if (g.score != "*" && tsNow - lastMaj > 7*day ||
+              g.score == "*" && tsNow - lastMaj > 91*day)
+            {
+              GameModel.remove(g.id);
+            }
+          });
+        });
+      });
+    });
+  },
 }
 
 module.exports = GameModel;
diff --git a/server/models/Problem.js b/server/models/Problem.js
deleted file mode 100644 (file)
index a1f9903..0000000
+++ /dev/null
@@ -1,81 +0,0 @@
-var db = require("../utils/database");
-
-/*
- * Structure:
- *   id: problem number (int)
- *   uid: user id (int)
- *   vid: variant id (int)
- *   added: timestamp
- *   instructions: text
- *   solution: text
- */
-
-const ProblemModel =
-{
-       create: function(uid, vid, fen, instructions, solution, cb)
-       {
-               db.serialize(function() {
-                       const insertQuery =
-                               "INSERT INTO Problems (added, uid, vid, fen, instructions, solution) " +
-                               "VALUES (" + Date.now() + "," + uid + "," + vid + ",'" + fen + "',?,?)";
-                       db.run(insertQuery, [instructions, solution], err => {
-                               if (!!err)
-                                       return cb(err);
-                               db.get("SELECT last_insert_rowid() AS rowid", cb);
-                       });
-               });
-       },
-
-       getOne: function(id, callback)
-       {
-               db.serialize(function() {
-                       const query =
-                               "SELECT * " +
-                               "FROM Problems " +
-                               "WHERE id = " + id;
-                       db.get(query, callback);
-               });
-       },
-
-       fetchN: function(vid, uid, type, directionStr, lastDt, MaxNbProblems, callback)
-       {
-               db.serialize(function() {
-                       let typeLine = "";
-                       if (uid > 0)
-                               typeLine = "AND uid " + (type=="others" ? "!=" : "=") + " " + uid;
-                       const query =
-                               "SELECT * FROM Problems " +
-                               "WHERE vid = " + vid +
-                               "  AND added " + directionStr + " " + lastDt + " " + typeLine + " " +
-                               "ORDER BY added " + (directionStr=="<" ? "DESC " : "") +
-                               "LIMIT " + MaxNbProblems;
-                       db.all(query, callback);
-               });
-       },
-
-       // TODO: update fails (but insert is OK)
-       update: function(id, uid, fen, instructions, solution, cb)
-       {
-               db.serialize(function() {
-                       const query =
-                               "UPDATE Problems SET " +
-                                       "fen = '" + fen + "', " +
-                                       "instructions = ?, " +
-                                       "solution = ? " +
-                               "WHERE id = " + id + " AND uid = " + uid;
-                       db.run(query, [instructions,solution], cb);
-               });
-       },
-
-       remove: function(id, uid)
-       {
-               db.serialize(function() {
-                       const query =
-                               "DELETE FROM Problems " +
-                               "WHERE id = " + id + " AND uid = " + uid;
-                       db.run(query);
-               });
-       },
-}
-
-module.exports = ProblemModel;
index b2a99e0..c2e7883 100644 (file)
@@ -142,4 +142,23 @@ const UserModel =
   }
 }
 
+// TODO: adapt
+//exports.cleanUsersDb = function()
+//{
+//     var tsNow = new Date().getTime();
+//     // 86400000 = 24 hours in milliseconds
+//     var day = 86400000;
+//
+//     db.users.find({}, (err,userArray) => {
+//             userArray.forEach( u => {
+//                     if ((u.sessionTokens.length==0 &&
+//                                     u._id.getTimestamp().getTime() + day < tsNow) //unlogged
+//                             || u.updated + 365*day < tsNow) //inactive for one year
+//                     {
+//                             db.users.remove({"_id": u._id});
+//                     }
+//             });
+//     });
+//}
+
 module.exports = UserModel;
index fbf3433..a890e60 100644 (file)
@@ -9,7 +9,6 @@ router.get("/", access.ajax, (req,res) => {
 router.use("/", require("./challenges"));
 router.use("/", require("./games"));
 router.use("/", require("./messages"));
-router.use("/", require("./problems"));
 router.use("/", require("./users"));
 router.use("/", require("./variants"));
 
diff --git a/server/routes/problems.js b/server/routes/problems.js
deleted file mode 100644 (file)
index 777543b..0000000
+++ /dev/null
@@ -1,94 +0,0 @@
-// AJAX methods to get, create, update or delete a problem
-
-let router = require("express").Router();
-const access = require("../utils/access");
-const ProblemModel = require("../models/Problem");
-const sanitizeHtml = require('sanitize-html');
-const MaxNbProblems = 20;
-
-function sanitizeUserInput(fen, instructions, solution)
-{
-       if (!fen.match(/^[a-zA-Z0-9, /-]*$/))
-               return "Bad characters in FEN string";
-       instructions = sanitizeHtml(instructions);
-       solution = sanitizeHtml(solution);
-       if (instructions.length == 0)
-               return "Empty instructions";
-       if (solution.length == 0)
-               return "Empty solution";
-       return {
-               fen: fen,
-               instructions: instructions,
-               solution: solution
-       };
-}
-
-// Get one problem (TODO: vid unused, here for URL de-ambiguification)
-router.get("/problems/:vid([0-9]+)/:id([0-9]+)", access.ajax, (req,res) => {
-       const pid = req.params["id"];
-       ProblemModel.getOne(pid, (err,problem) => {
-               if (!!err)
-                       return res.json(err);
-               return res.json({problem: problem});
-       });
-});
-
-// Fetch N previous or next problems
-router.get("/problems/:vid([0-9]+)", access.ajax, (req,res) => {
-       const vid = req.params["vid"];
-       const directionStr = (req.query.direction == "forward" ? ">" : "<");
-       const lastDt = req.query.last_dt;
-       const type = req.query.type;
-       if (!lastDt.match(/[0-9]+/))
-               return res.json({errmsg: "Bad timestamp"});
-       if (!["others","mine"].includes(type))
-               return res.json({errmsg: "Bad type"});
-       ProblemModel.fetchN(vid, req.userId, type, directionStr, lastDt, MaxNbProblems,
-               (err,problems) => {
-                       if (!!err)
-                               return res.json(err);
-                       return res.json({problems: problems});
-               }
-       );
-});
-
-// Upload a problem (sanitize inputs)
-router.post("/problems/:vid([0-9]+)", access.logged, access.ajax, (req,res) => {
-       const vid = req.params["vid"];
-       const s = sanitizeUserInput(
-               req.body["fen"], req.body["instructions"], req.body["solution"]);
-       if (typeof s === "string")
-               return res.json({errmsg: s});
-  ProblemModel.create(req.userId, vid, s.fen, s.instructions, s.solution,
-               (err,pid) => {
-                       if (!!err)
-                               return res.json(err);
-                       res.json({id: pid["rowid"]});
-               }
-       );
-});
-
-// Update a problem (also sanitize inputs)
-router.put("/problems/:id([0-9]+)", access.logged, access.ajax, (req,res) => {
-       const pid = req.params["id"]; //problem ID
-       const s = sanitizeUserInput(
-               req.body["fen"], req.body["instructions"], req.body["solution"]);
-       if (typeof s === "string")
-               return res.json({errmsg: s});
-       ProblemModel.update(pid, req.userId, s.fen, s.instructions, s.solution,
-               err => {
-                       if (!!err)
-                               return res.json(err);
-                       res.json({});
-               }
-       );
-});
-
-// Delete a problem
-router.delete("/problems/:id([0-9]+)", access.logged, access.ajax, (req,res) => {
-       const pid = req.params["id"]; //problem ID
-  ProblemModel.remove(pid, req.userId);
-       res.json({});
-});
-
-module.exports = router;