diff --git a/customize.dist/fsStore.js b/customize.dist/fsStore.js index 7ccde1947..8f2405643 100644 --- a/customize.dist/fsStore.js +++ b/customize.dist/fsStore.js @@ -131,9 +131,10 @@ define([ }; var onReady = function (f, proxy, Cryptpad, exp) { - var fo = FO.init(proxy.drive, { + var fo = exp.fo = FO.init(proxy.drive, { Cryptpad: Cryptpad }); + //storeObj = proxy; store = initStore(fo, proxy, exp); if (typeof(f) === 'function') { diff --git a/customize.dist/translations/messages.fr.js b/customize.dist/translations/messages.fr.js index e82df349f..03c459d47 100644 --- a/customize.dist/translations/messages.fr.js +++ b/customize.dist/translations/messages.fr.js @@ -25,6 +25,7 @@ define(function () { out.loading = "Chargement..."; out.error = "Erreur"; + out.saved = "Enregistré"; out.disconnected = 'Déconnecté'; out.synchronizing = 'Synchronisation'; @@ -248,6 +249,11 @@ define(function () { out.settings_resetTipsButton = "Réinitialiser les astuces visibles dans CryptDrive"; out.settings_resetTipsDone = "Toutes les astuces sont de nouveau visibles."; + out.settings_importTitle = "Importer les pads récents de ce navigateur dans mon CryptDrive"; + out.settings_import = "Importer"; + out.settings_importConfirm = "Êtes-vous sûr de vouloir importer les pads récents de ce navigateur dans le CryptDrive de votre compte utilisateur ?"; + out.settings_importDone = "Importation terminée"; + out.settings_userFeedbackHint1 = "CryptPad peut envoyer des retours d'expérience très limités vers le serveur, de manière à nous permettre d'améliorer l'expérience des utilisateurs."; out.settings_userFeedbackHint2 = "Le contenu de vos pads et les clés de déchiffrement ne seront jamais partagés avec le serveur."; out.settings_userFeedback = "Activer l'envoi de retours d'expérience"; diff --git a/customize.dist/translations/messages.js b/customize.dist/translations/messages.js index 95fb8d0b6..59b6124a3 100644 --- a/customize.dist/translations/messages.js +++ b/customize.dist/translations/messages.js @@ -27,6 +27,7 @@ define(function () { out.loading = "Loading..."; out.error = "Error"; + out.saved = "Saved"; out.disconnected = 'Disconnected'; out.synchronizing = 'Synchronizing'; @@ -250,6 +251,11 @@ define(function () { out.settings_resetTipsButton = "Reset the available tips in CryptDrive"; out.settings_resetTipsDone = "All the tips are now visible again."; + out.settings_importTitle = "Import this browser's recent pads in my CryptDrive"; + out.settings_import = "Import"; + out.settings_confirm = "Are you sure you want to import recent pads from this browser to your user account's CryptDrive?"; + out.settings_done = "Import completed"; + out.settings_userFeedbackHint1 = "CryptPad provides some very basic feedback to the server, to let us know how to improve your experience."; out.settings_userFeedbackHint2 = "Your pad's content will never be shared with the server."; out.settings_userFeedback = "Enable user feedback"; diff --git a/www/common/cryptpad-common.js b/www/common/cryptpad-common.js index 68f8ba4b6..5dca75e25 100644 --- a/www/common/cryptpad-common.js +++ b/www/common/cryptpad-common.js @@ -621,6 +621,28 @@ define([ }; // STORAGE + var findWeaker = common.findWeaker = function (href, recents) { + var rHref = href || getRelativeHref(window.location.href); + var parsed = parsePadUrl(rHref); + if (!parsed.hash) { return false; } + var weaker; + recents.some(function (pad) { + var p = parsePadUrl(pad.href); + if (p.type !== parsed.type) { return; } // Not the same type + if (p.hash === parsed.hash) { return; } // Same hash, not stronger + var pHash = parseHash(p.hash); + var parsedHash = parseHash(parsed.hash); + if (!parsedHash || !pHash) { return; } + if (pHash.version !== parsedHash.version) { return; } + if (pHash.channel !== parsedHash.channel) { return; } + if (pHash.mode === 'view' && parsedHash.mode === 'edit') { + weaker = pad.href; + return true; + } + return; + }); + return weaker; + }; var findStronger = common.findStronger = function (href, recents) { var rHref = href || getRelativeHref(window.location.href); var parsed = parsePadUrl(rHref); diff --git a/www/common/fileObject.js b/www/common/fileObject.js index 7c63384e6..43ba5c3e5 100644 --- a/www/common/fileObject.js +++ b/www/common/fileObject.js @@ -6,10 +6,10 @@ define([ var Messages = {}; - var ROOT = "root"; - var UNSORTED = "unsorted"; - var TRASH = "trash"; - var TEMPLATE = "template"; + var ROOT = module.ROOT = "root"; + var UNSORTED = module.UNSORTED = "unsorted"; + var TRASH = module.TRASH = "trash"; + var TEMPLATE = module.TEMPLATE = "template"; var init = module.init = function (files, config) { var Cryptpad = config.Cryptpad; diff --git a/www/common/mergeDrive.js b/www/common/mergeDrive.js index 9071bf71c..492be601e 100644 --- a/www/common/mergeDrive.js +++ b/www/common/mergeDrive.js @@ -2,8 +2,9 @@ require.config({ paths: { 'json.sortify': '/bower_components/json.sortify/dist/J define([ '/common/cryptpad-common.js', '/common/cryptget.js', + '/common/fileObject.js', 'json.sortify' -], function (Cryptpad, Crypt, Sortify) { +], function (Cryptpad, Crypt, FO, Sortify) { var exp = {}; var getType = function (el) { @@ -17,6 +18,7 @@ define([ var nkey = key; while (typeof (obj[nkey]) !== "undefined") { nkey = key + '_' + i; + i++; } return nkey; }; @@ -39,7 +41,8 @@ define([ }; // Merge obj2 into obj1 - // If keepOld is true, obj1 values are kept in case of conflict in the ROOT object + // If keepOld is true, obj1 values are kept in case of conflicti + // Not used ATM var merge = function (obj1, obj2, keepOld) { if (typeof (obj1) !== "object" || typeof (obj2) !== "object") { return; }; Object.keys(obj2).forEach(function (k) { @@ -57,40 +60,116 @@ define([ } // Else, they're both maps or both arrays if (getType(obj1[k]) === "array" && getType(obj2[k]) === "array") { - // CryptPad_RECENTPADS - if (k === 'CryptPad_RECENTPADS') { - var old = obj1[k]; - obj2[k].forEach(function (pad) { - if (!old.some(function (op) { - // TODO read-only links - return op.href === pad.href; - })) { - old.push(pad); - } - }); - return; - } var c = obj1[k].concat(obj2[k]); obj1[k] = deduplicate(c); return; } - merge(obj1[k], obj2[k]); + merge(obj1[k], obj2[k], keepOld); + }); + }; + + var createFromPath = function (proxy, oldFo, path, href) { + var root = proxy.drive; + + var error = function (msg) { + console.error(msg || "Unable to find that path", path); + }; + + if (path[0] === FO.TRASH && path.length === 4) { + href = oldFo.getTrashElementData(path); + path.pop(); + } + + var p, next, nextRoot; + path.forEach(function (p, i) { + if (!root) { return; } + if (typeof(p) === "string") { + if (getType(root) !== "object") { root = undefined; error(); return; } + if (i === path.length - 1) { + root[findAvailableKey(root, p)] = href; + return; + } + next = getType(path[i+1]); + nextRoot = getType(root[p]); + if (nextRoot !== "undefined") { + if (next === "string" && nextRoot === "object" || next === "number" && nextRoot === "array") { + root = root[p]; + return; + } + p = findAvailableKey(root, p); + } + if (next === "number") { + root[p] = []; + root = root[p]; + return; + } + root[p] = {}; + root = root[p]; + return; + } + // Path contains a non-string element: it's an array index + if (typeof(p) !== "number") { root = undefined; error(); return; } + if (getType(root) !== "array") { root = undefined; error(); return; } + if (i === path.length - 1) { + if (root.indexOf(href) === -1) { root.push(href); } + return; + } + next = getType(path[i+1]); + if (next === "number") { + error('2 consecutives arrays in the user object'); + root = undefined; + //root.push([]); + //root = root[root.length - 1]; + return; + } + root.push({}); + root = root[root.length - 1]; + return; }); }; var mergeAnonDrive = exp.anonDriveIntoUser = function (proxy, cb) { // Make sure we have an FS_hash and we don't use it, otherwise just stop the migration and cb if (!localStorage.FS_hash || !Cryptpad.isLoggedIn()) { - delete sessionStorage.migrateAnonDrive; if (typeof(cb) === "function") { cb(); } } // Get the content of FS_hash and then merge the objects, remove the migration key and cb var todo = function (err, doc) { - if (err) { logError("Cannot migrate recent pads", err); return; } + if (err) { console.error("Cannot migrate recent pads", err); return; } var parsed; try { parsed = JSON.parse(doc); } catch (e) { logError("Cannot parsed recent pads", e); } if (parsed) { - merge(proxy, parsed, true); + //merge(proxy, parsed, true); + var oldFo = FO.init(parsed.drive, { + Cryptpad: Cryptpad + }); + var newData = Cryptpad.getStore().getProxy(); + var newFo = newData.fo; + var newRecentPads = proxy.drive[Cryptpad.storageKey]; + var newFiles = newFo.getFilesDataFiles(); + var oldFiles = oldFo.getFilesDataFiles(); + oldFiles.forEach(function (href) { + // Do not migrate a pad if we already have it, it would create a duplicate in the drive + if (newFiles.indexOf(href) !== -1) { return; } + // If we have a stronger version, do not add the current href + if (Cryptpad.findStronger(href, newRecentPads)) { return; } + // If we have a weaker version, replace the href by the new one + // NOTE: if that weaker version is in the trash, the strong one will be put in unsorted + var weaker = Cryptpad.findWeaker(href, newRecentPads); + if (weaker) { + newFo.replaceHref(weaker, href); + return; + } + // Here it means we have a new href, so we should add it to the drive at its old location + var paths = oldFo.findFile(href); + if (paths.length === 0) { return; } + createFromPath(proxy, oldFo, paths[0], href); + // Also, push the file data in our array + var data = oldFo.getFileData(href); + if (data) { + newRecentPads.push(data); + } + }); } if (typeof(cb) === "function") { cb(); } }; diff --git a/www/settings/main.js b/www/settings/main.js index 5d6eba16b..8cdb95b2f 100644 --- a/www/settings/main.js +++ b/www/settings/main.js @@ -66,10 +66,9 @@ define([ 'id': 'displayName', 'placeholder': Messages.anonymous}).appendTo($div); var $save = $('