From 5b0427ad59cc373a92c34fb8380fd9b26d5ab367 Mon Sep 17 00:00:00 2001 From: miraikumiko Date: Mon, 2 Jun 2025 17:31:39 +0200 Subject: [PATCH] Add activitypub.ex --- lib/nulla/activitypub.ex | 84 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 lib/nulla/activitypub.ex diff --git a/lib/nulla/activitypub.ex b/lib/nulla/activitypub.ex new file mode 100644 index 0000000..85647e1 --- /dev/null +++ b/lib/nulla/activitypub.ex @@ -0,0 +1,84 @@ +defmodule Nulla.ActivityPub do + @spec context() :: list() + defp context do + [ + "https://www.w3.org/ns/activitystreams", + "https://w3id.org/security/v1", + Jason.OrderedObject.new( + manuallyApprovesFollowers: "as:manuallyApprovesFollowers", + toot: "http://joinmastodon.org/ns#", + featured: %{"@id" => "toot:featured", "@type" => "@id"}, + featuredTags: %{"@id" => "toot:featuredTags", "@type" => "@id"}, + alsoKnownAs: %{"@id" => "as:alsoKnownAs", "@type" => "@id"}, + movedTo: %{"@id" => "as:movedTo", "@type" => "@id"}, + schema: "http://schema.org#", + PropertyValue: "schema:PropertyValue", + value: "schema:value", + discoverable: "toot:discoverable", + suspended: "toot:suspended", + memorial: "toot:memorial", + indexable: "toot:indexable", + attributionDomains: %{"@id" => "toot:attributionDomains", "@type" => "@id"}, + Hashtag: "as:Hashtag", + focalPoint: %{"@container" => "@list", "@id" => "toot:focalPoint"} + ) + ] + end + + @spec ap_user(String.t(), Nulla.Users.User.t()) :: Jason.OrderedObject.t() + def ap_user(domain, user) do + Jason.OrderedObject.new([ + "@context": context(), + id: "https://#{domain}/@#{user.username}", + type: "Person", + following: "https://#{domain}/@#{user.username}/following", + followers: "https://#{domain}/@#{user.username}/followers", + inbox: "https://#{domain}/@#{user.username}/inbox", + outbox: "https://#{domain}/@#{user.username}/outbox", + featured: "https://#{domain}/@#{user.username}/collections/featured", + preferredUsername: user.username, + name: user.realname, + summary: user.bio, + url: "https://#{domain}/@#{user.username}", + manuallyApprovesFollowers: user.follow_approval, + discoverable: user.is_discoverable, + indexable: user.is_indexable, + published: DateTime.to_iso8601(user.inserted_at), + memorial: user.is_memorial, + publicKey: Jason.OrderedObject.new( + id: "https://#{domain}/@#{user.username}#main-key", + owner: "https://#{domain}/@#{user.username}", + publicKeyPem: user.public_key + ), + tag: Enum.map(user.tags, fn tag -> + Jason.OrderedObject.new( + type: "Hashtag", + href: "https://#{domain}/tags/#{tag}", + name: "##{tag}" + ) + end), + attachment: Enum.map(user.fields, fn {name, value} -> + Jason.OrderedObject.new( + type: "PropertyValue", + name: name, + value: value + ) + end), + endpoints: Jason.OrderedObject.new( + sharedInbox: "https://#{domain}/inbox" + ), + icon: Jason.OrderedObject.new( + type: "Image", + mediaType: MIME.from_path(user.avatar), + url: "https://#{domain}#{user.avatar}" + ), + image: Jason.OrderedObject.new( + type: "Image", + mediaType: MIME.from_path(user.banner), + url: "https://#{domain}#{user.banner}" + ), + "vcard:bday": user.birthday, + "vcard:Address": user.location + ]) + end +end