diff --git a/BTCPayServer.Client/BTCPayServerClient.Apps.cs b/BTCPayServer.Client/BTCPayServerClient.Apps.cs index 4c2aff7ae7..3112467ca1 100644 --- a/BTCPayServer.Client/BTCPayServerClient.Apps.cs +++ b/BTCPayServer.Client/BTCPayServerClient.Apps.cs @@ -78,4 +78,14 @@ public virtual async Task DeleteApp(string appId, CancellationToken token = defa if (appId == null) throw new ArgumentNullException(nameof(appId)); await SendHttpRequest($"api/v1/apps/{appId}", null, HttpMethod.Delete, token); } + + public virtual async Task UploadAppItemImage(string appId, string filePath, string mimeType, CancellationToken token = default) + { + return await UploadFileRequest($"api/v1/apps/{appId}/image", filePath, mimeType, "file", HttpMethod.Post, token); + } + + public virtual async Task DeleteAppItemImage(string appId, string fileId, CancellationToken token = default) + { + await SendHttpRequest($"api/v1/apps/{appId}/image/{fileId}", null, HttpMethod.Delete, token); + } } diff --git a/BTCPayServer.Client/BTCPayServerClient.cs b/BTCPayServer.Client/BTCPayServerClient.cs index 1e3a035354..85adbddf8b 100644 --- a/BTCPayServer.Client/BTCPayServerClient.cs +++ b/BTCPayServer.Client/BTCPayServerClient.cs @@ -156,7 +156,7 @@ protected virtual HttpRequestMessage CreateHttpRequest(string path, protected virtual async Task UploadFileRequest(string apiPath, string filePath, string mimeType, string formFieldName, HttpMethod method = null, CancellationToken token = default) { using MultipartFormDataContent multipartContent = new(); - var fileContent = new StreamContent(File.OpenRead(filePath)); + using var fileContent = new StreamContent(File.OpenRead(filePath)); var fileName = Path.GetFileName(filePath); fileContent.Headers.ContentType = MediaTypeHeaderValue.Parse(mimeType); multipartContent.Add(fileContent, formFieldName, fileName); diff --git a/BTCPayServer.Common/BTCPayServer.Common.csproj b/BTCPayServer.Common/BTCPayServer.Common.csproj index e7f8a51303..bfa7a579e0 100644 --- a/BTCPayServer.Common/BTCPayServer.Common.csproj +++ b/BTCPayServer.Common/BTCPayServer.Common.csproj @@ -7,7 +7,4 @@ - - - diff --git a/BTCPayServer.Tests/GreenfieldAPITests.cs b/BTCPayServer.Tests/GreenfieldAPITests.cs index 307adf15b9..805d93097a 100644 --- a/BTCPayServer.Tests/GreenfieldAPITests.cs +++ b/BTCPayServer.Tests/GreenfieldAPITests.cs @@ -318,6 +318,20 @@ await AssertValidationError(["file"], Assert.Empty(await client.GetFiles()); storeData = await client.GetStore(store.Id); Assert.Null(storeData.LogoUrl); + + // App Item Image + var app = await client.CreatePointOfSaleApp(store.Id, new PointOfSaleAppRequest { AppName = "Test App" }); + await AssertValidationError(["file"], + async () => await client.UploadAppItemImage(app.Id, filePath, "text/csv") + ); + + var fileData = await client.UploadAppItemImage(app.Id, logoPath, "image/png"); + Assert.Equal("logo.png", fileData.OriginalName); + files = await client.GetFiles(); + Assert.Single(files); + + await client.DeleteAppItemImage(app.Id, fileData.Id); + Assert.Empty(await client.GetFiles()); } [Fact(Timeout = TestTimeout)] diff --git a/BTCPayServer/ColorPalette.cs b/BTCPayServer/ColorPalette.cs index 462a4350ba..631c549872 100644 --- a/BTCPayServer/ColorPalette.cs +++ b/BTCPayServer/ColorPalette.cs @@ -110,5 +110,10 @@ public Color FromHtml(string html) { return ColorTranslator.FromHtml(html); } + + public string ToHtml(Color color) + { + return ColorTranslator.ToHtml(color); + } } } diff --git a/BTCPayServer/Components/AppSales/AppSales.cs b/BTCPayServer/Components/AppSales/AppSales.cs index 4e0d3dbe58..02670e1153 100644 --- a/BTCPayServer/Components/AppSales/AppSales.cs +++ b/BTCPayServer/Components/AppSales/AppSales.cs @@ -1,11 +1,5 @@ -using System; -using System.Security.AccessControl; using System.Threading.Tasks; -using BTCPayServer.Data; -using BTCPayServer.Models.AppViewModels; using BTCPayServer.Services.Apps; -using BTCPayServer.Services.Stores; -using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.ViewComponents; using Microsoft.AspNetCore.Mvc.ViewFeatures; diff --git a/BTCPayServer/Components/AppSales/AppSalesViewModel.cs b/BTCPayServer/Components/AppSales/AppSalesViewModel.cs index d7fab9e943..3d7513cabf 100644 --- a/BTCPayServer/Components/AppSales/AppSalesViewModel.cs +++ b/BTCPayServer/Components/AppSales/AppSalesViewModel.cs @@ -1,6 +1,5 @@ using System.Collections.Generic; using BTCPayServer.Client.Models; -using BTCPayServer.Services.Apps; namespace BTCPayServer.Components.AppSales; diff --git a/BTCPayServer/Components/AppSales/Default.cshtml.js b/BTCPayServer/Components/AppSales/Default.cshtml.js index 37472d1d77..e3cc686045 100644 --- a/BTCPayServer/Components/AppSales/Default.cshtml.js +++ b/BTCPayServer/Components/AppSales/Default.cshtml.js @@ -45,7 +45,6 @@ if (!window.appSales) { function addEventListeners() { delegate('change', `#${id} [name="AppSalesPeriod-${appId}"]`, async e => { - console.log("CHANGED", id) const type = e.target.value; await update(type); }); diff --git a/BTCPayServer/Components/StoreLightningBalance/StoreLightningBalanceViewModel.cs b/BTCPayServer/Components/StoreLightningBalance/StoreLightningBalanceViewModel.cs index 6bfd3eec7f..d4d2a1d858 100644 --- a/BTCPayServer/Components/StoreLightningBalance/StoreLightningBalanceViewModel.cs +++ b/BTCPayServer/Components/StoreLightningBalance/StoreLightningBalanceViewModel.cs @@ -4,7 +4,6 @@ using BTCPayServer.Lightning; using BTCPayServer.Services.Rates; using NBitcoin; -using StoreData = BTCPayServer.Data.StoreData; namespace BTCPayServer.Components.StoreLightningBalance; diff --git a/BTCPayServer/Components/StoreLightningServices/Default.cshtml b/BTCPayServer/Components/StoreLightningServices/Default.cshtml index 3deb55c349..7cc0755f6f 100644 --- a/BTCPayServer/Components/StoreLightningServices/Default.cshtml +++ b/BTCPayServer/Components/StoreLightningServices/Default.cshtml @@ -2,14 +2,14 @@ @if (Model.Services != null && Model.Services.Any()) { -
+
Lightning Services
diff --git a/BTCPayServer/Components/StoreLightningServices/StoreLightningServices.cs b/BTCPayServer/Components/StoreLightningServices/StoreLightningServices.cs index 613079a2e1..b3247663c3 100644 --- a/BTCPayServer/Components/StoreLightningServices/StoreLightningServices.cs +++ b/BTCPayServer/Components/StoreLightningServices/StoreLightningServices.cs @@ -2,15 +2,16 @@ using System.Linq; using System.Threading.Tasks; using BTCPayServer.Abstractions.Extensions; +using BTCPayServer.Client; using BTCPayServer.Configuration; using BTCPayServer.Data; -using BTCPayServer.Lightning; using BTCPayServer.Models; using BTCPayServer.Models.StoreViewModels; using BTCPayServer.Payments; using BTCPayServer.Payments.Lightning; -using BTCPayServer.Services; -using BTCPayServer.Services.Stores; +using BTCPayServer.Security; +using BTCPayServer.Services.Invoices; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Options; @@ -20,24 +21,38 @@ public class StoreLightningServices : ViewComponent { private readonly BTCPayServerOptions _btcpayServerOptions; private readonly BTCPayNetworkProvider _networkProvider; + private readonly IAuthorizationService _authorizationService; + private readonly PaymentMethodHandlerDictionary _handlers; + private readonly IOptions _lightningNetworkOptions; private readonly IOptions _externalServiceOptions; public StoreLightningServices( BTCPayNetworkProvider networkProvider, BTCPayServerOptions btcpayServerOptions, + IAuthorizationService authorizationService, + PaymentMethodHandlerDictionary handlers, + IOptions lightningNetworkOptions, IOptions externalServiceOptions) { _networkProvider = networkProvider; _btcpayServerOptions = btcpayServerOptions; + _lightningNetworkOptions = lightningNetworkOptions; _externalServiceOptions = externalServiceOptions; + _authorizationService = authorizationService; + _handlers = handlers; } - public IViewComponentResult Invoke(StoreLightningServicesViewModel vm) + public async Task InvokeAsync(StoreData store, string cryptoCode) { - if (vm.Store == null) - throw new ArgumentNullException(nameof(vm.Store)); - if (vm.CryptoCode == null) - throw new ArgumentNullException(nameof(vm.CryptoCode)); + var vm = new StoreLightningServicesViewModel { StoreId = store.Id, CryptoCode = cryptoCode }; + var id = PaymentTypes.LN.GetPaymentMethodId(cryptoCode); + var existing = store.GetPaymentMethodConfig(id, _handlers); + if (existing?.IsInternalNode is true && _lightningNetworkOptions.Value.InternalLightningByCryptoCode.TryGetValue(cryptoCode, out _)) + { + var result = await _authorizationService.AuthorizeAsync(HttpContext.User, null, new PolicyRequirement(Policies.CanUseInternalLightningNode)); + vm.LightningNodeType = result.Succeeded ? LightningNodeType.Internal : null; + } + if (vm.LightningNodeType != LightningNodeType.Internal) return View(vm); if (!User.IsInRole(Roles.ServerAdmin)) diff --git a/BTCPayServer/Components/StoreLightningServices/StoreLightningServicesViewModel.cs b/BTCPayServer/Components/StoreLightningServices/StoreLightningServicesViewModel.cs index 8a1a9b8163..33dd3681f1 100644 --- a/BTCPayServer/Components/StoreLightningServices/StoreLightningServicesViewModel.cs +++ b/BTCPayServer/Components/StoreLightningServices/StoreLightningServicesViewModel.cs @@ -8,8 +8,8 @@ namespace BTCPayServer.Components.StoreLightningServices; public class StoreLightningServicesViewModel { + public string StoreId { get; set; } public string CryptoCode { get; set; } - public StoreData Store { get; set; } - public LightningNodeType LightningNodeType { get; set; } + public LightningNodeType? LightningNodeType { get; set; } public List Services { get; set; } } diff --git a/BTCPayServer/Components/StoreNumbers/Default.cshtml b/BTCPayServer/Components/StoreNumbers/Default.cshtml index 1b3f26fffb..b9517b47dd 100644 --- a/BTCPayServer/Components/StoreNumbers/Default.cshtml +++ b/BTCPayServer/Components/StoreNumbers/Default.cshtml @@ -1,7 +1,7 @@ @using BTCPayServer.Client @model BTCPayServer.Components.StoreNumbers.StoreNumbersViewModel -
+
@if (Model.InitialRendering) {
@@ -11,8 +11,8 @@