using System.Collections.Generic; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Routing; using Microsoft.AspNetCore.Authorization; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; using AyaNova.Models; using AyaNova.Api.ControllerHelpers; using AyaNova.Biz; using System; using Newtonsoft.Json; using Newtonsoft.Json.Serialization; using Newtonsoft.Json.Linq; using System.Linq; using AyaNova.Util; namespace AyaNova.Api.Controllers { /// /// Logo controller /// [ApiController] [ApiVersion("8.0")] [Route("api/v{version:apiVersion}/Logo")] [Produces("application/json")] [Authorize] public class LogoController : ControllerBase { private readonly AyContext ct; private readonly ILogger log; private readonly ApiServerState serverState; /// /// ctor /// /// /// /// public LogoController(AyContext dbcontext, ILogger logger, ApiServerState apiServerState) { ct = dbcontext; log = logger; serverState = apiServerState; } /// /// Get Logo /// /// One of "small", "medium", "large" /// A single Logo and it's values [AllowAnonymous] [HttpGet("{size}")] public async Task DownloadLogo([FromRoute] string size) { if (serverState.IsClosed) return StatusCode(503, new ApiErrorResponse(serverState.ApiErrorCode, null, serverState.Reason)); if (!ModelState.IsValid) { return BadRequest(new ApiErrorResponse(ModelState)); } var o = await ct.Logo.Include(z => z.LogoItems).SingleOrDefaultAsync(z => z.Id == id); //turn into correct format and then send as file if (o == null) { return NotFound(new ApiErrorResponse(ApiErrorCode.NOT_FOUND)); } var asText = Newtonsoft.Json.JsonConvert.SerializeObject( o, Newtonsoft.Json.Formatting.None, new JsonSerializerSettings { ContractResolver = new ShouldSerializeContractResolver(new string[] { "Concurrency", "Id", "LogoId" }) }); var bytes = System.Text.Encoding.UTF8.GetBytes(asText); var file = new FileContentResult(bytes, "application/octet-stream"); file.FileDownloadName = Util.FileUtil.StringToSafeFileName(o.Name) + ".json"; return file; } public class ShouldSerializeContractResolver : DefaultContractResolver { private readonly IEnumerable _excludePropertyNames; public ShouldSerializeContractResolver(IEnumerable excludePropertyNames) { _excludePropertyNames = excludePropertyNames; } protected override IList CreateProperties(Type type, MemberSerialization memberSerialization) { IList properties = base.CreateProperties(type, memberSerialization); // only serializer properties that start with the specified character properties = properties.Where(p => !_excludePropertyNames.Any(p2 => p2 == p.PropertyName)).ToList(); return properties; } } /// /// Upload Logo /// Max 15mb total /// /// One of "small", "medium", "large" /// Accepted [Authorize] [HttpPost("{size}")] [DisableFormValueModelBinding] [RequestSizeLimit(15000000)]//currently export file is 200kb * 50 maximum at a time = 15mb https://github.com/aspnet/Announcements/issues/267 public async Task UploadAsync([FromRoute] string size) { //https://docs.microsoft.com/en-us/aspnet/core/mvc/models/file-uploads?view=aspnetcore-3.1#upload-small-files-with-buffered-model-binding-to-a-database if (!serverState.IsOpen) return StatusCode(503, new ApiErrorResponse(serverState.ApiErrorCode, null, serverState.Reason)); // AyaTypeId attachToObject = null; ApiUploadProcessor.ApiUploadedFilesResult uploadFormData = null; try { if (!MultipartRequestHelper.IsMultipartContentType(Request.ContentType)) return BadRequest(new ApiErrorResponse(ApiErrorCode.INVALID_OPERATION, null, $"Expected a multipart request, but got {Request.ContentType}")); //Save uploads to disk under temporary file names until we decide how to handle them uploadFormData = await ApiUploadProcessor.ProcessUploadAsync(HttpContext); bool badRequest = false; string UploadObjectType = string.Empty; string UploadObjectId = string.Empty; string errorMessage = string.Empty; string Notes = string.Empty; List FileData = new List(); if ( !uploadFormData.FormFieldData.ContainsKey("FileData"))//only filedata is required { badRequest = true; errorMessage = "Missing required FormFieldData value: FileData"; } if (!badRequest) { if (uploadFormData.FormFieldData.ContainsKey("ObjectType")) UploadObjectType = uploadFormData.FormFieldData["ObjectType"].ToString(); if (uploadFormData.FormFieldData.ContainsKey("ObjectId")) UploadObjectId = uploadFormData.FormFieldData["ObjectId"].ToString(); if (uploadFormData.FormFieldData.ContainsKey("Notes")) Notes = uploadFormData.FormFieldData["Notes"].ToString(); //fileData in JSON stringify format which contains the actual last modified dates etc //"[{\"name\":\"Client.csv\",\"lastModified\":1582822079618},{\"name\":\"wmi4fu06nrs41.jpg\",\"lastModified\":1586900220990}]" FileData = Newtonsoft.Json.JsonConvert.DeserializeObject>(uploadFormData.FormFieldData["FileData"].ToString()); } // long UserId = UserIdFromContext.Id(HttpContext.Items); //Instantiate the business object handler LogoBiz biz = LogoBiz.GetBiz(ct, HttpContext); //We have our files now can parse and insert into db if (uploadFormData.UploadedFiles.Count > 0) { //deserialize each file and import foreach (UploadedFileInfo a in uploadFormData.UploadedFiles) { JObject o = JObject.Parse(System.IO.File.ReadAllText(a.InitialUploadedPathName)); if (!await biz.ImportAsync(o)) { //delete all the files temporarily uploaded and return bad request DeleteTempUploadFile(uploadFormData); return BadRequest(new ApiErrorResponse(biz.Errors)); } } } } catch (System.IO.InvalidDataException ex) { return BadRequest(new ApiErrorResponse(ApiErrorCode.INVALID_OPERATION, null, ex.Message)); } finally { //delete all the files temporarily uploaded and return bad request DeleteTempUploadFile(uploadFormData); } //Return the list of attachment ids and filenames return Accepted(); } private static void DeleteTempUploadFile(ApiUploadProcessor.ApiUploadedFilesResult uploadFormData) { if (uploadFormData.UploadedFiles.Count > 0) { foreach (UploadedFileInfo a in uploadFormData.UploadedFiles) { System.IO.File.Delete(a.InitialUploadedPathName); } } } } }