Some advances. TODO: test board.js, and then game.js, and then implement room.js
authorBenjamin Auder <benjamin.auder@somewhere>
Sat, 12 Jan 2019 14:21:00 +0000 (15:21 +0100)
committerBenjamin Auder <benjamin.auder@somewhere>
Sat, 12 Jan 2019 14:21:00 +0000 (15:21 +0100)
17 files changed:
TODO
config/parameters.js.dist
db/create.sql
models/Game.js
models/Problem.js
public/javascripts/components/game.js
public/javascripts/components/problems.js
public/javascripts/index.js
public/javascripts/layout.js
public/stylesheets/index.sass
public/stylesheets/layout.sass
reflexions [new file with mode: 0644]
routes/playing.js
utils/access.js
utils/tokenGenerator.js
views/index.pug
views/userMenu.pug

diff --git a/TODO b/TODO
index a4a9d5b..7ea4813 100644 (file)
--- a/TODO
+++ b/TODO
@@ -1,3 +1,8 @@
+Sur index, introduction menu remplacé par "mes parties", montrant parties (corr) en cours toutes variantes confondues
+Dans variant page, "mes parties" peut toujours contenir corr + importées (deux onglets)
+En fin de partie (observée ou non), bouton "import game" en + de "download game" ==> directement dans indexedDB
+--> sursis de 7 jours pour les parties par correspondance, qui sont encore chargées depuis le serveur
+
 mat en 2 échiqueté : brnkr3/pppp1p1p/4ps2/8/2P2P2/P1qP4/2c1s1PP/R1K5
 (Bb3+ Kb1 Ba2#)
 
index bb3cbe2..6f274dd 100644 (file)
@@ -1,4 +1,4 @@
-const Parameters =
+module.exports =
 {
        // For mail sending. NOTE: *no trailing slash*
        siteURL: "http://localhost:3000",
@@ -7,12 +7,12 @@ const Parameters =
        env: process.env.NODE_ENV || 'development',
 
        // Lifespan of a (login) cookie
-       cookieExpire: 183*24*3600*1000, //6 months in milliseconds
+       cookieExpire: 183*24*60*60*1000, //6 months in milliseconds
 
        // Characters in a login token, and period of validity (in milliseconds)
        token: {
                length: 16,
-               expire: 1000*60*30, //30 minutes in milliseconds
+               expire: 30*60*1000, //30 minutes in milliseconds
        },
 
        // Email settings
@@ -26,5 +26,3 @@ const Parameters =
                contact: "some_contact_email",
        },
 };
-
-module.exports = Parameters;
index e94b84a..5f463bf 100644 (file)
@@ -59,11 +59,11 @@ create table Games (
 
 -- Store informations about players in a corr game
 create table Players (
+       gid integer,
        uid integer,
        color character,
-       gid integer,
-       foreign key (uid) references Users(id),
-       foreign key (gid) references Games(id)
+       foreign key (gid) references Games(id),
+       foreign key (uid) references Users(id)
 );
 
 create table Moves (
index 2e57309..d279514 100644 (file)
@@ -1 +1 @@
-//TODO: at least this model (maybe MoveModel ?!)
+//TODO:
index 6184eaf..7858676 100644 (file)
@@ -65,7 +65,7 @@ exports.fetchN = function(vname, uid, type, directionStr, lastDt, MaxNbProblems,
                        "WHERE vid = (SELECT id FROM Variants WHERE name = '" + vname + "') " +
                        "  AND added " + directionStr + " " + lastDt + " " + typeLine + " " +
                        "ORDER BY added " + (directionStr=="<" ? "DESC " : "") +
-                       "LIMIT " + MaxNbProblems,
+                       "LIMIT " + MaxNbProblems;
                db.all(query, callback);
        });
 }
index 39c12c0..ca79125 100644 (file)
@@ -4,7 +4,7 @@
 // Game logic on a variant page: 3 modes, analyze, computer or human
 Vue.component('my-game', {
        // gameId: to find the game in storage (assumption: it exists)
-       props: ["gameId","mode","allowChat","allowMovelist"],
+       props: ["gameId","fen","mode","allowChat","allowMovelist"],
        data: function() {
                return {
                        // if oppid == "computer" then mode = "computer" (otherwise human)
@@ -24,6 +24,11 @@ Vue.component('my-game', {
                        vr: null, //VariantRules object, describing the game state + rules
                };
        },
+       watch: {
+               fen: function(newFen) {
+                       this.vr = new VariantRules(newFen);
+               },
+       },
        computed: {
                showChat: function() {
                        return this.allowChat && this.mode=='human' && this.score != '*';
index 9a14c70..5307704 100644 (file)
@@ -38,7 +38,7 @@ Vue.component('my-problems', {
                                                {{ curProb.instructions }}
                                        </p>
                                </div>
-                               <my-board :fen="curProb.fen" :analyze:"true" .................> //TODO: use my-game in analyze mode ?
+                               <my-game :fen="curProb.fen" :mode="analyze" :allowMovelist="true">
                                </my-board>
                                <div id="solution-div" class="section-content">
                                        <h3 class="clickable" @click="showSolution = !showSolution">
index 3d35c45..bc4cd9e 100644 (file)
@@ -5,10 +5,10 @@ new Vue({
                counts: {},
                curPrefix: "",
                conn: null,
+               display: "variants",
        },
        computed: {
                sortedCounts: function () {
-                       // TODO: priorité aux parties corr où c'est à nous de jouer !
                        const capitalizedPrefix = this.curPrefix.replace(/^\w/, c => c.toUpperCase());
                        const variantsCounts = variantArray
                        .filter( v => {
@@ -50,7 +50,7 @@ new Vue({
                this.conn.onmessage = socketMessageListener;
                this.conn.onclose = socketCloseListener;
 
-               // TODO:
+               // TODO: AJAX call get corr games (all variants)
                // si dernier lastMove sur serveur n'est pas le mien et nextColor == moi, alors background orange
                // ==> background orange si à moi de jouer par corr (sur main index)
                // (helper: static fonction "GetNextCol()" dans base_rules.js)
index 6d26b92..8cb79e0 100644 (file)
@@ -2,3 +2,4 @@
 //à l'arrivée sur le site : set peerID (un identifiant unique en tout cas...) si pas trouvé
 //
 //TODO: si une partie en cours dans storage, rediriger vers cette partie
+//(à condition que l'URL n'y corresponde pas déjà !)
index d25ecb4..5f76e00 100644 (file)
       margin-top: 10px
       font-size: 1em
 
-#introductionMenu, #userMenu
-  float: right
-  @media screen and (max-width: 767px)
-    .info-container
-      p
-        margin-right: 5px
-
 #flagMenu
   float: right
   margin-right: 10px
index eae4542..161995d 100644 (file)
@@ -35,6 +35,13 @@ body
       border-left: 1px solid var(--button-group-border-color)
       border-top: 0
 
+.right-menu
+  float: right
+  @media screen and (max-width: 767px)
+    .info-container
+      p
+        margin-right: 5px
+
 #settings, #contactForm
   max-width: 767px
   @media screen and (max-width: 767px)
diff --git a/reflexions b/reflexions
new file mode 100644 (file)
index 0000000..61c9932
--- /dev/null
@@ -0,0 +1,5 @@
+tell opponent that I got the move, for him to start timer (and lose...)
+board2, board3, board4
+VariantRules2, 3 et 4 aussi
+fetch challenges and corr games from server at startup (room)
+but forbid anonymous to start corr games or accept challenges
index 37592c9..7af0a1b 100644 (file)
@@ -90,12 +90,8 @@ router.get("/gamesbyplayer", access.logged, access.ajax, (req,res) => {
        });
 });
 
-// Load a rules page
-router.get("/rules/:variant([a-zA-Z0-9]+)", access.ajax, (req,res) => {
-       res.render("rules/" + req.params["variant"]);
-});
-
 // TODO: if newmove fail, takeback in GUI // TODO: check move structure
+// TODO: for corr games, move should contain an optional "message" field ("corr chat" !)
 router.post("/moves", access.logged, access.ajax, (req,res) => {
        let gid = ObjectId(req.body.gid);
        let fen = req.body.fen;
@@ -111,16 +107,4 @@ router.post("/moves", access.logged, access.ajax, (req,res) => {
        });
 });
 
-//TODO: if new chat fails, do not show chat message locally
-router.post("/chats", access.logged, access.ajax, (req,res) => {
-       let gid = ObjectId(req.body.gid);
-       let uid = ObjectId(req.body.uid);
-       let msg = req.body.msg; //TODO: sanitize HTML (strip all tags...)
-       GameModel.addChat(gid, uid, msg, (err,game) => {
-               access.checkRequest(res, err, game, "Cannot find game", () => {
-                       res.json({});
-               });
-       });
-});
-
 module.exports = router;
index 1c82cb6..49d204c 100644 (file)
@@ -1,41 +1,36 @@
-var Access = {};
-
-// Prevent access to "users pages"
-Access.logged = function(req, res, next)
+module.exports =
 {
-       if (req.userId == 0)
-               return res.redirect("/");
-       next();
-};
+       // Prevent access to "users pages"
+       logged: function(req, res, next) {
+               if (req.userId == 0)
+                       return res.redirect("/");
+               next();
+       },
 
-// Prevent access to "anonymous pages"
-Access.unlogged = function(req, res, next)
-{
-       if (req.userId > 0)
-               return res.redirect("/");
-       next();
-};
+       // Prevent access to "anonymous pages"
+       unlogged: function(req, res, next) {
+               if (req.userId > 0)
+                       return res.redirect("/");
+               next();
+       },
 
-// Prevent direct access to AJAX results
-Access.ajax = function(req, res, next)
-{
-       if (!req.xhr)
-               return res.json({errmsg: "Unauthorized access"});
-       next();
-}
+       // Prevent direct access to AJAX results
+       ajax: function(req, res, next) {
+               if (!req.xhr)
+                       return res.json({errmsg: "Unauthorized access"});
+               next();
+       },
 
-// Check for errors before callback (continue page loading). TODO: better name.
-Access.checkRequest = function(res, err, out, msg, cb)
-{
-       if (!!err)
-               return res.json({errmsg: err.errmsg || err.toString()});
-       if (!out
-               || (Array.isArray(out) && out.length == 0)
-               || (typeof out === "object" && Object.keys(out).length == 0))
-       {
-               return res.json({errmsg: msg});
-       }
-       cb();
+       // Check for errors before callback (continue page loading). TODO: better name.
+       checkRequest: function(res, err, out, msg, cb) {
+               if (!!err)
+                       return res.json({errmsg: err.errmsg || err.toString()});
+               if (!out
+                       || (Array.isArray(out) && out.length == 0)
+                       || (typeof out === "object" && Object.keys(out).length == 0))
+               {
+                       return res.json({errmsg: msg});
+               }
+               cb();
+       },
 }
-
-module.exports = Access;
index 5578c2e..1bc172c 100644 (file)
@@ -1,17 +1,14 @@
-var TokenGen = {};
-
-TokenGen.rand = function()
+module.exports =
 {
-       return Math.random().toString(36).substr(2); // remove `0.`
-};
+       rand: function() {
+               return Math.random().toString(36).substr(2); // remove `0.`
+       },
 
-TokenGen.generate = function(tlen)
-{
-       var res = "";
-       var nbRands = Math.ceil(tlen/10); //10 = min length of a rand() string
-       for (var i = 0; i < nbRands; i++)
-               res += TokenGen.rand();
-       return res.substr(0, tlen);
+       generate: function(tlen) {
+               var res = "";
+               var nbRands = Math.ceil(tlen/10); //10 = min length of a rand() string
+               for (var i = 0; i < nbRands; i++)
+                       res += TokenGen.rand();
+               return res.substr(0, tlen);
+       },
 }
-
-module.exports = TokenGen;
index 6b13a4e..823b67c 100644 (file)
@@ -14,7 +14,7 @@ block content
                                include welcome/fr
                .row
                        #header.col-sm-12.col-md-10.col-md-offset-1.col-lg-8.col-lg-offset-2
-                               #mainTitle
+                               #mainTitle.clickable(onClick="doClick('modalWelcome')")
                                        img(src="/images/index/unicorn.svg")
                                        .info-container
                                                p vchess.club
@@ -22,16 +22,21 @@ block content
                                #flagMenu.clickable(onClick="doClick('modalLang')")
                                        img(src="/images/flags/" + lang + ".svg")
                                include userMenu
-                               #introductionMenu.clickable(onClick="doClick('modalWelcome')")
+                               #mygamesMenu.clickable.right-menu(v-show="display=='variants'" @click="display='games'")
                                        .info-container
-                                               p Introduction
-               .row
+                                               p My games
+                               #variantsMenu.clickable.right-menu(v-show="display=='games'" @click="display='variants'")
+                                       .info-container
+                                               p Variants
+               .row(v-show="display=='variants'")
                        .col-sm-12.col-md-10.col-md-offset-1.col-lg-8.col-lg-offset-2
                                label(for="prefixFilter") Type first letters...
                                input#prefixFilter(v-model="curPrefix")
-               .row
                        my-variant-summary(v-for="(v,idx) in sortedCounts"
                                v-bind:vobj="v" v-bind:index="idx" v-bind:key="v.name")
+               .row(v-show="display=='games'")
+                       .col-sm-12.col-md-10.col-md-offset-1.col-lg-8.col-lg-offset-2
+                               p TODO: load from server, show timeControl + players + link "play"
 
 block javascripts
        script.
index f590a2e..5a0b074 100644 (file)
@@ -1,4 +1,4 @@
-#userMenu.clickable(onClick="doClick('modalUser')")
+#userMenu.clickable.right-menu(onClick="doClick('modalUser')")
        .info-container
                if !user.email
                        p