using Infineon.Monitoring.MonA; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Filters; using OI.Metrology.Server.Models; using OI.Metrology.Shared.DataModels; using OI.Metrology.Shared.Models.Stateless; using OI.Metrology.Shared.ViewModels; using System.Text; namespace OI.Metrology.Server.Controllers; public class ExportController : Controller { private readonly ILogger _Logger; private readonly AppSettings _AppSettings; private readonly bool _IsTestDatabase; private readonly IMetrologyRepository _MetrologyRepository; public ExportController(AppSettings appSettings, ILogger logger, IMetrologyRepository metrologyRepository) { _Logger = logger; _AppSettings = appSettings; _MetrologyRepository = metrologyRepository; _IsTestDatabase = appSettings.ConnectionString.Contains("test", StringComparison.InvariantCultureIgnoreCase); } public override void OnActionExecuted(ActionExecutedContext context) { base.OnActionExecuted(context); ViewBag.IsTestDatabase = _IsTestDatabase; } private string GetApiUrl() => string.IsNullOrEmpty(_AppSettings.ApiUrl) ? Url.Content("~/") : _AppSettings.ApiUrl[0] == '~' ? Url.Content(_AppSettings.ApiUrl) : _AppSettings.ApiUrl; [HttpGet] [Route("/Export")] public ActionResult Index() { Export model = new() { StartTime = DateTime.Now.AddMonths(-1), EndTime = DateTime.Now }; MonIn monIn = MonIn.GetInstance(); _ = monIn.SendStatus(_AppSettings.MonASite, _AppSettings.MonAResource, "Heartbeat", State.Up); ViewBag.ApiUrl = GetApiUrl(); return View(model); } [HttpPost] [Route("/ExportData")] public ActionResult ExportData(Export model) { 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 toolTypes = _MetrologyRepository.GetToolTypes(); toolType = toolTypes.Where(tt => tt.ID.ToString() == model.ToolType).SingleOrDefault(); if (toolType is null) ModelState.AddModelError("ToolType", "Invalid selection"); else if (string.IsNullOrWhiteSpace(toolType.ExportSPName)) ModelState.AddModelError("ToolType", "Tool type is not exportable"); } if (ModelState.IsValid) { try { 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); } catch (Exception ex) { ModelState.AddModelError("Exception", "Error exporting data"); ModelState.AddModelError("Exception", ex.Message); string errorMessage = $"Error exporting: {ex}"; _Logger.LogError(message: errorMessage); MonIn monIn = MonIn.GetInstance(); _ = monIn.SendStatus(_AppSettings.MonASite, _AppSettings.MonAResource, "Heartbeat", State.Warning); } } ViewBag.ApiUrl = GetApiUrl(); return View("Index", model); } 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(); 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); } protected static string GetRowData(System.Data.DataRow dr) { StringBuilder r = new(); for (int i = 0; i < dr.Table.Columns.Count; i++) { if (i > 0) _ = r.Append(','); object v = dr[i]; if (!Convert.IsDBNull(v)) { string? c = Convert.ToString(v); if (c is not null) _ = r.Append(FormatForCSV(c)); } } return r.ToString(); } protected static string GetColumnHeaders(System.Data.DataTable dt) { StringBuilder r = new(); for (int i = 0; i < dt.Columns.Count; i++) { if (i > 0) _ = r.Append(','); _ = r.Append(FormatForCSV(dt.Columns[i].ColumnName.TrimEnd('_'))); } return r.ToString(); } protected static string FormatForCSV(string v) { 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 { '\r' or '\n' => r.Append(' '), '"' => r.Append("\"\""), _ => r.Append(c), }; } if (doubleQuoted) _ = r.Append('"'); return r.ToString(); } }