Greenfield: Lightning addresses API (#4546)

* Greenfield: Lightning addresses API

* add docs

* Apply suggestions from code review

Co-authored-by: d11n <mail@dennisreimann.de>
This commit is contained in:
Andrew Camilleri
2023-01-23 10:11:34 +01:00
committed by GitHub
parent 9086822b94
commit 1d2bebf17a
9 changed files with 478 additions and 2 deletions

View File

@@ -0,0 +1,96 @@
#nullable enable
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using BTCPayServer.Abstractions.Extensions;
using BTCPayServer.Client;
using BTCPayServer.Data;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using AuthenticationSchemes = BTCPayServer.Abstractions.Constants.AuthenticationSchemes;
using LightningAddressData = BTCPayServer.Client.Models.LightningAddressData;
namespace BTCPayServer.Controllers.Greenfield
{
[ApiController]
[Authorize(AuthenticationSchemes = AuthenticationSchemes.Greenfield)]
public class GreenfieldStoreLightningAddressesController : ControllerBase
{
private readonly LightningAddressService _lightningAddressService;
public GreenfieldStoreLightningAddressesController(
LightningAddressService lightningAddressService)
{
_lightningAddressService = lightningAddressService;
}
private LightningAddressData ToModel(BTCPayServer.Data.LightningAddressData data)
{
var blob = data.Blob.GetBlob<LightningAddressDataBlob>();
return new LightningAddressData()
{
Username = data.Username, Max = blob.Max, Min = blob.Min, CurrencyCode = blob.CurrencyCode
};
}
[Authorize(Policy = Policies.CanViewStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Greenfield)]
[HttpGet("~/api/v1/stores/{storeId}/lightning-addresses")]
public async Task<IActionResult> GetStoreLightningAddresses(string storeId)
{
return Ok((await _lightningAddressService.Get(new LightningAddressQuery() {StoreIds = new[] {storeId}}))
.Select(ToModel).ToArray());
}
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Greenfield)]
[HttpDelete("~/api/v1/stores/{storeId}/lightning-addresses/{username}")]
public async Task<IActionResult> RemoveStoreLightningAddress(string storeId, string username)
{
if (await _lightningAddressService.Remove(username, storeId))
{
return Ok();
}
return
this.CreateAPIError(404, "lightning-address-not-found", "The lightning address was not present.");
}
[Authorize(Policy = Policies.CanViewStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Greenfield)]
[HttpGet("~/api/v1/stores/{storeId}/lightning-addresses/{username}")]
public async Task<IActionResult> GetStoreLightningAddress(string storeId, string username)
{
var res = await _lightningAddressService.Get(new LightningAddressQuery()
{
Usernames = new[] {username}, StoreIds = new[] {storeId},
});
return res?.Any() is true ? Ok(ToModel(res.First())) : this.CreateAPIError(404, "lightning-address-not-found", "The lightning address was not present.");
}
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Greenfield)]
[HttpPost("~/api/v1/stores/{storeId}/lightning-addresses/{username}")]
public async Task<IActionResult> AddOrUpdateStoreLightningAddress(
string storeId, string username, LightningAddressData data)
{
if (data.Min <= 0)
{
ModelState.AddModelError(nameof(data.Min), "Minimum must be greater than 0 if provided.");
return this.CreateValidationError(ModelState);
}
if (await _lightningAddressService.Set(new Data.LightningAddressData()
{
StoreDataId = storeId,
Username = username,
Blob = new LightningAddressDataBlob()
{
Max = data.Max, Min = data.Min, CurrencyCode = data.CurrencyCode
}.SerializeBlob()
}))
{
return await GetStoreLightningAddress(storeId, username);
}
return this.CreateAPIError((int)HttpStatusCode.BadRequest, "username-already-used",
"The username is already in use by another store.");
}
}
}

View File

@@ -26,6 +26,7 @@ using NBXplorer.Models;
using Newtonsoft.Json.Linq;
using InvoiceData = BTCPayServer.Client.Models.InvoiceData;
using Language = BTCPayServer.Client.Models.Language;
using LightningAddressData = BTCPayServer.Client.Models.LightningAddressData;
using NotificationData = BTCPayServer.Client.Models.NotificationData;
using PaymentRequestData = BTCPayServer.Client.Models.PaymentRequestData;
using PayoutData = BTCPayServer.Client.Models.PayoutData;
@@ -1232,5 +1233,27 @@ namespace BTCPayServer.Controllers.Greenfield
{
return GetFromActionResult<PayoutData>(await GetController<GreenfieldPullPaymentController>().GetStorePayout(storeId, payoutId));
}
public override async Task<LightningAddressData[]> GetStoreLightningAddresses(string storeId,
CancellationToken token = default)
{
return GetFromActionResult<LightningAddressData[]>(await GetController<GreenfieldStoreLightningAddressesController>().GetStoreLightningAddresses(storeId));
}
public override async Task<LightningAddressData> GetStoreLightningAddress(string storeId, string username, CancellationToken token = default)
{
return GetFromActionResult<LightningAddressData>(await GetController<GreenfieldStoreLightningAddressesController>().GetStoreLightningAddress(storeId, username));
}
public override async Task<LightningAddressData> AddOrUpdateStoreLightningAddress(string storeId, string username, LightningAddressData data,
CancellationToken token = default)
{
return GetFromActionResult<LightningAddressData>(await GetController<GreenfieldStoreLightningAddressesController>().AddOrUpdateStoreLightningAddress(storeId, username, data));
}
public override async Task RemoveStoreLightningAddress(string storeId, string username, CancellationToken token = default)
{
HandleActionResult(await GetController<GreenfieldStoreLightningAddressesController>().RemoveStoreLightningAddress(storeId, username));
}
}
}

View File

@@ -60,8 +60,9 @@ public class LightningAddressService
public async Task<bool> Set(LightningAddressData data)
{
data.Username = NormalizeUsername(data.Username);
await using var context = _applicationDbContextFactory.CreateContext();
var result = (await GetCore(context, new LightningAddressQuery() { Usernames = new[] { data.Username } }))
var result = (await GetCore(context, new LightningAddressQuery() { Usernames = new[] { data.Username} }))
.FirstOrDefault();
if (result is not null)
{
@@ -73,7 +74,6 @@ public class LightningAddressService
context.Remove(result);
}
data.Username = NormalizeUsername(data.Username);
await context.AddAsync(data);
await context.SaveChangesAsync();
_memoryCache.Remove(GetKey(data.Username));
@@ -82,6 +82,7 @@ public class LightningAddressService
public async Task<bool> Remove(string username, string? storeId = null)
{
username = NormalizeUsername(username);
await using var context = _applicationDbContextFactory.CreateContext();
var x = (await GetCore(context, new LightningAddressQuery() { Usernames = new[] { username } })).FirstOrDefault();
if (x is null)

View File

@@ -30,6 +30,7 @@ using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Routing;
using NBitcoin;
using Newtonsoft.Json;
using LightningAddressData = BTCPayServer.Data.LightningAddressData;
using MarkPayoutRequest = BTCPayServer.HostedServices.MarkPayoutRequest;
namespace BTCPayServer