diff --git a/src/main/scala/pt/tecnico/dsi/openstack/keystone/models/Role.scala b/src/main/scala/pt/tecnico/dsi/openstack/keystone/models/Role.scala index 092f7da..490c3a6 100644 --- a/src/main/scala/pt/tecnico/dsi/openstack/keystone/models/Role.scala +++ b/src/main/scala/pt/tecnico/dsi/openstack/keystone/models/Role.scala @@ -1,7 +1,7 @@ package pt.tecnico.dsi.openstack.keystone.models import io.circe.derivation.{deriveDecoder, deriveEncoder, renaming} -import io.circe.{Decoder, Encoder} +import io.circe.{Decoder, Encoder, HCursor} import pt.tecnico.dsi.openstack.common.models.{Identifiable, Link} object Role { @@ -36,7 +36,19 @@ object Role { name: Option[String] = None, description: Option[String] = None, ) + + object Assignment { + implicit val decoder: Decoder[Assignment] = { cursor: HCursor => + for { + // TODO: How to test if downField worked? + projectId <- cursor.downField("scope").downField("project").downField("id").as[String] + } yield Assignment(projectId) + } + } + + case class Assignment(projectId: String) } + case class Role( id: String, name: String, diff --git a/src/main/scala/pt/tecnico/dsi/openstack/keystone/services/Roles.scala b/src/main/scala/pt/tecnico/dsi/openstack/keystone/services/Roles.scala index 05455b9..e307bef 100644 --- a/src/main/scala/pt/tecnico/dsi/openstack/keystone/services/Roles.scala +++ b/src/main/scala/pt/tecnico/dsi/openstack/keystone/services/Roles.scala @@ -3,9 +3,9 @@ package pt.tecnico.dsi.openstack.keystone.services import cats.effect.Sync import cats.syntax.flatMap._ import fs2.Stream +import org.http4s.Status.Conflict import org.http4s.client.{Client, UnexpectedStatus} import org.http4s.{Header, Query, Uri} -import org.http4s.Status.Conflict import pt.tecnico.dsi.openstack.common.services.CrudService import pt.tecnico.dsi.openstack.keystone.models.Role @@ -13,6 +13,13 @@ final class Roles[F[_]: Sync: Client](baseUri: Uri, authToken: Header) extends CrudService[F, Role, Role.Create, Role.Update](baseUri, "role", authToken) with UniqueWithinDomain[F, Role] { + /** + * @param groupId filters the response by groupId + * @return a stream of ids from projects to which a certain group has been assigned a certain role + */ + def assignments(groupId: String): Stream[F, Role.Assignment] = + list[Role.Assignment]("role_assignments", baseUri / "role_assignments", Query.fromPairs("group.id" -> groupId)) + /** * @param name filters the response by a role name. * @param domainId filters the response by a domain ID.