using Newtonsoft.Json.Linq; using OI.Metrology.Shared.DataModels; using OI.Metrology.Shared.Models; using OI.Metrology.Shared.Models.Stateless; using OI.Metrology.Shared.Services; using System.Net; using System.Text.Json; namespace OI.Metrology.Server.Repository; public class InboundRepository : IInboundRepository { bool IInboundRepository.IsIPAddressAllowed(string inboundApiAllowedIPList, IPAddress? remoteIP) { if (string.IsNullOrWhiteSpace(inboundApiAllowedIPList)) return true; if (remoteIP is null) return false; byte[] remoteIPBytes = remoteIP.GetAddressBytes(); string[] allowedIPs = inboundApiAllowedIPList.Split(';'); foreach (string ip in allowedIPs) { IPAddress? parsedIP; if (IPAddress.TryParse(ip, out parsedIP)) { if (parsedIP.GetAddressBytes().SequenceEqual(remoteIPBytes)) return true; } } return false; } // this is the main endpoint, it accepts a JSON message that contains both the header and data records together // tooltype is the ToolTypeName column from the ToolType table // JToken is how you can accept a JSON message without deserialization. // Using "string" doesn't work because ASP.NET Core will expect a json encoded string, not give you the actual string. DataResponse IInboundRepository.Data(IMetrologyRepository metrologyRepository, IInboundDataService inboundDataService, string tooltype, string? json) { DataResponse result = new(); ToolType? toolType = metrologyRepository.GetToolTypeByName(tooltype); if (toolType is null) result.Errors.Add($"Invalid tool type: {tooltype}"); else { InboundCommon? inboundCommon = string.IsNullOrEmpty(json) ? null : JsonSerializer.Deserialize(json); if (inboundCommon is null || string.IsNullOrEmpty(inboundCommon.ProcessDataStandardFormat)) result.Errors.Add($"Invalid body: {json}"); else { string? sourceDirectory = Path.GetDirectoryName(inboundCommon.ProcessDataStandardFormat); string? parentDirectory = Path.GetDirectoryName(sourceDirectory); if (string.IsNullOrEmpty(sourceDirectory) || string.IsNullOrEmpty(parentDirectory) || !Directory.Exists(parentDirectory)) result.Errors.Add($"Invalid body:path: <{inboundCommon.ProcessDataStandardFormat}>"); else { JToken jToken = string.IsNullOrEmpty(json) ? JToken.Parse("{}") : JToken.Parse(json); if (jToken is null) result.Errors.Add($"Invalid body: {json}"); else { List metaData = metrologyRepository.GetToolTypeMetadataByToolTypeID(toolType.ID).ToList(); if (metaData is null) result.Errors.Add($"Invalid metadata for tool type: {tooltype}"); else { inboundDataService.ValidateJSONFields(jToken, 0, metaData, result.Errors, result.Warnings); if (!result.Errors.Any()) { try { result.HeaderID = inboundDataService.DoSQLInsert(jToken, toolType, metaData); result.Success = result.HeaderID > 0; string? destinationDirectory = Path.Combine(parentDirectory, result.HeaderID.ToString()); Directory.Move(sourceDirectory, destinationDirectory); } catch (Exception ex) { result.Errors.Add(ex.Message); } } } } } } } return result; } // this is the endpoint for attaching a field. It is not JSON, it is form-data/multipart like an HTML form because that's the normal way. // header ID is the ID value from the Header table // datauniqueid is the Title value from the Data/Detail table string? IInboundRepository.AttachFile(IMetrologyRepository metrologyRepository, IAttachmentsService attachmentsService, string tooltype, long headerid, string datauniqueid, string fileName, object uploadedFile) { string? result = null; ToolType toolType = metrologyRepository.GetToolTypeByName(tooltype); if (toolType is null) result = $"Invalid tool type: {tooltype}"; string filename = Path.GetFileName(fileName); if (string.IsNullOrWhiteSpace(filename)) result = "Empty filename"; if (filename.IndexOfAny(Path.GetInvalidFileNameChars()) >= 0) result = "Invalid filename"; if (result is null && toolType is not null) attachmentsService.SaveAttachment(toolType, headerid, datauniqueid, filename, uploadedFile); return result; } }