using RpgRoller.Domain; namespace RpgRoller.Tests; public sealed class ServiceAdminAndCampaignDeletionTests { [Fact] public void AdminRoleManagement_RequiresAdminAndProtectsSelf() { using var harness = ServiceTestSupport.CreateHarness(); var service = harness.Service; var bootstrapAdmin = ServiceTestSupport.GetValue(service.Register("admin", "Password123", "Admin")); _ = ServiceTestSupport.GetValue(service.Register("member", "Password123", "Member")); Assert.Contains(bootstrapAdmin.Roles, role => string.Equals(role, UserRoles.Admin, StringComparison.OrdinalIgnoreCase)); var adminSession = ServiceTestSupport.GetValue(service.Login("admin", "Password123")).SessionToken; var memberSession = ServiceTestSupport.GetValue(service.Login("member", "Password123")).SessionToken; var usernames = ServiceTestSupport.GetValue(service.GetUsernames(memberSession)); Assert.Equal(["admin", "member"], usernames); var forbiddenList = service.GetUsers(memberSession); Assert.False(forbiddenList.Succeeded); var users = ServiceTestSupport.GetValue(service.GetUsers(adminSession)); var memberUser = users.Single(user => string.Equals(user.Username, "member", StringComparison.OrdinalIgnoreCase)); Assert.Empty(memberUser.Roles); var promoted = ServiceTestSupport.GetValue(service.UpdateUserRoles(adminSession, memberUser.Id, [UserRoles.Admin])); Assert.Contains(promoted.Roles, role => string.Equals(role, UserRoles.Admin, StringComparison.OrdinalIgnoreCase)); var invalidRole = service.UpdateUserRoles(adminSession, memberUser.Id, [UserRoles.Admin, "gm"]); Assert.False(invalidRole.Succeeded); Assert.Equal("invalid_role", invalidRole.Error?.Code); var selfDemote = service.UpdateUserRoles(adminSession, bootstrapAdmin.Id, Array.Empty()); Assert.False(selfDemote.Succeeded); var selfDelete = service.DeleteUser(adminSession, bootstrapAdmin.Id); Assert.False(selfDelete.Succeeded); var deletedMember = ServiceTestSupport.GetValue(service.DeleteUser(adminSession, memberUser.Id)); Assert.True(deletedMember); var remainingUsers = ServiceTestSupport.GetValue(service.GetUsers(adminSession)); Assert.Single(remainingUsers); Assert.Equal(bootstrapAdmin.Id, remainingUsers[0].Id); } [Fact] public void CampaignDeletion_ByOwnerOrAdmin_UnlinksCharactersAndClearsLog() { 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 ownerDeletedCampaign = ServiceTestSupport.GetValue(service.CreateCampaign(gmSession, "Owner Delete", "d6")); var ownerDeleteResult = ServiceTestSupport.GetValue(service.DeleteCampaign(gmSession, ownerDeletedCampaign.Id)); Assert.True(ownerDeleteResult); Assert.False(service.GetCampaign(gmSession, ownerDeletedCampaign.Id).Succeeded); var adminDeletedCampaign = ServiceTestSupport.GetValue(service.CreateCampaign(gmSession, "Admin Delete", "d6")); var playerCharacter = ServiceTestSupport.GetValue(service.CreateCharacter(playerSession, "Scout", adminDeletedCampaign.Id)); var playerSkill = ServiceTestSupport.GetValue(service.CreateSkill(playerSession, playerCharacter.Id, "Stealth", "2D+1", 1, true)); _ = ServiceTestSupport.GetValue(service.RollSkill(playerSession, playerSkill.Id, "public")); var forbiddenDelete = service.DeleteCampaign(playerSession, adminDeletedCampaign.Id); Assert.False(forbiddenDelete.Succeeded); var adminDelete = ServiceTestSupport.GetValue(service.DeleteCampaign(adminSession, adminDeletedCampaign.Id)); Assert.True(adminDelete); Assert.False(service.GetCampaign(gmSession, adminDeletedCampaign.Id).Succeeded); var playerCharacters = ServiceTestSupport.GetValue(service.GetOwnCharacters(playerSession)); Assert.Single(playerCharacters); Assert.Null(playerCharacters[0].CampaignId); 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.Null(service.GetUserBySession(gmSession)); Assert.False(service.GetMe(gmSession).Succeeded); Assert.False(service.GetUsernames(gmSession).Succeeded); 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); } }