From 8d8fbe21bd58b0d1aa8cd653a0b3e8fcff2f86fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Manciot?= Date: Wed, 22 Nov 2023 18:09:14 +0100 Subject: [PATCH 01/37] add SoftPayment accounts, migrate PaymentProvider architecture to SPI, add Client within model, upgrade Session handling using SessionMaterials --- common/build.sbt | 4 + .../protobuf/message/payment/client.proto | 36 ++++ .../main/protobuf/model/payment/address.proto | 1 + .../main/protobuf/model/payment/client.proto | 84 ++++++++ .../protobuf/model/payment/paymentUser.proto | 1 + .../payment/message/AccountMessages.scala | 37 ++++ .../payment/message/PaymentMessages.scala | 126 ++++++++++-- .../payment/model/AddressDecorator.scala | 13 +- .../model/SoftPaymentAccountCompanion.scala | 15 ++ .../model/SoftPaymentAccountDecorator.scala | 10 + .../model/SoftPaymentClientDecorator.scala | 44 +++++ .../payment/serialization/package.scala | 37 +++- .../payment/spi/PaymentProvider.scala | 4 + .../payment/spi/PaymentProviderSpi.scala | 10 + .../payment/spi/PaymentProviders.scala | 40 ++++ core/build.sbt | 1 + .../handlers/SoftPaymentAccountDao.scala | 46 +++++ .../payment/launch/PaymentGuardian.scala | 10 +- .../typed/GenericPaymentBehavior.scala | 106 +++++++++- .../typed/SoftPaymentAccountBehavior.scala | 172 +++++++++++++++++ .../service/GenericPaymentEndpoints.scala | 3 +- .../service/GenericPaymentService.scala | 27 +-- .../service/RootPaymentEndpoints.scala | 14 +- .../softnetwork/payment/api/MangoPayApi.scala | 17 +- .../payment/api/MangoPayRoutes.scala | 18 +- ...softnetwork.payment.spi.PaymentProviderSpi | 1 + mangopay/src/main/resources/reference.conf | 4 +- .../softnetwork/payment/config/MangoPay.scala | 20 +- .../typed/MangoPayPaymentBehavior.scala | 7 +- .../service/MangoPayPaymentEndpoints.scala | 18 +- .../service/MangoPayPaymentService.scala | 15 +- .../payment/spi/MangoPayProvider.scala | 182 +++++++++++------- project/Versions.scala | 6 +- testkit/build.sbt | 1 + ...softnetwork.payment.spi.PaymentProviderSpi | 1 + .../handlers/MockSoftPaymentAccountDao.scala | 22 +++ .../typed/MockPaymentBehavior.scala | 18 +- .../MockSoftPaymentAccountBehavior.scala | 7 + .../scalatest/PaymentEndpointsTestKit.scala | 32 ++- .../scalatest/PaymentRouteTestKit.scala | 3 +- .../scalatest/PaymentRoutesTestKit.scala | 25 ++- .../payment/scalatest/PaymentTestKit.scala | 46 ++--- .../service/MockPaymentEndpoints.scala | 31 +-- .../payment/service/MockPaymentService.scala | 16 +- .../payment/spi/MockMangoPayProvider.scala | 18 ++ .../payment/handlers/PaymentHandlerSpec.scala | 13 +- ...EndpointsWithOneOffCookieSessionSpec.scala | 2 + ...EndpointsWithOneOffHeaderSessionSpec.scala | 2 + ...intsWithRefreshableCookieSessionSpec.scala | 2 + ...intsWithRefreshableHeaderSessionSpec.scala | 2 + ...entRoutesWithOneOffCookieSessionSpec.scala | 2 + ...entRoutesWithOneOffHeaderSessionSpec.scala | 2 + ...utesWithRefreshableCookieSessionSpec.scala | 2 + ...utesWithRefreshableHeaderSessionSpec.scala | 2 + .../payment/service/PaymentServiceSpec.scala | 4 +- 55 files changed, 1138 insertions(+), 244 deletions(-) create mode 100644 common/src/main/protobuf/message/payment/client.proto create mode 100644 common/src/main/protobuf/model/payment/client.proto create mode 100644 common/src/main/scala/app/softnetwork/payment/message/AccountMessages.scala create mode 100644 common/src/main/scala/app/softnetwork/payment/model/SoftPaymentAccountCompanion.scala create mode 100644 common/src/main/scala/app/softnetwork/payment/model/SoftPaymentAccountDecorator.scala create mode 100644 common/src/main/scala/app/softnetwork/payment/model/SoftPaymentClientDecorator.scala create mode 100644 common/src/main/scala/app/softnetwork/payment/spi/PaymentProviderSpi.scala create mode 100644 common/src/main/scala/app/softnetwork/payment/spi/PaymentProviders.scala create mode 100644 core/src/main/scala/app/softnetwork/payment/handlers/SoftPaymentAccountDao.scala create mode 100644 core/src/main/scala/app/softnetwork/payment/persistence/typed/SoftPaymentAccountBehavior.scala create mode 100644 mangopay/src/main/resources/META-INF/services/app.softnetwork.payment.spi.PaymentProviderSpi create mode 100644 testkit/src/main/resources/META-INF/services/app.softnetwork.payment.spi.PaymentProviderSpi create mode 100644 testkit/src/main/scala/app/softnetwork/payment/handlers/MockSoftPaymentAccountDao.scala create mode 100644 testkit/src/main/scala/app/softnetwork/payment/persistence/typed/MockSoftPaymentAccountBehavior.scala diff --git a/common/build.sbt b/common/build.sbt index c1d2ff5..9a0d86c 100644 --- a/common/build.sbt +++ b/common/build.sbt @@ -4,8 +4,12 @@ name := "payment-common" libraryDependencies ++= Seq( "app.softnetwork.persistence" %% "persistence-kv" % Versions.genericPersistence, + // scheduler "app.softnetwork.scheduler" %% "scheduler-common" % Versions.scheduler, "app.softnetwork.scheduler" %% "scheduler-common" % Versions.scheduler % "protobuf", + // account + "app.softnetwork.account" %% "account-common" % Versions.account, + "app.softnetwork.account" %% "account-common" % Versions.account % "protobuf", "app.softnetwork.api" %% "generic-server-api" % Versions.genericPersistence, "app.softnetwork.protobuf" %% "scalapb-extensions" % "0.1.7", "commons-validator" % "commons-validator" % "1.6" diff --git a/common/src/main/protobuf/message/payment/client.proto b/common/src/main/protobuf/message/payment/client.proto new file mode 100644 index 0000000..9db1306 --- /dev/null +++ b/common/src/main/protobuf/message/payment/client.proto @@ -0,0 +1,36 @@ +syntax = "proto2"; + +import "scalapb/scalapb.proto"; +import "google/protobuf/timestamp.proto"; +import "model/payment/client.proto"; + +package app.softnetwork.payment.message.SoftPaymentAccountEvents; + +option (scalapb.options) = { + single_file: true + flat_package: true + import: "app.softnetwork.persistence.message._" + import: "app.softnetwork.persistence.model._" + import: "app.softnetwork.protobuf.ScalaPBTypeMappers._" + import: "app.softnetwork.serialization._" + import: "app.softnetwork.account.message._" + import: "app.softnetwork.payment.model._" + import: "app.softnetwork.payment.message.SoftPaymentAccountEvents._" + import: "app.softnetwork.payment.serialization._" + preserve_unknown_fields: false + preamble: "sealed trait SoftPaymentAccountEvent extends AccountEvent" +}; + +message SoftPaymentAccountCreatedEvent { + option (scalapb.message).extends = "ProtobufEvent"; + option (scalapb.message).extends = "SoftPaymentAccountEvent"; + option (scalapb.message).extends = "AccountCreatedEvent[SoftPaymentAccount]"; + required app.softnetwork.payment.model.SoftPaymentAccount document = 1; +} + +message SoftPaymentAccountProviderRegisteredEvent { + option (scalapb.message).extends = "ProtobufEvent"; + option (scalapb.message).extends = "SoftPaymentAccountEvent"; + required app.softnetwork.payment.model.SoftPaymentAccount.Client client = 1; + required google.protobuf.Timestamp lastUpdated = 2 [(scalapb.field).type = "java.time.Instant"]; +} diff --git a/common/src/main/protobuf/model/payment/address.proto b/common/src/main/protobuf/model/payment/address.proto index a251150..14bc45a 100644 --- a/common/src/main/protobuf/model/payment/address.proto +++ b/common/src/main/protobuf/model/payment/address.proto @@ -22,4 +22,5 @@ message Address { required string city = 2; required string postalCode = 3; required string country = 4 [default = "FR"]; + optional string state = 5; } diff --git a/common/src/main/protobuf/model/payment/client.proto b/common/src/main/protobuf/model/payment/client.proto new file mode 100644 index 0000000..343082a --- /dev/null +++ b/common/src/main/protobuf/model/payment/client.proto @@ -0,0 +1,84 @@ +syntax = "proto2"; + +import "scalapb/scalapb.proto"; +import "model/accountStatus.proto"; +import "model/auth.proto"; +import "model/payment/address.proto"; +import "google/protobuf/timestamp.proto"; + +package app.softnetwork.payment.model; + +option (scalapb.options) = { + single_file: true + flat_package: true + import: "app.softnetwork.persistence.message._" + import: "app.softnetwork.persistence.model._" + import: "app.softnetwork.account.model._" + import: "app.softnetwork.account.serialization._" + import: "app.softnetwork.protobuf.ScalaPBTypeMappers._" + import: "Protobuf._" + preserve_unknown_fields: false +}; + +message SoftPaymentAccount { + + message Client { + + message Provider { + + enum ProviderType{ + MOCK = -1; + MANGOPAY = 0; + STRIPE = 1; + } + + required string providerId = 1; + required string providerApiKey = 2; + required ProviderType providerType = 3 [default = MANGOPAY]; + + } + + option (scalapb.message).extends = "SoftPaymentClientDecorator"; + + required Provider provider = 1; + required string clientId = 2; + optional string clientApiKey = 3; + optional string name = 4; + optional string description = 5; + optional string logoUrl = 6; + optional string websiteUrl = 7; + repeated string technicalEmails = 8; + repeated string administrativeEmails = 9; + repeated string billingEmails = 10; + repeated string fraudEmails = 11; + optional string vatNumber = 12; + optional Address address = 13; + } + + option (scalapb.message).extends = "ProtobufDomainObject"; + option (scalapb.message).extends = "Account"; + option (scalapb.message).extends = "Timestamped"; + option (scalapb.message).extends = "SoftPaymentAccountDecorator"; + option (scalapb.message).companion_extends = "SoftPaymentAccountCompanion"; + required string uuid = 1; + required google.protobuf.Timestamp createdDate = 2 [(scalapb.field).type = "java.time.Instant"]; + required google.protobuf.Timestamp lastUpdated = 3 [(scalapb.field).type = "java.time.Instant"]; + required app.softnetwork.account.model.Principal principal = 4; + repeated app.softnetwork.account.model.Principal secondaryPrincipals = 6; + optional app.softnetwork.account.model.BasicAccountProfile currentProfile = 7 [(scalapb.field).type = "Profile"]; + map profiles = 8 [(scalapb.field).value_type = "Profile"]; + required string credentials = 9; + optional google.protobuf.Timestamp lastLogin = 10 [(scalapb.field).type = "java.time.Instant"]; + required int32 nbLoginFailures = 11 [default = 0]; + required app.softnetwork.account.model.AccountStatus status = 12 [default = Inactive]; + optional app.softnetwork.account.model.VerificationToken verificationToken = 13; + optional app.softnetwork.account.model.VerificationCode verificationCode = 14; + optional app.softnetwork.account.model.BasicAccountDetails details = 15 [(scalapb.field).type = "AccountDetails"]; + repeated app.softnetwork.account.model.DeviceRegistration registrations = 16; + optional google.protobuf.Timestamp lastLogout = 17 [(scalapb.field).type = "java.time.Instant"]; + optional bool anonymous = 18; + optional bool fromAnonymous = 19; + repeated app.softnetwork.account.model.Application applications = 20; + + optional Client client = 21; +} \ No newline at end of file diff --git a/common/src/main/protobuf/model/payment/paymentUser.proto b/common/src/main/protobuf/model/payment/paymentUser.proto index 6e61898..c302bc1 100644 --- a/common/src/main/protobuf/model/payment/paymentUser.proto +++ b/common/src/main/protobuf/model/payment/paymentUser.proto @@ -123,6 +123,7 @@ message PaymentAccount { required PaymentAccountStatus paymentAccountStatus = 9 [default = DOCUMENTS_KO]; repeated Transaction transactions = 10; repeated RecurringPayment recurryingPayments = 11; + optional string clientId = 12; } message MandateResult{ diff --git a/common/src/main/scala/app/softnetwork/payment/message/AccountMessages.scala b/common/src/main/scala/app/softnetwork/payment/message/AccountMessages.scala new file mode 100644 index 0000000..8915d66 --- /dev/null +++ b/common/src/main/scala/app/softnetwork/payment/message/AccountMessages.scala @@ -0,0 +1,37 @@ +package app.softnetwork.payment.message + +import app.softnetwork.account.message.{ + AccountCommand, + AccountCommandResult, + AccountErrorMessage, + SignUp +} +import app.softnetwork.account.model.BasicAccountProfile +import app.softnetwork.payment.annotation.InternalApi +import app.softnetwork.payment.model.SoftPaymentAccount + +object AccountMessages { + case class SoftPaymentSignup( + login: String, + password: String, + provider: SoftPaymentAccount.Client.Provider, + override val confirmPassword: Option[String] = None, + override val profile: Option[BasicAccountProfile] = None + ) extends SignUp + + case class RegisterProvider(provider: SoftPaymentAccount.Client.Provider) extends AccountCommand + + @InternalApi + private[payment] case class LoadProvider(clientId: String) extends AccountCommand + + case class ProviderRegistered(client: SoftPaymentAccount.Client) extends AccountCommandResult + + case class ProviderLoaded(provider: SoftPaymentAccount.Client.Provider) + extends AccountCommandResult + + case object ProviderAlreadyRegistered extends AccountErrorMessage("provider.already.registered") + + case object ProviderNotRegistered extends AccountErrorMessage("provider.not.registered") + + case object ProviderNotFound extends AccountErrorMessage("provider.not.found") +} diff --git a/common/src/main/scala/app/softnetwork/payment/message/PaymentMessages.scala b/common/src/main/scala/app/softnetwork/payment/message/PaymentMessages.scala index ae2e1b4..ad4c243 100644 --- a/common/src/main/scala/app/softnetwork/payment/message/PaymentMessages.scala +++ b/common/src/main/scala/app/softnetwork/payment/message/PaymentMessages.scala @@ -27,9 +27,15 @@ object PaymentMessages { * - payment user * @param currency * - currency + * @param clientId + * - optional client id */ - case class PreRegisterCard(orderUuid: String, user: PaymentUser, currency: String = "EUR") - extends PaymentCommandWithKey { + case class PreRegisterCard( + orderUuid: String, + user: PaymentUser, + currency: String = "EUR", + clientId: Option[String] = None + ) extends PaymentCommandWithKey { val key: String = user.externalUuidWithProfile } @@ -141,8 +147,10 @@ object PaymentMessages { * @param cardPreAuthorizedTransactionId * - card pre authorized transaction id */ - case class CancelPreAuthorization(orderUuid: String, cardPreAuthorizedTransactionId: String) - extends PaymentCommandWithKey { + case class CancelPreAuthorization( + orderUuid: String, + cardPreAuthorizedTransactionId: String + ) extends PaymentCommandWithKey { lazy val key: String = cardPreAuthorizedTransactionId } @@ -151,8 +159,10 @@ object PaymentMessages { * @param cardPreAuthorizedTransactionId * - card pre authorized transaction id */ - case class ValidatePreAuthorization(orderUuid: String, cardPreAuthorizedTransactionId: String) - extends PaymentCommandWithKey { + case class ValidatePreAuthorization( + orderUuid: String, + cardPreAuthorizedTransactionId: String + ) extends PaymentCommandWithKey { lazy val key: String = cardPreAuthorizedTransactionId } @@ -259,6 +269,19 @@ object PaymentMessages { lazy val key: String = transactionId } + /** @param orderUuid + * - order uuid + * @param creditedAccount + * - account to credit + * @param creditedAmount + * - credited amount + * @param feesAmount + * - fees amount + * @param currency + * - currency + * @param externalReference + * - optional external reference + */ case class PayOut( orderUuid: String, creditedAccount: String, @@ -270,6 +293,19 @@ object PaymentMessages { val key: String = creditedAccount } + /** @param orderUuid + * - order uuid + * @param payInTransactionId + * - payIn transaction id + * @param refundAmount + * - refund amount + * @param currency + * - currency + * @param reasonMessage + * - reason message + * @param initializedByClient + * - whether the refund is initialized by the client or not + */ case class Refund( orderUuid: String, payInTransactionId: String, @@ -448,6 +484,8 @@ object PaymentMessages { * - next debited amount * @param nextFeesAmount * - next fees amount + * @param statementDescriptor + * - statement descriptor */ case class PayNextRecurring( recurringPaymentRegistrationId: String, @@ -475,6 +513,9 @@ object PaymentMessages { lazy val key: String = account } + /** @param transactionId + * - transaction id + */ case class LoadTransaction(transactionId: String) extends PaymentCommandWithKey { lazy val key: String = transactionId } @@ -502,34 +543,70 @@ object PaymentMessages { ): BankAccountCommand = BankAccountCommand(bankAccount, Right(legalUser), acceptedTermsOfPSP) } + /** @param creditedAccount + * - account to credit + * @param bankAccount + * - bank account + * @param user + * - payment user + * @param acceptedTermsOfPSP + * - whether or not the terms of the psp are accepted + * @param clientId + * - optional client id + */ case class CreateOrUpdateBankAccount( creditedAccount: String, bankAccount: BankAccount, user: Option[PaymentAccount.User] = None, - acceptedTermsOfPSP: Option[Boolean] = None + acceptedTermsOfPSP: Option[Boolean] = None, + clientId: Option[String] = None ) extends PaymentCommandWithKey { val key: String = creditedAccount } + /** @param creditedAccount + * - account to load + */ case class LoadBankAccount(creditedAccount: String) extends PaymentCommandWithKey { val key: String = creditedAccount } - case class DeleteBankAccount(creditedAccount: String, force: Option[Boolean]) - extends PaymentCommandWithKey { + /** @param creditedAccount + * - account to delete + * @param force + * - whether or not the bank account should be deleted even if the bank account deletion has + * been disabled + */ + case class DeleteBankAccount( + creditedAccount: String, + force: Option[Boolean] + ) extends PaymentCommandWithKey { val key: String = creditedAccount } + /** @param debitedAccount + * - account owning the cards to load + */ case class LoadCards(debitedAccount: String) extends PaymentCommandWithKey { val key: String = debitedAccount } + /** @param debitedAccount + * - account owning the card to disable + * @param cardId + * - card id + */ case class DisableCard(debitedAccount: String, cardId: String) extends PaymentCommandWithKey { val key: String = debitedAccount } /** Commands related to the kyc documents */ + /** @param creditedAccount + * - account to whom the KYC document would be added + * @param pages + * - pages of the KYC document + */ case class AddKycDocument( creditedAccount: String, pages: Seq[Array[Byte]], @@ -553,6 +630,11 @@ object PaymentMessages { lazy val key: String = kycDocumentId } + /** @param creditedAccount + * - account which owns the KYC document that would be loaded + * @param kycDocumentType + * - KYC document type + */ case class LoadKycDocumentStatus( creditedAccount: String, kycDocumentType: KycDocument.KycDocumentType @@ -562,15 +644,28 @@ object PaymentMessages { /** Commands related to the ubo declaration */ - case class CreateOrUpdateUbo(creditedAccount: String, ubo: UboDeclaration.UltimateBeneficialOwner) - extends PaymentCommandWithKey { + /** @param creditedAccount + * - account to whom the UBO declaration would be added + * @param ubo + * - ultimate beneficial owner + */ + case class CreateOrUpdateUbo( + creditedAccount: String, + ubo: UboDeclaration.UltimateBeneficialOwner + ) extends PaymentCommandWithKey { val key: String = creditedAccount } + /** @param creditedAccount + * - account which owns the UBO declaration that would be validated + */ case class ValidateUboDeclaration(creditedAccount: String) extends PaymentCommandWithKey { val key: String = creditedAccount } + /** @param creditedAccount + * - account which owns the UBO declaration that would be loaded + */ case class GetUboDeclaration(creditedAccount: String) extends PaymentCommandWithKey { val key: String = creditedAccount } @@ -592,10 +687,16 @@ object PaymentMessages { /** Commands related to the mandate */ + /** @param creditedAccount + * - account to whom the mandate would be added + */ case class CreateMandate(creditedAccount: String) extends PaymentCommandWithKey { val key: String = creditedAccount } + /** @param creditedAccount + * - account which owns the mandate that would be canceled + */ case class CancelMandate(creditedAccount: String) extends PaymentCommandWithKey { val key: String = creditedAccount } @@ -635,6 +736,9 @@ object PaymentMessages { lazy val key: String = userId } + /** @param paymentAccount + * - payment account + */ @InternalApi private[payment] case class CreateOrUpdatePaymentAccount(paymentAccount: PaymentAccount) extends PaymentCommandWithKey { diff --git a/common/src/main/scala/app/softnetwork/payment/model/AddressDecorator.scala b/common/src/main/scala/app/softnetwork/payment/model/AddressDecorator.scala index cf6e1b2..62b9dd3 100644 --- a/common/src/main/scala/app/softnetwork/payment/model/AddressDecorator.scala +++ b/common/src/main/scala/app/softnetwork/payment/model/AddressDecorator.scala @@ -17,7 +17,8 @@ trait AddressDecorator { self: Address => address.addressLine.equals(addressLine) && address.city.equals(city) && address.country.equals(country) && - address.postalCode.equals(postalCode) + address.postalCode.equals(postalCode) && + address.state.getOrElse("").equals(state.getOrElse("")) case _ => super.equals(obj) } @@ -25,11 +26,17 @@ trait AddressDecorator { self: Address => new Locale(language, country.toUpperCase).getDisplayCountry } -case class AddressView(addressLine: String, city: String, postalCode: String, country: String) +case class AddressView( + addressLine: String, + city: String, + postalCode: String, + country: String, + state: Option[String] +) object AddressView { def apply(address: Address): AddressView = { import address._ - AddressView(addressLine, city, postalCode, country) + AddressView(addressLine, city, postalCode, country, state) } } diff --git a/common/src/main/scala/app/softnetwork/payment/model/SoftPaymentAccountCompanion.scala b/common/src/main/scala/app/softnetwork/payment/model/SoftPaymentAccountCompanion.scala new file mode 100644 index 0000000..d0d3b4b --- /dev/null +++ b/common/src/main/scala/app/softnetwork/payment/model/SoftPaymentAccountCompanion.scala @@ -0,0 +1,15 @@ +package app.softnetwork.payment.model + +import app.softnetwork.account.model.{BasicAccount, BasicAccountCompanion} +import app.softnetwork.payment.serialization._ + +trait SoftPaymentAccountCompanion extends BasicAccountCompanion { + + def apply(account: Option[BasicAccount]): Option[SoftPaymentAccount] = { + account match { + case Some(a) => Some(a) + case _ => None + } + } + +} diff --git a/common/src/main/scala/app/softnetwork/payment/model/SoftPaymentAccountDecorator.scala b/common/src/main/scala/app/softnetwork/payment/model/SoftPaymentAccountDecorator.scala new file mode 100644 index 0000000..3d46a59 --- /dev/null +++ b/common/src/main/scala/app/softnetwork/payment/model/SoftPaymentAccountDecorator.scala @@ -0,0 +1,10 @@ +package app.softnetwork.payment.model + +import app.softnetwork.account.model.{BasicAccountProfile, Profile} + +trait SoftPaymentAccountDecorator { _: SoftPaymentAccount => + + override def newProfile(name: String): Profile = + BasicAccountProfile.defaultInstance.withName(name) + +} diff --git a/common/src/main/scala/app/softnetwork/payment/model/SoftPaymentClientDecorator.scala b/common/src/main/scala/app/softnetwork/payment/model/SoftPaymentClientDecorator.scala new file mode 100644 index 0000000..37fe167 --- /dev/null +++ b/common/src/main/scala/app/softnetwork/payment/model/SoftPaymentClientDecorator.scala @@ -0,0 +1,44 @@ +package app.softnetwork.payment.model + +import app.softnetwork.account.model.BearerTokenGenerator + +trait SoftPaymentClientDecorator { _: SoftPaymentAccount.Client => + + def generateApiKey(): String = BearerTokenGenerator.generateSHAToken(clientId) + +} + +case class SoftPaymentClientView( + clientId: String, + clientApiKey: Option[String] = None, + name: Option[String] = None, + description: Option[String] = None, + websiteUrl: Option[String] = None, + logoUrl: Option[String] = None, + technicalEmails: Seq[String] = Seq.empty, + administrativeEmails: Seq[String] = Seq.empty, + billingEmails: Seq[String] = Seq.empty, + fraudEmails: Seq[String] = Seq.empty, + vatNumber: Option[String] = None, + address: Option[AddressView] = None +) + +object SoftPaymentClientView { + def apply(client: SoftPaymentAccount.Client): SoftPaymentClientView = { + import client._ + SoftPaymentClientView( + clientId, + clientApiKey, + name, + description, + websiteUrl, + logoUrl, + technicalEmails, + administrativeEmails, + billingEmails, + fraudEmails, + vatNumber, + address.map(AddressView(_)) + ) + } +} diff --git a/common/src/main/scala/app/softnetwork/payment/serialization/package.scala b/common/src/main/scala/app/softnetwork/payment/serialization/package.scala index 0625bb0..82f9bc5 100644 --- a/common/src/main/scala/app/softnetwork/payment/serialization/package.scala +++ b/common/src/main/scala/app/softnetwork/payment/serialization/package.scala @@ -3,9 +3,10 @@ package app.softnetwork.payment import app.softnetwork.payment.model._ import app.softnetwork.protobuf.ScalaPBSerializers import ScalaPBSerializers.GeneratedEnumSerializer +import app.softnetwork.account.model.Account +import app.softnetwork.account.serialization.accountFormats import app.softnetwork.payment.api.{LegalUserType, TransactionStatus} import org.json4s.Formats -import app.softnetwork.serialization._ import scala.language.implicitConversions @@ -13,7 +14,7 @@ import scala.language.implicitConversions */ package object serialization { - val paymentFormats: Formats = commonFormats ++ + val paymentFormats: Formats = accountFormats ++ Seq( GeneratedEnumSerializer(KycDocument.KycDocumentStatus.enumCompanion), GeneratedEnumSerializer(KycDocument.KycDocumentType.enumCompanion), @@ -28,7 +29,8 @@ package object serialization { GeneratedEnumSerializer(Transaction.TransactionType.enumCompanion), GeneratedEnumSerializer(RecurringPayment.RecurringPaymentType.enumCompanion), GeneratedEnumSerializer(RecurringPayment.RecurringPaymentFrequency.enumCompanion), - GeneratedEnumSerializer(RecurringPayment.RecurringCardPaymentStatus.enumCompanion) + GeneratedEnumSerializer(RecurringPayment.RecurringCardPaymentStatus.enumCompanion), + GeneratedEnumSerializer(SoftPaymentAccount.Client.Provider.ProviderType.enumCompanion) ) implicit def transactionStatusToTransactionResponseStatus( @@ -84,4 +86,33 @@ package object serialization { case LegalUserType.ORGANIZATION => LegalUser.LegalUserType.ORGANIZATION } } + + implicit def accountToSoftPaymentAccount(account: Account): SoftPaymentAccount = { + account match { + case a: SoftPaymentAccount => a + case _ => + import account._ + SoftPaymentAccount.defaultInstance + .withApplications(applications) + .withCreatedDate(createdDate) + .withCredentials(credentials) + .withCurrentProfile(currentProfile.orNull) + .withDetails(details.orNull) + .withLastLogin(lastLogin.orNull) + .withLastUpdated(lastUpdated) + .withNbLoginFailures(nbLoginFailures) + .withPrincipal(principal) + .withProfiles(profiles) + .withRegistrations(registrations) + .withSecondaryPrincipals(secondaryPrincipals) + .withStatus(status) + .withUuid(uuid) + .withVerificationCode(verificationCode.orNull) + .withVerificationToken(verificationToken.orNull) + .copy( + anonymous = anonymous, + fromAnonymous = fromAnonymous + ) + } + } } diff --git a/common/src/main/scala/app/softnetwork/payment/spi/PaymentProvider.scala b/common/src/main/scala/app/softnetwork/payment/spi/PaymentProvider.scala index 6904a57..8faff45 100644 --- a/common/src/main/scala/app/softnetwork/payment/spi/PaymentProvider.scala +++ b/common/src/main/scala/app/softnetwork/payment/spi/PaymentProvider.scala @@ -12,6 +12,8 @@ private[payment] trait PaymentProvider { protected lazy val mlog: Logger = Logger(LoggerFactory.getLogger(getClass.getName)) + implicit def provider: SoftPaymentAccount.Client.Provider + /** @param maybePaymentAccount * - payment account to create or update * @return @@ -372,6 +374,8 @@ private[payment] trait PaymentProvider { /** @return * client fees */ + def client: Option[SoftPaymentAccount.Client] + def clientFees(): Option[Double] /** @param userId diff --git a/common/src/main/scala/app/softnetwork/payment/spi/PaymentProviderSpi.scala b/common/src/main/scala/app/softnetwork/payment/spi/PaymentProviderSpi.scala new file mode 100644 index 0000000..d0b05b4 --- /dev/null +++ b/common/src/main/scala/app/softnetwork/payment/spi/PaymentProviderSpi.scala @@ -0,0 +1,10 @@ +package app.softnetwork.payment.spi + +import app.softnetwork.payment.model.SoftPaymentAccount + +trait PaymentProviderSpi { + def providerType: SoftPaymentAccount.Client.Provider.ProviderType + + def paymentProvider(p: SoftPaymentAccount.Client.Provider): PaymentProvider + +} diff --git a/common/src/main/scala/app/softnetwork/payment/spi/PaymentProviders.scala b/common/src/main/scala/app/softnetwork/payment/spi/PaymentProviders.scala new file mode 100644 index 0000000..17e4718 --- /dev/null +++ b/common/src/main/scala/app/softnetwork/payment/spi/PaymentProviders.scala @@ -0,0 +1,40 @@ +package app.softnetwork.payment.spi + +import app.softnetwork.payment.model.SoftPaymentAccount + +import java.util.ServiceLoader +import scala.collection.JavaConverters._ + +object PaymentProviders { + + private[this] lazy val paymentProviderFactories: ServiceLoader[PaymentProviderSpi] = + ServiceLoader.load(classOf[PaymentProviderSpi]) + + private[this] var paymentProviders: Map[String, PaymentProvider] = Map.empty + + private[this] def paymentProviderKey(provider: SoftPaymentAccount.Client.Provider) = + s"${provider.providerType}-${provider.providerId}" + + def paymentProvider( + provider: SoftPaymentAccount.Client.Provider + ): PaymentProvider = { + paymentProviders.get(paymentProviderKey(provider)) match { + case Some(paymentProvider) => paymentProvider + case _ => + val paymentProvider = + paymentProviderFactories + .iterator() + .asScala + .find(_.providerType == provider.providerType) + .map(_.paymentProvider(provider)) + .getOrElse( + throw new Exception( + s"PaymentProvider not found for providerType: ${provider.providerType}" + ) + ) + paymentProviders += paymentProviderKey(provider) -> paymentProvider + paymentProvider + } + } + +} diff --git a/core/build.sbt b/core/build.sbt index 4b01b80..fa07d77 100644 --- a/core/build.sbt +++ b/core/build.sbt @@ -4,5 +4,6 @@ name := "payment-core" libraryDependencies ++= Seq( "app.softnetwork.persistence" %% "persistence-kv" % Versions.genericPersistence, + "app.softnetwork.account" %% "account-core" % Versions.account, "app.softnetwork.session" %% "session-core" % Versions.genericPersistence ) diff --git a/core/src/main/scala/app/softnetwork/payment/handlers/SoftPaymentAccountDao.scala b/core/src/main/scala/app/softnetwork/payment/handlers/SoftPaymentAccountDao.scala new file mode 100644 index 0000000..5180489 --- /dev/null +++ b/core/src/main/scala/app/softnetwork/payment/handlers/SoftPaymentAccountDao.scala @@ -0,0 +1,46 @@ +package app.softnetwork.payment.handlers + +import akka.actor.typed.ActorSystem +import akka.cluster.sharding.typed.scaladsl.EntityTypeKey +import app.softnetwork.account.handlers.{AccountDao, AccountHandler} +import app.softnetwork.account.message.AccountCommand +import app.softnetwork.payment.annotation.InternalApi +import app.softnetwork.payment.message.AccountMessages +import app.softnetwork.payment.message.AccountMessages.ProviderLoaded +import app.softnetwork.payment.model.SoftPaymentAccount +import app.softnetwork.payment.persistence.typed.SoftPaymentAccountBehavior +import app.softnetwork.persistence.typed.CommandTypeKey +import org.slf4j.{Logger, LoggerFactory} + +import scala.concurrent.{ExecutionContext, Future} +import scala.reflect.ClassTag + +trait SoftPaymentAccountDao extends AccountDao { _: AccountHandler => + @InternalApi + private[payment] def loadProvider( + clientId: String + )(implicit system: ActorSystem[_]): Future[Option[SoftPaymentAccount.Client.Provider]] = { + implicit val ec: ExecutionContext = system.executionContext + lookup(clientId) flatMap { + case Some(uuid) => + ?(uuid, AccountMessages.LoadProvider(clientId)) map { + case result: ProviderLoaded => Some(result.provider) + case _ => None + } + case _ => Future.successful(None) + } + } + +} + +trait SoftPaymentAccountTypeKey extends CommandTypeKey[AccountCommand] { + override def TypeKey(implicit tTag: ClassTag[AccountCommand]): EntityTypeKey[AccountCommand] = + SoftPaymentAccountBehavior.TypeKey +} + +object SoftPaymentAccountDao + extends SoftPaymentAccountDao + with AccountHandler + with SoftPaymentAccountTypeKey { + lazy val log: Logger = LoggerFactory getLogger getClass.getName +} diff --git a/core/src/main/scala/app/softnetwork/payment/launch/PaymentGuardian.scala b/core/src/main/scala/app/softnetwork/payment/launch/PaymentGuardian.scala index 2e42862..3f2b45f 100644 --- a/core/src/main/scala/app/softnetwork/payment/launch/PaymentGuardian.scala +++ b/core/src/main/scala/app/softnetwork/payment/launch/PaymentGuardian.scala @@ -7,7 +7,10 @@ import app.softnetwork.payment.persistence.query.{ GenericPaymentCommandProcessorStream, Scheduler2PaymentProcessorStream } -import app.softnetwork.payment.persistence.typed.GenericPaymentBehavior +import app.softnetwork.payment.persistence.typed.{ + GenericPaymentBehavior, + SoftPaymentAccountBehavior +} import app.softnetwork.persistence.launch.PersistentEntity import app.softnetwork.persistence.query.EventProcessorStream import app.softnetwork.persistence.schema.SchemaProvider @@ -21,9 +24,12 @@ trait PaymentGuardian extends SessionGuardian { _: SchemaProvider with CsrfCheck def paymentAccountBehavior: ActorSystem[_] => GenericPaymentBehavior + def softPaymentAccountBehavior: ActorSystem[_] => SoftPaymentAccountBehavior + def paymentEntities: ActorSystem[_] => Seq[PersistentEntity[_, _, _, _]] = sys => Seq( - paymentAccountBehavior(sys) + paymentAccountBehavior(sys), + softPaymentAccountBehavior(sys) ) /** initialize all entities diff --git a/core/src/main/scala/app/softnetwork/payment/persistence/typed/GenericPaymentBehavior.scala b/core/src/main/scala/app/softnetwork/payment/persistence/typed/GenericPaymentBehavior.scala index dddc440..b661b04 100644 --- a/core/src/main/scala/app/softnetwork/payment/persistence/typed/GenericPaymentBehavior.scala +++ b/core/src/main/scala/app/softnetwork/payment/persistence/typed/GenericPaymentBehavior.scala @@ -1,13 +1,14 @@ package app.softnetwork.payment.persistence.typed -import akka.actor.typed.{ActorRef, ActorSystem} import akka.actor.typed.scaladsl.{ActorContext, TimerScheduler} +import akka.actor.typed.{ActorRef, ActorSystem} import akka.cluster.sharding.typed.ShardingEnvelope import akka.persistence.typed.scaladsl.Effect import app.softnetwork.kv.handlers.GenericKeyValueDao +import app.softnetwork.payment.annotation.InternalApi import app.softnetwork.payment.config.PaymentSettings import app.softnetwork.payment.config.PaymentSettings.{AkkaNodeRole, PayInStatementDescriptor} -import app.softnetwork.payment.handlers.{GenericPaymentDao, PaymentKvDao} +import app.softnetwork.payment.handlers.{GenericPaymentDao, PaymentKvDao, SoftPaymentAccountDao} import app.softnetwork.payment.message.PaymentEvents._ import app.softnetwork.payment.message.PaymentMessages._ import app.softnetwork.payment.message.TransactionEvents._ @@ -19,9 +20,6 @@ import app.softnetwork.persistence._ import app.softnetwork.persistence.message.{BroadcastEvent, CrudEvent} import app.softnetwork.persistence.typed._ import app.softnetwork.scheduler.config.SchedulerSettings -import app.softnetwork.serialization.asJson -import app.softnetwork.time._ -import org.slf4j.Logger import app.softnetwork.scheduler.message.SchedulerEvents.{ ExternalEntityToSchedulerEvent, ExternalSchedulerEvent, @@ -29,6 +27,9 @@ import app.softnetwork.scheduler.message.SchedulerEvents.{ } import app.softnetwork.scheduler.message.{AddSchedule, RemoveSchedule} import app.softnetwork.scheduler.model.Schedule +import app.softnetwork.serialization.asJson +import app.softnetwork.time._ +import org.slf4j.Logger import java.time.LocalDate import java.util.Date @@ -44,7 +45,7 @@ trait GenericPaymentBehavior ExternalSchedulerEvent, PaymentResult ] - with ManifestWrapper[PaymentAccount] { _: PaymentProvider => + with ManifestWrapper[PaymentAccount] { override protected val manifestWrapper: ManifestW = ManifestW() @@ -55,6 +56,10 @@ trait GenericPaymentBehavior def paymentDao: GenericPaymentDao + def softPaymentAccountDao: SoftPaymentAccountDao = SoftPaymentAccountDao + + def defaultProvider: SoftPaymentAccount.Client.Provider + /** @return * node role required to start this actor */ @@ -193,8 +198,10 @@ trait GenericPaymentBehavior case cmd: PreRegisterCard => import cmd._ var registerWallet: Boolean = false - loadPaymentAccount(entityId, state, PaymentAccount.User.NaturalUser(user)) match { + loadPaymentAccount(entityId, state, PaymentAccount.User.NaturalUser(user), clientId) match { case Some(paymentAccount) => + val paymentProvider = loadPaymentProvider(paymentAccount.clientId) + import paymentProvider._ val lastUpdated = now() (paymentAccount.userId match { case None => @@ -329,6 +336,8 @@ trait GenericPaymentBehavior import cmd._ state match { case Some(paymentAccount) => + val paymentProvider = loadPaymentProvider(paymentAccount.clientId) + import paymentProvider._ paymentAccount.getNaturalUser.userId match { case Some(userId) => (registrationId match { @@ -380,6 +389,8 @@ trait GenericPaymentBehavior import cmd._ state match { case Some(paymentAccount) => + val paymentProvider = loadPaymentProvider(paymentAccount.clientId) + import paymentProvider._ loadCardPreAuthorized(orderUuid, preAuthorizationId) match { case Some(transaction) => handleCardPreAuthorization( @@ -400,6 +411,8 @@ trait GenericPaymentBehavior import cmd._ state match { case Some(paymentAccount) => + val paymentProvider = loadPaymentProvider(paymentAccount.clientId) + import paymentProvider._ paymentAccount.transactions.find(_.id == cardPreAuthorizedTransactionId) match { case Some(preAuthorizationTransaction) => val preAuthorizationCanceled = @@ -490,6 +503,8 @@ trait GenericPaymentBehavior case Success(s) => s match { case Some(creditedPaymentAccount) => + val paymentProvider = loadPaymentProvider(creditedPaymentAccount.clientId) + import paymentProvider._ creditedPaymentAccount.walletId match { case Some(creditedWalletId) => payInWithCardPreAuthorized( @@ -557,6 +572,8 @@ trait GenericPaymentBehavior import cmd._ state match { case Some(paymentAccount) => + val paymentProvider = loadPaymentProvider(paymentAccount.clientId) + import paymentProvider._ paymentType match { case Transaction.PaymentType.CARD => paymentAccount.userId match { @@ -733,6 +750,8 @@ trait GenericPaymentBehavior import cmd._ state match { case Some(paymentAccount) => + val paymentProvider = loadPaymentProvider(paymentAccount.clientId) + import paymentProvider._ loadPayIn(orderUuid, transactionId, None) match { case Some(transaction) => handlePayIn( @@ -753,6 +772,8 @@ trait GenericPaymentBehavior import cmd._ state match { case Some(paymentAccount) => + val paymentProvider = loadPaymentProvider(paymentAccount.clientId) + import paymentProvider._ loadPayIn(orderUuid, transactionId, None) match { case Some(transaction) => handlePayIn( @@ -773,6 +794,8 @@ trait GenericPaymentBehavior import cmd._ state match { case Some(paymentAccount) => + val paymentProvider = loadPaymentProvider(paymentAccount.clientId) + import paymentProvider._ (paymentAccount.transactions.find(_.id == payInTransactionId) match { case None => loadPayIn(orderUuid, payInTransactionId, None) case some => some @@ -920,6 +943,8 @@ trait GenericPaymentBehavior import cmd._ state match { case Some(paymentAccount) => + val paymentProvider = loadPaymentProvider(paymentAccount.clientId) + import paymentProvider._ paymentAccount.userId match { case Some(userId) => paymentAccount.walletId match { @@ -1117,6 +1142,8 @@ trait GenericPaymentBehavior import cmd._ state match { case Some(paymentAccount) => // debited account + val paymentProvider = loadPaymentProvider(paymentAccount.clientId) + import paymentProvider._ var maybeCreditedPaymentAccount: Option[PaymentAccount] = None transfer(paymentAccount.userId match { case Some(authorId) => @@ -1291,6 +1318,8 @@ trait GenericPaymentBehavior ) .thenRun(_ => MandateNotCanceled ~> replyTo) } else { + val paymentProvider = loadPaymentProvider(paymentAccount.clientId) + import paymentProvider._ paymentAccount.bankAccount match { case Some(bankAccount) => bankAccount.mandateId match { @@ -1345,6 +1374,8 @@ trait GenericPaymentBehavior case Some(userId) => paymentAccount.bankAccount.flatMap(_.id) match { case Some(bankAccountId) => + val paymentProvider = loadPaymentProvider(paymentAccount.clientId) + import paymentProvider._ loadMandate(Some(mandateId), userId, bankAccountId) match { case Some(report) => val internalStatus = @@ -1399,6 +1430,8 @@ trait GenericPaymentBehavior paymentAccount.bankAccount.flatMap(_.mandateId) match { case Some(mandateId) => if (paymentAccount.mandateActivated) { + val paymentProvider = loadPaymentProvider(paymentAccount.clientId) + import paymentProvider._ directDebit( Some( DirectDebitTransaction.defaultInstance @@ -1489,6 +1522,8 @@ trait GenericPaymentBehavior case Some(transaction) => paymentAccount.walletId match { case Some(creditedWalletId) => + val paymentProvider = loadPaymentProvider(paymentAccount.clientId) + import paymentProvider._ val transactionDate: LocalDate = Date.from(transaction.createdDate) directDebitTransaction( transaction.creditedWalletId.getOrElse(creditedWalletId), @@ -1567,6 +1602,8 @@ trait GenericPaymentBehavior _.getId == cmd.recurringPayInRegistrationId ) match { case Some(recurringPayment) => + val paymentProvider = loadPaymentProvider(paymentAccount.clientId) + import paymentProvider._ createRecurringCardPayment( RecurringPaymentTransaction.defaultInstance .withExternalUuid(paymentAccount.externalUuid) @@ -1612,6 +1649,8 @@ trait GenericPaymentBehavior import cmd._ paymentAccount.recurryingPayments.find(_.getId == recurringPayInRegistrationId) match { case Some(recurringPayment) => + val paymentProvider = loadPaymentProvider(paymentAccount.clientId) + import paymentProvider._ loadPayIn("", transactionId, Some(recurringPayInRegistrationId)) match { case Some(transaction) => handleRecurringPayment( @@ -1663,6 +1702,8 @@ trait GenericPaymentBehavior _.getId == recurringPaymentRegistrationId ) match { case Some(recurringPayment) => + val paymentProvider = loadPaymentProvider(paymentAccount.clientId) + import paymentProvider._ val debitedAmount = nextDebitedAmount.getOrElse( recurringPayment.nextDebitedAmount.getOrElse( recurringPayment.firstDebitedAmount @@ -1855,7 +1896,7 @@ trait GenericPaymentBehavior case None => cmd.user match { case Some(user) => - loadPaymentAccount(entityId, None, user) + loadPaymentAccount(entityId, None, user, cmd.clientId) case _ => None } case some => some @@ -2057,6 +2098,8 @@ trait GenericPaymentBehavior updatedPaymentAccount.getLegalUser.uboDeclarationRequired && updatedPaymentAccount.getLegalUser.uboDeclaration.isEmpty + val paymentProvider = loadPaymentProvider(paymentAccount.clientId) + import paymentProvider._ (paymentAccount.userId match { case None => createOrUpdatePaymentAccount(Some(updatedPaymentAccount)) @@ -2288,6 +2331,8 @@ trait GenericPaymentBehavior import cmd._ state match { case Some(paymentAccount) if paymentAccount.hasAcceptedTermsOfPSP => + val paymentProvider = loadPaymentProvider(paymentAccount.clientId) + import paymentProvider._ paymentAccount.userId match { case Some(userId) => addDocument(userId, entityId, pages, kycDocumentType) match { @@ -2412,6 +2457,8 @@ trait GenericPaymentBehavior case cmd: CreateOrUpdateUbo => state match { case Some(paymentAccount) => + val paymentProvider = loadPaymentProvider(paymentAccount.clientId) + import paymentProvider._ var declarationCreated: Boolean = false def createInternalDeclaration(): Option[UboDeclaration] = { createDeclaration(paymentAccount.userId.getOrElse("")) match { @@ -2486,6 +2533,8 @@ trait GenericPaymentBehavior case Some(uboDeclaration) if uboDeclaration.status.isUboDeclarationCreated || uboDeclaration.status.isUboDeclarationIncomplete || uboDeclaration.status.isUboDeclarationRefused => + val paymentProvider = loadPaymentProvider(paymentAccount.clientId) + import paymentProvider._ validateDeclaration(paymentAccount.userId.getOrElse(""), uboDeclaration.id) match { case Some(declaration) => val updatedUbo = declaration.withUbos(uboDeclaration.ubos) @@ -2536,6 +2585,8 @@ trait GenericPaymentBehavior if cmd.uboDeclarationId == uboDeclaration.id && uboDeclaration.status.isUboDeclarationValidationAsked => import cmd._ + val paymentProvider = loadPaymentProvider(paymentAccount.clientId) + import paymentProvider._ getDeclaration(paymentAccount.userId.getOrElse(""), uboDeclarationId) match { case Some(declaration) => val internalStatus = { @@ -2839,6 +2890,8 @@ trait GenericPaymentBehavior case Some(_) => Effect.none.thenRun(_ => CardNotDisabled ~> replyTo) case _ => + val paymentProvider = loadPaymentProvider(paymentAccount.clientId) + import paymentProvider._ disableCard(cmd.cardId) match { case Some(_) => val lastUpdated = now() @@ -2896,6 +2949,8 @@ trait GenericPaymentBehavior nextDebitedAmount = cmd.nextDebitedAmount, nextFeesAmount = cmd.nextFeesAmount ) + val paymentProvider = loadPaymentProvider(paymentAccount.clientId) + import paymentProvider._ registerRecurringCardPayment( userId, walletId, @@ -3024,6 +3079,8 @@ trait GenericPaymentBehavior _.getId == cmd.recurringPayInRegistrationId ) match { case Some(recurringPayment) if recurringPayment.`type`.isCard => + val paymentProvider = loadPaymentProvider(paymentAccount.clientId) + import paymentProvider._ val cardId: Option[String] = cmd.cardId match { case Some(cardId) => @@ -3192,6 +3249,8 @@ trait GenericPaymentBehavior bankAccountId: String )(implicit context: ActorContext[_]): Effect[ExternalSchedulerEvent, Option[PaymentAccount]] = { implicit val system: ActorSystem[_] = context.system + val paymentProvider = loadPaymentProvider(paymentAccount.clientId) + import paymentProvider._ mandate(creditedAccount, creditedUserId, bankAccountId) match { case Some(mandateResult) => if (mandateResult.status.isMandateFailed) { @@ -3254,9 +3313,10 @@ trait GenericPaymentBehavior private[this] def loadPaymentAccount( entityId: String, state: Option[PaymentAccount], - user: PaymentAccount.User + user: PaymentAccount.User, + clientId: Option[String] )(implicit system: ActorSystem[_], log: Logger): Option[PaymentAccount] = { - val pa = PaymentAccount.defaultInstance.withUser(user) + val pa = PaymentAccount.defaultInstance.withUser(user).copy(clientId = clientId) val uuid = pa.externalUuidWithProfile state match { case None => @@ -3282,6 +3342,11 @@ trait GenericPaymentBehavior s"the payment account entity $entityId has already been associated with another external uuid ${paymentAccount.externalUuid}" ) None + } else if (paymentAccount.clientId.getOrElse("") != clientId.getOrElse("")) { + log.warn( + s"the payment account entity $entityId has already been associated with another client ${paymentAccount.clientId}" + ) + None } else { keyValueDao.addKeyValue(uuid, entityId) Some(paymentAccount) @@ -3552,6 +3617,8 @@ trait GenericPaymentBehavior case _ => if (transaction.status.isTransactionSucceeded || transaction.status.isTransactionCreated) { log.debug("Order-{} paid in: {} -> {}", orderUuid, transaction.id, asJson(transaction)) + val paymentProvider = loadPaymentProvider(paymentAccount.clientId) + import paymentProvider._ val registerCardEvents: List[ExternalSchedulerEvent] = if (registerCard) { transaction.cardId match { @@ -3696,6 +3763,8 @@ trait GenericPaymentBehavior transaction.id, asJson(transaction) ) + val paymentProvider = loadPaymentProvider(paymentAccount.clientId) + import paymentProvider._ val registerCardEvents: List[ExternalSchedulerEvent] = if (registerCard) { transaction.cardId match { @@ -3782,6 +3851,8 @@ trait GenericPaymentBehavior val userId = paymentAccount.userId.getOrElse("") + val paymentProvider = loadPaymentProvider(paymentAccount.clientId) + import paymentProvider._ val report = loadDocumentStatus(userId, documentId) val internalStatus = @@ -3943,4 +4014,19 @@ trait GenericPaymentBehavior newDocuments } + + @InternalApi + private[this] def loadPaymentProvider( + clientId: Option[String] + )(implicit system: ActorSystem[_]): PaymentProvider = { + PaymentProviders.paymentProvider( + clientId + .flatMap(softPaymentAccountDao.loadProvider(_) complete () match { + case Success(s) => s + case Failure(_) => None + }) + .getOrElse(defaultProvider) + ) + } + } diff --git a/core/src/main/scala/app/softnetwork/payment/persistence/typed/SoftPaymentAccountBehavior.scala b/core/src/main/scala/app/softnetwork/payment/persistence/typed/SoftPaymentAccountBehavior.scala new file mode 100644 index 0000000..d75ca7b --- /dev/null +++ b/core/src/main/scala/app/softnetwork/payment/persistence/typed/SoftPaymentAccountBehavior.scala @@ -0,0 +1,172 @@ +package app.softnetwork.payment.persistence.typed + +import akka.actor.typed.ActorRef +import akka.actor.typed.scaladsl.{ActorContext, TimerScheduler} +import akka.persistence.typed.scaladsl.Effect +import app.softnetwork.account.handlers.{DefaultGenerator, Generator} +import app.softnetwork.account.message +import app.softnetwork.account.message.{ + AccountCommand, + AccountCommandResult, + AccountCreatedEvent, + AccountNotFound, + BasicAccountProfileUpdatedEvent, + ProfileUpdatedEvent +} +import app.softnetwork.account.model.{BasicAccount, BasicAccountProfile, Principal, PrincipalType} +import app.softnetwork.account.persistence.typed.AccountBehavior +import app.softnetwork.payment.message.AccountMessages +import app.softnetwork.payment.message.AccountMessages.SoftPaymentSignup +import app.softnetwork.payment.message.SoftPaymentAccountEvents.{ + SoftPaymentAccountCreatedEvent, + SoftPaymentAccountProviderRegisteredEvent +} +import app.softnetwork.payment.model.SoftPaymentAccount +import app.softnetwork.payment.spi.PaymentProviders +import app.softnetwork.persistence.typed._ +import app.softnetwork.scheduler.message.SchedulerEvents.ExternalSchedulerEvent + +import java.time.Instant + +trait SoftPaymentAccountBehavior extends AccountBehavior[SoftPaymentAccount, BasicAccountProfile] { + _: Generator => + override protected def createAccount( + entityId: String, + cmd: message.SignUp + )(implicit context: ActorContext[AccountCommand]): Option[SoftPaymentAccount] = { + cmd match { + case SoftPaymentSignup(_, _, provider, _, _) => + PaymentProviders.paymentProvider(provider).client match { + case Some(client) => + SoftPaymentAccount(BasicAccount(cmd, Some(entityId))) + .map(account => + account + .withClient(client.withClientApiKey(client.generateApiKey())) + .withSecondaryPrincipals( + account.secondaryPrincipals.filterNot( + _.`type` == PrincipalType.Other + ) :+ Principal(PrincipalType.Other, client.clientId) + ) + ) + case _ => None + } + case _ => None + } + } + + override protected def createProfileUpdatedEvent( + uuid: String, + profile: BasicAccountProfile, + loginUpdated: Option[Boolean] + )(implicit context: ActorContext[AccountCommand]): ProfileUpdatedEvent[BasicAccountProfile] = + BasicAccountProfileUpdatedEvent(uuid, profile, loginUpdated) + + override protected def createAccountCreatedEvent( + account: SoftPaymentAccount + )(implicit context: ActorContext[AccountCommand]): AccountCreatedEvent[SoftPaymentAccount] = + SoftPaymentAccountCreatedEvent(account) + + /** @param entityId + * - entity identity + * @param state + * - current state + * @param command + * - command to handle + * @param replyTo + * - optional actor to reply to + * @return + * effect + */ + override def handleCommand( + entityId: String, + state: Option[SoftPaymentAccount], + command: AccountCommand, + replyTo: Option[ActorRef[AccountCommandResult]], + timers: TimerScheduler[AccountCommand] + )(implicit + context: ActorContext[AccountCommand] + ): Effect[ExternalSchedulerEvent, Option[SoftPaymentAccount]] = { + command match { + case AccountMessages.RegisterProvider(provider) => + state match { + case Some(account) => + if (account.client.isDefined) { + Effect.none.thenRun { _ => + AccountMessages.ProviderAlreadyRegistered ~> replyTo + } + } else { + PaymentProviders.paymentProvider(provider).client match { + case Some(client) => + val updatedClient = client.withClientApiKey(client.generateApiKey()) + Effect + .persist( + SoftPaymentAccountProviderRegisteredEvent( + updatedClient, + Instant.now() + ) + ) + .thenRun(_ => AccountMessages.ProviderRegistered(updatedClient) ~> replyTo) + case _ => + Effect.none.thenRun { _ => + AccountMessages.ProviderNotRegistered ~> replyTo + } + } + } + case _ => + Effect.none.thenRun { _ => + AccountNotFound ~> replyTo + } + } + + case AccountMessages.LoadProvider(clientId) => + state match { + case Some(account) => + account.client match { + case Some(client) => + if (client.clientId == clientId) { + Effect.none.thenRun { _ => + AccountMessages.ProviderLoaded(client.provider) ~> replyTo + } + } else { + Effect.none.thenRun { _ => + AccountMessages.ProviderNotFound ~> replyTo + } + } + case _ => + Effect.none.thenRun { _ => + AccountMessages.ProviderNotFound ~> replyTo + } + } + case _ => + Effect.none.thenRun { _ => + AccountNotFound ~> replyTo + } + } + + case _ => super.handleCommand(entityId, state, command, replyTo, timers) + } + } + + /** @param state + * - current state + * @param event + * - event to hanlde + * @return + * new state + */ + override def handleEvent( + state: Option[SoftPaymentAccount], + event: ExternalSchedulerEvent + )(implicit context: ActorContext[_]): Option[SoftPaymentAccount] = { + event match { + case SoftPaymentAccountProviderRegisteredEvent(client, lastUpdated) => + state.map(_.withClient(client).withLastUpdated(lastUpdated)) + case _ => super.handleEvent(state, event) + } + } + +} + +case object SoftPaymentAccountBehavior extends SoftPaymentAccountBehavior with DefaultGenerator { + override def persistenceId: String = "SoftPaymentAccount" +} diff --git a/core/src/main/scala/app/softnetwork/payment/service/GenericPaymentEndpoints.scala b/core/src/main/scala/app/softnetwork/payment/service/GenericPaymentEndpoints.scala index feead6d..d710c69 100644 --- a/core/src/main/scala/app/softnetwork/payment/service/GenericPaymentEndpoints.scala +++ b/core/src/main/scala/app/softnetwork/payment/service/GenericPaymentEndpoints.scala @@ -3,6 +3,7 @@ package app.softnetwork.payment.service import app.softnetwork.payment.handlers.GenericPaymentHandler import app.softnetwork.payment.message.PaymentMessages._ import app.softnetwork.payment.model._ +import app.softnetwork.session.service.SessionMaterials import sttp.capabilities import sttp.capabilities.akka.AkkaStreams import sttp.model.Part @@ -22,7 +23,7 @@ trait GenericPaymentEndpoints with UboDeclarationEndpoints with RecurringPaymentEndpoints with MandateEndpoints { - _: GenericPaymentHandler => + _: GenericPaymentHandler with SessionMaterials => import app.softnetwork.serialization._ diff --git a/core/src/main/scala/app/softnetwork/payment/service/GenericPaymentService.scala b/core/src/main/scala/app/softnetwork/payment/service/GenericPaymentService.scala index 1d40880..53cc5b8 100644 --- a/core/src/main/scala/app/softnetwork/payment/service/GenericPaymentService.scala +++ b/core/src/main/scala/app/softnetwork/payment/service/GenericPaymentService.scala @@ -1,5 +1,6 @@ package app.softnetwork.payment.service +import akka.actor.typed.ActorSystem import akka.http.scaladsl.model.{HttpResponse, StatusCodes} import akka.http.scaladsl.server.{Directives, Route} import app.softnetwork.api.server.DefaultComplete @@ -14,21 +15,20 @@ import akka.http.scaladsl.server.directives.FileInfo import akka.stream.Materializer import akka.stream.scaladsl.{Sink, Source} import akka.util.ByteString -import app.softnetwork.session.service.SessionService +import app.softnetwork.session.service.{ServiceWithSessionDirectives, SessionMaterials} import com.softwaremill.session.CsrfDirectives.hmacTokenCsrfProtection import com.softwaremill.session.CsrfOptions.checkHeader import com.typesafe.scalalogging.StrictLogging import de.heikoseeberger.akkahttpjson4s.Json4sSupport import org.json4s.{jackson, Formats} import org.json4s.jackson.Serialization -import org.softnetwork.session.model.Session import app.softnetwork.api.server._ import app.softnetwork.payment.config.PaymentSettings._ import app.softnetwork.payment.model._ +import com.softwaremill.session.SessionConfig import java.io.ByteArrayOutputStream import scala.concurrent.Await - import scala.language.implicitConversions trait GenericPaymentService @@ -37,15 +37,16 @@ trait GenericPaymentService with Json4sSupport with StrictLogging with BasicPaymentService - with ApiRoute { _: GenericPaymentHandler => + with ServiceWithSessionDirectives[PaymentCommand, PaymentResult] + with ApiRoute { _: GenericPaymentHandler with SessionMaterials => implicit def serialization: Serialization.type = jackson.Serialization implicit def formats: Formats = paymentFormats - import Session._ + implicit def sessionConfig: SessionConfig - def sessionService: SessionService + override implicit def ts: ActorSystem[_] = system val route: Route = { pathPrefix(PaymentSettings.PaymentPath) { @@ -68,7 +69,7 @@ trait GenericPaymentService // check anti CSRF token hmacTokenCsrfProtection(checkHeader) { // check if a session exists - sessionService.requiredSession { session => + requiredSession(sc, gt) { session => pathEnd { get { run(LoadCards(externalUuidWithProfile(session))) completeWith { @@ -124,7 +125,7 @@ trait GenericPaymentService // check anti CSRF token hmacTokenCsrfProtection(checkHeader) { // check if a session exists - sessionService.requiredSession { session => + requiredSession(sc, gt) { session => get { pathEnd { run(LoadPaymentAccount(externalUuidWithProfile(session))) completeWith { @@ -363,7 +364,7 @@ trait GenericPaymentService // check anti CSRF token hmacTokenCsrfProtection(checkHeader) { // check if a session exists - sessionService.requiredSession { session => + requiredSession(sc, gt) { session => pathEnd { get { run(LoadBankAccount(externalUuidWithProfile(session))) completeWith { @@ -445,7 +446,7 @@ trait GenericPaymentService // check anti CSRF token hmacTokenCsrfProtection(checkHeader) { // check if a session exists - sessionService.requiredSession { session => + requiredSession(sc, gt) { session => pathEnd { get { run(GetUboDeclaration(externalUuidWithProfile(session))) completeWith { @@ -485,7 +486,7 @@ trait GenericPaymentService // check anti CSRF token hmacTokenCsrfProtection(checkHeader) { // check if a session exists - sessionService.requiredSession { session => + requiredSession(sc, gt) { session => pathEnd { get { run( @@ -543,7 +544,7 @@ trait GenericPaymentService // check anti CSRF token hmacTokenCsrfProtection(checkHeader) { // check if a session exists - sessionService.requiredSession { session => + requiredSession(sc, gt) { session => post { run(CreateMandate(externalUuidWithProfile(session))) completeWith { case r: MandateConfirmationRequired => @@ -566,7 +567,7 @@ trait GenericPaymentService // check anti CSRF token hmacTokenCsrfProtection(checkHeader) { // check if a session exists - sessionService.requiredSession { session => + requiredSession(sc, gt) { session => get { pathPrefix(Segment) { recurringPaymentRegistrationId => run( diff --git a/core/src/main/scala/app/softnetwork/payment/service/RootPaymentEndpoints.scala b/core/src/main/scala/app/softnetwork/payment/service/RootPaymentEndpoints.scala index 19140bc..717ea92 100644 --- a/core/src/main/scala/app/softnetwork/payment/service/RootPaymentEndpoints.scala +++ b/core/src/main/scala/app/softnetwork/payment/service/RootPaymentEndpoints.scala @@ -1,11 +1,13 @@ package app.softnetwork.payment.service +import akka.actor.typed.ActorSystem import app.softnetwork.api.server.ApiErrors import app.softnetwork.payment.config.PaymentSettings import app.softnetwork.payment.handlers.GenericPaymentHandler import app.softnetwork.payment.message.PaymentMessages._ import app.softnetwork.payment.serialization.paymentFormats -import app.softnetwork.session.service.ServiceWithSessionEndpoints +import app.softnetwork.session.service.{ServiceWithSessionEndpoints, SessionMaterials} +import com.softwaremill.session.SessionConfig import org.json4s.Formats import org.softnetwork.session.model.Session import sttp.model.headers.CookieValueWithMeta @@ -19,10 +21,14 @@ import scala.language.implicitConversions trait RootPaymentEndpoints extends BasicPaymentService with ServiceWithSessionEndpoints[PaymentCommand, PaymentResult] { - _: GenericPaymentHandler => + _: GenericPaymentHandler with SessionMaterials => override implicit def formats: Formats = paymentFormats + implicit def sessionConfig: SessionConfig + + override implicit def ts: ActorSystem[_] = system + override implicit def resultToApiError(result: PaymentResult): ApiErrors.ErrorInfo = error(result) lazy val rootEndpoint: Endpoint[Unit, Unit, Unit, Unit, Any] = @@ -41,7 +47,9 @@ trait RootPaymentEndpoints ] = ApiErrors .withApiErrorVariants( - antiCsrfWithRequiredSession(sc, gt, checkMode) + hmacTokenCsrfProtection(checkMode) { + requiredSession(sc, st) + } ) .in(PaymentSettings.PaymentPath) } diff --git a/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayApi.scala b/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayApi.scala index 805ce0f..0490348 100644 --- a/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayApi.scala +++ b/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayApi.scala @@ -15,9 +15,12 @@ import app.softnetwork.persistence.jdbc.query.{JdbcJournalProvider, JdbcOffsetPr import app.softnetwork.persistence.schema.SchemaProvider import app.softnetwork.scheduler.config.SchedulerSettings import app.softnetwork.session.CsrfCheck -import app.softnetwork.session.service.SessionEndpoints +import app.softnetwork.session.config.Settings +import app.softnetwork.session.service.SessionMaterials +import com.softwaremill.session.{SessionConfig, SessionManager} import com.typesafe.config.Config import org.slf4j.{Logger, LoggerFactory} +import org.softnetwork.session.model.Session import scala.concurrent.Future @@ -54,11 +57,17 @@ trait MangoPayApi extends PaymentApplication { self: SchemaProvider with CsrfChe PaymentServiceApiHandler.partial(MangoPayServer(system))(system) ) + def sessionConfig: SessionConfig = Settings.Session.DefaultSessionConfig + def paymentSwagger: ActorSystem[_] => SwaggerEndpoint = sys => - new MangoPayPaymentEndpoints with SwaggerEndpoint { + new MangoPayPaymentEndpoints with SwaggerEndpoint with SessionMaterials { + override implicit def manager(implicit + sessionConfig: SessionConfig + ): SessionManager[Session] = self.manager + override protected def sessionType: Session.SessionType = self.sessionType + override def log: Logger = LoggerFactory getLogger getClass.getName + override implicit def sessionConfig: SessionConfig = self.sessionConfig override implicit def system: ActorSystem[_] = sys - lazy val log: Logger = LoggerFactory getLogger getClass.getName - override def sessionEndpoints: SessionEndpoints = self.sessionEndpoints(system) override val applicationVersion: String = systemVersion() } } diff --git a/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayRoutes.scala b/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayRoutes.scala index a9ddf62..3ec9cf0 100644 --- a/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayRoutes.scala +++ b/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayRoutes.scala @@ -5,11 +5,23 @@ import app.softnetwork.api.server.ApiRoute import app.softnetwork.payment.launch.PaymentRoutes import app.softnetwork.payment.service.{GenericPaymentService, MangoPayPaymentService} import app.softnetwork.persistence.schema.SchemaProvider +import app.softnetwork.session.service.SessionMaterials +import com.softwaremill.session.{SessionConfig, SessionManager} +import org.slf4j.{Logger, LoggerFactory} +import org.softnetwork.session.model.Session -trait MangoPayRoutes extends PaymentRoutes { _: MangoPayApi with SchemaProvider => +trait MangoPayRoutes extends PaymentRoutes { self: MangoPayApi with SchemaProvider => - override def paymentService: ActorSystem[_] => GenericPaymentService = system => - MangoPayPaymentService(system, sessionService(system)) + override def paymentService: ActorSystem[_] => GenericPaymentService = sys => + new MangoPayPaymentService with SessionMaterials { + override implicit def manager(implicit + sessionConfig: SessionConfig + ): SessionManager[Session] = self.manager + override protected def sessionType: Session.SessionType = self.sessionType + override def log: Logger = LoggerFactory getLogger getClass.getName + override implicit def sessionConfig: SessionConfig = self.sessionConfig + override implicit def system: ActorSystem[_] = sys + } override def apiRoutes: ActorSystem[_] => List[ApiRoute] = system => super.apiRoutes(system) :+ paymentSwagger(system) diff --git a/mangopay/src/main/resources/META-INF/services/app.softnetwork.payment.spi.PaymentProviderSpi b/mangopay/src/main/resources/META-INF/services/app.softnetwork.payment.spi.PaymentProviderSpi new file mode 100644 index 0000000..9a9e11c --- /dev/null +++ b/mangopay/src/main/resources/META-INF/services/app.softnetwork.payment.spi.PaymentProviderSpi @@ -0,0 +1 @@ +app.softnetwork.payment.spi.MangoPayProviderFactory diff --git a/mangopay/src/main/resources/reference.conf b/mangopay/src/main/resources/reference.conf index e8a5cff..42da258 100644 --- a/mangopay/src/main/resources/reference.conf +++ b/mangopay/src/main/resources/reference.conf @@ -4,8 +4,8 @@ payment{ mangopay { version = "2.01" - client-id = "softnetworktest" - api-key = "qEdjqnNwoTUOMJzQcWEB7CH0nokvkJe0Vy83dxtBQ3fR1SRzq7" + client-id = "softpaymentdev" + api-key = "aJLYtPbdE672E7HHNk6jZrmz9Mwo8YWs05KZXVXje7xKWZHa8j" baseUrl = "https://api.sandbox.mangopay.com/" debug = false # https://docs.mangopay.com/guide/errors diff --git a/mangopay/src/main/scala/app/softnetwork/payment/config/MangoPay.scala b/mangopay/src/main/scala/app/softnetwork/payment/config/MangoPay.scala index bd174b6..9dffa74 100644 --- a/mangopay/src/main/scala/app/softnetwork/payment/config/MangoPay.scala +++ b/mangopay/src/main/scala/app/softnetwork/payment/config/MangoPay.scala @@ -1,10 +1,10 @@ package app.softnetwork.payment.config import MangoPaySettings._ +import app.softnetwork.payment.model.SoftPaymentAccount import com.mangopay.MangoPayApi import com.mangopay.core.enumerations.{EventType, HookStatus} import com.mangopay.entities.Hook - import com.typesafe.scalalogging.StrictLogging import scala.util.{Failure, Success, Try} @@ -41,18 +41,24 @@ object MangoPay extends StrictLogging { lazy val payPalReturnUrl = s"""$BaseUrl/$paypalPath/$PayPalRoute""" } - var maybeMangoPayApi: Option[MangoPayApi] = None + var mangoPayApis: Map[String, MangoPayApi] = Map.empty + + lazy val softPaymentProvider: SoftPaymentAccount.Client.Provider = + SoftPaymentAccount.Client.Provider.defaultInstance + .withProviderType(SoftPaymentAccount.Client.Provider.ProviderType.MANGOPAY) + .withProviderId(MangoPaySettings.MangoPayConfig.clientId) + .withProviderApiKey(MangoPaySettings.MangoPayConfig.apiKey) - def apply(): MangoPayApi = { - maybeMangoPayApi match { + def apply(provider: SoftPaymentAccount.Client.Provider): MangoPayApi = { + mangoPayApis.get(provider.providerId) match { case Some(mangoPayApi) => mangoPayApi case _ => // init MangoPay api import MangoPaySettings.MangoPayConfig._ val mangoPayApi = new MangoPayApi mangoPayApi.getConfig.setBaseUrl(baseUrl) - mangoPayApi.getConfig.setClientId(clientId) - mangoPayApi.getConfig.setClientPassword(apiKey) + mangoPayApi.getConfig.setClientId(provider.providerId) + mangoPayApi.getConfig.setClientPassword(provider.providerApiKey) mangoPayApi.getConfig.setDebugMode(debug) // init MangoPay hooks import scala.collection.JavaConverters._ @@ -78,7 +84,7 @@ object MangoPay extends StrictLogging { createOrUpdateHook(mangoPayApi, EventType.MANDATE_CREATED, hooks) createOrUpdateHook(mangoPayApi, EventType.MANDATE_ACTIVATED, hooks) createOrUpdateHook(mangoPayApi, EventType.MANDATE_EXPIRED, hooks) - maybeMangoPayApi = Some(mangoPayApi) + mangoPayApis = mangoPayApis.updated(provider.providerId, mangoPayApi) mangoPayApi } } diff --git a/mangopay/src/main/scala/app/softnetwork/payment/persistence/typed/MangoPayPaymentBehavior.scala b/mangopay/src/main/scala/app/softnetwork/payment/persistence/typed/MangoPayPaymentBehavior.scala index 9f5422b..6f35334 100644 --- a/mangopay/src/main/scala/app/softnetwork/payment/persistence/typed/MangoPayPaymentBehavior.scala +++ b/mangopay/src/main/scala/app/softnetwork/payment/persistence/typed/MangoPayPaymentBehavior.scala @@ -1,10 +1,13 @@ package app.softnetwork.payment.persistence.typed +import app.softnetwork.payment.config.MangoPay import app.softnetwork.payment.handlers.{GenericPaymentDao, MangoPayPaymentDao} -import app.softnetwork.payment.spi.MangoPayProvider +import app.softnetwork.payment.model.SoftPaymentAccount.Client case object MangoPayPaymentBehavior extends MangoPayPaymentBehavior { override lazy val paymentDao: GenericPaymentDao = MangoPayPaymentDao } -trait MangoPayPaymentBehavior extends GenericPaymentBehavior with MangoPayProvider +trait MangoPayPaymentBehavior extends GenericPaymentBehavior { + override def defaultProvider: Client.Provider = MangoPay.softPaymentProvider +} diff --git a/mangopay/src/main/scala/app/softnetwork/payment/service/MangoPayPaymentEndpoints.scala b/mangopay/src/main/scala/app/softnetwork/payment/service/MangoPayPaymentEndpoints.scala index 60930a9..9caf38e 100644 --- a/mangopay/src/main/scala/app/softnetwork/payment/service/MangoPayPaymentEndpoints.scala +++ b/mangopay/src/main/scala/app/softnetwork/payment/service/MangoPayPaymentEndpoints.scala @@ -1,18 +1,17 @@ package app.softnetwork.payment.service -import akka.actor.typed.ActorSystem import app.softnetwork.payment.config.PaymentSettings import app.softnetwork.payment.handlers.MangoPayPaymentHandler import app.softnetwork.payment.message.PaymentMessages._ import app.softnetwork.payment.model.{BankAccount, KycDocument, UboDeclaration} -import app.softnetwork.session.service.SessionEndpoints +import app.softnetwork.session.service.SessionMaterials import com.mangopay.core.enumerations.EventType -import org.slf4j.{Logger, LoggerFactory} import sttp.tapir.server.ServerEndpoint.Full import scala.concurrent.Future trait MangoPayPaymentEndpoints extends GenericPaymentEndpoints with MangoPayPaymentHandler { + _: SessionMaterials => /** should be implemented by each payment provider */ @@ -252,16 +251,3 @@ trait MangoPayPaymentEndpoints extends GenericPaymentEndpoints with MangoPayPaym } } - -object MangoPayPaymentEndpoints { - def apply( - _system: ActorSystem[_], - _sessionEndpoints: SessionEndpoints - ): MangoPayPaymentEndpoints = { - new MangoPayPaymentEndpoints { - lazy val log: Logger = LoggerFactory getLogger getClass.getName - override implicit def system: ActorSystem[_] = _system - override def sessionEndpoints: SessionEndpoints = _sessionEndpoints - } - } -} diff --git a/mangopay/src/main/scala/app/softnetwork/payment/service/MangoPayPaymentService.scala b/mangopay/src/main/scala/app/softnetwork/payment/service/MangoPayPaymentService.scala index 4a5382a..fbfad2f 100644 --- a/mangopay/src/main/scala/app/softnetwork/payment/service/MangoPayPaymentService.scala +++ b/mangopay/src/main/scala/app/softnetwork/payment/service/MangoPayPaymentService.scala @@ -1,6 +1,5 @@ package app.softnetwork.payment.service -import akka.actor.typed.ActorSystem import akka.http.scaladsl.model.{HttpResponse, StatusCodes} import akka.http.scaladsl.server.Route import app.softnetwork.payment.config.PaymentSettings.HooksRoute @@ -19,11 +18,11 @@ import app.softnetwork.payment.message.PaymentMessages.{ ValidateRegularUser } import app.softnetwork.payment.model.{BankAccount, KycDocument, UboDeclaration} -import app.softnetwork.session.service.SessionService +import app.softnetwork.session.service.SessionMaterials import com.mangopay.core.enumerations.EventType -import org.slf4j.{Logger, LoggerFactory} trait MangoPayPaymentService extends GenericPaymentService with MangoPayPaymentHandler { + _: SessionMaterials => def completeWithKycDocumentUpdatedResult( eventType: String, @@ -221,13 +220,3 @@ trait MangoPayPaymentService extends GenericPaymentService with MangoPayPaymentH } } } - -object MangoPayPaymentService { - def apply(_system: ActorSystem[_], _sessionService: SessionService): MangoPayPaymentService = { - new MangoPayPaymentService { - lazy val log: Logger = LoggerFactory getLogger getClass.getName - override implicit def system: ActorSystem[_] = _system - override def sessionService: SessionService = _sessionService - } - } -} diff --git a/mangopay/src/main/scala/app/softnetwork/payment/spi/MangoPayProvider.scala b/mangopay/src/main/scala/app/softnetwork/payment/spi/MangoPayProvider.scala index 273e22d..8128e81 100644 --- a/mangopay/src/main/scala/app/softnetwork/payment/spi/MangoPayProvider.scala +++ b/mangopay/src/main/scala/app/softnetwork/payment/spi/MangoPayProvider.scala @@ -24,6 +24,7 @@ import app.softnetwork.payment.model.{RecurringPayment, _} import app.softnetwork.payment.config.{MangoPay, MangoPaySettings} import app.softnetwork.payment.config.MangoPaySettings.MangoPayConfig._ import app.softnetwork.payment.model.PaymentUser.PaymentUserType +import app.softnetwork.payment.model.SoftPaymentAccount.Client.Provider import scala.util.{Failure, Success, Try} import app.softnetwork.persistence._ @@ -234,7 +235,7 @@ trait MangoPayProvider extends PaymentProvider { (if (userId.getOrElse("").trim.isEmpty) None else - Try(MangoPay().getUserApi.getNatural(userId.getOrElse(""))) match { + Try(MangoPay(provider).getUserApi.getNatural(userId.getOrElse(""))) match { case Success(u) => Option(u) case Failure(f) => mlog.error(f.getMessage, f) @@ -242,14 +243,14 @@ trait MangoPayProvider extends PaymentProvider { }) match { case Some(u) => user.setId(u.getId) - Try(MangoPay().getUserApi.update(user).getId) match { + Try(MangoPay(provider).getUserApi.update(user).getId) match { case Success(id) => Some(id) case Failure(f) => mlog.error(f.getMessage, f) None } case None => - Try(MangoPay().getUserApi.create(user).getId) match { + Try(MangoPay(provider).getUserApi.create(user).getId) match { case Success(id) => Some(id) case Failure(f) => mlog.error(f.getMessage, f) @@ -322,7 +323,9 @@ trait MangoPayProvider extends PaymentProvider { (if (legalRepresentative.userId.isEmpty) None else - Try(MangoPay().getUserApi.getLegal(legalRepresentative.userId.getOrElse(""))) match { + Try( + MangoPay(provider).getUserApi.getLegal(legalRepresentative.userId.getOrElse("")) + ) match { case Success(u) => Option(u) case Failure(f) => mlog.error(f.getMessage, f) @@ -330,14 +333,14 @@ trait MangoPayProvider extends PaymentProvider { }) match { case Some(u) => user.setId(u.getId) - Try(MangoPay().getUserApi.update(user).getId) match { + Try(MangoPay(provider).getUserApi.update(user).getId) match { case Success(id) => Some(id) case Failure(f) => mlog.error(f.getMessage, f) None } case None => - Try(MangoPay().getUserApi.create(user).getId) match { + Try(MangoPay(provider).getUserApi.create(user).getId) match { case Success(id) => Some(id) case Failure(f) => mlog.error(f.getMessage, f) @@ -377,7 +380,7 @@ trait MangoPayProvider extends PaymentProvider { wallet.setDescription(s"wallet for $externalUuid") wallet.setTag(externalUuid) Try( - MangoPay().getUserApi + MangoPay(provider).getUserApi .getWallets(userId) .asScala .find(w => @@ -388,14 +391,14 @@ trait MangoPayProvider extends PaymentProvider { maybeWallet match { case Some(w) => wallet.setId(w.getId) - Try(MangoPay().getWalletApi.update(wallet).getId) match { + Try(MangoPay(provider).getWalletApi.update(wallet).getId) match { case Success(id) => Some(id) case Failure(f) => mlog.error(f.getMessage, f) None } case None => - Try(MangoPay().getWalletApi.create(wallet).getId) match { + Try(MangoPay(provider).getWalletApi.create(wallet).getId) match { case Success(id) => Some(id) case Failure(f) => mlog.error(f.getMessage, f) @@ -441,7 +444,7 @@ trait MangoPayProvider extends PaymentProvider { bankAccount.setType(BankAccountType.IBAN) bankAccount.setUserId(userId) (if (id.isDefined) - Try(MangoPay().getUserApi.getBankAccount(userId, getId)) match { + Try(MangoPay(provider).getUserApi.getBankAccount(userId, getId)) match { case Success(b) => Option(b) case Failure(f) => mlog.error(f.getMessage, f) @@ -450,7 +453,7 @@ trait MangoPayProvider extends PaymentProvider { else None) match { case Some(previousBankAccount) => Try( - MangoPay().getUserApi + MangoPay(provider).getUserApi .updateBankAccount(userId, bankAccount, previousBankAccount.getId) .getId ) match { @@ -460,7 +463,7 @@ trait MangoPayProvider extends PaymentProvider { None } case _ => - Try(MangoPay().getUserApi.createBankAccount(userId, bankAccount).getId) match { + Try(MangoPay(provider).getUserApi.createBankAccount(userId, bankAccount).getId) match { case Success(id) => Option(id) case Failure(f) => mlog.error(f.getMessage, f) @@ -478,7 +481,7 @@ trait MangoPayProvider extends PaymentProvider { */ override def getActiveBankAccount(userId: String): Option[String] = { Try( - MangoPay().getUserApi + MangoPay(provider).getUserApi .getBankAccounts(userId) .asScala .filter(bankAccount => bankAccount.isActive) @@ -504,7 +507,7 @@ trait MangoPayProvider extends PaymentProvider { */ def checkBankAccount(userId: String, bankAccountId: String): Boolean = { Try( - MangoPay().getUserApi + MangoPay(provider).getUserApi .getBankAccounts(userId) .asScala .find(bankAccount => bankAccount.getId == bankAccountId) @@ -538,7 +541,7 @@ trait MangoPayProvider extends PaymentProvider { cardPreRegistration.setCurrency(CurrencyIso.valueOf(currency)) cardPreRegistration.setTag(externalUuid) cardPreRegistration.setUserId(userId) - Try(MangoPay().getCardRegistrationApi.create(cardPreRegistration)) match { + Try(MangoPay(provider).getCardRegistrationApi.create(cardPreRegistration)) match { case Success(cardRegistration) => Some( CardPreRegistration.defaultInstance @@ -569,10 +572,12 @@ trait MangoPayProvider extends PaymentProvider { ): Option[String] = { maybeRegistrationData match { case Some(registrationData) => - Try(MangoPay().getCardRegistrationApi.get(cardPreRegistrationId)) match { + Try(MangoPay(provider).getCardRegistrationApi.get(cardPreRegistrationId)) match { case Success(cardRegistration) => cardRegistration.setRegistrationData(registrationData) - Try(MangoPay().getCardRegistrationApi.update(cardRegistration).getCardId) match { + Try( + MangoPay(provider).getCardRegistrationApi.update(cardRegistration).getCardId + ) match { case Success(cardId) => Option(cardId) case Failure(f) => @@ -594,7 +599,7 @@ trait MangoPayProvider extends PaymentProvider { * card */ def loadCard(cardId: String): Option[Card] = { - Try(MangoPay().getCardApi.get(cardId)) match { + Try(MangoPay(provider).getCardApi.get(cardId)) match { case Success(card) => Some( Card.defaultInstance @@ -615,9 +620,9 @@ trait MangoPayProvider extends PaymentProvider { * the card disabled or none */ override def disableCard(cardId: String): Option[Card] = { - Try(MangoPay().getCardApi.get(cardId)) match { + Try(MangoPay(provider).getCardApi.get(cardId)) match { case Success(card) => - Try(MangoPay().getCardApi.disable(card)) match { + Try(MangoPay(provider).getCardApi.disable(card)) match { case Success(disabledCard) => Some( Card.defaultInstance @@ -686,8 +691,9 @@ trait MangoPayProvider extends PaymentProvider { } Try( idempotencyKey match { - case Some(s) => MangoPay().getCardPreAuthorizationApi.create(s, cardPreAuthorization) - case _ => MangoPay().getCardPreAuthorizationApi.create(cardPreAuthorization) + case Some(s) => + MangoPay(provider).getCardPreAuthorizationApi.create(s, cardPreAuthorization) + case _ => MangoPay(provider).getCardPreAuthorizationApi.create(cardPreAuthorization) } ) match { case Success(result) => @@ -761,7 +767,7 @@ trait MangoPayProvider extends PaymentProvider { cardPreAuthorizedTransactionId: String ): Option[Transaction] = { Try( - MangoPay().getCardPreAuthorizationApi.get(cardPreAuthorizedTransactionId) + MangoPay(provider).getCardPreAuthorizationApi.get(cardPreAuthorizedTransactionId) ) match { case Success(result) => Some( @@ -832,8 +838,8 @@ trait MangoPayProvider extends PaymentProvider { } Try( idempotencyKey match { - case Some(s) => MangoPay().getPayInApi.create(s, payIn) - case _ => MangoPay().getPayInApi.create(payIn) + case Some(s) => MangoPay(provider).getPayInApi.create(s, payIn) + case _ => MangoPay(provider).getPayInApi.create(payIn) } ) match { case Success(result) => @@ -911,12 +917,12 @@ trait MangoPayProvider extends PaymentProvider { cardPreAuthorizedTransactionId: String ): Boolean = { Try( - MangoPay().getCardPreAuthorizationApi.get(cardPreAuthorizedTransactionId) + MangoPay(provider).getCardPreAuthorizationApi.get(cardPreAuthorizedTransactionId) ) match { case Success(result) => result.setPaymentStatus(PaymentStatus.CANCELED) Try( - MangoPay().getCardPreAuthorizationApi.update(result) + MangoPay(provider).getCardPreAuthorizationApi.update(result) ) match { case Success(_) => true case Failure(f) => @@ -941,12 +947,12 @@ trait MangoPayProvider extends PaymentProvider { cardPreAuthorizedTransactionId: String ): Boolean = { Try( - MangoPay().getCardPreAuthorizationApi.get(cardPreAuthorizedTransactionId) + MangoPay(provider).getCardPreAuthorizationApi.get(cardPreAuthorizedTransactionId) ) match { case Success(result) => result.setPaymentStatus(PaymentStatus.VALIDATED) Try( - MangoPay().getCardPreAuthorizationApi.update(result) + MangoPay(provider).getCardPreAuthorizationApi.update(result) ) match { case Success(_) => true case Failure(f) => @@ -1024,8 +1030,8 @@ trait MangoPayProvider extends PaymentProvider { } Try( idempotencyKey match { - case Some(s) => MangoPay().getPayInApi.create(s, payIn) - case _ => MangoPay().getPayInApi.create(payIn) + case Some(s) => MangoPay(provider).getPayInApi.create(s, payIn) + case _ => MangoPay(provider).getPayInApi.create(payIn) } ) match { case Success(result) => @@ -1124,7 +1130,7 @@ trait MangoPayProvider extends PaymentProvider { payIn.setExecutionDetails(executionDetails) payIn.setExecutionType(PayInExecutionType.WEB) Try( - MangoPay().getPayInApi.create(payIn) + MangoPay(provider).getPayInApi.create(payIn) ) match { case Success(result) => Some( @@ -1205,8 +1211,9 @@ trait MangoPayProvider extends PaymentProvider { } Try( idempotencyKey match { - case Some(s) => MangoPay().getPayInApi.createRefund(s, payInTransactionId, refund) - case _ => MangoPay().getPayInApi.createRefund(payInTransactionId, refund) + case Some(s) => + MangoPay(provider).getPayInApi.createRefund(s, payInTransactionId, refund) + case _ => MangoPay(provider).getPayInApi.createRefund(payInTransactionId, refund) } ) match { case Success(result) => @@ -1289,7 +1296,7 @@ trait MangoPayProvider extends PaymentProvider { transfer.getFees.setAmount(feesAmount) transfer.getFees.setCurrency(CurrencyIso.valueOf(currency)) transfer.setDebitedWalletId(debitedWalletId) - Try(MangoPay().getTransferApi.create(transfer)) match { + Try(MangoPay(provider).getTransferApi.create(transfer)) match { case Success(result) => Some( Transaction() @@ -1388,8 +1395,8 @@ trait MangoPayProvider extends PaymentProvider { } Try( idempotencyKey match { - case Some(s) => MangoPay().getPayOutApi.create(s, payOut) - case _ => MangoPay().getPayOutApi.create(payOut) + case Some(s) => MangoPay(provider).getPayOutApi.create(s, payOut) + case _ => MangoPay(provider).getPayOutApi.create(payOut) } ) match { case Success(result) => @@ -1468,7 +1475,7 @@ trait MangoPayProvider extends PaymentProvider { transactionId: String, recurringPayInRegistrationId: Option[String] ): Option[Transaction] = { - Try(MangoPay().getPayInApi.get(transactionId)) match { + Try(MangoPay(provider).getPayInApi.get(transactionId)) match { case Success(result) => val `type` = if (result.getPaymentType == PayInPaymentType.DIRECT_DEBIT) { @@ -1571,7 +1578,7 @@ trait MangoPayProvider extends PaymentProvider { * Refund transaction */ override def loadRefund(orderUuid: String, transactionId: String): Option[Transaction] = { - Try(MangoPay().getPayInApi.getRefund(transactionId)) match { + Try(MangoPay(provider).getPayInApi.getRefund(transactionId)) match { case Success(result) => Some( Transaction().copy( @@ -1603,7 +1610,7 @@ trait MangoPayProvider extends PaymentProvider { * pay out transaction */ override def loadPayOut(orderUuid: String, transactionId: String): Option[Transaction] = { - Try(MangoPay().getPayOutApi.get(transactionId)) match { + Try(MangoPay(provider).getPayOutApi.get(transactionId)) match { case Success(result) => Some( Transaction().copy( @@ -1632,7 +1639,7 @@ trait MangoPayProvider extends PaymentProvider { * transfer transaction */ override def loadTransfer(transactionId: String): Option[Transaction] = { - Try(MangoPay().getTransferApi.get(transactionId)) match { + Try(MangoPay(provider).getTransferApi.get(transactionId)) match { case Success(result) => Some( Transaction().copy( @@ -1694,19 +1701,19 @@ trait MangoPayProvider extends PaymentProvider { documentType: KycDocument.KycDocumentType ): Option[String] = { // create document - Try(MangoPay().getUserApi.createKycDocument(userId, documentType, externalUuid)) match { + Try(MangoPay(provider).getUserApi.createKycDocument(userId, documentType, externalUuid)) match { case Success(s) => mlog.info(s"""Create $documentType for $externalUuid""") // ask for document creation s.setTag(externalUuid) s.setStatus(KycStatus.CREATED) - Try(MangoPay().getUserApi.updateKycDocument(userId, s)) match { + Try(MangoPay(provider).getUserApi.updateKycDocument(userId, s)) match { case Success(s2) => mlog.info(s"""Update $documentType for $externalUuid""") // add document pages if ( pages.forall { page => - Try(MangoPay().getUserApi.createKycPage(userId, s2.getId, page)) match { + Try(MangoPay(provider).getUserApi.createKycPage(userId, s2.getId, page)) match { case Success(_) => mlog.info(s"""Add document page for $externalUuid""") true @@ -1719,7 +1726,7 @@ trait MangoPayProvider extends PaymentProvider { // ask for document validation s2.setTag(externalUuid) s2.setStatus(KycStatus.VALIDATION_ASKED) - Try(MangoPay().getUserApi.updateKycDocument(userId, s2)) match { + Try(MangoPay(provider).getUserApi.updateKycDocument(userId, s2)) match { case Success(s3) => mlog.info(s"""Ask document ${s3.getId} validation for $externalUuid""") Some(s3.getId) @@ -1749,7 +1756,7 @@ trait MangoPayProvider extends PaymentProvider { */ override def loadDocumentStatus(userId: String, documentId: String): KycDocumentValidationReport = // load document - Try(MangoPay().getUserApi.getKycDocument(userId, documentId)) match { + Try(MangoPay(provider).getUserApi.getKycDocument(userId, documentId)) match { case Success(s) => KycDocumentValidationReport.defaultInstance .withId(documentId) @@ -1796,8 +1803,8 @@ trait MangoPayProvider extends PaymentProvider { mandate.setUserId(userId) Try( idempotencyKey match { - case Some(key) => MangoPay().getMandateApi.create(key, mandate) - case _ => MangoPay().getMandateApi.create(mandate) + case Some(key) => MangoPay(provider).getMandateApi.create(key, mandate) + case _ => MangoPay(provider).getMandateApi.create(mandate) } ) match { case Success(s) => @@ -1838,11 +1845,11 @@ trait MangoPayProvider extends PaymentProvider { ): Option[MandateResult] = { Try( maybeMandateId match { - case Some(mandateId) => Option(MangoPay().getMandateApi.get(mandateId)) + case Some(mandateId) => Option(MangoPay(provider).getMandateApi.get(mandateId)) case None => val sorting = new Sorting() sorting.addField("creationDate", SortDirection.desc) - MangoPay().getMandateApi + MangoPay(provider).getMandateApi .getForBankAccount( userId, bankAccountId, @@ -1885,7 +1892,7 @@ trait MangoPayProvider extends PaymentProvider { * mandate result */ override def cancelMandate(mandateId: String): Option[MandateResult] = { - Try(MangoPay().getMandateApi.cancel(mandateId)) match { + Try(MangoPay(provider).getMandateApi.cancel(mandateId)) match { case Success(mandate) => Some( MandateResult.defaultInstance @@ -1960,8 +1967,8 @@ trait MangoPayProvider extends PaymentProvider { } Try( idempotencyKey match { - case Some(s) => MangoPay().getPayInApi.create(s, payIn) - case _ => MangoPay().getPayInApi.create(payIn) + case Some(s) => MangoPay(provider).getPayInApi.create(s, payIn) + case _ => MangoPay(provider).getPayInApi.create(payIn) } ) match { case Success(result) => @@ -2030,7 +2037,7 @@ trait MangoPayProvider extends PaymentProvider { filters.setType(MangoPayTransactionType.PAYIN) filters.setAfterDate(transactionDate.toEpochSecond) Try( - MangoPay().getWalletApi + MangoPay(provider).getWalletApi .getTransactions( walletId, new Pagination(1, 100), @@ -2075,11 +2082,44 @@ trait MangoPayProvider extends PaymentProvider { } } + override def client: Option[SoftPaymentAccount.Client] = { + Try(MangoPay(provider).getClientApi.get()) match { + case Success(client) => + Some( + SoftPaymentAccount.Client.defaultInstance + .withClientId(client.getClientId + "." + provider.providerType.name.toLowerCase) + .withProvider(provider) + .copy( + name = Option(client.getName), + description = Option(client.getPlatformDescription), + logoUrl = Option(client.getLogo), + websiteUrl = Option(client.getPlatformUrl), + address = Option(client.getHeadquartersAddress).map(address => + Address.defaultInstance + .withAddressLine(address.getAddressLine1) + .withCity(address.getCity) + .withPostalCode(address.getPostalCode) + .withCountry(address.getCountry.name()) + .copy(state = Option(address.getRegion)) + ), + technicalEmails = client.getTechEmails.asScala, + administrativeEmails = client.getAdminEmails.asScala, + billingEmails = client.getBillingEmails.asScala, + fraudEmails = client.getFraudEmails.asScala, + vatNumber = Option(client.getTaxNumber) + ) + ) + case Failure(f) => + mlog.error(f.getMessage, f) + None + } + } + /** @return * client fees */ override def clientFees(): Option[Double] = { - Try(MangoPay().getClientApi.getWallet(FundsType.FEES, CurrencyIso.EUR)) match { + Try(MangoPay(provider).getClientApi.getWallet(FundsType.FEES, CurrencyIso.EUR)) match { case Success(wallet) => Some(wallet.getBalance.getAmount.toDouble / 100) case Failure(f) => mlog.error(f.getMessage, f) @@ -2093,7 +2133,7 @@ trait MangoPayProvider extends PaymentProvider { * Ultimate Beneficial Owner Declaration */ override def createDeclaration(userId: String): Option[UboDeclaration] = { - Try(MangoPay().getUboDeclarationApi.create(userId)) match { + Try(MangoPay(provider).getUboDeclarationApi.create(userId)) match { case Success(declaration) => Some( UboDeclaration.defaultInstance @@ -2152,9 +2192,9 @@ trait MangoPayProvider extends PaymentProvider { { if (id.isEmpty) { - Try(MangoPay().getUboDeclarationApi.createUbo(userId, uboDeclarationId, ubo)) + Try(MangoPay(provider).getUboDeclarationApi.createUbo(userId, uboDeclarationId, ubo)) } else { - Try(MangoPay().getUboDeclarationApi.updateUbo(userId, uboDeclarationId, ubo)) + Try(MangoPay(provider).getUboDeclarationApi.updateUbo(userId, uboDeclarationId, ubo)) } } match { case Success(s2) => @@ -2177,7 +2217,7 @@ trait MangoPayProvider extends PaymentProvider { * declaration with Ultimate Beneficial Owner(s) */ override def getDeclaration(userId: String, uboDeclarationId: String): Option[UboDeclaration] = { - Try(MangoPay().getUboDeclarationApi.get(userId, uboDeclarationId)) match { + Try(MangoPay(provider).getUboDeclarationApi.get(userId, uboDeclarationId)) match { case Success(s) => import scala.collection.JavaConverters._ Some( @@ -2226,7 +2266,9 @@ trait MangoPayProvider extends PaymentProvider { userId: String, uboDeclarationId: String ): Option[UboDeclaration] = { - Try(MangoPay().getUboDeclarationApi.submitForValidation(userId, uboDeclarationId)) match { + Try( + MangoPay(provider).getUboDeclarationApi.submitForValidation(userId, uboDeclarationId) + ) match { case Success(s) => Some( UboDeclaration.defaultInstance @@ -2323,7 +2365,8 @@ trait MangoPayProvider extends PaymentProvider { case _ => } Try( - MangoPay().getPayInApi.createRecurringPayment(generateUUID(), createRecurringPayment) + MangoPay(provider).getPayInApi + .createRecurringPayment(generateUUID(), createRecurringPayment) ) match { case Success(s) => Some( @@ -2366,7 +2409,7 @@ trait MangoPayProvider extends PaymentProvider { case _ => } Try( - MangoPay().getPayInApi + MangoPay(provider).getPayInApi .updateRecurringPayment(recurringPayInRegistrationId, recurringPaymentUpdate) ) match { case Success(s) => @@ -2394,7 +2437,7 @@ trait MangoPayProvider extends PaymentProvider { recurringPayInRegistrationId: String ): Option[RecurringPayment.RecurringCardPaymentResult] = { Try( - MangoPay().getPayInApi.getRecurringPayment(recurringPayInRegistrationId) + MangoPay(provider).getPayInApi.getRecurringPayment(recurringPayInRegistrationId) ) match { case Success(s) => Some( @@ -2458,7 +2501,7 @@ trait MangoPayProvider extends PaymentProvider { s"$recurringPaymentFor3DS/$recurringPayInRegistrationId" ) Try( - MangoPay().getPayInApi.createRecurringPayInCIT(generateUUID(), recurringPayInCIT) + MangoPay(provider).getPayInApi.createRecurringPayInCIT(generateUUID(), recurringPayInCIT) ) match { case Success(result) => Some( @@ -2511,7 +2554,7 @@ trait MangoPayProvider extends PaymentProvider { recurringPayInMIT.setFees(fees) recurringPayInMIT.setTag(externalUuid) Try( - MangoPay().getPayInApi.createRecurringPayInMIT(generateUUID(), recurringPayInMIT) + MangoPay(provider).getPayInApi.createRecurringPayInMIT(generateUUID(), recurringPayInMIT) ) match { case Success(result) => Some( @@ -2548,3 +2591,12 @@ trait MangoPayProvider extends PaymentProvider { } } + +class MangoPayProviderFactory extends PaymentProviderSpi { + override val providerType: Provider.ProviderType = Provider.ProviderType.MANGOPAY + + override def paymentProvider(p: SoftPaymentAccount.Client.Provider): MangoPayProvider = + new MangoPayProvider { + override implicit val provider: SoftPaymentAccount.Client.Provider = p + } +} diff --git a/project/Versions.scala b/project/Versions.scala index d229cde..b39226f 100644 --- a/project/Versions.scala +++ b/project/Versions.scala @@ -1,8 +1,10 @@ object Versions { - val genericPersistence = "0.4.1" + val genericPersistence = "0.5.0" - val scheduler = "0.4.1" + val scheduler = "0.5.0" + + val account = "0.5.0" val scalatest = "3.2.16" } diff --git a/testkit/build.sbt b/testkit/build.sbt index c5fa90e..5cdb86d 100644 --- a/testkit/build.sbt +++ b/testkit/build.sbt @@ -9,5 +9,6 @@ libraryDependencies ++= Seq( "app.softnetwork.api" %% "generic-server-api-testkit" % Versions.genericPersistence, "app.softnetwork.session" %% "session-testkit" % Versions.genericPersistence, "app.softnetwork.persistence" %% "persistence-core-testkit" % Versions.genericPersistence, + "app.softnetwork.account" %% "account-testkit" % Versions.account, "org.scalatest" %% "scalatest" % Versions.scalatest ) diff --git a/testkit/src/main/resources/META-INF/services/app.softnetwork.payment.spi.PaymentProviderSpi b/testkit/src/main/resources/META-INF/services/app.softnetwork.payment.spi.PaymentProviderSpi new file mode 100644 index 0000000..e4f69d5 --- /dev/null +++ b/testkit/src/main/resources/META-INF/services/app.softnetwork.payment.spi.PaymentProviderSpi @@ -0,0 +1 @@ +app.softnetwork.payment.spi.MockMangoPayProviderFactory diff --git a/testkit/src/main/scala/app/softnetwork/payment/handlers/MockSoftPaymentAccountDao.scala b/testkit/src/main/scala/app/softnetwork/payment/handlers/MockSoftPaymentAccountDao.scala new file mode 100644 index 0000000..3840059 --- /dev/null +++ b/testkit/src/main/scala/app/softnetwork/payment/handlers/MockSoftPaymentAccountDao.scala @@ -0,0 +1,22 @@ +package app.softnetwork.payment.handlers + +import akka.cluster.sharding.typed.scaladsl.EntityTypeKey +import app.softnetwork.account.handlers.AccountHandler +import app.softnetwork.account.message.AccountCommand +import app.softnetwork.payment.persistence.typed.MockSoftPaymentAccountBehavior +import app.softnetwork.persistence.typed.CommandTypeKey +import org.slf4j.{Logger, LoggerFactory} + +import scala.reflect.ClassTag + +trait MockBasicAccountTypeKey extends CommandTypeKey[AccountCommand] { + override def TypeKey(implicit tTag: ClassTag[AccountCommand]): EntityTypeKey[AccountCommand] = + MockSoftPaymentAccountBehavior.TypeKey +} + +object MockSoftPaymentAccountDao + extends SoftPaymentAccountDao + with AccountHandler + with MockBasicAccountTypeKey { + lazy val log: Logger = LoggerFactory getLogger getClass.getName +} diff --git a/testkit/src/main/scala/app/softnetwork/payment/persistence/typed/MockPaymentBehavior.scala b/testkit/src/main/scala/app/softnetwork/payment/persistence/typed/MockPaymentBehavior.scala index f7ea2d5..0d84a70 100644 --- a/testkit/src/main/scala/app/softnetwork/payment/persistence/typed/MockPaymentBehavior.scala +++ b/testkit/src/main/scala/app/softnetwork/payment/persistence/typed/MockPaymentBehavior.scala @@ -1,10 +1,22 @@ package app.softnetwork.payment.persistence.typed -import app.softnetwork.payment.handlers.{GenericPaymentDao, MockPaymentDao} -import app.softnetwork.payment.spi.MockMangoPayProvider +import app.softnetwork.payment.config.MangoPay +import app.softnetwork.payment.handlers.{ + GenericPaymentDao, + MockPaymentDao, + MockSoftPaymentAccountDao, + SoftPaymentAccountDao +} +import app.softnetwork.payment.model.SoftPaymentAccount.Client +import app.softnetwork.payment.model.SoftPaymentAccount.Client.Provider -case object MockPaymentBehavior extends GenericPaymentBehavior with MockMangoPayProvider { +object MockPaymentBehavior extends GenericPaymentBehavior { override def persistenceId = s"Mock${super.persistenceId}" override lazy val paymentDao: GenericPaymentDao = MockPaymentDao + + override lazy val softPaymentAccountDao: SoftPaymentAccountDao = MockSoftPaymentAccountDao + + override def defaultProvider: Client.Provider = + MangoPay.softPaymentProvider.withProviderType(Provider.ProviderType.MOCK) } diff --git a/testkit/src/main/scala/app/softnetwork/payment/persistence/typed/MockSoftPaymentAccountBehavior.scala b/testkit/src/main/scala/app/softnetwork/payment/persistence/typed/MockSoftPaymentAccountBehavior.scala new file mode 100644 index 0000000..64eceb5 --- /dev/null +++ b/testkit/src/main/scala/app/softnetwork/payment/persistence/typed/MockSoftPaymentAccountBehavior.scala @@ -0,0 +1,7 @@ +package app.softnetwork.payment.persistence.typed + +import app.softnetwork.account.handlers.MockGenerator + +object MockSoftPaymentAccountBehavior extends SoftPaymentAccountBehavior with MockGenerator { + override def persistenceId = "MockSoftPaymentAccount" +} diff --git a/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentEndpointsTestKit.scala b/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentEndpointsTestKit.scala index 380838a..4fef8fc 100644 --- a/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentEndpointsTestKit.scala +++ b/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentEndpointsTestKit.scala @@ -2,24 +2,42 @@ package app.softnetwork.payment.scalatest import akka.actor.typed.ActorSystem import app.softnetwork.api.server.Endpoint -import app.softnetwork.payment.launch.{PaymentEndpoints, PaymentGuardian} +import app.softnetwork.payment.launch.PaymentEndpoints import app.softnetwork.payment.service.{GenericPaymentEndpoints, MockPaymentEndpoints} import app.softnetwork.persistence.schema.SchemaProvider -import app.softnetwork.session.scalatest.SessionEndpointsRoutes +import app.softnetwork.session.scalatest.{SessionEndpointsRoutes, SessionTestKit} import app.softnetwork.session.CsrfCheck +import app.softnetwork.session.service.SessionMaterials +import com.softwaremill.session.{SessionConfig, SessionManager} +import org.slf4j.{Logger, LoggerFactory} +import org.softnetwork.session.model.Session + +import scala.concurrent.ExecutionContext trait PaymentEndpointsTestKit extends PaymentEndpoints with SessionEndpointsRoutes { - _: PaymentGuardian with SchemaProvider with CsrfCheck => + self: PaymentTestKit + with SessionTestKit + with SchemaProvider + with CsrfCheck + with SessionMaterials => - override def paymentEndpoints: ActorSystem[_] => GenericPaymentEndpoints = system => - MockPaymentEndpoints(system, sessionEndpoints(system)) + override def paymentEndpoints: ActorSystem[_] => GenericPaymentEndpoints = sys => + new MockPaymentEndpoints with SessionMaterials { + override implicit def manager(implicit + sessionConfig: SessionConfig + ): SessionManager[Session] = self.manager + override protected def sessionType: Session.SessionType = self.sessionType + override def log: Logger = LoggerFactory getLogger getClass.getName + override implicit def sessionConfig: SessionConfig = self.sessionConfig + override implicit def system: ActorSystem[_] = sys + override lazy val ec: ExecutionContext = sys.executionContext + } override def endpoints: ActorSystem[_] => List[Endpoint] = system => List( sessionServiceEndpoints(system), - paymentEndpoints(system), - MockPaymentEndpoints.swagger(system, sessionEndpoints(system)) + paymentEndpoints(system) ) } diff --git a/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentRouteTestKit.scala b/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentRouteTestKit.scala index 5d93d3a..5c390cc 100644 --- a/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentRouteTestKit.scala +++ b/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentRouteTestKit.scala @@ -8,12 +8,13 @@ import app.softnetwork.payment.api.PaymentGrpcServices import app.softnetwork.payment.config.PaymentSettings._ import app.softnetwork.payment.model._ import app.softnetwork.session.scalatest.SessionTestKit +import app.softnetwork.session.service.SessionMaterials import org.scalatest.Suite import java.nio.file.Paths trait PaymentRouteTestKit extends SessionTestKit with PaymentTestKit with PaymentGrpcServices { - _: Suite with ApiRoutes => + _: Suite with ApiRoutes with SessionMaterials => import app.softnetwork.serialization._ diff --git a/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentRoutesTestKit.scala b/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentRoutesTestKit.scala index 3f325f4..503429b 100644 --- a/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentRoutesTestKit.scala +++ b/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentRoutesTestKit.scala @@ -2,16 +2,31 @@ package app.softnetwork.payment.scalatest import akka.actor.typed.ActorSystem import app.softnetwork.api.server.ApiRoute -import app.softnetwork.payment.launch.{PaymentGuardian, PaymentRoutes} +import app.softnetwork.payment.launch.PaymentRoutes import app.softnetwork.payment.service.{GenericPaymentService, MockPaymentService} import app.softnetwork.persistence.schema.SchemaProvider -import app.softnetwork.session.scalatest.SessionServiceRoutes +import app.softnetwork.session.scalatest.{SessionServiceRoutes, SessionTestKit} +import app.softnetwork.session.service.SessionMaterials +import com.softwaremill.session.{SessionConfig, SessionManager} +import org.slf4j.{Logger, LoggerFactory} +import org.softnetwork.session.model.Session + +import scala.concurrent.ExecutionContext trait PaymentRoutesTestKit extends PaymentRoutes with SessionServiceRoutes { - _: PaymentGuardian with SchemaProvider => + self: PaymentTestKit with SessionTestKit with SchemaProvider with SessionMaterials => - override def paymentService: ActorSystem[_] => GenericPaymentService = system => - MockPaymentService(system, sessionService(system)) + override def paymentService: ActorSystem[_] => GenericPaymentService = sys => + new MockPaymentService with SessionMaterials { + override implicit def manager(implicit + sessionConfig: SessionConfig + ): SessionManager[Session] = self.manager + override protected def sessionType: Session.SessionType = self.sessionType + override def log: Logger = LoggerFactory getLogger getClass.getName + override implicit def sessionConfig: SessionConfig = self.sessionConfig + override implicit def system: ActorSystem[_] = sys + override lazy val ec: ExecutionContext = sys.executionContext + } override def apiRoutes: ActorSystem[_] => List[ApiRoute] = system => diff --git a/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentTestKit.scala b/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentTestKit.scala index 7a61b24..53a57ca 100644 --- a/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentTestKit.scala +++ b/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentTestKit.scala @@ -14,7 +14,12 @@ import app.softnetwork.payment.persistence.query.{ GenericPaymentCommandProcessorStream, Scheduler2PaymentProcessorStream } -import app.softnetwork.payment.persistence.typed.{GenericPaymentBehavior, MockPaymentBehavior} +import app.softnetwork.payment.persistence.typed.{ + GenericPaymentBehavior, + MockPaymentBehavior, + MockSoftPaymentAccountBehavior, + SoftPaymentAccountBehavior +} import app.softnetwork.persistence.launch.PersistentEntity import app.softnetwork.persistence.query.{ EventProcessorStream, @@ -23,12 +28,14 @@ import app.softnetwork.persistence.query.{ } import app.softnetwork.scheduler.config.SchedulerSettings import app.softnetwork.scheduler.scalatest.SchedulerTestKit +import app.softnetwork.session.service.SessionMaterials import org.scalatest.Suite import org.slf4j.{Logger, LoggerFactory} -import scala.concurrent.{ExecutionContextExecutor, Future} +import scala.concurrent.Future -trait PaymentTestKit extends SchedulerTestKit with PaymentGuardian { _: Suite => +trait PaymentTestKit extends SchedulerTestKit with PaymentGuardian { + _: Suite with SessionMaterials => /** @return * roles associated with this node @@ -38,6 +45,9 @@ trait PaymentTestKit extends SchedulerTestKit with PaymentGuardian { _: Suite => override def paymentAccountBehavior: ActorSystem[_] => GenericPaymentBehavior = _ => MockPaymentBehavior + override def softPaymentAccountBehavior: ActorSystem[_] => SoftPaymentAccountBehavior = _ => + MockSoftPaymentAccountBehavior + override def paymentCommandProcessorStream : ActorSystem[_] => GenericPaymentCommandProcessorStream = sys => new GenericPaymentCommandProcessorStream @@ -66,10 +76,7 @@ trait PaymentTestKit extends SchedulerTestKit with PaymentGuardian { _: Suite => transactionId: String, registerCard: Boolean, printReceipt: Boolean - )(implicit - system: ActorSystem[_] ): Future[Either[PayInFailed, Either[PaymentRedirection, PaidIn]]] = { - implicit val ec: ExecutionContextExecutor = system.executionContext MockPaymentHandler !? PayInFor3DS(orderUuid, transactionId, registerCard, printReceipt) map { case result: PaymentRedirection => Right(Left(result)) case result: PaidIn => Right(Right(result)) @@ -84,10 +91,7 @@ trait PaymentTestKit extends SchedulerTestKit with PaymentGuardian { _: Suite => preAuthorizationId: String, registerCard: Boolean = true, printReceipt: Boolean = false - )(implicit - system: ActorSystem[_] ): Future[Either[CardPreAuthorizationFailed, Either[PaymentRedirection, CardPreAuthorized]]] = { - implicit val ec: ExecutionContextExecutor = system.executionContext MockPaymentHandler !? PreAuthorizeCardFor3DS( orderUuid, preAuthorizationId, @@ -101,12 +105,12 @@ trait PaymentTestKit extends SchedulerTestKit with PaymentGuardian { _: Suite => } } - def payInFirstRecurringFor3DS(recurringPayInRegistrationId: String, transactionId: String)( - implicit system: ActorSystem[_] + def payInFirstRecurringFor3DS( + recurringPayInRegistrationId: String, + transactionId: String ): Future[ Either[FirstRecurringCardPaymentFailed, Either[PaymentRedirection, FirstRecurringPaidIn]] ] = { - implicit val ec: ExecutionContextExecutor = system.executionContext MockPaymentHandler !? PayInFirstRecurringFor3DS( recurringPayInRegistrationId, transactionId @@ -128,8 +132,7 @@ trait PaymentTestKit extends SchedulerTestKit with PaymentGuardian { _: Suite => def updateKycDocumentStatus( kycDocumentId: String, status: Option[KycDocument.KycDocumentStatus] = None - )(implicit system: ActorSystem[_]): Future[Either[PaymentError, KycDocumentStatusUpdated]] = { - implicit val ec: ExecutionContextExecutor = system.executionContext + ): Future[Either[PaymentError, KycDocumentStatusUpdated]] = { MockPaymentHandler !? UpdateKycDocumentStatus(kycDocumentId, status) map { case result: KycDocumentStatusUpdated => Right(result) case error: PaymentError => Left(error) @@ -140,18 +143,17 @@ trait PaymentTestKit extends SchedulerTestKit with PaymentGuardian { _: Suite => def updateUboDeclarationStatus( uboDeclarationId: String, status: Option[UboDeclaration.UboDeclarationStatus] = None - )(implicit system: ActorSystem[_]): Future[Boolean] = { - implicit val ec: ExecutionContextExecutor = system.executionContext + ): Future[Boolean] = { MockPaymentHandler !? UpdateUboDeclarationStatus(uboDeclarationId, status) map { case UboDeclarationStatusUpdated => true case _ => false } } - def updateMandateStatus(mandateId: String, status: Option[BankAccount.MandateStatus] = None)( - implicit system: ActorSystem[_] + def updateMandateStatus( + mandateId: String, + status: Option[BankAccount.MandateStatus] = None ): Future[Either[PaymentError, MandateStatusUpdated]] = { - implicit val ec: ExecutionContextExecutor = system.executionContext MockPaymentHandler !? UpdateMandateStatus(mandateId, status) map { case result: MandateStatusUpdated => Right(result) case error: PaymentError => Left(error) @@ -159,16 +161,14 @@ trait PaymentTestKit extends SchedulerTestKit with PaymentGuardian { _: Suite => } } - def validateRegularUser(userId: String)(implicit system: ActorSystem[_]): Future[Boolean] = { - implicit val ec: ExecutionContextExecutor = system.executionContext + def validateRegularUser(userId: String): Future[Boolean] = { MockPaymentHandler !? ValidateRegularUser(userId) map { case RegularUserValidated => true case _ => false } } - def invalidateRegularUser(userId: String)(implicit system: ActorSystem[_]): Future[Boolean] = { - implicit val ec: ExecutionContextExecutor = system.executionContext + def invalidateRegularUser(userId: String): Future[Boolean] = { MockPaymentHandler !? InvalidateRegularUser(userId) map { case RegularUserInvalidated => true case _ => false diff --git a/testkit/src/main/scala/app/softnetwork/payment/service/MockPaymentEndpoints.scala b/testkit/src/main/scala/app/softnetwork/payment/service/MockPaymentEndpoints.scala index 3c1275a..cb5cc22 100644 --- a/testkit/src/main/scala/app/softnetwork/payment/service/MockPaymentEndpoints.scala +++ b/testkit/src/main/scala/app/softnetwork/payment/service/MockPaymentEndpoints.scala @@ -1,33 +1,8 @@ package app.softnetwork.payment.service -import akka.actor.typed.ActorSystem -import app.softnetwork.api.server.SwaggerEndpoint import app.softnetwork.payment.handlers.MockPaymentHandler -import app.softnetwork.session.service.SessionEndpoints -import org.slf4j.{Logger, LoggerFactory} +import app.softnetwork.session.service.SessionMaterials -trait MockPaymentEndpoints extends MangoPayPaymentEndpoints with MockPaymentHandler - -object MockPaymentEndpoints { - def apply( - _system: ActorSystem[_], - _sessionEndpoints: SessionEndpoints - ): MockPaymentEndpoints = { - new MockPaymentEndpoints { - lazy val log: Logger = LoggerFactory getLogger getClass.getName - override implicit def system: ActorSystem[_] = _system - override def sessionEndpoints: SessionEndpoints = _sessionEndpoints - } - } - - def swagger( - _system: ActorSystem[_], - _sessionEndpoints: SessionEndpoints - ): SwaggerEndpoint = { - new MockPaymentEndpoints with SwaggerEndpoint { - lazy val log: Logger = LoggerFactory getLogger getClass.getName - override implicit def system: ActorSystem[_] = _system - override def sessionEndpoints: SessionEndpoints = _sessionEndpoints - } - } +trait MockPaymentEndpoints extends MangoPayPaymentEndpoints with MockPaymentHandler { + _: SessionMaterials => } diff --git a/testkit/src/main/scala/app/softnetwork/payment/service/MockPaymentService.scala b/testkit/src/main/scala/app/softnetwork/payment/service/MockPaymentService.scala index e23f71c..b5c9139 100644 --- a/testkit/src/main/scala/app/softnetwork/payment/service/MockPaymentService.scala +++ b/testkit/src/main/scala/app/softnetwork/payment/service/MockPaymentService.scala @@ -1,18 +1,8 @@ package app.softnetwork.payment.service -import akka.actor.typed.ActorSystem import app.softnetwork.payment.handlers.MockPaymentHandler -import app.softnetwork.session.service.SessionService -import org.slf4j.{Logger, LoggerFactory} +import app.softnetwork.session.service.SessionMaterials -trait MockPaymentService extends MangoPayPaymentService with MockPaymentHandler - -object MockPaymentService { - def apply(_system: ActorSystem[_], _sessionService: SessionService): MockPaymentService = { - new MockPaymentService { - lazy val log: Logger = LoggerFactory getLogger getClass.getName - override implicit def system: ActorSystem[_] = _system - override def sessionService: SessionService = _sessionService - } - } +trait MockPaymentService extends MangoPayPaymentService with MockPaymentHandler { + _: SessionMaterials => } diff --git a/testkit/src/main/scala/app/softnetwork/payment/spi/MockMangoPayProvider.scala b/testkit/src/main/scala/app/softnetwork/payment/spi/MockMangoPayProvider.scala index d4634cc..5b07e4c 100644 --- a/testkit/src/main/scala/app/softnetwork/payment/spi/MockMangoPayProvider.scala +++ b/testkit/src/main/scala/app/softnetwork/payment/spi/MockMangoPayProvider.scala @@ -3,6 +3,8 @@ package app.softnetwork.payment.spi import app.softnetwork.payment.config.MangoPaySettings.MangoPayConfig._ import app.softnetwork.payment.model.PaymentUser.PaymentUserType import app.softnetwork.payment.model.RecurringPayment.RecurringCardPaymentState +import app.softnetwork.payment.model.SoftPaymentAccount.Client +import app.softnetwork.payment.model.SoftPaymentAccount.Client.Provider import app.softnetwork.payment.model.{RecurringPayment, _} import app.softnetwork.persistence._ import app.softnetwork.time.DateExtensions @@ -1236,6 +1238,13 @@ trait MockMangoPayProvider extends MangoPayProvider { } } + override def client: Option[SoftPaymentAccount.Client] = + Some( + SoftPaymentAccount.Client.defaultInstance + .withProvider(provider) + .withClientId(s"${generateUUID()}.${provider.providerType.name.toLowerCase}") + ) + /** @return * client fees */ @@ -1710,3 +1719,12 @@ case class RecurringCardPaymentRegistration( currentState: RecurringCardPaymentState, registration: CreateRecurringPayment ) + +class MockMangoPayProviderFactory extends PaymentProviderSpi { + override val providerType: Provider.ProviderType = Provider.ProviderType.MOCK + + override def paymentProvider(p: Client.Provider): MockMangoPayProvider = + new MockMangoPayProvider { + override implicit def provider: Provider = p + } +} diff --git a/testkit/src/test/scala/app/softnetwork/payment/handlers/PaymentHandlerSpec.scala b/testkit/src/test/scala/app/softnetwork/payment/handlers/PaymentHandlerSpec.scala index 4b9e2ab..1df8fd1 100644 --- a/testkit/src/test/scala/app/softnetwork/payment/handlers/PaymentHandlerSpec.scala +++ b/testkit/src/test/scala/app/softnetwork/payment/handlers/PaymentHandlerSpec.scala @@ -9,8 +9,11 @@ import app.softnetwork.payment.model._ import app.softnetwork.payment.scalatest.PaymentTestKit import app.softnetwork.time._ import app.softnetwork.persistence.now +import app.softnetwork.session.config.Settings +import app.softnetwork.session.service.BasicSessionMaterials import org.scalatest.wordspec.AnyWordSpecLike import org.slf4j.{Logger, LoggerFactory} +import org.softnetwork.session.model.Session import java.time.LocalDate import scala.language.implicitConversions @@ -20,13 +23,17 @@ class PaymentHandlerSpec extends MockPaymentHandler with AnyWordSpecLike with PaymentGrpcServer - with PaymentTestKit { + with PaymentTestKit + with BasicSessionMaterials { lazy val log: Logger = LoggerFactory getLogger getClass.getName - implicit lazy val system: ActorSystem[_] = typedSystem() + override implicit lazy val ts: ActorSystem[_] = typedSystem() - lazy val client: PaymentClient = PaymentClient(system) + override protected def sessionType: Session.SessionType = + Settings.Session.SessionContinuityAndTransport + + lazy val client: PaymentClient = PaymentClient(ts) "Payment handler" must { "pre register card" in { diff --git a/testkit/src/test/scala/app/softnetwork/payment/service/PaymentEndpointsWithOneOffCookieSessionSpec.scala b/testkit/src/test/scala/app/softnetwork/payment/service/PaymentEndpointsWithOneOffCookieSessionSpec.scala index 667032c..2d37913 100644 --- a/testkit/src/test/scala/app/softnetwork/payment/service/PaymentEndpointsWithOneOffCookieSessionSpec.scala +++ b/testkit/src/test/scala/app/softnetwork/payment/service/PaymentEndpointsWithOneOffCookieSessionSpec.scala @@ -3,9 +3,11 @@ package app.softnetwork.payment.service import app.softnetwork.payment.scalatest.PaymentEndpointsTestKit import app.softnetwork.session.scalatest.OneOffCookieSessionEndpointsTestKit import app.softnetwork.session.CsrfCheckHeader +import app.softnetwork.session.service.BasicSessionMaterials class PaymentEndpointsWithOneOffCookieSessionSpec extends PaymentServiceSpec with OneOffCookieSessionEndpointsTestKit with PaymentEndpointsTestKit with CsrfCheckHeader + with BasicSessionMaterials diff --git a/testkit/src/test/scala/app/softnetwork/payment/service/PaymentEndpointsWithOneOffHeaderSessionSpec.scala b/testkit/src/test/scala/app/softnetwork/payment/service/PaymentEndpointsWithOneOffHeaderSessionSpec.scala index 05195d1..1a526b4 100644 --- a/testkit/src/test/scala/app/softnetwork/payment/service/PaymentEndpointsWithOneOffHeaderSessionSpec.scala +++ b/testkit/src/test/scala/app/softnetwork/payment/service/PaymentEndpointsWithOneOffHeaderSessionSpec.scala @@ -3,9 +3,11 @@ package app.softnetwork.payment.service import app.softnetwork.payment.scalatest.PaymentEndpointsTestKit import app.softnetwork.session.scalatest.OneOffHeaderSessionEndpointsTestKit import app.softnetwork.session.CsrfCheckHeader +import app.softnetwork.session.service.BasicSessionMaterials class PaymentEndpointsWithOneOffHeaderSessionSpec extends PaymentServiceSpec with OneOffHeaderSessionEndpointsTestKit with PaymentEndpointsTestKit with CsrfCheckHeader + with BasicSessionMaterials diff --git a/testkit/src/test/scala/app/softnetwork/payment/service/PaymentEndpointsWithRefreshableCookieSessionSpec.scala b/testkit/src/test/scala/app/softnetwork/payment/service/PaymentEndpointsWithRefreshableCookieSessionSpec.scala index 13fe4e5..236ff27 100644 --- a/testkit/src/test/scala/app/softnetwork/payment/service/PaymentEndpointsWithRefreshableCookieSessionSpec.scala +++ b/testkit/src/test/scala/app/softnetwork/payment/service/PaymentEndpointsWithRefreshableCookieSessionSpec.scala @@ -3,9 +3,11 @@ package app.softnetwork.payment.service import app.softnetwork.payment.scalatest.PaymentEndpointsTestKit import app.softnetwork.session.scalatest.RefreshableCookieSessionEndpointsTestKit import app.softnetwork.session.CsrfCheckHeader +import app.softnetwork.session.service.BasicSessionMaterials class PaymentEndpointsWithRefreshableCookieSessionSpec extends PaymentServiceSpec with RefreshableCookieSessionEndpointsTestKit with PaymentEndpointsTestKit with CsrfCheckHeader + with BasicSessionMaterials diff --git a/testkit/src/test/scala/app/softnetwork/payment/service/PaymentEndpointsWithRefreshableHeaderSessionSpec.scala b/testkit/src/test/scala/app/softnetwork/payment/service/PaymentEndpointsWithRefreshableHeaderSessionSpec.scala index 483cbb4..1c82c17 100644 --- a/testkit/src/test/scala/app/softnetwork/payment/service/PaymentEndpointsWithRefreshableHeaderSessionSpec.scala +++ b/testkit/src/test/scala/app/softnetwork/payment/service/PaymentEndpointsWithRefreshableHeaderSessionSpec.scala @@ -3,9 +3,11 @@ package app.softnetwork.payment.service import app.softnetwork.payment.scalatest.PaymentEndpointsTestKit import app.softnetwork.session.scalatest.RefreshableHeaderSessionEndpointsTestKit import app.softnetwork.session.CsrfCheckHeader +import app.softnetwork.session.service.BasicSessionMaterials class PaymentEndpointsWithRefreshableHeaderSessionSpec extends PaymentServiceSpec with RefreshableHeaderSessionEndpointsTestKit with PaymentEndpointsTestKit with CsrfCheckHeader + with BasicSessionMaterials diff --git a/testkit/src/test/scala/app/softnetwork/payment/service/PaymentRoutesWithOneOffCookieSessionSpec.scala b/testkit/src/test/scala/app/softnetwork/payment/service/PaymentRoutesWithOneOffCookieSessionSpec.scala index aacfc5c..b9a32c8 100644 --- a/testkit/src/test/scala/app/softnetwork/payment/service/PaymentRoutesWithOneOffCookieSessionSpec.scala +++ b/testkit/src/test/scala/app/softnetwork/payment/service/PaymentRoutesWithOneOffCookieSessionSpec.scala @@ -2,8 +2,10 @@ package app.softnetwork.payment.service import app.softnetwork.payment.scalatest.PaymentRoutesTestKit import app.softnetwork.session.scalatest.OneOffCookieSessionServiceTestKit +import app.softnetwork.session.service.BasicSessionMaterials class PaymentRoutesWithOneOffCookieSessionSpec extends PaymentServiceSpec with OneOffCookieSessionServiceTestKit with PaymentRoutesTestKit + with BasicSessionMaterials diff --git a/testkit/src/test/scala/app/softnetwork/payment/service/PaymentRoutesWithOneOffHeaderSessionSpec.scala b/testkit/src/test/scala/app/softnetwork/payment/service/PaymentRoutesWithOneOffHeaderSessionSpec.scala index 0fb196b..ea65a41 100644 --- a/testkit/src/test/scala/app/softnetwork/payment/service/PaymentRoutesWithOneOffHeaderSessionSpec.scala +++ b/testkit/src/test/scala/app/softnetwork/payment/service/PaymentRoutesWithOneOffHeaderSessionSpec.scala @@ -2,8 +2,10 @@ package app.softnetwork.payment.service import app.softnetwork.payment.scalatest.PaymentRoutesTestKit import app.softnetwork.session.scalatest.OneOffHeaderSessionServiceTestKit +import app.softnetwork.session.service.BasicSessionMaterials class PaymentRoutesWithOneOffHeaderSessionSpec extends PaymentServiceSpec with OneOffHeaderSessionServiceTestKit with PaymentRoutesTestKit + with BasicSessionMaterials diff --git a/testkit/src/test/scala/app/softnetwork/payment/service/PaymentRoutesWithRefreshableCookieSessionSpec.scala b/testkit/src/test/scala/app/softnetwork/payment/service/PaymentRoutesWithRefreshableCookieSessionSpec.scala index 4b1857c..3d104e2 100644 --- a/testkit/src/test/scala/app/softnetwork/payment/service/PaymentRoutesWithRefreshableCookieSessionSpec.scala +++ b/testkit/src/test/scala/app/softnetwork/payment/service/PaymentRoutesWithRefreshableCookieSessionSpec.scala @@ -2,8 +2,10 @@ package app.softnetwork.payment.service import app.softnetwork.payment.scalatest.PaymentRoutesTestKit import app.softnetwork.session.scalatest.RefreshableCookieSessionServiceTestKit +import app.softnetwork.session.service.BasicSessionMaterials class PaymentRoutesWithRefreshableCookieSessionSpec extends PaymentServiceSpec with RefreshableCookieSessionServiceTestKit with PaymentRoutesTestKit + with BasicSessionMaterials diff --git a/testkit/src/test/scala/app/softnetwork/payment/service/PaymentRoutesWithRefreshableHeaderSessionSpec.scala b/testkit/src/test/scala/app/softnetwork/payment/service/PaymentRoutesWithRefreshableHeaderSessionSpec.scala index 447746d..731f8cc 100644 --- a/testkit/src/test/scala/app/softnetwork/payment/service/PaymentRoutesWithRefreshableHeaderSessionSpec.scala +++ b/testkit/src/test/scala/app/softnetwork/payment/service/PaymentRoutesWithRefreshableHeaderSessionSpec.scala @@ -2,8 +2,10 @@ package app.softnetwork.payment.service import app.softnetwork.payment.scalatest.PaymentRoutesTestKit import app.softnetwork.session.scalatest.RefreshableHeaderSessionServiceTestKit +import app.softnetwork.session.service.BasicSessionMaterials class PaymentRoutesWithRefreshableHeaderSessionSpec extends PaymentServiceSpec with RefreshableHeaderSessionServiceTestKit with PaymentRoutesTestKit + with BasicSessionMaterials diff --git a/testkit/src/test/scala/app/softnetwork/payment/service/PaymentServiceSpec.scala b/testkit/src/test/scala/app/softnetwork/payment/service/PaymentServiceSpec.scala index f7533ea..bc28cf9 100644 --- a/testkit/src/test/scala/app/softnetwork/payment/service/PaymentServiceSpec.scala +++ b/testkit/src/test/scala/app/softnetwork/payment/service/PaymentServiceSpec.scala @@ -12,6 +12,7 @@ import app.softnetwork.payment.model._ import app.softnetwork.payment.scalatest.PaymentRouteTestKit import app.softnetwork.time._ import app.softnetwork.persistence.now +import app.softnetwork.session.service.SessionMaterials import org.scalatest.wordspec.AnyWordSpecLike import org.slf4j.{Logger, LoggerFactory} @@ -20,7 +21,8 @@ import java.time.LocalDate import scala.language.implicitConversions import scala.util.{Failure, Success} -trait PaymentServiceSpec extends AnyWordSpecLike with PaymentRouteTestKit { _: ApiRoutes => +trait PaymentServiceSpec extends AnyWordSpecLike with PaymentRouteTestKit { + _: ApiRoutes with SessionMaterials => lazy val log: Logger = LoggerFactory getLogger getClass.getName From 236096f3c584eb09693c663cedbbef82fb3c548e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Manciot?= Date: Wed, 22 Nov 2023 19:54:11 +0100 Subject: [PATCH 02/37] update payment guardian to extend account guardian --- .../payment/launch/PaymentGuardian.scala | 21 +++-- .../typed/SoftPaymentAccountBehavior.scala | 2 +- .../api/src/main/resources/reference.conf | 7 +- .../payment/api/BasicServiceEndpoint.scala | 67 --------------- .../payment/api/BasicServiceRoute.scala | 81 ------------------- .../softnetwork/payment/api/MangoPayApi.scala | 44 +++++++++- .../payment/api/MangoPayEndpoints.scala | 20 ++++- .../payment/api/MangoPayRoutes.scala | 3 + project/Versions.scala | 2 + .../handlers/MockSoftPaymentAccountDao.scala | 7 +- .../scalatest/PaymentRouteTestKit.scala | 3 + .../payment/scalatest/PaymentTestKit.scala | 49 ++++++++--- .../payment/handlers/PaymentHandlerSpec.scala | 22 ++--- .../payment/service/PaymentServiceSpec.scala | 10 +-- 14 files changed, 140 insertions(+), 198 deletions(-) delete mode 100644 mangopay/api/src/main/scala/app/softnetwork/payment/api/BasicServiceEndpoint.scala delete mode 100644 mangopay/api/src/main/scala/app/softnetwork/payment/api/BasicServiceRoute.scala diff --git a/core/src/main/scala/app/softnetwork/payment/launch/PaymentGuardian.scala b/core/src/main/scala/app/softnetwork/payment/launch/PaymentGuardian.scala index 3f2b45f..9455142 100644 --- a/core/src/main/scala/app/softnetwork/payment/launch/PaymentGuardian.scala +++ b/core/src/main/scala/app/softnetwork/payment/launch/PaymentGuardian.scala @@ -1,41 +1,38 @@ package app.softnetwork.payment.launch import akka.actor.typed.ActorSystem +import app.softnetwork.account.launch.AccountGuardian +import app.softnetwork.account.model.BasicAccountProfile import app.softnetwork.payment.PaymentCoreBuildInfo +import app.softnetwork.payment.model.SoftPaymentAccount import app.softnetwork.payment.persistence.data.paymentKvDao import app.softnetwork.payment.persistence.query.{ GenericPaymentCommandProcessorStream, Scheduler2PaymentProcessorStream } -import app.softnetwork.payment.persistence.typed.{ - GenericPaymentBehavior, - SoftPaymentAccountBehavior -} +import app.softnetwork.payment.persistence.typed.GenericPaymentBehavior import app.softnetwork.persistence.launch.PersistentEntity import app.softnetwork.persistence.query.EventProcessorStream import app.softnetwork.persistence.schema.SchemaProvider import app.softnetwork.persistence.typed.Singleton import app.softnetwork.session.CsrfCheck -import app.softnetwork.session.launch.SessionGuardian -trait PaymentGuardian extends SessionGuardian { _: SchemaProvider with CsrfCheck => +trait PaymentGuardian extends AccountGuardian[SoftPaymentAccount, BasicAccountProfile] { + _: SchemaProvider with CsrfCheck => import app.softnetwork.persistence.launch.PersistenceGuardian._ def paymentAccountBehavior: ActorSystem[_] => GenericPaymentBehavior - def softPaymentAccountBehavior: ActorSystem[_] => SoftPaymentAccountBehavior - def paymentEntities: ActorSystem[_] => Seq[PersistentEntity[_, _, _, _]] = sys => Seq( - paymentAccountBehavior(sys), - softPaymentAccountBehavior(sys) + paymentAccountBehavior(sys) ) /** initialize all entities */ override def entities: ActorSystem[_] => Seq[PersistentEntity[_, _, _, _]] = sys => - sessionEntities(sys) ++ paymentEntities(sys) + sessionEntities(sys) ++ accountEntities(sys) ++ paymentEntities(sys) /** initialize all singletons */ @@ -51,7 +48,7 @@ trait PaymentGuardian extends SessionGuardian { _: SchemaProvider with CsrfCheck /** initialize all event processor streams */ override def eventProcessorStreams: ActorSystem[_] => Seq[EventProcessorStream[_]] = sys => - paymentEventProcessorStreams(sys) + paymentEventProcessorStreams(sys) ++ accountEventProcessorStreams(sys) override def systemVersion(): String = sys.env.getOrElse("VERSION", PaymentCoreBuildInfo.version) diff --git a/core/src/main/scala/app/softnetwork/payment/persistence/typed/SoftPaymentAccountBehavior.scala b/core/src/main/scala/app/softnetwork/payment/persistence/typed/SoftPaymentAccountBehavior.scala index d75ca7b..ebca6aa 100644 --- a/core/src/main/scala/app/softnetwork/payment/persistence/typed/SoftPaymentAccountBehavior.scala +++ b/core/src/main/scala/app/softnetwork/payment/persistence/typed/SoftPaymentAccountBehavior.scala @@ -50,7 +50,7 @@ trait SoftPaymentAccountBehavior extends AccountBehavior[SoftPaymentAccount, Bas ) case _ => None } - case _ => None + case _ => SoftPaymentAccount(BasicAccount(cmd, Some(entityId))) } } diff --git a/mangopay/api/src/main/resources/reference.conf b/mangopay/api/src/main/resources/reference.conf index 95e0548..b1319a4 100644 --- a/mangopay/api/src/main/resources/reference.conf +++ b/mangopay/api/src/main/resources/reference.conf @@ -7,4 +7,9 @@ softnetwork.api.server.port = 9000 softnetwork.api.server.request-timeout = 120 s softnetwork.api.server.swagger-path-prefix = ["swagger", "payment"] -akka.cluster.roles = [${payment.akka-node-role}, ${softnetwork.scheduler.akka-node-role}] +akka.cluster.roles = [ + ${payment.akka-node-role}, + ${auth.akka-node-role}, + ${notification.akka-node-role}, + ${softnetwork.scheduler.akka-node-role} +] diff --git a/mangopay/api/src/main/scala/app/softnetwork/payment/api/BasicServiceEndpoint.scala b/mangopay/api/src/main/scala/app/softnetwork/payment/api/BasicServiceEndpoint.scala deleted file mode 100644 index 1cb686a..0000000 --- a/mangopay/api/src/main/scala/app/softnetwork/payment/api/BasicServiceEndpoint.scala +++ /dev/null @@ -1,67 +0,0 @@ -package app.softnetwork.payment.api - -import akka.actor.typed.ActorSystem -import app.softnetwork.api.server.ApiEndpoint -import app.softnetwork.session.service.SessionEndpoints -import com.softwaremill.session.{GetSessionTransport, SetSessionTransport} -import app.softnetwork.session.{TapirCsrfCheckMode, TapirEndpoints, TapirSessionContinuity} -import org.softnetwork.session.model.Session -import sttp.model.headers.WWWAuthenticateChallenge -import sttp.tapir._ -import sttp.tapir.model.UsernamePassword -import sttp.tapir.server.{PartialServerEndpointWithSecurityOutput, ServerEndpoint} - -import scala.concurrent.{ExecutionContext, Future} -import scala.language.implicitConversions - -trait BasicServiceEndpoint extends ApiEndpoint with TapirEndpoints { - - def sessionEndpoints: SessionEndpoints - - def sc: TapirSessionContinuity[Session] = sessionEndpoints.sc - - def st: SetSessionTransport = sessionEndpoints.st - - def gt: GetSessionTransport = sessionEndpoints.gt - - def checkMode: TapirCsrfCheckMode[Session] = sessionEndpoints.checkMode - - implicit def usernamePassword2Session(credentials: UsernamePassword): Option[Session] = { - Some(Session(credentials.username)) - } - - val emptySecurityEndpoint - : PartialServerEndpointWithSecurityOutput[Unit, Unit, Unit, Unit, Unit, Unit, Any, Future] = - endpoint.serverSecurityLogicSuccessWithOutput(_ => Future.successful(((), ()))) - - val createSessionEndpoint: ServerEndpoint[Any, Future] = { - hmacTokenCsrfProtection(checkMode) { - setSessionWithAuth(sc, st)( - auth.basic[UsernamePassword](WWWAuthenticateChallenge.basic("Basic Realm")) - ) - }.post - .in("auth" / "basic") - .serverLogicSuccess(_ => _ => Future.successful(())) - } - - val invalidateSessionEndpoint: ServerEndpoint[Any, Future] = - sessionEndpoints - .invalidateSession(sc, st) { - emptySecurityEndpoint - } - .delete - .in("auth" / "basic") - .serverLogicSuccess(_ => _ => Future.successful(())) - - override def endpoints: List[ServerEndpoint[Any, Future]] = - List(createSessionEndpoint, invalidateSessionEndpoint) - -} - -object BasicServiceEndpoint { - def apply(_system: ActorSystem[_], _sessionEndpoints: SessionEndpoints): BasicServiceEndpoint = - new BasicServiceEndpoint { - override def sessionEndpoints: SessionEndpoints = _sessionEndpoints - override implicit def ec: ExecutionContext = _system.executionContext - } -} diff --git a/mangopay/api/src/main/scala/app/softnetwork/payment/api/BasicServiceRoute.scala b/mangopay/api/src/main/scala/app/softnetwork/payment/api/BasicServiceRoute.scala deleted file mode 100644 index b63d848..0000000 --- a/mangopay/api/src/main/scala/app/softnetwork/payment/api/BasicServiceRoute.scala +++ /dev/null @@ -1,81 +0,0 @@ -package app.softnetwork.payment.api - -import akka.actor.typed.ActorSystem -import akka.http.scaladsl.model.{HttpResponse, StatusCodes} -import akka.http.scaladsl.server.{Directives, Route} -import akka.http.scaladsl.server.directives.Credentials -import app.softnetwork.api.server.DefaultComplete -import app.softnetwork.session.service.SessionService -import com.softwaremill.session.CsrfDirectives.{hmacTokenCsrfProtection, setNewCsrfToken} -import com.softwaremill.session.CsrfOptions.checkHeader -import de.heikoseeberger.akkahttpjson4s.Json4sSupport -import org.json4s.Formats -import org.softnetwork.session.model.Session - -trait BasicServiceRoute extends Directives with DefaultComplete with Json4sSupport { - - import app.softnetwork.persistence.generateUUID - import app.softnetwork.serialization._ - - import Session._ - - implicit def formats: Formats = commonFormats - - def sessionService: SessionService - - val route: Route = { - pathPrefix("auth") { - basic - } - } - - lazy val basic: Route = path("basic") { - get { - // check anti CSRF token - hmacTokenCsrfProtection(checkHeader) { - // check if a session exists - sessionService.requiredSession { session => - complete(HttpResponse(StatusCodes.OK, entity = session.id)) - } - } - } ~ post { - authenticateBasic("Basic Realm", BasicAuthAuthenticator) { identifier => - // create a new session - val session = Session(generateUUID(identifier)) - sessionService.setSession(session) { - // create a new anti csrf token - setNewCsrfToken(checkHeader) { - complete(HttpResponse(StatusCodes.OK, entity = session.id)) - } - } - } - } ~ delete { - // check anti CSRF token - hmacTokenCsrfProtection(checkHeader) { - // check if a session exists - sessionService.requiredSession { _ => - // invalidate session - sessionService.invalidateSession { - complete(HttpResponse(StatusCodes.OK)) - } - } - } - } - } - - private def BasicAuthAuthenticator(credentials: Credentials): Option[String] = { - credentials match { - case p @ Credentials.Provided(_) => Some(p.identifier) - case _ => None - } - } - -} - -object BasicServiceRoute { - def apply(_system: ActorSystem[_], _sessionService: SessionService): BasicServiceRoute = { - new BasicServiceRoute { - override def sessionService: SessionService = _sessionService - } - } -} diff --git a/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayApi.scala b/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayApi.scala index 0490348..3a6ff86 100644 --- a/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayApi.scala +++ b/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayApi.scala @@ -2,33 +2,64 @@ package app.softnetwork.payment.api import akka.actor.typed.ActorSystem import akka.http.scaladsl.model.{HttpRequest, HttpResponse} +import app.softnetwork.account.handlers.AccountDao +import app.softnetwork.account.model.BasicAccountProfile +import app.softnetwork.account.persistence.query.AccountEventProcessorStreams.InternalAccountEvents2AccountProcessorStream +import app.softnetwork.account.persistence.typed.AccountBehavior import app.softnetwork.api.server.SwaggerEndpoint -import app.softnetwork.payment.handlers.MangoPayPaymentHandler +import app.softnetwork.payment.handlers.{ + MangoPayPaymentHandler, + SoftPaymentAccountDao, + SoftPaymentAccountTypeKey +} import app.softnetwork.payment.launch.PaymentApplication +import app.softnetwork.payment.model.SoftPaymentAccount import app.softnetwork.payment.persistence.query.{ GenericPaymentCommandProcessorStream, Scheduler2PaymentProcessorStream } -import app.softnetwork.payment.persistence.typed.{GenericPaymentBehavior, MangoPayPaymentBehavior} +import app.softnetwork.payment.persistence.typed.{ + GenericPaymentBehavior, + MangoPayPaymentBehavior, + SoftPaymentAccountBehavior +} import app.softnetwork.payment.service.MangoPayPaymentEndpoints import app.softnetwork.persistence.jdbc.query.{JdbcJournalProvider, JdbcOffsetProvider} import app.softnetwork.persistence.schema.SchemaProvider import app.softnetwork.scheduler.config.SchedulerSettings import app.softnetwork.session.CsrfCheck import app.softnetwork.session.config.Settings +import app.softnetwork.session.model.SessionManagers import app.softnetwork.session.service.SessionMaterials import com.softwaremill.session.{SessionConfig, SessionManager} import com.typesafe.config.Config import org.slf4j.{Logger, LoggerFactory} import org.softnetwork.session.model.Session -import scala.concurrent.Future +import scala.concurrent.{ExecutionContext, Future} trait MangoPayApi extends PaymentApplication { self: SchemaProvider with CsrfCheck => override def paymentAccountBehavior: ActorSystem[_] => GenericPaymentBehavior = _ => MangoPayPaymentBehavior + override def accountBehavior + : ActorSystem[_] => AccountBehavior[SoftPaymentAccount, BasicAccountProfile] = _ => + SoftPaymentAccountBehavior + + override def accountDao: AccountDao = SoftPaymentAccountDao + + override def internalAccountEvents2AccountProcessorStream + : ActorSystem[_] => InternalAccountEvents2AccountProcessorStream = sys => + new InternalAccountEvents2AccountProcessorStream + with SoftPaymentAccountTypeKey + with JdbcJournalProvider + with JdbcOffsetProvider { + override def config: Config = MangoPayApi.this.config + override def tag: String = s"${SoftPaymentAccountBehavior.persistenceId}-to-internal" + override implicit def system: ActorSystem[_] = sys + } + override def paymentCommandProcessorStream : ActorSystem[_] => GenericPaymentCommandProcessorStream = sys => new GenericPaymentCommandProcessorStream @@ -59,6 +90,12 @@ trait MangoPayApi extends PaymentApplication { self: SchemaProvider with CsrfChe def sessionConfig: SessionConfig = Settings.Session.DefaultSessionConfig + override protected def sessionType: Session.SessionType = + Settings.Session.SessionContinuityAndTransport + + override protected def manager(implicit sessionConfig: SessionConfig): SessionManager[Session] = + SessionManagers.basic + def paymentSwagger: ActorSystem[_] => SwaggerEndpoint = sys => new MangoPayPaymentEndpoints with SwaggerEndpoint with SessionMaterials { override implicit def manager(implicit @@ -68,6 +105,7 @@ trait MangoPayApi extends PaymentApplication { self: SchemaProvider with CsrfChe override def log: Logger = LoggerFactory getLogger getClass.getName override implicit def sessionConfig: SessionConfig = self.sessionConfig override implicit def system: ActorSystem[_] = sys + override lazy val ec: ExecutionContext = sys.executionContext override val applicationVersion: String = systemVersion() } } diff --git a/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayEndpoints.scala b/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayEndpoints.scala index 5ed5636..b8cf77f 100644 --- a/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayEndpoints.scala +++ b/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayEndpoints.scala @@ -6,11 +6,25 @@ import app.softnetwork.payment.launch.PaymentEndpoints import app.softnetwork.payment.service.{GenericPaymentEndpoints, MangoPayPaymentEndpoints} import app.softnetwork.persistence.schema.SchemaProvider import app.softnetwork.session.CsrfCheck +import app.softnetwork.session.service.SessionMaterials +import com.softwaremill.session.{SessionConfig, SessionManager} +import org.softnetwork.session.model.Session + +import scala.concurrent.ExecutionContext trait MangoPayEndpoints extends PaymentEndpoints { - _: MangoPayApi with SchemaProvider with CsrfCheck => - override def paymentEndpoints: ActorSystem[_] => GenericPaymentEndpoints = system => - MangoPayPaymentEndpoints(system, sessionEndpoints(system)) + self: MangoPayApi with SchemaProvider with CsrfCheck => + override def paymentEndpoints: ActorSystem[_] => GenericPaymentEndpoints = sys => + new MangoPayPaymentEndpoints with SessionMaterials { + override def log: org.slf4j.Logger = org.slf4j.LoggerFactory.getLogger(getClass) + override implicit def system: ActorSystem[_] = sys + override lazy val ec: ExecutionContext = sys.executionContext + override implicit def manager(implicit + sessionConfig: SessionConfig + ): SessionManager[Session] = self.manager + override protected def sessionType: Session.SessionType = self.sessionType + override implicit def sessionConfig: SessionConfig = self.sessionConfig + } override def endpoints: ActorSystem[_] => List[Endpoint] = system => super.endpoints(system) :+ paymentSwagger(system) diff --git a/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayRoutes.scala b/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayRoutes.scala index 3ec9cf0..7b77742 100644 --- a/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayRoutes.scala +++ b/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayRoutes.scala @@ -10,6 +10,8 @@ import com.softwaremill.session.{SessionConfig, SessionManager} import org.slf4j.{Logger, LoggerFactory} import org.softnetwork.session.model.Session +import scala.concurrent.ExecutionContext + trait MangoPayRoutes extends PaymentRoutes { self: MangoPayApi with SchemaProvider => override def paymentService: ActorSystem[_] => GenericPaymentService = sys => @@ -21,6 +23,7 @@ trait MangoPayRoutes extends PaymentRoutes { self: MangoPayApi with SchemaProvid override def log: Logger = LoggerFactory getLogger getClass.getName override implicit def sessionConfig: SessionConfig = self.sessionConfig override implicit def system: ActorSystem[_] = sys + override lazy val ec: ExecutionContext = sys.executionContext } override def apiRoutes: ActorSystem[_] => List[ApiRoute] = system => diff --git a/project/Versions.scala b/project/Versions.scala index b39226f..8d45c62 100644 --- a/project/Versions.scala +++ b/project/Versions.scala @@ -4,6 +4,8 @@ object Versions { val scheduler = "0.5.0" + val notification = "0.5.0" + val account = "0.5.0" val scalatest = "3.2.16" diff --git a/testkit/src/main/scala/app/softnetwork/payment/handlers/MockSoftPaymentAccountDao.scala b/testkit/src/main/scala/app/softnetwork/payment/handlers/MockSoftPaymentAccountDao.scala index 3840059..18ff743 100644 --- a/testkit/src/main/scala/app/softnetwork/payment/handlers/MockSoftPaymentAccountDao.scala +++ b/testkit/src/main/scala/app/softnetwork/payment/handlers/MockSoftPaymentAccountDao.scala @@ -14,9 +14,8 @@ trait MockBasicAccountTypeKey extends CommandTypeKey[AccountCommand] { MockSoftPaymentAccountBehavior.TypeKey } -object MockSoftPaymentAccountDao - extends SoftPaymentAccountDao - with AccountHandler - with MockBasicAccountTypeKey { +trait MockSoftPaymentAccountHandler extends AccountHandler with MockBasicAccountTypeKey + +object MockSoftPaymentAccountDao extends SoftPaymentAccountDao with MockSoftPaymentAccountHandler { lazy val log: Logger = LoggerFactory getLogger getClass.getName } diff --git a/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentRouteTestKit.scala b/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentRouteTestKit.scala index 5c390cc..f4455c6 100644 --- a/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentRouteTestKit.scala +++ b/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentRouteTestKit.scala @@ -1,5 +1,6 @@ package app.softnetwork.payment.scalatest +import akka.actor.typed.ActorSystem import akka.http.scaladsl.model.headers.RawHeader import akka.http.scaladsl.model.{ContentTypes, Multipart, StatusCodes} import app.softnetwork.api.server.ApiRoutes @@ -20,6 +21,8 @@ trait PaymentRouteTestKit extends SessionTestKit with PaymentTestKit with Paymen override lazy val additionalConfig: String = paymentGrpcConfig + override implicit lazy val ts: ActorSystem[_] = typedSystem() + override def beforeAll(): Unit = { initAndJoinCluster() // pre load routes diff --git a/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentTestKit.scala b/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentTestKit.scala index 53a57ca..ce28989 100644 --- a/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentTestKit.scala +++ b/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentTestKit.scala @@ -1,8 +1,18 @@ package app.softnetwork.payment.scalatest import akka.actor.typed.ActorSystem +import app.softnetwork.account.config.AccountSettings +import app.softnetwork.account.handlers.AccountDao +import app.softnetwork.account.model.BasicAccountProfile +import app.softnetwork.account.persistence.query.AccountEventProcessorStreams.InternalAccountEvents2AccountProcessorStream +import app.softnetwork.account.persistence.typed.AccountBehavior +import app.softnetwork.notification.scalatest.AllNotificationsTestKit import app.softnetwork.payment.config.PaymentSettings._ -import app.softnetwork.payment.handlers.MockPaymentHandler +import app.softnetwork.payment.handlers.{ + MockPaymentHandler, + MockSoftPaymentAccountDao, + MockSoftPaymentAccountHandler +} import app.softnetwork.payment.launch.PaymentGuardian import app.softnetwork.payment.message.PaymentMessages.{ KycDocumentStatusNotUpdated, @@ -17,8 +27,7 @@ import app.softnetwork.payment.persistence.query.{ import app.softnetwork.payment.persistence.typed.{ GenericPaymentBehavior, MockPaymentBehavior, - MockSoftPaymentAccountBehavior, - SoftPaymentAccountBehavior + MockSoftPaymentAccountBehavior } import app.softnetwork.persistence.launch.PersistentEntity import app.softnetwork.persistence.query.{ @@ -34,20 +43,23 @@ import org.slf4j.{Logger, LoggerFactory} import scala.concurrent.Future -trait PaymentTestKit extends SchedulerTestKit with PaymentGuardian { +trait PaymentTestKit extends SchedulerTestKit with PaymentGuardian with AllNotificationsTestKit { _: Suite with SessionMaterials => /** @return * roles associated with this node */ - override def roles: Seq[String] = super.roles :+ AkkaNodeRole + override def roles: Seq[String] = super.roles :+ AkkaNodeRole :+ AccountSettings.AkkaNodeRole override def paymentAccountBehavior: ActorSystem[_] => GenericPaymentBehavior = _ => MockPaymentBehavior - override def softPaymentAccountBehavior: ActorSystem[_] => SoftPaymentAccountBehavior = _ => + override def accountBehavior + : ActorSystem[_] => AccountBehavior[SoftPaymentAccount, BasicAccountProfile] = _ => MockSoftPaymentAccountBehavior + override def accountDao: AccountDao = MockSoftPaymentAccountDao + override def paymentCommandProcessorStream : ActorSystem[_] => GenericPaymentCommandProcessorStream = sys => new GenericPaymentCommandProcessorStream @@ -71,6 +83,18 @@ trait PaymentTestKit extends SchedulerTestKit with PaymentGuardian { override implicit def system: ActorSystem[_] = sys } + override def internalAccountEvents2AccountProcessorStream + : ActorSystem[_] => InternalAccountEvents2AccountProcessorStream = sys => + new InternalAccountEvents2AccountProcessorStream + with MockSoftPaymentAccountHandler + with InMemoryJournalProvider + with InMemoryOffsetProvider { + lazy val log: Logger = LoggerFactory getLogger getClass.getName + override def tag: String = s"${MockSoftPaymentAccountBehavior.persistenceId}-to-internal" + override lazy val forTests: Boolean = true + override implicit def system: ActorSystem[_] = sys + } + def payInFor3DS( orderUuid: String, transactionId: String, @@ -176,13 +200,18 @@ trait PaymentTestKit extends SchedulerTestKit with PaymentGuardian { } override def entities: ActorSystem[_] => Seq[PersistentEntity[_, _, _, _]] = sys => - schedulerEntities(sys) ++ sessionEntities(sys) ++ paymentEntities(sys) + schedulerEntities(sys) ++ sessionEntities(sys) ++ accountEntities(sys) ++ paymentEntities( + sys + ) ++ notificationEntities(sys) override def eventProcessorStreams: ActorSystem[_] => Seq[EventProcessorStream[_]] = sys => schedulerEventProcessorStreams(sys) ++ - paymentEventProcessorStreams(sys) + paymentEventProcessorStreams(sys) ++ + accountEventProcessorStreams(sys) ++ + notificationEventProcessorStreams(sys) - /*override def initSystem: ActorSystem[_] => Unit = system => { + override def initSystem: ActorSystem[_] => Unit = system => { + initAccountSystem(system) initSchedulerSystem(system) - }*/ + } } diff --git a/testkit/src/test/scala/app/softnetwork/payment/handlers/PaymentHandlerSpec.scala b/testkit/src/test/scala/app/softnetwork/payment/handlers/PaymentHandlerSpec.scala index 1df8fd1..4407410 100644 --- a/testkit/src/test/scala/app/softnetwork/payment/handlers/PaymentHandlerSpec.scala +++ b/testkit/src/test/scala/app/softnetwork/payment/handlers/PaymentHandlerSpec.scala @@ -33,7 +33,7 @@ class PaymentHandlerSpec override protected def sessionType: Session.SessionType = Settings.Session.SessionContinuityAndTransport - lazy val client: PaymentClient = PaymentClient(ts) + lazy val paymentClient: PaymentClient = PaymentClient(ts) "Payment handler" must { "pre register card" in { @@ -503,7 +503,7 @@ class PaymentHandlerSpec sellerBankAccountId = paymentAccount.bankAccount.flatMap(_.id).getOrElse("") // assert(sellerBankAccountId != previousBankAccountId) uboDeclarationId = paymentAccount.getLegalUser.uboDeclaration.map(_.id).getOrElse("") - client.loadLegalUserDetails( + paymentClient.loadLegalUserDetails( computeExternalUuidWithProfile(sellerUuid, Some("seller")) ) complete () match { case Success(value) => @@ -796,7 +796,7 @@ class PaymentHandlerSpec case result: CardPreAuthorized => val transactionId = result.transactionId preAuthorizationId = transactionId - client.payInWithCardPreAuthorized( + paymentClient.payInWithCardPreAuthorized( preAuthorizationId, computeExternalUuidWithProfile(sellerUuid, Some("seller")), Some(110) @@ -806,7 +806,7 @@ class PaymentHandlerSpec assert(result.error.getOrElse("") == "DebitedAmountAbovePreAuthorizationAmount") case Failure(f) => fail(f.getMessage) } - client.payInWithCardPreAuthorized( + paymentClient.payInWithCardPreAuthorized( preAuthorizationId, computeExternalUuidWithProfile(sellerUuid, Some("seller")), Some(90) @@ -827,7 +827,7 @@ class PaymentHandlerSpec ) case other => fail(other.getClass.toString) } - client.payOut( + paymentClient.payOut( orderUuid, computeExternalUuidWithProfile(sellerUuid, Some("seller")), 100, @@ -857,7 +857,7 @@ class PaymentHandlerSpec ) ) await { case _: PaidIn => - client.payOut( + paymentClient.payOut( orderUuid, computeExternalUuidWithProfile(sellerUuid, Some("seller")), 100, @@ -905,7 +905,7 @@ class PaymentHandlerSpec ) ) await { case _: PaidIn => - client.payOut( + paymentClient.payOut( orderUuid, computeExternalUuidWithProfile(sellerUuid, Some("seller")), 100, @@ -936,7 +936,7 @@ class PaymentHandlerSpec ) await { case result: PaidIn => val payInTransactionId = result.transactionId - client.refund( + paymentClient.refund( orderUuid, payInTransactionId, 101, @@ -947,7 +947,7 @@ class PaymentHandlerSpec case Success(r) => assert(r.transactionId.isEmpty) assert(r.error.getOrElse("") == "IllegalTransactionAmount") - client.refund( + paymentClient.refund( orderUuid, payInTransactionId, 50, @@ -1006,7 +1006,7 @@ class PaymentHandlerSpec } case other => fail(other.toString) } - client.transfer( + paymentClient.transfer( Some(orderUuid), computeExternalUuidWithProfile(sellerUuid, Some("seller")), computeExternalUuidWithProfile(vendorUuid, Some("vendor")), @@ -1043,7 +1043,7 @@ class PaymentHandlerSpec } "direct debit" in { - client.directDebit( + paymentClient.directDebit( computeExternalUuidWithProfile(vendorUuid, Some("vendor")), 100, 0, diff --git a/testkit/src/test/scala/app/softnetwork/payment/service/PaymentServiceSpec.scala b/testkit/src/test/scala/app/softnetwork/payment/service/PaymentServiceSpec.scala index bc28cf9..2d26ed4 100644 --- a/testkit/src/test/scala/app/softnetwork/payment/service/PaymentServiceSpec.scala +++ b/testkit/src/test/scala/app/softnetwork/payment/service/PaymentServiceSpec.scala @@ -28,7 +28,7 @@ trait PaymentServiceSpec extends AnyWordSpecLike with PaymentRouteTestKit { import app.softnetwork.serialization._ - lazy val client: PaymentClient = PaymentClient(typedSystem()) + lazy val paymentClient: PaymentClient = PaymentClient(ts) "Payment service" must { "pre register card" in { @@ -347,7 +347,7 @@ trait PaymentServiceSpec extends AnyWordSpecLike with PaymentRouteTestKit { ) ~> routes ~> check { status shouldEqual StatusCodes.OK preAuthorizationId = responseAs[CardPreAuthorized].transactionId - client.payInWithCardPreAuthorized( + paymentClient.payInWithCardPreAuthorized( preAuthorizationId, computeExternalUuidWithProfile(sellerUuid, Some("seller")), None @@ -355,7 +355,7 @@ trait PaymentServiceSpec extends AnyWordSpecLike with PaymentRouteTestKit { case Success(result) => assert(result.transactionId.isDefined) assert(result.error.isEmpty) - client.payOut( + paymentClient.payOut( orderUuid, computeExternalUuidWithProfile(sellerUuid, Some("seller")), 100, @@ -409,7 +409,7 @@ trait PaymentServiceSpec extends AnyWordSpecLike with PaymentRouteTestKit { ) ~> routes ~> check { status shouldEqual StatusCodes.OK assert(responseAs[PaidIn].transactionId == transactionId) - client.payOut( + paymentClient.payOut( orderUuid, computeExternalUuidWithProfile(sellerUuid, Some("seller")), 5100, @@ -458,7 +458,7 @@ trait PaymentServiceSpec extends AnyWordSpecLike with PaymentRouteTestKit { ) ~> routes ~> check { status shouldEqual StatusCodes.OK assert(responseAs[PaidIn].transactionId == transactionId) - client.payOut( + paymentClient.payOut( orderUuid, computeExternalUuidWithProfile(sellerUuid, Some("seller")), 5100, From 00c5f3ad68ca64d3f284102bf372ca9eff32b956 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Manciot?= Date: Thu, 23 Nov 2023 00:00:26 +0100 Subject: [PATCH 03/37] add account and oauth endpoints --- common/src/main/resources/reference.conf | 11 +++- .../payment/launch/PaymentEndpoints.scala | 13 ++++- .../payment/launch/PaymentRoutes.scala | 22 +++++++- .../service/SoftPaymentAccountService.scala | 32 ++++++++++++ .../SoftPaymentAccountServiceEndpoints.scala | 35 +++++++++++++ .../service/SoftPaymentOAuthService.scala | 18 +++++++ .../SoftPaymentOAuthServiceEndpoints.scala | 22 ++++++++ .../payment/api/MangoPayEndpoints.scala | 35 ++++++++++++- .../payment/api/MangoPayRoutes.scala | 45 ++++++++++++++++- .../handlers/MockSoftPaymentAccountDao.scala | 4 +- .../scalatest/PaymentEndpointsTestKit.scala | 45 ++++++++++++++--- .../scalatest/PaymentRoutesTestKit.scala | 50 ++++++++++++++++--- .../MockSoftPaymentAccountService.scala | 11 ++++ ...ckSoftPaymentAccountServiceEndpoints.scala | 8 +++ .../service/MockSoftPaymentOAuthService.scala | 16 ++++++ ...MockSoftPaymentOAuthServiceEndpoints.scala | 16 ++++++ 16 files changed, 361 insertions(+), 22 deletions(-) create mode 100644 core/src/main/scala/app/softnetwork/payment/service/SoftPaymentAccountService.scala create mode 100644 core/src/main/scala/app/softnetwork/payment/service/SoftPaymentAccountServiceEndpoints.scala create mode 100644 core/src/main/scala/app/softnetwork/payment/service/SoftPaymentOAuthService.scala create mode 100644 core/src/main/scala/app/softnetwork/payment/service/SoftPaymentOAuthServiceEndpoints.scala create mode 100644 testkit/src/main/scala/app/softnetwork/payment/service/MockSoftPaymentAccountService.scala create mode 100644 testkit/src/main/scala/app/softnetwork/payment/service/MockSoftPaymentAccountServiceEndpoints.scala create mode 100644 testkit/src/main/scala/app/softnetwork/payment/service/MockSoftPaymentOAuthService.scala create mode 100644 testkit/src/main/scala/app/softnetwork/payment/service/MockSoftPaymentOAuthServiceEndpoints.scala diff --git a/common/src/main/resources/reference.conf b/common/src/main/resources/reference.conf index eca257d..bcb67c1 100644 --- a/common/src/main/resources/reference.conf +++ b/common/src/main/resources/reference.conf @@ -28,4 +28,13 @@ payment{ event-streams { external-to-payment-account-tag = "external-to-payment-account" } -} \ No newline at end of file +} + +auth { + path = "payment/account" + + oauth { + path = "payment/oauth" + } + +} diff --git a/core/src/main/scala/app/softnetwork/payment/launch/PaymentEndpoints.scala b/core/src/main/scala/app/softnetwork/payment/launch/PaymentEndpoints.scala index e94538d..efdcb37 100644 --- a/core/src/main/scala/app/softnetwork/payment/launch/PaymentEndpoints.scala +++ b/core/src/main/scala/app/softnetwork/payment/launch/PaymentEndpoints.scala @@ -1,13 +1,20 @@ package app.softnetwork.payment.launch import akka.actor.typed.ActorSystem +import app.softnetwork.account.launch.AccountEndpoints +import app.softnetwork.account.message.BasicAccountSignUp +import app.softnetwork.account.model.BasicAccountProfile import app.softnetwork.api.server.{ApiEndpoints, Endpoint} +import app.softnetwork.payment.model.SoftPaymentAccount import app.softnetwork.payment.serialization.paymentFormats import app.softnetwork.payment.service.GenericPaymentEndpoints import app.softnetwork.persistence.schema.SchemaProvider +import app.softnetwork.session.CsrfCheck import org.json4s.Formats -trait PaymentEndpoints extends ApiEndpoints { _: PaymentGuardian with SchemaProvider => +trait PaymentEndpoints + extends AccountEndpoints[SoftPaymentAccount, BasicAccountProfile, BasicAccountSignUp] { + _: PaymentGuardian with SchemaProvider with CsrfCheck => override implicit def formats: Formats = paymentFormats @@ -16,6 +23,8 @@ trait PaymentEndpoints extends ApiEndpoints { _: PaymentGuardian with SchemaProv override def endpoints: ActorSystem[_] => List[Endpoint] = system => List( - paymentEndpoints(system) + paymentEndpoints(system), + accountEndpoints(system), + oauthEndpoints(system) ) } diff --git a/core/src/main/scala/app/softnetwork/payment/launch/PaymentRoutes.scala b/core/src/main/scala/app/softnetwork/payment/launch/PaymentRoutes.scala index dae3de2..8924e19 100644 --- a/core/src/main/scala/app/softnetwork/payment/launch/PaymentRoutes.scala +++ b/core/src/main/scala/app/softnetwork/payment/launch/PaymentRoutes.scala @@ -1,13 +1,29 @@ package app.softnetwork.payment.launch import akka.actor.typed.ActorSystem +import app.softnetwork.account.launch.AccountRoutes +import app.softnetwork.account.model.{ + BasicAccountProfile, + DefaultAccountDetailsView, + DefaultAccountView, + DefaultProfileView +} import app.softnetwork.api.server.{ApiRoute, ApiRoutes} +import app.softnetwork.payment.model.SoftPaymentAccount import app.softnetwork.payment.serialization.paymentFormats import app.softnetwork.payment.service.GenericPaymentService import app.softnetwork.persistence.schema.SchemaProvider +import app.softnetwork.session.CsrfCheck import org.json4s.Formats -trait PaymentRoutes extends ApiRoutes { _: PaymentGuardian with SchemaProvider => +trait PaymentRoutes + extends AccountRoutes[ + SoftPaymentAccount, + BasicAccountProfile, + DefaultProfileView, + DefaultAccountDetailsView, + DefaultAccountView[DefaultProfileView, DefaultAccountDetailsView] + ] { _: PaymentGuardian with SchemaProvider with CsrfCheck => override implicit def formats: Formats = paymentFormats @@ -16,7 +32,9 @@ trait PaymentRoutes extends ApiRoutes { _: PaymentGuardian with SchemaProvider = override def apiRoutes: ActorSystem[_] => List[ApiRoute] = system => List( - paymentService(system) + paymentService(system), + accountService(system), + oauthService(system) ) } diff --git a/core/src/main/scala/app/softnetwork/payment/service/SoftPaymentAccountService.scala b/core/src/main/scala/app/softnetwork/payment/service/SoftPaymentAccountService.scala new file mode 100644 index 0000000..6795422 --- /dev/null +++ b/core/src/main/scala/app/softnetwork/payment/service/SoftPaymentAccountService.scala @@ -0,0 +1,32 @@ +package app.softnetwork.payment.service + +import akka.http.scaladsl.model.HttpRequest +import akka.http.scaladsl.server.Route +import akka.http.scaladsl.unmarshalling.Unmarshaller +import app.softnetwork.account.config.AccountSettings +import app.softnetwork.account.message.SignUp +import app.softnetwork.account.service.BasicAccountService +import app.softnetwork.payment.handlers.SoftPaymentAccountTypeKey +import app.softnetwork.payment.message.AccountMessages.SoftPaymentSignup +import app.softnetwork.session.service.SessionMaterials + +trait SoftPaymentAccountService extends BasicAccountService with SoftPaymentAccountTypeKey { + _: SessionMaterials => + + override val route: Route = { + pathPrefix(AccountSettings.Path) { + signUp ~ + basic ~ + login ~ + activate ~ + logout ~ + verificationCode ~ + resetPasswordToken ~ + resetPassword ~ + unsubscribe ~ + device ~ + password + } + } + +} diff --git a/core/src/main/scala/app/softnetwork/payment/service/SoftPaymentAccountServiceEndpoints.scala b/core/src/main/scala/app/softnetwork/payment/service/SoftPaymentAccountServiceEndpoints.scala new file mode 100644 index 0000000..013cf00 --- /dev/null +++ b/core/src/main/scala/app/softnetwork/payment/service/SoftPaymentAccountServiceEndpoints.scala @@ -0,0 +1,35 @@ +package app.softnetwork.payment.service + +import app.softnetwork.account.service.BasicAccountServiceEndpoints +import app.softnetwork.payment.handlers.SoftPaymentAccountTypeKey +import app.softnetwork.session.service.SessionMaterials +import sttp.capabilities +import sttp.capabilities.akka.AkkaStreams +import sttp.tapir.server.ServerEndpoint + +import scala.concurrent.Future + +trait SoftPaymentAccountServiceEndpoints + extends BasicAccountServiceEndpoints + with SoftPaymentAccountTypeKey { _: SessionMaterials => + + override lazy val endpoints + : List[ServerEndpoint[AkkaStreams with capabilities.WebSockets, Future]] = + List( + signUp, + basic, + login, + signIn, + activate, + logout, + signOut, + sendVerificationCode, + sendResetPasswordToken, + checkResetPasswordToken, + resetPassword, + unsubscribe, + registerDevice, + unregisterDevice, + updatePassword + ) +} diff --git a/core/src/main/scala/app/softnetwork/payment/service/SoftPaymentOAuthService.scala b/core/src/main/scala/app/softnetwork/payment/service/SoftPaymentOAuthService.scala new file mode 100644 index 0000000..acb689d --- /dev/null +++ b/core/src/main/scala/app/softnetwork/payment/service/SoftPaymentOAuthService.scala @@ -0,0 +1,18 @@ +package app.softnetwork.payment.service + +import akka.http.scaladsl.server.Route +import app.softnetwork.account.config.AccountSettings +import app.softnetwork.account.service.OAuthService +import app.softnetwork.payment.handlers.SoftPaymentAccountTypeKey +import app.softnetwork.session.service.SessionMaterials + +trait SoftPaymentOAuthService extends OAuthService with SoftPaymentAccountTypeKey { + _: SessionMaterials => + + override val route: Route = { + pathPrefix(AccountSettings.OAuthPath) { + concat(authorize :: (signin ++ backup).toList: _*) + } + } + +} diff --git a/core/src/main/scala/app/softnetwork/payment/service/SoftPaymentOAuthServiceEndpoints.scala b/core/src/main/scala/app/softnetwork/payment/service/SoftPaymentOAuthServiceEndpoints.scala new file mode 100644 index 0000000..05a060a --- /dev/null +++ b/core/src/main/scala/app/softnetwork/payment/service/SoftPaymentOAuthServiceEndpoints.scala @@ -0,0 +1,22 @@ +package app.softnetwork.payment.service + +import app.softnetwork.account.service.OAuthServiceEndpoints +import app.softnetwork.payment.handlers.SoftPaymentAccountTypeKey +import app.softnetwork.session.service.SessionMaterials +import sttp.capabilities +import sttp.capabilities.akka.AkkaStreams +import sttp.tapir.server.ServerEndpoint + +import scala.concurrent.Future + +trait SoftPaymentOAuthServiceEndpoints + extends OAuthServiceEndpoints + with SoftPaymentAccountTypeKey { _: SessionMaterials => + + override lazy val endpoints + : List[ServerEndpoint[AkkaStreams with capabilities.WebSockets, Future]] = + List( + authorize + ) ++ services.map(signin) ++ services.map(backup) + +} diff --git a/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayEndpoints.scala b/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayEndpoints.scala index b8cf77f..bdb97bd 100644 --- a/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayEndpoints.scala +++ b/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayEndpoints.scala @@ -1,9 +1,16 @@ package app.softnetwork.payment.api import akka.actor.typed.ActorSystem +import app.softnetwork.account.message +import app.softnetwork.account.service.{AccountServiceEndpoints, OAuthServiceEndpoints} import app.softnetwork.api.server.Endpoint import app.softnetwork.payment.launch.PaymentEndpoints -import app.softnetwork.payment.service.{GenericPaymentEndpoints, MangoPayPaymentEndpoints} +import app.softnetwork.payment.service.{ + GenericPaymentEndpoints, + MangoPayPaymentEndpoints, + SoftPaymentAccountServiceEndpoints, + SoftPaymentOAuthServiceEndpoints +} import app.softnetwork.persistence.schema.SchemaProvider import app.softnetwork.session.CsrfCheck import app.softnetwork.session.service.SessionMaterials @@ -26,6 +33,32 @@ trait MangoPayEndpoints extends PaymentEndpoints { override implicit def sessionConfig: SessionConfig = self.sessionConfig } + override def accountEndpoints + : ActorSystem[_] => AccountServiceEndpoints[message.BasicAccountSignUp] = sys => + new SoftPaymentAccountServiceEndpoints with SessionMaterials { + override def log: org.slf4j.Logger = org.slf4j.LoggerFactory.getLogger(getClass) + override implicit def system: ActorSystem[_] = sys + override lazy val ec: ExecutionContext = sys.executionContext + override implicit def manager(implicit + sessionConfig: SessionConfig + ): SessionManager[Session] = self.manager + override protected def sessionType: Session.SessionType = self.sessionType + override implicit def sessionConfig: SessionConfig = self.sessionConfig + override protected val manifestWrapper: ManifestW = ManifestW() + } + + override def oauthEndpoints: ActorSystem[_] => OAuthServiceEndpoints = sys => + new SoftPaymentOAuthServiceEndpoints with SessionMaterials { + override def log: org.slf4j.Logger = org.slf4j.LoggerFactory.getLogger(getClass) + override implicit def system: ActorSystem[_] = sys + override lazy val ec: ExecutionContext = sys.executionContext + override implicit def manager(implicit + sessionConfig: SessionConfig + ): SessionManager[Session] = self.manager + override protected def sessionType: Session.SessionType = self.sessionType + override implicit def sessionConfig: SessionConfig = self.sessionConfig + } + override def endpoints: ActorSystem[_] => List[Endpoint] = system => super.endpoints(system) :+ paymentSwagger(system) } diff --git a/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayRoutes.scala b/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayRoutes.scala index 7b77742..ab62b47 100644 --- a/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayRoutes.scala +++ b/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayRoutes.scala @@ -1,10 +1,22 @@ package app.softnetwork.payment.api import akka.actor.typed.ActorSystem +import app.softnetwork.account.model.{ + DefaultAccountDetailsView, + DefaultAccountView, + DefaultProfileView +} +import app.softnetwork.account.service.{AccountService, OAuthService} import app.softnetwork.api.server.ApiRoute import app.softnetwork.payment.launch.PaymentRoutes -import app.softnetwork.payment.service.{GenericPaymentService, MangoPayPaymentService} +import app.softnetwork.payment.service.{ + GenericPaymentService, + MangoPayPaymentService, + SoftPaymentAccountService, + SoftPaymentOAuthService +} import app.softnetwork.persistence.schema.SchemaProvider +import app.softnetwork.session.CsrfCheck import app.softnetwork.session.service.SessionMaterials import com.softwaremill.session.{SessionConfig, SessionManager} import org.slf4j.{Logger, LoggerFactory} @@ -12,7 +24,7 @@ import org.softnetwork.session.model.Session import scala.concurrent.ExecutionContext -trait MangoPayRoutes extends PaymentRoutes { self: MangoPayApi with SchemaProvider => +trait MangoPayRoutes extends PaymentRoutes { self: MangoPayApi with SchemaProvider with CsrfCheck => override def paymentService: ActorSystem[_] => GenericPaymentService = sys => new MangoPayPaymentService with SessionMaterials { @@ -26,6 +38,35 @@ trait MangoPayRoutes extends PaymentRoutes { self: MangoPayApi with SchemaProvid override lazy val ec: ExecutionContext = sys.executionContext } + override def accountService: ActorSystem[_] => AccountService[ + DefaultProfileView, + DefaultAccountDetailsView, + DefaultAccountView[DefaultProfileView, DefaultAccountDetailsView] + ] = sys => + new SoftPaymentAccountService with SessionMaterials { + override implicit def manager(implicit + sessionConfig: SessionConfig + ): SessionManager[Session] = self.manager + override protected def sessionType: Session.SessionType = self.sessionType + override def log: Logger = LoggerFactory getLogger getClass.getName + override implicit def sessionConfig: SessionConfig = self.sessionConfig + override implicit def system: ActorSystem[_] = sys + override lazy val ec: ExecutionContext = sys.executionContext + override protected val manifestWrapper: ManifestW = ManifestW() + } + + override def oauthService: ActorSystem[_] => OAuthService = sys => + new SoftPaymentOAuthService with SessionMaterials { + override implicit def manager(implicit + sessionConfig: SessionConfig + ): SessionManager[Session] = self.manager + override protected def sessionType: Session.SessionType = self.sessionType + override def log: Logger = LoggerFactory getLogger getClass.getName + override implicit def sessionConfig: SessionConfig = self.sessionConfig + override implicit def system: ActorSystem[_] = sys + override lazy val ec: ExecutionContext = sys.executionContext + } + override def apiRoutes: ActorSystem[_] => List[ApiRoute] = system => super.apiRoutes(system) :+ paymentSwagger(system) } diff --git a/testkit/src/main/scala/app/softnetwork/payment/handlers/MockSoftPaymentAccountDao.scala b/testkit/src/main/scala/app/softnetwork/payment/handlers/MockSoftPaymentAccountDao.scala index 18ff743..2ba229d 100644 --- a/testkit/src/main/scala/app/softnetwork/payment/handlers/MockSoftPaymentAccountDao.scala +++ b/testkit/src/main/scala/app/softnetwork/payment/handlers/MockSoftPaymentAccountDao.scala @@ -9,12 +9,12 @@ import org.slf4j.{Logger, LoggerFactory} import scala.reflect.ClassTag -trait MockBasicAccountTypeKey extends CommandTypeKey[AccountCommand] { +trait MockSoftPaymentAccountTypeKey extends CommandTypeKey[AccountCommand] { override def TypeKey(implicit tTag: ClassTag[AccountCommand]): EntityTypeKey[AccountCommand] = MockSoftPaymentAccountBehavior.TypeKey } -trait MockSoftPaymentAccountHandler extends AccountHandler with MockBasicAccountTypeKey +trait MockSoftPaymentAccountHandler extends AccountHandler with MockSoftPaymentAccountTypeKey object MockSoftPaymentAccountDao extends SoftPaymentAccountDao with MockSoftPaymentAccountHandler { lazy val log: Logger = LoggerFactory getLogger getClass.getName diff --git a/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentEndpointsTestKit.scala b/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentEndpointsTestKit.scala index 4fef8fc..8550fbe 100644 --- a/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentEndpointsTestKit.scala +++ b/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentEndpointsTestKit.scala @@ -1,9 +1,19 @@ package app.softnetwork.payment.scalatest import akka.actor.typed.ActorSystem +import app.softnetwork.account.message +import app.softnetwork.account.message.BasicAccountSignUp +import app.softnetwork.account.service.{AccountServiceEndpoints, OAuthServiceEndpoints} import app.softnetwork.api.server.Endpoint import app.softnetwork.payment.launch.PaymentEndpoints -import app.softnetwork.payment.service.{GenericPaymentEndpoints, MockPaymentEndpoints} +import app.softnetwork.payment.service.{ + GenericPaymentEndpoints, + MockPaymentEndpoints, + MockSoftPaymentAccountServiceEndpoints, + MockSoftPaymentOAuthServiceEndpoints, + SoftPaymentAccountServiceEndpoints, + SoftPaymentOAuthServiceEndpoints +} import app.softnetwork.persistence.schema.SchemaProvider import app.softnetwork.session.scalatest.{SessionEndpointsRoutes, SessionTestKit} import app.softnetwork.session.CsrfCheck @@ -21,6 +31,8 @@ trait PaymentEndpointsTestKit extends PaymentEndpoints with SessionEndpointsRout with CsrfCheck with SessionMaterials => + implicit def sessionConfig: SessionConfig + override def paymentEndpoints: ActorSystem[_] => GenericPaymentEndpoints = sys => new MockPaymentEndpoints with SessionMaterials { override implicit def manager(implicit @@ -34,10 +46,31 @@ trait PaymentEndpointsTestKit extends PaymentEndpoints with SessionEndpointsRout } override def endpoints: ActorSystem[_] => List[Endpoint] = - system => - List( - sessionServiceEndpoints(system), - paymentEndpoints(system) - ) + system => super.endpoints(system) :+ sessionServiceEndpoints(system) + + override def accountEndpoints: ActorSystem[_] => AccountServiceEndpoints[BasicAccountSignUp] = + sys => + new MockSoftPaymentAccountServiceEndpoints with SessionMaterials { + override implicit def manager(implicit + sessionConfig: SessionConfig + ): SessionManager[Session] = self.manager + override protected def sessionType: Session.SessionType = self.sessionType + override def log: Logger = LoggerFactory getLogger getClass.getName + override implicit def sessionConfig: SessionConfig = self.sessionConfig + override implicit def system: ActorSystem[_] = sys + override lazy val ec: ExecutionContext = sys.executionContext + override protected val manifestWrapper: ManifestW = ManifestW() + } + override def oauthEndpoints: ActorSystem[_] => OAuthServiceEndpoints = sys => + new MockSoftPaymentOAuthServiceEndpoints with SessionMaterials { + override implicit def manager(implicit + sessionConfig: SessionConfig + ): SessionManager[Session] = self.manager + override protected def sessionType: Session.SessionType = self.sessionType + override def log: Logger = LoggerFactory getLogger getClass.getName + override implicit def sessionConfig: SessionConfig = self.sessionConfig + override implicit def system: ActorSystem[_] = sys + override lazy val ec: ExecutionContext = sys.executionContext + } } diff --git a/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentRoutesTestKit.scala b/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentRoutesTestKit.scala index 503429b..124c43c 100644 --- a/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentRoutesTestKit.scala +++ b/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentRoutesTestKit.scala @@ -1,9 +1,20 @@ package app.softnetwork.payment.scalatest import akka.actor.typed.ActorSystem +import app.softnetwork.account.model.{ + DefaultAccountDetailsView, + DefaultAccountView, + DefaultProfileView +} +import app.softnetwork.account.service.{AccountService, OAuthService} import app.softnetwork.api.server.ApiRoute import app.softnetwork.payment.launch.PaymentRoutes -import app.softnetwork.payment.service.{GenericPaymentService, MockPaymentService} +import app.softnetwork.payment.service.{ + GenericPaymentService, + MockPaymentService, + MockSoftPaymentAccountService, + MockSoftPaymentOAuthService +} import app.softnetwork.persistence.schema.SchemaProvider import app.softnetwork.session.scalatest.{SessionServiceRoutes, SessionTestKit} import app.softnetwork.session.service.SessionMaterials @@ -28,11 +39,38 @@ trait PaymentRoutesTestKit extends PaymentRoutes with SessionServiceRoutes { override lazy val ec: ExecutionContext = sys.executionContext } + implicit def sessionConfig: SessionConfig + + override def accountService: ActorSystem[_] => AccountService[ + DefaultProfileView, + DefaultAccountDetailsView, + DefaultAccountView[DefaultProfileView, DefaultAccountDetailsView] + ] = sys => + new MockSoftPaymentAccountService with SessionMaterials { + override implicit def manager(implicit + sessionConfig: SessionConfig + ): SessionManager[Session] = self.manager + override protected def sessionType: Session.SessionType = self.sessionType + override def log: Logger = LoggerFactory getLogger getClass.getName + override implicit def sessionConfig: SessionConfig = self.sessionConfig + override implicit def system: ActorSystem[_] = sys + override lazy val ec: ExecutionContext = sys.executionContext + override protected val manifestWrapper: ManifestW = ManifestW() + } + + override def oauthService: ActorSystem[_] => OAuthService = sys => + new MockSoftPaymentOAuthService with SessionMaterials { + override implicit def manager(implicit + sessionConfig: SessionConfig + ): SessionManager[Session] = self.manager + override protected def sessionType: Session.SessionType = self.sessionType + override def log: Logger = LoggerFactory getLogger getClass.getName + override implicit def sessionConfig: SessionConfig = self.sessionConfig + override implicit def system: ActorSystem[_] = sys + override lazy val ec: ExecutionContext = sys.executionContext + } + override def apiRoutes: ActorSystem[_] => List[ApiRoute] = - system => - List( - sessionServiceRoute(system), - paymentService(system) - ) + system => super.apiRoutes(system) :+ sessionServiceRoute(system) } diff --git a/testkit/src/main/scala/app/softnetwork/payment/service/MockSoftPaymentAccountService.scala b/testkit/src/main/scala/app/softnetwork/payment/service/MockSoftPaymentAccountService.scala new file mode 100644 index 0000000..a1f4975 --- /dev/null +++ b/testkit/src/main/scala/app/softnetwork/payment/service/MockSoftPaymentAccountService.scala @@ -0,0 +1,11 @@ +package app.softnetwork.payment.service + +import app.softnetwork.payment.handlers.MockSoftPaymentAccountTypeKey +import app.softnetwork.session.service.SessionMaterials + +trait MockSoftPaymentAccountService + extends SoftPaymentAccountService + with MockSoftPaymentAccountTypeKey { + _: SessionMaterials => + +} diff --git a/testkit/src/main/scala/app/softnetwork/payment/service/MockSoftPaymentAccountServiceEndpoints.scala b/testkit/src/main/scala/app/softnetwork/payment/service/MockSoftPaymentAccountServiceEndpoints.scala new file mode 100644 index 0000000..7849ff3 --- /dev/null +++ b/testkit/src/main/scala/app/softnetwork/payment/service/MockSoftPaymentAccountServiceEndpoints.scala @@ -0,0 +1,8 @@ +package app.softnetwork.payment.service + +import app.softnetwork.payment.handlers.MockSoftPaymentAccountTypeKey +import app.softnetwork.session.service.SessionMaterials + +trait MockSoftPaymentAccountServiceEndpoints + extends SoftPaymentAccountServiceEndpoints + with MockSoftPaymentAccountTypeKey { _: SessionMaterials => } diff --git a/testkit/src/main/scala/app/softnetwork/payment/service/MockSoftPaymentOAuthService.scala b/testkit/src/main/scala/app/softnetwork/payment/service/MockSoftPaymentOAuthService.scala new file mode 100644 index 0000000..aace6e2 --- /dev/null +++ b/testkit/src/main/scala/app/softnetwork/payment/service/MockSoftPaymentOAuthService.scala @@ -0,0 +1,16 @@ +package app.softnetwork.payment.service + +import app.softnetwork.account.spi.OAuth2Service +import app.softnetwork.payment.handlers.MockSoftPaymentAccountTypeKey +import app.softnetwork.session.service.SessionMaterials +import com.github.scribejava.core.oauth.DummyApiService + +trait MockSoftPaymentOAuthService + extends SoftPaymentOAuthService + with MockSoftPaymentAccountTypeKey { + _: SessionMaterials => + override lazy val services: Seq[OAuth2Service] = + Seq( + new DummyApiService() + ) +} diff --git a/testkit/src/main/scala/app/softnetwork/payment/service/MockSoftPaymentOAuthServiceEndpoints.scala b/testkit/src/main/scala/app/softnetwork/payment/service/MockSoftPaymentOAuthServiceEndpoints.scala new file mode 100644 index 0000000..dc0b4e4 --- /dev/null +++ b/testkit/src/main/scala/app/softnetwork/payment/service/MockSoftPaymentOAuthServiceEndpoints.scala @@ -0,0 +1,16 @@ +package app.softnetwork.payment.service + +import app.softnetwork.account.spi.OAuth2Service +import app.softnetwork.payment.handlers.MockSoftPaymentAccountTypeKey +import app.softnetwork.session.service.SessionMaterials +import com.github.scribejava.core.oauth.DummyApiService + +trait MockSoftPaymentOAuthServiceEndpoints + extends SoftPaymentOAuthServiceEndpoints + with MockSoftPaymentAccountTypeKey { _: SessionMaterials => + + override lazy val services: Seq[OAuth2Service] = + Seq( + new DummyApiService() + ) +} From 7db48000f128f6355e6d099656ee2a99101e84f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Manciot?= Date: Tue, 28 Nov 2023 14:36:18 +0100 Subject: [PATCH 04/37] add ClientSession, update manager according to authenticated client --- common/src/main/protobuf/api/payment.proto | 27 ++ .../protobuf/message/payment/client.proto | 14 + .../main/protobuf/model/payment/client.proto | 3 +- common/src/main/resources/reference.conf | 47 ++- .../payment/api/PaymentClient.scala | 276 ++++++++++++------ .../payment/config/PaymentSettings.scala | 4 + .../payment/message/AccountMessages.scala | 25 +- .../model/SoftPaymentAccountDecorator.scala | 7 + .../model/SoftPaymentClientDecorator.scala | 1 + .../payment/api/PaymentServer.scala | 40 ++- .../handlers/SoftPaymentAccountDao.scala | 75 ++++- .../typed/SoftPaymentAccountBehavior.scala | 213 ++++++++++++-- .../service/BankAccountEndpoints.scala | 30 +- .../payment/service/CardEndpoints.scala | 22 +- .../service/CardPaymentEndpoints.scala | 17 +- .../payment/service/ClientSession.scala | 83 ++++++ .../service/ClientSessionDirectives.scala | 43 +++ .../service/ClientSessionEndpoints.scala | 153 ++++++++++ .../service/GenericPaymentEndpoints.scala | 6 +- .../service/GenericPaymentService.scala | 20 +- .../service/KycDocumentEndpoints.scala | 12 +- .../payment/service/MandateEndpoints.scala | 12 +- .../service/RecurringPaymentEndpoints.scala | 24 +- .../service/RootPaymentEndpoints.scala | 32 +- .../service/SoftPaymentAccountService.scala | 13 +- .../SoftPaymentAccountServiceEndpoints.scala | 8 + .../service/SoftPaymentOAuthService.scala | 104 ++++++- .../SoftPaymentOAuthServiceEndpoints.scala | 184 +++++++++++- .../service/UboDeclarationEndpoints.scala | 18 +- mangopay/api/build.sbt | 2 +- .../payment/api/MangoPayEndpoints.scala | 4 +- .../payment/api/MangoPayRoutes.scala | 4 +- .../payment/api/MangoPayServer.scala | 2 +- project/Versions.scala | 8 +- .../payment/api/MockPaymentServer.scala | 7 +- .../scalatest/PaymentEndpointsTestKit.scala | 7 +- .../scalatest/PaymentRoutesTestKit.scala | 7 +- 37 files changed, 1320 insertions(+), 234 deletions(-) create mode 100644 core/src/main/scala/app/softnetwork/payment/service/ClientSession.scala create mode 100644 core/src/main/scala/app/softnetwork/payment/service/ClientSessionDirectives.scala create mode 100644 core/src/main/scala/app/softnetwork/payment/service/ClientSessionEndpoints.scala diff --git a/common/src/main/protobuf/api/payment.proto b/common/src/main/protobuf/api/payment.proto index c065d2f..c6704ed 100644 --- a/common/src/main/protobuf/api/payment.proto +++ b/common/src/main/protobuf/api/payment.proto @@ -26,6 +26,8 @@ service PaymentServiceApi { rpc CancelMandate (CancelMandateRequest) returns (CancelMandateResponse) {} rpc LoadBankAccountOwner (LoadBankAccountOwnerRequest) returns (LoadBankAccountOwnerResponse) {} rpc LoadLegalUser(LoadLegalUserRequest) returns (LoadLegalUserResponse) {} + rpc GenerateClientTokens (GenerateClientTokensRequest) returns (ClientTokensResponse) {} + rpc RefreshClientTokens (RefreshClientTokensRequest) returns (ClientTokensResponse) {} } message CreateOrUpdatePaymentAccountRequest { @@ -182,3 +184,28 @@ message LoadLegalUserResponse { app.softnetwork.payment.model.Address legalRepresentativeAddress = 4; app.softnetwork.payment.model.Address headQuartersAddress = 5; } + +message Tokens { + string access_token = 1; + string token_type = 2; + int64 expires_in = 3; + string refresh_token = 4; +// google.protobuf.StringValue scope = 5; +} + +message ClientTokensResponse { + oneof clientTokens { + Tokens tokens = 1; + string error = 2; + } +} + +message GenerateClientTokensRequest { + string client_id = 1; + string client_secret = 2; + google.protobuf.StringValue scope = 3; +} + +message RefreshClientTokensRequest { + string refresh_token = 1; +} diff --git a/common/src/main/protobuf/message/payment/client.proto b/common/src/main/protobuf/message/payment/client.proto index 9db1306..b3c2806 100644 --- a/common/src/main/protobuf/message/payment/client.proto +++ b/common/src/main/protobuf/message/payment/client.proto @@ -34,3 +34,17 @@ message SoftPaymentAccountProviderRegisteredEvent { required app.softnetwork.payment.model.SoftPaymentAccount.Client client = 1; required google.protobuf.Timestamp lastUpdated = 2 [(scalapb.field).type = "java.time.Instant"]; } + +message SoftPaymentAccountTokenRegisteredEvent { + option (scalapb.message).extends = "ProtobufEvent"; + option (scalapb.message).extends = "SoftPaymentAccountEvent"; + required app.softnetwork.payment.model.SoftPaymentAccount.Client client = 1; + required google.protobuf.Timestamp lastUpdated = 2 [(scalapb.field).type = "java.time.Instant"]; +} + +message SoftPaymentAccountTokenRefreshedEvent { + option (scalapb.message).extends = "ProtobufEvent"; + option (scalapb.message).extends = "SoftPaymentAccountEvent"; + required app.softnetwork.payment.model.SoftPaymentAccount.Client client = 1; + required google.protobuf.Timestamp lastUpdated = 2 [(scalapb.field).type = "java.time.Instant"]; +} diff --git a/common/src/main/protobuf/model/payment/client.proto b/common/src/main/protobuf/model/payment/client.proto index 343082a..9c63198 100644 --- a/common/src/main/protobuf/model/payment/client.proto +++ b/common/src/main/protobuf/model/payment/client.proto @@ -53,6 +53,7 @@ message SoftPaymentAccount { repeated string fraudEmails = 11; optional string vatNumber = 12; optional Address address = 13; + optional app.softnetwork.account.model.AccessToken accessToken = 14; } option (scalapb.message).extends = "ProtobufDomainObject"; @@ -80,5 +81,5 @@ message SoftPaymentAccount { optional bool fromAnonymous = 19; repeated app.softnetwork.account.model.Application applications = 20; - optional Client client = 21; + repeated Client clients = 21; } \ No newline at end of file diff --git a/common/src/main/resources/reference.conf b/common/src/main/resources/reference.conf index bcb67c1..ec1ae39 100644 --- a/common/src/main/resources/reference.conf +++ b/common/src/main/resources/reference.conf @@ -1,11 +1,20 @@ # Important: enable HTTP/2 in ActorSystem's config akka.http.server.preview.enable-http2 = on +softnetwork { + api { + server { + port = 9000 + root-path = "payment" + } + } +} + payment{ - baseUrl = "http://localhost/api" + baseUrl = "http://localhost:"${softnetwork.api.server.port}"/"${softnetwork.api.server.root-path} baseUrl = ${?PAYMENT_BASE_URL} - path = "payment" + path = "api" path = ${?PAYMENT_PATH} payIn-route = "payIn" @@ -28,13 +37,43 @@ payment{ event-streams { external-to-payment-account-tag = "external-to-payment-account" } + + client { + akka.http.session { + cookie { + name = "_clientdata" + secure = false + http-only = true + domain = none + path = "/" + max-age = 30 days + } + header { + send-to-client-name = "Set-X-API-KEY" + get-from-client-name = "X-API-KEY" + } + max-age = 7 days + encrypt-data = true + + jws { + alg = "HS256" + } + + jwt { + iss = "softpayment" + include-iat = true + } + } + } } auth { - path = "payment/account" + path = "account" + + realm = "SoftPayment" oauth { - path = "payment/oauth" + path = "oauth" } } diff --git a/common/src/main/scala/app/softnetwork/payment/api/PaymentClient.scala b/common/src/main/scala/app/softnetwork/payment/api/PaymentClient.scala index f10ea99..5d55217 100644 --- a/common/src/main/scala/app/softnetwork/payment/api/PaymentClient.scala +++ b/common/src/main/scala/app/softnetwork/payment/api/PaymentClient.scala @@ -2,7 +2,9 @@ package app.softnetwork.payment.api import akka.actor.typed.ActorSystem import akka.grpc.GrpcClientSettings +import akka.grpc.scaladsl.SingleResponseRequestBuilder import app.softnetwork.api.server.client.{GrpcClient, GrpcClientFactory} +import app.softnetwork.payment.annotation.InternalApi import app.softnetwork.payment.model.{ BankAccountOwner, LegalUserDetails, @@ -20,29 +22,57 @@ trait PaymentClient extends GrpcClient { GrpcClientSettings.fromConfig(name) ) - def createOrUpdatePaymentAccount(paymentAccount: PaymentAccount): Future[Boolean] = { - grpcClient.createOrUpdatePaymentAccount( - CreateOrUpdatePaymentAccountRequest(Some(paymentAccount)) - ) map (_.succeeded) + @InternalApi + private[payment] def withAuthorization[Req, Res]( + single: SingleResponseRequestBuilder[Req, Res], + token: Option[String] + ): SingleResponseRequestBuilder[Req, Res] = { + token match { + case Some(t) => single.addHeader("Authorization", s"Bearer $t") + case _ => single + } + } + + def createOrUpdatePaymentAccount( + paymentAccount: PaymentAccount, + token: Option[String] = None + ): Future[Boolean] = { + withAuthorization( + grpcClient.createOrUpdatePaymentAccount(), + token + ) + .invoke( + CreateOrUpdatePaymentAccountRequest(Some(paymentAccount)) + ) map (_.succeeded) } def payInWithCardPreAuthorized( preAuthorizationId: String, creditedAccount: String, - debitedAmount: Option[Int] + debitedAmount: Option[Int], + token: Option[String] = None ): Future[TransactionResponse] = { - grpcClient.payInWithCardPreAuthorized( - PayInWithCardPreAuthorizedRequest(preAuthorizationId, creditedAccount, debitedAmount) + withAuthorization( + grpcClient.payInWithCardPreAuthorized(), + token ) + .invoke( + PayInWithCardPreAuthorizedRequest(preAuthorizationId, creditedAccount, debitedAmount) + ) } def cancelPreAuthorization( orderUuid: String, - cardPreAuthorizedTransactionId: String + cardPreAuthorizedTransactionId: String, + token: Option[String] = None ): Future[Option[Boolean]] = { - grpcClient.cancelPreAuthorization( - CancelPreAuthorizationRequest(orderUuid, cardPreAuthorizedTransactionId) - ) map (_.preAuthorizationCanceled) + withAuthorization( + grpcClient.cancelPreAuthorization(), + token + ) + .invoke( + CancelPreAuthorizationRequest(orderUuid, cardPreAuthorizedTransactionId) + ) map (_.preAuthorizationCanceled) } def refund( @@ -51,18 +81,23 @@ trait PaymentClient extends GrpcClient { refundAmount: Int, currency: String, reasonMessage: String, - initializedByClient: Boolean + initializedByClient: Boolean, + token: Option[String] = None ): Future[TransactionResponse] = { - grpcClient.refund( - RefundRequest( - orderUuid, - payInTransactionId, - refundAmount, - currency, - reasonMessage, - initializedByClient - ) + withAuthorization( + grpcClient.refund(), + token ) + .invoke( + RefundRequest( + orderUuid, + payInTransactionId, + refundAmount, + currency, + reasonMessage, + initializedByClient + ) + ) } def payOut( @@ -71,18 +106,23 @@ trait PaymentClient extends GrpcClient { creditedAmount: Int, feesAmount: Int, currency: String, - externalReference: Option[String] + externalReference: Option[String], + token: Option[String] = None ): Future[TransactionResponse] = { - grpcClient.payOut( - PayOutRequest( - orderUuid, - creditedAccount, - creditedAmount, - feesAmount, - currency, - externalReference - ) + withAuthorization( + grpcClient.payOut(), + token ) + .invoke( + PayOutRequest( + orderUuid, + creditedAccount, + creditedAmount, + feesAmount, + currency, + externalReference + ) + ) } def transfer( @@ -93,20 +133,25 @@ trait PaymentClient extends GrpcClient { feesAmount: Int, currency: String, payOutRequired: Boolean, - externalReference: Option[String] + externalReference: Option[String], + token: Option[String] = None ): Future[TransferResponse] = { - grpcClient.transfer( - TransferRequest( - orderUuid, - debitedAccount, - creditedAccount, - debitedAmount, - feesAmount, - currency, - payOutRequired, - externalReference - ) + withAuthorization( + grpcClient.transfer(), + token ) + .invoke( + TransferRequest( + orderUuid, + debitedAccount, + creditedAccount, + debitedAmount, + feesAmount, + currency, + payOutRequired, + externalReference + ) + ) } def directDebit( @@ -115,24 +160,36 @@ trait PaymentClient extends GrpcClient { feesAmount: Int, currency: String, statementDescriptor: String, - externalReference: Option[String] + externalReference: Option[String], + token: Option[String] = None ): Future[TransactionResponse] = { - grpcClient.directDebit( - DirectDebitRequest( - creditedAccount, - debitedAmount, - feesAmount, - currency, - statementDescriptor, - externalReference - ) + withAuthorization( + grpcClient.directDebit(), + token ) + .invoke( + DirectDebitRequest( + creditedAccount, + debitedAmount, + feesAmount, + currency, + statementDescriptor, + externalReference + ) + ) } - def loadDirectDebitTransaction(directDebitTransactionId: String): Future[TransactionResponse] = { - grpcClient.loadDirectDebitTransaction( - LoadDirectDebitTransactionRequest(directDebitTransactionId) + def loadDirectDebitTransaction( + directDebitTransactionId: String, + token: Option[String] = None + ): Future[TransactionResponse] = { + withAuthorization( + grpcClient.loadDirectDebitTransaction(), + token ) + .invoke( + LoadDirectDebitTransactionRequest(directDebitTransactionId) + ) } def registerRecurringPayment( @@ -146,41 +203,64 @@ trait PaymentClient extends GrpcClient { frequency: Option[RecurringPayment.RecurringPaymentFrequency], fixedNextAmount: Option[Boolean], nextDebitedAmount: Option[Int], - nextFeesAmount: Option[Int] + nextFeesAmount: Option[Int], + token: Option[String] = None ): Future[Option[String]] = { - grpcClient.registerRecurringPayment( - RegisterRecurringPaymentRequest( - debitedAccount, - firstDebitedAmount, - firstFeesAmount, - currency, - `type`, - startDate, - endDate, - frequency match { - case Some(f) => f - case _ => - RegisterRecurringPaymentRequest.RecurringPaymentFrequency.UNKNOWN_PAYMENT_FREQUENCY - }, - fixedNextAmount, - nextDebitedAmount, - nextFeesAmount - ) - ) map (_.recurringPaymentRegistrationId) + withAuthorization( + grpcClient.registerRecurringPayment(), + token + ) + .invoke( + RegisterRecurringPaymentRequest( + debitedAccount, + firstDebitedAmount, + firstFeesAmount, + currency, + `type`, + startDate, + endDate, + frequency match { + case Some(f) => f + case _ => + RegisterRecurringPaymentRequest.RecurringPaymentFrequency.UNKNOWN_PAYMENT_FREQUENCY + }, + fixedNextAmount, + nextDebitedAmount, + nextFeesAmount + ) + ) map (_.recurringPaymentRegistrationId) } - def cancelMandate(externalUuid: String): Future[Boolean] = { - grpcClient.cancelMandate(CancelMandateRequest(externalUuid)) map (_.succeeded) + def cancelMandate(externalUuid: String, token: Option[String] = None): Future[Boolean] = { + withAuthorization( + grpcClient.cancelMandate(), + token + ) + .invoke(CancelMandateRequest(externalUuid)) map (_.succeeded) } - def loadBankAccountOwner(externalUuid: String): Future[BankAccountOwner] = { - grpcClient.loadBankAccountOwner(LoadBankAccountOwnerRequest(externalUuid)) map (response => + def loadBankAccountOwner( + externalUuid: String, + token: Option[String] = None + ): Future[BankAccountOwner] = { + withAuthorization( + grpcClient.loadBankAccountOwner(), + token + ) + .invoke(LoadBankAccountOwnerRequest(externalUuid)) map (response => BankAccountOwner(response.ownerName, response.ownerAddress) ) } - def loadLegalUserDetails(externalUuid: String): Future[LegalUserDetails] = { - grpcClient.loadLegalUser(LoadLegalUserRequest(externalUuid)) map (response => + def loadLegalUserDetails( + externalUuid: String, + token: Option[String] = None + ): Future[LegalUserDetails] = { + withAuthorization( + grpcClient.loadLegalUser(), + token + ) + .invoke(LoadLegalUserRequest(externalUuid)) map (response => LegalUserDetails( response.legalUserType, response.legalName, @@ -190,6 +270,38 @@ trait PaymentClient extends GrpcClient { ) ) } + + def generateClientTokens( + clientId: String, + clientSecret: String, + scope: Option[String] = None + ): Future[Option[Tokens]] = { + grpcClient + .generateClientTokens() + .invoke( + GenerateClientTokensRequest(clientId, clientSecret, scope) + ) map (response => + response.clientTokens match { + case r: ClientTokensResponse.ClientTokens.Tokens => + r.tokens + case _ => None + } + ) + } + + def refreshClientTokens(refreshToken: String): Future[Option[Tokens]] = { + grpcClient + .refreshClientTokens() + .invoke( + RefreshClientTokensRequest(refreshToken) + ) map (response => + response.clientTokens match { + case r: ClientTokensResponse.ClientTokens.Tokens => + r.tokens + case _ => None + } + ) + } } object PaymentClient extends GrpcClientFactory[PaymentClient] { diff --git a/common/src/main/scala/app/softnetwork/payment/config/PaymentSettings.scala b/common/src/main/scala/app/softnetwork/payment/config/PaymentSettings.scala index b601006..c216508 100644 --- a/common/src/main/scala/app/softnetwork/payment/config/PaymentSettings.scala +++ b/common/src/main/scala/app/softnetwork/payment/config/PaymentSettings.scala @@ -1,5 +1,6 @@ package app.softnetwork.payment.config +import com.softwaremill.session.SessionConfig import com.typesafe.config.{Config, ConfigFactory} import com.typesafe.scalalogging.StrictLogging @@ -33,6 +34,9 @@ trait PaymentSettings extends StrictLogging { config.getString("payment.event-streams.external-to-payment-account-tag") val AkkaNodeRole: String = config.getString("payment.akka-node-role") + + val ClientSessionConfig: SessionConfig = + SessionConfig.fromConfig(config.getConfig("payment.client").withFallback(config)) } object PaymentSettings extends PaymentSettings diff --git a/common/src/main/scala/app/softnetwork/payment/message/AccountMessages.scala b/common/src/main/scala/app/softnetwork/payment/message/AccountMessages.scala index 8915d66..44de2b1 100644 --- a/common/src/main/scala/app/softnetwork/payment/message/AccountMessages.scala +++ b/common/src/main/scala/app/softnetwork/payment/message/AccountMessages.scala @@ -4,11 +4,12 @@ import app.softnetwork.account.message.{ AccountCommand, AccountCommandResult, AccountErrorMessage, + LookupAccountCommand, SignUp } import app.softnetwork.account.model.BasicAccountProfile import app.softnetwork.payment.annotation.InternalApi -import app.softnetwork.payment.model.SoftPaymentAccount +import app.softnetwork.payment.model.{ApiKey, SoftPaymentAccount} object AccountMessages { case class SoftPaymentSignup( @@ -22,16 +23,32 @@ object AccountMessages { case class RegisterProvider(provider: SoftPaymentAccount.Client.Provider) extends AccountCommand @InternalApi - private[payment] case class LoadProvider(clientId: String) extends AccountCommand + private[payment] case class LoadClient(clientId: String) extends LookupAccountCommand + + case object ListApiKeys extends AccountCommand + + case class GenerateClientToken( + client_id: String, + client_secret: String, + scope: Option[String] = None + ) extends LookupAccountCommand + + case class RefreshClientToken(refreshToken: String) extends LookupAccountCommand + + case class OAuthClient(token: String) extends LookupAccountCommand case class ProviderRegistered(client: SoftPaymentAccount.Client) extends AccountCommandResult - case class ProviderLoaded(provider: SoftPaymentAccount.Client.Provider) + case class ClientLoaded(client: SoftPaymentAccount.Client) extends AccountCommandResult + + case class ApiKeysLoaded(apiKeys: Seq[ApiKey]) extends AccountCommandResult + + case class OAuthClientSucceededResult(client: SoftPaymentAccount.Client) extends AccountCommandResult case object ProviderAlreadyRegistered extends AccountErrorMessage("provider.already.registered") case object ProviderNotRegistered extends AccountErrorMessage("provider.not.registered") - case object ProviderNotFound extends AccountErrorMessage("provider.not.found") + case object ClientNotFound extends AccountErrorMessage("client.not.found") } diff --git a/common/src/main/scala/app/softnetwork/payment/model/SoftPaymentAccountDecorator.scala b/common/src/main/scala/app/softnetwork/payment/model/SoftPaymentAccountDecorator.scala index 3d46a59..0b05cf6 100644 --- a/common/src/main/scala/app/softnetwork/payment/model/SoftPaymentAccountDecorator.scala +++ b/common/src/main/scala/app/softnetwork/payment/model/SoftPaymentAccountDecorator.scala @@ -7,4 +7,11 @@ trait SoftPaymentAccountDecorator { _: SoftPaymentAccount => override def newProfile(name: String): Profile = BasicAccountProfile.defaultInstance.withName(name) + lazy val apiKeys: Seq[ApiKey] = + this.clients.map(client => ApiKey(client.clientId, client.clientApiKey)) } + +case class ApiKey( + clientId: String, + clientApiKey: Option[String] = None +) diff --git a/common/src/main/scala/app/softnetwork/payment/model/SoftPaymentClientDecorator.scala b/common/src/main/scala/app/softnetwork/payment/model/SoftPaymentClientDecorator.scala index 37fe167..4476786 100644 --- a/common/src/main/scala/app/softnetwork/payment/model/SoftPaymentClientDecorator.scala +++ b/common/src/main/scala/app/softnetwork/payment/model/SoftPaymentClientDecorator.scala @@ -6,6 +6,7 @@ trait SoftPaymentClientDecorator { _: SoftPaymentAccount.Client => def generateApiKey(): String = BearerTokenGenerator.generateSHAToken(clientId) + lazy val view: SoftPaymentClientView = SoftPaymentClientView(this) } case class SoftPaymentClientView( diff --git a/core/src/main/scala/app/softnetwork/payment/api/PaymentServer.scala b/core/src/main/scala/app/softnetwork/payment/api/PaymentServer.scala index 578d98c..ac5f8e0 100644 --- a/core/src/main/scala/app/softnetwork/payment/api/PaymentServer.scala +++ b/core/src/main/scala/app/softnetwork/payment/api/PaymentServer.scala @@ -1,7 +1,7 @@ package app.softnetwork.payment.api import akka.actor.typed.ActorSystem -import app.softnetwork.payment.handlers.GenericPaymentHandler +import app.softnetwork.payment.handlers.{GenericPaymentHandler, SoftPaymentAccountDao} import app.softnetwork.payment.message.PaymentMessages.{ BankAccountLoaded, CancelMandate, @@ -346,4 +346,42 @@ trait PaymentServer extends PaymentServiceApi with GenericPaymentHandler { case _ => LoadLegalUserResponse() } } + + def softPaymentAccountDao: SoftPaymentAccountDao = SoftPaymentAccountDao + + override def generateClientTokens( + in: GenerateClientTokensRequest + ): Future[ClientTokensResponse] = { + import in._ + softPaymentAccountDao.generateClientToken(clientId, clientSecret, scope) map { + case Some(tokens) => + import tokens._ + ClientTokensResponse.defaultInstance.withTokens( + Tokens( + access_token, + token_type, + expires_in, + refresh_token + ) + ) + case _ => ClientTokensResponse.defaultInstance.withError("unknown") + } + } + + override def refreshClientTokens(in: RefreshClientTokensRequest): Future[ClientTokensResponse] = { + import in._ + softPaymentAccountDao.refreshClientToken(refreshToken) map { + case Some(tokens) => + import tokens._ + ClientTokensResponse.defaultInstance.withTokens( + Tokens( + access_token, + token_type, + expires_in, + refresh_token + ) + ) + case _ => ClientTokensResponse.defaultInstance.withError("unknown") + } + } } diff --git a/core/src/main/scala/app/softnetwork/payment/handlers/SoftPaymentAccountDao.scala b/core/src/main/scala/app/softnetwork/payment/handlers/SoftPaymentAccountDao.scala index 5180489..fcd4292 100644 --- a/core/src/main/scala/app/softnetwork/payment/handlers/SoftPaymentAccountDao.scala +++ b/core/src/main/scala/app/softnetwork/payment/handlers/SoftPaymentAccountDao.scala @@ -2,11 +2,16 @@ package app.softnetwork.payment.handlers import akka.actor.typed.ActorSystem import akka.cluster.sharding.typed.scaladsl.EntityTypeKey +import app.softnetwork.account.config.AccountSettings import app.softnetwork.account.handlers.{AccountDao, AccountHandler} -import app.softnetwork.account.message.AccountCommand +import app.softnetwork.account.message.{ + AccessTokenGenerated, + AccessTokenRefreshed, + AccountCommand, + Tokens +} import app.softnetwork.payment.annotation.InternalApi import app.softnetwork.payment.message.AccountMessages -import app.softnetwork.payment.message.AccountMessages.ProviderLoaded import app.softnetwork.payment.model.SoftPaymentAccount import app.softnetwork.payment.persistence.typed.SoftPaymentAccountBehavior import app.softnetwork.persistence.typed.CommandTypeKey @@ -21,16 +26,68 @@ trait SoftPaymentAccountDao extends AccountDao { _: AccountHandler => clientId: String )(implicit system: ActorSystem[_]): Future[Option[SoftPaymentAccount.Client.Provider]] = { implicit val ec: ExecutionContext = system.executionContext - lookup(clientId) flatMap { - case Some(uuid) => - ?(uuid, AccountMessages.LoadProvider(clientId)) map { - case result: ProviderLoaded => Some(result.provider) - case _ => None - } - case _ => Future.successful(None) + loadClient(clientId).map(_.map(_.provider)) + } + + @InternalApi + private[payment] def loadClient( + clientId: String + )(implicit system: ActorSystem[_]): Future[Option[SoftPaymentAccount.Client]] = { + implicit val ec: ExecutionContext = system.executionContext + ??(clientId, AccountMessages.LoadClient(clientId)) map { + case result: AccountMessages.ClientLoaded => Some(result.client) + case _ => None + } + } + + @InternalApi + private[payment] def oauthClient( + token: String + )(implicit system: ActorSystem[_]): Future[Option[SoftPaymentAccount.Client]] = { + implicit val ec: ExecutionContext = system.executionContext + ??(token, AccountMessages.OAuthClient(token)) map { + case result: AccountMessages.OAuthClientSucceededResult => Some(result.client) + case _ => None } } + def generateClientToken( + clientId: String, + clientSecret: String, + scope: Option[String] = None + )(implicit system: ActorSystem[_]): Future[Option[Tokens]] = { + implicit val ec: ExecutionContext = system.executionContext + ??(clientId, AccountMessages.GenerateClientToken(clientId, clientSecret, scope)) map { + case result: AccessTokenGenerated => + Some( + Tokens( + result.accessToken.token, + result.accessToken.tokenType.toLowerCase(), + AccountSettings.OAuthSettings.accessToken.expirationTime * 60, + result.accessToken.refreshToken + ) + ) + case _ => None + } + } + + def refreshClientToken( + refreshToken: String + )(implicit system: ActorSystem[_]): Future[Option[Tokens]] = { + implicit val ec: ExecutionContext = system.executionContext + ??(refreshToken, AccountMessages.RefreshClientToken(refreshToken)) map { + case result: AccessTokenRefreshed => + Some( + Tokens( + result.accessToken.token, + result.accessToken.tokenType.toLowerCase(), + AccountSettings.OAuthSettings.accessToken.expirationTime * 60, + result.accessToken.refreshToken + ) + ) + case _ => None + } + } } trait SoftPaymentAccountTypeKey extends CommandTypeKey[AccountCommand] { diff --git a/core/src/main/scala/app/softnetwork/payment/persistence/typed/SoftPaymentAccountBehavior.scala b/core/src/main/scala/app/softnetwork/payment/persistence/typed/SoftPaymentAccountBehavior.scala index ebca6aa..ce6683d 100644 --- a/core/src/main/scala/app/softnetwork/payment/persistence/typed/SoftPaymentAccountBehavior.scala +++ b/core/src/main/scala/app/softnetwork/payment/persistence/typed/SoftPaymentAccountBehavior.scala @@ -1,30 +1,25 @@ package app.softnetwork.payment.persistence.typed -import akka.actor.typed.ActorRef +import akka.actor.typed.{ActorRef, ActorSystem} import akka.actor.typed.scaladsl.{ActorContext, TimerScheduler} import akka.persistence.typed.scaladsl.Effect import app.softnetwork.account.handlers.{DefaultGenerator, Generator} -import app.softnetwork.account.message -import app.softnetwork.account.message.{ - AccountCommand, - AccountCommandResult, - AccountCreatedEvent, - AccountNotFound, - BasicAccountProfileUpdatedEvent, - ProfileUpdatedEvent -} +import app.softnetwork.account.message._ import app.softnetwork.account.model.{BasicAccount, BasicAccountProfile, Principal, PrincipalType} import app.softnetwork.account.persistence.typed.AccountBehavior import app.softnetwork.payment.message.AccountMessages import app.softnetwork.payment.message.AccountMessages.SoftPaymentSignup import app.softnetwork.payment.message.SoftPaymentAccountEvents.{ SoftPaymentAccountCreatedEvent, - SoftPaymentAccountProviderRegisteredEvent + SoftPaymentAccountProviderRegisteredEvent, + SoftPaymentAccountTokenRefreshedEvent, + SoftPaymentAccountTokenRegisteredEvent } import app.softnetwork.payment.model.SoftPaymentAccount import app.softnetwork.payment.spi.PaymentProviders import app.softnetwork.persistence.typed._ import app.softnetwork.scheduler.message.SchedulerEvents.ExternalSchedulerEvent +import app.softnetwork.security.sha256 import java.time.Instant @@ -32,7 +27,7 @@ trait SoftPaymentAccountBehavior extends AccountBehavior[SoftPaymentAccount, Bas _: Generator => override protected def createAccount( entityId: String, - cmd: message.SignUp + cmd: SignUp )(implicit context: ActorContext[AccountCommand]): Option[SoftPaymentAccount] = { cmd match { case SoftPaymentSignup(_, _, provider, _, _) => @@ -41,7 +36,7 @@ trait SoftPaymentAccountBehavior extends AccountBehavior[SoftPaymentAccount, Bas SoftPaymentAccount(BasicAccount(cmd, Some(entityId))) .map(account => account - .withClient(client.withClientApiKey(client.generateApiKey())) + .withClients(Seq(client.withClientApiKey(client.generateApiKey()))) .withSecondaryPrincipals( account.secondaryPrincipals.filterNot( _.`type` == PrincipalType.Other @@ -86,11 +81,12 @@ trait SoftPaymentAccountBehavior extends AccountBehavior[SoftPaymentAccount, Bas )(implicit context: ActorContext[AccountCommand] ): Effect[ExternalSchedulerEvent, Option[SoftPaymentAccount]] = { + implicit val system: ActorSystem[_] = context.system command match { case AccountMessages.RegisterProvider(provider) => state match { case Some(account) => - if (account.client.isDefined) { + if (account.clients.exists(_.provider.providerId == provider.providerId)) { Effect.none.thenRun { _ => AccountMessages.ProviderAlreadyRegistered ~> replyTo } @@ -98,6 +94,7 @@ trait SoftPaymentAccountBehavior extends AccountBehavior[SoftPaymentAccount, Bas PaymentProviders.paymentProvider(provider).client match { case Some(client) => val updatedClient = client.withClientApiKey(client.generateApiKey()) + accountKeyDao.addAccountKey(updatedClient.clientId, entityId) Effect .persist( SoftPaymentAccountProviderRegisteredEvent( @@ -118,25 +115,176 @@ trait SoftPaymentAccountBehavior extends AccountBehavior[SoftPaymentAccount, Bas } } - case AccountMessages.LoadProvider(clientId) => + case AccountMessages.LoadClient(clientId) => state match { case Some(account) => - account.client match { + account.clients.find(_.clientId == clientId) match { case Some(client) => - if (client.clientId == clientId) { - Effect.none.thenRun { _ => - AccountMessages.ProviderLoaded(client.provider) ~> replyTo - } + Effect.none.thenRun { _ => + AccountMessages.ClientLoaded(client) ~> replyTo + } + case _ => + Effect.none.thenRun { _ => + AccountMessages.ClientNotFound ~> replyTo + } + } + case _ => + Effect.none.thenRun { _ => + AccountNotFound ~> replyTo + } + } + + case AccountMessages.ListApiKeys => + state match { + case Some(account) => + Effect.none.thenRun { _ => + AccountMessages.ApiKeysLoaded(account.apiKeys) ~> replyTo + } + case _ => + Effect.none.thenRun { _ => + AccountNotFound ~> replyTo + } + } + + case AccountMessages.GenerateClientToken( + clientId, + clientSecret, + scope + ) => // grant_type=client_credentials + state match { + case Some(account) if account.status.isActive => + account.clients.find(_.clientId == clientId) match { + case Some(client) if client.accessToken.exists(!_.expired) => + Effect.none.thenRun(_ => AccessTokenAlreadyExists ~> replyTo) + + case Some(client) if client.clientApiKey.isEmpty => + Effect.none.thenRun(_ => AccountMessages.ClientNotFound ~> replyTo) + + case Some(client) => + if (client.getClientApiKey == clientSecret) { + val accessToken = + generator.generateAccessToken( + account.primaryPrincipal.value, + scope + ) + accountKeyDao.addAccountKey(accessToken.token, entityId) + accountKeyDao.addAccountKey(accessToken.refreshToken, entityId) + Effect + .persist( + SoftPaymentAccountTokenRegisteredEvent( + client.withAccessToken( + accessToken.copy( + token = sha256(accessToken.token), + refreshToken = sha256(accessToken.refreshToken) + ) + ), + Instant.now() + ) + ) + .thenRun { _ => + AccessTokenGenerated(accessToken) ~> replyTo + } } else { Effect.none.thenRun { _ => - AccountMessages.ProviderNotFound ~> replyTo + AccountMessages.ClientNotFound ~> replyTo } } + case _ => Effect.none.thenRun { _ => - AccountMessages.ProviderNotFound ~> replyTo + AccountMessages.ClientNotFound ~> replyTo } } + + case Some(account) if account.status.isDisabled => + Effect.none.thenRun(_ => AccountDisabled ~> replyTo) + + case Some(account) if account.status.isDeleted => + Effect.none.thenRun(_ => AccountDeleted(account) ~> replyTo) + + case _ => + Effect.none.thenRun { _ => + AccountNotFound ~> replyTo + } + } + + case AccountMessages.RefreshClientToken(refreshToken) => + state match { + case Some(account) if account.status.isActive => + account.clients.find( + _.accessToken.map(_.refreshToken).getOrElse("") == sha256(refreshToken) + ) match { + case Some(client) => + val previousToken = client.getAccessToken + val accessToken = + generator.generateAccessToken( + account.primaryPrincipal.value, + previousToken.scope + ) + accountKeyDao.removeAccountKey(previousToken.token) + accountKeyDao.removeAccountKey(previousToken.refreshToken) + accountKeyDao.addAccountKey(accessToken.token, entityId) + accountKeyDao.addAccountKey(accessToken.refreshToken, entityId) + Effect + .persist( + SoftPaymentAccountTokenRefreshedEvent( + client.withAccessToken( + accessToken.copy( + token = sha256(accessToken.token), + refreshToken = sha256(accessToken.refreshToken) + ) + ), + Instant.now() + ) + ) + .thenRun { _ => + AccessTokenGenerated(accessToken) ~> replyTo + } + + case _ => + Effect.none.thenRun { _ => + AccountMessages.ClientNotFound ~> replyTo + } + } + + case Some(account) if account.status.isDisabled => + Effect.none.thenRun(_ => AccountDisabled ~> replyTo) + + case Some(account) if account.status.isDeleted => + Effect.none.thenRun(_ => AccountDeleted(account) ~> replyTo) + + case _ => + Effect.none.thenRun { _ => + AccountNotFound ~> replyTo + } + } + + case AccountMessages.OAuthClient(token) => + state match { + case Some(account) if account.status.isActive => + account.clients.find( + _.accessToken.map(_.token).getOrElse("") == sha256(token) + ) match { + case Some(client) if client.getAccessToken.expired => + Effect.none.thenRun(_ => TokenExpired ~> replyTo) + + case Some(client) => + Effect.none.thenRun { _ => + AccountMessages.OAuthClientSucceededResult(client) ~> replyTo + } + + case _ => + Effect.none.thenRun { _ => + AccountMessages.ClientNotFound ~> replyTo + } + } + + case Some(account) if account.status.isDisabled => + Effect.none.thenRun(_ => AccountDisabled ~> replyTo) + + case Some(account) if account.status.isDeleted => + Effect.none.thenRun(_ => AccountDeleted(account) ~> replyTo) + case _ => Effect.none.thenRun { _ => AccountNotFound ~> replyTo @@ -160,7 +308,26 @@ trait SoftPaymentAccountBehavior extends AccountBehavior[SoftPaymentAccount, Bas )(implicit context: ActorContext[_]): Option[SoftPaymentAccount] = { event match { case SoftPaymentAccountProviderRegisteredEvent(client, lastUpdated) => - state.map(_.withClient(client).withLastUpdated(lastUpdated)) + state.map(account => { + account + .withClients(account.clients.filterNot(_.clientId == client.clientId) :+ client) + .withLastUpdated(lastUpdated) + }) + + case SoftPaymentAccountTokenRegisteredEvent(client, lastUpdated) => + state.map(account => { + account + .withClients(account.clients.filterNot(_.clientId == client.clientId) :+ client) + .withLastUpdated(lastUpdated) + }) + + case SoftPaymentAccountTokenRefreshedEvent(client, lastUpdated) => + state.map(account => { + account + .withClients(account.clients.filterNot(_.clientId == client.clientId) :+ client) + .withLastUpdated(lastUpdated) + }) + case _ => super.handleEvent(state, event) } } diff --git a/core/src/main/scala/app/softnetwork/payment/service/BankAccountEndpoints.scala b/core/src/main/scala/app/softnetwork/payment/service/BankAccountEndpoints.scala index c7317d3..541df81 100644 --- a/core/src/main/scala/app/softnetwork/payment/service/BankAccountEndpoints.scala +++ b/core/src/main/scala/app/softnetwork/payment/service/BankAccountEndpoints.scala @@ -17,14 +17,14 @@ trait BankAccountEndpoints { _: RootPaymentEndpoints with GenericPaymentHandler import app.softnetwork.serialization._ val createOrUpdateBankAccount: ServerEndpoint[Any with AkkaStreams, Future] = - secureEndpoint.post + requiredSessionEndpoint.post .in(PaymentSettings.BankRoute) .in(jsonBody[BankAccountCommand].description("Legal or natural user bank account")) .out( statusCode(StatusCode.Ok) .and(jsonBody[BankAccountCreatedOrUpdated].description("Bank account created or updated")) ) - .serverLogic(session => { bank => + .serverLogic(principal => { bank => import bank._ var externalUuid: String = "" val updatedUser: Option[PaymentAccount.User] = { @@ -32,12 +32,12 @@ trait BankAccountEndpoints { _: RootPaymentEndpoints with GenericPaymentHandler case Left(naturalUser) => var updatedNaturalUser = { if (naturalUser.externalUuid.trim.isEmpty) { - naturalUser.withExternalUuid(session.id) + naturalUser.withExternalUuid(principal._2.id) } else { naturalUser } } - session.profile match { + principal._2.profile match { case Some(profile) if updatedNaturalUser.profile.isEmpty => updatedNaturalUser = updatedNaturalUser.withProfile(profile) case _ => @@ -47,9 +47,10 @@ trait BankAccountEndpoints { _: RootPaymentEndpoints with GenericPaymentHandler case Right(legalUser) => var updatedLegalRepresentative = legalUser.legalRepresentative if (updatedLegalRepresentative.externalUuid.trim.isEmpty) { - updatedLegalRepresentative = updatedLegalRepresentative.withExternalUuid(session.id) + updatedLegalRepresentative = + updatedLegalRepresentative.withExternalUuid(principal._2.id) } - session.profile match { + principal._2.profile match { case Some(profile) if updatedLegalRepresentative.profile.isEmpty => updatedLegalRepresentative = updatedLegalRepresentative.withProfile(profile) case _ => @@ -64,10 +65,11 @@ trait BankAccountEndpoints { _: RootPaymentEndpoints with GenericPaymentHandler } run( CreateOrUpdateBankAccount( - externalUuidWithProfile(session), + externalUuidWithProfile(principal._2), bankAccount.withExternalUuid(externalUuid), updatedUser, - acceptedTermsOfPSP + acceptedTermsOfPSP, + clientId = principal._1.map(_.clientId) ) ).map { case r: BankAccountCreatedOrUpdated => Right(r) @@ -77,7 +79,7 @@ trait BankAccountEndpoints { _: RootPaymentEndpoints with GenericPaymentHandler .description("Create or update legal or natural user bank account") val loadBankAccount: ServerEndpoint[Any with AkkaStreams, Future] = - secureEndpoint.get + requiredSessionEndpoint.get .in(PaymentSettings.BankRoute) .out( statusCode(StatusCode.Ok).and( @@ -85,10 +87,10 @@ trait BankAccountEndpoints { _: RootPaymentEndpoints with GenericPaymentHandler .description("Authenticated user bank account") ) ) - .serverLogic(session => + .serverLogic(principal => _ => { run( - LoadBankAccount(externalUuidWithProfile(session)) + LoadBankAccount(externalUuidWithProfile(principal._2)) ).map { case r: BankAccountLoaded => Right(r.bankAccount.view) case other => Left(error(other)) @@ -98,14 +100,14 @@ trait BankAccountEndpoints { _: RootPaymentEndpoints with GenericPaymentHandler .description("Load authenticated user bank account") val deleteBankAccount: ServerEndpoint[Any with AkkaStreams, Future] = - secureEndpoint.delete + requiredSessionEndpoint.delete .in(PaymentSettings.BankRoute) .out( statusCode(StatusCode.Ok).and(jsonBody[BankAccountDeleted.type]) ) - .serverLogic(session => + .serverLogic(principal => _ => - run(DeleteBankAccount(externalUuidWithProfile(session), Some(false))).map { + run(DeleteBankAccount(externalUuidWithProfile(principal._2), Some(false))).map { case BankAccountDeleted => Right(BankAccountDeleted) case other => Left(error(other)) } diff --git a/core/src/main/scala/app/softnetwork/payment/service/CardEndpoints.scala b/core/src/main/scala/app/softnetwork/payment/service/CardEndpoints.scala index 0d112f0..3a97ced 100644 --- a/core/src/main/scala/app/softnetwork/payment/service/CardEndpoints.scala +++ b/core/src/main/scala/app/softnetwork/payment/service/CardEndpoints.scala @@ -17,16 +17,16 @@ trait CardEndpoints { _: RootPaymentEndpoints with GenericPaymentHandler => import app.softnetwork.serialization._ val loadCards: ServerEndpoint[Any with AkkaStreams, Future] = - secureEndpoint.get + requiredSessionEndpoint.get .in(PaymentSettings.CardRoute) .out( statusCode(StatusCode.Ok).and( jsonBody[Seq[CardView]].description("Authenticated user cards") ) ) - .serverLogic(session => + .serverLogic(principal => _ => { - run(LoadCards(externalUuidWithProfile(session))).map { + run(LoadCards(externalUuidWithProfile(principal._2))).map { case r: CardsLoaded => Right(r.cards.map(_.view)) case other => Left(error(other)) } @@ -35,7 +35,7 @@ trait CardEndpoints { _: RootPaymentEndpoints with GenericPaymentHandler => .description("Load authenticated user cards") val preRegisterCard: ServerEndpoint[Any with AkkaStreams, Future] = - secureEndpoint.post + requiredSessionEndpoint.post .in(PaymentSettings.CardRoute) .in(jsonBody[PreRegisterCard]) .out( @@ -44,20 +44,20 @@ trait CardEndpoints { _: RootPaymentEndpoints with GenericPaymentHandler => .description("Card pre registration data") ) ) - .serverLogic(session => + .serverLogic(principal => cmd => { var updatedUser = if (cmd.user.externalUuid.trim.isEmpty) { - cmd.user.withExternalUuid(session.id) + cmd.user.withExternalUuid(principal._2.id) } else { cmd.user } - session.profile match { + principal._2.profile match { case Some(profile) if updatedUser.profile.isEmpty => updatedUser = updatedUser.withProfile(profile) case _ => } - run(cmd.copy(user = updatedUser)).map { + run(cmd.copy(user = updatedUser, clientId = principal._1.map(_.clientId))).map { case r: CardPreRegistered => Right(r.cardPreRegistration) case other => Left(error(other)) } @@ -66,15 +66,15 @@ trait CardEndpoints { _: RootPaymentEndpoints with GenericPaymentHandler => .description("Pre register card") val disableCard: ServerEndpoint[Any with AkkaStreams, Future] = - secureEndpoint.delete + requiredSessionEndpoint.delete .in(PaymentSettings.CardRoute) .in(query[String]("cardId").description("Card id to disable")) .out( statusCode(StatusCode.Ok).and(jsonBody[CardDisabled.type]) ) - .serverLogic(session => + .serverLogic(principal => cardId => { - run(DisableCard(externalUuidWithProfile(session), cardId)).map { + run(DisableCard(externalUuidWithProfile(principal._2), cardId)).map { case CardDisabled => Right(CardDisabled) case other => Left(error(other)) } diff --git a/core/src/main/scala/app/softnetwork/payment/service/CardPaymentEndpoints.scala b/core/src/main/scala/app/softnetwork/payment/service/CardPaymentEndpoints.scala index c6d0f2d..6b72b40 100644 --- a/core/src/main/scala/app/softnetwork/payment/service/CardPaymentEndpoints.scala +++ b/core/src/main/scala/app/softnetwork/payment/service/CardPaymentEndpoints.scala @@ -3,6 +3,7 @@ package app.softnetwork.payment.service import app.softnetwork.payment.config.PaymentSettings import app.softnetwork.payment.handlers.GenericPaymentHandler import app.softnetwork.payment.message.PaymentMessages._ +import app.softnetwork.payment.model.SoftPaymentAccount import org.softnetwork.session.model.Session import sttp.capabilities import sttp.capabilities.akka.AkkaStreams @@ -19,7 +20,7 @@ trait CardPaymentEndpoints { _: RootPaymentEndpoints with GenericPaymentHandler def payment(payment: Payment): PartialServerEndpointWithSecurityOutput[ (Seq[Option[String]], Option[String], Method, Option[String]), - Session, + (Option[SoftPaymentAccount.Client], Session), (Option[String], Option[String], Option[String], Option[String], Payment), Any, (Seq[Option[String]], Option[CookieValueWithMeta]), @@ -27,7 +28,7 @@ trait CardPaymentEndpoints { _: RootPaymentEndpoints with GenericPaymentHandler Any, Future ] = - secureEndpoint + requiredSessionEndpoint .in(header[Option[String]](HeaderNames.AcceptLanguage)) .in(header[Option[String]](HeaderNames.Accept)) .in(header[Option[String]](HeaderNames.UserAgent)) @@ -67,13 +68,13 @@ trait CardPaymentEndpoints { _: RootPaymentEndpoints with GenericPaymentHandler ) ) ) - .serverLogic(session => { case (language, accept, userAgent, ipAddress, payment) => + .serverLogic(principal => { case (language, accept, userAgent, ipAddress, payment) => val browserInfo = extractBrowserInfo(language, accept, userAgent, payment) import payment._ run( PreAuthorizeCard( orderUuid, - externalUuidWithProfile(session), + externalUuidWithProfile(principal._2), debitedAmount, currency, registrationId, @@ -155,14 +156,14 @@ trait CardPaymentEndpoints { _: RootPaymentEndpoints with GenericPaymentHandler ) ) ) - .serverLogic(session => { + .serverLogic(principal => { case (language, accept, userAgent, ipAddress, payment, creditedAccount) => val browserInfo = extractBrowserInfo(language, accept, userAgent, payment) import payment._ run( PayIn( orderUuid, - externalUuidWithProfile(session), + externalUuidWithProfile(principal._2), debitedAmount, currency, creditedAccount, @@ -268,14 +269,14 @@ trait CardPaymentEndpoints { _: RootPaymentEndpoints with GenericPaymentHandler ) ) ) - .serverLogic(session => { + .serverLogic(principal => { case (language, accept, userAgent, ipAddress, payment, recurringPaymentRegistrationId) => val browserInfo = extractBrowserInfo(language, accept, userAgent, payment) import payment._ run( PayInFirstRecurring( recurringPaymentRegistrationId, - externalUuidWithProfile(session), + externalUuidWithProfile(principal._2), if (browserInfo.isDefined) Some(ipAddress) else None, browserInfo, statementDescriptor diff --git a/core/src/main/scala/app/softnetwork/payment/service/ClientSession.scala b/core/src/main/scala/app/softnetwork/payment/service/ClientSession.scala new file mode 100644 index 0000000..44f6fc7 --- /dev/null +++ b/core/src/main/scala/app/softnetwork/payment/service/ClientSession.scala @@ -0,0 +1,83 @@ +package app.softnetwork.payment.service + +import app.softnetwork.concurrent.Completion +import app.softnetwork.payment.config.PaymentSettings.ClientSessionConfig +import app.softnetwork.payment.handlers.SoftPaymentAccountDao +import app.softnetwork.payment.model.SoftPaymentAccount +import app.softnetwork.session.service.SessionMaterials +import com.softwaremill.session._ +import org.softnetwork.session.model.Session + +import scala.language.implicitConversions +import scala.util.{Failure, Success} + +trait ClientSession extends Completion { _: SessionMaterials => + + def softPaymentAccountDao: SoftPaymentAccountDao = SoftPaymentAccountDao + + implicit def sessionConfig: SessionConfig + + implicit def toSession(client: SoftPaymentAccount.Client): Session = { + var session = Session(client.clientId) + session += (Session.adminKey, "false") + session += (Session.anonymousKey, "false") + session += ("iss", ClientSessionConfig.jwt.issuer.getOrElse("")) + session += ("sub", client.clientId) + session += ("scope", client.accessToken.flatMap(_.scope).getOrElse("")) + session + } + + def encodeClient( + client: SoftPaymentAccount.Client + ): String = { + clientSessionManager(client.clientId).clientSessionManager.encode(client) + } + + def decodeClient(data: String): Option[Session] = + manager(ClientSessionConfig).clientSessionManager.decode(data).toOption + + def clientSessionManager(clientId: String): SessionManager[Session] = { + implicit val innerSessionConfig: SessionConfig = + ClientSessionConfig.copy( + jwt = ClientSessionConfig.jwt.copy(subject = Some(clientId)), + sessionEncryptData = true + ) + manager(innerSessionConfig) + } + + def clientCookieName: String = ClientSessionConfig.sessionCookieConfig.name + + def sendToClientHeaderName: String = + ClientSessionConfig.sessionHeaderConfig.sendToClientHeaderName + + def getFromClientHeaderName: String = + ClientSessionConfig.sessionHeaderConfig.getFromClientHeaderName + + def sessionManager(clientId: Option[String]): SessionManager[Session] = { + clientId match { + case Some(id) => + softPaymentAccountDao.loadClient(id) complete () match { + case Success(s) => clientSessionManager(s) + case Failure(_) => manager + } + case _ => manager + } + } + + def clientSessionManager(client: Option[SoftPaymentAccount.Client]): SessionManager[Session] = { + client match { + case Some(c) => + implicit val innerSessionConfig: SessionConfig = + sessionConfig.copy( + jwt = sessionConfig.jwt.copy( + issuer = ClientSessionConfig.jwt.issuer, + subject = Some(c.clientId) + ), + sessionEncryptData = true, + serverSecret = c.getClientApiKey + ) + manager(innerSessionConfig) + case _ => manager + } + } +} diff --git a/core/src/main/scala/app/softnetwork/payment/service/ClientSessionDirectives.scala b/core/src/main/scala/app/softnetwork/payment/service/ClientSessionDirectives.scala new file mode 100644 index 0000000..ab43157 --- /dev/null +++ b/core/src/main/scala/app/softnetwork/payment/service/ClientSessionDirectives.scala @@ -0,0 +1,43 @@ +package app.softnetwork.payment.service + +import akka.http.scaladsl.server.Directives.authenticateOAuth2Async +import akka.http.scaladsl.server.Route +import akka.http.scaladsl.server.directives.Credentials +import app.softnetwork.account.config.AccountSettings +import app.softnetwork.payment.annotation.InternalApi +import app.softnetwork.payment.model.SoftPaymentAccount +import app.softnetwork.session.service.{SessionMaterials, SessionService} +import org.softnetwork.session.model.Session + +import scala.concurrent.Future + +trait ClientSessionDirectives extends SessionService with ClientSession { _: SessionMaterials => + + @InternalApi + private[payment] def requiredClientSession( + body: (Option[SoftPaymentAccount.Client], Session) => Route + ): Route = + authenticateOAuth2Async(AccountSettings.Realm, oauthClient).optional { client => + requiredSession(sc(clientSessionManager(client)), gt) { session => + body(client, session) + } + } + + @InternalApi + private[payment] def optionalClientSession( + body: (Option[SoftPaymentAccount.Client], Option[Session]) => Route + ): Route = + authenticateOAuth2Async(AccountSettings.Realm, oauthClient).optional { client => + optionalSession(sc(clientSessionManager(client)), gt) { session => + body(client, session) + } + } + + @InternalApi + private[payment] def oauthClient: Credentials => Future[Option[SoftPaymentAccount.Client]] = { + case _ @Credentials.Provided(token) => + softPaymentAccountDao.oauthClient(token) + case _ => Future.successful(None) + } + +} diff --git a/core/src/main/scala/app/softnetwork/payment/service/ClientSessionEndpoints.scala b/core/src/main/scala/app/softnetwork/payment/service/ClientSessionEndpoints.scala new file mode 100644 index 0000000..507a577 --- /dev/null +++ b/core/src/main/scala/app/softnetwork/payment/service/ClientSessionEndpoints.scala @@ -0,0 +1,153 @@ +package app.softnetwork.payment.service + +import app.softnetwork.account.config.AccountSettings +import app.softnetwork.payment.annotation.InternalApi +import app.softnetwork.payment.model.SoftPaymentAccount +import app.softnetwork.session._ +import app.softnetwork.session.service.{SessionEndpoints, SessionMaterials} +import com.softwaremill.session.{ + CookieOrHeaderST, + CookieST, + HeaderST, + SessionManager, + SessionResult +} +import org.json4s.Formats +import org.softnetwork.session.model.Session +import sttp.model.headers.WWWAuthenticateChallenge +import sttp.monad.FutureMonad +import sttp.tapir._ +import sttp.tapir.server.PartialServerEndpointWithSecurityOutput + +import scala.concurrent.Future + +trait ClientSessionEndpoints extends SessionEndpoints with ClientSession { + _: SessionMaterials => + + implicit def formats: Formats + + import TapirSessionOptions._ + + @InternalApi + private[payment] def requiredClientSession: PartialServerEndpointWithSecurityOutput[Seq[ + Option[String] + ], (Option[SoftPaymentAccount.Client], Session), Unit, Unit, Seq[ + Option[String] + ], Unit, Any, Future] = { + val partial = clientSession(Some(true)) + partial.endpoint + .out(partial.securityOutput) + .serverSecurityLogicWithOutput { inputs => + partial.securityLogic(new FutureMonad())(inputs).map { + case Left(l) => Left(l) + case Right(r) => + r._2._2.toOption match { + case Some(session) => Right((r._1, (r._2._1, session))) + case _ => Left(()) + } + } + } + } + + @InternalApi + private[payment] def optionalClientSession: PartialServerEndpointWithSecurityOutput[Seq[ + Option[String] + ], (Option[SoftPaymentAccount.Client], Option[Session]), Unit, Unit, Seq[ + Option[String] + ], Unit, Any, Future] = { + val partial = clientSession(Some(false)) + partial.endpoint + .out(partial.securityOutput) + .serverSecurityLogicWithOutput { inputs => + partial.securityLogic(new FutureMonad())(inputs).map { + case Left(l) => Left(l) + case Right(r) => Right((r._1, (r._2._1, r._2._2.toOption))) + } + } + } + + @InternalApi + private[payment] def clientSession( + required: Option[Boolean] + ): PartialServerEndpointWithSecurityOutput[Seq[ + Option[String] + ], (Option[SoftPaymentAccount.Client], SessionResult[Session]), Unit, Unit, Seq[ + Option[String] + ], Unit, Any, Future] = { + val partial = sc.session(gt, required) + partial.endpoint + .prependSecurityIn( + auth.bearer[Option[String]](WWWAuthenticateChallenge.bearer(AccountSettings.Realm)) + ) + .mapSecurityIn(inputs => Seq(inputs._1) ++ inputs._2)(seq => + (seq.head, seq.slice(1, seq.size)) + ) + .out(partial.securityOutput) + .serverSecurityLogicWithOutput { inputs => + (inputs.head match { + case Some(token) => softPaymentAccountDao.oauthClient(token) + case _ => Future.successful(None) + }) flatMap { client => + implicit val manager: SessionManager[Session] = clientSessionManager(client) + sessionType match { + case Session.SessionType.OneOffCookie | Session.SessionType.OneOffHeader => // oneOff + (gt match { + case CookieST => + sc.sessionLogic(None, inputs.tail.head, None, gt, required) + case HeaderST => + sc.sessionLogic(None, None, inputs.tail.head, gt, required) + case CookieOrHeaderST => + sc.sessionLogic(None, inputs.tail.head, inputs.last, gt, required) + }) match { + case Left(l) => Future.successful(Left(l)) + case Right(r) => Future.successful(Right((r._1, (client, r._2)))) + } + case _ => // refreshable + (gt match { + case CookieST => + oneOff.sessionLogic(None, inputs.tail.head, None, gt, required) match { + case Left(l) => Left(l) + case Right(r) => + refreshable.sessionLogic(Some(r._2), inputs.last, None, gt, required) + } + case HeaderST => + oneOff.sessionLogic(None, None, inputs.tail.head, gt, required) match { + case Left(l) => Left(l) + case Right(r) => + refreshable.sessionLogic(Some(r._2), None, inputs.last, gt, required) + } + case CookieOrHeaderST => + val oneOffInputs = inputs.tail.take(2) + val refreshableInputs = inputs.takeRight(2) + oneOff.sessionLogic( + None, + oneOffInputs.head, + oneOffInputs.last, + gt, + required + ) match { + case Left(l) => Left(l) + case Right(r) => + refreshable.sessionLogic( + Some(r._2), + refreshableInputs.head, + refreshableInputs.last, + gt, + required + ) + } + }) match { + case Left(l) => Future.successful(Left(l)) + case Right(r) => Future.successful(Right((r._1, (client, r._2)))) + } + } +// case None => +// partial.securityLogic(new FutureMonad())(inputs.tail).map { +// case Left(l) => Left(l) +// case Right(r) => Right((r._1, (None, r._2))) +// } + } + } + } + +} diff --git a/core/src/main/scala/app/softnetwork/payment/service/GenericPaymentEndpoints.scala b/core/src/main/scala/app/softnetwork/payment/service/GenericPaymentEndpoints.scala index d710c69..6812e3c 100644 --- a/core/src/main/scala/app/softnetwork/payment/service/GenericPaymentEndpoints.scala +++ b/core/src/main/scala/app/softnetwork/payment/service/GenericPaymentEndpoints.scala @@ -32,11 +32,11 @@ trait GenericPaymentEndpoints def hooks: Full[Unit, Unit, (String, String), Unit, Unit, Any, Future] val loadPaymentAccount: ServerEndpoint[Any with AkkaStreams, Future] = - secureEndpoint.get + requiredSessionEndpoint.get .out(jsonBody[PaymentAccountView].description("Authenticated user payment account")) - .serverLogic(session => + .serverLogic(principal => _ => { - run(LoadPaymentAccount(externalUuidWithProfile(session))).map { + run(LoadPaymentAccount(externalUuidWithProfile(principal._2))).map { case r: PaymentAccountLoaded => Right(r.paymentAccount.view) case other => Left(error(other)) } diff --git a/core/src/main/scala/app/softnetwork/payment/service/GenericPaymentService.scala b/core/src/main/scala/app/softnetwork/payment/service/GenericPaymentService.scala index 53cc5b8..0d40ac0 100644 --- a/core/src/main/scala/app/softnetwork/payment/service/GenericPaymentService.scala +++ b/core/src/main/scala/app/softnetwork/payment/service/GenericPaymentService.scala @@ -38,6 +38,7 @@ trait GenericPaymentService with StrictLogging with BasicPaymentService with ServiceWithSessionDirectives[PaymentCommand, PaymentResult] + with ClientSessionDirectives with ApiRoute { _: GenericPaymentHandler with SessionMaterials => implicit def serialization: Serialization.type = jackson.Serialization @@ -69,7 +70,7 @@ trait GenericPaymentService // check anti CSRF token hmacTokenCsrfProtection(checkHeader) { // check if a session exists - requiredSession(sc, gt) { session => + requiredClientSession { (client, session) => pathEnd { get { run(LoadCards(externalUuidWithProfile(session))) completeWith { @@ -96,7 +97,7 @@ trait GenericPaymentService updatedUser = updatedUser.withProfile(profile) case _ => } - run(cmd.copy(user = updatedUser)) completeWith { + run(cmd.copy(user = updatedUser, clientId = client.map(_.clientId))) completeWith { case r: CardPreRegistered => complete( HttpResponse( @@ -125,7 +126,7 @@ trait GenericPaymentService // check anti CSRF token hmacTokenCsrfProtection(checkHeader) { // check if a session exists - requiredSession(sc, gt) { session => + requiredClientSession { (_, session) => get { pathEnd { run(LoadPaymentAccount(externalUuidWithProfile(session))) completeWith { @@ -364,7 +365,7 @@ trait GenericPaymentService // check anti CSRF token hmacTokenCsrfProtection(checkHeader) { // check if a session exists - requiredSession(sc, gt) { session => + requiredClientSession { (client, session) => pathEnd { get { run(LoadBankAccount(externalUuidWithProfile(session))) completeWith { @@ -422,7 +423,8 @@ trait GenericPaymentService externalUuidWithProfile(session), bankAccount.withExternalUuid(externalUuid), updatedUser, - acceptedTermsOfPSP + acceptedTermsOfPSP, + client.map(_.clientId) ) ) completeWith { case r: BankAccountCreatedOrUpdated => @@ -446,7 +448,7 @@ trait GenericPaymentService // check anti CSRF token hmacTokenCsrfProtection(checkHeader) { // check if a session exists - requiredSession(sc, gt) { session => + requiredClientSession { (_, session) => pathEnd { get { run(GetUboDeclaration(externalUuidWithProfile(session))) completeWith { @@ -486,7 +488,7 @@ trait GenericPaymentService // check anti CSRF token hmacTokenCsrfProtection(checkHeader) { // check if a session exists - requiredSession(sc, gt) { session => + requiredClientSession { (_, session) => pathEnd { get { run( @@ -544,7 +546,7 @@ trait GenericPaymentService // check anti CSRF token hmacTokenCsrfProtection(checkHeader) { // check if a session exists - requiredSession(sc, gt) { session => + requiredClientSession { (_, session) => post { run(CreateMandate(externalUuidWithProfile(session))) completeWith { case r: MandateConfirmationRequired => @@ -567,7 +569,7 @@ trait GenericPaymentService // check anti CSRF token hmacTokenCsrfProtection(checkHeader) { // check if a session exists - requiredSession(sc, gt) { session => + requiredClientSession { (_, session) => get { pathPrefix(Segment) { recurringPaymentRegistrationId => run( diff --git a/core/src/main/scala/app/softnetwork/payment/service/KycDocumentEndpoints.scala b/core/src/main/scala/app/softnetwork/payment/service/KycDocumentEndpoints.scala index e55b605..a6032ca 100644 --- a/core/src/main/scala/app/softnetwork/payment/service/KycDocumentEndpoints.scala +++ b/core/src/main/scala/app/softnetwork/payment/service/KycDocumentEndpoints.scala @@ -18,7 +18,7 @@ trait KycDocumentEndpoints { _: RootPaymentEndpoints with GenericPaymentHandler import app.softnetwork.serialization._ val loadKycDocument: ServerEndpoint[Any with AkkaStreams, Future] = - secureEndpoint.get + requiredSessionEndpoint.get .in(PaymentSettings.KycRoute) .in( query[String]("documentType") @@ -34,14 +34,14 @@ trait KycDocumentEndpoints { _: RootPaymentEndpoints with GenericPaymentHandler .description("Kyc document validation report") ) ) - .serverLogic(session => { documentType => + .serverLogic(principal => { documentType => val maybeKycDocumentType: Option[KycDocument.KycDocumentType] = KycDocument.KycDocumentType.enumCompanion.fromName(documentType) maybeKycDocumentType match { case None => Future.successful(Left(ApiErrors.BadRequest("wrong kyc document type"))) case Some(kycDocumentType) => - run(LoadKycDocumentStatus(externalUuidWithProfile(session), kycDocumentType)).map { + run(LoadKycDocumentStatus(externalUuidWithProfile(principal._2), kycDocumentType)).map { case r: KycDocumentStatusLoaded => Right(r.report) case other => Left(error(other)) } @@ -50,7 +50,7 @@ trait KycDocumentEndpoints { _: RootPaymentEndpoints with GenericPaymentHandler .description("Load Kyc document validation report") val addKycDocument: ServerEndpoint[Any with AkkaStreams, Future] = - secureEndpoint.post + requiredSessionEndpoint.post .in(PaymentSettings.KycRoute) .in( query[String]("documentType") @@ -67,14 +67,14 @@ trait KycDocumentEndpoints { _: RootPaymentEndpoints with GenericPaymentHandler ) ) ) - .serverLogic(session => { case (documentType, pages) => + .serverLogic(principal => { case (documentType, pages) => val maybeKycDocumentType: Option[KycDocument.KycDocumentType] = KycDocument.KycDocumentType.enumCompanion.fromName(documentType) maybeKycDocumentType match { case None => Future.successful(Left(ApiErrors.BadRequest("wrong kyc document type"))) case Some(kycDocumentType) => - run(AddKycDocument(externalUuidWithProfile(session), pages.bytes, kycDocumentType)) + run(AddKycDocument(externalUuidWithProfile(principal._2), pages.bytes, kycDocumentType)) .map { case r: KycDocumentAdded => Right(r) case other => Left(error(other)) diff --git a/core/src/main/scala/app/softnetwork/payment/service/MandateEndpoints.scala b/core/src/main/scala/app/softnetwork/payment/service/MandateEndpoints.scala index 665468e..3449e0c 100644 --- a/core/src/main/scala/app/softnetwork/payment/service/MandateEndpoints.scala +++ b/core/src/main/scala/app/softnetwork/payment/service/MandateEndpoints.scala @@ -17,7 +17,7 @@ trait MandateEndpoints { _: RootPaymentEndpoints with GenericPaymentHandler => import app.softnetwork.serialization._ val createMandate: ServerEndpoint[Any with AkkaStreams, Future] = - secureEndpoint.post + requiredSessionEndpoint.post .in(PaymentSettings.MandateRoute) .out( oneOf[PaymentResult]( @@ -32,9 +32,9 @@ trait MandateEndpoints { _: RootPaymentEndpoints with GenericPaymentHandler => ) ) ) - .serverLogic(session => + .serverLogic(principal => _ => - run(CreateMandate(externalUuidWithProfile(session))).map { + run(CreateMandate(externalUuidWithProfile(principal._2))).map { case MandateCreated => Right(MandateCreated) case r: MandateConfirmationRequired => Right(r) case other => Left(error(other)) @@ -43,15 +43,15 @@ trait MandateEndpoints { _: RootPaymentEndpoints with GenericPaymentHandler => .description("Create a mandate for the authenticated payment account") val cancelMandate: ServerEndpoint[Any with AkkaStreams, Future] = - secureEndpoint.delete + requiredSessionEndpoint.delete .in(PaymentSettings.MandateRoute) .out( statusCode(StatusCode.Ok) .and(jsonBody[MandateCanceled.type].description("Mandate canceled")) ) - .serverLogic(session => + .serverLogic(principal => _ => - run(CancelMandate(externalUuidWithProfile(session))).map { + run(CancelMandate(externalUuidWithProfile(principal._2))).map { case MandateCanceled => Right(MandateCanceled) case other => Left(error(other)) } diff --git a/core/src/main/scala/app/softnetwork/payment/service/RecurringPaymentEndpoints.scala b/core/src/main/scala/app/softnetwork/payment/service/RecurringPaymentEndpoints.scala index 4a1e53f..0a104b7 100644 --- a/core/src/main/scala/app/softnetwork/payment/service/RecurringPaymentEndpoints.scala +++ b/core/src/main/scala/app/softnetwork/payment/service/RecurringPaymentEndpoints.scala @@ -17,7 +17,7 @@ trait RecurringPaymentEndpoints { _: RootPaymentEndpoints with GenericPaymentHan import app.softnetwork.serialization._ val registerRecurringPayment: ServerEndpoint[Any with AkkaStreams, Future] = - secureEndpoint.post + requiredSessionEndpoint.post .in(PaymentSettings.RecurringPaymentRoute) .in(jsonBody[RegisterRecurringPayment].description("Recurring payment to register")) .out( @@ -38,9 +38,9 @@ trait RecurringPaymentEndpoints { _: RootPaymentEndpoints with GenericPaymentHan ) ) ) - .serverLogic(session => + .serverLogic(principal => cmd => - run(cmd.copy(debitedAccount = externalUuidWithProfile(session))).map { + run(cmd.copy(debitedAccount = externalUuidWithProfile(principal._2))).map { case r: RecurringPaymentRegistered => Right(r) case r: MandateConfirmationRequired => Right(r) case other => Left(error(other)) @@ -49,7 +49,7 @@ trait RecurringPaymentEndpoints { _: RootPaymentEndpoints with GenericPaymentHan .description("Register a recurring payment for the authenticated payment account") val loadRecurringPayment: ServerEndpoint[Any with AkkaStreams, Future] = - secureEndpoint.get + requiredSessionEndpoint.get .in(PaymentSettings.RecurringPaymentRoute) .in(path[String]) .out( @@ -58,11 +58,11 @@ trait RecurringPaymentEndpoints { _: RootPaymentEndpoints with GenericPaymentHan .description("Recurring payment successfully loaded") ) ) - .serverLogic(session => + .serverLogic(principal => recurringPaymentRegistrationId => run( LoadRecurringPayment( - externalUuidWithProfile(session), + externalUuidWithProfile(principal._2), recurringPaymentRegistrationId ) ).map { @@ -73,7 +73,7 @@ trait RecurringPaymentEndpoints { _: RootPaymentEndpoints with GenericPaymentHan .description("Load the recurring payment of the authenticated payment account") val updateRecurringCardPaymentRegistration: ServerEndpoint[Any with AkkaStreams, Future] = - secureEndpoint.put + requiredSessionEndpoint.put .in(PaymentSettings.RecurringPaymentRoute) .in( jsonBody[UpdateRecurringCardPaymentRegistration].description( @@ -87,9 +87,9 @@ trait RecurringPaymentEndpoints { _: RootPaymentEndpoints with GenericPaymentHan .description("Recurring card payment successfully updated") ) ) - .serverLogic(session => + .serverLogic(principal => cmd => - run(cmd.copy(debitedAccount = externalUuidWithProfile(session))).map { + run(cmd.copy(debitedAccount = externalUuidWithProfile(principal._2))).map { case r: RecurringCardPaymentRegistrationUpdated => Right(r.result) case other => Left(error(other)) } @@ -99,18 +99,18 @@ trait RecurringPaymentEndpoints { _: RootPaymentEndpoints with GenericPaymentHan ) val deleteRecurringPayment: ServerEndpoint[Any with AkkaStreams, Future] = - secureEndpoint.delete + requiredSessionEndpoint.delete .in(PaymentSettings.RecurringPaymentRoute) .in(path[String]) .out( statusCode(StatusCode.Ok) .and(jsonBody[RecurringPayment.RecurringCardPaymentResult]) ) - .serverLogic(session => + .serverLogic(principal => recurringPaymentRegistrationId => run( UpdateRecurringCardPaymentRegistration( - externalUuidWithProfile(session), + externalUuidWithProfile(principal._2), recurringPaymentRegistrationId, None, Some(RecurringPayment.RecurringCardPaymentStatus.ENDED) diff --git a/core/src/main/scala/app/softnetwork/payment/service/RootPaymentEndpoints.scala b/core/src/main/scala/app/softnetwork/payment/service/RootPaymentEndpoints.scala index 717ea92..1cd26e0 100644 --- a/core/src/main/scala/app/softnetwork/payment/service/RootPaymentEndpoints.scala +++ b/core/src/main/scala/app/softnetwork/payment/service/RootPaymentEndpoints.scala @@ -5,9 +5,9 @@ import app.softnetwork.api.server.ApiErrors import app.softnetwork.payment.config.PaymentSettings import app.softnetwork.payment.handlers.GenericPaymentHandler import app.softnetwork.payment.message.PaymentMessages._ +import app.softnetwork.payment.model.SoftPaymentAccount import app.softnetwork.payment.serialization.paymentFormats import app.softnetwork.session.service.{ServiceWithSessionEndpoints, SessionMaterials} -import com.softwaremill.session.SessionConfig import org.json4s.Formats import org.softnetwork.session.model.Session import sttp.model.headers.CookieValueWithMeta @@ -20,13 +20,12 @@ import scala.language.implicitConversions trait RootPaymentEndpoints extends BasicPaymentService - with ServiceWithSessionEndpoints[PaymentCommand, PaymentResult] { + with ServiceWithSessionEndpoints[PaymentCommand, PaymentResult] + with ClientSessionEndpoints { _: GenericPaymentHandler with SessionMaterials => override implicit def formats: Formats = paymentFormats - implicit def sessionConfig: SessionConfig - override implicit def ts: ActorSystem[_] = system override implicit def resultToApiError(result: PaymentResult): ApiErrors.ErrorInfo = error(result) @@ -35,9 +34,9 @@ trait RootPaymentEndpoints endpoint .in(PaymentSettings.PaymentPath) - lazy val secureEndpoint: PartialServerEndpointWithSecurityOutput[ + lazy val requiredSessionEndpoint: PartialServerEndpointWithSecurityOutput[ (Seq[Option[String]], Option[String], Method, Option[String]), - Session, + (Option[SoftPaymentAccount.Client], Session), Unit, Any, (Seq[Option[String]], Option[CookieValueWithMeta]), @@ -48,8 +47,27 @@ trait RootPaymentEndpoints ApiErrors .withApiErrorVariants( hmacTokenCsrfProtection(checkMode) { - requiredSession(sc, st) + requiredClientSession } ) .in(PaymentSettings.PaymentPath) + + lazy val optionalSessionEndpoint: PartialServerEndpointWithSecurityOutput[ + (Seq[Option[String]], Option[String], Method, Option[String]), + (Option[SoftPaymentAccount.Client], Option[Session]), + Unit, + Any, + (Seq[Option[String]], Option[CookieValueWithMeta]), + Unit, + Any, + Future + ] = + ApiErrors + .withApiErrorVariants( + hmacTokenCsrfProtection(checkMode) { + optionalClientSession + } + ) + .in(PaymentSettings.PaymentPath) + } diff --git a/core/src/main/scala/app/softnetwork/payment/service/SoftPaymentAccountService.scala b/core/src/main/scala/app/softnetwork/payment/service/SoftPaymentAccountService.scala index 6795422..703fd51 100644 --- a/core/src/main/scala/app/softnetwork/payment/service/SoftPaymentAccountService.scala +++ b/core/src/main/scala/app/softnetwork/payment/service/SoftPaymentAccountService.scala @@ -1,22 +1,25 @@ package app.softnetwork.payment.service -import akka.http.scaladsl.model.HttpRequest import akka.http.scaladsl.server.Route -import akka.http.scaladsl.unmarshalling.Unmarshaller import app.softnetwork.account.config.AccountSettings -import app.softnetwork.account.message.SignUp import app.softnetwork.account.service.BasicAccountService +import app.softnetwork.payment.config.PaymentSettings.ClientSessionConfig import app.softnetwork.payment.handlers.SoftPaymentAccountTypeKey -import app.softnetwork.payment.message.AccountMessages.SoftPaymentSignup +import app.softnetwork.payment.serialization.paymentFormats import app.softnetwork.session.service.SessionMaterials +import com.softwaremill.session.SessionConfig +import org.json4s.Formats trait SoftPaymentAccountService extends BasicAccountService with SoftPaymentAccountTypeKey { _: SessionMaterials => + implicit def sessionConfig: SessionConfig = ClientSessionConfig + + override implicit lazy val formats: Formats = paymentFormats + override val route: Route = { pathPrefix(AccountSettings.Path) { signUp ~ - basic ~ login ~ activate ~ logout ~ diff --git a/core/src/main/scala/app/softnetwork/payment/service/SoftPaymentAccountServiceEndpoints.scala b/core/src/main/scala/app/softnetwork/payment/service/SoftPaymentAccountServiceEndpoints.scala index 013cf00..903ce05 100644 --- a/core/src/main/scala/app/softnetwork/payment/service/SoftPaymentAccountServiceEndpoints.scala +++ b/core/src/main/scala/app/softnetwork/payment/service/SoftPaymentAccountServiceEndpoints.scala @@ -1,8 +1,12 @@ package app.softnetwork.payment.service import app.softnetwork.account.service.BasicAccountServiceEndpoints +import app.softnetwork.payment.config.PaymentSettings.ClientSessionConfig import app.softnetwork.payment.handlers.SoftPaymentAccountTypeKey +import app.softnetwork.payment.serialization.paymentFormats import app.softnetwork.session.service.SessionMaterials +import com.softwaremill.session.SessionConfig +import org.json4s.Formats import sttp.capabilities import sttp.capabilities.akka.AkkaStreams import sttp.tapir.server.ServerEndpoint @@ -13,6 +17,10 @@ trait SoftPaymentAccountServiceEndpoints extends BasicAccountServiceEndpoints with SoftPaymentAccountTypeKey { _: SessionMaterials => + implicit def sessionConfig: SessionConfig = ClientSessionConfig + + override implicit lazy val formats: Formats = paymentFormats + override lazy val endpoints : List[ServerEndpoint[AkkaStreams with capabilities.WebSockets, Future]] = List( diff --git a/core/src/main/scala/app/softnetwork/payment/service/SoftPaymentOAuthService.scala b/core/src/main/scala/app/softnetwork/payment/service/SoftPaymentOAuthService.scala index acb689d..278a161 100644 --- a/core/src/main/scala/app/softnetwork/payment/service/SoftPaymentOAuthService.scala +++ b/core/src/main/scala/app/softnetwork/payment/service/SoftPaymentOAuthService.scala @@ -1,17 +1,115 @@ package app.softnetwork.payment.service -import akka.http.scaladsl.server.Route +import akka.http.scaladsl.model.StatusCodes +import akka.http.scaladsl.model.headers.BasicHttpCredentials +import akka.http.scaladsl.server.{AuthenticationFailedRejection, RejectionHandler, Route} import app.softnetwork.account.config.AccountSettings +import app.softnetwork.account.message.{ + AccessTokenGenerated, + AccessTokenRefreshed, + AccountErrorMessage, + Tokens +} import app.softnetwork.account.service.OAuthService +import app.softnetwork.payment.config.PaymentSettings.ClientSessionConfig import app.softnetwork.payment.handlers.SoftPaymentAccountTypeKey +import app.softnetwork.payment.message.AccountMessages.{GenerateClientToken, RefreshClientToken} +import app.softnetwork.payment.serialization.paymentFormats import app.softnetwork.session.service.SessionMaterials +import com.softwaremill.session.SessionConfig +import org.json4s.Formats +import org.softnetwork.session.model.Session -trait SoftPaymentOAuthService extends OAuthService with SoftPaymentAccountTypeKey { +trait SoftPaymentOAuthService + extends OAuthService + with SoftPaymentAccountTypeKey + with ClientSessionDirectives { _: SessionMaterials => + implicit def sessionConfig: SessionConfig = ClientSessionConfig + + override implicit lazy val formats: Formats = paymentFormats + override val route: Route = { pathPrefix(AccountSettings.OAuthPath) { - concat(authorize :: (signin ++ backup).toList: _*) + concat(token ~ me :: (signin ++ backup).toList: _*) + } + } + + override lazy val token: Route = + path("token") { + post { + formField("grant_type") { + case "client_credentials" => + formField("credentials") { credentials => + val httpCredentials = BasicHttpCredentials(credentials) + val clientId = httpCredentials.username + val clientSecret = httpCredentials.password + run(clientId, GenerateClientToken(clientId, clientSecret)) completeWith { + case r: AccessTokenGenerated => + complete( + StatusCodes.OK, + Tokens( + r.accessToken.token, + r.accessToken.tokenType.toLowerCase(), + AccountSettings.OAuthSettings.accessToken.expirationTime * 60, + r.accessToken.refreshToken + ) + ) + case error: AccountErrorMessage => + complete( + StatusCodes.BadRequest, + Map( + "error" -> "access_denied", + "error_description" -> error.message + ) + ) + case _ => complete(StatusCodes.BadRequest) + } + } + case "refresh_token" => + formField("refresh_token") { refreshToken => + run(refreshToken, RefreshClientToken(refreshToken)) completeWith { + case r: AccessTokenRefreshed => + complete( + StatusCodes.OK, + Tokens( + r.accessToken.token, + r.accessToken.tokenType.toLowerCase(), + AccountSettings.OAuthSettings.accessToken.expirationTime * 60, + r.accessToken.refreshToken + ) + ) + case error: AccountErrorMessage => + complete( + StatusCodes.BadRequest, + Map( + "error" -> "access_denied", + "error_description" -> error.message + ) + ) + case _ => complete(StatusCodes.BadRequest) + } + } + case _ => complete(StatusCodes.BadRequest) + } + } + } + + override lazy val me: Route = path("me") { + get { + handleRejections( + RejectionHandler + .newBuilder() + .handleAll[AuthenticationFailedRejection](authenticationFailedRejectionHandler) + .result() + ) { + authenticateOAuth2Async(AccountSettings.Realm, oauthClient) { client => + setSession(sc(clientSessionManager(client.clientId)), st, client.asInstanceOf[Session]) { + complete(StatusCodes.OK) + } + } + } } } diff --git a/core/src/main/scala/app/softnetwork/payment/service/SoftPaymentOAuthServiceEndpoints.scala b/core/src/main/scala/app/softnetwork/payment/service/SoftPaymentOAuthServiceEndpoints.scala index 05a060a..36ff028 100644 --- a/core/src/main/scala/app/softnetwork/payment/service/SoftPaymentOAuthServiceEndpoints.scala +++ b/core/src/main/scala/app/softnetwork/payment/service/SoftPaymentOAuthServiceEndpoints.scala @@ -1,22 +1,202 @@ package app.softnetwork.payment.service +import akka.http.scaladsl.model.headers.BasicHttpCredentials +import app.softnetwork.account.config.AccountSettings +import app.softnetwork.account.message.{ + AccessTokenGenerated, + AccessTokenRefreshed, + AccountErrorMessage, + BearerAuthenticationFailed, + Tokens +} import app.softnetwork.account.service.OAuthServiceEndpoints +import app.softnetwork.api.server.ApiErrors +import app.softnetwork.payment.config.PaymentSettings.ClientSessionConfig import app.softnetwork.payment.handlers.SoftPaymentAccountTypeKey +import app.softnetwork.payment.message.AccountMessages.{ + GenerateClientToken, + OAuthClient, + OAuthClientSucceededResult, + RefreshClientToken +} +import app.softnetwork.payment.serialization.paymentFormats +import app.softnetwork.session.httpCookieToTapirCookieWithMeta import app.softnetwork.session.service.SessionMaterials +import com.softwaremill.session.{CookieST, HeaderST, SessionConfig} +import org.json4s.Formats import sttp.capabilities import sttp.capabilities.akka.AkkaStreams +import sttp.model.headers.WWWAuthenticateChallenge +import sttp.tapir.EndpointIO.Example +import sttp.tapir.json.json4s.jsonBody import sttp.tapir.server.ServerEndpoint import scala.concurrent.Future trait SoftPaymentOAuthServiceEndpoints extends OAuthServiceEndpoints - with SoftPaymentAccountTypeKey { _: SessionMaterials => + with SoftPaymentAccountTypeKey + with ClientSession { _: SessionMaterials => + + import app.softnetwork.serialization.serialization + + implicit def sessionConfig: SessionConfig = ClientSessionConfig + + override implicit lazy val formats: Formats = paymentFormats override lazy val endpoints : List[ServerEndpoint[AkkaStreams with capabilities.WebSockets, Future]] = List( - authorize + token, + me ) ++ services.map(signin) ++ services.map(backup) + override val token: ServerEndpoint[Any with AkkaStreams, Future] = + endpoint.post + .in(AccountSettings.OAuthPath / "token") + .description("OAuth2 token endpoint") + .errorOut(ApiErrors.oneOfApiErrors) + .in( + formBody[Map[String, String]] + .description("form body") + .map[ClientTokenRequest](m => ClientTokenRequest.decode(m))(ClientTokenRequest.encode) + .example( + Example.of( + ClientCredentials( + "SplxlOBeZQQYbYS6WxSbIA", + Some("*") + ), + Some("client credentials request") + ) + ) + .example( + Example.of( + RefreshToken("tGzv3JOkF0XG5Qx2TlKWIA"), + Some("refresh token request") + ) + ) + ) + .out(jsonBody[Tokens]) + .serverLogic { + case tokenRequest: ClientCredentials => + import tokenRequest._ + val httpCredentials = BasicHttpCredentials(credentials) + val clientId = httpCredentials.username + val clientSecret = httpCredentials.password + run(clientId, GenerateClientToken(clientId, clientSecret)) map { + case r: AccessTokenGenerated => + Right( + Tokens( + r.accessToken.token, + r.accessToken.tokenType.toLowerCase(), + AccountSettings.OAuthSettings.accessToken.expirationTime * 60, + r.accessToken.refreshToken + ) + ) + case error: AccountErrorMessage => + Left(ApiErrors.BadRequest(error.message)) + case _ => Left(ApiErrors.BadRequest("Unknown")) + } + case tokenRequest: RefreshToken => + import tokenRequest._ + run(refreshToken, RefreshClientToken(refreshToken)) map { + case r: AccessTokenRefreshed => + Right( + Tokens( + r.accessToken.token, + r.accessToken.tokenType.toLowerCase(), + AccountSettings.OAuthSettings.accessToken.expirationTime * 60, + r.accessToken.refreshToken + ) + ) + case error: AccountErrorMessage => + Left(ApiErrors.BadRequest(error.message)) + case _ => Left(ApiErrors.BadRequest("Unknown")) + } + case tokenRequest: UnsupportedGrantType => + Future.successful( + Left(ApiErrors.BadRequest(s"Unknown grant_type ${tokenRequest.grantType}")) + ) + } + + override val me: ServerEndpoint[Any with AkkaStreams, Future] = + endpoint.get + .in(AccountSettings.OAuthPath / "me") + .description("OAuth2 me endpoint") + .securityIn(auth.bearer[String](WWWAuthenticateChallenge.bearer(AccountSettings.Realm))) + .errorOut(ApiErrors.oneOfApiErrors) + .out(setCookieOpt(clientCookieName)) + .out(header[Option[String]](sendToClientHeaderName)) + .serverSecurityLogicWithOutput[Unit, Future](token => + run(token, OAuthClient(token)) map { + case r: OAuthClientSucceededResult => + val encoded = encodeClient(r.client) + Right( + st match { + case HeaderST => + (None, Some(encoded)) + case CookieST => + ( + Some(manager.clientSessionManager.createCookieWithValue(encoded).valueWithMeta), + None + ) + }, + () + ) + + case _ => Left(resultToApiError(BearerAuthenticationFailed)) + } + ) + .serverLogic { _ => _ => + Future.successful( + Right(()) + ) + } + +} + +sealed trait ClientTokenRequest { + def asMap(): Map[String, String] +} + +case class ClientCredentials(credentials: String, scope: Option[String] = None) + extends ClientTokenRequest { + override def asMap(): Map[String, String] = + Map( + "grant_type" -> "client_credentials", + "credentials" -> credentials, + "scope" -> scope.getOrElse("") + ) +} + +case class RefreshToken(refreshToken: String) extends ClientTokenRequest { + override def asMap(): Map[String, String] = + Map( + "grant_type" -> "refresh_token", + "refresh_token" -> refreshToken + ) +} + +case class UnsupportedGrantType(grantType: String) extends ClientTokenRequest { + override def asMap(): Map[String, String] = + Map( + "grant_type" -> grantType + ) +} + +object ClientTokenRequest { + def decode(form: Map[String, String]): ClientTokenRequest = { + form.getOrElse("grant_type", "") match { + case "client_credentials" => + ClientCredentials( + form("credentials"), + form.get("scope") + ) + case "refresh_token" => + RefreshToken(form("refresh_token")) + case other => UnsupportedGrantType(other) + } + } + + def encode(tokenRequest: ClientTokenRequest): Map[String, String] = tokenRequest.asMap() } diff --git a/core/src/main/scala/app/softnetwork/payment/service/UboDeclarationEndpoints.scala b/core/src/main/scala/app/softnetwork/payment/service/UboDeclarationEndpoints.scala index 6f93906..f305813 100644 --- a/core/src/main/scala/app/softnetwork/payment/service/UboDeclarationEndpoints.scala +++ b/core/src/main/scala/app/softnetwork/payment/service/UboDeclarationEndpoints.scala @@ -17,7 +17,7 @@ trait UboDeclarationEndpoints { _: RootPaymentEndpoints with GenericPaymentHandl import app.softnetwork.serialization._ val addUboDeclaration: ServerEndpoint[Any with AkkaStreams, Future] = - secureEndpoint.post + requiredSessionEndpoint.post .in(PaymentSettings.DeclarationRoute) .in( jsonBody[UboDeclaration.UltimateBeneficialOwner] @@ -30,8 +30,8 @@ trait UboDeclarationEndpoints { _: RootPaymentEndpoints with GenericPaymentHandl .description("The UBO successfully recorded") ) ) - .serverLogic(session => { ubo => - run(CreateOrUpdateUbo(externalUuidWithProfile(session), ubo)).map { + .serverLogic(principal => { ubo => + run(CreateOrUpdateUbo(externalUuidWithProfile(principal._2), ubo)).map { case r: UboCreatedOrUpdated => Right(r.ubo) case other => Left(error(other)) } @@ -39,7 +39,7 @@ trait UboDeclarationEndpoints { _: RootPaymentEndpoints with GenericPaymentHandl .description("Record an UBO for the authenticated legal payment account") val loadUboDeclaration: ServerEndpoint[Any with AkkaStreams, Future] = - secureEndpoint.get + requiredSessionEndpoint.get .in(PaymentSettings.DeclarationRoute) .out( statusCode(StatusCode.Ok) @@ -48,9 +48,9 @@ trait UboDeclarationEndpoints { _: RootPaymentEndpoints with GenericPaymentHandl .description("Ubo declaration of the authenticated legal payment account") ) ) - .serverLogic(session => + .serverLogic(principal => _ => - run(GetUboDeclaration(externalUuidWithProfile(session))).map { + run(GetUboDeclaration(externalUuidWithProfile(principal._2))).map { case r: UboDeclarationLoaded => Right(r.declaration.view) case other => Left(error(other)) } @@ -58,7 +58,7 @@ trait UboDeclarationEndpoints { _: RootPaymentEndpoints with GenericPaymentHandl .description("Load the Ubo declaration of the authenticated legal payment account") val validateUboDeclaration: ServerEndpoint[Any with AkkaStreams, Future] = - secureEndpoint.put + requiredSessionEndpoint.put .in(PaymentSettings.DeclarationRoute) .out( statusCode(StatusCode.Ok).and( @@ -67,9 +67,9 @@ trait UboDeclarationEndpoints { _: RootPaymentEndpoints with GenericPaymentHandl ) ) ) - .serverLogic(session => + .serverLogic(principal => _ => - run(ValidateUboDeclaration(externalUuidWithProfile(session))).map { + run(ValidateUboDeclaration(externalUuidWithProfile(principal._2))).map { case UboDeclarationAskedForValidation => Right(UboDeclarationAskedForValidation) case other => Left(error(other)) } diff --git a/mangopay/api/build.sbt b/mangopay/api/build.sbt index 04ae0cf..986d3dc 100644 --- a/mangopay/api/build.sbt +++ b/mangopay/api/build.sbt @@ -27,5 +27,5 @@ organization := "app.softnetwork.payment" name := "mangopay-api" libraryDependencies ++= Seq( - "app.softnetwork.scheduler" %% "scheduler-api" % Versions.scheduler + "app.softnetwork.notification" %% "notification-api" % Versions.notification ) diff --git a/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayEndpoints.scala b/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayEndpoints.scala index bdb97bd..4e4fe3d 100644 --- a/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayEndpoints.scala +++ b/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayEndpoints.scala @@ -43,7 +43,7 @@ trait MangoPayEndpoints extends PaymentEndpoints { sessionConfig: SessionConfig ): SessionManager[Session] = self.manager override protected def sessionType: Session.SessionType = self.sessionType - override implicit def sessionConfig: SessionConfig = self.sessionConfig +// override implicit def sessionConfig: SessionConfig = self.sessionConfig override protected val manifestWrapper: ManifestW = ManifestW() } @@ -56,7 +56,7 @@ trait MangoPayEndpoints extends PaymentEndpoints { sessionConfig: SessionConfig ): SessionManager[Session] = self.manager override protected def sessionType: Session.SessionType = self.sessionType - override implicit def sessionConfig: SessionConfig = self.sessionConfig +// override implicit def sessionConfig: SessionConfig = self.sessionConfig } override def endpoints: ActorSystem[_] => List[Endpoint] = system => diff --git a/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayRoutes.scala b/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayRoutes.scala index ab62b47..aecc279 100644 --- a/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayRoutes.scala +++ b/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayRoutes.scala @@ -49,7 +49,7 @@ trait MangoPayRoutes extends PaymentRoutes { self: MangoPayApi with SchemaProvid ): SessionManager[Session] = self.manager override protected def sessionType: Session.SessionType = self.sessionType override def log: Logger = LoggerFactory getLogger getClass.getName - override implicit def sessionConfig: SessionConfig = self.sessionConfig +// override implicit def sessionConfig: SessionConfig = self.sessionConfig override implicit def system: ActorSystem[_] = sys override lazy val ec: ExecutionContext = sys.executionContext override protected val manifestWrapper: ManifestW = ManifestW() @@ -62,7 +62,7 @@ trait MangoPayRoutes extends PaymentRoutes { self: MangoPayApi with SchemaProvid ): SessionManager[Session] = self.manager override protected def sessionType: Session.SessionType = self.sessionType override def log: Logger = LoggerFactory getLogger getClass.getName - override implicit def sessionConfig: SessionConfig = self.sessionConfig +// override implicit def sessionConfig: SessionConfig = self.sessionConfig override implicit def system: ActorSystem[_] = sys override lazy val ec: ExecutionContext = sys.executionContext } diff --git a/mangopay/src/main/scala/app/softnetwork/payment/api/MangoPayServer.scala b/mangopay/src/main/scala/app/softnetwork/payment/api/MangoPayServer.scala index 9a08607..2ad48c7 100644 --- a/mangopay/src/main/scala/app/softnetwork/payment/api/MangoPayServer.scala +++ b/mangopay/src/main/scala/app/softnetwork/payment/api/MangoPayServer.scala @@ -1,7 +1,7 @@ package app.softnetwork.payment.api import akka.actor.typed.ActorSystem -import app.softnetwork.payment.handlers.MangoPayPaymentTypeKey +import app.softnetwork.payment.handlers.{MangoPayPaymentTypeKey, SoftPaymentAccountDao} import org.slf4j.{Logger, LoggerFactory} trait MangoPayServer extends PaymentServer with MangoPayPaymentTypeKey diff --git a/project/Versions.scala b/project/Versions.scala index 8d45c62..ba9b5db 100644 --- a/project/Versions.scala +++ b/project/Versions.scala @@ -1,12 +1,12 @@ object Versions { - val genericPersistence = "0.5.0" + val genericPersistence = "0.5.1" - val scheduler = "0.5.0" + val scheduler = "0.5.1" - val notification = "0.5.0" + val notification = "0.5.1" - val account = "0.5.0" + val account = "0.5.1" val scalatest = "3.2.16" } diff --git a/testkit/src/main/scala/app/softnetwork/payment/api/MockPaymentServer.scala b/testkit/src/main/scala/app/softnetwork/payment/api/MockPaymentServer.scala index 77ab6f4..0bd9a16 100644 --- a/testkit/src/main/scala/app/softnetwork/payment/api/MockPaymentServer.scala +++ b/testkit/src/main/scala/app/softnetwork/payment/api/MockPaymentServer.scala @@ -1,7 +1,11 @@ package app.softnetwork.payment.api import akka.actor.typed.ActorSystem -import app.softnetwork.payment.handlers.MockPaymentTypeKey +import app.softnetwork.payment.handlers.{ + MockPaymentTypeKey, + MockSoftPaymentAccountDao, + SoftPaymentAccountDao +} import org.slf4j.{Logger, LoggerFactory} trait MockPaymentServer extends PaymentServer with MockPaymentTypeKey @@ -9,6 +13,7 @@ trait MockPaymentServer extends PaymentServer with MockPaymentTypeKey object MockPaymentServer { def apply(sys: ActorSystem[_]): MockPaymentServer = { new MockPaymentServer { + override def softPaymentAccountDao: SoftPaymentAccountDao = MockSoftPaymentAccountDao lazy val log: Logger = LoggerFactory getLogger getClass.getName override implicit val system: ActorSystem[_] = sys } diff --git a/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentEndpointsTestKit.scala b/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentEndpointsTestKit.scala index 8550fbe..f188b6b 100644 --- a/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentEndpointsTestKit.scala +++ b/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentEndpointsTestKit.scala @@ -5,6 +5,7 @@ import app.softnetwork.account.message import app.softnetwork.account.message.BasicAccountSignUp import app.softnetwork.account.service.{AccountServiceEndpoints, OAuthServiceEndpoints} import app.softnetwork.api.server.Endpoint +import app.softnetwork.payment.handlers.{MockSoftPaymentAccountDao, SoftPaymentAccountDao} import app.softnetwork.payment.launch.PaymentEndpoints import app.softnetwork.payment.service.{ GenericPaymentEndpoints, @@ -43,6 +44,7 @@ trait PaymentEndpointsTestKit extends PaymentEndpoints with SessionEndpointsRout override implicit def sessionConfig: SessionConfig = self.sessionConfig override implicit def system: ActorSystem[_] = sys override lazy val ec: ExecutionContext = sys.executionContext + override def softPaymentAccountDao: SoftPaymentAccountDao = MockSoftPaymentAccountDao } override def endpoints: ActorSystem[_] => List[Endpoint] = @@ -56,7 +58,7 @@ trait PaymentEndpointsTestKit extends PaymentEndpoints with SessionEndpointsRout ): SessionManager[Session] = self.manager override protected def sessionType: Session.SessionType = self.sessionType override def log: Logger = LoggerFactory getLogger getClass.getName - override implicit def sessionConfig: SessionConfig = self.sessionConfig +// override implicit def sessionConfig: SessionConfig = self.sessionConfig override implicit def system: ActorSystem[_] = sys override lazy val ec: ExecutionContext = sys.executionContext override protected val manifestWrapper: ManifestW = ManifestW() @@ -69,8 +71,9 @@ trait PaymentEndpointsTestKit extends PaymentEndpoints with SessionEndpointsRout ): SessionManager[Session] = self.manager override protected def sessionType: Session.SessionType = self.sessionType override def log: Logger = LoggerFactory getLogger getClass.getName - override implicit def sessionConfig: SessionConfig = self.sessionConfig +// override implicit def sessionConfig: SessionConfig = self.sessionConfig override implicit def system: ActorSystem[_] = sys override lazy val ec: ExecutionContext = sys.executionContext + override def softPaymentAccountDao: SoftPaymentAccountDao = MockSoftPaymentAccountDao } } diff --git a/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentRoutesTestKit.scala b/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentRoutesTestKit.scala index 124c43c..07a025e 100644 --- a/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentRoutesTestKit.scala +++ b/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentRoutesTestKit.scala @@ -8,6 +8,7 @@ import app.softnetwork.account.model.{ } import app.softnetwork.account.service.{AccountService, OAuthService} import app.softnetwork.api.server.ApiRoute +import app.softnetwork.payment.handlers.{MockSoftPaymentAccountDao, SoftPaymentAccountDao} import app.softnetwork.payment.launch.PaymentRoutes import app.softnetwork.payment.service.{ GenericPaymentService, @@ -37,6 +38,7 @@ trait PaymentRoutesTestKit extends PaymentRoutes with SessionServiceRoutes { override implicit def sessionConfig: SessionConfig = self.sessionConfig override implicit def system: ActorSystem[_] = sys override lazy val ec: ExecutionContext = sys.executionContext + override def softPaymentAccountDao: SoftPaymentAccountDao = MockSoftPaymentAccountDao } implicit def sessionConfig: SessionConfig @@ -52,7 +54,7 @@ trait PaymentRoutesTestKit extends PaymentRoutes with SessionServiceRoutes { ): SessionManager[Session] = self.manager override protected def sessionType: Session.SessionType = self.sessionType override def log: Logger = LoggerFactory getLogger getClass.getName - override implicit def sessionConfig: SessionConfig = self.sessionConfig +// override implicit def sessionConfig: SessionConfig = self.sessionConfig override implicit def system: ActorSystem[_] = sys override lazy val ec: ExecutionContext = sys.executionContext override protected val manifestWrapper: ManifestW = ManifestW() @@ -65,9 +67,10 @@ trait PaymentRoutesTestKit extends PaymentRoutes with SessionServiceRoutes { ): SessionManager[Session] = self.manager override protected def sessionType: Session.SessionType = self.sessionType override def log: Logger = LoggerFactory getLogger getClass.getName - override implicit def sessionConfig: SessionConfig = self.sessionConfig +// override implicit def sessionConfig: SessionConfig = self.sessionConfig override implicit def system: ActorSystem[_] = sys override lazy val ec: ExecutionContext = sys.executionContext + override def softPaymentAccountDao: SoftPaymentAccountDao = MockSoftPaymentAccountDao } override def apiRoutes: ActorSystem[_] => List[ApiRoute] = From 37ba7338bce04e2c4bc213bf67892035a6422f54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Manciot?= Date: Thu, 30 Nov 2023 15:21:00 +0100 Subject: [PATCH 05/37] add JwtClaims materials --- common/src/main/protobuf/model/jwt.proto | 36 +++++++++ .../main/protobuf/model/payment/client.proto | 1 + .../payment/message/AccountMessages.scala | 9 ++- .../payment/model/ProviderDecorator.scala | 5 ++ .../model/SoftPaymentAccountDecorator.scala | 6 +- .../session/model/JwtClaimsCompanion.scala | 81 +++++++++++++++++++ .../session/model/JwtClaimsDecorator.scala | 80 ++++++++++++++++++ .../handlers/SoftPaymentAccountDao.scala | 14 +++- .../typed/SoftPaymentAccountBehavior.scala | 19 +++++ .../payment/service/ClientSession.scala | 31 ++++++- .../service/ClientSessionDirectives.scala | 15 ++-- .../service/ClientSessionEndpoints.scala | 14 ++-- .../service/SoftPaymentAccountService.scala | 2 +- .../service/SoftPaymentOAuthService.scala | 4 +- .../session/handlers/ApiKeyDao.scala | 12 +++ .../JwtClaimsRefreshTokenHandler.scala | 33 ++++++++ .../typed/JwtClaimsRefreshTokenBehavior.scala | 9 +++ .../session/service/JwtClaimsDirectives.scala | 40 +++++++++ .../session/service/JwtClaimsEncoder.scala | 65 +++++++++++++++ .../session/service/JwtClaimsEndpoints.scala | 39 +++++++++ .../session/service/JwtClaimsManager.scala | 20 +++++ .../session/service/JwtClaimsMaterials.scala | 24 ++++++ .../session/service/JwtClaimsSerializer.scala | 21 +++++ .../ServiceWithJwtClaimsDirectives.scala | 11 +++ .../ServiceWithJwtClaimsEndpoints.scala | 9 +++ .../payment/api/MangoPayRoutes.scala | 2 - .../payment/spi/MockMangoPayProvider.scala | 2 +- 27 files changed, 574 insertions(+), 30 deletions(-) create mode 100644 common/src/main/protobuf/model/jwt.proto create mode 100644 common/src/main/scala/app/softnetwork/payment/model/ProviderDecorator.scala create mode 100644 common/src/main/scala/app/softnetwork/session/model/JwtClaimsCompanion.scala create mode 100644 common/src/main/scala/app/softnetwork/session/model/JwtClaimsDecorator.scala create mode 100644 core/src/main/scala/app/softnetwork/session/handlers/ApiKeyDao.scala create mode 100644 core/src/main/scala/app/softnetwork/session/handlers/JwtClaimsRefreshTokenHandler.scala create mode 100644 core/src/main/scala/app/softnetwork/session/persistence/typed/JwtClaimsRefreshTokenBehavior.scala create mode 100644 core/src/main/scala/app/softnetwork/session/service/JwtClaimsDirectives.scala create mode 100644 core/src/main/scala/app/softnetwork/session/service/JwtClaimsEncoder.scala create mode 100644 core/src/main/scala/app/softnetwork/session/service/JwtClaimsEndpoints.scala create mode 100644 core/src/main/scala/app/softnetwork/session/service/JwtClaimsManager.scala create mode 100644 core/src/main/scala/app/softnetwork/session/service/JwtClaimsMaterials.scala create mode 100644 core/src/main/scala/app/softnetwork/session/service/JwtClaimsSerializer.scala create mode 100644 core/src/main/scala/app/softnetwork/session/service/ServiceWithJwtClaimsDirectives.scala create mode 100644 core/src/main/scala/app/softnetwork/session/service/ServiceWithJwtClaimsEndpoints.scala diff --git a/common/src/main/protobuf/model/jwt.proto b/common/src/main/protobuf/model/jwt.proto new file mode 100644 index 0000000..cce4e02 --- /dev/null +++ b/common/src/main/protobuf/model/jwt.proto @@ -0,0 +1,36 @@ +syntax = "proto3"; + +import "scalapb/scalapb.proto"; +import "google/protobuf/wrappers.proto"; + +package app.softnetwork.session.model; + +option (scalapb.options) = { + single_file: true + flat_package: true + import: "app.softnetwork.persistence.model._" + import: "app.softnetwork.serialization._" + import: "app.softnetwork.session.model._" + preserve_unknown_fields: false +}; + +message JwtClaims { + option (scalapb.message).extends = "SessionData"; + option (scalapb.message).extends = "JwtClaimsDecorator"; + option (scalapb.message).companion_extends = "JwtClaimsCompanion"; + map data = 1 [(scalapb.field).map_type="collection.immutable.Map", (scalapb.field).scala_name = "additionalClaims"]; + bool refreshable = 2; + google.protobuf.StringValue iss = 3; + google.protobuf.StringValue sub = 4; + google.protobuf.StringValue aud = 5; + google.protobuf.Int64Value exp = 6; + google.protobuf.Int64Value nbf = 7; + google.protobuf.Int64Value iat = 8; + google.protobuf.StringValue jti = 9; +} + +message ApiKey { + option (scalapb.message).extends = "ProtobufDomainObject"; + string clientId = 1; + google.protobuf.StringValue clientSecret = 2; +} diff --git a/common/src/main/protobuf/model/payment/client.proto b/common/src/main/protobuf/model/payment/client.proto index 9c63198..ee0c853 100644 --- a/common/src/main/protobuf/model/payment/client.proto +++ b/common/src/main/protobuf/model/payment/client.proto @@ -32,6 +32,7 @@ message SoftPaymentAccount { STRIPE = 1; } + option (scalapb.message).extends = "ProviderDecorator"; required string providerId = 1; required string providerApiKey = 2; required ProviderType providerType = 3 [default = MANGOPAY]; diff --git a/common/src/main/scala/app/softnetwork/payment/message/AccountMessages.scala b/common/src/main/scala/app/softnetwork/payment/message/AccountMessages.scala index 44de2b1..4ef244f 100644 --- a/common/src/main/scala/app/softnetwork/payment/message/AccountMessages.scala +++ b/common/src/main/scala/app/softnetwork/payment/message/AccountMessages.scala @@ -9,7 +9,8 @@ import app.softnetwork.account.message.{ } import app.softnetwork.account.model.BasicAccountProfile import app.softnetwork.payment.annotation.InternalApi -import app.softnetwork.payment.model.{ApiKey, SoftPaymentAccount} +import app.softnetwork.payment.model.SoftPaymentAccount +import app.softnetwork.session.model.ApiKey object AccountMessages { case class SoftPaymentSignup( @@ -25,6 +26,8 @@ object AccountMessages { @InternalApi private[payment] case class LoadClient(clientId: String) extends LookupAccountCommand + case class LoadApiKey(clientId: String) extends LookupAccountCommand + case object ListApiKeys extends AccountCommand case class GenerateClientToken( @@ -43,6 +46,8 @@ object AccountMessages { case class ApiKeysLoaded(apiKeys: Seq[ApiKey]) extends AccountCommandResult + case class ApiKeyLoaded(apiKey: ApiKey) extends AccountCommandResult + case class OAuthClientSucceededResult(client: SoftPaymentAccount.Client) extends AccountCommandResult @@ -51,4 +56,6 @@ object AccountMessages { case object ProviderNotRegistered extends AccountErrorMessage("provider.not.registered") case object ClientNotFound extends AccountErrorMessage("client.not.found") + + case object ApiKeyNotFound extends AccountErrorMessage("api.key.not.found") } diff --git a/common/src/main/scala/app/softnetwork/payment/model/ProviderDecorator.scala b/common/src/main/scala/app/softnetwork/payment/model/ProviderDecorator.scala new file mode 100644 index 0000000..9b64914 --- /dev/null +++ b/common/src/main/scala/app/softnetwork/payment/model/ProviderDecorator.scala @@ -0,0 +1,5 @@ +package app.softnetwork.payment.model + +trait ProviderDecorator { _: SoftPaymentAccount.Client.Provider => + lazy val clientId = s"$providerId.${providerType.name.toLowerCase}" +} diff --git a/common/src/main/scala/app/softnetwork/payment/model/SoftPaymentAccountDecorator.scala b/common/src/main/scala/app/softnetwork/payment/model/SoftPaymentAccountDecorator.scala index 0b05cf6..6215789 100644 --- a/common/src/main/scala/app/softnetwork/payment/model/SoftPaymentAccountDecorator.scala +++ b/common/src/main/scala/app/softnetwork/payment/model/SoftPaymentAccountDecorator.scala @@ -1,6 +1,7 @@ package app.softnetwork.payment.model import app.softnetwork.account.model.{BasicAccountProfile, Profile} +import app.softnetwork.session.model.ApiKey trait SoftPaymentAccountDecorator { _: SoftPaymentAccount => @@ -10,8 +11,3 @@ trait SoftPaymentAccountDecorator { _: SoftPaymentAccount => lazy val apiKeys: Seq[ApiKey] = this.clients.map(client => ApiKey(client.clientId, client.clientApiKey)) } - -case class ApiKey( - clientId: String, - clientApiKey: Option[String] = None -) diff --git a/common/src/main/scala/app/softnetwork/session/model/JwtClaimsCompanion.scala b/common/src/main/scala/app/softnetwork/session/model/JwtClaimsCompanion.scala new file mode 100644 index 0000000..e2d5e85 --- /dev/null +++ b/common/src/main/scala/app/softnetwork/session/model/JwtClaimsCompanion.scala @@ -0,0 +1,81 @@ +package app.softnetwork.session.model + +import app.softnetwork.persistence.generateUUID +import app.softnetwork.session.config.Settings.Session._ +import org.json4s._ +import org.json4s.jackson.JsonMethods._ + +import java.util.Base64 +import scala.util.Try + +trait JwtClaimsCompanion { + val adminKey = "admin" + + val profileKey = "profile" + + val anonymousKey = "anonymous" + + val idKey: String = DefaultSessionConfig.sessionCookieConfig.name + + val clientIdKey: String = "client_id" + + val refreshable: Boolean = Continuity match { + case "refreshable" => true + case _ => false + } + + def apply(): JwtClaims = + JwtClaims.defaultInstance + .withAdditionalClaims(Map(idKey -> generateUUID())) + .withRefreshable(refreshable) + + def apply(s: String): JwtClaims = + Try { + val sCleaned = if (s.startsWith("Bearer")) s.substring(7).trim else s + val List(_, p, _) = sCleaned.split("\\.").toList + val decodedValue = Try { + parse(new String(Base64.getUrlDecoder.decode(p), "utf-8")) + } + for (jv <- decodedValue) yield { + val iss = jv \\ "iss" match { + case JString(value) => Some(value) + case _ => None + } + val sub = jv \\ "sub" match { + case JString(value) => Some(value) + case _ => None + } + val aud = jv \\ "aud" match { + case JString(value) => Some(value) + case _ => None + } + val exp = jv \\ "exp" match { + case JInt(value) => Some(value.toLong) + case _ => None + } + val nbf = jv \\ "nbf" match { + case JInt(value) => Some(value.toLong) + case _ => None + } + val iat = jv \\ "iat" match { + case JInt(value) => Some(value.toLong) + case _ => None + } + val jti = jv \\ "jti" match { + case JString(value) => Some(value) + case _ => None + } + JwtClaims( + Map.empty, + refreshable, + iss, + sub, + aud, + exp, + nbf, + iat, + jti + ).withId(sub.getOrElse(generateUUID())) + } + }.flatten.toOption.getOrElse(JwtClaims()) +} diff --git a/common/src/main/scala/app/softnetwork/session/model/JwtClaimsDecorator.scala b/common/src/main/scala/app/softnetwork/session/model/JwtClaimsDecorator.scala new file mode 100644 index 0000000..650a872 --- /dev/null +++ b/common/src/main/scala/app/softnetwork/session/model/JwtClaimsDecorator.scala @@ -0,0 +1,80 @@ +package app.softnetwork.session.model + +trait JwtClaimsDecorator { self: JwtClaims => + + import JwtClaims._ + + private var dirty: Boolean = false + + def isDirty: Boolean = dirty + + def get(key: String): Option[String] = additionalClaims.get(key) + + def isEmpty: Boolean = additionalClaims.isEmpty + + def contains(key: String): Boolean = additionalClaims.contains(key) + + def -(key: String): JwtClaims = + synchronized { + dirty = true + withAdditionalClaims(additionalClaims - key) + } + + def +(claim: (String, String)): JwtClaims = + synchronized { + dirty = true + withAdditionalClaims(additionalClaims + claim) + } + + def ++(claims: Seq[(String, String)]): JwtClaims = + synchronized { + dirty = true + withAdditionalClaims(additionalClaims ++ claims) + } + + def apply(key: String): String = additionalClaims(key) + + lazy val id: String = sub.getOrElse(additionalClaims(idKey)) + + def withId(id: String): JwtClaims = { + synchronized { + dirty = true + withAdditionalClaims(additionalClaims + (idKey -> id)).withSub(id) + } + } + + lazy val clientId: String = iss.getOrElse(additionalClaims(clientIdKey)) + + def withClientId(clientId: String): JwtClaims = { + synchronized { + dirty = true + withAdditionalClaims(additionalClaims + (clientIdKey -> clientId)).withIss(clientId) + } + } + + lazy val admin: Boolean = get(adminKey).exists(_.toBoolean) + + def withAdmin(admin: Boolean): JwtClaims = { + synchronized { + dirty = true + withAdditionalClaims(additionalClaims + (adminKey -> admin.toString)) + } + } + + lazy val anonymous: Boolean = get(anonymousKey).exists(_.toBoolean) + + def withAnonymous(anonymous: Boolean): JwtClaims = { + synchronized { + dirty = true + withAdditionalClaims(additionalClaims + (anonymousKey -> anonymous.toString)) + } + } + lazy val profile: Option[String] = get(profileKey) + + def withProfile(profile: Option[String]): JwtClaims = { + synchronized { + dirty = true + withAdditionalClaims(additionalClaims + (profileKey -> profile.getOrElse(""))) + } + } +} diff --git a/core/src/main/scala/app/softnetwork/payment/handlers/SoftPaymentAccountDao.scala b/core/src/main/scala/app/softnetwork/payment/handlers/SoftPaymentAccountDao.scala index fcd4292..d7a397d 100644 --- a/core/src/main/scala/app/softnetwork/payment/handlers/SoftPaymentAccountDao.scala +++ b/core/src/main/scala/app/softnetwork/payment/handlers/SoftPaymentAccountDao.scala @@ -15,12 +15,14 @@ import app.softnetwork.payment.message.AccountMessages import app.softnetwork.payment.model.SoftPaymentAccount import app.softnetwork.payment.persistence.typed.SoftPaymentAccountBehavior import app.softnetwork.persistence.typed.CommandTypeKey +import app.softnetwork.session.handlers.ApiKeyDao +import app.softnetwork.session.model.ApiKey import org.slf4j.{Logger, LoggerFactory} import scala.concurrent.{ExecutionContext, Future} import scala.reflect.ClassTag -trait SoftPaymentAccountDao extends AccountDao { _: AccountHandler => +trait SoftPaymentAccountDao extends AccountDao with ApiKeyDao { _: AccountHandler => @InternalApi private[payment] def loadProvider( clientId: String @@ -88,6 +90,16 @@ trait SoftPaymentAccountDao extends AccountDao { _: AccountHandler => case _ => None } } + + override def loadApiKey( + clientId: String + )(implicit system: ActorSystem[_]): Future[Option[ApiKey]] = { + implicit val ec: ExecutionContext = system.executionContext + ??(clientId, AccountMessages.LoadApiKey(clientId)) map { + case result: AccountMessages.ApiKeyLoaded => Some(result.apiKey) + case _ => None + } + } } trait SoftPaymentAccountTypeKey extends CommandTypeKey[AccountCommand] { diff --git a/core/src/main/scala/app/softnetwork/payment/persistence/typed/SoftPaymentAccountBehavior.scala b/core/src/main/scala/app/softnetwork/payment/persistence/typed/SoftPaymentAccountBehavior.scala index ce6683d..43a8560 100644 --- a/core/src/main/scala/app/softnetwork/payment/persistence/typed/SoftPaymentAccountBehavior.scala +++ b/core/src/main/scala/app/softnetwork/payment/persistence/typed/SoftPaymentAccountBehavior.scala @@ -146,6 +146,25 @@ trait SoftPaymentAccountBehavior extends AccountBehavior[SoftPaymentAccount, Bas } } + case AccountMessages.LoadApiKey(clientId) => + state match { + case Some(account) => + account.apiKeys.find(_.clientId == clientId) match { + case Some(apiKey) => + Effect.none.thenRun { _ => + AccountMessages.ApiKeyLoaded(apiKey) ~> replyTo + } + case _ => + Effect.none.thenRun { _ => + AccountMessages.ApiKeyNotFound ~> replyTo + } + } + case _ => + Effect.none.thenRun { _ => + AccountNotFound ~> replyTo + } + } + case AccountMessages.GenerateClientToken( clientId, clientSecret, diff --git a/core/src/main/scala/app/softnetwork/payment/service/ClientSession.scala b/core/src/main/scala/app/softnetwork/payment/service/ClientSession.scala index 44f6fc7..300c05f 100644 --- a/core/src/main/scala/app/softnetwork/payment/service/ClientSession.scala +++ b/core/src/main/scala/app/softnetwork/payment/service/ClientSession.scala @@ -4,10 +4,12 @@ import app.softnetwork.concurrent.Completion import app.softnetwork.payment.config.PaymentSettings.ClientSessionConfig import app.softnetwork.payment.handlers.SoftPaymentAccountDao import app.softnetwork.payment.model.SoftPaymentAccount +import app.softnetwork.session.model.JwtClaims import app.softnetwork.session.service.SessionMaterials import com.softwaremill.session._ import org.softnetwork.session.model.Session +import scala.concurrent.Future import scala.language.implicitConversions import scala.util.{Failure, Success} @@ -30,17 +32,17 @@ trait ClientSession extends Completion { _: SessionMaterials => def encodeClient( client: SoftPaymentAccount.Client ): String = { - clientSessionManager(client.clientId).clientSessionManager.encode(client) + clientSessionManager(client).clientSessionManager.encode(client) } def decodeClient(data: String): Option[Session] = manager(ClientSessionConfig).clientSessionManager.decode(data).toOption - def clientSessionManager(clientId: String): SessionManager[Session] = { + def clientSessionManager(client: SoftPaymentAccount.Client): SessionManager[Session] = { implicit val innerSessionConfig: SessionConfig = ClientSessionConfig.copy( - jwt = ClientSessionConfig.jwt.copy(subject = Some(clientId)), - sessionEncryptData = true + jwt = ClientSessionConfig.jwt.copy(subject = Some(client.clientId)), + serverSecret = client.getClientApiKey ) manager(innerSessionConfig) } @@ -80,4 +82,25 @@ trait ClientSession extends Completion { _: SessionMaterials => case _ => manager } } + + protected def toClient(token: Option[String]): Future[Option[SoftPaymentAccount.Client]] = { + token match { + case Some(value) => + softPaymentAccountDao.oauthClient(value) flatMap { + case Some(client) => Future.successful(Some(client)) + case _ => + val jwt = JwtClaims(value) + if (jwt.iss.contains(sessionConfig.jwt.issuer.getOrElse("")) && jwt.sub.isDefined) { + softPaymentAccountDao.loadClient(jwt.sub.get) flatMap { + case Some(client) => Future.successful(Some(client)) + case _ => Future.successful(None) + } + } else { + Future.successful(None) + } + } + case _ => Future.successful(None) + } + } + } diff --git a/core/src/main/scala/app/softnetwork/payment/service/ClientSessionDirectives.scala b/core/src/main/scala/app/softnetwork/payment/service/ClientSessionDirectives.scala index ab43157..e031bd5 100644 --- a/core/src/main/scala/app/softnetwork/payment/service/ClientSessionDirectives.scala +++ b/core/src/main/scala/app/softnetwork/payment/service/ClientSessionDirectives.scala @@ -1,7 +1,7 @@ package app.softnetwork.payment.service import akka.http.scaladsl.server.Directives.authenticateOAuth2Async -import akka.http.scaladsl.server.Route +import akka.http.scaladsl.server.{Directive1, Route} import akka.http.scaladsl.server.directives.Credentials import app.softnetwork.account.config.AccountSettings import app.softnetwork.payment.annotation.InternalApi @@ -13,11 +13,15 @@ import scala.concurrent.Future trait ClientSessionDirectives extends SessionService with ClientSession { _: SessionMaterials => + @InternalApi + private[payment] def clientDirective: Directive1[Option[SoftPaymentAccount.Client]] = + authenticateOAuth2Async(AccountSettings.Realm, oauthClient).optional + @InternalApi private[payment] def requiredClientSession( body: (Option[SoftPaymentAccount.Client], Session) => Route ): Route = - authenticateOAuth2Async(AccountSettings.Realm, oauthClient).optional { client => + clientDirective { client => requiredSession(sc(clientSessionManager(client)), gt) { session => body(client, session) } @@ -27,7 +31,7 @@ trait ClientSessionDirectives extends SessionService with ClientSession { _: Ses private[payment] def optionalClientSession( body: (Option[SoftPaymentAccount.Client], Option[Session]) => Route ): Route = - authenticateOAuth2Async(AccountSettings.Realm, oauthClient).optional { client => + clientDirective { client => optionalSession(sc(clientSessionManager(client)), gt) { session => body(client, session) } @@ -35,9 +39,8 @@ trait ClientSessionDirectives extends SessionService with ClientSession { _: Ses @InternalApi private[payment] def oauthClient: Credentials => Future[Option[SoftPaymentAccount.Client]] = { - case _ @Credentials.Provided(token) => - softPaymentAccountDao.oauthClient(token) - case _ => Future.successful(None) + case _ @Credentials.Provided(token) => toClient(Some(token)) + case _ => Future.successful(None) } } diff --git a/core/src/main/scala/app/softnetwork/payment/service/ClientSessionEndpoints.scala b/core/src/main/scala/app/softnetwork/payment/service/ClientSessionEndpoints.scala index 507a577..bac436a 100644 --- a/core/src/main/scala/app/softnetwork/payment/service/ClientSessionEndpoints.scala +++ b/core/src/main/scala/app/softnetwork/payment/service/ClientSessionEndpoints.scala @@ -28,6 +28,11 @@ trait ClientSessionEndpoints extends SessionEndpoints with ClientSession { import TapirSessionOptions._ + protected def clientInput: EndpointInput[Option[String]] = + auth + .bearer[Option[String]](WWWAuthenticateChallenge.bearer(AccountSettings.Realm)) + .description("OAuth2 bearer token") + @InternalApi private[payment] def requiredClientSession: PartialServerEndpointWithSecurityOutput[Seq[ Option[String] @@ -76,18 +81,13 @@ trait ClientSessionEndpoints extends SessionEndpoints with ClientSession { ], Unit, Any, Future] = { val partial = sc.session(gt, required) partial.endpoint - .prependSecurityIn( - auth.bearer[Option[String]](WWWAuthenticateChallenge.bearer(AccountSettings.Realm)) - ) + .prependSecurityIn(clientInput) .mapSecurityIn(inputs => Seq(inputs._1) ++ inputs._2)(seq => (seq.head, seq.slice(1, seq.size)) ) .out(partial.securityOutput) .serverSecurityLogicWithOutput { inputs => - (inputs.head match { - case Some(token) => softPaymentAccountDao.oauthClient(token) - case _ => Future.successful(None) - }) flatMap { client => + toClient(inputs.head) flatMap { client => implicit val manager: SessionManager[Session] = clientSessionManager(client) sessionType match { case Session.SessionType.OneOffCookie | Session.SessionType.OneOffHeader => // oneOff diff --git a/core/src/main/scala/app/softnetwork/payment/service/SoftPaymentAccountService.scala b/core/src/main/scala/app/softnetwork/payment/service/SoftPaymentAccountService.scala index 703fd51..5c724ac 100644 --- a/core/src/main/scala/app/softnetwork/payment/service/SoftPaymentAccountService.scala +++ b/core/src/main/scala/app/softnetwork/payment/service/SoftPaymentAccountService.scala @@ -13,7 +13,7 @@ import org.json4s.Formats trait SoftPaymentAccountService extends BasicAccountService with SoftPaymentAccountTypeKey { _: SessionMaterials => - implicit def sessionConfig: SessionConfig = ClientSessionConfig + final implicit def sessionConfig: SessionConfig = ClientSessionConfig override implicit lazy val formats: Formats = paymentFormats diff --git a/core/src/main/scala/app/softnetwork/payment/service/SoftPaymentOAuthService.scala b/core/src/main/scala/app/softnetwork/payment/service/SoftPaymentOAuthService.scala index 278a161..fe73fbe 100644 --- a/core/src/main/scala/app/softnetwork/payment/service/SoftPaymentOAuthService.scala +++ b/core/src/main/scala/app/softnetwork/payment/service/SoftPaymentOAuthService.scala @@ -26,7 +26,7 @@ trait SoftPaymentOAuthService with ClientSessionDirectives { _: SessionMaterials => - implicit def sessionConfig: SessionConfig = ClientSessionConfig + final implicit def sessionConfig: SessionConfig = ClientSessionConfig override implicit lazy val formats: Formats = paymentFormats @@ -105,7 +105,7 @@ trait SoftPaymentOAuthService .result() ) { authenticateOAuth2Async(AccountSettings.Realm, oauthClient) { client => - setSession(sc(clientSessionManager(client.clientId)), st, client.asInstanceOf[Session]) { + setSession(sc(clientSessionManager(client)), st, client.asInstanceOf[Session]) { complete(StatusCodes.OK) } } diff --git a/core/src/main/scala/app/softnetwork/session/handlers/ApiKeyDao.scala b/core/src/main/scala/app/softnetwork/session/handlers/ApiKeyDao.scala new file mode 100644 index 0000000..8e867f9 --- /dev/null +++ b/core/src/main/scala/app/softnetwork/session/handlers/ApiKeyDao.scala @@ -0,0 +1,12 @@ +package app.softnetwork.session.handlers + +import akka.actor.typed.ActorSystem +import app.softnetwork.session.model.ApiKey + +import scala.concurrent.Future + +trait ApiKeyDao { + + def loadApiKey(clientId: String)(implicit system: ActorSystem[_]): Future[Option[ApiKey]] + +} diff --git a/core/src/main/scala/app/softnetwork/session/handlers/JwtClaimsRefreshTokenHandler.scala b/core/src/main/scala/app/softnetwork/session/handlers/JwtClaimsRefreshTokenHandler.scala new file mode 100644 index 0000000..9169361 --- /dev/null +++ b/core/src/main/scala/app/softnetwork/session/handlers/JwtClaimsRefreshTokenHandler.scala @@ -0,0 +1,33 @@ +package app.softnetwork.session.handlers + +import akka.actor.typed.ActorSystem +import akka.cluster.sharding.typed.scaladsl.EntityTypeKey +import app.softnetwork.persistence.typed.CommandTypeKey +import app.softnetwork.session.message.RefreshTokenCommand +import app.softnetwork.session.model.JwtClaims +import app.softnetwork.session.persistence.typed.JwtClaimsRefreshTokenBehavior +import org.slf4j.{Logger, LoggerFactory} + +import scala.reflect.ClassTag + +trait JwtClaimsRefreshTokenTypeKey extends CommandTypeKey[RefreshTokenCommand] { + override def TypeKey(implicit + tTag: ClassTag[RefreshTokenCommand] + ): EntityTypeKey[RefreshTokenCommand] = + JwtClaimsRefreshTokenBehavior.TypeKey +} +trait JwtClaimsRefreshTokenHandler + extends RefreshTokenHandler[JwtClaims] + with JwtClaimsRefreshTokenTypeKey + +trait JwtClaimsRefreshTokenDao extends RefreshTokenDao[JwtClaims] with JwtClaimsRefreshTokenHandler + +object JwtClaimsRefreshTokenDao { + def apply(asystem: ActorSystem[_]): JwtClaimsRefreshTokenDao = { + new JwtClaimsRefreshTokenDao() { + override implicit val system: ActorSystem[_] = asystem + + override lazy val log: Logger = LoggerFactory getLogger getClass.getName + } + } +} diff --git a/core/src/main/scala/app/softnetwork/session/persistence/typed/JwtClaimsRefreshTokenBehavior.scala b/core/src/main/scala/app/softnetwork/session/persistence/typed/JwtClaimsRefreshTokenBehavior.scala new file mode 100644 index 0000000..414597f --- /dev/null +++ b/core/src/main/scala/app/softnetwork/session/persistence/typed/JwtClaimsRefreshTokenBehavior.scala @@ -0,0 +1,9 @@ +package app.softnetwork.session.persistence.typed + +import app.softnetwork.session.model.JwtClaims + +trait JwtClaimsRefreshTokenBehavior extends RefreshTokenBehavior[JwtClaims] { + override val persistenceId = "JwtClaims" +} + +object JwtClaimsRefreshTokenBehavior extends JwtClaimsRefreshTokenBehavior diff --git a/core/src/main/scala/app/softnetwork/session/service/JwtClaimsDirectives.scala b/core/src/main/scala/app/softnetwork/session/service/JwtClaimsDirectives.scala new file mode 100644 index 0000000..f7db1a4 --- /dev/null +++ b/core/src/main/scala/app/softnetwork/session/service/JwtClaimsDirectives.scala @@ -0,0 +1,40 @@ +package app.softnetwork.session.service + +import app.softnetwork.session.model.JwtClaims +import com.softwaremill.session.{ + CsrfCheckMode, + CsrfOptions, + GetSessionTransport, + SessionContinuity, + SessionDirectives, + SessionManager, + SetSessionTransport +} +import org.softnetwork.session.model.Session + +trait JwtClaimsDirectives extends SessionDirectives { _: JwtClaimsMaterials => + + import com.softwaremill.session.SessionOptions._ + + def sc(implicit manager: SessionManager[JwtClaims]): SessionContinuity[JwtClaims] = + sessionType match { + case Session.SessionType.OneOffCookie | Session.SessionType.OneOffHeader => oneOff + case _ => refreshable + } + + lazy val st: SetSessionTransport = + sessionType match { + case Session.SessionType.OneOffCookie | Session.SessionType.RefreshableCookie => usingCookies + case _ => usingHeaders + } + + lazy val gt: GetSessionTransport = st + + def checkMode(implicit manager: SessionManager[JwtClaims]): CsrfCheckMode[JwtClaims] = + if (headerAndForm) { + CsrfOptions.checkHeaderAndForm + } else { + CsrfOptions.checkHeader + } + +} diff --git a/core/src/main/scala/app/softnetwork/session/service/JwtClaimsEncoder.scala b/core/src/main/scala/app/softnetwork/session/service/JwtClaimsEncoder.scala new file mode 100644 index 0000000..5c72c05 --- /dev/null +++ b/core/src/main/scala/app/softnetwork/session/service/JwtClaimsEncoder.scala @@ -0,0 +1,65 @@ +package app.softnetwork.session.service + +import akka.actor.typed.ActorSystem +import app.softnetwork.concurrent.Completion +import app.softnetwork.session.handlers.ApiKeyDao +import app.softnetwork.session.model.JwtClaims +import com.softwaremill.session._ +import org.json4s.{DefaultFormats, Formats, JValue} + +import scala.util.Try + +trait JwtClaimsEncoder extends SessionEncoder[JwtClaims] with Completion { + + implicit def system: ActorSystem[_] + + implicit def formats: Formats = DefaultFormats + + implicit def sessionSerializer: SessionSerializer[JwtClaims, JValue] = JwtClaimsSerializer + + def apiKeyDao: ApiKeyDao + + def sessionEncoder = new JwtSessionEncoder[JwtClaims] + + override def encode(t: JwtClaims, nowMillis: Long, config: SessionConfig): String = { + val jwt = config.jwt.copy( + issuer = t.iss.orElse(config.jwt.issuer), + subject = t.sub.orElse(config.jwt.subject), + audience = t.aud.orElse(config.jwt.audience) + ) + (t.iss match { + case Some(iss) => + (apiKeyDao.loadApiKey(iss) complete ()).toOption.flatten + case _ => None + }) match { + case Some(apiKey) if apiKey.clientSecret.isDefined => + sessionEncoder.encode( + t, + nowMillis, + config.copy(jwt = jwt, serverSecret = apiKey.clientSecret.get) + ) + case _ => sessionEncoder.encode(t, nowMillis, config.copy(jwt = jwt)) + } + } + + override def decode(s: String, config: SessionConfig): Try[DecodeResult[JwtClaims]] = { + val jwtClaims = JwtClaims(s) + val maybeClientId = + if (jwtClaims.iss.contains(config.jwt.issuer.getOrElse(""))) jwtClaims.sub + else jwtClaims.iss + val innerConfig = (maybeClientId match { + case Some(clientId) => + (apiKeyDao.loadApiKey(clientId) complete ()).toOption.flatten.flatMap(_.clientSecret) + case _ => None + }) match { + case Some(clientSecret) => + config.copy(serverSecret = clientSecret) + case _ => + config + } + sessionEncoder + .decode(s, innerConfig) + .map(result => result.copy(t = jwtClaims.copy(additionalClaims = result.t.additionalClaims))) + + } +} diff --git a/core/src/main/scala/app/softnetwork/session/service/JwtClaimsEndpoints.scala b/core/src/main/scala/app/softnetwork/session/service/JwtClaimsEndpoints.scala new file mode 100644 index 0000000..388c5ce --- /dev/null +++ b/core/src/main/scala/app/softnetwork/session/service/JwtClaimsEndpoints.scala @@ -0,0 +1,39 @@ +package app.softnetwork.session.service + +import app.softnetwork.session.model.JwtClaims +import app.softnetwork.session.{ + TapirCsrfCheckMode, + TapirCsrfOptions, + TapirEndpoints, + TapirSessionContinuity +} +import com.softwaremill.session.{GetSessionTransport, SessionManager, SetSessionTransport} +import org.softnetwork.session.model.Session + +trait JwtClaimsEndpoints extends TapirEndpoints { + _: JwtClaimsMaterials => + + import app.softnetwork.session.TapirSessionOptions._ + + def sc(implicit manager: SessionManager[JwtClaims]): TapirSessionContinuity[JwtClaims] = + sessionType match { + case Session.SessionType.OneOffCookie | Session.SessionType.OneOffHeader => oneOff + case _ => refreshable + } + + lazy val st: SetSessionTransport = + sessionType match { + case Session.SessionType.OneOffCookie | Session.SessionType.RefreshableCookie => usingCookies + case _ => usingHeaders + } + + lazy val gt: GetSessionTransport = st + + def checkMode(implicit manager: SessionManager[JwtClaims]): TapirCsrfCheckMode[JwtClaims] = + if (headerAndForm) { + TapirCsrfOptions.checkHeaderAndForm + } else { + TapirCsrfOptions.checkHeader + } + +} diff --git a/core/src/main/scala/app/softnetwork/session/service/JwtClaimsManager.scala b/core/src/main/scala/app/softnetwork/session/service/JwtClaimsManager.scala new file mode 100644 index 0000000..9a5b1ca --- /dev/null +++ b/core/src/main/scala/app/softnetwork/session/service/JwtClaimsManager.scala @@ -0,0 +1,20 @@ +package app.softnetwork.session.service + +import akka.actor.typed.ActorSystem +import app.softnetwork.session.handlers.ApiKeyDao +import app.softnetwork.session.model.JwtClaims +import com.softwaremill.session.{SessionConfig, SessionEncoder, SessionManager} + +import scala.language.reflectiveCalls + +trait JwtClaimsManager extends JwtClaimsMaterials { self: { def apiKeyDao: ApiKeyDao } => + + override def manager(implicit sessionConfig: SessionConfig): SessionManager[JwtClaims] = { + implicit val encoder: SessionEncoder[JwtClaims] = new JwtClaimsEncoder { + override implicit def system: ActorSystem[_] = self.ts + override def apiKeyDao: ApiKeyDao = self.apiKeyDao + } + new SessionManager[JwtClaims](sessionConfig) + } + +} diff --git a/core/src/main/scala/app/softnetwork/session/service/JwtClaimsMaterials.scala b/core/src/main/scala/app/softnetwork/session/service/JwtClaimsMaterials.scala new file mode 100644 index 0000000..97d57b1 --- /dev/null +++ b/core/src/main/scala/app/softnetwork/session/service/JwtClaimsMaterials.scala @@ -0,0 +1,24 @@ +package app.softnetwork.session.service + +import akka.actor.typed.ActorSystem +import app.softnetwork.session.handlers.JwtClaimsRefreshTokenDao +import app.softnetwork.session.model.JwtClaims +import com.softwaremill.session.{RefreshTokenStorage, SessionConfig, SessionManager} +import org.softnetwork.session.model.Session + +import scala.concurrent.ExecutionContext + +trait JwtClaimsMaterials { + + implicit def manager(implicit sessionConfig: SessionConfig): SessionManager[JwtClaims] + + implicit def ts: ActorSystem[_] + + implicit def ec: ExecutionContext = ts.executionContext + + implicit def refreshTokenStorage: RefreshTokenStorage[JwtClaims] = JwtClaimsRefreshTokenDao(ts) + + protected def sessionType: Session.SessionType + + def headerAndForm: Boolean = false +} diff --git a/core/src/main/scala/app/softnetwork/session/service/JwtClaimsSerializer.scala b/core/src/main/scala/app/softnetwork/session/service/JwtClaimsSerializer.scala new file mode 100644 index 0000000..e238e2c --- /dev/null +++ b/core/src/main/scala/app/softnetwork/session/service/JwtClaimsSerializer.scala @@ -0,0 +1,21 @@ +package app.softnetwork.session.service + +import app.softnetwork.session.model.JwtClaims +import com.softwaremill.session.SessionSerializer +import org.json4s.jackson.JsonMethods.asJValue +import org.json4s.{DefaultFormats, DefaultWriters, Formats, JValue} + +import scala.util.Try + +case object JwtClaimsSerializer extends SessionSerializer[JwtClaims, JValue] { + + implicit val formats: Formats = DefaultFormats + + import DefaultWriters._ + + override def serialize(t: JwtClaims): JValue = asJValue(t.additionalClaims) + + override def deserialize(r: JValue): Try[JwtClaims] = Try { + JwtClaims(additionalClaims = r.extract[Map[String, String]]) + } +} diff --git a/core/src/main/scala/app/softnetwork/session/service/ServiceWithJwtClaimsDirectives.scala b/core/src/main/scala/app/softnetwork/session/service/ServiceWithJwtClaimsDirectives.scala new file mode 100644 index 0000000..b9446ae --- /dev/null +++ b/core/src/main/scala/app/softnetwork/session/service/ServiceWithJwtClaimsDirectives.scala @@ -0,0 +1,11 @@ +package app.softnetwork.session.service + +import app.softnetwork.api.server.ApiRoute +import app.softnetwork.persistence.message.{Command, CommandResult} +import app.softnetwork.persistence.service.Service +import app.softnetwork.persistence.typed.scaladsl.Patterns + +trait ServiceWithJwtClaimsDirectives[C <: Command, R <: CommandResult] + extends Service[C, R] + with ApiRoute + with JwtClaimsDirectives { _: Patterns[C, R] with JwtClaimsMaterials => } diff --git a/core/src/main/scala/app/softnetwork/session/service/ServiceWithJwtClaimsEndpoints.scala b/core/src/main/scala/app/softnetwork/session/service/ServiceWithJwtClaimsEndpoints.scala new file mode 100644 index 0000000..511e610 --- /dev/null +++ b/core/src/main/scala/app/softnetwork/session/service/ServiceWithJwtClaimsEndpoints.scala @@ -0,0 +1,9 @@ +package app.softnetwork.session.service + +import app.softnetwork.api.server.ServiceEndpoints +import app.softnetwork.persistence.message.{Command, CommandResult} +import app.softnetwork.persistence.typed.scaladsl.Patterns + +trait ServiceWithJwtClaimsEndpoints[C <: Command, R <: CommandResult] + extends ServiceEndpoints[C, R] + with JwtClaimsEndpoints { _: Patterns[C, R] with JwtClaimsMaterials => } diff --git a/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayRoutes.scala b/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayRoutes.scala index aecc279..ff8d9d7 100644 --- a/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayRoutes.scala +++ b/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayRoutes.scala @@ -49,7 +49,6 @@ trait MangoPayRoutes extends PaymentRoutes { self: MangoPayApi with SchemaProvid ): SessionManager[Session] = self.manager override protected def sessionType: Session.SessionType = self.sessionType override def log: Logger = LoggerFactory getLogger getClass.getName -// override implicit def sessionConfig: SessionConfig = self.sessionConfig override implicit def system: ActorSystem[_] = sys override lazy val ec: ExecutionContext = sys.executionContext override protected val manifestWrapper: ManifestW = ManifestW() @@ -62,7 +61,6 @@ trait MangoPayRoutes extends PaymentRoutes { self: MangoPayApi with SchemaProvid ): SessionManager[Session] = self.manager override protected def sessionType: Session.SessionType = self.sessionType override def log: Logger = LoggerFactory getLogger getClass.getName -// override implicit def sessionConfig: SessionConfig = self.sessionConfig override implicit def system: ActorSystem[_] = sys override lazy val ec: ExecutionContext = sys.executionContext } diff --git a/testkit/src/main/scala/app/softnetwork/payment/spi/MockMangoPayProvider.scala b/testkit/src/main/scala/app/softnetwork/payment/spi/MockMangoPayProvider.scala index 5b07e4c..2223d30 100644 --- a/testkit/src/main/scala/app/softnetwork/payment/spi/MockMangoPayProvider.scala +++ b/testkit/src/main/scala/app/softnetwork/payment/spi/MockMangoPayProvider.scala @@ -1242,7 +1242,7 @@ trait MockMangoPayProvider extends MangoPayProvider { Some( SoftPaymentAccount.Client.defaultInstance .withProvider(provider) - .withClientId(s"${generateUUID()}.${provider.providerType.name.toLowerCase}") + .withClientId(provider.clientId) ) /** @return From 41b0b4e6246c235e4f4f9f02427bca8f4c34e07b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Manciot?= Date: Sun, 3 Dec 2023 15:22:44 +0100 Subject: [PATCH 06/37] upgrade to typed session materials --- common/src/main/protobuf/model/jwt.proto | 36 --------- .../payment/message/AccountMessages.scala | 2 +- .../model/SoftPaymentAccountDecorator.scala | 2 +- .../session/model/JwtClaimsCompanion.scala | 81 ------------------- .../session/model/JwtClaimsDecorator.scala | 80 ------------------ .../handlers/SoftPaymentAccountDao.scala | 7 +- .../payment/launch/PaymentEndpoints.scala | 8 +- .../payment/launch/PaymentRoutes.scala | 6 +- .../payment/service/BasicPaymentService.scala | 4 +- .../service/CardPaymentEndpoints.scala | 4 +- .../payment/service/ClientSession.scala | 33 ++++---- .../service/ClientSessionDirectives.scala | 9 ++- .../service/ClientSessionEndpoints.scala | 16 ++-- .../service/GenericPaymentEndpoints.scala | 3 +- .../service/GenericPaymentService.scala | 5 +- .../service/RootPaymentEndpoints.scala | 10 +-- .../service/SoftPaymentAccountService.scala | 7 +- .../SoftPaymentAccountServiceEndpoints.scala | 7 +- .../service/SoftPaymentOAuthService.scala | 8 +- .../SoftPaymentOAuthServiceEndpoints.scala | 7 +- .../session/handlers/ApiKeyDao.scala | 12 --- .../JwtClaimsRefreshTokenHandler.scala | 33 -------- .../typed/JwtClaimsRefreshTokenBehavior.scala | 9 --- .../session/service/JwtClaimsDirectives.scala | 40 --------- .../session/service/JwtClaimsEncoder.scala | 65 --------------- .../session/service/JwtClaimsEndpoints.scala | 39 --------- .../session/service/JwtClaimsManager.scala | 20 ----- .../session/service/JwtClaimsMaterials.scala | 24 ------ .../session/service/JwtClaimsSerializer.scala | 21 ----- .../ServiceWithJwtClaimsDirectives.scala | 11 --- .../ServiceWithJwtClaimsEndpoints.scala | 9 --- .../service/MangoPayPaymentEndpoints.scala | 3 +- .../service/MangoPayPaymentService.scala | 3 +- project/Versions.scala | 8 +- .../scalatest/PaymentEndpointsTestKit.scala | 52 +++++++----- .../scalatest/PaymentRouteTestKit.scala | 8 +- .../scalatest/PaymentRoutesTestKit.scala | 47 +++++++---- .../payment/scalatest/PaymentTestKit.scala | 21 ++--- .../service/MockPaymentEndpoints.scala | 3 +- .../payment/service/MockPaymentService.scala | 3 +- .../MockSoftPaymentAccountService.scala | 3 +- ...ckSoftPaymentAccountServiceEndpoints.scala | 3 +- .../service/MockSoftPaymentOAuthService.scala | 3 +- ...MockSoftPaymentOAuthServiceEndpoints.scala | 3 +- .../payment/handlers/PaymentHandlerSpec.scala | 6 +- ...EndpointsWithOneOffCookieSessionSpec.scala | 5 +- ...EndpointsWithOneOffHeaderSessionSpec.scala | 5 +- ...intsWithRefreshableCookieSessionSpec.scala | 5 +- ...intsWithRefreshableHeaderSessionSpec.scala | 5 +- ...entRoutesWithOneOffCookieSessionSpec.scala | 5 +- ...entRoutesWithOneOffHeaderSessionSpec.scala | 5 +- ...utesWithRefreshableCookieSessionSpec.scala | 5 +- ...utesWithRefreshableHeaderSessionSpec.scala | 5 +- .../payment/service/PaymentServiceSpec.scala | 11 ++- 54 files changed, 212 insertions(+), 623 deletions(-) delete mode 100644 common/src/main/protobuf/model/jwt.proto delete mode 100644 common/src/main/scala/app/softnetwork/session/model/JwtClaimsCompanion.scala delete mode 100644 common/src/main/scala/app/softnetwork/session/model/JwtClaimsDecorator.scala delete mode 100644 core/src/main/scala/app/softnetwork/session/handlers/ApiKeyDao.scala delete mode 100644 core/src/main/scala/app/softnetwork/session/handlers/JwtClaimsRefreshTokenHandler.scala delete mode 100644 core/src/main/scala/app/softnetwork/session/persistence/typed/JwtClaimsRefreshTokenBehavior.scala delete mode 100644 core/src/main/scala/app/softnetwork/session/service/JwtClaimsDirectives.scala delete mode 100644 core/src/main/scala/app/softnetwork/session/service/JwtClaimsEncoder.scala delete mode 100644 core/src/main/scala/app/softnetwork/session/service/JwtClaimsEndpoints.scala delete mode 100644 core/src/main/scala/app/softnetwork/session/service/JwtClaimsManager.scala delete mode 100644 core/src/main/scala/app/softnetwork/session/service/JwtClaimsMaterials.scala delete mode 100644 core/src/main/scala/app/softnetwork/session/service/JwtClaimsSerializer.scala delete mode 100644 core/src/main/scala/app/softnetwork/session/service/ServiceWithJwtClaimsDirectives.scala delete mode 100644 core/src/main/scala/app/softnetwork/session/service/ServiceWithJwtClaimsEndpoints.scala diff --git a/common/src/main/protobuf/model/jwt.proto b/common/src/main/protobuf/model/jwt.proto deleted file mode 100644 index cce4e02..0000000 --- a/common/src/main/protobuf/model/jwt.proto +++ /dev/null @@ -1,36 +0,0 @@ -syntax = "proto3"; - -import "scalapb/scalapb.proto"; -import "google/protobuf/wrappers.proto"; - -package app.softnetwork.session.model; - -option (scalapb.options) = { - single_file: true - flat_package: true - import: "app.softnetwork.persistence.model._" - import: "app.softnetwork.serialization._" - import: "app.softnetwork.session.model._" - preserve_unknown_fields: false -}; - -message JwtClaims { - option (scalapb.message).extends = "SessionData"; - option (scalapb.message).extends = "JwtClaimsDecorator"; - option (scalapb.message).companion_extends = "JwtClaimsCompanion"; - map data = 1 [(scalapb.field).map_type="collection.immutable.Map", (scalapb.field).scala_name = "additionalClaims"]; - bool refreshable = 2; - google.protobuf.StringValue iss = 3; - google.protobuf.StringValue sub = 4; - google.protobuf.StringValue aud = 5; - google.protobuf.Int64Value exp = 6; - google.protobuf.Int64Value nbf = 7; - google.protobuf.Int64Value iat = 8; - google.protobuf.StringValue jti = 9; -} - -message ApiKey { - option (scalapb.message).extends = "ProtobufDomainObject"; - string clientId = 1; - google.protobuf.StringValue clientSecret = 2; -} diff --git a/common/src/main/scala/app/softnetwork/payment/message/AccountMessages.scala b/common/src/main/scala/app/softnetwork/payment/message/AccountMessages.scala index 4ef244f..19859ed 100644 --- a/common/src/main/scala/app/softnetwork/payment/message/AccountMessages.scala +++ b/common/src/main/scala/app/softnetwork/payment/message/AccountMessages.scala @@ -10,7 +10,7 @@ import app.softnetwork.account.message.{ import app.softnetwork.account.model.BasicAccountProfile import app.softnetwork.payment.annotation.InternalApi import app.softnetwork.payment.model.SoftPaymentAccount -import app.softnetwork.session.model.ApiKey +import org.softnetwork.session.model.ApiKey object AccountMessages { case class SoftPaymentSignup( diff --git a/common/src/main/scala/app/softnetwork/payment/model/SoftPaymentAccountDecorator.scala b/common/src/main/scala/app/softnetwork/payment/model/SoftPaymentAccountDecorator.scala index 6215789..cc4d006 100644 --- a/common/src/main/scala/app/softnetwork/payment/model/SoftPaymentAccountDecorator.scala +++ b/common/src/main/scala/app/softnetwork/payment/model/SoftPaymentAccountDecorator.scala @@ -1,7 +1,7 @@ package app.softnetwork.payment.model import app.softnetwork.account.model.{BasicAccountProfile, Profile} -import app.softnetwork.session.model.ApiKey +import org.softnetwork.session.model.ApiKey trait SoftPaymentAccountDecorator { _: SoftPaymentAccount => diff --git a/common/src/main/scala/app/softnetwork/session/model/JwtClaimsCompanion.scala b/common/src/main/scala/app/softnetwork/session/model/JwtClaimsCompanion.scala deleted file mode 100644 index e2d5e85..0000000 --- a/common/src/main/scala/app/softnetwork/session/model/JwtClaimsCompanion.scala +++ /dev/null @@ -1,81 +0,0 @@ -package app.softnetwork.session.model - -import app.softnetwork.persistence.generateUUID -import app.softnetwork.session.config.Settings.Session._ -import org.json4s._ -import org.json4s.jackson.JsonMethods._ - -import java.util.Base64 -import scala.util.Try - -trait JwtClaimsCompanion { - val adminKey = "admin" - - val profileKey = "profile" - - val anonymousKey = "anonymous" - - val idKey: String = DefaultSessionConfig.sessionCookieConfig.name - - val clientIdKey: String = "client_id" - - val refreshable: Boolean = Continuity match { - case "refreshable" => true - case _ => false - } - - def apply(): JwtClaims = - JwtClaims.defaultInstance - .withAdditionalClaims(Map(idKey -> generateUUID())) - .withRefreshable(refreshable) - - def apply(s: String): JwtClaims = - Try { - val sCleaned = if (s.startsWith("Bearer")) s.substring(7).trim else s - val List(_, p, _) = sCleaned.split("\\.").toList - val decodedValue = Try { - parse(new String(Base64.getUrlDecoder.decode(p), "utf-8")) - } - for (jv <- decodedValue) yield { - val iss = jv \\ "iss" match { - case JString(value) => Some(value) - case _ => None - } - val sub = jv \\ "sub" match { - case JString(value) => Some(value) - case _ => None - } - val aud = jv \\ "aud" match { - case JString(value) => Some(value) - case _ => None - } - val exp = jv \\ "exp" match { - case JInt(value) => Some(value.toLong) - case _ => None - } - val nbf = jv \\ "nbf" match { - case JInt(value) => Some(value.toLong) - case _ => None - } - val iat = jv \\ "iat" match { - case JInt(value) => Some(value.toLong) - case _ => None - } - val jti = jv \\ "jti" match { - case JString(value) => Some(value) - case _ => None - } - JwtClaims( - Map.empty, - refreshable, - iss, - sub, - aud, - exp, - nbf, - iat, - jti - ).withId(sub.getOrElse(generateUUID())) - } - }.flatten.toOption.getOrElse(JwtClaims()) -} diff --git a/common/src/main/scala/app/softnetwork/session/model/JwtClaimsDecorator.scala b/common/src/main/scala/app/softnetwork/session/model/JwtClaimsDecorator.scala deleted file mode 100644 index 650a872..0000000 --- a/common/src/main/scala/app/softnetwork/session/model/JwtClaimsDecorator.scala +++ /dev/null @@ -1,80 +0,0 @@ -package app.softnetwork.session.model - -trait JwtClaimsDecorator { self: JwtClaims => - - import JwtClaims._ - - private var dirty: Boolean = false - - def isDirty: Boolean = dirty - - def get(key: String): Option[String] = additionalClaims.get(key) - - def isEmpty: Boolean = additionalClaims.isEmpty - - def contains(key: String): Boolean = additionalClaims.contains(key) - - def -(key: String): JwtClaims = - synchronized { - dirty = true - withAdditionalClaims(additionalClaims - key) - } - - def +(claim: (String, String)): JwtClaims = - synchronized { - dirty = true - withAdditionalClaims(additionalClaims + claim) - } - - def ++(claims: Seq[(String, String)]): JwtClaims = - synchronized { - dirty = true - withAdditionalClaims(additionalClaims ++ claims) - } - - def apply(key: String): String = additionalClaims(key) - - lazy val id: String = sub.getOrElse(additionalClaims(idKey)) - - def withId(id: String): JwtClaims = { - synchronized { - dirty = true - withAdditionalClaims(additionalClaims + (idKey -> id)).withSub(id) - } - } - - lazy val clientId: String = iss.getOrElse(additionalClaims(clientIdKey)) - - def withClientId(clientId: String): JwtClaims = { - synchronized { - dirty = true - withAdditionalClaims(additionalClaims + (clientIdKey -> clientId)).withIss(clientId) - } - } - - lazy val admin: Boolean = get(adminKey).exists(_.toBoolean) - - def withAdmin(admin: Boolean): JwtClaims = { - synchronized { - dirty = true - withAdditionalClaims(additionalClaims + (adminKey -> admin.toString)) - } - } - - lazy val anonymous: Boolean = get(anonymousKey).exists(_.toBoolean) - - def withAnonymous(anonymous: Boolean): JwtClaims = { - synchronized { - dirty = true - withAdditionalClaims(additionalClaims + (anonymousKey -> anonymous.toString)) - } - } - lazy val profile: Option[String] = get(profileKey) - - def withProfile(profile: Option[String]): JwtClaims = { - synchronized { - dirty = true - withAdditionalClaims(additionalClaims + (profileKey -> profile.getOrElse(""))) - } - } -} diff --git a/core/src/main/scala/app/softnetwork/payment/handlers/SoftPaymentAccountDao.scala b/core/src/main/scala/app/softnetwork/payment/handlers/SoftPaymentAccountDao.scala index d7a397d..174bc69 100644 --- a/core/src/main/scala/app/softnetwork/payment/handlers/SoftPaymentAccountDao.scala +++ b/core/src/main/scala/app/softnetwork/payment/handlers/SoftPaymentAccountDao.scala @@ -15,14 +15,13 @@ import app.softnetwork.payment.message.AccountMessages import app.softnetwork.payment.model.SoftPaymentAccount import app.softnetwork.payment.persistence.typed.SoftPaymentAccountBehavior import app.softnetwork.persistence.typed.CommandTypeKey -import app.softnetwork.session.handlers.ApiKeyDao -import app.softnetwork.session.model.ApiKey +import org.softnetwork.session.model.ApiKey import org.slf4j.{Logger, LoggerFactory} import scala.concurrent.{ExecutionContext, Future} import scala.reflect.ClassTag -trait SoftPaymentAccountDao extends AccountDao with ApiKeyDao { _: AccountHandler => +trait SoftPaymentAccountDao extends AccountDao { _: AccountHandler => @InternalApi private[payment] def loadProvider( clientId: String @@ -91,7 +90,7 @@ trait SoftPaymentAccountDao extends AccountDao with ApiKeyDao { _: AccountHandle } } - override def loadApiKey( + def loadApiKey( clientId: String )(implicit system: ActorSystem[_]): Future[Option[ApiKey]] = { implicit val ec: ExecutionContext = system.executionContext diff --git a/core/src/main/scala/app/softnetwork/payment/launch/PaymentEndpoints.scala b/core/src/main/scala/app/softnetwork/payment/launch/PaymentEndpoints.scala index efdcb37..4eb7da0 100644 --- a/core/src/main/scala/app/softnetwork/payment/launch/PaymentEndpoints.scala +++ b/core/src/main/scala/app/softnetwork/payment/launch/PaymentEndpoints.scala @@ -11,9 +11,15 @@ import app.softnetwork.payment.service.GenericPaymentEndpoints import app.softnetwork.persistence.schema.SchemaProvider import app.softnetwork.session.CsrfCheck import org.json4s.Formats +import org.softnetwork.session.model.JwtClaims trait PaymentEndpoints - extends AccountEndpoints[SoftPaymentAccount, BasicAccountProfile, BasicAccountSignUp] { + extends AccountEndpoints[ + SoftPaymentAccount, + BasicAccountProfile, + BasicAccountSignUp, + JwtClaims + ] { _: PaymentGuardian with SchemaProvider with CsrfCheck => override implicit def formats: Formats = paymentFormats diff --git a/core/src/main/scala/app/softnetwork/payment/launch/PaymentRoutes.scala b/core/src/main/scala/app/softnetwork/payment/launch/PaymentRoutes.scala index 8924e19..f00aa62 100644 --- a/core/src/main/scala/app/softnetwork/payment/launch/PaymentRoutes.scala +++ b/core/src/main/scala/app/softnetwork/payment/launch/PaymentRoutes.scala @@ -8,13 +8,14 @@ import app.softnetwork.account.model.{ DefaultAccountView, DefaultProfileView } -import app.softnetwork.api.server.{ApiRoute, ApiRoutes} +import app.softnetwork.api.server.ApiRoute import app.softnetwork.payment.model.SoftPaymentAccount import app.softnetwork.payment.serialization.paymentFormats import app.softnetwork.payment.service.GenericPaymentService import app.softnetwork.persistence.schema.SchemaProvider import app.softnetwork.session.CsrfCheck import org.json4s.Formats +import org.softnetwork.session.model.JwtClaims trait PaymentRoutes extends AccountRoutes[ @@ -22,7 +23,8 @@ trait PaymentRoutes BasicAccountProfile, DefaultProfileView, DefaultAccountDetailsView, - DefaultAccountView[DefaultProfileView, DefaultAccountDetailsView] + DefaultAccountView[DefaultProfileView, DefaultAccountDetailsView], + JwtClaims ] { _: PaymentGuardian with SchemaProvider with CsrfCheck => override implicit def formats: Formats = paymentFormats diff --git a/core/src/main/scala/app/softnetwork/payment/service/BasicPaymentService.scala b/core/src/main/scala/app/softnetwork/payment/service/BasicPaymentService.scala index 6d9a7e3..5fb17c3 100644 --- a/core/src/main/scala/app/softnetwork/payment/service/BasicPaymentService.scala +++ b/core/src/main/scala/app/softnetwork/payment/service/BasicPaymentService.scala @@ -5,7 +5,7 @@ import app.softnetwork.payment.handlers.GenericPaymentHandler import app.softnetwork.payment.message.PaymentMessages._ import app.softnetwork.payment.model.{computeExternalUuidWithProfile, BrowserInfo} import app.softnetwork.persistence.service.Service -import org.softnetwork.session.model.Session +import org.softnetwork.session.model.JwtClaims import java.util.TimeZone import scala.concurrent.Future @@ -37,7 +37,7 @@ trait BasicPaymentService extends Service[PaymentCommand, PaymentResult] { case _ => ApiErrors.BadRequest("Unknown") } - protected[payment] def externalUuidWithProfile(session: Session): String = + protected[payment] def externalUuidWithProfile(session: JwtClaims): String = computeExternalUuidWithProfile(session.id, session.profile) protected[payment] def extractBrowserInfo( diff --git a/core/src/main/scala/app/softnetwork/payment/service/CardPaymentEndpoints.scala b/core/src/main/scala/app/softnetwork/payment/service/CardPaymentEndpoints.scala index 6b72b40..67b93ed 100644 --- a/core/src/main/scala/app/softnetwork/payment/service/CardPaymentEndpoints.scala +++ b/core/src/main/scala/app/softnetwork/payment/service/CardPaymentEndpoints.scala @@ -4,7 +4,7 @@ import app.softnetwork.payment.config.PaymentSettings import app.softnetwork.payment.handlers.GenericPaymentHandler import app.softnetwork.payment.message.PaymentMessages._ import app.softnetwork.payment.model.SoftPaymentAccount -import org.softnetwork.session.model.Session +import org.softnetwork.session.model.JwtClaims import sttp.capabilities import sttp.capabilities.akka.AkkaStreams import sttp.model.{HeaderNames, Method, StatusCode} @@ -20,7 +20,7 @@ trait CardPaymentEndpoints { _: RootPaymentEndpoints with GenericPaymentHandler def payment(payment: Payment): PartialServerEndpointWithSecurityOutput[ (Seq[Option[String]], Option[String], Method, Option[String]), - (Option[SoftPaymentAccount.Client], Session), + (Option[SoftPaymentAccount.Client], JwtClaims), (Option[String], Option[String], Option[String], Option[String], Payment), Any, (Seq[Option[String]], Option[CookieValueWithMeta]), diff --git a/core/src/main/scala/app/softnetwork/payment/service/ClientSession.scala b/core/src/main/scala/app/softnetwork/payment/service/ClientSession.scala index 300c05f..bbd89d7 100644 --- a/core/src/main/scala/app/softnetwork/payment/service/ClientSession.scala +++ b/core/src/main/scala/app/softnetwork/payment/service/ClientSession.scala @@ -4,27 +4,28 @@ import app.softnetwork.concurrent.Completion import app.softnetwork.payment.config.PaymentSettings.ClientSessionConfig import app.softnetwork.payment.handlers.SoftPaymentAccountDao import app.softnetwork.payment.model.SoftPaymentAccount -import app.softnetwork.session.model.JwtClaims import app.softnetwork.session.service.SessionMaterials +import org.softnetwork.session.model.JwtClaims import com.softwaremill.session._ -import org.softnetwork.session.model.Session import scala.concurrent.Future import scala.language.implicitConversions import scala.util.{Failure, Success} -trait ClientSession extends Completion { _: SessionMaterials => +trait ClientSession extends Completion { self: SessionMaterials[JwtClaims] => def softPaymentAccountDao: SoftPaymentAccountDao = SoftPaymentAccountDao implicit def sessionConfig: SessionConfig - implicit def toSession(client: SoftPaymentAccount.Client): Session = { - var session = Session(client.clientId) - session += (Session.adminKey, "false") - session += (Session.anonymousKey, "false") - session += ("iss", ClientSessionConfig.jwt.issuer.getOrElse("")) - session += ("sub", client.clientId) + implicit def toSession(client: SoftPaymentAccount.Client): JwtClaims = { + var session = JwtClaims.newSession + .withAdmin(false) + .withAnonymous(false) + .copy( + iss = ClientSessionConfig.jwt.issuer, + sub = Some(client.clientId) + ) session += ("scope", client.accessToken.flatMap(_.scope).getOrElse("")) session } @@ -35,16 +36,16 @@ trait ClientSession extends Completion { _: SessionMaterials => clientSessionManager(client).clientSessionManager.encode(client) } - def decodeClient(data: String): Option[Session] = - manager(ClientSessionConfig).clientSessionManager.decode(data).toOption + def decodeClient(data: String): Option[JwtClaims] = + manager(ClientSessionConfig, JwtClaims).clientSessionManager.decode(data).toOption - def clientSessionManager(client: SoftPaymentAccount.Client): SessionManager[Session] = { + def clientSessionManager(client: SoftPaymentAccount.Client): SessionManager[JwtClaims] = { implicit val innerSessionConfig: SessionConfig = ClientSessionConfig.copy( jwt = ClientSessionConfig.jwt.copy(subject = Some(client.clientId)), serverSecret = client.getClientApiKey ) - manager(innerSessionConfig) + manager(innerSessionConfig, JwtClaims) } def clientCookieName: String = ClientSessionConfig.sessionCookieConfig.name @@ -55,7 +56,7 @@ trait ClientSession extends Completion { _: SessionMaterials => def getFromClientHeaderName: String = ClientSessionConfig.sessionHeaderConfig.getFromClientHeaderName - def sessionManager(clientId: Option[String]): SessionManager[Session] = { + def sessionManager(clientId: Option[String]): SessionManager[JwtClaims] = { clientId match { case Some(id) => softPaymentAccountDao.loadClient(id) complete () match { @@ -66,7 +67,7 @@ trait ClientSession extends Completion { _: SessionMaterials => } } - def clientSessionManager(client: Option[SoftPaymentAccount.Client]): SessionManager[Session] = { + def clientSessionManager(client: Option[SoftPaymentAccount.Client]): SessionManager[JwtClaims] = { client match { case Some(c) => implicit val innerSessionConfig: SessionConfig = @@ -78,7 +79,7 @@ trait ClientSession extends Completion { _: SessionMaterials => sessionEncryptData = true, serverSecret = c.getClientApiKey ) - manager(innerSessionConfig) + manager(innerSessionConfig, JwtClaims) case _ => manager } } diff --git a/core/src/main/scala/app/softnetwork/payment/service/ClientSessionDirectives.scala b/core/src/main/scala/app/softnetwork/payment/service/ClientSessionDirectives.scala index e031bd5..cbba570 100644 --- a/core/src/main/scala/app/softnetwork/payment/service/ClientSessionDirectives.scala +++ b/core/src/main/scala/app/softnetwork/payment/service/ClientSessionDirectives.scala @@ -7,11 +7,12 @@ import app.softnetwork.account.config.AccountSettings import app.softnetwork.payment.annotation.InternalApi import app.softnetwork.payment.model.SoftPaymentAccount import app.softnetwork.session.service.{SessionMaterials, SessionService} -import org.softnetwork.session.model.Session +import org.softnetwork.session.model.JwtClaims import scala.concurrent.Future -trait ClientSessionDirectives extends SessionService with ClientSession { _: SessionMaterials => +trait ClientSessionDirectives extends SessionService[JwtClaims] with ClientSession { + _: SessionMaterials[JwtClaims] => @InternalApi private[payment] def clientDirective: Directive1[Option[SoftPaymentAccount.Client]] = @@ -19,7 +20,7 @@ trait ClientSessionDirectives extends SessionService with ClientSession { _: Ses @InternalApi private[payment] def requiredClientSession( - body: (Option[SoftPaymentAccount.Client], Session) => Route + body: (Option[SoftPaymentAccount.Client], JwtClaims) => Route ): Route = clientDirective { client => requiredSession(sc(clientSessionManager(client)), gt) { session => @@ -29,7 +30,7 @@ trait ClientSessionDirectives extends SessionService with ClientSession { _: Ses @InternalApi private[payment] def optionalClientSession( - body: (Option[SoftPaymentAccount.Client], Option[Session]) => Route + body: (Option[SoftPaymentAccount.Client], Option[JwtClaims]) => Route ): Route = clientDirective { client => optionalSession(sc(clientSessionManager(client)), gt) { session => diff --git a/core/src/main/scala/app/softnetwork/payment/service/ClientSessionEndpoints.scala b/core/src/main/scala/app/softnetwork/payment/service/ClientSessionEndpoints.scala index bac436a..f76b38d 100644 --- a/core/src/main/scala/app/softnetwork/payment/service/ClientSessionEndpoints.scala +++ b/core/src/main/scala/app/softnetwork/payment/service/ClientSessionEndpoints.scala @@ -3,8 +3,8 @@ package app.softnetwork.payment.service import app.softnetwork.account.config.AccountSettings import app.softnetwork.payment.annotation.InternalApi import app.softnetwork.payment.model.SoftPaymentAccount -import app.softnetwork.session._ import app.softnetwork.session.service.{SessionEndpoints, SessionMaterials} +import org.softnetwork.session.model.JwtClaims import com.softwaremill.session.{ CookieOrHeaderST, CookieST, @@ -21,12 +21,12 @@ import sttp.tapir.server.PartialServerEndpointWithSecurityOutput import scala.concurrent.Future -trait ClientSessionEndpoints extends SessionEndpoints with ClientSession { - _: SessionMaterials => +trait ClientSessionEndpoints extends SessionEndpoints[JwtClaims] with ClientSession { + _: SessionMaterials[JwtClaims] => implicit def formats: Formats - import TapirSessionOptions._ + import app.softnetwork.session.TapirSessionOptions._ protected def clientInput: EndpointInput[Option[String]] = auth @@ -36,7 +36,7 @@ trait ClientSessionEndpoints extends SessionEndpoints with ClientSession { @InternalApi private[payment] def requiredClientSession: PartialServerEndpointWithSecurityOutput[Seq[ Option[String] - ], (Option[SoftPaymentAccount.Client], Session), Unit, Unit, Seq[ + ], (Option[SoftPaymentAccount.Client], JwtClaims), Unit, Unit, Seq[ Option[String] ], Unit, Any, Future] = { val partial = clientSession(Some(true)) @@ -57,7 +57,7 @@ trait ClientSessionEndpoints extends SessionEndpoints with ClientSession { @InternalApi private[payment] def optionalClientSession: PartialServerEndpointWithSecurityOutput[Seq[ Option[String] - ], (Option[SoftPaymentAccount.Client], Option[Session]), Unit, Unit, Seq[ + ], (Option[SoftPaymentAccount.Client], Option[JwtClaims]), Unit, Unit, Seq[ Option[String] ], Unit, Any, Future] = { val partial = clientSession(Some(false)) @@ -76,7 +76,7 @@ trait ClientSessionEndpoints extends SessionEndpoints with ClientSession { required: Option[Boolean] ): PartialServerEndpointWithSecurityOutput[Seq[ Option[String] - ], (Option[SoftPaymentAccount.Client], SessionResult[Session]), Unit, Unit, Seq[ + ], (Option[SoftPaymentAccount.Client], SessionResult[JwtClaims]), Unit, Unit, Seq[ Option[String] ], Unit, Any, Future] = { val partial = sc.session(gt, required) @@ -88,7 +88,7 @@ trait ClientSessionEndpoints extends SessionEndpoints with ClientSession { .out(partial.securityOutput) .serverSecurityLogicWithOutput { inputs => toClient(inputs.head) flatMap { client => - implicit val manager: SessionManager[Session] = clientSessionManager(client) + implicit val manager: SessionManager[JwtClaims] = clientSessionManager(client) sessionType match { case Session.SessionType.OneOffCookie | Session.SessionType.OneOffHeader => // oneOff (gt match { diff --git a/core/src/main/scala/app/softnetwork/payment/service/GenericPaymentEndpoints.scala b/core/src/main/scala/app/softnetwork/payment/service/GenericPaymentEndpoints.scala index 6812e3c..ac06cd8 100644 --- a/core/src/main/scala/app/softnetwork/payment/service/GenericPaymentEndpoints.scala +++ b/core/src/main/scala/app/softnetwork/payment/service/GenericPaymentEndpoints.scala @@ -4,6 +4,7 @@ import app.softnetwork.payment.handlers.GenericPaymentHandler import app.softnetwork.payment.message.PaymentMessages._ import app.softnetwork.payment.model._ import app.softnetwork.session.service.SessionMaterials +import org.softnetwork.session.model.JwtClaims import sttp.capabilities import sttp.capabilities.akka.AkkaStreams import sttp.model.Part @@ -23,7 +24,7 @@ trait GenericPaymentEndpoints with UboDeclarationEndpoints with RecurringPaymentEndpoints with MandateEndpoints { - _: GenericPaymentHandler with SessionMaterials => + _: GenericPaymentHandler with SessionMaterials[JwtClaims] => import app.softnetwork.serialization._ diff --git a/core/src/main/scala/app/softnetwork/payment/service/GenericPaymentService.scala b/core/src/main/scala/app/softnetwork/payment/service/GenericPaymentService.scala index 0d40ac0..ebcaae8 100644 --- a/core/src/main/scala/app/softnetwork/payment/service/GenericPaymentService.scala +++ b/core/src/main/scala/app/softnetwork/payment/service/GenericPaymentService.scala @@ -26,6 +26,7 @@ import app.softnetwork.api.server._ import app.softnetwork.payment.config.PaymentSettings._ import app.softnetwork.payment.model._ import com.softwaremill.session.SessionConfig +import org.softnetwork.session.model.JwtClaims import java.io.ByteArrayOutputStream import scala.concurrent.Await @@ -37,9 +38,9 @@ trait GenericPaymentService with Json4sSupport with StrictLogging with BasicPaymentService - with ServiceWithSessionDirectives[PaymentCommand, PaymentResult] + with ServiceWithSessionDirectives[PaymentCommand, PaymentResult, JwtClaims] with ClientSessionDirectives - with ApiRoute { _: GenericPaymentHandler with SessionMaterials => + with ApiRoute { _: GenericPaymentHandler with SessionMaterials[JwtClaims] => implicit def serialization: Serialization.type = jackson.Serialization diff --git a/core/src/main/scala/app/softnetwork/payment/service/RootPaymentEndpoints.scala b/core/src/main/scala/app/softnetwork/payment/service/RootPaymentEndpoints.scala index 1cd26e0..bdfe497 100644 --- a/core/src/main/scala/app/softnetwork/payment/service/RootPaymentEndpoints.scala +++ b/core/src/main/scala/app/softnetwork/payment/service/RootPaymentEndpoints.scala @@ -9,7 +9,7 @@ import app.softnetwork.payment.model.SoftPaymentAccount import app.softnetwork.payment.serialization.paymentFormats import app.softnetwork.session.service.{ServiceWithSessionEndpoints, SessionMaterials} import org.json4s.Formats -import org.softnetwork.session.model.Session +import org.softnetwork.session.model.JwtClaims import sttp.model.headers.CookieValueWithMeta import sttp.model.Method import sttp.tapir.server.PartialServerEndpointWithSecurityOutput @@ -20,9 +20,9 @@ import scala.language.implicitConversions trait RootPaymentEndpoints extends BasicPaymentService - with ServiceWithSessionEndpoints[PaymentCommand, PaymentResult] + with ServiceWithSessionEndpoints[PaymentCommand, PaymentResult, JwtClaims] with ClientSessionEndpoints { - _: GenericPaymentHandler with SessionMaterials => + _: GenericPaymentHandler with SessionMaterials[JwtClaims] => override implicit def formats: Formats = paymentFormats @@ -36,7 +36,7 @@ trait RootPaymentEndpoints lazy val requiredSessionEndpoint: PartialServerEndpointWithSecurityOutput[ (Seq[Option[String]], Option[String], Method, Option[String]), - (Option[SoftPaymentAccount.Client], Session), + (Option[SoftPaymentAccount.Client], JwtClaims), Unit, Any, (Seq[Option[String]], Option[CookieValueWithMeta]), @@ -54,7 +54,7 @@ trait RootPaymentEndpoints lazy val optionalSessionEndpoint: PartialServerEndpointWithSecurityOutput[ (Seq[Option[String]], Option[String], Method, Option[String]), - (Option[SoftPaymentAccount.Client], Option[Session]), + (Option[SoftPaymentAccount.Client], Option[JwtClaims]), Unit, Any, (Seq[Option[String]], Option[CookieValueWithMeta]), diff --git a/core/src/main/scala/app/softnetwork/payment/service/SoftPaymentAccountService.scala b/core/src/main/scala/app/softnetwork/payment/service/SoftPaymentAccountService.scala index 5c724ac..ca1a4fb 100644 --- a/core/src/main/scala/app/softnetwork/payment/service/SoftPaymentAccountService.scala +++ b/core/src/main/scala/app/softnetwork/payment/service/SoftPaymentAccountService.scala @@ -9,9 +9,12 @@ import app.softnetwork.payment.serialization.paymentFormats import app.softnetwork.session.service.SessionMaterials import com.softwaremill.session.SessionConfig import org.json4s.Formats +import org.softnetwork.session.model.JwtClaims -trait SoftPaymentAccountService extends BasicAccountService with SoftPaymentAccountTypeKey { - _: SessionMaterials => +trait SoftPaymentAccountService + extends BasicAccountService[JwtClaims] + with SoftPaymentAccountTypeKey { + _: SessionMaterials[JwtClaims] => final implicit def sessionConfig: SessionConfig = ClientSessionConfig diff --git a/core/src/main/scala/app/softnetwork/payment/service/SoftPaymentAccountServiceEndpoints.scala b/core/src/main/scala/app/softnetwork/payment/service/SoftPaymentAccountServiceEndpoints.scala index 903ce05..293236b 100644 --- a/core/src/main/scala/app/softnetwork/payment/service/SoftPaymentAccountServiceEndpoints.scala +++ b/core/src/main/scala/app/softnetwork/payment/service/SoftPaymentAccountServiceEndpoints.scala @@ -7,6 +7,7 @@ import app.softnetwork.payment.serialization.paymentFormats import app.softnetwork.session.service.SessionMaterials import com.softwaremill.session.SessionConfig import org.json4s.Formats +import org.softnetwork.session.model.JwtClaims import sttp.capabilities import sttp.capabilities.akka.AkkaStreams import sttp.tapir.server.ServerEndpoint @@ -14,10 +15,10 @@ import sttp.tapir.server.ServerEndpoint import scala.concurrent.Future trait SoftPaymentAccountServiceEndpoints - extends BasicAccountServiceEndpoints - with SoftPaymentAccountTypeKey { _: SessionMaterials => + extends BasicAccountServiceEndpoints[JwtClaims] + with SoftPaymentAccountTypeKey { _: SessionMaterials[JwtClaims] => - implicit def sessionConfig: SessionConfig = ClientSessionConfig + final implicit def sessionConfig: SessionConfig = ClientSessionConfig override implicit lazy val formats: Formats = paymentFormats diff --git a/core/src/main/scala/app/softnetwork/payment/service/SoftPaymentOAuthService.scala b/core/src/main/scala/app/softnetwork/payment/service/SoftPaymentOAuthService.scala index fe73fbe..0f26fcf 100644 --- a/core/src/main/scala/app/softnetwork/payment/service/SoftPaymentOAuthService.scala +++ b/core/src/main/scala/app/softnetwork/payment/service/SoftPaymentOAuthService.scala @@ -18,13 +18,13 @@ import app.softnetwork.payment.serialization.paymentFormats import app.softnetwork.session.service.SessionMaterials import com.softwaremill.session.SessionConfig import org.json4s.Formats -import org.softnetwork.session.model.Session +import org.softnetwork.session.model.JwtClaims trait SoftPaymentOAuthService - extends OAuthService + extends OAuthService[JwtClaims] with SoftPaymentAccountTypeKey with ClientSessionDirectives { - _: SessionMaterials => + _: SessionMaterials[JwtClaims] => final implicit def sessionConfig: SessionConfig = ClientSessionConfig @@ -105,7 +105,7 @@ trait SoftPaymentOAuthService .result() ) { authenticateOAuth2Async(AccountSettings.Realm, oauthClient) { client => - setSession(sc(clientSessionManager(client)), st, client.asInstanceOf[Session]) { + setSession(sc(clientSessionManager(client)), st, client.asInstanceOf[JwtClaims]) { complete(StatusCodes.OK) } } diff --git a/core/src/main/scala/app/softnetwork/payment/service/SoftPaymentOAuthServiceEndpoints.scala b/core/src/main/scala/app/softnetwork/payment/service/SoftPaymentOAuthServiceEndpoints.scala index 36ff028..99c2226 100644 --- a/core/src/main/scala/app/softnetwork/payment/service/SoftPaymentOAuthServiceEndpoints.scala +++ b/core/src/main/scala/app/softnetwork/payment/service/SoftPaymentOAuthServiceEndpoints.scala @@ -24,6 +24,7 @@ import app.softnetwork.session.httpCookieToTapirCookieWithMeta import app.softnetwork.session.service.SessionMaterials import com.softwaremill.session.{CookieST, HeaderST, SessionConfig} import org.json4s.Formats +import org.softnetwork.session.model.JwtClaims import sttp.capabilities import sttp.capabilities.akka.AkkaStreams import sttp.model.headers.WWWAuthenticateChallenge @@ -34,13 +35,13 @@ import sttp.tapir.server.ServerEndpoint import scala.concurrent.Future trait SoftPaymentOAuthServiceEndpoints - extends OAuthServiceEndpoints + extends OAuthServiceEndpoints[JwtClaims] with SoftPaymentAccountTypeKey - with ClientSession { _: SessionMaterials => + with ClientSession { _: SessionMaterials[JwtClaims] => import app.softnetwork.serialization.serialization - implicit def sessionConfig: SessionConfig = ClientSessionConfig + final implicit def sessionConfig: SessionConfig = ClientSessionConfig override implicit lazy val formats: Formats = paymentFormats diff --git a/core/src/main/scala/app/softnetwork/session/handlers/ApiKeyDao.scala b/core/src/main/scala/app/softnetwork/session/handlers/ApiKeyDao.scala deleted file mode 100644 index 8e867f9..0000000 --- a/core/src/main/scala/app/softnetwork/session/handlers/ApiKeyDao.scala +++ /dev/null @@ -1,12 +0,0 @@ -package app.softnetwork.session.handlers - -import akka.actor.typed.ActorSystem -import app.softnetwork.session.model.ApiKey - -import scala.concurrent.Future - -trait ApiKeyDao { - - def loadApiKey(clientId: String)(implicit system: ActorSystem[_]): Future[Option[ApiKey]] - -} diff --git a/core/src/main/scala/app/softnetwork/session/handlers/JwtClaimsRefreshTokenHandler.scala b/core/src/main/scala/app/softnetwork/session/handlers/JwtClaimsRefreshTokenHandler.scala deleted file mode 100644 index 9169361..0000000 --- a/core/src/main/scala/app/softnetwork/session/handlers/JwtClaimsRefreshTokenHandler.scala +++ /dev/null @@ -1,33 +0,0 @@ -package app.softnetwork.session.handlers - -import akka.actor.typed.ActorSystem -import akka.cluster.sharding.typed.scaladsl.EntityTypeKey -import app.softnetwork.persistence.typed.CommandTypeKey -import app.softnetwork.session.message.RefreshTokenCommand -import app.softnetwork.session.model.JwtClaims -import app.softnetwork.session.persistence.typed.JwtClaimsRefreshTokenBehavior -import org.slf4j.{Logger, LoggerFactory} - -import scala.reflect.ClassTag - -trait JwtClaimsRefreshTokenTypeKey extends CommandTypeKey[RefreshTokenCommand] { - override def TypeKey(implicit - tTag: ClassTag[RefreshTokenCommand] - ): EntityTypeKey[RefreshTokenCommand] = - JwtClaimsRefreshTokenBehavior.TypeKey -} -trait JwtClaimsRefreshTokenHandler - extends RefreshTokenHandler[JwtClaims] - with JwtClaimsRefreshTokenTypeKey - -trait JwtClaimsRefreshTokenDao extends RefreshTokenDao[JwtClaims] with JwtClaimsRefreshTokenHandler - -object JwtClaimsRefreshTokenDao { - def apply(asystem: ActorSystem[_]): JwtClaimsRefreshTokenDao = { - new JwtClaimsRefreshTokenDao() { - override implicit val system: ActorSystem[_] = asystem - - override lazy val log: Logger = LoggerFactory getLogger getClass.getName - } - } -} diff --git a/core/src/main/scala/app/softnetwork/session/persistence/typed/JwtClaimsRefreshTokenBehavior.scala b/core/src/main/scala/app/softnetwork/session/persistence/typed/JwtClaimsRefreshTokenBehavior.scala deleted file mode 100644 index 414597f..0000000 --- a/core/src/main/scala/app/softnetwork/session/persistence/typed/JwtClaimsRefreshTokenBehavior.scala +++ /dev/null @@ -1,9 +0,0 @@ -package app.softnetwork.session.persistence.typed - -import app.softnetwork.session.model.JwtClaims - -trait JwtClaimsRefreshTokenBehavior extends RefreshTokenBehavior[JwtClaims] { - override val persistenceId = "JwtClaims" -} - -object JwtClaimsRefreshTokenBehavior extends JwtClaimsRefreshTokenBehavior diff --git a/core/src/main/scala/app/softnetwork/session/service/JwtClaimsDirectives.scala b/core/src/main/scala/app/softnetwork/session/service/JwtClaimsDirectives.scala deleted file mode 100644 index f7db1a4..0000000 --- a/core/src/main/scala/app/softnetwork/session/service/JwtClaimsDirectives.scala +++ /dev/null @@ -1,40 +0,0 @@ -package app.softnetwork.session.service - -import app.softnetwork.session.model.JwtClaims -import com.softwaremill.session.{ - CsrfCheckMode, - CsrfOptions, - GetSessionTransport, - SessionContinuity, - SessionDirectives, - SessionManager, - SetSessionTransport -} -import org.softnetwork.session.model.Session - -trait JwtClaimsDirectives extends SessionDirectives { _: JwtClaimsMaterials => - - import com.softwaremill.session.SessionOptions._ - - def sc(implicit manager: SessionManager[JwtClaims]): SessionContinuity[JwtClaims] = - sessionType match { - case Session.SessionType.OneOffCookie | Session.SessionType.OneOffHeader => oneOff - case _ => refreshable - } - - lazy val st: SetSessionTransport = - sessionType match { - case Session.SessionType.OneOffCookie | Session.SessionType.RefreshableCookie => usingCookies - case _ => usingHeaders - } - - lazy val gt: GetSessionTransport = st - - def checkMode(implicit manager: SessionManager[JwtClaims]): CsrfCheckMode[JwtClaims] = - if (headerAndForm) { - CsrfOptions.checkHeaderAndForm - } else { - CsrfOptions.checkHeader - } - -} diff --git a/core/src/main/scala/app/softnetwork/session/service/JwtClaimsEncoder.scala b/core/src/main/scala/app/softnetwork/session/service/JwtClaimsEncoder.scala deleted file mode 100644 index 5c72c05..0000000 --- a/core/src/main/scala/app/softnetwork/session/service/JwtClaimsEncoder.scala +++ /dev/null @@ -1,65 +0,0 @@ -package app.softnetwork.session.service - -import akka.actor.typed.ActorSystem -import app.softnetwork.concurrent.Completion -import app.softnetwork.session.handlers.ApiKeyDao -import app.softnetwork.session.model.JwtClaims -import com.softwaremill.session._ -import org.json4s.{DefaultFormats, Formats, JValue} - -import scala.util.Try - -trait JwtClaimsEncoder extends SessionEncoder[JwtClaims] with Completion { - - implicit def system: ActorSystem[_] - - implicit def formats: Formats = DefaultFormats - - implicit def sessionSerializer: SessionSerializer[JwtClaims, JValue] = JwtClaimsSerializer - - def apiKeyDao: ApiKeyDao - - def sessionEncoder = new JwtSessionEncoder[JwtClaims] - - override def encode(t: JwtClaims, nowMillis: Long, config: SessionConfig): String = { - val jwt = config.jwt.copy( - issuer = t.iss.orElse(config.jwt.issuer), - subject = t.sub.orElse(config.jwt.subject), - audience = t.aud.orElse(config.jwt.audience) - ) - (t.iss match { - case Some(iss) => - (apiKeyDao.loadApiKey(iss) complete ()).toOption.flatten - case _ => None - }) match { - case Some(apiKey) if apiKey.clientSecret.isDefined => - sessionEncoder.encode( - t, - nowMillis, - config.copy(jwt = jwt, serverSecret = apiKey.clientSecret.get) - ) - case _ => sessionEncoder.encode(t, nowMillis, config.copy(jwt = jwt)) - } - } - - override def decode(s: String, config: SessionConfig): Try[DecodeResult[JwtClaims]] = { - val jwtClaims = JwtClaims(s) - val maybeClientId = - if (jwtClaims.iss.contains(config.jwt.issuer.getOrElse(""))) jwtClaims.sub - else jwtClaims.iss - val innerConfig = (maybeClientId match { - case Some(clientId) => - (apiKeyDao.loadApiKey(clientId) complete ()).toOption.flatten.flatMap(_.clientSecret) - case _ => None - }) match { - case Some(clientSecret) => - config.copy(serverSecret = clientSecret) - case _ => - config - } - sessionEncoder - .decode(s, innerConfig) - .map(result => result.copy(t = jwtClaims.copy(additionalClaims = result.t.additionalClaims))) - - } -} diff --git a/core/src/main/scala/app/softnetwork/session/service/JwtClaimsEndpoints.scala b/core/src/main/scala/app/softnetwork/session/service/JwtClaimsEndpoints.scala deleted file mode 100644 index 388c5ce..0000000 --- a/core/src/main/scala/app/softnetwork/session/service/JwtClaimsEndpoints.scala +++ /dev/null @@ -1,39 +0,0 @@ -package app.softnetwork.session.service - -import app.softnetwork.session.model.JwtClaims -import app.softnetwork.session.{ - TapirCsrfCheckMode, - TapirCsrfOptions, - TapirEndpoints, - TapirSessionContinuity -} -import com.softwaremill.session.{GetSessionTransport, SessionManager, SetSessionTransport} -import org.softnetwork.session.model.Session - -trait JwtClaimsEndpoints extends TapirEndpoints { - _: JwtClaimsMaterials => - - import app.softnetwork.session.TapirSessionOptions._ - - def sc(implicit manager: SessionManager[JwtClaims]): TapirSessionContinuity[JwtClaims] = - sessionType match { - case Session.SessionType.OneOffCookie | Session.SessionType.OneOffHeader => oneOff - case _ => refreshable - } - - lazy val st: SetSessionTransport = - sessionType match { - case Session.SessionType.OneOffCookie | Session.SessionType.RefreshableCookie => usingCookies - case _ => usingHeaders - } - - lazy val gt: GetSessionTransport = st - - def checkMode(implicit manager: SessionManager[JwtClaims]): TapirCsrfCheckMode[JwtClaims] = - if (headerAndForm) { - TapirCsrfOptions.checkHeaderAndForm - } else { - TapirCsrfOptions.checkHeader - } - -} diff --git a/core/src/main/scala/app/softnetwork/session/service/JwtClaimsManager.scala b/core/src/main/scala/app/softnetwork/session/service/JwtClaimsManager.scala deleted file mode 100644 index 9a5b1ca..0000000 --- a/core/src/main/scala/app/softnetwork/session/service/JwtClaimsManager.scala +++ /dev/null @@ -1,20 +0,0 @@ -package app.softnetwork.session.service - -import akka.actor.typed.ActorSystem -import app.softnetwork.session.handlers.ApiKeyDao -import app.softnetwork.session.model.JwtClaims -import com.softwaremill.session.{SessionConfig, SessionEncoder, SessionManager} - -import scala.language.reflectiveCalls - -trait JwtClaimsManager extends JwtClaimsMaterials { self: { def apiKeyDao: ApiKeyDao } => - - override def manager(implicit sessionConfig: SessionConfig): SessionManager[JwtClaims] = { - implicit val encoder: SessionEncoder[JwtClaims] = new JwtClaimsEncoder { - override implicit def system: ActorSystem[_] = self.ts - override def apiKeyDao: ApiKeyDao = self.apiKeyDao - } - new SessionManager[JwtClaims](sessionConfig) - } - -} diff --git a/core/src/main/scala/app/softnetwork/session/service/JwtClaimsMaterials.scala b/core/src/main/scala/app/softnetwork/session/service/JwtClaimsMaterials.scala deleted file mode 100644 index 97d57b1..0000000 --- a/core/src/main/scala/app/softnetwork/session/service/JwtClaimsMaterials.scala +++ /dev/null @@ -1,24 +0,0 @@ -package app.softnetwork.session.service - -import akka.actor.typed.ActorSystem -import app.softnetwork.session.handlers.JwtClaimsRefreshTokenDao -import app.softnetwork.session.model.JwtClaims -import com.softwaremill.session.{RefreshTokenStorage, SessionConfig, SessionManager} -import org.softnetwork.session.model.Session - -import scala.concurrent.ExecutionContext - -trait JwtClaimsMaterials { - - implicit def manager(implicit sessionConfig: SessionConfig): SessionManager[JwtClaims] - - implicit def ts: ActorSystem[_] - - implicit def ec: ExecutionContext = ts.executionContext - - implicit def refreshTokenStorage: RefreshTokenStorage[JwtClaims] = JwtClaimsRefreshTokenDao(ts) - - protected def sessionType: Session.SessionType - - def headerAndForm: Boolean = false -} diff --git a/core/src/main/scala/app/softnetwork/session/service/JwtClaimsSerializer.scala b/core/src/main/scala/app/softnetwork/session/service/JwtClaimsSerializer.scala deleted file mode 100644 index e238e2c..0000000 --- a/core/src/main/scala/app/softnetwork/session/service/JwtClaimsSerializer.scala +++ /dev/null @@ -1,21 +0,0 @@ -package app.softnetwork.session.service - -import app.softnetwork.session.model.JwtClaims -import com.softwaremill.session.SessionSerializer -import org.json4s.jackson.JsonMethods.asJValue -import org.json4s.{DefaultFormats, DefaultWriters, Formats, JValue} - -import scala.util.Try - -case object JwtClaimsSerializer extends SessionSerializer[JwtClaims, JValue] { - - implicit val formats: Formats = DefaultFormats - - import DefaultWriters._ - - override def serialize(t: JwtClaims): JValue = asJValue(t.additionalClaims) - - override def deserialize(r: JValue): Try[JwtClaims] = Try { - JwtClaims(additionalClaims = r.extract[Map[String, String]]) - } -} diff --git a/core/src/main/scala/app/softnetwork/session/service/ServiceWithJwtClaimsDirectives.scala b/core/src/main/scala/app/softnetwork/session/service/ServiceWithJwtClaimsDirectives.scala deleted file mode 100644 index b9446ae..0000000 --- a/core/src/main/scala/app/softnetwork/session/service/ServiceWithJwtClaimsDirectives.scala +++ /dev/null @@ -1,11 +0,0 @@ -package app.softnetwork.session.service - -import app.softnetwork.api.server.ApiRoute -import app.softnetwork.persistence.message.{Command, CommandResult} -import app.softnetwork.persistence.service.Service -import app.softnetwork.persistence.typed.scaladsl.Patterns - -trait ServiceWithJwtClaimsDirectives[C <: Command, R <: CommandResult] - extends Service[C, R] - with ApiRoute - with JwtClaimsDirectives { _: Patterns[C, R] with JwtClaimsMaterials => } diff --git a/core/src/main/scala/app/softnetwork/session/service/ServiceWithJwtClaimsEndpoints.scala b/core/src/main/scala/app/softnetwork/session/service/ServiceWithJwtClaimsEndpoints.scala deleted file mode 100644 index 511e610..0000000 --- a/core/src/main/scala/app/softnetwork/session/service/ServiceWithJwtClaimsEndpoints.scala +++ /dev/null @@ -1,9 +0,0 @@ -package app.softnetwork.session.service - -import app.softnetwork.api.server.ServiceEndpoints -import app.softnetwork.persistence.message.{Command, CommandResult} -import app.softnetwork.persistence.typed.scaladsl.Patterns - -trait ServiceWithJwtClaimsEndpoints[C <: Command, R <: CommandResult] - extends ServiceEndpoints[C, R] - with JwtClaimsEndpoints { _: Patterns[C, R] with JwtClaimsMaterials => } diff --git a/mangopay/src/main/scala/app/softnetwork/payment/service/MangoPayPaymentEndpoints.scala b/mangopay/src/main/scala/app/softnetwork/payment/service/MangoPayPaymentEndpoints.scala index 9caf38e..b66b85d 100644 --- a/mangopay/src/main/scala/app/softnetwork/payment/service/MangoPayPaymentEndpoints.scala +++ b/mangopay/src/main/scala/app/softnetwork/payment/service/MangoPayPaymentEndpoints.scala @@ -6,12 +6,13 @@ import app.softnetwork.payment.message.PaymentMessages._ import app.softnetwork.payment.model.{BankAccount, KycDocument, UboDeclaration} import app.softnetwork.session.service.SessionMaterials import com.mangopay.core.enumerations.EventType +import org.softnetwork.session.model.JwtClaims import sttp.tapir.server.ServerEndpoint.Full import scala.concurrent.Future trait MangoPayPaymentEndpoints extends GenericPaymentEndpoints with MangoPayPaymentHandler { - _: SessionMaterials => + _: SessionMaterials[JwtClaims] => /** should be implemented by each payment provider */ diff --git a/mangopay/src/main/scala/app/softnetwork/payment/service/MangoPayPaymentService.scala b/mangopay/src/main/scala/app/softnetwork/payment/service/MangoPayPaymentService.scala index fbfad2f..e4e34ec 100644 --- a/mangopay/src/main/scala/app/softnetwork/payment/service/MangoPayPaymentService.scala +++ b/mangopay/src/main/scala/app/softnetwork/payment/service/MangoPayPaymentService.scala @@ -20,9 +20,10 @@ import app.softnetwork.payment.message.PaymentMessages.{ import app.softnetwork.payment.model.{BankAccount, KycDocument, UboDeclaration} import app.softnetwork.session.service.SessionMaterials import com.mangopay.core.enumerations.EventType +import org.softnetwork.session.model.JwtClaims trait MangoPayPaymentService extends GenericPaymentService with MangoPayPaymentHandler { - _: SessionMaterials => + _: SessionMaterials[JwtClaims] => def completeWithKycDocumentUpdatedResult( eventType: String, diff --git a/project/Versions.scala b/project/Versions.scala index ba9b5db..5be3561 100644 --- a/project/Versions.scala +++ b/project/Versions.scala @@ -1,12 +1,12 @@ object Versions { - val genericPersistence = "0.5.1" + val genericPersistence = "0.6.0" - val scheduler = "0.5.1" + val scheduler = "0.6.1" - val notification = "0.5.1" + val notification = "0.6.1" - val account = "0.5.1" + val account = "0.6.0" val scalatest = "3.2.16" } diff --git a/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentEndpointsTestKit.scala b/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentEndpointsTestKit.scala index f188b6b..2b8a2d1 100644 --- a/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentEndpointsTestKit.scala +++ b/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentEndpointsTestKit.scala @@ -1,7 +1,6 @@ package app.softnetwork.payment.scalatest import akka.actor.typed.ActorSystem -import app.softnetwork.account.message import app.softnetwork.account.message.BasicAccountSignUp import app.softnetwork.account.service.{AccountServiceEndpoints, OAuthServiceEndpoints} import app.softnetwork.api.server.Endpoint @@ -11,69 +10,78 @@ import app.softnetwork.payment.service.{ GenericPaymentEndpoints, MockPaymentEndpoints, MockSoftPaymentAccountServiceEndpoints, - MockSoftPaymentOAuthServiceEndpoints, - SoftPaymentAccountServiceEndpoints, - SoftPaymentOAuthServiceEndpoints + MockSoftPaymentOAuthServiceEndpoints } import app.softnetwork.persistence.schema.SchemaProvider import app.softnetwork.session.scalatest.{SessionEndpointsRoutes, SessionTestKit} import app.softnetwork.session.CsrfCheck +import app.softnetwork.session.model.SessionDataCompanion import app.softnetwork.session.service.SessionMaterials -import com.softwaremill.session.{SessionConfig, SessionManager} +import com.softwaremill.session.{RefreshTokenStorage, SessionConfig, SessionManager} import org.slf4j.{Logger, LoggerFactory} -import org.softnetwork.session.model.Session +import org.softnetwork.session.model.{JwtClaims, Session} import scala.concurrent.ExecutionContext -trait PaymentEndpointsTestKit extends PaymentEndpoints with SessionEndpointsRoutes { +trait PaymentEndpointsTestKit extends PaymentEndpoints with SessionEndpointsRoutes[JwtClaims] { self: PaymentTestKit - with SessionTestKit + with SessionTestKit[JwtClaims] with SchemaProvider with CsrfCheck - with SessionMaterials => + with SessionMaterials[JwtClaims] => implicit def sessionConfig: SessionConfig override def paymentEndpoints: ActorSystem[_] => GenericPaymentEndpoints = sys => - new MockPaymentEndpoints with SessionMaterials { + new MockPaymentEndpoints with SessionMaterials[JwtClaims] { override implicit def manager(implicit - sessionConfig: SessionConfig - ): SessionManager[Session] = self.manager + sessionConfig: SessionConfig, + companion: SessionDataCompanion[JwtClaims] + ): SessionManager[JwtClaims] = self.manager override protected def sessionType: Session.SessionType = self.sessionType override def log: Logger = LoggerFactory getLogger getClass.getName override implicit def sessionConfig: SessionConfig = self.sessionConfig override implicit def system: ActorSystem[_] = sys override lazy val ec: ExecutionContext = sys.executionContext override def softPaymentAccountDao: SoftPaymentAccountDao = MockSoftPaymentAccountDao + override implicit def refreshTokenStorage: RefreshTokenStorage[JwtClaims] = + self.refreshTokenStorage } override def endpoints: ActorSystem[_] => List[Endpoint] = system => super.endpoints(system) :+ sessionServiceEndpoints(system) - override def accountEndpoints: ActorSystem[_] => AccountServiceEndpoints[BasicAccountSignUp] = + override def accountEndpoints + : ActorSystem[_] => AccountServiceEndpoints[BasicAccountSignUp, JwtClaims] = sys => - new MockSoftPaymentAccountServiceEndpoints with SessionMaterials { + new MockSoftPaymentAccountServiceEndpoints with SessionMaterials[JwtClaims] { override implicit def manager(implicit - sessionConfig: SessionConfig - ): SessionManager[Session] = self.manager + sessionConfig: SessionConfig, + companion: SessionDataCompanion[JwtClaims] + ): SessionManager[JwtClaims] = self.manager override protected def sessionType: Session.SessionType = self.sessionType override def log: Logger = LoggerFactory getLogger getClass.getName -// override implicit def sessionConfig: SessionConfig = self.sessionConfig override implicit def system: ActorSystem[_] = sys override lazy val ec: ExecutionContext = sys.executionContext override protected val manifestWrapper: ManifestW = ManifestW() + override implicit def refreshTokenStorage: RefreshTokenStorage[JwtClaims] = + self.refreshTokenStorage + override implicit def companion: SessionDataCompanion[JwtClaims] = self.companion } - override def oauthEndpoints: ActorSystem[_] => OAuthServiceEndpoints = sys => - new MockSoftPaymentOAuthServiceEndpoints with SessionMaterials { + override def oauthEndpoints: ActorSystem[_] => OAuthServiceEndpoints[JwtClaims] = sys => + new MockSoftPaymentOAuthServiceEndpoints with SessionMaterials[JwtClaims] { override implicit def manager(implicit - sessionConfig: SessionConfig - ): SessionManager[Session] = self.manager + sessionConfig: SessionConfig, + companion: SessionDataCompanion[JwtClaims] + ): SessionManager[JwtClaims] = self.manager override protected def sessionType: Session.SessionType = self.sessionType override def log: Logger = LoggerFactory getLogger getClass.getName -// override implicit def sessionConfig: SessionConfig = self.sessionConfig override implicit def system: ActorSystem[_] = sys override lazy val ec: ExecutionContext = sys.executionContext override def softPaymentAccountDao: SoftPaymentAccountDao = MockSoftPaymentAccountDao + override implicit def refreshTokenStorage: RefreshTokenStorage[JwtClaims] = + self.refreshTokenStorage + override implicit def companion: SessionDataCompanion[JwtClaims] = self.companion } } diff --git a/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentRouteTestKit.scala b/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentRouteTestKit.scala index f4455c6..690a5ca 100644 --- a/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentRouteTestKit.scala +++ b/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentRouteTestKit.scala @@ -11,11 +11,15 @@ import app.softnetwork.payment.model._ import app.softnetwork.session.scalatest.SessionTestKit import app.softnetwork.session.service.SessionMaterials import org.scalatest.Suite +import org.softnetwork.session.model.JwtClaims import java.nio.file.Paths -trait PaymentRouteTestKit extends SessionTestKit with PaymentTestKit with PaymentGrpcServices { - _: Suite with ApiRoutes with SessionMaterials => +trait PaymentRouteTestKit + extends SessionTestKit[JwtClaims] + with PaymentTestKit + with PaymentGrpcServices { + _: Suite with ApiRoutes with SessionMaterials[JwtClaims] => import app.softnetwork.serialization._ diff --git a/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentRoutesTestKit.scala b/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentRoutesTestKit.scala index 07a025e..590d3d1 100644 --- a/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentRoutesTestKit.scala +++ b/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentRoutesTestKit.scala @@ -17,28 +17,35 @@ import app.softnetwork.payment.service.{ MockSoftPaymentOAuthService } import app.softnetwork.persistence.schema.SchemaProvider +import app.softnetwork.session.model.SessionDataCompanion import app.softnetwork.session.scalatest.{SessionServiceRoutes, SessionTestKit} import app.softnetwork.session.service.SessionMaterials -import com.softwaremill.session.{SessionConfig, SessionManager} +import com.softwaremill.session.{RefreshTokenStorage, SessionConfig, SessionManager} import org.slf4j.{Logger, LoggerFactory} -import org.softnetwork.session.model.Session +import org.softnetwork.session.model.{JwtClaims, Session} import scala.concurrent.ExecutionContext -trait PaymentRoutesTestKit extends PaymentRoutes with SessionServiceRoutes { - self: PaymentTestKit with SessionTestKit with SchemaProvider with SessionMaterials => +trait PaymentRoutesTestKit extends PaymentRoutes with SessionServiceRoutes[JwtClaims] { + self: PaymentTestKit + with SessionTestKit[JwtClaims] + with SchemaProvider + with SessionMaterials[JwtClaims] => override def paymentService: ActorSystem[_] => GenericPaymentService = sys => - new MockPaymentService with SessionMaterials { + new MockPaymentService with SessionMaterials[JwtClaims] { override implicit def manager(implicit - sessionConfig: SessionConfig - ): SessionManager[Session] = self.manager + sessionConfig: SessionConfig, + companion: SessionDataCompanion[JwtClaims] + ): SessionManager[JwtClaims] = self.manager override protected def sessionType: Session.SessionType = self.sessionType override def log: Logger = LoggerFactory getLogger getClass.getName override implicit def sessionConfig: SessionConfig = self.sessionConfig override implicit def system: ActorSystem[_] = sys override lazy val ec: ExecutionContext = sys.executionContext override def softPaymentAccountDao: SoftPaymentAccountDao = MockSoftPaymentAccountDao + override implicit def refreshTokenStorage: RefreshTokenStorage[JwtClaims] = + self.refreshTokenStorage } implicit def sessionConfig: SessionConfig @@ -46,31 +53,39 @@ trait PaymentRoutesTestKit extends PaymentRoutes with SessionServiceRoutes { override def accountService: ActorSystem[_] => AccountService[ DefaultProfileView, DefaultAccountDetailsView, - DefaultAccountView[DefaultProfileView, DefaultAccountDetailsView] + DefaultAccountView[DefaultProfileView, DefaultAccountDetailsView], + JwtClaims ] = sys => - new MockSoftPaymentAccountService with SessionMaterials { + new MockSoftPaymentAccountService with SessionMaterials[JwtClaims] { override implicit def manager(implicit - sessionConfig: SessionConfig - ): SessionManager[Session] = self.manager + sessionConfig: SessionConfig, + companion: SessionDataCompanion[JwtClaims] + ): SessionManager[JwtClaims] = self.manager override protected def sessionType: Session.SessionType = self.sessionType override def log: Logger = LoggerFactory getLogger getClass.getName -// override implicit def sessionConfig: SessionConfig = self.sessionConfig override implicit def system: ActorSystem[_] = sys override lazy val ec: ExecutionContext = sys.executionContext override protected val manifestWrapper: ManifestW = ManifestW() + override implicit def refreshTokenStorage: RefreshTokenStorage[JwtClaims] = + self.refreshTokenStorage + override implicit def companion: SessionDataCompanion[JwtClaims] = self.companion } - override def oauthService: ActorSystem[_] => OAuthService = sys => - new MockSoftPaymentOAuthService with SessionMaterials { + override def oauthService: ActorSystem[_] => OAuthService[JwtClaims] = sys => + new MockSoftPaymentOAuthService with SessionMaterials[JwtClaims] { override implicit def manager(implicit - sessionConfig: SessionConfig - ): SessionManager[Session] = self.manager + sessionConfig: SessionConfig, + companion: SessionDataCompanion[JwtClaims] + ): SessionManager[JwtClaims] = self.manager override protected def sessionType: Session.SessionType = self.sessionType override def log: Logger = LoggerFactory getLogger getClass.getName // override implicit def sessionConfig: SessionConfig = self.sessionConfig override implicit def system: ActorSystem[_] = sys override lazy val ec: ExecutionContext = sys.executionContext override def softPaymentAccountDao: SoftPaymentAccountDao = MockSoftPaymentAccountDao + override implicit def refreshTokenStorage: RefreshTokenStorage[JwtClaims] = + self.refreshTokenStorage + override implicit def companion: SessionDataCompanion[JwtClaims] = self.companion } override def apiRoutes: ActorSystem[_] => List[ApiRoute] = diff --git a/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentTestKit.scala b/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentTestKit.scala index ce28989..c206127 100644 --- a/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentTestKit.scala +++ b/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentTestKit.scala @@ -37,14 +37,13 @@ import app.softnetwork.persistence.query.{ } import app.softnetwork.scheduler.config.SchedulerSettings import app.softnetwork.scheduler.scalatest.SchedulerTestKit -import app.softnetwork.session.service.SessionMaterials import org.scalatest.Suite import org.slf4j.{Logger, LoggerFactory} -import scala.concurrent.Future +import scala.concurrent.{ExecutionContext, Future} trait PaymentTestKit extends SchedulerTestKit with PaymentGuardian with AllNotificationsTestKit { - _: Suite with SessionMaterials => + _: Suite => /** @return * roles associated with this node @@ -100,6 +99,8 @@ trait PaymentTestKit extends SchedulerTestKit with PaymentGuardian with AllNotif transactionId: String, registerCard: Boolean, printReceipt: Boolean + )(implicit + ec: ExecutionContext ): Future[Either[PayInFailed, Either[PaymentRedirection, PaidIn]]] = { MockPaymentHandler !? PayInFor3DS(orderUuid, transactionId, registerCard, printReceipt) map { case result: PaymentRedirection => Right(Left(result)) @@ -115,6 +116,8 @@ trait PaymentTestKit extends SchedulerTestKit with PaymentGuardian with AllNotif preAuthorizationId: String, registerCard: Boolean = true, printReceipt: Boolean = false + )(implicit + ec: ExecutionContext ): Future[Either[CardPreAuthorizationFailed, Either[PaymentRedirection, CardPreAuthorized]]] = { MockPaymentHandler !? PreAuthorizeCardFor3DS( orderUuid, @@ -132,7 +135,7 @@ trait PaymentTestKit extends SchedulerTestKit with PaymentGuardian with AllNotif def payInFirstRecurringFor3DS( recurringPayInRegistrationId: String, transactionId: String - ): Future[ + )(implicit ec: ExecutionContext): Future[ Either[FirstRecurringCardPaymentFailed, Either[PaymentRedirection, FirstRecurringPaidIn]] ] = { MockPaymentHandler !? PayInFirstRecurringFor3DS( @@ -156,7 +159,7 @@ trait PaymentTestKit extends SchedulerTestKit with PaymentGuardian with AllNotif def updateKycDocumentStatus( kycDocumentId: String, status: Option[KycDocument.KycDocumentStatus] = None - ): Future[Either[PaymentError, KycDocumentStatusUpdated]] = { + )(implicit ec: ExecutionContext): Future[Either[PaymentError, KycDocumentStatusUpdated]] = { MockPaymentHandler !? UpdateKycDocumentStatus(kycDocumentId, status) map { case result: KycDocumentStatusUpdated => Right(result) case error: PaymentError => Left(error) @@ -167,7 +170,7 @@ trait PaymentTestKit extends SchedulerTestKit with PaymentGuardian with AllNotif def updateUboDeclarationStatus( uboDeclarationId: String, status: Option[UboDeclaration.UboDeclarationStatus] = None - ): Future[Boolean] = { + )(implicit ec: ExecutionContext): Future[Boolean] = { MockPaymentHandler !? UpdateUboDeclarationStatus(uboDeclarationId, status) map { case UboDeclarationStatusUpdated => true case _ => false @@ -177,7 +180,7 @@ trait PaymentTestKit extends SchedulerTestKit with PaymentGuardian with AllNotif def updateMandateStatus( mandateId: String, status: Option[BankAccount.MandateStatus] = None - ): Future[Either[PaymentError, MandateStatusUpdated]] = { + )(implicit ec: ExecutionContext): Future[Either[PaymentError, MandateStatusUpdated]] = { MockPaymentHandler !? UpdateMandateStatus(mandateId, status) map { case result: MandateStatusUpdated => Right(result) case error: PaymentError => Left(error) @@ -185,14 +188,14 @@ trait PaymentTestKit extends SchedulerTestKit with PaymentGuardian with AllNotif } } - def validateRegularUser(userId: String): Future[Boolean] = { + def validateRegularUser(userId: String)(implicit ec: ExecutionContext): Future[Boolean] = { MockPaymentHandler !? ValidateRegularUser(userId) map { case RegularUserValidated => true case _ => false } } - def invalidateRegularUser(userId: String): Future[Boolean] = { + def invalidateRegularUser(userId: String)(implicit ec: ExecutionContext): Future[Boolean] = { MockPaymentHandler !? InvalidateRegularUser(userId) map { case RegularUserInvalidated => true case _ => false diff --git a/testkit/src/main/scala/app/softnetwork/payment/service/MockPaymentEndpoints.scala b/testkit/src/main/scala/app/softnetwork/payment/service/MockPaymentEndpoints.scala index cb5cc22..54f3782 100644 --- a/testkit/src/main/scala/app/softnetwork/payment/service/MockPaymentEndpoints.scala +++ b/testkit/src/main/scala/app/softnetwork/payment/service/MockPaymentEndpoints.scala @@ -2,7 +2,8 @@ package app.softnetwork.payment.service import app.softnetwork.payment.handlers.MockPaymentHandler import app.softnetwork.session.service.SessionMaterials +import org.softnetwork.session.model.JwtClaims trait MockPaymentEndpoints extends MangoPayPaymentEndpoints with MockPaymentHandler { - _: SessionMaterials => + _: SessionMaterials[JwtClaims] => } diff --git a/testkit/src/main/scala/app/softnetwork/payment/service/MockPaymentService.scala b/testkit/src/main/scala/app/softnetwork/payment/service/MockPaymentService.scala index b5c9139..b18c6b0 100644 --- a/testkit/src/main/scala/app/softnetwork/payment/service/MockPaymentService.scala +++ b/testkit/src/main/scala/app/softnetwork/payment/service/MockPaymentService.scala @@ -2,7 +2,8 @@ package app.softnetwork.payment.service import app.softnetwork.payment.handlers.MockPaymentHandler import app.softnetwork.session.service.SessionMaterials +import org.softnetwork.session.model.JwtClaims trait MockPaymentService extends MangoPayPaymentService with MockPaymentHandler { - _: SessionMaterials => + _: SessionMaterials[JwtClaims] => } diff --git a/testkit/src/main/scala/app/softnetwork/payment/service/MockSoftPaymentAccountService.scala b/testkit/src/main/scala/app/softnetwork/payment/service/MockSoftPaymentAccountService.scala index a1f4975..b843f98 100644 --- a/testkit/src/main/scala/app/softnetwork/payment/service/MockSoftPaymentAccountService.scala +++ b/testkit/src/main/scala/app/softnetwork/payment/service/MockSoftPaymentAccountService.scala @@ -2,10 +2,11 @@ package app.softnetwork.payment.service import app.softnetwork.payment.handlers.MockSoftPaymentAccountTypeKey import app.softnetwork.session.service.SessionMaterials +import org.softnetwork.session.model.JwtClaims trait MockSoftPaymentAccountService extends SoftPaymentAccountService with MockSoftPaymentAccountTypeKey { - _: SessionMaterials => + _: SessionMaterials[JwtClaims] => } diff --git a/testkit/src/main/scala/app/softnetwork/payment/service/MockSoftPaymentAccountServiceEndpoints.scala b/testkit/src/main/scala/app/softnetwork/payment/service/MockSoftPaymentAccountServiceEndpoints.scala index 7849ff3..e326b14 100644 --- a/testkit/src/main/scala/app/softnetwork/payment/service/MockSoftPaymentAccountServiceEndpoints.scala +++ b/testkit/src/main/scala/app/softnetwork/payment/service/MockSoftPaymentAccountServiceEndpoints.scala @@ -2,7 +2,8 @@ package app.softnetwork.payment.service import app.softnetwork.payment.handlers.MockSoftPaymentAccountTypeKey import app.softnetwork.session.service.SessionMaterials +import org.softnetwork.session.model.JwtClaims trait MockSoftPaymentAccountServiceEndpoints extends SoftPaymentAccountServiceEndpoints - with MockSoftPaymentAccountTypeKey { _: SessionMaterials => } + with MockSoftPaymentAccountTypeKey { _: SessionMaterials[JwtClaims] => } diff --git a/testkit/src/main/scala/app/softnetwork/payment/service/MockSoftPaymentOAuthService.scala b/testkit/src/main/scala/app/softnetwork/payment/service/MockSoftPaymentOAuthService.scala index aace6e2..ba8f9f5 100644 --- a/testkit/src/main/scala/app/softnetwork/payment/service/MockSoftPaymentOAuthService.scala +++ b/testkit/src/main/scala/app/softnetwork/payment/service/MockSoftPaymentOAuthService.scala @@ -4,11 +4,12 @@ import app.softnetwork.account.spi.OAuth2Service import app.softnetwork.payment.handlers.MockSoftPaymentAccountTypeKey import app.softnetwork.session.service.SessionMaterials import com.github.scribejava.core.oauth.DummyApiService +import org.softnetwork.session.model.JwtClaims trait MockSoftPaymentOAuthService extends SoftPaymentOAuthService with MockSoftPaymentAccountTypeKey { - _: SessionMaterials => + _: SessionMaterials[JwtClaims] => override lazy val services: Seq[OAuth2Service] = Seq( new DummyApiService() diff --git a/testkit/src/main/scala/app/softnetwork/payment/service/MockSoftPaymentOAuthServiceEndpoints.scala b/testkit/src/main/scala/app/softnetwork/payment/service/MockSoftPaymentOAuthServiceEndpoints.scala index dc0b4e4..0f40346 100644 --- a/testkit/src/main/scala/app/softnetwork/payment/service/MockSoftPaymentOAuthServiceEndpoints.scala +++ b/testkit/src/main/scala/app/softnetwork/payment/service/MockSoftPaymentOAuthServiceEndpoints.scala @@ -4,10 +4,11 @@ import app.softnetwork.account.spi.OAuth2Service import app.softnetwork.payment.handlers.MockSoftPaymentAccountTypeKey import app.softnetwork.session.service.SessionMaterials import com.github.scribejava.core.oauth.DummyApiService +import org.softnetwork.session.model.JwtClaims trait MockSoftPaymentOAuthServiceEndpoints extends SoftPaymentOAuthServiceEndpoints - with MockSoftPaymentAccountTypeKey { _: SessionMaterials => + with MockSoftPaymentAccountTypeKey { _: SessionMaterials[JwtClaims] => override lazy val services: Seq[OAuth2Service] = Seq( diff --git a/testkit/src/test/scala/app/softnetwork/payment/handlers/PaymentHandlerSpec.scala b/testkit/src/test/scala/app/softnetwork/payment/handlers/PaymentHandlerSpec.scala index 4407410..0e27b57 100644 --- a/testkit/src/test/scala/app/softnetwork/payment/handlers/PaymentHandlerSpec.scala +++ b/testkit/src/test/scala/app/softnetwork/payment/handlers/PaymentHandlerSpec.scala @@ -10,7 +10,6 @@ import app.softnetwork.payment.scalatest.PaymentTestKit import app.softnetwork.time._ import app.softnetwork.persistence.now import app.softnetwork.session.config.Settings -import app.softnetwork.session.service.BasicSessionMaterials import org.scalatest.wordspec.AnyWordSpecLike import org.slf4j.{Logger, LoggerFactory} import org.softnetwork.session.model.Session @@ -22,13 +21,12 @@ import scala.util.{Failure, Success} class PaymentHandlerSpec extends MockPaymentHandler with AnyWordSpecLike - with PaymentGrpcServer with PaymentTestKit - with BasicSessionMaterials { + with PaymentGrpcServer { lazy val log: Logger = LoggerFactory getLogger getClass.getName - override implicit lazy val ts: ActorSystem[_] = typedSystem() + implicit lazy val ts: ActorSystem[_] = typedSystem() override protected def sessionType: Session.SessionType = Settings.Session.SessionContinuityAndTransport diff --git a/testkit/src/test/scala/app/softnetwork/payment/service/PaymentEndpointsWithOneOffCookieSessionSpec.scala b/testkit/src/test/scala/app/softnetwork/payment/service/PaymentEndpointsWithOneOffCookieSessionSpec.scala index 2d37913..59353ae 100644 --- a/testkit/src/test/scala/app/softnetwork/payment/service/PaymentEndpointsWithOneOffCookieSessionSpec.scala +++ b/testkit/src/test/scala/app/softnetwork/payment/service/PaymentEndpointsWithOneOffCookieSessionSpec.scala @@ -4,10 +4,11 @@ import app.softnetwork.payment.scalatest.PaymentEndpointsTestKit import app.softnetwork.session.scalatest.OneOffCookieSessionEndpointsTestKit import app.softnetwork.session.CsrfCheckHeader import app.softnetwork.session.service.BasicSessionMaterials +import org.softnetwork.session.model.JwtClaims class PaymentEndpointsWithOneOffCookieSessionSpec extends PaymentServiceSpec - with OneOffCookieSessionEndpointsTestKit + with OneOffCookieSessionEndpointsTestKit[JwtClaims] with PaymentEndpointsTestKit with CsrfCheckHeader - with BasicSessionMaterials + with BasicSessionMaterials[JwtClaims] diff --git a/testkit/src/test/scala/app/softnetwork/payment/service/PaymentEndpointsWithOneOffHeaderSessionSpec.scala b/testkit/src/test/scala/app/softnetwork/payment/service/PaymentEndpointsWithOneOffHeaderSessionSpec.scala index 1a526b4..4f1622c 100644 --- a/testkit/src/test/scala/app/softnetwork/payment/service/PaymentEndpointsWithOneOffHeaderSessionSpec.scala +++ b/testkit/src/test/scala/app/softnetwork/payment/service/PaymentEndpointsWithOneOffHeaderSessionSpec.scala @@ -4,10 +4,11 @@ import app.softnetwork.payment.scalatest.PaymentEndpointsTestKit import app.softnetwork.session.scalatest.OneOffHeaderSessionEndpointsTestKit import app.softnetwork.session.CsrfCheckHeader import app.softnetwork.session.service.BasicSessionMaterials +import org.softnetwork.session.model.JwtClaims class PaymentEndpointsWithOneOffHeaderSessionSpec extends PaymentServiceSpec - with OneOffHeaderSessionEndpointsTestKit + with OneOffHeaderSessionEndpointsTestKit[JwtClaims] with PaymentEndpointsTestKit with CsrfCheckHeader - with BasicSessionMaterials + with BasicSessionMaterials[JwtClaims] diff --git a/testkit/src/test/scala/app/softnetwork/payment/service/PaymentEndpointsWithRefreshableCookieSessionSpec.scala b/testkit/src/test/scala/app/softnetwork/payment/service/PaymentEndpointsWithRefreshableCookieSessionSpec.scala index 236ff27..01b9212 100644 --- a/testkit/src/test/scala/app/softnetwork/payment/service/PaymentEndpointsWithRefreshableCookieSessionSpec.scala +++ b/testkit/src/test/scala/app/softnetwork/payment/service/PaymentEndpointsWithRefreshableCookieSessionSpec.scala @@ -4,10 +4,11 @@ import app.softnetwork.payment.scalatest.PaymentEndpointsTestKit import app.softnetwork.session.scalatest.RefreshableCookieSessionEndpointsTestKit import app.softnetwork.session.CsrfCheckHeader import app.softnetwork.session.service.BasicSessionMaterials +import org.softnetwork.session.model.JwtClaims class PaymentEndpointsWithRefreshableCookieSessionSpec extends PaymentServiceSpec - with RefreshableCookieSessionEndpointsTestKit + with RefreshableCookieSessionEndpointsTestKit[JwtClaims] with PaymentEndpointsTestKit with CsrfCheckHeader - with BasicSessionMaterials + with BasicSessionMaterials[JwtClaims] diff --git a/testkit/src/test/scala/app/softnetwork/payment/service/PaymentEndpointsWithRefreshableHeaderSessionSpec.scala b/testkit/src/test/scala/app/softnetwork/payment/service/PaymentEndpointsWithRefreshableHeaderSessionSpec.scala index 1c82c17..9f3b001 100644 --- a/testkit/src/test/scala/app/softnetwork/payment/service/PaymentEndpointsWithRefreshableHeaderSessionSpec.scala +++ b/testkit/src/test/scala/app/softnetwork/payment/service/PaymentEndpointsWithRefreshableHeaderSessionSpec.scala @@ -4,10 +4,11 @@ import app.softnetwork.payment.scalatest.PaymentEndpointsTestKit import app.softnetwork.session.scalatest.RefreshableHeaderSessionEndpointsTestKit import app.softnetwork.session.CsrfCheckHeader import app.softnetwork.session.service.BasicSessionMaterials +import org.softnetwork.session.model.JwtClaims class PaymentEndpointsWithRefreshableHeaderSessionSpec extends PaymentServiceSpec - with RefreshableHeaderSessionEndpointsTestKit + with RefreshableHeaderSessionEndpointsTestKit[JwtClaims] with PaymentEndpointsTestKit with CsrfCheckHeader - with BasicSessionMaterials + with BasicSessionMaterials[JwtClaims] diff --git a/testkit/src/test/scala/app/softnetwork/payment/service/PaymentRoutesWithOneOffCookieSessionSpec.scala b/testkit/src/test/scala/app/softnetwork/payment/service/PaymentRoutesWithOneOffCookieSessionSpec.scala index b9a32c8..5294a3a 100644 --- a/testkit/src/test/scala/app/softnetwork/payment/service/PaymentRoutesWithOneOffCookieSessionSpec.scala +++ b/testkit/src/test/scala/app/softnetwork/payment/service/PaymentRoutesWithOneOffCookieSessionSpec.scala @@ -3,9 +3,10 @@ package app.softnetwork.payment.service import app.softnetwork.payment.scalatest.PaymentRoutesTestKit import app.softnetwork.session.scalatest.OneOffCookieSessionServiceTestKit import app.softnetwork.session.service.BasicSessionMaterials +import org.softnetwork.session.model.JwtClaims class PaymentRoutesWithOneOffCookieSessionSpec extends PaymentServiceSpec - with OneOffCookieSessionServiceTestKit + with OneOffCookieSessionServiceTestKit[JwtClaims] with PaymentRoutesTestKit - with BasicSessionMaterials + with BasicSessionMaterials[JwtClaims] diff --git a/testkit/src/test/scala/app/softnetwork/payment/service/PaymentRoutesWithOneOffHeaderSessionSpec.scala b/testkit/src/test/scala/app/softnetwork/payment/service/PaymentRoutesWithOneOffHeaderSessionSpec.scala index ea65a41..5902a9d 100644 --- a/testkit/src/test/scala/app/softnetwork/payment/service/PaymentRoutesWithOneOffHeaderSessionSpec.scala +++ b/testkit/src/test/scala/app/softnetwork/payment/service/PaymentRoutesWithOneOffHeaderSessionSpec.scala @@ -3,9 +3,10 @@ package app.softnetwork.payment.service import app.softnetwork.payment.scalatest.PaymentRoutesTestKit import app.softnetwork.session.scalatest.OneOffHeaderSessionServiceTestKit import app.softnetwork.session.service.BasicSessionMaterials +import org.softnetwork.session.model.JwtClaims class PaymentRoutesWithOneOffHeaderSessionSpec extends PaymentServiceSpec - with OneOffHeaderSessionServiceTestKit + with OneOffHeaderSessionServiceTestKit[JwtClaims] with PaymentRoutesTestKit - with BasicSessionMaterials + with BasicSessionMaterials[JwtClaims] diff --git a/testkit/src/test/scala/app/softnetwork/payment/service/PaymentRoutesWithRefreshableCookieSessionSpec.scala b/testkit/src/test/scala/app/softnetwork/payment/service/PaymentRoutesWithRefreshableCookieSessionSpec.scala index 3d104e2..10c6045 100644 --- a/testkit/src/test/scala/app/softnetwork/payment/service/PaymentRoutesWithRefreshableCookieSessionSpec.scala +++ b/testkit/src/test/scala/app/softnetwork/payment/service/PaymentRoutesWithRefreshableCookieSessionSpec.scala @@ -3,9 +3,10 @@ package app.softnetwork.payment.service import app.softnetwork.payment.scalatest.PaymentRoutesTestKit import app.softnetwork.session.scalatest.RefreshableCookieSessionServiceTestKit import app.softnetwork.session.service.BasicSessionMaterials +import org.softnetwork.session.model.JwtClaims class PaymentRoutesWithRefreshableCookieSessionSpec extends PaymentServiceSpec - with RefreshableCookieSessionServiceTestKit + with RefreshableCookieSessionServiceTestKit[JwtClaims] with PaymentRoutesTestKit - with BasicSessionMaterials + with BasicSessionMaterials[JwtClaims] diff --git a/testkit/src/test/scala/app/softnetwork/payment/service/PaymentRoutesWithRefreshableHeaderSessionSpec.scala b/testkit/src/test/scala/app/softnetwork/payment/service/PaymentRoutesWithRefreshableHeaderSessionSpec.scala index 731f8cc..82e8165 100644 --- a/testkit/src/test/scala/app/softnetwork/payment/service/PaymentRoutesWithRefreshableHeaderSessionSpec.scala +++ b/testkit/src/test/scala/app/softnetwork/payment/service/PaymentRoutesWithRefreshableHeaderSessionSpec.scala @@ -3,9 +3,10 @@ package app.softnetwork.payment.service import app.softnetwork.payment.scalatest.PaymentRoutesTestKit import app.softnetwork.session.scalatest.RefreshableHeaderSessionServiceTestKit import app.softnetwork.session.service.BasicSessionMaterials +import org.softnetwork.session.model.JwtClaims class PaymentRoutesWithRefreshableHeaderSessionSpec extends PaymentServiceSpec - with RefreshableHeaderSessionServiceTestKit + with RefreshableHeaderSessionServiceTestKit[JwtClaims] with PaymentRoutesTestKit - with BasicSessionMaterials + with BasicSessionMaterials[JwtClaims] diff --git a/testkit/src/test/scala/app/softnetwork/payment/service/PaymentServiceSpec.scala b/testkit/src/test/scala/app/softnetwork/payment/service/PaymentServiceSpec.scala index 2d26ed4..f8ce48c 100644 --- a/testkit/src/test/scala/app/softnetwork/payment/service/PaymentServiceSpec.scala +++ b/testkit/src/test/scala/app/softnetwork/payment/service/PaymentServiceSpec.scala @@ -12,9 +12,13 @@ import app.softnetwork.payment.model._ import app.softnetwork.payment.scalatest.PaymentRouteTestKit import app.softnetwork.time._ import app.softnetwork.persistence.now +import app.softnetwork.session.handlers.JwtClaimsRefreshTokenDao +import app.softnetwork.session.model.SessionDataCompanion import app.softnetwork.session.service.SessionMaterials +import com.softwaremill.session.RefreshTokenStorage import org.scalatest.wordspec.AnyWordSpecLike import org.slf4j.{Logger, LoggerFactory} +import org.softnetwork.session.model.JwtClaims import java.net.{InetAddress, URLEncoder} import java.time.LocalDate @@ -22,7 +26,7 @@ import scala.language.implicitConversions import scala.util.{Failure, Success} trait PaymentServiceSpec extends AnyWordSpecLike with PaymentRouteTestKit { - _: ApiRoutes with SessionMaterials => + _: ApiRoutes with SessionMaterials[JwtClaims] => lazy val log: Logger = LoggerFactory getLogger getClass.getName @@ -30,6 +34,11 @@ trait PaymentServiceSpec extends AnyWordSpecLike with PaymentRouteTestKit { lazy val paymentClient: PaymentClient = PaymentClient(ts) + override implicit def companion: SessionDataCompanion[JwtClaims] = JwtClaims + + override implicit def refreshTokenStorage: RefreshTokenStorage[JwtClaims] = + JwtClaimsRefreshTokenDao(ts) + "Payment service" must { "pre register card" in { createSession(customerUuid, Some("customer")) From d3c4b92a1d95e82a3cf999719c19a323a0f3859f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Manciot?= Date: Mon, 4 Dec 2023 06:56:36 +0100 Subject: [PATCH 07/37] remove ClientSessionConfig --- common/src/main/resources/reference.conf | 40 ++++++------------- .../payment/config/PaymentSettings.scala | 3 -- .../payment/service/ClientSession.scala | 15 +++---- .../service/SoftPaymentAccountService.scala | 4 +- .../SoftPaymentAccountServiceEndpoints.scala | 4 +- .../service/SoftPaymentOAuthService.scala | 4 +- .../SoftPaymentOAuthServiceEndpoints.scala | 4 +- 7 files changed, 27 insertions(+), 47 deletions(-) diff --git a/common/src/main/resources/reference.conf b/common/src/main/resources/reference.conf index ec1ae39..53521e0 100644 --- a/common/src/main/resources/reference.conf +++ b/common/src/main/resources/reference.conf @@ -10,6 +10,19 @@ softnetwork { } } +akka.http.session { + encrypt-data = true + + jws { + alg = "HS256" + } + + jwt { + iss = "softpayment" + include-iat = true + } +} + payment{ baseUrl = "http://localhost:"${softnetwork.api.server.port}"/"${softnetwork.api.server.root-path} baseUrl = ${?PAYMENT_BASE_URL} @@ -38,33 +51,6 @@ payment{ external-to-payment-account-tag = "external-to-payment-account" } - client { - akka.http.session { - cookie { - name = "_clientdata" - secure = false - http-only = true - domain = none - path = "/" - max-age = 30 days - } - header { - send-to-client-name = "Set-X-API-KEY" - get-from-client-name = "X-API-KEY" - } - max-age = 7 days - encrypt-data = true - - jws { - alg = "HS256" - } - - jwt { - iss = "softpayment" - include-iat = true - } - } - } } auth { diff --git a/common/src/main/scala/app/softnetwork/payment/config/PaymentSettings.scala b/common/src/main/scala/app/softnetwork/payment/config/PaymentSettings.scala index c216508..b7ad971 100644 --- a/common/src/main/scala/app/softnetwork/payment/config/PaymentSettings.scala +++ b/common/src/main/scala/app/softnetwork/payment/config/PaymentSettings.scala @@ -1,6 +1,5 @@ package app.softnetwork.payment.config -import com.softwaremill.session.SessionConfig import com.typesafe.config.{Config, ConfigFactory} import com.typesafe.scalalogging.StrictLogging @@ -35,8 +34,6 @@ trait PaymentSettings extends StrictLogging { val AkkaNodeRole: String = config.getString("payment.akka-node-role") - val ClientSessionConfig: SessionConfig = - SessionConfig.fromConfig(config.getConfig("payment.client").withFallback(config)) } object PaymentSettings extends PaymentSettings diff --git a/core/src/main/scala/app/softnetwork/payment/service/ClientSession.scala b/core/src/main/scala/app/softnetwork/payment/service/ClientSession.scala index bbd89d7..5dc48b3 100644 --- a/core/src/main/scala/app/softnetwork/payment/service/ClientSession.scala +++ b/core/src/main/scala/app/softnetwork/payment/service/ClientSession.scala @@ -1,7 +1,6 @@ package app.softnetwork.payment.service import app.softnetwork.concurrent.Completion -import app.softnetwork.payment.config.PaymentSettings.ClientSessionConfig import app.softnetwork.payment.handlers.SoftPaymentAccountDao import app.softnetwork.payment.model.SoftPaymentAccount import app.softnetwork.session.service.SessionMaterials @@ -23,7 +22,6 @@ trait ClientSession extends Completion { self: SessionMaterials[JwtClaims] => .withAdmin(false) .withAnonymous(false) .copy( - iss = ClientSessionConfig.jwt.issuer, sub = Some(client.clientId) ) session += ("scope", client.accessToken.flatMap(_.scope).getOrElse("")) @@ -37,24 +35,24 @@ trait ClientSession extends Completion { self: SessionMaterials[JwtClaims] => } def decodeClient(data: String): Option[JwtClaims] = - manager(ClientSessionConfig, JwtClaims).clientSessionManager.decode(data).toOption + manager(sessionConfig, JwtClaims).clientSessionManager.decode(data).toOption def clientSessionManager(client: SoftPaymentAccount.Client): SessionManager[JwtClaims] = { implicit val innerSessionConfig: SessionConfig = - ClientSessionConfig.copy( - jwt = ClientSessionConfig.jwt.copy(subject = Some(client.clientId)), + sessionConfig.copy( + jwt = sessionConfig.jwt.copy(subject = Some(client.clientId)), serverSecret = client.getClientApiKey ) manager(innerSessionConfig, JwtClaims) } - def clientCookieName: String = ClientSessionConfig.sessionCookieConfig.name + def clientCookieName: String = sessionConfig.sessionCookieConfig.name def sendToClientHeaderName: String = - ClientSessionConfig.sessionHeaderConfig.sendToClientHeaderName + sessionConfig.sessionHeaderConfig.sendToClientHeaderName def getFromClientHeaderName: String = - ClientSessionConfig.sessionHeaderConfig.getFromClientHeaderName + sessionConfig.sessionHeaderConfig.getFromClientHeaderName def sessionManager(clientId: Option[String]): SessionManager[JwtClaims] = { clientId match { @@ -73,7 +71,6 @@ trait ClientSession extends Completion { self: SessionMaterials[JwtClaims] => implicit val innerSessionConfig: SessionConfig = sessionConfig.copy( jwt = sessionConfig.jwt.copy( - issuer = ClientSessionConfig.jwt.issuer, subject = Some(c.clientId) ), sessionEncryptData = true, diff --git a/core/src/main/scala/app/softnetwork/payment/service/SoftPaymentAccountService.scala b/core/src/main/scala/app/softnetwork/payment/service/SoftPaymentAccountService.scala index ca1a4fb..17793fc 100644 --- a/core/src/main/scala/app/softnetwork/payment/service/SoftPaymentAccountService.scala +++ b/core/src/main/scala/app/softnetwork/payment/service/SoftPaymentAccountService.scala @@ -3,9 +3,9 @@ package app.softnetwork.payment.service import akka.http.scaladsl.server.Route import app.softnetwork.account.config.AccountSettings import app.softnetwork.account.service.BasicAccountService -import app.softnetwork.payment.config.PaymentSettings.ClientSessionConfig import app.softnetwork.payment.handlers.SoftPaymentAccountTypeKey import app.softnetwork.payment.serialization.paymentFormats +import app.softnetwork.session.config.Settings import app.softnetwork.session.service.SessionMaterials import com.softwaremill.session.SessionConfig import org.json4s.Formats @@ -16,7 +16,7 @@ trait SoftPaymentAccountService with SoftPaymentAccountTypeKey { _: SessionMaterials[JwtClaims] => - final implicit def sessionConfig: SessionConfig = ClientSessionConfig + implicit def sessionConfig: SessionConfig = Settings.Session.DefaultSessionConfig override implicit lazy val formats: Formats = paymentFormats diff --git a/core/src/main/scala/app/softnetwork/payment/service/SoftPaymentAccountServiceEndpoints.scala b/core/src/main/scala/app/softnetwork/payment/service/SoftPaymentAccountServiceEndpoints.scala index 293236b..9c28734 100644 --- a/core/src/main/scala/app/softnetwork/payment/service/SoftPaymentAccountServiceEndpoints.scala +++ b/core/src/main/scala/app/softnetwork/payment/service/SoftPaymentAccountServiceEndpoints.scala @@ -1,9 +1,9 @@ package app.softnetwork.payment.service import app.softnetwork.account.service.BasicAccountServiceEndpoints -import app.softnetwork.payment.config.PaymentSettings.ClientSessionConfig import app.softnetwork.payment.handlers.SoftPaymentAccountTypeKey import app.softnetwork.payment.serialization.paymentFormats +import app.softnetwork.session.config.Settings import app.softnetwork.session.service.SessionMaterials import com.softwaremill.session.SessionConfig import org.json4s.Formats @@ -18,7 +18,7 @@ trait SoftPaymentAccountServiceEndpoints extends BasicAccountServiceEndpoints[JwtClaims] with SoftPaymentAccountTypeKey { _: SessionMaterials[JwtClaims] => - final implicit def sessionConfig: SessionConfig = ClientSessionConfig + implicit def sessionConfig: SessionConfig = Settings.Session.DefaultSessionConfig override implicit lazy val formats: Formats = paymentFormats diff --git a/core/src/main/scala/app/softnetwork/payment/service/SoftPaymentOAuthService.scala b/core/src/main/scala/app/softnetwork/payment/service/SoftPaymentOAuthService.scala index 0f26fcf..52d68f3 100644 --- a/core/src/main/scala/app/softnetwork/payment/service/SoftPaymentOAuthService.scala +++ b/core/src/main/scala/app/softnetwork/payment/service/SoftPaymentOAuthService.scala @@ -11,10 +11,10 @@ import app.softnetwork.account.message.{ Tokens } import app.softnetwork.account.service.OAuthService -import app.softnetwork.payment.config.PaymentSettings.ClientSessionConfig import app.softnetwork.payment.handlers.SoftPaymentAccountTypeKey import app.softnetwork.payment.message.AccountMessages.{GenerateClientToken, RefreshClientToken} import app.softnetwork.payment.serialization.paymentFormats +import app.softnetwork.session.config.Settings import app.softnetwork.session.service.SessionMaterials import com.softwaremill.session.SessionConfig import org.json4s.Formats @@ -26,7 +26,7 @@ trait SoftPaymentOAuthService with ClientSessionDirectives { _: SessionMaterials[JwtClaims] => - final implicit def sessionConfig: SessionConfig = ClientSessionConfig + implicit def sessionConfig: SessionConfig = Settings.Session.DefaultSessionConfig override implicit lazy val formats: Formats = paymentFormats diff --git a/core/src/main/scala/app/softnetwork/payment/service/SoftPaymentOAuthServiceEndpoints.scala b/core/src/main/scala/app/softnetwork/payment/service/SoftPaymentOAuthServiceEndpoints.scala index 99c2226..8c02e4a 100644 --- a/core/src/main/scala/app/softnetwork/payment/service/SoftPaymentOAuthServiceEndpoints.scala +++ b/core/src/main/scala/app/softnetwork/payment/service/SoftPaymentOAuthServiceEndpoints.scala @@ -11,7 +11,6 @@ import app.softnetwork.account.message.{ } import app.softnetwork.account.service.OAuthServiceEndpoints import app.softnetwork.api.server.ApiErrors -import app.softnetwork.payment.config.PaymentSettings.ClientSessionConfig import app.softnetwork.payment.handlers.SoftPaymentAccountTypeKey import app.softnetwork.payment.message.AccountMessages.{ GenerateClientToken, @@ -20,6 +19,7 @@ import app.softnetwork.payment.message.AccountMessages.{ RefreshClientToken } import app.softnetwork.payment.serialization.paymentFormats +import app.softnetwork.session.config.Settings import app.softnetwork.session.httpCookieToTapirCookieWithMeta import app.softnetwork.session.service.SessionMaterials import com.softwaremill.session.{CookieST, HeaderST, SessionConfig} @@ -41,7 +41,7 @@ trait SoftPaymentOAuthServiceEndpoints import app.softnetwork.serialization.serialization - final implicit def sessionConfig: SessionConfig = ClientSessionConfig + implicit def sessionConfig: SessionConfig = Settings.Session.DefaultSessionConfig override implicit lazy val formats: Formats = paymentFormats From cce22ae5329b37cb7c3e9a315320f3bf8c9d2f2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Manciot?= Date: Mon, 4 Dec 2023 12:25:49 +0100 Subject: [PATCH 08/37] add typed session materials --- .../payment/launch/PaymentEndpoints.scala | 7 +- .../payment/launch/PaymentRoutes.scala | 7 +- .../service/BankAccountEndpoints.scala | 4 +- .../payment/service/BasicPaymentService.scala | 6 +- .../payment/service/CardEndpoints.scala | 4 +- .../service/CardPaymentEndpoints.scala | 7 +- .../payment/service/ClientSession.scala | 42 ++++++---- .../service/ClientSessionDirectives.scala | 12 +-- .../service/ClientSessionEndpoints.scala | 21 ++--- .../service/GenericPaymentEndpoints.scala | 22 ++--- .../service/GenericPaymentService.scala | 10 +-- .../service/KycDocumentEndpoints.scala | 4 +- .../payment/service/MandateEndpoints.scala | 4 +- .../service/RecurringPaymentEndpoints.scala | 4 +- .../service/RootPaymentEndpoints.scala | 14 ++-- .../service/SoftPaymentAccountService.scala | 8 +- .../SoftPaymentAccountServiceEndpoints.scala | 8 +- .../service/SoftPaymentOAuthService.scala | 12 +-- .../SoftPaymentOAuthServiceEndpoints.scala | 8 +- .../service/UboDeclarationEndpoints.scala | 4 +- .../api/src/main/resources/reference.conf | 5 +- .../softnetwork/payment/api/MangoPayApi.scala | 84 ++++++++++++++++--- .../payment/api/MangoPayEndpoints.scala | 53 ++++++++---- .../payment/api/MangoPayEndpointsApi.scala | 5 +- .../MangoPayEndpointsPostgresLauncher.scala | 32 ++++++- .../payment/api/MangoPayRoutes.scala | 47 +++++++---- .../payment/api/MangoPayRoutesApi.scala | 5 +- .../api/MangoPayRoutesPostgresLauncher.scala | 31 ++++++- .../api/MangoPayWithSchedulerApi.scala | 5 +- .../api/MangoPayWithSchedulerEndpoints.scala | 38 ++++++++- .../MangoPayWithSchedulerEndpointsApi.scala | 7 +- ...thSchedulerEndpointsPostgresLauncher.scala | 32 ++++++- .../api/MangoPayWithSchedulerRoutes.scala | 53 +++++++++++- .../api/MangoPayWithSchedulerRoutesApi.scala | 7 +- ...yWithSchedulerRoutesPostgresLauncher.scala | 32 ++++++- mangopay/src/main/resources/reference.conf | 3 - .../service/MangoPayPaymentEndpoints.scala | 8 +- .../service/MangoPayPaymentService.scala | 8 +- .../scalatest/PaymentEndpointsTestKit.scala | 46 +++++----- .../scalatest/PaymentRouteTestKit.scala | 8 +- .../scalatest/PaymentRoutesTestKit.scala | 48 +++++------ .../payment/scalatest/PaymentTestKit.scala | 4 + .../service/MockPaymentEndpoints.scala | 8 +- .../payment/service/MockPaymentService.scala | 8 +- .../MockSoftPaymentAccountService.scala | 8 +- ...ckSoftPaymentAccountServiceEndpoints.scala | 8 +- .../service/MockSoftPaymentOAuthService.scala | 8 +- ...MockSoftPaymentOAuthServiceEndpoints.scala | 8 +- ...EndpointsWithOneOffCookieSessionSpec.scala | 11 ++- ...EndpointsWithOneOffHeaderSessionSpec.scala | 11 ++- ...intsWithRefreshableCookieSessionSpec.scala | 11 ++- ...intsWithRefreshableHeaderSessionSpec.scala | 11 ++- ...entRoutesWithOneOffCookieSessionSpec.scala | 11 ++- ...entRoutesWithOneOffHeaderSessionSpec.scala | 11 ++- ...utesWithRefreshableCookieSessionSpec.scala | 11 ++- ...utesWithRefreshableHeaderSessionSpec.scala | 11 ++- .../payment/service/PaymentServiceSpec.scala | 16 ++-- 57 files changed, 631 insertions(+), 290 deletions(-) diff --git a/core/src/main/scala/app/softnetwork/payment/launch/PaymentEndpoints.scala b/core/src/main/scala/app/softnetwork/payment/launch/PaymentEndpoints.scala index 4eb7da0..1f1512f 100644 --- a/core/src/main/scala/app/softnetwork/payment/launch/PaymentEndpoints.scala +++ b/core/src/main/scala/app/softnetwork/payment/launch/PaymentEndpoints.scala @@ -10,21 +10,22 @@ import app.softnetwork.payment.serialization.paymentFormats import app.softnetwork.payment.service.GenericPaymentEndpoints import app.softnetwork.persistence.schema.SchemaProvider import app.softnetwork.session.CsrfCheck +import app.softnetwork.session.model.{SessionData, SessionDataDecorator} import org.json4s.Formats import org.softnetwork.session.model.JwtClaims -trait PaymentEndpoints +trait PaymentEndpoints[SD <: SessionData with SessionDataDecorator[SD]] extends AccountEndpoints[ SoftPaymentAccount, BasicAccountProfile, BasicAccountSignUp, - JwtClaims + SD ] { _: PaymentGuardian with SchemaProvider with CsrfCheck => override implicit def formats: Formats = paymentFormats - def paymentEndpoints: ActorSystem[_] => GenericPaymentEndpoints + def paymentEndpoints: ActorSystem[_] => GenericPaymentEndpoints[SD] override def endpoints: ActorSystem[_] => List[Endpoint] = system => diff --git a/core/src/main/scala/app/softnetwork/payment/launch/PaymentRoutes.scala b/core/src/main/scala/app/softnetwork/payment/launch/PaymentRoutes.scala index f00aa62..a8125b8 100644 --- a/core/src/main/scala/app/softnetwork/payment/launch/PaymentRoutes.scala +++ b/core/src/main/scala/app/softnetwork/payment/launch/PaymentRoutes.scala @@ -14,22 +14,23 @@ import app.softnetwork.payment.serialization.paymentFormats import app.softnetwork.payment.service.GenericPaymentService import app.softnetwork.persistence.schema.SchemaProvider import app.softnetwork.session.CsrfCheck +import app.softnetwork.session.model.{SessionData, SessionDataDecorator} import org.json4s.Formats import org.softnetwork.session.model.JwtClaims -trait PaymentRoutes +trait PaymentRoutes[SD <: SessionData with SessionDataDecorator[SD]] extends AccountRoutes[ SoftPaymentAccount, BasicAccountProfile, DefaultProfileView, DefaultAccountDetailsView, DefaultAccountView[DefaultProfileView, DefaultAccountDetailsView], - JwtClaims + SD ] { _: PaymentGuardian with SchemaProvider with CsrfCheck => override implicit def formats: Formats = paymentFormats - def paymentService: ActorSystem[_] => GenericPaymentService + def paymentService: ActorSystem[_] => GenericPaymentService[SD] override def apiRoutes: ActorSystem[_] => List[ApiRoute] = system => diff --git a/core/src/main/scala/app/softnetwork/payment/service/BankAccountEndpoints.scala b/core/src/main/scala/app/softnetwork/payment/service/BankAccountEndpoints.scala index 541df81..346a763 100644 --- a/core/src/main/scala/app/softnetwork/payment/service/BankAccountEndpoints.scala +++ b/core/src/main/scala/app/softnetwork/payment/service/BankAccountEndpoints.scala @@ -4,6 +4,7 @@ import app.softnetwork.payment.config.PaymentSettings import app.softnetwork.payment.handlers.GenericPaymentHandler import app.softnetwork.payment.message.PaymentMessages._ import app.softnetwork.payment.model.{BankAccountView, PaymentAccount} +import app.softnetwork.session.model.{SessionData, SessionDataDecorator} import sttp.capabilities import sttp.capabilities.akka.AkkaStreams import sttp.model.StatusCode @@ -12,7 +13,8 @@ import sttp.tapir.server.ServerEndpoint import scala.concurrent.Future -trait BankAccountEndpoints { _: RootPaymentEndpoints with GenericPaymentHandler => +trait BankAccountEndpoints[SD <: SessionData with SessionDataDecorator[SD]] { + _: RootPaymentEndpoints[SD] with GenericPaymentHandler => import app.softnetwork.serialization._ diff --git a/core/src/main/scala/app/softnetwork/payment/service/BasicPaymentService.scala b/core/src/main/scala/app/softnetwork/payment/service/BasicPaymentService.scala index 5fb17c3..bc92db5 100644 --- a/core/src/main/scala/app/softnetwork/payment/service/BasicPaymentService.scala +++ b/core/src/main/scala/app/softnetwork/payment/service/BasicPaymentService.scala @@ -3,9 +3,8 @@ package app.softnetwork.payment.service import app.softnetwork.api.server.ApiErrors import app.softnetwork.payment.handlers.GenericPaymentHandler import app.softnetwork.payment.message.PaymentMessages._ -import app.softnetwork.payment.model.{computeExternalUuidWithProfile, BrowserInfo} +import app.softnetwork.payment.model.BrowserInfo import app.softnetwork.persistence.service.Service -import org.softnetwork.session.model.JwtClaims import java.util.TimeZone import scala.concurrent.Future @@ -37,9 +36,6 @@ trait BasicPaymentService extends Service[PaymentCommand, PaymentResult] { case _ => ApiErrors.BadRequest("Unknown") } - protected[payment] def externalUuidWithProfile(session: JwtClaims): String = - computeExternalUuidWithProfile(session.id, session.profile) - protected[payment] def extractBrowserInfo( language: Option[String], accept: Option[String], diff --git a/core/src/main/scala/app/softnetwork/payment/service/CardEndpoints.scala b/core/src/main/scala/app/softnetwork/payment/service/CardEndpoints.scala index 3a97ced..57f4537 100644 --- a/core/src/main/scala/app/softnetwork/payment/service/CardEndpoints.scala +++ b/core/src/main/scala/app/softnetwork/payment/service/CardEndpoints.scala @@ -4,6 +4,7 @@ import app.softnetwork.payment.config.PaymentSettings import app.softnetwork.payment.handlers.GenericPaymentHandler import app.softnetwork.payment.message.PaymentMessages._ import app.softnetwork.payment.model.{CardPreRegistration, CardView} +import app.softnetwork.session.model.{SessionData, SessionDataDecorator} import sttp.capabilities import sttp.capabilities.akka.AkkaStreams import sttp.model.StatusCode @@ -12,7 +13,8 @@ import sttp.tapir.server.ServerEndpoint import scala.concurrent.Future -trait CardEndpoints { _: RootPaymentEndpoints with GenericPaymentHandler => +trait CardEndpoints[SD <: SessionData with SessionDataDecorator[SD]] { + _: RootPaymentEndpoints[SD] with GenericPaymentHandler => import app.softnetwork.serialization._ diff --git a/core/src/main/scala/app/softnetwork/payment/service/CardPaymentEndpoints.scala b/core/src/main/scala/app/softnetwork/payment/service/CardPaymentEndpoints.scala index 67b93ed..ef9a15c 100644 --- a/core/src/main/scala/app/softnetwork/payment/service/CardPaymentEndpoints.scala +++ b/core/src/main/scala/app/softnetwork/payment/service/CardPaymentEndpoints.scala @@ -4,7 +4,7 @@ import app.softnetwork.payment.config.PaymentSettings import app.softnetwork.payment.handlers.GenericPaymentHandler import app.softnetwork.payment.message.PaymentMessages._ import app.softnetwork.payment.model.SoftPaymentAccount -import org.softnetwork.session.model.JwtClaims +import app.softnetwork.session.model.{SessionData, SessionDataDecorator} import sttp.capabilities import sttp.capabilities.akka.AkkaStreams import sttp.model.{HeaderNames, Method, StatusCode} @@ -14,13 +14,14 @@ import sttp.tapir.server.{PartialServerEndpointWithSecurityOutput, ServerEndpoin import scala.concurrent.Future -trait CardPaymentEndpoints { _: RootPaymentEndpoints with GenericPaymentHandler => +trait CardPaymentEndpoints[SD <: SessionData with SessionDataDecorator[SD]] { + _: RootPaymentEndpoints[SD] with GenericPaymentHandler => import app.softnetwork.serialization._ def payment(payment: Payment): PartialServerEndpointWithSecurityOutput[ (Seq[Option[String]], Option[String], Method, Option[String]), - (Option[SoftPaymentAccount.Client], JwtClaims), + (Option[SoftPaymentAccount.Client], SD), (Option[String], Option[String], Option[String], Option[String], Payment), Any, (Seq[Option[String]], Option[CookieValueWithMeta]), diff --git a/core/src/main/scala/app/softnetwork/payment/service/ClientSession.scala b/core/src/main/scala/app/softnetwork/payment/service/ClientSession.scala index 5dc48b3..48e2b49 100644 --- a/core/src/main/scala/app/softnetwork/payment/service/ClientSession.scala +++ b/core/src/main/scala/app/softnetwork/payment/service/ClientSession.scala @@ -2,28 +2,30 @@ package app.softnetwork.payment.service import app.softnetwork.concurrent.Completion import app.softnetwork.payment.handlers.SoftPaymentAccountDao -import app.softnetwork.payment.model.SoftPaymentAccount +import app.softnetwork.payment.model.{computeExternalUuidWithProfile, SoftPaymentAccount} +import app.softnetwork.session.model.{SessionData, SessionDataCompanion, SessionDataDecorator} import app.softnetwork.session.service.SessionMaterials -import org.softnetwork.session.model.JwtClaims +import org.softnetwork.session.model.{ApiKey, JwtClaims} import com.softwaremill.session._ import scala.concurrent.Future import scala.language.implicitConversions import scala.util.{Failure, Success} -trait ClientSession extends Completion { self: SessionMaterials[JwtClaims] => +trait ClientSession[SD <: SessionData with SessionDataDecorator[SD]] extends Completion { + self: SessionMaterials[SD] => def softPaymentAccountDao: SoftPaymentAccountDao = SoftPaymentAccountDao implicit def sessionConfig: SessionConfig - implicit def toSession(client: SoftPaymentAccount.Client): JwtClaims = { - var session = JwtClaims.newSession + implicit def companion: SessionDataCompanion[SD] + + implicit def toSession(client: SoftPaymentAccount.Client): SD = { + var session = companion.newSession .withAdmin(false) .withAnonymous(false) - .copy( - sub = Some(client.clientId) - ) + .withClientId(client.clientId) session += ("scope", client.accessToken.flatMap(_.scope).getOrElse("")) session } @@ -34,16 +36,17 @@ trait ClientSession extends Completion { self: SessionMaterials[JwtClaims] => clientSessionManager(client).clientSessionManager.encode(client) } - def decodeClient(data: String): Option[JwtClaims] = - manager(sessionConfig, JwtClaims).clientSessionManager.decode(data).toOption + def decodeClient(data: String): Option[SD] = manager.clientSessionManager.decode(data).toOption - def clientSessionManager(client: SoftPaymentAccount.Client): SessionManager[JwtClaims] = { + def clientSessionManager(client: SoftPaymentAccount.Client): SessionManager[SD] = { implicit val innerSessionConfig: SessionConfig = sessionConfig.copy( - jwt = sessionConfig.jwt.copy(subject = Some(client.clientId)), + jwt = sessionConfig.jwt.copy( + subject = Some(client.clientId) + ), serverSecret = client.getClientApiKey ) - manager(innerSessionConfig, JwtClaims) + manager(innerSessionConfig, companion) } def clientCookieName: String = sessionConfig.sessionCookieConfig.name @@ -54,7 +57,7 @@ trait ClientSession extends Completion { self: SessionMaterials[JwtClaims] => def getFromClientHeaderName: String = sessionConfig.sessionHeaderConfig.getFromClientHeaderName - def sessionManager(clientId: Option[String]): SessionManager[JwtClaims] = { + def sessionManager(clientId: Option[String]): SessionManager[SD] = { clientId match { case Some(id) => softPaymentAccountDao.loadClient(id) complete () match { @@ -65,7 +68,7 @@ trait ClientSession extends Completion { self: SessionMaterials[JwtClaims] => } } - def clientSessionManager(client: Option[SoftPaymentAccount.Client]): SessionManager[JwtClaims] = { + def clientSessionManager(client: Option[SoftPaymentAccount.Client]): SessionManager[SD] = { client match { case Some(c) => implicit val innerSessionConfig: SessionConfig = @@ -73,14 +76,16 @@ trait ClientSession extends Completion { self: SessionMaterials[JwtClaims] => jwt = sessionConfig.jwt.copy( subject = Some(c.clientId) ), - sessionEncryptData = true, serverSecret = c.getClientApiKey ) - manager(innerSessionConfig, JwtClaims) + manager(innerSessionConfig, companion) case _ => manager } } + def loadApiKey(clientId: String): Future[Option[ApiKey]] = + softPaymentAccountDao.loadApiKey(clientId) + protected def toClient(token: Option[String]): Future[Option[SoftPaymentAccount.Client]] = { token match { case Some(value) => @@ -101,4 +106,7 @@ trait ClientSession extends Completion { self: SessionMaterials[JwtClaims] => } } + protected[payment] def externalUuidWithProfile(session: SD): String = + computeExternalUuidWithProfile(session.id, session.profile) + } diff --git a/core/src/main/scala/app/softnetwork/payment/service/ClientSessionDirectives.scala b/core/src/main/scala/app/softnetwork/payment/service/ClientSessionDirectives.scala index cbba570..28d680f 100644 --- a/core/src/main/scala/app/softnetwork/payment/service/ClientSessionDirectives.scala +++ b/core/src/main/scala/app/softnetwork/payment/service/ClientSessionDirectives.scala @@ -6,13 +6,15 @@ import akka.http.scaladsl.server.directives.Credentials import app.softnetwork.account.config.AccountSettings import app.softnetwork.payment.annotation.InternalApi import app.softnetwork.payment.model.SoftPaymentAccount +import app.softnetwork.session.model.{SessionData, SessionDataDecorator} import app.softnetwork.session.service.{SessionMaterials, SessionService} -import org.softnetwork.session.model.JwtClaims import scala.concurrent.Future -trait ClientSessionDirectives extends SessionService[JwtClaims] with ClientSession { - _: SessionMaterials[JwtClaims] => +trait ClientSessionDirectives[SD <: SessionData with SessionDataDecorator[SD]] + extends SessionService[SD] + with ClientSession[SD] { + _: SessionMaterials[SD] => @InternalApi private[payment] def clientDirective: Directive1[Option[SoftPaymentAccount.Client]] = @@ -20,7 +22,7 @@ trait ClientSessionDirectives extends SessionService[JwtClaims] with ClientSessi @InternalApi private[payment] def requiredClientSession( - body: (Option[SoftPaymentAccount.Client], JwtClaims) => Route + body: (Option[SoftPaymentAccount.Client], SD) => Route ): Route = clientDirective { client => requiredSession(sc(clientSessionManager(client)), gt) { session => @@ -30,7 +32,7 @@ trait ClientSessionDirectives extends SessionService[JwtClaims] with ClientSessi @InternalApi private[payment] def optionalClientSession( - body: (Option[SoftPaymentAccount.Client], Option[JwtClaims]) => Route + body: (Option[SoftPaymentAccount.Client], Option[SD]) => Route ): Route = clientDirective { client => optionalSession(sc(clientSessionManager(client)), gt) { session => diff --git a/core/src/main/scala/app/softnetwork/payment/service/ClientSessionEndpoints.scala b/core/src/main/scala/app/softnetwork/payment/service/ClientSessionEndpoints.scala index f76b38d..4b994de 100644 --- a/core/src/main/scala/app/softnetwork/payment/service/ClientSessionEndpoints.scala +++ b/core/src/main/scala/app/softnetwork/payment/service/ClientSessionEndpoints.scala @@ -3,8 +3,8 @@ package app.softnetwork.payment.service import app.softnetwork.account.config.AccountSettings import app.softnetwork.payment.annotation.InternalApi import app.softnetwork.payment.model.SoftPaymentAccount +import app.softnetwork.session.model.{SessionData, SessionDataDecorator} import app.softnetwork.session.service.{SessionEndpoints, SessionMaterials} -import org.softnetwork.session.model.JwtClaims import com.softwaremill.session.{ CookieOrHeaderST, CookieST, @@ -21,8 +21,10 @@ import sttp.tapir.server.PartialServerEndpointWithSecurityOutput import scala.concurrent.Future -trait ClientSessionEndpoints extends SessionEndpoints[JwtClaims] with ClientSession { - _: SessionMaterials[JwtClaims] => +trait ClientSessionEndpoints[SD <: SessionData with SessionDataDecorator[SD]] + extends SessionEndpoints[SD] + with ClientSession[SD] { + _: SessionMaterials[SD] => implicit def formats: Formats @@ -36,7 +38,7 @@ trait ClientSessionEndpoints extends SessionEndpoints[JwtClaims] with ClientSess @InternalApi private[payment] def requiredClientSession: PartialServerEndpointWithSecurityOutput[Seq[ Option[String] - ], (Option[SoftPaymentAccount.Client], JwtClaims), Unit, Unit, Seq[ + ], (Option[SoftPaymentAccount.Client], SD), Unit, Unit, Seq[ Option[String] ], Unit, Any, Future] = { val partial = clientSession(Some(true)) @@ -57,7 +59,7 @@ trait ClientSessionEndpoints extends SessionEndpoints[JwtClaims] with ClientSess @InternalApi private[payment] def optionalClientSession: PartialServerEndpointWithSecurityOutput[Seq[ Option[String] - ], (Option[SoftPaymentAccount.Client], Option[JwtClaims]), Unit, Unit, Seq[ + ], (Option[SoftPaymentAccount.Client], Option[SD]), Unit, Unit, Seq[ Option[String] ], Unit, Any, Future] = { val partial = clientSession(Some(false)) @@ -76,7 +78,7 @@ trait ClientSessionEndpoints extends SessionEndpoints[JwtClaims] with ClientSess required: Option[Boolean] ): PartialServerEndpointWithSecurityOutput[Seq[ Option[String] - ], (Option[SoftPaymentAccount.Client], SessionResult[JwtClaims]), Unit, Unit, Seq[ + ], (Option[SoftPaymentAccount.Client], SessionResult[SD]), Unit, Unit, Seq[ Option[String] ], Unit, Any, Future] = { val partial = sc.session(gt, required) @@ -88,7 +90,7 @@ trait ClientSessionEndpoints extends SessionEndpoints[JwtClaims] with ClientSess .out(partial.securityOutput) .serverSecurityLogicWithOutput { inputs => toClient(inputs.head) flatMap { client => - implicit val manager: SessionManager[JwtClaims] = clientSessionManager(client) + implicit val manager: SessionManager[SD] = clientSessionManager(client) sessionType match { case Session.SessionType.OneOffCookie | Session.SessionType.OneOffHeader => // oneOff (gt match { @@ -141,11 +143,6 @@ trait ClientSessionEndpoints extends SessionEndpoints[JwtClaims] with ClientSess case Right(r) => Future.successful(Right((r._1, (client, r._2)))) } } -// case None => -// partial.securityLogic(new FutureMonad())(inputs.tail).map { -// case Left(l) => Left(l) -// case Right(r) => Right((r._1, (None, r._2))) -// } } } } diff --git a/core/src/main/scala/app/softnetwork/payment/service/GenericPaymentEndpoints.scala b/core/src/main/scala/app/softnetwork/payment/service/GenericPaymentEndpoints.scala index ac06cd8..f2a8e60 100644 --- a/core/src/main/scala/app/softnetwork/payment/service/GenericPaymentEndpoints.scala +++ b/core/src/main/scala/app/softnetwork/payment/service/GenericPaymentEndpoints.scala @@ -3,8 +3,8 @@ package app.softnetwork.payment.service import app.softnetwork.payment.handlers.GenericPaymentHandler import app.softnetwork.payment.message.PaymentMessages._ import app.softnetwork.payment.model._ +import app.softnetwork.session.model.{SessionData, SessionDataDecorator} import app.softnetwork.session.service.SessionMaterials -import org.softnetwork.session.model.JwtClaims import sttp.capabilities import sttp.capabilities.akka.AkkaStreams import sttp.model.Part @@ -15,16 +15,16 @@ import sttp.tapir.server.ServerEndpoint.Full import scala.concurrent.Future import scala.language.{implicitConversions, postfixOps} -trait GenericPaymentEndpoints - extends RootPaymentEndpoints - with CardEndpoints - with CardPaymentEndpoints - with BankAccountEndpoints - with KycDocumentEndpoints - with UboDeclarationEndpoints - with RecurringPaymentEndpoints - with MandateEndpoints { - _: GenericPaymentHandler with SessionMaterials[JwtClaims] => +trait GenericPaymentEndpoints[SD <: SessionData with SessionDataDecorator[SD]] + extends RootPaymentEndpoints[SD] + with CardEndpoints[SD] + with CardPaymentEndpoints[SD] + with BankAccountEndpoints[SD] + with KycDocumentEndpoints[SD] + with UboDeclarationEndpoints[SD] + with RecurringPaymentEndpoints[SD] + with MandateEndpoints[SD] { + _: GenericPaymentHandler with SessionMaterials[SD] => import app.softnetwork.serialization._ diff --git a/core/src/main/scala/app/softnetwork/payment/service/GenericPaymentService.scala b/core/src/main/scala/app/softnetwork/payment/service/GenericPaymentService.scala index ebcaae8..c43ada2 100644 --- a/core/src/main/scala/app/softnetwork/payment/service/GenericPaymentService.scala +++ b/core/src/main/scala/app/softnetwork/payment/service/GenericPaymentService.scala @@ -25,22 +25,22 @@ import org.json4s.jackson.Serialization import app.softnetwork.api.server._ import app.softnetwork.payment.config.PaymentSettings._ import app.softnetwork.payment.model._ +import app.softnetwork.session.model.{SessionData, SessionDataDecorator} import com.softwaremill.session.SessionConfig -import org.softnetwork.session.model.JwtClaims import java.io.ByteArrayOutputStream import scala.concurrent.Await import scala.language.implicitConversions -trait GenericPaymentService +trait GenericPaymentService[SD <: SessionData with SessionDataDecorator[SD]] extends Directives with DefaultComplete with Json4sSupport with StrictLogging with BasicPaymentService - with ServiceWithSessionDirectives[PaymentCommand, PaymentResult, JwtClaims] - with ClientSessionDirectives - with ApiRoute { _: GenericPaymentHandler with SessionMaterials[JwtClaims] => + with ServiceWithSessionDirectives[PaymentCommand, PaymentResult, SD] + with ClientSessionDirectives[SD] + with ApiRoute { _: GenericPaymentHandler with SessionMaterials[SD] => implicit def serialization: Serialization.type = jackson.Serialization diff --git a/core/src/main/scala/app/softnetwork/payment/service/KycDocumentEndpoints.scala b/core/src/main/scala/app/softnetwork/payment/service/KycDocumentEndpoints.scala index a6032ca..38e5611 100644 --- a/core/src/main/scala/app/softnetwork/payment/service/KycDocumentEndpoints.scala +++ b/core/src/main/scala/app/softnetwork/payment/service/KycDocumentEndpoints.scala @@ -5,6 +5,7 @@ import app.softnetwork.payment.config.PaymentSettings import app.softnetwork.payment.handlers.GenericPaymentHandler import app.softnetwork.payment.message.PaymentMessages._ import app.softnetwork.payment.model.{KycDocument, KycDocumentValidationReport} +import app.softnetwork.session.model.{SessionData, SessionDataDecorator} import sttp.capabilities import sttp.capabilities.akka.AkkaStreams import sttp.model.StatusCode @@ -13,7 +14,8 @@ import sttp.tapir.server.ServerEndpoint import scala.concurrent.Future -trait KycDocumentEndpoints { _: RootPaymentEndpoints with GenericPaymentHandler => +trait KycDocumentEndpoints[SD <: SessionData with SessionDataDecorator[SD]] { + _: RootPaymentEndpoints[SD] with GenericPaymentHandler => import app.softnetwork.serialization._ diff --git a/core/src/main/scala/app/softnetwork/payment/service/MandateEndpoints.scala b/core/src/main/scala/app/softnetwork/payment/service/MandateEndpoints.scala index 3449e0c..28ae92e 100644 --- a/core/src/main/scala/app/softnetwork/payment/service/MandateEndpoints.scala +++ b/core/src/main/scala/app/softnetwork/payment/service/MandateEndpoints.scala @@ -4,6 +4,7 @@ import app.softnetwork.payment.config.PaymentSettings import app.softnetwork.payment.handlers.GenericPaymentHandler import app.softnetwork.payment.message.PaymentMessages._ import app.softnetwork.payment.model.MandateResult +import app.softnetwork.session.model.{SessionData, SessionDataDecorator} import sttp.capabilities import sttp.capabilities.akka.AkkaStreams import sttp.model.StatusCode @@ -12,7 +13,8 @@ import sttp.tapir.server.ServerEndpoint import scala.concurrent.Future -trait MandateEndpoints { _: RootPaymentEndpoints with GenericPaymentHandler => +trait MandateEndpoints[SD <: SessionData with SessionDataDecorator[SD]] { + _: RootPaymentEndpoints[SD] with GenericPaymentHandler => import app.softnetwork.serialization._ diff --git a/core/src/main/scala/app/softnetwork/payment/service/RecurringPaymentEndpoints.scala b/core/src/main/scala/app/softnetwork/payment/service/RecurringPaymentEndpoints.scala index 0a104b7..fa078a2 100644 --- a/core/src/main/scala/app/softnetwork/payment/service/RecurringPaymentEndpoints.scala +++ b/core/src/main/scala/app/softnetwork/payment/service/RecurringPaymentEndpoints.scala @@ -4,6 +4,7 @@ import app.softnetwork.payment.config.PaymentSettings import app.softnetwork.payment.handlers.GenericPaymentHandler import app.softnetwork.payment.message.PaymentMessages._ import app.softnetwork.payment.model.{RecurringPayment, RecurringPaymentView} +import app.softnetwork.session.model.{SessionData, SessionDataDecorator} import sttp.capabilities import sttp.capabilities.akka.AkkaStreams import sttp.model.StatusCode @@ -12,7 +13,8 @@ import sttp.tapir.server.ServerEndpoint import scala.concurrent.Future -trait RecurringPaymentEndpoints { _: RootPaymentEndpoints with GenericPaymentHandler => +trait RecurringPaymentEndpoints[SD <: SessionData with SessionDataDecorator[SD]] { + _: RootPaymentEndpoints[SD] with GenericPaymentHandler => import app.softnetwork.serialization._ diff --git a/core/src/main/scala/app/softnetwork/payment/service/RootPaymentEndpoints.scala b/core/src/main/scala/app/softnetwork/payment/service/RootPaymentEndpoints.scala index bdfe497..a03d95a 100644 --- a/core/src/main/scala/app/softnetwork/payment/service/RootPaymentEndpoints.scala +++ b/core/src/main/scala/app/softnetwork/payment/service/RootPaymentEndpoints.scala @@ -7,9 +7,9 @@ import app.softnetwork.payment.handlers.GenericPaymentHandler import app.softnetwork.payment.message.PaymentMessages._ import app.softnetwork.payment.model.SoftPaymentAccount import app.softnetwork.payment.serialization.paymentFormats +import app.softnetwork.session.model.{SessionData, SessionDataDecorator} import app.softnetwork.session.service.{ServiceWithSessionEndpoints, SessionMaterials} import org.json4s.Formats -import org.softnetwork.session.model.JwtClaims import sttp.model.headers.CookieValueWithMeta import sttp.model.Method import sttp.tapir.server.PartialServerEndpointWithSecurityOutput @@ -18,11 +18,11 @@ import sttp.tapir.Endpoint import scala.concurrent.Future import scala.language.implicitConversions -trait RootPaymentEndpoints +trait RootPaymentEndpoints[SD <: SessionData with SessionDataDecorator[SD]] extends BasicPaymentService - with ServiceWithSessionEndpoints[PaymentCommand, PaymentResult, JwtClaims] - with ClientSessionEndpoints { - _: GenericPaymentHandler with SessionMaterials[JwtClaims] => + with ServiceWithSessionEndpoints[PaymentCommand, PaymentResult, SD] + with ClientSessionEndpoints[SD] { + _: GenericPaymentHandler with SessionMaterials[SD] => override implicit def formats: Formats = paymentFormats @@ -36,7 +36,7 @@ trait RootPaymentEndpoints lazy val requiredSessionEndpoint: PartialServerEndpointWithSecurityOutput[ (Seq[Option[String]], Option[String], Method, Option[String]), - (Option[SoftPaymentAccount.Client], JwtClaims), + (Option[SoftPaymentAccount.Client], SD), Unit, Any, (Seq[Option[String]], Option[CookieValueWithMeta]), @@ -54,7 +54,7 @@ trait RootPaymentEndpoints lazy val optionalSessionEndpoint: PartialServerEndpointWithSecurityOutput[ (Seq[Option[String]], Option[String], Method, Option[String]), - (Option[SoftPaymentAccount.Client], Option[JwtClaims]), + (Option[SoftPaymentAccount.Client], Option[SD]), Unit, Any, (Seq[Option[String]], Option[CookieValueWithMeta]), diff --git a/core/src/main/scala/app/softnetwork/payment/service/SoftPaymentAccountService.scala b/core/src/main/scala/app/softnetwork/payment/service/SoftPaymentAccountService.scala index 17793fc..37b58ca 100644 --- a/core/src/main/scala/app/softnetwork/payment/service/SoftPaymentAccountService.scala +++ b/core/src/main/scala/app/softnetwork/payment/service/SoftPaymentAccountService.scala @@ -6,15 +6,15 @@ import app.softnetwork.account.service.BasicAccountService import app.softnetwork.payment.handlers.SoftPaymentAccountTypeKey import app.softnetwork.payment.serialization.paymentFormats import app.softnetwork.session.config.Settings +import app.softnetwork.session.model.{SessionData, SessionDataDecorator} import app.softnetwork.session.service.SessionMaterials import com.softwaremill.session.SessionConfig import org.json4s.Formats -import org.softnetwork.session.model.JwtClaims -trait SoftPaymentAccountService - extends BasicAccountService[JwtClaims] +trait SoftPaymentAccountService[SD <: SessionData with SessionDataDecorator[SD]] + extends BasicAccountService[SD] with SoftPaymentAccountTypeKey { - _: SessionMaterials[JwtClaims] => + _: SessionMaterials[SD] => implicit def sessionConfig: SessionConfig = Settings.Session.DefaultSessionConfig diff --git a/core/src/main/scala/app/softnetwork/payment/service/SoftPaymentAccountServiceEndpoints.scala b/core/src/main/scala/app/softnetwork/payment/service/SoftPaymentAccountServiceEndpoints.scala index 9c28734..d4b20c4 100644 --- a/core/src/main/scala/app/softnetwork/payment/service/SoftPaymentAccountServiceEndpoints.scala +++ b/core/src/main/scala/app/softnetwork/payment/service/SoftPaymentAccountServiceEndpoints.scala @@ -4,19 +4,19 @@ import app.softnetwork.account.service.BasicAccountServiceEndpoints import app.softnetwork.payment.handlers.SoftPaymentAccountTypeKey import app.softnetwork.payment.serialization.paymentFormats import app.softnetwork.session.config.Settings +import app.softnetwork.session.model.{SessionData, SessionDataDecorator} import app.softnetwork.session.service.SessionMaterials import com.softwaremill.session.SessionConfig import org.json4s.Formats -import org.softnetwork.session.model.JwtClaims import sttp.capabilities import sttp.capabilities.akka.AkkaStreams import sttp.tapir.server.ServerEndpoint import scala.concurrent.Future -trait SoftPaymentAccountServiceEndpoints - extends BasicAccountServiceEndpoints[JwtClaims] - with SoftPaymentAccountTypeKey { _: SessionMaterials[JwtClaims] => +trait SoftPaymentAccountServiceEndpoints[SD <: SessionData with SessionDataDecorator[SD]] + extends BasicAccountServiceEndpoints[SD] + with SoftPaymentAccountTypeKey { _: SessionMaterials[SD] => implicit def sessionConfig: SessionConfig = Settings.Session.DefaultSessionConfig diff --git a/core/src/main/scala/app/softnetwork/payment/service/SoftPaymentOAuthService.scala b/core/src/main/scala/app/softnetwork/payment/service/SoftPaymentOAuthService.scala index 52d68f3..cd9a138 100644 --- a/core/src/main/scala/app/softnetwork/payment/service/SoftPaymentOAuthService.scala +++ b/core/src/main/scala/app/softnetwork/payment/service/SoftPaymentOAuthService.scala @@ -15,16 +15,16 @@ import app.softnetwork.payment.handlers.SoftPaymentAccountTypeKey import app.softnetwork.payment.message.AccountMessages.{GenerateClientToken, RefreshClientToken} import app.softnetwork.payment.serialization.paymentFormats import app.softnetwork.session.config.Settings +import app.softnetwork.session.model.{SessionData, SessionDataDecorator} import app.softnetwork.session.service.SessionMaterials import com.softwaremill.session.SessionConfig import org.json4s.Formats -import org.softnetwork.session.model.JwtClaims -trait SoftPaymentOAuthService - extends OAuthService[JwtClaims] +trait SoftPaymentOAuthService[SD <: SessionData with SessionDataDecorator[SD]] + extends OAuthService[SD] with SoftPaymentAccountTypeKey - with ClientSessionDirectives { - _: SessionMaterials[JwtClaims] => + with ClientSessionDirectives[SD] { + _: SessionMaterials[SD] => implicit def sessionConfig: SessionConfig = Settings.Session.DefaultSessionConfig @@ -105,7 +105,7 @@ trait SoftPaymentOAuthService .result() ) { authenticateOAuth2Async(AccountSettings.Realm, oauthClient) { client => - setSession(sc(clientSessionManager(client)), st, client.asInstanceOf[JwtClaims]) { + setSession(sc(clientSessionManager(client)), st, client.asInstanceOf[SD]) { complete(StatusCodes.OK) } } diff --git a/core/src/main/scala/app/softnetwork/payment/service/SoftPaymentOAuthServiceEndpoints.scala b/core/src/main/scala/app/softnetwork/payment/service/SoftPaymentOAuthServiceEndpoints.scala index 8c02e4a..ec08761 100644 --- a/core/src/main/scala/app/softnetwork/payment/service/SoftPaymentOAuthServiceEndpoints.scala +++ b/core/src/main/scala/app/softnetwork/payment/service/SoftPaymentOAuthServiceEndpoints.scala @@ -21,10 +21,10 @@ import app.softnetwork.payment.message.AccountMessages.{ import app.softnetwork.payment.serialization.paymentFormats import app.softnetwork.session.config.Settings import app.softnetwork.session.httpCookieToTapirCookieWithMeta +import app.softnetwork.session.model.{SessionData, SessionDataDecorator} import app.softnetwork.session.service.SessionMaterials import com.softwaremill.session.{CookieST, HeaderST, SessionConfig} import org.json4s.Formats -import org.softnetwork.session.model.JwtClaims import sttp.capabilities import sttp.capabilities.akka.AkkaStreams import sttp.model.headers.WWWAuthenticateChallenge @@ -34,10 +34,10 @@ import sttp.tapir.server.ServerEndpoint import scala.concurrent.Future -trait SoftPaymentOAuthServiceEndpoints - extends OAuthServiceEndpoints[JwtClaims] +trait SoftPaymentOAuthServiceEndpoints[SD <: SessionData with SessionDataDecorator[SD]] + extends OAuthServiceEndpoints[SD] with SoftPaymentAccountTypeKey - with ClientSession { _: SessionMaterials[JwtClaims] => + with ClientSession[SD] { _: SessionMaterials[SD] => import app.softnetwork.serialization.serialization diff --git a/core/src/main/scala/app/softnetwork/payment/service/UboDeclarationEndpoints.scala b/core/src/main/scala/app/softnetwork/payment/service/UboDeclarationEndpoints.scala index f305813..6c3d2cf 100644 --- a/core/src/main/scala/app/softnetwork/payment/service/UboDeclarationEndpoints.scala +++ b/core/src/main/scala/app/softnetwork/payment/service/UboDeclarationEndpoints.scala @@ -4,6 +4,7 @@ import app.softnetwork.payment.config.PaymentSettings import app.softnetwork.payment.handlers.GenericPaymentHandler import app.softnetwork.payment.message.PaymentMessages._ import app.softnetwork.payment.model.{UboDeclaration, UboDeclarationView} +import app.softnetwork.session.model.{SessionData, SessionDataDecorator} import sttp.capabilities import sttp.capabilities.akka.AkkaStreams import sttp.model.StatusCode @@ -12,7 +13,8 @@ import sttp.tapir.server.ServerEndpoint import scala.concurrent.Future -trait UboDeclarationEndpoints { _: RootPaymentEndpoints with GenericPaymentHandler => +trait UboDeclarationEndpoints[SD <: SessionData with SessionDataDecorator[SD]] { + _: RootPaymentEndpoints[SD] with GenericPaymentHandler => import app.softnetwork.serialization._ diff --git a/mangopay/api/src/main/resources/reference.conf b/mangopay/api/src/main/resources/reference.conf index b1319a4..4e7797c 100644 --- a/mangopay/api/src/main/resources/reference.conf +++ b/mangopay/api/src/main/resources/reference.conf @@ -1,11 +1,10 @@ include "softnetwork-jdbc-persistence.conf" include "softnetwork-scheduler.conf" -softnetwork.api.name = "softnetwork-mangopay" +softnetwork.api.name = "softpayment" softnetwork.api.version = "0.5.0" -softnetwork.api.server.port = 9000 softnetwork.api.server.request-timeout = 120 s -softnetwork.api.server.swagger-path-prefix = ["swagger", "payment"] +softnetwork.api.server.swagger-path-prefix = ["swagger", "api"] akka.cluster.roles = [ ${payment.akka-node-role}, diff --git a/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayApi.scala b/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayApi.scala index 3a6ff86..fd9483c 100644 --- a/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayApi.scala +++ b/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayApi.scala @@ -2,11 +2,13 @@ package app.softnetwork.payment.api import akka.actor.typed.ActorSystem import akka.http.scaladsl.model.{HttpRequest, HttpResponse} +import app.softnetwork.account.config.AccountSettings import app.softnetwork.account.handlers.AccountDao import app.softnetwork.account.model.BasicAccountProfile import app.softnetwork.account.persistence.query.AccountEventProcessorStreams.InternalAccountEvents2AccountProcessorStream import app.softnetwork.account.persistence.typed.AccountBehavior import app.softnetwork.api.server.SwaggerEndpoint +import app.softnetwork.payment.config.PaymentSettings import app.softnetwork.payment.handlers.{ MangoPayPaymentHandler, SoftPaymentAccountDao, @@ -23,22 +25,33 @@ import app.softnetwork.payment.persistence.typed.{ MangoPayPaymentBehavior, SoftPaymentAccountBehavior } -import app.softnetwork.payment.service.MangoPayPaymentEndpoints +import app.softnetwork.payment.service.{ + MangoPayPaymentEndpoints, + SoftPaymentAccountServiceEndpoints, + SoftPaymentOAuthServiceEndpoints +} import app.softnetwork.persistence.jdbc.query.{JdbcJournalProvider, JdbcOffsetProvider} import app.softnetwork.persistence.schema.SchemaProvider import app.softnetwork.scheduler.config.SchedulerSettings import app.softnetwork.session.CsrfCheck import app.softnetwork.session.config.Settings -import app.softnetwork.session.model.SessionManagers +import app.softnetwork.session.model.{ + SessionData, + SessionDataCompanion, + SessionDataDecorator, + SessionManagers +} import app.softnetwork.session.service.SessionMaterials -import com.softwaremill.session.{SessionConfig, SessionManager} +import com.softwaremill.session.{RefreshTokenStorage, SessionConfig, SessionManager} import com.typesafe.config.Config import org.slf4j.{Logger, LoggerFactory} import org.softnetwork.session.model.Session +import sttp.tapir.swagger.SwaggerUIOptions import scala.concurrent.{ExecutionContext, Future} -trait MangoPayApi extends PaymentApplication { self: SchemaProvider with CsrfCheck => +trait MangoPayApi[SD <: SessionData with SessionDataDecorator[SD]] extends PaymentApplication { + self: SchemaProvider with CsrfCheck => override def paymentAccountBehavior: ActorSystem[_] => GenericPaymentBehavior = _ => MangoPayPaymentBehavior @@ -88,24 +101,73 @@ trait MangoPayApi extends PaymentApplication { self: SchemaProvider with CsrfChe PaymentServiceApiHandler.partial(MangoPayServer(system))(system) ) - def sessionConfig: SessionConfig = Settings.Session.DefaultSessionConfig + implicit def sessionConfig: SessionConfig = Settings.Session.DefaultSessionConfig + + implicit def companion: SessionDataCompanion[SD] + + protected def manager: SessionManager[SD] = SessionManagers.basic + + protected def refreshTokenStorage: ActorSystem[_] => RefreshTokenStorage[SD] override protected def sessionType: Session.SessionType = Settings.Session.SessionContinuityAndTransport - override protected def manager(implicit sessionConfig: SessionConfig): SessionManager[Session] = - SessionManagers.basic - def paymentSwagger: ActorSystem[_] => SwaggerEndpoint = sys => - new MangoPayPaymentEndpoints with SwaggerEndpoint with SessionMaterials { + new MangoPayPaymentEndpoints[SD] with SwaggerEndpoint with SessionMaterials[SD] { override implicit def manager(implicit - sessionConfig: SessionConfig - ): SessionManager[Session] = self.manager + sessionConfig: SessionConfig, + companion: SessionDataCompanion[SD] + ): SessionManager[SD] = self.manager override protected def sessionType: Session.SessionType = self.sessionType override def log: Logger = LoggerFactory getLogger getClass.getName override implicit def sessionConfig: SessionConfig = self.sessionConfig override implicit def system: ActorSystem[_] = sys override lazy val ec: ExecutionContext = sys.executionContext + override implicit def refreshTokenStorage: RefreshTokenStorage[SD] = + self.refreshTokenStorage(sys) + override implicit def companion: SessionDataCompanion[SD] = self.companion override val applicationVersion: String = systemVersion() + override val swaggerUIOptions: SwaggerUIOptions = + SwaggerUIOptions.default.pathPrefix(List("swagger", PaymentSettings.PaymentPath)) } + + def accountSwagger: ActorSystem[_] => SwaggerEndpoint = sys => + new SoftPaymentAccountServiceEndpoints[SD] with SwaggerEndpoint with SessionMaterials[SD] { + lazy val log: Logger = LoggerFactory getLogger getClass.getName + override implicit def system: ActorSystem[_] = sys + override implicit lazy val ec: ExecutionContext = sys.executionContext + override protected def sessionType: Session.SessionType = self.sessionType + override implicit def sessionConfig: SessionConfig = self.sessionConfig + override implicit def manager(implicit + sessionConfig: SessionConfig, + companion: SessionDataCompanion[SD] + ): SessionManager[SD] = self.manager + override protected val manifestWrapper: ManifestW = ManifestW() + override implicit def refreshTokenStorage: RefreshTokenStorage[SD] = + self.refreshTokenStorage(sys) + override implicit def companion: SessionDataCompanion[SD] = self.companion + override val applicationVersion: String = self.systemVersion() + override val swaggerUIOptions: SwaggerUIOptions = + SwaggerUIOptions.default.pathPrefix(List("swagger", AccountSettings.Path)) + } + + def oauthSwagger: ActorSystem[_] => SwaggerEndpoint = + sys => + new SoftPaymentOAuthServiceEndpoints[SD] with SwaggerEndpoint with SessionMaterials[SD] { + override implicit def system: ActorSystem[_] = sys + override implicit lazy val ec: ExecutionContext = sys.executionContext + override protected def sessionType: Session.SessionType = self.sessionType + override implicit def sessionConfig: SessionConfig = self.sessionConfig + override implicit def manager(implicit + sessionConfig: SessionConfig, + companion: SessionDataCompanion[SD] + ): SessionManager[SD] = self.manager + override def log: Logger = LoggerFactory getLogger getClass.getName + override implicit def refreshTokenStorage: RefreshTokenStorage[SD] = + self.refreshTokenStorage(sys) + override implicit def companion: SessionDataCompanion[SD] = self.companion + override val applicationVersion: String = self.systemVersion() + override val swaggerUIOptions: SwaggerUIOptions = + SwaggerUIOptions.default.pathPrefix(List("swagger", AccountSettings.OAuthPath)) + } } diff --git a/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayEndpoints.scala b/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayEndpoints.scala index 4e4fe3d..e049705 100644 --- a/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayEndpoints.scala +++ b/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayEndpoints.scala @@ -13,52 +13,69 @@ import app.softnetwork.payment.service.{ } import app.softnetwork.persistence.schema.SchemaProvider import app.softnetwork.session.CsrfCheck +import app.softnetwork.session.model.{SessionData, SessionDataCompanion, SessionDataDecorator} import app.softnetwork.session.service.SessionMaterials -import com.softwaremill.session.{SessionConfig, SessionManager} +import com.softwaremill.session.{RefreshTokenStorage, SessionConfig, SessionManager} import org.softnetwork.session.model.Session import scala.concurrent.ExecutionContext -trait MangoPayEndpoints extends PaymentEndpoints { - self: MangoPayApi with SchemaProvider with CsrfCheck => - override def paymentEndpoints: ActorSystem[_] => GenericPaymentEndpoints = sys => - new MangoPayPaymentEndpoints with SessionMaterials { +trait MangoPayEndpoints[SD <: SessionData with SessionDataDecorator[SD]] + extends PaymentEndpoints[SD] { + self: MangoPayApi[SD] with SchemaProvider with CsrfCheck => + + override def paymentEndpoints: ActorSystem[_] => GenericPaymentEndpoints[SD] = sys => + new MangoPayPaymentEndpoints[SD] with SessionMaterials[SD] { override def log: org.slf4j.Logger = org.slf4j.LoggerFactory.getLogger(getClass) override implicit def system: ActorSystem[_] = sys override lazy val ec: ExecutionContext = sys.executionContext override implicit def manager(implicit - sessionConfig: SessionConfig - ): SessionManager[Session] = self.manager + sessionConfig: SessionConfig, + companion: SessionDataCompanion[SD] + ): SessionManager[SD] = self.manager override protected def sessionType: Session.SessionType = self.sessionType override implicit def sessionConfig: SessionConfig = self.sessionConfig + override implicit def refreshTokenStorage: RefreshTokenStorage[SD] = + self.refreshTokenStorage(sys) + override implicit def companion: SessionDataCompanion[SD] = self.companion } override def accountEndpoints - : ActorSystem[_] => AccountServiceEndpoints[message.BasicAccountSignUp] = sys => - new SoftPaymentAccountServiceEndpoints with SessionMaterials { + : ActorSystem[_] => AccountServiceEndpoints[message.BasicAccountSignUp, SD] = sys => + new SoftPaymentAccountServiceEndpoints[SD] with SessionMaterials[SD] { override def log: org.slf4j.Logger = org.slf4j.LoggerFactory.getLogger(getClass) override implicit def system: ActorSystem[_] = sys override lazy val ec: ExecutionContext = sys.executionContext override implicit def manager(implicit - sessionConfig: SessionConfig - ): SessionManager[Session] = self.manager + sessionConfig: SessionConfig, + companion: SessionDataCompanion[SD] + ): SessionManager[SD] = self.manager override protected def sessionType: Session.SessionType = self.sessionType -// override implicit def sessionConfig: SessionConfig = self.sessionConfig + override implicit def sessionConfig: SessionConfig = self.sessionConfig override protected val manifestWrapper: ManifestW = ManifestW() + override implicit def refreshTokenStorage: RefreshTokenStorage[SD] = + self.refreshTokenStorage(sys) + override implicit def companion: SessionDataCompanion[SD] = self.companion } - override def oauthEndpoints: ActorSystem[_] => OAuthServiceEndpoints = sys => - new SoftPaymentOAuthServiceEndpoints with SessionMaterials { + override def oauthEndpoints: ActorSystem[_] => OAuthServiceEndpoints[SD] = sys => + new SoftPaymentOAuthServiceEndpoints[SD] with SessionMaterials[SD] { override def log: org.slf4j.Logger = org.slf4j.LoggerFactory.getLogger(getClass) override implicit def system: ActorSystem[_] = sys override lazy val ec: ExecutionContext = sys.executionContext override implicit def manager(implicit - sessionConfig: SessionConfig - ): SessionManager[Session] = self.manager + sessionConfig: SessionConfig, + companion: SessionDataCompanion[SD] + ): SessionManager[SD] = self.manager override protected def sessionType: Session.SessionType = self.sessionType -// override implicit def sessionConfig: SessionConfig = self.sessionConfig + override implicit def sessionConfig: SessionConfig = self.sessionConfig + override implicit def refreshTokenStorage: RefreshTokenStorage[SD] = + self.refreshTokenStorage(sys) + override implicit def companion: SessionDataCompanion[SD] = self.companion } override def endpoints: ActorSystem[_] => List[Endpoint] = system => - super.endpoints(system) :+ paymentSwagger(system) + super.endpoints(system) :+ paymentSwagger(system) :+ accountSwagger(system) :+ oauthSwagger( + system + ) } diff --git a/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayEndpointsApi.scala b/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayEndpointsApi.scala index a1ea704..b3ad203 100644 --- a/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayEndpointsApi.scala +++ b/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayEndpointsApi.scala @@ -2,8 +2,11 @@ package app.softnetwork.payment.api import app.softnetwork.persistence.schema.SchemaProvider import app.softnetwork.session.CsrfCheck +import app.softnetwork.session.model.{SessionData, SessionDataDecorator} -trait MangoPayEndpointsApi extends MangoPayApi with MangoPayEndpoints { +trait MangoPayEndpointsApi[SD <: SessionData with SessionDataDecorator[SD]] + extends MangoPayApi[SD] + with MangoPayEndpoints[SD] { _: SchemaProvider with CsrfCheck => } diff --git a/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayEndpointsPostgresLauncher.scala b/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayEndpointsPostgresLauncher.scala index 5f446fc..3d78507 100644 --- a/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayEndpointsPostgresLauncher.scala +++ b/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayEndpointsPostgresLauncher.scala @@ -1,17 +1,45 @@ package app.softnetwork.payment.api +import akka.actor.typed.ActorSystem +import app.softnetwork.payment.handlers.SoftPaymentAccountDao +import app.softnetwork.payment.service.{GenericPaymentEndpoints, MangoPayPaymentEndpoints} import app.softnetwork.persistence.jdbc.schema.{JdbcSchemaProvider, JdbcSchemaTypes} import app.softnetwork.persistence.schema.SchemaType import app.softnetwork.session.CsrfCheckHeader +import app.softnetwork.session.handlers.JwtClaimsRefreshTokenDao +import app.softnetwork.session.model.{SessionDataCompanion, SessionManagers} +import app.softnetwork.session.service.JwtClaimsSessionMaterials +import com.softwaremill.session.{RefreshTokenStorage, SessionConfig, SessionManager} import org.slf4j.{Logger, LoggerFactory} +import org.softnetwork.session.model.{ApiKey, JwtClaims, Session} + +import scala.concurrent.{ExecutionContext, Future} object MangoPayEndpointsPostgresLauncher - extends MangoPayEndpointsApi + extends MangoPayEndpointsApi[JwtClaims] with JdbcSchemaProvider - with CsrfCheckHeader { + with CsrfCheckHeader { self => lazy val log: Logger = LoggerFactory getLogger getClass.getName override def schemaType: SchemaType = JdbcSchemaTypes.Postgres + override implicit def companion: SessionDataCompanion[JwtClaims] = JwtClaims + + override protected def refreshTokenStorage: ActorSystem[_] => RefreshTokenStorage[JwtClaims] = + sys => JwtClaimsRefreshTokenDao(sys) + + override protected def manager: SessionManager[JwtClaims] = SessionManagers.jwt + + override def paymentEndpoints: ActorSystem[_] => GenericPaymentEndpoints[JwtClaims] = sys => + new MangoPayPaymentEndpoints[JwtClaims] with JwtClaimsSessionMaterials { + override implicit def system: ActorSystem[_] = sys + override implicit lazy val ec: ExecutionContext = sys.executionContext + override implicit def sessionConfig: SessionConfig = self.sessionConfig + override def log: Logger = LoggerFactory getLogger getClass.getName + override implicit def refreshTokenStorage: RefreshTokenStorage[JwtClaims] = + self.refreshTokenStorage(sys) + override implicit def companion: SessionDataCompanion[JwtClaims] = self.companion + override protected def sessionType: Session.SessionType = self.sessionType + } } diff --git a/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayRoutes.scala b/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayRoutes.scala index ff8d9d7..295c2a1 100644 --- a/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayRoutes.scala +++ b/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayRoutes.scala @@ -17,54 +17,71 @@ import app.softnetwork.payment.service.{ } import app.softnetwork.persistence.schema.SchemaProvider import app.softnetwork.session.CsrfCheck +import app.softnetwork.session.model.{SessionData, SessionDataCompanion, SessionDataDecorator} import app.softnetwork.session.service.SessionMaterials -import com.softwaremill.session.{SessionConfig, SessionManager} +import com.softwaremill.session.{RefreshTokenStorage, SessionConfig, SessionManager} import org.slf4j.{Logger, LoggerFactory} import org.softnetwork.session.model.Session import scala.concurrent.ExecutionContext -trait MangoPayRoutes extends PaymentRoutes { self: MangoPayApi with SchemaProvider with CsrfCheck => +trait MangoPayRoutes[SD <: SessionData with SessionDataDecorator[SD]] extends PaymentRoutes[SD] { + self: MangoPayApi[SD] with SchemaProvider with CsrfCheck => - override def paymentService: ActorSystem[_] => GenericPaymentService = sys => - new MangoPayPaymentService with SessionMaterials { + override def paymentService: ActorSystem[_] => GenericPaymentService[SD] = sys => + new MangoPayPaymentService[SD] with SessionMaterials[SD] { override implicit def manager(implicit - sessionConfig: SessionConfig - ): SessionManager[Session] = self.manager + sessionConfig: SessionConfig, + companion: SessionDataCompanion[SD] + ): SessionManager[SD] = self.manager override protected def sessionType: Session.SessionType = self.sessionType override def log: Logger = LoggerFactory getLogger getClass.getName override implicit def sessionConfig: SessionConfig = self.sessionConfig override implicit def system: ActorSystem[_] = sys override lazy val ec: ExecutionContext = sys.executionContext + override implicit def refreshTokenStorage: RefreshTokenStorage[SD] = + self.refreshTokenStorage(sys) + override implicit def companion: SessionDataCompanion[SD] = self.companion } override def accountService: ActorSystem[_] => AccountService[ DefaultProfileView, DefaultAccountDetailsView, - DefaultAccountView[DefaultProfileView, DefaultAccountDetailsView] + DefaultAccountView[DefaultProfileView, DefaultAccountDetailsView], + SD ] = sys => - new SoftPaymentAccountService with SessionMaterials { + new SoftPaymentAccountService[SD] with SessionMaterials[SD] { override implicit def manager(implicit - sessionConfig: SessionConfig - ): SessionManager[Session] = self.manager + sessionConfig: SessionConfig, + companion: SessionDataCompanion[SD] + ): SessionManager[SD] = self.manager override protected def sessionType: Session.SessionType = self.sessionType override def log: Logger = LoggerFactory getLogger getClass.getName override implicit def system: ActorSystem[_] = sys override lazy val ec: ExecutionContext = sys.executionContext override protected val manifestWrapper: ManifestW = ManifestW() + override implicit def refreshTokenStorage: RefreshTokenStorage[SD] = + self.refreshTokenStorage(sys) + override implicit def companion: SessionDataCompanion[SD] = self.companion } - override def oauthService: ActorSystem[_] => OAuthService = sys => - new SoftPaymentOAuthService with SessionMaterials { + override def oauthService: ActorSystem[_] => OAuthService[SD] = sys => + new SoftPaymentOAuthService[SD] with SessionMaterials[SD] { override implicit def manager(implicit - sessionConfig: SessionConfig - ): SessionManager[Session] = self.manager + sessionConfig: SessionConfig, + companion: SessionDataCompanion[SD] + ): SessionManager[SD] = self.manager override protected def sessionType: Session.SessionType = self.sessionType override def log: Logger = LoggerFactory getLogger getClass.getName override implicit def system: ActorSystem[_] = sys override lazy val ec: ExecutionContext = sys.executionContext + override implicit def refreshTokenStorage: RefreshTokenStorage[SD] = + self.refreshTokenStorage(sys) + override implicit def companion: SessionDataCompanion[SD] = self.companion } override def apiRoutes: ActorSystem[_] => List[ApiRoute] = system => - super.apiRoutes(system) :+ paymentSwagger(system) + super.apiRoutes(system) :+ paymentSwagger(system) :+ accountSwagger(system) :+ oauthSwagger( + system + ) } diff --git a/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayRoutesApi.scala b/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayRoutesApi.scala index bd58cfc..44f5a62 100644 --- a/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayRoutesApi.scala +++ b/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayRoutesApi.scala @@ -2,7 +2,10 @@ package app.softnetwork.payment.api import app.softnetwork.persistence.schema.SchemaProvider import app.softnetwork.session.CsrfCheck +import app.softnetwork.session.model.{SessionData, SessionDataDecorator} -trait MangoPayRoutesApi extends MangoPayApi with MangoPayRoutes { +trait MangoPayRoutesApi[SD <: SessionData with SessionDataDecorator[SD]] + extends MangoPayApi[SD] + with MangoPayRoutes[SD] { _: SchemaProvider with CsrfCheck => } diff --git a/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayRoutesPostgresLauncher.scala b/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayRoutesPostgresLauncher.scala index cb2bc1d..4a9f034 100644 --- a/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayRoutesPostgresLauncher.scala +++ b/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayRoutesPostgresLauncher.scala @@ -1,16 +1,43 @@ package app.softnetwork.payment.api +import akka.actor.typed.ActorSystem +import app.softnetwork.payment.service.{GenericPaymentService, MangoPayPaymentService} import app.softnetwork.persistence.jdbc.schema.{JdbcSchemaProvider, JdbcSchemaTypes} import app.softnetwork.persistence.schema.SchemaType import app.softnetwork.session.CsrfCheckHeader +import app.softnetwork.session.handlers.JwtClaimsRefreshTokenDao +import app.softnetwork.session.model.{SessionDataCompanion, SessionManagers} +import app.softnetwork.session.service.JwtClaimsSessionMaterials +import com.softwaremill.session.{RefreshTokenStorage, SessionConfig, SessionManager} import org.slf4j.{Logger, LoggerFactory} +import org.softnetwork.session.model.{JwtClaims, Session} + +import scala.concurrent.ExecutionContext object MangoPayRoutesPostgresLauncher - extends MangoPayRoutesApi + extends MangoPayRoutesApi[JwtClaims] with JdbcSchemaProvider - with CsrfCheckHeader { + with CsrfCheckHeader { self => lazy val log: Logger = LoggerFactory getLogger getClass.getName override def schemaType: SchemaType = JdbcSchemaTypes.Postgres + override implicit def companion: SessionDataCompanion[JwtClaims] = JwtClaims + + override protected def refreshTokenStorage: ActorSystem[_] => RefreshTokenStorage[JwtClaims] = + sys => JwtClaimsRefreshTokenDao(sys) + + override protected def manager: SessionManager[JwtClaims] = SessionManagers.jwt + + override def paymentService: ActorSystem[_] => GenericPaymentService[JwtClaims] = sys => + new MangoPayPaymentService[JwtClaims] with JwtClaimsSessionMaterials { + override implicit def system: ActorSystem[_] = sys + override implicit lazy val ec: ExecutionContext = sys.executionContext + override implicit def sessionConfig: SessionConfig = self.sessionConfig + override def log: Logger = LoggerFactory getLogger getClass.getName + override implicit def refreshTokenStorage: RefreshTokenStorage[JwtClaims] = + self.refreshTokenStorage(sys) + override implicit def companion: SessionDataCompanion[JwtClaims] = self.companion + override protected def sessionType: Session.SessionType = self.sessionType + } } diff --git a/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayWithSchedulerApi.scala b/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayWithSchedulerApi.scala index 10e8059..a74e080 100644 --- a/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayWithSchedulerApi.scala +++ b/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayWithSchedulerApi.scala @@ -9,11 +9,14 @@ import app.softnetwork.persistence.schema.SchemaProvider import app.softnetwork.scheduler.api.{SchedulerApi, SchedulerServiceApiHandler} import app.softnetwork.scheduler.handlers.SchedulerHandler import app.softnetwork.scheduler.persistence.query.Entity2SchedulerProcessorStream +import app.softnetwork.session.model.{SessionData, SessionDataDecorator} import com.typesafe.config.Config import scala.concurrent.Future -trait MangoPayWithSchedulerApi extends MangoPayApi with SchedulerApi { _: SchemaProvider => +trait MangoPayWithSchedulerApi[SD <: SessionData with SessionDataDecorator[SD]] + extends MangoPayApi[SD] + with SchedulerApi { _: SchemaProvider => override def entity2SchedulerProcessorStream: ActorSystem[_] => Entity2SchedulerProcessorStream = sys => diff --git a/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayWithSchedulerEndpoints.scala b/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayWithSchedulerEndpoints.scala index 86c4665..7de1873 100644 --- a/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayWithSchedulerEndpoints.scala +++ b/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayWithSchedulerEndpoints.scala @@ -1,14 +1,44 @@ package app.softnetwork.payment.api import akka.actor.typed.ActorSystem -import app.softnetwork.api.server.Endpoint +import app.softnetwork.api.server.{Endpoint, SwaggerApiEndpoint} import app.softnetwork.persistence.schema.SchemaProvider +import app.softnetwork.scheduler.config.SchedulerSettings import app.softnetwork.scheduler.launch.SchedulerEndpoints +import app.softnetwork.scheduler.service.SchedulerServiceEndpoints import app.softnetwork.session.CsrfCheck +import app.softnetwork.session.model.{SessionData, SessionDataCompanion, SessionDataDecorator} +import app.softnetwork.session.service.SessionMaterials +import com.softwaremill.session.{RefreshTokenStorage, SessionConfig, SessionManager} +import org.slf4j.{Logger, LoggerFactory} +import org.softnetwork.session.model.Session +import sttp.tapir.swagger.SwaggerUIOptions -trait MangoPayWithSchedulerEndpoints extends SchedulerEndpoints with MangoPayEndpoints { - _: MangoPayWithSchedulerApi with SchemaProvider with CsrfCheck => +import scala.concurrent.ExecutionContext + +trait MangoPayWithSchedulerEndpoints[SD <: SessionData with SessionDataDecorator[SD]] + extends SchedulerEndpoints[SD] + with MangoPayEndpoints[SD] { + self: MangoPayWithSchedulerApi[SD] with SchemaProvider with CsrfCheck => + + override def schedulerEndpoints: ActorSystem[_] => SchedulerServiceEndpoints[SD] = sys => + new SchedulerServiceEndpoints[SD] with SwaggerApiEndpoint with SessionMaterials[SD] { + override implicit def system: ActorSystem[_] = sys + override lazy val ec: ExecutionContext = sys.executionContext + override implicit def manager(implicit + sessionConfig: SessionConfig, + companion: SessionDataCompanion[SD] + ): SessionManager[SD] = self.manager + lazy val log: Logger = LoggerFactory getLogger getClass.getName + override protected def sessionType: Session.SessionType = self.sessionType + override implicit def refreshTokenStorage: RefreshTokenStorage[SD] = + self.refreshTokenStorage(sys) + override implicit def companion: SessionDataCompanion[SD] = self.companion + override val applicationVersion: String = systemVersion() + override val swaggerUIOptions: SwaggerUIOptions = + SwaggerUIOptions.default.pathPrefix(List("swagger", SchedulerSettings.SchedulerPath)) + } override def endpoints: ActorSystem[_] => List[Endpoint] = system => - super.endpoints(system) :+ schedulerEndpoints(system) :+ schedulerSwagger(system) + super.endpoints(system) :+ schedulerEndpoints(system) } diff --git a/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayWithSchedulerEndpointsApi.scala b/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayWithSchedulerEndpointsApi.scala index f254567..ca5794c 100644 --- a/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayWithSchedulerEndpointsApi.scala +++ b/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayWithSchedulerEndpointsApi.scala @@ -2,7 +2,8 @@ package app.softnetwork.payment.api import app.softnetwork.persistence.schema.SchemaProvider import app.softnetwork.session.CsrfCheck +import app.softnetwork.session.model.{SessionData, SessionDataDecorator} -trait MangoPayWithSchedulerEndpointsApi - extends MangoPayWithSchedulerApi - with MangoPayWithSchedulerEndpoints { _: SchemaProvider with CsrfCheck => } +trait MangoPayWithSchedulerEndpointsApi[SD <: SessionData with SessionDataDecorator[SD]] + extends MangoPayWithSchedulerApi[SD] + with MangoPayWithSchedulerEndpoints[SD] { _: SchemaProvider with CsrfCheck => } diff --git a/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayWithSchedulerEndpointsPostgresLauncher.scala b/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayWithSchedulerEndpointsPostgresLauncher.scala index 6c8bca7..ec1e915 100644 --- a/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayWithSchedulerEndpointsPostgresLauncher.scala +++ b/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayWithSchedulerEndpointsPostgresLauncher.scala @@ -1,17 +1,45 @@ package app.softnetwork.payment.api +import akka.actor.typed.ActorSystem +import app.softnetwork.payment.handlers.SoftPaymentAccountDao +import app.softnetwork.payment.service.{GenericPaymentEndpoints, MangoPayPaymentEndpoints} import app.softnetwork.persistence.jdbc.schema.{JdbcSchemaProvider, JdbcSchemaTypes} import app.softnetwork.persistence.schema.SchemaType import app.softnetwork.session.CsrfCheckHeader +import app.softnetwork.session.handlers.JwtClaimsRefreshTokenDao +import app.softnetwork.session.model.{SessionDataCompanion, SessionManagers} +import app.softnetwork.session.service.JwtClaimsSessionMaterials +import com.softwaremill.session.{RefreshTokenStorage, SessionConfig, SessionManager} import org.slf4j.{Logger, LoggerFactory} +import org.softnetwork.session.model.{ApiKey, JwtClaims, Session} + +import scala.concurrent.{ExecutionContext, Future} object MangoPayWithSchedulerEndpointsPostgresLauncher - extends MangoPayWithSchedulerEndpointsApi + extends MangoPayWithSchedulerEndpointsApi[JwtClaims] with JdbcSchemaProvider - with CsrfCheckHeader { + with CsrfCheckHeader { self => lazy val log: Logger = LoggerFactory getLogger getClass.getName override def schemaType: SchemaType = JdbcSchemaTypes.Postgres + override implicit def companion: SessionDataCompanion[JwtClaims] = JwtClaims + + override protected def refreshTokenStorage: ActorSystem[_] => RefreshTokenStorage[JwtClaims] = + sys => JwtClaimsRefreshTokenDao(sys) + + override protected def manager: SessionManager[JwtClaims] = SessionManagers.jwt + + override def paymentEndpoints: ActorSystem[_] => GenericPaymentEndpoints[JwtClaims] = sys => + new MangoPayPaymentEndpoints[JwtClaims] with JwtClaimsSessionMaterials { + override implicit def system: ActorSystem[_] = sys + override implicit lazy val ec: ExecutionContext = sys.executionContext + override implicit def sessionConfig: SessionConfig = self.sessionConfig + override def log: Logger = LoggerFactory getLogger getClass.getName + override implicit def refreshTokenStorage: RefreshTokenStorage[JwtClaims] = + self.refreshTokenStorage(sys) + override implicit def companion: SessionDataCompanion[JwtClaims] = self.companion + override protected def sessionType: Session.SessionType = self.sessionType + } } diff --git a/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayWithSchedulerRoutes.scala b/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayWithSchedulerRoutes.scala index 6f96b05..0734eb2 100644 --- a/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayWithSchedulerRoutes.scala +++ b/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayWithSchedulerRoutes.scala @@ -1,12 +1,59 @@ package app.softnetwork.payment.api import akka.actor.typed.ActorSystem -import app.softnetwork.api.server.ApiRoute +import app.softnetwork.api.server.{ApiRoute, SwaggerEndpoint} import app.softnetwork.persistence.schema.SchemaProvider +import app.softnetwork.scheduler.config.SchedulerSettings import app.softnetwork.scheduler.launch.SchedulerRoutes +import app.softnetwork.scheduler.service.{SchedulerService, SchedulerServiceEndpoints} +import app.softnetwork.session.model.{SessionData, SessionDataCompanion, SessionDataDecorator} +import app.softnetwork.session.service.SessionMaterials +import com.softwaremill.session.{RefreshTokenStorage, SessionConfig, SessionManager} +import org.slf4j.{Logger, LoggerFactory} +import org.softnetwork.session.model.Session +import sttp.tapir.swagger.SwaggerUIOptions + +import scala.concurrent.ExecutionContext + +trait MangoPayWithSchedulerRoutes[SD <: SessionData with SessionDataDecorator[SD]] + extends SchedulerRoutes[SD] + with MangoPayRoutes[SD] { + self: MangoPayWithSchedulerApi[SD] with SchemaProvider => + + override def schedulerService: ActorSystem[_] => SchedulerService[SD] = sys => + new SchedulerService[SD] with SessionMaterials[SD] { + override implicit def system: ActorSystem[_] = sys + override lazy val ec: ExecutionContext = sys.executionContext + lazy val log: Logger = LoggerFactory getLogger getClass.getName + override protected def sessionType: Session.SessionType = self.sessionType + override implicit def refreshTokenStorage: RefreshTokenStorage[SD] = + self.refreshTokenStorage(sys) + override implicit def companion: SessionDataCompanion[SD] = self.companion + override implicit def manager(implicit + sessionConfig: SessionConfig, + companion: SessionDataCompanion[SD] + ): SessionManager[SD] = self.manager + } + + private def schedulerSwagger: ActorSystem[_] => SwaggerEndpoint = + sys => + new SchedulerServiceEndpoints[SD] with SwaggerEndpoint with SessionMaterials[SD] { + override implicit def system: ActorSystem[_] = sys + override lazy val ec: ExecutionContext = sys.executionContext + lazy val log: Logger = LoggerFactory getLogger getClass.getName + override protected def sessionType: Session.SessionType = self.sessionType + override implicit def refreshTokenStorage: RefreshTokenStorage[SD] = + self.refreshTokenStorage(sys) + override implicit def companion: SessionDataCompanion[SD] = self.companion + override implicit def manager(implicit + sessionConfig: SessionConfig, + companion: SessionDataCompanion[SD] + ): SessionManager[SD] = self.manager + override val applicationVersion: String = systemVersion() + override val swaggerUIOptions: SwaggerUIOptions = + SwaggerUIOptions.default.pathPrefix(List("swagger", SchedulerSettings.SchedulerPath)) + } -trait MangoPayWithSchedulerRoutes extends SchedulerRoutes with MangoPayRoutes { - _: MangoPayWithSchedulerApi with SchemaProvider => override def apiRoutes: ActorSystem[_] => List[ApiRoute] = system => super.apiRoutes(system) :+ schedulerService(system) :+ schedulerSwagger(system) } diff --git a/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayWithSchedulerRoutesApi.scala b/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayWithSchedulerRoutesApi.scala index 7acc945..c124e03 100644 --- a/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayWithSchedulerRoutesApi.scala +++ b/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayWithSchedulerRoutesApi.scala @@ -1,7 +1,8 @@ package app.softnetwork.payment.api import app.softnetwork.persistence.schema.SchemaProvider +import app.softnetwork.session.model.{SessionData, SessionDataDecorator} -trait MangoPayWithSchedulerRoutesApi - extends MangoPayWithSchedulerApi - with MangoPayWithSchedulerRoutes { _: SchemaProvider => } +trait MangoPayWithSchedulerRoutesApi[SD <: SessionData with SessionDataDecorator[SD]] + extends MangoPayWithSchedulerApi[SD] + with MangoPayWithSchedulerRoutes[SD] { _: SchemaProvider => } diff --git a/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayWithSchedulerRoutesPostgresLauncher.scala b/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayWithSchedulerRoutesPostgresLauncher.scala index 34c70e7..b53a131 100644 --- a/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayWithSchedulerRoutesPostgresLauncher.scala +++ b/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayWithSchedulerRoutesPostgresLauncher.scala @@ -1,14 +1,42 @@ package app.softnetwork.payment.api +import akka.actor.typed.ActorSystem +import app.softnetwork.payment.handlers.SoftPaymentAccountDao +import app.softnetwork.payment.service.{GenericPaymentService, MangoPayPaymentService} import app.softnetwork.persistence.jdbc.schema.{JdbcSchemaProvider, JdbcSchemaTypes} import app.softnetwork.persistence.schema.SchemaType +import app.softnetwork.session.handlers.JwtClaimsRefreshTokenDao +import app.softnetwork.session.model.{SessionDataCompanion, SessionManagers} +import app.softnetwork.session.service.JwtClaimsSessionMaterials +import com.softwaremill.session.{RefreshTokenStorage, SessionConfig, SessionManager} import org.slf4j.{Logger, LoggerFactory} +import org.softnetwork.session.model.{ApiKey, JwtClaims, Session} + +import scala.concurrent.{ExecutionContext, Future} object MangoPayWithSchedulerRoutesPostgresLauncher - extends MangoPayWithSchedulerRoutesApi - with JdbcSchemaProvider { + extends MangoPayWithSchedulerRoutesApi[JwtClaims] + with JdbcSchemaProvider { self => lazy val log: Logger = LoggerFactory getLogger getClass.getName override def schemaType: SchemaType = JdbcSchemaTypes.Postgres + override implicit def companion: SessionDataCompanion[JwtClaims] = JwtClaims + + override protected def refreshTokenStorage: ActorSystem[_] => RefreshTokenStorage[JwtClaims] = + sys => JwtClaimsRefreshTokenDao(sys) + + override protected def manager: SessionManager[JwtClaims] = SessionManagers.jwt + + override def paymentService: ActorSystem[_] => GenericPaymentService[JwtClaims] = sys => + new MangoPayPaymentService[JwtClaims] with JwtClaimsSessionMaterials { + override implicit def system: ActorSystem[_] = sys + override implicit lazy val ec: ExecutionContext = sys.executionContext + override implicit def sessionConfig: SessionConfig = self.sessionConfig + override def log: Logger = LoggerFactory getLogger getClass.getName + override implicit def refreshTokenStorage: RefreshTokenStorage[JwtClaims] = + self.refreshTokenStorage(sys) + override implicit def companion: SessionDataCompanion[JwtClaims] = self.companion + override protected def sessionType: Session.SessionType = self.sessionType + } } diff --git a/mangopay/src/main/resources/reference.conf b/mangopay/src/main/resources/reference.conf index 42da258..9c1552b 100644 --- a/mangopay/src/main/resources/reference.conf +++ b/mangopay/src/main/resources/reference.conf @@ -1,7 +1,4 @@ payment{ - path = "payment" - path = ${?PAYMENT_PATH} - mangopay { version = "2.01" client-id = "softpaymentdev" diff --git a/mangopay/src/main/scala/app/softnetwork/payment/service/MangoPayPaymentEndpoints.scala b/mangopay/src/main/scala/app/softnetwork/payment/service/MangoPayPaymentEndpoints.scala index b66b85d..9679e16 100644 --- a/mangopay/src/main/scala/app/softnetwork/payment/service/MangoPayPaymentEndpoints.scala +++ b/mangopay/src/main/scala/app/softnetwork/payment/service/MangoPayPaymentEndpoints.scala @@ -4,15 +4,17 @@ import app.softnetwork.payment.config.PaymentSettings import app.softnetwork.payment.handlers.MangoPayPaymentHandler import app.softnetwork.payment.message.PaymentMessages._ import app.softnetwork.payment.model.{BankAccount, KycDocument, UboDeclaration} +import app.softnetwork.session.model.{SessionData, SessionDataDecorator} import app.softnetwork.session.service.SessionMaterials import com.mangopay.core.enumerations.EventType -import org.softnetwork.session.model.JwtClaims import sttp.tapir.server.ServerEndpoint.Full import scala.concurrent.Future -trait MangoPayPaymentEndpoints extends GenericPaymentEndpoints with MangoPayPaymentHandler { - _: SessionMaterials[JwtClaims] => +trait MangoPayPaymentEndpoints[SD <: SessionData with SessionDataDecorator[SD]] + extends GenericPaymentEndpoints[SD] + with MangoPayPaymentHandler { + _: SessionMaterials[SD] => /** should be implemented by each payment provider */ diff --git a/mangopay/src/main/scala/app/softnetwork/payment/service/MangoPayPaymentService.scala b/mangopay/src/main/scala/app/softnetwork/payment/service/MangoPayPaymentService.scala index e4e34ec..0766abf 100644 --- a/mangopay/src/main/scala/app/softnetwork/payment/service/MangoPayPaymentService.scala +++ b/mangopay/src/main/scala/app/softnetwork/payment/service/MangoPayPaymentService.scala @@ -18,12 +18,14 @@ import app.softnetwork.payment.message.PaymentMessages.{ ValidateRegularUser } import app.softnetwork.payment.model.{BankAccount, KycDocument, UboDeclaration} +import app.softnetwork.session.model.{SessionData, SessionDataDecorator} import app.softnetwork.session.service.SessionMaterials import com.mangopay.core.enumerations.EventType -import org.softnetwork.session.model.JwtClaims -trait MangoPayPaymentService extends GenericPaymentService with MangoPayPaymentHandler { - _: SessionMaterials[JwtClaims] => +trait MangoPayPaymentService[SD <: SessionData with SessionDataDecorator[SD]] + extends GenericPaymentService[SD] + with MangoPayPaymentHandler { + _: SessionMaterials[SD] => def completeWithKycDocumentUpdatedResult( eventType: String, diff --git a/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentEndpointsTestKit.scala b/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentEndpointsTestKit.scala index 2b8a2d1..7c85c32 100644 --- a/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentEndpointsTestKit.scala +++ b/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentEndpointsTestKit.scala @@ -15,7 +15,7 @@ import app.softnetwork.payment.service.{ import app.softnetwork.persistence.schema.SchemaProvider import app.softnetwork.session.scalatest.{SessionEndpointsRoutes, SessionTestKit} import app.softnetwork.session.CsrfCheck -import app.softnetwork.session.model.SessionDataCompanion +import app.softnetwork.session.model.{SessionData, SessionDataCompanion, SessionDataDecorator} import app.softnetwork.session.service.SessionMaterials import com.softwaremill.session.{RefreshTokenStorage, SessionConfig, SessionManager} import org.slf4j.{Logger, LoggerFactory} @@ -23,65 +23,67 @@ import org.softnetwork.session.model.{JwtClaims, Session} import scala.concurrent.ExecutionContext -trait PaymentEndpointsTestKit extends PaymentEndpoints with SessionEndpointsRoutes[JwtClaims] { +trait PaymentEndpointsTestKit[SD <: SessionData with SessionDataDecorator[SD]] + extends PaymentEndpoints[SD] + with SessionEndpointsRoutes[SD] { self: PaymentTestKit - with SessionTestKit[JwtClaims] + with SessionTestKit[SD] with SchemaProvider with CsrfCheck - with SessionMaterials[JwtClaims] => + with SessionMaterials[SD] => implicit def sessionConfig: SessionConfig - override def paymentEndpoints: ActorSystem[_] => GenericPaymentEndpoints = sys => - new MockPaymentEndpoints with SessionMaterials[JwtClaims] { + override def paymentEndpoints: ActorSystem[_] => GenericPaymentEndpoints[SD] = sys => + new MockPaymentEndpoints[SD] with SessionMaterials[SD] { override implicit def manager(implicit sessionConfig: SessionConfig, - companion: SessionDataCompanion[JwtClaims] - ): SessionManager[JwtClaims] = self.manager + companion: SessionDataCompanion[SD] + ): SessionManager[SD] = self.manager override protected def sessionType: Session.SessionType = self.sessionType override def log: Logger = LoggerFactory getLogger getClass.getName override implicit def sessionConfig: SessionConfig = self.sessionConfig override implicit def system: ActorSystem[_] = sys override lazy val ec: ExecutionContext = sys.executionContext override def softPaymentAccountDao: SoftPaymentAccountDao = MockSoftPaymentAccountDao - override implicit def refreshTokenStorage: RefreshTokenStorage[JwtClaims] = + override implicit def refreshTokenStorage: RefreshTokenStorage[SD] = self.refreshTokenStorage + override implicit def companion: SessionDataCompanion[SD] = self.companion } override def endpoints: ActorSystem[_] => List[Endpoint] = system => super.endpoints(system) :+ sessionServiceEndpoints(system) - override def accountEndpoints - : ActorSystem[_] => AccountServiceEndpoints[BasicAccountSignUp, JwtClaims] = + override def accountEndpoints: ActorSystem[_] => AccountServiceEndpoints[BasicAccountSignUp, SD] = sys => - new MockSoftPaymentAccountServiceEndpoints with SessionMaterials[JwtClaims] { + new MockSoftPaymentAccountServiceEndpoints[SD] with SessionMaterials[SD] { override implicit def manager(implicit sessionConfig: SessionConfig, - companion: SessionDataCompanion[JwtClaims] - ): SessionManager[JwtClaims] = self.manager + companion: SessionDataCompanion[SD] + ): SessionManager[SD] = self.manager override protected def sessionType: Session.SessionType = self.sessionType override def log: Logger = LoggerFactory getLogger getClass.getName override implicit def system: ActorSystem[_] = sys override lazy val ec: ExecutionContext = sys.executionContext override protected val manifestWrapper: ManifestW = ManifestW() - override implicit def refreshTokenStorage: RefreshTokenStorage[JwtClaims] = + override implicit def refreshTokenStorage: RefreshTokenStorage[SD] = self.refreshTokenStorage - override implicit def companion: SessionDataCompanion[JwtClaims] = self.companion + override implicit def companion: SessionDataCompanion[SD] = self.companion } - override def oauthEndpoints: ActorSystem[_] => OAuthServiceEndpoints[JwtClaims] = sys => - new MockSoftPaymentOAuthServiceEndpoints with SessionMaterials[JwtClaims] { + override def oauthEndpoints: ActorSystem[_] => OAuthServiceEndpoints[SD] = sys => + new MockSoftPaymentOAuthServiceEndpoints[SD] with SessionMaterials[SD] { override implicit def manager(implicit sessionConfig: SessionConfig, - companion: SessionDataCompanion[JwtClaims] - ): SessionManager[JwtClaims] = self.manager + companion: SessionDataCompanion[SD] + ): SessionManager[SD] = self.manager override protected def sessionType: Session.SessionType = self.sessionType override def log: Logger = LoggerFactory getLogger getClass.getName override implicit def system: ActorSystem[_] = sys override lazy val ec: ExecutionContext = sys.executionContext override def softPaymentAccountDao: SoftPaymentAccountDao = MockSoftPaymentAccountDao - override implicit def refreshTokenStorage: RefreshTokenStorage[JwtClaims] = + override implicit def refreshTokenStorage: RefreshTokenStorage[SD] = self.refreshTokenStorage - override implicit def companion: SessionDataCompanion[JwtClaims] = self.companion + override implicit def companion: SessionDataCompanion[SD] = self.companion } } diff --git a/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentRouteTestKit.scala b/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentRouteTestKit.scala index 690a5ca..ee3cc23 100644 --- a/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentRouteTestKit.scala +++ b/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentRouteTestKit.scala @@ -8,18 +8,18 @@ import app.softnetwork.api.server.config.ServerSettings.RootPath import app.softnetwork.payment.api.PaymentGrpcServices import app.softnetwork.payment.config.PaymentSettings._ import app.softnetwork.payment.model._ +import app.softnetwork.session.model.{SessionData, SessionDataDecorator} import app.softnetwork.session.scalatest.SessionTestKit import app.softnetwork.session.service.SessionMaterials import org.scalatest.Suite -import org.softnetwork.session.model.JwtClaims import java.nio.file.Paths -trait PaymentRouteTestKit - extends SessionTestKit[JwtClaims] +trait PaymentRouteTestKit[SD <: SessionData with SessionDataDecorator[SD]] + extends SessionTestKit[SD] with PaymentTestKit with PaymentGrpcServices { - _: Suite with ApiRoutes with SessionMaterials[JwtClaims] => + _: Suite with ApiRoutes with SessionMaterials[SD] => import app.softnetwork.serialization._ diff --git a/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentRoutesTestKit.scala b/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentRoutesTestKit.scala index 590d3d1..2d4f1a9 100644 --- a/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentRoutesTestKit.scala +++ b/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentRoutesTestKit.scala @@ -17,35 +17,35 @@ import app.softnetwork.payment.service.{ MockSoftPaymentOAuthService } import app.softnetwork.persistence.schema.SchemaProvider -import app.softnetwork.session.model.SessionDataCompanion +import app.softnetwork.session.model.{SessionData, SessionDataCompanion, SessionDataDecorator} import app.softnetwork.session.scalatest.{SessionServiceRoutes, SessionTestKit} import app.softnetwork.session.service.SessionMaterials import com.softwaremill.session.{RefreshTokenStorage, SessionConfig, SessionManager} import org.slf4j.{Logger, LoggerFactory} -import org.softnetwork.session.model.{JwtClaims, Session} +import org.softnetwork.session.model.Session import scala.concurrent.ExecutionContext -trait PaymentRoutesTestKit extends PaymentRoutes with SessionServiceRoutes[JwtClaims] { - self: PaymentTestKit - with SessionTestKit[JwtClaims] - with SchemaProvider - with SessionMaterials[JwtClaims] => +trait PaymentRoutesTestKit[SD <: SessionData with SessionDataDecorator[SD]] + extends PaymentRoutes[SD] + with SessionServiceRoutes[SD] { + self: PaymentTestKit with SessionTestKit[SD] with SchemaProvider with SessionMaterials[SD] => - override def paymentService: ActorSystem[_] => GenericPaymentService = sys => - new MockPaymentService with SessionMaterials[JwtClaims] { + override def paymentService: ActorSystem[_] => GenericPaymentService[SD] = sys => + new MockPaymentService[SD] with SessionMaterials[SD] { override implicit def manager(implicit sessionConfig: SessionConfig, - companion: SessionDataCompanion[JwtClaims] - ): SessionManager[JwtClaims] = self.manager + companion: SessionDataCompanion[SD] + ): SessionManager[SD] = self.manager override protected def sessionType: Session.SessionType = self.sessionType override def log: Logger = LoggerFactory getLogger getClass.getName override implicit def sessionConfig: SessionConfig = self.sessionConfig override implicit def system: ActorSystem[_] = sys override lazy val ec: ExecutionContext = sys.executionContext override def softPaymentAccountDao: SoftPaymentAccountDao = MockSoftPaymentAccountDao - override implicit def refreshTokenStorage: RefreshTokenStorage[JwtClaims] = + override implicit def refreshTokenStorage: RefreshTokenStorage[SD] = self.refreshTokenStorage + override implicit def companion: SessionDataCompanion[SD] = self.companion } implicit def sessionConfig: SessionConfig @@ -54,38 +54,38 @@ trait PaymentRoutesTestKit extends PaymentRoutes with SessionServiceRoutes[JwtCl DefaultProfileView, DefaultAccountDetailsView, DefaultAccountView[DefaultProfileView, DefaultAccountDetailsView], - JwtClaims + SD ] = sys => - new MockSoftPaymentAccountService with SessionMaterials[JwtClaims] { + new MockSoftPaymentAccountService[SD] with SessionMaterials[SD] { override implicit def manager(implicit sessionConfig: SessionConfig, - companion: SessionDataCompanion[JwtClaims] - ): SessionManager[JwtClaims] = self.manager + companion: SessionDataCompanion[SD] + ): SessionManager[SD] = self.manager override protected def sessionType: Session.SessionType = self.sessionType override def log: Logger = LoggerFactory getLogger getClass.getName override implicit def system: ActorSystem[_] = sys override lazy val ec: ExecutionContext = sys.executionContext override protected val manifestWrapper: ManifestW = ManifestW() - override implicit def refreshTokenStorage: RefreshTokenStorage[JwtClaims] = + override implicit def refreshTokenStorage: RefreshTokenStorage[SD] = self.refreshTokenStorage - override implicit def companion: SessionDataCompanion[JwtClaims] = self.companion + override implicit def companion: SessionDataCompanion[SD] = self.companion } - override def oauthService: ActorSystem[_] => OAuthService[JwtClaims] = sys => - new MockSoftPaymentOAuthService with SessionMaterials[JwtClaims] { + override def oauthService: ActorSystem[_] => OAuthService[SD] = sys => + new MockSoftPaymentOAuthService[SD] with SessionMaterials[SD] { override implicit def manager(implicit sessionConfig: SessionConfig, - companion: SessionDataCompanion[JwtClaims] - ): SessionManager[JwtClaims] = self.manager + companion: SessionDataCompanion[SD] + ): SessionManager[SD] = self.manager override protected def sessionType: Session.SessionType = self.sessionType override def log: Logger = LoggerFactory getLogger getClass.getName // override implicit def sessionConfig: SessionConfig = self.sessionConfig override implicit def system: ActorSystem[_] = sys override lazy val ec: ExecutionContext = sys.executionContext override def softPaymentAccountDao: SoftPaymentAccountDao = MockSoftPaymentAccountDao - override implicit def refreshTokenStorage: RefreshTokenStorage[JwtClaims] = + override implicit def refreshTokenStorage: RefreshTokenStorage[SD] = self.refreshTokenStorage - override implicit def companion: SessionDataCompanion[JwtClaims] = self.companion + override implicit def companion: SessionDataCompanion[SD] = self.companion } override def apiRoutes: ActorSystem[_] => List[ApiRoute] = diff --git a/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentTestKit.scala b/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentTestKit.scala index c206127..4bf8277 100644 --- a/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentTestKit.scala +++ b/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentTestKit.scala @@ -39,6 +39,7 @@ import app.softnetwork.scheduler.config.SchedulerSettings import app.softnetwork.scheduler.scalatest.SchedulerTestKit import org.scalatest.Suite import org.slf4j.{Logger, LoggerFactory} +import org.softnetwork.session.model.ApiKey import scala.concurrent.{ExecutionContext, Future} @@ -59,6 +60,9 @@ trait PaymentTestKit extends SchedulerTestKit with PaymentGuardian with AllNotif override def accountDao: AccountDao = MockSoftPaymentAccountDao + def loadApiKey(clientId: String): Future[Option[ApiKey]] = + MockPaymentBehavior.softPaymentAccountDao.loadApiKey(clientId) + override def paymentCommandProcessorStream : ActorSystem[_] => GenericPaymentCommandProcessorStream = sys => new GenericPaymentCommandProcessorStream diff --git a/testkit/src/main/scala/app/softnetwork/payment/service/MockPaymentEndpoints.scala b/testkit/src/main/scala/app/softnetwork/payment/service/MockPaymentEndpoints.scala index 54f3782..c83ed27 100644 --- a/testkit/src/main/scala/app/softnetwork/payment/service/MockPaymentEndpoints.scala +++ b/testkit/src/main/scala/app/softnetwork/payment/service/MockPaymentEndpoints.scala @@ -1,9 +1,11 @@ package app.softnetwork.payment.service import app.softnetwork.payment.handlers.MockPaymentHandler +import app.softnetwork.session.model.{SessionData, SessionDataDecorator} import app.softnetwork.session.service.SessionMaterials -import org.softnetwork.session.model.JwtClaims -trait MockPaymentEndpoints extends MangoPayPaymentEndpoints with MockPaymentHandler { - _: SessionMaterials[JwtClaims] => +trait MockPaymentEndpoints[SD <: SessionData with SessionDataDecorator[SD]] + extends MangoPayPaymentEndpoints[SD] + with MockPaymentHandler { + _: SessionMaterials[SD] => } diff --git a/testkit/src/main/scala/app/softnetwork/payment/service/MockPaymentService.scala b/testkit/src/main/scala/app/softnetwork/payment/service/MockPaymentService.scala index b18c6b0..d737ec8 100644 --- a/testkit/src/main/scala/app/softnetwork/payment/service/MockPaymentService.scala +++ b/testkit/src/main/scala/app/softnetwork/payment/service/MockPaymentService.scala @@ -1,9 +1,11 @@ package app.softnetwork.payment.service import app.softnetwork.payment.handlers.MockPaymentHandler +import app.softnetwork.session.model.{SessionData, SessionDataDecorator} import app.softnetwork.session.service.SessionMaterials -import org.softnetwork.session.model.JwtClaims -trait MockPaymentService extends MangoPayPaymentService with MockPaymentHandler { - _: SessionMaterials[JwtClaims] => +trait MockPaymentService[SD <: SessionData with SessionDataDecorator[SD]] + extends MangoPayPaymentService[SD] + with MockPaymentHandler { + _: SessionMaterials[SD] => } diff --git a/testkit/src/main/scala/app/softnetwork/payment/service/MockSoftPaymentAccountService.scala b/testkit/src/main/scala/app/softnetwork/payment/service/MockSoftPaymentAccountService.scala index b843f98..79a6e4b 100644 --- a/testkit/src/main/scala/app/softnetwork/payment/service/MockSoftPaymentAccountService.scala +++ b/testkit/src/main/scala/app/softnetwork/payment/service/MockSoftPaymentAccountService.scala @@ -1,12 +1,12 @@ package app.softnetwork.payment.service import app.softnetwork.payment.handlers.MockSoftPaymentAccountTypeKey +import app.softnetwork.session.model.{SessionData, SessionDataDecorator} import app.softnetwork.session.service.SessionMaterials -import org.softnetwork.session.model.JwtClaims -trait MockSoftPaymentAccountService - extends SoftPaymentAccountService +trait MockSoftPaymentAccountService[SD <: SessionData with SessionDataDecorator[SD]] + extends SoftPaymentAccountService[SD] with MockSoftPaymentAccountTypeKey { - _: SessionMaterials[JwtClaims] => + _: SessionMaterials[SD] => } diff --git a/testkit/src/main/scala/app/softnetwork/payment/service/MockSoftPaymentAccountServiceEndpoints.scala b/testkit/src/main/scala/app/softnetwork/payment/service/MockSoftPaymentAccountServiceEndpoints.scala index e326b14..5018af3 100644 --- a/testkit/src/main/scala/app/softnetwork/payment/service/MockSoftPaymentAccountServiceEndpoints.scala +++ b/testkit/src/main/scala/app/softnetwork/payment/service/MockSoftPaymentAccountServiceEndpoints.scala @@ -1,9 +1,9 @@ package app.softnetwork.payment.service import app.softnetwork.payment.handlers.MockSoftPaymentAccountTypeKey +import app.softnetwork.session.model.{SessionData, SessionDataDecorator} import app.softnetwork.session.service.SessionMaterials -import org.softnetwork.session.model.JwtClaims -trait MockSoftPaymentAccountServiceEndpoints - extends SoftPaymentAccountServiceEndpoints - with MockSoftPaymentAccountTypeKey { _: SessionMaterials[JwtClaims] => } +trait MockSoftPaymentAccountServiceEndpoints[SD <: SessionData with SessionDataDecorator[SD]] + extends SoftPaymentAccountServiceEndpoints[SD] + with MockSoftPaymentAccountTypeKey { _: SessionMaterials[SD] => } diff --git a/testkit/src/main/scala/app/softnetwork/payment/service/MockSoftPaymentOAuthService.scala b/testkit/src/main/scala/app/softnetwork/payment/service/MockSoftPaymentOAuthService.scala index ba8f9f5..c8b957f 100644 --- a/testkit/src/main/scala/app/softnetwork/payment/service/MockSoftPaymentOAuthService.scala +++ b/testkit/src/main/scala/app/softnetwork/payment/service/MockSoftPaymentOAuthService.scala @@ -2,14 +2,14 @@ package app.softnetwork.payment.service import app.softnetwork.account.spi.OAuth2Service import app.softnetwork.payment.handlers.MockSoftPaymentAccountTypeKey +import app.softnetwork.session.model.{SessionData, SessionDataDecorator} import app.softnetwork.session.service.SessionMaterials import com.github.scribejava.core.oauth.DummyApiService -import org.softnetwork.session.model.JwtClaims -trait MockSoftPaymentOAuthService - extends SoftPaymentOAuthService +trait MockSoftPaymentOAuthService[SD <: SessionData with SessionDataDecorator[SD]] + extends SoftPaymentOAuthService[SD] with MockSoftPaymentAccountTypeKey { - _: SessionMaterials[JwtClaims] => + _: SessionMaterials[SD] => override lazy val services: Seq[OAuth2Service] = Seq( new DummyApiService() diff --git a/testkit/src/main/scala/app/softnetwork/payment/service/MockSoftPaymentOAuthServiceEndpoints.scala b/testkit/src/main/scala/app/softnetwork/payment/service/MockSoftPaymentOAuthServiceEndpoints.scala index 0f40346..6fe8e95 100644 --- a/testkit/src/main/scala/app/softnetwork/payment/service/MockSoftPaymentOAuthServiceEndpoints.scala +++ b/testkit/src/main/scala/app/softnetwork/payment/service/MockSoftPaymentOAuthServiceEndpoints.scala @@ -2,13 +2,13 @@ package app.softnetwork.payment.service import app.softnetwork.account.spi.OAuth2Service import app.softnetwork.payment.handlers.MockSoftPaymentAccountTypeKey +import app.softnetwork.session.model.{SessionData, SessionDataDecorator} import app.softnetwork.session.service.SessionMaterials import com.github.scribejava.core.oauth.DummyApiService -import org.softnetwork.session.model.JwtClaims -trait MockSoftPaymentOAuthServiceEndpoints - extends SoftPaymentOAuthServiceEndpoints - with MockSoftPaymentAccountTypeKey { _: SessionMaterials[JwtClaims] => +trait MockSoftPaymentOAuthServiceEndpoints[SD <: SessionData with SessionDataDecorator[SD]] + extends SoftPaymentOAuthServiceEndpoints[SD] + with MockSoftPaymentAccountTypeKey { _: SessionMaterials[SD] => override lazy val services: Seq[OAuth2Service] = Seq( diff --git a/testkit/src/test/scala/app/softnetwork/payment/service/PaymentEndpointsWithOneOffCookieSessionSpec.scala b/testkit/src/test/scala/app/softnetwork/payment/service/PaymentEndpointsWithOneOffCookieSessionSpec.scala index 59353ae..6a6c9e9 100644 --- a/testkit/src/test/scala/app/softnetwork/payment/service/PaymentEndpointsWithOneOffCookieSessionSpec.scala +++ b/testkit/src/test/scala/app/softnetwork/payment/service/PaymentEndpointsWithOneOffCookieSessionSpec.scala @@ -3,12 +3,15 @@ package app.softnetwork.payment.service import app.softnetwork.payment.scalatest.PaymentEndpointsTestKit import app.softnetwork.session.scalatest.OneOffCookieSessionEndpointsTestKit import app.softnetwork.session.CsrfCheckHeader -import app.softnetwork.session.service.BasicSessionMaterials +import app.softnetwork.session.model.SessionDataCompanion +import app.softnetwork.session.service.JwtClaimsSessionMaterials import org.softnetwork.session.model.JwtClaims class PaymentEndpointsWithOneOffCookieSessionSpec - extends PaymentServiceSpec + extends PaymentServiceSpec[JwtClaims] with OneOffCookieSessionEndpointsTestKit[JwtClaims] - with PaymentEndpointsTestKit + with PaymentEndpointsTestKit[JwtClaims] with CsrfCheckHeader - with BasicSessionMaterials[JwtClaims] + with JwtClaimsSessionMaterials { + override implicit def companion: SessionDataCompanion[JwtClaims] = JwtClaims +} diff --git a/testkit/src/test/scala/app/softnetwork/payment/service/PaymentEndpointsWithOneOffHeaderSessionSpec.scala b/testkit/src/test/scala/app/softnetwork/payment/service/PaymentEndpointsWithOneOffHeaderSessionSpec.scala index 4f1622c..ed81055 100644 --- a/testkit/src/test/scala/app/softnetwork/payment/service/PaymentEndpointsWithOneOffHeaderSessionSpec.scala +++ b/testkit/src/test/scala/app/softnetwork/payment/service/PaymentEndpointsWithOneOffHeaderSessionSpec.scala @@ -3,12 +3,15 @@ package app.softnetwork.payment.service import app.softnetwork.payment.scalatest.PaymentEndpointsTestKit import app.softnetwork.session.scalatest.OneOffHeaderSessionEndpointsTestKit import app.softnetwork.session.CsrfCheckHeader -import app.softnetwork.session.service.BasicSessionMaterials +import app.softnetwork.session.model.SessionDataCompanion +import app.softnetwork.session.service.JwtClaimsSessionMaterials import org.softnetwork.session.model.JwtClaims class PaymentEndpointsWithOneOffHeaderSessionSpec - extends PaymentServiceSpec + extends PaymentServiceSpec[JwtClaims] with OneOffHeaderSessionEndpointsTestKit[JwtClaims] - with PaymentEndpointsTestKit + with PaymentEndpointsTestKit[JwtClaims] with CsrfCheckHeader - with BasicSessionMaterials[JwtClaims] + with JwtClaimsSessionMaterials { + override implicit def companion: SessionDataCompanion[JwtClaims] = JwtClaims +} diff --git a/testkit/src/test/scala/app/softnetwork/payment/service/PaymentEndpointsWithRefreshableCookieSessionSpec.scala b/testkit/src/test/scala/app/softnetwork/payment/service/PaymentEndpointsWithRefreshableCookieSessionSpec.scala index 01b9212..00fc3f9 100644 --- a/testkit/src/test/scala/app/softnetwork/payment/service/PaymentEndpointsWithRefreshableCookieSessionSpec.scala +++ b/testkit/src/test/scala/app/softnetwork/payment/service/PaymentEndpointsWithRefreshableCookieSessionSpec.scala @@ -3,12 +3,15 @@ package app.softnetwork.payment.service import app.softnetwork.payment.scalatest.PaymentEndpointsTestKit import app.softnetwork.session.scalatest.RefreshableCookieSessionEndpointsTestKit import app.softnetwork.session.CsrfCheckHeader -import app.softnetwork.session.service.BasicSessionMaterials +import app.softnetwork.session.model.SessionDataCompanion +import app.softnetwork.session.service.JwtClaimsSessionMaterials import org.softnetwork.session.model.JwtClaims class PaymentEndpointsWithRefreshableCookieSessionSpec - extends PaymentServiceSpec + extends PaymentServiceSpec[JwtClaims] with RefreshableCookieSessionEndpointsTestKit[JwtClaims] - with PaymentEndpointsTestKit + with PaymentEndpointsTestKit[JwtClaims] with CsrfCheckHeader - with BasicSessionMaterials[JwtClaims] + with JwtClaimsSessionMaterials { + override implicit def companion: SessionDataCompanion[JwtClaims] = JwtClaims +} diff --git a/testkit/src/test/scala/app/softnetwork/payment/service/PaymentEndpointsWithRefreshableHeaderSessionSpec.scala b/testkit/src/test/scala/app/softnetwork/payment/service/PaymentEndpointsWithRefreshableHeaderSessionSpec.scala index 9f3b001..029388e 100644 --- a/testkit/src/test/scala/app/softnetwork/payment/service/PaymentEndpointsWithRefreshableHeaderSessionSpec.scala +++ b/testkit/src/test/scala/app/softnetwork/payment/service/PaymentEndpointsWithRefreshableHeaderSessionSpec.scala @@ -3,12 +3,15 @@ package app.softnetwork.payment.service import app.softnetwork.payment.scalatest.PaymentEndpointsTestKit import app.softnetwork.session.scalatest.RefreshableHeaderSessionEndpointsTestKit import app.softnetwork.session.CsrfCheckHeader -import app.softnetwork.session.service.BasicSessionMaterials +import app.softnetwork.session.model.SessionDataCompanion +import app.softnetwork.session.service.JwtClaimsSessionMaterials import org.softnetwork.session.model.JwtClaims class PaymentEndpointsWithRefreshableHeaderSessionSpec - extends PaymentServiceSpec + extends PaymentServiceSpec[JwtClaims] with RefreshableHeaderSessionEndpointsTestKit[JwtClaims] - with PaymentEndpointsTestKit + with PaymentEndpointsTestKit[JwtClaims] with CsrfCheckHeader - with BasicSessionMaterials[JwtClaims] + with JwtClaimsSessionMaterials { + override implicit def companion: SessionDataCompanion[JwtClaims] = JwtClaims +} diff --git a/testkit/src/test/scala/app/softnetwork/payment/service/PaymentRoutesWithOneOffCookieSessionSpec.scala b/testkit/src/test/scala/app/softnetwork/payment/service/PaymentRoutesWithOneOffCookieSessionSpec.scala index 5294a3a..3ed8baa 100644 --- a/testkit/src/test/scala/app/softnetwork/payment/service/PaymentRoutesWithOneOffCookieSessionSpec.scala +++ b/testkit/src/test/scala/app/softnetwork/payment/service/PaymentRoutesWithOneOffCookieSessionSpec.scala @@ -1,12 +1,15 @@ package app.softnetwork.payment.service import app.softnetwork.payment.scalatest.PaymentRoutesTestKit +import app.softnetwork.session.model.SessionDataCompanion import app.softnetwork.session.scalatest.OneOffCookieSessionServiceTestKit -import app.softnetwork.session.service.BasicSessionMaterials +import app.softnetwork.session.service.JwtClaimsSessionMaterials import org.softnetwork.session.model.JwtClaims class PaymentRoutesWithOneOffCookieSessionSpec - extends PaymentServiceSpec + extends PaymentServiceSpec[JwtClaims] with OneOffCookieSessionServiceTestKit[JwtClaims] - with PaymentRoutesTestKit - with BasicSessionMaterials[JwtClaims] + with PaymentRoutesTestKit[JwtClaims] + with JwtClaimsSessionMaterials { + override implicit def companion: SessionDataCompanion[JwtClaims] = JwtClaims +} diff --git a/testkit/src/test/scala/app/softnetwork/payment/service/PaymentRoutesWithOneOffHeaderSessionSpec.scala b/testkit/src/test/scala/app/softnetwork/payment/service/PaymentRoutesWithOneOffHeaderSessionSpec.scala index 5902a9d..b5d8671 100644 --- a/testkit/src/test/scala/app/softnetwork/payment/service/PaymentRoutesWithOneOffHeaderSessionSpec.scala +++ b/testkit/src/test/scala/app/softnetwork/payment/service/PaymentRoutesWithOneOffHeaderSessionSpec.scala @@ -1,12 +1,15 @@ package app.softnetwork.payment.service import app.softnetwork.payment.scalatest.PaymentRoutesTestKit +import app.softnetwork.session.model.SessionDataCompanion import app.softnetwork.session.scalatest.OneOffHeaderSessionServiceTestKit -import app.softnetwork.session.service.BasicSessionMaterials +import app.softnetwork.session.service.JwtClaimsSessionMaterials import org.softnetwork.session.model.JwtClaims class PaymentRoutesWithOneOffHeaderSessionSpec - extends PaymentServiceSpec + extends PaymentServiceSpec[JwtClaims] with OneOffHeaderSessionServiceTestKit[JwtClaims] - with PaymentRoutesTestKit - with BasicSessionMaterials[JwtClaims] + with PaymentRoutesTestKit[JwtClaims] + with JwtClaimsSessionMaterials { + override implicit def companion: SessionDataCompanion[JwtClaims] = JwtClaims +} diff --git a/testkit/src/test/scala/app/softnetwork/payment/service/PaymentRoutesWithRefreshableCookieSessionSpec.scala b/testkit/src/test/scala/app/softnetwork/payment/service/PaymentRoutesWithRefreshableCookieSessionSpec.scala index 10c6045..144a98b 100644 --- a/testkit/src/test/scala/app/softnetwork/payment/service/PaymentRoutesWithRefreshableCookieSessionSpec.scala +++ b/testkit/src/test/scala/app/softnetwork/payment/service/PaymentRoutesWithRefreshableCookieSessionSpec.scala @@ -1,12 +1,15 @@ package app.softnetwork.payment.service import app.softnetwork.payment.scalatest.PaymentRoutesTestKit +import app.softnetwork.session.model.SessionDataCompanion import app.softnetwork.session.scalatest.RefreshableCookieSessionServiceTestKit -import app.softnetwork.session.service.BasicSessionMaterials +import app.softnetwork.session.service.JwtClaimsSessionMaterials import org.softnetwork.session.model.JwtClaims class PaymentRoutesWithRefreshableCookieSessionSpec - extends PaymentServiceSpec + extends PaymentServiceSpec[JwtClaims] with RefreshableCookieSessionServiceTestKit[JwtClaims] - with PaymentRoutesTestKit - with BasicSessionMaterials[JwtClaims] + with PaymentRoutesTestKit[JwtClaims] + with JwtClaimsSessionMaterials { + override implicit def companion: SessionDataCompanion[JwtClaims] = JwtClaims +} diff --git a/testkit/src/test/scala/app/softnetwork/payment/service/PaymentRoutesWithRefreshableHeaderSessionSpec.scala b/testkit/src/test/scala/app/softnetwork/payment/service/PaymentRoutesWithRefreshableHeaderSessionSpec.scala index 82e8165..3986808 100644 --- a/testkit/src/test/scala/app/softnetwork/payment/service/PaymentRoutesWithRefreshableHeaderSessionSpec.scala +++ b/testkit/src/test/scala/app/softnetwork/payment/service/PaymentRoutesWithRefreshableHeaderSessionSpec.scala @@ -1,12 +1,15 @@ package app.softnetwork.payment.service import app.softnetwork.payment.scalatest.PaymentRoutesTestKit +import app.softnetwork.session.model.SessionDataCompanion import app.softnetwork.session.scalatest.RefreshableHeaderSessionServiceTestKit -import app.softnetwork.session.service.BasicSessionMaterials +import app.softnetwork.session.service.JwtClaimsSessionMaterials import org.softnetwork.session.model.JwtClaims class PaymentRoutesWithRefreshableHeaderSessionSpec - extends PaymentServiceSpec + extends PaymentServiceSpec[JwtClaims] with RefreshableHeaderSessionServiceTestKit[JwtClaims] - with PaymentRoutesTestKit - with BasicSessionMaterials[JwtClaims] + with PaymentRoutesTestKit[JwtClaims] + with JwtClaimsSessionMaterials { + override implicit def companion: SessionDataCompanion[JwtClaims] = JwtClaims +} diff --git a/testkit/src/test/scala/app/softnetwork/payment/service/PaymentServiceSpec.scala b/testkit/src/test/scala/app/softnetwork/payment/service/PaymentServiceSpec.scala index f8ce48c..765b769 100644 --- a/testkit/src/test/scala/app/softnetwork/payment/service/PaymentServiceSpec.scala +++ b/testkit/src/test/scala/app/softnetwork/payment/service/PaymentServiceSpec.scala @@ -12,21 +12,20 @@ import app.softnetwork.payment.model._ import app.softnetwork.payment.scalatest.PaymentRouteTestKit import app.softnetwork.time._ import app.softnetwork.persistence.now -import app.softnetwork.session.handlers.JwtClaimsRefreshTokenDao -import app.softnetwork.session.model.SessionDataCompanion +import app.softnetwork.session.model.{SessionData, SessionDataDecorator} import app.softnetwork.session.service.SessionMaterials -import com.softwaremill.session.RefreshTokenStorage import org.scalatest.wordspec.AnyWordSpecLike import org.slf4j.{Logger, LoggerFactory} -import org.softnetwork.session.model.JwtClaims import java.net.{InetAddress, URLEncoder} import java.time.LocalDate import scala.language.implicitConversions import scala.util.{Failure, Success} -trait PaymentServiceSpec extends AnyWordSpecLike with PaymentRouteTestKit { - _: ApiRoutes with SessionMaterials[JwtClaims] => +trait PaymentServiceSpec[SD <: SessionData with SessionDataDecorator[SD]] + extends AnyWordSpecLike + with PaymentRouteTestKit[SD] { + _: ApiRoutes with SessionMaterials[SD] => lazy val log: Logger = LoggerFactory getLogger getClass.getName @@ -34,11 +33,6 @@ trait PaymentServiceSpec extends AnyWordSpecLike with PaymentRouteTestKit { lazy val paymentClient: PaymentClient = PaymentClient(ts) - override implicit def companion: SessionDataCompanion[JwtClaims] = JwtClaims - - override implicit def refreshTokenStorage: RefreshTokenStorage[JwtClaims] = - JwtClaimsRefreshTokenDao(ts) - "Payment service" must { "pre register card" in { createSession(customerUuid, Some("customer")) From 41d4427f4a16d585bcda9d7aa80bd41e12c271b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Manciot?= Date: Mon, 4 Dec 2023 14:12:45 +0100 Subject: [PATCH 09/37] register providers payment account --- .../payment/message/AccountMessages.scala | 12 +++++++++ .../payment/model/ProviderDecorator.scala | 20 +++++++++++++- .../payment/spi/PaymentProviderSpi.scala | 1 + .../payment/spi/PaymentProviders.scala | 3 +++ .../handlers/SoftPaymentAccountDao.scala | 11 ++++++++ .../payment/launch/PaymentEndpoints.scala | 1 - .../payment/launch/PaymentGuardian.scala | 27 +++++++++++++++++++ .../payment/launch/PaymentRoutes.scala | 1 - .../typed/SoftPaymentAccountBehavior.scala | 22 +++++++++++++++ .../softnetwork/payment/api/MangoPayApi.scala | 2 -- .../payment/spi/MangoPayProvider.scala | 3 +++ .../payment/scalatest/PaymentTestKit.scala | 8 +++--- .../payment/spi/MockMangoPayProvider.scala | 3 +++ 13 files changed, 106 insertions(+), 8 deletions(-) diff --git a/common/src/main/scala/app/softnetwork/payment/message/AccountMessages.scala b/common/src/main/scala/app/softnetwork/payment/message/AccountMessages.scala index 19859ed..bbf6ee5 100644 --- a/common/src/main/scala/app/softnetwork/payment/message/AccountMessages.scala +++ b/common/src/main/scala/app/softnetwork/payment/message/AccountMessages.scala @@ -10,6 +10,7 @@ import app.softnetwork.account.message.{ import app.softnetwork.account.model.BasicAccountProfile import app.softnetwork.payment.annotation.InternalApi import app.softnetwork.payment.model.SoftPaymentAccount +import app.softnetwork.persistence.message.EntityCommand import org.softnetwork.session.model.ApiKey object AccountMessages { @@ -23,6 +24,12 @@ object AccountMessages { case class RegisterProvider(provider: SoftPaymentAccount.Client.Provider) extends AccountCommand + case class RegisterProviderAccount(provider: SoftPaymentAccount.Client.Provider) + extends AccountCommand + with EntityCommand { + override def id: String = provider.clientId + } + @InternalApi private[payment] case class LoadClient(clientId: String) extends LookupAccountCommand @@ -42,6 +49,8 @@ object AccountMessages { case class ProviderRegistered(client: SoftPaymentAccount.Client) extends AccountCommandResult + case class ProviderAccountRegistered(account: SoftPaymentAccount) extends AccountCommandResult + case class ClientLoaded(client: SoftPaymentAccount.Client) extends AccountCommandResult case class ApiKeysLoaded(apiKeys: Seq[ApiKey]) extends AccountCommandResult @@ -55,6 +64,9 @@ object AccountMessages { case object ProviderNotRegistered extends AccountErrorMessage("provider.not.registered") + case object ProviderAccountNotRegistered + extends AccountErrorMessage("provider.account.not.registered") + case object ClientNotFound extends AccountErrorMessage("client.not.found") case object ApiKeyNotFound extends AccountErrorMessage("api.key.not.found") diff --git a/common/src/main/scala/app/softnetwork/payment/model/ProviderDecorator.scala b/common/src/main/scala/app/softnetwork/payment/model/ProviderDecorator.scala index 9b64914..8be9541 100644 --- a/common/src/main/scala/app/softnetwork/payment/model/ProviderDecorator.scala +++ b/common/src/main/scala/app/softnetwork/payment/model/ProviderDecorator.scala @@ -1,5 +1,23 @@ package app.softnetwork.payment.model -trait ProviderDecorator { _: SoftPaymentAccount.Client.Provider => +import app.softnetwork.account.model.{Principal, PrincipalType} +import app.softnetwork.payment.spi.PaymentProviders + +trait ProviderDecorator { self: SoftPaymentAccount.Client.Provider => lazy val clientId = s"$providerId.${providerType.name.toLowerCase}" + + lazy val client: SoftPaymentAccount.Client = { + PaymentProviders.paymentProvider(self).client match { + case Some(value) => value.withClientApiKey(self.providerApiKey) + case _ => + throw new Exception(s"PaymentProvider not found for providerType: ${providerType}") + } + } + + lazy val account: SoftPaymentAccount = { + SoftPaymentAccount.defaultInstance + .withUuid(clientId) + .withAnonymous(true) + .withClients(Seq(client)) + } } diff --git a/common/src/main/scala/app/softnetwork/payment/spi/PaymentProviderSpi.scala b/common/src/main/scala/app/softnetwork/payment/spi/PaymentProviderSpi.scala index d0b05b4..0130477 100644 --- a/common/src/main/scala/app/softnetwork/payment/spi/PaymentProviderSpi.scala +++ b/common/src/main/scala/app/softnetwork/payment/spi/PaymentProviderSpi.scala @@ -7,4 +7,5 @@ trait PaymentProviderSpi { def paymentProvider(p: SoftPaymentAccount.Client.Provider): PaymentProvider + def softPaymentProvider: SoftPaymentAccount.Client.Provider } diff --git a/common/src/main/scala/app/softnetwork/payment/spi/PaymentProviders.scala b/common/src/main/scala/app/softnetwork/payment/spi/PaymentProviders.scala index 17e4718..d185b66 100644 --- a/common/src/main/scala/app/softnetwork/payment/spi/PaymentProviders.scala +++ b/common/src/main/scala/app/softnetwork/payment/spi/PaymentProviders.scala @@ -15,6 +15,9 @@ object PaymentProviders { private[this] def paymentProviderKey(provider: SoftPaymentAccount.Client.Provider) = s"${provider.providerType}-${provider.providerId}" + def defaultPaymentProviders: Seq[SoftPaymentAccount.Client.Provider] = + paymentProviderFactories.iterator().asScala.map(_.softPaymentProvider).toSeq + def paymentProvider( provider: SoftPaymentAccount.Client.Provider ): PaymentProvider = { diff --git a/core/src/main/scala/app/softnetwork/payment/handlers/SoftPaymentAccountDao.scala b/core/src/main/scala/app/softnetwork/payment/handlers/SoftPaymentAccountDao.scala index 174bc69..bc47962 100644 --- a/core/src/main/scala/app/softnetwork/payment/handlers/SoftPaymentAccountDao.scala +++ b/core/src/main/scala/app/softnetwork/payment/handlers/SoftPaymentAccountDao.scala @@ -99,6 +99,17 @@ trait SoftPaymentAccountDao extends AccountDao { _: AccountHandler => case _ => None } } + + def registerProviderAccount(provider: SoftPaymentAccount.Client.Provider)(implicit + system: ActorSystem[_] + ): Future[Option[SoftPaymentAccount]] = { + implicit val ec: ExecutionContext = system.executionContext + !?(AccountMessages.RegisterProviderAccount(provider)) map { + case result: AccountMessages.ProviderAccountRegistered => Some(result.account) + case _ => None + } + } + } trait SoftPaymentAccountTypeKey extends CommandTypeKey[AccountCommand] { diff --git a/core/src/main/scala/app/softnetwork/payment/launch/PaymentEndpoints.scala b/core/src/main/scala/app/softnetwork/payment/launch/PaymentEndpoints.scala index 1f1512f..451c002 100644 --- a/core/src/main/scala/app/softnetwork/payment/launch/PaymentEndpoints.scala +++ b/core/src/main/scala/app/softnetwork/payment/launch/PaymentEndpoints.scala @@ -12,7 +12,6 @@ import app.softnetwork.persistence.schema.SchemaProvider import app.softnetwork.session.CsrfCheck import app.softnetwork.session.model.{SessionData, SessionDataDecorator} import org.json4s.Formats -import org.softnetwork.session.model.JwtClaims trait PaymentEndpoints[SD <: SessionData with SessionDataDecorator[SD]] extends AccountEndpoints[ diff --git a/core/src/main/scala/app/softnetwork/payment/launch/PaymentGuardian.scala b/core/src/main/scala/app/softnetwork/payment/launch/PaymentGuardian.scala index 9455142..89df7a3 100644 --- a/core/src/main/scala/app/softnetwork/payment/launch/PaymentGuardian.scala +++ b/core/src/main/scala/app/softnetwork/payment/launch/PaymentGuardian.scala @@ -1,9 +1,11 @@ package app.softnetwork.payment.launch import akka.actor.typed.ActorSystem +import app.softnetwork.account.handlers.AccountDao import app.softnetwork.account.launch.AccountGuardian import app.softnetwork.account.model.BasicAccountProfile import app.softnetwork.payment.PaymentCoreBuildInfo +import app.softnetwork.payment.handlers.SoftPaymentAccountDao import app.softnetwork.payment.model.SoftPaymentAccount import app.softnetwork.payment.persistence.data.paymentKvDao import app.softnetwork.payment.persistence.query.{ @@ -11,12 +13,15 @@ import app.softnetwork.payment.persistence.query.{ Scheduler2PaymentProcessorStream } import app.softnetwork.payment.persistence.typed.GenericPaymentBehavior +import app.softnetwork.payment.spi.PaymentProviders import app.softnetwork.persistence.launch.PersistentEntity import app.softnetwork.persistence.query.EventProcessorStream import app.softnetwork.persistence.schema.SchemaProvider import app.softnetwork.persistence.typed.Singleton import app.softnetwork.session.CsrfCheck +import scala.concurrent.ExecutionContext + trait PaymentGuardian extends AccountGuardian[SoftPaymentAccount, BasicAccountProfile] { _: SchemaProvider with CsrfCheck => @@ -52,4 +57,26 @@ trait PaymentGuardian extends AccountGuardian[SoftPaymentAccount, BasicAccountPr override def systemVersion(): String = sys.env.getOrElse("VERSION", PaymentCoreBuildInfo.version) + + def softPaymentAccountDao: SoftPaymentAccountDao = SoftPaymentAccountDao + + final override def accountDao: AccountDao = softPaymentAccountDao + + def registerProvidersAccount: ActorSystem[_] => Unit = system => { + PaymentProviders.defaultPaymentProviders.foreach(provider => { + implicit val ec: ExecutionContext = system.executionContext + softPaymentAccountDao.registerProviderAccount(provider)(system) map { + case Some(account) => + system.log.info(s"Registered provider account for ${provider.providerId}: $account") + case _ => + system.log.warn(s"Failed to register provider account for ${provider.providerId}") + } + }) + } + + override def initSystem: ActorSystem[_] => Unit = system => { + registerProvidersAccount(system) + super.initSystem(system) + } + } diff --git a/core/src/main/scala/app/softnetwork/payment/launch/PaymentRoutes.scala b/core/src/main/scala/app/softnetwork/payment/launch/PaymentRoutes.scala index a8125b8..57a19f5 100644 --- a/core/src/main/scala/app/softnetwork/payment/launch/PaymentRoutes.scala +++ b/core/src/main/scala/app/softnetwork/payment/launch/PaymentRoutes.scala @@ -16,7 +16,6 @@ import app.softnetwork.persistence.schema.SchemaProvider import app.softnetwork.session.CsrfCheck import app.softnetwork.session.model.{SessionData, SessionDataDecorator} import org.json4s.Formats -import org.softnetwork.session.model.JwtClaims trait PaymentRoutes[SD <: SessionData with SessionDataDecorator[SD]] extends AccountRoutes[ diff --git a/core/src/main/scala/app/softnetwork/payment/persistence/typed/SoftPaymentAccountBehavior.scala b/core/src/main/scala/app/softnetwork/payment/persistence/typed/SoftPaymentAccountBehavior.scala index 43a8560..1f7cfc5 100644 --- a/core/src/main/scala/app/softnetwork/payment/persistence/typed/SoftPaymentAccountBehavior.scala +++ b/core/src/main/scala/app/softnetwork/payment/persistence/typed/SoftPaymentAccountBehavior.scala @@ -310,6 +310,28 @@ trait SoftPaymentAccountBehavior extends AccountBehavior[SoftPaymentAccount, Bas } } + case AccountMessages.RegisterProviderAccount(provider) => + state match { + case Some(account) => + accountKeyDao.addAccountKey(provider.clientId, entityId) + Effect + .persist( + SoftPaymentAccountProviderRegisteredEvent( + provider.client, + Instant.now() + ) + ) + .thenRun(state => + AccountMessages.ProviderAccountRegistered(state.getOrElse(account)) ~> replyTo + ) + case _ => + val account = provider.account + accountKeyDao.addAccountKey(provider.clientId, entityId) + Effect.persist(SoftPaymentAccountCreatedEvent(account)).thenRun { state => + AccountMessages.ProviderAccountRegistered(state.getOrElse(account)) ~> replyTo + } + } + case _ => super.handleCommand(entityId, state, command, replyTo, timers) } } diff --git a/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayApi.scala b/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayApi.scala index fd9483c..c7579c2 100644 --- a/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayApi.scala +++ b/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayApi.scala @@ -60,8 +60,6 @@ trait MangoPayApi[SD <: SessionData with SessionDataDecorator[SD]] extends Payme : ActorSystem[_] => AccountBehavior[SoftPaymentAccount, BasicAccountProfile] = _ => SoftPaymentAccountBehavior - override def accountDao: AccountDao = SoftPaymentAccountDao - override def internalAccountEvents2AccountProcessorStream : ActorSystem[_] => InternalAccountEvents2AccountProcessorStream = sys => new InternalAccountEvents2AccountProcessorStream diff --git a/mangopay/src/main/scala/app/softnetwork/payment/spi/MangoPayProvider.scala b/mangopay/src/main/scala/app/softnetwork/payment/spi/MangoPayProvider.scala index 8128e81..e6e8ab5 100644 --- a/mangopay/src/main/scala/app/softnetwork/payment/spi/MangoPayProvider.scala +++ b/mangopay/src/main/scala/app/softnetwork/payment/spi/MangoPayProvider.scala @@ -2599,4 +2599,7 @@ class MangoPayProviderFactory extends PaymentProviderSpi { new MangoPayProvider { override implicit val provider: SoftPaymentAccount.Client.Provider = p } + + override def softPaymentProvider: SoftPaymentAccount.Client.Provider = + MangoPay.softPaymentProvider } diff --git a/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentTestKit.scala b/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentTestKit.scala index 4bf8277..40b7828 100644 --- a/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentTestKit.scala +++ b/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentTestKit.scala @@ -11,7 +11,8 @@ import app.softnetwork.payment.config.PaymentSettings._ import app.softnetwork.payment.handlers.{ MockPaymentHandler, MockSoftPaymentAccountDao, - MockSoftPaymentAccountHandler + MockSoftPaymentAccountHandler, + SoftPaymentAccountDao } import app.softnetwork.payment.launch.PaymentGuardian import app.softnetwork.payment.message.PaymentMessages.{ @@ -58,8 +59,6 @@ trait PaymentTestKit extends SchedulerTestKit with PaymentGuardian with AllNotif : ActorSystem[_] => AccountBehavior[SoftPaymentAccount, BasicAccountProfile] = _ => MockSoftPaymentAccountBehavior - override def accountDao: AccountDao = MockSoftPaymentAccountDao - def loadApiKey(clientId: String): Future[Option[ApiKey]] = MockPaymentBehavior.softPaymentAccountDao.loadApiKey(clientId) @@ -220,5 +219,8 @@ trait PaymentTestKit extends SchedulerTestKit with PaymentGuardian with AllNotif override def initSystem: ActorSystem[_] => Unit = system => { initAccountSystem(system) initSchedulerSystem(system) + registerProvidersAccount(system) } + + override def softPaymentAccountDao: SoftPaymentAccountDao = MockSoftPaymentAccountDao } diff --git a/testkit/src/main/scala/app/softnetwork/payment/spi/MockMangoPayProvider.scala b/testkit/src/main/scala/app/softnetwork/payment/spi/MockMangoPayProvider.scala index 2223d30..cc19e48 100644 --- a/testkit/src/main/scala/app/softnetwork/payment/spi/MockMangoPayProvider.scala +++ b/testkit/src/main/scala/app/softnetwork/payment/spi/MockMangoPayProvider.scala @@ -1,5 +1,6 @@ package app.softnetwork.payment.spi +import app.softnetwork.payment.config.MangoPay import app.softnetwork.payment.config.MangoPaySettings.MangoPayConfig._ import app.softnetwork.payment.model.PaymentUser.PaymentUserType import app.softnetwork.payment.model.RecurringPayment.RecurringCardPaymentState @@ -1727,4 +1728,6 @@ class MockMangoPayProviderFactory extends PaymentProviderSpi { new MockMangoPayProvider { override implicit def provider: Provider = p } + + override def softPaymentProvider: Provider = MangoPay.softPaymentProvider } From 822d12c88dff2b8b1ca77a7a2bebb7ecaaf26ead Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Manciot?= Date: Tue, 5 Dec 2023 16:33:55 +0100 Subject: [PATCH 10/37] upgrade dependencies, retrieve clientId from bearer token or session --- build.sbt | 11 ++++++-- .../payment/model/ProviderDecorator.scala | 4 +-- .../service/BankAccountEndpoints.scala | 2 +- .../payment/service/CardEndpoints.scala | 7 ++++- .../service/GenericPaymentService.scala | 9 +++++-- project/Versions.scala | 8 +++--- .../payment/scalatest/PaymentTestKit.scala | 1 - .../payment/spi/MockMangoPayProvider.scala | 3 ++- .../payment/service/PaymentServiceSpec.scala | 27 ++++++++++++------- 9 files changed, 49 insertions(+), 23 deletions(-) diff --git a/build.sbt b/build.sbt index 9c289f4..a728258 100644 --- a/build.sbt +++ b/build.sbt @@ -2,7 +2,7 @@ ThisBuild / organization := "app.softnetwork" name := "payment" -ThisBuild / version := "0.5.0" +ThisBuild / version := "0.6.0" ThisBuild / scalaVersion := "2.12.18" @@ -49,6 +49,13 @@ lazy val mangopay = project.in(file("mangopay")) core % "compile->compile;test->test;it->it" ) +lazy val stripe = project.in(file("stripe")) + .configs(IntegrationTest) + .settings(Defaults.itSettings) + .dependsOn( + core % "compile->compile;test->test;it->it" + ) + lazy val api = project.in(file("mangopay/api")) .configs(IntegrationTest) .settings(Defaults.itSettings) @@ -65,6 +72,6 @@ lazy val testkit = project.in(file("testkit")) ) lazy val root = project.in(file(".")) - .aggregate(common, core, mangopay, testkit, api) + .aggregate(common, core, mangopay, stripe, testkit, api) .configs(IntegrationTest) .settings(Defaults.itSettings) diff --git a/common/src/main/scala/app/softnetwork/payment/model/ProviderDecorator.scala b/common/src/main/scala/app/softnetwork/payment/model/ProviderDecorator.scala index 8be9541..88beb0b 100644 --- a/common/src/main/scala/app/softnetwork/payment/model/ProviderDecorator.scala +++ b/common/src/main/scala/app/softnetwork/payment/model/ProviderDecorator.scala @@ -1,14 +1,14 @@ package app.softnetwork.payment.model -import app.softnetwork.account.model.{Principal, PrincipalType} import app.softnetwork.payment.spi.PaymentProviders +import app.softnetwork.security.sha256 trait ProviderDecorator { self: SoftPaymentAccount.Client.Provider => lazy val clientId = s"$providerId.${providerType.name.toLowerCase}" lazy val client: SoftPaymentAccount.Client = { PaymentProviders.paymentProvider(self).client match { - case Some(value) => value.withClientApiKey(self.providerApiKey) + case Some(value) => value.withClientApiKey(sha256(self.providerApiKey)) case _ => throw new Exception(s"PaymentProvider not found for providerType: ${providerType}") } diff --git a/core/src/main/scala/app/softnetwork/payment/service/BankAccountEndpoints.scala b/core/src/main/scala/app/softnetwork/payment/service/BankAccountEndpoints.scala index 346a763..8c8194d 100644 --- a/core/src/main/scala/app/softnetwork/payment/service/BankAccountEndpoints.scala +++ b/core/src/main/scala/app/softnetwork/payment/service/BankAccountEndpoints.scala @@ -71,7 +71,7 @@ trait BankAccountEndpoints[SD <: SessionData with SessionDataDecorator[SD]] { bankAccount.withExternalUuid(externalUuid), updatedUser, acceptedTermsOfPSP, - clientId = principal._1.map(_.clientId) + clientId = principal._1.map(_.clientId).orElse(principal._2.clientId) ) ).map { case r: BankAccountCreatedOrUpdated => Right(r) diff --git a/core/src/main/scala/app/softnetwork/payment/service/CardEndpoints.scala b/core/src/main/scala/app/softnetwork/payment/service/CardEndpoints.scala index 57f4537..216dc9f 100644 --- a/core/src/main/scala/app/softnetwork/payment/service/CardEndpoints.scala +++ b/core/src/main/scala/app/softnetwork/payment/service/CardEndpoints.scala @@ -59,7 +59,12 @@ trait CardEndpoints[SD <: SessionData with SessionDataDecorator[SD]] { updatedUser = updatedUser.withProfile(profile) case _ => } - run(cmd.copy(user = updatedUser, clientId = principal._1.map(_.clientId))).map { + run( + cmd.copy( + user = updatedUser, + clientId = principal._1.map(_.clientId).orElse(principal._2.clientId) + ) + ).map { case r: CardPreRegistered => Right(r.cardPreRegistration) case other => Left(error(other)) } diff --git a/core/src/main/scala/app/softnetwork/payment/service/GenericPaymentService.scala b/core/src/main/scala/app/softnetwork/payment/service/GenericPaymentService.scala index c43ada2..b99688e 100644 --- a/core/src/main/scala/app/softnetwork/payment/service/GenericPaymentService.scala +++ b/core/src/main/scala/app/softnetwork/payment/service/GenericPaymentService.scala @@ -98,7 +98,12 @@ trait GenericPaymentService[SD <: SessionData with SessionDataDecorator[SD]] updatedUser = updatedUser.withProfile(profile) case _ => } - run(cmd.copy(user = updatedUser, clientId = client.map(_.clientId))) completeWith { + run( + cmd.copy( + user = updatedUser, + clientId = client.map(_.clientId).orElse(session.clientId) + ) + ) completeWith { case r: CardPreRegistered => complete( HttpResponse( @@ -425,7 +430,7 @@ trait GenericPaymentService[SD <: SessionData with SessionDataDecorator[SD]] bankAccount.withExternalUuid(externalUuid), updatedUser, acceptedTermsOfPSP, - client.map(_.clientId) + client.map(_.clientId).orElse(session.clientId) ) ) completeWith { case r: BankAccountCreatedOrUpdated => diff --git a/project/Versions.scala b/project/Versions.scala index 5be3561..7e9cffb 100644 --- a/project/Versions.scala +++ b/project/Versions.scala @@ -1,12 +1,12 @@ object Versions { - val genericPersistence = "0.6.0" + val genericPersistence = "0.6.1" - val scheduler = "0.6.1" + val scheduler = "0.6.2" - val notification = "0.6.1" + val notification = "0.6.2" - val account = "0.6.0" + val account = "0.6.1" val scalatest = "3.2.16" } diff --git a/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentTestKit.scala b/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentTestKit.scala index 40b7828..2aa97b0 100644 --- a/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentTestKit.scala +++ b/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentTestKit.scala @@ -2,7 +2,6 @@ package app.softnetwork.payment.scalatest import akka.actor.typed.ActorSystem import app.softnetwork.account.config.AccountSettings -import app.softnetwork.account.handlers.AccountDao import app.softnetwork.account.model.BasicAccountProfile import app.softnetwork.account.persistence.query.AccountEventProcessorStreams.InternalAccountEvents2AccountProcessorStream import app.softnetwork.account.persistence.typed.AccountBehavior diff --git a/testkit/src/main/scala/app/softnetwork/payment/spi/MockMangoPayProvider.scala b/testkit/src/main/scala/app/softnetwork/payment/spi/MockMangoPayProvider.scala index cc19e48..4143a60 100644 --- a/testkit/src/main/scala/app/softnetwork/payment/spi/MockMangoPayProvider.scala +++ b/testkit/src/main/scala/app/softnetwork/payment/spi/MockMangoPayProvider.scala @@ -1729,5 +1729,6 @@ class MockMangoPayProviderFactory extends PaymentProviderSpi { override implicit def provider: Provider = p } - override def softPaymentProvider: Provider = MangoPay.softPaymentProvider + override def softPaymentProvider: Provider = + MangoPay.softPaymentProvider.withProviderType(providerType) } diff --git a/testkit/src/test/scala/app/softnetwork/payment/service/PaymentServiceSpec.scala b/testkit/src/test/scala/app/softnetwork/payment/service/PaymentServiceSpec.scala index 765b769..0d419e9 100644 --- a/testkit/src/test/scala/app/softnetwork/payment/service/PaymentServiceSpec.scala +++ b/testkit/src/test/scala/app/softnetwork/payment/service/PaymentServiceSpec.scala @@ -9,6 +9,7 @@ import app.softnetwork.payment.data._ import app.softnetwork.payment.config.PaymentSettings._ import app.softnetwork.payment.message.PaymentMessages._ import app.softnetwork.payment.model._ +import app.softnetwork.payment.persistence.typed.MockPaymentBehavior import app.softnetwork.payment.scalatest.PaymentRouteTestKit import app.softnetwork.time._ import app.softnetwork.persistence.now @@ -33,9 +34,17 @@ trait PaymentServiceSpec[SD <: SessionData with SessionDataDecorator[SD]] lazy val paymentClient: PaymentClient = PaymentClient(ts) + def clientId: String = MockPaymentBehavior.defaultProvider.clientId + + lazy val customerSession: SD with SessionDataDecorator[SD] = + companion.newSession.withId(customerUuid).withProfile(Some("customer")).withClientId(clientId) + + lazy val sellerSession: SD with SessionDataDecorator[SD] = + companion.newSession.withId(sellerUuid).withProfile(Some("seller")).withClientId(clientId) + "Payment service" must { "pre register card" in { - createSession(customerUuid, Some("customer")) + createNewSession(customerSession) withHeaders( Get(s"/$RootPath/$PaymentPath/$CardRoute") ) ~> routes ~> check { @@ -108,7 +117,7 @@ trait PaymentServiceSpec[SD <: SessionData with SessionDataDecorator[SD]] } "not create bank account with wrong iban" in { - createSession(sellerUuid, Some("seller")) + createNewSession(sellerSession) withHeaders( Post( s"/$RootPath/$PaymentPath/$BankRoute", @@ -334,7 +343,7 @@ trait PaymentServiceSpec[SD <: SessionData with SessionDataDecorator[SD]] } "pay in / out with pre authorized card" in { - createSession(customerUuid, Some("customer")) + createNewSession(customerSession) withHeaders( Post( s"/$RootPath/$PaymentPath/$PreAuthorizeCardRoute", @@ -377,7 +386,7 @@ trait PaymentServiceSpec[SD <: SessionData with SessionDataDecorator[SD]] } "pay in / out with 3ds" in { - createSession(customerUuid, Some("customer")) + createNewSession(customerSession) withHeaders( Post( s"/$RootPath/$PaymentPath/$PayInRoute/${URLEncoder @@ -430,7 +439,7 @@ trait PaymentServiceSpec[SD <: SessionData with SessionDataDecorator[SD]] } "pay in / out with PayPal" in { - createSession(customerUuid, Some("customer")) + createNewSession(customerSession) withHeaders( Post( s"/$RootPath/$PaymentPath/$PayInRoute/${URLEncoder @@ -479,7 +488,7 @@ trait PaymentServiceSpec[SD <: SessionData with SessionDataDecorator[SD]] } "create mandate" in { - createSession(sellerUuid, Some("seller")) + createNewSession(sellerSession) withHeaders( Post(s"/$RootPath/$PaymentPath/$MandateRoute") ) ~> routes ~> check { @@ -558,7 +567,7 @@ trait PaymentServiceSpec[SD <: SessionData with SessionDataDecorator[SD]] } "register recurring card payment" in { - createSession(customerUuid, Some("customer")) + createNewSession(customerSession) withHeaders( Post( s"/$RootPath/$PaymentPath/$RecurringPaymentRoute", @@ -635,7 +644,7 @@ trait PaymentServiceSpec[SD <: SessionData with SessionDataDecorator[SD]] } "cancel mandate" in { - createSession(sellerUuid, Some("seller")) + createNewSession(sellerSession) withHeaders( Delete(s"/$RootPath/$PaymentPath/$MandateRoute") ) ~> routes ~> check { @@ -667,7 +676,7 @@ trait PaymentServiceSpec[SD <: SessionData with SessionDataDecorator[SD]] } "disable card" in { - createSession(customerUuid, Some("customer")) + createNewSession(customerSession) withHeaders( Delete(s"/$RootPath/$PaymentPath/$CardRoute?cardId=$cardId") ) ~> routes ~> check { From a4b997e741ced25e8b2bc66f062115da5cdc56c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Manciot?= Date: Wed, 6 Dec 2023 14:24:52 +0100 Subject: [PATCH 11/37] update grpc client and server, clean mangopay resources --- common/src/main/resources/reference.conf | 5 + .../payment/api/PaymentClient.scala | 16 +- .../payment/api/PaymentClientSettings.scala | 22 ++ .../payment/model/ProviderDecorator.scala | 2 +- .../payment/api/PaymentGrpcService.scala | 49 +++++ .../payment/api/PaymentGrpcServices.scala | 10 + .../payment/api/PaymentServer.scala | 17 +- ...cPaymentHandler.scala => PaymentDao.scala} | 17 +- .../handlers/SoftPaymentAccountDao.scala | 46 ++++- .../payment/launch/PaymentApplication.scala | 7 +- .../payment/launch/PaymentEndpoints.scala | 4 +- .../payment/launch/PaymentGuardian.scala | 38 +++- .../payment/launch/PaymentRoutes.scala | 4 +- ...la => PaymentCommandProcessorStream.scala} | 6 +- .../Scheduler2PaymentProcessorStream.scala | 4 +- ...ntBehavior.scala => PaymentBehavior.scala} | 188 +++++++++++++----- .../service/BankAccountEndpoints.scala | 4 +- .../payment/service/BasicPaymentService.scala | 4 +- .../payment/service/CardEndpoints.scala | 4 +- .../service/CardPaymentEndpoints.scala | 4 +- .../payment/service/ClientSession.scala | 22 +- .../service/ClientSessionDirectives.scala | 2 +- .../service/ClientSessionEndpoints.scala | 2 +- .../service/KycDocumentEndpoints.scala | 4 +- .../payment/service/MandateEndpoints.scala | 4 +- ...mentService.scala => PaymentService.scala} | 6 +- ...ts.scala => PaymentServiceEndpoints.scala} | 6 +- .../service/RecurringPaymentEndpoints.scala | 4 +- .../service/RootPaymentEndpoints.scala | 4 +- .../service/UboDeclarationEndpoints.scala | 4 +- .../softnetwork/payment/api/MangoPayApi.scala | 61 ++---- .../payment/api/MangoPayEndpoints.scala | 8 +- .../MangoPayEndpointsPostgresLauncher.scala | 6 +- .../payment/api/MangoPayRoutes.scala | 4 +- .../api/MangoPayRoutesPostgresLauncher.scala | 4 +- .../api/MangoPayWithSchedulerApi.scala | 2 +- ...thSchedulerEndpointsPostgresLauncher.scala | 6 +- ...yWithSchedulerRoutesPostgresLauncher.scala | 4 +- .../payment/api/MangoPayServer.scala | 16 -- .../payment/handlers/MangoPayPaymentDao.scala | 7 - .../handlers/MangoPayPaymentHandler.scala | 9 - .../handlers/MangoPayPaymentTypeKey.scala | 15 -- ...angoPayPaymentCommandProcessorStream.scala | 10 - .../typed/MangoPayPaymentBehavior.scala | 13 -- .../service/MangoPayPaymentService.scala | 6 +- ... => MangoPayPaymentServiceEndpoints.scala} | 8 +- project/Versions.scala | 8 +- .../payment/api/PaymentClientTestKit.scala | 16 ++ ...r.scala => PaymentGrpcServerTestKit.scala} | 4 +- ...scala => PaymentGrpcServicesTestKit.scala} | 23 +-- .../payment/handlers/MockPaymentDao.scala | 2 +- .../payment/handlers/MockPaymentHandler.scala | 2 +- .../MockPaymentCommandProcessorStream.scala | 10 - .../typed/MockPaymentBehavior.scala | 11 +- .../scalatest/PaymentEndpointsTestKit.scala | 10 +- .../scalatest/PaymentRouteTestKit.scala | 4 +- .../scalatest/PaymentRoutesTestKit.scala | 6 +- .../payment/scalatest/PaymentTestKit.scala | 59 ++++-- ...cala => MockPaymentServiceEndpoints.scala} | 4 +- .../payment/handlers/PaymentHandlerSpec.scala | 46 +++-- .../payment/service/PaymentServiceSpec.scala | 3 - 61 files changed, 542 insertions(+), 354 deletions(-) create mode 100644 common/src/main/scala/app/softnetwork/payment/api/PaymentClientSettings.scala create mode 100644 core/src/main/scala/app/softnetwork/payment/api/PaymentGrpcService.scala create mode 100644 core/src/main/scala/app/softnetwork/payment/api/PaymentGrpcServices.scala rename core/src/main/scala/app/softnetwork/payment/handlers/{GenericPaymentHandler.scala => PaymentDao.scala} (92%) rename core/src/main/scala/app/softnetwork/payment/persistence/query/{GenericPaymentCommandProcessorStream.scala => PaymentCommandProcessorStream.scala} (97%) rename core/src/main/scala/app/softnetwork/payment/persistence/typed/{GenericPaymentBehavior.scala => PaymentBehavior.scala} (96%) rename core/src/main/scala/app/softnetwork/payment/service/{GenericPaymentService.scala => PaymentService.scala} (99%) rename core/src/main/scala/app/softnetwork/payment/service/{GenericPaymentEndpoints.scala => PaymentServiceEndpoints.scala} (91%) delete mode 100644 mangopay/src/main/scala/app/softnetwork/payment/api/MangoPayServer.scala delete mode 100644 mangopay/src/main/scala/app/softnetwork/payment/handlers/MangoPayPaymentDao.scala delete mode 100644 mangopay/src/main/scala/app/softnetwork/payment/handlers/MangoPayPaymentHandler.scala delete mode 100644 mangopay/src/main/scala/app/softnetwork/payment/handlers/MangoPayPaymentTypeKey.scala delete mode 100644 mangopay/src/main/scala/app/softnetwork/payment/persistence/query/MangoPayPaymentCommandProcessorStream.scala delete mode 100644 mangopay/src/main/scala/app/softnetwork/payment/persistence/typed/MangoPayPaymentBehavior.scala rename mangopay/src/main/scala/app/softnetwork/payment/service/{MangoPayPaymentEndpoints.scala => MangoPayPaymentServiceEndpoints.scala} (97%) create mode 100644 testkit/src/main/scala/app/softnetwork/payment/api/PaymentClientTestKit.scala rename testkit/src/main/scala/app/softnetwork/payment/api/{PaymentGrpcServer.scala => PaymentGrpcServerTestKit.scala} (88%) rename testkit/src/main/scala/app/softnetwork/payment/api/{PaymentGrpcServices.scala => PaymentGrpcServicesTestKit.scala} (62%) delete mode 100644 testkit/src/main/scala/app/softnetwork/payment/persistence/query/MockPaymentCommandProcessorStream.scala rename testkit/src/main/scala/app/softnetwork/payment/service/{MockPaymentEndpoints.scala => MockPaymentServiceEndpoints.scala} (68%) diff --git a/common/src/main/resources/reference.conf b/common/src/main/resources/reference.conf index 53521e0..d21c707 100644 --- a/common/src/main/resources/reference.conf +++ b/common/src/main/resources/reference.conf @@ -51,6 +51,11 @@ payment{ external-to-payment-account-tag = "external-to-payment-account" } + client-id = "" + client-id = ${?PAYMENT_CLIENT_ID} + + api-key = "" + api-key = ${?PAYMENT_API_KEY} } auth { diff --git a/common/src/main/scala/app/softnetwork/payment/api/PaymentClient.scala b/common/src/main/scala/app/softnetwork/payment/api/PaymentClient.scala index 5d55217..fec77b6 100644 --- a/common/src/main/scala/app/softnetwork/payment/api/PaymentClient.scala +++ b/common/src/main/scala/app/softnetwork/payment/api/PaymentClient.scala @@ -22,15 +22,19 @@ trait PaymentClient extends GrpcClient { GrpcClientSettings.fromConfig(name) ) + @InternalApi + private[payment] def paymentClientSettings: PaymentClientSettings = PaymentClientSettings(system) + + @InternalApi + private[payment] lazy val generatedToken: String = + paymentClientSettings.generateToken() + @InternalApi private[payment] def withAuthorization[Req, Res]( single: SingleResponseRequestBuilder[Req, Res], token: Option[String] ): SingleResponseRequestBuilder[Req, Res] = { - token match { - case Some(t) => single.addHeader("Authorization", s"Bearer $t") - case _ => single - } + oauth2(single, token.getOrElse(generatedToken)) } def createOrUpdatePaymentAccount( @@ -42,7 +46,9 @@ trait PaymentClient extends GrpcClient { token ) .invoke( - CreateOrUpdatePaymentAccountRequest(Some(paymentAccount)) + CreateOrUpdatePaymentAccountRequest( + Some(paymentAccount.withClientId(paymentClientSettings.clientId)) + ) ) map (_.succeeded) } diff --git a/common/src/main/scala/app/softnetwork/payment/api/PaymentClientSettings.scala b/common/src/main/scala/app/softnetwork/payment/api/PaymentClientSettings.scala new file mode 100644 index 0000000..1dcb5f4 --- /dev/null +++ b/common/src/main/scala/app/softnetwork/payment/api/PaymentClientSettings.scala @@ -0,0 +1,22 @@ +package app.softnetwork.payment.api + +import akka.actor.typed.ActorSystem +import org.softnetwork.session.model.JwtClaims + +case class PaymentClientSettings(clientId: String, apiKey: String) { + def generateToken(): String = + JwtClaims.newSession + .withClientId(clientId) + .encode(clientId, apiKey) + +} + +object PaymentClientSettings { + def apply(system: ActorSystem[_]): PaymentClientSettings = { + val clientConfig = system.settings.config.getConfig("payment") + PaymentClientSettings( + clientId = clientConfig.getString("client-id"), + apiKey = clientConfig.getString("api-key") + ) + } +} diff --git a/common/src/main/scala/app/softnetwork/payment/model/ProviderDecorator.scala b/common/src/main/scala/app/softnetwork/payment/model/ProviderDecorator.scala index 88beb0b..56dcd72 100644 --- a/common/src/main/scala/app/softnetwork/payment/model/ProviderDecorator.scala +++ b/common/src/main/scala/app/softnetwork/payment/model/ProviderDecorator.scala @@ -10,7 +10,7 @@ trait ProviderDecorator { self: SoftPaymentAccount.Client.Provider => PaymentProviders.paymentProvider(self).client match { case Some(value) => value.withClientApiKey(sha256(self.providerApiKey)) case _ => - throw new Exception(s"PaymentProvider not found for providerType: ${providerType}") + throw new Exception(s"PaymentProvider not found for providerType: $providerType") } } diff --git a/core/src/main/scala/app/softnetwork/payment/api/PaymentGrpcService.scala b/core/src/main/scala/app/softnetwork/payment/api/PaymentGrpcService.scala new file mode 100644 index 0000000..368e06f --- /dev/null +++ b/core/src/main/scala/app/softnetwork/payment/api/PaymentGrpcService.scala @@ -0,0 +1,49 @@ +package app.softnetwork.payment.api + +import akka.actor.typed.ActorSystem +import akka.http.scaladsl.model.headers.HttpChallenges +import akka.http.scaladsl.model.{HttpRequest, HttpResponse} +import akka.http.scaladsl.server.{AuthenticationFailedRejection, Route} +import akka.http.scaladsl.server.directives.Credentials +import app.softnetwork.account.config.AccountSettings +import app.softnetwork.api.server.GrpcService +import app.softnetwork.concurrent.Completion +import app.softnetwork.payment.handlers.SoftPaymentAccountDao + +import scala.concurrent.Future + +class PaymentGrpcService(server: PaymentServer, softPaymentAccountDao: SoftPaymentAccountDao) + extends GrpcService + with Completion { + override def grpcService: ActorSystem[_] => PartialFunction[HttpRequest, Future[HttpResponse]] = + system => PaymentServiceApiHandler.partial(server)(system) + + override def route: ActorSystem[_] => Route = system => + authenticateOAuth2Async( + AccountSettings.Realm, + { + case _ @Credentials.Provided(token) => + softPaymentAccountDao.authenticateClient(Some(token))(system) + case _ => Future.successful(None) + } + ).optional { + case (Some(client)) => + handle( + grpcService(system), + Seq( + AuthenticationFailedRejection( + AuthenticationFailedRejection.CredentialsRejected, + HttpChallenges.oAuth2(AccountSettings.Realm) + ) + ) + ) + case _ => + reject( + AuthenticationFailedRejection( + AuthenticationFailedRejection.CredentialsRejected, + HttpChallenges.oAuth2(AccountSettings.Realm) + ) + ) + } + +} diff --git a/core/src/main/scala/app/softnetwork/payment/api/PaymentGrpcServices.scala b/core/src/main/scala/app/softnetwork/payment/api/PaymentGrpcServices.scala new file mode 100644 index 0000000..7f43d42 --- /dev/null +++ b/core/src/main/scala/app/softnetwork/payment/api/PaymentGrpcServices.scala @@ -0,0 +1,10 @@ +package app.softnetwork.payment.api + +import akka.actor.typed.ActorSystem +import app.softnetwork.api.server.{GrpcService, GrpcServices} +import app.softnetwork.payment.launch.PaymentGuardian + +trait PaymentGrpcServices extends GrpcServices { _: PaymentGuardian => + override def grpcServices: ActorSystem[_] => Seq[GrpcService] = system => + paymentGrpcServices(system) +} diff --git a/core/src/main/scala/app/softnetwork/payment/api/PaymentServer.scala b/core/src/main/scala/app/softnetwork/payment/api/PaymentServer.scala index ac5f8e0..2c94252 100644 --- a/core/src/main/scala/app/softnetwork/payment/api/PaymentServer.scala +++ b/core/src/main/scala/app/softnetwork/payment/api/PaymentServer.scala @@ -1,7 +1,7 @@ package app.softnetwork.payment.api import akka.actor.typed.ActorSystem -import app.softnetwork.payment.handlers.{GenericPaymentHandler, SoftPaymentAccountDao} +import app.softnetwork.payment.handlers.{PaymentHandler, SoftPaymentAccountDao} import app.softnetwork.payment.message.PaymentMessages.{ BankAccountLoaded, CancelMandate, @@ -23,7 +23,6 @@ import app.softnetwork.payment.message.PaymentMessages.{ PaymentAccountCreated, PaymentAccountLoaded, PaymentAccountUpdated, - PaymentCommand, PaymentError, PreAuthorizationCanceled, RecurringPaymentRegistered, @@ -37,13 +36,12 @@ import app.softnetwork.payment.message.PaymentMessages.{ } import app.softnetwork.payment.model.RecurringPayment import app.softnetwork.payment.serialization._ -import app.softnetwork.persistence.typed.CommandTypeKey +import org.slf4j.{Logger, LoggerFactory} import scala.concurrent.{ExecutionContextExecutor, Future} import scala.language.implicitConversions -trait PaymentServer extends PaymentServiceApi with GenericPaymentHandler { - _: CommandTypeKey[PaymentCommand] => +trait PaymentServer extends PaymentServiceApi with PaymentHandler { implicit def system: ActorSystem[_] implicit lazy val ec: ExecutionContextExecutor = system.executionContext @@ -385,3 +383,12 @@ trait PaymentServer extends PaymentServiceApi with GenericPaymentHandler { } } } + +object PaymentServer { + def apply(sys: ActorSystem[_]): PaymentServer = { + new PaymentServer { + lazy val log: Logger = LoggerFactory getLogger getClass.getName + override implicit val system: ActorSystem[_] = sys + } + } +} diff --git a/core/src/main/scala/app/softnetwork/payment/handlers/GenericPaymentHandler.scala b/core/src/main/scala/app/softnetwork/payment/handlers/PaymentDao.scala similarity index 92% rename from core/src/main/scala/app/softnetwork/payment/handlers/GenericPaymentHandler.scala rename to core/src/main/scala/app/softnetwork/payment/handlers/PaymentDao.scala index 631e948..59ac1e1 100644 --- a/core/src/main/scala/app/softnetwork/payment/handlers/GenericPaymentHandler.scala +++ b/core/src/main/scala/app/softnetwork/payment/handlers/PaymentDao.scala @@ -1,19 +1,26 @@ package app.softnetwork.payment.handlers import akka.actor.typed.ActorSystem +import akka.cluster.sharding.typed.scaladsl.EntityTypeKey import app.softnetwork.kv.handlers.GenericKeyValueDao import app.softnetwork.payment.message.PaymentMessages._ import app.softnetwork.persistence.typed.scaladsl.EntityPattern import app.softnetwork.payment.model._ +import app.softnetwork.payment.persistence.typed.PaymentBehavior import app.softnetwork.persistence._ import app.softnetwork.persistence.typed.CommandTypeKey +import org.slf4j.{Logger, LoggerFactory} import scala.concurrent.{ExecutionContextExecutor, Future} import scala.language.implicitConversions import scala.reflect.ClassTag -trait GenericPaymentHandler extends EntityPattern[PaymentCommand, PaymentResult] { - _: CommandTypeKey[PaymentCommand] => +trait PaymentTypeKey extends CommandTypeKey[PaymentCommand] { + override def TypeKey(implicit tTag: ClassTag[PaymentCommand]): EntityTypeKey[PaymentCommand] = + PaymentBehavior.TypeKey +} + +trait PaymentHandler extends EntityPattern[PaymentCommand, PaymentResult] with PaymentTypeKey { lazy val keyValueDao: GenericKeyValueDao = PaymentKvDao //FIXME app.softnetwork.payment.persistence.data.paymentKvDao @@ -46,7 +53,7 @@ trait GenericPaymentHandler extends EntityPattern[PaymentCommand, PaymentResult] } } -trait GenericPaymentDao { _: GenericPaymentHandler => +trait PaymentDao { _: PaymentHandler => protected[payment] def loadPaymentAccount( key: String @@ -236,3 +243,7 @@ trait GenericPaymentDao { _: GenericPaymentHandler => } } } + +object PaymentDao extends PaymentDao with PaymentHandler { + lazy val log: Logger = LoggerFactory.getLogger(getClass.getName) +} diff --git a/core/src/main/scala/app/softnetwork/payment/handlers/SoftPaymentAccountDao.scala b/core/src/main/scala/app/softnetwork/payment/handlers/SoftPaymentAccountDao.scala index bc47962..127f674 100644 --- a/core/src/main/scala/app/softnetwork/payment/handlers/SoftPaymentAccountDao.scala +++ b/core/src/main/scala/app/softnetwork/payment/handlers/SoftPaymentAccountDao.scala @@ -15,7 +15,9 @@ import app.softnetwork.payment.message.AccountMessages import app.softnetwork.payment.model.SoftPaymentAccount import app.softnetwork.payment.persistence.typed.SoftPaymentAccountBehavior import app.softnetwork.persistence.typed.CommandTypeKey -import org.softnetwork.session.model.ApiKey +import app.softnetwork.session.model.JwtClaimsEncoder +import com.softwaremill.session.SessionConfig +import org.softnetwork.session.model.{ApiKey, JwtClaims} import org.slf4j.{Logger, LoggerFactory} import scala.concurrent.{ExecutionContext, Future} @@ -110,6 +112,48 @@ trait SoftPaymentAccountDao extends AccountDao { _: AccountHandler => } } + def authenticateClient( + token: Option[String] + )(implicit system: ActorSystem[_]): Future[Option[SoftPaymentAccount.Client]] = { + token match { + case Some(value) => + implicit val ec: ExecutionContext = system.executionContext + oauthClient(value) flatMap { + case Some(client) => Future.successful(Some(client)) + case _ => + val t = JwtClaims(value) + t.clientId match { + case Some(clientId) => + loadApiKey(clientId) flatMap { + case Some(apiKey) if apiKey.clientSecret.isDefined => + val config = SessionConfig.default(apiKey.getClientSecret) + JwtClaimsEncoder + .decode( + value, + config.copy(jwt = + config.jwt.copy( + issuer = t.issuer.orElse(config.jwt.issuer), + subject = t.subject.orElse(config.jwt.subject), + audience = t.aud.orElse(config.jwt.audience) + ) + ) + ) + .toOption match { + case Some(result) if result.signatureMatches => + loadClient(clientId) flatMap { + case Some(client) => Future.successful(Some(client)) + case _ => Future.successful(None) + } + case _ => Future.successful(None) + } + case _ => Future.successful(None) + } + case _ => Future.successful(None) + } + } + case _ => Future.successful(None) + } + } } trait SoftPaymentAccountTypeKey extends CommandTypeKey[AccountCommand] { diff --git a/core/src/main/scala/app/softnetwork/payment/launch/PaymentApplication.scala b/core/src/main/scala/app/softnetwork/payment/launch/PaymentApplication.scala index b52b13e..843d8df 100644 --- a/core/src/main/scala/app/softnetwork/payment/launch/PaymentApplication.scala +++ b/core/src/main/scala/app/softnetwork/payment/launch/PaymentApplication.scala @@ -2,10 +2,15 @@ package app.softnetwork.payment.launch import app.softnetwork.api.server.ApiRoutes import app.softnetwork.api.server.launch.Application +import app.softnetwork.payment.api.PaymentGrpcServices import app.softnetwork.persistence.schema.SchemaProvider import app.softnetwork.session.CsrfCheck -trait PaymentApplication extends Application with ApiRoutes with PaymentGuardian { +trait PaymentApplication + extends Application + with ApiRoutes + with PaymentGuardian + with PaymentGrpcServices { _: SchemaProvider with CsrfCheck => override val applicationVersion = systemVersion() } diff --git a/core/src/main/scala/app/softnetwork/payment/launch/PaymentEndpoints.scala b/core/src/main/scala/app/softnetwork/payment/launch/PaymentEndpoints.scala index 451c002..47d703c 100644 --- a/core/src/main/scala/app/softnetwork/payment/launch/PaymentEndpoints.scala +++ b/core/src/main/scala/app/softnetwork/payment/launch/PaymentEndpoints.scala @@ -7,7 +7,7 @@ import app.softnetwork.account.model.BasicAccountProfile import app.softnetwork.api.server.{ApiEndpoints, Endpoint} import app.softnetwork.payment.model.SoftPaymentAccount import app.softnetwork.payment.serialization.paymentFormats -import app.softnetwork.payment.service.GenericPaymentEndpoints +import app.softnetwork.payment.service.PaymentServiceEndpoints import app.softnetwork.persistence.schema.SchemaProvider import app.softnetwork.session.CsrfCheck import app.softnetwork.session.model.{SessionData, SessionDataDecorator} @@ -24,7 +24,7 @@ trait PaymentEndpoints[SD <: SessionData with SessionDataDecorator[SD]] override implicit def formats: Formats = paymentFormats - def paymentEndpoints: ActorSystem[_] => GenericPaymentEndpoints[SD] + def paymentEndpoints: ActorSystem[_] => PaymentServiceEndpoints[SD] override def endpoints: ActorSystem[_] => List[Endpoint] = system => diff --git a/core/src/main/scala/app/softnetwork/payment/launch/PaymentGuardian.scala b/core/src/main/scala/app/softnetwork/payment/launch/PaymentGuardian.scala index 89df7a3..33384f4 100644 --- a/core/src/main/scala/app/softnetwork/payment/launch/PaymentGuardian.scala +++ b/core/src/main/scala/app/softnetwork/payment/launch/PaymentGuardian.scala @@ -4,15 +4,18 @@ import akka.actor.typed.ActorSystem import app.softnetwork.account.handlers.AccountDao import app.softnetwork.account.launch.AccountGuardian import app.softnetwork.account.model.BasicAccountProfile +import app.softnetwork.account.persistence.typed.AccountBehavior +import app.softnetwork.api.server.GrpcService import app.softnetwork.payment.PaymentCoreBuildInfo +import app.softnetwork.payment.api.{PaymentGrpcService, PaymentServer} import app.softnetwork.payment.handlers.SoftPaymentAccountDao import app.softnetwork.payment.model.SoftPaymentAccount import app.softnetwork.payment.persistence.data.paymentKvDao import app.softnetwork.payment.persistence.query.{ - GenericPaymentCommandProcessorStream, + PaymentCommandProcessorStream, Scheduler2PaymentProcessorStream } -import app.softnetwork.payment.persistence.typed.GenericPaymentBehavior +import app.softnetwork.payment.persistence.typed.{PaymentBehavior, SoftPaymentAccountBehavior} import app.softnetwork.payment.spi.PaymentProviders import app.softnetwork.persistence.launch.PersistentEntity import app.softnetwork.persistence.query.EventProcessorStream @@ -27,11 +30,15 @@ trait PaymentGuardian extends AccountGuardian[SoftPaymentAccount, BasicAccountPr import app.softnetwork.persistence.launch.PersistenceGuardian._ - def paymentAccountBehavior: ActorSystem[_] => GenericPaymentBehavior + def paymentBehavior: ActorSystem[_] => PaymentBehavior = _ => PaymentBehavior + + override def accountBehavior + : ActorSystem[_] => AccountBehavior[SoftPaymentAccount, BasicAccountProfile] = _ => + SoftPaymentAccountBehavior def paymentEntities: ActorSystem[_] => Seq[PersistentEntity[_, _, _, _]] = sys => Seq( - paymentAccountBehavior(sys) + paymentBehavior(sys) ) /** initialize all entities @@ -43,7 +50,7 @@ trait PaymentGuardian extends AccountGuardian[SoftPaymentAccount, BasicAccountPr */ override def singletons: ActorSystem[_] => Seq[Singleton[_]] = _ => Seq(paymentKvDao) - def paymentCommandProcessorStream: ActorSystem[_] => GenericPaymentCommandProcessorStream + def paymentCommandProcessorStream: ActorSystem[_] => PaymentCommandProcessorStream def scheduler2PaymentProcessorStream: ActorSystem[_] => Scheduler2PaymentProcessorStream @@ -62,6 +69,13 @@ trait PaymentGuardian extends AccountGuardian[SoftPaymentAccount, BasicAccountPr final override def accountDao: AccountDao = softPaymentAccountDao + def paymentServer: ActorSystem[_] => PaymentServer = system => PaymentServer(system) + + def paymentGrpcServices: ActorSystem[_] => Seq[GrpcService] = system => + Seq( + new PaymentGrpcService(paymentServer(system), softPaymentAccountDao) + ) + def registerProvidersAccount: ActorSystem[_] => Unit = system => { PaymentProviders.defaultPaymentProviders.foreach(provider => { implicit val ec: ExecutionContext = system.executionContext @@ -79,4 +93,18 @@ trait PaymentGuardian extends AccountGuardian[SoftPaymentAccount, BasicAccountPr super.initSystem(system) } + override def banner: String = + """ + |█████████ ██████ █████ ███████████ █████ + | ███░░░░░███ ███░░███ ░░███ ░░███░░░░░███ ░░███ + |░███ ░░░ ██████ ░███ ░░░ ███████ ░███ ░███ ██████ █████ ████ █████████████ ██████ ████████ ███████ + |░░█████████ ███░░███ ███████ ░░░███░ ░██████████ ░░░░░███ ░░███ ░███ ░░███░░███░░███ ███░░███░░███░░███ ░░░███░ + | ░░░░░░░░███░███ ░███░░░███░ ░███ ░███░░░░░░ ███████ ░███ ░███ ░███ ░███ ░███ ░███████ ░███ ░███ ░███ + | ███ ░███░███ ░███ ░███ ░███ ███ ░███ ███░░███ ░███ ░███ ░███ ░███ ░███ ░███░░░ ░███ ░███ ░███ ███ + |░░█████████ ░░██████ █████ ░░█████ █████ ░░████████ ░░███████ █████░███ █████░░██████ ████ █████ ░░█████ + | ░░░░░░░░░ ░░░░░░ ░░░░░ ░░░░░ ░░░░░ ░░░░░░░░ ░░░░░███ ░░░░░ ░░░ ░░░░░ ░░░░░░ ░░░░ ░░░░░ ░░░░░ + | ███ ░███ + | ░░██████ + | ░░░░░░ + |""".stripMargin } diff --git a/core/src/main/scala/app/softnetwork/payment/launch/PaymentRoutes.scala b/core/src/main/scala/app/softnetwork/payment/launch/PaymentRoutes.scala index 57a19f5..38a75d7 100644 --- a/core/src/main/scala/app/softnetwork/payment/launch/PaymentRoutes.scala +++ b/core/src/main/scala/app/softnetwork/payment/launch/PaymentRoutes.scala @@ -11,7 +11,7 @@ import app.softnetwork.account.model.{ import app.softnetwork.api.server.ApiRoute import app.softnetwork.payment.model.SoftPaymentAccount import app.softnetwork.payment.serialization.paymentFormats -import app.softnetwork.payment.service.GenericPaymentService +import app.softnetwork.payment.service.PaymentService import app.softnetwork.persistence.schema.SchemaProvider import app.softnetwork.session.CsrfCheck import app.softnetwork.session.model.{SessionData, SessionDataDecorator} @@ -29,7 +29,7 @@ trait PaymentRoutes[SD <: SessionData with SessionDataDecorator[SD]] override implicit def formats: Formats = paymentFormats - def paymentService: ActorSystem[_] => GenericPaymentService[SD] + def paymentService: ActorSystem[_] => PaymentService[SD] override def apiRoutes: ActorSystem[_] => List[ApiRoute] = system => diff --git a/core/src/main/scala/app/softnetwork/payment/persistence/query/GenericPaymentCommandProcessorStream.scala b/core/src/main/scala/app/softnetwork/payment/persistence/query/PaymentCommandProcessorStream.scala similarity index 97% rename from core/src/main/scala/app/softnetwork/payment/persistence/query/GenericPaymentCommandProcessorStream.scala rename to core/src/main/scala/app/softnetwork/payment/persistence/query/PaymentCommandProcessorStream.scala index 48c93d7..86af8fe 100644 --- a/core/src/main/scala/app/softnetwork/payment/persistence/query/GenericPaymentCommandProcessorStream.scala +++ b/core/src/main/scala/app/softnetwork/payment/persistence/query/PaymentCommandProcessorStream.scala @@ -3,7 +3,7 @@ package app.softnetwork.payment.persistence.query import akka.Done import akka.actor.typed.eventstream.EventStream.Publish import akka.persistence.typed.PersistenceId -import app.softnetwork.payment.handlers.GenericPaymentHandler +import app.softnetwork.payment.handlers.PaymentHandler import app.softnetwork.payment.message.PaymentEvents._ import app.softnetwork.payment.message.PaymentMessages._ import app.softnetwork.payment.config.PaymentSettings @@ -11,8 +11,8 @@ import app.softnetwork.persistence.query.{EventProcessorStream, JournalProvider, import scala.concurrent.Future -trait GenericPaymentCommandProcessorStream extends EventProcessorStream[PaymentEventWithCommand] { - _: JournalProvider with OffsetProvider with GenericPaymentHandler => +trait PaymentCommandProcessorStream extends EventProcessorStream[PaymentEventWithCommand] { + _: JournalProvider with OffsetProvider with PaymentHandler => override lazy val tag: String = PaymentSettings.ExternalToPaymentAccountTag diff --git a/core/src/main/scala/app/softnetwork/payment/persistence/query/Scheduler2PaymentProcessorStream.scala b/core/src/main/scala/app/softnetwork/payment/persistence/query/Scheduler2PaymentProcessorStream.scala index 0454cd6..8a65d04 100644 --- a/core/src/main/scala/app/softnetwork/payment/persistence/query/Scheduler2PaymentProcessorStream.scala +++ b/core/src/main/scala/app/softnetwork/payment/persistence/query/Scheduler2PaymentProcessorStream.scala @@ -1,7 +1,7 @@ package app.softnetwork.payment.persistence.query import akka.actor.typed.eventstream.EventStream.Publish -import app.softnetwork.payment.handlers.GenericPaymentHandler +import app.softnetwork.payment.handlers.PaymentHandler import app.softnetwork.payment.message.PaymentMessages.{ PaymentCommand, PaymentResult, @@ -16,7 +16,7 @@ import scala.concurrent.Future trait Scheduler2PaymentProcessorStream extends Scheduler2EntityProcessorStream[PaymentCommand, PaymentResult] { - _: GenericPaymentHandler with JournalProvider with OffsetProvider => + _: PaymentHandler with JournalProvider with OffsetProvider => /** @param schedule * - the schedule to trigger diff --git a/core/src/main/scala/app/softnetwork/payment/persistence/typed/GenericPaymentBehavior.scala b/core/src/main/scala/app/softnetwork/payment/persistence/typed/PaymentBehavior.scala similarity index 96% rename from core/src/main/scala/app/softnetwork/payment/persistence/typed/GenericPaymentBehavior.scala rename to core/src/main/scala/app/softnetwork/payment/persistence/typed/PaymentBehavior.scala index b661b04..ff1196d 100644 --- a/core/src/main/scala/app/softnetwork/payment/persistence/typed/GenericPaymentBehavior.scala +++ b/core/src/main/scala/app/softnetwork/payment/persistence/typed/PaymentBehavior.scala @@ -6,9 +6,10 @@ import akka.cluster.sharding.typed.ShardingEnvelope import akka.persistence.typed.scaladsl.Effect import app.softnetwork.kv.handlers.GenericKeyValueDao import app.softnetwork.payment.annotation.InternalApi +import app.softnetwork.payment.api.PaymentClientSettings import app.softnetwork.payment.config.PaymentSettings import app.softnetwork.payment.config.PaymentSettings.{AkkaNodeRole, PayInStatementDescriptor} -import app.softnetwork.payment.handlers.{GenericPaymentDao, PaymentKvDao, SoftPaymentAccountDao} +import app.softnetwork.payment.handlers.{PaymentDao, PaymentKvDao, SoftPaymentAccountDao} import app.softnetwork.payment.message.PaymentEvents._ import app.softnetwork.payment.message.PaymentMessages._ import app.softnetwork.payment.message.TransactionEvents._ @@ -38,7 +39,7 @@ import scala.util.{Failure, Success} /** Created by smanciot on 22/04/2022. */ -trait GenericPaymentBehavior +trait PaymentBehavior extends TimeStampedBehavior[ PaymentCommand, PaymentAccount, @@ -54,12 +55,10 @@ trait GenericPaymentBehavior val nextRecurringPayment: String = "NextRecurringPayment" - def paymentDao: GenericPaymentDao + def paymentDao: PaymentDao = PaymentDao def softPaymentAccountDao: SoftPaymentAccountDao = SoftPaymentAccountDao - def defaultProvider: SoftPaymentAccount.Client.Provider - /** @return * node role required to start this actor */ @@ -112,6 +111,8 @@ trait GenericPaymentBehavior ): Effect[ExternalSchedulerEvent, Option[PaymentAccount]] = { implicit val system: ActorSystem[_] = context.system implicit val log: Logger = context.log + implicit val paymentClientSettings: PaymentClientSettings = PaymentClientSettings(system) + val internalClientId = Option(paymentClientSettings.clientId) command match { case cmd: CreateOrUpdatePaymentAccount => @@ -200,7 +201,10 @@ trait GenericPaymentBehavior var registerWallet: Boolean = false loadPaymentAccount(entityId, state, PaymentAccount.User.NaturalUser(user), clientId) match { case Some(paymentAccount) => - val paymentProvider = loadPaymentProvider(paymentAccount.clientId) + val clientId = paymentAccount.clientId.orElse( + internalClientId + ) + val paymentProvider = loadPaymentProvider(clientId) import paymentProvider._ val lastUpdated = now() (paymentAccount.userId match { @@ -336,7 +340,10 @@ trait GenericPaymentBehavior import cmd._ state match { case Some(paymentAccount) => - val paymentProvider = loadPaymentProvider(paymentAccount.clientId) + val clientId = paymentAccount.clientId.orElse( + internalClientId + ) + val paymentProvider = loadPaymentProvider(clientId) import paymentProvider._ paymentAccount.getNaturalUser.userId match { case Some(userId) => @@ -389,7 +396,10 @@ trait GenericPaymentBehavior import cmd._ state match { case Some(paymentAccount) => - val paymentProvider = loadPaymentProvider(paymentAccount.clientId) + val clientId = paymentAccount.clientId.orElse( + internalClientId + ) + val paymentProvider = loadPaymentProvider(clientId) import paymentProvider._ loadCardPreAuthorized(orderUuid, preAuthorizationId) match { case Some(transaction) => @@ -411,7 +421,10 @@ trait GenericPaymentBehavior import cmd._ state match { case Some(paymentAccount) => - val paymentProvider = loadPaymentProvider(paymentAccount.clientId) + val clientId = paymentAccount.clientId.orElse( + internalClientId + ) + val paymentProvider = loadPaymentProvider(clientId) import paymentProvider._ paymentAccount.transactions.find(_.id == cardPreAuthorizedTransactionId) match { case Some(preAuthorizationTransaction) => @@ -503,7 +516,10 @@ trait GenericPaymentBehavior case Success(s) => s match { case Some(creditedPaymentAccount) => - val paymentProvider = loadPaymentProvider(creditedPaymentAccount.clientId) + val clientId = creditedPaymentAccount.clientId.orElse( + internalClientId + ) + val paymentProvider = loadPaymentProvider(clientId) import paymentProvider._ creditedPaymentAccount.walletId match { case Some(creditedWalletId) => @@ -572,7 +588,10 @@ trait GenericPaymentBehavior import cmd._ state match { case Some(paymentAccount) => - val paymentProvider = loadPaymentProvider(paymentAccount.clientId) + val clientId = paymentAccount.clientId.orElse( + internalClientId + ) + val paymentProvider = loadPaymentProvider(clientId) import paymentProvider._ paymentType match { case Transaction.PaymentType.CARD => @@ -750,7 +769,10 @@ trait GenericPaymentBehavior import cmd._ state match { case Some(paymentAccount) => - val paymentProvider = loadPaymentProvider(paymentAccount.clientId) + val clientId = paymentAccount.clientId.orElse( + internalClientId + ) + val paymentProvider = loadPaymentProvider(clientId) import paymentProvider._ loadPayIn(orderUuid, transactionId, None) match { case Some(transaction) => @@ -772,7 +794,10 @@ trait GenericPaymentBehavior import cmd._ state match { case Some(paymentAccount) => - val paymentProvider = loadPaymentProvider(paymentAccount.clientId) + val clientId = paymentAccount.clientId.orElse( + internalClientId + ) + val paymentProvider = loadPaymentProvider(clientId) import paymentProvider._ loadPayIn(orderUuid, transactionId, None) match { case Some(transaction) => @@ -794,7 +819,10 @@ trait GenericPaymentBehavior import cmd._ state match { case Some(paymentAccount) => - val paymentProvider = loadPaymentProvider(paymentAccount.clientId) + val clientId = paymentAccount.clientId.orElse( + internalClientId + ) + val paymentProvider = loadPaymentProvider(clientId) import paymentProvider._ (paymentAccount.transactions.find(_.id == payInTransactionId) match { case None => loadPayIn(orderUuid, payInTransactionId, None) @@ -943,7 +971,10 @@ trait GenericPaymentBehavior import cmd._ state match { case Some(paymentAccount) => - val paymentProvider = loadPaymentProvider(paymentAccount.clientId) + val clientId = paymentAccount.clientId.orElse( + internalClientId + ) + val paymentProvider = loadPaymentProvider(clientId) import paymentProvider._ paymentAccount.userId match { case Some(userId) => @@ -1142,7 +1173,10 @@ trait GenericPaymentBehavior import cmd._ state match { case Some(paymentAccount) => // debited account - val paymentProvider = loadPaymentProvider(paymentAccount.clientId) + val clientId = paymentAccount.clientId.orElse( + internalClientId + ) + val paymentProvider = loadPaymentProvider(clientId) import paymentProvider._ var maybeCreditedPaymentAccount: Option[PaymentAccount] = None transfer(paymentAccount.userId match { @@ -1318,7 +1352,10 @@ trait GenericPaymentBehavior ) .thenRun(_ => MandateNotCanceled ~> replyTo) } else { - val paymentProvider = loadPaymentProvider(paymentAccount.clientId) + val clientId = paymentAccount.clientId.orElse( + internalClientId + ) + val paymentProvider = loadPaymentProvider(clientId) import paymentProvider._ paymentAccount.bankAccount match { case Some(bankAccount) => @@ -1374,7 +1411,10 @@ trait GenericPaymentBehavior case Some(userId) => paymentAccount.bankAccount.flatMap(_.id) match { case Some(bankAccountId) => - val paymentProvider = loadPaymentProvider(paymentAccount.clientId) + val clientId = paymentAccount.clientId.orElse( + internalClientId + ) + val paymentProvider = loadPaymentProvider(clientId) import paymentProvider._ loadMandate(Some(mandateId), userId, bankAccountId) match { case Some(report) => @@ -1430,7 +1470,10 @@ trait GenericPaymentBehavior paymentAccount.bankAccount.flatMap(_.mandateId) match { case Some(mandateId) => if (paymentAccount.mandateActivated) { - val paymentProvider = loadPaymentProvider(paymentAccount.clientId) + val clientId = paymentAccount.clientId.orElse( + internalClientId + ) + val paymentProvider = loadPaymentProvider(clientId) import paymentProvider._ directDebit( Some( @@ -1522,7 +1565,10 @@ trait GenericPaymentBehavior case Some(transaction) => paymentAccount.walletId match { case Some(creditedWalletId) => - val paymentProvider = loadPaymentProvider(paymentAccount.clientId) + val clientId = paymentAccount.clientId.orElse( + internalClientId + ) + val paymentProvider = loadPaymentProvider(clientId) import paymentProvider._ val transactionDate: LocalDate = Date.from(transaction.createdDate) directDebitTransaction( @@ -1602,7 +1648,10 @@ trait GenericPaymentBehavior _.getId == cmd.recurringPayInRegistrationId ) match { case Some(recurringPayment) => - val paymentProvider = loadPaymentProvider(paymentAccount.clientId) + val clientId = paymentAccount.clientId.orElse( + internalClientId + ) + val paymentProvider = loadPaymentProvider(clientId) import paymentProvider._ createRecurringCardPayment( RecurringPaymentTransaction.defaultInstance @@ -1649,7 +1698,10 @@ trait GenericPaymentBehavior import cmd._ paymentAccount.recurryingPayments.find(_.getId == recurringPayInRegistrationId) match { case Some(recurringPayment) => - val paymentProvider = loadPaymentProvider(paymentAccount.clientId) + val clientId = paymentAccount.clientId.orElse( + internalClientId + ) + val paymentProvider = loadPaymentProvider(clientId) import paymentProvider._ loadPayIn("", transactionId, Some(recurringPayInRegistrationId)) match { case Some(transaction) => @@ -1702,7 +1754,10 @@ trait GenericPaymentBehavior _.getId == recurringPaymentRegistrationId ) match { case Some(recurringPayment) => - val paymentProvider = loadPaymentProvider(paymentAccount.clientId) + val clientId = paymentAccount.clientId.orElse( + internalClientId + ) + val paymentProvider = loadPaymentProvider(clientId) import paymentProvider._ val debitedAmount = nextDebitedAmount.getOrElse( recurringPayment.nextDebitedAmount.getOrElse( @@ -2098,7 +2153,10 @@ trait GenericPaymentBehavior updatedPaymentAccount.getLegalUser.uboDeclarationRequired && updatedPaymentAccount.getLegalUser.uboDeclaration.isEmpty - val paymentProvider = loadPaymentProvider(paymentAccount.clientId) + val clientId = paymentAccount.clientId.orElse( + internalClientId + ) + val paymentProvider = loadPaymentProvider(clientId) import paymentProvider._ (paymentAccount.userId match { case None => @@ -2331,7 +2389,10 @@ trait GenericPaymentBehavior import cmd._ state match { case Some(paymentAccount) if paymentAccount.hasAcceptedTermsOfPSP => - val paymentProvider = loadPaymentProvider(paymentAccount.clientId) + val clientId = paymentAccount.clientId.orElse( + internalClientId + ) + val paymentProvider = loadPaymentProvider(clientId) import paymentProvider._ paymentAccount.userId match { case Some(userId) => @@ -2457,7 +2518,10 @@ trait GenericPaymentBehavior case cmd: CreateOrUpdateUbo => state match { case Some(paymentAccount) => - val paymentProvider = loadPaymentProvider(paymentAccount.clientId) + val clientId = paymentAccount.clientId.orElse( + internalClientId + ) + val paymentProvider = loadPaymentProvider(clientId) import paymentProvider._ var declarationCreated: Boolean = false def createInternalDeclaration(): Option[UboDeclaration] = { @@ -2533,7 +2597,10 @@ trait GenericPaymentBehavior case Some(uboDeclaration) if uboDeclaration.status.isUboDeclarationCreated || uboDeclaration.status.isUboDeclarationIncomplete || uboDeclaration.status.isUboDeclarationRefused => - val paymentProvider = loadPaymentProvider(paymentAccount.clientId) + val clientId = paymentAccount.clientId.orElse( + internalClientId + ) + val paymentProvider = loadPaymentProvider(clientId) import paymentProvider._ validateDeclaration(paymentAccount.userId.getOrElse(""), uboDeclaration.id) match { case Some(declaration) => @@ -2585,7 +2652,10 @@ trait GenericPaymentBehavior if cmd.uboDeclarationId == uboDeclaration.id && uboDeclaration.status.isUboDeclarationValidationAsked => import cmd._ - val paymentProvider = loadPaymentProvider(paymentAccount.clientId) + val clientId = paymentAccount.clientId.orElse( + internalClientId + ) + val paymentProvider = loadPaymentProvider(clientId) import paymentProvider._ getDeclaration(paymentAccount.userId.getOrElse(""), uboDeclarationId) match { case Some(declaration) => @@ -2890,7 +2960,10 @@ trait GenericPaymentBehavior case Some(_) => Effect.none.thenRun(_ => CardNotDisabled ~> replyTo) case _ => - val paymentProvider = loadPaymentProvider(paymentAccount.clientId) + val clientId = paymentAccount.clientId.orElse( + internalClientId + ) + val paymentProvider = loadPaymentProvider(clientId) import paymentProvider._ disableCard(cmd.cardId) match { case Some(_) => @@ -2949,7 +3022,10 @@ trait GenericPaymentBehavior nextDebitedAmount = cmd.nextDebitedAmount, nextFeesAmount = cmd.nextFeesAmount ) - val paymentProvider = loadPaymentProvider(paymentAccount.clientId) + val clientId = paymentAccount.clientId.orElse( + internalClientId + ) + val paymentProvider = loadPaymentProvider(clientId) import paymentProvider._ registerRecurringCardPayment( userId, @@ -3079,7 +3155,10 @@ trait GenericPaymentBehavior _.getId == cmd.recurringPayInRegistrationId ) match { case Some(recurringPayment) if recurringPayment.`type`.isCard => - val paymentProvider = loadPaymentProvider(paymentAccount.clientId) + val clientId = paymentAccount.clientId.orElse( + internalClientId + ) + val paymentProvider = loadPaymentProvider(clientId) import paymentProvider._ val cardId: Option[String] = cmd.cardId match { @@ -3247,9 +3326,13 @@ trait GenericPaymentBehavior paymentAccount: PaymentAccount, creditedUserId: String, bankAccountId: String - )(implicit context: ActorContext[_]): Effect[ExternalSchedulerEvent, Option[PaymentAccount]] = { + )(implicit + context: ActorContext[_], + paymentClientSettings: PaymentClientSettings + ): Effect[ExternalSchedulerEvent, Option[PaymentAccount]] = { implicit val system: ActorSystem[_] = context.system - val paymentProvider = loadPaymentProvider(paymentAccount.clientId) + val clientId = paymentAccount.clientId.orElse(Option(paymentClientSettings.clientId)) + val paymentProvider = loadPaymentProvider(clientId) import paymentProvider._ mandate(creditedAccount, creditedUserId, bankAccountId) match { case Some(mandateResult) => @@ -3315,7 +3398,7 @@ trait GenericPaymentBehavior state: Option[PaymentAccount], user: PaymentAccount.User, clientId: Option[String] - )(implicit system: ActorSystem[_], log: Logger): Option[PaymentAccount] = { + )(implicit system: ActorSystem[_], log: Logger, paymentClientSettings: PaymentClientSettings): Option[PaymentAccount] = { val pa = PaymentAccount.defaultInstance.withUser(user).copy(clientId = clientId) val uuid = pa.externalUuidWithProfile state match { @@ -3342,14 +3425,15 @@ trait GenericPaymentBehavior s"the payment account entity $entityId has already been associated with another external uuid ${paymentAccount.externalUuid}" ) None - } else if (paymentAccount.clientId.getOrElse("") != clientId.getOrElse("")) { - log.warn( - s"the payment account entity $entityId has already been associated with another client ${paymentAccount.clientId}" - ) - None } else { keyValueDao.addKeyValue(uuid, entityId) - Some(paymentAccount) + Some( + paymentAccount.copy(clientId = + paymentAccount.clientId + .orElse(clientId) + .orElse(Option(paymentClientSettings.clientId)) + ) + ) } } } @@ -3590,7 +3674,8 @@ trait GenericPaymentBehavior transaction: Transaction )(implicit system: ActorSystem[_], - log: Logger + log: Logger, + paymentClientSettings: PaymentClientSettings ): Effect[ExternalSchedulerEvent, Option[PaymentAccount]] = { keyValueDao.addKeyValue( transaction.id, @@ -3617,7 +3702,10 @@ trait GenericPaymentBehavior case _ => if (transaction.status.isTransactionSucceeded || transaction.status.isTransactionCreated) { log.debug("Order-{} paid in: {} -> {}", orderUuid, transaction.id, asJson(transaction)) - val paymentProvider = loadPaymentProvider(paymentAccount.clientId) + val clientId = paymentAccount.clientId.orElse( + Option(paymentClientSettings.clientId) + ) + val paymentProvider = loadPaymentProvider(clientId) import paymentProvider._ val registerCardEvents: List[ExternalSchedulerEvent] = if (registerCard) { @@ -3727,7 +3815,8 @@ trait GenericPaymentBehavior transaction: Transaction )(implicit system: ActorSystem[_], - log: Logger + log: Logger, + paymentClientSettings: PaymentClientSettings ): Effect[ExternalSchedulerEvent, Option[PaymentAccount]] = { keyValueDao.addKeyValue( transaction.id, @@ -3763,7 +3852,8 @@ trait GenericPaymentBehavior transaction.id, asJson(transaction) ) - val paymentProvider = loadPaymentProvider(paymentAccount.clientId) + val clientId = paymentAccount.clientId.orElse(Option(paymentClientSettings.clientId)) + val paymentProvider = loadPaymentProvider(clientId) import paymentProvider._ val registerCardEvents: List[ExternalSchedulerEvent] = if (registerCard) { @@ -3844,14 +3934,16 @@ trait GenericPaymentBehavior documentId: String, maybeStatus: Option[KycDocument.KycDocumentStatus] = None )(implicit - system: ActorSystem[_] + system: ActorSystem[_], + paymentClientSettings: PaymentClientSettings ): (KycDocumentValidationReport, List[ExternalSchedulerEvent]) = { var events: List[ExternalSchedulerEvent] = List.empty val lastUpdated = now() val userId = paymentAccount.userId.getOrElse("") - val paymentProvider = loadPaymentProvider(paymentAccount.clientId) + val clientId = paymentAccount.clientId.orElse(Option(paymentClientSettings.clientId)) + val paymentProvider = loadPaymentProvider(clientId) import paymentProvider._ val report = loadDocumentStatus(userId, documentId) @@ -4025,8 +4117,10 @@ trait GenericPaymentBehavior case Success(s) => s case Failure(_) => None }) - .getOrElse(defaultProvider) + .getOrElse(throw new Exception("Payment provider not found")) ) } } + +object PaymentBehavior extends PaymentBehavior diff --git a/core/src/main/scala/app/softnetwork/payment/service/BankAccountEndpoints.scala b/core/src/main/scala/app/softnetwork/payment/service/BankAccountEndpoints.scala index 8c8194d..be3484b 100644 --- a/core/src/main/scala/app/softnetwork/payment/service/BankAccountEndpoints.scala +++ b/core/src/main/scala/app/softnetwork/payment/service/BankAccountEndpoints.scala @@ -1,7 +1,7 @@ package app.softnetwork.payment.service import app.softnetwork.payment.config.PaymentSettings -import app.softnetwork.payment.handlers.GenericPaymentHandler +import app.softnetwork.payment.handlers.PaymentHandler import app.softnetwork.payment.message.PaymentMessages._ import app.softnetwork.payment.model.{BankAccountView, PaymentAccount} import app.softnetwork.session.model.{SessionData, SessionDataDecorator} @@ -14,7 +14,7 @@ import sttp.tapir.server.ServerEndpoint import scala.concurrent.Future trait BankAccountEndpoints[SD <: SessionData with SessionDataDecorator[SD]] { - _: RootPaymentEndpoints[SD] with GenericPaymentHandler => + _: RootPaymentEndpoints[SD] with PaymentHandler => import app.softnetwork.serialization._ diff --git a/core/src/main/scala/app/softnetwork/payment/service/BasicPaymentService.scala b/core/src/main/scala/app/softnetwork/payment/service/BasicPaymentService.scala index bc92db5..47e5876 100644 --- a/core/src/main/scala/app/softnetwork/payment/service/BasicPaymentService.scala +++ b/core/src/main/scala/app/softnetwork/payment/service/BasicPaymentService.scala @@ -1,7 +1,7 @@ package app.softnetwork.payment.service import app.softnetwork.api.server.ApiErrors -import app.softnetwork.payment.handlers.GenericPaymentHandler +import app.softnetwork.payment.handlers.PaymentHandler import app.softnetwork.payment.message.PaymentMessages._ import app.softnetwork.payment.model.BrowserInfo import app.softnetwork.persistence.service.Service @@ -11,7 +11,7 @@ import scala.concurrent.Future import scala.reflect.ClassTag trait BasicPaymentService extends Service[PaymentCommand, PaymentResult] { - _: GenericPaymentHandler => + _: PaymentHandler => def run(command: PaymentCommandWithKey)(implicit tTag: ClassTag[PaymentCommand] diff --git a/core/src/main/scala/app/softnetwork/payment/service/CardEndpoints.scala b/core/src/main/scala/app/softnetwork/payment/service/CardEndpoints.scala index 216dc9f..86b94a1 100644 --- a/core/src/main/scala/app/softnetwork/payment/service/CardEndpoints.scala +++ b/core/src/main/scala/app/softnetwork/payment/service/CardEndpoints.scala @@ -1,7 +1,7 @@ package app.softnetwork.payment.service import app.softnetwork.payment.config.PaymentSettings -import app.softnetwork.payment.handlers.GenericPaymentHandler +import app.softnetwork.payment.handlers.PaymentHandler import app.softnetwork.payment.message.PaymentMessages._ import app.softnetwork.payment.model.{CardPreRegistration, CardView} import app.softnetwork.session.model.{SessionData, SessionDataDecorator} @@ -14,7 +14,7 @@ import sttp.tapir.server.ServerEndpoint import scala.concurrent.Future trait CardEndpoints[SD <: SessionData with SessionDataDecorator[SD]] { - _: RootPaymentEndpoints[SD] with GenericPaymentHandler => + _: RootPaymentEndpoints[SD] with PaymentHandler => import app.softnetwork.serialization._ diff --git a/core/src/main/scala/app/softnetwork/payment/service/CardPaymentEndpoints.scala b/core/src/main/scala/app/softnetwork/payment/service/CardPaymentEndpoints.scala index ef9a15c..c7cd679 100644 --- a/core/src/main/scala/app/softnetwork/payment/service/CardPaymentEndpoints.scala +++ b/core/src/main/scala/app/softnetwork/payment/service/CardPaymentEndpoints.scala @@ -1,7 +1,7 @@ package app.softnetwork.payment.service import app.softnetwork.payment.config.PaymentSettings -import app.softnetwork.payment.handlers.GenericPaymentHandler +import app.softnetwork.payment.handlers.PaymentHandler import app.softnetwork.payment.message.PaymentMessages._ import app.softnetwork.payment.model.SoftPaymentAccount import app.softnetwork.session.model.{SessionData, SessionDataDecorator} @@ -15,7 +15,7 @@ import sttp.tapir.server.{PartialServerEndpointWithSecurityOutput, ServerEndpoin import scala.concurrent.Future trait CardPaymentEndpoints[SD <: SessionData with SessionDataDecorator[SD]] { - _: RootPaymentEndpoints[SD] with GenericPaymentHandler => + _: RootPaymentEndpoints[SD] with PaymentHandler => import app.softnetwork.serialization._ diff --git a/core/src/main/scala/app/softnetwork/payment/service/ClientSession.scala b/core/src/main/scala/app/softnetwork/payment/service/ClientSession.scala index 48e2b49..f3483d4 100644 --- a/core/src/main/scala/app/softnetwork/payment/service/ClientSession.scala +++ b/core/src/main/scala/app/softnetwork/payment/service/ClientSession.scala @@ -5,7 +5,7 @@ import app.softnetwork.payment.handlers.SoftPaymentAccountDao import app.softnetwork.payment.model.{computeExternalUuidWithProfile, SoftPaymentAccount} import app.softnetwork.session.model.{SessionData, SessionDataCompanion, SessionDataDecorator} import app.softnetwork.session.service.SessionMaterials -import org.softnetwork.session.model.{ApiKey, JwtClaims} +import org.softnetwork.session.model.ApiKey import com.softwaremill.session._ import scala.concurrent.Future @@ -86,26 +86,6 @@ trait ClientSession[SD <: SessionData with SessionDataDecorator[SD]] extends Com def loadApiKey(clientId: String): Future[Option[ApiKey]] = softPaymentAccountDao.loadApiKey(clientId) - protected def toClient(token: Option[String]): Future[Option[SoftPaymentAccount.Client]] = { - token match { - case Some(value) => - softPaymentAccountDao.oauthClient(value) flatMap { - case Some(client) => Future.successful(Some(client)) - case _ => - val jwt = JwtClaims(value) - if (jwt.iss.contains(sessionConfig.jwt.issuer.getOrElse("")) && jwt.sub.isDefined) { - softPaymentAccountDao.loadClient(jwt.sub.get) flatMap { - case Some(client) => Future.successful(Some(client)) - case _ => Future.successful(None) - } - } else { - Future.successful(None) - } - } - case _ => Future.successful(None) - } - } - protected[payment] def externalUuidWithProfile(session: SD): String = computeExternalUuidWithProfile(session.id, session.profile) diff --git a/core/src/main/scala/app/softnetwork/payment/service/ClientSessionDirectives.scala b/core/src/main/scala/app/softnetwork/payment/service/ClientSessionDirectives.scala index 28d680f..9be5cfc 100644 --- a/core/src/main/scala/app/softnetwork/payment/service/ClientSessionDirectives.scala +++ b/core/src/main/scala/app/softnetwork/payment/service/ClientSessionDirectives.scala @@ -42,7 +42,7 @@ trait ClientSessionDirectives[SD <: SessionData with SessionDataDecorator[SD]] @InternalApi private[payment] def oauthClient: Credentials => Future[Option[SoftPaymentAccount.Client]] = { - case _ @Credentials.Provided(token) => toClient(Some(token)) + case _ @Credentials.Provided(token) => softPaymentAccountDao.authenticateClient(Some(token)) case _ => Future.successful(None) } diff --git a/core/src/main/scala/app/softnetwork/payment/service/ClientSessionEndpoints.scala b/core/src/main/scala/app/softnetwork/payment/service/ClientSessionEndpoints.scala index 4b994de..c62b6af 100644 --- a/core/src/main/scala/app/softnetwork/payment/service/ClientSessionEndpoints.scala +++ b/core/src/main/scala/app/softnetwork/payment/service/ClientSessionEndpoints.scala @@ -89,7 +89,7 @@ trait ClientSessionEndpoints[SD <: SessionData with SessionDataDecorator[SD]] ) .out(partial.securityOutput) .serverSecurityLogicWithOutput { inputs => - toClient(inputs.head) flatMap { client => + softPaymentAccountDao.authenticateClient(inputs.head) flatMap { client => implicit val manager: SessionManager[SD] = clientSessionManager(client) sessionType match { case Session.SessionType.OneOffCookie | Session.SessionType.OneOffHeader => // oneOff diff --git a/core/src/main/scala/app/softnetwork/payment/service/KycDocumentEndpoints.scala b/core/src/main/scala/app/softnetwork/payment/service/KycDocumentEndpoints.scala index 38e5611..e8c6c26 100644 --- a/core/src/main/scala/app/softnetwork/payment/service/KycDocumentEndpoints.scala +++ b/core/src/main/scala/app/softnetwork/payment/service/KycDocumentEndpoints.scala @@ -2,7 +2,7 @@ package app.softnetwork.payment.service import app.softnetwork.api.server.ApiErrors import app.softnetwork.payment.config.PaymentSettings -import app.softnetwork.payment.handlers.GenericPaymentHandler +import app.softnetwork.payment.handlers.PaymentHandler import app.softnetwork.payment.message.PaymentMessages._ import app.softnetwork.payment.model.{KycDocument, KycDocumentValidationReport} import app.softnetwork.session.model.{SessionData, SessionDataDecorator} @@ -15,7 +15,7 @@ import sttp.tapir.server.ServerEndpoint import scala.concurrent.Future trait KycDocumentEndpoints[SD <: SessionData with SessionDataDecorator[SD]] { - _: RootPaymentEndpoints[SD] with GenericPaymentHandler => + _: RootPaymentEndpoints[SD] with PaymentHandler => import app.softnetwork.serialization._ diff --git a/core/src/main/scala/app/softnetwork/payment/service/MandateEndpoints.scala b/core/src/main/scala/app/softnetwork/payment/service/MandateEndpoints.scala index 28ae92e..f1c0cb5 100644 --- a/core/src/main/scala/app/softnetwork/payment/service/MandateEndpoints.scala +++ b/core/src/main/scala/app/softnetwork/payment/service/MandateEndpoints.scala @@ -1,7 +1,7 @@ package app.softnetwork.payment.service import app.softnetwork.payment.config.PaymentSettings -import app.softnetwork.payment.handlers.GenericPaymentHandler +import app.softnetwork.payment.handlers.PaymentHandler import app.softnetwork.payment.message.PaymentMessages._ import app.softnetwork.payment.model.MandateResult import app.softnetwork.session.model.{SessionData, SessionDataDecorator} @@ -14,7 +14,7 @@ import sttp.tapir.server.ServerEndpoint import scala.concurrent.Future trait MandateEndpoints[SD <: SessionData with SessionDataDecorator[SD]] { - _: RootPaymentEndpoints[SD] with GenericPaymentHandler => + _: RootPaymentEndpoints[SD] with PaymentHandler => import app.softnetwork.serialization._ diff --git a/core/src/main/scala/app/softnetwork/payment/service/GenericPaymentService.scala b/core/src/main/scala/app/softnetwork/payment/service/PaymentService.scala similarity index 99% rename from core/src/main/scala/app/softnetwork/payment/service/GenericPaymentService.scala rename to core/src/main/scala/app/softnetwork/payment/service/PaymentService.scala index b99688e..35111f1 100644 --- a/core/src/main/scala/app/softnetwork/payment/service/GenericPaymentService.scala +++ b/core/src/main/scala/app/softnetwork/payment/service/PaymentService.scala @@ -4,7 +4,7 @@ import akka.actor.typed.ActorSystem import akka.http.scaladsl.model.{HttpResponse, StatusCodes} import akka.http.scaladsl.server.{Directives, Route} import app.softnetwork.api.server.DefaultComplete -import app.softnetwork.payment.handlers.GenericPaymentHandler +import app.softnetwork.payment.handlers.PaymentHandler import app.softnetwork.payment.message.PaymentMessages._ import app.softnetwork.payment.serialization._ import app.softnetwork.payment.config.PaymentSettings @@ -32,7 +32,7 @@ import java.io.ByteArrayOutputStream import scala.concurrent.Await import scala.language.implicitConversions -trait GenericPaymentService[SD <: SessionData with SessionDataDecorator[SD]] +trait PaymentService[SD <: SessionData with SessionDataDecorator[SD]] extends Directives with DefaultComplete with Json4sSupport @@ -40,7 +40,7 @@ trait GenericPaymentService[SD <: SessionData with SessionDataDecorator[SD]] with BasicPaymentService with ServiceWithSessionDirectives[PaymentCommand, PaymentResult, SD] with ClientSessionDirectives[SD] - with ApiRoute { _: GenericPaymentHandler with SessionMaterials[SD] => + with ApiRoute { _: PaymentHandler with SessionMaterials[SD] => implicit def serialization: Serialization.type = jackson.Serialization diff --git a/core/src/main/scala/app/softnetwork/payment/service/GenericPaymentEndpoints.scala b/core/src/main/scala/app/softnetwork/payment/service/PaymentServiceEndpoints.scala similarity index 91% rename from core/src/main/scala/app/softnetwork/payment/service/GenericPaymentEndpoints.scala rename to core/src/main/scala/app/softnetwork/payment/service/PaymentServiceEndpoints.scala index f2a8e60..bdba841 100644 --- a/core/src/main/scala/app/softnetwork/payment/service/GenericPaymentEndpoints.scala +++ b/core/src/main/scala/app/softnetwork/payment/service/PaymentServiceEndpoints.scala @@ -1,6 +1,6 @@ package app.softnetwork.payment.service -import app.softnetwork.payment.handlers.GenericPaymentHandler +import app.softnetwork.payment.handlers.PaymentHandler import app.softnetwork.payment.message.PaymentMessages._ import app.softnetwork.payment.model._ import app.softnetwork.session.model.{SessionData, SessionDataDecorator} @@ -15,7 +15,7 @@ import sttp.tapir.server.ServerEndpoint.Full import scala.concurrent.Future import scala.language.{implicitConversions, postfixOps} -trait GenericPaymentEndpoints[SD <: SessionData with SessionDataDecorator[SD]] +trait PaymentServiceEndpoints[SD <: SessionData with SessionDataDecorator[SD]] extends RootPaymentEndpoints[SD] with CardEndpoints[SD] with CardPaymentEndpoints[SD] @@ -24,7 +24,7 @@ trait GenericPaymentEndpoints[SD <: SessionData with SessionDataDecorator[SD]] with UboDeclarationEndpoints[SD] with RecurringPaymentEndpoints[SD] with MandateEndpoints[SD] { - _: GenericPaymentHandler with SessionMaterials[SD] => + _: PaymentHandler with SessionMaterials[SD] => import app.softnetwork.serialization._ diff --git a/core/src/main/scala/app/softnetwork/payment/service/RecurringPaymentEndpoints.scala b/core/src/main/scala/app/softnetwork/payment/service/RecurringPaymentEndpoints.scala index fa078a2..3069766 100644 --- a/core/src/main/scala/app/softnetwork/payment/service/RecurringPaymentEndpoints.scala +++ b/core/src/main/scala/app/softnetwork/payment/service/RecurringPaymentEndpoints.scala @@ -1,7 +1,7 @@ package app.softnetwork.payment.service import app.softnetwork.payment.config.PaymentSettings -import app.softnetwork.payment.handlers.GenericPaymentHandler +import app.softnetwork.payment.handlers.PaymentHandler import app.softnetwork.payment.message.PaymentMessages._ import app.softnetwork.payment.model.{RecurringPayment, RecurringPaymentView} import app.softnetwork.session.model.{SessionData, SessionDataDecorator} @@ -14,7 +14,7 @@ import sttp.tapir.server.ServerEndpoint import scala.concurrent.Future trait RecurringPaymentEndpoints[SD <: SessionData with SessionDataDecorator[SD]] { - _: RootPaymentEndpoints[SD] with GenericPaymentHandler => + _: RootPaymentEndpoints[SD] with PaymentHandler => import app.softnetwork.serialization._ diff --git a/core/src/main/scala/app/softnetwork/payment/service/RootPaymentEndpoints.scala b/core/src/main/scala/app/softnetwork/payment/service/RootPaymentEndpoints.scala index a03d95a..169a7e9 100644 --- a/core/src/main/scala/app/softnetwork/payment/service/RootPaymentEndpoints.scala +++ b/core/src/main/scala/app/softnetwork/payment/service/RootPaymentEndpoints.scala @@ -3,7 +3,7 @@ package app.softnetwork.payment.service import akka.actor.typed.ActorSystem import app.softnetwork.api.server.ApiErrors import app.softnetwork.payment.config.PaymentSettings -import app.softnetwork.payment.handlers.GenericPaymentHandler +import app.softnetwork.payment.handlers.PaymentHandler import app.softnetwork.payment.message.PaymentMessages._ import app.softnetwork.payment.model.SoftPaymentAccount import app.softnetwork.payment.serialization.paymentFormats @@ -22,7 +22,7 @@ trait RootPaymentEndpoints[SD <: SessionData with SessionDataDecorator[SD]] extends BasicPaymentService with ServiceWithSessionEndpoints[PaymentCommand, PaymentResult, SD] with ClientSessionEndpoints[SD] { - _: GenericPaymentHandler with SessionMaterials[SD] => + _: PaymentHandler with SessionMaterials[SD] => override implicit def formats: Formats = paymentFormats diff --git a/core/src/main/scala/app/softnetwork/payment/service/UboDeclarationEndpoints.scala b/core/src/main/scala/app/softnetwork/payment/service/UboDeclarationEndpoints.scala index 6c3d2cf..c7878f7 100644 --- a/core/src/main/scala/app/softnetwork/payment/service/UboDeclarationEndpoints.scala +++ b/core/src/main/scala/app/softnetwork/payment/service/UboDeclarationEndpoints.scala @@ -1,7 +1,7 @@ package app.softnetwork.payment.service import app.softnetwork.payment.config.PaymentSettings -import app.softnetwork.payment.handlers.GenericPaymentHandler +import app.softnetwork.payment.handlers.PaymentHandler import app.softnetwork.payment.message.PaymentMessages._ import app.softnetwork.payment.model.{UboDeclaration, UboDeclarationView} import app.softnetwork.session.model.{SessionData, SessionDataDecorator} @@ -14,7 +14,7 @@ import sttp.tapir.server.ServerEndpoint import scala.concurrent.Future trait UboDeclarationEndpoints[SD <: SessionData with SessionDataDecorator[SD]] { - _: RootPaymentEndpoints[SD] with GenericPaymentHandler => + _: RootPaymentEndpoints[SD] with PaymentHandler => import app.softnetwork.serialization._ diff --git a/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayApi.scala b/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayApi.scala index c7579c2..d555cd1 100644 --- a/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayApi.scala +++ b/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayApi.scala @@ -1,32 +1,19 @@ package app.softnetwork.payment.api import akka.actor.typed.ActorSystem -import akka.http.scaladsl.model.{HttpRequest, HttpResponse} import app.softnetwork.account.config.AccountSettings -import app.softnetwork.account.handlers.AccountDao -import app.softnetwork.account.model.BasicAccountProfile import app.softnetwork.account.persistence.query.AccountEventProcessorStreams.InternalAccountEvents2AccountProcessorStream -import app.softnetwork.account.persistence.typed.AccountBehavior import app.softnetwork.api.server.SwaggerEndpoint import app.softnetwork.payment.config.PaymentSettings -import app.softnetwork.payment.handlers.{ - MangoPayPaymentHandler, - SoftPaymentAccountDao, - SoftPaymentAccountTypeKey -} +import app.softnetwork.payment.handlers.{PaymentHandler, SoftPaymentAccountTypeKey} import app.softnetwork.payment.launch.PaymentApplication -import app.softnetwork.payment.model.SoftPaymentAccount import app.softnetwork.payment.persistence.query.{ - GenericPaymentCommandProcessorStream, + PaymentCommandProcessorStream, Scheduler2PaymentProcessorStream } -import app.softnetwork.payment.persistence.typed.{ - GenericPaymentBehavior, - MangoPayPaymentBehavior, - SoftPaymentAccountBehavior -} +import app.softnetwork.payment.persistence.typed.{PaymentBehavior, SoftPaymentAccountBehavior} import app.softnetwork.payment.service.{ - MangoPayPaymentEndpoints, + MangoPayPaymentServiceEndpoints, SoftPaymentAccountServiceEndpoints, SoftPaymentOAuthServiceEndpoints } @@ -48,18 +35,11 @@ import org.slf4j.{Logger, LoggerFactory} import org.softnetwork.session.model.Session import sttp.tapir.swagger.SwaggerUIOptions -import scala.concurrent.{ExecutionContext, Future} +import scala.concurrent.ExecutionContext trait MangoPayApi[SD <: SessionData with SessionDataDecorator[SD]] extends PaymentApplication { self: SchemaProvider with CsrfCheck => - override def paymentAccountBehavior: ActorSystem[_] => GenericPaymentBehavior = _ => - MangoPayPaymentBehavior - - override def accountBehavior - : ActorSystem[_] => AccountBehavior[SoftPaymentAccount, BasicAccountProfile] = _ => - SoftPaymentAccountBehavior - override def internalAccountEvents2AccountProcessorStream : ActorSystem[_] => InternalAccountEvents2AccountProcessorStream = sys => new InternalAccountEvents2AccountProcessorStream @@ -71,34 +51,27 @@ trait MangoPayApi[SD <: SessionData with SessionDataDecorator[SD]] extends Payme override implicit def system: ActorSystem[_] = sys } - override def paymentCommandProcessorStream - : ActorSystem[_] => GenericPaymentCommandProcessorStream = sys => - new GenericPaymentCommandProcessorStream - with MangoPayPaymentHandler - with JdbcJournalProvider - with JdbcOffsetProvider { - override def config: Config = MangoPayApi.this.config - override implicit def system: ActorSystem[_] = sys - } + override def paymentCommandProcessorStream: ActorSystem[_] => PaymentCommandProcessorStream = + sys => + new PaymentCommandProcessorStream + with PaymentHandler + with JdbcJournalProvider + with JdbcOffsetProvider { + override def config: Config = MangoPayApi.this.config + override implicit def system: ActorSystem[_] = sys + } override def scheduler2PaymentProcessorStream : ActorSystem[_] => Scheduler2PaymentProcessorStream = sys => new Scheduler2PaymentProcessorStream - with MangoPayPaymentHandler + with PaymentHandler with JdbcJournalProvider with JdbcOffsetProvider { override def config: Config = MangoPayApi.this.config - override val tag: String = SchedulerSettings.tag(MangoPayPaymentBehavior.persistenceId) + override val tag: String = SchedulerSettings.tag(PaymentBehavior.persistenceId) override implicit def system: ActorSystem[_] = sys } - override def grpcServices - : ActorSystem[_] => Seq[PartialFunction[HttpRequest, Future[HttpResponse]]] = - system => - Seq( - PaymentServiceApiHandler.partial(MangoPayServer(system))(system) - ) - implicit def sessionConfig: SessionConfig = Settings.Session.DefaultSessionConfig implicit def companion: SessionDataCompanion[SD] @@ -111,7 +84,7 @@ trait MangoPayApi[SD <: SessionData with SessionDataDecorator[SD]] extends Payme Settings.Session.SessionContinuityAndTransport def paymentSwagger: ActorSystem[_] => SwaggerEndpoint = sys => - new MangoPayPaymentEndpoints[SD] with SwaggerEndpoint with SessionMaterials[SD] { + new MangoPayPaymentServiceEndpoints[SD] with SwaggerEndpoint with SessionMaterials[SD] { override implicit def manager(implicit sessionConfig: SessionConfig, companion: SessionDataCompanion[SD] diff --git a/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayEndpoints.scala b/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayEndpoints.scala index e049705..1a4e059 100644 --- a/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayEndpoints.scala +++ b/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayEndpoints.scala @@ -6,8 +6,8 @@ import app.softnetwork.account.service.{AccountServiceEndpoints, OAuthServiceEnd import app.softnetwork.api.server.Endpoint import app.softnetwork.payment.launch.PaymentEndpoints import app.softnetwork.payment.service.{ - GenericPaymentEndpoints, - MangoPayPaymentEndpoints, + MangoPayPaymentServiceEndpoints, + PaymentServiceEndpoints, SoftPaymentAccountServiceEndpoints, SoftPaymentOAuthServiceEndpoints } @@ -24,8 +24,8 @@ trait MangoPayEndpoints[SD <: SessionData with SessionDataDecorator[SD]] extends PaymentEndpoints[SD] { self: MangoPayApi[SD] with SchemaProvider with CsrfCheck => - override def paymentEndpoints: ActorSystem[_] => GenericPaymentEndpoints[SD] = sys => - new MangoPayPaymentEndpoints[SD] with SessionMaterials[SD] { + override def paymentEndpoints: ActorSystem[_] => PaymentServiceEndpoints[SD] = sys => + new MangoPayPaymentServiceEndpoints[SD] with SessionMaterials[SD] { override def log: org.slf4j.Logger = org.slf4j.LoggerFactory.getLogger(getClass) override implicit def system: ActorSystem[_] = sys override lazy val ec: ExecutionContext = sys.executionContext diff --git a/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayEndpointsPostgresLauncher.scala b/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayEndpointsPostgresLauncher.scala index 3d78507..3bbfd2b 100644 --- a/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayEndpointsPostgresLauncher.scala +++ b/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayEndpointsPostgresLauncher.scala @@ -2,7 +2,7 @@ package app.softnetwork.payment.api import akka.actor.typed.ActorSystem import app.softnetwork.payment.handlers.SoftPaymentAccountDao -import app.softnetwork.payment.service.{GenericPaymentEndpoints, MangoPayPaymentEndpoints} +import app.softnetwork.payment.service.{MangoPayPaymentServiceEndpoints, PaymentServiceEndpoints} import app.softnetwork.persistence.jdbc.schema.{JdbcSchemaProvider, JdbcSchemaTypes} import app.softnetwork.persistence.schema.SchemaType import app.softnetwork.session.CsrfCheckHeader @@ -31,8 +31,8 @@ object MangoPayEndpointsPostgresLauncher override protected def manager: SessionManager[JwtClaims] = SessionManagers.jwt - override def paymentEndpoints: ActorSystem[_] => GenericPaymentEndpoints[JwtClaims] = sys => - new MangoPayPaymentEndpoints[JwtClaims] with JwtClaimsSessionMaterials { + override def paymentEndpoints: ActorSystem[_] => PaymentServiceEndpoints[JwtClaims] = sys => + new MangoPayPaymentServiceEndpoints[JwtClaims] with JwtClaimsSessionMaterials { override implicit def system: ActorSystem[_] = sys override implicit lazy val ec: ExecutionContext = sys.executionContext override implicit def sessionConfig: SessionConfig = self.sessionConfig diff --git a/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayRoutes.scala b/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayRoutes.scala index 295c2a1..103edb6 100644 --- a/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayRoutes.scala +++ b/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayRoutes.scala @@ -10,8 +10,8 @@ import app.softnetwork.account.service.{AccountService, OAuthService} import app.softnetwork.api.server.ApiRoute import app.softnetwork.payment.launch.PaymentRoutes import app.softnetwork.payment.service.{ - GenericPaymentService, MangoPayPaymentService, + PaymentService, SoftPaymentAccountService, SoftPaymentOAuthService } @@ -28,7 +28,7 @@ import scala.concurrent.ExecutionContext trait MangoPayRoutes[SD <: SessionData with SessionDataDecorator[SD]] extends PaymentRoutes[SD] { self: MangoPayApi[SD] with SchemaProvider with CsrfCheck => - override def paymentService: ActorSystem[_] => GenericPaymentService[SD] = sys => + override def paymentService: ActorSystem[_] => PaymentService[SD] = sys => new MangoPayPaymentService[SD] with SessionMaterials[SD] { override implicit def manager(implicit sessionConfig: SessionConfig, diff --git a/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayRoutesPostgresLauncher.scala b/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayRoutesPostgresLauncher.scala index 4a9f034..80d9828 100644 --- a/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayRoutesPostgresLauncher.scala +++ b/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayRoutesPostgresLauncher.scala @@ -1,7 +1,7 @@ package app.softnetwork.payment.api import akka.actor.typed.ActorSystem -import app.softnetwork.payment.service.{GenericPaymentService, MangoPayPaymentService} +import app.softnetwork.payment.service.{MangoPayPaymentService, PaymentService} import app.softnetwork.persistence.jdbc.schema.{JdbcSchemaProvider, JdbcSchemaTypes} import app.softnetwork.persistence.schema.SchemaType import app.softnetwork.session.CsrfCheckHeader @@ -29,7 +29,7 @@ object MangoPayRoutesPostgresLauncher override protected def manager: SessionManager[JwtClaims] = SessionManagers.jwt - override def paymentService: ActorSystem[_] => GenericPaymentService[JwtClaims] = sys => + override def paymentService: ActorSystem[_] => PaymentService[JwtClaims] = sys => new MangoPayPaymentService[JwtClaims] with JwtClaimsSessionMaterials { override implicit def system: ActorSystem[_] = sys override implicit lazy val ec: ExecutionContext = sys.executionContext diff --git a/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayWithSchedulerApi.scala b/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayWithSchedulerApi.scala index a74e080..0a60f80 100644 --- a/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayWithSchedulerApi.scala +++ b/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayWithSchedulerApi.scala @@ -42,6 +42,6 @@ trait MangoPayWithSchedulerApi[SD <: SessionData with SessionDataDecorator[SD]] override def grpcServices : ActorSystem[_] => Seq[PartialFunction[HttpRequest, Future[HttpResponse]]] = system => Seq( - PaymentServiceApiHandler.partial(MangoPayServer(system))(system) + PaymentServiceApiHandler.partial(PaymentServer(system))(system) ) :+ SchedulerServiceApiHandler.partial(schedulerServer(system))(system) } diff --git a/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayWithSchedulerEndpointsPostgresLauncher.scala b/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayWithSchedulerEndpointsPostgresLauncher.scala index ec1e915..85ecd12 100644 --- a/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayWithSchedulerEndpointsPostgresLauncher.scala +++ b/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayWithSchedulerEndpointsPostgresLauncher.scala @@ -2,7 +2,7 @@ package app.softnetwork.payment.api import akka.actor.typed.ActorSystem import app.softnetwork.payment.handlers.SoftPaymentAccountDao -import app.softnetwork.payment.service.{GenericPaymentEndpoints, MangoPayPaymentEndpoints} +import app.softnetwork.payment.service.{MangoPayPaymentServiceEndpoints, PaymentServiceEndpoints} import app.softnetwork.persistence.jdbc.schema.{JdbcSchemaProvider, JdbcSchemaTypes} import app.softnetwork.persistence.schema.SchemaType import app.softnetwork.session.CsrfCheckHeader @@ -31,8 +31,8 @@ object MangoPayWithSchedulerEndpointsPostgresLauncher override protected def manager: SessionManager[JwtClaims] = SessionManagers.jwt - override def paymentEndpoints: ActorSystem[_] => GenericPaymentEndpoints[JwtClaims] = sys => - new MangoPayPaymentEndpoints[JwtClaims] with JwtClaimsSessionMaterials { + override def paymentEndpoints: ActorSystem[_] => PaymentServiceEndpoints[JwtClaims] = sys => + new MangoPayPaymentServiceEndpoints[JwtClaims] with JwtClaimsSessionMaterials { override implicit def system: ActorSystem[_] = sys override implicit lazy val ec: ExecutionContext = sys.executionContext override implicit def sessionConfig: SessionConfig = self.sessionConfig diff --git a/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayWithSchedulerRoutesPostgresLauncher.scala b/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayWithSchedulerRoutesPostgresLauncher.scala index b53a131..ad57794 100644 --- a/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayWithSchedulerRoutesPostgresLauncher.scala +++ b/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayWithSchedulerRoutesPostgresLauncher.scala @@ -2,7 +2,7 @@ package app.softnetwork.payment.api import akka.actor.typed.ActorSystem import app.softnetwork.payment.handlers.SoftPaymentAccountDao -import app.softnetwork.payment.service.{GenericPaymentService, MangoPayPaymentService} +import app.softnetwork.payment.service.{MangoPayPaymentService, PaymentService} import app.softnetwork.persistence.jdbc.schema.{JdbcSchemaProvider, JdbcSchemaTypes} import app.softnetwork.persistence.schema.SchemaType import app.softnetwork.session.handlers.JwtClaimsRefreshTokenDao @@ -28,7 +28,7 @@ object MangoPayWithSchedulerRoutesPostgresLauncher override protected def manager: SessionManager[JwtClaims] = SessionManagers.jwt - override def paymentService: ActorSystem[_] => GenericPaymentService[JwtClaims] = sys => + override def paymentService: ActorSystem[_] => PaymentService[JwtClaims] = sys => new MangoPayPaymentService[JwtClaims] with JwtClaimsSessionMaterials { override implicit def system: ActorSystem[_] = sys override implicit lazy val ec: ExecutionContext = sys.executionContext diff --git a/mangopay/src/main/scala/app/softnetwork/payment/api/MangoPayServer.scala b/mangopay/src/main/scala/app/softnetwork/payment/api/MangoPayServer.scala deleted file mode 100644 index 2ad48c7..0000000 --- a/mangopay/src/main/scala/app/softnetwork/payment/api/MangoPayServer.scala +++ /dev/null @@ -1,16 +0,0 @@ -package app.softnetwork.payment.api - -import akka.actor.typed.ActorSystem -import app.softnetwork.payment.handlers.{MangoPayPaymentTypeKey, SoftPaymentAccountDao} -import org.slf4j.{Logger, LoggerFactory} - -trait MangoPayServer extends PaymentServer with MangoPayPaymentTypeKey - -object MangoPayServer { - def apply(sys: ActorSystem[_]): MangoPayServer = { - new MangoPayServer { - lazy val log: Logger = LoggerFactory getLogger getClass.getName - override implicit val system: ActorSystem[_] = sys - } - } -} diff --git a/mangopay/src/main/scala/app/softnetwork/payment/handlers/MangoPayPaymentDao.scala b/mangopay/src/main/scala/app/softnetwork/payment/handlers/MangoPayPaymentDao.scala deleted file mode 100644 index 20f104e..0000000 --- a/mangopay/src/main/scala/app/softnetwork/payment/handlers/MangoPayPaymentDao.scala +++ /dev/null @@ -1,7 +0,0 @@ -package app.softnetwork.payment.handlers - -import org.slf4j.{Logger, LoggerFactory} - -object MangoPayPaymentDao extends GenericPaymentDao with MangoPayPaymentHandler { - lazy val log: Logger = LoggerFactory getLogger getClass.getName -} diff --git a/mangopay/src/main/scala/app/softnetwork/payment/handlers/MangoPayPaymentHandler.scala b/mangopay/src/main/scala/app/softnetwork/payment/handlers/MangoPayPaymentHandler.scala deleted file mode 100644 index 7db51f0..0000000 --- a/mangopay/src/main/scala/app/softnetwork/payment/handlers/MangoPayPaymentHandler.scala +++ /dev/null @@ -1,9 +0,0 @@ -package app.softnetwork.payment.handlers - -import org.slf4j.{Logger, LoggerFactory} - -object MangoPayPaymentHandler extends MangoPayPaymentHandler { - lazy val log: Logger = LoggerFactory getLogger getClass.getName -} - -trait MangoPayPaymentHandler extends GenericPaymentHandler with MangoPayPaymentTypeKey diff --git a/mangopay/src/main/scala/app/softnetwork/payment/handlers/MangoPayPaymentTypeKey.scala b/mangopay/src/main/scala/app/softnetwork/payment/handlers/MangoPayPaymentTypeKey.scala deleted file mode 100644 index 51fdf47..0000000 --- a/mangopay/src/main/scala/app/softnetwork/payment/handlers/MangoPayPaymentTypeKey.scala +++ /dev/null @@ -1,15 +0,0 @@ -package app.softnetwork.payment.handlers - -import akka.cluster.sharding.typed.scaladsl.EntityTypeKey -import app.softnetwork.payment.message.PaymentMessages.PaymentCommand -import app.softnetwork.payment.persistence.typed.MangoPayPaymentBehavior -import app.softnetwork.persistence.typed.CommandTypeKey - -import scala.reflect.ClassTag - -/** Created by smanciot on 22/04/2022. - */ -trait MangoPayPaymentTypeKey extends CommandTypeKey[PaymentCommand] { - override def TypeKey(implicit tTag: ClassTag[PaymentCommand]): EntityTypeKey[PaymentCommand] = - MangoPayPaymentBehavior.TypeKey -} diff --git a/mangopay/src/main/scala/app/softnetwork/payment/persistence/query/MangoPayPaymentCommandProcessorStream.scala b/mangopay/src/main/scala/app/softnetwork/payment/persistence/query/MangoPayPaymentCommandProcessorStream.scala deleted file mode 100644 index 06cc8e9..0000000 --- a/mangopay/src/main/scala/app/softnetwork/payment/persistence/query/MangoPayPaymentCommandProcessorStream.scala +++ /dev/null @@ -1,10 +0,0 @@ -package app.softnetwork.payment.persistence.query - -import app.softnetwork.payment.handlers.MangoPayPaymentHandler -import app.softnetwork.persistence.query.{JournalProvider, OffsetProvider} - -trait MangoPayPaymentCommandProcessorStream - extends GenericPaymentCommandProcessorStream - with MangoPayPaymentHandler { - _: JournalProvider with OffsetProvider => -} diff --git a/mangopay/src/main/scala/app/softnetwork/payment/persistence/typed/MangoPayPaymentBehavior.scala b/mangopay/src/main/scala/app/softnetwork/payment/persistence/typed/MangoPayPaymentBehavior.scala deleted file mode 100644 index 6f35334..0000000 --- a/mangopay/src/main/scala/app/softnetwork/payment/persistence/typed/MangoPayPaymentBehavior.scala +++ /dev/null @@ -1,13 +0,0 @@ -package app.softnetwork.payment.persistence.typed - -import app.softnetwork.payment.config.MangoPay -import app.softnetwork.payment.handlers.{GenericPaymentDao, MangoPayPaymentDao} -import app.softnetwork.payment.model.SoftPaymentAccount.Client - -case object MangoPayPaymentBehavior extends MangoPayPaymentBehavior { - override lazy val paymentDao: GenericPaymentDao = MangoPayPaymentDao -} - -trait MangoPayPaymentBehavior extends GenericPaymentBehavior { - override def defaultProvider: Client.Provider = MangoPay.softPaymentProvider -} diff --git a/mangopay/src/main/scala/app/softnetwork/payment/service/MangoPayPaymentService.scala b/mangopay/src/main/scala/app/softnetwork/payment/service/MangoPayPaymentService.scala index 0766abf..cb6a615 100644 --- a/mangopay/src/main/scala/app/softnetwork/payment/service/MangoPayPaymentService.scala +++ b/mangopay/src/main/scala/app/softnetwork/payment/service/MangoPayPaymentService.scala @@ -3,7 +3,7 @@ package app.softnetwork.payment.service import akka.http.scaladsl.model.{HttpResponse, StatusCodes} import akka.http.scaladsl.server.Route import app.softnetwork.payment.config.PaymentSettings.HooksRoute -import app.softnetwork.payment.handlers.MangoPayPaymentHandler +import app.softnetwork.payment.handlers.PaymentHandler import app.softnetwork.payment.message.PaymentMessages.{ InvalidateRegularUser, KycDocumentStatusUpdated, @@ -23,8 +23,8 @@ import app.softnetwork.session.service.SessionMaterials import com.mangopay.core.enumerations.EventType trait MangoPayPaymentService[SD <: SessionData with SessionDataDecorator[SD]] - extends GenericPaymentService[SD] - with MangoPayPaymentHandler { + extends PaymentService[SD] + with PaymentHandler { _: SessionMaterials[SD] => def completeWithKycDocumentUpdatedResult( diff --git a/mangopay/src/main/scala/app/softnetwork/payment/service/MangoPayPaymentEndpoints.scala b/mangopay/src/main/scala/app/softnetwork/payment/service/MangoPayPaymentServiceEndpoints.scala similarity index 97% rename from mangopay/src/main/scala/app/softnetwork/payment/service/MangoPayPaymentEndpoints.scala rename to mangopay/src/main/scala/app/softnetwork/payment/service/MangoPayPaymentServiceEndpoints.scala index 9679e16..6707598 100644 --- a/mangopay/src/main/scala/app/softnetwork/payment/service/MangoPayPaymentEndpoints.scala +++ b/mangopay/src/main/scala/app/softnetwork/payment/service/MangoPayPaymentServiceEndpoints.scala @@ -1,7 +1,7 @@ package app.softnetwork.payment.service import app.softnetwork.payment.config.PaymentSettings -import app.softnetwork.payment.handlers.MangoPayPaymentHandler +import app.softnetwork.payment.handlers.PaymentHandler import app.softnetwork.payment.message.PaymentMessages._ import app.softnetwork.payment.model.{BankAccount, KycDocument, UboDeclaration} import app.softnetwork.session.model.{SessionData, SessionDataDecorator} @@ -11,9 +11,9 @@ import sttp.tapir.server.ServerEndpoint.Full import scala.concurrent.Future -trait MangoPayPaymentEndpoints[SD <: SessionData with SessionDataDecorator[SD]] - extends GenericPaymentEndpoints[SD] - with MangoPayPaymentHandler { +trait MangoPayPaymentServiceEndpoints[SD <: SessionData with SessionDataDecorator[SD]] + extends PaymentServiceEndpoints[SD] + with PaymentHandler { _: SessionMaterials[SD] => /** should be implemented by each payment provider diff --git a/project/Versions.scala b/project/Versions.scala index 7e9cffb..4d56869 100644 --- a/project/Versions.scala +++ b/project/Versions.scala @@ -1,12 +1,12 @@ object Versions { - val genericPersistence = "0.6.1" + val genericPersistence = "0.6.2" - val scheduler = "0.6.2" + val scheduler = "0.6.3" - val notification = "0.6.2" + val notification = "0.6.3" - val account = "0.6.1" + val account = "0.6.2" val scalatest = "3.2.16" } diff --git a/testkit/src/main/scala/app/softnetwork/payment/api/PaymentClientTestKit.scala b/testkit/src/main/scala/app/softnetwork/payment/api/PaymentClientTestKit.scala new file mode 100644 index 0000000..50d9525 --- /dev/null +++ b/testkit/src/main/scala/app/softnetwork/payment/api/PaymentClientTestKit.scala @@ -0,0 +1,16 @@ +package app.softnetwork.payment.api + +import app.softnetwork.payment.config.MangoPay +import app.softnetwork.payment.model.SoftPaymentAccount +import app.softnetwork.security.sha256 + +trait PaymentClientTestKit { + + def provider: SoftPaymentAccount.Client.Provider = + MangoPay.softPaymentProvider.withProviderType( + SoftPaymentAccount.Client.Provider.ProviderType.MOCK + ) + + def settings: PaymentClientSettings = + PaymentClientSettings(provider.clientId, sha256(provider.providerApiKey)) +} diff --git a/testkit/src/main/scala/app/softnetwork/payment/api/PaymentGrpcServer.scala b/testkit/src/main/scala/app/softnetwork/payment/api/PaymentGrpcServerTestKit.scala similarity index 88% rename from testkit/src/main/scala/app/softnetwork/payment/api/PaymentGrpcServer.scala rename to testkit/src/main/scala/app/softnetwork/payment/api/PaymentGrpcServerTestKit.scala index 1f9d51d..01a3119 100644 --- a/testkit/src/main/scala/app/softnetwork/payment/api/PaymentGrpcServer.scala +++ b/testkit/src/main/scala/app/softnetwork/payment/api/PaymentGrpcServerTestKit.scala @@ -6,9 +6,9 @@ import app.softnetwork.persistence.scalatest.InMemoryPersistenceTestKit import app.softnetwork.scheduler.launch.SchedulerGuardian import org.scalatest.Suite -trait PaymentGrpcServer +trait PaymentGrpcServerTestKit extends PersistenceScalatestGrpcTest - with PaymentGrpcServices + with PaymentGrpcServicesTestKit with InMemoryPersistenceTestKit { _: Suite with PaymentGuardian with SchedulerGuardian => override lazy val additionalConfig: String = paymentGrpcConfig } diff --git a/testkit/src/main/scala/app/softnetwork/payment/api/PaymentGrpcServices.scala b/testkit/src/main/scala/app/softnetwork/payment/api/PaymentGrpcServicesTestKit.scala similarity index 62% rename from testkit/src/main/scala/app/softnetwork/payment/api/PaymentGrpcServices.scala rename to testkit/src/main/scala/app/softnetwork/payment/api/PaymentGrpcServicesTestKit.scala index 8b2e363..b04fa67 100644 --- a/testkit/src/main/scala/app/softnetwork/payment/api/PaymentGrpcServices.scala +++ b/testkit/src/main/scala/app/softnetwork/payment/api/PaymentGrpcServicesTestKit.scala @@ -1,28 +1,18 @@ package app.softnetwork.payment.api import akka.actor.typed.ActorSystem -import akka.http.scaladsl.model.{HttpRequest, HttpResponse} +import app.softnetwork.api.server.GrpcService import app.softnetwork.api.server.scalatest.ServerTestKit import app.softnetwork.payment.launch.PaymentGuardian -import app.softnetwork.scheduler.api.SchedulerGrpcServices +import app.softnetwork.scheduler.api.SchedulerGrpcServicesTestKit import app.softnetwork.scheduler.launch.SchedulerGuardian -import scala.concurrent.Future - -trait PaymentGrpcServices extends SchedulerGrpcServices { +trait PaymentGrpcServicesTestKit extends SchedulerGrpcServicesTestKit with PaymentClientTestKit { _: PaymentGuardian with SchedulerGuardian with ServerTestKit => - override def grpcServices - : ActorSystem[_] => Seq[PartialFunction[HttpRequest, Future[HttpResponse]]] = system => + override def grpcServices: ActorSystem[_] => Seq[GrpcService] = system => paymentGrpcServices(system) ++ schedulerGrpcServices(system) - def paymentGrpcServices - : ActorSystem[_] => Seq[PartialFunction[HttpRequest, Future[HttpResponse]]] = - system => - Seq( - PaymentServiceApiHandler.partial(MockPaymentServer(system))(system) - ) - def paymentGrpcConfig: String = schedulerGrpcConfig + s""" |# Important: enable HTTP/2 in ActorSystem's config |akka.http.server.preview.enable-http2 = on @@ -31,5 +21,10 @@ trait PaymentGrpcServices extends SchedulerGrpcServices { | port = $port | use-tls = false |} + | + |payment.client-id = "${settings.clientId}" + | + |payment.api-key = "${settings.apiKey}" + | |""".stripMargin } diff --git a/testkit/src/main/scala/app/softnetwork/payment/handlers/MockPaymentDao.scala b/testkit/src/main/scala/app/softnetwork/payment/handlers/MockPaymentDao.scala index 64bec7a..61bccaa 100644 --- a/testkit/src/main/scala/app/softnetwork/payment/handlers/MockPaymentDao.scala +++ b/testkit/src/main/scala/app/softnetwork/payment/handlers/MockPaymentDao.scala @@ -2,6 +2,6 @@ package app.softnetwork.payment.handlers import org.slf4j.{Logger, LoggerFactory} -object MockPaymentDao extends GenericPaymentDao with MockPaymentHandler { +object MockPaymentDao extends PaymentDao with MockPaymentHandler { lazy val log: Logger = LoggerFactory getLogger getClass.getName } diff --git a/testkit/src/main/scala/app/softnetwork/payment/handlers/MockPaymentHandler.scala b/testkit/src/main/scala/app/softnetwork/payment/handlers/MockPaymentHandler.scala index 7739f86..b49dd59 100644 --- a/testkit/src/main/scala/app/softnetwork/payment/handlers/MockPaymentHandler.scala +++ b/testkit/src/main/scala/app/softnetwork/payment/handlers/MockPaymentHandler.scala @@ -6,4 +6,4 @@ object MockPaymentHandler extends MockPaymentHandler { lazy val log: Logger = LoggerFactory getLogger getClass.getName } -trait MockPaymentHandler extends GenericPaymentHandler with MockPaymentTypeKey +trait MockPaymentHandler extends PaymentHandler with MockPaymentTypeKey diff --git a/testkit/src/main/scala/app/softnetwork/payment/persistence/query/MockPaymentCommandProcessorStream.scala b/testkit/src/main/scala/app/softnetwork/payment/persistence/query/MockPaymentCommandProcessorStream.scala deleted file mode 100644 index 1a820ca..0000000 --- a/testkit/src/main/scala/app/softnetwork/payment/persistence/query/MockPaymentCommandProcessorStream.scala +++ /dev/null @@ -1,10 +0,0 @@ -package app.softnetwork.payment.persistence.query - -import app.softnetwork.payment.handlers.MockPaymentHandler -import app.softnetwork.persistence.query.{JournalProvider, OffsetProvider} - -trait MockPaymentCommandProcessorStream - extends GenericPaymentCommandProcessorStream - with MockPaymentHandler { - _: JournalProvider with OffsetProvider => -} diff --git a/testkit/src/main/scala/app/softnetwork/payment/persistence/typed/MockPaymentBehavior.scala b/testkit/src/main/scala/app/softnetwork/payment/persistence/typed/MockPaymentBehavior.scala index 0d84a70..bcae61a 100644 --- a/testkit/src/main/scala/app/softnetwork/payment/persistence/typed/MockPaymentBehavior.scala +++ b/testkit/src/main/scala/app/softnetwork/payment/persistence/typed/MockPaymentBehavior.scala @@ -1,22 +1,17 @@ package app.softnetwork.payment.persistence.typed -import app.softnetwork.payment.config.MangoPay import app.softnetwork.payment.handlers.{ - GenericPaymentDao, MockPaymentDao, MockSoftPaymentAccountDao, + PaymentDao, SoftPaymentAccountDao } -import app.softnetwork.payment.model.SoftPaymentAccount.Client -import app.softnetwork.payment.model.SoftPaymentAccount.Client.Provider -object MockPaymentBehavior extends GenericPaymentBehavior { +object MockPaymentBehavior extends PaymentBehavior { override def persistenceId = s"Mock${super.persistenceId}" - override lazy val paymentDao: GenericPaymentDao = MockPaymentDao + override lazy val paymentDao: PaymentDao = MockPaymentDao override lazy val softPaymentAccountDao: SoftPaymentAccountDao = MockSoftPaymentAccountDao - override def defaultProvider: Client.Provider = - MangoPay.softPaymentProvider.withProviderType(Provider.ProviderType.MOCK) } diff --git a/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentEndpointsTestKit.scala b/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentEndpointsTestKit.scala index 7c85c32..3a76285 100644 --- a/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentEndpointsTestKit.scala +++ b/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentEndpointsTestKit.scala @@ -7,10 +7,10 @@ import app.softnetwork.api.server.Endpoint import app.softnetwork.payment.handlers.{MockSoftPaymentAccountDao, SoftPaymentAccountDao} import app.softnetwork.payment.launch.PaymentEndpoints import app.softnetwork.payment.service.{ - GenericPaymentEndpoints, - MockPaymentEndpoints, + MockPaymentServiceEndpoints, MockSoftPaymentAccountServiceEndpoints, - MockSoftPaymentOAuthServiceEndpoints + MockSoftPaymentOAuthServiceEndpoints, + PaymentServiceEndpoints } import app.softnetwork.persistence.schema.SchemaProvider import app.softnetwork.session.scalatest.{SessionEndpointsRoutes, SessionTestKit} @@ -34,8 +34,8 @@ trait PaymentEndpointsTestKit[SD <: SessionData with SessionDataDecorator[SD]] implicit def sessionConfig: SessionConfig - override def paymentEndpoints: ActorSystem[_] => GenericPaymentEndpoints[SD] = sys => - new MockPaymentEndpoints[SD] with SessionMaterials[SD] { + override def paymentEndpoints: ActorSystem[_] => PaymentServiceEndpoints[SD] = sys => + new MockPaymentServiceEndpoints[SD] with SessionMaterials[SD] { override implicit def manager(implicit sessionConfig: SessionConfig, companion: SessionDataCompanion[SD] diff --git a/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentRouteTestKit.scala b/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentRouteTestKit.scala index ee3cc23..d7acf09 100644 --- a/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentRouteTestKit.scala +++ b/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentRouteTestKit.scala @@ -5,7 +5,7 @@ import akka.http.scaladsl.model.headers.RawHeader import akka.http.scaladsl.model.{ContentTypes, Multipart, StatusCodes} import app.softnetwork.api.server.ApiRoutes import app.softnetwork.api.server.config.ServerSettings.RootPath -import app.softnetwork.payment.api.PaymentGrpcServices +import app.softnetwork.payment.api.PaymentGrpcServicesTestKit import app.softnetwork.payment.config.PaymentSettings._ import app.softnetwork.payment.model._ import app.softnetwork.session.model.{SessionData, SessionDataDecorator} @@ -18,7 +18,7 @@ import java.nio.file.Paths trait PaymentRouteTestKit[SD <: SessionData with SessionDataDecorator[SD]] extends SessionTestKit[SD] with PaymentTestKit - with PaymentGrpcServices { + with PaymentGrpcServicesTestKit { _: Suite with ApiRoutes with SessionMaterials[SD] => import app.softnetwork.serialization._ diff --git a/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentRoutesTestKit.scala b/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentRoutesTestKit.scala index 2d4f1a9..71c6f8b 100644 --- a/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentRoutesTestKit.scala +++ b/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentRoutesTestKit.scala @@ -11,10 +11,10 @@ import app.softnetwork.api.server.ApiRoute import app.softnetwork.payment.handlers.{MockSoftPaymentAccountDao, SoftPaymentAccountDao} import app.softnetwork.payment.launch.PaymentRoutes import app.softnetwork.payment.service.{ - GenericPaymentService, MockPaymentService, MockSoftPaymentAccountService, - MockSoftPaymentOAuthService + MockSoftPaymentOAuthService, + PaymentService } import app.softnetwork.persistence.schema.SchemaProvider import app.softnetwork.session.model.{SessionData, SessionDataCompanion, SessionDataDecorator} @@ -31,7 +31,7 @@ trait PaymentRoutesTestKit[SD <: SessionData with SessionDataDecorator[SD]] with SessionServiceRoutes[SD] { self: PaymentTestKit with SessionTestKit[SD] with SchemaProvider with SessionMaterials[SD] => - override def paymentService: ActorSystem[_] => GenericPaymentService[SD] = sys => + override def paymentService: ActorSystem[_] => PaymentService[SD] = sys => new MockPaymentService[SD] with SessionMaterials[SD] { override implicit def manager(implicit sessionConfig: SessionConfig, diff --git a/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentTestKit.scala b/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentTestKit.scala index 2aa97b0..feb90d5 100644 --- a/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentTestKit.scala +++ b/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentTestKit.scala @@ -6,6 +6,7 @@ import app.softnetwork.account.model.BasicAccountProfile import app.softnetwork.account.persistence.query.AccountEventProcessorStreams.InternalAccountEvents2AccountProcessorStream import app.softnetwork.account.persistence.typed.AccountBehavior import app.softnetwork.notification.scalatest.AllNotificationsTestKit +import app.softnetwork.payment.api.{MockPaymentServer, PaymentClientTestKit, PaymentServer} import app.softnetwork.payment.config.PaymentSettings._ import app.softnetwork.payment.handlers.{ MockPaymentHandler, @@ -14,20 +15,16 @@ import app.softnetwork.payment.handlers.{ SoftPaymentAccountDao } import app.softnetwork.payment.launch.PaymentGuardian -import app.softnetwork.payment.message.PaymentMessages.{ - KycDocumentStatusNotUpdated, - UboDeclarationStatusUpdated, - _ -} +import app.softnetwork.payment.message.PaymentMessages._ import app.softnetwork.payment.model._ import app.softnetwork.payment.persistence.query.{ - GenericPaymentCommandProcessorStream, + PaymentCommandProcessorStream, Scheduler2PaymentProcessorStream } import app.softnetwork.payment.persistence.typed.{ - GenericPaymentBehavior, MockPaymentBehavior, - MockSoftPaymentAccountBehavior + MockSoftPaymentAccountBehavior, + PaymentBehavior } import app.softnetwork.persistence.launch.PersistentEntity import app.softnetwork.persistence.query.{ @@ -37,13 +34,18 @@ import app.softnetwork.persistence.query.{ } import app.softnetwork.scheduler.config.SchedulerSettings import app.softnetwork.scheduler.scalatest.SchedulerTestKit +import com.typesafe.config.{Config, ConfigFactory} import org.scalatest.Suite import org.slf4j.{Logger, LoggerFactory} import org.softnetwork.session.model.ApiKey import scala.concurrent.{ExecutionContext, Future} -trait PaymentTestKit extends SchedulerTestKit with PaymentGuardian with AllNotificationsTestKit { +trait PaymentTestKit + extends SchedulerTestKit + with PaymentGuardian + with AllNotificationsTestKit + with PaymentClientTestKit { _: Suite => /** @return @@ -51,26 +53,41 @@ trait PaymentTestKit extends SchedulerTestKit with PaymentGuardian with AllNotif */ override def roles: Seq[String] = super.roles :+ AkkaNodeRole :+ AccountSettings.AkkaNodeRole - override def paymentAccountBehavior: ActorSystem[_] => GenericPaymentBehavior = _ => - MockPaymentBehavior + override def paymentBehavior: ActorSystem[_] => PaymentBehavior = _ => MockPaymentBehavior override def accountBehavior : ActorSystem[_] => AccountBehavior[SoftPaymentAccount, BasicAccountProfile] = _ => MockSoftPaymentAccountBehavior + override def paymentServer: ActorSystem[_] => PaymentServer = system => MockPaymentServer(system) + def loadApiKey(clientId: String): Future[Option[ApiKey]] = MockPaymentBehavior.softPaymentAccountDao.loadApiKey(clientId) - override def paymentCommandProcessorStream - : ActorSystem[_] => GenericPaymentCommandProcessorStream = sys => - new GenericPaymentCommandProcessorStream - with MockPaymentHandler - with InMemoryJournalProvider - with InMemoryOffsetProvider { - lazy val log: Logger = LoggerFactory getLogger getClass.getName - override val forTests: Boolean = true - override implicit def system: ActorSystem[_] = sys - } + def clientId: String = settings.clientId + + override lazy val config: Config = akkaConfig + .withFallback(ConfigFactory.load("softnetwork-in-memory-persistence.conf")) + .withFallback( + ConfigFactory.parseString( + s""" + |payment.client-id = "$clientId" + |payment.api-key = "${settings.apiKey}" + |""".stripMargin + ) + ) + .withFallback(ConfigFactory.load()) + + override def paymentCommandProcessorStream: ActorSystem[_] => PaymentCommandProcessorStream = + sys => + new PaymentCommandProcessorStream + with MockPaymentHandler + with InMemoryJournalProvider + with InMemoryOffsetProvider { + lazy val log: Logger = LoggerFactory getLogger getClass.getName + override val forTests: Boolean = true + override implicit def system: ActorSystem[_] = sys + } override def scheduler2PaymentProcessorStream : ActorSystem[_] => Scheduler2PaymentProcessorStream = sys => diff --git a/testkit/src/main/scala/app/softnetwork/payment/service/MockPaymentEndpoints.scala b/testkit/src/main/scala/app/softnetwork/payment/service/MockPaymentServiceEndpoints.scala similarity index 68% rename from testkit/src/main/scala/app/softnetwork/payment/service/MockPaymentEndpoints.scala rename to testkit/src/main/scala/app/softnetwork/payment/service/MockPaymentServiceEndpoints.scala index c83ed27..d4a4dea 100644 --- a/testkit/src/main/scala/app/softnetwork/payment/service/MockPaymentEndpoints.scala +++ b/testkit/src/main/scala/app/softnetwork/payment/service/MockPaymentServiceEndpoints.scala @@ -4,8 +4,8 @@ import app.softnetwork.payment.handlers.MockPaymentHandler import app.softnetwork.session.model.{SessionData, SessionDataDecorator} import app.softnetwork.session.service.SessionMaterials -trait MockPaymentEndpoints[SD <: SessionData with SessionDataDecorator[SD]] - extends MangoPayPaymentEndpoints[SD] +trait MockPaymentServiceEndpoints[SD <: SessionData with SessionDataDecorator[SD]] + extends MangoPayPaymentServiceEndpoints[SD] with MockPaymentHandler { _: SessionMaterials[SD] => } diff --git a/testkit/src/test/scala/app/softnetwork/payment/handlers/PaymentHandlerSpec.scala b/testkit/src/test/scala/app/softnetwork/payment/handlers/PaymentHandlerSpec.scala index 0e27b57..c511351 100644 --- a/testkit/src/test/scala/app/softnetwork/payment/handlers/PaymentHandlerSpec.scala +++ b/testkit/src/test/scala/app/softnetwork/payment/handlers/PaymentHandlerSpec.scala @@ -1,7 +1,7 @@ package app.softnetwork.payment.handlers import akka.actor.typed.ActorSystem -import app.softnetwork.payment.api.{PaymentClient, PaymentGrpcServer} +import app.softnetwork.payment.api.{PaymentClient, PaymentGrpcServerTestKit} import app.softnetwork.payment.data._ import app.softnetwork.payment.message.PaymentMessages._ import app.softnetwork.payment.model.PaymentAccount.User @@ -22,7 +22,7 @@ class PaymentHandlerSpec extends MockPaymentHandler with AnyWordSpecLike with PaymentTestKit - with PaymentGrpcServer { + with PaymentGrpcServerTestKit { lazy val log: Logger = LoggerFactory getLogger getClass.getName @@ -38,7 +38,8 @@ class PaymentHandlerSpec !?( PreRegisterCard( orderUuid, - naturalUser.withProfile("customer") + naturalUser.withProfile("customer"), + clientId = Some(clientId) ) ) await { case cardPreRegistered: CardPreRegistered => @@ -158,7 +159,8 @@ class PaymentHandlerSpec CreateOrUpdateBankAccount( computeExternalUuidWithProfile(sellerUuid, Some("seller")), BankAccount(None, ownerName, ownerAddress, iban, ""), - Some(User.NaturalUser(naturalUser.withExternalUuid(sellerUuid).withProfile("seller"))) + Some(User.NaturalUser(naturalUser.withExternalUuid(sellerUuid).withProfile("seller"))), + clientId = Some(clientId) ) ) await { case r: BankAccountCreatedOrUpdated => @@ -204,7 +206,8 @@ class PaymentHandlerSpec .withExternalUuid(sellerUuid) .withProfile("seller") ) - ) + ), + clientId = Some(clientId) ) ) await { case r: BankAccountCreatedOrUpdated => @@ -250,7 +253,8 @@ class PaymentHandlerSpec .withExternalUuid(sellerUuid) .withProfile("seller") ) - ) + ), + clientId = Some(clientId) ) ) await { case r: BankAccountCreatedOrUpdated => @@ -277,7 +281,8 @@ class PaymentHandlerSpec .withExternalUuid(sellerUuid) .withProfile("seller") ) - ) + ), + clientId = Some(clientId) ) ) await { case r: BankAccountCreatedOrUpdated => @@ -308,7 +313,8 @@ class PaymentHandlerSpec .withExternalUuid(sellerUuid) .withProfile("seller") ) - ) + ), + clientId = Some(clientId) ) ) await { case r: BankAccountCreatedOrUpdated => assert(!r.kycUpdated && !r.documentsUpdated && r.userUpdated) @@ -335,7 +341,8 @@ class PaymentHandlerSpec .withExternalUuid(sellerUuid) .withProfile("seller") ) - ) + ), + clientId = Some(clientId) ) ) await { case r: BankAccountCreatedOrUpdated => assert(!r.kycUpdated && !r.documentsUpdated && r.userUpdated) @@ -415,7 +422,8 @@ class PaymentHandlerSpec legalUser.withLegalRepresentative(legalUser.legalRepresentative.withProfile("seller")) ) ), - Some(true) + Some(true), + clientId = Some(clientId) ) ) await { case r: BankAccountCreatedOrUpdated => @@ -465,7 +473,8 @@ class PaymentHandlerSpec ) ) ), - Some(true) + Some(true), + clientId = Some(clientId) ) ) await { case r: BankAccountCreatedOrUpdated => @@ -541,7 +550,8 @@ class PaymentHandlerSpec computeExternalUuidWithProfile(sellerUuid, Some("seller")), updatedBankAccount, Some(User.LegalUser(updatedLegalUser)), - Some(true) + Some(true), + clientId = Some(clientId) ) ) await { case r: BankAccountCreatedOrUpdated => @@ -590,7 +600,8 @@ class PaymentHandlerSpec computeExternalUuidWithProfile(sellerUuid, Some("seller")), updatedBankAccount, Some(User.LegalUser(updatedLegalUser)), - Some(true) + Some(true), + clientId = Some(clientId) ) ) await { case r: BankAccountCreatedOrUpdated => @@ -605,7 +616,8 @@ class PaymentHandlerSpec computeExternalUuidWithProfile(sellerUuid, Some("seller")), updatedBankAccount.withBic(""), Some(User.LegalUser(updatedLegalUser)), - Some(true) + Some(true), + clientId = Some(clientId) ) ) await { case r: BankAccountCreatedOrUpdated => @@ -624,7 +636,8 @@ class PaymentHandlerSpec computeExternalUuidWithProfile(sellerUuid, Some("seller")), updatedBankAccount, Some(User.LegalUser(updatedLegalUser)), - Some(true) + Some(true), + clientId = Some(clientId) ) ) await { case r: BankAccountCreatedOrUpdated => @@ -969,7 +982,8 @@ class PaymentHandlerSpec CreateOrUpdateBankAccount( computeExternalUuidWithProfile(vendorUuid, Some("vendor")), BankAccount(None, ownerName, ownerAddress, iban, bic), - Some(User.NaturalUser(naturalUser.withExternalUuid(vendorUuid).withProfile("vendor"))) + Some(User.NaturalUser(naturalUser.withExternalUuid(vendorUuid).withProfile("vendor"))), + clientId = Some(clientId) ) ) await { case r: BankAccountCreatedOrUpdated => diff --git a/testkit/src/test/scala/app/softnetwork/payment/service/PaymentServiceSpec.scala b/testkit/src/test/scala/app/softnetwork/payment/service/PaymentServiceSpec.scala index 0d419e9..c0c8729 100644 --- a/testkit/src/test/scala/app/softnetwork/payment/service/PaymentServiceSpec.scala +++ b/testkit/src/test/scala/app/softnetwork/payment/service/PaymentServiceSpec.scala @@ -9,7 +9,6 @@ import app.softnetwork.payment.data._ import app.softnetwork.payment.config.PaymentSettings._ import app.softnetwork.payment.message.PaymentMessages._ import app.softnetwork.payment.model._ -import app.softnetwork.payment.persistence.typed.MockPaymentBehavior import app.softnetwork.payment.scalatest.PaymentRouteTestKit import app.softnetwork.time._ import app.softnetwork.persistence.now @@ -34,8 +33,6 @@ trait PaymentServiceSpec[SD <: SessionData with SessionDataDecorator[SD]] lazy val paymentClient: PaymentClient = PaymentClient(ts) - def clientId: String = MockPaymentBehavior.defaultProvider.clientId - lazy val customerSession: SD with SessionDataDecorator[SD] = companion.newSession.withId(customerUuid).withProfile(Some("customer")).withClientId(clientId) From fbd638d458bd28e29da1615d308fc004b5860971 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Manciot?= Date: Wed, 6 Dec 2023 14:32:26 +0100 Subject: [PATCH 12/37] fix mangopay api with scheduler --- .../payment/persistence/typed/PaymentBehavior.scala | 6 +++++- .../payment/api/MangoPayWithSchedulerApi.scala | 13 ++++--------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/core/src/main/scala/app/softnetwork/payment/persistence/typed/PaymentBehavior.scala b/core/src/main/scala/app/softnetwork/payment/persistence/typed/PaymentBehavior.scala index ff1196d..a4ea686 100644 --- a/core/src/main/scala/app/softnetwork/payment/persistence/typed/PaymentBehavior.scala +++ b/core/src/main/scala/app/softnetwork/payment/persistence/typed/PaymentBehavior.scala @@ -3398,7 +3398,11 @@ trait PaymentBehavior state: Option[PaymentAccount], user: PaymentAccount.User, clientId: Option[String] - )(implicit system: ActorSystem[_], log: Logger, paymentClientSettings: PaymentClientSettings): Option[PaymentAccount] = { + )(implicit + system: ActorSystem[_], + log: Logger, + paymentClientSettings: PaymentClientSettings + ): Option[PaymentAccount] = { val pa = PaymentAccount.defaultInstance.withUser(user).copy(clientId = clientId) val uuid = pa.externalUuidWithProfile state match { diff --git a/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayWithSchedulerApi.scala b/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayWithSchedulerApi.scala index 0a60f80..8346d64 100644 --- a/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayWithSchedulerApi.scala +++ b/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayWithSchedulerApi.scala @@ -1,19 +1,17 @@ package app.softnetwork.payment.api import akka.actor.typed.ActorSystem -import akka.http.scaladsl.model.{HttpRequest, HttpResponse} +import app.softnetwork.api.server.GrpcService import app.softnetwork.persistence.jdbc.query.{JdbcJournalProvider, JdbcOffsetProvider} import app.softnetwork.persistence.launch.PersistentEntity import app.softnetwork.persistence.query.EventProcessorStream import app.softnetwork.persistence.schema.SchemaProvider -import app.softnetwork.scheduler.api.{SchedulerApi, SchedulerServiceApiHandler} +import app.softnetwork.scheduler.api.SchedulerApi import app.softnetwork.scheduler.handlers.SchedulerHandler import app.softnetwork.scheduler.persistence.query.Entity2SchedulerProcessorStream import app.softnetwork.session.model.{SessionData, SessionDataDecorator} import com.typesafe.config.Config -import scala.concurrent.Future - trait MangoPayWithSchedulerApi[SD <: SessionData with SessionDataDecorator[SD]] extends MangoPayApi[SD] with SchedulerApi { _: SchemaProvider => @@ -39,9 +37,6 @@ trait MangoPayWithSchedulerApi[SD <: SessionData with SessionDataDecorator[SD]] initSchedulerSystem(system) }*/ - override def grpcServices - : ActorSystem[_] => Seq[PartialFunction[HttpRequest, Future[HttpResponse]]] = system => - Seq( - PaymentServiceApiHandler.partial(PaymentServer(system))(system) - ) :+ SchedulerServiceApiHandler.partial(schedulerServer(system))(system) + override def grpcServices: ActorSystem[_] => Seq[GrpcService] = system => + paymentGrpcServices(system) ++ schedulerGrpcServices(system) } From 6b1e534dc46bc69054383b09256cdb803d3b9ae9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Manciot?= Date: Wed, 6 Dec 2023 19:38:29 +0100 Subject: [PATCH 13/37] init client module --- build.sbt | 12 ++++++-- client/build.sbt | 13 +++++++++ .../src/main/protobuf/api/payment.proto | 0 .../main/protobuf/model/payment/address.proto | 2 +- .../main/protobuf/model/payment/card.proto | 2 +- .../protobuf/model/payment/document.proto | 2 +- .../protobuf/model/payment/paymentUser.proto | 2 +- .../protobuf/model/payment/transaction.proto | 0 client/src/main/resources/reference.conf | 21 ++++++++++++++ .../payment/api/PaymentClient.scala | 16 ++++------- .../api/config}/PaymentClientSettings.scala | 2 +- .../payment/api/serialization/package.scala | 28 ++++++++++++++++--- .../payment/model/AddressDecorator.scala | 4 ++- .../payment/model/BankAccountCompanion.scala | 0 .../payment/model/BankAccountDecorator.scala | 3 +- .../payment/model/BankAccountOwner.scala | 0 .../payment/model/CardDecorator.scala | 5 ++-- .../payment/model/KycDocumentDecorator.scala | 4 ++- .../payment/model/LegalUserDecorator.scala | 3 +- .../payment/model/LegalUserDetails.scala | 0 .../model/PaymentAccountDecorator.scala | 3 +- .../payment/model/PaymentUserCompanion.scala | 0 .../payment/model/PaymentUserDecorator.scala | 4 ++- .../model/RecurringPaymentDecorator.scala | 0 .../payment/model/RefundAction.scala | 0 .../payment/model/TransactionCompanion.scala | 0 .../payment/model/TransactionDecorator.scala | 0 .../model/UboDeclarationDecorator.scala | 0 .../UltimateBeneficialOwnerDecorator.scala | 0 .../softnetwork/payment/model/package.scala | 0 common/build.sbt | 13 ++------- common/src/main/resources/reference.conf | 18 ------------ .../payment/serialization/package.scala | 20 ------------- core/build.sbt | 4 +++ .../payment/api/PaymentServer.scala | 1 + .../persistence/typed/PaymentBehavior.scala | 2 +- .../payment/api/PaymentClientTestKit.scala | 1 + 37 files changed, 107 insertions(+), 78 deletions(-) create mode 100644 client/build.sbt rename {common => client}/src/main/protobuf/api/payment.proto (100%) rename {common => client}/src/main/protobuf/model/payment/address.proto (92%) rename {common => client}/src/main/protobuf/model/payment/card.proto (94%) rename {common => client}/src/main/protobuf/model/payment/document.proto (98%) rename {common => client}/src/main/protobuf/model/payment/paymentUser.proto (99%) rename {common => client}/src/main/protobuf/model/payment/transaction.proto (100%) create mode 100644 client/src/main/resources/reference.conf rename {common => client}/src/main/scala/app/softnetwork/payment/api/PaymentClient.scala (94%) rename {common/src/main/scala/app/softnetwork/payment/api => client/src/main/scala/app/softnetwork/payment/api/config}/PaymentClientSettings.scala (93%) rename common/src/main/scala/app/softnetwork/payment/api/api.scala => client/src/main/scala/app/softnetwork/payment/api/serialization/package.scala (81%) rename {common => client}/src/main/scala/app/softnetwork/payment/model/AddressDecorator.scala (91%) rename {common => client}/src/main/scala/app/softnetwork/payment/model/BankAccountCompanion.scala (100%) rename {common => client}/src/main/scala/app/softnetwork/payment/model/BankAccountDecorator.scala (96%) rename {common => client}/src/main/scala/app/softnetwork/payment/model/BankAccountOwner.scala (100%) rename {common => client}/src/main/scala/app/softnetwork/payment/model/CardDecorator.scala (92%) rename {common => client}/src/main/scala/app/softnetwork/payment/model/KycDocumentDecorator.scala (87%) rename {common => client}/src/main/scala/app/softnetwork/payment/model/LegalUserDecorator.scala (93%) rename {common => client}/src/main/scala/app/softnetwork/payment/model/LegalUserDetails.scala (100%) rename {common => client}/src/main/scala/app/softnetwork/payment/model/PaymentAccountDecorator.scala (97%) rename {common => client}/src/main/scala/app/softnetwork/payment/model/PaymentUserCompanion.scala (100%) rename {common => client}/src/main/scala/app/softnetwork/payment/model/PaymentUserDecorator.scala (89%) rename {common => client}/src/main/scala/app/softnetwork/payment/model/RecurringPaymentDecorator.scala (100%) rename {common => client}/src/main/scala/app/softnetwork/payment/model/RefundAction.scala (100%) rename {common => client}/src/main/scala/app/softnetwork/payment/model/TransactionCompanion.scala (100%) rename {common => client}/src/main/scala/app/softnetwork/payment/model/TransactionDecorator.scala (100%) rename {common => client}/src/main/scala/app/softnetwork/payment/model/UboDeclarationDecorator.scala (100%) rename {common => client}/src/main/scala/app/softnetwork/payment/model/UltimateBeneficialOwnerDecorator.scala (100%) rename {common => client}/src/main/scala/app/softnetwork/payment/model/package.scala (100%) diff --git a/build.sbt b/build.sbt index a728258..42b5369 100644 --- a/build.sbt +++ b/build.sbt @@ -29,15 +29,23 @@ ThisBuild / libraryDependencies ++= Seq( Test / parallelExecution := false +lazy val client = project.in(file("client")) + .configs(IntegrationTest) + .settings(Defaults.itSettings) + .enablePlugins(AkkaGrpcPlugin) + lazy val common = project.in(file("common")) .configs(IntegrationTest) .settings(Defaults.itSettings) .enablePlugins(AkkaGrpcPlugin) + .dependsOn( + client % "compile->compile;test->test;it->it" + ) lazy val core = project.in(file("core")) .configs(IntegrationTest) .settings(Defaults.itSettings, app.softnetwork.Info.infoSettings) - .enablePlugins(BuildInfoPlugin) + .enablePlugins(BuildInfoPlugin, AkkaGrpcPlugin) .dependsOn( common % "compile->compile;test->test;it->it" ) @@ -72,6 +80,6 @@ lazy val testkit = project.in(file("testkit")) ) lazy val root = project.in(file(".")) - .aggregate(common, core, mangopay, stripe, testkit, api) + .aggregate(client, common, core, mangopay, stripe, testkit, api) .configs(IntegrationTest) .settings(Defaults.itSettings) diff --git a/client/build.sbt b/client/build.sbt new file mode 100644 index 0000000..a32ed63 --- /dev/null +++ b/client/build.sbt @@ -0,0 +1,13 @@ +organization := "app.softnetwork.payment" + +name := "payment-client" + +akkaGrpcGeneratedSources := Seq(AkkaGrpc.Client) + +libraryDependencies ++= Seq( + "app.softnetwork.account" %% "account-common" % Versions.account, + "app.softnetwork.account" %% "account-common" % Versions.account % "protobuf", + "app.softnetwork.api" %% "generic-server-api" % Versions.genericPersistence, + "app.softnetwork.protobuf" %% "scalapb-extensions" % "0.1.7", + "commons-validator" % "commons-validator" % "1.6" +) \ No newline at end of file diff --git a/common/src/main/protobuf/api/payment.proto b/client/src/main/protobuf/api/payment.proto similarity index 100% rename from common/src/main/protobuf/api/payment.proto rename to client/src/main/protobuf/api/payment.proto diff --git a/common/src/main/protobuf/model/payment/address.proto b/client/src/main/protobuf/model/payment/address.proto similarity index 92% rename from common/src/main/protobuf/model/payment/address.proto rename to client/src/main/protobuf/model/payment/address.proto index 14bc45a..4de1b14 100644 --- a/common/src/main/protobuf/model/payment/address.proto +++ b/client/src/main/protobuf/model/payment/address.proto @@ -11,7 +11,7 @@ option (scalapb.options) = { import: "app.softnetwork.persistence.model._" import: "app.softnetwork.serialization._" import: "app.softnetwork.payment.model._" - import: "app.softnetwork.payment.serialization._" +// import: "app.softnetwork.payment.serialization._" preserve_unknown_fields: false }; diff --git a/common/src/main/protobuf/model/payment/card.proto b/client/src/main/protobuf/model/payment/card.proto similarity index 94% rename from common/src/main/protobuf/model/payment/card.proto rename to client/src/main/protobuf/model/payment/card.proto index 23861af..3e711a3 100644 --- a/common/src/main/protobuf/model/payment/card.proto +++ b/client/src/main/protobuf/model/payment/card.proto @@ -11,7 +11,7 @@ option (scalapb.options) = { import: "app.softnetwork.persistence.model._" import: "app.softnetwork.serialization._" import: "app.softnetwork.payment.model._" - import: "app.softnetwork.payment.serialization._" +// import: "app.softnetwork.payment.serialization._" preserve_unknown_fields: false }; diff --git a/common/src/main/protobuf/model/payment/document.proto b/client/src/main/protobuf/model/payment/document.proto similarity index 98% rename from common/src/main/protobuf/model/payment/document.proto rename to client/src/main/protobuf/model/payment/document.proto index ef70315..be34922 100644 --- a/common/src/main/protobuf/model/payment/document.proto +++ b/client/src/main/protobuf/model/payment/document.proto @@ -14,7 +14,7 @@ option (scalapb.options) = { import: "app.softnetwork.protobuf.ScalaPBTypeMappers._" import: "app.softnetwork.serialization._" import: "app.softnetwork.payment.model._" - import: "app.softnetwork.payment.serialization._" +// import: "app.softnetwork.payment.serialization._" preserve_unknown_fields: false }; diff --git a/common/src/main/protobuf/model/payment/paymentUser.proto b/client/src/main/protobuf/model/payment/paymentUser.proto similarity index 99% rename from common/src/main/protobuf/model/payment/paymentUser.proto rename to client/src/main/protobuf/model/payment/paymentUser.proto index c302bc1..c9bb8fe 100644 --- a/common/src/main/protobuf/model/payment/paymentUser.proto +++ b/client/src/main/protobuf/model/payment/paymentUser.proto @@ -17,7 +17,7 @@ option (scalapb.options) = { import: "app.softnetwork.protobuf.ScalaPBTypeMappers._" import: "app.softnetwork.serialization._" import: "app.softnetwork.payment.model._" - import: "app.softnetwork.payment.serialization._" +// import: "app.softnetwork.payment.serialization._" preserve_unknown_fields: false }; diff --git a/common/src/main/protobuf/model/payment/transaction.proto b/client/src/main/protobuf/model/payment/transaction.proto similarity index 100% rename from common/src/main/protobuf/model/payment/transaction.proto rename to client/src/main/protobuf/model/payment/transaction.proto diff --git a/client/src/main/resources/reference.conf b/client/src/main/resources/reference.conf new file mode 100644 index 0000000..c0f2fb4 --- /dev/null +++ b/client/src/main/resources/reference.conf @@ -0,0 +1,21 @@ +akka.http.session { + encrypt-data = true + + jws { + alg = "HS256" + } + + jwt { + iss = "softpayment" + include-iat = true + } +} + +payment{ + client-id = "" + client-id = ${?PAYMENT_CLIENT_ID} + + api-key = "" + api-key = ${?PAYMENT_API_KEY} +} + diff --git a/common/src/main/scala/app/softnetwork/payment/api/PaymentClient.scala b/client/src/main/scala/app/softnetwork/payment/api/PaymentClient.scala similarity index 94% rename from common/src/main/scala/app/softnetwork/payment/api/PaymentClient.scala rename to client/src/main/scala/app/softnetwork/payment/api/PaymentClient.scala index fec77b6..975328a 100644 --- a/common/src/main/scala/app/softnetwork/payment/api/PaymentClient.scala +++ b/client/src/main/scala/app/softnetwork/payment/api/PaymentClient.scala @@ -4,14 +4,14 @@ import akka.actor.typed.ActorSystem import akka.grpc.GrpcClientSettings import akka.grpc.scaladsl.SingleResponseRequestBuilder import app.softnetwork.api.server.client.{GrpcClient, GrpcClientFactory} -import app.softnetwork.payment.annotation.InternalApi +import app.softnetwork.payment.api.config.PaymentClientSettings +import app.softnetwork.payment.api.serialization._ import app.softnetwork.payment.model.{ BankAccountOwner, LegalUserDetails, PaymentAccount, RecurringPayment } -import app.softnetwork.payment.serialization._ import java.util.Date import scala.concurrent.Future @@ -22,15 +22,11 @@ trait PaymentClient extends GrpcClient { GrpcClientSettings.fromConfig(name) ) - @InternalApi - private[payment] def paymentClientSettings: PaymentClientSettings = PaymentClientSettings(system) + lazy val settings: PaymentClientSettings = PaymentClientSettings(system) - @InternalApi - private[payment] lazy val generatedToken: String = - paymentClientSettings.generateToken() + private lazy val generatedToken: String = settings.generateToken() - @InternalApi - private[payment] def withAuthorization[Req, Res]( + private def withAuthorization[Req, Res]( single: SingleResponseRequestBuilder[Req, Res], token: Option[String] ): SingleResponseRequestBuilder[Req, Res] = { @@ -47,7 +43,7 @@ trait PaymentClient extends GrpcClient { ) .invoke( CreateOrUpdatePaymentAccountRequest( - Some(paymentAccount.withClientId(paymentClientSettings.clientId)) + Some(paymentAccount.withClientId(settings.clientId)) ) ) map (_.succeeded) } diff --git a/common/src/main/scala/app/softnetwork/payment/api/PaymentClientSettings.scala b/client/src/main/scala/app/softnetwork/payment/api/config/PaymentClientSettings.scala similarity index 93% rename from common/src/main/scala/app/softnetwork/payment/api/PaymentClientSettings.scala rename to client/src/main/scala/app/softnetwork/payment/api/config/PaymentClientSettings.scala index 1dcb5f4..b696bfe 100644 --- a/common/src/main/scala/app/softnetwork/payment/api/PaymentClientSettings.scala +++ b/client/src/main/scala/app/softnetwork/payment/api/config/PaymentClientSettings.scala @@ -1,4 +1,4 @@ -package app.softnetwork.payment.api +package app.softnetwork.payment.api.config import akka.actor.typed.ActorSystem import org.softnetwork.session.model.JwtClaims diff --git a/common/src/main/scala/app/softnetwork/payment/api/api.scala b/client/src/main/scala/app/softnetwork/payment/api/serialization/package.scala similarity index 81% rename from common/src/main/scala/app/softnetwork/payment/api/api.scala rename to client/src/main/scala/app/softnetwork/payment/api/serialization/package.scala index 9e30a71..a15a425 100644 --- a/common/src/main/scala/app/softnetwork/payment/api/api.scala +++ b/client/src/main/scala/app/softnetwork/payment/api/serialization/package.scala @@ -1,11 +1,10 @@ -package app.softnetwork.payment +package app.softnetwork.payment.api -import app.softnetwork.payment.model.RecurringPayment +import app.softnetwork.payment.model.{LegalUser, RecurringPayment} import scala.language.implicitConversions -package object api { - +package object serialization { implicit def recurringPaymentTypeToRegisterRecurringPaymentType( `type`: RecurringPayment.RecurringPaymentType ): RegisterRecurringPaymentRequest.RecurringPaymentType = { @@ -77,4 +76,25 @@ package object api { case _ => None } } + + implicit def LegalUserTypeToLegalResponseUserType( + legalUserType: LegalUser.LegalUserType + ): LegalUserType = { + legalUserType match { + case LegalUser.LegalUserType.BUSINESS => LegalUserType.BUSINESS + case LegalUser.LegalUserType.SOLETRADER => LegalUserType.SOLETRADER + case LegalUser.LegalUserType.ORGANIZATION => LegalUserType.ORGANIZATION + } + } + + implicit def LegalResponseUserTypeToLegalUserType( + legalUserType: LegalUserType + ): LegalUser.LegalUserType = { + legalUserType match { + case LegalUserType.BUSINESS => LegalUser.LegalUserType.BUSINESS + case LegalUserType.SOLETRADER => LegalUser.LegalUserType.SOLETRADER + case LegalUserType.ORGANIZATION => LegalUser.LegalUserType.ORGANIZATION + } + } + } diff --git a/common/src/main/scala/app/softnetwork/payment/model/AddressDecorator.scala b/client/src/main/scala/app/softnetwork/payment/model/AddressDecorator.scala similarity index 91% rename from common/src/main/scala/app/softnetwork/payment/model/AddressDecorator.scala rename to client/src/main/scala/app/softnetwork/payment/model/AddressDecorator.scala index 62b9dd3..f99aa90 100644 --- a/common/src/main/scala/app/softnetwork/payment/model/AddressDecorator.scala +++ b/client/src/main/scala/app/softnetwork/payment/model/AddressDecorator.scala @@ -1,5 +1,7 @@ package app.softnetwork.payment.model +import app.softnetwork.payment.model + import java.util.Locale trait AddressDecorator { self: Address => @@ -10,7 +12,7 @@ trait AddressDecorator { self: Address => country.trim.isEmpty || postalCode.trim.isEmpty - lazy val view: AddressView = AddressView(self) + lazy val view: AddressView = model.AddressView(self) override def equals(obj: Any): Boolean = obj match { case address: Address => diff --git a/common/src/main/scala/app/softnetwork/payment/model/BankAccountCompanion.scala b/client/src/main/scala/app/softnetwork/payment/model/BankAccountCompanion.scala similarity index 100% rename from common/src/main/scala/app/softnetwork/payment/model/BankAccountCompanion.scala rename to client/src/main/scala/app/softnetwork/payment/model/BankAccountCompanion.scala diff --git a/common/src/main/scala/app/softnetwork/payment/model/BankAccountDecorator.scala b/client/src/main/scala/app/softnetwork/payment/model/BankAccountDecorator.scala similarity index 96% rename from common/src/main/scala/app/softnetwork/payment/model/BankAccountDecorator.scala rename to client/src/main/scala/app/softnetwork/payment/model/BankAccountDecorator.scala index e3c325d..0c579d1 100644 --- a/common/src/main/scala/app/softnetwork/payment/model/BankAccountDecorator.scala +++ b/client/src/main/scala/app/softnetwork/payment/model/BankAccountDecorator.scala @@ -1,5 +1,6 @@ package app.softnetwork.payment.model +import app.softnetwork.payment.model import app.softnetwork.security._ import app.softnetwork.validation.RegexValidator import org.apache.commons.validator.routines.IBANValidator @@ -65,7 +66,7 @@ trait BankAccountDecorator { self: BankAccount => lazy val tag: String = externalUuid - lazy val view: BankAccountView = BankAccountView(self) + lazy val view: BankAccountView = model.BankAccountView(self) } case class BankAccountView( diff --git a/common/src/main/scala/app/softnetwork/payment/model/BankAccountOwner.scala b/client/src/main/scala/app/softnetwork/payment/model/BankAccountOwner.scala similarity index 100% rename from common/src/main/scala/app/softnetwork/payment/model/BankAccountOwner.scala rename to client/src/main/scala/app/softnetwork/payment/model/BankAccountOwner.scala diff --git a/common/src/main/scala/app/softnetwork/payment/model/CardDecorator.scala b/client/src/main/scala/app/softnetwork/payment/model/CardDecorator.scala similarity index 92% rename from common/src/main/scala/app/softnetwork/payment/model/CardDecorator.scala rename to client/src/main/scala/app/softnetwork/payment/model/CardDecorator.scala index 39fa261..85b8010 100644 --- a/common/src/main/scala/app/softnetwork/payment/model/CardDecorator.scala +++ b/client/src/main/scala/app/softnetwork/payment/model/CardDecorator.scala @@ -1,8 +1,9 @@ package app.softnetwork.payment.model +import app.softnetwork.payment.model + import java.text.SimpleDateFormat import java.util.Date - import scala.util.{Failure, Success, Try} trait CardDecorator { self: Card => @@ -22,7 +23,7 @@ trait CardDecorator { self: Card => .withLastName(lastName) .withBirthday(birthday) - lazy val view: CardView = CardView(self) + lazy val view: CardView = model.CardView(self) } case class CardView( diff --git a/common/src/main/scala/app/softnetwork/payment/model/KycDocumentDecorator.scala b/client/src/main/scala/app/softnetwork/payment/model/KycDocumentDecorator.scala similarity index 87% rename from common/src/main/scala/app/softnetwork/payment/model/KycDocumentDecorator.scala rename to client/src/main/scala/app/softnetwork/payment/model/KycDocumentDecorator.scala index e698291..286dbc1 100644 --- a/common/src/main/scala/app/softnetwork/payment/model/KycDocumentDecorator.scala +++ b/client/src/main/scala/app/softnetwork/payment/model/KycDocumentDecorator.scala @@ -1,7 +1,9 @@ package app.softnetwork.payment.model +import app.softnetwork.payment.model + trait KycDocumentDecorator { self: KycDocument => - lazy val view: KycDocumentView = KycDocumentView(self) + lazy val view: KycDocumentView = model.KycDocumentView(self) } case class KycDocumentView( diff --git a/common/src/main/scala/app/softnetwork/payment/model/LegalUserDecorator.scala b/client/src/main/scala/app/softnetwork/payment/model/LegalUserDecorator.scala similarity index 93% rename from common/src/main/scala/app/softnetwork/payment/model/LegalUserDecorator.scala rename to client/src/main/scala/app/softnetwork/payment/model/LegalUserDecorator.scala index 2ecb4e2..6392125 100644 --- a/common/src/main/scala/app/softnetwork/payment/model/LegalUserDecorator.scala +++ b/client/src/main/scala/app/softnetwork/payment/model/LegalUserDecorator.scala @@ -1,5 +1,6 @@ package app.softnetwork.payment.model +import app.softnetwork.payment.model import app.softnetwork.validation.RegexValidator import scala.util.matching.Regex @@ -16,7 +17,7 @@ trait LegalUserDecorator { self: LegalUser => lazy val uboDeclarationValidated: Boolean = !uboDeclarationRequired || uboDeclaration.exists(_.status.isUboDeclarationValidated) - lazy val view: LegalUserView = LegalUserView(self) + lazy val view: LegalUserView = model.LegalUserView(self) } object SiretValidator extends RegexValidator { diff --git a/common/src/main/scala/app/softnetwork/payment/model/LegalUserDetails.scala b/client/src/main/scala/app/softnetwork/payment/model/LegalUserDetails.scala similarity index 100% rename from common/src/main/scala/app/softnetwork/payment/model/LegalUserDetails.scala rename to client/src/main/scala/app/softnetwork/payment/model/LegalUserDetails.scala diff --git a/common/src/main/scala/app/softnetwork/payment/model/PaymentAccountDecorator.scala b/client/src/main/scala/app/softnetwork/payment/model/PaymentAccountDecorator.scala similarity index 97% rename from common/src/main/scala/app/softnetwork/payment/model/PaymentAccountDecorator.scala rename to client/src/main/scala/app/softnetwork/payment/model/PaymentAccountDecorator.scala index 15e6016..5249ae8 100644 --- a/common/src/main/scala/app/softnetwork/payment/model/PaymentAccountDecorator.scala +++ b/client/src/main/scala/app/softnetwork/payment/model/PaymentAccountDecorator.scala @@ -1,5 +1,6 @@ package app.softnetwork.payment.model +import app.softnetwork.payment import app.softnetwork.persistence._ import java.time.Instant @@ -109,7 +110,7 @@ trait PaymentAccountDecorator { self: PaymentAccount => lazy val hasAcceptedTermsOfPSP: Boolean = !legalUser || getLegalUser.lastAcceptedTermsOfPSP.isDefined - lazy val view: PaymentAccountView = PaymentAccountView(self) + lazy val view: PaymentAccountView = payment.model.PaymentAccountView(self) } case class PaymentAccountView( diff --git a/common/src/main/scala/app/softnetwork/payment/model/PaymentUserCompanion.scala b/client/src/main/scala/app/softnetwork/payment/model/PaymentUserCompanion.scala similarity index 100% rename from common/src/main/scala/app/softnetwork/payment/model/PaymentUserCompanion.scala rename to client/src/main/scala/app/softnetwork/payment/model/PaymentUserCompanion.scala diff --git a/common/src/main/scala/app/softnetwork/payment/model/PaymentUserDecorator.scala b/client/src/main/scala/app/softnetwork/payment/model/PaymentUserDecorator.scala similarity index 89% rename from common/src/main/scala/app/softnetwork/payment/model/PaymentUserDecorator.scala rename to client/src/main/scala/app/softnetwork/payment/model/PaymentUserDecorator.scala index 392c373..237c11b 100644 --- a/common/src/main/scala/app/softnetwork/payment/model/PaymentUserDecorator.scala +++ b/client/src/main/scala/app/softnetwork/payment/model/PaymentUserDecorator.scala @@ -1,9 +1,11 @@ package app.softnetwork.payment.model +import app.softnetwork.payment.model + trait PaymentUserDecorator { self: PaymentUser => lazy val externalUuidWithProfile: String = computeExternalUuidWithProfile(externalUuid, profile) - lazy val view: PaymentUserView = PaymentUserView(self) + lazy val view: PaymentUserView = model.PaymentUserView(self) } case class PaymentUserView( diff --git a/common/src/main/scala/app/softnetwork/payment/model/RecurringPaymentDecorator.scala b/client/src/main/scala/app/softnetwork/payment/model/RecurringPaymentDecorator.scala similarity index 100% rename from common/src/main/scala/app/softnetwork/payment/model/RecurringPaymentDecorator.scala rename to client/src/main/scala/app/softnetwork/payment/model/RecurringPaymentDecorator.scala diff --git a/common/src/main/scala/app/softnetwork/payment/model/RefundAction.scala b/client/src/main/scala/app/softnetwork/payment/model/RefundAction.scala similarity index 100% rename from common/src/main/scala/app/softnetwork/payment/model/RefundAction.scala rename to client/src/main/scala/app/softnetwork/payment/model/RefundAction.scala diff --git a/common/src/main/scala/app/softnetwork/payment/model/TransactionCompanion.scala b/client/src/main/scala/app/softnetwork/payment/model/TransactionCompanion.scala similarity index 100% rename from common/src/main/scala/app/softnetwork/payment/model/TransactionCompanion.scala rename to client/src/main/scala/app/softnetwork/payment/model/TransactionCompanion.scala diff --git a/common/src/main/scala/app/softnetwork/payment/model/TransactionDecorator.scala b/client/src/main/scala/app/softnetwork/payment/model/TransactionDecorator.scala similarity index 100% rename from common/src/main/scala/app/softnetwork/payment/model/TransactionDecorator.scala rename to client/src/main/scala/app/softnetwork/payment/model/TransactionDecorator.scala diff --git a/common/src/main/scala/app/softnetwork/payment/model/UboDeclarationDecorator.scala b/client/src/main/scala/app/softnetwork/payment/model/UboDeclarationDecorator.scala similarity index 100% rename from common/src/main/scala/app/softnetwork/payment/model/UboDeclarationDecorator.scala rename to client/src/main/scala/app/softnetwork/payment/model/UboDeclarationDecorator.scala diff --git a/common/src/main/scala/app/softnetwork/payment/model/UltimateBeneficialOwnerDecorator.scala b/client/src/main/scala/app/softnetwork/payment/model/UltimateBeneficialOwnerDecorator.scala similarity index 100% rename from common/src/main/scala/app/softnetwork/payment/model/UltimateBeneficialOwnerDecorator.scala rename to client/src/main/scala/app/softnetwork/payment/model/UltimateBeneficialOwnerDecorator.scala diff --git a/common/src/main/scala/app/softnetwork/payment/model/package.scala b/client/src/main/scala/app/softnetwork/payment/model/package.scala similarity index 100% rename from common/src/main/scala/app/softnetwork/payment/model/package.scala rename to client/src/main/scala/app/softnetwork/payment/model/package.scala diff --git a/common/build.sbt b/common/build.sbt index 9a0d86c..87d6196 100644 --- a/common/build.sbt +++ b/common/build.sbt @@ -2,17 +2,10 @@ organization := "app.softnetwork.payment" name := "payment-common" +akkaGrpcGeneratedSources := Seq(AkkaGrpc.Client) + libraryDependencies ++= Seq( - "app.softnetwork.persistence" %% "persistence-kv" % Versions.genericPersistence, - // scheduler - "app.softnetwork.scheduler" %% "scheduler-common" % Versions.scheduler, - "app.softnetwork.scheduler" %% "scheduler-common" % Versions.scheduler % "protobuf", - // account - "app.softnetwork.account" %% "account-common" % Versions.account, - "app.softnetwork.account" %% "account-common" % Versions.account % "protobuf", - "app.softnetwork.api" %% "generic-server-api" % Versions.genericPersistence, - "app.softnetwork.protobuf" %% "scalapb-extensions" % "0.1.7", - "commons-validator" % "commons-validator" % "1.6" + "app.softnetwork.persistence" %% "persistence-kv" % Versions.genericPersistence ) Compile / unmanagedResourceDirectories += baseDirectory.value / "src/main/protobuf" diff --git a/common/src/main/resources/reference.conf b/common/src/main/resources/reference.conf index d21c707..f96dd66 100644 --- a/common/src/main/resources/reference.conf +++ b/common/src/main/resources/reference.conf @@ -10,19 +10,6 @@ softnetwork { } } -akka.http.session { - encrypt-data = true - - jws { - alg = "HS256" - } - - jwt { - iss = "softpayment" - include-iat = true - } -} - payment{ baseUrl = "http://localhost:"${softnetwork.api.server.port}"/"${softnetwork.api.server.root-path} baseUrl = ${?PAYMENT_BASE_URL} @@ -51,11 +38,6 @@ payment{ external-to-payment-account-tag = "external-to-payment-account" } - client-id = "" - client-id = ${?PAYMENT_CLIENT_ID} - - api-key = "" - api-key = ${?PAYMENT_API_KEY} } auth { diff --git a/common/src/main/scala/app/softnetwork/payment/serialization/package.scala b/common/src/main/scala/app/softnetwork/payment/serialization/package.scala index 82f9bc5..9de45f3 100644 --- a/common/src/main/scala/app/softnetwork/payment/serialization/package.scala +++ b/common/src/main/scala/app/softnetwork/payment/serialization/package.scala @@ -67,26 +67,6 @@ package object serialization { } } - implicit def LegalUserTypeToLegalResponseUserType( - legalUserType: LegalUser.LegalUserType - ): LegalUserType = { - legalUserType match { - case LegalUser.LegalUserType.BUSINESS => LegalUserType.BUSINESS - case LegalUser.LegalUserType.SOLETRADER => LegalUserType.SOLETRADER - case LegalUser.LegalUserType.ORGANIZATION => LegalUserType.ORGANIZATION - } - } - - implicit def LegalResponseUserTypeToLegalUserType( - legalUserType: LegalUserType - ): LegalUser.LegalUserType = { - legalUserType match { - case LegalUserType.BUSINESS => LegalUser.LegalUserType.BUSINESS - case LegalUserType.SOLETRADER => LegalUser.LegalUserType.SOLETRADER - case LegalUserType.ORGANIZATION => LegalUser.LegalUserType.ORGANIZATION - } - } - implicit def accountToSoftPaymentAccount(account: Account): SoftPaymentAccount = { account match { case a: SoftPaymentAccount => a diff --git a/core/build.sbt b/core/build.sbt index fa07d77..8877f62 100644 --- a/core/build.sbt +++ b/core/build.sbt @@ -2,6 +2,10 @@ organization := "app.softnetwork.payment" name := "payment-core" +akkaGrpcGeneratedSources := Seq(AkkaGrpc.Server) + +Compile / PB.protoSources := Seq(sourceDirectory.value / ".." / ".." / "client/src/main/protobuf/api") + libraryDependencies ++= Seq( "app.softnetwork.persistence" %% "persistence-kv" % Versions.genericPersistence, "app.softnetwork.account" %% "account-core" % Versions.account, diff --git a/core/src/main/scala/app/softnetwork/payment/api/PaymentServer.scala b/core/src/main/scala/app/softnetwork/payment/api/PaymentServer.scala index 2c94252..4b46a25 100644 --- a/core/src/main/scala/app/softnetwork/payment/api/PaymentServer.scala +++ b/core/src/main/scala/app/softnetwork/payment/api/PaymentServer.scala @@ -1,6 +1,7 @@ package app.softnetwork.payment.api import akka.actor.typed.ActorSystem +import app.softnetwork.payment.api.serialization._ import app.softnetwork.payment.handlers.{PaymentHandler, SoftPaymentAccountDao} import app.softnetwork.payment.message.PaymentMessages.{ BankAccountLoaded, diff --git a/core/src/main/scala/app/softnetwork/payment/persistence/typed/PaymentBehavior.scala b/core/src/main/scala/app/softnetwork/payment/persistence/typed/PaymentBehavior.scala index a4ea686..97478d1 100644 --- a/core/src/main/scala/app/softnetwork/payment/persistence/typed/PaymentBehavior.scala +++ b/core/src/main/scala/app/softnetwork/payment/persistence/typed/PaymentBehavior.scala @@ -6,7 +6,7 @@ import akka.cluster.sharding.typed.ShardingEnvelope import akka.persistence.typed.scaladsl.Effect import app.softnetwork.kv.handlers.GenericKeyValueDao import app.softnetwork.payment.annotation.InternalApi -import app.softnetwork.payment.api.PaymentClientSettings +import app.softnetwork.payment.api.config.PaymentClientSettings import app.softnetwork.payment.config.PaymentSettings import app.softnetwork.payment.config.PaymentSettings.{AkkaNodeRole, PayInStatementDescriptor} import app.softnetwork.payment.handlers.{PaymentDao, PaymentKvDao, SoftPaymentAccountDao} diff --git a/testkit/src/main/scala/app/softnetwork/payment/api/PaymentClientTestKit.scala b/testkit/src/main/scala/app/softnetwork/payment/api/PaymentClientTestKit.scala index 50d9525..1d2678e 100644 --- a/testkit/src/main/scala/app/softnetwork/payment/api/PaymentClientTestKit.scala +++ b/testkit/src/main/scala/app/softnetwork/payment/api/PaymentClientTestKit.scala @@ -1,5 +1,6 @@ package app.softnetwork.payment.api +import app.softnetwork.payment.api.config.PaymentClientSettings import app.softnetwork.payment.config.MangoPay import app.softnetwork.payment.model.SoftPaymentAccount import app.softnetwork.security.sha256 From 7de287134ddd1cabd9e3c66bc931c7ab3094b69d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Manciot?= Date: Wed, 6 Dec 2023 23:38:19 +0100 Subject: [PATCH 14/37] add module client --- client/build.sbt | 15 ++- client/src/main/protobuf/api/client.proto | 41 ++++++++ client/src/main/protobuf/api/payment.proto | 27 ------ client/src/main/resources/reference.conf | 13 +++ .../app/softnetwork/payment/api/Client.scala | 59 ++++++++++++ .../payment/api/PaymentClient.scala | 31 ------- .../app/softnetwork/payment/cli/Command.scala | 12 +++ .../payment/cli/CommandConfig.scala | 15 +++ .../app/softnetwork/payment/cli/Main.scala | 93 +++++++++++++++++++ .../payment/cli/tokens/Tokens.scala | 39 ++++++++ .../payment/cli/tokens/TokensConfig.scala | 31 +++++++ .../payment/api/ClientGrpcService.scala | 14 +++ .../payment/api/ClientServer.scala | 62 +++++++++++++ .../payment/api/PaymentServer.scala | 39 +------- .../payment/launch/PaymentGuardian.scala | 12 ++- project/Versions.scala | 6 ++ .../payment/api/MockClientServer.scala | 22 +++++ .../payment/api/MockPaymentServer.scala | 4 +- .../payment/scalatest/PaymentTestKit.scala | 10 +- 19 files changed, 442 insertions(+), 103 deletions(-) create mode 100644 client/src/main/protobuf/api/client.proto create mode 100644 client/src/main/scala/app/softnetwork/payment/api/Client.scala create mode 100644 client/src/main/scala/app/softnetwork/payment/cli/Command.scala create mode 100644 client/src/main/scala/app/softnetwork/payment/cli/CommandConfig.scala create mode 100644 client/src/main/scala/app/softnetwork/payment/cli/Main.scala create mode 100644 client/src/main/scala/app/softnetwork/payment/cli/tokens/Tokens.scala create mode 100644 client/src/main/scala/app/softnetwork/payment/cli/tokens/TokensConfig.scala create mode 100644 core/src/main/scala/app/softnetwork/payment/api/ClientGrpcService.scala create mode 100644 core/src/main/scala/app/softnetwork/payment/api/ClientServer.scala create mode 100644 testkit/src/main/scala/app/softnetwork/payment/api/MockClientServer.scala diff --git a/client/build.sbt b/client/build.sbt index a32ed63..1b75fab 100644 --- a/client/build.sbt +++ b/client/build.sbt @@ -4,10 +4,21 @@ name := "payment-client" akkaGrpcGeneratedSources := Seq(AkkaGrpc.Client) +val jacksonExclusions = Seq( + ExclusionRule(organization = "com.fasterxml.jackson.core"), + ExclusionRule(organization = "com.fasterxml.jackson.databind"), + ExclusionRule(organization = "com.fasterxml.jackson.jaxrs"), + ExclusionRule(organization = "com.fasterxml.jackson.module"), + ExclusionRule(organization = "com.fasterxml.jackson.dataformat", "jackson-dataformat-yaml") +) + libraryDependencies ++= Seq( "app.softnetwork.account" %% "account-common" % Versions.account, "app.softnetwork.account" %% "account-common" % Versions.account % "protobuf", "app.softnetwork.api" %% "generic-server-api" % Versions.genericPersistence, "app.softnetwork.protobuf" %% "scalapb-extensions" % "0.1.7", - "commons-validator" % "commons-validator" % "1.6" -) \ No newline at end of file + "commons-validator" % "commons-validator" % "1.6", + "com.github.scopt" %% "scopt" % Versions.scopt, + "org.scalatra.scalate" %% "scalate-core" % Versions.scalate exclude ("org.scala-lang.modules", "scala-xml_2.12") exclude ("org.scala-lang.modules", "scala-parser-combinators_2.12"), + "com.hubspot.jinjava" % "jinjava" % Versions.jinja excludeAll (jacksonExclusions *) exclude ("com.google.guava", "guava") exclude ("org.apache.commons", "commons-lang3") +) diff --git a/client/src/main/protobuf/api/client.proto b/client/src/main/protobuf/api/client.proto new file mode 100644 index 0000000..26ef8c2 --- /dev/null +++ b/client/src/main/protobuf/api/client.proto @@ -0,0 +1,41 @@ +syntax = "proto3"; + +import "scalapb/scalapb.proto"; +import "google/protobuf/wrappers.proto"; + +package app.softnetwork.payment.api; + +option (scalapb.options) = { + import: "app.softnetwork.protobuf.ScalaPBTypeMappers._" + preserve_unknown_fields: false +}; + +service ClientServiceApi { + rpc GenerateClientTokens (GenerateClientTokensRequest) returns (ClientTokensResponse) {} + rpc RefreshClientTokens (RefreshClientTokensRequest) returns (ClientTokensResponse) {} +} + +message Tokens { + string access_token = 1; + string token_type = 2; + int64 expires_in = 3; + string refresh_token = 4; + // google.protobuf.StringValue scope = 5; +} + +message ClientTokensResponse { + oneof clientTokens { + Tokens tokens = 1; + string error = 2; + } +} + +message GenerateClientTokensRequest { + string client_id = 1; + string client_secret = 2; + google.protobuf.StringValue scope = 3; +} + +message RefreshClientTokensRequest { + string refresh_token = 1; +} diff --git a/client/src/main/protobuf/api/payment.proto b/client/src/main/protobuf/api/payment.proto index c6704ed..c065d2f 100644 --- a/client/src/main/protobuf/api/payment.proto +++ b/client/src/main/protobuf/api/payment.proto @@ -26,8 +26,6 @@ service PaymentServiceApi { rpc CancelMandate (CancelMandateRequest) returns (CancelMandateResponse) {} rpc LoadBankAccountOwner (LoadBankAccountOwnerRequest) returns (LoadBankAccountOwnerResponse) {} rpc LoadLegalUser(LoadLegalUserRequest) returns (LoadLegalUserResponse) {} - rpc GenerateClientTokens (GenerateClientTokensRequest) returns (ClientTokensResponse) {} - rpc RefreshClientTokens (RefreshClientTokensRequest) returns (ClientTokensResponse) {} } message CreateOrUpdatePaymentAccountRequest { @@ -184,28 +182,3 @@ message LoadLegalUserResponse { app.softnetwork.payment.model.Address legalRepresentativeAddress = 4; app.softnetwork.payment.model.Address headQuartersAddress = 5; } - -message Tokens { - string access_token = 1; - string token_type = 2; - int64 expires_in = 3; - string refresh_token = 4; -// google.protobuf.StringValue scope = 5; -} - -message ClientTokensResponse { - oneof clientTokens { - Tokens tokens = 1; - string error = 2; - } -} - -message GenerateClientTokensRequest { - string client_id = 1; - string client_secret = 2; - google.protobuf.StringValue scope = 3; -} - -message RefreshClientTokensRequest { - string refresh_token = 1; -} diff --git a/client/src/main/resources/reference.conf b/client/src/main/resources/reference.conf index c0f2fb4..16e3759 100644 --- a/client/src/main/resources/reference.conf +++ b/client/src/main/resources/reference.conf @@ -19,3 +19,16 @@ payment{ api-key = ${?PAYMENT_API_KEY} } +akka.http.server.preview.enable-http2 = on + +akka.grpc.client.PaymentService { + host = localhost + port = 9000 + use-tls = false +} + +akka.grpc.client.ClientService { + host = localhost + port = 9000 + use-tls = false +} diff --git a/client/src/main/scala/app/softnetwork/payment/api/Client.scala b/client/src/main/scala/app/softnetwork/payment/api/Client.scala new file mode 100644 index 0000000..cdb4a6e --- /dev/null +++ b/client/src/main/scala/app/softnetwork/payment/api/Client.scala @@ -0,0 +1,59 @@ +package app.softnetwork.payment.api + +import akka.actor.typed.ActorSystem +import akka.grpc.GrpcClientSettings +import app.softnetwork.api.server.client.{GrpcClient, GrpcClientFactory} +import app.softnetwork.payment.api.config.PaymentClientSettings + +import scala.concurrent.Future + +trait Client extends GrpcClient { + + implicit lazy val grpcClient: ClientServiceApiClient = + ClientServiceApiClient( + GrpcClientSettings.fromConfig(name) + ) + + lazy val settings: PaymentClientSettings = PaymentClientSettings(system) + + def generateClientTokens( + scope: Option[String] = None + ): Future[Option[Tokens]] = { + import settings._ + grpcClient + .generateClientTokens() + .invoke( + GenerateClientTokensRequest(clientId, apiKey, scope) + ) map (response => + response.clientTokens match { + case r: ClientTokensResponse.ClientTokens.Tokens => + r.tokens + case _ => None + } + ) + } + + def refreshClientTokens(refreshToken: String): Future[Option[Tokens]] = { + grpcClient + .refreshClientTokens() + .invoke( + RefreshClientTokensRequest(refreshToken) + ) map (response => + response.clientTokens match { + case r: ClientTokensResponse.ClientTokens.Tokens => + r.tokens + case _ => None + } + ) + } +} + +object Client extends GrpcClientFactory[Client] { + override val name: String = "ClientService" + override def init(sys: ActorSystem[_]): Client = { + new Client { + override implicit lazy val system: ActorSystem[_] = sys + val name: String = Client.name + } + } +} diff --git a/client/src/main/scala/app/softnetwork/payment/api/PaymentClient.scala b/client/src/main/scala/app/softnetwork/payment/api/PaymentClient.scala index 975328a..0343257 100644 --- a/client/src/main/scala/app/softnetwork/payment/api/PaymentClient.scala +++ b/client/src/main/scala/app/softnetwork/payment/api/PaymentClient.scala @@ -273,37 +273,6 @@ trait PaymentClient extends GrpcClient { ) } - def generateClientTokens( - clientId: String, - clientSecret: String, - scope: Option[String] = None - ): Future[Option[Tokens]] = { - grpcClient - .generateClientTokens() - .invoke( - GenerateClientTokensRequest(clientId, clientSecret, scope) - ) map (response => - response.clientTokens match { - case r: ClientTokensResponse.ClientTokens.Tokens => - r.tokens - case _ => None - } - ) - } - - def refreshClientTokens(refreshToken: String): Future[Option[Tokens]] = { - grpcClient - .refreshClientTokens() - .invoke( - RefreshClientTokensRequest(refreshToken) - ) map (response => - response.clientTokens match { - case r: ClientTokensResponse.ClientTokens.Tokens => - r.tokens - case _ => None - } - ) - } } object PaymentClient extends GrpcClientFactory[PaymentClient] { diff --git a/client/src/main/scala/app/softnetwork/payment/cli/Command.scala b/client/src/main/scala/app/softnetwork/payment/cli/Command.scala new file mode 100644 index 0000000..a67c1d6 --- /dev/null +++ b/client/src/main/scala/app/softnetwork/payment/cli/Command.scala @@ -0,0 +1,12 @@ +package app.softnetwork.payment.cli + +import akka.actor.typed.ActorSystem +import app.softnetwork.payment.api.PaymentClient + +import scala.concurrent.{ExecutionContext, Future} + +trait Command[T] { + + def run(config: T)(implicit system: ActorSystem[_]): Future[String] + +} diff --git a/client/src/main/scala/app/softnetwork/payment/cli/CommandConfig.scala b/client/src/main/scala/app/softnetwork/payment/cli/CommandConfig.scala new file mode 100644 index 0000000..e5fb438 --- /dev/null +++ b/client/src/main/scala/app/softnetwork/payment/cli/CommandConfig.scala @@ -0,0 +1,15 @@ +package app.softnetwork.payment.cli + +import scopt.OParser + +trait CommandConfig { + def command: String +} + +trait CliConfig[T] extends CommandConfig { + def parser: OParser[Unit, T] + + def usage(): String = OParser.usage(parser) + + def parse(args: Seq[String]): Option[T] +} diff --git a/client/src/main/scala/app/softnetwork/payment/cli/Main.scala b/client/src/main/scala/app/softnetwork/payment/cli/Main.scala new file mode 100644 index 0000000..65fc0cd --- /dev/null +++ b/client/src/main/scala/app/softnetwork/payment/cli/Main.scala @@ -0,0 +1,93 @@ +package app.softnetwork.payment.cli + +import akka.actor.typed.ActorSystem +import akka.actor.typed.scaladsl.Behaviors +import app.softnetwork.payment.PaymentClientBuildInfo +import app.softnetwork.payment.cli.tokens.{Tokens, TokensConfig} +import com.typesafe.scalalogging.StrictLogging + +import scala.concurrent.ExecutionContext + +object Main extends StrictLogging { + + def main(args: Array[String]): Unit = { + implicit def system: ActorSystem[_] = ActorSystem(Behaviors.empty, "PaymentClient") + new Main().run(args) + } +} + +class Main() extends StrictLogging { + val configs: List[CliConfig[_]] = List( + TokensConfig + ) + + private def printUsage(): Unit = { + // scalastyle:off println + println(s"Payment Version ${PaymentClientBuildInfo.version}") + println("Usage:") + println("\tpayment [command]") + println("Available commands =>") + configs.foreach { config => + println(s"\t${config.command}") + } + } + + private def printUsage(command: String): Unit = { + // scalastyle:off println + configs.find(_.command == command) match { + case None => + println(s"ERROR: Unknown command --> $command") + case Some(config) => + println(config.usage()) + } + } + // scalastyle:on println + + def help(args: List[String]): Unit = { + args match { + case Nil | "help" :: Nil => + printUsage() + System.exit(0) + case "help" :: command :: any => + printUsage(command) + System.exit(0) + case _ => + } + } + + def run(args: Array[String])(implicit system: ActorSystem[_]): Unit = { + help(args.toList) + args.toList match { + case command :: any => + configs.find(_.command == command) match { + case None => + println(s"ERROR: Unknown command --> $command") + printUsage() + System.exit(1) + case Some(config) => + command match { + case "tokens" => + TokensConfig.parse(any) match { + case None => + println(s"ERROR: Invalid arguments for command --> $command") + printUsage(command) + System.exit(1) + case Some(conf) => + implicit def ec: ExecutionContext = system.executionContext + Tokens.run(conf) onComplete { result => + println(result) + System.exit(0) + } + } + case _ => + println(s"ERROR: Unknown command --> $command") + printUsage() + System.exit(1) + } + } + case _ => + printUsage() + System.exit(1) + } + } +} diff --git a/client/src/main/scala/app/softnetwork/payment/cli/tokens/Tokens.scala b/client/src/main/scala/app/softnetwork/payment/cli/tokens/Tokens.scala new file mode 100644 index 0000000..3bcffe6 --- /dev/null +++ b/client/src/main/scala/app/softnetwork/payment/cli/tokens/Tokens.scala @@ -0,0 +1,39 @@ +package app.softnetwork.payment.cli.tokens + +import akka.actor.typed.ActorSystem +import app.softnetwork.payment.api.Client +import app.softnetwork.payment.cli.Command +import com.typesafe.scalalogging.StrictLogging + +import scala.concurrent.{ExecutionContext, Future} + +object Tokens extends Command[TokensConfig] with StrictLogging { + def run( + config: TokensConfig + )(implicit system: ActorSystem[_]): Future[String] = { + implicit val ec: ExecutionContext = system.executionContext + val client = Client(system) + config.refreshToken match { + case Some(refreshToken) => + client.refreshClientTokens(refreshToken) map { + case Some(tokens) => + s""" + |Tokens refreshed successfully! + |${tokens.toString} + |""".stripMargin + case _ => + s""" + |Tokens refresh failed! + |""".stripMargin + } + case None => + client.generateClientTokens() map { + case Some(tokens) => + s"Tokens generated successfully! ${tokens.toString}" + case _ => + "Tokens generation failed!" + } + } + } + +} diff --git a/client/src/main/scala/app/softnetwork/payment/cli/tokens/TokensConfig.scala b/client/src/main/scala/app/softnetwork/payment/cli/tokens/TokensConfig.scala new file mode 100644 index 0000000..118e09b --- /dev/null +++ b/client/src/main/scala/app/softnetwork/payment/cli/tokens/TokensConfig.scala @@ -0,0 +1,31 @@ +package app.softnetwork.payment.cli.tokens + +import app.softnetwork.payment.cli.{CliConfig, Command} +import scopt.OParser + +case class TokensConfig( + refreshToken: Option[String] = None +) + +object TokensConfig extends CliConfig[TokensConfig] { + + val command: String = "tokens" + + val parser: OParser[Unit, TokensConfig] = { + val builder = OParser.builder[TokensConfig] + import builder._ + OParser.sequence( + programName(s"payment $command"), + head("payment", command, "[options]"), + opt[String]('r', "refreshToken") + .action((x, c) => c.copy(refreshToken = Some(x))) + .text("refresh token") + ) + } + + def parse(args: Seq[String]): Option[TokensConfig] = { + OParser.parse(parser, args, TokensConfig()) + } + + def runner: Command[TokensConfig] = Tokens +} diff --git a/core/src/main/scala/app/softnetwork/payment/api/ClientGrpcService.scala b/core/src/main/scala/app/softnetwork/payment/api/ClientGrpcService.scala new file mode 100644 index 0000000..24b2f2d --- /dev/null +++ b/core/src/main/scala/app/softnetwork/payment/api/ClientGrpcService.scala @@ -0,0 +1,14 @@ +package app.softnetwork.payment.api + +import akka.actor.typed.ActorSystem +import akka.http.scaladsl.model.{HttpRequest, HttpResponse} +import app.softnetwork.api.server.GrpcService + +import scala.concurrent.Future + +class ClientGrpcService(server: ClientServer) extends GrpcService { + + override def grpcService: ActorSystem[_] => PartialFunction[HttpRequest, Future[HttpResponse]] = + system => ClientServiceApiHandler.partial(server)(system) + +} diff --git a/core/src/main/scala/app/softnetwork/payment/api/ClientServer.scala b/core/src/main/scala/app/softnetwork/payment/api/ClientServer.scala new file mode 100644 index 0000000..9690c76 --- /dev/null +++ b/core/src/main/scala/app/softnetwork/payment/api/ClientServer.scala @@ -0,0 +1,62 @@ +package app.softnetwork.payment.api + +import akka.actor.typed.ActorSystem +import app.softnetwork.payment.handlers.{PaymentHandler, SoftPaymentAccountDao} +import org.slf4j.{Logger, LoggerFactory} + +import scala.concurrent.{ExecutionContextExecutor, Future} + +trait ClientServer extends ClientServiceApi with PaymentHandler { + + implicit def system: ActorSystem[_] + + implicit lazy val ec: ExecutionContextExecutor = system.executionContext + + def softPaymentAccountDao: SoftPaymentAccountDao = SoftPaymentAccountDao + + override def generateClientTokens( + in: GenerateClientTokensRequest + ): Future[ClientTokensResponse] = { + import in._ + softPaymentAccountDao.generateClientToken(clientId, clientSecret, scope) map { + case Some(tokens) => + import tokens._ + ClientTokensResponse.defaultInstance.withTokens( + Tokens( + access_token, + token_type, + expires_in, + refresh_token + ) + ) + case _ => ClientTokensResponse.defaultInstance.withError("unknown") + } + } + + override def refreshClientTokens(in: RefreshClientTokensRequest): Future[ClientTokensResponse] = { + import in._ + softPaymentAccountDao.refreshClientToken(refreshToken) map { + case Some(tokens) => + import tokens._ + ClientTokensResponse.defaultInstance.withTokens( + Tokens( + access_token, + token_type, + expires_in, + refresh_token + ) + ) + case _ => ClientTokensResponse.defaultInstance.withError("unknown") + } + } +} + +object ClientServer { + + def apply(sys: ActorSystem[_]): ClientServer = { + new ClientServer { + lazy val log: Logger = LoggerFactory getLogger getClass.getName + override implicit val system: ActorSystem[_] = sys + } + } +} diff --git a/core/src/main/scala/app/softnetwork/payment/api/PaymentServer.scala b/core/src/main/scala/app/softnetwork/payment/api/PaymentServer.scala index 4b46a25..762a167 100644 --- a/core/src/main/scala/app/softnetwork/payment/api/PaymentServer.scala +++ b/core/src/main/scala/app/softnetwork/payment/api/PaymentServer.scala @@ -2,7 +2,7 @@ package app.softnetwork.payment.api import akka.actor.typed.ActorSystem import app.softnetwork.payment.api.serialization._ -import app.softnetwork.payment.handlers.{PaymentHandler, SoftPaymentAccountDao} +import app.softnetwork.payment.handlers.PaymentHandler import app.softnetwork.payment.message.PaymentMessages.{ BankAccountLoaded, CancelMandate, @@ -346,43 +346,6 @@ trait PaymentServer extends PaymentServiceApi with PaymentHandler { } } - def softPaymentAccountDao: SoftPaymentAccountDao = SoftPaymentAccountDao - - override def generateClientTokens( - in: GenerateClientTokensRequest - ): Future[ClientTokensResponse] = { - import in._ - softPaymentAccountDao.generateClientToken(clientId, clientSecret, scope) map { - case Some(tokens) => - import tokens._ - ClientTokensResponse.defaultInstance.withTokens( - Tokens( - access_token, - token_type, - expires_in, - refresh_token - ) - ) - case _ => ClientTokensResponse.defaultInstance.withError("unknown") - } - } - - override def refreshClientTokens(in: RefreshClientTokensRequest): Future[ClientTokensResponse] = { - import in._ - softPaymentAccountDao.refreshClientToken(refreshToken) map { - case Some(tokens) => - import tokens._ - ClientTokensResponse.defaultInstance.withTokens( - Tokens( - access_token, - token_type, - expires_in, - refresh_token - ) - ) - case _ => ClientTokensResponse.defaultInstance.withError("unknown") - } - } } object PaymentServer { diff --git a/core/src/main/scala/app/softnetwork/payment/launch/PaymentGuardian.scala b/core/src/main/scala/app/softnetwork/payment/launch/PaymentGuardian.scala index 33384f4..b247a0c 100644 --- a/core/src/main/scala/app/softnetwork/payment/launch/PaymentGuardian.scala +++ b/core/src/main/scala/app/softnetwork/payment/launch/PaymentGuardian.scala @@ -7,7 +7,12 @@ import app.softnetwork.account.model.BasicAccountProfile import app.softnetwork.account.persistence.typed.AccountBehavior import app.softnetwork.api.server.GrpcService import app.softnetwork.payment.PaymentCoreBuildInfo -import app.softnetwork.payment.api.{PaymentGrpcService, PaymentServer} +import app.softnetwork.payment.api.{ + ClientGrpcService, + ClientServer, + PaymentGrpcService, + PaymentServer +} import app.softnetwork.payment.handlers.SoftPaymentAccountDao import app.softnetwork.payment.model.SoftPaymentAccount import app.softnetwork.payment.persistence.data.paymentKvDao @@ -71,9 +76,12 @@ trait PaymentGuardian extends AccountGuardian[SoftPaymentAccount, BasicAccountPr def paymentServer: ActorSystem[_] => PaymentServer = system => PaymentServer(system) + def clientServer: ActorSystem[_] => ClientServer = system => ClientServer(system) + def paymentGrpcServices: ActorSystem[_] => Seq[GrpcService] = system => Seq( - new PaymentGrpcService(paymentServer(system), softPaymentAccountDao) + new PaymentGrpcService(paymentServer(system), softPaymentAccountDao), + new ClientGrpcService(clientServer(system)) ) def registerProvidersAccount: ActorSystem[_] => Unit = system => { diff --git a/project/Versions.scala b/project/Versions.scala index 4d56869..be6c935 100644 --- a/project/Versions.scala +++ b/project/Versions.scala @@ -9,4 +9,10 @@ object Versions { val account = "0.6.2" val scalatest = "3.2.16" + + val scopt = "4.0.1" + + val jinja = "2.7.1" + + val scalate = "1.9.8" } diff --git a/testkit/src/main/scala/app/softnetwork/payment/api/MockClientServer.scala b/testkit/src/main/scala/app/softnetwork/payment/api/MockClientServer.scala new file mode 100644 index 0000000..2680594 --- /dev/null +++ b/testkit/src/main/scala/app/softnetwork/payment/api/MockClientServer.scala @@ -0,0 +1,22 @@ +package app.softnetwork.payment.api + +import akka.actor.typed.ActorSystem +import app.softnetwork.payment.handlers.{ + MockPaymentHandler, + MockPaymentTypeKey, + MockSoftPaymentAccountDao, + SoftPaymentAccountDao +} +import org.slf4j.{Logger, LoggerFactory} + +trait MockClientServer extends ClientServer with MockPaymentHandler + +object MockClientServer { + def apply(sys: ActorSystem[_]): MockClientServer = { + new MockClientServer { + override def softPaymentAccountDao: SoftPaymentAccountDao = MockSoftPaymentAccountDao + lazy val log: Logger = LoggerFactory getLogger getClass.getName + override implicit val system: ActorSystem[_] = sys + } + } +} diff --git a/testkit/src/main/scala/app/softnetwork/payment/api/MockPaymentServer.scala b/testkit/src/main/scala/app/softnetwork/payment/api/MockPaymentServer.scala index 0bd9a16..152b69d 100644 --- a/testkit/src/main/scala/app/softnetwork/payment/api/MockPaymentServer.scala +++ b/testkit/src/main/scala/app/softnetwork/payment/api/MockPaymentServer.scala @@ -2,18 +2,18 @@ package app.softnetwork.payment.api import akka.actor.typed.ActorSystem import app.softnetwork.payment.handlers.{ + MockPaymentHandler, MockPaymentTypeKey, MockSoftPaymentAccountDao, SoftPaymentAccountDao } import org.slf4j.{Logger, LoggerFactory} -trait MockPaymentServer extends PaymentServer with MockPaymentTypeKey +trait MockPaymentServer extends PaymentServer with MockPaymentHandler object MockPaymentServer { def apply(sys: ActorSystem[_]): MockPaymentServer = { new MockPaymentServer { - override def softPaymentAccountDao: SoftPaymentAccountDao = MockSoftPaymentAccountDao lazy val log: Logger = LoggerFactory getLogger getClass.getName override implicit val system: ActorSystem[_] = sys } diff --git a/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentTestKit.scala b/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentTestKit.scala index feb90d5..d01c01b 100644 --- a/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentTestKit.scala +++ b/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentTestKit.scala @@ -6,7 +6,13 @@ import app.softnetwork.account.model.BasicAccountProfile import app.softnetwork.account.persistence.query.AccountEventProcessorStreams.InternalAccountEvents2AccountProcessorStream import app.softnetwork.account.persistence.typed.AccountBehavior import app.softnetwork.notification.scalatest.AllNotificationsTestKit -import app.softnetwork.payment.api.{MockPaymentServer, PaymentClientTestKit, PaymentServer} +import app.softnetwork.payment.api.{ + ClientServer, + MockClientServer, + MockPaymentServer, + PaymentClientTestKit, + PaymentServer +} import app.softnetwork.payment.config.PaymentSettings._ import app.softnetwork.payment.handlers.{ MockPaymentHandler, @@ -61,6 +67,8 @@ trait PaymentTestKit override def paymentServer: ActorSystem[_] => PaymentServer = system => MockPaymentServer(system) + override def clientServer: ActorSystem[_] => ClientServer = system => MockClientServer(system) + def loadApiKey(clientId: String): Future[Option[ApiKey]] = MockPaymentBehavior.softPaymentAccountDao.loadApiKey(clientId) From aa052ea1d43dad682d1c19dc2c61c7c82a22f8b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Manciot?= Date: Wed, 6 Dec 2023 23:46:59 +0100 Subject: [PATCH 15/37] update main client --- .../app/softnetwork/payment/cli/Main.scala | 26 +++++++++++-------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/client/src/main/scala/app/softnetwork/payment/cli/Main.scala b/client/src/main/scala/app/softnetwork/payment/cli/Main.scala index 65fc0cd..a72957b 100644 --- a/client/src/main/scala/app/softnetwork/payment/cli/Main.scala +++ b/client/src/main/scala/app/softnetwork/payment/cli/Main.scala @@ -2,11 +2,12 @@ package app.softnetwork.payment.cli import akka.actor.typed.ActorSystem import akka.actor.typed.scaladsl.Behaviors +import app.softnetwork.concurrent.Completion import app.softnetwork.payment.PaymentClientBuildInfo import app.softnetwork.payment.cli.tokens.{Tokens, TokensConfig} import com.typesafe.scalalogging.StrictLogging -import scala.concurrent.ExecutionContext +import scala.util.{Failure, Success} object Main extends StrictLogging { @@ -16,7 +17,7 @@ object Main extends StrictLogging { } } -class Main() extends StrictLogging { +class Main extends Completion with StrictLogging { val configs: List[CliConfig[_]] = List( TokensConfig ) @@ -43,12 +44,12 @@ class Main() extends StrictLogging { } // scalastyle:on println - def help(args: List[String]): Unit = { + private def help(args: List[String]): Unit = { args match { case Nil | "help" :: Nil => printUsage() System.exit(0) - case "help" :: command :: any => + case "help" :: command :: _ => printUsage(command) System.exit(0) case _ => @@ -58,25 +59,28 @@ class Main() extends StrictLogging { def run(args: Array[String])(implicit system: ActorSystem[_]): Unit = { help(args.toList) args.toList match { - case command :: any => + case command :: list => configs.find(_.command == command) match { case None => println(s"ERROR: Unknown command --> $command") printUsage() System.exit(1) - case Some(config) => + case Some(_) => command match { case "tokens" => - TokensConfig.parse(any) match { + TokensConfig.parse(list) match { case None => println(s"ERROR: Invalid arguments for command --> $command") printUsage(command) System.exit(1) case Some(conf) => - implicit def ec: ExecutionContext = system.executionContext - Tokens.run(conf) onComplete { result => - println(result) - System.exit(0) + Tokens.run(conf) complete () match { + case Success(result) => + println(result) + System.exit(0) + case Failure(f) => + logger.error(s"Failed to run command $command", f) + System.exit(1) } } case _ => From 01d7c30cd2453c64839873b004fc6dcd3db691e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Manciot?= Date: Thu, 7 Dec 2023 00:12:55 +0100 Subject: [PATCH 16/37] to fix account status while creating account for provider(s) --- .../scala/app/softnetwork/payment/model/ProviderDecorator.scala | 2 ++ 1 file changed, 2 insertions(+) diff --git a/common/src/main/scala/app/softnetwork/payment/model/ProviderDecorator.scala b/common/src/main/scala/app/softnetwork/payment/model/ProviderDecorator.scala index 56dcd72..a29567a 100644 --- a/common/src/main/scala/app/softnetwork/payment/model/ProviderDecorator.scala +++ b/common/src/main/scala/app/softnetwork/payment/model/ProviderDecorator.scala @@ -1,5 +1,6 @@ package app.softnetwork.payment.model +import app.softnetwork.account.model.AccountStatus import app.softnetwork.payment.spi.PaymentProviders import app.softnetwork.security.sha256 @@ -19,5 +20,6 @@ trait ProviderDecorator { self: SoftPaymentAccount.Client.Provider => .withUuid(clientId) .withAnonymous(true) .withClients(Seq(client)) + .withStatus(AccountStatus.Active) } } From 759588462171e1737561b9390df0d66ae5ec044a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Manciot?= Date: Thu, 7 Dec 2023 10:15:39 +0100 Subject: [PATCH 17/37] update access token stuff --- build.sbt | 4 ++-- client/src/main/protobuf/api/client.proto | 2 +- .../payment/cli/tokens/Tokens.scala | 11 ++++++++-- .../payment/api/ClientServer.scala | 6 ++++-- .../handlers/SoftPaymentAccountDao.scala | 21 +++++++++++-------- .../typed/SoftPaymentAccountBehavior.scala | 21 ++++++++++++++----- .../service/SoftPaymentOAuthService.scala | 10 +++++---- .../SoftPaymentOAuthServiceEndpoints.scala | 10 +++++---- project/Versions.scala | 2 +- 9 files changed, 57 insertions(+), 30 deletions(-) diff --git a/build.sbt b/build.sbt index 42b5369..fdf8182 100644 --- a/build.sbt +++ b/build.sbt @@ -31,8 +31,8 @@ Test / parallelExecution := false lazy val client = project.in(file("client")) .configs(IntegrationTest) - .settings(Defaults.itSettings) - .enablePlugins(AkkaGrpcPlugin) + .settings(Defaults.itSettings, app.softnetwork.Info.infoSettings) + .enablePlugins(BuildInfoPlugin, AkkaGrpcPlugin) lazy val common = project.in(file("common")) .configs(IntegrationTest) diff --git a/client/src/main/protobuf/api/client.proto b/client/src/main/protobuf/api/client.proto index 26ef8c2..de45ea3 100644 --- a/client/src/main/protobuf/api/client.proto +++ b/client/src/main/protobuf/api/client.proto @@ -20,7 +20,7 @@ message Tokens { string token_type = 2; int64 expires_in = 3; string refresh_token = 4; - // google.protobuf.StringValue scope = 5; + google.protobuf.Int64Value refresh_token_expires_in = 5; } message ClientTokensResponse { diff --git a/client/src/main/scala/app/softnetwork/payment/cli/tokens/Tokens.scala b/client/src/main/scala/app/softnetwork/payment/cli/tokens/Tokens.scala index 3bcffe6..83312c3 100644 --- a/client/src/main/scala/app/softnetwork/payment/cli/tokens/Tokens.scala +++ b/client/src/main/scala/app/softnetwork/payment/cli/tokens/Tokens.scala @@ -4,6 +4,7 @@ import akka.actor.typed.ActorSystem import app.softnetwork.payment.api.Client import app.softnetwork.payment.cli.Command import com.typesafe.scalalogging.StrictLogging +import org.json4s.Formats import scala.concurrent.{ExecutionContext, Future} @@ -13,13 +14,15 @@ object Tokens extends Command[TokensConfig] with StrictLogging { )(implicit system: ActorSystem[_]): Future[String] = { implicit val ec: ExecutionContext = system.executionContext val client = Client(system) + implicit val formats: Formats = org.json4s.DefaultFormats config.refreshToken match { case Some(refreshToken) => client.refreshClientTokens(refreshToken) map { case Some(tokens) => + val json = org.json4s.jackson.Serialization.writePretty(tokens) s""" |Tokens refreshed successfully! - |${tokens.toString} + |$json |""".stripMargin case _ => s""" @@ -29,7 +32,11 @@ object Tokens extends Command[TokensConfig] with StrictLogging { case None => client.generateClientTokens() map { case Some(tokens) => - s"Tokens generated successfully! ${tokens.toString}" + val json = org.json4s.jackson.Serialization.writePretty(tokens) + s""" + |Tokens generated successfully! + |$json + |""".stripMargin case _ => "Tokens generation failed!" } diff --git a/core/src/main/scala/app/softnetwork/payment/api/ClientServer.scala b/core/src/main/scala/app/softnetwork/payment/api/ClientServer.scala index 9690c76..9aed44a 100644 --- a/core/src/main/scala/app/softnetwork/payment/api/ClientServer.scala +++ b/core/src/main/scala/app/softnetwork/payment/api/ClientServer.scala @@ -26,7 +26,8 @@ trait ClientServer extends ClientServiceApi with PaymentHandler { access_token, token_type, expires_in, - refresh_token + refresh_token, + refresh_token_expires_in.map(_.toLong) ) ) case _ => ClientTokensResponse.defaultInstance.withError("unknown") @@ -43,7 +44,8 @@ trait ClientServer extends ClientServiceApi with PaymentHandler { access_token, token_type, expires_in, - refresh_token + refresh_token, + refresh_token_expires_in.map(_.toLong) ) ) case _ => ClientTokensResponse.defaultInstance.withError("unknown") diff --git a/core/src/main/scala/app/softnetwork/payment/handlers/SoftPaymentAccountDao.scala b/core/src/main/scala/app/softnetwork/payment/handlers/SoftPaymentAccountDao.scala index 127f674..ff75e37 100644 --- a/core/src/main/scala/app/softnetwork/payment/handlers/SoftPaymentAccountDao.scala +++ b/core/src/main/scala/app/softnetwork/payment/handlers/SoftPaymentAccountDao.scala @@ -2,7 +2,6 @@ package app.softnetwork.payment.handlers import akka.actor.typed.ActorSystem import akka.cluster.sharding.typed.scaladsl.EntityTypeKey -import app.softnetwork.account.config.AccountSettings import app.softnetwork.account.handlers.{AccountDao, AccountHandler} import app.softnetwork.account.message.{ AccessTokenGenerated, @@ -62,12 +61,14 @@ trait SoftPaymentAccountDao extends AccountDao { _: AccountHandler => implicit val ec: ExecutionContext = system.executionContext ??(clientId, AccountMessages.GenerateClientToken(clientId, clientSecret, scope)) map { case result: AccessTokenGenerated => + import result._ Some( Tokens( - result.accessToken.token, - result.accessToken.tokenType.toLowerCase(), - AccountSettings.OAuthSettings.accessToken.expirationTime * 60, - result.accessToken.refreshToken + accessToken.token, + accessToken.tokenType.toLowerCase(), + accessToken.expiresIn, + accessToken.refreshToken, + accessToken.refreshExpiresIn ) ) case _ => None @@ -80,12 +81,14 @@ trait SoftPaymentAccountDao extends AccountDao { _: AccountHandler => implicit val ec: ExecutionContext = system.executionContext ??(refreshToken, AccountMessages.RefreshClientToken(refreshToken)) map { case result: AccessTokenRefreshed => + import result._ Some( Tokens( - result.accessToken.token, - result.accessToken.tokenType.toLowerCase(), - AccountSettings.OAuthSettings.accessToken.expirationTime * 60, - result.accessToken.refreshToken + accessToken.token, + accessToken.tokenType.toLowerCase(), + accessToken.expiresIn, + accessToken.refreshToken, + accessToken.refreshExpiresIn ) ) case _ => None diff --git a/core/src/main/scala/app/softnetwork/payment/persistence/typed/SoftPaymentAccountBehavior.scala b/core/src/main/scala/app/softnetwork/payment/persistence/typed/SoftPaymentAccountBehavior.scala index 1f7cfc5..3f2b5eb 100644 --- a/core/src/main/scala/app/softnetwork/payment/persistence/typed/SoftPaymentAccountBehavior.scala +++ b/core/src/main/scala/app/softnetwork/payment/persistence/typed/SoftPaymentAccountBehavior.scala @@ -231,7 +231,9 @@ trait SoftPaymentAccountBehavior extends AccountBehavior[SoftPaymentAccount, Bas state match { case Some(account) if account.status.isActive => account.clients.find( - _.accessToken.map(_.refreshToken).getOrElse("") == sha256(refreshToken) + _.accessToken.exists(at => + at.refreshToken == sha256(refreshToken) && !at.refreshExpired + ) ) match { case Some(client) => val previousToken = client.getAccessToken @@ -257,7 +259,7 @@ trait SoftPaymentAccountBehavior extends AccountBehavior[SoftPaymentAccount, Bas ) ) .thenRun { _ => - AccessTokenGenerated(accessToken) ~> replyTo + AccessTokenRefreshed(accessToken) ~> replyTo } case _ => @@ -313,12 +315,21 @@ trait SoftPaymentAccountBehavior extends AccountBehavior[SoftPaymentAccount, Bas case AccountMessages.RegisterProviderAccount(provider) => state match { case Some(account) => + val updatedClient = account.clients.find(_.clientId == provider.clientId) match { + case Some(client) => + client.withClientApiKey(provider.client.getClientApiKey) + case _ => + provider.client + } accountKeyDao.addAccountKey(provider.clientId, entityId) Effect .persist( - SoftPaymentAccountProviderRegisteredEvent( - provider.client, - Instant.now() + List( + AccountActivatedEvent(entityId, Some(Instant.now())), + SoftPaymentAccountProviderRegisteredEvent( + updatedClient, + Instant.now() + ) ) ) .thenRun(state => diff --git a/core/src/main/scala/app/softnetwork/payment/service/SoftPaymentOAuthService.scala b/core/src/main/scala/app/softnetwork/payment/service/SoftPaymentOAuthService.scala index cd9a138..599fa54 100644 --- a/core/src/main/scala/app/softnetwork/payment/service/SoftPaymentOAuthService.scala +++ b/core/src/main/scala/app/softnetwork/payment/service/SoftPaymentOAuthService.scala @@ -52,8 +52,9 @@ trait SoftPaymentOAuthService[SD <: SessionData with SessionDataDecorator[SD]] Tokens( r.accessToken.token, r.accessToken.tokenType.toLowerCase(), - AccountSettings.OAuthSettings.accessToken.expirationTime * 60, - r.accessToken.refreshToken + r.accessToken.expiresIn, + r.accessToken.refreshToken, + r.accessToken.refreshExpiresIn ) ) case error: AccountErrorMessage => @@ -76,8 +77,9 @@ trait SoftPaymentOAuthService[SD <: SessionData with SessionDataDecorator[SD]] Tokens( r.accessToken.token, r.accessToken.tokenType.toLowerCase(), - AccountSettings.OAuthSettings.accessToken.expirationTime * 60, - r.accessToken.refreshToken + r.accessToken.expiresIn, + r.accessToken.refreshToken, + r.accessToken.refreshExpiresIn ) ) case error: AccountErrorMessage => diff --git a/core/src/main/scala/app/softnetwork/payment/service/SoftPaymentOAuthServiceEndpoints.scala b/core/src/main/scala/app/softnetwork/payment/service/SoftPaymentOAuthServiceEndpoints.scala index ec08761..cdfdae9 100644 --- a/core/src/main/scala/app/softnetwork/payment/service/SoftPaymentOAuthServiceEndpoints.scala +++ b/core/src/main/scala/app/softnetwork/payment/service/SoftPaymentOAuthServiceEndpoints.scala @@ -90,8 +90,9 @@ trait SoftPaymentOAuthServiceEndpoints[SD <: SessionData with SessionDataDecorat Tokens( r.accessToken.token, r.accessToken.tokenType.toLowerCase(), - AccountSettings.OAuthSettings.accessToken.expirationTime * 60, - r.accessToken.refreshToken + r.accessToken.expiresIn, + r.accessToken.refreshToken, + r.accessToken.refreshExpiresIn ) ) case error: AccountErrorMessage => @@ -106,8 +107,9 @@ trait SoftPaymentOAuthServiceEndpoints[SD <: SessionData with SessionDataDecorat Tokens( r.accessToken.token, r.accessToken.tokenType.toLowerCase(), - AccountSettings.OAuthSettings.accessToken.expirationTime * 60, - r.accessToken.refreshToken + r.accessToken.expiresIn, + r.accessToken.refreshToken, + r.accessToken.refreshExpiresIn ) ) case error: AccountErrorMessage => diff --git a/project/Versions.scala b/project/Versions.scala index be6c935..230372d 100644 --- a/project/Versions.scala +++ b/project/Versions.scala @@ -6,7 +6,7 @@ object Versions { val notification = "0.6.3" - val account = "0.6.2" + val account = "0.6.2.1" val scalatest = "3.2.16" From 0d41e7d0ce362125da3f72accc49f5b9dbe18062 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Manciot?= Date: Thu, 7 Dec 2023 10:55:20 +0100 Subject: [PATCH 18/37] disable upload coverage to Codecov --- .github/workflows/build.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ca07cba..e032fa3 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -40,13 +40,13 @@ jobs: # cache: 'sbt' - name: Run tests & Coverage Report run: sbt coverage test coverageReport - - name: Upload coverage to Codecov - uses: codecov/codecov-action@v3 - with: - files: common/target/scala-2.12/coverage-report/cobertura.xml,core/target/scala-2.12/coverage-report/cobertura.xml,teskit/target/scala-2.12/coverage-report/cobertura.xml - flags: unittests - fail_ci_if_error: true - verbose: true +# - name: Upload coverage to Codecov +# uses: codecov/codecov-action@v3 +# with: +# files: common/target/scala-2.12/coverage-report/cobertura.xml,core/target/scala-2.12/coverage-report/cobertura.xml,teskit/target/scala-2.12/coverage-report/cobertura.xml +# flags: unittests +# fail_ci_if_error: true +# verbose: true # - name: Run tests # run: sbt test # Optional: This step uploads information to the GitHub dependency graph and unblocking Dependabot alerts for the repository From 59f5926d09f66ba24eaac52e59467af2b618dd1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Manciot?= Date: Thu, 7 Dec 2023 11:06:24 +0100 Subject: [PATCH 19/37] clean and run tests only for PR --- .github/workflows/build.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e032fa3..a614974 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -38,8 +38,8 @@ jobs: java-version: '8' distribution: 'temurin' # cache: 'sbt' - - name: Run tests & Coverage Report - run: sbt coverage test coverageReport +# - name: Run tests & Coverage Report +# run: sbt coverage test coverageReport # - name: Upload coverage to Codecov # uses: codecov/codecov-action@v3 # with: @@ -47,8 +47,8 @@ jobs: # flags: unittests # fail_ci_if_error: true # verbose: true - # - name: Run tests - # run: sbt test + - name: Run tests + run: sbt clean test # Optional: This step uploads information to the GitHub dependency graph and unblocking Dependabot alerts for the repository # - name: Upload dependency graph # uses: scalacenter/sbt-dependency-submission@ab086b50c947c9774b70f39fc7f6e20ca2706c91 From d591f763844d196d27d4bfc49f0063673407f2e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Manciot?= Date: Thu, 7 Dec 2023 11:53:12 +0100 Subject: [PATCH 20/37] update ClientServer --- .../app/softnetwork/payment/api/ClientServer.scala | 10 ++++------ .../payment/handlers/SoftPaymentAccountDao.scala | 9 ++++----- .../app/softnetwork/payment/api/MockClientServer.scala | 10 ++-------- .../payment/handlers/MockSoftPaymentAccountDao.scala | 9 ++++++--- 4 files changed, 16 insertions(+), 22 deletions(-) diff --git a/core/src/main/scala/app/softnetwork/payment/api/ClientServer.scala b/core/src/main/scala/app/softnetwork/payment/api/ClientServer.scala index 9aed44a..756cfb8 100644 --- a/core/src/main/scala/app/softnetwork/payment/api/ClientServer.scala +++ b/core/src/main/scala/app/softnetwork/payment/api/ClientServer.scala @@ -1,24 +1,22 @@ package app.softnetwork.payment.api import akka.actor.typed.ActorSystem -import app.softnetwork.payment.handlers.{PaymentHandler, SoftPaymentAccountDao} +import app.softnetwork.payment.handlers.SoftPaymentAccountDao import org.slf4j.{Logger, LoggerFactory} import scala.concurrent.{ExecutionContextExecutor, Future} -trait ClientServer extends ClientServiceApi with PaymentHandler { +trait ClientServer extends ClientServiceApi with SoftPaymentAccountDao { implicit def system: ActorSystem[_] implicit lazy val ec: ExecutionContextExecutor = system.executionContext - def softPaymentAccountDao: SoftPaymentAccountDao = SoftPaymentAccountDao - override def generateClientTokens( in: GenerateClientTokensRequest ): Future[ClientTokensResponse] = { import in._ - softPaymentAccountDao.generateClientToken(clientId, clientSecret, scope) map { + generateClientToken(clientId, clientSecret, scope) map { case Some(tokens) => import tokens._ ClientTokensResponse.defaultInstance.withTokens( @@ -36,7 +34,7 @@ trait ClientServer extends ClientServiceApi with PaymentHandler { override def refreshClientTokens(in: RefreshClientTokensRequest): Future[ClientTokensResponse] = { import in._ - softPaymentAccountDao.refreshClientToken(refreshToken) map { + refreshClientToken(refreshToken) map { case Some(tokens) => import tokens._ ClientTokensResponse.defaultInstance.withTokens( diff --git a/core/src/main/scala/app/softnetwork/payment/handlers/SoftPaymentAccountDao.scala b/core/src/main/scala/app/softnetwork/payment/handlers/SoftPaymentAccountDao.scala index ff75e37..f50aac7 100644 --- a/core/src/main/scala/app/softnetwork/payment/handlers/SoftPaymentAccountDao.scala +++ b/core/src/main/scala/app/softnetwork/payment/handlers/SoftPaymentAccountDao.scala @@ -22,7 +22,7 @@ import org.slf4j.{Logger, LoggerFactory} import scala.concurrent.{ExecutionContext, Future} import scala.reflect.ClassTag -trait SoftPaymentAccountDao extends AccountDao { _: AccountHandler => +trait SoftPaymentAccountDao extends AccountDao with SoftPaymentAccountHandler { @InternalApi private[payment] def loadProvider( clientId: String @@ -164,9 +164,8 @@ trait SoftPaymentAccountTypeKey extends CommandTypeKey[AccountCommand] { SoftPaymentAccountBehavior.TypeKey } -object SoftPaymentAccountDao - extends SoftPaymentAccountDao - with AccountHandler - with SoftPaymentAccountTypeKey { +trait SoftPaymentAccountHandler extends AccountHandler with SoftPaymentAccountTypeKey + +object SoftPaymentAccountDao extends SoftPaymentAccountDao { lazy val log: Logger = LoggerFactory getLogger getClass.getName } diff --git a/testkit/src/main/scala/app/softnetwork/payment/api/MockClientServer.scala b/testkit/src/main/scala/app/softnetwork/payment/api/MockClientServer.scala index 2680594..6d3927b 100644 --- a/testkit/src/main/scala/app/softnetwork/payment/api/MockClientServer.scala +++ b/testkit/src/main/scala/app/softnetwork/payment/api/MockClientServer.scala @@ -1,20 +1,14 @@ package app.softnetwork.payment.api import akka.actor.typed.ActorSystem -import app.softnetwork.payment.handlers.{ - MockPaymentHandler, - MockPaymentTypeKey, - MockSoftPaymentAccountDao, - SoftPaymentAccountDao -} +import app.softnetwork.payment.handlers.MockSoftPaymentAccountDao import org.slf4j.{Logger, LoggerFactory} -trait MockClientServer extends ClientServer with MockPaymentHandler +trait MockClientServer extends ClientServer with MockSoftPaymentAccountDao object MockClientServer { def apply(sys: ActorSystem[_]): MockClientServer = { new MockClientServer { - override def softPaymentAccountDao: SoftPaymentAccountDao = MockSoftPaymentAccountDao lazy val log: Logger = LoggerFactory getLogger getClass.getName override implicit val system: ActorSystem[_] = sys } diff --git a/testkit/src/main/scala/app/softnetwork/payment/handlers/MockSoftPaymentAccountDao.scala b/testkit/src/main/scala/app/softnetwork/payment/handlers/MockSoftPaymentAccountDao.scala index 2ba229d..43567b0 100644 --- a/testkit/src/main/scala/app/softnetwork/payment/handlers/MockSoftPaymentAccountDao.scala +++ b/testkit/src/main/scala/app/softnetwork/payment/handlers/MockSoftPaymentAccountDao.scala @@ -1,7 +1,6 @@ package app.softnetwork.payment.handlers import akka.cluster.sharding.typed.scaladsl.EntityTypeKey -import app.softnetwork.account.handlers.AccountHandler import app.softnetwork.account.message.AccountCommand import app.softnetwork.payment.persistence.typed.MockSoftPaymentAccountBehavior import app.softnetwork.persistence.typed.CommandTypeKey @@ -14,8 +13,12 @@ trait MockSoftPaymentAccountTypeKey extends CommandTypeKey[AccountCommand] { MockSoftPaymentAccountBehavior.TypeKey } -trait MockSoftPaymentAccountHandler extends AccountHandler with MockSoftPaymentAccountTypeKey +trait MockSoftPaymentAccountHandler + extends SoftPaymentAccountHandler + with MockSoftPaymentAccountTypeKey -object MockSoftPaymentAccountDao extends SoftPaymentAccountDao with MockSoftPaymentAccountHandler { +trait MockSoftPaymentAccountDao extends SoftPaymentAccountDao with MockSoftPaymentAccountTypeKey + +object MockSoftPaymentAccountDao extends MockSoftPaymentAccountDao { lazy val log: Logger = LoggerFactory getLogger getClass.getName } From 7cf526ab9dbfac8eb7a600684c3f809ad7dbc801 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Manciot?= Date: Thu, 7 Dec 2023 12:55:14 +0100 Subject: [PATCH 21/37] update payment client requests --- client/src/main/protobuf/api/payment.proto | 13 +++ .../protobuf/model/payment/paymentUser.proto | 2 + .../payment/api/PaymentClient.scala | 34 ++++-- .../payment/message/PaymentMessages.scala | 64 +++++++++-- .../payment/api/PaymentServer.scala | 36 ++++-- .../service/BankAccountEndpoints.scala | 107 +++++++++--------- .../payment/service/MandateEndpoints.scala | 11 +- .../payment/service/PaymentService.scala | 34 ++++-- .../service/PaymentServiceEndpoints.scala | 11 +- .../service/RecurringPaymentEndpoints.scala | 11 +- 10 files changed, 224 insertions(+), 99 deletions(-) diff --git a/client/src/main/protobuf/api/payment.proto b/client/src/main/protobuf/api/payment.proto index c065d2f..7342fee 100644 --- a/client/src/main/protobuf/api/payment.proto +++ b/client/src/main/protobuf/api/payment.proto @@ -40,6 +40,7 @@ message PayInWithCardPreAuthorizedRequest { string preAuthorizationId = 1; string creditedAccount = 2; google.protobuf.Int32Value debitedAmount = 3; + string clientId = 4; } enum TransactionStatus{ @@ -59,6 +60,7 @@ message TransactionResponse { message CancelPreAuthorizationRequest { string orderUuid = 1; string cardPreAuthorizedTransactionId = 2; + string clientId = 3; } message CancelPreAuthorizationResponse { @@ -72,6 +74,7 @@ message RefundRequest { string currency = 4; string reasonMessage = 5; bool initializedByClient = 6; + string clientId = 7; } message PayOutRequest { @@ -81,6 +84,7 @@ message PayOutRequest { int32 feesAmount = 4; string currency = 5; google.protobuf.StringValue externalReference = 6; + string clientId = 7; } message TransferRequest { @@ -92,6 +96,7 @@ message TransferRequest { string currency = 6; bool payOutRequired = 7; google.protobuf.StringValue externalReference = 8; + string clientId = 9; } message TransferResponse { @@ -108,10 +113,12 @@ message DirectDebitRequest { string currency = 4; string statementDescriptor = 5; google.protobuf.StringValue externalReference = 6; + string clientId = 7; } message LoadDirectDebitTransactionRequest { string directDebitTransactionId = 1; + string clientId = 2; } message RegisterRecurringPaymentRequest { @@ -142,6 +149,9 @@ message RegisterRecurringPaymentRequest { google.protobuf.BoolValue fixedNextAmount = 9; google.protobuf.Int32Value nextDebitedAmount = 10; google.protobuf.Int32Value nextFeesAmount = 11; + google.protobuf.StringValue statementDescriptor = 12; + google.protobuf.StringValue externalReference = 13; + string clientId = 14; } message RegisterRecurringPaymentResponse { @@ -150,6 +160,7 @@ message RegisterRecurringPaymentResponse { message CancelMandateRequest { string externalUuid = 1; + string clientId = 2; } message CancelMandateResponse { @@ -158,6 +169,7 @@ message CancelMandateResponse { message LoadBankAccountOwnerRequest { string externalUuid = 1; + string clientId = 2; } message LoadBankAccountOwnerResponse { @@ -173,6 +185,7 @@ enum LegalUserType { message LoadLegalUserRequest { string externalUuid = 1; + string clientId = 2; } message LoadLegalUserResponse { diff --git a/client/src/main/protobuf/model/payment/paymentUser.proto b/client/src/main/protobuf/model/payment/paymentUser.proto index c9bb8fe..f14e8c6 100644 --- a/client/src/main/protobuf/model/payment/paymentUser.proto +++ b/client/src/main/protobuf/model/payment/paymentUser.proto @@ -192,4 +192,6 @@ message RecurringPayment { optional int32 cumulatedFeesAmount = 20; optional bool migration = 21; optional string cardId = 22; + optional string statementDescriptor = 23; + optional string externalReference = 24; } \ No newline at end of file diff --git a/client/src/main/scala/app/softnetwork/payment/api/PaymentClient.scala b/client/src/main/scala/app/softnetwork/payment/api/PaymentClient.scala index 0343257..8a4e850 100644 --- a/client/src/main/scala/app/softnetwork/payment/api/PaymentClient.scala +++ b/client/src/main/scala/app/softnetwork/payment/api/PaymentClient.scala @@ -59,7 +59,12 @@ trait PaymentClient extends GrpcClient { token ) .invoke( - PayInWithCardPreAuthorizedRequest(preAuthorizationId, creditedAccount, debitedAmount) + PayInWithCardPreAuthorizedRequest( + preAuthorizationId, + creditedAccount, + debitedAmount, + settings.clientId + ) ) } @@ -73,7 +78,7 @@ trait PaymentClient extends GrpcClient { token ) .invoke( - CancelPreAuthorizationRequest(orderUuid, cardPreAuthorizedTransactionId) + CancelPreAuthorizationRequest(orderUuid, cardPreAuthorizedTransactionId, settings.clientId) ) map (_.preAuthorizationCanceled) } @@ -97,7 +102,8 @@ trait PaymentClient extends GrpcClient { refundAmount, currency, reasonMessage, - initializedByClient + initializedByClient, + settings.clientId ) ) } @@ -122,7 +128,8 @@ trait PaymentClient extends GrpcClient { creditedAmount, feesAmount, currency, - externalReference + externalReference, + settings.clientId ) ) } @@ -151,7 +158,8 @@ trait PaymentClient extends GrpcClient { feesAmount, currency, payOutRequired, - externalReference + externalReference, + settings.clientId ) ) } @@ -176,7 +184,8 @@ trait PaymentClient extends GrpcClient { feesAmount, currency, statementDescriptor, - externalReference + externalReference, + settings.clientId ) ) } @@ -190,7 +199,7 @@ trait PaymentClient extends GrpcClient { token ) .invoke( - LoadDirectDebitTransactionRequest(directDebitTransactionId) + LoadDirectDebitTransactionRequest(directDebitTransactionId, settings.clientId) ) } @@ -206,6 +215,8 @@ trait PaymentClient extends GrpcClient { fixedNextAmount: Option[Boolean], nextDebitedAmount: Option[Int], nextFeesAmount: Option[Int], + statementDescriptor: Option[String], + externalReference: Option[String], token: Option[String] = None ): Future[Option[String]] = { withAuthorization( @@ -228,7 +239,10 @@ trait PaymentClient extends GrpcClient { }, fixedNextAmount, nextDebitedAmount, - nextFeesAmount + nextFeesAmount, + statementDescriptor, + externalReference, + settings.clientId ) ) map (_.recurringPaymentRegistrationId) } @@ -249,7 +263,7 @@ trait PaymentClient extends GrpcClient { grpcClient.loadBankAccountOwner(), token ) - .invoke(LoadBankAccountOwnerRequest(externalUuid)) map (response => + .invoke(LoadBankAccountOwnerRequest(externalUuid, settings.clientId)) map (response => BankAccountOwner(response.ownerName, response.ownerAddress) ) } @@ -262,7 +276,7 @@ trait PaymentClient extends GrpcClient { grpcClient.loadLegalUser(), token ) - .invoke(LoadLegalUserRequest(externalUuid)) map (response => + .invoke(LoadLegalUserRequest(externalUuid, settings.clientId)) map (response => LegalUserDetails( response.legalUserType, response.legalName, diff --git a/common/src/main/scala/app/softnetwork/payment/message/PaymentMessages.scala b/common/src/main/scala/app/softnetwork/payment/message/PaymentMessages.scala index ad4c243..885d3bd 100644 --- a/common/src/main/scala/app/softnetwork/payment/message/PaymentMessages.scala +++ b/common/src/main/scala/app/softnetwork/payment/message/PaymentMessages.scala @@ -146,10 +146,13 @@ object PaymentMessages { * - order unique id * @param cardPreAuthorizedTransactionId * - card pre authorized transaction id + * @param clientId + * - optional client id */ case class CancelPreAuthorization( orderUuid: String, - cardPreAuthorizedTransactionId: String + cardPreAuthorizedTransactionId: String, + clientId: Option[String] = None ) extends PaymentCommandWithKey { lazy val key: String = cardPreAuthorizedTransactionId } @@ -176,11 +179,14 @@ object PaymentMessages { * @param debitedAmount * - amount to be debited from the account that made the pre-authorization (if not specified it * will be the amount specified during the pre-authorization) + * @param clientId + * - optional client id */ case class PayInWithCardPreAuthorized( preAuthorizationId: String, creditedAccount: String, - debitedAmount: Option[Int] + debitedAmount: Option[Int], + clientId: Option[String] = None ) extends PaymentCommandWithKey { lazy val key: String = preAuthorizationId } @@ -281,6 +287,8 @@ object PaymentMessages { * - currency * @param externalReference * - optional external reference + * @param clientId + * - optional client id */ case class PayOut( orderUuid: String, @@ -288,7 +296,8 @@ object PaymentMessages { creditedAmount: Int, feesAmount: Int = 0, currency: String = "EUR", - externalReference: Option[String] = None + externalReference: Option[String] = None, + clientId: Option[String] = None ) extends PaymentCommandWithKey { val key: String = creditedAccount } @@ -305,6 +314,8 @@ object PaymentMessages { * - reason message * @param initializedByClient * - whether the refund is initialized by the client or not + * @param clientId + * - optional client id */ case class Refund( orderUuid: String, @@ -312,7 +323,8 @@ object PaymentMessages { refundAmount: Int, currency: String = "EUR", reasonMessage: String, - initializedByClient: Boolean + initializedByClient: Boolean, + clientId: Option[String] = None ) extends PaymentCommandWithKey { lazy val key: String = payInTransactionId } @@ -333,6 +345,8 @@ object PaymentMessages { * - whether an immediate pay out is required or not * @param externalReference * - optional external reference + * @param clientId + * - optional client id */ case class Transfer( orderUuid: Option[String] = None, @@ -342,7 +356,8 @@ object PaymentMessages { feesAmount: Int = 0, currency: String = "EUR", payOutRequired: Boolean = true, - externalReference: Option[String] = None + externalReference: Option[String] = None, + clientId: Option[String] = None ) extends PaymentCommandWithKey { val key: String = debitedAccount } @@ -359,6 +374,8 @@ object PaymentMessages { * - statement descriptor * @param externalReference * - optional external reference + * @param clientId + * - optional client id */ case class DirectDebit( creditedAccount: String, @@ -366,16 +383,21 @@ object PaymentMessages { feesAmount: Int = 0, currency: String = "EUR", statementDescriptor: String, - externalReference: Option[String] = None + externalReference: Option[String] = None, + clientId: Option[String] = None ) extends PaymentCommandWithKey { val key: String = creditedAccount } /** @param directDebitTransactionId * - direct debit transaction id + * @param clientId + * - optional client id */ - case class LoadDirectDebitTransaction(directDebitTransactionId: String) - extends PaymentCommandWithKey { + case class LoadDirectDebitTransaction( + directDebitTransactionId: String, + clientId: Option[String] = None + ) extends PaymentCommandWithKey { val key: String = directDebitTransactionId } @@ -401,6 +423,12 @@ object PaymentMessages { * - next debited amount * @param nextFeesAmount * - next fees amount + * @param statementDescriptor + * - statement descriptor + * @param externalReference + * - optional external reference + * @param clientId + * - optional client id */ case class RegisterRecurringPayment( debitedAccount: String, @@ -413,7 +441,10 @@ object PaymentMessages { frequency: Option[RecurringPayment.RecurringPaymentFrequency] = None, fixedNextAmount: Option[Boolean] = None, nextDebitedAmount: Option[Int] = None, - nextFeesAmount: Option[Int] = None + nextFeesAmount: Option[Int] = None, + statementDescriptor: Option[String] = None, + externalReference: Option[String] = None, + clientId: Option[String] = None ) extends PaymentCommandWithKey { val key: String = debitedAccount } @@ -507,9 +538,12 @@ object PaymentMessages { * * @param account * - payment account reference + * @param clientId + * - optional client id */ @InternalApi - private[payment] case class LoadPaymentAccount(account: String) extends PaymentCommandWithKey { + private[payment] case class LoadPaymentAccount(account: String, clientId: Option[String] = None) + extends PaymentCommandWithKey { lazy val key: String = account } @@ -566,8 +600,11 @@ object PaymentMessages { /** @param creditedAccount * - account to load + * @param clientId + * - optional client id */ - case class LoadBankAccount(creditedAccount: String) extends PaymentCommandWithKey { + case class LoadBankAccount(creditedAccount: String, clientId: Option[String] = None) + extends PaymentCommandWithKey { val key: String = creditedAccount } @@ -696,8 +733,11 @@ object PaymentMessages { /** @param creditedAccount * - account which owns the mandate that would be canceled + * @param clientId + * - optional client id */ - case class CancelMandate(creditedAccount: String) extends PaymentCommandWithKey { + case class CancelMandate(creditedAccount: String, clientId: Option[String] = None) + extends PaymentCommandWithKey { val key: String = creditedAccount } diff --git a/core/src/main/scala/app/softnetwork/payment/api/PaymentServer.scala b/core/src/main/scala/app/softnetwork/payment/api/PaymentServer.scala index 762a167..ecc78d9 100644 --- a/core/src/main/scala/app/softnetwork/payment/api/PaymentServer.scala +++ b/core/src/main/scala/app/softnetwork/payment/api/PaymentServer.scala @@ -65,7 +65,9 @@ trait PaymentServer extends PaymentServiceApi with PaymentHandler { in: PayInWithCardPreAuthorizedRequest ): Future[TransactionResponse] = { import in._ - !?(PayInWithCardPreAuthorized(preAuthorizationId, creditedAccount, debitedAmount)) map { + !?( + PayInWithCardPreAuthorized(preAuthorizationId, creditedAccount, debitedAmount, Some(clientId)) + ) map { case r: PaidIn => TransactionResponse( transactionId = Some(r.transactionId), @@ -94,7 +96,7 @@ trait PaymentServer extends PaymentServiceApi with PaymentHandler { in: CancelPreAuthorizationRequest ): Future[CancelPreAuthorizationResponse] = { import in._ - !?(CancelPreAuthorization(orderUuid, cardPreAuthorizedTransactionId)) map { + !?(CancelPreAuthorization(orderUuid, cardPreAuthorizedTransactionId, Some(clientId))) map { case r: PreAuthorizationCanceled => CancelPreAuthorizationResponse(Some(r.preAuthorizationCanceled)) case _ => CancelPreAuthorizationResponse() @@ -110,7 +112,8 @@ trait PaymentServer extends PaymentServiceApi with PaymentHandler { refundAmount, currency, reasonMessage, - initializedByClient + initializedByClient, + Some(clientId) ) ) map { case r: Refunded => @@ -140,7 +143,15 @@ trait PaymentServer extends PaymentServiceApi with PaymentHandler { override def payOut(in: PayOutRequest): Future[TransactionResponse] = { import in._ !?( - PayOut(orderUuid, creditedAccount, creditedAmount, feesAmount, currency, externalReference) + PayOut( + orderUuid, + creditedAccount, + creditedAmount, + feesAmount, + currency, + externalReference, + Some(clientId) + ) ) map { case r: PaidOut => TransactionResponse( @@ -177,7 +188,8 @@ trait PaymentServer extends PaymentServiceApi with PaymentHandler { feesAmount, currency, payOutRequired, - externalReference + externalReference, + Some(clientId) ) ) map { case r: Transferred => @@ -214,7 +226,8 @@ trait PaymentServer extends PaymentServiceApi with PaymentHandler { feesAmount, currency, statementDescriptor, - externalReference + externalReference, + Some(clientId) ) ) map { case r: DirectDebited => @@ -245,7 +258,7 @@ trait PaymentServer extends PaymentServiceApi with PaymentHandler { in: LoadDirectDebitTransactionRequest ): Future[TransactionResponse] = { import in._ - !?(LoadDirectDebitTransaction(directDebitTransactionId)) map { + !?(LoadDirectDebitTransaction(directDebitTransactionId, Some(clientId))) map { case r: DirectDebited => TransactionResponse( transactionId = Some(r.transactionId), @@ -289,7 +302,10 @@ trait PaymentServer extends PaymentServiceApi with PaymentHandler { frequency, fixedNextAmount, nextDebitedAmount, - nextFeesAmount + nextFeesAmount, + statementDescriptor, + externalReference, + Some(clientId) ) ) map { case r: RecurringPaymentRegistered => @@ -312,7 +328,7 @@ trait PaymentServer extends PaymentServiceApi with PaymentHandler { in: LoadBankAccountOwnerRequest ): Future[LoadBankAccountOwnerResponse] = { import in._ - !?(LoadBankAccount(externalUuid)) map { + !?(LoadBankAccount(externalUuid, Some(clientId))) map { case r: BankAccountLoaded => LoadBankAccountOwnerResponse(r.bankAccount.ownerName, Some(r.bankAccount.ownerAddress)) case _ => LoadBankAccountOwnerResponse() @@ -323,7 +339,7 @@ trait PaymentServer extends PaymentServiceApi with PaymentHandler { in: LoadLegalUserRequest ): Future[LoadLegalUserResponse] = { import in._ - !?(LoadPaymentAccount(externalUuid)) map { + !?(LoadPaymentAccount(externalUuid, Some(clientId))) map { case r: PaymentAccountLoaded if r.paymentAccount.user.isLegalUser => val legalUser = r.paymentAccount.getLegalUser LoadLegalUserResponse( diff --git a/core/src/main/scala/app/softnetwork/payment/service/BankAccountEndpoints.scala b/core/src/main/scala/app/softnetwork/payment/service/BankAccountEndpoints.scala index be3484b..f2e0fc5 100644 --- a/core/src/main/scala/app/softnetwork/payment/service/BankAccountEndpoints.scala +++ b/core/src/main/scala/app/softnetwork/payment/service/BankAccountEndpoints.scala @@ -26,58 +26,60 @@ trait BankAccountEndpoints[SD <: SessionData with SessionDataDecorator[SD]] { statusCode(StatusCode.Ok) .and(jsonBody[BankAccountCreatedOrUpdated].description("Bank account created or updated")) ) - .serverLogic(principal => { bank => - import bank._ - var externalUuid: String = "" - val updatedUser: Option[PaymentAccount.User] = { - user match { - case Left(naturalUser) => - var updatedNaturalUser = { - if (naturalUser.externalUuid.trim.isEmpty) { - naturalUser.withExternalUuid(principal._2.id) - } else { - naturalUser + .serverLogic { + case (client, session) => { bank => + import bank._ + var externalUuid: String = "" + val updatedUser: Option[PaymentAccount.User] = { + user match { + case Left(naturalUser) => + var updatedNaturalUser = { + if (naturalUser.externalUuid.trim.isEmpty) { + naturalUser.withExternalUuid(session.id) + } else { + naturalUser + } } - } - principal._2.profile match { - case Some(profile) if updatedNaturalUser.profile.isEmpty => - updatedNaturalUser = updatedNaturalUser.withProfile(profile) - case _ => - } - externalUuid = updatedNaturalUser.externalUuid - Some(PaymentAccount.User.NaturalUser(updatedNaturalUser)) - case Right(legalUser) => - var updatedLegalRepresentative = legalUser.legalRepresentative - if (updatedLegalRepresentative.externalUuid.trim.isEmpty) { - updatedLegalRepresentative = - updatedLegalRepresentative.withExternalUuid(principal._2.id) - } - principal._2.profile match { - case Some(profile) if updatedLegalRepresentative.profile.isEmpty => - updatedLegalRepresentative = updatedLegalRepresentative.withProfile(profile) - case _ => - } - externalUuid = updatedLegalRepresentative.externalUuid - Some( - PaymentAccount.User.LegalUser( - legalUser.withLegalRepresentative(updatedLegalRepresentative) + session.profile match { + case Some(profile) if updatedNaturalUser.profile.isEmpty => + updatedNaturalUser = updatedNaturalUser.withProfile(profile) + case _ => + } + externalUuid = updatedNaturalUser.externalUuid + Some(PaymentAccount.User.NaturalUser(updatedNaturalUser)) + case Right(legalUser) => + var updatedLegalRepresentative = legalUser.legalRepresentative + if (updatedLegalRepresentative.externalUuid.trim.isEmpty) { + updatedLegalRepresentative = + updatedLegalRepresentative.withExternalUuid(session.id) + } + session.profile match { + case Some(profile) if updatedLegalRepresentative.profile.isEmpty => + updatedLegalRepresentative = updatedLegalRepresentative.withProfile(profile) + case _ => + } + externalUuid = updatedLegalRepresentative.externalUuid + Some( + PaymentAccount.User.LegalUser( + legalUser.withLegalRepresentative(updatedLegalRepresentative) + ) ) - ) + } + } + run( + CreateOrUpdateBankAccount( + externalUuidWithProfile(session), + bankAccount.withExternalUuid(externalUuid), + updatedUser, + acceptedTermsOfPSP, + clientId = client.map(_.clientId).orElse(session.clientId) + ) + ).map { + case r: BankAccountCreatedOrUpdated => Right(r) + case other => Left(error(other)) } } - run( - CreateOrUpdateBankAccount( - externalUuidWithProfile(principal._2), - bankAccount.withExternalUuid(externalUuid), - updatedUser, - acceptedTermsOfPSP, - clientId = principal._1.map(_.clientId).orElse(principal._2.clientId) - ) - ).map { - case r: BankAccountCreatedOrUpdated => Right(r) - case other => Left(error(other)) - } - }) + } .description("Create or update legal or natural user bank account") val loadBankAccount: ServerEndpoint[Any with AkkaStreams, Future] = @@ -89,16 +91,19 @@ trait BankAccountEndpoints[SD <: SessionData with SessionDataDecorator[SD]] { .description("Authenticated user bank account") ) ) - .serverLogic(principal => + .serverLogic { case (client, session) => _ => { run( - LoadBankAccount(externalUuidWithProfile(principal._2)) + LoadBankAccount( + externalUuidWithProfile(session), + clientId = client.map(_.clientId).orElse(session.clientId) + ) ).map { case r: BankAccountLoaded => Right(r.bankAccount.view) case other => Left(error(other)) } } - ) + } .description("Load authenticated user bank account") val deleteBankAccount: ServerEndpoint[Any with AkkaStreams, Future] = diff --git a/core/src/main/scala/app/softnetwork/payment/service/MandateEndpoints.scala b/core/src/main/scala/app/softnetwork/payment/service/MandateEndpoints.scala index f1c0cb5..06931cf 100644 --- a/core/src/main/scala/app/softnetwork/payment/service/MandateEndpoints.scala +++ b/core/src/main/scala/app/softnetwork/payment/service/MandateEndpoints.scala @@ -51,13 +51,18 @@ trait MandateEndpoints[SD <: SessionData with SessionDataDecorator[SD]] { statusCode(StatusCode.Ok) .and(jsonBody[MandateCanceled.type].description("Mandate canceled")) ) - .serverLogic(principal => + .serverLogic { case (client, session) => _ => - run(CancelMandate(externalUuidWithProfile(principal._2))).map { + run( + CancelMandate( + externalUuidWithProfile(session), + clientId = client.map(_.clientId).orElse(session.clientId) + ) + ).map { case MandateCanceled => Right(MandateCanceled) case other => Left(error(other)) } - ) + } .description("Create Mandate for the authenticated payment account") val updateMandateStatus: ServerEndpoint[Any with AkkaStreams, Future] = diff --git a/core/src/main/scala/app/softnetwork/payment/service/PaymentService.scala b/core/src/main/scala/app/softnetwork/payment/service/PaymentService.scala index 35111f1..7837186 100644 --- a/core/src/main/scala/app/softnetwork/payment/service/PaymentService.scala +++ b/core/src/main/scala/app/softnetwork/payment/service/PaymentService.scala @@ -132,10 +132,15 @@ trait PaymentService[SD <: SessionData with SessionDataDecorator[SD]] // check anti CSRF token hmacTokenCsrfProtection(checkHeader) { // check if a session exists - requiredClientSession { (_, session) => + requiredClientSession { (client, session) => get { pathEnd { - run(LoadPaymentAccount(externalUuidWithProfile(session))) completeWith { + run( + LoadPaymentAccount( + externalUuidWithProfile(session), + clientId = client.map(_.clientId).orElse(session.clientId) + ) + ) completeWith { case r: PaymentAccountLoaded => complete(HttpResponse(StatusCodes.OK, entity = r.paymentAccount.view)) case other => error(other) @@ -374,7 +379,12 @@ trait PaymentService[SD <: SessionData with SessionDataDecorator[SD]] requiredClientSession { (client, session) => pathEnd { get { - run(LoadBankAccount(externalUuidWithProfile(session))) completeWith { + run( + LoadBankAccount( + externalUuidWithProfile(session), + clientId = client.map(_.clientId).orElse(session.clientId) + ) + ) completeWith { case r: BankAccountLoaded => complete( HttpResponse( @@ -552,7 +562,7 @@ trait PaymentService[SD <: SessionData with SessionDataDecorator[SD]] // check anti CSRF token hmacTokenCsrfProtection(checkHeader) { // check if a session exists - requiredClientSession { (_, session) => + requiredClientSession { (client, session) => post { run(CreateMandate(externalUuidWithProfile(session))) completeWith { case r: MandateConfirmationRequired => @@ -562,7 +572,12 @@ trait PaymentService[SD <: SessionData with SessionDataDecorator[SD]] } } ~ delete { - run(CancelMandate(externalUuidWithProfile(session))) completeWith { + run( + CancelMandate( + externalUuidWithProfile(session), + clientId = client.map(_.clientId).orElse(session.clientId) + ) + ) completeWith { case MandateCanceled => complete(HttpResponse(StatusCodes.OK)) case other => error(other) } @@ -575,7 +590,7 @@ trait PaymentService[SD <: SessionData with SessionDataDecorator[SD]] // check anti CSRF token hmacTokenCsrfProtection(checkHeader) { // check if a session exists - requiredClientSession { (_, session) => + requiredClientSession { (client, session) => get { pathPrefix(Segment) { recurringPaymentRegistrationId => run( @@ -588,7 +603,12 @@ trait PaymentService[SD <: SessionData with SessionDataDecorator[SD]] } } ~ post { entity(as[RegisterRecurringPayment]) { cmd => - run(cmd.copy(debitedAccount = externalUuidWithProfile(session))) completeWith { + run( + cmd.copy( + debitedAccount = externalUuidWithProfile(session), + clientId = client.map(_.clientId).orElse(session.clientId) + ) + ) completeWith { case r: RecurringPaymentRegistered => complete(HttpResponse(StatusCodes.OK, entity = r)) case r: MandateConfirmationRequired => diff --git a/core/src/main/scala/app/softnetwork/payment/service/PaymentServiceEndpoints.scala b/core/src/main/scala/app/softnetwork/payment/service/PaymentServiceEndpoints.scala index bdba841..7815d51 100644 --- a/core/src/main/scala/app/softnetwork/payment/service/PaymentServiceEndpoints.scala +++ b/core/src/main/scala/app/softnetwork/payment/service/PaymentServiceEndpoints.scala @@ -35,14 +35,19 @@ trait PaymentServiceEndpoints[SD <: SessionData with SessionDataDecorator[SD]] val loadPaymentAccount: ServerEndpoint[Any with AkkaStreams, Future] = requiredSessionEndpoint.get .out(jsonBody[PaymentAccountView].description("Authenticated user payment account")) - .serverLogic(principal => + .serverLogic { case (client, session) => _ => { - run(LoadPaymentAccount(externalUuidWithProfile(principal._2))).map { + run( + LoadPaymentAccount( + externalUuidWithProfile(session), + clientId = client.map(_.clientId).orElse(session.clientId) + ) + ).map { case r: PaymentAccountLoaded => Right(r.paymentAccount.view) case other => Left(error(other)) } } - ) + } .description("Load authenticated user payment account") override val endpoints: List[ServerEndpoint[AkkaStreams with capabilities.WebSockets, Future]] = diff --git a/core/src/main/scala/app/softnetwork/payment/service/RecurringPaymentEndpoints.scala b/core/src/main/scala/app/softnetwork/payment/service/RecurringPaymentEndpoints.scala index 3069766..0a4e8a4 100644 --- a/core/src/main/scala/app/softnetwork/payment/service/RecurringPaymentEndpoints.scala +++ b/core/src/main/scala/app/softnetwork/payment/service/RecurringPaymentEndpoints.scala @@ -40,14 +40,19 @@ trait RecurringPaymentEndpoints[SD <: SessionData with SessionDataDecorator[SD]] ) ) ) - .serverLogic(principal => + .serverLogic { case (client, session) => cmd => - run(cmd.copy(debitedAccount = externalUuidWithProfile(principal._2))).map { + run( + cmd.copy( + debitedAccount = externalUuidWithProfile(session), + clientId = client.map(_.clientId).orElse(session.clientId) + ) + ).map { case r: RecurringPaymentRegistered => Right(r) case r: MandateConfirmationRequired => Right(r) case other => Left(error(other)) } - ) + } .description("Register a recurring payment for the authenticated payment account") val loadRecurringPayment: ServerEndpoint[Any with AkkaStreams, Future] = From 1469e823ee326a54214d6927482d3ac16915a8f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Manciot?= Date: Thu, 7 Dec 2023 13:25:53 +0100 Subject: [PATCH 22/37] add optional clientId field for transactions --- .../protobuf/model/payment/transaction.proto | 1 + .../persistence/typed/PaymentBehavior.scala | 69 ++++++++++++------- .../service/BankAccountEndpoints.scala | 5 +- 3 files changed, 46 insertions(+), 29 deletions(-) diff --git a/client/src/main/protobuf/model/payment/transaction.proto b/client/src/main/protobuf/model/payment/transaction.proto index 463897c..c18df20 100644 --- a/client/src/main/protobuf/model/payment/transaction.proto +++ b/client/src/main/protobuf/model/payment/transaction.proto @@ -84,6 +84,7 @@ message Transaction { optional string returnUrl = 30; optional string payPalBuyerAccountEmail = 31; optional string idempotencyKey = 32; + optional string clientId = 33; } message BrowserInfo { diff --git a/core/src/main/scala/app/softnetwork/payment/persistence/typed/PaymentBehavior.scala b/core/src/main/scala/app/softnetwork/payment/persistence/typed/PaymentBehavior.scala index 97478d1..2075435 100644 --- a/core/src/main/scala/app/softnetwork/payment/persistence/typed/PaymentBehavior.scala +++ b/core/src/main/scala/app/softnetwork/payment/persistence/typed/PaymentBehavior.scala @@ -421,9 +421,11 @@ trait PaymentBehavior import cmd._ state match { case Some(paymentAccount) => - val clientId = paymentAccount.clientId.orElse( - internalClientId - ) + val clientId = paymentAccount.clientId + .orElse(cmd.clientId) + .orElse( + internalClientId + ) val paymentProvider = loadPaymentProvider(clientId) import paymentProvider._ paymentAccount.transactions.find(_.id == cardPreAuthorizedTransactionId) match { @@ -432,7 +434,9 @@ trait PaymentBehavior cancelPreAuthorization(orderUuid, cardPreAuthorizedTransactionId) val updatedPaymentAccount = paymentAccount.withTransactions( paymentAccount.transactions.filterNot(_.id == cardPreAuthorizedTransactionId) :+ - preAuthorizationTransaction.withPreAuthorizationCanceled(preAuthorizationCanceled) + preAuthorizationTransaction + .withPreAuthorizationCanceled(preAuthorizationCanceled) + .copy(clientId = clientId) ) val lastUpdated = now() Effect @@ -819,9 +823,11 @@ trait PaymentBehavior import cmd._ state match { case Some(paymentAccount) => - val clientId = paymentAccount.clientId.orElse( - internalClientId - ) + val clientId = paymentAccount.clientId + .orElse(cmd.clientId) + .orElse( + internalClientId + ) val paymentProvider = loadPaymentProvider(clientId) import paymentProvider._ (paymentAccount.transactions.find(_.id == payInTransactionId) match { @@ -856,7 +862,7 @@ trait PaymentBehavior val updatedPaymentAccount = paymentAccount .withTransactions( paymentAccount.transactions.filterNot(_.id == transaction.id) - :+ transaction + :+ transaction.copy(clientId = clientId) ) .withLastUpdated(lastUpdated) val upsertedEvent = @@ -971,9 +977,11 @@ trait PaymentBehavior import cmd._ state match { case Some(paymentAccount) => - val clientId = paymentAccount.clientId.orElse( - internalClientId - ) + val clientId = paymentAccount.clientId + .orElse(cmd.clientId) + .orElse( + internalClientId + ) val paymentProvider = loadPaymentProvider(clientId) import paymentProvider._ paymentAccount.userId match { @@ -1002,7 +1010,7 @@ trait PaymentBehavior val updatedPaymentAccount = paymentAccount .withTransactions( paymentAccount.transactions.filterNot(_.id == transaction.id) - :+ transaction + :+ transaction.copy(clientId = clientId) ) .withLastUpdated(lastUpdated) if (transaction.status.isTransactionFailedForTechnicalReason) { @@ -1173,9 +1181,11 @@ trait PaymentBehavior import cmd._ state match { case Some(paymentAccount) => // debited account - val clientId = paymentAccount.clientId.orElse( - internalClientId - ) + val clientId = paymentAccount.clientId + .orElse(cmd.clientId) + .orElse( + internalClientId + ) val paymentProvider = loadPaymentProvider(clientId) import paymentProvider._ var maybeCreditedPaymentAccount: Option[PaymentAccount] = None @@ -1225,7 +1235,7 @@ trait PaymentBehavior val updatedPaymentAccount = paymentAccount .withTransactions( paymentAccount.transactions.filterNot(_.id == transaction.id) - :+ transaction + :+ transaction.copy(clientId = clientId) ) .withLastUpdated(lastUpdated) if ( @@ -1470,9 +1480,11 @@ trait PaymentBehavior paymentAccount.bankAccount.flatMap(_.mandateId) match { case Some(mandateId) => if (paymentAccount.mandateActivated) { - val clientId = paymentAccount.clientId.orElse( - internalClientId - ) + val clientId = paymentAccount.clientId + .orElse(cmd.clientId) + .orElse( + internalClientId + ) val paymentProvider = loadPaymentProvider(clientId) import paymentProvider._ directDebit( @@ -1495,7 +1507,7 @@ trait PaymentBehavior val updatedPaymentAccount = paymentAccount .withTransactions( paymentAccount.transactions.filterNot(_.id == transaction.id) - :+ transaction + :+ transaction.copy(clientId = clientId) ) .withLastUpdated(lastUpdated) if ( @@ -1565,9 +1577,11 @@ trait PaymentBehavior case Some(transaction) => paymentAccount.walletId match { case Some(creditedWalletId) => - val clientId = paymentAccount.clientId.orElse( - internalClientId - ) + val clientId = paymentAccount.clientId + .orElse(cmd.clientId) + .orElse( + internalClientId + ) val paymentProvider = loadPaymentProvider(clientId) import paymentProvider._ val transactionDate: LocalDate = Date.from(transaction.createdDate) @@ -1586,7 +1600,7 @@ trait PaymentBehavior val updatedPaymentAccount = paymentAccount .withTransactions( paymentAccount.transactions.filterNot(_.id == t.id) - :+ updatedTransaction + :+ updatedTransaction.copy(clientId = clientId) ) .withLastUpdated(lastUpdated) if (t.status.isTransactionSucceeded || t.status.isTransactionCreated) { @@ -3751,8 +3765,10 @@ trait PaymentBehavior val updatedTransaction = updatedPaymentAccount.transactions .find(_.id == preAuthorizationId) .map( - _.copy(preAuthorizationValidated = - Some(validatePreAuthorization(transaction.orderUuid, preAuthorizationId)) + _.copy( + preAuthorizationValidated = + Some(validatePreAuthorization(transaction.orderUuid, preAuthorizationId)), + clientId = clientId ) ) updatedPaymentAccount.withTransactions( @@ -3832,6 +3848,7 @@ trait PaymentBehavior .withTransactions( paymentAccount.transactions .filterNot(_.id == transaction.id) :+ transaction + .copy(clientId = paymentAccount.clientId) ) .withLastUpdated(lastUpdated) transaction.status match { diff --git a/core/src/main/scala/app/softnetwork/payment/service/BankAccountEndpoints.scala b/core/src/main/scala/app/softnetwork/payment/service/BankAccountEndpoints.scala index f2e0fc5..e14650a 100644 --- a/core/src/main/scala/app/softnetwork/payment/service/BankAccountEndpoints.scala +++ b/core/src/main/scala/app/softnetwork/payment/service/BankAccountEndpoints.scala @@ -26,8 +26,8 @@ trait BankAccountEndpoints[SD <: SessionData with SessionDataDecorator[SD]] { statusCode(StatusCode.Ok) .and(jsonBody[BankAccountCreatedOrUpdated].description("Bank account created or updated")) ) - .serverLogic { - case (client, session) => { bank => + .serverLogic { case (client, session) => + bank => import bank._ var externalUuid: String = "" val updatedUser: Option[PaymentAccount.User] = { @@ -78,7 +78,6 @@ trait BankAccountEndpoints[SD <: SessionData with SessionDataDecorator[SD]] { case r: BankAccountCreatedOrUpdated => Right(r) case other => Left(error(other)) } - } } .description("Create or update legal or natural user bank account") From 11aa7505eeb0997c96a725655fa1367a12992dc8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Manciot?= Date: Thu, 7 Dec 2023 13:48:32 +0100 Subject: [PATCH 23/37] keep client details when registering an existing provider --- .../payment/model/ProviderDecorator.scala | 3 ++- .../payment/persistence/typed/PaymentBehavior.scala | 6 +++++- .../typed/SoftPaymentAccountBehavior.scala | 13 +++++++++++-- 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/common/src/main/scala/app/softnetwork/payment/model/ProviderDecorator.scala b/common/src/main/scala/app/softnetwork/payment/model/ProviderDecorator.scala index a29567a..b44d1da 100644 --- a/common/src/main/scala/app/softnetwork/payment/model/ProviderDecorator.scala +++ b/common/src/main/scala/app/softnetwork/payment/model/ProviderDecorator.scala @@ -9,7 +9,8 @@ trait ProviderDecorator { self: SoftPaymentAccount.Client.Provider => lazy val client: SoftPaymentAccount.Client = { PaymentProviders.paymentProvider(self).client match { - case Some(value) => value.withClientApiKey(sha256(self.providerApiKey)) + case Some(client) => + client.withClientApiKey(sha256(self.providerApiKey)) case _ => throw new Exception(s"PaymentProvider not found for providerType: $providerType") } diff --git a/core/src/main/scala/app/softnetwork/payment/persistence/typed/PaymentBehavior.scala b/core/src/main/scala/app/softnetwork/payment/persistence/typed/PaymentBehavior.scala index 2075435..658a684 100644 --- a/core/src/main/scala/app/softnetwork/payment/persistence/typed/PaymentBehavior.scala +++ b/core/src/main/scala/app/softnetwork/payment/persistence/typed/PaymentBehavior.scala @@ -1794,7 +1794,11 @@ trait PaymentBehavior .withDebitedAmount(debitedAmount) .withFeesAmount(feesAmount) .withCurrency(currency) - .withStatementDescriptor(statementDescriptor.getOrElse("")) // TODO + .withStatementDescriptor( + statementDescriptor + .orElse(recurringPayment.statementDescriptor) + .getOrElse("") + ) // TODO ) match { case Some(transaction) => handleRecurringPayment( diff --git a/core/src/main/scala/app/softnetwork/payment/persistence/typed/SoftPaymentAccountBehavior.scala b/core/src/main/scala/app/softnetwork/payment/persistence/typed/SoftPaymentAccountBehavior.scala index 3f2b5eb..0ac5d18 100644 --- a/core/src/main/scala/app/softnetwork/payment/persistence/typed/SoftPaymentAccountBehavior.scala +++ b/core/src/main/scala/app/softnetwork/payment/persistence/typed/SoftPaymentAccountBehavior.scala @@ -86,14 +86,23 @@ trait SoftPaymentAccountBehavior extends AccountBehavior[SoftPaymentAccount, Bas case AccountMessages.RegisterProvider(provider) => state match { case Some(account) => - if (account.clients.exists(_.provider.providerId == provider.providerId)) { + if ( + account.clients.exists(cl => + cl.provider.providerId == provider.providerId && + cl.provider.providerApiKey == provider.providerApiKey + ) + ) { Effect.none.thenRun { _ => AccountMessages.ProviderAlreadyRegistered ~> replyTo } } else { PaymentProviders.paymentProvider(provider).client match { case Some(client) => - val updatedClient = client.withClientApiKey(client.generateApiKey()) + val updatedClient = + account.clients + .find(_.provider.providerId == provider.providerId) + .map(_.withProvider(provider)) + .getOrElse(client.withClientApiKey(client.generateApiKey())) accountKeyDao.addAccountKey(updatedClient.clientId, entityId) Effect .persist( From 65fda94716daba191fe2024e02d35178bff31db5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Manciot?= Date: Fri, 8 Dec 2023 01:39:17 +0100 Subject: [PATCH 24/37] add signup api --- client/src/main/protobuf/api/client.proto | 27 +++++++++ .../app/softnetwork/payment/api/Client.scala | 38 ++++++++++-- .../app/softnetwork/payment/cli/Command.scala | 3 +- .../app/softnetwork/payment/cli/Main.scala | 24 +++++++- .../payment/cli/signup/SignUpClient.scala | 35 +++++++++++ .../cli/signup/SignUpClientConfig.scala | 60 +++++++++++++++++++ .../payment/cli/tokens/Tokens.scala | 14 +++-- common/src/main/resources/reference.conf | 2 + .../payment/message/AccountMessages.scala | 2 +- .../payment/api/ClientServer.scala | 41 +++++++++++-- .../handlers/SoftPaymentAccountDao.scala | 42 ++++++++++--- .../typed/SoftPaymentAccountBehavior.scala | 12 +++- 12 files changed, 266 insertions(+), 34 deletions(-) create mode 100644 client/src/main/scala/app/softnetwork/payment/cli/signup/SignUpClient.scala create mode 100644 client/src/main/scala/app/softnetwork/payment/cli/signup/SignUpClientConfig.scala diff --git a/client/src/main/protobuf/api/client.proto b/client/src/main/protobuf/api/client.proto index de45ea3..5a9f387 100644 --- a/client/src/main/protobuf/api/client.proto +++ b/client/src/main/protobuf/api/client.proto @@ -11,10 +11,37 @@ option (scalapb.options) = { }; service ClientServiceApi { + rpc SignUpClient (SignUpClientRequest) returns (SignUpClientResponse) {} rpc GenerateClientTokens (GenerateClientTokensRequest) returns (ClientTokensResponse) {} rpc RefreshClientTokens (RefreshClientTokensRequest) returns (ClientTokensResponse) {} } +enum ProviderType { + MOCK = 0; + MANGOPAY = 1; +// STRIPE = 2; +} + +message SignUpClientRequest { + string principal = 1; + string credentials = 2; + string provider_id = 3; + string provider_api_key = 4; + ProviderType provider_type = 5; +} + +message ClientCreated { + string client_id = 1; + string client_secret = 2; +} + +message SignUpClientResponse { + oneof signup { + ClientCreated client = 1; + string error = 2; + } +} + message Tokens { string access_token = 1; string token_type = 2; diff --git a/client/src/main/scala/app/softnetwork/payment/api/Client.scala b/client/src/main/scala/app/softnetwork/payment/api/Client.scala index cdb4a6e..0dcf66f 100644 --- a/client/src/main/scala/app/softnetwork/payment/api/Client.scala +++ b/client/src/main/scala/app/softnetwork/payment/api/Client.scala @@ -18,7 +18,7 @@ trait Client extends GrpcClient { def generateClientTokens( scope: Option[String] = None - ): Future[Option[Tokens]] = { + ): Future[Either[String, Option[Tokens]]] = { import settings._ grpcClient .generateClientTokens() @@ -27,13 +27,13 @@ trait Client extends GrpcClient { ) map (response => response.clientTokens match { case r: ClientTokensResponse.ClientTokens.Tokens => - r.tokens - case _ => None + Right(r.tokens) + case error: ClientTokensResponse.ClientTokens.Error => Left(error.value) } ) } - def refreshClientTokens(refreshToken: String): Future[Option[Tokens]] = { + def refreshClientTokens(refreshToken: String): Future[Either[String, Option[Tokens]]] = { grpcClient .refreshClientTokens() .invoke( @@ -41,8 +41,34 @@ trait Client extends GrpcClient { ) map (response => response.clientTokens match { case r: ClientTokensResponse.ClientTokens.Tokens => - r.tokens - case _ => None + Right(r.tokens) + case error: ClientTokensResponse.ClientTokens.Error => Left(error.value) + } + ) + } + + def signUpClient( + principal: String, + credentials: Array[Char], + providerId: String, + providerApiKey: Array[Char], + providerType: Option[ProviderType] + ): Future[Either[String, Option[ClientCreated]]] = { + grpcClient + .signUpClient() + .invoke( + SignUpClientRequest( + principal, + credentials.mkString, + providerId, + providerApiKey.mkString, + providerType.getOrElse(ProviderType.MANGOPAY) + ) + ) map (response => + response.signup match { + case r: SignUpClientResponse.Signup.Client => + Right(r.client) + case error: SignUpClientResponse.Signup.Error => Left(error.value) } ) } diff --git a/client/src/main/scala/app/softnetwork/payment/cli/Command.scala b/client/src/main/scala/app/softnetwork/payment/cli/Command.scala index a67c1d6..de13be2 100644 --- a/client/src/main/scala/app/softnetwork/payment/cli/Command.scala +++ b/client/src/main/scala/app/softnetwork/payment/cli/Command.scala @@ -1,9 +1,8 @@ package app.softnetwork.payment.cli import akka.actor.typed.ActorSystem -import app.softnetwork.payment.api.PaymentClient -import scala.concurrent.{ExecutionContext, Future} +import scala.concurrent.Future trait Command[T] { diff --git a/client/src/main/scala/app/softnetwork/payment/cli/Main.scala b/client/src/main/scala/app/softnetwork/payment/cli/Main.scala index a72957b..088eefb 100644 --- a/client/src/main/scala/app/softnetwork/payment/cli/Main.scala +++ b/client/src/main/scala/app/softnetwork/payment/cli/Main.scala @@ -4,6 +4,7 @@ import akka.actor.typed.ActorSystem import akka.actor.typed.scaladsl.Behaviors import app.softnetwork.concurrent.Completion import app.softnetwork.payment.PaymentClientBuildInfo +import app.softnetwork.payment.cli.signup.{SignUpClient, SignUpClientConfig} import app.softnetwork.payment.cli.tokens.{Tokens, TokensConfig} import com.typesafe.scalalogging.StrictLogging @@ -19,6 +20,7 @@ object Main extends StrictLogging { class Main extends Completion with StrictLogging { val configs: List[CliConfig[_]] = List( + SignUpClientConfig, TokensConfig ) @@ -65,13 +67,29 @@ class Main extends Completion with StrictLogging { println(s"ERROR: Unknown command --> $command") printUsage() System.exit(1) - case Some(_) => + case Some(config) => command match { - case "tokens" => + case SignUpClientConfig.command => + SignUpClientConfig.parse(list) match { + case None => + println(s"ERROR: Invalid arguments for command --> $command") + printUsage(config.usage()) + System.exit(1) + case Some(conf) => + SignUpClient.run(conf) complete () match { + case Success(result) => + println(result) + System.exit(0) + case Failure(f) => + logger.error(s"Failed to run command $command", f) + System.exit(1) + } + } + case TokensConfig.command => TokensConfig.parse(list) match { case None => println(s"ERROR: Invalid arguments for command --> $command") - printUsage(command) + printUsage(config.usage()) System.exit(1) case Some(conf) => Tokens.run(conf) complete () match { diff --git a/client/src/main/scala/app/softnetwork/payment/cli/signup/SignUpClient.scala b/client/src/main/scala/app/softnetwork/payment/cli/signup/SignUpClient.scala new file mode 100644 index 0000000..aa697b6 --- /dev/null +++ b/client/src/main/scala/app/softnetwork/payment/cli/signup/SignUpClient.scala @@ -0,0 +1,35 @@ +package app.softnetwork.payment.cli.signup + +import akka.actor.typed.ActorSystem +import app.softnetwork.payment.api.Client +import app.softnetwork.payment.cli.Command +import org.json4s.Formats + +import scala.concurrent.{ExecutionContext, Future} + +object SignUpClient extends Command[SignUpClientConfig] { + override def run(config: SignUpClientConfig)(implicit system: ActorSystem[_]): Future[String] = { + implicit val ec: ExecutionContext = system.executionContext + val client = Client(system) + implicit val formats: Formats = org.json4s.DefaultFormats + client.signUpClient( + config.principal, + config.credentials, + config.providerId, + config.providerApiKey, + config.providerType + ) map { + case Right(client) => + val json = org.json4s.jackson.Serialization.writePretty(client) + s""" + |Client registered successfully! + |$json + |""".stripMargin + case Left(error) => + s""" + |Client registration failed! + |$error + |""".stripMargin + } + } +} diff --git a/client/src/main/scala/app/softnetwork/payment/cli/signup/SignUpClientConfig.scala b/client/src/main/scala/app/softnetwork/payment/cli/signup/SignUpClientConfig.scala new file mode 100644 index 0000000..78bc471 --- /dev/null +++ b/client/src/main/scala/app/softnetwork/payment/cli/signup/SignUpClientConfig.scala @@ -0,0 +1,60 @@ +package app.softnetwork.payment.cli.signup + +import app.softnetwork.payment.api.ProviderType +import app.softnetwork.payment.cli.{CliConfig, Command} +import scopt.OParser + +case class SignUpClientConfig( + principal: String = "", + credentials: Array[Char] = Array.emptyCharArray, + providerId: String = "", + providerApiKey: Array[Char] = Array.emptyCharArray, + providerType: Option[ProviderType] = None +) + +object SignUpClientConfig extends CliConfig[SignUpClientConfig] { + + val command: String = "signup" + + val parser: OParser[Unit, SignUpClientConfig] = { + val builder = OParser.builder[SignUpClientConfig] + import builder._ + OParser.sequence( + programName(s"payment $command"), + head("payment", command, "[options]"), + opt[String]('p', "principal") + .action((x, c) => c.copy(principal = x)) + .text("principal") + .required(), + opt[String]('c', "credentials") + .action((x, c) => c.copy(credentials = x.toCharArray)) + .text("credentials") + .required() + /*.validate(x => + import app.softnetwork.account.config.AccountSettings.passwordRules + passwordRules().validate(x) match { + case Right(_) => success + case Left(error) => failure(error.mkString(", ")) + } + )*/, + opt[String]('i', "providerId") + .action((x, c) => c.copy(providerId = x)) + .text("provider Id") + .required(), + opt[String]('k', "providerApiKey") + .action((x, c) => c.copy(providerApiKey = x.toCharArray)) + .text("provider Api Key") + .required(), + opt[String]('t', "providerType") + .action((x, c) => c.copy(providerType = ProviderType.fromName(x))) + .text("provider type") + .optional() + ) + } + + def parse(args: Seq[String]): Option[SignUpClientConfig] = { + OParser.parse(parser, args, SignUpClientConfig()) + } + + def runner: Command[SignUpClientConfig] = SignUpClient +} diff --git a/client/src/main/scala/app/softnetwork/payment/cli/tokens/Tokens.scala b/client/src/main/scala/app/softnetwork/payment/cli/tokens/Tokens.scala index 83312c3..e751eed 100644 --- a/client/src/main/scala/app/softnetwork/payment/cli/tokens/Tokens.scala +++ b/client/src/main/scala/app/softnetwork/payment/cli/tokens/Tokens.scala @@ -18,27 +18,31 @@ object Tokens extends Command[TokensConfig] with StrictLogging { config.refreshToken match { case Some(refreshToken) => client.refreshClientTokens(refreshToken) map { - case Some(tokens) => + case Right(tokens) => val json = org.json4s.jackson.Serialization.writePretty(tokens) s""" |Tokens refreshed successfully! |$json |""".stripMargin - case _ => + case Left(error) => s""" |Tokens refresh failed! + |$error |""".stripMargin } case None => client.generateClientTokens() map { - case Some(tokens) => + case Right(tokens) => val json = org.json4s.jackson.Serialization.writePretty(tokens) s""" |Tokens generated successfully! |$json |""".stripMargin - case _ => - "Tokens generation failed!" + case Left(error) => + s""" + |Tokens generation failed! + |$error + |""".stripMargin } } } diff --git a/common/src/main/resources/reference.conf b/common/src/main/resources/reference.conf index f96dd66..26a5119 100644 --- a/common/src/main/resources/reference.conf +++ b/common/src/main/resources/reference.conf @@ -41,6 +41,8 @@ payment{ } auth { + baseUrl = "http://localhost:"${softnetwork.api.server.port}"/"${softnetwork.api.server.root-path} + path = "account" realm = "SoftPayment" diff --git a/common/src/main/scala/app/softnetwork/payment/message/AccountMessages.scala b/common/src/main/scala/app/softnetwork/payment/message/AccountMessages.scala index bbf6ee5..209af7a 100644 --- a/common/src/main/scala/app/softnetwork/payment/message/AccountMessages.scala +++ b/common/src/main/scala/app/softnetwork/payment/message/AccountMessages.scala @@ -14,7 +14,7 @@ import app.softnetwork.persistence.message.EntityCommand import org.softnetwork.session.model.ApiKey object AccountMessages { - case class SoftPaymentSignup( + case class SoftPaymentSignUp( login: String, password: String, provider: SoftPaymentAccount.Client.Provider, diff --git a/core/src/main/scala/app/softnetwork/payment/api/ClientServer.scala b/core/src/main/scala/app/softnetwork/payment/api/ClientServer.scala index 756cfb8..2fd1136 100644 --- a/core/src/main/scala/app/softnetwork/payment/api/ClientServer.scala +++ b/core/src/main/scala/app/softnetwork/payment/api/ClientServer.scala @@ -2,6 +2,8 @@ package app.softnetwork.payment.api import akka.actor.typed.ActorSystem import app.softnetwork.payment.handlers.SoftPaymentAccountDao +import app.softnetwork.payment.message.AccountMessages +import app.softnetwork.payment.model.SoftPaymentAccount import org.slf4j.{Logger, LoggerFactory} import scala.concurrent.{ExecutionContextExecutor, Future} @@ -16,8 +18,8 @@ trait ClientServer extends ClientServiceApi with SoftPaymentAccountDao { in: GenerateClientTokensRequest ): Future[ClientTokensResponse] = { import in._ - generateClientToken(clientId, clientSecret, scope) map { - case Some(tokens) => + generateClientTokens(clientId, clientSecret, scope) map { + case Right(tokens) => import tokens._ ClientTokensResponse.defaultInstance.withTokens( Tokens( @@ -28,14 +30,14 @@ trait ClientServer extends ClientServiceApi with SoftPaymentAccountDao { refresh_token_expires_in.map(_.toLong) ) ) - case _ => ClientTokensResponse.defaultInstance.withError("unknown") + case Left(error) => ClientTokensResponse.defaultInstance.withError(error) } } override def refreshClientTokens(in: RefreshClientTokensRequest): Future[ClientTokensResponse] = { import in._ - refreshClientToken(refreshToken) map { - case Some(tokens) => + refreshClientTokens(refreshToken) map { + case Right(tokens) => import tokens._ ClientTokensResponse.defaultInstance.withTokens( Tokens( @@ -46,7 +48,34 @@ trait ClientServer extends ClientServiceApi with SoftPaymentAccountDao { refresh_token_expires_in.map(_.toLong) ) ) - case _ => ClientTokensResponse.defaultInstance.withError("unknown") + case Left(error) => ClientTokensResponse.defaultInstance.withError(error) + } + } + + override def signUpClient(in: SignUpClientRequest): Future[SignUpClientResponse] = { + import in._ + signUpClient( + AccountMessages.SoftPaymentSignUp( + principal, + credentials, + SoftPaymentAccount.Client.Provider( + providerId, + providerApiKey, + SoftPaymentAccount.Client.Provider.ProviderType + .fromName(providerType.name) + .getOrElse(SoftPaymentAccount.Client.Provider.ProviderType.MANGOPAY) + ) + ) + ) map { + case Right(client) => + import client._ + SignUpClientResponse.defaultInstance.withClient( + ClientCreated( + clientId, + clientApiKey.getOrElse("") + ) + ) + case Left(error) => SignUpClientResponse.defaultInstance.withError(error) } } } diff --git a/core/src/main/scala/app/softnetwork/payment/handlers/SoftPaymentAccountDao.scala b/core/src/main/scala/app/softnetwork/payment/handlers/SoftPaymentAccountDao.scala index f50aac7..68b472c 100644 --- a/core/src/main/scala/app/softnetwork/payment/handlers/SoftPaymentAccountDao.scala +++ b/core/src/main/scala/app/softnetwork/payment/handlers/SoftPaymentAccountDao.scala @@ -7,12 +7,15 @@ import app.softnetwork.account.message.{ AccessTokenGenerated, AccessTokenRefreshed, AccountCommand, + AccountCreated, + AccountErrorMessage, Tokens } import app.softnetwork.payment.annotation.InternalApi import app.softnetwork.payment.message.AccountMessages import app.softnetwork.payment.model.SoftPaymentAccount import app.softnetwork.payment.persistence.typed.SoftPaymentAccountBehavior +import app.softnetwork.persistence.generateUUID import app.softnetwork.persistence.typed.CommandTypeKey import app.softnetwork.session.model.JwtClaimsEncoder import com.softwaremill.session.SessionConfig @@ -53,16 +56,16 @@ trait SoftPaymentAccountDao extends AccountDao with SoftPaymentAccountHandler { } } - def generateClientToken( + def generateClientTokens( clientId: String, clientSecret: String, scope: Option[String] = None - )(implicit system: ActorSystem[_]): Future[Option[Tokens]] = { + )(implicit system: ActorSystem[_]): Future[Either[String, Tokens]] = { implicit val ec: ExecutionContext = system.executionContext ??(clientId, AccountMessages.GenerateClientToken(clientId, clientSecret, scope)) map { case result: AccessTokenGenerated => import result._ - Some( + Right( Tokens( accessToken.token, accessToken.tokenType.toLowerCase(), @@ -71,18 +74,19 @@ trait SoftPaymentAccountDao extends AccountDao with SoftPaymentAccountHandler { accessToken.refreshExpiresIn ) ) - case _ => None + case error: AccountErrorMessage => Left(error.message) + case _ => Left("unknown") } } - def refreshClientToken( + def refreshClientTokens( refreshToken: String - )(implicit system: ActorSystem[_]): Future[Option[Tokens]] = { + )(implicit system: ActorSystem[_]): Future[Either[String, Tokens]] = { implicit val ec: ExecutionContext = system.executionContext ??(refreshToken, AccountMessages.RefreshClientToken(refreshToken)) map { case result: AccessTokenRefreshed => import result._ - Some( + Right( Tokens( accessToken.token, accessToken.tokenType.toLowerCase(), @@ -91,7 +95,29 @@ trait SoftPaymentAccountDao extends AccountDao with SoftPaymentAccountHandler { accessToken.refreshExpiresIn ) ) - case _ => None + case error: AccountErrorMessage => Left(error.message) + case _ => Left("unknown") + } + } + + def signUpClient( + signUp: AccountMessages.SoftPaymentSignUp + )(implicit system: ActorSystem[_]): Future[Either[String, SoftPaymentAccount.Client]] = { + implicit val ec: ExecutionContext = system.executionContext + ??( + generateUUID(Some(signUp.login)), + signUp + ) map { + case result: AccountCreated => + Right( + result.account + .asInstanceOf[SoftPaymentAccount] + .clients + .find(_.provider.providerId == signUp.provider.providerId) + .get + ) + case error: AccountErrorMessage => Left(error.message) + case _ => Left("unknown") } } diff --git a/core/src/main/scala/app/softnetwork/payment/persistence/typed/SoftPaymentAccountBehavior.scala b/core/src/main/scala/app/softnetwork/payment/persistence/typed/SoftPaymentAccountBehavior.scala index 0ac5d18..29743cf 100644 --- a/core/src/main/scala/app/softnetwork/payment/persistence/typed/SoftPaymentAccountBehavior.scala +++ b/core/src/main/scala/app/softnetwork/payment/persistence/typed/SoftPaymentAccountBehavior.scala @@ -8,7 +8,7 @@ import app.softnetwork.account.message._ import app.softnetwork.account.model.{BasicAccount, BasicAccountProfile, Principal, PrincipalType} import app.softnetwork.account.persistence.typed.AccountBehavior import app.softnetwork.payment.message.AccountMessages -import app.softnetwork.payment.message.AccountMessages.SoftPaymentSignup +import app.softnetwork.payment.message.AccountMessages.SoftPaymentSignUp import app.softnetwork.payment.message.SoftPaymentAccountEvents.{ SoftPaymentAccountCreatedEvent, SoftPaymentAccountProviderRegisteredEvent, @@ -30,7 +30,7 @@ trait SoftPaymentAccountBehavior extends AccountBehavior[SoftPaymentAccount, Bas cmd: SignUp )(implicit context: ActorContext[AccountCommand]): Option[SoftPaymentAccount] = { cmd match { - case SoftPaymentSignup(_, _, provider, _, _) => + case SoftPaymentSignUp(_, _, provider, _, _) => PaymentProviders.paymentProvider(provider).client match { case Some(client) => SoftPaymentAccount(BasicAccount(cmd, Some(entityId))) @@ -89,12 +89,18 @@ trait SoftPaymentAccountBehavior extends AccountBehavior[SoftPaymentAccount, Bas if ( account.clients.exists(cl => cl.provider.providerId == provider.providerId && - cl.provider.providerApiKey == provider.providerApiKey + cl.provider.providerApiKey == provider.providerApiKey ) ) { Effect.none.thenRun { _ => AccountMessages.ProviderAlreadyRegistered ~> replyTo } + } else if ( + (accountKeyDao.lookupAccount(provider.clientId) complete ()).exists(_ != entityId) + ) { + Effect.none.thenRun { _ => + AccountMessages.ProviderAlreadyRegistered ~> replyTo + } } else { PaymentProviders.paymentProvider(provider).client match { case Some(client) => From 64ce0a0e790d97819b8f2d6d223254881585361d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Manciot?= Date: Fri, 8 Dec 2023 12:29:00 +0100 Subject: [PATCH 25/37] add activation api --- client/src/main/protobuf/api/client.proto | 12 ++++ client/src/main/resources/reference.conf | 2 +- .../app/softnetwork/payment/api/Client.scala | 13 +++++ .../api/config/PaymentClientSettings.scala | 16 +++++- .../app/softnetwork/payment/cli/Main.scala | 18 ++++++ .../payment/cli/activate/ActivateClient.scala | 26 +++++++++ .../cli/activate/ActivateClientConfig.scala | 30 ++++++++++ .../cli/signup/SignUpClientConfig.scala | 2 +- .../payment/message/AccountMessages.scala | 2 + .../snippets/account/inactive.mustache | 7 +++ .../payment/api/ClientServer.scala | 10 ++++ .../handlers/SoftPaymentAccountDao.scala | 13 +++++ .../typed/SoftPaymentAccountBehavior.scala | 55 +++++++++++++++++++ 13 files changed, 203 insertions(+), 3 deletions(-) create mode 100644 client/src/main/scala/app/softnetwork/payment/cli/activate/ActivateClient.scala create mode 100644 client/src/main/scala/app/softnetwork/payment/cli/activate/ActivateClientConfig.scala create mode 100644 core/src/main/resources/snippets/account/inactive.mustache diff --git a/client/src/main/protobuf/api/client.proto b/client/src/main/protobuf/api/client.proto index 5a9f387..d295c9f 100644 --- a/client/src/main/protobuf/api/client.proto +++ b/client/src/main/protobuf/api/client.proto @@ -12,6 +12,7 @@ option (scalapb.options) = { service ClientServiceApi { rpc SignUpClient (SignUpClientRequest) returns (SignUpClientResponse) {} + rpc ActivateClient (ActivateClientRequest) returns (ActivateClientResponse) {} rpc GenerateClientTokens (GenerateClientTokensRequest) returns (ClientTokensResponse) {} rpc RefreshClientTokens (RefreshClientTokensRequest) returns (ClientTokensResponse) {} } @@ -42,6 +43,17 @@ message SignUpClientResponse { } } +message ActivateClientRequest { + string token = 1; +} + +message ActivateClientResponse { + oneof activation { + bool activated = 1; + string error = 2; + } +} + message Tokens { string access_token = 1; string token_type = 2; diff --git a/client/src/main/resources/reference.conf b/client/src/main/resources/reference.conf index 16e3759..015b7e2 100644 --- a/client/src/main/resources/reference.conf +++ b/client/src/main/resources/reference.conf @@ -6,7 +6,7 @@ akka.http.session { } jwt { - iss = "softpayment" + iss = "soft-payment" include-iat = true } } diff --git a/client/src/main/scala/app/softnetwork/payment/api/Client.scala b/client/src/main/scala/app/softnetwork/payment/api/Client.scala index 0dcf66f..f5181c0 100644 --- a/client/src/main/scala/app/softnetwork/payment/api/Client.scala +++ b/client/src/main/scala/app/softnetwork/payment/api/Client.scala @@ -72,6 +72,19 @@ trait Client extends GrpcClient { } ) } + + def activateClient(token: String): Future[Either[String, Boolean]] = { + grpcClient + .activateClient() + .invoke( + ActivateClientRequest(token) + ) map (response => + response.activation match { + case r: ActivateClientResponse.Activation.Activated => Right(r.value) + case error: ActivateClientResponse.Activation.Error => Left(error.value) + } + ) + } } object Client extends GrpcClientFactory[Client] { diff --git a/client/src/main/scala/app/softnetwork/payment/api/config/PaymentClientSettings.scala b/client/src/main/scala/app/softnetwork/payment/api/config/PaymentClientSettings.scala index b696bfe..416cfa7 100644 --- a/client/src/main/scala/app/softnetwork/payment/api/config/PaymentClientSettings.scala +++ b/client/src/main/scala/app/softnetwork/payment/api/config/PaymentClientSettings.scala @@ -1,8 +1,11 @@ package app.softnetwork.payment.api.config import akka.actor.typed.ActorSystem +import com.typesafe.config.{Config, ConfigFactory} import org.softnetwork.session.model.JwtClaims +import java.nio.file.{Path, Paths} + case class PaymentClientSettings(clientId: String, apiKey: String) { def generateToken(): String = JwtClaims.newSession @@ -13,7 +16,18 @@ case class PaymentClientSettings(clientId: String, apiKey: String) { object PaymentClientSettings { def apply(system: ActorSystem[_]): PaymentClientSettings = { - val clientConfig = system.settings.config.getConfig("payment") + val softPaymentHome = + sys.env.getOrElse("SOFT_PAYMENT_HOME", System.getProperty("user.home") + "/soft-payment") + val clientConfigFile: Path = Paths.get(s"$softPaymentHome/config/application.conf") + val clientConfig: Config = { + if (clientConfigFile.toFile.exists()) { + ConfigFactory + .parseFile(clientConfigFile.toFile) + .withFallback(system.settings.config.getConfig("payment")) + } else { + system.settings.config.getConfig("payment") + } + } PaymentClientSettings( clientId = clientConfig.getString("client-id"), apiKey = clientConfig.getString("api-key") diff --git a/client/src/main/scala/app/softnetwork/payment/cli/Main.scala b/client/src/main/scala/app/softnetwork/payment/cli/Main.scala index 088eefb..17d1950 100644 --- a/client/src/main/scala/app/softnetwork/payment/cli/Main.scala +++ b/client/src/main/scala/app/softnetwork/payment/cli/Main.scala @@ -4,6 +4,7 @@ import akka.actor.typed.ActorSystem import akka.actor.typed.scaladsl.Behaviors import app.softnetwork.concurrent.Completion import app.softnetwork.payment.PaymentClientBuildInfo +import app.softnetwork.payment.cli.activate.{ActivateClient, ActivateClientConfig} import app.softnetwork.payment.cli.signup.{SignUpClient, SignUpClientConfig} import app.softnetwork.payment.cli.tokens.{Tokens, TokensConfig} import com.typesafe.scalalogging.StrictLogging @@ -21,6 +22,7 @@ object Main extends StrictLogging { class Main extends Completion with StrictLogging { val configs: List[CliConfig[_]] = List( SignUpClientConfig, + ActivateClientConfig, TokensConfig ) @@ -101,6 +103,22 @@ class Main extends Completion with StrictLogging { System.exit(1) } } + case ActivateClientConfig.command => + ActivateClientConfig.parse(list) match { + case None => + println(s"ERROR: Invalid arguments for command --> $command") + printUsage(config.usage()) + System.exit(1) + case Some(conf) => + ActivateClient.run(conf) complete () match { + case Success(result) => + println(result) + System.exit(0) + case Failure(f) => + logger.error(s"Failed to run command $command", f) + System.exit(1) + } + } case _ => println(s"ERROR: Unknown command --> $command") printUsage() diff --git a/client/src/main/scala/app/softnetwork/payment/cli/activate/ActivateClient.scala b/client/src/main/scala/app/softnetwork/payment/cli/activate/ActivateClient.scala new file mode 100644 index 0000000..e03726b --- /dev/null +++ b/client/src/main/scala/app/softnetwork/payment/cli/activate/ActivateClient.scala @@ -0,0 +1,26 @@ +package app.softnetwork.payment.cli.activate + +import akka.actor.typed.ActorSystem +import app.softnetwork.payment.api.Client +import app.softnetwork.payment.cli.Command + +import scala.concurrent.{ExecutionContext, Future} + +object ActivateClient extends Command[ActivateClientConfig] { + override def run( + config: ActivateClientConfig + )(implicit system: ActorSystem[_]): Future[String] = { + implicit val ec: ExecutionContext = system.executionContext + val client = Client(system) + client.activateClient(config.token) map { + case Right(activated) => + if (activated) "Client activated successfully!" + else "Client activation failed!" + case Left(error) => + s""" + |Client activation failed! + |$error + |""".stripMargin + } + } +} diff --git a/client/src/main/scala/app/softnetwork/payment/cli/activate/ActivateClientConfig.scala b/client/src/main/scala/app/softnetwork/payment/cli/activate/ActivateClientConfig.scala new file mode 100644 index 0000000..9ca87fb --- /dev/null +++ b/client/src/main/scala/app/softnetwork/payment/cli/activate/ActivateClientConfig.scala @@ -0,0 +1,30 @@ +package app.softnetwork.payment.cli.activate + +import app.softnetwork.payment.cli.{CliConfig, Command} +import scopt.OParser + +case class ActivateClientConfig(token: String = "") + +object ActivateClientConfig extends CliConfig[ActivateClientConfig] { + + val command: String = "activate" + + val parser: OParser[Unit, ActivateClientConfig] = { + val builder = OParser.builder[ActivateClientConfig] + import builder._ + OParser.sequence( + programName(s"payment $command"), + head("payment", command, "[options]"), + opt[String]('t', "token") + .action((x, c) => c.copy(token = x)) + .text("token") + .required() + ) + } + + def parse(args: Seq[String]): Option[ActivateClientConfig] = { + OParser.parse(parser, args, ActivateClientConfig()) + } + + def runner: Command[ActivateClientConfig] = ActivateClient +} diff --git a/client/src/main/scala/app/softnetwork/payment/cli/signup/SignUpClientConfig.scala b/client/src/main/scala/app/softnetwork/payment/cli/signup/SignUpClientConfig.scala index 78bc471..1bccc5f 100644 --- a/client/src/main/scala/app/softnetwork/payment/cli/signup/SignUpClientConfig.scala +++ b/client/src/main/scala/app/softnetwork/payment/cli/signup/SignUpClientConfig.scala @@ -30,7 +30,7 @@ object SignUpClientConfig extends CliConfig[SignUpClientConfig] { .action((x, c) => c.copy(credentials = x.toCharArray)) .text("credentials") .required() - /*.validate(x => + /*.validate(x => import app.softnetwork.account.config.AccountSettings.passwordRules passwordRules().validate(x) match { case Right(_) => success diff --git a/common/src/main/scala/app/softnetwork/payment/message/AccountMessages.scala b/common/src/main/scala/app/softnetwork/payment/message/AccountMessages.scala index 209af7a..3df053f 100644 --- a/common/src/main/scala/app/softnetwork/payment/message/AccountMessages.scala +++ b/common/src/main/scala/app/softnetwork/payment/message/AccountMessages.scala @@ -70,4 +70,6 @@ object AccountMessages { case object ClientNotFound extends AccountErrorMessage("client.not.found") case object ApiKeyNotFound extends AccountErrorMessage("api.key.not.found") + + case class InactiveAccount(help: String) extends AccountErrorMessage(s"InactiveAccount\n$help") } diff --git a/core/src/main/resources/snippets/account/inactive.mustache b/core/src/main/resources/snippets/account/inactive.mustache new file mode 100644 index 0000000..91bc4ab --- /dev/null +++ b/core/src/main/resources/snippets/account/inactive.mustache @@ -0,0 +1,7 @@ +Please activate your account ! + +Using the cli : +{{command}} + +Using the API : +curl -X GET {{activationUrl}} \ No newline at end of file diff --git a/core/src/main/scala/app/softnetwork/payment/api/ClientServer.scala b/core/src/main/scala/app/softnetwork/payment/api/ClientServer.scala index 2fd1136..a1f3751 100644 --- a/core/src/main/scala/app/softnetwork/payment/api/ClientServer.scala +++ b/core/src/main/scala/app/softnetwork/payment/api/ClientServer.scala @@ -1,6 +1,7 @@ package app.softnetwork.payment.api import akka.actor.typed.ActorSystem +import app.softnetwork.account.message.Activate import app.softnetwork.payment.handlers.SoftPaymentAccountDao import app.softnetwork.payment.message.AccountMessages import app.softnetwork.payment.model.SoftPaymentAccount @@ -78,6 +79,15 @@ trait ClientServer extends ClientServiceApi with SoftPaymentAccountDao { case Left(error) => SignUpClientResponse.defaultInstance.withError(error) } } + + override def activateClient(in: ActivateClientRequest): Future[ActivateClientResponse] = { + import in._ + activateClient(Activate(token)) map { + case Right(activated) => ActivateClientResponse.defaultInstance.withActivated(activated) + case Left(error) => + ActivateClientResponse.defaultInstance.withError(error) + } + } } object ClientServer { diff --git a/core/src/main/scala/app/softnetwork/payment/handlers/SoftPaymentAccountDao.scala b/core/src/main/scala/app/softnetwork/payment/handlers/SoftPaymentAccountDao.scala index 68b472c..d6cb7ef 100644 --- a/core/src/main/scala/app/softnetwork/payment/handlers/SoftPaymentAccountDao.scala +++ b/core/src/main/scala/app/softnetwork/payment/handlers/SoftPaymentAccountDao.scala @@ -6,9 +6,11 @@ import app.softnetwork.account.handlers.{AccountDao, AccountHandler} import app.softnetwork.account.message.{ AccessTokenGenerated, AccessTokenRefreshed, + AccountActivated, AccountCommand, AccountCreated, AccountErrorMessage, + Activate, Tokens } import app.softnetwork.payment.annotation.InternalApi @@ -121,6 +123,17 @@ trait SoftPaymentAccountDao extends AccountDao with SoftPaymentAccountHandler { } } + def activateClient( + activation: Activate + )(implicit system: ActorSystem[_]): Future[Either[String, Boolean]] = { + implicit val ec: ExecutionContext = system.executionContext + ??(activation.token, activation) map { + case result: AccountActivated => Right(result.account.status.isActive) + case error: AccountErrorMessage => Left(error.message) + case _ => Left("unknown") + } + } + def loadApiKey( clientId: String )(implicit system: ActorSystem[_]): Future[Option[ApiKey]] = { diff --git a/core/src/main/scala/app/softnetwork/payment/persistence/typed/SoftPaymentAccountBehavior.scala b/core/src/main/scala/app/softnetwork/payment/persistence/typed/SoftPaymentAccountBehavior.scala index 29743cf..1427566 100644 --- a/core/src/main/scala/app/softnetwork/payment/persistence/typed/SoftPaymentAccountBehavior.scala +++ b/core/src/main/scala/app/softnetwork/payment/persistence/typed/SoftPaymentAccountBehavior.scala @@ -3,10 +3,12 @@ package app.softnetwork.payment.persistence.typed import akka.actor.typed.{ActorRef, ActorSystem} import akka.actor.typed.scaladsl.{ActorContext, TimerScheduler} import akka.persistence.typed.scaladsl.Effect +import app.softnetwork.account.config.AccountSettings.{ActivationTokenExpirationTime, BaseUrl, Path} import app.softnetwork.account.handlers.{DefaultGenerator, Generator} import app.softnetwork.account.message._ import app.softnetwork.account.model.{BasicAccount, BasicAccountProfile, Principal, PrincipalType} import app.softnetwork.account.persistence.typed.AccountBehavior +import app.softnetwork.notification.message.ExternalEntityToNotificationEvent import app.softnetwork.payment.message.AccountMessages import app.softnetwork.payment.message.AccountMessages.SoftPaymentSignUp import app.softnetwork.payment.message.SoftPaymentAccountEvents.{ @@ -20,6 +22,8 @@ import app.softnetwork.payment.spi.PaymentProviders import app.softnetwork.persistence.typed._ import app.softnetwork.scheduler.message.SchedulerEvents.ExternalSchedulerEvent import app.softnetwork.security.sha256 +import mustache.Mustache +import org.slf4j.Logger import java.time.Instant @@ -230,6 +234,9 @@ trait SoftPaymentAccountBehavior extends AccountBehavior[SoftPaymentAccount, Bas } } + case Some(account) if !account.status.isActive => + inactiveAccount(entityId, account, replyTo) + case Some(account) if account.status.isDisabled => Effect.none.thenRun(_ => AccountDisabled ~> replyTo) @@ -283,6 +290,9 @@ trait SoftPaymentAccountBehavior extends AccountBehavior[SoftPaymentAccount, Bas } } + case Some(account) if !account.status.isActive => + inactiveAccount(entityId, account, replyTo) + case Some(account) if account.status.isDisabled => Effect.none.thenRun(_ => AccountDisabled ~> replyTo) @@ -399,6 +409,51 @@ trait SoftPaymentAccountBehavior extends AccountBehavior[SoftPaymentAccount, Bas } } + private def inactiveAccount( + entityId: String, + account: SoftPaymentAccount, + replyTo: Option[ActorRef[AccountCommandResult]] + )(implicit + context: ActorContext[_] + ): Effect[ExternalEntityToNotificationEvent, Option[SoftPaymentAccount]] = { + implicit val log: Logger = context.log + implicit val system: ActorSystem[Nothing] = context.system + def help(token: String): String = { + Mustache("snippets/account/inactive.mustache").render( + Map( + "command" -> s"payment activate -t $token", + "activationUrl" -> s"$BaseUrl/$Path/activate?token=$token" + ) + ) + } + account.verificationToken match { + case Some(v) => + if (v.expired) { + accountKeyDao.removeAccountKey(v.token) + val activationToken = generator.generateToken( + account.primaryPrincipal.value, + ActivationTokenExpirationTime + ) + accountKeyDao.addAccountKey(activationToken.token, entityId) + val notifications = sendActivation(entityId, account, activationToken) + Effect + .persist(notifications.toList) + .thenRun(_ => AccountMessages.InactiveAccount(help(activationToken.token)) ~> replyTo) + } else { + Effect.none.thenRun(_ => AccountMessages.InactiveAccount(help(v.token)) ~> replyTo) + } + case _ => + val activationToken = generator.generateToken( + account.primaryPrincipal.value, + ActivationTokenExpirationTime + ) + accountKeyDao.addAccountKey(activationToken.token, entityId) + val notifications = sendActivation(entityId, account, activationToken) + Effect + .persist(notifications.toList) + .thenRun(_ => AccountMessages.InactiveAccount(help(activationToken.token)) ~> replyTo) + } + } } case object SoftPaymentAccountBehavior extends SoftPaymentAccountBehavior with DefaultGenerator { From 7ff8f4c89dc6cce7eaa4b69ada37b5020609c9ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Manciot?= Date: Sat, 9 Dec 2023 07:22:16 +0100 Subject: [PATCH 26/37] add client packaging --- build.sbt | 2 +- client/build.sbt | 4 +++- .../payment/api/config/PaymentClientSettings.scala | 7 ++++--- .../softnetwork/payment/cli/CommandConfig.scala | 2 ++ .../scala/app/softnetwork/payment/cli/Main.scala | 11 ++++++++--- .../cli/activate/ActivateClientConfig.scala | 4 ++-- .../payment/cli/signup/SignUpClientConfig.scala | 14 +++++++------- .../payment/cli/tokens/TokensConfig.scala | 7 ++++--- .../payment/handlers/SoftPaymentAccountDao.scala | 4 ++-- .../typed/SoftPaymentAccountBehavior.scala | 3 ++- .../payment/api/PaymentGrpcServicesTestKit.scala | 9 ++++++++- 11 files changed, 43 insertions(+), 24 deletions(-) diff --git a/build.sbt b/build.sbt index fdf8182..8b32d31 100644 --- a/build.sbt +++ b/build.sbt @@ -32,7 +32,7 @@ Test / parallelExecution := false lazy val client = project.in(file("client")) .configs(IntegrationTest) .settings(Defaults.itSettings, app.softnetwork.Info.infoSettings) - .enablePlugins(BuildInfoPlugin, AkkaGrpcPlugin) + .enablePlugins(BuildInfoPlugin, AkkaGrpcPlugin, JavaAppPackaging) lazy val common = project.in(file("common")) .configs(IntegrationTest) diff --git a/client/build.sbt b/client/build.sbt index 1b75fab..ff8ccee 100644 --- a/client/build.sbt +++ b/client/build.sbt @@ -1,6 +1,6 @@ organization := "app.softnetwork.payment" -name := "payment-client" +name := "soft-payment" akkaGrpcGeneratedSources := Seq(AkkaGrpc.Client) @@ -22,3 +22,5 @@ libraryDependencies ++= Seq( "org.scalatra.scalate" %% "scalate-core" % Versions.scalate exclude ("org.scala-lang.modules", "scala-xml_2.12") exclude ("org.scala-lang.modules", "scala-parser-combinators_2.12"), "com.hubspot.jinjava" % "jinjava" % Versions.jinja excludeAll (jacksonExclusions *) exclude ("com.google.guava", "guava") exclude ("org.apache.commons", "commons-lang3") ) + +Compile / mainClass := Some("app.softnetwork.payment.cli.Main") diff --git a/client/src/main/scala/app/softnetwork/payment/api/config/PaymentClientSettings.scala b/client/src/main/scala/app/softnetwork/payment/api/config/PaymentClientSettings.scala index 416cfa7..7e81dec 100644 --- a/client/src/main/scala/app/softnetwork/payment/api/config/PaymentClientSettings.scala +++ b/client/src/main/scala/app/softnetwork/payment/api/config/PaymentClientSettings.scala @@ -19,13 +19,14 @@ object PaymentClientSettings { val softPaymentHome = sys.env.getOrElse("SOFT_PAYMENT_HOME", System.getProperty("user.home") + "/soft-payment") val clientConfigFile: Path = Paths.get(s"$softPaymentHome/config/application.conf") + val systemConfig = system.settings.config.getConfig("payment") val clientConfig: Config = { - if (clientConfigFile.toFile.exists()) { + if (clientConfigFile.toFile.exists() && !systemConfig.hasPath("test")) { ConfigFactory .parseFile(clientConfigFile.toFile) - .withFallback(system.settings.config.getConfig("payment")) + .withFallback(systemConfig) } else { - system.settings.config.getConfig("payment") + systemConfig } } PaymentClientSettings( diff --git a/client/src/main/scala/app/softnetwork/payment/cli/CommandConfig.scala b/client/src/main/scala/app/softnetwork/payment/cli/CommandConfig.scala index e5fb438..873a8c3 100644 --- a/client/src/main/scala/app/softnetwork/payment/cli/CommandConfig.scala +++ b/client/src/main/scala/app/softnetwork/payment/cli/CommandConfig.scala @@ -4,6 +4,8 @@ import scopt.OParser trait CommandConfig { def command: String + + def shell: String = Main.shell } trait CliConfig[T] extends CommandConfig { diff --git a/client/src/main/scala/app/softnetwork/payment/cli/Main.scala b/client/src/main/scala/app/softnetwork/payment/cli/Main.scala index 17d1950..43ab594 100644 --- a/client/src/main/scala/app/softnetwork/payment/cli/Main.scala +++ b/client/src/main/scala/app/softnetwork/payment/cli/Main.scala @@ -3,7 +3,7 @@ package app.softnetwork.payment.cli import akka.actor.typed.ActorSystem import akka.actor.typed.scaladsl.Behaviors import app.softnetwork.concurrent.Completion -import app.softnetwork.payment.PaymentClientBuildInfo +import app.softnetwork.payment.SoftPaymentBuildInfo import app.softnetwork.payment.cli.activate.{ActivateClient, ActivateClientConfig} import app.softnetwork.payment.cli.signup.{SignUpClient, SignUpClientConfig} import app.softnetwork.payment.cli.tokens.{Tokens, TokensConfig} @@ -13,6 +13,8 @@ import scala.util.{Failure, Success} object Main extends StrictLogging { + def shell: String = "soft-payment" + def main(args: Array[String]): Unit = { implicit def system: ActorSystem[_] = ActorSystem(Behaviors.empty, "PaymentClient") new Main().run(args) @@ -28,9 +30,9 @@ class Main extends Completion with StrictLogging { private def printUsage(): Unit = { // scalastyle:off println - println(s"Payment Version ${PaymentClientBuildInfo.version}") + println(s"SoftPayment Version ${SoftPaymentBuildInfo.version}") println("Usage:") - println("\tpayment [command]") + println(s"\t${Main.shell} [command]") println("Available commands =>") configs.foreach { config => println(s"\t${config.command}") @@ -56,6 +58,9 @@ class Main extends Completion with StrictLogging { case "help" :: command :: _ => printUsage(command) System.exit(0) + case command :: "help" :: Nil => + printUsage(command) + System.exit(0) case _ => } } diff --git a/client/src/main/scala/app/softnetwork/payment/cli/activate/ActivateClientConfig.scala b/client/src/main/scala/app/softnetwork/payment/cli/activate/ActivateClientConfig.scala index 9ca87fb..40db977 100644 --- a/client/src/main/scala/app/softnetwork/payment/cli/activate/ActivateClientConfig.scala +++ b/client/src/main/scala/app/softnetwork/payment/cli/activate/ActivateClientConfig.scala @@ -13,8 +13,8 @@ object ActivateClientConfig extends CliConfig[ActivateClientConfig] { val builder = OParser.builder[ActivateClientConfig] import builder._ OParser.sequence( - programName(s"payment $command"), - head("payment", command, "[options]"), + programName(s"$shell $command"), + head(shell, command, "[options]"), opt[String]('t', "token") .action((x, c) => c.copy(token = x)) .text("token") diff --git a/client/src/main/scala/app/softnetwork/payment/cli/signup/SignUpClientConfig.scala b/client/src/main/scala/app/softnetwork/payment/cli/signup/SignUpClientConfig.scala index 1bccc5f..44821c7 100644 --- a/client/src/main/scala/app/softnetwork/payment/cli/signup/SignUpClientConfig.scala +++ b/client/src/main/scala/app/softnetwork/payment/cli/signup/SignUpClientConfig.scala @@ -9,7 +9,7 @@ case class SignUpClientConfig( credentials: Array[Char] = Array.emptyCharArray, providerId: String = "", providerApiKey: Array[Char] = Array.emptyCharArray, - providerType: Option[ProviderType] = None + providerType: Option[ProviderType] = Some(ProviderType.MANGOPAY) ) object SignUpClientConfig extends CliConfig[SignUpClientConfig] { @@ -20,8 +20,8 @@ object SignUpClientConfig extends CliConfig[SignUpClientConfig] { val builder = OParser.builder[SignUpClientConfig] import builder._ OParser.sequence( - programName(s"payment $command"), - head("payment", command, "[options]"), + programName(s"$shell $command"), + head(shell, command, "[options]"), opt[String]('p', "principal") .action((x, c) => c.copy(principal = x)) .text("principal") @@ -39,15 +39,15 @@ object SignUpClientConfig extends CliConfig[SignUpClientConfig] { )*/, opt[String]('i', "providerId") .action((x, c) => c.copy(providerId = x)) - .text("provider Id") + .text("payment provider Id") .required(), opt[String]('k', "providerApiKey") .action((x, c) => c.copy(providerApiKey = x.toCharArray)) - .text("provider Api Key") + .text("payment provider Api Key") .required(), opt[String]('t', "providerType") - .action((x, c) => c.copy(providerType = ProviderType.fromName(x))) - .text("provider type") + .action((x, c) => c.copy(providerType = ProviderType.fromName(x.toUpperCase))) + .text("optional payment provider type - default is 'MangoPay'") .optional() ) } diff --git a/client/src/main/scala/app/softnetwork/payment/cli/tokens/TokensConfig.scala b/client/src/main/scala/app/softnetwork/payment/cli/tokens/TokensConfig.scala index 118e09b..049826c 100644 --- a/client/src/main/scala/app/softnetwork/payment/cli/tokens/TokensConfig.scala +++ b/client/src/main/scala/app/softnetwork/payment/cli/tokens/TokensConfig.scala @@ -15,11 +15,12 @@ object TokensConfig extends CliConfig[TokensConfig] { val builder = OParser.builder[TokensConfig] import builder._ OParser.sequence( - programName(s"payment $command"), - head("payment", command, "[options]"), + programName(s"$shell $command"), + head(shell, command, "[options]"), opt[String]('r', "refreshToken") .action((x, c) => c.copy(refreshToken = Some(x))) - .text("refresh token") + .text("optional refresh token") + .optional() ) } diff --git a/core/src/main/scala/app/softnetwork/payment/handlers/SoftPaymentAccountDao.scala b/core/src/main/scala/app/softnetwork/payment/handlers/SoftPaymentAccountDao.scala index d6cb7ef..0581bf7 100644 --- a/core/src/main/scala/app/softnetwork/payment/handlers/SoftPaymentAccountDao.scala +++ b/core/src/main/scala/app/softnetwork/payment/handlers/SoftPaymentAccountDao.scala @@ -183,8 +183,8 @@ trait SoftPaymentAccountDao extends AccountDao with SoftPaymentAccountHandler { .toOption match { case Some(result) if result.signatureMatches => loadClient(clientId) flatMap { - case Some(client) => Future.successful(Some(client)) - case _ => Future.successful(None) + case None => Future.successful(None) + case some => Future.successful(some) } case _ => Future.successful(None) } diff --git a/core/src/main/scala/app/softnetwork/payment/persistence/typed/SoftPaymentAccountBehavior.scala b/core/src/main/scala/app/softnetwork/payment/persistence/typed/SoftPaymentAccountBehavior.scala index 1427566..6df6b38 100644 --- a/core/src/main/scala/app/softnetwork/payment/persistence/typed/SoftPaymentAccountBehavior.scala +++ b/core/src/main/scala/app/softnetwork/payment/persistence/typed/SoftPaymentAccountBehavior.scala @@ -9,6 +9,7 @@ import app.softnetwork.account.message._ import app.softnetwork.account.model.{BasicAccount, BasicAccountProfile, Principal, PrincipalType} import app.softnetwork.account.persistence.typed.AccountBehavior import app.softnetwork.notification.message.ExternalEntityToNotificationEvent +import app.softnetwork.payment.cli.Main import app.softnetwork.payment.message.AccountMessages import app.softnetwork.payment.message.AccountMessages.SoftPaymentSignUp import app.softnetwork.payment.message.SoftPaymentAccountEvents.{ @@ -421,7 +422,7 @@ trait SoftPaymentAccountBehavior extends AccountBehavior[SoftPaymentAccount, Bas def help(token: String): String = { Mustache("snippets/account/inactive.mustache").render( Map( - "command" -> s"payment activate -t $token", + "command" -> s"${Main.shell} activate -t $token", "activationUrl" -> s"$BaseUrl/$Path/activate?token=$token" ) ) diff --git a/testkit/src/main/scala/app/softnetwork/payment/api/PaymentGrpcServicesTestKit.scala b/testkit/src/main/scala/app/softnetwork/payment/api/PaymentGrpcServicesTestKit.scala index b04fa67..7b26b62 100644 --- a/testkit/src/main/scala/app/softnetwork/payment/api/PaymentGrpcServicesTestKit.scala +++ b/testkit/src/main/scala/app/softnetwork/payment/api/PaymentGrpcServicesTestKit.scala @@ -16,14 +16,21 @@ trait PaymentGrpcServicesTestKit extends SchedulerGrpcServicesTestKit with Payme def paymentGrpcConfig: String = schedulerGrpcConfig + s""" |# Important: enable HTTP/2 in ActorSystem's config |akka.http.server.preview.enable-http2 = on + | + |akka.grpc.client."${Client.name}"{ + | host = $interface + | port = $port + | use-tls = false + |} + | |akka.grpc.client."${PaymentClient.name}"{ | host = $interface | port = $port | use-tls = false |} | + |payment.test = true |payment.client-id = "${settings.clientId}" - | |payment.api-key = "${settings.apiKey}" | |""".stripMargin From b5a5cef93bdfd180406e7b7abc116b5302bc73c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Manciot?= Date: Sat, 9 Dec 2023 10:19:30 +0100 Subject: [PATCH 27/37] update payment dao and server --- .../payment/api/PaymentServer.scala | 265 ++++++------------ .../payment/handlers/PaymentDao.scala | 250 +++++++++++++++-- .../handlers/SoftPaymentAccountDao.scala | 23 +- .../persistence/typed/PaymentBehavior.scala | 13 +- .../payment/api/MockPaymentServer.scala | 9 +- .../payment/handlers/MockPaymentDao.scala | 4 +- 6 files changed, 347 insertions(+), 217 deletions(-) diff --git a/core/src/main/scala/app/softnetwork/payment/api/PaymentServer.scala b/core/src/main/scala/app/softnetwork/payment/api/PaymentServer.scala index ecc78d9..1f3443d 100644 --- a/core/src/main/scala/app/softnetwork/payment/api/PaymentServer.scala +++ b/core/src/main/scala/app/softnetwork/payment/api/PaymentServer.scala @@ -2,47 +2,31 @@ package app.softnetwork.payment.api import akka.actor.typed.ActorSystem import app.softnetwork.payment.api.serialization._ -import app.softnetwork.payment.handlers.PaymentHandler +import app.softnetwork.payment.handlers.PaymentDao import app.softnetwork.payment.message.PaymentMessages.{ - BankAccountLoaded, - CancelMandate, - CancelPreAuthorization, CreateOrUpdatePaymentAccount, - DirectDebit, DirectDebitFailed, DirectDebited, - LoadBankAccount, - LoadDirectDebitTransaction, - LoadPaymentAccount, - MandateCanceled, PaidIn, PaidOut, - PayInFailed, - PayInWithCardPreAuthorized, - PayOut, PayOutFailed, PaymentAccountCreated, - PaymentAccountLoaded, PaymentAccountUpdated, - PaymentError, PreAuthorizationCanceled, RecurringPaymentRegistered, - Refund, RefundFailed, Refunded, - RegisterRecurringPayment, - Transfer, TransferFailed, Transferred } -import app.softnetwork.payment.model.RecurringPayment +import app.softnetwork.payment.model.{BankAccount, PaymentAccount, RecurringPayment} import app.softnetwork.payment.serialization._ import org.slf4j.{Logger, LoggerFactory} import scala.concurrent.{ExecutionContextExecutor, Future} import scala.language.implicitConversions -trait PaymentServer extends PaymentServiceApi with PaymentHandler { +trait PaymentServer extends PaymentServiceApi with PaymentDao { implicit def system: ActorSystem[_] implicit lazy val ec: ExecutionContextExecutor = system.executionContext @@ -65,30 +49,23 @@ trait PaymentServer extends PaymentServiceApi with PaymentHandler { in: PayInWithCardPreAuthorizedRequest ): Future[TransactionResponse] = { import in._ - !?( - PayInWithCardPreAuthorized(preAuthorizationId, creditedAccount, debitedAmount, Some(clientId)) + payInWithCardPreAuthorized( + preAuthorizationId, + creditedAccount, + debitedAmount, + Some(clientId) ) map { - case r: PaidIn => + case Right(r: PaidIn) => TransactionResponse( transactionId = Some(r.transactionId), transactionStatus = r.transactionStatus ) - case f: PayInFailed => + case Left(f) => TransactionResponse( - transactionId = Some(f.transactionId), + transactionId = if (f.transactionId.isEmpty) None else Some(f.transactionId), transactionStatus = f.transactionStatus, error = Some(f.message) ) - case e: PaymentError => - TransactionResponse( - transactionStatus = TransactionStatus.TRANSACTION_NOT_SPECIFIED, - error = Some(e.message) - ) - case _ => - TransactionResponse( - transactionStatus = TransactionStatus.TRANSACTION_NOT_SPECIFIED, - error = Some("unknown") - ) } } @@ -96,8 +73,8 @@ trait PaymentServer extends PaymentServiceApi with PaymentHandler { in: CancelPreAuthorizationRequest ): Future[CancelPreAuthorizationResponse] = { import in._ - !?(CancelPreAuthorization(orderUuid, cardPreAuthorizedTransactionId, Some(clientId))) map { - case r: PreAuthorizationCanceled => + cancelPreAuthorization(orderUuid, cardPreAuthorizedTransactionId, Some(clientId)) map { + case Right(r: PreAuthorizationCanceled) => CancelPreAuthorizationResponse(Some(r.preAuthorizationCanceled)) case _ => CancelPreAuthorizationResponse() } @@ -105,152 +82,104 @@ trait PaymentServer extends PaymentServiceApi with PaymentHandler { override def refund(in: RefundRequest): Future[TransactionResponse] = { import in._ - !?( - Refund( - orderUuid, - payInTransactionId, - refundAmount, - currency, - reasonMessage, - initializedByClient, - Some(clientId) - ) + refund( + orderUuid, + payInTransactionId, + refundAmount, + currency, + reasonMessage, + initializedByClient, + Some(clientId) ) map { - case r: Refunded => + case Right(r: Refunded) => TransactionResponse( transactionId = Some(r.transactionId), transactionStatus = r.transactionStatus ) - case f: RefundFailed => + case Left(f: RefundFailed) => TransactionResponse( - transactionId = Some(f.transactionId), + transactionId = if (f.transactionId.isEmpty) None else Some(f.transactionId), transactionStatus = f.transactionStatus, error = Some(f.message) ) - case e: PaymentError => - TransactionResponse( - transactionStatus = TransactionStatus.TRANSACTION_NOT_SPECIFIED, - error = Some(e.message) - ) - case _ => - TransactionResponse( - transactionStatus = TransactionStatus.TRANSACTION_NOT_SPECIFIED, - error = Some("unknown") - ) } } override def payOut(in: PayOutRequest): Future[TransactionResponse] = { import in._ - !?( - PayOut( - orderUuid, - creditedAccount, - creditedAmount, - feesAmount, - currency, - externalReference, - Some(clientId) - ) + payOut( + orderUuid, + creditedAccount, + creditedAmount, + feesAmount, + currency, + externalReference, + Some(clientId) ) map { - case r: PaidOut => + case Right(r: PaidOut) => TransactionResponse( transactionId = Some(r.transactionId), transactionStatus = r.transactionStatus ) - case f: PayOutFailed => + case Left(f: PayOutFailed) => TransactionResponse( - transactionId = Some(f.transactionId), + transactionId = if (f.transactionId.isEmpty) None else Some(f.transactionId), transactionStatus = f.transactionStatus, error = Some(f.message) ) - case e: PaymentError => - TransactionResponse( - transactionStatus = TransactionStatus.TRANSACTION_NOT_SPECIFIED, - error = Some(e.message) - ) - case _ => - TransactionResponse( - transactionStatus = TransactionStatus.TRANSACTION_NOT_SPECIFIED, - error = Some("unknown") - ) } } override def transfer(in: TransferRequest): Future[TransferResponse] = { import in._ - !?( - Transfer( - orderUuid, - debitedAccount, - creditedAccount, - debitedAmount, - feesAmount, - currency, - payOutRequired, - externalReference, - Some(clientId) - ) + transfer( + orderUuid, + debitedAccount, + creditedAccount, + debitedAmount, + feesAmount, + currency, + payOutRequired, + externalReference, + Some(clientId) ) map { - case r: Transferred => + case Right(r: Transferred) => TransferResponse( Some(r.transferredTransactionId), r.transferredTransactionStatus, r.paidOutTransactionId ) - case f: TransferFailed => + case Left(f: TransferFailed) => TransferResponse( - Some(f.transferredTransactionId), + if (f.transferredTransactionId.isEmpty) None else Some(f.transferredTransactionId), f.transferredTransactionStatus, error = Some(f.message) ) - case e: PaymentError => - TransferResponse( - transferredTransactionStatus = TransactionStatus.TRANSACTION_NOT_SPECIFIED, - error = Some(e.message) - ) - case _ => - TransferResponse( - transferredTransactionStatus = TransactionStatus.TRANSACTION_NOT_SPECIFIED, - error = Some("unknown") - ) } } override def directDebit(in: DirectDebitRequest): Future[TransactionResponse] = { import in._ - !?( - DirectDebit( - creditedAccount, - debitedAmount, - feesAmount, - currency, - statementDescriptor, - externalReference, - Some(clientId) - ) + directDebit( + creditedAccount, + debitedAmount, + feesAmount, + currency, + statementDescriptor, + externalReference, + Some(clientId) ) map { - case r: DirectDebited => + case Right(r: DirectDebited) => TransactionResponse( transactionId = Some(r.transactionId), transactionStatus = r.transactionStatus ) - case f: DirectDebitFailed => + case Left(f: DirectDebitFailed) => TransactionResponse( - transactionId = Some(f.transactionId), + transactionId = if (f.transactionId.isEmpty) None else Some(f.transactionId), transactionStatus = f.transactionStatus, error = Some(f.message) ) - case e: PaymentError => - TransactionResponse( - transactionStatus = TransactionStatus.TRANSACTION_NOT_SPECIFIED, - error = Some(e.message) - ) - case _ => - TransactionResponse( - transactionStatus = TransactionStatus.TRANSACTION_NOT_SPECIFIED, - error = Some("unknown") - ) } } @@ -258,28 +187,18 @@ trait PaymentServer extends PaymentServiceApi with PaymentHandler { in: LoadDirectDebitTransactionRequest ): Future[TransactionResponse] = { import in._ - !?(LoadDirectDebitTransaction(directDebitTransactionId, Some(clientId))) map { - case r: DirectDebited => + loadDirectDebitTransaction(directDebitTransactionId, Some(clientId)) map { + case Right(r: DirectDebited) => TransactionResponse( transactionId = Some(r.transactionId), transactionStatus = r.transactionStatus ) - case f: DirectDebitFailed => + case Left(f: DirectDebitFailed) => TransactionResponse( - transactionId = Some(f.transactionId), + transactionId = if (f.transactionId.isEmpty) None else Some(f.transactionId), transactionStatus = f.transactionStatus, error = Some(f.message) ) - case e: PaymentError => - TransactionResponse( - transactionStatus = TransactionStatus.TRANSACTION_NOT_SPECIFIED, - error = Some(e.message) - ) - case _ => - TransactionResponse( - transactionStatus = TransactionStatus.TRANSACTION_NOT_SPECIFIED, - error = Some("unknown") - ) } } @@ -289,26 +208,24 @@ trait PaymentServer extends PaymentServiceApi with PaymentHandler { import in._ val maybeType: Option[RecurringPayment.RecurringPaymentType] = `type` maybeType match { - case Some(atype) => - !?( - RegisterRecurringPayment( - debitedAccount, - firstDebitedAmount, - firstFeesAmount, - currency, - atype, - startDate, - endDate, - frequency, - fixedNextAmount, - nextDebitedAmount, - nextFeesAmount, - statementDescriptor, - externalReference, - Some(clientId) - ) + case Some(recurringPaymentType) => + registerRecurringPayment( + debitedAccount, + firstDebitedAmount, + firstFeesAmount, + currency, + recurringPaymentType, + startDate, + endDate, + frequency, + fixedNextAmount, + nextDebitedAmount, + nextFeesAmount, + statementDescriptor, + externalReference, + Some(clientId) ) map { - case r: RecurringPaymentRegistered => + case Right(r: RecurringPaymentRegistered) => RegisterRecurringPaymentResponse(Some(r.recurringPaymentRegistrationId)) case _ => RegisterRecurringPaymentResponse() } @@ -318,9 +235,9 @@ trait PaymentServer extends PaymentServiceApi with PaymentHandler { override def cancelMandate(in: CancelMandateRequest): Future[CancelMandateResponse] = { import in._ - !?(CancelMandate(externalUuid)) map { - case MandateCanceled => CancelMandateResponse(true) - case _ => CancelMandateResponse() + cancelMandate(externalUuid, Some(clientId)) map { + case Right(r) => CancelMandateResponse(r) + case Left(_) => CancelMandateResponse() } } @@ -328,9 +245,9 @@ trait PaymentServer extends PaymentServiceApi with PaymentHandler { in: LoadBankAccountOwnerRequest ): Future[LoadBankAccountOwnerResponse] = { import in._ - !?(LoadBankAccount(externalUuid, Some(clientId))) map { - case r: BankAccountLoaded => - LoadBankAccountOwnerResponse(r.bankAccount.ownerName, Some(r.bankAccount.ownerAddress)) + loadBankAccount(externalUuid, Some(clientId)) map { + case Some(r: BankAccount) => + LoadBankAccountOwnerResponse(r.ownerName, Some(r.ownerAddress)) case _ => LoadBankAccountOwnerResponse() } } @@ -339,9 +256,9 @@ trait PaymentServer extends PaymentServiceApi with PaymentHandler { in: LoadLegalUserRequest ): Future[LoadLegalUserResponse] = { import in._ - !?(LoadPaymentAccount(externalUuid, Some(clientId))) map { - case r: PaymentAccountLoaded if r.paymentAccount.user.isLegalUser => - val legalUser = r.paymentAccount.getLegalUser + loadPaymentAccount(externalUuid, Some(clientId)) map { + case Some(r: PaymentAccount) if r.user.isLegalUser => + val legalUser = r.getLegalUser LoadLegalUserResponse( legalUser.legalUserType, legalUser.legalName, @@ -349,8 +266,8 @@ trait PaymentServer extends PaymentServiceApi with PaymentHandler { Some(legalUser.legalRepresentativeAddress), Some(legalUser.headQuartersAddress) ) - case r: PaymentAccountLoaded if r.paymentAccount.bankAccount.isDefined => - val bankAccount = r.paymentAccount.getBankAccount + case Some(r: PaymentAccount) if r.bankAccount.isDefined => + val bankAccount = r.getBankAccount LoadLegalUserResponse( LegalUserType.SOLETRADER, bankAccount.ownerName, diff --git a/core/src/main/scala/app/softnetwork/payment/handlers/PaymentDao.scala b/core/src/main/scala/app/softnetwork/payment/handlers/PaymentDao.scala index 59ac1e1..b8018f4 100644 --- a/core/src/main/scala/app/softnetwork/payment/handlers/PaymentDao.scala +++ b/core/src/main/scala/app/softnetwork/payment/handlers/PaymentDao.scala @@ -3,7 +3,8 @@ package app.softnetwork.payment.handlers import akka.actor.typed.ActorSystem import akka.cluster.sharding.typed.scaladsl.EntityTypeKey import app.softnetwork.kv.handlers.GenericKeyValueDao -import app.softnetwork.payment.message.PaymentMessages._ +import app.softnetwork.payment.annotation.InternalApi +import app.softnetwork.payment.message.PaymentMessages.{MandateCanceled, _} import app.softnetwork.persistence.typed.scaladsl.EntityPattern import app.softnetwork.payment.model._ import app.softnetwork.payment.persistence.typed.PaymentBehavior @@ -11,6 +12,7 @@ import app.softnetwork.persistence._ import app.softnetwork.persistence.typed.CommandTypeKey import org.slf4j.{Logger, LoggerFactory} +import java.util.Date import scala.concurrent.{ExecutionContextExecutor, Future} import scala.language.implicitConversions import scala.reflect.ClassTag @@ -53,28 +55,49 @@ trait PaymentHandler extends EntityPattern[PaymentCommand, PaymentResult] with P } } -trait PaymentDao { _: PaymentHandler => +trait PaymentDao extends PaymentHandler { - protected[payment] def loadPaymentAccount( - key: String + @InternalApi + private[payment] def loadPaymentAccount( + key: String, + clientId: Option[String] )(implicit system: ActorSystem[_]): Future[Option[PaymentAccount]] = { implicit val ec: ExecutionContextExecutor = system.executionContext - !?(LoadPaymentAccount(key)) map { + !?(LoadPaymentAccount(key, clientId)) map { case result: PaymentAccountLoaded => Some(result.paymentAccount) case _ => None } } - def preRegisterCard(orderUuid: String, user: PaymentUser, currency: String = "EUR")(implicit - system: ActorSystem[_] - ): Future[Option[CardPreRegistration]] = { + @InternalApi + private[payment] def loadBankAccount( + externalUuid: String, + clientId: Option[String] = None + )(implicit system: ActorSystem[_]): Future[Option[BankAccount]] = { implicit val ec: ExecutionContextExecutor = system.executionContext - !?(PreRegisterCard(orderUuid, user, currency)) map { - case result: CardPreRegistered => Some(result.cardPreRegistration) + !?(LoadBankAccount(externalUuid, clientId)) map { + case result: BankAccountLoaded => Some(result.bankAccount) case _ => None } } + @InternalApi + private[payment] def preRegisterCard( + orderUuid: String, + user: PaymentUser, + currency: String = "EUR", + clientId: Option[String] = None + )(implicit + system: ActorSystem[_] + ): Future[Either[String, CardPreRegistration]] = { + implicit val ec: ExecutionContextExecutor = system.executionContext + !?(PreRegisterCard(orderUuid, user, currency, clientId)) map { + case result: CardPreRegistered => Right(result.cardPreRegistration) + case error: PaymentError => Left(error.message) + case _ => Left("unknown") + } + } + def payIn( orderUuid: String, debitedAccount: String, @@ -154,29 +177,53 @@ trait PaymentDao { _: PaymentHandler => } } - def payInWithCardPreAuthorized( + @InternalApi + private[payment] def cancelPreAuthorization( + orderUuid: String, + cardPreAuthorizedTransactionId: String, + clientId: Option[String] = None + )(implicit system: ActorSystem[_]): Future[Either[String, PreAuthorizationCanceled]] = { + implicit val ec: ExecutionContextExecutor = system.executionContext + !?(CancelPreAuthorization(orderUuid, cardPreAuthorizedTransactionId, clientId)) map { + case result: PreAuthorizationCanceled => Right(result) + case error: PaymentError => Left(error.message) + case _ => Left("unknown") + } + } + + @InternalApi + private[payment] def payInWithCardPreAuthorized( preAuthorizationId: String, creditedAccount: String, - debitedAmount: Option[Int] + debitedAmount: Option[Int], + clientId: Option[String] = None )(implicit system: ActorSystem[_] ): Future[Either[PayInFailed, PaidIn]] = { implicit val ec: ExecutionContextExecutor = system.executionContext - !?(PayInWithCardPreAuthorized(preAuthorizationId, creditedAccount, debitedAmount)) map { + !?( + PayInWithCardPreAuthorized(preAuthorizationId, creditedAccount, debitedAmount, clientId) + ) map { case result: PaidIn => Right(result) case error: PayInFailed => Left(error) + case error: PaymentError => + Left( + PayInFailed("", Transaction.TransactionStatus.TRANSACTION_NOT_SPECIFIED, error.message) + ) case _ => Left(PayInFailed("", Transaction.TransactionStatus.TRANSACTION_NOT_SPECIFIED, "unknown")) } } - def refund( + @InternalApi + private[payment] def refund( orderUuid: String, payInTransactionId: String, refundAmount: Int, currency: String = "EUR", reasonMessage: String, - initializedByClient: Boolean + initializedByClient: Boolean, + clientId: Option[String] = None )(implicit system: ActorSystem[_]): Future[Either[RefundFailed, Refunded]] = { implicit val ec: ExecutionContextExecutor = system.executionContext !?( @@ -186,44 +233,67 @@ trait PaymentDao { _: PaymentHandler => refundAmount, currency, reasonMessage, - initializedByClient + initializedByClient, + clientId ) ) map { case result: Refunded => Right(result) case error: RefundFailed => Left(error) + case error: PaymentError => + Left( + RefundFailed("", Transaction.TransactionStatus.TRANSACTION_NOT_SPECIFIED, error.message) + ) case _ => Left(RefundFailed("", Transaction.TransactionStatus.TRANSACTION_NOT_SPECIFIED, "unknown")) } } - def payOut( + @InternalApi + private[payment] def payOut( orderUuid: String, creditedAccount: String, creditedAmount: Int, feesAmount: Int, currency: String = "EUR", - externalReference: Option[String] + externalReference: Option[String], + clientId: Option[String] = None )(implicit system: ActorSystem[_] ): Future[Either[PayOutFailed, PaidOut]] = { implicit val ec: ExecutionContextExecutor = system.executionContext !?( - PayOut(orderUuid, creditedAccount, creditedAmount, feesAmount, currency, externalReference) + PayOut( + orderUuid, + creditedAccount, + creditedAmount, + feesAmount, + currency, + externalReference, + clientId + ) ) map { case result: PaidOut => Right(result) case error: PayOutFailed => Left(error) + case error: PaymentError => + Left( + PayOutFailed("", Transaction.TransactionStatus.TRANSACTION_NOT_SPECIFIED, error.message) + ) case _ => Left(PayOutFailed("", Transaction.TransactionStatus.TRANSACTION_NOT_SPECIFIED, "unknown")) } } - def transfer( + @InternalApi + private[payment] def transfer( orderUuid: Option[String] = None, debitedAccount: String, creditedAccount: String, debitedAmount: Int, feesAmount: Int = 0, - payOutRequired: Boolean = true + currency: String = "EUR", + payOutRequired: Boolean = true, + externalReference: Option[String] = None, + clientId: Option[String] = None )(implicit system: ActorSystem[_]): Future[Either[TransferFailed, Transferred]] = { implicit val ec: ExecutionContextExecutor = system.executionContext !?( @@ -233,17 +303,151 @@ trait PaymentDao { _: PaymentHandler => creditedAccount, debitedAmount, feesAmount, - payOutRequired + currency, + payOutRequired, + externalReference, + clientId ) ) map { case result: Transferred => Right(result) case error: TransferFailed => Left(error) + case error: PaymentError => + Left( + TransferFailed("", Transaction.TransactionStatus.TRANSACTION_NOT_SPECIFIED, error.message) + ) case _ => Left(TransferFailed("", Transaction.TransactionStatus.TRANSACTION_NOT_SPECIFIED, "unknown")) } } + + @InternalApi + private[payment] def cancelMandate( + creditedAccount: String, + clientId: Option[String] = None + )(implicit system: ActorSystem[_]): Future[Either[String, Boolean]] = { + implicit val ec: ExecutionContextExecutor = system.executionContext + !?(CancelMandate(creditedAccount, clientId)) map { + case MandateCanceled => Right(true) + case error: PaymentError => Left(error.message) + case _ => Left("unknown") + } + } + + @InternalApi + private[payment] def directDebit( + creditedAccount: String, + debitedAmount: Int, + feesAmount: Int = 0, + currency: String = "EUR", + statementDescriptor: String, + externalReference: Option[String] = None, + clientId: Option[String] = None + )(implicit + system: ActorSystem[_] + ): Future[Either[DirectDebitFailed, DirectDebited]] = { + implicit val ec: ExecutionContextExecutor = system.executionContext + !?( + DirectDebit( + creditedAccount, + debitedAmount, + feesAmount, + currency, + statementDescriptor, + externalReference, + clientId + ) + ) map { + case result: DirectDebited => Right(result) + case error: DirectDebitFailed => Left(error) + case error: PaymentError => + Left( + DirectDebitFailed( + "", + Transaction.TransactionStatus.TRANSACTION_NOT_SPECIFIED, + error.message + ) + ) + case _ => + Left( + DirectDebitFailed("", Transaction.TransactionStatus.TRANSACTION_NOT_SPECIFIED, "unknown") + ) + } + } + + @InternalApi + private[payment] def loadDirectDebitTransaction( + directDebitTransactionId: String, + clientId: Option[String] = None + )(implicit + system: ActorSystem[_] + ): Future[Either[DirectDebitFailed, DirectDebited]] = { + implicit val ec: ExecutionContextExecutor = system.executionContext + !?(LoadDirectDebitTransaction(directDebitTransactionId, clientId)) map { + case result: DirectDebited => Right(result) + case error: DirectDebitFailed => Left(error) + case error: PaymentError => + Left( + DirectDebitFailed( + "", + Transaction.TransactionStatus.TRANSACTION_NOT_SPECIFIED, + error.message + ) + ) + case _ => + Left( + DirectDebitFailed("", Transaction.TransactionStatus.TRANSACTION_NOT_SPECIFIED, "unknown") + ) + } + } + + @InternalApi + private[payment] def registerRecurringPayment( + debitedAccount: String, + firstDebitedAmount: Int, + firstFeesAmount: Int, + currency: String = "EUR", + `type`: RecurringPayment.RecurringPaymentType = RecurringPayment.RecurringPaymentType.CARD, + startDate: Option[Date] = None, + endDate: Option[Date] = None, + frequency: Option[RecurringPayment.RecurringPaymentFrequency] = None, + fixedNextAmount: Option[Boolean] = None, + nextDebitedAmount: Option[Int] = None, + nextFeesAmount: Option[Int] = None, + statementDescriptor: Option[String] = None, + externalReference: Option[String] = None, + clientId: Option[String] = None + )(implicit + system: ActorSystem[_] + ): Future[Either[String, RecurringPaymentRegistered]] = { + implicit val ec: ExecutionContextExecutor = system.executionContext + !?( + RegisterRecurringPayment( + debitedAccount, + firstDebitedAmount, + firstFeesAmount, + currency, + `type`, + startDate, + endDate, + frequency, + fixedNextAmount, + nextDebitedAmount, + nextFeesAmount, + statementDescriptor, + externalReference, + Some(clientId) + ) + ) map { + case result: RecurringPaymentRegistered => Right(result) + case error: PaymentError => Left(error.message) + case _ => + Left( + "unknown" + ) + } + } } -object PaymentDao extends PaymentDao with PaymentHandler { +object PaymentDao extends PaymentDao { lazy val log: Logger = LoggerFactory.getLogger(getClass.getName) } diff --git a/core/src/main/scala/app/softnetwork/payment/handlers/SoftPaymentAccountDao.scala b/core/src/main/scala/app/softnetwork/payment/handlers/SoftPaymentAccountDao.scala index 0581bf7..060b75a 100644 --- a/core/src/main/scala/app/softnetwork/payment/handlers/SoftPaymentAccountDao.scala +++ b/core/src/main/scala/app/softnetwork/payment/handlers/SoftPaymentAccountDao.scala @@ -58,7 +58,8 @@ trait SoftPaymentAccountDao extends AccountDao with SoftPaymentAccountHandler { } } - def generateClientTokens( + @InternalApi + private[payment] def generateClientTokens( clientId: String, clientSecret: String, scope: Option[String] = None @@ -81,7 +82,8 @@ trait SoftPaymentAccountDao extends AccountDao with SoftPaymentAccountHandler { } } - def refreshClientTokens( + @InternalApi + private[payment] def refreshClientTokens( refreshToken: String )(implicit system: ActorSystem[_]): Future[Either[String, Tokens]] = { implicit val ec: ExecutionContext = system.executionContext @@ -102,7 +104,8 @@ trait SoftPaymentAccountDao extends AccountDao with SoftPaymentAccountHandler { } } - def signUpClient( + @InternalApi + private[payment] def signUpClient( signUp: AccountMessages.SoftPaymentSignUp )(implicit system: ActorSystem[_]): Future[Either[String, SoftPaymentAccount.Client]] = { implicit val ec: ExecutionContext = system.executionContext @@ -123,7 +126,8 @@ trait SoftPaymentAccountDao extends AccountDao with SoftPaymentAccountHandler { } } - def activateClient( + @InternalApi + private[payment] def activateClient( activation: Activate )(implicit system: ActorSystem[_]): Future[Either[String, Boolean]] = { implicit val ec: ExecutionContext = system.executionContext @@ -134,7 +138,8 @@ trait SoftPaymentAccountDao extends AccountDao with SoftPaymentAccountHandler { } } - def loadApiKey( + @InternalApi + private[payment] def loadApiKey( clientId: String )(implicit system: ActorSystem[_]): Future[Option[ApiKey]] = { implicit val ec: ExecutionContext = system.executionContext @@ -144,8 +149,9 @@ trait SoftPaymentAccountDao extends AccountDao with SoftPaymentAccountHandler { } } - def registerProviderAccount(provider: SoftPaymentAccount.Client.Provider)(implicit - system: ActorSystem[_] + @InternalApi + private[payment] def registerProviderAccount(provider: SoftPaymentAccount.Client.Provider)( + implicit system: ActorSystem[_] ): Future[Option[SoftPaymentAccount]] = { implicit val ec: ExecutionContext = system.executionContext !?(AccountMessages.RegisterProviderAccount(provider)) map { @@ -154,7 +160,8 @@ trait SoftPaymentAccountDao extends AccountDao with SoftPaymentAccountHandler { } } - def authenticateClient( + @InternalApi + private[payment] def authenticateClient( token: Option[String] )(implicit system: ActorSystem[_]): Future[Option[SoftPaymentAccount.Client]] = { token match { diff --git a/core/src/main/scala/app/softnetwork/payment/persistence/typed/PaymentBehavior.scala b/core/src/main/scala/app/softnetwork/payment/persistence/typed/PaymentBehavior.scala index 658a684..fd38dbc 100644 --- a/core/src/main/scala/app/softnetwork/payment/persistence/typed/PaymentBehavior.scala +++ b/core/src/main/scala/app/softnetwork/payment/persistence/typed/PaymentBehavior.scala @@ -464,6 +464,11 @@ trait PaymentBehavior import cmd._ state match { case Some(paymentAccount) => + val clientId = paymentAccount.clientId + .orElse(cmd.clientId) + .orElse( + internalClientId + ) val maybeTransaction = paymentAccount.transactions.find(_.id == preAuthorizationId) maybeTransaction match { case None => @@ -516,7 +521,7 @@ trait PaymentBehavior ) case Some(preAuthorizationTransaction) => // load credited payment account - paymentDao.loadPaymentAccount(creditedAccount) complete () match { + paymentDao.loadPaymentAccount(creditedAccount, clientId) complete () match { case Success(s) => s match { case Some(creditedPaymentAccount) => @@ -611,7 +616,7 @@ trait PaymentBehavior }) match { case Some(cardId) => // load credited payment account - paymentDao.loadPaymentAccount(creditedAccount) complete () match { + paymentDao.loadPaymentAccount(creditedAccount, clientId) complete () match { case Success(s) => s match { case Some(creditedPaymentAccount) => @@ -687,7 +692,7 @@ trait PaymentBehavior paymentAccount.userId match { case Some(userId) => // load credited payment account - paymentDao.loadPaymentAccount(creditedAccount) complete () match { + paymentDao.loadPaymentAccount(creditedAccount, clientId) complete () match { case Success(s) => s match { case Some(creditedPaymentAccount) => @@ -1194,7 +1199,7 @@ trait PaymentBehavior paymentAccount.walletId match { case Some(debitedWalletId) => // load credited payment account - paymentDao.loadPaymentAccount(creditedAccount) complete () match { + paymentDao.loadPaymentAccount(creditedAccount, clientId) complete () match { case Success(s) => maybeCreditedPaymentAccount = s maybeCreditedPaymentAccount match { diff --git a/testkit/src/main/scala/app/softnetwork/payment/api/MockPaymentServer.scala b/testkit/src/main/scala/app/softnetwork/payment/api/MockPaymentServer.scala index 152b69d..39f4a43 100644 --- a/testkit/src/main/scala/app/softnetwork/payment/api/MockPaymentServer.scala +++ b/testkit/src/main/scala/app/softnetwork/payment/api/MockPaymentServer.scala @@ -1,15 +1,10 @@ package app.softnetwork.payment.api import akka.actor.typed.ActorSystem -import app.softnetwork.payment.handlers.{ - MockPaymentHandler, - MockPaymentTypeKey, - MockSoftPaymentAccountDao, - SoftPaymentAccountDao -} +import app.softnetwork.payment.handlers.MockPaymentDao import org.slf4j.{Logger, LoggerFactory} -trait MockPaymentServer extends PaymentServer with MockPaymentHandler +trait MockPaymentServer extends PaymentServer with MockPaymentDao object MockPaymentServer { def apply(sys: ActorSystem[_]): MockPaymentServer = { diff --git a/testkit/src/main/scala/app/softnetwork/payment/handlers/MockPaymentDao.scala b/testkit/src/main/scala/app/softnetwork/payment/handlers/MockPaymentDao.scala index 61bccaa..95bc3d6 100644 --- a/testkit/src/main/scala/app/softnetwork/payment/handlers/MockPaymentDao.scala +++ b/testkit/src/main/scala/app/softnetwork/payment/handlers/MockPaymentDao.scala @@ -2,6 +2,8 @@ package app.softnetwork.payment.handlers import org.slf4j.{Logger, LoggerFactory} -object MockPaymentDao extends PaymentDao with MockPaymentHandler { +trait MockPaymentDao extends PaymentDao with MockPaymentTypeKey + +object MockPaymentDao extends MockPaymentDao { lazy val log: Logger = LoggerFactory getLogger getClass.getName } From 67e005fead413a9a66e1b0b4f246003018549e9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Manciot?= Date: Mon, 11 Dec 2023 12:55:25 +0100 Subject: [PATCH 28/37] add clients command --- client/build.sbt | 2 +- .../app/softnetwork/payment/api/Client.scala | 8 +- .../payment/api/PaymentClient.scala | 4 +- .../payment/api/config/ApiKeys.scala | 48 ++++++++++++ .../api/config/PaymentClientSettings.scala | 37 --------- .../api/config/SoftPayClientSettings.scala | 73 +++++++++++++++++ .../app/softnetwork/payment/cli/Main.scala | 26 ++++++- .../payment/cli/clients/Clients.scala | 75 ++++++++++++++++++ .../payment/cli/clients/ClientsConfig.scala | 78 +++++++++++++++++++ .../payment/cli/signup/SignUpClient.scala | 2 + .../persistence/typed/PaymentBehavior.scala | 50 ++++++------ .../api/PaymentGrpcServicesTestKit.scala | 9 +-- ...stKit.scala => SoftPayClientTestKit.scala} | 11 ++- 13 files changed, 340 insertions(+), 83 deletions(-) create mode 100644 client/src/main/scala/app/softnetwork/payment/api/config/ApiKeys.scala delete mode 100644 client/src/main/scala/app/softnetwork/payment/api/config/PaymentClientSettings.scala create mode 100644 client/src/main/scala/app/softnetwork/payment/api/config/SoftPayClientSettings.scala create mode 100644 client/src/main/scala/app/softnetwork/payment/cli/clients/Clients.scala create mode 100644 client/src/main/scala/app/softnetwork/payment/cli/clients/ClientsConfig.scala rename testkit/src/main/scala/app/softnetwork/payment/api/{PaymentClientTestKit.scala => SoftPayClientTestKit.scala} (59%) diff --git a/client/build.sbt b/client/build.sbt index ff8ccee..ef49d88 100644 --- a/client/build.sbt +++ b/client/build.sbt @@ -1,6 +1,6 @@ organization := "app.softnetwork.payment" -name := "soft-payment" +name := "softpay" akkaGrpcGeneratedSources := Seq(AkkaGrpc.Client) diff --git a/client/src/main/scala/app/softnetwork/payment/api/Client.scala b/client/src/main/scala/app/softnetwork/payment/api/Client.scala index f5181c0..e657b1d 100644 --- a/client/src/main/scala/app/softnetwork/payment/api/Client.scala +++ b/client/src/main/scala/app/softnetwork/payment/api/Client.scala @@ -3,7 +3,7 @@ package app.softnetwork.payment.api import akka.actor.typed.ActorSystem import akka.grpc.GrpcClientSettings import app.softnetwork.api.server.client.{GrpcClient, GrpcClientFactory} -import app.softnetwork.payment.api.config.PaymentClientSettings +import app.softnetwork.payment.api.config.SoftPayClientSettings import scala.concurrent.Future @@ -14,7 +14,7 @@ trait Client extends GrpcClient { GrpcClientSettings.fromConfig(name) ) - lazy val settings: PaymentClientSettings = PaymentClientSettings(system) + lazy val settings: SoftPayClientSettings = SoftPayClientSettings(system) def generateClientTokens( scope: Option[String] = None @@ -53,7 +53,7 @@ trait Client extends GrpcClient { providerId: String, providerApiKey: Array[Char], providerType: Option[ProviderType] - ): Future[Either[String, Option[ClientCreated]]] = { + ): Future[Either[String, ClientCreated]] = { grpcClient .signUpClient() .invoke( @@ -67,7 +67,7 @@ trait Client extends GrpcClient { ) map (response => response.signup match { case r: SignUpClientResponse.Signup.Client => - Right(r.client) + Right(r.value) case error: SignUpClientResponse.Signup.Error => Left(error.value) } ) diff --git a/client/src/main/scala/app/softnetwork/payment/api/PaymentClient.scala b/client/src/main/scala/app/softnetwork/payment/api/PaymentClient.scala index 8a4e850..c25a828 100644 --- a/client/src/main/scala/app/softnetwork/payment/api/PaymentClient.scala +++ b/client/src/main/scala/app/softnetwork/payment/api/PaymentClient.scala @@ -4,7 +4,7 @@ import akka.actor.typed.ActorSystem import akka.grpc.GrpcClientSettings import akka.grpc.scaladsl.SingleResponseRequestBuilder import app.softnetwork.api.server.client.{GrpcClient, GrpcClientFactory} -import app.softnetwork.payment.api.config.PaymentClientSettings +import app.softnetwork.payment.api.config.SoftPayClientSettings import app.softnetwork.payment.api.serialization._ import app.softnetwork.payment.model.{ BankAccountOwner, @@ -22,7 +22,7 @@ trait PaymentClient extends GrpcClient { GrpcClientSettings.fromConfig(name) ) - lazy val settings: PaymentClientSettings = PaymentClientSettings(system) + lazy val settings: SoftPayClientSettings = SoftPayClientSettings(system) private lazy val generatedToken: String = settings.generateToken() diff --git a/client/src/main/scala/app/softnetwork/payment/api/config/ApiKeys.scala b/client/src/main/scala/app/softnetwork/payment/api/config/ApiKeys.scala new file mode 100644 index 0000000..122a1b3 --- /dev/null +++ b/client/src/main/scala/app/softnetwork/payment/api/config/ApiKeys.scala @@ -0,0 +1,48 @@ +package app.softnetwork.payment.api.config + +import java.nio.file.Paths + +object ApiKeys { + + private[this] lazy val filePath: String = { + val config = SoftPayClientSettings.SOFT_PAY_HOME + "/config" + Paths.get(config).toFile.mkdirs() + config + "/apiKeys.conf" + } + + private[this] def write(apiKeys: Map[String, String]): Unit = { + val file = Paths.get(filePath).toFile + file.createNewFile() + val apiKeysWriter = new java.io.BufferedWriter(new java.io.FileWriter(file)) + apiKeys.foreach { case (clientId, apiKey) => + apiKeysWriter.append( + s"""$clientId=$apiKey + |""".stripMargin + ) + } + apiKeysWriter.close() + } + + def list(): Map[String, String] = { + val file = Paths.get(filePath).toFile + file.createNewFile() + import scala.io.Source + val source = Source + .fromFile(filePath) + val apiKeys = + source.getLines + .filter(line => line.nonEmpty) + .map(line => line.split("=")) + .map { case Array(clientId, apiKey) => clientId.trim -> apiKey.trim } + .toMap + source.close() + apiKeys //.keys.map(clientId => ApiKey(clientId, Some(apiKeys(clientId)))).toSeq + } + + def +(clientId: String, apiKey: String): Unit = write(list() + (clientId -> apiKey)) + + def -(clientId: String): Unit = write(list() - clientId) + + def get(clientId: String): Option[String] = list().get(clientId) + +} diff --git a/client/src/main/scala/app/softnetwork/payment/api/config/PaymentClientSettings.scala b/client/src/main/scala/app/softnetwork/payment/api/config/PaymentClientSettings.scala deleted file mode 100644 index 7e81dec..0000000 --- a/client/src/main/scala/app/softnetwork/payment/api/config/PaymentClientSettings.scala +++ /dev/null @@ -1,37 +0,0 @@ -package app.softnetwork.payment.api.config - -import akka.actor.typed.ActorSystem -import com.typesafe.config.{Config, ConfigFactory} -import org.softnetwork.session.model.JwtClaims - -import java.nio.file.{Path, Paths} - -case class PaymentClientSettings(clientId: String, apiKey: String) { - def generateToken(): String = - JwtClaims.newSession - .withClientId(clientId) - .encode(clientId, apiKey) - -} - -object PaymentClientSettings { - def apply(system: ActorSystem[_]): PaymentClientSettings = { - val softPaymentHome = - sys.env.getOrElse("SOFT_PAYMENT_HOME", System.getProperty("user.home") + "/soft-payment") - val clientConfigFile: Path = Paths.get(s"$softPaymentHome/config/application.conf") - val systemConfig = system.settings.config.getConfig("payment") - val clientConfig: Config = { - if (clientConfigFile.toFile.exists() && !systemConfig.hasPath("test")) { - ConfigFactory - .parseFile(clientConfigFile.toFile) - .withFallback(systemConfig) - } else { - systemConfig - } - } - PaymentClientSettings( - clientId = clientConfig.getString("client-id"), - apiKey = clientConfig.getString("api-key") - ) - } -} diff --git a/client/src/main/scala/app/softnetwork/payment/api/config/SoftPayClientSettings.scala b/client/src/main/scala/app/softnetwork/payment/api/config/SoftPayClientSettings.scala new file mode 100644 index 0000000..73fea5a --- /dev/null +++ b/client/src/main/scala/app/softnetwork/payment/api/config/SoftPayClientSettings.scala @@ -0,0 +1,73 @@ +package app.softnetwork.payment.api.config + +import akka.actor.typed.ActorSystem +import com.typesafe.config.{Config, ConfigFactory} +import org.softnetwork.session.model.{ApiKey, JwtClaims} + +import java.nio.file.{Path, Paths} + +case class SoftPayClientSettings(clientId: String, apiKey: String) { + def generateToken(): String = + JwtClaims.newSession + .withClientId(clientId) + .encode(clientId, apiKey) + + def write(): Unit = { + ApiKeys.+(clientId, apiKey) + select() + } + + private[payment] def select(): Unit = { + val config = SoftPayClientSettings.SOFT_PAY_HOME + "/config" + Paths.get(config).toFile.mkdirs() + val application = Paths.get(config + "/application.conf").toFile + application.createNewFile() + val applicationWriter = new java.io.BufferedWriter(new java.io.FileWriter(application)) + applicationWriter.write( + s"""client-id = "$clientId" + |api-key = "$apiKey" + |""".stripMargin + ) + applicationWriter.close() + } + +} + +object SoftPayClientSettings { + lazy val SOFT_PAY_HOME: String = + sys.env.getOrElse( + "SOFT_PAY_HOME", + Option(System.getProperty("user.home") + "/soft-pay").getOrElse(".") + ) + + def apply(system: ActorSystem[_]): SoftPayClientSettings = { + val clientConfigFile: Path = Paths.get(s"$SOFT_PAY_HOME/config/application.conf") + val systemConfig = system.settings.config.getConfig("payment") + val clientConfig: Config = { + if ( + clientConfigFile.toFile + .exists() && (!systemConfig.hasPath("test") || !systemConfig.getBoolean("test")) + ) { + ConfigFactory + .parseFile(clientConfigFile.toFile) + .withFallback(systemConfig) + } else { + systemConfig + } + } + SoftPayClientSettings( + clientId = clientConfig.getString("client-id"), + apiKey = clientConfig.getString("api-key") + ) + } + + def select(clientId: String): Option[SoftPayClientSettings] = { + ApiKeys.list().get(clientId) match { + case Some(apiKey) => + val softPayClientSettings = SoftPayClientSettings(clientId, apiKey) + softPayClientSettings.select() + Some(softPayClientSettings) + case None => None + } + } +} diff --git a/client/src/main/scala/app/softnetwork/payment/cli/Main.scala b/client/src/main/scala/app/softnetwork/payment/cli/Main.scala index 43ab594..1ea719f 100644 --- a/client/src/main/scala/app/softnetwork/payment/cli/Main.scala +++ b/client/src/main/scala/app/softnetwork/payment/cli/Main.scala @@ -3,8 +3,9 @@ package app.softnetwork.payment.cli import akka.actor.typed.ActorSystem import akka.actor.typed.scaladsl.Behaviors import app.softnetwork.concurrent.Completion -import app.softnetwork.payment.SoftPaymentBuildInfo +import app.softnetwork.payment.SoftpayBuildInfo import app.softnetwork.payment.cli.activate.{ActivateClient, ActivateClientConfig} +import app.softnetwork.payment.cli.clients.{Clients, ClientsConfig} import app.softnetwork.payment.cli.signup.{SignUpClient, SignUpClientConfig} import app.softnetwork.payment.cli.tokens.{Tokens, TokensConfig} import com.typesafe.scalalogging.StrictLogging @@ -13,7 +14,7 @@ import scala.util.{Failure, Success} object Main extends StrictLogging { - def shell: String = "soft-payment" + def shell: String = "softpay" def main(args: Array[String]): Unit = { implicit def system: ActorSystem[_] = ActorSystem(Behaviors.empty, "PaymentClient") @@ -25,12 +26,13 @@ class Main extends Completion with StrictLogging { val configs: List[CliConfig[_]] = List( SignUpClientConfig, ActivateClientConfig, - TokensConfig + TokensConfig, + ClientsConfig ) private def printUsage(): Unit = { // scalastyle:off println - println(s"SoftPayment Version ${SoftPaymentBuildInfo.version}") + println(s"Softpay Version ${SoftpayBuildInfo.version}") println("Usage:") println(s"\t${Main.shell} [command]") println("Available commands =>") @@ -124,6 +126,22 @@ class Main extends Completion with StrictLogging { System.exit(1) } } + case ClientsConfig.command => + ClientsConfig.parse(list) match { + case None => + println(s"ERROR: Invalid arguments for command --> $command") + printUsage(config.usage()) + System.exit(1) + case Some(conf) => + Clients.run(conf) complete () match { + case Success(result) => + println(result) + System.exit(0) + case Failure(f) => + logger.error(s"Failed to run command $command", f) + System.exit(1) + } + } case _ => println(s"ERROR: Unknown command --> $command") printUsage() diff --git a/client/src/main/scala/app/softnetwork/payment/cli/clients/Clients.scala b/client/src/main/scala/app/softnetwork/payment/cli/clients/Clients.scala new file mode 100644 index 0000000..96a9247 --- /dev/null +++ b/client/src/main/scala/app/softnetwork/payment/cli/clients/Clients.scala @@ -0,0 +1,75 @@ +package app.softnetwork.payment.cli.clients + +import akka.actor.typed.ActorSystem +import app.softnetwork.payment.api.config.{ApiKeys, SoftPayClientSettings} +import app.softnetwork.payment.cli.Command + +import scala.concurrent.Future + +object Clients extends Command[ClientsConfig] { + override def run(config: ClientsConfig)(implicit system: ActorSystem[_]): Future[String] = { + config.subCommand match { + case ClientsSubCommand.List => + Future.successful( + s""" + |Available clients: + |\t${ApiKeys.list().filter(_._2.trim.nonEmpty).keys.mkString("\n\t")} + |""".stripMargin + ) + case ClientsSubCommand.Set => + config.clientId match { + case Some(clientId) => + Future.successful(SoftPayClientSettings.select(clientId) match { + case Some(softPayClientSettings) => + s""" + |Client $clientId selected successfully! + |\tapiKey: ${softPayClientSettings.apiKey} + |""".stripMargin + case None => + s""" + |apiKey not found for $clientId! + |""".stripMargin + }) + } + case ClientsSubCommand.Get => + config.clientId match { + case Some(clientId) => + Future.successful(ApiKeys.get(clientId) match { + case Some(apiKey) => + s""" + |Client $clientId loaded successfully! + |\tapiKey: $apiKey + |""".stripMargin + case None => + s""" + |apiKey not found for $clientId! + |""".stripMargin + }) + } + case ClientsSubCommand.Add => + config.clientId match { + case Some(clientId) => + ApiKeys.+(clientId, config.apiKey.getOrElse("")) match { + case _ => + Future.successful( + s""" + |Client $clientId added successfully! + |""".stripMargin + ) + } + } + case ClientsSubCommand.Remove => + config.clientId match { + case Some(clientId) => + ApiKeys.-(clientId) match { + case _ => + Future.successful( + s""" + |Client $clientId removed successfully! + |""".stripMargin + ) + } + } + } + } +} diff --git a/client/src/main/scala/app/softnetwork/payment/cli/clients/ClientsConfig.scala b/client/src/main/scala/app/softnetwork/payment/cli/clients/ClientsConfig.scala new file mode 100644 index 0000000..6332465 --- /dev/null +++ b/client/src/main/scala/app/softnetwork/payment/cli/clients/ClientsConfig.scala @@ -0,0 +1,78 @@ +package app.softnetwork.payment.cli.clients + +import app.softnetwork.payment.cli.{CliConfig, Command} +import scopt.OParser + +object ClientsSubCommand extends Enumeration { + type ClientsSubCommand = Value + val Empty, List, Get, Set, Add, Remove = Value +} + +case class ClientsConfig( + subCommand: ClientsSubCommand.Value = ClientsSubCommand.Empty, + clientId: Option[String] = None, + apiKey: Option[String] = None +) + +object ClientsConfig extends CliConfig[ClientsConfig] { + + val command: String = "clients" + + val parser: OParser[Unit, ClientsConfig] = { + val builder = OParser.builder[ClientsConfig] + import builder._ + OParser.sequence( + programName(s"$shell $command"), + head(shell, command, "[options]"), + cmd("list") + .action((_, c) => c.copy(subCommand = ClientsSubCommand.List)) + .text("list all clients"), + cmd("get") + .action((_, c) => c.copy(subCommand = ClientsSubCommand.Get)) + .text("get client by id") + .children( + opt[String]('i', "clientId") + .action((x, c) => c.copy(clientId = Some(x))) + .text("client Id") + .required() + ), + cmd("remove") + .action((_, c) => c.copy(subCommand = ClientsSubCommand.Remove)) + .text("remove client by id") + .children( + opt[String]('i', "clientId") + .action((x, c) => c.copy(clientId = Some(x))) + .text("client Id") + .required() + ), + cmd("add") + .action((_, c) => c.copy(subCommand = ClientsSubCommand.Add)) + .text("add api key") + .children( + opt[String]('i', "clientId") + .action((x, c) => c.copy(clientId = Some(x))) + .text("client Id") + .required(), + opt[String]('s', "apiKey") + .action((x, c) => c.copy(apiKey = Some(x))) + .text("api Key") + .required() + ), + cmd("set") + .action((_, c) => c.copy(subCommand = ClientsSubCommand.Set)) + .text("set client by id") + .children( + opt[String]('i', "clientId") + .action((x, c) => c.copy(clientId = Some(x))) + .text("client Id") + .required() + ) + ) + } + + def parse(args: Seq[String]): Option[ClientsConfig] = { + OParser.parse(parser, args, ClientsConfig()) + } + + def runner: Command[ClientsConfig] = Clients +} diff --git a/client/src/main/scala/app/softnetwork/payment/cli/signup/SignUpClient.scala b/client/src/main/scala/app/softnetwork/payment/cli/signup/SignUpClient.scala index aa697b6..8620940 100644 --- a/client/src/main/scala/app/softnetwork/payment/cli/signup/SignUpClient.scala +++ b/client/src/main/scala/app/softnetwork/payment/cli/signup/SignUpClient.scala @@ -2,6 +2,7 @@ package app.softnetwork.payment.cli.signup import akka.actor.typed.ActorSystem import app.softnetwork.payment.api.Client +import app.softnetwork.payment.api.config.SoftPayClientSettings import app.softnetwork.payment.cli.Command import org.json4s.Formats @@ -20,6 +21,7 @@ object SignUpClient extends Command[SignUpClientConfig] { config.providerType ) map { case Right(client) => + SoftPayClientSettings(client.clientId, client.clientSecret).write() val json = org.json4s.jackson.Serialization.writePretty(client) s""" |Client registered successfully! diff --git a/core/src/main/scala/app/softnetwork/payment/persistence/typed/PaymentBehavior.scala b/core/src/main/scala/app/softnetwork/payment/persistence/typed/PaymentBehavior.scala index fd38dbc..aee6162 100644 --- a/core/src/main/scala/app/softnetwork/payment/persistence/typed/PaymentBehavior.scala +++ b/core/src/main/scala/app/softnetwork/payment/persistence/typed/PaymentBehavior.scala @@ -6,7 +6,7 @@ import akka.cluster.sharding.typed.ShardingEnvelope import akka.persistence.typed.scaladsl.Effect import app.softnetwork.kv.handlers.GenericKeyValueDao import app.softnetwork.payment.annotation.InternalApi -import app.softnetwork.payment.api.config.PaymentClientSettings +import app.softnetwork.payment.api.config.SoftPayClientSettings import app.softnetwork.payment.config.PaymentSettings import app.softnetwork.payment.config.PaymentSettings.{AkkaNodeRole, PayInStatementDescriptor} import app.softnetwork.payment.handlers.{PaymentDao, PaymentKvDao, SoftPaymentAccountDao} @@ -111,8 +111,8 @@ trait PaymentBehavior ): Effect[ExternalSchedulerEvent, Option[PaymentAccount]] = { implicit val system: ActorSystem[_] = context.system implicit val log: Logger = context.log - implicit val paymentClientSettings: PaymentClientSettings = PaymentClientSettings(system) - val internalClientId = Option(paymentClientSettings.clientId) + implicit val softPayClientSettings: SoftPayClientSettings = SoftPayClientSettings(system) + val internalClientId = Option(softPayClientSettings.clientId) command match { case cmd: CreateOrUpdatePaymentAccount => @@ -201,9 +201,11 @@ trait PaymentBehavior var registerWallet: Boolean = false loadPaymentAccount(entityId, state, PaymentAccount.User.NaturalUser(user), clientId) match { case Some(paymentAccount) => - val clientId = paymentAccount.clientId.orElse( - internalClientId - ) + val clientId = paymentAccount.clientId + .orElse(cmd.clientId) + .orElse( + internalClientId + ) val paymentProvider = loadPaymentProvider(clientId) import paymentProvider._ val lastUpdated = now() @@ -228,7 +230,7 @@ trait PaymentBehavior }) match { case Some(walletId) => keyValueDao.addKeyValue(walletId, entityId) - val createOrUpdatePaymentAccount = + val paymentAccountUpsertedEvent = PaymentAccountUpsertedEvent.defaultInstance .withDocument( paymentAccount @@ -276,7 +278,7 @@ trait PaymentBehavior .withLastName(user.lastName) .withBirthday(user.birthday) ) - ) ++ walletEvents :+ createOrUpdatePaymentAccount + ) ++ walletEvents :+ paymentAccountUpsertedEvent ) .thenRun(_ => CardPreRegistered(cardPreRegistration) ~> replyTo) case _ => @@ -290,13 +292,13 @@ trait PaymentBehavior .withUserId(userId) .withWalletId(walletId) .withLastUpdated(lastUpdated) - ) :+ createOrUpdatePaymentAccount + ) :+ paymentAccountUpsertedEvent ) .thenRun(_ => CardNotPreRegistered ~> replyTo) } else { Effect .persist( - createOrUpdatePaymentAccount + paymentAccountUpsertedEvent ) .thenRun(_ => CardNotPreRegistered ~> replyTo) } @@ -870,7 +872,7 @@ trait PaymentBehavior :+ transaction.copy(clientId = clientId) ) .withLastUpdated(lastUpdated) - val upsertedEvent = + val paymentAccountUpsertedEvent = PaymentAccountUpsertedEvent.defaultInstance .withDocument(updatedPaymentAccount) .withLastUpdated(lastUpdated) @@ -889,7 +891,7 @@ trait PaymentBehavior .withOrderUuid(orderUuid) .withResultMessage(transaction.resultMessage) .withTransaction(transaction) - ) :+ upsertedEvent + ) :+ paymentAccountUpsertedEvent ) .thenRun(_ => RefundFailed( @@ -923,7 +925,7 @@ trait PaymentBehavior .withReasonMessage(reasonMessage) .withInitializedByClient(initializedByClient) .withPaymentType(transaction.paymentType) - ) :+ upsertedEvent + ) :+ paymentAccountUpsertedEvent ) .thenRun(_ => Refunded(transaction.id, transaction.status) ~> replyTo) } else { @@ -940,7 +942,7 @@ trait PaymentBehavior .withOrderUuid(orderUuid) .withResultMessage(transaction.resultMessage) .withTransaction(transaction) - ) :+ upsertedEvent + ) :+ paymentAccountUpsertedEvent ) .thenRun(_ => RefundFailed( @@ -3351,10 +3353,10 @@ trait PaymentBehavior bankAccountId: String )(implicit context: ActorContext[_], - paymentClientSettings: PaymentClientSettings + softPayClientSettings: SoftPayClientSettings ): Effect[ExternalSchedulerEvent, Option[PaymentAccount]] = { implicit val system: ActorSystem[_] = context.system - val clientId = paymentAccount.clientId.orElse(Option(paymentClientSettings.clientId)) + val clientId = paymentAccount.clientId.orElse(Option(softPayClientSettings.clientId)) val paymentProvider = loadPaymentProvider(clientId) import paymentProvider._ mandate(creditedAccount, creditedUserId, bankAccountId) match { @@ -3424,7 +3426,7 @@ trait PaymentBehavior )(implicit system: ActorSystem[_], log: Logger, - paymentClientSettings: PaymentClientSettings + softPayClientSettings: SoftPayClientSettings ): Option[PaymentAccount] = { val pa = PaymentAccount.defaultInstance.withUser(user).copy(clientId = clientId) val uuid = pa.externalUuidWithProfile @@ -3458,7 +3460,7 @@ trait PaymentBehavior paymentAccount.copy(clientId = paymentAccount.clientId .orElse(clientId) - .orElse(Option(paymentClientSettings.clientId)) + .orElse(Option(softPayClientSettings.clientId)) ) ) } @@ -3702,7 +3704,7 @@ trait PaymentBehavior )(implicit system: ActorSystem[_], log: Logger, - paymentClientSettings: PaymentClientSettings + softPayClientSettings: SoftPayClientSettings ): Effect[ExternalSchedulerEvent, Option[PaymentAccount]] = { keyValueDao.addKeyValue( transaction.id, @@ -3730,7 +3732,7 @@ trait PaymentBehavior if (transaction.status.isTransactionSucceeded || transaction.status.isTransactionCreated) { log.debug("Order-{} paid in: {} -> {}", orderUuid, transaction.id, asJson(transaction)) val clientId = paymentAccount.clientId.orElse( - Option(paymentClientSettings.clientId) + Option(softPayClientSettings.clientId) ) val paymentProvider = loadPaymentProvider(clientId) import paymentProvider._ @@ -3845,7 +3847,7 @@ trait PaymentBehavior )(implicit system: ActorSystem[_], log: Logger, - paymentClientSettings: PaymentClientSettings + softPayClientSettings: SoftPayClientSettings ): Effect[ExternalSchedulerEvent, Option[PaymentAccount]] = { keyValueDao.addKeyValue( transaction.id, @@ -3882,7 +3884,7 @@ trait PaymentBehavior transaction.id, asJson(transaction) ) - val clientId = paymentAccount.clientId.orElse(Option(paymentClientSettings.clientId)) + val clientId = paymentAccount.clientId.orElse(Option(softPayClientSettings.clientId)) val paymentProvider = loadPaymentProvider(clientId) import paymentProvider._ val registerCardEvents: List[ExternalSchedulerEvent] = @@ -3965,14 +3967,14 @@ trait PaymentBehavior maybeStatus: Option[KycDocument.KycDocumentStatus] = None )(implicit system: ActorSystem[_], - paymentClientSettings: PaymentClientSettings + softPayClientSettings: SoftPayClientSettings ): (KycDocumentValidationReport, List[ExternalSchedulerEvent]) = { var events: List[ExternalSchedulerEvent] = List.empty val lastUpdated = now() val userId = paymentAccount.userId.getOrElse("") - val clientId = paymentAccount.clientId.orElse(Option(paymentClientSettings.clientId)) + val clientId = paymentAccount.clientId.orElse(Option(softPayClientSettings.clientId)) val paymentProvider = loadPaymentProvider(clientId) import paymentProvider._ val report = loadDocumentStatus(userId, documentId) diff --git a/testkit/src/main/scala/app/softnetwork/payment/api/PaymentGrpcServicesTestKit.scala b/testkit/src/main/scala/app/softnetwork/payment/api/PaymentGrpcServicesTestKit.scala index 7b26b62..40735a8 100644 --- a/testkit/src/main/scala/app/softnetwork/payment/api/PaymentGrpcServicesTestKit.scala +++ b/testkit/src/main/scala/app/softnetwork/payment/api/PaymentGrpcServicesTestKit.scala @@ -7,7 +7,7 @@ import app.softnetwork.payment.launch.PaymentGuardian import app.softnetwork.scheduler.api.SchedulerGrpcServicesTestKit import app.softnetwork.scheduler.launch.SchedulerGuardian -trait PaymentGrpcServicesTestKit extends SchedulerGrpcServicesTestKit with PaymentClientTestKit { +trait PaymentGrpcServicesTestKit extends SchedulerGrpcServicesTestKit with SoftPayClientTestKit { _: PaymentGuardian with SchedulerGuardian with ServerTestKit => override def grpcServices: ActorSystem[_] => Seq[GrpcService] = system => @@ -28,10 +28,5 @@ trait PaymentGrpcServicesTestKit extends SchedulerGrpcServicesTestKit with Payme | port = $port | use-tls = false |} - | - |payment.test = true - |payment.client-id = "${settings.clientId}" - |payment.api-key = "${settings.apiKey}" - | - |""".stripMargin + |""".stripMargin + softPayClientSettings } diff --git a/testkit/src/main/scala/app/softnetwork/payment/api/PaymentClientTestKit.scala b/testkit/src/main/scala/app/softnetwork/payment/api/SoftPayClientTestKit.scala similarity index 59% rename from testkit/src/main/scala/app/softnetwork/payment/api/PaymentClientTestKit.scala rename to testkit/src/main/scala/app/softnetwork/payment/api/SoftPayClientTestKit.scala index 1d2678e..289d81b 100644 --- a/testkit/src/main/scala/app/softnetwork/payment/api/PaymentClientTestKit.scala +++ b/testkit/src/main/scala/app/softnetwork/payment/api/SoftPayClientTestKit.scala @@ -1,17 +1,20 @@ package app.softnetwork.payment.api -import app.softnetwork.payment.api.config.PaymentClientSettings import app.softnetwork.payment.config.MangoPay import app.softnetwork.payment.model.SoftPaymentAccount import app.softnetwork.security.sha256 -trait PaymentClientTestKit { +trait SoftPayClientTestKit { def provider: SoftPaymentAccount.Client.Provider = MangoPay.softPaymentProvider.withProviderType( SoftPaymentAccount.Client.Provider.ProviderType.MOCK ) - def settings: PaymentClientSettings = - PaymentClientSettings(provider.clientId, sha256(provider.providerApiKey)) + def softPayClientSettings: String = + s""" + |payment.test = true + |payment.client-id = "${provider.clientId}" + |payment.api-key = "${sha256(provider.providerApiKey)}" + |""".stripMargin } From d5d78263ddd729dabe0b4678a6032f64eea292f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Manciot?= Date: Mon, 11 Dec 2023 12:55:46 +0100 Subject: [PATCH 29/37] rename PaymentClientTestKit --- .../payment/scalatest/PaymentTestKit.scala | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentTestKit.scala b/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentTestKit.scala index d01c01b..de65dce 100644 --- a/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentTestKit.scala +++ b/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentTestKit.scala @@ -10,8 +10,8 @@ import app.softnetwork.payment.api.{ ClientServer, MockClientServer, MockPaymentServer, - PaymentClientTestKit, - PaymentServer + PaymentServer, + SoftPayClientTestKit } import app.softnetwork.payment.config.PaymentSettings._ import app.softnetwork.payment.handlers.{ @@ -51,7 +51,7 @@ trait PaymentTestKit extends SchedulerTestKit with PaymentGuardian with AllNotificationsTestKit - with PaymentClientTestKit { + with SoftPayClientTestKit { _: Suite => /** @return @@ -72,17 +72,12 @@ trait PaymentTestKit def loadApiKey(clientId: String): Future[Option[ApiKey]] = MockPaymentBehavior.softPaymentAccountDao.loadApiKey(clientId) - def clientId: String = settings.clientId + def clientId: String = provider.clientId override lazy val config: Config = akkaConfig .withFallback(ConfigFactory.load("softnetwork-in-memory-persistence.conf")) .withFallback( - ConfigFactory.parseString( - s""" - |payment.client-id = "$clientId" - |payment.api-key = "${settings.apiKey}" - |""".stripMargin - ) + ConfigFactory.parseString(softPayClientSettings) ) .withFallback(ConfigFactory.load()) From f1568394be5e0fe7be23d9cbaea73e5ddcad0a61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Manciot?= Date: Mon, 11 Dec 2023 17:14:14 +0100 Subject: [PATCH 30/37] rename PaymentUser to NaturalUser, PaymentUserType to NaturalUserType --- .../protobuf/model/payment/paymentUser.proto | 14 ++++----- .../api/config/SoftPayClientSettings.scala | 2 +- .../payment/model/LegalUserDecorator.scala | 2 +- ...anion.scala => NaturalUserCompanion.scala} | 6 ++-- ...rator.scala => NaturalUserDecorator.scala} | 16 +++++----- .../model/PaymentAccountDecorator.scala | 4 +-- .../payment/message/PaymentMessages.scala | 6 ++-- .../payment/serialization/package.scala | 4 +-- .../payment/spi/PaymentProvider.scala | 2 +- .../payment/handlers/PaymentDao.scala | 2 +- .../persistence/typed/PaymentBehavior.scala | 30 +++++++++---------- .../payment/spi/MangoPayProvider.scala | 12 ++++---- .../softnetwork/payment/data/package.scala | 6 ++-- .../payment/spi/MockMangoPayProvider.scala | 12 ++++---- .../payment/handlers/PaymentHandlerSpec.scala | 10 +++---- 15 files changed, 64 insertions(+), 64 deletions(-) rename client/src/main/scala/app/softnetwork/payment/model/{PaymentUserCompanion.scala => NaturalUserCompanion.scala} (84%) rename client/src/main/scala/app/softnetwork/payment/model/{PaymentUserDecorator.scala => NaturalUserDecorator.scala} (64%) diff --git a/client/src/main/protobuf/model/payment/paymentUser.proto b/client/src/main/protobuf/model/payment/paymentUser.proto index f14e8c6..777833b 100644 --- a/client/src/main/protobuf/model/payment/paymentUser.proto +++ b/client/src/main/protobuf/model/payment/paymentUser.proto @@ -57,14 +57,14 @@ message BankAccount { optional MandateScheme mandateScheme = 14 [default = MANDATE_SEPA]; } -message PaymentUser { - enum PaymentUserType { +message NaturalUser { + enum NaturalUserType { PAYER = 0; COLLECTOR = 1; } option (scalapb.message).extends = "ProtobufDomainObject"; - option (scalapb.message).extends = "PaymentUserDecorator"; - option (scalapb.message).companion_extends = "PaymentUserCompanion"; + option (scalapb.message).extends = "NaturalUserDecorator"; + option (scalapb.message).companion_extends = "NaturalUserCompanion"; required string firstName = 1; required string lastName = 2; required string email = 3; @@ -75,7 +75,7 @@ message PaymentUser { optional string walletId = 8; required string externalUuid = 9; optional string profile = 10; - optional PaymentUserType paymentUserType = 11; + optional NaturalUserType naturalUserType = 11; // optional string secondaryWalletId = 12; } @@ -90,7 +90,7 @@ message LegalUser { required LegalUserType legalUserType = 1; required string legalName = 2; required string siret = 3; - required PaymentUser legalRepresentative = 4; + required NaturalUser legalRepresentative = 4; required Address legalRepresentativeAddress = 5; required Address headQuartersAddress = 6; optional UboDeclaration uboDeclaration = 7; @@ -114,7 +114,7 @@ message PaymentAccount { required google.protobuf.Timestamp createdDate = 2 [(scalapb.field).type = "java.time.Instant"]; required google.protobuf.Timestamp lastUpdated = 3 [(scalapb.field).type = "java.time.Instant"]; oneof user { - PaymentUser naturalUser = 4; + NaturalUser naturalUser = 4; LegalUser legalUser = 5; } repeated Card cards = 6; diff --git a/client/src/main/scala/app/softnetwork/payment/api/config/SoftPayClientSettings.scala b/client/src/main/scala/app/softnetwork/payment/api/config/SoftPayClientSettings.scala index 73fea5a..dc25896 100644 --- a/client/src/main/scala/app/softnetwork/payment/api/config/SoftPayClientSettings.scala +++ b/client/src/main/scala/app/softnetwork/payment/api/config/SoftPayClientSettings.scala @@ -2,7 +2,7 @@ package app.softnetwork.payment.api.config import akka.actor.typed.ActorSystem import com.typesafe.config.{Config, ConfigFactory} -import org.softnetwork.session.model.{ApiKey, JwtClaims} +import org.softnetwork.session.model.JwtClaims import java.nio.file.{Path, Paths} diff --git a/client/src/main/scala/app/softnetwork/payment/model/LegalUserDecorator.scala b/client/src/main/scala/app/softnetwork/payment/model/LegalUserDecorator.scala index 6392125..e79ce85 100644 --- a/client/src/main/scala/app/softnetwork/payment/model/LegalUserDecorator.scala +++ b/client/src/main/scala/app/softnetwork/payment/model/LegalUserDecorator.scala @@ -28,7 +28,7 @@ case class LegalUserView( legalUserType: LegalUser.LegalUserType, legalName: String, siret: String, - legalRepresentative: PaymentUserView, + legalRepresentative: NaturalUserView, legalRepresentativeAddress: AddressView, headQuartersAddress: AddressView, uboDeclaration: Option[UboDeclarationView] = None, diff --git a/client/src/main/scala/app/softnetwork/payment/model/PaymentUserCompanion.scala b/client/src/main/scala/app/softnetwork/payment/model/NaturalUserCompanion.scala similarity index 84% rename from client/src/main/scala/app/softnetwork/payment/model/PaymentUserCompanion.scala rename to client/src/main/scala/app/softnetwork/payment/model/NaturalUserCompanion.scala index af51c35..95cefd6 100644 --- a/client/src/main/scala/app/softnetwork/payment/model/PaymentUserCompanion.scala +++ b/client/src/main/scala/app/softnetwork/payment/model/NaturalUserCompanion.scala @@ -1,6 +1,6 @@ package app.softnetwork.payment.model -trait PaymentUserCompanion { +trait NaturalUserCompanion { def apply( firstName: String, lastName: String, @@ -8,8 +8,8 @@ trait PaymentUserCompanion { nationality: Option[String], birthday: String, countryOfResidence: Option[String] - ): PaymentUser = { - PaymentUser.defaultInstance + ): NaturalUser = { + NaturalUser.defaultInstance .withFirstName(firstName) .withLastName(lastName) .withEmail(email) diff --git a/client/src/main/scala/app/softnetwork/payment/model/PaymentUserDecorator.scala b/client/src/main/scala/app/softnetwork/payment/model/NaturalUserDecorator.scala similarity index 64% rename from client/src/main/scala/app/softnetwork/payment/model/PaymentUserDecorator.scala rename to client/src/main/scala/app/softnetwork/payment/model/NaturalUserDecorator.scala index 237c11b..9d6e13c 100644 --- a/client/src/main/scala/app/softnetwork/payment/model/PaymentUserDecorator.scala +++ b/client/src/main/scala/app/softnetwork/payment/model/NaturalUserDecorator.scala @@ -2,13 +2,13 @@ package app.softnetwork.payment.model import app.softnetwork.payment.model -trait PaymentUserDecorator { self: PaymentUser => +trait NaturalUserDecorator { self: NaturalUser => lazy val externalUuidWithProfile: String = computeExternalUuidWithProfile(externalUuid, profile) - lazy val view: PaymentUserView = model.PaymentUserView(self) + lazy val view: NaturalUserView = NaturalUserView(self) } -case class PaymentUserView( +case class NaturalUserView( userId: Option[String] = None, firstName: String, lastName: String, @@ -18,13 +18,13 @@ case class PaymentUserView( countryOfResidence: String, externalUuid: String, profile: Option[String] = None, - paymentUserType: Option[PaymentUser.PaymentUserType] = None + naturalUserType: Option[NaturalUser.NaturalUserType] = None ) -object PaymentUserView { - def apply(paymentUser: PaymentUser): PaymentUserView = { +object NaturalUserView { + def apply(paymentUser: NaturalUser): NaturalUserView = { import paymentUser._ - PaymentUserView( + NaturalUserView( userId, firstName, lastName, @@ -34,7 +34,7 @@ object PaymentUserView { countryOfResidence, externalUuid, profile, - paymentUserType + naturalUserType ) } } diff --git a/client/src/main/scala/app/softnetwork/payment/model/PaymentAccountDecorator.scala b/client/src/main/scala/app/softnetwork/payment/model/PaymentAccountDecorator.scala index 5249ae8..6be0332 100644 --- a/client/src/main/scala/app/softnetwork/payment/model/PaymentAccountDecorator.scala +++ b/client/src/main/scala/app/softnetwork/payment/model/PaymentAccountDecorator.scala @@ -7,7 +7,7 @@ import java.time.Instant trait PaymentAccountDecorator { self: PaymentAccount => - lazy val maybeUser: Option[PaymentUser] = { + lazy val maybeUser: Option[NaturalUser] = { if (user.isLegalUser) { Some(getLegalUser.legalRepresentative) } else if (user.isNaturalUser) { @@ -116,7 +116,7 @@ trait PaymentAccountDecorator { self: PaymentAccount => case class PaymentAccountView( createdDate: Instant, lastUpdated: Instant, - naturalUser: Option[PaymentUserView] = None, + naturalUser: Option[NaturalUserView] = None, legalUser: Option[LegalUserView] = None, cards: Seq[CardView] = Seq.empty, bankAccount: Option[BankAccountView] = None, diff --git a/common/src/main/scala/app/softnetwork/payment/message/PaymentMessages.scala b/common/src/main/scala/app/softnetwork/payment/message/PaymentMessages.scala index 885d3bd..78a8dc8 100644 --- a/common/src/main/scala/app/softnetwork/payment/message/PaymentMessages.scala +++ b/common/src/main/scala/app/softnetwork/payment/message/PaymentMessages.scala @@ -32,7 +32,7 @@ object PaymentMessages { */ case class PreRegisterCard( orderUuid: String, - user: PaymentUser, + user: NaturalUser, currency: String = "EUR", clientId: Option[String] = None ) extends PaymentCommandWithKey { @@ -558,7 +558,7 @@ object PaymentMessages { case class BankAccountCommand( bankAccount: BankAccount, - user: Either[PaymentUser, LegalUser], + user: Either[NaturalUser, LegalUser], acceptedTermsOfPSP: Option[Boolean] = None ) @@ -566,7 +566,7 @@ object PaymentMessages { def apply( bankAccount: BankAccount, - naturalUser: PaymentUser, + naturalUser: NaturalUser, acceptedTermsOfPSP: Option[Boolean] ): BankAccountCommand = BankAccountCommand(bankAccount, Left(naturalUser), acceptedTermsOfPSP) diff --git a/common/src/main/scala/app/softnetwork/payment/serialization/package.scala b/common/src/main/scala/app/softnetwork/payment/serialization/package.scala index 9de45f3..7284478 100644 --- a/common/src/main/scala/app/softnetwork/payment/serialization/package.scala +++ b/common/src/main/scala/app/softnetwork/payment/serialization/package.scala @@ -5,7 +5,7 @@ import app.softnetwork.protobuf.ScalaPBSerializers import ScalaPBSerializers.GeneratedEnumSerializer import app.softnetwork.account.model.Account import app.softnetwork.account.serialization.accountFormats -import app.softnetwork.payment.api.{LegalUserType, TransactionStatus} +import app.softnetwork.payment.api.TransactionStatus import org.json4s.Formats import scala.language.implicitConversions @@ -20,7 +20,7 @@ package object serialization { GeneratedEnumSerializer(KycDocument.KycDocumentType.enumCompanion), GeneratedEnumSerializer(UboDeclaration.UboDeclarationStatus.enumCompanion), GeneratedEnumSerializer(Transaction.PaymentType.enumCompanion), - GeneratedEnumSerializer(PaymentUser.PaymentUserType.enumCompanion), + GeneratedEnumSerializer(NaturalUser.NaturalUserType.enumCompanion), GeneratedEnumSerializer(LegalUser.LegalUserType.enumCompanion), GeneratedEnumSerializer(PaymentAccount.PaymentAccountStatus.enumCompanion), GeneratedEnumSerializer(BankAccount.MandateStatus.enumCompanion), diff --git a/common/src/main/scala/app/softnetwork/payment/spi/PaymentProvider.scala b/common/src/main/scala/app/softnetwork/payment/spi/PaymentProvider.scala index 8faff45..281ec60 100644 --- a/common/src/main/scala/app/softnetwork/payment/spi/PaymentProvider.scala +++ b/common/src/main/scala/app/softnetwork/payment/spi/PaymentProvider.scala @@ -39,7 +39,7 @@ private[payment] trait PaymentProvider { * @return * provider user id */ - def createOrUpdateNaturalUser(maybeNaturalUser: Option[PaymentUser]): Option[String] + def createOrUpdateNaturalUser(maybeNaturalUser: Option[NaturalUser]): Option[String] /** @param maybeLegalUser * - legal user to create diff --git a/core/src/main/scala/app/softnetwork/payment/handlers/PaymentDao.scala b/core/src/main/scala/app/softnetwork/payment/handlers/PaymentDao.scala index b8018f4..a379c18 100644 --- a/core/src/main/scala/app/softnetwork/payment/handlers/PaymentDao.scala +++ b/core/src/main/scala/app/softnetwork/payment/handlers/PaymentDao.scala @@ -84,7 +84,7 @@ trait PaymentDao extends PaymentHandler { @InternalApi private[payment] def preRegisterCard( orderUuid: String, - user: PaymentUser, + user: NaturalUser, currency: String = "EUR", clientId: Option[String] = None )(implicit diff --git a/core/src/main/scala/app/softnetwork/payment/persistence/typed/PaymentBehavior.scala b/core/src/main/scala/app/softnetwork/payment/persistence/typed/PaymentBehavior.scala index aee6162..4331646 100644 --- a/core/src/main/scala/app/softnetwork/payment/persistence/typed/PaymentBehavior.scala +++ b/core/src/main/scala/app/softnetwork/payment/persistence/typed/PaymentBehavior.scala @@ -14,7 +14,7 @@ import app.softnetwork.payment.message.PaymentEvents._ import app.softnetwork.payment.message.PaymentMessages._ import app.softnetwork.payment.message.TransactionEvents._ import app.softnetwork.payment.model.LegalUser.LegalUserType -import app.softnetwork.payment.model.PaymentUser.PaymentUserType +import app.softnetwork.payment.model.NaturalUser.NaturalUserType import app.softnetwork.payment.model._ import app.softnetwork.payment.spi._ import app.softnetwork.persistence._ @@ -214,7 +214,7 @@ trait PaymentBehavior createOrUpdatePaymentAccount( Some( paymentAccount.withNaturalUser( - user.withPaymentUserType(PaymentUserType.PAYER) + user.withNaturalUserType(NaturalUserType.PAYER) ) ) ) @@ -240,7 +240,7 @@ trait PaymentBehavior user .withUserId(userId) .withWalletId(walletId) - .withPaymentUserType(PaymentUserType.PAYER) + .withNaturalUserType(NaturalUserType.PAYER) ) ) .withLastUpdated(lastUpdated) @@ -311,7 +311,7 @@ trait PaymentBehavior paymentAccount .copy( user = PaymentAccount.User.NaturalUser( - user.withUserId(userId).withPaymentUserType(PaymentUserType.PAYER) + user.withUserId(userId).withNaturalUserType(NaturalUserType.PAYER) ) ) .withLastUpdated(lastUpdated) @@ -327,7 +327,7 @@ trait PaymentBehavior .withDocument( paymentAccount .withNaturalUser( - user.withPaymentUserType(PaymentUserType.PAYER) + user.withNaturalUserType(NaturalUserType.PAYER) ) .withLastUpdated(lastUpdated) ) @@ -1998,9 +1998,9 @@ trait PaymentBehavior userId = previousLegalUser.legalRepresentative.userId, walletId = previousLegalUser.legalRepresentative.walletId ) - .withPaymentUserType( - updatedLegalUser.legalRepresentative.paymentUserType - .getOrElse(PaymentUserType.COLLECTOR) + .withNaturalUserType( + updatedLegalUser.legalRepresentative.naturalUserType + .getOrElse(NaturalUserType.COLLECTOR) ), uboDeclaration = previousLegalUser.uboDeclaration, lastAcceptedTermsOfPSP = previousLegalUser.lastAcceptedTermsOfPSP @@ -2011,9 +2011,9 @@ trait PaymentBehavior PaymentAccount.User.LegalUser( updatedLegalUser.copy( legalRepresentative = - updatedLegalUser.legalRepresentative.withPaymentUserType( - updatedLegalUser.legalRepresentative.paymentUserType.getOrElse( - PaymentUserType.COLLECTOR + updatedLegalUser.legalRepresentative.withNaturalUserType( + updatedLegalUser.legalRepresentative.naturalUserType.getOrElse( + NaturalUserType.COLLECTOR ) ) ) @@ -2027,15 +2027,15 @@ trait PaymentBehavior userId = previousNaturalUser.userId, walletId = previousNaturalUser.walletId ) - .withPaymentUserType( - updatedNaturalUser.paymentUserType.getOrElse(PaymentUserType.COLLECTOR) + .withNaturalUserType( + updatedNaturalUser.naturalUserType.getOrElse(NaturalUserType.COLLECTOR) ) ) } else if (updatedUser.isNaturalUser) { val updatedNaturalUser = updatedUser.naturalUser.get PaymentAccount.User.NaturalUser( - updatedNaturalUser.withPaymentUserType( - updatedNaturalUser.paymentUserType.getOrElse(PaymentUserType.COLLECTOR) + updatedNaturalUser.withNaturalUserType( + updatedNaturalUser.naturalUserType.getOrElse(NaturalUserType.COLLECTOR) ) ) } else { diff --git a/mangopay/src/main/scala/app/softnetwork/payment/spi/MangoPayProvider.scala b/mangopay/src/main/scala/app/softnetwork/payment/spi/MangoPayProvider.scala index e6e8ab5..121b398 100644 --- a/mangopay/src/main/scala/app/softnetwork/payment/spi/MangoPayProvider.scala +++ b/mangopay/src/main/scala/app/softnetwork/payment/spi/MangoPayProvider.scala @@ -23,7 +23,7 @@ import com.mangopay.entities.subentities.{BrowserInfo => MangoPayBrowserInfo, _} import app.softnetwork.payment.model.{RecurringPayment, _} import app.softnetwork.payment.config.{MangoPay, MangoPaySettings} import app.softnetwork.payment.config.MangoPaySettings.MangoPayConfig._ -import app.softnetwork.payment.model.PaymentUser.PaymentUserType +import app.softnetwork.payment.model.NaturalUser.NaturalUserType import app.softnetwork.payment.model.SoftPaymentAccount.Client.Provider import scala.util.{Failure, Success, Try} @@ -205,7 +205,7 @@ trait MangoPayProvider extends PaymentProvider { * @return * provider user id */ - def createOrUpdateNaturalUser(maybeNaturalUser: Option[PaymentUser]): Option[String] = { + def createOrUpdateNaturalUser(maybeNaturalUser: Option[NaturalUser]): Option[String] = { maybeNaturalUser match { case Some(naturalUser) => import naturalUser._ @@ -222,10 +222,10 @@ trait MangoPayProvider extends PaymentProvider { user.setTag(externalUuid) user.setNationality(CountryIso.valueOf(nationality)) user.setCountryOfResidence(CountryIso.valueOf(countryOfResidence)) - paymentUserType match { + naturalUserType match { case Some(value) => value match { - case PaymentUserType.PAYER => user.setUserCategory(UserCategory.PAYER) + case NaturalUserType.PAYER => user.setUserCategory(UserCategory.PAYER) case _ => user.setUserCategory(UserCategory.OWNER) user.setTermsAndConditionsAccepted(true) @@ -307,10 +307,10 @@ trait MangoPayProvider extends PaymentProvider { ) user.setEmail(legalRepresentative.email) user.setCompanyNumber(siret) - legalRepresentative.paymentUserType match { + legalRepresentative.naturalUserType match { case Some(value) => value match { - case PaymentUserType.PAYER => user.setUserCategory(UserCategory.PAYER) + case NaturalUserType.PAYER => user.setUserCategory(UserCategory.PAYER) case _ => user.setUserCategory(UserCategory.OWNER) user.setTermsAndConditionsAccepted(true) diff --git a/testkit/src/main/scala/app/softnetwork/payment/data/package.scala b/testkit/src/main/scala/app/softnetwork/payment/data/package.scala index ba13117..a244b32 100644 --- a/testkit/src/main/scala/app/softnetwork/payment/data/package.scala +++ b/testkit/src/main/scala/app/softnetwork/payment/data/package.scala @@ -1,6 +1,6 @@ package app.softnetwork.payment -import app.softnetwork.payment.model.{Address, CardPreRegistration, LegalUser, PaymentUser} +import app.softnetwork.payment.model.{Address, CardPreRegistration, LegalUser, NaturalUser} import app.softnetwork.payment.model.UboDeclaration.UltimateBeneficialOwner import app.softnetwork.payment.model.UboDeclaration.UltimateBeneficialOwner.BirthPlace @@ -25,8 +25,8 @@ package object data { val lastName = "lastName" val birthday = "26/12/1972" val email = "demo@softnetwork.fr" - val naturalUser: PaymentUser = - PaymentUser.defaultInstance + val naturalUser: NaturalUser = + NaturalUser.defaultInstance .withExternalUuid(customerUuid) .withFirstName(firstName) .withLastName(lastName) diff --git a/testkit/src/main/scala/app/softnetwork/payment/spi/MockMangoPayProvider.scala b/testkit/src/main/scala/app/softnetwork/payment/spi/MockMangoPayProvider.scala index 4143a60..60523bc 100644 --- a/testkit/src/main/scala/app/softnetwork/payment/spi/MockMangoPayProvider.scala +++ b/testkit/src/main/scala/app/softnetwork/payment/spi/MockMangoPayProvider.scala @@ -2,7 +2,7 @@ package app.softnetwork.payment.spi import app.softnetwork.payment.config.MangoPay import app.softnetwork.payment.config.MangoPaySettings.MangoPayConfig._ -import app.softnetwork.payment.model.PaymentUser.PaymentUserType +import app.softnetwork.payment.model.NaturalUser.NaturalUserType import app.softnetwork.payment.model.RecurringPayment.RecurringCardPaymentState import app.softnetwork.payment.model.SoftPaymentAccount.Client import app.softnetwork.payment.model.SoftPaymentAccount.Client.Provider @@ -44,7 +44,7 @@ trait MockMangoPayProvider extends MangoPayProvider { * @return * provider user id */ - override def createOrUpdateNaturalUser(maybeNaturalUser: Option[PaymentUser]): Option[String] = + override def createOrUpdateNaturalUser(maybeNaturalUser: Option[NaturalUser]): Option[String] = maybeNaturalUser match { case Some(naturalUser) => import naturalUser._ @@ -60,10 +60,10 @@ trait MockMangoPayProvider extends MangoPayProvider { user.setTag(externalUuid) user.setNationality(CountryIso.valueOf(nationality)) user.setCountryOfResidence(CountryIso.valueOf(countryOfResidence)) - paymentUserType match { + naturalUserType match { case Some(value) => value match { - case PaymentUserType.PAYER => user.setUserCategory(UserCategory.PAYER) + case NaturalUserType.PAYER => user.setUserCategory(UserCategory.PAYER) case _ => user.setUserCategory(UserCategory.OWNER) user.setTermsAndConditionsAccepted(true) @@ -129,10 +129,10 @@ trait MockMangoPayProvider extends MangoPayProvider { ) user.setEmail(legalRepresentative.email) user.setCompanyNumber(siret) - legalRepresentative.paymentUserType match { + legalRepresentative.naturalUserType match { case Some(value) => value match { - case PaymentUserType.PAYER => user.setUserCategory(UserCategory.PAYER) + case NaturalUserType.PAYER => user.setUserCategory(UserCategory.PAYER) case _ => user.setUserCategory(UserCategory.OWNER) user.setTermsAndConditionsAccepted(true) diff --git a/testkit/src/test/scala/app/softnetwork/payment/handlers/PaymentHandlerSpec.scala b/testkit/src/test/scala/app/softnetwork/payment/handlers/PaymentHandlerSpec.scala index c511351..cda60ad 100644 --- a/testkit/src/test/scala/app/softnetwork/payment/handlers/PaymentHandlerSpec.scala +++ b/testkit/src/test/scala/app/softnetwork/payment/handlers/PaymentHandlerSpec.scala @@ -58,7 +58,7 @@ class PaymentHandlerSpec assert(naturalUser.userId.isDefined) assert(naturalUser.walletId.isDefined) assert( - naturalUser.paymentUserType.getOrElse(PaymentUser.PaymentUserType.COLLECTOR).isPayer + naturalUser.naturalUserType.getOrElse(NaturalUser.NaturalUserType.COLLECTOR).isPayer ) case other => fail(other.toString) } @@ -177,8 +177,8 @@ class PaymentHandlerSpec ) sellerBankAccountId = paymentAccount.bankAccount.flatMap(_.id).getOrElse("") assert( - paymentAccount.getNaturalUser.paymentUserType - .getOrElse(PaymentUser.PaymentUserType.PAYER) + paymentAccount.getNaturalUser.naturalUserType + .getOrElse(NaturalUser.NaturalUserType.PAYER) .isCollector ) case other => fail(other.toString) @@ -226,8 +226,8 @@ class PaymentHandlerSpec sellerBankAccountId = paymentAccount.bankAccount.flatMap(_.id).getOrElse("") // assert(sellerBankAccountId != previousBankAccountId) assert( - paymentAccount.getNaturalUser.paymentUserType - .getOrElse(PaymentUser.PaymentUserType.PAYER) + paymentAccount.getNaturalUser.naturalUserType + .getOrElse(NaturalUser.NaturalUserType.PAYER) .isCollector ) case other => fail(other.toString) From ec3de78bdec79746bda69f26c261d0aa97aa310d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Manciot?= Date: Tue, 12 Dec 2023 06:54:36 +0100 Subject: [PATCH 31/37] rename soft payment messages and entities --- .../protobuf/message/payment/client.proto | 32 ++++----- .../main/protobuf/model/payment/client.proto | 22 +++--- .../payment/message/AccountMessages.scala | 23 ++++--- ...on.scala => SoftPayAccountCompanion.scala} | 4 +- ...or.scala => SoftPayAccountDecorator.scala} | 2 +- ...tor.scala => SoftPayClientDecorator.scala} | 12 ++-- ...r.scala => SoftPayProviderDecorator.scala} | 8 +-- .../payment/serialization/package.scala | 10 +-- .../payment/spi/PaymentProvider.scala | 4 +- .../payment/spi/PaymentProviderSpi.scala | 8 +-- .../payment/spi/PaymentProviders.scala | 8 +-- .../payment/api/ClientServer.scala | 14 ++-- .../payment/api/PaymentGrpcService.scala | 6 +- ...countDao.scala => SoftPayAccountDao.scala} | 44 ++++++------ .../payment/launch/PaymentEndpoints.scala | 4 +- .../payment/launch/PaymentGuardian.scala | 20 +++--- .../payment/launch/PaymentRoutes.scala | 4 +- .../persistence/typed/PaymentBehavior.scala | 6 +- ...ior.scala => SoftPayAccountBehavior.scala} | 68 +++++++++---------- .../service/CardPaymentEndpoints.scala | 4 +- .../payment/service/ClientSession.scala | 18 ++--- .../service/ClientSessionDirectives.scala | 12 ++-- .../service/ClientSessionEndpoints.scala | 10 +-- .../service/RootPaymentEndpoints.scala | 6 +- ...vice.scala => SoftPayAccountService.scala} | 6 +- ...a => SoftPayAccountServiceEndpoints.scala} | 6 +- ...ervice.scala => SoftPayOAuthService.scala} | 6 +- ...ala => SoftPayOAuthServiceEndpoints.scala} | 6 +- .../softnetwork/payment/api/MangoPayApi.scala | 16 ++--- .../payment/api/MangoPayEndpoints.scala | 8 +-- .../MangoPayEndpointsPostgresLauncher.scala | 2 +- .../payment/api/MangoPayRoutes.scala | 8 +-- ...thSchedulerEndpointsPostgresLauncher.scala | 2 +- ...yWithSchedulerRoutesPostgresLauncher.scala | 2 +- .../softnetwork/payment/config/MangoPay.scala | 10 +-- .../payment/spi/MangoPayProvider.scala | 17 ++--- .../payment/api/MockClientServer.scala | 4 +- .../payment/api/SoftPayClientTestKit.scala | 8 +-- .../handlers/MockSoftPayAccountDao.scala | 22 ++++++ .../handlers/MockSoftPaymentAccountDao.scala | 24 ------- .../typed/MockPaymentBehavior.scala | 6 +- .../typed/MockSoftPayAccountBehavior.scala | 7 ++ .../MockSoftPaymentAccountBehavior.scala | 7 -- .../scalatest/PaymentEndpointsTestKit.scala | 14 ++-- .../scalatest/PaymentRoutesTestKit.scala | 14 ++-- .../payment/scalatest/PaymentTestKit.scala | 20 +++--- .../service/MockSoftPayAccountService.scala | 12 ++++ .../MockSoftPayAccountServiceEndpoints.scala | 9 +++ ...ce.scala => MockSoftPayOAuthService.scala} | 8 +-- ...=> MockSoftPayOAuthServiceEndpoints.scala} | 8 +-- .../MockSoftPaymentAccountService.scala | 12 ---- ...ckSoftPaymentAccountServiceEndpoints.scala | 9 --- .../payment/spi/MockMangoPayProvider.scala | 19 +++--- 53 files changed, 324 insertions(+), 317 deletions(-) rename common/src/main/scala/app/softnetwork/payment/model/{SoftPaymentAccountCompanion.scala => SoftPayAccountCompanion.scala} (64%) rename common/src/main/scala/app/softnetwork/payment/model/{SoftPaymentAccountDecorator.scala => SoftPayAccountDecorator.scala} (85%) rename common/src/main/scala/app/softnetwork/payment/model/{SoftPaymentClientDecorator.scala => SoftPayClientDecorator.scala} (75%) rename common/src/main/scala/app/softnetwork/payment/model/{ProviderDecorator.scala => SoftPayProviderDecorator.scala} (75%) rename core/src/main/scala/app/softnetwork/payment/handlers/{SoftPaymentAccountDao.scala => SoftPayAccountDao.scala} (83%) rename core/src/main/scala/app/softnetwork/payment/persistence/typed/{SoftPaymentAccountBehavior.scala => SoftPayAccountBehavior.scala} (88%) rename core/src/main/scala/app/softnetwork/payment/service/{SoftPaymentAccountService.scala => SoftPayAccountService.scala} (84%) rename core/src/main/scala/app/softnetwork/payment/service/{SoftPaymentAccountServiceEndpoints.scala => SoftPayAccountServiceEndpoints.scala} (84%) rename core/src/main/scala/app/softnetwork/payment/service/{SoftPaymentOAuthService.scala => SoftPayOAuthService.scala} (95%) rename core/src/main/scala/app/softnetwork/payment/service/{SoftPaymentOAuthServiceEndpoints.scala => SoftPayOAuthServiceEndpoints.scala} (97%) create mode 100644 testkit/src/main/scala/app/softnetwork/payment/handlers/MockSoftPayAccountDao.scala delete mode 100644 testkit/src/main/scala/app/softnetwork/payment/handlers/MockSoftPaymentAccountDao.scala create mode 100644 testkit/src/main/scala/app/softnetwork/payment/persistence/typed/MockSoftPayAccountBehavior.scala delete mode 100644 testkit/src/main/scala/app/softnetwork/payment/persistence/typed/MockSoftPaymentAccountBehavior.scala create mode 100644 testkit/src/main/scala/app/softnetwork/payment/service/MockSoftPayAccountService.scala create mode 100644 testkit/src/main/scala/app/softnetwork/payment/service/MockSoftPayAccountServiceEndpoints.scala rename testkit/src/main/scala/app/softnetwork/payment/service/{MockSoftPaymentOAuthService.scala => MockSoftPayOAuthService.scala} (63%) rename testkit/src/main/scala/app/softnetwork/payment/service/{MockSoftPaymentOAuthServiceEndpoints.scala => MockSoftPayOAuthServiceEndpoints.scala} (57%) delete mode 100644 testkit/src/main/scala/app/softnetwork/payment/service/MockSoftPaymentAccountService.scala delete mode 100644 testkit/src/main/scala/app/softnetwork/payment/service/MockSoftPaymentAccountServiceEndpoints.scala diff --git a/common/src/main/protobuf/message/payment/client.proto b/common/src/main/protobuf/message/payment/client.proto index b3c2806..d32a246 100644 --- a/common/src/main/protobuf/message/payment/client.proto +++ b/common/src/main/protobuf/message/payment/client.proto @@ -4,7 +4,7 @@ import "scalapb/scalapb.proto"; import "google/protobuf/timestamp.proto"; import "model/payment/client.proto"; -package app.softnetwork.payment.message.SoftPaymentAccountEvents; +package app.softnetwork.payment.message.SoftPayAccountEvents; option (scalapb.options) = { single_file: true @@ -15,36 +15,36 @@ option (scalapb.options) = { import: "app.softnetwork.serialization._" import: "app.softnetwork.account.message._" import: "app.softnetwork.payment.model._" - import: "app.softnetwork.payment.message.SoftPaymentAccountEvents._" + import: "app.softnetwork.payment.message.SoftPayAccountEvents._" import: "app.softnetwork.payment.serialization._" preserve_unknown_fields: false - preamble: "sealed trait SoftPaymentAccountEvent extends AccountEvent" + preamble: "sealed trait SoftPayAccountEvent extends AccountEvent" }; -message SoftPaymentAccountCreatedEvent { +message SoftPayAccountCreatedEvent { option (scalapb.message).extends = "ProtobufEvent"; - option (scalapb.message).extends = "SoftPaymentAccountEvent"; - option (scalapb.message).extends = "AccountCreatedEvent[SoftPaymentAccount]"; - required app.softnetwork.payment.model.SoftPaymentAccount document = 1; + option (scalapb.message).extends = "SoftPayAccountEvent"; + option (scalapb.message).extends = "AccountCreatedEvent[SoftPayAccount]"; + required app.softnetwork.payment.model.SoftPayAccount document = 1; } -message SoftPaymentAccountProviderRegisteredEvent { +message SoftPayAccountProviderRegisteredEvent { option (scalapb.message).extends = "ProtobufEvent"; - option (scalapb.message).extends = "SoftPaymentAccountEvent"; - required app.softnetwork.payment.model.SoftPaymentAccount.Client client = 1; + option (scalapb.message).extends = "SoftPayAccountEvent"; + required app.softnetwork.payment.model.SoftPayAccount.SoftPayClient client = 1; required google.protobuf.Timestamp lastUpdated = 2 [(scalapb.field).type = "java.time.Instant"]; } -message SoftPaymentAccountTokenRegisteredEvent { +message SoftPayAccountTokenRegisteredEvent { option (scalapb.message).extends = "ProtobufEvent"; - option (scalapb.message).extends = "SoftPaymentAccountEvent"; - required app.softnetwork.payment.model.SoftPaymentAccount.Client client = 1; + option (scalapb.message).extends = "SoftPayAccountEvent"; + required app.softnetwork.payment.model.SoftPayAccount.SoftPayClient client = 1; required google.protobuf.Timestamp lastUpdated = 2 [(scalapb.field).type = "java.time.Instant"]; } -message SoftPaymentAccountTokenRefreshedEvent { +message SoftPayAccountTokenRefreshedEvent { option (scalapb.message).extends = "ProtobufEvent"; - option (scalapb.message).extends = "SoftPaymentAccountEvent"; - required app.softnetwork.payment.model.SoftPaymentAccount.Client client = 1; + option (scalapb.message).extends = "SoftPayAccountEvent"; + required app.softnetwork.payment.model.SoftPayAccount.SoftPayClient client = 1; required google.protobuf.Timestamp lastUpdated = 2 [(scalapb.field).type = "java.time.Instant"]; } diff --git a/common/src/main/protobuf/model/payment/client.proto b/common/src/main/protobuf/model/payment/client.proto index ee0c853..4cbc8fe 100644 --- a/common/src/main/protobuf/model/payment/client.proto +++ b/common/src/main/protobuf/model/payment/client.proto @@ -20,28 +20,28 @@ option (scalapb.options) = { preserve_unknown_fields: false }; -message SoftPaymentAccount { +message SoftPayAccount { - message Client { + message SoftPayClient { - message Provider { + message SoftPayProvider { - enum ProviderType{ + enum SoftPayProviderType{ MOCK = -1; MANGOPAY = 0; STRIPE = 1; } - option (scalapb.message).extends = "ProviderDecorator"; + option (scalapb.message).extends = "SoftPayProviderDecorator"; required string providerId = 1; required string providerApiKey = 2; - required ProviderType providerType = 3 [default = MANGOPAY]; + required SoftPayProviderType providerType = 3 [default = MANGOPAY]; } - option (scalapb.message).extends = "SoftPaymentClientDecorator"; + option (scalapb.message).extends = "SoftPayClientDecorator"; - required Provider provider = 1; + required SoftPayProvider provider = 1; required string clientId = 2; optional string clientApiKey = 3; optional string name = 4; @@ -60,8 +60,8 @@ message SoftPaymentAccount { option (scalapb.message).extends = "ProtobufDomainObject"; option (scalapb.message).extends = "Account"; option (scalapb.message).extends = "Timestamped"; - option (scalapb.message).extends = "SoftPaymentAccountDecorator"; - option (scalapb.message).companion_extends = "SoftPaymentAccountCompanion"; + option (scalapb.message).extends = "SoftPayAccountDecorator"; + option (scalapb.message).companion_extends = "SoftPayAccountCompanion"; required string uuid = 1; required google.protobuf.Timestamp createdDate = 2 [(scalapb.field).type = "java.time.Instant"]; required google.protobuf.Timestamp lastUpdated = 3 [(scalapb.field).type = "java.time.Instant"]; @@ -82,5 +82,5 @@ message SoftPaymentAccount { optional bool fromAnonymous = 19; repeated app.softnetwork.account.model.Application applications = 20; - repeated Client clients = 21; + repeated SoftPayClient clients = 21; } \ No newline at end of file diff --git a/common/src/main/scala/app/softnetwork/payment/message/AccountMessages.scala b/common/src/main/scala/app/softnetwork/payment/message/AccountMessages.scala index 3df053f..a10ef1e 100644 --- a/common/src/main/scala/app/softnetwork/payment/message/AccountMessages.scala +++ b/common/src/main/scala/app/softnetwork/payment/message/AccountMessages.scala @@ -9,22 +9,23 @@ import app.softnetwork.account.message.{ } import app.softnetwork.account.model.BasicAccountProfile import app.softnetwork.payment.annotation.InternalApi -import app.softnetwork.payment.model.SoftPaymentAccount +import app.softnetwork.payment.model.SoftPayAccount import app.softnetwork.persistence.message.EntityCommand import org.softnetwork.session.model.ApiKey object AccountMessages { - case class SoftPaymentSignUp( + case class SoftPaySignUp( login: String, password: String, - provider: SoftPaymentAccount.Client.Provider, + provider: SoftPayAccount.SoftPayClient.SoftPayProvider, override val confirmPassword: Option[String] = None, override val profile: Option[BasicAccountProfile] = None ) extends SignUp - case class RegisterProvider(provider: SoftPaymentAccount.Client.Provider) extends AccountCommand + case class RegisterProvider(provider: SoftPayAccount.SoftPayClient.SoftPayProvider) + extends AccountCommand - case class RegisterProviderAccount(provider: SoftPaymentAccount.Client.Provider) + case class RegisterAccountWithProvider(provider: SoftPayAccount.SoftPayClient.SoftPayProvider) extends AccountCommand with EntityCommand { override def id: String = provider.clientId @@ -47,25 +48,25 @@ object AccountMessages { case class OAuthClient(token: String) extends LookupAccountCommand - case class ProviderRegistered(client: SoftPaymentAccount.Client) extends AccountCommandResult + case class ProviderRegistered(client: SoftPayAccount.SoftPayClient) extends AccountCommandResult - case class ProviderAccountRegistered(account: SoftPaymentAccount) extends AccountCommandResult + case class AccountWithProviderRegistered(account: SoftPayAccount) extends AccountCommandResult - case class ClientLoaded(client: SoftPaymentAccount.Client) extends AccountCommandResult + case class ClientLoaded(client: SoftPayAccount.SoftPayClient) extends AccountCommandResult case class ApiKeysLoaded(apiKeys: Seq[ApiKey]) extends AccountCommandResult case class ApiKeyLoaded(apiKey: ApiKey) extends AccountCommandResult - case class OAuthClientSucceededResult(client: SoftPaymentAccount.Client) + case class OAuthClientSucceededResult(client: SoftPayAccount.SoftPayClient) extends AccountCommandResult case object ProviderAlreadyRegistered extends AccountErrorMessage("provider.already.registered") case object ProviderNotRegistered extends AccountErrorMessage("provider.not.registered") - case object ProviderAccountNotRegistered - extends AccountErrorMessage("provider.account.not.registered") + case object AccountWithProviderNotRegistered + extends AccountErrorMessage("account.with.provider.not.registered") case object ClientNotFound extends AccountErrorMessage("client.not.found") diff --git a/common/src/main/scala/app/softnetwork/payment/model/SoftPaymentAccountCompanion.scala b/common/src/main/scala/app/softnetwork/payment/model/SoftPayAccountCompanion.scala similarity index 64% rename from common/src/main/scala/app/softnetwork/payment/model/SoftPaymentAccountCompanion.scala rename to common/src/main/scala/app/softnetwork/payment/model/SoftPayAccountCompanion.scala index d0d3b4b..c33f4b6 100644 --- a/common/src/main/scala/app/softnetwork/payment/model/SoftPaymentAccountCompanion.scala +++ b/common/src/main/scala/app/softnetwork/payment/model/SoftPayAccountCompanion.scala @@ -3,9 +3,9 @@ package app.softnetwork.payment.model import app.softnetwork.account.model.{BasicAccount, BasicAccountCompanion} import app.softnetwork.payment.serialization._ -trait SoftPaymentAccountCompanion extends BasicAccountCompanion { +trait SoftPayAccountCompanion extends BasicAccountCompanion { - def apply(account: Option[BasicAccount]): Option[SoftPaymentAccount] = { + def apply(account: Option[BasicAccount]): Option[SoftPayAccount] = { account match { case Some(a) => Some(a) case _ => None diff --git a/common/src/main/scala/app/softnetwork/payment/model/SoftPaymentAccountDecorator.scala b/common/src/main/scala/app/softnetwork/payment/model/SoftPayAccountDecorator.scala similarity index 85% rename from common/src/main/scala/app/softnetwork/payment/model/SoftPaymentAccountDecorator.scala rename to common/src/main/scala/app/softnetwork/payment/model/SoftPayAccountDecorator.scala index cc4d006..0a3da8c 100644 --- a/common/src/main/scala/app/softnetwork/payment/model/SoftPaymentAccountDecorator.scala +++ b/common/src/main/scala/app/softnetwork/payment/model/SoftPayAccountDecorator.scala @@ -3,7 +3,7 @@ package app.softnetwork.payment.model import app.softnetwork.account.model.{BasicAccountProfile, Profile} import org.softnetwork.session.model.ApiKey -trait SoftPaymentAccountDecorator { _: SoftPaymentAccount => +trait SoftPayAccountDecorator { _: SoftPayAccount => override def newProfile(name: String): Profile = BasicAccountProfile.defaultInstance.withName(name) diff --git a/common/src/main/scala/app/softnetwork/payment/model/SoftPaymentClientDecorator.scala b/common/src/main/scala/app/softnetwork/payment/model/SoftPayClientDecorator.scala similarity index 75% rename from common/src/main/scala/app/softnetwork/payment/model/SoftPaymentClientDecorator.scala rename to common/src/main/scala/app/softnetwork/payment/model/SoftPayClientDecorator.scala index 4476786..b147edf 100644 --- a/common/src/main/scala/app/softnetwork/payment/model/SoftPaymentClientDecorator.scala +++ b/common/src/main/scala/app/softnetwork/payment/model/SoftPayClientDecorator.scala @@ -2,14 +2,14 @@ package app.softnetwork.payment.model import app.softnetwork.account.model.BearerTokenGenerator -trait SoftPaymentClientDecorator { _: SoftPaymentAccount.Client => +trait SoftPayClientDecorator { _: SoftPayAccount.SoftPayClient => def generateApiKey(): String = BearerTokenGenerator.generateSHAToken(clientId) - lazy val view: SoftPaymentClientView = SoftPaymentClientView(this) + lazy val view: SoftPayClientView = SoftPayClientView(this) } -case class SoftPaymentClientView( +case class SoftPayClientView( clientId: String, clientApiKey: Option[String] = None, name: Option[String] = None, @@ -24,10 +24,10 @@ case class SoftPaymentClientView( address: Option[AddressView] = None ) -object SoftPaymentClientView { - def apply(client: SoftPaymentAccount.Client): SoftPaymentClientView = { +object SoftPayClientView { + def apply(client: SoftPayAccount.SoftPayClient): SoftPayClientView = { import client._ - SoftPaymentClientView( + SoftPayClientView( clientId, clientApiKey, name, diff --git a/common/src/main/scala/app/softnetwork/payment/model/ProviderDecorator.scala b/common/src/main/scala/app/softnetwork/payment/model/SoftPayProviderDecorator.scala similarity index 75% rename from common/src/main/scala/app/softnetwork/payment/model/ProviderDecorator.scala rename to common/src/main/scala/app/softnetwork/payment/model/SoftPayProviderDecorator.scala index b44d1da..97e4e07 100644 --- a/common/src/main/scala/app/softnetwork/payment/model/ProviderDecorator.scala +++ b/common/src/main/scala/app/softnetwork/payment/model/SoftPayProviderDecorator.scala @@ -4,10 +4,10 @@ import app.softnetwork.account.model.AccountStatus import app.softnetwork.payment.spi.PaymentProviders import app.softnetwork.security.sha256 -trait ProviderDecorator { self: SoftPaymentAccount.Client.Provider => +trait SoftPayProviderDecorator { self: SoftPayAccount.SoftPayClient.SoftPayProvider => lazy val clientId = s"$providerId.${providerType.name.toLowerCase}" - lazy val client: SoftPaymentAccount.Client = { + lazy val client: SoftPayAccount.SoftPayClient = { PaymentProviders.paymentProvider(self).client match { case Some(client) => client.withClientApiKey(sha256(self.providerApiKey)) @@ -16,8 +16,8 @@ trait ProviderDecorator { self: SoftPaymentAccount.Client.Provider => } } - lazy val account: SoftPaymentAccount = { - SoftPaymentAccount.defaultInstance + lazy val account: SoftPayAccount = { + SoftPayAccount.defaultInstance .withUuid(clientId) .withAnonymous(true) .withClients(Seq(client)) diff --git a/common/src/main/scala/app/softnetwork/payment/serialization/package.scala b/common/src/main/scala/app/softnetwork/payment/serialization/package.scala index 7284478..61fb5ac 100644 --- a/common/src/main/scala/app/softnetwork/payment/serialization/package.scala +++ b/common/src/main/scala/app/softnetwork/payment/serialization/package.scala @@ -30,7 +30,9 @@ package object serialization { GeneratedEnumSerializer(RecurringPayment.RecurringPaymentType.enumCompanion), GeneratedEnumSerializer(RecurringPayment.RecurringPaymentFrequency.enumCompanion), GeneratedEnumSerializer(RecurringPayment.RecurringCardPaymentStatus.enumCompanion), - GeneratedEnumSerializer(SoftPaymentAccount.Client.Provider.ProviderType.enumCompanion) + GeneratedEnumSerializer( + SoftPayAccount.SoftPayClient.SoftPayProvider.SoftPayProviderType.enumCompanion + ) ) implicit def transactionStatusToTransactionResponseStatus( @@ -67,12 +69,12 @@ package object serialization { } } - implicit def accountToSoftPaymentAccount(account: Account): SoftPaymentAccount = { + implicit def accountToSoftPaymentAccount(account: Account): SoftPayAccount = { account match { - case a: SoftPaymentAccount => a + case a: SoftPayAccount => a case _ => import account._ - SoftPaymentAccount.defaultInstance + SoftPayAccount.defaultInstance .withApplications(applications) .withCreatedDate(createdDate) .withCredentials(credentials) diff --git a/common/src/main/scala/app/softnetwork/payment/spi/PaymentProvider.scala b/common/src/main/scala/app/softnetwork/payment/spi/PaymentProvider.scala index 281ec60..733cf38 100644 --- a/common/src/main/scala/app/softnetwork/payment/spi/PaymentProvider.scala +++ b/common/src/main/scala/app/softnetwork/payment/spi/PaymentProvider.scala @@ -12,7 +12,7 @@ private[payment] trait PaymentProvider { protected lazy val mlog: Logger = Logger(LoggerFactory.getLogger(getClass.getName)) - implicit def provider: SoftPaymentAccount.Client.Provider + implicit def provider: SoftPayAccount.SoftPayClient.SoftPayProvider /** @param maybePaymentAccount * - payment account to create or update @@ -374,7 +374,7 @@ private[payment] trait PaymentProvider { /** @return * client fees */ - def client: Option[SoftPaymentAccount.Client] + def client: Option[SoftPayAccount.SoftPayClient] def clientFees(): Option[Double] diff --git a/common/src/main/scala/app/softnetwork/payment/spi/PaymentProviderSpi.scala b/common/src/main/scala/app/softnetwork/payment/spi/PaymentProviderSpi.scala index 0130477..83f09e9 100644 --- a/common/src/main/scala/app/softnetwork/payment/spi/PaymentProviderSpi.scala +++ b/common/src/main/scala/app/softnetwork/payment/spi/PaymentProviderSpi.scala @@ -1,11 +1,11 @@ package app.softnetwork.payment.spi -import app.softnetwork.payment.model.SoftPaymentAccount +import app.softnetwork.payment.model.SoftPayAccount trait PaymentProviderSpi { - def providerType: SoftPaymentAccount.Client.Provider.ProviderType + def providerType: SoftPayAccount.SoftPayClient.SoftPayProvider.SoftPayProviderType - def paymentProvider(p: SoftPaymentAccount.Client.Provider): PaymentProvider + def paymentProvider(p: SoftPayAccount.SoftPayClient.SoftPayProvider): PaymentProvider - def softPaymentProvider: SoftPaymentAccount.Client.Provider + def softPaymentProvider: SoftPayAccount.SoftPayClient.SoftPayProvider } diff --git a/common/src/main/scala/app/softnetwork/payment/spi/PaymentProviders.scala b/common/src/main/scala/app/softnetwork/payment/spi/PaymentProviders.scala index d185b66..3ff1433 100644 --- a/common/src/main/scala/app/softnetwork/payment/spi/PaymentProviders.scala +++ b/common/src/main/scala/app/softnetwork/payment/spi/PaymentProviders.scala @@ -1,6 +1,6 @@ package app.softnetwork.payment.spi -import app.softnetwork.payment.model.SoftPaymentAccount +import app.softnetwork.payment.model.SoftPayAccount import java.util.ServiceLoader import scala.collection.JavaConverters._ @@ -12,14 +12,14 @@ object PaymentProviders { private[this] var paymentProviders: Map[String, PaymentProvider] = Map.empty - private[this] def paymentProviderKey(provider: SoftPaymentAccount.Client.Provider) = + private[this] def paymentProviderKey(provider: SoftPayAccount.SoftPayClient.SoftPayProvider) = s"${provider.providerType}-${provider.providerId}" - def defaultPaymentProviders: Seq[SoftPaymentAccount.Client.Provider] = + def defaultPaymentProviders: Seq[SoftPayAccount.SoftPayClient.SoftPayProvider] = paymentProviderFactories.iterator().asScala.map(_.softPaymentProvider).toSeq def paymentProvider( - provider: SoftPaymentAccount.Client.Provider + provider: SoftPayAccount.SoftPayClient.SoftPayProvider ): PaymentProvider = { paymentProviders.get(paymentProviderKey(provider)) match { case Some(paymentProvider) => paymentProvider diff --git a/core/src/main/scala/app/softnetwork/payment/api/ClientServer.scala b/core/src/main/scala/app/softnetwork/payment/api/ClientServer.scala index a1f3751..d7d61ff 100644 --- a/core/src/main/scala/app/softnetwork/payment/api/ClientServer.scala +++ b/core/src/main/scala/app/softnetwork/payment/api/ClientServer.scala @@ -2,14 +2,14 @@ package app.softnetwork.payment.api import akka.actor.typed.ActorSystem import app.softnetwork.account.message.Activate -import app.softnetwork.payment.handlers.SoftPaymentAccountDao +import app.softnetwork.payment.handlers.SoftPayAccountDao import app.softnetwork.payment.message.AccountMessages -import app.softnetwork.payment.model.SoftPaymentAccount +import app.softnetwork.payment.model.SoftPayAccount import org.slf4j.{Logger, LoggerFactory} import scala.concurrent.{ExecutionContextExecutor, Future} -trait ClientServer extends ClientServiceApi with SoftPaymentAccountDao { +trait ClientServer extends ClientServiceApi with SoftPayAccountDao { implicit def system: ActorSystem[_] @@ -56,15 +56,15 @@ trait ClientServer extends ClientServiceApi with SoftPaymentAccountDao { override def signUpClient(in: SignUpClientRequest): Future[SignUpClientResponse] = { import in._ signUpClient( - AccountMessages.SoftPaymentSignUp( + AccountMessages.SoftPaySignUp( principal, credentials, - SoftPaymentAccount.Client.Provider( + SoftPayAccount.SoftPayClient.SoftPayProvider( providerId, providerApiKey, - SoftPaymentAccount.Client.Provider.ProviderType + SoftPayAccount.SoftPayClient.SoftPayProvider.SoftPayProviderType .fromName(providerType.name) - .getOrElse(SoftPaymentAccount.Client.Provider.ProviderType.MANGOPAY) + .getOrElse(SoftPayAccount.SoftPayClient.SoftPayProvider.SoftPayProviderType.MANGOPAY) ) ) ) map { diff --git a/core/src/main/scala/app/softnetwork/payment/api/PaymentGrpcService.scala b/core/src/main/scala/app/softnetwork/payment/api/PaymentGrpcService.scala index 368e06f..e5ab3b0 100644 --- a/core/src/main/scala/app/softnetwork/payment/api/PaymentGrpcService.scala +++ b/core/src/main/scala/app/softnetwork/payment/api/PaymentGrpcService.scala @@ -8,11 +8,11 @@ import akka.http.scaladsl.server.directives.Credentials import app.softnetwork.account.config.AccountSettings import app.softnetwork.api.server.GrpcService import app.softnetwork.concurrent.Completion -import app.softnetwork.payment.handlers.SoftPaymentAccountDao +import app.softnetwork.payment.handlers.SoftPayAccountDao import scala.concurrent.Future -class PaymentGrpcService(server: PaymentServer, softPaymentAccountDao: SoftPaymentAccountDao) +class PaymentGrpcService(server: PaymentServer, softPayAccountDao: SoftPayAccountDao) extends GrpcService with Completion { override def grpcService: ActorSystem[_] => PartialFunction[HttpRequest, Future[HttpResponse]] = @@ -23,7 +23,7 @@ class PaymentGrpcService(server: PaymentServer, softPaymentAccountDao: SoftPayme AccountSettings.Realm, { case _ @Credentials.Provided(token) => - softPaymentAccountDao.authenticateClient(Some(token))(system) + softPayAccountDao.authenticateClient(Some(token))(system) case _ => Future.successful(None) } ).optional { diff --git a/core/src/main/scala/app/softnetwork/payment/handlers/SoftPaymentAccountDao.scala b/core/src/main/scala/app/softnetwork/payment/handlers/SoftPayAccountDao.scala similarity index 83% rename from core/src/main/scala/app/softnetwork/payment/handlers/SoftPaymentAccountDao.scala rename to core/src/main/scala/app/softnetwork/payment/handlers/SoftPayAccountDao.scala index 060b75a..2628b58 100644 --- a/core/src/main/scala/app/softnetwork/payment/handlers/SoftPaymentAccountDao.scala +++ b/core/src/main/scala/app/softnetwork/payment/handlers/SoftPayAccountDao.scala @@ -15,8 +15,8 @@ import app.softnetwork.account.message.{ } import app.softnetwork.payment.annotation.InternalApi import app.softnetwork.payment.message.AccountMessages -import app.softnetwork.payment.model.SoftPaymentAccount -import app.softnetwork.payment.persistence.typed.SoftPaymentAccountBehavior +import app.softnetwork.payment.model.SoftPayAccount +import app.softnetwork.payment.persistence.typed.SoftPayAccountBehavior import app.softnetwork.persistence.generateUUID import app.softnetwork.persistence.typed.CommandTypeKey import app.softnetwork.session.model.JwtClaimsEncoder @@ -27,11 +27,13 @@ import org.slf4j.{Logger, LoggerFactory} import scala.concurrent.{ExecutionContext, Future} import scala.reflect.ClassTag -trait SoftPaymentAccountDao extends AccountDao with SoftPaymentAccountHandler { +trait SoftPayAccountDao extends AccountDao with SoftPayAccountHandler { @InternalApi private[payment] def loadProvider( clientId: String - )(implicit system: ActorSystem[_]): Future[Option[SoftPaymentAccount.Client.Provider]] = { + )(implicit + system: ActorSystem[_] + ): Future[Option[SoftPayAccount.SoftPayClient.SoftPayProvider]] = { implicit val ec: ExecutionContext = system.executionContext loadClient(clientId).map(_.map(_.provider)) } @@ -39,7 +41,7 @@ trait SoftPaymentAccountDao extends AccountDao with SoftPaymentAccountHandler { @InternalApi private[payment] def loadClient( clientId: String - )(implicit system: ActorSystem[_]): Future[Option[SoftPaymentAccount.Client]] = { + )(implicit system: ActorSystem[_]): Future[Option[SoftPayAccount.SoftPayClient]] = { implicit val ec: ExecutionContext = system.executionContext ??(clientId, AccountMessages.LoadClient(clientId)) map { case result: AccountMessages.ClientLoaded => Some(result.client) @@ -50,7 +52,7 @@ trait SoftPaymentAccountDao extends AccountDao with SoftPaymentAccountHandler { @InternalApi private[payment] def oauthClient( token: String - )(implicit system: ActorSystem[_]): Future[Option[SoftPaymentAccount.Client]] = { + )(implicit system: ActorSystem[_]): Future[Option[SoftPayAccount.SoftPayClient]] = { implicit val ec: ExecutionContext = system.executionContext ??(token, AccountMessages.OAuthClient(token)) map { case result: AccountMessages.OAuthClientSucceededResult => Some(result.client) @@ -106,8 +108,8 @@ trait SoftPaymentAccountDao extends AccountDao with SoftPaymentAccountHandler { @InternalApi private[payment] def signUpClient( - signUp: AccountMessages.SoftPaymentSignUp - )(implicit system: ActorSystem[_]): Future[Either[String, SoftPaymentAccount.Client]] = { + signUp: AccountMessages.SoftPaySignUp + )(implicit system: ActorSystem[_]): Future[Either[String, SoftPayAccount.SoftPayClient]] = { implicit val ec: ExecutionContext = system.executionContext ??( generateUUID(Some(signUp.login)), @@ -116,7 +118,7 @@ trait SoftPaymentAccountDao extends AccountDao with SoftPaymentAccountHandler { case result: AccountCreated => Right( result.account - .asInstanceOf[SoftPaymentAccount] + .asInstanceOf[SoftPayAccount] .clients .find(_.provider.providerId == signUp.provider.providerId) .get @@ -150,20 +152,22 @@ trait SoftPaymentAccountDao extends AccountDao with SoftPaymentAccountHandler { } @InternalApi - private[payment] def registerProviderAccount(provider: SoftPaymentAccount.Client.Provider)( - implicit system: ActorSystem[_] - ): Future[Option[SoftPaymentAccount]] = { + private[payment] def registerAccountWithProvider( + provider: SoftPayAccount.SoftPayClient.SoftPayProvider + )(implicit + system: ActorSystem[_] + ): Future[Option[SoftPayAccount]] = { implicit val ec: ExecutionContext = system.executionContext - !?(AccountMessages.RegisterProviderAccount(provider)) map { - case result: AccountMessages.ProviderAccountRegistered => Some(result.account) - case _ => None + !?(AccountMessages.RegisterAccountWithProvider(provider)) map { + case result: AccountMessages.AccountWithProviderRegistered => Some(result.account) + case _ => None } } @InternalApi private[payment] def authenticateClient( token: Option[String] - )(implicit system: ActorSystem[_]): Future[Option[SoftPaymentAccount.Client]] = { + )(implicit system: ActorSystem[_]): Future[Option[SoftPayAccount.SoftPayClient]] = { token match { case Some(value) => implicit val ec: ExecutionContext = system.executionContext @@ -205,13 +209,13 @@ trait SoftPaymentAccountDao extends AccountDao with SoftPaymentAccountHandler { } } -trait SoftPaymentAccountTypeKey extends CommandTypeKey[AccountCommand] { +trait SoftPayAccountTypeKey extends CommandTypeKey[AccountCommand] { override def TypeKey(implicit tTag: ClassTag[AccountCommand]): EntityTypeKey[AccountCommand] = - SoftPaymentAccountBehavior.TypeKey + SoftPayAccountBehavior.TypeKey } -trait SoftPaymentAccountHandler extends AccountHandler with SoftPaymentAccountTypeKey +trait SoftPayAccountHandler extends AccountHandler with SoftPayAccountTypeKey -object SoftPaymentAccountDao extends SoftPaymentAccountDao { +object SoftPayAccountDao extends SoftPayAccountDao { lazy val log: Logger = LoggerFactory getLogger getClass.getName } diff --git a/core/src/main/scala/app/softnetwork/payment/launch/PaymentEndpoints.scala b/core/src/main/scala/app/softnetwork/payment/launch/PaymentEndpoints.scala index 47d703c..eeeb0a4 100644 --- a/core/src/main/scala/app/softnetwork/payment/launch/PaymentEndpoints.scala +++ b/core/src/main/scala/app/softnetwork/payment/launch/PaymentEndpoints.scala @@ -5,7 +5,7 @@ import app.softnetwork.account.launch.AccountEndpoints import app.softnetwork.account.message.BasicAccountSignUp import app.softnetwork.account.model.BasicAccountProfile import app.softnetwork.api.server.{ApiEndpoints, Endpoint} -import app.softnetwork.payment.model.SoftPaymentAccount +import app.softnetwork.payment.model.SoftPayAccount import app.softnetwork.payment.serialization.paymentFormats import app.softnetwork.payment.service.PaymentServiceEndpoints import app.softnetwork.persistence.schema.SchemaProvider @@ -15,7 +15,7 @@ import org.json4s.Formats trait PaymentEndpoints[SD <: SessionData with SessionDataDecorator[SD]] extends AccountEndpoints[ - SoftPaymentAccount, + SoftPayAccount, BasicAccountProfile, BasicAccountSignUp, SD diff --git a/core/src/main/scala/app/softnetwork/payment/launch/PaymentGuardian.scala b/core/src/main/scala/app/softnetwork/payment/launch/PaymentGuardian.scala index b247a0c..541c3c2 100644 --- a/core/src/main/scala/app/softnetwork/payment/launch/PaymentGuardian.scala +++ b/core/src/main/scala/app/softnetwork/payment/launch/PaymentGuardian.scala @@ -13,14 +13,14 @@ import app.softnetwork.payment.api.{ PaymentGrpcService, PaymentServer } -import app.softnetwork.payment.handlers.SoftPaymentAccountDao -import app.softnetwork.payment.model.SoftPaymentAccount +import app.softnetwork.payment.handlers.SoftPayAccountDao +import app.softnetwork.payment.model.SoftPayAccount import app.softnetwork.payment.persistence.data.paymentKvDao import app.softnetwork.payment.persistence.query.{ PaymentCommandProcessorStream, Scheduler2PaymentProcessorStream } -import app.softnetwork.payment.persistence.typed.{PaymentBehavior, SoftPaymentAccountBehavior} +import app.softnetwork.payment.persistence.typed.{PaymentBehavior, SoftPayAccountBehavior} import app.softnetwork.payment.spi.PaymentProviders import app.softnetwork.persistence.launch.PersistentEntity import app.softnetwork.persistence.query.EventProcessorStream @@ -30,7 +30,7 @@ import app.softnetwork.session.CsrfCheck import scala.concurrent.ExecutionContext -trait PaymentGuardian extends AccountGuardian[SoftPaymentAccount, BasicAccountProfile] { +trait PaymentGuardian extends AccountGuardian[SoftPayAccount, BasicAccountProfile] { _: SchemaProvider with CsrfCheck => import app.softnetwork.persistence.launch.PersistenceGuardian._ @@ -38,8 +38,8 @@ trait PaymentGuardian extends AccountGuardian[SoftPaymentAccount, BasicAccountPr def paymentBehavior: ActorSystem[_] => PaymentBehavior = _ => PaymentBehavior override def accountBehavior - : ActorSystem[_] => AccountBehavior[SoftPaymentAccount, BasicAccountProfile] = _ => - SoftPaymentAccountBehavior + : ActorSystem[_] => AccountBehavior[SoftPayAccount, BasicAccountProfile] = _ => + SoftPayAccountBehavior def paymentEntities: ActorSystem[_] => Seq[PersistentEntity[_, _, _, _]] = sys => Seq( @@ -70,9 +70,9 @@ trait PaymentGuardian extends AccountGuardian[SoftPaymentAccount, BasicAccountPr override def systemVersion(): String = sys.env.getOrElse("VERSION", PaymentCoreBuildInfo.version) - def softPaymentAccountDao: SoftPaymentAccountDao = SoftPaymentAccountDao + def softPayAccountDao: SoftPayAccountDao = SoftPayAccountDao - final override def accountDao: AccountDao = softPaymentAccountDao + final override def accountDao: AccountDao = softPayAccountDao def paymentServer: ActorSystem[_] => PaymentServer = system => PaymentServer(system) @@ -80,14 +80,14 @@ trait PaymentGuardian extends AccountGuardian[SoftPaymentAccount, BasicAccountPr def paymentGrpcServices: ActorSystem[_] => Seq[GrpcService] = system => Seq( - new PaymentGrpcService(paymentServer(system), softPaymentAccountDao), + new PaymentGrpcService(paymentServer(system), softPayAccountDao), new ClientGrpcService(clientServer(system)) ) def registerProvidersAccount: ActorSystem[_] => Unit = system => { PaymentProviders.defaultPaymentProviders.foreach(provider => { implicit val ec: ExecutionContext = system.executionContext - softPaymentAccountDao.registerProviderAccount(provider)(system) map { + softPayAccountDao.registerAccountWithProvider(provider)(system) map { case Some(account) => system.log.info(s"Registered provider account for ${provider.providerId}: $account") case _ => diff --git a/core/src/main/scala/app/softnetwork/payment/launch/PaymentRoutes.scala b/core/src/main/scala/app/softnetwork/payment/launch/PaymentRoutes.scala index 38a75d7..971f2bb 100644 --- a/core/src/main/scala/app/softnetwork/payment/launch/PaymentRoutes.scala +++ b/core/src/main/scala/app/softnetwork/payment/launch/PaymentRoutes.scala @@ -9,7 +9,7 @@ import app.softnetwork.account.model.{ DefaultProfileView } import app.softnetwork.api.server.ApiRoute -import app.softnetwork.payment.model.SoftPaymentAccount +import app.softnetwork.payment.model.SoftPayAccount import app.softnetwork.payment.serialization.paymentFormats import app.softnetwork.payment.service.PaymentService import app.softnetwork.persistence.schema.SchemaProvider @@ -19,7 +19,7 @@ import org.json4s.Formats trait PaymentRoutes[SD <: SessionData with SessionDataDecorator[SD]] extends AccountRoutes[ - SoftPaymentAccount, + SoftPayAccount, BasicAccountProfile, DefaultProfileView, DefaultAccountDetailsView, diff --git a/core/src/main/scala/app/softnetwork/payment/persistence/typed/PaymentBehavior.scala b/core/src/main/scala/app/softnetwork/payment/persistence/typed/PaymentBehavior.scala index 4331646..13b28f6 100644 --- a/core/src/main/scala/app/softnetwork/payment/persistence/typed/PaymentBehavior.scala +++ b/core/src/main/scala/app/softnetwork/payment/persistence/typed/PaymentBehavior.scala @@ -9,7 +9,7 @@ import app.softnetwork.payment.annotation.InternalApi import app.softnetwork.payment.api.config.SoftPayClientSettings import app.softnetwork.payment.config.PaymentSettings import app.softnetwork.payment.config.PaymentSettings.{AkkaNodeRole, PayInStatementDescriptor} -import app.softnetwork.payment.handlers.{PaymentDao, PaymentKvDao, SoftPaymentAccountDao} +import app.softnetwork.payment.handlers.{PaymentDao, PaymentKvDao, SoftPayAccountDao} import app.softnetwork.payment.message.PaymentEvents._ import app.softnetwork.payment.message.PaymentMessages._ import app.softnetwork.payment.message.TransactionEvents._ @@ -57,7 +57,7 @@ trait PaymentBehavior def paymentDao: PaymentDao = PaymentDao - def softPaymentAccountDao: SoftPaymentAccountDao = SoftPaymentAccountDao + def softPayAccountDao: SoftPayAccountDao = SoftPayAccountDao /** @return * node role required to start this actor @@ -4145,7 +4145,7 @@ trait PaymentBehavior )(implicit system: ActorSystem[_]): PaymentProvider = { PaymentProviders.paymentProvider( clientId - .flatMap(softPaymentAccountDao.loadProvider(_) complete () match { + .flatMap(softPayAccountDao.loadProvider(_) complete () match { case Success(s) => s case Failure(_) => None }) diff --git a/core/src/main/scala/app/softnetwork/payment/persistence/typed/SoftPaymentAccountBehavior.scala b/core/src/main/scala/app/softnetwork/payment/persistence/typed/SoftPayAccountBehavior.scala similarity index 88% rename from core/src/main/scala/app/softnetwork/payment/persistence/typed/SoftPaymentAccountBehavior.scala rename to core/src/main/scala/app/softnetwork/payment/persistence/typed/SoftPayAccountBehavior.scala index 6df6b38..f99514a 100644 --- a/core/src/main/scala/app/softnetwork/payment/persistence/typed/SoftPaymentAccountBehavior.scala +++ b/core/src/main/scala/app/softnetwork/payment/persistence/typed/SoftPayAccountBehavior.scala @@ -11,14 +11,14 @@ import app.softnetwork.account.persistence.typed.AccountBehavior import app.softnetwork.notification.message.ExternalEntityToNotificationEvent import app.softnetwork.payment.cli.Main import app.softnetwork.payment.message.AccountMessages -import app.softnetwork.payment.message.AccountMessages.SoftPaymentSignUp -import app.softnetwork.payment.message.SoftPaymentAccountEvents.{ - SoftPaymentAccountCreatedEvent, - SoftPaymentAccountProviderRegisteredEvent, - SoftPaymentAccountTokenRefreshedEvent, - SoftPaymentAccountTokenRegisteredEvent +import app.softnetwork.payment.message.AccountMessages.SoftPaySignUp +import app.softnetwork.payment.message.SoftPayAccountEvents.{ + SoftPayAccountCreatedEvent, + SoftPayAccountProviderRegisteredEvent, + SoftPayAccountTokenRefreshedEvent, + SoftPayAccountTokenRegisteredEvent } -import app.softnetwork.payment.model.SoftPaymentAccount +import app.softnetwork.payment.model.SoftPayAccount import app.softnetwork.payment.spi.PaymentProviders import app.softnetwork.persistence.typed._ import app.softnetwork.scheduler.message.SchedulerEvents.ExternalSchedulerEvent @@ -28,17 +28,17 @@ import org.slf4j.Logger import java.time.Instant -trait SoftPaymentAccountBehavior extends AccountBehavior[SoftPaymentAccount, BasicAccountProfile] { +trait SoftPayAccountBehavior extends AccountBehavior[SoftPayAccount, BasicAccountProfile] { _: Generator => override protected def createAccount( entityId: String, cmd: SignUp - )(implicit context: ActorContext[AccountCommand]): Option[SoftPaymentAccount] = { + )(implicit context: ActorContext[AccountCommand]): Option[SoftPayAccount] = { cmd match { - case SoftPaymentSignUp(_, _, provider, _, _) => + case SoftPaySignUp(_, _, provider, _, _) => PaymentProviders.paymentProvider(provider).client match { case Some(client) => - SoftPaymentAccount(BasicAccount(cmd, Some(entityId))) + SoftPayAccount(BasicAccount(cmd, Some(entityId))) .map(account => account .withClients(Seq(client.withClientApiKey(client.generateApiKey()))) @@ -50,7 +50,7 @@ trait SoftPaymentAccountBehavior extends AccountBehavior[SoftPaymentAccount, Bas ) case _ => None } - case _ => SoftPaymentAccount(BasicAccount(cmd, Some(entityId))) + case _ => SoftPayAccount(BasicAccount(cmd, Some(entityId))) } } @@ -62,9 +62,9 @@ trait SoftPaymentAccountBehavior extends AccountBehavior[SoftPaymentAccount, Bas BasicAccountProfileUpdatedEvent(uuid, profile, loginUpdated) override protected def createAccountCreatedEvent( - account: SoftPaymentAccount - )(implicit context: ActorContext[AccountCommand]): AccountCreatedEvent[SoftPaymentAccount] = - SoftPaymentAccountCreatedEvent(account) + account: SoftPayAccount + )(implicit context: ActorContext[AccountCommand]): AccountCreatedEvent[SoftPayAccount] = + SoftPayAccountCreatedEvent(account) /** @param entityId * - entity identity @@ -79,13 +79,13 @@ trait SoftPaymentAccountBehavior extends AccountBehavior[SoftPaymentAccount, Bas */ override def handleCommand( entityId: String, - state: Option[SoftPaymentAccount], + state: Option[SoftPayAccount], command: AccountCommand, replyTo: Option[ActorRef[AccountCommandResult]], timers: TimerScheduler[AccountCommand] )(implicit context: ActorContext[AccountCommand] - ): Effect[ExternalSchedulerEvent, Option[SoftPaymentAccount]] = { + ): Effect[ExternalSchedulerEvent, Option[SoftPayAccount]] = { implicit val system: ActorSystem[_] = context.system command match { case AccountMessages.RegisterProvider(provider) => @@ -117,7 +117,7 @@ trait SoftPaymentAccountBehavior extends AccountBehavior[SoftPaymentAccount, Bas accountKeyDao.addAccountKey(updatedClient.clientId, entityId) Effect .persist( - SoftPaymentAccountProviderRegisteredEvent( + SoftPayAccountProviderRegisteredEvent( updatedClient, Instant.now() ) @@ -210,7 +210,7 @@ trait SoftPaymentAccountBehavior extends AccountBehavior[SoftPaymentAccount, Bas accountKeyDao.addAccountKey(accessToken.refreshToken, entityId) Effect .persist( - SoftPaymentAccountTokenRegisteredEvent( + SoftPayAccountTokenRegisteredEvent( client.withAccessToken( accessToken.copy( token = sha256(accessToken.token), @@ -271,7 +271,7 @@ trait SoftPaymentAccountBehavior extends AccountBehavior[SoftPaymentAccount, Bas accountKeyDao.addAccountKey(accessToken.refreshToken, entityId) Effect .persist( - SoftPaymentAccountTokenRefreshedEvent( + SoftPayAccountTokenRefreshedEvent( client.withAccessToken( accessToken.copy( token = sha256(accessToken.token), @@ -338,7 +338,7 @@ trait SoftPaymentAccountBehavior extends AccountBehavior[SoftPaymentAccount, Bas } } - case AccountMessages.RegisterProviderAccount(provider) => + case AccountMessages.RegisterAccountWithProvider(provider) => state match { case Some(account) => val updatedClient = account.clients.find(_.clientId == provider.clientId) match { @@ -352,20 +352,20 @@ trait SoftPaymentAccountBehavior extends AccountBehavior[SoftPaymentAccount, Bas .persist( List( AccountActivatedEvent(entityId, Some(Instant.now())), - SoftPaymentAccountProviderRegisteredEvent( + SoftPayAccountProviderRegisteredEvent( updatedClient, Instant.now() ) ) ) .thenRun(state => - AccountMessages.ProviderAccountRegistered(state.getOrElse(account)) ~> replyTo + AccountMessages.AccountWithProviderRegistered(state.getOrElse(account)) ~> replyTo ) case _ => val account = provider.account accountKeyDao.addAccountKey(provider.clientId, entityId) - Effect.persist(SoftPaymentAccountCreatedEvent(account)).thenRun { state => - AccountMessages.ProviderAccountRegistered(state.getOrElse(account)) ~> replyTo + Effect.persist(SoftPayAccountCreatedEvent(account)).thenRun { state => + AccountMessages.AccountWithProviderRegistered(state.getOrElse(account)) ~> replyTo } } @@ -381,25 +381,25 @@ trait SoftPaymentAccountBehavior extends AccountBehavior[SoftPaymentAccount, Bas * new state */ override def handleEvent( - state: Option[SoftPaymentAccount], + state: Option[SoftPayAccount], event: ExternalSchedulerEvent - )(implicit context: ActorContext[_]): Option[SoftPaymentAccount] = { + )(implicit context: ActorContext[_]): Option[SoftPayAccount] = { event match { - case SoftPaymentAccountProviderRegisteredEvent(client, lastUpdated) => + case SoftPayAccountProviderRegisteredEvent(client, lastUpdated) => state.map(account => { account .withClients(account.clients.filterNot(_.clientId == client.clientId) :+ client) .withLastUpdated(lastUpdated) }) - case SoftPaymentAccountTokenRegisteredEvent(client, lastUpdated) => + case SoftPayAccountTokenRegisteredEvent(client, lastUpdated) => state.map(account => { account .withClients(account.clients.filterNot(_.clientId == client.clientId) :+ client) .withLastUpdated(lastUpdated) }) - case SoftPaymentAccountTokenRefreshedEvent(client, lastUpdated) => + case SoftPayAccountTokenRefreshedEvent(client, lastUpdated) => state.map(account => { account .withClients(account.clients.filterNot(_.clientId == client.clientId) :+ client) @@ -412,11 +412,11 @@ trait SoftPaymentAccountBehavior extends AccountBehavior[SoftPaymentAccount, Bas private def inactiveAccount( entityId: String, - account: SoftPaymentAccount, + account: SoftPayAccount, replyTo: Option[ActorRef[AccountCommandResult]] )(implicit context: ActorContext[_] - ): Effect[ExternalEntityToNotificationEvent, Option[SoftPaymentAccount]] = { + ): Effect[ExternalEntityToNotificationEvent, Option[SoftPayAccount]] = { implicit val log: Logger = context.log implicit val system: ActorSystem[Nothing] = context.system def help(token: String): String = { @@ -457,6 +457,6 @@ trait SoftPaymentAccountBehavior extends AccountBehavior[SoftPaymentAccount, Bas } } -case object SoftPaymentAccountBehavior extends SoftPaymentAccountBehavior with DefaultGenerator { - override def persistenceId: String = "SoftPaymentAccount" +case object SoftPayAccountBehavior extends SoftPayAccountBehavior with DefaultGenerator { + override def persistenceId: String = "SoftPayAccount" } diff --git a/core/src/main/scala/app/softnetwork/payment/service/CardPaymentEndpoints.scala b/core/src/main/scala/app/softnetwork/payment/service/CardPaymentEndpoints.scala index c7cd679..3ef1527 100644 --- a/core/src/main/scala/app/softnetwork/payment/service/CardPaymentEndpoints.scala +++ b/core/src/main/scala/app/softnetwork/payment/service/CardPaymentEndpoints.scala @@ -3,7 +3,7 @@ package app.softnetwork.payment.service import app.softnetwork.payment.config.PaymentSettings import app.softnetwork.payment.handlers.PaymentHandler import app.softnetwork.payment.message.PaymentMessages._ -import app.softnetwork.payment.model.SoftPaymentAccount +import app.softnetwork.payment.model.SoftPayAccount import app.softnetwork.session.model.{SessionData, SessionDataDecorator} import sttp.capabilities import sttp.capabilities.akka.AkkaStreams @@ -21,7 +21,7 @@ trait CardPaymentEndpoints[SD <: SessionData with SessionDataDecorator[SD]] { def payment(payment: Payment): PartialServerEndpointWithSecurityOutput[ (Seq[Option[String]], Option[String], Method, Option[String]), - (Option[SoftPaymentAccount.Client], SD), + (Option[SoftPayAccount.SoftPayClient], SD), (Option[String], Option[String], Option[String], Option[String], Payment), Any, (Seq[Option[String]], Option[CookieValueWithMeta]), diff --git a/core/src/main/scala/app/softnetwork/payment/service/ClientSession.scala b/core/src/main/scala/app/softnetwork/payment/service/ClientSession.scala index f3483d4..96193a8 100644 --- a/core/src/main/scala/app/softnetwork/payment/service/ClientSession.scala +++ b/core/src/main/scala/app/softnetwork/payment/service/ClientSession.scala @@ -1,8 +1,8 @@ package app.softnetwork.payment.service import app.softnetwork.concurrent.Completion -import app.softnetwork.payment.handlers.SoftPaymentAccountDao -import app.softnetwork.payment.model.{computeExternalUuidWithProfile, SoftPaymentAccount} +import app.softnetwork.payment.handlers.SoftPayAccountDao +import app.softnetwork.payment.model.{computeExternalUuidWithProfile, SoftPayAccount} import app.softnetwork.session.model.{SessionData, SessionDataCompanion, SessionDataDecorator} import app.softnetwork.session.service.SessionMaterials import org.softnetwork.session.model.ApiKey @@ -15,13 +15,13 @@ import scala.util.{Failure, Success} trait ClientSession[SD <: SessionData with SessionDataDecorator[SD]] extends Completion { self: SessionMaterials[SD] => - def softPaymentAccountDao: SoftPaymentAccountDao = SoftPaymentAccountDao + def softPayAccountDao: SoftPayAccountDao = SoftPayAccountDao implicit def sessionConfig: SessionConfig implicit def companion: SessionDataCompanion[SD] - implicit def toSession(client: SoftPaymentAccount.Client): SD = { + implicit def toSession(client: SoftPayAccount.SoftPayClient): SD = { var session = companion.newSession .withAdmin(false) .withAnonymous(false) @@ -31,14 +31,14 @@ trait ClientSession[SD <: SessionData with SessionDataDecorator[SD]] extends Com } def encodeClient( - client: SoftPaymentAccount.Client + client: SoftPayAccount.SoftPayClient ): String = { clientSessionManager(client).clientSessionManager.encode(client) } def decodeClient(data: String): Option[SD] = manager.clientSessionManager.decode(data).toOption - def clientSessionManager(client: SoftPaymentAccount.Client): SessionManager[SD] = { + def clientSessionManager(client: SoftPayAccount.SoftPayClient): SessionManager[SD] = { implicit val innerSessionConfig: SessionConfig = sessionConfig.copy( jwt = sessionConfig.jwt.copy( @@ -60,7 +60,7 @@ trait ClientSession[SD <: SessionData with SessionDataDecorator[SD]] extends Com def sessionManager(clientId: Option[String]): SessionManager[SD] = { clientId match { case Some(id) => - softPaymentAccountDao.loadClient(id) complete () match { + softPayAccountDao.loadClient(id) complete () match { case Success(s) => clientSessionManager(s) case Failure(_) => manager } @@ -68,7 +68,7 @@ trait ClientSession[SD <: SessionData with SessionDataDecorator[SD]] extends Com } } - def clientSessionManager(client: Option[SoftPaymentAccount.Client]): SessionManager[SD] = { + def clientSessionManager(client: Option[SoftPayAccount.SoftPayClient]): SessionManager[SD] = { client match { case Some(c) => implicit val innerSessionConfig: SessionConfig = @@ -84,7 +84,7 @@ trait ClientSession[SD <: SessionData with SessionDataDecorator[SD]] extends Com } def loadApiKey(clientId: String): Future[Option[ApiKey]] = - softPaymentAccountDao.loadApiKey(clientId) + softPayAccountDao.loadApiKey(clientId) protected[payment] def externalUuidWithProfile(session: SD): String = computeExternalUuidWithProfile(session.id, session.profile) diff --git a/core/src/main/scala/app/softnetwork/payment/service/ClientSessionDirectives.scala b/core/src/main/scala/app/softnetwork/payment/service/ClientSessionDirectives.scala index 9be5cfc..53db4fc 100644 --- a/core/src/main/scala/app/softnetwork/payment/service/ClientSessionDirectives.scala +++ b/core/src/main/scala/app/softnetwork/payment/service/ClientSessionDirectives.scala @@ -5,7 +5,7 @@ import akka.http.scaladsl.server.{Directive1, Route} import akka.http.scaladsl.server.directives.Credentials import app.softnetwork.account.config.AccountSettings import app.softnetwork.payment.annotation.InternalApi -import app.softnetwork.payment.model.SoftPaymentAccount +import app.softnetwork.payment.model.SoftPayAccount import app.softnetwork.session.model.{SessionData, SessionDataDecorator} import app.softnetwork.session.service.{SessionMaterials, SessionService} @@ -17,12 +17,12 @@ trait ClientSessionDirectives[SD <: SessionData with SessionDataDecorator[SD]] _: SessionMaterials[SD] => @InternalApi - private[payment] def clientDirective: Directive1[Option[SoftPaymentAccount.Client]] = + private[payment] def clientDirective: Directive1[Option[SoftPayAccount.SoftPayClient]] = authenticateOAuth2Async(AccountSettings.Realm, oauthClient).optional @InternalApi private[payment] def requiredClientSession( - body: (Option[SoftPaymentAccount.Client], SD) => Route + body: (Option[SoftPayAccount.SoftPayClient], SD) => Route ): Route = clientDirective { client => requiredSession(sc(clientSessionManager(client)), gt) { session => @@ -32,7 +32,7 @@ trait ClientSessionDirectives[SD <: SessionData with SessionDataDecorator[SD]] @InternalApi private[payment] def optionalClientSession( - body: (Option[SoftPaymentAccount.Client], Option[SD]) => Route + body: (Option[SoftPayAccount.SoftPayClient], Option[SD]) => Route ): Route = clientDirective { client => optionalSession(sc(clientSessionManager(client)), gt) { session => @@ -41,8 +41,8 @@ trait ClientSessionDirectives[SD <: SessionData with SessionDataDecorator[SD]] } @InternalApi - private[payment] def oauthClient: Credentials => Future[Option[SoftPaymentAccount.Client]] = { - case _ @Credentials.Provided(token) => softPaymentAccountDao.authenticateClient(Some(token)) + private[payment] def oauthClient: Credentials => Future[Option[SoftPayAccount.SoftPayClient]] = { + case _ @Credentials.Provided(token) => softPayAccountDao.authenticateClient(Some(token)) case _ => Future.successful(None) } diff --git a/core/src/main/scala/app/softnetwork/payment/service/ClientSessionEndpoints.scala b/core/src/main/scala/app/softnetwork/payment/service/ClientSessionEndpoints.scala index c62b6af..277e409 100644 --- a/core/src/main/scala/app/softnetwork/payment/service/ClientSessionEndpoints.scala +++ b/core/src/main/scala/app/softnetwork/payment/service/ClientSessionEndpoints.scala @@ -2,7 +2,7 @@ package app.softnetwork.payment.service import app.softnetwork.account.config.AccountSettings import app.softnetwork.payment.annotation.InternalApi -import app.softnetwork.payment.model.SoftPaymentAccount +import app.softnetwork.payment.model.SoftPayAccount import app.softnetwork.session.model.{SessionData, SessionDataDecorator} import app.softnetwork.session.service.{SessionEndpoints, SessionMaterials} import com.softwaremill.session.{ @@ -38,7 +38,7 @@ trait ClientSessionEndpoints[SD <: SessionData with SessionDataDecorator[SD]] @InternalApi private[payment] def requiredClientSession: PartialServerEndpointWithSecurityOutput[Seq[ Option[String] - ], (Option[SoftPaymentAccount.Client], SD), Unit, Unit, Seq[ + ], (Option[SoftPayAccount.SoftPayClient], SD), Unit, Unit, Seq[ Option[String] ], Unit, Any, Future] = { val partial = clientSession(Some(true)) @@ -59,7 +59,7 @@ trait ClientSessionEndpoints[SD <: SessionData with SessionDataDecorator[SD]] @InternalApi private[payment] def optionalClientSession: PartialServerEndpointWithSecurityOutput[Seq[ Option[String] - ], (Option[SoftPaymentAccount.Client], Option[SD]), Unit, Unit, Seq[ + ], (Option[SoftPayAccount.SoftPayClient], Option[SD]), Unit, Unit, Seq[ Option[String] ], Unit, Any, Future] = { val partial = clientSession(Some(false)) @@ -78,7 +78,7 @@ trait ClientSessionEndpoints[SD <: SessionData with SessionDataDecorator[SD]] required: Option[Boolean] ): PartialServerEndpointWithSecurityOutput[Seq[ Option[String] - ], (Option[SoftPaymentAccount.Client], SessionResult[SD]), Unit, Unit, Seq[ + ], (Option[SoftPayAccount.SoftPayClient], SessionResult[SD]), Unit, Unit, Seq[ Option[String] ], Unit, Any, Future] = { val partial = sc.session(gt, required) @@ -89,7 +89,7 @@ trait ClientSessionEndpoints[SD <: SessionData with SessionDataDecorator[SD]] ) .out(partial.securityOutput) .serverSecurityLogicWithOutput { inputs => - softPaymentAccountDao.authenticateClient(inputs.head) flatMap { client => + softPayAccountDao.authenticateClient(inputs.head) flatMap { client => implicit val manager: SessionManager[SD] = clientSessionManager(client) sessionType match { case Session.SessionType.OneOffCookie | Session.SessionType.OneOffHeader => // oneOff diff --git a/core/src/main/scala/app/softnetwork/payment/service/RootPaymentEndpoints.scala b/core/src/main/scala/app/softnetwork/payment/service/RootPaymentEndpoints.scala index 169a7e9..58f4005 100644 --- a/core/src/main/scala/app/softnetwork/payment/service/RootPaymentEndpoints.scala +++ b/core/src/main/scala/app/softnetwork/payment/service/RootPaymentEndpoints.scala @@ -5,7 +5,7 @@ import app.softnetwork.api.server.ApiErrors import app.softnetwork.payment.config.PaymentSettings import app.softnetwork.payment.handlers.PaymentHandler import app.softnetwork.payment.message.PaymentMessages._ -import app.softnetwork.payment.model.SoftPaymentAccount +import app.softnetwork.payment.model.SoftPayAccount import app.softnetwork.payment.serialization.paymentFormats import app.softnetwork.session.model.{SessionData, SessionDataDecorator} import app.softnetwork.session.service.{ServiceWithSessionEndpoints, SessionMaterials} @@ -36,7 +36,7 @@ trait RootPaymentEndpoints[SD <: SessionData with SessionDataDecorator[SD]] lazy val requiredSessionEndpoint: PartialServerEndpointWithSecurityOutput[ (Seq[Option[String]], Option[String], Method, Option[String]), - (Option[SoftPaymentAccount.Client], SD), + (Option[SoftPayAccount.SoftPayClient], SD), Unit, Any, (Seq[Option[String]], Option[CookieValueWithMeta]), @@ -54,7 +54,7 @@ trait RootPaymentEndpoints[SD <: SessionData with SessionDataDecorator[SD]] lazy val optionalSessionEndpoint: PartialServerEndpointWithSecurityOutput[ (Seq[Option[String]], Option[String], Method, Option[String]), - (Option[SoftPaymentAccount.Client], Option[SD]), + (Option[SoftPayAccount.SoftPayClient], Option[SD]), Unit, Any, (Seq[Option[String]], Option[CookieValueWithMeta]), diff --git a/core/src/main/scala/app/softnetwork/payment/service/SoftPaymentAccountService.scala b/core/src/main/scala/app/softnetwork/payment/service/SoftPayAccountService.scala similarity index 84% rename from core/src/main/scala/app/softnetwork/payment/service/SoftPaymentAccountService.scala rename to core/src/main/scala/app/softnetwork/payment/service/SoftPayAccountService.scala index 37b58ca..245d9a8 100644 --- a/core/src/main/scala/app/softnetwork/payment/service/SoftPaymentAccountService.scala +++ b/core/src/main/scala/app/softnetwork/payment/service/SoftPayAccountService.scala @@ -3,7 +3,7 @@ package app.softnetwork.payment.service import akka.http.scaladsl.server.Route import app.softnetwork.account.config.AccountSettings import app.softnetwork.account.service.BasicAccountService -import app.softnetwork.payment.handlers.SoftPaymentAccountTypeKey +import app.softnetwork.payment.handlers.SoftPayAccountTypeKey import app.softnetwork.payment.serialization.paymentFormats import app.softnetwork.session.config.Settings import app.softnetwork.session.model.{SessionData, SessionDataDecorator} @@ -11,9 +11,9 @@ import app.softnetwork.session.service.SessionMaterials import com.softwaremill.session.SessionConfig import org.json4s.Formats -trait SoftPaymentAccountService[SD <: SessionData with SessionDataDecorator[SD]] +trait SoftPayAccountService[SD <: SessionData with SessionDataDecorator[SD]] extends BasicAccountService[SD] - with SoftPaymentAccountTypeKey { + with SoftPayAccountTypeKey { _: SessionMaterials[SD] => implicit def sessionConfig: SessionConfig = Settings.Session.DefaultSessionConfig diff --git a/core/src/main/scala/app/softnetwork/payment/service/SoftPaymentAccountServiceEndpoints.scala b/core/src/main/scala/app/softnetwork/payment/service/SoftPayAccountServiceEndpoints.scala similarity index 84% rename from core/src/main/scala/app/softnetwork/payment/service/SoftPaymentAccountServiceEndpoints.scala rename to core/src/main/scala/app/softnetwork/payment/service/SoftPayAccountServiceEndpoints.scala index d4b20c4..17feef1 100644 --- a/core/src/main/scala/app/softnetwork/payment/service/SoftPaymentAccountServiceEndpoints.scala +++ b/core/src/main/scala/app/softnetwork/payment/service/SoftPayAccountServiceEndpoints.scala @@ -1,7 +1,7 @@ package app.softnetwork.payment.service import app.softnetwork.account.service.BasicAccountServiceEndpoints -import app.softnetwork.payment.handlers.SoftPaymentAccountTypeKey +import app.softnetwork.payment.handlers.SoftPayAccountTypeKey import app.softnetwork.payment.serialization.paymentFormats import app.softnetwork.session.config.Settings import app.softnetwork.session.model.{SessionData, SessionDataDecorator} @@ -14,9 +14,9 @@ import sttp.tapir.server.ServerEndpoint import scala.concurrent.Future -trait SoftPaymentAccountServiceEndpoints[SD <: SessionData with SessionDataDecorator[SD]] +trait SoftPayAccountServiceEndpoints[SD <: SessionData with SessionDataDecorator[SD]] extends BasicAccountServiceEndpoints[SD] - with SoftPaymentAccountTypeKey { _: SessionMaterials[SD] => + with SoftPayAccountTypeKey { _: SessionMaterials[SD] => implicit def sessionConfig: SessionConfig = Settings.Session.DefaultSessionConfig diff --git a/core/src/main/scala/app/softnetwork/payment/service/SoftPaymentOAuthService.scala b/core/src/main/scala/app/softnetwork/payment/service/SoftPayOAuthService.scala similarity index 95% rename from core/src/main/scala/app/softnetwork/payment/service/SoftPaymentOAuthService.scala rename to core/src/main/scala/app/softnetwork/payment/service/SoftPayOAuthService.scala index 599fa54..75bbb42 100644 --- a/core/src/main/scala/app/softnetwork/payment/service/SoftPaymentOAuthService.scala +++ b/core/src/main/scala/app/softnetwork/payment/service/SoftPayOAuthService.scala @@ -11,7 +11,7 @@ import app.softnetwork.account.message.{ Tokens } import app.softnetwork.account.service.OAuthService -import app.softnetwork.payment.handlers.SoftPaymentAccountTypeKey +import app.softnetwork.payment.handlers.SoftPayAccountTypeKey import app.softnetwork.payment.message.AccountMessages.{GenerateClientToken, RefreshClientToken} import app.softnetwork.payment.serialization.paymentFormats import app.softnetwork.session.config.Settings @@ -20,9 +20,9 @@ import app.softnetwork.session.service.SessionMaterials import com.softwaremill.session.SessionConfig import org.json4s.Formats -trait SoftPaymentOAuthService[SD <: SessionData with SessionDataDecorator[SD]] +trait SoftPayOAuthService[SD <: SessionData with SessionDataDecorator[SD]] extends OAuthService[SD] - with SoftPaymentAccountTypeKey + with SoftPayAccountTypeKey with ClientSessionDirectives[SD] { _: SessionMaterials[SD] => diff --git a/core/src/main/scala/app/softnetwork/payment/service/SoftPaymentOAuthServiceEndpoints.scala b/core/src/main/scala/app/softnetwork/payment/service/SoftPayOAuthServiceEndpoints.scala similarity index 97% rename from core/src/main/scala/app/softnetwork/payment/service/SoftPaymentOAuthServiceEndpoints.scala rename to core/src/main/scala/app/softnetwork/payment/service/SoftPayOAuthServiceEndpoints.scala index cdfdae9..252613a 100644 --- a/core/src/main/scala/app/softnetwork/payment/service/SoftPaymentOAuthServiceEndpoints.scala +++ b/core/src/main/scala/app/softnetwork/payment/service/SoftPayOAuthServiceEndpoints.scala @@ -11,7 +11,7 @@ import app.softnetwork.account.message.{ } import app.softnetwork.account.service.OAuthServiceEndpoints import app.softnetwork.api.server.ApiErrors -import app.softnetwork.payment.handlers.SoftPaymentAccountTypeKey +import app.softnetwork.payment.handlers.SoftPayAccountTypeKey import app.softnetwork.payment.message.AccountMessages.{ GenerateClientToken, OAuthClient, @@ -34,9 +34,9 @@ import sttp.tapir.server.ServerEndpoint import scala.concurrent.Future -trait SoftPaymentOAuthServiceEndpoints[SD <: SessionData with SessionDataDecorator[SD]] +trait SoftPayOAuthServiceEndpoints[SD <: SessionData with SessionDataDecorator[SD]] extends OAuthServiceEndpoints[SD] - with SoftPaymentAccountTypeKey + with SoftPayAccountTypeKey with ClientSession[SD] { _: SessionMaterials[SD] => import app.softnetwork.serialization.serialization diff --git a/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayApi.scala b/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayApi.scala index d555cd1..7fa29f8 100644 --- a/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayApi.scala +++ b/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayApi.scala @@ -5,17 +5,17 @@ import app.softnetwork.account.config.AccountSettings import app.softnetwork.account.persistence.query.AccountEventProcessorStreams.InternalAccountEvents2AccountProcessorStream import app.softnetwork.api.server.SwaggerEndpoint import app.softnetwork.payment.config.PaymentSettings -import app.softnetwork.payment.handlers.{PaymentHandler, SoftPaymentAccountTypeKey} +import app.softnetwork.payment.handlers.{PaymentHandler, SoftPayAccountTypeKey} import app.softnetwork.payment.launch.PaymentApplication import app.softnetwork.payment.persistence.query.{ PaymentCommandProcessorStream, Scheduler2PaymentProcessorStream } -import app.softnetwork.payment.persistence.typed.{PaymentBehavior, SoftPaymentAccountBehavior} +import app.softnetwork.payment.persistence.typed.{PaymentBehavior, SoftPayAccountBehavior} import app.softnetwork.payment.service.{ MangoPayPaymentServiceEndpoints, - SoftPaymentAccountServiceEndpoints, - SoftPaymentOAuthServiceEndpoints + SoftPayAccountServiceEndpoints, + SoftPayOAuthServiceEndpoints } import app.softnetwork.persistence.jdbc.query.{JdbcJournalProvider, JdbcOffsetProvider} import app.softnetwork.persistence.schema.SchemaProvider @@ -43,11 +43,11 @@ trait MangoPayApi[SD <: SessionData with SessionDataDecorator[SD]] extends Payme override def internalAccountEvents2AccountProcessorStream : ActorSystem[_] => InternalAccountEvents2AccountProcessorStream = sys => new InternalAccountEvents2AccountProcessorStream - with SoftPaymentAccountTypeKey + with SoftPayAccountTypeKey with JdbcJournalProvider with JdbcOffsetProvider { override def config: Config = MangoPayApi.this.config - override def tag: String = s"${SoftPaymentAccountBehavior.persistenceId}-to-internal" + override def tag: String = s"${SoftPayAccountBehavior.persistenceId}-to-internal" override implicit def system: ActorSystem[_] = sys } @@ -103,7 +103,7 @@ trait MangoPayApi[SD <: SessionData with SessionDataDecorator[SD]] extends Payme } def accountSwagger: ActorSystem[_] => SwaggerEndpoint = sys => - new SoftPaymentAccountServiceEndpoints[SD] with SwaggerEndpoint with SessionMaterials[SD] { + new SoftPayAccountServiceEndpoints[SD] with SwaggerEndpoint with SessionMaterials[SD] { lazy val log: Logger = LoggerFactory getLogger getClass.getName override implicit def system: ActorSystem[_] = sys override implicit lazy val ec: ExecutionContext = sys.executionContext @@ -124,7 +124,7 @@ trait MangoPayApi[SD <: SessionData with SessionDataDecorator[SD]] extends Payme def oauthSwagger: ActorSystem[_] => SwaggerEndpoint = sys => - new SoftPaymentOAuthServiceEndpoints[SD] with SwaggerEndpoint with SessionMaterials[SD] { + new SoftPayOAuthServiceEndpoints[SD] with SwaggerEndpoint with SessionMaterials[SD] { override implicit def system: ActorSystem[_] = sys override implicit lazy val ec: ExecutionContext = sys.executionContext override protected def sessionType: Session.SessionType = self.sessionType diff --git a/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayEndpoints.scala b/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayEndpoints.scala index 1a4e059..b9b9bb7 100644 --- a/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayEndpoints.scala +++ b/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayEndpoints.scala @@ -8,8 +8,8 @@ import app.softnetwork.payment.launch.PaymentEndpoints import app.softnetwork.payment.service.{ MangoPayPaymentServiceEndpoints, PaymentServiceEndpoints, - SoftPaymentAccountServiceEndpoints, - SoftPaymentOAuthServiceEndpoints + SoftPayAccountServiceEndpoints, + SoftPayOAuthServiceEndpoints } import app.softnetwork.persistence.schema.SchemaProvider import app.softnetwork.session.CsrfCheck @@ -42,7 +42,7 @@ trait MangoPayEndpoints[SD <: SessionData with SessionDataDecorator[SD]] override def accountEndpoints : ActorSystem[_] => AccountServiceEndpoints[message.BasicAccountSignUp, SD] = sys => - new SoftPaymentAccountServiceEndpoints[SD] with SessionMaterials[SD] { + new SoftPayAccountServiceEndpoints[SD] with SessionMaterials[SD] { override def log: org.slf4j.Logger = org.slf4j.LoggerFactory.getLogger(getClass) override implicit def system: ActorSystem[_] = sys override lazy val ec: ExecutionContext = sys.executionContext @@ -59,7 +59,7 @@ trait MangoPayEndpoints[SD <: SessionData with SessionDataDecorator[SD]] } override def oauthEndpoints: ActorSystem[_] => OAuthServiceEndpoints[SD] = sys => - new SoftPaymentOAuthServiceEndpoints[SD] with SessionMaterials[SD] { + new SoftPayOAuthServiceEndpoints[SD] with SessionMaterials[SD] { override def log: org.slf4j.Logger = org.slf4j.LoggerFactory.getLogger(getClass) override implicit def system: ActorSystem[_] = sys override lazy val ec: ExecutionContext = sys.executionContext diff --git a/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayEndpointsPostgresLauncher.scala b/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayEndpointsPostgresLauncher.scala index 3bbfd2b..c1f040b 100644 --- a/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayEndpointsPostgresLauncher.scala +++ b/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayEndpointsPostgresLauncher.scala @@ -1,7 +1,7 @@ package app.softnetwork.payment.api import akka.actor.typed.ActorSystem -import app.softnetwork.payment.handlers.SoftPaymentAccountDao +import app.softnetwork.payment.handlers.SoftPayAccountDao import app.softnetwork.payment.service.{MangoPayPaymentServiceEndpoints, PaymentServiceEndpoints} import app.softnetwork.persistence.jdbc.schema.{JdbcSchemaProvider, JdbcSchemaTypes} import app.softnetwork.persistence.schema.SchemaType diff --git a/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayRoutes.scala b/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayRoutes.scala index 103edb6..98ce1af 100644 --- a/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayRoutes.scala +++ b/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayRoutes.scala @@ -12,8 +12,8 @@ import app.softnetwork.payment.launch.PaymentRoutes import app.softnetwork.payment.service.{ MangoPayPaymentService, PaymentService, - SoftPaymentAccountService, - SoftPaymentOAuthService + SoftPayAccountService, + SoftPayOAuthService } import app.softnetwork.persistence.schema.SchemaProvider import app.softnetwork.session.CsrfCheck @@ -50,7 +50,7 @@ trait MangoPayRoutes[SD <: SessionData with SessionDataDecorator[SD]] extends Pa DefaultAccountView[DefaultProfileView, DefaultAccountDetailsView], SD ] = sys => - new SoftPaymentAccountService[SD] with SessionMaterials[SD] { + new SoftPayAccountService[SD] with SessionMaterials[SD] { override implicit def manager(implicit sessionConfig: SessionConfig, companion: SessionDataCompanion[SD] @@ -66,7 +66,7 @@ trait MangoPayRoutes[SD <: SessionData with SessionDataDecorator[SD]] extends Pa } override def oauthService: ActorSystem[_] => OAuthService[SD] = sys => - new SoftPaymentOAuthService[SD] with SessionMaterials[SD] { + new SoftPayOAuthService[SD] with SessionMaterials[SD] { override implicit def manager(implicit sessionConfig: SessionConfig, companion: SessionDataCompanion[SD] diff --git a/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayWithSchedulerEndpointsPostgresLauncher.scala b/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayWithSchedulerEndpointsPostgresLauncher.scala index 85ecd12..a3c5144 100644 --- a/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayWithSchedulerEndpointsPostgresLauncher.scala +++ b/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayWithSchedulerEndpointsPostgresLauncher.scala @@ -1,7 +1,7 @@ package app.softnetwork.payment.api import akka.actor.typed.ActorSystem -import app.softnetwork.payment.handlers.SoftPaymentAccountDao +import app.softnetwork.payment.handlers.SoftPayAccountDao import app.softnetwork.payment.service.{MangoPayPaymentServiceEndpoints, PaymentServiceEndpoints} import app.softnetwork.persistence.jdbc.schema.{JdbcSchemaProvider, JdbcSchemaTypes} import app.softnetwork.persistence.schema.SchemaType diff --git a/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayWithSchedulerRoutesPostgresLauncher.scala b/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayWithSchedulerRoutesPostgresLauncher.scala index ad57794..c65b4ac 100644 --- a/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayWithSchedulerRoutesPostgresLauncher.scala +++ b/mangopay/api/src/main/scala/app/softnetwork/payment/api/MangoPayWithSchedulerRoutesPostgresLauncher.scala @@ -1,7 +1,7 @@ package app.softnetwork.payment.api import akka.actor.typed.ActorSystem -import app.softnetwork.payment.handlers.SoftPaymentAccountDao +import app.softnetwork.payment.handlers.SoftPayAccountDao import app.softnetwork.payment.service.{MangoPayPaymentService, PaymentService} import app.softnetwork.persistence.jdbc.schema.{JdbcSchemaProvider, JdbcSchemaTypes} import app.softnetwork.persistence.schema.SchemaType diff --git a/mangopay/src/main/scala/app/softnetwork/payment/config/MangoPay.scala b/mangopay/src/main/scala/app/softnetwork/payment/config/MangoPay.scala index 9dffa74..9a3c112 100644 --- a/mangopay/src/main/scala/app/softnetwork/payment/config/MangoPay.scala +++ b/mangopay/src/main/scala/app/softnetwork/payment/config/MangoPay.scala @@ -1,7 +1,7 @@ package app.softnetwork.payment.config import MangoPaySettings._ -import app.softnetwork.payment.model.SoftPaymentAccount +import app.softnetwork.payment.model.SoftPayAccount import com.mangopay.MangoPayApi import com.mangopay.core.enumerations.{EventType, HookStatus} import com.mangopay.entities.Hook @@ -43,13 +43,13 @@ object MangoPay extends StrictLogging { var mangoPayApis: Map[String, MangoPayApi] = Map.empty - lazy val softPaymentProvider: SoftPaymentAccount.Client.Provider = - SoftPaymentAccount.Client.Provider.defaultInstance - .withProviderType(SoftPaymentAccount.Client.Provider.ProviderType.MANGOPAY) + lazy val softPayProvider: SoftPayAccount.SoftPayClient.SoftPayProvider = + SoftPayAccount.SoftPayClient.SoftPayProvider.defaultInstance + .withProviderType(SoftPayAccount.SoftPayClient.SoftPayProvider.SoftPayProviderType.MANGOPAY) .withProviderId(MangoPaySettings.MangoPayConfig.clientId) .withProviderApiKey(MangoPaySettings.MangoPayConfig.apiKey) - def apply(provider: SoftPaymentAccount.Client.Provider): MangoPayApi = { + def apply(provider: SoftPayAccount.SoftPayClient.SoftPayProvider): MangoPayApi = { mangoPayApis.get(provider.providerId) match { case Some(mangoPayApi) => mangoPayApi case _ => diff --git a/mangopay/src/main/scala/app/softnetwork/payment/spi/MangoPayProvider.scala b/mangopay/src/main/scala/app/softnetwork/payment/spi/MangoPayProvider.scala index 121b398..9b6823f 100644 --- a/mangopay/src/main/scala/app/softnetwork/payment/spi/MangoPayProvider.scala +++ b/mangopay/src/main/scala/app/softnetwork/payment/spi/MangoPayProvider.scala @@ -24,7 +24,7 @@ import app.softnetwork.payment.model.{RecurringPayment, _} import app.softnetwork.payment.config.{MangoPay, MangoPaySettings} import app.softnetwork.payment.config.MangoPaySettings.MangoPayConfig._ import app.softnetwork.payment.model.NaturalUser.NaturalUserType -import app.softnetwork.payment.model.SoftPaymentAccount.Client.Provider +import app.softnetwork.payment.model.SoftPayAccount.SoftPayClient.SoftPayProvider import scala.util.{Failure, Success, Try} import app.softnetwork.persistence._ @@ -2082,11 +2082,11 @@ trait MangoPayProvider extends PaymentProvider { } } - override def client: Option[SoftPaymentAccount.Client] = { + override def client: Option[SoftPayAccount.SoftPayClient] = { Try(MangoPay(provider).getClientApi.get()) match { case Success(client) => Some( - SoftPaymentAccount.Client.defaultInstance + SoftPayAccount.SoftPayClient.defaultInstance .withClientId(client.getClientId + "." + provider.providerType.name.toLowerCase) .withProvider(provider) .copy( @@ -2593,13 +2593,14 @@ trait MangoPayProvider extends PaymentProvider { } class MangoPayProviderFactory extends PaymentProviderSpi { - override val providerType: Provider.ProviderType = Provider.ProviderType.MANGOPAY + override val providerType: SoftPayProvider.SoftPayProviderType = + SoftPayProvider.SoftPayProviderType.MANGOPAY - override def paymentProvider(p: SoftPaymentAccount.Client.Provider): MangoPayProvider = + override def paymentProvider(p: SoftPayAccount.SoftPayClient.SoftPayProvider): MangoPayProvider = new MangoPayProvider { - override implicit val provider: SoftPaymentAccount.Client.Provider = p + override implicit val provider: SoftPayAccount.SoftPayClient.SoftPayProvider = p } - override def softPaymentProvider: SoftPaymentAccount.Client.Provider = - MangoPay.softPaymentProvider + override def softPaymentProvider: SoftPayAccount.SoftPayClient.SoftPayProvider = + MangoPay.softPayProvider } diff --git a/testkit/src/main/scala/app/softnetwork/payment/api/MockClientServer.scala b/testkit/src/main/scala/app/softnetwork/payment/api/MockClientServer.scala index 6d3927b..7c038f6 100644 --- a/testkit/src/main/scala/app/softnetwork/payment/api/MockClientServer.scala +++ b/testkit/src/main/scala/app/softnetwork/payment/api/MockClientServer.scala @@ -1,10 +1,10 @@ package app.softnetwork.payment.api import akka.actor.typed.ActorSystem -import app.softnetwork.payment.handlers.MockSoftPaymentAccountDao +import app.softnetwork.payment.handlers.MockSoftPayAccountDao import org.slf4j.{Logger, LoggerFactory} -trait MockClientServer extends ClientServer with MockSoftPaymentAccountDao +trait MockClientServer extends ClientServer with MockSoftPayAccountDao object MockClientServer { def apply(sys: ActorSystem[_]): MockClientServer = { diff --git a/testkit/src/main/scala/app/softnetwork/payment/api/SoftPayClientTestKit.scala b/testkit/src/main/scala/app/softnetwork/payment/api/SoftPayClientTestKit.scala index 289d81b..7fefa59 100644 --- a/testkit/src/main/scala/app/softnetwork/payment/api/SoftPayClientTestKit.scala +++ b/testkit/src/main/scala/app/softnetwork/payment/api/SoftPayClientTestKit.scala @@ -1,14 +1,14 @@ package app.softnetwork.payment.api import app.softnetwork.payment.config.MangoPay -import app.softnetwork.payment.model.SoftPaymentAccount +import app.softnetwork.payment.model.SoftPayAccount import app.softnetwork.security.sha256 trait SoftPayClientTestKit { - def provider: SoftPaymentAccount.Client.Provider = - MangoPay.softPaymentProvider.withProviderType( - SoftPaymentAccount.Client.Provider.ProviderType.MOCK + def provider: SoftPayAccount.SoftPayClient.SoftPayProvider = + MangoPay.softPayProvider.withProviderType( + SoftPayAccount.SoftPayClient.SoftPayProvider.SoftPayProviderType.MOCK ) def softPayClientSettings: String = diff --git a/testkit/src/main/scala/app/softnetwork/payment/handlers/MockSoftPayAccountDao.scala b/testkit/src/main/scala/app/softnetwork/payment/handlers/MockSoftPayAccountDao.scala new file mode 100644 index 0000000..096d6d4 --- /dev/null +++ b/testkit/src/main/scala/app/softnetwork/payment/handlers/MockSoftPayAccountDao.scala @@ -0,0 +1,22 @@ +package app.softnetwork.payment.handlers + +import akka.cluster.sharding.typed.scaladsl.EntityTypeKey +import app.softnetwork.account.message.AccountCommand +import app.softnetwork.payment.persistence.typed.MockSoftPayAccountBehavior +import app.softnetwork.persistence.typed.CommandTypeKey +import org.slf4j.{Logger, LoggerFactory} + +import scala.reflect.ClassTag + +trait MockSoftPayAccountTypeKey extends CommandTypeKey[AccountCommand] { + override def TypeKey(implicit tTag: ClassTag[AccountCommand]): EntityTypeKey[AccountCommand] = + MockSoftPayAccountBehavior.TypeKey +} + +trait MockSoftPayAccountHandler extends SoftPayAccountHandler with MockSoftPayAccountTypeKey + +trait MockSoftPayAccountDao extends SoftPayAccountDao with MockSoftPayAccountTypeKey + +object MockSoftPayAccountDao extends MockSoftPayAccountDao { + lazy val log: Logger = LoggerFactory getLogger getClass.getName +} diff --git a/testkit/src/main/scala/app/softnetwork/payment/handlers/MockSoftPaymentAccountDao.scala b/testkit/src/main/scala/app/softnetwork/payment/handlers/MockSoftPaymentAccountDao.scala deleted file mode 100644 index 43567b0..0000000 --- a/testkit/src/main/scala/app/softnetwork/payment/handlers/MockSoftPaymentAccountDao.scala +++ /dev/null @@ -1,24 +0,0 @@ -package app.softnetwork.payment.handlers - -import akka.cluster.sharding.typed.scaladsl.EntityTypeKey -import app.softnetwork.account.message.AccountCommand -import app.softnetwork.payment.persistence.typed.MockSoftPaymentAccountBehavior -import app.softnetwork.persistence.typed.CommandTypeKey -import org.slf4j.{Logger, LoggerFactory} - -import scala.reflect.ClassTag - -trait MockSoftPaymentAccountTypeKey extends CommandTypeKey[AccountCommand] { - override def TypeKey(implicit tTag: ClassTag[AccountCommand]): EntityTypeKey[AccountCommand] = - MockSoftPaymentAccountBehavior.TypeKey -} - -trait MockSoftPaymentAccountHandler - extends SoftPaymentAccountHandler - with MockSoftPaymentAccountTypeKey - -trait MockSoftPaymentAccountDao extends SoftPaymentAccountDao with MockSoftPaymentAccountTypeKey - -object MockSoftPaymentAccountDao extends MockSoftPaymentAccountDao { - lazy val log: Logger = LoggerFactory getLogger getClass.getName -} diff --git a/testkit/src/main/scala/app/softnetwork/payment/persistence/typed/MockPaymentBehavior.scala b/testkit/src/main/scala/app/softnetwork/payment/persistence/typed/MockPaymentBehavior.scala index bcae61a..0040960 100644 --- a/testkit/src/main/scala/app/softnetwork/payment/persistence/typed/MockPaymentBehavior.scala +++ b/testkit/src/main/scala/app/softnetwork/payment/persistence/typed/MockPaymentBehavior.scala @@ -2,9 +2,9 @@ package app.softnetwork.payment.persistence.typed import app.softnetwork.payment.handlers.{ MockPaymentDao, - MockSoftPaymentAccountDao, + MockSoftPayAccountDao, PaymentDao, - SoftPaymentAccountDao + SoftPayAccountDao } object MockPaymentBehavior extends PaymentBehavior { @@ -12,6 +12,6 @@ object MockPaymentBehavior extends PaymentBehavior { override lazy val paymentDao: PaymentDao = MockPaymentDao - override lazy val softPaymentAccountDao: SoftPaymentAccountDao = MockSoftPaymentAccountDao + override lazy val softPayAccountDao: SoftPayAccountDao = MockSoftPayAccountDao } diff --git a/testkit/src/main/scala/app/softnetwork/payment/persistence/typed/MockSoftPayAccountBehavior.scala b/testkit/src/main/scala/app/softnetwork/payment/persistence/typed/MockSoftPayAccountBehavior.scala new file mode 100644 index 0000000..83ff837 --- /dev/null +++ b/testkit/src/main/scala/app/softnetwork/payment/persistence/typed/MockSoftPayAccountBehavior.scala @@ -0,0 +1,7 @@ +package app.softnetwork.payment.persistence.typed + +import app.softnetwork.account.handlers.MockGenerator + +object MockSoftPayAccountBehavior extends SoftPayAccountBehavior with MockGenerator { + override def persistenceId = "MockSoftPayAccount" +} diff --git a/testkit/src/main/scala/app/softnetwork/payment/persistence/typed/MockSoftPaymentAccountBehavior.scala b/testkit/src/main/scala/app/softnetwork/payment/persistence/typed/MockSoftPaymentAccountBehavior.scala deleted file mode 100644 index 64eceb5..0000000 --- a/testkit/src/main/scala/app/softnetwork/payment/persistence/typed/MockSoftPaymentAccountBehavior.scala +++ /dev/null @@ -1,7 +0,0 @@ -package app.softnetwork.payment.persistence.typed - -import app.softnetwork.account.handlers.MockGenerator - -object MockSoftPaymentAccountBehavior extends SoftPaymentAccountBehavior with MockGenerator { - override def persistenceId = "MockSoftPaymentAccount" -} diff --git a/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentEndpointsTestKit.scala b/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentEndpointsTestKit.scala index 3a76285..8459c4d 100644 --- a/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentEndpointsTestKit.scala +++ b/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentEndpointsTestKit.scala @@ -4,12 +4,12 @@ import akka.actor.typed.ActorSystem import app.softnetwork.account.message.BasicAccountSignUp import app.softnetwork.account.service.{AccountServiceEndpoints, OAuthServiceEndpoints} import app.softnetwork.api.server.Endpoint -import app.softnetwork.payment.handlers.{MockSoftPaymentAccountDao, SoftPaymentAccountDao} +import app.softnetwork.payment.handlers.{MockSoftPayAccountDao, SoftPayAccountDao} import app.softnetwork.payment.launch.PaymentEndpoints import app.softnetwork.payment.service.{ MockPaymentServiceEndpoints, - MockSoftPaymentAccountServiceEndpoints, - MockSoftPaymentOAuthServiceEndpoints, + MockSoftPayAccountServiceEndpoints, + MockSoftPayOAuthServiceEndpoints, PaymentServiceEndpoints } import app.softnetwork.persistence.schema.SchemaProvider @@ -45,7 +45,7 @@ trait PaymentEndpointsTestKit[SD <: SessionData with SessionDataDecorator[SD]] override implicit def sessionConfig: SessionConfig = self.sessionConfig override implicit def system: ActorSystem[_] = sys override lazy val ec: ExecutionContext = sys.executionContext - override def softPaymentAccountDao: SoftPaymentAccountDao = MockSoftPaymentAccountDao + override def softPayAccountDao: SoftPayAccountDao = MockSoftPayAccountDao override implicit def refreshTokenStorage: RefreshTokenStorage[SD] = self.refreshTokenStorage override implicit def companion: SessionDataCompanion[SD] = self.companion @@ -56,7 +56,7 @@ trait PaymentEndpointsTestKit[SD <: SessionData with SessionDataDecorator[SD]] override def accountEndpoints: ActorSystem[_] => AccountServiceEndpoints[BasicAccountSignUp, SD] = sys => - new MockSoftPaymentAccountServiceEndpoints[SD] with SessionMaterials[SD] { + new MockSoftPayAccountServiceEndpoints[SD] with SessionMaterials[SD] { override implicit def manager(implicit sessionConfig: SessionConfig, companion: SessionDataCompanion[SD] @@ -72,7 +72,7 @@ trait PaymentEndpointsTestKit[SD <: SessionData with SessionDataDecorator[SD]] } override def oauthEndpoints: ActorSystem[_] => OAuthServiceEndpoints[SD] = sys => - new MockSoftPaymentOAuthServiceEndpoints[SD] with SessionMaterials[SD] { + new MockSoftPayOAuthServiceEndpoints[SD] with SessionMaterials[SD] { override implicit def manager(implicit sessionConfig: SessionConfig, companion: SessionDataCompanion[SD] @@ -81,7 +81,7 @@ trait PaymentEndpointsTestKit[SD <: SessionData with SessionDataDecorator[SD]] override def log: Logger = LoggerFactory getLogger getClass.getName override implicit def system: ActorSystem[_] = sys override lazy val ec: ExecutionContext = sys.executionContext - override def softPaymentAccountDao: SoftPaymentAccountDao = MockSoftPaymentAccountDao + override def softPayAccountDao: SoftPayAccountDao = MockSoftPayAccountDao override implicit def refreshTokenStorage: RefreshTokenStorage[SD] = self.refreshTokenStorage override implicit def companion: SessionDataCompanion[SD] = self.companion diff --git a/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentRoutesTestKit.scala b/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentRoutesTestKit.scala index 71c6f8b..f23d157 100644 --- a/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentRoutesTestKit.scala +++ b/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentRoutesTestKit.scala @@ -8,12 +8,12 @@ import app.softnetwork.account.model.{ } import app.softnetwork.account.service.{AccountService, OAuthService} import app.softnetwork.api.server.ApiRoute -import app.softnetwork.payment.handlers.{MockSoftPaymentAccountDao, SoftPaymentAccountDao} +import app.softnetwork.payment.handlers.{MockSoftPayAccountDao, SoftPayAccountDao} import app.softnetwork.payment.launch.PaymentRoutes import app.softnetwork.payment.service.{ MockPaymentService, - MockSoftPaymentAccountService, - MockSoftPaymentOAuthService, + MockSoftPayAccountService, + MockSoftPayOAuthService, PaymentService } import app.softnetwork.persistence.schema.SchemaProvider @@ -42,7 +42,7 @@ trait PaymentRoutesTestKit[SD <: SessionData with SessionDataDecorator[SD]] override implicit def sessionConfig: SessionConfig = self.sessionConfig override implicit def system: ActorSystem[_] = sys override lazy val ec: ExecutionContext = sys.executionContext - override def softPaymentAccountDao: SoftPaymentAccountDao = MockSoftPaymentAccountDao + override def softPayAccountDao: SoftPayAccountDao = MockSoftPayAccountDao override implicit def refreshTokenStorage: RefreshTokenStorage[SD] = self.refreshTokenStorage override implicit def companion: SessionDataCompanion[SD] = self.companion @@ -56,7 +56,7 @@ trait PaymentRoutesTestKit[SD <: SessionData with SessionDataDecorator[SD]] DefaultAccountView[DefaultProfileView, DefaultAccountDetailsView], SD ] = sys => - new MockSoftPaymentAccountService[SD] with SessionMaterials[SD] { + new MockSoftPayAccountService[SD] with SessionMaterials[SD] { override implicit def manager(implicit sessionConfig: SessionConfig, companion: SessionDataCompanion[SD] @@ -72,7 +72,7 @@ trait PaymentRoutesTestKit[SD <: SessionData with SessionDataDecorator[SD]] } override def oauthService: ActorSystem[_] => OAuthService[SD] = sys => - new MockSoftPaymentOAuthService[SD] with SessionMaterials[SD] { + new MockSoftPayOAuthService[SD] with SessionMaterials[SD] { override implicit def manager(implicit sessionConfig: SessionConfig, companion: SessionDataCompanion[SD] @@ -82,7 +82,7 @@ trait PaymentRoutesTestKit[SD <: SessionData with SessionDataDecorator[SD]] // override implicit def sessionConfig: SessionConfig = self.sessionConfig override implicit def system: ActorSystem[_] = sys override lazy val ec: ExecutionContext = sys.executionContext - override def softPaymentAccountDao: SoftPaymentAccountDao = MockSoftPaymentAccountDao + override def softPayAccountDao: SoftPayAccountDao = MockSoftPayAccountDao override implicit def refreshTokenStorage: RefreshTokenStorage[SD] = self.refreshTokenStorage override implicit def companion: SessionDataCompanion[SD] = self.companion diff --git a/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentTestKit.scala b/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentTestKit.scala index de65dce..d50519e 100644 --- a/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentTestKit.scala +++ b/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentTestKit.scala @@ -16,9 +16,9 @@ import app.softnetwork.payment.api.{ import app.softnetwork.payment.config.PaymentSettings._ import app.softnetwork.payment.handlers.{ MockPaymentHandler, - MockSoftPaymentAccountDao, - MockSoftPaymentAccountHandler, - SoftPaymentAccountDao + MockSoftPayAccountDao, + MockSoftPayAccountHandler, + SoftPayAccountDao } import app.softnetwork.payment.launch.PaymentGuardian import app.softnetwork.payment.message.PaymentMessages._ @@ -29,7 +29,7 @@ import app.softnetwork.payment.persistence.query.{ } import app.softnetwork.payment.persistence.typed.{ MockPaymentBehavior, - MockSoftPaymentAccountBehavior, + MockSoftPayAccountBehavior, PaymentBehavior } import app.softnetwork.persistence.launch.PersistentEntity @@ -62,15 +62,15 @@ trait PaymentTestKit override def paymentBehavior: ActorSystem[_] => PaymentBehavior = _ => MockPaymentBehavior override def accountBehavior - : ActorSystem[_] => AccountBehavior[SoftPaymentAccount, BasicAccountProfile] = _ => - MockSoftPaymentAccountBehavior + : ActorSystem[_] => AccountBehavior[SoftPayAccount, BasicAccountProfile] = _ => + MockSoftPayAccountBehavior override def paymentServer: ActorSystem[_] => PaymentServer = system => MockPaymentServer(system) override def clientServer: ActorSystem[_] => ClientServer = system => MockClientServer(system) def loadApiKey(clientId: String): Future[Option[ApiKey]] = - MockPaymentBehavior.softPaymentAccountDao.loadApiKey(clientId) + MockPaymentBehavior.softPayAccountDao.loadApiKey(clientId) def clientId: String = provider.clientId @@ -107,11 +107,11 @@ trait PaymentTestKit override def internalAccountEvents2AccountProcessorStream : ActorSystem[_] => InternalAccountEvents2AccountProcessorStream = sys => new InternalAccountEvents2AccountProcessorStream - with MockSoftPaymentAccountHandler + with MockSoftPayAccountHandler with InMemoryJournalProvider with InMemoryOffsetProvider { lazy val log: Logger = LoggerFactory getLogger getClass.getName - override def tag: String = s"${MockSoftPaymentAccountBehavior.persistenceId}-to-internal" + override def tag: String = s"${MockSoftPayAccountBehavior.persistenceId}-to-internal" override lazy val forTests: Boolean = true override implicit def system: ActorSystem[_] = sys } @@ -241,5 +241,5 @@ trait PaymentTestKit registerProvidersAccount(system) } - override def softPaymentAccountDao: SoftPaymentAccountDao = MockSoftPaymentAccountDao + override def softPayAccountDao: SoftPayAccountDao = MockSoftPayAccountDao } diff --git a/testkit/src/main/scala/app/softnetwork/payment/service/MockSoftPayAccountService.scala b/testkit/src/main/scala/app/softnetwork/payment/service/MockSoftPayAccountService.scala new file mode 100644 index 0000000..08ee16a --- /dev/null +++ b/testkit/src/main/scala/app/softnetwork/payment/service/MockSoftPayAccountService.scala @@ -0,0 +1,12 @@ +package app.softnetwork.payment.service + +import app.softnetwork.payment.handlers.MockSoftPayAccountTypeKey +import app.softnetwork.session.model.{SessionData, SessionDataDecorator} +import app.softnetwork.session.service.SessionMaterials + +trait MockSoftPayAccountService[SD <: SessionData with SessionDataDecorator[SD]] + extends SoftPayAccountService[SD] + with MockSoftPayAccountTypeKey { + _: SessionMaterials[SD] => + +} diff --git a/testkit/src/main/scala/app/softnetwork/payment/service/MockSoftPayAccountServiceEndpoints.scala b/testkit/src/main/scala/app/softnetwork/payment/service/MockSoftPayAccountServiceEndpoints.scala new file mode 100644 index 0000000..dccb47f --- /dev/null +++ b/testkit/src/main/scala/app/softnetwork/payment/service/MockSoftPayAccountServiceEndpoints.scala @@ -0,0 +1,9 @@ +package app.softnetwork.payment.service + +import app.softnetwork.payment.handlers.MockSoftPayAccountTypeKey +import app.softnetwork.session.model.{SessionData, SessionDataDecorator} +import app.softnetwork.session.service.SessionMaterials + +trait MockSoftPayAccountServiceEndpoints[SD <: SessionData with SessionDataDecorator[SD]] + extends SoftPayAccountServiceEndpoints[SD] + with MockSoftPayAccountTypeKey { _: SessionMaterials[SD] => } diff --git a/testkit/src/main/scala/app/softnetwork/payment/service/MockSoftPaymentOAuthService.scala b/testkit/src/main/scala/app/softnetwork/payment/service/MockSoftPayOAuthService.scala similarity index 63% rename from testkit/src/main/scala/app/softnetwork/payment/service/MockSoftPaymentOAuthService.scala rename to testkit/src/main/scala/app/softnetwork/payment/service/MockSoftPayOAuthService.scala index c8b957f..4e37db4 100644 --- a/testkit/src/main/scala/app/softnetwork/payment/service/MockSoftPaymentOAuthService.scala +++ b/testkit/src/main/scala/app/softnetwork/payment/service/MockSoftPayOAuthService.scala @@ -1,14 +1,14 @@ package app.softnetwork.payment.service import app.softnetwork.account.spi.OAuth2Service -import app.softnetwork.payment.handlers.MockSoftPaymentAccountTypeKey +import app.softnetwork.payment.handlers.MockSoftPayAccountTypeKey import app.softnetwork.session.model.{SessionData, SessionDataDecorator} import app.softnetwork.session.service.SessionMaterials import com.github.scribejava.core.oauth.DummyApiService -trait MockSoftPaymentOAuthService[SD <: SessionData with SessionDataDecorator[SD]] - extends SoftPaymentOAuthService[SD] - with MockSoftPaymentAccountTypeKey { +trait MockSoftPayOAuthService[SD <: SessionData with SessionDataDecorator[SD]] + extends SoftPayOAuthService[SD] + with MockSoftPayAccountTypeKey { _: SessionMaterials[SD] => override lazy val services: Seq[OAuth2Service] = Seq( diff --git a/testkit/src/main/scala/app/softnetwork/payment/service/MockSoftPaymentOAuthServiceEndpoints.scala b/testkit/src/main/scala/app/softnetwork/payment/service/MockSoftPayOAuthServiceEndpoints.scala similarity index 57% rename from testkit/src/main/scala/app/softnetwork/payment/service/MockSoftPaymentOAuthServiceEndpoints.scala rename to testkit/src/main/scala/app/softnetwork/payment/service/MockSoftPayOAuthServiceEndpoints.scala index 6fe8e95..9db8e00 100644 --- a/testkit/src/main/scala/app/softnetwork/payment/service/MockSoftPaymentOAuthServiceEndpoints.scala +++ b/testkit/src/main/scala/app/softnetwork/payment/service/MockSoftPayOAuthServiceEndpoints.scala @@ -1,14 +1,14 @@ package app.softnetwork.payment.service import app.softnetwork.account.spi.OAuth2Service -import app.softnetwork.payment.handlers.MockSoftPaymentAccountTypeKey +import app.softnetwork.payment.handlers.MockSoftPayAccountTypeKey import app.softnetwork.session.model.{SessionData, SessionDataDecorator} import app.softnetwork.session.service.SessionMaterials import com.github.scribejava.core.oauth.DummyApiService -trait MockSoftPaymentOAuthServiceEndpoints[SD <: SessionData with SessionDataDecorator[SD]] - extends SoftPaymentOAuthServiceEndpoints[SD] - with MockSoftPaymentAccountTypeKey { _: SessionMaterials[SD] => +trait MockSoftPayOAuthServiceEndpoints[SD <: SessionData with SessionDataDecorator[SD]] + extends SoftPayOAuthServiceEndpoints[SD] + with MockSoftPayAccountTypeKey { _: SessionMaterials[SD] => override lazy val services: Seq[OAuth2Service] = Seq( diff --git a/testkit/src/main/scala/app/softnetwork/payment/service/MockSoftPaymentAccountService.scala b/testkit/src/main/scala/app/softnetwork/payment/service/MockSoftPaymentAccountService.scala deleted file mode 100644 index 79a6e4b..0000000 --- a/testkit/src/main/scala/app/softnetwork/payment/service/MockSoftPaymentAccountService.scala +++ /dev/null @@ -1,12 +0,0 @@ -package app.softnetwork.payment.service - -import app.softnetwork.payment.handlers.MockSoftPaymentAccountTypeKey -import app.softnetwork.session.model.{SessionData, SessionDataDecorator} -import app.softnetwork.session.service.SessionMaterials - -trait MockSoftPaymentAccountService[SD <: SessionData with SessionDataDecorator[SD]] - extends SoftPaymentAccountService[SD] - with MockSoftPaymentAccountTypeKey { - _: SessionMaterials[SD] => - -} diff --git a/testkit/src/main/scala/app/softnetwork/payment/service/MockSoftPaymentAccountServiceEndpoints.scala b/testkit/src/main/scala/app/softnetwork/payment/service/MockSoftPaymentAccountServiceEndpoints.scala deleted file mode 100644 index 5018af3..0000000 --- a/testkit/src/main/scala/app/softnetwork/payment/service/MockSoftPaymentAccountServiceEndpoints.scala +++ /dev/null @@ -1,9 +0,0 @@ -package app.softnetwork.payment.service - -import app.softnetwork.payment.handlers.MockSoftPaymentAccountTypeKey -import app.softnetwork.session.model.{SessionData, SessionDataDecorator} -import app.softnetwork.session.service.SessionMaterials - -trait MockSoftPaymentAccountServiceEndpoints[SD <: SessionData with SessionDataDecorator[SD]] - extends SoftPaymentAccountServiceEndpoints[SD] - with MockSoftPaymentAccountTypeKey { _: SessionMaterials[SD] => } diff --git a/testkit/src/main/scala/app/softnetwork/payment/spi/MockMangoPayProvider.scala b/testkit/src/main/scala/app/softnetwork/payment/spi/MockMangoPayProvider.scala index 60523bc..07366dc 100644 --- a/testkit/src/main/scala/app/softnetwork/payment/spi/MockMangoPayProvider.scala +++ b/testkit/src/main/scala/app/softnetwork/payment/spi/MockMangoPayProvider.scala @@ -4,8 +4,8 @@ import app.softnetwork.payment.config.MangoPay import app.softnetwork.payment.config.MangoPaySettings.MangoPayConfig._ import app.softnetwork.payment.model.NaturalUser.NaturalUserType import app.softnetwork.payment.model.RecurringPayment.RecurringCardPaymentState -import app.softnetwork.payment.model.SoftPaymentAccount.Client -import app.softnetwork.payment.model.SoftPaymentAccount.Client.Provider +import app.softnetwork.payment.model.SoftPayAccount.SoftPayClient +import app.softnetwork.payment.model.SoftPayAccount.SoftPayClient.SoftPayProvider import app.softnetwork.payment.model.{RecurringPayment, _} import app.softnetwork.persistence._ import app.softnetwork.time.DateExtensions @@ -1239,9 +1239,9 @@ trait MockMangoPayProvider extends MangoPayProvider { } } - override def client: Option[SoftPaymentAccount.Client] = + override def client: Option[SoftPayAccount.SoftPayClient] = Some( - SoftPaymentAccount.Client.defaultInstance + SoftPayAccount.SoftPayClient.defaultInstance .withProvider(provider) .withClientId(provider.clientId) ) @@ -1722,13 +1722,14 @@ case class RecurringCardPaymentRegistration( ) class MockMangoPayProviderFactory extends PaymentProviderSpi { - override val providerType: Provider.ProviderType = Provider.ProviderType.MOCK + override val providerType: SoftPayProvider.SoftPayProviderType = + SoftPayProvider.SoftPayProviderType.MOCK - override def paymentProvider(p: Client.Provider): MockMangoPayProvider = + override def paymentProvider(p: SoftPayClient.SoftPayProvider): MockMangoPayProvider = new MockMangoPayProvider { - override implicit def provider: Provider = p + override implicit def provider: SoftPayProvider = p } - override def softPaymentProvider: Provider = - MangoPay.softPaymentProvider.withProviderType(providerType) + override def softPaymentProvider: SoftPayProvider = + MangoPay.softPayProvider.withProviderType(providerType) } From 0e2b3fcb3a1b2f6a3e3e3d1cc3838d97fd88947f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Manciot?= Date: Tue, 12 Dec 2023 07:01:58 +0100 Subject: [PATCH 32/37] rename softpay client and provider resources --- .../main/protobuf/message/payment/client.proto | 6 +++--- .../main/protobuf/model/payment/client.proto | 12 ++++++------ .../payment/message/AccountMessages.scala | 14 ++++++-------- .../payment/model/SoftPayClientDecorator.scala | 4 ++-- .../model/SoftPayProviderDecorator.scala | 4 ++-- .../payment/serialization/package.scala | 2 +- .../payment/spi/PaymentProvider.scala | 4 ++-- .../payment/spi/PaymentProviderSpi.scala | 6 +++--- .../payment/spi/PaymentProviders.scala | 6 +++--- .../softnetwork/payment/api/ClientServer.scala | 6 +++--- .../payment/handlers/SoftPayAccountDao.scala | 12 ++++++------ .../payment/service/CardPaymentEndpoints.scala | 2 +- .../payment/service/ClientSession.scala | 8 ++++---- .../service/ClientSessionDirectives.scala | 8 ++++---- .../service/ClientSessionEndpoints.scala | 6 +++--- .../payment/service/RootPaymentEndpoints.scala | 4 ++-- .../softnetwork/payment/config/MangoPay.scala | 8 ++++---- .../payment/spi/MangoPayProvider.scala | 16 ++++++++-------- .../payment/api/SoftPayClientTestKit.scala | 4 ++-- .../payment/spi/MockMangoPayProvider.scala | 18 +++++++++--------- 20 files changed, 74 insertions(+), 76 deletions(-) diff --git a/common/src/main/protobuf/message/payment/client.proto b/common/src/main/protobuf/message/payment/client.proto index d32a246..32bb09d 100644 --- a/common/src/main/protobuf/message/payment/client.proto +++ b/common/src/main/protobuf/message/payment/client.proto @@ -31,20 +31,20 @@ message SoftPayAccountCreatedEvent { message SoftPayAccountProviderRegisteredEvent { option (scalapb.message).extends = "ProtobufEvent"; option (scalapb.message).extends = "SoftPayAccountEvent"; - required app.softnetwork.payment.model.SoftPayAccount.SoftPayClient client = 1; + required app.softnetwork.payment.model.SoftPayAccount.Client client = 1; required google.protobuf.Timestamp lastUpdated = 2 [(scalapb.field).type = "java.time.Instant"]; } message SoftPayAccountTokenRegisteredEvent { option (scalapb.message).extends = "ProtobufEvent"; option (scalapb.message).extends = "SoftPayAccountEvent"; - required app.softnetwork.payment.model.SoftPayAccount.SoftPayClient client = 1; + required app.softnetwork.payment.model.SoftPayAccount.Client client = 1; required google.protobuf.Timestamp lastUpdated = 2 [(scalapb.field).type = "java.time.Instant"]; } message SoftPayAccountTokenRefreshedEvent { option (scalapb.message).extends = "ProtobufEvent"; option (scalapb.message).extends = "SoftPayAccountEvent"; - required app.softnetwork.payment.model.SoftPayAccount.SoftPayClient client = 1; + required app.softnetwork.payment.model.SoftPayAccount.Client client = 1; required google.protobuf.Timestamp lastUpdated = 2 [(scalapb.field).type = "java.time.Instant"]; } diff --git a/common/src/main/protobuf/model/payment/client.proto b/common/src/main/protobuf/model/payment/client.proto index 4cbc8fe..8b4b095 100644 --- a/common/src/main/protobuf/model/payment/client.proto +++ b/common/src/main/protobuf/model/payment/client.proto @@ -22,11 +22,11 @@ option (scalapb.options) = { message SoftPayAccount { - message SoftPayClient { + message Client { - message SoftPayProvider { + message Provider { - enum SoftPayProviderType{ + enum ProviderType{ MOCK = -1; MANGOPAY = 0; STRIPE = 1; @@ -35,13 +35,13 @@ message SoftPayAccount { option (scalapb.message).extends = "SoftPayProviderDecorator"; required string providerId = 1; required string providerApiKey = 2; - required SoftPayProviderType providerType = 3 [default = MANGOPAY]; + required ProviderType providerType = 3 [default = MANGOPAY]; } option (scalapb.message).extends = "SoftPayClientDecorator"; - required SoftPayProvider provider = 1; + required Provider provider = 1; required string clientId = 2; optional string clientApiKey = 3; optional string name = 4; @@ -82,5 +82,5 @@ message SoftPayAccount { optional bool fromAnonymous = 19; repeated app.softnetwork.account.model.Application applications = 20; - repeated SoftPayClient clients = 21; + repeated Client clients = 21; } \ No newline at end of file diff --git a/common/src/main/scala/app/softnetwork/payment/message/AccountMessages.scala b/common/src/main/scala/app/softnetwork/payment/message/AccountMessages.scala index a10ef1e..b1351a8 100644 --- a/common/src/main/scala/app/softnetwork/payment/message/AccountMessages.scala +++ b/common/src/main/scala/app/softnetwork/payment/message/AccountMessages.scala @@ -17,15 +17,14 @@ object AccountMessages { case class SoftPaySignUp( login: String, password: String, - provider: SoftPayAccount.SoftPayClient.SoftPayProvider, + provider: SoftPayAccount.Client.Provider, override val confirmPassword: Option[String] = None, override val profile: Option[BasicAccountProfile] = None ) extends SignUp - case class RegisterProvider(provider: SoftPayAccount.SoftPayClient.SoftPayProvider) - extends AccountCommand + case class RegisterProvider(provider: SoftPayAccount.Client.Provider) extends AccountCommand - case class RegisterAccountWithProvider(provider: SoftPayAccount.SoftPayClient.SoftPayProvider) + case class RegisterAccountWithProvider(provider: SoftPayAccount.Client.Provider) extends AccountCommand with EntityCommand { override def id: String = provider.clientId @@ -48,18 +47,17 @@ object AccountMessages { case class OAuthClient(token: String) extends LookupAccountCommand - case class ProviderRegistered(client: SoftPayAccount.SoftPayClient) extends AccountCommandResult + case class ProviderRegistered(client: SoftPayAccount.Client) extends AccountCommandResult case class AccountWithProviderRegistered(account: SoftPayAccount) extends AccountCommandResult - case class ClientLoaded(client: SoftPayAccount.SoftPayClient) extends AccountCommandResult + case class ClientLoaded(client: SoftPayAccount.Client) extends AccountCommandResult case class ApiKeysLoaded(apiKeys: Seq[ApiKey]) extends AccountCommandResult case class ApiKeyLoaded(apiKey: ApiKey) extends AccountCommandResult - case class OAuthClientSucceededResult(client: SoftPayAccount.SoftPayClient) - extends AccountCommandResult + case class OAuthClientSucceededResult(client: SoftPayAccount.Client) extends AccountCommandResult case object ProviderAlreadyRegistered extends AccountErrorMessage("provider.already.registered") diff --git a/common/src/main/scala/app/softnetwork/payment/model/SoftPayClientDecorator.scala b/common/src/main/scala/app/softnetwork/payment/model/SoftPayClientDecorator.scala index b147edf..8ba4f59 100644 --- a/common/src/main/scala/app/softnetwork/payment/model/SoftPayClientDecorator.scala +++ b/common/src/main/scala/app/softnetwork/payment/model/SoftPayClientDecorator.scala @@ -2,7 +2,7 @@ package app.softnetwork.payment.model import app.softnetwork.account.model.BearerTokenGenerator -trait SoftPayClientDecorator { _: SoftPayAccount.SoftPayClient => +trait SoftPayClientDecorator { _: SoftPayAccount.Client => def generateApiKey(): String = BearerTokenGenerator.generateSHAToken(clientId) @@ -25,7 +25,7 @@ case class SoftPayClientView( ) object SoftPayClientView { - def apply(client: SoftPayAccount.SoftPayClient): SoftPayClientView = { + def apply(client: SoftPayAccount.Client): SoftPayClientView = { import client._ SoftPayClientView( clientId, diff --git a/common/src/main/scala/app/softnetwork/payment/model/SoftPayProviderDecorator.scala b/common/src/main/scala/app/softnetwork/payment/model/SoftPayProviderDecorator.scala index 97e4e07..1678001 100644 --- a/common/src/main/scala/app/softnetwork/payment/model/SoftPayProviderDecorator.scala +++ b/common/src/main/scala/app/softnetwork/payment/model/SoftPayProviderDecorator.scala @@ -4,10 +4,10 @@ import app.softnetwork.account.model.AccountStatus import app.softnetwork.payment.spi.PaymentProviders import app.softnetwork.security.sha256 -trait SoftPayProviderDecorator { self: SoftPayAccount.SoftPayClient.SoftPayProvider => +trait SoftPayProviderDecorator { self: SoftPayAccount.Client.Provider => lazy val clientId = s"$providerId.${providerType.name.toLowerCase}" - lazy val client: SoftPayAccount.SoftPayClient = { + lazy val client: SoftPayAccount.Client = { PaymentProviders.paymentProvider(self).client match { case Some(client) => client.withClientApiKey(sha256(self.providerApiKey)) diff --git a/common/src/main/scala/app/softnetwork/payment/serialization/package.scala b/common/src/main/scala/app/softnetwork/payment/serialization/package.scala index 61fb5ac..22fc43b 100644 --- a/common/src/main/scala/app/softnetwork/payment/serialization/package.scala +++ b/common/src/main/scala/app/softnetwork/payment/serialization/package.scala @@ -31,7 +31,7 @@ package object serialization { GeneratedEnumSerializer(RecurringPayment.RecurringPaymentFrequency.enumCompanion), GeneratedEnumSerializer(RecurringPayment.RecurringCardPaymentStatus.enumCompanion), GeneratedEnumSerializer( - SoftPayAccount.SoftPayClient.SoftPayProvider.SoftPayProviderType.enumCompanion + SoftPayAccount.Client.Provider.ProviderType.enumCompanion ) ) diff --git a/common/src/main/scala/app/softnetwork/payment/spi/PaymentProvider.scala b/common/src/main/scala/app/softnetwork/payment/spi/PaymentProvider.scala index 733cf38..8c1bf95 100644 --- a/common/src/main/scala/app/softnetwork/payment/spi/PaymentProvider.scala +++ b/common/src/main/scala/app/softnetwork/payment/spi/PaymentProvider.scala @@ -12,7 +12,7 @@ private[payment] trait PaymentProvider { protected lazy val mlog: Logger = Logger(LoggerFactory.getLogger(getClass.getName)) - implicit def provider: SoftPayAccount.SoftPayClient.SoftPayProvider + implicit def provider: SoftPayAccount.Client.Provider /** @param maybePaymentAccount * - payment account to create or update @@ -374,7 +374,7 @@ private[payment] trait PaymentProvider { /** @return * client fees */ - def client: Option[SoftPayAccount.SoftPayClient] + def client: Option[SoftPayAccount.Client] def clientFees(): Option[Double] diff --git a/common/src/main/scala/app/softnetwork/payment/spi/PaymentProviderSpi.scala b/common/src/main/scala/app/softnetwork/payment/spi/PaymentProviderSpi.scala index 83f09e9..6ff737c 100644 --- a/common/src/main/scala/app/softnetwork/payment/spi/PaymentProviderSpi.scala +++ b/common/src/main/scala/app/softnetwork/payment/spi/PaymentProviderSpi.scala @@ -3,9 +3,9 @@ package app.softnetwork.payment.spi import app.softnetwork.payment.model.SoftPayAccount trait PaymentProviderSpi { - def providerType: SoftPayAccount.SoftPayClient.SoftPayProvider.SoftPayProviderType + def providerType: SoftPayAccount.Client.Provider.ProviderType - def paymentProvider(p: SoftPayAccount.SoftPayClient.SoftPayProvider): PaymentProvider + def paymentProvider(p: SoftPayAccount.Client.Provider): PaymentProvider - def softPaymentProvider: SoftPayAccount.SoftPayClient.SoftPayProvider + def softPaymentProvider: SoftPayAccount.Client.Provider } diff --git a/common/src/main/scala/app/softnetwork/payment/spi/PaymentProviders.scala b/common/src/main/scala/app/softnetwork/payment/spi/PaymentProviders.scala index 3ff1433..6c91016 100644 --- a/common/src/main/scala/app/softnetwork/payment/spi/PaymentProviders.scala +++ b/common/src/main/scala/app/softnetwork/payment/spi/PaymentProviders.scala @@ -12,14 +12,14 @@ object PaymentProviders { private[this] var paymentProviders: Map[String, PaymentProvider] = Map.empty - private[this] def paymentProviderKey(provider: SoftPayAccount.SoftPayClient.SoftPayProvider) = + private[this] def paymentProviderKey(provider: SoftPayAccount.Client.Provider) = s"${provider.providerType}-${provider.providerId}" - def defaultPaymentProviders: Seq[SoftPayAccount.SoftPayClient.SoftPayProvider] = + def defaultPaymentProviders: Seq[SoftPayAccount.Client.Provider] = paymentProviderFactories.iterator().asScala.map(_.softPaymentProvider).toSeq def paymentProvider( - provider: SoftPayAccount.SoftPayClient.SoftPayProvider + provider: SoftPayAccount.Client.Provider ): PaymentProvider = { paymentProviders.get(paymentProviderKey(provider)) match { case Some(paymentProvider) => paymentProvider diff --git a/core/src/main/scala/app/softnetwork/payment/api/ClientServer.scala b/core/src/main/scala/app/softnetwork/payment/api/ClientServer.scala index d7d61ff..b574112 100644 --- a/core/src/main/scala/app/softnetwork/payment/api/ClientServer.scala +++ b/core/src/main/scala/app/softnetwork/payment/api/ClientServer.scala @@ -59,12 +59,12 @@ trait ClientServer extends ClientServiceApi with SoftPayAccountDao { AccountMessages.SoftPaySignUp( principal, credentials, - SoftPayAccount.SoftPayClient.SoftPayProvider( + SoftPayAccount.Client.Provider( providerId, providerApiKey, - SoftPayAccount.SoftPayClient.SoftPayProvider.SoftPayProviderType + SoftPayAccount.Client.Provider.ProviderType .fromName(providerType.name) - .getOrElse(SoftPayAccount.SoftPayClient.SoftPayProvider.SoftPayProviderType.MANGOPAY) + .getOrElse(SoftPayAccount.Client.Provider.ProviderType.MANGOPAY) ) ) ) map { diff --git a/core/src/main/scala/app/softnetwork/payment/handlers/SoftPayAccountDao.scala b/core/src/main/scala/app/softnetwork/payment/handlers/SoftPayAccountDao.scala index 2628b58..07e621f 100644 --- a/core/src/main/scala/app/softnetwork/payment/handlers/SoftPayAccountDao.scala +++ b/core/src/main/scala/app/softnetwork/payment/handlers/SoftPayAccountDao.scala @@ -33,7 +33,7 @@ trait SoftPayAccountDao extends AccountDao with SoftPayAccountHandler { clientId: String )(implicit system: ActorSystem[_] - ): Future[Option[SoftPayAccount.SoftPayClient.SoftPayProvider]] = { + ): Future[Option[SoftPayAccount.Client.Provider]] = { implicit val ec: ExecutionContext = system.executionContext loadClient(clientId).map(_.map(_.provider)) } @@ -41,7 +41,7 @@ trait SoftPayAccountDao extends AccountDao with SoftPayAccountHandler { @InternalApi private[payment] def loadClient( clientId: String - )(implicit system: ActorSystem[_]): Future[Option[SoftPayAccount.SoftPayClient]] = { + )(implicit system: ActorSystem[_]): Future[Option[SoftPayAccount.Client]] = { implicit val ec: ExecutionContext = system.executionContext ??(clientId, AccountMessages.LoadClient(clientId)) map { case result: AccountMessages.ClientLoaded => Some(result.client) @@ -52,7 +52,7 @@ trait SoftPayAccountDao extends AccountDao with SoftPayAccountHandler { @InternalApi private[payment] def oauthClient( token: String - )(implicit system: ActorSystem[_]): Future[Option[SoftPayAccount.SoftPayClient]] = { + )(implicit system: ActorSystem[_]): Future[Option[SoftPayAccount.Client]] = { implicit val ec: ExecutionContext = system.executionContext ??(token, AccountMessages.OAuthClient(token)) map { case result: AccountMessages.OAuthClientSucceededResult => Some(result.client) @@ -109,7 +109,7 @@ trait SoftPayAccountDao extends AccountDao with SoftPayAccountHandler { @InternalApi private[payment] def signUpClient( signUp: AccountMessages.SoftPaySignUp - )(implicit system: ActorSystem[_]): Future[Either[String, SoftPayAccount.SoftPayClient]] = { + )(implicit system: ActorSystem[_]): Future[Either[String, SoftPayAccount.Client]] = { implicit val ec: ExecutionContext = system.executionContext ??( generateUUID(Some(signUp.login)), @@ -153,7 +153,7 @@ trait SoftPayAccountDao extends AccountDao with SoftPayAccountHandler { @InternalApi private[payment] def registerAccountWithProvider( - provider: SoftPayAccount.SoftPayClient.SoftPayProvider + provider: SoftPayAccount.Client.Provider )(implicit system: ActorSystem[_] ): Future[Option[SoftPayAccount]] = { @@ -167,7 +167,7 @@ trait SoftPayAccountDao extends AccountDao with SoftPayAccountHandler { @InternalApi private[payment] def authenticateClient( token: Option[String] - )(implicit system: ActorSystem[_]): Future[Option[SoftPayAccount.SoftPayClient]] = { + )(implicit system: ActorSystem[_]): Future[Option[SoftPayAccount.Client]] = { token match { case Some(value) => implicit val ec: ExecutionContext = system.executionContext diff --git a/core/src/main/scala/app/softnetwork/payment/service/CardPaymentEndpoints.scala b/core/src/main/scala/app/softnetwork/payment/service/CardPaymentEndpoints.scala index 3ef1527..8e7746d 100644 --- a/core/src/main/scala/app/softnetwork/payment/service/CardPaymentEndpoints.scala +++ b/core/src/main/scala/app/softnetwork/payment/service/CardPaymentEndpoints.scala @@ -21,7 +21,7 @@ trait CardPaymentEndpoints[SD <: SessionData with SessionDataDecorator[SD]] { def payment(payment: Payment): PartialServerEndpointWithSecurityOutput[ (Seq[Option[String]], Option[String], Method, Option[String]), - (Option[SoftPayAccount.SoftPayClient], SD), + (Option[SoftPayAccount.Client], SD), (Option[String], Option[String], Option[String], Option[String], Payment), Any, (Seq[Option[String]], Option[CookieValueWithMeta]), diff --git a/core/src/main/scala/app/softnetwork/payment/service/ClientSession.scala b/core/src/main/scala/app/softnetwork/payment/service/ClientSession.scala index 96193a8..7c99f04 100644 --- a/core/src/main/scala/app/softnetwork/payment/service/ClientSession.scala +++ b/core/src/main/scala/app/softnetwork/payment/service/ClientSession.scala @@ -21,7 +21,7 @@ trait ClientSession[SD <: SessionData with SessionDataDecorator[SD]] extends Com implicit def companion: SessionDataCompanion[SD] - implicit def toSession(client: SoftPayAccount.SoftPayClient): SD = { + implicit def toSession(client: SoftPayAccount.Client): SD = { var session = companion.newSession .withAdmin(false) .withAnonymous(false) @@ -31,14 +31,14 @@ trait ClientSession[SD <: SessionData with SessionDataDecorator[SD]] extends Com } def encodeClient( - client: SoftPayAccount.SoftPayClient + client: SoftPayAccount.Client ): String = { clientSessionManager(client).clientSessionManager.encode(client) } def decodeClient(data: String): Option[SD] = manager.clientSessionManager.decode(data).toOption - def clientSessionManager(client: SoftPayAccount.SoftPayClient): SessionManager[SD] = { + def clientSessionManager(client: SoftPayAccount.Client): SessionManager[SD] = { implicit val innerSessionConfig: SessionConfig = sessionConfig.copy( jwt = sessionConfig.jwt.copy( @@ -68,7 +68,7 @@ trait ClientSession[SD <: SessionData with SessionDataDecorator[SD]] extends Com } } - def clientSessionManager(client: Option[SoftPayAccount.SoftPayClient]): SessionManager[SD] = { + def clientSessionManager(client: Option[SoftPayAccount.Client]): SessionManager[SD] = { client match { case Some(c) => implicit val innerSessionConfig: SessionConfig = diff --git a/core/src/main/scala/app/softnetwork/payment/service/ClientSessionDirectives.scala b/core/src/main/scala/app/softnetwork/payment/service/ClientSessionDirectives.scala index 53db4fc..6a20065 100644 --- a/core/src/main/scala/app/softnetwork/payment/service/ClientSessionDirectives.scala +++ b/core/src/main/scala/app/softnetwork/payment/service/ClientSessionDirectives.scala @@ -17,12 +17,12 @@ trait ClientSessionDirectives[SD <: SessionData with SessionDataDecorator[SD]] _: SessionMaterials[SD] => @InternalApi - private[payment] def clientDirective: Directive1[Option[SoftPayAccount.SoftPayClient]] = + private[payment] def clientDirective: Directive1[Option[SoftPayAccount.Client]] = authenticateOAuth2Async(AccountSettings.Realm, oauthClient).optional @InternalApi private[payment] def requiredClientSession( - body: (Option[SoftPayAccount.SoftPayClient], SD) => Route + body: (Option[SoftPayAccount.Client], SD) => Route ): Route = clientDirective { client => requiredSession(sc(clientSessionManager(client)), gt) { session => @@ -32,7 +32,7 @@ trait ClientSessionDirectives[SD <: SessionData with SessionDataDecorator[SD]] @InternalApi private[payment] def optionalClientSession( - body: (Option[SoftPayAccount.SoftPayClient], Option[SD]) => Route + body: (Option[SoftPayAccount.Client], Option[SD]) => Route ): Route = clientDirective { client => optionalSession(sc(clientSessionManager(client)), gt) { session => @@ -41,7 +41,7 @@ trait ClientSessionDirectives[SD <: SessionData with SessionDataDecorator[SD]] } @InternalApi - private[payment] def oauthClient: Credentials => Future[Option[SoftPayAccount.SoftPayClient]] = { + private[payment] def oauthClient: Credentials => Future[Option[SoftPayAccount.Client]] = { case _ @Credentials.Provided(token) => softPayAccountDao.authenticateClient(Some(token)) case _ => Future.successful(None) } diff --git a/core/src/main/scala/app/softnetwork/payment/service/ClientSessionEndpoints.scala b/core/src/main/scala/app/softnetwork/payment/service/ClientSessionEndpoints.scala index 277e409..9ebc5d5 100644 --- a/core/src/main/scala/app/softnetwork/payment/service/ClientSessionEndpoints.scala +++ b/core/src/main/scala/app/softnetwork/payment/service/ClientSessionEndpoints.scala @@ -38,7 +38,7 @@ trait ClientSessionEndpoints[SD <: SessionData with SessionDataDecorator[SD]] @InternalApi private[payment] def requiredClientSession: PartialServerEndpointWithSecurityOutput[Seq[ Option[String] - ], (Option[SoftPayAccount.SoftPayClient], SD), Unit, Unit, Seq[ + ], (Option[SoftPayAccount.Client], SD), Unit, Unit, Seq[ Option[String] ], Unit, Any, Future] = { val partial = clientSession(Some(true)) @@ -59,7 +59,7 @@ trait ClientSessionEndpoints[SD <: SessionData with SessionDataDecorator[SD]] @InternalApi private[payment] def optionalClientSession: PartialServerEndpointWithSecurityOutput[Seq[ Option[String] - ], (Option[SoftPayAccount.SoftPayClient], Option[SD]), Unit, Unit, Seq[ + ], (Option[SoftPayAccount.Client], Option[SD]), Unit, Unit, Seq[ Option[String] ], Unit, Any, Future] = { val partial = clientSession(Some(false)) @@ -78,7 +78,7 @@ trait ClientSessionEndpoints[SD <: SessionData with SessionDataDecorator[SD]] required: Option[Boolean] ): PartialServerEndpointWithSecurityOutput[Seq[ Option[String] - ], (Option[SoftPayAccount.SoftPayClient], SessionResult[SD]), Unit, Unit, Seq[ + ], (Option[SoftPayAccount.Client], SessionResult[SD]), Unit, Unit, Seq[ Option[String] ], Unit, Any, Future] = { val partial = sc.session(gt, required) diff --git a/core/src/main/scala/app/softnetwork/payment/service/RootPaymentEndpoints.scala b/core/src/main/scala/app/softnetwork/payment/service/RootPaymentEndpoints.scala index 58f4005..cb0be8c 100644 --- a/core/src/main/scala/app/softnetwork/payment/service/RootPaymentEndpoints.scala +++ b/core/src/main/scala/app/softnetwork/payment/service/RootPaymentEndpoints.scala @@ -36,7 +36,7 @@ trait RootPaymentEndpoints[SD <: SessionData with SessionDataDecorator[SD]] lazy val requiredSessionEndpoint: PartialServerEndpointWithSecurityOutput[ (Seq[Option[String]], Option[String], Method, Option[String]), - (Option[SoftPayAccount.SoftPayClient], SD), + (Option[SoftPayAccount.Client], SD), Unit, Any, (Seq[Option[String]], Option[CookieValueWithMeta]), @@ -54,7 +54,7 @@ trait RootPaymentEndpoints[SD <: SessionData with SessionDataDecorator[SD]] lazy val optionalSessionEndpoint: PartialServerEndpointWithSecurityOutput[ (Seq[Option[String]], Option[String], Method, Option[String]), - (Option[SoftPayAccount.SoftPayClient], Option[SD]), + (Option[SoftPayAccount.Client], Option[SD]), Unit, Any, (Seq[Option[String]], Option[CookieValueWithMeta]), diff --git a/mangopay/src/main/scala/app/softnetwork/payment/config/MangoPay.scala b/mangopay/src/main/scala/app/softnetwork/payment/config/MangoPay.scala index 9a3c112..3e844ff 100644 --- a/mangopay/src/main/scala/app/softnetwork/payment/config/MangoPay.scala +++ b/mangopay/src/main/scala/app/softnetwork/payment/config/MangoPay.scala @@ -43,13 +43,13 @@ object MangoPay extends StrictLogging { var mangoPayApis: Map[String, MangoPayApi] = Map.empty - lazy val softPayProvider: SoftPayAccount.SoftPayClient.SoftPayProvider = - SoftPayAccount.SoftPayClient.SoftPayProvider.defaultInstance - .withProviderType(SoftPayAccount.SoftPayClient.SoftPayProvider.SoftPayProviderType.MANGOPAY) + lazy val softPayProvider: SoftPayAccount.Client.Provider = + SoftPayAccount.Client.Provider.defaultInstance + .withProviderType(SoftPayAccount.Client.Provider.ProviderType.MANGOPAY) .withProviderId(MangoPaySettings.MangoPayConfig.clientId) .withProviderApiKey(MangoPaySettings.MangoPayConfig.apiKey) - def apply(provider: SoftPayAccount.SoftPayClient.SoftPayProvider): MangoPayApi = { + def apply(provider: SoftPayAccount.Client.Provider): MangoPayApi = { mangoPayApis.get(provider.providerId) match { case Some(mangoPayApi) => mangoPayApi case _ => diff --git a/mangopay/src/main/scala/app/softnetwork/payment/spi/MangoPayProvider.scala b/mangopay/src/main/scala/app/softnetwork/payment/spi/MangoPayProvider.scala index 9b6823f..29be0a6 100644 --- a/mangopay/src/main/scala/app/softnetwork/payment/spi/MangoPayProvider.scala +++ b/mangopay/src/main/scala/app/softnetwork/payment/spi/MangoPayProvider.scala @@ -24,7 +24,7 @@ import app.softnetwork.payment.model.{RecurringPayment, _} import app.softnetwork.payment.config.{MangoPay, MangoPaySettings} import app.softnetwork.payment.config.MangoPaySettings.MangoPayConfig._ import app.softnetwork.payment.model.NaturalUser.NaturalUserType -import app.softnetwork.payment.model.SoftPayAccount.SoftPayClient.SoftPayProvider +import app.softnetwork.payment.model.SoftPayAccount.Client.Provider import scala.util.{Failure, Success, Try} import app.softnetwork.persistence._ @@ -2082,11 +2082,11 @@ trait MangoPayProvider extends PaymentProvider { } } - override def client: Option[SoftPayAccount.SoftPayClient] = { + override def client: Option[SoftPayAccount.Client] = { Try(MangoPay(provider).getClientApi.get()) match { case Success(client) => Some( - SoftPayAccount.SoftPayClient.defaultInstance + SoftPayAccount.Client.defaultInstance .withClientId(client.getClientId + "." + provider.providerType.name.toLowerCase) .withProvider(provider) .copy( @@ -2593,14 +2593,14 @@ trait MangoPayProvider extends PaymentProvider { } class MangoPayProviderFactory extends PaymentProviderSpi { - override val providerType: SoftPayProvider.SoftPayProviderType = - SoftPayProvider.SoftPayProviderType.MANGOPAY + override val providerType: Provider.ProviderType = + Provider.ProviderType.MANGOPAY - override def paymentProvider(p: SoftPayAccount.SoftPayClient.SoftPayProvider): MangoPayProvider = + override def paymentProvider(p: SoftPayAccount.Client.Provider): MangoPayProvider = new MangoPayProvider { - override implicit val provider: SoftPayAccount.SoftPayClient.SoftPayProvider = p + override implicit val provider: SoftPayAccount.Client.Provider = p } - override def softPaymentProvider: SoftPayAccount.SoftPayClient.SoftPayProvider = + override def softPaymentProvider: SoftPayAccount.Client.Provider = MangoPay.softPayProvider } diff --git a/testkit/src/main/scala/app/softnetwork/payment/api/SoftPayClientTestKit.scala b/testkit/src/main/scala/app/softnetwork/payment/api/SoftPayClientTestKit.scala index 7fefa59..f2f56f1 100644 --- a/testkit/src/main/scala/app/softnetwork/payment/api/SoftPayClientTestKit.scala +++ b/testkit/src/main/scala/app/softnetwork/payment/api/SoftPayClientTestKit.scala @@ -6,9 +6,9 @@ import app.softnetwork.security.sha256 trait SoftPayClientTestKit { - def provider: SoftPayAccount.SoftPayClient.SoftPayProvider = + def provider: SoftPayAccount.Client.Provider = MangoPay.softPayProvider.withProviderType( - SoftPayAccount.SoftPayClient.SoftPayProvider.SoftPayProviderType.MOCK + SoftPayAccount.Client.Provider.ProviderType.MOCK ) def softPayClientSettings: String = diff --git a/testkit/src/main/scala/app/softnetwork/payment/spi/MockMangoPayProvider.scala b/testkit/src/main/scala/app/softnetwork/payment/spi/MockMangoPayProvider.scala index 07366dc..dec6934 100644 --- a/testkit/src/main/scala/app/softnetwork/payment/spi/MockMangoPayProvider.scala +++ b/testkit/src/main/scala/app/softnetwork/payment/spi/MockMangoPayProvider.scala @@ -4,8 +4,8 @@ import app.softnetwork.payment.config.MangoPay import app.softnetwork.payment.config.MangoPaySettings.MangoPayConfig._ import app.softnetwork.payment.model.NaturalUser.NaturalUserType import app.softnetwork.payment.model.RecurringPayment.RecurringCardPaymentState -import app.softnetwork.payment.model.SoftPayAccount.SoftPayClient -import app.softnetwork.payment.model.SoftPayAccount.SoftPayClient.SoftPayProvider +import app.softnetwork.payment.model.SoftPayAccount.Client +import app.softnetwork.payment.model.SoftPayAccount.Client.Provider import app.softnetwork.payment.model.{RecurringPayment, _} import app.softnetwork.persistence._ import app.softnetwork.time.DateExtensions @@ -1239,9 +1239,9 @@ trait MockMangoPayProvider extends MangoPayProvider { } } - override def client: Option[SoftPayAccount.SoftPayClient] = + override def client: Option[SoftPayAccount.Client] = Some( - SoftPayAccount.SoftPayClient.defaultInstance + SoftPayAccount.Client.defaultInstance .withProvider(provider) .withClientId(provider.clientId) ) @@ -1722,14 +1722,14 @@ case class RecurringCardPaymentRegistration( ) class MockMangoPayProviderFactory extends PaymentProviderSpi { - override val providerType: SoftPayProvider.SoftPayProviderType = - SoftPayProvider.SoftPayProviderType.MOCK + override val providerType: Provider.ProviderType = + Provider.ProviderType.MOCK - override def paymentProvider(p: SoftPayClient.SoftPayProvider): MockMangoPayProvider = + override def paymentProvider(p: Client.Provider): MockMangoPayProvider = new MockMangoPayProvider { - override implicit def provider: SoftPayProvider = p + override implicit def provider: Provider = p } - override def softPaymentProvider: SoftPayProvider = + override def softPaymentProvider: Provider = MangoPay.softPayProvider.withProviderType(providerType) } From 9f3a777f3b2af7a2babc15d3357563de196a16e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Manciot?= Date: Tue, 12 Dec 2023 07:44:36 +0100 Subject: [PATCH 33/37] rename softpay account and client registration messages --- .../softnetwork/payment/message/AccountMessages.scala | 9 ++++++--- .../persistence/typed/SoftPayAccountBehavior.scala | 8 +++++--- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/common/src/main/scala/app/softnetwork/payment/message/AccountMessages.scala b/common/src/main/scala/app/softnetwork/payment/message/AccountMessages.scala index b1351a8..e7e877c 100644 --- a/common/src/main/scala/app/softnetwork/payment/message/AccountMessages.scala +++ b/common/src/main/scala/app/softnetwork/payment/message/AccountMessages.scala @@ -22,7 +22,8 @@ object AccountMessages { override val profile: Option[BasicAccountProfile] = None ) extends SignUp - case class RegisterProvider(provider: SoftPayAccount.Client.Provider) extends AccountCommand + case class RegisterClientWithProvider(provider: SoftPayAccount.Client.Provider) + extends AccountCommand case class RegisterAccountWithProvider(provider: SoftPayAccount.Client.Provider) extends AccountCommand @@ -47,7 +48,8 @@ object AccountMessages { case class OAuthClient(token: String) extends LookupAccountCommand - case class ProviderRegistered(client: SoftPayAccount.Client) extends AccountCommandResult + case class ClientWithProviderRegistered(client: SoftPayAccount.Client) + extends AccountCommandResult case class AccountWithProviderRegistered(account: SoftPayAccount) extends AccountCommandResult @@ -61,7 +63,8 @@ object AccountMessages { case object ProviderAlreadyRegistered extends AccountErrorMessage("provider.already.registered") - case object ProviderNotRegistered extends AccountErrorMessage("provider.not.registered") + case object ClientWithProviderNotRegistered + extends AccountErrorMessage("client.with.provider.not.registered") case object AccountWithProviderNotRegistered extends AccountErrorMessage("account.with.provider.not.registered") diff --git a/core/src/main/scala/app/softnetwork/payment/persistence/typed/SoftPayAccountBehavior.scala b/core/src/main/scala/app/softnetwork/payment/persistence/typed/SoftPayAccountBehavior.scala index f99514a..07c9433 100644 --- a/core/src/main/scala/app/softnetwork/payment/persistence/typed/SoftPayAccountBehavior.scala +++ b/core/src/main/scala/app/softnetwork/payment/persistence/typed/SoftPayAccountBehavior.scala @@ -88,7 +88,7 @@ trait SoftPayAccountBehavior extends AccountBehavior[SoftPayAccount, BasicAccoun ): Effect[ExternalSchedulerEvent, Option[SoftPayAccount]] = { implicit val system: ActorSystem[_] = context.system command match { - case AccountMessages.RegisterProvider(provider) => + case AccountMessages.RegisterClientWithProvider(provider) => state match { case Some(account) => if ( @@ -122,10 +122,12 @@ trait SoftPayAccountBehavior extends AccountBehavior[SoftPayAccount, BasicAccoun Instant.now() ) ) - .thenRun(_ => AccountMessages.ProviderRegistered(updatedClient) ~> replyTo) + .thenRun(_ => + AccountMessages.ClientWithProviderRegistered(updatedClient) ~> replyTo + ) case _ => Effect.none.thenRun { _ => - AccountMessages.ProviderNotRegistered ~> replyTo + AccountMessages.ClientWithProviderNotRegistered ~> replyTo } } } From 838a3ef055d075da689c69d3735b1a4d8762e365 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Manciot?= Date: Tue, 12 Dec 2023 08:37:31 +0100 Subject: [PATCH 34/37] update softpay cli --- .../app/softnetwork/payment/cli/Cmd.scala | 34 ++++ .../app/softnetwork/payment/cli/Command.scala | 11 -- .../payment/cli/CommandConfig.scala | 17 -- .../app/softnetwork/payment/cli/Main.scala | 114 +++---------- .../payment/cli/activate/ActivateClient.scala | 26 --- .../cli/activate/ActivateClientCmd.scala | 50 ++++++ .../cli/activate/ActivateClientConfig.scala | 27 --- .../payment/cli/clients/Clients.scala | 75 --------- .../payment/cli/clients/ClientsCmd.scala | 158 ++++++++++++++++++ .../payment/cli/clients/ClientsConfig.scala | 66 -------- .../payment/cli/signup/SignUpClient.scala | 37 ---- .../payment/cli/signup/SignUpClientCmd.scala | 89 ++++++++++ .../cli/signup/SignUpClientConfig.scala | 49 ------ .../payment/cli/tokens/Tokens.scala | 50 ------ .../payment/cli/tokens/TokensCmd.scala | 82 +++++++++ .../payment/cli/tokens/TokensConfig.scala | 27 --- 16 files changed, 439 insertions(+), 473 deletions(-) create mode 100644 client/src/main/scala/app/softnetwork/payment/cli/Cmd.scala delete mode 100644 client/src/main/scala/app/softnetwork/payment/cli/Command.scala delete mode 100644 client/src/main/scala/app/softnetwork/payment/cli/CommandConfig.scala delete mode 100644 client/src/main/scala/app/softnetwork/payment/cli/activate/ActivateClient.scala create mode 100644 client/src/main/scala/app/softnetwork/payment/cli/activate/ActivateClientCmd.scala delete mode 100644 client/src/main/scala/app/softnetwork/payment/cli/clients/Clients.scala create mode 100644 client/src/main/scala/app/softnetwork/payment/cli/clients/ClientsCmd.scala delete mode 100644 client/src/main/scala/app/softnetwork/payment/cli/signup/SignUpClient.scala create mode 100644 client/src/main/scala/app/softnetwork/payment/cli/signup/SignUpClientCmd.scala delete mode 100644 client/src/main/scala/app/softnetwork/payment/cli/tokens/Tokens.scala create mode 100644 client/src/main/scala/app/softnetwork/payment/cli/tokens/TokensCmd.scala diff --git a/client/src/main/scala/app/softnetwork/payment/cli/Cmd.scala b/client/src/main/scala/app/softnetwork/payment/cli/Cmd.scala new file mode 100644 index 0000000..d923572 --- /dev/null +++ b/client/src/main/scala/app/softnetwork/payment/cli/Cmd.scala @@ -0,0 +1,34 @@ +package app.softnetwork.payment.cli + +import akka.actor.typed.ActorSystem +import scopt.OParser + +import scala.concurrent.Future + +trait Cmd[T] { + + def name: String + + private[cli] def shell: String = Main.shell + + def parser: OParser[Unit, T] + + private[cli] def usage(): String = OParser.usage(parser) + + def parse(args: Seq[String]): Option[T] + + final def run( + args: Seq[String] + )(implicit system: ActorSystem[_]): Future[(Int, Option[String])] = { + parse(args) match { + case Some(config) => run(config) + case None => + Future.successful( + (1, Some(s"ERROR: Invalid arguments for command --> $shell $name\n${usage()}")) + ) + } + } + + def run(config: T)(implicit system: ActorSystem[_]): Future[(Int, Option[String])] + +} diff --git a/client/src/main/scala/app/softnetwork/payment/cli/Command.scala b/client/src/main/scala/app/softnetwork/payment/cli/Command.scala deleted file mode 100644 index de13be2..0000000 --- a/client/src/main/scala/app/softnetwork/payment/cli/Command.scala +++ /dev/null @@ -1,11 +0,0 @@ -package app.softnetwork.payment.cli - -import akka.actor.typed.ActorSystem - -import scala.concurrent.Future - -trait Command[T] { - - def run(config: T)(implicit system: ActorSystem[_]): Future[String] - -} diff --git a/client/src/main/scala/app/softnetwork/payment/cli/CommandConfig.scala b/client/src/main/scala/app/softnetwork/payment/cli/CommandConfig.scala deleted file mode 100644 index 873a8c3..0000000 --- a/client/src/main/scala/app/softnetwork/payment/cli/CommandConfig.scala +++ /dev/null @@ -1,17 +0,0 @@ -package app.softnetwork.payment.cli - -import scopt.OParser - -trait CommandConfig { - def command: String - - def shell: String = Main.shell -} - -trait CliConfig[T] extends CommandConfig { - def parser: OParser[Unit, T] - - def usage(): String = OParser.usage(parser) - - def parse(args: Seq[String]): Option[T] -} diff --git a/client/src/main/scala/app/softnetwork/payment/cli/Main.scala b/client/src/main/scala/app/softnetwork/payment/cli/Main.scala index 1ea719f..594ce04 100644 --- a/client/src/main/scala/app/softnetwork/payment/cli/Main.scala +++ b/client/src/main/scala/app/softnetwork/payment/cli/Main.scala @@ -4,10 +4,10 @@ import akka.actor.typed.ActorSystem import akka.actor.typed.scaladsl.Behaviors import app.softnetwork.concurrent.Completion import app.softnetwork.payment.SoftpayBuildInfo -import app.softnetwork.payment.cli.activate.{ActivateClient, ActivateClientConfig} -import app.softnetwork.payment.cli.clients.{Clients, ClientsConfig} -import app.softnetwork.payment.cli.signup.{SignUpClient, SignUpClientConfig} -import app.softnetwork.payment.cli.tokens.{Tokens, TokensConfig} +import app.softnetwork.payment.cli.activate.ActivateClientCmd +import app.softnetwork.payment.cli.clients.ClientsCmd +import app.softnetwork.payment.cli.signup.SignUpClientCmd +import app.softnetwork.payment.cli.tokens.TokensCmd import com.typesafe.scalalogging.StrictLogging import scala.util.{Failure, Success} @@ -23,36 +23,36 @@ object Main extends StrictLogging { } class Main extends Completion with StrictLogging { - val configs: List[CliConfig[_]] = List( - SignUpClientConfig, - ActivateClientConfig, - TokensConfig, - ClientsConfig + private[cli] val cmds: List[Cmd[_]] = List( + SignUpClientCmd, + ActivateClientCmd, + TokensCmd, + ClientsCmd ) - private def printUsage(): Unit = { + private[cli] def printUsage(): Unit = { // scalastyle:off println println(s"Softpay Version ${SoftpayBuildInfo.version}") println("Usage:") println(s"\t${Main.shell} [command]") println("Available commands =>") - configs.foreach { config => - println(s"\t${config.command}") + cmds.foreach { cmd => + println(s"\t${cmd.name}") } } - private def printUsage(command: String): Unit = { + private[cli] def printUsage(cmd: String): Unit = { // scalastyle:off println - configs.find(_.command == command) match { + cmds.find(_.name == cmd) match { case None => - println(s"ERROR: Unknown command --> $command") - case Some(config) => - println(config.usage()) + println(s"ERROR: Unknown command --> $cmd") + case Some(cmd) => + println(cmd.usage()) } } // scalastyle:on println - private def help(args: List[String]): Unit = { + private[cli] def help(args: List[String]): Unit = { args match { case Nil | "help" :: Nil => printUsage() @@ -71,80 +71,18 @@ class Main extends Completion with StrictLogging { help(args.toList) args.toList match { case command :: list => - configs.find(_.command == command) match { + cmds.find(_.name == command) match { case None => println(s"ERROR: Unknown command --> $command") printUsage() System.exit(1) - case Some(config) => - command match { - case SignUpClientConfig.command => - SignUpClientConfig.parse(list) match { - case None => - println(s"ERROR: Invalid arguments for command --> $command") - printUsage(config.usage()) - System.exit(1) - case Some(conf) => - SignUpClient.run(conf) complete () match { - case Success(result) => - println(result) - System.exit(0) - case Failure(f) => - logger.error(s"Failed to run command $command", f) - System.exit(1) - } - } - case TokensConfig.command => - TokensConfig.parse(list) match { - case None => - println(s"ERROR: Invalid arguments for command --> $command") - printUsage(config.usage()) - System.exit(1) - case Some(conf) => - Tokens.run(conf) complete () match { - case Success(result) => - println(result) - System.exit(0) - case Failure(f) => - logger.error(s"Failed to run command $command", f) - System.exit(1) - } - } - case ActivateClientConfig.command => - ActivateClientConfig.parse(list) match { - case None => - println(s"ERROR: Invalid arguments for command --> $command") - printUsage(config.usage()) - System.exit(1) - case Some(conf) => - ActivateClient.run(conf) complete () match { - case Success(result) => - println(result) - System.exit(0) - case Failure(f) => - logger.error(s"Failed to run command $command", f) - System.exit(1) - } - } - case ClientsConfig.command => - ClientsConfig.parse(list) match { - case None => - println(s"ERROR: Invalid arguments for command --> $command") - printUsage(config.usage()) - System.exit(1) - case Some(conf) => - Clients.run(conf) complete () match { - case Success(result) => - println(result) - System.exit(0) - case Failure(f) => - logger.error(s"Failed to run command $command", f) - System.exit(1) - } - } - case _ => - println(s"ERROR: Unknown command --> $command") - printUsage() + case Some(cmd) => + cmd.run(list) complete () match { + case Success((exit, message)) => + message.foreach(println) + System.exit(exit) + case Failure(f) => + logger.error(s"Failed to run command ${cmd.name}", f) System.exit(1) } } diff --git a/client/src/main/scala/app/softnetwork/payment/cli/activate/ActivateClient.scala b/client/src/main/scala/app/softnetwork/payment/cli/activate/ActivateClient.scala deleted file mode 100644 index e03726b..0000000 --- a/client/src/main/scala/app/softnetwork/payment/cli/activate/ActivateClient.scala +++ /dev/null @@ -1,26 +0,0 @@ -package app.softnetwork.payment.cli.activate - -import akka.actor.typed.ActorSystem -import app.softnetwork.payment.api.Client -import app.softnetwork.payment.cli.Command - -import scala.concurrent.{ExecutionContext, Future} - -object ActivateClient extends Command[ActivateClientConfig] { - override def run( - config: ActivateClientConfig - )(implicit system: ActorSystem[_]): Future[String] = { - implicit val ec: ExecutionContext = system.executionContext - val client = Client(system) - client.activateClient(config.token) map { - case Right(activated) => - if (activated) "Client activated successfully!" - else "Client activation failed!" - case Left(error) => - s""" - |Client activation failed! - |$error - |""".stripMargin - } - } -} diff --git a/client/src/main/scala/app/softnetwork/payment/cli/activate/ActivateClientCmd.scala b/client/src/main/scala/app/softnetwork/payment/cli/activate/ActivateClientCmd.scala new file mode 100644 index 0000000..33e4f96 --- /dev/null +++ b/client/src/main/scala/app/softnetwork/payment/cli/activate/ActivateClientCmd.scala @@ -0,0 +1,50 @@ +package app.softnetwork.payment.cli.activate + +import akka.actor.typed.ActorSystem +import app.softnetwork.payment.api.Client +import app.softnetwork.payment.cli.Cmd +import scopt.OParser + +import scala.concurrent.{ExecutionContext, Future} + +object ActivateClientCmd extends Cmd[ActivateClientConfig] { + + val name: String = "activate" + + val parser: OParser[Unit, ActivateClientConfig] = { + val builder = OParser.builder[ActivateClientConfig] + import builder._ + OParser.sequence( + programName(s"$shell $name"), + head(shell, name, "[options]"), + opt[String]('t', "token") + .action((x, c) => c.copy(token = x)) + .text("token") + .required() + ) + } + + def parse(args: Seq[String]): Option[ActivateClientConfig] = { + OParser.parse(parser, args, ActivateClientConfig()) + } + + override def run( + config: ActivateClientConfig + )(implicit system: ActorSystem[_]): Future[(Int, Option[String])] = { + implicit val ec: ExecutionContext = system.executionContext + val client = Client(system) + client.activateClient(config.token) map { + case Right(activated) => + if (activated) (0, Some("Client activated successfully!")) + else (1, Some("Client activation failed!")) + case Left(error) => + ( + 1, + Some(s""" + |Client activation failed! + |$error + |""".stripMargin) + ) + } + } +} diff --git a/client/src/main/scala/app/softnetwork/payment/cli/activate/ActivateClientConfig.scala b/client/src/main/scala/app/softnetwork/payment/cli/activate/ActivateClientConfig.scala index 40db977..3d7da4a 100644 --- a/client/src/main/scala/app/softnetwork/payment/cli/activate/ActivateClientConfig.scala +++ b/client/src/main/scala/app/softnetwork/payment/cli/activate/ActivateClientConfig.scala @@ -1,30 +1,3 @@ package app.softnetwork.payment.cli.activate -import app.softnetwork.payment.cli.{CliConfig, Command} -import scopt.OParser - case class ActivateClientConfig(token: String = "") - -object ActivateClientConfig extends CliConfig[ActivateClientConfig] { - - val command: String = "activate" - - val parser: OParser[Unit, ActivateClientConfig] = { - val builder = OParser.builder[ActivateClientConfig] - import builder._ - OParser.sequence( - programName(s"$shell $command"), - head(shell, command, "[options]"), - opt[String]('t', "token") - .action((x, c) => c.copy(token = x)) - .text("token") - .required() - ) - } - - def parse(args: Seq[String]): Option[ActivateClientConfig] = { - OParser.parse(parser, args, ActivateClientConfig()) - } - - def runner: Command[ActivateClientConfig] = ActivateClient -} diff --git a/client/src/main/scala/app/softnetwork/payment/cli/clients/Clients.scala b/client/src/main/scala/app/softnetwork/payment/cli/clients/Clients.scala deleted file mode 100644 index 96a9247..0000000 --- a/client/src/main/scala/app/softnetwork/payment/cli/clients/Clients.scala +++ /dev/null @@ -1,75 +0,0 @@ -package app.softnetwork.payment.cli.clients - -import akka.actor.typed.ActorSystem -import app.softnetwork.payment.api.config.{ApiKeys, SoftPayClientSettings} -import app.softnetwork.payment.cli.Command - -import scala.concurrent.Future - -object Clients extends Command[ClientsConfig] { - override def run(config: ClientsConfig)(implicit system: ActorSystem[_]): Future[String] = { - config.subCommand match { - case ClientsSubCommand.List => - Future.successful( - s""" - |Available clients: - |\t${ApiKeys.list().filter(_._2.trim.nonEmpty).keys.mkString("\n\t")} - |""".stripMargin - ) - case ClientsSubCommand.Set => - config.clientId match { - case Some(clientId) => - Future.successful(SoftPayClientSettings.select(clientId) match { - case Some(softPayClientSettings) => - s""" - |Client $clientId selected successfully! - |\tapiKey: ${softPayClientSettings.apiKey} - |""".stripMargin - case None => - s""" - |apiKey not found for $clientId! - |""".stripMargin - }) - } - case ClientsSubCommand.Get => - config.clientId match { - case Some(clientId) => - Future.successful(ApiKeys.get(clientId) match { - case Some(apiKey) => - s""" - |Client $clientId loaded successfully! - |\tapiKey: $apiKey - |""".stripMargin - case None => - s""" - |apiKey not found for $clientId! - |""".stripMargin - }) - } - case ClientsSubCommand.Add => - config.clientId match { - case Some(clientId) => - ApiKeys.+(clientId, config.apiKey.getOrElse("")) match { - case _ => - Future.successful( - s""" - |Client $clientId added successfully! - |""".stripMargin - ) - } - } - case ClientsSubCommand.Remove => - config.clientId match { - case Some(clientId) => - ApiKeys.-(clientId) match { - case _ => - Future.successful( - s""" - |Client $clientId removed successfully! - |""".stripMargin - ) - } - } - } - } -} diff --git a/client/src/main/scala/app/softnetwork/payment/cli/clients/ClientsCmd.scala b/client/src/main/scala/app/softnetwork/payment/cli/clients/ClientsCmd.scala new file mode 100644 index 0000000..45fb143 --- /dev/null +++ b/client/src/main/scala/app/softnetwork/payment/cli/clients/ClientsCmd.scala @@ -0,0 +1,158 @@ +package app.softnetwork.payment.cli.clients + +import akka.actor.typed.ActorSystem +import app.softnetwork.payment.api.config.{ApiKeys, SoftPayClientSettings} +import app.softnetwork.payment.cli.Cmd +import scopt.OParser + +import scala.concurrent.Future + +object ClientsCmd extends Cmd[ClientsConfig] { + + val name: String = "clients" + + val parser: OParser[Unit, ClientsConfig] = { + val builder = OParser.builder[ClientsConfig] + import builder._ + OParser.sequence( + programName(s"$shell $name"), + head(shell, name, "[options]"), + cmd("list") + .action((_, c) => c.copy(subCommand = ClientsSubCommand.List)) + .text("list all clients"), + cmd("get") + .action((_, c) => c.copy(subCommand = ClientsSubCommand.Get)) + .text("get client by id") + .children( + opt[String]('i', "clientId") + .action((x, c) => c.copy(clientId = Some(x))) + .text("client Id") + .required() + ), + cmd("remove") + .action((_, c) => c.copy(subCommand = ClientsSubCommand.Remove)) + .text("remove client by id") + .children( + opt[String]('i', "clientId") + .action((x, c) => c.copy(clientId = Some(x))) + .text("client Id") + .required() + ), + cmd("add") + .action((_, c) => c.copy(subCommand = ClientsSubCommand.Add)) + .text("add api key") + .children( + opt[String]('i', "clientId") + .action((x, c) => c.copy(clientId = Some(x))) + .text("client Id") + .required(), + opt[String]('s', "apiKey") + .action((x, c) => c.copy(apiKey = Some(x))) + .text("api Key") + .required() + ), + cmd("set") + .action((_, c) => c.copy(subCommand = ClientsSubCommand.Set)) + .text("set client by id") + .children( + opt[String]('i', "clientId") + .action((x, c) => c.copy(clientId = Some(x))) + .text("client Id") + .required() + ) + ) + } + + def parse(args: Seq[String]): Option[ClientsConfig] = { + OParser.parse(parser, args, ClientsConfig()) + } + + override def run( + config: ClientsConfig + )(implicit system: ActorSystem[_]): Future[(Int, Option[String])] = { + config.subCommand match { + case ClientsSubCommand.List => + Future.successful( + ( + 0, + Some(s""" + |Available clients: + |\t${ApiKeys.list().filter(_._2.trim.nonEmpty).keys.mkString("\n\t")} + |""".stripMargin) + ) + ) + case ClientsSubCommand.Set => + config.clientId match { + case Some(clientId) => + Future.successful(SoftPayClientSettings.select(clientId) match { + case Some(softPayClientSettings) => + ( + 0, + Some(s""" + |Client $clientId selected successfully! + |\tapiKey: ${softPayClientSettings.apiKey} + |""".stripMargin) + ) + case None => + ( + 1, + Some(s""" + |apiKey not found for $clientId! + |""".stripMargin) + ) + }) + } + case ClientsSubCommand.Get => + config.clientId match { + case Some(clientId) => + Future.successful(ApiKeys.get(clientId) match { + case Some(apiKey) => + ( + 0, + Some(s""" + |Client $clientId loaded successfully! + |\tapiKey: $apiKey + |""".stripMargin) + ) + case None => + ( + 1, + Some(s""" + |apiKey not found for $clientId! + |""".stripMargin) + ) + }) + } + case ClientsSubCommand.Add => + config.clientId match { + case Some(clientId) => + ApiKeys.+(clientId, config.apiKey.getOrElse("")) match { + case _ => + Future.successful( + ( + 0, + Some(s""" + |Client $clientId added successfully! + |""".stripMargin) + ) + ) + } + } + case ClientsSubCommand.Remove => + config.clientId match { + case Some(clientId) => + ApiKeys.-(clientId) match { + case _ => + Future.successful( + ( + 0, + Some(s""" + |Client $clientId removed successfully! + |""".stripMargin) + ) + ) + } + } + } + } +} diff --git a/client/src/main/scala/app/softnetwork/payment/cli/clients/ClientsConfig.scala b/client/src/main/scala/app/softnetwork/payment/cli/clients/ClientsConfig.scala index 6332465..d12062a 100644 --- a/client/src/main/scala/app/softnetwork/payment/cli/clients/ClientsConfig.scala +++ b/client/src/main/scala/app/softnetwork/payment/cli/clients/ClientsConfig.scala @@ -1,8 +1,5 @@ package app.softnetwork.payment.cli.clients -import app.softnetwork.payment.cli.{CliConfig, Command} -import scopt.OParser - object ClientsSubCommand extends Enumeration { type ClientsSubCommand = Value val Empty, List, Get, Set, Add, Remove = Value @@ -13,66 +10,3 @@ case class ClientsConfig( clientId: Option[String] = None, apiKey: Option[String] = None ) - -object ClientsConfig extends CliConfig[ClientsConfig] { - - val command: String = "clients" - - val parser: OParser[Unit, ClientsConfig] = { - val builder = OParser.builder[ClientsConfig] - import builder._ - OParser.sequence( - programName(s"$shell $command"), - head(shell, command, "[options]"), - cmd("list") - .action((_, c) => c.copy(subCommand = ClientsSubCommand.List)) - .text("list all clients"), - cmd("get") - .action((_, c) => c.copy(subCommand = ClientsSubCommand.Get)) - .text("get client by id") - .children( - opt[String]('i', "clientId") - .action((x, c) => c.copy(clientId = Some(x))) - .text("client Id") - .required() - ), - cmd("remove") - .action((_, c) => c.copy(subCommand = ClientsSubCommand.Remove)) - .text("remove client by id") - .children( - opt[String]('i', "clientId") - .action((x, c) => c.copy(clientId = Some(x))) - .text("client Id") - .required() - ), - cmd("add") - .action((_, c) => c.copy(subCommand = ClientsSubCommand.Add)) - .text("add api key") - .children( - opt[String]('i', "clientId") - .action((x, c) => c.copy(clientId = Some(x))) - .text("client Id") - .required(), - opt[String]('s', "apiKey") - .action((x, c) => c.copy(apiKey = Some(x))) - .text("api Key") - .required() - ), - cmd("set") - .action((_, c) => c.copy(subCommand = ClientsSubCommand.Set)) - .text("set client by id") - .children( - opt[String]('i', "clientId") - .action((x, c) => c.copy(clientId = Some(x))) - .text("client Id") - .required() - ) - ) - } - - def parse(args: Seq[String]): Option[ClientsConfig] = { - OParser.parse(parser, args, ClientsConfig()) - } - - def runner: Command[ClientsConfig] = Clients -} diff --git a/client/src/main/scala/app/softnetwork/payment/cli/signup/SignUpClient.scala b/client/src/main/scala/app/softnetwork/payment/cli/signup/SignUpClient.scala deleted file mode 100644 index 8620940..0000000 --- a/client/src/main/scala/app/softnetwork/payment/cli/signup/SignUpClient.scala +++ /dev/null @@ -1,37 +0,0 @@ -package app.softnetwork.payment.cli.signup - -import akka.actor.typed.ActorSystem -import app.softnetwork.payment.api.Client -import app.softnetwork.payment.api.config.SoftPayClientSettings -import app.softnetwork.payment.cli.Command -import org.json4s.Formats - -import scala.concurrent.{ExecutionContext, Future} - -object SignUpClient extends Command[SignUpClientConfig] { - override def run(config: SignUpClientConfig)(implicit system: ActorSystem[_]): Future[String] = { - implicit val ec: ExecutionContext = system.executionContext - val client = Client(system) - implicit val formats: Formats = org.json4s.DefaultFormats - client.signUpClient( - config.principal, - config.credentials, - config.providerId, - config.providerApiKey, - config.providerType - ) map { - case Right(client) => - SoftPayClientSettings(client.clientId, client.clientSecret).write() - val json = org.json4s.jackson.Serialization.writePretty(client) - s""" - |Client registered successfully! - |$json - |""".stripMargin - case Left(error) => - s""" - |Client registration failed! - |$error - |""".stripMargin - } - } -} diff --git a/client/src/main/scala/app/softnetwork/payment/cli/signup/SignUpClientCmd.scala b/client/src/main/scala/app/softnetwork/payment/cli/signup/SignUpClientCmd.scala new file mode 100644 index 0000000..efd3c01 --- /dev/null +++ b/client/src/main/scala/app/softnetwork/payment/cli/signup/SignUpClientCmd.scala @@ -0,0 +1,89 @@ +package app.softnetwork.payment.cli.signup + +import akka.actor.typed.ActorSystem +import app.softnetwork.payment.api.config.SoftPayClientSettings +import app.softnetwork.payment.api.{Client, ProviderType} +import app.softnetwork.payment.cli.Cmd +import org.json4s.Formats +import scopt.OParser + +import scala.concurrent.{ExecutionContext, Future} + +object SignUpClientCmd extends Cmd[SignUpClientConfig] { + + val name: String = "signup" + + val parser: OParser[Unit, SignUpClientConfig] = { + val builder = OParser.builder[SignUpClientConfig] + import builder._ + OParser.sequence( + programName(s"$shell $name"), + head(shell, name, "[options]"), + opt[String]('p', "principal") + .action((x, c) => c.copy(principal = x)) + .text("principal") + .required(), + opt[String]('c', "credentials") + .action((x, c) => c.copy(credentials = x.toCharArray)) + .text("credentials") + .required() + /*.validate(x => + import app.softnetwork.account.config.AccountSettings.passwordRules + passwordRules().validate(x) match { + case Right(_) => success + case Left(error) => failure(error.mkString(", ")) + } + )*/, + opt[String]('i', "providerId") + .action((x, c) => c.copy(providerId = x)) + .text("payment provider Id") + .required(), + opt[String]('k', "providerApiKey") + .action((x, c) => c.copy(providerApiKey = x.toCharArray)) + .text("payment provider Api Key") + .required(), + opt[String]('t', "providerType") + .action((x, c) => c.copy(providerType = ProviderType.fromName(x.toUpperCase))) + .text("optional payment provider type - default is 'MangoPay'") + .optional() + ) + } + + def parse(args: Seq[String]): Option[SignUpClientConfig] = { + OParser.parse(parser, args, SignUpClientConfig()) + } + + override def run( + config: SignUpClientConfig + )(implicit system: ActorSystem[_]): Future[(Int, Option[String])] = { + implicit val ec: ExecutionContext = system.executionContext + val client = Client(system) + implicit val formats: Formats = org.json4s.DefaultFormats + client.signUpClient( + config.principal, + config.credentials, + config.providerId, + config.providerApiKey, + config.providerType + ) map { + case Right(client) => + SoftPayClientSettings(client.clientId, client.clientSecret).write() + val json = org.json4s.jackson.Serialization.writePretty(client) + ( + 0, + Some(s""" + |Client registered successfully! + |$json + |""".stripMargin) + ) + case Left(error) => + ( + 1, + Some(s""" + |Client registration failed! + |$error + |""".stripMargin) + ) + } + } +} diff --git a/client/src/main/scala/app/softnetwork/payment/cli/signup/SignUpClientConfig.scala b/client/src/main/scala/app/softnetwork/payment/cli/signup/SignUpClientConfig.scala index 44821c7..23ac24f 100644 --- a/client/src/main/scala/app/softnetwork/payment/cli/signup/SignUpClientConfig.scala +++ b/client/src/main/scala/app/softnetwork/payment/cli/signup/SignUpClientConfig.scala @@ -1,8 +1,6 @@ package app.softnetwork.payment.cli.signup import app.softnetwork.payment.api.ProviderType -import app.softnetwork.payment.cli.{CliConfig, Command} -import scopt.OParser case class SignUpClientConfig( principal: String = "", @@ -11,50 +9,3 @@ case class SignUpClientConfig( providerApiKey: Array[Char] = Array.emptyCharArray, providerType: Option[ProviderType] = Some(ProviderType.MANGOPAY) ) - -object SignUpClientConfig extends CliConfig[SignUpClientConfig] { - - val command: String = "signup" - - val parser: OParser[Unit, SignUpClientConfig] = { - val builder = OParser.builder[SignUpClientConfig] - import builder._ - OParser.sequence( - programName(s"$shell $command"), - head(shell, command, "[options]"), - opt[String]('p', "principal") - .action((x, c) => c.copy(principal = x)) - .text("principal") - .required(), - opt[String]('c', "credentials") - .action((x, c) => c.copy(credentials = x.toCharArray)) - .text("credentials") - .required() - /*.validate(x => - import app.softnetwork.account.config.AccountSettings.passwordRules - passwordRules().validate(x) match { - case Right(_) => success - case Left(error) => failure(error.mkString(", ")) - } - )*/, - opt[String]('i', "providerId") - .action((x, c) => c.copy(providerId = x)) - .text("payment provider Id") - .required(), - opt[String]('k', "providerApiKey") - .action((x, c) => c.copy(providerApiKey = x.toCharArray)) - .text("payment provider Api Key") - .required(), - opt[String]('t', "providerType") - .action((x, c) => c.copy(providerType = ProviderType.fromName(x.toUpperCase))) - .text("optional payment provider type - default is 'MangoPay'") - .optional() - ) - } - - def parse(args: Seq[String]): Option[SignUpClientConfig] = { - OParser.parse(parser, args, SignUpClientConfig()) - } - - def runner: Command[SignUpClientConfig] = SignUpClient -} diff --git a/client/src/main/scala/app/softnetwork/payment/cli/tokens/Tokens.scala b/client/src/main/scala/app/softnetwork/payment/cli/tokens/Tokens.scala deleted file mode 100644 index e751eed..0000000 --- a/client/src/main/scala/app/softnetwork/payment/cli/tokens/Tokens.scala +++ /dev/null @@ -1,50 +0,0 @@ -package app.softnetwork.payment.cli.tokens - -import akka.actor.typed.ActorSystem -import app.softnetwork.payment.api.Client -import app.softnetwork.payment.cli.Command -import com.typesafe.scalalogging.StrictLogging -import org.json4s.Formats - -import scala.concurrent.{ExecutionContext, Future} - -object Tokens extends Command[TokensConfig] with StrictLogging { - def run( - config: TokensConfig - )(implicit system: ActorSystem[_]): Future[String] = { - implicit val ec: ExecutionContext = system.executionContext - val client = Client(system) - implicit val formats: Formats = org.json4s.DefaultFormats - config.refreshToken match { - case Some(refreshToken) => - client.refreshClientTokens(refreshToken) map { - case Right(tokens) => - val json = org.json4s.jackson.Serialization.writePretty(tokens) - s""" - |Tokens refreshed successfully! - |$json - |""".stripMargin - case Left(error) => - s""" - |Tokens refresh failed! - |$error - |""".stripMargin - } - case None => - client.generateClientTokens() map { - case Right(tokens) => - val json = org.json4s.jackson.Serialization.writePretty(tokens) - s""" - |Tokens generated successfully! - |$json - |""".stripMargin - case Left(error) => - s""" - |Tokens generation failed! - |$error - |""".stripMargin - } - } - } - -} diff --git a/client/src/main/scala/app/softnetwork/payment/cli/tokens/TokensCmd.scala b/client/src/main/scala/app/softnetwork/payment/cli/tokens/TokensCmd.scala new file mode 100644 index 0000000..0b9029c --- /dev/null +++ b/client/src/main/scala/app/softnetwork/payment/cli/tokens/TokensCmd.scala @@ -0,0 +1,82 @@ +package app.softnetwork.payment.cli.tokens + +import akka.actor.typed.ActorSystem +import app.softnetwork.payment.api.Client +import app.softnetwork.payment.cli.Cmd +import org.json4s.Formats +import scopt.OParser + +import scala.concurrent.{ExecutionContext, Future} + +object TokensCmd extends Cmd[TokensConfig] { + + val name: String = "tokens" + + val parser: OParser[Unit, TokensConfig] = { + val builder = OParser.builder[TokensConfig] + import builder._ + OParser.sequence( + programName(s"$shell $name"), + head(shell, name, "[options]"), + opt[String]('r', "refreshToken") + .action((x, c) => c.copy(refreshToken = Some(x))) + .text("optional refresh token") + .optional() + ) + } + + def parse(args: Seq[String]): Option[TokensConfig] = { + OParser.parse(parser, args, TokensConfig()) + } + + def run( + config: TokensConfig + )(implicit system: ActorSystem[_]): Future[(Int, Option[String])] = { + implicit val ec: ExecutionContext = system.executionContext + val client = Client(system) + implicit val formats: Formats = org.json4s.DefaultFormats + config.refreshToken match { + case Some(refreshToken) => + client.refreshClientTokens(refreshToken) map { + case Right(tokens) => + val json = org.json4s.jackson.Serialization.writePretty(tokens) + ( + 0, + Some(s""" + |Tokens refreshed successfully! + |$json + |""".stripMargin) + ) + case Left(error) => + ( + 1, + Some(s""" + |Tokens refresh failed! + |$error + |""".stripMargin) + ) + } + case None => + client.generateClientTokens() map { + case Right(tokens) => + val json = org.json4s.jackson.Serialization.writePretty(tokens) + ( + 0, + Some(s""" + |Tokens generated successfully! + |$json + |""".stripMargin) + ) + case Left(error) => + ( + 1, + Some(s""" + |Tokens generation failed! + |$error + |""".stripMargin) + ) + } + } + } + +} diff --git a/client/src/main/scala/app/softnetwork/payment/cli/tokens/TokensConfig.scala b/client/src/main/scala/app/softnetwork/payment/cli/tokens/TokensConfig.scala index 049826c..f618c53 100644 --- a/client/src/main/scala/app/softnetwork/payment/cli/tokens/TokensConfig.scala +++ b/client/src/main/scala/app/softnetwork/payment/cli/tokens/TokensConfig.scala @@ -1,32 +1,5 @@ package app.softnetwork.payment.cli.tokens -import app.softnetwork.payment.cli.{CliConfig, Command} -import scopt.OParser - case class TokensConfig( refreshToken: Option[String] = None ) - -object TokensConfig extends CliConfig[TokensConfig] { - - val command: String = "tokens" - - val parser: OParser[Unit, TokensConfig] = { - val builder = OParser.builder[TokensConfig] - import builder._ - OParser.sequence( - programName(s"$shell $command"), - head(shell, command, "[options]"), - opt[String]('r', "refreshToken") - .action((x, c) => c.copy(refreshToken = Some(x))) - .text("optional refresh token") - .optional() - ) - } - - def parse(args: Seq[String]): Option[TokensConfig] = { - OParser.parse(parser, args, TokensConfig()) - } - - def runner: Command[TokensConfig] = Tokens -} From 29e4c60325fb4300a49f8adb40446c621d10dcec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Manciot?= Date: Fri, 15 Mar 2024 09:31:05 +0100 Subject: [PATCH 35/37] update mandate creation command, add clientId field to several payment message events --- .../main/protobuf/model/payment/address.proto | 1 - .../main/protobuf/model/payment/card.proto | 1 - .../protobuf/model/payment/document.proto | 1 - .../protobuf/model/payment/paymentUser.proto | 1 - .../payment/cli/tokens/TokensCmd.scala | 1 + .../protobuf/message/payment/payment.proto | 9 +++++ .../payment/message/PaymentMessages.scala | 4 ++- .../payment/spi/PaymentProviders.scala | 7 ++-- .../query/PaymentCommandProcessorStream.scala | 35 ++++++++++++++----- .../persistence/typed/PaymentBehavior.scala | 29 +++++++++------ .../payment/service/MandateEndpoints.scala | 7 +++- .../payment/service/PaymentService.scala | 7 +++- 12 files changed, 71 insertions(+), 32 deletions(-) diff --git a/client/src/main/protobuf/model/payment/address.proto b/client/src/main/protobuf/model/payment/address.proto index 4de1b14..20023a2 100644 --- a/client/src/main/protobuf/model/payment/address.proto +++ b/client/src/main/protobuf/model/payment/address.proto @@ -11,7 +11,6 @@ option (scalapb.options) = { import: "app.softnetwork.persistence.model._" import: "app.softnetwork.serialization._" import: "app.softnetwork.payment.model._" -// import: "app.softnetwork.payment.serialization._" preserve_unknown_fields: false }; diff --git a/client/src/main/protobuf/model/payment/card.proto b/client/src/main/protobuf/model/payment/card.proto index 3e711a3..383ce37 100644 --- a/client/src/main/protobuf/model/payment/card.proto +++ b/client/src/main/protobuf/model/payment/card.proto @@ -11,7 +11,6 @@ option (scalapb.options) = { import: "app.softnetwork.persistence.model._" import: "app.softnetwork.serialization._" import: "app.softnetwork.payment.model._" -// import: "app.softnetwork.payment.serialization._" preserve_unknown_fields: false }; diff --git a/client/src/main/protobuf/model/payment/document.proto b/client/src/main/protobuf/model/payment/document.proto index be34922..a640b2d 100644 --- a/client/src/main/protobuf/model/payment/document.proto +++ b/client/src/main/protobuf/model/payment/document.proto @@ -14,7 +14,6 @@ option (scalapb.options) = { import: "app.softnetwork.protobuf.ScalaPBTypeMappers._" import: "app.softnetwork.serialization._" import: "app.softnetwork.payment.model._" -// import: "app.softnetwork.payment.serialization._" preserve_unknown_fields: false }; diff --git a/client/src/main/protobuf/model/payment/paymentUser.proto b/client/src/main/protobuf/model/payment/paymentUser.proto index 777833b..7251ebe 100644 --- a/client/src/main/protobuf/model/payment/paymentUser.proto +++ b/client/src/main/protobuf/model/payment/paymentUser.proto @@ -17,7 +17,6 @@ option (scalapb.options) = { import: "app.softnetwork.protobuf.ScalaPBTypeMappers._" import: "app.softnetwork.serialization._" import: "app.softnetwork.payment.model._" -// import: "app.softnetwork.payment.serialization._" preserve_unknown_fields: false }; diff --git a/client/src/main/scala/app/softnetwork/payment/cli/tokens/TokensCmd.scala b/client/src/main/scala/app/softnetwork/payment/cli/tokens/TokensCmd.scala index 0b9029c..e222eff 100644 --- a/client/src/main/scala/app/softnetwork/payment/cli/tokens/TokensCmd.scala +++ b/client/src/main/scala/app/softnetwork/payment/cli/tokens/TokensCmd.scala @@ -18,6 +18,7 @@ object TokensCmd extends Cmd[TokensConfig] { OParser.sequence( programName(s"$shell $name"), head(shell, name, "[options]"), + note("Command to generate/refresh tokens"), opt[String]('r', "refreshToken") .action((x, c) => c.copy(refreshToken = Some(x))) .text("optional refresh token") diff --git a/common/src/main/protobuf/message/payment/payment.proto b/common/src/main/protobuf/message/payment/payment.proto index ec0b3a5..bf7eca9 100644 --- a/common/src/main/protobuf/message/payment/payment.proto +++ b/common/src/main/protobuf/message/payment/payment.proto @@ -186,6 +186,7 @@ message PayInWithCardPreAuthorizedCommandEvent{ required string preAuthorizationId = 1; required string creditedAccount = 2; optional int32 debitedAmount = 3; + optional string clientId = 4; } message RefundCommandEvent{ @@ -197,6 +198,7 @@ message RefundCommandEvent{ required string currency = 4 [default = "EUR"]; required string reasonMessage = 5; required bool initializedByClient = 6; + optional string clientId = 7; } message PayOutCommandEvent{ @@ -208,6 +210,7 @@ message PayOutCommandEvent{ required int32 feesAmount = 4; required string currency = 5 [default = "EUR"]; optional string externalReference = 6; + optional string clientId = 7; } message TransferCommandEvent{ @@ -221,6 +224,7 @@ message TransferCommandEvent{ required string currency = 6 [default = "EUR"]; required bool payOutRequired = 7 [default = true]; optional string externalReference = 8; + optional string clientId = 9; } message DirectDebitCommandEvent{ @@ -232,6 +236,7 @@ message DirectDebitCommandEvent{ required string currency = 4 [default = "EUR"]; required string statementDescriptor = 5; optional string externalReference = 6; + optional string clientId = 7; } message CreateOrUpdatePaymentAccountCommandEvent{ @@ -254,6 +259,7 @@ message RegisterRecurringPaymentCommandEvent { optional bool fixedNextAmount = 9; optional int32 nextDebitedAmount = 10; optional int32 nextFeesAmount = 11; + optional string clientId = 12; } message RecurringPaymentRegisteredEvent { @@ -269,12 +275,14 @@ message CancelPreAuthorizationCommandEvent { option (scalapb.message).extends = "PaymentCommandEvent"; required string orderUuid = 1; required string cardPreAuthorizedTransactionId = 2; + optional string clientId = 3; } message LoadDirectDebitTransactionCommandEvent { option (scalapb.message).extends = "ProtobufEvent"; option (scalapb.message).extends = "PaymentCommandEvent"; required string directDebitTransactionId = 1; + optional string clientId = 2; } message PaymentAccountCreatedOrUpdatedEvent { @@ -290,6 +298,7 @@ message CancelMandateCommandEvent { option (scalapb.message).extends = "ProtobufEvent"; option (scalapb.message).extends = "PaymentCommandEvent"; required string externalUuid = 1; + optional string clientId = 2; } message MandateCancelationFailedEvent { diff --git a/common/src/main/scala/app/softnetwork/payment/message/PaymentMessages.scala b/common/src/main/scala/app/softnetwork/payment/message/PaymentMessages.scala index 78a8dc8..e9032dd 100644 --- a/common/src/main/scala/app/softnetwork/payment/message/PaymentMessages.scala +++ b/common/src/main/scala/app/softnetwork/payment/message/PaymentMessages.scala @@ -726,8 +726,10 @@ object PaymentMessages { /** @param creditedAccount * - account to whom the mandate would be added + * @param clientId + * - optional client id */ - case class CreateMandate(creditedAccount: String) extends PaymentCommandWithKey { + case class CreateMandate(creditedAccount: String, clientId: Option[String] = None) extends PaymentCommandWithKey { val key: String = creditedAccount } diff --git a/common/src/main/scala/app/softnetwork/payment/spi/PaymentProviders.scala b/common/src/main/scala/app/softnetwork/payment/spi/PaymentProviders.scala index 6c91016..cb41a6f 100644 --- a/common/src/main/scala/app/softnetwork/payment/spi/PaymentProviders.scala +++ b/common/src/main/scala/app/softnetwork/payment/spi/PaymentProviders.scala @@ -12,16 +12,13 @@ object PaymentProviders { private[this] var paymentProviders: Map[String, PaymentProvider] = Map.empty - private[this] def paymentProviderKey(provider: SoftPayAccount.Client.Provider) = - s"${provider.providerType}-${provider.providerId}" - def defaultPaymentProviders: Seq[SoftPayAccount.Client.Provider] = paymentProviderFactories.iterator().asScala.map(_.softPaymentProvider).toSeq def paymentProvider( provider: SoftPayAccount.Client.Provider ): PaymentProvider = { - paymentProviders.get(paymentProviderKey(provider)) match { + paymentProviders.get(provider.clientId) match { case Some(paymentProvider) => paymentProvider case _ => val paymentProvider = @@ -35,7 +32,7 @@ object PaymentProviders { s"PaymentProvider not found for providerType: ${provider.providerType}" ) ) - paymentProviders += paymentProviderKey(provider) -> paymentProvider + paymentProviders += provider.clientId -> paymentProvider paymentProvider } } diff --git a/core/src/main/scala/app/softnetwork/payment/persistence/query/PaymentCommandProcessorStream.scala b/core/src/main/scala/app/softnetwork/payment/persistence/query/PaymentCommandProcessorStream.scala index 86af8fe..1ac71af 100644 --- a/core/src/main/scala/app/softnetwork/payment/persistence/query/PaymentCommandProcessorStream.scala +++ b/core/src/main/scala/app/softnetwork/payment/persistence/query/PaymentCommandProcessorStream.scala @@ -58,7 +58,12 @@ trait PaymentCommandProcessorStream extends EventProcessorStream[PaymentEventWit case evt: PayInWithCardPreAuthorizedCommandEvent => import evt._ val command = - PayInWithCardPreAuthorized(preAuthorizationId, creditedAccount, debitedAmount) + PayInWithCardPreAuthorized( + preAuthorizationId, + creditedAccount, + debitedAmount, + clientId + ) !?(command) map { case _: PaidInResult => if (forTests) system.eventStream.tell(Publish(event)) @@ -77,7 +82,8 @@ trait PaymentCommandProcessorStream extends EventProcessorStream[PaymentEventWit refundAmount, currency, reasonMessage, - initializedByClient + initializedByClient, + clientId ) !?(command) map { case _: Refunded => @@ -97,7 +103,8 @@ trait PaymentCommandProcessorStream extends EventProcessorStream[PaymentEventWit creditedAmount, feesAmount, currency, - externalReference + externalReference, + clientId ) !?(command) map { case _: PaidOut => @@ -119,7 +126,8 @@ trait PaymentCommandProcessorStream extends EventProcessorStream[PaymentEventWit feesAmount, currency, payOutRequired, - externalReference + externalReference, + clientId ) !?(command) map { case _: Transferred => @@ -139,7 +147,8 @@ trait PaymentCommandProcessorStream extends EventProcessorStream[PaymentEventWit feesAmount, currency, statementDescriptor, - externalReference + externalReference, + clientId ) !?(command) map { case _: DirectDebited => @@ -153,7 +162,10 @@ trait PaymentCommandProcessorStream extends EventProcessorStream[PaymentEventWit } case evt: LoadDirectDebitTransactionCommandEvent => import evt._ - val command = LoadDirectDebitTransaction(directDebitTransactionId) + val command = LoadDirectDebitTransaction( + directDebitTransactionId, + clientId + ) !?(command) map { case _: DirectDebited => if (forTests) system.eventStream.tell(Publish(event)) @@ -177,7 +189,8 @@ trait PaymentCommandProcessorStream extends EventProcessorStream[PaymentEventWit frequency, fixedNextAmount, nextDebitedAmount, - nextFeesAmount + nextFeesAmount, + clientId ) !?(command) map { case _: RecurringPaymentRegistered => @@ -191,7 +204,11 @@ trait PaymentCommandProcessorStream extends EventProcessorStream[PaymentEventWit } case evt: CancelPreAuthorizationCommandEvent => import evt._ - val command = CancelPreAuthorization(orderUuid, cardPreAuthorizedTransactionId) + val command = CancelPreAuthorization( + orderUuid, + cardPreAuthorizedTransactionId, + clientId + ) !?(command) map { case _: PreAuthorizationCanceled => if (forTests) system.eventStream.tell(Publish(event)) @@ -204,7 +221,7 @@ trait PaymentCommandProcessorStream extends EventProcessorStream[PaymentEventWit } case evt: CancelMandateCommandEvent => import evt._ - val command = CancelMandate(externalUuid) + val command = CancelMandate(externalUuid, clientId) !?(command) map { case MandateCanceled => if (forTests) system.eventStream.tell(Publish(event)) diff --git a/core/src/main/scala/app/softnetwork/payment/persistence/typed/PaymentBehavior.scala b/core/src/main/scala/app/softnetwork/payment/persistence/typed/PaymentBehavior.scala index 13b28f6..5ab7ea1 100644 --- a/core/src/main/scala/app/softnetwork/payment/persistence/typed/PaymentBehavior.scala +++ b/core/src/main/scala/app/softnetwork/payment/persistence/typed/PaymentBehavior.scala @@ -1347,7 +1347,8 @@ trait PaymentBehavior creditedAccount, paymentAccount, creditedUserId, - bankAccountId + bankAccountId, + clientId ) } case _ => Effect.none.thenRun(_ => BankAccountNotFound ~> replyTo) @@ -1357,7 +1358,7 @@ trait PaymentBehavior case _ => Effect.none.thenRun(_ => PaymentAccountNotFound ~> replyTo) } - case _: CancelMandate => + case cmd: CancelMandate => state match { case Some(paymentAccount) => if (paymentAccount.mandateExists && paymentAccount.mandateRequired) { @@ -1369,9 +1370,11 @@ trait PaymentBehavior ) .thenRun(_ => MandateNotCanceled ~> replyTo) } else { - val clientId = paymentAccount.clientId.orElse( - internalClientId - ) + val clientId = paymentAccount.clientId + .orElse(cmd.clientId) + .orElse( + internalClientId + ) val paymentProvider = loadPaymentProvider(clientId) import paymentProvider._ paymentAccount.bankAccount match { @@ -3047,9 +3050,11 @@ trait PaymentBehavior nextDebitedAmount = cmd.nextDebitedAmount, nextFeesAmount = cmd.nextFeesAmount ) - val clientId = paymentAccount.clientId.orElse( - internalClientId - ) + val clientId = paymentAccount.clientId + .orElse(cmd.clientId) + .orElse( + internalClientId + ) val paymentProvider = loadPaymentProvider(clientId) import paymentProvider._ registerRecurringCardPayment( @@ -3350,14 +3355,16 @@ trait PaymentBehavior creditedAccount: String, paymentAccount: PaymentAccount, creditedUserId: String, - bankAccountId: String + bankAccountId: String, + clientId: Option[String] = None )(implicit context: ActorContext[_], softPayClientSettings: SoftPayClientSettings ): Effect[ExternalSchedulerEvent, Option[PaymentAccount]] = { implicit val system: ActorSystem[_] = context.system - val clientId = paymentAccount.clientId.orElse(Option(softPayClientSettings.clientId)) - val paymentProvider = loadPaymentProvider(clientId) + val _clientId = + paymentAccount.clientId.orElse(clientId).orElse(Option(softPayClientSettings.clientId)) + val paymentProvider = loadPaymentProvider(_clientId) import paymentProvider._ mandate(creditedAccount, creditedUserId, bankAccountId) match { case Some(mandateResult) => diff --git a/core/src/main/scala/app/softnetwork/payment/service/MandateEndpoints.scala b/core/src/main/scala/app/softnetwork/payment/service/MandateEndpoints.scala index 06931cf..7d70681 100644 --- a/core/src/main/scala/app/softnetwork/payment/service/MandateEndpoints.scala +++ b/core/src/main/scala/app/softnetwork/payment/service/MandateEndpoints.scala @@ -36,7 +36,12 @@ trait MandateEndpoints[SD <: SessionData with SessionDataDecorator[SD]] { ) .serverLogic(principal => _ => - run(CreateMandate(externalUuidWithProfile(principal._2))).map { + run( + CreateMandate( + externalUuidWithProfile(principal._2), + clientId = principal._1.map(_.clientId).orElse(principal._2.clientId) + ) + ).map { case MandateCreated => Right(MandateCreated) case r: MandateConfirmationRequired => Right(r) case other => Left(error(other)) diff --git a/core/src/main/scala/app/softnetwork/payment/service/PaymentService.scala b/core/src/main/scala/app/softnetwork/payment/service/PaymentService.scala index 7837186..72fd6fd 100644 --- a/core/src/main/scala/app/softnetwork/payment/service/PaymentService.scala +++ b/core/src/main/scala/app/softnetwork/payment/service/PaymentService.scala @@ -564,7 +564,12 @@ trait PaymentService[SD <: SessionData with SessionDataDecorator[SD]] // check if a session exists requiredClientSession { (client, session) => post { - run(CreateMandate(externalUuidWithProfile(session))) completeWith { + run( + CreateMandate( + externalUuidWithProfile(session), + clientId = client.map(_.clientId).orElse(session.clientId) + ) + ) completeWith { case r: MandateConfirmationRequired => complete(HttpResponse(StatusCodes.OK, entity = r)) case MandateCreated => complete(HttpResponse(StatusCodes.OK)) From f6ce9f10f7fccb5f1845329435d61d50dd1a5e79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Manciot?= Date: Sat, 16 Mar 2024 09:56:50 +0100 Subject: [PATCH 36/37] to fix fmt --- .../app/softnetwork/payment/message/PaymentMessages.scala | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/common/src/main/scala/app/softnetwork/payment/message/PaymentMessages.scala b/common/src/main/scala/app/softnetwork/payment/message/PaymentMessages.scala index e9032dd..971f447 100644 --- a/common/src/main/scala/app/softnetwork/payment/message/PaymentMessages.scala +++ b/common/src/main/scala/app/softnetwork/payment/message/PaymentMessages.scala @@ -729,7 +729,8 @@ object PaymentMessages { * @param clientId * - optional client id */ - case class CreateMandate(creditedAccount: String, clientId: Option[String] = None) extends PaymentCommandWithKey { + case class CreateMandate(creditedAccount: String, clientId: Option[String] = None) + extends PaymentCommandWithKey { val key: String = creditedAccount } From ccd451b97aca5f121d79334c16735ec4f250842d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Manciot?= Date: Sat, 16 Mar 2024 10:48:51 +0100 Subject: [PATCH 37/37] add client publication --- build.sbt | 2 +- client/build.sbt | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/build.sbt b/build.sbt index 8b32d31..9ff45f7 100644 --- a/build.sbt +++ b/build.sbt @@ -32,7 +32,7 @@ Test / parallelExecution := false lazy val client = project.in(file("client")) .configs(IntegrationTest) .settings(Defaults.itSettings, app.softnetwork.Info.infoSettings) - .enablePlugins(BuildInfoPlugin, AkkaGrpcPlugin, JavaAppPackaging) + .enablePlugins(BuildInfoPlugin, AkkaGrpcPlugin, JavaAppPackaging, UniversalDeployPlugin) lazy val common = project.in(file("common")) .configs(IntegrationTest) diff --git a/client/build.sbt b/client/build.sbt index ef49d88..05b3533 100644 --- a/client/build.sbt +++ b/client/build.sbt @@ -1,7 +1,11 @@ +import com.typesafe.sbt.packager.SettingsHelper.makeDeploymentSettings + organization := "app.softnetwork.payment" name := "softpay" +maintainer := "stephane.manciot@gmail.com" + akkaGrpcGeneratedSources := Seq(AkkaGrpc.Client) val jacksonExclusions = Seq( @@ -24,3 +28,5 @@ libraryDependencies ++= Seq( ) Compile / mainClass := Some("app.softnetwork.payment.cli.Main") + +makeDeploymentSettings(Universal, packageBin in Universal, "zip") \ No newline at end of file