app/util/AtomLogic.scala (76 lines of code) (raw):

package util import cats.syntax.either._ import com.amazonaws.services.dynamodbv2.model.AmazonDynamoDBException import com.gu.atom.data.DynamoCompositeKey import com.gu.contentatom.thrift._ import com.gu.contententity.thrift.Entity import com.gu.fezziwig.CirceScroogeMacros._ import com.gu.pandomainauth.model.User import io.circe.generic.auto._ import io.circe.{DecodingFailure, ParsingFailure, parser, _} import models._ import play.api.Logging import util.AtomElementBuilders._ object AtomLogic extends Logging { def buildKey(atomType: AtomType, id: String) = DynamoCompositeKey(atomType.name, Some(id)) def getVersion(version: String): Version = version match { case "preview" => Preview case "live" => Live } def validateAtomType(atomType: String): Either[AtomAPIError, AtomType] = { val t = AtomType.valueOf(atomType) Either.cond(t.isDefined, t.get, InvalidAtomTypeError) } def processException(exception: Exception): Either[AtomAPIError, Nothing] = { val atomApiError = exception match { case e: ParsingFailure => AtomJsonParsingError(e.message) case e: DecodingFailure => AtomThriftDeserialisingError(e.message) case e: AmazonDynamoDBException => AmazonDynamoError(e.getMessage) case _ => UnexpectedExceptionError } logger.error(atomApiError.msg, exception) Left(atomApiError) } def extractRequestBody(body: Option[String]): Either[AtomAPIError, String] = Either.cond(body.isDefined, body.get, BodyRequiredForUpdateError) def extractCreateAtomFields(body: Option[String]): Either[AtomAPIError, Option[CreateAtomFields]] = { body.map { body => for { json <- Parser.stringToJson(body) createAtomFields <- json.as[CreateAtomFields].fold(processException, m => Right(m)) } yield Some(createAtomFields) }.getOrElse(Right(None)) } def updateTakenDownChangeRecord(atom: Atom, user: User): Atom = atom.copy(contentChangeDetails = buildContentChangeDetails(user, Some(atom.contentChangeDetails), updateTakenDown = true)) } object Parser extends Logging { import AtomLogic._ //These implicits speed up compilation private implicit val atomDecoder = { implicit val entityDecoder = Decoder[Entity] implicit val imageAssetDecoder = Decoder[ImageAsset] implicit val imageDecoder = Decoder[Image] implicit val changeRecord = Decoder[ChangeRecord] implicit val atomDataDecoder = Decoder[AtomData] implicit val flagsDecoder = Decoder[Flags] Decoder[Atom] } def stringToAtom(atomString: String): Either[AtomAPIError, Atom] = { logger.info(s"Parsing atom json: $atomString") for { json <- stringToJson(atomString) atom <- jsonToAtom(json) } yield atom } def jsonToAtom(json: Json): Either[AtomAPIError, Atom] = { logger.info(s"Parsing json: $json") json.as[Atom].fold(processException, m => Right(m)) } def stringToJson(atomJson: String): Either[AtomAPIError, Json] = { logger.info(s"Parsing body to json: $atomJson") val parsingResult = for { parsedJson <- parser.parse(atomJson) } yield parsedJson parsingResult.fold(processException, a => Right(a)) } }