Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

HIPP-1708: Spike for data model #482

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions app/models/application/Application.scala
Original file line number Diff line number Diff line change
Expand Up @@ -28,18 +28,19 @@ case class Application (
lastUpdated: LocalDateTime,
teamId: Option[String],
teamMembers: Seq[TeamMember],
environments: Environments,
// environments: Environments,
apis: Seq[Api],
issues: Seq[String] = Seq.empty,
deleted: Option[Deleted] = None,
teamName: Option[String] = None,
credentials: Set[Credential]
)

object Application {

def apply(id: String, name: String, createdBy: Creator, teamId: Option[String], teamMembers: Seq[TeamMember]): Application = {
val now = LocalDateTime.now()
Application(id, name, now, createdBy, now, teamId, teamMembers, Environments(), Seq.empty)
Application(id, name, now, createdBy, now, teamId, teamMembers, Seq.empty, credentials = Set.empty)
}

def apply(id: String, name: String, createdBy: Creator, teamId: String): Application = {
Expand All @@ -56,7 +57,7 @@ object Application {

def apply(id: String, name: String, createdBy: Creator, environments: Environments): Application = {
val now = LocalDateTime.now()
Application(id, name, now, createdBy, now, None, Seq.empty, environments, Seq.empty)
Application(id, name, now, createdBy, now, None, Seq.empty, Seq.empty, credentials = environments.toCredentials)
}

implicit val applicationFormat: Format[Application] = Json.format[Application]
Expand Down
99 changes: 34 additions & 65 deletions app/models/application/ApplicationLenses.scala
Original file line number Diff line number Diff line change
Expand Up @@ -22,54 +22,12 @@ import models.user.UserModel

object ApplicationLenses {

val applicationEnvironments: Lens[Application, Environments] =
Lens[Application, Environments](
get = _.environments,
set = (application, environments) => application.copy(environments = environments)
)

val environmentScopes: Lens[Environment, Seq[Scope]] =
Lens[Environment, Seq[Scope]](
get = _.scopes,
set = (environment, scopes) => environment.copy(scopes = scopes)
)

val environmentCredentials: Lens[Environment, Seq[Credential]] =
Lens[Environment, Seq[Credential]](
val applicationCredentials: Lens[Application, Set[Credential]] =
Lens[Application, Set[Credential]](
get = _.credentials,
set = (environment, credentials) => environment.copy(credentials = credentials)
set = (application, credentials) => application.copy(credentials = credentials)
)

val environmentPrimary: Lens[Environments, Environment] =
Lens[Environments, Environment](
get = _.primary,
set = (environments, primary) => environments.copy(primary = primary)
)

val applicationPrimary: Lens[Application, Environment] =
Lens.compose(applicationEnvironments, environmentPrimary)

val applicationPrimaryScopes: Lens[Application, Seq[Scope]] =
Lens.compose(applicationPrimary, environmentScopes)

val applicationPrimaryCredentials: Lens[Application, Seq[Credential]] =
Lens.compose(applicationPrimary, environmentCredentials)

val environmentSecondary: Lens[Environments, Environment] =
Lens[Environments, Environment](
get = _.secondary,
set = (environments, secondary) => environments.copy(secondary = secondary)
)

val applicationSecondary: Lens[Application, Environment] =
Lens.compose(applicationEnvironments, environmentSecondary)

val applicationSecondaryScopes: Lens[Application, Seq[Scope]] =
Lens.compose(applicationSecondary, environmentScopes)

val applicationSecondaryCredentials: Lens[Application, Seq[Credential]] =
Lens.compose(applicationSecondary, environmentCredentials)

val applicationTeamMembers: Lens[Application, Seq[TeamMember]] =
Lens[Application, Seq[TeamMember]](
get = _.teamMembers,
Expand All @@ -91,53 +49,64 @@ object ApplicationLenses {
implicit class ApplicationLensOps(application: Application) {

def setScopes(environmentName: EnvironmentName, scopes: Seq[Scope]): Application = {
environmentName match {
case Primary => applicationPrimaryScopes.set(application, scopes)
case Secondary => applicationSecondaryScopes.set(application, scopes)
}
application
}

def setScopes(hipEnvironment: HipEnvironment, scopes: Seq[Scope]): Application = {
setScopes(hipEnvironment.environmentName, scopes)
}

private def getCredentials(environmentId: String): Seq[Credential] = {
applicationCredentials
.get(application)
.filter(_.environmentId == environmentId)
.toSeq
.sortBy(_.created)
}

def getCredentials(environmentName: EnvironmentName): Seq[Credential] = {
environmentName match {
case Primary => applicationPrimaryCredentials.get(application)
case Secondary => applicationSecondaryCredentials.get(application)
case Primary => getCredentials(EnvironmentName.primaryEnvironmentId)
case Secondary => getCredentials(EnvironmentName.secondaryEnvironmentId)
}
}

def getCredentials(hipEnvironment: HipEnvironment): Seq[Credential] = {
getCredentials(hipEnvironment.environmentName)
getCredentials(hipEnvironment.id)
}

def getMasterCredential(environmentName: EnvironmentName): Option[Credential] = {
environmentName match {
case Primary =>
applicationPrimaryCredentials.get(application)
.sortWith((a, b) => a.created.isAfter(b.created))
.headOption
case Secondary =>
applicationSecondaryCredentials.get(application)
.sortWith((a, b) => a.created.isAfter(b.created))
.headOption
}
getCredentials(environmentName)
.sortWith((a, b) => a.created.isAfter(b.created))
.headOption
}

def getMasterCredential(hipEnvironment: HipEnvironment): Option[Credential] = {
getMasterCredential(hipEnvironment.environmentName)
}

private def setCredentials(environmentId: String, credentials: Seq[Credential]): Application = {
applicationCredentials.set(
application,
applicationCredentials
.get(application)
.filterNot(_.environmentId == environmentId) ++ credentials.toSet
)
}

def setCredentials(environmentName: EnvironmentName, credentials: Seq[Credential]): Application = {
environmentName match {
case Primary => applicationPrimaryCredentials.set(application, credentials)
case Secondary => applicationSecondaryCredentials.set(application, credentials)
case Primary => setCredentials(EnvironmentName.primaryEnvironmentId, credentials)
case Secondary => setCredentials(EnvironmentName.secondaryEnvironmentId, credentials)
}
}

def setCredentials(hipEnvironment: HipEnvironment, credentials: Seq[Credential]): Application = {
setCredentials(hipEnvironment.environmentName, credentials)
setCredentials(hipEnvironment.id, credentials)
}

def setCredentials(credentials: Set[Credential]): Application = {
applicationCredentials.set(application, credentials)
}

def setTeamId(teamId: String): Application = {
Expand Down
2 changes: 1 addition & 1 deletion app/models/application/Credential.scala
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import play.api.libs.json.{Format, Json}

import java.time.LocalDateTime

case class Credential(clientId: String, created: LocalDateTime, clientSecret: Option[String], secretFragment: Option[String])
case class Credential(clientId: String, created: LocalDateTime, clientSecret: Option[String], secretFragment: Option[String], environmentId: String)

object Credential {

Expand Down
4 changes: 4 additions & 0 deletions app/models/application/EnvironmentName.scala
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,8 @@ object EnvironmentName extends Enumerable.Implicits {
value.toString
}
}

val primaryEnvironmentId: String = "production"
val secondaryEnvironmentId: String = "test"

}
8 changes: 7 additions & 1 deletion app/models/application/Environments.scala
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,13 @@ import play.api.libs.json.{Format, Json}
case class Environments(
primary:Environment,
secondary:Environment
)
) {

def toCredentials: Set[Credential] = {
(primary.credentials ++ secondary.credentials).toSet
}

}

object Environments {

Expand Down
2 changes: 1 addition & 1 deletion app/views/admin/ManageApplicationsView.scala.html
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
}

@clientIds(application: Application) = @{
Seq(application.environments.primary, application.environments.secondary).flatMap(_.credentials.map(_.clientId)).mkString(",")
application.credentials.map(_.clientId).mkString(",")
}

@layout(
Expand Down
9 changes: 5 additions & 4 deletions it/test/connectors/ApplicationsConnectorSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -322,7 +322,7 @@ class ApplicationsConnectorSpec

"ApplicationsConnector.addCredential" - {
"must place the correct request and return the new Credential" in {
val expected = Credential("test-client-id", LocalDateTime.now(), Some("test-secret"), Some("test-fragment"))
val expected = Credential("test-client-id", LocalDateTime.now(), Some("test-secret"), Some("test-fragment"), FakeHipEnvironments.production.id)

stubFor(
post(urlEqualTo(s"/api-hub-applications/applications/${FakeApplication.id}/environments/${FakeHipEnvironments.production.id}/credentials"))
Expand Down Expand Up @@ -1717,7 +1717,8 @@ class ApplicationsConnectorSpec
clientId = s"test-client-id-$i",
created = LocalDateTime.now(),
clientSecret = None,
secretFragment = None
secretFragment = None,
environmentId = environment.id
)
)

Expand Down Expand Up @@ -1874,8 +1875,8 @@ object ApplicationsConnectorSpec extends HttpClientV2Support {
LocalDateTime.now(),
None,
Seq(TeamMember(FakeUser.email)),
Environments(),
Seq.empty
Seq.empty,
credentials = Set.empty
)

val invalidOasResponse: InvalidOasResponse = InvalidOasResponse(
Expand Down
33 changes: 10 additions & 23 deletions test-utils/generators/ApplicationGenerator.scala
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@

package generators

import models.application._
import config.HipEnvironment
import fakes.FakeHipEnvironments
import models.application.*
import org.scalacheck.rng.Seed
import org.scalacheck.{Arbitrary, Gen}

Expand Down Expand Up @@ -59,32 +61,17 @@ trait ApplicationGenerator {
} yield TeamMember(email)
}

val scopeGenerator: Gen[Scope] = {
for {
name <- Gen.alphaStr
} yield Scope(name)
val hipEnvironmentGenerator: Gen[HipEnvironment] = {
Gen.oneOf(FakeHipEnvironments.environments)
}

val credentialGenerator: Gen[Credential] = {
for {
clientId <- Gen.uuid
clientSecret <- Gen.uuid
created <- localDateTimeGenerator
} yield Credential(clientId.toString, created, Some(clientSecret.toString), Some(clientSecret.toString.takeRight(4)))
}

val environmentGenerator: Gen[Environment] = {
for {
scopes <- Gen.listOf(scopeGenerator)
credentials <- Gen.listOf(credentialGenerator)
} yield Environment(scopes, credentials)
}

val environmentsGenerator: Gen[Environments] = {
for {
primary <- environmentGenerator
secondary <- environmentGenerator
} yield Environments(primary,secondary)
hipEnvironment <- hipEnvironmentGenerator
} yield Credential(clientId.toString, created, Some(clientSecret.toString), Some(clientSecret.toString.takeRight(4)), hipEnvironment.id)
}

private def applicationGen: Gen[Application] = Gen.sized { _ =>
Expand All @@ -96,7 +83,7 @@ trait ApplicationGenerator {
lastUpdated <- localDateTimeGenerator
teamId <- teamIdGenerator
teamMembers <- Gen.listOf(teamMemberGenerator)
environments <- environmentsGenerator
credentials <- Gen.listOf(credentialGenerator)
} yield
Application(
appId,
Expand All @@ -106,8 +93,8 @@ trait ApplicationGenerator {
lastUpdated,
teamId,
teamMembers,
environments,
Seq.empty
Seq.empty,
credentials = credentials.toSet
)
}

Expand Down
34 changes: 2 additions & 32 deletions test/controllers/actions/FakeApplication.scala
Original file line number Diff line number Diff line change
Expand Up @@ -28,36 +28,6 @@ object FakeApplication extends Application(
LocalDateTime.now(),
None,
Seq(TeamMember(FakeUser.email)),
Environments(),
Seq.empty
)

object FakeApplicationWithSecrets extends Application(
"fake-application-id",
"fake-application-name",
LocalDateTime.now(),
Creator(FakeUser.email),
LocalDateTime.now(),
None,
Seq(TeamMember(FakeUser.email)),
Environments(
primary = Environment(scopes = Seq(Scope("scope_name")), credentials = Seq(Credential("primary_client_id", LocalDateTime.now(), None, Some("primary fragment")))),
secondary = Environment(scopes = Seq(Scope("scope_name")), credentials = Seq(Credential("secondary_client_id", LocalDateTime.now(), Some("secondary secret"), Some("secondary fragment"))))
),
Seq.empty
)

object FakeApplicationWithIdButNoSecrets extends Application(
"fake-application-id",
"fake-application-name",
LocalDateTime.now(),
Creator(FakeUser.email),
LocalDateTime.now(),
None,
Seq(TeamMember(FakeUser.email)),
Environments(
primary = Environment(scopes = Seq(Scope("scope_name")), credentials = Seq(Credential("primary_client_id", LocalDateTime.now(), None, None))),
secondary = Environment(scopes = Seq(Scope("scope_name")), credentials = Seq(Credential("secondary_client_id", LocalDateTime.now(), None, None)))
),
Seq.empty
Seq.empty,
credentials = Set.empty
)
21 changes: 13 additions & 8 deletions test/controllers/admin/ManageApplicationsControllerSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ package controllers.admin

import base.SpecBase
import controllers.routes
import models.application.{Application, Creator, Environment, Environments, TeamMember, Credential}
import fakes.FakeHipEnvironments
import models.application.{Application, Creator, Credential, Environment, Environments, TeamMember}
import models.application.ApplicationLenses.ApplicationLensOps
import models.user.UserModel
import org.mockito.ArgumentMatchers.{any, eq as eqTo}
import org.mockito.Mockito.{verify, when}
Expand Down Expand Up @@ -50,12 +52,12 @@ class ManageApplicationsControllerSpec
val primaryClientId2 = "client-id-2"
val secondaryClientId1 = "client-id-3"
val secondaryClientId2 = "client-id-4"
val environmentsWithCredentials = Environments(
buildEnvironmentWithClientIds(Seq(primaryClientId1, primaryClientId2)),
buildEnvironmentWithClientIds(Seq(secondaryClientId1, secondaryClientId2))
)

val credentials = buildCredentials(Seq(primaryClientId1, primaryClientId2), FakeHipEnvironments.production.id) ++
buildCredentials(Seq(secondaryClientId1, secondaryClientId2), FakeHipEnvironments.test.id)

val applications = Seq(
Application("id-1", "app-name-2", Creator(creatorEmail), Seq.empty).copy(teamMembers = Seq(TeamMember(testEmail))).copy(environments = environmentsWithCredentials),
Application("id-1", "app-name-2", Creator(creatorEmail), Seq.empty).copy(teamMembers = Seq(TeamMember(testEmail))).setCredentials(credentials.toSet),
Application("id-2", "app-name-1", Creator(creatorEmail), Seq.empty).copy(teamMembers = Seq(TeamMember(testEmail)))
)

Expand Down Expand Up @@ -106,8 +108,11 @@ class ManageApplicationsControllerSpec
Fixture(playApplication, apiHubService)
}

private def buildEnvironmentWithClientIds(clientIds: Seq[String]): Environment = {
Environment(Seq.empty, clientIds.map(id => Credential(id, LocalDateTime.now(), None, None)))
private def buildCredentials(clientIds: Seq[String], environmentId: String) = {
clientIds.map(
clientId =>
Credential(clientId, LocalDateTime.now(), None, None, environmentId)
)
}

}
Loading