app/story_packages/model/frontsapi.scala (139 lines of code) (raw):

package frontsapi.model import com.gu.facia.client.models._ import com.gu.pandomainauth.model.User import org.joda.time.DateTime import play.api.libs.json._ import story_packages.services.{FrontsApi, Logging} import conf.ApplicationConfiguration import story_packages.tools.FaciaApiIO import story_packages.updates.UpdateList import scala.concurrent.ExecutionContext.Implicits.global import scala.concurrent.Future import scala.util.{Failure, Success, Try} trait UpdateActionsTrait extends Logging { def faciaApiIO: FaciaApiIO def frontsApi: FrontsApi def config: ApplicationConfiguration implicit val updateListWrite: OWrites[UpdateList] = Json.writes[UpdateList] def insertIntoLive(update: UpdateList, identity: User, collectionJson: CollectionJson): CollectionJson = { val live = updateList(update, identity, collectionJson.live) collectionJson.copy(live=live)} def deleteFromLive(update: UpdateList, collectionJson: CollectionJson): CollectionJson = collectionJson.copy(live=collectionJson.live.filterNot(_.id == update.item)) def putCollectionJson(id: String, collectionJson: CollectionJson): CollectionJson = faciaApiIO.putCollectionJson(id, collectionJson) def updateIdentity(collectionJson: CollectionJson, identity: User): CollectionJson = collectionJson.copy(lastUpdated = DateTime.now, updatedBy = getUserName(identity), updatedEmail = identity.email) //Archiving def archiveUpdateBlock(collectionId: String, collectionJson: CollectionJson, updateJson: JsValue, identity: User): CollectionJson = { archiveBlock(collectionId, collectionJson, Json.obj("action" -> "update", "update" -> updateJson), identity) } def archiveDeleteBlock(collectionId: String, collectionJson: CollectionJson, updateJson: JsValue, identity: User): CollectionJson = { archiveBlock(collectionId, collectionJson, Json.obj("action" -> "delete", "update" -> updateJson), identity) } private def archiveBlock(id: String, collectionJson: CollectionJson, action: String, identity: User): CollectionJson = archiveBlock(id, collectionJson, Json.obj("action" -> action), identity) private def archiveBlock(id: String, collectionJson: CollectionJson, updateJson: JsValue, identity: User): CollectionJson = Try(faciaApiIO.archive(id, collectionJson, updateJson, identity)) match { case Failure(t: Throwable) => { Logger.warn(t.toString) collectionJson } case Success(_) => collectionJson } def updateCollectionList(id: String, update: UpdateList, identity: User): Future[Option[CollectionJson]] = { lazy val updateJson = Json.toJson(update) frontsApi.amazonClient.collection(id).map { maybeCollectionJson => maybeCollectionJson .map(insertIntoLive(update, identity, _)) .map(pruneBlock) .map(sortByGroupAndCap) .map(updateIdentity(_, identity)) .map(putCollectionJson(id, _)) .map(archiveUpdateBlock(id, _, updateJson, identity)) .orElse(Option(createCollectionJson(identity, update))) .map(putCollectionJson(id, _))}} def updateCollectionFilter(id: String, update: UpdateList, identity: User): Future[Option[CollectionJson]] = { lazy val updateJson = Json.toJson(update) frontsApi.amazonClient.collection(id).map { maybeCollectionJson => maybeCollectionJson .map(deleteFromLive(update, _)) .map(pruneBlock) .map(sortByGroupAndCap) .map(archiveDeleteBlock(id, _, updateJson, identity)) .map(updateIdentity(_, identity)) .map(putCollectionJson(id, _))}} private def updateList(update: UpdateList, identity: User, blocks: List[Trail]): List[Trail] = { val trail: Trail = blocks .find(_.id == update.item) .map { currentTrail => val newMeta = for (updateMeta <- update.itemMeta) yield updateMeta currentTrail.copy(meta = newMeta) } .getOrElse(Trail(update.item, DateTime.now.getMillis, Some(getUserName(identity)), update.itemMeta)) val listWithoutItem = blocks.filterNot(_.id == update.item) val splitList: (List[Trail], List[Trail]) = { //Different index logic if item is being place at itself in list //(Eg for metadata update, or group change, index must come from list without item removed) if (update.position.exists(_ == update.item)) { val index = blocks.indexWhere(_.id == update.item) listWithoutItem.splitAt(index) } else { val index = update.after.filter {_ == true} .map {_ => listWithoutItem.indexWhere(t => update.position.exists(_ == t.id)) + 1} .getOrElse { listWithoutItem.indexWhere(t => update.position.exists(_ == t.id)) } listWithoutItem.splitAt(index) } } splitList._1 ::: (trail +: splitList._2) } def createCollectionJson(identity: User, update: UpdateList): CollectionJson = { val userName = getUserName(identity) CollectionJson( live = List(Trail( id = update.item, frontPublicationDate = DateTime.now.getMillis, publishedBy = Some(userName), meta = update.itemMeta) ), draft = None, treats = None, lastUpdated = DateTime.now, updatedBy = userName, updatedEmail = identity.email, displayName = None, href = None, previously = None, targetedTerritory = None ) } private def pruneBlock(collectionJson: CollectionJson): CollectionJson = collectionJson.copy( live = collectionJson.live .map(pruneGroupOfZero) .map(pruneMetaDataIfEmpty), draft = None, previously = None ) private def pruneGroupOfZero(trail: Trail): Trail = trail.copy(meta = trail.meta.map( metaData => metaData.copy(json = metaData.json.filter{ case ("group", JsString("0")) => false case _ => true}))) private def pruneMetaDataIfEmpty(trail: Trail): Trail = trail.copy(meta = trail.meta.filter(_.json.nonEmpty)) private def removeGroupsFromTrail(trail: Trail): Trail = trail.copy(meta = trail.meta.map(metaData => metaData.copy(json = metaData.json - "group"))) private def getUserName(identity: User): String = s"${identity.firstName} ${identity.lastName}" private def sortByGroupAndCap(collectionJson: CollectionJson) = collectionJson.copy(live = sortTrailsByGroupAndCap(collectionJson.live)) private def sortTrailsByGroupAndCap(trails: List[Trail]): List[Trail] = { val trailGroups = trails.groupBy(_.meta.flatMap(_.group).map(_.toInt).getOrElse(0)) trailGroups.keys.toList.sorted(Ordering.Int.reverse).flatMap(groupId => { trailGroups.getOrElse(groupId, Nil).take(groupId match { case 0 => config.facia.linkingCollectionCap case 1 => config.facia.includedCollectionCap case _ => 0 }) }) } } class UpdateActions(val faciaApiIO: FaciaApiIO, val frontsApi: FrontsApi, val config: ApplicationConfiguration) extends UpdateActionsTrait