membership-attribute-service/app/controllers/ContactController.scala (87 lines of code) (raw):
package controllers
import actions.{AuthAndBackendRequest, CommonActions, Return401IfNotSignedInRecently}
import com.gu.monitoring.SafeLogger.LogPrefix
import com.gu.monitoring.SafeLogging
import models.AccessScope.updateSelf
import models.DeliveryAddress
import monitoring.CreateMetrics
import play.api.mvc.{Action, AnyContent, BaseController, ControllerComponents}
import services.salesforce.ContactRepository
import scala.concurrent.{ExecutionContext, Future}
import scala.util.control.Exception
class ContactController(
commonActions: CommonActions,
override val controllerComponents: ControllerComponents,
createMetrics: CreateMetrics,
) extends BaseController
with SafeLogging {
import commonActions._
private implicit val ec: ExecutionContext = controllerComponents.executionContext
val metrics = createMetrics.forService(classOf[ContactController])
def updateDeliveryAddress(contactId: String): Action[AnyContent] =
AuthorizeForRecentLogin(Return401IfNotSignedInRecently, requiredScopes = List(updateSelf)).async { request =>
import request.logPrefix
metrics.measureDuration("PUT /user-attributes/me/delivery-address/:contactId") {
logger.info(s"Updating delivery address for contact $contactId")
isContactOwnedByRequester(request, contactId) flatMap { valid =>
if (valid) {
val submitted = Exception.allCatch.either {
request.body.asJson map (_.as[DeliveryAddress])
}
submitted match {
case Left(parsingFailure) => Future.successful(BadRequest(parsingFailure.getMessage))
case Right(None) => Future.successful(BadRequest(s"Not json: ${request.body}"))
case Right(Some(address)) =>
val contactRepository = request.touchpoint.contactRepository
update(contactRepository, contactId, address) map { _ =>
NoContent
} recover { case updateFailure =>
BadGateway(updateFailure.getMessage)
}
}
} else
Future.successful(
BadRequest(
s"Contact $contactId not related to current user ${request.redirectAdvice.userId}",
),
)
}
}
}
private def isContactOwnedByRequester(
request: AuthAndBackendRequest[AnyContent],
contactId: String,
)(implicit logPrefix: LogPrefix): Future[Boolean] = {
val contactRepository = request.touchpoint.contactRepository
request.redirectAdvice.userId match {
case Some(userId) =>
contactRepository.get(userId).map(_.toEither).map {
case Right(Some(contact)) => contact.salesforceContactId == contactId
case _ => false
}
case None => Future.successful(false)
}
}
private def update(
contactRepository: ContactRepository,
contactId: String,
address: DeliveryAddress,
)(implicit logPrefix: LogPrefix): Future[Unit] = {
val contactFields = {
def contactField(name: String, optValue: Option[String]): Map[String, String] =
optValue map { value =>
Map(name -> value.trim)
} getOrElse Map()
val mergedAddressLines = DeliveryAddress.mergeAddressLines(address)
Map() ++
contactField("MailingStreet", mergedAddressLines) ++
contactField("MailingCity", address.town) ++
contactField("MailingState", address.region) ++
contactField("MailingPostalCode", address.postcode) ++
contactField("MailingCountry", address.country) ++
contactField("Delivery_Information__c", address.instructions) ++
contactField("Address_Change_Information_Last_Quoted__c", address.addressChangeInformation)
}
contactRepository.update(contactId, contactFields)
}
}