Reputation: 308
Continuing from this thread, on HN: https://news.ycombinator.com/item?id=5462769
Reading through the firefeed rules file answered a lot of questions for me, except for these two:
Upvotes: 6
Views: 1154
Reputation: 17999
Now that Firebase Functions has been released (in beta) to the general public, it seems to be a good option: https://firebase.googleblog.com/2017/03/introducing-cloud-functions-for-firebase.html
The idea is to have each user be allowed to add their name, by key, to an "upvoters" collection for the tweet. They can create or delete their entry -- but there can only be one, since it's by-key and the security rule only allows control of their one key.
When finding of the "upvote count" is to take place, the client could get the full list of upvoters and tally the number. But instead, for performance's sake, we create a Firebase Function which is triggered whenever an upvote entry is added or removed.
All it does then is increase or decrease an "upvote count" property on the tweet. This is the same as before, except that we make a security rule that only lets the cloud-hosted Function modify this field. Thus, the modification is always trusted and safe, and removes the need for the client to receive the list of upvoters just to get the upvote-count.
Upvotes: 0
Reputation: 40582
1. Not editable but deletable by the author
".write": "!data.exists() || (!newData.exists() && data.child('author') === auth.id)"
2. Liking/Upvoting
On the client, use a transaction which allows you to increment the value safely:
ref.transaction(function(currentValue) {
return (currentValue||0)+1;
}, function(error) {
if( error ) /* failed too many times */
else /* it worked */
});
Security is also straightforward:
".validate": "newData.isNumber() && newData.val() === data.val()+1"
2.5 Ensuring Unique Votes
I'm not sure what this means; the records can't be edited and presumably if they could, only the author would be able to do so; so I don't really understand "modified" in this context: "if the user hasn't modified this before? How would that work?"
To ensure votes are unique, you just store them by user ID. The user can remove their vote by deleting the record.
I'd recommend storing these in a separate path than the sparks and still maintaining a simple increment (the messages that are getting voted up/down) as you don't want to have to retrieve the entire list of voters each time you fetch the spark.
The security rules would look like so:
"votes": {
"$spark_id": {
"$vote": {
".read": "$vote === auth.id",
".write": "$vote === auth.id",
// to allow downvoting in addition to up or delete, just add -1 here
".validate": "newData.val() === 1 || newData.val() === null"
}
}
}
And now add a check to the validate rule for the increment:
".validate": "!root.child('votes').child($spark_id).child(auth.id).exists() && newData.isNumber() && newData.val() === data.val()+1"
Upvotes: 9