Skip to content

Commit

Permalink
Merge pull request #960 from ostelco/feature/support-provision-sim
Browse files Browse the repository at this point in the history
Add new sim provisioning API to support endpoint
  • Loading branch information
prasanthu authored Nov 26, 2019
2 parents 7dc29d0 + 80edf3e commit b655a29
Show file tree
Hide file tree
Showing 11 changed files with 197 additions and 10 deletions.
46 changes: 46 additions & 0 deletions acceptance-tests/src/main/kotlin/org/ostelco/at/jersey/Tests.kt
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ import kotlin.test.assertFails
import kotlin.test.assertNotNull
import kotlin.test.assertNull
import kotlin.test.assertTrue
import kotlin.test.fail


class CustomerTest {
Expand Down Expand Up @@ -283,6 +284,51 @@ class RegionsTest {
StripePayment.deleteCustomer(customerId = customerId)
}
}
@Test
fun `jersey test - POST support simprofile - Sim profile from houston`() {

val email = "regions-${randomInt()}@test.com"
var customerId = ""
try {
customerId = createCustomer(name = "Test Single Region User", email = email).id
enableRegion(email = email)

var regionDetailsList: Collection<RegionDetails> = get {
path = "/regions"
this.email = email
}

assertEquals(2, regionDetailsList.size, "Customer should have 2 regions")
var receivedRegion = regionDetailsList.find { it.status == APPROVED }
?: fail("Failed to find an approved region.")
val regionCode = receivedRegion.region.id
val simProfile = post<SimProfile> {
path = "/support/simprofile/$customerId"
this.email = email
this.queryParams = mapOf("regionCode" to regionCode, "profileType" to "iphone", "alias" to "")
}

regionDetailsList = get {
path = "/regions"
this.email = email
}
// Find the same Region
receivedRegion = regionDetailsList.find { it.region.id == regionCode }
?: fail("Failed to find the region used to create sim profile.")

assertEquals(
1,
receivedRegion.simProfiles.size,
"Should have only one sim profile")

assertNotNull(receivedRegion.simProfiles.single().iccId)
assertEquals("", receivedRegion.simProfiles.single().alias)
assertNotNull(receivedRegion.simProfiles.single().eSimActivationCode)
assertEquals(simProfile.iccId, receivedRegion.simProfiles.single().iccId)
} finally {
StripePayment.deleteCustomer(customerId = customerId)
}
}
}

class SubscriptionsTest {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ class SimProfilesResource(private val regionCode: String, private val dao: Subsc
dao.provisionSimProfile(
identity = token.identity,
regionCode = regionCode,
profileType = profileType)
profileType = profileType,
alias = "")
.responseBuilder()
}.build()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ interface SubscriberDAO {

fun getSimProfiles(identity: Identity, regionCode: String): Either<ApiError, Collection<SimProfile>>

fun provisionSimProfile(identity: Identity, regionCode: String, profileType: String?): Either<ApiError, SimProfile>
fun provisionSimProfile(identity: Identity, regionCode: String, profileType: String?, alias: String): Either<ApiError, SimProfile>

fun updateSimProfile(identity: Identity, regionCode: String, iccId: String, alias: String): Either<ApiError, SimProfile>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -190,9 +190,9 @@ class SubscriberDAOImpl : SubscriberDAO {
}
}

override fun provisionSimProfile(identity: Identity, regionCode: String, profileType: String?): Either<ApiError, SimProfile> {
override fun provisionSimProfile(identity: Identity, regionCode: String, profileType: String?, alias: String): Either<ApiError, SimProfile> {
return try {
storage.provisionSimProfile(identity, regionCode, profileType).mapLeft {
storage.provisionSimProfile(identity, regionCode, profileType, alias).mapLeft {
AuditLog.error(identity, message = "Failed to provision SIM profile.")
NotFoundError("Failed to provision SIM profile.", ApiErrorCode.FAILED_TO_PROVISION_SIM_PROFILE, it)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,6 @@ class SupportModule : PrimeModule {
jerseySever.register(ContextResource())
jerseySever.register(AuditLogResource())
jerseySever.register(CustomerResource())
jerseySever.register(SimProfilesResource())
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import org.ostelco.prime.apierror.InternalServerError
import org.ostelco.prime.apierror.NotFoundError
import org.ostelco.prime.apierror.responseBuilder
import org.ostelco.prime.appnotifier.AppNotifier
import org.ostelco.prime.auditlog.AuditLog
import org.ostelco.prime.auth.AccessTokenPrincipal
import org.ostelco.prime.getLogger
import org.ostelco.prime.model.Bundle
Expand All @@ -20,18 +21,21 @@ import org.ostelco.prime.model.Customer
import org.ostelco.prime.model.Identity
import org.ostelco.prime.model.PurchaseRecord
import org.ostelco.prime.model.ScanInformation
import org.ostelco.prime.model.SimProfile
import org.ostelco.prime.model.Subscription
import org.ostelco.prime.module.getResource
import org.ostelco.prime.notifications.NOTIFY_OPS_MARKER
import org.ostelco.prime.paymentprocessor.core.ForbiddenError
import org.ostelco.prime.paymentprocessor.core.ProductInfo
import org.ostelco.prime.storage.AdminDataSource
import org.ostelco.prime.storage.AuditLogStore
import org.ostelco.prime.tracing.EnableTracing
import java.util.regex.Pattern
import javax.validation.constraints.NotNull
import javax.ws.rs.DELETE
import javax.ws.rs.GET
import javax.ws.rs.PUT
import javax.ws.rs.POST
import javax.ws.rs.Path
import javax.ws.rs.PathParam
import javax.ws.rs.Produces
Expand Down Expand Up @@ -464,3 +468,62 @@ class CustomerResource {
}
}
}

/**
* Resource used to provision new sim profiles.
*/
@Path("/support/simprofile")

class SimProfilesResource {
private val logger by getLogger()
private val storage by lazy { getResource<AdminDataSource>() }

/**
* Provision a new SIM card.
*/
@EnableTracing
@POST
@Path("{id}")
@Produces(MediaType.APPLICATION_JSON)
fun provisionSimProfile(@Auth token: AccessTokenPrincipal?,
@NotNull
@PathParam("id")
id: String,
@QueryParam("regionCode")
regionCode: String,
@QueryParam("profileType")
profileType: String,
@QueryParam("alias")
alias: String): Response =
if (token == null) {
Response.status(Response.Status.UNAUTHORIZED)
} else {
logger.info("${token.name} Creating new SIM profile in region $regionCode & profileType $profileType for customerId: $id")
provisionSimProfile(
customerId =id,
regionCode = regionCode,
profileType = profileType,
alias = alias)
.responseBuilder(success = Response.Status.CREATED)
}.build()

private fun provisionSimProfile(customerId: String, regionCode: String, profileType: String, alias: String): Either<ApiError, SimProfile> {
return try {
storage.getAnyIdentityForCustomerId(id = customerId).flatMap { identity: Identity ->
storage.provisionSimProfile(identity, regionCode, profileType, alias).mapLeft {
AuditLog.error(identity, message = "Failed to provision SIM profile.")
it
}.map {
AuditLog.info(identity, message = "Provisioned new SIM with ICCID ${it.iccId} by support.")
it
}
}.mapLeft {
NotFoundError("Failed to provision SIM profile.", ApiErrorCode.FAILED_TO_PROVISION_SIM_PROFILE, it)
}
} catch (e: Exception) {
logger.error("Failed to provision SIM profile for customer with id - $customerId", e)
Either.left(NotFoundError("Failed to provision SIM profile", ApiErrorCode.FAILED_TO_PROVISION_SIM_PROFILE))
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -747,7 +747,8 @@ object Neo4jStoreSingleton : GraphStore {
override fun provisionSimProfile(
identity: ModelIdentity,
regionCode: String,
profileType: String?): Either<StoreError, ModelSimProfile> = writeTransaction {
profileType: String?,
alias: String): Either<StoreError, ModelSimProfile> = writeTransaction {
IO {
Either.monad<StoreError>().binding {
val customerId = getCustomerId(identity = identity).bind()
Expand All @@ -766,7 +767,7 @@ object Neo4jStoreSingleton : GraphStore {
val simEntry = simManager.allocateNextEsimProfile(hlr = hssNameLookup.getHssName(region.id.toLowerCase()), phoneType = profileType)
.mapLeft { NotFoundError("eSIM profile", id = "Loltel") }
.bind()
val simProfile = SimProfile(id = UUID.randomUUID().toString(), iccId = simEntry.iccId, requestedOn = utcTimeNow())
val simProfile = SimProfile(id = UUID.randomUUID().toString(), iccId = simEntry.iccId, alias = alias, requestedOn = utcTimeNow())
create { simProfile }.bind()
fact { (Customer withId customerId) has (SimProfile withId simProfile.id) }.bind()
fact { (SimProfile withId simProfile.id) isFor (Region withCode regionCode.toLowerCase()) }.bind()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -749,7 +749,8 @@ class Neo4jStoreTest {
Neo4jStoreSingleton.provisionSimProfile(
identity = IDENTITY,
regionCode = REGION_CODE,
profileType = "default")
profileType = "default",
alias = "")
.bimap(
{ fail(it.message) },
{
Expand Down Expand Up @@ -956,7 +957,8 @@ class Neo4jStoreTest {
Neo4jStoreSingleton.provisionSimProfile(
identity = IDENTITY,
regionCode = REGION_CODE,
profileType = "default")
profileType = "default",
alias = "")
.mapLeft { fail(it.message) }

// test
Expand Down Expand Up @@ -1032,7 +1034,8 @@ class Neo4jStoreTest {
Neo4jStoreSingleton.provisionSimProfile(
identity = IDENTITY,
regionCode = REGION_CODE,
profileType = "default")
profileType = "default",
alias = "")
.mapLeft { fail(it.message) }

// test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ interface ClientGraphStore {
/**
* Provision new SIM Profile for Customer
*/
fun provisionSimProfile(identity: Identity, regionCode: String, profileType: String?): Either<StoreError, SimProfile>
fun provisionSimProfile(identity: Identity, regionCode: String, profileType: String?, alias: String): Either<StoreError, SimProfile>

/**
* Update SIM Profile for Customer
Expand Down
36 changes: 36 additions & 0 deletions prime/infra/dev/prime-houston-api.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,42 @@ paths:
description: "The customerId of the customer"
required: true
type: string
"/support/simprofile/{id}":
post:
description: "Provision SIM Profile for the user."
produces:
- application/json
operationId: "provisionSimProfile"
responses:
201:
description: "Provisioned SIM profile for this user."
schema:
$ref: '#/definitions/SimProfile'
400:
description: "Not allowed for this region, or missing parameters."
500:
description: "Service Unavailable"
security:
- auth0_jwt: []
parameters:
- name: id
in: path
description: "The customerId of the user"
required: true
type: string
- name: regionCode
in: query
description: "Region code"
required: true
type: string
- name: profileType
in: query
description: "Profile Type"
type: string
- name: alias
in: query
description: "Name for the SIM"
type: string

definitions:
Context:
Expand Down
36 changes: 36 additions & 0 deletions prime/infra/prod/prime-houston-api.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,42 @@ paths:
description: "The customerId of the customer"
required: true
type: string
"/support/simprofile/{id}":
post:
description: "Provision SIM Profile for the user."
produces:
- application/json
operationId: "provisionSimProfile"
responses:
201:
description: "Provisioned SIM profile for this user."
schema:
$ref: '#/definitions/SimProfile'
400:
description: "Not allowed for this region, or missing parameters."
500:
description: "Service Unavailable"
security:
- auth0_jwt: []
parameters:
- name: id
in: path
description: "The customerId of the user"
required: true
type: string
- name: regionCode
in: query
description: "Region code"
required: true
type: string
- name: profileType
in: query
description: "Profile Type"
type: string
- name: alias
in: query
description: "Name for the SIM"
type: string

definitions:
Context:
Expand Down

0 comments on commit b655a29

Please sign in to comment.