private def makeArticlesFrom()

in common/app/common/TrailsToShowcase.scala [301:372]


  private def makeArticlesFrom(
      content: Seq[PressedContent],
      required: Int,
      articleType: String,
      maxTitleLength: Int,
      maxOverlineLength: Int,
  ): Either[Seq[String], Seq[Article]] = {
    val articleOutcomes = content.map { contentItem =>
      // Collect the mandatory fields for the article. If any of these are missing we can skip this item
      val proposedArticleTitle = titleOfLengthFrom(maxTitleLength, contentItem)
      val proposedArticleImage = rundownPanelArticleImageUrlFor(contentItem)
      val proposedOverline = overlineFrom(contentItem, maxOverlineLength)

      val maybeArticle = for {
        webPublicationDate <- contentItem.card.webPublicationDateOption
        title <- proposedArticleTitle.toOption
        guid <- guidFor(contentItem)
        webUrl <- webUrl(contentItem)
        imageUrl <- proposedArticleImage.toOption
        maybeOverline <- proposedOverline.toOption
      } yield {
        val lastModified = contentItem.card.lastModifiedOption.getOrElse(webPublicationDate)
        Article(
          guid,
          title,
          webUrl,
          webPublicationDate,
          lastModified,
          bylineFrom(contentItem),
          maybeOverline,
          Some(imageUrl),
        )
      }

      maybeArticle.map(Right(_)).getOrElse {
        val problems = Seq(proposedArticleTitle, proposedArticleImage, proposedOverline).map(_.left.toOption)
        Left(problems)
      }
    }

    // We require exactly 3 articles for a valid rundown panel; 2 for a related articles single story panel
    val correctNumberOfArticlesToUse =
      Some(articleOutcomes.flatMap(_.toOption).take(required)).filter(_.size == required)

    correctNumberOfArticlesToUse
      .map { articles =>
        // Most of our content has bylines. Kicker is an optional override in our tools
        // Therefore we should default to using author tags if it is available on all the articles.
        // If kickers have been supplied for all articles we will use that in preference to authors
        val allAuthorsPresent = articles.forall(_.author.nonEmpty)
        val allKickersPresent = articles.forall(_.overline.nonEmpty)
        if (allKickersPresent) {
          // Use kickers; remove any authors
          Right(articles.map(_.copy(author = None)))
        } else if (allAuthorsPresent) {
          // Use authors; remove any kickers
          Right(articles.map(_.copy(overline = None)))
        } else {
          // We can't use these articles as all author or all overline is a requirement
          Left(Seq(s"$articleType trails need to have all Kickers or all Bylines"))
        }
      }
      .getOrElse {
        val articleProblems = articleOutcomes
          .flatMap(_.left.toOption)
          .flatten
          .flatten
          .flatten
        // Could not make required number of valid articles is the most useful message to the editor so put it first
        Left(s"Could not find $required valid ${articleType.toLowerCase} trails" +: articleProblems)
      }
  }