diff --git a/www/common/common-ui-elements.js b/www/common/common-ui-elements.js index 5aa390120..21e157394 100644 --- a/www/common/common-ui-elements.js +++ b/www/common/common-ui-elements.js @@ -76,6 +76,8 @@ define([ })); }).nThen(function (waitFor) { var base = common.getMetadataMgr().getPrivateData().origin; + // XXX getFileData? + // XXX getPadMetadata common.getPadAttribute('href', waitFor(function (err, val) { if (!val) { return; } data.href = base + val; @@ -99,26 +101,40 @@ define([ common.getPadAttribute('ctime', waitFor(function (err, val) { data.ctime = val; })); + common.getPadAttribute('title', waitFor(function (err, val) { + data.title = val; + })); common.getPadAttribute('tags', waitFor(function (err, val) { data.tags = val; })); + common.getSframeChannel().query('Q_GET_PAD_METADATA', null, waitFor(function (err, val) { + if (err) { return; } + data.owners = val.owners; + data.expire = val.expire; + data.pending_owners = val.pending_owners; + })); + /* common.getPadAttribute('owners', waitFor(function (err, val) { data.owners = val; })); common.getPadAttribute('expire', waitFor(function (err, val) { data.expire = val; - })); + }));*/ }).nThen(function () { cb(void 0, data); }); }; - var createOwnerModal = function (common, channel, owners) { + var createOwnerModal = function (common, data) { var friends = common.getFriends(true); var sframeChan = common.getSframeChannel(); var priv = common.getMetadataMgr().getPrivateData(); + var user = common.getMetadataMgr().getUserData(); var edPublic = priv.edPublic; + var channel = data.channel; + var owners = data.owners; var $div1, $div2; + var redrawAll = function () {}; // Remove owner column var drawRemove = function () { @@ -181,12 +197,7 @@ define([ err = err || (res && res.error); if (err) { return void UI.warn('ERROR' + err); } // XXX owners = res.owners; - var $d1 = $div1; - var $d2 = $div2; - drawRemove().insertBefore($d1); - $d1.remove(); - drawAdd().insertBefore($d2); - $d2.remove(); + redrawAll(); UI.log('DONE'); // XXX }); }; @@ -240,36 +251,70 @@ define([ var toAdd = sel.map(function (el) { return friends[$(el).attr('data-curve')].edPublic; }).filter(function (x) { return x; }); - // Send the command - var send = function () { - // XXX Pinning problem.... + + nThen(function (waitFor) { + var msg = "Are you sure?"; // XXX + UI.confirm(msg, waitFor(function (yes) { + if (!yes) { + waitFor.abort(); + return; + } + })); + }).nThen(function (waitFor) { + // Send the command sframeChan.query('Q_SET_PAD_METADATA', { channel: channel, - command: 'ADD_OWNERS', + command: 'ADD_PENDING_OWNERS', value: toAdd - }, function (err, res) { + }, waitFor(function (err, res) { err = err || (res && res.error); - if (err) { return void UI.warn('ERROR' + err); } // XXX + if (err) { + waitFor.abort(); + return void UI.warn('ERROR' + err); + } // XXX owners = res.owners; - var $d1 = $div1; - var $d2 = $div2; - drawRemove().insertBefore($d1); - $d1.remove(); - drawAdd().insertBefore($d2); - $d2.remove(); - UI.log('DONE'); // XXX + })); + }).nThen(function (waitFor) { + // TODO send notifications + sel.forEach(function () { + var friend = friends[$(el).attr('data-curve')]; + if (!friend) { return; } + common.mailbox.sendTo("ADD_OWNER", { + channel: channel, + href: data.href, + password: data.password, + title: data.title, + user: { + displayName: user.name, + avatar: user.avatar, + profile: user.profile, + notifications: user.notifications, + curvePublic: user.curvePublic, + edPublic: priv.edPublic + } + }, { + channel: friend.notifications, + curvePublic: friend.curvePublic + }, waitFor()); }); - }; - var msg = "Are you sure?"; // XXX - UI.confirm(msg, function (yes) { - if (!yes) { return; } - send(); + }).nThen(function () { + redrawAll(); + UI.log('DONE'); // XXX }); }); $div2.append(h('p', addButton)); return $div2; }; + redrawAll = function () { + var $d1 = $div1; + var $d2 = $div2; + drawRemove().insertBefore($d1); + $d1.remove(); + drawAdd().insertBefore($d2); + $d2.remove(); + }; + // Create modal var link = h('div.cp-share-columns', [ drawRemove()[0], @@ -326,7 +371,7 @@ define([ if (owned) { var manageOwners = h('button.no-margin', 'Manage owners'); // XXX $(manageOwners).click(function () { - var modal = createOwnerModal(common, data.channel, data.owners); + var modal = createOwnerModal(common, data); UI.openCustomModal(modal, { wide: true, }); @@ -3168,7 +3213,7 @@ define([ UIElements.displayFriendRequestModal = function (common, data) { var msg = data.content.msg; - var text = Messages._getKey('contacts_request', [msg.content.displayName]); + var text = Messages._getKey('contacts_request', [Util.fixHTML(msg.content.displayName)]); var todo = function (yes) { common.getSframeChannel().query("Q_ANSWER_FRIEND_REQUEST", { @@ -3213,5 +3258,77 @@ define([ UI.openCustomModal(modal); }; + UIElements.displayAddOwnerModal = function (common, data) { + var priv = common.getMetadataMgr().getPrivateData(); + var sframeChan = common.getSframeChannel(); + var msg = data.content.msg; + var name = Util.fixHTML(msg.content.user.displayName) || Messages.anonymous; + var title = Util.fixHTML(msg.content.title); + + Messages.owner_add = '{0} wants you to be an owner of the pad {1}. Do you accept?'; //XXX + var text = Messages._getKey('owner_add', [name, title]); + + var link = h('a', { + href: '#' + }, Messages.requestEdit_viewPad); + $(link).click(function (e) { + e.preventDefault(); + e.stopPropagation(); + if (data.content.password) { + common.sessionStorage.put('newPadPassword', data.content.password, function () { + common.openURL(msg.content.href); + }); + return; + } + common.openURL(msg.content.href); + }); + + var div = h('div', [ + UI.setHTML(h('p'), text), + link + ]); + + var todo = function (yes) { + if (yes) { + sframeChan.query('Q_SET_PAD_METADATA', { + channel: channel, + command: 'ADD_OWNERS', + value: [priv.edPublic] + }, function (err, res) { + err = err || (res && res.error); + if (err) { + return void UI.warn('ERROR' + err); + } // XXX + UI.log('DONE'); // XXX + // TODO send notification to the sender? + }); + return; + } + // XXX implement decline? + }; + + var buttons = [{ + name: Messages.friendRequest_later, + onClick: function () {}, + keys: [27] + }, { + className: 'primary', + name: Messages.friendRequest_accept, + onClick: function () { + todo(true); + }, + keys: [13] + }, { + className: 'primary', + name: Messages.friendRequest_decline, + onClick: function () { + todo(false); + }, + keys: [[13, 'ctrl']] + }]; + var modal = UI.dialog.customModal(div, {buttons: buttons}); + UI.openCustomModal(modal); + }; + return UIElements; }); diff --git a/www/common/cryptpad-common.js b/www/common/cryptpad-common.js index 4ed0976ff..56e5edcae 100644 --- a/www/common/cryptpad-common.js +++ b/www/common/cryptpad-common.js @@ -758,6 +758,10 @@ define([ pad.onConnectEvent = Util.mkEvent(); pad.onErrorEvent = Util.mkEvent(); + pad.getPadMetadata = function (data, cb) { + postMessage('GET_PAD_METADATA', data, cb); + }; + pad.requestAccess = function (data, cb) { postMessage("REQUEST_PAD_ACCESS", data, cb); }; @@ -769,7 +773,10 @@ define([ postMessage('SET_PAD_METADATA', data, cb); }; common.getPadMetadata = function (data, cb) { - postMessage('GET_PAD_METADATA', data, cb); + common.anonRpcMsg('GET_METADATA', data.channel, function (err, obj) { + if (err) { return void cb({error: err}); } + cb(obj && obj[0]); + }); }; common.changePadPassword = function (Crypt, href, newPassword, edPublic, cb) { diff --git a/www/common/notifications.js b/www/common/notifications.js index 72b62b501..010d1f46e 100644 --- a/www/common/notifications.js +++ b/www/common/notifications.js @@ -210,6 +210,27 @@ define([ }; }; + + handlers['ADD_OWNER'] = function (common, data) { + var content = data.content; + var msg = content.msg; + + // Display the notification + content.getFormatText = function () { + return Messages._getKey('friendRequest_notification', [name]); + }; + + // Check authenticity + if (msg.author !== msg.content.curvePublic) { return; } + + // if not archived, add handlers + if (!content.archived) { + content.handler = function () { + UIElements.displayAddOwnerModal(common, data); + }; + } + }; + // NOTE: don't forget to fixHTML everything returned by "getFormatText" return { diff --git a/www/common/outer/async-store.js b/www/common/outer/async-store.js index 9a2ce0f7c..9c5c23bf8 100644 --- a/www/common/outer/async-store.js +++ b/www/common/outer/async-store.js @@ -1374,6 +1374,7 @@ define([ }; Store.getPadMetadata = function (clientId, data, cb) { + console.log(data); if (!data.channel) { return void cb({ error: 'ENOTFOUND'}); } var channel = channels[data.channel]; if (!channel) { return void cb({ error: 'ENOTFOUND' }); } diff --git a/www/common/outer/mailbox-handlers.js b/www/common/outer/mailbox-handlers.js index 9d383caa1..cca192d04 100644 --- a/www/common/outer/mailbox-handlers.js +++ b/www/common/outer/mailbox-handlers.js @@ -259,6 +259,32 @@ define([ cb(false); }; + // Hide duplicates when receiving an ADD_OWNER notification: + var addOwners = {}; + handlers['ADD_OWNER'] = function (ctx, box, data, cb) { + var msg = data.msg; + var content = msg.content; + + if (msg.author !== content.user.curvePublic) { return void cb(true); } + if (!content.href || !content.title || !content.channel) { + console.log('Remove invalid notification'); + return void cb(true); + } + + var channel = content.channel; + + if (addOwners[channel]) { return void cb(true); } + addOwners[channel] = true; + + cb(false); + }; + removeHandlers['ADD_OWNER'] = function (ctx, box, data) { + var channel = data.content.channel; + if (addOwners[channel]) { + delete addOwners[channel]; + } + }; + return { add: function (ctx, box, data, cb) { /** diff --git a/www/common/sframe-common-mailbox.js b/www/common/sframe-common-mailbox.js index 5aaaa5340..e468b29f1 100644 --- a/www/common/sframe-common-mailbox.js +++ b/www/common/sframe-common-mailbox.js @@ -32,13 +32,17 @@ define([ }); }; - mailbox.sendTo = function (type, content, user) { + mailbox.sendTo = function (type, content, user, cb) { + cb = cb || function () {}; execCommand('SENDTO', { type: type, msg: content, user: user }, function (err, obj) { - if (err || (obj && obj.error)) { return void console.error(err || obj.error); } + cb(err || (obj && obj.error), obj); + if (err || (obj && obj.error)) { + return void console.error(err || obj.error); + } }); }; diff --git a/www/common/sframe-common-outer.js b/www/common/sframe-common-outer.js index 38214752f..cc568553a 100644 --- a/www/common/sframe-common-outer.js +++ b/www/common/sframe-common-outer.js @@ -981,7 +981,7 @@ define([ // Try to get the owner's mailbox from the pad metadata first. // If it's is an older owned pad, check if the owner is a friend // or an acquaintance (from async-store directly in requestAccess) - Cryptpad.getPadMetadata({ + Cryptpad.pad.getPadMetadata({ channel: secret.channel }, waitFor(function (obj) { obj = obj || {}; @@ -1004,6 +1004,15 @@ define([ }); }); + sframeChan.on('Q_GET_PAD_METADATA', function (data, cb) { + if (!data || !data.channel) { + data = { + channel: secret.channel + }; + } + console.log(data); + Cryptpad.getPadMetadata(data, cb); + }); sframeChan.on('Q_SET_PAD_METADATA', function (data, cb) { Cryptpad.setPadMetadata(data, cb); }); diff --git a/www/drive/inner.js b/www/drive/inner.js index fbdaaa7a0..138d01f3d 100644 --- a/www/drive/inner.js +++ b/www/drive/inner.js @@ -3715,6 +3715,20 @@ define([ data.sharedFolder = true; } + if (manager.isFile(el) && data.roHref) { // Only for pads! + sframeChan.query('Q_GET_PAD_METADATA', { + channel: data.channel + }, function (err, val) { + console.log(arguments); + if (!err && !(val && val.error)) { + data.owners = val.owners; + data.expire = val.expire; + data.pending_owners = val.pending_owners; + } + UIElements.getProperties(common, data, cb); + }); + return; + } UIElements.getProperties(common, data, cb); };