diff --git a/www/common/outer/async-store.js b/www/common/outer/async-store.js index 65078b287..afb799990 100644 --- a/www/common/outer/async-store.js +++ b/www/common/outer/async-store.js @@ -1330,13 +1330,16 @@ define([ store.proxy.friends_pending = store.proxy.friends_pending || {}; - var twoDaysAgo = +new Date() - (2 * 24 * 3600 * 1000); - if (store.proxy.friends_pending[data.curvePublic] && - store.proxy.friends_pending[data.curvePublic] > twoDaysAgo) { - return void cb({error: 'TIMEOUT'}); + var p = store.proxy.friends_pending[data.curvePublic]; + if (p) { + return void cb({error: 'ALREADY_SENT'}); } - store.proxy.friends_pending[data.curvePublic] = +new Date(); + store.proxy.friends_pending[data.curvePublic] = { + time: +new Date(), + channel: data.notifications, + curvePublic: data.curvePublic + }; broadcast([], "UPDATE_METADATA"); store.mailbox.sendTo('FRIEND_REQUEST', { @@ -1348,6 +1351,37 @@ define([ cb(obj); }); }; + Store.cancelFriendRequest = function (data, cb) { + if (!data.curvePublic || !data.notifications) { + return void cb({error: 'EINVAL'}); + } + + var proxy = store.proxy; + var f = Messaging.getFriend(proxy, data.curvePublic); + + if (f) { + // Already friend + console.error("You can't cancel an accepted friend request"); + return void cb({error: 'ALREADY_FRIEND'}); + } + + var pending = Util.find(store, ['proxy', 'friends_pending']) || {}; + if (!pending) { return void cb(); } + + store.mailbox.sendTo('CANCEL_FRIEND_REQUEST', { + user: Messaging.createData(store.proxy) + }, { + channel: data.notifications, + curvePublic: data.curvePublic + }, function (obj) { + if (obj && obj.error) { return void cb(obj); } + delete store.proxy.friends_pending[data.curvePublic]; + broadcast([], "UPDATE_METADATA"); + onSync(null, function () { + cb(obj); + }); + }); + }; Store.anonGetPreviewContent = function (clientId, data, cb) { Team.anonGetPreviewContent({ @@ -2448,18 +2482,6 @@ define([ }); }; - var cleanFriendRequests = function () { - try { - if (!store.proxy.friends_pending) { return; } - var twoDaysAgo = +new Date() - (2 * 24 * 3600 * 1000); - Object.keys(store.proxy.friends_pending).forEach(function (curve) { - if (store.proxy.friends_pending[curve] < twoDaysAgo) { - delete store.proxy.friends_pending[curve]; - } - }); - } catch (e) {} - }; - ////////////////////////////////////////////////////////////////// /////////////////////// Init ///////////////////////////////////// ////////////////////////////////////////////////////////////////// @@ -2543,7 +2565,6 @@ define([ loadUniversal(Profile, 'profile', waitFor); loadUniversal(Team, 'team', waitFor, clientId); loadUniversal(History, 'history', waitFor); - cleanFriendRequests(); }).nThen(function () { var requestLogin = function () { broadcast([], "REQUEST_LOGIN"); diff --git a/www/common/outer/mailbox-handlers.js b/www/common/outer/mailbox-handlers.js index 326b4afc7..17ef80ea2 100644 --- a/www/common/outer/mailbox-handlers.js +++ b/www/common/outer/mailbox-handlers.js @@ -33,11 +33,15 @@ define([ // in memory from the same user, dismiss the new one if (friendRequest[data.msg.author]) { return void cb(true); } - friendRequest[data.msg.author] = true; + friendRequest[data.msg.author] = { + type: box.type, + hash: data.hash + }; // If the user is already in our friend list, automatically accept the request if (Messaging.getFriend(ctx.store.proxy, data.msg.author) || ctx.store.proxy.friends_pending[data.msg.author]) { + delete ctx.store.proxy.friends_pending[data.msg.author]; Messaging.acceptFriendRequest(ctx.store, userData, function (obj) { @@ -49,13 +53,16 @@ define([ realtime: ctx.store.realtime, pinPads: ctx.pinPads }, userData, function (err) { - if (err) { return void console.error(err); } + if (err) { + console.error(err); + return void cb(true); + } if (ctx.store.messenger) { ctx.store.messenger.onFriendAdded(userData); } + ctx.updateMetadata(); + cb(true); }); - ctx.updateMetadata(); - cb(true); }); return; } @@ -97,20 +104,29 @@ define([ ctx.updateMetadata(); if (friendRequestDeclined[data.msg.author]) { return; } - friendRequestDeclined[data.msg.author] = true; box.sendMessage({ type: 'FRIEND_REQUEST_DECLINED', content: { user: userData } - }, function () {}); + }, function (hash) { + friendRequestDeclined[data.msg.author] = { + type: box.type, + hash: hash + }; + }); }, getRandomTimeout(ctx)); }; // UI for declined friend request handlers['FRIEND_REQUEST_DECLINED'] = function (ctx, box, data, cb) { ctx.updateMetadata(); var curve = data.msg.content.user.curvePublic || data.msg.content.user; - if (friendRequestDeclined[curve]) { return void cb(true); } - friendRequestDeclined[curve] = true; - cb(); + var toRemove = friendRequestAccepted[curve]; + delete friendRequestAccepted[curve]; + if (friendRequestDeclined[curve]) { return void cb(true, toRemove); } + friendRequestDeclined[curve] = { + type: box.type, + hash: data.hash + }; + cb(false, toRemove); }; removeHandlers['FRIEND_REQUEST_DECLINED'] = function (ctx, box, data) { var curve = data.content.user.curvePublic || data.content.user; @@ -148,11 +164,15 @@ define([ if (ctx.store.modules['profile']) { ctx.store.modules['profile'].update(); } // Display the "accepted" state in the UI if (friendRequestAccepted[data.msg.author]) { return; } - friendRequestAccepted[data.msg.author] = true; box.sendMessage({ type: 'FRIEND_REQUEST_ACCEPTED', content: { user: userData } - }, function () {}); + }, function (hash) { + friendRequestAccepted[data.msg.author] = { + type: box.type, + hash: hash + }; + }); }); }, getRandomTimeout(ctx)); }; @@ -160,20 +180,32 @@ define([ handlers['FRIEND_REQUEST_ACCEPTED'] = function (ctx, box, data, cb) { ctx.updateMetadata(); var curve = data.msg.content.user.curvePublic || data.msg.content.user; - if (friendRequestAccepted[curve]) { return void cb(true); } - friendRequestAccepted[curve] = true; - cb(); + var toRemove = friendRequestDeclined[curve]; + delete friendRequestDeclined[curve]; + if (friendRequestAccepted[curve]) { return void cb(true, toRemove); } + friendRequestAccepted[curve] = { + type: box.type, + hash: data.hash + }; + cb(false, toRemove); }; removeHandlers['FRIEND_REQUEST_ACCEPTED'] = function (ctx, box, data) { var curve = data.content.user.curvePublic || data.content.user; if (friendRequestAccepted[curve]) { delete friendRequestAccepted[curve]; } }; + handlers['CANCEL_FRIEND_REQUEST'] = function (ctx, box, data, cb) { + var f = friendRequest[data.msg.author]; + if (!f) { return void cb(true); } + cb(true, f); + }; + handlers['UNFRIEND'] = function (ctx, box, data, cb) { var curve = data.msg.author; var friend = Messaging.getFriend(ctx.store.proxy, curve); if (!friend) { return void cb(true); } delete ctx.store.proxy.friends[curve]; + delete ctx.store.proxy.friends_pending[curve]; if (ctx.store.messenger) { ctx.store.messenger.onFriendRemoved(curve, friend.channel); } diff --git a/www/common/outer/mailbox.js b/www/common/outer/mailbox.js index 803d8bc93..d9c0dc4e2 100644 --- a/www/common/outer/mailbox.js +++ b/www/common/outer/mailbox.js @@ -271,7 +271,7 @@ proxy.mailboxes = { hash: hash }; showMessage(ctx, type, message); - cb(); + cb(hash); }, keys.curvePublic); }; box.queue.forEach(function (msg) { diff --git a/www/common/outer/messenger.js b/www/common/outer/messenger.js index 6587d9e4d..b5aab9ca5 100644 --- a/www/common/outer/messenger.js +++ b/www/common/outer/messenger.js @@ -459,6 +459,13 @@ define([ } }; + // Cancel pending friend requests + var cancelFriend = function (ctx, data, _cb) { + var cb = Util.once(_cb); + if (typeof(cb) !== 'function') { return void console.error('NO_CALLBACK'); } + ctx.Store.cancelFriendRequest(data, cb); + }; + var getAllClients = function (ctx) { var all = []; Array.prototype.push.apply(all, ctx.friendsClients); @@ -935,6 +942,7 @@ define([ if (AppConfig.availablePadTypes.indexOf('contacts') === -1) { return; } var ctx = { store: store, + Store: cfg.Store, updateMetadata: cfg.updateMetadata, pinPads: cfg.pinPads, emit: emit, @@ -1047,6 +1055,9 @@ define([ if (cmd === 'REMOVE_FRIEND') { return void removeFriend(ctx, data, cb); } + if (cmd === 'CANCEL_FRIEND') { + return void cancelFriend(ctx, data, cb); + } if (cmd === 'MUTE_USER') { return void muteUser(ctx, data, cb); } diff --git a/www/common/toolbar.js b/www/common/toolbar.js index 7794f3fde..82cc8cbb4 100644 --- a/www/common/toolbar.js +++ b/www/common/toolbar.js @@ -229,7 +229,6 @@ MessengerUI, Messages) { // Editors var pendingFriends = Common.getPendingFriends(); // Friend requests sent var friendRequests = Common.getFriendRequests(); // Friend requests received - var friendTo = +new Date() - (2 * 24 * 3600 * 1000); editUsersNames.forEach(function (data) { var name = data.name || Messages.anonymous; var $span = $('', {'class': 'cp-avatar'}); @@ -297,7 +296,7 @@ MessengerUI, Messages) { } } else if (Common.isLoggedIn() && data.curvePublic && !friends[data.curvePublic] && !priv.readOnly) { - if (pendingFriends[data.curvePublic] && pendingFriends[data.curvePublic] > friendTo) { + if (pendingFriends[data.curvePublic]) { $('