mirror of
https://github.com/btcpayserver/btcpayserver.git
synced 2025-03-11 01:35:22 +01:00
Refactor plugin apps (#4780)
* Refactor plugins * Add missing names to view models * Cleanups * Replace SalesAppBaseType by two interfaces --------- Co-authored-by: Dennis Reimann <mail@dennisreimann.de>
This commit is contained in:
parent
53f3758abc
commit
04ba1430ca
28 changed files with 163 additions and 160 deletions
|
@ -623,7 +623,7 @@ namespace BTCPayServer.Tests
|
|||
var apps = user.GetController<UIAppsController>();
|
||||
var pos = user.GetController<UIPointOfSaleController>();
|
||||
var vm = Assert.IsType<CreateAppViewModel>(Assert.IsType<ViewResult>(apps.CreateApp(user.StoreId)).Model);
|
||||
var appType = PointOfSaleApp.AppType;
|
||||
var appType = PointOfSaleAppType.AppType;
|
||||
vm.AppName = "test";
|
||||
vm.SelectedAppType = appType;
|
||||
var redirect = Assert.IsType<RedirectResult>(apps.CreateApp(user.StoreId, vm).Result);
|
||||
|
|
|
@ -37,7 +37,7 @@ namespace BTCPayServer.Tests
|
|||
var apps = user.GetController<UIAppsController>();
|
||||
var apps2 = user2.GetController<UIAppsController>();
|
||||
var crowdfund = user.GetController<UICrowdfundController>();
|
||||
var appType = CrowdfundApp.AppType;
|
||||
var appType = CrowdfundAppType.AppType;
|
||||
var vm = Assert.IsType<CreateAppViewModel>(Assert.IsType<ViewResult>(apps.CreateApp(user.StoreId, appType)).Model);
|
||||
Assert.Equal(appType, vm.SelectedAppType);
|
||||
Assert.Null(vm.AppName);
|
||||
|
@ -77,7 +77,7 @@ namespace BTCPayServer.Tests
|
|||
var apps = user.GetController<UIAppsController>();
|
||||
var crowdfund = user.GetController<UICrowdfundController>();
|
||||
var vm = apps.CreateApp(user.StoreId).AssertViewModel<CreateAppViewModel>();
|
||||
var appType = CrowdfundApp.AppType;
|
||||
var appType = CrowdfundAppType.AppType;
|
||||
vm.AppName = "test";
|
||||
vm.SelectedAppType = appType;
|
||||
var redirect = Assert.IsType<RedirectResult>(apps.CreateApp(user.StoreId, vm).Result);
|
||||
|
@ -169,7 +169,7 @@ namespace BTCPayServer.Tests
|
|||
var apps = user.GetController<UIAppsController>();
|
||||
var crowdfund = user.GetController<UICrowdfundController>();
|
||||
var vm = Assert.IsType<CreateAppViewModel>(Assert.IsType<ViewResult>(apps.CreateApp(user.StoreId)).Model);
|
||||
var appType = CrowdfundApp.AppType;
|
||||
var appType = CrowdfundAppType.AppType;
|
||||
vm.AppName = "test";
|
||||
vm.SelectedAppType = appType;
|
||||
Assert.IsType<RedirectResult>(apps.CreateApp(user.StoreId, vm).Result);
|
||||
|
|
|
@ -31,7 +31,7 @@ namespace BTCPayServer.Tests
|
|||
var apps = user.GetController<UIAppsController>();
|
||||
var pos = user.GetController<UIPointOfSaleController>();
|
||||
var vm = Assert.IsType<CreateAppViewModel>(Assert.IsType<ViewResult>(apps.CreateApp(user.StoreId)).Model);
|
||||
var appType = PointOfSaleApp.AppType;
|
||||
var appType = PointOfSaleAppType.AppType;
|
||||
vm.AppName = "test";
|
||||
vm.SelectedAppType = appType;
|
||||
var redirect = Assert.IsType<RedirectResult>(apps.CreateApp(user.StoreId, vm).Result);
|
||||
|
|
|
@ -1955,7 +1955,7 @@ namespace BTCPayServer.Tests
|
|||
var apps = user.GetController<UIAppsController>();
|
||||
var apps2 = user2.GetController<UIAppsController>();
|
||||
var pos = user.GetController<UIPointOfSaleController>();
|
||||
var appType = PointOfSaleApp.AppType;
|
||||
var appType = PointOfSaleAppType.AppType;
|
||||
var vm = Assert.IsType<CreateAppViewModel>(Assert.IsType<ViewResult>(apps.CreateApp(user.StoreId, appType)).Model);
|
||||
Assert.Equal(appType, vm.SelectedAppType);
|
||||
Assert.Null(vm.AppName);
|
||||
|
|
|
@ -7,6 +7,8 @@ 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;
|
||||
|
||||
namespace BTCPayServer.Components.AppSales;
|
||||
|
||||
|
@ -27,6 +29,9 @@ public class AppSales : ViewComponent
|
|||
|
||||
public async Task<IViewComponentResult> InvokeAsync(string appId, string appType)
|
||||
{
|
||||
var type = _appService.GetAppType(appType);
|
||||
if (type is not IHasSaleStatsAppType salesAppType || type is not AppBaseType appBaseType)
|
||||
return new HtmlContentViewComponentResult(new StringHtmlContent(string.Empty));
|
||||
var vm = new AppSalesViewModel
|
||||
{
|
||||
Id = appId,
|
||||
|
@ -42,7 +47,8 @@ public class AppSales : ViewComponent
|
|||
vm.SalesCount = stats.SalesCount;
|
||||
vm.Series = stats.Series;
|
||||
vm.AppType = app.AppType;
|
||||
vm.AppUrl = await _appService.ConfigureLink(app, app.AppType);
|
||||
vm.AppUrl = await appBaseType.ConfigureLink(app);
|
||||
vm.Name = app.Name;
|
||||
|
||||
return View(vm);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
using System.Collections.Generic;
|
||||
using BTCPayServer.Data;
|
||||
using BTCPayServer.Services.Apps;
|
||||
|
||||
namespace BTCPayServer.Components.AppSales;
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
@using BTCPayServer.Plugins.Crowdfund
|
||||
@model BTCPayServer.Components.AppSales.AppSalesViewModel
|
||||
@{
|
||||
var label = Model.AppType == CrowdfundApp.AppType ? "Contributions" : "Sales";
|
||||
var label = Model.AppType == CrowdfundAppType.AppType ? "Contributions" : "Sales";
|
||||
}
|
||||
|
||||
<div id="AppSales-@Model.Id" class="widget app-sales">
|
||||
|
|
|
@ -7,6 +7,8 @@ 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;
|
||||
|
||||
namespace BTCPayServer.Components.AppTopItems;
|
||||
|
||||
|
@ -19,8 +21,12 @@ public class AppTopItems : ViewComponent
|
|||
_appService = appService;
|
||||
}
|
||||
|
||||
public async Task<IViewComponentResult> InvokeAsync(string appId, string appType = null)
|
||||
public async Task<IViewComponentResult> InvokeAsync(string appId, string appType)
|
||||
{
|
||||
var type = _appService.GetAppType(appType);
|
||||
if (type is not IHasItemStatsAppType salesAppType || type is not AppBaseType appBaseType)
|
||||
return new HtmlContentViewComponentResult(new StringHtmlContent(string.Empty));
|
||||
|
||||
var vm = new AppTopItemsViewModel
|
||||
{
|
||||
Id = appId,
|
||||
|
@ -36,7 +42,8 @@ public class AppTopItems : ViewComponent
|
|||
vm.SalesCount = entries.Select(e => e.SalesCount).ToList();
|
||||
vm.Entries = entries.ToList();
|
||||
vm.AppType = app.AppType;
|
||||
vm.AppUrl = await _appService.ConfigureLink(app, app.AppType);
|
||||
vm.AppUrl = await appBaseType.ConfigureLink(app);
|
||||
vm.Name = app.Name;
|
||||
|
||||
return View(vm);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
using System.Collections.Generic;
|
||||
using BTCPayServer.Data;
|
||||
using BTCPayServer.Services.Apps;
|
||||
|
||||
namespace BTCPayServer.Components.AppTopItems;
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
@using BTCPayServer.Plugins.Crowdfund
|
||||
@model BTCPayServer.Components.AppTopItems.AppTopItemsViewModel
|
||||
@{
|
||||
var label = Model.AppType == CrowdfundApp.AppType ? "contribution" : "sale";
|
||||
var label = Model.AppType == CrowdfundAppType.AppType ? "contribution" : "sale";
|
||||
}
|
||||
|
||||
<div id="AppTopItems-@Model.Id" class="widget app-top-items">
|
||||
<header class="mb-3">
|
||||
<h3>Top @(Model.AppType == CrowdfundApp.AppType ? "Perks" : "Items")</h3>
|
||||
<h3>Top @(Model.AppType == CrowdfundAppType.AppType ? "Perks" : "Items")</h3>
|
||||
@if (!string.IsNullOrEmpty(Model.AppUrl))
|
||||
{
|
||||
<a href="@Model.AppUrl">View All</a>
|
||||
|
|
|
@ -66,7 +66,7 @@ namespace BTCPayServer.Controllers.Greenfield
|
|||
{
|
||||
StoreDataId = storeId,
|
||||
Name = request.AppName,
|
||||
AppType = CrowdfundApp.AppType
|
||||
AppType = CrowdfundAppType.AppType
|
||||
};
|
||||
|
||||
appData.SetSettings(ToCrowdfundSettings(request));
|
||||
|
@ -97,7 +97,7 @@ namespace BTCPayServer.Controllers.Greenfield
|
|||
{
|
||||
StoreDataId = storeId,
|
||||
Name = request.AppName,
|
||||
AppType = PointOfSaleApp.AppType
|
||||
AppType = PointOfSaleAppType.AppType
|
||||
};
|
||||
|
||||
appData.SetSettings(ToPointOfSaleSettings(request));
|
||||
|
@ -111,7 +111,7 @@ namespace BTCPayServer.Controllers.Greenfield
|
|||
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Greenfield)]
|
||||
public async Task<IActionResult> UpdatePointOfSaleApp(string appId, CreatePointOfSaleAppRequest request)
|
||||
{
|
||||
var app = await _appService.GetApp(appId, PointOfSaleApp.AppType);
|
||||
var app = await _appService.GetApp(appId, PointOfSaleAppType.AppType);
|
||||
if (app == null)
|
||||
{
|
||||
return AppNotFound();
|
||||
|
@ -184,7 +184,7 @@ namespace BTCPayServer.Controllers.Greenfield
|
|||
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Greenfield)]
|
||||
public async Task<IActionResult> GetPosApp(string appId)
|
||||
{
|
||||
var app = await _appService.GetApp(appId, PointOfSaleApp.AppType);
|
||||
var app = await _appService.GetApp(appId, PointOfSaleAppType.AppType);
|
||||
if (app == null)
|
||||
{
|
||||
return AppNotFound();
|
||||
|
@ -197,7 +197,7 @@ namespace BTCPayServer.Controllers.Greenfield
|
|||
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Greenfield)]
|
||||
public async Task<IActionResult> GetCrowdfundApp(string appId)
|
||||
{
|
||||
var app = await _appService.GetApp(appId, CrowdfundApp.AppType);
|
||||
var app = await _appService.GetApp(appId, CrowdfundAppType.AppType);
|
||||
if (app == null)
|
||||
{
|
||||
return AppNotFound();
|
||||
|
@ -245,7 +245,7 @@ namespace BTCPayServer.Controllers.Greenfield
|
|||
EmbeddedCSS = request.EmbeddedCSS?.Trim(),
|
||||
NotificationUrl = request.NotificationUrl?.Trim(),
|
||||
Tagline = request.Tagline?.Trim(),
|
||||
PerksTemplate = request.PerksTemplate != null ? _appService.SerializeTemplate(_appService.Parse(request.PerksTemplate?.Trim(), request.TargetCurrency)) : null,
|
||||
PerksTemplate = request.PerksTemplate is not null ? _appService.SerializeTemplate(_appService.Parse(request.PerksTemplate.Trim(), request.TargetCurrency!)) : null,
|
||||
// If Disqus shortname is not null or empty we assume that Disqus should be enabled
|
||||
DisqusEnabled = !string.IsNullOrEmpty(request.DisqusShortname?.Trim()),
|
||||
DisqusShortname = request.DisqusShortname?.Trim(),
|
||||
|
@ -363,7 +363,8 @@ namespace BTCPayServer.Controllers.Greenfield
|
|||
{
|
||||
try
|
||||
{
|
||||
_appService.SerializeTemplate(_appService.Parse(request.Template, request.Currency));
|
||||
// Just checking if we can serialize, we don't care about the currency
|
||||
_appService.SerializeTemplate(_appService.Parse(request.Template, "USD"));
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
@ -452,7 +453,8 @@ namespace BTCPayServer.Controllers.Greenfield
|
|||
|
||||
try
|
||||
{
|
||||
_appService.SerializeTemplate(_appService.Parse(request.PerksTemplate, request.TargetCurrency));
|
||||
// Just checking if we can serialize, we don't care about the currency
|
||||
_appService.SerializeTemplate(_appService.Parse(request.PerksTemplate, "USD"));
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
|
|
@ -21,7 +21,7 @@ namespace BTCPayServer.Controllers
|
|||
|
||||
app.StoreData = GetCurrentStore();
|
||||
|
||||
return ViewComponent("AppTopItems", new { appId = app.Id });
|
||||
return ViewComponent("AppTopItems", new { appId = app.Id, appType = app.AppType });
|
||||
}
|
||||
|
||||
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
|
||||
|
@ -33,7 +33,7 @@ namespace BTCPayServer.Controllers
|
|||
return NotFound();
|
||||
|
||||
app.StoreData = GetCurrentStore();
|
||||
return ViewComponent("AppSales", new { appId = app.Id });
|
||||
return ViewComponent("AppSales", new { appId = app.Id, appType = app.AppType });
|
||||
}
|
||||
|
||||
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
|
||||
|
|
|
@ -124,8 +124,8 @@ namespace BTCPayServer.Controllers
|
|||
{
|
||||
var store = GetCurrentStore();
|
||||
vm.StoreId = store.Id;
|
||||
var types = _appService.GetAvailableAppTypes();
|
||||
if (!types.ContainsKey(vm.SelectedAppType))
|
||||
var type = _appService.GetAppType(vm.SelectedAppType);
|
||||
if (type is null)
|
||||
ModelState.AddModelError(nameof(vm.SelectedAppType), "Invalid App Type");
|
||||
|
||||
if (!ModelState.IsValid)
|
||||
|
@ -147,7 +147,8 @@ namespace BTCPayServer.Controllers
|
|||
TempData[WellKnownTempData.SuccessMessage] = "App successfully created";
|
||||
CreatedAppId = appData.Id;
|
||||
|
||||
var url = await _appService.ConfigureLink(appData, vm.SelectedAppType);
|
||||
|
||||
var url = await type.ConfigureLink(appData);
|
||||
return Redirect(url);
|
||||
}
|
||||
|
||||
|
|
|
@ -256,12 +256,12 @@ namespace BTCPayServer
|
|||
PointOfSaleSettings posS = null;
|
||||
switch (app.AppType)
|
||||
{
|
||||
case CrowdfundApp.AppType:
|
||||
case CrowdfundAppType.AppType:
|
||||
var cfS = app.GetSettings<CrowdfundSettings>();
|
||||
currencyCode = cfS.TargetCurrency;
|
||||
items = _appService.Parse(cfS.PerksTemplate, cfS.TargetCurrency);
|
||||
break;
|
||||
case PointOfSaleApp.AppType:
|
||||
case PointOfSaleAppType.AppType:
|
||||
posS = app.GetSettings<PointOfSaleSettings>();
|
||||
currencyCode = posS.Currency;
|
||||
items = _appService.Parse(posS.Template, posS.Currency);
|
||||
|
@ -287,7 +287,7 @@ namespace BTCPayServer
|
|||
return NotFound();
|
||||
}
|
||||
}
|
||||
else if (app.AppType == PointOfSaleApp.AppType && posS?.ShowCustomAmount is not true)
|
||||
else if (app.AppType == PointOfSaleAppType.AppType && posS?.ShowCustomAmount is not true)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
@ -400,7 +400,7 @@ namespace BTCPayServer
|
|||
|
||||
var redirectUrl = app?.AppType switch
|
||||
{
|
||||
PointOfSaleApp.AppType => app.GetSettings<PointOfSaleSettings>().RedirectUrl ??
|
||||
PointOfSaleAppType.AppType => app.GetSettings<PointOfSaleSettings>().RedirectUrl ??
|
||||
HttpContext.Request.GetAbsoluteUri($"/apps/{app.Id}/pos"),
|
||||
_ => null
|
||||
};
|
||||
|
|
|
@ -42,6 +42,8 @@ namespace BTCPayServer.Controllers
|
|||
return View(vm);
|
||||
|
||||
var userId = GetUserId();
|
||||
if (userId is null)
|
||||
return NotFound();
|
||||
var apps = await _appService.GetAllApps(userId, false, store.Id);
|
||||
foreach (var app in apps)
|
||||
{
|
||||
|
|
|
@ -37,11 +37,11 @@ namespace BTCPayServer.HostedServices
|
|||
{
|
||||
switch (data.AppType)
|
||||
{
|
||||
case PointOfSaleApp.AppType:
|
||||
case PointOfSaleAppType.AppType:
|
||||
var possettings = data.GetSettings<PointOfSaleSettings>();
|
||||
return (Data: data, Settings: (object)possettings,
|
||||
Items: _appService.Parse(possettings.Template, possettings.Currency));
|
||||
case CrowdfundApp.AppType:
|
||||
case CrowdfundAppType.AppType:
|
||||
var cfsettings = data.GetSettings<CrowdfundSettings>();
|
||||
return (Data: data, Settings: (object)cfsettings,
|
||||
Items: _appService.Parse(cfsettings.PerksTemplate, cfsettings.TargetCurrency));
|
||||
|
@ -68,11 +68,11 @@ namespace BTCPayServer.HostedServices
|
|||
|
||||
switch (valueTuple.Data.AppType)
|
||||
{
|
||||
case PointOfSaleApp.AppType:
|
||||
case PointOfSaleAppType.AppType:
|
||||
((PointOfSaleSettings)valueTuple.Settings).Template =
|
||||
_appService.SerializeTemplate(valueTuple.Items);
|
||||
break;
|
||||
case CrowdfundApp.AppType:
|
||||
case CrowdfundAppType.AppType:
|
||||
((CrowdfundSettings)valueTuple.Settings).PerksTemplate =
|
||||
_appService.SerializeTemplate(valueTuple.Items);
|
||||
break;
|
||||
|
|
|
@ -470,7 +470,7 @@ WHERE cte.""Id""=p.""Id""
|
|||
string newTemplate;
|
||||
switch (app.AppType)
|
||||
{
|
||||
case CrowdfundApp.AppType:
|
||||
case CrowdfundAppType.AppType:
|
||||
var settings1 = app.GetSettings<CrowdfundSettings>();
|
||||
if (string.IsNullOrEmpty(settings1.TargetCurrency))
|
||||
{
|
||||
|
@ -486,7 +486,7 @@ WHERE cte.""Id""=p.""Id""
|
|||
};
|
||||
break;
|
||||
|
||||
case PointOfSaleApp.AppType:
|
||||
case PointOfSaleAppType.AppType:
|
||||
|
||||
var settings2 = app.GetSettings<PointOfSaleSettings>();
|
||||
if (string.IsNullOrEmpty(settings2.Currency))
|
||||
|
|
|
@ -33,7 +33,7 @@ namespace BTCPayServer.Models.AppViewModels
|
|||
|
||||
private void SetApps(AppService appService)
|
||||
{
|
||||
var defaultAppType = PointOfSaleApp.AppType;
|
||||
var defaultAppType = PointOfSaleAppType.AppType;
|
||||
var choices = appService.GetAvailableAppTypes().Select(pair =>
|
||||
new SelectListItem(pair.Value, pair.Key, pair.Key == defaultAppType));
|
||||
|
||||
|
|
|
@ -36,7 +36,7 @@ namespace BTCPayServer.Plugins.Crowdfund.Controllers
|
|||
StoreRepository storeRepository,
|
||||
UIInvoiceController invoiceController,
|
||||
UserManager<ApplicationUser> userManager,
|
||||
CrowdfundApp app)
|
||||
CrowdfundAppType app)
|
||||
{
|
||||
_currencies = currencies;
|
||||
_appService = appService;
|
||||
|
@ -53,21 +53,21 @@ namespace BTCPayServer.Plugins.Crowdfund.Controllers
|
|||
private readonly AppService _appService;
|
||||
private readonly UIInvoiceController _invoiceController;
|
||||
private readonly UserManager<ApplicationUser> _userManager;
|
||||
private readonly CrowdfundApp _app;
|
||||
private readonly CrowdfundAppType _app;
|
||||
|
||||
[HttpGet("/")]
|
||||
[HttpGet("/apps/{appId}/crowdfund")]
|
||||
[XFrameOptions(XFrameOptionsAttribute.XFrameOptions.Unset)]
|
||||
[DomainMappingConstraint(CrowdfundApp.AppType)]
|
||||
[DomainMappingConstraint(CrowdfundAppType.AppType)]
|
||||
public async Task<IActionResult> ViewCrowdfund(string appId)
|
||||
{
|
||||
var app = await _appService.GetApp(appId, CrowdfundApp.AppType, true);
|
||||
var app = await _appService.GetApp(appId, CrowdfundAppType.AppType, true);
|
||||
|
||||
if (app == null)
|
||||
return NotFound();
|
||||
var settings = app.GetSettings<CrowdfundSettings>();
|
||||
|
||||
var isAdmin = await _appService.GetAppDataIfOwner(GetUserId(), appId, CrowdfundApp.AppType) != null;
|
||||
var isAdmin = await _appService.GetAppDataIfOwner(GetUserId(), appId, CrowdfundAppType.AppType) != null;
|
||||
|
||||
var hasEnoughSettingsToLoad = !string.IsNullOrEmpty(settings.TargetCurrency);
|
||||
if (!hasEnoughSettingsToLoad)
|
||||
|
@ -92,17 +92,17 @@ namespace BTCPayServer.Plugins.Crowdfund.Controllers
|
|||
[XFrameOptions(XFrameOptionsAttribute.XFrameOptions.Unset)]
|
||||
[IgnoreAntiforgeryToken]
|
||||
[EnableCors(CorsPolicies.All)]
|
||||
[DomainMappingConstraint(CrowdfundApp.AppType)]
|
||||
[DomainMappingConstraint(CrowdfundAppType.AppType)]
|
||||
[RateLimitsFilter(ZoneLimits.PublicInvoices, Scope = RateLimitsScope.RemoteAddress)]
|
||||
public async Task<IActionResult> ContributeToCrowdfund(string appId, ContributeToCrowdfund request, CancellationToken cancellationToken)
|
||||
{
|
||||
var app = await _appService.GetApp(appId, CrowdfundApp.AppType, true);
|
||||
var app = await _appService.GetApp(appId, CrowdfundAppType.AppType, true);
|
||||
|
||||
if (app == null)
|
||||
return NotFound();
|
||||
var settings = app.GetSettings<CrowdfundSettings>();
|
||||
|
||||
var isAdmin = await _appService.GetAppDataIfOwner(GetUserId(), appId, CrowdfundApp.AppType) != null;
|
||||
var isAdmin = await _appService.GetAppDataIfOwner(GetUserId(), appId, CrowdfundAppType.AppType) != null;
|
||||
|
||||
if (!settings.Enabled && !isAdmin)
|
||||
{
|
||||
|
@ -398,7 +398,7 @@ namespace BTCPayServer.Plugins.Crowdfund.Controllers
|
|||
|
||||
private async Task<ViewCrowdfundViewModel> GetAppInfo(string appId)
|
||||
{
|
||||
var app = await _appService.GetApp(appId, CrowdfundApp.AppType, true);
|
||||
var app = await _appService.GetApp(appId, CrowdfundAppType.AppType, true);
|
||||
if (app is null)
|
||||
{
|
||||
return null;
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
#nullable enable
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
@ -9,6 +10,7 @@ using BTCPayServer.Configuration;
|
|||
using BTCPayServer.Data;
|
||||
using BTCPayServer.Plugins.Crowdfund.Controllers;
|
||||
using BTCPayServer.Plugins.Crowdfund.Models;
|
||||
using BTCPayServer.Plugins.PointOfSale;
|
||||
using BTCPayServer.Services;
|
||||
using BTCPayServer.Services.Apps;
|
||||
using BTCPayServer.Services.Invoices;
|
||||
|
@ -29,14 +31,14 @@ namespace BTCPayServer.Plugins.Crowdfund
|
|||
public override void Execute(IServiceCollection services)
|
||||
{
|
||||
services.AddSingleton<IUIExtension>(new UIExtension("Crowdfund/NavExtension", "apps-nav"));
|
||||
services.AddSingleton<CrowdfundApp>();
|
||||
services.AddSingleton<IApp>(provider => provider.GetRequiredService<CrowdfundApp>());
|
||||
services.AddSingleton<CrowdfundAppType>();
|
||||
services.AddSingleton<AppBaseType, CrowdfundAppType>();
|
||||
|
||||
base.Execute(services);
|
||||
}
|
||||
}
|
||||
|
||||
public class CrowdfundApp: IApp
|
||||
public class CrowdfundAppType: AppBaseType, IHasSaleStatsAppType, IHasItemStatsAppType
|
||||
{
|
||||
private readonly LinkGenerator _linkGenerator;
|
||||
private readonly IOptions<BTCPayServerOptions> _options;
|
||||
|
@ -45,12 +47,8 @@ namespace BTCPayServer.Plugins.Crowdfund
|
|||
private readonly HtmlSanitizer _htmlSanitizer;
|
||||
private readonly InvoiceRepository _invoiceRepository;
|
||||
public const string AppType = "Crowdfund";
|
||||
public string Description => AppType;
|
||||
public string Type => AppType;
|
||||
public bool SupportsSalesStats => true;
|
||||
public bool SupportsItemStats => true;
|
||||
|
||||
public CrowdfundApp(
|
||||
public CrowdfundAppType(
|
||||
LinkGenerator linkGenerator,
|
||||
IOptions<BTCPayServerOptions> options,
|
||||
InvoiceRepository invoiceRepository,
|
||||
|
@ -58,6 +56,7 @@ namespace BTCPayServer.Plugins.Crowdfund
|
|||
CurrencyNameTable currencyNameTable,
|
||||
HtmlSanitizer htmlSanitizer)
|
||||
{
|
||||
Description = Type = AppType;
|
||||
_linkGenerator = linkGenerator;
|
||||
_options = options;
|
||||
_displayFormatter = displayFormatter;
|
||||
|
@ -66,10 +65,10 @@ namespace BTCPayServer.Plugins.Crowdfund
|
|||
_invoiceRepository = invoiceRepository;
|
||||
}
|
||||
|
||||
public Task<string> ConfigureLink(AppData app)
|
||||
public override Task<string> ConfigureLink(AppData app)
|
||||
{
|
||||
return Task.FromResult(_linkGenerator.GetPathByAction(nameof(UICrowdfundController.UpdateCrowdfund),
|
||||
"UICrowdfund", new { appId = app.Id }, _options.Value.RootPath));
|
||||
"UICrowdfund", new { appId = app.Id }, _options.Value.RootPath)!);
|
||||
}
|
||||
|
||||
public Task<SalesStats> GetSalesStats(AppData app, InvoiceEntity[] paidInvoices, int numberOfDays)
|
||||
|
@ -114,14 +113,14 @@ namespace BTCPayServer.Plugins.Crowdfund
|
|||
|
||||
return Task.FromResult<IEnumerable<ItemStats>>(perkCount);
|
||||
}
|
||||
|
||||
public async Task<object> GetInfo(AppData appData)
|
||||
|
||||
public override async Task<object?> GetInfo(AppData appData)
|
||||
{
|
||||
var settings = appData.GetSettings<CrowdfundSettings>();
|
||||
var resetEvery = settings.StartDate.HasValue ? settings.ResetEvery : CrowdfundResetEvery.Never;
|
||||
DateTime? lastResetDate = null;
|
||||
DateTime? nextResetDate = null;
|
||||
if (resetEvery != CrowdfundResetEvery.Never)
|
||||
if (resetEvery != CrowdfundResetEvery.Never && settings.StartDate is not null)
|
||||
{
|
||||
lastResetDate = settings.StartDate.Value;
|
||||
|
||||
|
@ -187,7 +186,7 @@ namespace BTCPayServer.Plugins.Crowdfund
|
|||
.ToList();
|
||||
var remainingPerks = perks.Where(item => !newPerksOrder.Contains(item));
|
||||
newPerksOrder.AddRange(remainingPerks);
|
||||
perks = newPerksOrder.ToArray();
|
||||
perks = newPerksOrder.ToArray()!;
|
||||
}
|
||||
|
||||
var store = appData.StoreData;
|
||||
|
@ -247,17 +246,17 @@ namespace BTCPayServer.Plugins.Crowdfund
|
|||
};
|
||||
}
|
||||
|
||||
public Task SetDefaultSettings(AppData appData, string defaultCurrency)
|
||||
public override Task SetDefaultSettings(AppData appData, string defaultCurrency)
|
||||
{
|
||||
var emptyCrowdfund = new CrowdfundSettings { TargetCurrency = defaultCurrency };
|
||||
appData.SetSettings(emptyCrowdfund);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task<string> ViewLink(AppData app)
|
||||
public override Task<string> ViewLink(AppData app)
|
||||
{
|
||||
return Task.FromResult(_linkGenerator.GetPathByAction(nameof(UICrowdfundController.ViewCrowdfund),
|
||||
"UICrowdfund", new {appId = app.Id}, _options.Value.RootPath));
|
||||
"UICrowdfund", new {appId = app.Id}, _options.Value.RootPath)!);
|
||||
}
|
||||
|
||||
private static bool IsPaid(InvoiceEntity entity)
|
||||
|
|
|
@ -64,11 +64,11 @@ namespace BTCPayServer.Plugins.PointOfSale.Controllers
|
|||
[HttpGet("/")]
|
||||
[HttpGet("/apps/{appId}/pos")]
|
||||
[HttpGet("/apps/{appId}/pos/{viewType?}")]
|
||||
[DomainMappingConstraint(PointOfSaleApp.AppType)]
|
||||
[DomainMappingConstraint(PointOfSaleAppType.AppType)]
|
||||
[XFrameOptions(XFrameOptionsAttribute.XFrameOptions.Unset)]
|
||||
public async Task<IActionResult> ViewPointOfSale(string appId, PosViewType? viewType = null)
|
||||
{
|
||||
var app = await _appService.GetApp(appId, PointOfSaleApp.AppType);
|
||||
var app = await _appService.GetApp(appId, PointOfSaleAppType.AppType);
|
||||
if (app == null)
|
||||
return NotFound();
|
||||
var settings = app.GetSettings<PointOfSaleSettings>();
|
||||
|
@ -121,7 +121,7 @@ namespace BTCPayServer.Plugins.PointOfSale.Controllers
|
|||
[HttpPost("/apps/{appId}/pos/{viewType?}")]
|
||||
[IgnoreAntiforgeryToken]
|
||||
[EnableCors(CorsPolicies.All)]
|
||||
[DomainMappingConstraint(PointOfSaleApp.AppType)]
|
||||
[DomainMappingConstraint(PointOfSaleAppType.AppType)]
|
||||
[RateLimitsFilter(ZoneLimits.PublicInvoices, Scope = RateLimitsScope.RemoteAddress)]
|
||||
[XFrameOptions(XFrameOptionsAttribute.XFrameOptions.Unset)]
|
||||
public async Task<IActionResult> ViewPointOfSale(string appId,
|
||||
|
@ -137,7 +137,7 @@ namespace BTCPayServer.Plugins.PointOfSale.Controllers
|
|||
RequiresRefundEmail requiresRefundEmail = RequiresRefundEmail.InheritFromStore,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
var app = await _appService.GetApp(appId, PointOfSaleApp.AppType);
|
||||
var app = await _appService.GetApp(appId, PointOfSaleAppType.AppType);
|
||||
if (string.IsNullOrEmpty(choiceKey) && amount <= 0)
|
||||
{
|
||||
return RedirectToAction(nameof(ViewPointOfSale), new { appId });
|
||||
|
@ -334,7 +334,7 @@ namespace BTCPayServer.Plugins.PointOfSale.Controllers
|
|||
[XFrameOptions(XFrameOptionsAttribute.XFrameOptions.Unset)]
|
||||
public async Task<IActionResult> POSForm(string appId, PosViewType? viewType = null)
|
||||
{
|
||||
var app = await _appService.GetApp(appId, PointOfSaleApp.AppType);
|
||||
var app = await _appService.GetApp(appId, PointOfSaleAppType.AppType);
|
||||
if (app == null)
|
||||
return NotFound();
|
||||
|
||||
|
@ -380,7 +380,7 @@ namespace BTCPayServer.Plugins.PointOfSale.Controllers
|
|||
[XFrameOptions(XFrameOptionsAttribute.XFrameOptions.Unset)]
|
||||
public async Task<IActionResult> POSFormSubmit(string appId, FormViewModel viewModel, PosViewType? viewType = null)
|
||||
{
|
||||
var app = await _appService.GetApp(appId, PointOfSaleApp.AppType);
|
||||
var app = await _appService.GetApp(appId, PointOfSaleAppType.AppType);
|
||||
if (app == null)
|
||||
return NotFound();
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
#nullable enable
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
@ -28,7 +29,7 @@ namespace BTCPayServer.Plugins.PointOfSale
|
|||
public override void Execute(IServiceCollection services)
|
||||
{
|
||||
services.AddSingleton<IUIExtension>(new UIExtension("PointOfSale/NavExtension", "apps-nav"));
|
||||
services.AddSingleton<IApp,PointOfSaleApp>();
|
||||
services.AddSingleton<AppBaseType, PointOfSaleAppType>();
|
||||
base.Execute(services);
|
||||
}
|
||||
}
|
||||
|
@ -45,34 +46,37 @@ namespace BTCPayServer.Plugins.PointOfSale
|
|||
Print
|
||||
}
|
||||
|
||||
public class PointOfSaleApp: IApp
|
||||
public class PointOfSaleAppType: AppBaseType, IHasSaleStatsAppType, IHasItemStatsAppType
|
||||
{
|
||||
private readonly LinkGenerator _linkGenerator;
|
||||
private readonly IOptions<BTCPayServerOptions> _btcPayServerOptions;
|
||||
private readonly DisplayFormatter _displayFormatter;
|
||||
private readonly HtmlSanitizer _htmlSanitizer;
|
||||
public const string AppType = "PointOfSale";
|
||||
public string Description => "Point of Sale";
|
||||
public string Type => AppType;
|
||||
public bool SupportsSalesStats => true;
|
||||
public bool SupportsItemStats => true;
|
||||
|
||||
public PointOfSaleApp(
|
||||
public PointOfSaleAppType(
|
||||
LinkGenerator linkGenerator,
|
||||
IOptions<BTCPayServerOptions> btcPayServerOptions,
|
||||
DisplayFormatter displayFormatter,
|
||||
HtmlSanitizer htmlSanitizer)
|
||||
{
|
||||
Type = AppType;
|
||||
Description = "Point of Sale";
|
||||
_linkGenerator = linkGenerator;
|
||||
_btcPayServerOptions = btcPayServerOptions;
|
||||
_displayFormatter = displayFormatter;
|
||||
_htmlSanitizer = htmlSanitizer;
|
||||
}
|
||||
|
||||
public Task<string> ConfigureLink(AppData app)
|
||||
public override Task<string> ConfigureLink(AppData app)
|
||||
{
|
||||
return Task.FromResult(_linkGenerator.GetPathByAction(nameof(UIPointOfSaleController.UpdatePointOfSale),
|
||||
"UIPointOfSale", new { appId = app.Id }, _btcPayServerOptions.Value.RootPath));
|
||||
"UIPointOfSale", new { appId = app.Id }, _btcPayServerOptions.Value.RootPath)!);
|
||||
}
|
||||
|
||||
public override Task<object?> GetInfo(AppData appData)
|
||||
{
|
||||
return Task.FromResult<object?>(null);
|
||||
}
|
||||
|
||||
public Task<SalesStats> GetSalesStats(AppData app, InvoiceEntity[] paidInvoices, int numberOfDays)
|
||||
|
@ -114,22 +118,17 @@ namespace BTCPayServer.Plugins.PointOfSale
|
|||
return Task.FromResult<IEnumerable<ItemStats>>(itemCount);
|
||||
}
|
||||
|
||||
public Task<object> GetInfo(AppData appData)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task SetDefaultSettings(AppData appData, string defaultCurrency)
|
||||
public override Task SetDefaultSettings(AppData appData, string defaultCurrency)
|
||||
{
|
||||
var empty = new PointOfSaleSettings { Currency = defaultCurrency };
|
||||
appData.SetSettings(empty);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task<string> ViewLink(AppData app)
|
||||
public override Task<string> ViewLink(AppData app)
|
||||
{
|
||||
return Task.FromResult(_linkGenerator.GetPathByAction(nameof(UIPointOfSaleController.ViewPointOfSale),
|
||||
"UIPointOfSale", new { appId = app.Id }, _btcPayServerOptions.Value.RootPath));
|
||||
"UIPointOfSale", new { appId = app.Id }, _btcPayServerOptions.Value.RootPath)!);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@ namespace BTCPayServer.Services.Apps
|
|||
{
|
||||
public class AppService
|
||||
{
|
||||
private readonly IEnumerable<IApp> _apps;
|
||||
private readonly Dictionary<string, AppBaseType> _appTypes;
|
||||
readonly ApplicationDbContextFactory _ContextFactory;
|
||||
private readonly InvoiceRepository _InvoiceRepository;
|
||||
readonly CurrencyNameTable _Currencies;
|
||||
|
@ -40,7 +40,7 @@ namespace BTCPayServer.Services.Apps
|
|||
private readonly HtmlSanitizer _HtmlSanitizer;
|
||||
public CurrencyNameTable Currencies => _Currencies;
|
||||
public AppService(
|
||||
IEnumerable<IApp> apps,
|
||||
IEnumerable<AppBaseType> apps,
|
||||
ApplicationDbContextFactory contextFactory,
|
||||
InvoiceRepository invoiceRepository,
|
||||
CurrencyNameTable currencies,
|
||||
|
@ -48,7 +48,7 @@ namespace BTCPayServer.Services.Apps
|
|||
StoreRepository storeRepository,
|
||||
HtmlSanitizer htmlSanitizer)
|
||||
{
|
||||
_apps = apps;
|
||||
_appTypes = apps.ToDictionary(a => a.Type, a=> a);
|
||||
_ContextFactory = contextFactory;
|
||||
_InvoiceRepository = invoiceRepository;
|
||||
_Currencies = currencies;
|
||||
|
@ -56,40 +56,33 @@ namespace BTCPayServer.Services.Apps
|
|||
_HtmlSanitizer = htmlSanitizer;
|
||||
_displayFormatter = displayFormatter;
|
||||
}
|
||||
|
||||
#nullable enable
|
||||
public Dictionary<string, string> GetAvailableAppTypes()
|
||||
{
|
||||
return _apps.ToDictionary(app => app.Type, app => app.Description);
|
||||
}
|
||||
|
||||
public Task<string> ConfigureLink(AppData app, string vmSelectedAppType)
|
||||
{
|
||||
return GetAppForType(vmSelectedAppType).ConfigureLink(app);
|
||||
return _appTypes.ToDictionary(app => app.Key, app => app.Value.Description);
|
||||
}
|
||||
|
||||
private IApp GetAppForType(string appType)
|
||||
public AppBaseType? GetAppType(string appType)
|
||||
{
|
||||
return _apps.First(app => app.Type == appType);
|
||||
_appTypes.TryGetValue(appType, out var a);
|
||||
return a;
|
||||
}
|
||||
|
||||
public async Task<object> GetInfo(string appId)
|
||||
|
||||
public async Task<object?> GetInfo(string appId)
|
||||
{
|
||||
var appData = await GetApp(appId, null);
|
||||
if (appData is null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
var app = GetAppForType(appData.AppType);
|
||||
if (app is null)
|
||||
{
|
||||
var appType = GetAppType(appData.AppType);
|
||||
if (appType is null)
|
||||
return null;
|
||||
}
|
||||
|
||||
return app.GetInfo(appData);
|
||||
return appType.GetInfo(appData);
|
||||
}
|
||||
|
||||
|
||||
public async Task<IEnumerable<ItemStats>> GetItemStats(AppData appData)
|
||||
{
|
||||
if (GetAppType(appData.AppType) is not IHasItemStatsAppType salesType)
|
||||
throw new InvalidOperationException("This app isn't a SalesAppBaseType");
|
||||
var paidInvoices = await GetInvoicesForApp(_InvoiceRepository,appData,
|
||||
null, new []
|
||||
{
|
||||
|
@ -97,7 +90,7 @@ namespace BTCPayServer.Services.Apps
|
|||
InvoiceState.ToString(InvoiceStatusLegacy.Confirmed),
|
||||
InvoiceState.ToString(InvoiceStatusLegacy.Complete)
|
||||
});
|
||||
return await GetAppForType(appData.AppType).GetItemStats(appData, paidInvoices);
|
||||
return await salesType.GetItemStats(appData, paidInvoices);
|
||||
}
|
||||
|
||||
public static Task<SalesStats> GetSalesStatswithPOSItems(ViewPointOfSaleViewModel.Item[] items,
|
||||
|
@ -136,6 +129,8 @@ namespace BTCPayServer.Services.Apps
|
|||
|
||||
public async Task<SalesStats> GetSalesStats(AppData app, int numberOfDays = 7)
|
||||
{
|
||||
if (GetAppType(app.AppType) is not IHasSaleStatsAppType salesType)
|
||||
throw new InvalidOperationException("This app isn't a SalesAppBaseType");
|
||||
var paidInvoices = await GetInvoicesForApp(_InvoiceRepository, app, DateTimeOffset.UtcNow - TimeSpan.FromDays(numberOfDays),
|
||||
new []
|
||||
{
|
||||
|
@ -143,12 +138,13 @@ namespace BTCPayServer.Services.Apps
|
|||
InvoiceState.ToString(InvoiceStatusLegacy.Confirmed),
|
||||
InvoiceState.ToString(InvoiceStatusLegacy.Complete)
|
||||
});
|
||||
return await GetAppForType(app.AppType).GetSalesStats(app, paidInvoices, numberOfDays);
|
||||
|
||||
return await salesType.GetSalesStats(app, paidInvoices, numberOfDays);
|
||||
}
|
||||
|
||||
public class InvoiceStatsItem
|
||||
{
|
||||
public string ItemCode { get; set; }
|
||||
public string ItemCode { get; set; } = string.Empty;
|
||||
public decimal FiatPrice { get; set; }
|
||||
public DateTime Date { get; set; }
|
||||
}
|
||||
|
@ -204,8 +200,8 @@ namespace BTCPayServer.Services.Apps
|
|||
public static string GetAppOrderId(string appType, string appId) =>
|
||||
appType switch
|
||||
{
|
||||
CrowdfundApp.AppType => $"crowdfund-app_{appId}",
|
||||
PointOfSaleApp.AppType => $"pos-app_{appId}",
|
||||
CrowdfundAppType.AppType => $"crowdfund-app_{appId}",
|
||||
PointOfSaleAppType.AppType => $"pos-app_{appId}",
|
||||
_ => $"{appType}_{appId}"
|
||||
};
|
||||
|
||||
|
@ -215,7 +211,7 @@ namespace BTCPayServer.Services.Apps
|
|||
return invoice.GetInternalTags("APP#");
|
||||
}
|
||||
|
||||
public static async Task<InvoiceEntity[]> GetInvoicesForApp(InvoiceRepository invoiceRepository, AppData appData, DateTimeOffset? startDate = null, string[] status = null)
|
||||
public static async Task<InvoiceEntity[]> GetInvoicesForApp(InvoiceRepository invoiceRepository, AppData appData, DateTimeOffset? startDate = null, string[]? status = null)
|
||||
{
|
||||
var invoices = await invoiceRepository.GetInvoices(new InvoiceQuery
|
||||
{
|
||||
|
@ -252,7 +248,7 @@ namespace BTCPayServer.Services.Apps
|
|||
return await ctx.SaveChangesAsync() == 1;
|
||||
}
|
||||
|
||||
public async Task<ListAppsViewModel.ListAppViewModel[]> GetAllApps(string userId, bool allowNoUser = false, string storeId = null)
|
||||
public async Task<ListAppsViewModel.ListAppViewModel[]> GetAllApps(string? userId, bool allowNoUser = false, string? storeId = null)
|
||||
{
|
||||
await using var ctx = _ContextFactory.CreateContext();
|
||||
var listApps = await ctx.UserStore
|
||||
|
@ -294,7 +290,7 @@ namespace BTCPayServer.Services.Apps
|
|||
string style;
|
||||
switch (appType)
|
||||
{
|
||||
case PointOfSaleApp.AppType:
|
||||
case PointOfSaleAppType.AppType:
|
||||
var settings = app.GetSettings<PointOfSaleSettings>();
|
||||
string posViewStyle = (settings.EnableShoppingCart ? PosViewType.Cart : settings.DefaultView).ToString();
|
||||
style = typeof(PosViewType).DisplayName(posViewStyle);
|
||||
|
@ -328,7 +324,7 @@ namespace BTCPayServer.Services.Apps
|
|||
return await query.ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<AppData> GetApp(string appId, string appType, bool includeStore = false)
|
||||
public async Task<AppData?> GetApp(string appId, string? appType, bool includeStore = false)
|
||||
{
|
||||
await using var ctx = _ContextFactory.CreateContext();
|
||||
var query = ctx.Apps
|
||||
|
@ -342,7 +338,7 @@ namespace BTCPayServer.Services.Apps
|
|||
return await query.FirstOrDefaultAsync();
|
||||
}
|
||||
|
||||
public Task<StoreData> GetStore(AppData app)
|
||||
public Task<StoreData?> GetStore(AppData app)
|
||||
{
|
||||
return _storeRepository.FindStore(app.StoreDataId);
|
||||
}
|
||||
|
@ -354,7 +350,7 @@ namespace BTCPayServer.Services.Apps
|
|||
{
|
||||
var itemNode = new YamlMappingNode();
|
||||
itemNode.Add("title", new YamlScalarNode(item.Title));
|
||||
if (item.Price.Type != ViewPointOfSaleViewModel.Item.ItemPrice.ItemPriceType.Topup)
|
||||
if (item.Price.Type != ViewPointOfSaleViewModel.Item.ItemPrice.ItemPriceType.Topup && item.Price.Value is not null)
|
||||
itemNode.Add("price", new YamlScalarNode(item.Price.Value.ToStringInvariant()));
|
||||
if (!string.IsNullOrEmpty(item.Description))
|
||||
{
|
||||
|
@ -436,8 +432,11 @@ namespace BTCPayServer.Services.Apps
|
|||
case "false":
|
||||
case null:
|
||||
price.Type = ViewPointOfSaleViewModel.Item.ItemPrice.ItemPriceType.Fixed;
|
||||
price.Value = decimal.Parse(pValue.Value.Value, CultureInfo.InvariantCulture);
|
||||
price.Formatted = displayFormatter.Currency(price.Value.Value, currency, DisplayFormatter.CurrencyFormat.Symbol);
|
||||
if (pValue?.Value.Value is not null)
|
||||
{
|
||||
price.Value = decimal.Parse(pValue.Value.Value, CultureInfo.InvariantCulture);
|
||||
price.Formatted = displayFormatter.Currency(price.Value.Value, currency, DisplayFormatter.CurrencyFormat.Symbol);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -464,13 +463,13 @@ namespace BTCPayServer.Services.Apps
|
|||
{
|
||||
return Parse(htmlSanitizer, displayFormatter, template, currency).Where(c => !c.Disabled).ToArray();
|
||||
}
|
||||
|
||||
|
||||
#nullable restore
|
||||
private class PosHolder
|
||||
{
|
||||
private readonly HtmlSanitizer _htmlSanitizer;
|
||||
|
||||
public PosHolder(HtmlSanitizer htmlSanitizer)
|
||||
public PosHolder(
|
||||
HtmlSanitizer htmlSanitizer)
|
||||
{
|
||||
_htmlSanitizer = htmlSanitizer;
|
||||
}
|
||||
|
@ -506,8 +505,8 @@ namespace BTCPayServer.Services.Apps
|
|||
public string Key { get; set; }
|
||||
public YamlScalarNode Value { get; set; }
|
||||
}
|
||||
|
||||
public async Task<AppData> GetAppDataIfOwner(string userId, string appId, string type = null)
|
||||
#nullable enable
|
||||
public async Task<AppData?> GetAppDataIfOwner(string userId, string appId, string? type = null)
|
||||
{
|
||||
if (userId == null || appId == null)
|
||||
return null;
|
||||
|
@ -542,7 +541,7 @@ namespace BTCPayServer.Services.Apps
|
|||
await ctx.SaveChangesAsync();
|
||||
}
|
||||
|
||||
private static bool TryParseJson(string json, out JObject result)
|
||||
private static bool TryParseJson(string json, [MaybeNullWhen(false)] out JObject result)
|
||||
{
|
||||
result = null;
|
||||
try
|
||||
|
@ -584,7 +583,7 @@ namespace BTCPayServer.Services.Apps
|
|||
|
||||
public async Task SetDefaultSettings(AppData appData, string defaultCurrency)
|
||||
{
|
||||
var app = GetAppForType(appData.AppType);
|
||||
var app = GetAppType(appData.AppType);
|
||||
if (app is null)
|
||||
{
|
||||
appData.SetSettings(null);
|
||||
|
@ -597,19 +596,10 @@ namespace BTCPayServer.Services.Apps
|
|||
|
||||
public async Task<string?> ViewLink(AppData app)
|
||||
{
|
||||
var appType = GetAppForType(app.AppType);
|
||||
var appType = GetAppType(app.AppType);
|
||||
return await appType?.ViewLink(app)!;
|
||||
}
|
||||
#nullable restore
|
||||
public bool SupportsSalesStats(AppData app)
|
||||
{
|
||||
return GetAppForType(app.AppType).SupportsSalesStats;
|
||||
}
|
||||
|
||||
public bool SupportsItemStats(AppData app)
|
||||
{
|
||||
return GetAppForType(app.AppType).SupportsItemStats;
|
||||
}
|
||||
}
|
||||
|
||||
public class ItemStats
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
#nullable enable
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Threading.Tasks;
|
||||
|
@ -6,18 +7,22 @@ using BTCPayServer.Services.Invoices;
|
|||
|
||||
namespace BTCPayServer.Services.Apps
|
||||
{
|
||||
public interface IApp
|
||||
public abstract class AppBaseType
|
||||
{
|
||||
public string Description { get; set; } = string.Empty;
|
||||
public string Type { get; set; } = string.Empty;
|
||||
public abstract Task<object?> GetInfo(AppData appData);
|
||||
public abstract Task<string> ConfigureLink(AppData app);
|
||||
public abstract Task<string> ViewLink(AppData app);
|
||||
public abstract Task SetDefaultSettings(AppData appData, string defaultCurrency);
|
||||
}
|
||||
public interface IHasSaleStatsAppType
|
||||
{
|
||||
public string Description { get; }
|
||||
public string Type { get; }
|
||||
public bool SupportsSalesStats { get; }
|
||||
public bool SupportsItemStats { get; }
|
||||
Task<string> ConfigureLink(AppData app);
|
||||
Task<string> ViewLink(AppData app);
|
||||
Task SetDefaultSettings(AppData appData, string defaultCurrency);
|
||||
Task<SalesStats> GetSalesStats(AppData app, InvoiceEntity[] paidInvoices, int numberOfDays);
|
||||
}
|
||||
public interface IHasItemStatsAppType
|
||||
{
|
||||
Task<IEnumerable<ItemStats>> GetItemStats(AppData appData, InvoiceEntity[] invoiceEntities);
|
||||
Task<object> GetInfo(AppData appData);
|
||||
}
|
||||
|
||||
public enum RequiresRefundEmail
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
@{ var store = Context.GetStoreData(); }
|
||||
|
||||
@if (store != null && Model.AppType == CrowdfundApp.AppType)
|
||||
@if (store != null && Model.AppType == CrowdfundAppType.AppType)
|
||||
{
|
||||
<li class="nav-item" permission="@Policies.CanModifyStoreSettings">
|
||||
<a asp-area="" asp-controller="UICrowdfund" asp-action="UpdateCrowdfund" asp-route-appId="@Model.Id" class="nav-link @ViewData.IsActivePage(AppsNavPages.Update, Model.Id)" id="@($"StoreNav-App-{Model.Id}")">
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
@{ var store = Context.GetStoreData(); }
|
||||
|
||||
@if (store != null && Model.AppType == PointOfSaleApp.AppType)
|
||||
@if (store != null && Model.AppType == PointOfSaleAppType.AppType)
|
||||
{
|
||||
<li class="nav-item" permission="@Policies.CanModifyStoreSettings">
|
||||
<a asp-area="" asp-controller="UIPointOfSale" asp-action="UpdatePointOfSale" asp-route-appId="@Model.Id" class="nav-link @ViewData.IsActivePage(AppsNavPages.Update, Model.Id)" id="@($"StoreNav-App-{Model.Id}")">
|
||||
|
|
|
@ -97,7 +97,7 @@
|
|||
@if (!string.IsNullOrEmpty(viewStyle))
|
||||
{
|
||||
<span>-</span>
|
||||
@Safe.Raw(viewStyle)
|
||||
<span>@viewStyle</span>
|
||||
}
|
||||
</td>
|
||||
<td class="text-end">
|
||||
|
|
|
@ -119,14 +119,8 @@
|
|||
<vc:store-recent-invoices vm="@(new StoreRecentInvoicesViewModel { Store = store, CryptoCode = Model.CryptoCode, InitialRendering = true })"/>
|
||||
@foreach (var app in Model.Apps)
|
||||
{
|
||||
@if (AppService.SupportsSalesStats(app))
|
||||
{
|
||||
<vc:app-sales app-id="@app.Id" app-type="@app.AppType" />
|
||||
}
|
||||
@if (AppService.SupportsItemStats(app))
|
||||
{
|
||||
<vc:app-top-items app-id="@app.Id" app-type="@app.AppType" />
|
||||
}
|
||||
<vc:app-sales app-id="@app.Id" app-type="@app.AppType" />
|
||||
<vc:app-top-items app-id="@app.Id" app-type="@app.AppType" />
|
||||
}
|
||||
</div>
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue