Group FAQs by a topic relation, ordered; drop unused FAQ teaser
This commit is contained in:
1 parent
28944c155a
commit
2ea8856d65
14 files changed
+328
-128
No files matched your search
@@ -18,7 +18,7 @@ public sealed class PocketBaseClientTests(PocketBaseFixture pocketBase)
|
||||
var events = await client.GetEventsAsync();
|
||||
|
||||
// Two seeded events, earliest start first.
|
||||
events.Select(e => e.Title).ShouldBe(["Elternbeiratssitzung", "Herbstbasar"]);
|
||||
events.Select(@event => @event.Title).ShouldBe(["Elternbeiratssitzung", "Herbstbasar"]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -46,8 +46,8 @@ public sealed class PocketBaseClientTests(PocketBaseFixture pocketBase)
|
||||
|
||||
var events = await client.GetEventsAsync();
|
||||
|
||||
var meeting = events.Single(e => e.Title == "Elternbeiratssitzung");
|
||||
var basar = events.Single(e => e.Title == "Herbstbasar");
|
||||
var meeting = events.Single(@event => @event.Title == "Elternbeiratssitzung");
|
||||
var basar = events.Single(@event => @event.Title == "Herbstbasar");
|
||||
meeting.End.ShouldBeNull(); // no end seeded
|
||||
basar.End.ShouldNotBeNull(); // end seeded
|
||||
}
|
||||
@@ -60,7 +60,7 @@ public sealed class PocketBaseClientTests(PocketBaseFixture pocketBase)
|
||||
var posts = await client.GetPostsAsync();
|
||||
|
||||
// Sorted by -date: March before January.
|
||||
posts.Select(p => p.Title).ShouldBe(["Neuer Vorstand", "Neue Sporthalle"]);
|
||||
posts.Select(post => post.Title).ShouldBe(["Neuer Vorstand", "Neue Sporthalle"]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -85,9 +85,9 @@ public sealed class PocketBaseClientTests(PocketBaseFixture pocketBase)
|
||||
var pages = await client.GetPagesAsync();
|
||||
|
||||
// The draft (public=false) must be filtered out, the public ones present.
|
||||
pages.ShouldNotContain(p => p.Slug == "draft");
|
||||
pages.ShouldContain(p => p.Slug == "home");
|
||||
pages.ShouldContain(p => p.Slug == "contact");
|
||||
pages.ShouldNotContain(page => page.Slug == "draft");
|
||||
pages.ShouldContain(page => page.Slug == "home");
|
||||
pages.ShouldContain(page => page.Slug == "contact");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -111,7 +111,10 @@ public sealed class PocketBaseClientTests(PocketBaseFixture pocketBase)
|
||||
|
||||
var faqs = await client.GetFaqsAsync();
|
||||
|
||||
faqs.Select(f => f.Topic).ShouldBe(["Mensa und Mittagessen", "Schließfächer"], ignoreOrder: true);
|
||||
faqs.ShouldAllBe(f => !string.IsNullOrWhiteSpace(f.Question));
|
||||
// The topic relation is expanded, so each entry carries its topic. The two
|
||||
// seeded topics are ordered (Mensa order 1 before Schließfächer order 2), and
|
||||
// GetFaqsAsync sorts by topic.order, so the groups come back in that order.
|
||||
faqs.Select(faq => faq.Topic?.Title).ShouldBe(["Mensa und Mittagessen", "Schließfächer"]);
|
||||
faqs.ShouldAllBe(faq => !string.IsNullOrWhiteSpace(faq.Question));
|
||||
}
|
||||
}
|
||||
@@ -313,23 +313,49 @@ public sealed class PocketBaseFixture : IAsyncLifetime
|
||||
title = "Herbstbasar", location = "Schulhof", note = "", @public = true,
|
||||
});
|
||||
|
||||
// Faqs: two topics.
|
||||
// Faq topics: two, ordered. The topics own the grouping and the order the FAQ
|
||||
// page shows the groups in (Mensa before Schließfächer).
|
||||
var lunchTopicId = await CreateRecordAsync(http, "faq_topics", new
|
||||
{
|
||||
title = "Mensa und Mittagessen", slug = "mensa", intro = "",
|
||||
order = 1, @public = true,
|
||||
});
|
||||
var lockerTopicId = await CreateRecordAsync(http, "faq_topics", new
|
||||
{
|
||||
title = "Schließfächer", slug = "schliessfach", intro = "",
|
||||
order = 2, @public = true,
|
||||
});
|
||||
|
||||
// Faqs: each points at its topic through the "topic" relation (the created
|
||||
// topic id), and carries its own order within the topic.
|
||||
await CreateRecordAsync(http, "faqs", new
|
||||
{
|
||||
question = "Wann gibt es Mittagessen?", answer = "Um 12 Uhr.",
|
||||
topic = "Mensa und Mittagessen", @public = true,
|
||||
topic = lunchTopicId, order = 1, @public = true,
|
||||
});
|
||||
await CreateRecordAsync(http, "faqs", new
|
||||
{
|
||||
question = "Wie viel kostet ein Schließfach?", answer = "20 Euro.",
|
||||
topic = "Schließfächer", @public = true,
|
||||
topic = lockerTopicId, order = 1, @public = true,
|
||||
});
|
||||
}
|
||||
|
||||
private static async Task CreateRecordAsync(HttpClient http, string collection, object record)
|
||||
private static async Task<string> CreateRecordAsync(HttpClient http, string collection, object record)
|
||||
{
|
||||
var response = await http.PostAsJsonAsync($"/api/collections/{collection}/records", record);
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
// Return the created record's id so a caller can seed a relation to it (e.g. a
|
||||
// faq pointing at its topic). Callers that do not need it just ignore the value.
|
||||
var created = await response.Content.ReadFromJsonAsync<CreatedRecord>();
|
||||
return created?.Id ?? throw new InvalidOperationException(
|
||||
$"PocketBase returned no id for the created '{collection}' record.");
|
||||
}
|
||||
|
||||
private sealed record CreatedRecord
|
||||
{
|
||||
[System.Text.Json.Serialization.JsonPropertyName("id")]
|
||||
public string Id { get; init; } = string.Empty;
|
||||
}
|
||||
|
||||
private sealed record AuthResponse
|
||||
|
||||
Reference in new issue
Block a user