mirror of
https://github.com/aljazceru/btcpayserver.git
synced 2025-12-17 22:14:26 +01:00
work on building the viewmodel for crowdfund
This commit is contained in:
@@ -8,13 +8,16 @@ using System.Threading.Tasks;
|
|||||||
using BTCPayServer.Data;
|
using BTCPayServer.Data;
|
||||||
using BTCPayServer.Filters;
|
using BTCPayServer.Filters;
|
||||||
using BTCPayServer.Models.AppViewModels;
|
using BTCPayServer.Models.AppViewModels;
|
||||||
|
using BTCPayServer.Rating;
|
||||||
using BTCPayServer.Security;
|
using BTCPayServer.Security;
|
||||||
using BTCPayServer.Services.Apps;
|
using BTCPayServer.Services.Apps;
|
||||||
|
using BTCPayServer.Services.Invoices;
|
||||||
using BTCPayServer.Services.Rates;
|
using BTCPayServer.Services.Rates;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Cors;
|
using Microsoft.AspNetCore.Cors;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using NBitpayClient;
|
||||||
using YamlDotNet.RepresentationModel;
|
using YamlDotNet.RepresentationModel;
|
||||||
using static BTCPayServer.Controllers.AppsController;
|
using static BTCPayServer.Controllers.AppsController;
|
||||||
|
|
||||||
@@ -22,14 +25,24 @@ namespace BTCPayServer.Controllers
|
|||||||
{
|
{
|
||||||
public class AppsPublicController : Controller
|
public class AppsPublicController : Controller
|
||||||
{
|
{
|
||||||
public AppsPublicController(AppsHelper appsHelper, InvoiceController invoiceController)
|
public AppsPublicController(AppsHelper appsHelper,
|
||||||
|
InvoiceController invoiceController,
|
||||||
|
RateFetcher rateFetcher,
|
||||||
|
BTCPayNetworkProvider btcPayNetworkProvider,
|
||||||
|
InvoiceRepository invoiceRepository)
|
||||||
{
|
{
|
||||||
_AppsHelper = appsHelper;
|
_AppsHelper = appsHelper;
|
||||||
_InvoiceController = invoiceController;
|
_InvoiceController = invoiceController;
|
||||||
|
_rateFetcher = rateFetcher;
|
||||||
|
_btcPayNetworkProvider = btcPayNetworkProvider;
|
||||||
|
_invoiceRepository = invoiceRepository;
|
||||||
}
|
}
|
||||||
|
|
||||||
private AppsHelper _AppsHelper;
|
private AppsHelper _AppsHelper;
|
||||||
private InvoiceController _InvoiceController;
|
private InvoiceController _InvoiceController;
|
||||||
|
private readonly RateFetcher _rateFetcher;
|
||||||
|
private readonly BTCPayNetworkProvider _btcPayNetworkProvider;
|
||||||
|
private readonly InvoiceRepository _invoiceRepository;
|
||||||
|
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
[Route("/apps/{appId}/pos")]
|
[Route("/apps/{appId}/pos")]
|
||||||
@@ -80,15 +93,40 @@ namespace BTCPayServer.Controllers
|
|||||||
return NotFound();
|
return NotFound();
|
||||||
var settings = app.GetSettings<CrowdfundSettings>();
|
var settings = app.GetSettings<CrowdfundSettings>();
|
||||||
var currency = _AppsHelper.GetCurrencyData(settings.TargetCurrency, false);
|
var currency = _AppsHelper.GetCurrencyData(settings.TargetCurrency, false);
|
||||||
double step = currency == null ? 1 : Math.Pow(10, -(currency.Divisibility));
|
|
||||||
|
return View(CrowdfundHelper.GetInfo(app, _invoiceRepository, _rateFetcher, _btcPayNetworkProvider ));
|
||||||
var numberFormatInfo = _AppsHelper.Currencies.GetNumberFormatInfo(currency.Code) ?? _AppsHelper.Currencies.GetNumberFormatInfo("USD");
|
|
||||||
return View(new ViewCrowdfundViewModel()
|
|
||||||
{
|
|
||||||
Title = settings.Title,
|
|
||||||
CustomCSSLink = settings.CustomCSSLink
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[HttpPost]
|
||||||
|
[Route("/apps/{appId}/crowdfund/contribute")]
|
||||||
|
[XFrameOptionsAttribute(null)]
|
||||||
|
[IgnoreAntiforgeryToken]
|
||||||
|
[EnableCors(CorsPolicies.All)]
|
||||||
|
public async Task<IActionResult> ContributeToCrowdfund(string appId,[FromBody]ContributeToCrowdfund request, [FromQuery]bool redirectToCheckout)
|
||||||
|
{
|
||||||
|
var app = await _AppsHelper.GetApp(appId, AppType.Crowdfund);
|
||||||
|
if (app == null)
|
||||||
|
return NotFound();
|
||||||
|
var settings = app.GetSettings<CrowdfundSettings>();
|
||||||
|
var currency = _AppsHelper.GetCurrencyData(settings.TargetCurrency, false);
|
||||||
|
var store = await _AppsHelper.GetStore(app);
|
||||||
|
var invoice = await _InvoiceController.CreateInvoiceCore(new Invoice()
|
||||||
|
{
|
||||||
|
|
||||||
|
}, store, HttpContext.Request.GetAbsoluteRoot());
|
||||||
|
if (redirectToCheckout)
|
||||||
|
{
|
||||||
|
return RedirectToAction(nameof(InvoiceController.Checkout), "Invoice", new { invoiceId = invoice.Data.Id });
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return Json(new
|
||||||
|
{
|
||||||
|
InvoiceId = invoice.Data.Id
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
[HttpPost]
|
[HttpPost]
|
||||||
[Route("/apps/{appId}/pos")]
|
[Route("/apps/{appId}/pos")]
|
||||||
@@ -152,6 +190,84 @@ namespace BTCPayServer.Controllers
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class CrowdfundHelper
|
||||||
|
{
|
||||||
|
private static async Task<decimal> GetCurrentContributionAmount(InvoiceEntity[] invoices, string primaryCurrency,
|
||||||
|
RateFetcher rateFetcher, RateRules rateRules)
|
||||||
|
{
|
||||||
|
decimal result = 0;
|
||||||
|
|
||||||
|
var groupingByCurrency = invoices.GroupBy(entity => entity.ProductInformation.Currency);
|
||||||
|
|
||||||
|
var ratesTask = rateFetcher.FetchRates(
|
||||||
|
groupingByCurrency
|
||||||
|
.Select((entities) => new CurrencyPair(entities.Key, primaryCurrency))
|
||||||
|
.ToHashSet(),
|
||||||
|
rateRules);
|
||||||
|
|
||||||
|
var finalTasks = new List<Task>();
|
||||||
|
foreach (var rateTask in ratesTask)
|
||||||
|
{
|
||||||
|
finalTasks.Add(rateTask.Value.ContinueWith(task =>
|
||||||
|
{
|
||||||
|
var rate = task.Result.BidAsk?.Bid;
|
||||||
|
if (rate == null) return;
|
||||||
|
var currencyGroup = groupingByCurrency.Single(entities => entities.Key == rateTask.Key.Left);
|
||||||
|
result += currencyGroup.Sum(entity => entity.ProductInformation.Price / rate.Value);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
await Task.WhenAll(finalTasks);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async Task<ViewCrowdfundViewModel> GetInfo(AppData appData, InvoiceRepository invoiceRepository,
|
||||||
|
RateFetcher rateFetcher, BTCPayNetworkProvider btcPayNetworkProvider)
|
||||||
|
{
|
||||||
|
var settings = appData.GetSettings<CrowdfundSettings>();
|
||||||
|
var invoices = await GetPaidInvoicesForApp(appData, invoiceRepository);
|
||||||
|
var rateRules = appData.StoreData.GetStoreBlob().GetRateRules(btcPayNetworkProvider);
|
||||||
|
var currentAmount = await GetCurrentContributionAmount(
|
||||||
|
invoices,
|
||||||
|
settings.TargetCurrency, rateFetcher, rateRules);
|
||||||
|
var paidInvoices = invoices.Length;
|
||||||
|
var active = (settings.StartDate == null || DateTime.UtcNow >= settings.StartDate) &&
|
||||||
|
(settings.EndDate == null || DateTime.UtcNow <= settings.EndDate) &&
|
||||||
|
(!settings.EnforceTargetAmount || settings.TargetAmount > currentAmount)
|
||||||
|
|
||||||
|
return new ViewCrowdfundViewModel()
|
||||||
|
{
|
||||||
|
Title = settings.Title,
|
||||||
|
Description = settings.Description,
|
||||||
|
CustomCSSLink = settings.CustomCSSLink,
|
||||||
|
StoreId = appData.StoreDataId,
|
||||||
|
AppId = appData.Id,
|
||||||
|
StartDate = settings.StartDate,
|
||||||
|
EndDate = settings.EndDate,
|
||||||
|
TargetAmount = settings.TargetAmount,
|
||||||
|
TargetCurrency = settings.TargetCurrency,
|
||||||
|
EnforceTargetAmount = settings.EnforceTargetAmount,
|
||||||
|
Info = new ViewCrowdfundViewModel.CrowdfundInfo()
|
||||||
|
{
|
||||||
|
TotalContributors = paidInvoices,
|
||||||
|
CurrentAmount = currentAmount,
|
||||||
|
Active = active
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static async Task<InvoiceEntity[]> GetPaidInvoicesForApp(AppData appData, InvoiceRepository invoiceRepository)
|
||||||
|
{
|
||||||
|
return await invoiceRepository.GetInvoices(new InvoiceQuery()
|
||||||
|
{
|
||||||
|
OrderId = appData.Id,
|
||||||
|
Status = new string[]{ InvoiceState.ToString(InvoiceStatus.Complete)}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public class AppsHelper
|
public class AppsHelper
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -15,11 +15,9 @@ namespace BTCPayServer.Models.AppViewModels
|
|||||||
[Required]
|
[Required]
|
||||||
public bool Enabled { get; set; }
|
public bool Enabled { get; set; }
|
||||||
|
|
||||||
|
|
||||||
public DateTime? StartDate { get; set; }
|
public DateTime? StartDate { get; set; }
|
||||||
public DateTime? EndDate { get; set; }
|
public DateTime? EndDate { get; set; }
|
||||||
|
|
||||||
|
|
||||||
[Required]
|
[Required]
|
||||||
[MaxLength(5)]
|
[MaxLength(5)]
|
||||||
[Display(Name = "The primary currency used for targets and stats")]
|
[Display(Name = "The primary currency used for targets and stats")]
|
||||||
|
|||||||
@@ -1,8 +1,39 @@
|
|||||||
namespace BTCPayServer.Models.AppViewModels
|
using System;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
|
||||||
|
namespace BTCPayServer.Models.AppViewModels
|
||||||
{
|
{
|
||||||
public class ViewCrowdfundViewModel
|
public class ViewCrowdfundViewModel
|
||||||
{
|
{
|
||||||
|
public string StatusMessage{ get; set; }
|
||||||
|
public string StoreId { get; set; }
|
||||||
|
public string AppId { get; set; }
|
||||||
public string Title { get; set; }
|
public string Title { get; set; }
|
||||||
|
public string Description { get; set; }
|
||||||
public string CustomCSSLink { get; set; }
|
public string CustomCSSLink { get; set; }
|
||||||
|
public DateTime? StartDate { get; set; }
|
||||||
|
public DateTime? EndDate { get; set; }
|
||||||
|
|
||||||
|
public string TargetCurrency { get; set; }
|
||||||
|
public decimal? TargetAmount { get; set; }
|
||||||
|
public bool EnforceTargetAmount { get; set; }
|
||||||
|
|
||||||
|
public CrowdfundInfo Info { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
public class CrowdfundInfo
|
||||||
|
{
|
||||||
|
public int TotalContributors { get; set; }
|
||||||
|
public decimal CurrentAmount { get; set; }
|
||||||
|
public bool Active { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public class ContributeToCrowdfund
|
||||||
|
{
|
||||||
|
[Required] public decimal Amount { get; set; }
|
||||||
|
public string Email { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
@model BTCPayServer.Models.AppViewModels.ContributeToCrowdfund
|
||||||
|
|
||||||
|
|
||||||
|
<form method="post" action="contribute">
|
||||||
|
<input asp-for="Email" type="email"/>
|
||||||
|
<input asp-for="Amount" type="number" step="any" />
|
||||||
|
<button type="submit">Contribute</button>
|
||||||
|
</form>
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
@model BTCPayServer.Models.AppViewModels.ViewCrowdfundViewModel
|
||||||
|
<div class="container d-flex h-100">
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-lg-12 text-center">
|
||||||
|
<partial name="_StatusMessage" for="@Model.StatusMessage"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<header>
|
||||||
|
<h1>@Model.Title</h1>
|
||||||
|
</header>
|
||||||
|
<main>
|
||||||
|
@Model.Description
|
||||||
|
<partial name="ContributeForm"/>
|
||||||
|
</main>
|
||||||
|
<footer></footer>
|
||||||
|
<pre> @Html.Raw(Model)</pre>
|
||||||
|
</div>
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
@addTagHelper *, Meziantou.AspNetCore.BundleTagHelpers
|
@addTagHelper *, Meziantou.AspNetCore.BundleTagHelpers
|
||||||
@inject BTCPayServer.HostedServices.CssThemeManager themeManager
|
@inject BTCPayServer.HostedServices.CssThemeManager themeManager
|
||||||
|
|
||||||
|
@using System.Security.AccessControl
|
||||||
@model BTCPayServer.Models.AppViewModels.ViewCrowdfundViewModel
|
@model BTCPayServer.Models.AppViewModels.ViewCrowdfundViewModel
|
||||||
@{
|
@{
|
||||||
ViewData["Title"] = Model.Title;
|
ViewData["Title"] = Model.Title;
|
||||||
@@ -11,18 +12,22 @@
|
|||||||
<html class="h-100">
|
<html class="h-100">
|
||||||
<head>
|
<head>
|
||||||
<title>@Model.Title</title>
|
<title>@Model.Title</title>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8"/>
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||||
<link href="@this.Context.Request.GetAbsoluteUri(themeManager.BootstrapUri)" rel="stylesheet" />
|
<link href="@this.Context.Request.GetAbsoluteUri(themeManager.BootstrapUri)" rel="stylesheet"/>
|
||||||
@if (Model.CustomCSSLink != null)
|
@if (Model.CustomCSSLink != null)
|
||||||
{
|
{
|
||||||
<link href="@Model.CustomCSSLink" rel="stylesheet" />
|
<link href="@Model.CustomCSSLink" rel="stylesheet"/>
|
||||||
}
|
}
|
||||||
<link href="~/vendor/font-awesome/css/font-awesome.min.css" rel="stylesheet" />
|
<link href="~/vendor/font-awesome/css/font-awesome.min.css" rel="stylesheet"/>
|
||||||
|
<bundle name="wwwroot/bundles/crowdfund-bundle.min.js"></bundle>
|
||||||
|
<script>
|
||||||
|
var srvModel = @Html.Raw(Model);
|
||||||
|
|
||||||
|
</script>
|
||||||
</head>
|
</head>
|
||||||
<body class="h-100">
|
<body class="h-100">
|
||||||
|
<partial name="MinimalCrowdfund" model="@Model"/>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -61,5 +61,13 @@
|
|||||||
"wwwroot/cart/js/cart.js",
|
"wwwroot/cart/js/cart.js",
|
||||||
"wwwroot/cart/js/cart.jquery.js"
|
"wwwroot/cart/js/cart.jquery.js"
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"outputFileName": "wwwroot/bundles/crowdfund-bundle.min.js",
|
||||||
|
"inputFiles": [
|
||||||
|
"wwwroot/vendor/jquery/jquery.js",
|
||||||
|
"wwwroot/vendor/bootstrap4/js/bootstrap.js",
|
||||||
|
"wwwroot/modal/btcpay.js"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
Reference in New Issue
Block a user