Greenfield quality of life improvements from feedback (#2880)

* Greenfield quality of life improvements from feedback

fix #2854

* Greenfield quality of life improvements from feedback

fix #2855
This commit is contained in:
Andrew Camilleri
2021-09-25 07:04:34 +02:00
committed by GitHub
parent ef70f4d547
commit 9f6c7180b2
15 changed files with 62 additions and 45 deletions

View File

@@ -47,7 +47,7 @@ namespace BTCPayServer.Client
public virtual async Task<LightningNetworkPaymentMethodData> UpdateStoreLightningNetworkPaymentMethod( public virtual async Task<LightningNetworkPaymentMethodData> UpdateStoreLightningNetworkPaymentMethod(
string storeId, string storeId,
string cryptoCode, LightningNetworkPaymentMethodData paymentMethod, string cryptoCode, UpdateLightningNetworkPaymentMethodRequest paymentMethod,
CancellationToken token = default) CancellationToken token = default)
{ {
var response = await _httpClient.SendAsync( var response = await _httpClient.SendAsync(
@@ -55,10 +55,5 @@ namespace BTCPayServer.Client
bodyPayload: paymentMethod, method: HttpMethod.Put), token); bodyPayload: paymentMethod, method: HttpMethod.Put), token);
return await HandleResponse<LightningNetworkPaymentMethodData>(response); return await HandleResponse<LightningNetworkPaymentMethodData>(response);
} }
public virtual Task<LightningNetworkPaymentMethodData>
UpdateStoreLightningNetworkPaymentMethodToInternalNode(string storeId,
string cryptoCode, CancellationToken token = default) => UpdateStoreLightningNetworkPaymentMethod(
storeId, cryptoCode, new LightningNetworkPaymentMethodData(cryptoCode, "Internal Node", true), token);
} }
} }

View File

@@ -45,7 +45,7 @@ namespace BTCPayServer.Client
} }
public virtual async Task<OnChainPaymentMethodData> UpdateStoreOnChainPaymentMethod(string storeId, public virtual async Task<OnChainPaymentMethodData> UpdateStoreOnChainPaymentMethod(string storeId,
string cryptoCode, OnChainPaymentMethodData paymentMethod, string cryptoCode, UpdateOnChainPaymentMethodRequest paymentMethod,
CancellationToken token = default) CancellationToken token = default)
{ {
var response = await _httpClient.SendAsync( var response = await _httpClient.SendAsync(
@@ -56,7 +56,7 @@ namespace BTCPayServer.Client
public virtual async Task<OnChainPaymentMethodPreviewResultData> public virtual async Task<OnChainPaymentMethodPreviewResultData>
PreviewProposedStoreOnChainPaymentMethodAddresses( PreviewProposedStoreOnChainPaymentMethodAddresses(
string storeId, string cryptoCode, OnChainPaymentMethodData paymentMethod, int offset = 0, string storeId, string cryptoCode, UpdateOnChainPaymentMethodRequest paymentMethod, int offset = 0,
int amount = 10, int amount = 10,
CancellationToken token = default) CancellationToken token = default)
{ {

View File

@@ -4,5 +4,6 @@
{ {
public bool Enabled { get; set; } public bool Enabled { get; set; }
public object Data { get; set; } public object Data { get; set; }
public string CryptoCode { get; set; }
} }
} }

View File

@@ -16,11 +16,14 @@ namespace BTCPayServer.Client.Models
{ {
} }
public LightningNetworkPaymentMethodData(string cryptoCode, string connectionString, bool enabled) public LightningNetworkPaymentMethodData(string cryptoCode, string connectionString, bool enabled, string paymentMethod)
{ {
Enabled = enabled; Enabled = enabled;
CryptoCode = cryptoCode; CryptoCode = cryptoCode;
ConnectionString = connectionString; ConnectionString = connectionString;
PaymentMethod = paymentMethod;
} }
public string PaymentMethod { get; set; }
} }
} }

View File

@@ -30,15 +30,18 @@ namespace BTCPayServer.Client.Models
/// </summary> /// </summary>
public bool Enabled { get; set; } public bool Enabled { get; set; }
public string PaymentMethod { get; set; }
public OnChainPaymentMethodData() public OnChainPaymentMethodData()
{ {
} }
public OnChainPaymentMethodData(string cryptoCode, string derivationScheme, bool enabled, string label, RootedKeyPath accountKeyPath) : public OnChainPaymentMethodData(string cryptoCode, string derivationScheme, bool enabled, string label, RootedKeyPath accountKeyPath, string paymentMethod) :
base(cryptoCode, derivationScheme, label, accountKeyPath) base(cryptoCode, derivationScheme, label, accountKeyPath)
{ {
Enabled = enabled; Enabled = enabled;
PaymentMethod = paymentMethod;
} }
} }
} }

View File

@@ -11,8 +11,8 @@ namespace BTCPayServer.Client.Models
} }
public OnChainPaymentMethodDataWithSensitiveData(string cryptoCode, string derivationScheme, bool enabled, public OnChainPaymentMethodDataWithSensitiveData(string cryptoCode, string derivationScheme, bool enabled,
string label, RootedKeyPath accountKeyPath, Mnemonic mnemonic) : base(cryptoCode, derivationScheme, enabled, string label, RootedKeyPath accountKeyPath, Mnemonic mnemonic, string paymentMethod) : base(cryptoCode, derivationScheme, enabled,
label, accountKeyPath) label, accountKeyPath, paymentMethod)
{ {
Mnemonic = mnemonic; Mnemonic = mnemonic;
} }

View File

@@ -1466,7 +1466,7 @@ namespace BTCPayServer.Tests
Assert.Empty(await client.GetStoreOnChainPaymentMethods(store.Id)); Assert.Empty(await client.GetStoreOnChainPaymentMethods(store.Id));
await AssertHttpError(403, async () => await AssertHttpError(403, async () =>
{ {
await viewOnlyClient.UpdateStoreOnChainPaymentMethod(store.Id, "BTC", new OnChainPaymentMethodData() { }); await viewOnlyClient.UpdateStoreOnChainPaymentMethod(store.Id, "BTC", new UpdateOnChainPaymentMethodRequest() { });
}); });
var xpriv = new Mnemonic("all all all all all all all all all all all all").DeriveExtKey() var xpriv = new Mnemonic("all all all all all all all all all all all all").DeriveExtKey()
@@ -1479,15 +1479,15 @@ namespace BTCPayServer.Tests
}); });
Assert.Equal(firstAddress, (await viewOnlyClient.PreviewProposedStoreOnChainPaymentMethodAddresses(store.Id, "BTC", Assert.Equal(firstAddress, (await viewOnlyClient.PreviewProposedStoreOnChainPaymentMethodAddresses(store.Id, "BTC",
new OnChainPaymentMethodData() { Enabled = true, DerivationScheme = xpub })).Addresses.First().Address); new UpdateOnChainPaymentMethodRequest() { Enabled = true, DerivationScheme = xpub })).Addresses.First().Address);
var method = await client.UpdateStoreOnChainPaymentMethod(store.Id, "BTC", var method = await client.UpdateStoreOnChainPaymentMethod(store.Id, "BTC",
new OnChainPaymentMethodData() { Enabled = true, DerivationScheme = xpub }); new UpdateOnChainPaymentMethodRequest() { Enabled = true, DerivationScheme = xpub });
Assert.Equal(xpub, method.DerivationScheme); Assert.Equal(xpub, method.DerivationScheme);
method = await client.UpdateStoreOnChainPaymentMethod(store.Id, "BTC", method = await client.UpdateStoreOnChainPaymentMethod(store.Id, "BTC",
new OnChainPaymentMethodData() { Enabled = true, DerivationScheme = xpub, Label = "lol", AccountKeyPath = RootedKeyPath.Parse("01020304/1/2/3") }); new UpdateOnChainPaymentMethodRequest() { Enabled = true, DerivationScheme = xpub, Label = "lol", AccountKeyPath = RootedKeyPath.Parse("01020304/1/2/3") });
method = await client.GetStoreOnChainPaymentMethod(store.Id, "BTC"); method = await client.GetStoreOnChainPaymentMethod(store.Id, "BTC");
@@ -1583,7 +1583,7 @@ namespace BTCPayServer.Tests
Assert.Empty(await adminClient.GetStoreLightningNetworkPaymentMethods(store.Id)); Assert.Empty(await adminClient.GetStoreLightningNetworkPaymentMethods(store.Id));
await AssertHttpError(403, async () => await AssertHttpError(403, async () =>
{ {
await viewOnlyClient.UpdateStoreLightningNetworkPaymentMethod(store.Id, "BTC", new LightningNetworkPaymentMethodData() { }); await viewOnlyClient.UpdateStoreLightningNetworkPaymentMethod(store.Id, "BTC", new UpdateLightningNetworkPaymentMethodRequest() { });
}); });
await AssertHttpError(404, async () => await AssertHttpError(404, async () =>
{ {
@@ -1618,37 +1618,33 @@ namespace BTCPayServer.Tests
{ {
var ex = await AssertValidationError(new[] { "ConnectionString" }, async () => var ex = await AssertValidationError(new[] { "ConnectionString" }, async () =>
{ {
await adminClient.UpdateStoreLightningNetworkPaymentMethod(store.Id, "BTC", new LightningNetworkPaymentMethodData() await adminClient.UpdateStoreLightningNetworkPaymentMethod(store.Id, "BTC", new UpdateLightningNetworkPaymentMethodRequest()
{ {
ConnectionString = forbidden, ConnectionString = forbidden,
CryptoCode = "BTC",
Enabled = true Enabled = true
}); });
}); });
Assert.Contains("btcpay.server.canmodifyserversettings", ex.Message); Assert.Contains("btcpay.server.canmodifyserversettings", ex.Message);
// However, the other client should work because he has `btcpay.server.canmodifyserversettings` // However, the other client should work because he has `btcpay.server.canmodifyserversettings`
await admin2Client.UpdateStoreLightningNetworkPaymentMethod(admin2.StoreId, "BTC", new LightningNetworkPaymentMethodData() await admin2Client.UpdateStoreLightningNetworkPaymentMethod(admin2.StoreId, "BTC", new UpdateLightningNetworkPaymentMethodRequest()
{ {
ConnectionString = forbidden, ConnectionString = forbidden,
CryptoCode = "BTC",
Enabled = true Enabled = true
}); });
} }
// Allowed ip should be ok // Allowed ip should be ok
await adminClient.UpdateStoreLightningNetworkPaymentMethod(store.Id, "BTC", new LightningNetworkPaymentMethodData() await adminClient.UpdateStoreLightningNetworkPaymentMethod(store.Id, "BTC", new UpdateLightningNetworkPaymentMethodRequest()
{ {
ConnectionString = "type=clightning;server=tcp://8.8.8.8", ConnectionString = "type=clightning;server=tcp://8.8.8.8",
CryptoCode = "BTC",
Enabled = true Enabled = true
}); });
// If we strip the admin's right, he should not be able to set unsafe anymore, even if the API key is still valid // If we strip the admin's right, he should not be able to set unsafe anymore, even if the API key is still valid
await admin2.MakeAdmin(false); await admin2.MakeAdmin(false);
await AssertValidationError(new[] { "ConnectionString" }, async () => await AssertValidationError(new[] { "ConnectionString" }, async () =>
{ {
await admin2Client.UpdateStoreLightningNetworkPaymentMethod(admin2.StoreId, "BTC", new LightningNetworkPaymentMethodData() await admin2Client.UpdateStoreLightningNetworkPaymentMethod(admin2.StoreId, "BTC", new UpdateLightningNetworkPaymentMethodRequest()
{ {
ConnectionString = "type=clightning;server=tcp://127.0.0.1", ConnectionString = "type=clightning;server=tcp://127.0.0.1",
CryptoCode = "BTC",
Enabled = true Enabled = true
}); });
}); });
@@ -1666,14 +1662,22 @@ namespace BTCPayServer.Tests
}); });
await Assert.ThrowsAsync<GreenFieldValidationException>(async () => await Assert.ThrowsAsync<GreenFieldValidationException>(async () =>
{ {
await nonAdminUserClient.UpdateStoreLightningNetworkPaymentMethod(nonAdminUser.StoreId, "BTC", method); await nonAdminUserClient.UpdateStoreLightningNetworkPaymentMethod(nonAdminUser.StoreId, "BTC", new UpdateLightningNetworkPaymentMethodRequest()
{
Enabled = method.Enabled,
ConnectionString = method.ConnectionString
});
}); });
settings = await tester.PayTester.GetService<SettingsRepository>().GetSettingAsync<PoliciesSettings>(); settings = await tester.PayTester.GetService<SettingsRepository>().GetSettingAsync<PoliciesSettings>();
settings.AllowLightningInternalNodeForAll = true; settings.AllowLightningInternalNodeForAll = true;
await tester.PayTester.GetService<SettingsRepository>().UpdateSetting(settings); await tester.PayTester.GetService<SettingsRepository>().UpdateSetting(settings);
await nonAdminUserClient.UpdateStoreLightningNetworkPaymentMethod(nonAdminUser.StoreId, "BTC", method); await nonAdminUserClient.UpdateStoreLightningNetworkPaymentMethod(nonAdminUser.StoreId, "BTC", new UpdateLightningNetworkPaymentMethodRequest()
{
Enabled = method.Enabled,
ConnectionString = method.ConnectionString
});
} }
[Fact(Timeout = 60 * 2 * 1000)] [Fact(Timeout = 60 * 2 * 1000)]
@@ -1953,7 +1957,7 @@ namespace BTCPayServer.Tests
Assert.Empty(await adminClient.GetStorePaymentMethods(store.Id)); Assert.Empty(await adminClient.GetStorePaymentMethods(store.Id));
await adminClient.UpdateStoreLightningNetworkPaymentMethodToInternalNode(admin.StoreId, "BTC"); await adminClient.UpdateStoreLightningNetworkPaymentMethod(admin.StoreId, "BTC", new UpdateLightningNetworkPaymentMethodRequest("Internal Node", true));
void VerifyLightning(Dictionary<string, GenericPaymentMethodData> dictionary) void VerifyLightning(Dictionary<string, GenericPaymentMethodData> dictionary)
{ {
@@ -1968,7 +1972,7 @@ namespace BTCPayServer.Tests
var randK = new Mnemonic(Wordlist.English, WordCount.Twelve).DeriveExtKey().Neuter().ToString(Network.RegTest); var randK = new Mnemonic(Wordlist.English, WordCount.Twelve).DeriveExtKey().Neuter().ToString(Network.RegTest);
await adminClient.UpdateStoreOnChainPaymentMethod(admin.StoreId, "BTC", await adminClient.UpdateStoreOnChainPaymentMethod(admin.StoreId, "BTC",
new OnChainPaymentMethodData("BTC", randK, true, "testing", null)); new UpdateOnChainPaymentMethodRequest(true, randK, "testing", null));
void VerifyOnChain(Dictionary<string, GenericPaymentMethodData> dictionary) void VerifyOnChain(Dictionary<string, GenericPaymentMethodData> dictionary)
{ {

View File

@@ -518,7 +518,7 @@ namespace BTCPayServer.Controllers.GreenField
} }
public override async Task<OnChainPaymentMethodData> UpdateStoreOnChainPaymentMethod(string storeId, public override async Task<OnChainPaymentMethodData> UpdateStoreOnChainPaymentMethod(string storeId,
string cryptoCode, OnChainPaymentMethodData paymentMethod, string cryptoCode, UpdateOnChainPaymentMethodRequest paymentMethod,
CancellationToken token = default) CancellationToken token = default)
{ {
return GetFromActionResult<OnChainPaymentMethodData>( return GetFromActionResult<OnChainPaymentMethodData>(
@@ -532,7 +532,7 @@ namespace BTCPayServer.Controllers.GreenField
public override Task<OnChainPaymentMethodPreviewResultData> PreviewProposedStoreOnChainPaymentMethodAddresses( public override Task<OnChainPaymentMethodPreviewResultData> PreviewProposedStoreOnChainPaymentMethodAddresses(
string storeId, string cryptoCode, string storeId, string cryptoCode,
OnChainPaymentMethodData paymentMethod, int offset = 0, int amount = 10, CancellationToken token = default) UpdateOnChainPaymentMethodRequest paymentMethod, int offset = 0, int amount = 10, CancellationToken token = default)
{ {
return Task.FromResult(GetFromActionResult<OnChainPaymentMethodPreviewResultData>( return Task.FromResult(GetFromActionResult<OnChainPaymentMethodPreviewResultData>(
_chainPaymentMethodsController.GetProposedOnChainPaymentMethodPreview(storeId, cryptoCode, _chainPaymentMethodsController.GetProposedOnChainPaymentMethodPreview(storeId, cryptoCode,
@@ -772,7 +772,7 @@ namespace BTCPayServer.Controllers.GreenField
public override async Task<LightningNetworkPaymentMethodData> UpdateStoreLightningNetworkPaymentMethod( public override async Task<LightningNetworkPaymentMethodData> UpdateStoreLightningNetworkPaymentMethod(
string storeId, string cryptoCode, string storeId, string cryptoCode,
LightningNetworkPaymentMethodData paymentMethod, CancellationToken token = default) UpdateLightningNetworkPaymentMethodRequest paymentMethod, CancellationToken token = default)
{ {
return GetFromActionResult<LightningNetworkPaymentMethodData>(await return GetFromActionResult<LightningNetworkPaymentMethodData>(await
_storeLightningNetworkPaymentMethodsController.UpdateLightningNetworkPaymentMethod(storeId, cryptoCode, _storeLightningNetworkPaymentMethodsController.UpdateLightningNetworkPaymentMethod(storeId, cryptoCode,
@@ -878,13 +878,6 @@ namespace BTCPayServer.Controllers.GreenField
return Task.FromResult(GetFromActionResult<PermissionMetadata[]>(_homeController.Permissions())); return Task.FromResult(GetFromActionResult<PermissionMetadata[]>(_homeController.Permissions()));
} }
public override async Task<LightningNetworkPaymentMethodData> UpdateStoreLightningNetworkPaymentMethodToInternalNode(string storeId, string cryptoCode,
CancellationToken token = default)
{
//nothing to change, just local client sugar
return await base.UpdateStoreLightningNetworkPaymentMethodToInternalNode(storeId, cryptoCode, token);
}
public override Task<Dictionary<string, GenericPaymentMethodData>> GetStorePaymentMethods(string storeId, bool? enabled = null, CancellationToken token = default) public override Task<Dictionary<string, GenericPaymentMethodData>> GetStorePaymentMethods(string storeId, bool? enabled = null, CancellationToken token = default)
{ {
return Task.FromResult(GetFromActionResult(_storePaymentMethodsController.GetStorePaymentMethods(storeId, enabled))); return Task.FromResult(GetFromActionResult(_storePaymentMethodsController.GetStorePaymentMethods(storeId, enabled)));

View File

@@ -58,7 +58,8 @@ namespace BTCPayServer.Controllers.GreenField
paymentMethod.PaymentId.CryptoCode, paymentMethod.PaymentId.CryptoCode,
paymentMethod.GetExternalLightningUrl()?.ToString() ?? paymentMethod.GetExternalLightningUrl()?.ToString() ??
paymentMethod.GetDisplayableConnectionString(), paymentMethod.GetDisplayableConnectionString(),
!excludedPaymentMethods.Match(paymentMethod.PaymentId) !excludedPaymentMethods.Match(paymentMethod.PaymentId),
paymentMethod.PaymentId.ToStringNormalized()
) )
) )
.Where((result) => enabled is null || enabled == result.Enabled) .Where((result) => enabled is null || enabled == result.Enabled)
@@ -205,7 +206,8 @@ namespace BTCPayServer.Controllers.GreenField
return paymentMethod is null return paymentMethod is null
? null ? null
: new LightningNetworkPaymentMethodData(paymentMethod.PaymentId.CryptoCode, : new LightningNetworkPaymentMethodData(paymentMethod.PaymentId.CryptoCode,
paymentMethod.GetDisplayableConnectionString(), !excluded); paymentMethod.GetDisplayableConnectionString(), !excluded,
paymentMethod.PaymentId.ToStringNormalized());
} }
private bool GetNetwork(string cryptoCode, [MaybeNullWhen(false)] out BTCPayNetwork network) private bool GetNetwork(string cryptoCode, [MaybeNullWhen(false)] out BTCPayNetwork network)

View File

@@ -91,7 +91,7 @@ namespace BTCPayServer.Controllers.GreenField
await _storeRepository.UpdateStore(store); await _storeRepository.UpdateStore(store);
var rawResult = GetExistingBtcLikePaymentMethod(cryptoCode, store); var rawResult = GetExistingBtcLikePaymentMethod(cryptoCode, store);
var result = new OnChainPaymentMethodDataWithSensitiveData(rawResult.CryptoCode, rawResult.DerivationScheme, var result = new OnChainPaymentMethodDataWithSensitiveData(rawResult.CryptoCode, rawResult.DerivationScheme,
rawResult.Enabled, rawResult.Label, rawResult.AccountKeyPath, response.GetMnemonic()); rawResult.Enabled, rawResult.Label, rawResult.AccountKeyPath, response.GetMnemonic(), derivationSchemeSettings.PaymentId.ToStringNormalized());
return Ok(result); return Ok(result);
} }

View File

@@ -57,7 +57,9 @@ namespace BTCPayServer.Controllers.GreenField
.OfType<DerivationSchemeSettings>() .OfType<DerivationSchemeSettings>()
.Select(strategy => .Select(strategy =>
new OnChainPaymentMethodData(strategy.PaymentId.CryptoCode, new OnChainPaymentMethodData(strategy.PaymentId.CryptoCode,
strategy.AccountDerivation.ToString(), !excludedPaymentMethods.Match(strategy.PaymentId), strategy.Label, strategy.GetSigningAccountKeySettings().GetRootedKeyPath())) strategy.AccountDerivation.ToString(), !excludedPaymentMethods.Match(strategy.PaymentId),
strategy.Label, strategy.GetSigningAccountKeySettings().GetRootedKeyPath(),
strategy.PaymentId.ToStringNormalized()))
.Where((result) => enabled is null || enabled == result.Enabled) .Where((result) => enabled is null || enabled == result.Enabled)
.ToList(); .ToList();
} }
@@ -144,7 +146,7 @@ namespace BTCPayServer.Controllers.GreenField
public IActionResult GetProposedOnChainPaymentMethodPreview( public IActionResult GetProposedOnChainPaymentMethodPreview(
string storeId, string storeId,
string cryptoCode, string cryptoCode,
[FromBody] OnChainPaymentMethodDataPreview paymentMethodData, [FromBody] UpdateOnChainPaymentMethodRequest paymentMethodData,
int offset = 0, int amount = 10) int offset = 0, int amount = 10)
{ {
if (!GetCryptoCodeWallet(cryptoCode, out var network, out BTCPayWallet _)) if (!GetCryptoCodeWallet(cryptoCode, out var network, out BTCPayWallet _))
@@ -291,7 +293,8 @@ namespace BTCPayServer.Controllers.GreenField
? null ? null
: new OnChainPaymentMethodData(paymentMethod.PaymentId.CryptoCode, : new OnChainPaymentMethodData(paymentMethod.PaymentId.CryptoCode,
paymentMethod.AccountDerivation.ToString(), !excluded, paymentMethod.Label, paymentMethod.AccountDerivation.ToString(), !excluded, paymentMethod.Label,
paymentMethod.GetSigningAccountKeySettings().GetRootedKeyPath()); paymentMethod.GetSigningAccountKeySettings().GetRootedKeyPath(),
paymentMethod.PaymentId.ToStringNormalized());
} }
} }
} }

View File

@@ -38,6 +38,7 @@ namespace BTCPayServer.Controllers.GreenField
method => method.PaymentId.ToStringNormalized(), method => method.PaymentId.ToStringNormalized(),
method => new GenericPaymentMethodData() method => new GenericPaymentMethodData()
{ {
CryptoCode = method.PaymentId.CryptoCode,
Enabled = enabled.GetValueOrDefault(!excludedPaymentMethods.Match(method.PaymentId)), Enabled = enabled.GetValueOrDefault(!excludedPaymentMethods.Match(method.PaymentId)),
Data = method.PaymentId.PaymentType.GetGreenfieldData(method) Data = method.PaymentId.PaymentType.GetGreenfieldData(method)
})); }));

View File

@@ -64,6 +64,10 @@
"type": "boolean", "type": "boolean",
"description": "Whether the payment method is enabled" "description": "Whether the payment method is enabled"
}, },
"cryptoCode": {
"type": "boolean",
"description": "The currency code of the payment method"
},
"data": { "data": {
"type": "object", "type": "object",
"additionalProperties": false, "additionalProperties": false,

View File

@@ -271,6 +271,10 @@
"cryptoCode": { "cryptoCode": {
"type": "string", "type": "string",
"description": "Crypto code of the payment method" "description": "Crypto code of the payment method"
},
"paymentMethod": {
"type": "string",
"description": "The payment method"
} }
} }
}, },

View File

@@ -463,6 +463,10 @@
"enabled": { "enabled": {
"type": "boolean", "type": "boolean",
"description": "Whether the payment method is enabled" "description": "Whether the payment method is enabled"
},
"paymentMethod": {
"type": "string",
"description": "The payment method"
} }
} }
}, },