diff options
author | Andrés Manelli <andresmanelli@gmail.com> | 2019-03-16 22:43:47 +0100 |
---|---|---|
committer | Andrés Manelli <andresmanelli@gmail.com> | 2019-03-16 22:49:45 +0100 |
commit | d01fccd9497120613bf2c0b986963e67e7f3d6fa (patch) | |
tree | 0ad6cc465e427397b7125bb8f3ff0f0719d28c0b | |
parent | 4cd0d1c3971f001eccf023bb84f1bee113fed215 (diff) | |
download | wekan-d01fccd9497120613bf2c0b986963e67e7f3d6fa.tar.gz wekan-d01fccd9497120613bf2c0b986963e67e7f3d6fa.tar.bz2 wekan-d01fccd9497120613bf2c0b986963e67e7f3d6fa.zip |
- Fix card copy & move between boards with customFields
- Fix card copy & move between boards with labels with same name
- Fix activities for labels when copying and moving card
- Fix activities for customFields when copying and moving card
-rw-r--r-- | client/components/activities/activities.jade | 9 | ||||
-rw-r--r-- | client/components/activities/activities.js | 8 | ||||
-rw-r--r-- | client/components/cards/cardDetails.js | 8 | ||||
-rw-r--r-- | client/components/lists/list.js | 4 | ||||
-rw-r--r-- | client/components/sidebar/sidebarCustomFields.js | 13 | ||||
-rw-r--r-- | models/boards.js | 2 | ||||
-rw-r--r-- | models/cards.js | 102 | ||||
-rw-r--r-- | models/customFields.js | 61 | ||||
-rw-r--r-- | server/lib/utils.js | 6 |
9 files changed, 179 insertions, 34 deletions
diff --git a/client/components/activities/activities.jade b/client/components/activities/activities.jade index 949400f6..54066da8 100644 --- a/client/components/activities/activities.jade +++ b/client/components/activities/activities.jade @@ -99,6 +99,9 @@ template(name="boardActivities") else | {{{_ 'activity-added' memberLink cardLink}}}. + if($eq activityType 'moveCardBoard') + | {{{_ 'activity-moved' cardLink oldBoardName boardName}}}. + if($eq activityType 'moveCard') | {{{_ 'activity-moved' cardLink oldList.title list.title}}}. @@ -135,7 +138,7 @@ template(name="cardActivities") p.activity-desc +memberName(user=user) if($eq activityType 'createCard') - | {{_ 'activity-added' cardLabel list.title}}. + | {{_ 'activity-added' cardLabel listName}}. if($eq activityType 'importCard') | {{{_ 'activity-imported' cardLabel list.title sourceLink}}}. if($eq activityType 'joinMember') @@ -176,6 +179,10 @@ template(name="cardActivities") | {{_ 'activity-sent' cardLabel boardLabel}}. if($eq activityType 'moveCard') | {{_ 'activity-moved' cardLabel oldList.title list.title}}. + + if($eq activityType 'moveCardBoard') + | {{{_ 'activity-moved' cardLink oldBoardName boardName}}}. + if($eq activityType 'addAttachment') | {{{_ 'activity-attached' attachmentLink cardLabel}}}. if attachment.isImage diff --git a/client/components/activities/activities.js b/client/components/activities/activities.js index 81995221..cbdd776e 100644 --- a/client/components/activities/activities.js +++ b/client/components/activities/activities.js @@ -74,6 +74,8 @@ BlazeComponent.extendComponent({ lastLabel(){ const lastLabelId = this.currentData().labelId; + if (!lastLabelId) + return; const lastLabel = Boards.findOne(Session.get('currentBoard')).getLabelById(lastLabelId); if(lastLabel.name === undefined || lastLabel.name === ''){ return lastLabel.color; @@ -84,11 +86,15 @@ BlazeComponent.extendComponent({ lastCustomField(){ const lastCustomField = CustomFields.findOne(this.currentData().customFieldId); + if (!lastCustomField) + return null; return lastCustomField.name; }, lastCustomFieldValue(){ const lastCustomField = CustomFields.findOne(this.currentData().customFieldId); + if (!lastCustomField) + return null; const value = this.currentData().value; if (lastCustomField.settings.dropdownItems && lastCustomField.settings.dropdownItems.length > 0) { const dropDownValue = _.find(lastCustomField.settings.dropdownItems, (item) => { @@ -135,6 +141,8 @@ BlazeComponent.extendComponent({ customField() { const customField = this.currentData().customField(); + if (!customField) + return null; return customField.name; }, diff --git a/client/components/cards/cardDetails.js b/client/components/cards/cardDetails.js index d27fe732..79e9e311 100644 --- a/client/components/cards/cardDetails.js +++ b/client/components/cards/cardDetails.js @@ -412,11 +412,13 @@ Template.moveCardPopup.events({ // XXX We should *not* get the currentCard from the global state, but // instead from a “component” state. const card = Cards.findOne(Session.get('currentCard')); + const bSelect = $('.js-select-boards')[0]; + const boardId = bSelect.options[bSelect.selectedIndex].value; const lSelect = $('.js-select-lists')[0]; - const newListId = lSelect.options[lSelect.selectedIndex].value; + const listId = lSelect.options[lSelect.selectedIndex].value; const slSelect = $('.js-select-swimlanes')[0]; - card.swimlaneId = slSelect.options[slSelect.selectedIndex].value; - card.move(card.swimlaneId, newListId, 0); + const swimlaneId = slSelect.options[slSelect.selectedIndex].value; + card.move(boardId, swimlaneId, listId, 0); Popup.close(); }, }); diff --git a/client/components/lists/list.js b/client/components/lists/list.js index 868be2ce..cceae7b4 100644 --- a/client/components/lists/list.js +++ b/client/components/lists/list.js @@ -86,12 +86,12 @@ BlazeComponent.extendComponent({ if (MultiSelection.isActive()) { Cards.find(MultiSelection.getMongoSelector()).forEach((card, i) => { - card.move(swimlaneId, listId, sortIndex.base + i * sortIndex.increment); + card.move(currentBoard._id, swimlaneId, listId, sortIndex.base + i * sortIndex.increment); }); } else { const cardDomElement = ui.item.get(0); const card = Blaze.getData(cardDomElement); - card.move(swimlaneId, listId, sortIndex.base); + card.move(currentBoard._id, swimlaneId, listId, sortIndex.base); } boardComponent.setIsDragging(false); }, diff --git a/client/components/sidebar/sidebarCustomFields.js b/client/components/sidebar/sidebarCustomFields.js index bdd8e7a0..81147ce5 100644 --- a/client/components/sidebar/sidebarCustomFields.js +++ b/client/components/sidebar/sidebarCustomFields.js @@ -116,15 +116,22 @@ const CreateCustomFieldPopup = BlazeComponent.extendComponent({ data.boardIds = [Session.get('currentBoard')]; CustomFields.insert(data); } else { - data.boardIds = {$in: [Session.get('currentBoard')]}; CustomFields.update(this.data()._id, {$set: data}); } Popup.back(); }, 'click .js-delete-custom-field': Popup.afterConfirm('deleteCustomField', function() { - const customFieldId = this._id; - CustomFields.remove(customFieldId); + const customField = CustomFields.findOne(this._id); + if (customField.boardIds.length > 1) { + CustomFields.update(customField._id, { + $pull: { + boardIds: Session.get('currentBoard') + } + }); + } else { + CustomFields.remove(customField._id); + } Popup.close(); }), }]; diff --git a/models/boards.js b/models/boards.js index 9a71ede8..99ac8e6e 100644 --- a/models/boards.js +++ b/models/boards.js @@ -466,7 +466,7 @@ Boards.helpers({ }, customFields() { - return CustomFields.find({ boardId: this._id }, { sort: { name: 1 } }); + return CustomFields.find({ boardIds: {$in: [this._id]} }, { sort: { name: 1 } }); }, // XXX currently mutations return no value so we have an issue when using addLabel in import diff --git a/models/cards.js b/models/cards.js index 2caecb46..c234ab37 100644 --- a/models/cards.js +++ b/models/cards.js @@ -289,9 +289,19 @@ Cards.helpers({ const oldId = this._id; const oldCard = Cards.findOne(oldId); + // Copy Custom Fields + if (oldBoard._id !== boardId) { + CustomFields.find({ + _id: {$in: oldCard.customFields.map((cf) => { return cf._id; })}, + }).forEach((cf) => { + if (!_.contains(cf.boardIds, boardId)) + cf.addBoard(boardId); + }); + } + delete this._id; delete this.labelIds; - this.labelIds= newCardLabels; + this.labelIds = newCardLabels; this.boardId = boardId; this.swimlaneId = swimlaneId; this.listId = listId; @@ -306,7 +316,6 @@ Cards.helpers({ // copy checklists Checklists.find({cardId: oldId}).forEach((ch) => { - // REMOVE verify copy with arguments ch.copy(_id); }); @@ -314,13 +323,11 @@ Cards.helpers({ Cards.find({parentId: oldId}).forEach((subtask) => { subtask.parentId = _id; subtask._id = null; - // REMOVE verify copy with arguments instead of insert? Cards.insert(subtask); }); // copy card comments CardComments.find({cardId: oldId}).forEach((cmt) => { - // REMOVE verify copy with arguments cmt.copy(_id); }); @@ -485,6 +492,9 @@ Cards.helpers({ const definition = definitions.find((definition) => { return definition._id === customField._id; }); + if (!definition) { + return {}; + } //search for "True Value" which is for DropDowns other then the Value (which is the id) let trueValue = customField.value; if (definition.settings.dropdownItems && definition.settings.dropdownItems.length > 0) { @@ -1054,18 +1064,41 @@ Cards.mutations({ }; }, - move(swimlaneId, listId, sortIndex) { - const list = Lists.findOne(listId); + move(boardId, swimlaneId, listId, sort) { + // Copy Custom Fields + if (this.boardId !== boardId) { + CustomFields.find({ + _id: {$in: this.customFields.map((cf) => { return cf._id; })}, + }).forEach((cf) => { + if (!_.contains(cf.boardIds, boardId)) + cf.addBoard(boardId); + }); + } + + // Get label names + const oldBoard = Boards.findOne(this.boardId); + const oldBoardLabels = oldBoard.labels; + const oldCardLabels = _.pluck(_.filter(oldBoardLabels, (label) => { + return _.contains(this.labelIds, label._id); + }), 'name'); + + const newBoard = Boards.findOne(boardId); + const newBoardLabels = newBoard.labels; + const newCardLabelIds = _.pluck(_.filter(newBoardLabels, (label) => { + return label.name && _.contains(oldCardLabels, label.name); + }), '_id'); + const mutatedFields = { + boardId, swimlaneId, listId, - boardId: list.boardId, - sort: sortIndex, + sort, + labelIds: newCardLabelIds, }; - return { + Cards.update(this._id, { $set: mutatedFields, - }; + }); }, addLabel(labelId) { @@ -1287,8 +1320,47 @@ Cards.mutations({ //FUNCTIONS FOR creation of Activities -function cardMove(userId, doc, fieldNames, oldListId, oldSwimlaneId) { - if ((_.contains(fieldNames, 'listId') && doc.listId !== oldListId) || +function updateActivities(doc, fieldNames, modifier) { + if (_.contains(fieldNames, 'labelIds') && _.contains(fieldNames, 'boardId')) { + Activities.find({ + activityType: 'addedLabel', + cardId: doc._id, + }).forEach((a) => { + const lidx = doc.labelIds.indexOf(a.labelId); + if (lidx !== -1 && modifier.$set.labelIds.length > lidx) { + Activities.update(a._id, { + $set: { + labelId: modifier.$set.labelIds[doc.labelIds.indexOf(a.labelId)], + boardId: modifier.$set.boardId, + } + }); + } else { + Activities.remove(a._id); + } + }); + } else if (_.contains(fieldNames, 'boardId')) { + Activities.remove({ + activityType: 'addedLabel', + cardId: doc._id, + }); + } +} + +function cardMove(userId, doc, fieldNames, oldListId, oldSwimlaneId, oldBoardId) { + if (_.contains(fieldNames, 'boardId') && (doc.boardId !== oldBoardId)) { + Activities.insert({ + userId, + activityType: 'moveCardBoard', + boardName: Boards.findOne(doc.boardId).title, + boardId: doc.boardId, + oldBoardId, + oldBoardName: Boards.findOne(oldBoardId).title, + cardId: doc._id, + swimlaneName: Swimlanes.findOne(doc.swimlaneId).title, + swimlaneId: doc.swimlaneId, + oldSwimlaneId, + }); + } else if ((_.contains(fieldNames, 'listId') && doc.listId !== oldListId) || (_.contains(fieldNames, 'swimlaneId') && doc.swimlaneId !== oldSwimlaneId)){ Activities.insert({ userId, @@ -1435,7 +1507,7 @@ function cardCustomFields(userId, doc, fieldNames, modifier) { // only individual changes are registered if (dotNotation.length > 1) { - const customFieldId = doc.customFields[dot_notation[1]]._id; + const customFieldId = doc.customFields[dotNotation[1]]._id; const act = { userId, customFieldId, @@ -1508,12 +1580,14 @@ if (Meteor.isServer) { Cards.after.update(function(userId, doc, fieldNames) { const oldListId = this.previous.listId; const oldSwimlaneId = this.previous.swimlaneId; - cardMove(userId, doc, fieldNames, oldListId, oldSwimlaneId); + const oldBoardId = this.previous.boardId; + cardMove(userId, doc, fieldNames, oldListId, oldSwimlaneId, oldBoardId); }); // Add a new activity if we add or remove a member to the card Cards.before.update((userId, doc, fieldNames, modifier) => { cardMembers(userId, doc, fieldNames, modifier); + updateActivities(doc, fieldNames, modifier); }); // Add a new activity if we add or remove a label to the card diff --git a/models/customFields.js b/models/customFields.js index 79f96708..a67ddb7d 100644 --- a/models/customFields.js +++ b/models/customFields.js @@ -72,17 +72,37 @@ CustomFields.attachSchema(new SimpleSchema({ }, })); +CustomFields.mutations({ + addBoard(boardId) { + if (boardId) { + return { + $push: { + boardIds: boardId, + }, + }; + } else { + return null; + } + }, +}); + CustomFields.allow({ insert(userId, doc) { - return allowIsBoardMember(userId, Boards.findOne(doc.boardId)); + return allowIsAnyBoardMember(userId, Boards.find({ + _id: {$in: doc.boardIds}, + }).fetch()); }, update(userId, doc) { - return allowIsBoardMember(userId, Boards.findOne(doc.boardId)); + return allowIsAnyBoardMember(userId, Boards.find({ + _id: {$in: doc.boardIds}, + }).fetch()); }, remove(userId, doc) { - return allowIsBoardMember(userId, Boards.findOne(doc.boardId)); + return allowIsAnyBoardMember(userId, Boards.find({ + _id: {$in: doc.boardIds}, + }).fetch()); }, - fetch: ['userId', 'boardId'], + fetch: ['userId', 'boardIds'], }); // not sure if we need this? @@ -92,27 +112,48 @@ function customFieldCreation(userId, doc){ Activities.insert({ userId, activityType: 'createCustomField', - boardId: doc.boardId, + boardId: doc.boardIds[0], // We are creating a customField, it has only one boardId customFieldId: doc._id, }); } if (Meteor.isServer) { Meteor.startup(() => { - CustomFields._collection._ensureIndex({ boardId: 1 }); + CustomFields._collection._ensureIndex({ boardIds: 1 }); }); CustomFields.after.insert((userId, doc) => { customFieldCreation(userId, doc); }); - CustomFields.after.remove((userId, doc) => { + CustomFields.before.update((userId, doc, fieldNames, modifier) => { + if (_.contains(fieldNames, 'boardIds') && modifier.$pull) { + Cards.update( + {boardId: modifier.$pull.boardIds, 'customFields._id': doc._id}, + {$pull: {'customFields': {'_id': doc._id}}}, + {multi: true} + ); + Activities.remove({ + customFieldId: doc._id, + boardId: modifier.$pull.boardIds, + }); + } else if (_.contains(fieldNames, 'boardIds') && modifier.$push) { + Activities.insert({ + userId, + activityType: 'createCustomField', + boardId: modifier.$push.boardIds, + customFieldId: doc._id, + }); + } + }); + + CustomFields.before.remove((userId, doc) => { Activities.remove({ customFieldId: doc._id, }); Cards.update( - {'boardId': doc.boardId, 'customFields._id': doc._id}, + {boardId: {$in: doc.boardIds}, 'customFields._id': doc._id}, {$pull: {'customFields': {'_id': doc._id}}}, {multi: true} ); @@ -186,7 +227,7 @@ if (Meteor.isServer) { showOnCard: req.body.showOnCard, automaticallyOnCard: req.body.automaticallyOnCard, showLabelOnMiniCard: req.body.showLabelOnMiniCard, - boardId: paramBoardId, + boardIds: {$in: [paramBoardId]}, }); const customField = CustomFields.findOne({_id: id, boardIds: {$in: [paramBoardId]} }); @@ -214,7 +255,7 @@ if (Meteor.isServer) { Authentication.checkUserId( req.userId); const paramBoardId = req.params.boardId; const id = req.params.customFieldId; - CustomFields.remove({ _id: id, boardId: paramBoardId }); + CustomFields.remove({ _id: id, boardIds: {$in: [paramBoardId]} }); JsonRoutes.sendResult(res, { code: 200, data: { diff --git a/server/lib/utils.js b/server/lib/utils.js index ee925847..3b4412fe 100644 --- a/server/lib/utils.js +++ b/server/lib/utils.js @@ -6,6 +6,12 @@ allowIsBoardMember = function(userId, board) { return board && board.hasMember(userId); }; +allowIsAnyBoardMember = function(userId, boards) { + return _.some(boards, (board) => { + return board && board.hasMember(userId); + }); +}; + allowIsBoardMemberCommentOnly = function(userId, board) { return board && board.hasMember(userId) && !board.hasCommentOnly(userId); }; |