Skip to content

Commit

Permalink
Merge branch 'master' into update-localstack-3-8
Browse files Browse the repository at this point in the history
  • Loading branch information
imsdu authored Oct 15, 2024
2 parents 5a109a0 + b44315f commit c914b83
Show file tree
Hide file tree
Showing 22 changed files with 74 additions and 151 deletions.
2 changes: 0 additions & 2 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ val kindProjectorVersion = "0.13.3"
val log4catsVersion = "2.7.0"
val logbackVersion = "1.5.10"
val magnoliaVersion = "1.1.10"
val mockitoVersion = "1.17.37"
val munitVersion = "1.0.2"
val munitCatsEffectVersion = "2.0.0"
val nimbusJoseJwtVersion = "9.41.2"
Expand Down Expand Up @@ -112,7 +111,6 @@ lazy val kindProjector = "org.typelevel" %% "kind
lazy val log4cats = "org.typelevel" %% "log4cats-slf4j" % log4catsVersion
lazy val logback = "ch.qos.logback" % "logback-classic" % logbackVersion
lazy val magnolia = "com.softwaremill.magnolia1_2" %% "magnolia" % magnoliaVersion
lazy val mockito = "org.mockito" %% "mockito-scala" % mockitoVersion
lazy val munit = "org.scalameta" %% "munit" % munitVersion
lazy val munitCatsEffect = "org.typelevel" %% "munit-cats-effect" % munitCatsEffectVersion
lazy val nimbusJoseJwt = "com.nimbusds" % "nimbus-jose-jwt" % nimbusJoseJwtVersion
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ class SchemaJobRoutes(
)
}
}.map { s =>
FileResponse("validation.json", ContentTypes.`application/json`, None, None, None, s)
FileResponse("validation.json", ContentTypes.`application/json`, None, None, s)
}

def routes: Route =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -469,7 +469,6 @@ final class Files(
attributes.filename,
mediaType,
Some(ResourceF.etagValue(file)),
Some(file.updatedAt),
Some(attributes.bytes),
s.attemptNarrow[FileRejection]
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import ch.epfl.bluebrain.nexus.delta.sourcing.model.ProjectRef
import ch.epfl.bluebrain.nexus.delta.sourcing.offset.Offset
import io.circe.Encoder

import java.time.Instant
import scala.reflect.ClassTag

object DeltaDirectives extends DeltaDirectives
Expand Down Expand Up @@ -140,30 +139,23 @@ trait DeltaDirectives extends UriDirectives {
.getOrElse(HttpEncodings.identity)
}

def conditionalCache(
value: Option[String],
lastModified: Option[Instant],
mediaType: MediaType,
encoding: HttpEncoding
): Directive0 =
conditionalCache(value, lastModified, mediaType, None, encoding)
def conditionalCache(value: Option[String], mediaType: MediaType, encoding: HttpEncoding): Directive0 =
conditionalCache(value, mediaType, None, encoding)

/**
* Wraps its inner route with support for Conditional Requests as defined by http://tools.ietf.org/html/rfc7232
*
* Supports `Etag` and `Last-Modified` headers:
* Supports `Etag` header:
* https://doc.akka.io/docs/akka-http/10.0/routing-dsl/directives/cache-condition-directives/conditional.html
*/
def conditionalCache(
value: Option[String],
lastModified: Option[Instant],
mediaType: MediaType,
jsonldFormat: Option[JsonLdFormat],
encoding: HttpEncoding
): Directive0 = {
val entityTag = value.map(EtagUtils.compute(_, mediaType, jsonldFormat, encoding))
val lastModifiedDateTime = lastModified.map { instant => DateTime(instant.toEpochMilli) }
Directives.conditional(entityTag, lastModifiedDateTime)
val entityTag = value.map(EtagUtils.compute(_, mediaType, jsonldFormat, encoding))
Directives.conditional(entityTag, None)
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@ import ch.epfl.bluebrain.nexus.delta.sdk.directives.Response.Complete
import ch.epfl.bluebrain.nexus.delta.sdk.marshalling.HttpResponseFields
import ch.epfl.bluebrain.nexus.delta.sdk.{AkkaSource, JsonLdValue}

import java.time.Instant

/**
* A file response content
*
Expand Down Expand Up @@ -40,7 +38,6 @@ object FileResponse {
filename: String,
contentType: ContentType,
etag: Option[String],
lastModified: Option[Instant],
bytes: Option[Long]
)

Expand All @@ -52,21 +49,18 @@ object FileResponse {
value.bytes.map { bytes => `Content-Length`(bytes) }.toSeq

override def entityTag(value: Metadata): Option[String] = value.etag

override def lastModified(value: Metadata): Option[Instant] = value.lastModified
}
}

def apply[E: JsonLdEncoder: HttpResponseFields](
filename: String,
contentType: ContentType,
etag: Option[String],
lastModified: Option[Instant],
bytes: Option[Long],
io: IO[Either[E, AkkaSource]]
) =
new FileResponse(
Metadata(filename, contentType, etag, lastModified, bytes),
Metadata(filename, contentType, etag, bytes),
io.map { r =>
r.leftMap { e =>
Complete(e).map(JsonLdValue(_))
Expand All @@ -78,13 +72,12 @@ object FileResponse {
filename: String,
contentType: ContentType,
etag: Option[String],
lastModified: Option[Instant],
bytes: Option[Long],
source: AkkaSource
): FileResponse =
new FileResponse(Metadata(filename, contentType, etag, lastModified, bytes), IO.pure(Right(source)))
new FileResponse(Metadata(filename, contentType, etag, bytes), IO.pure(Right(source)))

def noCache(filename: String, contentType: ContentType, bytes: Option[Long], source: AkkaSource): FileResponse =
new FileResponse(Metadata(filename, contentType, None, None, bytes), IO.pure(Right(source)))
new FileResponse(Metadata(filename, contentType, None, bytes), IO.pure(Right(source)))

}
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@ import ch.epfl.bluebrain.nexus.delta.sdk.syntax._
import io.circe.syntax._
import io.circe.{Encoder, Json}

import java.time.Instant

/**
* An enumeration of possible Route responses
*/
Expand All @@ -28,7 +26,6 @@ object Response {
status: StatusCode,
headers: Seq[HttpHeader],
entityTag: Option[String],
lastModified: Option[Instant],
value: A
) extends Response[A] {
def map[B](f: A => B): Complete[B] = copy(value = f(value))
Expand All @@ -40,7 +37,7 @@ object Response {
* A constructor helper for when [[HttpResponseFields]] is present
*/
def apply[A: HttpResponseFields](value: A): Complete[A] =
Complete(value.status, value.headers, value.entityTag, value.lastModified, value)
Complete(value.status, value.headers, value.entityTag, value)
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,12 +68,12 @@ object ResponseToJsonLd extends FileBytesInstances {
encoding: HttpEncoding
): Route = {
val ioRoute = ioFinal.flatMap {
case RouteOutcome.RouteRejected(rej) => IO.pure(reject(rej))
case RouteOutcome.RouteFailed(Complete(status, headers, _, _, value)) =>
case RouteOutcome.RouteRejected(rej) => IO.pure(reject(rej))
case RouteOutcome.RouteFailed(Complete(status, headers, _, value)) =>
handle(value).map(complete(status, headers, _))
case RouteOutcome.RouteCompleted(Complete(status, headers, entityTag, lastModified, value)) =>
case RouteOutcome.RouteCompleted(Complete(status, headers, entityTag, value)) =>
handle(value).map { r =>
conditionalCache(entityTag, lastModified, mediaType, jsonldFormat, encoding) {
conditionalCache(entityTag, mediaType, jsonldFormat, encoding) {
complete(status, headers, r)
}
}
Expand Down Expand Up @@ -154,12 +154,7 @@ object ResponseToJsonLd extends FileBytesInstances {
val contentDisposition =
RawHeader("Content-Disposition", s"""attachment; filename="$encodedFilename"""")
requestEncoding { encoding =>
conditionalCache(
metadata.entityTag,
metadata.lastModified,
metadata.contentType.mediaType,
encoding
) {
conditionalCache(metadata.entityTag, metadata.contentType.mediaType, encoding) {
respondWithHeaders(contentDisposition, metadata.headers: _*) {
complete(statusOverride.getOrElse(OK), HttpEntity(metadata.contentType, content))
}
Expand Down Expand Up @@ -225,7 +220,7 @@ sealed trait ValueInstances extends LowPriorityValueInstances {
)(implicit cr: RemoteContextResolution, jo: JsonKeyOrdering): ResponseToJsonLd =
ResponseToJsonLd(io.map[RouteOutcome[E]] {
case Left(e) => RouteOutcome.RouteFailed(Complete(e).map[JsonLdValue](JsonLdValue(_)))
case Right(value) => RouteOutcome.RouteCompleted(Complete(OK, Seq.empty, None, None, value))
case Right(value) => RouteOutcome.RouteCompleted(Complete(OK, Seq.empty, None, value))
})

implicit def rejectValue[E: JsonLdEncoder](
Expand All @@ -248,5 +243,5 @@ sealed trait LowPriorityValueInstances {
implicit def valueWithoutHttpResponseFields[A: JsonLdEncoder](
value: A
)(implicit cr: RemoteContextResolution, jo: JsonKeyOrdering): ResponseToJsonLd =
ResponseToJsonLd(IO.pure[UseRight[A]](Right(Complete(OK, Seq.empty, None, None, value))))
ResponseToJsonLd(IO.pure[UseRight[A]](Right(Complete(OK, Seq.empty, None, value))))
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@ object ResponseToJsonLdDiscardingEntity extends DiscardValueInstances {
new ResponseToJsonLdDiscardingEntity {

private def fallbackAsPlainJson =
onSuccess(io.unsafeToFuture()) { case Complete(status, headers, entityTag, lastModified, value) =>
onSuccess(io.unsafeToFuture()) { case Complete(status, headers, entityTag, value) =>
requestEncoding { encoding =>
conditionalCache(entityTag, lastModified, MediaTypes.`application/json`, encoding) {
conditionalCache(entityTag, MediaTypes.`application/json`, encoding) {
complete(status, headers, value.asJson)
}
}
Expand All @@ -53,7 +53,7 @@ sealed trait DiscardValueInstances extends DiscardLowPriorityValueInstances {
implicit def ioValue[A: JsonLdEncoder: Encoder](
io: IO[A]
)(implicit cr: RemoteContextResolution, jo: JsonKeyOrdering): ResponseToJsonLdDiscardingEntity =
ResponseToJsonLdDiscardingEntity(io.map(Complete(OK, Seq.empty, None, None, _)))
ResponseToJsonLdDiscardingEntity(io.map(Complete(OK, Seq.empty, None, _)))

implicit def valueWithHttpResponseFields[A: JsonLdEncoder: HttpResponseFields: Encoder](
value: A
Expand All @@ -66,6 +66,6 @@ sealed trait DiscardLowPriorityValueInstances {
implicit def valueWithoutHttpResponseFields[A: JsonLdEncoder: Encoder](
value: A
)(implicit cr: RemoteContextResolution, jo: JsonKeyOrdering): ResponseToJsonLdDiscardingEntity =
ResponseToJsonLdDiscardingEntity(IO.pure(Complete(OK, Seq.empty, None, None, value)))
ResponseToJsonLdDiscardingEntity(IO.pure(Complete(OK, Seq.empty, None, value)))

}
Original file line number Diff line number Diff line change
Expand Up @@ -45,15 +45,15 @@ object ResponseToMarshaller extends RdfMarshalling {
implicit def ioEntityMarshaller[A: ToEntityMarshaller](
io: IO[A]
)(implicit cr: RemoteContextResolution, jo: JsonKeyOrdering): ResponseToMarshaller =
ResponseToMarshaller(io.map[UseRight[A]](v => Right(Complete(OK, Seq.empty, None, None, v))))
ResponseToMarshaller(io.map[UseRight[A]](v => Right(Complete(OK, Seq.empty, None, v))))

implicit def ioEntityMarshaller[E: JsonLdEncoder: HttpResponseFields, A: ToEntityMarshaller](
io: IO[Either[E, A]]
)(implicit cr: RemoteContextResolution, jo: JsonKeyOrdering): ResponseToMarshaller = {
val ioComplete = io.map {
_.bimap(
e => Complete(e),
a => Complete(OK, Seq.empty, None, None, a)
a => Complete(OK, Seq.empty, None, a)
)
}
ResponseToMarshaller(ioComplete)
Expand All @@ -63,7 +63,7 @@ object ResponseToMarshaller extends RdfMarshalling {
io: IO[Either[Response[E], A]]
)(implicit cr: RemoteContextResolution, jo: JsonKeyOrdering): ResponseToMarshaller = {
val ioComplete = io.map {
_.map(a => Complete(OK, Seq.empty, None, None, a))
_.map(a => Complete(OK, Seq.empty, None, a))
}
ResponseToMarshaller(ioComplete)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ object ResponseToOriginalSource extends RdfMarshalling {
case Right(v: Complete[OriginalSource]) =>
IO.pure {
requestEncoding { encoding =>
conditionalCache(v.entityTag, v.lastModified, MediaTypes.`application/json`, encoding) {
conditionalCache(v.entityTag, MediaTypes.`application/json`, encoding) {
complete(v.status, v.headers, v.value)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ package ch.epfl.bluebrain.nexus.delta.sdk.marshalling

import akka.http.scaladsl.model.{HttpHeader, StatusCode, StatusCodes}

import java.time.Instant

/**
* Typeclass definition for ''A''s from which the HttpHeaders and StatusCode can be ontained.
*
Expand All @@ -29,8 +27,6 @@ trait HttpResponseFields[A] {
def headersFrom(value: A): Seq[HttpHeader]

def entityTag(value: A): Option[String]

def lastModified(value: A): Option[Instant]
}

// $COVERAGE-OFF$
Expand All @@ -46,10 +42,9 @@ object HttpResponseFields {
*/
def apply[A](f: A => StatusCode): HttpResponseFields[A] =
new HttpResponseFields[A] {
override def statusFrom(value: A): StatusCode = f(value)
override def headersFrom(value: A): Seq[HttpHeader] = Seq.empty
override def entityTag(value: A): Option[String] = None
override def lastModified(value: A): Option[Instant] = None
override def statusFrom(value: A): StatusCode = f(value)
override def headersFrom(value: A): Seq[HttpHeader] = Seq.empty
override def entityTag(value: A): Option[String] = None
}

/**
Expand All @@ -62,18 +57,16 @@ object HttpResponseFields {
*/
def fromStatusAndHeaders[A](f: A => (StatusCode, Seq[HttpHeader])): HttpResponseFields[A] =
new HttpResponseFields[A] {
override def statusFrom(value: A): StatusCode = f(value)._1
override def headersFrom(value: A): Seq[HttpHeader] = f(value)._2
override def entityTag(value: A): Option[String] = None
override def lastModified(value: A): Option[Instant] = None
override def statusFrom(value: A): StatusCode = f(value)._1
override def headersFrom(value: A): Seq[HttpHeader] = f(value)._2
override def entityTag(value: A): Option[String] = None
}

def fromTagAndLastModified[A](f: A => (String, Instant)): HttpResponseFields[A] =
def fromTag[A](f: A => String): HttpResponseFields[A] =
new HttpResponseFields[A] {
override def statusFrom(value: A): StatusCode = StatusCodes.OK
override def headersFrom(value: A): Seq[HttpHeader] = Seq.empty
override def entityTag(value: A): Option[String] = Some(f(value)._1)
override def lastModified(value: A): Option[Instant] = Some(f(value)._2)
override def statusFrom(value: A): StatusCode = StatusCodes.OK
override def headersFrom(value: A): Seq[HttpHeader] = Seq.empty
override def entityTag(value: A): Option[String] = Some(f(value))
}

def defaultOk[A]: HttpResponseFields[A] = HttpResponseFields { _ => StatusCodes.OK }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@ import ch.epfl.bluebrain.nexus.delta.sdk.syntax._
import io.circe.syntax.EncoderOps
import io.circe.{Encoder, Json}

import java.time.Instant

/**
* Defines an original source (what has been provided by clients during the api call)
*
Expand Down Expand Up @@ -69,14 +67,12 @@ object OriginalSource {
implicit val originalSourceHttpResponseFields: HttpResponseFields[OriginalSource] = {
val resourceFHttpResponseField = ResourceF.resourceFHttpResponseFields[Unit]
new HttpResponseFields[OriginalSource] {
override def statusFrom(value: OriginalSource): StatusCode =
override def statusFrom(value: OriginalSource): StatusCode =
resourceFHttpResponseField.statusFrom(value.resourceF)
override def headersFrom(value: OriginalSource): Seq[HttpHeader] =
override def headersFrom(value: OriginalSource): Seq[HttpHeader] =
resourceFHttpResponseField.headersFrom(value.resourceF)
override def entityTag(value: OriginalSource): Option[String] =
override def entityTag(value: OriginalSource): Option[String] =
resourceFHttpResponseField.entityTag(value.resourceF)
override def lastModified(value: OriginalSource): Option[Instant] =
resourceFHttpResponseField.lastModified(value.resourceF)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,6 @@ object ResourceF {
def etagValue[A](value: ResourceF[A]) = s"${value.uris.relativeAccessUri}_${value.rev}"

implicit def resourceFHttpResponseFields[A]: HttpResponseFields[ResourceF[A]] =
HttpResponseFields.fromTagAndLastModified { value => (etagValue(value), value.updatedAt) }
HttpResponseFields.fromTag { value => etagValue(value) }

}
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ package ch.epfl.bluebrain.nexus.delta.sdk.syntax
import akka.http.scaladsl.model.{HttpHeader, StatusCode}
import ch.epfl.bluebrain.nexus.delta.sdk.marshalling.HttpResponseFields

import java.time.Instant

trait HttpResponseFieldsSyntax {
implicit final def httpResponseFieldsSyntax[A](value: A): HttpResponseFieldsOps[A] = new HttpResponseFieldsOps(value)
}
Expand Down Expand Up @@ -32,10 +30,4 @@ final class HttpResponseFieldsOps[A](private val value: A) extends AnyVal {
def entityTag(implicit responseFields: HttpResponseFields[A]): Option[String] =
responseFields.entityTag(value)

/**
* @return
* the entity for the last-modified support in conditional requests
*/
def lastModified(implicit responseFields: HttpResponseFields[A]): Option[Instant] =
responseFields.lastModified(value)
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,6 @@ object SimpleResource extends CirceLiteral {
override def headersFrom(value: SimpleResource): Seq[HttpHeader] = Seq(new RawHeader("Test", "Value"))

override def entityTag(value: SimpleResource): Option[String] = Some(value.id.toString)

override def lastModified(value: SimpleResource): Option[Instant] = Some(value.createdAt)
}

val rawHeader: RawHeader = new RawHeader("Test", "Value")
Expand Down
Loading

0 comments on commit c914b83

Please sign in to comment.