Delete owned campaigns on user delete and preserve campaign characters
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
|
||||
- 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)
|
||||
- User deletion by admin also deletes campaigns owned by that user and unlinks all characters from those deleted campaigns
|
||||
- Campaign management owner labels use account display names (no GUID fallback rendering)
|
||||
- Character edit flow supports unlinking from campaigns (owner/GM/admin) and assigning to any existing campaign via expanded campaign options
|
||||
- Campaign management supports character deletion by character owner or admin
|
||||
|
||||
@@ -80,4 +80,53 @@ public sealed class ServiceAdminAndCampaignDeletionTests
|
||||
using var db = harness.CreateDbContext();
|
||||
Assert.Empty(db.RollLogEntries.Where(entry => entry.CampaignId == adminDeletedCampaign.Id));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DeleteUser_DeletesOwnedCampaigns_AndUnlinksCharactersInThoseCampaigns()
|
||||
{
|
||||
using var harness = ServiceTestSupport.CreateHarness(4, 5, 6);
|
||||
var service = harness.Service;
|
||||
|
||||
_ = ServiceTestSupport.GetValue(service.Register("admin", "Password123", "Admin"));
|
||||
_ = ServiceTestSupport.GetValue(service.Register("gm", "Password123", "GM"));
|
||||
_ = ServiceTestSupport.GetValue(service.Register("player", "Password123", "Player"));
|
||||
|
||||
var adminSession = ServiceTestSupport.GetValue(service.Login("admin", "Password123")).SessionToken;
|
||||
var gmSession = ServiceTestSupport.GetValue(service.Login("gm", "Password123")).SessionToken;
|
||||
var playerSession = ServiceTestSupport.GetValue(service.Login("player", "Password123")).SessionToken;
|
||||
|
||||
var gmOwnedCampaign = ServiceTestSupport.GetValue(service.CreateCampaign(gmSession, "GM Campaign", "d6"));
|
||||
var adminOwnedCampaign = ServiceTestSupport.GetValue(service.CreateCampaign(adminSession, "Admin Campaign", "d6"));
|
||||
|
||||
var gmCharacterInOwnedCampaign = ServiceTestSupport.GetValue(service.CreateCharacter(gmSession, "GM Hero", gmOwnedCampaign.Id));
|
||||
var playerCharacterInGmCampaign = ServiceTestSupport.GetValue(service.CreateCharacter(playerSession, "Player Hero", gmOwnedCampaign.Id));
|
||||
var gmCharacterOutsideOwnedCampaign = ServiceTestSupport.GetValue(service.CreateCharacter(gmSession, "Visitor", adminOwnedCampaign.Id));
|
||||
|
||||
var playerSkill = ServiceTestSupport.GetValue(service.CreateSkill(playerSession, playerCharacterInGmCampaign.Id, "Scout", "2D+1", 1, true));
|
||||
_ = ServiceTestSupport.GetValue(service.RollSkill(playerSession, playerSkill.Id, "public"));
|
||||
|
||||
var gmUsers = ServiceTestSupport.GetValue(service.GetUsers(adminSession));
|
||||
var gmUser = gmUsers.Single(user => string.Equals(user.Username, "gm", StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
var deleteResult = ServiceTestSupport.GetValue(service.DeleteUser(adminSession, gmUser.Id));
|
||||
Assert.True(deleteResult);
|
||||
|
||||
Assert.False(service.GetCampaign(adminSession, gmOwnedCampaign.Id).Succeeded);
|
||||
|
||||
var playerCharacters = ServiceTestSupport.GetValue(service.GetOwnCharacters(playerSession));
|
||||
var unlinkedPlayerCharacter = playerCharacters.Single(character => character.Id == playerCharacterInGmCampaign.Id);
|
||||
Assert.Null(unlinkedPlayerCharacter.CampaignId);
|
||||
|
||||
using var db = harness.CreateDbContext();
|
||||
Assert.DoesNotContain(db.Campaigns, campaign => campaign.Id == gmOwnedCampaign.Id);
|
||||
Assert.Empty(db.RollLogEntries.Where(entry => entry.CampaignId == gmOwnedCampaign.Id));
|
||||
|
||||
var preservedGmCharacter = db.Characters.Single(character => character.Id == gmCharacterInOwnedCampaign.Id);
|
||||
Assert.Null(preservedGmCharacter.CampaignId);
|
||||
|
||||
var preservedPlayerCharacter = db.Characters.Single(character => character.Id == playerCharacterInGmCampaign.Id);
|
||||
Assert.Null(preservedPlayerCharacter.CampaignId);
|
||||
|
||||
Assert.DoesNotContain(db.Characters, character => character.Id == gmCharacterOutsideOwnedCampaign.Id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -321,10 +321,19 @@ public sealed class GameService : IGameService
|
||||
return ServiceResult<bool>.Failure("user_not_found", "User was not found.");
|
||||
|
||||
var gmCampaignIds = m_CampaignsById.Values.Where(campaign => campaign.GmUserId == targetUser.Id).Select(campaign => campaign.Id).ToArray();
|
||||
var gmCampaignIdSet = gmCampaignIds.ToHashSet();
|
||||
var preservedCharacterIds = m_CharactersById.Values
|
||||
.Where(character => character.CampaignId.HasValue && gmCampaignIdSet.Contains(character.CampaignId.Value))
|
||||
.Select(character => character.Id)
|
||||
.ToHashSet();
|
||||
|
||||
foreach (var campaignId in gmCampaignIds)
|
||||
DeleteCampaignLocked(campaignId);
|
||||
|
||||
var ownedCharacterIds = m_CharactersById.Values.Where(character => character.OwnerUserId == targetUser.Id).Select(character => character.Id).ToArray();
|
||||
var ownedCharacterIds = m_CharactersById.Values
|
||||
.Where(character => character.OwnerUserId == targetUser.Id && !preservedCharacterIds.Contains(character.Id))
|
||||
.Select(character => character.Id)
|
||||
.ToArray();
|
||||
foreach (var characterId in ownedCharacterIds)
|
||||
DeleteCharacterLocked(characterId);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user