Compare commits

..

3 Commits

Author SHA1 Message Date
416b283341 merge 2025-06-04 15:49:41 +08:00
82192fde0d Revert "fix test"
This reverts commit 457ee8f5d3.
2025-05-30 11:30:46 +08:00
457ee8f5d3 fix test 2025-05-30 11:15:11 +08:00
3 changed files with 128 additions and 169 deletions

View File

@ -11,7 +11,6 @@ using System.Collections.Generic;
using Microsoft.Data.SqlClient;
using Microsoft.EntityFrameworkCore;
using MySqlConnector;
using Org.BouncyCastle.Asn1.Cms;
namespace PSTW_CentralSystem.Areas.MMS.Controllers
{
@ -22,8 +21,8 @@ namespace PSTW_CentralSystem.Areas.MMS.Controllers
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 required DateTime DateSample { get; set; }
public required TimeSpan TimeSample { get; set; }
public required string ClassifyID { get; set; }
public string? OptionalName1 { get; set; }
public string? OptionalName2 { get; set; }
@ -38,21 +37,6 @@ namespace PSTW_CentralSystem.Areas.MMS.Controllers
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
{
@ -71,37 +55,28 @@ namespace PSTW_CentralSystem.Areas.MMS.Controllers
return View();
}
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()
public IActionResult TarBallForm()//Queries the database and returns a view with tarball data
{
try
{
var marineTarballs = _context.MarineTarballs
var marineTarballs = _context.MarineTarballs //ERRORRRRRRR======================================
.Select(t => new
{
t.Id,
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
Date = t.DateSample.ToString("yyyy/MM/dd"),
Station = t.StationID
})
.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
@ -201,7 +176,8 @@ namespace PSTW_CentralSystem.Areas.MMS.Controllers
// Determine content type based on extension
string contentType = "image/jpeg"; // default
string extension = Path.GetExtension(sanitizedFileName)?.ToLower();
string extension = Path.GetExtension(sanitizedFileName).ToLower();
//string extension = Path.GetExtension(sanitizedFileName)?.ToLower();
if (extension == ".png")
{
@ -247,7 +223,7 @@ namespace PSTW_CentralSystem.Areas.MMS.Controllers
}
}
public async Task<IActionResult> GenerateReport(int id)
public async Task<IActionResult> GenerateReport(int id)//calls GeneratePdfResponse to generate a PDF for inline viewing
{
return await GeneratePdfResponse(id, true);
}
@ -264,7 +240,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;
}
@ -279,15 +255,24 @@ namespace PSTW_CentralSystem.Areas.MMS.Controllers
private async Task<IActionResult> GeneratePdfResponse(int id, bool forceDownload)
{
Console.WriteLine($"Requested ID in {(forceDownload ? "GenerateReport" : "ViewPDF")}: {id}");
// Test network connection first
try
{
_networkAccessService.ConnectToNetworkPath();
_networkAccessService.DisconnectFromNetworkShare();
}
catch (Exception ex)
{
return StatusCode(500, $"Cannot access network: {ex.Message}");
}
try
{
_networkAccessService.ConnectToNetworkPath();
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
// ===== 1. Get Data from Database =====
var query = @"
SELECT
marine.*,
@ -300,85 +285,70 @@ namespace PSTW_CentralSystem.Areas.MMS.Controllers
JOIN tbl_state state ON station.StateID = state.StateID
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 tarballEntries = await _context.Database
var tarball = await _context.Database
.SqlQueryRaw<TarballPdfDto>(query, new MySqlParameter("@id", id))
.ToListAsync();
.FirstOrDefaultAsync();
if (!tarballEntries.Any())
return NotFound($"No records found for Id: {id}");
if (tarball == null)
return NotFound("Record not found");
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
// Prepare boolean values for PDF
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";
// Construct image paths ensuring correct naming format
var stationFolder = Path.Combine(PhotoBasePath, tarball.StationID);
// ===== 2. Get Images =====
// For date (stored as DATE in DB → "2025-01-30" becomes "20250130")
var sampleDateString = tarball.DateSample.ToString("yyyyMMdd");
var sampleTimeString = tarball.TimeSample.ToString(@"hhmmss");
// For time (stored as TIME in DB → "16:49:02" becomes "164902")
var sampleTimeString = tarball.TimeSample.ToString("hhmmss");
var stationFolder = Path.Combine(PhotoBasePath, tarball.StationID);
var stationImages = new Dictionary<string, string>();
var foundAnyImages = false;
if (Directory.Exists(stationFolder))
{
var imageTypes = new Dictionary<string, string>
{
{ "LEFTSIDECOASTALVIEW", null },
{ "RIGHTSIDECOASTALVIEW", null },
{ "DRAWINGVERTICALLINES", null },
{ "DRAWINGHORIZONTALLINES", null },
{ "OPTIONAL01", null },
{ "OPTIONAL02", null },
{ "OPTIONAL03", null },
{ "OPTIONAL04", null }
};
var basePattern = $"{tarball.StationID}_{sampleDateString}_{sampleTimeString}_";
var allImages = Directory.GetFiles(stationFolder, $"{basePattern}*");
foreach (var imagePath in Directory.GetFiles(stationFolder))
foreach (var imagePath in allImages)
{
var fileName = Path.GetFileNameWithoutExtension(imagePath);
foreach (var type in imageTypes.Keys.ToList())
{
if (fileName.StartsWith($"{tarball.StationID}_{sampleDateString}_{sampleTimeString}") &&
fileName.Contains(type, StringComparison.OrdinalIgnoreCase))
{
imageTypes[type] = imagePath;
break;
var type = fileName.Split('_').Last();
stationImages[type] = imagePath;
foundAnyImages = true;
}
}
}
stationImages = imageTypes;
}
// Validate mandatory images exist
var mandatoryImages = new List<string>
if (!foundAnyImages)
{
return StatusCode(404, "No images found for this record");
}
// Verify mandatory images exist
var mandatoryImages = new[] {
"LEFTSIDECOASTALVIEW",
"RIGHTSIDECOASTALVIEW",
"DRAWINGVERTICALLINES",
"DRAWINGHORIZONTALLINES"
};
foreach (var mandatoryType in mandatoryImages)
foreach (var type in mandatoryImages)
{
if (!stationImages.ContainsKey(mandatoryType) || stationImages[mandatoryType] == null)
if (!stationImages.ContainsKey(type))
{
return StatusCode(400, $"Missing mandatory image: {mandatoryType} for {tarball.StationID} on {tarball.DateSample}");
return StatusCode(400, $"Missing mandatory image: {type}");
}
}
// Generate PDF using existing classification and sorting logic
var pdfDocument = new TarBallPDF(
// ===== 3. Generate PDF =====
var pdf = new TarBallPDF(
tarball.StateName,
tarball.StationID,
tarball.LocationName,
@ -409,26 +379,22 @@ namespace PSTW_CentralSystem.Areas.MMS.Controllers
tarball.LevelName
).GeneratePdf();
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);
// ===== 4. Return PDF =====
var downloadName = $"{tarball.StationID}_{sampleDateString}_{sampleTimeString}.pdf";
return forceDownload
? File(pdf, "application/pdf", downloadName)
: File(pdf, "application/pdf");
}
catch (Exception ex)
{
return StatusCode(500, $"Error: {ex.Message}");
return StatusCode(500, $"PDF generation failed: {ex.Message}");
}
finally
{
_networkAccessService.DisconnectFromNetworkShare();
}
}
private bool IsImageValid(string imagePath)
{
try

View File

@ -11,8 +11,8 @@ namespace PSTW_CentralSystem.Areas.MMS.Models.PDFGenerator
string longitude, string latitude, DateTime dateSample, TimeSpan timeSample,
string classifyID, bool tarBallYes, bool tarBallNo, bool isSand, bool isNonSandy,
bool isCoquina, string photoPath1, string photoPath2, string photoPath3, string photoPath4,
string photoPath5, string photoPath6, string photoPath7, string photoPath8,
string optionalName1, string optionalName2, string optionalName3, string optionalName4,
string? photoPath5, string? photoPath6, string? photoPath7, string? photoPath8,
string? optionalName1, string? optionalName2, string? optionalName3, string? optionalName4,
string firstSampler, string fullName, string levelName
)
: IDocument
@ -360,7 +360,7 @@ namespace PSTW_CentralSystem.Areas.MMS.Models.PDFGenerator
table.Cell().Element(CellStyle).Text("Signature").FontSize(12);
table.Cell().Element(CellStyle).Text("");
table.Cell().Element(CellStyle).Text("Date").FontSize(12);
table.Cell().Element(CellStyle).Text(_dateSample.ToString("yyyy/MM/dd")).FontSize(12);
table.Cell().Element(CellStyle).Text($"{_dateSample:yyyyMMdd}").FontSize(12);
table.Cell().Element(CellStyle).Text("Designation").FontSize(12);
table.Cell().ColumnSpan(3).Element(CellStyle).Text(_levelName).FontSize(12);

View File

@ -102,21 +102,15 @@
return []; // Return an empty array if no data is available
}
// 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();
});
// Extract all years from the data
const allYears = this.dataFromServer.map(data => new Date(data.date).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
@ -160,11 +154,12 @@
"data": null,
"render": (data, type, row, meta) => meta.row + 1 // Dynamically generate "No."
},
{ "data": "date"},
{ "data": "date", "render": (data) => new Date(data).toLocaleDateString('en-GB') },
{ "data": "station" },
{
"data": null,
"render": (data) => `
"render": () => `
<button class="btn btn-success">Approve</button>
<button class="btn btn-danger">Reject</button>
`
@ -172,10 +167,8 @@
{
"data": null,
"render": (data) => `
<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>
<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>
`
}
],