Skip to content

Commit

Permalink
Centralize all mutations at the model level
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
mquandalle committed Sep 8, 2015
1 parent c04341f commit 45b662a
Show file tree
Hide file tree
Showing 26 changed files with 395 additions and 377 deletions.
1 change: 1 addition & 0 deletions .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ globals:
presences: true
Ps: true
ReactiveTabs: false
Restivus: false
SimpleSchema: false
SubsManager: false
T9n: false
Expand Down
3 changes: 2 additions & 1 deletion .meteor/packages
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,15 @@ mquandalle:stylus
es5-shim

# Collections
mongo
aldeed:collection2
cfs:gridfs
cfs:standard-packages
dburles:collection-helpers
idmontie:migrations
matb33:collection-hooks
matteodem:easy-search
mongo
mquandalle:collection-mutations
reywood:publish-composite

# Account system
Expand Down
1 change: 1 addition & 0 deletions .meteor/versions
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ [email protected]
[email protected]
mousetrap:[email protected]_1
mquandalle:[email protected]
mquandalle:[email protected]
mquandalle:[email protected]_1
mquandalle:[email protected]
mquandalle:[email protected]_1
Expand Down
10 changes: 3 additions & 7 deletions client/components/boards/boardArchive.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,9 @@ BlazeComponent.extendComponent({
events() {
return [{
'click .js-restore-board'() {
const boardId = this.currentData()._id;
Boards.update(boardId, {
$set: {
archived: false,
},
});
Utils.goBoardId(boardId);
const board = this.currentData();
board.restore();
Utils.goBoardId(board._id);
},
}];
},
Expand Down
31 changes: 11 additions & 20 deletions client/components/boards/boardHeader.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ Template.boardMenuPopup.events({
'click .js-change-board-color': Popup.open('boardChangeColor'),
'click .js-change-language': Popup.open('changeLanguage'),
'click .js-archive-board ': Popup.afterConfirm('archiveBoard', () => {
const boardId = Session.get('currentBoard');
Boards.update(boardId, { $set: { archived: true }});
const currentBoard = Boards.findOne(Session.get('currentBoard'));
currentBoard.archive();
// XXX We should have some kind of notification on top of the page to
// confirm that the board was successfully archived.
FlowRouter.go('home');
Expand All @@ -17,13 +17,9 @@ Template.boardMenuPopup.events({

Template.boardChangeTitlePopup.events({
submit(evt, tpl) {
const title = tpl.$('.js-board-name').val().trim();
if (title) {
Boards.update(this._id, {
$set: {
title,
},
});
const newTitle = tpl.$('.js-board-name').val().trim();
if (newTitle) {
this.rename(newTitle);
Popup.close();
}
evt.preventDefault();
Expand Down Expand Up @@ -95,12 +91,9 @@ BlazeComponent.extendComponent({
events() {
return [{
'click .js-select-background'(evt) {
const currentBoardId = Session.get('currentBoard');
Boards.update(currentBoardId, {
$set: {
color: this.currentData().toString(),
},
});
const currentBoard = Boards.findOne(Session.get('currentBoard'));
const newColor = this.currentData().toString();
currentBoard.setColor(newColor);
evt.preventDefault();
},
}];
Expand Down Expand Up @@ -168,11 +161,9 @@ BlazeComponent.extendComponent({
},

selectBoardVisibility() {
Boards.update(Session.get('currentBoard'), {
$set: {
permission: this.currentData(),
},
});
const currentBoard = Boards.findOne(Session.get('currentBoard'));
const visibility = this.currentData();
currentBoard.setVisibility(visibility);
Popup.close();
},

Expand Down
4 changes: 2 additions & 2 deletions client/components/cards/attachments.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@ Template.attachmentsGalery.events({
// XXX Not implemented!
},
'click .js-add-cover'() {
Cards.update(this.cardId, { $set: { coverId: this._id } });
Cards.findOne(this.cardId).setCover(this._id);
},
'click .js-remove-cover'() {
Cards.update(this.cardId, { $unset: { coverId: '' } });
Cards.findOne(this.cardId).unsetCover();
},
});

Expand Down
25 changes: 5 additions & 20 deletions client/components/cards/cardDetails.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,12 +55,6 @@ BlazeComponent.extendComponent({
this.componentParent().showOverlay.set(false);
},

updateCard(modifier) {
Cards.update(this.data()._id, {
$set: modifier,
});
},

events() {
const events = {
[`${CSSEvents.animationend} .js-card-details`]() {
Expand All @@ -76,13 +70,13 @@ BlazeComponent.extendComponent({
'submit .js-card-description'(evt) {
evt.preventDefault();
const description = this.currentComponent().getValue();
this.updateCard({ description });
this.data().setDescription(description);
},
'submit .js-card-details-title'(evt) {
evt.preventDefault();
const title = this.currentComponent().getValue();
if ($.trim(title)) {
this.updateCard({ title });
this.data().setTitle(title);
}
},
'click .js-member': Popup.open('cardMember'),
Expand Down Expand Up @@ -135,14 +129,9 @@ Template.cardDetailsActionsPopup.events({
'click .js-labels': Popup.open('cardLabels'),
'click .js-attachments': Popup.open('cardAttachments'),
'click .js-move-card': Popup.open('moveCard'),
// 'click .js-copy': Popup.open(),
'click .js-archive'(evt) {
evt.preventDefault();
Cards.update(this._id, {
$set: {
archived: true,
},
});
this.archive();
Popup.close();
},
'click .js-more': Popup.open('cardMore'),
Expand All @@ -152,13 +141,9 @@ Template.moveCardPopup.events({
'click .js-select-list'() {
// XXX We should *not* get the currentCard from the global state, but
// instead from a “component” state.
const cardId = Session.get('currentCard');
const card = Cards.findOne(Session.get('currentCard'));
const newListId = this._id;
Cards.update(cardId, {
$set: {
listId: newListId,
},
});
card.move(newListId);
Popup.close();
},
});
Expand Down
51 changes: 8 additions & 43 deletions client/components/cards/labels.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,19 +45,9 @@ Template.createLabelPopup.helpers({

Template.cardLabelsPopup.events({
'click .js-select-label'(evt) {
const cardId = Template.parentData(2).data._id;
const card = Cards.findOne(Session.get('currentCard'));
const labelId = this._id;
let operation;
if (Cards.find({ _id: cardId, labelIds: labelId}).count() === 0)
operation = '$addToSet';
else
operation = '$pull';

Cards.update(cardId, {
[operation]: {
labelIds: labelId,
},
});
card.toggleLabel(labelId);
evt.preventDefault();
},
'click .js-edit-label': Popup.open('editLabel'),
Expand All @@ -79,52 +69,27 @@ Template.formLabel.events({
Template.createLabelPopup.events({
// Create the new label
'submit .create-label'(evt, tpl) {
const board = Boards.findOne(Session.get('currentBoard'));
const name = tpl.$('#labelName').val().trim();
const boardId = Session.get('currentBoard');
const color = Blaze.getData(tpl.find('.fa-check')).color;

Boards.update(boardId, {
$push: {
labels: {
name,
color,
_id: Random.id(6),
},
},
});

board.addLabel(name, color);
Popup.back();
evt.preventDefault();
},
});

Template.editLabelPopup.events({
'click .js-delete-label': Popup.afterConfirm('deleteLabel', function() {
const boardId = Session.get('currentBoard');
Boards.update(boardId, {
$pull: {
labels: {
_id: this._id,
},
},
});

const board = Boards.findOne(Session.get('currentBoard'));
board.removeLabel(this._id);
Popup.back(2);
}),
'submit .edit-label'(evt, tpl) {
evt.preventDefault();
const board = Boards.findOne(Session.get('currentBoard'));
const name = tpl.$('#labelName').val().trim();
const boardId = Session.get('currentBoard');
const getLabel = Utils.getLabelIndex(boardId, this._id);
const color = Blaze.getData(tpl.find('.fa-check')).color;

Boards.update(boardId, {
$set: {
[getLabel.key('name')]: name,
[getLabel.key('color')]: color,
},
});

board.editLabel(this._id, name, color);
Popup.back();
},
});
Expand Down
25 changes: 7 additions & 18 deletions client/components/lists/list.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,23 +73,13 @@ BlazeComponent.extendComponent({
$cards.sortable('cancel');

if (MultiSelection.isActive()) {
Cards.find(MultiSelection.getMongoSelector()).forEach((c, i) => {
Cards.update(c._id, {
$set: {
listId,
sort: sortIndex.base + i * sortIndex.increment,
},
});
Cards.find(MultiSelection.getMongoSelector()).forEach((card, i) => {
card.move(listId, sortIndex.base + i * sortIndex.increment);
});
} else {
const cardDomElement = ui.item.get(0);
const cardId = Blaze.getData(cardDomElement)._id;
Cards.update(cardId, {
$set: {
listId,
sort: sortIndex.base,
},
});
const card = Blaze.getData(cardDomElement);
card.move(listId, sortIndex.base);
}
boardComponent.setIsDragging(false);
},
Expand All @@ -107,16 +97,15 @@ BlazeComponent.extendComponent({
accept: '.js-member,.js-label',
drop(event, ui) {
const cardId = Blaze.getData(this)._id;
let addToSet;
const card = Cards.findOne(cardId);

if (ui.draggable.hasClass('js-member')) {
const memberId = Blaze.getData(ui.draggable.get(0)).userId;
addToSet = { members: memberId };
card.assignMember(memberId);
} else {
const labelId = Blaze.getData(ui.draggable.get(0))._id;
addToSet = { labelIds: labelId };
card.addLabel(labelId);
}
Cards.update(cardId, { $addToSet: addToSet });
},
});
});
Expand Down
39 changes: 10 additions & 29 deletions client/components/lists/listHeader.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,10 @@ BlazeComponent.extendComponent({

editTitle(evt) {
evt.preventDefault();
const form = this.componentChildren('inlinedForm')[0];
const newTitle = form.getValue();
const newTitle = this.componentChildren('inlinedForm')[0].getValue();
const list = this.currentData();
if ($.trim(newTitle)) {
Lists.update(this.currentData()._id, {
$set: {
title: newTitle,
},
});
list.rename(newTitle);
}
},

Expand All @@ -33,45 +29,30 @@ Template.listActionPopup.events({
},
'click .js-list-subscribe'() {},
'click .js-select-cards'() {
const cardIds = Cards.find(
{listId: this._id},
{fields: { _id: 1 }}
).map((card) => card._id);
const cardIds = this.allCards().map((card) => card._id);
MultiSelection.add(cardIds);
Popup.close();
},
'click .js-move-cards': Popup.open('listMoveCards'),
'click .js-archive-cards': Popup.afterConfirm('listArchiveCards', () => {
Cards.find({listId: this._id}).forEach((card) => {
Cards.update(card._id, {
$set: {
archived: true,
},
});
this.allCards().forEach((card) => {
card.archive();
});
Popup.close();
}),
'click .js-close-list'(evt) {
evt.preventDefault();
Lists.update(this._id, {
$set: {
archived: true,
},
});
this.archive();
Popup.close();
},
});

Template.listMoveCardsPopup.events({
'click .js-select-list'() {
const fromList = Template.parentData(2).data._id;
const fromList = Template.parentData(2).data;
const toList = this._id;
Cards.find({ listId: fromList }).forEach((card) => {
Cards.update(card._id, {
$set: {
listId: toList,
},
});
fromList.allCards().forEach((card) => {
card.move(toList);
});
Popup.close();
},
Expand Down
Loading

0 comments on commit 45b662a

Please sign in to comment.