Initial curated itworx-knowledge-hub source from 3b1751d0d9dee551aa6994eee0093704dc334817
This commit is contained in:
commit
ad8ad252a9
825 files changed
+124216
No files matched your search
@@ -0,0 +1,95 @@
|
||||
using System.Net;
|
||||
using System.Net.Http.Json;
|
||||
using ItWorx.KnowledgeHub.Contracts.Admin;
|
||||
using ItWorx.KnowledgeHub.Contracts.Knowledge;
|
||||
using ItWorx.KnowledgeHub.Infrastructure.Persistence;
|
||||
using ItWorx.KnowledgeHub.IntegrationTests.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace ItWorx.KnowledgeHub.IntegrationTests.Knowledge;
|
||||
|
||||
/// <summary>The explicit administrative purge never removes a page still within its
|
||||
/// trash retention window, and is never reachable except by an administrator
|
||||
/// (docs/09-data-safety.md: "never a permanent delete through a normal UI flow").</summary>
|
||||
[Collection(PostgresTestGroup.Name)]
|
||||
public sealed class TrashPurgeTests(PostgresContainerFixture postgres) : OwnerSetupTestBase(postgres)
|
||||
{
|
||||
[Fact]
|
||||
public async Task Purge_does_not_remove_a_trashed_page_still_within_its_retention_window()
|
||||
{
|
||||
using var client = Factory.CreateClient();
|
||||
await SetupHelper.LoginAsync(client, OwnerEmail, OwnerPassword);
|
||||
|
||||
var createResponse = await SetupHelper.PostWithCsrfAsync(
|
||||
client, "/api/v1/pages", new CreatePageRequest(null, "Recent verwijderd", "WikiPage", "Inhoud.", null));
|
||||
var page = await createResponse.Content.ReadFromJsonAsync<PageDetail>();
|
||||
Assert.NotNull(page);
|
||||
|
||||
await SetupHelper.PostWithCsrfAndIfMatchAsync(client, $"/api/v1/pages/{page.Id}/trash", (object?)null, page.ETag);
|
||||
|
||||
var purgeResponse = await SetupHelper.PostWithCsrfAsync(client, "/api/v1/admin/trash/purge", (object?)null);
|
||||
Assert.Equal(HttpStatusCode.OK, purgeResponse.StatusCode);
|
||||
var result = await purgeResponse.Content.ReadFromJsonAsync<TrashPurgeResponse>();
|
||||
Assert.NotNull(result);
|
||||
Assert.Equal(0, result.PurgedCount);
|
||||
|
||||
var stillThere = await client.GetAsync($"/api/v1/pages/{page.Id}");
|
||||
Assert.Equal(HttpStatusCode.OK, stillThere.StatusCode);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Purge_permanently_removes_a_trashed_page_once_its_retention_window_has_elapsed()
|
||||
{
|
||||
using var client = Factory.CreateClient();
|
||||
await SetupHelper.LoginAsync(client, OwnerEmail, OwnerPassword);
|
||||
|
||||
var createResponse = await SetupHelper.PostWithCsrfAsync(
|
||||
client, "/api/v1/pages", new CreatePageRequest(null, "Lang geleden verwijderd", "WikiPage", "Inhoud.", null));
|
||||
var page = await createResponse.Content.ReadFromJsonAsync<PageDetail>();
|
||||
Assert.NotNull(page);
|
||||
|
||||
await SetupHelper.PostWithCsrfAndIfMatchAsync(client, $"/api/v1/pages/{page.Id}/trash", (object?)null, page.ETag);
|
||||
|
||||
// Directly back-date the retention window rather than waiting 30 real days —
|
||||
// the use case's own eligibility computation (Trash(...) with a fixed
|
||||
// TimeSpan) is exercised elsewhere; this test proves the purge query itself
|
||||
// correctly identifies and removes an eligible row.
|
||||
using (var scope = Factory.Services.CreateScope())
|
||||
{
|
||||
var db = scope.ServiceProvider.GetRequiredService<KnowledgeHubDbContext>();
|
||||
await db.Database.ExecuteSqlInterpolatedAsync(
|
||||
$"UPDATE pages SET purge_after = {DateTimeOffset.UtcNow.AddDays(-1)} WHERE id = {page.Id}");
|
||||
}
|
||||
|
||||
var purgeResponse = await SetupHelper.PostWithCsrfAsync(client, "/api/v1/admin/trash/purge", (object?)null);
|
||||
Assert.Equal(HttpStatusCode.OK, purgeResponse.StatusCode);
|
||||
var result = await purgeResponse.Content.ReadFromJsonAsync<TrashPurgeResponse>();
|
||||
Assert.NotNull(result);
|
||||
Assert.Equal(1, result.PurgedCount);
|
||||
|
||||
var afterPurge = await client.GetAsync($"/api/v1/pages/{page.Id}");
|
||||
Assert.Equal(HttpStatusCode.NotFound, afterPurge.StatusCode);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Purge_is_administrator_only()
|
||||
{
|
||||
using var client = Factory.CreateClient();
|
||||
await SetupHelper.LoginAsync(client, OwnerEmail, OwnerPassword);
|
||||
|
||||
var editorEmail = "redacteur-purge@itworx.test";
|
||||
var editorPassword = "correct-horse-battery-staple";
|
||||
await SetupHelper.PostWithCsrfAsync(
|
||||
client,
|
||||
"/api/v1/admin/users",
|
||||
new CreateUserRequest("Redacteur", editorEmail, editorPassword, "Editor"));
|
||||
|
||||
using var editorClient = Factory.CreateClient();
|
||||
await SetupHelper.LoginAsync(editorClient, editorEmail, editorPassword);
|
||||
|
||||
var response = await SetupHelper.PostWithCsrfAsync(editorClient, "/api/v1/admin/trash/purge", (object?)null);
|
||||
|
||||
Assert.Equal(HttpStatusCode.Forbidden, response.StatusCode);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user