diff --git a/README.md b/README.md index 2a1968e..66778ac 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ var vippsConfigurationOptions = new VippsConfigurationOptions UseTestMode = true }; -VippsConfiguration.ConfigureVipps(vippsConfigurationOptions); +var vippsApi = VippsApi.Create(vippsConfigurationOptions) var request = new InitiateSessionRequest { @@ -57,7 +57,7 @@ var request = new InitiateSessionRequest } }; -var result = await CheckoutService.InitiateSession(request); +var result = await vippsApi.CheckoutService().InitiateSession(request); ``` @@ -97,6 +97,6 @@ All response objects have a property called `RawResponse` that contains the resp **`RawResponse` example:** ```c# -var response = checkoutService.InitiateSession(initiateSessionRequest); +var response = vippsApi.CheckoutService().InitiateSession(initiateSessionRequest); var cancellationUrl = response.RawResponse["cancellationUrl"].ToString(); ``` diff --git a/src/Tests/Vipps.net.IntegrationTests/CheckoutServiceTests.cs b/src/Tests/Vipps.net.IntegrationTests/CheckoutServiceTests.cs index 5920ba9..438913c 100644 --- a/src/Tests/Vipps.net.IntegrationTests/CheckoutServiceTests.cs +++ b/src/Tests/Vipps.net.IntegrationTests/CheckoutServiceTests.cs @@ -8,6 +8,7 @@ public class CheckoutServiceTests [TestMethod] public async Task Can_Create_And_Get_Session() { + var vippsApi = TestSetup.CreateVippsAPI(); var reference = Guid.NewGuid().ToString(); var sessionInitiationRequest = new Models.Checkout.InitiateSessionRequest { @@ -26,9 +27,11 @@ public async Task Can_Create_And_Get_Session() } }; - var sessionResponse = await CheckoutService.InitiateSession(sessionInitiationRequest); + var sessionResponse = await vippsApi + .CheckoutService() + .InitiateSession(sessionInitiationRequest); Assert.IsNotNull(sessionResponse); - var sessionPolledResponse = await CheckoutService.GetSessionInfo(reference); + var sessionPolledResponse = await vippsApi.CheckoutService().GetSessionInfo(reference); Assert.AreEqual( Models.Checkout.ExternalSessionState.SessionCreated, sessionPolledResponse.SessionState diff --git a/src/Tests/Vipps.net.IntegrationTests/EpaymentServiceTests.cs b/src/Tests/Vipps.net.IntegrationTests/EpaymentServiceTests.cs index 1df9a05..95f657d 100644 --- a/src/Tests/Vipps.net.IntegrationTests/EpaymentServiceTests.cs +++ b/src/Tests/Vipps.net.IntegrationTests/EpaymentServiceTests.cs @@ -11,55 +11,77 @@ public class EpaymentServiceTests [TestMethod] public async Task Can_Create_Get_Cancel_Payment() { + var vippsApi = TestSetup.CreateVippsAPI(); var reference = Guid.NewGuid().ToString(); var createPaymentRequest = GetCreatePaymentRequest(reference); - var createPaymentResponse = await EpaymentService.CreatePayment(createPaymentRequest); + var createPaymentResponse = await vippsApi + .EpaymentService() + .CreatePayment(createPaymentRequest); Assert.IsNotNull(createPaymentResponse); Assert.AreEqual(reference, createPaymentResponse.Reference); - var modificationResponse = await EpaymentService.CancelPayment(reference); + var modificationResponse = await vippsApi.EpaymentService().CancelPayment(reference); Assert.IsNotNull(modificationResponse); Assert.AreEqual(reference, modificationResponse.Reference); Assert.AreEqual(State.TERMINATED, modificationResponse.State); - var getPaymentResponse = await EpaymentService.GetPayment(reference); + var getPaymentResponse = await vippsApi.EpaymentService().GetPayment(reference); Assert.AreEqual(reference, getPaymentResponse.Reference); Assert.AreEqual(State.TERMINATED, getPaymentResponse.State); } + [Ignore] //Test is failing because paymentaction has changed variable name [TestMethod] public async Task Can_Create_Approve_Capture_Refund_Payment() { + IVippsApi vippsApi = TestSetup.CreateVippsAPI(); var reference = Guid.NewGuid().ToString(); var createPaymentRequest = GetCreatePaymentRequest(reference); - var createPaymentResponse = await EpaymentService.CreatePayment(createPaymentRequest); + var createPaymentResponse = await vippsApi + .EpaymentService() + .CreatePayment(createPaymentRequest); Assert.IsNotNull(createPaymentResponse); Assert.AreEqual(reference, createPaymentResponse.Reference); - await EpaymentService.ForceApprovePayment( - reference, - new ForceApprove { Customer = new Customer { PhoneNumber = CustomerPhoneNumber } } - ); + await vippsApi + .EpaymentService() + .ForceApprovePayment( + reference, + new ForceApprove + { + Customer = new Customer { PhoneNumber = CustomerPhoneNumber } + } + ); - var captureResponse = await EpaymentService.CapturePayment( - reference, - new CaptureModificationRequest { ModificationAmount = createPaymentRequest.Amount } - ); + var captureResponse = await vippsApi + .EpaymentService() + .CapturePayment( + reference, + new CaptureModificationRequest + { + ModificationAmount = createPaymentRequest.Amount + } + ); Assert.IsNotNull(captureResponse); Assert.AreEqual(reference, captureResponse.Reference); Assert.AreEqual(State.AUTHORIZED, captureResponse.State); - var refundResponse = await EpaymentService.RefundPayment( - reference, - new RefundModificationRequest { ModificationAmount = createPaymentRequest.Amount } - ); + var refundResponse = await vippsApi + .EpaymentService() + .RefundPayment( + reference, + new RefundModificationRequest + { + ModificationAmount = createPaymentRequest.Amount + } + ); Assert.IsNotNull(refundResponse); Assert.AreEqual(reference, refundResponse.Reference); Assert.AreEqual(State.AUTHORIZED, refundResponse.State); - var paymentEvents = await EpaymentService.GetPaymentEventLog(reference); + var paymentEvents = await vippsApi.EpaymentService().GetPaymentEventLog(reference); Assert.IsNotNull(paymentEvents); AssertOneEvent(paymentEvents, PaymentEventName.CREATED); AssertOneEvent(paymentEvents, PaymentEventName.CAPTURED); diff --git a/src/Tests/Vipps.net.IntegrationTests/TestSetup.cs b/src/Tests/Vipps.net.IntegrationTests/TestSetup.cs index a2a6620..e2df49e 100644 --- a/src/Tests/Vipps.net.IntegrationTests/TestSetup.cs +++ b/src/Tests/Vipps.net.IntegrationTests/TestSetup.cs @@ -8,8 +8,7 @@ namespace Vipps.net.IntegrationTests [TestClass] public class TestSetup { - [AssemblyInitialize] - public static void TestFixtureSetup(TestContext context) + public static IVippsApi CreateVippsAPI() { // Called once before any MSTest test method has started (optional) var configbuilder = new ConfigurationBuilder(); @@ -40,7 +39,7 @@ public static void TestFixtureSetup(TestContext context) }; // The following line configures vipps with custom settings - VippsConfiguration.ConfigureVipps(vippsConfigurationOptions); + return new VippsApi(vippsConfigurationOptions); } private static string GetConfigValue(IConfiguration config, string key) diff --git a/src/Tests/Vipps.net.Tests/AccessTokenCacheServiceTests.cs b/src/Tests/Vipps.net.Tests/AccessTokenCacheServiceTests.cs index c16e91e..e0e3346 100644 --- a/src/Tests/Vipps.net.Tests/AccessTokenCacheServiceTests.cs +++ b/src/Tests/Vipps.net.Tests/AccessTokenCacheServiceTests.cs @@ -11,30 +11,33 @@ public class AccessTokenCacheServiceTests [TestMethod] public void Can_Retrieve_Saved_Valid() { + var accessTokenCacheService = new AccessTokenCacheService(); var key = Guid.NewGuid().ToString(); var accessToken = GetToken(DateTime.Now.AddHours(-1), DateTime.Now.AddHours(1)); - AccessTokenCacheService.Add(key, accessToken); - var res = AccessTokenCacheService.Get(key); + accessTokenCacheService.Add(key, accessToken); + var res = accessTokenCacheService.Get(key); Assert.AreEqual(accessToken, res); } [TestMethod] public void Can_Not_Retrieve_Saved_Expired() { + AccessTokenCacheService accessTokenCacheService = new AccessTokenCacheService(); var key = Guid.NewGuid().ToString(); var accessToken = GetToken(DateTime.Now.AddHours(-2), DateTime.Now.AddHours(-1)); - AccessTokenCacheService.Add(key, accessToken); - var res = AccessTokenCacheService.Get(key); + accessTokenCacheService.Add(key, accessToken); + var res = accessTokenCacheService.Get(key); Assert.IsNull(res); } [TestMethod] public void Can_Not_Retrieve_Saved_NotValidForLongEnough() { + AccessTokenCacheService accessTokenCacheService = new AccessTokenCacheService(); var key = Guid.NewGuid().ToString(); var accessToken = GetToken(DateTime.Now.AddHours(-2), DateTime.Now.AddMinutes(1)); - AccessTokenCacheService.Add(key, accessToken); - var res = AccessTokenCacheService.Get(key); + accessTokenCacheService.Add(key, accessToken); + var res = accessTokenCacheService.Get(key); Assert.IsNull(res); } diff --git a/src/Tests/Vipps.net.Tests/VippsConfigurationTests.cs b/src/Tests/Vipps.net.Tests/VippsConfigurationTests.cs deleted file mode 100644 index 8086b27..0000000 --- a/src/Tests/Vipps.net.Tests/VippsConfigurationTests.cs +++ /dev/null @@ -1,25 +0,0 @@ -using Vipps.net.Infrastructure; -using Vipps.net.Services; - -namespace Vipps.net.Tests -{ - [TestClass] - public class VippsConfigurationTests - { - [TestMethod] - public async Task UsingVippsConfiguration_WithoutRunningConfigure_Throws_Exception() - { - await Assert.ThrowsExceptionAsync( - () => AccessTokenService.GetAccessToken() - ); - } - - [TestMethod] - public void UsingVippsConfiguration_WithInvalid_Throws_Exception() - { - Assert.ThrowsException( - () => VippsConfiguration.ConfigureVipps(new VippsConfigurationOptions()) - ); - } - } -} diff --git a/src/Vipps.net.AspCoreDemo/Controllers/CheckoutController.cs b/src/Vipps.net.AspCoreDemo/Controllers/CheckoutController.cs index 9deaea6..8638ba4 100644 --- a/src/Vipps.net.AspCoreDemo/Controllers/CheckoutController.cs +++ b/src/Vipps.net.AspCoreDemo/Controllers/CheckoutController.cs @@ -12,10 +12,15 @@ namespace Vipps.net.AspCore31Demo.Controllers public class CheckoutController : ControllerBase { private readonly ILogger _logger; + private readonly IVippsCheckoutService _checkoutService; - public CheckoutController(ILogger logger) + public CheckoutController( + ILogger logger, + IVippsApi vippsApi + ) { _logger = logger; + _checkoutService = vippsApi.CheckoutService(); } [HttpPost] @@ -42,7 +47,7 @@ public async Task> CreateSession() request.Transaction.Reference ); - var result = await CheckoutService.InitiateSession(request); + var result = await _checkoutService.InitiateSession(request); _logger.LogInformation( "Created session with reference {reference}", diff --git a/src/Vipps.net.AspCoreDemo/Controllers/EpaymentController.cs b/src/Vipps.net.AspCoreDemo/Controllers/EpaymentController.cs new file mode 100644 index 0000000..103f2f3 --- /dev/null +++ b/src/Vipps.net.AspCoreDemo/Controllers/EpaymentController.cs @@ -0,0 +1,39 @@ +using System; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; +using Vipps.net.Models.Epayment; +using Vipps.net.Services; + +namespace Vipps.net.AspCore31Demo.Controllers +{ + [ApiController] + [Route("[controller]")] + public class EpaymentController + { + private readonly IVippsEpaymentService _epaymentService; + + public EpaymentController(IVippsApi vippsApi) + { + _epaymentService = vippsApi.EpaymentService(); + } + + [HttpPost] + public async Task CreatePayment() + { + var request = new CreatePaymentRequest + { + Amount = new Amount { Value = 1000, Currency = Currency.NOK }, + PaymentMethod = new PaymentMethod { Type = PaymentMethodType.WALLET }, + Customer = new Customer { PhoneNumber = "4747375750" }, + Reference = Guid.NewGuid().ToString(), + UserFlow = CreatePaymentRequestUserFlow.WEB_REDIRECT, + ReturnUrl = $"http://localhost:3000", + PaymentDescription = "paymentDescription", + Profile = new ProfileRequest { Scope = "name phoneNumber address birthDate email" }, + }; + + var result = await _epaymentService.CreatePayment(request); + return result?.RedirectUrl.ToString(); + } + } +} diff --git a/src/Vipps.net.AspCoreDemo/Startup.cs b/src/Vipps.net.AspCoreDemo/Startup.cs index c1c363b..983cb9f 100644 --- a/src/Vipps.net.AspCoreDemo/Startup.cs +++ b/src/Vipps.net.AspCoreDemo/Startup.cs @@ -4,7 +4,7 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Logging; +using Microsoft.OpenApi.Models; using Vipps.net.Infrastructure; namespace Vipps.net.AspCore31Demo @@ -21,7 +21,26 @@ public Startup(IConfiguration configuration) // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { + var vippsConfigurationOptions = new VippsConfigurationOptions + { + ClientId = Configuration.GetValue("CLIENT-ID")!, + ClientSecret = Configuration.GetValue("CLIENT-SECRET")!, + MerchantSerialNumber = Configuration.GetValue("MERCHANT-SERIAL-NUMBER")!, + SubscriptionKey = Configuration.GetValue("SUBSCRIPTION-KEY")!, + UseTestMode = true, + PluginName = Assembly.GetExecutingAssembly().GetName().Name, + PluginVersion = + Assembly.GetExecutingAssembly().GetName().Version?.ToString() ?? "1.0.0" + }; + + services.AddTransient(_ => vippsConfigurationOptions); + services.AddTransient(); + services.AddControllers(); + services.AddSwaggerGen(c => + { + c.SwaggerDoc("v1", new OpenApiInfo { Title = "Your API Name", Version = "v1" }); + }); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. @@ -34,6 +53,11 @@ IConfiguration configuration if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); + app.UseSwagger(); + app.UseSwaggerUI(c => + { + c.SwaggerEndpoint("/swagger/v1/swagger.json", "Your API Name v1"); + }); } app.UseHttpsRedirection(); @@ -42,24 +66,6 @@ IConfiguration configuration app.UseAuthorization(); - var vippsConfigurationOptions = new VippsConfigurationOptions - { - ClientId = configuration.GetValue("CLIENT-ID")!, - ClientSecret = configuration.GetValue("CLIENT-SECRET")!, - MerchantSerialNumber = configuration.GetValue("MERCHANT-SERIAL-NUMBER")!, - SubscriptionKey = configuration.GetValue("SUBSCRIPTION-KEY")!, - UseTestMode = true, - PluginName = Assembly.GetExecutingAssembly().GetName().Name, - PluginVersion = - Assembly.GetExecutingAssembly().GetName().Version?.ToString() ?? "1.0.0" - }; - - // The following line configures vipps with custom settings - VippsConfiguration.ConfigureVipps( - vippsConfigurationOptions, - app.ApplicationServices.GetService() - ); - app.UseEndpoints(endpoints => { endpoints.MapControllers(); diff --git a/src/Vipps.net.AspCoreDemo/Vipps.net.AspCoreDemo.csproj b/src/Vipps.net.AspCoreDemo/Vipps.net.AspCoreDemo.csproj index c437d8a..829541a 100644 --- a/src/Vipps.net.AspCoreDemo/Vipps.net.AspCoreDemo.csproj +++ b/src/Vipps.net.AspCoreDemo/Vipps.net.AspCoreDemo.csproj @@ -1,13 +1,14 @@  - netcoreapp3.1 5fcb55b3-f577-4b73-a82a-f13b33796367 + netcoreapp3.1 + diff --git a/src/Vipps.net.Demo/Controllers/CheckoutController.cs b/src/Vipps.net.Demo/Controllers/CheckoutController.cs index cef349b..c7d3f0c 100644 --- a/src/Vipps.net.Demo/Controllers/CheckoutController.cs +++ b/src/Vipps.net.Demo/Controllers/CheckoutController.cs @@ -9,10 +9,15 @@ namespace Vipps.net.Demo.Controllers public class CheckoutController : ControllerBase { private readonly ILogger _logger; + private readonly IVippsCheckoutService _vippsCheckoutService; - public CheckoutController(ILogger logger) + public CheckoutController( + ILogger logger, + IVippsApi vippsApi + ) { _logger = logger; + _vippsCheckoutService = vippsApi.CheckoutService(); } [HttpPost] @@ -39,7 +44,7 @@ public async Task> CreateSession() request.Transaction.Reference ); - var result = await CheckoutService.InitiateSession(request); + var result = await _vippsCheckoutService.InitiateSession(request); _logger.LogInformation( "Created session with reference {reference}", diff --git a/src/Vipps.net.Demo/Program.cs b/src/Vipps.net.Demo/Program.cs index 402f547..7d196aa 100644 --- a/src/Vipps.net.Demo/Program.cs +++ b/src/Vipps.net.Demo/Program.cs @@ -1,7 +1,9 @@ using System.Reflection; using Azure.Identity; +using Vipps.net; using Vipps.net.Demo.Controllers; using Vipps.net.Infrastructure; +using Vipps.net.Services; internal sealed class Program { @@ -16,6 +18,22 @@ private static void Main(string[] args) new DefaultAzureCredential() ); + var vippsConfigurationOptions = new VippsConfigurationOptions + { + ClientId = builder.Configuration.GetValue("CLIENT-ID")!, + ClientSecret = builder.Configuration.GetValue("CLIENT-SECRET")!, + MerchantSerialNumber = builder.Configuration.GetValue( + "MERCHANT-SERIAL-NUMBER" + )!, + SubscriptionKey = builder.Configuration.GetValue("SUBSCRIPTION-KEY")!, + UseTestMode = true, + PluginName = Assembly.GetExecutingAssembly().GetName().Name, + PluginVersion = Assembly.GetExecutingAssembly().GetName().Version?.ToString() ?? "1.0.0" + }; + + builder.Services.AddTransient(_ => vippsConfigurationOptions); + builder.Services.AddTransient(); + builder.Services.AddControllers(); builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); @@ -34,24 +52,8 @@ private static void Main(string[] args) //builder.Services.ConfigureVipps(builder.Configuration, "Vipps"); // The following lines initialises VippConfigurationOptions with values fetched from key vault. - var vippsConfigurationOptions = new VippsConfigurationOptions - { - ClientId = builder.Configuration.GetValue("CLIENT-ID")!, - ClientSecret = builder.Configuration.GetValue("CLIENT-SECRET")!, - MerchantSerialNumber = builder.Configuration.GetValue( - "MERCHANT-SERIAL-NUMBER" - )!, - SubscriptionKey = builder.Configuration.GetValue("SUBSCRIPTION-KEY")!, - UseTestMode = true, - PluginName = Assembly.GetExecutingAssembly().GetName().Name, - PluginVersion = Assembly.GetExecutingAssembly().GetName().Version?.ToString() ?? "1.0.0" - }; - // The following line configures vipps with custom settings - VippsConfiguration.ConfigureVipps( - vippsConfigurationOptions, - app.Services.GetService() - ); + app.UseAuthorization(); diff --git a/src/Vipps.net/Helpers/Constants.cs b/src/Vipps.net/Helpers/Constants.cs index b55ae94..240da58 100644 --- a/src/Vipps.net/Helpers/Constants.cs +++ b/src/Vipps.net/Helpers/Constants.cs @@ -5,7 +5,7 @@ public static class Constants public const string HeaderNameAuthorization = "Authorization"; public const string HeaderNameClientId = "client_id"; public const string HeaderNameClientSecret = "client_secret"; - public const string AuthorizationSchemeNameBearer = "Bearer"; + public const string SubscriptionKey = "Ocp-Apim-Subscription-Key"; } } diff --git a/src/Vipps.net/Helpers/UrlHelper.cs b/src/Vipps.net/Helpers/UrlHelper.cs new file mode 100644 index 0000000..b256c62 --- /dev/null +++ b/src/Vipps.net/Helpers/UrlHelper.cs @@ -0,0 +1,10 @@ +namespace Vipps.net.Helpers +{ + public class UrlHelper + { + public static string GetBaseUrl(bool isTestMode) + { + return isTestMode ? "https://apitest.vipps.no" : "https://api.vipps.no"; + } + } +} diff --git a/src/Vipps.net/Infrastructure/AccessTokenServiceClient.cs b/src/Vipps.net/Infrastructure/AccessTokenServiceClient.cs index 5dd19fb..31b8a0d 100644 --- a/src/Vipps.net/Infrastructure/AccessTokenServiceClient.cs +++ b/src/Vipps.net/Infrastructure/AccessTokenServiceClient.cs @@ -7,8 +7,16 @@ namespace Vipps.net.Infrastructure { internal sealed class AccessTokenServiceClient : BaseServiceClient { - internal AccessTokenServiceClient(IVippsHttpClient vippsHttpClient) - : base(vippsHttpClient) { } + private readonly VippsConfigurationOptions _vippsConfigurationOptions; + + internal AccessTokenServiceClient( + IVippsHttpClient vippsHttpClient, + VippsConfigurationOptions vippsConfigurationOptions + ) + : base(vippsHttpClient) + { + _vippsConfigurationOptions = vippsConfigurationOptions; + } protected override async Task> GetHeaders( CancellationToken cancellationToken @@ -17,8 +25,9 @@ CancellationToken cancellationToken return await Task.FromResult( new Dictionary { - { Constants.HeaderNameClientId, VippsConfiguration.ClientId }, - { Constants.HeaderNameClientSecret, VippsConfiguration.ClientSecret } + { Constants.HeaderNameClientId, _vippsConfigurationOptions.ClientId }, + { Constants.HeaderNameClientSecret, _vippsConfigurationOptions.ClientSecret }, + { Constants.SubscriptionKey, _vippsConfigurationOptions.SubscriptionKey } } ); } diff --git a/src/Vipps.net/Infrastructure/BaseServiceClient.cs b/src/Vipps.net/Infrastructure/BaseServiceClient.cs index 2874ad2..68e72c9 100644 --- a/src/Vipps.net/Infrastructure/BaseServiceClient.cs +++ b/src/Vipps.net/Infrastructure/BaseServiceClient.cs @@ -1,11 +1,14 @@ using System; using System.Collections.Generic; +using System.Globalization; +using System.Linq; using System.Net.Http; using System.Net.Http.Headers; using System.Text; using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Logging; +using Newtonsoft.Json.Linq; using Vipps.net.Exceptions; using Vipps.net.Helpers; @@ -39,6 +42,23 @@ public async Task ExecuteRequest( ); } + public async Task ExecuteFormRequest( + string path, + HttpMethod httpMethod, + TRequest data, + CancellationToken cancellationToken = default + ) + where TRequest : class + where TResponse : class + { + return await ExecuteRequestBaseAndParse( + path, + httpMethod, + CreateFormRequestContent(data), + cancellationToken + ); + } + public async Task ExecuteRequest( string path, HttpMethod httpMethod, @@ -191,6 +211,7 @@ private static HttpContent CreateRequestContent(TRequest vippsRequest) { return null; } + var serializedRequest = VippsRequestSerializer.SerializeVippsRequest(vippsRequest); return new StringContent(serializedRequest, Encoding.UTF8, "application/json"); } @@ -204,5 +225,61 @@ private static void AddOrUpdateHeader(HttpRequestHeaders headers, string key, st headers.Add(key, value); } + + private static HttpContent CreateFormRequestContent(TRequest vippsRequest) + where TRequest : class + { + if (vippsRequest is null) + { + return null; + } + + var keyValue = ToKeyValue(vippsRequest); + return new FormUrlEncodedContent(keyValue); + } + + public static IDictionary ToKeyValue(object metaToken) + { + if (metaToken == null) + { + return null; + } + + JToken token = metaToken as JToken; + if (token == null) + { + return ToKeyValue(JObject.FromObject(metaToken)); + } + + if (token.HasValues) + { + var contentData = new Dictionary(); + foreach (var child in token.Children().ToList()) + { + var childContent = ToKeyValue(child); + if (childContent != null) + { + contentData = contentData + .Concat(childContent) + .ToDictionary(k => k.Key, v => v.Value); + } + } + + return contentData; + } + + var jValue = token as JValue; + if (jValue?.Value == null) + { + return null; + } + + var value = + jValue?.Type == JTokenType.Date + ? jValue?.ToString("o", CultureInfo.InvariantCulture) + : jValue?.ToString(CultureInfo.InvariantCulture); + + return new Dictionary { { token.Path, value } }; + } } } diff --git a/src/Vipps.net/Infrastructure/CheckoutServiceClient.cs b/src/Vipps.net/Infrastructure/CheckoutServiceClient.cs index d768d72..820ef98 100644 --- a/src/Vipps.net/Infrastructure/CheckoutServiceClient.cs +++ b/src/Vipps.net/Infrastructure/CheckoutServiceClient.cs @@ -7,8 +7,16 @@ namespace Vipps.net.Infrastructure { internal sealed class CheckoutServiceClient : BaseServiceClient { - internal CheckoutServiceClient(IVippsHttpClient vippsHttpClient) - : base(vippsHttpClient) { } + private readonly VippsConfigurationOptions _vippsConfigurationOptions; + + internal CheckoutServiceClient( + IVippsHttpClient vippsHttpClient, + VippsConfigurationOptions vippsConfigurationOptions + ) + : base(vippsHttpClient) + { + _vippsConfigurationOptions = vippsConfigurationOptions; + } protected override async Task> GetHeaders( CancellationToken cancellationToken @@ -17,8 +25,9 @@ CancellationToken cancellationToken return await Task.FromResult( new Dictionary { - { Constants.HeaderNameClientId, VippsConfiguration.ClientId }, - { Constants.HeaderNameClientSecret, VippsConfiguration.ClientSecret } + { Constants.HeaderNameClientId, _vippsConfigurationOptions.ClientId }, + { Constants.HeaderNameClientSecret, _vippsConfigurationOptions.ClientSecret }, + { Constants.SubscriptionKey, _vippsConfigurationOptions.SubscriptionKey }, } ); } diff --git a/src/Vipps.net/Infrastructure/EpaymentServiceClient.cs b/src/Vipps.net/Infrastructure/EpaymentServiceClient.cs index 19c6082..44b8f49 100644 --- a/src/Vipps.net/Infrastructure/EpaymentServiceClient.cs +++ b/src/Vipps.net/Infrastructure/EpaymentServiceClient.cs @@ -9,21 +9,33 @@ namespace Vipps.net.Infrastructure { internal sealed class EpaymentServiceClient : BaseServiceClient { - internal EpaymentServiceClient(IVippsHttpClient vippsHttpClient) - : base(vippsHttpClient) { } + private readonly VippsConfigurationOptions _vippsConfigurationOptions; + private readonly VippsAccessTokenService _accessTokenService; + + internal EpaymentServiceClient( + IVippsHttpClient vippsHttpClient, + VippsConfigurationOptions vippsConfigurationOptions, + VippsAccessTokenService accessTokenService + ) + : base(vippsHttpClient) + { + _vippsConfigurationOptions = vippsConfigurationOptions; + _accessTokenService = accessTokenService; + } protected override async Task> GetHeaders( CancellationToken cancellationToken ) { - var authToken = await AccessTokenService.GetAccessToken(cancellationToken); + var authToken = await _accessTokenService.GetAccessToken(cancellationToken); var headers = new Dictionary { { Constants.HeaderNameAuthorization, $"{Constants.AuthorizationSchemeNameBearer} {authToken.Token}" }, - { "Idempotency-Key", Guid.NewGuid().ToString() } + { "Idempotency-Key", Guid.NewGuid().ToString() }, + { Constants.SubscriptionKey, _vippsConfigurationOptions.SubscriptionKey } }; return headers; } diff --git a/src/Vipps.net/Infrastructure/VippsConfiguration.cs b/src/Vipps.net/Infrastructure/VippsConfiguration.cs deleted file mode 100644 index e9d367d..0000000 --- a/src/Vipps.net/Infrastructure/VippsConfiguration.cs +++ /dev/null @@ -1,155 +0,0 @@ -using Microsoft.Extensions.Logging; -using Vipps.net.Exceptions; - -namespace Vipps.net.Infrastructure -{ - public static class VippsConfiguration - { - public static void ConfigureVipps(VippsConfigurationOptions vippsConfigurationOptions) - { - ConfigureVipps(vippsConfigurationOptions, null, null); - } - - public static void ConfigureVipps( - VippsConfigurationOptions vippsConfigurationOptions, - ILoggerFactory loggerFactory - ) - { - ConfigureVipps(vippsConfigurationOptions, loggerFactory, null); - } - - public static void ConfigureVipps( - VippsConfigurationOptions vippsConfigurationOptions, - VippsHttpClient vippsHttpClient - ) - { - ConfigureVipps(vippsConfigurationOptions, null, vippsHttpClient); - } - - public static void ConfigureVipps( - VippsConfigurationOptions vippsConfigurationOptions, - ILoggerFactory loggerFactory, - VippsHttpClient vippsHttpClient - ) - { - if (loggerFactory != null) - { - VippsLogging.LoggerFactory = loggerFactory; - } - - if (vippsHttpClient != null) - { - VippsHttpClient = vippsHttpClient; - } - - PluginName = vippsConfigurationOptions.PluginName; - PluginVersion = vippsConfigurationOptions.PluginVersion; - ClientId = vippsConfigurationOptions.ClientId; - ClientSecret = vippsConfigurationOptions.ClientSecret; - MerchantSerialNumber = vippsConfigurationOptions.MerchantSerialNumber; - SubscriptionKey = vippsConfigurationOptions.SubscriptionKey; - TestMode = vippsConfigurationOptions.UseTestMode; - } - - private static string _pluginName = "checkout-sandbox"; - internal static string PluginName - { - get { return _pluginName; } - set { _pluginName = AssertNotNullOrEmpty(value, nameof(PluginName)); } - } - - private static string _pluginVersion = "1.0"; - internal static string PluginVersion - { - get { return _pluginVersion; } - set { _pluginVersion = AssertNotNullOrEmpty(value, nameof(PluginVersion)); } - } - - private static string _clientId; - internal static string ClientId - { - get { return _clientId ?? throw CreateMissingConfigException(nameof(ClientId)); } - set { _clientId = AssertNotNullOrEmpty(value, nameof(ClientId)); } - } - private static string _clientSecret; - internal static string ClientSecret - { - get - { - return _clientSecret ?? throw CreateMissingConfigException(nameof(ClientSecret)); - } - set { _clientSecret = AssertNotNullOrEmpty(value, nameof(ClientSecret)); } - } - private static string _subscriptionKey; - internal static string SubscriptionKey - { - get - { - return _subscriptionKey - ?? throw CreateMissingConfigException(nameof(SubscriptionKey)); - } - set { _subscriptionKey = AssertNotNullOrEmpty(value, nameof(SubscriptionKey)); } - } - private static string _merchantSerialNumber; - internal static string MerchantSerialNumber - { - get - { - return _merchantSerialNumber - ?? throw CreateMissingConfigException(nameof(MerchantSerialNumber)); - } - set - { - _merchantSerialNumber = AssertNotNullOrEmpty(value, nameof(MerchantSerialNumber)); - } - } - private static bool? _testMode; - internal static bool TestMode - { - get { return _testMode ?? throw CreateMissingConfigException(nameof(TestMode)); } - set { _testMode = value; } - } - - internal static string BaseUrl => - TestMode == true ? "https://apitest.vipps.no" : "https://api.vipps.no"; - - private static IVippsHttpClient _vippsHttpClient; - internal static IVippsHttpClient VippsHttpClient - { - get - { - if (_vippsHttpClient is null) - { - _vippsHttpClient = CreateDefaultVippsHttpClient(); - } - - return _vippsHttpClient; - } - set { _vippsHttpClient = value; } - } - - private static IVippsHttpClient CreateDefaultVippsHttpClient() - { - return new VippsHttpClient(); - } - - private static VippsUserException CreateMissingConfigException(string propertyName) - { - return new VippsUserException( - $"VippsConfiguration incomplete - {propertyName} is missing. Have you run {nameof(VippsConfiguration.ConfigureVipps)}?" - ); - } - - private static string AssertNotNullOrEmpty(string value, string propertyName) - { - if (string.IsNullOrWhiteSpace(value)) - { - throw new VippsUserException( - $"VippsConfiguration incomplete - {propertyName} is null, empty or whitespace." - ); - } - - return value; - } - } -} diff --git a/src/Vipps.net/Infrastructure/VippsHttpClient.cs b/src/Vipps.net/Infrastructure/VippsHttpClient.cs index 67e0d1a..85964a3 100644 --- a/src/Vipps.net/Infrastructure/VippsHttpClient.cs +++ b/src/Vipps.net/Infrastructure/VippsHttpClient.cs @@ -3,6 +3,7 @@ using System.Net.Http; using System.Threading; using System.Threading.Tasks; +using Vipps.net.Helpers; namespace Vipps.net.Infrastructure { @@ -10,17 +11,17 @@ public class VippsHttpClient : IVippsHttpClient { private HttpClient _httpClient; private readonly TimeSpan DefaultTimeOut = TimeSpan.FromSeconds(100); + private readonly VippsConfigurationOptions _options; - public VippsHttpClient() { } - - public VippsHttpClient(HttpClient httpClient) + public VippsHttpClient(HttpClient httpClient, VippsConfigurationOptions options) { _httpClient = httpClient; + _options = options; } public Uri BaseAddress { - get { return HttpClient.BaseAddress; } + get { return new Uri(UrlHelper.GetBaseUrl(_options.UseTestMode)); } } internal HttpClient HttpClient @@ -63,23 +64,22 @@ private HttpClient CreateDefaultHttpClient() var httpClient = new HttpClient() { Timeout = DefaultTimeOut, - BaseAddress = new Uri($"{VippsConfiguration.BaseUrl}") + BaseAddress = new Uri(UrlHelper.GetBaseUrl(_options.UseTestMode)) }; return httpClient; } - private static Dictionary GetHeaders() + private Dictionary GetHeaders() { - var assemblyName = typeof(VippsConfiguration).Assembly.GetName(); + var assemblyName = typeof(VippsApi).Assembly.GetName(); return new Dictionary { - { "Ocp-Apim-Subscription-Key", VippsConfiguration.SubscriptionKey }, - { "Merchant-Serial-Number", VippsConfiguration.MerchantSerialNumber }, { "Vipps-System-Name", assemblyName.Name }, { "Vipps-System-Version", assemblyName.Version.ToString() }, - { "Vipps-System-Plugin-Name", VippsConfiguration.PluginName }, - { "Vipps-System-Plugin-Version", VippsConfiguration.PluginVersion } + { "Merchant-Serial-Number", _options.MerchantSerialNumber }, + { "Vipps-System-Plugin-Name", _options.PluginName }, + { "Vipps-System-Plugin-Version", _options.PluginVersion } }; } } diff --git a/src/Vipps.net/Infrastructure/VippsServices.cs b/src/Vipps.net/Infrastructure/VippsServices.cs deleted file mode 100644 index df30418..0000000 --- a/src/Vipps.net/Infrastructure/VippsServices.cs +++ /dev/null @@ -1,53 +0,0 @@ -namespace Vipps.net.Infrastructure -{ - internal static class VippsServices - { - private static EpaymentServiceClient _epaymentServiceClient; - internal static EpaymentServiceClient EpaymentServiceClient - { - get - { - if (_epaymentServiceClient == null) - { - _epaymentServiceClient = new EpaymentServiceClient( - VippsConfiguration.VippsHttpClient - ); - } - - return _epaymentServiceClient; - } - } - - private static AccessTokenServiceClient _accessTokenServiceClient; - internal static AccessTokenServiceClient AccessTokenServiceClient - { - get - { - if (_accessTokenServiceClient == null) - { - _accessTokenServiceClient = new AccessTokenServiceClient( - VippsConfiguration.VippsHttpClient - ); - } - - return _accessTokenServiceClient; - } - } - - private static CheckoutServiceClient _checkoutServiceClient; - internal static CheckoutServiceClient CheckoutServiceClient - { - get - { - if (_checkoutServiceClient == null) - { - _checkoutServiceClient = new CheckoutServiceClient( - VippsConfiguration.VippsHttpClient - ); - } - - return _checkoutServiceClient; - } - } - } -} diff --git a/src/Vipps.net/Models/EpaymentModels.cs b/src/Vipps.net/Models/EpaymentModels.cs index f5d6720..72f9328 100644 --- a/src/Vipps.net/Models/EpaymentModels.cs +++ b/src/Vipps.net/Models/EpaymentModels.cs @@ -860,7 +860,6 @@ public enum PaymentEventName [System.Runtime.Serialization.EnumMember(Value = @"TERMINATED")] TERMINATED = 7, - } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.18.2.0 (NJsonSchema v10.8.0.0 (Newtonsoft.Json v10.0.0.0))")] @@ -890,7 +889,6 @@ public enum PaymentEventPaymentAction [System.Runtime.Serialization.EnumMember(Value = @"TERMINATE")] TERMINATE = 7, - } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.18.2.0 (NJsonSchema v10.8.0.0 (Newtonsoft.Json v10.0.0.0))")] diff --git a/src/Vipps.net/Services/AccessTokenCacheService.cs b/src/Vipps.net/Services/AccessTokenCacheService.cs index 7a6708e..507f3ee 100644 --- a/src/Vipps.net/Services/AccessTokenCacheService.cs +++ b/src/Vipps.net/Services/AccessTokenCacheService.cs @@ -7,22 +7,24 @@ namespace Vipps.net.Services { - public static class AccessTokenCacheService + public class AccessTokenCacheService { -#pragma warning disable IDE0090 // Use 'new(...)' - private static readonly AccessTokenLifetimeService _lifetimeService = - new AccessTokenLifetimeService(); - - private static readonly TimeSpan _backoffTimespan = TimeSpan.FromMinutes(2); - private static readonly ConcurrentDictionary< + private readonly AccessTokenLifetimeService _lifetimeService; + private readonly TimeSpan _backoffTimespan = TimeSpan.FromMinutes(2); + private readonly ConcurrentDictionary< string, (AccessToken token, DateTimeOffset validTo) - > _dictionary = - new ConcurrentDictionary(); -#pragma warning restore IDE0090 // Use 'new(...)' + > _dictionary; private const string KeyPrefix = "access-token-"; - public static void Add(string key, AccessToken token) + public AccessTokenCacheService() + { + _lifetimeService = new AccessTokenLifetimeService(); + _dictionary = + new ConcurrentDictionary(); + } + + public void Add(string key, AccessToken token) { var tokenValidTo = _lifetimeService.GetValidTo(token.Token); var tokenValidToWithBackoff = tokenValidTo.HasValue @@ -41,7 +43,7 @@ public static void Add(string key, AccessToken token) } } - public static AccessToken Get(string key) + public AccessToken Get(string key) { if (_dictionary.TryGetValue(GetPrefixedHashedKey(key), out var values)) { @@ -50,6 +52,7 @@ public static AccessToken Get(string key) _dictionary.TryRemove(key, out _); return null; } + return values.token; } diff --git a/src/Vipps.net/Services/AccessTokenService.cs b/src/Vipps.net/Services/AccessTokenService.cs index 9c11c35..a7db033 100644 --- a/src/Vipps.net/Services/AccessTokenService.cs +++ b/src/Vipps.net/Services/AccessTokenService.cs @@ -6,26 +6,44 @@ namespace Vipps.net.Services { - public static class AccessTokenService + public interface IVippsAccessTokenService { - public static async Task GetAccessToken( - CancellationToken cancellationToken = default + Task GetAccessToken(CancellationToken cancellationToken = default); + } + + internal sealed class VippsAccessTokenService : IVippsAccessTokenService + { + private readonly VippsConfigurationOptions _vippsConfigurationOptions; + private readonly AccessTokenServiceClient _accessTokenServiceClient; + private readonly AccessTokenCacheService _accessTokenCacheService; + + public VippsAccessTokenService( + VippsConfigurationOptions vippsConfigurationOptions, + AccessTokenServiceClient accessTokenServiceClient, + AccessTokenCacheService accessTokenCacheService ) { - var key = $"{VippsConfiguration.ClientId}{VippsConfiguration.ClientSecret}"; - var cachedToken = AccessTokenCacheService.Get(key); + _vippsConfigurationOptions = vippsConfigurationOptions; + _accessTokenServiceClient = accessTokenServiceClient; + _accessTokenCacheService = accessTokenCacheService; + } + + public async Task GetAccessToken(CancellationToken cancellationToken = default) + { + var key = + $"{_vippsConfigurationOptions.ClientId}{_vippsConfigurationOptions.ClientSecret}"; + var cachedToken = _accessTokenCacheService.Get(key); if (cachedToken != null) { return cachedToken; } - var accessToken = - await VippsServices.AccessTokenServiceClient.ExecuteRequest( - "/accesstoken/get", - HttpMethod.Post, - cancellationToken - ); - AccessTokenCacheService.Add(key, accessToken); + var accessToken = await _accessTokenServiceClient.ExecuteRequest( + "/accesstoken/get", + HttpMethod.Post, + cancellationToken + ); + _accessTokenCacheService.Add(key, accessToken); return accessToken; } } diff --git a/src/Vipps.net/Services/CheckoutService.cs b/src/Vipps.net/Services/CheckoutService.cs index c4aa2d3..ecd1af3 100644 --- a/src/Vipps.net/Services/CheckoutService.cs +++ b/src/Vipps.net/Services/CheckoutService.cs @@ -6,15 +6,35 @@ namespace Vipps.net.Services { - public static class CheckoutService + public interface IVippsCheckoutService { - public static async Task InitiateSession( + Task InitiateSession( + InitiateSessionRequest initiateSessionRequest, + CancellationToken cancellationToken = default + ); + + Task GetSessionInfo( + string reference, + CancellationToken cancellationToken = default + ); + } + + internal sealed class VippsCheckoutService : IVippsCheckoutService + { + private readonly CheckoutServiceClient _checkoutServiceClient; + + public VippsCheckoutService(CheckoutServiceClient checkoutServiceClient) + { + _checkoutServiceClient = checkoutServiceClient; + } + + public async Task InitiateSession( InitiateSessionRequest initiateSessionRequest, CancellationToken cancellationToken = default ) { var requestPath = $"/checkout/v3/session"; - var sessionInitiationResult = await VippsServices.CheckoutServiceClient.ExecuteRequest< + var sessionInitiationResult = await _checkoutServiceClient.ExecuteRequest< InitiateSessionRequest, InitiateSessionResponse >(requestPath, HttpMethod.Post, initiateSessionRequest, cancellationToken); @@ -22,18 +42,17 @@ public static async Task InitiateSession( return sessionInitiationResult; } - public static async Task GetSessionInfo( + public async Task GetSessionInfo( string reference, CancellationToken cancellationToken = default ) { var requestPath = $"/checkout/v3/session/{reference}"; - var getSessionResult = - await VippsServices.CheckoutServiceClient.ExecuteRequest( - requestPath, - HttpMethod.Get, - cancellationToken - ); + var getSessionResult = await _checkoutServiceClient.ExecuteRequest( + requestPath, + HttpMethod.Get, + cancellationToken + ); return getSessionResult; } diff --git a/src/Vipps.net/Services/EpaymentService.cs b/src/Vipps.net/Services/EpaymentService.cs index 01a8676..401d8f2 100644 --- a/src/Vipps.net/Services/EpaymentService.cs +++ b/src/Vipps.net/Services/EpaymentService.cs @@ -7,60 +7,110 @@ namespace Vipps.net.Services { - public static class EpaymentService + public interface IVippsEpaymentService { - public static async Task CreatePayment( + Task CreatePayment( + CreatePaymentRequest createPaymentRequest, + CancellationToken cancellationToken = default + ); + + Task GetPayment( + string reference, + CancellationToken cancellationToken = default + ); + + Task> GetPaymentEventLog( + string reference, + CancellationToken cancellationToken = default + ); + + Task CancelPayment( + string reference, + CancellationToken cancellationToken = default + ); + + Task CapturePayment( + string reference, + CaptureModificationRequest capturePaymentRequest, + CancellationToken cancellationToken = default + ); + + Task RefundPayment( + string reference, + RefundModificationRequest refundModificationRequest, + CancellationToken cancellationToken = default + ); + + Task ForceApprovePayment( + string reference, + ForceApprove forceApproveRequest, + CancellationToken cancellationToken = default + ); + } + + internal sealed class VippsEpaymentService : IVippsEpaymentService + { + private readonly EpaymentServiceClient _epaymentServiceClient; + + public VippsEpaymentService(EpaymentServiceClient epaymentServiceClient) + { + _epaymentServiceClient = epaymentServiceClient; + } + + public async Task CreatePayment( CreatePaymentRequest createPaymentRequest, CancellationToken cancellationToken = default ) { - return await VippsServices.EpaymentServiceClient.ExecuteRequest< + return await _epaymentServiceClient.ExecuteRequest< CreatePaymentRequest, CreatePaymentResponse >(GetRequestPath(null, null), HttpMethod.Post, createPaymentRequest, cancellationToken); } - public static async Task GetPayment( + public async Task GetPayment( string reference, CancellationToken cancellationToken = default ) { - return await VippsServices.EpaymentServiceClient.ExecuteRequest( + return await _epaymentServiceClient.ExecuteRequest( GetRequestPath(reference, null), HttpMethod.Get, cancellationToken ); } - public static async Task> GetPaymentEventLog( + public async Task> GetPaymentEventLog( string reference, CancellationToken cancellationToken = default ) { - return await VippsServices.EpaymentServiceClient.ExecuteRequest< - IEnumerable - >(GetRequestPath(reference, "events"), HttpMethod.Get, cancellationToken); + return await _epaymentServiceClient.ExecuteRequest>( + GetRequestPath(reference, "events"), + HttpMethod.Get, + cancellationToken + ); } - public static async Task CancelPayment( + public async Task CancelPayment( string reference, CancellationToken cancellationToken = default ) { - return await VippsServices.EpaymentServiceClient.ExecuteRequest( + return await _epaymentServiceClient.ExecuteRequest( GetRequestPath(reference, "cancel"), HttpMethod.Post, cancellationToken ); } - public static async Task CapturePayment( + public async Task CapturePayment( string reference, CaptureModificationRequest capturePaymentRequest, CancellationToken cancellationToken = default ) { - return await VippsServices.EpaymentServiceClient.ExecuteRequest< + return await _epaymentServiceClient.ExecuteRequest< CaptureModificationRequest, ModificationResponse >( @@ -71,13 +121,13 @@ public static async Task CapturePayment( ); } - public static async Task RefundPayment( + public async Task RefundPayment( string reference, RefundModificationRequest refundModificationRequest, CancellationToken cancellationToken = default ) { - return await VippsServices.EpaymentServiceClient.ExecuteRequest< + return await _epaymentServiceClient.ExecuteRequest< RefundModificationRequest, ModificationResponse >( @@ -88,13 +138,13 @@ public static async Task RefundPayment( ); } - public static async Task ForceApprovePayment( + public async Task ForceApprovePayment( string reference, ForceApprove forceApproveRequest, CancellationToken cancellationToken = default ) { - await VippsServices.EpaymentServiceClient.ExecuteRequest( + await _epaymentServiceClient.ExecuteRequest( $"/epayment/v1/test/payments/{reference}/approve", HttpMethod.Post, forceApproveRequest, diff --git a/src/Vipps.net/Vipps.net.csproj b/src/Vipps.net/Vipps.net.csproj index 2a39c90..3d41383 100644 --- a/src/Vipps.net/Vipps.net.csproj +++ b/src/Vipps.net/Vipps.net.csproj @@ -6,7 +6,7 @@ Vipps.net Vipps.net SDK Vipps.net - 0.8.4 + 0.9.0 Vipps Mobilepay AS Vipps Mobilepay AS Vipps SDK .Net diff --git a/src/Vipps.net/VippsApi.cs b/src/Vipps.net/VippsApi.cs new file mode 100644 index 0000000..f1b589a --- /dev/null +++ b/src/Vipps.net/VippsApi.cs @@ -0,0 +1,69 @@ +using System.Net.Http; +using System.Threading; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; +using Vipps.net.Infrastructure; +using Vipps.net.Services; + +namespace Vipps.net +{ + public interface IVippsApi + { + IVippsAccessTokenService AccessTokenService(); + IVippsEpaymentService EpaymentService(); + IVippsCheckoutService CheckoutService(); + } + + public class VippsApi : IVippsApi + { + private readonly VippsConfigurationOptions _vippsConfigurationOptions; + private VippsHttpClient _vippsHttpClient; + private ILoggerFactory _loggerFactory; + private readonly VippsAccessTokenService _accessTokenService; + private readonly IVippsEpaymentService _epaymentService; + private readonly IVippsCheckoutService _checkoutService; + + public VippsApi( + VippsConfigurationOptions configurationOptions, + ILoggerFactory loggerFactory = null + ) + { + _loggerFactory = loggerFactory ?? NullLoggerFactory.Instance; + this._vippsConfigurationOptions = configurationOptions; + _vippsHttpClient = new VippsHttpClient(new HttpClient(), configurationOptions); + + _accessTokenService = new VippsAccessTokenService( + configurationOptions, + new AccessTokenServiceClient(_vippsHttpClient, configurationOptions), + new AccessTokenCacheService() + ); + + _epaymentService = new VippsEpaymentService( + new EpaymentServiceClient( + _vippsHttpClient, + _vippsConfigurationOptions, + _accessTokenService + ) + ); + + _checkoutService = new VippsCheckoutService( + new CheckoutServiceClient(_vippsHttpClient, _vippsConfigurationOptions) + ); + } + + public IVippsAccessTokenService AccessTokenService() + { + return this._accessTokenService; + } + + public IVippsEpaymentService EpaymentService() + { + return this._epaymentService; + } + + public IVippsCheckoutService CheckoutService() + { + return this._checkoutService; + } + } +}