The card marks an edited post with a button that opens its versions, newest first (/statuses/:id/history), each with its time, warning and words; PrivaPub now has a remote post's earlier versions from Pleroma's formerRepresentations too. The composer's e2e test opens the history after its edit. The wall test retries smuser's post while Smithereen has not yet had the persona's Accept. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LsXgEaXee4GCU1hwYgPJXw
240 lines
7.7 KiB
C#
240 lines
7.7 KiB
C#
using System.Text.Json.Nodes;
|
|
|
|
namespace decePubClient.Models.Mastodon;
|
|
|
|
/// <summary>/api/privapub/v1/instances: what PrivaPub stored about a server, and where it is.</summary>
|
|
public class InstanceDescription
|
|
{
|
|
public string Host { get; set; }
|
|
public string Software { get; set; }
|
|
public string Version { get; set; }
|
|
public string NodeName { get; set; }
|
|
public List<string> Protocols { get; set; } = [];
|
|
public bool? OpenRegistrations { get; set; }
|
|
public DateTime? DescribedAt { get; set; }
|
|
public string DescriptionError { get; set; }
|
|
public JsonNode NodeInfo { get; set; }
|
|
public InstanceDelivery Delivery { get; set; }
|
|
public InstanceLocation Geo { get; set; }
|
|
}
|
|
|
|
public class InstanceDelivery
|
|
{
|
|
public int ConsecutiveFailures { get; set; }
|
|
public DateTime? UnavailableUntil { get; set; }
|
|
public DateTime? LastSuccessAt { get; set; }
|
|
public DateTime? LastFailureAt { get; set; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// The public projection of a server's place. Precision: city (coordinates to 0.1°, city and network), country (located
|
|
/// only to a country) or cdn (the CDN's name, its domain, how PrivaPub found it, and where the server was before it).
|
|
/// </summary>
|
|
public class InstanceLocation
|
|
{
|
|
public string Precision { get; set; }
|
|
public string Country { get; set; }
|
|
public string City { get; set; }
|
|
public double? Latitude { get; set; }
|
|
public double? Longitude { get; set; }
|
|
public string Network { get; set; }
|
|
public string Cdn { get; set; }
|
|
public string CdnDomain { get; set; }
|
|
/// <summary>ranges (the CDN's published addresses), headers (its fingerprint in the server's answers) or asn.</summary>
|
|
public string CdnSource { get; set; }
|
|
public InstancePlace BeforeCdn { get; set; }
|
|
public string Source { get; set; }
|
|
public DateTime? LocatedAt { get; set; }
|
|
}
|
|
|
|
/// <summary>Where a server was in a week (an ISO week, "2026-W40").</summary>
|
|
public class InstancePlace
|
|
{
|
|
public string Week { get; set; }
|
|
public string Country { get; set; }
|
|
public string City { get; set; }
|
|
public double? Latitude { get; set; }
|
|
public double? Longitude { get; set; }
|
|
}
|
|
|
|
/// <summary>/api/privapub/v1/instances/{host}/history: one weekly snapshot of a server.</summary>
|
|
public class InstanceWeek
|
|
{
|
|
public string Week { get; set; }
|
|
public DateTime? TakenAt { get; set; }
|
|
public bool Reachable { get; set; }
|
|
public string Software { get; set; }
|
|
public string Version { get; set; }
|
|
public long? UsersTotal { get; set; }
|
|
public long? UsersActiveMonth { get; set; }
|
|
public long? LocalPosts { get; set; }
|
|
public bool? OpenRegistrations { get; set; }
|
|
public InstanceLocation Geo { get; set; }
|
|
}
|
|
|
|
/// <summary>/api/privapub/v1/cdns: a CDN as a group of servers, named by its own domain (Key).</summary>
|
|
public class CdnSummary
|
|
{
|
|
public string Key { get; set; }
|
|
public string Name { get; set; }
|
|
public string Domain { get; set; }
|
|
public int Servers { get; set; }
|
|
public int Ranges { get; set; }
|
|
public DateTime? RangesUpdatedAt { get; set; }
|
|
public List<string> DetectedBy { get; set; } = [];
|
|
}
|
|
|
|
/// <summary>/api/privapub/v1/cdns/{key}: the servers behind a CDN and, newest first, week by week who joined and left.</summary>
|
|
public class CdnDetail : CdnSummary
|
|
{
|
|
public List<string> Hosts { get; set; } = [];
|
|
public bool HostsTruncated { get; set; }
|
|
public List<CdnWeek> Weeks { get; set; } = [];
|
|
}
|
|
|
|
public class CdnWeek
|
|
{
|
|
public string Week { get; set; }
|
|
public int Servers { get; set; }
|
|
public List<string> Joined { get; set; } = [];
|
|
public List<string> Left { get; set; } = [];
|
|
}
|
|
|
|
/// <summary>/api/privapub/v1/statuses/{id}/provenance: how a remote post reached PrivaPub. Path is local for a local post.</summary>
|
|
public class Provenance
|
|
{
|
|
public string ObjectUri { get; set; }
|
|
public string ObjectType { get; set; }
|
|
public string Url { get; set; }
|
|
/// <summary>delivered, fetched, unrecorded or local.</summary>
|
|
public string Path { get; set; }
|
|
public bool Refetched { get; set; }
|
|
public ProvenanceActivity Activity { get; set; }
|
|
public string Inbox { get; set; }
|
|
public string FetchedBy { get; set; }
|
|
public ProvenanceSignature Signature { get; set; }
|
|
public DateTime? ReceivedAt { get; set; }
|
|
public DateTime? Published { get; set; }
|
|
public DateTime? Updated { get; set; }
|
|
public List<string> Extensions { get; set; } = [];
|
|
public List<string> ContextNamespaces { get; set; } = [];
|
|
public JsonNode Raw { get; set; }
|
|
public int RawBytes { get; set; }
|
|
public string RawHash { get; set; }
|
|
public bool RawTruncated { get; set; }
|
|
public List<ProvenanceRevision> Revisions { get; set; } = [];
|
|
public InstanceDescription Instance { get; set; }
|
|
}
|
|
|
|
public class ProvenanceActivity
|
|
{
|
|
public string Id { get; set; }
|
|
public string Type { get; set; }
|
|
public string Actor { get; set; }
|
|
}
|
|
|
|
public class ProvenanceSignature
|
|
{
|
|
public string Scheme { get; set; }
|
|
public string KeyId { get; set; }
|
|
public string Algorithm { get; set; }
|
|
public List<string> Headers { get; set; } = [];
|
|
}
|
|
|
|
public class ProvenanceRevision
|
|
{
|
|
public string ActivityId { get; set; }
|
|
public DateTime? Updated { get; set; }
|
|
public DateTime? ReceivedAt { get; set; }
|
|
public string RawHash { get; set; }
|
|
}
|
|
|
|
/// <summary>The answer of /oauth/token.</summary>
|
|
public class TokenResponse
|
|
{
|
|
public string AccessToken { get; set; }
|
|
public string TokenType { get; set; }
|
|
public string IssuedTokenType { get; set; }
|
|
public string Scope { get; set; }
|
|
public long CreatedAt { get; set; }
|
|
}
|
|
|
|
/// <summary>An error of the Mastodon API or of /oauth: {"error": ..., "error_description": ...}.</summary>
|
|
public class MastodonError
|
|
{
|
|
public string Error { get; set; }
|
|
public string ErrorDescription { get; set; }
|
|
}
|
|
|
|
/// <summary>POST /api/v1/statuses. The text is plain: the Mastodon API does not take Markdown.</summary>
|
|
public class PostStatusForm
|
|
{
|
|
public string Status { get; set; }
|
|
public List<string> MediaIds { get; set; } = [];
|
|
public string InReplyToId { get; set; }
|
|
public bool Sensitive { get; set; }
|
|
public string SpoilerText { get; set; }
|
|
public string Visibility { get; set; }
|
|
public string Language { get; set; }
|
|
/// <summary>When the post is to be published (ISO 8601, at least five minutes ahead); null posts it now.</summary>
|
|
public string ScheduledAt { get; set; }
|
|
public PollForm Poll { get; set; }
|
|
public string QuotedStatusId { get; set; }
|
|
}
|
|
|
|
public class PollForm
|
|
{
|
|
public List<string> Options { get; set; } = [];
|
|
public int ExpiresIn { get; set; }
|
|
public bool Multiple { get; set; }
|
|
}
|
|
|
|
/// <summary>What an edit sends: the words and their warning; the media stay as they are.</summary>
|
|
public class StatusEditForm
|
|
{
|
|
public string Status { get; set; }
|
|
public string SpoilerText { get; set; }
|
|
public bool Sensitive { get; set; }
|
|
public string Language { get; set; }
|
|
}
|
|
|
|
/// <summary>/api/v1/statuses/:id/source: the author's own text of a post, to edit it.</summary>
|
|
public class StatusSource
|
|
{
|
|
public string Id { get; set; }
|
|
public string Text { get; set; }
|
|
public string SpoilerText { get; set; }
|
|
}
|
|
|
|
/// <summary>/api/v1/statuses/:id/history: one version of a post, the oldest first and the one showing last.</summary>
|
|
public class StatusEdit
|
|
{
|
|
public string Content { get; set; }
|
|
public string SpoilerText { get; set; }
|
|
public bool Sensitive { get; set; }
|
|
public DateTime CreatedAt { get; set; }
|
|
public List<CustomEmoji> Emojis { get; set; } = [];
|
|
}
|
|
|
|
/// <summary>A post waiting for its time (/api/v1/scheduled_statuses).</summary>
|
|
public class ScheduledStatus
|
|
{
|
|
public string Id { get; set; }
|
|
public DateTime ScheduledAt { get; set; }
|
|
public ScheduledParams Params { get; set; } = new();
|
|
public List<MediaAttachment> MediaAttachments { get; set; } = [];
|
|
}
|
|
|
|
public class ScheduledParams
|
|
{
|
|
public string Text { get; set; }
|
|
public string SpoilerText { get; set; }
|
|
public string Visibility { get; set; }
|
|
public string InReplyToId { get; set; }
|
|
}
|
|
|
|
public class ScheduleForm
|
|
{
|
|
public string ScheduledAt { get; set; }
|
|
}
|