mirror of
https://github.com/btcpayserver/btcpayserver.git
synced 2024-11-19 01:43:50 +01:00
Code formatting updates (#4502)
* Editorconfig: Add space_before_self_closing setting This was a difference between the way dotnet-format and Rider format code. See https://www.jetbrains.com/help/rider/EditorConfig_Index.html * Editorconfig: Keep 4 spaces indentation for Swagger JSON files They are all formatted that way, let's keep it like that. * Apply dotnet-format, mostly white-space related changes
This commit is contained in:
parent
3fa28bb46d
commit
d5d0be5824
@ -11,10 +11,14 @@ insert_final_newline = true
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
charset = utf-8
|
||||
space_before_self_closing = true
|
||||
|
||||
[*.json]
|
||||
indent_size = 2
|
||||
|
||||
[swagger*.json]
|
||||
indent_size = 4
|
||||
|
||||
# C# files
|
||||
[*.cs]
|
||||
# New line preferences
|
||||
@ -67,7 +71,7 @@ dotnet_naming_symbols.private_internal_fields.applicable_kinds = field
|
||||
dotnet_naming_symbols.private_internal_fields.applicable_accessibilities = private, internal
|
||||
|
||||
dotnet_naming_style.camel_case_underscore_style.required_prefix = _
|
||||
dotnet_naming_style.camel_case_underscore_style.capitalization = camel_case
|
||||
dotnet_naming_style.camel_case_underscore_style.capitalization = camel_case
|
||||
|
||||
# Code style defaults
|
||||
dotnet_sort_system_directives_first = true
|
||||
|
@ -1,4 +1,4 @@
|
||||
#nullable enable
|
||||
#nullable enable
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
@ -1,4 +1,4 @@
|
||||
#nullable enable
|
||||
#nullable enable
|
||||
namespace BTCPayServer.Abstractions.Contracts;
|
||||
|
||||
public interface IScopeProvider
|
||||
|
@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
|
||||
namespace BTCPayServer.Abstractions.Contracts;
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using NBitcoin;
|
||||
|
||||
|
@ -9,7 +9,7 @@ public class AssetQuoteResult
|
||||
|
||||
public AssetQuoteResult() { }
|
||||
|
||||
public AssetQuoteResult(string fromAsset, string toAsset,decimal bid, decimal ask)
|
||||
public AssetQuoteResult(string fromAsset, string toAsset, decimal bid, decimal ask)
|
||||
{
|
||||
FromAsset = fromAsset;
|
||||
ToAsset = toAsset;
|
||||
|
@ -2,10 +2,7 @@ namespace BTCPayServer.Abstractions.Custodians;
|
||||
|
||||
public class AssetBalancesUnavailableException : CustodianApiException
|
||||
{
|
||||
|
||||
public AssetBalancesUnavailableException(System.Exception e) : base(500, "asset-balances-unavailable", $"Cannot fetch the asset balances: {e.Message}", e)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
using System;
|
||||
namespace BTCPayServer.Abstractions.Custodians;
|
||||
public class CustodianApiException: Exception {
|
||||
public class CustodianApiException : Exception
|
||||
{
|
||||
public int HttpStatus { get; }
|
||||
public string Code { get; }
|
||||
|
||||
@ -9,7 +10,8 @@ public class CustodianApiException: Exception {
|
||||
HttpStatus = httpStatus;
|
||||
Code = code;
|
||||
}
|
||||
public CustodianApiException( int httpStatus, string code, string message) : this(httpStatus, code, message, null)
|
||||
|
||||
public CustodianApiException(int httpStatus, string code, string message) : this(httpStatus, code, message, null)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,8 @@
|
||||
namespace BTCPayServer.Abstractions.Custodians;
|
||||
|
||||
public class CustodianFeatureNotImplementedException: CustodianApiException
|
||||
public class CustodianFeatureNotImplementedException : CustodianApiException
|
||||
{
|
||||
public CustodianFeatureNotImplementedException(string message) : base(400, "not-implemented", message)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,8 @@
|
||||
namespace BTCPayServer.Abstractions.Custodians;
|
||||
|
||||
public class InsufficientFundsException : CustodianApiException
|
||||
{
|
||||
{
|
||||
public InsufficientFundsException(string message) : base(400, "insufficient-funds", message)
|
||||
{
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ public class TradeNotFoundException : CustodianApiException
|
||||
{
|
||||
private string tradeId { get; }
|
||||
|
||||
public TradeNotFoundException(string tradeId) : base(404,"trade-not-found","Could not find trade ID " + tradeId)
|
||||
public TradeNotFoundException(string tradeId) : base(404, "trade-not-found", "Could not find trade ID " + tradeId)
|
||||
{
|
||||
this.tradeId = tradeId;
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
namespace BTCPayServer.Abstractions.Custodians;
|
||||
|
||||
public class WrongTradingPairException: CustodianApiException
|
||||
public class WrongTradingPairException : CustodianApiException
|
||||
{
|
||||
public const int HttpCode = 404;
|
||||
public WrongTradingPairException(string fromAsset, string toAsset) : base(HttpCode, "wrong-trading-pair", $"Cannot find a trading pair for converting {fromAsset} into {toAsset}.")
|
||||
|
@ -9,18 +9,16 @@ namespace BTCPayServer.Abstractions.Custodians;
|
||||
|
||||
public interface ICanTrade
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* A list of tradable asset pairs, or NULL if the custodian cannot trade/convert assets. if thr asset pair contains fiat, fiat is always put last. If both assets are a cyrptocode or both are fiat, the pair is written alphabetically. Always in uppercase. Example: ["BTC/EUR","BTC/USD", "EUR/USD", "BTC/ETH",...]
|
||||
*/
|
||||
public List<AssetPairData> GetTradableAssetPairs();
|
||||
|
||||
|
||||
/**
|
||||
* Execute a market order right now.
|
||||
*/
|
||||
public Task<MarketTradeResult> TradeMarketAsync(string fromAsset, string toAsset, decimal qty, JObject config, CancellationToken cancellationToken);
|
||||
|
||||
|
||||
/**
|
||||
* Get the details about a previous market trade.
|
||||
*/
|
||||
|
@ -12,7 +12,7 @@ public interface ICustodian
|
||||
* Get the unique code that identifies this custodian.
|
||||
*/
|
||||
string Code { get; }
|
||||
|
||||
|
||||
string Name { get; }
|
||||
|
||||
/**
|
||||
|
@ -30,12 +30,12 @@ public static class GreenfieldExtensions
|
||||
{
|
||||
return controller.BadRequest(new GreenfieldAPIError(errorCode, errorMessage));
|
||||
}
|
||||
|
||||
|
||||
public static IActionResult CreateAPIError(this ControllerBase controller, int httpCode, string errorCode, string errorMessage)
|
||||
{
|
||||
return controller.StatusCode(httpCode, new GreenfieldAPIError(errorCode, errorMessage));
|
||||
}
|
||||
|
||||
|
||||
public static IActionResult CreateAPIPermissionError(this ControllerBase controller, string missingPermission, string message = null)
|
||||
{
|
||||
return controller.StatusCode(403, new GreenfieldPermissionAPIError(missingPermission, message));
|
||||
|
@ -11,7 +11,7 @@ public static class HttpRequestExtensions
|
||||
return false;
|
||||
return request.Host.Host.EndsWith(".onion", StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
|
||||
public static string GetAbsoluteRoot(this HttpRequest request)
|
||||
{
|
||||
return string.Concat(
|
||||
|
@ -6,7 +6,6 @@ namespace BTCPayServer.Abstractions.Extensions;
|
||||
|
||||
public static class StringExtensions
|
||||
{
|
||||
|
||||
public static bool IsValidFileName(this string fileName)
|
||||
{
|
||||
return !fileName.ToCharArray().Any(c => Path.GetInvalidFileNameChars().Contains(c)
|
||||
@ -41,5 +40,4 @@ public static class StringExtensions
|
||||
return str.Substring(0, str.Length - 1);
|
||||
return str;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -50,7 +50,7 @@ namespace BTCPayServer.Abstractions.Extensions
|
||||
{
|
||||
return IsActiveCategory(viewData, category.ToString(), id);
|
||||
}
|
||||
|
||||
|
||||
public static string IsActiveCategory(this ViewDataDictionary viewData, string category, object id = null)
|
||||
{
|
||||
if (!viewData.ContainsKey(ACTIVE_CATEGORY_KEY))
|
||||
@ -77,7 +77,7 @@ namespace BTCPayServer.Abstractions.Extensions
|
||||
? ActivePageClass
|
||||
: null;
|
||||
}
|
||||
|
||||
|
||||
public static string IsActivePage(this ViewDataDictionary viewData, string page, string category, object id = null)
|
||||
{
|
||||
if (!viewData.ContainsKey(ACTIVE_PAGE_KEY))
|
||||
@ -126,7 +126,7 @@ namespace BTCPayServer.Abstractions.Extensions
|
||||
{
|
||||
return $"{(int)timeSpan.TotalMinutes} minute{Plural((int)timeSpan.TotalMinutes)}";
|
||||
}
|
||||
return timeSpan.Days < 1
|
||||
return timeSpan.Days < 1
|
||||
? $"{(int)timeSpan.TotalHours} hour{Plural((int)timeSpan.TotalHours)}"
|
||||
: $"{(int)timeSpan.TotalDays} day{Plural((int)timeSpan.TotalDays)}";
|
||||
}
|
||||
|
@ -17,16 +17,16 @@ public class AlertMessage
|
||||
Danger,
|
||||
Info
|
||||
}
|
||||
|
||||
|
||||
[JsonConverter(typeof(StringEnumConverter))]
|
||||
public AlertMessageType Type;
|
||||
|
||||
|
||||
// The translated message to be shown to the user
|
||||
public string Message;
|
||||
|
||||
public AlertMessage()
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
public AlertMessage(AlertMessageType type, string message)
|
||||
|
@ -17,7 +17,7 @@ public class Field
|
||||
Label = label,
|
||||
Name = name,
|
||||
Value = value,
|
||||
OriginalValue = value,
|
||||
OriginalValue = value,
|
||||
Required = required,
|
||||
HelpText = helpText,
|
||||
Type = type
|
||||
|
@ -22,10 +22,10 @@ public class Form
|
||||
#nullable restore
|
||||
// Messages to be shown at the top of the form indicating user feedback like "Saved successfully" or "Please change X because of Y." or a warning, etc...
|
||||
public List<AlertMessage> TopMessages { get; set; } = new();
|
||||
|
||||
|
||||
// Groups of fields in the form
|
||||
public List<Field> Fields { get; set; } = new();
|
||||
|
||||
|
||||
// Are all the fields valid in the form?
|
||||
public bool IsValid()
|
||||
{
|
||||
@ -36,7 +36,7 @@ public class Form
|
||||
{
|
||||
return GetFieldByName(name, Fields, null);
|
||||
}
|
||||
|
||||
|
||||
private static Field GetFieldByName(string name, List<Field> fields, string prefix)
|
||||
{
|
||||
prefix ??= string.Empty;
|
||||
@ -45,7 +45,7 @@ public class Form
|
||||
var currentPrefix = prefix;
|
||||
if (!string.IsNullOrEmpty(field.Name))
|
||||
{
|
||||
|
||||
|
||||
currentPrefix = $"{prefix}{field.Name}";
|
||||
if (currentPrefix.Equals(name, StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
@ -60,7 +60,7 @@ public class Form
|
||||
{
|
||||
return subFieldResult;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@ -73,7 +73,7 @@ public class Form
|
||||
private static List<string> GetAllNames(List<Field> fields)
|
||||
{
|
||||
var names = new List<string>();
|
||||
|
||||
|
||||
foreach (var field in fields)
|
||||
{
|
||||
string prefix = string.Empty;
|
||||
@ -85,7 +85,7 @@ public class Form
|
||||
|
||||
if (field.Fields.Any())
|
||||
{
|
||||
names.AddRange(GetAllNames(field.Fields).Select(s => $"{prefix}{s}" ));
|
||||
names.AddRange(GetAllNames(field.Fields).Select(s => $"{prefix}{s}"));
|
||||
}
|
||||
}
|
||||
|
||||
@ -105,7 +105,7 @@ public class Form
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void ApplyValuesFromForm(IFormCollection form)
|
||||
{
|
||||
var names = GetAllNames();
|
||||
@ -125,7 +125,7 @@ public class Form
|
||||
{
|
||||
return GetValues(Fields);
|
||||
}
|
||||
|
||||
|
||||
private static Dictionary<string, object> GetValues(List<Field> fields)
|
||||
{
|
||||
var result = new Dictionary<string, object>();
|
||||
@ -136,11 +136,12 @@ public class Form
|
||||
{
|
||||
var values = GetValues(fields);
|
||||
values.Remove(string.Empty, out var keylessValue);
|
||||
|
||||
|
||||
result.TryAdd(name, values);
|
||||
|
||||
if (keylessValue is not Dictionary<string, object> dict) continue;
|
||||
foreach (KeyValuePair<string,object> keyValuePair in dict)
|
||||
if (keylessValue is not Dictionary<string, object> dict)
|
||||
continue;
|
||||
foreach (KeyValuePair<string, object> keyValuePair in dict)
|
||||
{
|
||||
result.TryAdd(keyValuePair.Key, keyValuePair.Value);
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ public class AuthorizationFilterHandle
|
||||
public AuthorizationHandlerContext Context { get; }
|
||||
public PolicyRequirement Requirement { get; }
|
||||
public HttpContext HttpContext { get; }
|
||||
public bool Success { get; private set; }
|
||||
public bool Success { get; private set; }
|
||||
|
||||
public AuthorizationFilterHandle(
|
||||
AuthorizationHandlerContext context,
|
||||
|
@ -29,5 +29,5 @@ public class SVGUse : UrlResolutionTagHelper2
|
||||
attr = _fileVersionProvider.AddFileVersionToPath(ViewContext.HttpContext.Request.PathBase, attr);
|
||||
output.Attributes.SetAttribute("href", attr);
|
||||
base.Process(context, output);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ namespace BTCPayServer.Client
|
||||
method: HttpMethod.Post), token);
|
||||
return await HandleResponse<PointOfSaleAppData>(response);
|
||||
}
|
||||
|
||||
|
||||
public virtual async Task<CrowdfundAppData> CreateCrowdfundApp(string storeId,
|
||||
CreateCrowdfundAppRequest request, CancellationToken token = default)
|
||||
{
|
||||
|
@ -58,7 +58,7 @@ namespace BTCPayServer.Client
|
||||
|
||||
public virtual async Task<MarketTradeResponseData> MarketTradeCustodianAccountAsset(string storeId, string accountId, TradeRequestData request, CancellationToken token = default)
|
||||
{
|
||||
|
||||
|
||||
//var response = await _httpClient.SendAsync(CreateHttpRequest("api/v1/users", null, request, HttpMethod.Post), token);
|
||||
//return await HandleResponse<ApplicationUserData>(response);
|
||||
var internalRequest = CreateHttpRequest($"api/v1/stores/{storeId}/custodian-accounts/{accountId}/trades/market", null,
|
||||
@ -81,8 +81,8 @@ namespace BTCPayServer.Client
|
||||
var response = await _httpClient.SendAsync(CreateHttpRequest($"api/v1/stores/{storeId}/custodian-accounts/{accountId}/trades/quote", queryPayload), token);
|
||||
return await HandleResponse<TradeQuoteResponseData>(response);
|
||||
}
|
||||
|
||||
public virtual async Task<WithdrawalResponseData> CreateWithdrawal(string storeId, string accountId, WithdrawRequestData request, CancellationToken token = default)
|
||||
|
||||
public virtual async Task<WithdrawalResponseData> CreateWithdrawal(string storeId, string accountId, WithdrawRequestData request, CancellationToken token = default)
|
||||
{
|
||||
var response = await _httpClient.SendAsync(CreateHttpRequest($"api/v1/stores/{storeId}/custodian-accounts/{accountId}/withdrawals", bodyPayload: request, method: HttpMethod.Post), token);
|
||||
return await HandleResponse<WithdrawalResponseData>(response);
|
||||
|
@ -17,7 +17,7 @@ namespace BTCPayServer.Client
|
||||
method: HttpMethod.Get), token);
|
||||
return await HandleResponse<LightningNodeInformationData>(response);
|
||||
}
|
||||
|
||||
|
||||
public virtual async Task<LightningNodeBalanceData> GetLightningNodeBalance(string cryptoCode,
|
||||
CancellationToken token = default)
|
||||
{
|
||||
@ -95,7 +95,7 @@ namespace BTCPayServer.Client
|
||||
method: HttpMethod.Get), token);
|
||||
return await HandleResponse<LightningInvoiceData>(response);
|
||||
}
|
||||
|
||||
|
||||
public virtual async Task<LightningInvoiceData[]> GetLightningInvoices(string cryptoCode,
|
||||
bool? pendingOnly = null, long? offsetIndex = null, CancellationToken token = default)
|
||||
{
|
||||
|
@ -17,7 +17,7 @@ namespace BTCPayServer.Client
|
||||
method: HttpMethod.Get), token);
|
||||
return await HandleResponse<LightningNodeInformationData>(response);
|
||||
}
|
||||
|
||||
|
||||
public virtual async Task<LightningNodeBalanceData> GetLightningNodeBalance(string storeId, string cryptoCode,
|
||||
CancellationToken token = default)
|
||||
{
|
||||
@ -97,7 +97,7 @@ namespace BTCPayServer.Client
|
||||
method: HttpMethod.Get), token);
|
||||
return await HandleResponse<LightningInvoiceData>(response);
|
||||
}
|
||||
|
||||
|
||||
public virtual async Task<LightningInvoiceData[]> GetLightningInvoices(string storeId, string cryptoCode,
|
||||
bool? pendingOnly = null, long? offsetIndex = null, CancellationToken token = default)
|
||||
{
|
||||
|
@ -39,7 +39,7 @@ namespace BTCPayServer.Client
|
||||
parameters.Add("includeNeighbourData", v);
|
||||
var response =
|
||||
await _httpClient.SendAsync(
|
||||
CreateHttpRequest($"api/v1/stores/{storeId}/payment-methods/onchain/{cryptoCode}/wallet/objects", parameters, method:HttpMethod.Get), token);
|
||||
CreateHttpRequest($"api/v1/stores/{storeId}/payment-methods/onchain/{cryptoCode}/wallet/objects", parameters, method: HttpMethod.Get), token);
|
||||
return await HandleResponse<OnChainWalletObjectData[]>(response);
|
||||
}
|
||||
public virtual async Task RemoveOnChainWalletObject(string storeId, string cryptoCode, OnChainWalletObjectId objectId,
|
||||
@ -47,7 +47,7 @@ namespace BTCPayServer.Client
|
||||
{
|
||||
var response =
|
||||
await _httpClient.SendAsync(
|
||||
CreateHttpRequest($"api/v1/stores/{storeId}/payment-methods/onchain/{cryptoCode}/wallet/objects/{objectId.Type}/{objectId.Id}", method:HttpMethod.Delete), token);
|
||||
CreateHttpRequest($"api/v1/stores/{storeId}/payment-methods/onchain/{cryptoCode}/wallet/objects/{objectId.Type}/{objectId.Id}", method: HttpMethod.Delete), token);
|
||||
await HandleResponse(response);
|
||||
}
|
||||
public virtual async Task<OnChainWalletObjectData> AddOrUpdateOnChainWalletObject(string storeId, string cryptoCode, AddOnChainWalletObjectRequest request,
|
||||
@ -55,7 +55,7 @@ namespace BTCPayServer.Client
|
||||
{
|
||||
var response =
|
||||
await _httpClient.SendAsync(
|
||||
CreateHttpRequest($"api/v1/stores/{storeId}/payment-methods/onchain/{cryptoCode}/wallet/objects", method:HttpMethod.Post, bodyPayload: request), token);
|
||||
CreateHttpRequest($"api/v1/stores/{storeId}/payment-methods/onchain/{cryptoCode}/wallet/objects", method: HttpMethod.Post, bodyPayload: request), token);
|
||||
return await HandleResponse<OnChainWalletObjectData>(response);
|
||||
}
|
||||
public virtual async Task AddOrUpdateOnChainWalletLink(string storeId, string cryptoCode,
|
||||
@ -65,7 +65,7 @@ namespace BTCPayServer.Client
|
||||
{
|
||||
var response =
|
||||
await _httpClient.SendAsync(
|
||||
CreateHttpRequest($"api/v1/stores/{storeId}/payment-methods/onchain/{cryptoCode}/wallet/objects/{objectId.Type}/{objectId.Id}/links", method:HttpMethod.Post, bodyPayload: request), token);
|
||||
CreateHttpRequest($"api/v1/stores/{storeId}/payment-methods/onchain/{cryptoCode}/wallet/objects/{objectId.Type}/{objectId.Id}/links", method: HttpMethod.Post, bodyPayload: request), token);
|
||||
await HandleResponse(response);
|
||||
}
|
||||
public virtual async Task RemoveOnChainWalletLinks(string storeId, string cryptoCode,
|
||||
@ -75,7 +75,7 @@ namespace BTCPayServer.Client
|
||||
{
|
||||
var response =
|
||||
await _httpClient.SendAsync(
|
||||
CreateHttpRequest($"api/v1/stores/{storeId}/payment-methods/onchain/{cryptoCode}/wallet/objects/{objectId.Type}/{objectId.Id}/links/{link.Type}/{link.Id}", method:HttpMethod.Delete), token);
|
||||
CreateHttpRequest($"api/v1/stores/{storeId}/payment-methods/onchain/{cryptoCode}/wallet/objects/{objectId.Type}/{objectId.Id}/links/{link.Type}/{link.Id}", method: HttpMethod.Delete), token);
|
||||
await HandleResponse(response);
|
||||
}
|
||||
}
|
||||
|
@ -63,7 +63,8 @@ namespace BTCPayServer.Client
|
||||
{
|
||||
query.Add(nameof(statusFilter), statusFilter);
|
||||
}
|
||||
if (labelFilter != null) {
|
||||
if (labelFilter != null)
|
||||
{
|
||||
query.Add(nameof(labelFilter), labelFilter);
|
||||
}
|
||||
var response =
|
||||
|
@ -52,17 +52,17 @@ namespace BTCPayServer.Client
|
||||
{
|
||||
var response = await _httpClient.SendAsync(CreateHttpRequest($"api/v1/pull-payments/{HttpUtility.UrlEncode(pullPaymentId)}/payouts", bodyPayload: payoutRequest, method: HttpMethod.Post), cancellationToken);
|
||||
return await HandleResponse<PayoutData>(response);
|
||||
}
|
||||
}
|
||||
public virtual async Task<PayoutData> GetPullPaymentPayout(string pullPaymentId, string payoutId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var response = await _httpClient.SendAsync(CreateHttpRequest($"api/v1/pull-payments/{HttpUtility.UrlEncode(pullPaymentId)}/payouts/{payoutId}", method: HttpMethod.Get), cancellationToken);
|
||||
return await HandleResponse<PayoutData>(response);
|
||||
}
|
||||
}
|
||||
public virtual async Task<PayoutData> GetStorePayout(string storeId, string payoutId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var response = await _httpClient.SendAsync(CreateHttpRequest($"api/v1/stores/{storeId}/payouts/{payoutId}", method: HttpMethod.Get), cancellationToken);
|
||||
return await HandleResponse<PayoutData>(response);
|
||||
}
|
||||
}
|
||||
public virtual async Task<PayoutData> CreatePayout(string storeId, CreatePayoutThroughStoreRequest payoutRequest, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var response = await _httpClient.SendAsync(CreateHttpRequest($"api/v1/stores/{storeId}/payouts", bodyPayload: payoutRequest, method: HttpMethod.Post), cancellationToken);
|
||||
|
@ -9,7 +9,7 @@ namespace BTCPayServer.Client
|
||||
{
|
||||
public partial class BTCPayServerClient
|
||||
{
|
||||
public virtual async Task<IEnumerable<PayoutProcessorData>> GetPayoutProcessors(string storeId,
|
||||
public virtual async Task<IEnumerable<PayoutProcessorData>> GetPayoutProcessors(string storeId,
|
||||
CancellationToken token = default)
|
||||
{
|
||||
var response = await _httpClient.SendAsync(CreateHttpRequest($"api/v1/stores/{storeId}/payout-processors"), token);
|
||||
@ -20,28 +20,28 @@ namespace BTCPayServer.Client
|
||||
var response = await _httpClient.SendAsync(CreateHttpRequest($"api/v1/stores/{storeId}/payout-processors/{processor}/{paymentMethod}", null, HttpMethod.Delete), token);
|
||||
await HandleResponse(response);
|
||||
}
|
||||
|
||||
|
||||
public virtual async Task<IEnumerable<LightningAutomatedPayoutSettings>> GetStoreLightningAutomatedPayoutProcessors(string storeId, string? paymentMethod = null,
|
||||
CancellationToken token = default)
|
||||
{
|
||||
var response = await _httpClient.SendAsync(CreateHttpRequest($"api/v1/stores/{storeId}/payout-processors/LightningAutomatedPayoutSenderFactory{(paymentMethod is null? string.Empty: $"/{paymentMethod}")}"), token);
|
||||
var response = await _httpClient.SendAsync(CreateHttpRequest($"api/v1/stores/{storeId}/payout-processors/LightningAutomatedPayoutSenderFactory{(paymentMethod is null ? string.Empty : $"/{paymentMethod}")}"), token);
|
||||
return await HandleResponse<IEnumerable<LightningAutomatedPayoutSettings>>(response);
|
||||
}
|
||||
public virtual async Task<LightningAutomatedPayoutSettings> UpdateStoreLightningAutomatedPayoutProcessors(string storeId, string paymentMethod,LightningAutomatedPayoutSettings request, CancellationToken token = default)
|
||||
public virtual async Task<LightningAutomatedPayoutSettings> UpdateStoreLightningAutomatedPayoutProcessors(string storeId, string paymentMethod, LightningAutomatedPayoutSettings request, CancellationToken token = default)
|
||||
{
|
||||
var response = await _httpClient.SendAsync(CreateHttpRequest($"api/v1/stores/{storeId}/payout-processors/LightningAutomatedPayoutSenderFactory/{paymentMethod}",null, request, HttpMethod.Put ), token);
|
||||
var response = await _httpClient.SendAsync(CreateHttpRequest($"api/v1/stores/{storeId}/payout-processors/LightningAutomatedPayoutSenderFactory/{paymentMethod}", null, request, HttpMethod.Put), token);
|
||||
return await HandleResponse<LightningAutomatedPayoutSettings>(response);
|
||||
}
|
||||
public virtual async Task<OnChainAutomatedPayoutSettings> UpdateStoreOnChainAutomatedPayoutProcessors(string storeId, string paymentMethod,OnChainAutomatedPayoutSettings request, CancellationToken token = default)
|
||||
public virtual async Task<OnChainAutomatedPayoutSettings> UpdateStoreOnChainAutomatedPayoutProcessors(string storeId, string paymentMethod, OnChainAutomatedPayoutSettings request, CancellationToken token = default)
|
||||
{
|
||||
var response = await _httpClient.SendAsync(CreateHttpRequest($"api/v1/stores/{storeId}/payout-processors/OnChainAutomatedPayoutSenderFactory/{paymentMethod}",null, request, HttpMethod.Put ), token);
|
||||
var response = await _httpClient.SendAsync(CreateHttpRequest($"api/v1/stores/{storeId}/payout-processors/OnChainAutomatedPayoutSenderFactory/{paymentMethod}", null, request, HttpMethod.Put), token);
|
||||
return await HandleResponse<OnChainAutomatedPayoutSettings>(response);
|
||||
}
|
||||
|
||||
|
||||
public virtual async Task<IEnumerable<OnChainAutomatedPayoutSettings>> GetStoreOnChainAutomatedPayoutProcessors(string storeId, string? paymentMethod = null,
|
||||
CancellationToken token = default)
|
||||
{
|
||||
var response = await _httpClient.SendAsync(CreateHttpRequest($"api/v1/stores/{storeId}/payout-processors/OnChainAutomatedPayoutSenderFactory{(paymentMethod is null? string.Empty: $"/{paymentMethod}")}"), token);
|
||||
var response = await _httpClient.SendAsync(CreateHttpRequest($"api/v1/stores/{storeId}/payout-processors/OnChainAutomatedPayoutSenderFactory{(paymentMethod is null ? string.Empty : $"/{paymentMethod}")}"), token);
|
||||
return await HandleResponse<IEnumerable<OnChainAutomatedPayoutSettings>>(response);
|
||||
}
|
||||
}
|
||||
|
@ -44,7 +44,7 @@ namespace BTCPayServer.Client
|
||||
{
|
||||
using var response = await _httpClient.SendAsync(
|
||||
CreateHttpRequest($"api/v1/stores/{storeId}/rates/configuration/preview", bodyPayload: request,
|
||||
queryPayload: new Dictionary<string, object>() {{"currencyPair", currencyPair}},
|
||||
queryPayload: new Dictionary<string, object>() { { "currencyPair", currencyPair } },
|
||||
method: HttpMethod.Post),
|
||||
token);
|
||||
return await HandleResponse<List<StoreRatePreviewResult>>(response);
|
||||
|
@ -36,12 +36,12 @@ namespace BTCPayServer.Client
|
||||
public virtual async Task<bool> LockUser(string idOrEmail, bool locked, CancellationToken token = default)
|
||||
{
|
||||
var response = await _httpClient.SendAsync(CreateHttpRequest($"api/v1/users/{idOrEmail}/lock", null,
|
||||
new LockUserRequest {Locked = locked}, HttpMethod.Post), token);
|
||||
new LockUserRequest { Locked = locked }, HttpMethod.Post), token);
|
||||
await HandleResponse(response);
|
||||
return response.IsSuccessStatusCode;
|
||||
}
|
||||
|
||||
public virtual async Task<ApplicationUserData[]> GetUsers( CancellationToken token = default)
|
||||
public virtual async Task<ApplicationUserData[]> GetUsers(CancellationToken token = default)
|
||||
{
|
||||
var response = await _httpClient.SendAsync(CreateHttpRequest($"api/v1/users/", null, HttpMethod.Get), token);
|
||||
return await HandleResponse<ApplicationUserData[]>(response);
|
||||
|
@ -8,7 +8,7 @@ public class AssetPairData
|
||||
public AssetPairData()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
public AssetPairData(string assetBought, string assetSold, decimal minimumTradeQty)
|
||||
{
|
||||
AssetBought = assetBought;
|
||||
@ -25,7 +25,7 @@ public class AssetPairData
|
||||
[JsonProperty]
|
||||
public decimal MinimumTradeQty { set; get; }
|
||||
|
||||
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return AssetBought + "/" + AssetSold;
|
||||
|
@ -11,14 +11,14 @@ namespace BTCPayServer.Client.Models
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
public CreateLightningInvoiceRequest(LightMoney amount, string description, TimeSpan expiry)
|
||||
{
|
||||
Amount = amount;
|
||||
Description = description;
|
||||
Expiry = expiry;
|
||||
}
|
||||
|
||||
|
||||
[JsonConverter(typeof(JsonConverters.LightMoneyJsonConverter))]
|
||||
public LightMoney Amount { get; set; }
|
||||
public string Description { get; set; }
|
||||
|
@ -5,11 +5,11 @@ namespace BTCPayServer.Client.Models
|
||||
public abstract class CustodianAccountBaseData
|
||||
{
|
||||
public string CustodianCode { get; set; }
|
||||
|
||||
|
||||
public string Name { get; set; }
|
||||
|
||||
|
||||
public string StoreId { get; set; }
|
||||
|
||||
|
||||
public JObject Config { get; set; }
|
||||
}
|
||||
|
||||
|
@ -2,13 +2,13 @@ using System.Collections.Generic;
|
||||
|
||||
namespace BTCPayServer.Client.Models;
|
||||
|
||||
public class CustodianAccountResponse: CustodianAccountData
|
||||
public class CustodianAccountResponse : CustodianAccountData
|
||||
{
|
||||
public IDictionary<string, decimal> AssetBalances { get; set; }
|
||||
|
||||
public CustodianAccountResponse()
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -9,5 +9,5 @@ public class CustodianData
|
||||
public Dictionary<string, AssetPairData> TradableAssetPairs { get; set; }
|
||||
public string[] WithdrawablePaymentMethods { get; set; }
|
||||
public string[] DepositablePaymentMethods { get; set; }
|
||||
|
||||
|
||||
}
|
||||
|
@ -6,10 +6,10 @@ public class DepositAddressData
|
||||
// * Example: P2PKH, P2SH, P2WPKH, P2TR, BOLT11, ...
|
||||
// */
|
||||
// public string Type { get; set; }
|
||||
|
||||
|
||||
/**
|
||||
* Format depends hugely on the type.
|
||||
*/
|
||||
public string Address { get; set; }
|
||||
|
||||
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using BTCPayServer.Client.JsonConverters;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
@ -7,7 +7,7 @@ namespace BTCPayServer.Client.Models;
|
||||
public class LightningAutomatedPayoutSettings
|
||||
{
|
||||
public string PaymentMethod { get; set; }
|
||||
|
||||
|
||||
[JsonConverter(typeof(TimeSpanJsonConverter.Seconds))]
|
||||
public TimeSpan IntervalSeconds { get; set; }
|
||||
}
|
||||
|
@ -9,10 +9,10 @@ namespace BTCPayServer.Client.Models
|
||||
{
|
||||
[JsonProperty("onchain")]
|
||||
public OnchainBalanceData OnchainBalance { get; set; }
|
||||
|
||||
|
||||
[JsonProperty("offchain")]
|
||||
public OffchainBalanceData OffchainBalance { get; set; }
|
||||
|
||||
|
||||
public LightningNodeBalanceData()
|
||||
{
|
||||
}
|
||||
@ -31,7 +31,7 @@ namespace BTCPayServer.Client.Models
|
||||
|
||||
[JsonConverter(typeof(JsonConverters.MoneyJsonConverter))]
|
||||
public Money Unconfirmed { get; set; }
|
||||
|
||||
|
||||
[JsonConverter(typeof(JsonConverters.MoneyJsonConverter))]
|
||||
public Money Reserved { get; set; }
|
||||
}
|
||||
@ -40,13 +40,13 @@ namespace BTCPayServer.Client.Models
|
||||
{
|
||||
[JsonConverter(typeof(LightMoneyJsonConverter))]
|
||||
public LightMoney Opening { get; set; }
|
||||
|
||||
|
||||
[JsonConverter(typeof(LightMoneyJsonConverter))]
|
||||
public LightMoney Local { get; set; }
|
||||
|
||||
|
||||
[JsonConverter(typeof(LightMoneyJsonConverter))]
|
||||
public LightMoney Remote { get; set; }
|
||||
|
||||
|
||||
[JsonConverter(typeof(LightMoneyJsonConverter))]
|
||||
public LightMoney Closing { get; set; }
|
||||
}
|
||||
|
@ -17,12 +17,12 @@ namespace BTCPayServer.Client.Models
|
||||
|
||||
[JsonProperty("BOLT11")]
|
||||
public string BOLT11 { get; set; }
|
||||
|
||||
|
||||
public string Preimage { get; set; }
|
||||
|
||||
[JsonConverter(typeof(NBitcoin.JsonConverters.DateTimeToUnixTimeConverter))]
|
||||
public DateTimeOffset? CreatedAt { get; set; }
|
||||
|
||||
|
||||
[JsonConverter(typeof(LightMoneyJsonConverter))]
|
||||
public LightMoney TotalAmount { get; set; }
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
namespace BTCPayServer.Client;
|
||||
namespace BTCPayServer.Client;
|
||||
|
||||
public class LockUserRequest
|
||||
{
|
||||
|
@ -16,7 +16,7 @@ public class MarketTradeResponseData
|
||||
public string TradeId { get; }
|
||||
|
||||
public string AccountId { get; }
|
||||
|
||||
|
||||
public string CustodianCode { get; }
|
||||
|
||||
public MarketTradeResponseData(string fromAsset, string toAsset, List<LedgerEntryData> ledgerEntries, string tradeId, string accountId, string custodianCode)
|
||||
|
@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using BTCPayServer.Client.JsonConverters;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
@ -7,9 +7,9 @@ namespace BTCPayServer.Client.Models;
|
||||
public class OnChainAutomatedPayoutSettings
|
||||
{
|
||||
public string PaymentMethod { get; set; }
|
||||
|
||||
|
||||
[JsonConverter(typeof(TimeSpanJsonConverter.Seconds))]
|
||||
public TimeSpan IntervalSeconds { get; set; }
|
||||
|
||||
public int? FeeBlockTarget { get; set; }
|
||||
public int? FeeBlockTarget { get; set; }
|
||||
}
|
||||
|
@ -11,13 +11,13 @@ namespace BTCPayServer.Client.Models
|
||||
{
|
||||
[JsonProperty("BOLT11")]
|
||||
public string BOLT11 { get; set; }
|
||||
|
||||
|
||||
[JsonProperty(ItemConverterType = typeof(NumericStringJsonConverter))]
|
||||
public float? MaxFeePercent { get; set; }
|
||||
|
||||
|
||||
[JsonConverter(typeof(MoneyJsonConverter))]
|
||||
public Money MaxFeeFlat { get; set; }
|
||||
|
||||
|
||||
[JsonConverter(typeof(LightMoneyJsonConverter))]
|
||||
public LightMoney Amount { get; set; }
|
||||
|
||||
|
@ -12,7 +12,7 @@ namespace BTCPayServer.Client.Models
|
||||
[JsonConverter(typeof(NBitcoin.JsonConverters.DateTimeToUnixTimeConverter))]
|
||||
public DateTimeOffset Created { get; set; }
|
||||
}
|
||||
|
||||
|
||||
public class PointOfSaleAppData : AppDataBase
|
||||
{
|
||||
// We can add POS specific things here later
|
||||
|
@ -1,7 +1,7 @@
|
||||
namespace BTCPayServer.Client.Models;
|
||||
namespace BTCPayServer.Client.Models;
|
||||
|
||||
public class RateSource
|
||||
{
|
||||
public string Id { get; set; }
|
||||
public string Name { get; set; }
|
||||
}
|
||||
}
|
||||
|
@ -60,7 +60,7 @@ namespace BTCPayServer.Client.Models
|
||||
public NetworkFeeMode NetworkFeeMode { get; set; } = NetworkFeeMode.Never;
|
||||
|
||||
public bool PayJoinEnabled { get; set; }
|
||||
|
||||
|
||||
public InvoiceData.ReceiptOptions Receipt { get; set; }
|
||||
|
||||
|
||||
|
@ -7,7 +7,7 @@ namespace BTCPayServer.Client.Models
|
||||
/// </summary>
|
||||
public string Id { get; set; }
|
||||
}
|
||||
|
||||
|
||||
public class StoreUserData
|
||||
{
|
||||
/// <summary>
|
||||
|
@ -1,4 +1,4 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace BTCPayServer.Client.Models;
|
||||
|
||||
@ -7,4 +7,4 @@ public class StoreRatePreviewResult
|
||||
public string CurrencyPair { get; set; }
|
||||
public decimal? Rate { get; set; }
|
||||
public List<string> Errors { get; set; }
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
namespace BTCPayServer.Client.Models;
|
||||
namespace BTCPayServer.Client.Models;
|
||||
|
||||
public class StoreRateResult
|
||||
{
|
||||
public string CurrencyPair { get; set; }
|
||||
public decimal Rate { get; set; }
|
||||
}
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ namespace BTCPayServer
|
||||
internal Task ProcessTask;
|
||||
public async Task Process(CancellationToken cancellationToken)
|
||||
{
|
||||
retry:
|
||||
retry:
|
||||
while (Chan.Reader.TryRead(out var item))
|
||||
{
|
||||
await item(cancellationToken);
|
||||
@ -52,7 +52,7 @@ namespace BTCPayServer
|
||||
{
|
||||
lock (_Queues)
|
||||
{
|
||||
retry:
|
||||
retry:
|
||||
if (stopped)
|
||||
return;
|
||||
Cleanup();
|
||||
|
@ -67,7 +67,7 @@ namespace BTCPayServer.Data
|
||||
public DbSet<WalletTransactionData> WalletTransactions { get; set; }
|
||||
public DbSet<WebhookDeliveryData> WebhookDeliveries { get; set; }
|
||||
public DbSet<WebhookData> Webhooks { get; set; }
|
||||
public DbSet<LightningAddressData> LightningAddresses{ get; set; }
|
||||
public DbSet<LightningAddressData> LightningAddresses { get; set; }
|
||||
public DbSet<PayoutProcessorData> PayoutProcessors { get; set; }
|
||||
|
||||
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
|
||||
|
@ -14,28 +14,28 @@ public class CustodianAccountData
|
||||
[Required]
|
||||
[MaxLength(50)]
|
||||
public string StoreId { get; set; }
|
||||
|
||||
|
||||
[Required]
|
||||
[MaxLength(50)]
|
||||
public string CustodianCode { get; set; }
|
||||
|
||||
|
||||
[Required]
|
||||
[MaxLength(50)]
|
||||
public string Name { get; set; }
|
||||
|
||||
|
||||
[JsonIgnore]
|
||||
public byte[] Blob { get; set; }
|
||||
|
||||
|
||||
[JsonIgnore]
|
||||
public StoreData StoreData { get; set; }
|
||||
|
||||
|
||||
internal static void OnModelCreating(ModelBuilder builder)
|
||||
{
|
||||
builder.Entity<CustodianAccountData>()
|
||||
.HasOne(o => o.StoreData)
|
||||
.WithMany(i => i.CustodianAccounts)
|
||||
.HasForeignKey(i => i.StoreId).OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
|
||||
builder.Entity<APIKeyData>()
|
||||
.HasIndex(o => o.StoreId);
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace BTCPayServer.Data;
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace BTCPayServer.Data.Data;
|
||||
@ -11,9 +11,9 @@ public class PayoutProcessorData
|
||||
public StoreData Store { get; set; }
|
||||
public string PaymentMethod { get; set; }
|
||||
public string Processor { get; set; }
|
||||
|
||||
|
||||
public byte[] Blob { get; set; }
|
||||
|
||||
|
||||
internal static void OnModelCreating(ModelBuilder builder)
|
||||
{
|
||||
|
||||
|
@ -11,7 +11,7 @@ public class StoreSettingData
|
||||
public string Value { get; set; }
|
||||
|
||||
public StoreData Store { get; set; }
|
||||
|
||||
|
||||
public static void OnModelCreating(ModelBuilder builder, DatabaseFacade databaseFacade)
|
||||
{
|
||||
builder.Entity<StoreSettingData>().HasKey(data => new { data.StoreId, data.Name });
|
||||
|
@ -2,5 +2,5 @@ namespace BTCPayServer.Data;
|
||||
|
||||
public class TradeResultData
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using System;
|
||||
using BTCPayServer.Data;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||
|
||||
|
@ -57,8 +57,8 @@ namespace BTCPayServer.PluginPacker
|
||||
|
||||
var sha256sums = new StringBuilder();
|
||||
sha256sums.AppendLine(
|
||||
$"{Encoders.Hex.EncodeData(Hashes.SHA256(Encoding.UTF8.GetBytes(json)))} {name}.btcpay.json");
|
||||
|
||||
$"{Encoders.Hex.EncodeData(Hashes.SHA256(Encoding.UTF8.GetBytes(json)))} {name}.btcpay.json");
|
||||
|
||||
sha256sums.AppendLine(
|
||||
$"{Encoders.Hex.EncodeData(Hashes.SHA256(await File.ReadAllBytesAsync(outputFile + ".btcpay")))} {name}.btcpay");
|
||||
|
||||
@ -68,7 +68,7 @@ namespace BTCPayServer.PluginPacker
|
||||
File.Delete(sha256dirs);
|
||||
}
|
||||
await File.WriteAllTextAsync(sha256dirs, sha256sums.ToString());
|
||||
|
||||
|
||||
// try Windows executable first, fall back to macOS/Linux PowerShell
|
||||
try
|
||||
{
|
||||
@ -86,7 +86,7 @@ namespace BTCPayServer.PluginPacker
|
||||
$"Attempted to sign hashes with gpg but maybe powershell is not installed?\n{ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Console.WriteLine($"Created {outputFile}.btcpay at {directory}");
|
||||
}
|
||||
|
||||
|
@ -27,8 +27,8 @@ namespace BTCPayServer.Rating
|
||||
Url = url;
|
||||
Source = source;
|
||||
}
|
||||
|
||||
public string DisplayName =>
|
||||
|
||||
public string DisplayName =>
|
||||
Source switch
|
||||
{
|
||||
RateSource.Direct => Name,
|
||||
|
@ -1,4 +1,4 @@
|
||||
using System.Net.Http;
|
||||
using System.Net.Http;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Rating;
|
||||
|
@ -23,7 +23,7 @@ namespace BTCPayServer.Services.Rates
|
||||
{
|
||||
await new SynchronizationContextRemover();
|
||||
|
||||
var exchangeAPI = (T) await ExchangeAPI.GetExchangeAPIAsync<T>();
|
||||
var exchangeAPI = (T)await ExchangeAPI.GetExchangeAPIAsync<T>();
|
||||
exchangeAPI.RequestMaker = new HttpClientRequestMaker(exchangeAPI, _httpClient, cancellationToken);
|
||||
var rates = await exchangeAPI.GetTickersAsync();
|
||||
|
||||
|
@ -177,11 +177,11 @@ namespace BTCPayServer.Services.Rates
|
||||
var result = JsonConvert.DeserializeObject<T>(stringResult);
|
||||
if (result is JToken json)
|
||||
{
|
||||
if (!(json is JArray) && json["result"] is JObject {Count: > 0} pairResult)
|
||||
if (!(json is JArray) && json["result"] is JObject { Count: > 0 } pairResult)
|
||||
{
|
||||
return (T)(object)(pairResult);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!(json is JArray) && json["error"] is JArray error && error.Count != 0)
|
||||
{
|
||||
throw new APIException(string.Join("\n",
|
||||
|
@ -7,8 +7,8 @@ using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Rating;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace BTCPayServer.Services.Rates
|
||||
{
|
||||
|
@ -58,14 +58,14 @@ namespace BTCPayServer.Tests
|
||||
s.GoToProfile(ManageNavPages.APIKeys);
|
||||
s.Driver.FindElement(By.Id("AddApiKey")).Click();
|
||||
Assert.Contains("btcpay.server.canmodifyserversettings", s.Driver.PageSource);
|
||||
|
||||
|
||||
//server management should show now
|
||||
s.Driver.SetCheckbox(By.Id("btcpay.server.canmodifyserversettings"), true);
|
||||
s.Driver.SetCheckbox(By.Id("btcpay.store.canmodifystoresettings"), true);
|
||||
s.Driver.SetCheckbox(By.Id("btcpay.user.canviewprofile"), true);
|
||||
s.Driver.FindElement(By.Id("Generate")).Click();
|
||||
var superApiKey = s.FindAlertMessage().FindElement(By.TagName("code")).Text;
|
||||
|
||||
|
||||
//this api key has access to everything
|
||||
await TestApiAgainstAccessToken(superApiKey, tester, user, Policies.CanModifyServerSettings, Policies.CanModifyStoreSettings, Policies.CanViewProfile);
|
||||
|
||||
@ -75,7 +75,7 @@ namespace BTCPayServer.Tests
|
||||
var serverOnlyApiKey = s.FindAlertMessage().FindElement(By.TagName("code")).Text;
|
||||
await TestApiAgainstAccessToken(serverOnlyApiKey, tester, user,
|
||||
Policies.CanModifyServerSettings);
|
||||
|
||||
|
||||
s.Driver.FindElement(By.Id("AddApiKey")).Click();
|
||||
s.Driver.SetCheckbox(By.Id("btcpay.store.canmodifystoresettings"), true);
|
||||
s.Driver.FindElement(By.Id("Generate")).Click();
|
||||
@ -108,7 +108,7 @@ namespace BTCPayServer.Tests
|
||||
await TestApiAgainstAccessToken<bool>("incorrect key", $"{TestApiPath}/me/id",
|
||||
tester.PayTester.HttpClient);
|
||||
});
|
||||
|
||||
|
||||
TestLogs.LogInformation("Checking authorize screen");
|
||||
|
||||
//let's test the authorized screen now
|
||||
@ -124,35 +124,35 @@ namespace BTCPayServer.Tests
|
||||
var callbackUrl = s.ServerUri + "postredirect-callback-test";
|
||||
var authUrl = BTCPayServerClient.GenerateAuthorizeUri(s.ServerUri,
|
||||
new[] { Policies.CanModifyServerSettings }, applicationDetails: (appidentifier, new Uri(callbackUrl))).ToString();
|
||||
|
||||
|
||||
// No upfront store selection with only server settings
|
||||
s.GoToUrl(authUrl);
|
||||
Assert.Contains(appidentifier, s.Driver.PageSource);
|
||||
Assert.True(s.Driver.ElementDoesNotExist(By.CssSelector("select#StoreId")));
|
||||
|
||||
|
||||
// No upfront store selection with selectiveStores being false
|
||||
authUrl = BTCPayServerClient.GenerateAuthorizeUri(s.ServerUri,
|
||||
new[] { Policies.CanModifyStoreSettings, Policies.CanModifyServerSettings }, selectiveStores: false, applicationDetails: (appidentifier, new Uri(callbackUrl))).ToString();
|
||||
s.GoToUrl(authUrl);
|
||||
Assert.True(s.Driver.ElementDoesNotExist(By.CssSelector("select#StoreId")));
|
||||
|
||||
|
||||
// Now with store settings
|
||||
authUrl = BTCPayServerClient.GenerateAuthorizeUri(s.ServerUri,
|
||||
new[] { Policies.CanModifyStoreSettings, Policies.CanModifyServerSettings }, selectiveStores: true, applicationDetails: (appidentifier, new Uri(callbackUrl))).ToString();
|
||||
s.GoToUrl(authUrl);
|
||||
Assert.Contains(appidentifier, s.Driver.PageSource);
|
||||
|
||||
|
||||
// Select a store
|
||||
var select = new SelectElement(s.Driver.FindElement(By.Id("StoreId")));
|
||||
select.SelectByIndex(0);
|
||||
s.Driver.FindElement(By.Id("continue")).Click();
|
||||
|
||||
|
||||
Assert.Equal("hidden", s.Driver.FindElement(By.Id("btcpay.store.canmodifystoresettings")).GetAttribute("type").ToLowerInvariant());
|
||||
Assert.Equal("true", s.Driver.FindElement(By.Id("btcpay.store.canmodifystoresettings")).GetAttribute("value").ToLowerInvariant());
|
||||
Assert.Equal("hidden", s.Driver.FindElement(By.Id("btcpay.server.canmodifyserversettings")).GetAttribute("type").ToLowerInvariant());
|
||||
Assert.Equal("true", s.Driver.FindElement(By.Id("btcpay.server.canmodifyserversettings")).GetAttribute("value").ToLowerInvariant());
|
||||
Assert.DoesNotContain("change-store-mode", s.Driver.PageSource);
|
||||
|
||||
|
||||
s.Driver.WaitForAndClick(By.Id("consent-yes"));
|
||||
Assert.Equal(callbackUrl, s.Driver.Url);
|
||||
|
||||
@ -192,12 +192,12 @@ namespace BTCPayServer.Tests
|
||||
|
||||
//if it's the same, go to the confirm page
|
||||
s.GoToUrl(authUrl);
|
||||
|
||||
|
||||
// Select the same store
|
||||
select = new SelectElement(s.Driver.FindElement(By.Id("StoreId")));
|
||||
select.SelectByIndex(0);
|
||||
s.Driver.FindElement(By.Id("continue")).Click();
|
||||
|
||||
|
||||
Assert.Contains("previously generated the API Key", s.Driver.PageSource);
|
||||
s.Driver.WaitForAndClick(By.Id("continue"));
|
||||
Assert.Equal(callbackUrl, s.Driver.Url);
|
||||
@ -207,12 +207,12 @@ namespace BTCPayServer.Tests
|
||||
new[] { Policies.CanModifyStoreSettings, Policies.CanModifyServerSettings }, false, true, (appidentifier, new Uri("https://international.local/callback"))).ToString();
|
||||
|
||||
s.GoToUrl(authUrl);
|
||||
|
||||
|
||||
// Select the same store
|
||||
select = new SelectElement(s.Driver.FindElement(By.Id("StoreId")));
|
||||
select.SelectByIndex(0);
|
||||
s.Driver.FindElement(By.Id("continue")).Click();
|
||||
|
||||
|
||||
Assert.DoesNotContain("previously generated the API Key", s.Driver.PageSource);
|
||||
Assert.False(s.Driver.Url.StartsWith("https://international.com/callback"));
|
||||
|
||||
@ -230,11 +230,11 @@ namespace BTCPayServer.Tests
|
||||
TestLogs.LogInformation("Generating API key");
|
||||
s.Driver.WaitForAndClick(By.Id("Generate"));
|
||||
var allAPIKey = s.FindAlertMessage().FindElement(By.TagName("code")).Text;
|
||||
|
||||
|
||||
TestLogs.LogInformation($"Checking API key permissions: {allAPIKey}");
|
||||
var apikeydata = await TestApiAgainstAccessToken<ApiKeyData>(allAPIKey, "api/v1/api-keys/current", tester.PayTester.HttpClient);
|
||||
Assert.Equal(checkedPermissionCount, apikeydata.Permissions.Length);
|
||||
|
||||
|
||||
TestLogs.LogInformation("Checking empty permissions");
|
||||
authUrl = BTCPayServerClient.GenerateAuthorizeUri(s.ServerUri, Array.Empty<string>(), false, true).ToString();
|
||||
s.GoToUrl(authUrl);
|
||||
@ -279,10 +279,10 @@ namespace BTCPayServer.Tests
|
||||
var canModifyServer = Permission.Create(Policies.CanModifyServerSettings);
|
||||
var unrestricted = Permission.Create(Policies.Unrestricted);
|
||||
var selectiveStorePermissions = permissions.Where(p => p.Scope != null && p.Policy == Policies.CanModifyStoreSettings);
|
||||
|
||||
|
||||
TestLogs.LogInformation("Testing can edit store for first user");
|
||||
IEnumerable<Permission> storePermissions = selectiveStorePermissions as Permission[] ?? selectiveStorePermissions.ToArray();
|
||||
|
||||
|
||||
if (permissions.Contains(canModifyAllStores) || storePermissions.Any())
|
||||
{
|
||||
var resultStores =
|
||||
|
@ -16,11 +16,11 @@ namespace BTCPayServer.Tests
|
||||
public class CheckoutV2Tests : UnitTestBase
|
||||
{
|
||||
private const int TestTimeout = TestUtils.TestTimeout;
|
||||
|
||||
|
||||
public CheckoutV2Tests(ITestOutputHelper helper) : base(helper)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
[Fact(Timeout = TestTimeout)]
|
||||
[Trait("Lightning", "Lightning")]
|
||||
public async Task CanConfigureCheckout()
|
||||
@ -41,20 +41,20 @@ namespace BTCPayServer.Tests
|
||||
s.Driver.FindElement(By.Id("StoreWebsite")).SendKeys(storeUrl);
|
||||
s.Driver.FindElement(By.Id("Save")).Click();
|
||||
Assert.Contains("Store successfully updated", s.FindAlertMessage().Text);
|
||||
|
||||
|
||||
// Default payment method
|
||||
var invoiceId = s.CreateInvoice(defaultPaymentMethod: "BTC_LightningLike");
|
||||
s.GoToInvoiceCheckout(invoiceId);
|
||||
|
||||
|
||||
// Ensure we are seeing Checkout v2
|
||||
s.Driver.WaitUntilAvailable(By.Id("Checkout-v2"));
|
||||
|
||||
|
||||
Assert.Equal(2, s.Driver.FindElements(By.CssSelector(".payment-method")).Count);
|
||||
Assert.Contains("Lightning", s.Driver.WaitForElement(By.CssSelector(".payment-method.active")).Text);
|
||||
Assert.DoesNotContain("LNURL", s.Driver.PageSource);
|
||||
var payUrl = s.Driver.FindElement(By.CssSelector(".btn-primary")).GetAttribute("href");
|
||||
Assert.StartsWith("lightning:", payUrl);
|
||||
|
||||
|
||||
// Lightning amount in Sats
|
||||
Assert.Contains("BTC", s.Driver.FindElement(By.Id("AmountDue")).Text);
|
||||
s.GoToHome();
|
||||
@ -64,7 +64,7 @@ namespace BTCPayServer.Tests
|
||||
Assert.Contains("BTC Lightning settings successfully updated", s.FindAlertMessage().Text);
|
||||
s.GoToInvoiceCheckout(invoiceId);
|
||||
Assert.Contains("Sats", s.Driver.FindElement(By.Id("AmountDue")).Text);
|
||||
|
||||
|
||||
// Expire
|
||||
var expirySeconds = s.Driver.FindElement(By.Id("ExpirySeconds"));
|
||||
expirySeconds.Clear();
|
||||
@ -82,12 +82,12 @@ namespace BTCPayServer.Tests
|
||||
});
|
||||
Assert.True(s.Driver.ElementDoesNotExist(By.Id("ReceiptLink")));
|
||||
Assert.Equal(storeUrl, s.Driver.FindElement(By.Id("StoreLink")).GetAttribute("href"));
|
||||
|
||||
|
||||
// Test payment
|
||||
s.GoToHome();
|
||||
invoiceId = s.CreateInvoice();
|
||||
s.GoToInvoiceCheckout(invoiceId);
|
||||
|
||||
|
||||
// Details
|
||||
s.Driver.ToggleCollapse("PaymentDetails");
|
||||
var details = s.Driver.FindElement(By.CssSelector(".payment-details"));
|
||||
@ -96,7 +96,7 @@ namespace BTCPayServer.Tests
|
||||
Assert.Contains("Exchange Rate", details.Text);
|
||||
Assert.Contains("Amount Due", details.Text);
|
||||
Assert.Contains("Recommended Fee", details.Text);
|
||||
|
||||
|
||||
// Pay partial amount
|
||||
await Task.Delay(200);
|
||||
var address = s.Driver.FindElement(By.CssSelector(".qr-container")).GetAttribute("data-destination");
|
||||
@ -104,7 +104,7 @@ namespace BTCPayServer.Tests
|
||||
await s.Server.ExplorerNode.SendToAddressAsync(BitcoinAddress.Create(address, Network.RegTest),
|
||||
Money.Parse(amountFraction));
|
||||
await s.Server.ExplorerNode.GenerateAsync(1);
|
||||
|
||||
|
||||
// Fake Pay
|
||||
s.Driver.FindElement(By.Id("FakePayAmount")).FillIn(amountFraction);
|
||||
s.Driver.FindElement(By.Id("FakePay")).Click();
|
||||
@ -125,7 +125,7 @@ namespace BTCPayServer.Tests
|
||||
Assert.Contains("Mined 1 block",
|
||||
s.Driver.WaitForElement(By.Id("CheatSuccessMessage")).Text);
|
||||
});
|
||||
|
||||
|
||||
// Pay full amount
|
||||
var amountDue = s.Driver.FindElement(By.Id("AmountDue")).GetAttribute("data-amount-due");
|
||||
s.Driver.FindElement(By.Id("FakePayAmount")).FillIn(amountDue);
|
||||
@ -139,21 +139,21 @@ namespace BTCPayServer.Tests
|
||||
});
|
||||
s.Driver.FindElement(By.Id("ReceiptLink"));
|
||||
Assert.Equal(storeUrl, s.Driver.FindElement(By.Id("StoreLink")).GetAttribute("href"));
|
||||
|
||||
|
||||
// BIP21
|
||||
s.GoToHome();
|
||||
s.GoToStore(StoreNavPages.CheckoutAppearance);
|
||||
s.Driver.SetCheckbox(By.Id("OnChainWithLnInvoiceFallback"), true);
|
||||
s.Driver.FindElement(By.Id("Save")).Click();
|
||||
Assert.Contains("Store successfully updated", s.FindAlertMessage().Text);
|
||||
|
||||
|
||||
invoiceId = s.CreateInvoice();
|
||||
s.GoToInvoiceCheckout(invoiceId);
|
||||
Assert.Empty(s.Driver.FindElements(By.CssSelector(".payment-method")));
|
||||
payUrl = s.Driver.FindElement(By.CssSelector(".btn-primary")).GetAttribute("href");
|
||||
Assert.StartsWith("bitcoin:", payUrl);
|
||||
Assert.Contains("&LIGHTNING=", payUrl);
|
||||
|
||||
|
||||
// BIP21 with LN as default payment method
|
||||
s.GoToHome();
|
||||
invoiceId = s.CreateInvoice(defaultPaymentMethod: "BTC_LightningLike");
|
||||
@ -162,7 +162,7 @@ namespace BTCPayServer.Tests
|
||||
payUrl = s.Driver.FindElement(By.CssSelector(".btn-primary")).GetAttribute("href");
|
||||
Assert.StartsWith("bitcoin:", payUrl);
|
||||
Assert.Contains("&LIGHTNING=", payUrl);
|
||||
|
||||
|
||||
// BIP21 with topup invoice (which is only available with Bitcoin onchain)
|
||||
s.GoToHome();
|
||||
invoiceId = s.CreateInvoice(amount: null);
|
||||
@ -171,7 +171,7 @@ namespace BTCPayServer.Tests
|
||||
payUrl = s.Driver.FindElement(By.CssSelector(".btn-primary")).GetAttribute("href");
|
||||
Assert.StartsWith("bitcoin:", payUrl);
|
||||
Assert.DoesNotContain("&LIGHTNING=", payUrl);
|
||||
|
||||
|
||||
// Expiry message should not show amount for topup invoice
|
||||
expirySeconds = s.Driver.FindElement(By.Id("ExpirySeconds"));
|
||||
expirySeconds.Clear();
|
||||
@ -199,12 +199,12 @@ namespace BTCPayServer.Tests
|
||||
s.Driver.Navigate()
|
||||
.GoToUrl(new Uri(s.ServerUri, $"tests/index.html?invoice={invoiceId}"));
|
||||
s.Driver.WaitUntilAvailable(By.Name("btcpay"));
|
||||
|
||||
|
||||
var frameElement = s.Driver.FindElement(By.Name("btcpay"));
|
||||
Assert.True(frameElement.Displayed);
|
||||
var iframe = s.Driver.SwitchTo().Frame(frameElement);
|
||||
iframe.WaitUntilAvailable(By.Id("Checkout-v2"));
|
||||
|
||||
|
||||
await s.Server.ExplorerNode.SendToAddressAsync(BitcoinAddress.Create(invoice
|
||||
.GetPaymentMethod(new PaymentMethodId("BTC", PaymentTypes.BTCLike))
|
||||
.GetPaymentMethodDetails().GetPaymentDestination(), Network.RegTest),
|
||||
|
@ -138,7 +138,7 @@ retry:
|
||||
el.Clear();
|
||||
el.SendKeys(text);
|
||||
}
|
||||
|
||||
|
||||
public static void ScrollTo(this IWebDriver driver, IWebElement element)
|
||||
{
|
||||
driver.ExecuteJavaScript("arguments[0].scrollIntoView();", element);
|
||||
@ -148,7 +148,7 @@ retry:
|
||||
{
|
||||
ScrollTo(driver, driver.FindElement(selector));
|
||||
}
|
||||
|
||||
|
||||
public static void WaitUntilAvailable(this IWebDriver driver, By selector, TimeSpan? waitTime = null)
|
||||
{
|
||||
// Try fast path
|
||||
@ -165,7 +165,7 @@ retry:
|
||||
wait.UntilJsIsReady();
|
||||
|
||||
int retriesLeft = 4;
|
||||
retry:
|
||||
retry:
|
||||
try
|
||||
{
|
||||
var el = driver.FindElement(selector);
|
||||
@ -176,18 +176,19 @@ retry:
|
||||
catch (NoSuchElementException) when (retriesLeft > 0)
|
||||
{
|
||||
retriesLeft--;
|
||||
if (waitTime != null) Thread.Sleep(waitTime.Value);
|
||||
if (waitTime != null)
|
||||
Thread.Sleep(waitTime.Value);
|
||||
goto retry;
|
||||
}
|
||||
wait.UntilJsIsReady();
|
||||
}
|
||||
|
||||
|
||||
public static void WaitForAndClick(this IWebDriver driver, By selector)
|
||||
{
|
||||
driver.WaitUntilAvailable(selector);
|
||||
driver.FindElement(selector).Click();
|
||||
}
|
||||
|
||||
|
||||
public static bool ElementDoesNotExist(this IWebDriver driver, By selector)
|
||||
{
|
||||
Assert.Throws<NoSuchElementException>(() =>
|
||||
|
@ -672,7 +672,7 @@ namespace BTCPayServer.Tests
|
||||
Assert.Equal(3, inner.Keys.Count);
|
||||
Assert.Equal(2, inner.RequiredSignatures);
|
||||
Assert.Equal(expected, inner.ToString());
|
||||
|
||||
|
||||
// Output Descriptor
|
||||
networkProvider = new BTCPayNetworkProvider(ChainName.Mainnet);
|
||||
parser = new DerivationSchemeParser(networkProvider.BTC);
|
||||
@ -681,7 +681,7 @@ namespace BTCPayServer.Tests
|
||||
Assert.Single(rootedKeyPath);
|
||||
Assert.IsType<DirectDerivationStrategy>(strategyBase);
|
||||
Assert.True(((DirectDerivationStrategy)strategyBase).Segwit);
|
||||
|
||||
|
||||
// Failure cases
|
||||
Assert.Throws<FormatException>(() => { parser.Parse("xpub 661MyMwAqRbcGVBsTGeNZN6QGVHmMHLdSA4FteGsRrEriu4pnVZMZWnruFFFXkMnyoBjyHndD3Qwcfz4MPzBUxjSevweNFQx7SAYZATtcDw"); }); // invalid format because of space
|
||||
Assert.Throws<ParsingException>(() => { parser.ParseOutputDescriptor("invalid"); }); // invalid in general
|
||||
@ -744,7 +744,7 @@ namespace BTCPayServer.Tests
|
||||
Assert.Equal("49'/0'/0'", specter.AccountKeySettings[0].AccountKeyPath.ToString());
|
||||
Assert.Equal("Specter", specter.Label);
|
||||
Assert.Null(error);
|
||||
|
||||
|
||||
// Failure case
|
||||
Assert.False(DerivationSchemeSettings.TryParseFromWalletFile(
|
||||
"{\"keystore\": {\"ckcc_xpub\": \"tpubFailure\", \"xpub\": \"tpubFailure\", \"label\": \"Failure\"}, \"wallet_type\": \"standard\"}",
|
||||
@ -1077,7 +1077,8 @@ namespace BTCPayServer.Tests
|
||||
{
|
||||
MultiProcessingQueueTest t = new MultiProcessingQueueTest();
|
||||
t.Tcs = new TaskCompletionSource();
|
||||
q.Enqueue(queueName, async (cancellationToken) => {
|
||||
q.Enqueue(queueName, async (cancellationToken) =>
|
||||
{
|
||||
t.Started = true;
|
||||
try
|
||||
{
|
||||
@ -1774,11 +1775,11 @@ namespace BTCPayServer.Tests
|
||||
{
|
||||
foreach (var policy in Policies.AllPolicies)
|
||||
{
|
||||
Assert.True( UIManageController.AddApiKeyViewModel.PermissionValueItem.PermissionDescriptions.ContainsKey(policy));
|
||||
if (Policies.IsStorePolicy(policy))
|
||||
{
|
||||
Assert.True( UIManageController.AddApiKeyViewModel.PermissionValueItem.PermissionDescriptions.ContainsKey($"{policy}:"));
|
||||
}
|
||||
Assert.True(UIManageController.AddApiKeyViewModel.PermissionValueItem.PermissionDescriptions.ContainsKey(policy));
|
||||
if (Policies.IsStorePolicy(policy))
|
||||
{
|
||||
Assert.True(UIManageController.AddApiKeyViewModel.PermissionValueItem.PermissionDescriptions.ContainsKey($"{policy}:"));
|
||||
}
|
||||
}
|
||||
}
|
||||
[Fact]
|
||||
@ -1804,8 +1805,8 @@ namespace BTCPayServer.Tests
|
||||
PaymentMethod = new PaymentMethodId("BTC", PaymentTypes.BTCLike)
|
||||
}
|
||||
};
|
||||
var newBlob = new Serializer(null).ToString(blob).Replace( "paymentMethod\":\"BTC\"","paymentMethod\":\"ETH_ZYC\"");
|
||||
Assert.Empty(StoreDataExtensions.GetStoreBlob(new StoreData() {StoreBlob = newBlob}).PaymentMethodCriteria);
|
||||
var newBlob = new Serializer(null).ToString(blob).Replace("paymentMethod\":\"BTC\"", "paymentMethod\":\"ETH_ZYC\"");
|
||||
Assert.Empty(StoreDataExtensions.GetStoreBlob(new StoreData() { StoreBlob = newBlob }).PaymentMethodCriteria);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -77,7 +77,7 @@ public class MockCustodian : ICustodian, ICanDeposit, ICanTrade, ICanWithdraw
|
||||
public List<AssetPairData> GetTradableAssetPairs()
|
||||
{
|
||||
var r = new List<AssetPairData>();
|
||||
r.Add(new AssetPairData("BTC", "EUR", (decimal) 0.0001));
|
||||
r.Add(new AssetPairData("BTC", "EUR", (decimal)0.0001));
|
||||
return r;
|
||||
}
|
||||
|
||||
|
@ -21,7 +21,7 @@ namespace BTCPayServer.Tests
|
||||
public PSBTTests(ITestOutputHelper helper) : base(helper)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
[Fact]
|
||||
[Trait("Selenium", "Selenium")]
|
||||
public async Task CanPlayWithPSBT()
|
||||
|
@ -395,9 +395,9 @@ namespace BTCPayServer.Tests
|
||||
s.GoToWallet(receiverWalletId, WalletsNavPages.Transactions);
|
||||
Assert.Contains(invoiceId, s.Driver.PageSource);
|
||||
Assert.Contains("payjoin", s.Driver.PageSource);
|
||||
//this label does not always show since input gets used
|
||||
// Assert.Contains("payjoin-exposed", s.Driver.PageSource);
|
||||
});
|
||||
//this label does not always show since input gets used
|
||||
// Assert.Contains("payjoin-exposed", s.Driver.PageSource);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -46,7 +46,7 @@ namespace BTCPayServer.Tests
|
||||
// Reset this using `dotnet user-secrets remove RunSeleniumInBrowser`
|
||||
|
||||
var chromeDriverPath = config["ChromeDriverDirectory"] ?? (Server.PayTester.InContainer ? "/usr/bin" : Directory.GetCurrentDirectory());
|
||||
|
||||
|
||||
var options = new ChromeOptions();
|
||||
if (!runInBrowser)
|
||||
{
|
||||
@ -284,12 +284,12 @@ namespace BTCPayServer.Tests
|
||||
{
|
||||
AddLightningNode(null, null, true);
|
||||
}
|
||||
|
||||
|
||||
public void AddLightningNode(LightningConnectionType? connectionType = null, bool test = true)
|
||||
{
|
||||
AddLightningNode(null, connectionType, test);
|
||||
}
|
||||
|
||||
|
||||
public void AddLightningNode(string cryptoCode = null, LightningConnectionType? connectionType = null, bool test = true)
|
||||
{
|
||||
cryptoCode ??= "BTC";
|
||||
@ -405,7 +405,7 @@ namespace BTCPayServer.Tests
|
||||
{
|
||||
GoToStore(null, storeNavPage);
|
||||
}
|
||||
|
||||
|
||||
public void GoToStore(string storeId, StoreNavPages storeNavPage = StoreNavPages.General)
|
||||
{
|
||||
if (storeId is not null)
|
||||
@ -415,7 +415,7 @@ namespace BTCPayServer.Tests
|
||||
if (WalletId != null)
|
||||
WalletId = new WalletId(storeId, WalletId.CryptoCode);
|
||||
}
|
||||
|
||||
|
||||
Driver.FindElement(By.Id("StoreNav-StoreSettings")).Click();
|
||||
|
||||
if (storeNavPage != StoreNavPages.General)
|
||||
@ -434,7 +434,7 @@ namespace BTCPayServer.Tests
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void GoToWalletSettings(string cryptoCode = "BTC")
|
||||
{
|
||||
Driver.FindElement(By.Id($"StoreNav-Wallet{cryptoCode}")).Click();
|
||||
@ -555,7 +555,7 @@ namespace BTCPayServer.Tests
|
||||
for (var i = 0; i < coins; i++)
|
||||
{
|
||||
bool mined = false;
|
||||
retry:
|
||||
retry:
|
||||
try
|
||||
{
|
||||
await Server.ExplorerNode.SendToAddressAsync(address, Money.Coins(denomination));
|
||||
|
@ -63,7 +63,7 @@ namespace BTCPayServer.Tests
|
||||
Assert.Contains("Starting listening NBXplorer", s.Driver.PageSource);
|
||||
s.Driver.Quit();
|
||||
}
|
||||
|
||||
|
||||
[Fact(Timeout = TestTimeout)]
|
||||
public async Task CanUseForms()
|
||||
{
|
||||
@ -72,14 +72,14 @@ namespace BTCPayServer.Tests
|
||||
s.RegisterNewUser(true);
|
||||
s.CreateNewStore();
|
||||
s.GenerateWallet(isHotWallet: true);
|
||||
|
||||
|
||||
// Point Of Sale
|
||||
s.Driver.FindElement(By.Id("StoreNav-CreateApp")).Click();
|
||||
new SelectElement(s.Driver.FindElement(By.Id("SelectedAppType"))).SelectByValue("PointOfSale");
|
||||
s.Driver.FindElement(By.Id("AppName")).SendKeys(Guid.NewGuid().ToString());
|
||||
s.Driver.FindElement(By.Id("Create")).Click();
|
||||
Assert.Contains("App successfully created", s.FindAlertMessage().Text);
|
||||
|
||||
|
||||
new SelectElement(s.Driver.FindElement(By.Id("FormId"))).SelectByValue("Email");
|
||||
s.Driver.FindElement(By.Id("SaveSettings")).Click();
|
||||
Assert.Contains("App updated", s.FindAlertMessage().Text);
|
||||
@ -89,16 +89,16 @@ namespace BTCPayServer.Tests
|
||||
Assert.Equal(2, windows.Count);
|
||||
s.Driver.SwitchTo().Window(windows[1]);
|
||||
s.Driver.FindElement(By.CssSelector("button[type='submit']")).Click();
|
||||
|
||||
|
||||
Assert.Contains("Enter your email", s.Driver.PageSource);
|
||||
s.Driver.FindElement(By.Name("buyerEmail")).SendKeys("aa@aa.com");
|
||||
s.Driver.FindElement(By.CssSelector("input[type='submit']")).Click();
|
||||
|
||||
|
||||
s.PayInvoice(true);
|
||||
var invoiceId = s.Driver.Url[(s.Driver.Url.LastIndexOf("/", StringComparison.Ordinal) + 1)..];
|
||||
s.GoToInvoice(invoiceId);
|
||||
Assert.Contains("aa@aa.com", s.Driver.PageSource);
|
||||
|
||||
|
||||
// Payment Request
|
||||
s.Driver.FindElement(By.Id("StoreNav-PaymentRequests")).Click();
|
||||
s.Driver.FindElement(By.Id("CreatePaymentRequest")).Click();
|
||||
@ -106,19 +106,19 @@ namespace BTCPayServer.Tests
|
||||
s.Driver.FindElement(By.Id("Amount")).SendKeys("700");
|
||||
new SelectElement(s.Driver.FindElement(By.Id("FormId"))).SelectByValue("Email");
|
||||
s.Driver.FindElement(By.Id("SaveButton")).Click();
|
||||
|
||||
|
||||
s.Driver.FindElement(By.XPath("//a[starts-with(@id, 'Edit-')]")).Click();
|
||||
var editUrl = s.Driver.Url;
|
||||
s.Driver.FindElement(By.Id("ViewPaymentRequest")).Click();
|
||||
s.Driver.FindElement(By.CssSelector("[data-test='form-button']")).Click();
|
||||
Assert.Contains("Enter your email", s.Driver.PageSource);
|
||||
|
||||
|
||||
s.Driver.FindElement(By.Name("buyerEmail")).SendKeys("aa@aa.com");
|
||||
s.Driver.FindElement(By.CssSelector("input[type='submit']")).Click();
|
||||
s.Driver.Navigate().GoToUrl(editUrl);
|
||||
Assert.Contains("aa@aa.com", s.Driver.PageSource);
|
||||
}
|
||||
|
||||
|
||||
[Fact(Timeout = TestTimeout)]
|
||||
public async Task CanUseCPFP()
|
||||
{
|
||||
@ -372,7 +372,7 @@ namespace BTCPayServer.Tests
|
||||
using var s = CreateSeleniumTester();
|
||||
await s.StartAsync();
|
||||
s.RegisterNewUser(true);
|
||||
|
||||
|
||||
// Server Emails
|
||||
s.Driver.Navigate().GoToUrl(s.Link("/server/emails"));
|
||||
if (s.Driver.PageSource.Contains("Configured"))
|
||||
@ -382,21 +382,21 @@ namespace BTCPayServer.Tests
|
||||
}
|
||||
CanSetupEmailCore(s);
|
||||
s.CreateNewStore();
|
||||
|
||||
|
||||
// Store Emails
|
||||
s.GoToStore(StoreNavPages.Emails);
|
||||
s.Driver.FindElement(By.Id("ConfigureEmailRules")).Click();
|
||||
Assert.Contains("You need to configure email settings before this feature works", s.Driver.PageSource);
|
||||
|
||||
|
||||
s.GoToStore(StoreNavPages.Emails);
|
||||
CanSetupEmailCore(s);
|
||||
|
||||
|
||||
// Store Email Rules
|
||||
s.Driver.FindElement(By.Id("ConfigureEmailRules")).Click();
|
||||
Assert.Contains("There are no rules yet.", s.Driver.PageSource);
|
||||
Assert.DoesNotContain("id=\"SaveEmailRules\"", s.Driver.PageSource);
|
||||
Assert.DoesNotContain("You need to configure email settings before this feature works", s.Driver.PageSource);
|
||||
|
||||
|
||||
s.Driver.FindElement(By.Id("CreateEmailRule")).Click();
|
||||
var select = new SelectElement(s.Driver.FindElement(By.Id("Rules_0__Trigger")));
|
||||
select.SelectByText("InvoiceSettled", true);
|
||||
@ -456,7 +456,7 @@ namespace BTCPayServer.Tests
|
||||
|
||||
Assert.DoesNotContain("/server/services/dynamic-dns/pouet.hello.com/delete", s.Driver.PageSource);
|
||||
}
|
||||
|
||||
|
||||
[Fact(Timeout = TestTimeout)]
|
||||
public async Task CanCreateInvoiceInUI()
|
||||
{
|
||||
@ -491,7 +491,7 @@ namespace BTCPayServer.Tests
|
||||
s.Driver.FindElements(By.ClassName("changeInvoiceState"))[0].Click();
|
||||
TestUtils.Eventually(() => Assert.Contains("Settled (marked)", s.Driver.PageSource));
|
||||
}
|
||||
|
||||
|
||||
[Fact(Timeout = TestTimeout)]
|
||||
public async Task CanUseInvoiceReceipts()
|
||||
{
|
||||
@ -513,9 +513,9 @@ namespace BTCPayServer.Tests
|
||||
s.Driver.Navigate().Refresh();
|
||||
Assert.DoesNotContain("invoice-unsettled", s.Driver.PageSource);
|
||||
Assert.DoesNotContain("invoice-processing", s.Driver.PageSource);
|
||||
});
|
||||
|
||||
Assert.Contains(s.Server.PayTester.GetService<CurrencyNameTable>().DisplayFormatCurrency(100, "USD"),
|
||||
});
|
||||
|
||||
Assert.Contains(s.Server.PayTester.GetService<CurrencyNameTable>().DisplayFormatCurrency(100, "USD"),
|
||||
s.Driver.PageSource);
|
||||
Assert.Contains(i, s.Driver.PageSource);
|
||||
|
||||
@ -525,7 +525,7 @@ namespace BTCPayServer.Tests
|
||||
var receipturl = s.Driver.Url + "/receipt";
|
||||
s.Driver.Navigate().GoToUrl(receipturl);
|
||||
s.Driver.FindElement(By.Id("invoice-unsettled"));
|
||||
|
||||
|
||||
s.GoToInvoices(s.StoreId);
|
||||
s.GoToInvoiceCheckout(i);
|
||||
var checkouturi = s.Driver.Url;
|
||||
@ -540,19 +540,19 @@ namespace BTCPayServer.Tests
|
||||
s.Driver.Navigate().Refresh();
|
||||
Assert.DoesNotContain("invoice-unsettled", s.Driver.PageSource);
|
||||
Assert.Contains("invoice-processing", s.Driver.PageSource);
|
||||
});
|
||||
});
|
||||
s.GoToUrl(checkouturi);
|
||||
|
||||
await s.Server.PayTester.InvoiceRepository.MarkInvoiceStatus(i, InvoiceStatus.Settled);
|
||||
|
||||
|
||||
TestUtils.Eventually(() => s.Driver.FindElement(By.Id("receipt-btn")).Click());
|
||||
TestUtils.Eventually(() =>
|
||||
{
|
||||
s.Driver.Navigate().Refresh();
|
||||
Assert.DoesNotContain("invoice-unsettled", s.Driver.PageSource);
|
||||
Assert.DoesNotContain("invoice-processing", s.Driver.PageSource);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
[Fact(Timeout = TestTimeout)]
|
||||
@ -571,7 +571,7 @@ namespace BTCPayServer.Tests
|
||||
Assert.Contains("/stores/create", s.Driver.Url);
|
||||
|
||||
(_, string storeId) = s.CreateNewStore();
|
||||
|
||||
|
||||
// should redirect to store
|
||||
s.GoToUrl("/");
|
||||
|
||||
@ -623,7 +623,7 @@ namespace BTCPayServer.Tests
|
||||
Assert.Contains("There are no invoices matching your criteria.", s.Driver.PageSource);
|
||||
var invoiceId = s.CreateInvoice();
|
||||
s.FindAlertMessage();
|
||||
|
||||
|
||||
var invoiceUrl = s.Driver.Url;
|
||||
|
||||
//let's test archiving an invoice
|
||||
@ -737,7 +737,7 @@ namespace BTCPayServer.Tests
|
||||
s.RegisterNewUser();
|
||||
s.CreateNewStore();
|
||||
s.AddDerivationScheme();
|
||||
|
||||
|
||||
s.GoToStore(StoreNavPages.Tokens);
|
||||
s.Driver.FindElement(By.Id("CreateNewToken")).Click();
|
||||
s.Driver.FindElement(By.Id("RequestPairing")).Click();
|
||||
@ -781,7 +781,7 @@ namespace BTCPayServer.Tests
|
||||
s.Driver.FindElement(By.Id("SelectedAppType")).SendKeys("Point of Sale");
|
||||
s.Driver.FindElement(By.Id("Create")).Click();
|
||||
Assert.Contains("App successfully created", s.FindAlertMessage().Text);
|
||||
|
||||
|
||||
s.Driver.FindElement(By.CssSelector(".template-item:nth-of-type(1) .btn-primary")).Click();
|
||||
s.Driver.FindElement(By.Id("BuyButtonText")).SendKeys("Take my money");
|
||||
s.Driver.FindElement(By.Id("SaveItemChanges")).Click();
|
||||
@ -825,7 +825,7 @@ namespace BTCPayServer.Tests
|
||||
// Make sure after login, we are not redirected to the PoS
|
||||
Assert.DoesNotContain("Tea shop", s.Driver.PageSource);
|
||||
var prevUrl = s.Driver.Url;
|
||||
|
||||
|
||||
// We are only if explicitly going to /
|
||||
s.GoToUrl("/");
|
||||
Assert.Contains("Tea shop", s.Driver.PageSource);
|
||||
@ -848,7 +848,7 @@ namespace BTCPayServer.Tests
|
||||
s.LogIn(userId);
|
||||
// Make sure after login, we are not redirected to the PoS
|
||||
Assert.DoesNotContain("Tea shop", s.Driver.PageSource);
|
||||
|
||||
|
||||
// We are only if explicitly going to /
|
||||
s.GoToUrl("/");
|
||||
Assert.Contains("Tea shop", s.Driver.PageSource);
|
||||
@ -868,20 +868,20 @@ namespace BTCPayServer.Tests
|
||||
s.Driver.FindElement(By.Id("SelectedAppType")).SendKeys("Crowdfund");
|
||||
s.Driver.FindElement(By.Id("Create")).Click();
|
||||
Assert.Contains("App successfully created", s.FindAlertMessage().Text);
|
||||
|
||||
|
||||
s.Driver.FindElement(By.Id("Title")).SendKeys("Kukkstarter");
|
||||
s.Driver.FindElement(By.CssSelector("div.note-editable.card-block")).SendKeys("1BTC = 1BTC");
|
||||
s.Driver.FindElement(By.Id("TargetCurrency")).Clear();
|
||||
s.Driver.FindElement(By.Id("TargetCurrency")).SendKeys("JPY");
|
||||
s.Driver.FindElement(By.Id("TargetAmount")).SendKeys("700");
|
||||
|
||||
|
||||
// test wrong dates
|
||||
s.Driver.ExecuteJavaScript("const now = new Date();document.getElementById('StartDate').value = now.toISOString();" +
|
||||
"const yst = new Date(now.setDate(now.getDate() -1));document.getElementById('EndDate').value = yst.toISOString()");
|
||||
s.Driver.FindElement(By.Id("SaveSettings")).Click();
|
||||
Assert.Contains("End date cannot be before start date", s.Driver.PageSource);
|
||||
Assert.DoesNotContain("App updated", s.Driver.PageSource);
|
||||
|
||||
|
||||
// unset end date
|
||||
s.Driver.ExecuteJavaScript("document.getElementById('EndDate').value = ''");
|
||||
s.Driver.FindElement(By.Id("SaveSettings")).Click();
|
||||
@ -894,7 +894,7 @@ namespace BTCPayServer.Tests
|
||||
|
||||
Assert.Equal("currently active!",
|
||||
s.Driver.FindElement(By.CssSelector("[data-test='time-state']")).Text);
|
||||
|
||||
|
||||
s.Driver.Close();
|
||||
s.Driver.SwitchTo().Window(windows[0]);
|
||||
}
|
||||
@ -917,23 +917,23 @@ namespace BTCPayServer.Tests
|
||||
Assert.Equal("USD", currencyInput.GetAttribute("value"));
|
||||
currencyInput.Clear();
|
||||
currencyInput.SendKeys("BTC");
|
||||
|
||||
|
||||
s.Driver.FindElement(By.Id("SaveButton")).Click();
|
||||
s.Driver.FindElement(By.XPath("//a[starts-with(@id, 'Edit-')]")).Click();
|
||||
var editUrl = s.Driver.Url;
|
||||
|
||||
|
||||
s.Driver.FindElement(By.Id("ViewPaymentRequest")).Click();
|
||||
var viewUrl = s.Driver.Url;
|
||||
|
||||
|
||||
Assert.Equal("Amount due", s.Driver.FindElement(By.CssSelector("[data-test='amount-due-title']")).Text);
|
||||
Assert.Equal("Pay Invoice", s.Driver.FindElement(By.CssSelector("[data-test='pay-button']")).Text.Trim());
|
||||
|
||||
|
||||
// expire
|
||||
s.GoToUrl(editUrl);
|
||||
s.Driver.ExecuteJavaScript("document.getElementById('ExpiryDate').value = '2021-01-21T21:00:00.000Z'");
|
||||
s.Driver.FindElement(By.Id("SaveButton")).Click();
|
||||
s.Driver.FindElement(By.XPath("//a[starts-with(@id, 'Edit-')]")).Click();
|
||||
|
||||
|
||||
s.GoToUrl(viewUrl);
|
||||
Assert.Equal("Expired", s.Driver.WaitForElement(By.CssSelector("[data-test='status']")).Text);
|
||||
|
||||
@ -947,22 +947,22 @@ namespace BTCPayServer.Tests
|
||||
s.GoToUrl(editUrl);
|
||||
Assert.True(s.Driver.FindElement(By.Id("Amount")).Enabled);
|
||||
Assert.True(s.Driver.FindElement(By.Id("Currency")).Enabled);
|
||||
|
||||
|
||||
s.GoToUrl(viewUrl);
|
||||
s.Driver.AssertElementNotFound(By.CssSelector("[data-test='status']"));
|
||||
Assert.Equal("Pay Invoice", s.Driver.FindElement(By.CssSelector("[data-test='pay-button']")).Text.Trim());
|
||||
|
||||
|
||||
// test invoice creation, click with JS, because the button is inside a sticky header
|
||||
s.Driver.ExecuteJavaScript("document.querySelector('[data-test=\"pay-button\"]').click()");
|
||||
// checkout v1
|
||||
s.Driver.WaitForElement(By.CssSelector("invoice"));
|
||||
Assert.Contains("Awaiting Payment", s.Driver.PageSource);
|
||||
|
||||
|
||||
// amount and currency should not be editable, because invoice exists
|
||||
s.GoToUrl(editUrl);
|
||||
Assert.False(s.Driver.FindElement(By.Id("Amount")).Enabled);
|
||||
Assert.False(s.Driver.FindElement(By.Id("Currency")).Enabled);
|
||||
|
||||
|
||||
// archive (from details page)
|
||||
var payReqId = s.Driver.Url.Split('/').Last();
|
||||
s.Driver.FindElement(By.Id("ArchivePaymentRequest")).Click();
|
||||
@ -971,7 +971,7 @@ namespace BTCPayServer.Tests
|
||||
s.Driver.FindElement(By.Id("SearchDropdownToggle")).Click();
|
||||
s.Driver.FindElement(By.Id("SearchIncludeArchived")).Click();
|
||||
Assert.Contains("Pay123", s.Driver.PageSource);
|
||||
|
||||
|
||||
// unarchive (from list)
|
||||
s.Driver.FindElement(By.Id($"ToggleArchival-{payReqId}")).Click();
|
||||
Assert.Contains("The payment request has been unarchived", s.FindAlertMessage().Text);
|
||||
@ -1123,7 +1123,7 @@ namespace BTCPayServer.Tests
|
||||
s.GoToStore(StoreNavPages.Webhooks);
|
||||
s.Driver.FindElement(By.LinkText("Modify")).Click();
|
||||
var elements = s.Driver.FindElements(By.ClassName("redeliver"));
|
||||
|
||||
|
||||
// One worked, one failed
|
||||
s.Driver.FindElement(By.ClassName("fa-times"));
|
||||
s.Driver.FindElement(By.ClassName("fa-check"));
|
||||
@ -1199,7 +1199,7 @@ namespace BTCPayServer.Tests
|
||||
Assert.True(s.Driver.ElementDoesNotExist(By.Id("GoBack")));
|
||||
s.Driver.FindElement(By.Id("CancelWizard")).Click();
|
||||
s.Driver.FindElement(By.Id("WalletNav-Receive")).Click();
|
||||
|
||||
|
||||
//generate a receiving address
|
||||
s.Driver.FindElement(By.CssSelector("button[value=generate-new-address]")).Click();
|
||||
Assert.True(s.Driver.FindElement(By.CssSelector("#address-tab .qr-container")).Displayed);
|
||||
@ -1343,7 +1343,7 @@ namespace BTCPayServer.Tests
|
||||
Assert.Empty(s.Driver.FindElements(By.Id("confirm")));
|
||||
s.Driver.FindElement(By.Id("proceed")).Click();
|
||||
Assert.Equal(settingsUri.ToString(), s.Driver.Url);
|
||||
|
||||
|
||||
// Once more, test the cancel link of the wallet send page leads back to the previous page
|
||||
s.Driver.FindElement(By.Id("WalletNav-Send")).Click();
|
||||
cancelUrl = s.Driver.FindElement(By.Id("CancelWizard")).GetAttribute("href");
|
||||
@ -1352,12 +1352,12 @@ namespace BTCPayServer.Tests
|
||||
Assert.True(s.Driver.ElementDoesNotExist(By.Id("GoBack")));
|
||||
s.Driver.FindElement(By.Id("CancelWizard")).Click();
|
||||
Assert.Equal(settingsUri.ToString(), s.Driver.Url);
|
||||
|
||||
|
||||
// Transactions list contains export and action, ensure functions are present.
|
||||
s.Driver.FindElement(By.Id($"StoreNav-Wallet{cryptoCode}")).Click();
|
||||
s.Driver.FindElement(By.Id("ActionsDropdownToggle")).Click();
|
||||
s.Driver.FindElement(By.Id("BumpFee"));
|
||||
|
||||
|
||||
// JSON export
|
||||
s.Driver.FindElement(By.Id("ExportDropdownToggle")).Click();
|
||||
s.Driver.FindElement(By.Id("ExportJSON")).Click();
|
||||
@ -1367,7 +1367,7 @@ namespace BTCPayServer.Tests
|
||||
Assert.EndsWith("export?format=json", s.Driver.Url);
|
||||
Assert.Contains("\"Amount\": \"3.00000000\"", s.Driver.PageSource);
|
||||
s.Driver.SwitchTo().Window(s.Driver.WindowHandles.First());
|
||||
|
||||
|
||||
// CSV export
|
||||
s.Driver.FindElement(By.Id("ExportDropdownToggle")).Click();
|
||||
s.Driver.FindElement(By.Id("ExportCSV")).Click();
|
||||
@ -1389,7 +1389,7 @@ namespace BTCPayServer.Tests
|
||||
s.Driver.FindElement(By.Id("AccountKeys_0__MasterFingerprint")).GetAttribute("value"));
|
||||
Assert.Contains("m/84'/1'/0'",
|
||||
s.Driver.FindElement(By.Id("AccountKeys_0__AccountKeyPath")).GetAttribute("value"));
|
||||
|
||||
|
||||
// Transactions list is empty
|
||||
s.Driver.FindElement(By.Id($"StoreNav-Wallet{cryptoCode}")).Click();
|
||||
Assert.Contains("There are no transactions yet.", s.Driver.PageSource);
|
||||
@ -1605,7 +1605,7 @@ namespace BTCPayServer.Tests
|
||||
|
||||
newStore = s.CreateNewStore();
|
||||
s.AddLightningNode();
|
||||
|
||||
|
||||
//Currently an onchain wallet is required to use the Lightning payouts feature..
|
||||
s.GenerateWallet("BTC", "", true, true);
|
||||
s.GoToStore(newStore.storeId, StoreNavPages.PullPayments);
|
||||
@ -1680,8 +1680,8 @@ namespace BTCPayServer.Tests
|
||||
s.Driver.FindElement(By.Id($"{PayoutState.Completed}-view")).Click();
|
||||
Assert.Contains(bolt, s.Driver.PageSource);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//auto-approve pull payments
|
||||
|
||||
@ -1703,8 +1703,8 @@ namespace BTCPayServer.Tests
|
||||
Assert.Contains(PayoutState.AwaitingPayment.GetStateString(), s.Driver.PageSource);
|
||||
|
||||
//lnurl-w support check
|
||||
|
||||
s.GoToStore(s.StoreId,StoreNavPages.PullPayments);
|
||||
|
||||
s.GoToStore(s.StoreId, StoreNavPages.PullPayments);
|
||||
s.Driver.FindElement(By.Id("NewPullPayment")).Click();
|
||||
s.Driver.FindElement(By.Id("Name")).SendKeys("PP1");
|
||||
s.Driver.SetCheckbox(By.Id("AutoApproveClaims"), true);
|
||||
@ -1715,7 +1715,7 @@ namespace BTCPayServer.Tests
|
||||
s.FindAlertMessage(StatusMessageModel.StatusSeverity.Success);
|
||||
s.Driver.FindElement(By.LinkText("View")).Click();
|
||||
s.Driver.FindElement(By.CssSelector("#lnurlwithdraw-button")).Click();
|
||||
var lnurl = new Uri(LNURL.LNURL.Parse(s.Driver.FindElement(By.Id("qr-code-data-input")).GetAttribute("value"), out _).ToString().Replace("https", "http"));
|
||||
var lnurl = new Uri(LNURL.LNURL.Parse(s.Driver.FindElement(By.Id("qr-code-data-input")).GetAttribute("value"), out _).ToString().Replace("https", "http"));
|
||||
s.Driver.FindElement(By.CssSelector("button[data-bs-dismiss='modal']")).Click();
|
||||
var info = Assert.IsType<LNURLWithdrawRequest>(await LNURL.LNURL.FetchInformation(lnurl, s.Server.PayTester.HttpClient));
|
||||
Assert.Equal(info.MaxWithdrawable, new LightMoney(0.0000001m, LightMoneyUnit.BTC));
|
||||
@ -1723,7 +1723,7 @@ namespace BTCPayServer.Tests
|
||||
info = Assert.IsType<LNURLWithdrawRequest>(await LNURL.LNURL.FetchInformation(info.BalanceCheck, s.Server.PayTester.HttpClient));
|
||||
Assert.Equal(info.MaxWithdrawable, new LightMoney(0.0000001m, LightMoneyUnit.BTC));
|
||||
Assert.Equal(info.CurrentBalance, new LightMoney(0.0000001m, LightMoneyUnit.BTC));
|
||||
|
||||
|
||||
var bolt2 = (await s.Server.CustomerLightningD.CreateInvoice(
|
||||
new LightMoney(0.0000001m, LightMoneyUnit.BTC),
|
||||
$"LNurl w payout test {DateTime.UtcNow.Ticks}",
|
||||
@ -1733,12 +1733,12 @@ namespace BTCPayServer.Tests
|
||||
{
|
||||
s.Driver.Navigate().Refresh();
|
||||
Assert.Contains(bolt2.BOLT11, s.Driver.PageSource);
|
||||
|
||||
|
||||
Assert.Contains(PayoutState.Completed.GetStateString(), s.Driver.PageSource);
|
||||
Assert.Equal( LightningInvoiceStatus.Paid, (await s.Server.CustomerLightningD.GetInvoice(bolt2.Id)).Status );
|
||||
Assert.Equal(LightningInvoiceStatus.Paid, (await s.Server.CustomerLightningD.GetInvoice(bolt2.Id)).Status);
|
||||
});
|
||||
|
||||
s.GoToStore(s.StoreId,StoreNavPages.PullPayments);
|
||||
|
||||
s.GoToStore(s.StoreId, StoreNavPages.PullPayments);
|
||||
s.Driver.FindElement(By.Id("NewPullPayment")).Click();
|
||||
s.Driver.FindElement(By.Id("Name")).SendKeys("PP1");
|
||||
s.Driver.SetCheckbox(By.Id("AutoApproveClaims"), false);
|
||||
@ -1749,8 +1749,8 @@ namespace BTCPayServer.Tests
|
||||
s.FindAlertMessage(StatusMessageModel.StatusSeverity.Success);
|
||||
s.Driver.FindElement(By.LinkText("View")).Click();
|
||||
s.Driver.FindElement(By.CssSelector("#lnurlwithdraw-button")).Click();
|
||||
lnurl = new Uri(LNURL.LNURL.Parse(s.Driver.FindElement(By.Id("qr-code-data-input")).GetAttribute("value"), out _).ToString().Replace("https", "http"));
|
||||
|
||||
lnurl = new Uri(LNURL.LNURL.Parse(s.Driver.FindElement(By.Id("qr-code-data-input")).GetAttribute("value"), out _).ToString().Replace("https", "http"));
|
||||
|
||||
s.Driver.FindElement(By.CssSelector("button[data-bs-dismiss='modal']")).Click();
|
||||
info = Assert.IsType<LNURLWithdrawRequest>(await LNURL.LNURL.FetchInformation(lnurl, s.Server.PayTester.HttpClient));
|
||||
Assert.Equal(info.MaxWithdrawable, new LightMoney(0.0000001m, LightMoneyUnit.BTC));
|
||||
@ -1758,7 +1758,7 @@ namespace BTCPayServer.Tests
|
||||
info = Assert.IsType<LNURLWithdrawRequest>(await LNURL.LNURL.FetchInformation(info.BalanceCheck, s.Server.PayTester.HttpClient));
|
||||
Assert.Equal(info.MaxWithdrawable, new LightMoney(0.0000001m, LightMoneyUnit.BTC));
|
||||
Assert.Equal(info.CurrentBalance, new LightMoney(0.0000001m, LightMoneyUnit.BTC));
|
||||
|
||||
|
||||
bolt2 = (await s.Server.CustomerLightningD.CreateInvoice(
|
||||
new LightMoney(0.0000001m, LightMoneyUnit.BTC),
|
||||
$"LNurl w payout test {DateTime.UtcNow.Ticks}",
|
||||
@ -1768,7 +1768,7 @@ namespace BTCPayServer.Tests
|
||||
{
|
||||
s.Driver.Navigate().Refresh();
|
||||
Assert.Contains(bolt2.BOLT11, s.Driver.PageSource);
|
||||
|
||||
|
||||
Assert.Contains(PayoutState.AwaitingApproval.GetStateString(), s.Driver.PageSource);
|
||||
});
|
||||
}
|
||||
@ -1867,7 +1867,8 @@ namespace BTCPayServer.Tests
|
||||
});
|
||||
var greenfield = await s.AsTestAccount().CreateClient();
|
||||
var paymentMethods = await greenfield.GetInvoicePaymentMethods(s.StoreId, i);
|
||||
Assert.Single(paymentMethods, p => {
|
||||
Assert.Single(paymentMethods, p =>
|
||||
{
|
||||
return p.AdditionalData["providedComment"].Value<string>() == "lol2";
|
||||
});
|
||||
// Standard invoice test
|
||||
@ -1977,12 +1978,12 @@ namespace BTCPayServer.Tests
|
||||
s.Driver.FindElement(By.Id("Name")).SendKeys("PP1");
|
||||
s.Driver.FindElement(By.Id("Amount")).Clear();
|
||||
s.Driver.FindElement(By.Id("Amount")).SendKeys("0.0000001");
|
||||
|
||||
|
||||
var currencyInput = s.Driver.FindElement(By.Id("Currency"));
|
||||
Assert.Equal("USD", currencyInput.GetAttribute("value"));
|
||||
currencyInput.Clear();
|
||||
currencyInput.SendKeys("BTC");
|
||||
|
||||
|
||||
s.Driver.FindElement(By.Id("Create")).Click();
|
||||
s.Driver.FindElement(By.LinkText("View")).Click();
|
||||
s.Driver.FindElement(By.Id("Destination")).SendKeys(lnurl);
|
||||
@ -2124,7 +2125,7 @@ retry:
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
[Fact]
|
||||
[Trait("Selenium", "Selenium")]
|
||||
public async Task CanUseLNURLAuth()
|
||||
@ -2138,32 +2139,32 @@ retry:
|
||||
.FindElement(By.CssSelector($"option[value='{(int)Fido2Credential.CredentialType.LNURLAuth}']")).Click();
|
||||
s.Driver.FindElement(By.Id("btn-add")).Click();
|
||||
var links = s.Driver.FindElements(By.CssSelector(".tab-content a")).Select(element => element.GetAttribute("href"));
|
||||
Assert.Equal(2,links.Count());
|
||||
Assert.Equal(2, links.Count());
|
||||
Uri prevEndpoint = null;
|
||||
foreach (string link in links)
|
||||
{
|
||||
var endpoint = LNURL.LNURL.Parse(link, out var tag);
|
||||
Assert.Equal("login",tag);
|
||||
if(endpoint.Scheme != "https")
|
||||
Assert.Equal("login", tag);
|
||||
if (endpoint.Scheme != "https")
|
||||
prevEndpoint = endpoint;
|
||||
}
|
||||
|
||||
var linkingKey = new Key();
|
||||
var request = Assert.IsType<LNAuthRequest>(await LNURL.LNURL.FetchInformation(prevEndpoint, null));
|
||||
_ = await request.SendChallenge(linkingKey, new HttpClient());
|
||||
TestUtils.Eventually(() => s.FindAlertMessage());
|
||||
|
||||
TestUtils.Eventually(() => s.FindAlertMessage());
|
||||
|
||||
s.Logout();
|
||||
s.LogIn(user, "123456");
|
||||
var section = s.Driver.FindElement(By.Id("lnurlauth-section"));
|
||||
links = section.FindElements(By.CssSelector(".tab-content a")).Select(element => element.GetAttribute("href"));
|
||||
Assert.Equal(2,links.Count());
|
||||
Assert.Equal(2, links.Count());
|
||||
prevEndpoint = null;
|
||||
foreach (string link in links)
|
||||
{
|
||||
var endpoint = LNURL.LNURL.Parse(link, out var tag);
|
||||
Assert.Equal("login",tag);
|
||||
if(endpoint.Scheme != "https")
|
||||
Assert.Equal("login", tag);
|
||||
if (endpoint.Scheme != "https")
|
||||
prevEndpoint = endpoint;
|
||||
}
|
||||
request = Assert.IsType<LNAuthRequest>(await LNURL.LNURL.FetchInformation(prevEndpoint, null));
|
||||
@ -2173,7 +2174,7 @@ retry:
|
||||
Assert.Equal(s.Driver.Url, s.ServerUri.ToString());
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
private static void CanBrowseContent(SeleniumTester s)
|
||||
{
|
||||
s.Driver.FindElement(By.ClassName("delivery-content")).Click();
|
||||
|
@ -254,7 +254,7 @@ namespace BTCPayServer.Tests
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
|
||||
public string Email
|
||||
{
|
||||
get;
|
||||
|
@ -75,7 +75,7 @@ namespace BTCPayServer.Tests
|
||||
public async Task CanQueryDirectProviders()
|
||||
{
|
||||
// TODO: Check once in a while whether or not they are working again
|
||||
string[] brokenShitcoinCasinos = {};
|
||||
string[] brokenShitcoinCasinos = { };
|
||||
var skipped = 0;
|
||||
var factory = FastTests.CreateBTCPayRateFactory();
|
||||
var directlySupported = factory.GetSupportedExchanges().Where(s => s.Source == RateSource.Direct)
|
||||
@ -95,7 +95,7 @@ namespace BTCPayServer.Tests
|
||||
skipped++;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
TestLogs.LogInformation($"Testing {name}");
|
||||
|
||||
result.Fetcher.InvalidateCache();
|
||||
@ -175,7 +175,7 @@ namespace BTCPayServer.Tests
|
||||
var p = new KrakenExchangeRateProvider();
|
||||
var rates = await p.GetRatesAsync(default);
|
||||
Assert.Contains(rates, e => e.CurrencyPair == new CurrencyPair("XMR", "BTC") && e.BidAsk.Bid < 1.0m);
|
||||
|
||||
|
||||
// Check we didn't skip too many exchanges
|
||||
Assert.InRange(skipped, 0, 3);
|
||||
}
|
||||
@ -225,7 +225,7 @@ namespace BTCPayServer.Tests
|
||||
{
|
||||
var uri = new Uri(url);
|
||||
int retryLeft = 3;
|
||||
retry:
|
||||
retry:
|
||||
try
|
||||
{
|
||||
using var request = new HttpRequestMessage(HttpMethod.Get, uri);
|
||||
@ -350,7 +350,7 @@ namespace BTCPayServer.Tests
|
||||
expected = (await (await client.GetAsync($"https://unpkg.com/@chenfengyuan/vue-qrcode@{version}/dist/vue-qrcode.min.js")).Content.ReadAsStringAsync()).Trim();
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
|
||||
string GetFileContent(params string[] path)
|
||||
{
|
||||
var l = path.ToList();
|
||||
|
@ -189,7 +189,7 @@ namespace BTCPayServer.Tests
|
||||
|
||||
Assert.Equal(description, json["components"]["securitySchemes"]["API_Key"]["description"].Value<string>());
|
||||
}
|
||||
|
||||
|
||||
[Fact]
|
||||
[Trait("Integration", "Integration")]
|
||||
public async void CanStoreArbitrarySettingsWithStore()
|
||||
@ -199,11 +199,11 @@ namespace BTCPayServer.Tests
|
||||
var user = tester.NewAccount();
|
||||
await user.GrantAccessAsync();
|
||||
var settingsRepo = tester.PayTester.ServiceProvider.GetRequiredService<IStoreRepository>();
|
||||
var arbValue = await settingsRepo.GetSettingAsync<string>(user.StoreId,"arbitrary");
|
||||
var arbValue = await settingsRepo.GetSettingAsync<string>(user.StoreId, "arbitrary");
|
||||
Assert.Null(arbValue);
|
||||
await settingsRepo.UpdateSetting(user.StoreId, "arbitrary", "saved");
|
||||
|
||||
arbValue = await settingsRepo.GetSettingAsync<string>(user.StoreId,"arbitrary");
|
||||
arbValue = await settingsRepo.GetSettingAsync<string>(user.StoreId, "arbitrary");
|
||||
Assert.Equal("saved", arbValue);
|
||||
|
||||
await settingsRepo.UpdateSetting<TestData>(user.StoreId, "arbitrary", new TestData() { Name = "hello" });
|
||||
@ -1934,8 +1934,8 @@ namespace BTCPayServer.Tests
|
||||
Assert.Contains($",orderId,{invoice.Id},", paidresult.Content);
|
||||
Assert.Contains($",On-Chain,BTC,0.0991,0.0001,5000.0", paidresult.Content);
|
||||
Assert.Contains($",USD,5.00", paidresult.Content); // Seems hacky but some plateform does not render this decimal the same
|
||||
Assert.Contains("0,,\"Some \"\", description\",New (paidPartial),new,paidPartial",
|
||||
paidresult.Content);
|
||||
Assert.Contains("0,,\"Some \"\", description\",New (paidPartial),new,paidPartial",
|
||||
paidresult.Content);
|
||||
});
|
||||
}
|
||||
|
||||
@ -2157,7 +2157,7 @@ namespace BTCPayServer.Tests
|
||||
Assert.Equal("paidPartial", localInvoice.ExceptionStatus.ToString());
|
||||
Assert.Equal(1, localInvoice.CryptoInfo[0].TxCount);
|
||||
Assert.NotEqual(localInvoice.BitcoinAddress, invoice.BitcoinAddress); //New address
|
||||
Assert.True(IsMapped(invoice, ctx));
|
||||
Assert.True(IsMapped(invoice, ctx));
|
||||
Assert.True(IsMapped(localInvoice, ctx));
|
||||
|
||||
invoiceEntity = repo.GetInvoice(invoice.Id, true).GetAwaiter().GetResult();
|
||||
@ -2175,7 +2175,7 @@ namespace BTCPayServer.Tests
|
||||
Assert.Equal(firstPayment + secondPayment, localInvoice.BtcPaid);
|
||||
Assert.Equal(Money.Zero, localInvoice.BtcDue);
|
||||
Assert.Equal(localInvoice.BitcoinAddress, invoiceAddress.ToString()); //no new address generated
|
||||
Assert.True(IsMapped(localInvoice, ctx));
|
||||
Assert.True(IsMapped(localInvoice, ctx));
|
||||
Assert.False((bool)((JValue)localInvoice.ExceptionStatus).Value);
|
||||
});
|
||||
|
||||
|
@ -26,9 +26,11 @@ public class AppSales : ViewComponent
|
||||
|
||||
public async Task<IViewComponentResult> InvokeAsync(AppSalesViewModel vm)
|
||||
{
|
||||
if (vm.App == null) throw new ArgumentNullException(nameof(vm.App));
|
||||
if (vm.InitialRendering) return View(vm);
|
||||
|
||||
if (vm.App == null)
|
||||
throw new ArgumentNullException(nameof(vm.App));
|
||||
if (vm.InitialRendering)
|
||||
return View(vm);
|
||||
|
||||
var stats = await _appService.GetSalesStats(vm.App);
|
||||
|
||||
vm.SalesCount = stats.SalesCount;
|
||||
|
@ -20,13 +20,15 @@ public class AppTopItems : ViewComponent
|
||||
|
||||
public async Task<IViewComponentResult> InvokeAsync(AppTopItemsViewModel vm)
|
||||
{
|
||||
if (vm.App == null) throw new ArgumentNullException(nameof(vm.App));
|
||||
if (vm.InitialRendering) return View(vm);
|
||||
|
||||
if (vm.App == null)
|
||||
throw new ArgumentNullException(nameof(vm.App));
|
||||
if (vm.InitialRendering)
|
||||
return View(vm);
|
||||
|
||||
var entries = Enum.Parse<AppType>(vm.App.AppType) == AppType.Crowdfund
|
||||
? await _appService.GetPerkStats(vm.App)
|
||||
: await _appService.GetItemStats(vm.App);
|
||||
|
||||
|
||||
vm.Entries = entries.ToList();
|
||||
|
||||
return View(vm);
|
||||
|
@ -76,7 +76,7 @@ namespace BTCPayServer.Components.MainNav
|
||||
AppName = a.AppName,
|
||||
AppType = Enum.Parse<AppType>(a.AppType)
|
||||
}).ToList();
|
||||
|
||||
|
||||
if (PoliciesSettings.Experimental)
|
||||
{
|
||||
// Custodian Accounts
|
||||
|
@ -47,26 +47,29 @@ public class StoreLightningBalance : ViewComponent
|
||||
|
||||
public async Task<IViewComponentResult> InvokeAsync(StoreLightningBalanceViewModel vm)
|
||||
{
|
||||
if (vm.Store == null) throw new ArgumentNullException(nameof(vm.Store));
|
||||
if (vm.CryptoCode == null) throw new ArgumentNullException(nameof(vm.CryptoCode));
|
||||
|
||||
if (vm.Store == null)
|
||||
throw new ArgumentNullException(nameof(vm.Store));
|
||||
if (vm.CryptoCode == null)
|
||||
throw new ArgumentNullException(nameof(vm.CryptoCode));
|
||||
|
||||
vm.DefaultCurrency = vm.Store.GetStoreBlob().DefaultCurrency;
|
||||
vm.CurrencyData = _currencies.GetCurrencyData(vm.DefaultCurrency, true);
|
||||
|
||||
if (vm.InitialRendering) return View(vm);
|
||||
|
||||
if (vm.InitialRendering)
|
||||
return View(vm);
|
||||
|
||||
try
|
||||
{
|
||||
var lightningClient = GetLightningClient(vm.Store, vm.CryptoCode);
|
||||
var balance = await lightningClient.GetBalance();
|
||||
vm.Balance = balance;
|
||||
vm.TotalOnchain = balance.OnchainBalance != null
|
||||
? (balance.OnchainBalance.Confirmed?? 0L) + (balance.OnchainBalance.Reserved ?? 0L) +
|
||||
? (balance.OnchainBalance.Confirmed ?? 0L) + (balance.OnchainBalance.Reserved ?? 0L) +
|
||||
(balance.OnchainBalance.Unconfirmed ?? 0L)
|
||||
: null;
|
||||
vm.TotalOffchain = balance.OffchainBalance != null
|
||||
? (balance.OffchainBalance.Opening?? 0) + (balance.OffchainBalance.Local?? 0) +
|
||||
(balance.OffchainBalance.Closing?? 0)
|
||||
? (balance.OffchainBalance.Opening ?? 0) + (balance.OffchainBalance.Local ?? 0) +
|
||||
(balance.OffchainBalance.Closing ?? 0)
|
||||
: null;
|
||||
}
|
||||
catch (NotSupportedException)
|
||||
@ -81,7 +84,7 @@ public class StoreLightningBalance : ViewComponent
|
||||
}
|
||||
return View(vm);
|
||||
}
|
||||
|
||||
|
||||
private ILightningClient GetLightningClient(StoreData store, string cryptoCode)
|
||||
{
|
||||
var network = _networkProvider.GetNetwork<BTCPayNetwork>(cryptoCode);
|
||||
@ -89,9 +92,10 @@ public class StoreLightningBalance : ViewComponent
|
||||
var existing = store.GetSupportedPaymentMethods(_networkProvider)
|
||||
.OfType<LightningSupportedPaymentMethod>()
|
||||
.FirstOrDefault(d => d.PaymentId == id);
|
||||
if (existing == null) return null;
|
||||
|
||||
if (existing.GetExternalLightningUrl() is {} connectionString)
|
||||
if (existing == null)
|
||||
return null;
|
||||
|
||||
if (existing.GetExternalLightningUrl() is { } connectionString)
|
||||
{
|
||||
return _lightningClientFactory.Create(connectionString, network);
|
||||
}
|
||||
|
@ -34,10 +34,14 @@ public class StoreLightningServices : ViewComponent
|
||||
|
||||
public IViewComponentResult Invoke(StoreLightningServicesViewModel vm)
|
||||
{
|
||||
if (vm.Store == null) throw new ArgumentNullException(nameof(vm.Store));
|
||||
if (vm.CryptoCode == null) throw new ArgumentNullException(nameof(vm.CryptoCode));
|
||||
if (vm.LightningNodeType != LightningNodeType.Internal) return View(vm);
|
||||
if (!User.IsInRole(Roles.ServerAdmin)) return View(vm);
|
||||
if (vm.Store == null)
|
||||
throw new ArgumentNullException(nameof(vm.Store));
|
||||
if (vm.CryptoCode == null)
|
||||
throw new ArgumentNullException(nameof(vm.CryptoCode));
|
||||
if (vm.LightningNodeType != LightningNodeType.Internal)
|
||||
return View(vm);
|
||||
if (!User.IsInRole(Roles.ServerAdmin))
|
||||
return View(vm);
|
||||
|
||||
var services = _externalServiceOptions.Value.ExternalServices.ToList()
|
||||
.Where(service => ExternalServices.LightningServiceTypes.Contains(service.Type))
|
||||
@ -62,7 +66,7 @@ public class StoreLightningServices : ViewComponent
|
||||
})
|
||||
.Select(t => t.Result)
|
||||
.ToList();
|
||||
|
||||
|
||||
// other services
|
||||
foreach ((string key, Uri value) in _externalServiceOptions.Value.OtherExternalServices)
|
||||
{
|
||||
|
@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using Dapper;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
@ -9,6 +8,7 @@ using BTCPayServer.Data;
|
||||
using BTCPayServer.Services;
|
||||
using BTCPayServer.Services.Stores;
|
||||
using BTCPayServer.Services.Wallets;
|
||||
using Dapper;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
@ -41,13 +41,16 @@ public class StoreNumbers : ViewComponent
|
||||
|
||||
public async Task<IViewComponentResult> InvokeAsync(StoreNumbersViewModel vm)
|
||||
{
|
||||
if (vm.Store == null) throw new ArgumentNullException(nameof(vm.Store));
|
||||
if (vm.CryptoCode == null) throw new ArgumentNullException(nameof(vm.CryptoCode));
|
||||
|
||||
if (vm.Store == null)
|
||||
throw new ArgumentNullException(nameof(vm.Store));
|
||||
if (vm.CryptoCode == null)
|
||||
throw new ArgumentNullException(nameof(vm.CryptoCode));
|
||||
|
||||
vm.WalletId = new WalletId(vm.Store.Id, vm.CryptoCode);
|
||||
|
||||
if (vm.InitialRendering) return View(vm);
|
||||
|
||||
if (vm.InitialRendering)
|
||||
return View(vm);
|
||||
|
||||
await using var ctx = _dbContextFactory.CreateContext();
|
||||
var payoutsCount = await ctx.Payouts
|
||||
.Where(p => p.PullPaymentData.StoreId == vm.Store.Id && !p.PullPaymentData.Archived && p.State == PayoutState.AwaitingApproval)
|
||||
@ -55,7 +58,7 @@ public class StoreNumbers : ViewComponent
|
||||
var refundsCount = await ctx.Invoices
|
||||
.Where(i => i.StoreData.Id == vm.Store.Id && !i.Archived && i.CurrentRefundId != null)
|
||||
.CountAsync();
|
||||
|
||||
|
||||
var derivation = vm.Store.GetDerivationSchemeSettings(_networkProvider, vm.CryptoCode);
|
||||
int? transactionsCount = null;
|
||||
if (derivation != null && _nbxConnectionFactory.Available)
|
||||
|
@ -35,31 +35,34 @@ public class StoreRecentInvoices : ViewComponent
|
||||
|
||||
public async Task<IViewComponentResult> InvokeAsync(StoreRecentInvoicesViewModel vm)
|
||||
{
|
||||
if (vm.Store == null) throw new ArgumentNullException(nameof(vm.Store));
|
||||
if (vm.CryptoCode == null) throw new ArgumentNullException(nameof(vm.CryptoCode));
|
||||
if (vm.InitialRendering) return View(vm);
|
||||
|
||||
if (vm.Store == null)
|
||||
throw new ArgumentNullException(nameof(vm.Store));
|
||||
if (vm.CryptoCode == null)
|
||||
throw new ArgumentNullException(nameof(vm.CryptoCode));
|
||||
if (vm.InitialRendering)
|
||||
return View(vm);
|
||||
|
||||
var userId = _userManager.GetUserId(UserClaimsPrincipal);
|
||||
var invoiceEntities = await _invoiceRepo.GetInvoices(new InvoiceQuery
|
||||
{
|
||||
UserId = userId,
|
||||
StoreId = new [] { vm.Store.Id },
|
||||
IncludeArchived = false,
|
||||
IncludeRefunds = true,
|
||||
Take = 5
|
||||
});
|
||||
|
||||
{
|
||||
UserId = userId,
|
||||
StoreId = new[] { vm.Store.Id },
|
||||
IncludeArchived = false,
|
||||
IncludeRefunds = true,
|
||||
Take = 5
|
||||
});
|
||||
|
||||
vm.Invoices = (from invoice in invoiceEntities
|
||||
let state = invoice.GetInvoiceState()
|
||||
select new StoreRecentInvoiceViewModel
|
||||
{
|
||||
Date = invoice.InvoiceTime,
|
||||
Status = state,
|
||||
HasRefund = invoice.Refunds.Any(),
|
||||
InvoiceId = invoice.Id,
|
||||
OrderId = invoice.Metadata.OrderId ?? string.Empty,
|
||||
AmountCurrency = _currencyNameTable.DisplayFormatCurrency(invoice.Price, invoice.Currency),
|
||||
}).ToList();
|
||||
let state = invoice.GetInvoiceState()
|
||||
select new StoreRecentInvoiceViewModel
|
||||
{
|
||||
Date = invoice.InvoiceTime,
|
||||
Status = state,
|
||||
HasRefund = invoice.Refunds.Any(),
|
||||
InvoiceId = invoice.Id,
|
||||
OrderId = invoice.Metadata.OrderId ?? string.Empty,
|
||||
AmountCurrency = _currencyNameTable.DisplayFormatCurrency(invoice.Price, invoice.Currency),
|
||||
}).ToList();
|
||||
|
||||
return View(vm);
|
||||
}
|
||||
|
@ -1,22 +1,22 @@
|
||||
#nullable enable
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Abstractions.Extensions;
|
||||
using BTCPayServer.Data;
|
||||
using BTCPayServer.Services;
|
||||
using BTCPayServer.Models.StoreViewModels;
|
||||
using BTCPayServer.Services;
|
||||
using BTCPayServer.Services.Stores;
|
||||
using Dapper;
|
||||
using BTCPayServer.Services.Wallets;
|
||||
using Dapper;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using NBXplorer.Client;
|
||||
using static BTCPayServer.Components.StoreRecentTransactions.StoreRecentTransactionsViewModel;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using NBitcoin;
|
||||
using NBXplorer.Client;
|
||||
using static BTCPayServer.Components.StoreRecentTransactions.StoreRecentTransactionsViewModel;
|
||||
|
||||
namespace BTCPayServer.Components.StoreRecentTransactions;
|
||||
|
||||
@ -35,13 +35,16 @@ public class StoreRecentTransactions : ViewComponent
|
||||
|
||||
public async Task<IViewComponentResult> InvokeAsync(StoreRecentTransactionsViewModel vm)
|
||||
{
|
||||
if (vm.Store == null) throw new ArgumentNullException(nameof(vm.Store));
|
||||
if (vm.CryptoCode == null) throw new ArgumentNullException(nameof(vm.CryptoCode));
|
||||
if (vm.Store == null)
|
||||
throw new ArgumentNullException(nameof(vm.Store));
|
||||
if (vm.CryptoCode == null)
|
||||
throw new ArgumentNullException(nameof(vm.CryptoCode));
|
||||
|
||||
vm.WalletId = new WalletId(vm.Store.Id, vm.CryptoCode);
|
||||
|
||||
if (vm.InitialRendering) return View(vm);
|
||||
|
||||
|
||||
if (vm.InitialRendering)
|
||||
return View(vm);
|
||||
|
||||
var derivationSettings = vm.Store.GetDerivationSchemeSettings(NetworkProvider, vm.CryptoCode);
|
||||
var transactions = new List<StoreRecentTransactionViewModel>();
|
||||
if (derivationSettings?.AccountDerivation is not null)
|
||||
@ -63,7 +66,7 @@ public class StoreRecentTransactions : ViewComponent
|
||||
}
|
||||
|
||||
vm.Transactions = transactions;
|
||||
|
||||
|
||||
return View(vm);
|
||||
}
|
||||
}
|
||||
|
@ -33,7 +33,7 @@ public class StoreWalletBalance : ViewComponent
|
||||
public StoreWalletBalance(
|
||||
StoreRepository storeRepo,
|
||||
CurrencyNameTable currencies,
|
||||
WalletHistogramService walletHistogramService,
|
||||
WalletHistogramService walletHistogramService,
|
||||
BTCPayWalletProvider walletProvider,
|
||||
BTCPayNetworkProvider networkProvider)
|
||||
{
|
||||
@ -50,7 +50,7 @@ public class StoreWalletBalance : ViewComponent
|
||||
var walletId = new WalletId(store.Id, cryptoCode);
|
||||
var data = await _walletHistogramService.GetHistogram(store, walletId, DefaultType);
|
||||
var defaultCurrency = store.GetStoreBlob().DefaultCurrency;
|
||||
|
||||
|
||||
var vm = new StoreWalletBalanceViewModel
|
||||
{
|
||||
Store = store,
|
||||
@ -69,7 +69,7 @@ public class StoreWalletBalance : ViewComponent
|
||||
}
|
||||
else
|
||||
{
|
||||
using CancellationTokenSource cts = new (TimeSpan.FromSeconds(3));
|
||||
using CancellationTokenSource cts = new(TimeSpan.FromSeconds(3));
|
||||
var wallet = _walletProvider.GetWallet(_networkProvider.DefaultNetwork);
|
||||
var derivation = store.GetDerivationSchemeSettings(_networkProvider, walletId.CryptoCode);
|
||||
if (derivation is not null)
|
||||
|
@ -42,7 +42,7 @@ namespace BTCPayServer.Components.WalletNav
|
||||
var wallet = _walletProvider.GetWallet(network);
|
||||
var derivation = store.GetDerivationSchemeSettings(_networkProvider, walletId.CryptoCode);
|
||||
var balance = await _walletsController.GetBalanceString(wallet, derivation?.AccountDerivation);
|
||||
|
||||
|
||||
var vm = new WalletNavViewModel
|
||||
{
|
||||
WalletId = walletId,
|
||||
|
@ -97,7 +97,7 @@ namespace BTCPayServer.Configuration
|
||||
}
|
||||
}
|
||||
connectionString.CookieFilePath = null;
|
||||
|
||||
|
||||
if (serviceType == ExternalServiceTypes.RTL || serviceType == ExternalServiceTypes.Configurator ||
|
||||
serviceType == ExternalServiceTypes.ThunderHub || serviceType == ExternalServiceTypes.Torq)
|
||||
{
|
||||
|
@ -92,7 +92,7 @@ namespace BTCPayServer.Configuration
|
||||
&&
|
||||
o.ServiceName.Equals(serviceName, StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
|
||||
public static readonly ExternalServiceTypes[] LightningServiceTypes =
|
||||
{
|
||||
ExternalServiceTypes.Spark,
|
||||
@ -100,7 +100,7 @@ namespace BTCPayServer.Configuration
|
||||
ExternalServiceTypes.ThunderHub,
|
||||
ExternalServiceTypes.Torq
|
||||
};
|
||||
|
||||
|
||||
public static readonly string[] LightningServiceNames =
|
||||
{
|
||||
"Lightning Terminal"
|
||||
@ -114,7 +114,7 @@ namespace BTCPayServer.Configuration
|
||||
public ExternalConnectionString ConnectionString { get; set; }
|
||||
public string CryptoCode { get; set; }
|
||||
public string ServiceName { get; set; }
|
||||
|
||||
|
||||
public async Task<string> GetLink(Uri absoluteUriNoPathBase, ChainName networkType)
|
||||
{
|
||||
var connectionString = await ConnectionString.Expand(absoluteUriNoPathBase, Type, networkType);
|
||||
|
@ -25,7 +25,7 @@ namespace BTCPayServer.Controllers
|
||||
[Authorize(Policy = ServerPolicies.CanGetRates.Key, AuthenticationSchemes = AuthenticationSchemes.Bitpay)]
|
||||
public class BitpayRateController : Controller
|
||||
{
|
||||
|
||||
|
||||
readonly RateFetcher _rateProviderFactory;
|
||||
readonly BTCPayNetworkProvider _networkProvider;
|
||||
readonly CurrencyNameTable _currencyNameTable;
|
||||
@ -67,7 +67,7 @@ namespace BTCPayServer.Controllers
|
||||
public async Task<IActionResult> GetCurrencyPairRate(string baseCurrency, string currency, CancellationToken cancellationToken)
|
||||
{
|
||||
var result = await GetRates2($"{baseCurrency}_{currency}", null, cancellationToken);
|
||||
return (result as JsonResult)?.Value is not Rate[] rates
|
||||
return (result as JsonResult)?.Value is not Rate[] rates
|
||||
? result
|
||||
: Json(new DataWrapper<Rate>(rates.First()));
|
||||
}
|
||||
@ -152,7 +152,7 @@ namespace BTCPayServer.Controllers
|
||||
|
||||
[JsonProperty(PropertyName = "name")]
|
||||
public string Name { get; set; }
|
||||
|
||||
|
||||
[JsonProperty(PropertyName = "cryptoCode")]
|
||||
public string CryptoCode { get; set; }
|
||||
|
||||
@ -161,7 +161,7 @@ namespace BTCPayServer.Controllers
|
||||
|
||||
[JsonProperty(PropertyName = "code")]
|
||||
public string Code { get; set; }
|
||||
|
||||
|
||||
[JsonProperty(PropertyName = "rate")]
|
||||
public decimal Value { get; set; }
|
||||
}
|
||||
|
@ -3,13 +3,13 @@ using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Abstractions.Constants;
|
||||
using BTCPayServer.Abstractions.Extensions;
|
||||
using BTCPayServer.Client;
|
||||
using BTCPayServer.Client.Models;
|
||||
using BTCPayServer.Data;
|
||||
using BTCPayServer.Services.Apps;
|
||||
using BTCPayServer.Services.Rates;
|
||||
using BTCPayServer.Services.Stores;
|
||||
using BTCPayServer.Abstractions.Extensions;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Cors;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
@ -86,7 +86,7 @@ namespace BTCPayServer.Controllers.Greenfield
|
||||
{
|
||||
return validationResult;
|
||||
}
|
||||
|
||||
|
||||
var appData = new AppData
|
||||
{
|
||||
StoreDataId = storeId,
|
||||
@ -112,7 +112,7 @@ namespace BTCPayServer.Controllers.Greenfield
|
||||
}
|
||||
|
||||
var settings = app.GetSettings<PointOfSaleSettings>();
|
||||
|
||||
|
||||
// This is not obvious but we must have a non-null currency or else request validation may work incorrectly
|
||||
request.Currency = request.Currency ?? settings.Currency;
|
||||
|
||||
@ -124,7 +124,7 @@ namespace BTCPayServer.Controllers.Greenfield
|
||||
|
||||
app.Name = request.AppName;
|
||||
app.SetSettings(ToPointOfSaleSettings(request));
|
||||
|
||||
|
||||
await _appService.UpdateOrCreateApp(app);
|
||||
|
||||
return Ok(ToPointOfSaleModel(app));
|
||||
@ -152,7 +152,7 @@ namespace BTCPayServer.Controllers.Greenfield
|
||||
{
|
||||
return AppNotFound();
|
||||
}
|
||||
|
||||
|
||||
return Ok(ToModel(app));
|
||||
}
|
||||
|
||||
@ -164,7 +164,7 @@ namespace BTCPayServer.Controllers.Greenfield
|
||||
{
|
||||
return AppNotFound();
|
||||
}
|
||||
|
||||
|
||||
await _appService.DeleteApp(app);
|
||||
|
||||
return Ok();
|
||||
@ -281,7 +281,7 @@ namespace BTCPayServer.Controllers.Greenfield
|
||||
ModelState.AddModelError(nameof(request.Template), "Invalid template");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
validationResult = this.CreateValidationError(ModelState);
|
||||
@ -304,7 +304,7 @@ namespace BTCPayServer.Controllers.Greenfield
|
||||
|
||||
private string[]? ValidateStringArray(string[]? arr)
|
||||
{
|
||||
if (arr == null || !arr.Any())
|
||||
if (arr == null || !arr.Any())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
@ -359,7 +359,7 @@ namespace BTCPayServer.Controllers.Greenfield
|
||||
{
|
||||
ModelState.AddModelError(nameof(request.EndDate), "End date cannot be before start date");
|
||||
}
|
||||
|
||||
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
validationResult = this.CreateValidationError(ModelState);
|
||||
|
@ -91,7 +91,7 @@ namespace BTCPayServer.Controllers.Greenfield
|
||||
var custodianAccount = await ToModel(custodianAccountData, assetBalances, cancellationToken);
|
||||
return Ok(custodianAccount);
|
||||
}
|
||||
|
||||
|
||||
// [HttpGet("~/api/v1/stores/{storeId}/custodian-accounts/{accountId}/config")]
|
||||
// [Authorize(Policy = Policies.CanManageCustodianAccounts,
|
||||
// AuthenticationSchemes = AuthenticationSchemes.Greenfield)]
|
||||
@ -276,7 +276,7 @@ namespace BTCPayServer.Controllers.Greenfield
|
||||
}
|
||||
catch (CustodianApiException e)
|
||||
{
|
||||
return this.CreateAPIError(e.HttpStatus, e.Code,
|
||||
return this.CreateAPIError(e.HttpStatus, e.Code,
|
||||
e.Message);
|
||||
}
|
||||
}
|
||||
|
@ -11,10 +11,10 @@ using BTCPayServer.Client.Models;
|
||||
using BTCPayServer.Data;
|
||||
using BTCPayServer.HostedServices;
|
||||
using BTCPayServer.Payments;
|
||||
using BTCPayServer.Rating;
|
||||
using BTCPayServer.Services;
|
||||
using BTCPayServer.Services.Invoices;
|
||||
using BTCPayServer.Services.Rates;
|
||||
using BTCPayServer.Rating;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Cors;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
@ -425,21 +425,22 @@ namespace BTCPayServer.Controllers.Greenfield
|
||||
createPullPayment.Amount = cryptoPaid.RoundToSignificant(paymentMethodDivisibility);
|
||||
createPullPayment.AutoApproveClaims = true;
|
||||
break;
|
||||
|
||||
|
||||
case RefundVariant.CurrentRate:
|
||||
createPullPayment.Currency = invoicePaymentMethod.GetId().CryptoCode;
|
||||
createPullPayment.Amount = Math.Round(paidCurrency / rateResult.BidAsk.Bid, paymentMethodDivisibility);
|
||||
createPullPayment.AutoApproveClaims = true;
|
||||
break;
|
||||
|
||||
|
||||
case RefundVariant.Fiat:
|
||||
createPullPayment.Currency = invoice.Currency;
|
||||
createPullPayment.Amount = paidCurrency;
|
||||
createPullPayment.AutoApproveClaims = false;
|
||||
break;
|
||||
|
||||
|
||||
case RefundVariant.Custom:
|
||||
if (request.CustomAmount is null || (request.CustomAmount is decimal v && v <= 0)) {
|
||||
if (request.CustomAmount is null || (request.CustomAmount is decimal v && v <= 0))
|
||||
{
|
||||
this.ModelState.AddModelError(nameof(request.CustomAmount), "Amount must be greater than 0");
|
||||
}
|
||||
|
||||
@ -466,14 +467,14 @@ namespace BTCPayServer.Controllers.Greenfield
|
||||
createPullPayment.Amount = request.CustomAmount.Value;
|
||||
createPullPayment.AutoApproveClaims = paymentMethodId.CryptoCode == request.CustomCurrency;
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
ModelState.AddModelError(nameof(request.RefundVariant), "Please select a valid refund option");
|
||||
return this.CreateValidationError(ModelState);
|
||||
}
|
||||
|
||||
var ppId = await _pullPaymentService.CreatePullPayment(createPullPayment);
|
||||
|
||||
|
||||
await using var ctx = _dbContextFactory.CreateContext();
|
||||
(await ctx.Invoices.FindAsync(new[] { invoice.Id }, cancellationToken))!.CurrentRefundId = ppId;
|
||||
ctx.Refunds.Add(new RefundData
|
||||
@ -599,7 +600,7 @@ namespace BTCPayServer.Controllers.Greenfield
|
||||
Amount = entity.Price,
|
||||
Type = entity.Type,
|
||||
Id = entity.Id,
|
||||
CheckoutLink = request is null? null: linkGenerator.CheckoutLink(entity.Id, request.Scheme, request.Host, request.PathBase),
|
||||
CheckoutLink = request is null ? null : linkGenerator.CheckoutLink(entity.Id, request.Scheme, request.Host, request.PathBase),
|
||||
Status = entity.Status.ToModernStatus(),
|
||||
AdditionalStatus = entity.ExceptionStatus,
|
||||
Currency = entity.Currency,
|
||||
|
@ -40,7 +40,7 @@ namespace BTCPayServer.Controllers.Greenfield
|
||||
_lightningClientFactory = lightningClientFactory;
|
||||
_btcPayNetworkProvider = btcPayNetworkProvider;
|
||||
}
|
||||
|
||||
|
||||
[Authorize(Policy = Policies.CanUseLightningNodeInStore,
|
||||
AuthenticationSchemes = AuthenticationSchemes.Greenfield)]
|
||||
[HttpGet("~/api/v1/stores/{storeId}/lightning/{cryptoCode}/info")]
|
||||
@ -135,13 +135,13 @@ namespace BTCPayServer.Controllers.Greenfield
|
||||
{
|
||||
throw ErrorCryptoCodeNotFound();
|
||||
}
|
||||
|
||||
|
||||
var store = HttpContext.GetStoreData();
|
||||
if (store == null)
|
||||
{
|
||||
throw new JsonHttpException(StoreNotFound());
|
||||
}
|
||||
|
||||
|
||||
var id = new PaymentMethodId(cryptoCode, PaymentTypes.LightningLike);
|
||||
var existing = store.GetSupportedPaymentMethods(_btcPayNetworkProvider)
|
||||
.OfType<LightningSupportedPaymentMethod>()
|
||||
@ -164,7 +164,7 @@ namespace BTCPayServer.Controllers.Greenfield
|
||||
}
|
||||
throw ErrorLightningNodeNotConfiguredForStore();
|
||||
}
|
||||
|
||||
|
||||
private IActionResult StoreNotFound()
|
||||
{
|
||||
return this.CreateAPIError(404, "store-not-found", "The store was not found");
|
||||
|
@ -23,7 +23,7 @@ namespace BTCPayServer.Controllers.Greenfield
|
||||
// Do not mark handled, it is possible filters above have better errors
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public abstract class GreenfieldLightningNodeApiController : Controller
|
||||
{
|
||||
private readonly BTCPayNetworkProvider _btcPayNetworkProvider;
|
||||
@ -209,7 +209,7 @@ namespace BTCPayServer.Controllers.Greenfield
|
||||
var lightningClient = await GetLightningClient(cryptoCode, true);
|
||||
var network = _btcPayNetworkProvider.GetNetwork<BTCPayNetwork>(cryptoCode);
|
||||
BOLT11PaymentRequest bolt11 = null;
|
||||
|
||||
|
||||
if (string.IsNullOrEmpty(lightningInvoice.BOLT11) ||
|
||||
!BOLT11PaymentRequest.TryParse(lightningInvoice.BOLT11, out bolt11, network.NBitcoinNetwork))
|
||||
{
|
||||
@ -220,7 +220,7 @@ namespace BTCPayServer.Controllers.Greenfield
|
||||
{
|
||||
return this.CreateValidationError(ModelState);
|
||||
}
|
||||
|
||||
|
||||
var param = lightningInvoice.MaxFeeFlat != null || lightningInvoice.MaxFeePercent != null
|
||||
|| lightningInvoice.Amount != null || lightningInvoice.SendTimeout != null
|
||||
? new PayInvoiceParams
|
||||
@ -232,12 +232,12 @@ namespace BTCPayServer.Controllers.Greenfield
|
||||
}
|
||||
: null;
|
||||
var result = await lightningClient.Pay(lightningInvoice.BOLT11, param, cancellationToken);
|
||||
|
||||
|
||||
if (result.Result is PayResult.Ok or PayResult.Unknown && bolt11?.PaymentHash is not null)
|
||||
{
|
||||
// get a new instance of the LN client, because the old one might have disposed its HTTPClient
|
||||
lightningClient = await GetLightningClient(cryptoCode, true);
|
||||
|
||||
|
||||
var paymentHash = bolt11.PaymentHash.ToString();
|
||||
var payment = await lightningClient.GetPayment(paymentHash, cancellationToken);
|
||||
var data = new LightningPaymentData
|
||||
@ -253,7 +253,7 @@ namespace BTCPayServer.Controllers.Greenfield
|
||||
};
|
||||
return result.Result is PayResult.Ok ? Ok(data) : Accepted(data);
|
||||
}
|
||||
|
||||
|
||||
return result.Result switch
|
||||
{
|
||||
PayResult.CouldNotFindRoute => this.CreateAPIError("could-not-find-route", "Impossible to find a route to the peer"),
|
||||
@ -265,7 +265,7 @@ namespace BTCPayServer.Controllers.Greenfield
|
||||
PayResult.Ok => Ok(new LightningPaymentData
|
||||
{
|
||||
Status = LightningPaymentStatus.Complete,
|
||||
TotalAmount = result.Details?.TotalAmount,
|
||||
TotalAmount = result.Details?.TotalAmount,
|
||||
FeeAmount = result.Details?.FeeAmount
|
||||
}),
|
||||
_ => throw new NotSupportedException("Unsupported PayResult")
|
||||
@ -308,14 +308,14 @@ namespace BTCPayServer.Controllers.Greenfield
|
||||
{
|
||||
return this.CreateValidationError(ModelState);
|
||||
}
|
||||
|
||||
|
||||
request.Description ??= "";
|
||||
try
|
||||
{
|
||||
var param = new CreateInvoiceParams(request.Amount, request.Description, request.Expiry)
|
||||
{
|
||||
PrivateRouteHints = request.PrivateRouteHints,
|
||||
DescriptionHashOnly = request.DescriptionHashOnly
|
||||
{
|
||||
PrivateRouteHints = request.PrivateRouteHints,
|
||||
DescriptionHashOnly = request.DescriptionHashOnly
|
||||
};
|
||||
var invoice = await lightningClient.CreateInvoice(param, cancellationToken);
|
||||
return Ok(ToModel(invoice));
|
||||
|
@ -20,7 +20,7 @@ namespace BTCPayServer.Controllers.Greenfield
|
||||
{
|
||||
private readonly IEnumerable<IPayoutProcessorFactory> _factories;
|
||||
|
||||
public GreenfieldPayoutProcessorsController(IEnumerable<IPayoutProcessorFactory>factories)
|
||||
public GreenfieldPayoutProcessorsController(IEnumerable<IPayoutProcessorFactory> factories)
|
||||
{
|
||||
_factories = factories;
|
||||
}
|
||||
@ -39,5 +39,5 @@ namespace BTCPayServer.Controllers.Greenfield
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
@ -199,10 +199,10 @@ namespace BTCPayServer.Controllers.Greenfield
|
||||
var pp = await _pullPaymentService.GetPullPayment(pullPaymentId, true);
|
||||
if (pp is null)
|
||||
return PullPaymentNotFound();
|
||||
|
||||
var payouts =await _pullPaymentService.GetPayouts(new PullPaymentHostedService.PayoutQuery()
|
||||
|
||||
var payouts = await _pullPaymentService.GetPayouts(new PullPaymentHostedService.PayoutQuery()
|
||||
{
|
||||
PullPayments = new[] {pullPaymentId},
|
||||
PullPayments = new[] { pullPaymentId },
|
||||
States = GetStateFilter(includeCancelled)
|
||||
});
|
||||
return base.Ok(payouts
|
||||
@ -219,10 +219,11 @@ namespace BTCPayServer.Controllers.Greenfield
|
||||
|
||||
var payout = (await _pullPaymentService.GetPayouts(new PullPaymentHostedService.PayoutQuery()
|
||||
{
|
||||
PullPayments = new[] {pullPaymentId}, PayoutIds = new[] {payoutId}
|
||||
PullPayments = new[] { pullPaymentId },
|
||||
PayoutIds = new[] { payoutId }
|
||||
})).FirstOrDefault();
|
||||
|
||||
|
||||
|
||||
|
||||
if (payout is null)
|
||||
return PayoutNotFound();
|
||||
return base.Ok(ToModel(payout));
|
||||
@ -291,17 +292,17 @@ namespace BTCPayServer.Controllers.Greenfield
|
||||
ModelState.AddModelError(nameof(request.Amount), $"Amount too small (should be at least {ppBlob.MinimumClaim})");
|
||||
return this.CreateValidationError(ModelState);
|
||||
}
|
||||
var result = await _pullPaymentService.Claim(new ClaimRequest()
|
||||
var result = await _pullPaymentService.Claim(new ClaimRequest()
|
||||
{
|
||||
Destination = destination.destination,
|
||||
PullPaymentId = pullPaymentId,
|
||||
Value = request.Amount,
|
||||
PaymentMethodId = paymentMethodId,
|
||||
});
|
||||
|
||||
return HandleClaimResult(result);
|
||||
|
||||
return HandleClaimResult(result);
|
||||
}
|
||||
|
||||
|
||||
[HttpPost("~/api/v1/stores/{storeId}/payouts")]
|
||||
[Authorize(Policy = Policies.CanManagePullPayments, AuthenticationSchemes = AuthenticationSchemes.Greenfield)]
|
||||
public async Task<IActionResult> CreatePayoutThroughStore(string storeId, CreatePayoutThroughStoreRequest request)
|
||||
@ -413,11 +414,11 @@ namespace BTCPayServer.Controllers.Greenfield
|
||||
{
|
||||
var payouts = await _pullPaymentService.GetPayouts(new PullPaymentHostedService.PayoutQuery()
|
||||
{
|
||||
Stores = new[] {storeId},
|
||||
Stores = new[] { storeId },
|
||||
States = GetStateFilter(includeCancelled)
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
return base.Ok(payouts
|
||||
.Select(ToModel).ToArray());
|
||||
}
|
||||
@ -426,7 +427,7 @@ namespace BTCPayServer.Controllers.Greenfield
|
||||
[Authorize(Policy = Policies.CanManagePullPayments, AuthenticationSchemes = AuthenticationSchemes.Greenfield)]
|
||||
public async Task<IActionResult> CancelPayout(string storeId, string payoutId)
|
||||
{
|
||||
var res= await _pullPaymentService.Cancel(new PullPaymentHostedService.CancelRequest(new[] { payoutId }, new []{storeId}));
|
||||
var res = await _pullPaymentService.Cancel(new PullPaymentHostedService.CancelRequest(new[] { payoutId }, new[] { storeId }));
|
||||
return MapResult(res.First().Value);
|
||||
}
|
||||
|
||||
@ -530,14 +531,15 @@ namespace BTCPayServer.Controllers.Greenfield
|
||||
|
||||
var payout = (await _pullPaymentService.GetPayouts(new PullPaymentHostedService.PayoutQuery()
|
||||
{
|
||||
Stores = new[] {storeId}, PayoutIds = new[] {payoutId}
|
||||
Stores = new[] { storeId },
|
||||
PayoutIds = new[] { payoutId }
|
||||
})).FirstOrDefault();
|
||||
|
||||
if (payout is null)
|
||||
return PayoutNotFound();
|
||||
return base.Ok(ToModel(payout));
|
||||
}
|
||||
|
||||
|
||||
private IActionResult MapResult(MarkPayoutRequest.PayoutPaidResult result)
|
||||
{
|
||||
var errorMessage = MarkPayoutRequest.GetErrorMessage(result);
|
||||
|
@ -42,9 +42,9 @@ namespace BTCPayServer.Controllers.Greenfield
|
||||
await _payoutProcessorService.GetProcessors(
|
||||
new PayoutProcessorService.PayoutProcessorQuery()
|
||||
{
|
||||
Stores = new[] {storeId},
|
||||
Processors = new[] {LightningAutomatedPayoutSenderFactory.ProcessorName},
|
||||
PaymentMethods = paymentMethod is null ? null : new[] {paymentMethod}
|
||||
Stores = new[] { storeId },
|
||||
Processors = new[] { LightningAutomatedPayoutSenderFactory.ProcessorName },
|
||||
PaymentMethods = paymentMethod is null ? null : new[] { paymentMethod }
|
||||
});
|
||||
|
||||
return Ok(configured.Select(ToModel).ToArray());
|
||||
@ -61,7 +61,7 @@ namespace BTCPayServer.Controllers.Greenfield
|
||||
|
||||
private static AutomatedPayoutBlob FromModel(LightningAutomatedPayoutSettings data)
|
||||
{
|
||||
return new AutomatedPayoutBlob() {Interval = data.IntervalSeconds};
|
||||
return new AutomatedPayoutBlob() { Interval = data.IntervalSeconds };
|
||||
}
|
||||
|
||||
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Greenfield)]
|
||||
@ -75,9 +75,9 @@ namespace BTCPayServer.Controllers.Greenfield
|
||||
(await _payoutProcessorService.GetProcessors(
|
||||
new PayoutProcessorService.PayoutProcessorQuery()
|
||||
{
|
||||
Stores = new[] {storeId},
|
||||
Processors = new[] {LightningAutomatedPayoutSenderFactory.ProcessorName},
|
||||
PaymentMethods = new[] {paymentMethod}
|
||||
Stores = new[] { storeId },
|
||||
Processors = new[] { LightningAutomatedPayoutSenderFactory.ProcessorName },
|
||||
PaymentMethods = new[] { paymentMethod }
|
||||
}))
|
||||
.FirstOrDefault();
|
||||
activeProcessor ??= new PayoutProcessorData();
|
||||
@ -88,7 +88,9 @@ namespace BTCPayServer.Controllers.Greenfield
|
||||
var tcs = new TaskCompletionSource();
|
||||
_eventAggregator.Publish(new PayoutProcessorUpdated()
|
||||
{
|
||||
Data = activeProcessor, Id = activeProcessor.Id, Processed = tcs
|
||||
Data = activeProcessor,
|
||||
Id = activeProcessor.Id,
|
||||
Processed = tcs
|
||||
});
|
||||
await tcs.Task;
|
||||
return Ok(ToModel(activeProcessor));
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user