using Core; using LiMan.APi.Data; using LiMan.DB.DBModels; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.StaticFiles; using Microsoft.Extensions.Configuration; using NLog; using System; using System.Collections.Generic; using System.IO; using System.Net; using System.Threading.Tasks; namespace LiMan.APi.Controllers { /// /// Controller caricamento file /// [ApiController] [Route("api/filesave")] public class FilesaveController : ControllerBase { #region Private Fields private static IConfiguration _configuration; /// /// Classe per logging /// private static NLog.Logger Log = LogManager.GetCurrentClassLogger(); private readonly IWebHostEnvironment env; #endregion Private Fields #region Public Constructors /// /// Init generico /// /// /// /// public FilesaveController(IConfiguration configuration, ApiDataService DataService, IWebHostEnvironment env) { dataService = DataService; _configuration = configuration; this.env = env; Log.Info("Avviata classe FilesaveController"); } #endregion Public Constructors #region Protected Properties /// /// Dataservice x accesso DB /// protected ApiDataService dataService { get; set; } #endregion Protected Properties #region Protected Methods /// /// Calcolo correetto mimetype da nome file /// /// /// protected string GetMimeType(string fileName) { var provider = new FileExtensionContentTypeProvider(); string contentType; if (!provider.TryGetContentType(fileName, out contentType)) { contentType = "application/octet-stream"; } return contentType; } #endregion Protected Methods #region Public Methods /// GET api/filesave/id/filename /// /// Recupera un singolo file dato ticket code + nome file (safe) /// /// Ticket code formato T00000000 /// Nome file (safe) /// Nome file da scaricare /// [HttpGet("{id}/{secureName}/{fileName}")] public async Task DownloadFile(string id, string secureName, string fileName) { string relDir = _configuration["FileShare"]; string ticketDir = Path.Combine(relDir, id); var filePath = Path.Combine(ticketDir, secureName); // verifico esistenza.. if (System.IO.File.Exists(filePath)) { var bytes = await System.IO.File.ReadAllBytesAsync(filePath); return File(bytes, GetMimeType(fileName), fileName); } else { return File(new byte[0], "text/plain", "Empty.txt"); } } /// /// Elenco files assaociati a ticket supporto /// /// /// /// // POST api/filesave/list/1 [HttpPost("list/{id}")] public async Task> list(int id, [FromBody] SupportRequest CurrRequest) { List result = new List(); // controllo valori if (CurrRequest.IsValid) { // cerco i files dato ticket result = await dataService.FileGetFilt(id); await dataService.recordCall(CurrRequest.CodInst, CurrRequest.CodApp, $"POST:api/files/list:{id}"); } return result; } /// /// Caricamento file effettivo via POST /// /// TicketId x riferimento /// Elenco files da caricare /// [HttpPost()] public async Task>> PostFiles([FromForm] int ticketId, [FromForm] IEnumerable files) { // max 10 files var maxAllowedFiles = 10; // max 50 mb long maxFileSize = 1024 * 1024 * 50; var filesProcessed = 0; string ticketDir = $"T{ticketId:000000000}"; var resourcePath = new Uri($"{Request.Scheme}://{Request.Host}/api/filesave/list/{ticketId}"); List uploadResults = new(); string fileDir = env.ContentRootPath; string relDir = env.EnvironmentName; foreach (var file in files) { var uploadResult = new UploadResult(); string trustedFileNameForFileStorage; var untrustedFileName = file.FileName; uploadResult.FileName = untrustedFileName; var trustedFileNameForDisplay = WebUtility.HtmlEncode(untrustedFileName); if (filesProcessed < maxAllowedFiles) { if (file.Length == 0) { Log.Info($"{trustedFileNameForDisplay} length is 0 (Err: 1)"); uploadResult.ErrorCode = 1; } else if (file.Length > maxFileSize) { Log.Info($"{trustedFileNameForDisplay} of {file.Length} bytes is larger than the limit of {maxFileSize} bytes (Err: 2)"); uploadResult.ErrorCode = 2; } else { try { DateTime oggi = DateTime.Today; trustedFileNameForFileStorage = Path.GetRandomFileName(); relDir = _configuration["FileShare"]; fileDir = Path.Combine(relDir, ticketDir); if (!Directory.Exists(fileDir)) { Directory.CreateDirectory(fileDir); } var path = Path.Combine(fileDir, trustedFileNameForFileStorage); await using FileStream fs = new(path, FileMode.Create); await file.CopyToAsync(fs); Log.Info($"{trustedFileNameForDisplay} saved at {path}"); uploadResult.Uploaded = true; uploadResult.StoredFileName = trustedFileNameForFileStorage; } catch (IOException ex) { Log.Error($"{trustedFileNameForDisplay} error on upload (Err: 3): {ex.Message}"); uploadResult.ErrorCode = 3; } } filesProcessed++; } else { Log.Info($"{trustedFileNameForDisplay} not uploaded because the request exceeded the allowed {maxAllowedFiles} of files (Err: 4)"); uploadResult.ErrorCode = 4; } uploadResults.Add(uploadResult); } // salvo su DB var fatto = dataService.FileAdd(ticketId, ticketDir, uploadResults); Log.Info($"Ticket: {ticketId} | dir: {ticketDir} | {uploadResults.Count} files"); return new CreatedResult(resourcePath, uploadResults); } /// /// Caricamento file effettivo via POST /// /// TicketId x riferimento /// Elenco files da caricare /// [HttpPost("single")] public async Task> PostSingleFile([FromForm] int ticketId, [FromForm] IFormFile file) { // max 200 mb long maxFileSize = 1024 * 1024 * 200; string ticketDir = $"T{ticketId:000000000}"; var resourcePath = new Uri($"{Request.Scheme}://{Request.Host}/api/filesave/list/{ticketId}"); List uploadResults = new(); string fileDir = env.ContentRootPath; string relDir = env.EnvironmentName; var uploadResult = new UploadResult(); string trustedFileNameForFileStorage; var untrustedFileName = file.FileName; uploadResult.FileName = untrustedFileName; var trustedFileNameForDisplay = WebUtility.HtmlEncode(untrustedFileName); if (file.Length == 0) { Log.Info($"{trustedFileNameForDisplay} length is 0 (Err: 1)"); uploadResult.ErrorCode = 1; } else if (file.Length > maxFileSize) { Log.Info($"{trustedFileNameForDisplay} of {file.Length} bytes is larger than the limit of {maxFileSize} bytes (Err: 2)"); uploadResult.ErrorCode = 2; } else { try { DateTime oggi = DateTime.Today; trustedFileNameForFileStorage = Path.GetRandomFileName(); relDir = _configuration["FileShare"]; fileDir = Path.Combine(relDir, ticketDir); if (!Directory.Exists(fileDir)) { Directory.CreateDirectory(fileDir); } var path = Path.Combine(fileDir, trustedFileNameForFileStorage); await using FileStream fs = new(path, FileMode.Create); await file.CopyToAsync(fs); Log.Info($"{trustedFileNameForDisplay} saved at {path}"); uploadResult.Uploaded = true; uploadResult.StoredFileName = trustedFileNameForFileStorage; } catch (IOException ex) { Log.Error($"{trustedFileNameForDisplay} error on upload (Err: 3): {ex.Message}"); uploadResult.ErrorCode = 3; } } uploadResults.Add(uploadResult); // salvo su DB var fatto = dataService.FileAdd(ticketId, ticketDir, uploadResults); Log.Info($"Ticket: {ticketId} | dir: {ticketDir} | {uploadResults.Count} files"); return new CreatedResult(resourcePath, uploadResult); } #endregion Public Methods } }