feat: Enhance room image handling by introducing default image and updating display logic; add unit tests for image resolution

This commit is contained in:
Alexa
2026-07-02 10:37:34 +03:00
parent fbfabaf26e
commit 0986a0a118
4 changed files with 58 additions and 8 deletions
+1
View File
@@ -88,3 +88,4 @@ Recovered(*)/
local-releases/** local-releases/**
DorkNet.Models/bin-verify/** DorkNet.Models/bin-verify/**
DorkNet.Models/bin-verify2/** DorkNet.Models/bin-verify2/**
identityserver-signing.pfx
+39
View File
@@ -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));
}
}
@@ -65,7 +65,6 @@ public class CommunityBoardController(
? new() ? new()
: await db.Rooms : await db.Rooms
.Where(r => ids.Contains(r.Id)) .Where(r => ids.Contains(r.Id))
.Select(r => new { r.Id, r.Name, r.ImageName })
.ToDictionaryAsync(r => r.Id); .ToDictionaryAsync(r => r.Id);
// 2020.12 FeaturedRoomGroup deserializer (NMPFCIJPODA.PPGFHEDFBEA) // 2020.12 FeaturedRoomGroup deserializer (NMPFCIJPODA.PPGFHEDFBEA)
// reads required keys: FeaturedRoomGroupId, Name, Rooms (NOT // reads required keys: FeaturedRoomGroupId, Name, Rooms (NOT
@@ -76,13 +75,13 @@ public class CommunityBoardController(
FeaturedRoomGroupId = 0L, FeaturedRoomGroupId = 0L,
Name = group.Name ?? string.Empty, Name = group.Name ?? string.Empty,
Rooms = ids.Select(id => rooms.TryGetValue(id, out var r) Rooms = ids.Select(id => rooms.TryGetValue(id, out var r)
? new { RoomName = r.Name, RoomId = r.Id, ImageName = r.ImageName ?? string.Empty } ? new { RoomName = r.Name, RoomId = r.Id, ImageName = RoomService.ResolveDisplayImageName(r) }
: new { RoomName = string.Empty, RoomId = id, ImageName = string.Empty }) : new { RoomName = string.Empty, RoomId = id, ImageName = RoomService.DefaultRoomImageName })
.ToArray(), .ToArray(),
// Keep the old key around for any 2020.03 clients hitting prod. // Keep the old key around for any 2020.03 clients hitting prod.
FeaturedRooms = ids.Select(id => rooms.TryGetValue(id, out var r) FeaturedRooms = ids.Select(id => rooms.TryGetValue(id, out var r)
? new { RoomName = r.Name, RoomId = r.Id, ImageName = r.ImageName ?? string.Empty } ? new { RoomName = r.Name, RoomId = r.Id, ImageName = RoomService.ResolveDisplayImageName(r) }
: new { RoomName = string.Empty, RoomId = id, ImageName = string.Empty }) : new { RoomName = string.Empty, RoomId = id, ImageName = RoomService.DefaultRoomImageName })
.ToArray(), .ToArray(),
}; };
} }
+14 -3
View File
@@ -11,6 +11,8 @@ namespace DorkNet.Server.Services;
/// </summary> /// </summary>
public class RoomService(DorkNetDbContext db) public class RoomService(DorkNetDbContext db)
{ {
public const string DefaultRoomImageName = "image_RecCenter.png";
/// <summary> /// <summary>
/// Idempotent seed of the well-known Rec Room Original rooms — pulled /// Idempotent seed of the well-known Rec Room Original rooms — pulled
/// from the AGRoomRuntimeConfig.Locations array we walked in /// from the AGRoomRuntimeConfig.Locations array we walked in
@@ -232,7 +234,6 @@ public class RoomService(DorkNetDbContext db)
// image/<blob-name> keys, so do NOT require the mapped blob // image/<blob-name> keys, so do NOT require the mapped blob
// filename to exist on local disk before using it. Local disk // filename to exist on local disk before using it. Local disk
// is only a fallback for rooms with no blob-name mapping. // 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"); var imagesDir = Path.Combine(AppContext.BaseDirectory, "data", "images");
bool OnDisk(string name) => bool OnDisk(string name) =>
!string.IsNullOrEmpty(name) && File.Exists(Path.Combine(imagesDir, name)); !string.IsNullOrEmpty(name) && File.Exists(Path.Combine(imagesDir, name));
@@ -248,7 +249,7 @@ public class RoomService(DorkNetDbContext db)
else if (OnDisk(r.ImageName)) else if (OnDisk(r.ImageName))
preferred = r.ImageName; preferred = r.ImageName;
else else
preferred = ultimateFallback; preferred = DefaultRoomImageName;
if (r.ImageName != preferred) if (r.ImageName != preferred)
{ {
@@ -1085,7 +1086,7 @@ public class RoomService(DorkNetDbContext db)
Description = r.Description, Description = r.Description,
CreatorPlayerId = r.CreatorPlayerId, CreatorPlayerId = r.CreatorPlayerId,
CreatorAccountId = r.CreatorPlayerId, CreatorAccountId = r.CreatorPlayerId,
ImageName = r.ImageName, ImageName = ResolveDisplayImageName(r),
State = r.State, State = r.State,
Accessibility = r.Accessibility, Accessibility = r.Accessibility,
SupportsLevelVoting = r.SupportsLevelVoting, 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;
}
/// <summary> /// <summary>
/// Idempotent admin overrides applied AFTER SeedAsync. Keeps the seed /// Idempotent admin overrides applied AFTER SeedAsync. Keeps the seed
/// table itself untouched (so a clean DB build still seeds the /// table itself untouched (so a clean DB build still seeds the