Files
SocialPub/PrivaPub/Models/User/Avatar.cs
T
thepraandClaude Opus 5.5 1c7d1ece9c Pins across servers, both ways
An account elsewhere that pins or unpins one of its posts (Add or Remove on its `featured`) now shows those pins on its
profile here (`pinned=true`), in its order and its public posts only; a community's announce of a moderator's Add does
the same for the community. The `featured` collection itself is read with the account's counts, at most once a day, so
pins made before PrivaPub ever saw an account show too. Any other target (Smithereen's wall, a community's moderators)
is dropped. A persona's pin and unpin go to the post's audience as Add and Remove on /trophies, as Mastodon sends them.

Checked live against Mastodon (scenarios/pins.sh, 8 checks). The town's checker learnt three peer rules from the
village: Misskey and Sharkey keep a forwarded reply only with its author's LD signature (only Mastodon signs), they
count no renote by a bot, and Mastodon never sees a Lemmy vote on a post in a community. The village of 2026-10-05
checks clean, 2454 of 2454.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LsXgEaXee4GCU1hwYgPJXw
2026-10-05 22:48:57 +02:00

161 lines
5.8 KiB
C#

using MongoDB.Entities;
using PrivaPub.Infrastructure.Ids;
namespace PrivaPub.Models.User
{
public class Avatar : Entity
{
public string Url { get; set; }//url
public string Name { get; set; }//name
public string UserName { get; set; }//preferredUsername
public string Biography { get; set; }//summary
public Dictionary<string, string> SharedPersonalContacts { get; set; } = new();
public string PrivateKey { get; set; }
public string PublicKey { get; set; }
public AvatarAccountState AccountState { get; set; } = AvatarAccountState.Normal;
public AvatarSettings Settings { get; set; } = new();
public Dictionary<string, string> Fields { get; set; } = new();
public string Domain { get; set; }
public string PersonalNote { get; set; }
public string ModerationNote { get; set; }
public string InboxURL { get; set; }
public string OutboxURL { get; set; }
public string MovedToURL { get; set; }
public string PictureURL { get; set; }//icon
public string ThumbnailURL { get; set; }//image
public AvatarType AvatarType { get; set; } = AvatarType.Person;
public AvatarServer AvatarServer { get; set; } = AvatarServer.PrivaPub;
public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
public DateTime PublishedOn { get; set; } = PrivacyIds.PublishedDay(DateTime.UtcNow);//the actor's published: a few days before CreatedAt, so same-day personas differ
public DateTime? SilencedAt { get; set; }
public DateTime? SuspendedAt { get; set; }
public DateTime? BannedAt { get; set; }
public DateTime? DeletionAt { get; set; }
public override object GenerateNewID() => PrivacyIds.ForDay(PublishedOn);
}
public class ForeignAvatar : Entity
{
public string Url { get; set; }//url
public string Name { get; set; }//name
public string UserName { get; set; }//preferredUsername
public string Biography { get; set; }//summary
public Dictionary<string, string> SharedPersonalContacts { get; set; } = new();
public string PrivateKey { get; set; }
public string PublicKey { get; set; }
public AvatarAccountState AccountState { get; set; } = AvatarAccountState.Normal;
public AvatarSettings Settings { get; set; } = new();
public Dictionary<string, string> Fields { get; set; } = new();
public string Domain { get; set; }
public string PersonalNote { get; set; }
public string ModerationNote { get; set; }
public bool IsDiscoverable { get; set; } = true;
public bool IsIndexable { get; set; }
public bool IsLocked { get; set; }//manuallyApprovesFollowers
public bool IsMemorial { get; set; }
public List<PrivaPub.Models.Post.CustomEmoji> Emojis { get; set; } = new();
public string PictureDescription { get; set; }
public string HeaderDescription { get; set; }
public DateTime? Published { get; set; }//the actor's own published
public List<string> Features { get; set; }//protocol extensions its document uses, for statistics (ActorFeatures)
public string ActorURI { get; set; }//id
public string PublicKeyId { get; set; }
public string FollowersURL { get; set; }
public string FollowingURL { get; set; }
public string SharedInboxURL { get; set; }
public string InboxURL { get; set; }
public string OutboxURL { get; set; }
public string FeaturedURL { get; set; }//featured: the posts it pins
public string MovedToURL { get; set; }
public List<string> AlsoKnownAs { get; set; } = new();//alsoKnownAs: the accounts it says it also is
public string PictureURL { get; set; }//icon
public string ThumbnailURL { get; set; }//image
public AvatarType AvatarType { get; set; } = AvatarType.Person;
public AvatarServer AvatarServer { get; set; } = AvatarServer.Unknown;
public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
public DateTime? SilencedAt { get; set; }
public DateTime? SuspendedAt { get; set; }
public DateTime? BannedAt { get; set; }
public DateTime? DeletionAt { get; set; }
public DateTime? ForgottenAt { get; set; }//its likes, votes, boosts and replies were taken out of our counts (GoneActors)
public int? FollowersCount { get; set; }//its own collections' totalItems, read at most daily (AccountCountsJob)
public int? FollowingCount { get; set; }
public int? StatusesCount { get; set; }
public DateTime? CountedAt { get; set; }
}
public class AvatarSettings
{
public string LanguageCode { get; set; } = "en-GB";
public bool IsDefault { get; set; } = true;
public short IconsThemeIndexColour { get; set; } = 25;
public short LightThemeIndexColour { get; set; } = 25;
public short DarkThemeIndexColour { get; set; } = 215;
public bool PreferSystemTheming { get; set; } = true;
public bool ThemeIsDarkMode { get; set; } = false;
public bool ThemeIsDarkGray { get; set; } = false;
public bool ThemeIsLightGray { get; set; } = true;
public bool IsLocked { get; set; }
public bool IsBot { get; set; }
public bool IsDiscoverable { get; set; } = true;
public bool IsIndexable { get; set; }
public bool HideCollections { get; set; } = true;
public string DefaultVisibility { get; set; } = "public";
public bool DefaultSensitive { get; set; }
public string DefaultLanguage { get; set; }
public string QuotePolicy { get; set; } = QuotePolicies.Public;//owner decision: anyone may quote a public post, automatically
}
public static class QuotePolicies
{
public const string Public = "public";
public const string Followers = "followers";
public const string Nobody = "nobody";
public static bool IsKnown(string value) => value is Public or Followers or Nobody;
}
public enum AvatarServer
{
Unknown,
Pleroma,
Mastodon,
Akkoma,
Misskey,
PrivaPub
}
public enum AvatarType
{
Application,
Group,
Organization,
Person,
Service
}
public enum AvatarAccountState
{
Normal,
Silenced,
Suspended,
Banned,
Deleted
}
}