mirror of
https://github.com/aljazceru/btcpayserver.git
synced 2025-12-17 22:14:26 +01:00
Allow filtering of invoices over storeid and status
This commit is contained in:
@@ -251,6 +251,17 @@ namespace BTCPayServer.Tests
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void CanParseFilter()
|
||||||
|
{
|
||||||
|
var filter = "storeid:abc status:abed blabhbalh ";
|
||||||
|
var search = new SearchString(filter);
|
||||||
|
Assert.Equal("storeid:abc status:abed blabhbalh", search.ToString());
|
||||||
|
Assert.Equal("blabhbalh", search.TextSearch);
|
||||||
|
Assert.Equal("abc", search.Filters["storeid"]);
|
||||||
|
Assert.Equal("abed", search.Filters["status"]);
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void InvoiceFlowThroughDifferentStatesCorrectly()
|
public void InvoiceFlowThroughDifferentStatesCorrectly()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<TargetFramework>netcoreapp2.0</TargetFramework>
|
<TargetFramework>netcoreapp2.0</TargetFramework>
|
||||||
<Version>1.0.0.34</Version>
|
<Version>1.0.0.35</Version>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Remove="Build\dockerfiles\**" />
|
<Compile Remove="Build\dockerfiles\**" />
|
||||||
|
|||||||
@@ -188,12 +188,15 @@ namespace BTCPayServer.Controllers
|
|||||||
public async Task<IActionResult> ListInvoices(string searchTerm = null, int skip = 0, int count = 20)
|
public async Task<IActionResult> ListInvoices(string searchTerm = null, int skip = 0, int count = 20)
|
||||||
{
|
{
|
||||||
var model = new InvoicesModel();
|
var model = new InvoicesModel();
|
||||||
|
var filterString = new SearchString(searchTerm);
|
||||||
foreach (var invoice in await _InvoiceRepository.GetInvoices(new InvoiceQuery()
|
foreach (var invoice in await _InvoiceRepository.GetInvoices(new InvoiceQuery()
|
||||||
{
|
{
|
||||||
TextSearch = searchTerm,
|
TextSearch = filterString.TextSearch,
|
||||||
Count = count,
|
Count = count,
|
||||||
Skip = skip,
|
Skip = skip,
|
||||||
UserId = GetUserId()
|
UserId = GetUserId(),
|
||||||
|
Status = filterString.Filters.TryGet("status"),
|
||||||
|
StoreId = filterString.Filters.TryGet("storeid")
|
||||||
}))
|
}))
|
||||||
{
|
{
|
||||||
model.SearchTerm = searchTerm;
|
model.SearchTerm = searchTerm;
|
||||||
|
|||||||
@@ -146,6 +146,7 @@ namespace BTCPayServer.Controllers
|
|||||||
|
|
||||||
var storeBlob = store.GetStoreBlob(_Network);
|
var storeBlob = store.GetStoreBlob(_Network);
|
||||||
var vm = new StoreViewModel();
|
var vm = new StoreViewModel();
|
||||||
|
vm.Id = store.Id;
|
||||||
vm.StoreName = store.StoreName;
|
vm.StoreName = store.StoreName;
|
||||||
vm.StoreWebsite = store.StoreWebsite;
|
vm.StoreWebsite = store.StoreWebsite;
|
||||||
vm.NetworkFee = !storeBlob.NetworkFeeDisabled;
|
vm.NetworkFee = !storeBlob.NetworkFeeDisabled;
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ namespace BTCPayServer.Models.StoreViewModels
|
|||||||
{
|
{
|
||||||
public class StoreViewModel
|
public class StoreViewModel
|
||||||
{
|
{
|
||||||
|
public string Id { get; set; }
|
||||||
[Display(Name = "Store Name")]
|
[Display(Name = "Store Name")]
|
||||||
[Required]
|
[Required]
|
||||||
[MaxLength(50)]
|
[MaxLength(50)]
|
||||||
|
|||||||
49
BTCPayServer/SearchString.cs
Normal file
49
BTCPayServer/SearchString.cs
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace BTCPayServer
|
||||||
|
{
|
||||||
|
public class SearchString
|
||||||
|
{
|
||||||
|
string _OriginalString;
|
||||||
|
public SearchString(string str)
|
||||||
|
{
|
||||||
|
str = str ?? string.Empty;
|
||||||
|
str = str.Trim();
|
||||||
|
_OriginalString = str.Trim();
|
||||||
|
TextSearch = _OriginalString;
|
||||||
|
var splitted = str.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
|
||||||
|
Filters
|
||||||
|
= splitted
|
||||||
|
.Select(t => t.Split(new char[] { ':' }, StringSplitOptions.RemoveEmptyEntries))
|
||||||
|
.Where(kv => kv.Length == 2)
|
||||||
|
.Select(kv => new KeyValuePair<string, string>(kv[0].ToLowerInvariant(), kv[1]))
|
||||||
|
.ToDictionary(o => o.Key, o => o.Value);
|
||||||
|
|
||||||
|
foreach(var filter in splitted)
|
||||||
|
{
|
||||||
|
if(filter.Split(new char[] { ':' }, StringSplitOptions.RemoveEmptyEntries).Length == 2)
|
||||||
|
{
|
||||||
|
TextSearch = TextSearch.Replace(filter, string.Empty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TextSearch = TextSearch.Trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
public string TextSearch
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
private set;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Dictionary<string, string> Filters { get; private set; }
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return _OriginalString;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -16,7 +16,15 @@
|
|||||||
<div class="col-lg-12 text-center">
|
<div class="col-lg-12 text-center">
|
||||||
<h2 class="section-heading">@ViewData["Title"]</h2>
|
<h2 class="section-heading">@ViewData["Title"]</h2>
|
||||||
<hr class="primary">
|
<hr class="primary">
|
||||||
<p>Create, search or pay an invoice.</p>
|
<p>Create, search or pay an invoice. (<a href="#help" data-toggle="collapse">Help</a>)</p>
|
||||||
|
<div id="help" class="collapse text-left">
|
||||||
|
<p>You can search for invoice Id, deposit address, price, order id, store id, any buyer information and any product information.</br>
|
||||||
|
You can also apply filters to your search by searching for `filtername:value`, here is a list of supported filters</p>
|
||||||
|
<ul>
|
||||||
|
<li><b>store:id</b> for filtering a specific store</li>
|
||||||
|
<li><b>status:(expired|invalid|complete|confirmed|paid|new)</b> for filtering a specific status</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<form asp-action="SearchInvoice" method="post">
|
<form asp-action="SearchInvoice" method="post">
|
||||||
<input asp-for="SearchTerm" class="form-control" />
|
<input asp-for="SearchTerm" class="form-control" />
|
||||||
@@ -43,12 +51,12 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
@foreach (var invoice in Model.Invoices)
|
@foreach(var invoice in Model.Invoices)
|
||||||
{
|
{
|
||||||
<tr>
|
<tr>
|
||||||
<td>@invoice.Date</td>
|
<td>@invoice.Date</td>
|
||||||
<td>@invoice.InvoiceId</td>
|
<td>@invoice.InvoiceId</td>
|
||||||
@if (invoice.Status == "paid")
|
@if(invoice.Status == "paid")
|
||||||
{
|
{
|
||||||
<td>
|
<td>
|
||||||
<div class="btn-group">
|
<div class="btn-group">
|
||||||
@@ -72,7 +80,7 @@
|
|||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
<span>
|
<span>
|
||||||
@if (Model.Skip != 0)
|
@if(Model.Skip != 0)
|
||||||
{
|
{
|
||||||
<a href="@Url.Action("ListInvoices", new
|
<a href="@Url.Action("ListInvoices", new
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -16,6 +16,15 @@
|
|||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<form method="post">
|
<form method="post">
|
||||||
|
<div class="form-group">
|
||||||
|
<label asp-for="Id"></label>
|
||||||
|
<input asp-for="Id" readonly class="form-control" />
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label asp-for="StoreName"></label>
|
||||||
|
<input asp-for="StoreName" class="form-control" />
|
||||||
|
<span asp-validation-for="StoreName" class="text-danger"></span>
|
||||||
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label asp-for="StoreName"></label>
|
<label asp-for="StoreName"></label>
|
||||||
<input asp-for="StoreName" class="form-control" />
|
<input asp-for="StoreName" class="form-control" />
|
||||||
|
|||||||
Reference in New Issue
Block a user