app/tools/FaciaApiIO.scala (142 lines of code) (raw):
package tools
import com.gu.facia.client.models.{CollectionJson, ConfigJson}
import com.gu.pandomainauth.model.User
import frontsapi.model.CollectionJsonFunctions
import org.joda.time.DateTime
import play.api.libs.json.{JsValue, _}
import services.{FrontsApi, S3FrontsApi}
import logging.Logging
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future
import scala.util.Try
trait FaciaApiRead {
def getCollectionJson(id: String): Future[Option[CollectionJson]]
}
trait FaciaApiWrite {
def putCollectionJson(
id: String,
collectionJson: CollectionJson
): CollectionJson
def publishCollectionJson(
id: String,
identity: User
): Future[Option[CollectionJson]]
def discardCollectionJson(
id: String,
identity: User
): Future[Option[CollectionJson]]
def archive(
id: String,
collectionJson: CollectionJson,
update: JsValue,
identity: User
): Unit
}
class FaciaApiIO(val frontsApi: FrontsApi, val s3FrontsApi: S3FrontsApi)
extends FaciaApiRead
with FaciaApiWrite
with Logging {
def getCollectionJson(id: String): Future[Option[CollectionJson]] =
frontsApi.amazonClient.collection(id)
def putCollectionJson(
id: String,
collectionJson: CollectionJson
): CollectionJson = {
Try(
s3FrontsApi.putCollectionJson(
id,
Json.prettyPrint(Json.toJson(collectionJson))
)
)
collectionJson
}
private def mutateCollectionJson(
f: User => CollectionJson => Option[CollectionJson]
)(id: String, identity: User): Future[Option[CollectionJson]] =
getCollectionJson(id)
.map { maybeCollectionJson =>
maybeCollectionJson
.flatMap(f(identity))
.map(putCollectionJson(id, _))
}
def publishCollectionJson(id: String, identity: User) =
mutateCollectionJson(FaciaApi.preparePublishCollectionJson)(id, identity)
def discardCollectionJson(id: String, identity: User) =
mutateCollectionJson(FaciaApi.prepareDiscardCollectionJson)(id, identity)
def archive(
id: String,
collectionJson: CollectionJson,
update: JsValue,
identity: User
): Unit = {
Json.toJson(collectionJson).transform[JsObject](Reads.JsObjectReads) match {
case JsSuccess(result, _) =>
s3FrontsApi.archive(
id,
Json.prettyPrint(result + ("diff", update)),
identity
)
case JsError(errors) =>
throw new Exception(s"Could not archive $id: $errors")
}
}
def v2Archive(
id: String,
collectionJson: CollectionJson,
identity: User
): Unit = {
Json.toJson(collectionJson).transform[JsObject](Reads.JsObjectReads) match {
case JsSuccess(result, _) =>
s3FrontsApi.archive(id, Json.prettyPrint(result), identity)
case JsError(errors) =>
throw new Exception(s"Could not archive $id: $errors")
}
}
def putMasterConfig(config: ConfigJson): Option[ConfigJson] = {
Try(s3FrontsApi.putMasterConfig(Json.prettyPrint(Json.toJson(config))))
.map(_ => config)
.toOption
}
def archiveMasterConfig(config: ConfigJson, identity: User): Unit =
s3FrontsApi.archiveMasterConfig(
Json.prettyPrint(Json.toJson(config)),
identity
)
}
/** this is the pure and unit testable stuff for the FaciaApiIO
*/
object FaciaApi {
// testable
def preparePublishCollectionJson(
identity: User
)(collectionJson: CollectionJson): Option[CollectionJson] =
Some(collectionJson)
.filter(_.draft.isDefined)
.map(updatePublicationDateForNew)
.map(CollectionJsonFunctions.updatePreviouslyForPublish)
.map(collectionJson =>
collectionJson.copy(live = collectionJson.draft.get, draft = None)
)
.map(updateIdentity(_, identity))
def prepareDiscardCollectionJson(
identity: User
)(collectionJson: CollectionJson): Option[CollectionJson] =
Some(collectionJson)
.map(_.copy(draft = None))
.map(updateIdentity(_, identity))
def updateIdentity(
collectionJson: CollectionJson,
identity: User
): CollectionJson = collectionJson.copy(
lastUpdated = DateTime.now,
updatedBy = identity.firstName + " " + identity.lastName,
updatedEmail = identity.email
)
def updatePublicationDateForNew(
collectionJson: CollectionJson
): CollectionJson = {
val liveIds = collectionJson.live.map(_.id).toSet
val draftsWithNewDate = collectionJson.draft.get.map { draft =>
if (liveIds.contains(draft.id)) draft
else draft.copy(frontPublicationDate = DateTime.now.getMillis)
}
collectionJson.copy(draft = Some(draftsWithNewDate))
}
}