app/logic/FlexibleApi.scala (61 lines of code) (raw):
package logic
import java.util.Base64
import helpers.Loggable
import models._
import org.joda.time.DateTime
import play.api.libs.json.Json
import play.api.libs.ws.WSClient
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future
class FlexibleApi(wsClient: WSClient) extends Loggable {
def changeDetails(stack: FlexibleStack, contentId: String): Future[Option[ChangeDetails]] = {
wsClient.url(s"${stack.apiPrefix}/content/$contentId/changeDetails").get().map { response =>
response.status match {
case 200 =>
val revision = (response.json \ "data" \ "revision").asOpt[Long]
val lastModified = (response.json \ "data" \ "lastModified" \ "date").asOpt[Long].map(new DateTime(_))
(revision, lastModified) match {
case (Some(rev), Some(lm)) => Some(ChangeDetails(rev, lm))
case _ => None
}
case _ => None
}
}
}
def restoreToExisting(stack: FlexibleStack, userHeader: (String, String), contentId: String, snapshot: Snapshot): Attempt[String] = {
val attempt = Attempt.Async.Right(
wsClient
.url(s"${stack.apiPrefix}/restorer/content/$contentId")
.withHttpHeaders(userHeader)
.put(snapshot.data)
)
attempt.flatMap { response =>
response.status match {
case 204 => Attempt.Right(s"${stack.composerPrefix}/content/$contentId")
case other => Attempt.Left(AttemptError(s"Failed to restore to existing: $other - ${response.body}"))
}
}
}
def restoreToNew(stack: FlexibleStack, userHeader: (String, String), contentId: String, snapshot: Snapshot): Attempt[String] = {
val attempt = Attempt.Async.Right(
wsClient
.url(s"${stack.apiPrefix}/restorer/contentRaw/$contentId")
.withHttpHeaders(userHeader)
.put(snapshot.data)
)
attempt.flatMap { response =>
response.status match {
case 204 => Attempt.Right(s"${stack.composerPrefix}/content/$contentId")
case other => Attempt.Left(AttemptError(s"Failed to restore to new: $other - ${response.body}"))
}
}
}
def restore(stack: FlexibleStack, user: User, contentId: String, snapshot: Snapshot): Attempt[String] = {
val userString = Json.stringify(Json.toJson(user))
// see https://github.com/guardian/flexible-content/pull/3130
val userHeaderBase64 = "X-GU-User-base64" -> Base64.getEncoder.encodeToString(userString.getBytes("UTF-8"))
restoreToExisting(stack, userHeaderBase64, contentId, snapshot).recoverWith { errors =>
logger.info(s"Failed to restore $contentId to existing content in ${stack.displayName} - trying to upload new content ($errors)")
restoreToNew(stack, userHeaderBase64, contentId, snapshot)
}
}
}