Add owner/admin character deletion in campaign management

This commit is contained in:
2026-02-26 17:56:52 +01:00
parent ac5acd77f0
commit 51d04fcdc5
11 changed files with 174 additions and 9 deletions

View File

@@ -188,4 +188,45 @@ public sealed class CampaignApiTests : ApiTestBase
Assert.Contains(playerCampaignOptions, option => option.Id == firstCampaign.Id);
Assert.Contains(playerCampaignOptions, option => option.Id == secondCampaign.Id);
}
[Fact]
public async Task CharacterDelete_RequiresOwnerOrAdmin()
{
using var factory = CreateFactory(6, 5, 4);
using var adminClient = factory.CreateClient(new() { AllowAutoRedirect = false });
using var gmClient = factory.CreateClient(new() { AllowAutoRedirect = false });
using var ownerClient = factory.CreateClient(new() { AllowAutoRedirect = false });
using var otherClient = factory.CreateClient(new() { AllowAutoRedirect = false });
await RegisterAsync(adminClient, "admin-delete", "Password123", "Admin");
await LoginAsync(adminClient, "admin-delete", "Password123");
await RegisterAsync(gmClient, "gm-delete", "Password123", "GM");
await LoginAsync(gmClient, "gm-delete", "Password123");
await RegisterAsync(ownerClient, "owner-delete", "Password123", "Owner");
await LoginAsync(ownerClient, "owner-delete", "Password123");
await RegisterAsync(otherClient, "other-delete", "Password123", "Other");
await LoginAsync(otherClient, "other-delete", "Password123");
var campaign = await PostAsync<CreateCampaignRequest, CampaignDetails>(gmClient, "/api/campaigns", new("Deletion Campaign", "d6"));
var ownerCharacter = await PostAsync<CreateCharacterRequest, CharacterSummary>(ownerClient, "/api/characters", new("Owner Character", campaign.Id));
var otherCharacter = await PostAsync<CreateCharacterRequest, CharacterSummary>(otherClient, "/api/characters", new("Other Character", campaign.Id));
var gmDeleteAttempt = await gmClient.DeleteAsync($"/api/characters/{ownerCharacter.Id}");
Assert.Equal(HttpStatusCode.BadRequest, gmDeleteAttempt.StatusCode);
var otherDeleteAttempt = await otherClient.DeleteAsync($"/api/characters/{ownerCharacter.Id}");
Assert.Equal(HttpStatusCode.BadRequest, otherDeleteAttempt.StatusCode);
var ownerDelete = await ownerClient.DeleteAsync($"/api/characters/{ownerCharacter.Id}");
Assert.Equal(HttpStatusCode.OK, ownerDelete.StatusCode);
var adminDelete = await adminClient.DeleteAsync($"/api/characters/{otherCharacter.Id}");
Assert.Equal(HttpStatusCode.OK, adminDelete.StatusCode);
var campaignAfterDeletes = await GetAsync<CampaignDetails>(gmClient, $"/api/campaigns/{campaign.Id}");
Assert.Empty(campaignAfterDeletes.Characters);
}
}

View File

@@ -136,4 +136,40 @@ public sealed class ServiceSkillGroupAndOwnershipTests
var adminUnlink = ServiceTestSupport.GetValue(service.UpdateCharacter(adminTwoSession, character.Id, "Admin Unlink", null));
Assert.Null(adminUnlink.CampaignId);
}
[Fact]
public void CharacterDelete_AllowsOnlyOwnerOrAdmin()
{
using var harness = ServiceTestSupport.CreateHarness();
var service = harness.Service;
service.Register("admin", "Password123", "Admin");
service.Register("gm", "Password123", "GM");
service.Register("owner", "Password123", "Owner");
service.Register("other", "Password123", "Other");
var adminSession = ServiceTestSupport.GetValue(service.Login("admin", "Password123")).SessionToken;
var gmSession = ServiceTestSupport.GetValue(service.Login("gm", "Password123")).SessionToken;
var ownerSession = ServiceTestSupport.GetValue(service.Login("owner", "Password123")).SessionToken;
var otherSession = ServiceTestSupport.GetValue(service.Login("other", "Password123")).SessionToken;
var campaign = ServiceTestSupport.GetValue(service.CreateCampaign(gmSession, "Main", "d6"));
var ownerCharacter = ServiceTestSupport.GetValue(service.CreateCharacter(ownerSession, "Owner Character", campaign.Id));
var otherCharacter = ServiceTestSupport.GetValue(service.CreateCharacter(otherSession, "Other Character", campaign.Id));
var gmDeleteAttempt = service.DeleteCharacter(gmSession, ownerCharacter.Id);
Assert.False(gmDeleteAttempt.Succeeded);
var otherDeleteAttempt = service.DeleteCharacter(otherSession, ownerCharacter.Id);
Assert.False(otherDeleteAttempt.Succeeded);
var ownerDelete = ServiceTestSupport.GetValue(service.DeleteCharacter(ownerSession, ownerCharacter.Id));
Assert.True(ownerDelete);
var adminDelete = ServiceTestSupport.GetValue(service.DeleteCharacter(adminSession, otherCharacter.Id));
Assert.True(adminDelete);
var campaignAfterDeletes = ServiceTestSupport.GetValue(service.GetCampaign(gmSession, campaign.Id));
Assert.Empty(campaignAfterDeletes.Characters);
}
}