Teams: async-store refactoring

pull/1/head
yflory 6 years ago
parent 2b57d82e8a
commit 834e12fcba

@ -270,8 +270,6 @@
margin-left: -5px; margin-left: -5px;
padding-left: 5px; padding-left: 5px;
} }
& > span.cp-app-drive-element-row:not(.cp-app-drive-element-selected):not(.cp-app-drive-element-active):hover {
}
} }
} }
span.cp-app-drive-element { span.cp-app-drive-element {
@ -360,14 +358,14 @@
z-index: 10; z-index: 10;
cursor: default; cursor: default;
&:before { &:before {
position:relative; position: relative;
top: -1px; top: -1px;
} }
} }
.cp-app-drive-tree-docs { .cp-app-drive-tree-docs {
.cp-app-drive-tree-root > .cp-app-drive-element-row > .cp-app-drive-icon-expcol { .cp-app-drive-tree-root > .cp-app-drive-element-row > .cp-app-drive-icon-expcol {
position: relative; position: relative;
top:0; top: 0;
left: -10px; left: -10px;
} }
.cp-app-drive-tree-root > .cp-app-drive-element-row > .cp-app-drive-icon-folder { .cp-app-drive-tree-root > .cp-app-drive-element-row > .cp-app-drive-icon-folder {
@ -587,7 +585,7 @@
top: 3px; top: 3px;
right: 3px; right: 3px;
.fa, .cptools { .fa, .cptools {
margin:0; margin: 0;
font-size: 18px; font-size: 18px;
} }
} }

@ -157,8 +157,9 @@ define([
timeout: 5 * 60 * 1000 timeout: 5 * 60 * 1000
}); });
}; };
common.addSharedFolder = function (secret, cb) { common.addSharedFolder = function (teamId, secret, cb) {
postMessage("ADD_SHARED_FOLDER", { postMessage("ADD_SHARED_FOLDER", {
teamId: teamId,
path: ['root'], path: ['root'],
folderData: { folderData: {
href: '/drive/#' + Hash.getEditHashFromKeys(secret), href: '/drive/#' + Hash.getEditHashFromKeys(secret),

@ -59,18 +59,7 @@ define([
return; return;
} }
}; };
var getProxy = function (teamId) {
var s = getStore(teamId);
if (!s) { return; }
return s.proxy;
};
var getManager = function (teamId) {
var s = getStore(teamId);
if (!s) { return; }
return s.manager;
};
// XXX search for all calls
var onSync = function (teamId, cb) { var onSync = function (teamId, cb) {
var s = getStore(teamId); var s = getStore(teamId);
if (!s) { return void cb({ error: 'ENOTFOUND' }); } if (!s) { return void cb({ error: 'ENOTFOUND' }); }
@ -335,7 +324,7 @@ define([
}; };
Store.uploadComplete = function (clientId, data, cb) { Store.uploadComplete = function (clientId, data, cb) {
var s = getStore(teamId); var s = getStore(data.teamId);
if (!s) { return void cb({ error: 'ENOTFOUND' }); } if (!s) { return void cb({ error: 'ENOTFOUND' }); }
if (!s.rpc) { return void cb({error: 'RPC_NOT_READY'}); } if (!s.rpc) { return void cb({error: 'RPC_NOT_READY'}); }
if (data.owned) { if (data.owned) {
@ -354,7 +343,7 @@ define([
}; };
Store.uploadStatus = function (clientId, data, cb) { Store.uploadStatus = function (clientId, data, cb) {
var s = getStore(teamId); var s = getStore(data.teamId);
if (!s) { return void cb({ error: 'ENOTFOUND' }); } if (!s) { return void cb({ error: 'ENOTFOUND' }); }
if (!s.rpc) { return void cb({error: 'RPC_NOT_READY'}); } if (!s.rpc) { return void cb({error: 'RPC_NOT_READY'}); }
s.rpc.uploadStatus(data.size, function (err, res) { s.rpc.uploadStatus(data.size, function (err, res) {
@ -364,7 +353,7 @@ define([
}; };
Store.uploadCancel = function (clientId, data, cb) { Store.uploadCancel = function (clientId, data, cb) {
var s = getStore(teamId); var s = getStore(data.teamId);
if (!s) { return void cb({ error: 'ENOTFOUND' }); } if (!s) { return void cb({ error: 'ENOTFOUND' }); }
if (!s.rpc) { return void cb({error: 'RPC_NOT_READY'}); } if (!s.rpc) { return void cb({error: 'RPC_NOT_READY'}); }
s.rpc.uploadCancel(data.size, function (err, res) { s.rpc.uploadCancel(data.size, function (err, res) {
@ -374,7 +363,7 @@ define([
}; };
Store.uploadChunk = function (clientId, data, cb) { Store.uploadChunk = function (clientId, data, cb) {
var s = getStore(teamId); var s = getStore(data.teamId);
if (!s) { return void cb({ error: 'ENOTFOUND' }); } if (!s) { return void cb({ error: 'ENOTFOUND' }); }
if (!s.rpc) { return void cb({error: 'RPC_NOT_READY'}); } if (!s.rpc) { return void cb({error: 'RPC_NOT_READY'}); }
s.rpc.send.unauthenticated('UPLOAD', data.chunk, function (e, msg) { s.rpc.send.unauthenticated('UPLOAD', data.chunk, function (e, msg) {
@ -603,7 +592,7 @@ define([
send('DRIVE_CHANGE', { send('DRIVE_CHANGE', {
path: ['drive', UserObject.FILES_DATA] path: ['drive', UserObject.FILES_DATA]
}, clientId); }, clientId);
onSync(teamId, cb); onSync(data.teamId, cb);
}); });
}; };
@ -776,20 +765,22 @@ define([
return stores; return stores;
}; };
Store.setPadAttribute = function (clientId, data, cb) { Store.setPadAttribute = function (clientId, data, cb) {
getAllStores.forEach(function (s) { nThen(function (waitFor) {
s.manager.setPadAttribute(data, function () { getAllStores().forEach(function (s) {
var send = s.id ? s.sendEvent : sendDriveEvent; s.manager.setPadAttribute(data, waitFor(function () {
send('DRIVE_CHANGE', { var send = s.id ? s.sendEvent : sendDriveEvent;
path: ['drive', UserObject.FILES_DATA] send('DRIVE_CHANGE', {
}, clientId); path: ['drive', UserObject.FILES_DATA]
onSync(s.id, cb); }, clientId);
onSync(s.id, waitFor());
}));
}); });
}); }).nThen(cb); // cb when all managers are synced
}; };
Store.getPadAttribute = function (clientId, data, cb) { Store.getPadAttribute = function (clientId, data, cb) {
var res = {}; var res = {};
nThen(function (waitFor) { nThen(function (waitFor) {
getAllStores.forEach(function (s) { getAllStores().forEach(function (s) {
s.manager.getPadAttribute(data, waitFor(function (err, val) { s.manager.getPadAttribute(data, waitFor(function (err, val) {
if (err) { return; } if (err) { return; }
if (!res.value || res.atime < val.atime) { if (!res.value || res.atime < val.atime) {
@ -850,7 +841,7 @@ define([
// Tags // Tags
Store.listAllTags = function (clientId, data, cb) { Store.listAllTags = function (clientId, data, cb) {
var tags = {}; var tags = {};
getAllStores.forEach(function (s) { getAllStores().forEach(function (s) {
var l = s.manager.getTagsList(); var l = s.manager.getTagsList();
Object.keys(l).forEach(function (tag) { Object.keys(l).forEach(function (tag) {
tags[tag] = (tags[tag] || 0) + l[tag]; tags[tag] = (tags[tag] || 0) + l[tag];
@ -866,12 +857,12 @@ define([
// No templates in shared folders: we don't need the manager here // No templates in shared folders: we don't need the manager here
var res = []; var res = [];
var channels = []; var channels = [];
getAllStores.forEach(function (s) { getAllStores().forEach(function (s) {
var templateFiles = s.userObject.getFiles(['template']); var templateFiles = s.userObject.getFiles(['template']);
templateFiles.forEach(function (f) { templateFiles.forEach(function (f) {
var data = s.userObject.getFileData(f); var data = s.userObject.getFileData(f);
// Don't push duplicates // Don't push duplicates
if (channels.indexOf(data.channel) !== -1) { return } if (channels.indexOf(data.channel) !== -1) { return; }
channels.push(data.channel); channels.push(data.channel);
// Puhs a copy of the data // Puhs a copy of the data
res.push(JSON.parse(JSON.stringify(data))); res.push(JSON.parse(JSON.stringify(data)));
@ -881,35 +872,60 @@ define([
}; };
Store.incrementTemplateUse = function (clientId, href) { Store.incrementTemplateUse = function (clientId, href) {
// No templates in shared folders: we don't need the manager here // No templates in shared folders: we don't need the manager here
store.userObject.getPadAttribute(href, 'used', function (err, data) { getAllStores().forEach(function (s) {
// This is a not critical function, abort in case of error to make sure we won't s.userObject.getPadAttribute(href, 'used', function (err, data) {
// create any issue with the user object or the async store // This is a not critical function, abort in case of error to make sure we won't
if (err) { return; } // create any issue with the user object or the async store
var used = typeof data === "number" ? ++data : 1; if (err) { return; }
store.userObject.setPadAttribute(href, 'used', used); var used = typeof data === "number" ? ++data : 1;
s.userObject.setPadAttribute(href, 'used', used);
});
}); });
}; };
// Pads // Pads
Store.isOnlyInSharedFolder = function (clientId, channel, cb) { Store.isOnlyInSharedFolder = function (clientId, channel, cb) {
var res = store.manager.findChannel(channel); var res = false;
// The main drive doesn't have an fId (folder ID)
var isInMainDrive = function (obj) { return !obj.fId; };
// A pad is only in a shared folder if it is in one of our managers
// AND if if it not in any "main" drive
getAllStores().some(function (s) {
var _res = s.manager.findChannel(channel);
// Not in this manager: go the the next one
if (!_res.length) { return; }
// if the pad is in the main drive, cb(false)
if (_res.some(isInMainDrive)) {
res = false;
return true;
}
// Otherwise the pad is only in a shared folder in this manager:
// set the result to true and check the next manager
res = true;
});
// A pad is only in a shared worker if: return cb (res);
// 1. this pad is in at least one proxy
// 2. no proxy containing this pad is the main drive
return cb (res.length && !res.some(function (obj) {
// Main drive doesn't have an fId (folder ID)
return !obj.fId;
}));
}; };
Store.moveToTrash = function (clientId, data, cb) { Store.moveToTrash = function (clientId, data, cb) {
var href = Hash.getRelativeHref(data.href); var href = Hash.getRelativeHref(data.href);
store.userObject.forget(href); nThen(function (waitFor) {
sendDriveEvent('DRIVE_CHANGE', { getAllStores().forEach(function (s) {
path: ['drive', UserObject.FILES_DATA] var deleted = s.userObject.forget(href);
}, clientId); if (!deleted) { return; }
onSync(cb); var send = s.id ? s.sendEvent : sendDriveEvent;
send('DRIVE_CHANGE', {
path: ['drive', UserObject.FILES_DATA]
}, clientId);
onSync(s.id, waitFor());
});
}).nThen(cb);
}; };
// XXX Teams. encrypted href...
Store.setPadTitle = function (clientId, data, cb) { Store.setPadTitle = function (clientId, data, cb) {
var title = data.title; var title = data.title;
var href = data.href; var href = data.href;
@ -935,9 +951,19 @@ define([
expire = +channelData.data.expire || undefined; expire = +channelData.data.expire || undefined;
} }
var datas = store.manager.findChannel(channel); // Check if the pad is stored in any managers.
var contains = datas.length !== 0; // If it is stored, update its data, otherwise ask the user where to store it
datas.forEach(function (obj) { var allData = [];
var sendTo = [];
getAllStores().forEach(function (s) {
var res = s.manager.findChannel(channel);
if (res.length) {
sendTo.push(s.id);
}
Array.prototype.push.apply(allData, res);
});
var contains = allData.length !== 0;
allData.forEach(function (obj) {
var pad = obj.data; var pad = obj.data;
pad.atime = +new Date(); pad.atime = +new Date();
pad.title = title; pad.title = title;
@ -961,6 +987,7 @@ define([
// Add the pad if it does not exist in our drive // Add the pad if it does not exist in our drive
if (!contains) { if (!contains) {
var autoStore = Util.find(store.proxy, ['settings', 'general', 'autostore']); var autoStore = Util.find(store.proxy, ['settings', 'general', 'autostore']);
// XXX owned by one of our teams?
var ownedByMe = Array.isArray(owners) && owners.indexOf(store.proxy.edPublic) !== -1; var ownedByMe = Array.isArray(owners) && owners.indexOf(store.proxy.edPublic) !== -1;
if (autoStore !== 1 && !data.forceSave && !data.path && !ownedByMe) { if (autoStore !== 1 && !data.forceSave && !data.path && !ownedByMe) {
// send event to inner to display the corner popup // send event to inner to display the corner popup
@ -975,6 +1002,7 @@ define([
href = undefined; href = undefined;
} }
Store.addPad(clientId, { Store.addPad(clientId, {
teamId: data.teamId,
href: href, href: href,
roHref: roHref, roHref: roHref,
channel: channel, channel: channel,
@ -990,19 +1018,30 @@ define([
}); });
return; return;
} }
} else { }
sendDriveEvent('DRIVE_CHANGE', {
sendTo.forEach(function (teamId) {
var send = teamId ? getStore(teamId).sendEvent : sendDriveEvent;
send('DRIVE_CHANGE', {
path: ['drive', UserObject.FILES_DATA] path: ['drive', UserObject.FILES_DATA]
}, clientId); }, clientId);
// Let inner know that dropped files shouldn't trigger the popup });
postMessage(clientId, "AUTOSTORE_DISPLAY_POPUP", { // Let inner know that dropped files shouldn't trigger the popup
stored: true postMessage(clientId, "AUTOSTORE_DISPLAY_POPUP", {
stored: true
});
nThen(function (waitFor) {
sendTo.forEach(function (teamId) {
onSync(teamId, waitFor());
}); });
} }).nThen(cb);
onSync(cb);
}; };
// Filepicker app // Filepicker app
// Get a map of file data corresponding to the given filters.
// The keys used in the map represent the ID of the "files"
// TODO maybe we shouldn't mix results from teams and from the user?
Store.getSecureFilesList = function (clientId, query, cb) { Store.getSecureFilesList = function (clientId, query, cb) {
var list = {}; var list = {};
var types = query.types; var types = query.types;
@ -1019,20 +1058,31 @@ define([
} }
return filtered; return filtered;
}; };
store.manager.getSecureFilesList(where).forEach(function (obj) { var channels = [];
var data = obj.data; getAllStores().forEach(function (s) {
var id = obj.id; s.manager.getSecureFilesList(where).forEach(function (obj) {
var parsed = Hash.parsePadUrl(data.href || data.roHref); var data = obj.data;
if ((!types || types.length === 0 || types.indexOf(parsed.type) !== -1) && if (channels.indexOf(data.channel) !== -1) { return; }
!isFiltered(parsed.type, data)) { var id = obj.id;
list[id] = data; var parsed = Hash.parsePadUrl(data.href || data.roHref);
} if ((!types || types.length === 0 || types.indexOf(parsed.type) !== -1) &&
!isFiltered(parsed.type, data)) {
list[id] = data;
}
});
}); });
cb(list); cb(list);
}; };
// Get the first pad we can find in any of our managers and return its file data
Store.getPadData = function (clientId, id, cb) { Store.getPadData = function (clientId, id, cb) {
// FIXME: this is only used for templates at the moment, so we don't need the manager var res = {};
cb(store.userObject.getFileData(id)); getAllStores().some(function (s) {
var d = s.userObject.getFileData(id);
if (!d.roHref && !d.href) { return; }
res = d;
return true;
});
cb(res);
}; };
@ -1109,16 +1159,22 @@ define([
}; };
// Get hashes for the share button // Get hashes for the share button
// If we can find a stronger hash
Store.getStrongerHash = function (clientId, data, cb) { Store.getStrongerHash = function (clientId, data, cb) {
var allPads = Util.find(store.proxy, ['drive', 'filesData']) || {}; var found = getAllStores().some(function (s) {
var allPads = Util.find(s.proxy, ['drive', 'filesData']) || {};
// If we have a stronger version in drive, add it and add a redirect button
var stronger = Hash.findStronger(data.href, data.channel, allPads); // If we have a stronger version in drive, add it and add a redirect button
if (stronger) { var stronger = Hash.findStronger(data.href, data.channel, allPads);
var parsed2 = Hash.parsePadUrl(stronger.href); if (stronger) {
return void cb(parsed2.hash); var parsed2 = Hash.parsePadUrl(stronger.href);
cb(parsed2.hash);
return true;
}
});
if (!found) {
cb();
} }
cb();
}; };
// Universal // Universal
@ -1318,12 +1374,14 @@ define([
}, },
onMetadataUpdate: function (metadata) { onMetadataUpdate: function (metadata) {
channel.data = metadata || {}; channel.data = metadata || {};
var allData = store.manager.findChannel(data.channel); getAllStores().forEach(function (s) {
allData.forEach(function (obj) { var allData = s.manager.findChannel(data.channel);
obj.data.owners = metadata.owners; allData.forEach(function (obj) {
if (metadata.expire) { obj.data.owners = metadata.owners;
obj.data.expire = +metadata.expire; if (metadata.expire) {
} obj.data.expire = +metadata.expire;
}
});
}); });
channel.bcast("PAD_METADATA", metadata); channel.bcast("PAD_METADATA", metadata);
}, },
@ -1460,6 +1518,7 @@ define([
var href, title; var href, title;
// XXX TEAMOWNER
if (!res.some(function (obj) { if (!res.some(function (obj) {
if (obj.data && if (obj.data &&
Array.isArray(obj.data.owners) && obj.data.owners.indexOf(edPublic) !== -1 && Array.isArray(obj.data.owners) && obj.data.owners.indexOf(edPublic) !== -1 &&
@ -1509,6 +1568,10 @@ define([
Store.setPadMetadata = function (clientId, data, cb) { Store.setPadMetadata = function (clientId, data, cb) {
if (!data.channel) { return void cb({ error: 'ENOTFOUND'}); } if (!data.channel) { return void cb({ error: 'ENOTFOUND'}); }
if (!data.command) { return void cb({ error: 'EINVAL' }); } if (!data.command) { return void cb({ error: 'EINVAL' }); }
// XXX TEAMOWNER
// If owned by a team, we should use the team rpc here
// We'll need common-ui-elements to tell us the "owners" value or we can
// call getPadMetadata first
store.rpc.setMetadata(data, function (err, res) { store.rpc.setMetadata(data, function (err, res) {
if (err) { return void cb({ error: err }); } if (err) { return void cb({ error: err }); }
if (!Array.isArray(res) || !res.length) { return void cb({}); } if (!Array.isArray(res) || !res.length) { return void cb({}); }
@ -1638,8 +1701,10 @@ define([
Store.loadSharedFolder(null, data.id, data.data, cb); Store.loadSharedFolder(null, data.id, data.data, cb);
}; };
Store.addSharedFolder = function (clientId, data, cb) { Store.addSharedFolder = function (clientId, data, cb) {
store.manager.addSharedFolder(data, function (id) { var s = getStore(data.teamId);
sendDriveEvent('DRIVE_CHANGE', { s.manager.addSharedFolder(data, function (id) {
var send = data.teamId ? s.sendEvent : sendDriveEvent;
send('DRIVE_CHANGE', {
path: ['drive', UserObject.FILES_DATA] path: ['drive', UserObject.FILES_DATA]
}, clientId); }, clientId);
cb(id); cb(id);
@ -1650,20 +1715,17 @@ define([
Store.userObjectCommand = function (clientId, cmdData, cb) { Store.userObjectCommand = function (clientId, cmdData, cb) {
if (!cmdData || !cmdData.cmd) { return; } if (!cmdData || !cmdData.cmd) { return; }
//var data = cmdData.data; //var data = cmdData.data;
var s = getStore(cmdData.teamId);
var cb2 = function (data2) { var cb2 = function (data2) {
//var paths = data.paths || [data.path] || []; var send = cmdData.teamId ? s.sendEvent : sendDriveEvent;
//paths = paths.concat(data.newPath ? [data.newPath] : []); send('DRIVE_CHANGE', {
//paths.forEach(function (p) { path: ['drive', UserObject.FILES_DATA]
sendDriveEvent('DRIVE_CHANGE', { }, clientId);
path: ['drive', UserObject.FILES_DATA] onSync(cmdData.teamId, function () {
//path: ['drive'].concat(p)
}, clientId);
//});
onSync(function () {
cb(data2); cb(data2);
}); });
}; };
store.manager.command(cmdData, cb2); s.manager.command(cmdData, cb2);
}; };
// Clients management // Clients management

@ -83,7 +83,7 @@ define([
}).nThen(function (waitFor) { }).nThen(function (waitFor) {
Object.keys(shared).forEach(function (id) { Object.keys(shared).forEach(function (id) {
var sf = shared[id]; var sf = shared[id];
var rt = SF.load({ SF.load({
network: network, network: network,
store: store store: store
}, id, sf, waitFor()); }, id, sf, waitFor());

@ -36,6 +36,7 @@ define([
// load manager with userObject // load manager with userObject
// team.manager =... team.userObject = .... // team.manager =... team.userObject = ....
// load shared folders // load shared folders
// register event for these folders
// ~resetPins for the team? // ~resetPins for the team?
// getPinLimit // getPinLimit
ctx.teams[id] = team; ctx.teams[id] = team;
@ -63,6 +64,9 @@ define([
lm.proxy.on('create', function () { lm.proxy.on('create', function () {
}).on('ready', function () { }).on('ready', function () {
var sendEvent = function (type, data, sender) { var sendEvent = function (type, data, sender) {
type = type;
data = data;
sender = sender;
// XXX emit UPDATE event to the inner iframe // XXX emit UPDATE event to the inner iframe
// don't send the event back to the sender // don't send the event back to the sender
// types are DRIVE_CHANGE, DRIVE_REMOVE and DRIVE_LOG // types are DRIVE_CHANGE, DRIVE_REMOVE and DRIVE_LOG

@ -317,10 +317,11 @@ define([
if (!loggedIn && !config.testMode) { if (!loggedIn && !config.testMode) {
// delete permanently // delete permanently
spliceFileData(id); spliceFileData(id);
return; return true;
} }
var paths = exp.findFile(id); var paths = exp.findFile(id);
exp.move(paths, [TRASH]); exp.move(paths, [TRASH]);
return true;
}; };
// REPLACE // REPLACE

@ -40,7 +40,7 @@ define([
var hash = window.location.hash.slice(1); var hash = window.location.hash.slice(1);
if (hash && Utils.LocalStore.isLoggedIn()) { if (hash && Utils.LocalStore.isLoggedIn()) {
// Add a shared folder! // Add a shared folder!
Cryptpad.addSharedFolder(secret, function (id) { Cryptpad.addSharedFolder(null, secret, function (id) {
window.CryptPad_newSharedFolder = id; window.CryptPad_newSharedFolder = id;
cb(); cb();
}); });

@ -41,7 +41,7 @@ define([
var hash = window.location.hash.slice(1); var hash = window.location.hash.slice(1);
if (hash && Utils.LocalStore.isLoggedIn()) { if (hash && Utils.LocalStore.isLoggedIn()) {
// Add a shared folder! // Add a shared folder!
Cryptpad.addSharedFolder(secret, function (id) { Cryptpad.addSharedFolder(teamId, secret, function (id) {
window.CryptPad_newSharedFolder = id; window.CryptPad_newSharedFolder = id;
cb(); cb();
}); });
@ -58,13 +58,8 @@ define([
cb(); cb();
}; };
var addRpc = function (sframeChan, Cryptpad, Utils) { var addRpc = function (sframeChan, Cryptpad, Utils) {
sframeChan.on('EV_BURN_ANON_DRIVE', function () {
if (Utils.LocalStore.isLoggedIn()) { return; }
Utils.LocalStore.setFSHash('');
Utils.LocalStore.clearThumbnail();
window.location.reload();
});
sframeChan.on('Q_DRIVE_USEROBJECT', function (data, cb) { sframeChan.on('Q_DRIVE_USEROBJECT', function (data, cb) {
data.teamId = teamId;
Cryptpad.userObjectCommand(data, cb); Cryptpad.userObjectCommand(data, cb);
}); });
// XXX no drive restore in teams? you could restore old keys... // XXX no drive restore in teams? you could restore old keys...
@ -115,9 +110,9 @@ define([
afterSecrets: afterSecrets, afterSecrets: afterSecrets,
noHash: true, noHash: true,
noRealtime: true, noRealtime: true,
driveEvents: true, //driveEvents: true,
addRpc: addRpc, addRpc: addRpc,
isDrive: true, isDrive: true, // Used for history...
}); });
}); });
}); });

Loading…
Cancel
Save