Reputation: 51
I am trying to accomplish the following functionality:
I'm struggling on that last one. I tried this:
!exists(/databases/$(database)/documents/matches/$(uid)/players/$(request.auth.uid)) // if the user is not already in another match
...but it doesn't seem to work.
Here are my rules:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /userAuthData/{uid}/{documents=**} {
allow read: if false
allow write: if false
}
match /userData/{uid}/{documents=**} {
allow read: if request.auth != null && request.auth.uid == uid
allow write: if false
}
function allowCreateMatch(uid) {
return request.auth != null
&& exists(/databases/$(database)/documents/userData/$(request.auth.uid)) // if the user exists
&& !exists(/databases/$(database)/documents/matches/$(request.auth.uid)) // if the user does not have their own match already
&& !exists(/databases/$(database)/documents/matches/$(uid)/players/$(request.auth.uid)) // if the user is not already in another match
&& request.resource.data.maxPlayers == 2 // if the match is set to have 2 players (1v1 is the default for now)
&& request.resource.data.state == 1 // if the match is set to a state of WAITING_FOR_PLAYERS
}
function allowJoinMatch(uid) {
return request.auth != null
&& exists(/databases/$(database)/documents/userData/$(request.auth.uid)) // if the user exists
&& !exists(/databases/$(database)/documents/matches/$(request.auth.uid)) // if the user does not have their own match already
&& !exists(/databases/$(database)/documents/matches/$(uid)/players/$(request.auth.uid)) // if the user is not already in another match
&& !(request.auth.uid in resource.data.players) // if the user is not already in the match
&& resource.data.players.keys().toSet().size() < resource.data.maxPlayers // if there is room left based on the max number of players
&& resource.data.state == 1 // if the match is in a state of WAITING_FOR_PLAYERS
&& resource.data.maxPlayers == request.resource.data.maxPlayers // if there max players value is the same
&& request.resource.data.players.keys().toSet().size() + 1 == resource.data.maxPlayers
? request.resource.data.state == 2 // the match is should be set to a state of READY_TO_START
: request.resource.data.state == 1 // the match is should be set to a state of WAITING_FOR_PLAYERS
}
function allowDeletion() {
return request.auth.uid == resource.id
&& resource.data.state == 1
}
match /matches/{uid}/{documents=**} {
allow read: if true
allow create: if allowCreateMatch(uid)
allow update: if allowJoinMatch(uid)
allow delete: if allowDeletion()
}
}
}
Upvotes: 0
Views: 90
Reputation: 317427
It's not possible with security rules to perform a query other than a simple single-document get()
. Queries for unknown numbers of documents are not allowed because they would not scale in the way that security rules require.
If you can't express your rule in terms of getting a single document, then you will either need to change your data in some way to make this possible, or route your write through some backend that can perform the query you need.
Upvotes: 1