Skip to content

Commit

Permalink
going through merge conflicts
Browse files Browse the repository at this point in the history
  • Loading branch information
jonflynng committed May 9, 2023
2 parents 7849d4c + 2103dce commit 1b7e0ee
Show file tree
Hide file tree
Showing 51 changed files with 435 additions and 330 deletions.
2 changes: 1 addition & 1 deletion build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -534,7 +534,7 @@ lazy val `product-move-api` = lambdaProject(
awsSQS,
scalatest,
"com.softwaremill.sttp.client3" %% "zio-json" % sttpVersion,
"dev.zio" %% "zio-logging-slf4j" % "2.0.1",
"dev.zio" %% "zio-logging-slf4j" % "2.1.12",
"dev.zio" %% "zio-test" % zio2Version % Test,
"dev.zio" %% "zio-test-sbt" % zio2Version % Test,
"com.softwaremill.sttp.tapir" %% "tapir-core" % tapirVersion,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ object Handler extends Logging {

def apply(inputStream: InputStream, outputStream: OutputStream, context: Context): Unit = {
ApiGatewayHandler(LambdaIO(inputStream, outputStream, context))(
ContinueProcessing(Operation.noHealthcheck(steps = handle))
ContinueProcessing(Operation.noHealthcheck(steps = handle)),
)
}

Expand Down
24 changes: 0 additions & 24 deletions handlers/product-move-api/cfn.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -344,28 +344,4 @@ Resources:
Period: 60
Statistic: Sum
Threshold: 1
TreatMissingData: notBreaching

4xxApiAlarm:
Type: AWS::CloudWatch::Alarm
Condition: IsProd
DependsOn:
- ProductMoveApiGateway
Properties:
AlarmActions:
- !Sub arn:aws:sns:${AWS::Region}:${AWS::AccountId}:retention-dev
AlarmName: !Sub The product-move-api returned multiple 4xx responses
AlarmDescription: Check the logs for details - https://eu-west-1.console.aws.amazon.com/cloudwatch/home?region=eu-west-1#logsV2:log-groups/log-group/$252Faws$252Flambda$252Fmove-product-PROD
ComparisonOperator: GreaterThanThreshold
Dimensions:
- Name: ApiName
Value: !Sub product-move-api-${Stage}-ApiGateway
- Name: Stage
Value: !Sub ${Stage}
EvaluationPeriods: 1
MetricName: 4XXError
Namespace: AWS/ApiGateway
Period: 3600
Statistic: Sum
Threshold: 3
TreatMissingData: notBreaching
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.gu.productmove

import com.gu.productmove
import com.gu.productmove.endpoint.move.ProductMoveEndpointTypes.{ErrorResponse, InternalServerError}
import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider
import software.amazon.awssdk.regions.Region
import software.amazon.awssdk.services.s3.S3Client
Expand Down Expand Up @@ -28,25 +29,27 @@ object AwsS3Live {

private class AwsS3Live(s3Client: S3Client) extends AwsS3:

override def getObject(bucket: String, key: String): Task[String] =
ZIO.attempt {
val objectRequest: GetObjectRequest = GetObjectRequest
.builder()
.key(key)
.bucket(bucket)
.build();
val response = s3Client.getObjectAsBytes(objectRequest)
response.asUtf8String()
}
override def getObject(bucket: String, key: String): ZIO[Any, ErrorResponse, String] =
ZIO
.attempt {
val objectRequest: GetObjectRequest = GetObjectRequest
.builder()
.key(key)
.bucket(bucket)
.build();
val response = s3Client.getObjectAsBytes(objectRequest)
response.asUtf8String()
}
.mapError(e => InternalServerError(e.toString))

trait AwsS3 {

def getObject(bucket: String, key: String): Task[String]
def getObject(bucket: String, key: String): ZIO[Any, ErrorResponse, String]

}
object AwsS3 {

def getObject(bucket: String, key: String): RIO[AwsS3, String] =
def getObject(bucket: String, key: String): ZIO[AwsS3, ErrorResponse, String] =
ZIO.environmentWithZIO[AwsS3](_.get.getObject(bucket, key))

}
Original file line number Diff line number Diff line change
@@ -1,20 +1,22 @@
package com.gu.productmove

import com.gu.productmove.GuStageLive.Stage
import com.gu.productmove.endpoint.move.ProductMoveEndpointTypes.{ErrorResponse, InternalServerError}
import com.gu.supporterdata.model.Stage.{DEV, PROD, UAT}
import com.gu.supporterdata.model.{SupporterRatePlanItem}
import com.gu.supporterdata.model.SupporterRatePlanItem
import com.gu.supporterdata.services.SupporterDataDynamoService

import java.time.LocalDate
import scala.concurrent.ExecutionContext.Implicits.global
import zio.*
import zio.json.*

trait Dynamo {
def writeItem(item: SupporterRatePlanItem): ZIO[Any, String, Unit]
def writeItem(item: SupporterRatePlanItem): ZIO[Any, ErrorResponse, Unit]
}

object Dynamo {
def writeItem(item: SupporterRatePlanItem): ZIO[Dynamo, String, Unit] = {
def writeItem(item: SupporterRatePlanItem): ZIO[Dynamo, ErrorResponse, Unit] = {
ZIO.environmentWithZIO(_.get.writeItem(item))
}
}
Expand All @@ -27,19 +29,19 @@ object DynamoLive {
case Stage.PROD => PROD
}

val layer: ZLayer[Stage, String, Dynamo] =
val layer: ZLayer[Stage, ErrorResponse, Dynamo] =
ZLayer.scoped {
ZIO.service[Stage].map { stage =>
val dynamoService = SupporterDataDynamoService(getStage(stage))

new Dynamo {
override def writeItem(item: SupporterRatePlanItem): ZIO[Any, String, Unit] =
override def writeItem(item: SupporterRatePlanItem): ZIO[Any, ErrorResponse, Unit] =
ZIO
.fromFuture {
dynamoService.writeItem(item)
}
.mapError { ex =>
s"Failed to write to the Supporter Data Dynamo table for identityId: ${item.identityId} with subscription Number: ${item.subscriptionName} with error: ${ex.toString}"
InternalServerError(s"Failed to write to the Supporter Data Dynamo table for identityId: ${item.identityId} with subscription Number: ${item.subscriptionName} with error: ${ex.toString}")
}
.flatMap { _ =>
ZIO.log(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package com.gu.productmove

import com.gu.effects.sqs.AwsSQSSend.EmailQueueName
import com.gu.productmove.GuStageLive.Stage
import com.gu.productmove.endpoint.move.ProductMoveEndpointTypes.{ErrorResponse, InternalServerError}
import com.gu.productmove.refund.RefundInput
import com.gu.productmove.salesforce.Salesforce.SalesforceRecordInput
import com.gu.productmove.zuora.GetAccount.{BillToContact, GetAccountResponse}
Expand All @@ -19,38 +20,40 @@ import java.time.LocalDate
import java.time.format.DateTimeFormatter

trait SQS {
def sendEmail(message: EmailMessage): ZIO[Any, String, Unit]
def sendEmail(message: EmailMessage): ZIO[Any, ErrorResponse, Unit]

def queueRefund(refundInput: RefundInput): ZIO[Any, String, Unit]
def queueRefund(refundInput: RefundInput): ZIO[Any, ErrorResponse, Unit]

def queueSalesforceTracking(salesforceRecordInput: SalesforceRecordInput): ZIO[Any, String, Unit]
def queueSalesforceTracking(salesforceRecordInput: SalesforceRecordInput): ZIO[Any, ErrorResponse, Unit]
}

object SQS {
def sendEmail(message: EmailMessage): ZIO[SQS, String, Unit] = {
def sendEmail(message: EmailMessage): ZIO[SQS, ErrorResponse, Unit] = {
ZIO.environmentWithZIO(_.get.sendEmail(message))
}

def queueRefund(refundInput: RefundInput): ZIO[SQS, String, Unit] = {
def queueRefund(refundInput: RefundInput): ZIO[SQS, ErrorResponse, Unit] = {
ZIO.environmentWithZIO(_.get.queueRefund(refundInput))
}

def queueSalesforceTracking(salesforceRecordInput: SalesforceRecordInput): ZIO[SQS, String, Unit] = {
def queueSalesforceTracking(salesforceRecordInput: SalesforceRecordInput): ZIO[SQS, ErrorResponse, Unit] = {
ZIO.environmentWithZIO(_.get.queueSalesforceTracking(salesforceRecordInput))
}
}

object SQSLive {
val layer: ZLayer[AwsCredentialsProvider with Stage, String, SQS] =
val layer: ZLayer[AwsCredentialsProvider with Stage, ErrorResponse, SQS] =
ZLayer.scoped(for {
stage <- ZIO.service[Stage]
sqsClient <- initializeSQSClient().mapError(ex => s"Failed to initialize SQS Client with error: $ex")
sqsClient <- initializeSQSClient().mapError(ex =>
InternalServerError(s"Failed to initialize SQS Client with error: $ex"),
)
emailQueueName = EmailQueueName.value
emailQueueUrlResponse <- getQueue(emailQueueName, sqsClient)
refundQueueUrlResponse <- getQueue(s"product-switch-refund-${stage.toString}", sqsClient)
salesforceTrackingQueueUrlResponse <- getQueue(s"product-switch-salesforce-tracking-${stage.toString}", sqsClient)
} yield new SQS {
override def sendEmail(message: EmailMessage): ZIO[Any, String, Unit] =
override def sendEmail(message: EmailMessage): ZIO[Any, ErrorResponse, Unit] =
for {
_ <- ZIO
.fromCompletableFuture {
Expand All @@ -64,9 +67,13 @@ object SQSLive {
.mapError { ex =>
message.To.ContactAttributes.SubscriberAttributes match {
case attributes: EmailPayloadProductSwitchAttributes =>
s"Failed to send product switch email message to SQS for sfContactId: ${message.SfContactId} with subscription Number: ${attributes.subscription_id} with error: ${ex.toString} to SQS queue $emailQueueName"
InternalServerError(
s"Failed to send product switch email message to SQS for sfContactId: ${message.SfContactId} with subscription Number: ${attributes.subscription_id} with error: ${ex.toString} to SQS queue $emailQueueName",
)
case attributes: EmailPayloadCancellationAttributes =>
s"Failed to send subscription cancellation email message to SQS for sfContactId: ${message.SfContactId} with error: ${ex.toString} to SQS queue $emailQueueName"
InternalServerError(
s"Failed to send subscription cancellation email message to SQS for sfContactId: ${message.SfContactId} with error: ${ex.toString} to SQS queue $emailQueueName",
)
}
}
_ <- ZIO.log(
Expand All @@ -79,7 +86,7 @@ object SQSLive {
)
} yield ()

override def queueRefund(refundInput: RefundInput): ZIO[Any, String, Unit] =
override def queueRefund(refundInput: RefundInput): ZIO[Any, ErrorResponse, Unit] =
for {
_ <- ZIO
.fromCompletableFuture {
Expand All @@ -91,14 +98,18 @@ object SQSLive {
)
}
.mapError { ex =>
s"Failed to send sqs refund message with subscription Number: ${refundInput.subscriptionName} with error: ${ex.toString}"
InternalServerError(
s"Failed to send sqs refund message with subscription Number: ${refundInput.subscriptionName} with error: ${ex.toString}",
)
}
_ <- ZIO.log(
s"Successfully sent refund message for subscription number: ${refundInput.subscriptionName}",
)
} yield ()

override def queueSalesforceTracking(salesforceRecordInput: SalesforceRecordInput): ZIO[Any, String, Unit] =
override def queueSalesforceTracking(
salesforceRecordInput: SalesforceRecordInput,
): ZIO[Any, ErrorResponse, Unit] =
for {
_ <- ZIO
.fromCompletableFuture {
Expand All @@ -110,7 +121,9 @@ object SQSLive {
)
}
.mapError { ex =>
s"Failed to send sqs salesforce tracking message with subscription Number: ${salesforceRecordInput.subscriptionName} with error: ${ex.toString}"
InternalServerError(
s"Failed to send sqs salesforce tracking message with subscription Number: ${salesforceRecordInput.subscriptionName} with error: ${ex.toString}",
)
}
_ <- ZIO.log(
s"Successfully sent salesforce tracking message for subscription number: ${salesforceRecordInput.subscriptionName}",
Expand All @@ -124,14 +137,17 @@ object SQSLive {
sqsClient <- ZIO.fromAutoCloseable(ZIO.attempt(impl(creds)))
} yield sqsClient

private def getQueue(queueName: String, sqsAsyncClient: SqsAsyncClient): ZIO[Any, String, GetQueueUrlResponse] =
private def getQueue(
queueName: String,
sqsAsyncClient: SqsAsyncClient,
): ZIO[Any, ErrorResponse, GetQueueUrlResponse] =
val queueUrl = GetQueueUrlRequest.builder.queueName(queueName).build()

ZIO
.fromCompletableFuture(
sqsAsyncClient.getQueueUrl(queueUrl),
)
.mapError { ex => s"Failed to get sqs queue name: $queueName, error: ${ex.getMessage}" }
.mapError { ex => InternalServerError(s"Failed to get sqs queue name: $queueName, error: ${ex.getMessage}") }

private def impl(creds: AwsCredentialsProvider): SqsAsyncClient =
SqsAsyncClient.builder
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ package com.gu.productmove

import com.gu.newproduct.api.productcatalog.{Annual, BillingPeriod, Monthly}
import zio.{IO, ZIO}
import com.gu.productmove.endpoint.move.ProductMoveEndpointTypes.{ErrorResponse, InternalServerError}

object Util {
def getFromEnv(prop: String): Either[String, String] = {
sys.env.get(prop).toRight(s"Could not obtain $prop")
}
def getFromEnv(prop: String): Either[ErrorResponse, String] =
sys.env.get(prop).toRight(InternalServerError(s"Could not obtain $prop"))
}
Loading

0 comments on commit 1b7e0ee

Please sign in to comment.