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

View File

@@ -22,24 +22,51 @@ using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace BTCPayServer.Controllers
{
public partial class ServerController
{
[HttpGet("server/files/{fileId?}")]
public async Task<IActionResult> Files(string fileId = null)
[HttpGet("server/files")]
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()
{
Files = await _StoredFileRepository.GetFiles(),
SelectedFileId = string.IsNullOrEmpty(fileUrl) ? null : fileId,
DirectFileUrl = fileUrl,
Files = await _StoredFileRepository.GetFiles(),
DirectUrlByFiles = 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);
}
@@ -51,7 +78,7 @@ namespace BTCPayServer.Controllers
await _FileService.RemoveFile(fileId, null);
return RedirectToAction(nameof(Files), new
{
fileId = "",
fileIds = Array.Empty<string>(),
statusMessage = "File removed"
});
}
@@ -127,7 +154,7 @@ namespace BTCPayServer.Controllers
});
return RedirectToAction(nameof(Files), new
{
fileId
fileIds = new string[] { fileId }
});
}
@@ -190,18 +217,10 @@ namespace BTCPayServer.Controllers
Severity = statusMessageSeverity
});
if (fileIds.Count == 1)
{
return RedirectToAction(nameof(Files), new
{
statusMessage = "File added!",
fileId = fileIds[0]
});
}
else
{
return RedirectToAction(nameof(Files));
}
return RedirectToAction(nameof(Files), new
{
fileIds = fileIds.ToArray(),
});
}
else
{

View File

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

View File

@@ -45,7 +45,7 @@ else
<td>@file.Timestamp.ToBrowserDate()</td>
<td>@file.ApplicationUser.UserName</td>
<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="DeleteFile" asp-route-fileId="@file.Id">Remove</a>
</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));
<div class="card mb-2">
<div class="card-text">
<ul class="list-group list-group-flush">
<li class="list-group-item">
@file.FileName
</li>
<li class="list-group-item">
<strong>URL:</strong>
<a asp-action="GetFile" asp-controller="Storage" asp-route-fileId="@Model.SelectedFileId" target="_blank">
@Url.Action("GetFile", "Storage", new
{
fileId = Model.SelectedFileId
}, Context.Request.Scheme, Context.Request.Host.ToString())
</a>
</li>
<li class="list-group-item">
<strong>Direct URL:</strong>
<a href="@Model.DirectFileUrl" target="_blank" rel="noreferrer noopener">@Model.DirectFileUrl</a>
</li>
</ul>
foreach (KeyValuePair<string, string> fileUrlPair in Model.DirectUrlByFiles)
{
var fileId = fileUrlPair.Key;
var fileUrl = fileUrlPair.Value;
var file = Model.Files.Single(storedFile => storedFile.Id.Equals(fileId, StringComparison.InvariantCultureIgnoreCase));
<div class="card mb-2">
<div class="card-text">
<ul class="list-group list-group-flush">
<li class="list-group-item">
@file.FileName
</li>
<li class="list-group-item">
<strong>URL:</strong>
<a asp-action="GetFile" asp-controller="Storage" asp-route-fileId="@fileId" target="_blank">
@Url.Action("GetFile", "Storage", new
{
fileId = fileId
}, Context.Request.Scheme, Context.Request.Host.ToString())
</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>
}
}
@if (Model.StorageConfigured)