2017-09-13 08:47:34 +02:00
using BTCPayServer.Authentication ;
using Microsoft.Extensions.Logging ;
using BTCPayServer.Filters ;
using BTCPayServer.Logging ;
using BTCPayServer.Models ;
using Microsoft.AspNetCore.Mvc ;
using NBitpayClient ;
using System ;
using System.Collections.Generic ;
using System.Linq ;
using System.Threading.Tasks ;
using BTCPayServer.Data ;
2017-10-20 21:06:37 +02:00
using BTCPayServer.Services.Invoices ;
2017-10-13 10:46:19 +02:00
using Microsoft.AspNetCore.Cors ;
using BTCPayServer.Services.Stores ;
2017-09-13 08:47:34 +02:00
namespace BTCPayServer.Controllers
{
2017-10-27 10:53:04 +02:00
[EnableCors("BitpayAPI")]
[BitpayAPIConstraint]
public class InvoiceControllerAPI : Controller
2017-09-13 08:47:34 +02:00
{
2017-10-27 10:53:04 +02:00
private InvoiceController _InvoiceController ;
private InvoiceRepository _InvoiceRepository ;
private TokenRepository _TokenRepository ;
private StoreRepository _StoreRepository ;
2017-10-13 10:46:19 +02:00
2017-10-27 10:53:04 +02:00
public InvoiceControllerAPI ( InvoiceController invoiceController ,
InvoiceRepository invoceRepository ,
TokenRepository tokenRepository ,
StoreRepository storeRepository )
{
this . _InvoiceController = invoiceController ;
this . _InvoiceRepository = invoceRepository ;
this . _TokenRepository = tokenRepository ;
this . _StoreRepository = storeRepository ;
}
2017-10-13 10:46:19 +02:00
2017-10-27 10:53:04 +02:00
[HttpPost]
[Route("invoices")]
[MediaTypeConstraint("application/json")]
public async Task < DataWrapper < InvoiceResponse > > CreateInvoice ( [ FromBody ] Invoice invoice )
{
var bitToken = await CheckTokenPermissionAsync ( Facade . Merchant , invoice . Token ) ;
var store = await FindStore ( bitToken ) ;
return await _InvoiceController . CreateInvoiceCore ( invoice , store , HttpContext . Request . GetAbsoluteRoot ( ) ) ;
}
2017-09-13 08:47:34 +02:00
2017-10-27 10:53:04 +02:00
[HttpGet]
[Route("invoices/{id}")]
public async Task < DataWrapper < InvoiceResponse > > GetInvoice ( string id , string token )
{
var bitToken = await CheckTokenPermissionAsync ( Facade . Merchant , token ) ;
var store = await FindStore ( bitToken ) ;
var invoice = await _InvoiceRepository . GetInvoice ( store . Id , id ) ;
if ( invoice = = null )
throw new BitpayHttpException ( 404 , "Object not found" ) ;
2017-09-13 08:47:34 +02:00
2017-10-27 10:53:04 +02:00
var resp = invoice . EntityToDTO ( ) ;
return new DataWrapper < InvoiceResponse > ( resp ) ;
}
2017-09-13 08:47:34 +02:00
2017-10-27 10:53:04 +02:00
[HttpGet]
[Route("invoices")]
public async Task < DataWrapper < InvoiceResponse [ ] > > GetInvoices (
string token ,
DateTimeOffset ? dateStart = null ,
DateTimeOffset ? dateEnd = null ,
string orderId = null ,
string itemCode = null ,
string status = null ,
int? limit = null ,
int? offset = null )
{
if ( dateEnd ! = null )
dateEnd = dateEnd . Value + TimeSpan . FromDays ( 1 ) ; //Should include the end day
var bitToken = await CheckTokenPermissionAsync ( Facade . Merchant , token ) ;
var store = await FindStore ( bitToken ) ;
var query = new InvoiceQuery ( )
{
Count = limit ,
Skip = offset ,
EndDate = dateEnd ,
StartDate = dateStart ,
OrderId = orderId ,
ItemCode = itemCode ,
Status = status ,
StoreId = store . Id
} ;
2017-09-13 08:47:34 +02:00
2017-10-27 10:53:04 +02:00
var entities = ( await _InvoiceRepository . GetInvoices ( query ) )
. Select ( ( o ) = > o . EntityToDTO ( ) ) . ToArray ( ) ;
2017-09-13 08:47:34 +02:00
2017-10-27 10:53:04 +02:00
return DataWrapper . Create ( entities ) ;
}
2017-09-13 08:47:34 +02:00
2017-10-27 10:53:04 +02:00
private async Task < BitTokenEntity > CheckTokenPermissionAsync ( Facade facade , string expectedToken )
{
if ( facade = = null )
throw new ArgumentNullException ( nameof ( facade ) ) ;
2017-09-13 08:47:34 +02:00
2017-10-27 10:53:04 +02:00
var actualTokens = ( await _TokenRepository . GetTokens ( this . GetBitIdentity ( ) . SIN ) ) . ToArray ( ) ;
actualTokens = actualTokens . SelectMany ( t = > GetCompatibleTokens ( t ) ) . ToArray ( ) ;
2017-09-13 08:47:34 +02:00
2017-10-27 10:53:04 +02:00
var actualToken = actualTokens . FirstOrDefault ( a = > a . Value . Equals ( expectedToken , StringComparison . Ordinal ) ) ;
if ( expectedToken = = null | | actualToken = = null )
{
Logs . PayServer . LogDebug ( $"No token found for facade {facade} for SIN {this.GetBitIdentity().SIN}" ) ;
throw new BitpayHttpException ( 401 , $"This endpoint does not support the `{actualTokens.Select(a => a.Facade).Concat(new[] { " user " }).FirstOrDefault()}` facade" ) ;
}
return actualToken ;
}
2017-09-25 18:31:43 +02:00
2017-10-27 10:53:04 +02:00
private IEnumerable < BitTokenEntity > GetCompatibleTokens ( BitTokenEntity token )
{
if ( token . Facade = = Facade . Merchant . ToString ( ) )
{
yield return token . Clone ( Facade . User ) ;
yield return token . Clone ( Facade . PointOfSale ) ;
}
if ( token . Facade = = Facade . PointOfSale . ToString ( ) )
{
yield return token . Clone ( Facade . User ) ;
}
yield return token ;
}
2017-09-13 08:47:34 +02:00
2017-10-27 10:53:04 +02:00
private async Task < StoreData > FindStore ( BitTokenEntity bitToken )
{
var store = await _StoreRepository . FindStore ( bitToken . StoreId ) ;
if ( store = = null )
throw new BitpayHttpException ( 401 , "Unknown store" ) ;
return store ;
}
}
2017-09-13 08:47:34 +02:00
}