diff --git a/article-api/src/main/scala/no/ndla/articleapi/db/HtmlMigration.scala b/article-api/src/main/scala/no/ndla/articleapi/db/HtmlMigration.scala index 527cf16112..163fcfc37b 100644 --- a/article-api/src/main/scala/no/ndla/articleapi/db/HtmlMigration.scala +++ b/article-api/src/main/scala/no/ndla/articleapi/db/HtmlMigration.scala @@ -72,10 +72,10 @@ abstract class HtmlMigration extends DocumentMigration { val newArticle = oldArticle.copy( title = convertedTitle, - introduction = convertedIntroduction, content = convertedContent, - metaDescription = convertedMetaDescription, visualElement = convertedVisualElement, + introduction = convertedIntroduction, + metaDescription = convertedMetaDescription, ) newArticle.asJson.noSpaces } diff --git a/article-api/src/main/scala/no/ndla/articleapi/db/migration/V69__SetPublishedCount.scala b/article-api/src/main/scala/no/ndla/articleapi/db/migration/V69__SetPublishedCount.scala new file mode 100644 index 0000000000..c0b983c772 --- /dev/null +++ b/article-api/src/main/scala/no/ndla/articleapi/db/migration/V69__SetPublishedCount.scala @@ -0,0 +1,49 @@ +/* + * Part of NDLA article-api + * Copyright (C) 2026 NDLA + * + * See LICENSE + * + */ + +package no.ndla.articleapi.db.migration + +import io.circe.{Json, parser} +import no.ndla.database.TableMigration +import org.postgresql.util.PGobject +import scalikejdbc.{DBSession, SQLSyntax, WrappedResultSet} +import scalikejdbc.interpolation.Implicits.scalikejdbcSQLInterpolationImplicitDef + +case class DocumentRow(id: Long, revision: Int, articleId: Long, document: String) + +class V69__SetPublishedCount extends TableMigration[DocumentRow] { + val columnName: String = "document" + override val tableName: String = "contentdata" + + private lazy val columnNameSQL: SQLSyntax = SQLSyntax.createUnsafely(columnName) + override lazy val whereClause: SQLSyntax = sqls"$columnNameSQL is not null" + + private def countOtherVersions(revision: Int, articleId: Long)(implicit session: DBSession): Long = { + sql"select count(*) from $tableNameSQL where revision < $revision and article_id = $articleId" + .map(rs => rs.long("count")) + .single() + .getOrElse(0L) + } + + override def extractRowData(rs: WrappedResultSet): DocumentRow = + DocumentRow(rs.long("id"), rs.int("revision"), rs.long("article_id"), rs.string(columnName)) + + override def updateRow(rowData: DocumentRow)(implicit session: DBSession): Int = { + val other = countOtherVersions(rowData.revision, rowData.articleId) + val oldDocument = parser.parse(rowData.document).toTry.get + val newDoc = oldDocument.mapObject(_.add("publishedCount", Json.fromLong(other + 1))).noSpaces + + val dataObject = new PGobject() + dataObject.setType("jsonb") + dataObject.setValue(newDoc) + sql"""update $tableNameSQL + set $columnNameSQL = $dataObject + where id = ${rowData.id} + """.update() + } +} diff --git a/article-api/src/main/scala/no/ndla/articleapi/model/api/ArticleV2DTO.scala b/article-api/src/main/scala/no/ndla/articleapi/model/api/ArticleV2DTO.scala index 3f9163b830..4d887cd789 100644 --- a/article-api/src/main/scala/no/ndla/articleapi/model/api/ArticleV2DTO.scala +++ b/article-api/src/main/scala/no/ndla/articleapi/model/api/ArticleV2DTO.scala @@ -71,6 +71,8 @@ case class ArticleV2DTO( disclaimer: Option[DisclaimerDTO], @description("Traits extracted from the article content") traits: List[ArticleTrait], + @description("Number of times the article have been published") + publishedCount: Int, ) object ArticleV2DTO { diff --git a/article-api/src/main/scala/no/ndla/articleapi/service/ConverterService.scala b/article-api/src/main/scala/no/ndla/articleapi/service/ConverterService.scala index 9a27b2ddb9..6db6d6c87e 100644 --- a/article-api/src/main/scala/no/ndla/articleapi/service/ConverterService.scala +++ b/article-api/src/main/scala/no/ndla/articleapi/service/ConverterService.scala @@ -189,14 +189,14 @@ class ConverterService(using props: Props) extends StrictLogging { val newPublishedDate = partialArticle.published.getOrElse(existingArticle.published) existingArticle.copy( - availability = newAvailability, - grepCodes = newGrepCodes, copyright = existingArticle.copyright.copy(license = newLicense), + tags = newTags, metaDescription = newMeta, + published = newPublishedDate, + grepCodes = newGrepCodes, + availability = newAvailability, relatedContent = newRelatedContent, - tags = newTags, revisionDate = newRevisionDate, - published = newPublishedDate, ) } @@ -289,6 +289,7 @@ class ConverterService(using props: Props) extends StrictLogging { slug = article.slug, disclaimer = disclaimer, traits = article.traits, + publishedCount = article.publishedCount.getOrElse(1), ) ) } else { diff --git a/article-api/src/test/scala/no/ndla/articleapi/TestData.scala b/article-api/src/test/scala/no/ndla/articleapi/TestData.scala index 2e523bbc99..b714c794d3 100644 --- a/article-api/src/test/scala/no/ndla/articleapi/TestData.scala +++ b/article-api/src/test/scala/no/ndla/articleapi/TestData.scala @@ -83,6 +83,7 @@ class TestData { slug = None, disclaimer = None, traits = List.empty, + publishedCount = 1, ) val apiArticleV2: api.ArticleV2DTO = api.ArticleV2DTO( @@ -129,6 +130,7 @@ class TestData { slug = None, disclaimer = None, traits = List.empty, + publishedCount = 1, ) val sampleArticleWithPublicDomain: Article = Article( @@ -161,6 +163,7 @@ class TestData { slug = None, disclaimer = OptLanguageFields.empty, traits = List.empty, + publishedCount = Some(1), ) val sampleDomainArticle: Article = Article( @@ -188,6 +191,7 @@ class TestData { slug = None, disclaimer = OptLanguageFields.empty, traits = List.empty, + publishedCount = Some(1), ) val sampleDomainArticle2: Article = Article( @@ -215,6 +219,7 @@ class TestData { slug = None, disclaimer = OptLanguageFields.empty, traits = List.empty, + publishedCount = Some(1), ) val sampleArticleWithByNcSa: Article = sampleArticleWithPublicDomain.copy(copyright = byNcSaCopyright) @@ -254,6 +259,7 @@ class TestData { slug = None, disclaimer = OptLanguageFields.empty, traits = List.empty, + publishedCount = Some(1), ) val apiArticleWithHtmlFaultV2: api.ArticleV2DTO = api.ArticleV2DTO( @@ -301,6 +307,7 @@ class TestData { slug = None, disclaimer = None, traits = List.empty, + publishedCount = 1, ) val (nodeId, nodeId2) = ("1234", "4321") @@ -337,6 +344,7 @@ class TestData { slug = None, disclaimer = OptLanguageFields.empty, traits = List.empty, + publishedCount = Some(1), ) } diff --git a/article-api/src/test/scala/no/ndla/articleapi/service/ConverterServiceTest.scala b/article-api/src/test/scala/no/ndla/articleapi/service/ConverterServiceTest.scala index b54be330d3..58bbc357bc 100644 --- a/article-api/src/test/scala/no/ndla/articleapi/service/ConverterServiceTest.scala +++ b/article-api/src/test/scala/no/ndla/articleapi/service/ConverterServiceTest.scala @@ -203,12 +203,12 @@ class ConverterServiceTest extends UnitSuite with TestEnvironment { val existingArticle = TestData .sampleDomainArticle .copy( - availability = Availability.everyone, - grepCodes = Seq("old", "code"), copyright = Copyright("CC-BY-4.0", Some("origin"), Seq(), Seq(), Seq(), None, None, false), + tags = Seq(Tag(Seq("gammel", "Tag"), "nb")), metaDescription = Seq(Description("gammelDesc", "nb")), + grepCodes = Seq("old", "code"), + availability = Availability.everyone, relatedContent = Seq(Left(RelatedContentLink("title1", "url1")), Right(12L)), - tags = Seq(Tag(Seq("gammel", "Tag"), "nb")), ) val revisionDate = NDLADate.now() @@ -232,18 +232,18 @@ class ConverterServiceTest extends UnitSuite with TestEnvironment { val updatedArticle = TestData .sampleDomainArticle .copy( - availability = Availability.teacher, - grepCodes = Seq("New", "grep", "codes"), copyright = Copyright("newLicense", Some("origin"), Seq(), Seq(), Seq(), None, None, false), + tags = Seq(Tag(Seq("nye", "Tags"), "nb")), metaDescription = Seq(Description("nyDesc", "nb")), + published = revisionDate, + grepCodes = Seq("New", "grep", "codes"), + availability = Availability.teacher, relatedContent = Seq( Left(RelatedContentLink("New Title", "New Url")), Left(RelatedContentLink("Newer Title", "Newer Url")), Right(42L), ), - tags = Seq(Tag(Seq("nye", "Tags"), "nb")), revisionDate = Some(revisionDate), - published = revisionDate, ) service.updateArticleFields(existingArticle, partialArticle) should be(updatedArticle) @@ -254,13 +254,13 @@ class ConverterServiceTest extends UnitSuite with TestEnvironment { val existingArticle = TestData .sampleDomainArticle .copy( - availability = Availability.everyone, - grepCodes = Seq("old", "code"), copyright = Copyright("CC-BY-4.0", Some("origin"), Seq(), Seq(), Seq(), None, None, false), + tags = Seq(Tag(Seq("Gluten", "Tag"), "de")), metaDescription = Seq(Description("oldDesc", "de")), + grepCodes = Seq("old", "code"), + availability = Availability.everyone, relatedContent = Seq(Left(RelatedContentLink("title1", "url1")), Left(RelatedContentLink("old title", "old url"))), - tags = Seq(Tag(Seq("Gluten", "Tag"), "de")), ) val revisionDate = NDLADate.now() @@ -289,14 +289,14 @@ class ConverterServiceTest extends UnitSuite with TestEnvironment { val updatedArticle = TestData .sampleDomainArticle .copy( - availability = Availability.teacher, - grepCodes = Seq("New", "grep", "codes"), copyright = Copyright("newLicense", Some("origin"), Seq(), Seq(), Seq(), None, None, false), + tags = Seq(Tag(Seq("Guten", "Tag"), "de")), metaDescription = Seq(Description("neuDesc", "de")), + published = revisionDate, + grepCodes = Seq("New", "grep", "codes"), + availability = Availability.teacher, relatedContent = Seq(Right(42L), Right(420L), Right(4200L)), - tags = Seq(Tag(Seq("Guten", "Tag"), "de")), revisionDate = Some(revisionDate), - published = revisionDate, ) service.updateArticleFields(existingArticle, partialArticle) should be(updatedArticle) diff --git a/article-api/src/test/scala/no/ndla/articleapi/service/ReadServiceTest.scala b/article-api/src/test/scala/no/ndla/articleapi/service/ReadServiceTest.scala index b13874a6e6..8ed3a6f34d 100644 --- a/article-api/src/test/scala/no/ndla/articleapi/service/ReadServiceTest.scala +++ b/article-api/src/test/scala/no/ndla/articleapi/service/ReadServiceTest.scala @@ -293,8 +293,8 @@ class ReadServiceTest extends UnitSuite with TestEnvironment { title = Seq(Title("Parent title", "nb")), metaDescription = Seq(Description("Parent description", "nb")), metaImage = Seq(ArticleMetaImage("1000", "alt", "nb")), - slug = Some("some-slug"), published = date, + slug = Some("some-slug"), ) val article1 = TestData @@ -304,8 +304,8 @@ class ReadServiceTest extends UnitSuite with TestEnvironment { title = Seq(Title("Article1 title", "nb")), metaDescription = Seq(Description("Article1 description", "nb")), metaImage = Seq(ArticleMetaImage("1000", "alt", "nb")), - slug = Some("slug-one"), published = date, + slug = Some("slug-one"), ) val article2 = TestData @@ -315,8 +315,8 @@ class ReadServiceTest extends UnitSuite with TestEnvironment { title = Seq(Title("Article2 title", "nb")), metaDescription = Seq(Description("Article2 description", "nb")), metaImage = Seq(), - slug = Some("slug-two"), published = date, + slug = Some("slug-two"), ) val frontPage = FrontPageDTO( diff --git a/article-api/src/test/scala/no/ndla/articleapi/service/search/ArticleSearchServiceTest.scala b/article-api/src/test/scala/no/ndla/articleapi/service/search/ArticleSearchServiceTest.scala index 1d1c973a76..602bf7f7ca 100644 --- a/article-api/src/test/scala/no/ndla/articleapi/service/search/ArticleSearchServiceTest.scala +++ b/article-api/src/test/scala/no/ndla/articleapi/service/search/ArticleSearchServiceTest.scala @@ -72,14 +72,14 @@ class ArticleSearchServiceTest extends ElasticsearchIntegrationSuite with UnitSu .copy( id = Option(1), title = List(Title("Batmen er på vift med en bil", "nb")), - introduction = List(Introduction("Batmen", "nb")), content = List( ArticleContent("Bilde av en bil flaggermusmann som vifter med vingene bil.", "nb") ), tags = List(Tag(List("fugl"), "nb")), + introduction = List(Introduction("Batmen", "nb")), + metaImage = List(ArticleMetaImage("5555", "Alt text is here friend", "nb")), created = today.minusDays(4), updated = today.minusDays(3), - metaImage = List(ArticleMetaImage("5555", "Alt text is here friend", "nb")), grepCodes = Seq("KV123", "KV456"), ) @@ -88,9 +88,9 @@ class ArticleSearchServiceTest extends ElasticsearchIntegrationSuite with UnitSu .copy( id = Option(2), title = List(Title("Pingvinen er ute og går", "nb")), - introduction = List(Introduction("Pingvinen", "nb")), content = List(ArticleContent("

Bilde av en

en pingvin som vagger borover en gate

", "nb")), tags = List(Tag(List("fugl"), "nb")), + introduction = List(Introduction("Pingvinen", "nb")), created = today.minusDays(4), updated = today.minusDays(2), grepCodes = Seq("KV123", "KV456"), @@ -101,9 +101,9 @@ class ArticleSearchServiceTest extends ElasticsearchIntegrationSuite with UnitSu .copy( id = Option(3), title = List(Title("Donald Duck kjører bil", "nb")), - introduction = List(Introduction("Donald Duck", "nb")), content = List(ArticleContent("

Bilde av en en and

som kjører en rød bil.

", "nb")), tags = List(Tag(List("and"), "nb")), + introduction = List(Introduction("Donald Duck", "nb")), created = today.minusDays(4), updated = today.minusDays(1), grepCodes = Seq("KV456"), @@ -114,10 +114,10 @@ class ArticleSearchServiceTest extends ElasticsearchIntegrationSuite with UnitSu .copy( id = Option(4), title = List(Title("Superman er ute og flyr", "nb")), - introduction = List(Introduction("Superman", "nb")), content = List(ArticleContent("

Bilde av en flygende mann

som har superkrefter.

", "nb")), tags = List(Tag(List("supermann"), "nb")), + introduction = List(Introduction("Superman", "nb")), created = today.minusDays(4), updated = today, ) @@ -127,9 +127,9 @@ class ArticleSearchServiceTest extends ElasticsearchIntegrationSuite with UnitSu .copy( id = Option(5), title = List(Title("Hulken løfter biler", "nb")), - introduction = List(Introduction("Hulken", "nb")), content = List(ArticleContent("

Bilde av hulk

som løfter en rød bil.

", "nb")), tags = List(Tag(List("hulk"), "nb")), + introduction = List(Introduction("Hulken", "nb")), created = today.minusDays(40), updated = today.minusDays(35), ) @@ -139,7 +139,6 @@ class ArticleSearchServiceTest extends ElasticsearchIntegrationSuite with UnitSu .copy( id = Option(6), title = List(Title("Loke og Tor prøver å fange midgaardsormen", "nb")), - introduction = List(Introduction("Loke og Tor", "nb")), content = List( ArticleContent( "

Bilde av Loke og Tor

som fisker fra Naglfar.

", @@ -147,6 +146,7 @@ class ArticleSearchServiceTest extends ElasticsearchIntegrationSuite with UnitSu ) ), tags = List(Tag(List("Loke", "Tor", "Naglfar"), "nb")), + introduction = List(Introduction("Loke og Tor", "nb")), created = today.minusDays(30), updated = today.minusDays(25), ) @@ -156,9 +156,9 @@ class ArticleSearchServiceTest extends ElasticsearchIntegrationSuite with UnitSu .copy( id = Option(7), title = List(Title("Yggdrasil livets tre", "nb")), - introduction = List(Introduction("Yggdrasil", "nb")), content = List(ArticleContent("

Bilde av Yggdrasil livets tre med alle dyrene som bor i det.", "nb")), tags = List(Tag(List("yggdrasil"), "nb")), + introduction = List(Introduction("Yggdrasil", "nb")), created = today.minusDays(20), updated = today.minusDays(15), ) @@ -168,9 +168,9 @@ class ArticleSearchServiceTest extends ElasticsearchIntegrationSuite with UnitSu .copy( id = Option(8), title = List(Title("Baldur har mareritt", "nb")), - introduction = List(Introduction("Baldur", "nb")), content = List(ArticleContent("

Bilde av Baldurs mareritt om Ragnarok.", "nb")), tags = List(Tag(List("baldur"), "nb")), + introduction = List(Introduction("Baldur", "nb")), created = today.minusDays(10), updated = today.minusDays(5), articleType = ArticleType.TopicArticle, @@ -181,9 +181,9 @@ class ArticleSearchServiceTest extends ElasticsearchIntegrationSuite with UnitSu .copy( id = Option(9), title = List(Title("En Baldur har mareritt om Ragnarok", "nb")), - introduction = List(Introduction("Baldur", "nb")), content = List(ArticleContent("

Bilde av Baldurs som har mareritt.", "nb")), tags = List(Tag(List("baldur"), "nb")), + introduction = List(Introduction("Baldur", "nb")), created = today.minusDays(10), updated = today.minusDays(5), articleType = ArticleType.TopicArticle, @@ -194,9 +194,9 @@ class ArticleSearchServiceTest extends ElasticsearchIntegrationSuite with UnitSu .copy( id = Option(10), title = List(Title("This article is in english", "en")), - introduction = List(Introduction("Engulsk", "en")), content = List(ArticleContent("

Something something english What about", "en")), tags = List(Tag(List("englando"), "en")), + introduction = List(Introduction("Engulsk", "en")), created = today.minusDays(10), updated = today.minusDays(5), articleType = ArticleType.TopicArticle, @@ -207,15 +207,15 @@ class ArticleSearchServiceTest extends ElasticsearchIntegrationSuite with UnitSu .copy( id = Option(11), title = List(Title("Katter", "nb"), Title("Cats", "en"), Title("Baloi", "biz")), + content = + List(ArticleContent("

Noe om en katt

", "nb"), ArticleContent("

Something about a cat

", "en")), + tags = List(Tag(List("ikkehund"), "nb"), Tag(List("notdog"), "en")), introduction = List( Introduction("Katter er store", "nb"), Introduction("Cats are big", "en"), Introduction("Cats are baloi", "biz"), ), metaDescription = List(Description("hurr durr ima sheep", "en")), - content = - List(ArticleContent("

Noe om en katt

", "nb"), ArticleContent("

Something about a cat

", "en")), - tags = List(Tag(List("ikkehund"), "nb"), Tag(List("notdog"), "en")), created = today.minusDays(10), updated = today.minusDays(5), articleType = ArticleType.TopicArticle, @@ -226,10 +226,10 @@ class ArticleSearchServiceTest extends ElasticsearchIntegrationSuite with UnitSu .copy( id = Option(12), title = List(Title("availability - Hemmelig lærer artikkel", "nb")), - introduction = List(Introduction("Lærer", "nb")), - metaDescription = List(Description("lærer", "nb")), content = List(ArticleContent("

Lærer

", "nb")), tags = List(Tag(List("lærer"), "nb")), + introduction = List(Introduction("Lærer", "nb")), + metaDescription = List(Description("lærer", "nb")), created = today.minusDays(10), updated = today.minusDays(5), articleType = ArticleType.Standard, @@ -241,10 +241,10 @@ class ArticleSearchServiceTest extends ElasticsearchIntegrationSuite with UnitSu .copy( id = Option(13), title = List(Title("availability - Hemmelig student artikkel", "nb")), - introduction = List(Introduction("Student", "nb")), - metaDescription = List(Description("student", "nb")), content = List(ArticleContent("

Student

", "nb")), tags = List(Tag(List("student"), "nb")), + introduction = List(Introduction("Student", "nb")), + metaDescription = List(Description("student", "nb")), created = today.minusDays(10), updated = today.minusDays(5), articleType = ArticleType.Standard, diff --git a/common/src/main/scala/no/ndla/common/model/api/search/MultiSearchSummaryDTO.scala b/common/src/main/scala/no/ndla/common/model/api/search/MultiSearchSummaryDTO.scala index be0fa57491..739be813d8 100644 --- a/common/src/main/scala/no/ndla/common/model/api/search/MultiSearchSummaryDTO.scala +++ b/common/src/main/scala/no/ndla/common/model/api/search/MultiSearchSummaryDTO.scala @@ -138,6 +138,8 @@ case class MultiSearchSummaryDTO( resultType: SearchType, @description("List of codes the resource is tagged with") grepCodes: Seq[String], + @description("Number of times resource is published") + publishedCount: Option[Int], ) extends MultiSummaryBaseDTO object MultiSearchSummaryDTO extends SchemaImplicits { diff --git a/common/src/main/scala/no/ndla/common/model/domain/article/Article.scala b/common/src/main/scala/no/ndla/common/model/domain/article/Article.scala index ff2a5e40b6..2dfe63a21a 100644 --- a/common/src/main/scala/no/ndla/common/model/domain/article/Article.scala +++ b/common/src/main/scala/no/ndla/common/model/domain/article/Article.scala @@ -41,6 +41,7 @@ case class Article( slug: Option[String], disclaimer: OptLanguageFields[String], traits: List[ArticleTrait], + publishedCount: Option[Int], ) extends Content object Article { diff --git a/common/src/main/scala/no/ndla/common/model/domain/draft/Draft.scala b/common/src/main/scala/no/ndla/common/model/domain/draft/Draft.scala index a9bf0c2a14..39b4a70065 100644 --- a/common/src/main/scala/no/ndla/common/model/domain/draft/Draft.scala +++ b/common/src/main/scala/no/ndla/common/model/domain/draft/Draft.scala @@ -52,6 +52,7 @@ case class Draft( qualityEvaluation: Option[QualityEvaluation], disclaimer: OptLanguageFields[String], traits: List[ArticleTrait], + publishedCount: Int, ) extends Content { def supportedLanguages: Seq[String] = getSupportedLanguages( diff --git a/common/src/test/scala/no/ndla/common/model/api/search/MultiSearchSummaryDTOTest.scala b/common/src/test/scala/no/ndla/common/model/api/search/MultiSearchSummaryDTOTest.scala index fe848a8db5..733d8f2b28 100644 --- a/common/src/test/scala/no/ndla/common/model/api/search/MultiSearchSummaryDTOTest.scala +++ b/common/src/test/scala/no/ndla/common/model/api/search/MultiSearchSummaryDTOTest.scala @@ -53,6 +53,8 @@ class MultiSearchSummaryDTOTest extends UnitTestSuiteBase { paths = List(), lastUpdated = now, license = None, + revision = None, + started = false, revisions = Seq(), responsible = None, comments = None, @@ -64,8 +66,7 @@ class MultiSearchSummaryDTOTest extends UnitTestSuiteBase { favorited = None, resultType = SearchType.Articles, grepCodes = Seq.empty, - revision = None, - started = false, + publishedCount = Some(1), ) import io.circe.syntax.* diff --git a/draft-api/src/main/scala/no/ndla/draftapi/db/migration/V83__SetPublishedCount.scala b/draft-api/src/main/scala/no/ndla/draftapi/db/migration/V83__SetPublishedCount.scala new file mode 100644 index 0000000000..deb1c44748 --- /dev/null +++ b/draft-api/src/main/scala/no/ndla/draftapi/db/migration/V83__SetPublishedCount.scala @@ -0,0 +1,53 @@ +/* + * Part of NDLA draft-api + * Copyright (C) 2026 NDLA + * + * See LICENSE + * + */ + +package no.ndla.draftapi.db.migration + +import io.circe.{Json, parser} +import no.ndla.database.TableMigration +import org.postgresql.util.PGobject +import scalikejdbc.{DBSession, SQLSyntax, WrappedResultSet} +import scalikejdbc.interpolation.Implicits.scalikejdbcSQLInterpolationImplicitDef + +case class DocumentRow(id: Long, revision: Int, articleId: Long, document: String) + +class V83__SetPublishedCount extends TableMigration[DocumentRow] { + val columnName: String = "document" + override val tableName: String = "articledata" + + private lazy val columnNameSQL: SQLSyntax = SQLSyntax.createUnsafely(columnName) + override lazy val whereClause: SQLSyntax = sqls"$columnNameSQL is not null" + + private def countOtherVersions(revision: Int, articleId: Long)(implicit session: DBSession): Long = { + sql"select count(*) from $tableNameSQL where revision < $revision and article_id = $articleId and $columnNameSQL -> 'status' ->> 'current' = 'PUBLISHED'" + .map(rs => rs.long("count")) + .single() + .getOrElse(0L) + } + + override def extractRowData(rs: WrappedResultSet): DocumentRow = + DocumentRow(rs.long("id"), rs.int("revision"), rs.long("article_id"), rs.string(columnName)) + + override def updateRow(rowData: DocumentRow)(implicit session: DBSession): Int = { + var other = countOtherVersions(rowData.revision, rowData.articleId) + val oldDocument = parser.parse(rowData.document).toTry.get + val published = oldDocument.hcursor.downField("status").downField("current").as[String].toTry.getOrElse("") + if (published == "PUBLISHED") { + other = other + 1 + } + val newDoc = oldDocument.mapObject(_.add("publishedCount", Json.fromLong(other))).noSpaces + + val dataObject = new PGobject() + dataObject.setType("jsonb") + dataObject.setValue(newDoc) + sql"""update $tableNameSQL + set $columnNameSQL = $dataObject + where id = ${rowData.id} + """.update() + } +} diff --git a/draft-api/src/main/scala/no/ndla/draftapi/model/api/ArticleDTO.scala b/draft-api/src/main/scala/no/ndla/draftapi/model/api/ArticleDTO.scala index 5530cdcd00..281557d380 100644 --- a/draft-api/src/main/scala/no/ndla/draftapi/model/api/ArticleDTO.scala +++ b/draft-api/src/main/scala/no/ndla/draftapi/model/api/ArticleDTO.scala @@ -97,6 +97,8 @@ case class ArticleDTO( disclaimer: Option[DisclaimerDTO], @description("Traits extracted from the article content") traits: List[ArticleTrait], + @description("Number of times the article is published") + publishedCount: Int, ) object ArticleDTO { diff --git a/draft-api/src/main/scala/no/ndla/draftapi/service/ConverterService.scala b/draft-api/src/main/scala/no/ndla/draftapi/service/ConverterService.scala index 10d3188c1d..5cc9547a83 100644 --- a/draft-api/src/main/scala/no/ndla/draftapi/service/ConverterService.scala +++ b/draft-api/src/main/scala/no/ndla/draftapi/service/ConverterService.scala @@ -129,6 +129,7 @@ class ConverterService(using qualityEvaluation = qualityEvaluationToDomain(newArticle.qualityEvaluation), disclaimer = domainDisclaimer, traits = traits, + publishedCount = 0, ) ) } @@ -334,6 +335,7 @@ class ConverterService(using qualityEvaluation = toApiQualityEvaluation(article.qualityEvaluation), disclaimer = disclaimer, traits = article.traits, + publishedCount = article.publishedCount, ) ) } else { @@ -521,6 +523,7 @@ class ConverterService(using slug = draft.slug, disclaimer = draft.disclaimer, traits = draft.traits, + publishedCount = Some(draft.publishedCount), ) ) } @@ -739,6 +742,7 @@ class ConverterService(using qualityEvaluation = qualityEvaluationToDomain(article.qualityEvaluation), disclaimer = updatedDisclaimer, traits = traitUtil.getArticleTraits(updatedContents), + publishedCount = toMergeInto.publishedCount, ) Success(converted) diff --git a/draft-api/src/main/scala/no/ndla/draftapi/service/StateTransitionRules.scala b/draft-api/src/main/scala/no/ndla/draftapi/service/StateTransitionRules.scala index efba21ba44..cba33bdded 100644 --- a/draft-api/src/main/scala/no/ndla/draftapi/service/StateTransitionRules.scala +++ b/draft-api/src/main/scala/no/ndla/draftapi/service/StateTransitionRules.scala @@ -78,13 +78,14 @@ class StateTransitionRules(using (article, user) => article.id match { case Some(id) => for { - externalIds <- dbUtility.readOnly(implicit session => draftRepository.getExternalIdsFromId(id)) - h5pPaths = converterService.getEmbeddedH5PPaths(article) - _ = h5pApiClient.publishH5Ps(h5pPaths, user) - taxonomyT = taxonomyApiClient.updateTaxonomyIfExists(id, article, user) - articleUpdateT = articleApiClient.updateArticle(id, article, externalIds, useSoftValidation, user) - _ <- taxonomyT - articleUpdate <- articleUpdateT + externalIds <- dbUtility.readOnly(implicit session => draftRepository.getExternalIdsFromId(id)) + h5pPaths = converterService.getEmbeddedH5PPaths(article) + _ = h5pApiClient.publishH5Ps(h5pPaths, user) + withPublishCount = article.copy(publishedCount = article.publishedCount + 1) + taxonomyT = taxonomyApiClient.updateTaxonomyIfExists(id, article, user) + articleUpdateT = articleApiClient.updateArticle(id, withPublishCount, externalIds, useSoftValidation, user) + _ <- taxonomyT + articleUpdate <- articleUpdateT } yield articleUpdate case None => Failure(NotFoundException("This is a bug, article to publish has no id.")) }, @@ -262,7 +263,7 @@ class StateTransitionRules(using } } - def debugLog(x: Any): Unit = { + private def debugLog(x: Any): Unit = { if (scala.util.Properties.propOrEmpty("DEBUG_FLAKE") == "true") { println(x) } diff --git a/draft-api/src/main/scala/no/ndla/draftapi/service/WriteService.scala b/draft-api/src/main/scala/no/ndla/draftapi/service/WriteService.scala index 62be524893..2ccd3e7466 100644 --- a/draft-api/src/main/scala/no/ndla/draftapi/service/WriteService.scala +++ b/draft-api/src/main/scala/no/ndla/draftapi/service/WriteService.scala @@ -203,7 +203,9 @@ class WriteService(using } } - def updateArticleAndStoreAsNewIfPublished(article: Draft, statusWasUpdated: Boolean)(using DBSession): Try[Draft] = { + private def updateArticleAndStoreAsNewIfPublished(article: Draft, statusWasUpdated: Boolean)(using + DBSession + ): Try[Draft] = { val storeAsNewVersion = statusWasUpdated && article.status.current == PUBLISHED draftRepository.updateArticle(article) match { case Success(updated) if storeAsNewVersion => draftRepository.storeArticleAsNewVersion(updated, None) diff --git a/draft-api/src/main/scala/no/ndla/draftapi/validation/ContentValidator.scala b/draft-api/src/main/scala/no/ndla/draftapi/validation/ContentValidator.scala index 5abcfe8995..36fdbdbd58 100644 --- a/draft-api/src/main/scala/no/ndla/draftapi/validation/ContentValidator.scala +++ b/draft-api/src/main/scala/no/ndla/draftapi/validation/ContentValidator.scala @@ -73,12 +73,12 @@ class ContentValidator(using private def getArticleOnLanguage(article: Draft, language: String): Draft = { article.copy( - content = article.content.filter(_.language == language), - introduction = article.introduction.filter(_.language == language), - metaDescription = article.metaDescription.filter(_.language == language), title = article.title.filter(_.language == language), + content = article.content.filter(_.language == language), tags = article.tags.filter(_.language == language), visualElement = article.visualElement.filter(_.language == language), + introduction = article.introduction.filter(_.language == language), + metaDescription = article.metaDescription.filter(_.language == language), metaImage = article.metaImage.filter(_.language == language), ) } @@ -130,12 +130,12 @@ class ContentValidator(using .withSortedLanguageFields(article) .copy( revision = None, + updated = NDLADate.MIN, + updatedBy = "", notes = Seq.empty, editorLabels = Seq.empty, - comments = List.empty, - updated = NDLADate.MIN, revisionMeta = Seq.empty, - updatedBy = "", + comments = List.empty, ) withComparableValues(oldArticle) == withComparableValues(changedArticle) diff --git a/draft-api/src/test/scala/no/ndla/draftapi/TestData.scala b/draft-api/src/test/scala/no/ndla/draftapi/TestData.scala index f45896e6da..db118e368e 100644 --- a/draft-api/src/test/scala/no/ndla/draftapi/TestData.scala +++ b/draft-api/src/test/scala/no/ndla/draftapi/TestData.scala @@ -121,6 +121,7 @@ object TestData { qualityEvaluation = None, disclaimer = None, traits = List.empty, + publishedCount = 1, ) val blankUpdatedArticle: UpdatedArticleDTO = api.UpdatedArticleDTO( @@ -240,6 +241,7 @@ object TestData { qualityEvaluation = None, disclaimer = None, traits = List.empty, + publishedCount = 1, ) val apiArticleUserTest: api.ArticleDTO = api.ArticleDTO( @@ -296,6 +298,7 @@ object TestData { qualityEvaluation = None, disclaimer = None, traits = List.empty, + publishedCount = 1, ) val sampleTopicArticle: Draft = Draft( @@ -332,6 +335,7 @@ object TestData { qualityEvaluation = None, disclaimer = OptLanguageFields.empty, traits = List.empty, + publishedCount = 0, ) val sampleArticleWithPublicDomain: Draft = Draft( @@ -368,6 +372,7 @@ object TestData { qualityEvaluation = None, disclaimer = OptLanguageFields.empty, traits = List.empty, + publishedCount = 0, ) val sampleDomainArticle: Draft = Draft( @@ -406,6 +411,7 @@ object TestData { qualityEvaluation = None, disclaimer = OptLanguageFields.empty, traits = List.empty, + publishedCount = 1, ) val newArticle: NewArticleDTO = api.NewArticleDTO( @@ -460,9 +466,9 @@ object TestData { content = Seq( common.ArticleContent( """ - | - |
  1. Det er ikke lov å gjøre dette.

  2. Dette er helt ok
- |
  1. Det er ikke lov å gjøre dette.

  2. Dette er helt ok
+ | + |
  1. Det er ikke lov å gjøre dette.

  2. Dette er helt ok
+ |
  1. Det er ikke lov å gjøre dette.

  2. Dette er helt ok
""".stripMargin, "en", ) @@ -508,6 +514,7 @@ object TestData { qualityEvaluation = None, disclaimer = OptLanguageFields.empty, traits = List.empty, + publishedCount = 0, ) val apiArticleWithHtmlFaultV2: api.ArticleDTO = api.ArticleDTO( @@ -519,9 +526,9 @@ object TestData { content = Some( api.ArticleContentDTO( """ - | - |
  1. Det er ikke lov å gjøre dette.

  2. Dette er helt ok
- |
  1. Det er ikke lov å gjøre dette.

  2. Dette er helt ok
+ | + |
  1. Det er ikke lov å gjøre dette.

  2. Dette er helt ok
+ |
  1. Det er ikke lov å gjøre dette.

  2. Dette er helt ok
""".stripMargin, "en", ) @@ -567,6 +574,7 @@ object TestData { qualityEvaluation = None, disclaimer = None, traits = List.empty, + publishedCount = 1, ) val (nodeId, nodeId2) = ("1234", "4321") diff --git a/draft-api/src/test/scala/no/ndla/draftapi/service/ConverterServiceTest.scala b/draft-api/src/test/scala/no/ndla/draftapi/service/ConverterServiceTest.scala index 3ff5d79f84..1f581e6aea 100644 --- a/draft-api/src/test/scala/no/ndla/draftapi/service/ConverterServiceTest.scala +++ b/draft-api/src/test/scala/no/ndla/draftapi/service/ConverterServiceTest.scala @@ -193,6 +193,7 @@ class ConverterServiceTest extends UnitSuite with TestEnvironment { qualityEvaluation = None, disclaimer = OptLanguageFields.withValue("Disclaimer test", "nb"), traits = List.empty, + publishedCount = 0, ) val updatedNothing = TestData.blankUpdatedArticle.copy(revision = 4, language = Some("nb")) @@ -239,6 +240,7 @@ class ConverterServiceTest extends UnitSuite with TestEnvironment { qualityEvaluation = None, disclaimer = OptLanguageFields.withValue("Disclaimer test", "nb"), traits = List.empty, + publishedCount = 0, ) val expectedArticle = Draft( @@ -275,6 +277,7 @@ class ConverterServiceTest extends UnitSuite with TestEnvironment { qualityEvaluation = None, disclaimer = OptLanguageFields.withValue("NyDisclaimer test", "nb"), traits = List.empty, + publishedCount = 0, ) val updatedEverything = TestData @@ -344,6 +347,7 @@ class ConverterServiceTest extends UnitSuite with TestEnvironment { qualityEvaluation = None, disclaimer = OptLanguageFields.empty, traits = List.empty, + publishedCount = 0, ) val expectedArticle = Draft( @@ -388,6 +392,7 @@ class ConverterServiceTest extends UnitSuite with TestEnvironment { qualityEvaluation = None, disclaimer = OptLanguageFields.empty, traits = List.empty, + publishedCount = 0, ) val updatedEverything = TestData @@ -627,7 +632,7 @@ class ConverterServiceTest extends UnitSuite with TestEnvironment { ): @unchecked res1.availability should be(Availability.teacher) - res1.availability should not be (Availability.everyone) + res1.availability should not be Availability.everyone // Should default til everyone res2.availability should be(Availability.everyone) res3.availability should be(Availability.everyone) @@ -717,9 +722,9 @@ class ConverterServiceTest extends UnitSuite with TestEnvironment { ): @unchecked res1.responsible.get.responsibleId should be("nyid") - res1.responsible.get.lastUpdated should not be (yesterday) + res1.responsible.get.lastUpdated should not be yesterday res2.responsible.get.responsibleId should be("nyid") - res2.responsible.get.lastUpdated should not be (yesterday) + res2.responsible.get.lastUpdated should not be yesterday res3.responsible.get.responsibleId should be("oldId") res3.responsible.get.lastUpdated should be(yesterday) } @@ -761,6 +766,7 @@ class ConverterServiceTest extends UnitSuite with TestEnvironment { qualityEvaluation = None, disclaimer = OptLanguageFields.withValue("articleDisclaimer", "nb"), traits = List.empty, + publishedCount = 1, ) val article = common .model @@ -795,6 +801,7 @@ class ConverterServiceTest extends UnitSuite with TestEnvironment { slug = Some("kjempe-slug"), disclaimer = OptLanguageFields.withValue("articleDisclaimer", "nb"), traits = List.empty, + publishedCount = Some(1), ) val result = service.toArticleApiArticle(draft) diff --git a/draft-api/src/test/scala/no/ndla/draftapi/service/StateTransitionRulesTest.scala b/draft-api/src/test/scala/no/ndla/draftapi/service/StateTransitionRulesTest.scala index e5530cfec7..e68bf63785 100644 --- a/draft-api/src/test/scala/no/ndla/draftapi/service/StateTransitionRulesTest.scala +++ b/draft-api/src/test/scala/no/ndla/draftapi/service/StateTransitionRulesTest.scala @@ -136,7 +136,11 @@ class StateTransitionRulesTest extends UnitSuite with TestEnvironment { test("doTransition should publish the article when transitioning to PUBLISHED") { val expectedStatus = common.Status(PUBLISHED, Set.empty) val editorNotes = Seq(common.EditorNote("Status endret", "unit_test", expectedStatus, NDLADate.now())) - val expectedArticle = InProcessArticle.copy(status = expectedStatus, notes = editorNotes) + val expectedArticle = InProcessArticle.copy( + status = expectedStatus, + notes = editorNotes, + publishedCount = InProcessArticle.publishedCount + 1, + ) when(draftRepository.getExternalIdsFromId(any[Long])(using any[DBSession])).thenReturn(Success(List("1234"))) when(converterService.getEmbeddedConceptIds(any[Draft])).thenReturn(Seq.empty) when(converterService.getEmbeddedH5PPaths(any[Draft])).thenReturn(Seq.empty) @@ -362,6 +366,7 @@ class StateTransitionRulesTest extends UnitSuite with TestEnvironment { qualityEvaluation = None, disclaimer = OptLanguageFields.empty, traits = List.empty, + publishedCount = 0, ) val article = common .article @@ -390,6 +395,7 @@ class StateTransitionRulesTest extends UnitSuite with TestEnvironment { slug = None, disclaimer = OptLanguageFields.empty, traits = List.empty, + publishedCount = Some(1), ) val status = common.Status(END_CONTROL, Set.empty) @@ -417,7 +423,11 @@ class StateTransitionRulesTest extends UnitSuite with TestEnvironment { val h5pPaths = Seq(s"/resource/$h5pId") val expectedStatus = common.Status(PUBLISHED, Set.empty) val editorNotes = Seq(common.EditorNote("Status endret", "unit_test", expectedStatus, NDLADate.now())) - val expectedArticle = InProcessArticle.copy(status = expectedStatus, notes = editorNotes) + val expectedArticle = InProcessArticle.copy( + status = expectedStatus, + notes = editorNotes, + publishedCount = InProcessArticle.publishedCount + 1, + ) when(draftRepository.getExternalIdsFromId(any[Long])(using any[DBSession])).thenReturn(Success(List("1234"))) when(converterService.getEmbeddedConceptIds(any[Draft])).thenReturn(Seq.empty) when(converterService.getEmbeddedH5PPaths(any[Draft])).thenReturn(h5pPaths) @@ -491,6 +501,7 @@ class StateTransitionRulesTest extends UnitSuite with TestEnvironment { qualityEvaluation = None, disclaimer = OptLanguageFields.empty, traits = List.empty, + publishedCount = 0, ) val status = common.Status(PLANNED, Set.empty) val transitionsToTest = stateTransitionRules.StateTransitions.filter(_.to == PUBLISHED) @@ -550,6 +561,7 @@ class StateTransitionRulesTest extends UnitSuite with TestEnvironment { qualityEvaluation = None, disclaimer = OptLanguageFields.empty, traits = List.empty, + publishedCount = 0, ) val status = common.Status(PLANNED, Set.empty) val transitionsToTest = stateTransitionRules.StateTransitions.filter(_.to == ARCHIVED) @@ -611,6 +623,7 @@ class StateTransitionRulesTest extends UnitSuite with TestEnvironment { qualityEvaluation = None, disclaimer = OptLanguageFields.empty, traits = List.empty, + publishedCount = 0, ) val status = common.Status(PLANNED, Set.empty) val transitionsToTest = stateTransitionRules.StateTransitions.filter(_.to == UNPUBLISHED) @@ -673,6 +686,7 @@ class StateTransitionRulesTest extends UnitSuite with TestEnvironment { qualityEvaluation = None, disclaimer = OptLanguageFields.empty, traits = List.empty, + publishedCount = 0, ) val status = common.Status(PUBLISHED, Set.empty) val transitionToTest: StateTransition = PUBLISHED -> IN_PROGRESS diff --git a/draft-api/src/test/scala/no/ndla/draftapi/validation/ContentValidatorTest.scala b/draft-api/src/test/scala/no/ndla/draftapi/validation/ContentValidatorTest.scala index 57bc453dad..c595f75735 100644 --- a/draft-api/src/test/scala/no/ndla/draftapi/validation/ContentValidatorTest.scala +++ b/draft-api/src/test/scala/no/ndla/draftapi/validation/ContentValidatorTest.scala @@ -25,7 +25,7 @@ import java.util.UUID import scala.util.{Failure, Success} class ContentValidatorTest extends UnitSuite with TestEnvironment { - override implicit lazy val dbUtility = new DBUtility + override implicit lazy val dbUtility: DBUtility = new DBUtility override implicit lazy val contentValidator: ContentValidator = new ContentValidator() override implicit lazy val converterService: ConverterService = new ConverterService val validDocument = """

heisann

heia

""" diff --git a/integration-tests/src/test/scala/no/ndla/integrationtests/draftapi/articleapi/ArticleApiClientTest.scala b/integration-tests/src/test/scala/no/ndla/integrationtests/draftapi/articleapi/ArticleApiClientTest.scala index a4dd09da4c..180890ca08 100644 --- a/integration-tests/src/test/scala/no/ndla/integrationtests/draftapi/articleapi/ArticleApiClientTest.scala +++ b/integration-tests/src/test/scala/no/ndla/integrationtests/draftapi/articleapi/ArticleApiClientTest.scala @@ -135,6 +135,7 @@ class ArticleApiClientTest qualityEvaluation = None, disclaimer = OptLanguageFields.empty, traits = List.empty, + publishedCount = 0, ) val exampleToken = @@ -156,8 +157,8 @@ class ArticleApiClientTest td.sampleDomainArticle .copy( id = Some(id), - updated = NDLADate.fromUnixTime(0), created = NDLADate.fromUnixTime(0), + updated = NDLADate.fromUnixTime(0), published = NDLADate.fromUnixTime(0), ), List(s"1$id"), diff --git a/integration-tests/src/test/scala/no/ndla/integrationtests/searchapi/articleapi/ArticleApiClientTest.scala b/integration-tests/src/test/scala/no/ndla/integrationtests/searchapi/articleapi/ArticleApiClientTest.scala index ee34516f64..977629ed20 100644 --- a/integration-tests/src/test/scala/no/ndla/integrationtests/searchapi/articleapi/ArticleApiClientTest.scala +++ b/integration-tests/src/test/scala/no/ndla/integrationtests/searchapi/articleapi/ArticleApiClientTest.scala @@ -93,8 +93,8 @@ class ArticleApiClientTest td.sampleDomainArticle .copy( id = Some(id), - updated = NDLADate.fromUnixTime(0), created = NDLADate.fromUnixTime(0), + updated = NDLADate.fromUnixTime(0), published = NDLADate.fromUnixTime(0), ), List(s"1$id"), diff --git a/search-api/src/main/scala/no/ndla/searchapi/controller/SearchController.scala b/search-api/src/main/scala/no/ndla/searchapi/controller/SearchController.scala index ce31febdbf..62acc822c2 100644 --- a/search-api/src/main/scala/no/ndla/searchapi/controller/SearchController.scala +++ b/search-api/src/main/scala/no/ndla/searchapi/controller/SearchController.scala @@ -399,6 +399,7 @@ class SearchController(using publishedDateTo = dateParamOrNone("published-date-to"), resultTypes = stringListParam("result-types").flatMap(SearchType.withNameOption).some, tags = stringListParam("tags").some, + publishedCount = intParamOrNone("published-count"), ) ) @@ -557,6 +558,7 @@ class SearchController(using publishedFilterTo = params.publishedDateTo, resultTypes = params.resultTypes, tags = params.tags.getOrElse(List.empty), + publishedCount = params.publishedCount, ) } } diff --git a/search-api/src/main/scala/no/ndla/searchapi/controller/parameters/DraftSearchParamsDTO.scala b/search-api/src/main/scala/no/ndla/searchapi/controller/parameters/DraftSearchParamsDTO.scala index 99423296cb..d41ba30ad2 100644 --- a/search-api/src/main/scala/no/ndla/searchapi/controller/parameters/DraftSearchParamsDTO.scala +++ b/search-api/src/main/scala/no/ndla/searchapi/controller/parameters/DraftSearchParamsDTO.scala @@ -50,16 +50,16 @@ case class DraftSearchParamsDTO( languageFilter: Option[List[String]], @description( """A list of relevances the learning resources should be filtered by. - |If subjects are specified the learning resource must have specified relevances in relation to a specified subject. - |If levels are specified the learning resource must have specified relevances in relation to a specified level.""" + |If subjects are specified the learning resource must have specified relevances in relation to a specified subject. + |If levels are specified the learning resource must have specified relevances in relation to a specified level.""" .stripMargin ) relevance: Option[List[String]], @description( s"""A unique string obtained from a search you want to keep scrolling in. To obtain one from a search, provide one of the following values: ["0", "initial", "start", "first"]. - |When scrolling, the parameters from the initial search is used, except in the case of 'language' and 'fallback'. - |This value may change between scrolls. Always use the one in the latest scroll result. - |""".stripMargin + |When scrolling, the parameters from the initial search is used, except in the case of 'language' and 'fallback'. + |This value may change between scrolls. Always use the one in the latest scroll result. + |""".stripMargin ) scrollId: Option[String], @description( @@ -67,8 +67,8 @@ case class DraftSearchParamsDTO( ) draftStatus: Option[List[String]], @description(s"""List of users to filter by. - |The value to search for is the user-id from Auth0. - |UpdatedBy on article and user in editorial-notes are searched.""".stripMargin) + |The value to search for is the user-id from Auth0. + |UpdatedBy on article and user in editorial-notes are searched.""".stripMargin) users: Option[List[String]], @description("A list of codes from GREP API the resources should be filtered by.") grepCodes: Option[List[String]], @@ -106,6 +106,8 @@ case class DraftSearchParamsDTO( resultTypes: Option[List[SearchType]], @description("Only return results that have one of the specified tags.") tags: Option[List[String]], + @description("Only return results that have specified publishedCount") + publishedCount: Option[Int], ) object DraftSearchParamsDTO { diff --git a/search-api/src/main/scala/no/ndla/searchapi/model/search/SearchableArticle.scala b/search-api/src/main/scala/no/ndla/searchapi/model/search/SearchableArticle.scala index 8ff4d731eb..f84c50fb01 100644 --- a/search-api/src/main/scala/no/ndla/searchapi/model/search/SearchableArticle.scala +++ b/search-api/src/main/scala/no/ndla/searchapi/model/search/SearchableArticle.scala @@ -43,6 +43,7 @@ case class SearchableArticle( availability: String, learningResourceType: LearningResourceType, typeName: List[String], + publishedCount: Int, domainObject: Article, nodes: List[Node], ) diff --git a/search-api/src/main/scala/no/ndla/searchapi/model/search/SearchableDraft.scala b/search-api/src/main/scala/no/ndla/searchapi/model/search/SearchableDraft.scala index b041e2208c..4bd6b467ee 100644 --- a/search-api/src/main/scala/no/ndla/searchapi/model/search/SearchableDraft.scala +++ b/search-api/src/main/scala/no/ndla/searchapi/model/search/SearchableDraft.scala @@ -61,6 +61,7 @@ case class SearchableDraft( favorited: Long, learningResourceType: LearningResourceType, typeName: List[String], + publishedCount: Int, domainObject: Draft, nodes: List[Node], ) diff --git a/search-api/src/main/scala/no/ndla/searchapi/model/search/settings/MultiDraftSearchSettings.scala b/search-api/src/main/scala/no/ndla/searchapi/model/search/settings/MultiDraftSearchSettings.scala index 99b00b07b3..b183d6342b 100644 --- a/search-api/src/main/scala/no/ndla/searchapi/model/search/settings/MultiDraftSearchSettings.scala +++ b/search-api/src/main/scala/no/ndla/searchapi/model/search/settings/MultiDraftSearchSettings.scala @@ -56,6 +56,7 @@ case class MultiDraftSearchSettings( publishedFilterTo: Option[NDLADate], resultTypes: Option[List[SearchType]], tags: List[String], + publishedCount: Option[Int], ) object MultiDraftSearchSettings { @@ -93,9 +94,10 @@ object MultiDraftSearchSettings { articleTypes = List.empty, filterInactive = false, priority = List.empty, - publishedFilterTo = None, publishedFilterFrom = None, + publishedFilterTo = None, resultTypes = Some(List(SearchType.Articles, SearchType.LearningPaths)), tags = List.empty, + publishedCount = None, ) } diff --git a/search-api/src/main/scala/no/ndla/searchapi/service/search/ArticleIndexService.scala b/search-api/src/main/scala/no/ndla/searchapi/service/search/ArticleIndexService.scala index d55aa45885..aaf8c21994 100644 --- a/search-api/src/main/scala/no/ndla/searchapi/service/search/ArticleIndexService.scala +++ b/search-api/src/main/scala/no/ndla/searchapi/service/search/ArticleIndexService.scala @@ -93,6 +93,7 @@ class ArticleIndexService(using ), nestedField("metaImage").fields(keywordField("imageId"), keywordField("altText"), keywordField("language")), dateField("nextRevision.revisionDate"), // This is needed for sorting, even if it is never used for articles + intField("publishedCount"), ) val dynamics = languageValuesMapping("title", keepRaw = true) ++ languageValuesMapping("metaDescription") ++ diff --git a/search-api/src/main/scala/no/ndla/searchapi/service/search/DraftIndexService.scala b/search-api/src/main/scala/no/ndla/searchapi/service/search/DraftIndexService.scala index 792bfdd9a1..03a668d524 100644 --- a/search-api/src/main/scala/no/ndla/searchapi/service/search/DraftIndexService.scala +++ b/search-api/src/main/scala/no/ndla/searchapi/service/search/DraftIndexService.scala @@ -112,6 +112,7 @@ class DraftIndexService(using keywordField("defaultParentTopicName"), keywordField("defaultRoot"), keywordField("defaultResourceTypeName"), + intField("publishedCount"), ) val dynamics = languageValuesMapping("title", keepRaw = true) ++ languageValuesMapping("metaDescription") ++ diff --git a/search-api/src/main/scala/no/ndla/searchapi/service/search/MultiDraftSearchService.scala b/search-api/src/main/scala/no/ndla/searchapi/service/search/MultiDraftSearchService.scala index 5dd2890777..d1d98e1c4d 100644 --- a/search-api/src/main/scala/no/ndla/searchapi/service/search/MultiDraftSearchService.scala +++ b/search-api/src/main/scala/no/ndla/searchapi/service/search/MultiDraftSearchService.scala @@ -304,6 +304,12 @@ class MultiDraftSearchService(using boolQuery().should(settings.priority.map(p => termQuery("priority", p.entryName))) ) + val publishedCountFilter = settings + .publishedCount + .map { count => + termQuery("publishedCount", count) + } + val articleTypeFilter = Some(boolQuery().should(settings.articleTypes.map(articleType => termQuery("articleType", articleType)))) val learningResourceType = learningResourceFilter(settings.learningResourceTypes) @@ -337,6 +343,7 @@ class MultiDraftSearchService(using responsibleIdFilter, priorityFilter, learningResourceType, + publishedCountFilter, ).flatten } diff --git a/search-api/src/main/scala/no/ndla/searchapi/service/search/SearchConverterService.scala b/search-api/src/main/scala/no/ndla/searchapi/service/search/SearchConverterService.scala index 78c941f06b..b94dd90093 100644 --- a/search-api/src/main/scala/no/ndla/searchapi/service/search/SearchConverterService.scala +++ b/search-api/src/main/scala/no/ndla/searchapi/service/search/SearchConverterService.scala @@ -246,6 +246,7 @@ class SearchConverterService(using availability = ai.availability.toString, learningResourceType = learningResourceType, typeName = typeNames, + publishedCount = ai.publishedCount.getOrElse(1), domainObject = ai, nodes = nodes, ) @@ -563,6 +564,7 @@ class SearchConverterService(using favorited = favorited, learningResourceType = learningResourceType, typeName = typeNames, + publishedCount = draft.publishedCount, domainObject = draft, nodes = nodes, ) @@ -740,6 +742,8 @@ class SearchConverterService(using paths = getPathsFromContext(searchableArticle.contexts), lastUpdated = searchableArticle.lastUpdated, license = Some(searchableArticle.license), + revision = searchableArticle.domainObject.revision, + started = false, revisions = Seq.empty, responsible = None, comments = None, @@ -750,9 +754,8 @@ class SearchConverterService(using published = None, favorited = None, resultType = SearchType.Articles, - revision = searchableArticle.domainObject.revision, - started = false, grepCodes = Seq.empty, + publishedCount = Some(searchableArticle.publishedCount), ) ) } @@ -844,6 +847,8 @@ class SearchConverterService(using paths = getPathsFromContext(searchableDraft.contexts), lastUpdated = searchableDraft.lastUpdated, license = searchableDraft.license, + revision = searchableDraft.domainObject.revision, + started = searchableDraft.domainObject.started, revisions = revisions, responsible = responsible, comments = Some(comments), @@ -854,9 +859,8 @@ class SearchConverterService(using published = Some(searchableDraft.published), favorited = Some(searchableDraft.favorited), resultType = SearchType.Drafts, - revision = searchableDraft.domainObject.revision, - started = searchableDraft.domainObject.started, grepCodes = searchableDraft.domainObject.grepCodes, + publishedCount = Some(searchableDraft.publishedCount), ) ) } @@ -935,6 +939,8 @@ class SearchConverterService(using paths = getPathsFromContext(searchableLearningPath.contexts), lastUpdated = searchableLearningPath.lastUpdated, license = Some(searchableLearningPath.license), + revision = searchableLearningPath.domainObject.revision, + started = false, revisions = revisions, responsible = responsible, comments = Some(comments), @@ -945,9 +951,8 @@ class SearchConverterService(using published = None, favorited = Some(searchableLearningPath.favorited), resultType = SearchType.LearningPaths, - revision = searchableLearningPath.domainObject.revision, grepCodes = searchableLearningPath.grepCodes, - started = false, + publishedCount = None, ) ) } @@ -1000,6 +1005,8 @@ class SearchConverterService(using paths = List.empty, lastUpdated = searchableConcept.lastUpdated, license = searchableConcept.license, + revision = None, + started = false, revisions = Seq.empty, responsible = responsible, comments = None, @@ -1010,9 +1017,8 @@ class SearchConverterService(using published = None, favorited = Some(searchableConcept.favorited), resultType = SearchType.Concepts, - revision = None, grepCodes = Seq.empty, - started = false, + publishedCount = None, ) ) } diff --git a/search-api/src/test/scala/no/ndla/searchapi/TestData.scala b/search-api/src/test/scala/no/ndla/searchapi/TestData.scala index 50bd5db63a..0ed3f9afd2 100644 --- a/search-api/src/test/scala/no/ndla/searchapi/TestData.scala +++ b/search-api/src/test/scala/no/ndla/searchapi/TestData.scala @@ -205,6 +205,7 @@ object TestData { slug = None, disclaimer = OptLanguageFields.empty, traits = List.empty, + publishedCount = None, ) val sampleDomainArticle: Article = Article( @@ -232,6 +233,7 @@ object TestData { slug = None, disclaimer = OptLanguageFields.empty, traits = List.empty, + publishedCount = None, ) val sampleDomainArticle2: Article = Article( @@ -259,6 +261,7 @@ object TestData { slug = None, disclaimer = OptLanguageFields.empty, traits = List.empty, + publishedCount = None, ) val sampleArticleWithByNcSa: Article = @@ -516,7 +519,6 @@ object TestData { .copy( id = Option(14), title = List(Title("Forsideartikkel", "nb")), - slug = Some("forsideartikkel"), content = List( ArticleContent( s"Forsideartikkel

avsnitt

<$EmbedTagName data-resource=\"concept\" data-content-id=\"123\" data-title=\"Forklaring\" data-type=\"block\">", @@ -531,6 +533,7 @@ object TestData { updated = today.minusDays(5), published = today.minusDays(5), articleType = ArticleType.FrontpageArticle, + slug = Some("forsideartikkel"), ) val articlesToIndex: Seq[Article] = List( @@ -575,6 +578,7 @@ object TestData { slug = None, disclaimer = OptLanguageFields.empty, traits = List.empty, + publishedCount = None, ) val emptyDomainDraft: Draft = Draft( @@ -611,6 +615,7 @@ object TestData { qualityEvaluation = None, disclaimer = OptLanguageFields.empty, traits = List.empty, + publishedCount = 0, ) val draftStatus: Status = Status(DraftStatus.PLANNED, Set.empty) @@ -675,6 +680,7 @@ object TestData { qualityEvaluation = None, disclaimer = OptLanguageFields.empty, traits = List.empty, + publishedCount = 0, ) val sampleDraftWithByNcSa: Draft = sampleDraftWithPublicDomain.copy(copyright = Some(draftByNcSaCopyright)) @@ -685,16 +691,16 @@ object TestData { .copy( id = Option(1), title = List(Title("Batmen er på vift med en bil", "nb")), - introduction = List(Introduction("Batmen", "nb")), - metaDescription = List.empty, - visualElement = List.empty, content = List( ArticleContent("Bilde av en bil flaggermusmann som vifter med vingene bil.", "nb") ), + copyright = Some(draftByNcSaCopyright.copy(creators = List(Author(ContributorType.Writer, "Kjekspolitiet")))), tags = List(Tag(List("fugl"), "nb")), + visualElement = List.empty, + introduction = List(Introduction("Batmen", "nb")), + metaDescription = List.empty, created = today.minusDays(4), updated = today.minusDays(3), - copyright = Some(draftByNcSaCopyright.copy(creators = List(Author(ContributorType.Writer, "Kjekspolitiet")))), grepCodes = Seq("K123", "K456"), ) @@ -703,19 +709,19 @@ object TestData { .copy( id = Option(2), title = List(Title("Pingvinen er ute og går", "nb")), - introduction = List(Introduction("Pingvinen", "nb")), - metaDescription = List.empty, - visualElement = List.empty, content = List(ArticleContent("

Bilde av en

en pingvin som vagger borover en gate

", "nb")), - tags = List(Tag(List("fugl"), "nb")), - created = today.minusDays(4), - updated = today.minusDays(2), copyright = Some( draftPublicDomainCopyright.copy( creators = List(Author(ContributorType.Writer, "Pjolter")), processors = List(Author(ContributorType.Editorial, "Svims")), ) ), + tags = List(Tag(List("fugl"), "nb")), + visualElement = List.empty, + introduction = List(Introduction("Pingvinen", "nb")), + metaDescription = List.empty, + created = today.minusDays(4), + updated = today.minusDays(2), grepCodes = Seq("K456", "K123"), ) @@ -724,11 +730,11 @@ object TestData { .copy( id = Option(3), title = List(Title("Donald Duck kjører bil", "nb")), - introduction = List(Introduction("Donald Duck", "nb")), - metaDescription = List.empty, - visualElement = List.empty, content = List(ArticleContent("

Bilde av en en and

som kjører en rød bil.

", "nb")), tags = List(Tag(List("and"), "nb")), + visualElement = List.empty, + introduction = List(Introduction("Donald Duck", "nb")), + metaDescription = List.empty, created = today.minusDays(4), updated = today.minusDays(1), grepCodes = Seq("K123"), @@ -739,12 +745,12 @@ object TestData { .copy( id = Option(4), title = List(Title("Superman er ute og flyr", "nb")), - introduction = List(Introduction("Superman", "nb")), - metaDescription = List.empty, - visualElement = List.empty, content = List(ArticleContent("

Bilde av en flygende mann

som har superkrefter.

", "nb")), tags = List(Tag(List("supermann"), "nb")), + visualElement = List.empty, + introduction = List(Introduction("Superman", "nb")), + metaDescription = List.empty, created = today.minusDays(4), updated = today, ) @@ -754,11 +760,11 @@ object TestData { .copy( id = Option(5), title = List(Title("Hulken løfter biler", "nb")), - introduction = List(Introduction("Hulken", "nb")), - metaDescription = List.empty, - visualElement = List.empty, content = List(ArticleContent("

Bilde av hulk

som løfter en rød bil.

", "nb")), tags = List(Tag(List("hulk"), "nb")), + visualElement = List.empty, + introduction = List(Introduction("Hulken", "nb")), + metaDescription = List.empty, created = today.minusDays(40), updated = today.minusDays(35), notes = @@ -774,9 +780,6 @@ object TestData { .copy( id = Option(6), title = List(Title("Loke og Tor prøver å fange midgaardsormen", "nb")), - introduction = List(Introduction("Loke og Tor", "nb")), - metaDescription = List.empty, - visualElement = List.empty, content = List( ArticleContent( "

Bilde av Loke og Tor

som fisker fra Naglfar.

", @@ -784,6 +787,9 @@ object TestData { ) ), tags = List(Tag(List("Loke", "Tor", "Naglfar"), "nb")), + visualElement = List.empty, + introduction = List(Introduction("Loke og Tor", "nb")), + metaDescription = List.empty, created = today.minusDays(30), updated = today.minusDays(25), ) @@ -793,11 +799,11 @@ object TestData { .copy( id = Option(7), title = List(Title("Yggdrasil livets tre", "nb")), - introduction = List(Introduction("Yggdrasil", "nb")), - metaDescription = List.empty, - visualElement = List.empty, content = List(ArticleContent("

Bilde av Yggdrasil livets tre med alle dyrene som bor i det.", "nb")), tags = List(Tag(List("yggdrasil"), "nb")), + visualElement = List.empty, + introduction = List(Introduction("Yggdrasil", "nb")), + metaDescription = List.empty, created = today.minusDays(20), updated = today.minusDays(15), ) @@ -807,11 +813,11 @@ object TestData { .copy( id = Option(8), title = List(Title("Baldur har mareritt", "nb")), - introduction = List(Introduction("Baldur", "nb")), - metaDescription = List.empty, - visualElement = List.empty, content = List(ArticleContent("

Bilde av Baldurs mareritt om Ragnarok.", "nb")), tags = List(Tag(List("baldur"), "nb")), + visualElement = List.empty, + introduction = List(Introduction("Baldur", "nb")), + metaDescription = List.empty, created = today.minusDays(10), updated = today.minusDays(5), articleType = ArticleType.TopicArticle, @@ -822,11 +828,11 @@ object TestData { .copy( id = Option(9), title = List(Title("Baldur har mareritt om Ragnarok", "nb")), - introduction = List(Introduction("Baldur", "nb")), - metaDescription = List.empty, - visualElement = List.empty, content = List(ArticleContent("

Bilde av Baldurs som har mareritt.", "nb")), tags = List(Tag(List("baldur"), "nb")), + visualElement = List.empty, + introduction = List(Introduction("Baldur", "nb")), + metaDescription = List.empty, created = today.minusDays(10), updated = today.minusDays(5), articleType = ArticleType.TopicArticle, @@ -838,11 +844,11 @@ object TestData { id = Option(10), status = Status(DraftStatus.IN_PROGRESS, Set.empty), title = List(Title("This article is in english", "en")), - introduction = List(Introduction("Engulsk", "en")), - metaDescription = List.empty, - visualElement = List.empty, content = List(ArticleContent("

Something something english What", "en")), tags = List(Tag(List("englando"), "en")), + visualElement = List.empty, + introduction = List(Introduction("Engulsk", "en")), + metaDescription = List.empty, metaImage = List(ArticleMetaImage("123", "alt", "en")), created = today.minusDays(10), updated = today.minusDays(5), @@ -855,12 +861,12 @@ object TestData { id = Option(11), status = Status(DraftStatus.IN_PROGRESS, Set.empty), title = List(Title("Katter", "nb"), Title("Cats", "en")), - introduction = List(Introduction("Katter er store", "nb"), Introduction("Cats are big", "en")), content = List(ArticleContent("

Noe om en katt

", "nb"), ArticleContent("

Something about a cat

", "en")), tags = List(Tag(List("katt"), "nb"), Tag(List("cat"), "en")), - metaDescription = List(common.Description("hurr dirr ima sheep", "en")), visualElement = List.empty, + introduction = List(Introduction("Katter er store", "nb"), Introduction("Cats are big", "en")), + metaDescription = List(common.Description("hurr dirr ima sheep", "en")), created = today.minusDays(10), updated = today.minusDays(5), articleType = ArticleType.TopicArticle, @@ -872,8 +878,6 @@ object TestData { id = Option(12), status = importedDraftStatus, title = List(Title("Ekstrastoff", "nb")), - introduction = List(Introduction("Ekstra", "nb")), - metaDescription = List(common.Description("", "nb")), content = List( ArticleContent( s"""

artikkeltekst med fire deler

<$EmbedTagName data-resource=\"concept\" data-resource_id=\"222\"> @@ -890,8 +894,10 @@ object TestData { "nb", ) ), - visualElement = List(VisualElement(s"<$EmbedTagName data-resource_id=\"333\">", "nb")), tags = List(Tag(List(""), "nb")), + visualElement = List(VisualElement(s"<$EmbedTagName data-resource_id=\"333\">", "nb")), + introduction = List(Introduction("Ekstra", "nb")), + metaDescription = List(common.Description("", "nb")), created = today.minusDays(10), updated = today.minusDays(5), ) @@ -901,8 +907,6 @@ object TestData { .copy( id = Option(13), title = List(Title("Luringen", "nb"), Title("English title", "en"), Title("Chhattisgarhi title", "hne")), - introduction = List(Introduction("Luringen", "nb")), - metaDescription = List(common.Description("", "nb")), content = List( ArticleContent( s"

Helsesøster

Søkeord: delt?streng delt!streng delt&streng

<$EmbedTagName data-resource=\"content-link\" data-content-type=\"article\" data-content-id=\"666\">
", @@ -917,8 +921,10 @@ object TestData { "hne", ), ), - visualElement = List.empty, tags = List(Tag(List(""), "nb")), + visualElement = List.empty, + introduction = List(Introduction("Luringen", "nb")), + metaDescription = List(common.Description("", "nb")), created = today.minusDays(10), updated = today.minusDays(5), updatedBy = "someotheruser", @@ -929,15 +935,15 @@ object TestData { .sampleDraftWithPublicDomain .copy( id = Option(14), + status = Status(current = DraftStatus.ARCHIVED, other = Set.empty), title = List(Title("Slettet", "nb")), - introduction = List(Introduction("Slettet", "nb")), - metaDescription = List(common.Description("", "nb")), content = List(ArticleContent("", "nb")), - visualElement = List.empty, tags = List(Tag(List(""), "nb")), + visualElement = List.empty, + introduction = List(Introduction("Slettet", "nb")), + metaDescription = List(common.Description("", "nb")), created = today.minusDays(10), updated = today.minusDays(5), - status = Status(current = DraftStatus.ARCHIVED, other = Set.empty), ) val draft15: Draft = TestData @@ -945,14 +951,14 @@ object TestData { .copy( id = Option(15), title = List(Title("Engler og demoner", "nb")), - introduction = List(Introduction("Religion", "nb")), - metaDescription = List(common.Description("metareligion", "nb")), content = List( ArticleContent("

Vanlig i gamle testamentet

delt-streng

", "nb"), ArticleContent("

Christianity!

", "en"), ), - visualElement = List.empty, tags = List(Tag(List("engel"), "nb")), + visualElement = List.empty, + introduction = List(Introduction("Religion", "nb")), + metaDescription = List(common.Description("metareligion", "nb")), created = today.minusDays(10), updated = today.minusDays(5), articleType = ArticleType.TopicArticle, @@ -963,15 +969,15 @@ object TestData { .copy( id = Option(16), title = List(Title("Engler og demoner", "nb")), - slug = Some("engler-og-demoner"), - introduction = List(Introduction("Religion", "nb")), - metaDescription = List(common.Description("metareligion", "nb")), content = List(ArticleContent("

Vanlig i gamle testamentet

", "nb")), - visualElement = List.empty, tags = List(Tag(List("engel"), "nb")), + visualElement = List.empty, + introduction = List(Introduction("Religion", "nb")), + metaDescription = List(common.Description("metareligion", "nb")), created = today.minusDays(10), updated = today.minusDays(5), articleType = ArticleType.FrontpageArticle, + slug = Some("engler-og-demoner"), ) val draft17: Draft = TestData @@ -980,15 +986,15 @@ object TestData { id = Option(17), status = Status(DraftStatus.UNPUBLISHED, Set.empty), title = List(Title("Engler og demoner", "nb")), - slug = Some("engler-og-demoner"), - introduction = List(Introduction("Religion", "nb")), - metaDescription = List(common.Description("metareligion", "nb")), content = List(ArticleContent("

Vanlig i gamle testamentet

", "nb")), - visualElement = List.empty, tags = List(Tag(List("engel"), "nb")), + visualElement = List.empty, + introduction = List(Introduction("Religion", "nb")), + metaDescription = List(common.Description("metareligion", "nb")), created = today.minusDays(10), updated = today.minusDays(5), articleType = ArticleType.TopicArticle, + slug = Some("engler-og-demoner"), ) val draftsToIndex: List[Draft] = List( @@ -1834,6 +1840,7 @@ object TestData { publishedFilterTo = None, resultTypes = None, tags = List.empty, + publishedCount = None, ) val searchableResourceTypes: List[ContextResourceType] = List( @@ -1965,6 +1972,7 @@ object TestData { favorited = 0, learningResourceType = LearningResourceType.Article, typeName = List(), + publishedCount = 0, domainObject = TestData .draft1 .copy( @@ -1977,6 +1985,7 @@ object TestData { status = Status(current = DraftStatus.IN_PROGRESS, other = Set(DraftStatus.PUBLISHED)), ) ), + publishedCount = 0, ), nodes = List.empty, ) diff --git a/search-api/src/test/scala/no/ndla/searchapi/controller/SearchControllerTest.scala b/search-api/src/test/scala/no/ndla/searchapi/controller/SearchControllerTest.scala index 64c7ae90ad..1bd6253b3b 100644 --- a/search-api/src/test/scala/no/ndla/searchapi/controller/SearchControllerTest.scala +++ b/search-api/src/test/scala/no/ndla/searchapi/controller/SearchControllerTest.scala @@ -172,7 +172,7 @@ class SearchControllerTest extends UnitSuite with TestEnvironment with TapirCont val expectedSettings = TestData .multiDraftSearchSettings - .copy(fallback = true, language = "nn", pageSize = 10, shouldScroll = true, sort = Sort.ByRelevanceDesc) + .copy(fallback = true, language = "nn", pageSize = 10, sort = Sort.ByRelevanceDesc, shouldScroll = true) verify(multiDraftSearchService, times(0)).scroll(any[String], any[String]) verify(multiDraftSearchService, times(1)).matchingQuery(eqTo(expectedSettings)) diff --git a/search-api/src/test/scala/no/ndla/searchapi/model/search/SearchableArticleTest.scala b/search-api/src/test/scala/no/ndla/searchapi/model/search/SearchableArticleTest.scala index 3f6350dc20..119e77f518 100644 --- a/search-api/src/test/scala/no/ndla/searchapi/model/search/SearchableArticleTest.scala +++ b/search-api/src/test/scala/no/ndla/searchapi/model/search/SearchableArticleTest.scala @@ -80,6 +80,7 @@ class SearchableArticleTest extends UnitSuite with TestEnvironment { availability = "everyone", learningResourceType = LearningResourceType.Article, typeName = List.empty, + publishedCount = 42, domainObject = TestData.article1, nodes = nodes, ) @@ -147,6 +148,7 @@ class SearchableArticleTest extends UnitSuite with TestEnvironment { availability = "everyone", learningResourceType = LearningResourceType.Article, typeName = List.empty, + publishedCount = 42, domainObject = TestData.article1, nodes = nodes, ) diff --git a/search-api/src/test/scala/no/ndla/searchapi/model/search/SearchableDraftTest.scala b/search-api/src/test/scala/no/ndla/searchapi/model/search/SearchableDraftTest.scala index c0631664a9..6e3ea637d3 100644 --- a/search-api/src/test/scala/no/ndla/searchapi/model/search/SearchableDraftTest.scala +++ b/search-api/src/test/scala/no/ndla/searchapi/model/search/SearchableDraftTest.scala @@ -120,6 +120,7 @@ class SearchableDraftTest extends UnitSuite with TestEnvironment { favorited = 0, learningResourceType = LearningResourceType.Article, typeName = List.empty, + publishedCount = 0, domainObject = TestData .draft1 .copy( @@ -132,6 +133,7 @@ class SearchableDraftTest extends UnitSuite with TestEnvironment { status = CommonStatus(current = DraftStatus.IN_PROGRESS, other = Set(DraftStatus.PUBLISHED)), ) ), + publishedCount = 1, ), nodes = nodes, ) diff --git a/search-api/src/test/scala/no/ndla/searchapi/service/search/ArticleIndexServiceTest.scala b/search-api/src/test/scala/no/ndla/searchapi/service/search/ArticleIndexServiceTest.scala index 513638ac49..99034f3816 100644 --- a/search-api/src/test/scala/no/ndla/searchapi/service/search/ArticleIndexServiceTest.scala +++ b/search-api/src/test/scala/no/ndla/searchapi/service/search/ArticleIndexServiceTest.scala @@ -123,9 +123,6 @@ class ArticleIndexServiceTest extends ElasticsearchIntegrationSuite with UnitSui "en", ), ), - metaImage = List(ArticleMetaImage("hei", "hå", "nb"), ArticleMetaImage("hei", "hå", "en")), - metaDescription = Seq(Description("hei", "nb"), Description("hei", "en")), - visualElement = Seq(VisualElement("hei", "nb"), VisualElement("hei", "en")), copyright = Copyright( license = "CC-BY-SA-4.0", origin = None, @@ -136,7 +133,11 @@ class ArticleIndexServiceTest extends ElasticsearchIntegrationSuite with UnitSui validTo = None, processed = false, ), + visualElement = Seq(VisualElement("hei", "nb"), VisualElement("hei", "en")), + metaDescription = Seq(Description("hei", "nb"), Description("hei", "en")), + metaImage = List(ArticleMetaImage("hei", "hå", "nb"), ArticleMetaImage("hei", "hå", "en")), traits = List(Interactive), + publishedCount = Some(1), ) val searchableToTestWith = searchConverterService diff --git a/search-api/src/test/scala/no/ndla/searchapi/service/search/DraftIndexServiceTest.scala b/search-api/src/test/scala/no/ndla/searchapi/service/search/DraftIndexServiceTest.scala index e835d935a0..1b43c370da 100644 --- a/search-api/src/test/scala/no/ndla/searchapi/service/search/DraftIndexServiceTest.scala +++ b/search-api/src/test/scala/no/ndla/searchapi/service/search/DraftIndexServiceTest.scala @@ -54,18 +54,13 @@ class DraftIndexServiceTest extends ElasticsearchIntegrationSuite with UnitSuite val domainDraft = TestData .draft1 .copy( + status = Status(DraftStatus.PLANNED, Set(DraftStatus.IMPORTED)), content = Seq( ArticleContent( """

hei

""", "nb", ) ), - status = Status(DraftStatus.PLANNED, Set(DraftStatus.IMPORTED)), - notes = Seq(EditorNote("hei", "test", Status(DraftStatus.PLANNED, Set(DraftStatus.IMPORTED)), now)), - previousVersionsNotes = - Seq(EditorNote("hei", "test", Status(DraftStatus.PLANNED, Set(DraftStatus.IMPORTED)), now)), - revisionMeta = Seq(RevisionMeta(UUID.randomUUID(), now, "hei", RevisionStatus.NeedsRevision)), - traits = List(ArticleTrait.Interactive), copyright = Some( DraftCopyright( license = Some("hei"), @@ -78,7 +73,12 @@ class DraftIndexServiceTest extends ElasticsearchIntegrationSuite with UnitSuite false, ) ), + notes = Seq(EditorNote("hei", "test", Status(DraftStatus.PLANNED, Set(DraftStatus.IMPORTED)), now)), + previousVersionsNotes = + Seq(EditorNote("hei", "test", Status(DraftStatus.PLANNED, Set(DraftStatus.IMPORTED)), now)), + revisionMeta = Seq(RevisionMeta(UUID.randomUUID(), now, "hei", RevisionStatus.NeedsRevision)), responsible = Some(Responsible("yolo", now)), + traits = List(ArticleTrait.Interactive), ) val searchableToTestWith = searchConverterService .asSearchableDraft( diff --git a/search-api/src/test/scala/no/ndla/searchapi/service/search/MultiDraftSearchServiceAtomicTest.scala b/search-api/src/test/scala/no/ndla/searchapi/service/search/MultiDraftSearchServiceAtomicTest.scala index 74e93dbe30..da6be4f2ec 100644 --- a/search-api/src/test/scala/no/ndla/searchapi/service/search/MultiDraftSearchServiceAtomicTest.scala +++ b/search-api/src/test/scala/no/ndla/searchapi/service/search/MultiDraftSearchServiceAtomicTest.scala @@ -109,14 +109,14 @@ class MultiDraftSearchServiceAtomicTest extends ElasticsearchIntegrationSuite wi blockUntil(() => draftIndexService.countDocuments == 3) val Success(search1) = multiDraftSearchService.matchingQuery( - multiDraftSearchSettings.copy(embedId = Some("3"), embedResource = List("content-link")) + multiDraftSearchSettings.copy(embedResource = List("content-link"), embedId = Some("3")) ): @unchecked search1.totalCount should be(1) search1.summaryResults.map(_.id) should be(List(2)) val Success(search2) = multiDraftSearchService.matchingQuery( - multiDraftSearchSettings.copy(embedId = Some("3"), embedResource = List("content-link", "related-content")) + multiDraftSearchSettings.copy(embedResource = List("content-link", "related-content"), embedId = Some("3")) ): @unchecked search2.totalCount should be(2) @@ -454,7 +454,7 @@ class MultiDraftSearchServiceAtomicTest extends ElasticsearchIntegrationSuite wi multiDraftSearchService .matchingQuery( - multiDraftSearchSettings.copy(responsibleIdFilter = List.empty, sort = Sort.ByResponsibleLastUpdatedAsc) + multiDraftSearchSettings.copy(sort = Sort.ByResponsibleLastUpdatedAsc, responsibleIdFilter = List.empty) ) .get .summaryResults @@ -462,7 +462,7 @@ class MultiDraftSearchServiceAtomicTest extends ElasticsearchIntegrationSuite wi multiDraftSearchService .matchingQuery( - multiDraftSearchSettings.copy(responsibleIdFilter = List.empty, sort = Sort.ByResponsibleLastUpdatedDesc) + multiDraftSearchSettings.copy(sort = Sort.ByResponsibleLastUpdatedDesc, responsibleIdFilter = List.empty) ) .get .summaryResults @@ -714,13 +714,13 @@ class MultiDraftSearchServiceAtomicTest extends ElasticsearchIntegrationSuite wi blockUntil(() => draftIndexService.countDocuments == 4) multiDraftSearchService - .matchingQuery(multiDraftSearchSettings.copy(responsibleIdFilter = List.empty, sort = Sort.ByStatusAsc)) + .matchingQuery(multiDraftSearchSettings.copy(sort = Sort.ByStatusAsc, responsibleIdFilter = List.empty)) .get .summaryResults .map(_.id) should be(Seq(4, 3, 1, 2)) multiDraftSearchService - .matchingQuery(multiDraftSearchSettings.copy(responsibleIdFilter = List.empty, sort = Sort.ByStatusDesc)) + .matchingQuery(multiDraftSearchSettings.copy(sort = Sort.ByStatusDesc, responsibleIdFilter = List.empty)) .get .summaryResults .map(_.id) should be(Seq(2, 1, 3, 4)) @@ -789,6 +789,7 @@ class MultiDraftSearchServiceAtomicTest extends ElasticsearchIntegrationSuite wi ) ), ) + draftIndexService.indexDocument(draft1, indexingBundle).get blockUntil(() => draftIndexService.countDocuments == 1) @@ -1018,8 +1019,8 @@ class MultiDraftSearchServiceAtomicTest extends ElasticsearchIntegrationSuite wi multiDraftSearchService .matchingQuery( multiDraftSearchSettings.copy( - sort = Sort.ByIdAsc, query = NonEmptyString.fromString("giraff"), + sort = Sort.ByIdAsc, resultTypes = Some(List(SearchType.Drafts, SearchType.Concepts, SearchType.LearningPaths)), ) ) @@ -1030,8 +1031,8 @@ class MultiDraftSearchServiceAtomicTest extends ElasticsearchIntegrationSuite wi multiDraftSearchService .matchingQuery( multiDraftSearchSettings.copy( - sort = Sort.ByIdAsc, query = NonEmptyString.fromString("apekatt"), + sort = Sort.ByIdAsc, resultTypes = Some(List(SearchType.Drafts, SearchType.Concepts, SearchType.LearningPaths)), ) ) @@ -1133,8 +1134,8 @@ class MultiDraftSearchServiceAtomicTest extends ElasticsearchIntegrationSuite wi val search = multiDraftSearchService .matchingQuery( multiDraftSearchSettings.copy( - resultTypes = Some(List(SearchType.Drafts, SearchType.Concepts, SearchType.LearningPaths)), responsibleIdFilter = List("some-user"), + resultTypes = Some(List(SearchType.Drafts, SearchType.Concepts, SearchType.LearningPaths)), ) ) .get diff --git a/search-api/src/test/scala/no/ndla/searchapi/service/search/MultiDraftSearchServiceTest.scala b/search-api/src/test/scala/no/ndla/searchapi/service/search/MultiDraftSearchServiceTest.scala index 9343222278..e22810ce9a 100644 --- a/search-api/src/test/scala/no/ndla/searchapi/service/search/MultiDraftSearchServiceTest.scala +++ b/search-api/src/test/scala/no/ndla/searchapi/service/search/MultiDraftSearchServiceTest.scala @@ -562,7 +562,7 @@ class MultiDraftSearchServiceTest extends ElasticsearchIntegrationSuite with Tes search.summaryResults.map(_.id) should be(Seq(2, 3, 4, 5, 6, 10, 11, 13, 15)) val Success(search2) = multiDraftSearchService.matchingQuery( - multiDraftSearchSettings.copy(language = "*", supportedLanguages = List("en", "nb"), pageSize = 100) + multiDraftSearchSettings.copy(language = "*", pageSize = 100, supportedLanguages = List("en", "nb")) ): @unchecked search2.totalCount should be(21) search2.summaryResults.map(_.id) should be(Seq(1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 8, 9, 10, 11, 12, 13, 15, 16)) @@ -791,10 +791,7 @@ class MultiDraftSearchServiceTest extends ElasticsearchIntegrationSuite with Tes multiDraftSearchSettings.copy(statusFilter = List(DraftStatus.UNPUBLISHED)) ): @unchecked val Success(search3) = multiDraftSearchService.matchingQuery( - multiDraftSearchSettings.copy( - withIdIn = List(14, 17), // 14 is archived, 17 is unpublished - statusFilter = List.empty, - ) + multiDraftSearchSettings.copy(withIdIn = List(14, 17), statusFilter = List.empty) ): @unchecked search1.summaryResults.map(_.id) should be(Seq(14)) @@ -1176,10 +1173,10 @@ class MultiDraftSearchServiceTest extends ElasticsearchIntegrationSuite with Tes test("That filtering on tags works") { val Success(search) = multiDraftSearchService.matchingQuery( - multiDraftSearchSettings.copy(tags = List("fugl"), language = "nb") + multiDraftSearchSettings.copy(language = "nb", tags = List("fugl")) ): @unchecked val Success(search2) = multiDraftSearchService.matchingQuery( - multiDraftSearchSettings.copy(tags = List("hulk"), language = "nb") + multiDraftSearchSettings.copy(language = "nb", tags = List("hulk")) ): @unchecked search.totalCount should be(2)