diff --git a/pinneddata.js b/pinneddata.js index 8dbbc7fec..2ecf8605d 100644 --- a/pinneddata.js +++ b/pinneddata.js @@ -30,7 +30,7 @@ const sizeForHashes = (hashes, dsFileStats) => { let sum = 0; hashes.forEach((h) => { const s = dsFileStats[h]; - if (typeof(s) !== 'number') { + if (typeof(s) !== 'object' || typeof(s.size) !== 'number') { //console.log('missing ' + h + ' ' + typeof(s)); } else { sum += s.size; @@ -62,11 +62,26 @@ nThen((waitFor) => { }); }); }).nThen((waitFor) => { + + Fs.readdir('./blob', waitFor((err, list) => { + if (err) { throw err; } + dirList = list; + })); +}).nThen((waitFor) => { + dirList.forEach((f) => { + sema.take((returnAfter) => { + Fs.readdir('./blob/' + f, waitFor(returnAfter((err, list2) => { + if (err) { throw err; } + list2.forEach((ff) => { fileList.push('./blob/' + f + '/' + ff); }); + }))); + }); + }); +}).nThen((waitFor) => { fileList.forEach((f) => { sema.take((returnAfter) => { Fs.stat(f, waitFor(returnAfter((err, st) => { if (err) { throw err; } - dsFileStats[f.replace(/^.*\/([^\/]*)\.ndjson$/, (all, a) => (a))] = st; + dsFileStats[f.replace(/^.*\/([^\/\.]*)(\.ndjson)?$/, (all, a) => (a))] = st; }))); }); }); diff --git a/www/common/common-title.js b/www/common/common-title.js index 3b71ec63e..dcdbed055 100644 --- a/www/common/common-title.js +++ b/www/common/common-title.js @@ -1,4 +1,4 @@ -define(function () { +define(['jquery'], function ($) { var module = {}; module.create = function (cfg, onLocal, Cryptpad) { @@ -45,7 +45,8 @@ define(function () { }; // update title: href is optional; if not specified, we use window.location.href - exp.updateTitle = function (newTitle, href) { + exp.updateTitle = function (newTitle, href, cb) { + cb = cb || $.noop; if (newTitle === exp.title) { return; } // Change the title now, and set it back to the old value if there is an error var oldTitle = exp.title; @@ -54,9 +55,10 @@ define(function () { console.log("Couldn't set pad title"); console.error(err); updateLocalTitle(oldTitle); - return; + return void cb(err); } updateLocalTitle(data); + cb(null, data); if (!$title) { return; } $title.find('span.title').text(data); $title.find('input').val(data); diff --git a/www/common/cryptpad-common.js b/www/common/cryptpad-common.js index aefc86a31..901d33079 100644 --- a/www/common/cryptpad-common.js +++ b/www/common/cryptpad-common.js @@ -78,7 +78,7 @@ define([ var deduplicateString = common.deduplicateString = Util.deduplicateString; common.uint8ArrayToHex = Util.uint8ArrayToHex; common.replaceHash = Util.replaceHash; - var getHash = common.getHash = Util.getHash; + common.getHash = Util.getHash; common.fixFileName = Util.fixFileName; common.bytesToMegabytes = Util.bytesToMegabytes; common.bytesToKilobytes = Util.bytesToKilobytes; @@ -426,9 +426,8 @@ define([ // STORAGE common.setPadAttribute = function (attr, value, cb) { - getStore().setDrive([getHash(), attr].join('.'), value, function (err, data) { - cb(err, data); - }); + var href = getRelativeHref(window.location.href); + getStore().setPadAttribute(href, attr, value, cb); }; common.setAttribute = function (attr, value, cb) { getStore().set(["cryptpad", attr].join('.'), value, function (err, data) { @@ -441,9 +440,8 @@ define([ // STORAGE common.getPadAttribute = function (attr, cb) { - getStore().getDrive([getHash(), attr].join('.'), function (err, data) { - cb(err, data); - }); + var href = getRelativeHref(window.location.href); + getStore().getPadAttribute(href, attr, cb); }; common.getAttribute = function (attr, cb) { getStore().get(["cryptpad", attr].join('.'), function (err, data) { diff --git a/www/common/fsStore.js b/www/common/fsStore.js index aa3e69530..b47d3c50e 100644 --- a/www/common/fsStore.js +++ b/www/common/fsStore.js @@ -60,6 +60,9 @@ define([ cb(void 0, res); }; + ret.setPadAttribute = filesOp.setAttribute; + ret.getPadAttribute = filesOp.getAttribute; + ret.getDrive = function (key, cb) { cb(void 0, storeObj.drive[key]); }; diff --git a/www/common/userObject.js b/www/common/userObject.js index b21fb739a..7a0dba83c 100644 --- a/www/common/userObject.js +++ b/www/common/userObject.js @@ -132,6 +132,21 @@ define([ if (type === 'name') { return data.filename; } return data.filename || data.title || NEW_FILE_NAME; }; + exp.getAttribute = function (href, attr, cb) { + cb = cb || $.noop; + var id = exp.getIdFromHref(href); + if (!id) { return void cb(null, undefined); } + var data = getFileData(id); + cb(null, data[attr]); + }; + exp.setAttribute = function (href, attr, value, cb) { + cb = cb || $.noop; + var id = exp.getIdFromHref(href); + if (!id) { return void cb("E_INVAL_HREF"); } + if (!attr || !attr.trim()) { return void cb("E_INVAL_ATTR"); } + var data = getFileData(id); + data[attr] = value; + }; // PATHS @@ -970,6 +985,20 @@ define([ us.splice(idx, 1); }); }; + var migrateAttributes = function (el, id, parsed) { + // Migrate old pad attributes + ['userid', 'previewMode'].forEach(function (attr) { + var key = parsed.hash + '.' + attr; + var key2 = parsed.hash.slice(0,-1) + '.' + attr;// old pads not ending with / + if (files[key] || files[key2]) { + debug("Migrating pad attribute", attr, "for pad", id); + el[attr] = files[key] || files[key2]; + } + delete files[key]; + delete files[key2]; + }); + // Migration done + }; var fixFilesData = function () { if (typeof files[FILES_DATA] !== "object") { debug("OLD_FILES_DATA was not an object"); files[FILES_DATA] = {}; } var fd = files[FILES_DATA]; @@ -989,6 +1018,15 @@ define([ toClean.push(id); continue; } + var parsed = Cryptpad.parsePadUrl(el.href); + if (!parsed.hash) { + debug("Removing an element in filesData with a invalid href.", el); + toClean.push(id); + continue; + } + + migrateAttributes(el, id, parsed); + if ((Cryptpad.isLoggedIn() || config.testMode) && rootFiles.indexOf(id) === -1) { debug("An element in filesData was not in ROOT, TEMPLATE or TRASH.", id, el); var newName = Cryptpad.createChannelId(); @@ -1001,12 +1039,19 @@ define([ }); }; + var fixDrive = function () { + Object.keys(files).forEach(function (key) { + if (key.slice(0,1) === '/') { delete files[key]; } + }); + }; + fixRoot(); fixTrashRoot(); if (!workgroup) { fixTemplate(); fixFilesData(); } + fixDrive(); if (JSON.stringify(files) !== before) { debug("Your file system was corrupted. It has been cleaned so that the pads you visit can be stored safely"); diff --git a/www/drive/tests.js b/www/drive/tests.js index ddc3b0fb7..5861e5410 100644 --- a/www/drive/tests.js +++ b/www/drive/tests.js @@ -242,6 +242,18 @@ define([ fo.migrate(todo); }, "DRIVE4: migration and fixFiles with a pad in trash not root"); + // Pad attributes migration + assert(function (cb) { + console.log('START PAD ATTRIBUTES'); + var files = JSON.parse(JSON.stringify(example)); + files[href1.slice(6) + '.userid'] = 'value'; + files[href1.slice(6) + '.previewMode'] = true; + var fo = FO.init(files, config); + fo.fixFiles(); + return cb(files.filesData[id1].userid === 'value' + && files.filesData[id1].previewMode); + }, "PAD ATTRIBUTES"); + // userObject Tests // UTILS diff --git a/www/poll/main.js b/www/poll/main.js index b8085f56a..ecb308a36 100644 --- a/www/poll/main.js +++ b/www/poll/main.js @@ -552,11 +552,19 @@ var ready = function (info, userid, readOnly) { } else { APP.proxy.info.defaultTitle = Title.defaultTitle; } + + var andThen = function () { + if (readOnly) { return; } + Cryptpad.setPadAttribute('userid', userid, function (e) { + if (e) { console.error(e); } + }); + }; + if (Cryptpad.initialName && !APP.proxy.info.title) { APP.proxy.info.title = Cryptpad.initialName; - Title.updateTitle(Cryptpad.initialName); + Title.updateTitle(Cryptpad.initialName, null, andThen); } else { - Title.updateTitle(APP.proxy.info.title || Title.defaultTitle); + Title.updateTitle(APP.proxy.info.title || Title.defaultTitle, null, andThen); } // Description @@ -621,6 +629,7 @@ var ready = function (info, userid, readOnly) { } else { publish(true); } + Cryptpad.removeLoadingScreen(); if (readOnly) { return; } @@ -760,10 +769,7 @@ var create = function (info) { if (e) { console.error(e); } if (!userid) { userid = Render.coluid(); } APP.userid = userid; - Cryptpad.setPadAttribute('userid', userid, function (e) { - if (e) { console.error(e); } - ready(info, userid, readOnly); - }); + ready(info, userid, readOnly); }); }) .on('disconnect', disconnect)