in common/app/model/CrosswordData.scala [91:165]
def fromCrossword(crossword: Crossword, content: contentapi.Content): CrosswordData = {
// For entry groups, all separator locations for entries within the
// group are incorrectly stored on the first group entry. We normalize
// the data to store the separator locations on their corresponding entries.
val shipSolutions = crossword.dateSolutionAvailable.map(_.toJoda.isBeforeNow).getOrElse(crossword.solutionAvailable)
val entries = crossword.entries.collect {
case entry if !shipSolutions => Entry.fromCrosswordEntry(entry.copy(solution = None))
case entry => Entry.fromCrosswordEntry(entry)
}
val entryGroups = entries
.groupBy(_.group)
// Sort using the group ordering
.map { case (orderedGroupEntryIds, groupEntries) =>
(orderedGroupEntryIds, orderedGroupEntryIds.flatMap(id => groupEntries.find(_.id == id)))
}
val newEntries = entryGroups
.map { case (_, groupEntries) =>
val maybeSeparatorLocations: Option[Map[String, Seq[Int]]] =
groupEntries
.find(_.separatorLocations.exists(_.nonEmpty))
.flatMap(_.separatorLocations)
val bounds: Map[(Int, Int), Entry] =
groupEntries
.foldLeft((0, Map.empty[(Int, Int), Entry])) { case ((upperBound, m), entry) =>
val newLowerBound = upperBound
val newUpperBound = upperBound + entry.length
(newUpperBound, m + ((newLowerBound, newUpperBound) -> entry))
}
._2
val newGroupEntries: Seq[Entry] = bounds.map { case ((lowerBound, upperBound), entry) =>
maybeSeparatorLocations
.map { separatorLocations =>
val newSeparatorLocations: Map[String, Seq[Int]] = separatorLocations.map { case (separator, locations) =>
val newLocations =
locations
.filter(location => location > lowerBound && location <= upperBound)
.map(location => location - lowerBound)
(separator, newLocations)
}
entry.copy(separatorLocations = Some(newSeparatorLocations))
}
.getOrElse(entry)
}.toList
newGroupEntries
}
.toList
.flatten
// Revert back to the original order
val sortedNewEntries = entries.flatMap(entry => newEntries.find(_.id == entry.id))
val crosswordType = CamelCase.toHyphenated(crossword.`type`.name)
CrosswordData(
s"crosswords/$crosswordType/${crossword.number.toString}",
crossword.number,
crossword.name,
creator = for (creator <- crossword.creator) yield CrosswordCreator(creator.name, creator.webUrl),
crossword.date.toJoda,
content.webPublicationDate.fold(crossword.date.toJoda)(_.toJoda),
sortedNewEntries.toSeq,
solutionAvailable = shipSolutions,
crossword.dateSolutionAvailable.map(_.toJoda),
CrosswordDimensions(crossword.dimensions.cols, crossword.dimensions.rows),
crosswordType,
crossword.pdf,
crossword.instructions,
)
}