membership-attribute-service/app/wiring/AppLoader.scala (121 lines of code) (raw):
package wiring
import actions.CommonActions
import ch.qos.logback.classic.LoggerContext
import com.gu.memsub.subsv2.Catalog
import com.gu.memsub.subsv2.services.SubscriptionService
import com.gu.monitoring.SafeLoggerImpl
import com.gu.zuora.ZuoraSoapService
import components.TouchpointBackends
import configuration.{CreateTestUsernames, SentryConfig, Stage}
import controllers._
import filters._
import monitoring.{CreateRealMetrics, ErrorHandler, SentryLogging}
import org.apache.pekko.actor.ActorSystem
import org.slf4j.LoggerFactory
import play.api.ApplicationLoader.Context
import play.api._
import play.api.db.{DBComponents, HikariCPComponents}
import play.api.libs.ws.ahc.AhcWSComponents
import play.api.mvc.EssentialFilter
import play.filters.cors.{CORSConfig, CORSFilter}
import play.filters.csrf.CSRFComponents
import router.Routes
import services.mail.{QueueName, SendEmail, SendEmailToSQS}
import services.salesforce.ContactRepository
import services.stripe.{BasicStripeService, ChooseStripe}
import services.zuora.rest.ZuoraRestService
import services._
import scala.concurrent.{ExecutionContext, Future}
class AppLoader extends ApplicationLoader {
def load(context: Context): Application = {
LoggerConfigurator(context.environment.classLoader).foreach {
_.configure(context.environment)
}
val loggerPackageName = classOf[SafeLoggerImpl].getPackageName
// at the moment we get SafeLogger.scala:49 type things in the logs
// adding to the FrameworkPackages makes logback skip over and find the real line of code
LoggerFactory.getILoggerFactory.asInstanceOf[LoggerContext].getFrameworkPackages.add(loggerPackageName)
val config = context.initialConfiguration.underlying
SentryLogging.init(new SentryConfig(config))
createMyComponents(context).application
}
protected def createMyComponents(context: Context) =
new MyComponents(context)
}
class MyComponents(context: Context)
extends BuiltInComponentsFromContext(context)
with AhcWSComponents
with CSRFComponents
with HikariCPComponents
with DBComponents {
lazy val config = context.initialConfiguration.underlying
lazy val stage = Stage(config.getString("stage"))
lazy val isProd = stage.value == "PROD"
lazy val createMetrics = new CreateRealMetrics(stage)
lazy val supporterProductDataServiceOverride: Option[SupporterProductDataService] = None
lazy val contactRepositoryOverride: Option[ContactRepository] = None
lazy val subscriptionServiceOverride: Option[SubscriptionService[Future]] = None
lazy val zuoraRestServiceOverride: Option[ZuoraRestService] = None
lazy val catalogServiceOverride: Option[Future[Catalog]] = None
lazy val zuoraSoapServiceOverride: Option[ZuoraSoapService with HealthCheckableService] = None
lazy val patronsStripeServiceOverride: Option[BasicStripeService] = None
lazy val chooseStripeOverride: Option[ChooseStripe] = None
lazy val emailQueueName = QueueName(if (isProd) "braze-emails-PROD" else "braze-emails-CODE")
lazy val sendEmail: SendEmail = new SendEmailToSQS(emailQueueName)
lazy val touchPointBackends = new TouchpointBackends(
actorSystem,
config,
createMetrics,
supporterProductDataServiceOverride,
contactRepositoryOverride,
subscriptionServiceOverride,
zuoraRestServiceOverride,
catalogServiceOverride,
zuoraSoapServiceOverride,
patronsStripeServiceOverride,
chooseStripeOverride,
)
private val testUserChecker = new TestUserChecker(CreateTestUsernames.from(config))
private val addGuIdentityHeaders = new AddGuIdentityHeaders(touchPointBackends.normal.identityAuthService, testUserChecker)
lazy val commonActions = new CommonActions(touchPointBackends, defaultBodyParser, testUserChecker)
override lazy val httpErrorHandler: ErrorHandler =
new ErrorHandler(
environment,
configuration,
devContext.map(_.sourceMapper),
Some(router),
touchPointBackends.normal.identityAuthService,
addGuIdentityHeaders,
)
implicit val system: ActorSystem = actorSystem
lazy val dbService: ContributionsStoreDatabaseService = {
val db = dbApi.database("oneOffStore")
val jdbcExecutionContext: ExecutionContext = actorSystem.dispatchers.lookup("contexts.jdbc-context")
PostgresDatabaseService.fromDatabase(db)(jdbcExecutionContext)
}
lazy val mobileSubscriptionService = new MobileSubscriptionServiceImpl(wsClient = wsClient, config)
lazy val router: Routes = new Routes(
httpErrorHandler,
new HealthCheckController(touchPointBackends, controllerComponents),
new AttributeController(commonActions, controllerComponents, dbService, mobileSubscriptionService, addGuIdentityHeaders, createMetrics),
new ExistingPaymentOptionsController(commonActions, controllerComponents, createMetrics),
new AccountController(commonActions, controllerComponents, dbService, sendEmail, createMetrics),
new PaymentUpdateController(commonActions, controllerComponents, sendEmail, createMetrics),
new ContactController(commonActions, controllerComponents, createMetrics),
)
val postPaths: Seq[String] = router.documentation.collect { case ("POST", path, _) => path }
lazy val corsConfig = new CorsConfig(configuration)
override lazy val httpFilters: Seq[EssentialFilter] = Seq(
new CheckCacheHeadersFilter(),
csrfFilter,
new AddEC2InstanceHeader(wsClient),
new AddGuIdentityHeadersFilter(addGuIdentityHeaders),
CORSFilter(corsConfig = corsConfig.mmaUpdateCorsConfig, pathPrefixes = postPaths),
CORSFilter(corsConfig = corsConfig.corsConfig, pathPrefixes = Seq("/user-attributes")),
)
}
class CorsConfig(val configuration: Configuration) {
lazy val corsConfig = CORSConfig.fromConfiguration(configuration)
lazy val mmaUpdateCorsConfig = corsConfig.copy(
isHttpHeaderAllowed = Seq("accept", "content-type", "csrf-token", "origin").contains(_),
isHttpMethodAllowed = Seq("POST", "OPTIONS").contains(_),
)
}