In essence I create a directive with the path, then map and filter it to insert the required rejections then map to get rid of my option.
def validateRoles(user: User, role: Role)(optClient: Tuple1[Option[Client]]) = {
(for {
client <- optClient._1 // returns Int bit map of roles for this (client, user) as option
roles <- authenticationHolder.model.clientUsers.get(ClientUserNames(client.name, user.name)) } yield {
logger.debug(s"client is $client roles $roles looking for $role")
(role & roles) != 0
}).getOrElse(false)
}
// simply checks the client exists. Note the mucking around with Tuple1 - this seems to be necessary as it's tuples all the way
val clientOf : (Tuple1[String]) => Option[Client] = { ts => authenticationHolder.model.clients.get(ts._1) }
def clientRole(user: User, role: Role) = path( Segment ) // match a string for client name
.tmap[Option[Client]](clientOf) // get the client
.tfilter(validateRoles(user, role)(_), AuthorizationFailedRejection) // filter out non-existent client or no authorisation
.tmap[Client](_._1.get) // turns it into the client itself. Couldn't figure out if I could combine filter and map more elegantly
// not pretty but all I've got time for today