[backend/federation] Federate user pronouns

This commit is contained in:
pancakes 2025-01-26 17:22:06 +10:00 committed by Laura Hausmann
parent 6001ff960a
commit 2aa6eb608b
No known key found for this signature in database
GPG key ID: D044E84C5BE01605
5 changed files with 51 additions and 3 deletions

View file

@ -21,6 +21,7 @@ public static class Constants
public const string MastodonNs = "http://joinmastodon.org/ns"; public const string MastodonNs = "http://joinmastodon.org/ns";
public const string MisskeyNs = "https://misskey-hub.net/ns"; public const string MisskeyNs = "https://misskey-hub.net/ns";
public const string FedibirdNs = "http://fedibird.com/ns"; public const string FedibirdNs = "http://fedibird.com/ns";
public const string PancakesNs = "https://ns.pancakes.gay/as/";
public static readonly string[] SystemUsers = ["instance.actor", "relay.actor"]; public static readonly string[] SystemUsers = ["instance.actor", "relay.actor"];
public const string APMime = "application/activity+json"; public const string APMime = "application/activity+json";

View file

@ -80,7 +80,14 @@ public class UserRenderer(
var attachments = profile?.Fields var attachments = profile?.Fields
.Select(p => new ASField { Name = p.Name, Value = RenderFieldValue(p.Value) }) .Select(p => new ASField { Name = p.Name, Value = RenderFieldValue(p.Value) })
.Cast<ASAttachment>() .Concat<ASAttachment>(profile.Pronouns != null && profile.Pronouns.Count != 0
?
[
profile.Pronouns.TryGetValue("", out var pronouns)
? new ASPronouns { Name = pronouns }
: new ASPronouns { NameMap = profile.Pronouns }
]
: [])
.ToList(); .ToList();
var summary = profile?.Description != null var summary = profile?.Description != null

View file

@ -43,7 +43,8 @@
"Bite": "https://ns.mia.jetzt/as#Bite", "Bite": "https://ns.mia.jetzt/as#Bite",
"quoteUri": "http://fedibird.com/ns#quoteUri", "quoteUri": "http://fedibird.com/ns#quoteUri",
"EmojiReact": "http://litepub.social/ns#EmojiReact" "EmojiReact": "http://litepub.social/ns#EmojiReact",
"Pronouns": "https://ns.pancakes.gay/as/#Pronouns"
} }
] ]
} }

View file

@ -1,8 +1,11 @@
using System.Text.Json.Serialization;
using Iceshrimp.Backend.Core.Configuration; using Iceshrimp.Backend.Core.Configuration;
using Newtonsoft.Json; using Newtonsoft.Json;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using J = Newtonsoft.Json.JsonPropertyAttribute; using J = Newtonsoft.Json.JsonPropertyAttribute;
using JC = Newtonsoft.Json.JsonConverterAttribute; using JC = Newtonsoft.Json.JsonConverterAttribute;
using JI = System.Text.Json.Serialization.JsonIgnoreAttribute;
using JsonConverter = Newtonsoft.Json.JsonConverter;
namespace Iceshrimp.Backend.Core.Federation.ActivityStreams.Types; namespace Iceshrimp.Backend.Core.Federation.ActivityStreams.Types;
@ -50,6 +53,21 @@ public class ASField : ASAttachment
public ASField() => Type = $"{Constants.SchemaNs}#PropertyValue"; public ASField() => Type = $"{Constants.SchemaNs}#PropertyValue";
} }
public class ASPronouns : ASAttachment
{
public ASPronouns() => Type = $"{Constants.PancakesNs}#Pronouns";
[J($"{Constants.ActivityStreamsNs}#name")]
[JC(typeof(ValueObjectConverter))]
[JI(Condition = JsonIgnoreCondition.WhenWritingNull)]
public string? Name { get; set; }
[J($"{Constants.ActivityStreamsNs}#nameMap")]
[JC(typeof(ValueObjectConverter))]
[JI(Condition = JsonIgnoreCondition.WhenWritingNull)]
public Dictionary<string, string>? NameMap { get; set; }
}
public class ASImageConverter : ASSerializer.ListSingleObjectConverter<ASImage>; public class ASImageConverter : ASSerializer.ListSingleObjectConverter<ASImage>;
public sealed class ASAttachmentConverter : JsonConverter public sealed class ASAttachmentConverter : JsonConverter
@ -99,6 +117,7 @@ public sealed class ASAttachmentConverter : JsonConverter
$"{Constants.ActivityStreamsNs}#Document" => obj.ToObject<ASDocument?>(), $"{Constants.ActivityStreamsNs}#Document" => obj.ToObject<ASDocument?>(),
$"{Constants.ActivityStreamsNs}#Image" => obj.ToObject<ASImage?>(), $"{Constants.ActivityStreamsNs}#Image" => obj.ToObject<ASImage?>(),
$"{Constants.SchemaNs}#PropertyValue" => obj.ToObject<ASField?>(), $"{Constants.SchemaNs}#PropertyValue" => obj.ToObject<ASField?>(),
$"{Constants.PancakesNs}#Pronouns" => obj.ToObject<ASPronouns?>(),
_ => attachment _ => attachment
}; };
} }

View file

@ -159,6 +159,15 @@ public class UserService(
.AwaitAllAsync() .AwaitAllAsync()
: null; : null;
var pronounsAttachment = actor.Attachments?.OfType<ASPronouns>()
.FirstOrDefault(p => p is { Name: not null } or { NameMap: not null });
var pronouns = pronounsAttachment switch
{
{ Name: not null } => new Dictionary<string, string> { { "", pronounsAttachment.Name } },
{ NameMap: not null } => pronounsAttachment.NameMap,
_ => null
};
var bio = actor.MkSummary?.ReplaceLineEndings("\n").Trim(); var bio = actor.MkSummary?.ReplaceLineEndings("\n").Trim();
if (bio == null) if (bio == null)
{ {
@ -209,7 +218,8 @@ public class UserService(
//Location = TODO, //Location = TODO,
Fields = fields?.ToArray() ?? [], Fields = fields?.ToArray() ?? [],
UserHost = user.Host, UserHost = user.Host,
Url = actor.Url?.Link Url = actor.Url?.Link,
Pronouns = pronouns
}; };
var publicKey = new UserPublickey var publicKey = new UserPublickey
@ -326,6 +336,15 @@ public class UserService(
.AwaitAllAsync() .AwaitAllAsync()
: null; : null;
var pronounsAttachment = actor.Attachments?.OfType<ASPronouns>()
.FirstOrDefault(p => p is { Name: not null } or { NameMap: not null });
var pronouns = pronounsAttachment switch
{
{ Name: not null } => new Dictionary<string, string> { { "", pronounsAttachment.Name } },
{ NameMap: not null } => pronounsAttachment.NameMap,
_ => null
};
user.Emojis = emoji.Select(p => p.Id).ToList(); user.Emojis = emoji.Select(p => p.Id).ToList();
//TODO: FollowersCount //TODO: FollowersCount
//TODO: FollowingCount //TODO: FollowingCount
@ -351,6 +370,7 @@ public class UserService(
user.UserProfile.Fields = fields?.ToArray() ?? []; user.UserProfile.Fields = fields?.ToArray() ?? [];
user.UserProfile.UserHost = user.Host; user.UserProfile.UserHost = user.Host;
user.UserProfile.Url = actor.Url?.Link; user.UserProfile.Url = actor.Url?.Link;
user.UserProfile.Pronouns = pronouns;
user.UserProfile.MentionsResolved = false; user.UserProfile.MentionsResolved = false;