Compare commits
1 Commits
416b283341
...
9bd5774e08
| Author | SHA1 | Date | |
|---|---|---|---|
| 9bd5774e08 |
@ -11,6 +11,7 @@ using System.Collections.Generic;
|
||||
using Microsoft.Data.SqlClient;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using MySqlConnector;
|
||||
using Org.BouncyCastle.Asn1.Cms;
|
||||
|
||||
namespace PSTW_CentralSystem.Areas.MMS.Controllers
|
||||
{
|
||||
@ -18,25 +19,40 @@ namespace PSTW_CentralSystem.Areas.MMS.Controllers
|
||||
{
|
||||
// From tbl_marine_tarball
|
||||
public int Id { get; set; }
|
||||
public string StationID { get; set; }
|
||||
public string Longitude { get; set; }
|
||||
public string Latitude { get; set; }
|
||||
public required string StationID { get; set; }
|
||||
public required string Longitude { get; set; }
|
||||
public required string Latitude { get; set; }
|
||||
public DateTime DateSample { get; set; }
|
||||
public TimeSpan TimeSample { get; set; }
|
||||
public string ClassifyID { get; set; }
|
||||
public string OptionalName1 { get; set; }
|
||||
public string OptionalName2 { get; set; }
|
||||
public string OptionalName3 { get; set; }
|
||||
public string OptionalName4 { get; set; }
|
||||
public string FirstSampler { get; set; }
|
||||
public required string ClassifyID { get; set; }
|
||||
public string? OptionalName1 { get; set; }
|
||||
public string? OptionalName2 { get; set; }
|
||||
public string? OptionalName3 { get; set; }
|
||||
public string? OptionalName4 { get; set; }
|
||||
public required string FirstSampler { get; set; }
|
||||
|
||||
// From joined tables
|
||||
public string LocationName { get; set; } // From tbl_marine_station
|
||||
public string StateName { get; set; } // From tbl_state
|
||||
public string FullName { get; set; } // From tbl_user
|
||||
public string LevelName { get; set; } // From tbl_level
|
||||
public required string LocationName { get; set; } // From tbl_marine_station
|
||||
public required string StateName { get; set; } // From tbl_state
|
||||
public required string FullName { get; set; } // From tbl_user
|
||||
public required string LevelName { get; set; } // From tbl_level
|
||||
}
|
||||
|
||||
public class TarBallGroupViewModel
|
||||
{
|
||||
public List<int> Id { get; set; } = new List<int>();
|
||||
public required string StationID { get; set; }
|
||||
public required string Date { get; set; }
|
||||
public required int TimeSampleCount { get; set; }
|
||||
public required string LatestTime {get; set; }
|
||||
public List<TarBallTimeSample> TimeSamples { get; set; } = new List<TarBallTimeSample>();
|
||||
}
|
||||
|
||||
public class TarBallTimeSample
|
||||
{
|
||||
public required int Id { get; set; }
|
||||
public string Time { get; set; }
|
||||
}
|
||||
[Area("MMS")]
|
||||
public class MarineController : Controller
|
||||
{
|
||||
@ -55,28 +71,37 @@ namespace PSTW_CentralSystem.Areas.MMS.Controllers
|
||||
return View();
|
||||
}
|
||||
|
||||
public IActionResult TarBallForm()//Queries the database and returns a view with tarball data
|
||||
public class StationDateGroup
|
||||
{
|
||||
public required string StationID { get; set; }
|
||||
public DateTime DateSample { get; set; }
|
||||
public List<TarballPdfDto> TimeSamples { get; set; } = new List<TarballPdfDto>();
|
||||
}
|
||||
public IActionResult TarBallForm()
|
||||
{
|
||||
try
|
||||
{
|
||||
var marineTarballs = _context.MarineTarballs //ERRORRRRRRR======================================
|
||||
var marineTarballs = _context.MarineTarballs
|
||||
.Select(t => new
|
||||
{
|
||||
t.Id,
|
||||
Date = t.DateSample.ToString("yyyy/MM/dd"),
|
||||
Station = t.StationID
|
||||
station = t.StationID,
|
||||
date = t.DateSample.ToString("yyyy/MM/dd"),
|
||||
time = t.TimeSample.ToString(@"hh\:mm\:ss"),
|
||||
fullDate = t.DateSample, // Keep DateTime for sorting
|
||||
t.TimeSample
|
||||
})
|
||||
.AsEnumerable()
|
||||
.OrderByDescending(t => t.fullDate)
|
||||
.ThenByDescending(t => t.TimeSample)
|
||||
.ToList();
|
||||
|
||||
Console.WriteLine($"Marine Tarballs Count: {marineTarballs.Count}");
|
||||
return View(marineTarballs);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// Show the real error in the browser (for debugging only)
|
||||
return Content($"Error: {ex.Message}<br/>{ex.StackTrace}", "text/html");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
[HttpGet] // Explicitly mark as a GET endpoint
|
||||
@ -222,7 +247,7 @@ namespace PSTW_CentralSystem.Areas.MMS.Controllers
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<IActionResult> GenerateReport(int id)//calls GeneratePdfResponse to generate a PDF for inline viewing
|
||||
public async Task<IActionResult> GenerateReport(int id)
|
||||
{
|
||||
return await GeneratePdfResponse(id, true);
|
||||
}
|
||||
@ -239,7 +264,7 @@ namespace PSTW_CentralSystem.Areas.MMS.Controllers
|
||||
{
|
||||
// Add timeout for safety
|
||||
var task = Task.Run(() => GeneratePdfResponse(id, false));
|
||||
if (task.Wait(TimeSpan.FromSeconds(30))) // 30 second timeout
|
||||
if (task.Wait(TimeSpan.FromSeconds(30))) // 30-second timeout
|
||||
{
|
||||
return task.Result;
|
||||
}
|
||||
@ -254,63 +279,55 @@ namespace PSTW_CentralSystem.Areas.MMS.Controllers
|
||||
|
||||
private async Task<IActionResult> GeneratePdfResponse(int id, bool forceDownload)
|
||||
{
|
||||
Console.WriteLine($"Requested ID in {(forceDownload ? "GenerateReport" : "ViewPDF")}: {id}");
|
||||
|
||||
// Temporary network connection test
|
||||
try
|
||||
{
|
||||
Console.WriteLine("Testing network connection...");
|
||||
_networkAccessService.ConnectToNetworkPath();
|
||||
Console.WriteLine("Network connected successfully!");
|
||||
_networkAccessService.DisconnectFromNetworkShare();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"NETWORK ERROR: {ex.Message}");
|
||||
return StatusCode(500, $"Cannot access network: {ex.Message}");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// Connect to the network path
|
||||
_networkAccessService.ConnectToNetworkPath();
|
||||
|
||||
// ===== 1. NEW SQL QUERY APPROACH =====
|
||||
var record = await _context.MarineTarballs.FirstOrDefaultAsync(t => t.Id == id);
|
||||
if (record == null)
|
||||
return NotFound($"No record found for Id: {id}");
|
||||
|
||||
// Retrieve all entries for the same StationID and DateSample
|
||||
var query = @"
|
||||
SELECT
|
||||
marine.*,
|
||||
station.LocationName,
|
||||
state.StateName,
|
||||
user.FullName,level.LevelName
|
||||
user.FullName,
|
||||
level.LevelName
|
||||
FROM tbl_marine_tarball marine
|
||||
JOIN tbl_marine_station station ON marine.StationID = station.StationID
|
||||
JOIN tbl_state state ON station.StateID = state.StateID
|
||||
JOIN tbl_user user ON marine.FirstSampler = user.FullName -- Corrected column name
|
||||
JOIN tbl_user user ON marine.FirstSampler = user.FullName
|
||||
JOIN tbl_level level ON user.LevelID = level.LevelID
|
||||
WHERE marine.Id = @id";
|
||||
WHERE marine.Id=@id";
|
||||
|
||||
var tarball = await _context.Database
|
||||
var tarballEntries = await _context.Database
|
||||
.SqlQueryRaw<TarballPdfDto>(query, new MySqlParameter("@id", id))
|
||||
.FirstOrDefaultAsync();
|
||||
.ToListAsync();
|
||||
|
||||
if (tarball == null)
|
||||
return NotFound("Record not found");
|
||||
if (!tarballEntries.Any())
|
||||
return NotFound($"No records found for Id: {id}");
|
||||
|
||||
//Prepare boolean values for PDF
|
||||
var pdfList = new List<IActionResult>();
|
||||
|
||||
// Iterate over each unique TimeSample within the same DateSample
|
||||
foreach (var timeGroup in tarballEntries.GroupBy(t => t.TimeSample))
|
||||
{
|
||||
var tarball = timeGroup.First(); // Use first entry per time sample
|
||||
|
||||
// Classification logic remains unchanged
|
||||
bool tarBallYes = tarball.ClassifyID != "NO";
|
||||
bool tarBallNo = tarball.ClassifyID == "NO";
|
||||
bool isSand = tarball.ClassifyID == "SD";
|
||||
bool isNonSandy = tarball.ClassifyID == "NS";
|
||||
bool isCoquina = tarball.ClassifyID == "CO";
|
||||
|
||||
// ===== 2. Get Images from path =====
|
||||
var sampleDateString = tarball.DateSample.ToString("yyyyMMdd");
|
||||
//var sampleTimeString = tarball.TimeSample.ToString("hhmmss");
|
||||
var sampleTimePrefix = ((int)tarball.TimeSample.TotalHours).ToString("D2") +
|
||||
tarball.TimeSample.Minutes.ToString("D2");
|
||||
// Construct image paths ensuring correct naming format
|
||||
var stationFolder = Path.Combine(PhotoBasePath, tarball.StationID);
|
||||
var sampleDateString = tarball.DateSample.ToString("yyyyMMdd");
|
||||
var sampleTimeString = tarball.TimeSample.ToString(@"hhmmss");
|
||||
|
||||
//Image collection
|
||||
var stationImages = new Dictionary<string, string>();
|
||||
|
||||
if (Directory.Exists(stationFolder))
|
||||
@ -321,7 +338,7 @@ namespace PSTW_CentralSystem.Areas.MMS.Controllers
|
||||
{ "RIGHTSIDECOASTALVIEW", null },
|
||||
{ "DRAWINGVERTICALLINES", null },
|
||||
{ "DRAWINGHORIZONTALLINES", null },
|
||||
{ "OPTIONAL01", null }, // Will remain null if not found
|
||||
{ "OPTIONAL01", null },
|
||||
{ "OPTIONAL02", null },
|
||||
{ "OPTIONAL03", null },
|
||||
{ "OPTIONAL04", null }
|
||||
@ -332,7 +349,8 @@ namespace PSTW_CentralSystem.Areas.MMS.Controllers
|
||||
var fileName = Path.GetFileNameWithoutExtension(imagePath);
|
||||
foreach (var type in imageTypes.Keys.ToList())
|
||||
{
|
||||
if (fileName.EndsWith(type, StringComparison.OrdinalIgnoreCase))
|
||||
if (fileName.StartsWith($"{tarball.StationID}_{sampleDateString}_{sampleTimeString}") &&
|
||||
fileName.Contains(type, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
imageTypes[type] = imagePath;
|
||||
break;
|
||||
@ -341,7 +359,8 @@ namespace PSTW_CentralSystem.Areas.MMS.Controllers
|
||||
}
|
||||
stationImages = imageTypes;
|
||||
}
|
||||
//Mandatory images
|
||||
|
||||
// Validate mandatory images exist
|
||||
var mandatoryImages = new List<string>
|
||||
{
|
||||
"LEFTSIDECOASTALVIEW",
|
||||
@ -350,16 +369,16 @@ namespace PSTW_CentralSystem.Areas.MMS.Controllers
|
||||
"DRAWINGHORIZONTALLINES"
|
||||
};
|
||||
|
||||
foreach(var mandatoryType in mandatoryImages)
|
||||
foreach (var mandatoryType in mandatoryImages)
|
||||
{
|
||||
if(!stationImages.ContainsKey(mandatoryType))
|
||||
if (!stationImages.ContainsKey(mandatoryType) || stationImages[mandatoryType] == null)
|
||||
{
|
||||
return StatusCode(400, $"Missing mandatory image: {mandatoryType}");
|
||||
return StatusCode(400, $"Missing mandatory image: {mandatoryType} for {tarball.StationID} on {tarball.DateSample}");
|
||||
}
|
||||
}
|
||||
|
||||
// ===== 3. GENERATE PDF (ADAPTED FOR NEW DTO) =====
|
||||
var pdf = new TarBallPDF(
|
||||
// Generate PDF using existing classification and sorting logic
|
||||
var pdfDocument = new TarBallPDF(
|
||||
tarball.StateName,
|
||||
tarball.StationID,
|
||||
tarball.LocationName,
|
||||
@ -390,23 +409,26 @@ namespace PSTW_CentralSystem.Areas.MMS.Controllers
|
||||
tarball.LevelName
|
||||
).GeneratePdf();
|
||||
|
||||
return forceDownload
|
||||
? File(pdf, "application/pdf", $"{tarball.StationID}_{tarball.DateSample:yyyyMMdd}_{tarball.TimeSample:hhmmss}.pdf")
|
||||
: File(pdf, "application/pdf");
|
||||
string pdfFileName = $"{tarball.StationID}_{tarball.DateSample:yyyyMMdd}_{tarball.TimeSample:hhmmss}.pdf";
|
||||
|
||||
pdfList.Add(
|
||||
forceDownload
|
||||
? File(pdfDocument, "application/pdf", pdfFileName)
|
||||
: File(pdfDocument, "application/pdf")
|
||||
);
|
||||
}
|
||||
|
||||
return pdfList.Count == 1 ? pdfList.First() : Ok(pdfList);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
var errorMessage = ex.InnerException != null
|
||||
? $"{ex.Message} (Inner: {ex.InnerException.Message})"
|
||||
: ex.Message;
|
||||
return Content($"PDF generation failed: {errorMessage}<br/>{ex.StackTrace}", "text/html");
|
||||
return StatusCode(500, $"Error: {ex.Message}");
|
||||
}
|
||||
finally
|
||||
{
|
||||
_networkAccessService.DisconnectFromNetworkShare();
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsImageValid(string imagePath)
|
||||
{
|
||||
try
|
||||
|
||||
@ -102,15 +102,21 @@
|
||||
return []; // Return an empty array if no data is available
|
||||
}
|
||||
|
||||
// Extract all years from the data
|
||||
const allYears = this.dataFromServer.map(data => new Date(data.date).getFullYear());
|
||||
// Extract all years from the data (handling both FormattedDate and date)
|
||||
const allYears = this.dataFromServer.map(data => {
|
||||
const dateStr = data.Date || data.date; // Handle both cases
|
||||
return new Date(dateStr).getFullYear();
|
||||
});
|
||||
|
||||
// Find the minimum and maximum years
|
||||
const minYear = Math.min(...allYears);
|
||||
const maxYear = Math.max(...allYears);
|
||||
|
||||
// Generate a range of years from minYear to maxYear
|
||||
return Array.from({ length: maxYear - minYear + 1 }, (_, i) => (minYear + i).toString());
|
||||
return Array.from(
|
||||
{ length: maxYear - minYear + 1 },
|
||||
(_, i) => (minYear + i).toString()
|
||||
);
|
||||
},
|
||||
sortedFilteredData() {
|
||||
// If no filters are applied, return all data sorted by descending date
|
||||
@ -154,11 +160,11 @@
|
||||
"data": null,
|
||||
"render": (data, type, row, meta) => meta.row + 1 // Dynamically generate "No."
|
||||
},
|
||||
{ "data": "date", "render": (data) => new Date(data).toLocaleDateString('en-GB') },
|
||||
{ "data": "date"},
|
||||
{ "data": "station" },
|
||||
{
|
||||
"data": null,
|
||||
"render": () => `
|
||||
"render": (data) => `
|
||||
<button class="btn btn-success">Approve</button>
|
||||
<button class="btn btn-danger">Reject</button>
|
||||
`
|
||||
@ -166,8 +172,10 @@
|
||||
{
|
||||
"data": null,
|
||||
"render": (data) => `
|
||||
<a href="/MMS/Marine/ViewPDF?id=${data.id}" class="btn btn-primary" target="_blank">View PDF</a>
|
||||
<a href="/MMS/Marine/GenerateReport?id=${data.id}" class="btn btn-primary">Download PDF</a>
|
||||
<a href="/MMS/Marine/ViewPDF?stationId=${data.Id}"
|
||||
class="btn btn-primary" target="_blank">View PDF</a>
|
||||
<a href="/MMS/Marine/GenerateReport?stationId=${data.Id}"
|
||||
class="btn btn-primary">Download PDF</a>
|
||||
`
|
||||
}
|
||||
],
|
||||
|
||||
Loading…
Reference in New Issue
Block a user