diff --git a/Definitions/DTO/Comparers/DtoMissingObjectEntryComparer.cs b/Definitions/DTO/Comparers/DtoMissingObjectEntryComparer.cs new file mode 100644 index 00000000..2f94e6f3 --- /dev/null +++ b/Definitions/DTO/Comparers/DtoMissingObjectEntryComparer.cs @@ -0,0 +1,21 @@ +using System.Diagnostics.CodeAnalysis; + +namespace Definitions.DTO.Comparers; + +public class DtoMissingObjectEntryComparer : IEqualityComparer +{ + public bool Equals(DtoMissingObjectEntry? x, DtoMissingObjectEntry? y) + { + if (x is null || y is null) + { + return false; + } + + return x.DatName == y.DatName + && x.DatChecksum == y.DatChecksum + && x.ObjectType == y.ObjectType; + } + + public int GetHashCode([DisallowNull] DtoMissingObjectEntry obj) + => HashCode.Combine(obj.DatName, obj.DatChecksum, obj.ObjectType); +} diff --git a/ObjectService/RouteHandlers/TableHandlers/ObjectMissingRouteHandler.cs b/ObjectService/RouteHandlers/TableHandlers/ObjectMissingRouteHandler.cs new file mode 100644 index 00000000..c946e42d --- /dev/null +++ b/ObjectService/RouteHandlers/TableHandlers/ObjectMissingRouteHandler.cs @@ -0,0 +1,130 @@ +using Common; +using Definitions; +using Definitions.Database; +using Definitions.DTO; +using Definitions.DTO.Mappers; +using Definitions.ObjectModels.Types; +using Definitions.Web; +using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; + +namespace ObjectService.RouteHandlers.TableHandlers; + +public class ObjectMissingRouteHandler : ITableRouteHandler +{ + public static string BaseRoute => RoutesV2.Missing; + public static Delegate ListDelegate => ListAsync; + public static Delegate CreateDelegate => CreateAsync; + public static Delegate ReadDelegate => ReadAsync; + public static Delegate UpdateDelegate => UpdateAsync; + public static Delegate DeleteDelegate => DeleteAsync; + + public static void MapAdditionalRoutes(IEndpointRouteBuilder parentRoute) + { + // No additional routes needed for missing objects beyond the standard CRUD operations + } + + static async Task ListAsync([FromServices] LocoDbContext db, [FromServices] ILogger logger) + { + logger.LogInformation("[ListAsync] List requested for missing objects"); + + return Results.Ok( + await db.Objects + .Where(x => x.Availability == ObjectAvailability.Missing) + .Select(x => x.ToDtoEntry()) + .ToListAsync()); + } + + static async Task CreateAsync([FromBody] DtoMissingObjectEntry entry, [FromServices] LocoDbContext db, [FromServices] ILogger logger) + { + logger.LogInformation("[CreateAsync] Create requested"); + + var objName = $"{entry.DatName}_{entry.DatChecksum}"; + var existing = await db.Objects.FirstOrDefaultAsync(x => x.Name == objName); + if (existing != null) + { + return Results.Conflict($"Object already exists in the database. DatName={entry.DatName} DatChecksum={entry.DatChecksum} UploadedDate={existing.UploadedDate}"); + } + + // double check it's missing + if (db.DoesObjectExist(entry.DatName, entry.DatChecksum, out var existingObject) && existingObject != null) + { + return Results.Conflict($"Object already exists in the database. UniqueId={existingObject.Id} DatName={entry.DatName} DatChecksum={entry.DatChecksum} UploadedDate={existingObject.UploadedDate}"); + } + + // save to db if true + var tblObject = new TblObject() + { + Name = $"{entry.DatName}_{entry.DatChecksum}", + Description = string.Empty, + ObjectSource = ObjectSource.Custom, + ObjectType = entry.ObjectType, + VehicleType = null, + Availability = ObjectAvailability.Missing, + CreatedDate = null, + ModifiedDate = null, + UploadedDate = DateOnly.UtcToday, + Authors = [], + Tags = [], + ObjectPacks = [], + DatObjects = [], + StringTable = [], + SubObjectId = 0, + Licence = null, + }; + + _ = await db.Objects.AddAsync(tblObject); + _ = await db.SaveChangesAsync(); + + // make dat objects + //var xxHash3 = XxHash3.HashToUInt64(datFileBytes); + tblObject.DatObjects.Add(new TblDatObject() + { + ObjectId = tblObject.Id, + DatName = entry.DatName, + DatChecksum = entry.DatChecksum, + xxHash3 = 0, + Object = tblObject, + }); + + // save again + _ = await db.SaveChangesAsync(); + return Results.Created($"Successfully added 'missing' DAT object {tblObject.Name} with checksum {entry.DatChecksum} and unique id {tblObject.Id}", tblObject.Id); + } + + static async Task ReadAsync([FromRoute] UniqueObjectId id, [FromServices] LocoDbContext db, [FromServices] ILogger logger) + { + logger.LogInformation("[ReadAsync] Read requested"); + + var existing = await db.Objects + .FirstOrDefaultAsync(x => x.Availability == ObjectAvailability.Missing && x.Id == id); + + if (existing == null) + { + return Results.NotFound(); + } + + return Results.Ok(existing.ToDtoEntry()); + } + + static async Task UpdateAsync([FromRoute] UniqueObjectId id, [FromBody] DtoMissingObjectEntry request, [FromServices] LocoDbContext db) + => await Task.FromResult(Results.Problem(statusCode: StatusCodes.Status501NotImplemented)); + + static async Task DeleteAsync([FromRoute] UniqueObjectId id, [FromServices] LocoDbContext db, [FromServices] ILogger logger) + { + logger.LogInformation("[DeleteAsync] Delete requested"); + + var existing = await db.Objects + .FirstOrDefaultAsync(x => x.Availability == ObjectAvailability.Missing && x.Id == id); + + if (existing == null) + { + return Results.NotFound(); + } + + _ = db.Objects.Remove(existing); + _ = await db.SaveChangesAsync(); + + return Results.Ok(); + } +} diff --git a/ObjectService/RouteHandlers/TableHandlers/ObjectRouteHandler.cs b/ObjectService/RouteHandlers/TableHandlers/ObjectRouteHandler.cs index 47d806d5..b7947f80 100644 --- a/ObjectService/RouteHandlers/TableHandlers/ObjectRouteHandler.cs +++ b/ObjectService/RouteHandlers/TableHandlers/ObjectRouteHandler.cs @@ -35,81 +35,13 @@ public static void MapRoutes(IEndpointRouteBuilder parentRoute) public static void MapAdditionalRoutes(IEndpointRouteBuilder parentRoute) { - _ = parentRoute.MapGet(RoutesV2.Missing, ListMissingObjects); - _ = parentRoute.MapPost(RoutesV2.Missing, AddMissingObject); + BaseTableRouteHandler.MapRoutes(parentRoute); var resourceRoute = parentRoute.MapGroup(RoutesV2.ResourceRoute); _ = resourceRoute.MapGet(RoutesV2.File, GetObjectFileAsync); _ = resourceRoute.MapGet(RoutesV2.Images, GetObjectImagesAsync); } - static async Task ListMissingObjects([FromServices] LocoDbContext db, [FromServices] ILogger logger) - { - logger.LogInformation("[ListMissingObjects] List requested for missing objects"); - - return Results.Ok( - await db.Objects - .Include(x => x.DatObjects) - .Where(x => x.Availability == ObjectAvailability.Missing) - .Select(x => x.ToDtoEntry()) - .ToListAsync()); - } - - static async Task AddMissingObject([FromBody] DtoMissingObjectEntry entry, [FromServices] LocoDbContext db, [FromServices] ILogger logger) - { - var objName = $"{entry.DatName}_{entry.DatChecksum}"; - var existing = await db.Objects.FirstOrDefaultAsync(x => x.Name == objName); - if (existing != null) - { - return Results.Conflict($"Object already exists in the database. DatName={entry.DatName} DatChecksum={entry.DatChecksum} UploadedDate={existing!.UploadedDate}"); - } - - // double check it's missing - if (db.DoesObjectExist(entry.DatName, entry.DatChecksum, out var existingObject) && existingObject != null) - { - return Results.Conflict($"Object already exists in the database. UniqueId={existingObject.Id} DatName={entry.DatName} DatChecksum={entry.DatChecksum} UploadedDate={existingObject!.UploadedDate}"); - } - - // save to db if true - var tblObject = new TblObject() - { - Name = $"{entry.DatName}_{entry.DatChecksum}", - Description = string.Empty, - ObjectSource = ObjectSource.Custom, - ObjectType = entry.ObjectType, - VehicleType = null, - Availability = ObjectAvailability.Missing, - CreatedDate = null, - ModifiedDate = null, - UploadedDate = DateOnly.UtcToday, - Authors = [], - Tags = [], - ObjectPacks = [], - DatObjects = [], - StringTable = [], - SubObjectId = 0, - Licence = null, - }; - - _ = await db.Objects.AddAsync(tblObject); - _ = await db.SaveChangesAsync(); - - // make dat objects - //var xxHash3 = XxHash3.HashToUInt64(datFileBytes); - tblObject.DatObjects.Add(new TblDatObject() - { - ObjectId = tblObject.Id, - DatName = entry.DatName, - DatChecksum = entry.DatChecksum, - xxHash3 = 0, - Object = tblObject, - }); - - // save again - _ = await db.SaveChangesAsync(); - return Results.Created($"Successfully added 'missing' DAT object {tblObject.Name} with checksum {entry.DatChecksum} and unique id {tblObject.Id}", tblObject.Id); - } - //static async Task CreateAsync(DtoObjectDescriptor request, [FromServices] LocoDbContext db, [FromServices] IServiceProvider sp, [FromServices] ILogger logger) //{ // logger.LogInformation("[CreateAsync] Upload requested"); diff --git a/Tests/ObjectServiceIntegrationTests/ObjectMissingRoutesTest.cs b/Tests/ObjectServiceIntegrationTests/ObjectMissingRoutesTest.cs new file mode 100644 index 00000000..0641edd0 --- /dev/null +++ b/Tests/ObjectServiceIntegrationTests/ObjectMissingRoutesTest.cs @@ -0,0 +1,12 @@ +using Definitions.Database; +using Definitions.DTO; +using NUnit.Framework; + +namespace ObjectService.Tests.Integration; + +[TestFixture] +public class ObjectMissingRoutesTest + //: BaseReferenceDataTableTestFixture +{ + // todo: implement tests for missing objects routes +}