Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Credential Defintion Error Handling Part 2 #1155

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not needed anymore. An implicit conversion Failure->ErrorResponse is already defined in the companion object of the latter.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

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 {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See previous comment => .mapError() is no more needed.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

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(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above (obsolete) 😉

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

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 {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess these case classes are obsolete. We now rely on the new CredentialDefinitionServiceError file/trait, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

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
Loading