From 8d5d3bdf2fb7bdd10e2d76578aff59a1aab89527 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Victor=20Peter=20Rouven=20M=C3=BCller?= Date: Mon, 31 Jan 2022 18:04:42 +0100 Subject: [PATCH] [JSON-API] User management endpoint adjustments (#12578) * Return an empty object for deleteUser & createUser * Make the field rights for creating a user optional & fix the tests changelog_begin - [HTTP-JSON] Adjusted the response for the createUser & deleteUser endpoint to an empty object instead of "true". This was done to allow possible future extensions to the return type without applying breaking changes. - [HTTP-JSON] Made the field rights optional for the request body of the createUser endpoint. Now it is possible to create a user with just the userId (i.e. { "userId": "nice.user" }). changelog_end --- ...ServiceIntegrationTestUserManagement.scala | 87 +++++++++++++------ .../com/digitalasset/http/Endpoints.scala | 15 ++-- .../scala/com/digitalasset/http/domain.scala | 2 +- 3 files changed, 72 insertions(+), 32 deletions(-) diff --git a/ledger-service/http-json/src/it/scala/http/HttpServiceIntegrationTestUserManagement.scala b/ledger-service/http-json/src/it/scala/http/HttpServiceIntegrationTestUserManagement.scala index 7dcdcae06dc8..bce4f79202e9 100644 --- a/ledger-service/http-json/src/it/scala/http/HttpServiceIntegrationTestUserManagement.scala +++ b/ledger-service/http-json/src/it/scala/http/HttpServiceIntegrationTestUserManagement.scala @@ -259,14 +259,15 @@ class HttpServiceIntegrationTestUserManagementNoAuth participantAdminJwt ) { (uri, _, _, _, _) => import spray.json._ - import spray.json.DefaultJsonProtocol._ val alice = getUniqueParty("Alice") val createUserRequest = domain.CreateUserRequest( "nice.user2", Some(alice.unwrap), - List[domain.UserRight]( - domain.CanActAs(alice), - domain.ParticipantAdmin, + Some( + List[domain.UserRight]( + domain.CanActAs(alice), + domain.ParticipantAdmin, + ) ), ) for { @@ -275,11 +276,39 @@ class HttpServiceIntegrationTestUserManagementNoAuth createUserRequest.toJson, headers = authorizationHeader(participantAdminJwt), ) - assertion <- { - status shouldBe StatusCodes.OK - getResult(output).convertTo[Boolean] shouldBe true - } - } yield assertion + } yield { + status shouldBe StatusCodes.OK + getResult(output) shouldBe JsObject() + } + } + + "creating a user with default values should be possible via the user/create endpoint" in withHttpServiceAndClient( + participantAdminJwt + ) { (uri, _, _, _, _) => + import spray.json._ + val username = getUniqueUserName("nice.user") + for { + (status, output) <- postRequest( + uri.withPath(Uri.Path("/v1/user/create")), + JsObject("userId" -> JsString(username)), + headers = authorizationHeader(participantAdminJwt), + ) + _ <- status shouldBe StatusCodes.OK + (status2, output2) <- postRequest( + uri.withPath(Uri.Path("/v1/user")), + domain.GetUserRequest(username).toJson, + headers = authorizationHeader(participantAdminJwt), + ) + _ <- status2 shouldBe StatusCodes.OK + _ <- getResult(output2).convertTo[UserDetails] shouldEqual UserDetails(username, None) + (status3, output3) <- postRequest( + uri.withPath(Uri.Path("/v1/user/rights")), + domain.ListUserRightsRequest(username).toJson, + headers = authorizationHeader(participantAdminJwt), + ) + _ <- status3 shouldBe StatusCodes.OK + } yield getResult(output3) + .convertTo[List[domain.UserRight]] shouldEqual List.empty } "getting all users should be possible via the users endpoint" in withHttpServiceAndClient( @@ -295,9 +324,11 @@ class HttpServiceIntegrationTestUserManagementNoAuth domain.CreateUserRequest( name, Some(alice.unwrap), - List[domain.UserRight]( - domain.CanActAs(alice), - domain.ParticipantAdmin, + Some( + List[domain.UserRight]( + domain.CanActAs(alice), + domain.ParticipantAdmin, + ) ), ) ) @@ -325,14 +356,15 @@ class HttpServiceIntegrationTestUserManagementNoAuth participantAdminJwt ) { (uri, _, _, _, _) => import spray.json._ - import spray.json.DefaultJsonProtocol._ val alice = getUniqueParty("Alice") val createUserRequest = domain.CreateUserRequest( getUniqueUserName("nice.user"), Some(alice.unwrap), - List[domain.UserRight]( - domain.CanActAs(alice), - domain.ParticipantAdmin, + Some( + List[domain.UserRight]( + domain.CanActAs(alice), + domain.ParticipantAdmin, + ) ), ) for { @@ -343,7 +375,7 @@ class HttpServiceIntegrationTestUserManagementNoAuth ) _ <- { status1 shouldBe StatusCodes.OK - getResult(output1).convertTo[Boolean] shouldBe true + getResult(output1) shouldBe JsObject() } (status2, output2) <- postRequest( uri.withPath(Uri.Path(s"/v1/user")), @@ -363,14 +395,15 @@ class HttpServiceIntegrationTestUserManagementNoAuth participantAdminJwt ) { (uri, _, _, _, _) => import spray.json._ - import spray.json.DefaultJsonProtocol._ val alice = getUniqueParty("Alice") val createUserRequest = domain.CreateUserRequest( getUniqueUserName("nice.user"), Some(alice.unwrap), - List[domain.UserRight]( - domain.CanActAs(alice), - domain.ParticipantAdmin, + Some( + List[domain.UserRight]( + domain.CanActAs(alice), + domain.ParticipantAdmin, + ) ), ) for { @@ -381,7 +414,7 @@ class HttpServiceIntegrationTestUserManagementNoAuth ) _ <- { status1 shouldBe StatusCodes.OK - getResult(output1).convertTo[Boolean] shouldBe true + getResult(output1) shouldBe JsObject() } (status2, output2) <- getRequest( uri.withPath(Uri.Path(s"/v1/user")), @@ -405,9 +438,11 @@ class HttpServiceIntegrationTestUserManagementNoAuth val createUserRequest = domain.CreateUserRequest( getUniqueUserName("nice.user"), Some(alice.unwrap), - List[domain.UserRight]( - domain.CanActAs(alice), - domain.ParticipantAdmin, + Some( + List[domain.UserRight]( + domain.CanActAs(alice), + domain.ParticipantAdmin, + ) ), ) for { @@ -418,7 +453,7 @@ class HttpServiceIntegrationTestUserManagementNoAuth ) _ <- { status1 shouldBe StatusCodes.OK - getResult(output1).convertTo[Boolean] shouldBe true + getResult(output1) shouldBe JsObject() } (status2, _) <- postRequest( uri.withPath(Uri.Path(s"/v1/user/delete")), diff --git a/ledger-service/http-json/src/main/scala/com/digitalasset/http/Endpoints.scala b/ledger-service/http-json/src/main/scala/com/digitalasset/http/Endpoints.scala index 7a95e34d6914..f9988a799c3f 100644 --- a/ledger-service/http-json/src/main/scala/com/digitalasset/http/Endpoints.scala +++ b/ledger-service/http-json/src/main/scala/com/digitalasset/http/Endpoints.scala @@ -484,12 +484,12 @@ class Endpoints( def deleteUser(req: HttpRequest)(implicit lc: LoggingContextOf[InstanceUUID with RequestID] - ): ET[domain.SyncResponse[Boolean]] = + ): ET[domain.SyncResponse[spray.json.JsObject]] = proxyWithCommandET { (jwt, deleteUserRequest: domain.DeleteUserRequest) => for { userId <- parseUserId(deleteUserRequest.userId) _ <- EitherT.rightT(userManagementClient.deleteUser(userId, Some(jwt.value))) - } yield domain.OkResponse(true): domain.SyncResponse[Boolean] + } yield emptyObjectResponse }(req) def listUsers(req: HttpRequest)(implicit @@ -596,7 +596,7 @@ class Endpoints( def createUser(req: HttpRequest)(implicit lc: LoggingContextOf[InstanceUUID with RequestID] - ): ET[domain.SyncResponse[Boolean]] = + ): ET[domain.SyncResponse[spray.json.JsObject]] = proxyWithCommand { (jwt, createUserRequest: domain.CreateUserRequest) => { import scalaz.std.option._ @@ -609,7 +609,9 @@ class Endpoints( primaryParty <- createUserRequest.primaryParty.traverse(it => Ref.Party.fromString(it).disjunction ) - rights <- domain.UserRights.toLedgerUserRights(createUserRequest.rights) + rights <- domain.UserRights.toLedgerUserRights( + createUserRequest.rights.getOrElse(List.empty) + ) } yield (username, primaryParty, rights) for { info <- EitherT.either(input.leftMap(InvalidUserInput)): ET[ @@ -623,7 +625,7 @@ class Endpoints( Some(jwt.value), ) ) - } yield domain.OkResponse(true): domain.SyncResponse[Boolean] + } yield emptyObjectResponse }.run }(req) @@ -926,6 +928,9 @@ class Endpoints( UserId.fromString(rawUserId).disjunction.leftMap(InvalidUserInput) ) } + + private val emptyObjectResponse: domain.SyncResponse[spray.json.JsObject] = + domain.OkResponse(spray.json.JsObject()) } object Endpoints { diff --git a/ledger-service/http-json/src/main/scala/com/digitalasset/http/domain.scala b/ledger-service/http-json/src/main/scala/com/digitalasset/http/domain.scala index f107bd017bec..febe6a5616fc 100644 --- a/ledger-service/http-json/src/main/scala/com/digitalasset/http/domain.scala +++ b/ledger-service/http-json/src/main/scala/com/digitalasset/http/domain.scala @@ -174,7 +174,7 @@ object domain extends com.daml.fetchcontracts.domain.Aliases { final case class CreateUserRequest( userId: String, primaryParty: Option[String], - rights: List[UserRight], + rights: Option[List[UserRight]], ) final case class ListUserRightsRequest(userId: String)