Skip to content

Commit

Permalink
Using admin tool, identify customer using jsonPayload.mdc.customerIde…
Browse files Browse the repository at this point in the history
…ntity in the logs

Identify customer in the logs
  • Loading branch information
vihangpatil authored Nov 8, 2019
2 parents becb138 + dfac29b commit bda0d7f
Show file tree
Hide file tree
Showing 10 changed files with 78 additions and 35 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import io.dropwizard.auth.Auth
import org.ostelco.prime.apierror.ApiError
import org.ostelco.prime.apierror.ApiErrorCode
import org.ostelco.prime.apierror.ApiErrorCode.FAILED_TO_FETCH_AUDIT_LOGS
import org.ostelco.prime.apierror.ApiErrorMapper
import org.ostelco.prime.apierror.InternalServerError
import org.ostelco.prime.apierror.NotFoundError
import org.ostelco.prime.apierror.responseBuilder
Expand All @@ -32,7 +31,6 @@ import java.util.regex.Pattern
import javax.validation.constraints.NotNull
import javax.ws.rs.DELETE
import javax.ws.rs.GET
import javax.ws.rs.POST
import javax.ws.rs.PUT
import javax.ws.rs.Path
import javax.ws.rs.PathParam
Expand Down Expand Up @@ -115,7 +113,7 @@ class ProfilesResource {

private fun getAllScanInformation(customerId: String): Either<ApiError, Collection<ScanInformation>> {
return try {
storage.getIdentityForCustomerId(id = customerId).flatMap { identity: Identity ->
storage.getAnyIdentityForCustomerId(id = customerId).flatMap { identity: Identity ->
storage.getAllScanInformation(identity = identity)
}.mapLeft {
NotFoundError("Failed to fetch scan information.", ApiErrorCode.FAILED_TO_FETCH_SCAN_INFORMATION, it)
Expand Down Expand Up @@ -162,10 +160,8 @@ class ProfilesResource {

private fun getProfileListForMsisdn(msisdn: String): Either<ApiError, Collection<Customer>> {
return try {
storage.getCustomerForMsisdn(msisdn).mapLeft {
storage.getCustomersForMsisdn(msisdn).mapLeft {
NotFoundError("Failed to fetch profile.", ApiErrorCode.FAILED_TO_FETCH_CUSTOMER, it)
}.map {
listOf(it)
}
} catch (e: Exception) {
logger.error("Failed to fetch profile for msisdn $msisdn", e)
Expand All @@ -176,7 +172,7 @@ class ProfilesResource {
// TODO: Reuse the one from SubscriberDAO
private fun getSubscriptions(customerId: String): Either<ApiError, Collection<Subscription>> {
return try {
storage.getIdentityForCustomerId(id = customerId).flatMap { identity: Identity ->
storage.getAnyIdentityForCustomerId(id = customerId).flatMap { identity: Identity ->
storage.getSubscriptions(identity)
}.mapLeft {
NotFoundError("Failed to get subscriptions.", ApiErrorCode.FAILED_TO_FETCH_SUBSCRIPTIONS, it)
Expand Down Expand Up @@ -216,7 +212,7 @@ class BundlesResource {
// TODO: Reuse the one from SubscriberDAO
private fun getBundles(customerId: String): Either<ApiError, Collection<Bundle>> {
return try {
storage.getIdentityForCustomerId(id = customerId).flatMap { identity: Identity ->
storage.getAnyIdentityForCustomerId(id = customerId).flatMap { identity: Identity ->
storage.getBundles(identity)
}.mapLeft {
NotFoundError("Failed to get bundles. ${it.message}", ApiErrorCode.FAILED_TO_FETCH_BUNDLES)
Expand Down Expand Up @@ -256,7 +252,7 @@ class PurchaseResource {
// TODO: Reuse the one from SubscriberDAO
private fun getPurchaseHistory(customerId: String): Either<ApiError, Collection<PurchaseRecord>> {
return try {
storage.getIdentityForCustomerId(id = customerId).flatMap { identity: Identity ->
storage.getAnyIdentityForCustomerId(id = customerId).flatMap { identity: Identity ->
storage.getPurchaseRecords(identity)
}.bimap(
{ NotFoundError("Failed to get purchase history.", ApiErrorCode.FAILED_TO_FETCH_PAYMENT_HISTORY, it) },
Expand Down Expand Up @@ -306,7 +302,7 @@ class RefundResource {

private fun refundPurchase(customerId: String, purchaseRecordId: String, reason: String): Either<ApiError, ProductInfo> {
return try {
storage.getIdentityForCustomerId(id = customerId).flatMap { identity: Identity ->
storage.getAnyIdentityForCustomerId(id = customerId).flatMap { identity: Identity ->
storage.refundPurchase(identity, purchaseRecordId, reason)
}.mapLeft {
when (it) {
Expand Down Expand Up @@ -350,7 +346,7 @@ class ContextResource {
// TODO: Reuse the one from SubscriberDAO
private fun getContext(customerId: String): Either<ApiError, Context> {
return try {
storage.getIdentityForCustomerId(id = customerId).flatMap { identity: Identity ->
storage.getAnyIdentityForCustomerId(id = customerId).flatMap { identity: Identity ->
storage.getCustomer(identity).map { customer ->
storage.getAllRegionDetails(identity = identity)
.fold(
Expand Down Expand Up @@ -459,7 +455,7 @@ class CustomerResource {
// TODO: Reuse the one from SubscriberDAO
private fun removeCustomer(customerId: String): Either<ApiError, Unit> {
return try {
storage.getIdentityForCustomerId(id = customerId).flatMap { identity: Identity ->
storage.getAnyIdentityForCustomerId(id = customerId).flatMap { identity: Identity ->
storage.removeCustomer(identity)
}.mapLeft {
NotFoundError("Failed to remove customer.", ApiErrorCode.FAILED_TO_REMOVE_CUSTOMER, it)
Expand Down
6 changes: 6 additions & 0 deletions neo4j-store/src/main/kotlin/org/ostelco/prime/dsl/Syntax.kt
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,12 @@ infix fun Customer.Companion.referredBy(customer: CustomerContext) =
fromId = customer.id
)

infix fun Customer.Companion.withSubscription(subscription: SubscriptionContext) =
RelatedToClause(
relationType = subscriptionRelation,
toId = subscription.id
)

//
// ExCustomer
//
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import org.ostelco.prime.dsl.withId
import org.ostelco.prime.dsl.withKyc
import org.ostelco.prime.dsl.withMsisdn
import org.ostelco.prime.dsl.withSku
import org.ostelco.prime.dsl.withSubscription
import org.ostelco.prime.dsl.writeTransaction
import org.ostelco.prime.ekyc.DaveKycService
import org.ostelco.prime.ekyc.MyInfoKycService
Expand Down Expand Up @@ -2100,21 +2101,11 @@ object Neo4jStoreSingleton : GraphStore {
// Balance (Customer - Subscription - Bundle)
//

override fun getCustomerForMsisdn(msisdn: String): Either<StoreError, Customer> = readTransaction {
read("""
MATCH (customer:${customerEntity.name})-[:${subscriptionRelation.name}]->(subscription:${subscriptionEntity.name} {msisdn: '$msisdn'})
RETURN customer
""".trimIndent(),
transaction) {
if (it.hasNext())
Either.right(customerEntity.createEntity(it.single().get("customer").asMap()))
else
Either.left(NotFoundError(type = customerEntity.name, id = msisdn))
}
override fun getCustomersForMsisdn(msisdn: String): Either<StoreError, Collection<Customer>> = readTransaction {
get(Customer withSubscription (Subscription withMsisdn msisdn))
}


override fun getIdentityForCustomerId(id: String): Either<StoreError, ModelIdentity> = readTransaction {
override fun getAnyIdentityForCustomerId(id: String): Either<StoreError, ModelIdentity> = readTransaction {
read("""
MATCH (:${customerEntity.name} { id:'$id' })<-[r:${identifiesRelation.name}]-(identity:${identityEntity.name})
RETURN identity, r.provider as provider
Expand All @@ -2135,7 +2126,7 @@ object Neo4jStoreSingleton : GraphStore {
read("""
MATCH (c:${customerEntity.name})<-[r:${identifiesRelation.name}]-(identity:${identityEntity.name})
WHERE c.contactEmail contains '$queryString' or c.nickname contains '$queryString' or c.id contains '$queryString'
RETURN c, identity, r.provider as provider
RETURN identity, r.provider as provider
""".trimIndent(),
transaction) {
if (it.hasNext()) {
Expand All @@ -2152,6 +2143,20 @@ object Neo4jStoreSingleton : GraphStore {
}
}

override fun getAllIdentities(): Either<StoreError, Collection<org.ostelco.prime.model.Identity>> = readTransaction {
read("""
MATCH (:${customerEntity.name})<-[r:${identifiesRelation.name}]-(identity:${identityEntity.name})
RETURN identity, r.provider as provider
""".trimIndent(),
transaction) { statementResult ->
statementResult.list { record ->
val identity = identityEntity.createEntity(record.get("identity").asMap())
val provider = record.get("provider").asString()
ModelIdentity(id = identity.id, type = identity.type, provider = provider)
}.right()
}
}

//
// For metrics
//
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -548,7 +548,7 @@ object ObjectHandler {

private fun toSimpleMap(map: Map<String, Any?>, prefix: String = ""): Map<String, Any> {
val outputMap: MutableMap<String, Any> = LinkedHashMap()
map.forEach { key, value ->
map.forEach { (key, value) ->
when (value) {
is Map<*, *> -> outputMap.putAll(toSimpleMap(value as Map<String, Any>, "$prefix$key$SEPARATOR"))
is List<*> -> println("Skipping list value: $value for key: $key")
Expand All @@ -569,7 +569,7 @@ object ObjectHandler {

internal fun toNestedMap(map: Map<String, Any>): Map<String, Any> {
val outputMap: MutableMap<String, Any> = LinkedHashMap()
map.forEach { key, value ->
map.forEach { (key, value) ->
if (key.contains(SEPARATOR)) {
val keys = key.split(SEPARATOR)
var loopMap = outputMap
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,10 @@ object Notifications {
val lowBalanceThreshold = ConfigRegistry.config.lowBalanceThreshold
if ((balance < lowBalanceThreshold) && ((balance + reserved) > lowBalanceThreshold)) {
// TODO martin : Title and message should differ depending on subscription
storage.getCustomerForMsisdn(msisdn).map { customer ->
appNotifier.notify(customer.id, "OYA", "You have less then " + lowBalanceThreshold / 1000000 + "Mb data left")
storage.getCustomersForMsisdn(msisdn).map { customers ->
customers.forEach { customer ->
appNotifier.notify(customer.id, "OYA", "You have less then " + lowBalanceThreshold / 1000000 + "Mb data left")
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -195,10 +195,11 @@ data class ConsumptionResult(val msisdnAnalyticsId: String, val granted: Long, v

interface AdminGraphStore {

fun getCustomerForMsisdn(msisdn: String): Either<StoreError, Customer>
fun getCustomersForMsisdn(msisdn: String): Either<StoreError, Collection<Customer>>

fun getIdentityForCustomerId(id: String): Either<StoreError, Identity>
fun getAnyIdentityForCustomerId(id: String): Either<StoreError, Identity>
fun getIdentitiesFor(queryString: String): Either<StoreError, Collection<Identity>>
fun getAllIdentities(): Either<StoreError, Collection<Identity>>

/**
* Link Customer to MSISDN
Expand Down
2 changes: 1 addition & 1 deletion prime/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ plugins {
}

// Update version in [script/start.sh] too.
version = "1.72.1"
version = "1.72.2"

dependencies {
// interface module between prime and prime-modules
Expand Down
2 changes: 1 addition & 1 deletion prime/script/start.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@ exec java \
-Dfile.encoding=UTF-8 \
--add-opens java.base/java.lang=ALL-UNNAMED \
--add-opens java.base/java.io=ALL-UNNAMED \
-agentpath:/opt/cprof/profiler_java_agent.so=-cprof_service=prime,-cprof_service_version=1.72.1,-logtostderr,-minloglevel=2,-cprof_enable_heap_sampling \
-agentpath:/opt/cprof/profiler_java_agent.so=-cprof_service=prime,-cprof_service_version=1.72.2,-logtostderr,-minloglevel=2,-cprof_enable_heap_sampling \
-jar /prime.jar server /config/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import org.ostelco.tools.prime.admin.actions.approveRegionForCustomer
import org.ostelco.tools.prime.admin.actions.createCustomer
import org.ostelco.tools.prime.admin.actions.createSubscription
import org.ostelco.tools.prime.admin.actions.getAllRegionDetails
import org.ostelco.tools.prime.admin.actions.identifyCustomer
import org.ostelco.tools.prime.admin.actions.print
import org.ostelco.tools.prime.admin.actions.printLeft
import org.ostelco.tools.prime.admin.actions.setBalance
Expand Down Expand Up @@ -121,4 +122,10 @@ fun doActions() {

}

fun debug() {

// identify customer using `jsonPayload.mdc.customerIdentity` in the logs
identifyCustomer(setOf(""))
}

data class SimProfileData(val iccId: String, val msisdn: String)
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import arrow.core.left
import arrow.core.right
import arrow.effects.IO
import arrow.instances.either.monad.monad
import org.apache.commons.codec.digest.DigestUtils
import org.ostelco.prime.dsl.withId
import org.ostelco.prime.dsl.writeTransaction
import org.ostelco.prime.model.Bundle
Expand Down Expand Up @@ -126,4 +127,29 @@ private fun emailAsIdentity(email: String) = Identity(
id = email,
type = "EMAIL",
provider = "email"
)
)

fun identifyCustomer(idDigests: Set<String>) = IO {
Either.monad<StoreError>().binding {
adminStore
// get all Identity values
.getAllIdentities()
.bind()
// map to <Digest of id, Identity>
.map { String(Base64.getEncoder().encode(DigestUtils.sha256(it.id))) to it }
.toMap()
// filter on idDigests we want to find
.filterKeys { idDigests.contains(it) }
// find customer for each filtered Identity
.forEach { (idDigest, identity) ->
adminStore.getCustomer(identity).bimap(
{ println("No Customer found for digest: $idDigest. - ${it.message}") },
{ println("Found Customer ID: ${it.id} for digest: $idDigest") }
)
}
}.fix()
}
.unsafeRunSync()
.mapLeft {
println(it.message)
}

0 comments on commit bda0d7f

Please sign in to comment.