mirror of
https://github.com/aljazceru/btcpayserver.git
synced 2025-12-18 14:34:23 +01:00
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:
@@ -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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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,12 +217,9 @@ namespace BTCPayServer.Controllers
|
|||||||
Severity = statusMessageSeverity
|
Severity = statusMessageSeverity
|
||||||
});
|
});
|
||||||
|
|
||||||
if (fileIds.Count == 1)
|
|
||||||
{
|
|
||||||
return RedirectToAction(nameof(Files), new
|
return RedirectToAction(nameof(Files), new
|
||||||
{
|
{
|
||||||
statusMessage = "File added!",
|
fileIds = fileIds.ToArray(),
|
||||||
fileId = fileIds[0]
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -203,11 +227,6 @@ namespace BTCPayServer.Controllers
|
|||||||
return RedirectToAction(nameof(Files));
|
return RedirectToAction(nameof(Files));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
return RedirectToAction(nameof(Files));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private string GetUserId()
|
private string GetUserId()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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,9 +63,15 @@ 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)
|
||||||
|
{
|
||||||
|
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 mb-2">
|
||||||
<div class="card-text">
|
<div class="card-text">
|
||||||
<ul class="list-group list-group-flush">
|
<ul class="list-group list-group-flush">
|
||||||
@@ -74,21 +80,22 @@ else
|
|||||||
</li>
|
</li>
|
||||||
<li class="list-group-item">
|
<li class="list-group-item">
|
||||||
<strong>URL:</strong>
|
<strong>URL:</strong>
|
||||||
<a asp-action="GetFile" asp-controller="Storage" asp-route-fileId="@Model.SelectedFileId" target="_blank">
|
<a asp-action="GetFile" asp-controller="Storage" asp-route-fileId="@fileId" target="_blank">
|
||||||
@Url.Action("GetFile", "Storage", new
|
@Url.Action("GetFile", "Storage", new
|
||||||
{
|
{
|
||||||
fileId = Model.SelectedFileId
|
fileId = fileId
|
||||||
}, Context.Request.Scheme, Context.Request.Host.ToString())
|
}, Context.Request.Scheme, Context.Request.Host.ToString())
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="list-group-item">
|
<li class="list-group-item">
|
||||||
<strong>Direct URL:</strong>
|
<strong>Direct URL:</strong>
|
||||||
<a href="@Model.DirectFileUrl" target="_blank" rel="noreferrer noopener">@Model.DirectFileUrl</a>
|
<a href="@fileUrl" target="_blank" rel="noreferrer noopener">@fileUrl</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@if (Model.StorageConfigured)
|
@if (Model.StorageConfigured)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user