diff --git a/BTCPayServer.Abstractions/Contracts/IBTCPayServerClientFactory.cs b/BTCPayServer.Abstractions/Contracts/IBTCPayServerClientFactory.cs deleted file mode 100644 index e23ab709b..000000000 --- a/BTCPayServer.Abstractions/Contracts/IBTCPayServerClientFactory.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System.Threading.Tasks; -using BTCPayServer.Client; -using Microsoft.AspNetCore.Http; - -namespace BTCPayServer.Abstractions.Contracts -{ - public interface IBTCPayServerClientFactory - { - Task Create(string userId, params string[] storeIds); - Task Create(string userId, string[] storeIds, HttpContext httpRequest); - } -} diff --git a/BTCPayServer.Tests/BTCPayServerTester.cs b/BTCPayServer.Tests/BTCPayServerTester.cs index a734b15ac..ed069302d 100644 --- a/BTCPayServer.Tests/BTCPayServerTester.cs +++ b/BTCPayServer.Tests/BTCPayServerTester.cs @@ -169,6 +169,10 @@ namespace BTCPayServer.Tests #endif var conf = confBuilder.Build(); _Host = new WebHostBuilder() + .UseDefaultServiceProvider(options => + { + options.ValidateScopes = true; + }) .UseConfiguration(conf) .UseContentRoot(FindBTCPayServerDirectory()) .UseWebRoot(Path.Combine(FindBTCPayServerDirectory(), "wwwroot")) @@ -284,10 +288,7 @@ namespace BTCPayServer.Tests public string IntegratedLightning { get; internal set; } public bool InContainer { get; internal set; } - public T GetService() - { - return _Host.Services.GetRequiredService(); - } + public T GetService() => _Host.Services.GetRequiredService(); public IServiceProvider ServiceProvider => _Host.Services; diff --git a/BTCPayServer.Tests/GreenfieldAPITests.cs b/BTCPayServer.Tests/GreenfieldAPITests.cs index 3d4ced103..d4edadaa9 100644 --- a/BTCPayServer.Tests/GreenfieldAPITests.cs +++ b/BTCPayServer.Tests/GreenfieldAPITests.cs @@ -52,41 +52,6 @@ namespace BTCPayServer.Tests { } - [Fact(Timeout = TestTimeout)] - [Trait("Integration", "Integration")] - [Trait("Lightning", "Lightning")] - public async Task LocalClientTests() - { - using var tester = CreateServerTester(); - tester.ActivateLightning(); - await tester.StartAsync(); - await tester.EnsureChannelsSetup(); - var user = tester.NewAccount(); - await user.GrantAccessAsync(); - await user.MakeAdmin(); - user.RegisterLightningNode("BTC", LightningConnectionType.CLightning); - var factory = tester.PayTester.GetService(); - Assert.NotNull(factory); - var client = await factory.Create(user.UserId, user.StoreId); - await client.GetCurrentUser(); - await client.GetStores(); - var store = await client.GetStore(user.StoreId); - Assert.NotNull(store); - var addr = await client.GetLightningDepositAddress(user.StoreId, "BTC"); - Assert.NotNull(BitcoinAddress.Create(addr, Network.RegTest)); - - await user.CreateStoreAsync(); - var store1 = user.StoreId; - await user.CreateStoreAsync(); - var store2 = user.StoreId; - var store1Client = await factory.Create(null, store1); - var store2Client = await factory.Create(null, store2); - var store1Res = await store1Client.GetStore(store1); - var store2Res = await store2Client.GetStore(store2); - Assert.Equal(store1, store1Res.Id); - Assert.Equal(store2, store2Res.Id); - } - [Fact(Timeout = TestTimeout)] [Trait("Integration", "Integration")] public async Task MissingPermissionTest() diff --git a/BTCPayServer.Tests/PlaywrightTests.cs b/BTCPayServer.Tests/PlaywrightTests.cs index 899595093..e7fed9036 100644 --- a/BTCPayServer.Tests/PlaywrightTests.cs +++ b/BTCPayServer.Tests/PlaywrightTests.cs @@ -28,6 +28,7 @@ using ExchangeSharp; using LNURL; using Microsoft.AspNetCore.Identity; using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Playwright; using static Microsoft.Playwright.Assertions; using NBitcoin; @@ -200,7 +201,8 @@ namespace BTCPayServer.Tests await s.Page.FillAsync("#Email", changedEmail); await s.ClickPagePrimary(); await s.FindAlertMessage(); - var manager = tester.PayTester.GetService>(); + using var scope = tester.PayTester.ServiceProvider.CreateScope(); + var manager = scope.ServiceProvider.GetRequiredService>(); Assert.NotNull(await manager.FindByNameAsync(changedEmail)); Assert.NotNull(await manager.FindByEmailAsync(changedEmail)); } @@ -1242,13 +1244,9 @@ namespace BTCPayServer.Tests await s.LogIn(admin.RegisterDetails.Email, admin.RegisterDetails.Password); await s.GoToHome(); - await TestUtils.EventuallyAsync(async () => - { - Assert.Equal("1", await s.Page.Locator("#NotificationsBadge").TextContentAsync()); - }); - + await Expect(s.Page.Locator("#NotificationsBadge")).ToContainTextAsync("1"); await s.Page.ClickAsync("#NotificationsHandle"); - await s.Page.Locator($"#NotificationsList .notification:has-text('New user {unapproved.RegisterDetails.Email} requires approval')").WaitForAsync(); + await Expect(s.Page.Locator("#NotificationsList .notification")).ToContainTextAsync($"New user {unapproved.RegisterDetails.Email} requires approval"); await s.Page.ClickAsync("#NotificationsMarkAllAsSeen"); await s.GoToServer(ServerNavPages.Policies); @@ -1754,8 +1752,8 @@ namespace BTCPayServer.Tests opening = s.Page.Context.WaitForPageAsync(); await s.Page.ClickAsync("text=View"); newPage = await opening; - await Expect(newPage.Locator("body")).ToContainTextAsync("Description Edit"); - await Expect(newPage.Locator("body")).ToContainTextAsync("PP1 Edited"); + await Expect(newPage.GetByTestId("description")).ToContainTextAsync("Description Edit"); + await Expect(newPage.GetByTestId("title")).ToContainTextAsync("PP1 Edited"); } [Fact] @@ -2288,22 +2286,23 @@ namespace BTCPayServer.Tests await s.FindAlertMessage(); Assert.DoesNotContain("Unarchive", await s.Page.Locator("#btn-archive-toggle").InnerTextAsync()); await s.GoToInvoices(storeId); + await s.Page.WaitForSelectorAsync($"tr[id=invoice_{invoiceId}]"); Assert.Contains(invoiceId, await s.Page.ContentAsync()); // archive via list - await s.Page.Locator($".mass-action-select[value=\"{invoiceId}\"]").ClickAsync(); - await s.Page.Locator("#ArchiveSelected").ClickAsync(); - Assert.Contains("1 invoice archived", await (await s.FindAlertMessage()).InnerTextAsync()); + await s.Page.ClickAsync($".mass-action-select[value=\"{invoiceId}\"]"); + await s.Page.ClickAsync("#ArchiveSelected"); + await s.FindAlertMessage(partialText: "1 invoice archived"); Assert.DoesNotContain(invoiceId, await s.Page.ContentAsync()); // unarchive via list await s.Page.Locator("#StatusOptionsToggle").ClickAsync(); await s.Page.Locator("#StatusOptionsIncludeArchived").ClickAsync(); Assert.Contains(invoiceId, await s.Page.ContentAsync()); - await s.Page.Locator($".mass-action-select[value=\"{invoiceId}\"]").ClickAsync(); - await s.Page.Locator("#UnarchiveSelected").ClickAsync(); - Assert.Contains("1 invoice unarchived", await (await s.FindAlertMessage()).InnerTextAsync()); - Assert.Contains(invoiceId, await s.Page.ContentAsync()); + await s.Page.ClickAsync($".mass-action-select[value=\"{invoiceId}\"]"); + await s.Page.ClickAsync("#UnarchiveSelected"); + await s.FindAlertMessage(partialText: "1 invoice unarchived"); + await s.Page.WaitForSelectorAsync($"tr[id=invoice_{invoiceId}]"); // When logout out we should not be able to access store and invoice details await s.GoToUrl("/account"); diff --git a/BTCPayServer.Tests/TestAccount.cs b/BTCPayServer.Tests/TestAccount.cs index d1f559393..249f71379 100644 --- a/BTCPayServer.Tests/TestAccount.cs +++ b/BTCPayServer.Tests/TestAccount.cs @@ -26,6 +26,7 @@ using BTCPayServer.Services.Wallets; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.DependencyInjection; using NBitcoin; using NBitcoin.DataEncoders; using NBitcoin.Payment; @@ -58,13 +59,14 @@ namespace BTCPayServer.Tests public async Task MakeAdmin(bool isAdmin = true) { - var userManager = parent.PayTester.GetService>(); + using var scope = parent.PayTester.ServiceProvider.CreateScope(); + var userManager = scope.ServiceProvider.GetRequiredService>(); var u = await userManager.FindByIdAsync(UserId); if (isAdmin) await userManager.AddToRoleAsync(u, Roles.ServerAdmin); else await userManager.RemoveFromRoleAsync(u, Roles.ServerAdmin); - IsAdmin = true; + IsAdmin = isAdmin; } public Task CreateClient() diff --git a/BTCPayServer/Controllers/GreenField/LocalBTCPayServerClient.cs b/BTCPayServer/Controllers/GreenField/LocalBTCPayServerClient.cs deleted file mode 100644 index 3c824f3d8..000000000 --- a/BTCPayServer/Controllers/GreenField/LocalBTCPayServerClient.cs +++ /dev/null @@ -1,1367 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Net.Http; -using System.Reflection; -using System.Security.Claims; -using System.Threading; -using System.Threading.Tasks; -using BTCPayServer.Abstractions.Contracts; -using BTCPayServer.Client; -using BTCPayServer.Client.Models; -using BTCPayServer.Controllers.GreenField; -using BTCPayServer.Data; -using BTCPayServer.Plugins.Webhooks.Controllers; -using BTCPayServer.Security; -using BTCPayServer.Security.Greenfield; -using BTCPayServer.Plugins.Emails.Services; -using BTCPayServer.Services.Stores; -using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Identity; -using Microsoft.AspNetCore.Mvc; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Options; -using NBitcoin; -using Newtonsoft.Json.Linq; -using InvoiceData = BTCPayServer.Client.Models.InvoiceData; -using Language = BTCPayServer.Client.Models.Language; -using LightningAddressData = BTCPayServer.Client.Models.LightningAddressData; -using NotificationData = BTCPayServer.Client.Models.NotificationData; -using PayoutData = BTCPayServer.Client.Models.PayoutData; -using PayoutProcessorData = BTCPayServer.Client.Models.PayoutProcessorData; -using PullPaymentData = BTCPayServer.Client.Models.PullPaymentData; -using StoreData = BTCPayServer.Client.Models.StoreData; -using StoreWebhookData = BTCPayServer.Client.Models.StoreWebhookData; -using WebhookDeliveryData = BTCPayServer.Client.Models.WebhookDeliveryData; - -namespace BTCPayServer.Controllers.Greenfield -{ - public class BTCPayServerClientFactory : IBTCPayServerClientFactory - { - private readonly StoreRepository _storeRepository; - private readonly IOptionsMonitor _identityOptions; - private readonly UserManager _userManager; - - private readonly IServiceProvider _serviceProvider; - - public BTCPayServerClientFactory( - StoreRepository storeRepository, - IOptionsMonitor identityOptions, - UserManager userManager, - IServiceProvider serviceProvider) - { - _storeRepository = storeRepository; - _identityOptions = identityOptions; - _userManager = userManager; - _serviceProvider = serviceProvider; - } - - public Task Create(string userId, params string[] storeIds) - { - return Create(userId, storeIds, new DefaultHttpContext() - { - Request = - { - Scheme = "https", - Host = new HostString("dummy.com"), - Path = new PathString(), - PathBase = new PathString(), - } - }); - } - - public async Task Create(string userId, string[] storeIds, HttpContext context) - { - if (!string.IsNullOrEmpty(userId)) - { - var user = await _userManager.FindByIdAsync(userId); - List claims = new List - { - new Claim(_identityOptions.CurrentValue.ClaimsIdentity.UserIdClaimType, userId), - new Claim(GreenfieldConstants.ClaimTypes.Permission, - Permission.Create(Policies.Unrestricted).ToString()) - }; - claims.AddRange((await _userManager.GetRolesAsync(user)).Select(s => - new Claim(_identityOptions.CurrentValue.ClaimsIdentity.RoleClaimType, s))); - context.User = - new ClaimsPrincipal(new ClaimsIdentity(claims, - $"Local{GreenfieldConstants.AuthenticationType}WithUser")); - } - else - { - context.User = - new ClaimsPrincipal(new ClaimsIdentity( - new List() - { - new(_identityOptions.CurrentValue.ClaimsIdentity.RoleClaimType, Roles.ServerAdmin) - }, - $"Local{GreenfieldConstants.AuthenticationType}")); - } - - if (storeIds?.Any() is true) - { - context.SetStoreData(await _storeRepository.FindStore(storeIds.First())); - context.SetStoresData(await _storeRepository.GetStoresByUserId(userId, storeIds)); - } - else - { - context.SetStoresData(await _storeRepository.GetStoresByUserId(userId)); - } - - return ActivatorUtilities.CreateInstance(_serviceProvider, - new LocalHttpContextAccessor() { HttpContext = context }); - - } - } - - - public class LocalHttpContextAccessor : IHttpContextAccessor - { - public HttpContext HttpContext { get; set; } - } - - public class LocalBTCPayServerClient : BTCPayServerClient - { - private readonly IHttpContextAccessor _httpContextAccessor; - private readonly IServiceProvider _serviceProvider; - - - public LocalBTCPayServerClient( - IHttpContextAccessor httpContextAccessor, - IServiceProvider serviceProvider) : base(new Uri("https://dummy.local"), "", "") - { - _httpContextAccessor = httpContextAccessor; - _serviceProvider = serviceProvider; - } - - private T GetController() where T : ControllerBase - { - var authoverride = new AuthorizationService(new GreenfieldAuthorizationHandler(_httpContextAccessor, - _serviceProvider.GetService>(), - _serviceProvider.GetService(), - _serviceProvider.GetService())); - - var controller = _serviceProvider.GetService(); - controller.ControllerContext.HttpContext = _httpContextAccessor.HttpContext; - var authInterface = typeof(IAuthorizationService); - var type = controller.GetType(); - do - { - foreach (FieldInfo fieldInfo in type.GetFields(BindingFlags.FlattenHierarchy | - BindingFlags.Instance | - BindingFlags.NonPublic | - BindingFlags.Public | - BindingFlags.Static) - .Where(info => - authInterface == info.FieldType || authInterface.IsAssignableFrom(info.FieldType))) - { - fieldInfo.SetValue(controller, authoverride); - } - - type = type.BaseType; - } while (type is not null); - - return controller; - } - - class AuthorizationService : IAuthorizationService - { - private readonly GreenfieldAuthorizationHandler _greenfieldAuthorizationHandler; - - public AuthorizationService(GreenfieldAuthorizationHandler greenfieldAuthorizationHandler) - { - _greenfieldAuthorizationHandler = greenfieldAuthorizationHandler; - } - - public async Task AuthorizeAsync(ClaimsPrincipal user, object resource, - IEnumerable requirements) - { - var withuser = user.Identity?.AuthenticationType == - $"Local{GreenfieldConstants.AuthenticationType}WithUser"; - if (withuser) - { - var newUser = new ClaimsPrincipal(new ClaimsIdentity(user.Claims, - $"{GreenfieldConstants.AuthenticationType}")); - var newContext = new AuthorizationHandlerContext(requirements, newUser, resource); - await _greenfieldAuthorizationHandler.HandleAsync(newContext); - if (newContext.HasSucceeded) - { - return AuthorizationResult.Success(); - } - - return AuthorizationResult.Failed(); - } - - var succeed = user.Identity.AuthenticationType == $"Local{GreenfieldConstants.AuthenticationType}"; - - if (succeed) - { - return AuthorizationResult.Success(); - } - - return AuthorizationResult.Failed(); - } - - public Task AuthorizeAsync(ClaimsPrincipal user, object resource, string policyName) - { - return AuthorizeAsync(user, resource, - new List(new[] { new PolicyRequirement(policyName) })); - } - } - - protected override HttpRequestMessage CreateHttpRequest(string path, - Dictionary queryPayload = null, HttpMethod method = null) - { - throw new NotSupportedException("This method is not supported by the LocalBTCPayServerClient."); - } - - public override async Task GetOnChainWalletObjects(string storeId, string cryptoCode, - GetWalletObjectsRequest query = null, - CancellationToken token = default) - { - return GetFromActionResult( - await GetController().GetOnChainWalletObjects(storeId, cryptoCode, query?.Type, query?.Ids, query?.IncludeNeighbourData)); - } - - public override async Task GetOnChainWalletObject(string storeId, string cryptoCode, OnChainWalletObjectId objectId, bool? includeNeighbourData = null, CancellationToken token = default) - { - return GetFromActionResult( - await GetController().GetOnChainWalletObject(storeId, cryptoCode, objectId.Type, objectId.Id, includeNeighbourData)); - } - public override async Task AddOrUpdateOnChainWalletObject(string storeId, string cryptoCode, AddOnChainWalletObjectRequest request, CancellationToken token = default) - { - return GetFromActionResult( - await GetController().AddOrUpdateOnChainWalletObject(storeId, cryptoCode, request)); - } - - public override async Task RemoveOnChainWalletLinks(string storeId, string cryptoCode, OnChainWalletObjectId objectId, OnChainWalletObjectId link, CancellationToken token = default) - { - HandleActionResult(await GetController().RemoveOnChainWalletLink(storeId, cryptoCode, objectId.Type, objectId.Id, link.Type, link.Id)); - } - - public override async Task RemoveOnChainWalletObject(string storeId, string cryptoCode, OnChainWalletObjectId objectId, CancellationToken token = default) - { - HandleActionResult(await GetController().RemoveOnChainWalletObject(storeId, cryptoCode, objectId.Type, objectId.Id)); - } - - public override async Task AddOrUpdateOnChainWalletLink(string storeId, string cryptoCode, OnChainWalletObjectId objectId, AddOnChainWalletObjectLinkRequest request = null, CancellationToken token = default) - { - HandleActionResult(await GetController().AddOrUpdateOnChainWalletLinks(storeId, cryptoCode, objectId.Type, objectId.Id, request)); - } - - public override async Task CreateWebhook(string storeId, CreateStoreWebhookRequest create, - CancellationToken token = default) - { - return GetFromActionResult( - await GetController().CreateWebhook(storeId, create)); - } - - public override async Task GetWebhook(string storeId, string webhookId, - CancellationToken token = default) - { - return GetFromActionResult( - await GetController().ListWebhooks(storeId, webhookId)); - } - - public override async Task UpdateWebhook(string storeId, string webhookId, - UpdateStoreWebhookRequest update, - CancellationToken token = default) - { - return GetFromActionResult( - await GetController().UpdateWebhook(storeId, webhookId, update)); - } - - public override async Task DeleteWebhook(string storeId, string webhookId, - CancellationToken token = default) - { - HandleActionResult(await GetController().DeleteWebhook(storeId, webhookId)); - return true; - } - - public override async Task GetWebhooks(string storeId, CancellationToken token = default) - { - return GetFromActionResult( - await GetController().ListWebhooks(storeId, null)); - } - - public override async Task GetWebhookDeliveries(string storeId, string webhookId, - CancellationToken token = default) - { - return GetFromActionResult( - await GetController().ListDeliveries(storeId, webhookId, null)); - } - - public override async Task GetWebhookDelivery(string storeId, string webhookId, - string deliveryId, CancellationToken token = default) - { - return GetFromActionResult( - await GetController().ListDeliveries(storeId, webhookId, deliveryId)); - } - - public override async Task RedeliverWebhook(string storeId, string webhookId, string deliveryId, - CancellationToken token = default) - { - return GetFromActionResult( - await GetController().RedeliverWebhook(storeId, webhookId, deliveryId)); - } - - public override async Task GetWebhookDeliveryRequest(string storeId, string webhookId, - string deliveryId, CancellationToken token = default) - { - return GetFromActionResult( - await GetController().GetDeliveryRequest(storeId, webhookId, deliveryId)); - } - - public override async Task CreatePullPayment(string storeId, CreatePullPaymentRequest request, - CancellationToken cancellationToken = default) - { - return GetFromActionResult( - await GetController().CreatePullPayment(storeId, request)); - } - - public override async Task GetPullPayment(string pullPaymentId, - CancellationToken cancellationToken = default) - { - return GetFromActionResult( - await GetController().GetPullPayment(pullPaymentId)); - } - - public override async Task GetPullPayments(string storeId, bool includeArchived = false, - CancellationToken cancellationToken = default) - { - return GetFromActionResult( - await GetController().GetPullPayments(storeId, includeArchived)); - } - - public override async Task ArchivePullPayment(string storeId, string pullPaymentId, - CancellationToken cancellationToken = default) - { - HandleActionResult(await GetController().ArchivePullPayment(storeId, pullPaymentId)); - } - - public override async Task GetPayouts(string pullPaymentId, bool includeCancelled = false, - CancellationToken cancellationToken = default) - { - return GetFromActionResult( - await GetController().GetPayouts(pullPaymentId, includeCancelled)); - } - - public override async Task CreatePayout(string pullPaymentId, CreatePayoutRequest payoutRequest, - CancellationToken cancellationToken = default) - { - return GetFromActionResult( - await GetController().CreatePayout(pullPaymentId, payoutRequest, cancellationToken)); - } - - public override async Task CancelPayout(string storeId, string payoutId, - CancellationToken cancellationToken = default) - { - HandleActionResult(await GetController().CancelPayout(storeId, payoutId)); - } - - public override async Task ApprovePayout(string storeId, string payoutId, - ApprovePayoutRequest request, CancellationToken cancellationToken = default) - { - return GetFromActionResult( - await GetController().ApprovePayout(storeId, payoutId, request, cancellationToken)); - } - - public override async Task GetLightningNodeInfo(string storeId, string cryptoCode, - CancellationToken token = default) - { - return GetFromActionResult( - await GetController().GetInfo(cryptoCode, token)); - } - - public override async Task GetLightningNodeBalance(string storeId, string cryptoCode, - CancellationToken token = default) - { - return GetFromActionResult( - await GetController().GetBalance(cryptoCode, token)); - } - - public override async Task GetLightningNodeHistogram(string storeId, string cryptoCode, HistogramType? type = null, - CancellationToken token = default) - { - return GetFromActionResult( - await GetController().GetHistogram(cryptoCode, type, token)); - } - - public override async Task ConnectToLightningNode(string storeId, string cryptoCode, - ConnectToNodeRequest request, CancellationToken token = default) - { - HandleActionResult(await GetController().ConnectToNode(cryptoCode, request, token)); - } - - public override async Task> GetLightningNodeChannels(string storeId, - string cryptoCode, CancellationToken token = default) - { - return GetFromActionResult>( - await GetController().GetChannels(cryptoCode, token)); - } - - public override async Task OpenLightningChannel(string storeId, string cryptoCode, - OpenLightningChannelRequest request, - CancellationToken token = default) - { - HandleActionResult(await GetController().OpenChannel(cryptoCode, request, token)); - } - - public override async Task GetLightningDepositAddress(string storeId, string cryptoCode, - CancellationToken token = default) - { - return GetFromActionResult( - await GetController().GetDepositAddress(cryptoCode, token)); - } - - public override async Task PayLightningInvoice(string storeId, string cryptoCode, - PayLightningInvoiceRequest request, CancellationToken token = default) - { - return GetFromActionResult( - await GetController().PayInvoice(cryptoCode, request, token)); - } - - public override async Task GetLightningInvoice(string storeId, string cryptoCode, - string invoiceId, CancellationToken token = default) - { - return GetFromActionResult( - await GetController().GetInvoice(cryptoCode, invoiceId, token)); - } - - public override async Task GetLightningInvoices(string storeId, string cryptoCode, - bool? pendingOnly = null, long? offsetIndex = null, CancellationToken token = default) - { - return GetFromActionResult( - await GetController().GetInvoices(cryptoCode, pendingOnly, offsetIndex, token)); - } - - public override async Task GetLightningPayments(string storeId, string cryptoCode, - bool? includePending = null, long? offsetIndex = null, CancellationToken token = default) - { - return GetFromActionResult( - await GetController().GetPayments(cryptoCode, includePending, offsetIndex, token)); - } - - public override async Task CreateLightningInvoice(string storeId, string cryptoCode, - CreateLightningInvoiceRequest request, CancellationToken token = default) - { - return GetFromActionResult( - await GetController().CreateInvoice(cryptoCode, request, token)); - } - - public override async Task GetLightningNodeInfo(string cryptoCode, - CancellationToken token = default) - { - return GetFromActionResult( - await GetController().GetInfo(cryptoCode)); - } - - public override async Task GetLightningNodeBalance(string cryptoCode, - CancellationToken token = default) - { - return GetFromActionResult( - await GetController().GetBalance(cryptoCode)); - } - - public override async Task GetLightningNodeHistogram(string cryptoCode, HistogramType? type = null, - CancellationToken token = default) - { - return GetFromActionResult( - await GetController().GetHistogram(cryptoCode, type, token)); - } - - public override async Task ConnectToLightningNode(string cryptoCode, ConnectToNodeRequest request, - CancellationToken token = default) - { - HandleActionResult(await GetController().ConnectToNode(cryptoCode, request, token)); - } - - public override async Task> GetLightningNodeChannels(string cryptoCode, - CancellationToken token = default) - { - return GetFromActionResult>( - await GetController().GetChannels(cryptoCode, token)); - } - - public override async Task OpenLightningChannel(string cryptoCode, OpenLightningChannelRequest request, - CancellationToken token = default) - { - HandleActionResult(await GetController().OpenChannel(cryptoCode, request, token)); - } - - public override async Task GetLightningDepositAddress(string cryptoCode, - CancellationToken token = default) - { - return GetFromActionResult( - await GetController().GetDepositAddress(cryptoCode, token)); - } - - public override async Task PayLightningInvoice(string cryptoCode, - PayLightningInvoiceRequest request, CancellationToken token = default) - { - return GetFromActionResult( - await GetController().PayInvoice(cryptoCode, request, token)); - } - - public override async Task GetLightningInvoice(string cryptoCode, string invoiceId, - CancellationToken token = default) - { - return GetFromActionResult( - await GetController().GetInvoice(cryptoCode, invoiceId, token)); - } - - public override async Task GetLightningInvoices(string cryptoCode, - bool? pendingOnly = null, long? offsetIndex = null, CancellationToken token = default) - { - return GetFromActionResult( - await GetController().GetInvoices(cryptoCode, pendingOnly, offsetIndex, token)); - } - - public override async Task GetLightningPayments(string cryptoCode, - bool? includePending = null, long? offsetIndex = null, CancellationToken token = default) - { - return GetFromActionResult( - await GetController().GetPayments(cryptoCode, includePending, offsetIndex, token)); - } - - public override async Task CreateLightningInvoice(string cryptoCode, - CreateLightningInvoiceRequest request, - CancellationToken token = default) - { - return GetFromActionResult( - await GetController().CreateInvoice(cryptoCode, request, token)); - } - - private T GetFromActionResult(IActionResult result) - { - HandleActionResult(result); - return result switch - { - JsonResult jsonResult => (T)jsonResult.Value, - OkObjectResult { Value: T res } => res, - OkObjectResult { Value: JValue res } => res.Value(), - _ => default - }; - } - - private void HandleActionResult(IActionResult result) - { - switch (result) - { - case UnprocessableEntityObjectResult { Value: List validationErrors }: - throw new GreenfieldValidationException(validationErrors.ToArray()); - case BadRequestObjectResult { Value: GreenfieldAPIError error }: - throw new GreenfieldAPIException(400, error); - case ObjectResult { Value: GreenfieldAPIError error }: - throw new GreenfieldAPIException(400, error); - case NotFoundResult _: - throw new GreenfieldAPIException(404, new GreenfieldAPIError("not-found", "")); - default: - return; - } - } - - private T GetFromActionResult(ActionResult result) - { - return GetFromActionResult((IActionResult)result); - } - - private T GetFromActionResult(ActionResult result) - { - return result.Value ?? GetFromActionResult(result.Result); - } - - public override async Task PreviewProposedStoreOnChainPaymentMethodAddresses( - string storeId, string paymentMethodId, - string derivationScheme, int offset = 0, int count = 10, - CancellationToken token = default) - { - return GetFromActionResult( - await GetController().GetProposedOnChainPaymentMethodPreview(storeId, Payments.PaymentMethodId.Parse(paymentMethodId), - new UpdatePaymentMethodRequest() { Config = JValue.CreateString(derivationScheme) }, offset, count)); - } - - public override Task PreviewStoreOnChainPaymentMethodAddresses( - string storeId, string paymentMethodId, int offset = 0, int amount = 10, CancellationToken token = default) - { - return Task.FromResult(GetFromActionResult( - GetController().GetOnChainPaymentMethodPreview(storeId, Payments.PaymentMethodId.Parse(paymentMethodId), offset, - amount))); - } - - public override Task GetHealth(CancellationToken token = default) - { - return Task.FromResult(GetFromActionResult(GetController().GetHealth())); - } - - public override async Task> GetPaymentRequests(string storeId, - bool includeArchived = false, CancellationToken token = default) - { - return GetFromActionResult(await GetController().GetPaymentRequests(storeId, includeArchived)); - } - - public override async Task GetPaymentRequest(string storeId, string paymentRequestId, - CancellationToken token = default) - { - return GetFromActionResult( - await GetController().GetPaymentRequest(storeId, paymentRequestId)); - } - - public override async Task ArchivePaymentRequest(string storeId, string paymentRequestId, - CancellationToken token = default) - { - HandleActionResult(await GetController().ArchivePaymentRequest(storeId, paymentRequestId)); - } - - public override async Task PayPaymentRequest(string storeId, string paymentRequestId, PayPaymentRequestRequest request, CancellationToken token = default) - { - return GetFromActionResult( - await GetController().PayPaymentRequest(storeId, paymentRequestId, request, token)); - } - - public override async Task CreatePaymentRequest(string storeId, - PaymentRequestBaseData request, CancellationToken token = default) - { - return GetFromActionResult( - await GetController().CreateOrUpdatePaymentRequest(storeId, request)); - } - - public override async Task UpdatePaymentRequest(string storeId, string paymentRequestId, - PaymentRequestBaseData request, - CancellationToken token = default) - { - return GetFromActionResult( - await GetController().CreateOrUpdatePaymentRequest(storeId, request, paymentRequestId)); - } - - public override async Task GetCurrentAPIKeyInfo(CancellationToken token = default) - { - return GetFromActionResult(await GetController().GetKey()); - } - - public override async Task CreateAPIKey(CreateApiKeyRequest request, - CancellationToken token = default) - { - return GetFromActionResult(await GetController().CreateAPIKey(request)); - } - - public override async Task RevokeCurrentAPIKeyInfo(CancellationToken token = default) - { - HandleActionResult(await GetController().RevokeCurrentKey()); - } - - public override async Task RevokeAPIKey(string apikey, CancellationToken token = default) - { - HandleActionResult(await GetController().RevokeAPIKey(apikey)); - } - - public override async Task GetNotificationSettings(CancellationToken token = default) - { - return GetFromActionResult( - await GetController().GetNotificationSettings()); - } - - public override async Task UpdateNotificationSettings(UpdateNotificationSettingsRequest request, CancellationToken token = default) - { - return GetFromActionResult( - await GetController().UpdateNotificationSettings(request)); - } - - public override async Task> GetNotifications(bool? seen = null, - int? skip = null, int? take = null, string[] storeId = null, CancellationToken token = default) - { - return GetFromActionResult>( - await GetController().GetNotifications(seen, skip, take, storeId)); - } - - public override async Task GetNotification(string notificationId, - CancellationToken token = default) - { - return GetFromActionResult( - await GetController().GetNotification(notificationId)); - } - - public override async Task UpdateNotification(string notificationId, bool? seen, - CancellationToken token = default) - { - return GetFromActionResult( - await GetController().UpdateNotification(notificationId, - new UpdateNotification() { Seen = seen })); - } - - public override async Task RemoveNotification(string notificationId, CancellationToken token = default) - { - HandleActionResult(await GetController().DeleteNotification(notificationId)); - } - - public override async Task GetCurrentUser(CancellationToken token = default) - { - return GetFromActionResult(await GetController().GetCurrentUser()); - } - - public override async Task CreateUser(CreateApplicationUserRequest request, - CancellationToken token = default) - { - return GetFromActionResult(await GetController().CreateUser(request, token)); - } - - public override async Task ShowOnChainWalletOverview(string storeId, - string cryptoCode, CancellationToken token = default) - { - return GetFromActionResult( - await GetController().ShowOnChainWalletOverview(storeId, cryptoCode)); - } - - public override async Task GetOnChainWalletHistogram(string storeId, string cryptoCode, HistogramType? type = null, CancellationToken token = default) - { - return GetFromActionResult( - await GetController().GetOnChainWalletHistogram(storeId, cryptoCode, type?.ToString())); - } - - public override async Task GetOnChainWalletReceiveAddress(string storeId, - string cryptoCode, bool forceGenerate = false, - CancellationToken token = default) - { - return GetFromActionResult( - await GetController().GetOnChainWalletReceiveAddress(storeId, cryptoCode, - forceGenerate)); - } - - public override async Task UnReserveOnChainWalletReceiveAddress(string storeId, string cryptoCode, - CancellationToken token = default) - { - HandleActionResult( - await GetController().UnReserveOnChainWalletReceiveAddress(storeId, cryptoCode)); - } - - public override async Task> ShowOnChainWalletTransactions( - string storeId, string cryptoCode, TransactionStatus[] statusFilter = null, string labelFilter = null, int skip = 0, - CancellationToken token = default) - { - return GetFromActionResult>( - await GetController().ShowOnChainWalletTransactions(storeId, cryptoCode, statusFilter)); - } - - public override async Task GetOnChainWalletTransaction(string storeId, - string cryptoCode, string transactionId, CancellationToken token = default) - { - return GetFromActionResult( - await GetController().GetOnChainWalletTransaction(storeId, cryptoCode, transactionId)); - } - - public override async Task> GetOnChainWalletUTXOs(string storeId, - string cryptoCode, CancellationToken token = default) - { - return GetFromActionResult>( - await GetController().GetOnChainWalletUTXOs(storeId, cryptoCode)); - } - - public override async Task CreateOnChainTransaction(string storeId, - string cryptoCode, CreateOnChainTransactionRequest request, CancellationToken token = default) - { - if (!request.ProceedWithBroadcast) - { - throw new ArgumentOutOfRangeException(nameof(request.ProceedWithBroadcast), - "Please use CreateOnChainTransactionButDoNotBroadcast when wanting to only create the transaction"); - } - - return GetFromActionResult( - await GetController().CreateOnChainTransaction(storeId, cryptoCode, request)); - } - - public override async Task CreateOnChainTransactionButDoNotBroadcast(string storeId, - string cryptoCode, - CreateOnChainTransactionRequest request, Network network, CancellationToken token = default) - { - if (request.ProceedWithBroadcast) - { - throw new ArgumentOutOfRangeException(nameof(request.ProceedWithBroadcast), - "Please use CreateOnChainTransaction when wanting to also broadcast the transaction"); - } - - return Transaction.Parse( - GetFromActionResult( - await GetController().CreateOnChainTransaction(storeId, cryptoCode, request)), - network); - } - - public override async Task> GetStores(CancellationToken token = default) - { - return GetFromActionResult(await GetController().GetStores()); - } - - public override async Task GetStore(string storeId, CancellationToken token = default) - { - return GetFromActionResult(await GetController().GetStore(storeId)); - } - - public override async Task RemoveStore(string storeId, CancellationToken token = default) - { - HandleActionResult(await GetController().RemoveStore(storeId)); - } - - public override async Task CreateStore(CreateStoreRequest request, CancellationToken token = default) - { - return GetFromActionResult(await GetController().CreateStore(request)); - } - - public override async Task UpdateStore(string storeId, UpdateStoreRequest request, - CancellationToken token = default) - { - return GetFromActionResult(await GetController().UpdateStore(storeId, request)); - } - - public override async Task UploadStoreLogo(string storeId, string filePath, string mimeType, CancellationToken token = default) - { - var file = GetFormFile(filePath, mimeType); - return GetFromActionResult(await GetController().UploadStoreLogo(storeId, file)); - } - - public override async Task DeleteStoreLogo(string storeId, CancellationToken token = default) - { - HandleActionResult(await GetController().DeleteStoreLogo(storeId)); - } - - public override async Task> GetInvoices(string storeId, string[] orderId = null, - InvoiceStatus[] status = null, - DateTimeOffset? startDate = null, - DateTimeOffset? endDate = null, - string textSearch = null, - bool includeArchived = false, - int? skip = null, - int? take = null, - CancellationToken token = default - ) - { - return GetFromActionResult>( - await GetController().GetInvoices(storeId, orderId, - status?.Select(invoiceStatus => invoiceStatus.ToString())?.ToArray(), startDate, - endDate, textSearch, includeArchived, skip, take)); - } - - public override async Task GetInvoice(string storeId, string invoiceId, - CancellationToken token = default) - { - return GetFromActionResult(await GetController().GetInvoice(storeId, invoiceId)); - } - - public override async Task GetInvoicePaymentMethods(string storeId, - string invoiceId, - bool onlyAccountedPayments = true, bool includeSensitive = false, - CancellationToken token = default) - { - return GetFromActionResult( - await GetController().GetInvoicePaymentMethods(storeId, invoiceId, onlyAccountedPayments, includeSensitive)); - } - - public override async Task ArchiveInvoice(string storeId, string invoiceId, CancellationToken token = default) - { - HandleActionResult(await GetController().ArchiveInvoice(storeId, invoiceId)); - } - - public override async Task CreateInvoice(string storeId, CreateInvoiceRequest request, - CancellationToken token = default) - { - return GetFromActionResult(await GetController().CreateInvoice(storeId, request)); - } - - public override async Task UpdateInvoice(string storeId, string invoiceId, - UpdateInvoiceRequest request, CancellationToken token = default) - { - return GetFromActionResult( - await GetController().UpdateInvoice(storeId, invoiceId, request)); - } - - public override async Task MarkInvoiceStatus(string storeId, string invoiceId, - MarkInvoiceStatusRequest request, - CancellationToken token = default) - { - return GetFromActionResult( - await GetController().MarkInvoiceStatus(storeId, invoiceId, request)); - } - - public override async Task UnarchiveInvoice(string storeId, string invoiceId, - CancellationToken token = default) - { - return GetFromActionResult( - await GetController().UnarchiveInvoice(storeId, invoiceId)); - } - - public override Task GetServerInfo(CancellationToken token = default) - { - return Task.FromResult(GetFromActionResult(GetController().ServerInfo())); - } - - public override async Task ActivateInvoicePaymentMethod(string storeId, string invoiceId, string paymentMethod, - CancellationToken token = default) - { - HandleActionResult( - await GetController().ActivateInvoicePaymentMethod(storeId, invoiceId, paymentMethod)); - } - - public override async Task GetOnChainFeeRate(string storeId, string cryptoCode, - int? blockTarget = null, CancellationToken token = default) - { - return GetFromActionResult( - await GetController().GetOnChainFeeRate(storeId, cryptoCode, blockTarget)); - } - - public override async Task UpdateCurrentUser(UpdateApplicationUserRequest request, CancellationToken token = default) - { - return GetFromActionResult(await GetController().UpdateCurrentUser(request, token)); - } - - public override async Task UploadCurrentUserProfilePicture(string filePath, string mimeType, CancellationToken token = default) - { - var file = GetFormFile(filePath, mimeType); - return GetFromActionResult(await GetController().UploadCurrentUserProfilePicture(file)); - } - - public override async Task DeleteCurrentUserProfilePicture(CancellationToken token = default) - { - HandleActionResult(await GetController().DeleteCurrentUserProfilePicture()); - } - - public override async Task DeleteCurrentUser(CancellationToken token = default) - { - HandleActionResult(await GetController().DeleteCurrentUser()); - } - - public override async Task DeleteUser(string userId, CancellationToken token = default) - { - HandleActionResult(await GetController().DeleteUser(userId)); - } - - public override Task GetAvailableLanguages(CancellationToken token = default) - { - return Task.FromResult(GetController().LanguageService.GetLanguages() - .Select(language => new Language(language.Code, language.DisplayName)).ToArray()); - } - - public override Task GetPermissionMetadata(CancellationToken token = default) - { - return Task.FromResult(GetFromActionResult(GetController().Permissions())); - } - - public override async Task GetStorePaymentMethods(string storeId, - bool? onlyEnabled = null, bool? includeConfig = null, CancellationToken token = default) - { - return GetFromActionResult(await GetController().GetStorePaymentMethods(storeId, onlyEnabled, includeConfig)); - } - - public override async Task GenerateOnChainWallet(string storeId, - string paymentMethodId, GenerateOnChainWalletRequest request, - CancellationToken token = default) - { - return GetFromActionResult( - await GetController().GenerateOnChainWallet(storeId, Payments.PaymentMethodId.Parse(paymentMethodId), - request)); - } - - public override async Task SendEmail(string storeId, SendEmailRequest request, - CancellationToken token = default) - { - HandleActionResult(await GetController().SendEmailFromStore(storeId, request)); - } - - public override Task GetStoreEmailSettings(string storeId, CancellationToken token = default) - { - return Task.FromResult( - GetFromActionResult(GetController().GetStoreEmailSettings())); - } - - public override async Task UpdateStoreEmailSettings(string storeId, - EmailSettingsData request, CancellationToken token = default) - { - return GetFromActionResult( - await GetController().UpdateStoreEmailSettings(storeId, - JObject.FromObject(request).ToObject())); - } - - public override async Task GetUsers(CancellationToken token = default) - { - return GetFromActionResult(await GetController().GetUsers()); - } - - public override async Task> GetStoreUsers(string storeId, - CancellationToken token = default) - { - return GetFromActionResult>(await GetController().GetStoreUsers()); - } - - public override async Task AddStoreUser(string storeId, StoreUserData request, - CancellationToken token = default) - { - HandleActionResult(await GetController().AddOrUpdateStoreUser(storeId, request)); - } - - public override async Task UpdateStoreUser(string storeId, string userId, StoreUserData request, - CancellationToken token = default) - { - HandleActionResult(await GetController().AddOrUpdateStoreUser(storeId, request, userId)); - } - - public override async Task RemoveStoreUser(string storeId, string userId, CancellationToken token = default) - { - HandleActionResult(await GetController().RemoveStoreUser(storeId, userId)); - } - - public override async Task GetUserByIdOrEmail(string idOrEmail, - CancellationToken token = default) - { - return GetFromActionResult(await GetController().GetUser(idOrEmail)); - } - - public override async Task LockUser(string idOrEmail, bool disabled, CancellationToken token = default) - { - return GetFromActionResult( - await GetController().LockUser(idOrEmail, - new LockUserRequest { Locked = disabled })); - } - - public override async Task ApproveUser(string idOrEmail, bool approved, CancellationToken token = default) - { - return GetFromActionResult( - await GetController().ApproveUser(idOrEmail, - new ApproveUserRequest { Approved = approved })); - } - - public override async Task PatchOnChainWalletTransaction(string storeId, - string cryptoCode, string transactionId, - PatchOnChainTransactionRequest request, bool force = false, CancellationToken token = default) - { - return GetFromActionResult( - await GetController().PatchOnChainWalletTransaction(storeId, cryptoCode, transactionId, - request, force)); - } - - public override async Task GetLightningPayment(string cryptoCode, string paymentHash, - CancellationToken token = default) - { - return GetFromActionResult( - await GetController().GetPayment(cryptoCode, paymentHash, token)); - } - - public override async Task GetLightningPayment(string storeId, string cryptoCode, - string paymentHash, CancellationToken token = default) - { - return GetFromActionResult( - await GetController().GetPayment(cryptoCode, paymentHash, token)); - } - - public override async Task CreatePayout(string storeId, - CreatePayoutThroughStoreRequest payoutRequest, - CancellationToken cancellationToken = default) - { - return GetFromActionResult( - await GetController().CreatePayoutThroughStore(storeId, payoutRequest)); - } - - public override async Task> GetPayoutProcessors(string storeId, - CancellationToken token = default) - { - return GetFromActionResult>( - await GetController().GetStorePayoutProcessors(storeId)); - } - - public override Task> GetPayoutProcessors(CancellationToken token = default) - { - return Task.FromResult( - GetFromActionResult>(GetController() - .GetPayoutProcessors())); - } - - public override async Task RemovePayoutProcessor(string storeId, string processor, string paymentMethod, - CancellationToken token = default) - { - HandleActionResult( - await GetController().RemoveStorePayoutProcessor(storeId, processor, - paymentMethod)); - } - - public override async Task> - GetStoreOnChainAutomatedPayoutProcessors(string storeId, string paymentMethod = null, - CancellationToken token = default) - { - return GetFromActionResult>( - await GetController() - .GetStoreOnChainAutomatedPayoutProcessors(storeId, paymentMethod)); - } - - public override async Task> - GetStoreLightningAutomatedPayoutProcessors(string storeId, string paymentMethod = null, - CancellationToken token = default) - { - return GetFromActionResult>( - await GetController() - .GetStoreLightningAutomatedPayoutProcessors(storeId, paymentMethod)); - } - - public override async Task UpdateStoreOnChainAutomatedPayoutProcessors( - string storeId, string paymentMethod, - OnChainAutomatedPayoutSettings request, CancellationToken token = default) - { - return GetFromActionResult( - await GetController() - .UpdateStoreOnchainAutomatedPayoutProcessor(storeId, paymentMethod, request)); - } - - public override async Task UpdateStoreLightningAutomatedPayoutProcessors( - string storeId, string paymentMethod, - LightningAutomatedPayoutSettings request, CancellationToken token = default) - { - return GetFromActionResult( - await GetController() - .UpdateStoreLightningAutomatedPayoutProcessor(storeId, paymentMethod, request)); - } - - public override async Task GetStorePayouts(string storeId, bool includeCancelled = false, - CancellationToken cancellationToken = default) - { - return GetFromActionResult( - await GetController() - .GetStorePayouts(storeId, includeCancelled)); - } - - public override async Task CreatePointOfSaleApp( - string storeId, - PointOfSaleAppRequest request, CancellationToken token = default) - { - return GetFromActionResult( - await GetController().CreatePointOfSaleApp(storeId, request)); - } - - public override async Task UpdatePointOfSaleApp( - string appId, - PointOfSaleAppRequest request, CancellationToken token = default) - { - return GetFromActionResult( - await GetController().UpdatePointOfSaleApp(appId, request)); - } - - public override async Task CreateCrowdfundApp( - string storeId, - CrowdfundAppRequest request, CancellationToken token = default) - { - return GetFromActionResult( - await GetController().CreateCrowdfundApp(storeId, request)); - } - - public override async Task GetApp(string appId, CancellationToken token = default) - { - return GetFromActionResult( - await GetController().GetApp(appId)); - } - - public override async Task GetAllApps(string storeId, CancellationToken token = default) - { - return GetFromActionResult( - await GetController().GetAllApps(storeId)); - } - - public override async Task GetAllApps(CancellationToken token = default) - { - return GetFromActionResult( - await GetController().GetAllApps()); - } - - public override async Task GetAppSales(string appId, int numberOfDays = 7, CancellationToken token = default) - { - return GetFromActionResult( - await GetController().GetAppSales(appId, numberOfDays)); - } - - public override async Task> GetAppTopItems(string appId, int offset = 0, int count = 10, CancellationToken token = default) - { - return GetFromActionResult>( - await GetController().GetAppTopItems(appId, offset, count)); - } - - public override async Task DeleteApp(string appId, CancellationToken token = default) - { - HandleActionResult(await GetController().DeleteApp(appId)); - } - - public override async Task UploadAppItemImage(string appId, string filePath, string mimeType, CancellationToken token = default) - { - var file = GetFormFile(filePath, mimeType); - return GetFromActionResult(await GetController().UploadAppItemImage(appId, file)); - } - - public override async Task DeleteAppItemImage(string appId, string fileId, CancellationToken token = default) - { - HandleActionResult(await GetController().DeleteAppItemImage(appId, fileId)); - } - - public override Task> GetRateSources(CancellationToken token = default) - { - return Task.FromResult(GetFromActionResult(GetController().GetRateSources())); - } - - public override Task GetStoreRateConfiguration(string storeId, bool? fallback = null, CancellationToken token = default) - { - var ctrl = GetController(); - var res = fallback switch - { - null or true => ctrl.GetStoreFallbackRateConfiguration(), - false => ctrl.GetStoreRateConfiguration() - }; - return Task.FromResult(GetFromActionResult(res)); - } - - public override async Task> GetStoreRates(string storeId, - string[] currencyPair = null, CancellationToken token = default) - { - return GetFromActionResult>(await GetController().GetStoreRates(currencyPair)); - } - - public override async Task> PreviewUpdateStoreRateConfiguration(string storeId, - StoreRateConfiguration request, - string[] currencyPair = null, - CancellationToken token = default) - { - return GetFromActionResult>( - await GetController().PreviewUpdateStoreRateConfiguration(request, - currencyPair)); - } - - public override async Task UpdateStoreRateConfiguration(string storeId, StoreRateConfiguration request, bool? fallback = null, CancellationToken token = default) - { - var ctrl = GetController(); - var res = fallback switch - { - null or true => await ctrl.UpdateStoreRateConfiguration(request), - false => await ctrl.UpdateStoreRateFallbackConfiguration(request) - }; - return GetFromActionResult(res); - } - - public override async Task MarkPayoutPaid(string storeId, string payoutId, CancellationToken cancellationToken = default) - { - HandleActionResult(await GetController().MarkPayoutPaid(storeId, payoutId, cancellationToken)); - } - - public override async Task MarkPayout(string storeId, string payoutId, MarkPayoutRequest request, - CancellationToken cancellationToken = default) - { - HandleActionResult(await GetController().MarkPayout(storeId, payoutId, request)); - } - - public override async Task GetPullPaymentPayout(string pullPaymentId, string payoutId, CancellationToken cancellationToken = default) - { - return GetFromActionResult(await GetController().GetPayout(pullPaymentId, payoutId)); - } - - public override async Task RegisterBoltcard(string pullPaymentId, RegisterBoltcardRequest request, CancellationToken cancellationToken = default) - { - return GetFromActionResult(await GetController().RegisterBoltcard(pullPaymentId, request)); - } - - public override async Task GetPullPaymentLNURL(string pullPaymentId, CancellationToken cancellationToken = default) - { - return GetFromActionResult(await GetController().GetPullPaymentLNURL(pullPaymentId)); - } - - public override async Task GetStorePayout(string storeId, string payoutId, - CancellationToken cancellationToken = default) - { - return GetFromActionResult(await GetController().GetStorePayout(storeId, payoutId)); - } - - public override async Task GetStoreLightningAddresses(string storeId, - CancellationToken token = default) - { - return GetFromActionResult(await GetController().GetStoreLightningAddresses(storeId)); - } - - public override async Task GetStoreLightningAddress(string storeId, string username, CancellationToken token = default) - { - return GetFromActionResult(await GetController().GetStoreLightningAddress(storeId, username)); - } - - public override async Task AddOrUpdateStoreLightningAddress(string storeId, string username, LightningAddressData data, - CancellationToken token = default) - { - return GetFromActionResult(await GetController().AddOrUpdateStoreLightningAddress(storeId, username, data)); - } - - public override async Task RemoveStoreLightningAddress(string storeId, string username, CancellationToken token = default) - { - HandleActionResult(await GetController().RemoveStoreLightningAddress(storeId, username)); - } - - public override async Task GetPosApp(string appId, - CancellationToken cancellationToken = default) - { - return GetFromActionResult(await GetController().GetPosApp(appId)); - } - - public override async Task GetCrowdfundApp(string appId, - CancellationToken cancellationToken = default) - { - return GetFromActionResult(await GetController().GetCrowdfundApp(appId)); - } - - public override async Task GetInvoiceRefundTriggerData(string storeId, string invoiceId, string paymentMethodId, - CancellationToken token = default) - { - return GetFromActionResult(await GetController().GetInvoiceRefundTriggerData(storeId, invoiceId, paymentMethodId, token)); - } - public override async Task RefundInvoice(string storeId, string invoiceId, RefundInvoiceRequest request, CancellationToken token = default) - { - return GetFromActionResult(await GetController().RefundInvoice(storeId, invoiceId, request, token)); - } - public override async Task RevokeAPIKey(string userId, string apikey, CancellationToken token = default) - { - HandleActionResult(await GetController().RevokeAPIKey(userId, apikey)); - } - - public override async Task CreateAPIKey(string userId, CreateApiKeyRequest request, CancellationToken token = default) - { - return GetFromActionResult(await GetController().CreateUserAPIKey(userId, request)); - } - - public override async Task> GetServerRoles(CancellationToken token = default) - { - return GetFromActionResult>(await GetController().GetServerRoles()); - } - public override async Task> GetStoreRoles(string storeId, CancellationToken token = default) - { - return GetFromActionResult>(await GetController().GetStoreRoles(storeId)); - } - - public override async Task GetFiles(CancellationToken token = default) - { - return GetFromActionResult(await GetController().GetFiles()); - } - - public override async Task GetFile(string fileId, CancellationToken token = default) - { - return GetFromActionResult(await GetController().GetFile(fileId)); - } - - public override async Task UploadFile(string filePath, string mimeType, CancellationToken token = default) - { - var file = GetFormFile(filePath, mimeType); - return GetFromActionResult(await GetController().UploadFile(file)); - } - - public override async Task DeleteFile(string fileId, CancellationToken token = default) - { - HandleActionResult(await GetController().DeleteFile(fileId)); - } - - private IFormFile GetFormFile(string filePath, string mimeType) - { - var fileName = Path.GetFileName(filePath); - var fs = File.OpenRead(filePath); - return new FormFile(fs, 0, fs.Length, fileName, fileName) - { - Headers = new HeaderDictionary(), - ContentType = mimeType - }; - } - } -} diff --git a/BTCPayServer/Controllers/UIInvoiceController.cs b/BTCPayServer/Controllers/UIInvoiceController.cs index b5d7d24ec..f4eccf933 100644 --- a/BTCPayServer/Controllers/UIInvoiceController.cs +++ b/BTCPayServer/Controllers/UIInvoiceController.cs @@ -39,7 +39,6 @@ namespace BTCPayServer.Controllers public partial class UIInvoiceController : Controller { readonly InvoiceRepository _InvoiceRepository; - private readonly WalletRepository _walletRepository; readonly RateFetcher _RateProvider; readonly StoreRepository _StoreRepository; readonly UserManager _UserManager; @@ -71,14 +70,12 @@ namespace BTCPayServer.Controllers public UIInvoiceController( InvoiceRepository invoiceRepository, - WalletRepository walletRepository, DisplayFormatter displayFormatter, CurrencyNameTable currencyNameTable, UserManager userManager, RateFetcher rateProvider, StoreRepository storeRepository, EventAggregator eventAggregator, - ContentSecurityPolicies csp, BTCPayNetworkProvider networkProvider, PayoutMethodHandlerDictionary payoutHandlers, PaymentMethodHandlerDictionary paymentMethodHandlerDictionary, @@ -105,7 +102,6 @@ namespace BTCPayServer.Controllers _CurrencyNameTable = currencyNameTable ?? throw new ArgumentNullException(nameof(currencyNameTable)); _StoreRepository = storeRepository ?? throw new ArgumentNullException(nameof(storeRepository)); _InvoiceRepository = invoiceRepository ?? throw new ArgumentNullException(nameof(invoiceRepository)); - _walletRepository = walletRepository; _RateProvider = rateProvider ?? throw new ArgumentNullException(nameof(rateProvider)); _UserManager = userManager; _EventAggregator = eventAggregator; diff --git a/BTCPayServer/Data/Payouts/LightningLike/BoltInvoiceClaimDestination.cs b/BTCPayServer/Data/Payouts/LightningLike/BoltInvoiceClaimDestination.cs index 5b7ef6a30..f54e6c96b 100644 --- a/BTCPayServer/Data/Payouts/LightningLike/BoltInvoiceClaimDestination.cs +++ b/BTCPayServer/Data/Payouts/LightningLike/BoltInvoiceClaimDestination.cs @@ -1,27 +1,20 @@ +#nullable enable using System; using BTCPayServer.Lightning; using NBitcoin; namespace BTCPayServer.Data.Payouts.LightningLike { - public class BoltInvoiceClaimDestination : ILightningLikeLikeClaimDestination + public class BoltInvoiceClaimDestination(string bolt11, BOLT11PaymentRequest paymentRequest) : ILightningLikeLikeClaimDestination { - public BoltInvoiceClaimDestination(string bolt11, BOLT11PaymentRequest paymentRequest) - { - Bolt11 = bolt11 ?? throw new ArgumentNullException(nameof(bolt11)); - PaymentRequest = paymentRequest; - PaymentHash = paymentRequest.Hash; - Amount = paymentRequest.MinimumAmount.MilliSatoshi == LightMoney.Zero ? null: paymentRequest.MinimumAmount.ToDecimal(LightMoneyUnit.BTC); - } - public override string ToString() { return Bolt11; } - public string Bolt11 { get; } - public BOLT11PaymentRequest PaymentRequest { get; } - public uint256 PaymentHash { get; } + public string Bolt11 { get; } = bolt11 ?? throw new ArgumentNullException(nameof(bolt11)); + public BOLT11PaymentRequest PaymentRequest { get; } = paymentRequest; + public uint256 PaymentHash { get; } = paymentRequest.Hash; public string Id => PaymentHash.ToString(); - public decimal? Amount { get; } + public decimal? Amount { get; } = paymentRequest.MinimumAmount.MilliSatoshi == LightMoney.Zero ? null: paymentRequest.MinimumAmount.ToDecimal(LightMoneyUnit.BTC); }; } diff --git a/BTCPayServer/Data/Payouts/LightningLike/LightningLikePayoutHandler.cs b/BTCPayServer/Data/Payouts/LightningLike/LightningLikePayoutHandler.cs index a79a272b4..fbfb12f69 100644 --- a/BTCPayServer/Data/Payouts/LightningLike/LightningLikePayoutHandler.cs +++ b/BTCPayServer/Data/Payouts/LightningLike/LightningLikePayoutHandler.cs @@ -1,7 +1,5 @@ using System; -using System.Collections.Concurrent; using System.Collections.Generic; -using System.Linq; using System.Net.Http; using System.Threading; using System.Threading.Tasks; @@ -14,13 +12,10 @@ using BTCPayServer.Payments; using BTCPayServer.Payments.Bitcoin; using BTCPayServer.Payments.Lightning; using BTCPayServer.Payouts; -using BTCPayServer.Services; using BTCPayServer.Services.Invoices; using LNURL; -using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Options; -using MimeKit; using NBitcoin; namespace BTCPayServer.Data.Payouts.LightningLike @@ -32,7 +27,7 @@ namespace BTCPayServer.Data.Payouts.LightningLike public PaymentMethodId PaymentMethodId { get; } private readonly IOptions _options; - private PaymentMethodHandlerDictionary _paymentHandlers; + private readonly PaymentMethodHandlerDictionary _paymentHandlers; public BTCPayNetwork Network { get; } public string[] DefaultRateRules => Network.DefaultRateRules; @@ -43,15 +38,13 @@ namespace BTCPayServer.Data.Payouts.LightningLike public const string LightningLikePayoutHandlerClearnetNamedClient = nameof(LightningLikePayoutHandlerClearnetNamedClient); private readonly IHttpClientFactory _httpClientFactory; - private readonly UserService _userService; - private readonly IAuthorizationService _authorizationService; public LightningLikePayoutHandler( PayoutMethodId payoutMethodId, IOptions options, BTCPayNetwork network, PaymentMethodHandlerDictionary paymentHandlers, - IHttpClientFactory httpClientFactory, UserService userService, IAuthorizationService authorizationService) + IHttpClientFactory httpClientFactory) { _paymentHandlers = paymentHandlers; Network = network; @@ -59,8 +52,6 @@ namespace BTCPayServer.Data.Payouts.LightningLike _options = options; PaymentMethodId = PaymentTypes.LN.GetPaymentMethodId(network.CryptoCode); _httpClientFactory = httpClientFactory; - _userService = userService; - _authorizationService = authorizationService; Currency = network.CryptoCode; } @@ -112,7 +103,7 @@ namespace BTCPayServer.Data.Payouts.LightningLike } var result = - BOLT11PaymentRequest.TryParse(destination, out var invoice, Network.NBitcoinNetwork) + BOLT11PaymentRequest.TryParse(destination, out var invoice, Network.NBitcoinNetwork) && invoice is not null ? new BoltInvoiceClaimDestination(destination, invoice) : null; diff --git a/BTCPayServer/Hosting/BTCPayServerServices.cs b/BTCPayServer/Hosting/BTCPayServerServices.cs index fb1d1529a..7abe2edab 100644 --- a/BTCPayServer/Hosting/BTCPayServerServices.cs +++ b/BTCPayServer/Hosting/BTCPayServerServices.cs @@ -73,7 +73,6 @@ using BTCPayServer.Payouts; using ExchangeSharp; using Microsoft.Extensions.Localization; using Microsoft.AspNetCore.Mvc.Localization; -using System.Reflection; using Microsoft.EntityFrameworkCore; namespace BTCPayServer.Hosting @@ -427,7 +426,7 @@ o.GetRequiredService>().ToDictionary(o => o.P services.AddSingleton(); services.AddSingleton(); - services.AddScoped(); + services.AddSingleton(); RegisterExchangeRecommendations(services); services.AddSingleton(); @@ -481,10 +480,6 @@ o.GetRequiredService>().ToDictionary(o => o.P services.AddSingleton(); services.AddSingleton(); - //create a simple client which hooks up to the http scope - services.AddScoped(); - //also provide a factory that can impersonate user/store id - services.AddSingleton(); services.AddPayoutProcesors(); services.AddForms(); diff --git a/BTCPayServer/Plugins/Emails/HostedServices/UserEventTriggerHostedService.cs b/BTCPayServer/Plugins/Emails/HostedServices/UserEventTriggerHostedService.cs index 60d974d48..830358008 100644 --- a/BTCPayServer/Plugins/Emails/HostedServices/UserEventTriggerHostedService.cs +++ b/BTCPayServer/Plugins/Emails/HostedServices/UserEventTriggerHostedService.cs @@ -11,6 +11,7 @@ using BTCPayServer.Services; using BTCPayServer.Services.Notifications; using BTCPayServer.Services.Notifications.Blobs; using Microsoft.AspNetCore.Identity; +using Microsoft.Extensions.DependencyInjection; using Newtonsoft.Json.Linq; using QRCoder; @@ -18,14 +19,12 @@ namespace BTCPayServer.Plugins.Emails.HostedServices; public class UserEventHostedService( EventAggregator eventAggregator, - UserManager userManager, + IServiceScopeFactory serviceScopeFactory, ISettingsAccessor serverSettings, NotificationSender notificationSender, Logs logs) : EventHostedServiceBase(eventAggregator, logs) { - public UserManager UserManager { get; } = userManager; - protected override void SubscribeToEvents() { SubscribeAny(); @@ -117,7 +116,9 @@ public class UserEventHostedService( private async Task CreateTriggerEvent(string trigger, JObject model, ApplicationUser user) { - var admins = await UserManager.GetUsersInRoleAsync(Roles.ServerAdmin); + using var scope = serviceScopeFactory.CreateScope(); + var userManager = scope.ServiceProvider.GetRequiredService>(); + var admins = await userManager.GetUsersInRoleAsync(Roles.ServerAdmin); var adminMailboxes = string.Join(", ", admins.Select(a => a.GetMailboxAddress().ToString()).ToArray()); model["Admins"] = new JObject() { diff --git a/BTCPayServer/Plugins/Subscriptions/SubscriptionHostedService.cs b/BTCPayServer/Plugins/Subscriptions/SubscriptionHostedService.cs index b4e013cfb..34c04f052 100644 --- a/BTCPayServer/Plugins/Subscriptions/SubscriptionHostedService.cs +++ b/BTCPayServer/Plugins/Subscriptions/SubscriptionHostedService.cs @@ -18,6 +18,7 @@ using BTCPayServer.Services.Rates; using Dapper; using Microsoft.AspNetCore.Routing; using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.DependencyInjection; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using static BTCPayServer.Data.Subscriptions.SubscriberData; @@ -30,7 +31,7 @@ public class SubscriptionHostedService( EventAggregator eventAggregator, ApplicationDbContextFactory applicationDbContextFactory, SettingsRepository settingsRepository, - UIInvoiceController invoiceController, + IServiceScopeFactory scopeFactory, CurrencyNameTable currencyNameTable, LinkGenerator linkGenerator, Logs logger) : EventHostedServiceBase(eventAggregator, logger), IPeriodicTask @@ -162,6 +163,8 @@ public class SubscriptionHostedService( if (amount > 0) { + using var scope = scopeFactory.CreateScope(); + var invoiceController = scope.ServiceProvider.GetRequiredService(); var request = await invoiceController.CreateInvoiceCoreRaw(new() { Currency = plan.Currency, diff --git a/BTCPayServer/Services/BTCPayServerSecurityStampValidator.cs b/BTCPayServer/Services/BTCPayServerSecurityStampValidator.cs index 0c178e8ac..8ab27da32 100644 --- a/BTCPayServer/Services/BTCPayServerSecurityStampValidator.cs +++ b/BTCPayServer/Services/BTCPayServerSecurityStampValidator.cs @@ -26,6 +26,10 @@ public class BTCPayServerSecurityStampValidator( ConcurrentDictionary _DisabledUsers = new ConcurrentDictionary(); public bool HasAny => !_DisabledUsers.IsEmpty; + /// + /// Note that you also need to invalidate the security stamp of the user + /// + /// public void Add(string user) { _DisabledUsers.TryAdd(user, DateTimeOffset.UtcNow); diff --git a/BTCPayServer/Services/Notifications/NotificationSender.cs b/BTCPayServer/Services/Notifications/NotificationSender.cs index 31a7a8861..f420e169e 100644 --- a/BTCPayServer/Services/Notifications/NotificationSender.cs +++ b/BTCPayServer/Services/Notifications/NotificationSender.cs @@ -6,6 +6,7 @@ using BTCPayServer.Abstractions.Contracts; using BTCPayServer.Data; using Microsoft.AspNetCore.Identity; using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.DependencyInjection; namespace BTCPayServer.Services.Notifications { @@ -13,25 +14,15 @@ namespace BTCPayServer.Services.Notifications { public string UserId { get; set; } } - public class NotificationSender + public class NotificationSender(ApplicationDbContextFactory contextFactory, IServiceScopeFactory scopeFactory, NotificationManager notificationManager) { - private readonly ApplicationDbContextFactory _contextFactory; - private readonly UserManager _userManager; - private readonly NotificationManager _notificationManager; - - public NotificationSender(ApplicationDbContextFactory contextFactory, UserManager userManager, NotificationManager notificationManager) - { - _contextFactory = contextFactory; - _userManager = userManager; - _notificationManager = notificationManager; - } public async Task SendNotification(INotificationScope scope, BaseNotification notification) { ArgumentNullException.ThrowIfNull(scope); ArgumentNullException.ThrowIfNull(notification); var users = await GetUsers(scope, notification.Identifier); - await using (var db = _contextFactory.CreateContext()) + await using (var db = contextFactory.CreateContext()) { foreach (var uid in users) { @@ -48,7 +39,7 @@ namespace BTCPayServer.Services.Notifications } await db.SaveChangesAsync(); } - _notificationManager.InvalidateNotificationCache(users); + notificationManager.InvalidateNotificationCache(users); } public BaseNotification GetBaseNotification(NotificationData notificationData) @@ -58,7 +49,7 @@ namespace BTCPayServer.Services.Notifications private async Task GetUsers(INotificationScope scope, string notificationIdentifier) { - await using var ctx = _contextFactory.CreateContext(); + await using var ctx = contextFactory.CreateContext(); var split = notificationIdentifier.Split('_', StringSplitOptions.None); var terms = new List(); @@ -71,8 +62,8 @@ namespace BTCPayServer.Services.Notifications { case AdminScope _: { - query = _userManager.GetUsersInRoleAsync(Roles.ServerAdmin).Result.AsQueryable(); - + using var s = scopeFactory.CreateScope(); + query = s.ServiceProvider.GetService>().GetUsersInRoleAsync(Roles.ServerAdmin).Result.AsQueryable(); break; } case StoreScope s: diff --git a/BTCPayServer/Views/UIPullPayment/ViewPullPayment.cshtml b/BTCPayServer/Views/UIPullPayment/ViewPullPayment.cshtml index f5b88ec3f..cbf73796b 100644 --- a/BTCPayServer/Views/UIPullPayment/ViewPullPayment.cshtml +++ b/BTCPayServer/Views/UIPullPayment/ViewPullPayment.cshtml @@ -93,7 +93,7 @@
@if (!string.IsNullOrWhiteSpace(Model.Title)) { -

@Model.Title

+

@Model.Title

}
Start Date @@ -122,7 +122,7 @@ } @if (!string.IsNullOrEmpty(Model.Description)) { -
@Safe.Raw(Model.Description)
+
@Safe.Raw(Model.Description)
}