define([ '/common/userObject.js', '/common/common-util.js', '/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, Feedback, nThen) { var getConfig = function (Env) { var cfg = {}; for (var k in Env.cfg) { cfg[k] = Env.cfg[k]; } return cfg; }; // Add a shared folder to the list var addProxy = function (Env, id, lm, leave, editKey, force) { if (Env.folders[id] && !force && !Env.folders[id].restricted) { // Shared folder already added to the proxy-manager, probably // a cached version if (Env.folders[id].offline && !lm.cache) { Env.folders[id].offline = false; if (Env.folders[id].userObject.fixFiles) { Env.folders[id].userObject.fixFiles(); } Env.Store.refreshDriveUI(); } return; } var cfg = getConfig(Env); cfg.sharedFolder = true; cfg.id = id; cfg.editKey = editKey; cfg.rt = lm.realtime; cfg.readOnly = Boolean(!editKey); var userObject = UserObject.init(lm.proxy, cfg); if (userObject.fixFiles) { // Only in outer userObject.fixFiles(); } var proxy = lm.proxy; if (proxy.metadata && proxy.metadata.title) { var sf = Env.user.proxy[UserObject.SHARED_FOLDERS][id]; if (sf) { sf.lastTitle = proxy.metadata.title; } } Env.folders[id] = { proxy: lm.proxy, userObject: userObject, leave: leave, restricted: proxy.restricted, offline: Boolean(lm.cache) }; if (proxy.on) { proxy.on('disconnect', function () { Env.folders[id].offline = true; }); proxy.on('reconnect', function () { Env.folders[id].offline = false; }); } return userObject; }; var removeProxy = function (Env, id) { var f = Env.folders[id]; if (!f) { return; } f.leave(); delete Env.folders[id]; }; // Password may have changed var deprecateProxy = function (Env, id, channel) { if (Env.folders[id] && Env.folders[id].deleting) { // Folder is being deleted by its owner, don't deprecate it return; } if (Env.user.userObject.readOnly) { // In a read-only team, we can't deprecate a shared folder // Use a empty object with a deprecated flag... var lm = { proxy: { deprecated: true } }; removeProxy(Env, id); addProxy(Env, id, lm, function () {}); return void Env.Store.refreshDriveUI(); } if (channel) { Env.unpinPads([channel], function () {}); } Env.user.userObject.deprecateSharedFolder(id); removeProxy(Env, id); if (Env.Store && Env.Store.refreshDriveUI) { Env.Store.refreshDriveUI(); } }; var restrictedProxy = function (Env, id) { var lm = { proxy: { restricted: true, root: {}, filesData: {} } }; removeProxy(Env, id); addProxy(Env, id, lm, function () {}); return void Env.Store.refreshDriveUI(); }; /* Tools */ var _ownedByMe = function (Env, owners) { return Array.isArray(owners) && owners.indexOf(Env.edPublic) !== -1; }; var _ownedByOther = function (Env, owners) { return Array.isArray(owners) && owners.length && (!Env.edPublic || owners.indexOf(Env.edPublic) === -1); }; var _getUserObjects = function (Env) { var userObjects = [Env.user.userObject]; var foldersUO = Object.keys(Env.folders).map(function (k) { return Env.folders[k].userObject; }); Array.prototype.push.apply(userObjects, foldersUO); return userObjects; }; var _getUserObjectFromId = function (Env, id) { var userObjects = _getUserObjects(Env); var userObject = Env.user.userObject; userObjects.some(function (uo) { if (Object.keys(uo.getFileData(id)).length) { userObject = uo; return true; } }); return userObject; }; var _getUserObjectPath = function (Env, uo) { var fId = Number(uo.id); if (!fId) { return; } var fPath = Env.user.userObject.findFile(fId)[0]; return fPath; }; // Return files data objects associated to a channel for setPadTitle // All occurences are returned, in drive or shared folders // If "editable" is true, the data returned is a proxy, otherwise // it's a cloned object (NOTE: href should never be edited directly) var findChannel = function (Env, channel, editable) { var ret = []; Env.user.userObject.findChannels([channel], true).forEach(function (id) { // Check in shared folders, then clone if needed var data = Env.user.proxy[UserObject.SHARED_FOLDERS][id]; if (data && !editable) { data = JSON.parse(JSON.stringify(data)); } // If it's not a shared folder, check the pads if (!data) { data = Env.user.userObject.getFileData(id, editable); } ret.push({ id: id, data: data, userObject: Env.user.userObject }); }); Object.keys(Env.folders).forEach(function (fId) { Env.folders[fId].userObject.findChannels([channel]).forEach(function (id) { ret.push({ id: id, fId: fId, data: Env.folders[fId].userObject.getFileData(id, editable), userObject: Env.folders[fId].userObject }); }); }); return ret; }; // Return files data objects associated to a given href for setPadAttribute... // If "editable" is true, the data returned is a proxy, otherwise // it's a cloned object (NOTE: href should never be edited directly) var findHref = function (Env, href) { var ret = []; var id = Env.user.userObject.getIdFromHref(href); if (id) { ret.push({ data: Env.user.userObject.getFileData(id), userObject: Env.user.userObject }); } Object.keys(Env.folders).forEach(function (fId) { var id = Env.folders[fId].userObject.getIdFromHref(href); if (!id) { return; } ret.push({ fId: fId, data: Env.folders[fId].userObject.getFileData(id), userObject: Env.folders[fId].userObject }); }); return ret; }; // Return paths linked to a file ID var findFile = function (Env, id) { var ret = []; var userObjects = _getUserObjects(Env); userObjects.forEach(function (uo) { var fPath = _getUserObjectPath(Env, uo); var results = uo.findFile(id); if (fPath) { // This is a shared folder, we have to fix the paths in the results results.forEach(function (p) { Array.prototype.unshift.apply(p, fPath); }); } // Push the results from this proxy Array.prototype.push.apply(ret, results); }); return ret; }; // Returns file IDs corresponding to the provided channels var _findChannels = function (Env, channels, onlyMain) { if (onlyMain) { return Env.user.userObject.findChannels(channels); } var ret = []; var userObjects = _getUserObjects(Env); userObjects.forEach(function (uo) { var results = uo.findChannels(channels); Array.prototype.push.apply(ret, results); }); ret = Util.deduplicateString(ret); return ret; }; var _getFileData = function (Env, id, editable) { var userObjects = _getUserObjects(Env); var data = {}; userObjects.some(function (uo) { data = uo.getFileData(id, editable); if (data && Object.keys(data).length) { return true; } }); return data; }; var getSharedFolderData = function (Env, id) { var inHistory; if (Env.isHistoryMode && !Env.folders[id]) { inHistory = true; } else if (!Env.folders[id]) { return {}; } var proxy = inHistory? {}: Env.folders[id].proxy; // Clean deprecated values if (Object.keys(proxy.metadata || {}).length > 1) { proxy.metadata = { title: proxy.metadata.title }; } var obj = Util.clone(proxy.metadata || {}); for (var k in Env.user.proxy[UserObject.SHARED_FOLDERS][id] || {}) { if (typeof(Env.user.proxy[UserObject.SHARED_FOLDERS][id][k]) === "undefined") { // XXX "deleted folder" for restricted shared folders when viewer in a team continue; } var data = Util.clone(Env.user.proxy[UserObject.SHARED_FOLDERS][id][k]); if (k === "href" && data.indexOf('#') === -1) { try { data = Env.user.userObject.cryptor.decrypt(data); } catch (e) {} } if (k === "href" && data.indexOf('#') === -1) { data = undefined; } obj[k] = data; } return obj; }; // Transform an absolute path into a path relative to the correct shared folder var _resolvePath = function (Env, path) { var res = { id: null, userObject: Env.user.userObject, path: path }; if (!Array.isArray(path) || path.length <= 1) { return res; } var current; var uo = Env.user.userObject; // We don't need to check the last element of the path because we only need to split it // when the path contains an element inside the shared folder for (var i=2; i