diff --git a/app.js b/app.js
index 86feab0..d39ce30 100644
--- a/app.js
+++ b/app.js
@@ -98,8 +98,7 @@ function enter(res, user) { //login, color, id
msg.id = result[0]["max(id)"] + 1;
chat.addnewmessage(msg);
res.cookie("danchat.token", token, {
- path: "/",
- httpOnly: true
+ path: "/"
});
res.redirect("/");
})
@@ -521,7 +520,24 @@ app.post("/user/add/friend", parserJSON, (req, res) => {
var userId = dt1[0].id;
sql.query(`insert into friends_requests(from_id, to_id) values (${u.id}, ${userId})`, (err) => {
if (err) console.error(err);
- res.json(new ResponseObject(true));
+ sql.query(`select token from tokens where id = ${userId}`, (err, data) => {
+ if (err) console.error(err);
+ if (data === undefined || data.length === 0) {
+ res.json(new ResponseObject(true));
+ } else {
+ sql.query(`select login, firstname, lastname, color, sex from users where id = ${u.id}`, (err, dt2) => {
+ if (err) console.error(err);
+ io.emit(data[0].token, {
+ type: "newIncomingRequest",
+ login: dt2[0].login,
+ name: `${dt2[0].firstname} ${dt2[0].lastname}`,
+ color : dt2[0].color,
+ sex : dt2[0].sex
+ })
+ res.json(new ResponseObject(true));
+ })
+ }
+ })
})
})
}
@@ -582,7 +598,24 @@ app.post("/user/accept/incomingrequest", parserJSON, (req, res) => {
if (err) console.error(err);
sql.query(`insert into friends (id_1, id_2) values (${userId}, ${u.id})`, (err) => {
if (err) console.error(err);
- res.json(new ResponseObject(true));
+ sql.query(`select token from tokens where id = ${userId}`, (err, data) => {
+ if (err) console.error(err);
+ if (data === undefined || data.length === 0) {
+ res.json(new ResponseObject(true));
+ } else {
+ sql.query(`select login, firstname, lastname, sex, color from users where id = ${u.id}`, (err, dt2) => {
+ if (err) console.error(err);
+ io.emit(data[0].token, {
+ type: "acceptOutcomingRequest",
+ login: dt2[0].login,
+ name: `${dt2[0].firstname} ${dt2[0].lastname}`,
+ color : dt2[0].color,
+ sex : dt2[0].sex
+ })
+ res.json(new ResponseObject(true));
+ })
+ }
+ })
})
})
})
@@ -609,7 +642,24 @@ app.post("/user/delete/friend", parserJSON, (req, res) => {
if (err) console.error(err);
sql.query(`insert into friends_requests (from_id, to_id) values (${friendId}, ${u.id})`, (err) => {
if (err) console.error(err);
- res.json(new ResponseObject(true));
+ sql.query(`select token from tokens where id = ${friendId}`, (err, data) => {
+ if (err) console.error(err);
+ if (data === undefined || data.length === 0) {
+ res.json(new ResponseObject(true));
+ } else {
+ sql.query(`select login, firstname, lastname, sex, color from users where id = ${u.id}`, (err, dt2) => {
+ if (err) console.error(err);
+ io.emit(data[0].token, {
+ type: "deletingFromFriends",
+ login: dt2[0].login,
+ name: `${dt2[0].firstname} ${dt2[0].lastname}`,
+ color : dt2[0].color,
+ sex : dt2[0].sex
+ })
+ res.json(new ResponseObject(true));
+ })
+ }
+ })
})
})
})
diff --git a/public/js/functions.js b/public/js/functions.js
new file mode 100644
index 0000000..bf48e9f
--- /dev/null
+++ b/public/js/functions.js
@@ -0,0 +1,6 @@
+function getCookie(name) {
+ var matches = document.cookie.match(new RegExp(
+ "(?:^|; )" + name.replace(/([\.$?*|{}\(\)\[\]\\\/\+^])/g, '\\$1') + "=([^;]*)"
+ ));
+ return matches ? decodeURIComponent(matches[1]) : undefined;
+}
diff --git a/public/js/notifications.js b/public/js/notifications.js
new file mode 100644
index 0000000..36a5950
--- /dev/null
+++ b/public/js/notifications.js
@@ -0,0 +1,33 @@
+socket.on(getCookie("danchat.token"), function(update) {
+ if (update.type === "newIncomingRequest") {
+ VanillaToasts.create({
+ title: "Уведомление",
+ text: `${update.login} (${update.name}) хочет с вами дружить`,
+ type: "info",
+ callback: ()=>{
+ location = "/incoming"
+ },
+ timeout:20000
+ });
+ } else if (update.type === "acceptOutcomingRequest") {
+ VanillaToasts.create({
+ title: "Уведомление",
+ text: `${update.login} (${update.name}) принял${update.sex?"":"а"} вашу заявку`,
+ type: "success",
+ callback: ()=>{
+ location = "/friends"
+ },
+ timeout:20000
+ });
+ } else if (update.type === "deletingFromFriends") {
+ VanillaToasts.create({
+ title: "Уведомление",
+ text: `${update.login} (${update.name}) удалил${update.sex?"":"а"} вас из друзей`,
+ type: "error",
+ callback: ()=>{
+ location = "/friends"
+ },
+ timeout:20000
+ });
+ }
+})
diff --git a/public/js/vanillatoasts.js b/public/js/vanillatoasts.js
new file mode 100644
index 0000000..16aef96
--- /dev/null
+++ b/public/js/vanillatoasts.js
@@ -0,0 +1,132 @@
+(function(root, factory) {
+ try {
+ // commonjs
+ if (typeof exports === 'object') {
+ module.exports = factory();
+ // global
+ } else {
+ root.VanillaToasts = factory();
+ }
+ } catch(error) {
+ console.log('Isomorphic compatibility is not supported at this time for VanillaToasts.')
+ }
+})(this, function() {
+
+ // We need DOM to be ready
+ if (document.readyState === 'complete') {
+ init();
+ } else {
+ window.addEventListener('DOMContentLoaded', init);
+ }
+
+ // Create VanillaToasts object
+ VanillaToasts = {
+ // In case toast creation is attempted before dom has finished loading!
+ create: function() {
+ console.error([
+ 'DOM has not finished loading.',
+ '\tInvoke create method when DOM\s readyState is complete'
+ ].join('\n'))
+ },
+ //function to manually set timeout after create
+ setTimeout: function() {
+ console.error([
+ 'DOM has not finished loading.',
+ '\tInvoke create method when DOM\s readyState is complete'
+ ].join('\n'))
+ },
+ toasts: {} //store toasts to modify later
+ };
+ var autoincrement = 0;
+
+ // Initialize library
+ function init() {
+ // Toast container
+ var container = document.createElement('div');
+ container.id = 'vanillatoasts-container';
+ document.body.appendChild(container);
+
+ // @Override
+ // Replace create method when DOM has finished loading
+ VanillaToasts.create = function(options) {
+ var toast = document.createElement('div');
+ toast.id = ++autoincrement;
+ toast.id = 'toast-' + toast.id;
+ toast.className = 'vanillatoasts-toast';
+
+ // title
+ if (options.title) {
+ var h4 = document.createElement('h4');
+ h4.className = 'vanillatoasts-title';
+ h4.innerHTML = options.title;
+ toast.appendChild(h4);
+ }
+
+ // text
+ if (options.text) {
+ var p = document.createElement('p');
+ p.className = 'vanillatoasts-text';
+ p.innerHTML = options.text;
+ toast.appendChild(p);
+ }
+
+ // icon
+ if (options.icon) {
+ var img = document.createElement('img');
+ img.src = options.icon;
+ img.className = 'vanillatoasts-icon';
+ toast.appendChild(img);
+ }
+
+ // click callback
+ if (typeof options.callback === 'function') {
+ toast.addEventListener('click', options.callback);
+ }
+
+ // toast api
+ toast.hide = function() {
+ toast.className += ' vanillatoasts-fadeOut';
+ toast.addEventListener('animationend', removeToast, false);
+ };
+
+ // autohide
+ if (options.timeout) {
+ setTimeout(toast.hide, options.timeout);
+ }
+
+ if (options.type) {
+ toast.className += ' vanillatoasts-' + options.type;
+ }
+
+ toast.addEventListener('click', toast.hide);
+
+
+ function removeToast() {
+ document.getElementById('vanillatoasts-container').removeChild(toast);
+ delete VanillaToasts.toasts[toast.id]; //remove toast from object
+ }
+
+ document.getElementById('vanillatoasts-container').appendChild(toast);
+
+ //add toast to object so its easily gettable by its id
+ VanillaToasts.toasts[toast.id] = toast;
+
+ return toast;
+ }
+
+ /*
+ custom function to manually initiate timeout of
+ the toast. Useful if toast is created as persistant
+ because we don't want it to start to timeout until
+ we tell it to
+ */
+ VanillaToasts.setTimeout = function(toastid, val) {
+ if(VanillaToasts.toasts[toastid]){
+ setTimeout(VanillaToasts.toasts[toastid].hide, val);
+ }
+ }
+ }
+
+ return VanillaToasts;
+
+});
diff --git a/public/styles/vanillatoasts.css b/public/styles/vanillatoasts.css
new file mode 100644
index 0000000..431d580
--- /dev/null
+++ b/public/styles/vanillatoasts.css
@@ -0,0 +1,98 @@
+#vanillatoasts-container {
+ position: fixed;
+ top: 0;
+ right: 0;
+ width: 320px;
+ font-family: 'Helvetica';
+}
+
+.vanillatoasts-toast {
+ position: relative;
+ padding: 20px 17px;
+ margin: 20px;
+ border-radius: 10px;
+ background: #F5F5F5;
+ cursor: pointer;
+ box-shadow: 1px 1px 3px rgba(0, 0, 0, 0.1);
+ animation-duration: .3s;
+ animation-name: VanillaToasts;
+ animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);
+}
+
+.vanillatoasts-fadeOut {
+ animation-name: VanillaToastsFadeOut;
+ animation-duration: .3s;
+ animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);
+ animation-fill-mode: forwards;
+}
+
+#vanillatoasts-container p,
+#vanillatoasts-container h4 {
+ margin: 3px 0!important;
+}
+
+.vanillatoasts-title {
+ font-weight: 700;
+ font-size: 15px;
+ margin-bottom: 10px;
+}
+
+.vanillatoasts-text {
+ font-size: 14px;
+ color: #2e2e2e;
+}
+
+.vanillatoasts-icon {
+ position: absolute;
+ top: 5px;
+ left: -40px;
+ width: 50px;
+ height: 50px;
+ border-radius: 100%;
+ box-shadow: 1px 1px 3px rgba(0, 0, 0, 0.1);
+ background: #FFF;
+}
+
+.vanillatoasts-toast a, .vanillatoasts-toast a:hover {
+ color: #549EDB !important;
+ text-decoration: none !important;
+}
+
+/** toast types */
+.vanillatoasts-success {
+ border-bottom: 5px solid #51C625;
+}
+
+.vanillatoasts-warning {
+ border-bottom: 5px solid #DB9215;
+}
+
+.vanillatoasts-error {
+ border-bottom: 5px solid #DB2B1D;
+}
+
+.vanillatoasts-info {
+ border-bottom: 5px solid #27ABDB;
+}
+
+@keyframes VanillaToasts {
+ from {
+ transform: translate3d(400px, 0, 0);;
+ opacity: 0;
+ }
+ to {
+ transform: translate3d(0, 0, 0);
+ opacity: 1;
+ }
+}
+
+@keyframes VanillaToastsFadeOut {
+ from {
+ transform: translate3d(0, 0, 0);
+ opacity: 1;
+ }
+ to {
+ transform: translate3d(400px, 0, 0);
+ opacity: 0;
+ }
+}
diff --git a/views/chat.ejs b/views/chat.ejs
index 76633a3..00a2cda 100644
--- a/views/chat.ejs
+++ b/views/chat.ejs
@@ -22,7 +22,10 @@
+
+
+
Онлайн: <%=onlineCounter%>
<%- include('partials/footer.ejs') %>