div(v-show="stage!='Login'")
fieldset
label(for="username") {{ st.tr["Name"] }}
- input#username(type="text" v-model="user.name")
+ input#username(type="text" v-model="st.user.name")
fieldset
label(for="useremail") {{ st.tr["Email"] }}
- input#useremail(type="email" v-model="user.email")
+ input#useremail(type="email" v-model="st.user.email")
fieldset
label(for="notifyNew") {{ st.tr["Notifications by email"] }}
- input#notifyNew(type="checkbox" v-model="user.notify")
+ input#notifyNew(type="checkbox" v-model="st.user.notify")
div(v-show="stage=='Login'")
fieldset
label(for="nameOrEmail") {{ st.tr["Name or Email"] }}
name: 'my-upsert-user',
data: function() {
return {
- user: store.state.user,
nameOrEmail: "", //for login
logStage: "Login", //or Register
infoMsg: "",
nameOrEmail: function(newValue) {
if (newValue.indexOf('@') >= 0)
{
- this.user.email = newValue;
- this.user.name = "";
+ this.st.user.email = newValue;
+ this.st.user.name = "";
}
else
{
- this.user.name = newValue;
- this.user.email = "";
+ this.st.user.name = newValue;
+ this.st.user.email = "";
}
},
},
return (this.infoMsg.length > 0 ? "block" : "none");
},
stage: function() {
- return this.user.id > 0 ? "Update" : this.logStage;
+ return this.st.user.id > 0 ? "Update" : this.logStage;
},
},
methods: {
error = checkNameEmail({[type]: this.nameOrEmail});
}
else
- error = checkNameEmail(this.user);
+ error = checkNameEmail(this.st.user);
if (!!error)
return alert(error);
this.infoMsg = "Processing... Please wait";
ajax(this.ajaxUrl(), this.ajaxMethod(),
- this.stage == "Login" ? { nameOrEmail: this.nameOrEmail } : this.user,
+ this.stage == "Login" ? { nameOrEmail: this.nameOrEmail } : this.st.user,
res => {
this.infoMsg = this.infoMessage();
if (this.stage != "Update")
);
},
doLogout: function() {
- let logoutBtn = document.getElementById("logoutBtn");
- logoutBtn.disabled = true;
- // NOTE: this local cleaning would logically happen when we're sure
- // that token is erased. But in the case a user clear the cookies,
- // it would lead to situations where he cannot ("locally") log out.
- // At worst, if token deletion fails the user can erase cookie manually.
- this.user.id = 0;
- this.user.name = "";
- this.user.email = "";
- this.user.notify = false;
- localStorage.removeItem("myid");
- localStorage.removeItem("myname");
- ajax("/logout", "GET", () => {
- logoutBtn.disabled = false; //for symmetry, but not very useful...
- document.getElementById("modalUser").checked = false;
- // this.$router.push("/") will fail if logout from Hall, so:
- document.location.reload(true);
- });
+ document.getElementById("modalUser").checked = false;
+ this.$router.push("/logout");
},
},
};
{
path: "/authenticate/:token",
name: "authenticate",
- beforeEnter: (to, from, next) => {
- ajax(
- "/authenticate",
- "GET",
- {token: to.params["token"]},
- (res) => {
- if (!res.errmsg) //if not already logged in
- {
- store.state.user.id = res.id;
- store.state.user.name = res.name;
- store.state.user.email = res.email;
- store.state.user.notify = res.notify;
- localStorage["myname"] = res.name;
- localStorage["myid"] = res.id;
- }
- // TODO: I don't like these 2 lines, "next('/')" should be enough
- window.location = "/";
- next();
- }
- );
- },
- component: Hall,
- //redirect: "/", //problem: redirection before end of AJAX request
+ component: loadView("Auth"),
+ },
+ {
+ path: "/logout",
+ name: "logout",
+ component: loadView("Logout"),
},
{
path: "/mygames",
"All": "All",
"Analyze": "Analyze",
"Analyze in Dark mode makes no sense!": "Analyze in Dark mode makes no sense!",
+ "Authentication successful!": "Authentication successful!",
"Apply": "Apply",
"Available": "Available",
"Black": "Black",
"Live games": "Live games",
"Login": "Login",
"Logout": "Logout",
+ "Logout successful!": "Logout successful!",
"Modifications applied!": "Modifications applied!",
"Mutual agreement": "Mutual agreement",
"My games": "My games",
"Analyze": "Analizar",
"Analyze in Dark mode makes no sense!": "¡ Analizar en modo Dark no tiene sentido !",
"Apply": "Aplicar",
+ "Authentication successful!": "¡ Autenticación exitosa !",
"Available": "Disponible",
"Black": "Negras",
"Black to move": "Juegan las negras",
"Live games": "Partidas en vivo",
"Login": "Login",
"Logout": "Logout",
+ "Logout successful!": "¡ Desconexión exitosa !",
"Modifications applied!": "¡ Modificaciones aplicadas !",
"Mutual agreement": "Acuerdo mutuo",
"My games": "Mis partidas",
"Analyze": "Analyser",
"Analyze in Dark mode makes no sense!": "Analyser en mode Dark n'a pas de sens !",
"Apply": "Appliquer",
+ "Authentication successful!": "Authentification réussie !",
"Available": "Disponible",
"Black": "Noirs",
"Black to move": "Trait aux noirs",
"Live games": "Parties en direct",
"Login": "Login",
"Logout": "Logout",
+ "Logout successful!": "Déconnection réussie !",
"Modifications applied!": "Modifications effectuées !",
"Mutual agreement": "Accord mutuel",
"My games": "Mes parties",
},
};
</script>
-
-<style lang="sass">
-.warn
- padding: 3px
- color: red
- background-color: lightgrey
- font-weight: bold
-
-p.boxed
- background-color: #FFCC66
- padding: 5px
-
-.stageDelimiter
- color: purple
-
-.section-title
- padding: 0
-
-.section-title > h4
- padding: 5px
-
-ol, ul:not(.browser-default)
- padding-left: 20px
-
-ul:not(.browser-default)
- margin-top: 5px
-
-ul:not(.browser-default) > li
- list-style-type: disc
-</style>
--- /dev/null
+<template lang="pug">
+main
+ .row
+ .col-sm-12.col-md-10.col-md-offset-1.col-lg-8.col-lg-offset-2
+ p(:class="{warn:!!this.errmsg}")
+ | {{ errmsg || st.tr["Authentication successful!"] }}
+</template>
+
+<script>
+import { store } from "@/store";
+import { ajax } from "@/utils/ajax";
+
+export default {
+ name: 'my-auth',
+ data: function() {
+ return {
+ st: store.state,
+ errmsg: "",
+ };
+ },
+ created: function() {
+ ajax(
+ "/authenticate",
+ "GET",
+ {token: this.$route.params["token"]},
+ (res) => {
+ if (!res.errmsg) //if not already logged in
+ {
+ this.st.user.id = res.id;
+ this.st.user.name = res.name;
+ this.st.user.email = res.email;
+ this.st.user.notify = res.notify;
+ localStorage["myname"] = res.name;
+ localStorage["myid"] = res.id;
+ }
+ else
+ this.errmsg = res.errmsg;
+ }
+ );
+ },
+};
+</script>
+
+<style lang="sass" scoped>
+.warn
+ padding: 3px
+ color: red
+ background-color: lightgrey
+ font-weight: bold
+</style>
switch (data.code)
{
case "duplicate":
+ this.st.conn.send(JSON.stringify({code:"duplicate"}));
alert(this.st.tr["Warning: multi-tabs not supported"]);
break;
// 0.2] Receive clients list (just socket IDs)
case "pollclients":
- {
data.sockIds.forEach(sid => {
if (!!this.people[sid])
return;
this.st.conn.send(JSON.stringify({code:"askidentity", target:sid}));
});
break;
- }
case "askidentity":
- {
// Request for identification: reply if I'm not anonymous
if (this.st.user.id > 0)
{
target:data.from}));
}
break;
- }
case "identity":
- {
this.$set(this.people, data.user.sid,
{id: data.user.id, name: data.user.name});
// Ask potentially missed last state, if opponent and I play
this.st.conn.send(JSON.stringify({code:"asklastate", target:data.user.sid}));
}
break;
- }
case "asklastate":
- {
// Sending last state if I played a move or score != "*"
if ((this.game.moves.length > 0 && this.vr.turn != this.game.mycolor)
|| this.game.score != "*" || this.drawOffer == "sent")
}));
}
break;
- }
case "askgame":
// Send current (live) game if I play in (not an observer),
// and not asked by opponent (!)
document.getElementById("chatBtn").style.backgroundColor = "#c5fefe";
break;
case "lastate": //got opponent infos about last move
- {
this.lastate = data.state;
if (this.game.rendered) //game is rendered (Board component)
this.processLastate();
//else: will be processed when game is ready
break;
- }
case "resign":
this.gameOver(data.side=="b" ? "1-0" : "0-1", "Resign");
break;
this.loadGame(data.game, this.roomInit);
break;
case "connect":
- {
this.$set(this.people, data.from, {name:"", id:0});
this.st.conn.send(JSON.stringify({code:"askidentity", target:data.from}));
break;
- }
case "disconnect":
this.$delete(this.people, data.from);
break;
// Always add myself to players' list
const my = this.st.user;
this.$set(this.people, my.sid, {id:my.id, name:my.name});
- // Retrieve live challenge (not older than 30 minute) if any:
- const chall = JSON.parse(localStorage.getItem("challenge") || "false");
- if (!!chall)
- {
- // NOTE: a challenge survives 3 minutes, for potential connection issues
- if ((Date.now() - chall.added)/1000 <= 3*60)
- {
- chall.added = Date.now(); //update added time, for next disconnect...
- this.challenges.push(chall);
- localStorage.setItem("challenge", JSON.stringify(chall));
- }
- else
- localStorage.removeItem("challenge");
- }
// Ask server for current corr games (all but mines)
ajax(
"/games",
switch (data.code)
{
case "duplicate":
+ this.st.conn.send(JSON.stringify({code:"duplicate"}));
+ this.st.conn.send = () => {};
alert(this.st.tr["Warning: multi-tabs not supported"]);
break;
// 0.2] Receive clients list (just socket IDs)
this.st.conn.send(JSON.stringify({code:"askgames"}));
break;
case "askidentity":
- {
// Request for identification: reply if I'm not anonymous
if (this.st.user.id > 0)
{
target:data.from}));
}
break;
- }
case "identity":
- {
this.$set(this.people, data.user.sid,
{
id: data.user.id,
gamer: this.people[data.user.sid].gamer,
});
break;
- }
case "askchallenge":
{
// Send my current live challenge (if any)
break;
}
case "challenge":
- {
// Receive challenge from some player (+sid)
// NOTE about next condition: see "askchallenge" case.
if (!data.chall.to || data.chall.to == this.st.user.name)
this.challenges.push(newChall);
}
break;
- }
case "game":
{
// Receive game from some player (+sid)
break;
}
case "newgame":
- {
// New game just started: data contain all information
if (this.classifyObject(data.gameInfo) == "live")
this.startNewGame(data.gameInfo);
setTimeout(() => { modalBox.checked = false; }, 3000);
}
break;
- }
case "newchat":
this.newChat = data.chat;
break;
case "refusechallenge":
- {
ArrayFun.remove(this.challenges, c => c.id == data.cid);
- localStorage.removeItem("challenge");
alert(this.st.tr["Challenge declined"]);
break;
- }
case "deletechallenge":
- {
// NOTE: the challenge may be already removed
ArrayFun.remove(this.challenges, c => c.id == data.cid);
- localStorage.removeItem("challenge"); //in case of
break;
- }
case "connect":
case "gconnect":
this.$set(this.people, data.from, {name:"", id:0, gamer:data.code[0]=='g'});
name: this.st.user.name,
};
this.challenges.push(chall);
- if (ctype == "live")
- localStorage.setItem("challenge", JSON.stringify(chall));
- // Also remember timeControl + vid for quicker further challenges:
+ // Remember timeControl + vid for quicker further challenges:
localStorage.setItem("timeControl", chall.timeControl);
localStorage.setItem("vid", chall.vid);
document.getElementById("modalNewgame").checked = false;
{id: c.id}
);
}
- else //live
- localStorage.removeItem("challenge");
this.sendSomethingTo({name:c.to}, "deletechallenge", {cid:c.id});
}
// In all cases, the challenge is consumed:
--- /dev/null
+<template lang="pug">
+main
+ .row
+ .col-sm-12.col-md-10.col-md-offset-1.col-lg-8.col-lg-offset-2
+ p(:class="{warn:!!this.errmsg}")
+ | {{ errmsg || st.tr["Logout successful!"] }}
+</template>
+
+<script>
+import { store } from "@/store";
+import { ajax } from "@/utils/ajax";
+
+export default {
+ name: 'my-logout',
+ data: function() {
+ return {
+ st: store.state,
+ errmsg: "",
+ };
+ },
+ created: function() {
+ // NOTE: this local cleaning would logically happen when we're sure
+ // that token is erased. But in the case a user clear the cookies,
+ // it would lead to situations where he cannot ("locally") log out.
+ // At worst, if token deletion fails the user can erase cookie manually.
+ this.st.user.id = 0;
+ this.st.user.name = "";
+ this.st.user.email = "";
+ this.st.user.notify = false;
+ localStorage.removeItem("myid");
+ localStorage.removeItem("myname");
+ ajax("/logout", "GET"); //TODO: listen for errors?
+ },
+};
+</script>
+
+<style lang="sass" scoped>
+.warn
+ padding: 3px
+ color: red
+ background-color: lightgrey
+ font-weight: bold
+</style>
wss.on("connection", (socket, req) => {
const query = getJsonFromUrl(req.url);
const sid = query["sid"];
- if (!!clients[sid])
- {
- // Dummy messages listener: just send "duplicate" event on anything
- // ('connect' events for Hall and Game, 'askfullgame' for observers)
- return socket.on("message", objtxt => {
- if (["connect","askfullgame"].includes(JSON.parse(objtxt).code))
- socket.send(JSON.stringify({code:"duplicate"}));
- });
- }
- clients[sid] = {sock: socket, page: query["page"]};
const notifyRoom = (page,code,obj={},excluded=[]) => {
Object.keys(clients).forEach(k => {
if (k in excluded)
}
});
};
- // Wait for "connect" message to notify connection to the room,
- // because if game loading is slow the message listener might
- // not be ready too early.
- socket.on("message", objtxt => {
+ const messageListener = (objtxt) => {
let obj = JSON.parse(objtxt);
if (!!obj.target && !clients[obj.target])
return; //receiver not connected, nothing we can do
switch (obj.code)
{
+ case "duplicate":
+ // Turn off message listening, and send disconnect if needed:
+ socket.removeListener("message", messageListener);
+ socket.removeListener("close", closeListener);
+ if (clients[sid].page != obj.page)
+ {
+ notifyRoom(clients[sid].page, "disconnect");
+ if (clients[sid].page.indexOf("/game/") >= 0)
+ notifyRoom("/", "gdisconnect");
+ }
+ break;
+ // Wait for "connect" message to notify connection to the room,
+ // because if game loading is slow the message listener might
+ // not be ready too early.
case "connect":
{
const curPage = clients[sid].page;
{code:"draw", message:obj.message}));
break;
}
- });
- socket.on("close", () => {
+ };
+ const closeListener = () => {
const page = clients[sid].page;
delete clients[sid];
notifyRoom(page, "disconnect");
if (page.indexOf("/game/") >= 0)
notifyRoom("/", "gdisconnect"); //notify main hall
- });
+ };
+ if (!!clients[sid])
+ {
+ // Turn off old sock through current client:
+ clients[sid].sock.send(JSON.stringify({code:"duplicate"}));
+ }
+ // Potentially replace current connection:
+ clients[sid] = {sock: socket, page: query["page"]};
+ socket.on("message", messageListener);
+ socket.on("close", closeListener);
});
}