Skip to content

Commit

Permalink
fix: Credential Defintion Error Handling Part 2 (#1155)
Browse files Browse the repository at this point in the history
Signed-off-by: Bassam Riman <bassam.riman@iohk.io>
  • Loading branch information
CryptoKnightIOG committed Jun 6, 2024
1 parent d6dfb72 commit 2df5306
Show file tree
Hide file tree
Showing 16 changed files with 137 additions and 159 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ package org.hyperledger.identus.pollux.credentialdefinition.controller

import org.hyperledger.identus.api.http.*
import org.hyperledger.identus.api.http.model.{Order, Pagination}
import org.hyperledger.identus.pollux.core.service.CredentialDefinitionService
import org.hyperledger.identus.pollux.core.service.CredentialDefinitionService.Error.*
import org.hyperledger.identus.pollux.core.service.CredentialDefinitionServiceError
import org.hyperledger.identus.pollux.credentialdefinition.http.{
CredentialDefinitionInput,
CredentialDefinitionResponse,
Expand Down Expand Up @@ -45,31 +44,12 @@ trait CredentialDefinitionController {

object CredentialDefinitionController {
def domainToHttpError(
error: CredentialDefinitionService.Error
): ErrorResponse = {
error match {
case RepositoryError(cause: Throwable) =>
ErrorResponse.internalServerError("RepositoryError", detail = Option(cause.toString))
case error: GuidNotFoundError =>
ErrorResponse.notFound(detail = Option(error.message))
case error: IdNotFoundError =>
ErrorResponse.notFound(detail = Option(error.message))
case UpdateError(id, version, author, message) =>
ErrorResponse.badRequest(
title = "CredentialDefinitionUpdateError",
detail = Option(s"Credential definition update error: id=$id, version=$version, author=$author, msg=$message")
)
case CredentialDefinitionCreationError(msg: String) =>
ErrorResponse.badRequest(detail = Option(msg))
case UnexpectedError(msg: String) =>
ErrorResponse.internalServerError(detail = Option(msg))
case CredentialDefinitionValidationError(cause) =>
ErrorResponse.badRequest(detail = Some(cause.message))
}
}
error: CredentialDefinitionServiceError
): ErrorResponse =
error

implicit def domainToHttpErrorIO[R, T](
domainIO: ZIO[R, CredentialDefinitionService.Error, T]
domainIO: ZIO[R, CredentialDefinitionServiceError, T]
): ZIO[R, ErrorResponse, T] = {
domainIO.mapError(domainToHttpError)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@ import org.hyperledger.identus.api.http.*
import org.hyperledger.identus.api.http.model.{CollectionStats, Order, Pagination}
import org.hyperledger.identus.castor.core.model.did.{LongFormPrismDID, PrismDID}
import org.hyperledger.identus.pollux.core.model.schema.CredentialDefinition.FilteredEntries
import org.hyperledger.identus.pollux.core.service.CredentialDefinitionService
import org.hyperledger.identus.pollux.core.service.CredentialDefinitionService.Error.*
import org.hyperledger.identus.pollux.core.service.{CredentialDefinitionService, CredentialDefinitionServiceError}
import org.hyperledger.identus.pollux.credentialdefinition
import org.hyperledger.identus.pollux.credentialdefinition.controller.CredentialDefinitionController.domainToHttpErrorIO
import org.hyperledger.identus.pollux.credentialdefinition.http.{
Expand Down Expand Up @@ -37,8 +36,8 @@ class CredentialDefinitionControllerImpl(service: CredentialDefinitionService, m
.create(toDomain(in))
.map(cs => fromDomain(cs).withBaseUri(rc.request.uri))
} yield result).mapError {
case e: ErrorResponse => e
case e: CredentialDefinitionService.Error => CredentialDefinitionController.domainToHttpError(e)
case e: ErrorResponse => e
case e: CredentialDefinitionServiceError => CredentialDefinitionController.domainToHttpError(e)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ package org.hyperledger.identus.pollux.credentialschema.controller

import org.hyperledger.identus.api.http.*
import org.hyperledger.identus.api.http.model.{Order, Pagination}
import org.hyperledger.identus.pollux.core.service.CredentialSchemaService
import org.hyperledger.identus.pollux.core.service.CredentialSchemaService.*
import org.hyperledger.identus.pollux.core.service.CredentialSchemaServiceError
import org.hyperledger.identus.pollux.credentialschema.http.{
CredentialSchemaInput,
CredentialSchemaResponse,
Expand Down Expand Up @@ -49,11 +48,11 @@ trait CredentialSchemaController {

object CredentialSchemaController {
def domainToHttpError(
error: CredentialSchemaService.Error
error: CredentialSchemaServiceError
): ErrorResponse = error

implicit def domainToHttpErrorIO[R, T](
domainIO: ZIO[R, CredentialSchemaService.Error, T]
domainIO: ZIO[R, CredentialSchemaServiceError, T]
): ZIO[R, ErrorResponse, T] = {
domainIO.mapError(domainToHttpError)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import org.hyperledger.identus.api.http.model.{CollectionStats, Order, Paginatio
import org.hyperledger.identus.castor.core.model.did.{LongFormPrismDID, PrismDID}
import org.hyperledger.identus.pollux.core.model.schema.CredentialSchema.FilteredEntries
import org.hyperledger.identus.pollux.core.service.CredentialSchemaService
import org.hyperledger.identus.pollux.core.service.CredentialSchemaService.*
import org.hyperledger.identus.pollux.credentialschema.controller.CredentialSchemaController.domainToHttpErrorIO
import org.hyperledger.identus.pollux.credentialschema.http.{
CredentialSchemaInput,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,11 +119,11 @@ trait CredentialDefinitionTestTools extends PostgresTestContainerSupport {
backend
}

def deleteAllCredentialDefinitions: RIO[CredentialDefinitionRepository & WalletAccessContext, Long] = {
def deleteAllCredentialDefinitions: RIO[CredentialDefinitionRepository & WalletAccessContext, Unit] = {
for {
repository <- ZIO.service[CredentialDefinitionRepository]
count <- repository.deleteAll()
} yield count
result <- repository.deleteAll()
} yield result
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ object CredentialSchemaAnoncredSpec extends ZIOSpecDefault with CredentialSchema
_.detail,
isSome(
equalTo(
"Credential Schema Validation Error=UnsupportedCredentialSchemaType(Unsupported VC Schema type WrongSchema)"
"Credential Schema Validation Error=Unsupported VC Schema type WrongSchema"
)
)
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,11 @@ import org.hyperledger.identus.agent.walletapi.model.Entity
import org.hyperledger.identus.container.util.MigrationAspects.*
import org.hyperledger.identus.pollux.core.model.schema.`type`.CredentialJsonSchemaType
import org.hyperledger.identus.pollux.core.model.schema.CredentialSchema
import org.hyperledger.identus.pollux.core.service.{CredentialSchemaService, CredentialSchemaServiceImpl}
import org.hyperledger.identus.pollux.core.service.{
CredentialSchemaGuidNotFoundError,
CredentialSchemaService,
CredentialSchemaServiceImpl
}
import org.hyperledger.identus.pollux.sql.repository.JdbcCredentialSchemaRepository
import zio.*
import zio.json.*
Expand Down Expand Up @@ -105,10 +109,10 @@ object CredentialSchemaMultiTenancySpec extends ZIOSpecDefault with CredentialSc
.exit

aliceCannotUpdateBobsVCSchema = assert(notFoundSchemaAError)(
fails(isSubtype[CredentialSchemaService.GuidNotFoundError](anything))
fails(isSubtype[CredentialSchemaGuidNotFoundError](anything))
)
bobCannotUpdateAlicesVCSchema = assert(notFoundSchemaBError)(
fails(isSubtype[CredentialSchemaService.GuidNotFoundError](anything))
fails(isSubtype[CredentialSchemaGuidNotFoundError](anything))
)

fetchedSchemaAbyB <- service.getByGUID(updatedSchemaA.guid).provideLayer(Bob.wacLayer)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,22 @@ package org.hyperledger.identus.pollux.core.repository
import org.hyperledger.identus.pollux.core.model.schema.CredentialDefinition
import org.hyperledger.identus.pollux.core.repository.Repository.SearchCapability
import org.hyperledger.identus.shared.models.WalletAccessContext
import zio.{RIO, Task}
import zio.{UIO, URIO}

import java.util.UUID

trait CredentialDefinitionRepository
extends Repository[WalletTask, CredentialDefinition]
with SearchCapability[WalletTask, CredentialDefinition.Filter, CredentialDefinition] {
def create(cs: CredentialDefinition): RIO[WalletAccessContext, CredentialDefinition]
def create(cs: CredentialDefinition): URIO[WalletAccessContext, CredentialDefinition]

def getByGuid(guid: UUID): Task[Option[CredentialDefinition]]
def findByGuid(guid: UUID): UIO[Option[CredentialDefinition]]

def update(cs: CredentialDefinition): RIO[WalletAccessContext, Option[CredentialDefinition]]
def update(cs: CredentialDefinition): URIO[WalletAccessContext, CredentialDefinition]

def getAllVersions(id: UUID, author: String): RIO[WalletAccessContext, Seq[String]]
def getAllVersions(id: UUID, author: String): URIO[WalletAccessContext, Seq[String]]

def delete(guid: UUID): RIO[WalletAccessContext, Option[CredentialDefinition]]
def delete(guid: UUID): URIO[WalletAccessContext, CredentialDefinition]

def deleteAll(): RIO[WalletAccessContext, Long]
def deleteAll(): URIO[WalletAccessContext, Unit]
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,21 +26,20 @@ class CredentialDefinitionRepositoryInMemory(
}(ZIO.succeed)
} yield walletRef

override def create(record: CredentialDefinition): RIO[WalletAccessContext, CredentialDefinition] = {
override def create(record: CredentialDefinition): URIO[WalletAccessContext, CredentialDefinition] = {
for {
storeRef <- walletStoreRef
_ <- for {
store <- storeRef.get
maybeRecord = store.values.find(_.id == record.guid)
_ <- maybeRecord match
case None => ZIO.unit
case Some(value) => ZIO.fail(UniqueConstraintViolation("Unique Constraint Violation on 'id'"))
maybeRecord = store.values
.find(_.id == record.guid)
.foreach(_ => throw UniqueConstraintViolation("Unique Constraint Violation on 'id'"))
} yield ()
_ <- storeRef.update(r => r + (record.guid -> record))
} yield record
}

override def getByGuid(guid: UUID): Task[Option[CredentialDefinition]] = {
override def findByGuid(guid: UUID): UIO[Option[CredentialDefinition]] = {
for {
storeRefs <- walletRefs.get
storeRefOption <- ZIO.filter(storeRefs.values)(storeRef => storeRef.get.map(_.contains(guid))).map(_.headOption)
Expand All @@ -51,21 +50,19 @@ class CredentialDefinitionRepositoryInMemory(
} yield record
}

override def update(cs: CredentialDefinition): RIO[WalletAccessContext, Option[CredentialDefinition]] = {
override def update(cs: CredentialDefinition): URIO[WalletAccessContext, CredentialDefinition] = {
for {
storeRef <- walletStoreRef
store <- storeRef.get
maybeExisting = store.get(cs.id)
_ <- maybeExisting match {
case Some(existing) =>
val updatedStore = store.updated(cs.id, cs)
storeRef.set(updatedStore)
case None => ZIO.unit
existing = store.getOrElse(cs.id, throw new IllegalStateException("Entity doesn't exists"))
_ <- {
val updatedStore = store.updated(cs.id, cs)
storeRef.set(updatedStore)
}
} yield maybeExisting
} yield existing
}

override def getAllVersions(id: UUID, author: String): RIO[WalletAccessContext, Seq[String]] = {
override def getAllVersions(id: UUID, author: String): URIO[WalletAccessContext, Seq[String]] = {
for {
storeRef <- walletStoreRef
store <- storeRef.get
Expand All @@ -75,25 +72,21 @@ class CredentialDefinitionRepositoryInMemory(
.toSeq
}

override def delete(guid: UUID): RIO[WalletAccessContext, Option[CredentialDefinition]] = {
override def delete(guid: UUID): URIO[WalletAccessContext, CredentialDefinition] = {
for {
storeRef <- walletStoreRef
store <- storeRef.get
maybeRecord = store.get(guid)
_ <- maybeRecord match {
case Some(record) => storeRef.update(r => r - record.id)
case None => ZIO.unit
}
} yield maybeRecord
record = store.getOrElse(guid, throw new IllegalStateException("Entity doesn't exists"))
_ <- storeRef.update(r => r - record.id)
} yield record
}

override def deleteAll(): RIO[WalletAccessContext, Long] = {
override def deleteAll(): URIO[WalletAccessContext, Unit] = {
for {
storeRef <- walletStoreRef
store <- storeRef.get
deleted = store.size
_ <- storeRef.update(Map.empty)
} yield deleted.toLong
} yield ZIO.unit
}

override def search(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import zio.{IO, ZIO}
import java.util.UUID

trait CredentialDefinitionService {
private[service] type Result[T] = ZIO[WalletAccessContext, CredentialDefinitionService.Error, T]
private[service] type Result[T] = ZIO[WalletAccessContext, CredentialDefinitionServiceError, T]

/** @param in
* CredentialDefinition form for creating the instance
Expand All @@ -23,7 +23,7 @@ trait CredentialDefinitionService {
* @return
* The instance of the credential definition or credential service error
*/
def getByGUID(guid: UUID): IO[CredentialDefinitionService.Error, CredentialDefinition]
def getByGUID(guid: UUID): IO[CredentialDefinitionServiceError, CredentialDefinition]

def delete(guid: UUID): Result[CredentialDefinition]

Expand All @@ -38,22 +38,15 @@ object CredentialDefinitionService {

final case class RepositoryError(cause: Throwable) extends Error

final case class GuidNotFoundError(guid: UUID) extends Error {
def message = s"Credential Definition record cannot be found by `guid`=$guid"
}
final case class IdNotFoundError(id: UUID) extends Error {
def message = s"Credential Definition record cannot be found by `id`=$id"
}
final case class NotFoundError(guid: Option[UUID] = None, id: Option[UUID] = None, message: String) extends Error

// final case class NotFoundError(guid: Option[UUID] = None, id: Option[UUID] = None, message: String) extends Error
object NotFoundError {
def byGuid(guid: UUID): NotFoundError =
NotFoundError(guid = Option(guid), message = s"Credential Definition record cannot be found by `guid`=$guid")

// object NotFoundError {
// def byGuid(guid: UUID): NotFoundError =
// NotFoundError(guid = Option(guid), message = s"Credential Definition record cannot be found by `guid`=$guid")

// def byId(id: UUID): NotFoundError =
// NotFoundError(id = Option(id), message = s"Credential Definition record cannot be found by `id`=$id")
// }
def byId(id: UUID): NotFoundError =
NotFoundError(id = Option(id), message = s"Credential Definition record cannot be found by `id`=$id")
}

final case class UpdateError(id: UUID, version: String, author: String, message: String) extends Error

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package org.hyperledger.identus.pollux.core.service

import org.hyperledger.identus.pollux.core.model.error.CredentialSchemaError
import org.hyperledger.identus.pollux.core.model.schema.CredentialSchema
import org.hyperledger.identus.pollux.core.model.schema.CredentialSchema.*
import org.hyperledger.identus.shared.models.{Failure, StatusCode}

import java.util.UUID

sealed trait CredentialDefinitionServiceError(
val statusCode: StatusCode,
val userFacingMessage: String
) extends Failure {
override val namespace = "CredentialDefinition"
}

final case class CredentialDefinitionGuidNotFoundError(guid: UUID)
extends CredentialDefinitionServiceError(
StatusCode.NotFound,
s"Credential Definition record cannot be found by `guid`=$guid"
)

final case class CredentialDefinitionUpdateError(id: UUID, version: String, author: String, message: String)
extends CredentialDefinitionServiceError(
StatusCode.BadRequest,
s"Credential Definition update error: id=$id, version=$version, author=$author, msg=$message"
)

final case class CredentialDefinitionCreationError(msg: String)
extends CredentialDefinitionServiceError(
StatusCode.BadRequest,
s"Credential Definition Creation Error=${msg}"
)

final case class CredentialDefinitionValidationError(cause: CredentialSchemaError)
extends CredentialDefinitionServiceError(
StatusCode.BadRequest,
s"Credential Definition Validation Error=${cause.message}"
)
Loading

0 comments on commit 2df5306

Please sign in to comment.