From 306301e881b2637750b1aa3ff66a0d90a9568474 Mon Sep 17 00:00:00 2001 From: Lauri Ojansivu Date: Tue, 13 Aug 2019 02:33:41 +0300 Subject: Assignee field. In Progress. Thanks to xet7 ! Related #2452 --- client/lib/filter.js | 3 +- models/cards.js | 162 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 164 insertions(+), 1 deletion(-) diff --git a/client/lib/filter.js b/client/lib/filter.js index f19dc617..940d5480 100644 --- a/client/lib/filter.js +++ b/client/lib/filter.js @@ -451,10 +451,11 @@ Filter = { // before changing the schema. labelIds: new SetFilter(), members: new SetFilter(), + assignees: new SetFilter(), customFields: new SetFilter('_id'), advanced: new AdvancedFilter(), - _fields: ['labelIds', 'members', 'customFields'], + _fields: ['labelIds', 'members', 'assignees', 'customFields'], // We don't filter cards that have been added after the last filter change. To // implement this we keep the id of these cards in this `_exceptions` fields diff --git a/models/cards.js b/models/cards.js index d92d003c..121d4a0f 100644 --- a/models/cards.js +++ b/models/cards.js @@ -201,6 +201,14 @@ Cards.attachSchema( optional: true, defaultValue: [], }, + assignees: { + /** + * list of assignees (user IDs) who are responsible for completing card + */ + type: [String], + optional: true, + defaultValue: [], + }, receivedAt: { /** * Date the card was received @@ -409,6 +417,10 @@ Cards.helpers({ return _.contains(this.getMembers(), memberId); }, + isAssignee(assigneeId) { + return _.contains(this.getAssignee(), assigneeId); + }, + activities() { if (this.isLinkedCard()) { return Activities.find( @@ -743,6 +755,20 @@ Cards.helpers({ } }, + getAssignees() { + if (this.isLinkedCard()) { + const card = Cards.findOne({ _id: this.linkedId }); + return card.assignees; + } else if (this.isLinkedBoard()) { + const board = Boards.findOne({ _id: this.linkedId }); + return board.activeAssignees().map(assignee => { + return assignee.userId; + }); + } else { + return this.assignees; + } + }, + assignMember(memberId) { if (this.isLinkedCard()) { return Cards.update( @@ -760,6 +786,23 @@ Cards.helpers({ } }, + assignAssignee(assigneeId) { + if (this.isLinkedCard()) { + return Cards.update( + { _id: this.linkedId }, + { $addToSet: { assignees: assigneeId } }, + ); + } else if (this.isLinkedBoard()) { + const board = Boards.findOne({ _id: this.linkedId }); + return board.addAssignee(assigneeId); + } else { + return Cards.update( + { _id: this._id }, + { $addToSet: { assignees: assigneeId } }, + ); + } + }, + unassignMember(memberId) { if (this.isLinkedCard()) { return Cards.update( @@ -774,6 +817,23 @@ Cards.helpers({ } }, + unassignAssignee(assigneeId) { + if (this.isLinkedCard()) { + return Cards.update( + { _id: this.linkedId }, + { $pull: { assignees: assigneeId } }, + ); + } else if (this.isLinkedBoard()) { + const board = Boards.findOne({ _id: this.linkedId }); + return board.removeAssignee(assigneeId); + } else { + return Cards.update( + { _id: this._id }, + { $pull: { assignees: assigneeId } }, + ); + } + }, + toggleMember(memberId) { if (this.getMembers() && this.getMembers().indexOf(memberId) > -1) { return this.unassignMember(memberId); @@ -782,6 +842,14 @@ Cards.helpers({ } }, + toggleAssignee(assigneeId) { + if (this.getAssignees() && this.getAssignees().indexOf(assigneeId) > -1) { + return this.unassignAssignee(assigneeId); + } else { + return this.assignAssignee(assigneeId); + } + }, + getReceived() { if (this.isLinkedCard()) { const card = Cards.findOne({ _id: this.linkedId }); @@ -1124,6 +1192,14 @@ Cards.mutations({ }; }, + assignAssignee(assigneeId) { + return { + $addToSet: { + assignees: assigneeId, + }, + }; + }, + unassignMember(memberId) { return { $pull: { @@ -1132,6 +1208,14 @@ Cards.mutations({ }; }, + unassignAssignee(assigneeId) { + return { + $pull: { + assignee: assigneeId, + }, + }; + }, + toggleMember(memberId) { if (this.members && this.members.indexOf(memberId) > -1) { return this.unassignMember(memberId); @@ -1140,6 +1224,14 @@ Cards.mutations({ } }, + toggleAssignee(assigneeId) { + if (this.assignees && this.assignees.indexOf(assigneeId) > -1) { + return this.unassignAssignee(assigneeId); + } else { + return this.assignAssignee(assigneeId); + } + }, + assignCustomField(customFieldId) { return { $addToSet: { @@ -1414,6 +1506,28 @@ function cardMembers(userId, doc, fieldNames, modifier) { } } + function cardAssignees(userId, doc, fieldNames, modifier) { + if (!_.contains(fieldNames, 'assignees')) return; + let assigneeId; + // Say hello to the new assignee + if (modifier.$addToSet && modifier.$addToSet.assignees) { + assigneeId = modifier.$addToSet.assignees; + const username = Users.findOne(assigneeId).username; + if (!_.contains(doc.assignees, assigneeId)) { + Activities.insert({ + userId, + username, + activityType: 'joinAssignee', + boardId: doc.boardId, + cardId: doc._id, + assigneeId, + listId: doc.listId, + swimlaneId: doc.swimlaneId, + }); + } + } + } + // Say goodbye to the former member if (modifier.$pull && modifier.$pull.members) { memberId = modifier.$pull.members; @@ -1432,6 +1546,25 @@ function cardMembers(userId, doc, fieldNames, modifier) { }); } } + + // Say goodbye to the former assignee + if (modifier.$pull && modifier.$pull.assignees) { + assigneeId = modifier.$pull.assignees; + const username = Users.findOne(assigneeId).username; + // Check that the former assignee is assignee of the card + if (_.contains(doc.assignees, assigneeId)) { + Activities.insert({ + userId, + username, + activityType: 'unjoinAssignee', + boardId: doc.boardId, + cardId: doc._id, + assigneeId, + listId: doc.listId, + swimlaneId: doc.swimlaneId, + }); + } + } } function cardLabels(userId, doc, fieldNames, modifier) { @@ -1650,6 +1783,12 @@ if (Meteor.isServer) { updateActivities(doc, fieldNames, modifier); }); + // Add a new activity if we add or remove a assignee to the card + Cards.before.update((userId, doc, fieldNames, modifier) => { + cardAssignees(userId, doc, fieldNames, modifier); + updateActivities(doc, fieldNames, modifier); + }); + // Add a new activity if we add or remove a label to the card Cards.before.update((userId, doc, fieldNames, modifier) => { cardLabels(userId, doc, fieldNames, modifier); @@ -1809,6 +1948,7 @@ if (Meteor.isServer) { * @param {string} description the description of the new card * @param {string} swimlaneId the swimlane ID of the new card * @param {string} [members] the member IDs list of the new card + * @param {string} [assignees] the assignee IDs list of the new card * @return_type {_id: string} */ JsonRoutes.add('POST', '/api/boards/:boardId/lists/:listId/cards', function( @@ -1830,6 +1970,7 @@ if (Meteor.isServer) { _id: req.body.authorId, }); const members = req.body.members || [req.body.authorId]; + const assignees = req.body.assignees; if (typeof check !== 'undefined') { const id = Cards.direct.insert({ title: req.body.title, @@ -1841,6 +1982,7 @@ if (Meteor.isServer) { swimlaneId: req.body.swimlaneId, sort: currentCards.count(), members, + assignees, }); JsonRoutes.sendResult(res, { code: 200, @@ -1892,6 +2034,7 @@ if (Meteor.isServer) { * @param {string} [labelIds] the new list of label IDs attached to the card * @param {string} [swimlaneId] the new swimlane ID of the card * @param {string} [members] the new list of member IDs attached to the card + * @param {string} [assignees] the new list of assignee IDs attached to the card * @param {string} [requestedBy] the new requestedBy field of the card * @param {string} [assignedBy] the new assignedBy field of the card * @param {string} [receivedAt] the new receivedAt field of the card @@ -2152,6 +2295,25 @@ if (Meteor.isServer) { { $set: { members: newmembers } }, ); } + if (req.body.hasOwnProperty('assignees')) { + let newassignees = req.body.assignees; + if (_.isString(newassignees)) { + if (newassignees === '') { + newassignees = null; + } else { + newassignees = [newassignees]; + } + } + Cards.direct.update( + { + _id: paramCardId, + listId: paramListId, + boardId: paramBoardId, + archived: false, + }, + { $set: { assignees: newassignees } }, + ); + } if (req.body.hasOwnProperty('swimlaneId')) { const newParamSwimlaneId = req.body.swimlaneId; Cards.direct.update( -- cgit v1.2.3-1-g7c22