I'm implementing a users and events system. One restriction is that a user can only host 1 event at a time.
I initially tried to implement the restriction by querying the events node in the events .write rule, by looking for an event that already had a userId equal to auth.uid. But i couldn't figure out how to do that, so i decided to create a new node, hosts, as a lookup table. It just stores any userIds that are currently hosting an event. If a user tries to create a event, and their userId already exists in hosts, then it's an error.
Rules:
{
"rules":{
"users":{
"$uid":{
".read": "auth.uid == $uid",
".write": "auth.uid == $uid",
".validate": "newData.exists()"
}
},
"hosts":{
"$uid":{
".read": "true",
//to be a host, you must be a user
".write": "auth.uid == $uid && root.child('users').hasChild(auth.uid) && !root.child('hosts').hasChild(auth.uid)",
".validate": "newData.exists()"
}
},
"events":{
"$uid":{
".read": "true",
//to create an event, you must be a host
".write": "root.child('hosts').hasChild(auth.uid)",
".validate": "true"
}
}
}
}
Javascript:
createEvent(form){
var user = firebase.auth().currentUser
var db = firebase.database();
var newEventRef = db.ref('events').push();
var newEvent = {}
newEvent[uid] = form*/
var update = {
['hosts/'+user.uid]: true
update['events/'+newEventRef.key] = form
};
db.ref().update(update)
.then((...args)=>{
...
})
.catch(err=>{
...
})
},
The problem with the update call is that it always fails. I'm trying to insert into hosts and events at the same time. But the events write rule expects the userId to be in hosts before it writes, so i guess that's why it fails.
Do i have to make 2 separate updates? 1 to insert userId into hosts, and then if that succeeds, another insert into events?
In security rules there are three variables that refer to the data:
data - the data as it exists at the location of the rule before it is updatednewData - the data as it exists at the location of the rule after it is updatedroot - the data as it exists at the root of thd database before it is updatedSo when you refer to root in your rules, you get the data from before the update. To get the updated data, you have to refer to newData. Since unfortunately there is no newRoot, you will have to navigate from newData up to the required level by calling parent() multiple times.
Once example:
"events":{
"$uid":{
".read": "true",
//to create an event, you must be a host
".write": "newData.parent().parent().child('hosts').hasChild(auth.uid)",
".validate": "true"
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With