From 82c59fb85f5f44928a506da59087809640d99050 Mon Sep 17 00:00:00 2001 From: Xavier Priour Date: Wed, 2 Dec 2015 09:51:27 +0100 Subject: Fix #417: exception when importing older boards (missing creationDate) --- models/import.js | 49 +++++++++++++++++++++++++++++++++++-------------- 1 file changed, 35 insertions(+), 14 deletions(-) (limited to 'models') diff --git a/models/import.js b/models/import.js index 33f56d4b..40df2dd9 100644 --- a/models/import.js +++ b/models/import.js @@ -5,6 +5,9 @@ const DateString = Match.Where(function (dateAsString) { class TrelloCreator { constructor(data) { + // we log current date, to use the same timestamp for all our actions. + // this helps to retrieve all elements performed by the same import. + this._now = new Date(); // The object creation dates, indexed by Trello id (so we only parse actions // once!) this.createdAt = { @@ -25,6 +28,25 @@ class TrelloCreator { this.attachments = {}; } + /** + * If dateString is provided, + * return the Date it represents. + * If not, will return the date when it was first called. + * This is useful for us, as we want all import operations to + * have the exact same date for easier later retrieval. + * + * @param {String} dateString a properly formatted Date + */ + now(dateString) { + if(dateString) { + return new Date(dateString); + } + if(!this._now) { + this._now = new Date(); + } + return this._now; + } + checkActions(trelloActions) { check(trelloActions, [Match.ObjectIncluding({ data: Object, @@ -79,11 +101,11 @@ class TrelloCreator { // You must call parseActions before calling this one. createBoardAndLabels(trelloBoard) { - const createdAt = this.createdAt.board; const boardToCreate = { archived: trelloBoard.closed, color: this.getColor(trelloBoard.prefs.background), - createdAt, + // very old boards won't have a creation activity so no creation date + createdAt: this.now(this.createdAt.board), labels: [], members: [{ userId: Meteor.userId(), @@ -124,14 +146,13 @@ class TrelloCreator { this.labels[label.id] = labelToCreate._id; boardToCreate.labels.push(labelToCreate); }); - const now = new Date(); const boardId = Boards.direct.insert(boardToCreate); - Boards.direct.update(boardId, {$set: {modifiedAt: now}}); + Boards.direct.update(boardId, {$set: {modifiedAt: this.now()}}); // log activity Activities.direct.insert({ activityType: 'importBoard', boardId, - createdAt: now, + createdAt: this.now(), source: { id: trelloBoard.id, system: 'Trello', @@ -157,8 +178,9 @@ class TrelloCreator { const cardToCreate = { archived: card.closed, boardId, - createdAt: new Date(this.createdAt.cards[card.id] || Date.now()), - dateLastActivity: new Date(), + // very old boards won't have a creation activity so no creation date + createdAt: this.now(this.createdAt.cards[card.id]), + dateLastActivity: this.now(), description: card.desc, listId: this.lists[card.idList], sort: card.pos, @@ -198,7 +220,7 @@ class TrelloCreator { activityType: 'importCard', boardId, cardId, - createdAt: new Date(), + createdAt: this.now(), listId: cardToCreate.listId, source: { id: card.id, @@ -216,7 +238,7 @@ class TrelloCreator { const commentToCreate = { boardId, cardId, - createdAt: comment.date, + createdAt: this.now(comment.date), text: comment.data.text, // XXX use the original comment user instead userId: Meteor.userId(), @@ -229,7 +251,7 @@ class TrelloCreator { boardId: commentToCreate.boardId, cardId: commentToCreate.cardId, commentId, - createdAt: commentToCreate.createdAt, + createdAt: this.now(commentToCreate.createdAt), userId: commentToCreate.userId, }); }); @@ -292,19 +314,18 @@ class TrelloCreator { // creation date wasn't found on the action log. This happen on old // Trello boards (eg from 2013) that didn't log the 'createList' action // we require. - createdAt: new Date(this.createdAt.lists[list.id] || Date.now()), + createdAt: this.now(this.createdAt.lists[list.id]), title: list.name, userId: Meteor.userId(), }; const listId = Lists.direct.insert(listToCreate); - const now = new Date(); - Lists.direct.update(listId, {$set: {'updatedAt': now}}); + Lists.direct.update(listId, {$set: {'updatedAt': this.now()}}); this.lists[list.id] = listId; // log activity Activities.direct.insert({ activityType: 'importList', boardId, - createdAt: now, + createdAt: this.now(), listId, source: { id: list.id, -- cgit v1.2.3-1-g7c22 From 2057764801a8644c5280efe5faf92ef15ba2735b Mon Sep 17 00:00:00 2001 From: Xavier Priour Date: Wed, 2 Dec 2015 11:28:32 +0100 Subject: Import trello: map comment author --- models/import.js | 50 ++++++++++++++++++++++++++++++++------------------ 1 file changed, 32 insertions(+), 18 deletions(-) (limited to 'models') diff --git a/models/import.js b/models/import.js index 40df2dd9..21c47cad 100644 --- a/models/import.js +++ b/models/import.js @@ -7,7 +7,7 @@ class TrelloCreator { constructor(data) { // we log current date, to use the same timestamp for all our actions. // this helps to retrieve all elements performed by the same import. - this._now = new Date(); + this._nowDate = new Date(); // The object creation dates, indexed by Trello id (so we only parse actions // once!) this.createdAt = { @@ -37,14 +37,28 @@ class TrelloCreator { * * @param {String} dateString a properly formatted Date */ - now(dateString) { + _now(dateString) { if(dateString) { return new Date(dateString); } - if(!this._now) { - this._now = new Date(); + if(!this._nowDate) { + this._nowDate = new Date(); } - return this._now; + return this._nowDate; + } + + /** + * if trelloUserId is provided and we have a mapping, + * return it. + * Otherwise return current logged user. + * @param trelloUserId + * @private + */ + _user(trelloUserId) { + if(trelloUserId && this.members[trelloUserId]) { + return this.members[trelloUserId]; + } + return Meteor.userId(); } checkActions(trelloActions) { @@ -105,7 +119,7 @@ class TrelloCreator { archived: trelloBoard.closed, color: this.getColor(trelloBoard.prefs.background), // very old boards won't have a creation activity so no creation date - createdAt: this.now(this.createdAt.board), + createdAt: this._now(this.createdAt.board), labels: [], members: [{ userId: Meteor.userId(), @@ -147,12 +161,12 @@ class TrelloCreator { boardToCreate.labels.push(labelToCreate); }); const boardId = Boards.direct.insert(boardToCreate); - Boards.direct.update(boardId, {$set: {modifiedAt: this.now()}}); + Boards.direct.update(boardId, {$set: {modifiedAt: this._now()}}); // log activity Activities.direct.insert({ activityType: 'importBoard', boardId, - createdAt: this.now(), + createdAt: this._now(), source: { id: trelloBoard.id, system: 'Trello', @@ -179,8 +193,8 @@ class TrelloCreator { archived: card.closed, boardId, // very old boards won't have a creation activity so no creation date - createdAt: this.now(this.createdAt.cards[card.id]), - dateLastActivity: this.now(), + createdAt: this._now(this.createdAt.cards[card.id]), + dateLastActivity: this._now(), description: card.desc, listId: this.lists[card.idList], sort: card.pos, @@ -220,7 +234,7 @@ class TrelloCreator { activityType: 'importCard', boardId, cardId, - createdAt: this.now(), + createdAt: this._now(), listId: cardToCreate.listId, source: { id: card.id, @@ -238,10 +252,10 @@ class TrelloCreator { const commentToCreate = { boardId, cardId, - createdAt: this.now(comment.date), + createdAt: this._now(comment.date), text: comment.data.text, - // XXX use the original comment user instead - userId: Meteor.userId(), + // map comment author, default to current user + userId: this._user(comment.memberCreator.id), }; // dateLastActivity will be set from activity insert, no need to // update it ourselves @@ -251,7 +265,7 @@ class TrelloCreator { boardId: commentToCreate.boardId, cardId: commentToCreate.cardId, commentId, - createdAt: this.now(commentToCreate.createdAt), + createdAt: this._now(commentToCreate.createdAt), userId: commentToCreate.userId, }); }); @@ -314,18 +328,18 @@ class TrelloCreator { // creation date wasn't found on the action log. This happen on old // Trello boards (eg from 2013) that didn't log the 'createList' action // we require. - createdAt: this.now(this.createdAt.lists[list.id]), + createdAt: this._now(this.createdAt.lists[list.id]), title: list.name, userId: Meteor.userId(), }; const listId = Lists.direct.insert(listToCreate); - Lists.direct.update(listId, {$set: {'updatedAt': this.now()}}); + Lists.direct.update(listId, {$set: {'updatedAt': this._now()}}); this.lists[list.id] = listId; // log activity Activities.direct.insert({ activityType: 'importList', boardId, - createdAt: this.now(), + createdAt: this._now(), listId, source: { id: list.id, -- cgit v1.2.3-1-g7c22 From f639bada5c4d068b0db51f893ecb8218c73a6564 Mon Sep 17 00:00:00 2001 From: Xavier Priour Date: Wed, 2 Dec 2015 12:37:51 +0100 Subject: Import trello: map card author and board admins --- models/import.js | 54 +++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 37 insertions(+), 17 deletions(-) (limited to 'models') diff --git a/models/import.js b/models/import.js index 21c47cad..101ba067 100644 --- a/models/import.js +++ b/models/import.js @@ -8,13 +8,19 @@ class TrelloCreator { // we log current date, to use the same timestamp for all our actions. // this helps to retrieve all elements performed by the same import. this._nowDate = new Date(); - // The object creation dates, indexed by Trello id (so we only parse actions - // once!) + // The object creation dates, indexed by Trello id + // (so we only parse actions once!) this.createdAt = { board: null, cards: {}, lists: {}, }; + // The object creator Trello Id, indexed by the object Trello id + // (so we only parse actions once!) + this.createdBy = { + cards: {}, // only cards have a field for that + }; + // Map of labels Trello ID => Wekan ID this.labels = {}; // Map of lists Trello ID => Wekan ID @@ -139,10 +145,16 @@ class TrelloCreator { if(this.members[trelloId]) { const wekanId = this.members[trelloId]; // do we already have it in our list? - if(!boardToCreate.members.find((wekanMember) => wekanMember.userId === wekanId)) { + const wekanMember = boardToCreate.members.find((wekanMember) => wekanMember.userId === wekanId); + if(wekanMember) { + // we're already mapped, but maybe with lower rights + if(!wekanMember.isAdmin) { + wekanMember.isAdmin = this.getAdmin(trelloMembership.memberType); + } + } else { boardToCreate.members.push({ userId: wekanId, - isAdmin: false, + isAdmin: this.getAdmin(trelloMembership.memberType), isActive: true, }); } @@ -172,9 +184,9 @@ class TrelloCreator { system: 'Trello', url: trelloBoard.url, }, - // We attribute the import to current user, not the one from the original - // object. - userId: Meteor.userId(), + // We attribute the import to current user, + // not the author from the original object. + userId: this._user(), }); return boardId; } @@ -199,8 +211,8 @@ class TrelloCreator { listId: this.lists[card.idList], sort: card.pos, title: card.name, - // XXX use the original user? - userId: Meteor.userId(), + // we attribute the card to its creator if available + userId: this._user(this.createdBy.cards[card.id]), }; // add labels if (card.idLabels) { @@ -241,9 +253,9 @@ class TrelloCreator { system: 'Trello', url: card.url, }, - // we attribute the import to current user, not the one from the - // original card - userId: Meteor.userId(), + // we attribute the import to current user, + // not the author of the original card + userId: this._user(), }); // add comments const comments = this.comments[card.id]; @@ -254,7 +266,7 @@ class TrelloCreator { cardId, createdAt: this._now(comment.date), text: comment.data.text, - // map comment author, default to current user + // we attribute the comment to the original author, default to current user userId: this._user(comment.memberCreator.id), }; // dateLastActivity will be set from activity insert, no need to @@ -266,6 +278,8 @@ class TrelloCreator { cardId: commentToCreate.cardId, commentId, createdAt: this._now(commentToCreate.createdAt), + // we attribute the addComment (not the import) + // to the original author - it is needed by some UI elements. userId: commentToCreate.userId, }); }); @@ -330,7 +344,6 @@ class TrelloCreator { // we require. createdAt: this._now(this.createdAt.lists[list.id]), title: list.name, - userId: Meteor.userId(), }; const listId = Lists.direct.insert(listToCreate); Lists.direct.update(listId, {$set: {'updatedAt': this._now()}}); @@ -345,13 +358,19 @@ class TrelloCreator { id: list.id, system: 'Trello', }, - // We attribute the import to current user, not the one from the - // original object - userId: Meteor.userId(), + // We attribute the import to current user, + // not the creator of the original object + userId: this._user(), }); }); } + getAdmin(trelloMemberType) { + if (trelloMemberType === 'admin') { + return true; + } + return false; + } getColor(trelloColorCode) { // trello color name => wekan color @@ -411,6 +430,7 @@ class TrelloCreator { case 'createCard': const cardId = action.data.card.id; this.createdAt.cards[cardId] = action.date; + this.createdBy.cards[cardId] = action.idMemberCreator; break; case 'createList': const listId = action.data.list.id; -- cgit v1.2.3-1-g7c22 From 32698bcc9868e3d2b9708a43ea0ecca024c08ad2 Mon Sep 17 00:00:00 2001 From: Xavier Priour Date: Wed, 2 Dec 2015 20:37:12 +0100 Subject: Fix code style --- models/import.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'models') diff --git a/models/import.js b/models/import.js index 101ba067..4be1273c 100644 --- a/models/import.js +++ b/models/import.js @@ -366,10 +366,7 @@ class TrelloCreator { } getAdmin(trelloMemberType) { - if (trelloMemberType === 'admin') { - return true; - } - return false; + return trelloMemberType === 'admin'; } getColor(trelloColorCode) { -- cgit v1.2.3-1-g7c22