Reputation: 403
I want to check if the username already is in use. This function gets called when the current user does not have a child of "username":
func createUsername()
{
let userID = FIRAuth.auth()?.currentUser?.uid
FIRDatabase.database().reference().updateChildValues([
"users/\(userID!)/username": username.text!,
"usernames/\(username.text!)": userID!
], withCompletionBlock: { (error, reference) in
if (error != nil) {
print("disallowed")
// Write was disallowed because username exists
}
})
}
In combination with this rules:
{
"rules": {
"users": {
"$uid": {
".read": "$uid === auth.uid",
".write": "$uid === auth.uid",
"username": {
".read": true,
".write": "!data.exists() && newData.exists()",
".validate": "newData.isString()"
}
}
},
"usernames": {
"$username": {
".read": true,
".write": "!data.exists() && newData.exists()",
".validate": "newData.isString() && newData.val() == root.child('users/' + auth.uid + '/username').val()"
}
}
}
}
I got the answer from: https://groups.google.com/forum/#!topic/firebase-talk/dA1Lkykd-tk I get this error message:
[Firebase/Database][I-RDB03812] updateChildValues: at / failed: permission_denied
I am not sure why this wont work. I also tried this answer: Firebase android : make username unique But this did not work for me. There is something wrong with the rules but I dont know what.
Update, little change in rules, still same error:
{
"rules": {
"users": {
"$uid": {
".read": "$uid === auth.uid",
".write": "$uid === auth.uid",
"username": {
".read": true,
".write": "!data.exists() && newData.exists()",
".validate": "newData.isString()"
}
}
},
"usernames": {
"$username": {
".read": true,
".write": "!data.exists() && newData.exists()",
".validate": "newData.isString() && newData.val() == newData.parent().parent().child('users/' + auth.uid + '/username').val()"
}
}
}
}
I also changed the parent() things, but it wouldn't work aswell. I changed to 4 parents, and 0 parents. Same error.
Upvotes: 0
Views: 1281
Reputation: 598901
Update: The problem comes from this validation rule:
".validate": "newData.isString() && newData.val() == root.child('users/' + auth.uid + '/username').val()"
You're comparing the new data against the current root. Since the user has just been created /users/$uid
won't yet exist.
What you want to do is compare the new data against the new users node. To get to this node, you should navigate from newData
up to the new root when comparing:
".validate": "newData.isString() &&
newData.val() == newData.parent().parent().child('users/' + auth.uid + '/username').val()"
I'll leave my previous response below, since it may prove useful in learning how to troubleshoot a problem like this.
I just pasted your rules into a project of mine, simplified them a bit and used your code without problems. I'm not sure why you're having a problem.
The code:
FIRAuth.auth()?.signInAnonymously(completion: { (user, error) in
let username = "puf"
let userID = FIRAuth.auth()?.currentUser?.uid
self.ref.child("42188459").updateChildValues([
"users/\(userID!)/username": username,
"usernames/\(username)": userID!
], withCompletionBlock: { (error, reference) in
if (error != nil) {
print("disallowed")
// Write was disallowed because username exists
}
})
})
The rules snippet:
"users": {
"$uid": {
".write": "$uid === auth.uid",
"username": {
".write": "!data.exists() && newData.exists()",
}
}
},
"usernames": {
"$username": {
".write": "!data.exists() && newData.exists()",
}
}
The resulting JSON:
{
"usernames" : {
"puf" : "DBP4Pw3uiwQfUaDJw1XBR8oFBUK2"
},
"users" : {
"DBP4Pw3uiwQfUaDJw1XBR8oFBUK2" : {
"username" : "puf"
}
}
}
Upvotes: 1