From 07711c082ee4f01e307211c75543753b1df1ca8f Mon Sep 17 00:00:00 2001 From: Pavel Vesely Date: Tue, 15 Dec 2020 10:49:48 +0100 Subject: [PATCH] FileController - content disposition --- Oqtane.Client/Modules/ModuleBase.cs | 7 ++- Oqtane.Server/Controllers/FileController.cs | 53 ++++++++++++++++---- Oqtane.Server/Extensions/MimeUtilities.cs | 31 ++++++++++++ Oqtane.Server/Extensions/StringExtensions.cs | 13 +---- Oqtane.Shared/Shared/Utilities.cs | 16 ++++-- 5 files changed, 93 insertions(+), 27 deletions(-) create mode 100644 Oqtane.Server/Extensions/MimeUtilities.cs diff --git a/Oqtane.Client/Modules/ModuleBase.cs b/Oqtane.Client/Modules/ModuleBase.cs index bfd9d395..3fd548ac 100644 --- a/Oqtane.Client/Modules/ModuleBase.cs +++ b/Oqtane.Client/Modules/ModuleBase.cs @@ -116,7 +116,12 @@ namespace Oqtane.Modules public string ContentUrl(int fileid) { - return Utilities.ContentUrl(PageState.Alias, fileid); + return ContentUrl(fileid, false); + } + + public string ContentUrl(int fileid, bool asAttachment) + { + return Utilities.ContentUrl(PageState.Alias, fileid, asAttachment); } public virtual Dictionary GetUrlParameters(string parametersTemplate = "") diff --git a/Oqtane.Server/Controllers/FileController.cs b/Oqtane.Server/Controllers/FileController.cs index 5389b423..a5f0ffdd 100644 --- a/Oqtane.Server/Controllers/FileController.cs +++ b/Oqtane.Server/Controllers/FileController.cs @@ -66,7 +66,7 @@ namespace Oqtane.Controllers { foreach (string file in Directory.GetFiles(folder)) { - files.Add(new Models.File { Name = Path.GetFileName(file), Extension = Path.GetExtension(file)?.Replace(".", "") }); + files.Add(new Models.File {Name = Path.GetFileName(file), Extension = Path.GetExtension(file)?.Replace(".", "")}); } } } @@ -147,8 +147,10 @@ namespace Oqtane.Controllers { Directory.CreateDirectory(folderpath); } + System.IO.File.Move(Path.Combine(GetFolderPath(_file.Folder), _file.Name), Path.Combine(folderpath, file.Name)); } + file.Extension = Path.GetExtension(file.Name).ToLower().Replace(".", ""); file = _files.UpdateFile(file); _logger.Log(LogLevel.Information, this, LogFunction.Update, "File Updated {File}", file); @@ -221,7 +223,7 @@ namespace Oqtane.Controllers { _logger.Log(LogLevel.Error, this, LogFunction.Create, "File Could Not Be Downloaded From Url Due To Its File Extension {Url}", url); - HttpContext.Response.StatusCode = (int)HttpStatusCode.Conflict; + HttpContext.Response.StatusCode = (int) HttpStatusCode.Conflict; return file; } @@ -229,7 +231,7 @@ namespace Oqtane.Controllers { _logger.Log(LogLevel.Error, this, LogFunction.Create, $"File Could Not Be Downloaded From Url Due To Its File Name Not Allowed {url}"); - HttpContext.Response.StatusCode = (int)HttpStatusCode.Conflict; + HttpContext.Response.StatusCode = (int) HttpStatusCode.Conflict; return file; } @@ -266,7 +268,7 @@ namespace Oqtane.Controllers if (!file.FileName.IsPathOrFileValid()) { - HttpContext.Response.StatusCode = (int)HttpStatusCode.Conflict; + HttpContext.Response.StatusCode = (int) HttpStatusCode.Conflict; return; } @@ -432,9 +434,38 @@ namespace Oqtane.Controllers return canaccess; } + + /// + /// Get file with header + /// Content-Disposition: inline + /// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition + /// + /// File Id from Oqtane filesystem + /// file content + // GET api//download/5 [HttpGet("download/{id}")] - public IActionResult Download(int id) + public IActionResult DownloadInline(int id) + { + return Download(id, false); + } + /// + /// Get file with header + /// Content-Disposition: attachment; filename="filename.jpg" + /// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition + /// + /// + /// File Id from Oqtane filesystem + /// + + // GET api//download/5/attach + [HttpGet("download/{id}/attach")] + public IActionResult DownloadAttachment(int id) + { + return Download(id, true); + } + + private IActionResult Download(int id, bool asAttachment) { var file = _files.GetFile(id); if (file != null) @@ -444,7 +475,10 @@ namespace Oqtane.Controllers var filepath = Path.Combine(GetFolderPath(file.Folder), file.Name); if (System.IO.File.Exists(filepath)) { - return PhysicalFile(filepath, file.Name.GetMimeType(), file.Name); + var result = asAttachment + ? PhysicalFile(filepath, file.GetMimeType(), file.Name) + : PhysicalFile(filepath, file.GetMimeType()); + return result; } _logger.Log(LogLevel.Error, this, LogFunction.Read, "File Does Not Exist {FileId} {FilePath}", id, filepath); @@ -461,8 +495,9 @@ namespace Oqtane.Controllers _logger.Log(LogLevel.Error, this, LogFunction.Read, "File Not Found {FileId}", id); HttpContext.Response.StatusCode = 404; } + string errorPath = Path.Combine(GetFolderPath("images"), "error.png"); - return System.IO.File.Exists(errorPath) ? PhysicalFile(errorPath, errorPath.GetMimeType()) : null; + return System.IO.File.Exists(errorPath) ? PhysicalFile(errorPath, MimeUtilities.GetMimeType(errorPath)) : null; } private string GetFolderPath(Folder folder) @@ -480,7 +515,7 @@ namespace Oqtane.Controllers if (!Directory.Exists(folderpath)) { string path = ""; - var separators = new char[] { Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar }; + var separators = new char[] {Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar}; string[] folders = folderpath.Split(separators, StringSplitOptions.RemoveEmptyEntries); foreach (string folder in folders) { @@ -501,7 +536,7 @@ namespace Oqtane.Controllers FileInfo fileinfo = new FileInfo(filepath); file.Extension = fileinfo.Extension.ToLower().Replace(".", ""); - file.Size = (int)fileinfo.Length; + file.Size = (int) fileinfo.Length; file.ImageHeight = 0; file.ImageWidth = 0; diff --git a/Oqtane.Server/Extensions/MimeUtilities.cs b/Oqtane.Server/Extensions/MimeUtilities.cs new file mode 100644 index 00000000..f5983da6 --- /dev/null +++ b/Oqtane.Server/Extensions/MimeUtilities.cs @@ -0,0 +1,31 @@ +using Microsoft.AspNetCore.StaticFiles; +using Oqtane.Models; + +namespace Oqtane.Extensions +{ + public static class MimeUtilities + { + /// + /// Return Mime content type based on file extension + /// + /// File name + public static string GetMimeType(string fileName) + { + var provider = new FileExtensionContentTypeProvider(); + + if (!provider.TryGetContentType(fileName, out var contentType)) + contentType = "application/octet-stream"; + // we can add additional mappings here + + return contentType; + } + + /// + /// Return Mime content type based on file extension + /// + public static string GetMimeType(this File file) + { + return GetMimeType(file?.Name); + } + } +} diff --git a/Oqtane.Server/Extensions/StringExtensions.cs b/Oqtane.Server/Extensions/StringExtensions.cs index a2c7c88b..ede3bce9 100644 --- a/Oqtane.Server/Extensions/StringExtensions.cs +++ b/Oqtane.Server/Extensions/StringExtensions.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using System.Linq; using Microsoft.AspNetCore.StaticFiles; +using Oqtane.Models; namespace Oqtane.Extensions { @@ -15,17 +16,5 @@ namespace Oqtane.Extensions return list.Any(f => s.StartsWith(f)); } - - public static string GetMimeType(this string fileName) - { - var provider = new FileExtensionContentTypeProvider(); - - if (!provider.TryGetContentType(fileName, out var contentType)) - { - contentType = "application/octet-stream"; - } - - return contentType; - } } } diff --git a/Oqtane.Shared/Shared/Utilities.cs b/Oqtane.Shared/Shared/Utilities.cs index c2cfc90f..3de29f59 100644 --- a/Oqtane.Shared/Shared/Utilities.cs +++ b/Oqtane.Shared/Shared/Utilities.cs @@ -95,11 +95,17 @@ namespace Oqtane.Shared return NavigateUrl(alias, path, parameters); } - public static string ContentUrl(Alias alias, int fileid) + public static string ContentUrl(Alias alias, int fileId) { - string url = (alias == null) ? "/~" : "/" + alias.AliasId; - url += Constants.ContentUrl + fileid.ToString(); - return url; + return ContentUrl(alias, fileId, false); + } + + public static string ContentUrl(Alias alias, int fileId, bool asAttachment) + { + var aliasUrl = (alias == null) ? "/~" : "/" + alias.AliasId; + var method = asAttachment ? "/attach":""; + + return $"{aliasUrl}{Constants.ContentUrl}{fileId}{method}"; } public static string GetTypeName(string fullyqualifiedtypename) @@ -380,4 +386,4 @@ namespace Oqtane.Shared return dictionary; } } -} \ No newline at end of file +}