mirror of
https://github.com/wekan/wekan.git
synced 2025-12-16 15:30:13 +01:00
Import board: import comments and log activities
This commit is contained in:
parent
469d47cd9f
commit
4540bd36c4
5 changed files with 179 additions and 93 deletions
|
|
@ -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 }}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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() {
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,7 @@ const ImportPopup = BlazeComponent.extendComponent({
|
||||||
|
|
||||||
onFinish() {
|
onFinish() {
|
||||||
Popup.close();
|
Popup.close();
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
ImportPopup.extendComponent({
|
ImportPopup.extendComponent({
|
||||||
|
|
|
||||||
|
|
@ -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",
|
||||||
|
|
|
||||||
166
models/import.js
166
models/import.js
|
|
@ -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;
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue