Merge branch 'communities-trim' into merge-trim
This commit is contained in:
commit
672725629c
@ -52,6 +52,22 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
div.cp-button-confirm {
|
||||||
|
display: inline-block;
|
||||||
|
button {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
.cp-button-timer {
|
||||||
|
height: 3px;
|
||||||
|
& > div {
|
||||||
|
height: 100%;
|
||||||
|
background-color: @colortheme_alertify-primary;
|
||||||
|
&.danger, &.btn-danger, &.danger-alt, &.btn-danger-alt {
|
||||||
|
background-color: @colortheme_alertify-red;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
button:not(.pure-button):not(.md-button):not(.mdl-button) {
|
button:not(.pure-button):not(.md-button):not(.mdl-button) {
|
||||||
|
|
||||||
@ -89,6 +105,7 @@
|
|||||||
white-space: normal;
|
white-space: normal;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.danger, &.btn-danger {
|
&.danger, &.btn-danger {
|
||||||
background-color: @colortheme_alertify-red;
|
background-color: @colortheme_alertify-red;
|
||||||
border-color: @colortheme_alertify-red-border;
|
border-color: @colortheme_alertify-red-border;
|
||||||
@ -98,6 +115,15 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.danger-alt, &.btn-danger-alt {
|
||||||
|
border-color: @colortheme_alertify-red;
|
||||||
|
color: @colortheme_alertify-red;
|
||||||
|
&:hover, &:active {
|
||||||
|
color: @colortheme_alertify-red-color;
|
||||||
|
background-color: contrast(@colortheme_modal-bg, darken(@colortheme_alertify-red, 10%), lighten(@colortheme_alertify-red, 10%));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
&.safe, &.btn-safe {
|
&.safe, &.btn-safe {
|
||||||
background-color: @colortheme_alertify-green;
|
background-color: @colortheme_alertify-green;
|
||||||
border-color: @colortheme_alertify-green-border;
|
border-color: @colortheme_alertify-green-border;
|
||||||
|
|||||||
@ -26,6 +26,42 @@
|
|||||||
// Properties modal
|
// Properties modal
|
||||||
.cp-app-prop {
|
.cp-app-prop {
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
|
.cp-app-prop-size-container {
|
||||||
|
height: 20px;
|
||||||
|
background-color: @colortheme_logo-2;
|
||||||
|
margin: 10px 0;
|
||||||
|
padding: 0;
|
||||||
|
div {
|
||||||
|
height: 20px;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
background-color: #CCCCCC;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.cp-app-prop-size-legend {
|
||||||
|
color: @colortheme_modal-fg;
|
||||||
|
display: flex;
|
||||||
|
margin: 10px 0;
|
||||||
|
& > div {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
flex-basis: 50%;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
.cp-app-prop-history-size-color, .cp-app-prop-contents-size-color {
|
||||||
|
display: inline-block;
|
||||||
|
height: 20px;
|
||||||
|
width: 20px;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
.cp-app-prop-history-size-color {
|
||||||
|
background-color: #CCCCCC;
|
||||||
|
}
|
||||||
|
.cp-app-prop-contents-size-color {
|
||||||
|
background-color: @colortheme_logo-2;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.cp-app-prop-content {
|
.cp-app-prop-content {
|
||||||
|
|||||||
@ -599,6 +599,7 @@ const handleGetHistory = function (Env, Server, seq, userId, parsed) {
|
|||||||
var config = parsed[2];
|
var config = parsed[2];
|
||||||
var metadata = {};
|
var metadata = {};
|
||||||
var lastKnownHash;
|
var lastKnownHash;
|
||||||
|
var txid;
|
||||||
|
|
||||||
// clients can optionally pass a map of attributes
|
// clients can optionally pass a map of attributes
|
||||||
// if the channel already exists this map will be ignored
|
// if the channel already exists this map will be ignored
|
||||||
@ -606,6 +607,7 @@ const handleGetHistory = function (Env, Server, seq, userId, parsed) {
|
|||||||
if (config && typeof config === "object" && !Array.isArray(parsed[2])) {
|
if (config && typeof config === "object" && !Array.isArray(parsed[2])) {
|
||||||
lastKnownHash = config.lastKnownHash;
|
lastKnownHash = config.lastKnownHash;
|
||||||
metadata = config.metadata || {};
|
metadata = config.metadata || {};
|
||||||
|
txid = config.txid;
|
||||||
if (metadata.expire) {
|
if (metadata.expire) {
|
||||||
metadata.expire = +metadata.expire * 1000 + (+new Date());
|
metadata.expire = +metadata.expire * 1000 + (+new Date());
|
||||||
}
|
}
|
||||||
@ -655,11 +657,12 @@ const handleGetHistory = function (Env, Server, seq, userId, parsed) {
|
|||||||
msgCount++;
|
msgCount++;
|
||||||
// avoid sending the metadata message a second time
|
// avoid sending the metadata message a second time
|
||||||
if (isMetadataMessage(msg) && metadata_cache[channelName]) { return readMore(); }
|
if (isMetadataMessage(msg) && metadata_cache[channelName]) { return readMore(); }
|
||||||
|
if (txid) { msg[0] = txid; }
|
||||||
Server.send(userId, [0, HISTORY_KEEPER_ID, 'MSG', userId, JSON.stringify(msg)], readMore);
|
Server.send(userId, [0, HISTORY_KEEPER_ID, 'MSG', userId, JSON.stringify(msg)], readMore);
|
||||||
}, (err) => {
|
}, (err) => {
|
||||||
if (err && err.code !== 'ENOENT') {
|
if (err && err.code !== 'ENOENT') {
|
||||||
if (err.message !== 'EINVAL') { Log.error("HK_GET_HISTORY", err); }
|
if (err.message !== 'EINVAL') { Log.error("HK_GET_HISTORY", err); }
|
||||||
const parsedMsg = {error:err.message, channel: channelName};
|
const parsedMsg = {error:err.message, channel: channelName, txid: txid};
|
||||||
Server.send(userId, [0, HISTORY_KEEPER_ID, 'MSG', userId, JSON.stringify(parsedMsg)]);
|
Server.send(userId, [0, HISTORY_KEEPER_ID, 'MSG', userId, JSON.stringify(parsedMsg)]);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -707,7 +710,7 @@ const handleGetHistory = function (Env, Server, seq, userId, parsed) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// End of history message:
|
// End of history message:
|
||||||
let parsedMsg = {state: 1, channel: channelName};
|
let parsedMsg = {state: 1, channel: channelName, txid: txid};
|
||||||
|
|
||||||
Server.send(userId, [0, HISTORY_KEEPER_ID, 'MSG', userId, JSON.stringify(parsedMsg)]);
|
Server.send(userId, [0, HISTORY_KEEPER_ID, 'MSG', userId, JSON.stringify(parsedMsg)]);
|
||||||
});
|
});
|
||||||
|
|||||||
@ -975,10 +975,11 @@ var trimChannel = function (env, channelName, hash, _cb) {
|
|||||||
if (msgHash === hash) {
|
if (msgHash === hash) {
|
||||||
// everything from this point on should be retained
|
// everything from this point on should be retained
|
||||||
retain = true;
|
retain = true;
|
||||||
return void tempStream.write(msgObj.buff, function () {
|
return void tempStream.write(s_msg + '\n', function () {
|
||||||
readMore();
|
readMore();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
readMore();
|
||||||
};
|
};
|
||||||
|
|
||||||
readMessagesBin(env, channelName, 0, handler, w(function (err) {
|
readMessagesBin(env, channelName, 0, handler, w(function (err) {
|
||||||
|
|||||||
@ -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) {
|
UI.proposal = function (content, cb) {
|
||||||
var buttons = [{
|
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) {
|
UIElements.updateTags = function (common, href) {
|
||||||
var existing, tags;
|
var existing, tags;
|
||||||
NThen(function(waitFor) {
|
NThen(function(waitFor) {
|
||||||
@ -704,6 +711,9 @@ define([
|
|||||||
var $d = $('<div>');
|
var $d = $('<div>');
|
||||||
if (!data) { return void cb(void 0, $d); }
|
if (!data) { return void cb(void 0, $d); }
|
||||||
|
|
||||||
|
var priv = common.getMetadataMgr().getPrivateData();
|
||||||
|
var edPublic = priv.edPublic;
|
||||||
|
|
||||||
if (data.href) {
|
if (data.href) {
|
||||||
$('<label>', {'for': 'cp-app-prop-link'}).text(Messages.editShare).appendTo($d);
|
$('<label>', {'for': 'cp-app-prop-link'}).text(Messages.editShare).appendTo($d);
|
||||||
$d.append(UI.dialog.selectable(data.href, {
|
$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())]));
|
$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 (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...
|
// check the size of this file...
|
||||||
var bytes = 0;
|
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) {
|
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) {
|
chan.forEach(function (c) {
|
||||||
common.getFileSize(c, waitFor(function (e, _bytes) {
|
common.getFileSize(c, waitFor(function (e, _bytes) {
|
||||||
if (e) {
|
if (e) {
|
||||||
@ -746,20 +773,88 @@ define([
|
|||||||
bytes += _bytes;
|
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 () {
|
}).nThen(function () {
|
||||||
if (bytes === 0) { return void cb(void 0, $d); }
|
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]);
|
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)]));
|
$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) {
|
Messages.historyTrim_historySize = 'History: {0}'; // XXX
|
||||||
$('<label>', {'for': 'cp-app-prop-channel'}).text('Channel ID').appendTo($d);
|
Messages.historyTrim_contentsSize = 'Contents: {0}'; // XXX
|
||||||
if (AppConfig.pinBugRecovery) { $d.append(h('p', AppConfig.pinBugRecovery)); }
|
|
||||||
$d.append(UI.dialog.selectable(data.channel, {
|
var p = Math.round((historyBytes / bytes) * 100);
|
||||||
id: 'cp-app-prop-link',
|
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);
|
cb(void 0, $d);
|
||||||
});
|
});
|
||||||
|
|||||||
@ -227,6 +227,7 @@
|
|||||||
else if (bytes >= oneMegabyte) { return 'MB'; }
|
else if (bytes >= oneMegabyte) { return 'MB'; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// given a path, asynchronously return an arraybuffer
|
// given a path, asynchronously return an arraybuffer
|
||||||
Util.fetch = function (src, cb, progress) {
|
Util.fetch = function (src, cb, progress) {
|
||||||
var CB = Util.once(cb);
|
var CB = Util.once(cb);
|
||||||
|
|||||||
@ -17,6 +17,7 @@ define([
|
|||||||
'/common/outer/profile.js',
|
'/common/outer/profile.js',
|
||||||
'/common/outer/team.js',
|
'/common/outer/team.js',
|
||||||
'/common/outer/messenger.js',
|
'/common/outer/messenger.js',
|
||||||
|
'/common/outer/history.js',
|
||||||
'/common/outer/network-config.js',
|
'/common/outer/network-config.js',
|
||||||
'/customize/application_config.js',
|
'/customize/application_config.js',
|
||||||
|
|
||||||
@ -28,7 +29,7 @@ define([
|
|||||||
'/bower_components/saferphore/index.js',
|
'/bower_components/saferphore/index.js',
|
||||||
], function (Sortify, UserObject, ProxyManager, Migrate, Hash, Util, Constants, Feedback,
|
], function (Sortify, UserObject, ProxyManager, Migrate, Hash, Util, Constants, Feedback,
|
||||||
Realtime, Messaging, Pinpad,
|
Realtime, Messaging, Pinpad,
|
||||||
SF, Cursor, OnlyOffice, Mailbox, Profile, Team, Messenger,
|
SF, Cursor, OnlyOffice, Mailbox, Profile, Team, Messenger, History,
|
||||||
NetConfig, AppConfig,
|
NetConfig, AppConfig,
|
||||||
Crypto, ChainPad, CpNetflux, Listmap, nThen, Saferphore) {
|
Crypto, ChainPad, CpNetflux, Listmap, nThen, Saferphore) {
|
||||||
|
|
||||||
@ -49,8 +50,6 @@ define([
|
|||||||
var sendDriveEvent = function () {};
|
var sendDriveEvent = function () {};
|
||||||
var registerProxyEvents = function () {};
|
var registerProxyEvents = function () {};
|
||||||
|
|
||||||
var storeHash, storeChannel;
|
|
||||||
|
|
||||||
var store = window.CryptPad_AsyncStore = {
|
var store = window.CryptPad_AsyncStore = {
|
||||||
modules: {}
|
modules: {}
|
||||||
};
|
};
|
||||||
@ -159,13 +158,7 @@ define([
|
|||||||
};
|
};
|
||||||
|
|
||||||
var getUserChannelList = function () {
|
var getUserChannelList = function () {
|
||||||
// start with your userHash...
|
var userChannel = store.driveChannel;
|
||||||
var userHash = storeHash;
|
|
||||||
if (!userHash) { return null; }
|
|
||||||
|
|
||||||
// No password for drive
|
|
||||||
var secret = Hash.getSecrets('drive', userHash);
|
|
||||||
var userChannel = secret.channel;
|
|
||||||
if (!userChannel) { return null; }
|
if (!userChannel) { return null; }
|
||||||
|
|
||||||
// Get the list of pads' channel ID in your drive
|
// Get the list of pads' channel ID in your drive
|
||||||
@ -173,7 +166,7 @@ define([
|
|||||||
// It now includes channels from shared folders
|
// It now includes channels from shared folders
|
||||||
var list = store.manager.getChannelsList('pin');
|
var list = store.manager.getChannelsList('pin');
|
||||||
|
|
||||||
// Get the avatar
|
// Get the avatar & profile
|
||||||
var profile = store.proxy.profile;
|
var profile = store.proxy.profile;
|
||||||
if (profile) {
|
if (profile) {
|
||||||
var profileChan = profile.edit ? Hash.hrefToHexChannelId('/profile/#' + profile.edit, null) : null;
|
var profileChan = profile.edit ? Hash.hrefToHexChannelId('/profile/#' + profile.edit, null) : null;
|
||||||
@ -182,6 +175,10 @@ define([
|
|||||||
if (avatarChan) { list.push(avatarChan); }
|
if (avatarChan) { list.push(avatarChan); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (store.proxy.todo) {
|
||||||
|
list.push(Hash.hrefToHexChannelId('/todo/#' + store.proxy.todo, null));
|
||||||
|
}
|
||||||
|
|
||||||
if (store.proxy.friends) {
|
if (store.proxy.friends) {
|
||||||
var fList = Messaging.getFriendChannelsList(store.proxy);
|
var fList = Messaging.getFriendChannelsList(store.proxy);
|
||||||
list = list.concat(fList);
|
list = list.concat(fList);
|
||||||
@ -314,7 +311,7 @@ define([
|
|||||||
teamId = data.teamId;
|
teamId = data.teamId;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (channel === storeChannel && !force) {
|
if (channel === store.driveChannel && !force) {
|
||||||
return void cb({error: 'User drive removal blocked!'});
|
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'}); }
|
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) {
|
store.anon_rpc.send("GET_FILE_SIZE", channelId, function (e, response) {
|
||||||
if (e) { return void cb({error: e}); }
|
if (e) { return void cb({error: e}); }
|
||||||
if (response && response.length && typeof(response[0]) === 'number') {
|
if (response && response.length && typeof(response[0]) === 'number') {
|
||||||
@ -713,11 +712,9 @@ define([
|
|||||||
|
|
||||||
Store.deleteAccount = function (clientId, data, cb) {
|
Store.deleteAccount = function (clientId, data, cb) {
|
||||||
var edPublic = store.proxy.edPublic;
|
var edPublic = store.proxy.edPublic;
|
||||||
// No password for drive
|
|
||||||
var secret = Hash.getSecrets('drive', storeHash);
|
|
||||||
Store.anonRpcMsg(clientId, {
|
Store.anonRpcMsg(clientId, {
|
||||||
msg: 'GET_METADATA',
|
msg: 'GET_METADATA',
|
||||||
data: secret.channel
|
data: store.driveChannel
|
||||||
}, function (data) {
|
}, function (data) {
|
||||||
var metadata = data[0];
|
var metadata = data[0];
|
||||||
// Owned drive
|
// Owned drive
|
||||||
@ -737,7 +734,7 @@ define([
|
|||||||
}).nThen(function (waitFor) {
|
}).nThen(function (waitFor) {
|
||||||
// Delete Drive
|
// Delete Drive
|
||||||
Store.removeOwnedChannel(clientId, {
|
Store.removeOwnedChannel(clientId, {
|
||||||
channel: secret.channel,
|
channel: store.driveChannel,
|
||||||
force: true
|
force: true
|
||||||
}, waitFor());
|
}, waitFor());
|
||||||
}).nThen(function () {
|
}).nThen(function () {
|
||||||
@ -753,7 +750,7 @@ define([
|
|||||||
var toSign = {
|
var toSign = {
|
||||||
intent: 'Please delete my account.'
|
intent: 'Please delete my account.'
|
||||||
};
|
};
|
||||||
toSign.drive = secret.channel;
|
toSign.drive = store.driveChannel;
|
||||||
toSign.edPublic = edPublic;
|
toSign.edPublic = edPublic;
|
||||||
var signKey = Crypto.Nacl.util.decodeBase64(store.proxy.edPrivate);
|
var signKey = Crypto.Nacl.util.decodeBase64(store.proxy.edPrivate);
|
||||||
var proof = Crypto.Nacl.sign.detached(Crypto.Nacl.util.decodeUTF8(Sortify(toSign)), signKey);
|
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.
|
// 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"
|
// 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'}); }
|
if (!data.channel) { return void cb({ error: 'ENOTFOUND'}); }
|
||||||
store.anon_rpc.send('GET_METADATA', data.channel, function (err, obj) {
|
store.anon_rpc.send('GET_METADATA', data.channel, function (err, obj) {
|
||||||
if (err) { return void cb({error: err}); }
|
if (err) { return void cb({error: err}); }
|
||||||
@ -1850,7 +1849,9 @@ define([
|
|||||||
network.sendto(hk, JSON.stringify(['GET_FULL_HISTORY', data.channel, data.validateKey]));
|
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 network = store.network;
|
||||||
var hk = network.historyKeeper;
|
var hk = network.historyKeeper;
|
||||||
|
|
||||||
@ -1862,6 +1863,8 @@ define([
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var txid = Math.floor(Math.random() * 1000000);
|
||||||
|
|
||||||
var msgs = [];
|
var msgs = [];
|
||||||
var completed = false;
|
var completed = false;
|
||||||
var onMsg = function (msg, sender) {
|
var onMsg = function (msg, sender) {
|
||||||
@ -1870,6 +1873,8 @@ define([
|
|||||||
var parsed = parse(msg);
|
var parsed = parse(msg);
|
||||||
if (!parsed) { return; }
|
if (!parsed) { return; }
|
||||||
|
|
||||||
|
if (parsed.txid && parsed.txid !== txid) { return; }
|
||||||
|
|
||||||
// Ignore the metadata message
|
// Ignore the metadata message
|
||||||
if (parsed.validateKey && parsed.channel) { return; }
|
if (parsed.validateKey && parsed.channel) { return; }
|
||||||
if (parsed.error && parsed.channel) {
|
if (parsed.error && parsed.channel) {
|
||||||
@ -1890,9 +1895,20 @@ define([
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
msg = parsed[4];
|
if (Array.isArray(parsed) && parsed[0] && parsed[0] !== txid) { return; }
|
||||||
|
|
||||||
// Keep only the history for our channel
|
// Keep only the history for our channel
|
||||||
if (parsed[3] !== data.channel) { return; }
|
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) {
|
if (msg) {
|
||||||
msg = msg.replace(/cp\|(([A-Za-z0-9+\/=]+)\|)?/, '');
|
msg = msg.replace(/cp\|(([A-Za-z0-9+\/=]+)\|)?/, '');
|
||||||
msgs.push(msg);
|
msgs.push(msg);
|
||||||
@ -1901,6 +1917,7 @@ define([
|
|||||||
network.on('message', onMsg);
|
network.on('message', onMsg);
|
||||||
|
|
||||||
var cfg = {
|
var cfg = {
|
||||||
|
txid: txid,
|
||||||
lastKnownHash: data.lastKnownHash
|
lastKnownHash: data.lastKnownHash
|
||||||
};
|
};
|
||||||
var msg = ['GET_HISTORY', data.channel, cfg];
|
var msg = ['GET_HISTORY', data.channel, cfg];
|
||||||
@ -2071,6 +2088,7 @@ define([
|
|||||||
store.mailbox.removeClient(clientId);
|
store.mailbox.removeClient(clientId);
|
||||||
} catch (e) { console.error(e); }
|
} catch (e) { console.error(e); }
|
||||||
Object.keys(store.modules).forEach(function (key) {
|
Object.keys(store.modules).forEach(function (key) {
|
||||||
|
if (!store.modules[key].removeClient) { return; }
|
||||||
try {
|
try {
|
||||||
store.modules[key].removeClient(clientId);
|
store.modules[key].removeClient(clientId);
|
||||||
} catch (e) { console.error(e); }
|
} catch (e) { console.error(e); }
|
||||||
@ -2332,6 +2350,7 @@ define([
|
|||||||
store.messenger = store.modules['messenger'];
|
store.messenger = store.modules['messenger'];
|
||||||
loadUniversal(Profile, 'profile', waitFor);
|
loadUniversal(Profile, 'profile', waitFor);
|
||||||
loadUniversal(Team, 'team', waitFor);
|
loadUniversal(Team, 'team', waitFor);
|
||||||
|
loadUniversal(History, 'history', waitFor);
|
||||||
cleanFriendRequests();
|
cleanFriendRequests();
|
||||||
}).nThen(function () {
|
}).nThen(function () {
|
||||||
var requestLogin = function () {
|
var requestLogin = function () {
|
||||||
@ -2427,13 +2446,12 @@ define([
|
|||||||
|
|
||||||
var connect = function (clientId, data, cb) {
|
var connect = function (clientId, data, cb) {
|
||||||
var hash = data.userHash || data.anonHash || Hash.createRandomHash('drive');
|
var hash = data.userHash || data.anonHash || Hash.createRandomHash('drive');
|
||||||
storeHash = hash;
|
|
||||||
if (!hash) {
|
if (!hash) {
|
||||||
return void cb({error: '[Store.init] Unable to find or create a drive hash. Aborting...'});
|
return void cb({error: '[Store.init] Unable to find or create a drive hash. Aborting...'});
|
||||||
}
|
}
|
||||||
// No password for drive
|
// No password for drive
|
||||||
var secret = Hash.getSecrets('drive', hash);
|
var secret = Hash.getSecrets('drive', hash);
|
||||||
storeChannel = secret.channel;
|
store.driveChannel = secret.channel;
|
||||||
var listmapConfig = {
|
var listmapConfig = {
|
||||||
data: {},
|
data: {},
|
||||||
websocketURL: NetConfig.getWebsocketURL(),
|
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) {
|
exp.clearOwnedChannel = function (channel, cb) {
|
||||||
if (typeof(channel) !== 'string' || channel.length !== 32) {
|
if (typeof(channel) !== 'string' || channel.length !== 32) {
|
||||||
return void cb('INVALID_ARGUMENTS');
|
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 () {
|
queue.next = function () {
|
||||||
if (queue.queue.length === 0) {
|
if (queue.queue.length === 0) {
|
||||||
clearTimeout(queue.to);
|
clearTimeout(queue.to);
|
||||||
@ -262,7 +255,7 @@ define([
|
|||||||
// name
|
// name
|
||||||
$('<td>').append($link).appendTo($tr);
|
$('<td>').append($link).appendTo($tr);
|
||||||
// size
|
// size
|
||||||
$('<td>').text(prettySize(estimate)).appendTo($tr);
|
$('<td>').text(UIElements.prettySize(estimate)).appendTo($tr);
|
||||||
// progress
|
// progress
|
||||||
$('<td>', {'class': 'cp-fileupload-table-progress'}).append($progressContainer).appendTo($tr);
|
$('<td>', {'class': 'cp-fileupload-table-progress'}).append($progressContainer).appendTo($tr);
|
||||||
// cancel
|
// cancel
|
||||||
|
|||||||
@ -21,6 +21,11 @@
|
|||||||
max-width: 650px;
|
max-width: 650px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
div.alert {
|
||||||
|
font-size: @colortheme_app-font-size;
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
#cp-export-container {
|
#cp-export-container {
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -171,7 +176,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.cp-settings-change-password, .cp-settings-migrate {
|
.cp-settings-change-password, .cp-settings-own-drive {
|
||||||
[type="password"], [type="text"] {
|
[type="password"], [type="text"] {
|
||||||
width: @sidebar_button-width;
|
width: @sidebar_button-width;
|
||||||
flex: unset;
|
flex: unset;
|
||||||
|
|||||||
@ -48,12 +48,12 @@ define([
|
|||||||
|
|
||||||
var categories = {
|
var categories = {
|
||||||
'account': [
|
'account': [
|
||||||
|
'cp-settings-own-drive',
|
||||||
'cp-settings-info-block',
|
'cp-settings-info-block',
|
||||||
'cp-settings-displayname',
|
'cp-settings-displayname',
|
||||||
'cp-settings-language-selector',
|
'cp-settings-language-selector',
|
||||||
'cp-settings-resettips',
|
'cp-settings-resettips',
|
||||||
'cp-settings-change-password',
|
'cp-settings-change-password',
|
||||||
'cp-settings-migrate',
|
|
||||||
'cp-settings-delete'
|
'cp-settings-delete'
|
||||||
],
|
],
|
||||||
'security': [
|
'security': [
|
||||||
@ -73,7 +73,8 @@ define([
|
|||||||
'cp-settings-thumbnails',
|
'cp-settings-thumbnails',
|
||||||
'cp-settings-drive-backup',
|
'cp-settings-drive-backup',
|
||||||
'cp-settings-drive-import-local',
|
'cp-settings-drive-import-local',
|
||||||
'cp-settings-drive-reset'
|
'cp-settings-trim-history'
|
||||||
|
//'cp-settings-drive-reset'
|
||||||
],
|
],
|
||||||
'cursor': [
|
'cursor': [
|
||||||
'cp-settings-cursor-color',
|
'cp-settings-cursor-color',
|
||||||
@ -146,6 +147,11 @@ define([
|
|||||||
hintFunction(safeKey).appendTo($div);
|
hintFunction(safeKey).appendTo($div);
|
||||||
}
|
}
|
||||||
getter(function (content) {
|
getter(function (content) {
|
||||||
|
if (content === false) {
|
||||||
|
$div.remove();
|
||||||
|
$div = undefined;
|
||||||
|
return;
|
||||||
|
}
|
||||||
$div.append(content);
|
$div.append(content);
|
||||||
}, $div);
|
}, $div);
|
||||||
return $div;
|
return $div;
|
||||||
@ -520,19 +526,12 @@ define([
|
|||||||
return $div;
|
return $div;
|
||||||
};
|
};
|
||||||
|
|
||||||
create['migrate'] = function () {
|
makeBlock('own-drive', function (cb, $div) {
|
||||||
if (privateData.isDriveOwned) { return; }
|
if (privateData.isDriveOwned || !common.isLoggedIn()) {
|
||||||
if (!common.isLoggedIn()) { return; }
|
return void cb(false);
|
||||||
|
}
|
||||||
|
|
||||||
var $div = $('<div>', { 'class': 'cp-settings-migrate cp-sidebarlayout-element'});
|
$div.addClass('alert alert-warning');
|
||||||
|
|
||||||
$('<span>', {'class': 'label'}).text(Messages.settings_ownDriveTitle).appendTo($div);
|
|
||||||
|
|
||||||
$('<span>', {'class': 'cp-sidebarlayout-description'})
|
|
||||||
.append(Messages.settings_ownDriveHint).appendTo($div);
|
|
||||||
|
|
||||||
var $ok = $('<span>', {'class': 'fa fa-check', title: Messages.saved});
|
|
||||||
var $spinner = $('<span>', {'class': 'fa fa-spinner fa-pulse'});
|
|
||||||
|
|
||||||
var form = h('div', [
|
var form = h('div', [
|
||||||
UI.passwordInput({
|
UI.passwordInput({
|
||||||
@ -541,13 +540,13 @@ define([
|
|||||||
}, true),
|
}, true),
|
||||||
h('button.btn.btn-primary', Messages.settings_ownDriveButton)
|
h('button.btn.btn-primary', Messages.settings_ownDriveButton)
|
||||||
]);
|
]);
|
||||||
|
var $form = $(form);
|
||||||
$(form).appendTo($div);
|
var spinner = UI.makeSpinner($form);
|
||||||
|
|
||||||
var todo = function () {
|
var todo = function () {
|
||||||
var password = $(form).find('#cp-settings-migrate-password').val();
|
var password = $form.find('#cp-settings-migrate-password').val();
|
||||||
if (!password) { return; }
|
if (!password) { return; }
|
||||||
$spinner.show();
|
spinner.spin();
|
||||||
UI.confirm(Messages.settings_ownDriveConfirm, function (yes) {
|
UI.confirm(Messages.settings_ownDriveConfirm, function (yes) {
|
||||||
if (!yes) { return; }
|
if (!yes) { return; }
|
||||||
var data = {
|
var data = {
|
||||||
@ -561,16 +560,15 @@ define([
|
|||||||
sframeChan.query('Q_CHANGE_USER_PASSWORD', data, function (err, obj) {
|
sframeChan.query('Q_CHANGE_USER_PASSWORD', data, function (err, obj) {
|
||||||
UI.removeLoadingScreen();
|
UI.removeLoadingScreen();
|
||||||
if (err || obj.error) { return UI.alert(Messages.settings_changePasswordError); }
|
if (err || obj.error) { return UI.alert(Messages.settings_changePasswordError); }
|
||||||
$ok.show();
|
spinner.done();
|
||||||
$spinner.hide();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
$(form).find('button').click(function () {
|
$form.find('button').click(function () {
|
||||||
todo();
|
todo();
|
||||||
});
|
});
|
||||||
$(form).find('input').keydown(function (e) {
|
$form.find('input').keydown(function (e) {
|
||||||
// Save on Enter
|
// Save on Enter
|
||||||
if (e.which === 13) {
|
if (e.which === 13) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
@ -579,11 +577,9 @@ define([
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$spinner.hide().appendTo($div);
|
|
||||||
$ok.hide().appendTo($div);
|
|
||||||
|
|
||||||
return $div;
|
cb(form);
|
||||||
};
|
}, true);
|
||||||
|
|
||||||
// Security
|
// Security
|
||||||
|
|
||||||
@ -1215,6 +1211,90 @@ define([
|
|||||||
return $div;
|
return $div;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var redrawTrimHistory = function (cb, $div) {
|
||||||
|
var spinner = UI.makeSpinner();
|
||||||
|
var button = h('button.btn.btn-danger-alt', {
|
||||||
|
disabled: 'disabled'
|
||||||
|
}, Messages.trimHistory_button || 'delete history... xxx'); // XXX
|
||||||
|
var currentSize = h('p', $(spinner.spinner).clone()[0]);
|
||||||
|
var content = h('div#cp-settings-trim-container', [
|
||||||
|
currentSize,
|
||||||
|
button,
|
||||||
|
spinner.ok,
|
||||||
|
spinner.spinner
|
||||||
|
]);
|
||||||
|
|
||||||
|
if (!privateData.isDriveOwned) {
|
||||||
|
var href = privateData.origin + privateData.pathname + '#' + 'account';
|
||||||
|
$(currentSize).html(Messages.trimHistory_needMigration || 'Need migration <a>Click</a>'); // XXX
|
||||||
|
$(currentSize).find('a').prop('href', href).click(function (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
$('.cp-sidebarlayout-category[data-category="account"]').click();
|
||||||
|
});
|
||||||
|
return void cb(content);
|
||||||
|
}
|
||||||
|
|
||||||
|
Messages.trimHistory_currentSize = 'Size XXX: <b>{0}</b>'; // XXX
|
||||||
|
|
||||||
|
var $button = $(button);
|
||||||
|
var size;
|
||||||
|
var channels = [];
|
||||||
|
nThen(function (waitFor) {
|
||||||
|
APP.history.execCommand('GET_HISTORY_SIZE', {
|
||||||
|
account: true,
|
||||||
|
channels: []
|
||||||
|
}, waitFor(function (obj) {
|
||||||
|
if (obj && obj.error) {
|
||||||
|
waitFor.abort();
|
||||||
|
var error = h('div.alert.alert-danger', Messages.trimHistory_error || 'error'); // XXX
|
||||||
|
$(content).empty().append(error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
channels = obj.channels;
|
||||||
|
size = Number(obj.size);
|
||||||
|
}));
|
||||||
|
}).nThen(function () {
|
||||||
|
if (!size || size < 1024) {
|
||||||
|
$(currentSize).html(Messages.trimHistory_noHistory || 'no history...'); // XXX
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$(currentSize).html(Messages._getKey('trimHistory_currentSize', [UIElements.prettySize(size)]));
|
||||||
|
$button.click(function () {
|
||||||
|
//UI.confirm(Messages.trimHistory_confirm, function (yes) {
|
||||||
|
UI.confirmButton(button, {
|
||||||
|
classes: 'btn-danger'
|
||||||
|
}, function (yes) {
|
||||||
|
if (!yes) { return; }
|
||||||
|
|
||||||
|
$button.remove();
|
||||||
|
spinner.spin();
|
||||||
|
APP.history.execCommand('TRIM_HISTORY', {
|
||||||
|
channels: channels
|
||||||
|
}, function (obj) {
|
||||||
|
if (obj && obj.error) {
|
||||||
|
var error = h('div.alert.alert-danger', Messages.trimHistory_error || 'error'); // XXX
|
||||||
|
$(content).empty().append(error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
spinner.hide();
|
||||||
|
redrawTrimHistory(cb, $div);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}).prop('disabled', '');
|
||||||
|
});
|
||||||
|
|
||||||
|
$div.find('#cp-settings-trim-container').remove();
|
||||||
|
cb(content);
|
||||||
|
};
|
||||||
|
makeBlock('trim-history', function (cb, $div) {
|
||||||
|
if (!common.isLoggedIn()) { return; }
|
||||||
|
// XXX settings_trimHistoryTitle, settings_trimHistoryHint, trimHistory_button, trimHistory_error
|
||||||
|
// XXX trimHistory_success, trimHistory_confirm, trimHistory_noHistory
|
||||||
|
// XXX trimHistory_needMigration (clickable <a> tag (no attribute) to go to the "account" part of settings)
|
||||||
|
redrawTrimHistory(cb, $div);
|
||||||
|
}, true);
|
||||||
|
|
||||||
|
/*
|
||||||
create['drive-reset'] = function () {
|
create['drive-reset'] = function () {
|
||||||
var $div = $('<div>', {'class': 'cp-settings-drive-reset cp-sidebarlayout-element'});
|
var $div = $('<div>', {'class': 'cp-settings-drive-reset cp-sidebarlayout-element'});
|
||||||
$('<label>').text(Messages.settings_resetNewTitle).appendTo($div);
|
$('<label>').text(Messages.settings_resetNewTitle).appendTo($div);
|
||||||
@ -1238,6 +1318,7 @@ define([
|
|||||||
|
|
||||||
return $div;
|
return $div;
|
||||||
};
|
};
|
||||||
|
*/
|
||||||
|
|
||||||
// Cursor settings
|
// Cursor settings
|
||||||
|
|
||||||
@ -1638,7 +1719,10 @@ define([
|
|||||||
APP.$usage = $('<div>', {'class': 'usage'}).appendTo(APP.$leftside);
|
APP.$usage = $('<div>', {'class': 'usage'}).appendTo(APP.$leftside);
|
||||||
var active = privateData.category || 'account';
|
var active = privateData.category || 'account';
|
||||||
Object.keys(categories).forEach(function (key) {
|
Object.keys(categories).forEach(function (key) {
|
||||||
var $category = $('<div>', {'class': 'cp-sidebarlayout-category'}).appendTo($categories);
|
var $category = $('<div>', {
|
||||||
|
'class': 'cp-sidebarlayout-category',
|
||||||
|
'data-category': key
|
||||||
|
}).appendTo($categories);
|
||||||
if (key === 'account') { $category.append($('<span>', {'class': 'fa fa-user-o'})); }
|
if (key === 'account') { $category.append($('<span>', {'class': 'fa fa-user-o'})); }
|
||||||
if (key === 'drive') { $category.append($('<span>', {'class': 'fa fa-hdd-o'})); }
|
if (key === 'drive') { $category.append($('<span>', {'class': 'fa fa-hdd-o'})); }
|
||||||
if (key === 'cursor') { $category.append($('<span>', {'class': 'fa fa-i-cursor' })); }
|
if (key === 'cursor') { $category.append($('<span>', {'class': 'fa fa-i-cursor' })); }
|
||||||
@ -1697,6 +1781,7 @@ define([
|
|||||||
};
|
};
|
||||||
APP.toolbar = Toolbar.create(configTb);
|
APP.toolbar = Toolbar.create(configTb);
|
||||||
APP.toolbar.$rightside.hide();
|
APP.toolbar.$rightside.hide();
|
||||||
|
APP.history = common.makeUniversal('history');
|
||||||
|
|
||||||
// Content
|
// Content
|
||||||
var $rightside = APP.$rightside;
|
var $rightside = APP.$rightside;
|
||||||
@ -1715,6 +1800,7 @@ define([
|
|||||||
categories[cat].forEach(addItem);
|
categories[cat].forEach(addItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// TODO RPC
|
// TODO RPC
|
||||||
//obj.proxy.on('change', [], refresh);
|
//obj.proxy.on('change', [], refresh);
|
||||||
//obj.proxy.on('remove', [], refresh);
|
//obj.proxy.on('remove', [], refresh);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user