app/controllers/Migration.scala (131 lines of code) (raw):

package controllers import com.gu.pandomainauth.PanDomainAuthSettingsRefresher import com.gu.tagmanagement.{EventType, TagEvent} import model.command.FlexTagReindexCommand import model.{PaidContentInformation, Sponsorship, TagAudit} import permissions.TriggerMigrationPermissionsCheck import play.api.Logging import play.api.libs.json.Json import play.api.libs.ws.WSClient import play.api.mvc.{BaseController, ControllerComponents} import repositories._ import services.KinesisStreams import services.migration.PaidContentMigrator import scala.concurrent.ExecutionContext import scala.io.Source class Migration( val wsClient: WSClient, override val controllerComponents: ControllerComponents, val panDomainSettings: PanDomainAuthSettingsRefresher )( implicit ec: ExecutionContext ) extends BaseController with PanDomainAuthActions with Logging { def showPaidContentUploadForm = (APIAuthAction andThen TriggerMigrationPermissionsCheck()) { Ok(views.html.Application.migration.paidContentUploadForm()) } def migratePaidContent = APIAuthAction(parse.multipartFormData) { req => req.body.file("migrationFile").map{ jsonFile => val jsonString = Source.fromFile(jsonFile.ref.path.toFile, "UTF-8").getLines().mkString("\n") val json = Json.parse(jsonString) val sponsorships = json.as[List[Sponsorship]] sponsorships.foreach { sponsorship => PaidContentMigrator.migrate(sponsorship) } Ok(s"Migrated ${sponsorships.length} tags to paid content type") }.getOrElse(BadRequest("unable to read file")) } def movePaidcontentSponsorshipUpToSection = (APIAuthAction andThen TriggerMigrationPermissionsCheck()) { implicit val username = Some("sponsorship Migration") val paidContentTags = TagLookupCache.search(new TagSearchCriteria(types = Some(List("PaidContent")))) var count = 0 paidContentTags foreach{ tag => val section = tag.section.flatMap{sid => SectionRepository.getSection(sid)} section foreach { s => if (s.sectionTagId == tag.id) { val sponsorship = tag.sponsorship.flatMap{sid => SponsorshipRepository.getSponsorship(sid)} val targetedSponsorship = sponsorship map { spon => val targetSections = spon.sections.getOrElse(Nil) val updatedSponsorship = spon.copy(sections = Some((s.id :: targetSections).distinct)) SponsorshipRepository.updateSponsorship(updatedSponsorship) if(updatedSponsorship.status == "active"){ SponsorshipOperations.addSponsorshipToSection(updatedSponsorship.id, s.id) count = count + 1 } } } } } Ok(s"updated $count sections") } def flattenSponsoredMicrosite(sponsorshipId: Long) = (APIAuthAction andThen TriggerMigrationPermissionsCheck()) { implicit val username = Some("sponsorship Migration") val spons = SponsorshipRepository.getSponsorship(sponsorshipId) var count = 0 spons.foreach { s => PaidContentMigrator.migrate(s) for ( tags <- s.tags; tagId <- tags; tag <- TagRepository.getTag(tagId) ) { val section = tag.section.flatMap { sid => SectionRepository.getSection(sid) } section foreach { s => if (s.sectionTagId == tag.id) { val sponsorship = tag.sponsorship.flatMap { sid => SponsorshipRepository.getSponsorship(sid) } val targetedSponsorship = sponsorship map { spon => val targetSections = spon.sections.getOrElse(Nil) val updatedSponsorship = spon.copy(sections = Some((s.id :: targetSections).distinct)) SponsorshipRepository.updateSponsorship(updatedSponsorship) if (updatedSponsorship.status == "active") { SponsorshipOperations.addSponsorshipToSection(updatedSponsorship.id, s.id) count = count + 1 } } } } } } Ok(s"updated $count partner zones") } def addMissingPaidContentTypes() = (APIAuthAction andThen TriggerMigrationPermissionsCheck()) { implicit val username = Some("sponsorship Migration") val paidContentTags = TagLookupCache.search( TagSearchCriteria(types = Some(List("PaidContent"))) ) val missingSubType = paidContentTags.filter{t => t.paidContentInformation.isEmpty || t.paidContentInformation.get.paidContentType == null || t.paidContentInformation.get.paidContentType.trim == "" } missingSubType foreach{ t => val paidContentInformation = t.paidContentInformation match { case Some(pc) => pc.copy(paidContentType = "Topic") case None => PaidContentInformation(paidContentType = "Topic", campaignColour = None) } val withSubType = t.copy(paidContentInformation = Some(paidContentInformation)) TagRepository.upsertTag(withSubType) foreach { updatedTag => KinesisStreams.tagUpdateStream.publishUpdate(updatedTag.id.toString, TagEvent(EventType.Update, updatedTag.id, Some(updatedTag.asThrift))) TagAuditRepository.upsertTagAudit(TagAudit.updated(updatedTag)) FlexTagReindexCommand(updatedTag).process() } } Ok(missingSubType.map{t => t.externalName}.mkString("\n")) } def dudupeActiveSponsorships() = (APIAuthAction andThen TriggerMigrationPermissionsCheck()) { implicit val username = Some("sponsorship Migration") val allTags = TagLookupCache.allTags.get val tagsWithDuplicatSpons = allTags.filter{t => t.activeSponsorships.length != t.activeSponsorships.distinct.length } for ( t <- tagsWithDuplicatSpons; spons <- t.activeSponsorships.headOption ){ // this is a massive cheat, the add operation not enforces distinctness so adding an already present sponsorship // will cause the list to dedupe and the correct indexing messages to be sent. SponsorshipOperations.addSponsorshipToTag(spons, t.id) } Ok(s"removed ${tagsWithDuplicatSpons.length} dupes") } }