Import board: import comments and log activities

This commit is contained in:
Xavier Priour 2015-10-19 00:59:50 +02:00
parent 469d47cd9f
commit 4540bd36c4
5 changed files with 179 additions and 93 deletions

View file

@ -14,56 +14,62 @@ template(name="boardActivities")
p.activity-desc p.activity-desc
+memberName(user=user) +memberName(user=user)
if($eq activityType 'createBoard') if($eq activityType 'addAttachment')
| {{_ 'activity-created' boardLabel}}. | {{{_ 'activity-attached' attachmentLink cardLink}}}.
if($eq activityType 'createList')
| {{_ 'activity-added' list.title boardLabel}}.
if($eq activityType 'archivedList')
| {{_ 'activity-archived' list.title}}.
if($eq activityType 'createCard')
| {{{_ 'activity-added' cardLink boardLabel}}}.
if($eq activityType 'importCard')
| {{{_ 'activity-imported' cardLink boardLabel sourceLink}}}.
if($eq activityType 'archivedCard')
| {{{_ 'activity-archived' cardLink}}}.
if($eq activityType 'restoredCard')
| {{{_ 'activity-sent' cardLink boardLabel}}}.
if($eq activityType 'moveCard')
| {{{_ 'activity-moved' cardLink oldList.title list.title}}}.
if($eq activityType 'addBoardMember') if($eq activityType 'addBoardMember')
| {{{_ 'activity-added' memberLink boardLabel}}}. | {{{_ 'activity-added' memberLink boardLabel}}}.
if($eq activityType 'removeBoardMember')
| {{{_ 'activity-excluded' memberLink boardLabel}}}.
if($eq activityType 'joinMember')
if($eq currentUser._id member._id)
| {{{_ 'activity-joined' cardLink}}}.
else
| {{{_ 'activity-added' memberLink cardLink}}}.
if($eq activityType 'unjoinMember')
if($eq currentUser._id member._id)
| {{{_ 'activity-unjoined' cardLink}}}.
else
| {{{_ 'activity-removed' memberLink cardLink}}}.
if($eq activityType 'addComment') if($eq activityType 'addComment')
| {{{_ 'activity-on' cardLink}}} | {{{_ 'activity-on' cardLink}}}
a.activity-comment(href="{{ card.absoluteUrl }}") a.activity-comment(href="{{ card.absoluteUrl }}")
+viewer +viewer
= comment.text = comment.text
if($eq activityType 'addAttachment') if($eq activityType 'archivedCard')
| {{{_ 'activity-attached' attachmentLink cardLink}}}. | {{{_ 'activity-archived' cardLink}}}.
if($eq activityType 'archivedList')
| {{_ 'activity-archived' list.title}}.
if($eq activityType 'createBoard')
| {{_ 'activity-created' boardLabel}}.
if($eq activityType 'createCard')
| {{{_ 'activity-added' cardLink boardLabel}}}.
if($eq activityType 'createList')
| {{_ 'activity-added' list.title boardLabel}}.
if($eq activityType 'importBoard')
| {{{_ 'activity-imported-board' boardLabel sourceLink}}}.
if($eq activityType 'importCard')
| {{{_ 'activity-imported' cardLink boardLabel sourceLink}}}.
if($eq activityType 'importList')
| {{{_ 'activity-imported' listLabel boardLabel sourceLink}}}.
if($eq activityType 'joinMember')
if($eq currentUser._id member._id)
| {{{_ 'activity-joined' cardLink}}}.
else
| {{{_ 'activity-added' memberLink cardLink}}}.
if($eq activityType 'moveCard')
| {{{_ 'activity-moved' cardLink oldList.title list.title}}}.
if($eq activityType 'removeBoardMember')
| {{{_ 'activity-excluded' memberLink boardLabel}}}.
if($eq activityType 'restoredCard')
| {{{_ 'activity-sent' cardLink boardLabel}}}.
if($eq activityType 'unjoinMember')
if($eq currentUser._id member._id)
| {{{_ 'activity-unjoined' cardLink}}}.
else
| {{{_ 'activity-removed' memberLink cardLink}}}.
span.activity-meta {{ moment createdAt }} span.activity-meta {{ moment createdAt }}

View file

@ -60,11 +60,22 @@ BlazeComponent.extendComponent({
}, card.title)); }, card.title));
}, },
listLabel() {
return this.currentData().list().title;
},
sourceLink() { sourceLink() {
const source = this.currentData().source; const source = this.currentData().source;
return source && Blaze.toHTML(HTML.A({ if(source) {
href: source.url, if(source.url) {
}, source.system)); return Blaze.toHTML(HTML.A({
href: source.url,
}, source.system));
} else {
return source.system;
}
}
return null;
}, },
memberLink() { memberLink() {

View file

@ -46,7 +46,7 @@ const ImportPopup = BlazeComponent.extendComponent({
onFinish() { onFinish() {
Popup.close(); Popup.close();
} },
}); });
ImportPopup.extendComponent({ ImportPopup.extendComponent({

View file

@ -8,6 +8,7 @@
"activity-created": "created %s", "activity-created": "created %s",
"activity-excluded": "excluded %s from %s", "activity-excluded": "excluded %s from %s",
"activity-imported": "imported %s into %s from %s", "activity-imported": "imported %s into %s from %s",
"activity-imported-board": "imported %s from %s",
"activity-joined": "joined %s", "activity-joined": "joined %s",
"activity-moved": "moved %s from %s to %s", "activity-moved": "moved %s from %s to %s",
"activity-on": "on %s", "activity-on": "on %s",

View file

@ -10,12 +10,14 @@ class TrelloCreator {
this.labels = {}; this.labels = {};
// the lists we created, indexed by Trello id (to map when importing cards) // the lists we created, indexed by Trello id (to map when importing cards)
this.lists = {}; this.lists = {};
// the comments, indexed by Trello card id (to map when importing cards)
this.comments = {};
} }
/** /**
* must call parseActions before calling this one * must call parseActions before calling this one
*/ */
createBoardAndLabels(trelloBoard, dateOfImport) { createBoardAndLabels(trelloBoard) {
const createdAt = this.createdAt.board; const createdAt = this.createdAt.board;
const boardToCreate = { const boardToCreate = {
archived: trelloBoard.closed, archived: trelloBoard.closed,
@ -35,7 +37,7 @@ class TrelloCreator {
title: trelloBoard.name, title: trelloBoard.name,
}; };
trelloBoard.labels.forEach((label) => { trelloBoard.labels.forEach((label) => {
labelToCreate = { const labelToCreate = {
_id: Random.id(6), _id: Random.id(6),
color: label.color, color: label.color,
name: label.name, name: label.name,
@ -45,11 +47,23 @@ class TrelloCreator {
boardToCreate.labels.push(labelToCreate); boardToCreate.labels.push(labelToCreate);
}); });
const boardId = Boards.direct.insert(boardToCreate); const boardId = Boards.direct.insert(boardToCreate);
// XXX add activities // log activity
Activities.direct.insert({
activityType: 'importBoard',
boardId,
createdAt: new Date(),
source: {
id: trelloBoard.id,
system: 'Trello',
url: trelloBoard.url,
},
// we attribute the import to current user, not the one from the original object
userId: Meteor.userId(),
});
return boardId; return boardId;
} }
createLists(trelloLists, boardId, dateOfImport) { createLists(trelloLists, boardId) {
trelloLists.forEach((list) => { trelloLists.forEach((list) => {
const listToCreate = { const listToCreate = {
archived: list.closed, archived: list.closed,
@ -60,17 +74,29 @@ class TrelloCreator {
}; };
listToCreate._id = Lists.direct.insert(listToCreate); listToCreate._id = Lists.direct.insert(listToCreate);
this.lists[list.id] = listToCreate; this.lists[list.id] = listToCreate;
// XXX add activities // log activity
Activities.direct.insert({
activityType: 'importList',
boardId,
createdAt: new Date(),
listId: listToCreate._id,
source: {
id: list.id,
system: 'Trello',
},
// we attribute the import to current user, not the one from the original object
userId: Meteor.userId(),
});
}); });
} }
createCards(trelloCards, boardId, dateOfImport) { createCardsAndComments(trelloCards, boardId) {
trelloCards.forEach((card) => { trelloCards.forEach((card) => {
const cardToCreate = { const cardToCreate = {
archived: card.closed, archived: card.closed,
boardId, boardId,
createdAt: this.createdAt.cards[card.id], createdAt: this.createdAt.cards[card.id],
dateLastActivity: dateOfImport, dateLastActivity: new Date(),
description: card.desc, description: card.desc,
listId: this.lists[card.idList]._id, listId: this.lists[card.idList]._id,
sort: card.pos, sort: card.pos,
@ -84,37 +110,102 @@ class TrelloCreator {
return this.labels[trelloId]._id; return this.labels[trelloId]._id;
}); });
} }
Cards.direct.insert(cardToCreate); // insert card
// XXX add comments const cardId = Cards.direct.insert(cardToCreate);
// log activity
Activities.direct.insert({
activityType: 'importCard',
boardId,
cardId,
createdAt: new Date(),
listId: cardToCreate.listId,
source: {
id: card.id,
system: 'Trello',
url: card.url,
},
// we attribute the import to current user, not the one from the original card
userId: Meteor.userId(),
});
// add comments
const comments = this.comments[card.id];
if(comments) {
comments.forEach((comment) => {
const commentToCreate = {
boardId,
cardId,
createdAt: comment.date,
text: comment.data.text,
// XXX use the original comment user instead
userId: Meteor.userId(),
};
const commentId = CardComments.direct.insert(commentToCreate);
Activities.direct.insert({
activityType: 'addComment',
boardId: commentToCreate.boardId,
cardId: commentToCreate.cardId,
commentId,
createdAt: commentToCreate.createdAt,
userId: commentToCreate.userId,
});
});
}
// XXX add attachments // XXX add attachments
// XXX add activities
}); });
} }
parseActions(trelloActions) { parseActions(trelloActions) {
trelloActions.forEach((action) =>{ trelloActions.forEach((action) => {
switch (action.type) { switch (action.type) {
case 'createBoard': case 'createBoard':
this.createdAt.board = action.date; this.createdAt.board = action.date;
break; break;
case 'createCard': case 'createCard':
const cardId = action.data.card.id; const cardId = action.data.card.id;
this.createdAt.cards[cardId] = action.date; this.createdAt.cards[cardId] = action.date;
break; break;
case 'createList': case 'createList':
const listId = action.data.list.id; const listId = action.data.list.id;
this.createdAt.lists[listId] = action.date; this.createdAt.lists[listId] = action.date;
break; break;
// XXX extract comments as well case 'commentCard':
default: const id = action.data.card.id;
// do nothing if(this.comments[id]) {
break; this.comments[id].push(action);
} else {
this.comments[id] = [action];
}
break;
default:
// do nothing
break;
} }
}); });
} }
} }
Meteor.methods({ Meteor.methods({
importTrelloBoard(trelloBoard, data) {
const trelloCreator = new TrelloCreator();
// 1. check parameters are ok from a syntax point of view
try {
// XXX do proper checking
check(trelloBoard, Object);
check(data, Object);
} catch(e) {
throw new Meteor.Error('error-json-schema');
}
// 2. check parameters are ok from a business point of view (exist & authorized)
// XXX check we are allowed
// 3. create all elements
trelloCreator.parseActions(trelloBoard.actions);
const boardId = trelloCreator.createBoardAndLabels(trelloBoard);
trelloCreator.createLists(trelloBoard.lists, boardId);
trelloCreator.createCardsAndComments(trelloBoard.cards, boardId);
// XXX set modifiedAt or lastActivity
// XXX add members
return boardId;
},
importTrelloCard(trelloCard, data) { importTrelloCard(trelloCard, data) {
// 1. check parameters are ok from a syntax point of view // 1. check parameters are ok from a syntax point of view
const DateString = Match.Where(function (dateAsString) { const DateString = Match.Where(function (dateAsString) {
@ -245,27 +336,4 @@ Meteor.methods({
}); });
return cardId; return cardId;
}, },
importTrelloBoard(trelloBoard, data) {
const trelloCreator = new TrelloCreator();
// 1. check parameters are ok from a syntax point of view
try {
// XXX do proper checking
check(trelloBoard, Object);
check(data, Object);
} catch(e) {
throw new Meteor.Error('error-json-schema');
}
// 2. check parameters are ok from a business point of view (exist & authorized)
// XXX check we are allowed
// 3. create all elements
const dateOfImport = new Date();
trelloCreator.parseActions(trelloBoard.actions);
const boardId = trelloCreator.createBoardAndLabels(trelloBoard, dateOfImport);
trelloCreator.createLists(trelloBoard.lists, boardId, dateOfImport);
trelloCreator.createCards(trelloBoard.cards, boardId, dateOfImport);
// XXX add activities
// XXX set modifiedAt or lastActivity
// XXX add members
return boardId;
},
}); });