From 2be5d6140901fc7bb2a33d672e52cfdc545a1912 Mon Sep 17 00:00:00 2001
From: Benjamin Auder <benjamin.auder@somewhere>
Date: Fri, 29 Nov 2019 17:04:34 +0100
Subject: [PATCH] Advance on corr game start

---
 client/src/views/Hall.vue   | 22 ++++++++++++----------
 server/models/Challenge.js  | 19 +++++++++++++------
 server/models/Game.js       | 17 ++++++++---------
 server/models/User.js       | 15 +++++++++++----
 server/routes/challenges.js |  2 +-
 server/routes/games.js      | 16 ++++++++++------
 server/routes/users.js      |  2 +-
 7 files changed, 56 insertions(+), 37 deletions(-)

diff --git a/client/src/views/Hall.vue b/client/src/views/Hall.vue
index 4c80803a..0467dab9 100644
--- a/client/src/views/Hall.vue
+++ b/client/src/views/Hall.vue
@@ -509,15 +509,17 @@ export default {
             cid: c.id, target: c.from.sid}));
         }
       }
-      else
-        localStorage.removeItem("challenge");
-      if (c.type == "corr")
+      else //my challenge
       {
-        ajax(
-          "/challenges",
-          "DELETE",
-          {id: c.id}
-        );
+        localStorage.removeItem("challenge");
+        if (c.type == "corr")
+        {
+          ajax(
+            "/challenges",
+            "DELETE",
+            {id: c.id}
+          );
+        }
       }
     },
     // NOTE: when launching game, the challenge is already deleted
@@ -542,9 +544,9 @@ export default {
         ajax(
           "/games",
           "POST",
-          {gameInfo: gameInfo}
+          {gameInfo: gameInfo, cid: c.id}, //cid useful to delete challenge
+          response => { this.$router.push("/game/" + response.gameId); }
         );
-        // TODO: redirection here
       }
     },
     // NOTE: for live games only (corr games start on the server)
diff --git a/server/models/Challenge.js b/server/models/Challenge.js
index c988aba5..c7476299 100644
--- a/server/models/Challenge.js
+++ b/server/models/Challenge.js
@@ -67,20 +67,27 @@ const ChallengeModel =
     });
   },
 
-  remove: function(id, uid, cb)
+  remove: function(id)
   {
     db.serialize(function() {
-      let query =
+      const query =
+        "DELETE FROM Challenges " +
+        "WHERE id = " + id;
+      db.run(query);
+    });
+  },
+
+  safeRemove: function(id, uid, cb)
+  {
+    db.serialize(function() {
+      const query =
         "SELECT 1 " +
         "FROM Challenges " +
         "WHERE id = " + id + " AND uid = " + uid;
       db.get(query, (err,chall) => {
         if (!chall)
           return cb({errmsg: "Not your challenge"});
-        query =
-          "DELETE FROM Challenges " +
-          "WHERE id = " + id;
-        db.run(query);
+        ChallengeModel.remove(id);
         cb(null);
       });
     });
diff --git a/server/models/Game.js b/server/models/Game.js
index 954ffc40..e60bfe51 100644
--- a/server/models/Game.js
+++ b/server/models/Game.js
@@ -35,15 +35,14 @@ const GameModel =
 			db.run(insertQuery, err => {
 				if (!!err)
 					return cb(err);
-				db.get("SELECT last_insert_rowid() AS rowid", (err2,lastId) => {
-					players.forEach(p => {
-						query =
-							"INSERT INTO Players VALUES " +
-              // Remaining time = -1 means "unstarted"
-							"(" + lastId["rowid"] + "," + p.id + "," + p.color + ", -1)";
-						db.run(query, cb);
-					});
-				});
+        players.forEach(p => {
+          query =
+            "INSERT INTO Players VALUES " +
+            // Remaining time = -1 means "unstarted"
+            "(" + this.lastID + "," + p.id + "," + p.color + ", -1)";
+          db.run(query);
+        });
+        cb(null, {gid: this.lastID});
 			});
 		});
 	},
diff --git a/server/models/User.js b/server/models/User.js
index 60584275..b2a99e05 100644
--- a/server/models/User.js
+++ b/server/models/User.js
@@ -1,7 +1,7 @@
 var db = require("../utils/database");
-var maild = require("../utils/mailer.js");
 var genToken = require("../utils/tokenGenerator");
 var params = require("../config/parameters");
+var sendEmail = require('../utils/mailer');
 
 /*
  * Structure:
@@ -128,10 +128,17 @@ const UserModel =
   /////////////////
   // NOTIFICATIONS
 
-  tryNotify: function(oppId, gid, vname, message)
+  tryNotify: function(oppId, message)
   {
-    // TODO: send email to oppId (request...) with title
-    // "vchess.club - vname" and content "message"
+		UserModel.getOne("id", oppId, (err,opp) => {
+      if (!err || !opp.notify)
+        return; //error is ignored here (TODO: should be logged)
+      const subject = "vchess.club - notification";
+      const body = "Hello " + opp.name + "!\n" + message;
+      sendEmail(params.mail.noreply, opp.email, subject, body, err => {
+        res.json(err || {});
+      });
+    });
   }
 }
 
diff --git a/server/routes/challenges.js b/server/routes/challenges.js
index acec3c13..146bbe2d 100644
--- a/server/routes/challenges.js
+++ b/server/routes/challenges.js
@@ -43,7 +43,7 @@ router.post("/challenges", access.logged, access.ajax, (req,res) => {
 
 router.delete("/challenges", access.logged, access.ajax, (req,res) => {
   const cid = req.query.id;
-  ChallengeModel.remove(cid, req.userId, err => {
+  ChallengeModel.safeRemove(cid, req.userId, err => {
     res.json(err || {}); //TODO: just "return err" because is empty if no errors
   });
 });
diff --git a/server/routes/games.js b/server/routes/games.js
index 35a7f42f..cc8a17bb 100644
--- a/server/routes/games.js
+++ b/server/routes/games.js
@@ -1,6 +1,7 @@
 var router = require("express").Router();
 var UserModel = require("../models/User");
 var sendEmail = require('../utils/mailer');
+var ChallengeModel = require('../models/Challenge');
 var GameModel = require('../models/Game');
 var VariantModel = require('../models/Variant');
 var access = require("../utils/access");
@@ -26,15 +27,18 @@ router.post("/games", access.logged, access.ajax, (req,res) => {
 	const gameInfo = JSON.parse(req.body.gameInfo);
 	if (!gameInfo.players.some(p => p.id == req.user.id))
 		return res.json({errmsg: "Cannot start someone else's game"});
-	let fen = req.body.fen;
+	const cid = req.body.cid;
+  ChallengeModel.remove(cid);
+	const fen = req.body.fen;
 	GameModel.create(
     gameInfo.vid, gameInfo.fen, gameInfo.timeControl, gameInfo.players,
-		(err,game) => {
+		(err,ret) => {
 			access.checkRequest(res, err, game, "Cannot create game", () => {
-				if (!!req.body.offlineOpp)
-					UserModel.tryNotify(req.body.offlineOpp, game.id, variant.name,
-            "New game: " + "game link"); //TODO: give game link
-				res.json({game: game});
+        const oppIdx = gameInfo.players[0].id == req.user.id ? 1 : 0;
+        const oppId = gameInfo.players[oppIdx].id;
+        UserModel.tryNotify(oppId,
+          "New game: " + params.siteURL + "/game/" + gid);
+				res.json({gameId: ret.gid});
 			});
 		}
 	);
diff --git a/server/routes/users.js b/server/routes/users.js
index 5b04ddd1..99810b63 100644
--- a/server/routes/users.js
+++ b/server/routes/users.js
@@ -45,7 +45,7 @@ function setAndSendLoginToken(subject, to, res)
 		if (!!err)
 			return res.json({errmsg: err.toString()});
 		const body =
-			"Hello " + to.name + "!\n" +
+			"Hello " + to.name + "!\\n" +
 			"Access your account here: " +
 			params.siteURL + "/#/authenticate/" + token + "\\n" +
 			"Token will expire in " + params.token.expire/(1000*60) + " minutes."
-- 
2.44.0