110 lines
4.1 KiB
C#
110 lines
4.1 KiB
C#
using System.Text.Json.Serialization;
|
|
|
|
namespace Elternbeirat.Contracts;
|
|
|
|
/// <summary>
|
|
/// A single question and answer of the FAQ, as stored in PocketBase.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// On the FAQ page, entries are grouped by their <see cref="Topic"/>. The topic is
|
|
/// a PocketBase relation; <see cref="Topic"/> is the resolved topic record, present
|
|
/// only when the query expanded the relation (see <see cref="FaqExpand"/>).
|
|
/// </remarks>
|
|
public record Faq
|
|
{
|
|
/// <summary>
|
|
/// Gets the PocketBase record id.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// <see langword="required"/>: every stored record has an id. Modeling it as
|
|
/// required states which fields a record must carry, independent of the store,
|
|
/// so a future data source has to supply them too.
|
|
/// </remarks>
|
|
[JsonPropertyName("id")]
|
|
public required string Id { get; init; }
|
|
|
|
/// <summary>
|
|
/// Gets the question as a parent would phrase it.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// <see langword="required"/>: a FAQ entry without a question is incomplete, and
|
|
/// the field is required in PocketBase.
|
|
/// </remarks>
|
|
[JsonPropertyName("question")]
|
|
public required string Question { get; init; }
|
|
|
|
/// <summary>
|
|
/// Gets the answer as Markdown.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// <see langword="required"/>: a FAQ entry exists to answer its question, so an
|
|
/// entry without an answer is incomplete. The field is required in PocketBase.
|
|
/// </remarks>
|
|
[JsonPropertyName("answer")]
|
|
public required string Answer { get; init; }
|
|
|
|
/// <summary>
|
|
/// Gets the sort order of the question within its topic.
|
|
/// </summary>
|
|
/// <value>
|
|
/// The sort key; questions with smaller values appear first.
|
|
/// </value>
|
|
[JsonPropertyName("order")]
|
|
public double Order { get; init; }
|
|
|
|
/// <summary>
|
|
/// Gets whether this entry is published and may be shown to visitors.
|
|
/// </summary>
|
|
/// <value>
|
|
/// <see langword="true"/> when the entry is public, <see langword="false"/> for a
|
|
/// draft that must stay hidden.
|
|
/// </value>
|
|
/// <remarks>
|
|
/// Collection queries filter on <c>public=true</c> server-side, so entries loaded
|
|
/// that way are always public and never need this checked. It matters only for the
|
|
/// <c>faqs_via_topic</c> back-relation expand behind <see cref="FaqTopic.Faqs"/>:
|
|
/// PocketBase does not apply the topic query's <c>public</c> filter to expanded
|
|
/// child records, so a draft question would otherwise leak onto the topic page.
|
|
/// That getter filters on this to keep drafts hidden.
|
|
/// </remarks>
|
|
[JsonPropertyName("public")]
|
|
public bool Public { get; init; }
|
|
|
|
/// <summary>
|
|
/// Gets the expanded relations returned by PocketBase, or <see langword="null"/>
|
|
/// when the query did not expand any.
|
|
/// </summary>
|
|
[JsonPropertyName("expand")]
|
|
public FaqExpand? Expand { get; init; }
|
|
|
|
/// <summary>
|
|
/// Gets the resolved topic this entry is grouped under, or <see langword="null"/>
|
|
/// when the query did not expand the topic relation.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Convenience over <see cref="Expand"/>: the FAQ page reads the grouping
|
|
/// heading from here. It is <see langword="null"/> unless the entry was loaded
|
|
/// with the topic relation expanded.
|
|
/// </remarks>
|
|
[JsonIgnore]
|
|
public FaqTopic? Topic => Expand?.Topic;
|
|
}
|
|
|
|
/// <summary>
|
|
/// The relations of a <see cref="Faq"/> that PocketBase returns under
|
|
/// <c>expand</c> when the query asks for them.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// One property per expandable relation, named after its PocketBase field, so the
|
|
/// JSON <c>expand</c> object maps straight onto it. <see cref="Faq.Topic"/> reads
|
|
/// through this.
|
|
/// </remarks>
|
|
public record FaqExpand
|
|
{
|
|
/// <summary>
|
|
/// Gets the expanded topic of the <c>topic</c> relation, if it was expanded.
|
|
/// </summary>
|
|
[JsonPropertyName("topic")]
|
|
public FaqTopic? Topic { get; init; }
|
|
}
|