TargetFramework update,

reference updates and added tests for Viewer
This commit is contained in:
2023-01-06 21:17:30 -07:00
parent 791724fdd4
commit f0c2140f93
82 changed files with 10187 additions and 1052 deletions

View File

@ -0,0 +1,29 @@
using Microsoft.AspNetCore.Mvc;
using OI.Metrology.Shared.Models.Stateless;
namespace OI.Metrology.Viewer.ApiControllers;
[ApiController]
[Route("api/[controller]")]
public class AppSettingsController : ControllerBase, IAppSettingsController<ActionResult>
{
private readonly IAppSettingsRepository _AppSettingsRepository;
public AppSettingsController(IAppSettingsRepository AppSettingsRepository) => _AppSettingsRepository = AppSettingsRepository;
[HttpGet(nameof(IAppSettingsController<ActionResult>.Action.App))]
public ActionResult GetAppSettings()
{
List<string> results = _AppSettingsRepository.GetAppSettings();
return Ok(results);
}
[HttpGet(nameof(IAppSettingsController<ActionResult>.Action.DevOps))]
public ActionResult GetBuildNumberAndGitCommitSeven()
{
string result = _AppSettingsRepository.GetBuildNumberAndGitCommitSeven();
return Ok(result);
}
}

View File

@ -1,50 +1,39 @@
using Microsoft.AspNetCore.Mvc;
using OI.Metrology.Shared.DataModels;
using OI.Metrology.Shared.Repositories;
using OI.Metrology.Shared.Models.Stateless;
using OI.Metrology.Shared.Services;
using System;
using System.IO;
namespace OI.Metrology.Viewer.ApiControllers;
public class AttachmentsController : Controller
{
private readonly IMetrologyRepo _Repo;
private readonly IAttachmentsService _AttachmentsService;
public AttachmentsController(IMetrologyRepo repo, IAttachmentsService attachmentsService)
private readonly IAttachmentsService _AttachmentsService;
private readonly IMetrologyRepository _MetrologyRepository;
public AttachmentsController(IMetrologyRepository metrologyRepository, IAttachmentsService attachmentsService)
{
_Repo = repo;
_AttachmentsService = attachmentsService;
_MetrologyRepository = metrologyRepository;
}
// this endpoint was created in hope that it would make retrieving attachments to display in OpenInsight easier
// url would be like /api/attachments/mercuryprobe/header/HgProbe_66-232268-4329_20180620052640032/data.pdf
[HttpGet("/api/attachments/{toolTypeName}/{tabletype}/{title}/{filename}")]
public IActionResult GetAttachment(
string toolTypeName,
string tabletype,
string title,
string filename)
public IActionResult GetAttachment(string toolTypeName, string tabletype, string title, string filename)
{
ToolType tt = _Repo.GetToolTypeByName(toolTypeName);
ToolType tt = _MetrologyRepository.GetToolTypeByName(toolTypeName);
bool header = !string.Equals(tabletype.Trim(), "data", StringComparison.OrdinalIgnoreCase);
try
{
string contenttype = "application/pdf";
if (filename.ToLower().TrimEnd().EndsWith(".txt"))
contenttype = "text/plain";
Stream fs = _AttachmentsService.GetAttachmentStreamByTitle(tt, header, title, filename);
return File(fs, contenttype);
}
catch (Exception ex)
{
return Content(ex.Message);
}
catch (Exception ex) { return Content(ex.Message); }
}
}

View File

@ -1,37 +1,31 @@
using Microsoft.AspNetCore.Mvc;
namespace OI.Metrology.Viewer.ApiContollers;
namespace OI.Metrology.Viewer.ApiControllers;
using OI.Metrology.Shared.Repositories;
using OI.Metrology.Shared.Models.Stateless;
using System.Text.Json;
// this controller is for the Awaiting Dispo functionality
[Route("api/[controller]")]
public class AwaitingDispoController : Controller
{
private readonly IMetrologyRepo _Repo;
public AwaitingDispoController(IMetrologyRepo repo) => _Repo = repo;
private readonly IMetrologyRepository _MetrologyRepository;
public AwaitingDispoController(IMetrologyRepository metrologyRepository) =>
_MetrologyRepository = metrologyRepository;
// returns the data to show in the Awaiting Dispo grid
// marked no-cache, just-in-case since igniteUI automatically adds a query string parameter to prevent caching
[HttpGet("/api/awaitingdispo")]
[HttpGet]
[ResponseCache(NoStore = true)]
public IActionResult Index()
{
var r = new
{
Results = _Repo.GetAwaitingDispo()
};
return Json(r, new JsonSerializerOptions { PropertyNamingPolicy = null, WriteIndented = true });
}
public IActionResult Index() =>
Json(_MetrologyRepository.GetAwaitingDispo(), new JsonSerializerOptions { PropertyNamingPolicy = null, WriteIndented = true });
// this endpoint is used to set the ReviewDate column, causing the header to no longer show in Awaiting Dispo
[HttpPost("/api/awaitingdispo/markasreviewed")]
public IActionResult MarkAsReviewed([FromQuery] long headerid, [FromQuery] int tooltypeid)
{
_ = _Repo.UpdateReviewDate(tooltypeid, headerid, false);
_ = _MetrologyRepository.UpdateReviewDate(tooltypeid, headerid, false);
return Ok();
}
@ -39,7 +33,7 @@ public class AwaitingDispoController : Controller
[HttpPost("/api/awaitingdispo/markasawaiting")]
public IActionResult MarkAsAwaiting([FromQuery] long headerid, [FromQuery] int tooltypeid)
{
if (_Repo.UpdateReviewDate(tooltypeid, headerid, true) <= 1)
if (_MetrologyRepository.UpdateReviewDate(tooltypeid, headerid, true) <= 1)
return Ok();
else
return StatusCode(444);

View File

@ -0,0 +1,29 @@
using Microsoft.AspNetCore.Mvc;
using OI.Metrology.Shared.Models.Stateless;
namespace OI.Metrology.Viewer.ApiControllers;
[ApiController]
[Route("api/[controller]")]
public class ClientSettingsController : ControllerBase, IClientSettingsController<ActionResult>
{
private readonly IClientSettingsRepository _ClientSettingsRepository;
public ClientSettingsController(IClientSettingsRepository clientSettingsRepository) => _ClientSettingsRepository = clientSettingsRepository;
[HttpGet(nameof(IClientSettingsController<ActionResult>.Action.Client))]
public ActionResult GetClientSettings()
{
List<string> results = _ClientSettingsRepository.GetClientSettings(Request.HttpContext.Connection?.RemoteIpAddress);
return Ok(results);
}
[HttpGet(nameof(IClientSettingsController<ActionResult>.Action.IP))]
public ActionResult GetIpAddress()
{
string result = _ClientSettingsRepository.GetIpAddress(Request.HttpContext.Connection?.RemoteIpAddress);
return Ok(result);
}
}

View File

@ -1,168 +1,78 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json.Linq;
using OI.Metrology.Shared.DataModels;
using OI.Metrology.Shared.Repositories;
using OI.Metrology.Shared.Models;
using OI.Metrology.Shared.Models.Stateless;
using OI.Metrology.Shared.Services;
using OI.Metrology.Viewer.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
namespace OI.Metrology.Viewer.ApiContollers;
namespace OI.Metrology.Viewer.ApiControllers;
[ApiController]
public class InboundController : ControllerBase
[Route("api/[controller]")]
public partial class InboundController : ControllerBase, IInboundController<IActionResult>
{
private readonly ILogger _Logger;
private readonly IMetrologyRepo _Repo;
private readonly AppSettings _AppSettings;
private readonly IAttachmentsService _AttachmentService;
private readonly IInboundRepository _InboundRepository;
private readonly IAttachmentsService _AttachmentsService;
private readonly IInboundDataService _InboundDataService;
private readonly IMetrologyRepository _MetrologyRepository;
public InboundController(AppSettings appSettings, ILogger<InboundController> logger, IMetrologyRepo repo, IInboundDataService inboundDataService, IAttachmentsService attachmentService)
public InboundController(AppSettings appSettings, ILogger<InboundController> logger, IMetrologyRepository metrologyRepository, IInboundRepository inboundRepository, IInboundDataService inboundDataService, IAttachmentsService attachmentsService)
{
_Repo = repo;
_Logger = logger;
_AppSettings = appSettings;
_AttachmentService = attachmentService;
_InboundRepository = inboundRepository;
_AttachmentsService = attachmentsService;
_InboundDataService = inboundDataService;
_MetrologyRepository = metrologyRepository;
}
// this class represents the API response back to the client
public class DataResponse
{
public bool Success { get; set; }
public long HeaderID { get; set; }
public List<string> Errors { get; set; }
public List<string> Warnings { get; set; }
}
// 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.
[HttpPost("/api/inbound/{tooltype}")]
[HttpPost]
[Route("{tooltype}")]
public IActionResult Data(string tooltype, [FromBody] JToken jsonbody)
{
DataResponse r = new()
IPAddress? remoteIP = HttpContext.Connection.RemoteIpAddress;
if (!_InboundRepository.IsIPAddressAllowed(_AppSettings.InboundApiAllowedIPList, remoteIP))
{
Success = false,
HeaderID = -1,
Errors = new List<string>(),
Warnings = new List<string>()
};
if (!IsIPAddressAllowed())
{
_Logger.LogInformation($"Rejected remote IP: {HttpContext.Connection.RemoteIpAddress}");
r.Errors.Add("Remote IP is not on allowed list");
return Unauthorized(r);
}
ToolType toolType = _Repo.GetToolTypeByName(tooltype);
if (toolType == null)
{
r.Errors.Add("Invalid tool type: " + tooltype);
return BadRequest(r);
}
// get metadata
List<ToolTypeMetadata> metaData = _Repo.GetToolTypeMetadataByToolTypeID(toolType.ID).ToList();
if (metaData == null)
{
r.Errors.Add("Invalid metadata for tool type: " + tooltype);
return BadRequest(r);
}
// validate fields
if (jsonbody != null)
_InboundDataService.ValidateJSONFields(jsonbody, 0, metaData, r.Errors, r.Warnings);
else
r.Errors.Add("Invalid json");
if (r.Errors.Count == 0)
{
try
{
r.HeaderID = _InboundDataService.DoSQLInsert(jsonbody, toolType, metaData);
r.Success = r.HeaderID > 0;
}
catch (Exception ex)
{
r.Errors.Add(ex.Message);
}
return Ok(r);
}
else
{
return BadRequest(r);
}
}
// 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
[HttpPost("/api/inbound/{tooltype}/attachment")]
public IActionResult AttachFile(string tooltype, [FromQuery] long headerid, [FromQuery] string datauniqueid = "")
{
if (!IsIPAddressAllowed())
{
_Logger.LogInformation($"Rejected remote IP: {HttpContext.Connection.RemoteIpAddress}");
_Logger.LogInformation($"Rejected remote IP: {remoteIP}");
return Unauthorized("Remote IP is not on allowed list");
}
ToolType toolType = _Repo.GetToolTypeByName(tooltype);
if (toolType == null)
return BadRequest($"Invalid tool type: {tooltype}");
if (Request.Form == null)
return BadRequest($"Invalid form");
if (Request.Form.Files.Count != 1)
return BadRequest($"Invalid file count");
string filename = System.IO.Path.GetFileName(Request.Form.Files[0].FileName);
if (string.IsNullOrWhiteSpace(filename))
return BadRequest("Empty filename");
if (filename.IndexOfAny(System.IO.Path.GetInvalidFileNameChars()) >= 0)
return BadRequest("Invalid filename");
_AttachmentService.SaveAttachment(toolType, headerid, datauniqueid, filename, Request.Form.Files[0]);
return Ok();
else
{
DataResponse dataResponse = _InboundRepository.Data(_MetrologyRepository, _InboundDataService, tooltype, jsonbody);
if (!dataResponse.Errors.Any())
return Ok(dataResponse);
else
return BadRequest(dataResponse);
}
}
protected bool IsIPAddressAllowed()
[HttpPost]
[Route("{tooltype}/attachment")]
public IActionResult AttachFile(string tooltype, [FromQuery] long headerid, [FromQuery] string datauniqueid = "")
{
if (string.IsNullOrWhiteSpace(_AppSettings.InboundApiAllowedIPList))
return true;
System.Net.IPAddress remoteIP = HttpContext.Connection.RemoteIpAddress;
byte[] remoteIPBytes = remoteIP.GetAddressBytes();
string[] allowedIPs = _AppSettings.InboundApiAllowedIPList.Split(';');
foreach (string ip in allowedIPs)
IPAddress? remoteIP = HttpContext.Connection.RemoteIpAddress;
if (!_InboundRepository.IsIPAddressAllowed(_AppSettings.InboundApiAllowedIPList, remoteIP))
{
System.Net.IPAddress parsedIP;
if (System.Net.IPAddress.TryParse(ip, out parsedIP))
{
if (parsedIP.GetAddressBytes().SequenceEqual(remoteIPBytes))
return true;
}
_Logger.LogInformation($"Rejected remote IP: {remoteIP}");
return Unauthorized("Remote IP is not on allowed list");
}
else
{
if (Request.Form is null)
return BadRequest($"Invalid form");
if (Request.Form.Files.Count != 1)
return BadRequest($"Invalid file count");
IFormFile formFile = Request.Form.Files[0];
string? message = _InboundRepository.AttachFile(_MetrologyRepository, _AttachmentsService, tooltype, headerid, datauniqueid, formFile.FileName, formFile);
if (message is null)
return Ok();
else
return BadRequest(message);
}
return false;
}
}

View File

@ -0,0 +1,46 @@
using Microsoft.AspNetCore.Mvc;
using OI.Metrology.Shared.Models.Stateless;
namespace OI.Metrology.Viewer.ApiControllers;
[ApiController]
[Route("api/[controller]")]
public class ServiceShopOrderController : ControllerBase, IServiceShopOrderController<ActionResult>
{
private readonly IServiceShopOrderRepository _ServiceShopOrderRepository;
public ServiceShopOrderController(IServiceShopOrderRepository ServiceShopOrderRepository) => _ServiceShopOrderRepository = ServiceShopOrderRepository;
[HttpGet(nameof(IServiceShopOrderController<ActionResult>.Action.All))]
public async Task<ActionResult> GetAllServiceShopOrders()
{
try
{
Shared.ViewModels.ServiceShopOrder[] results = await _ServiceShopOrderRepository.GetAllServiceShopOrders();
return Ok(results);
}
catch (Exception)
{
return StatusCode(StatusCodes.Status500InternalServerError,
"Error retrieving data from the database");
}
}
[HttpGet]
[Route("{id}")]
public async Task<ActionResult> GetServiceShopOrders(string id)
{
try
{
Shared.ViewModels.ServiceShopOrder[] results = await _ServiceShopOrderRepository.GetServiceShopOrders(id);
return Ok(results);
}
catch (Exception)
{
return StatusCode(StatusCodes.Status500InternalServerError,
"Error retrieving data from the database");
}
}
}

View File

@ -1,249 +1,84 @@
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;
using System;
using System.IO;
using System.Linq;
namespace OI.Metrology.Viewer.ApiContollers;
namespace OI.Metrology.Viewer.ApiControllers;
using OI.Metrology.Shared.DataModels;
using OI.Metrology.Shared.Repositories;
using OI.Metrology.Shared.Models.Stateless;
using OI.Metrology.Shared.Services;
using OI.Metrology.Viewer.Models;
using System.Collections.Generic;
using System.Text.Json;
// using System.Data.Common;
public class ToolTypesController : Controller
[Route("api/[controller]")]
public class ToolTypesController : Controller, IToolTypesController<IActionResult>
{
// this controller powers the bulk of the UI
// it is named after the /api/tooltypes prefix
// the URL pattern is RESTful and the tool type is the root of every request
private readonly IMetrologyRepo _Repo;
private readonly AppSettings _AppSettings;
private readonly IMetrologyRepository _MetrologyRepo;
private readonly IAttachmentsService _AttachmentsService;
private readonly IToolTypesRepository _ToolTypesRepository;
public ToolTypesController(AppSettings appSettings, IMetrologyRepo repo, IAttachmentsService attachmentsService)
public ToolTypesController(AppSettings appSettings, IMetrologyRepository metrologyRepository, IAttachmentsService attachmentsService, IToolTypesRepository toolTypesRepository)
{
_Repo = repo;
_AppSettings = appSettings;
_MetrologyRepo = metrologyRepository;
_AttachmentsService = attachmentsService;
_ToolTypesRepository = toolTypesRepository;
}
// Get a list of tooltypes, returns just Name and ID
[HttpGet("/api/tooltypes")]
public IActionResult Index()
[HttpGet]
public IActionResult Index() =>
Json(_ToolTypesRepository.Index(_MetrologyRepo), new JsonSerializerOptions { PropertyNamingPolicy = null, WriteIndented = true });
[HttpGet]
[Route("{id}")]
public IActionResult GetToolTypeMetadata(int id, string sortby = "") =>
Json(_ToolTypesRepository.GetToolTypeMetadata(_MetrologyRepo, id, sortby), new JsonSerializerOptions { PropertyNamingPolicy = null, WriteIndented = true });
[HttpGet]
[Route("{id}/headers")]
public IActionResult GetHeaders(int id, [FromQuery] DateTime? datebegin, [FromQuery] DateTime? dateend, [FromQuery] int? page, [FromQuery] int? pagesize, [FromQuery] long? headerid) =>
Content(_ToolTypesRepository.GetHeaders(_MetrologyRepo, id, datebegin, dateend, page, pagesize, headerid));
[HttpGet]
[Route("{id}/headertitles")]
public IActionResult GetHeaderTitles(int id, [FromQuery] int? page, [FromQuery] int? pagesize) =>
Content(_ToolTypesRepository.GetHeaderTitles(_MetrologyRepo, id, page, pagesize));
[HttpGet]
[Route("{id}/headers/{headerid}/fields")]
public IActionResult GetHeaderFields(int id, long headerid) =>
Content(_ToolTypesRepository.GetHeaderFields(_MetrologyRepo, id, headerid));
[HttpGet]
[Route("{id}/headers/{headerid}/data")]
public IActionResult GetData(int id, long headerid) =>
Content(_ToolTypesRepository.GetData(_MetrologyRepo, id, headerid));
[HttpGet]
[Route("{toolTypeId}/{tabletype}/files/{attachmentId}/{filename}")]
public IActionResult GetAttachment(int toolTypeId, string tabletype, string attachmentId, string filename)
{
var r = new
{
Results = _Repo.GetToolTypes().Select(tt => new { tt.ToolTypeName, tt.ID })
};
return Json(r, new JsonSerializerOptions { PropertyNamingPolicy = null, WriteIndented = true });
(string? message, string? contenttype, Stream? stream) = _ToolTypesRepository.GetAttachment(_MetrologyRepo, _AttachmentsService, toolTypeId, tabletype, attachmentId, filename);
if (message is not null)
return Content(message);
else if (contenttype is not null && stream is not null)
return File(stream, contenttype);
else
throw new Exception();
}
// Gets the metadata for a tooltype, accepts a parameter which sorts the results
// This is used to setup the grid displays on the UI
[HttpGet("/api/tooltypes/{id}")]
public IActionResult GetToolTypeMetadata(int id, string sortby = "")
{
ToolType tt = _Repo.GetToolTypeByID(id);
IEnumerable<ToolTypeMetadata> md = _Repo.GetToolTypeMetadataByToolTypeID(id);
if (string.Equals(sortby, "grid", StringComparison.OrdinalIgnoreCase))
md = md.OrderBy(f => f.GridDisplayOrder).ToList();
if (string.Equals(sortby, "table", StringComparison.OrdinalIgnoreCase))
md = md.OrderBy(f => f.GridDisplayOrder).ToList();
var r = new
{
Results = new
{
ToolType = tt,
Metadata = md
}
};
return Json(r, new JsonSerializerOptions { PropertyNamingPolicy = null, WriteIndented = true });
}
// Gets headers, request/response format is to allow paging with igniteUI
// The headerid parameter is used for navigating directly to a header, when the button is clicked in Awaiting Dispo
[HttpGet("/api/tooltypes/{id}/headers")]
public IActionResult GetHeaders(
int id,
[FromQuery] DateTime? datebegin,
[FromQuery] DateTime? dateend,
[FromQuery] int? page,
[FromQuery] int? pagesize,
[FromQuery] long? headerid)
{
long totalRecs;
System.Data.DataTable dt = _Repo.GetHeaders(id, datebegin, dateend, page, pagesize, headerid, out totalRecs);
var r = new
{
Results = dt,
TotalRows = totalRecs,
};
string json = JsonConvert.SerializeObject(r);
return Content(json);
}
// Gets header titles, used in the Run Headers UI
[HttpGet("/api/tooltypes/{id}/headertitles")]
public IActionResult GetHeaderTitles(
int id,
[FromQuery] int? page,
[FromQuery] int? pagesize)
{
long totalRecs;
IEnumerable<HeaderCommon> dt = _Repo.GetHeaderTitles(id, page, pagesize, out totalRecs);
var r = new
{
Results = dt,
TotalRows = totalRecs,
};
string json = JsonConvert.SerializeObject(r);
return Content(json);
}
// Get all of the fields for a header, used with the Run Header UI
[HttpGet("/api/tooltypes/{id}/headers/{headerid}/fields")]
public IActionResult GetHeaderFields(
int id,
long headerid)
{
var r = new
{
Results = _Repo.GetHeaderFields(id, headerid).Select(x => new { Column = x.Key, x.Value }).ToList()
};
string json = JsonConvert.SerializeObject(r);
return Content(json);
}
// Get the data for a header, used with the Run Info UI
[HttpGet("/api/tooltypes/{id}/headers/{headerid}/data")]
public IActionResult GetData(
int id,
long headerid)
{
var r = new
{
Results = _Repo.GetData(id, headerid)
};
string json = JsonConvert.SerializeObject(r);
return Content(json);
}
// Display an attachment, used for Run Info - note it is by tool type ID and attachment GUID, so it is best for internal use
[HttpGet("/api/tooltypes/{toolTypeId}/{tabletype}/files/{attachmentId}/{filename}")]
public IActionResult GetAttachment(
int toolTypeId,
string tabletype,
string attachmentId,
string filename)
{
ToolType tt = _Repo.GetToolTypeByID(toolTypeId);
bool header = !string.Equals(tabletype.Trim(), "data", StringComparison.OrdinalIgnoreCase);
Guid attachmentIdParsed;
if (!Guid.TryParse(attachmentId, out attachmentIdParsed))
return Content("Invalid attachment id");
try
{
// figure out what content type to use. this is very simple because there are only two types being used
string contenttype = "application/pdf";
if (filename.ToLower().TrimEnd().EndsWith(".txt"))
contenttype = "text/plain";
// Get attachment stream and feed it to the client
Stream fs = _AttachmentsService.GetAttachmentStreamByAttachmentId(tt, header, attachmentIdParsed, filename);
return File(fs, contenttype);
}
catch (Exception ex)
{
return Content(ex.Message);
}
}
// This endpoint triggers writing of the OI Export file
[HttpPost("/api/tooltypes/{toolTypeId}/headers/{headerid}/oiexport")]
[HttpPost]
[Route("{toolTypeId}/headers/{headerid}/oiexport")]
public IActionResult OIExport(int toolTypeId, long headerid)
{
// Call the export stored procedure
System.Data.DataSet ds = _Repo.GetOIExportData(toolTypeId, headerid);
try
{
// The SP must return 3 result tables
if (ds.Tables.Count != 3)
throw new Exception("Error exporting, invalid results");
// The first table has just one row, which is the export filename
if (ds.Tables[0].Rows.Count != 1)
throw new Exception("Error exporting, invalid filename");
string filename = Convert.ToString(ds.Tables[0].Rows[0][0]);
// The second table has the header data
if (ds.Tables[1].Rows.Count != 1)
throw new Exception("Error exporting, invalid header data");
System.Text.StringBuilder sb = new();
foreach (object o in ds.Tables[1].Rows[0].ItemArray)
{
if ((o != null) && (!Convert.IsDBNull(o)))
_ = sb.Append(Convert.ToString(o));
_ = sb.Append('\t');
}
// The third table has the detail data
foreach (System.Data.DataRow dr in ds.Tables[2].Rows)
{
foreach (object o in dr.ItemArray)
{
if ((o != null) && (!Convert.IsDBNull(o)))
_ = sb.Append(Convert.ToString(o));
_ = sb.Append('\t');
}
}
_ = sb.AppendLine();
// The output file will only have one line, the header columns are output first
// Then each detail rows has it's columns appended
// H1, H2, H3, D1.1, D1.2, D1.3, D2.1, D2.2, D2.3, etc
// Write the file
System.IO.File.WriteAllText(
Path.Join(_AppSettings.OIExportPath, filename),
sb.ToString());
}
catch (Exception ex)
{
string json = JsonConvert.SerializeObject(new
{
ex.Message,
});
return BadRequest(json);
}
var r = new
{
Message = "OK",
};
return Ok(r);
Exception? exception = _ToolTypesRepository.OIExport(_MetrologyRepo, _AppSettings.OIExportPath, toolTypeId, headerid);
if (exception is null)
return Ok(new { Message = "OK" });
else
return BadRequest(JsonConvert.SerializeObject(new { exception.Message }));
}
}

View File

@ -1,11 +1,5 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using OI.Metrology.Viewer.Models;
using System;
using System.IO;
using System.Linq;
using OI.Metrology.Viewer.Models;
using System.Text;
using System.Threading.Tasks;
namespace OI.Metrology.Viewer;
@ -43,7 +37,8 @@ public class ApiLoggingMiddleware
else
{
// if there are content type filters configured, only log is the request begins with one of them
doLogging = _AppSettings.ApiLoggingContentTypes.Split(';').Any(ct => httpContext.Request.ContentType.StartsWith(ct));
string? contentType = httpContext.Request.ContentType;
doLogging = contentType is not null && _AppSettings.ApiLoggingContentTypes.Split(';').Any(ct => contentType.StartsWith(ct));
}
}
}

View File

@ -1,7 +1,5 @@
using Microsoft.AspNetCore.Diagnostics;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
namespace OI.Metrology.Viewer.Controllers;
@ -14,8 +12,8 @@ public class ErrorHandlerController : Controller
public IActionResult Index()
{
IExceptionHandlerFeature error = HttpContext.Features.Get<IExceptionHandlerFeature>();
if (error == null)
IExceptionHandlerFeature? error = HttpContext.Features.Get<IExceptionHandlerFeature>();
if (error is null)
{
return Redirect("~/");
}
@ -24,7 +22,7 @@ public class ErrorHandlerController : Controller
_Logger.LogError("Unhandled exception: " + error.Error.ToString());
dynamic r = new
{
Message = error.Error == null ? "Error" : error.Error.Message
Message = error.Error is null ? "Error" : error.Error.Message
};
return StatusCode(StatusCodes.Status500InternalServerError, r);
}

View File

@ -1,14 +1,10 @@
using Infineon.Monitoring.MonA;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Logging;
using OI.Metrology.Shared.DataModels;
using OI.Metrology.Shared.Repositories;
using OI.Metrology.Shared.Models.Stateless;
using OI.Metrology.Shared.ViewModels;
using OI.Metrology.Viewer.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace OI.Metrology.Viewer.Controllers;
@ -17,14 +13,14 @@ public class ExportController : Controller
{
private readonly ILogger _Logger;
private readonly bool _IsTestDatabase;
private readonly IMetrologyRepo _Repo;
private readonly AppSettings _AppSettings;
private readonly IMetrologyRepository _MetrologyRepository;
public ExportController(AppSettings appSettings, ILogger<ExportController> logger, IMetrologyRepo repo)
public ExportController(AppSettings appSettings, ILogger<ExportController> logger, IMetrologyRepository metrologyRepository)
{
_Repo = repo;
_Logger = logger;
_AppSettings = appSettings;
_MetrologyRepository = metrologyRepository;
_IsTestDatabase = appSettings.ConnectionString.Contains("test", StringComparison.InvariantCultureIgnoreCase);
}
@ -52,14 +48,14 @@ public class ExportController : Controller
[Route("/ExportData")]
public ActionResult ExportData(Export model)
{
ToolType toolType = null;
ToolType? toolType = null;
if (string.IsNullOrEmpty(model.ToolType))
ModelState.AddModelError("Exception", "Invalid selection");
else
{
if (model.StartTime > model.EndTime)
ModelState.AddModelError("EndTime", "End time must be after start time");
IEnumerable<ToolType> toolTypes = _Repo.GetToolTypes();
IEnumerable<ToolType> toolTypes = _MetrologyRepository.GetToolTypes();
toolType = toolTypes.Where(tt => tt.ID.ToString() == model.ToolType).SingleOrDefault();
if (toolType is null)
ModelState.AddModelError("ToolType", "Invalid selection");
@ -73,7 +69,7 @@ public class ExportController : Controller
DateTime startDT = model.StartDate.Date.Add(model.StartTime.TimeOfDay);
DateTime endDT = model.EndDate.Date.Add(model.EndTime.TimeOfDay);
return DoCSVExport(toolType.ToolTypeName, toolType.ExportSPName, startDT, endDT);
return DoCSVExport(toolType?.ToolTypeName, toolType?.ExportSPName, startDT, endDT);
}
catch (Exception ex)
{
@ -86,22 +82,17 @@ public class ExportController : Controller
return View("Index", model);
}
protected ActionResult DoCSVExport(string toolTypeName, string spName, DateTime startTime, DateTime endTime)
protected ActionResult DoCSVExport(string? toolTypeName, string? spName, DateTime startTime, DateTime endTime)
{
string fileName = string.Format("Export_{0}_{1:yyyyMMddHHmm}_to_{2:yyyyMMddHHmm}.csv", toolTypeName, startTime, endTime);
StringBuilder sb = new();
System.Data.DataTable dt = _Repo.ExportData(spName, startTime, endTime);
if (spName is null)
throw new NullReferenceException(nameof(spName));
System.Data.DataTable dt = _MetrologyRepository.ExportData(spName, startTime, endTime);
_ = sb.AppendLine(GetColumnHeaders(dt));
foreach (System.Data.DataRow dr in dt.Rows)
{
_ = sb.AppendLine(GetRowData(dr));
}
byte[] contents = Encoding.UTF8.GetBytes(sb.ToString());
return File(contents, "application/octet-stream", fileName);
}
@ -112,10 +103,13 @@ public class ExportController : Controller
{
if (i > 0)
_ = r.Append(',');
object v = dr[i];
if (!Convert.IsDBNull(v))
_ = r.Append(FormatForCSV(Convert.ToString(v)));
{
string? c = Convert.ToString(v);
if (c is not null)
_ = r.Append(FormatForCSV(c));
}
}
return r.ToString();
}
@ -135,16 +129,13 @@ public class ExportController : Controller
protected static string FormatForCSV(string v)
{
StringBuilder r = new(v.Length + 2);
bool doubleQuoted = false;
StringBuilder r = new(v.Length + 2);
if (v.StartsWith(' ') || v.EndsWith(' ') || v.Contains(',') || v.Contains('"'))
{
_ = r.Append('"');
doubleQuoted = true;
}
foreach (char c in v)
{
_ = c switch
@ -154,10 +145,8 @@ public class ExportController : Controller
_ => r.Append(c),
};
}
if (doubleQuoted)
_ = r.Append('"');
return r.ToString();
}

View File

@ -1,20 +1,19 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using OI.Metrology.Shared.Repositories;
using OI.Metrology.Shared.Models.Stateless;
using OI.Metrology.Shared.ViewModels;
using OI.Metrology.Viewer.Models;
using System;
namespace OI.Metrology.Viewer.Controllers;
public class PagesController : Controller
{
private readonly IMetrologyRepo _Repo;
private readonly bool _IsTestDatabase;
private readonly IMetrologyRepository _MetrologyRepository;
public PagesController(AppSettings appSettings, IMetrologyRepo repo)
public PagesController(AppSettings appSettings, IMetrologyRepository metrologyRepository)
{
_Repo = repo;
_MetrologyRepository = metrologyRepository;
_IsTestDatabase = appSettings.ConnectionString.Contains("test", StringComparison.InvariantCultureIgnoreCase);
}
@ -48,7 +47,7 @@ public class PagesController : Controller
};
if (headerid > 0)
{
m.HeaderAttachmentID = _Repo.GetHeaderAttachmentID(tooltypeid, headerid);
m.HeaderAttachmentID = _MetrologyRepository.GetHeaderAttachmentID(tooltypeid, headerid);
}
return View(m);
}

File diff suppressed because it is too large Load Diff

View File

@ -1,61 +1,26 @@
using System.Text.Json;
using System.Text.Json.Serialization;
namespace OI.Metrology.Viewer.Models;
public class AppSettings
public record AppSettings(string ApiLoggingContentTypes,
string ApiLoggingPathPrefixes,
string ApiLogPath,
string AttachmentPath,
string BuildNumber,
string Company,
string ConnectionString,
string GitCommitSeven,
string InboundApiAllowedIPList,
bool IsDevelopment,
bool IsStaging,
string MonAResource,
string MonASite,
string OI2SqlConnectionString,
string OIExportPath,
string URLs,
string WorkingDirectoryName)
{
public string ApiLoggingContentTypes { init; get; }
public string ApiLoggingPathPrefixes { init; get; }
public string ApiLogPath { init; get; }
public string AttachmentPath { init; get; }
public string BuildNumber { init; get; }
public string Company { init; get; }
public string ConnectionString { init; get; }
public string GitCommitSeven { init; get; }
public string InboundApiAllowedIPList { init; get; }
public string MonAResource { init; get; }
public string MonASite { init; get; }
public string Oi2SqlConnectionString { init; get; }
public string OIExportPath { init; get; }
public string URLs { init; get; }
public string WorkingDirectoryName { init; get; }
[JsonConstructor]
public AppSettings(string apiLoggingContentTypes,
string apiLoggingPathPrefixes,
string apiLogPath,
string attachmentPath,
string buildNumber,
string company,
string connectionString,
string gitCommitSeven,
string inboundApiAllowedIPList,
string monAResource,
string monASite,
string oi2SqlConnectionString,
string oiExportPath,
string urls,
string workingDirectoryName)
{
ApiLoggingContentTypes = apiLoggingContentTypes;
ApiLoggingPathPrefixes = apiLoggingPathPrefixes;
ApiLogPath = apiLogPath;
AttachmentPath = attachmentPath;
BuildNumber = buildNumber;
Company = company;
ConnectionString = connectionString;
GitCommitSeven = gitCommitSeven;
InboundApiAllowedIPList = inboundApiAllowedIPList;
MonAResource = monAResource;
MonASite = monASite;
Oi2SqlConnectionString = oi2SqlConnectionString;
OIExportPath = oiExportPath;
URLs = urls;
WorkingDirectoryName = workingDirectoryName;
}
public override string ToString()
{
string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true });

View File

@ -1,4 +1,3 @@
using Microsoft.Extensions.Configuration;
using System.ComponentModel.DataAnnotations;
using System.Text.Json;
@ -18,6 +17,8 @@ public class AppSettings
[Display(Name = "Connection String"), Required] public string ConnectionString { get; set; }
[Display(Name = "Git Commit Seven"), Required] public string GitCommitSeven { get; set; }
[Display(Name = "Inbound Api Allowed IP List"), Required] public string InboundApiAllowedIPList { get; set; }
[Display(Name = "Is Development"), Required] public bool? IsDevelopment { get; set; }
[Display(Name = "Is Staging"), Required] public bool? IsStaging { get; set; }
[Display(Name = "MonA Resource"), Required] public string MonAResource { get; set; }
[Display(Name = "MonA Site"), Required] public string MonASite { get; set; }
[Display(Name = "Oi 2 Sql Connection String"), Required] public string Oi2SqlConnectionString { get; set; }
@ -33,9 +34,45 @@ public class AppSettings
return result;
}
private static Models.AppSettings Get(AppSettings appSettings)
private static Models.AppSettings Get(AppSettings? appSettings)
{
Models.AppSettings result;
if (appSettings is null)
throw new NullReferenceException(nameof(appSettings));
if (appSettings.ApiLoggingContentTypes is null)
throw new NullReferenceException(nameof(ApiLoggingContentTypes));
if (appSettings.ApiLoggingPathPrefixes is null)
throw new NullReferenceException(nameof(ApiLoggingPathPrefixes));
if (appSettings.ApiLogPath is null)
throw new NullReferenceException(nameof(ApiLogPath));
if (appSettings.AttachmentPath is null)
throw new NullReferenceException(nameof(AttachmentPath));
if (appSettings.BuildNumber is null)
throw new NullReferenceException(nameof(BuildNumber));
if (appSettings.Company is null)
throw new NullReferenceException(nameof(Company));
if (appSettings.ConnectionString is null)
throw new NullReferenceException(nameof(ConnectionString));
if (appSettings.GitCommitSeven is null)
throw new NullReferenceException(nameof(GitCommitSeven));
if (appSettings.InboundApiAllowedIPList is null)
throw new NullReferenceException(nameof(InboundApiAllowedIPList));
if (appSettings.IsDevelopment is null)
throw new NullReferenceException(nameof(IsDevelopment));
if (appSettings.IsStaging is null)
throw new NullReferenceException(nameof(IsStaging));
if (appSettings.MonAResource is null)
throw new NullReferenceException(nameof(MonAResource));
if (appSettings.MonASite is null)
throw new NullReferenceException(nameof(MonASite));
if (appSettings.Oi2SqlConnectionString is null)
throw new NullReferenceException(nameof(Oi2SqlConnectionString));
if (appSettings.OIExportPath is null)
throw new NullReferenceException(nameof(OIExportPath));
if (appSettings.URLs is null)
throw new NullReferenceException(nameof(URLs));
if (appSettings.WorkingDirectoryName is null)
throw new NullReferenceException(nameof(WorkingDirectoryName));
result = new(
appSettings.ApiLoggingContentTypes,
appSettings.ApiLoggingPathPrefixes,
@ -46,6 +83,8 @@ public class AppSettings
appSettings.ConnectionString,
appSettings.GitCommitSeven,
appSettings.InboundApiAllowedIPList,
appSettings.IsDevelopment.Value,
appSettings.IsStaging.Value,
appSettings.MonAResource,
appSettings.MonASite,
appSettings.Oi2SqlConnectionString,
@ -58,7 +97,7 @@ public class AppSettings
public static Models.AppSettings Get(IConfigurationRoot configurationRoot)
{
Models.AppSettings result;
AppSettings appSettings = configurationRoot.Get<AppSettings>();
AppSettings? appSettings = configurationRoot.Get<AppSettings>();
result = Get(appSettings);
return result;
}

View File

@ -6,13 +6,13 @@
<SccLocalPath>SAK</SccLocalPath>
</PropertyGroup>
<PropertyGroup>
<ImplicitUsings>disable</ImplicitUsings>
<ImplicitUsings>enable</ImplicitUsings>
<IsPackable>false</IsPackable>
<LangVersion>10.0</LangVersion>
<Nullable>disable</Nullable>
<Nullable>enable</Nullable>
<OutputType>Exe</OutputType>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net7.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<Compile Remove="logs\**" />
@ -26,22 +26,25 @@
<ItemGroup>
<PackageReference Include="Dapper" Version="2.0.123" />
<PackageReference Include="EntityFramework" Version="6.4.4" />
<PackageReference Include="jQuery" Version="3.6.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="6.0.1" />
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="6.0.1" />
<PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="6.0.1" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="6.0.1" />
<PackageReference Include="Serilog.AspNetCore" Version="6.0.1" />
<PackageReference Include="jQuery" Version="3.6.3" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="7.0.1" />
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="7.0.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.2" />
<PackageReference Include="Serilog.AspNetCore.Ingestion" Version="1.0.0-dev-00032" />
<PackageReference Include="Serilog.AspNetCore" Version="6.1.0" />
<PackageReference Include="Serilog.Settings.Configuration" Version="3.4.0" />
<PackageReference Include="Serilog.Sinks.Console" Version="4.1.0" />
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
<PackageReference Include="System.Data.SqlClient" Version="4.8.4" />
<PackageReference Include="System.Data.SqlClient" Version="4.8.5" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Shared\Shared.csproj" />
<ProjectReference Include="..\Shared\OI.Metrology.Shared.csproj" />
</ItemGroup>
<ItemGroup>
<Folder Include="moves\" />
@ -58,5 +61,8 @@
<None Include="appsettings.Development.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="Data\Mike\service-shop.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>

View File

@ -1,19 +1,14 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Hosting.WindowsServices;
using Microsoft.Extensions.Logging;
using OI.Metrology.Shared.Models;
using OI.Metrology.Shared.Models.Stateless;
using OI.Metrology.Shared.Repositories;
using OI.Metrology.Shared.Services;
using OI.Metrology.Viewer.Models;
using OI.Metrology.Viewer.Repositories;
using OI.Metrology.Viewer.Repository;
using OI.Metrology.Viewer.Services;
using Serilog;
using System;
using System.IO;
using System.Reflection;
namespace OI.Metrology.Viewer;
@ -25,7 +20,7 @@ public class Program
{
string webRootPath;
Assembly assembly = Assembly.GetExecutingAssembly();
string assemblyName = assembly.GetName()?.Name;
string? assemblyName = assembly.GetName()?.Name;
if (string.IsNullOrEmpty(assemblyName))
throw new Exception();
string baseAssemblyName = assemblyName.Split('.')[0];
@ -63,14 +58,27 @@ public class Program
{
_ = webApplicationBuilder.Services.Configure<ApiBehaviorOptions>(options => options.SuppressModelStateInvalidFilter = true);
_ = webApplicationBuilder.Services.AddControllersWithViews();
_ = new MetrologyRepo(new SQLDbConnectionFactory(appSettings), null);
#pragma warning disable CS8600, CS8602, CS8603, CS8604, CS8625
_ = new MetrologyRepository(new SQLDbConnectionFactory(appSettings), null);
#pragma warning restore
_ = webApplicationBuilder.Services.AddDistributedMemoryCache();
_ = webApplicationBuilder.Services.AddMemoryCache();
_ = webApplicationBuilder.Services.AddSingleton<AppSettings, AppSettings>(_ => appSettings);
AppSettingsRepository appSettingsRepository = new(appSettings);
ClientSettingsRepository clientSettingsRepository = new(appSettings);
_ = webApplicationBuilder.Services.AddSingleton(_ => appSettings);
_ = webApplicationBuilder.Services.AddSingleton<IInboundRepository, InboundRepository>();
_ = webApplicationBuilder.Services.AddSingleton<IToolTypesRepository, ToolTypesRepository>();
_ = webApplicationBuilder.Services.AddSingleton<IDbConnectionFactory, SQLDbConnectionFactory>();
_ = webApplicationBuilder.Services.AddSingleton<IAppSettingsRepository>(_ => appSettingsRepository);
_ = webApplicationBuilder.Services.AddSingleton<IClientSettingsRepository>(_ => clientSettingsRepository);
_ = webApplicationBuilder.Services.AddSingleton<IServiceShopOrderRepository, ServiceShopOrderRepository>();
_ = webApplicationBuilder.Services.AddScoped<IAttachmentsService, AttachmentsService>();
_ = webApplicationBuilder.Services.AddScoped<IInboundDataService, InboundDataService>();
_ = webApplicationBuilder.Services.AddScoped<IMetrologyRepo, MetrologyRepo>();
_ = webApplicationBuilder.Services.AddSingleton<IDbConnectionFactory, SQLDbConnectionFactory>();
_ = webApplicationBuilder.Services.AddScoped<IMetrologyRepository, MetrologyRepository>();
_ = webApplicationBuilder.Services.AddSwaggerGen();
_ = webApplicationBuilder.Services.AddSession(sessionOptions =>
{
@ -84,8 +92,10 @@ public class Program
_ = webApplicationBuilder.Services.AddSingleton<IHostLifetime, WindowsServiceLifetime>();
_ = webApplicationBuilder.Logging.AddEventLog(settings =>
{
#pragma warning disable CA1416
if (string.IsNullOrEmpty(settings.SourceName))
settings.SourceName = webApplicationBuilder.Environment.ApplicationName;
#pragma warning restore
});
}
WebApplication webApplication = webApplicationBuilder.Build();

View File

@ -0,0 +1,37 @@
using OI.Metrology.Shared.Models.Stateless;
using OI.Metrology.Viewer.Models;
using System.Text.Json;
namespace OI.Metrology.Viewer.Repository;
public class AppSettingsRepository : IAppSettingsRepository
{
private readonly AppSettings _AppSettings;
public AppSettingsRepository(AppSettings appSettings) => _AppSettings = appSettings;
public List<string> GetAppSettings()
{
List<string> results = new();
string json = JsonSerializer.Serialize(_AppSettings);
JsonElement jsonElement = JsonSerializer.Deserialize<JsonElement>(json);
JsonProperty[] jsonProperties = jsonElement.EnumerateObject().ToArray();
foreach (JsonProperty jsonProperty in jsonProperties)
results.Add(jsonProperty.Value.ToString());
if (!_AppSettings.IsDevelopment)
throw new Exception("Shouldn't expose!");
return results;
}
List<string> IAppSettingsRepository.GetAppSettings() => GetAppSettings();
public string GetBuildNumberAndGitCommitSeven()
{
string result = string.Concat(_AppSettings.BuildNumber, '-', _AppSettings.GitCommitSeven);
return result;
}
string IAppSettingsRepository.GetBuildNumberAndGitCommitSeven() => GetBuildNumberAndGitCommitSeven();
}

View File

@ -0,0 +1,36 @@
using OI.Metrology.Shared.Models.Stateless;
using OI.Metrology.Viewer.Models;
using System.Net;
namespace OI.Metrology.Viewer.Repository;
public class ClientSettingsRepository : IClientSettingsRepository
{
private readonly AppSettings _AppSettings;
public ClientSettingsRepository(AppSettings appSettings) => _AppSettings = appSettings;
public List<string> GetClientSettings(IPAddress? remoteIpAddress)
{
List<string> results = new();
if (remoteIpAddress is null)
results.Add(nameof(remoteIpAddress));
else
results.Add(remoteIpAddress.ToString());
if (!_AppSettings.IsDevelopment)
throw new Exception("Shouldn't expose!");
return results;
}
List<string> IClientSettingsRepository.GetClientSettings(IPAddress? remoteIpAddress) => GetClientSettings(remoteIpAddress);
public string GetIpAddress(IPAddress? remoteIpAddress)
{
string result = remoteIpAddress is null ? string.Empty : remoteIpAddress.ToString();
return result;
}
string IClientSettingsRepository.GetIpAddress(IPAddress? remoteIpAddress) => GetIpAddress(remoteIpAddress);
}

View File

@ -0,0 +1,88 @@
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;
namespace OI.Metrology.Viewer.Repository;
public class InboundRepository : IInboundRepository
{
private readonly Serilog.ILogger _Log;
public InboundRepository() => _Log = Serilog.Log.ForContext<InboundRepository>();
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, JToken jsonbody)
{
DataResponse result = new();
ToolType? toolType = metrologyRepository.GetToolTypeByName(tooltype);
if (toolType is null)
result.Errors.Add("Invalid tool type: " + tooltype);
else
{
List<ToolTypeMetadata> metaData = metrologyRepository.GetToolTypeMetadataByToolTypeID(toolType.ID).ToList();
if (metaData is null)
result.Errors.Add("Invalid metadata for tool type: " + tooltype);
else if (jsonbody is null)
result.Errors.Add("Invalid json");
else
inboundDataService.ValidateJSONFields(jsonbody, 0, metaData, result.Errors, result.Warnings);
if (metaData is not null && jsonbody is not null && !result.Errors.Any())
{
try
{
result.HeaderID = inboundDataService.DoSQLInsert(jsonbody, toolType, metaData);
result.Success = result.HeaderID > 0;
}
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;
}
}

View File

@ -2,22 +2,22 @@
using Microsoft.Extensions.Caching.Memory;
using Newtonsoft.Json.Linq;
using OI.Metrology.Shared.DataModels;
using OI.Metrology.Shared.Models.Stateless;
using OI.Metrology.Shared.Repositories;
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Linq;
using System.Transactions;
#pragma warning disable CS8600, CS8602, CS8603, CS8604, CS8625
namespace OI.Metrology.Viewer.Repositories;
public class MetrologyRepo : IMetrologyRepo
public class MetrologyRepository : IMetrologyRepository
{
private readonly IMemoryCache _Cache;
private readonly IDbConnectionFactory _DBConnectionFactory;
public MetrologyRepo(IDbConnectionFactory dbConnectionFactory, IMemoryCache memoryCache)
public MetrologyRepository(IDbConnectionFactory dbConnectionFactory, IMemoryCache memoryCache)
{
_Cache = memoryCache;
_DBConnectionFactory = dbConnectionFactory;
@ -139,10 +139,10 @@ public class MetrologyRepo : IMetrologyRepo
// build field map
foreach (ToolTypeMetadata f in fields)
{
if ((f.ApiName != null) && f.ApiName.Contains('\\'))
if ((f.ApiName is not null) && f.ApiName.Contains('\\'))
{
string n = f.ApiName.Split('\\')[0].Trim().ToUpper();
if (containerField == null)
if (containerField is null)
containerField = n;
else if (!string.Equals(containerField, n))
throw new Exception("Only one container field is allowed");
@ -156,7 +156,7 @@ public class MetrologyRepo : IMetrologyRepo
}
}
if (containerField == null)
if (containerField is null)
{
// No container field, just insert a single row
@ -167,7 +167,7 @@ public class MetrologyRepo : IMetrologyRepo
// Find the container field in the json
JProperty contJP = jsonrow.Children<JProperty>().Where(c => string.Equals(c.Name.Trim(), containerField, StringComparison.OrdinalIgnoreCase)).SingleOrDefault();
if ((contJP != null) && (contJP.Value is JArray array))
if ((contJP is not null) && (contJP.Value is JArray array))
{
JArray contRows = array;
@ -220,11 +220,11 @@ public class MetrologyRepo : IMetrologyRepo
{
string apifield = jp.Name.Trim().ToUpper();
if (fieldmap.ContainsKey(apifield))
if (fieldmap.TryGetValue(apifield, out string value))
{
string parmname = string.Format("@p{0}", parmnumber);
columns += string.Format("[{0}],", fieldmap[apifield]);
columns += string.Format("[{0}],", value);
parms += parmname;
parms += ",";
parmnumber += 1;
@ -236,18 +236,18 @@ public class MetrologyRepo : IMetrologyRepo
}
}
if ((containerrow != null) && (containerFieldmap != null))
if ((containerrow is not null) && (containerFieldmap is not null))
{
foreach (JProperty jp in containerrow.Children<JProperty>())
{
string apifield = jp.Name.Trim().ToUpper();
if (containerFieldmap.ContainsKey(apifield))
if (containerFieldmap.TryGetValue(apifield, out string value))
{
string parmname = string.Format("@p{0}", parmnumber);
columns += string.Format("[{0}],", containerFieldmap[apifield]);
columns += string.Format("[{0}],", value);
parms += parmname;
parms += ",";
parmnumber += 1;
@ -267,7 +267,7 @@ public class MetrologyRepo : IMetrologyRepo
cmd.CommandText = columns.TrimEnd(',') + parms.TrimEnd(',') + ";SELECT SCOPE_IDENTITY();";
object o = cmd.ExecuteScalar();
if ((o == null) || Convert.IsDBNull(o))
if ((o is null) || Convert.IsDBNull(o))
throw new Exception("Unexpected query result");
return Convert.ToInt64(o);
}
@ -307,7 +307,7 @@ public class MetrologyRepo : IMetrologyRepo
{
if (!firstField)
_ = sb.Append(',');
if (f.GridAttributes != null && f.GridAttributes.Contains("isNull"))
if (f.GridAttributes is not null && f.GridAttributes.Contains("isNull"))
{
_ = sb.AppendFormat("{0}", "ISNULL(" + f.ColumnName + ", '')[" + f.ColumnName + "]");
}
@ -325,11 +325,11 @@ public class MetrologyRepo : IMetrologyRepo
public DataTable GetHeaders(int toolTypeId, DateTime? startTime, DateTime? endTime, int? pageNo, int? pageSize, long? headerId, out long totalRecords)
{
ToolType tt = GetToolTypeByID(toolTypeId);
if (tt == null)
if (tt is null)
throw new Exception("Invalid tool type ID");
IEnumerable<ToolTypeMetadata> md = GetToolTypeMetadataByToolTypeID(toolTypeId);
if (md == null)
if (md is null)
throw new Exception("Invalid tool type metadata");
DataTable dt = new();
@ -418,11 +418,11 @@ public class MetrologyRepo : IMetrologyRepo
public DataTable GetData(int toolTypeId, long headerid)
{
ToolType tt = GetToolTypeByID(toolTypeId);
if (tt == null)
if (tt is null)
throw new Exception("Invalid tool type ID");
IEnumerable<ToolTypeMetadata> md = GetToolTypeMetadataByToolTypeID(toolTypeId);
if (md == null)
if (md is null)
throw new Exception("Invalid tool type metadata");
DataTable dt = new();
@ -513,7 +513,7 @@ public class MetrologyRepo : IMetrologyRepo
public Guid GetHeaderAttachmentID(int toolTypeId, long headerId)
{
ToolType tt = GetToolTypeByID(toolTypeId);
if (tt == null)
if (tt is null)
throw new Exception("Invalid tool type ID");
using DbConnection conn = GetDbConnection();
@ -525,7 +525,7 @@ public class MetrologyRepo : IMetrologyRepo
public string GetHeaderInsertDate(int toolTypeId, long headerId)
{
ToolType tt = GetToolTypeByID(toolTypeId);
if (tt == null)
if (tt is null)
throw new Exception("Invalid tool type ID");
using DbConnection conn = GetDbConnection();
@ -557,7 +557,7 @@ public class MetrologyRepo : IMetrologyRepo
public Guid GetDataAttachmentID(int toolTypeId, long headerId, string title)
{
ToolType tt = GetToolTypeByID(toolTypeId);
if (tt == null)
if (tt is null)
throw new Exception("Invalid tool type ID");
using DbConnection conn = GetDbConnection();
@ -570,7 +570,7 @@ public class MetrologyRepo : IMetrologyRepo
public string GetDataInsertDate(int toolTypeId, long headerId, string title)
{
ToolType tt = GetToolTypeByID(toolTypeId);
if (tt == null)
if (tt is null)
throw new Exception("Invalid tool type ID");
using DbConnection conn = GetDbConnection();
@ -603,7 +603,7 @@ public class MetrologyRepo : IMetrologyRepo
public DataSet GetOIExportData(int toolTypeId, long headerid)
{
ToolType tt = GetToolTypeByID(toolTypeId);
if (tt == null)
if (tt is null)
throw new Exception("Invalid tool type ID");
if (string.IsNullOrWhiteSpace(tt.OIExportSPName))
@ -632,7 +632,7 @@ public class MetrologyRepo : IMetrologyRepo
public IEnumerable<HeaderCommon> GetHeaderTitles(int toolTypeId, int? pageNo, int? pageSize, out long totalRecords)
{
ToolType tt = GetToolTypeByID(toolTypeId);
if (tt == null)
if (tt is null)
throw new Exception("Invalid tool type ID");
using DbConnection conn = GetDbConnection();
@ -661,11 +661,11 @@ public class MetrologyRepo : IMetrologyRepo
public IEnumerable<KeyValuePair<string, string>> GetHeaderFields(int toolTypeId, long headerid)
{
ToolType tt = GetToolTypeByID(toolTypeId);
if (tt == null)
if (tt is null)
throw new Exception("Invalid tool type ID");
IEnumerable<ToolTypeMetadata> md = GetToolTypeMetadataByToolTypeID(toolTypeId);
if (md == null)
if (md is null)
throw new Exception("Invalid tool type metadata");
List<KeyValuePair<string, string>> r = new();
@ -692,10 +692,10 @@ public class MetrologyRepo : IMetrologyRepo
foreach (ToolTypeMetadata m in md.Where(m => m.Header == true && m.TableDisplayOrder > 0).OrderBy(m => m.TableDisplayOrder))
{
string v = "";
if (dr != null)
if (dr is not null)
{
object o = dr[m.ColumnName];
if (o != null && !Convert.IsDBNull(o))
if (o is not null && !Convert.IsDBNull(o))
v = Convert.ToString(o);
}
KeyValuePair<string, string> kvp = new(m.DisplayTitle, v);
@ -714,7 +714,7 @@ public class MetrologyRepo : IMetrologyRepo
public int UpdateReviewDate(int toolTypeId, long headerId, bool clearDate)
{
ToolType tt = GetToolTypeByID(toolTypeId);
if (tt == null)
if (tt is null)
throw new Exception("Invalid tool type ID");
using DbConnection conn = GetDbConnection();
@ -736,7 +736,7 @@ public class MetrologyRepo : IMetrologyRepo
public Guid GetHeaderAttachmentIDByTitle(int toolTypeId, string title)
{
ToolType tt = GetToolTypeByID(toolTypeId);
if (tt == null)
if (tt is null)
throw new Exception("Invalid tool type ID");
using DbConnection conn = GetDbConnection();
@ -748,7 +748,7 @@ public class MetrologyRepo : IMetrologyRepo
public Guid GetDataAttachmentIDByTitle(int toolTypeId, string title)
{
ToolType tt = GetToolTypeByID(toolTypeId);
if (tt == null)
if (tt is null)
throw new Exception("Invalid tool type ID");
using DbConnection conn = GetDbConnection();
@ -757,5 +757,5 @@ public class MetrologyRepo : IMetrologyRepo
return conn.ExecuteScalar<Guid>(sql, param: new { Title = title });
}
DataTable IMetrologyRepo.GetDataSharePoint(int toolTypeId, string headerId) => throw new NotImplementedException();
DataTable IMetrologyRepository.GetDataSharePoint(int toolTypeId, string headerId) => throw new NotImplementedException();
}

View File

@ -0,0 +1,56 @@
using OI.Metrology.Shared.Models.Stateless;
using OI.Metrology.Shared.ViewModels;
using Serilog.Context;
using System.Text.Json;
namespace OI.Metrology.Viewer.Repository;
public class ServiceShopOrderRepository : IServiceShopOrderRepository
{
private readonly Serilog.ILogger _Log;
public ServiceShopOrderRepository() => _Log = Serilog.Log.ForContext<ServiceShopOrderRepository>();
private static ServiceShopOrder[] GetServiceShopOrders(Shared.Models.ServiceShop? serviceShop)
{
ServiceShopOrder[] result = IServiceShopOrder.GetServiceShopOrders(serviceShop);
return result;
}
private static Shared.Models.ServiceShop? GetServiceShopOrders()
{
Shared.Models.ServiceShop? result;
string jsonFile;
string checkDirectory = Path.Combine(AppContext.BaseDirectory, "Data/Mike");
if (Directory.Exists(checkDirectory))
jsonFile = Path.Combine(checkDirectory, "service-shop.json");
else
jsonFile = Path.Combine(AppContext.BaseDirectory, "service-shop.json");
string json = File.ReadAllText(jsonFile);
result = JsonSerializer.Deserialize<Shared.Models.ServiceShop>(json);
return result;
}
async Task<ServiceShopOrder[]> IServiceShopOrderRepository.GetAllServiceShopOrders()
{
ServiceShopOrder[] results;
string? methodName = IMethodName.GetActualAsyncMethodName();
using (LogContext.PushProperty("MethodName", methodName))
{
_Log.Debug("() => ...");
Shared.Models.ServiceShop? serviceShop = await Task.Run(GetServiceShopOrders);
results = GetServiceShopOrders(serviceShop);
}
return results.ToArray();
}
async Task<ServiceShopOrder[]> IServiceShopOrderRepository.GetServiceShopOrders(string id)
{
ServiceShopOrder[] results;
Shared.Models.ServiceShop? serviceShop = await Task.Run(GetServiceShopOrders);
results = GetServiceShopOrders(serviceShop).Where(l => l.Id == id).ToArray();
return results;
}
}

View File

@ -0,0 +1,177 @@
using Newtonsoft.Json;
using OI.Metrology.Shared.DataModels;
using OI.Metrology.Shared.Models.Stateless;
using OI.Metrology.Shared.Services;
namespace OI.Metrology.Viewer.Repository;
public class ToolTypesRepository : IToolTypesRepository
{
private readonly Serilog.ILogger _Log;
public ToolTypesRepository() => _Log = Serilog.Log.ForContext<ToolTypesRepository>();
// Get a list of tooltypes, returns just Name and ID
object IToolTypesRepository.Index(IMetrologyRepository metrologyRepository)
{
var r = new
{
Results = metrologyRepository.GetToolTypes().Select(tt => new { tt.ToolTypeName, tt.ID })
};
return r;
}
// Gets the metadata for a tooltype, accepts a parameter which sorts the results
// This is used to setup the grid displays on the UI
object IToolTypesRepository.GetToolTypeMetadata(IMetrologyRepository metrologyRepository, int id, string sortby)
{
ToolType tt = metrologyRepository.GetToolTypeByID(id);
IEnumerable<ToolTypeMetadata> md = metrologyRepository.GetToolTypeMetadataByToolTypeID(id);
if (string.Equals(sortby, "grid", StringComparison.OrdinalIgnoreCase))
md = md.OrderBy(f => f.GridDisplayOrder).ToList();
if (string.Equals(sortby, "table", StringComparison.OrdinalIgnoreCase))
md = md.OrderBy(f => f.GridDisplayOrder).ToList();
var r = new
{
Results = new
{
ToolType = tt,
Metadata = md
}
};
return r;
}
// Gets headers, request/response format is to allow paging with igniteUI
// The headerid parameter is used for navigating directly to a header, when the button is clicked in Awaiting Dispo
string IToolTypesRepository.GetHeaders(IMetrologyRepository metrologyRepository, int id, DateTime? datebegin, DateTime? dateend, int? page, int? pagesize, long? headerid)
{
string result;
long totalRecs;
System.Data.DataTable dt = metrologyRepository.GetHeaders(id, datebegin, dateend, page, pagesize, headerid, out totalRecs);
var r = new
{
Results = dt,
TotalRows = totalRecs,
};
result = JsonConvert.SerializeObject(r);
return result;
}
// Gets header titles, used in the Run Headers UI
string IToolTypesRepository.GetHeaderTitles(IMetrologyRepository metrologyRepository, int id, int? page, int? pagesize)
{
string result;
long totalRecs;
IEnumerable<HeaderCommon> dt = metrologyRepository.GetHeaderTitles(id, page, pagesize, out totalRecs);
var r = new
{
Results = dt,
TotalRows = totalRecs,
};
result = JsonConvert.SerializeObject(r);
return result;
}
// Get all of the fields for a header, used with the Run Header UI
string IToolTypesRepository.GetHeaderFields(IMetrologyRepository metrologyRepository, int id, long headerid)
{
string result;
var r = new
{
Results = metrologyRepository.GetHeaderFields(id, headerid).Select(x => new { Column = x.Key, x.Value }).ToList()
};
result = JsonConvert.SerializeObject(r);
return result;
}
// Get the data for a header, used with the Run Info UI
string IToolTypesRepository.GetData(IMetrologyRepository metrologyRepository, int id, long headerid)
{
string result;
var r = new
{
Results = metrologyRepository.GetData(id, headerid)
};
result = JsonConvert.SerializeObject(r);
return result;
}
// Display an attachment, used for Run Info - note it is by tool type ID and attachment GUID, so it is best for internal use
(string?, string?, Stream?) IToolTypesRepository.GetAttachment(IMetrologyRepository metrologyRepository, IAttachmentsService attachmentsService, int toolTypeId, string tabletype, string attachmentId, string filename)
{
Stream? stream = null;
string? message = null;
Guid attachmentIdParsed;
string? contenttype = null;
ToolType tt = metrologyRepository.GetToolTypeByID(toolTypeId);
bool header = !string.Equals(tabletype.Trim(), "data", StringComparison.OrdinalIgnoreCase);
if (!Guid.TryParse(attachmentId, out attachmentIdParsed))
message = "Invalid attachment id";
else
{
try
{
// figure out what content type to use. this is very simple because there are only two types being used
contenttype = "application/pdf";
if (filename.ToLower().TrimEnd().EndsWith(".txt"))
contenttype = "text/plain";
// Get attachment stream and feed it to the client
stream = attachmentsService.GetAttachmentStreamByAttachmentId(tt, header, attachmentIdParsed, filename);
}
catch (Exception ex) { message = ex.Message; }
}
return new(message, contenttype, stream);
}
// This endpoint triggers writing of the OI Export file
Exception? IToolTypesRepository.OIExport(IMetrologyRepository metrologyRepository, string oiExportPath, int toolTypeId, long headerid)
{
Exception? result = null;
// Call the export stored procedure
_Log.Debug($"Exporting to <{oiExportPath}>");
System.Data.DataSet ds = metrologyRepository.GetOIExportData(toolTypeId, headerid);
try
{
// The SP must return 3 result tables
if (ds.Tables.Count != 3)
throw new Exception("Error exporting, invalid results");
// The first table has just one row, which is the export filename
if (ds.Tables[0].Rows.Count != 1)
throw new Exception("Error exporting, invalid filename");
string? filename = Convert.ToString(ds.Tables[0].Rows[0][0]);
// The second table has the header data
if (ds.Tables[1].Rows.Count != 1)
throw new Exception("Error exporting, invalid header data");
System.Text.StringBuilder sb = new();
foreach (object? o in ds.Tables[1].Rows[0].ItemArray)
{
if ((o is not null) && (!Convert.IsDBNull(o)))
_ = sb.Append(Convert.ToString(o));
_ = sb.Append('\t');
}
// The third table has the detail data
foreach (System.Data.DataRow dr in ds.Tables[2].Rows)
{
foreach (object? o in dr.ItemArray)
{
if ((o is not null) && (!Convert.IsDBNull(o)))
_ = sb.Append(Convert.ToString(o));
_ = sb.Append('\t');
}
}
_ = sb.AppendLine();
// The output file will only have one line, the header columns are output first
// Then each detail rows has it's columns appended
// H1, H2, H3, D1.1, D1.2, D1.3, D2.1, D2.2, D2.3, etc
// Write the file
File.WriteAllText(Path.Join(oiExportPath, filename), sb.ToString());
}
catch (Exception ex) { result = ex; }
return result;
}
}

View File

@ -1,32 +1,32 @@
using System;
using System.Globalization;
using System.IO;
using System.Globalization;
namespace OI.Metrology.Viewer.Services;
using OI.Metrology.Shared.DataModels;
using OI.Metrology.Shared.Repositories;
using OI.Metrology.Shared.Models.Stateless;
using OI.Metrology.Shared.Services;
using OI.Metrology.Viewer.Models;
public class AttachmentsService : IAttachmentsService
{
private readonly AppSettings _AppSettings;
private readonly IMetrologyRepository _MetrologyRepository;
private readonly IMetrologyRepo _Repo;
public AttachmentsService(AppSettings appSettings, IMetrologyRepo repo)
public AttachmentsService(AppSettings appSettings, IMetrologyRepository metrologyRepository)
{
_AppSettings = appSettings;
_Repo = repo;
_MetrologyRepository = metrologyRepository;
}
protected Stream GetAttachmentStream(string tableName, Guid attachmentId, string filename)
protected Stream GetAttachmentStream(string? tableName, Guid attachmentId, string filename)
{
if (attachmentId.Equals(Guid.Empty))
throw new Exception("No attachments found");
DateTime insertDate = Convert.ToDateTime(_Repo.GetAttachmentInsertDateByGUID(tableName, attachmentId));
if (tableName is null)
throw new NullReferenceException(nameof(tableName));
DateTime insertDate = Convert.ToDateTime(_MetrologyRepository.GetAttachmentInsertDateByGUID(tableName, attachmentId));
int year = insertDate.Year;
DateTime d = insertDate;
CultureInfo cul = CultureInfo.CurrentCulture;
@ -50,28 +50,28 @@ public class AttachmentsService : IAttachmentsService
public Stream GetAttachmentStreamByTitle(ToolType toolType, bool header, string title, string filename)
{
if (toolType == null)
if (toolType is null)
throw new Exception("Invalid tool type");
Guid attachmentId;
string tableName;
string? tableName;
if (header)
{
tableName = toolType.HeaderTableName;
attachmentId = _Repo.GetHeaderAttachmentIDByTitle(toolType.ID, title);
attachmentId = _MetrologyRepository.GetHeaderAttachmentIDByTitle(toolType.ID, title);
}
else
{
tableName = toolType.DataTableName;
attachmentId = _Repo.GetDataAttachmentIDByTitle(toolType.ID, title);
attachmentId = _MetrologyRepository.GetDataAttachmentIDByTitle(toolType.ID, title);
}
return GetAttachmentStream(tableName, attachmentId, filename);
}
public Stream GetAttachmentStreamByAttachmentId(ToolType toolType, bool header, Guid attachmentId, string filename)
{
if (toolType == null)
if (toolType is null)
throw new Exception("Invalid tool type");
string tableName;
string? tableName;
if (header)
tableName = toolType.HeaderTableName;
else
@ -79,27 +79,27 @@ public class AttachmentsService : IAttachmentsService
return GetAttachmentStream(tableName, attachmentId, filename);
}
private void SaveAttachment(ToolType toolType, long headerId, string dataUniqueId, string filename, Microsoft.AspNetCore.Http.IFormFile uploadedFile)
private void SaveAttachment(ToolType toolType, long headerId, string dataUniqueId, string filename, IFormFile uploadedFile)
{
if (toolType == null)
if (toolType is null)
throw new Exception("Invalid tool type");
using System.Transactions.TransactionScope trans = _Repo.StartTransaction();
using System.Transactions.TransactionScope trans = _MetrologyRepository.StartTransaction();
Guid attachmentId = Guid.Empty;
DateTime insertDate = new();
string tableName = "";
string? tableName = "";
if (string.IsNullOrWhiteSpace(dataUniqueId))
{
attachmentId = _Repo.GetHeaderAttachmentID(toolType.ID, headerId);
insertDate = Convert.ToDateTime(_Repo.GetHeaderInsertDate(toolType.ID, headerId));
attachmentId = _MetrologyRepository.GetHeaderAttachmentID(toolType.ID, headerId);
insertDate = Convert.ToDateTime(_MetrologyRepository.GetHeaderInsertDate(toolType.ID, headerId));
tableName = toolType.HeaderTableName;
}
else
{
attachmentId = _Repo.GetDataAttachmentID(toolType.ID, headerId, dataUniqueId);
insertDate = Convert.ToDateTime(_Repo.GetDataInsertDate(toolType.ID, headerId, dataUniqueId));
attachmentId = _MetrologyRepository.GetDataAttachmentID(toolType.ID, headerId, dataUniqueId);
insertDate = Convert.ToDateTime(_MetrologyRepository.GetDataInsertDate(toolType.ID, headerId, dataUniqueId));
// Get Date for new directory name
tableName = toolType.DataTableName;
@ -131,7 +131,7 @@ public class AttachmentsService : IAttachmentsService
public void SaveAttachment(ToolType toolType, long headerId, string dataUniqueId, string filename, object uploadedFile)
{
Microsoft.AspNetCore.Http.IFormFile formFile = (Microsoft.AspNetCore.Http.IFormFile)uploadedFile;
IFormFile formFile = (IFormFile)uploadedFile;
SaveAttachment(toolType, headerId, dataUniqueId, filename, formFile);
}

View File

@ -1,18 +1,17 @@
using Newtonsoft.Json.Linq;
using OI.Metrology.Shared.DataModels;
using OI.Metrology.Shared.Repositories;
using OI.Metrology.Shared.Models.Stateless;
using OI.Metrology.Shared.Services;
using System;
using System.Collections.Generic;
using System.Linq;
#pragma warning disable CS8600, CS8602, CS8603, CS8604, CS8625
namespace OI.Metrology.Viewer.Services;
public class InboundDataService : IInboundDataService
{
private readonly IMetrologyRepo _Repo;
private readonly IMetrologyRepository _MetrologyRepository;
public InboundDataService(IMetrologyRepo repo) => _Repo = repo;
public InboundDataService(IMetrologyRepository metrologyRepository) => _MetrologyRepository = metrologyRepository;
public long DoSQLInsert(JToken jsonbody, ToolType toolType, List<ToolTypeMetadata> metaData)
{
@ -37,11 +36,11 @@ public class InboundDataService : IInboundDataService
long headerId = 0;
using (System.Transactions.TransactionScope transScope = _Repo.StartTransaction())
using (System.Transactions.TransactionScope transScope = _MetrologyRepository.StartTransaction())
{
try
{
_Repo.PurgeExistingData(toolType.ID, uniqueId);
_MetrologyRepository.PurgeExistingData(toolType.ID, uniqueId);
}
catch (Exception ex)
{
@ -50,7 +49,7 @@ public class InboundDataService : IInboundDataService
try
{
headerId = _Repo.InsertToolDataJSON(jsonbody, -1, metaData, toolType.HeaderTableName);
headerId = _MetrologyRepository.InsertToolDataJSON(jsonbody, -1, metaData, toolType.HeaderTableName);
}
catch (Exception ex)
{
@ -60,11 +59,11 @@ public class InboundDataService : IInboundDataService
int detailrow = 1;
try
{
if (detailsArray != null)
if (detailsArray is not null)
{
foreach (JToken detail in detailsArray)
{
_ = _Repo.InsertToolDataJSON(detail, headerId, metaData, toolType.DataTableName);
_ = _MetrologyRepository.InsertToolDataJSON(detail, headerId, metaData, toolType.DataTableName);
detailrow += 1;
}
}
@ -133,7 +132,7 @@ public class InboundDataService : IInboundDataService
if (jp.First is JArray array)
detailsArray = array;
else if ((jp.First is JValue value) && (value.Value == null))
else if ((jp.First is JValue value) && (value.Value is null))
detailsArray = null;
else
errors.Add("Invalid details field");
@ -169,7 +168,7 @@ public class InboundDataService : IInboundDataService
}
// if a Details container if found, process it by recursion
if (detailsArray != null)
if (detailsArray is not null)
{
int i = 1;
foreach (JToken detail in detailsArray)
@ -189,7 +188,7 @@ public class InboundDataService : IInboundDataService
{
// get the json data for this container field, ex: Points
JProperty contJP = jsonbody.Children<JProperty>().Where(jp => string.Equals(jp.Name, containerField, StringComparison.OrdinalIgnoreCase)).SingleOrDefault();
if ((contJP != null) && (contJP.Value is JArray array))
if ((contJP is not null) && (contJP.Value is JArray array))
{
JArray contJPArray = array;

View File

@ -1,10 +1,11 @@
using OI.Metrology.Shared.Repositories;
using OI.Metrology.Viewer.Models;
using System;
using System.Data.Common;
using System.Data.SqlClient;
namespace OI.Metrology.Viewer.Repositories;
#pragma warning disable CS8600, CS8602, CS8603, CS8604, CS8625
namespace OI.Metrology.Viewer.Services;
public class SQLDbConnectionFactory : IDbConnectionFactory
{

View File

@ -73,7 +73,7 @@
<li><a href="https://oi-metrology-viewer-archive.mes.infineon.com/" target="_blank">Archive</a></li>
</ul>
<p class="navbar-text navbar-right">
@User.Identity.Name
@User.Identity?.Name
</p>
</div>
</div>

View File

@ -1,26 +1,6 @@
{
"AllowedHosts": "*",
"ApiLoggingContentTypes": "application/json",
"ApiLoggingPathPrefixes": "/api/inbound",
"ApiLogPath": "D:\\Metrology\\MetrologyAPILogs",
"AttachmentPath": "\\\\messv02ecc1.ec.local\\EC_Metrology_Si\\MetrologyAttachments",
"BuildNumber": "1",
"Company": "Infineon Technologies Americas Corp.",
"ConnectionString": "Data Source=messv01ec.ec.local\\PROD1,53959;Integrated Security=True;Initial Catalog=Metrology;",
"GitCommitSeven": "1234567",
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Log4netProvider": "Debug",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"InboundApiAllowedIPList": "",
"IsDevelopment": true,
"MonAResource": "OI_Metrology_Viewer_IFX",
"MonASite": "auc",
"Oi2SqlConnectionString": "Data Source=messv01ec.ec.local\\PROD1,53959;Initial Catalog=LSL2SQL;Persist Security Info=True;User ID=srpadmin;Password=0okm9ijn;",
"OIExportPath": "\\\\openinsight-db-srv.na.infineon.com\\apps\\Metrology\\Data",
"Serilog": {
"Using": [
"Serilog.Sinks.Console",
@ -58,6 +38,5 @@
"Application": "Sample"
}
},
"URLs": "https://localhost:7130;http://localhost:5126",
"WorkingDirectoryName": "IFXApps"
"URLs": "https://localhost:7130;http://localhost:5126"
}

View File

@ -17,6 +17,8 @@
}
},
"InboundApiAllowedIPList": "",
"IsDevelopment": false,
"IsStaging": false,
"MonAResource": "OI_Metrology_Viewer_EC",
"MonASite": "auc",
"Oi2SqlConnectionString": "Data Source=messv01ec.ec.local\\PROD1,53959;Initial Catalog=LSL2SQL;Persist Security Info=True;User ID=srpadmin;Password=0okm9ijn;",
@ -26,7 +28,7 @@
"Serilog.Sinks.Console",
"Serilog.Sinks.File"
],
"MinimumLevel": "Debug",
"MinimumLevel": "Information",
"WriteTo": [
{
"Name": "Debug",