have the mutation simulation and server operation returning the same result, add missing viewableIf, pass comment object to Telescope.operateOnItem

This commit is contained in:
xavcz 2016-11-02 13:29:43 +01:00
parent c1e1c68c23
commit 7c88d27d62
5 changed files with 95 additions and 109 deletions

View file

@ -125,8 +125,8 @@ const resolvers = {
}, },
Mutation: { Mutation: {
postVote(root, {postId, voteType}, context) { postVote(root, {postId, voteType}, context) {
Meteor._sleepForMs(2000); // wait 2 seconds Meteor._sleepForMs(2000); // wait 2 seconds for demonstration purpose
console.log("sleep done") console.log("sleep done");
const post = Posts.findOne(postId); const post = Posts.findOne(postId);
return Users.canDo(context.currentUser, `posts.${voteType}`) ? Telescope.operateOnItem(Posts, post, context.currentUser, voteType) : false; return Users.canDo(context.currentUser, `posts.${voteType}`) ? Telescope.operateOnItem(Posts, post, context.currentUser, voteType) : false;
}, },

View file

@ -89,25 +89,29 @@ const VoteWithMutation = graphql(gql`
postVote(postId: $postId, voteType: $voteType) { postVote(postId: $postId, voteType: $voteType) {
_id _id
baseScore baseScore
downvotes
downvoters {
_id
}
upvotes
upvoters {
_id
}
} }
} }
`, { `, {
props: ({ownProps, mutate}) => ({ props: ({ownProps, mutate}) => ({
vote: ({post, voteType, currentUser}) => { vote: ({post, voteType, currentUser}) => {
const { baseScore, _id } = Telescope.operateOnItem(Posts, post, currentUser, voteType, true); const votedItem = Telescope.operateOnItem(Posts, post, currentUser, voteType, true);
// console.log("// votedItem")
// console.log(votedItem)
return mutate({ return mutate({
variables: {postId: post._id, voteType}, variables: {postId: post._id, voteType},
optimisticResponse: { optimisticResponse: {
__typename: 'Mutation', __typename: 'Mutation',
postVote: { postVote: {
__typename: 'Post', ...votedItem,
_id,
baseScore,
}, },
}, }
}) })
} }
}), }),

View file

@ -178,7 +178,7 @@ function CommentsNewUpvoteOwnComment (comment) {
var commentAuthor = Users.findOne(comment.userId); var commentAuthor = Users.findOne(comment.userId);
// upvote comment // upvote comment
Telescope.operateOnItem(Comments, comment._id, commentAuthor, "upvote"); Telescope.operateOnItem(Comments, comment, commentAuthor, "upvote");
return comment; return comment;
} }

View file

@ -83,7 +83,7 @@ Telescope.schemas.userData = new SimpleSchema({
type: [Telescope.schemas.votes], type: [Telescope.schemas.votes],
publish: false, publish: false,
optional: true, optional: true,
// viewableIf: alwaysPublic, viewableIf: alwaysPublic,
}, },
/** /**
An array containing posts downvotes An array containing posts downvotes
@ -92,7 +92,7 @@ Telescope.schemas.userData = new SimpleSchema({
type: [Telescope.schemas.votes], type: [Telescope.schemas.votes],
publish: false, publish: false,
optional: true, optional: true,
// viewableIf: alwaysPublic, viewableIf: alwaysPublic,
}, },
/** /**
The user's email. Modifiable. The user's email. Modifiable.
@ -192,7 +192,7 @@ Telescope.schemas.userData = new SimpleSchema({
type: [Telescope.schemas.votes], type: [Telescope.schemas.votes],
publish: false, publish: false,
optional: true, optional: true,
// viewableIf: alwaysPublic, viewableIf: alwaysPublic,
}, },
/** /**
An array containing posts upvotes An array containing posts upvotes
@ -201,7 +201,7 @@ Telescope.schemas.userData = new SimpleSchema({
type: [Telescope.schemas.votes], type: [Telescope.schemas.votes],
publish: false, publish: false,
optional: true, optional: true,
// viewableIf: alwaysPublic, viewableIf: alwaysPublic,
}, },
/** /**
A link to the user's homepage A link to the user's homepage

View file

@ -20,133 +20,115 @@ Telescope.operateOnItem = function (collection, item, user, operation, isSimulat
// console.log(user) // console.log(user)
// console.log(operation) // console.log(operation)
if (isSimulation) { // ---------------------------- "Real" Server-Side Operation -------------------------- //
// ------------------------------ Optimistic UI Simulation ------------------------------ //
const simulatedItem = { // make sure item and user are defined, and user can perform the operation
__typename: 'Post', const collectionName = item.__typename ? Telescope.utils.getCollectionNameFromTypename(item.__typename) : item.getCollectionName();
_id: item._id,
upvoters: item.upvoters,
upvotes: item.upvotes,
baseScore: item.baseScore
};
// console.log("// before simulation") if (
// console.log(operation) !item ||
// console.log(_.clone(simulatedItem)) !user ||
!Users.canDo(user, `${collectionName}.${operation}`) ||
operation === "upvote" && hasUpvotedItem ||
operation === "downvote" && hasDownvotedItem ||
operation === "cancelUpvote" && !hasUpvotedItem ||
operation === "cancelDownvote" && !hasDownvotedItem
) {
return false;
}
switch (operation) { if (typeof item.upvoters === 'undefined') {
item.upvoters = [];
}
case "upvote": if (typeof item.downvoters === 'undefined') {
if (hasDownvotedItem) { item.downvoters = [];
Telescope.operateOnItem(collection, item, user, "cancelDownvote", true); }
}
simulatedItem.upvoters.push(user._id);
simulatedItem.upvotes += 1;
simulatedItem.baseScore += votePower;
break;
case "downvote": // ------------------------------ Sync Callbacks ------------------------------ //
if (hasUpvotedItem) {
Telescope.operateOnItem(collection, item, user, "cancelUpvote", true);
}
simulatedItem.downvoters.push(user._id);
simulatedItem.downvotes += 1;
simulatedItem.baseScore -= votePower;
case "cancelUpvote": item = Telescope.callbacks.run(operation, item, user);
simulatedItem.upvoters = _.reject(simulatedItem.upvoters, u => u._id === user._id);
simulatedItem.upvotes -= 1;
simulatedItem.baseScore -= votePower;
break;
case "cancelDownvote": switch (operation) {
simulatedItem.downvoters = _.reject(simulatedItem.downvoters, u => u._id === user._id);
simulatedItem.downvoters -= 1;
simulatedItem.baseScore += votePower;
break;
}
// console.log("// after simulation") case "upvote":
// console.log(_.clone(simulatedItem)) if (hasDownvotedItem) {
Telescope.operateOnItem(collection, item, user, "cancelDownvote", isSimulation);
return simulatedItem; }
} else { const upvoter = isSimulation ? {__typename: "User", _id: user._id} : user._id
item.upvoters.push(upvoter);
// ------------------------------ "Real" Server-Side Operation ------------------------------ // item.upvotes += 1;
item.baseScore += votePower;
// make sure item and user are defined, and user can perform the operation
if ( if (!isSimulation) {
!item ||
!user ||
!Users.canDo(user, `${item.getCollectionName()}.${operation}`) ||
operation === "upvote" && hasUpvotedItem ||
operation === "downvote" && hasDownvotedItem ||
operation === "cancelUpvote" && !hasUpvotedItem||
operation === "cancelDownvote" && !hasDownvotedItem
) {
return false;
}
// ------------------------------ Sync Callbacks ------------------------------ //
item = Telescope.callbacks.run(operation, item, user);
switch (operation) {
case "upvote":
if (hasDownvotedItem) {
Telescope.operateOnItem(collection, item, user, "cancelDownvote", isSimulation);
}
update = { update = {
$addToSet: {upvoters: user._id}, $addToSet: {upvoters: user._id},
$inc: {upvotes: 1, baseScore: votePower} $inc: {upvotes: 1, baseScore: votePower}
} }
break; }
break;
case "downvote": case "downvote":
if (hasUpvotedItem) {
Telescope.operateOnItem(collection, item, user, "cancelUpvote", isSimulation);
}
if (hasUpvotedItem) { const downvoter = isSimulation ? {__typename: "User", _id: user._id} : user._id
Telescope.operateOnItem(collection, item, user, "cancelUpvote", isSimulation); item.downvoters.push(downvoter);
} item.downvotes += 1;
item.baseScore -= votePower;
if (!isSimulation) {
update = { update = {
$addToSet: {downvoters: user._id}, $addToSet: {downvoters: user._id},
$inc: {downvotes: 1, baseScore: -votePower} $inc: {downvotes: 1, baseScore: -votePower}
} }
break; }
break;
case "cancelUpvote":
case "cancelUpvote":
item.upvoters = item.upvoters.filter(u => typeof u === 'string' ? u !== user._id : u._id !== user._id);
item.upvotes -= 1;
item.baseScore -= votePower;
if (!isSimulation) {
update = { update = {
$pull: {upvoters: user._id}, $pull: {upvoters: user._id},
$inc: {upvotes: -1, baseScore: -votePower} $inc: {upvotes: -1, baseScore: -votePower}
}; };
break; }
break;
case "cancelDownvote":
case "cancelDownvote":
item.downvoters = item.downvoters.filter(u => typeof u === 'string' ? u !== user._id : u._id !== user._id);
item.downvotes -= 1;
item.baseScore += votePower;
if (!isSimulation) {
update = { update = {
$pull: {downvoters: user._id}, $pull: {downvoters: user._id},
$inc: {downvotes: -1, baseScore: votePower} $inc: {downvotes: -1, baseScore: votePower}
}; };
break; }
} break;
}
if (!isSimulation) {
update["$set"] = {inactive: false}; update["$set"] = {inactive: false};
var result = collection.update({_id: item._id}, update); const result = collection.update({_id: item._id}, update);
if (result > 0) { if (result > 0) {
// extend item with baseScore to help calculate newScore
item = _.extend(item, {baseScore: (item.baseScore + votePower)});
// --------------------- Server-Side Async Callbacks --------------------- // // --------------------- Server-Side Async Callbacks --------------------- //
Telescope.callbacks.runAsync(operation+".async", item, user, collection, operation); Telescope.callbacks.runAsync(operation+".async", item, user, collection, operation);
return item;
} }
} }
// if (isSimulation) {
// console.log('item from apollo store', item);
// } else {
// console.log('item from mongo db', item);
// }
return item;
}; };