From c9b625bd4f296f4f44c90f7fcd6ce23bbbad2cc6 Mon Sep 17 00:00:00 2001 From: Dave Walker Date: Sun, 18 Jan 2026 08:56:07 +0000 Subject: [PATCH 1/3] Rename IMO to 'Identifier' ; Remove schema constraints on identifier --- docker/api/Dockerfile | 2 +- docker/ui/Dockerfile | 2 +- .../Controllers/SightingsController.cs | 10 +- .../Controllers/VesselsController.cs | 20 +- .../ShippingRecorder.Api.csproj | 4 +- .../Database/VesselManager.cs | 69 +- .../ShippingRecorder.BusinessLogic.csproj | 4 +- .../Sql/MyVoyages.sql | 2 +- .../ApiClient/SightingClient.cs | 8 +- .../ApiClient/VesselClient.cs | 24 +- .../Interfaces/ISightingClient.cs | 2 +- .../Interfaces/IVesselClient.cs | 6 +- .../ShippingRecorder.Client.csproj | 4 +- ...20251207050413_InitialCreation.Designer.cs | 511 -------------- .../20260107141718_JobStatus.Designer.cs | 544 -------------- .../Migrations/20260107141718_JobStatus.cs | 41 -- ...60108161616_LocationStatistics.Designer.cs | 558 --------------- .../20260108161616_LocationStatistics.cs | 35 - ...0260108165158_SightingsByMonth.Designer.cs | 578 --------------- .../20260108165158_SightingsByMonth.cs | 37 - .../20260108174600_MyVoyages.Designer.cs | 598 ---------------- .../Migrations/20260108174600_MyVoyages.cs | 38 - ...60108181050_OperatorStatistics.Designer.cs | 615 ---------------- .../20260108181050_OperatorStatistics.cs | 36 - ...108183209_VesselTypeStatistics.Designer.cs | 632 ----------------- .../20260108183209_VesselTypeStatistics.cs | 36 - .../20260108184554_FlagStatistics.Designer.cs | 652 ----------------- .../20260108184554_FlagStatistics.cs | 37 - .../20260111174920_VoyageVessel.Designer.cs | 666 ------------------ .../Migrations/20260111174920_VoyageVessel.cs | 54 -- .../20260111175439_VoyageEventDate.cs | 30 - ...084003_NonIMOVesselIdentifier.Designer.cs} | 24 +- ... 20260118084003_NonIMOVesselIdentifier.cs} | 151 +++- .../ShippingRecorderDbContextModelSnapshot.cs | 20 +- .../ShippingRecorder.Data.csproj | 4 +- .../ShippingRecorderDbContext.cs | 12 +- .../Entities/ExportableSighting.cs | 6 +- .../Entities/ExportableVessel.cs | 75 +- .../Entities/ExportableVoyage.cs | 8 +- .../Extensions/SightingExtensions.cs | 2 +- .../Extensions/VesselExtensions.cs | 3 +- .../Extensions/VoyageExtensions.cs | 2 +- .../Import/SightingImporter.cs | 10 +- .../Import/VesselImporter.cs | 16 +- .../Import/VoyageImporter.cs | 10 +- .../ShippingRecorder.DataExchange.csproj | 4 +- .../Db/RegistrationHistory.cs | 4 +- src/ShippingRecorder.Entities/Db/Vessel.cs | 11 +- .../Exceptions/InvalidIMOException.cs | 8 +- .../Interfaces/IVesselManager.cs | 6 +- .../Reporting/MyVoyages.cs | 2 +- .../ShippingRecorder.Entities.csproj | 4 +- .../ShippingRecorder.Manager.csproj | 4 +- .../SearchSightingsByVesselController.cs | 2 +- .../Controllers/VesselsController.cs | 41 +- .../Helpers/VesselListGenerator.cs | 6 +- .../Models/AddVesselViewModel.cs | 2 +- .../Models/SightingDetailsViewModel.cs | 10 +- .../Models/SightingSearchByVesselViewModel.cs | 10 +- .../ShippingRecorder.Mvc.csproj | 4 +- .../Views/ConfirmDetails/Index.cshtml | 4 +- .../Views/MyVoyages/Index.cshtml | 2 +- .../SearchSightingsByVessel/Index.cshtml | 8 +- .../Shared/_SightingSearchResults.cshtml | 4 +- .../Views/Shared/_SightingSummary.cshtml | 4 +- .../Views/Shared/_VesselProperties.cshtml | 8 +- .../Views/Shared/_VoyageSearchResults.cshtml | 2 +- .../Views/SightingDetails/Index.cshtml | 6 +- .../Views/VesselDetails/Index.cshtml | 4 +- .../Views/Vessels/Index.cshtml | 4 +- .../Wizard/AddSightingWizard.cs | 15 +- .../Client/SightingClientTest.cs | 8 +- .../Client/VesselClientTest.cs | 25 +- .../Client/VoyageClientTest.cs | 2 +- .../Db/RegistrationHistoryManagerTest.cs | 4 +- .../Db/SightingsManagerTest.cs | 2 +- .../Db/VesselManagerTest.cs | 50 +- .../Db/VoyageEventManagerTest.cs | 4 +- .../Db/VoyageManagerTest.cs | 4 +- .../Export/SightingExporterTest.cs | 10 +- .../Export/VesselExporterTest.cs | 10 +- .../Export/VoyageExporterTest.cs | 10 +- .../Extensions/DecimalExtensionsTest.cs | 2 +- .../Extensions/IntegerExtenionsTest.cs | 2 +- .../Extensions/StringExtensionsTest.cs | 2 +- .../Import/SightingImporterTest.cs | 20 +- .../Import/VesselImporterTest.cs | 18 +- .../Import/VoyageImporterTest.cs | 20 +- .../Mocks/DataGenerator.cs | 3 +- .../ShippingRecorder.Tests.csproj | 2 +- 90 files changed, 533 insertions(+), 6042 deletions(-) delete mode 100644 src/ShippingRecorder.Data/Migrations/20251207050413_InitialCreation.Designer.cs delete mode 100644 src/ShippingRecorder.Data/Migrations/20260107141718_JobStatus.Designer.cs delete mode 100644 src/ShippingRecorder.Data/Migrations/20260107141718_JobStatus.cs delete mode 100644 src/ShippingRecorder.Data/Migrations/20260108161616_LocationStatistics.Designer.cs delete mode 100644 src/ShippingRecorder.Data/Migrations/20260108161616_LocationStatistics.cs delete mode 100644 src/ShippingRecorder.Data/Migrations/20260108165158_SightingsByMonth.Designer.cs delete mode 100644 src/ShippingRecorder.Data/Migrations/20260108165158_SightingsByMonth.cs delete mode 100644 src/ShippingRecorder.Data/Migrations/20260108174600_MyVoyages.Designer.cs delete mode 100644 src/ShippingRecorder.Data/Migrations/20260108174600_MyVoyages.cs delete mode 100644 src/ShippingRecorder.Data/Migrations/20260108181050_OperatorStatistics.Designer.cs delete mode 100644 src/ShippingRecorder.Data/Migrations/20260108181050_OperatorStatistics.cs delete mode 100644 src/ShippingRecorder.Data/Migrations/20260108183209_VesselTypeStatistics.Designer.cs delete mode 100644 src/ShippingRecorder.Data/Migrations/20260108183209_VesselTypeStatistics.cs delete mode 100644 src/ShippingRecorder.Data/Migrations/20260108184554_FlagStatistics.Designer.cs delete mode 100644 src/ShippingRecorder.Data/Migrations/20260108184554_FlagStatistics.cs delete mode 100644 src/ShippingRecorder.Data/Migrations/20260111174920_VoyageVessel.Designer.cs delete mode 100644 src/ShippingRecorder.Data/Migrations/20260111174920_VoyageVessel.cs delete mode 100644 src/ShippingRecorder.Data/Migrations/20260111175439_VoyageEventDate.cs rename src/ShippingRecorder.Data/Migrations/{20260111175439_VoyageEventDate.Designer.cs => 20260118084003_NonIMOVesselIdentifier.Designer.cs} (97%) rename src/ShippingRecorder.Data/Migrations/{20251207050413_InitialCreation.cs => 20260118084003_NonIMOVesselIdentifier.cs} (73%) diff --git a/docker/api/Dockerfile b/docker/api/Dockerfile index bc0f8c2..b411bdc 100644 --- a/docker/api/Dockerfile +++ b/docker/api/Dockerfile @@ -1,4 +1,4 @@ FROM mcr.microsoft.com/dotnet/core/aspnet:latest -COPY shippingrecorder.api-1.8.0.0 /opt/shippingrecorder.api +COPY shippingrecorder.api-1.9.0.0 /opt/shippingrecorder.api WORKDIR /opt/shippingrecorder.api/bin ENTRYPOINT [ "./ShippingRecorder.Api" ] diff --git a/docker/ui/Dockerfile b/docker/ui/Dockerfile index 676394a..7ac5481 100644 --- a/docker/ui/Dockerfile +++ b/docker/ui/Dockerfile @@ -1,4 +1,4 @@ FROM mcr.microsoft.com/dotnet/aspnet:latest AS runtime -COPY shippingrecorder.mvc-1.8.0.0 /opt/shippingrecorder.mvc +COPY shippingrecorder.mvc-1.9.0.0 /opt/shippingrecorder.mvc WORKDIR /opt/shippingrecorder.mvc/bin ENTRYPOINT [ "./ShippingRecorder.Mvc" ] diff --git a/src/ShippingRecorder.Api/Controllers/SightingsController.cs b/src/ShippingRecorder.Api/Controllers/SightingsController.cs index e41f607..4c8a6c8 100644 --- a/src/ShippingRecorder.Api/Controllers/SightingsController.cs +++ b/src/ShippingRecorder.Api/Controllers/SightingsController.cs @@ -55,16 +55,16 @@ public async Task>> GetSightingsByVesselAsync(int ve } [HttpGet] - [Route("recent/imo/{imo}")] - public async Task> GetMostRecentVesselSightingAsync(string imo) + [Route("recent/identifier/{identifier}")] + public async Task> GetMostRecentVesselSightingAsync(string identifier) { - LogMessage(Severity.Debug, $"Retrieving most recent sighting for vessel {imo}"); + LogMessage(Severity.Debug, $"Retrieving most recent sighting for vessel {identifier}"); - Sighting sighting = await Factory.Sightings.GetMostRecentAsync(x => x.Vessel.IMO == imo); + Sighting sighting = await Factory.Sightings.GetMostRecentAsync(x => x.Vessel.Identifier == identifier); if (sighting == null) { - LogMessage(Severity.Debug, $"Sighting for vessel {imo} not found"); + LogMessage(Severity.Debug, $"Sighting for vessel {identifier} not found"); return NoContent(); } diff --git a/src/ShippingRecorder.Api/Controllers/VesselsController.cs b/src/ShippingRecorder.Api/Controllers/VesselsController.cs index 7f53d11..e3701bb 100644 --- a/src/ShippingRecorder.Api/Controllers/VesselsController.cs +++ b/src/ShippingRecorder.Api/Controllers/VesselsController.cs @@ -53,16 +53,16 @@ public async Task> GetVesselByIdAsync(int id) } [HttpGet] - [Route("imo/{imo}")] - public async Task> GetVesselByIMOAsync(string imo) + [Route("identifier/{identifier}")] + public async Task> GetVesselByIdentifierAsync(string identifier) { - LogMessage(Severity.Debug, $"Retrieving vessel with IMO {imo}"); + LogMessage(Severity.Debug, $"Retrieving vessel with identifier {identifier}"); - Vessel vessel = await Factory.Vessels.GetAsync(m => m.IMO == imo); + Vessel vessel = await Factory.Vessels.GetAsync(m => m.Identifier == identifier); if (vessel == null) { - LogMessage(Severity.Debug, $"Vessel with IMO {imo} not found"); + LogMessage(Severity.Debug, $"Vessel with identifier {identifier} not found"); return NotFound(); } @@ -75,13 +75,14 @@ public async Task> AddVesselAsync([FromBody] Vessel templat { LogMessage(Severity.Debug, $"Adding vessel: " + - $"IMO = {template.IMO}, " + + $"Identifier = {template.Identifier}, " + + $"Is IMO = {template.IsIMO}, " + $"Built = {template.Built}, " + $"Draught = {template.Draught}, " + $"Length = {template.Length}, " + $"Beam = {template.Beam}"); - Vessel vessel = await Factory.Vessels.AddAsync(template.IMO, template.Built, template.Draught, template.Length, template.Beam); + Vessel vessel = await Factory.Vessels.AddAsync(template.Identifier, template.IsIMO, template.Built, template.Draught, template.Length, template.Beam); LogMessage(Severity.Debug, $"Vessel added: {vessel}"); return vessel; } @@ -93,13 +94,14 @@ public async Task> UpdateVesselAsync([FromBody] Vessel temp LogMessage(Severity.Debug, $"Adding vessel: " + $"ID = {template.Id}, " + - $"IMO = {template.IMO}, " + + $"Identifier = {template.Identifier}, " + + $"Is IMO = {template.IsIMO}, " + $"Built = {template.Built}, " + $"Draught = {template.Draught}, " + $"Length = {template.Length}, " + $"Beam = {template.Beam}"); - Vessel vessel = await Factory.Vessels.UpdateAsync(template.Id, template.IMO, template.Built, template.Draught, template.Length, template.Beam); + Vessel vessel = await Factory.Vessels.UpdateAsync(template.Id, template.Identifier, template.IsIMO, template.Built, template.Draught, template.Length, template.Beam); LogMessage(Severity.Debug, $"Vessel updated: {vessel}"); return vessel; } diff --git a/src/ShippingRecorder.Api/ShippingRecorder.Api.csproj b/src/ShippingRecorder.Api/ShippingRecorder.Api.csproj index cfe13f0..23d418f 100644 --- a/src/ShippingRecorder.Api/ShippingRecorder.Api.csproj +++ b/src/ShippingRecorder.Api/ShippingRecorder.Api.csproj @@ -2,8 +2,8 @@ net9.0 - 1.8.0.0 - 1.8.0.0 + 1.9.0.0 + 1.9.0.0 enable false NU1900 diff --git a/src/ShippingRecorder.BusinessLogic/Database/VesselManager.cs b/src/ShippingRecorder.BusinessLogic/Database/VesselManager.cs index 05257b9..d4cb708 100644 --- a/src/ShippingRecorder.BusinessLogic/Database/VesselManager.cs +++ b/src/ShippingRecorder.BusinessLogic/Database/VesselManager.cs @@ -46,7 +46,7 @@ public virtual IAsyncEnumerable ListAsync(Expression> .ThenInclude(h => h.Flag) .Include(x => x.RegistrationHistory) .ThenInclude(h => h.Operator) - .OrderBy(x => x.IMO) + .OrderBy(x => x.Identifier) .Skip((pageNumber - 1) * pageSize) .Take(pageSize) .AsAsyncEnumerable(); @@ -54,31 +54,40 @@ public virtual IAsyncEnumerable ListAsync(Expression> /// /// Add a vessel /// - /// + /// + /// /// /// /// /// /// - public async Task AddAsync(string imo, int? built, decimal? draught, int? length, int? beam) + public async Task AddAsync(string identifier, bool isIMO, int? built, decimal? draught, int? length, int? beam) { - imo = imo.CleanCode(); - _factory.Logger.LogMessage(Severity.Debug, $"Adding vessel: IMO = {imo}, Built = {built}, Draught = {draught}, Length = {length}, Beam = {beam}"); + _factory.Logger.LogMessage(Severity.Debug, $"Adding vessel: Identifier = {identifier}, Built = {built}, Draught = {draught}, Length = {length}, Beam = {beam}"); // Validate the parameters - imo.ValidateNumericAndThrow(7, 7); + if (isIMO) + { + identifier = identifier.CleanCode(); + identifier.ValidateNumericAndThrow(7, 7); + } + else + { + identifier = identifier.Clean().ToUpper(); + } + built.ValidateIntegerAndThrow(Vessel.EarliestYearBuilt, DateTime.Today.Year, true); draught.ValidateDecimalAndThrow(Vessel.MinimumDraught, decimal.MaxValue, true); length.ValidateIntegerAndThrow(Vessel.MinimumLength, int.MaxValue, true); beam.ValidateIntegerAndThrow(Vessel.MinimumBeam, int.MaxValue, true); // Check the vessel doesn't already exist - await CheckVesselIsNotADuplicate(imo, 0); + await CheckVesselIsNotADuplicate(identifier, 0); // Add the vessel and save changes var vessel = new Vessel { - IMO = imo, + Identifier = identifier, Built = built, Draught = draught, Length = length, @@ -98,19 +107,20 @@ public async Task AddAsync(string imo, int? built, decimal? draught, int /// /// Add a vessel, if it doesn't already exist /// - /// + /// + /// /// /// /// /// /// - public async Task AddIfNotExistsAsync(string imo, int? built, decimal? draught, int? length, int? beam) + public async Task AddIfNotExistsAsync(string identifier, bool isIMO, int? built, decimal? draught, int? length, int? beam) { - imo = imo.CleanCode(); - var vessel = await GetAsync(x => x.IMO == imo); + identifier = isIMO ? identifier.CleanCode() : identifier.Clean().ToUpper(); + var vessel = await GetAsync(x => x.Identifier == identifier); if (vessel == null) { - vessel = await AddAsync(imo, built, draught, length, beam); + vessel = await AddAsync(identifier, isIMO, built, draught, length, beam); } return vessel; } @@ -119,20 +129,29 @@ public async Task AddIfNotExistsAsync(string imo, int? built, decimal? d /// Update a vessel /// /// - /// + /// + /// /// /// /// /// /// /// - public async Task UpdateAsync(long id, string imo, int? built, decimal? draught, int? length, int? beam) + public async Task UpdateAsync(long id, string identifier, bool isIMO, int? built, decimal? draught, int? length, int? beam) { - imo = imo.CleanCode(); - _factory.Logger.LogMessage(Severity.Debug, $"Updating vessel: ID = {id}, IMO = {imo}, Built = {built}, Draught = {draught}, Length = {length}, Beam = {beam}"); + identifier = identifier.CleanCode(); + _factory.Logger.LogMessage(Severity.Debug, $"Updating vessel: ID = {id}, Identifier = {identifier}, Built = {built}, Draught = {draught}, Length = {length}, Beam = {beam}"); - // Validate the IMO - imo.ValidateNumericAndThrow(7, 7); + // Validate the identifier + if (isIMO) + { + identifier = identifier.CleanCode(); + identifier.ValidateNumericAndThrow(7, 7); + } + else + { + identifier = identifier.Clean().ToUpper(); + } // Retrieve the vessel var vessel = await Context.Vessels.FirstOrDefaultAsync(x => x.Id == id); @@ -143,10 +162,10 @@ public async Task UpdateAsync(long id, string imo, int? built, decimal? } // Check the vessel doesn't already exist - await CheckVesselIsNotADuplicate(imo, id); + await CheckVesselIsNotADuplicate(identifier, id); // Update the vessel properties and save changes - vessel.IMO = imo; + vessel.Identifier = identifier; vessel.Built = built; vessel.Draught = draught; vessel.Length = length; @@ -187,15 +206,15 @@ public async Task DeleteAsync(long id) /// /// Raise an exception if an attempt is made to add/update a duplicate vessel /// - /// + /// /// /// - private async Task CheckVesselIsNotADuplicate(string imo, long id) + private async Task CheckVesselIsNotADuplicate(string identifier, long id) { - var vessel = await Context.Vessels.FirstOrDefaultAsync(x => x.IMO == imo); + var vessel = await Context.Vessels.FirstOrDefaultAsync(x => x.Identifier == identifier); if ((vessel != null) && (vessel.Id != id)) { - var message = $"Vessel {imo} already exists"; + var message = $"Vessel {identifier} already exists"; throw new VesselExistsException(message); } } diff --git a/src/ShippingRecorder.BusinessLogic/ShippingRecorder.BusinessLogic.csproj b/src/ShippingRecorder.BusinessLogic/ShippingRecorder.BusinessLogic.csproj index a7fc837..c2c95fc 100644 --- a/src/ShippingRecorder.BusinessLogic/ShippingRecorder.BusinessLogic.csproj +++ b/src/ShippingRecorder.BusinessLogic/ShippingRecorder.BusinessLogic.csproj @@ -3,7 +3,7 @@ net9.0 ShippingRecorder.BusinessLogic - 1.8.0.0 + 1.9.0.0 Dave Walker Copyright (c) Dave Walker 2025 Dave Walker @@ -15,7 +15,7 @@ https://github.com/davewalker5/ShippingRecorder MIT false - 1.8.0.0 + 1.9.0.0 NU1900 diff --git a/src/ShippingRecorder.BusinessLogic/Sql/MyVoyages.sql b/src/ShippingRecorder.BusinessLogic/Sql/MyVoyages.sql index d5e0ead..d9c64a0 100644 --- a/src/ShippingRecorder.BusinessLogic/Sql/MyVoyages.sql +++ b/src/ShippingRecorder.BusinessLogic/Sql/MyVoyages.sql @@ -1,6 +1,6 @@ SELECT s.Date, l.Name AS "Location", - v.IMO, + v.Identifier, rh.Name AS "Vessel", v.Id AS "VesselId" FROM SIGHTING s diff --git a/src/ShippingRecorder.Client/ApiClient/SightingClient.cs b/src/ShippingRecorder.Client/ApiClient/SightingClient.cs index 9e21a5e..f161907 100644 --- a/src/ShippingRecorder.Client/ApiClient/SightingClient.cs +++ b/src/ShippingRecorder.Client/ApiClient/SightingClient.cs @@ -119,12 +119,12 @@ public async Task> ListAsync(int pageNumber, int pageSize) => await ListSightingsAsync(null, pageNumber, pageSize); /// - /// Get the most recent sighting of an aircraft + /// Get the most recent sighting of a vessel /// - /// + /// /// - public async Task GetMostRecentVesselSightingAsync(string imo) - => (await ListSightingsAsync($"vessel/{imo}", 1, 1))?.FirstOrDefault(); + public async Task GetMostRecentVesselSightingAsync(string identifier) + => (await ListSightingsAsync($"vessel/{identifier}", 1, 1))?.FirstOrDefault(); /// /// Return a list of sightings for the specified vessel diff --git a/src/ShippingRecorder.Client/ApiClient/VesselClient.cs b/src/ShippingRecorder.Client/ApiClient/VesselClient.cs index 316fa5d..e40d832 100644 --- a/src/ShippingRecorder.Client/ApiClient/VesselClient.cs +++ b/src/ShippingRecorder.Client/ApiClient/VesselClient.cs @@ -41,14 +41,14 @@ public async Task GetAsync(long id) } /// - /// Return the vessel with the specified IMO + /// Return the vessel with the specified identifier /// - /// + /// /// - public async Task GetAsync(string imo) + public async Task GetAsync(string identifier) { var baseRoute = Settings.ApiRoutes.First(r => r.Name == RouteKey).Route; - var route = $"{baseRoute}/imo/{imo}"; + var route = $"{baseRoute}/identifier/{identifier}"; var json = await SendDirectAsync(route, null, HttpMethod.Get); var vessel = Deserialize(json); return vessel; @@ -57,17 +57,19 @@ public async Task GetAsync(string imo) /// /// Add a new vessel to the database /// - /// + /// + /// /// /// /// /// /// - public async Task AddAsync(string imo, int? built, decimal? draught, int? length, int? beam) + public async Task AddAsync(string identifier, bool isIMO, int? built, decimal? draught, int? length, int? beam) { dynamic template = new { - IMO = imo, + Identifier = identifier, + IsIMO = isIMO, Built = built, Draught = draught, Length = length, @@ -85,18 +87,20 @@ public async Task AddAsync(string imo, int? built, decimal? draught, int /// Update an existing vessel /// /// - /// + /// + /// /// /// /// /// /// - public async Task UpdateAsync(long id, string imo, int? built, decimal? draught, int? length, int? beam) + public async Task UpdateAsync(long id, string identifier, bool isIMO, int? built, decimal? draught, int? length, int? beam) { dynamic template = new { Id = id, - IMO = imo, + Identifier = identifier, + IsIMO = isIMO, Built = built, Draught = draught, Length = length, diff --git a/src/ShippingRecorder.Client/Interfaces/ISightingClient.cs b/src/ShippingRecorder.Client/Interfaces/ISightingClient.cs index 4e7c8a2..716f9c7 100644 --- a/src/ShippingRecorder.Client/Interfaces/ISightingClient.cs +++ b/src/ShippingRecorder.Client/Interfaces/ISightingClient.cs @@ -11,7 +11,7 @@ public interface ISightingClient : IImporter, IExporter Task AddAsync(long locationId, long? voyageId, long vesselId, DateTime date, bool isMyVoyage); Task DeleteAsync(long id); Task> ListAsync(int pageNumber, int pageSize); - Task GetMostRecentVesselSightingAsync(string imo); + Task GetMostRecentVesselSightingAsync(string identifier); Task> ListSightingsByVesselAsync(long vesselId, int pageNumber, int pageSize); Task> ListSightingsByLocationAsync(long locationId, int pageNumber, int pageSize); Task> ListSightingsByDateAsync(DateTime start, DateTime end, int pageNumber, int pageSize); diff --git a/src/ShippingRecorder.Client/Interfaces/IVesselClient.cs b/src/ShippingRecorder.Client/Interfaces/IVesselClient.cs index a7c2bba..12c0d57 100644 --- a/src/ShippingRecorder.Client/Interfaces/IVesselClient.cs +++ b/src/ShippingRecorder.Client/Interfaces/IVesselClient.cs @@ -7,10 +7,10 @@ namespace ShippingRecorder.Client.Interfaces public interface IVesselClient : IImporter, IExporter { Task GetAsync(long id); - Task GetAsync(string imo); - Task AddAsync(string imo, int? built, decimal? draught, int? length, int? beam); + Task GetAsync(string identifier); + Task AddAsync(string identifier, bool isIMO, int? built, decimal? draught, int? length, int? beam); Task DeleteAsync(long id); Task> ListAsync(int pageNumber, int pageSize); - Task UpdateAsync(long id, string imo, int? built, decimal? draught, int? length, int? beam); + Task UpdateAsync(long id, string identifier, bool isIMO, int? built, decimal? draught, int? length, int? beam); } } \ No newline at end of file diff --git a/src/ShippingRecorder.Client/ShippingRecorder.Client.csproj b/src/ShippingRecorder.Client/ShippingRecorder.Client.csproj index ee0428a..68c826b 100644 --- a/src/ShippingRecorder.Client/ShippingRecorder.Client.csproj +++ b/src/ShippingRecorder.Client/ShippingRecorder.Client.csproj @@ -3,7 +3,7 @@ net9.0 ShippingRecorder.Client - 1.8.0.0 + 1.9.0.0 Dave Walker Copyright (c) Dave Walker 2025 Dave Walker @@ -15,7 +15,7 @@ https://github.com/davewalker5/ShippingRecorder MIT false - 1.8.0.0 + 1.9.0.0 NU1900 diff --git a/src/ShippingRecorder.Data/Migrations/20251207050413_InitialCreation.Designer.cs b/src/ShippingRecorder.Data/Migrations/20251207050413_InitialCreation.Designer.cs deleted file mode 100644 index 3774d2b..0000000 --- a/src/ShippingRecorder.Data/Migrations/20251207050413_InitialCreation.Designer.cs +++ /dev/null @@ -1,511 +0,0 @@ -// -using System; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using ShippingRecorder.Data; - -#nullable disable - -namespace ShippingRecorder.Data.Migrations -{ - [DbContext(typeof(ShippingRecorderDbContext))] - [Migration("20251207050413_InitialCreation")] - partial class InitialCreation - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder.HasAnnotation("ProductVersion", "9.0.7"); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Country", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasColumnName("id"); - - b.Property("Code") - .IsRequired() - .HasMaxLength(2) - .HasColumnType("TEXT") - .HasColumnName("code"); - - b.Property("Name") - .IsRequired() - .HasColumnType("TEXT") - .HasColumnName("name"); - - b.HasKey("Id"); - - b.HasIndex("Code") - .IsUnique(); - - b.HasIndex("Name") - .IsUnique(); - - b.ToTable("COUNTRY", null, t => - { - t.HasCheckConstraint("CK_Code_Characters", "code GLOB '[A-Z0-9]*'"); - - t.HasCheckConstraint("CK_Code_Length", "length(code) = 2"); - }); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Location", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasColumnName("id"); - - b.Property("Name") - .IsRequired() - .HasColumnType("TEXT") - .HasColumnName("name"); - - b.HasKey("Id"); - - b.HasIndex("Name") - .IsUnique(); - - b.ToTable("LOCATION", (string)null); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Operator", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasColumnName("id"); - - b.Property("Name") - .IsRequired() - .HasColumnType("TEXT") - .HasColumnName("name"); - - b.HasKey("Id"); - - b.HasIndex("Name") - .IsUnique(); - - b.ToTable("OPERATOR", (string)null); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Port", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasColumnName("id"); - - b.Property("Code") - .IsRequired() - .HasMaxLength(5) - .HasColumnType("TEXT") - .HasColumnName("code"); - - b.Property("CountryId") - .HasColumnType("INTEGER") - .HasColumnName("country_id"); - - b.Property("Name") - .IsRequired() - .HasColumnType("TEXT") - .HasColumnName("name"); - - b.HasKey("Id"); - - b.HasIndex("Code") - .IsUnique(); - - b.HasIndex("CountryId"); - - b.ToTable("PORT", null, t => - { - t.HasCheckConstraint("CK_Code_AlphaNumeric", "code GLOB '[A-Za-z0-9]*'"); - - t.HasCheckConstraint("CK_Code_Length", "length(code) = 5"); - }); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.RegistrationHistory", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasColumnName("id"); - - b.Property("Cabins") - .HasColumnType("INTEGER") - .HasColumnName("cabins"); - - b.Property("Callsign") - .IsRequired() - .HasColumnType("TEXT") - .HasColumnName("callsign"); - - b.Property("Crew") - .HasColumnType("INTEGER") - .HasColumnName("crew"); - - b.Property("Date") - .HasColumnType("DATETIME") - .HasColumnName("date"); - - b.Property("Decks") - .HasColumnType("INTEGER") - .HasColumnName("decks"); - - b.Property("FlagId") - .HasColumnType("INTEGER") - .HasColumnName("flag_id"); - - b.Property("IsActive") - .HasColumnType("INTEGER") - .HasColumnName("is_active"); - - b.Property("MMSI") - .IsRequired() - .HasMaxLength(9) - .HasColumnType("TEXT") - .HasColumnName("mmsi"); - - b.Property("Name") - .IsRequired() - .HasColumnType("TEXT") - .HasColumnName("name"); - - b.Property("OperatorId") - .HasColumnType("INTEGER") - .HasColumnName("operator_id"); - - b.Property("Passengers") - .HasColumnType("INTEGER") - .HasColumnName("passengers"); - - b.Property("Tonnage") - .HasColumnType("INTEGER") - .HasColumnName("tonnage"); - - b.Property("VesselId") - .HasColumnType("INTEGER") - .HasColumnName("vessel_id"); - - b.Property("VesselTypeId") - .HasColumnType("INTEGER") - .HasColumnName("vessel_type_id"); - - b.HasKey("Id"); - - b.HasIndex("FlagId"); - - b.HasIndex("OperatorId"); - - b.HasIndex("VesselId"); - - b.HasIndex("VesselTypeId"); - - b.ToTable("REGISTRATION_HISTORY", null, t => - { - t.HasCheckConstraint("CK_Callsign_Characters", "callsign GLOB '[A-Z0-9]*'"); - - t.HasCheckConstraint("CK_MMSI_Length", "length(mmsi) = 9"); - - t.HasCheckConstraint("CK_MMSI_Numeric", "mmsi GLOB '[0-9]*'"); - }); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Sighting", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasColumnName("id"); - - b.Property("Date") - .HasColumnType("DATETIME") - .HasColumnName("date"); - - b.Property("IsMyVoyage") - .HasColumnType("INTEGER") - .HasColumnName("is_my_voyage"); - - b.Property("LocationId") - .HasColumnType("INTEGER") - .HasColumnName("location_id"); - - b.Property("VesselId") - .HasColumnType("INTEGER") - .HasColumnName("vessel_id"); - - b.Property("VoyageId") - .HasColumnType("INTEGER") - .HasColumnName("voyage_id"); - - b.HasKey("Id"); - - b.HasIndex("LocationId"); - - b.HasIndex("VesselId"); - - b.HasIndex("VoyageId"); - - b.ToTable("SIGHTING", (string)null); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.User", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasColumnName("id"); - - b.Property("Password") - .IsRequired() - .HasColumnType("TEXT") - .HasColumnName("Password"); - - b.Property("UserName") - .IsRequired() - .HasColumnType("TEXT") - .HasColumnName("UserName"); - - b.HasKey("Id"); - - b.HasIndex("UserName") - .IsUnique(); - - b.ToTable("USER", (string)null); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Vessel", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasColumnName("id"); - - b.Property("Beam") - .HasColumnType("INTEGER") - .HasColumnName("beam"); - - b.Property("Built") - .HasColumnType("INTEGER") - .HasColumnName("built"); - - b.Property("Draught") - .HasColumnType("TEXT") - .HasColumnName("draught"); - - b.Property("IMO") - .IsRequired() - .HasMaxLength(7) - .HasColumnType("TEXT") - .HasColumnName("imo"); - - b.Property("Length") - .HasColumnType("INTEGER") - .HasColumnName("length"); - - b.HasKey("Id"); - - b.HasIndex("IMO") - .IsUnique(); - - b.ToTable("VESSEL", null, t => - { - t.HasCheckConstraint("CK_IMO_Length", "length(imo) = 7"); - - t.HasCheckConstraint("CK_IMO_Numeric", "imo GLOB '[0-9]*'"); - }); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.VesselType", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasColumnName("id"); - - b.Property("Name") - .IsRequired() - .HasColumnType("TEXT") - .HasColumnName("name"); - - b.HasKey("Id"); - - b.HasIndex("Name") - .IsUnique(); - - b.ToTable("VESSEL_TYPE", (string)null); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Voyage", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasColumnName("id"); - - b.Property("Number") - .IsRequired() - .HasColumnType("TEXT") - .HasColumnName("number"); - - b.Property("OperatorId") - .HasColumnType("INTEGER") - .HasColumnName("operator_id"); - - b.HasKey("Id"); - - b.HasIndex("OperatorId"); - - b.ToTable("VOYAGE", (string)null); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.VoyageEvent", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasColumnName("id"); - - b.Property("Date") - .HasColumnType("DATETIME") - .HasColumnName("arrival"); - - b.Property("EventType") - .HasColumnType("INTEGER") - .HasColumnName("event_type"); - - b.Property("PortId") - .HasColumnType("INTEGER") - .HasColumnName("port_id"); - - b.Property("VoyageId") - .HasColumnType("INTEGER") - .HasColumnName("voyage_id"); - - b.HasKey("Id"); - - b.HasIndex("PortId"); - - b.HasIndex("VoyageId"); - - b.ToTable("VOYAGE_EVENT", (string)null); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Port", b => - { - b.HasOne("ShippingRecorder.Entities.Db.Country", "Country") - .WithMany() - .HasForeignKey("CountryId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.Navigation("Country"); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.RegistrationHistory", b => - { - b.HasOne("ShippingRecorder.Entities.Db.Country", "Flag") - .WithMany() - .HasForeignKey("FlagId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.HasOne("ShippingRecorder.Entities.Db.Operator", "Operator") - .WithMany() - .HasForeignKey("OperatorId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.HasOne("ShippingRecorder.Entities.Db.Vessel", null) - .WithMany("RegistrationHistory") - .HasForeignKey("VesselId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.HasOne("ShippingRecorder.Entities.Db.VesselType", "VesselType") - .WithMany() - .HasForeignKey("VesselTypeId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.Navigation("Flag"); - - b.Navigation("Operator"); - - b.Navigation("VesselType"); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Sighting", b => - { - b.HasOne("ShippingRecorder.Entities.Db.Location", "Location") - .WithMany() - .HasForeignKey("LocationId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.HasOne("ShippingRecorder.Entities.Db.Vessel", "Vessel") - .WithMany() - .HasForeignKey("VesselId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.HasOne("ShippingRecorder.Entities.Db.Voyage", "Voyage") - .WithMany() - .HasForeignKey("VoyageId") - .OnDelete(DeleteBehavior.Restrict); - - b.Navigation("Location"); - - b.Navigation("Vessel"); - - b.Navigation("Voyage"); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Voyage", b => - { - b.HasOne("ShippingRecorder.Entities.Db.Operator", "Operator") - .WithMany() - .HasForeignKey("OperatorId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.Navigation("Operator"); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.VoyageEvent", b => - { - b.HasOne("ShippingRecorder.Entities.Db.Port", "Port") - .WithMany() - .HasForeignKey("PortId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.HasOne("ShippingRecorder.Entities.Db.Voyage", null) - .WithMany("Events") - .HasForeignKey("VoyageId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.Navigation("Port"); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Vessel", b => - { - b.Navigation("RegistrationHistory"); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Voyage", b => - { - b.Navigation("Events"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/src/ShippingRecorder.Data/Migrations/20260107141718_JobStatus.Designer.cs b/src/ShippingRecorder.Data/Migrations/20260107141718_JobStatus.Designer.cs deleted file mode 100644 index 65c8786..0000000 --- a/src/ShippingRecorder.Data/Migrations/20260107141718_JobStatus.Designer.cs +++ /dev/null @@ -1,544 +0,0 @@ -// -using System; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using ShippingRecorder.Data; - -#nullable disable - -namespace ShippingRecorder.Data.Migrations -{ - [DbContext(typeof(ShippingRecorderDbContext))] - [Migration("20260107141718_JobStatus")] - partial class JobStatus - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder.HasAnnotation("ProductVersion", "9.0.7"); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Country", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasColumnName("id"); - - b.Property("Code") - .IsRequired() - .HasMaxLength(2) - .HasColumnType("TEXT") - .HasColumnName("code"); - - b.Property("Name") - .IsRequired() - .HasColumnType("TEXT") - .HasColumnName("name"); - - b.HasKey("Id"); - - b.HasIndex("Code") - .IsUnique(); - - b.HasIndex("Name") - .IsUnique(); - - b.ToTable("COUNTRY", null, t => - { - t.HasCheckConstraint("CK_Code_Characters", "code GLOB '[A-Z0-9]*'"); - - t.HasCheckConstraint("CK_Code_Length", "length(code) = 2"); - }); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.JobStatus", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasColumnName("id"); - - b.Property("End") - .HasColumnType("DATETIME") - .HasColumnName("end"); - - b.Property("Error") - .HasColumnType("TEXT") - .HasColumnName("error"); - - b.Property("Name") - .IsRequired() - .HasColumnType("TEXT") - .HasColumnName("name"); - - b.Property("Parameters") - .HasColumnType("TEXT") - .HasColumnName("parameters"); - - b.Property("Start") - .HasColumnType("DATETIME") - .HasColumnName("start"); - - b.HasKey("Id"); - - b.ToTable("JOB_STATUS", (string)null); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Location", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasColumnName("id"); - - b.Property("Name") - .IsRequired() - .HasColumnType("TEXT") - .HasColumnName("name"); - - b.HasKey("Id"); - - b.HasIndex("Name") - .IsUnique(); - - b.ToTable("LOCATION", (string)null); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Operator", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasColumnName("id"); - - b.Property("Name") - .IsRequired() - .HasColumnType("TEXT") - .HasColumnName("name"); - - b.HasKey("Id"); - - b.HasIndex("Name") - .IsUnique(); - - b.ToTable("OPERATOR", (string)null); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Port", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasColumnName("id"); - - b.Property("Code") - .IsRequired() - .HasMaxLength(5) - .HasColumnType("TEXT") - .HasColumnName("code"); - - b.Property("CountryId") - .HasColumnType("INTEGER") - .HasColumnName("country_id"); - - b.Property("Name") - .IsRequired() - .HasColumnType("TEXT") - .HasColumnName("name"); - - b.HasKey("Id"); - - b.HasIndex("Code") - .IsUnique(); - - b.HasIndex("CountryId"); - - b.ToTable("PORT", null, t => - { - t.HasCheckConstraint("CK_Code_AlphaNumeric", "code GLOB '[A-Za-z0-9]*'"); - - t.HasCheckConstraint("CK_Code_Length", "length(code) = 5"); - }); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.RegistrationHistory", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasColumnName("id"); - - b.Property("Cabins") - .HasColumnType("INTEGER") - .HasColumnName("cabins"); - - b.Property("Callsign") - .IsRequired() - .HasColumnType("TEXT") - .HasColumnName("callsign"); - - b.Property("Crew") - .HasColumnType("INTEGER") - .HasColumnName("crew"); - - b.Property("Date") - .HasColumnType("DATETIME") - .HasColumnName("date"); - - b.Property("Decks") - .HasColumnType("INTEGER") - .HasColumnName("decks"); - - b.Property("FlagId") - .HasColumnType("INTEGER") - .HasColumnName("flag_id"); - - b.Property("IsActive") - .HasColumnType("INTEGER") - .HasColumnName("is_active"); - - b.Property("MMSI") - .IsRequired() - .HasMaxLength(9) - .HasColumnType("TEXT") - .HasColumnName("mmsi"); - - b.Property("Name") - .IsRequired() - .HasColumnType("TEXT") - .HasColumnName("name"); - - b.Property("OperatorId") - .HasColumnType("INTEGER") - .HasColumnName("operator_id"); - - b.Property("Passengers") - .HasColumnType("INTEGER") - .HasColumnName("passengers"); - - b.Property("Tonnage") - .HasColumnType("INTEGER") - .HasColumnName("tonnage"); - - b.Property("VesselId") - .HasColumnType("INTEGER") - .HasColumnName("vessel_id"); - - b.Property("VesselTypeId") - .HasColumnType("INTEGER") - .HasColumnName("vessel_type_id"); - - b.HasKey("Id"); - - b.HasIndex("FlagId"); - - b.HasIndex("OperatorId"); - - b.HasIndex("VesselId"); - - b.HasIndex("VesselTypeId"); - - b.ToTable("REGISTRATION_HISTORY", null, t => - { - t.HasCheckConstraint("CK_Callsign_Characters", "callsign GLOB '[A-Z0-9]*'"); - - t.HasCheckConstraint("CK_MMSI_Length", "length(mmsi) = 9"); - - t.HasCheckConstraint("CK_MMSI_Numeric", "mmsi GLOB '[0-9]*'"); - }); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Sighting", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasColumnName("id"); - - b.Property("Date") - .HasColumnType("DATETIME") - .HasColumnName("date"); - - b.Property("IsMyVoyage") - .HasColumnType("INTEGER") - .HasColumnName("is_my_voyage"); - - b.Property("LocationId") - .HasColumnType("INTEGER") - .HasColumnName("location_id"); - - b.Property("VesselId") - .HasColumnType("INTEGER") - .HasColumnName("vessel_id"); - - b.Property("VoyageId") - .HasColumnType("INTEGER") - .HasColumnName("voyage_id"); - - b.HasKey("Id"); - - b.HasIndex("LocationId"); - - b.HasIndex("VesselId"); - - b.HasIndex("VoyageId"); - - b.ToTable("SIGHTING", (string)null); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.User", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasColumnName("id"); - - b.Property("Password") - .IsRequired() - .HasColumnType("TEXT") - .HasColumnName("Password"); - - b.Property("UserName") - .IsRequired() - .HasColumnType("TEXT") - .HasColumnName("UserName"); - - b.HasKey("Id"); - - b.HasIndex("UserName") - .IsUnique(); - - b.ToTable("USER", (string)null); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Vessel", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasColumnName("id"); - - b.Property("Beam") - .HasColumnType("INTEGER") - .HasColumnName("beam"); - - b.Property("Built") - .HasColumnType("INTEGER") - .HasColumnName("built"); - - b.Property("Draught") - .HasColumnType("TEXT") - .HasColumnName("draught"); - - b.Property("IMO") - .IsRequired() - .HasMaxLength(7) - .HasColumnType("TEXT") - .HasColumnName("imo"); - - b.Property("Length") - .HasColumnType("INTEGER") - .HasColumnName("length"); - - b.HasKey("Id"); - - b.HasIndex("IMO") - .IsUnique(); - - b.ToTable("VESSEL", null, t => - { - t.HasCheckConstraint("CK_IMO_Length", "length(imo) = 7"); - - t.HasCheckConstraint("CK_IMO_Numeric", "imo GLOB '[0-9]*'"); - }); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.VesselType", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasColumnName("id"); - - b.Property("Name") - .IsRequired() - .HasColumnType("TEXT") - .HasColumnName("name"); - - b.HasKey("Id"); - - b.HasIndex("Name") - .IsUnique(); - - b.ToTable("VESSEL_TYPE", (string)null); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Voyage", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasColumnName("id"); - - b.Property("Number") - .IsRequired() - .HasColumnType("TEXT") - .HasColumnName("number"); - - b.Property("OperatorId") - .HasColumnType("INTEGER") - .HasColumnName("operator_id"); - - b.HasKey("Id"); - - b.HasIndex("OperatorId"); - - b.ToTable("VOYAGE", (string)null); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.VoyageEvent", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasColumnName("id"); - - b.Property("Date") - .HasColumnType("DATETIME") - .HasColumnName("arrival"); - - b.Property("EventType") - .HasColumnType("INTEGER") - .HasColumnName("event_type"); - - b.Property("PortId") - .HasColumnType("INTEGER") - .HasColumnName("port_id"); - - b.Property("VoyageId") - .HasColumnType("INTEGER") - .HasColumnName("voyage_id"); - - b.HasKey("Id"); - - b.HasIndex("PortId"); - - b.HasIndex("VoyageId"); - - b.ToTable("VOYAGE_EVENT", (string)null); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Port", b => - { - b.HasOne("ShippingRecorder.Entities.Db.Country", "Country") - .WithMany() - .HasForeignKey("CountryId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.Navigation("Country"); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.RegistrationHistory", b => - { - b.HasOne("ShippingRecorder.Entities.Db.Country", "Flag") - .WithMany() - .HasForeignKey("FlagId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.HasOne("ShippingRecorder.Entities.Db.Operator", "Operator") - .WithMany() - .HasForeignKey("OperatorId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.HasOne("ShippingRecorder.Entities.Db.Vessel", null) - .WithMany("RegistrationHistory") - .HasForeignKey("VesselId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.HasOne("ShippingRecorder.Entities.Db.VesselType", "VesselType") - .WithMany() - .HasForeignKey("VesselTypeId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.Navigation("Flag"); - - b.Navigation("Operator"); - - b.Navigation("VesselType"); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Sighting", b => - { - b.HasOne("ShippingRecorder.Entities.Db.Location", "Location") - .WithMany() - .HasForeignKey("LocationId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.HasOne("ShippingRecorder.Entities.Db.Vessel", "Vessel") - .WithMany() - .HasForeignKey("VesselId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.HasOne("ShippingRecorder.Entities.Db.Voyage", "Voyage") - .WithMany() - .HasForeignKey("VoyageId") - .OnDelete(DeleteBehavior.Restrict); - - b.Navigation("Location"); - - b.Navigation("Vessel"); - - b.Navigation("Voyage"); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Voyage", b => - { - b.HasOne("ShippingRecorder.Entities.Db.Operator", "Operator") - .WithMany() - .HasForeignKey("OperatorId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.Navigation("Operator"); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.VoyageEvent", b => - { - b.HasOne("ShippingRecorder.Entities.Db.Port", "Port") - .WithMany() - .HasForeignKey("PortId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.HasOne("ShippingRecorder.Entities.Db.Voyage", null) - .WithMany("Events") - .HasForeignKey("VoyageId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.Navigation("Port"); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Vessel", b => - { - b.Navigation("RegistrationHistory"); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Voyage", b => - { - b.Navigation("Events"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/src/ShippingRecorder.Data/Migrations/20260107141718_JobStatus.cs b/src/ShippingRecorder.Data/Migrations/20260107141718_JobStatus.cs deleted file mode 100644 index d22d4d5..0000000 --- a/src/ShippingRecorder.Data/Migrations/20260107141718_JobStatus.cs +++ /dev/null @@ -1,41 +0,0 @@ -using System; -using System.Diagnostics.CodeAnalysis; -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -namespace ShippingRecorder.Data.Migrations -{ - /// - [ExcludeFromCodeCoverage] - public partial class JobStatus : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.CreateTable( - name: "JOB_STATUS", - columns: table => new - { - id = table.Column(type: "INTEGER", nullable: false) - .Annotation("Sqlite:Autoincrement", true), - name = table.Column(type: "TEXT", nullable: false), - parameters = table.Column(type: "TEXT", nullable: true), - start = table.Column(type: "DATETIME", nullable: false), - end = table.Column(type: "DATETIME", nullable: true), - error = table.Column(type: "TEXT", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_JOB_STATUS", x => x.id); - }); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropTable( - name: "JOB_STATUS"); - } - } -} diff --git a/src/ShippingRecorder.Data/Migrations/20260108161616_LocationStatistics.Designer.cs b/src/ShippingRecorder.Data/Migrations/20260108161616_LocationStatistics.Designer.cs deleted file mode 100644 index 9523174..0000000 --- a/src/ShippingRecorder.Data/Migrations/20260108161616_LocationStatistics.Designer.cs +++ /dev/null @@ -1,558 +0,0 @@ -// -using System; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using ShippingRecorder.Data; - -#nullable disable - -namespace ShippingRecorder.Data.Migrations -{ - [DbContext(typeof(ShippingRecorderDbContext))] - [Migration("20260108161616_LocationStatistics")] - partial class LocationStatistics - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder.HasAnnotation("ProductVersion", "9.0.7"); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Country", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasColumnName("id"); - - b.Property("Code") - .IsRequired() - .HasMaxLength(2) - .HasColumnType("TEXT") - .HasColumnName("code"); - - b.Property("Name") - .IsRequired() - .HasColumnType("TEXT") - .HasColumnName("name"); - - b.HasKey("Id"); - - b.HasIndex("Code") - .IsUnique(); - - b.HasIndex("Name") - .IsUnique(); - - b.ToTable("COUNTRY", null, t => - { - t.HasCheckConstraint("CK_Code_Characters", "code GLOB '[A-Z0-9]*'"); - - t.HasCheckConstraint("CK_Code_Length", "length(code) = 2"); - }); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.JobStatus", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasColumnName("id"); - - b.Property("End") - .HasColumnType("DATETIME") - .HasColumnName("end"); - - b.Property("Error") - .HasColumnType("TEXT") - .HasColumnName("error"); - - b.Property("Name") - .IsRequired() - .HasColumnType("TEXT") - .HasColumnName("name"); - - b.Property("Parameters") - .HasColumnType("TEXT") - .HasColumnName("parameters"); - - b.Property("Start") - .HasColumnType("DATETIME") - .HasColumnName("start"); - - b.HasKey("Id"); - - b.ToTable("JOB_STATUS", (string)null); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Location", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasColumnName("id"); - - b.Property("Name") - .IsRequired() - .HasColumnType("TEXT") - .HasColumnName("name"); - - b.HasKey("Id"); - - b.HasIndex("Name") - .IsUnique(); - - b.ToTable("LOCATION", (string)null); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Operator", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasColumnName("id"); - - b.Property("Name") - .IsRequired() - .HasColumnType("TEXT") - .HasColumnName("name"); - - b.HasKey("Id"); - - b.HasIndex("Name") - .IsUnique(); - - b.ToTable("OPERATOR", (string)null); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Port", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasColumnName("id"); - - b.Property("Code") - .IsRequired() - .HasMaxLength(5) - .HasColumnType("TEXT") - .HasColumnName("code"); - - b.Property("CountryId") - .HasColumnType("INTEGER") - .HasColumnName("country_id"); - - b.Property("Name") - .IsRequired() - .HasColumnType("TEXT") - .HasColumnName("name"); - - b.HasKey("Id"); - - b.HasIndex("Code") - .IsUnique(); - - b.HasIndex("CountryId"); - - b.ToTable("PORT", null, t => - { - t.HasCheckConstraint("CK_Code_AlphaNumeric", "code GLOB '[A-Za-z0-9]*'"); - - t.HasCheckConstraint("CK_Code_Length", "length(code) = 5"); - }); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.RegistrationHistory", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasColumnName("id"); - - b.Property("Cabins") - .HasColumnType("INTEGER") - .HasColumnName("cabins"); - - b.Property("Callsign") - .IsRequired() - .HasColumnType("TEXT") - .HasColumnName("callsign"); - - b.Property("Crew") - .HasColumnType("INTEGER") - .HasColumnName("crew"); - - b.Property("Date") - .HasColumnType("DATETIME") - .HasColumnName("date"); - - b.Property("Decks") - .HasColumnType("INTEGER") - .HasColumnName("decks"); - - b.Property("FlagId") - .HasColumnType("INTEGER") - .HasColumnName("flag_id"); - - b.Property("IsActive") - .HasColumnType("INTEGER") - .HasColumnName("is_active"); - - b.Property("MMSI") - .IsRequired() - .HasMaxLength(9) - .HasColumnType("TEXT") - .HasColumnName("mmsi"); - - b.Property("Name") - .IsRequired() - .HasColumnType("TEXT") - .HasColumnName("name"); - - b.Property("OperatorId") - .HasColumnType("INTEGER") - .HasColumnName("operator_id"); - - b.Property("Passengers") - .HasColumnType("INTEGER") - .HasColumnName("passengers"); - - b.Property("Tonnage") - .HasColumnType("INTEGER") - .HasColumnName("tonnage"); - - b.Property("VesselId") - .HasColumnType("INTEGER") - .HasColumnName("vessel_id"); - - b.Property("VesselTypeId") - .HasColumnType("INTEGER") - .HasColumnName("vessel_type_id"); - - b.HasKey("Id"); - - b.HasIndex("FlagId"); - - b.HasIndex("OperatorId"); - - b.HasIndex("VesselId"); - - b.HasIndex("VesselTypeId"); - - b.ToTable("REGISTRATION_HISTORY", null, t => - { - t.HasCheckConstraint("CK_Callsign_Characters", "callsign GLOB '[A-Z0-9]*'"); - - t.HasCheckConstraint("CK_MMSI_Length", "length(mmsi) = 9"); - - t.HasCheckConstraint("CK_MMSI_Numeric", "mmsi GLOB '[0-9]*'"); - }); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Sighting", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasColumnName("id"); - - b.Property("Date") - .HasColumnType("DATETIME") - .HasColumnName("date"); - - b.Property("IsMyVoyage") - .HasColumnType("INTEGER") - .HasColumnName("is_my_voyage"); - - b.Property("LocationId") - .HasColumnType("INTEGER") - .HasColumnName("location_id"); - - b.Property("VesselId") - .HasColumnType("INTEGER") - .HasColumnName("vessel_id"); - - b.Property("VoyageId") - .HasColumnType("INTEGER") - .HasColumnName("voyage_id"); - - b.HasKey("Id"); - - b.HasIndex("LocationId"); - - b.HasIndex("VesselId"); - - b.HasIndex("VoyageId"); - - b.ToTable("SIGHTING", (string)null); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.User", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasColumnName("id"); - - b.Property("Password") - .IsRequired() - .HasColumnType("TEXT") - .HasColumnName("Password"); - - b.Property("UserName") - .IsRequired() - .HasColumnType("TEXT") - .HasColumnName("UserName"); - - b.HasKey("Id"); - - b.HasIndex("UserName") - .IsUnique(); - - b.ToTable("USER", (string)null); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Vessel", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasColumnName("id"); - - b.Property("Beam") - .HasColumnType("INTEGER") - .HasColumnName("beam"); - - b.Property("Built") - .HasColumnType("INTEGER") - .HasColumnName("built"); - - b.Property("Draught") - .HasColumnType("TEXT") - .HasColumnName("draught"); - - b.Property("IMO") - .IsRequired() - .HasMaxLength(7) - .HasColumnType("TEXT") - .HasColumnName("imo"); - - b.Property("Length") - .HasColumnType("INTEGER") - .HasColumnName("length"); - - b.HasKey("Id"); - - b.HasIndex("IMO") - .IsUnique(); - - b.ToTable("VESSEL", null, t => - { - t.HasCheckConstraint("CK_IMO_Length", "length(imo) = 7"); - - t.HasCheckConstraint("CK_IMO_Numeric", "imo GLOB '[0-9]*'"); - }); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.VesselType", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasColumnName("id"); - - b.Property("Name") - .IsRequired() - .HasColumnType("TEXT") - .HasColumnName("name"); - - b.HasKey("Id"); - - b.HasIndex("Name") - .IsUnique(); - - b.ToTable("VESSEL_TYPE", (string)null); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Voyage", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasColumnName("id"); - - b.Property("Number") - .IsRequired() - .HasColumnType("TEXT") - .HasColumnName("number"); - - b.Property("OperatorId") - .HasColumnType("INTEGER") - .HasColumnName("operator_id"); - - b.HasKey("Id"); - - b.HasIndex("OperatorId"); - - b.ToTable("VOYAGE", (string)null); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.VoyageEvent", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasColumnName("id"); - - b.Property("Date") - .HasColumnType("DATETIME") - .HasColumnName("arrival"); - - b.Property("EventType") - .HasColumnType("INTEGER") - .HasColumnName("event_type"); - - b.Property("PortId") - .HasColumnType("INTEGER") - .HasColumnName("port_id"); - - b.Property("VoyageId") - .HasColumnType("INTEGER") - .HasColumnName("voyage_id"); - - b.HasKey("Id"); - - b.HasIndex("PortId"); - - b.HasIndex("VoyageId"); - - b.ToTable("VOYAGE_EVENT", (string)null); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Reporting.LocationStatistics", b => - { - b.Property("Name") - .HasColumnType("TEXT"); - - b.Property("Sightings") - .HasColumnType("INTEGER"); - - b.Property("Vessels") - .HasColumnType("INTEGER"); - - b.ToTable("LocationStatistics"); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Port", b => - { - b.HasOne("ShippingRecorder.Entities.Db.Country", "Country") - .WithMany() - .HasForeignKey("CountryId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.Navigation("Country"); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.RegistrationHistory", b => - { - b.HasOne("ShippingRecorder.Entities.Db.Country", "Flag") - .WithMany() - .HasForeignKey("FlagId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.HasOne("ShippingRecorder.Entities.Db.Operator", "Operator") - .WithMany() - .HasForeignKey("OperatorId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.HasOne("ShippingRecorder.Entities.Db.Vessel", null) - .WithMany("RegistrationHistory") - .HasForeignKey("VesselId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.HasOne("ShippingRecorder.Entities.Db.VesselType", "VesselType") - .WithMany() - .HasForeignKey("VesselTypeId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.Navigation("Flag"); - - b.Navigation("Operator"); - - b.Navigation("VesselType"); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Sighting", b => - { - b.HasOne("ShippingRecorder.Entities.Db.Location", "Location") - .WithMany() - .HasForeignKey("LocationId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.HasOne("ShippingRecorder.Entities.Db.Vessel", "Vessel") - .WithMany() - .HasForeignKey("VesselId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.HasOne("ShippingRecorder.Entities.Db.Voyage", "Voyage") - .WithMany() - .HasForeignKey("VoyageId") - .OnDelete(DeleteBehavior.Restrict); - - b.Navigation("Location"); - - b.Navigation("Vessel"); - - b.Navigation("Voyage"); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Voyage", b => - { - b.HasOne("ShippingRecorder.Entities.Db.Operator", "Operator") - .WithMany() - .HasForeignKey("OperatorId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.Navigation("Operator"); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.VoyageEvent", b => - { - b.HasOne("ShippingRecorder.Entities.Db.Port", "Port") - .WithMany() - .HasForeignKey("PortId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.HasOne("ShippingRecorder.Entities.Db.Voyage", null) - .WithMany("Events") - .HasForeignKey("VoyageId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.Navigation("Port"); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Vessel", b => - { - b.Navigation("RegistrationHistory"); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Voyage", b => - { - b.Navigation("Events"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/src/ShippingRecorder.Data/Migrations/20260108161616_LocationStatistics.cs b/src/ShippingRecorder.Data/Migrations/20260108161616_LocationStatistics.cs deleted file mode 100644 index 718bae0..0000000 --- a/src/ShippingRecorder.Data/Migrations/20260108161616_LocationStatistics.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System.Diagnostics.CodeAnalysis; -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -namespace ShippingRecorder.Data.Migrations -{ - /// - [ExcludeFromCodeCoverage] - public partial class LocationStatistics : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.CreateTable( - name: "LocationStatistics", - columns: table => new - { - Name = table.Column(type: "TEXT", nullable: true), - Sightings = table.Column(type: "INTEGER", nullable: true), - Vessels = table.Column(type: "INTEGER", nullable: true) - }, - constraints: table => - { - }); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropTable( - name: "LocationStatistics"); - } - } -} diff --git a/src/ShippingRecorder.Data/Migrations/20260108165158_SightingsByMonth.Designer.cs b/src/ShippingRecorder.Data/Migrations/20260108165158_SightingsByMonth.Designer.cs deleted file mode 100644 index 3966579..0000000 --- a/src/ShippingRecorder.Data/Migrations/20260108165158_SightingsByMonth.Designer.cs +++ /dev/null @@ -1,578 +0,0 @@ -// -using System; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using ShippingRecorder.Data; - -#nullable disable - -namespace ShippingRecorder.Data.Migrations -{ - [DbContext(typeof(ShippingRecorderDbContext))] - [Migration("20260108165158_SightingsByMonth")] - partial class SightingsByMonth - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder.HasAnnotation("ProductVersion", "9.0.7"); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Country", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasColumnName("id"); - - b.Property("Code") - .IsRequired() - .HasMaxLength(2) - .HasColumnType("TEXT") - .HasColumnName("code"); - - b.Property("Name") - .IsRequired() - .HasColumnType("TEXT") - .HasColumnName("name"); - - b.HasKey("Id"); - - b.HasIndex("Code") - .IsUnique(); - - b.HasIndex("Name") - .IsUnique(); - - b.ToTable("COUNTRY", null, t => - { - t.HasCheckConstraint("CK_Code_Characters", "code GLOB '[A-Z0-9]*'"); - - t.HasCheckConstraint("CK_Code_Length", "length(code) = 2"); - }); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.JobStatus", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasColumnName("id"); - - b.Property("End") - .HasColumnType("DATETIME") - .HasColumnName("end"); - - b.Property("Error") - .HasColumnType("TEXT") - .HasColumnName("error"); - - b.Property("Name") - .IsRequired() - .HasColumnType("TEXT") - .HasColumnName("name"); - - b.Property("Parameters") - .HasColumnType("TEXT") - .HasColumnName("parameters"); - - b.Property("Start") - .HasColumnType("DATETIME") - .HasColumnName("start"); - - b.HasKey("Id"); - - b.ToTable("JOB_STATUS", (string)null); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Location", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasColumnName("id"); - - b.Property("Name") - .IsRequired() - .HasColumnType("TEXT") - .HasColumnName("name"); - - b.HasKey("Id"); - - b.HasIndex("Name") - .IsUnique(); - - b.ToTable("LOCATION", (string)null); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Operator", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasColumnName("id"); - - b.Property("Name") - .IsRequired() - .HasColumnType("TEXT") - .HasColumnName("name"); - - b.HasKey("Id"); - - b.HasIndex("Name") - .IsUnique(); - - b.ToTable("OPERATOR", (string)null); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Port", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasColumnName("id"); - - b.Property("Code") - .IsRequired() - .HasMaxLength(5) - .HasColumnType("TEXT") - .HasColumnName("code"); - - b.Property("CountryId") - .HasColumnType("INTEGER") - .HasColumnName("country_id"); - - b.Property("Name") - .IsRequired() - .HasColumnType("TEXT") - .HasColumnName("name"); - - b.HasKey("Id"); - - b.HasIndex("Code") - .IsUnique(); - - b.HasIndex("CountryId"); - - b.ToTable("PORT", null, t => - { - t.HasCheckConstraint("CK_Code_AlphaNumeric", "code GLOB '[A-Za-z0-9]*'"); - - t.HasCheckConstraint("CK_Code_Length", "length(code) = 5"); - }); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.RegistrationHistory", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasColumnName("id"); - - b.Property("Cabins") - .HasColumnType("INTEGER") - .HasColumnName("cabins"); - - b.Property("Callsign") - .IsRequired() - .HasColumnType("TEXT") - .HasColumnName("callsign"); - - b.Property("Crew") - .HasColumnType("INTEGER") - .HasColumnName("crew"); - - b.Property("Date") - .HasColumnType("DATETIME") - .HasColumnName("date"); - - b.Property("Decks") - .HasColumnType("INTEGER") - .HasColumnName("decks"); - - b.Property("FlagId") - .HasColumnType("INTEGER") - .HasColumnName("flag_id"); - - b.Property("IsActive") - .HasColumnType("INTEGER") - .HasColumnName("is_active"); - - b.Property("MMSI") - .IsRequired() - .HasMaxLength(9) - .HasColumnType("TEXT") - .HasColumnName("mmsi"); - - b.Property("Name") - .IsRequired() - .HasColumnType("TEXT") - .HasColumnName("name"); - - b.Property("OperatorId") - .HasColumnType("INTEGER") - .HasColumnName("operator_id"); - - b.Property("Passengers") - .HasColumnType("INTEGER") - .HasColumnName("passengers"); - - b.Property("Tonnage") - .HasColumnType("INTEGER") - .HasColumnName("tonnage"); - - b.Property("VesselId") - .HasColumnType("INTEGER") - .HasColumnName("vessel_id"); - - b.Property("VesselTypeId") - .HasColumnType("INTEGER") - .HasColumnName("vessel_type_id"); - - b.HasKey("Id"); - - b.HasIndex("FlagId"); - - b.HasIndex("OperatorId"); - - b.HasIndex("VesselId"); - - b.HasIndex("VesselTypeId"); - - b.ToTable("REGISTRATION_HISTORY", null, t => - { - t.HasCheckConstraint("CK_Callsign_Characters", "callsign GLOB '[A-Z0-9]*'"); - - t.HasCheckConstraint("CK_MMSI_Length", "length(mmsi) = 9"); - - t.HasCheckConstraint("CK_MMSI_Numeric", "mmsi GLOB '[0-9]*'"); - }); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Sighting", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasColumnName("id"); - - b.Property("Date") - .HasColumnType("DATETIME") - .HasColumnName("date"); - - b.Property("IsMyVoyage") - .HasColumnType("INTEGER") - .HasColumnName("is_my_voyage"); - - b.Property("LocationId") - .HasColumnType("INTEGER") - .HasColumnName("location_id"); - - b.Property("VesselId") - .HasColumnType("INTEGER") - .HasColumnName("vessel_id"); - - b.Property("VoyageId") - .HasColumnType("INTEGER") - .HasColumnName("voyage_id"); - - b.HasKey("Id"); - - b.HasIndex("LocationId"); - - b.HasIndex("VesselId"); - - b.HasIndex("VoyageId"); - - b.ToTable("SIGHTING", (string)null); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.User", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasColumnName("id"); - - b.Property("Password") - .IsRequired() - .HasColumnType("TEXT") - .HasColumnName("Password"); - - b.Property("UserName") - .IsRequired() - .HasColumnType("TEXT") - .HasColumnName("UserName"); - - b.HasKey("Id"); - - b.HasIndex("UserName") - .IsUnique(); - - b.ToTable("USER", (string)null); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Vessel", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasColumnName("id"); - - b.Property("Beam") - .HasColumnType("INTEGER") - .HasColumnName("beam"); - - b.Property("Built") - .HasColumnType("INTEGER") - .HasColumnName("built"); - - b.Property("Draught") - .HasColumnType("TEXT") - .HasColumnName("draught"); - - b.Property("IMO") - .IsRequired() - .HasMaxLength(7) - .HasColumnType("TEXT") - .HasColumnName("imo"); - - b.Property("Length") - .HasColumnType("INTEGER") - .HasColumnName("length"); - - b.HasKey("Id"); - - b.HasIndex("IMO") - .IsUnique(); - - b.ToTable("VESSEL", null, t => - { - t.HasCheckConstraint("CK_IMO_Length", "length(imo) = 7"); - - t.HasCheckConstraint("CK_IMO_Numeric", "imo GLOB '[0-9]*'"); - }); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.VesselType", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasColumnName("id"); - - b.Property("Name") - .IsRequired() - .HasColumnType("TEXT") - .HasColumnName("name"); - - b.HasKey("Id"); - - b.HasIndex("Name") - .IsUnique(); - - b.ToTable("VESSEL_TYPE", (string)null); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Voyage", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasColumnName("id"); - - b.Property("Number") - .IsRequired() - .HasColumnType("TEXT") - .HasColumnName("number"); - - b.Property("OperatorId") - .HasColumnType("INTEGER") - .HasColumnName("operator_id"); - - b.HasKey("Id"); - - b.HasIndex("OperatorId"); - - b.ToTable("VOYAGE", (string)null); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.VoyageEvent", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasColumnName("id"); - - b.Property("Date") - .HasColumnType("DATETIME") - .HasColumnName("arrival"); - - b.Property("EventType") - .HasColumnType("INTEGER") - .HasColumnName("event_type"); - - b.Property("PortId") - .HasColumnType("INTEGER") - .HasColumnName("port_id"); - - b.Property("VoyageId") - .HasColumnType("INTEGER") - .HasColumnName("voyage_id"); - - b.HasKey("Id"); - - b.HasIndex("PortId"); - - b.HasIndex("VoyageId"); - - b.ToTable("VOYAGE_EVENT", (string)null); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Reporting.LocationStatistics", b => - { - b.Property("Name") - .HasColumnType("TEXT"); - - b.Property("Sightings") - .HasColumnType("INTEGER"); - - b.Property("Vessels") - .HasColumnType("INTEGER"); - - b.ToTable("LocationStatistics"); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Reporting.SightingsByMonth", b => - { - b.Property("Locations") - .HasColumnType("INTEGER"); - - b.Property("Month") - .HasColumnType("INTEGER"); - - b.Property("Sightings") - .HasColumnType("INTEGER"); - - b.Property("Vessels") - .HasColumnType("INTEGER"); - - b.Property("Year") - .HasColumnType("INTEGER"); - - b.ToTable("SightingsByMonth"); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Port", b => - { - b.HasOne("ShippingRecorder.Entities.Db.Country", "Country") - .WithMany() - .HasForeignKey("CountryId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.Navigation("Country"); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.RegistrationHistory", b => - { - b.HasOne("ShippingRecorder.Entities.Db.Country", "Flag") - .WithMany() - .HasForeignKey("FlagId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.HasOne("ShippingRecorder.Entities.Db.Operator", "Operator") - .WithMany() - .HasForeignKey("OperatorId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.HasOne("ShippingRecorder.Entities.Db.Vessel", null) - .WithMany("RegistrationHistory") - .HasForeignKey("VesselId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.HasOne("ShippingRecorder.Entities.Db.VesselType", "VesselType") - .WithMany() - .HasForeignKey("VesselTypeId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.Navigation("Flag"); - - b.Navigation("Operator"); - - b.Navigation("VesselType"); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Sighting", b => - { - b.HasOne("ShippingRecorder.Entities.Db.Location", "Location") - .WithMany() - .HasForeignKey("LocationId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.HasOne("ShippingRecorder.Entities.Db.Vessel", "Vessel") - .WithMany() - .HasForeignKey("VesselId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.HasOne("ShippingRecorder.Entities.Db.Voyage", "Voyage") - .WithMany() - .HasForeignKey("VoyageId") - .OnDelete(DeleteBehavior.Restrict); - - b.Navigation("Location"); - - b.Navigation("Vessel"); - - b.Navigation("Voyage"); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Voyage", b => - { - b.HasOne("ShippingRecorder.Entities.Db.Operator", "Operator") - .WithMany() - .HasForeignKey("OperatorId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.Navigation("Operator"); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.VoyageEvent", b => - { - b.HasOne("ShippingRecorder.Entities.Db.Port", "Port") - .WithMany() - .HasForeignKey("PortId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.HasOne("ShippingRecorder.Entities.Db.Voyage", null) - .WithMany("Events") - .HasForeignKey("VoyageId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.Navigation("Port"); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Vessel", b => - { - b.Navigation("RegistrationHistory"); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Voyage", b => - { - b.Navigation("Events"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/src/ShippingRecorder.Data/Migrations/20260108165158_SightingsByMonth.cs b/src/ShippingRecorder.Data/Migrations/20260108165158_SightingsByMonth.cs deleted file mode 100644 index 1fcba83..0000000 --- a/src/ShippingRecorder.Data/Migrations/20260108165158_SightingsByMonth.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System.Diagnostics.CodeAnalysis; -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -namespace ShippingRecorder.Data.Migrations -{ - /// - [ExcludeFromCodeCoverage] - public partial class SightingsByMonth : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.CreateTable( - name: "SightingsByMonth", - columns: table => new - { - Year = table.Column(type: "INTEGER", nullable: false), - Month = table.Column(type: "INTEGER", nullable: false), - Sightings = table.Column(type: "INTEGER", nullable: true), - Locations = table.Column(type: "INTEGER", nullable: true), - Vessels = table.Column(type: "INTEGER", nullable: true) - }, - constraints: table => - { - }); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropTable( - name: "SightingsByMonth"); - } - } -} diff --git a/src/ShippingRecorder.Data/Migrations/20260108174600_MyVoyages.Designer.cs b/src/ShippingRecorder.Data/Migrations/20260108174600_MyVoyages.Designer.cs deleted file mode 100644 index 38c4e29..0000000 --- a/src/ShippingRecorder.Data/Migrations/20260108174600_MyVoyages.Designer.cs +++ /dev/null @@ -1,598 +0,0 @@ -// -using System; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using ShippingRecorder.Data; - -#nullable disable - -namespace ShippingRecorder.Data.Migrations -{ - [DbContext(typeof(ShippingRecorderDbContext))] - [Migration("20260108174600_MyVoyages")] - partial class MyVoyages - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder.HasAnnotation("ProductVersion", "9.0.7"); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Country", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasColumnName("id"); - - b.Property("Code") - .IsRequired() - .HasMaxLength(2) - .HasColumnType("TEXT") - .HasColumnName("code"); - - b.Property("Name") - .IsRequired() - .HasColumnType("TEXT") - .HasColumnName("name"); - - b.HasKey("Id"); - - b.HasIndex("Code") - .IsUnique(); - - b.HasIndex("Name") - .IsUnique(); - - b.ToTable("COUNTRY", null, t => - { - t.HasCheckConstraint("CK_Code_Characters", "code GLOB '[A-Z0-9]*'"); - - t.HasCheckConstraint("CK_Code_Length", "length(code) = 2"); - }); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.JobStatus", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasColumnName("id"); - - b.Property("End") - .HasColumnType("DATETIME") - .HasColumnName("end"); - - b.Property("Error") - .HasColumnType("TEXT") - .HasColumnName("error"); - - b.Property("Name") - .IsRequired() - .HasColumnType("TEXT") - .HasColumnName("name"); - - b.Property("Parameters") - .HasColumnType("TEXT") - .HasColumnName("parameters"); - - b.Property("Start") - .HasColumnType("DATETIME") - .HasColumnName("start"); - - b.HasKey("Id"); - - b.ToTable("JOB_STATUS", (string)null); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Location", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasColumnName("id"); - - b.Property("Name") - .IsRequired() - .HasColumnType("TEXT") - .HasColumnName("name"); - - b.HasKey("Id"); - - b.HasIndex("Name") - .IsUnique(); - - b.ToTable("LOCATION", (string)null); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Operator", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasColumnName("id"); - - b.Property("Name") - .IsRequired() - .HasColumnType("TEXT") - .HasColumnName("name"); - - b.HasKey("Id"); - - b.HasIndex("Name") - .IsUnique(); - - b.ToTable("OPERATOR", (string)null); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Port", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasColumnName("id"); - - b.Property("Code") - .IsRequired() - .HasMaxLength(5) - .HasColumnType("TEXT") - .HasColumnName("code"); - - b.Property("CountryId") - .HasColumnType("INTEGER") - .HasColumnName("country_id"); - - b.Property("Name") - .IsRequired() - .HasColumnType("TEXT") - .HasColumnName("name"); - - b.HasKey("Id"); - - b.HasIndex("Code") - .IsUnique(); - - b.HasIndex("CountryId"); - - b.ToTable("PORT", null, t => - { - t.HasCheckConstraint("CK_Code_AlphaNumeric", "code GLOB '[A-Za-z0-9]*'"); - - t.HasCheckConstraint("CK_Code_Length", "length(code) = 5"); - }); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.RegistrationHistory", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasColumnName("id"); - - b.Property("Cabins") - .HasColumnType("INTEGER") - .HasColumnName("cabins"); - - b.Property("Callsign") - .IsRequired() - .HasColumnType("TEXT") - .HasColumnName("callsign"); - - b.Property("Crew") - .HasColumnType("INTEGER") - .HasColumnName("crew"); - - b.Property("Date") - .HasColumnType("DATETIME") - .HasColumnName("date"); - - b.Property("Decks") - .HasColumnType("INTEGER") - .HasColumnName("decks"); - - b.Property("FlagId") - .HasColumnType("INTEGER") - .HasColumnName("flag_id"); - - b.Property("IsActive") - .HasColumnType("INTEGER") - .HasColumnName("is_active"); - - b.Property("MMSI") - .IsRequired() - .HasMaxLength(9) - .HasColumnType("TEXT") - .HasColumnName("mmsi"); - - b.Property("Name") - .IsRequired() - .HasColumnType("TEXT") - .HasColumnName("name"); - - b.Property("OperatorId") - .HasColumnType("INTEGER") - .HasColumnName("operator_id"); - - b.Property("Passengers") - .HasColumnType("INTEGER") - .HasColumnName("passengers"); - - b.Property("Tonnage") - .HasColumnType("INTEGER") - .HasColumnName("tonnage"); - - b.Property("VesselId") - .HasColumnType("INTEGER") - .HasColumnName("vessel_id"); - - b.Property("VesselTypeId") - .HasColumnType("INTEGER") - .HasColumnName("vessel_type_id"); - - b.HasKey("Id"); - - b.HasIndex("FlagId"); - - b.HasIndex("OperatorId"); - - b.HasIndex("VesselId"); - - b.HasIndex("VesselTypeId"); - - b.ToTable("REGISTRATION_HISTORY", null, t => - { - t.HasCheckConstraint("CK_Callsign_Characters", "callsign GLOB '[A-Z0-9]*'"); - - t.HasCheckConstraint("CK_MMSI_Length", "length(mmsi) = 9"); - - t.HasCheckConstraint("CK_MMSI_Numeric", "mmsi GLOB '[0-9]*'"); - }); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Sighting", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasColumnName("id"); - - b.Property("Date") - .HasColumnType("DATETIME") - .HasColumnName("date"); - - b.Property("IsMyVoyage") - .HasColumnType("INTEGER") - .HasColumnName("is_my_voyage"); - - b.Property("LocationId") - .HasColumnType("INTEGER") - .HasColumnName("location_id"); - - b.Property("VesselId") - .HasColumnType("INTEGER") - .HasColumnName("vessel_id"); - - b.Property("VoyageId") - .HasColumnType("INTEGER") - .HasColumnName("voyage_id"); - - b.HasKey("Id"); - - b.HasIndex("LocationId"); - - b.HasIndex("VesselId"); - - b.HasIndex("VoyageId"); - - b.ToTable("SIGHTING", (string)null); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.User", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasColumnName("id"); - - b.Property("Password") - .IsRequired() - .HasColumnType("TEXT") - .HasColumnName("Password"); - - b.Property("UserName") - .IsRequired() - .HasColumnType("TEXT") - .HasColumnName("UserName"); - - b.HasKey("Id"); - - b.HasIndex("UserName") - .IsUnique(); - - b.ToTable("USER", (string)null); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Vessel", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasColumnName("id"); - - b.Property("Beam") - .HasColumnType("INTEGER") - .HasColumnName("beam"); - - b.Property("Built") - .HasColumnType("INTEGER") - .HasColumnName("built"); - - b.Property("Draught") - .HasColumnType("TEXT") - .HasColumnName("draught"); - - b.Property("IMO") - .IsRequired() - .HasMaxLength(7) - .HasColumnType("TEXT") - .HasColumnName("imo"); - - b.Property("Length") - .HasColumnType("INTEGER") - .HasColumnName("length"); - - b.HasKey("Id"); - - b.HasIndex("IMO") - .IsUnique(); - - b.ToTable("VESSEL", null, t => - { - t.HasCheckConstraint("CK_IMO_Length", "length(imo) = 7"); - - t.HasCheckConstraint("CK_IMO_Numeric", "imo GLOB '[0-9]*'"); - }); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.VesselType", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasColumnName("id"); - - b.Property("Name") - .IsRequired() - .HasColumnType("TEXT") - .HasColumnName("name"); - - b.HasKey("Id"); - - b.HasIndex("Name") - .IsUnique(); - - b.ToTable("VESSEL_TYPE", (string)null); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Voyage", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasColumnName("id"); - - b.Property("Number") - .IsRequired() - .HasColumnType("TEXT") - .HasColumnName("number"); - - b.Property("OperatorId") - .HasColumnType("INTEGER") - .HasColumnName("operator_id"); - - b.HasKey("Id"); - - b.HasIndex("OperatorId"); - - b.ToTable("VOYAGE", (string)null); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.VoyageEvent", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasColumnName("id"); - - b.Property("Date") - .HasColumnType("DATETIME") - .HasColumnName("arrival"); - - b.Property("EventType") - .HasColumnType("INTEGER") - .HasColumnName("event_type"); - - b.Property("PortId") - .HasColumnType("INTEGER") - .HasColumnName("port_id"); - - b.Property("VoyageId") - .HasColumnType("INTEGER") - .HasColumnName("voyage_id"); - - b.HasKey("Id"); - - b.HasIndex("PortId"); - - b.HasIndex("VoyageId"); - - b.ToTable("VOYAGE_EVENT", (string)null); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Reporting.LocationStatistics", b => - { - b.Property("Name") - .HasColumnType("TEXT"); - - b.Property("Sightings") - .HasColumnType("INTEGER"); - - b.Property("Vessels") - .HasColumnType("INTEGER"); - - b.ToTable("LocationStatistics"); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Reporting.MyVoyages", b => - { - b.Property("Date") - .HasColumnType("TEXT"); - - b.Property("IMO") - .HasColumnType("TEXT"); - - b.Property("Location") - .HasColumnType("TEXT"); - - b.Property("Vessel") - .HasColumnType("TEXT"); - - b.Property("VesselId") - .HasColumnType("INTEGER"); - - b.ToTable("MyVoyages"); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Reporting.SightingsByMonth", b => - { - b.Property("Locations") - .HasColumnType("INTEGER"); - - b.Property("Month") - .HasColumnType("INTEGER"); - - b.Property("Sightings") - .HasColumnType("INTEGER"); - - b.Property("Vessels") - .HasColumnType("INTEGER"); - - b.Property("Year") - .HasColumnType("INTEGER"); - - b.ToTable("SightingsByMonth"); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Port", b => - { - b.HasOne("ShippingRecorder.Entities.Db.Country", "Country") - .WithMany() - .HasForeignKey("CountryId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.Navigation("Country"); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.RegistrationHistory", b => - { - b.HasOne("ShippingRecorder.Entities.Db.Country", "Flag") - .WithMany() - .HasForeignKey("FlagId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.HasOne("ShippingRecorder.Entities.Db.Operator", "Operator") - .WithMany() - .HasForeignKey("OperatorId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.HasOne("ShippingRecorder.Entities.Db.Vessel", null) - .WithMany("RegistrationHistory") - .HasForeignKey("VesselId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.HasOne("ShippingRecorder.Entities.Db.VesselType", "VesselType") - .WithMany() - .HasForeignKey("VesselTypeId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.Navigation("Flag"); - - b.Navigation("Operator"); - - b.Navigation("VesselType"); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Sighting", b => - { - b.HasOne("ShippingRecorder.Entities.Db.Location", "Location") - .WithMany() - .HasForeignKey("LocationId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.HasOne("ShippingRecorder.Entities.Db.Vessel", "Vessel") - .WithMany() - .HasForeignKey("VesselId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.HasOne("ShippingRecorder.Entities.Db.Voyage", "Voyage") - .WithMany() - .HasForeignKey("VoyageId") - .OnDelete(DeleteBehavior.Restrict); - - b.Navigation("Location"); - - b.Navigation("Vessel"); - - b.Navigation("Voyage"); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Voyage", b => - { - b.HasOne("ShippingRecorder.Entities.Db.Operator", "Operator") - .WithMany() - .HasForeignKey("OperatorId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.Navigation("Operator"); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.VoyageEvent", b => - { - b.HasOne("ShippingRecorder.Entities.Db.Port", "Port") - .WithMany() - .HasForeignKey("PortId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.HasOne("ShippingRecorder.Entities.Db.Voyage", null) - .WithMany("Events") - .HasForeignKey("VoyageId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.Navigation("Port"); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Vessel", b => - { - b.Navigation("RegistrationHistory"); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Voyage", b => - { - b.Navigation("Events"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/src/ShippingRecorder.Data/Migrations/20260108174600_MyVoyages.cs b/src/ShippingRecorder.Data/Migrations/20260108174600_MyVoyages.cs deleted file mode 100644 index 9844cc1..0000000 --- a/src/ShippingRecorder.Data/Migrations/20260108174600_MyVoyages.cs +++ /dev/null @@ -1,38 +0,0 @@ -using System; -using System.Diagnostics.CodeAnalysis; -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -namespace ShippingRecorder.Data.Migrations -{ - /// - [ExcludeFromCodeCoverage] - public partial class MyVoyages : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.CreateTable( - name: "MyVoyages", - columns: table => new - { - Date = table.Column(type: "TEXT", nullable: false), - Location = table.Column(type: "TEXT", nullable: true), - IMO = table.Column(type: "TEXT", nullable: true), - Vessel = table.Column(type: "TEXT", nullable: true), - VesselId = table.Column(type: "INTEGER", nullable: false) - }, - constraints: table => - { - }); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropTable( - name: "MyVoyages"); - } - } -} diff --git a/src/ShippingRecorder.Data/Migrations/20260108181050_OperatorStatistics.Designer.cs b/src/ShippingRecorder.Data/Migrations/20260108181050_OperatorStatistics.Designer.cs deleted file mode 100644 index ae9ab5c..0000000 --- a/src/ShippingRecorder.Data/Migrations/20260108181050_OperatorStatistics.Designer.cs +++ /dev/null @@ -1,615 +0,0 @@ -// -using System; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using ShippingRecorder.Data; - -#nullable disable - -namespace ShippingRecorder.Data.Migrations -{ - [DbContext(typeof(ShippingRecorderDbContext))] - [Migration("20260108181050_OperatorStatistics")] - partial class OperatorStatistics - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder.HasAnnotation("ProductVersion", "9.0.7"); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Country", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasColumnName("id"); - - b.Property("Code") - .IsRequired() - .HasMaxLength(2) - .HasColumnType("TEXT") - .HasColumnName("code"); - - b.Property("Name") - .IsRequired() - .HasColumnType("TEXT") - .HasColumnName("name"); - - b.HasKey("Id"); - - b.HasIndex("Code") - .IsUnique(); - - b.HasIndex("Name") - .IsUnique(); - - b.ToTable("COUNTRY", null, t => - { - t.HasCheckConstraint("CK_Code_Characters", "code GLOB '[A-Z0-9]*'"); - - t.HasCheckConstraint("CK_Code_Length", "length(code) = 2"); - }); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.JobStatus", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasColumnName("id"); - - b.Property("End") - .HasColumnType("DATETIME") - .HasColumnName("end"); - - b.Property("Error") - .HasColumnType("TEXT") - .HasColumnName("error"); - - b.Property("Name") - .IsRequired() - .HasColumnType("TEXT") - .HasColumnName("name"); - - b.Property("Parameters") - .HasColumnType("TEXT") - .HasColumnName("parameters"); - - b.Property("Start") - .HasColumnType("DATETIME") - .HasColumnName("start"); - - b.HasKey("Id"); - - b.ToTable("JOB_STATUS", (string)null); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Location", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasColumnName("id"); - - b.Property("Name") - .IsRequired() - .HasColumnType("TEXT") - .HasColumnName("name"); - - b.HasKey("Id"); - - b.HasIndex("Name") - .IsUnique(); - - b.ToTable("LOCATION", (string)null); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Operator", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasColumnName("id"); - - b.Property("Name") - .IsRequired() - .HasColumnType("TEXT") - .HasColumnName("name"); - - b.HasKey("Id"); - - b.HasIndex("Name") - .IsUnique(); - - b.ToTable("OPERATOR", (string)null); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Port", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasColumnName("id"); - - b.Property("Code") - .IsRequired() - .HasMaxLength(5) - .HasColumnType("TEXT") - .HasColumnName("code"); - - b.Property("CountryId") - .HasColumnType("INTEGER") - .HasColumnName("country_id"); - - b.Property("Name") - .IsRequired() - .HasColumnType("TEXT") - .HasColumnName("name"); - - b.HasKey("Id"); - - b.HasIndex("Code") - .IsUnique(); - - b.HasIndex("CountryId"); - - b.ToTable("PORT", null, t => - { - t.HasCheckConstraint("CK_Code_AlphaNumeric", "code GLOB '[A-Za-z0-9]*'"); - - t.HasCheckConstraint("CK_Code_Length", "length(code) = 5"); - }); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.RegistrationHistory", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasColumnName("id"); - - b.Property("Cabins") - .HasColumnType("INTEGER") - .HasColumnName("cabins"); - - b.Property("Callsign") - .IsRequired() - .HasColumnType("TEXT") - .HasColumnName("callsign"); - - b.Property("Crew") - .HasColumnType("INTEGER") - .HasColumnName("crew"); - - b.Property("Date") - .HasColumnType("DATETIME") - .HasColumnName("date"); - - b.Property("Decks") - .HasColumnType("INTEGER") - .HasColumnName("decks"); - - b.Property("FlagId") - .HasColumnType("INTEGER") - .HasColumnName("flag_id"); - - b.Property("IsActive") - .HasColumnType("INTEGER") - .HasColumnName("is_active"); - - b.Property("MMSI") - .IsRequired() - .HasMaxLength(9) - .HasColumnType("TEXT") - .HasColumnName("mmsi"); - - b.Property("Name") - .IsRequired() - .HasColumnType("TEXT") - .HasColumnName("name"); - - b.Property("OperatorId") - .HasColumnType("INTEGER") - .HasColumnName("operator_id"); - - b.Property("Passengers") - .HasColumnType("INTEGER") - .HasColumnName("passengers"); - - b.Property("Tonnage") - .HasColumnType("INTEGER") - .HasColumnName("tonnage"); - - b.Property("VesselId") - .HasColumnType("INTEGER") - .HasColumnName("vessel_id"); - - b.Property("VesselTypeId") - .HasColumnType("INTEGER") - .HasColumnName("vessel_type_id"); - - b.HasKey("Id"); - - b.HasIndex("FlagId"); - - b.HasIndex("OperatorId"); - - b.HasIndex("VesselId"); - - b.HasIndex("VesselTypeId"); - - b.ToTable("REGISTRATION_HISTORY", null, t => - { - t.HasCheckConstraint("CK_Callsign_Characters", "callsign GLOB '[A-Z0-9]*'"); - - t.HasCheckConstraint("CK_MMSI_Length", "length(mmsi) = 9"); - - t.HasCheckConstraint("CK_MMSI_Numeric", "mmsi GLOB '[0-9]*'"); - }); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Sighting", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasColumnName("id"); - - b.Property("Date") - .HasColumnType("DATETIME") - .HasColumnName("date"); - - b.Property("IsMyVoyage") - .HasColumnType("INTEGER") - .HasColumnName("is_my_voyage"); - - b.Property("LocationId") - .HasColumnType("INTEGER") - .HasColumnName("location_id"); - - b.Property("VesselId") - .HasColumnType("INTEGER") - .HasColumnName("vessel_id"); - - b.Property("VoyageId") - .HasColumnType("INTEGER") - .HasColumnName("voyage_id"); - - b.HasKey("Id"); - - b.HasIndex("LocationId"); - - b.HasIndex("VesselId"); - - b.HasIndex("VoyageId"); - - b.ToTable("SIGHTING", (string)null); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.User", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasColumnName("id"); - - b.Property("Password") - .IsRequired() - .HasColumnType("TEXT") - .HasColumnName("Password"); - - b.Property("UserName") - .IsRequired() - .HasColumnType("TEXT") - .HasColumnName("UserName"); - - b.HasKey("Id"); - - b.HasIndex("UserName") - .IsUnique(); - - b.ToTable("USER", (string)null); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Vessel", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasColumnName("id"); - - b.Property("Beam") - .HasColumnType("INTEGER") - .HasColumnName("beam"); - - b.Property("Built") - .HasColumnType("INTEGER") - .HasColumnName("built"); - - b.Property("Draught") - .HasColumnType("TEXT") - .HasColumnName("draught"); - - b.Property("IMO") - .IsRequired() - .HasMaxLength(7) - .HasColumnType("TEXT") - .HasColumnName("imo"); - - b.Property("Length") - .HasColumnType("INTEGER") - .HasColumnName("length"); - - b.HasKey("Id"); - - b.HasIndex("IMO") - .IsUnique(); - - b.ToTable("VESSEL", null, t => - { - t.HasCheckConstraint("CK_IMO_Length", "length(imo) = 7"); - - t.HasCheckConstraint("CK_IMO_Numeric", "imo GLOB '[0-9]*'"); - }); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.VesselType", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasColumnName("id"); - - b.Property("Name") - .IsRequired() - .HasColumnType("TEXT") - .HasColumnName("name"); - - b.HasKey("Id"); - - b.HasIndex("Name") - .IsUnique(); - - b.ToTable("VESSEL_TYPE", (string)null); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Voyage", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasColumnName("id"); - - b.Property("Number") - .IsRequired() - .HasColumnType("TEXT") - .HasColumnName("number"); - - b.Property("OperatorId") - .HasColumnType("INTEGER") - .HasColumnName("operator_id"); - - b.HasKey("Id"); - - b.HasIndex("OperatorId"); - - b.ToTable("VOYAGE", (string)null); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.VoyageEvent", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasColumnName("id"); - - b.Property("Date") - .HasColumnType("DATETIME") - .HasColumnName("arrival"); - - b.Property("EventType") - .HasColumnType("INTEGER") - .HasColumnName("event_type"); - - b.Property("PortId") - .HasColumnType("INTEGER") - .HasColumnName("port_id"); - - b.Property("VoyageId") - .HasColumnType("INTEGER") - .HasColumnName("voyage_id"); - - b.HasKey("Id"); - - b.HasIndex("PortId"); - - b.HasIndex("VoyageId"); - - b.ToTable("VOYAGE_EVENT", (string)null); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Reporting.LocationStatistics", b => - { - b.Property("Name") - .HasColumnType("TEXT"); - - b.Property("Sightings") - .HasColumnType("INTEGER"); - - b.Property("Vessels") - .HasColumnType("INTEGER"); - - b.ToTable("LocationStatistics"); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Reporting.MyVoyages", b => - { - b.Property("Date") - .HasColumnType("TEXT"); - - b.Property("IMO") - .HasColumnType("TEXT"); - - b.Property("Location") - .HasColumnType("TEXT"); - - b.Property("Vessel") - .HasColumnType("TEXT"); - - b.Property("VesselId") - .HasColumnType("INTEGER"); - - b.ToTable("MyVoyages"); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Reporting.OperatorStatistics", b => - { - b.Property("Locations") - .HasColumnType("INTEGER"); - - b.Property("Name") - .HasColumnType("TEXT"); - - b.Property("Sightings") - .HasColumnType("INTEGER"); - - b.Property("Vessels") - .HasColumnType("INTEGER"); - - b.ToTable("OperatorStatistics"); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Reporting.SightingsByMonth", b => - { - b.Property("Locations") - .HasColumnType("INTEGER"); - - b.Property("Month") - .HasColumnType("INTEGER"); - - b.Property("Sightings") - .HasColumnType("INTEGER"); - - b.Property("Vessels") - .HasColumnType("INTEGER"); - - b.Property("Year") - .HasColumnType("INTEGER"); - - b.ToTable("SightingsByMonth"); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Port", b => - { - b.HasOne("ShippingRecorder.Entities.Db.Country", "Country") - .WithMany() - .HasForeignKey("CountryId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.Navigation("Country"); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.RegistrationHistory", b => - { - b.HasOne("ShippingRecorder.Entities.Db.Country", "Flag") - .WithMany() - .HasForeignKey("FlagId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.HasOne("ShippingRecorder.Entities.Db.Operator", "Operator") - .WithMany() - .HasForeignKey("OperatorId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.HasOne("ShippingRecorder.Entities.Db.Vessel", null) - .WithMany("RegistrationHistory") - .HasForeignKey("VesselId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.HasOne("ShippingRecorder.Entities.Db.VesselType", "VesselType") - .WithMany() - .HasForeignKey("VesselTypeId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.Navigation("Flag"); - - b.Navigation("Operator"); - - b.Navigation("VesselType"); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Sighting", b => - { - b.HasOne("ShippingRecorder.Entities.Db.Location", "Location") - .WithMany() - .HasForeignKey("LocationId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.HasOne("ShippingRecorder.Entities.Db.Vessel", "Vessel") - .WithMany() - .HasForeignKey("VesselId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.HasOne("ShippingRecorder.Entities.Db.Voyage", "Voyage") - .WithMany() - .HasForeignKey("VoyageId") - .OnDelete(DeleteBehavior.Restrict); - - b.Navigation("Location"); - - b.Navigation("Vessel"); - - b.Navigation("Voyage"); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Voyage", b => - { - b.HasOne("ShippingRecorder.Entities.Db.Operator", "Operator") - .WithMany() - .HasForeignKey("OperatorId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.Navigation("Operator"); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.VoyageEvent", b => - { - b.HasOne("ShippingRecorder.Entities.Db.Port", "Port") - .WithMany() - .HasForeignKey("PortId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.HasOne("ShippingRecorder.Entities.Db.Voyage", null) - .WithMany("Events") - .HasForeignKey("VoyageId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.Navigation("Port"); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Vessel", b => - { - b.Navigation("RegistrationHistory"); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Voyage", b => - { - b.Navigation("Events"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/src/ShippingRecorder.Data/Migrations/20260108181050_OperatorStatistics.cs b/src/ShippingRecorder.Data/Migrations/20260108181050_OperatorStatistics.cs deleted file mode 100644 index b7b63a7..0000000 --- a/src/ShippingRecorder.Data/Migrations/20260108181050_OperatorStatistics.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Diagnostics.CodeAnalysis; -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -namespace ShippingRecorder.Data.Migrations -{ - /// - [ExcludeFromCodeCoverage] - public partial class OperatorStatistics : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.CreateTable( - name: "OperatorStatistics", - columns: table => new - { - Name = table.Column(type: "TEXT", nullable: true), - Sightings = table.Column(type: "INTEGER", nullable: true), - Locations = table.Column(type: "INTEGER", nullable: true), - Vessels = table.Column(type: "INTEGER", nullable: true) - }, - constraints: table => - { - }); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropTable( - name: "OperatorStatistics"); - } - } -} diff --git a/src/ShippingRecorder.Data/Migrations/20260108183209_VesselTypeStatistics.Designer.cs b/src/ShippingRecorder.Data/Migrations/20260108183209_VesselTypeStatistics.Designer.cs deleted file mode 100644 index a7bdff3..0000000 --- a/src/ShippingRecorder.Data/Migrations/20260108183209_VesselTypeStatistics.Designer.cs +++ /dev/null @@ -1,632 +0,0 @@ -// -using System; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using ShippingRecorder.Data; - -#nullable disable - -namespace ShippingRecorder.Data.Migrations -{ - [DbContext(typeof(ShippingRecorderDbContext))] - [Migration("20260108183209_VesselTypeStatistics")] - partial class VesselTypeStatistics - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder.HasAnnotation("ProductVersion", "9.0.7"); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Country", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasColumnName("id"); - - b.Property("Code") - .IsRequired() - .HasMaxLength(2) - .HasColumnType("TEXT") - .HasColumnName("code"); - - b.Property("Name") - .IsRequired() - .HasColumnType("TEXT") - .HasColumnName("name"); - - b.HasKey("Id"); - - b.HasIndex("Code") - .IsUnique(); - - b.HasIndex("Name") - .IsUnique(); - - b.ToTable("COUNTRY", null, t => - { - t.HasCheckConstraint("CK_Code_Characters", "code GLOB '[A-Z0-9]*'"); - - t.HasCheckConstraint("CK_Code_Length", "length(code) = 2"); - }); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.JobStatus", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasColumnName("id"); - - b.Property("End") - .HasColumnType("DATETIME") - .HasColumnName("end"); - - b.Property("Error") - .HasColumnType("TEXT") - .HasColumnName("error"); - - b.Property("Name") - .IsRequired() - .HasColumnType("TEXT") - .HasColumnName("name"); - - b.Property("Parameters") - .HasColumnType("TEXT") - .HasColumnName("parameters"); - - b.Property("Start") - .HasColumnType("DATETIME") - .HasColumnName("start"); - - b.HasKey("Id"); - - b.ToTable("JOB_STATUS", (string)null); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Location", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasColumnName("id"); - - b.Property("Name") - .IsRequired() - .HasColumnType("TEXT") - .HasColumnName("name"); - - b.HasKey("Id"); - - b.HasIndex("Name") - .IsUnique(); - - b.ToTable("LOCATION", (string)null); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Operator", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasColumnName("id"); - - b.Property("Name") - .IsRequired() - .HasColumnType("TEXT") - .HasColumnName("name"); - - b.HasKey("Id"); - - b.HasIndex("Name") - .IsUnique(); - - b.ToTable("OPERATOR", (string)null); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Port", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasColumnName("id"); - - b.Property("Code") - .IsRequired() - .HasMaxLength(5) - .HasColumnType("TEXT") - .HasColumnName("code"); - - b.Property("CountryId") - .HasColumnType("INTEGER") - .HasColumnName("country_id"); - - b.Property("Name") - .IsRequired() - .HasColumnType("TEXT") - .HasColumnName("name"); - - b.HasKey("Id"); - - b.HasIndex("Code") - .IsUnique(); - - b.HasIndex("CountryId"); - - b.ToTable("PORT", null, t => - { - t.HasCheckConstraint("CK_Code_AlphaNumeric", "code GLOB '[A-Za-z0-9]*'"); - - t.HasCheckConstraint("CK_Code_Length", "length(code) = 5"); - }); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.RegistrationHistory", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasColumnName("id"); - - b.Property("Cabins") - .HasColumnType("INTEGER") - .HasColumnName("cabins"); - - b.Property("Callsign") - .IsRequired() - .HasColumnType("TEXT") - .HasColumnName("callsign"); - - b.Property("Crew") - .HasColumnType("INTEGER") - .HasColumnName("crew"); - - b.Property("Date") - .HasColumnType("DATETIME") - .HasColumnName("date"); - - b.Property("Decks") - .HasColumnType("INTEGER") - .HasColumnName("decks"); - - b.Property("FlagId") - .HasColumnType("INTEGER") - .HasColumnName("flag_id"); - - b.Property("IsActive") - .HasColumnType("INTEGER") - .HasColumnName("is_active"); - - b.Property("MMSI") - .IsRequired() - .HasMaxLength(9) - .HasColumnType("TEXT") - .HasColumnName("mmsi"); - - b.Property("Name") - .IsRequired() - .HasColumnType("TEXT") - .HasColumnName("name"); - - b.Property("OperatorId") - .HasColumnType("INTEGER") - .HasColumnName("operator_id"); - - b.Property("Passengers") - .HasColumnType("INTEGER") - .HasColumnName("passengers"); - - b.Property("Tonnage") - .HasColumnType("INTEGER") - .HasColumnName("tonnage"); - - b.Property("VesselId") - .HasColumnType("INTEGER") - .HasColumnName("vessel_id"); - - b.Property("VesselTypeId") - .HasColumnType("INTEGER") - .HasColumnName("vessel_type_id"); - - b.HasKey("Id"); - - b.HasIndex("FlagId"); - - b.HasIndex("OperatorId"); - - b.HasIndex("VesselId"); - - b.HasIndex("VesselTypeId"); - - b.ToTable("REGISTRATION_HISTORY", null, t => - { - t.HasCheckConstraint("CK_Callsign_Characters", "callsign GLOB '[A-Z0-9]*'"); - - t.HasCheckConstraint("CK_MMSI_Length", "length(mmsi) = 9"); - - t.HasCheckConstraint("CK_MMSI_Numeric", "mmsi GLOB '[0-9]*'"); - }); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Sighting", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasColumnName("id"); - - b.Property("Date") - .HasColumnType("DATETIME") - .HasColumnName("date"); - - b.Property("IsMyVoyage") - .HasColumnType("INTEGER") - .HasColumnName("is_my_voyage"); - - b.Property("LocationId") - .HasColumnType("INTEGER") - .HasColumnName("location_id"); - - b.Property("VesselId") - .HasColumnType("INTEGER") - .HasColumnName("vessel_id"); - - b.Property("VoyageId") - .HasColumnType("INTEGER") - .HasColumnName("voyage_id"); - - b.HasKey("Id"); - - b.HasIndex("LocationId"); - - b.HasIndex("VesselId"); - - b.HasIndex("VoyageId"); - - b.ToTable("SIGHTING", (string)null); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.User", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasColumnName("id"); - - b.Property("Password") - .IsRequired() - .HasColumnType("TEXT") - .HasColumnName("Password"); - - b.Property("UserName") - .IsRequired() - .HasColumnType("TEXT") - .HasColumnName("UserName"); - - b.HasKey("Id"); - - b.HasIndex("UserName") - .IsUnique(); - - b.ToTable("USER", (string)null); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Vessel", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasColumnName("id"); - - b.Property("Beam") - .HasColumnType("INTEGER") - .HasColumnName("beam"); - - b.Property("Built") - .HasColumnType("INTEGER") - .HasColumnName("built"); - - b.Property("Draught") - .HasColumnType("TEXT") - .HasColumnName("draught"); - - b.Property("IMO") - .IsRequired() - .HasMaxLength(7) - .HasColumnType("TEXT") - .HasColumnName("imo"); - - b.Property("Length") - .HasColumnType("INTEGER") - .HasColumnName("length"); - - b.HasKey("Id"); - - b.HasIndex("IMO") - .IsUnique(); - - b.ToTable("VESSEL", null, t => - { - t.HasCheckConstraint("CK_IMO_Length", "length(imo) = 7"); - - t.HasCheckConstraint("CK_IMO_Numeric", "imo GLOB '[0-9]*'"); - }); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.VesselType", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasColumnName("id"); - - b.Property("Name") - .IsRequired() - .HasColumnType("TEXT") - .HasColumnName("name"); - - b.HasKey("Id"); - - b.HasIndex("Name") - .IsUnique(); - - b.ToTable("VESSEL_TYPE", (string)null); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Voyage", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasColumnName("id"); - - b.Property("Number") - .IsRequired() - .HasColumnType("TEXT") - .HasColumnName("number"); - - b.Property("OperatorId") - .HasColumnType("INTEGER") - .HasColumnName("operator_id"); - - b.HasKey("Id"); - - b.HasIndex("OperatorId"); - - b.ToTable("VOYAGE", (string)null); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.VoyageEvent", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasColumnName("id"); - - b.Property("Date") - .HasColumnType("DATETIME") - .HasColumnName("arrival"); - - b.Property("EventType") - .HasColumnType("INTEGER") - .HasColumnName("event_type"); - - b.Property("PortId") - .HasColumnType("INTEGER") - .HasColumnName("port_id"); - - b.Property("VoyageId") - .HasColumnType("INTEGER") - .HasColumnName("voyage_id"); - - b.HasKey("Id"); - - b.HasIndex("PortId"); - - b.HasIndex("VoyageId"); - - b.ToTable("VOYAGE_EVENT", (string)null); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Reporting.LocationStatistics", b => - { - b.Property("Name") - .HasColumnType("TEXT"); - - b.Property("Sightings") - .HasColumnType("INTEGER"); - - b.Property("Vessels") - .HasColumnType("INTEGER"); - - b.ToTable("LocationStatistics"); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Reporting.MyVoyages", b => - { - b.Property("Date") - .HasColumnType("TEXT"); - - b.Property("IMO") - .HasColumnType("TEXT"); - - b.Property("Location") - .HasColumnType("TEXT"); - - b.Property("Vessel") - .HasColumnType("TEXT"); - - b.Property("VesselId") - .HasColumnType("INTEGER"); - - b.ToTable("MyVoyages"); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Reporting.OperatorStatistics", b => - { - b.Property("Locations") - .HasColumnType("INTEGER"); - - b.Property("Name") - .HasColumnType("TEXT"); - - b.Property("Sightings") - .HasColumnType("INTEGER"); - - b.Property("Vessels") - .HasColumnType("INTEGER"); - - b.ToTable("OperatorStatistics"); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Reporting.SightingsByMonth", b => - { - b.Property("Locations") - .HasColumnType("INTEGER"); - - b.Property("Month") - .HasColumnType("INTEGER"); - - b.Property("Sightings") - .HasColumnType("INTEGER"); - - b.Property("Vessels") - .HasColumnType("INTEGER"); - - b.Property("Year") - .HasColumnType("INTEGER"); - - b.ToTable("SightingsByMonth"); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Reporting.VesselTypeStatistics", b => - { - b.Property("Locations") - .HasColumnType("INTEGER"); - - b.Property("Name") - .HasColumnType("TEXT"); - - b.Property("Sightings") - .HasColumnType("INTEGER"); - - b.Property("Vessels") - .HasColumnType("INTEGER"); - - b.ToTable("VesselTypeStatistics"); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Port", b => - { - b.HasOne("ShippingRecorder.Entities.Db.Country", "Country") - .WithMany() - .HasForeignKey("CountryId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.Navigation("Country"); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.RegistrationHistory", b => - { - b.HasOne("ShippingRecorder.Entities.Db.Country", "Flag") - .WithMany() - .HasForeignKey("FlagId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.HasOne("ShippingRecorder.Entities.Db.Operator", "Operator") - .WithMany() - .HasForeignKey("OperatorId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.HasOne("ShippingRecorder.Entities.Db.Vessel", null) - .WithMany("RegistrationHistory") - .HasForeignKey("VesselId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.HasOne("ShippingRecorder.Entities.Db.VesselType", "VesselType") - .WithMany() - .HasForeignKey("VesselTypeId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.Navigation("Flag"); - - b.Navigation("Operator"); - - b.Navigation("VesselType"); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Sighting", b => - { - b.HasOne("ShippingRecorder.Entities.Db.Location", "Location") - .WithMany() - .HasForeignKey("LocationId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.HasOne("ShippingRecorder.Entities.Db.Vessel", "Vessel") - .WithMany() - .HasForeignKey("VesselId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.HasOne("ShippingRecorder.Entities.Db.Voyage", "Voyage") - .WithMany() - .HasForeignKey("VoyageId") - .OnDelete(DeleteBehavior.Restrict); - - b.Navigation("Location"); - - b.Navigation("Vessel"); - - b.Navigation("Voyage"); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Voyage", b => - { - b.HasOne("ShippingRecorder.Entities.Db.Operator", "Operator") - .WithMany() - .HasForeignKey("OperatorId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.Navigation("Operator"); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.VoyageEvent", b => - { - b.HasOne("ShippingRecorder.Entities.Db.Port", "Port") - .WithMany() - .HasForeignKey("PortId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.HasOne("ShippingRecorder.Entities.Db.Voyage", null) - .WithMany("Events") - .HasForeignKey("VoyageId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.Navigation("Port"); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Vessel", b => - { - b.Navigation("RegistrationHistory"); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Voyage", b => - { - b.Navigation("Events"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/src/ShippingRecorder.Data/Migrations/20260108183209_VesselTypeStatistics.cs b/src/ShippingRecorder.Data/Migrations/20260108183209_VesselTypeStatistics.cs deleted file mode 100644 index c573d99..0000000 --- a/src/ShippingRecorder.Data/Migrations/20260108183209_VesselTypeStatistics.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Diagnostics.CodeAnalysis; -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -namespace ShippingRecorder.Data.Migrations -{ - /// - [ExcludeFromCodeCoverage] - public partial class VesselTypeStatistics : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.CreateTable( - name: "VesselTypeStatistics", - columns: table => new - { - Name = table.Column(type: "TEXT", nullable: true), - Sightings = table.Column(type: "INTEGER", nullable: true), - Locations = table.Column(type: "INTEGER", nullable: true), - Vessels = table.Column(type: "INTEGER", nullable: true) - }, - constraints: table => - { - }); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropTable( - name: "VesselTypeStatistics"); - } - } -} diff --git a/src/ShippingRecorder.Data/Migrations/20260108184554_FlagStatistics.Designer.cs b/src/ShippingRecorder.Data/Migrations/20260108184554_FlagStatistics.Designer.cs deleted file mode 100644 index b63f258..0000000 --- a/src/ShippingRecorder.Data/Migrations/20260108184554_FlagStatistics.Designer.cs +++ /dev/null @@ -1,652 +0,0 @@ -// -using System; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using ShippingRecorder.Data; - -#nullable disable - -namespace ShippingRecorder.Data.Migrations -{ - [DbContext(typeof(ShippingRecorderDbContext))] - [Migration("20260108184554_FlagStatistics")] - partial class FlagStatistics - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder.HasAnnotation("ProductVersion", "9.0.7"); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Country", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasColumnName("id"); - - b.Property("Code") - .IsRequired() - .HasMaxLength(2) - .HasColumnType("TEXT") - .HasColumnName("code"); - - b.Property("Name") - .IsRequired() - .HasColumnType("TEXT") - .HasColumnName("name"); - - b.HasKey("Id"); - - b.HasIndex("Code") - .IsUnique(); - - b.HasIndex("Name") - .IsUnique(); - - b.ToTable("COUNTRY", null, t => - { - t.HasCheckConstraint("CK_Code_Characters", "code GLOB '[A-Z0-9]*'"); - - t.HasCheckConstraint("CK_Code_Length", "length(code) = 2"); - }); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.JobStatus", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasColumnName("id"); - - b.Property("End") - .HasColumnType("DATETIME") - .HasColumnName("end"); - - b.Property("Error") - .HasColumnType("TEXT") - .HasColumnName("error"); - - b.Property("Name") - .IsRequired() - .HasColumnType("TEXT") - .HasColumnName("name"); - - b.Property("Parameters") - .HasColumnType("TEXT") - .HasColumnName("parameters"); - - b.Property("Start") - .HasColumnType("DATETIME") - .HasColumnName("start"); - - b.HasKey("Id"); - - b.ToTable("JOB_STATUS", (string)null); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Location", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasColumnName("id"); - - b.Property("Name") - .IsRequired() - .HasColumnType("TEXT") - .HasColumnName("name"); - - b.HasKey("Id"); - - b.HasIndex("Name") - .IsUnique(); - - b.ToTable("LOCATION", (string)null); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Operator", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasColumnName("id"); - - b.Property("Name") - .IsRequired() - .HasColumnType("TEXT") - .HasColumnName("name"); - - b.HasKey("Id"); - - b.HasIndex("Name") - .IsUnique(); - - b.ToTable("OPERATOR", (string)null); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Port", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasColumnName("id"); - - b.Property("Code") - .IsRequired() - .HasMaxLength(5) - .HasColumnType("TEXT") - .HasColumnName("code"); - - b.Property("CountryId") - .HasColumnType("INTEGER") - .HasColumnName("country_id"); - - b.Property("Name") - .IsRequired() - .HasColumnType("TEXT") - .HasColumnName("name"); - - b.HasKey("Id"); - - b.HasIndex("Code") - .IsUnique(); - - b.HasIndex("CountryId"); - - b.ToTable("PORT", null, t => - { - t.HasCheckConstraint("CK_Code_AlphaNumeric", "code GLOB '[A-Za-z0-9]*'"); - - t.HasCheckConstraint("CK_Code_Length", "length(code) = 5"); - }); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.RegistrationHistory", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasColumnName("id"); - - b.Property("Cabins") - .HasColumnType("INTEGER") - .HasColumnName("cabins"); - - b.Property("Callsign") - .IsRequired() - .HasColumnType("TEXT") - .HasColumnName("callsign"); - - b.Property("Crew") - .HasColumnType("INTEGER") - .HasColumnName("crew"); - - b.Property("Date") - .HasColumnType("DATETIME") - .HasColumnName("date"); - - b.Property("Decks") - .HasColumnType("INTEGER") - .HasColumnName("decks"); - - b.Property("FlagId") - .HasColumnType("INTEGER") - .HasColumnName("flag_id"); - - b.Property("IsActive") - .HasColumnType("INTEGER") - .HasColumnName("is_active"); - - b.Property("MMSI") - .IsRequired() - .HasMaxLength(9) - .HasColumnType("TEXT") - .HasColumnName("mmsi"); - - b.Property("Name") - .IsRequired() - .HasColumnType("TEXT") - .HasColumnName("name"); - - b.Property("OperatorId") - .HasColumnType("INTEGER") - .HasColumnName("operator_id"); - - b.Property("Passengers") - .HasColumnType("INTEGER") - .HasColumnName("passengers"); - - b.Property("Tonnage") - .HasColumnType("INTEGER") - .HasColumnName("tonnage"); - - b.Property("VesselId") - .HasColumnType("INTEGER") - .HasColumnName("vessel_id"); - - b.Property("VesselTypeId") - .HasColumnType("INTEGER") - .HasColumnName("vessel_type_id"); - - b.HasKey("Id"); - - b.HasIndex("FlagId"); - - b.HasIndex("OperatorId"); - - b.HasIndex("VesselId"); - - b.HasIndex("VesselTypeId"); - - b.ToTable("REGISTRATION_HISTORY", null, t => - { - t.HasCheckConstraint("CK_Callsign_Characters", "callsign GLOB '[A-Z0-9]*'"); - - t.HasCheckConstraint("CK_MMSI_Length", "length(mmsi) = 9"); - - t.HasCheckConstraint("CK_MMSI_Numeric", "mmsi GLOB '[0-9]*'"); - }); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Sighting", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasColumnName("id"); - - b.Property("Date") - .HasColumnType("DATETIME") - .HasColumnName("date"); - - b.Property("IsMyVoyage") - .HasColumnType("INTEGER") - .HasColumnName("is_my_voyage"); - - b.Property("LocationId") - .HasColumnType("INTEGER") - .HasColumnName("location_id"); - - b.Property("VesselId") - .HasColumnType("INTEGER") - .HasColumnName("vessel_id"); - - b.Property("VoyageId") - .HasColumnType("INTEGER") - .HasColumnName("voyage_id"); - - b.HasKey("Id"); - - b.HasIndex("LocationId"); - - b.HasIndex("VesselId"); - - b.HasIndex("VoyageId"); - - b.ToTable("SIGHTING", (string)null); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.User", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasColumnName("id"); - - b.Property("Password") - .IsRequired() - .HasColumnType("TEXT") - .HasColumnName("Password"); - - b.Property("UserName") - .IsRequired() - .HasColumnType("TEXT") - .HasColumnName("UserName"); - - b.HasKey("Id"); - - b.HasIndex("UserName") - .IsUnique(); - - b.ToTable("USER", (string)null); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Vessel", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasColumnName("id"); - - b.Property("Beam") - .HasColumnType("INTEGER") - .HasColumnName("beam"); - - b.Property("Built") - .HasColumnType("INTEGER") - .HasColumnName("built"); - - b.Property("Draught") - .HasColumnType("TEXT") - .HasColumnName("draught"); - - b.Property("IMO") - .IsRequired() - .HasMaxLength(7) - .HasColumnType("TEXT") - .HasColumnName("imo"); - - b.Property("Length") - .HasColumnType("INTEGER") - .HasColumnName("length"); - - b.HasKey("Id"); - - b.HasIndex("IMO") - .IsUnique(); - - b.ToTable("VESSEL", null, t => - { - t.HasCheckConstraint("CK_IMO_Length", "length(imo) = 7"); - - t.HasCheckConstraint("CK_IMO_Numeric", "imo GLOB '[0-9]*'"); - }); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.VesselType", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasColumnName("id"); - - b.Property("Name") - .IsRequired() - .HasColumnType("TEXT") - .HasColumnName("name"); - - b.HasKey("Id"); - - b.HasIndex("Name") - .IsUnique(); - - b.ToTable("VESSEL_TYPE", (string)null); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Voyage", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasColumnName("id"); - - b.Property("Number") - .IsRequired() - .HasColumnType("TEXT") - .HasColumnName("number"); - - b.Property("OperatorId") - .HasColumnType("INTEGER") - .HasColumnName("operator_id"); - - b.HasKey("Id"); - - b.HasIndex("OperatorId"); - - b.ToTable("VOYAGE", (string)null); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.VoyageEvent", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasColumnName("id"); - - b.Property("Date") - .HasColumnType("DATETIME") - .HasColumnName("arrival"); - - b.Property("EventType") - .HasColumnType("INTEGER") - .HasColumnName("event_type"); - - b.Property("PortId") - .HasColumnType("INTEGER") - .HasColumnName("port_id"); - - b.Property("VoyageId") - .HasColumnType("INTEGER") - .HasColumnName("voyage_id"); - - b.HasKey("Id"); - - b.HasIndex("PortId"); - - b.HasIndex("VoyageId"); - - b.ToTable("VOYAGE_EVENT", (string)null); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Reporting.FlagStatistics", b => - { - b.Property("Code") - .HasColumnType("TEXT"); - - b.Property("Locations") - .HasColumnType("INTEGER"); - - b.Property("Name") - .HasColumnType("TEXT"); - - b.Property("Sightings") - .HasColumnType("INTEGER"); - - b.Property("Vessels") - .HasColumnType("INTEGER"); - - b.ToTable("FlagStatistics"); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Reporting.LocationStatistics", b => - { - b.Property("Name") - .HasColumnType("TEXT"); - - b.Property("Sightings") - .HasColumnType("INTEGER"); - - b.Property("Vessels") - .HasColumnType("INTEGER"); - - b.ToTable("LocationStatistics"); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Reporting.MyVoyages", b => - { - b.Property("Date") - .HasColumnType("TEXT"); - - b.Property("IMO") - .HasColumnType("TEXT"); - - b.Property("Location") - .HasColumnType("TEXT"); - - b.Property("Vessel") - .HasColumnType("TEXT"); - - b.Property("VesselId") - .HasColumnType("INTEGER"); - - b.ToTable("MyVoyages"); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Reporting.OperatorStatistics", b => - { - b.Property("Locations") - .HasColumnType("INTEGER"); - - b.Property("Name") - .HasColumnType("TEXT"); - - b.Property("Sightings") - .HasColumnType("INTEGER"); - - b.Property("Vessels") - .HasColumnType("INTEGER"); - - b.ToTable("OperatorStatistics"); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Reporting.SightingsByMonth", b => - { - b.Property("Locations") - .HasColumnType("INTEGER"); - - b.Property("Month") - .HasColumnType("INTEGER"); - - b.Property("Sightings") - .HasColumnType("INTEGER"); - - b.Property("Vessels") - .HasColumnType("INTEGER"); - - b.Property("Year") - .HasColumnType("INTEGER"); - - b.ToTable("SightingsByMonth"); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Reporting.VesselTypeStatistics", b => - { - b.Property("Locations") - .HasColumnType("INTEGER"); - - b.Property("Name") - .HasColumnType("TEXT"); - - b.Property("Sightings") - .HasColumnType("INTEGER"); - - b.Property("Vessels") - .HasColumnType("INTEGER"); - - b.ToTable("VesselTypeStatistics"); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Port", b => - { - b.HasOne("ShippingRecorder.Entities.Db.Country", "Country") - .WithMany() - .HasForeignKey("CountryId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.Navigation("Country"); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.RegistrationHistory", b => - { - b.HasOne("ShippingRecorder.Entities.Db.Country", "Flag") - .WithMany() - .HasForeignKey("FlagId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.HasOne("ShippingRecorder.Entities.Db.Operator", "Operator") - .WithMany() - .HasForeignKey("OperatorId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.HasOne("ShippingRecorder.Entities.Db.Vessel", null) - .WithMany("RegistrationHistory") - .HasForeignKey("VesselId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.HasOne("ShippingRecorder.Entities.Db.VesselType", "VesselType") - .WithMany() - .HasForeignKey("VesselTypeId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.Navigation("Flag"); - - b.Navigation("Operator"); - - b.Navigation("VesselType"); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Sighting", b => - { - b.HasOne("ShippingRecorder.Entities.Db.Location", "Location") - .WithMany() - .HasForeignKey("LocationId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.HasOne("ShippingRecorder.Entities.Db.Vessel", "Vessel") - .WithMany() - .HasForeignKey("VesselId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.HasOne("ShippingRecorder.Entities.Db.Voyage", "Voyage") - .WithMany() - .HasForeignKey("VoyageId") - .OnDelete(DeleteBehavior.Restrict); - - b.Navigation("Location"); - - b.Navigation("Vessel"); - - b.Navigation("Voyage"); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Voyage", b => - { - b.HasOne("ShippingRecorder.Entities.Db.Operator", "Operator") - .WithMany() - .HasForeignKey("OperatorId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.Navigation("Operator"); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.VoyageEvent", b => - { - b.HasOne("ShippingRecorder.Entities.Db.Port", "Port") - .WithMany() - .HasForeignKey("PortId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.HasOne("ShippingRecorder.Entities.Db.Voyage", null) - .WithMany("Events") - .HasForeignKey("VoyageId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.Navigation("Port"); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Vessel", b => - { - b.Navigation("RegistrationHistory"); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Voyage", b => - { - b.Navigation("Events"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/src/ShippingRecorder.Data/Migrations/20260108184554_FlagStatistics.cs b/src/ShippingRecorder.Data/Migrations/20260108184554_FlagStatistics.cs deleted file mode 100644 index 122805f..0000000 --- a/src/ShippingRecorder.Data/Migrations/20260108184554_FlagStatistics.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System.Diagnostics.CodeAnalysis; -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -namespace ShippingRecorder.Data.Migrations -{ - /// - [ExcludeFromCodeCoverage] - public partial class FlagStatistics : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.CreateTable( - name: "FlagStatistics", - columns: table => new - { - Code = table.Column(type: "TEXT", nullable: true), - Name = table.Column(type: "TEXT", nullable: true), - Sightings = table.Column(type: "INTEGER", nullable: true), - Locations = table.Column(type: "INTEGER", nullable: true), - Vessels = table.Column(type: "INTEGER", nullable: true) - }, - constraints: table => - { - }); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropTable( - name: "FlagStatistics"); - } - } -} diff --git a/src/ShippingRecorder.Data/Migrations/20260111174920_VoyageVessel.Designer.cs b/src/ShippingRecorder.Data/Migrations/20260111174920_VoyageVessel.Designer.cs deleted file mode 100644 index 327cfb1..0000000 --- a/src/ShippingRecorder.Data/Migrations/20260111174920_VoyageVessel.Designer.cs +++ /dev/null @@ -1,666 +0,0 @@ -// -using System; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using ShippingRecorder.Data; - -#nullable disable - -namespace ShippingRecorder.Data.Migrations -{ - [DbContext(typeof(ShippingRecorderDbContext))] - [Migration("20260111174920_VoyageVessel")] - partial class VoyageVessel - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder.HasAnnotation("ProductVersion", "9.0.7"); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Country", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasColumnName("id"); - - b.Property("Code") - .IsRequired() - .HasMaxLength(2) - .HasColumnType("TEXT") - .HasColumnName("code"); - - b.Property("Name") - .IsRequired() - .HasColumnType("TEXT") - .HasColumnName("name"); - - b.HasKey("Id"); - - b.HasIndex("Code") - .IsUnique(); - - b.HasIndex("Name") - .IsUnique(); - - b.ToTable("COUNTRY", null, t => - { - t.HasCheckConstraint("CK_Code_Characters", "code GLOB '[A-Z0-9]*'"); - - t.HasCheckConstraint("CK_Code_Length", "length(code) = 2"); - }); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.JobStatus", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasColumnName("id"); - - b.Property("End") - .HasColumnType("DATETIME") - .HasColumnName("end"); - - b.Property("Error") - .HasColumnType("TEXT") - .HasColumnName("error"); - - b.Property("Name") - .IsRequired() - .HasColumnType("TEXT") - .HasColumnName("name"); - - b.Property("Parameters") - .HasColumnType("TEXT") - .HasColumnName("parameters"); - - b.Property("Start") - .HasColumnType("DATETIME") - .HasColumnName("start"); - - b.HasKey("Id"); - - b.ToTable("JOB_STATUS", (string)null); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Location", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasColumnName("id"); - - b.Property("Name") - .IsRequired() - .HasColumnType("TEXT") - .HasColumnName("name"); - - b.HasKey("Id"); - - b.HasIndex("Name") - .IsUnique(); - - b.ToTable("LOCATION", (string)null); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Operator", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasColumnName("id"); - - b.Property("Name") - .IsRequired() - .HasColumnType("TEXT") - .HasColumnName("name"); - - b.HasKey("Id"); - - b.HasIndex("Name") - .IsUnique(); - - b.ToTable("OPERATOR", (string)null); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Port", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasColumnName("id"); - - b.Property("Code") - .IsRequired() - .HasMaxLength(5) - .HasColumnType("TEXT") - .HasColumnName("code"); - - b.Property("CountryId") - .HasColumnType("INTEGER") - .HasColumnName("country_id"); - - b.Property("Name") - .IsRequired() - .HasColumnType("TEXT") - .HasColumnName("name"); - - b.HasKey("Id"); - - b.HasIndex("Code") - .IsUnique(); - - b.HasIndex("CountryId"); - - b.ToTable("PORT", null, t => - { - t.HasCheckConstraint("CK_Code_AlphaNumeric", "code GLOB '[A-Za-z0-9]*'"); - - t.HasCheckConstraint("CK_Code_Length", "length(code) = 5"); - }); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.RegistrationHistory", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasColumnName("id"); - - b.Property("Cabins") - .HasColumnType("INTEGER") - .HasColumnName("cabins"); - - b.Property("Callsign") - .IsRequired() - .HasColumnType("TEXT") - .HasColumnName("callsign"); - - b.Property("Crew") - .HasColumnType("INTEGER") - .HasColumnName("crew"); - - b.Property("Date") - .HasColumnType("DATETIME") - .HasColumnName("date"); - - b.Property("Decks") - .HasColumnType("INTEGER") - .HasColumnName("decks"); - - b.Property("FlagId") - .HasColumnType("INTEGER") - .HasColumnName("flag_id"); - - b.Property("IsActive") - .HasColumnType("INTEGER") - .HasColumnName("is_active"); - - b.Property("MMSI") - .IsRequired() - .HasMaxLength(9) - .HasColumnType("TEXT") - .HasColumnName("mmsi"); - - b.Property("Name") - .IsRequired() - .HasColumnType("TEXT") - .HasColumnName("name"); - - b.Property("OperatorId") - .HasColumnType("INTEGER") - .HasColumnName("operator_id"); - - b.Property("Passengers") - .HasColumnType("INTEGER") - .HasColumnName("passengers"); - - b.Property("Tonnage") - .HasColumnType("INTEGER") - .HasColumnName("tonnage"); - - b.Property("VesselId") - .HasColumnType("INTEGER") - .HasColumnName("vessel_id"); - - b.Property("VesselTypeId") - .HasColumnType("INTEGER") - .HasColumnName("vessel_type_id"); - - b.HasKey("Id"); - - b.HasIndex("FlagId"); - - b.HasIndex("OperatorId"); - - b.HasIndex("VesselId"); - - b.HasIndex("VesselTypeId"); - - b.ToTable("REGISTRATION_HISTORY", null, t => - { - t.HasCheckConstraint("CK_Callsign_Characters", "callsign GLOB '[A-Z0-9]*'"); - - t.HasCheckConstraint("CK_MMSI_Length", "length(mmsi) = 9"); - - t.HasCheckConstraint("CK_MMSI_Numeric", "mmsi GLOB '[0-9]*'"); - }); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Sighting", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasColumnName("id"); - - b.Property("Date") - .HasColumnType("DATETIME") - .HasColumnName("date"); - - b.Property("IsMyVoyage") - .HasColumnType("INTEGER") - .HasColumnName("is_my_voyage"); - - b.Property("LocationId") - .HasColumnType("INTEGER") - .HasColumnName("location_id"); - - b.Property("VesselId") - .HasColumnType("INTEGER") - .HasColumnName("vessel_id"); - - b.Property("VoyageId") - .HasColumnType("INTEGER") - .HasColumnName("voyage_id"); - - b.HasKey("Id"); - - b.HasIndex("LocationId"); - - b.HasIndex("VesselId"); - - b.HasIndex("VoyageId"); - - b.ToTable("SIGHTING", (string)null); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.User", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasColumnName("id"); - - b.Property("Password") - .IsRequired() - .HasColumnType("TEXT") - .HasColumnName("Password"); - - b.Property("UserName") - .IsRequired() - .HasColumnType("TEXT") - .HasColumnName("UserName"); - - b.HasKey("Id"); - - b.HasIndex("UserName") - .IsUnique(); - - b.ToTable("USER", (string)null); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Vessel", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasColumnName("id"); - - b.Property("Beam") - .HasColumnType("INTEGER") - .HasColumnName("beam"); - - b.Property("Built") - .HasColumnType("INTEGER") - .HasColumnName("built"); - - b.Property("Draught") - .HasColumnType("TEXT") - .HasColumnName("draught"); - - b.Property("IMO") - .IsRequired() - .HasMaxLength(7) - .HasColumnType("TEXT") - .HasColumnName("imo"); - - b.Property("Length") - .HasColumnType("INTEGER") - .HasColumnName("length"); - - b.HasKey("Id"); - - b.HasIndex("IMO") - .IsUnique(); - - b.ToTable("VESSEL", null, t => - { - t.HasCheckConstraint("CK_IMO_Length", "length(imo) = 7"); - - t.HasCheckConstraint("CK_IMO_Numeric", "imo GLOB '[0-9]*'"); - }); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.VesselType", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasColumnName("id"); - - b.Property("Name") - .IsRequired() - .HasColumnType("TEXT") - .HasColumnName("name"); - - b.HasKey("Id"); - - b.HasIndex("Name") - .IsUnique(); - - b.ToTable("VESSEL_TYPE", (string)null); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Voyage", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasColumnName("id"); - - b.Property("Number") - .IsRequired() - .HasColumnType("TEXT") - .HasColumnName("number"); - - b.Property("OperatorId") - .HasColumnType("INTEGER") - .HasColumnName("operator_id"); - - b.Property("VesselId") - .HasColumnType("INTEGER") - .HasColumnName("vessel_id"); - - b.HasKey("Id"); - - b.HasIndex("OperatorId"); - - b.HasIndex("VesselId"); - - b.ToTable("VOYAGE", (string)null); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.VoyageEvent", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasColumnName("id"); - - b.Property("Date") - .HasColumnType("DATETIME") - .HasColumnName("arrival"); - - b.Property("EventType") - .HasColumnType("INTEGER") - .HasColumnName("event_type"); - - b.Property("PortId") - .HasColumnType("INTEGER") - .HasColumnName("port_id"); - - b.Property("VoyageId") - .HasColumnType("INTEGER") - .HasColumnName("voyage_id"); - - b.HasKey("Id"); - - b.HasIndex("PortId"); - - b.HasIndex("VoyageId"); - - b.ToTable("VOYAGE_EVENT", (string)null); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Reporting.FlagStatistics", b => - { - b.Property("Code") - .HasColumnType("TEXT"); - - b.Property("Locations") - .HasColumnType("INTEGER"); - - b.Property("Name") - .HasColumnType("TEXT"); - - b.Property("Sightings") - .HasColumnType("INTEGER"); - - b.Property("Vessels") - .HasColumnType("INTEGER"); - - b.ToTable("FlagStatistics"); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Reporting.LocationStatistics", b => - { - b.Property("Name") - .HasColumnType("TEXT"); - - b.Property("Sightings") - .HasColumnType("INTEGER"); - - b.Property("Vessels") - .HasColumnType("INTEGER"); - - b.ToTable("LocationStatistics"); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Reporting.MyVoyages", b => - { - b.Property("Date") - .HasColumnType("TEXT"); - - b.Property("IMO") - .HasColumnType("TEXT"); - - b.Property("Location") - .HasColumnType("TEXT"); - - b.Property("Vessel") - .HasColumnType("TEXT"); - - b.Property("VesselId") - .HasColumnType("INTEGER"); - - b.ToTable("MyVoyages"); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Reporting.OperatorStatistics", b => - { - b.Property("Locations") - .HasColumnType("INTEGER"); - - b.Property("Name") - .HasColumnType("TEXT"); - - b.Property("Sightings") - .HasColumnType("INTEGER"); - - b.Property("Vessels") - .HasColumnType("INTEGER"); - - b.ToTable("OperatorStatistics"); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Reporting.SightingsByMonth", b => - { - b.Property("Locations") - .HasColumnType("INTEGER"); - - b.Property("Month") - .HasColumnType("INTEGER"); - - b.Property("Sightings") - .HasColumnType("INTEGER"); - - b.Property("Vessels") - .HasColumnType("INTEGER"); - - b.Property("Year") - .HasColumnType("INTEGER"); - - b.ToTable("SightingsByMonth"); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Reporting.VesselTypeStatistics", b => - { - b.Property("Locations") - .HasColumnType("INTEGER"); - - b.Property("Name") - .HasColumnType("TEXT"); - - b.Property("Sightings") - .HasColumnType("INTEGER"); - - b.Property("Vessels") - .HasColumnType("INTEGER"); - - b.ToTable("VesselTypeStatistics"); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Port", b => - { - b.HasOne("ShippingRecorder.Entities.Db.Country", "Country") - .WithMany() - .HasForeignKey("CountryId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.Navigation("Country"); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.RegistrationHistory", b => - { - b.HasOne("ShippingRecorder.Entities.Db.Country", "Flag") - .WithMany() - .HasForeignKey("FlagId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.HasOne("ShippingRecorder.Entities.Db.Operator", "Operator") - .WithMany() - .HasForeignKey("OperatorId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.HasOne("ShippingRecorder.Entities.Db.Vessel", null) - .WithMany("RegistrationHistory") - .HasForeignKey("VesselId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.HasOne("ShippingRecorder.Entities.Db.VesselType", "VesselType") - .WithMany() - .HasForeignKey("VesselTypeId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.Navigation("Flag"); - - b.Navigation("Operator"); - - b.Navigation("VesselType"); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Sighting", b => - { - b.HasOne("ShippingRecorder.Entities.Db.Location", "Location") - .WithMany() - .HasForeignKey("LocationId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.HasOne("ShippingRecorder.Entities.Db.Vessel", "Vessel") - .WithMany() - .HasForeignKey("VesselId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.HasOne("ShippingRecorder.Entities.Db.Voyage", "Voyage") - .WithMany() - .HasForeignKey("VoyageId") - .OnDelete(DeleteBehavior.Restrict); - - b.Navigation("Location"); - - b.Navigation("Vessel"); - - b.Navigation("Voyage"); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Voyage", b => - { - b.HasOne("ShippingRecorder.Entities.Db.Operator", "Operator") - .WithMany() - .HasForeignKey("OperatorId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.HasOne("ShippingRecorder.Entities.Db.Vessel", "Vessel") - .WithMany() - .HasForeignKey("VesselId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Operator"); - - b.Navigation("Vessel"); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.VoyageEvent", b => - { - b.HasOne("ShippingRecorder.Entities.Db.Port", "Port") - .WithMany() - .HasForeignKey("PortId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.HasOne("ShippingRecorder.Entities.Db.Voyage", null) - .WithMany("Events") - .HasForeignKey("VoyageId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.Navigation("Port"); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Vessel", b => - { - b.Navigation("RegistrationHistory"); - }); - - modelBuilder.Entity("ShippingRecorder.Entities.Db.Voyage", b => - { - b.Navigation("Events"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/src/ShippingRecorder.Data/Migrations/20260111174920_VoyageVessel.cs b/src/ShippingRecorder.Data/Migrations/20260111174920_VoyageVessel.cs deleted file mode 100644 index 6a990f1..0000000 --- a/src/ShippingRecorder.Data/Migrations/20260111174920_VoyageVessel.cs +++ /dev/null @@ -1,54 +0,0 @@ -using System.Diagnostics.CodeAnalysis; -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -namespace ShippingRecorder.Data.Migrations -{ - /// - [ExcludeFromCodeCoverage] - public partial class VoyageVessel : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.Sql("PRAGMA foreign_keys = ON;"); - - migrationBuilder.AddColumn( - name: "vessel_id", - table: "VOYAGE", - type: "INTEGER", - nullable: false, - defaultValue: 0L); - - migrationBuilder.CreateIndex( - name: "IX_VOYAGE_vessel_id", - table: "VOYAGE", - column: "vessel_id"); - - migrationBuilder.AddForeignKey( - name: "FK_VOYAGE_VESSEL_vessel_id", - table: "VOYAGE", - column: "vessel_id", - principalTable: "VESSEL", - principalColumn: "id", - onDelete: ReferentialAction.Cascade); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropForeignKey( - name: "FK_VOYAGE_VESSEL_vessel_id", - table: "VOYAGE"); - - migrationBuilder.DropIndex( - name: "IX_VOYAGE_vessel_id", - table: "VOYAGE"); - - migrationBuilder.DropColumn( - name: "vessel_id", - table: "VOYAGE"); - } - } -} diff --git a/src/ShippingRecorder.Data/Migrations/20260111175439_VoyageEventDate.cs b/src/ShippingRecorder.Data/Migrations/20260111175439_VoyageEventDate.cs deleted file mode 100644 index 6e2c14d..0000000 --- a/src/ShippingRecorder.Data/Migrations/20260111175439_VoyageEventDate.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System.Diagnostics.CodeAnalysis; -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -namespace ShippingRecorder.Data.Migrations -{ - /// - [ExcludeFromCodeCoverage] - public partial class VoyageEventDate : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.RenameColumn( - name: "arrival", - table: "VOYAGE_EVENT", - newName: "date"); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.RenameColumn( - name: "date", - table: "VOYAGE_EVENT", - newName: "arrival"); - } - } -} diff --git a/src/ShippingRecorder.Data/Migrations/20260111175439_VoyageEventDate.Designer.cs b/src/ShippingRecorder.Data/Migrations/20260118084003_NonIMOVesselIdentifier.Designer.cs similarity index 97% rename from src/ShippingRecorder.Data/Migrations/20260111175439_VoyageEventDate.Designer.cs rename to src/ShippingRecorder.Data/Migrations/20260118084003_NonIMOVesselIdentifier.Designer.cs index 94c398b..50d119d 100644 --- a/src/ShippingRecorder.Data/Migrations/20260111175439_VoyageEventDate.Designer.cs +++ b/src/ShippingRecorder.Data/Migrations/20260118084003_NonIMOVesselIdentifier.Designer.cs @@ -11,8 +11,8 @@ namespace ShippingRecorder.Data.Migrations { [DbContext(typeof(ShippingRecorderDbContext))] - [Migration("20260111175439_VoyageEventDate")] - partial class VoyageEventDate + [Migration("20260118084003_NonIMOVesselIdentifier")] + partial class NonIMOVesselIdentifier { /// protected override void BuildTargetModel(ModelBuilder modelBuilder) @@ -333,11 +333,14 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) .HasColumnType("TEXT") .HasColumnName("draught"); - b.Property("IMO") + b.Property("Identifier") .IsRequired() - .HasMaxLength(7) .HasColumnType("TEXT") - .HasColumnName("imo"); + .HasColumnName("identifier"); + + b.Property("IsIMO") + .HasColumnType("INTEGER") + .HasColumnName("is_imo"); b.Property("Length") .HasColumnType("INTEGER") @@ -345,15 +348,10 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.HasKey("Id"); - b.HasIndex("IMO") + b.HasIndex("Identifier") .IsUnique(); - b.ToTable("VESSEL", null, t => - { - t.HasCheckConstraint("CK_IMO_Length", "length(imo) = 7"); - - t.HasCheckConstraint("CK_IMO_Numeric", "imo GLOB '[0-9]*'"); - }); + b.ToTable("VESSEL", (string)null); }); modelBuilder.Entity("ShippingRecorder.Entities.Db.VesselType", b => @@ -476,7 +474,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Property("Date") .HasColumnType("TEXT"); - b.Property("IMO") + b.Property("Identifier") .HasColumnType("TEXT"); b.Property("Location") diff --git a/src/ShippingRecorder.Data/Migrations/20251207050413_InitialCreation.cs b/src/ShippingRecorder.Data/Migrations/20260118084003_NonIMOVesselIdentifier.cs similarity index 73% rename from src/ShippingRecorder.Data/Migrations/20251207050413_InitialCreation.cs rename to src/ShippingRecorder.Data/Migrations/20260118084003_NonIMOVesselIdentifier.cs index e727318..5436e3f 100644 --- a/src/ShippingRecorder.Data/Migrations/20251207050413_InitialCreation.cs +++ b/src/ShippingRecorder.Data/Migrations/20260118084003_NonIMOVesselIdentifier.cs @@ -8,11 +8,13 @@ namespace ShippingRecorder.Data.Migrations { /// [ExcludeFromCodeCoverage] - public partial class InitialCreation : Migration + public partial class NonIMOVesselIdentifier : Migration { /// protected override void Up(MigrationBuilder migrationBuilder) { + migrationBuilder.Sql("PRAGMA foreign_keys = ON;"); + migrationBuilder.CreateTable( name: "COUNTRY", columns: table => new @@ -29,6 +31,37 @@ protected override void Up(MigrationBuilder migrationBuilder) table.CheckConstraint("CK_Code_Length", "length(code) = 2"); }); + migrationBuilder.CreateTable( + name: "FlagStatistics", + columns: table => new + { + Code = table.Column(type: "TEXT", nullable: true), + Name = table.Column(type: "TEXT", nullable: true), + Sightings = table.Column(type: "INTEGER", nullable: true), + Locations = table.Column(type: "INTEGER", nullable: true), + Vessels = table.Column(type: "INTEGER", nullable: true) + }, + constraints: table => + { + }); + + migrationBuilder.CreateTable( + name: "JOB_STATUS", + columns: table => new + { + id = table.Column(type: "INTEGER", nullable: false) + .Annotation("Sqlite:Autoincrement", true), + name = table.Column(type: "TEXT", nullable: false), + parameters = table.Column(type: "TEXT", nullable: true), + start = table.Column(type: "DATETIME", nullable: false), + end = table.Column(type: "DATETIME", nullable: true), + error = table.Column(type: "TEXT", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_JOB_STATUS", x => x.id); + }); + migrationBuilder.CreateTable( name: "LOCATION", columns: table => new @@ -42,6 +75,32 @@ protected override void Up(MigrationBuilder migrationBuilder) table.PrimaryKey("PK_LOCATION", x => x.id); }); + migrationBuilder.CreateTable( + name: "LocationStatistics", + columns: table => new + { + Name = table.Column(type: "TEXT", nullable: true), + Sightings = table.Column(type: "INTEGER", nullable: true), + Vessels = table.Column(type: "INTEGER", nullable: true) + }, + constraints: table => + { + }); + + migrationBuilder.CreateTable( + name: "MyVoyages", + columns: table => new + { + Date = table.Column(type: "TEXT", nullable: false), + Location = table.Column(type: "TEXT", nullable: true), + Identifier = table.Column(type: "TEXT", nullable: true), + Vessel = table.Column(type: "TEXT", nullable: true), + VesselId = table.Column(type: "INTEGER", nullable: false) + }, + constraints: table => + { + }); + migrationBuilder.CreateTable( name: "OPERATOR", columns: table => new @@ -55,6 +114,33 @@ protected override void Up(MigrationBuilder migrationBuilder) table.PrimaryKey("PK_OPERATOR", x => x.id); }); + migrationBuilder.CreateTable( + name: "OperatorStatistics", + columns: table => new + { + Name = table.Column(type: "TEXT", nullable: true), + Sightings = table.Column(type: "INTEGER", nullable: true), + Locations = table.Column(type: "INTEGER", nullable: true), + Vessels = table.Column(type: "INTEGER", nullable: true) + }, + constraints: table => + { + }); + + migrationBuilder.CreateTable( + name: "SightingsByMonth", + columns: table => new + { + Year = table.Column(type: "INTEGER", nullable: false), + Month = table.Column(type: "INTEGER", nullable: false), + Sightings = table.Column(type: "INTEGER", nullable: true), + Locations = table.Column(type: "INTEGER", nullable: true), + Vessels = table.Column(type: "INTEGER", nullable: true) + }, + constraints: table => + { + }); + migrationBuilder.CreateTable( name: "USER", columns: table => new @@ -75,7 +161,8 @@ protected override void Up(MigrationBuilder migrationBuilder) { id = table.Column(type: "INTEGER", nullable: false) .Annotation("Sqlite:Autoincrement", true), - imo = table.Column(type: "TEXT", maxLength: 7, nullable: false), + identifier = table.Column(type: "TEXT", nullable: false), + is_imo = table.Column(type: "INTEGER", nullable: false), built = table.Column(type: "INTEGER", nullable: true), draught = table.Column(type: "TEXT", nullable: true), length = table.Column(type: "INTEGER", nullable: true), @@ -84,8 +171,6 @@ protected override void Up(MigrationBuilder migrationBuilder) constraints: table => { table.PrimaryKey("PK_VESSEL", x => x.id); - table.CheckConstraint("CK_IMO_Length", "length(imo) = 7"); - table.CheckConstraint("CK_IMO_Numeric", "imo GLOB '[0-9]*'"); }); migrationBuilder.CreateTable( @@ -101,6 +186,19 @@ protected override void Up(MigrationBuilder migrationBuilder) table.PrimaryKey("PK_VESSEL_TYPE", x => x.id); }); + migrationBuilder.CreateTable( + name: "VesselTypeStatistics", + columns: table => new + { + Name = table.Column(type: "TEXT", nullable: true), + Sightings = table.Column(type: "INTEGER", nullable: true), + Locations = table.Column(type: "INTEGER", nullable: true), + Vessels = table.Column(type: "INTEGER", nullable: true) + }, + constraints: table => + { + }); + migrationBuilder.CreateTable( name: "PORT", columns: table => new @@ -131,6 +229,7 @@ protected override void Up(MigrationBuilder migrationBuilder) id = table.Column(type: "INTEGER", nullable: false) .Annotation("Sqlite:Autoincrement", true), operator_id = table.Column(type: "INTEGER", nullable: false), + vessel_id = table.Column(type: "INTEGER", nullable: false), number = table.Column(type: "TEXT", nullable: false) }, constraints: table => @@ -142,6 +241,12 @@ protected override void Up(MigrationBuilder migrationBuilder) principalTable: "OPERATOR", principalColumn: "id", onDelete: ReferentialAction.Restrict); + table.ForeignKey( + name: "FK_VOYAGE_VESSEL_vessel_id", + column: x => x.vessel_id, + principalTable: "VESSEL", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); }); migrationBuilder.CreateTable( @@ -241,7 +346,7 @@ protected override void Up(MigrationBuilder migrationBuilder) voyage_id = table.Column(type: "INTEGER", nullable: false), event_type = table.Column(type: "INTEGER", nullable: false), port_id = table.Column(type: "INTEGER", nullable: false), - arrival = table.Column(type: "DATETIME", nullable: false) + date = table.Column(type: "DATETIME", nullable: false) }, constraints: table => { @@ -337,9 +442,9 @@ protected override void Up(MigrationBuilder migrationBuilder) unique: true); migrationBuilder.CreateIndex( - name: "IX_VESSEL_imo", + name: "IX_VESSEL_identifier", table: "VESSEL", - column: "imo", + column: "identifier", unique: true); migrationBuilder.CreateIndex( @@ -353,6 +458,11 @@ protected override void Up(MigrationBuilder migrationBuilder) table: "VOYAGE", column: "operator_id"); + migrationBuilder.CreateIndex( + name: "IX_VOYAGE_vessel_id", + table: "VOYAGE", + column: "vessel_id"); + migrationBuilder.CreateIndex( name: "IX_VOYAGE_EVENT_port_id", table: "VOYAGE_EVENT", @@ -367,15 +477,36 @@ protected override void Up(MigrationBuilder migrationBuilder) /// protected override void Down(MigrationBuilder migrationBuilder) { + migrationBuilder.DropTable( + name: "FlagStatistics"); + + migrationBuilder.DropTable( + name: "JOB_STATUS"); + + migrationBuilder.DropTable( + name: "LocationStatistics"); + + migrationBuilder.DropTable( + name: "MyVoyages"); + + migrationBuilder.DropTable( + name: "OperatorStatistics"); + migrationBuilder.DropTable( name: "REGISTRATION_HISTORY"); migrationBuilder.DropTable( name: "SIGHTING"); + migrationBuilder.DropTable( + name: "SightingsByMonth"); + migrationBuilder.DropTable( name: "USER"); + migrationBuilder.DropTable( + name: "VesselTypeStatistics"); + migrationBuilder.DropTable( name: "VOYAGE_EVENT"); @@ -385,9 +516,6 @@ protected override void Down(MigrationBuilder migrationBuilder) migrationBuilder.DropTable( name: "LOCATION"); - migrationBuilder.DropTable( - name: "VESSEL"); - migrationBuilder.DropTable( name: "PORT"); @@ -399,6 +527,9 @@ protected override void Down(MigrationBuilder migrationBuilder) migrationBuilder.DropTable( name: "OPERATOR"); + + migrationBuilder.DropTable( + name: "VESSEL"); } } } diff --git a/src/ShippingRecorder.Data/Migrations/ShippingRecorderDbContextModelSnapshot.cs b/src/ShippingRecorder.Data/Migrations/ShippingRecorderDbContextModelSnapshot.cs index 5e5ee29..05fc973 100644 --- a/src/ShippingRecorder.Data/Migrations/ShippingRecorderDbContextModelSnapshot.cs +++ b/src/ShippingRecorder.Data/Migrations/ShippingRecorderDbContextModelSnapshot.cs @@ -332,11 +332,14 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasColumnType("TEXT") .HasColumnName("draught"); - b.Property("IMO") + b.Property("Identifier") .IsRequired() - .HasMaxLength(7) .HasColumnType("TEXT") - .HasColumnName("imo"); + .HasColumnName("identifier"); + + b.Property("IsIMO") + .HasColumnType("INTEGER") + .HasColumnName("is_imo"); b.Property("Length") .HasColumnType("INTEGER") @@ -344,15 +347,10 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.HasKey("Id"); - b.HasIndex("IMO") + b.HasIndex("Identifier") .IsUnique(); - b.ToTable("VESSEL", null, t => - { - t.HasCheckConstraint("CK_IMO_Length", "length(imo) = 7"); - - t.HasCheckConstraint("CK_IMO_Numeric", "imo GLOB '[0-9]*'"); - }); + b.ToTable("VESSEL", (string)null); }); modelBuilder.Entity("ShippingRecorder.Entities.Db.VesselType", b => @@ -475,7 +473,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("Date") .HasColumnType("TEXT"); - b.Property("IMO") + b.Property("Identifier") .HasColumnType("TEXT"); b.Property("Location") diff --git a/src/ShippingRecorder.Data/ShippingRecorder.Data.csproj b/src/ShippingRecorder.Data/ShippingRecorder.Data.csproj index b5ad6ba..194c5ae 100644 --- a/src/ShippingRecorder.Data/ShippingRecorder.Data.csproj +++ b/src/ShippingRecorder.Data/ShippingRecorder.Data.csproj @@ -3,7 +3,7 @@ net9.0 ShippingRecorder.Data - 1.8.0.0 + 1.9.0.0 Dave Walker Copyright (c) Dave Walker 2025 Dave Walker @@ -15,7 +15,7 @@ https://github.com/davewalker5/ShippingRecorder MIT false - 1.8.0.0 + 1.9.0.0 NU1900 diff --git a/src/ShippingRecorder.Data/ShippingRecorderDbContext.cs b/src/ShippingRecorder.Data/ShippingRecorderDbContext.cs index d17b24f..cde223f 100644 --- a/src/ShippingRecorder.Data/ShippingRecorderDbContext.cs +++ b/src/ShippingRecorder.Data/ShippingRecorderDbContext.cs @@ -110,19 +110,15 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) modelBuilder.Entity(entity => { - entity.ToTable("VESSEL", tb => - { - tb.HasCheckConstraint("CK_IMO_Length", "length(imo) = 7"); - tb.HasCheckConstraint("CK_IMO_Numeric", "imo GLOB '[0-9]*'"); - }); - + entity.ToTable("VESSEL"); entity.Property(e => e.Id).HasColumnName("id").ValueGeneratedOnAdd(); - entity.Property(e => e.IMO).IsRequired().HasColumnName("imo").HasMaxLength(7); + entity.Property(e => e.Identifier).IsRequired().HasColumnName("identifier"); + entity.Property(e => e.IsIMO).HasColumnName("is_imo"); entity.Property(e => e.Built).HasColumnName("built"); entity.Property(e => e.Draught).HasColumnName("draught"); entity.Property(e => e.Length).HasColumnName("length"); entity.Property(e => e.Beam).HasColumnName("beam"); - entity.HasIndex(e => e.IMO).IsUnique(); + entity.HasIndex(e => e.Identifier).IsUnique(); entity.HasMany(e => e.RegistrationHistory).WithOne().HasForeignKey(h => h.VesselId).OnDelete(DeleteBehavior.Restrict); }); diff --git a/src/ShippingRecorder.DataExchange/Entities/ExportableSighting.cs b/src/ShippingRecorder.DataExchange/Entities/ExportableSighting.cs index 927bf92..79ab881 100644 --- a/src/ShippingRecorder.DataExchange/Entities/ExportableSighting.cs +++ b/src/ShippingRecorder.DataExchange/Entities/ExportableSighting.cs @@ -17,8 +17,8 @@ public class ExportableSighting : ExportableEntityBase [Export("Location", 2)] public string Location { get; set; } - [Export("IMO", 3)] - public string IMO { get; set; } + [Export("Identifier", 3)] + public string Identifier { get; set; } [Export("Voyage", 4)] public string VoyageNumber { get; set; } @@ -33,7 +33,7 @@ public static ExportableSighting FromCsv(string record) { Date = DateTime.ParseExact(words[0].Replace("\"", "").Trim(), DateFormat, CultureInfo.CurrentCulture), Location = words[1].Replace("\"", "").Trim(), - IMO = words[2].Replace("\"", "").Trim().CleanCode(), + Identifier = words[2].Replace("\"", "").Trim().CleanCode(), VoyageNumber = words[3].Replace("\"", "").Trim().Clean(), IsMyVoyage = words[4].Replace("\"", "").Trim().Equals("True", StringComparison.OrdinalIgnoreCase) }; diff --git a/src/ShippingRecorder.DataExchange/Entities/ExportableVessel.cs b/src/ShippingRecorder.DataExchange/Entities/ExportableVessel.cs index 06178c1..2e0ce98 100644 --- a/src/ShippingRecorder.DataExchange/Entities/ExportableVessel.cs +++ b/src/ShippingRecorder.DataExchange/Entities/ExportableVessel.cs @@ -9,7 +9,8 @@ namespace ShippingRecorder.DataExchange.Entities public class ExportableVessel : ExportableEntityBase { /// - /// IMO + /// Identifier + /// Identifier is an IMO /// Year built (may be blank) /// Maximum draught (may be blank) /// Length (may be blank) @@ -26,54 +27,57 @@ public class ExportableVessel : ExportableEntityBase /// Flag (Country Code) /// Operator Name /// - public const string CsvRecordPattern = @"^""\d{7}"",""\d*"",""[0-9.]*"",""\d*"",""\d*"",""\d*"",""\d*"",""\d*"",""\d*"",""\d*"",""[^""]+"",""[^""\s]+"",""\d{9}"",""[^""]+"",""[A-Za-z0-9]{2}"",""[^""]+"".?$"; + public const string CsvRecordPattern = @"^""\d{7}"",""True|False"",""\d*"",""[0-9.]*"",""\d*"",""\d*"",""\d*"",""\d*"",""\d*"",""\d*"",""\d*"",""[^""]+"",""[^""\s]+"",""\d{9}"",""[^""]+"",""[A-Za-z0-9]{2}"",""[^""]+"".?$"; - [Export("IMO", 1)] - public string IMO { get; set; } + [Export("Identifier", 1)] + public string Identifier { get; set; } - [Export("Year Built", 2)] + [Export("Is IMO", 2)] + public bool IsIMO { get; set; } + + [Export("Year Built", 3)] public int? Built { get; set; } - [Export("Draught", 3)] + [Export("Draught", 4)] public decimal? Draught { get; set; } - [Export("Length", 4)] + [Export("Length", 5)] public int? Length { get; set; } - [Export("Beam", 5)] + [Export("Beam", 6)] public int? Beam { get; set; } - [Export("Tonnage", 6)] + [Export("Tonnage", 7)] public int? Tonnage { get; set; } - [Export("Passengers", 7)] + [Export("Passengers", 8)] public int? Passengers { get; set; } - [Export("Crew", 8)] + [Export("Crew", 9)] public int? Crew { get; set; } - [Export("Decks", 9)] + [Export("Decks", 10)] public int? Decks { get; set; } - [Export("Cabins", 10)] + [Export("Cabins", 11)] public int? Cabins { get; set; } - [Export("Name", 11)] + [Export("Name", 12)] public string Name { get; set; } - [Export("Callsign", 12)] + [Export("Callsign", 13)] public string Callsign { get; set; } - [Export("MMSI", 13)] + [Export("MMSI", 14)] public string MMSI { get; set; } - [Export("Type", 14)] + [Export("Type", 15)] public string VesselType { get; set; } - [Export("Flag", 15)] + [Export("Flag", 16)] public string Flag { get; set; } - [Export("Operator", 16)] + [Export("Operator", 17)] public string Operator { get; set; } public static ExportableVessel FromCsv(string record) @@ -81,22 +85,23 @@ public static ExportableVessel FromCsv(string record) string[] words = record.Split(["\",\""], StringSplitOptions.None); return new ExportableVessel { - IMO = words[0].Replace("\"", "").Trim().CleanCode(), - Built = ExtractInteger(words[1].Replace("\"", "").Trim()), - Draught = ExtractDecimal(words[2].Replace("\"", "").Trim()), - Length = ExtractInteger(words[3].Replace("\"", "").Trim()), - Beam = ExtractInteger(words[4].Replace("\"", "").Trim()), - Tonnage = ExtractInteger(words[5].Replace("\"", "").Trim()), - Passengers = ExtractInteger(words[6].Replace("\"", "").Trim()), - Crew = ExtractInteger(words[7].Replace("\"", "").Trim()), - Decks = ExtractInteger(words[8].Replace("\"", "").Trim()), - Cabins = ExtractInteger(words[9].Replace("\"", "").Trim()), - Name = words[10].Replace("\"", "").Trim(), - Callsign = words[11].Replace("\"", "").Trim().CleanCode(), - MMSI = words[12].Replace("\"", "").Trim().CleanCode(), - VesselType = words[13].Replace("\"", "").Trim().TitleCase(), - Flag = words[14].Replace("\"", "").Trim().CleanCode(), - Operator = words[15].Replace("\"", "").Trim().TitleCase() + Identifier = words[0].Replace("\"", "").Trim().CleanCode(), + IsIMO = words[1].Replace("\"", "").Trim().Equals("True", StringComparison.OrdinalIgnoreCase), + Built = ExtractInteger(words[2].Replace("\"", "").Trim()), + Draught = ExtractDecimal(words[3].Replace("\"", "").Trim()), + Length = ExtractInteger(words[4].Replace("\"", "").Trim()), + Beam = ExtractInteger(words[5].Replace("\"", "").Trim()), + Tonnage = ExtractInteger(words[6].Replace("\"", "").Trim()), + Passengers = ExtractInteger(words[7].Replace("\"", "").Trim()), + Crew = ExtractInteger(words[8].Replace("\"", "").Trim()), + Decks = ExtractInteger(words[9].Replace("\"", "").Trim()), + Cabins = ExtractInteger(words[10].Replace("\"", "").Trim()), + Name = words[11].Replace("\"", "").Trim(), + Callsign = words[12].Replace("\"", "").Trim().CleanCode(), + MMSI = words[13].Replace("\"", "").Trim().CleanCode(), + VesselType = words[14].Replace("\"", "").Trim().TitleCase(), + Flag = words[15].Replace("\"", "").Trim().CleanCode(), + Operator = words[16].Replace("\"", "").Trim().TitleCase() }; } diff --git a/src/ShippingRecorder.DataExchange/Entities/ExportableVoyage.cs b/src/ShippingRecorder.DataExchange/Entities/ExportableVoyage.cs index d4c2d2b..87429e9 100644 --- a/src/ShippingRecorder.DataExchange/Entities/ExportableVoyage.cs +++ b/src/ShippingRecorder.DataExchange/Entities/ExportableVoyage.cs @@ -1,6 +1,5 @@ using System; using System.Diagnostics.CodeAnalysis; -using System.Globalization; using ShippingRecorder.BusinessLogic.Extensions; using ShippingRecorder.DataExchange.Attributes; @@ -10,6 +9,7 @@ namespace ShippingRecorder.DataExchange.Entities public class ExportableVoyage : ExportableEntityBase { /// + /// Vessel Identifier /// Operator /// Number /// Event Type @@ -18,8 +18,8 @@ public class ExportableVoyage : ExportableEntityBase /// public const string CsvRecordPattern = @"^""\d{7}"",(?:""(?!\s*"")[\s\S]*"",){3}""[A-Za-z]{2}[A-Za-z0-9]{3}"",""[0-9]{2}-[A-Za-z]{3}-[0-9]{4}"".?$"; - [Export("IMO", 1)] - public string IMO { get; set; } + [Export("Identifier", 1)] + public string Identifier { get; set; } [Export("Operator", 1)] public string Operator { get; set; } @@ -41,7 +41,7 @@ public static ExportableVoyage FromCsv(string record) string[] words = record.Split(["\",\""], StringSplitOptions.None); return new ExportableVoyage { - IMO = words[0].Replace("\"", "").Trim().CleanCode(), + Identifier = words[0].Replace("\"", "").Trim().CleanCode(), Operator = words[1].Replace("\"", "").Trim().TitleCase(), Number = words[2].Replace("\"", "").Trim().CleanCode(), EventType = words[3].Replace("\"", "").Trim(), diff --git a/src/ShippingRecorder.DataExchange/Extensions/SightingExtensions.cs b/src/ShippingRecorder.DataExchange/Extensions/SightingExtensions.cs index 57ef248..85f712f 100644 --- a/src/ShippingRecorder.DataExchange/Extensions/SightingExtensions.cs +++ b/src/ShippingRecorder.DataExchange/Extensions/SightingExtensions.cs @@ -16,7 +16,7 @@ public static ExportableSighting ToExportable(this Sighting sighting) { Date = sighting.Date, Location = sighting.Location.Name, - IMO = sighting.Vessel.IMO, + Identifier = sighting.Vessel.Identifier, VoyageNumber = sighting.Voyage?.Number, IsMyVoyage = sighting.IsMyVoyage }; diff --git a/src/ShippingRecorder.DataExchange/Extensions/VesselExtensions.cs b/src/ShippingRecorder.DataExchange/Extensions/VesselExtensions.cs index 868c356..ba4ccfc 100644 --- a/src/ShippingRecorder.DataExchange/Extensions/VesselExtensions.cs +++ b/src/ShippingRecorder.DataExchange/Extensions/VesselExtensions.cs @@ -15,7 +15,8 @@ public static class VesselExtensions public static ExportableVessel ToExportable(this Vessel vessel) => new() { - IMO = vessel.IMO, + Identifier = vessel.Identifier, + IsIMO = vessel.IsIMO, Built = vessel.Built, Draught = vessel.Draught, Length = vessel.Length, diff --git a/src/ShippingRecorder.DataExchange/Extensions/VoyageExtensions.cs b/src/ShippingRecorder.DataExchange/Extensions/VoyageExtensions.cs index 23bfe75..7bbc358 100644 --- a/src/ShippingRecorder.DataExchange/Extensions/VoyageExtensions.cs +++ b/src/ShippingRecorder.DataExchange/Extensions/VoyageExtensions.cs @@ -17,7 +17,7 @@ public static List ToExportable(this Voyage voyage) .Select(e => new ExportableVoyage { Operator = voyage.Operator.Name, - IMO = voyage.Vessel.IMO, + Identifier = voyage.Vessel.Identifier, Number = voyage.Number, EventType = e.EventType.ToString(), Port = e.Port.Code, diff --git a/src/ShippingRecorder.DataExchange/Import/SightingImporter.cs b/src/ShippingRecorder.DataExchange/Import/SightingImporter.cs index c893589..ac1b68e 100644 --- a/src/ShippingRecorder.DataExchange/Import/SightingImporter.cs +++ b/src/ShippingRecorder.DataExchange/Import/SightingImporter.cs @@ -50,7 +50,7 @@ protected override void Validate(ExportableSighting sighting, int recordCount) { ValidateField(x => x <= DateTime.Now, sighting.Date, "Date", recordCount); ValidateField(x => CheckLocationExists(x), sighting.Location, "Location", recordCount); - ValidateField(x => CheckVesselExists(x), sighting.IMO, "IMO", recordCount); + ValidateField(x => CheckVesselExists(x), sighting.Identifier, "Identifier", recordCount); ValidateField(x => CheckVoyageExists(x), sighting.VoyageNumber, "VoyageNumber", recordCount); } #pragma warning restore CS1998 @@ -63,7 +63,7 @@ protected override void Validate(ExportableSighting sighting, int recordCount) protected override async Task AddAsync(ExportableSighting sighting) { var location = _locations.First(x => x.Name == sighting.Location); - var vessel = _vessels.First(x => x.IMO == sighting.IMO); + var vessel = _vessels.First(x => x.Identifier == sighting.Identifier); long? voyageId = string.IsNullOrEmpty(sighting.VoyageNumber) ? null : _voyages.First(x => x.Number == sighting.VoyageNumber).Id; await _factory.Sightings.AddAsync(location.Id, voyageId, vessel.Id, sighting.Date, sighting.IsMyVoyage); } @@ -79,10 +79,10 @@ private bool CheckLocationExists(string name) /// /// Check a vessel exists /// - /// + /// /// - private bool CheckVesselExists(string imo) - => _vessels.FirstOrDefault(x => x.IMO == imo) != null; + private bool CheckVesselExists(string identifier) + => _vessels.FirstOrDefault(x => x.Identifier == identifier) != null; /// /// Check a voyage exists diff --git a/src/ShippingRecorder.DataExchange/Import/VesselImporter.cs b/src/ShippingRecorder.DataExchange/Import/VesselImporter.cs index fc9357e..fb7ef64 100644 --- a/src/ShippingRecorder.DataExchange/Import/VesselImporter.cs +++ b/src/ShippingRecorder.DataExchange/Import/VesselImporter.cs @@ -49,10 +49,10 @@ protected override ExportableVessel Inflate(string record) #pragma warning disable CS1998 protected override void Validate(ExportableVessel vessel, int recordCount) { - ValidateField(x => x.ValidateNumeric(7, 7), vessel.IMO, "IMO", recordCount); + ValidateField(x => x.ValidateNumeric(7, 7), vessel.Identifier, "Identifier", recordCount); ValidateField(x => x.ValidateNumeric(9, 9), vessel.MMSI, "MMSI", recordCount); ValidateField(x => x.ValidateAlpha(2, 2), vessel.Flag, "Flag", recordCount); - ValidateField(x => CheckVesselDoesNotExist(x), vessel.IMO, "IMO", recordCount); + ValidateField(x => CheckVesselDoesNotExist(x), vessel.Identifier, "Identifier", recordCount); ValidateField(x => CheckVesselTypeExists(x), vessel.VesselType, "VesselType", recordCount); ValidateField(x => CheckCountryExists(x), vessel.Flag, "Flag", recordCount); ValidateField(x => CheckOperatorExists(x), vessel.Operator, "Operator", recordCount); @@ -72,15 +72,15 @@ protected override async Task AddAsync(ExportableVessel vessel) // If the vessel exists, update its properties. Otherwise, create a new vessel long id; - var existing = await _factory.Vessels.GetAsync(x => x.IMO == vessel.IMO); + var existing = await _factory.Vessels.GetAsync(x => x.Identifier == vessel.Identifier); if (existing != null) { id = existing.Id; - await _factory.Vessels.UpdateAsync(id, vessel.IMO, vessel.Built, vessel.Draught, vessel.Length, vessel.Beam); + await _factory.Vessels.UpdateAsync(id, vessel.Identifier, vessel.IsIMO, vessel.Built, vessel.Draught, vessel.Length, vessel.Beam); } else { - id = (await _factory.Vessels.AddAsync(vessel.IMO, vessel.Built, vessel.Draught, vessel.Length, vessel.Beam)).Id; + id = (await _factory.Vessels.AddAsync(vessel.Identifier, vessel.IsIMO, vessel.Built, vessel.Draught, vessel.Length, vessel.Beam)).Id; } // Add the registration history @@ -102,11 +102,11 @@ protected override async Task AddAsync(ExportableVessel vessel) /// /// Check a vessel exists /// - /// + /// /// - private bool CheckVesselDoesNotExist(string imo) + private bool CheckVesselDoesNotExist(string identifier) { - var vessel = Task.Run(() => _factory.Vessels.GetAsync(x => x.IMO == imo)).Result; + var vessel = Task.Run(() => _factory.Vessels.GetAsync(x => x.Identifier == identifier)).Result; return vessel == null; } diff --git a/src/ShippingRecorder.DataExchange/Import/VoyageImporter.cs b/src/ShippingRecorder.DataExchange/Import/VoyageImporter.cs index ed8663b..704722a 100644 --- a/src/ShippingRecorder.DataExchange/Import/VoyageImporter.cs +++ b/src/ShippingRecorder.DataExchange/Import/VoyageImporter.cs @@ -49,7 +49,7 @@ protected override ExportableVoyage Inflate(string record) protected override void Validate(ExportableVoyage voyage, int recordCount) { ValidateField(x => CheckOperatorExists(x), voyage.Operator, "Operator", recordCount); - ValidateField(x => CheckVesselExists(x), voyage.IMO, "IMO", recordCount); + ValidateField(x => CheckVesselExists(x), voyage.Identifier, "Identifier", recordCount); ValidateField(x => CheckPortExists(x), voyage.Port, "Port", recordCount); ValidateField(x => Enum.TryParse(x, out _), voyage.EventType, "EventType", recordCount); ValidateField(x => CheckDateFormat(x), voyage.Date, "Date", recordCount); @@ -65,7 +65,7 @@ protected override async Task AddAsync(ExportableVoyage voyage) { // Load/create the voyage var op = _operators.First(x => x.Name == voyage.Operator); - var vessel = _vessels.First(x => x.IMO == voyage.IMO); + var vessel = _vessels.First(x => x.Identifier == voyage.Identifier); var imported = await _factory.Voyages.GetAsync(x => (x.OperatorId == op.Id) && (x.VesselId == vessel.Id) && (x.Number == voyage.Number)); imported ??= await _factory.Voyages.AddAsync(op.Id, vessel.Id, voyage.Number); @@ -87,10 +87,10 @@ private bool CheckOperatorExists(string name) /// /// Check a vessel exists /// - /// + /// /// - private bool CheckVesselExists(string imo) - => _vessels.FirstOrDefault(x => x.IMO == imo) != null; + private bool CheckVesselExists(string identifier) + => _vessels.FirstOrDefault(x => x.Identifier == identifier) != null; /// /// Check a port exists diff --git a/src/ShippingRecorder.DataExchange/ShippingRecorder.DataExchange.csproj b/src/ShippingRecorder.DataExchange/ShippingRecorder.DataExchange.csproj index 7db5e7d..15d9b10 100644 --- a/src/ShippingRecorder.DataExchange/ShippingRecorder.DataExchange.csproj +++ b/src/ShippingRecorder.DataExchange/ShippingRecorder.DataExchange.csproj @@ -3,7 +3,7 @@ net9.0 ShippingRecorder.DataExchange - 1.8.0.0 + 1.9.0.0 Dave Walker Copyright (c) Dave Walker 2025 Dave Walker @@ -15,7 +15,7 @@ https://github.com/davewalker5/ShippingRecorder MIT false - 1.8.0.0 + 1.9.0.0 NU1900 diff --git a/src/ShippingRecorder.Entities/Db/RegistrationHistory.cs b/src/ShippingRecorder.Entities/Db/RegistrationHistory.cs index 3201119..74ec56f 100644 --- a/src/ShippingRecorder.Entities/Db/RegistrationHistory.cs +++ b/src/ShippingRecorder.Entities/Db/RegistrationHistory.cs @@ -45,8 +45,8 @@ public class RegistrationHistory : ShippingRecorderEntityBase, IEquatable AddAsync(string imo, int? built, decimal? draught, int? length, int? beam); - Task AddIfNotExistsAsync(string imo, int? built, decimal? draught, int? length, int? beam); + Task AddAsync(string identifier, bool isIMO, int? built, decimal? draught, int? length, int? beam); + Task AddIfNotExistsAsync(string identifier, bool isIMO, int? built, decimal? draught, int? length, int? beam); Task GetAsync(Expression> predicate); IAsyncEnumerable ListAsync(Expression> predicate, int pageNumber, int pageSize); - Task UpdateAsync(long id, string imo, int? built, decimal? draught, int? length, int? beam); + Task UpdateAsync(long id, string identifier, bool isIMO, int? built, decimal? draught, int? length, int? beam); Task DeleteAsync(long id); } } \ No newline at end of file diff --git a/src/ShippingRecorder.Entities/Reporting/MyVoyages.cs b/src/ShippingRecorder.Entities/Reporting/MyVoyages.cs index 50a1612..06e58dc 100644 --- a/src/ShippingRecorder.Entities/Reporting/MyVoyages.cs +++ b/src/ShippingRecorder.Entities/Reporting/MyVoyages.cs @@ -10,7 +10,7 @@ public class MyVoyages { public DateTime Date { get; set; } public string Location { get; set; } - public string IMO { get; set; } + public string Identifier { get; set; } public string Vessel { get; set; } public long VesselId { get; set; } diff --git a/src/ShippingRecorder.Entities/ShippingRecorder.Entities.csproj b/src/ShippingRecorder.Entities/ShippingRecorder.Entities.csproj index 324ed77..27315b2 100644 --- a/src/ShippingRecorder.Entities/ShippingRecorder.Entities.csproj +++ b/src/ShippingRecorder.Entities/ShippingRecorder.Entities.csproj @@ -3,7 +3,7 @@ net9.0 ShippingRecorder.Entities - 1.8.0.0 + 1.9.0.0 Dave Walker Copyright (c) Dave Walker 2025 Dave Walker @@ -15,7 +15,7 @@ https://github.com/davewalker5/ShippingRecorder MIT false - 1.8.0.0 + 1.9.0.0 NU1900 diff --git a/src/ShippingRecorder.Manager/ShippingRecorder.Manager.csproj b/src/ShippingRecorder.Manager/ShippingRecorder.Manager.csproj index 51a5426..f6cfc43 100644 --- a/src/ShippingRecorder.Manager/ShippingRecorder.Manager.csproj +++ b/src/ShippingRecorder.Manager/ShippingRecorder.Manager.csproj @@ -3,8 +3,8 @@ Exe net9.0 - 1.8.0.0 - 1.8.0.0 + 1.9.0.0 + 1.9.0.0 Release;Debug NU1900 diff --git a/src/ShippingRecorder.Mvc/Controllers/SearchSightingsByVesselController.cs b/src/ShippingRecorder.Mvc/Controllers/SearchSightingsByVesselController.cs index e8d51d3..133584e 100644 --- a/src/ShippingRecorder.Mvc/Controllers/SearchSightingsByVesselController.cs +++ b/src/ShippingRecorder.Mvc/Controllers/SearchSightingsByVesselController.cs @@ -81,7 +81,7 @@ public async Task Index(SightingSearchByVesselViewModel model) { // Retrieve the aircraft with the specified registration number // then, if we have a valid aircraft, retrieve its sightings - Vessel vessel = await _vesselClient.GetAsync(model.IMO); + Vessel vessel = await _vesselClient.GetAsync(model.Identifier); if (vessel != null) { sightings = await _sightingClient.ListSightingsByVesselAsync(vessel.Id, page, _settings.SearchPageSize); diff --git a/src/ShippingRecorder.Mvc/Controllers/VesselsController.cs b/src/ShippingRecorder.Mvc/Controllers/VesselsController.cs index 758f5f5..adb26fe 100644 --- a/src/ShippingRecorder.Mvc/Controllers/VesselsController.cs +++ b/src/ShippingRecorder.Mvc/Controllers/VesselsController.cs @@ -7,12 +7,16 @@ using Microsoft.AspNetCore.Mvc; using ShippingRecorder.Entities.Interfaces; using HealthTracker.Mvc.Attributes; +using System.Text.RegularExpressions; namespace ShippingRecorder.Mvc.Controllers { [Authorize] public class VesselsController : ShippingRecorderControllerBase { + private static readonly Regex _IMORegex = new Regex(@"^\d{7}$", RegexOptions.Compiled); + private static readonly Regex _nonIMORegex = new Regex(@"^[\s\S]+$", RegexOptions.Compiled); + private readonly IVesselClient _vesselClient; private readonly IRegistrationHistoryClient _registrationClient; private readonly ICountryListGenerator _countryListGenerator; @@ -121,11 +125,18 @@ public async Task Add() [ValidateAntiForgeryToken] public async Task Add(AddVesselViewModel model) { + // If the model's nominally valid, validate the identifier + if (ModelState.IsValid && !IsValidVesselIdentifier(model.Vessel.Identifier, model.Vessel.IsIMO)) + { + ModelState.AddModelError("Vessel.Identifier", "Invalid vessel identifier"); + } + if (ModelState.IsValid) { _logger.LogDebug( $"Adding vessel: " + - $"IMO = {model.Vessel.IMO}, " + + $"Identifier = {model.Vessel.Identifier}, " + + $"Is IMO = {model.Vessel.IsIMO}, " + $"Built = {model.Vessel.Built}, " + $"Draught = {model.Vessel.Draught}, " + $"Length = {model.Vessel.Length}, " + @@ -144,7 +155,8 @@ public async Task Add(AddVesselViewModel model) $"Cabins = {model.Registration.Cabins}"); Vessel vessel = await _vesselClient.AddAsync( - model.Vessel.IMO, + model.Vessel.Identifier, + model.Vessel.IsIMO, model.Vessel.Built, model.Vessel.Draught, model.Vessel.Length, @@ -167,7 +179,7 @@ await _registrationClient.AddAsync( ModelState.Clear(); model.Clear(); - model.Message = $"Vessel '{vessel.IMO}' added successfully"; + model.Message = $"Vessel '{vessel.Identifier}' added successfully"; } else { @@ -212,11 +224,18 @@ public async Task Edit(VesselModel model) { IActionResult result; + // If the model's nominally valid, validate the identifier + if (ModelState.IsValid && !IsValidVesselIdentifier(model.Vessel.Identifier, model.Vessel.IsIMO)) + { + ModelState.AddModelError("Vessel.Identifier", "Invalid vessel identifier"); + } + if (ModelState.IsValid) { _logger.LogDebug( $"Updating vessel: ID = {model.Vessel.Id}, " + - $"IMO = {model.Vessel.IMO}, " + + $"Identifier = {model.Vessel.Identifier}, " + + $"Is IMO = {model.Vessel.IsIMO}, " + $"Built = {model.Vessel.Built}, " + $"Draught = {model.Vessel.Draught}, " + $"Length = {model.Vessel.Length}, " + @@ -236,7 +255,8 @@ public async Task Edit(VesselModel model) var vessel = await _vesselClient.UpdateAsync( model.Vessel.Id, - model.Vessel.IMO, + model.Vessel.Identifier, + model.Vessel.IsIMO, model.Vessel.Built, model.Vessel.Draught, model.Vessel.Length, @@ -298,8 +318,17 @@ public async Task ShowVesselDetails(long identifier) Registration = vessel.ActiveRegistrationHistory ?? new() { Date = DateTime.Today } }; - var title = $"Vessel Details for IMO {vessel.IMO}"; + var title = $"Vessel Details for Vessel {vessel.Identifier}"; return await LoadModalContent("_VesselDetails", model, title); } + + /// + /// Validate a vessel identifier based on whether it's an IMO or not + /// + /// + /// + /// + private static bool IsValidVesselIdentifier(string identifier, bool isIMO) + => isIMO ? _IMORegex.Matches(identifier.Trim()).Any() : _nonIMORegex.Matches(identifier.Trim()).Any(); } } diff --git a/src/ShippingRecorder.Mvc/Helpers/VesselListGenerator.cs b/src/ShippingRecorder.Mvc/Helpers/VesselListGenerator.cs index 10bdc74..f5d53ca 100644 --- a/src/ShippingRecorder.Mvc/Helpers/VesselListGenerator.cs +++ b/src/ShippingRecorder.Mvc/Helpers/VesselListGenerator.cs @@ -42,10 +42,10 @@ public async Task> Create() { foreach (var vessel in vessels) { - // Construct the list entry from the IMO and name, if available + // Construct the list entry from the vessel identifier and name, if available var text = vessel.ActiveRegistrationHistory != null ? - $"{vessel.IMO} - {vessel.ActiveRegistrationHistory?.Name}" : - vessel.IMO; + $"{vessel.Identifier} - {vessel.ActiveRegistrationHistory?.Name}" : + vessel.Identifier; list.Add(new SelectListItem() { Text = text, Value = vessel.Id.ToString() }); } diff --git a/src/ShippingRecorder.Mvc/Models/AddVesselViewModel.cs b/src/ShippingRecorder.Mvc/Models/AddVesselViewModel.cs index 348d74e..32b7b75 100644 --- a/src/ShippingRecorder.Mvc/Models/AddVesselViewModel.cs +++ b/src/ShippingRecorder.Mvc/Models/AddVesselViewModel.cs @@ -9,7 +9,7 @@ public class AddVesselViewModel : VesselModel public void Clear() { Vessel.Id = 0; - Vessel.IMO = ""; + Vessel.Identifier = ""; Vessel.Built = null; Vessel.Draught = null; Vessel.Length = null; diff --git a/src/ShippingRecorder.Mvc/Models/SightingDetailsViewModel.cs b/src/ShippingRecorder.Mvc/Models/SightingDetailsViewModel.cs index 09762a5..d00d16f 100644 --- a/src/ShippingRecorder.Mvc/Models/SightingDetailsViewModel.cs +++ b/src/ShippingRecorder.Mvc/Models/SightingDetailsViewModel.cs @@ -21,11 +21,11 @@ public class SightingDetailsViewModel : ShippingRecorderEntityBase [DisplayName("New Location")] public string NewLocation { get; set; } - [DisplayName("Vessel IMO")] - [StringLength(7, MinimumLength = 7, ErrorMessage = "IMO must be 7 digits long")] - [RegularExpression(@"^\d+$", ErrorMessage = "IMO must contain digits only")] - [Required(ErrorMessage = "You must provide a vessel IMO")] - public string IMO { get; set; } + [DisplayName("Vessel Identifier")] + [StringLength(7, MinimumLength = 7, ErrorMessage = "Vessel identifier must be 7 digits long")] + [RegularExpression(@"^\d+$", ErrorMessage = "Vessel identifier must contain digits only")] + [Required(ErrorMessage = "You must provide a vessel identifier")] + public string Identifier { get; set; } [DisplayName("Voyage")] public long VoyageId { get; set; } diff --git a/src/ShippingRecorder.Mvc/Models/SightingSearchByVesselViewModel.cs b/src/ShippingRecorder.Mvc/Models/SightingSearchByVesselViewModel.cs index 6d01386..75d9d13 100644 --- a/src/ShippingRecorder.Mvc/Models/SightingSearchByVesselViewModel.cs +++ b/src/ShippingRecorder.Mvc/Models/SightingSearchByVesselViewModel.cs @@ -5,10 +5,10 @@ namespace ShippingRecorder.Mvc.Models { public class SightingSearchByVesselViewModel : SightingSearchViewModelBase { - [DisplayName("IMO")] - [StringLength(7, MinimumLength = 7, ErrorMessage = "IMO must be 7 digits long")] - [RegularExpression(@"^\d+$", ErrorMessage = "IMO must contain digits only")] - [Required(ErrorMessage = "You must provide a vessel IMO")] - public string IMO { get; set; } + [DisplayName("Vessel Identifier")] + [StringLength(7, MinimumLength = 7, ErrorMessage = "Vessel identifier must be 7 digits long")] + [RegularExpression(@"^\d+$", ErrorMessage = "Vessel identifier must contain digits only")] + [Required(ErrorMessage = "You must provide a vessel identifier")] + public string Identifier { get; set; } } } diff --git a/src/ShippingRecorder.Mvc/ShippingRecorder.Mvc.csproj b/src/ShippingRecorder.Mvc/ShippingRecorder.Mvc.csproj index 2e269af..0b2fd1e 100644 --- a/src/ShippingRecorder.Mvc/ShippingRecorder.Mvc.csproj +++ b/src/ShippingRecorder.Mvc/ShippingRecorder.Mvc.csproj @@ -2,8 +2,8 @@ net9.0 - 1.8.0.0 - 1.8.0.0 + 1.9.0.0 + 1.9.0.0 enable false NU1900 diff --git a/src/ShippingRecorder.Mvc/Views/ConfirmDetails/Index.cshtml b/src/ShippingRecorder.Mvc/Views/ConfirmDetails/Index.cshtml index 8af3709..dc16207 100644 --- a/src/ShippingRecorder.Mvc/Views/ConfirmDetails/Index.cshtml +++ b/src/ShippingRecorder.Mvc/Views/ConfirmDetails/Index.cshtml @@ -40,9 +40,9 @@
- @Html.LabelFor(m => m.Vessel.IMO) + @Html.LabelFor(m => m.Vessel.Identifier)
- @Html.TextBoxFor(m => m.Vessel.IMO, htmlAttributes) + @Html.TextBoxFor(m => m.Vessel.Identifier, htmlAttributes)
diff --git a/src/ShippingRecorder.Mvc/Views/MyVoyages/Index.cshtml b/src/ShippingRecorder.Mvc/Views/MyVoyages/Index.cshtml index 16339a4..8bf9de5 100644 --- a/src/ShippingRecorder.Mvc/Views/MyVoyages/Index.cshtml +++ b/src/ShippingRecorder.Mvc/Views/MyVoyages/Index.cshtml @@ -88,7 +88,7 @@ @record.FormattedDate @record.Location - @record.IMO + @record.Identifier @record.Vessel diff --git a/src/ShippingRecorder.Mvc/Views/SearchSightingsByVessel/Index.cshtml b/src/ShippingRecorder.Mvc/Views/SearchSightingsByVessel/Index.cshtml index efffb2f..12938ac 100644 --- a/src/ShippingRecorder.Mvc/Views/SearchSightingsByVessel/Index.cshtml +++ b/src/ShippingRecorder.Mvc/Views/SearchSightingsByVessel/Index.cshtml @@ -14,7 +14,7 @@
- Search sightings by vessel IMO + Search sightings by vessel identifier

@@ -26,9 +26,9 @@
- @Html.LabelFor(m => m.IMO) + @Html.LabelFor(m => m.Identifier)
- @Html.TextBoxFor(m => m.IMO, new { + @Html.TextBoxFor(m => m.Identifier, new { @class = "form-control", type = "text", inputmode = "numeric", @@ -36,7 +36,7 @@ oninput = "this.value = this.value.replace(/[^0-9]/g, '')" })
- @Html.ValidationMessageFor(m => m.IMO, "", new { @class = "text-danger" }) + @Html.ValidationMessageFor(m => m.Identifier, "", new { @class = "text-danger" })
diff --git a/src/ShippingRecorder.Mvc/Views/Shared/_SightingSearchResults.cshtml b/src/ShippingRecorder.Mvc/Views/Shared/_SightingSearchResults.cshtml index e25aacb..48d5e47 100644 --- a/src/ShippingRecorder.Mvc/Views/Shared/_SightingSearchResults.cshtml +++ b/src/ShippingRecorder.Mvc/Views/Shared/_SightingSearchResults.cshtml @@ -13,7 +13,7 @@ - + @@ -27,7 +27,7 @@ - + @@ -25,7 +25,7 @@ - +
LocationIMOIdentifier Name Date Voyage
@sighting.Location.Name - @sighting.Vessel.IMO + @sighting.Vessel.Identifier diff --git a/src/ShippingRecorder.Mvc/Views/Shared/_SightingSummary.cshtml b/src/ShippingRecorder.Mvc/Views/Shared/_SightingSummary.cshtml index 041e975..0ede8f8 100644 --- a/src/ShippingRecorder.Mvc/Views/Shared/_SightingSummary.cshtml +++ b/src/ShippingRecorder.Mvc/Views/Shared/_SightingSummary.cshtml @@ -15,7 +15,7 @@
Last Seen LocationIMOIdentifier Name Voyage My Voyage
@Model.Sighting.Date.ToShortDateString() @Model.Sighting.Location.Name@Model.Sighting.Vessel.IMO@Model.Sighting.Vessel.Identifier @vesselName @Model.Sighting.Voyage?.Number diff --git a/src/ShippingRecorder.Mvc/Views/Shared/_VesselProperties.cshtml b/src/ShippingRecorder.Mvc/Views/Shared/_VesselProperties.cshtml index 0c0608a..df4eaf1 100644 --- a/src/ShippingRecorder.Mvc/Views/Shared/_VesselProperties.cshtml +++ b/src/ShippingRecorder.Mvc/Views/Shared/_VesselProperties.cshtml @@ -3,18 +3,20 @@ @{ var htmlAttributes = HtmlAttributesBuilder.IntegerAttributes(Model.Editable); + Dictionary identifierAttributes = HtmlAttributesBuilder.FormControlAttributes(Model.Editable); var draughtAttributes = HtmlAttributesBuilder.DecimalAttributes(Model.Editable); } @Html.HiddenFor(m => m.Vessel.Id) +@Html.HiddenFor(m => m.Vessel.IsIMO)
- @Html.LabelFor(m => m.Vessel.IMO) + @Html.LabelFor(m => m.Vessel.Identifier)
- @Html.TextBoxFor(m => m.Vessel.IMO, htmlAttributes) + @Html.TextBoxFor(m => m.Vessel.Identifier, identifierAttributes)
- @Html.ValidationMessageFor(m => m.Vessel.IMO, "", new { @class = "text-danger" }) + @Html.ValidationMessageFor(m => m.Vessel.Identifier, "", new { @class = "text-danger" })
@Html.LabelFor(m => m.Vessel.Built) diff --git a/src/ShippingRecorder.Mvc/Views/Shared/_VoyageSearchResults.cshtml b/src/ShippingRecorder.Mvc/Views/Shared/_VoyageSearchResults.cshtml index d4e4019..bf82734 100644 --- a/src/ShippingRecorder.Mvc/Views/Shared/_VoyageSearchResults.cshtml +++ b/src/ShippingRecorder.Mvc/Views/Shared/_VoyageSearchResults.cshtml @@ -30,7 +30,7 @@ var vesselName = voyage.Vessel.ActiveRegistrationHistory?.Name ?? ""; if (string.IsNullOrEmpty(vesselName)) { - vesselName = voyage.Vessel.IMO; + vesselName = voyage.Vessel.Identifier; } VoyageEvent firstEvent = voyage.FirstEvent(); diff --git a/src/ShippingRecorder.Mvc/Views/SightingDetails/Index.cshtml b/src/ShippingRecorder.Mvc/Views/SightingDetails/Index.cshtml index 260e586..7c1122a 100644 --- a/src/ShippingRecorder.Mvc/Views/SightingDetails/Index.cshtml +++ b/src/ShippingRecorder.Mvc/Views/SightingDetails/Index.cshtml @@ -74,11 +74,11 @@
- @Html.LabelFor(m => m.IMO) + @Html.LabelFor(m => m.Identifier)
- @Html.TextBoxFor(m => m.IMO, new { + @Html.TextBoxFor(m => m.Identifier, new { @class = "form-control", type = "text", inputmode = "numeric", @@ -86,7 +86,7 @@ oninput = "this.value = this.value.replace(/[^0-9]/g, '')" })
- @Html.ValidationMessageFor(m => m.IMO, "", new { @class = "text-danger" }) + @Html.ValidationMessageFor(m => m.Identifier, "", new { @class = "text-danger" })

diff --git a/src/ShippingRecorder.Mvc/Views/VesselDetails/Index.cshtml b/src/ShippingRecorder.Mvc/Views/VesselDetails/Index.cshtml index 525fc39..23d3963 100644 --- a/src/ShippingRecorder.Mvc/Views/VesselDetails/Index.cshtml +++ b/src/ShippingRecorder.Mvc/Views/VesselDetails/Index.cshtml @@ -10,7 +10,7 @@ { @Html.AntiForgeryToken() @Html.HiddenFor(m => m.Vessel.Id) - @Html.HiddenFor(m => m.Vessel.IMO) + @Html.HiddenFor(m => m.Vessel.Identifier) @Html.HiddenFor(m => m.Registration.Id)
@@ -25,7 +25,7 @@ @await Html.PartialAsync("_SightingSummary", new SightingSummaryViewModel() { - Message = $"Most Recent Sighting of {Model.MostRecentSighting.Vessel.IMO}", + Message = $"Most Recent Sighting of {Model.MostRecentSighting.Vessel.Identifier}", Sighting = Model.MostRecentSighting }); } diff --git a/src/ShippingRecorder.Mvc/Views/Vessels/Index.cshtml b/src/ShippingRecorder.Mvc/Views/Vessels/Index.cshtml index b829545..9d6ac09 100644 --- a/src/ShippingRecorder.Mvc/Views/Vessels/Index.cshtml +++ b/src/ShippingRecorder.Mvc/Views/Vessels/Index.cshtml @@ -27,7 +27,7 @@ - + @@ -39,7 +39,7 @@ { var vesselName = vessel?.ActiveRegistrationHistory?.Name ?? ""; - + diff --git a/src/ShippingRecorder.Mvc/Wizard/AddSightingWizard.cs b/src/ShippingRecorder.Mvc/Wizard/AddSightingWizard.cs index b5ba5f9..be66ff4 100644 --- a/src/ShippingRecorder.Mvc/Wizard/AddSightingWizard.cs +++ b/src/ShippingRecorder.Mvc/Wizard/AddSightingWizard.cs @@ -112,7 +112,7 @@ public async Task GetSightingDetailsModelAsync(string LocationId = sighting.LocationId, VoyageId = sighting.VoyageId ?? 0, VoyageName = sighting.Voyage?.ToString() ?? "", - IMO = sighting.Vessel.IMO + Identifier = sighting.Vessel.Identifier }; } else @@ -155,11 +155,11 @@ public async Task GetVesselDetailsModelAsync(string user { _logger.LogDebug($"Creating new vessel details model"); - // Not cached, so create a new one, using the cached sighting details model to supply the vessel IMO + // Not cached, so create a new one, using the cached sighting details model to supply the vessel identifier key = _cache.GetCacheKey(SightingDetailsKeyPrefix, userName); SightingDetailsViewModel sighting = _cache.Get(key); model = new VesselDetailsViewModel(); - model.Vessel.IMO = sighting.IMO; + model.Vessel.Identifier = sighting.Identifier; // Load vessel types, countries and operators model.VesselTypes = await _vesselTypeListGenerator.Create(); @@ -168,8 +168,8 @@ public async Task GetVesselDetailsModelAsync(string user } // See if this is an existing vessel - _logger.LogDebug($"Retrieving vessel with IMO {model.Vessel.IMO}"); - Vessel vessel = await _vesselClient.GetAsync(model.Vessel.IMO); + _logger.LogDebug($"Retrieving vessel with {model.Vessel.Identifier}"); + Vessel vessel = await _vesselClient.GetAsync(model.Vessel.Identifier); _logger.LogDebug($"Retrieved vessel: {vessel}"); if (vessel != null) @@ -182,7 +182,7 @@ public async Task GetVesselDetailsModelAsync(string user model.Editable = false; // Retrieve the most recent sighting of this vessel - model.MostRecentSighting = await _sightingClient.GetMostRecentVesselSightingAsync(vessel.IMO); + model.MostRecentSighting = await _sightingClient.GetMostRecentVesselSightingAsync(vessel.Identifier); } _logger.LogDebug($"Resolved vessel details model: {model}"); @@ -349,7 +349,8 @@ private async Task RetrieveOrCreateVessel(string userName) // Create the vessel vessel = await _vesselClient.AddAsync( - details.Vessel.IMO, + details.Vessel.Identifier, + details.Vessel.IsIMO, details.Vessel.Built, details.Vessel.Draught, details.Vessel.Length, diff --git a/src/ShippingRecorder.Tests/Client/SightingClientTest.cs b/src/ShippingRecorder.Tests/Client/SightingClientTest.cs index 47da448..9b412d3 100644 --- a/src/ShippingRecorder.Tests/Client/SightingClientTest.cs +++ b/src/ShippingRecorder.Tests/Client/SightingClientTest.cs @@ -149,13 +149,13 @@ public async Task GetTest() [TestMethod] public async Task GetMostRecentTest() { - var imo = DataGenerator.RandomInt(0, 9999999).ToString(); + var identifier = DataGenerator.RandomInt(0, 9999999).ToString(); var sighting = DataGenerator.CreateSighting(); var json = JsonSerializer.Serialize>([sighting]); _httpClient.AddResponse(json); - var retrieved = await _client.GetMostRecentVesselSightingAsync(imo); - var expectedRoute = $"{_settings.ApiRoutes.First(x => x.Name == "Sighting").Route}/vessel/{imo}"; + var retrieved = await _client.GetMostRecentVesselSightingAsync(identifier); + var expectedRoute = $"{_settings.ApiRoutes.First(x => x.Name == "Sighting").Route}/vessel/{identifier}"; Assert.AreEqual($"Bearer {ApiToken}", _httpClient.DefaultRequestHeaders.Authorization.ToString()); Assert.AreEqual($"{_settings.ApiUrl}", _httpClient.BaseAddress.ToString()); @@ -311,7 +311,7 @@ public async Task ImportFromFileTest() { var date = DateTime.Today; var sighting = DataGenerator.CreateSighting(); - var record = $@"""{date.ToString(ExportableSighting.DateFormat)}"",""{sighting.Location.Name}"",""{sighting.Vessel.IMO}"",""False"""; + var record = $@"""{date.ToString(ExportableSighting.DateFormat)}"",""{sighting.Location.Name}"",""{sighting.Vessel.Identifier}"",""False"""; _filePath = Path.ChangeExtension(Path.GetTempFileName(), "csv"); File.WriteAllLines(_filePath, ["", record]); _httpClient.AddResponse(""); diff --git a/src/ShippingRecorder.Tests/Client/VesselClientTest.cs b/src/ShippingRecorder.Tests/Client/VesselClientTest.cs index 5431146..2990498 100644 --- a/src/ShippingRecorder.Tests/Client/VesselClientTest.cs +++ b/src/ShippingRecorder.Tests/Client/VesselClientTest.cs @@ -58,7 +58,8 @@ public async Task AddTest() var vessel = DataGenerator.CreateVessel(); var json = JsonSerializer.Serialize(new { - vessel.IMO, + vessel.Identifier, + vessel.IsIMO, vessel.Built, vessel.Draught, vessel.Length, @@ -66,7 +67,7 @@ public async Task AddTest() }); _httpClient.AddResponse(json); - var added = await _client.AddAsync(vessel.IMO, vessel.Built, vessel.Draught, vessel.Length, vessel.Beam); + var added = await _client.AddAsync(vessel.Identifier, true, vessel.Built, vessel.Draught, vessel.Length, vessel.Beam); Assert.AreEqual($"Bearer {ApiToken}", _httpClient.DefaultRequestHeaders.Authorization.ToString()); Assert.AreEqual($"{_settings.ApiUrl}", _httpClient.BaseAddress.ToString()); @@ -75,7 +76,7 @@ public async Task AddTest() Assert.AreEqual(json, await _httpClient.Requests[0].Content.ReadAsStringAsync()); Assert.IsNotNull(added); - Assert.AreEqual(vessel.IMO, added.IMO); + Assert.AreEqual(vessel.Identifier, added.Identifier); Assert.AreEqual(vessel.Built, added.Built); Assert.AreEqual(vessel.Draught, added.Draught); Assert.AreEqual(vessel.Length, added.Length); @@ -89,7 +90,7 @@ public async Task UpdateTest() var json = JsonSerializer.Serialize(vessel); _httpClient.AddResponse(json); - var updated = await _client.UpdateAsync(vessel.Id, vessel.IMO, vessel.Built, vessel.Draught, vessel.Length, vessel.Beam); + var updated = await _client.UpdateAsync(vessel.Id, vessel.Identifier, true, vessel.Built, vessel.Draught, vessel.Length, vessel.Beam); Assert.AreEqual($"Bearer {ApiToken}", _httpClient.DefaultRequestHeaders.Authorization.ToString()); Assert.AreEqual($"{_settings.ApiUrl}", _httpClient.BaseAddress.ToString()); @@ -99,7 +100,7 @@ public async Task UpdateTest() Assert.StartsWith((await _httpClient.Requests[0].Content.ReadAsStringAsync())[..^1], json); Assert.IsNotNull(updated); Assert.AreEqual(vessel.Id, updated.Id); - Assert.AreEqual(vessel.IMO, updated.IMO); + Assert.AreEqual(vessel.Identifier, updated.Identifier); Assert.AreEqual(vessel.Built, updated.Built); Assert.AreEqual(vessel.Draught, updated.Draught); Assert.AreEqual(vessel.Length, updated.Length); @@ -138,7 +139,7 @@ public async Task GetByIdTest() Assert.IsNull(_httpClient.Requests[0].Content); Assert.IsNotNull(retrieved); Assert.AreEqual(vessel.Id, retrieved.Id); - Assert.AreEqual(vessel.IMO, retrieved.IMO); + Assert.AreEqual(vessel.Identifier, retrieved.Identifier); Assert.AreEqual(vessel.Built, retrieved.Built); Assert.AreEqual(vessel.Draught, retrieved.Draught); Assert.AreEqual(vessel.Length, retrieved.Length); @@ -146,14 +147,14 @@ public async Task GetByIdTest() } [TestMethod] - public async Task GetByIMOTest() + public async Task GetByIdentifierTest() { var vessel = DataGenerator.CreateVessel(); var json = JsonSerializer.Serialize(vessel); _httpClient.AddResponse(json); - var retrieved = await _client.GetAsync(vessel.IMO); - var expectedRoute = $"{_settings.ApiRoutes.First(x => x.Name == "Vessel").Route}/imo/{vessel.IMO}"; + var retrieved = await _client.GetAsync(vessel.Identifier); + var expectedRoute = $"{_settings.ApiRoutes.First(x => x.Name == "Vessel").Route}/identifier/{vessel.Identifier}"; Assert.AreEqual($"Bearer {ApiToken}", _httpClient.DefaultRequestHeaders.Authorization.ToString()); Assert.AreEqual($"{_settings.ApiUrl}", _httpClient.BaseAddress.ToString()); @@ -163,7 +164,7 @@ public async Task GetByIMOTest() Assert.IsNull(_httpClient.Requests[0].Content); Assert.IsNotNull(retrieved); Assert.AreEqual(vessel.Id, retrieved.Id); - Assert.AreEqual(vessel.IMO, retrieved.IMO); + Assert.AreEqual(vessel.Identifier, retrieved.Identifier); Assert.AreEqual(vessel.Built, retrieved.Built); Assert.AreEqual(vessel.Draught, retrieved.Draught); Assert.AreEqual(vessel.Length, retrieved.Length); @@ -189,7 +190,7 @@ public async Task ListTest() Assert.IsNotNull(vessels); Assert.HasCount(1, vessels); Assert.AreEqual(vessel.Id, vessels[0].Id); - Assert.AreEqual(vessel.IMO, vessels[0].IMO); + Assert.AreEqual(vessel.Identifier, vessels[0].Identifier); Assert.AreEqual(vessel.Built, vessels[0].Built); Assert.AreEqual(vessel.Draught, vessels[0].Draught); Assert.AreEqual(vessel.Length, vessels[0].Length); @@ -200,7 +201,7 @@ public async Task ListTest() public async Task ImportFromFileTest() { var vessel = DataGenerator.CreateVessel(); - var record = $@"""{vessel.IMO}"",""{vessel.Built}"",""{vessel.Draught}"",""{vessel.Length}"",""{vessel.Beam}"",""{vessel.ActiveRegistrationHistory.Tonnage}"",""{vessel.ActiveRegistrationHistory.Passengers}"",""{vessel.ActiveRegistrationHistory.Crew}"",""{vessel.ActiveRegistrationHistory.Decks}"",""{vessel.ActiveRegistrationHistory.Cabins}"",""{vessel.ActiveRegistrationHistory.Name}"",""{vessel.ActiveRegistrationHistory.Callsign}"",""{vessel.ActiveRegistrationHistory.MMSI}"",""{vessel.ActiveRegistrationHistory.VesselType.Name}"",""{vessel.ActiveRegistrationHistory.Flag}"",""{vessel.ActiveRegistrationHistory.Operator.Name}"""; + var record = $@"""{vessel.Identifier}"",""{vessel.Built}"",""{vessel.Draught}"",""{vessel.Length}"",""{vessel.Beam}"",""{vessel.ActiveRegistrationHistory.Tonnage}"",""{vessel.ActiveRegistrationHistory.Passengers}"",""{vessel.ActiveRegistrationHistory.Crew}"",""{vessel.ActiveRegistrationHistory.Decks}"",""{vessel.ActiveRegistrationHistory.Cabins}"",""{vessel.ActiveRegistrationHistory.Name}"",""{vessel.ActiveRegistrationHistory.Callsign}"",""{vessel.ActiveRegistrationHistory.MMSI}"",""{vessel.ActiveRegistrationHistory.VesselType.Name}"",""{vessel.ActiveRegistrationHistory.Flag}"",""{vessel.ActiveRegistrationHistory.Operator.Name}"""; _filePath = Path.ChangeExtension(Path.GetTempFileName(), "csv"); File.WriteAllLines(_filePath, ["", record]); _httpClient.AddResponse(""); diff --git a/src/ShippingRecorder.Tests/Client/VoyageClientTest.cs b/src/ShippingRecorder.Tests/Client/VoyageClientTest.cs index 9298023..e57fac7 100644 --- a/src/ShippingRecorder.Tests/Client/VoyageClientTest.cs +++ b/src/ShippingRecorder.Tests/Client/VoyageClientTest.cs @@ -158,7 +158,7 @@ public async Task ListTest() public async Task ImportFromFileTest() { var voyage = DataGenerator.CreateVoyage(); - var record = $@"""{voyage.Vessel.IMO}"",""{voyage.Operator.Name}"",""{voyage.Number}"",""{voyage.Events.First().EventType}"",""{voyage.Events.First().Port.Code}"",""{voyage.Events.First().Date.ToString(ExportableVoyage.DateFormat)}"""; + var record = $@"""{voyage.Vessel.Identifier}"",""{voyage.Operator.Name}"",""{voyage.Number}"",""{voyage.Events.First().EventType}"",""{voyage.Events.First().Port.Code}"",""{voyage.Events.First().Date.ToString(ExportableVoyage.DateFormat)}"""; _filePath = Path.ChangeExtension(Path.GetTempFileName(), "csv"); File.WriteAllLines(_filePath, ["", record]); _httpClient.AddResponse(""); diff --git a/src/ShippingRecorder.Tests/Db/RegistrationHistoryManagerTest.cs b/src/ShippingRecorder.Tests/Db/RegistrationHistoryManagerTest.cs index 022c154..264cbce 100644 --- a/src/ShippingRecorder.Tests/Db/RegistrationHistoryManagerTest.cs +++ b/src/ShippingRecorder.Tests/Db/RegistrationHistoryManagerTest.cs @@ -11,7 +11,7 @@ namespace ShippingRecorder.Tests.Db [TestClass] public class RegistrationHistoryManagerTest { - private const string IMO = "9226906"; + private const string VesselIdentifier = "9226906"; private const string VesselType = "Passenger (Cruise) Ship"; private const string UpdatedVesselType = "Vista-Class Cruise Ship"; private const string CountryCode = "BM"; @@ -48,7 +48,7 @@ public async Task TestInitializeAsync() { var context = ShippingRecorderDbContextFactory.CreateInMemoryDbContext(); _factory = new ShippingRecorderFactory(context, new MockFileLogger()); - _vesselId = (await _factory.Vessels.AddAsync(IMO, null, null, null, null)).Id; + _vesselId = (await _factory.Vessels.AddAsync(VesselIdentifier, true, null, null, null, null)).Id; _vesselTypeId = (await _factory.VesselTypes.AddAsync(VesselType)).Id; _updatedVesselTypeId = (await _factory.Operators.AddAsync(UpdatedVesselType)).Id; diff --git a/src/ShippingRecorder.Tests/Db/SightingsManagerTest.cs b/src/ShippingRecorder.Tests/Db/SightingsManagerTest.cs index b70fe65..c2294e3 100644 --- a/src/ShippingRecorder.Tests/Db/SightingsManagerTest.cs +++ b/src/ShippingRecorder.Tests/Db/SightingsManagerTest.cs @@ -28,7 +28,7 @@ public async Task TestInitializeAsync() _factory = new ShippingRecorderFactory(context, new MockFileLogger()); _operatorId = (await _factory.Operators.AddAsync("P&O Ferries")).Id; _vesselTypeId = (await _factory.VesselTypes.AddAsync("Passenger Ship")).Id; - _vesselId = (await _factory.Vessels.AddAsync("8420878", null, null, null, null)).Id; + _vesselId = (await _factory.Vessels.AddAsync("8420878", true, null, null, null, null)).Id; _voyageId = (await _factory.Voyages.AddAsync(_operatorId, _vesselId, "9272QIU261")).Id; _locationId = (await _factory.Locations.AddAsync("Arrecife")).Id; _ = await _factory.Sightings.AddAsync(_locationId, _voyageId, _vesselId, Date, false); diff --git a/src/ShippingRecorder.Tests/Db/VesselManagerTest.cs b/src/ShippingRecorder.Tests/Db/VesselManagerTest.cs index f1e50a3..02a7677 100644 --- a/src/ShippingRecorder.Tests/Db/VesselManagerTest.cs +++ b/src/ShippingRecorder.Tests/Db/VesselManagerTest.cs @@ -11,12 +11,12 @@ namespace ShippingRecorder.Tests.Db [TestClass] public class VesselManagerTest { - private const string IMO = "8420878"; + private const string VesselIdentifier = "8420878"; private const int Built = 2005; private const int Length = 285; private const int Beam = 32; private const decimal Draught = 8M; - private const string SecondIMO = "9226906"; + private const string SecondVesselIdentifier = "9226906"; private const int SecondBuilt = 2010; private const int SecondLength = 300; private const int SecondBeam = 40; @@ -29,32 +29,32 @@ public async Task TestInitializeAsync() { var context = ShippingRecorderDbContextFactory.CreateInMemoryDbContext(); _factory = new ShippingRecorderFactory(context, new MockFileLogger()); - _ = await _factory.Vessels.AddAsync(IMO, Built, Draught, Length, Beam); + _ = await _factory.Vessels.AddAsync(VesselIdentifier, true, Built, Draught, Length, Beam); } [TestMethod] public async Task CannotAddDuplicateTestAsync() - => await Assert.ThrowsAsync(() => _factory.Vessels.AddAsync(IMO, Built, Draught, Length, Beam)); + => await Assert.ThrowsAsync(() => _factory.Vessels.AddAsync(VesselIdentifier, true, Built, Draught, Length, Beam)); [TestMethod] - public async Task CannotAddWithNonNumericIMOTestAsync() - => await Assert.ThrowsAsync(() => _factory.Vessels.AddAsync("Invalid", null, null, null, null)); + public async Task CannotAddWithNonNumericIdentifierTestAsync() + => await Assert.ThrowsAsync(() => _factory.Vessels.AddAsync("Invalid", true, null, null, null, null)); [TestMethod] - public async Task CannotAddWithShortIMOTestAsync() - => await Assert.ThrowsAsync(() => _factory.Vessels.AddAsync(IMO[..6], null, null, null, null)); + public async Task CannotAddWithShortIdentiiferTestAsync() + => await Assert.ThrowsAsync(() => _factory.Vessels.AddAsync(VesselIdentifier[..6], true, null, null, null, null)); [TestMethod] - public async Task CannotAddWithLongIMOTestAsync() - => await Assert.ThrowsAsync(() => _factory.Vessels.AddAsync($"{IMO}0", null, null, null, null)); + public async Task CannotAddWithLongIdentifierTestAsync() + => await Assert.ThrowsAsync(() => _factory.Vessels.AddAsync($"{VesselIdentifier}0", true, null, null, null, null)); [TestMethod] public async Task AddAndGetTestAsync() { - var entity = await _factory.Vessels.GetAsync(e => e.IMO == IMO); + var entity = await _factory.Vessels.GetAsync(e => e.Identifier == VesselIdentifier); Assert.IsNotNull(entity); Assert.IsGreaterThan(0, entity.Id); - Assert.AreEqual(IMO, entity.IMO); + Assert.AreEqual(VesselIdentifier, entity.Identifier); Assert.AreEqual(Built, entity.Built); Assert.AreEqual(Draught, entity.Draught); Assert.AreEqual(Length, entity.Length); @@ -64,7 +64,7 @@ public async Task AddAndGetTestAsync() [TestMethod] public async Task AddExistingIfNotExistTestAsync() { - _ = await _factory.Vessels.AddIfNotExistsAsync(IMO, Built, Draught, Length, Beam); + _ = await _factory.Vessels.AddIfNotExistsAsync(VesselIdentifier, true, Built, Draught, Length, Beam); var count = _factory.GetContext().Vessels.Count(); Assert.AreEqual(1, count); } @@ -72,11 +72,11 @@ public async Task AddExistingIfNotExistTestAsync() [TestMethod] public async Task AddMissingIfNotExistTestAsync() { - var entity = await _factory.Vessels.AddIfNotExistsAsync(SecondIMO, SecondBuilt, SecondDraught, SecondLength, SecondBeam); + var entity = await _factory.Vessels.AddIfNotExistsAsync(SecondVesselIdentifier, true, SecondBuilt, SecondDraught, SecondLength, SecondBeam); var count = _factory.GetContext().Vessels.Count(); Assert.IsNotNull(entity); Assert.IsGreaterThan(0, entity.Id); - Assert.AreEqual(SecondIMO, entity.IMO); + Assert.AreEqual(SecondVesselIdentifier, entity.Identifier); Assert.AreEqual(SecondBuilt, entity.Built); Assert.AreEqual(SecondDraught, entity.Draught); Assert.AreEqual(SecondLength, entity.Length); @@ -87,7 +87,7 @@ public async Task AddMissingIfNotExistTestAsync() [TestMethod] public async Task GetMissingTestAsync() { - var entity = await _factory.Vessels.GetAsync(e => e.IMO == "Missing"); + var entity = await _factory.Vessels.GetAsync(e => e.Identifier == "Missing"); Assert.IsNull(entity); } @@ -96,7 +96,7 @@ public async Task ListAllTestAsync() { var entities = await _factory.Vessels.ListAsync(e => true, 1, int.MaxValue).ToListAsync(); Assert.HasCount(1, entities); - Assert.AreEqual(IMO, entities.First().IMO); + Assert.AreEqual(VesselIdentifier, entities.First().Identifier); Assert.AreEqual(Built, entities.First().Built); Assert.AreEqual(Draught, entities.First().Draught); Assert.AreEqual(Length, entities.First().Length); @@ -106,9 +106,9 @@ public async Task ListAllTestAsync() [TestMethod] public async Task FilteredListTestAsync() { - var entities = await _factory.Vessels.ListAsync(e => e.IMO == IMO, 1, int.MaxValue).ToListAsync(); + var entities = await _factory.Vessels.ListAsync(e => e.Identifier == VesselIdentifier, 1, int.MaxValue).ToListAsync(); Assert.HasCount(1, entities); - Assert.AreEqual(IMO, entities.First().IMO); + Assert.AreEqual(VesselIdentifier, entities.First().Identifier); Assert.AreEqual(Built, entities.First().Built); Assert.AreEqual(Draught, entities.First().Draught); Assert.AreEqual(Length, entities.First().Length); @@ -118,18 +118,18 @@ public async Task FilteredListTestAsync() [TestMethod] public async Task ListMissingTestAsync() { - var entities = await _factory.Vessels.ListAsync(e => e.IMO == "Missing", 1, int.MaxValue).ToListAsync(); + var entities = await _factory.Vessels.ListAsync(e => e.Identifier == "Missing", 1, int.MaxValue).ToListAsync(); Assert.IsEmpty(entities); } [TestMethod] public async Task UpdateTestAsync() { - var entity = await _factory.Vessels.GetAsync(e => e.IMO == IMO); - var updated = await _factory.Vessels.UpdateAsync(entity.Id, SecondIMO, SecondBuilt, SecondDraught, SecondLength, SecondBeam); + var entity = await _factory.Vessels.GetAsync(e => e.Identifier == VesselIdentifier); + var updated = await _factory.Vessels.UpdateAsync(entity.Id, SecondVesselIdentifier, true, SecondBuilt, SecondDraught, SecondLength, SecondBeam); Assert.IsNotNull(updated); Assert.AreEqual(entity.Id, updated.Id); - Assert.AreEqual(SecondIMO, entity.IMO); + Assert.AreEqual(SecondVesselIdentifier, entity.Identifier); Assert.AreEqual(SecondBuilt, entity.Built); Assert.AreEqual(SecondDraught, entity.Draught); Assert.AreEqual(SecondLength, entity.Length); @@ -138,12 +138,12 @@ public async Task UpdateTestAsync() [TestMethod] public async Task UpdateMissingTestAsync() - => await Assert.ThrowsAsync(() => _factory.Vessels.UpdateAsync(-1, SecondIMO, SecondBuilt, SecondDraught, SecondLength, SecondBeam)); + => await Assert.ThrowsAsync(() => _factory.Vessels.UpdateAsync(-1, SecondVesselIdentifier, true, SecondBuilt, SecondDraught, SecondLength, SecondBeam)); [TestMethod] public async Task DeleteTestAsync() { - var entity = await _factory.Vessels.GetAsync(e => e.IMO == IMO); + var entity = await _factory.Vessels.GetAsync(e => e.Identifier == VesselIdentifier); await _factory.Vessels.DeleteAsync(entity.Id); var count = _factory.GetContext().Vessels.Count(); Assert.AreEqual(0, count); diff --git a/src/ShippingRecorder.Tests/Db/VoyageEventManagerTest.cs b/src/ShippingRecorder.Tests/Db/VoyageEventManagerTest.cs index d8f991c..10c1097 100644 --- a/src/ShippingRecorder.Tests/Db/VoyageEventManagerTest.cs +++ b/src/ShippingRecorder.Tests/Db/VoyageEventManagerTest.cs @@ -15,7 +15,7 @@ namespace ShippingRecorder.Tests.Db public class VoyageEventManagerTest { private const string OperatorName = "P&O Ferries"; - private const string IMO = "9826548"; + private const string VesselIdentifier = "9826548"; private const string VoyageNumber = "87236JGH78"; private readonly List VoyageEvents = @@ -47,7 +47,7 @@ public async Task TestInitializeAsync() // Create the voyage var op = await _factory.Operators.AddAsync(OperatorName); - var vessel = await _factory.Vessels.AddAsync(IMO, null, null, null, null); + var vessel = await _factory.Vessels.AddAsync(VesselIdentifier, true, null, null, null, null); _voyage = await _factory.Voyages.AddAsync(op.Id, vessel.Id, VoyageNumber); // Create the voyage events diff --git a/src/ShippingRecorder.Tests/Db/VoyageManagerTest.cs b/src/ShippingRecorder.Tests/Db/VoyageManagerTest.cs index 1e31cbf..a34d9f7 100644 --- a/src/ShippingRecorder.Tests/Db/VoyageManagerTest.cs +++ b/src/ShippingRecorder.Tests/Db/VoyageManagerTest.cs @@ -28,9 +28,9 @@ public async Task TestInitializeAsync() var context = ShippingRecorderDbContextFactory.CreateInMemoryDbContext(); _factory = new ShippingRecorderFactory(context, new MockFileLogger()); _operatorId = (await _factory.Operators.AddAsync("P&O Ferries")).Id; - _vesselId = (await _factory.Vessels.AddAsync("9226906", null, null, null, null)).Id; + _vesselId = (await _factory.Vessels.AddAsync("9226906", true, null, null, null, null)).Id; _secondOperatorId = (await _factory.Operators.AddAsync("Royal Caribbean International")).Id; - _secondVesselId = (await _factory.Vessels.AddAsync("9744001", null, null, null, null)).Id; + _secondVesselId = (await _factory.Vessels.AddAsync("9744001", true, null, null, null, null)).Id; _ = await _factory.Voyages.AddAsync(_operatorId, _vesselId, Number); } diff --git a/src/ShippingRecorder.Tests/Export/SightingExporterTest.cs b/src/ShippingRecorder.Tests/Export/SightingExporterTest.cs index 7814b43..5a919b4 100644 --- a/src/ShippingRecorder.Tests/Export/SightingExporterTest.cs +++ b/src/ShippingRecorder.Tests/Export/SightingExporterTest.cs @@ -37,7 +37,7 @@ public void ConvertSingleObjectToExportable() var exportable = _sighting.ToExportable(); Assert.AreEqual(_sighting.Date, exportable.Date); Assert.AreEqual(_sighting.Location.Name, exportable.Location); - Assert.AreEqual(_sighting.Vessel.IMO, exportable.IMO); + Assert.AreEqual(_sighting.Vessel.Identifier, exportable.Identifier); Assert.AreEqual(_sighting.IsMyVoyage, exportable.IsMyVoyage); } @@ -48,7 +48,7 @@ public void ConvertCollectionToExportable() var exportable = sightings.ToExportable(); Assert.AreEqual(_sighting.Date, exportable.First().Date); Assert.AreEqual(_sighting.Location.Name, exportable.First().Location); - Assert.AreEqual(_sighting.Vessel.IMO, exportable.First().IMO); + Assert.AreEqual(_sighting.Vessel.Identifier, exportable.First().Identifier); Assert.AreEqual(_sighting.IsMyVoyage, exportable.First().IsMyVoyage); } @@ -56,11 +56,11 @@ public void ConvertCollectionToExportable() public void FromCsvRecordTest() { var isMyVoyage = _sighting.IsMyVoyage ? "True" : "False"; - var record = $@"""{_sighting.Date.ToString(ExportableEntityBase.DateFormat)}"",""{_sighting.Location.Name}"",""{_sighting.Vessel.IMO}"","""",""{isMyVoyage}"""; + var record = $@"""{_sighting.Date.ToString(ExportableEntityBase.DateFormat)}"",""{_sighting.Location.Name}"",""{_sighting.Vessel.Identifier}"","""",""{isMyVoyage}"""; var exportable = ExportableSighting.FromCsv(record); Assert.AreEqual(_sighting.Date, exportable.Date); Assert.AreEqual(_sighting.Location.Name, exportable.Location); - Assert.AreEqual(_sighting.Vessel.IMO, exportable.IMO); + Assert.AreEqual(_sighting.Vessel.Identifier, exportable.Identifier); Assert.AreEqual(_sighting.IsMyVoyage, exportable.IsMyVoyage); } @@ -91,7 +91,7 @@ public async Task ExportTest() var exportable = ExportableSighting.FromCsv(records[1]); Assert.AreEqual(_sighting.Date, exportable.Date); Assert.AreEqual(_sighting.Location.Name, exportable.Location); - Assert.AreEqual(_sighting.Vessel.IMO, exportable.IMO); + Assert.AreEqual(_sighting.Vessel.Identifier, exportable.Identifier); Assert.AreEqual(_sighting.IsMyVoyage, exportable.IsMyVoyage); } } diff --git a/src/ShippingRecorder.Tests/Export/VesselExporterTest.cs b/src/ShippingRecorder.Tests/Export/VesselExporterTest.cs index e4666aa..cba3060 100644 --- a/src/ShippingRecorder.Tests/Export/VesselExporterTest.cs +++ b/src/ShippingRecorder.Tests/Export/VesselExporterTest.cs @@ -35,7 +35,7 @@ public void CleanUp() public void ConvertSingleObjectToExportable() { var exportable = _vessel.ToExportable(); - Assert.AreEqual(_vessel.IMO, exportable.IMO); + Assert.AreEqual(_vessel.Identifier, exportable.Identifier); Assert.AreEqual(_vessel.Built, exportable.Built); Assert.AreEqual(_vessel.Draught, exportable.Draught); Assert.AreEqual(_vessel.Length, exportable.Length); @@ -58,7 +58,7 @@ public void ConvertCollectionToExportable() { List vessels = [_vessel]; var exportable = vessels.ToExportable(); - Assert.AreEqual(_vessel.IMO, exportable.First().IMO); + Assert.AreEqual(_vessel.Identifier, exportable.First().Identifier); Assert.AreEqual(_vessel.Built, exportable.First().Built); Assert.AreEqual(_vessel.Draught, exportable.First().Draught); Assert.AreEqual(_vessel.Length, exportable.First().Length); @@ -79,9 +79,9 @@ public void ConvertCollectionToExportable() [TestMethod] public void FromCsvRecordTest() { - var record = $@"""{_vessel.IMO}"",""{_vessel.Built}"",""{_vessel.Draught}"",""{_vessel.Length}"",""{_vessel.Beam}"",""{_vessel.ActiveRegistrationHistory.Tonnage}"",""{_vessel.ActiveRegistrationHistory.Passengers}"",""{_vessel.ActiveRegistrationHistory.Crew}"",""{_vessel.ActiveRegistrationHistory.Decks}"",""{_vessel.ActiveRegistrationHistory.Cabins}"",""{_vessel.ActiveRegistrationHistory.Name}"",""{_vessel.ActiveRegistrationHistory.Callsign}"",""{_vessel.ActiveRegistrationHistory.MMSI}"",""{_vessel.ActiveRegistrationHistory.VesselType.Name}"",""{_vessel.ActiveRegistrationHistory.Flag.Code}"",""{_vessel.ActiveRegistrationHistory.Operator.Name}"""; + var record = $@"""{_vessel.Identifier}"",""True"",""{_vessel.Built}"",""{_vessel.Draught}"",""{_vessel.Length}"",""{_vessel.Beam}"",""{_vessel.ActiveRegistrationHistory.Tonnage}"",""{_vessel.ActiveRegistrationHistory.Passengers}"",""{_vessel.ActiveRegistrationHistory.Crew}"",""{_vessel.ActiveRegistrationHistory.Decks}"",""{_vessel.ActiveRegistrationHistory.Cabins}"",""{_vessel.ActiveRegistrationHistory.Name}"",""{_vessel.ActiveRegistrationHistory.Callsign}"",""{_vessel.ActiveRegistrationHistory.MMSI}"",""{_vessel.ActiveRegistrationHistory.VesselType.Name}"",""{_vessel.ActiveRegistrationHistory.Flag.Code}"",""{_vessel.ActiveRegistrationHistory.Operator.Name}"""; var exportable = ExportableVessel.FromCsv(record); - Assert.AreEqual(_vessel.IMO, exportable.IMO); + Assert.AreEqual(_vessel.Identifier, exportable.Identifier); Assert.AreEqual(_vessel.Built, exportable.Built); Assert.AreEqual(_vessel.Draught, exportable.Draught); Assert.AreEqual(_vessel.Length, exportable.Length); @@ -126,7 +126,7 @@ public async Task ExportTest() Assert.HasCount(2, records); var exportable = ExportableVessel.FromCsv(records[1]); - Assert.AreEqual(_vessel.IMO, exportable.IMO); + Assert.AreEqual(_vessel.Identifier, exportable.Identifier); Assert.AreEqual(_vessel.Built, exportable.Built); Assert.AreEqual(_vessel.Draught, exportable.Draught); Assert.AreEqual(_vessel.Length, exportable.Length); diff --git a/src/ShippingRecorder.Tests/Export/VoyageExporterTest.cs b/src/ShippingRecorder.Tests/Export/VoyageExporterTest.cs index b0340b1..214dd5e 100644 --- a/src/ShippingRecorder.Tests/Export/VoyageExporterTest.cs +++ b/src/ShippingRecorder.Tests/Export/VoyageExporterTest.cs @@ -41,7 +41,7 @@ public void CleanUp() public void ConvertSingleObjectToExportable() { var exportable = _voyage.ToExportable(); - Assert.AreEqual(_voyage.Vessel.IMO, exportable.First().IMO); + Assert.AreEqual(_voyage.Vessel.Identifier, exportable.First().Identifier); Assert.AreEqual(_voyage.Operator.Name, exportable.First().Operator); Assert.AreEqual(_voyage.Number, exportable.First().Number); Assert.AreEqual(_voyage.Events.First().EventType.ToString(), exportable.First().EventType); @@ -54,7 +54,7 @@ public void ConvertCollectionToExportable() { List vessels = [_voyage]; var exportable = vessels.ToExportable(); - Assert.AreEqual(_voyage.Vessel.IMO, exportable.First().IMO); + Assert.AreEqual(_voyage.Vessel.Identifier, exportable.First().Identifier); Assert.AreEqual(_voyage.Operator.Name, exportable.First().Operator); Assert.AreEqual(_voyage.Number, exportable.First().Number); Assert.AreEqual(_voyage.Events.First().EventType.ToString(), exportable.First().EventType); @@ -66,9 +66,9 @@ public void ConvertCollectionToExportable() [TestMethod] public void FromCsvRecordTest() { - var record = $@"""{_voyage.Vessel.IMO}"",""{_voyage.Operator.Name}"",""{_voyage.Number}"",""{_voyage.Events.First().EventType}"",""{_voyage.Events.First().Port.Code}"",""{_voyage.Events.First().Date.ToString(ExportableVoyage.DateFormat)}"""; + var record = $@"""{_voyage.Vessel.Identifier}"",""{_voyage.Operator.Name}"",""{_voyage.Number}"",""{_voyage.Events.First().EventType}"",""{_voyage.Events.First().Port.Code}"",""{_voyage.Events.First().Date.ToString(ExportableVoyage.DateFormat)}"""; var exportable = ExportableVoyage.FromCsv(record); - Assert.AreEqual(_voyage.Vessel.IMO, exportable.IMO); + Assert.AreEqual(_voyage.Vessel.Identifier, exportable.Identifier); Assert.AreEqual(_voyage.Operator.Name, exportable.Operator); Assert.AreEqual(_voyage.Number, exportable.Number); Assert.AreEqual(_voyage.Events.First().EventType.ToString(), exportable.EventType); @@ -102,7 +102,7 @@ public async Task ExportTest() Assert.HasCount(2, records); var exportable = ExportableVoyage.FromCsv(records[1]); - Assert.AreEqual(_voyage.Vessel.IMO, exportable.IMO); + Assert.AreEqual(_voyage.Vessel.Identifier, exportable.Identifier); Assert.AreEqual(_voyage.Operator.Name, exportable.Operator); Assert.AreEqual(_voyage.Number, exportable.Number); Assert.AreEqual(_voyage.Events.First().EventType.ToString(), exportable.EventType); diff --git a/src/ShippingRecorder.Tests/Extensions/DecimalExtensionsTest.cs b/src/ShippingRecorder.Tests/Extensions/DecimalExtensionsTest.cs index 9d249e3..1ab5c39 100644 --- a/src/ShippingRecorder.Tests/Extensions/DecimalExtensionsTest.cs +++ b/src/ShippingRecorder.Tests/Extensions/DecimalExtensionsTest.cs @@ -46,7 +46,7 @@ public void ValidateTooLargeTest() public void ValidateFailureThrowsExceptionNumericTest() { decimal? i = null; - Assert.Throws(() => i.ValidateDecimalAndThrow(1, decimal.MaxValue, false)); + Assert.Throws(() => i.ValidateDecimalAndThrow(1, decimal.MaxValue, false)); } } } \ No newline at end of file diff --git a/src/ShippingRecorder.Tests/Extensions/IntegerExtenionsTest.cs b/src/ShippingRecorder.Tests/Extensions/IntegerExtenionsTest.cs index 0016238..c532b86 100644 --- a/src/ShippingRecorder.Tests/Extensions/IntegerExtenionsTest.cs +++ b/src/ShippingRecorder.Tests/Extensions/IntegerExtenionsTest.cs @@ -46,7 +46,7 @@ public void ValidateTooLargeTest() public void ValidateFailureThrowsExceptionNumericTest() { int? i = null; - Assert.Throws(() => i.ValidateIntegerAndThrow(1, int.MaxValue, false)); + Assert.Throws(() => i.ValidateIntegerAndThrow(1, int.MaxValue, false)); } } } \ No newline at end of file diff --git a/src/ShippingRecorder.Tests/Extensions/StringExtensionsTest.cs b/src/ShippingRecorder.Tests/Extensions/StringExtensionsTest.cs index f0c21b5..bb3b55e 100644 --- a/src/ShippingRecorder.Tests/Extensions/StringExtensionsTest.cs +++ b/src/ShippingRecorder.Tests/Extensions/StringExtensionsTest.cs @@ -37,6 +37,6 @@ public void ValidateNonNumericTest() [TestMethod] public void ValidateFailureThrowsExceptionNumericTest() - => Assert.Throws(() => "ABC1234".ValidateNumericAndThrow(7, 7)); + => Assert.Throws(() => "ABC1234".ValidateNumericAndThrow(7, 7)); } } \ No newline at end of file diff --git a/src/ShippingRecorder.Tests/Import/SightingImporterTest.cs b/src/ShippingRecorder.Tests/Import/SightingImporterTest.cs index 8a7f6b4..8c49381 100644 --- a/src/ShippingRecorder.Tests/Import/SightingImporterTest.cs +++ b/src/ShippingRecorder.Tests/Import/SightingImporterTest.cs @@ -43,11 +43,11 @@ public async Task ImportWithoutVoyageTest() var vessel = DataGenerator.CreateVessel(); location = await _factory.Locations.AddAsync(location.Name); - vessel = await _factory.Vessels.AddAsync(vessel.IMO, vessel.Built, vessel.Draught, vessel.Length, vessel.Beam); + vessel = await _factory.Vessels.AddAsync(vessel.Identifier, true, vessel.Built, vessel.Draught, vessel.Length, vessel.Beam); var importer = new SightingImporter(_factory, ExportableSighting.CsvRecordPattern); - var record = $@"""{date.ToString(ExportableSighting.DateFormat)}"",""{location.Name}"",""{vessel.IMO}"","""",""False"""; + var record = $@"""{date.ToString(ExportableSighting.DateFormat)}"",""{location.Name}"",""{vessel.Identifier}"","""",""False"""; _filePath = Path.ChangeExtension(Path.GetTempFileName(), "csv"); File.WriteAllLines(_filePath, ["", record]); @@ -77,12 +77,12 @@ public async Task ImportWithVoyageTest() location = await _factory.Locations.AddAsync(location.Name); op = await _factory.Operators.AddAsync(op.Name); - vessel = await _factory.Vessels.AddAsync(vessel.IMO, vessel.Built, vessel.Draught, vessel.Length, vessel.Beam); + vessel = await _factory.Vessels.AddAsync(vessel.Identifier, true, vessel.Built, vessel.Draught, vessel.Length, vessel.Beam); voyage = await _factory.Voyages.AddAsync(op.Id, vessel.Id, voyage.Number); var importer = new SightingImporter(_factory, ExportableSighting.CsvRecordPattern); - var record = $@"""{date.ToString(ExportableSighting.DateFormat)}"",""{location.Name}"",""{vessel.IMO}"",""{voyage.Number}"",""False"""; + var record = $@"""{date.ToString(ExportableSighting.DateFormat)}"",""{location.Name}"",""{vessel.Identifier}"",""{voyage.Number}"",""False"""; _filePath = Path.ChangeExtension(Path.GetTempFileName(), "csv"); File.WriteAllLines(_filePath, ["", record]); @@ -107,11 +107,11 @@ public async Task ImportForMissingLocationTest() var date = DateTime.Today; var vessel = DataGenerator.CreateVessel(); - vessel = await _factory.Vessels.AddAsync(vessel.IMO, vessel.Built, vessel.Draught, vessel.Length, vessel.Beam); + vessel = await _factory.Vessels.AddAsync(vessel.Identifier, true, vessel.Built, vessel.Draught, vessel.Length, vessel.Beam); var importer = new SightingImporter(_factory, ExportableSighting.CsvRecordPattern); - var record = $@"""{date.ToString(ExportableSighting.DateFormat)}"",""Missing"",""{vessel.IMO}"","""",""False"""; + var record = $@"""{date.ToString(ExportableSighting.DateFormat)}"",""Missing"",""{vessel.Identifier}"","""",""False"""; _filePath = Path.ChangeExtension(Path.GetTempFileName(), "csv"); File.WriteAllLines(_filePath, ["", record]); @@ -144,11 +144,11 @@ public async Task ImportForMissingVoyageTest() var voyage = DataGenerator.CreateVoyage(); location = await _factory.Locations.AddAsync(location.Name); - vessel = await _factory.Vessels.AddAsync(vessel.IMO, vessel.Built, vessel.Draught, vessel.Length, vessel.Beam); + vessel = await _factory.Vessels.AddAsync(vessel.Identifier, true, vessel.Built, vessel.Draught, vessel.Length, vessel.Beam); var importer = new SightingImporter(_factory, ExportableSighting.CsvRecordPattern); - var record = $@"""{date.ToString(ExportableSighting.DateFormat)}"",""{location.Name}"",""{vessel.IMO}"",""{voyage.Number}"",""False"""; + var record = $@"""{date.ToString(ExportableSighting.DateFormat)}"",""{location.Name}"",""{vessel.Identifier}"",""{voyage.Number}"",""False"""; _filePath = Path.ChangeExtension(Path.GetTempFileName(), "csv"); File.WriteAllLines(_filePath, ["", record]); @@ -163,11 +163,11 @@ public async Task ImportForFutureDateTest() var vessel = DataGenerator.CreateVessel(); location = await _factory.Locations.AddAsync(location.Name); - vessel = await _factory.Vessels.AddAsync(vessel.IMO, vessel.Built, vessel.Draught, vessel.Length, vessel.Beam); + vessel = await _factory.Vessels.AddAsync(vessel.Identifier, true, vessel.Built, vessel.Draught, vessel.Length, vessel.Beam); var importer = new SightingImporter(_factory, ExportableSighting.CsvRecordPattern); - var record = $@"""{date.ToString(ExportableSighting.DateFormat)}"",""{location.Name}"",""{vessel.IMO}"","""",""False"""; + var record = $@"""{date.ToString(ExportableSighting.DateFormat)}"",""{location.Name}"",""{vessel.Identifier}"","""",""False"""; _filePath = Path.ChangeExtension(Path.GetTempFileName(), "csv"); File.WriteAllLines(_filePath, ["", record]); diff --git a/src/ShippingRecorder.Tests/Import/VesselImporterTest.cs b/src/ShippingRecorder.Tests/Import/VesselImporterTest.cs index bfd7ba1..3822983 100644 --- a/src/ShippingRecorder.Tests/Import/VesselImporterTest.cs +++ b/src/ShippingRecorder.Tests/Import/VesselImporterTest.cs @@ -15,7 +15,7 @@ namespace ShippingRecorder.Tests.Import [TestClass] public class VesselImporterTest { - private const string IMO = "8420878"; + private const string VesselIdentifier = "8420878"; private const int Built = 2005; private const int Length = 285; private const int Beam = 32; @@ -58,7 +58,7 @@ public async Task ImportTest() _ = await _factory.VesselTypes.AddAsync(Type); _ = await _factory.Operators.AddAsync(Operator); - var record = $@"""{IMO}"",""{Built}"",""{Draught}"",""{Length}"",""{Beam}"",""{Tonnage}"",""{Passengers}"",""{Crew}"",""{Decks}"",""{Cabins}"",""{Name}"",""{Callsign}"",""{MMSI}"",""{Type}"",""{Flag}"",""{Operator}"""; + var record = $@"""{VesselIdentifier}"",""True"",""{Built}"",""{Draught}"",""{Length}"",""{Beam}"",""{Tonnage}"",""{Passengers}"",""{Crew}"",""{Decks}"",""{Cabins}"",""{Name}"",""{Callsign}"",""{MMSI}"",""{Type}"",""{Flag}"",""{Operator}"""; _filePath = Path.ChangeExtension(Path.GetTempFileName(), "csv"); File.WriteAllLines(_filePath, ["", record]); @@ -71,7 +71,7 @@ public async Task ImportTest() var vessels = await _factory.Vessels.ListAsync(x => true, 1, int.MaxValue).ToListAsync(); Assert.HasCount(1, vessels); - Assert.AreEqual(IMO, vessels.First().IMO); + Assert.AreEqual(VesselIdentifier, vessels.First().Identifier); } [TestMethod] @@ -84,14 +84,14 @@ public async Task InvalidRecordFormatTest() } [TestMethod] - public async Task InvalidIMOTest() + public async Task InvalidIdentifierTest() { _ = await _factory.Countries.AddAsync(Flag, "Bermuda"); _ = await _factory.VesselTypes.AddAsync(Type); _ = await _factory.Operators.AddAsync(Operator); - _ = await _factory.Vessels.AddAsync(IMO, Built, Draught, Length, Beam); + _ = await _factory.Vessels.AddAsync(VesselIdentifier, true, Built, Draught, Length, Beam); - var record = $@"""{IMO}"",""{Built}"",""{Draught}"",""{Length}"",""{Beam}"",""{Tonnage}"",""{Passengers}"",""{Crew}"",""{Decks}"",""{Cabins}"",""{Name}"",""{Callsign}"",""{MMSI}"",""{Type}"",""{Flag}"",""{Operator}"""; + var record = $@"""{VesselIdentifier}"",""True"",""{Built}"",""{Draught}"",""{Length}"",""{Beam}"",""{Tonnage}"",""{Passengers}"",""{Crew}"",""{Decks}"",""{Cabins}"",""{Name}"",""{Callsign}"",""{MMSI}"",""{Type}"",""{Flag}"",""{Operator}"""; _filePath = Path.ChangeExtension(Path.GetTempFileName(), "csv"); File.WriteAllLines(_filePath, ["", record]); var importer = new VesselImporter(_factory, ExportableVessel.CsvRecordPattern); @@ -104,7 +104,7 @@ public async Task InvalidVesselTypeTest() _ = await _factory.Countries.AddAsync(Flag, "Bermuda"); _ = await _factory.Operators.AddAsync(Operator); - var record = $@"""{IMO}"",""{Built}"",""{Draught}"",""{Length}"",""{Beam}"",""{Tonnage}"",""{Passengers}"",""{Crew}"",""{Decks}"",""{Cabins}"",""{Name}"",""{Callsign}"",""{MMSI}"",""{Type}"",""{Flag}"",""{Operator}"""; + var record = $@"""{VesselIdentifier}"",""True"",""{Built}"",""{Draught}"",""{Length}"",""{Beam}"",""{Tonnage}"",""{Passengers}"",""{Crew}"",""{Decks}"",""{Cabins}"",""{Name}"",""{Callsign}"",""{MMSI}"",""{Type}"",""{Flag}"",""{Operator}"""; _filePath = Path.ChangeExtension(Path.GetTempFileName(), "csv"); File.WriteAllLines(_filePath, ["", record]); var importer = new VesselImporter(_factory, ExportableVessel.CsvRecordPattern); @@ -117,7 +117,7 @@ public async Task InvalidFlagTest() _ = await _factory.VesselTypes.AddAsync(Type); _ = await _factory.Operators.AddAsync(Operator); - var record = $@"""{IMO}"",""{Built}"",""{Draught}"",""{Length}"",""{Beam}"",""{Tonnage}"",""{Passengers}"",""{Crew}"",""{Decks}"",""{Cabins}"",""{Name}"",""{Callsign}"",""{MMSI}"",""{Type}"",""{Flag}"",""{Operator}"""; + var record = $@"""{VesselIdentifier}"",""True"",""{Built}"",""{Draught}"",""{Length}"",""{Beam}"",""{Tonnage}"",""{Passengers}"",""{Crew}"",""{Decks}"",""{Cabins}"",""{Name}"",""{Callsign}"",""{MMSI}"",""{Type}"",""{Flag}"",""{Operator}"""; _filePath = Path.ChangeExtension(Path.GetTempFileName(), "csv"); File.WriteAllLines(_filePath, ["", record]); var importer = new VesselImporter(_factory, ExportableVessel.CsvRecordPattern); @@ -130,7 +130,7 @@ public async Task InvalidOperatorTest() _ = await _factory.Countries.AddAsync(Flag, "Bermuda"); _ = await _factory.VesselTypes.AddAsync(Type); - var record = $@"""{IMO}"",""{Built}"",""{Draught}"",""{Length}"",""{Beam}"",""{Tonnage}"",""{Passengers}"",""{Crew}"",""{Decks}"",""{Cabins}"",""{Name}"",""{Callsign}"",""{MMSI}"",""{Type}"",""{Flag}"",""{Operator}"""; + var record = $@"""{VesselIdentifier}"",""True"",""{Built}"",""{Draught}"",""{Length}"",""{Beam}"",""{Tonnage}"",""{Passengers}"",""{Crew}"",""{Decks}"",""{Cabins}"",""{Name}"",""{Callsign}"",""{MMSI}"",""{Type}"",""{Flag}"",""{Operator}"""; _filePath = Path.ChangeExtension(Path.GetTempFileName(), "csv"); File.WriteAllLines(_filePath, ["", record]); var importer = new VesselImporter(_factory, ExportableVessel.CsvRecordPattern); diff --git a/src/ShippingRecorder.Tests/Import/VoyageImporterTest.cs b/src/ShippingRecorder.Tests/Import/VoyageImporterTest.cs index ef31e5c..559fbc6 100644 --- a/src/ShippingRecorder.Tests/Import/VoyageImporterTest.cs +++ b/src/ShippingRecorder.Tests/Import/VoyageImporterTest.cs @@ -18,7 +18,7 @@ namespace ShippingRecorder.Tests.Import public class VoyageImporterTest { private const string Operator = "Carnival Uk"; - private const string IMO = "9826548"; + private const string VesselIdentifier = "9826548"; private const string Number = "K511"; private const string Port = "GBSOU"; @@ -47,10 +47,10 @@ public async Task ImportTest() var gb = await _factory.Countries.AddAsync("GB", "United Kingdom"); _ = await _factory.Ports.AddAsync(gb.Id, Port, "Southampton"); _ = await _factory.Operators.AddAsync(Operator); - _ = await _factory.Vessels.AddAsync(IMO, null, null, null, null); + _ = await _factory.Vessels.AddAsync(VesselIdentifier, true, null, null, null, null); var date = DateTime.Today; - var record = $@"""{IMO}"",""{Operator}"",""{Number}"",""Depart"",""{Port}"",""{date.ToString(ExportableVoyage.DateFormat)}"""; + var record = $@"""{VesselIdentifier}"",""{Operator}"",""{Number}"",""Depart"",""{Port}"",""{date.ToString(ExportableVoyage.DateFormat)}"""; _filePath = Path.ChangeExtension(Path.GetTempFileName(), "csv"); File.WriteAllLines(_filePath, ["", record]); @@ -84,10 +84,10 @@ public async Task InvalidOperatorTest() { var gb = await _factory.Countries.AddAsync("GB", "United Kingdom"); _ = await _factory.Ports.AddAsync(gb.Id, Port, "Southampton"); - _ = await _factory.Vessels.AddAsync(IMO, null, null, null, null); + _ = await _factory.Vessels.AddAsync(VesselIdentifier, true, null, null, null, null); var date = DateTime.Today; - var record = $@"""{IMO}"",""{Operator}"",""{Number}"",""Depart"",""{Port}"",""{date.ToString(ExportableVoyage.DateFormat)}"""; + var record = $@"""{VesselIdentifier}"",""{Operator}"",""{Number}"",""Depart"",""{Port}"",""{date.ToString(ExportableVoyage.DateFormat)}"""; _filePath = Path.ChangeExtension(Path.GetTempFileName(), "csv"); File.WriteAllLines(_filePath, ["", record]); @@ -103,7 +103,7 @@ public async Task InvalidVesselTest() _ = await _factory.Operators.AddAsync(Operator); var date = DateTime.Today; - var record = $@"""{IMO}"",""{Operator}"",""{Number}"",""Depart"",""{Port}"",""{date.ToString(ExportableVoyage.DateFormat)}"""; + var record = $@"""{VesselIdentifier}"",""{Operator}"",""{Number}"",""Depart"",""{Port}"",""{date.ToString(ExportableVoyage.DateFormat)}"""; _filePath = Path.ChangeExtension(Path.GetTempFileName(), "csv"); File.WriteAllLines(_filePath, ["", record]); @@ -115,10 +115,10 @@ public async Task InvalidVesselTest() public async Task InvalidPortTest() { _ = await _factory.Operators.AddAsync(Operator); - _ = await _factory.Vessels.AddAsync(IMO, null, null, null, null); + _ = await _factory.Vessels.AddAsync(VesselIdentifier, true, null, null, null, null); var date = DateTime.Today; - var record = $@"""{IMO}"",""{Operator}"",""{Number}"",""Depart"",""{Port}"",""{date.ToString(ExportableVoyage.DateFormat)}"""; + var record = $@"""{VesselIdentifier}"",""{Operator}"",""{Number}"",""Depart"",""{Port}"",""{date.ToString(ExportableVoyage.DateFormat)}"""; _filePath = Path.ChangeExtension(Path.GetTempFileName(), "csv"); File.WriteAllLines(_filePath, ["", record]); @@ -134,7 +134,7 @@ public async Task InvalidEventTypeTest() _ = await _factory.Operators.AddAsync(Operator); var date = DateTime.Today; - var record = $@"""{IMO}"",""{Operator}"",""{Number}"",""Invalid"",""{Port}"",""{date.ToString(ExportableVoyage.DateFormat)}"""; + var record = $@"""{VesselIdentifier}"",""{Operator}"",""{Number}"",""Invalid"",""{Port}"",""{date.ToString(ExportableVoyage.DateFormat)}"""; _filePath = Path.ChangeExtension(Path.GetTempFileName(), "csv"); File.WriteAllLines(_filePath, ["", record]); @@ -150,7 +150,7 @@ public async Task InvalidDateTest() _ = await _factory.Operators.AddAsync(Operator); var date = DateTime.Today; - var record = $@"""{IMO}"",""{Operator}"",""{Number}"",""Depart"",""{Port}"",""31-Jun-2025"""; + var record = $@"""{VesselIdentifier}"",""{Operator}"",""{Number}"",""Depart"",""{Port}"",""31-Jun-2025"""; _filePath = Path.ChangeExtension(Path.GetTempFileName(), "csv"); File.WriteAllLines(_filePath, ["", record]); diff --git a/src/ShippingRecorder.Tests/Mocks/DataGenerator.cs b/src/ShippingRecorder.Tests/Mocks/DataGenerator.cs index 78d893e..44aec9f 100644 --- a/src/ShippingRecorder.Tests/Mocks/DataGenerator.cs +++ b/src/ShippingRecorder.Tests/Mocks/DataGenerator.cs @@ -226,7 +226,8 @@ public static Vessel CreateVessel() var vessel = new Vessel { Id = RandomId(), - IMO = RandomInt(0, 9999999).ToString("0000000"), + Identifier = RandomInt(0, 9999999).ToString("0000000"), + IsIMO = true, Built = 1950 + RandomInt(0, DateTime.Today.Year - 1950), Draught = RandomDecimal(2M, 10M), Length = RandomInt(5, 300), diff --git a/src/ShippingRecorder.Tests/ShippingRecorder.Tests.csproj b/src/ShippingRecorder.Tests/ShippingRecorder.Tests.csproj index ab37da3..2405ce1 100644 --- a/src/ShippingRecorder.Tests/ShippingRecorder.Tests.csproj +++ b/src/ShippingRecorder.Tests/ShippingRecorder.Tests.csproj @@ -3,7 +3,7 @@ net9.0 false - 1.8.0.0 + 1.9.0.0 NU1900 From db54f46d138236d67d18901ddfd83fc3f8b62936 Mon Sep 17 00:00:00 2001 From: Dave Walker Date: Sun, 18 Jan 2026 10:23:51 +0000 Subject: [PATCH 2/3] Update editing and validation of vessel identifier to accommodate non-IMO identifiers --- .../Database/VesselManager.cs | 2 ++ src/ShippingRecorder.Entities/Db/Vessel.cs | 4 ++-- .../Views/Shared/_VesselProperties.cshtml | 8 +++++++- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/ShippingRecorder.BusinessLogic/Database/VesselManager.cs b/src/ShippingRecorder.BusinessLogic/Database/VesselManager.cs index d4cb708..d3dbbab 100644 --- a/src/ShippingRecorder.BusinessLogic/Database/VesselManager.cs +++ b/src/ShippingRecorder.BusinessLogic/Database/VesselManager.cs @@ -88,6 +88,7 @@ public async Task AddAsync(string identifier, bool isIMO, int? built, de var vessel = new Vessel { Identifier = identifier, + IsIMO = isIMO, Built = built, Draught = draught, Length = length, @@ -166,6 +167,7 @@ public async Task UpdateAsync(long id, string identifier, bool isIMO, in // Update the vessel properties and save changes vessel.Identifier = identifier; + vessel.IsIMO = isIMO; vessel.Built = built; vessel.Draught = draught; vessel.Length = length; diff --git a/src/ShippingRecorder.Entities/Db/Vessel.cs b/src/ShippingRecorder.Entities/Db/Vessel.cs index df04e34..26ef9eb 100644 --- a/src/ShippingRecorder.Entities/Db/Vessel.cs +++ b/src/ShippingRecorder.Entities/Db/Vessel.cs @@ -23,8 +23,8 @@ public class Vessel : ShippingRecorderEntityBase [Required(ErrorMessage = "You must provide a vessel identifier")] public string Identifier { get; set; } - [DisplayName("Is IMO")] - public bool IsIMO { get; set; } = true; + [DisplayName("Identifier is an IMO")] + public bool IsIMO { get; set; } [DisplayName("Built")] [YearRange(1900)] diff --git a/src/ShippingRecorder.Mvc/Views/Shared/_VesselProperties.cshtml b/src/ShippingRecorder.Mvc/Views/Shared/_VesselProperties.cshtml index df4eaf1..b8e3017 100644 --- a/src/ShippingRecorder.Mvc/Views/Shared/_VesselProperties.cshtml +++ b/src/ShippingRecorder.Mvc/Views/Shared/_VesselProperties.cshtml @@ -8,7 +8,6 @@ } @Html.HiddenFor(m => m.Vessel.Id) -@Html.HiddenFor(m => m.Vessel.IsIMO)
@@ -16,6 +15,13 @@
@Html.TextBoxFor(m => m.Vessel.Identifier, identifierAttributes)
+ @if (Model.Editable) + { +
+ @Html.CheckBoxFor(m => m.Vessel.IsIMO, new { @class = "form-check-input" }) + @Html.LabelFor(m => m.Vessel.IsIMO, new { @class = "form-check-label" }) +
+ } @Html.ValidationMessageFor(m => m.Vessel.Identifier, "", new { @class = "text-danger" })
From 796d48e62404377b9b6587620dd76861f417a882 Mon Sep 17 00:00:00 2001 From: Dave Walker Date: Sun, 18 Jan 2026 12:04:42 +0000 Subject: [PATCH 3/3] Relax mandatory fields on Vessel Registration History --- src/ShippingRecorder.Entities/Db/RegistrationHistory.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/ShippingRecorder.Entities/Db/RegistrationHistory.cs b/src/ShippingRecorder.Entities/Db/RegistrationHistory.cs index 74ec56f..1a21aeb 100644 --- a/src/ShippingRecorder.Entities/Db/RegistrationHistory.cs +++ b/src/ShippingRecorder.Entities/Db/RegistrationHistory.cs @@ -37,17 +37,14 @@ public class RegistrationHistory : ShippingRecorderEntityBase, IEquatable
IMOIdentifier Name Built Draught
@vessel.IMO@vessel.Identifier @vesselName @vessel.Built @vessel.Draught