diff --git a/learningpath-api/src/main/scala/no/ndla/learningpathapi/controller/LearningpathControllerV2.scala b/learningpath-api/src/main/scala/no/ndla/learningpathapi/controller/LearningpathControllerV2.scala index 1ed9eb9af8..739a61feb1 100644 --- a/learningpath-api/src/main/scala/no/ndla/learningpathapi/controller/LearningpathControllerV2.scala +++ b/learningpath-api/src/main/scala/no/ndla/learningpathapi/controller/LearningpathControllerV2.scala @@ -17,6 +17,7 @@ import no.ndla.language.Language import no.ndla.language.Language.AllLanguages import no.ndla.learningpathapi.Props import no.ndla.learningpathapi.model.api.* +import no.ndla.learningpathapi.model.domain.Sort.ByCreatedDesc import no.ndla.learningpathapi.model.domain.{License as _, *} import no.ndla.learningpathapi.service.search.{SearchConverterServiceComponent, SearchService} import no.ndla.learningpathapi.service.{ConverterService, ReadService, UpdateService} @@ -392,11 +393,16 @@ class LearningpathControllerV2(using .summary("Fetch all learningspaths you have created") .description("Shows your learningpaths.") .in("mine") + .in(sort) .out(jsonBody[List[LearningPathV2DTO]]) .errorOut(errorOutputsFor(401, 403, 404)) .withRequiredMyNDLAUserOrTokenUser - .serverLogicPure { user => _ => - readService.withOwnerV2(user, props.DefaultLanguage, true).asRight + .serverLogicPure { user => + { sortStr => + readService + .withOwnerV2(user, Sort.valueOf(sortStr).getOrElse(ByCreatedDesc), props.DefaultLanguage, true) + .asRight + } } def getLicenses: ServerEndpoint[Any, Eff] = endpoint diff --git a/learningpath-api/src/main/scala/no/ndla/learningpathapi/model/domain/Sort.scala b/learningpath-api/src/main/scala/no/ndla/learningpathapi/model/domain/Sort.scala index d448859ac1..a1ceb17657 100644 --- a/learningpath-api/src/main/scala/no/ndla/learningpathapi/model/domain/Sort.scala +++ b/learningpath-api/src/main/scala/no/ndla/learningpathapi/model/domain/Sort.scala @@ -27,10 +27,10 @@ object Sort extends Enum[Sort] with CirceEnum[Sort] { case object ByRelevanceAsc extends Sort("relevance") case object ByLastUpdatedDesc extends Sort("-lastUpdated") case object ByLastUpdatedAsc extends Sort("lastUpdated") - case object ByDurationDesc extends Sort("-duration") - case object ByDurationAsc extends Sort("duration") case object ByTitleDesc extends Sort("-title") case object ByTitleAsc extends Sort("title") + case object ByCreatedDesc extends Sort("-created") + case object ByCreatedAsc extends Sort("created") def valueOf(s: String): Option[Sort] = Sort.values.find(_.entryName == s) diff --git a/learningpath-api/src/main/scala/no/ndla/learningpathapi/repository/LearningPathRepository.scala b/learningpath-api/src/main/scala/no/ndla/learningpathapi/repository/LearningPathRepository.scala index 4abf40f557..aa3d7e8351 100644 --- a/learningpath-api/src/main/scala/no/ndla/learningpathapi/repository/LearningPathRepository.scala +++ b/learningpath-api/src/main/scala/no/ndla/learningpathapi/repository/LearningPathRepository.scala @@ -48,9 +48,21 @@ class LearningPathRepository extends StrictLogging { learningPathWhere(sqls"lp.external_id = $externalId") } - def withOwner(owner: String): List[LearningPath] = { + def withOwner(owner: String, sort: Sort): List[LearningPath] = { + val sortingOrder = sort match { + case Sort.ByCreatedDesc => sqls"order by lp.document->>'created' DESC" + case Sort.ByCreatedAsc => sqls"order by lp.document->>'created' ASC" + case Sort.ByLastUpdatedDesc => sqls"order by lp.document->>'lastUpdated' DESC" + case Sort.ByLastUpdatedAsc => sqls"order by lp.document->>'lastUpdated' ASC" + case Sort.ByIdDesc => sqls"order by lp.id DESC" + case Sort.ByIdAsc => sqls"order by lp.id ASC" + case Sort.ByRelevanceDesc => sqls"order by lp.id DESC" + case Sort.ByRelevanceAsc => sqls"order by lp.id ASC" + case Sort.ByTitleDesc => sqls"order by lp.document->'title'->0->>'title' DESC" + case Sort.ByTitleAsc => sqls"order by lp.document->'title'->0->>'title' ASC" + } learningPathsWhere( - sqls"lp.document->>'owner' = $owner AND lp.document->>'status' <> ${LearningPathStatus.DELETED.toString} order by lp.document->>'created' DESC" + sqls"lp.document->>'owner' = $owner AND lp.document->>'status' <> ${LearningPathStatus.DELETED.toString} $sortingOrder" ) } diff --git a/learningpath-api/src/main/scala/no/ndla/learningpathapi/service/ReadService.scala b/learningpath-api/src/main/scala/no/ndla/learningpathapi/service/ReadService.scala index 98b4821c53..fcafe435e9 100644 --- a/learningpath-api/src/main/scala/no/ndla/learningpathapi/service/ReadService.scala +++ b/learningpath-api/src/main/scala/no/ndla/learningpathapi/service/ReadService.scala @@ -37,9 +37,14 @@ class ReadService(using learningPathRepository.allPublishedContributors.map(author => commonApi.AuthorDTO(author.`type`, author.name)) } - def withOwnerV2(user: CombinedUserRequired, language: String, fallback: Boolean): List[LearningPathV2DTO] = { + def withOwnerV2( + user: CombinedUserRequired, + sort: Sort, + language: FeideID, + fallback: Boolean, + ): List[LearningPathV2DTO] = { learningPathRepository - .withOwner(user.id) + .withOwner(user.id, sort) .flatMap(value => converterService.asApiLearningpathV2(value, language, fallback, user).toOption) } diff --git a/learningpath-api/src/main/scala/no/ndla/learningpathapi/service/search/SearchService.scala b/learningpath-api/src/main/scala/no/ndla/learningpathapi/service/search/SearchService.scala index 5900218a07..8495b0ca67 100644 --- a/learningpath-api/src/main/scala/no/ndla/learningpathapi/service/search/SearchService.scala +++ b/learningpath-api/src/main/scala/no/ndla/learningpathapi/service/search/SearchService.scala @@ -264,8 +264,8 @@ class SearchService(using case AllLanguages => fieldSort("defaultTitle").order(SortOrder.Desc).missing("_last") case _ => fieldSort(s"titles.$sortLanguage.raw").order(SortOrder.Desc).missing("_last").unmappedType("long") } - case Sort.ByDurationAsc => fieldSort("duration").order(SortOrder.Asc).missing("_last") - case Sort.ByDurationDesc => fieldSort("duration").order(SortOrder.Desc).missing("_last") + case Sort.ByCreatedAsc => fieldSort("created").order(SortOrder.Asc).missing("_last") + case Sort.ByCreatedDesc => fieldSort("created").order(SortOrder.Desc).missing("_last") case Sort.ByLastUpdatedAsc => fieldSort("lastUpdated").order(SortOrder.Asc).missing("_last") case Sort.ByLastUpdatedDesc => fieldSort("lastUpdated").order(SortOrder.Desc).missing("_last") case Sort.ByRelevanceAsc => fieldSort("_score").order(SortOrder.Asc) diff --git a/learningpath-api/src/test/scala/no/ndla/learningpathapi/controller/LearningpathControllerV2Test.scala b/learningpath-api/src/test/scala/no/ndla/learningpathapi/controller/LearningpathControllerV2Test.scala index 8bd440772d..5b9286a63a 100644 --- a/learningpath-api/src/test/scala/no/ndla/learningpathapi/controller/LearningpathControllerV2Test.scala +++ b/learningpath-api/src/test/scala/no/ndla/learningpathapi/controller/LearningpathControllerV2Test.scala @@ -82,7 +82,7 @@ class LearningpathControllerV2Test extends UnitSuite with TestEnvironment with T withIdIn = List(1, 2), taggedWith = Some(tag), language = Some(language), - sort = Sort.ByDurationDesc, + sort = Sort.ByCreatedDesc, page = Some(page), pageSize = Some(pageSize), verificationStatus = Some(verificationStatus), @@ -94,7 +94,7 @@ class LearningpathControllerV2Test extends UnitSuite with TestEnvironment with T "query" -> query, "tag" -> tag, "language" -> language, - "sort" -> "-duration", + "sort" -> "-created", "page-size" -> s"$pageSize", "page" -> s"$page", "ids" -> s"$ids", @@ -148,14 +148,14 @@ class LearningpathControllerV2Test extends UnitSuite with TestEnvironment with T query = Some(query), taggedWith = Some(tag), language = Some(language), - sort = Sort.ByDurationDesc, + sort = Sort.ByCreatedDesc, page = Some(page), pageSize = Some(pageSize), ) when(searchService.matchingQuery(eqTo(expectedSettings))).thenReturn(Success(result)) val inputBody = - s"""{"query": "$query", "tag": "$tag", "language": "$language", "page": $page, "pageSize": $pageSize, "ids": [1, 2], "sort": "-duration" }""" + s"""{"query": "$query", "tag": "$tag", "language": "$language", "page": $page, "pageSize": $pageSize, "ids": [1, 2], "sort": "-created" }""" val res = simpleHttpClient.send( quickRequest.post(uri"http://localhost:$serverPort/learningpath-api/v2/learningpaths/search/").body(inputBody) ) diff --git a/learningpath-api/src/test/scala/no/ndla/learningpathapi/repository/LearningPathRepositoryIntegrationTest.scala b/learningpath-api/src/test/scala/no/ndla/learningpathapi/repository/LearningPathRepositoryIntegrationTest.scala index dae0c33b51..e22d2ba1b2 100644 --- a/learningpath-api/src/test/scala/no/ndla/learningpathapi/repository/LearningPathRepositoryIntegrationTest.scala +++ b/learningpath-api/src/test/scala/no/ndla/learningpathapi/repository/LearningPathRepositoryIntegrationTest.scala @@ -149,7 +149,7 @@ class LearningPathRepositoryIntegrationTest extends DatabaseIntegrationSuite wit } fail("Exception should prevent normal execution") } catch { - case _: Throwable => repository.withOwner(owner).length should be(0) + case _: Throwable => repository.withOwner(owner, Sort.ByCreatedDesc).length should be(0) } } @@ -423,7 +423,7 @@ class LearningPathRepositoryIntegrationTest extends DatabaseIntegrationSuite wit def deleteAllWithOwner(owner: String): Unit = { repository.inTransaction { implicit session => - repository.withOwner(owner).foreach(lp => repository.deletePath(lp.id.get)) + repository.withOwner(owner, Sort.ByCreatedDesc).foreach(lp => repository.deletePath(lp.id.get)) } } } diff --git a/learningpath-api/src/test/scala/no/ndla/learningpathapi/service/search/SearchServiceTest.scala b/learningpath-api/src/test/scala/no/ndla/learningpathapi/service/search/SearchServiceTest.scala index 7acec0f776..658439d387 100644 --- a/learningpath-api/src/test/scala/no/ndla/learningpathapi/service/search/SearchServiceTest.scala +++ b/learningpath-api/src/test/scala/no/ndla/learningpathapi/service/search/SearchServiceTest.scala @@ -313,16 +313,17 @@ class SearchServiceTest extends ElasticsearchIntegrationSuite with UnitSuite wit hits(4).id should be(EnglandoId) } - test("That order by durationDesc orders search result by duration descending") { - val Success(searchResult) = searchService.matchingQuery(searchSettings.copy(sort = Sort.ByDurationDesc)): @unchecked - val hits = searchResult.results + test("That order by lastUpdatedDesc orders search result by lastUpdated descending") { + val Success(searchResult) = + searchService.matchingQuery(searchSettings.copy(sort = Sort.ByLastUpdatedDesc)): @unchecked + val hits = searchResult.results searchResult.totalCount should be(4) hits.head.id should be(UnrelatedId) } test("That order ByDurationAsc orders search result by duration ascending") { - val Success(searchResult) = searchService.matchingQuery(searchSettings.copy(sort = Sort.ByDurationAsc)): @unchecked + val Success(searchResult) = searchService.matchingQuery(searchSettings.copy(sort = Sort.ByCreatedDesc)): @unchecked val hits = searchResult.results searchResult.totalCount should be(4)