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:
d11n 2023-01-06 14:18:07 +01:00 committed by GitHub
parent 3fa28bb46d
commit d5d0be5824
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
241 changed files with 1815 additions and 1715 deletions

View File

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

View File

@ -1,4 +1,4 @@
#nullable enable
#nullable enable
using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;

View File

@ -1,4 +1,4 @@
#nullable enable
#nullable enable
namespace BTCPayServer.Abstractions.Contracts;
public interface IScopeProvider

View File

@ -1,4 +1,4 @@
using System;
using System;
namespace BTCPayServer.Abstractions.Contracts;

View File

@ -1,4 +1,4 @@
using System.Collections.Generic;
using System.Collections.Generic;
using System.Threading.Tasks;
using NBitcoin;

View File

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

View File

@ -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)
{
}
}

View File

@ -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)
{
}
}

View File

@ -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)
{
}
}

View File

@ -1,9 +1,8 @@
namespace BTCPayServer.Abstractions.Custodians;
public class InsufficientFundsException : CustodianApiException
{
{
public InsufficientFundsException(string message) : base(400, "insufficient-funds", message)
{
}
}

View File

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

View File

@ -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}.")

View File

@ -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.
*/

View File

@ -12,7 +12,7 @@ public interface ICustodian
* Get the unique code that identifies this custodian.
*/
string Code { get; }
string Name { get; }
/**

View File

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

View File

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

View File

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

View File

@ -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)}";
}

View File

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

View File

@ -17,7 +17,7 @@ public class Field
Label = label,
Name = name,
Value = value,
OriginalValue = value,
OriginalValue = value,
Required = required,
HelpText = helpText,
Type = type

View File

@ -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);
}

View File

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

View File

@ -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);
}
}
}

View File

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

View File

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

View File

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

View File

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

View File

@ -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);
}
}

View File

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

View File

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

View File

@ -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);
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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()
{
}
}

View File

@ -9,5 +9,5 @@ public class CustodianData
public Dictionary<string, AssetPairData> TradableAssetPairs { get; set; }
public string[] WithdrawablePaymentMethods { get; set; }
public string[] DepositablePaymentMethods { get; set; }
}

View File

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

View File

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

View File

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

View File

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

View File

@ -1,4 +1,4 @@
namespace BTCPayServer.Client;
namespace BTCPayServer.Client;
public class LockUserRequest
{

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -7,7 +7,7 @@ namespace BTCPayServer.Client.Models
/// </summary>
public string Id { get; set; }
}
public class StoreUserData
{
/// <summary>

View File

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

View File

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

View File

@ -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();

View File

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

View File

@ -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);
}

View File

@ -1,4 +1,4 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
namespace BTCPayServer.Data;

View File

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

View File

@ -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 });

View File

@ -2,5 +2,5 @@ namespace BTCPayServer.Data;
public class TradeResultData
{
}

View File

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

View File

@ -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}");
}

View File

@ -27,8 +27,8 @@ namespace BTCPayServer.Rating
Url = url;
Source = source;
}
public string DisplayName =>
public string DisplayName =>
Source switch
{
RateSource.Direct => Name,

View File

@ -1,4 +1,4 @@
using System.Net.Http;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using BTCPayServer.Rating;

View File

@ -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();

View File

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

View File

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

View File

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

View File

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

View File

@ -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>(() =>

View File

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

View File

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

View File

@ -21,7 +21,7 @@ namespace BTCPayServer.Tests
public PSBTTests(ITestOutputHelper helper) : base(helper)
{
}
[Fact]
[Trait("Selenium", "Selenium")]
public async Task CanPlayWithPSBT()

View File

@ -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);
});
}
}

View File

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

View File

@ -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();

View File

@ -254,7 +254,7 @@ namespace BTCPayServer.Tests
get;
set;
}
public string Email
{
get;

View File

@ -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();

View File

@ -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);
});

View File

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

View File

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

View File

@ -76,7 +76,7 @@ namespace BTCPayServer.Components.MainNav
AppName = a.AppName,
AppType = Enum.Parse<AppType>(a.AppType)
}).ToList();
if (PoliciesSettings.Experimental)
{
// Custodian Accounts

View File

@ -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);
}

View File

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

View File

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

View File

@ -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);
}

View File

@ -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);
}
}

View File

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

View File

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

View File

@ -97,7 +97,7 @@ namespace BTCPayServer.Configuration
}
}
connectionString.CookieFilePath = null;
if (serviceType == ExternalServiceTypes.RTL || serviceType == ExternalServiceTypes.Configurator ||
serviceType == ExternalServiceTypes.ThunderHub || serviceType == ExternalServiceTypes.Torq)
{

View File

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

View File

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

View File

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

View File

@ -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);
}
}

View File

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

View File

@ -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");

View File

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

View File

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

View File

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

View File

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