From e47de269b957260fbff0f3cfecb566088bd5aa74 Mon Sep 17 00:00:00 2001 From: Alexa <53471801+Alexa-RR@users.noreply.github.com> Date: Thu, 2 Jul 2026 10:37:34 +0300 Subject: [PATCH] feat: Enhance room image handling by introducing default image and updating display logic; add unit tests for image resolution --- .gitignore | 1 + DorkNet.Server.Tests/RoomServiceTests.cs | 39 +++++++++++++++++++ .../CommunityBoardController.cs | 9 ++--- DorkNet.Server/Services/RoomService.cs | 17 ++++++-- 4 files changed, 58 insertions(+), 8 deletions(-) create mode 100644 DorkNet.Server.Tests/RoomServiceTests.cs diff --git a/.gitignore b/.gitignore index 4ec5dd0..efdd618 100644 --- a/.gitignore +++ b/.gitignore @@ -88,3 +88,4 @@ Recovered(*)/ local-releases/** DorkNet.Models/bin-verify/** DorkNet.Models/bin-verify2/** +identityserver-signing.pfx diff --git a/DorkNet.Server.Tests/RoomServiceTests.cs b/DorkNet.Server.Tests/RoomServiceTests.cs new file mode 100644 index 0000000..0c57226 --- /dev/null +++ b/DorkNet.Server.Tests/RoomServiceTests.cs @@ -0,0 +1,39 @@ +using System.Text.Json; +using DorkNet.Server.Data.Entities; +using DorkNet.Server.Services; + +namespace DorkNet.Server.Tests; + +public sealed class RoomServiceTests +{ + [Fact] + public void ToWireRoom_never_emits_empty_image_name() + { + var room = new RoomEntity + { + Id = 1001, + Name = "CustomRoomWithoutImage", + Description = "Custom room", + ImageName = "", + Accessibility = 1, + State = 0, + }; + + var json = JsonSerializer.Serialize(RoomService.ToWireRoom(room)); + using var document = JsonDocument.Parse(json); + + Assert.Equal(RoomService.DefaultRoomImageName, document.RootElement.GetProperty("ImageName").GetString()); + } + + [Fact] + public void ResolveDisplayImageName_preserves_existing_image_name() + { + var room = new RoomEntity + { + Name = "Paintball", + ImageName = "custom-thumbnail.png", + }; + + Assert.Equal("custom-thumbnail.png", RoomService.ResolveDisplayImageName(room)); + } +} diff --git a/DorkNet.Server/Controllers/API/CommunityBoard/CommunityBoardController.cs b/DorkNet.Server/Controllers/API/CommunityBoard/CommunityBoardController.cs index 6115c83..5324efe 100644 --- a/DorkNet.Server/Controllers/API/CommunityBoard/CommunityBoardController.cs +++ b/DorkNet.Server/Controllers/API/CommunityBoard/CommunityBoardController.cs @@ -65,7 +65,6 @@ public class CommunityBoardController( ? new() : await db.Rooms .Where(r => ids.Contains(r.Id)) - .Select(r => new { r.Id, r.Name, r.ImageName }) .ToDictionaryAsync(r => r.Id); // 2020.12 FeaturedRoomGroup deserializer (NMPFCIJPODA.PPGFHEDFBEA) // reads required keys: FeaturedRoomGroupId, Name, Rooms (NOT @@ -76,13 +75,13 @@ public class CommunityBoardController( FeaturedRoomGroupId = 0L, Name = group.Name ?? string.Empty, Rooms = ids.Select(id => rooms.TryGetValue(id, out var r) - ? new { RoomName = r.Name, RoomId = r.Id, ImageName = r.ImageName ?? string.Empty } - : new { RoomName = string.Empty, RoomId = id, ImageName = string.Empty }) + ? new { RoomName = r.Name, RoomId = r.Id, ImageName = RoomService.ResolveDisplayImageName(r) } + : new { RoomName = string.Empty, RoomId = id, ImageName = RoomService.DefaultRoomImageName }) .ToArray(), // Keep the old key around for any 2020.03 clients hitting prod. FeaturedRooms = ids.Select(id => rooms.TryGetValue(id, out var r) - ? new { RoomName = r.Name, RoomId = r.Id, ImageName = r.ImageName ?? string.Empty } - : new { RoomName = string.Empty, RoomId = id, ImageName = string.Empty }) + ? new { RoomName = r.Name, RoomId = r.Id, ImageName = RoomService.ResolveDisplayImageName(r) } + : new { RoomName = string.Empty, RoomId = id, ImageName = RoomService.DefaultRoomImageName }) .ToArray(), }; } diff --git a/DorkNet.Server/Services/RoomService.cs b/DorkNet.Server/Services/RoomService.cs index ceb4e43..fcdba91 100644 --- a/DorkNet.Server/Services/RoomService.cs +++ b/DorkNet.Server/Services/RoomService.cs @@ -11,6 +11,8 @@ namespace DorkNet.Server.Services; /// public class RoomService(DorkNetDbContext db) { + public const string DefaultRoomImageName = "image_RecCenter.png"; + /// /// Idempotent seed of the well-known Rec Room Original rooms — pulled /// from the AGRoomRuntimeConfig.Locations array we walked in @@ -232,7 +234,6 @@ public class RoomService(DorkNetDbContext db) // image/ keys, so do NOT require the mapped blob // filename to exist on local disk before using it. Local disk // is only a fallback for rooms with no blob-name mapping. - const string ultimateFallback = "image_RecCenter.png"; var imagesDir = Path.Combine(AppContext.BaseDirectory, "data", "images"); bool OnDisk(string name) => !string.IsNullOrEmpty(name) && File.Exists(Path.Combine(imagesDir, name)); @@ -248,7 +249,7 @@ public class RoomService(DorkNetDbContext db) else if (OnDisk(r.ImageName)) preferred = r.ImageName; else - preferred = ultimateFallback; + preferred = DefaultRoomImageName; if (r.ImageName != preferred) { @@ -1085,7 +1086,7 @@ public class RoomService(DorkNetDbContext db) Description = r.Description, CreatorPlayerId = r.CreatorPlayerId, CreatorAccountId = r.CreatorPlayerId, - ImageName = r.ImageName, + ImageName = ResolveDisplayImageName(r), State = r.State, Accessibility = r.Accessibility, SupportsLevelVoting = r.SupportsLevelVoting, @@ -1129,6 +1130,16 @@ public class RoomService(DorkNetDbContext db) }, }; + public static string ResolveDisplayImageName(RoomEntity r) + { + if (!string.IsNullOrWhiteSpace(r.ImageName)) + return r.ImageName; + + return RoomImagesByName.TryGetValue(r.Name, out var imageName) && !string.IsNullOrWhiteSpace(imageName) + ? imageName + : DefaultRoomImageName; + } + /// /// Idempotent admin overrides applied AFTER SeedAsync. Keeps the seed /// table itself untouched (so a clean DB build still seeds the