Add GreenField endpoint for fetching all apps (#4462)

Co-authored-by: Nicolas Dorier <nicolas.dorier@gmail.com>
This commit is contained in:
Umar Bolatov
2023-01-29 16:42:24 -08:00
committed by GitHub
parent b372dc21d6
commit c0c34fbb41
7 changed files with 206 additions and 4 deletions

View File

@@ -52,6 +52,24 @@ namespace BTCPayServer.Client
return await HandleResponse<AppDataBase>(response);
}
public virtual async Task<AppDataBase[]> GetAllApps(string storeId, CancellationToken token = default)
{
if (storeId == null)
throw new ArgumentNullException(nameof(storeId));
var response = await _httpClient.SendAsync(
CreateHttpRequest($"api/v1/stores/{storeId}/apps",
method: HttpMethod.Get), token);
return await HandleResponse<AppDataBase[]>(response);
}
public virtual async Task<AppDataBase[]> GetAllApps(CancellationToken token = default)
{
var response = await _httpClient.SendAsync(
CreateHttpRequest($"api/v1/apps",
method: HttpMethod.Get), token);
return await HandleResponse<AppDataBase[]>(response);
}
public virtual async Task DeleteApp(string appId, CancellationToken token = default)
{
if (appId == null)

View File

@@ -400,6 +400,64 @@ namespace BTCPayServer.Tests
Assert.Equal("Crowdfund", app.AppType);
}
[Fact(Timeout = TestTimeout)]
[Trait("Integration", "Integration")]
public async Task CanGetAllApps()
{
using var tester = CreateServerTester();
await tester.StartAsync();
var user = tester.NewAccount();
await user.RegisterDerivationSchemeAsync("BTC");
var client = await user.CreateClient();
var posApp = await client.CreatePointOfSaleApp(
user.StoreId,
new CreatePointOfSaleAppRequest()
{
AppName = "test app from API",
Currency = "JPY"
}
);
var crowdfundApp = await client.CreateCrowdfundApp(user.StoreId, new CreateCrowdfundAppRequest() { AppName = "test app from API" });
// Create another store and one app on it so we can get all apps from all stores for the user below
var newStore = await client.CreateStore(new CreateStoreRequest() { Name = "A" });
var newApp = await client.CreateCrowdfundApp(newStore.Id, new CreateCrowdfundAppRequest() { AppName = "new app" });
Assert.NotEqual(newApp.Id, user.StoreId);
// Get all apps for a specific store first
var apps = await client.GetAllApps(user.StoreId);
Assert.Equal(2, apps.Length);
Assert.Equal(posApp.Name, apps[0].Name);
Assert.Equal(posApp.StoreId, apps[0].StoreId);
Assert.Equal(posApp.AppType, apps[0].AppType);
Assert.Equal(crowdfundApp.Name, apps[1].Name);
Assert.Equal(crowdfundApp.StoreId, apps[1].StoreId);
Assert.Equal(crowdfundApp.AppType, apps[1].AppType);
// Get all apps for all store now
apps = await client.GetAllApps();
Assert.Equal(3, apps.Length);
Assert.Equal(posApp.Name, apps[0].Name);
Assert.Equal(posApp.StoreId, apps[0].StoreId);
Assert.Equal(posApp.AppType, apps[0].AppType);
Assert.Equal(crowdfundApp.Name, apps[1].Name);
Assert.Equal(crowdfundApp.StoreId, apps[1].StoreId);
Assert.Equal(crowdfundApp.AppType, apps[1].AppType);
Assert.Equal(newApp.Name, apps[2].Name);
Assert.Equal(newApp.StoreId, apps[2].StoreId);
Assert.Equal(newApp.AppType, apps[2].AppType);
}
[Fact(Timeout = TestTimeout)]
[Trait("Integration", "Integration")]
public async Task CanDeleteUsersViaApi()

View File

@@ -25,18 +25,20 @@ namespace BTCPayServer.Controllers.Greenfield
private readonly AppService _appService;
private readonly StoreRepository _storeRepository;
private readonly CurrencyNameTable _currencies;
private readonly UserManager<ApplicationUser> _userManager;
public GreenfieldAppsController(
AppService appService,
StoreRepository storeRepository,
UserManager<ApplicationUser> userManager,
BTCPayNetworkProvider btcPayNetworkProvider,
CurrencyNameTable currencies
CurrencyNameTable currencies,
UserManager<ApplicationUser> userManager
)
{
_appService = appService;
_storeRepository = storeRepository;
_currencies = currencies;
_userManager = userManager;
}
[HttpPost("~/api/v1/stores/{storeId}/apps/crowdfund")]
@@ -143,6 +145,24 @@ namespace BTCPayServer.Controllers.Greenfield
}
}
[HttpGet("~/api/v1/apps")]
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Greenfield)]
public async Task<IActionResult> GetAllApps()
{
var apps = await _appService.GetAllApps(_userManager.GetUserId(User));
return Ok(apps.Select(ToModel).ToArray());
}
[HttpGet("~/api/v1/stores/{storeId}/apps")]
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Greenfield)]
public async Task<IActionResult> GetAllApps(string storeId)
{
var apps = await _appService.GetAllApps(_userManager.GetUserId(User), allowNoUser: false, storeId);
return Ok(apps.Select(ToModel).ToArray());
}
[HttpGet("~/api/v1/apps/{appId}")]
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Greenfield)]
public async Task<IActionResult> GetApp(string appId)
@@ -250,6 +270,18 @@ namespace BTCPayServer.Controllers.Greenfield
};
}
private AppDataBase ToModel(Models.AppViewModels.ListAppsViewModel.ListAppViewModel appData)
{
return new AppDataBase
{
Id = appData.Id,
AppType = appData.AppType,
Name = appData.AppName,
StoreId = appData.StoreId,
Created = appData.Created,
};
}
private PointOfSaleAppData ToPointOfSaleModel(AppData appData)
{
return new PointOfSaleAppData

View File

@@ -1196,6 +1196,18 @@ namespace BTCPayServer.Controllers.Greenfield
await GetController<GreenfieldAppsController>().GetApp(appId));
}
public override async Task<AppDataBase[]> GetAllApps(string storeId, CancellationToken token = default)
{
return GetFromActionResult<AppDataBase[]>(
await GetController<GreenfieldAppsController>().GetAllApps(storeId));
}
public override async Task<AppDataBase[]> GetAllApps(CancellationToken token = default)
{
return GetFromActionResult<AppDataBase[]>(
await GetController<GreenfieldAppsController>().GetAllApps());
}
public override async Task DeleteApp(string appId, CancellationToken token = default)
{
HandleActionResult(await GetController<GreenfieldAppsController>().DeleteApp(appId));

View File

@@ -1,3 +1,6 @@
using System;
namespace BTCPayServer.Models.AppViewModels
{
public class ListAppsViewModel
@@ -14,6 +17,7 @@ namespace BTCPayServer.Models.AppViewModels
public string UpdateAction { get { return "Update" + AppType; } }
public string ViewAction { get { return "View" + AppType; } }
public DateTimeOffset Created { get; set; }
}
public ListAppViewModel[] Apps { get; set; }

View File

@@ -443,7 +443,8 @@ namespace BTCPayServer.Services.Apps
StoreName = us.StoreData.StoreName,
AppName = app.Name,
AppType = app.AppType,
Id = app.Id
Id = app.Id,
Created = app.Created,
})
.ToArrayAsync();

View File

@@ -267,7 +267,84 @@
}
]
}
}
},
"/api/v1/stores/{storeId}/apps": {
"parameters": [
{
"name": "storeId",
"in": "path",
"required": true,
"description": "The store ID",
"schema": {
"type": "string"
}
}
],
"get": {
"tags": [
"Apps"
],
"operationId": "Apps_GetAllAppsForStore",
"summary": "Get basic app data for all apps for a store",
"description": "Returns basic app data for all apps for a store",
"responses": {
"200": {
"description": "Array of basic app data object",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/BasicAppData"
}
}
}
}
}
},
"security": [
{
"API_Key": [
"btcpay.store.canmodifystoresettings"
],
"Basic": []
}
]
}
},
"/api/v1/apps": {
"get": {
"tags": [
"Apps"
],
"operationId": "Apps_GetAllApps",
"summary": "Get basic app data for all apps for all stores for a user",
"description": "Returns basic app data for all apps for all stores",
"responses": {
"200": {
"description": "Array of basic app data object",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/BasicAppData"
}
}
}
}
}
},
"security": [
{
"API_Key": [
"btcpay.store.canmodifystoresettings"
],
"Basic": []
}
]
}
}
},
"components": {
"schemas": {