Fix campaign owner labels to always use display names
This commit is contained in:
@@ -53,6 +53,7 @@ Gameplay capabilities now include:
|
|||||||
- Character owner selection in edit modal backed by existing-username dropdown data
|
- Character owner selection in edit modal backed by existing-username dropdown data
|
||||||
- Role-aware authorization with admin role support (including admin user/role management)
|
- Role-aware authorization with admin role support (including admin user/role management)
|
||||||
- Campaign deletion by campaign owner or admin (unlinks characters from the campaign and clears campaign log entries)
|
- Campaign deletion by campaign owner or admin (unlinks characters from the campaign and clears campaign log entries)
|
||||||
|
- Campaign management owner labels use account display names (no GUID fallback rendering)
|
||||||
|
|
||||||
## Prerequisites
|
## Prerequisites
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ public sealed class CampaignApiTests : ApiTestBase
|
|||||||
var campaign = await PostAsync<CreateCampaignRequest, CampaignDetails>(gmClient, "/api/campaigns", new("Alpha Campaign", "dnd5e"));
|
var campaign = await PostAsync<CreateCampaignRequest, CampaignDetails>(gmClient, "/api/campaigns", new("Alpha Campaign", "dnd5e"));
|
||||||
|
|
||||||
var gmCharacter = await PostAsync<CreateCharacterRequest, CharacterSummary>(gmClient, "/api/characters", new("Arin", campaign.Id));
|
var gmCharacter = await PostAsync<CreateCharacterRequest, CharacterSummary>(gmClient, "/api/characters", new("Arin", campaign.Id));
|
||||||
|
Assert.Equal("Game Master", gmCharacter.OwnerDisplayName);
|
||||||
|
|
||||||
var activateResponse = await gmClient.PostAsync($"/api/characters/{gmCharacter.Id}/activate", null);
|
var activateResponse = await gmClient.PostAsync($"/api/characters/{gmCharacter.Id}/activate", null);
|
||||||
Assert.Equal(HttpStatusCode.OK, activateResponse.StatusCode);
|
Assert.Equal(HttpStatusCode.OK, activateResponse.StatusCode);
|
||||||
@@ -39,10 +40,12 @@ public sealed class CampaignApiTests : ApiTestBase
|
|||||||
var details = await GetAsync<CampaignDetails>(gmClient, $"/api/campaigns/{campaign.Id}");
|
var details = await GetAsync<CampaignDetails>(gmClient, $"/api/campaigns/{campaign.Id}");
|
||||||
Assert.Equal(campaign.Id, details.Id);
|
Assert.Equal(campaign.Id, details.Id);
|
||||||
Assert.Single(details.Characters);
|
Assert.Single(details.Characters);
|
||||||
|
Assert.Equal("Game Master", details.Characters[0].OwnerDisplayName);
|
||||||
|
|
||||||
var currentCampaignCharacters = await GetAsync<IReadOnlyList<CharacterSummary>>(gmClient, "/api/characters");
|
var currentCampaignCharacters = await GetAsync<IReadOnlyList<CharacterSummary>>(gmClient, "/api/characters");
|
||||||
Assert.Single(currentCampaignCharacters);
|
Assert.Single(currentCampaignCharacters);
|
||||||
Assert.Equal(gmCharacter.Id, currentCampaignCharacters[0].Id);
|
Assert.Equal(gmCharacter.Id, currentCampaignCharacters[0].Id);
|
||||||
|
Assert.Equal("Game Master", currentCampaignCharacters[0].OwnerDisplayName);
|
||||||
|
|
||||||
var otherCampaign = await PostAsync<CreateCampaignRequest, CampaignDetails>(gmClient, "/api/campaigns", new("Beta Campaign", "d6"));
|
var otherCampaign = await PostAsync<CreateCampaignRequest, CampaignDetails>(gmClient, "/api/campaigns", new("Beta Campaign", "d6"));
|
||||||
|
|
||||||
@@ -96,6 +99,11 @@ public sealed class CampaignApiTests : ApiTestBase
|
|||||||
|
|
||||||
var transferResult = await PutAsync<UpdateCharacterRequest, CharacterSummary>(gmClient, $"/api/characters/{character.Id}", new("Grouped Hero", campaign.Id, "receiver2"));
|
var transferResult = await PutAsync<UpdateCharacterRequest, CharacterSummary>(gmClient, $"/api/characters/{character.Id}", new("Grouped Hero", campaign.Id, "receiver2"));
|
||||||
Assert.Equal("Grouped Hero", transferResult.Name);
|
Assert.Equal("Grouped Hero", transferResult.Name);
|
||||||
|
Assert.Equal("Receiver", transferResult.OwnerDisplayName);
|
||||||
|
|
||||||
|
var gmCampaignView = await GetAsync<CampaignDetails>(gmClient, $"/api/campaigns/{campaign.Id}");
|
||||||
|
var gmViewedCharacter = Assert.Single(gmCampaignView.Characters, c => c.Id == character.Id);
|
||||||
|
Assert.Equal("Receiver", gmViewedCharacter.OwnerDisplayName);
|
||||||
|
|
||||||
var ownerActivate = await ownerClient.PostAsync($"/api/characters/{character.Id}/activate", null);
|
var ownerActivate = await ownerClient.PostAsync($"/api/characters/{character.Id}/activate", null);
|
||||||
Assert.Equal(HttpStatusCode.BadRequest, ownerActivate.StatusCode);
|
Assert.Equal(HttpStatusCode.BadRequest, ownerActivate.StatusCode);
|
||||||
|
|||||||
@@ -590,10 +590,18 @@ public partial class Workspace : IAsyncDisposable
|
|||||||
if (User is not null && ownerUserId == User.Id)
|
if (User is not null && ownerUserId == User.Id)
|
||||||
return "You";
|
return "You";
|
||||||
|
|
||||||
if (SelectedCampaign is not null && ownerUserId == SelectedCampaign.Gm.Id)
|
if (SelectedCampaign is null)
|
||||||
|
return "Unknown owner";
|
||||||
|
|
||||||
|
if (ownerUserId == SelectedCampaign.Gm.Id)
|
||||||
return $"{SelectedCampaign.Gm.DisplayName} (GM)";
|
return $"{SelectedCampaign.Gm.DisplayName} (GM)";
|
||||||
|
|
||||||
return ownerUserId.ToString("N")[..8];
|
var ownerDisplayName = SelectedCampaign.Characters
|
||||||
|
.Where(character => character.OwnerUserId == ownerUserId)
|
||||||
|
.Select(character => character.OwnerDisplayName)
|
||||||
|
.FirstOrDefault(displayName => !string.IsNullOrWhiteSpace(displayName));
|
||||||
|
|
||||||
|
return string.IsNullOrWhiteSpace(ownerDisplayName) ? "Unknown owner" : ownerDisplayName;
|
||||||
}
|
}
|
||||||
|
|
||||||
private string CharacterLabel(Guid characterId)
|
private string CharacterLabel(Guid characterId)
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ public sealed record CreateCharacterRequest(string Name, Guid CampaignId);
|
|||||||
|
|
||||||
public sealed record UpdateCharacterRequest(string Name, Guid CampaignId, string? OwnerUsername = null);
|
public sealed record UpdateCharacterRequest(string Name, Guid CampaignId, string? OwnerUsername = null);
|
||||||
|
|
||||||
public sealed record CharacterSummary(Guid Id, string Name, Guid OwnerUserId, Guid? CampaignId);
|
public sealed record CharacterSummary(Guid Id, string Name, Guid OwnerUserId, Guid? CampaignId, string OwnerDisplayName);
|
||||||
|
|
||||||
public sealed record CreateSkillRequest(string Name, string DiceRollDefinition, int WildDice, bool AllowFumble, Guid? SkillGroupId = null);
|
public sealed record CreateSkillRequest(string Name, string DiceRollDefinition, int WildDice, bool AllowFumble, Guid? SkillGroupId = null);
|
||||||
|
|
||||||
|
|||||||
@@ -948,9 +948,10 @@ public sealed class GameService : IGameService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static CharacterSummary ToCharacterSummary(Character character)
|
private CharacterSummary ToCharacterSummary(Character character)
|
||||||
{
|
{
|
||||||
return new(character.Id, character.Name, character.OwnerUserId, character.CampaignId);
|
var ownerDisplayName = ResolveOwnerDisplayName(character.OwnerUserId);
|
||||||
|
return new(character.Id, character.Name, character.OwnerUserId, character.CampaignId, ownerDisplayName);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static SkillGroupSummary ToSkillGroupSummary(SkillGroup skillGroup)
|
private static SkillGroupSummary ToSkillGroupSummary(SkillGroup skillGroup)
|
||||||
@@ -980,6 +981,13 @@ public sealed class GameService : IGameService
|
|||||||
return JsonSerializer.Serialize(dice, DiceJsonOptions);
|
return JsonSerializer.Serialize(dice, DiceJsonOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private string ResolveOwnerDisplayName(Guid ownerUserId)
|
||||||
|
{
|
||||||
|
return m_UsersById.TryGetValue(ownerUserId, out var owner) && !string.IsNullOrWhiteSpace(owner.DisplayName)
|
||||||
|
? owner.DisplayName
|
||||||
|
: "Unknown owner";
|
||||||
|
}
|
||||||
|
|
||||||
private static IReadOnlyList<RollDieResult> DeserializeDice(string serializedDice)
|
private static IReadOnlyList<RollDieResult> DeserializeDice(string serializedDice)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(serializedDice))
|
if (string.IsNullOrWhiteSpace(serializedDice))
|
||||||
|
|||||||
Reference in New Issue
Block a user