From a993d4d18b8affa8d2f721fda98c793b7f32b6af Mon Sep 17 00:00:00 2001 From: John Cardinal Date: Fri, 7 Aug 2020 21:19:54 +0000 Subject: [PATCH] --- .../GlobalBizSettingsController.cs | 7 +- server/AyaNova/Controllers/LogoController.cs | 207 ++++++------------ server/AyaNova/models/Logo.cs | 3 + server/AyaNova/util/AySchema.cs | 4 +- 4 files changed, 72 insertions(+), 149 deletions(-) diff --git a/server/AyaNova/Controllers/GlobalBizSettingsController.cs b/server/AyaNova/Controllers/GlobalBizSettingsController.cs index ab880ef4..ac1b2a79 100644 --- a/server/AyaNova/Controllers/GlobalBizSettingsController.cs +++ b/server/AyaNova/Controllers/GlobalBizSettingsController.cs @@ -46,10 +46,7 @@ namespace AyaNova.Api.Controllers public async Task GetGlobalBizSettings() { if (serverState.IsClosed) - { - return StatusCode(503, new ApiErrorResponse(serverState.ApiErrorCode, null, serverState.Reason)); - } //Instantiate the business object handler GlobalBizSettingsBiz biz = GlobalBizSettingsBiz.GetBiz(ct, HttpContext); @@ -115,7 +112,7 @@ namespace AyaNova.Api.Controllers LicenseStatus = AyaNova.Core.License.ActiveKey.Status, MaintenanceExpired = AyaNova.Core.License.ActiveKey.MaintenanceExpired, ServerDbId = AyaNova.Core.License.ServerDbId, - Company=AyaNova.Core.License.ActiveKey.RegisteredTo + Company = AyaNova.Core.License.ActiveKey.RegisteredTo // , // TestTSDaysWMS=new TimeSpan(22,10,15,22,33), // TestTSHMS=new TimeSpan(5,16,33), @@ -125,7 +122,7 @@ namespace AyaNova.Api.Controllers // TestTS_D=new TimeSpan(22,0,0,0,0) - + }; return Ok(ApiOkResponse.Response(ret)); diff --git a/server/AyaNova/Controllers/LogoController.cs b/server/AyaNova/Controllers/LogoController.cs index 8576136e..0f3aa5a3 100644 --- a/server/AyaNova/Controllers/LogoController.cs +++ b/server/AyaNova/Controllers/LogoController.cs @@ -36,6 +36,7 @@ namespace AyaNova.Api.Controllers private readonly AyContext ct; private readonly ILogger log; private readonly ApiServerState serverState; + private const int MAXIMUM_LOGO_SIZE = 512000;//We really don't want it too big or it will slow the fuck down for everything /// @@ -66,189 +67,111 @@ namespace AyaNova.Api.Controllers { if (serverState.IsClosed) return StatusCode(503, new ApiErrorResponse(serverState.ApiErrorCode, null, serverState.Reason)); - - if (!ModelState.IsValid) - { return BadRequest(new ApiErrorResponse(ModelState)); - } + if (string.IsNullOrWhiteSpace(size)) + return BadRequest(new ApiErrorResponse(ApiErrorCode.VALIDATION_REQUIRED, "size", "Size is required and must be one of 'small', 'medium' or 'large'")); - + size = size.ToLowerInvariant(); + if (size != "small" && size != "medium" && size != "large") + return BadRequest(new ApiErrorResponse(ApiErrorCode.VALIDATION_INVALID_VALUE, "size", "Size parameter must be one of 'small', 'medium' or 'large'")); - 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) - { + var logo = await ct.Logo.SingleOrDefaultAsync(); + if (logo == 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) + switch (size) { - _excludePropertyNames = excludePropertyNames; + case "small": + return new FileStreamResult(new MemoryStream(logo.Small), Microsoft.Net.Http.Headers.MediaTypeHeaderValue.Parse(logo.SmallType)); + + case "medium": + return new FileStreamResult(new MemoryStream(logo.Medium), Microsoft.Net.Http.Headers.MediaTypeHeaderValue.Parse(logo.MediumType)); + + case "large": + return new FileStreamResult(new MemoryStream(logo.Large), Microsoft.Net.Http.Headers.MediaTypeHeaderValue.Parse(logo.LargeType)); + + } + return NotFound(new ApiErrorResponse(ApiErrorCode.NOT_FOUND)); - 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; - } + // 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; } /// /// Upload Logo - /// Max 15mb total + /// Max 500 KiB total (512000 bytes) + /// Must have full rights to Global object /// /// One of "small", "medium", "large" + /// Logo image file /// 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 + [RequestSizeLimit(MAXIMUM_LOGO_SIZE)]//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, IFormFile uploadFile) { - + //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)); + if (!Authorized.HasReadFullRole(HttpContext.Items, AyaType.Global)) + return StatusCode(403, new ApiNotAuthorizedResponse()); + if (string.IsNullOrWhiteSpace(size)) + return BadRequest(new ApiErrorResponse(ApiErrorCode.VALIDATION_REQUIRED, "size", "Size is required and must be one of 'small', 'medium' or 'large'")); - using (var memoryStream = new MemoryStream()) - { - await uploadFile.CopyToAsync(memoryStream); + size = size.ToLowerInvariant(); + if (size != "small" && size != "medium" && size != "large") + return BadRequest(new ApiErrorResponse(ApiErrorCode.VALIDATION_INVALID_VALUE, "size", "Size parameter must be one of 'small', 'medium' or 'large'")); - // Upload the file if less than 2 MB - if (memoryStream.Length < 2097152) - { - var logo = new Logo() + //get the one and only logo object + var logo = await ct.Logo.FirstOrDefaultAsync(); + if (logo == null) { - Content = memoryStream.ToArray() - }; - - _dbContext.File.Add(file); - - await _dbContext.SaveChangesAsync(); - } - else - { - ModelState.AddModelError("File", "The file is too large."); - } - } - - - - - // AyaTypeId attachToObject = null; - ApiUploadProcessor.ApiUploadedFilesResult uploadFormData = null; - try + logo = new Logo(); + ct.Logo.Add(logo); + await ct.SaveChangesAsync(); + } + using (var memoryStream = new MemoryStream()) { - 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 + await uploadFile.CopyToAsync(memoryStream); + if (memoryStream.Length < 2097152) + return BadRequest(new ApiErrorResponse(ApiErrorCode.VALIDATION_LENGTH_EXCEEDED, null, "Logo files must be smaller than 500KiB maximum")); + switch (size) { - 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()); + case "small": + logo.Small = memoryStream.ToArray(); + logo.SmallType = uploadFile.ContentType; + break; + case "medium": + logo.Medium = memoryStream.ToArray(); + logo.MediumType = uploadFile.ContentType; + break; + case "large": + logo.Large = memoryStream.ToArray(); + logo.LargeType = uploadFile.ContentType; + break; } - - - // 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)); - } - } - } + await ct.SaveChangesAsync(); } - 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); - } - } - } - - - } } \ No newline at end of file diff --git a/server/AyaNova/models/Logo.cs b/server/AyaNova/models/Logo.cs index d2246595..fe1e05a7 100644 --- a/server/AyaNova/models/Logo.cs +++ b/server/AyaNova/models/Logo.cs @@ -12,8 +12,11 @@ namespace AyaNova.Models { public long Id { get; set; } public byte[] Large { get; set; } + public string LargeType {get;set;} public byte[] Medium { get; set; } + public string MediumType {get;set;} public byte[] Small { get; set; } + public string SmallType {get;set;} } diff --git a/server/AyaNova/util/AySchema.cs b/server/AyaNova/util/AySchema.cs index c2b4a583..84e8a3e3 100644 --- a/server/AyaNova/util/AySchema.cs +++ b/server/AyaNova/util/AySchema.cs @@ -705,14 +705,14 @@ $BODY$; await SetSchemaLevelAsync(++currentSchema); } - ////////////////////////////////////////////////// + ////////////////////////////////////////////////// // LOGO table if (currentSchema < 13) { LogUpdateMessage(log); await ExecQueryAsync("CREATE TABLE alogo (id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, " + - "large bytea, medium bytea, small bytea)"); + "large bytea, largetype text, medium bytea, mediumtype text, small bytea, smalltype text)"); await SetSchemaLevelAsync(++currentSchema); }