-
-
Notifications
You must be signed in to change notification settings - Fork 24
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1 from erossini/Using-EasyMDE
Rewrite the Markdown Editor with EasyMDE
- Loading branch information
Showing
77 changed files
with
27,125 additions
and
201 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
namespace MarkdownEditorDemo.Api.Controllers; | ||
|
||
/// <summary> | ||
/// Files controller | ||
/// </summary> | ||
[ApiController] | ||
[Route("api/[Controller]")] | ||
public class FilesController : ControllerBase | ||
{ | ||
/// <summary> | ||
/// The logger | ||
/// </summary> | ||
private readonly ILogger<FilesController> _logger; | ||
/// <summary> | ||
/// The HTTP context accessor | ||
/// </summary> | ||
private readonly IHttpContextAccessor _httpContextAccessor; | ||
/// <summary> | ||
/// The file size limit | ||
/// </summary> | ||
private readonly long _fileSizeLimit; | ||
/// <summary> | ||
/// The permitted extensions | ||
/// </summary> | ||
private readonly string[] _permittedExtensions = { ".gif", ".png", ".jpg", ".jpeg" }; | ||
/// <summary> | ||
/// The target folder path | ||
/// </summary> | ||
private readonly string _targetFolderPath; | ||
|
||
/// <summary> | ||
/// Initializes a new instance of the <see cref="FilesController"/> class. | ||
/// </summary> | ||
/// <param name="logger">The logger.</param> | ||
/// <param name="config">The configuration.</param> | ||
public FilesController(ILogger<FilesController> logger, IConfiguration config, IHttpContextAccessor httpContextAccessor) | ||
{ | ||
_logger = logger; | ||
_httpContextAccessor = httpContextAccessor; | ||
|
||
_fileSizeLimit = config.GetValue<long>("FileSizeLimit"); | ||
_targetFolderPath = (string)System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().CodeBase); | ||
_targetFolderPath = Path.Combine(_targetFolderPath, "Uploads").Replace("file:\\", ""); | ||
|
||
Directory.CreateDirectory(_targetFolderPath); | ||
} | ||
|
||
/// <summary> | ||
/// Uploads a file. | ||
/// </summary> | ||
/// <returns></returns> | ||
[HttpPost] | ||
[DisableFormValueModelBinding] | ||
public async Task<IActionResult> Upload() | ||
{ | ||
if (!Request.ContentType.IsMultipartContentType()) | ||
{ | ||
ModelState.AddModelError("File", "The request couldn't be processed (Error 1)."); | ||
_logger.LogWarning($"The request content type [{Request.ContentType}] is invalid."); | ||
return BadRequest(ModelState); | ||
} | ||
|
||
var boundary = MediaTypeHeaderValue.Parse(Request.ContentType).GetBoundary(new FormOptions().MultipartBoundaryLengthLimit); | ||
var reader = new MultipartReader(boundary, HttpContext.Request.Body); | ||
var section = await reader.ReadNextSectionAsync(); | ||
|
||
string trustedFileNameForFileStorage = String.Empty; | ||
|
||
while (section != null) | ||
{ | ||
var hasContentDispositionHeader = ContentDispositionHeaderValue.TryParse(section.ContentDisposition, | ||
out var contentDisposition); | ||
|
||
if (hasContentDispositionHeader) | ||
{ | ||
if (contentDisposition.IsFileDisposition()) | ||
{ | ||
// Don't trust the file name sent by the client. To display the file name, HTML-encode the value. | ||
var trustedFileNameForDisplay = WebUtility.HtmlEncode(contentDisposition.FileName.Value); | ||
trustedFileNameForFileStorage = Path.GetFileNameWithoutExtension(Path.GetRandomFileName()) + | ||
Path.GetExtension(trustedFileNameForDisplay); | ||
|
||
var streamedFileContent = await FileHelpers.ProcessStreamedFile(section, contentDisposition, | ||
ModelState, _permittedExtensions, _fileSizeLimit); | ||
|
||
if (!ModelState.IsValid) | ||
return BadRequest(ModelState); | ||
|
||
var trustedFilePath = Path.Combine(_targetFolderPath, trustedFileNameForFileStorage); | ||
using (var targetStream = System.IO.File.Create(trustedFilePath)) | ||
{ | ||
await targetStream.WriteAsync(streamedFileContent); | ||
_logger.LogInformation($"Uploaded file '{trustedFileNameForDisplay}' saved to '{_targetFolderPath}' " + | ||
$"as {trustedFileNameForFileStorage}"); | ||
} | ||
} | ||
} | ||
|
||
// Drain any remaining section body that hasn't been consumed and read the headers for the next section. | ||
section = await reader.ReadNextSectionAsync(); | ||
} | ||
|
||
if (!string.IsNullOrEmpty(trustedFileNameForFileStorage)) | ||
{ | ||
string host = $"{_httpContextAccessor.HttpContext.Request.Scheme}://{_httpContextAccessor.HttpContext.Request.Host.Value}"; | ||
int index = FileHelpers.GetExtensionId(Path.GetExtension(trustedFileNameForFileStorage)); | ||
return Ok($"{host}/{index}/{Path.GetFileName(trustedFileNameForFileStorage)}"); | ||
} | ||
else | ||
return BadRequest("It wasn't possible to upload the file"); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
namespace MarkdownEditorDemo.Api.Controllers | ||
{ | ||
public class HomeController : Controller | ||
{ | ||
/// <summary> | ||
/// The logger | ||
/// </summary> | ||
private readonly ILogger<HomeController> _logger; | ||
/// <summary> | ||
/// The target folder path | ||
/// </summary> | ||
private readonly string _targetFolderPath; | ||
|
||
/// <summary> | ||
/// Initializes a new instance of the <see cref="HomeController"/> class. | ||
/// </summary> | ||
/// <param name="logger">The logger.</param> | ||
/// <param name="config">The configuration.</param> | ||
public HomeController(ILogger<HomeController> logger, IConfiguration config) | ||
{ | ||
_logger = logger; | ||
|
||
_targetFolderPath = (string)System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().CodeBase); | ||
_targetFolderPath = Path.Combine(_targetFolderPath, "Uploads"); | ||
} | ||
|
||
[HttpGet] | ||
[Route("{fileType}/{fileName}")] | ||
public async Task<IActionResult> Download(int fileType, string fileName) | ||
{ | ||
string ext = FileHelpers.GetExtensionById(fileType); | ||
if (ext == null) | ||
{ | ||
_logger.LogInformation($"Extension not found."); | ||
return BadRequest($"Extension not found."); | ||
} | ||
|
||
if(ext != Path.GetExtension(fileName)) | ||
{ | ||
_logger.LogInformation($"File not valid."); | ||
return BadRequest($"File not valid."); | ||
} | ||
|
||
var trustedFilePath = Path.Combine(_targetFolderPath, fileName).Replace("file:\\", ""); | ||
if (!System.IO.File.Exists(trustedFilePath)) | ||
{ | ||
_logger.LogInformation($"File {trustedFilePath} not exists"); | ||
return NotFound($"File {trustedFilePath} not exists"); | ||
} | ||
|
||
_logger.LogInformation($"Downloading file [{trustedFilePath}]."); | ||
var bytes = await System.IO.File.ReadAllBytesAsync(trustedFilePath); | ||
return File(bytes, ext.GetMimeTypes(), trustedFilePath); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
using Microsoft.AspNetCore.Mvc; | ||
|
||
namespace MarkdownEditorDemo.Api.Controllers | ||
{ | ||
[ApiController] | ||
[Route("api/[controller]")] | ||
public class ImageController : Controller | ||
{ | ||
[HttpPost] | ||
public async Task<IActionResult> Upload(IFormFile files) | ||
{ | ||
long size = files.Length; | ||
|
||
var filePath = Path.GetTempFileName(); | ||
|
||
using (var stream = System.IO.File.Create(filePath)) | ||
{ | ||
await files.CopyToAsync(stream); | ||
} | ||
|
||
// Process uploaded files | ||
// Don't rely on or trust the FileName property without validation. | ||
|
||
return Ok(); | ||
|
||
//// Check if thefile is there | ||
//if (file == null) | ||
// return BadRequest("File is required"); | ||
|
||
//// Get the file name | ||
//var fileName = file.FileName; | ||
|
||
//// Get the extension | ||
//var extension = Path.GetExtension(fileName); | ||
|
||
//// Validate the extension based on your business needs | ||
|
||
//// Generate a new file to avoid dublicates = (FileName withoutExtension - GUId.extension) | ||
//var newFileName = $"{Path.GetFileNameWithoutExtension(fileName)}-{Guid.NewGuid().ToString()}{extension}"; | ||
|
||
//// Create the full path of the file including the directory (For this demo we will save the file insidea folder called Data within wwwroot) | ||
//var directoryPath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "Data"); | ||
//var fullPath = Path.Combine(directoryPath, newFileName); | ||
|
||
//// Maek sure the directory is ther bycreating it if it's not exist | ||
//Directory.CreateDirectory(directoryPath); | ||
|
||
//// Create a new file stream where you want to put your file and copy the content from the current file stream to the new one | ||
//using (var fileStream = new FileStream(fullPath, FileMode.Create, FileAccess.Write)) | ||
//{ | ||
// // Copy the content to the new stream | ||
// await file.CopyToAsync(fileStream); | ||
//} | ||
|
||
//// You are done return the new URL which is (yourapplication url/data/newfilename) | ||
//return Ok($"https://localhost:44302/Data/{newFileName}"); | ||
} | ||
} | ||
} |
25 changes: 25 additions & 0 deletions
25
MarkdownEditorDemo.Api/Extensions/MultipartRequestExtensions.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
namespace MarkdownEditorDemo.Api.Extensions; | ||
|
||
public static class MultipartRequestExtensions | ||
{ | ||
// Content-Type: multipart/form-data; boundary="----WebKitFormBoundarymx2fSWqWSd0OxQqq" | ||
// The spec at https://tools.ietf.org/html/rfc2046#section-5.1 states that 70 characters is a reasonable limit. | ||
public static string GetBoundary(this MediaTypeHeaderValue contentType, int lengthLimit) | ||
{ | ||
var boundary = HeaderUtilities.RemoveQuotes(contentType.Boundary).Value; | ||
|
||
if (string.IsNullOrWhiteSpace(boundary)) | ||
throw new InvalidDataException("Missing content-type boundary."); | ||
|
||
if (boundary.Length > lengthLimit) | ||
throw new InvalidDataException($"Multipart boundary length limit {lengthLimit} exceeded."); | ||
|
||
return boundary; | ||
} | ||
|
||
public static bool IsMultipartContentType(this string contentType) | ||
{ | ||
return !string.IsNullOrEmpty(contentType) | ||
&& contentType.IndexOf("multipart/", StringComparison.OrdinalIgnoreCase) >= 0; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
namespace MarkdownEditorDemo.Api.Extensions | ||
{ | ||
public static class StringExtensions | ||
{ | ||
/// <summary> | ||
/// Gets the MIME types. | ||
/// </summary> | ||
/// <param name="ext">The ext.</param> | ||
/// <returns></returns> | ||
public static string GetMimeTypes(this string ext) | ||
{ | ||
switch (ext) | ||
{ | ||
case ".txt": return "text/plain"; | ||
case ".csv": return "text/csv"; | ||
case ".pdf": return "application/pdf"; | ||
case ".doc": return "application/vnd.ms-word"; | ||
case ".xls": return "application/vnd.ms-excel"; | ||
case ".ppt": return "application/vnd.ms-powerpoint"; | ||
case ".docx": return "application/vnd.openxmlformats-officedocument.wordprocessingml.document"; | ||
case ".xlsx": return "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"; | ||
case ".pptx": return "application/vnd.openxmlformats-officedocument.presentationml.presentation"; | ||
case ".png": return "image/png"; | ||
case ".jpg": return "image/jpeg"; | ||
case ".jpeg": return "image/jpeg"; | ||
case ".gif": return "image/gif"; | ||
default: return "application/octet-stream"; | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
using Microsoft.AspNetCore.Mvc.Filters; | ||
using Microsoft.AspNetCore.Mvc.ModelBinding; | ||
|
||
namespace MarkdownEditorDemo.Api.Filters | ||
{ | ||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] | ||
public class DisableFormValueModelBindingAttribute : Attribute, IResourceFilter | ||
{ | ||
public void OnResourceExecuting(ResourceExecutingContext context) | ||
{ | ||
var factories = context.ValueProviderFactories; | ||
factories.RemoveType<FormValueProviderFactory>(); | ||
factories.RemoveType<FormFileValueProviderFactory>(); | ||
factories.RemoveType<JQueryFormValueProviderFactory>(); | ||
} | ||
|
||
public void OnResourceExecuted(ResourceExecutedContext context) | ||
{ | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
global using MarkdownEditorDemo.Api.Extensions; | ||
global using MarkdownEditorDemo.Api.Filters; | ||
global using MarkdownEditorDemo.Api.Utilities; | ||
global using Microsoft.AspNetCore.Http.Features; | ||
global using Microsoft.AspNetCore.Mvc; | ||
global using Microsoft.AspNetCore.WebUtilities; | ||
global using Microsoft.Net.Http.Headers; | ||
global using System.Net; |
Oops, something went wrong.