summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--models/boards.js8
-rw-r--r--models/import.js204
2 files changed, 80 insertions, 132 deletions
diff --git a/models/boards.js b/models/boards.js
index fd0212c5..e42e06c6 100644
--- a/models/boards.js
+++ b/models/boards.js
@@ -111,6 +111,14 @@ Boards.helpers({
colorClass() {
return `board-color-${this.color}`;
},
+
+ // XXX currently mutations return no value so we have an issue when using addLabel in import
+ // XXX waiting on https://github.com/mquandalle/meteor-collection-mutations/issues/1 to remove...
+ pushLabel(name, color) {
+ const _id = Random.id(6);
+ Boards.direct.update(this._id, { $push: {labels: { _id, name, color }}});
+ return _id;
+ },
});
Boards.mutations({
diff --git a/models/import.js b/models/import.js
index 742fcf2f..be699746 100644
--- a/models/import.js
+++ b/models/import.js
@@ -11,9 +11,9 @@ class TrelloCreator {
cards: {},
lists: {},
};
- // the labels we created, indexed by Trello id (to map when importing cards)
+ // map of labels Trello ID => Wekan ID
this.labels = {};
- // the lists we created, indexed by Trello id (to map when importing cards)
+ // map of lists Trello ID => Wekan ID
this.lists = {};
// the comments, indexed by Trello card id (to map when importing cards)
this.comments = {};
@@ -25,41 +25,45 @@ class TrelloCreator {
date: DateString,
type: String,
})]);
- // XXX perform deeper checks based on type
+ // XXX we could perform more thorough checks based on action type
}
checkBoard(trelloBoard) {
check(trelloBoard, Match.ObjectIncluding({
closed: Boolean,
- labels: [Match.ObjectIncluding({
- // XXX check versus list
- color: String,
- name: String,
- })],
name: String,
prefs: Match.ObjectIncluding({
- // XXX check versus list
+ // XXX refine control by validating 'background' against a list of allowed values (is it worth the maintenance?)
background: String,
- // XXX check versus list
- permissionLevel: String,
+ permissionLevel: Match.Where((value) => {return ['org', 'private', 'public'].indexOf(value)>= 0;}),
}),
}));
}
- checkLists(trelloLists) {
- check(trelloLists, [Match.ObjectIncluding({
+ checkCards(trelloCards) {
+ check(trelloCards, [Match.ObjectIncluding({
closed: Boolean,
+ dateLastActivity: DateString,
+ desc: String,
+ idLabels: [String],
+ idMembers: [String],
name: String,
+ pos: Number,
})]);
}
- checkCards(trelloCards) {
- check(trelloCards, [Match.ObjectIncluding({
+ checkLabels(trelloLabels) {
+ check(trelloLabels, [Match.ObjectIncluding({
+ // XXX refine control by validating 'color' against a list of allowed values (is it worth the maintenance?)
+ color: String,
+ name: String,
+ })]);
+ }
+
+ checkLists(trelloLists) {
+ check(trelloLists, [Match.ObjectIncluding({
closed: Boolean,
- desc: String,
- // XXX check idLabels
name: String,
- pos: Number,
})]);
}
@@ -78,8 +82,7 @@ class TrelloCreator {
isAdmin: true,
isActive: true,
}],
- // current mapping is easy as trello and wekan use same keys: 'private' and 'public'
- permission: trelloBoard.prefs.permissionLevel,
+ permission: this.getPermission(trelloBoard.prefs.permissionLevel),
slug: getSlug(trelloBoard.name) || 'board',
stars: 0,
title: trelloBoard.name,
@@ -91,7 +94,7 @@ class TrelloCreator {
name: label.name,
};
// we need to remember them by Trello ID, as this is the only ref we have when importing cards
- this.labels[label.id] = labelToCreate;
+ this.labels[label.id] = labelToCreate._id;
boardToCreate.labels.push(labelToCreate);
});
const now = new Date();
@@ -113,6 +116,23 @@ class TrelloCreator {
return boardId;
}
+ /**
+ * Create labels if they do not exist and load this.labels.
+ */
+ createLabels(trelloLabels, board) {
+ trelloLabels.forEach((label) => {
+ const color = label.color;
+ const name = label.name;
+ const existingLabel = board.getLabel(name, color);
+ if (existingLabel) {
+ this.labels[label.id] = existingLabel._id;
+ } else {
+ const idLabelCreated = board.pushLabel(name, color);
+ this.labels[label.id] = idLabelCreated;
+ }
+ });
+ }
+
createLists(trelloLists, boardId) {
trelloLists.forEach((list) => {
const listToCreate = {
@@ -125,8 +145,7 @@ class TrelloCreator {
const listId = Lists.direct.insert(listToCreate);
const now = new Date();
Lists.direct.update(listId, {$set: {'updatedAt': now}});
- listToCreate._id = listId;
- this.lists[list.id] = listToCreate;
+ this.lists[list.id] = listId;
// log activity
Activities.direct.insert({
activityType: 'importList',
@@ -144,6 +163,7 @@ class TrelloCreator {
}
createCardsAndComments(trelloCards, boardId) {
+ const result = [];
trelloCards.forEach((card) => {
const cardToCreate = {
archived: card.closed,
@@ -151,7 +171,7 @@ class TrelloCreator {
createdAt: this.createdAt.cards[card.id],
dateLastActivity: new Date(),
description: card.desc,
- listId: this.lists[card.idList]._id,
+ listId: this.lists[card.idList],
sort: card.pos,
title: card.name,
// XXX use the original user?
@@ -160,7 +180,7 @@ class TrelloCreator {
// add labels
if(card.idLabels) {
cardToCreate.labelIds = card.idLabels.map((trelloId) => {
- return this.labels[trelloId]._id;
+ return this.labels[trelloId];
});
}
// insert card
@@ -205,7 +225,9 @@ class TrelloCreator {
});
}
// XXX add attachments
+ result.push(cardId);
});
+ return result;
}
getColor(trelloColorCode) {
@@ -225,6 +247,14 @@ class TrelloCreator {
return wekanColor || Boards.simpleSchema()._schema.color.allowedValues[0];
}
+ getPermission(trelloPermissionCode) {
+ if(trelloPermissionCode === 'public') {
+ return 'public';
+ }
+ // Wekan does NOT have organization level, so we default both 'private' and 'org' to private.
+ return 'private';
+ }
+
parseActions(trelloActions) {
trelloActions.forEach((action) => {
switch (action.type) {
@@ -258,19 +288,23 @@ class TrelloCreator {
Meteor.methods({
importTrelloBoard(trelloBoard, data) {
const trelloCreator = new TrelloCreator();
+
// 1. check all parameters are ok from a syntax point of view
try {
// we don't use additional data - this should be an empty object
check(data, {});
trelloCreator.checkActions(trelloBoard.actions);
trelloCreator.checkBoard(trelloBoard);
+ trelloCreator.checkLabels(trelloBoard.labels);
trelloCreator.checkLists(trelloBoard.lists);
trelloCreator.checkCards(trelloBoard.cards);
} catch(e) {
throw new Meteor.Error('error-json-schema');
}
+
// 2. check parameters are ok from a business point of view (exist & authorized)
// nothing to check, everyone can import boards in their account
+
// 3. create all elements
trelloCreator.parseActions(trelloBoard.actions);
const boardId = trelloCreator.createBoardAndLabels(trelloBoard);
@@ -279,33 +313,19 @@ Meteor.methods({
// XXX add members
return boardId;
},
+
importTrelloCard(trelloCard, data) {
+ const trelloCreator = new TrelloCreator();
+
// 1. check parameters are ok from a syntax point of view
- const DateString = Match.Where(function (dateAsString) {
- check(dateAsString, String);
- return moment(dateAsString, moment.ISO_8601).isValid();
- });
try {
- check(trelloCard, Match.ObjectIncluding({
- name: String,
- desc: String,
- closed: Boolean,
- dateLastActivity: DateString,
- labels: [Match.ObjectIncluding({
- name: String,
- color: String,
- })],
- actions: [Match.ObjectIncluding({
- type: String,
- date: DateString,
- data: Object,
- })],
- members: [Object],
- }));
check(data, {
listId: String,
sortIndex: Number,
});
+ trelloCreator.checkCards([trelloCard]);
+ trelloCreator.checkLabels(trelloCard.labels);
+ trelloCreator.checkActions(trelloCard.actions);
} catch(e) {
throw new Meteor.Error('error-json-schema');
}
@@ -321,92 +341,12 @@ Meteor.methods({
}
}
- // 3. map all fields for the card to create
- const dateOfImport = new Date();
- const cardToCreate = {
- archived: trelloCard.closed,
- boardId: list.boardId,
- // this is a default date, we'll fetch the actual one from the actions array
- createdAt: dateOfImport,
- dateLastActivity: dateOfImport,
- description: trelloCard.desc,
- listId: list._id,
- sort: data.sortIndex,
- title: trelloCard.name,
- // XXX use the original user?
- userId: Meteor.userId(),
- };
-
- // 4. find actual creation date
- const creationAction = trelloCard.actions.find((action) => {
- return action.type === 'createCard';
- });
- if(creationAction) {
- cardToCreate.createdAt = creationAction.date;
- }
-
- // 5. map labels - create missing ones
- trelloCard.labels.forEach((currentLabel) => {
- const color = currentLabel.color;
- const name = currentLabel.name;
- const existingLabel = list.board().getLabel(name, color);
- let labelId = undefined;
- if (existingLabel) {
- labelId = existingLabel._id;
- } else {
- let labelCreated = list.board().addLabel(name, color);
- // XXX currently mutations return no value so we have to fetch the label we just created
- // waiting on https://github.com/mquandalle/meteor-collection-mutations/issues/1 to remove...
- labelCreated = list.board().getLabel(name, color);
- labelId = labelCreated._id;
- }
- if(labelId) {
- if (!cardToCreate.labelIds) {
- cardToCreate.labelIds = [];
- }
- cardToCreate.labelIds.push(labelId);
- }
- });
-
- // 6. insert new card into list
- const cardId = Cards.direct.insert(cardToCreate);
- Activities.direct.insert({
- activityType: 'importCard',
- boardId: cardToCreate.boardId,
- cardId,
- createdAt: dateOfImport,
- listId: cardToCreate.listId,
- source: {
- id: trelloCard.id,
- system: 'Trello',
- url: trelloCard.url,
- },
- // we attribute the import to current user, not the one from the original card
- userId: Meteor.userId(),
- });
-
- // 7. parse actions and add comments
- trelloCard.actions.forEach((currentAction) => {
- if(currentAction.type === 'commentCard') {
- const commentToCreate = {
- boardId: list.boardId,
- cardId,
- createdAt: currentAction.date,
- text: currentAction.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,
- });
- }
- });
- return cardId;
+ // 3. create all elements
+ trelloCreator.lists[trelloCard.idList] = data.listId;
+ trelloCreator.parseActions(trelloCard.actions);
+ const board = list.board();
+ trelloCreator.createLabels(trelloCard.labels, board);
+ const cardIds = trelloCreator.createCardsAndComments([trelloCard], board._id);
+ return cardIds[0];
},
});