Merge branch 'communities-trim' into merge-trim
This commit is contained in:
@@ -599,6 +599,59 @@ define([
|
||||
}
|
||||
});
|
||||
};
|
||||
UI.confirmButton = function (originalBtn, config, _cb) {
|
||||
config = config || {};
|
||||
var cb = Util.once(Util.mkAsync(_cb));
|
||||
|
||||
var classes = 'btn ' + (config.classes || 'btn-primary');
|
||||
|
||||
var button = h('button', {
|
||||
"class": classes,
|
||||
title: config.title || ''
|
||||
}, Messages.areYouSure || "Are you sure?"); // XXX
|
||||
var $button = $(button);
|
||||
|
||||
var div = h('div', {
|
||||
"class": config.classes || ''
|
||||
});
|
||||
var timer = h('div.cp-button-timer', div);
|
||||
|
||||
var content = h('div.cp-button-confirm', [
|
||||
button,
|
||||
timer
|
||||
]);
|
||||
|
||||
var to;
|
||||
|
||||
var done = function (res) {
|
||||
cb(res);
|
||||
clearTimeout(to);
|
||||
$(content).remove();
|
||||
$(originalBtn).show();
|
||||
};
|
||||
|
||||
$button.click(function () {
|
||||
done(true);
|
||||
});
|
||||
|
||||
var TIMEOUT = 3000;
|
||||
var INTERVAL = 10;
|
||||
var i = 1;
|
||||
|
||||
var todo = function () {
|
||||
var p = 100 * ((TIMEOUT - (i * INTERVAL)) / TIMEOUT);
|
||||
if (i++ * INTERVAL >= TIMEOUT) {
|
||||
done(false);
|
||||
return;
|
||||
}
|
||||
$(div).css('width', p+'%');
|
||||
to = setTimeout(todo, INTERVAL);
|
||||
};
|
||||
to = setTimeout(todo, INTERVAL);
|
||||
|
||||
$(originalBtn).hide().after(content);
|
||||
};
|
||||
|
||||
|
||||
UI.proposal = function (content, cb) {
|
||||
var buttons = [{
|
||||
|
||||
@@ -30,6 +30,13 @@ define([
|
||||
});
|
||||
}
|
||||
|
||||
UIElements.prettySize = function (bytes) {
|
||||
var kB = Util.bytesToKilobytes(bytes);
|
||||
if (kB < 1024) { return kB + Messages.KB; }
|
||||
var mB = Util.bytesToMegabytes(bytes);
|
||||
return mB + Messages.MB;
|
||||
};
|
||||
|
||||
UIElements.updateTags = function (common, href) {
|
||||
var existing, tags;
|
||||
NThen(function(waitFor) {
|
||||
@@ -704,6 +711,9 @@ define([
|
||||
var $d = $('<div>');
|
||||
if (!data) { return void cb(void 0, $d); }
|
||||
|
||||
var priv = common.getMetadataMgr().getPrivateData();
|
||||
var edPublic = priv.edPublic;
|
||||
|
||||
if (data.href) {
|
||||
$('<label>', {'for': 'cp-app-prop-link'}).text(Messages.editShare).appendTo($d);
|
||||
$d.append(UI.dialog.selectable(data.href, {
|
||||
@@ -730,13 +740,30 @@ define([
|
||||
$d.append(h('div.cp-app-prop', [Messages.fm_lastAccess, h('br'), h('span.cp-app-prop-content', new Date(data.atime).toLocaleString())]));
|
||||
}
|
||||
|
||||
var owned = false;
|
||||
if (common.isLoggedIn()) {
|
||||
if (Array.isArray(data.owners)) {
|
||||
if (data.owners.indexOf(edPublic) !== -1) {
|
||||
owned = true;
|
||||
} else {
|
||||
Object.keys(priv.teams || {}).some(function (id) {
|
||||
var team = priv.teams[id] || {};
|
||||
if (team.viewer) { return; }
|
||||
if (data.owners.indexOf(team.edPublic) === -1) { return; }
|
||||
owned = id;
|
||||
return true;
|
||||
});
|
||||
}
|
||||
}
|
||||
// check the size of this file...
|
||||
var bytes = 0;
|
||||
var historyBytes;
|
||||
var chan = [data.channel];
|
||||
if (data.rtChannel) { chan.push(data.rtChannel); }
|
||||
if (data.lastVersion) { chan.push(Hash.hrefToHexChannelId(data.lastVersion)); }
|
||||
var history = common.makeUniversal('history');
|
||||
var trimChannels = [];
|
||||
NThen(function (waitFor) {
|
||||
var chan = [data.channel];
|
||||
if (data.rtChannel) { chan.push(data.rtChannel); }
|
||||
if (data.lastVersion) { chan.push(Hash.hrefToHexChannelId(data.lastVersion)); }
|
||||
chan.forEach(function (c) {
|
||||
common.getFileSize(c, waitFor(function (e, _bytes) {
|
||||
if (e) {
|
||||
@@ -746,20 +773,88 @@ define([
|
||||
bytes += _bytes;
|
||||
}));
|
||||
});
|
||||
|
||||
if (!owned) { return; }
|
||||
history.execCommand('GET_HISTORY_SIZE', {
|
||||
pad: true,
|
||||
channels: chan.filter(function (c) { return c.length === 32; }),
|
||||
teamId: typeof(owned) === "number" && owned
|
||||
}, waitFor(function (obj) {
|
||||
if (obj && obj.error) { return; }
|
||||
historyBytes = obj.size;
|
||||
trimChannels = obj.channels;
|
||||
}));
|
||||
}).nThen(function () {
|
||||
if (bytes === 0) { return void cb(void 0, $d); }
|
||||
var KB = Util.bytesToKilobytes(bytes);
|
||||
var formatted = UIElements.prettySize(bytes);
|
||||
|
||||
var formatted = Messages._getKey('formattedKB', [KB]);
|
||||
$d.append(h('div.cp-app-prop', [Messages.upload_size, h('br'), h('span.cp-app-prop-content', formatted)]));
|
||||
if (!owned || !historyBytes || historyBytes > bytes || historyBytes < 0) {
|
||||
$d.append(h('div.cp-app-prop', [
|
||||
Messages.upload_size,
|
||||
h('br'),
|
||||
h('span.cp-app-prop-content', formatted)
|
||||
]));
|
||||
return void cb(void 0, $d);
|
||||
}
|
||||
|
||||
if (data.sharedFolder && false) {
|
||||
$('<label>', {'for': 'cp-app-prop-channel'}).text('Channel ID').appendTo($d);
|
||||
if (AppConfig.pinBugRecovery) { $d.append(h('p', AppConfig.pinBugRecovery)); }
|
||||
$d.append(UI.dialog.selectable(data.channel, {
|
||||
id: 'cp-app-prop-link',
|
||||
}));
|
||||
}
|
||||
Messages.historyTrim_historySize = 'History: {0}'; // XXX
|
||||
Messages.historyTrim_contentsSize = 'Contents: {0}'; // XXX
|
||||
|
||||
var p = Math.round((historyBytes / bytes) * 100);
|
||||
var historyPrettySize = UIElements.prettySize(historyBytes);
|
||||
var contentsPrettySize = UIElements.prettySize(bytes - historyBytes);
|
||||
var button;
|
||||
var spinner = UI.makeSpinner();
|
||||
var size = h('div.cp-app-prop', [
|
||||
Messages.upload_size,
|
||||
h('br'),
|
||||
h('div.cp-app-prop-size-container', [
|
||||
h('div.cp-app-prop-size-history', { style: 'width:'+p+'%;' })
|
||||
]),
|
||||
h('div.cp-app-prop-size-legend', [
|
||||
h('div.cp-app-prop-history-size', [
|
||||
h('span.cp-app-prop-history-size-color'),
|
||||
h('span.cp-app-prop-content', Messages._getKey('historyTrim_historySize', [historyPrettySize]))
|
||||
]),
|
||||
h('div.cp-app-prop-contents-size', [
|
||||
h('span.cp-app-prop-contents-size-color'),
|
||||
h('span.cp-app-prop-content', Messages._getKey('historyTrim_contentsSize', [contentsPrettySize]))
|
||||
]),
|
||||
]),
|
||||
button = h('button.btn.btn-danger-alt.no-margin', Messages.trimHistory_button || 'test'), // XXX
|
||||
spinner.spinner
|
||||
]);
|
||||
$d.append(size);
|
||||
|
||||
var $button = $(button);
|
||||
$button.click(function () {
|
||||
UI.confirmButton(button, {
|
||||
classes: 'btn-danger'
|
||||
}, function (yes) {
|
||||
if (!yes) { return; }
|
||||
|
||||
$button.remove();
|
||||
spinner.spin();
|
||||
history.execCommand('TRIM_HISTORY', {
|
||||
pad: true,
|
||||
channels: trimChannels,
|
||||
teamId: typeof(owned) === "number" && owned
|
||||
}, function (obj) {
|
||||
spinner.hide();
|
||||
if (obj && obj.error) {
|
||||
$(size).append(h('div.alert.alert-danger', Messages.trimHistory_error || 'error')); // XXX
|
||||
return;
|
||||
}
|
||||
$(size).remove();
|
||||
var formatted = UIElements.prettySize(bytes - historyBytes);
|
||||
$d.append(h('div.cp-app-prop', [
|
||||
Messages.upload_size,
|
||||
h('br'),
|
||||
h('span.cp-app-prop-content', formatted)
|
||||
]));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
cb(void 0, $d);
|
||||
});
|
||||
|
||||
@@ -227,6 +227,7 @@
|
||||
else if (bytes >= oneMegabyte) { return 'MB'; }
|
||||
};
|
||||
|
||||
|
||||
// given a path, asynchronously return an arraybuffer
|
||||
Util.fetch = function (src, cb, progress) {
|
||||
var CB = Util.once(cb);
|
||||
|
||||
@@ -17,6 +17,7 @@ define([
|
||||
'/common/outer/profile.js',
|
||||
'/common/outer/team.js',
|
||||
'/common/outer/messenger.js',
|
||||
'/common/outer/history.js',
|
||||
'/common/outer/network-config.js',
|
||||
'/customize/application_config.js',
|
||||
|
||||
@@ -28,7 +29,7 @@ define([
|
||||
'/bower_components/saferphore/index.js',
|
||||
], function (Sortify, UserObject, ProxyManager, Migrate, Hash, Util, Constants, Feedback,
|
||||
Realtime, Messaging, Pinpad,
|
||||
SF, Cursor, OnlyOffice, Mailbox, Profile, Team, Messenger,
|
||||
SF, Cursor, OnlyOffice, Mailbox, Profile, Team, Messenger, History,
|
||||
NetConfig, AppConfig,
|
||||
Crypto, ChainPad, CpNetflux, Listmap, nThen, Saferphore) {
|
||||
|
||||
@@ -49,8 +50,6 @@ define([
|
||||
var sendDriveEvent = function () {};
|
||||
var registerProxyEvents = function () {};
|
||||
|
||||
var storeHash, storeChannel;
|
||||
|
||||
var store = window.CryptPad_AsyncStore = {
|
||||
modules: {}
|
||||
};
|
||||
@@ -159,13 +158,7 @@ define([
|
||||
};
|
||||
|
||||
var getUserChannelList = function () {
|
||||
// start with your userHash...
|
||||
var userHash = storeHash;
|
||||
if (!userHash) { return null; }
|
||||
|
||||
// No password for drive
|
||||
var secret = Hash.getSecrets('drive', userHash);
|
||||
var userChannel = secret.channel;
|
||||
var userChannel = store.driveChannel;
|
||||
if (!userChannel) { return null; }
|
||||
|
||||
// Get the list of pads' channel ID in your drive
|
||||
@@ -173,7 +166,7 @@ define([
|
||||
// It now includes channels from shared folders
|
||||
var list = store.manager.getChannelsList('pin');
|
||||
|
||||
// Get the avatar
|
||||
// Get the avatar & profile
|
||||
var profile = store.proxy.profile;
|
||||
if (profile) {
|
||||
var profileChan = profile.edit ? Hash.hrefToHexChannelId('/profile/#' + profile.edit, null) : null;
|
||||
@@ -182,6 +175,10 @@ define([
|
||||
if (avatarChan) { list.push(avatarChan); }
|
||||
}
|
||||
|
||||
if (store.proxy.todo) {
|
||||
list.push(Hash.hrefToHexChannelId('/todo/#' + store.proxy.todo, null));
|
||||
}
|
||||
|
||||
if (store.proxy.friends) {
|
||||
var fList = Messaging.getFriendChannelsList(store.proxy);
|
||||
list = list.concat(fList);
|
||||
@@ -314,7 +311,7 @@ define([
|
||||
teamId = data.teamId;
|
||||
}
|
||||
|
||||
if (channel === storeChannel && !force) {
|
||||
if (channel === store.driveChannel && !force) {
|
||||
return void cb({error: 'User drive removal blocked!'});
|
||||
}
|
||||
|
||||
@@ -446,10 +443,12 @@ define([
|
||||
});
|
||||
};
|
||||
|
||||
Store.getFileSize = function (clientId, data, cb) {
|
||||
Store.getFileSize = function (clientId, data, _cb) {
|
||||
var cb = Util.once(Util.mkAsync(_cb));
|
||||
|
||||
if (!store.anon_rpc) { return void cb({error: 'ANON_RPC_NOT_READY'}); }
|
||||
|
||||
var channelId = Hash.hrefToHexChannelId(data.href, data.password);
|
||||
var channelId = data.channel || Hash.hrefToHexChannelId(data.href, data.password);
|
||||
store.anon_rpc.send("GET_FILE_SIZE", channelId, function (e, response) {
|
||||
if (e) { return void cb({error: e}); }
|
||||
if (response && response.length && typeof(response[0]) === 'number') {
|
||||
@@ -713,11 +712,9 @@ define([
|
||||
|
||||
Store.deleteAccount = function (clientId, data, cb) {
|
||||
var edPublic = store.proxy.edPublic;
|
||||
// No password for drive
|
||||
var secret = Hash.getSecrets('drive', storeHash);
|
||||
Store.anonRpcMsg(clientId, {
|
||||
msg: 'GET_METADATA',
|
||||
data: secret.channel
|
||||
data: store.driveChannel
|
||||
}, function (data) {
|
||||
var metadata = data[0];
|
||||
// Owned drive
|
||||
@@ -737,7 +734,7 @@ define([
|
||||
}).nThen(function (waitFor) {
|
||||
// Delete Drive
|
||||
Store.removeOwnedChannel(clientId, {
|
||||
channel: secret.channel,
|
||||
channel: store.driveChannel,
|
||||
force: true
|
||||
}, waitFor());
|
||||
}).nThen(function () {
|
||||
@@ -753,7 +750,7 @@ define([
|
||||
var toSign = {
|
||||
intent: 'Please delete my account.'
|
||||
};
|
||||
toSign.drive = secret.channel;
|
||||
toSign.drive = store.driveChannel;
|
||||
toSign.edPublic = edPublic;
|
||||
var signKey = Crypto.Nacl.util.decodeBase64(store.proxy.edPrivate);
|
||||
var proof = Crypto.Nacl.sign.detached(Crypto.Nacl.util.decodeUTF8(Sortify(toSign)), signKey);
|
||||
@@ -1768,7 +1765,9 @@ define([
|
||||
|
||||
// Fetch the latest version of the metadata on the server and return it.
|
||||
// If the pad is stored in our drive, update the local values of "owners" and "expire"
|
||||
Store.getPadMetadata = function (clientId, data, cb) {
|
||||
Store.getPadMetadata = function (clientId, data, _cb) {
|
||||
var cb = Util.once(Util.mkAsync(_cb));
|
||||
|
||||
if (!data.channel) { return void cb({ error: 'ENOTFOUND'}); }
|
||||
store.anon_rpc.send('GET_METADATA', data.channel, function (err, obj) {
|
||||
if (err) { return void cb({error: err}); }
|
||||
@@ -1850,7 +1849,9 @@ define([
|
||||
network.sendto(hk, JSON.stringify(['GET_FULL_HISTORY', data.channel, data.validateKey]));
|
||||
};
|
||||
|
||||
Store.getHistory = function (clientId, data, cb) {
|
||||
Store.getHistory = function (clientId, data, _cb, full) {
|
||||
var cb = Util.once(Util.mkAsync(_cb));
|
||||
|
||||
var network = store.network;
|
||||
var hk = network.historyKeeper;
|
||||
|
||||
@@ -1862,6 +1863,8 @@ define([
|
||||
}
|
||||
};
|
||||
|
||||
var txid = Math.floor(Math.random() * 1000000);
|
||||
|
||||
var msgs = [];
|
||||
var completed = false;
|
||||
var onMsg = function (msg, sender) {
|
||||
@@ -1870,6 +1873,8 @@ define([
|
||||
var parsed = parse(msg);
|
||||
if (!parsed) { return; }
|
||||
|
||||
if (parsed.txid && parsed.txid !== txid) { return; }
|
||||
|
||||
// Ignore the metadata message
|
||||
if (parsed.validateKey && parsed.channel) { return; }
|
||||
if (parsed.error && parsed.channel) {
|
||||
@@ -1890,9 +1895,20 @@ define([
|
||||
return;
|
||||
}
|
||||
|
||||
msg = parsed[4];
|
||||
if (Array.isArray(parsed) && parsed[0] && parsed[0] !== txid) { return; }
|
||||
|
||||
// Keep only the history for our channel
|
||||
if (parsed[3] !== data.channel) { return; }
|
||||
// If we want the full messages, push the parsed data
|
||||
if (parsed[4] && full) {
|
||||
msgs.push({
|
||||
msg: msg,
|
||||
hash: parsed[4].slice(0,64)
|
||||
});
|
||||
return;
|
||||
}
|
||||
// Otherwise, push the messages
|
||||
msg = parsed[4];
|
||||
if (msg) {
|
||||
msg = msg.replace(/cp\|(([A-Za-z0-9+\/=]+)\|)?/, '');
|
||||
msgs.push(msg);
|
||||
@@ -1901,6 +1917,7 @@ define([
|
||||
network.on('message', onMsg);
|
||||
|
||||
var cfg = {
|
||||
txid: txid,
|
||||
lastKnownHash: data.lastKnownHash
|
||||
};
|
||||
var msg = ['GET_HISTORY', data.channel, cfg];
|
||||
@@ -2071,6 +2088,7 @@ define([
|
||||
store.mailbox.removeClient(clientId);
|
||||
} catch (e) { console.error(e); }
|
||||
Object.keys(store.modules).forEach(function (key) {
|
||||
if (!store.modules[key].removeClient) { return; }
|
||||
try {
|
||||
store.modules[key].removeClient(clientId);
|
||||
} catch (e) { console.error(e); }
|
||||
@@ -2332,6 +2350,7 @@ define([
|
||||
store.messenger = store.modules['messenger'];
|
||||
loadUniversal(Profile, 'profile', waitFor);
|
||||
loadUniversal(Team, 'team', waitFor);
|
||||
loadUniversal(History, 'history', waitFor);
|
||||
cleanFriendRequests();
|
||||
}).nThen(function () {
|
||||
var requestLogin = function () {
|
||||
@@ -2427,13 +2446,12 @@ define([
|
||||
|
||||
var connect = function (clientId, data, cb) {
|
||||
var hash = data.userHash || data.anonHash || Hash.createRandomHash('drive');
|
||||
storeHash = hash;
|
||||
if (!hash) {
|
||||
return void cb({error: '[Store.init] Unable to find or create a drive hash. Aborting...'});
|
||||
}
|
||||
// No password for drive
|
||||
var secret = Hash.getSecrets('drive', hash);
|
||||
storeChannel = secret.channel;
|
||||
store.driveChannel = secret.channel;
|
||||
var listmapConfig = {
|
||||
data: {},
|
||||
websocketURL: NetConfig.getWebsocketURL(),
|
||||
|
||||
246
www/common/outer/history.js
Normal file
246
www/common/outer/history.js
Normal file
@@ -0,0 +1,246 @@
|
||||
define([
|
||||
'/common/common-util.js',
|
||||
'/common/common-hash.js',
|
||||
'/common/userObject.js',
|
||||
'/bower_components/nthen/index.js',
|
||||
], function (Util, Hash, UserObject, nThen) {
|
||||
var History = {};
|
||||
var commands = {};
|
||||
|
||||
var getAccountChannels = function (ctx) {
|
||||
var channels = [];
|
||||
var edPublic = Util.find(ctx.store, ['proxy', 'edPublic']);
|
||||
|
||||
// Drive
|
||||
var driveOwned = (Util.find(ctx.store, ['driveMetadata', 'owners']) || []).indexOf(edPublic) !== -1;
|
||||
if (driveOwned) {
|
||||
channels.push(ctx.store.driveChannel);
|
||||
}
|
||||
|
||||
// Profile
|
||||
var profile = ctx.store.proxy.profile;
|
||||
if (profile) {
|
||||
var profileChan = profile.edit ? Hash.hrefToHexChannelId('/profile/#' + profile.edit, null) : null;
|
||||
if (profileChan) { channels.push(profileChan); }
|
||||
}
|
||||
|
||||
// Todo
|
||||
if (ctx.store.proxy.todo) {
|
||||
channels.push(Hash.hrefToHexChannelId('/todo/#' + ctx.store.proxy.todo, null));
|
||||
}
|
||||
|
||||
|
||||
// Mailboxes
|
||||
var mailboxes = ctx.store.proxy.mailboxes;
|
||||
if (mailboxes) {
|
||||
var mList = Object.keys(mailboxes).map(function (m) {
|
||||
return {
|
||||
lastKnownHash: mailboxes[m].lastKnownHash,
|
||||
channel: mailboxes[m].channel
|
||||
};
|
||||
});
|
||||
Array.prototype.push.apply(channels, mList);
|
||||
}
|
||||
|
||||
// Shared folders owned by me
|
||||
var sf = ctx.store.proxy[UserObject.SHARED_FOLDERS];
|
||||
if (sf) {
|
||||
var sfChannels = Object.keys(sf).map(function (fId) {
|
||||
var data = sf[fId];
|
||||
if (!data || !data.owners) { return; }
|
||||
var isOwner = Array.isArray(data.owners) && data.owners.indexOf(edPublic) !== -1;
|
||||
if (!isOwner) { return; }
|
||||
return data.channel;
|
||||
}).filter(Boolean);
|
||||
Array.prototype.push.apply(channels, sfChannels);
|
||||
}
|
||||
|
||||
return channels;
|
||||
};
|
||||
|
||||
var getEdPublic = function (ctx, teamId) {
|
||||
if (!teamId) { return Util.find(ctx.store, ['proxy', 'edPublic']); }
|
||||
|
||||
var teamData = Util.find(ctx, ['store', 'proxy', 'teams', teamId]);
|
||||
return Util.find(teamData, ['keys', 'drive', 'edPublic']);
|
||||
};
|
||||
var getRpc = function (ctx, teamId) {
|
||||
if (!teamId) { return ctx.store.rpc; }
|
||||
var teams = ctx.store.modules['team'];
|
||||
if (!teams) { return; }
|
||||
var team = teams.getTeam(teamId);
|
||||
if (!team) { return; }
|
||||
return team.rpc;
|
||||
};
|
||||
|
||||
var getHistoryData = function (ctx, channel, lastKnownHash, teamId, _cb) {
|
||||
var cb = Util.once(Util.mkAsync(_cb));
|
||||
var edPublic = getEdPublic(ctx, teamId);
|
||||
var Store = ctx.Store;
|
||||
|
||||
var total = 0;
|
||||
var history = 0;
|
||||
var metadata = 0;
|
||||
var hash;
|
||||
nThen(function (waitFor) {
|
||||
// Total size
|
||||
Store.getFileSize(null, {
|
||||
channel: channel
|
||||
}, waitFor(function (obj) {
|
||||
if (obj && obj.error) {
|
||||
waitFor.abort();
|
||||
return void cb(obj);
|
||||
}
|
||||
if (typeof(obj.size) === "undefined") {
|
||||
waitFor.abort();
|
||||
return void cb({error: 'ENOENT'});
|
||||
}
|
||||
total = obj.size;
|
||||
}));
|
||||
// Pad
|
||||
Store.getHistory(null, {
|
||||
channel: channel,
|
||||
lastKnownHash: lastKnownHash
|
||||
}, waitFor(function (obj) {
|
||||
if (obj && obj.error) {
|
||||
waitFor.abort();
|
||||
return void cb(obj);
|
||||
}
|
||||
if (!Array.isArray(obj)) {
|
||||
waitFor.abort();
|
||||
return void cb({error: 'EINVAL'});
|
||||
}
|
||||
|
||||
if (!obj.length) { return; }
|
||||
|
||||
hash = obj[0].hash;
|
||||
var messages = obj.map(function(data) {
|
||||
return data.msg;
|
||||
});
|
||||
history = messages.join('\n').length;
|
||||
}), true);
|
||||
// Metadata
|
||||
Store.getPadMetadata(null, {
|
||||
channel: channel
|
||||
}, waitFor(function (obj) {
|
||||
if (obj && obj.error) { return; }
|
||||
if (!obj || typeof(obj) !== "object") { return; }
|
||||
metadata = JSON.stringify(obj).length;
|
||||
if (!obj || !Array.isArray(obj.owners) ||
|
||||
obj.owners.indexOf(edPublic) === -1) {
|
||||
waitFor.abort();
|
||||
return void cb({error: 'INSUFFICIENT_PERMISSIONS'});
|
||||
}
|
||||
}));
|
||||
}).nThen(function () {
|
||||
cb({
|
||||
size: (total - metadata - history),
|
||||
hash: hash
|
||||
});
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
commands.GET_HISTORY_SIZE = function (ctx, data, cId, cb) {
|
||||
if (!ctx.store.loggedIn || !ctx.store.rpc) { return void cb({ error: 'INSUFFICIENT_PERMISSIONS' }); }
|
||||
var channels = data.channels;
|
||||
if (!Array.isArray(channels)) { return void cb({ error: 'EINVAL' }); }
|
||||
|
||||
var warning = [];
|
||||
|
||||
// If account trim history, get the correct channels here
|
||||
if (data.account) {
|
||||
channels = getAccountChannels(ctx);
|
||||
}
|
||||
|
||||
var size = 0;
|
||||
var res = [];
|
||||
nThen(function (waitFor) {
|
||||
channels.forEach(function (chan) {
|
||||
var channel = chan;
|
||||
var lastKnownHash;
|
||||
if (typeof (chan) === "object" && chan.channel) {
|
||||
channel = chan.channel;
|
||||
lastKnownHash = chan.lastKnownHash;
|
||||
}
|
||||
getHistoryData(ctx, channel, lastKnownHash, data.teamId, waitFor(function (obj) {
|
||||
if (obj && obj.error) {
|
||||
warning.push(obj.error);
|
||||
return;
|
||||
}
|
||||
size += obj.size;
|
||||
if (!obj.hash) { return; }
|
||||
res.push({
|
||||
channel: channel,
|
||||
hash: obj.hash
|
||||
});
|
||||
}));
|
||||
});
|
||||
}).nThen(function () {
|
||||
cb({
|
||||
warning: warning.length ? warning : undefined,
|
||||
channels: res,
|
||||
size: size
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
commands.TRIM_HISTORY = function (ctx, data, cId, cb) {
|
||||
if (!ctx.store.loggedIn || !ctx.store.rpc) { return void cb({ error: 'INSUFFICIENT_PERMISSIONS' }); }
|
||||
var channels = data.channels;
|
||||
if (!Array.isArray(channels)) { return void cb({ error: 'EINVAL' }); }
|
||||
|
||||
var rpc = getRpc(ctx, data.teamId);
|
||||
if (!rpc) { return void cb({ error: 'ENORPC'}); }
|
||||
|
||||
var warning = [];
|
||||
|
||||
nThen(function (waitFor) {
|
||||
channels.forEach(function (obj) {
|
||||
rpc.trimHistory(obj, waitFor(function (err) {
|
||||
if (err) {
|
||||
warning.push(err);
|
||||
return;
|
||||
}
|
||||
}));
|
||||
});
|
||||
}).nThen(function () {
|
||||
// Only one channel and warning: error
|
||||
if (channels.length === 1 && warning.length) {
|
||||
return void cb({error: warning[0]});
|
||||
}
|
||||
cb({
|
||||
warning: warning.length ? warning : undefined
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
History.init = function (cfg, waitFor, emit) {
|
||||
var history = {};
|
||||
if (!cfg.store) { return; }
|
||||
var ctx = {
|
||||
store: cfg.store,
|
||||
Store: cfg.Store,
|
||||
pinPads: cfg.pinPads,
|
||||
updateMetadata: cfg.updateMetadata,
|
||||
emit: emit,
|
||||
};
|
||||
|
||||
history.execCommand = function (clientId, obj, cb) {
|
||||
var cmd = obj.cmd;
|
||||
var data = obj.data;
|
||||
try {
|
||||
commands[cmd](ctx, data, clientId, cb);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
};
|
||||
|
||||
return history;
|
||||
};
|
||||
|
||||
return History;
|
||||
});
|
||||
|
||||
|
||||
|
||||
@@ -125,6 +125,17 @@ var factory = function (Util, Rpc) {
|
||||
});
|
||||
};
|
||||
|
||||
exp.trimHistory = function (data, _cb) {
|
||||
var cb = Util.once(Util.mkAsync(_cb));
|
||||
if (typeof(data) !== 'object' || !data.channel || !data.hash) {
|
||||
return void cb('INVALID_ARGUMENTS');
|
||||
}
|
||||
rpc.send('TRIM_HISTORY', data, function (e) {
|
||||
if (e) { return cb(e); }
|
||||
cb();
|
||||
});
|
||||
};
|
||||
|
||||
exp.clearOwnedChannel = function (channel, cb) {
|
||||
if (typeof(channel) !== 'string' || channel.length !== 32) {
|
||||
return void cb('INVALID_ARGUMENTS');
|
||||
|
||||
@@ -188,13 +188,6 @@ define([
|
||||
}
|
||||
};
|
||||
|
||||
var prettySize = function (bytes) {
|
||||
var kB = Util.bytesToKilobytes(bytes);
|
||||
if (kB < 1024) { return kB + Messages.KB; }
|
||||
var mB = Util.bytesToMegabytes(bytes);
|
||||
return mB + Messages.MB;
|
||||
};
|
||||
|
||||
queue.next = function () {
|
||||
if (queue.queue.length === 0) {
|
||||
clearTimeout(queue.to);
|
||||
@@ -262,7 +255,7 @@ define([
|
||||
// name
|
||||
$('<td>').append($link).appendTo($tr);
|
||||
// size
|
||||
$('<td>').text(prettySize(estimate)).appendTo($tr);
|
||||
$('<td>').text(UIElements.prettySize(estimate)).appendTo($tr);
|
||||
// progress
|
||||
$('<td>', {'class': 'cp-fileupload-table-progress'}).append($progressContainer).appendTo($tr);
|
||||
// cancel
|
||||
|
||||
Reference in New Issue
Block a user