mirror of
https://github.com/wekan/wekan.git
synced 2026-03-07 22:22:33 +01:00
Centralize all mutations at the model level
This commit uses a new package that I need to document. It tries to solve the long-standing debate in the Meteor community about allow/deny rules versus methods (RPC). This approach gives us both the centralized security rules of allow/deny and the white-list of allowed mutations similarly to Meteor methods. The idea to have static mutation descriptions is also inspired by Facebook's Relay/GraphQL. This will allow the development of a REST API using the high-level methods instead of the MongoDB queries to do the mapping between the HTTP requests and our collections.
This commit is contained in:
parent
c04341f1ea
commit
45b662a1dd
26 changed files with 395 additions and 377 deletions
|
|
@ -109,14 +109,6 @@ EscapeActions.register('sidebarView',
|
|||
() => { return Sidebar && Sidebar.getView() !== defaultView; }
|
||||
);
|
||||
|
||||
function getMemberIndex(board, searchId) {
|
||||
for (let i = 0; i < board.members.length; i++) {
|
||||
if (board.members[i].userId === searchId)
|
||||
return i;
|
||||
}
|
||||
throw new Meteor.Error('Member not found');
|
||||
}
|
||||
|
||||
Template.memberPopup.helpers({
|
||||
user() {
|
||||
return Users.findOne(this.userId);
|
||||
|
|
@ -135,13 +127,8 @@ Template.memberPopup.events({
|
|||
'click .js-change-role': Popup.open('changePermissions'),
|
||||
'click .js-remove-member': Popup.afterConfirm('removeMember', function() {
|
||||
const currentBoard = Boards.findOne(Session.get('currentBoard'));
|
||||
const memberIndex = getMemberIndex(currentBoard, this.userId);
|
||||
|
||||
Boards.update(currentBoard._id, {
|
||||
$set: {
|
||||
[`members.${memberIndex}.isActive`]: false,
|
||||
},
|
||||
});
|
||||
const memberId = this.userId;
|
||||
currentBoard.removeMember(memberId);
|
||||
Popup.close();
|
||||
}),
|
||||
'click .js-leave-member'() {
|
||||
|
|
@ -209,26 +196,7 @@ Template.addMemberPopup.events({
|
|||
'click .js-select-member'() {
|
||||
const userId = this._id;
|
||||
const currentBoard = Boards.findOne(Session.get('currentBoard'));
|
||||
const currentMembersIds = _.pluck(currentBoard.members, 'userId');
|
||||
if (currentMembersIds.indexOf(userId) === -1) {
|
||||
Boards.update(currentBoard._id, {
|
||||
$push: {
|
||||
members: {
|
||||
userId,
|
||||
isAdmin: false,
|
||||
isActive: true,
|
||||
},
|
||||
},
|
||||
});
|
||||
} else {
|
||||
const memberIndex = getMemberIndex(currentBoard, userId);
|
||||
|
||||
Boards.update(currentBoard._id, {
|
||||
$set: {
|
||||
[`members.${memberIndex}.isActive`]: true,
|
||||
},
|
||||
});
|
||||
}
|
||||
currentBoard.addMember(userId);
|
||||
Popup.close();
|
||||
},
|
||||
});
|
||||
|
|
@ -240,14 +208,9 @@ Template.addMemberPopup.onRendered(function() {
|
|||
Template.changePermissionsPopup.events({
|
||||
'click .js-set-admin, click .js-set-normal'(event) {
|
||||
const currentBoard = Boards.findOne(Session.get('currentBoard'));
|
||||
const memberIndex = getMemberIndex(currentBoard, this.userId);
|
||||
const memberId = this.userId;
|
||||
const isAdmin = $(event.currentTarget).hasClass('js-set-admin');
|
||||
|
||||
Boards.update(currentBoard._id, {
|
||||
$set: {
|
||||
[`members.${memberIndex}.isAdmin`]: isAdmin,
|
||||
},
|
||||
});
|
||||
currentBoard.setMemberPermission(memberId, isAdmin);
|
||||
Popup.back(1);
|
||||
},
|
||||
});
|
||||
|
|
|
|||
|
|
@ -29,8 +29,8 @@ BlazeComponent.extendComponent({
|
|||
events() {
|
||||
return [{
|
||||
'click .js-restore-card'() {
|
||||
const cardId = this.currentData()._id;
|
||||
Cards.update(cardId, {$set: {archived: false}});
|
||||
const card = this.currentData();
|
||||
card.restore();
|
||||
},
|
||||
'click .js-delete-card': Popup.afterConfirm('cardDelete', function() {
|
||||
const cardId = this._id;
|
||||
|
|
@ -38,8 +38,8 @@ BlazeComponent.extendComponent({
|
|||
Popup.close();
|
||||
}),
|
||||
'click .js-restore-list'() {
|
||||
const listId = this.currentData()._id;
|
||||
Lists.update(listId, {$set: {archived: false}});
|
||||
const list = this.currentData();
|
||||
list.restore();
|
||||
},
|
||||
}];
|
||||
},
|
||||
|
|
|
|||
|
|
@ -30,9 +30,9 @@ BlazeComponent.extendComponent({
|
|||
},
|
||||
}).register('filterSidebar');
|
||||
|
||||
function updateSelectedCards(query) {
|
||||
function mutateSelectedCards(mutationName, ...args) {
|
||||
Cards.find(MultiSelection.getMongoSelector()).forEach((card) => {
|
||||
Cards.update(card._id, query);
|
||||
card[mutationName](...args);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -67,47 +67,34 @@ BlazeComponent.extendComponent({
|
|||
'click .js-toggle-label-multiselection'(evt) {
|
||||
const labelId = this.currentData()._id;
|
||||
const mappedSelection = this.mapSelection('label', labelId);
|
||||
let operation;
|
||||
if (_.every(mappedSelection))
|
||||
operation = '$pull';
|
||||
else if (_.every(mappedSelection, (bool) => !bool))
|
||||
operation = '$addToSet';
|
||||
else {
|
||||
|
||||
if (_.every(mappedSelection)) {
|
||||
mutateSelectedCards('addLabel', labelId);
|
||||
} else if (_.every(mappedSelection, (bool) => !bool)) {
|
||||
mutateSelectedCards('removeLabel', labelId);
|
||||
} else {
|
||||
const popup = Popup.open('disambiguateMultiLabel');
|
||||
// XXX We need to have a better integration between the popup and the
|
||||
// UI components systems.
|
||||
return popup.call(this.currentData(), evt);
|
||||
}
|
||||
|
||||
updateSelectedCards({
|
||||
[operation]: {
|
||||
labelIds: labelId,
|
||||
},
|
||||
});
|
||||
},
|
||||
'click .js-toggle-member-multiselection'(evt) {
|
||||
const memberId = this.currentData()._id;
|
||||
const mappedSelection = this.mapSelection('member', memberId);
|
||||
let operation;
|
||||
if (_.every(mappedSelection))
|
||||
operation = '$pull';
|
||||
else if (_.every(mappedSelection, (bool) => !bool))
|
||||
operation = '$addToSet';
|
||||
else {
|
||||
if (_.every(mappedSelection)) {
|
||||
mutateSelectedCards('assignMember', memberId);
|
||||
} else if (_.every(mappedSelection, (bool) => !bool)) {
|
||||
mutateSelectedCards('unassignMember', memberId);
|
||||
} else {
|
||||
const popup = Popup.open('disambiguateMultiMember');
|
||||
// XXX We need to have a better integration between the popup and the
|
||||
// UI components systems.
|
||||
return popup.call(this.currentData(), evt);
|
||||
}
|
||||
|
||||
updateSelectedCards({
|
||||
[operation]: {
|
||||
members: memberId,
|
||||
},
|
||||
});
|
||||
},
|
||||
'click .js-archive-selection'() {
|
||||
updateSelectedCards({$set: {archived: true}});
|
||||
mutateSelectedCards('archive');
|
||||
},
|
||||
}];
|
||||
},
|
||||
|
|
@ -115,22 +102,22 @@ BlazeComponent.extendComponent({
|
|||
|
||||
Template.disambiguateMultiLabelPopup.events({
|
||||
'click .js-remove-label'() {
|
||||
updateSelectedCards({$pull: {labelIds: this._id}});
|
||||
mutateSelectedCards('removeLabel', this._id);
|
||||
Popup.close();
|
||||
},
|
||||
'click .js-add-label'() {
|
||||
updateSelectedCards({$addToSet: {labelIds: this._id}});
|
||||
mutateSelectedCards('addLabel', this._id);
|
||||
Popup.close();
|
||||
},
|
||||
});
|
||||
|
||||
Template.disambiguateMultiMemberPopup.events({
|
||||
'click .js-unassign-member'() {
|
||||
updateSelectedCards({$pull: {members: this._id}});
|
||||
mutateSelectedCards('assignMember', this._id);
|
||||
Popup.close();
|
||||
},
|
||||
'click .js-assign-member'() {
|
||||
updateSelectedCards({$addToSet: {members: this._id}});
|
||||
mutateSelectedCards('unassignMember', this._id);
|
||||
Popup.close();
|
||||
},
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue