From fe4c7e67075416c48aafe9e307bef5afea7937bc Mon Sep 17 00:00:00 2001
From: Benjamin Auder <benjamin.auder@somewhere>
Date: Fri, 7 Feb 2020 14:39:45 +0100
Subject: [PATCH] Fix corr challenges

---
 client/src/views/Hall.vue   | 62 ++++++++++++++++++++++++-------------
 server/models/Challenge.js  |  7 +++--
 server/models/User.js       | 21 +++++++------
 server/routes/all.js        |  4 +--
 server/routes/challenges.js |  3 ++
 server/routes/games.js      | 14 ++++-----
 server/routes/users.js      | 12 +++----
 server/utils/mailer.js      |  4 +++
 8 files changed, 80 insertions(+), 47 deletions(-)

diff --git a/client/src/views/Hall.vue b/client/src/views/Hall.vue
index bdcf84f9..0ce00e70 100644
--- a/client/src/views/Hall.vue
+++ b/client/src/views/Hall.vue
@@ -163,7 +163,7 @@ export default {
         }));
       }
     );
-    // Also ask for corr challenges (open + sent to me)
+    // Also ask for corr challenges (open + sent by/to me)
     ajax(
       "/challenges",
       "GET",
@@ -171,24 +171,44 @@ export default {
       response => {
         // Gather all senders names, and then retrieve full identity:
         // (TODO [perf]: some might be online...)
-        const uids = response.challenges.map(c => { return c.uid });
-        ajax("/users",
-          "GET",
-          { ids: uids.join(",") },
-          response2 => {
-            let names = {};
-            response2.users.forEach(u => {names[u.id] = u.name});
-            this.challenges = this.challenges.concat(
-              response.challenges.map(c => {
-                // (just players names in fact)
-                const from = {name: names[c.uid], id: c.uid};
-                const type = this.classifyObject(c);
-                const vname = this.getVname(c.vid);
-                return Object.assign({}, c, {type: type, vname: vname, from: from});
-              })
-            )
-          }
-        );
+        let names = {};
+        response.challenges.forEach(c => {
+          if (c.uid != this.st.user.id)
+            names[c.uid] = ""; //unknwon for now
+          else if (!!c.target && c.target != this.st.user.id)
+            names[c.target] = "";
+        });
+        const addChallenges = (newChalls) => {
+          names[this.st.user.id] = this.st.user.name; //in case of
+          this.challenges = this.challenges.concat(
+            response.challenges.map(c => {
+              const from = {name: names[c.uid], id: c.uid}; //or just name
+              const type = this.classifyObject(c);
+              const vname = this.getVname(c.vid);
+              return Object.assign({},
+                {
+                  type: type,
+                  vname: vname,
+                  from: from,
+                  to: (!!c.target ? names[c.target] : ""),
+                },
+                c);
+            })
+          );
+        };
+        if (names !== {})
+        {
+          ajax("/users",
+            "GET",
+            { ids: Object.keys(names).join(",") },
+            response2 => {
+              response2.users.forEach(u => {names[u.id] = u.name});
+              addChallenges();
+            }
+          );
+        }
+        else
+          addChallenges();
       }
     );
     // 0.1] Ask server for room composition:
@@ -526,9 +546,9 @@ export default {
           {chall:chall}, !!warnDisconnected);
         if (!isSent)
           return;
-        // Remove old challenge if any (only one at a time):
+        // Remove old challenge if any (only one at a time of a given type):
         const cIdx = this.challenges.findIndex(c =>
-          c.from.sid == this.st.user.sid && c.type == ctype);
+          (c.from.sid == this.st.user.sid || c.from.id == this.st.user.id) && c.type == ctype);
         if (cIdx >= 0)
         {
           // Delete current challenge (will be replaced now)
diff --git a/server/models/Challenge.js b/server/models/Challenge.js
index 7ccaa76f..fabeb7ae 100644
--- a/server/models/Challenge.js
+++ b/server/models/Challenge.js
@@ -56,14 +56,17 @@ const ChallengeModel =
     });
   },
 
-  // All challenges except where target is defined and not me
+  // All challenges except where target is defined and not me,
+  // and I'm not the sender.
   getByUser: function(uid, cb)
   {
     db.serialize(function() {
       const query =
         "SELECT * " +
         "FROM Challenges " +
-        "WHERE target IS NULL OR target = " + uid;
+        "WHERE target IS NULL" +
+          " OR uid = " + uid +
+          " OR target = " + uid;
       db.all(query, (err,challenges) => {
         return cb(err, challenges);
       });
diff --git a/server/models/User.js b/server/models/User.js
index 1a5397db..ff019bdb 100644
--- a/server/models/User.js
+++ b/server/models/User.js
@@ -131,16 +131,19 @@ const UserModel =
   /////////////////
   // NOTIFICATIONS
 
-  tryNotify: function(oppId, message)
+  notify: function(user, 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 || {});
-      });
+    const subject = "vchess.club - notification";
+    const body = "Hello " + user.name + "!\n" + message;
+    sendEmail(params.mail.noreply, user.email, subject, body);
+  },
+
+  tryNotify: function(id, message)
+  {
+    UserModel.getOne("id", id, (err,user) => {
+      if (!err || !user.notify)
+        return; //NOTE: error is ignored here
+      UserModel.notify(user, message);
     });
   },
 
diff --git a/server/routes/all.js b/server/routes/all.js
index a890e609..a3eb8587 100644
--- a/server/routes/all.js
+++ b/server/routes/all.js
@@ -1,5 +1,5 @@
-var router = require("express").Router();
-var access = require("../utils/access");
+let router = require("express").Router();
+const access = require("../utils/access");
 
 // To avoid a weird preflight AJAX request error in dev mode...
 router.get("/", access.ajax, (req,res) => {
diff --git a/server/routes/challenges.js b/server/routes/challenges.js
index 146bbe2d..28103fce 100644
--- a/server/routes/challenges.js
+++ b/server/routes/challenges.js
@@ -4,6 +4,7 @@ let router = require("express").Router();
 const access = require("../utils/access");
 const ChallengeModel = require("../models/Challenge");
 const UserModel = require("../models/User"); //for name check
+const params = require("../config/parameters");
 
 router.get("/challenges", (req,res) => {
   ChallengeModel.getByUser(req.query["uid"], (err,challenges) => {
@@ -35,6 +36,8 @@ router.post("/challenges", access.logged, access.ajax, (req,res) => {
         return res.json(err | {errmsg: "Typo in player name"});
       challenge.to = user.id; //ready now to insert challenge
       insertChallenge();
+      if (user.notify)
+        UserModel.notify(user, "New challenge: " + params.siteURL + "/");
     });
   }
   else
diff --git a/server/routes/games.js b/server/routes/games.js
index c6e25a6a..bef8bf5e 100644
--- a/server/routes/games.js
+++ b/server/routes/games.js
@@ -1,10 +1,10 @@
-var router = require("express").Router();
-var UserModel = require("../models/User");
-var ChallengeModel = require('../models/Challenge');
-var GameModel = require('../models/Game');
-var VariantModel = require('../models/Variant');
-var access = require("../utils/access");
-var params = require("../config/parameters");
+let router = require("express").Router();
+const UserModel = require("../models/User");
+const ChallengeModel = require('../models/Challenge');
+const GameModel = require('../models/Game');
+const VariantModel = require('../models/Variant');
+const access = require("../utils/access");
+const params = require("../config/parameters");
 
 // From main hall, start game between players 0 and 1
 router.post("/games", access.logged, access.ajax, (req,res) => {
diff --git a/server/routes/users.js b/server/routes/users.js
index 129cda23..ab139eb6 100644
--- a/server/routes/users.js
+++ b/server/routes/users.js
@@ -1,11 +1,11 @@
 // AJAX methods to get, create, update or delete a user
 
-var router = require("express").Router();
-var UserModel = require('../models/User');
-var sendEmail = require('../utils/mailer');
-var genToken = require("../utils/tokenGenerator");
-var access = require("../utils/access");
-var params = require("../config/parameters");
+let router = require("express").Router();
+const UserModel = require('../models/User');
+const sendEmail = require('../utils/mailer');
+const genToken = require("../utils/tokenGenerator");
+const access = require("../utils/access");
+const params = require("../config/parameters");
 
 // NOTE: this method is safe because the sessionToken must be guessed
 router.get("/whoami", access.ajax, (req,res) => {
diff --git a/server/utils/mailer.js b/server/utils/mailer.js
index 9a42a174..9d3ea302 100644
--- a/server/utils/mailer.js
+++ b/server/utils/mailer.js
@@ -10,8 +10,12 @@ module.exports = function(from, to, subject, body, cb)
     console.log("Subject: " + subject);
     let msgText = body.split('\\n');
     msgText.forEach(msg => { console.log(msg); });
+    if (!cb)
+      cb = (err) => { if (!!err) console.log(err); }
     return cb();
   }
+  else if (!cb)
+    cb = () => {}; //default: do nothing (TODO: log somewhere)
 
   // Create reusable transporter object using the default SMTP transport
   const transporter = nodemailer.createTransport({
-- 
2.44.0