diff --git a/www/common/application_config_internal.js b/www/common/application_config_internal.js index ab573ae70..2bf546054 100644 --- a/www/common/application_config_internal.js +++ b/www/common/application_config_internal.js @@ -12,7 +12,7 @@ define(function() { * You should never remove the drive from this list. */ config.availablePadTypes = ['drive', 'teams', 'pad', 'sheet', 'code', 'slide', 'poll', 'kanban', 'whiteboard', - /*'oodoc', 'ooslide',*/ 'file', 'todo', 'contacts']; + /*'oodoc', 'ooslide',*/ 'file', /*'todo',*/ 'contacts']; /* The registered only types are apps restricted to registered users. * You should never remove apps from this list unless you know what you're doing. The apps * listed here by default can't work without a user account. diff --git a/www/common/migrate-user-object.js b/www/common/migrate-user-object.js index ff56065a8..15b790531 100644 --- a/www/common/migrate-user-object.js +++ b/www/common/migrate-user-object.js @@ -4,10 +4,12 @@ define([ '/common/common-hash.js', '/common/common-util.js', '/common/common-messaging.js', + '/common/cryptget.js', '/common/outer/mailbox.js', + '/customize/messages.js', '/bower_components/nthen/index.js', '/bower_components/chainpad-crypto/crypto.js', -], function (AppConfig, Feedback, Hash, Util, Messaging, Mailbox, nThen, Crypto) { +], function (AppConfig, Feedback, Hash, Util, Messaging, Crypt, Mailbox, Messages, nThen, Crypto) { // Start migration check // Versions: // 1: migrate pad attributes @@ -320,6 +322,140 @@ define([ Feedback.send('Migrate-9', true); userObject.version = version = 9; } + }).nThen(function (waitFor) { + // Migration 10: deprecate todo + var fixTodo = function () { + var h = store.proxy.todo; + if (!h) { return; } + var next = waitFor(function () { + Feedback.send('Migrate-10', true); + userObject.version = version = 10; // XXX + }); + var old; + var opts = { + network: store.network, + initialState: '{}', + metadata: { + owners: store.proxy.edPublic ? [store.proxy.edPublic] : [] + } + }; + nThen(function (w) { + Crypt.get(h, w(function (err, val) { + if (err || !val) { + w.abort(); + next(); + return; + } + try { + old = JSON.parse(val); + } catch (e) {} // We will abort in the next step in case of error + }), opts); + }).nThen(function (w) { + if (!old || typeof(old) !== "object") { + w.abort(); + next(); + return; + } + var k = { + content: { + data: { + "1": { + id: "1", + color: 'color6', + item: [], + title: Messages.kanban_todo + }, + "2": { + id: "2", + color: 'color3', + item: [], + title: Messages.kanban_working + }, + "3": { + id: "3", + color: 'color5', + item: [], + title: Messages.kanban_done + }, + }, + items: {}, + list: [1, 2, 3] + }, + metadata: { + title: Messages.type.todo, + defaultTitle: Messages.type.todo, + type: "kanban" + } + }; + var i = 4; + var items = false; + (old.order || []).forEach(function (key) { + var data = old.data[key]; + if (!data || !data.task) { return; } + items = true; + var column = data.state ? '3' : '1'; + k.content.data[column].item.push(i); + k.content.items[i] = { + id: i, + title: data.task + }; + i++; + }); + if (!items) { + w.abort(); + next(); + return; + } + var newH = Hash.createRandomHash('kanban'); + var secret = Hash.getSecrets('kanban', newH); + var oldSecret = Hash.getSecrets('todo', h); + Crypt.put(newH, JSON.stringify(k), w(function (err) { + if (err) { + w.abort(); + next(); + return; + } + if (store.rpc) { + store.rpc.pin([secret.channel], function () { + // Try to pin and ignore errors... + // Todo won't be available anyway so keep your unpinned kanban + }); + store.rpc.unpin([oldSecret.channel], function () { + // Try to unpin and ignore errors... + }); + } + var href = Hash.hashToHref(newH, 'kanban'); + store.manager.addPad(['root'], { + title: Messages.type.todo, + owners: opts.metadata.owners, + channel: secret.channel, + href: href, + roHref: Hash.hashToHref(Hash.getViewHashFromKeys(secret), 'kanban'), + atime: +new Date(), + ctime: +new Date() + }, w(function (e) { + if (e) { return void console.error(e); } + delete store.proxy.todo; + var myData = Messaging.createData(userObject); + var ctx = { store: store }; + Mailbox.sendTo(ctx, 'MOVE_TODO', { + user: myData, + href: href, + }, { + channel: myData.notifications, + curvePublic: myData.curvePublic + }, function (obj) { + if (obj && obj.error) { return void console.error(obj); } + }); + })); + }), opts); + }).nThen(function () { + next(); + }); + }; + if (version < 10) { + fixTodo(); + } /*}).nThen(function (waitFor) { // Test progress bar in the loading screen var i = 0; diff --git a/www/common/notifications.js b/www/common/notifications.js index 44cdb9dfd..5b7767e86 100644 --- a/www/common/notifications.js +++ b/www/common/notifications.js @@ -365,6 +365,29 @@ define([ } }; + Messages.todo_move = "Your todo list has been moved to the pad {0}, as the Todo app is now deprecated."; + handlers['MOVE_TODO'] = function(common, data) { + var content = data.content; + var msg = content.msg; + + // Display the notification + var title = Util.fixHTML(Messages.type.todo); + var href = msg.content.href; + + content.getFormatText = function() { + return Messages._getKey('todo_move', [title]); + }; + if (href) { + content.handler = function() { + common.openURL(href); + defaultDismiss(common, data)(); + }; + } + if (!content.archived) { + content.dismissHandler = defaultDismiss(common, data); + } + }; + // NOTE: don't forget to fixHTML everything returned by "getFormatText" @@ -387,4 +410,4 @@ define([ }, allowed: Object.keys(handlers) }; -}); \ No newline at end of file +}); diff --git a/www/common/outer/mailbox-handlers.js b/www/common/outer/mailbox-handlers.js index 7677614ec..a55a2d63d 100644 --- a/www/common/outer/mailbox-handlers.js +++ b/www/common/outer/mailbox-handlers.js @@ -508,6 +508,12 @@ define([ cb(true); }; + // Make sure "todo migration" notifications are from yourself + handlers['MOVE_TODO'] = function (ctx, box, data, cb) { + var curve = ctx.store.proxy.curvePublic; + if (data.msg.author !== curve) { return void cb(true); } + cb(); + }; // Hide duplicates when receiving a SHARE_PAD notification: // Keep only one notification per channel: the stronger and more recent one diff --git a/www/todo/main.js b/www/todo/main.js index 7cd69223e..13f704de5 100644 --- a/www/todo/main.js +++ b/www/todo/main.js @@ -7,6 +7,7 @@ define([ '/common/sframe-common-outer.js' ], function (nThen, ApiConfig, DomReady, RequireConfig, SFCommonO) { var requireConfig = RequireConfig(); + window.location.href = '/drive/'; // Loaded in load #2 nThen(function (waitFor) {