work on building the viewmodel for crowdfund

This commit is contained in:
Andrew Camilleri
2018-12-18 16:27:03 +01:00
parent b5d360594a
commit 27bde55f54
7 changed files with 202 additions and 17 deletions

View File

@@ -8,13 +8,16 @@ using System.Threading.Tasks;
using BTCPayServer.Data;
using BTCPayServer.Filters;
using BTCPayServer.Models.AppViewModels;
using BTCPayServer.Rating;
using BTCPayServer.Security;
using BTCPayServer.Services.Apps;
using BTCPayServer.Services.Invoices;
using BTCPayServer.Services.Rates;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Cors;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using NBitpayClient;
using YamlDotNet.RepresentationModel;
using static BTCPayServer.Controllers.AppsController;
@@ -22,14 +25,24 @@ namespace BTCPayServer.Controllers
{
public class AppsPublicController : Controller
{
public AppsPublicController(AppsHelper appsHelper, InvoiceController invoiceController)
public AppsPublicController(AppsHelper appsHelper,
InvoiceController invoiceController,
RateFetcher rateFetcher,
BTCPayNetworkProvider btcPayNetworkProvider,
InvoiceRepository invoiceRepository)
{
_AppsHelper = appsHelper;
_InvoiceController = invoiceController;
_rateFetcher = rateFetcher;
_btcPayNetworkProvider = btcPayNetworkProvider;
_invoiceRepository = invoiceRepository;
}
private AppsHelper _AppsHelper;
private InvoiceController _InvoiceController;
private readonly RateFetcher _rateFetcher;
private readonly BTCPayNetworkProvider _btcPayNetworkProvider;
private readonly InvoiceRepository _invoiceRepository;
[HttpGet]
[Route("/apps/{appId}/pos")]
@@ -80,15 +93,40 @@ namespace BTCPayServer.Controllers
return NotFound();
var settings = app.GetSettings<CrowdfundSettings>();
var currency = _AppsHelper.GetCurrencyData(settings.TargetCurrency, false);
double step = currency == null ? 1 : Math.Pow(10, -(currency.Divisibility));
var numberFormatInfo = _AppsHelper.Currencies.GetNumberFormatInfo(currency.Code) ?? _AppsHelper.Currencies.GetNumberFormatInfo("USD");
return View(new ViewCrowdfundViewModel()
return View(CrowdfundHelper.GetInfo(app, _invoiceRepository, _rateFetcher, _btcPayNetworkProvider ));
}
[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)
{
Title = settings.Title,
CustomCSSLink = settings.CustomCSSLink
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]
[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
{

View File

@@ -15,11 +15,9 @@ namespace BTCPayServer.Models.AppViewModels
[Required]
public bool Enabled { get; set; }
public DateTime? StartDate { get; set; }
public DateTime? EndDate { get; set; }
[Required]
[MaxLength(5)]
[Display(Name = "The primary currency used for targets and stats")]

View File

@@ -1,8 +1,39 @@
namespace BTCPayServer.Models.AppViewModels
using System;
using System.ComponentModel.DataAnnotations;
namespace BTCPayServer.Models.AppViewModels
{
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 Description { 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; }
}
}

View File

@@ -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>

View File

@@ -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>

View File

@@ -1,6 +1,7 @@
@addTagHelper *, Meziantou.AspNetCore.BundleTagHelpers
@inject BTCPayServer.HostedServices.CssThemeManager themeManager
@using System.Security.AccessControl
@model BTCPayServer.Models.AppViewModels.ViewCrowdfundViewModel
@{
ViewData["Title"] = Model.Title;
@@ -11,18 +12,22 @@
<html class="h-100">
<head>
<title>@Model.Title</title>
<meta charset="utf-8" />
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1">
<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)
{
<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>
<body class="h-100">
<partial name="MinimalCrowdfund" model="@Model"/>
</body>
</html>

View File

@@ -61,5 +61,13 @@
"wwwroot/cart/js/cart.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"
]
}
]