Fauna auto-generated function status

I made this a separate issue to avoid confusion. However, it is related to another question posted today in the forum, because the auto-generated findUserByID can select all the fields and data I require on the query:

{
    findUserByID(id: "290125575057572353") {
      _id
      username
      description
      ownerOf {
        data {
          _id
          rankingname
          rankingdesc
        }
      }
      memberOf {
        data {
          _id
          active
          playerInfo {
            username
          }
          ladder {
            _id
            rankingname
            rankingdesc
          }
        }
      }
    }
  }

However, I believe I have to create my own UDF because I want access to the function to be restricted to logged in users:

{
  ref: Role("logged-in"),
  ts: 1616507132450000,
  name: "logged-in",
  privileges: [
    {
      resource: Collection("User"),
      actions: {
        read: true
      }
    },
    {
      resource: Ref(Ref("functions"), "user_find_by_id"),
      actions: {
        call: true
      }
    }
  ],
  membership: [
    {
      resource: Collection("User")
    }
  ]
}

Am I correct that I have to create a separate UDF if I want the logged-in role to restrict use of this function?
If not, how should I be doing this?
Thanks …

I agree it would be best to avoid making your own UDF for this.

If the user calling the GraphQL api has the “logged-in” role, then the read permission should be all that is required.

Notice that the shared query also reaches into other Collections, including your Ranking and Player (I think I got it right) collections. Also, in order to use the relationships it’s also going to use the indexes generated from @relation, e.g. playerinranking_by_user. All of these other permissions must be added as well.

If all of the player and raking info is public, then that’s awesome!

If it’s not all public, then you can still provide read access to all of the indexes and then provide predicates for the collections to describe which docs are available to a certain user.

(I’m referencing this older post for assumptions about the schema)

I agree it would be best to avoid making your own UDF for this:
Ok, I have reverted to the fauna generated function ‘findUserByID’

If the user calling the GraphQL api has the “logged-in” role, then the read permission should be all that is required:
the read/membership permissions on all three Collections has been set as well as the indexes generated from the relations (all of the player and ranking info is public):

name: "logged-in",
    privileges: [
        {
            resource: Collection("User"),
            actions: {
                read: true
            }
        },
        {
            resource: Collection("Ranking"),
            actions: {
                read: true
            }
        },
        {
            resource: Collection("Player"),
            actions: {
                read: true
            }
        },
        {
            resource: Index('ownerranking_by_user'),
            actions: {
                read: true
            }
        },
        {
            resource: Index('playerinranking_by_user'),
            actions: {
                read: true
            }
        },
        {
            resource: Index('unique_User_username'),
            actions: {
                read: true
            }
        }
    ],
    membership: [
        { resource: Collection("User") },
        { resource: Collection("Ranking") },
        { resource: Collection("Player") },
    ]

The schema is now:

type User {
 active: Boolean!
 username: String! @unique
 description: String
 email: String @unique
 mobile: String @unique
 ownerOf: [Ranking!]! @relation(name:"ownerranking")
 memberOf: [Player!]! @relation(name: "playerinranking")
}

type Player {
 active: Boolean!
 rank: Int!
 ladder: Ranking! @relation # add the relation Directive
 playerInfo: User! @relation(name: "playerinranking")
 challenger: Player @relation (name: "playerchallenger")
}

type Ranking {
 active: Boolean!
 rankingname: String!
 rankingdesc: String
 player: [Player] @relation # add the relation
 owner: User! @relation(name:"ownerranking")
}

type Mutation {

 createNewRanking(active: Boolean!, rankingname : String!, rankingdesc : String, rankingownerid : String!): Ranking! @resolver(name: "create_new_ranking")
 createNewUser(active: Boolean!, username : String!, password : String!, description: String, email: String, mobile: String): loginResult! @resolver(name: "create_new_user")
 loginUser(username: String!, password: String!): loginResult! @resolver(name: "login_user")
}

enum ChallengeResult {
 Won
 Lost 
 Abandoned
}


type Query {
 allUserNames: [String!]! @resolver(name: "all_user_names")
 allPlayerUIDs: [String!]! @resolver(name: "all_player_uids")
 allPlayerRanks: [Int!]! @resolver(name: "all_player_ranks")
 allPlayerChallengerUIDs: [String!]! @resolver(name: "all_player_challenger_uids")
 allPlayers: [Player] @resolver(name: "all_players")
 allRankings: [Ranking] @resolver(name: "all_rankings")
 allUsers: [User] @resolver(name: "all_users")
 gotPlayersByRankingId (rankingid: String!): [Player] @resolver(name: "got_players_byrankingid")
 gotRankingIdsByPlayer (uid: String!): [String] @resolver(name: "got_rankings_byplayerid")
 updateResult(challengeresult: ChallengeResult! playerrank: Int! opponentrank: Int!): Result! @resolver(name: "update_result")
}

type loginResult @embedded
{
 token : String
 logginUser : User
}

type Result @embedded {
 challengeresult: ChallengeResult!
 playerrank: Int!
 opponentrank: Int!
 message: String!
}

In PG, I login to the user corresponding to the document id searched for and obtain a token which is then applied to auth Bearer for the findUserByID function.
I now get:

"data": {
  "data": {
    "findUserByID": {
      "_id": "294007769929875981",
      "username": "Test1",
      "description": "t1",
      "ownerOf": {
        "data": []
      },
      "memberOf": {
        "data": []
      }
    }
  }
}

I appear not to have permissions under the ‘logged-in’ role to get the data within Ranking and Player collections.
What else might I be missing? Thanks …

I don’t know why ownerOf comes up blank, because it looks like should have proper permissions.

Sorry for the patronizing question, but are you certain that the links have been made between the User and respective Rankings and Players?

I created one user and some relations and was able to query, with a user token (changed graphql to Bearer token).

Role used:

{
  ref: Role("MyCustomRole"),
  ts: 1616695837655000,
  name: "MyCustomRole",
  privileges: [
    {
      resource: Collection("User"),
      actions: {
        read: true,
      }
    },
    {
      resource: Collection("Player"),
      actions: {
        read: true,
      }
    },
    {
      resource: Collection("Ranking"),
      actions: {
        read: true,
      }
    },
    {
      resource: Index("playerinranking_by_user"),
      actions: {
        read: true
      }
    },
    {
      resource: Index("playerchallenger_by_player"),
      actions: {
        read: true
      }
    },
    {
      resource: Index("ownerranking_by_user"),
      actions: {
        read: true
      }
    },
    {
      resource: Index("player_ladder_by_ranking"),
      actions: {
        read: true
      }
    }
  ],
  membership: [
    {
      resource: Collection("User")
    }
  ]
}

Confirmed that roles do work, because as soon as I removed one of the indexes the whole query failed as not having enough permissions.

Also,

An aside, it shouldn’t matter for the direction this query is going, but if you want to get the Player from the Relation, then don’t forget this relation:

While you didn’t name this relation, it is still built with an index. Make sure that the role has access to this as well. Probably player_ladder_by_ranking.

Please don’t worry about questions, it’s quite possible I could overlook something simple (my db experience is patchy).

I believe the links are there because the GQL fetches the data using Basic authentication. So it should, therefore, just be a token authentication issue, or does that miss the point(?).

Your custom role had a couple of Index references that mine didn’t so I added them:

    name: "logged-in",
    privileges: [
        {
            resource: Collection("User"),
            actions: {
                read: true
            }
        },
        {
            resource: Collection("Ranking"),
            actions: {
                read: true
            }
        },
        {
            resource: Collection("Player"),
            actions: {
                read: true
            }
        },
        {
            resource: Index('ownerranking_by_user'),
            actions: {
                read: true
            }
        },
        {
            resource: Index('playerinranking_by_user'),
            actions: {
                read: true
            }
        }
        ,
        {
            resource: Index('unique_User_username'),
            actions: {
                read: true
            }
        }
        ,

        {
            resource: Index("playerchallenger_by_player"),
            actions: {
                read: true
            }
        },
        {
            resource: Index("player_ladder_by_ranking"),
            actions: {
                read: true
            }
        },
        {
            resource: Index("ladder_in_player_by_ranking"),
            actions: {
                read: true
            }
        }
    ],
    membership: [
        { resource: Collection("User") }
    ]

As well as ensuring that any other fauna generated indexes e.g. player_ladder_by_ranking (that you mentioned) and another possible one ‘ladder_in_player_by_ranking’ were also included.

However, no change to the data returned in PG:

{
  "data": {
    "findUserByID": {
      "_id": "294007769929875981",
      "username": "Test1",
      "description": "t1",
      "ownerOf": {
        "data": []
      },
      "memberOf": {
        "data": []
      }
    }
  }
}

I tried with and without:

{
            resource: Index('unique_User_username'),
            actions: {
                read: true
            }
        }

since I had previously included it, but you had not.
I have also cut out, what I believe to be, for now, unnecessary query definitions in my schema which is now:

type User {
  active: Boolean!
  username: String! @unique
  description: String
  email: String @unique
  mobile: String @unique
  ownerOf: [Ranking!]! @relation(name:"ownerranking")
  memberOf: [Player!]! @relation(name: "playerinranking")
}

type Player {
  active: Boolean!
  rank: Int!
  ladder: Ranking!  @relation # add the relation Directive
  playerInfo: User! @relation(name: "playerinranking")
  challenger: Player @relation (name: "playerchallenger")
}

type Ranking {
  active: Boolean!
  rankingname: String!
  rankingdesc: String
  player: [Player] @relation # add the relation
  owner: User! @relation(name:"ownerranking")
}

type Mutation {
  
  createNewRanking(active: Boolean!, rankingname : String!, rankingdesc : String, rankingownerid : String!): Ranking! @resolver(name: "create_new_ranking")
  createNewUser(active: Boolean!, username : String!, password : String!, description: String, email: String, mobile: String): loginResult! @resolver(name: "create_new_user")
  loginUser(username: String!, password: String!): loginResult! @resolver(name: "login_user")
  updateResult(challengeresult: ChallengeResult! playerrank: Int! opponentrank: Int!): Result! @resolver(name: "update_result")
}

enum ChallengeResult {
  Won
  Lost 
  Abandoned
}


type loginResult @embedded
{
  token : String
  logginUser : User
}

type Result @embedded {
  challengeresult: ChallengeResult!
  playerrank: Int!
  opponentrank: Int!
  message: String!
}

If you can think of anything else I might have missed (?), please let me know. In the meantime, I have narrowed down the query to just:

findUserByID(id: "294007769929875981") {
    _id
    username
    description
    ownerOf {
      data {
        _id
        rankingname
        rankingdesc
      }
    }
  }
}

as I expect resolving that alone will help answer the memberOf issue as well.
Thanks again …

If you go back to querying this with the default key, then does ownerOf data all fill out?

Qu: “If you go back to querying this with the default key, then does ownerOf data all fill out?”
No, now it does not. How do I check that “that the links have been made between the User and respective Rankings and Players”?
The @relation directives are in the schema. I have indexes such as:
playerinranking_by_user
ownerranking_by_user
but I had these before. Do you have an idea what I might have changed? Thanks …

I wanted to make sure you actually created connections. Like, for one: do you remember actually using nested mutations or setting them directly in FQL? But ultimately, check the actual documents to inspect them (without GraphQL).

The docs explain how the data is modeled in the database for given relationships. With that, you open the relevant documents and see if they are actually linked the way you think that they should be.

Depending on how you created data, there’s different ways things can go wrong.

Did you create the documents in GraphQL use create nested mutations? This should of course make the relations just work, and what I did to add some super quick fake data.

Did you create the documents in GraphQL in separate queries, and then use connect nested mutations to connect them after the fact? Did errors occur, or did you forget some of the connections?

Did you create them in FQL, and/or try to “connect” them via FQL? Did you put the relations reference in the correct Collection? Did you save the full Ref (correct) or just the ID (incorrect)?

1 Like

Thanks. That’s resolved the ‘lost data’ issue. As there are no actual owner/memberOf fields displayed in User documents and because I must have deleted some player documents I missed that the user id didn’t actually link to a ranking or player. I will check that more carefully next time!