diff --git a/Definitions/Web/Client.cs b/Definitions/Web/Client.cs index 5b14082f..4ba1c3f5 100644 --- a/Definitions/Web/Client.cs +++ b/Definitions/Web/Client.cs @@ -43,4 +43,15 @@ public static async Task> GetObjectListAsync(HttpCli RoutesV2.Objects, request); } + + public static async Task AddMissingObjectAsync(HttpClient client, DtoMissingObjectEntry entry, ILogger? logger = null) + { + logger?.Debug($"Posting missing object {entry.DatName} with checksum {entry.DatChecksum} to {client.BaseAddress?.OriginalString}{RoutesV2.Objects}{RoutesV2.Missing}"); + return await ClientHelpers.PostAsync( + client, + ApiVersion, + RoutesV2.Objects + RoutesV2.Missing, + entry, + logger); + } } diff --git a/Gui/ObjectServiceClient.cs b/Gui/ObjectServiceClient.cs index a7101bb7..bec4fc57 100644 --- a/Gui/ObjectServiceClient.cs +++ b/Gui/ObjectServiceClient.cs @@ -69,4 +69,7 @@ public async Task> GetObjectListAsync() public async Task UploadDatFileAsync(string filename, byte[] datFileBytes, DateOnly creationDate, DateOnly modifiedDate) => await Client.UploadDatFileAsync(WebClient, filename, datFileBytes, creationDate, modifiedDate, Logger); + + public async Task AddMissingObjectAsync(DtoMissingObjectEntry entry) + => await Client.AddMissingObjectAsync(WebClient, entry, Logger); } diff --git a/Gui/ViewModels/LocoTypes/SCV5ViewModel.cs b/Gui/ViewModels/LocoTypes/SCV5ViewModel.cs index 8bc3b125..2e0701f2 100644 --- a/Gui/ViewModels/LocoTypes/SCV5ViewModel.cs +++ b/Gui/ViewModels/LocoTypes/SCV5ViewModel.cs @@ -160,7 +160,24 @@ async Task DownloadMissingObjects(GameObjDataFolder targetFolder) if (onlineObj == null) { - logger.Error("Couldn't find a matching object in the online index"); + logger.Error($"Couldn't find a matching object in the online index for {obj.ObjectType} \"{obj.Name}\" with checksum {obj.Checksum}"); + + // Add this missing object to the server's missing objects list + var missingEntry = new Definitions.DTO.DtoMissingObjectEntry( + obj.Name, + obj.Checksum, + obj.ObjectType.Convert()); + + var result = await Model.ObjectServiceClient.AddMissingObjectAsync(missingEntry); + if (result != 0) + { + logger.Info($"Successfully added missing object to server: {obj.Name} ({obj.Checksum})"); + } + else + { + logger.Error($"Failed to add missing object to server: {obj.Name} ({obj.Checksum})"); + } + continue; } diff --git a/Tests/ObjectServiceIntegrationTests/BaseReferenceDataTableTestFixture.cs b/Tests/ObjectServiceIntegrationTests/BaseReferenceDataTableTestFixture.cs index bf6b1bfa..c3c99937 100644 --- a/Tests/ObjectServiceIntegrationTests/BaseReferenceDataTableTestFixture.cs +++ b/Tests/ObjectServiceIntegrationTests/BaseReferenceDataTableTestFixture.cs @@ -22,16 +22,19 @@ public abstract class BaseRouteHandlerTestFixture [Test] public abstract Task PutAsync(); [Test] public abstract Task DeleteAsync(); + protected LocoDbContext GetDbContext() + => testWebAppFactory + .Services + .CreateScope() + .ServiceProvider + .GetRequiredService(); + async Task SeedDataAsync() { - using (var scope = testWebAppFactory.Services.CreateScope()) - { - var dbContext = scope.ServiceProvider.GetRequiredService(); + using var dbContext = GetDbContext(); + await SeedDataCoreAsync(dbContext); + _ = await dbContext.SaveChangesAsync(); - // Seed data - await SeedDataCoreAsync(dbContext); - _ = await dbContext.SaveChangesAsync(); - } } protected abstract Task SeedDataCoreAsync(LocoDbContext db); diff --git a/Tests/ObjectServiceIntegrationTests/ObjectRoutesTest.cs b/Tests/ObjectServiceIntegrationTests/ObjectRoutesTest.cs index f094a4ee..4bc31777 100644 --- a/Tests/ObjectServiceIntegrationTests/ObjectRoutesTest.cs +++ b/Tests/ObjectServiceIntegrationTests/ObjectRoutesTest.cs @@ -224,4 +224,33 @@ [new DtoDatObjectEntry(1, "AZVOG15C", 3072098364, 7051740550869341430, 3)], // d AssertDtoObjectDescriptorsAreEqual(results, expected); } + + [Test] + public async Task AddMissingObjectAsync() + { + // arrange + var missingEntry = new DtoMissingObjectEntry("TESTOBJ1", 123456789, ObjectType.Vehicle); + + // act + var result = await Client.AddMissingObjectAsync(HttpClient!, missingEntry, new Logger()); + + // assert + Assert.That(result, Is.Not.Zero, "Adding missing object should return the new unique id for that object"); + + // verify the object was added to the database + using var dbContext = GetDbContext(); + var addedObject = await dbContext.Objects + .Include(x => x.DatObjects) + .FirstOrDefaultAsync(x => x.Name == $"{missingEntry.DatName}_{missingEntry.DatChecksum}"); + + using (Assert.EnterMultipleScope()) + { + Assert.That(addedObject, Is.Not.Null, "Object should exist in database"); + Assert.That(addedObject!.Availability, Is.EqualTo(ObjectAvailability.Missing)); + Assert.That(addedObject.ObjectType, Is.EqualTo(ObjectType.Vehicle)); + Assert.That(addedObject.DatObjects.Count, Is.EqualTo(1)); + Assert.That(addedObject.DatObjects.First().DatName, Is.EqualTo(missingEntry.DatName)); + Assert.That(addedObject.DatObjects.First().DatChecksum, Is.EqualTo(missingEntry.DatChecksum)); + } + } }