Skip to content

Commit

Permalink
API-7700: add ActorType responsible for last action (#517)
Browse files Browse the repository at this point in the history
* API-7700: add ActorType responsible for last action to Applications response

* API-7700: pr-bot comment

* API-7700: shuffling code to make it more compliant with what's already there
  • Loading branch information
worthydolt authored Aug 27, 2024
1 parent 027059d commit 939fcbf
Show file tree
Hide file tree
Showing 7 changed files with 104 additions and 24 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import java.time.Instant
import javax.inject.{Inject, Singleton}
import scala.concurrent.{ExecutionContext, Future}

import org.mongodb.scala.model.Filters.{and, equal}
import org.mongodb.scala.model.Filters.{and, equal, in}
import org.mongodb.scala.model.Indexes.{ascending, descending}
import org.mongodb.scala.model.{IndexModel, IndexOptions}

Expand Down Expand Up @@ -94,6 +94,15 @@ class StateHistoryRepository @Inject() (mongo: MongoComponent)(implicit val ec:
.map(x => x.toList)
}

def fetchDeletedByApplicationIds(applicationIds: List[ApplicationId]): Future[List[StateHistory]] = {
collection.find(and(
in("applicationId", applicationIds.map(i => Codecs.toBson(i)): _*),
equal("state", Codecs.toBson(State.DELETED.toString))
))
.toFuture()
.map(x => x.toList)
}

def fetchLatestByStateForApplication(applicationId: ApplicationId, state: State): Future[Option[StateHistory]] = {
collection.find(and(
equal("applicationId", Codecs.toBson(applicationId)),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ import uk.gov.hmrc.thirdpartyapplication.connector._
import uk.gov.hmrc.thirdpartyapplication.controllers.{DeleteApplicationRequest, FixCollaboratorRequest}
import uk.gov.hmrc.thirdpartyapplication.domain.models.{ApplicationStateChange, Deleted}
import uk.gov.hmrc.thirdpartyapplication.models._
import uk.gov.hmrc.thirdpartyapplication.models.db.StoredApplication
import uk.gov.hmrc.thirdpartyapplication.models.db.{PaginatedApplicationData, StoredApplication}
import uk.gov.hmrc.thirdpartyapplication.repository.{ApplicationRepository, NotificationRepository, StateHistoryRepository, SubscriptionRepository, TermsOfUseInvitationRepository}
import uk.gov.hmrc.thirdpartyapplication.services.AuditAction._
import uk.gov.hmrc.thirdpartyapplication.util.http.HeaderCarrierUtils._
Expand Down Expand Up @@ -260,14 +260,25 @@ class ApplicationService @Inject() (
.map(application => Application(data = application))

def searchApplications(applicationSearch: ApplicationSearch): Future[PaginatedApplicationResponse] = {
applicationRepository.searchApplications("applicationSearch")(applicationSearch).map { data =>
PaginatedApplicationResponse(
page = applicationSearch.pageNumber,
pageSize = applicationSearch.pageSize,
total = data.totals.foldLeft(0)(_ + _.total),
matching = data.matching.foldLeft(0)(_ + _.total),
applications = data.applications.map(application => Application(data = application))
)

def buildApplication(storedApplication: StoredApplication, stateHistory: Option[StateHistory]) = {
val partApp = Application(data = storedApplication)
partApp.copy(moreApplication = partApp.moreApplication.copy(lastActionActor = stateHistory.map(sh => ActorType.actorType(sh.actor)).getOrElse(ActorType.UNKNOWN)))
}

val applicationsResponse: Future[PaginatedApplicationData] = applicationRepository.searchApplications("applicationSearch")(applicationSearch)
val appHistory: Future[List[StateHistory]] = {
applicationsResponse.map(data => data.applications.map(app => app.id)).flatMap(ar => stateHistoryRepository.fetchDeletedByApplicationIds(ar))
}

applicationsResponse.zipWith(appHistory) {
case (data, appHistory) => PaginatedApplicationResponse(
page = applicationSearch.pageNumber,
pageSize = applicationSearch.pageSize,
total = data.totals.foldLeft(0)(_ + _.total),
matching = data.matching.foldLeft(0)(_ + _.total),
applications = data.applications.map(app => buildApplication(app, appHistory.find(ah => ah.applicationId == app.id)))
)
}
}

Expand Down
13 changes: 0 additions & 13 deletions conf/application-json-logger.xml

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -192,5 +192,66 @@ class StateHistoryRepositoryISpec
savedStateHistories shouldBe List(stateHistory)
}
}
"fetchDeletedByApplicationIds" should {
"fetch a single deleted application" in {
val requesterEmail = "[email protected]".toLaxEmail
val appId = ApplicationId.random
val ts = instant
val actor: Actor = Actors.AppCollaborator(requesterEmail)

val stateHistory = StateHistory(appId, State.DELETED, actor, Some(State.PENDING_RESPONSIBLE_INDIVIDUAL_VERIFICATION), changedAt = ts)

val result = await(repository.insert(stateHistory))
result shouldBe stateHistory

val retrieved = await(repository.fetchDeletedByApplicationIds(List(appId, ApplicationId.random)))
retrieved.size shouldBe 1
retrieved.head shouldBe stateHistory
}
"fetch multiple deleted applications" in {
val requesterEmail = "[email protected]".toLaxEmail
val appId = ApplicationId.random
val appId2 = ApplicationId.random
val appId3 = ApplicationId.random
val ts = instant
val actor: Actor = Actors.AppCollaborator(requesterEmail)

val stateHistory = StateHistory(appId, State.DELETED, actor, Some(State.PENDING_RESPONSIBLE_INDIVIDUAL_VERIFICATION), changedAt = ts)
val stateHistory2 = stateHistory.copy(applicationId = appId2)
val stateHistory3 = stateHistory.copy(applicationId = appId3)

await(repository.insert(stateHistory))
await(repository.insert(stateHistory2))
await(repository.insert(stateHistory3))

val retrieved = await(repository.fetchDeletedByApplicationIds(List(appId, appId2, appId3)))
retrieved.size shouldBe 3
retrieved should contain(stateHistory)
retrieved should contain(stateHistory2)
retrieved should contain(stateHistory3)
}

"fetch multiple deleted applications and none in other states" in {
val requesterEmail = "[email protected]".toLaxEmail
val appId = ApplicationId.random
val appId2 = ApplicationId.random
val appId3 = ApplicationId.random
val ts = instant
val actor: Actor = Actors.AppCollaborator(requesterEmail)

val stateHistory = StateHistory(appId, State.DELETED, actor, Some(State.PENDING_RESPONSIBLE_INDIVIDUAL_VERIFICATION), changedAt = ts)
val stateHistory2 = stateHistory.copy(applicationId = appId2)
val stateHistory3 = stateHistory.copy(applicationId = appId3, state = State.PENDING_GATEKEEPER_APPROVAL)

await(repository.insert(stateHistory))
await(repository.insert(stateHistory2))
await(repository.insert(stateHistory3))

val retrieved = await(repository.fetchDeletedByApplicationIds(List(appId, appId2, appId3)))
retrieved.size shouldBe 2
retrieved should contain(stateHistory)
retrieved should contain(stateHistory2)
retrieved should not contain stateHistory3
}
}
}
2 changes: 1 addition & 1 deletion project/AppDependencies.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ object AppDependencies {
lazy val bootstrapVersion = "9.2.0"
lazy val hmrcMongoVersion = "1.7.0"
lazy val commonDomainVersion = "0.15.0"
lazy val applicationEventVersion = "0.63.0"
lazy val applicationEventVersion = "0.64.0"

private lazy val compileDeps = Seq(
"uk.gov.hmrc" %% "bootstrap-backend-play-30" % bootstrapVersion,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,12 @@ trait StateHistoryRepositoryMockModule extends MockitoSugar with ArgumentMatcher
def thenFailWith(ex: Exception) =
when(aMock.fetchByApplicationId(*[ApplicationId])).thenReturn(failed(ex))
}

object FetchDeletedByApplicationIds {

def thenReturnWhen(applicationIds: List[ApplicationId])(values: StateHistory*) =
when(aMock.fetchDeletedByApplicationIds(eqTo(applicationIds))).thenReturn(successful(values.toList))
}
}

object StateHistoryRepoMock extends BaseStateHistoryRepoMock {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -918,6 +918,8 @@ class ApplicationServiceSpec
)
)
)
val histories = List(aHistory(standardApplicationData.id), aHistory(privilegedApplicationData.id), aHistory(ropcApplicationData.id))
StateHistoryRepoMock.FetchDeletedByApplicationIds.thenReturnWhen(List(standardApplicationData.id, privilegedApplicationData.id, ropcApplicationData.id))(histories: _*)

val result: PaginatedApplicationResponse = await(underTest.searchApplications(search))

Expand Down Expand Up @@ -980,4 +982,8 @@ class ApplicationServiceSpec
ApplicationId.random
)
}

private def aHistory(appId: ApplicationId, state: State = State.DELETED): StateHistory = {
StateHistory(appId, state, Actors.AppCollaborator("anEmail".toLaxEmail), Some(State.TESTING), changedAt = instant)
}
}

0 comments on commit 939fcbf

Please sign in to comment.