Merge branch 'owned' into staging
commit
415375d034
|
@ -4,6 +4,7 @@
|
|||
@import (reference) "./limit-bar.less";
|
||||
@import (reference) "./tokenfield.less";
|
||||
@import (reference) "./dropdown.less";
|
||||
@import (reference) "./buttons.less";
|
||||
|
||||
.drive_main() {
|
||||
--LessLoader_require: LessLoader_currentFile();
|
||||
|
@ -44,10 +45,11 @@
|
|||
}
|
||||
|
||||
/* local mixins */
|
||||
@drive_icon-margin: 10px;
|
||||
.drive_fileIcon {
|
||||
li {
|
||||
display: inline-block;
|
||||
margin: 10px 10px;
|
||||
margin: @drive_icon-margin;
|
||||
width: 140px;
|
||||
height: 140px;
|
||||
text-align: center;
|
||||
|
@ -471,6 +473,7 @@
|
|||
margin-top: 10px;
|
||||
}
|
||||
.cp-app-drive-content-info-box {
|
||||
order: 10;
|
||||
line-height: 2em;
|
||||
padding: 0.25em 0.75em;
|
||||
margin: 1em;
|
||||
|
@ -493,6 +496,7 @@
|
|||
}
|
||||
}
|
||||
#cp-app-drive-content-folder {
|
||||
order: 20;
|
||||
li {
|
||||
&.cp-app-drive-search-result {
|
||||
display: flex;
|
||||
|
@ -546,7 +550,10 @@
|
|||
.cp-app-drive-element-truncated { display: none; }
|
||||
}
|
||||
div.cp-app-drive-content-grid {
|
||||
padding: 20px;
|
||||
padding: 1em;
|
||||
ul {
|
||||
margin: -(@drive_icon-margin);
|
||||
}
|
||||
.drive_fileIcon;
|
||||
li {
|
||||
&.cp-app-drive-element {
|
||||
|
@ -754,6 +761,7 @@
|
|||
}
|
||||
|
||||
& > .cp-app-drive-path {
|
||||
order: 1;
|
||||
width: 100%;
|
||||
height: @variables_bar-height;
|
||||
line-height: @variables_bar-height;
|
||||
|
@ -927,5 +935,12 @@
|
|||
text-transform: uppercase;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.cp-app-drive-button {
|
||||
order: 15;
|
||||
margin: 0 1em;
|
||||
.buttons_main();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -114,7 +114,6 @@ define([
|
|||
var $trashEmptyIcon = $('<span>', {"class": "fa fa-trash-o"});
|
||||
//var $collapseIcon = $('<span>', {"class": "fa fa-minus-square-o cp-app-drive-icon-expcol"});
|
||||
var $expandIcon = $('<span>', {"class": "fa fa-plus-square-o cp-app-drive-icon-expcol"});
|
||||
var $emptyTrashIcon = $('<button>', {"class": "fa fa-ban"});
|
||||
var $listIcon = $('<button>', {"class": "fa fa-list"});
|
||||
var $gridIcon = $('<button>', {"class": "fa fa-th-large"});
|
||||
var $sortAscIcon = $('<span>', {"class": "fa fa-angle-up sortasc"});
|
||||
|
@ -447,19 +446,19 @@ define([
|
|||
h('li', h('a.cp-app-drive-context-delete.dropdown-item.cp-app-drive-context-editable', {
|
||||
'tabindex': '-1',
|
||||
'data-icon': faTrash,
|
||||
}, Messages.fc_delete)),
|
||||
}, Messages.fc_delete)), // "Move to trash"
|
||||
h('li', h('a.cp-app-drive-context-deleteowned.dropdown-item.cp-app-drive-context-editable', {
|
||||
'tabindex': '-1',
|
||||
'data-icon': faDelete,
|
||||
}, Messages.fc_delete_owned)),
|
||||
}, Messages.fc_delete_owned)), // XXX update key? "Delete from the server"
|
||||
h('li', h('a.cp-app-drive-context-remove.dropdown-item.cp-app-drive-context-editable', {
|
||||
'tabindex': '-1',
|
||||
'data-icon': faDelete,
|
||||
}, Messages.fc_remove)),
|
||||
'data-icon': faTrash,
|
||||
}, Messages.fc_remove)), // XXX update key? "Remove from your CryptDrive"
|
||||
h('li', h('a.cp-app-drive-context-removesf.dropdown-item.cp-app-drive-context-editable', {
|
||||
'tabindex': '-1',
|
||||
'data-icon': faDelete,
|
||||
}, Messages.fc_remove_sharedfolder)),
|
||||
'data-icon': faTrash,
|
||||
}, Messages.fc_remove_sharedfolder)), // XXX update key? "Remove"
|
||||
$separator.clone()[0],
|
||||
h('li', h('a.cp-app-drive-context-properties.dropdown-item', {
|
||||
'tabindex': '-1',
|
||||
|
@ -1280,18 +1279,12 @@ define([
|
|||
// If we're not in the trash nor in a shared folder, hide "remove"
|
||||
if (!manager.isInSharedFolder(path)
|
||||
&& !$element.is('.cp-app-drive-element-sharedf')) {
|
||||
// This isn't a shared folder: can't delete shared folder
|
||||
hide.push('removesf');
|
||||
} else if (type === "tree") {
|
||||
// This is a shared folder or an element inside a shsared folder
|
||||
// ==> can't move to trash
|
||||
hide.push('delete');
|
||||
// Don't hide the deleteowned link if the element is a shared folder and
|
||||
// it is owned
|
||||
if (manager.isInSharedFolder(path) ||
|
||||
!$element.is('.cp-app-drive-element-owned')) {
|
||||
hide.push('deleteowned');
|
||||
} else {
|
||||
// This is a shared folder and it is owned
|
||||
hide.push('removesf');
|
||||
}
|
||||
}
|
||||
if ($element.closest('[data-ro]').length) {
|
||||
editable = false;
|
||||
|
@ -1658,22 +1651,11 @@ define([
|
|||
if (paths) {
|
||||
paths.forEach(function (p) { pathsList.push(p.path); });
|
||||
}
|
||||
var hasOwned = pathsList.some(function (p) {
|
||||
// NOTE: Owned pads in shared folders won't be removed from the server
|
||||
// so we don't have to check, we can use the default message
|
||||
if (manager.isInSharedFolder(p)) { return false; }
|
||||
|
||||
var el = manager.find(p);
|
||||
var data = manager.isSharedFolder(el) ? manager.getSharedFolderData(el)
|
||||
: manager.getFileData(el);
|
||||
return data.owners && data.owners.indexOf(edPublic) !== -1;
|
||||
});
|
||||
var msg = Messages._getKey("fm_removeSeveralPermanentlyDialog", [pathsList.length]);
|
||||
if (pathsList.length === 1) {
|
||||
msg = hasOwned ? Messages.fm_deleteOwnedPad : Messages.fm_removePermanentlyDialog;
|
||||
} else if (hasOwned) {
|
||||
msg = msg + '<br><em>' + Messages.fm_removePermanentlyNote + '</em>';
|
||||
msg = Messages.fm_removePermanentlyDialog;
|
||||
}
|
||||
// XXX update key to tell the user that these pads will still be avialble to other users
|
||||
UI.confirm(msg, function(res) {
|
||||
$(window).focus();
|
||||
if (!res) { return; }
|
||||
|
@ -2397,17 +2379,55 @@ define([
|
|||
$gridButton.attr('title', Messages.fm_viewGridButton);
|
||||
$container.append($listButton).append($gridButton);
|
||||
};
|
||||
var createEmptyTrashButton = function ($container) {
|
||||
var $button = $emptyTrashIcon.clone();
|
||||
$button.addClass('cp-app-drive-toolbar-emptytrash');
|
||||
$button.attr('title', Messages.fc_empty);
|
||||
$button.click(function () {
|
||||
UI.confirm(Messages.fm_emptyTrashDialog, function(res) {
|
||||
if (!res) { return; }
|
||||
manager.emptyTrash(refresh);
|
||||
var emptyTrashModal = function () {
|
||||
var ownedInTrash = manager.ownedInTrash();
|
||||
var hasOwned = Array.isArray(ownedInTrash) && ownedInTrash.length;
|
||||
Messages.fm_emptyTrashOwned = "Your trash contains documents you own. You can remove them for everyone or only from your drive"; // XXX
|
||||
var content = h('p', [
|
||||
Messages.fm_emptyTrashDialog,
|
||||
hasOwned ? h('br') : undefined,
|
||||
hasOwned ? Messages.fm_emptyTrashOwned : undefined // XXX update UI?
|
||||
]);
|
||||
var buttons = [{
|
||||
className: 'cancel',
|
||||
name: Messages.cancelButton,
|
||||
onClick: function () {},
|
||||
keys: [27]
|
||||
}];
|
||||
if (hasOwned) {
|
||||
buttons.push({
|
||||
className: 'secondary',
|
||||
name: Messages.fc_delete_owned,
|
||||
onClick: function () {
|
||||
manager.emptyTrash(true, refresh);
|
||||
},
|
||||
keys: []
|
||||
});
|
||||
}
|
||||
buttons.push({
|
||||
className: 'primary',
|
||||
// XXX fc_remove: Remove from your CryptDrive
|
||||
// We may want to use a new key here
|
||||
name: hasOwned ? Messages.fc_remove : Messages.okButton,
|
||||
onClick: function () {
|
||||
manager.emptyTrash(false, refresh);
|
||||
},
|
||||
keys: [13]
|
||||
});
|
||||
$container.append($button);
|
||||
var m = UI.dialog.customModal(content, {
|
||||
buttons: buttons
|
||||
});
|
||||
UI.openCustomModal(m);
|
||||
};
|
||||
var createEmptyTrashButton = function () {
|
||||
var button = h('button.btn.btn-danger', [
|
||||
h('i.fa.'+faTrash),
|
||||
h('span', Messages.fc_empty)
|
||||
]);
|
||||
$(button).click(function () {
|
||||
emptyTrashModal();
|
||||
});
|
||||
return $(h('div.cp-app-drive-button', button));
|
||||
};
|
||||
|
||||
// Get the upload options
|
||||
|
@ -3145,6 +3165,8 @@ define([
|
|||
var displayTrashRoot = function ($list, $folderHeader, $fileHeader) {
|
||||
var filesList = [];
|
||||
var root = files[TRASH];
|
||||
var isEmpty = true;
|
||||
|
||||
// Elements in the trash are JS arrays (several elements can have the same name)
|
||||
Object.keys(root).forEach(function (key) {
|
||||
if (!Array.isArray(root[key])) {
|
||||
|
@ -3160,7 +3182,14 @@ define([
|
|||
name: key
|
||||
});
|
||||
});
|
||||
isEmpty = false;
|
||||
});
|
||||
|
||||
if (!isEmpty) {
|
||||
var $empty = createEmptyTrashButton();
|
||||
$content.append($empty);
|
||||
}
|
||||
|
||||
var sortedFolders = sortTrashElements(true, filesList, null, !getSortFolderDesc());
|
||||
var sortedFiles = sortTrashElements(false, filesList, APP.store[SORT_FILE_BY], !getSortFileDesc());
|
||||
if (manager.hasSubfolder(root, true)) { $list.append($folderHeader); }
|
||||
|
@ -3569,9 +3598,6 @@ define([
|
|||
}
|
||||
createViewModeButton(APP.toolbar.$bottomR);
|
||||
}
|
||||
if (inTrash) {
|
||||
createEmptyTrashButton(APP.toolbar.$bottomR);
|
||||
}
|
||||
|
||||
var $list = $('<ul>').appendTo($dirContent);
|
||||
|
||||
|
@ -3587,7 +3613,6 @@ define([
|
|||
}
|
||||
$content.data('readOnlyFolder', readOnlyFolder);
|
||||
|
||||
// NewButton can be undefined if we're in read only mode
|
||||
if (!readOnlyFolder) {
|
||||
createNewButton(isInRoot, APP.toolbar.$bottomL);
|
||||
}
|
||||
|
@ -3599,6 +3624,7 @@ define([
|
|||
}
|
||||
*/
|
||||
|
||||
|
||||
if (APP.mobile()) {
|
||||
var $context = $('<button>', {
|
||||
id: 'cp-app-drive-toolbar-context-mobile'
|
||||
|
@ -4029,7 +4055,7 @@ define([
|
|||
UI.confirm(msgD, function(res) {
|
||||
$(window).focus();
|
||||
if (!res) { return; }
|
||||
manager.delete(pathsList, function () {
|
||||
manager.deleteOwned(pathsList, function () {
|
||||
pathsList.forEach(LS.removeFoldersOpened);
|
||||
removeSelected();
|
||||
refresh();
|
||||
|
@ -4425,10 +4451,7 @@ define([
|
|||
log(Messages.fm_forbidden);
|
||||
return;
|
||||
}
|
||||
UI.confirm(Messages.fm_emptyTrashDialog, function(res) {
|
||||
if (!res) { return; }
|
||||
manager.emptyTrash(refresh);
|
||||
});
|
||||
emptyTrashModal();
|
||||
}
|
||||
else if ($this.hasClass("cp-app-drive-context-remove")) {
|
||||
return void deletePaths(paths);
|
||||
|
|
|
@ -2382,10 +2382,10 @@ define([
|
|||
unpin: unpin,
|
||||
loadSharedFolder: loadSharedFolder,
|
||||
settings: proxy.settings,
|
||||
removeOwnedChannel: function (channel, cb) { Store.removeOwnedChannel('', channel, cb); },
|
||||
Store: Store
|
||||
}, {
|
||||
outer: true,
|
||||
removeOwnedChannel: function (channel, cb) { Store.removeOwnedChannel('', channel, cb); },
|
||||
edPublic: store.proxy.edPublic,
|
||||
loggedIn: store.loggedIn,
|
||||
log: function (msg) {
|
||||
|
|
|
@ -285,9 +285,6 @@ define([
|
|||
settings: {
|
||||
drive: Util.find(ctx.store, ['proxy', 'settings', 'drive'])
|
||||
},
|
||||
Store: ctx.Store
|
||||
}, {
|
||||
outer: true,
|
||||
removeOwnedChannel: function (channel, cb) {
|
||||
var data;
|
||||
if (typeof(channel) === "object") {
|
||||
|
@ -301,6 +298,9 @@ define([
|
|||
}
|
||||
ctx.Store.removeOwnedChannel('', data, cb);
|
||||
},
|
||||
Store: ctx.Store
|
||||
}, {
|
||||
outer: true,
|
||||
edPublic: keys.drive.edPublic,
|
||||
loggedIn: true,
|
||||
log: function (msg) {
|
||||
|
|
|
@ -3,9 +3,8 @@ define([
|
|||
'/common/common-util.js',
|
||||
'/common/common-hash.js',
|
||||
'/common/common-realtime.js',
|
||||
'/common/common-feedback.js',
|
||||
'/customize/messages.js'
|
||||
], function (AppConfig, Util, Hash, Realtime, Feedback, Messages) {
|
||||
], function (AppConfig, Util, Hash, Realtime, Messages) {
|
||||
var module = {};
|
||||
|
||||
var clone = function (o) {
|
||||
|
@ -14,12 +13,8 @@ define([
|
|||
};
|
||||
|
||||
module.init = function (config, exp, files) {
|
||||
var removeOwnedChannel = config.removeOwnedChannel || function () {
|
||||
console.error("removeOwnedChannel was not provided");
|
||||
};
|
||||
var loggedIn = config.loggedIn;
|
||||
var sharedFolder = config.sharedFolder;
|
||||
var edPublic = config.edPublic;
|
||||
|
||||
var readOnly = config.readOnly;
|
||||
|
||||
|
@ -134,40 +129,17 @@ define([
|
|||
};
|
||||
|
||||
// Find files in FILES_DATA that are not anymore in the drive, and remove them from
|
||||
// FILES_DATA. If there are owned pads, remove them from server too.
|
||||
// FILES_DATA.
|
||||
exp.checkDeletedFiles = function (cb) {
|
||||
if (!loggedIn && !config.testMode) { return void cb(); }
|
||||
if (readOnly) { return void cb('EFORBIDDEN'); }
|
||||
|
||||
var filesList = exp.getFiles([ROOT, 'hrefArray', TRASH]);
|
||||
var toClean = [];
|
||||
var ownedRemoved = [];
|
||||
exp.getFiles([FILES_DATA, SHARED_FOLDERS]).forEach(function (id) {
|
||||
if (filesList.indexOf(id) === -1) {
|
||||
var fd = exp.isSharedFolder(id) ? files[SHARED_FOLDERS][id] : exp.getFileData(id);
|
||||
var channelId = fd.channel;
|
||||
// If trying to remove an owned pad, remove it from server also
|
||||
if (!sharedFolder && fd.owners && fd.owners.indexOf(edPublic) !== -1
|
||||
&& channelId) {
|
||||
if (channelId) { ownedRemoved.push(channelId); }
|
||||
Feedback.send('REMOVE_OWNED_CHANNEL');
|
||||
removeOwnedChannel(channelId, function (obj) {
|
||||
if (obj && obj.error) {
|
||||
// If the error is that the file is already removed, nothing to
|
||||
// report, it's a normal behavior (pad expired probably)
|
||||
if (obj.error.code === 'ENOENT') { return; }
|
||||
|
||||
// RPC may not be responding
|
||||
// Send a report that can be handled manually
|
||||
console.error(obj.error);
|
||||
Feedback.send('ERROR_DELETING_OWNED_PAD=' + channelId + '|' + obj.error, true);
|
||||
}
|
||||
});
|
||||
// Also remove the realtime channel for onlyoffice
|
||||
if (fd.rtChannel) {
|
||||
removeOwnedChannel(fd.rtChannel, function () {});
|
||||
}
|
||||
}
|
||||
if (fd.lastVersion) { toClean.push(Hash.hrefToHexChannelId(fd.lastVersion)); }
|
||||
if (fd.rtChannel) { toClean.push(fd.rtChannel); }
|
||||
if (channelId) { toClean.push(channelId); }
|
||||
|
@ -180,7 +152,7 @@ define([
|
|||
}
|
||||
});
|
||||
if (!toClean.length) { return void cb(); }
|
||||
cb(null, toClean, ownedRemoved);
|
||||
cb(null, toClean);
|
||||
};
|
||||
var deleteHrefs = function (ids) {
|
||||
if (readOnly) { return; }
|
||||
|
|
|
@ -4,8 +4,9 @@ define([
|
|||
'/common/common-hash.js',
|
||||
'/common/outer/sharedfolder.js',
|
||||
'/customize/messages.js',
|
||||
'/common/common-feedback.js',
|
||||
'/bower_components/nthen/index.js',
|
||||
], function (UserObject, Util, Hash, SF, Messages, nThen) {
|
||||
], function (UserObject, Util, Hash, SF, Messages, Feedback, nThen) {
|
||||
|
||||
|
||||
var getConfig = function (Env) {
|
||||
|
@ -397,26 +398,13 @@ define([
|
|||
// Copy the elements to the new location
|
||||
var toCopy = _getCopyFromPaths(Env, resolved.main, Env.user.userObject);
|
||||
var newUserObject = newResolved.userObject;
|
||||
var ownedPads = [];
|
||||
toCopy.forEach(function (obj) {
|
||||
newUserObject.copyFromOtherDrive(newResolved.path, obj.el, obj.data, obj.key);
|
||||
var _owned = Object.keys(obj.data).filter(function (id) {
|
||||
var owners = obj.data[id].owners;
|
||||
return _ownedByMe(Env, owners);
|
||||
});
|
||||
Array.prototype.push.apply(ownedPads, _owned);
|
||||
});
|
||||
|
||||
if (copy) { return; }
|
||||
|
||||
if (resolved.main.length) {
|
||||
var rootPath = resolved.main[0].slice();
|
||||
rootPath.pop();
|
||||
ownedPads = Util.deduplicateString(ownedPads);
|
||||
ownedPads.forEach(function (id) {
|
||||
Env.user.userObject.add(Number(id), rootPath);
|
||||
});
|
||||
|
||||
// Remove the elements from the old location (without unpinning)
|
||||
Env.user.userObject.delete(resolved.main, waitFor()); // FIXME waitFor() is called synchronously
|
||||
}
|
||||
|
@ -703,23 +691,22 @@ define([
|
|||
});
|
||||
};
|
||||
|
||||
// Delete permanently some pads or folders
|
||||
var _delete = function (Env, data, cb) {
|
||||
data = data || {};
|
||||
var resolved = _resolvePaths(Env, data.paths);
|
||||
var resolved = data.resolved || _resolvePaths(Env, data.paths);
|
||||
if (!resolved.main.length && !Object.keys(resolved.folders).length) {
|
||||
return void cb({error: 'E_NOTFOUND'});
|
||||
}
|
||||
|
||||
// Deleted or password changed for a shared folder
|
||||
if (data.paths.length === 1 && data.paths[0][0] === UserObject.SHARED_FOLDERS_TEMP) {
|
||||
if (data.paths && data.paths.length === 1 &&
|
||||
data.paths[0][0] === UserObject.SHARED_FOLDERS_TEMP) {
|
||||
var temp = Util.find(Env, ['user', 'proxy', UserObject.SHARED_FOLDERS_TEMP]);
|
||||
delete temp[data.paths[0][1]];
|
||||
return void Env.onSync(cb);
|
||||
}
|
||||
|
||||
var toUnpin = [];
|
||||
var ownedRemoved;
|
||||
nThen(function (waitFor) {
|
||||
// Delete paths from the main drive and get the list of pads to unpin
|
||||
// We also get the list of owned pads that were removed
|
||||
|
@ -742,8 +729,8 @@ define([
|
|||
});
|
||||
});
|
||||
}
|
||||
uo.delete(resolved.main, waitFor(function (err, _toUnpin, _ownedRemoved) {
|
||||
ownedRemoved = _ownedRemoved;
|
||||
uo.delete(resolved.main, waitFor(function (err, _toUnpin/*, _ownedRemoved*/) {
|
||||
//ownedRemoved = _ownedRemoved;
|
||||
if (!Env.unpinPads || !_toUnpin) { return; }
|
||||
Array.prototype.push.apply(toUnpin, _toUnpin);
|
||||
}));
|
||||
|
@ -752,7 +739,7 @@ define([
|
|||
// Check if removed owned pads are duplicated in some shared folders
|
||||
// If that's the case, we have to remove them from the shared folders too
|
||||
// We can do that by adding their paths to the list of pads to remove from shared folders
|
||||
if (ownedRemoved) {
|
||||
/*if (ownedRemoved) {
|
||||
var ids = _findChannels(Env, ownedRemoved);
|
||||
ids.forEach(function (id) {
|
||||
var paths = findFile(Env, id);
|
||||
|
@ -765,7 +752,7 @@ define([
|
|||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}*/
|
||||
// Delete paths from the shared folders
|
||||
Object.keys(resolved.folders).forEach(function (id) {
|
||||
Env.folders[id].userObject.delete(resolved.folders[id], waitFor(function (err, _toUnpin) {
|
||||
|
@ -805,18 +792,114 @@ define([
|
|||
cb();
|
||||
});
|
||||
};
|
||||
// Delete permanently some pads or folders
|
||||
var _deleteOwned = function (Env, data, cb) {
|
||||
data = data || {};
|
||||
var resolved = _resolvePaths(Env, data.paths);
|
||||
if (!resolved.main.length && !Object.keys(resolved.folders).length) {
|
||||
return void cb({error: 'E_NOTFOUND'});
|
||||
}
|
||||
var toDelete = {
|
||||
main: [],
|
||||
folders: {}
|
||||
};
|
||||
var todo = function (id, uo, p, _cb) {
|
||||
var cb = Util.once(Util.mkAsync(_cb));
|
||||
var el = uo.find(p);
|
||||
if (!uo.isFile(el) && !uo.isSharedFolder(el)) { return; }
|
||||
var data = uo.isFile(el) ? uo.getFileData(el) : getSharedFolderData(Env, el);
|
||||
var chan = data.channel;
|
||||
Env.removeOwnedChannel(chan, function (obj) {
|
||||
// If the error is that the file is already removed, nothing to
|
||||
// report, it's a normal behavior (pad expired probably)
|
||||
if (obj && obj.error && obj.error.code !== "ENOENT") {
|
||||
// RPC may not be responding
|
||||
// Send a report that can be handled manually
|
||||
console.error(obj.error, chan);
|
||||
Feedback.send('ERROR_DELETING_OWNED_PAD=' + chan + '|' + obj.error, true);
|
||||
return void cb();
|
||||
}
|
||||
|
||||
// No error: delete the pads and all its copies from our drive and shared folders
|
||||
var ids = _findChannels(Env, [chan]);
|
||||
ids.forEach(function (id) {
|
||||
var paths = findFile(Env, id);
|
||||
var _resolved = _resolvePaths(Env, paths);
|
||||
|
||||
Array.prototype.push.apply(toDelete.main, _resolved.main);
|
||||
Object.keys(_resolved.folders).forEach(function (fId) {
|
||||
if (toDelete.folders[fId]) {
|
||||
Array.prototype.push.apply(toDelete.folders[fId], _resolved.folders[fId]);
|
||||
} else {
|
||||
toDelete.folders[fId] = _resolved.folders[fId];
|
||||
}
|
||||
});
|
||||
});
|
||||
cb();
|
||||
});
|
||||
};
|
||||
nThen(function (w) {
|
||||
// Delete owned pads from the server
|
||||
resolved.main.forEach(function (p) {
|
||||
todo(null, Env.user.userObject, p, w());
|
||||
});
|
||||
Object.keys(resolved.folders).forEach(function (id) {
|
||||
var uo = Env.folders[id].userObject;
|
||||
resolved.folders[id].forEach(function (p) {
|
||||
todo(id, uo, p, w());
|
||||
});
|
||||
});
|
||||
}).nThen(function () {
|
||||
// Remove deleted pads from the drive
|
||||
_delete(Env, { resolved: toDelete }, cb);
|
||||
});
|
||||
};
|
||||
|
||||
// Empty the trash (main drive only)
|
||||
var _emptyTrash = function (Env, data, cb) {
|
||||
Env.user.userObject.emptyTrash(function (err, toClean) {
|
||||
cb();
|
||||
nThen(function (waitFor) {
|
||||
if (data && data.deleteOwned) {
|
||||
// Delete owned pads in the trash from the server
|
||||
var owned = Env.user.userObject.ownedInTrash(function (owners) {
|
||||
return _ownedByMe(Env, owners);
|
||||
});
|
||||
owned.forEach(function (chan) {
|
||||
Env.removeOwnedChannel(chan, waitFor(function (obj) {
|
||||
// If the error is that the file is already removed, nothing to
|
||||
// report, it's a normal behavior (pad expired probably)
|
||||
if (obj && obj.error && obj.error.code !== "ENOENT") {
|
||||
// RPC may not be responding
|
||||
// Send a report that can be handled manually
|
||||
console.error(obj.error, chan);
|
||||
Feedback.send('ERROR_EMPTYTRASH_OWNED=' + chan + '|' + obj.error, true);
|
||||
}
|
||||
console.warn('DELETED', chan);
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
// Check if need need to restore a full hash (hidden hash deleted from drive)
|
||||
if (!Array.isArray(toClean)) { return; }
|
||||
var toCheck = Util.deduplicateString(toClean);
|
||||
toCheck.forEach(function (chan) {
|
||||
Env.Store.checkDeletedPad(chan);
|
||||
});
|
||||
});
|
||||
// Empty the trash
|
||||
Env.user.userObject.emptyTrash(waitFor(function (err, toClean) {
|
||||
cb();
|
||||
|
||||
// Don't block nThen for the lower-priority tasks
|
||||
setTimeout(function () {
|
||||
// Unpin deleted pads if needed
|
||||
// Check if we need to restore a full hash (hidden hash deleted from drive)
|
||||
if (!Array.isArray(toClean)) { return; }
|
||||
var toCheck = Util.deduplicateString(toClean);
|
||||
var toUnpin = [];
|
||||
toCheck.forEach(function (channel) {
|
||||
// Check unpin
|
||||
var data = findChannel(Env, channel, true);
|
||||
if (!data.length) { toUnpin.push(channel); }
|
||||
// Check hidden hash
|
||||
Env.Store.checkDeletedPad(channel);
|
||||
});
|
||||
Env.unpinPads(toUnpin, function () {});
|
||||
});
|
||||
}));
|
||||
}).nThen(cb);
|
||||
};
|
||||
// Rename files or folders
|
||||
var _rename = function (Env, data, cb) {
|
||||
|
@ -868,6 +951,8 @@ define([
|
|||
_convertFolderToSharedFolder(Env, data, cb); break;
|
||||
case 'delete':
|
||||
_delete(Env, data, cb); break;
|
||||
case 'deleteOwned':
|
||||
_deleteOwned(Env, data, cb); break;
|
||||
case 'emptyTrash':
|
||||
_emptyTrash(Env, data, cb); break;
|
||||
case 'rename':
|
||||
|
@ -1076,14 +1161,6 @@ define([
|
|||
if (e) { error = e; return; }
|
||||
uo.add(id, p);
|
||||
}));
|
||||
if (uo.id && _ownedByMe(Env, pad.owners)) {
|
||||
// Creating an owned pad in a shared folder:
|
||||
// We must add a copy in the user's personnal drive
|
||||
Env.user.userObject.pushData(pad, waitFor(function (e, id) {
|
||||
if (e) { error = e; return; }
|
||||
Env.user.userObject.add(id, ['root']);
|
||||
}));
|
||||
}
|
||||
}).nThen(function () {
|
||||
cb(error);
|
||||
});
|
||||
|
@ -1101,6 +1178,7 @@ define([
|
|||
unpinPads: data.unpin,
|
||||
onSync: data.onSync,
|
||||
Store: data.Store,
|
||||
removeOwnedChannel: data.removeOwnedChannel,
|
||||
loadSharedFolder: data.loadSharedFolder,
|
||||
cfg: uoConfig,
|
||||
edPublic: data.edPublic,
|
||||
|
@ -1140,6 +1218,7 @@ define([
|
|||
getChannelsList: callWithEnv(getChannelsList),
|
||||
addPad: callWithEnv(addPad),
|
||||
delete: callWithEnv(_delete),
|
||||
deleteOwned: callWithEnv(_deleteOwned),
|
||||
// Tools
|
||||
findChannel: callWithEnv(findChannel),
|
||||
findHref: callWithEnv(findHref),
|
||||
|
@ -1175,10 +1254,12 @@ define([
|
|||
}
|
||||
}, cb);
|
||||
};
|
||||
var emptyTrashInner = function (Env, cb) {
|
||||
var emptyTrashInner = function (Env, deleteOwned, cb) {
|
||||
return void Env.sframeChan.query("Q_DRIVE_USEROBJECT", {
|
||||
cmd: "emptyTrash",
|
||||
data: null
|
||||
data: {
|
||||
deleteOwned: deleteOwned
|
||||
}
|
||||
}, cb);
|
||||
};
|
||||
var addFolderInner = function (Env, path, name, cb) {
|
||||
|
@ -1228,6 +1309,14 @@ define([
|
|||
}
|
||||
}, cb);
|
||||
};
|
||||
var deleteOwnedInner = function (Env, paths, cb) {
|
||||
return void Env.sframeChan.query("Q_DRIVE_USEROBJECT", {
|
||||
cmd: "deleteOwned",
|
||||
data: {
|
||||
paths: paths,
|
||||
}
|
||||
}, cb);
|
||||
};
|
||||
var restoreInner = function (Env, path, cb) {
|
||||
return void Env.sframeChan.query("Q_DRIVE_USEROBJECT", {
|
||||
cmd: "restore",
|
||||
|
@ -1381,6 +1470,11 @@ define([
|
|||
}
|
||||
return Env.user.userObject.hasFile(el, trashRoot);
|
||||
};
|
||||
var ownedInTrash = function (Env) {
|
||||
return Env.user.userObject.ownedInTrash(function (owners) {
|
||||
return _ownedByMe(Env, owners);
|
||||
});
|
||||
};
|
||||
|
||||
var isDuplicateOwned = _isDuplicateOwned;
|
||||
|
||||
|
@ -1416,6 +1510,7 @@ define([
|
|||
restoreSharedFolder: callWithEnv(restoreSharedFolderInner),
|
||||
convertFolderToSharedFolder: callWithEnv(convertFolderToSharedFolderInner),
|
||||
delete: callWithEnv(deleteInner),
|
||||
deleteOwned: callWithEnv(deleteOwnedInner),
|
||||
restore: callWithEnv(restoreInner),
|
||||
setFolderData: callWithEnv(setFolderDataInner),
|
||||
// Tools
|
||||
|
@ -1435,6 +1530,7 @@ define([
|
|||
isInSharedFolder: callWithEnv(isInSharedFolder),
|
||||
getUserObjectPath: callWithEnv(getUserObjectPath),
|
||||
isDuplicateOwned: callWithEnv(isDuplicateOwned),
|
||||
ownedInTrash: callWithEnv(ownedInTrash),
|
||||
// Generic
|
||||
isValidDrive: callWithEnv(isValidDrive),
|
||||
isFile: callWithEnv(isFile),
|
||||
|
|
|
@ -844,6 +844,12 @@ define([
|
|||
files[TRASH] = {};
|
||||
exp.checkDeletedFiles(cb);
|
||||
};
|
||||
exp.ownedInTrash = function (isOwned) {
|
||||
return getFiles([TRASH]).map(function (id) {
|
||||
var data = exp.getFileData(id);
|
||||
return isOwned(data.owners) ? data.channel : undefined;
|
||||
}).filter(Boolean);
|
||||
};
|
||||
|
||||
// RENAME
|
||||
exp.rename = function (path, newName, cb) {
|
||||
|
|
Loading…
Reference in New Issue