diff --git a/Core/Entities/LeafInput.cs b/Core/Entities/LeafInput.cs index d162f50..dc25d44 100644 --- a/Core/Entities/LeafInput.cs +++ b/Core/Entities/LeafInput.cs @@ -5,6 +5,7 @@ using System.ComponentModel.DataAnnotations.Schema; using System.IO; using System.IO.Compression; using System.Linq; +using LeafWeb.Core.Utility; namespace LeafWeb.Core.Entities { @@ -133,56 +134,102 @@ namespace LeafWeb.Core.Entities #endregion - public override string ToString() + public override string ToString() { return $"{Id}_{Identifier}"; } - /// + /// /// Contains all output files in a zip /// public byte[] GetOutputFileZip(LeafOutputFileType? fileType) - { - using (var compressedFileStream = new MemoryStream()) - { - using (var archive = new ZipArchive(compressedFileStream, ZipArchiveMode.Create, true)) - { - foreach (var outputFile in OutputFiles.Where(f => !fileType.HasValue || f.FileType == fileType.Value)) - { - var entry = archive.CreateEntry(outputFile.Filename); - using (var originalFileStream = new MemoryStream(outputFile.FileContents.Contents)) - using (var entryStream = entry.Open()) - originalFileStream.CopyTo(entryStream); - } - } - return compressedFileStream.ToArray(); - } - } - - /// - /// Contains all input files in a zip - /// - public byte[] GetInputFileZip() - { - using (var compressedFileStream = new MemoryStream()) - { - using (var archive = new ZipArchive(compressedFileStream, ZipArchiveMode.Create, true)) - { - foreach (var inputFile in InputFiles) - { - var entry = archive.CreateEntry(inputFile.Filename); - using (var originalFileStream = new MemoryStream(inputFile.Contents)) - using (var entryStream = entry.Open()) - originalFileStream.CopyTo(entryStream); - } - } - return compressedFileStream.ToArray(); - } + { + return NewMemoryZipArchive((archive, stream) => + CompressOutputFiles( + OutputFiles.Where(f => !fileType.HasValue || f.FileType == fileType.Value), + archive)); } - public int GetOutputFileSizeSum() + /// + /// Contains all input files in a zip + /// + public byte[] GetInputFileZip() => + NewMemoryZipArchive((archive, stream) => CompressInputFiles(InputFiles, archive)); + + /// + /// Contains all input files in a zip, ordered into directories + /// + public static byte[] GetInputFilesZip(IEnumerable leafInputs) => + NewMemoryZipArchive((archive, stream) => + { + var inputs = leafInputs.ToList(); + + foreach (var leafInput in inputs) + { + var directory = $"{leafInput.Added:yyyy-dd-MM--HH-mm}_{leafInput.Identifier.FilterValidFilename()}"; + CompressInputFiles(leafInput.InputFiles, archive, directory); + } + }); + + /// + /// Contains all input files in a zip, ordered into directories + /// + public static byte[] GetOutputFilesZip_ToUser(IEnumerable leafInputs) => + NewMemoryZipArchive((archive, stream) => + { + var inputs = leafInputs.ToList(); + + foreach (var leafInput in inputs) + { + if (stream.Length > 2560000L) + continue; + var directory = $"{leafInput.Added:yyyy-dd-MM--HH-mm}_{leafInput.Identifier.FilterValidFilename()}"; + CompressOutputFiles(leafInput.OutputFiles.Where(f => f.FileType == LeafOutputFileType.ToUser), archive, directory); + } + }); + + private static byte[] NewMemoryZipArchive(Action addFiles) + { + using (var compressedFileStream = new MemoryStream()) + using (var archive = new ZipArchive(compressedFileStream, ZipArchiveMode.Create, true)) + { + addFiles(archive, compressedFileStream); + return compressedFileStream.ToArray(); + } + } + + private static long CompressInputFiles(IEnumerable inputFiles, ZipArchive archive, string prefix = "") + { + var contentsLength = 0L; + foreach (var inputFile in inputFiles) + { + contentsLength += inputFile.Contents.LongLength; + var entry = archive.CreateEntry(Path.Combine(prefix, inputFile.Filename)); + using (var originalFileStream = new MemoryStream(inputFile.Contents)) + using (var entryStream = entry.Open()) + originalFileStream.CopyTo(entryStream); + } + + return contentsLength; + } + + private static long CompressOutputFiles(IEnumerable outputFiles, ZipArchive archive, string prefix = "") + { + var contentsLength = 0L; + foreach (var outputFile in outputFiles) + { + contentsLength += outputFile.FileContents.Contents.LongLength; + var entry = archive.CreateEntry(Path.Combine(prefix, outputFile.Filename)); + using (var originalFileStream = new MemoryStream(outputFile.FileContents.Contents)) + using (var entryStream = entry.Open()) + originalFileStream.CopyTo(entryStream); + } + return contentsLength; + } + + public int GetOutputFileSizeSum() { return OutputFiles.Sum(o => o.FileContents.Contents.Length); } - } + } } \ No newline at end of file diff --git a/WebCms/Controllers/QueueController.cs b/WebCms/Controllers/QueueController.cs index 46237e7..c5488e5 100644 --- a/WebCms/Controllers/QueueController.cs +++ b/WebCms/Controllers/QueueController.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Caching; @@ -92,7 +93,7 @@ namespace LeafWeb.WebCms.Controllers return serviceDescription; } - public ActionResult Details(int id) + public ActionResult Details(int id) { var leafInput = DataService.GetLeafInput(id); @@ -106,27 +107,37 @@ namespace LeafWeb.WebCms.Controllers return View(viewModel); } - public ActionResult DownloadInput(int id) + public ActionResult DownloadInput(int id) { return GetInputZip(id); } - public ActionResult DownloadOutputToUser(int id) + public ActionResult DownloadOutputToUser(int id) { return GetOutputZip(id, LeafOutputFileType.ToUser); } - public ActionResult DownloadOutputNotToUser(int id) + public ActionResult DownloadOutputNotToUser(int id) { return GetOutputZip(id, LeafOutputFileType.NotToUser); } - public ActionResult DownloadOutputCleanedInput(int id) + public ActionResult DownloadOutputCleanedInput(int id) { return GetOutputZip(id, LeafOutputFileType.CleanedInput); } - private ActionResult GetOutputZip(int id, LeafOutputFileType type) + public ActionResult DownloadResultsInputZip(LeafDataQuery q) + { + return GetResults(q, LeafInput.GetInputFilesZip, $"LeafWeb_{DateTime.Now:yyyy-dd-MM--HH-mm-ss}_Input.zip"); + } + + public ActionResult DownloadResultsOutputZip(LeafDataQuery q) + { + return GetResults(q, LeafInput.GetOutputFilesZip_ToUser, $"LeafWeb_{DateTime.Now:yyyy-dd-MM--HH-mm-ss}_Output.zip"); + } + + private ActionResult GetOutputZip(int id, LeafOutputFileType type) { var leafInput = DataService.GetLeafInput(id); @@ -140,7 +151,7 @@ namespace LeafWeb.WebCms.Controllers return new FileContentResult(zip, "application/zip") { FileDownloadName = filename }; } - private ActionResult GetInputZip(int id) + private ActionResult GetInputZip(int id) { var leafInput = DataService.GetLeafInput(id); @@ -154,7 +165,24 @@ namespace LeafWeb.WebCms.Controllers return new FileContentResult(zip, "application/zip") { FileDownloadName = filename }; } - [ActionLog] + private ActionResult GetResults(LeafDataQuery query, Func, byte[]> getZip, string filename) + { + var resultItems = + DataService.GetLeafInputsOrdered(); + + resultItems = QueryFilter.Search(resultItems, query); + + if (resultItems == null) + return View("DownloadNotFound"); + + var zip = getZip(resultItems); + + //var filename = $"LeafWeb_{DateTime.Now:yyyy-dd-MM--HH-mm-ss}_Input.zip"; + + return new FileContentResult(zip, "application/zip") { FileDownloadName = filename }; + } + + [ActionLog] public ActionResult Delete(int id) { var leafInput = DataService.GetLeafInput(id); @@ -178,7 +206,7 @@ namespace LeafWeb.WebCms.Controllers return RedirectToUmbracoPage(LeafWebPageIds.ManageQueue); } - [ActionLog] + [ActionLog] public ActionResult Cancel(int id) { var leafInput = DataService.GetLeafInput(id); diff --git a/WebCms/Utility/NameValueCollectionUtil.cs b/WebCms/Utility/NameValueCollectionUtil.cs index 7d57e77..b808bd2 100644 --- a/WebCms/Utility/NameValueCollectionUtil.cs +++ b/WebCms/Utility/NameValueCollectionUtil.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Collections.Specialized; using System.Linq; using System.Web; +using System.Web.Routing; namespace LeafWeb.WebCms.Utility { @@ -27,5 +28,13 @@ namespace LeafWeb.WebCms.Utility return nvs; } + + public static RouteValueDictionary ToRouteValueDictionary(this NameValueCollection nvc) + { + var routeValues = new RouteValueDictionary(); + foreach (var key in nvc.AllKeys) + routeValues.Add(key, nvc[key]); + return routeValues; + } } } \ No newline at end of file diff --git a/WebCms/Views/Queue/Index.cshtml b/WebCms/Views/Queue/Index.cshtml index 02890e5..1d3f986 100644 --- a/WebCms/Views/Queue/Index.cshtml +++ b/WebCms/Views/Queue/Index.cshtml @@ -94,6 +94,8 @@ @if (Model.Items.Any()) { + @DownloadResultsInput() + @DownloadResultsOutput_ToUser()
@grid.Table(columns: grid.Columns( @@ -155,14 +157,14 @@ else @helper DetailsLink(dynamic item) { - var cssClass= CssClassUtil.CreateCssClassDataDictionary("dropdown-item"); + var cssClass = CssClassUtil.CreateCssClassDataDictionary("dropdown-item"); @Html.Partial("DisplayTemplates/_DetailsLink", (int)item.Id, cssClass) } @helper ChartLink(dynamic item) { - var cssClass= CssClassUtil.CreateCssClassDataDictionary("dropdown-item"); + var cssClass = CssClassUtil.CreateCssClassDataDictionary("dropdown-item"); if (!item.HasLeafChart) { @@ -224,7 +226,7 @@ else } @helper DeleteLink(LeafInput item) { - var cssClass + var cssClass = CssClassUtil.CreateCssClassDataDictionary("dropdown-item"); if (!item.IsDeletable) { @@ -235,7 +237,7 @@ else @helper CancelLink(LeafInput item) { - var cssClass + var cssClass = CssClassUtil.CreateCssClassDataDictionary("dropdown-item"); if (!item.IsCancellable) { @@ -246,7 +248,7 @@ else @helper PriorityForm(LeafInput item, Priority priority) { - var cssClass + var cssClass = CssClassUtil.CreateCssClassDataDictionary("dropdown-item"); @Html.Partial("DisplayTemplates/_PriorityForm", Tuple.Create(item.Id, item.PendingPriority, priority), cssClass) @@ -256,4 +258,19 @@ else { if (disabled) {disabled} +} + + +@helper DownloadResultsInput() +{ + + Input + +} + +@helper DownloadResultsOutput_ToUser() +{ + + Output + } \ No newline at end of file