Enhance files actions to accept arrays of fileids (#2735)

* Enhanced Files action by modifying it to accept a list of SelectedFileIds

* Added checks to verify all files passed to the files action exist, Updated tests

* Enhanced Files action to accept an array of fileIds

* Removed redundant fileId list
This commit is contained in:
Ayush Jain
2021-08-09 20:10:55 +05:30
committed by GitHub
parent 9387c2c771
commit 2dfb637e2f
4 changed files with 82 additions and 57 deletions

View File

@@ -13,6 +13,7 @@ using BTCPayServer.Tests.Logging;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using Newtonsoft.Json;
using Xunit; using Xunit;
using Xunit.Abstractions; using Xunit.Abstractions;
@@ -185,22 +186,23 @@ namespace BTCPayServer.Tests
fileList.Add(TestUtils.GetFormFile("uploadtestfile1.txt", fileContent)); fileList.Add(TestUtils.GetFormFile("uploadtestfile1.txt", fileContent));
var uploadFormFileResult = Assert.IsType<RedirectToActionResult>(await controller.CreateFiles(fileList)); var uploadFormFileResult = Assert.IsType<RedirectToActionResult>(await controller.CreateFiles(fileList));
Assert.True(uploadFormFileResult.RouteValues.ContainsKey("fileId")); Assert.True(uploadFormFileResult.RouteValues.ContainsKey("fileIds"));
var fileId = uploadFormFileResult.RouteValues["fileId"].ToString(); string[] uploadFileList = (string[])uploadFormFileResult.RouteValues["fileIds"];
var fileId = uploadFileList[0];
Assert.Equal("Files", uploadFormFileResult.ActionName); Assert.Equal("Files", uploadFormFileResult.ActionName);
//check if file was uploaded and saved in db //check if file was uploaded and saved in db
var viewFilesViewModel = var viewFilesViewModel =
Assert.IsType<ViewFilesViewModel>(Assert.IsType<ViewResult>(await controller.Files(fileId)).Model); Assert.IsType<ViewFilesViewModel>(Assert.IsType<ViewResult>(await controller.Files(new string[] { fileId })).Model);
Assert.NotEmpty(viewFilesViewModel.Files); Assert.NotEmpty(viewFilesViewModel.Files);
Assert.Equal(fileId, viewFilesViewModel.SelectedFileId); Assert.True(viewFilesViewModel.DirectUrlByFiles.ContainsKey(fileId));
Assert.NotEmpty(viewFilesViewModel.DirectFileUrl); Assert.NotEmpty(viewFilesViewModel.DirectUrlByFiles[fileId]);
//verify file is available and the same //verify file is available and the same
var net = new System.Net.WebClient(); var net = new System.Net.WebClient();
var data = await net.DownloadStringTaskAsync(new Uri(viewFilesViewModel.DirectFileUrl)); var data = await net.DownloadStringTaskAsync(new Uri(viewFilesViewModel.DirectUrlByFiles[fileId]));
Assert.Equal(fileContent, data); Assert.Equal(fileContent, data);
//create a temporary link to file //create a temporary link to file
@@ -232,10 +234,8 @@ namespace BTCPayServer.Tests
//attempt to fetch deleted file //attempt to fetch deleted file
viewFilesViewModel = viewFilesViewModel =
Assert.IsType<ViewFilesViewModel>(Assert.IsType<ViewResult>(await controller.Files(fileId)).Model); Assert.IsType<ViewFilesViewModel>(Assert.IsType<ViewResult>(await controller.Files(new string[] { fileId })).Model);
Assert.Null(viewFilesViewModel.DirectUrlByFiles);
Assert.Null(viewFilesViewModel.DirectFileUrl);
Assert.Null(viewFilesViewModel.SelectedFileId);
} }

View File

@@ -22,24 +22,51 @@ using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering; using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.AspNetCore.Mvc.ViewFeatures; using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
namespace BTCPayServer.Controllers namespace BTCPayServer.Controllers
{ {
public partial class ServerController public partial class ServerController
{ {
[HttpGet("server/files/{fileId?}")] [HttpGet("server/files")]
public async Task<IActionResult> Files(string fileId = null) public async Task<IActionResult> Files([FromQuery] string[] fileIds = null)
{ {
var fileUrl = string.IsNullOrEmpty(fileId) ? null : await _FileService.GetFileUrl(Request.GetAbsoluteRootUri(), fileId);
var model = new ViewFilesViewModel() var model = new ViewFilesViewModel()
{ {
Files = await _StoredFileRepository.GetFiles(), Files = await _StoredFileRepository.GetFiles(),
SelectedFileId = string.IsNullOrEmpty(fileUrl) ? null : fileId, DirectUrlByFiles = null,
DirectFileUrl = fileUrl,
StorageConfigured = (await _SettingsRepository.GetSettingAsync<StorageSettings>()) != null StorageConfigured = (await _SettingsRepository.GetSettingAsync<StorageSettings>()) != null
}; };
if (fileIds != null && fileIds.Length > 0)
{
bool allFilesExist = true;
Dictionary<string, string> directUrlByFiles = new Dictionary<string, string>();
foreach (string filename in fileIds)
{
string fileUrl = await _FileService.GetFileUrl(Request.GetAbsoluteRootUri(), filename);
if (fileUrl == null)
{
allFilesExist = false;
break;
}
directUrlByFiles.Add(filename, fileUrl);
}
if (!allFilesExist)
{
this.TempData.SetStatusMessageModel(new StatusMessageModel()
{
Message = "Some of the files were not found",
Severity = StatusMessageModel.StatusSeverity.Warning,
});
}
else
{
model.DirectUrlByFiles = directUrlByFiles;
}
}
return View(model); return View(model);
} }
@@ -51,7 +78,7 @@ namespace BTCPayServer.Controllers
await _FileService.RemoveFile(fileId, null); await _FileService.RemoveFile(fileId, null);
return RedirectToAction(nameof(Files), new return RedirectToAction(nameof(Files), new
{ {
fileId = "", fileIds = Array.Empty<string>(),
statusMessage = "File removed" statusMessage = "File removed"
}); });
} }
@@ -127,7 +154,7 @@ namespace BTCPayServer.Controllers
}); });
return RedirectToAction(nameof(Files), new return RedirectToAction(nameof(Files), new
{ {
fileId fileIds = new string[] { fileId }
}); });
} }
@@ -190,18 +217,10 @@ namespace BTCPayServer.Controllers
Severity = statusMessageSeverity Severity = statusMessageSeverity
}); });
if (fileIds.Count == 1) return RedirectToAction(nameof(Files), new
{ {
return RedirectToAction(nameof(Files), new fileIds = fileIds.ToArray(),
{ });
statusMessage = "File added!",
fileId = fileIds[0]
});
}
else
{
return RedirectToAction(nameof(Files));
}
} }
else else
{ {

View File

@@ -6,8 +6,7 @@ namespace BTCPayServer.Models.ServerViewModels
public class ViewFilesViewModel public class ViewFilesViewModel
{ {
public List<StoredFile> Files { get; set; } public List<StoredFile> Files { get; set; }
public string DirectFileUrl { get; set; } public Dictionary<string, string> DirectUrlByFiles { get; set; }
public string SelectedFileId { get; set; }
public bool StorageConfigured { get; set; } public bool StorageConfigured { get; set; }
} }
} }

View File

@@ -45,7 +45,7 @@ else
<td>@file.Timestamp.ToBrowserDate()</td> <td>@file.Timestamp.ToBrowserDate()</td>
<td>@file.ApplicationUser.UserName</td> <td>@file.ApplicationUser.UserName</td>
<td class="text-end"> <td class="text-end">
<a asp-action="Files" asp-route-fileId="@file.Id">Get Link</a> <a href="@Url.Action("Files", "Server", new { fileIds = new string[] { file.Id} })">Get Link</a>
- <a asp-action="CreateTemporaryFileUrl" asp-route-fileId="@file.Id">Get Temp Link</a> - <a asp-action="CreateTemporaryFileUrl" asp-route-fileId="@file.Id">Get Temp Link</a>
- <a asp-action="DeleteFile" asp-route-fileId="@file.Id">Remove</a> - <a asp-action="DeleteFile" asp-route-fileId="@file.Id">Remove</a>
</td> </td>
@@ -63,31 +63,38 @@ else
} }
@if (!string.IsNullOrEmpty(Model.SelectedFileId)) @if(Model.DirectUrlByFiles!=null && Model.DirectUrlByFiles.Count > 0)
{ {
var file = Model.Files.Single(storedFile => storedFile.Id.Equals(Model.SelectedFileId, StringComparison.InvariantCultureIgnoreCase)); foreach (KeyValuePair<string, string> fileUrlPair in Model.DirectUrlByFiles)
<div class="card mb-2"> {
<div class="card-text"> var fileId = fileUrlPair.Key;
<ul class="list-group list-group-flush"> var fileUrl = fileUrlPair.Value;
<li class="list-group-item"> var file = Model.Files.Single(storedFile => storedFile.Id.Equals(fileId, StringComparison.InvariantCultureIgnoreCase));
@file.FileName
</li>
<li class="list-group-item"> <div class="card mb-2">
<strong>URL:</strong> <div class="card-text">
<a asp-action="GetFile" asp-controller="Storage" asp-route-fileId="@Model.SelectedFileId" target="_blank"> <ul class="list-group list-group-flush">
@Url.Action("GetFile", "Storage", new <li class="list-group-item">
{ @file.FileName
fileId = Model.SelectedFileId </li>
}, Context.Request.Scheme, Context.Request.Host.ToString()) <li class="list-group-item">
</a> <strong>URL:</strong>
</li> <a asp-action="GetFile" asp-controller="Storage" asp-route-fileId="@fileId" target="_blank">
<li class="list-group-item"> @Url.Action("GetFile", "Storage", new
<strong>Direct URL:</strong> {
<a href="@Model.DirectFileUrl" target="_blank" rel="noreferrer noopener">@Model.DirectFileUrl</a> fileId = fileId
</li> }, Context.Request.Scheme, Context.Request.Host.ToString())
</ul> </a>
</li>
<li class="list-group-item">
<strong>Direct URL:</strong>
<a href="@fileUrl" target="_blank" rel="noreferrer noopener">@fileUrl</a>
</li>
</ul>
</div>
</div> </div>
</div> }
} }
@if (Model.StorageConfigured) @if (Model.StorageConfigured)