diff --git a/connect/lib/core/src/main/scala/io/iohk/atala/connect/core/model/ConnectionRecord.scala b/connect/lib/core/src/main/scala/io/iohk/atala/connect/core/model/ConnectionRecord.scala index 5048aa1935..96de1bb7fa 100644 --- a/connect/lib/core/src/main/scala/io/iohk/atala/connect/core/model/ConnectionRecord.scala +++ b/connect/lib/core/src/main/scala/io/iohk/atala/connect/core/model/ConnectionRecord.scala @@ -28,7 +28,7 @@ case class ConnectionRecord( id: UUID, createdAt: Instant, updatedAt: Option[Instant], - thid: Option[UUID], + thid: String, label: Option[String], role: Role, protocolState: ProtocolState, diff --git a/connect/lib/core/src/main/scala/io/iohk/atala/connect/core/model/error/ConnectionServiceError.scala b/connect/lib/core/src/main/scala/io/iohk/atala/connect/core/model/error/ConnectionServiceError.scala index a0ff1902a9..dfa93f00d2 100644 --- a/connect/lib/core/src/main/scala/io/iohk/atala/connect/core/model/error/ConnectionServiceError.scala +++ b/connect/lib/core/src/main/scala/io/iohk/atala/connect/core/model/error/ConnectionServiceError.scala @@ -7,7 +7,7 @@ sealed trait ConnectionServiceError object ConnectionServiceError { final case class RepositoryError(cause: Throwable) extends ConnectionServiceError final case class RecordIdNotFound(recordId: UUID) extends ConnectionServiceError - final case class ThreadIdNotFound(thid: UUID) extends ConnectionServiceError + final case class ThreadIdNotFound(thid: String) extends ConnectionServiceError final case class InvitationParsingError(cause: Throwable) extends ConnectionServiceError final case class UnexpectedError(msg: String) extends ConnectionServiceError final case class InvalidFlowStateError(msg: String) extends ConnectionServiceError diff --git a/connect/lib/core/src/main/scala/io/iohk/atala/connect/core/repository/ConnectionRepository.scala b/connect/lib/core/src/main/scala/io/iohk/atala/connect/core/repository/ConnectionRepository.scala index 8a55e2af75..11d70c556c 100644 --- a/connect/lib/core/src/main/scala/io/iohk/atala/connect/core/repository/ConnectionRepository.scala +++ b/connect/lib/core/src/main/scala/io/iohk/atala/connect/core/repository/ConnectionRepository.scala @@ -21,7 +21,7 @@ trait ConnectionRepository[F[_]] { def deleteConnectionRecord(recordId: UUID): F[Int] - def getConnectionRecordByThreadId(thid: UUID): F[Option[ConnectionRecord]] + def getConnectionRecordByThreadId(thid: String): F[Option[ConnectionRecord]] def updateWithConnectionRequest( recordId: UUID, diff --git a/connect/lib/core/src/main/scala/io/iohk/atala/connect/core/repository/ConnectionRepositoryInMemory.scala b/connect/lib/core/src/main/scala/io/iohk/atala/connect/core/repository/ConnectionRepositoryInMemory.scala index 6390f80e3c..6ffc6df8dc 100644 --- a/connect/lib/core/src/main/scala/io/iohk/atala/connect/core/repository/ConnectionRepositoryInMemory.scala +++ b/connect/lib/core/src/main/scala/io/iohk/atala/connect/core/repository/ConnectionRepositoryInMemory.scala @@ -134,10 +134,10 @@ class ConnectionRepositoryInMemory(storeRef: Ref[Map[UUID, ConnectionRecord]]) e .getOrElse(ZIO.succeed(0)) } yield count - override def getConnectionRecordByThreadId(thid: UUID): Task[Option[ConnectionRecord]] = { + override def getConnectionRecordByThreadId(thid: String): Task[Option[ConnectionRecord]] = { for { store <- storeRef.get - } yield store.values.find(_.thid.contains(thid)) + } yield store.values.find(_.thid.toString == thid) } override def getConnectionRecords: Task[Seq[ConnectionRecord]] = { @@ -161,16 +161,13 @@ class ConnectionRepositoryInMemory(storeRef: Ref[Map[UUID, ConnectionRecord]]) e override def createConnectionRecord(record: ConnectionRecord): Task[Int] = { for { - _ <- record.thid match - case None => ZIO.unit - case Some(value) => - for { - store <- storeRef.get - maybeRecord <- ZIO.succeed(store.values.find(_.thid == record.thid)) - _ <- maybeRecord match - case None => ZIO.unit - case Some(value) => ZIO.fail(UniqueConstraintViolation("Unique Constraint Violation on 'thid'")) - } yield () + _ <- for { + store <- storeRef.get + maybeRecord <- ZIO.succeed(store.values.find(_.thid == record.thid)) + _ <- maybeRecord match + case None => ZIO.unit + case Some(value) => ZIO.fail(UniqueConstraintViolation("Unique Constraint Violation on 'thid'")) + } yield () _ <- storeRef.update(r => r + (record.id -> record)) } yield 1 } diff --git a/connect/lib/core/src/main/scala/io/iohk/atala/connect/core/service/ConnectionService.scala b/connect/lib/core/src/main/scala/io/iohk/atala/connect/core/service/ConnectionService.scala index 5ea9ac1c7e..5bcb2f78bb 100644 --- a/connect/lib/core/src/main/scala/io/iohk/atala/connect/core/service/ConnectionService.scala +++ b/connect/lib/core/src/main/scala/io/iohk/atala/connect/core/service/ConnectionService.scala @@ -40,9 +40,10 @@ trait ConnectionService { states: ConnectionRecord.ProtocolState* ): IO[ConnectionServiceError, Seq[ConnectionRecord]] - /** Get the ConnectionRecord by the record id. If the record is id is not found the value None will be return */ def getConnectionRecord(recordId: UUID): IO[ConnectionServiceError, Option[ConnectionRecord]] + def getConnectionRecordByThreadId(thid: String): IO[ConnectionServiceError, Option[ConnectionRecord]] + def deleteConnectionRecord(recordId: UUID): IO[ConnectionServiceError, Int] def reportProcessingFailure(recordId: UUID, failReason: Option[String]): IO[ConnectionServiceError, Unit] diff --git a/connect/lib/core/src/main/scala/io/iohk/atala/connect/core/service/ConnectionServiceImpl.scala b/connect/lib/core/src/main/scala/io/iohk/atala/connect/core/service/ConnectionServiceImpl.scala index 2779a5c2aa..1bfab0c5ef 100644 --- a/connect/lib/core/src/main/scala/io/iohk/atala/connect/core/service/ConnectionServiceImpl.scala +++ b/connect/lib/core/src/main/scala/io/iohk/atala/connect/core/service/ConnectionServiceImpl.scala @@ -32,7 +32,7 @@ private class ConnectionServiceImpl( id = UUID.fromString(invitation.id), createdAt = Instant.now, updatedAt = None, - thid = Some(UUID.fromString(invitation.id)), // this is the default, can't with just use None? + thid = invitation.id, label = label, role = ConnectionRecord.Role.Inviter, protocolState = ConnectionRecord.ProtocolState.InvitationGenerated, @@ -80,6 +80,13 @@ private class ConnectionServiceImpl( } yield record } + override def getConnectionRecordByThreadId(thid: String): IO[ConnectionServiceError, Option[ConnectionRecord]] = + for { + record <- connectionRepository + .getConnectionRecordByThreadId(thid) + .mapError(RepositoryError.apply) + } yield record + override def deleteConnectionRecord(recordId: UUID): IO[ConnectionServiceError, Int] = ??? override def receiveConnectionInvitation(invitation: String): IO[ConnectionServiceError, ConnectionRecord] = @@ -88,7 +95,7 @@ private class ConnectionServiceImpl( .fromEither(io.circe.parser.decode[Invitation](Base64Utils.decodeUrlToString(invitation))) .mapError(err => InvitationParsingError(err)) _ <- connectionRepository - .getConnectionRecordByThreadId(UUID.fromString(invitation.id)) + .getConnectionRecordByThreadId(invitation.id) .mapError(RepositoryError.apply) .flatMap { case None => ZIO.unit @@ -99,9 +106,8 @@ private class ConnectionServiceImpl( id = UUID.randomUUID(), createdAt = Instant.now, updatedAt = None, - thid = Some( - UUID.fromString(invitation.id) - ), // TODO: According to the standard, we should rather use 'pthid' and not 'thid' + // TODO: According to the standard, we should rather use 'pthid' and not 'thid' + thid = invitation.id, label = None, role = ConnectionRecord.Role.Invitee, protocolState = ConnectionRecord.ProtocolState.InvitationReceived, @@ -285,7 +291,6 @@ private class ConnectionServiceImpl( thid <- ZIO .fromOption(thid) .mapError(_ => UnexpectedError("No `thid` found in credential request")) - .map(UUID.fromString) maybeRecord <- connectionRepository .getConnectionRecordByThreadId(thid) .mapError(RepositoryError.apply) diff --git a/connect/lib/core/src/test/scala/io/iohk/atala/connect/core/repository/ConnectionRepositorySpecSuite.scala b/connect/lib/core/src/test/scala/io/iohk/atala/connect/core/repository/ConnectionRepositorySpecSuite.scala index 07ad0fffb9..877e6662b0 100644 --- a/connect/lib/core/src/test/scala/io/iohk/atala/connect/core/repository/ConnectionRepositorySpecSuite.scala +++ b/connect/lib/core/src/test/scala/io/iohk/atala/connect/core/repository/ConnectionRepositorySpecSuite.scala @@ -20,7 +20,7 @@ object ConnectionRepositorySpecSuite { UUID.randomUUID, Instant.ofEpochSecond(Instant.now.getEpochSecond), None, - None, + UUID.randomUUID().toString, None, ConnectionRecord.Role.Inviter, ConnectionRecord.ProtocolState.InvitationGenerated, @@ -56,9 +56,9 @@ object ConnectionRepositorySpecSuite { test("createConnectionRecord prevents creation of 2 records with the same thid") { for { repo <- ZIO.service[ConnectionRepository[Task]] - thid = UUID.randomUUID() - aRecord = connectionRecord.copy(thid = Some(thid)) - bRecord = connectionRecord.copy(thid = Some(thid)) + thid = UUID.randomUUID().toString + aRecord = connectionRecord.copy(thid = thid) + bRecord = connectionRecord.copy(thid = thid) aCount <- repo.createConnectionRecord(aRecord) bCount <- repo.createConnectionRecord(bRecord).exit } yield { @@ -208,8 +208,8 @@ object ConnectionRepositorySpecSuite { test("getConnectionRecordByThreadId correctly returns an existing thid") { for { repo <- ZIO.service[ConnectionRepository[Task]] - thid = UUID.randomUUID() - aRecord = connectionRecord.copy(thid = Some(thid)) + thid = UUID.randomUUID().toString + aRecord = connectionRecord.copy(thid = thid) bRecord = connectionRecord _ <- repo.createConnectionRecord(aRecord) _ <- repo.createConnectionRecord(bRecord) @@ -219,11 +219,11 @@ object ConnectionRepositorySpecSuite { test("getConnectionRecordByThreadId returns nothing for an unknown thid") { for { repo <- ZIO.service[ConnectionRepository[Task]] - aRecord = connectionRecord.copy(thid = Some(UUID.randomUUID())) - bRecord = connectionRecord.copy(thid = Some(UUID.randomUUID())) + aRecord = connectionRecord.copy(thid = UUID.randomUUID().toString) + bRecord = connectionRecord.copy(thid = UUID.randomUUID().toString) _ <- repo.createConnectionRecord(aRecord) _ <- repo.createConnectionRecord(bRecord) - record <- repo.getConnectionRecordByThreadId(UUID.randomUUID()) + record <- repo.getConnectionRecordByThreadId(UUID.randomUUID().toString) } yield assertTrue(record.isEmpty) }, test("updateConnectionProtocolState updates the record") { diff --git a/connect/lib/core/src/test/scala/io/iohk/atala/connect/core/service/ConnectionServiceImplSpec.scala b/connect/lib/core/src/test/scala/io/iohk/atala/connect/core/service/ConnectionServiceImplSpec.scala index 39b843cb0e..0542779544 100644 --- a/connect/lib/core/src/test/scala/io/iohk/atala/connect/core/service/ConnectionServiceImplSpec.scala +++ b/connect/lib/core/src/test/scala/io/iohk/atala/connect/core/service/ConnectionServiceImplSpec.scala @@ -1,19 +1,18 @@ package io.iohk.atala.connect.core.service -import io.iohk.atala.connect.core.model.ConnectionRecord._ -import io.iohk.atala.connect.core.repository.ConnectionRepositoryInMemory - -import zio._ -import zio.test._ -import zio.test.Assertion._ -import io.iohk.atala.mercury.model.DidId +import io.circe.syntax.* import io.iohk.atala.connect.core.model.ConnectionRecord -import java.util.UUID +import io.iohk.atala.connect.core.model.ConnectionRecord.* import io.iohk.atala.connect.core.model.error.ConnectionServiceError -import java.time.Instant -import io.circe.syntax._ -import io.iohk.atala.mercury.model.Message +import io.iohk.atala.connect.core.repository.ConnectionRepositoryInMemory +import io.iohk.atala.mercury.model.{DidId, Message} import io.iohk.atala.mercury.protocol.connection.ConnectionResponse +import zio.* +import zio.test.* +import zio.test.Assertion.* + +import java.time.Instant +import java.util.UUID object ConnectionServiceImplSpec extends ZIOSpecDefault { @@ -32,7 +31,7 @@ object ConnectionServiceImplSpec extends ZIOSpecDefault { assertTrue(record.role == Role.Inviter) && assertTrue(record.connectionRequest.isEmpty) && assertTrue(record.connectionResponse.isEmpty) && - assertTrue(record.thid.contains(record.id)) && + assertTrue(record.thid == record.id.toString) && assertTrue(record.updatedAt.isEmpty) && assertTrue(record.invitation.from == did) && assertTrue(record.invitation.attachments.isEmpty) && @@ -113,7 +112,7 @@ object ConnectionServiceImplSpec extends ZIOSpecDefault { assertTrue(inviteeRecord.role == Role.Invitee) && assertTrue(inviteeRecord.connectionRequest.isEmpty) && assertTrue(inviteeRecord.connectionResponse.isEmpty) && - assertTrue(inviteeRecord.thid.contains(UUID.fromString(inviterRecord.invitation.id))) && + assertTrue(inviteeRecord.thid == inviterRecord.invitation.id) && assertTrue(inviteeRecord.updatedAt.isEmpty) && assertTrue(inviteeRecord.invitation == inviterRecord.invitation) } diff --git a/connect/lib/sql-doobie/src/main/scala/io/iohk/atala/connect/sql/repository/JdbcConnectionRepository.scala b/connect/lib/sql-doobie/src/main/scala/io/iohk/atala/connect/sql/repository/JdbcConnectionRepository.scala index d3ba4f029e..0f3421ca24 100644 --- a/connect/lib/sql-doobie/src/main/scala/io/iohk/atala/connect/sql/repository/JdbcConnectionRepository.scala +++ b/connect/lib/sql-doobie/src/main/scala/io/iohk/atala/connect/sql/repository/JdbcConnectionRepository.scala @@ -1,16 +1,15 @@ package io.iohk.atala.connect.sql.repository +import cats.data.NonEmptyList import doobie.* import doobie.implicits.* -import doobie.postgres.implicits._ -import io.circe._ -import io.circe.parser._ -import io.circe.syntax._ -import io.iohk.atala.connect.core.model.ConnectionRecord -import io.iohk.atala.connect.core.model.ConnectionRecord.ProtocolState -import io.iohk.atala.connect.core.model.ConnectionRecord.Role +import doobie.postgres.implicits.* +import io.circe.* +import io.circe.parser.* +import io.circe.syntax.* import io.iohk.atala.connect.core.model.* -import io.iohk.atala.connect.core.model.error.ConnectionRepositoryError._ +import io.iohk.atala.connect.core.model.ConnectionRecord.{ProtocolState, Role} +import io.iohk.atala.connect.core.model.error.ConnectionRepositoryError.* import io.iohk.atala.connect.core.repository.ConnectionRepository import io.iohk.atala.mercury.protocol.connection.* import io.iohk.atala.mercury.protocol.invitation.v2.Invitation @@ -20,7 +19,6 @@ import zio.interop.catz.* import java.time.Instant import java.util.UUID -import cats.data.NonEmptyList class JdbcConnectionRepository(xa: Transactor[Task]) extends ConnectionRepository[Task] { @@ -184,7 +182,7 @@ class JdbcConnectionRepository(xa: Transactor[Task]) extends ConnectionRepositor .transact(xa) } - override def getConnectionRecordByThreadId(thid: UUID): Task[Option[ConnectionRecord]] = { + override def getConnectionRecordByThreadId(thid: String): Task[Option[ConnectionRecord]] = { val cxnIO = sql""" | SELECT | id, diff --git a/pollux/lib/core/src/main/scala/io/iohk/atala/pollux/core/service/CredentialService.scala b/pollux/lib/core/src/main/scala/io/iohk/atala/pollux/core/service/CredentialService.scala index 4a828e5caa..e2737f03b2 100644 --- a/pollux/lib/core/src/main/scala/io/iohk/atala/pollux/core/service/CredentialService.scala +++ b/pollux/lib/core/src/main/scala/io/iohk/atala/pollux/core/service/CredentialService.scala @@ -20,11 +20,6 @@ import java.util.UUID trait CredentialService { - /** Copy pasted from Castor codebase for now TODO: replace with actual data from castor later - * - * @param method - * @param methodSpecificId - */ final case class DID( method: String, methodSpecificId: String @@ -63,11 +58,6 @@ trait CredentialService { issuingDID: Option[CanonicalPrismDID] ): IO[CredentialServiceError, IssueCredentialRecord] - /** Return the full list of CredentialRecords. - * - * TODO this function API maybe change in the future to return a lazy sequence of records or something similar to a - * batabase cursor. - */ def getIssueCredentialRecords: IO[CredentialServiceError, Seq[IssueCredentialRecord]] def getIssueCredentialRecordsByStates( @@ -76,11 +66,10 @@ trait CredentialService { states: IssueCredentialRecord.ProtocolState* ): IO[CredentialServiceError, Seq[IssueCredentialRecord]] - /** Get the CredentialRecord by the record's id. If the record's id is not found the value None will be return - * instead. - */ def getIssueCredentialRecord(recordId: DidCommID): IO[CredentialServiceError, Option[IssueCredentialRecord]] + def getIssueCredentialRecordByThreadId(thid: DidCommID): IO[CredentialServiceError, Option[IssueCredentialRecord]] + def receiveCredentialOffer(offer: OfferCredential): IO[CredentialServiceError, IssueCredentialRecord] def acceptCredentialOffer(recordId: DidCommID, subjectId: String): IO[CredentialServiceError, IssueCredentialRecord] diff --git a/pollux/lib/core/src/main/scala/io/iohk/atala/pollux/core/service/CredentialServiceImpl.scala b/pollux/lib/core/src/main/scala/io/iohk/atala/pollux/core/service/CredentialServiceImpl.scala index ff9164fa4c..c9132498df 100644 --- a/pollux/lib/core/src/main/scala/io/iohk/atala/pollux/core/service/CredentialServiceImpl.scala +++ b/pollux/lib/core/src/main/scala/io/iohk/atala/pollux/core/service/CredentialServiceImpl.scala @@ -55,6 +55,15 @@ private class CredentialServiceImpl( } yield records } + override def getIssueCredentialRecordByThreadId( + thid: DidCommID + ): IO[CredentialServiceError, Option[IssueCredentialRecord]] = + for { + record <- credentialRepository + .getIssueCredentialRecordByThreadId(thid) + .mapError(RepositoryError.apply) + } yield record + override def getIssueCredentialRecord( recordId: DidCommID ): IO[CredentialServiceError, Option[IssueCredentialRecord]] = { diff --git a/pollux/lib/core/src/main/scala/io/iohk/atala/pollux/core/service/PresentationService.scala b/pollux/lib/core/src/main/scala/io/iohk/atala/pollux/core/service/PresentationService.scala index d623338556..7d54a26c58 100644 --- a/pollux/lib/core/src/main/scala/io/iohk/atala/pollux/core/service/PresentationService.scala +++ b/pollux/lib/core/src/main/scala/io/iohk/atala/pollux/core/service/PresentationService.scala @@ -41,6 +41,8 @@ trait PresentationService { def getPresentationRecord(recordId: DidCommID): IO[PresentationError, Option[PresentationRecord]] + def getPresentationRecordByThreadId(thid: DidCommID): IO[PresentationError, Option[PresentationRecord]] + def receiveRequestPresentation( connectionId: Option[String], request: RequestPresentation diff --git a/pollux/lib/core/src/main/scala/io/iohk/atala/pollux/core/service/PresentationServiceImpl.scala b/pollux/lib/core/src/main/scala/io/iohk/atala/pollux/core/service/PresentationServiceImpl.scala index caa28266b6..1cb2cb6a0c 100644 --- a/pollux/lib/core/src/main/scala/io/iohk/atala/pollux/core/service/PresentationServiceImpl.scala +++ b/pollux/lib/core/src/main/scala/io/iohk/atala/pollux/core/service/PresentationServiceImpl.scala @@ -106,6 +106,13 @@ private class PresentationServiceImpl( } yield record } + override def getPresentationRecordByThreadId(thid: DidCommID): IO[PresentationError, Option[PresentationRecord]] = + for { + record <- presentationRepository + .getPresentationRecordByThreadId(thid) + .mapError(RepositoryError.apply) + } yield record + override def rejectRequestPresentation(recordId: DidCommID): IO[PresentationError, Option[PresentationRecord]] = { markRequestPresentationRejected(recordId) } diff --git a/prism-agent/service/server/src/main/scala/io/iohk/atala/connect/controller/ConnectionController.scala b/prism-agent/service/server/src/main/scala/io/iohk/atala/connect/controller/ConnectionController.scala index 55a9ff09a6..2bb9e0b81a 100644 --- a/prism-agent/service/server/src/main/scala/io/iohk/atala/connect/controller/ConnectionController.scala +++ b/prism-agent/service/server/src/main/scala/io/iohk/atala/connect/controller/ConnectionController.scala @@ -1,6 +1,6 @@ package io.iohk.atala.connect.controller -import io.iohk.atala.api.http.model.Pagination +import io.iohk.atala.api.http.model.PaginationInput import io.iohk.atala.api.http.{ErrorResponse, RequestContext} import io.iohk.atala.connect.controller.http.{ AcceptConnectionInvitationRequest, @@ -22,7 +22,7 @@ trait ConnectionController { rc: RequestContext ): IO[ErrorResponse, Connection] - def getConnections(pagination: Pagination)(implicit + def getConnections(paginationInput: PaginationInput, thid: Option[String])(implicit rc: RequestContext ): IO[ErrorResponse, ConnectionsPage] diff --git a/prism-agent/service/server/src/main/scala/io/iohk/atala/connect/controller/ConnectionControllerImpl.scala b/prism-agent/service/server/src/main/scala/io/iohk/atala/connect/controller/ConnectionControllerImpl.scala index 0ee0ed970f..7332262507 100644 --- a/prism-agent/service/server/src/main/scala/io/iohk/atala/connect/controller/ConnectionControllerImpl.scala +++ b/prism-agent/service/server/src/main/scala/io/iohk/atala/connect/controller/ConnectionControllerImpl.scala @@ -2,7 +2,7 @@ package io.iohk.atala.connect.controller import io.iohk.atala.agent.server.config.AppConfig import io.iohk.atala.agent.walletapi.service.ManagedDIDService -import io.iohk.atala.api.http.model.Pagination +import io.iohk.atala.api.http.model.PaginationInput import io.iohk.atala.api.http.{ErrorResponse, RequestContext} import io.iohk.atala.connect.controller.ConnectionController.toHttpError import io.iohk.atala.connect.controller.http.{ @@ -48,10 +48,13 @@ class ConnectionControllerImpl( } override def getConnections( - pagination: Pagination + paginationInput: PaginationInput, + thid: Option[String] )(implicit rc: RequestContext): IO[ErrorResponse, ConnectionsPage] = { val result = for { - connections <- service.getConnectionRecords() + connections <- thid match + case None => service.getConnectionRecords() + case Some(thid) => service.getConnectionRecordByThreadId(thid).map(_.toSeq) } yield ConnectionsPage(contents = connections.map(Connection.fromDomain)) result.mapError(toHttpError) diff --git a/prism-agent/service/server/src/main/scala/io/iohk/atala/connect/controller/ConnectionEndpoints.scala b/prism-agent/service/server/src/main/scala/io/iohk/atala/connect/controller/ConnectionEndpoints.scala index 2b01ecc09b..713ddb5c7f 100644 --- a/prism-agent/service/server/src/main/scala/io/iohk/atala/connect/controller/ConnectionEndpoints.scala +++ b/prism-agent/service/server/src/main/scala/io/iohk/atala/connect/controller/ConnectionEndpoints.scala @@ -66,11 +66,13 @@ object ConnectionEndpoints { .description("Gets an existing connection record by its unique identifier") .tag("Connections Management") - val getConnections: PublicEndpoint[(RequestContext, PaginationInput), ErrorResponse, ConnectionsPage, Any] = + val getConnections + : PublicEndpoint[(RequestContext, PaginationInput, Option[String]), ErrorResponse, ConnectionsPage, Any] = endpoint.get .in(extractFromRequest[RequestContext](RequestContext.apply)) .in("connections") .in(paginationInput) + .in(query[Option[String]]("thid").description("The thid of a DIDComm communication.")) .out(jsonBody[ConnectionsPage].description("The list of connection records.")) .errorOut(basicFailures) .name("getConnections") diff --git a/prism-agent/service/server/src/main/scala/io/iohk/atala/connect/controller/ConnectionServerEndpoints.scala b/prism-agent/service/server/src/main/scala/io/iohk/atala/connect/controller/ConnectionServerEndpoints.scala index 436f30d960..9dc47e396f 100644 --- a/prism-agent/service/server/src/main/scala/io/iohk/atala/connect/controller/ConnectionServerEndpoints.scala +++ b/prism-agent/service/server/src/main/scala/io/iohk/atala/connect/controller/ConnectionServerEndpoints.scala @@ -22,8 +22,8 @@ class ConnectionServerEndpoints(connectionController: ConnectionController) { } private val getConnectionsServerEndpoint: ZServerEndpoint[Any, Any] = - getConnections.zServerLogic { case (ctx: RequestContext, paginationInput: PaginationInput) => - connectionController.getConnections(paginationInput.toPagination)(ctx) + getConnections.zServerLogic { case (ctx: RequestContext, paginationInput: PaginationInput, thid: Option[String]) => + connectionController.getConnections(paginationInput, thid)(ctx) } private val acceptConnectionInvitationServerEndpoint: ZServerEndpoint[Any, Any] = diff --git a/prism-agent/service/server/src/main/scala/io/iohk/atala/connect/controller/http/Connection.scala b/prism-agent/service/server/src/main/scala/io/iohk/atala/connect/controller/http/Connection.scala index ace4775662..8a1a9d4252 100644 --- a/prism-agent/service/server/src/main/scala/io/iohk/atala/connect/controller/http/Connection.scala +++ b/prism-agent/service/server/src/main/scala/io/iohk/atala/connect/controller/http/Connection.scala @@ -16,6 +16,9 @@ case class Connection( @description(annotations.connectionId.description) @encodedExample(annotations.connectionId.example) connectionId: UUID, + @description(annotations.thid.description) + @encodedExample(annotations.thid.example) + thid: String, @description(annotations.label.description) @encodedExample(annotations.label.example) label: Option[String] = None, @@ -58,6 +61,7 @@ object Connection { def fromDomain(domain: model.ConnectionRecord): Connection = Connection( connectionId = domain.id, + thid = domain.thid, label = domain.label, myDid = domain.role match case Role.Inviter => @@ -87,6 +91,13 @@ object Connection { example = UUID.fromString("0527aea1-d131-3948-a34d-03af39aba8b4") ) + object thid + extends Annotation[String]( + description = "The unique identifier of the thread this connection record belongs to. " + + "The value will identical on both sides of the connection (inviter and invitee)", + example = "0527aea1-d131-3948-a34d-03af39aba8b4" + ) + object label extends Annotation[String]( description = "A human readable alias for the connection.", diff --git a/prism-agent/service/server/src/main/scala/io/iohk/atala/issue/controller/IssueControllerImpl.scala b/prism-agent/service/server/src/main/scala/io/iohk/atala/issue/controller/IssueControllerImpl.scala index 0b49f4e919..901cda9f7f 100644 --- a/prism-agent/service/server/src/main/scala/io/iohk/atala/issue/controller/IssueControllerImpl.scala +++ b/prism-agent/service/server/src/main/scala/io/iohk/atala/issue/controller/IssueControllerImpl.scala @@ -54,17 +54,16 @@ class IssueControllerImpl( rc: RequestContext ): IO[ErrorResponse, IssueCredentialRecordPage] = { val result = for { - records <- credentialService.getIssueCredentialRecords - outcome = thid match - case None => records - case Some(value) => records.filter(_.thid.value == value) // this logic should be moved to the DB + records <- thid match + case None => credentialService.getIssueCredentialRecords + case Some(thid) => credentialService.getIssueCredentialRecordByThreadId(DidCommID(thid)).map(_.toSeq) } yield IssueCredentialRecordPage( self = "/issue-credentials/records", kind = "Collection", pageOf = "1", next = None, previous = None, - contents = (outcome map IssueCredentialRecord.fromDomain) // TODO - Tech Debt - Optimise this transformation - each time we get a list of things we iterate it once here + contents = (records map IssueCredentialRecord.fromDomain) // TODO - Tech Debt - Optimise this transformation - each time we get a list of things we iterate it once here ) mapIssueErrors(result) } diff --git a/prism-agent/service/server/src/main/scala/io/iohk/atala/issue/controller/http/IssueCredentialRecord.scala b/prism-agent/service/server/src/main/scala/io/iohk/atala/issue/controller/http/IssueCredentialRecord.scala index 8911b94a5d..317587db09 100644 --- a/prism-agent/service/server/src/main/scala/io/iohk/atala/issue/controller/http/IssueCredentialRecord.scala +++ b/prism-agent/service/server/src/main/scala/io/iohk/atala/issue/controller/http/IssueCredentialRecord.scala @@ -12,6 +12,7 @@ import zio.json.ast.Json import java.nio.charset.StandardCharsets import java.time.{OffsetDateTime, ZoneOffset} +import java.util.UUID /** A class to represent an an outgoing response for a created credential offer. * @@ -42,6 +43,12 @@ import java.time.{OffsetDateTime, ZoneOffset} * Issuer DID of the verifiable credential object. for example: ''did:prism:issuerofverifiablecredentials'' */ final case class IssueCredentialRecord( + @description(annotations.recordId.description) + @encodedExample(annotations.recordId.example) + recordId: String, + @description(annotations.thid.description) + @encodedExample(annotations.thid.example) + thid: String, @description(annotations.subjectId.description) @encodedExample(annotations.subjectId.example) subjectId: Option[String] = None, @@ -54,9 +61,6 @@ final case class IssueCredentialRecord( @description(annotations.automaticIssuance.description) @encodedExample(annotations.automaticIssuance.example) automaticIssuance: Option[Boolean] = None, - @description(annotations.recordId.description) - @encodedExample(annotations.recordId.example) - recordId: String, @description(annotations.createdAt.description) @encodedExample(annotations.createdAt.example) createdAt: OffsetDateTime, @@ -82,6 +86,7 @@ object IssueCredentialRecord { def fromDomain(domain: PolluxIssueCredentialRecord): IssueCredentialRecord = IssueCredentialRecord( recordId = domain.id.value, + thid = domain.thid.value, createdAt = domain.createdAt.atOffset(ZoneOffset.UTC), updatedAt = domain.updatedAt.map(_.atOffset(ZoneOffset.UTC)), role = domain.role.toString, @@ -147,6 +152,13 @@ object IssueCredentialRecord { example = "80d612dc-0ded-4ac9-90b4-1b8eabb04545" ) + object thid + extends Annotation[String]( + description = "The unique identifier of the thread this credential record belongs to. " + + "The value will identical on both sides of the issue flow (issuer and holder)", + example = "0527aea1-d131-3948-a34d-03af39aba8b4" + ) + object createdAt extends Annotation[OffsetDateTime]( description = "The date and time when the issue credential record was created.", diff --git a/prism-agent/service/server/src/main/scala/io/iohk/atala/presentproof/controller/PresentProofController.scala b/prism-agent/service/server/src/main/scala/io/iohk/atala/presentproof/controller/PresentProofController.scala index 5e2c017a48..06643e1027 100644 --- a/prism-agent/service/server/src/main/scala/io/iohk/atala/presentproof/controller/PresentProofController.scala +++ b/prism-agent/service/server/src/main/scala/io/iohk/atala/presentproof/controller/PresentProofController.scala @@ -1,5 +1,6 @@ package io.iohk.atala.presentproof.controller +import io.iohk.atala.api.http.model.PaginationInput import io.iohk.atala.api.http.{ErrorResponse, RequestContext} import io.iohk.atala.pollux.core.model.error.PresentationError import io.iohk.atala.presentproof.controller.http.* @@ -15,9 +16,8 @@ trait PresentProofController { rc: RequestContext ): IO[ErrorResponse, RequestPresentationOutput] - def getAllPresentations( - offset: Option[Int], - limit: Option[Int], + def getPresentations( + paginationInput: PaginationInput, thid: Option[String] )(implicit rc: RequestContext diff --git a/prism-agent/service/server/src/main/scala/io/iohk/atala/presentproof/controller/PresentProofControllerImpl.scala b/prism-agent/service/server/src/main/scala/io/iohk/atala/presentproof/controller/PresentProofControllerImpl.scala index b6b460a800..9515536805 100644 --- a/prism-agent/service/server/src/main/scala/io/iohk/atala/presentproof/controller/PresentProofControllerImpl.scala +++ b/prism-agent/service/server/src/main/scala/io/iohk/atala/presentproof/controller/PresentProofControllerImpl.scala @@ -1,5 +1,6 @@ package io.iohk.atala.presentproof.controller import io.iohk.atala.agent.server.ControllerHelper +import io.iohk.atala.api.http.model.PaginationInput import io.iohk.atala.api.http.{ErrorResponse, RequestContext} import io.iohk.atala.connect.controller.ConnectionController import io.iohk.atala.connect.core.model.error.ConnectionServiceError @@ -49,16 +50,15 @@ class PresentProofControllerImpl( } } - override def getAllPresentations(offset: Option[Int], limit: Option[Int], thid: Option[String])(implicit + override def getPresentations(paginationInput: PaginationInput, thid: Option[String])(implicit rc: RequestContext ): IO[ErrorResponse, PresentationStatusPage] = { val result = for { - records <- presentationService.getPresentationRecords() - filteredRecords = thid match - case None => records - case Some(value) => records.filter(_.thid.value == value) // this logic should be moved to the DB + records <- thid match + case None => presentationService.getPresentationRecords() + case Some(thid) => presentationService.getPresentationRecordByThreadId(DidCommID(thid)).map(_.toSeq) } yield PresentationStatusPage( - filteredRecords.map(PresentationStatus.fromDomain) + records.map(PresentationStatus.fromDomain) ) result.mapError(PresentProofController.toHttpError) diff --git a/prism-agent/service/server/src/main/scala/io/iohk/atala/presentproof/controller/PresentProofServerEndpoints.scala b/prism-agent/service/server/src/main/scala/io/iohk/atala/presentproof/controller/PresentProofServerEndpoints.scala index a8769e20ab..d75bd9a89d 100644 --- a/prism-agent/service/server/src/main/scala/io/iohk/atala/presentproof/controller/PresentProofServerEndpoints.scala +++ b/prism-agent/service/server/src/main/scala/io/iohk/atala/presentproof/controller/PresentProofServerEndpoints.scala @@ -23,7 +23,7 @@ class PresentProofServerEndpoints(presentProofController: PresentProofController private val getAllPresentationsEndpoint: ZServerEndpoint[Any, Any] = getAllPresentations.zServerLogic { case (ctx: RequestContext, paginationInput: PaginationInput, thid: Option[String]) => - presentProofController.getAllPresentations(paginationInput.offset, paginationInput.limit, thid)(ctx) + presentProofController.getPresentations(paginationInput, thid)(ctx) } private val getPresentationEndpoint: ZServerEndpoint[Any, Any] = diff --git a/prism-agent/service/server/src/main/scala/io/iohk/atala/presentproof/controller/http/PresentationStatus.scala b/prism-agent/service/server/src/main/scala/io/iohk/atala/presentproof/controller/http/PresentationStatus.scala index 94a80c6b0c..f7300386e1 100644 --- a/prism-agent/service/server/src/main/scala/io/iohk/atala/presentproof/controller/http/PresentationStatus.scala +++ b/prism-agent/service/server/src/main/scala/io/iohk/atala/presentproof/controller/http/PresentationStatus.scala @@ -12,6 +12,9 @@ final case class PresentationStatus( @description(annotations.presentationId.description) @encodedExample(annotations.presentationId.example) presentationId: String, + @description(annotations.thid.description) + @encodedExample(annotations.thid.example) + thid: String, @description(annotations.status.description) @encodedExample(annotations.status.example) @validate(annotations.status.validator) @@ -41,6 +44,7 @@ object PresentationStatus { case None => Seq.empty PresentationStatus( domain.id.value, + thid = domain.thid.value, status = domain.protocolState.toString, proofs = Seq.empty, data = data, @@ -54,6 +58,14 @@ object PresentationStatus { description = "The unique identifier of the presentation record.", example = "3c6d9fa5-d277-431e-a6cb-d3956e47e610" ) + + object thid + extends Annotation[String]( + description = "The unique identifier of the thread this presentation record belongs to. " + + "The value will identical on both sides of the presentation flow (verifier and prover)", + example = "0527aea1-d131-3948-a34d-03af39aba8b4" + ) + object status extends Annotation[String]( description = "The current state of the proof presentation record.", diff --git a/tests/e2e-tests/src/main/kotlin/api_models/Connection.kt b/tests/e2e-tests/src/main/kotlin/api_models/Connection.kt index 3306601905..cefaf484b6 100644 --- a/tests/e2e-tests/src/main/kotlin/api_models/Connection.kt +++ b/tests/e2e-tests/src/main/kotlin/api_models/Connection.kt @@ -1,6 +1,7 @@ package api_models data class Connection( var connectionId: String = "", + var thid: String = "", var createdAt: String = "", var updatedAt: String = "", var invitation: Invitation = Invitation(), diff --git a/tests/e2e-tests/src/main/kotlin/api_models/Credential.kt b/tests/e2e-tests/src/main/kotlin/api_models/Credential.kt index 2a7082e567..499a3b7eff 100644 --- a/tests/e2e-tests/src/main/kotlin/api_models/Credential.kt +++ b/tests/e2e-tests/src/main/kotlin/api_models/Credential.kt @@ -6,6 +6,7 @@ data class Credential( var createdAt: String = "", var protocolState: String = "", var recordId: String = "", + var thid: String = "", var role: String = "", var schemaId: String? = "", var subjectId: String = "", diff --git a/tests/e2e-tests/src/main/kotlin/api_models/PresentationProof.kt b/tests/e2e-tests/src/main/kotlin/api_models/PresentationProof.kt index 600aff74ba..60c906f158 100644 --- a/tests/e2e-tests/src/main/kotlin/api_models/PresentationProof.kt +++ b/tests/e2e-tests/src/main/kotlin/api_models/PresentationProof.kt @@ -2,6 +2,7 @@ package api_models data class PresentationProof( var presentationId: String? = null, + var thid: String? = null, var status: String? = null, var connectionId: String? = null, var proofs: List? = null,